Changeset 55918 in vbox for trunk/src/VBox/Additions/x11/VBoxClient
- Timestamp:
- May 18, 2015 5:49:27 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp
r55846 r55918 1 1 /* $Id$ */ 2 2 /** @file 3 * X11 guest client - Drag and Drop.3 * X11 guest client - Drag and drop implementation. 4 4 */ 5 5 … … 50 50 #endif 51 51 52 /* For X11 guest xDnD is used. See http://www.acc.umu.se/~vatten/XDND.html for 52 /** 53 * For X11 guest xDnD is used. See http://www.acc.umu.se/~vatten/XDND.html for 53 54 * a walk trough. 54 55 * 55 * H->G: 56 * For X11 this means mainly forwarding all the events from HGCM to the 57 * appropriate X11 events. There exists a proxy window, which is invisible and 58 * used for all the X11 communication. On a HGCM Enter event, we set our proxy 59 * window as XdndSelection owner with the given mime-types. On every HGCM move 60 * event, we move the X11 mouse cursor to the new position and query for the 61 * window below that position. Depending on if it is XdndAware, a new window or 62 * a known window, we send the appropriate X11 messages to it. On HGCM drop, we 63 * send a XdndDrop message to the current window and wait for a X11 64 * SelectionMessage from the target window. Because we didn't have the data in 65 * the requested mime-type, yet, we save that message and ask the host for the 66 * data. When the data is successfully received from the host, we put the data 67 * as a property to the window and send a X11 SelectionNotify event to the 68 * target window. 69 * 70 * G->H: 71 * This is a lot more trickery than H->G. When a pending event from HGCM 72 * arrives, we ask if there currently is an owner of the XdndSelection 73 * property. If so, our proxy window is shown (1x1, but without backing store) 74 * and some mouse event is triggered. This should be followed by an XdndEnter 75 * event send to the proxy window. From this event we can fetch the necessary 76 * info of the MIME types and allowed actions and send this back to the host. 77 * On a drop request from the host, we query for the selection and should get 78 * the data in the specified mime-type. This data is send back to the host. 79 * After that we send a XdndLeave event to the source window. 80 * 81 * To-do: 82 * - Cancelling (e.g. with ESC key) doesn't work. 83 * 84 * To-do: 85 * - INCR (incremental transfers) support. 86 * - Make this much more robust for crashes of the other party. 87 * - Really check for the Xdnd version and the supported features. 56 * Host -> Guest: 57 * For X11 this means mainly forwarding all the events from HGCM to the 58 * appropriate X11 events. There exists a proxy window, which is invisible and 59 * used for all the X11 communication. On a HGCM Enter event, we set our proxy 60 * window as XdndSelection owner with the given mime-types. On every HGCM move 61 * event, we move the X11 mouse cursor to the new position and query for the 62 * window below that position. Depending on if it is XdndAware, a new window or 63 * a known window, we send the appropriate X11 messages to it. On HGCM drop, we 64 * send a XdndDrop message to the current window and wait for a X11 65 * SelectionMessage from the target window. Because we didn't have the data in 66 * the requested mime-type, yet, we save that message and ask the host for the 67 * data. When the data is successfully received from the host, we put the data 68 * as a property to the window and send a X11 SelectionNotify event to the 69 * target window. 70 * 71 * Guest -> Host: 72 * This is a lot more trickery than H->G. When a pending event from HGCM 73 * arrives, we ask if there currently is an owner of the XdndSelection 74 * property. If so, our proxy window is shown (1x1, but without backing store) 75 * and some mouse event is triggered. This should be followed by an XdndEnter 76 * event send to the proxy window. From this event we can fetch the necessary 77 * info of the MIME types and allowed actions and send this back to the host. 78 * On a drop request from the host, we query for the selection and should get 79 * the data in the specified mime-type. This data is send back to the host. 80 * After that we send a XdndLeave event to the source window. 81 * 82 ** @todo Cancelling (e.g. with ESC key) doesn't work. 83 ** @todo INCR (incremental transfers) support. 84 ** @todo Really check for the Xdnd version and the supported features. 85 ** @todo Either get rid of the xHelpers class or properly unify the code with the drag instance class. 88 86 */ 89 87 … … 91 89 #define VBOX_MAX_XPROPERTIES (LONG_MAX-1) 92 90 93 /* Shared struct used for adding new X11 events and HGCM messages to a single 94 * event queue. */ 91 /** 92 * Structure for storing new X11 events and HGCM messages 93 * into a single vent queue. 94 */ 95 95 struct DnDEvent 96 96 { … … 147 147 class DragAndDropService; 148 148 149 /** List of Atoms. */ 150 #define VBoxDnDAtomList RTCList<Atom> 151 149 152 /******************************************************************************* 150 153 * … … 186 189 } 187 190 188 inline RTCString xAtomListToString(const RTCList<Atom>&formatList)191 inline RTCString xAtomListToString(const VBoxDnDAtomList &formatList) 189 192 { 190 193 RTCString format; … … 198 201 199 202 private: 203 200 204 xHelpers(Display *pDisplay) 201 205 : m_pDisplay(pDisplay) … … 225 229 ******************************************************************************/ 226 230 227 xHelpers *xHelpers::m_pInstance = 0; 231 xHelpers *xHelpers::m_pInstance = NULL; 232 228 233 /* Has to be in sync with the XA_Type enum. */ 229 234 const char *xHelpers::m_xAtomNames[] = … … 337 342 338 343 #ifdef DEBUG 339 # define VBOX_DND_FN_DECL_LOG(x) inline x 344 # define VBOX_DND_FN_DECL_LOG(x) inline x /* For LogFlowXXX logging. */ 340 345 #else 341 346 # define VBOX_DND_FN_DECL_LOG(x) x 342 347 #endif 343 348 344 #define VBoxDnDAtomList RTCList<Atom> 345 346 /* For now only one DragInstance will exits when the app is running. In the 347 * future the support for having more than one drag and drop operation supported at the 348 * time will be necessary. */ 349 /** 350 * Class for handling a single drag and drop operation, that is, 351 * one source and one target at a time. 352 * 353 * For now only one DragInstance will exits when the app is running. 354 */ 349 355 class DragInstance 350 356 { … … 387 393 bool waitForX11ClientMsg(XClientMessageEvent &evMsg, Atom aType, RTMSINTERVAL uTimeoutMS = 100); 388 394 389 /* H ->G*/390 int 391 int 392 int 393 int hgDrop();394 int hgDataReceived(void *pvData, uint32_t cData);395 /* Host -> Guest handling. */ 396 int hgEnter(const RTCList<RTCString> &formats, uint32_t actions); 397 int hgLeave(void); 398 int hgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t action); 399 int hgDrop(void); 400 int hgDataReceived(const void *pvData, uint32_t cData); 395 401 396 402 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 397 /* G ->H*/398 int ghIsDnDPending();399 int 403 /* Guest -> Host handling. */ 404 int ghIsDnDPending(void); 405 int ghDropped(const RTCString &strFormat, uint32_t action); 400 406 #endif 401 407 … … 407 413 408 414 void wndXDnDClearActionList(Window wndThis) const; 409 void wndXDnDClear TypeList(Window wndThis) const;415 void wndXDnDClearFormatList(Window wndThis) const; 410 416 int wndXDnDGetActionList(Window wndThis, VBoxDnDAtomList &lstActions) const; 411 int wndXDnDGet TypeList(Window wndThis, VBoxDnDAtomList &lstTypes) const;417 int wndXDnDGetFormatList(Window wndThis, VBoxDnDAtomList &lstTypes) const; 412 418 int wndXDnDSetActionList(Window wndThis, const VBoxDnDAtomList &lstActions) const; 413 int wndXDnDSetFormatList(Window wndThis, Atom property, const VBoxDnDAtomList &lstFormats) const;414 415 int 416 int 417 static Atom 418 static int 419 static uint32_t 420 static uint32_t toHGCMActions(const RTCList<Atom>&actionsList);419 int wndXDnDSetFormatList(Window wndThis, Atom atmProp, const VBoxDnDAtomList &lstFormats) const; 420 421 int toAtomList(const RTCList<RTCString> &lstFormats, VBoxDnDAtomList &lstAtoms) const; 422 int toAtomList(const void *pvData, uint32_t cbData, VBoxDnDAtomList &lstAtoms) const; 423 static Atom toAtomAction(uint32_t uAction); 424 static int toAtomActions(uint32_t uActions, VBoxDnDAtomList &lstAtoms); 425 static uint32_t toHGCMAction(Atom atom); 426 static uint32_t toHGCMActions(const VBoxDnDAtomList &actionsList); 421 427 422 428 protected: … … 424 430 /** The instance's own DnD context. */ 425 431 VBGLR3GUESTDNDCMDCTX m_dndCtx; 432 /** Pointer to service instance. */ 426 433 DragAndDropService *m_pParent; 434 /** Pointer to X display operating on. */ 427 435 Display *m_pDisplay; 436 /** X screen ID to operate on. */ 428 437 int m_screenId; 438 /** Pointer to X screen operating on. */ 429 439 Screen *m_pScreen; 440 /** Root window handle. */ 430 441 Window m_wndRoot; 442 /** Proxy window handle. */ 431 443 Window m_wndProxy; 444 /** Current source/target window handle. */ 432 445 Window m_wndCur; 446 /** The XDnD protocol version the current 447 * source/target window is using. */ 433 448 long m_curVer; 449 /** List of (Atom) formats the source window supports. */ 434 450 VBoxDnDAtomList m_lstFormats; 451 /** List of (Atom) actions the source window supports. */ 435 452 VBoxDnDAtomList m_lstActions; 436 453 /** Deferred host to guest selection event for sending to the … … 475 492 private: 476 493 477 int x11DragAndDropInit(void);494 int dragAndDropInit(void); 478 495 static int hgcmEventThread(RTTHREAD hThread, void *pvUser); 479 496 static int x11EventThread(RTTHREAD hThread, void *pvUser); 480 481 void clearEventQueue();482 497 483 498 /* Private member vars */ … … 519 534 } 520 535 536 /** 537 * Unitializes (destroys) this drag instance. 538 */ 521 539 void DragInstance::uninit(void) 522 540 { … … 534 552 } 535 553 554 /** 555 * Resets this drag instance. 556 */ 536 557 void DragInstance::reset(void) 537 558 { … … 547 568 548 569 /* Clear any other DnD specific data on the proxy window. */ 549 wndXDnDClear TypeList(m_wndProxy);570 wndXDnDClearFormatList(m_wndProxy); 550 571 wndXDnDClearActionList(m_wndProxy); 551 572 … … 560 581 } 561 582 562 int DragInstance::init(uint32_t u32ScreenId) 583 /** 584 * Initializes this drag instance. 585 * 586 * @return IPRT status code. 587 * @param u32ScreenID X' screen ID to use. 588 */ 589 int DragInstance::init(uint32_t u32ScreenID) 563 590 { 564 591 int rc; … … 583 610 * Enough screens configured in the x11 server? 584 611 */ 585 if ((int)u32ScreenI d> ScreenCount(m_pDisplay))612 if ((int)u32ScreenID > ScreenCount(m_pDisplay)) 586 613 { 587 614 rc = VERR_INVALID_PARAMETER; … … 597 624 } 598 625 #endif 599 m_screenId = u32ScreenI d;626 m_screenId = u32ScreenID; 600 627 601 628 /* Now query the corresponding root window of this screen. */ … … 620 647 #ifdef VBOX_DND_DEBUG_WND 621 648 attr.background_pixel = XWhitePixel(m_pDisplay, m_screenId); 622 attr.border_pixel = XBlackPixel(m_pDisplay, m_screenId); 649 attr.border_pixel = XBlackPixel(m_pDisplay, m_screenId); 623 650 m_wndProxy = XCreateWindow(m_pDisplay, m_wndRoot /* Parent */, 624 651 100, 100, /* Position */ … … 628 655 InputOutput, /* Class */ 629 656 CopyFromParent, /* Visual */ 630 CWBackPixel 657 CWBackPixel 631 658 | CWBorderPixel 632 659 | CWOverrideRedirect 633 660 | CWDontPropagate, /* Value mask */ 634 &attr); /* Attributes for value mask */ 661 &attr); /* Attributes for value mask */ 635 662 #else 636 663 m_wndProxy = XCreateWindow(m_pDisplay, m_wndRoot /* Parent */, … … 674 701 else 675 702 LogRel(("DnD: Initializing drag instance for screen %RU32 failed with rc=%Rrc\n", 676 u32ScreenI d, rc));703 u32ScreenID, rc)); 677 704 678 705 LogFlowFuncLeaveRC(rc); … … 680 707 } 681 708 709 /** 710 * Logs an error message to the (release) logging instance. 711 * 712 * @param pszFormat Format string to log. 713 */ 682 714 VBOX_DND_FN_DECL_LOG(void) DragInstance::logError(const char *pszFormat, ...) 683 715 { … … 695 727 } 696 728 729 /** 730 * Callback handler for a generic client message from a window. 731 * 732 * @return IPRT status code. 733 * @param e X11 event to handle. 734 */ 697 735 int DragInstance::onX11ClientMessage(const XEvent &e) 698 736 { … … 708 746 case HG: 709 747 { 710 /* 748 /* 711 749 * Client messages are used to inform us about the status of a XdndAware 712 * window, in response of some events we send to them. 713 */ 750 * window, in response of some events we send to them. 751 */ 714 752 if ( e.xclient.message_type == xAtom(XA_XdndStatus) 715 753 && m_wndCur == static_cast<Window>(e.xclient.data.l[0])) 716 754 { 717 /* 755 /* 718 756 * The XdndStatus message tell us if the window will accept the DnD 719 757 * event and with which action. We immediately send this info down to 720 * the host as a response of a previous DnD message. 721 */ 758 * the host as a response of a previous DnD message. 759 */ 722 760 LogFlowThisFunc(("XA_XdndStatus: wnd=%#x, accept=%RTbool, action=%s\n", 723 761 e.xclient.data.l[0], … … 761 799 break; 762 800 } 763 801 764 802 default: 765 803 { … … 774 812 } 775 813 814 /** 815 * Callback handler for a XDnD selection notify from a window. This is needed 816 * to let the us know if a certain window has drag'n drop data to share with us, 817 * e.g. our proxy window. 818 * 819 * @return IPRT status code. 820 * @param e X11 event to handle. 821 */ 776 822 int DragInstance::onX11SelectionNotify(const XEvent &e) 777 823 { … … 807 853 } 808 854 855 /** 856 * Callback handler for a XDnD selection request from a window. This is needed 857 * to retrieve the data required to complete the actual drag'n drop operation. 858 * 859 * @returns IPRT status code. 860 * @param e X11 event to handle. 861 */ 809 862 int DragInstance::onX11SelectionRequest(const XEvent &e) 810 863 { … … 846 899 if (e.xselectionrequest.target == xAtom(XA_TARGETS)) 847 900 { 848 LogFlowThisFunc(("wnd=%#x '%s' asking for target list\n", 901 LogFlowThisFunc(("wnd=%#x '%s' asking for target list\n", 849 902 e.xselectionrequest.requestor, propName.value)); 850 903 … … 852 905 * window. */ 853 906 rc = wndXDnDSetFormatList(e.xselectionrequest.requestor, e.xselectionrequest.property, m_lstFormats); 854 if (RT_SUCCESS(rc)) 907 if (RT_SUCCESS(rc)) 855 908 { 856 909 atmTarget = e.xselectionrequest.target; … … 864 917 { 865 918 LogFlowThisFunc(("wnd=%#x '%s' asking for data, format=%s\n", 866 e.xselectionrequest.requestor, propName.value, 919 e.xselectionrequest.requestor, propName.value, 867 920 xAtomToString(e.xselectionrequest.target).c_str())); 868 921 … … 880 933 else 881 934 { 882 LogFlowThisFunc(("Saving selection notify message of wnd=%#x '%s'\n", 935 LogFlowThisFunc(("Saving selection notify message of wnd=%#x '%s'\n", 883 936 e.xselectionrequest.requestor, propName.value)); 884 937 … … 941 994 } 942 995 996 /** 997 * Handles X11 events, called by x11EventThread. 998 * 999 * @returns IPRT status code. 1000 * @param e X11 event to handle. 1001 */ 943 1002 int DragInstance::onX11Event(const XEvent &e) 944 1003 { … … 990 1049 991 1050 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 1051 /** 1052 * Waits for an X11 event of a specific type. 1053 * 1054 * @returns IPRT status code. 1055 * @param evX Reference where to store the event into. 1056 * @param iType Event type to wait for. 1057 * @param uTimeoutMS Timeout (in ms) to wait for the event. 1058 */ 992 1059 bool DragInstance::waitForX11Msg(XEvent &evX, int iType, RTMSINTERVAL uTimeoutMS /* = 100 */) 993 1060 { … … 1039 1106 } 1040 1107 1108 /** 1109 * Waits for an X11 client message of a specific type. 1110 * 1111 * @returns IPRT status code. 1112 * @param evMsg Reference where to store the event into. 1113 * @param aType Event type to wait for. 1114 * @param uTimeoutMS Timeout (in ms) to wait for the event. 1115 */ 1041 1116 bool DragInstance::waitForX11ClientMsg(XClientMessageEvent &evMsg, Atom aType, 1042 1117 RTMSINTERVAL uTimeoutMS /*= 100 */) … … 1058 1133 if (e.type == ClientMessage) 1059 1134 { 1135 /** @todo Check is aType matches the event's type! */ 1136 1060 1137 m_eventQueue.removeAt(i); 1061 1138 evMsg = e.xclient; … … 1094 1171 */ 1095 1172 1096 int DragInstance::hgEnter(const RTCList<RTCString> &formats, uint32_t uActions) 1173 /** 1174 * Host -> Guest: Event signalling that the host's (mouse) cursor just entered the VM's (guest's) display 1175 * area. 1176 * 1177 * @returns IPRT status code. 1178 * @param lstFormats List of supported formats from the host. 1179 * @param uActions (ORed) List of supported actions from the host. 1180 */ 1181 int DragInstance::hgEnter(const RTCList<RTCString> &lstFormats, uint32_t uActions) 1097 1182 { 1098 1183 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState)); 1099 1184 1100 if (m_enmMode != Unknown) 1185 if (m_enmMode != Unknown) 1101 1186 return VERR_INVALID_STATE; 1102 1187 … … 1104 1189 1105 1190 #ifdef DEBUG 1106 LogFlowThisFunc(("uActions=0x%x, lstFormats=%zu: ", uActions, formats.size()));1107 for (size_t i = 0; i < formats.size(); ++i)1108 LogFlow(("'%s' ", formats.at(i).c_str()));1191 LogFlowThisFunc(("uActions=0x%x, lstFormats=%zu: ", uActions, lstFormats.size())); 1192 for (size_t i = 0; i < lstFormats.size(); ++i) 1193 LogFlow(("'%s' ", lstFormats.at(i).c_str())); 1109 1194 LogFlow(("\n")); 1110 1195 #endif … … 1114 1199 do 1115 1200 { 1116 rc = toAtomList( formats, m_lstFormats);1201 rc = toAtomList(lstFormats, m_lstFormats); 1117 1202 if (RT_FAILURE(rc)) 1118 1203 break; … … 1145 1230 } 1146 1231 1232 /** 1233 * Host -> Guest: Event signalling that the host's (mouse) cursor has left the VM's (guest's) 1234 * display area. 1235 */ 1147 1236 int DragInstance::hgLeave(void) 1148 1237 { 1149 if (m_enmMode == HG) 1238 if (m_enmMode == HG) /* Only reset if in the right operation mode. */ 1150 1239 reset(); 1151 1240 … … 1153 1242 } 1154 1243 1155 int DragInstance::hgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t uAction) 1244 /** 1245 * Host -> Guest: Event signalling that the host's (mouse) cursor has been moved within the VM's 1246 * (guest's) display area. 1247 * 1248 * @returns IPRT status code. 1249 * @param u32xPos Relative X position within the guest's display area. 1250 * @param u32yPos Relative Y position within the guest's display area. 1251 * @param uDefaultAction Default action the host wants to perform on the guest 1252 * as soon as the operation successfully finishes. 1253 */ 1254 int DragInstance::hgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t uDefaultAction) 1156 1255 { 1157 1256 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState)); 1158 LogFlowThisFunc(("u32xPos=%RU32, u32yPos=%RU32, uAction=%RU32\n", u32xPos, u32yPos, u Action));1257 LogFlowThisFunc(("u32xPos=%RU32, u32yPos=%RU32, uAction=%RU32\n", u32xPos, u32yPos, uDefaultAction)); 1159 1258 1160 1259 if ( m_enmMode != HG … … 1212 1311 1213 1312 /* 1214 * Is the window under the cursor another one than our current one? 1215 * Cancel the current drop. 1313 * Is the window under the cursor another one than our current one? 1314 * Cancel the current drop. 1216 1315 */ 1217 1316 if ( wndCursor != m_wndCur … … 1280 1379 * Send a XdndPosition event with the proposed action to the guest. 1281 1380 */ 1282 Atom pa = toAtomAction(u Action);1381 Atom pa = toAtomAction(uDefaultAction); 1283 1382 LogFlowThisFunc(("strAction=%s\n", xAtomToString(pa).c_str())); 1284 1383 … … 1316 1415 } 1317 1416 1417 /** 1418 * Host -> Guest: Event signalling that the host has dropped the data over the VM (guest) window. 1419 * 1420 * @returns IPRT status code. 1421 */ 1318 1422 int DragInstance::hgDrop(void) 1319 1423 { … … 1328 1432 int rc = VINF_SUCCESS; 1329 1433 1330 /* 1434 /* 1331 1435 * Send a drop event to the current window and reset our DnD status. 1332 1436 */ … … 1354 1458 } 1355 1459 1356 int DragInstance::hgDataReceived(void *pvData, uint32_t cbData) 1460 /** 1461 * Host -> Guest: Event signalling that the host has sent drag'n drop (MIME) data 1462 * to the guest for further processing. 1463 * 1464 * @returns IPRT status code. 1465 * @param pvData Pointer to (MIME) data from host. 1466 * @param cbData Size (in bytes) of data from host. 1467 */ 1468 int DragInstance::hgDataReceived(const void *pvData, uint32_t cbData) 1357 1469 { 1358 1470 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState)); … … 1416 1528 1417 1529 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 1530 /** 1531 * Guest -> Host: Event signalling that the host is asking whether there is a pending 1532 * drag event on the guest (to the host). 1533 * 1534 * @returns IPRT status code. 1535 */ 1418 1536 int DragInstance::ghIsDnDPending(void) 1419 1537 { … … 1483 1601 else 1484 1602 { 1485 rc = wndXDnDGet TypeList(wndSelection, m_lstFormats);1603 rc = wndXDnDGetFormatList(wndSelection, m_lstFormats); 1486 1604 } 1487 1605 … … 1490 1608 */ 1491 1609 rc = wndXDnDGetActionList(wndSelection, m_lstActions); 1492 1610 1493 1611 fAcceptDrop = true; 1494 1612 } … … 1546 1664 } 1547 1665 1666 /** 1667 * Guest -> Host: Event signalling that the host has dropped the item(s) on the 1668 * host side. 1669 * 1670 * @returns IPRT status code. 1671 * @param strFormat Requested format to send to the host. 1672 * @param uAction Requested action to perform on the guest. 1673 */ 1548 1674 int DragInstance::ghDropped(const RTCString &strFormat, uint32_t uAction) 1549 1675 { 1550 LogFlowThisFunc(("mode=%RU32, state=%RU32, strFormat=%s, uAction=%RU32\n", 1676 LogFlowThisFunc(("mode=%RU32, state=%RU32, strFormat=%s, uAction=%RU32\n", 1551 1677 m_enmMode, m_enmState, strFormat.c_str(), uAction)); 1552 1678 … … 1577 1703 1 /* Button */, false /* fPress */); 1578 1704 1579 /** 1705 /** 1580 1706 * The fake button release event above should lead to a XdndDrop event from the 1581 1707 * source. Because of showing our proxy window, other Xdnd events can 1582 1708 * occur before, e.g. a XdndPosition event. We are not interested 1583 * in those, so just try to get the right one. 1584 */ 1709 * in those, so just try to get the right one. 1710 */ 1585 1711 1586 1712 XClientMessageEvent evDnDDrop; … … 1627 1753 &aPropType, &iPropFormat, &cItems, &cbRemaining, &pcData); 1628 1754 if (RT_UNLIKELY(xRc != Success)) 1629 LogFlowThisFunc(("Error getting XA_XdndSelection property of proxy window=%#x: %s\n", 1755 LogFlowThisFunc(("Error getting XA_XdndSelection property of proxy window=%#x: %s\n", 1630 1756 m_wndProxy, gX11->xErrorToString(xRc).c_str())); 1631 1757 … … 1680 1806 m.data.l[0] = m_wndProxy; /* Target window. */ 1681 1807 m.data.l[1] = 0; /* Don't accept the drop to not make the guest stuck. */ 1682 m.data.l[2] = RT_SUCCESS(rc) 1808 m.data.l[2] = RT_SUCCESS(rc) 1683 1809 ? toAtomAction(uAction) : None; /* Action used on success */ 1684 1810 1685 1811 xRc = XSendEvent(m_pDisplay, wndSource, True, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1686 1812 if (RT_UNLIKELY(xRc == 0)) 1687 LogFlowThisFunc(("Error sending XA_XdndFinished event to proxy window=%#x: %s\n", 1813 LogFlowThisFunc(("Error sending XA_XdndFinished event to proxy window=%#x: %s\n", 1688 1814 m_wndProxy, gX11->xErrorToString(xRc).c_str())); 1689 1815 } … … 1763 1889 */ 1764 1890 1891 /** 1892 * Moves the mouse pointer to a specific position. 1893 * 1894 * @returns IPRT status code. 1895 * @param iPosX Absolute X coordinate. 1896 * @param iPosY Absolute Y coordinate. 1897 */ 1765 1898 int DragInstance::mouseCursorMove(int iPosX, int iPosY) const 1766 1899 { … … 1782 1915 } 1783 1916 1917 /** 1918 * Sends a mouse button event to a specific window. 1919 * 1920 * @param wndDest Window to send the mouse button event to. 1921 * @param rx X coordinate relative to the root window's origin. 1922 * @param ry Y coordinate relative to the root window's origin. 1923 * @param iButton Mouse button to press/release. 1924 * @param fPress Whether to press or release the mouse button. 1925 */ 1784 1926 void DragInstance::mouseButtonSet(Window wndDest, int rx, int ry, int iButton, bool fPress) 1785 1927 { … … 1849 1991 } 1850 1992 1993 /** 1994 * Shows the (invisible) proxy window. The proxy window is needed for intercepting 1995 * drags from the host to the guest or from the guest to the host. It acts as a proxy 1996 * between the host and the actual (UI) element on the guest OS. 1997 * 1998 * To not make it miss any actions this window gets spawned across the entire guest 1999 * screen (think of an umbrella) to (hopefully) capture everything. A proxy window 2000 * which follows the cursor would be far too slow here. 2001 * 2002 * @returns IPRT status code. 2003 * @param piRootX X coordinate relative to the root window's origin. Optional. 2004 * @param piRootY Y coordinate relative to the root window's origin. Optional. 2005 * @param fMouseMove Whether to move the mouse cursor to the root window's origin or not. 2006 */ 1851 2007 int DragInstance::proxyWinShow(int *piRootX /*= NULL*/, 1852 2008 int *piRootY /*= NULL*/, … … 1860 2016 int rc = VINF_SUCCESS; 1861 2017 1862 #if 0 2018 #if 0 1863 2019 XTestGrabControl(m_pDisplay, False); 1864 2020 #endif … … 1898 2054 XSynchronize(m_pDisplay, False /* Disable sync */); 1899 2055 1900 #if 0 2056 #if 0 1901 2057 XTestGrabControl(m_pDisplay, True); 1902 2058 #endif … … 1905 2061 } 1906 2062 2063 /** 2064 * Hides the (invisible) proxy window. 2065 */ 1907 2066 int DragInstance::proxyWinHide(void) 1908 2067 { … … 1917 2076 } 1918 2077 2078 /** 2079 * Clear a window's supported/accepted actions list. 2080 * 2081 * @param wndThis Window to clear the list for. 2082 */ 1919 2083 void DragInstance::wndXDnDClearActionList(Window wndThis) const 1920 2084 { … … 1922 2086 } 1923 2087 1924 void DragInstance::wndXDnDClearTypeList(Window wndThis) const 2088 /** 2089 * Clear a window's supported/accepted formats list. 2090 * 2091 * @param wndThis Window to clear the list for. 2092 */ 2093 void DragInstance::wndXDnDClearFormatList(Window wndThis) const 1925 2094 { 1926 2095 XDeleteProperty(m_pDisplay, wndThis, xAtom(XA_XdndTypeList)); 1927 2096 } 1928 2097 2098 /** 2099 * Retrieves a window's supported/accepted XDnD actions. 2100 * 2101 * @returns IPRT status code. 2102 * @param wndThis Window to retrieve the XDnD actions for. 2103 * @param lstActions Reference to VBoxDnDAtomList to store the action into. 2104 */ 1929 2105 int DragInstance::wndXDnDGetActionList(Window wndThis, VBoxDnDAtomList &lstActions) const 1930 2106 { … … 1941 2117 if (xRc != Success) 1942 2118 { 1943 LogFlowThisFunc(("Error getting XA_XdndActionList atoms from window=%#x: %s\n", 2119 LogFlowThisFunc(("Error getting XA_XdndActionList atoms from window=%#x: %s\n", 1944 2120 wndThis, gX11->xErrorToString(xRc).c_str())); 1945 2121 return VERR_NOT_FOUND; 1946 2122 } 1947 2123 1948 if ( cItems > 0 2124 if ( cItems > 0 1949 2125 && pcbData) 1950 2126 { … … 1965 2141 } 1966 2142 1967 int DragInstance::wndXDnDGetTypeList(Window wndThis, VBoxDnDAtomList &lstTypes) const 2143 /** 2144 * Retrieves a window's supported/accepted XDnD formats. 2145 * 2146 * @returns IPRT status code. 2147 * @param wndThis Window to retrieve the XDnD formats for. 2148 * @param lstTypes Reference to VBoxDnDAtomList to store the formats into. 2149 */ 2150 int DragInstance::wndXDnDGetFormatList(Window wndThis, VBoxDnDAtomList &lstTypes) const 1968 2151 { 1969 2152 Atom iActType = None; … … 1978 2161 if (xRc != Success) 1979 2162 { 1980 LogFlowThisFunc(("Error getting XA_XdndTypeList atoms from window=%#x: %s\n", 2163 LogFlowThisFunc(("Error getting XA_XdndTypeList atoms from window=%#x: %s\n", 1981 2164 wndThis, gX11->xErrorToString(xRc).c_str())); 1982 2165 return VERR_NOT_FOUND; 1983 2166 } 1984 2167 1985 if ( cItems > 0 2168 if ( cItems > 0 1986 2169 && pcbData) 1987 2170 { … … 2002 2185 } 2003 2186 2187 /** 2188 * Sets (replaces) a window's XDnD accepted/allowed actions. 2189 * 2190 * @returns IPRT status code. 2191 * @param wndThis Window to set the format list for. 2192 * @param lstActions Reference to list of XDnD actions to set. 2193 * 2194 * @remark 2195 */ 2004 2196 int DragInstance::wndXDnDSetActionList(Window wndThis, const VBoxDnDAtomList &lstActions) const 2005 2197 { … … 2016 2208 } 2017 2209 2018 int DragInstance::wndXDnDSetFormatList(Window wndThis, Atom property, const VBoxDnDAtomList &lstFormats) const 2210 /** 2211 * Sets (replaces) a window's XDnD accepted format list. 2212 * 2213 * @returns IPRT status code. 2214 * @param wndThis Window to set the format list for. 2215 * @param atmProp Property to set. 2216 * @param lstFormats Reference to list of XDnD formats to set. 2217 */ 2218 int DragInstance::wndXDnDSetFormatList(Window wndThis, Atom atmProp, const VBoxDnDAtomList &lstFormats) const 2019 2219 { 2020 2220 if (lstFormats.isEmpty()) … … 2027 2227 2028 2228 /* Add the property with the property data to the window. */ 2029 XChangeProperty(m_pDisplay, wndThis, property,2229 XChangeProperty(m_pDisplay, wndThis, atmProp, 2030 2230 XA_ATOM, 32, PropModeReplace, 2031 2231 reinterpret_cast<const unsigned char*>(lstFormatsExt.raw()), … … 2035 2235 } 2036 2236 2237 /** 2238 * Converts a RTCString list to VBoxDnDAtomList list. 2239 * 2240 * @returns IPRT status code. 2241 * @param lstFormats Reference to RTCString list to convert. 2242 * @param lstAtoms Reference to VBoxDnDAtomList list to store results in. 2243 */ 2037 2244 int DragInstance::toAtomList(const RTCList<RTCString> &lstFormats, VBoxDnDAtomList &lstAtoms) const 2038 { 2245 { 2039 2246 for (size_t i = 0; i < lstFormats.size(); ++i) 2040 2247 lstAtoms.append(XInternAtom(m_pDisplay, lstFormats.at(i).c_str(), False)); … … 2043 2250 } 2044 2251 2252 /** 2253 * Converts a raw-data string list to VBoxDnDAtomList list. 2254 * 2255 * @returns IPRT status code. 2256 * @param pvData Pointer to string data to convert. 2257 * @param cbData Size (in bytes) to convert. 2258 * @param lstAtoms Reference to VBoxDnDAtomList list to store results in. 2259 */ 2045 2260 int DragInstance::toAtomList(const void *pvData, uint32_t cbData, VBoxDnDAtomList &lstAtoms) const 2046 2261 { … … 2053 2268 int rc = VINF_SUCCESS; 2054 2269 2055 RTCList<Atom>lstAtom;2270 VBoxDnDAtomList lstAtom; 2056 2271 while (cbStr) 2057 2272 { … … 2077 2292 } 2078 2293 2294 /** 2295 * Converts a HGCM-based drag'n drop action to a Atom-based drag'n drop action. 2296 * 2297 * @returns Converted Atom-based drag'n drop action. 2298 * @param uActions HGCM drag'n drop actions to convert. 2299 */ 2079 2300 /* static */ 2080 2301 Atom DragInstance::toAtomAction(uint32_t uAction) … … 2087 2308 } 2088 2309 2310 /** 2311 * Converts HGCM-based drag'n drop actions to a VBoxDnDAtomList list. 2312 * 2313 * @returns IPRT status code. 2314 * @param uActions HGCM drag'n drop actions to convert. 2315 * @param lstAtoms Reference to VBoxDnDAtomList to store actions in. 2316 */ 2089 2317 /* static */ 2090 2318 int DragInstance::toAtomActions(uint32_t uActions, VBoxDnDAtomList &lstAtoms) … … 2100 2328 } 2101 2329 2330 /** 2331 * Converts an Atom-based drag'n drop action to a HGCM drag'n drop action. 2332 * 2333 * @returns HGCM drag'n drop action. 2334 * @param atom Atom-based drag'n drop action to convert. 2335 */ 2102 2336 /* static */ 2103 2337 uint32_t DragInstance::toHGCMAction(Atom atom) … … 2115 2349 } 2116 2350 2351 /** 2352 * Converts an VBoxDnDAtomList list to an HGCM action list. 2353 * 2354 * @returns ORed HGCM action list. 2355 * @param actionsList List of Atom-based actions to convert. 2356 */ 2117 2357 /* static */ 2118 uint32_t DragInstance::toHGCMActions(const RTCList<Atom> &actionsList)2358 uint32_t DragInstance::toHGCMActions(const VBoxDnDAtomList &lstActions) 2119 2359 { 2120 2360 uint32_t uActions = DND_IGNORE_ACTION; 2121 2361 2122 for (size_t i = 0; i < actionsList.size(); ++i)2123 uActions |= toHGCMAction( actionsList.at(i));2362 for (size_t i = 0; i < lstActions.size(); ++i) 2363 uActions |= toHGCMAction(lstActions.at(i)); 2124 2364 2125 2365 return uActions; 2126 }2127 2128 /** @todo Replace by DnDURIList? */2129 RTCList<RTCString> toStringList(const void *pvData, uint32_t cbData)2130 {2131 if ( !pvData2132 || !cbData)2133 return RTCList<RTCString>();2134 2135 const char *pszStr = (char*)pvData;2136 uint32_t cbStr = cbData;2137 2138 RTCList<RTCString> lstString;2139 while (cbStr > 0)2140 {2141 size_t cbSize = RTStrNLen(pszStr, cbStr);2142 2143 /* Create a copy with max N chars, so that we are on the save side,2144 * even if the data isn't zero terminated. */2145 char *pszTmp = RTStrDupN(pszStr, cbSize);2146 lstString.append(pszTmp);2147 RTStrFree(pszTmp);2148 pszStr += cbSize + 1;2149 cbStr -= cbSize + 1;2150 }2151 2152 return lstString;2153 }2154 2155 /** @todo Is this function really needed? */2156 void DragAndDropService::clearEventQueue(void)2157 {2158 LogFlowThisFuncEnter();2159 m_eventQueue.clear();2160 2366 } 2161 2367 … … 2164 2370 ******************************************************************************/ 2165 2371 2372 /** 2373 * Main loop for the drag and drop service which does the HGCM message 2374 * processing and routing to the according drag and drop instance(s). 2375 * 2376 * @returns IPRT status code. 2377 * @param fDaemonised Whether to run in daemonized or not. Does not 2378 * apply for this service. 2379 */ 2166 2380 int DragAndDropService::run(bool fDaemonised /* = false */) 2167 2381 { … … 2171 2385 do 2172 2386 { 2173 /* Initialize X11 DnD. */2174 rc = x11DragAndDropInit();2387 /* Initialize drag and drop. */ 2388 rc = dragAndDropInit(); 2175 2389 if (RT_FAILURE(rc)) 2176 2390 break; … … 2271 2485 LogFlowFunc(("Message %RU32 processed with %Rrc\n", e.hgcm.uType, rc)); 2272 2486 if ( RT_FAILURE(rc) 2273 /* 2274 * Note: The hgXXX and ghXXX functions of the DnD instance above may return 2487 /* 2488 * Note: The hgXXX and ghXXX functions of the DnD instance above may return 2275 2489 * VERR_INVALID_STATE in case we're not in the expected state they want 2276 2490 * to operate in. As the user might drag content back and forth to/from … … 2324 2538 * Make sure that any X11 requests have actually been sent to the 2325 2539 * server, since we are waiting for responses using poll() on 2326 * another thread which will not automatically trigger flushing. 2327 */ 2540 * another thread which will not automatically trigger flushing. 2541 */ 2328 2542 XFlush(m_pDisplay); 2329 2543 … … 2336 2550 } 2337 2551 2338 int DragAndDropService::x11DragAndDropInit(void) 2552 /** 2553 * Initializes the drag and drop instance. 2554 * 2555 * @returns IPRT status code. 2556 */ 2557 int DragAndDropService::dragAndDropInit(void) 2339 2558 { 2340 2559 /* Initialise the guest library. */ 2341 2560 int rc = VbglR3InitUser(); 2342 2561 if (RT_FAILURE(rc)) 2343 VBClFatalError((" Failed to connect to the VirtualBox kernel service, rc=%Rrc\n", rc));2562 VBClFatalError(("DnD: Failed to connect to the VirtualBox kernel service, rc=%Rrc\n", rc)); 2344 2563 2345 2564 /* Connect to the x11 server. */ … … 2384 2603 } 2385 2604 2605 /** 2606 * Static callback function for HGCM message processing thread. An internal 2607 * message queue will be filled which then will be processed by the according 2608 * drag'n drop instance. 2609 * 2610 * @returns IPRT status code. 2611 * @param hThread Thread handle to use. 2612 * @param pvUser Pointer to DragAndDropService instance to use. 2613 */ 2386 2614 /* static */ 2387 2615 int DragAndDropService::hgcmEventThread(RTTHREAD hThread, void *pvUser) … … 2446 2674 } 2447 2675 2676 /** 2677 * Static callback function for X11 message processing thread. All X11 messages 2678 * will be directly routed to the according drag'n drop instance. 2679 * 2680 * @returns IPRT status code. 2681 * @param hThread Thread handle to use. 2682 * @param pvUser Pointer to DragAndDropService instance to use. 2683 */ 2448 2684 /* static */ 2449 2685 int DragAndDropService::x11EventThread(RTTHREAD hThread, void *pvUser)
Note:
See TracChangeset
for help on using the changeset viewer.