Changeset 56651 in vbox
- Timestamp:
- Jun 26, 2015 8:27:05 AM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp
r56322 r56651 24 24 25 25 #include <iprt/asm.h> 26 #include <iprt/buildconfig.h> 26 27 #include <iprt/critsect.h> 27 28 #include <iprt/thread.h> … … 51 52 52 53 /** 53 * For X11 guest xDnDis used. See http://www.acc.umu.se/~vatten/XDND.html for54 * For X11 guest Xdnd is used. See http://www.acc.umu.se/~vatten/XDND.html for 54 55 * a walk trough. 55 56 * … … 125 126 XA_text_plain, 126 127 XA_TEXT, 127 /* xDnD*/128 /* Xdnd */ 128 129 XA_XdndSelection, 129 130 XA_XdndAware, … … 145 146 }; 146 147 148 /** 149 * Xdnd message value indexes, sorted by message type. 150 */ 151 typedef enum XdndMsg 152 { 153 /** XdndEnter. */ 154 XdndEnterTypeCount = 3, /* Maximum number of types in XdndEnter message. */ 155 156 XdndEnterWindow = 0, /* Source window (sender). */ 157 XdndEnterFlags, /* Version in high byte, bit 0 => more data types. */ 158 XdndEnterType1, /* First available data type. */ 159 XdndEnterType2, /* Second available data type. */ 160 XdndEnterType3, /* Third available data type. */ 161 162 XdndEnterMoreTypesFlag = 1, /* Set if there are more than XdndEnterTypeCount. */ 163 XdndEnterVersionRShift = 24, /* Right shift to position version number. */ 164 XdndEnterVersionMask = 0xFF, /* Mask to get version after shifting. */ 165 166 /** XdndHere. */ 167 XdndHereWindow = 0, /* Source window (sender). */ 168 XdndHereFlags, /* Reserved. */ 169 XdndHerePt, /* X + Y coordinates of mouse (root window coords). */ 170 XdndHereTimeStamp, /* Timestamp for requesting data. */ 171 XdndHereAction, /* Action requested by user. */ 172 173 /** XdndPosition. */ 174 XdndPositionWindow = 0, /* Source window (sender). */ 175 XdndPositionFlags, /* Flags. */ 176 XdndPositionCoords, /* X/Y coordinates of the mouse position relative to the root window. */ 177 XdndPositionTimeStamp, /* Time stamp for retrieving the data. */ 178 XdndPositionAction, /* Action requested by the user. */ 179 180 /** XdndStatus. */ 181 XdndStatusWindow = 0, /* Target window (sender).*/ 182 XdndStatusFlags, /* Flags returned by target. */ 183 XdndStatusPt, /* X + Y of "no msg" rectangle (root window coords). */ 184 XdndStatusArea, /* Width + height of "no msg" rectangle. */ 185 XdndStatusAction, /* Action accepted by target. */ 186 187 XdndStatusAcceptDropFlag = 1, /* Set if target will accept the drop. */ 188 XdndStatusSendHereFlag = 2, /* Set if target wants a stream of XdndPosition. */ 189 190 /** XdndLeave. */ 191 XdndLeaveWindow = 0, /* Source window (sender). */ 192 XdndLeaveFlags, /* Reserved. */ 193 194 /** XdndDrop. */ 195 XdndDropWindow = 0, /* Source window (sender). */ 196 XdndDropFlags, /* Reserved. */ 197 XdndDropTimeStamp, /* Timestamp for requesting data. */ 198 199 /** XdndFinished. */ 200 XdndFinishedWindow = 0, /* Target window (sender). */ 201 XdndFinishedFlags, /* Version 5: Bit 0 is set if the current target accepted the drop. */ 202 XdndFinishedAction /* Version 5: Contains the action performed by the target. */ 203 204 } XdndMsg; 205 147 206 class DragAndDropService; 148 207 … … 249 308 "text/plain", 250 309 "TEXT", 251 /* xDnD*/310 /* Xdnd */ 252 311 "XdndSelection", 253 312 "XdndAware", … … 302 361 Window wndApp = 0; 303 362 int cProps = -1; 363 304 364 /* Fetch all x11 window properties of the parent window. */ 305 365 Atom *pProps = XListProperties(m_pDisplay, wndParent, &cProps); … … 308 368 /* We check the window for the WM_STATE property. */ 309 369 for (int i = 0; i < cProps; ++i) 370 { 310 371 if (pProps[i] == xAtom(XA_WM_STATE)) 311 372 { … … 314 375 break; 315 376 } 377 } 378 316 379 /* Cleanup */ 317 380 XFree(pProps); … … 383 446 384 447 /* Logging. */ 448 VBOX_DND_FN_DECL_LOG(void) logInfo(const char *pszFormat, ...); 385 449 VBOX_DND_FN_DECL_LOG(void) logError(const char *pszFormat, ...); 386 450 387 451 /* X11 message processing. */ 388 452 int onX11ClientMessage(const XEvent &e); 453 int onX11MotionNotify(const XEvent &e); 454 int onX11SelectionClear(const XEvent &e); 389 455 int onX11SelectionNotify(const XEvent &e); 390 456 int onX11SelectionRequest(const XEvent &e); 391 457 int onX11Event(const XEvent &e); 458 int waitForStatusChange(uint32_t enmState, RTMSINTERVAL uTimeoutMS = 30000); 392 459 bool waitForX11Msg(XEvent &evX, int iType, RTMSINTERVAL uTimeoutMS = 100); 393 460 bool waitForX11ClientMsg(XClientMessageEvent &evMsg, Atom aType, RTMSINTERVAL uTimeoutMS = 100); … … 396 463 int hgEnter(const RTCList<RTCString> &formats, uint32_t actions); 397 464 int hgLeave(void); 398 int hgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t action);399 int hgDrop( void);465 int hgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t uDefaultAction); 466 int hgDrop(uint32_t u32xPos, uint32_t u32yPos, uint32_t uDefaultAction); 400 467 int hgDataReceived(const void *pvData, uint32_t cData); 401 468 … … 409 476 int mouseCursorMove(int iPosX, int iPosY) const; 410 477 void mouseButtonSet(Window wndDest, int rx, int ry, int iButton, bool fPress); 411 int proxyWinShow(int *piRootX = NULL, int *piRootY = NULL , bool fMouseMove = false) const;478 int proxyWinShow(int *piRootX = NULL, int *piRootY = NULL) const; 412 479 int proxyWinHide(void); 413 480 481 /* X11 window helpers. */ 482 char *wndX11GetNameA(Window wndThis) const; 483 484 /* Xdnd protocol helpers. */ 414 485 void wndXDnDClearActionList(Window wndThis) const; 415 486 void wndXDnDClearFormatList(Window wndThis) const; … … 419 490 int wndXDnDSetFormatList(Window wndThis, Atom atmProp, const VBoxDnDAtomList &lstFormats) const; 420 491 492 /* Atom / HGCM formatting helpers. */ 421 493 int toAtomList(const RTCList<RTCString> &lstFormats, VBoxDnDAtomList &lstAtoms) const; 422 494 int toAtomList(const void *pvData, uint32_t cbData, VBoxDnDAtomList &lstAtoms) const; … … 451 523 /** List of (Atom) actions the source window supports. */ 452 524 VBoxDnDAtomList m_lstActions; 453 /** Deferred host to guest selection event for sending to the 454 * target window as soon as data from the host arrived. */ 455 XEvent m_eventHgSelection; 525 /** Buffer for answering the target window's selection request. */ 526 void *m_pvSelReqData; 527 /** Size (in bytes) of selection request data buffer. */ 528 uint32_t m_cbSelReqData; 456 529 /** Current operation mode. */ 457 Modem_enmMode;530 volatile uint32_t m_enmMode; 458 531 /** Current state of operation mode. */ 459 Statem_enmState;532 volatile uint32_t m_enmState; 460 533 /** The instance's own X event queue. */ 461 RTCMTList<XEvent> m_eventQueue ;534 RTCMTList<XEvent> m_eventQueueList; 462 535 /** Critical section for providing serialized access to list 463 536 * event queue's contents. */ … … 465 538 /** Event for notifying this instance in case of a new 466 539 * event. */ 467 RTSEMEVENT m_hEventSem; 540 RTSEMEVENT m_eventQueueEvent; 541 /** Critical section for data access. */ 542 RTCRITSECT m_dataCS; 468 543 /** List of allowed formats. */ 469 544 RTCList<RTCString> m_lstAllowedFormats; … … 528 603 , m_wndCur(0) 529 604 , m_curVer(-1) 605 , m_pvSelReqData(NULL) 606 , m_cbSelReqData(0) 530 607 , m_enmMode(Unknown) 531 608 , m_enmState(Uninitialized) 532 609 { 533 uninit();534 610 } 535 611 … … 539 615 void DragInstance::uninit(void) 540 616 { 541 reset(); 617 LogFlowFuncEnter(); 618 542 619 if (m_wndProxy != 0) 543 620 XDestroyWindow(m_pDisplay, m_wndProxy); 544 621 545 VbglR3DnDDisconnect(&m_dndCtx); 546 547 m_enmState = Uninitialized; 548 m_screenId = -1; 549 m_pScreen = 0; 550 m_wndRoot = 0; 551 m_wndProxy = 0; 622 int rc2 = VbglR3DnDDisconnect(&m_dndCtx); 623 624 if (m_pvSelReqData) 625 RTMemFree(m_pvSelReqData); 626 627 rc2 = RTSemEventDestroy(m_eventQueueEvent); 628 AssertRC(rc2); 629 630 rc2 = RTCritSectDelete(&m_eventQueueCS); 631 AssertRC(rc2); 632 633 rc2 = RTCritSectDelete(&m_dataCS); 634 AssertRC(rc2); 552 635 } 553 636 … … 562 645 proxyWinHide(); 563 646 564 /* If we are currently the Xdnd selection owner, clear that. */ 565 Window w = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection)); 566 if (w == m_wndProxy) 567 XSetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection), None, CurrentTime); 568 569 /* Clear any other DnD specific data on the proxy window. */ 570 wndXDnDClearFormatList(m_wndProxy); 571 wndXDnDClearActionList(m_wndProxy); 572 573 /* Reset the internal state. */ 574 m_lstActions.clear(); 575 m_lstFormats.clear(); 576 m_wndCur = 0; 577 m_curVer = -1; 578 m_enmState = Initialized; 579 m_enmMode = Unknown; 580 m_eventQueue.clear(); 647 int rc2 = RTCritSectEnter(&m_dataCS); 648 if (RT_SUCCESS(rc2)) 649 { 650 /* If we are currently the Xdnd selection owner, clear that. */ 651 Window pWnd = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection)); 652 if (pWnd == m_wndProxy) 653 XSetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection), None, CurrentTime); 654 655 /* Clear any other DnD specific data on the proxy window. */ 656 wndXDnDClearFormatList(m_wndProxy); 657 wndXDnDClearActionList(m_wndProxy); 658 659 /* Reset the internal state. */ 660 m_lstActions.clear(); 661 m_lstFormats.clear(); 662 m_wndCur = 0; 663 m_curVer = -1; 664 m_enmState = Initialized; 665 m_enmMode = Unknown; 666 m_eventQueueList.clear(); 667 668 /* Reset the selection request buffer. */ 669 if (m_pvSelReqData) 670 { 671 RTMemFree(m_pvSelReqData); 672 m_pvSelReqData = NULL; 673 674 Assert(m_cbSelReqData); 675 m_cbSelReqData = 0; 676 } 677 678 RTCritSectLeave(&m_dataCS); 679 } 581 680 } 582 681 … … 593 692 do 594 693 { 595 uninit();596 597 694 rc = VbglR3DnDConnect(&m_dndCtx); 598 695 if (RT_FAILURE(rc)) 599 696 break; 600 697 601 rc = RTSemEventCreate(&m_ hEventSem);698 rc = RTSemEventCreate(&m_eventQueueEvent); 602 699 if (RT_FAILURE(rc)) 603 700 break; 604 701 605 702 rc = RTCritSectInit(&m_eventQueueCS); 703 if (RT_FAILURE(rc)) 704 break; 705 706 rc = RTCritSectInit(&m_dataCS); 606 707 if (RT_FAILURE(rc)) 607 708 break; … … 684 785 XFlush(m_pDisplay); 685 786 #endif 686 LogFlowThisFunc(("Created proxy window 0x%x at m_wndRoot=0x%x ...\n", m_wndProxy, m_wndRoot));787 logInfo("Proxy window=0x%x, root window=0x%x ...\n", m_wndProxy, m_wndRoot); 687 788 688 789 /* Set the window's name for easier lookup. */ … … 697 798 if (RT_SUCCESS(rc)) 698 799 { 699 m_enmState = Initialized;800 reset(); 700 801 } 701 802 else 702 LogRel(("DnD: Initializing drag instance for screen %RU32 failed with rc=%Rrc\n", 703 u32ScreenID, rc)); 803 logError("Initializing drag instance for screen %RU32 failed with rc=%Rrc\n", u32ScreenID, rc); 704 804 705 805 LogFlowFuncLeaveRC(rc); … … 722 822 AssertPtr(psz); 723 823 LogFlowFunc(("%s", psz)); 824 LogRel(("DnD: %s", psz)); 825 826 RTStrFree(psz); 827 } 828 829 /** 830 * Logs an info message to the (release) logging instance. 831 * 832 * @param pszFormat Format string to log. 833 */ 834 VBOX_DND_FN_DECL_LOG(void) DragInstance::logInfo(const char *pszFormat, ...) 835 { 836 va_list args; 837 va_start(args, pszFormat); 838 char *psz = NULL; 839 RTStrAPrintfV(&psz, pszFormat, args); 840 va_end(args); 841 842 AssertPtr(psz); 843 LogFlowFunc(("%s", psz)); 724 844 LogRel2(("DnD: %s", psz)); 725 845 … … 737 857 AssertReturn(e.type == ClientMessage, VERR_INVALID_PARAMETER); 738 858 739 LogFlowThisFunc(("mode=% d, state=%d\n", m_enmMode, m_enmState));859 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState)); 740 860 LogFlowThisFunc(("Event wnd=%#x, msg=%s\n", e.xclient.window, xAtomToString(e.xclient.message_type).c_str())); 741 861 742 int rc ;862 int rc = VINF_SUCCESS; 743 863 744 864 switch (m_enmMode) … … 751 871 */ 752 872 if ( e.xclient.message_type == xAtom(XA_XdndStatus) 753 && m_wndCur == static_cast<Window>(e.xclient.data.l[ 0]))873 && m_wndCur == static_cast<Window>(e.xclient.data.l[XdndStatusWindow])) 754 874 { 875 bool fAcceptDrop = ASMBitTest (&e.xclient.data.l[XdndStatusFlags], 0); /* Does the target accept the drop? */ 876 bool fWantsPosition = ASMBitTest (&e.xclient.data.l[XdndStatusFlags], 1); /* Does the target want XdndPosition messages? */ 877 RTCString strActions = xAtomToString( e.xclient.data.l[XdndStatusAction]); 878 879 char *pszWndName = wndX11GetNameA(e.xclient.data.l[XdndStatusWindow]); 880 AssertPtr(pszWndName); 881 755 882 /* 756 883 * The XdndStatus message tell us if the window will accept the DnD … … 758 885 * the host as a response of a previous DnD message. 759 886 */ 760 LogFlowThisFunc(("XA_XdndStatus: wnd=%#x, accept=%RTbool, action=%s\n", 761 e.xclient.data.l[0], 762 ASMBitTest(&e.xclient.data.l[1], 0), 763 xAtomToString(e.xclient.data.l[4]).c_str())); 764 765 uint32_t uAction = DND_IGNORE_ACTION; 887 LogFlowThisFunc(("XA_XdndStatus: wnd=%#x ('%s'), fAcceptDrop=%RTbool, fWantsPosition=%RTbool, strActions=%s\n", 888 e.xclient.data.l[XdndStatusWindow], pszWndName, fAcceptDrop, fWantsPosition, strActions.c_str())); 889 890 RTStrFree(pszWndName); 891 892 uint16_t x = RT_HI_U16((uint32_t)e.xclient.data.l[XdndStatusPt]); 893 uint16_t y = RT_LO_U16((uint32_t)e.xclient.data.l[XdndStatusPt]); 894 uint16_t w = RT_HI_U16((uint32_t)e.xclient.data.l[XdndStatusArea]); 895 uint16_t h = RT_LO_U16((uint32_t)e.xclient.data.l[XdndStatusArea]); 896 LogFlowThisFunc(("\tReported dead area: x=%RU16, y=%RU16, w=%RU16, h=%RU16\n", x, y, w, h)); 897 898 uint32_t uAction = DND_IGNORE_ACTION; /* Default is ignoring. */ 766 899 /** @todo Compare this with the allowed actions. */ 767 if ( ASMBitTest(&e.xclient.data.l[1], 0))768 uAction = toHGCMAction(static_cast<Atom>(e.xclient.data.l[ 4]));900 if (fAcceptDrop) 901 uAction = toHGCMAction(static_cast<Atom>(e.xclient.data.l[XdndStatusAction])); 769 902 770 903 rc = VbglR3DnDHGAcknowledgeOperation(&m_dndCtx, uAction); … … 772 905 else if (e.xclient.message_type == xAtom(XA_XdndFinished)) 773 906 { 774 rc = VINF_SUCCESS; 907 bool fSucceeded = ASMBitTest(&e.xclient.data.l[XdndFinishedFlags], 0); 908 909 char *pszWndName = wndX11GetNameA(e.xclient.data.l[XdndFinishedWindow]); 910 AssertPtr(pszWndName); 775 911 776 912 /* This message is sent on an un/successful DnD drop request. */ 777 LogFlowThisFunc(("XA_XdndFinished: wnd=%#x, success=%RTbool, action=%s\n", 778 e.xclient.data.l[0], 779 ASMBitTest(&e.xclient.data.l[1], 0), 780 xAtomToString(e.xclient.data.l[2]).c_str())); 781 782 proxyWinHide(); 913 LogFlowThisFunc(("XA_XdndFinished: wnd=%#x ('%s'), success=%RTbool, action=%s\n", 914 e.xclient.data.l[XdndFinishedWindow], pszWndName, fSucceeded, 915 xAtomToString(e.xclient.data.l[XdndFinishedAction]).c_str())); 916 917 RTStrFree(pszWndName); 918 919 reset(); 783 920 } 784 921 else 785 922 { 786 LogFlowThisFunc(("Unhandled: wnd=%#x, msg=%s\n", 787 e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str())); 923 char *pszWndName = wndX11GetNameA(e.xclient.data.l[0]); 924 AssertPtr(pszWndName); 925 LogFlowThisFunc(("Unhandled: wnd=%#x ('%s'), msg=%s\n", 926 e.xclient.data.l[0], pszWndName, xAtomToString(e.xclient.message_type).c_str())); 927 RTStrFree(pszWndName); 928 788 929 rc = VERR_NOT_SUPPORTED; 789 930 } … … 792 933 } 793 934 935 case Unknown: /* Mode not set (yet). */ 794 936 case GH: 795 case Unknown: /* Mode not set (yet), just add what we got. */796 937 { 797 m_eventQueue.append(e); 798 rc = RTSemEventSignal(m_hEventSem); 938 /* 939 * This message marks the beginning of a new drag and drop 940 * operation on the guest. 941 */ 942 if (e.xclient.message_type == xAtom(XA_XdndEnter)) 943 { 944 LogFlowFunc(("XA_XdndEnter\n")); 945 946 /* 947 * Get the window which currently has the XA_XdndSelection 948 * bit set. 949 */ 950 Window wndSelection = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection)); 951 952 char *pszWndName = wndX11GetNameA(wndSelection); 953 AssertPtr(pszWndName); 954 955 LogFlowThisFunc(("wndSelection=%#x ('%s'), wndProxy=%#x\n", wndSelection, pszWndName, m_wndProxy)); 956 957 RTStrFree(pszWndName); 958 959 mouseButtonSet(m_wndProxy, -1, -1, 1, true /* fPress */); 960 961 /* 962 * Update our state and the window handle to process. 963 */ 964 int rc2 = RTCritSectEnter(&m_dataCS); 965 if (RT_SUCCESS(rc2)) 966 { 967 m_wndCur = wndSelection; 968 m_curVer = e.xclient.data.l[XdndEnterFlags] >> XdndEnterVersionRShift; 969 Assert(m_wndCur == (Window)e.xclient.data.l[XdndEnterWindow]); /* Source window. */ 970 #ifdef DEBUG 971 XWindowAttributes xwa; 972 XGetWindowAttributes(m_pDisplay, m_wndCur, &xwa); 973 LogFlowThisFunc(("wndCur=%#x, x=%d, y=%d, width=%d, height=%d\n", m_wndCur, xwa.x, xwa.y, xwa.width, xwa.height)); 974 #endif 975 /* 976 * Retrieve supported formats. 977 */ 978 979 /* Check if the MIME types are in the message itself or if we need 980 * to fetch the XdndTypeList property from the window. */ 981 bool fMoreTypes = e.xclient.data.l[XdndEnterFlags] & XdndEnterMoreTypesFlag; 982 LogFlowThisFunc(("XdndVer=%d, fMoreTypes=%RTbool\n", m_curVer, fMoreTypes)); 983 if (!fMoreTypes) 984 { 985 /* Only up to 3 format types supported. */ 986 /* Start with index 2 (first item). */ 987 for (int i = 2; i < 5; i++) 988 { 989 LogFlowThisFunc(("\t%s\n", gX11->xAtomToString(e.xclient.data.l[i]).c_str())); 990 m_lstFormats.append(e.xclient.data.l[i]); 991 } 992 } 993 else 994 { 995 /* More than 3 format types supported. */ 996 rc = wndXDnDGetFormatList(wndSelection, m_lstFormats); 997 } 998 999 /* 1000 * Retrieve supported actions. 1001 */ 1002 if (RT_SUCCESS(rc)) 1003 { 1004 if (m_curVer >= 2) /* More than one action allowed since protocol version 2. */ 1005 { 1006 rc = wndXDnDGetActionList(wndSelection, m_lstActions); 1007 } 1008 else /* Only "copy" action allowed on legacy applications. */ 1009 m_lstActions.append(XA_XdndActionCopy); 1010 } 1011 1012 if (RT_SUCCESS(rc)) 1013 { 1014 m_enmMode = GH; 1015 m_enmState = Dragging; 1016 } 1017 1018 RTCritSectLeave(&m_dataCS); 1019 } 1020 } 1021 else if ( e.xclient.message_type == xAtom(XA_XdndPosition) 1022 && m_wndCur == static_cast<Window>(e.xclient.data.l[XdndPositionWindow])) 1023 { 1024 int32_t lPos = e.xclient.data.l[XdndPositionCoords]; 1025 Atom atmAction = m_curVer >= 2 /* Actions other than "copy" or only supported since protocol version 2. */ 1026 ? e.xclient.data.l[XdndPositionAction] : xAtom(XA_XdndActionCopy); 1027 1028 LogFlowThisFunc(("XA_XdndPosition: wndProxy=%#x, wndCur=%#x, x=%RI32, y=%RI32, strAction=%s\n", 1029 m_wndProxy, m_wndCur, RT_HIWORD(lPos), RT_LOWORD(lPos), 1030 xAtomToString(atmAction).c_str())); 1031 1032 bool fAcceptDrop = true; 1033 1034 /* Reply with a XdndStatus message to tell the source whether 1035 * the data can be dropped or not. */ 1036 XClientMessageEvent m; 1037 RT_ZERO(m); 1038 m.type = ClientMessage; 1039 m.display = m_pDisplay; 1040 m.window = e.xclient.data.l[XdndPositionWindow]; 1041 m.message_type = xAtom(XA_XdndStatus); 1042 m.format = 32; 1043 m.data.l[XdndStatusWindow] = m_wndProxy; 1044 m.data.l[XdndStatusFlags] = fAcceptDrop ? RT_BIT(0) : 0; /* Whether to accept the drop or not. */ 1045 m.data.l[XdndStatusAction] = fAcceptDrop ? toAtomAction(DND_COPY_ACTION) : None; /** @todo Handle default action! */ 1046 1047 int xRc = XSendEvent(m_pDisplay, e.xclient.data.l[XdndPositionWindow], 1048 False /* Propagate */, NoEventMask, reinterpret_cast<XEvent *>(&m)); 1049 if (xRc == 0) 1050 logError("Error sending position XA_XdndStatus event to current window=%#x: %s\n", 1051 m_wndCur, gX11->xErrorToString(xRc).c_str()); 1052 } 1053 else if ( e.xclient.message_type == xAtom(XA_XdndLeave) 1054 && m_wndCur == static_cast<Window>(e.xclient.data.l[XdndLeaveWindow])) 1055 { 1056 LogFlowThisFunc(("XA_XdndLeave\n")); 1057 logInfo("Guest to host transfer canceled by the guest source window\n"); 1058 1059 /* Start over. */ 1060 reset(); 1061 } 1062 else if ( e.xclient.message_type == xAtom(XA_XdndDrop) 1063 && m_wndCur == static_cast<Window>(e.xclient.data.l[XdndDropWindow])) 1064 { 1065 LogFlowThisFunc(("XA_XdndDrop\n")); 1066 logInfo("Notified guest target window that drop operation is finished\n"); 1067 1068 m_eventQueueList.append(e); 1069 rc = RTSemEventSignal(m_eventQueueEvent); 1070 } 1071 else if ( e.xclient.message_type == xAtom(XA_XdndFinished) 1072 && m_wndCur == static_cast<Window>(e.xclient.data.l[XdndFinishedWindow])) 1073 { 1074 LogFlowThisFunc(("XA_XdndFinished\n")); 1075 logInfo("Guest target window finished drag and drop operation\n"); 1076 1077 m_eventQueueList.append(e); 1078 rc = RTSemEventSignal(m_eventQueueEvent); 1079 } 799 1080 break; 800 1081 } … … 812 1093 } 813 1094 1095 int DragInstance::onX11MotionNotify(const XEvent &e) 1096 { 1097 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState)); 1098 1099 return VINF_SUCCESS; 1100 } 1101 1102 /** 1103 * Callback handler for being notified if some other window now 1104 * is the owner of the current selection. 1105 * 1106 * @return IPRT status code. 1107 * @param e X11 event to handle. 1108 * 1109 * @remark 1110 */ 1111 int DragInstance::onX11SelectionClear(const XEvent &e) 1112 { 1113 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState)); 1114 1115 return VINF_SUCCESS; 1116 } 1117 814 1118 /** 815 1119 * Callback handler for a XDnD selection notify from a window. This is needed … … 824 1128 AssertReturn(e.type == SelectionNotify, VERR_INVALID_PARAMETER); 825 1129 826 LogFlowThisFunc(("m _mode=%d, m_state=%d\n", m_enmMode, m_enmState));1130 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState)); 827 1131 828 1132 int rc; … … 834 1138 if (m_enmState == Dropped) 835 1139 { 836 m_eventQueue .append(e);837 rc = RTSemEventSignal(m_ hEventSem);1140 m_eventQueueList.append(e); 1141 rc = RTSemEventSignal(m_eventQueueEvent); 838 1142 } 1143 else 1144 rc = VERR_WRONG_ORDER; 839 1145 break; 840 1146 } … … 864 1170 AssertReturn(e.type == SelectionRequest, VERR_INVALID_PARAMETER); 865 1171 866 LogFlowThisFunc(("m _mode=%d, m_state=%d\n", m_enmMode, m_enmState));1172 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState)); 867 1173 LogFlowThisFunc(("Event owner=%#x, requestor=%#x, selection=%s, target=%s, prop=%s, time=%u\n", 868 1174 e.xselectionrequest.owner, … … 874 1180 int rc; 875 1181 876 bool fSendEvent = false;877 Atom atmTarget = None;878 Atom atmProperty = None;879 880 1182 switch (m_enmMode) 881 1183 { … … 884 1186 rc = VINF_SUCCESS; 885 1187 1188 char *pszWndName = wndX11GetNameA(e.xselectionrequest.requestor); 1189 AssertPtr(pszWndName); 1190 1191 /* 1192 * Start by creating a refusal selection notify message. 1193 * That way we only need to care for the success case. 1194 */ 1195 1196 XEvent s; 1197 RT_ZERO(s); 1198 s.xselection.type = SelectionNotify; 1199 s.xselection.display = e.xselectionrequest.display; 1200 s.xselection.requestor = e.xselectionrequest.requestor; 1201 s.xselection.selection = e.xselectionrequest.selection; 1202 s.xselection.target = e.xselectionrequest.target; 1203 s.xselection.property = None; /* "None" means refusal. */ 1204 s.xselection.time = e.xselectionrequest.time; 1205 1206 const XSelectionRequestEvent *pReq = &e.xselectionrequest; 1207 886 1208 #ifdef DEBUG 887 XTextProperty propName; 888 XGetWMName(m_pDisplay, e.xselectionrequest.requestor, &propName); 1209 LogFlowFunc(("Supported formats:\n")); 1210 for (size_t i = 0; i < m_lstFormats.size(); i++) 1211 LogFlowFunc(("\t%s\n", xAtomToString(m_lstFormats.at(i)).c_str())); 889 1212 #endif 890 /*891 * A window is asking for some data. Normally here the data would be copied892 * into the selection buffer and send to the requestor. Obviously we can't893 * do that, because we first need to ask the host for the data of the894 * requested MIME type. This is done and later answered with the correct895 * data -- see DragInstance::hgDataReceived().896 */897 898 1213 /* Is the requestor asking for the possible MIME types? */ 899 if ( e.xselectionrequest.target == xAtom(XA_TARGETS))1214 if (pReq->target == xAtom(XA_TARGETS)) 900 1215 { 901 LogFlowThisFunc(("wnd=%#x ('%s') asking for target list\n", 902 e.xselectionrequest.requestor, propName.value ? (const char *)propName.value : "<No name>")); 1216 logInfo("Target window %#x ('%s') asking for target list\n", e.xselectionrequest.requestor, pszWndName); 903 1217 904 1218 /* If so, set the window property with the formats on the requestor 905 1219 * window. */ 906 rc = wndXDnDSetFormatList( e.xselectionrequest.requestor, e.xselectionrequest.property, m_lstFormats);1220 rc = wndXDnDSetFormatList(pReq->requestor, pReq->property, m_lstFormats); 907 1221 if (RT_SUCCESS(rc)) 908 { 909 atmTarget = e.xselectionrequest.target; 910 atmProperty = e.xselectionrequest.property; 911 912 fSendEvent = true; 913 } 1222 s.xselection.property = pReq->property; 914 1223 } 915 1224 /* Is the requestor asking for a specific MIME type (we support)? */ 916 else if (m_lstFormats.contains( e.xselectionrequest.target))1225 else if (m_lstFormats.contains(pReq->target)) 917 1226 { 918 LogFlowThisFunc(("wnd=%#x ('%s') asking for data, format=%s\n", 919 e.xselectionrequest.requestor, propName.value ? (const char *)propName.value : "<No name>", 920 xAtomToString(e.xselectionrequest.target).c_str())); 921 922 /* If so, we need to inform the host about this request. Save the 923 * selection request event for later use. */ 1227 logInfo("Target window %#x ('%s') is asking for data as '%s'\n", 1228 pReq->requestor, pszWndName, xAtomToString(pReq->target).c_str()); 1229 1230 /* Did we not drop our stuff to the guest yet? Bail out. */ 924 1231 if (m_enmState != Dropped) 925 1232 { 926 1233 LogFlowThisFunc(("Wrong state (%RU32), refusing request\n", m_enmState)); 927 928 atmTarget = None;929 atmProperty = e.xselectionrequest.property;930 931 fSendEvent = true;932 1234 } 1235 /* Did we not store the requestor's initial selection request yet? Then do so now. */ 933 1236 else 934 1237 { 935 LogFlowThisFunc(("Saving selection notify message of wnd=%#x ('%s')\n", 936 e.xselectionrequest.requestor, propName.value ? (const char *)propName.value : "<No name>")); 937 938 memcpy(&m_eventHgSelection, &e, sizeof(XEvent)); 939 940 RTCString strFormat = xAtomToString(e.xselectionrequest.target); 1238 /* Get the data format the requestor wants from us. */ 1239 RTCString strFormat = xAtomToString(pReq->target); 941 1240 Assert(strFormat.isNotEmpty()); 942 943 rc = VbglR3DnDHGRequestData(&m_dndCtx, strFormat.c_str()); 944 LogFlowThisFunc(("Requested data from host as \"%s\", rc=%Rrc\n", strFormat.c_str(), rc)); 1241 logInfo("Target window=%#x requested data from host as '%s', rc=%Rrc\n", 1242 pReq->requestor, strFormat.c_str(), rc); 1243 1244 /* Make a copy of the MIME data to be passed back. The X server will be become 1245 * the new owner of that data, so no deletion needed. */ 1246 /** @todo Do we need to do some more conversion here? XConvertSelection? */ 1247 void *pvData = RTMemDup(m_pvSelReqData, m_cbSelReqData); 1248 uint32_t cbData = m_cbSelReqData; 1249 1250 /* Always return the requested property. */ 1251 s.xselection.property = pReq->property; 1252 1253 /* Note: Always seems to return BadRequest. Seems fine. */ 1254 int xRc = XChangeProperty(s.xselection.display, s.xselection.requestor, s.xselection.property, 1255 s.xselection.target, 8, PropModeReplace, 1256 reinterpret_cast<const unsigned char*>(pvData), cbData); 1257 1258 LogFlowFunc(("Changing property '%s' (target '%s') of window=0x%x: %s\n", 1259 xAtomToString(pReq->property).c_str(), 1260 xAtomToString(pReq->target).c_str(), 1261 pReq->requestor, 1262 gX11->xErrorToString(xRc).c_str())); 945 1263 } 946 1264 } … … 948 1266 else 949 1267 { 950 LogFlowThisFunc(("Refusing unknown command of wnd=%#x ('%s')\n", e.xselectionrequest.requestor, 951 propName.value ? (const char *)propName.value : "<No name>")); 952 953 /* We don't understand this request message and therefore answer with an 954 * refusal messages. */ 955 fSendEvent = true; 1268 logError("Refusing unknown command/format '%s' of wnd=%#x ('%s')\n", 1269 xAtomToString(e.xselectionrequest.target).c_str(), pReq->requestor, pszWndName); 1270 rc = VERR_NOT_SUPPORTED; 956 1271 } 957 1272 958 if ( RT_SUCCESS(rc) 959 && fSendEvent) 960 { 961 XEvent s; 962 RT_ZERO(s); 963 s.xselection.type = SelectionNotify; 964 s.xselection.display = e.xselection.display; 965 s.xselection.time = e.xselectionrequest.time; 966 s.xselection.selection = e.xselectionrequest.selection; 967 s.xselection.requestor = e.xselectionrequest.requestor; 968 s.xselection.target = atmTarget; 969 s.xselection.property = atmProperty; 970 971 int xRc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s); 972 if (RT_UNLIKELY(xRc == 0)) 973 logError("Error sending SelectionNotify(1) event to wnd=%#x: %s\n", e.xselectionrequest.requestor, 974 gX11->xErrorToString(xRc).c_str()); 975 } 976 977 #ifdef DEBUG 978 if (propName.value) 979 XFree(propName.value); 980 #endif 1273 LogFlowThisFunc(("Offering type '%s', property '%s' to wnd=%#x ...\n", 1274 xAtomToString(pReq->target).c_str(), 1275 xAtomToString(pReq->property).c_str(), pReq->requestor)); 1276 1277 int xRc = XSendEvent(pReq->display, pReq->requestor, True /* Propagate */, 0, &s); 1278 if (xRc == 0) 1279 logError("Error sending SelectionNotify(1) event to wnd=%#x: %s\n", pReq->requestor, 1280 gX11->xErrorToString(xRc).c_str()); 1281 XFlush(pReq->display); 1282 1283 if (pszWndName) 1284 RTStrFree(pszWndName); 981 1285 break; 982 1286 } 983 1287 984 1288 default: 985 {986 LogFlowThisFunc(("Unhandled message for wnd=%#x: %s\n",987 e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str()));988 1289 rc = VERR_INVALID_STATE; 989 1290 break; 990 }991 1291 } 992 1292 … … 1023 1323 1024 1324 case SelectionClear: 1025 LogFlowThisFunc(("SelectionClear\n")); 1026 reset(); 1027 rc = VINF_SUCCESS; 1028 break; 1325 rc = onX11SelectionClear(e); 1326 break; 1029 1327 1030 1328 case SelectionNotify: … … 1036 1334 break; 1037 1335 1038 /*case MotionNotify:1039 hide();1040 break;*/1336 case MotionNotify: 1337 rc = onX11MotionNotify(e); 1338 break; 1041 1339 1042 1340 default: … … 1046 1344 1047 1345 LogFlowThisFunc(("rc=%Rrc\n", rc)); 1346 return rc; 1347 } 1348 1349 int DragInstance::waitForStatusChange(uint32_t enmState, RTMSINTERVAL uTimeoutMS /* = 30000 */) 1350 { 1351 const uint64_t uiStart = RTTimeMilliTS(); 1352 volatile uint32_t enmCurState; 1353 1354 int rc = VERR_TIMEOUT; 1355 1356 LogFlowFunc(("enmState=%RU32, uTimeoutMS=%RU32\n", enmState, uTimeoutMS)); 1357 1358 do 1359 { 1360 enmCurState = ASMAtomicReadU32(&m_enmState); 1361 if (enmCurState == enmState) 1362 { 1363 rc = VINF_SUCCESS; 1364 break; 1365 } 1366 } 1367 while (RTTimeMilliTS() - uiStart < uTimeoutMS); 1368 1369 LogFlowThisFunc(("Returning %Rrc\n", rc)); 1048 1370 return rc; 1049 1371 } … … 1060 1382 bool DragInstance::waitForX11Msg(XEvent &evX, int iType, RTMSINTERVAL uTimeoutMS /* = 100 */) 1061 1383 { 1062 LogFlowThisFunc(("iType=%d, uTimeoutMS=%RU32, cEventQueue=%zu\n", iType, uTimeoutMS, m_eventQueue .size()));1384 LogFlowThisFunc(("iType=%d, uTimeoutMS=%RU32, cEventQueue=%zu\n", iType, uTimeoutMS, m_eventQueueList.size())); 1063 1385 1064 1386 bool fFound = false; … … 1068 1390 { 1069 1391 /* Check if there is a client message in the queue. */ 1070 for (size_t i = 0; i < m_eventQueue .size(); i++)1392 for (size_t i = 0; i < m_eventQueueList.size(); i++) 1071 1393 { 1072 1394 int rc2 = RTCritSectEnter(&m_eventQueueCS); 1073 1395 if (RT_SUCCESS(rc2)) 1074 1396 { 1075 XEvent e = m_eventQueue .at(i);1397 XEvent e = m_eventQueueList.at(i); 1076 1398 1077 1399 fFound = e.type == iType; 1078 1400 if (fFound) 1079 1401 { 1080 m_eventQueue .removeAt(i);1402 m_eventQueueList.removeAt(i); 1081 1403 evX = e; 1082 1404 } … … 1093 1415 break; 1094 1416 1095 int rc2 = RTSemEventWait(m_ hEventSem, 25 /* ms */);1417 int rc2 = RTSemEventWait(m_eventQueueEvent, 25 /* ms */); 1096 1418 if ( RT_FAILURE(rc2) 1097 1419 && rc2 != VERR_TIMEOUT) … … 1116 1438 */ 1117 1439 bool DragInstance::waitForX11ClientMsg(XClientMessageEvent &evMsg, Atom aType, 1118 RTMSINTERVAL uTimeoutMS /* = 100 */)1440 RTMSINTERVAL uTimeoutMS /* = 100 */) 1119 1441 { 1120 1442 LogFlowThisFunc(("aType=%s, uTimeoutMS=%RU32, cEventQueue=%zu\n", 1121 xAtomToString(aType).c_str(), uTimeoutMS, m_eventQueue .size()));1443 xAtomToString(aType).c_str(), uTimeoutMS, m_eventQueueList.size())); 1122 1444 1123 1445 bool fFound = false; … … 1126 1448 { 1127 1449 /* Check if there is a client message in the queue. */ 1128 for (size_t i = 0; i < m_eventQueue .size(); i++)1450 for (size_t i = 0; i < m_eventQueueList.size(); i++) 1129 1451 { 1130 1452 int rc2 = RTCritSectEnter(&m_eventQueueCS); 1131 1453 if (RT_SUCCESS(rc2)) 1132 1454 { 1133 XEvent e = m_eventQueue.at(i); 1455 XEvent e = m_eventQueueList.at(i); 1456 if ( e.type == ClientMessage 1457 && e.xclient.message_type == aType) 1458 { 1459 m_eventQueueList.removeAt(i); 1460 evMsg = e.xclient; 1461 1462 fFound = true; 1463 } 1464 1134 1465 if (e.type == ClientMessage) 1135 1466 { 1136 /** @todo Check is aType matches the event's type! */ 1137 1138 m_eventQueue.removeAt(i); 1139 evMsg = e.xclient; 1140 1141 fFound = true; 1467 LogFlowThisFunc(("Client message: Type=%ld (%s)\n", 1468 e.xclient.message_type, xAtomToString(e.xclient.message_type).c_str())); 1142 1469 } 1470 else 1471 LogFlowThisFunc(("X message: Type=%d\n", e.type)); 1143 1472 1144 1473 rc2 = RTCritSectLeave(&m_eventQueueCS); … … 1153 1482 break; 1154 1483 1155 int rc2 = RTSemEventWait(m_ hEventSem, 25 /* ms */);1484 int rc2 = RTSemEventWait(m_eventQueueEvent, 25 /* ms */); 1156 1485 if ( RT_FAILURE(rc2) 1157 1486 && rc2 != VERR_TIMEOUT) … … 1220 1549 1221 1550 /* Set the DnD selection owner to our window. */ 1551 /** @todo Don't use CurrentTime -- according to ICCCM section 2.1. */ 1222 1552 XSetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection), m_wndProxy, CurrentTime); 1223 1553 … … 1287 1617 0, 2, False, AnyPropertyType, 1288 1618 &atmp, &fmt, &cItems, &cbRemaining, &pcData); 1289 1290 if (RT_UNLIKELY(xRc != Success))1619 if (xRc != Success) 1620 { 1291 1621 logError("Error getting properties of cursor window=%#x: %s\n", wndCursor, gX11->xErrorToString(xRc).c_str()); 1622 } 1292 1623 else 1293 1624 { 1294 if (RT_UNLIKELY(pcData == NULL || fmt != 32 || cItems != 1)) 1295 LogFlowThisFunc(("Wrong properties: pcData=%#x, iFmt=%d, cItems=%ul\n", pcData, fmt, cItems)); 1625 if (pcData == NULL || fmt != 32 || cItems != 1) 1626 { 1627 /** @todo Do we need to deal with this? */ 1628 logError("Wrong window properties for window %#x: pcData=%#x, iFmt=%d, cItems=%ul\n", 1629 wndCursor, pcData, fmt, cItems); 1630 } 1296 1631 else 1297 1632 { 1298 newVer = reinterpret_cast<long*>(pcData)[0]; 1299 #ifdef DEBUG 1300 XTextProperty propName; 1301 if (XGetWMName(m_pDisplay, wndCursor, &propName)) 1302 { 1303 LogFlowThisFunc(("Current: wndCursor=%#x '%s', XdndAware=%ld\n", wndCursor, propName.value, newVer)); 1304 XFree(propName.value); 1305 } 1306 #endif 1633 /* Get the current window's Xdnd version. */ 1634 newVer = reinterpret_cast<long *>(pcData)[0]; 1307 1635 } 1308 1636 … … 1311 1639 } 1312 1640 1313 /* 1314 * Is the window under the cursor another one than our current one? 1315 * Cancel the current drop. 1316 */ 1641 #ifdef DEBUG 1642 char *pszNameCursor = wndX11GetNameA(wndCursor); 1643 AssertPtr(pszNameCursor); 1644 char *pszNameCur = wndX11GetNameA(m_wndCur); 1645 AssertPtr(pszNameCur); 1646 1647 LogFlowThisFunc(("wndCursor=%x ('%s', Xdnd version %ld), wndCur=%x ('%s', Xdnd version %ld)\n", 1648 wndCursor, pszNameCursor, newVer, m_wndCur, pszNameCur, m_curVer)); 1649 1650 RTStrFree(pszNameCursor); 1651 RTStrFree(pszNameCur); 1652 #endif 1653 1317 1654 if ( wndCursor != m_wndCur 1318 1655 && m_curVer != -1) 1319 1656 { 1320 1657 LogFlowThisFunc(("XA_XdndLeave: window=%#x\n", m_wndCur)); 1658 1659 char *pszWndName = wndX11GetNameA(m_wndCur); 1660 AssertPtr(pszWndName); 1661 logInfo("Left old window %#x ('%s'), Xdnd version=%ld\n", m_wndCur, pszWndName, newVer); 1662 RTStrFree(pszWndName); 1321 1663 1322 1664 /* We left the current XdndAware window. Announce this to the current indow. */ 1323 1665 XClientMessageEvent m; 1324 1666 RT_ZERO(m); 1325 m.type = ClientMessage;1326 m.display = m_pDisplay;1327 m.window = m_wndCur;1328 m.message_type = xAtom(XA_XdndLeave);1329 m.format = 32;1330 m.data.l[ 0] = m_wndProxy; /* Source window. */1667 m.type = ClientMessage; 1668 m.display = m_pDisplay; 1669 m.window = m_wndCur; 1670 m.message_type = xAtom(XA_XdndLeave); 1671 m.format = 32; 1672 m.data.l[XdndLeaveWindow] = m_wndProxy; 1331 1673 1332 1674 xRc = XSendEvent(m_pDisplay, m_wndCur, False, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1333 if ( RT_UNLIKELY(xRc == 0))1675 if (xRc == 0) 1334 1676 logError("Error sending XA_XdndLeave event to old window=%#x: %s\n", m_wndCur, gX11->xErrorToString(xRc).c_str()); 1677 1678 /* Reset our current window. */ 1679 m_wndCur = 0; 1680 m_curVer = -1; 1335 1681 } 1336 1682 1337 1683 /* 1338 * Do we have a new window which now is under the cursor?1684 * Do we have a new Xdnd-aware window which now is under the cursor? 1339 1685 */ 1340 1686 if ( wndCursor != m_wndCur … … 1342 1688 { 1343 1689 LogFlowThisFunc(("XA_XdndEnter: window=%#x\n", wndCursor)); 1690 1691 char *pszWndName = wndX11GetNameA(wndCursor); 1692 AssertPtr(pszWndName); 1693 logInfo("Entered new window %#x ('%s'), supports Xdnd version=%ld\n", wndCursor, pszWndName, newVer); 1694 RTStrFree(pszWndName); 1344 1695 1345 1696 /* … … 1356 1707 m.message_type = xAtom(XA_XdndEnter); 1357 1708 m.format = 32; 1358 m.data.l[ 0] = m_wndProxy; /* Source window. */1359 m.data.l[ 1]= RT_MAKE_U32_FROM_U8(1360 /* Bit 0 is set if the source supports more than three data types. */1361 m_lstFormats.size() > 3 ? 1: 0,1362 /* Reserved for future use. */1363 0, 0,1364 /* Protocol version to use. */1365 RT_MIN(VBOX_XDND_VERSION, newVer));1366 m.data.l[ 2] = m_lstFormats.value(0, None);/* First data type to use. */1367 m.data.l[ 3] = m_lstFormats.value(1, None);/* Second data type to use. */1368 m.data.l[ 4] = m_lstFormats.value(2, None);/* Third data type to use. */1709 m.data.l[XdndEnterWindow] = m_wndProxy; 1710 m.data.l[XdndEnterFlags] = RT_MAKE_U32_FROM_U8( 1711 /* Bit 0 is set if the source supports more than three data types. */ 1712 m_lstFormats.size() > 3 ? RT_BIT(0) : 0, 1713 /* Reserved for future use. */ 1714 0, 0, 1715 /* Protocol version to use. */ 1716 RT_MIN(VBOX_XDND_VERSION, newVer)); 1717 m.data.l[XdndEnterType1] = m_lstFormats.value(0, None); /* First data type to use. */ 1718 m.data.l[XdndEnterType2] = m_lstFormats.value(1, None); /* Second data type to use. */ 1719 m.data.l[XdndEnterType3] = m_lstFormats.value(2, None); /* Third data type to use. */ 1369 1720 1370 1721 xRc = XSendEvent(m_pDisplay, wndCursor, False, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1371 if ( RT_UNLIKELY(xRc == 0))1722 if (xRc == 0) 1372 1723 logError("Error sending XA_XdndEnter event to window=%#x: %s\n", wndCursor, gX11->xErrorToString(xRc).c_str()); 1373 1724 } … … 1375 1726 if (newVer != -1) 1376 1727 { 1728 Assert(wndCursor != None); 1729 1377 1730 LogFlowThisFunc(("XA_XdndPosition: xPos=%RU32, yPos=%RU32 to window=%#x\n", u32xPos, u32yPos, wndCursor)); 1378 1731 … … 1390 1743 m.message_type = xAtom(XA_XdndPosition); 1391 1744 m.format = 32; 1392 m.data.l[ 0] = m_wndProxy; /* X window ID of source window. */1393 m.data.l[ 2] = RT_MAKE_U32(u32yPos, u32xPos); /* Cursor coordinates relative to the root window. */1394 m.data.l[ 3]= CurrentTime; /* Timestamp for retrieving data. */1395 m.data.l[ 4] = pa; /* Actions requested by the user. */1745 m.data.l[XdndPositionWindow] = m_wndProxy; /* X window ID of source window. */ 1746 m.data.l[XdndPositionCoords] = RT_MAKE_U32(u32yPos, u32xPos); /* Cursor coordinates relative to the root window. */ 1747 m.data.l[XdndPositionTimeStamp] = CurrentTime; /* Timestamp for retrieving data. */ 1748 m.data.l[XdndPositionAction] = pa; /* Actions requested by the user. */ 1396 1749 1397 1750 xRc = XSendEvent(m_pDisplay, wndCursor, False, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1398 if ( RT_UNLIKELY(xRc == 0))1751 if (xRc == 0) 1399 1752 logError("Error sending XA_XdndPosition event to current window=%#x: %s\n", wndCursor, gX11->xErrorToString(xRc).c_str()); 1400 1753 } 1401 1754 1402 if ( wndCursor == None 1403 && newVer == -1) 1755 if (newVer == -1) 1404 1756 { 1405 1757 /* No window to process, so send a ignore ack event to the host. */ … … 1408 1760 else 1409 1761 { 1762 Assert(wndCursor != None); 1763 1410 1764 m_wndCur = wndCursor; 1411 m_curVer = RT_MIN(VBOX_XDND_VERSION, newVer);1765 m_curVer = newVer; 1412 1766 } 1413 1767 … … 1420 1774 * 1421 1775 * @returns IPRT status code. 1422 */ 1423 int DragInstance::hgDrop(void) 1776 * @param u32xPos Relative X position within the guest's display area. 1777 * @param u32yPos Relative Y position within the guest's display area. 1778 * @param uDefaultAction Default action the host wants to perform on the guest 1779 * as soon as the operation successfully finishes. 1780 */ 1781 int DragInstance::hgDrop(uint32_t u32xPos, uint32_t u32yPos, uint32_t uDefaultAction) 1424 1782 { 1425 1783 LogFlowThisFunc(("wndCur=%#x, wndProxy=%#x, mode=%RU32, state=%RU32\n", m_wndCur, m_wndProxy, m_enmMode, m_enmState)); 1784 LogFlowThisFunc(("u32xPos=%RU32, u32yPos=%RU32, uAction=%RU32\n", u32xPos, u32yPos, uDefaultAction)); 1426 1785 1427 1786 if ( m_enmMode != HG … … 1431 1790 } 1432 1791 1792 /* Set the state accordingly. */ 1793 m_enmState = Dropped; 1794 1795 /* 1796 * Ask the host to send the raw data, as we don't (yet) know which format 1797 * the guest exactly expects. As blocking in a SelectionRequest message turned 1798 * out to be very unreliable (e.g. with KDE apps) we request to start transferring 1799 * file/directory data (if any) here. 1800 */ 1801 char szFormat[] = { "text/uri-list" }; 1802 1803 int rc = VbglR3DnDHGRequestData(&m_dndCtx, szFormat); 1804 logInfo("Drop event from host resuled in: %Rrc\n", rc); 1805 1806 LogFlowFuncLeaveRC(rc); 1807 return rc; 1808 } 1809 1810 /** 1811 * Host -> Guest: Event signalling that the host has finished sending drag'n drop 1812 * data to the guest for further processing. 1813 * 1814 * @returns IPRT status code. 1815 * @param pvData Pointer to (MIME) data from host. 1816 * @param cbData Size (in bytes) of data from host. 1817 */ 1818 int DragInstance::hgDataReceived(const void *pvData, uint32_t cbData) 1819 { 1820 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState)); 1821 LogFlowThisFunc(("pvData=%p, cbData=%RU32\n", pvData, cbData)); 1822 1823 if ( m_enmMode != HG 1824 || m_enmState != Dropped) 1825 { 1826 return VERR_INVALID_STATE; 1827 } 1828 1829 if ( pvData == NULL 1830 || cbData == 0) 1831 { 1832 return VERR_INVALID_PARAMETER; 1833 } 1834 1433 1835 int rc = VINF_SUCCESS; 1434 1836 1435 1837 /* 1436 * Send a drop event to the current window and reset our DnD status. 1838 * At this point all data needed (including sent files/directories) should 1839 * be on the guest, so proceed working on communicating with the target window. 1840 */ 1841 logInfo("Received %RU32 bytes MIME data from host\n", cbData); 1842 1843 /* Destroy any old data. */ 1844 if (m_pvSelReqData) 1845 { 1846 Assert(m_cbSelReqData); 1847 1848 RTMemFree(m_pvSelReqData); /** @todo RTMemRealloc? */ 1849 m_cbSelReqData = 0; 1850 } 1851 1852 /** @todo Handle incremental transfers. */ 1853 1854 /* Make a copy of the data. This data later then will be used to fill into 1855 * the selection request. */ 1856 if (cbData) 1857 { 1858 m_pvSelReqData = RTMemAlloc(cbData); 1859 if (!m_pvSelReqData) 1860 return VERR_NO_MEMORY; 1861 1862 memcpy(m_pvSelReqData, pvData, cbData); 1863 m_cbSelReqData = cbData; 1864 } 1865 1866 /* 1867 * Send a drop event to the current window (target). 1868 * This window in turn then will raise a SelectionRequest message to our proxy window, 1869 * which we will handle in our onX11SelectionRequest handler. 1870 * 1871 * The SelectionRequest will tell us in which format the target wants the data from the host. 1437 1872 */ 1438 1873 XClientMessageEvent m; … … 1443 1878 m.message_type = xAtom(XA_XdndDrop); 1444 1879 m.format = 32; 1445 m.data.l[0] = m_wndProxy; /* Source window. */ 1446 m.data.l[2] = CurrentTime; /* Timestamp. */ 1447 1448 int xRc = XSendEvent(m_pDisplay, m_wndCur, False, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1449 if (RT_UNLIKELY(xRc == 0)) 1450 logError("Error sending XA_XdndDrop event to wndCur=%#x: %s\n", m_wndCur, gX11->xErrorToString(xRc).c_str()); 1451 1452 m_wndCur = None; 1453 m_curVer = -1; 1454 1455 m_enmState = Dropped; 1880 m.data.l[XdndDropWindow] = m_wndProxy; /* Source window. */ 1881 m.data.l[XdndDropFlags] = 0; /* Reserved for future use. */ 1882 m.data.l[XdndDropTimeStamp] = CurrentTime; /* Our DnD data does not rely on any timing, so just use the current time. */ 1883 1884 int xRc = XSendEvent(m_pDisplay, m_wndCur, False /* Propagate */, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1885 if (xRc == 0) 1886 logError("Error sending XA_XdndDrop event to window=%#x: %s\n", m_wndCur, gX11->xErrorToString(xRc).c_str()); 1887 XFlush(m_pDisplay); 1456 1888 1457 1889 LogFlowFuncLeaveRC(rc); … … 1459 1891 } 1460 1892 1461 /**1462 * Host -> Guest: Event signalling that the host has sent drag'n drop (MIME) data1463 * to the guest for further processing.1464 *1465 * @returns IPRT status code.1466 * @param pvData Pointer to (MIME) data from host.1467 * @param cbData Size (in bytes) of data from host.1468 */1469 int DragInstance::hgDataReceived(const void *pvData, uint32_t cbData)1470 {1471 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState));1472 1473 if ( m_enmMode != HG1474 || m_enmState != Dropped)1475 {1476 return VERR_INVALID_STATE;1477 }1478 1479 if (RT_UNLIKELY( pvData == NULL1480 || cbData == 0))1481 {1482 return VERR_INVALID_PARAMETER;1483 }1484 1485 /* Make a copy of the data. The X server will become the new owner. */1486 void *pvNewData = RTMemAlloc(cbData);1487 if (RT_UNLIKELY(!pvNewData))1488 return VERR_NO_MEMORY;1489 1490 memcpy(pvNewData, pvData, cbData);1491 1492 /*1493 * The host has sent us the DnD data in the requested MIME type. This allows us1494 * to fill the XdndSelection property of the requestor window with the data1495 * and afterwards inform the host about the new status.1496 */1497 XEvent s;1498 RT_ZERO(s);1499 s.xselection.type = SelectionNotify;1500 s.xselection.display = m_eventHgSelection.xselection.display;1501 // s.xselection.owner = m_selEvent.xselectionrequest.owner;1502 s.xselection.time = m_eventHgSelection.xselectionrequest.time;1503 s.xselection.selection = m_eventHgSelection.xselectionrequest.selection;1504 s.xselection.requestor = m_eventHgSelection.xselectionrequest.requestor;1505 s.xselection.target = m_eventHgSelection.xselectionrequest.target;1506 s.xselection.property = m_eventHgSelection.xselectionrequest.property;1507 1508 LogFlowThisFunc(("owner=%#x, requestor=%#x, sel_atom=%s, target_atom=%s, prop_atom=%s, time=%u\n",1509 m_eventHgSelection.xselectionrequest.owner,1510 s.xselection.requestor,1511 xAtomToString(s.xselection.selection).c_str(),1512 xAtomToString(s.xselection.target).c_str(),1513 xAtomToString(s.xselection.property).c_str(),1514 s.xselection.time));1515 1516 /* Fill up the property with the data. */1517 XChangeProperty(s.xselection.display, s.xselection.requestor, s.xselection.property, s.xselection.target, 8, PropModeReplace,1518 reinterpret_cast<const unsigned char*>(pvNewData), cbData);1519 int xRc = XSendEvent(s.xselection.display, s.xselection.requestor, True, 0, &s);1520 if (RT_UNLIKELY(xRc == 0))1521 logError("Error sending SelectionNotify(2) event to window=%#x: %s\n",1522 s.xselection.requestor, gX11->xErrorToString(xRc).c_str());1523 1524 /* We're finally done, reset. */1525 reset();1526 1527 return VINF_SUCCESS;1528 }1529 1530 1893 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 1531 1894 /** … … 1539 1902 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState)); 1540 1903 1904 /* Currently in wrong mode? Bail out. */ 1541 1905 if (m_enmMode == HG) 1542 1906 return VERR_INVALID_STATE; 1543 1907 1908 /* Message already processed successfully? */ 1909 if ( m_enmMode == GH 1910 && ( m_enmState == Dragging 1911 || m_enmState == Dropped) 1912 ) 1913 { 1914 return VERR_INVALID_STATE; 1915 } 1916 1544 1917 int rc = VINF_SUCCESS; 1918 1919 /* Determine the current window which currently has the XdndSelection set. */ 1545 1920 Window wndSelection = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection)); 1546 LogFlowThisFunc(("Checking pending wndSelection=%#x, wndProxy=%#x\n", wndSelection, m_wndProxy)); 1547 1548 /* Is this another window which has a Xdnd selection than our current one? */ 1921 LogFlowThisFunc(("wndSelection=%#x, wndProxy=%#x, wndCur=%#x\n", wndSelection, m_wndProxy, m_wndCur)); 1922 1923 RTCString strFormats = "None"; /** @todo If empty, IOCTL fails with VERR_ACCESS_DENIED. */ 1924 uint32_t uDefAction = DND_IGNORE_ACTION; 1925 uint32_t uAllActions = DND_IGNORE_ACTION; 1926 1927 /* Is this another window which has a Xdnd selection and not our proxy window? */ 1549 1928 if ( wndSelection 1550 && wndSelection != m_wndProxy) 1551 { 1929 && wndSelection != m_wndCur) 1930 { 1931 #ifdef DEBUG 1932 char *pszWndName = wndX11GetNameA(wndSelection); 1933 AssertPtr(pszWndName); 1934 LogFlowThisFunc(("*** New source window ('%s') ***\n", pszWndName)); 1935 RTStrFree(pszWndName); 1936 #endif 1937 /* Start over. */ 1938 reset(); 1939 1552 1940 /* Map the window on the current cursor position, which should provoke 1553 1941 * an XdndEnter event. */ 1554 proxyWinShow(NULL, NULL, true); 1555 1556 XEvent e; 1557 if (waitForX11Msg(e, ClientMessage)) 1942 rc = proxyWinShow(NULL, NULL); 1943 if (RT_SUCCESS(rc)) 1558 1944 { 1559 bool fAcceptDrop = false; 1560 1561 int xRc; 1562 XClientMessageEvent *pEventClient = reinterpret_cast<XClientMessageEvent*>(&e); 1563 AssertPtr(pEventClient); 1564 1565 LogFlowThisFunc(("Received event=%s\n", 1566 gX11->xAtomToString(pEventClient->message_type).c_str())); 1567 1568 if (pEventClient->message_type == xAtom(XA_XdndEnter)) 1569 { 1570 LogFlowThisFunc(("XA_XdndEnter\n")); 1571 1572 /* 1573 * Prepare everything for our new window. 1574 */ 1575 reset(); 1576 1577 /* 1578 * Update our state and the window handle to process. 1579 */ 1580 m_enmMode = GH; 1581 m_enmState = Dragging; 1582 m_wndCur = wndSelection; 1583 Assert(m_wndCur == (Window)pEventClient->data.l[0]); 1584 #ifdef DEBUG 1585 XWindowAttributes xwa; 1586 XGetWindowAttributes(m_pDisplay, m_wndCur, &xwa); 1587 LogFlowThisFunc(("m_wndCur=%#x, x=%d, y=%d, width=%d, height=%d\n", 1588 m_wndCur, xwa.x, xwa.y, xwa.width, xwa.height)); 1589 #endif 1590 /* Check if the MIME types are in the message itself or if we need 1591 * to fetch the XdndTypeList property from the window. */ 1592 if (!ASMBitTest(&pEventClient->data.l[1], 0)) 1593 { 1594 for (int i = 2; i < 5; ++i) 1595 { 1596 LogFlowThisFunc(("Received format via message: %s\n", 1597 gX11->xAtomToString(pEventClient->data.l[i]).c_str())); 1598 1599 m_lstFormats.append(pEventClient->data.l[i]); 1600 } 1601 } 1602 else 1603 { 1604 rc = wndXDnDGetFormatList(wndSelection, m_lstFormats); 1605 } 1606 1607 /* 1608 * Fetch the actions. 1609 */ 1610 rc = wndXDnDGetActionList(wndSelection, m_lstActions); 1611 1612 fAcceptDrop = true; 1613 } 1614 /* Did the source tell us where the cursor currently is? */ 1615 else if (pEventClient->message_type == xAtom(XA_XdndPosition)) 1616 { 1617 LogFlowThisFunc(("XA_XdndPosition\n")); 1618 fAcceptDrop = true; 1619 } 1620 else if (pEventClient->message_type == xAtom(XA_XdndLeave)) 1621 { 1622 LogFlowThisFunc(("XA_XdndLeave\n")); 1623 } 1624 1625 if (fAcceptDrop) 1626 { 1627 /* Reply with a XdndStatus message to tell the source whether 1628 * the data can be dropped or not. */ 1629 XClientMessageEvent m; 1630 RT_ZERO(m); 1631 m.type = ClientMessage; 1632 m.display = m_pDisplay; 1633 m.window = m_wndCur; 1634 m.message_type = xAtom(XA_XdndStatus); 1635 m.format = 32; 1636 m.data.l[0] = m_wndProxy; 1637 m.data.l[1] = RT_BIT(0); /* Accept the drop. */ 1638 m.data.l[4] = xAtom(XA_XdndActionCopy); /** @todo Make the accepted action configurable. */ 1639 1640 xRc = XSendEvent(m_pDisplay, m_wndCur, 1641 False, 0, reinterpret_cast<XEvent*>(&m)); 1642 if (RT_UNLIKELY(xRc == 0)) 1643 { 1644 logError("Error sending position XA_XdndStatus event to current window=%#x: %s\n", 1645 m_wndCur, gX11->xErrorToString(xRc).c_str()); 1646 } 1647 } 1945 /* Wait until we're in "Dragging" state. */ 1946 rc = waitForStatusChange(Dragging, 5 * 1000); 1947 if (RT_SUCCESS(rc)) 1948 m_enmMode = GH; 1648 1949 } 1649 1650 /* Do we need to acknowledge at least one format to the host? */ 1651 if (!m_lstFormats.isEmpty()) 1652 { 1653 RTCString strFormats = gX11->xAtomListToString(m_lstFormats); 1654 uint32_t uDefAction = DND_COPY_ACTION; /** @todo Handle default action! */ 1655 uint32_t uAllActions = toHGCMActions(m_lstActions); 1656 1657 rc = VbglR3DnDGHAcknowledgePending(&m_dndCtx, uDefAction, uAllActions, strFormats.c_str()); 1658 LogFlowThisFunc(("Acknowledging m_uClientID=%RU32, allActions=0x%x, strFormats=%s, rc=%Rrc\n", 1659 m_dndCtx.uClientID, uAllActions, strFormats.c_str(), rc)); 1660 } 1661 } 1950 } 1951 else 1952 RTThreadSleep(3000); 1953 1954 /* 1955 * Acknowledge to the host in any case, regardless 1956 * if something failed here or not. Be responsive. 1957 */ 1958 1959 int rc2 = RTCritSectEnter(&m_dataCS); 1960 if (RT_SUCCESS(rc2)) 1961 { 1962 strFormats = gX11->xAtomListToString(m_lstFormats); 1963 uDefAction = DND_COPY_ACTION; /** @todo Handle default action! */ 1964 uAllActions = DND_COPY_ACTION; /** @todo Ditto. */ 1965 uAllActions |= toHGCMActions(m_lstActions); 1966 1967 RTCritSectLeave(&m_dataCS); 1968 } 1969 1970 rc2 = VbglR3DnDGHAcknowledgePending(&m_dndCtx, uDefAction, uAllActions, strFormats.c_str()); 1971 LogFlowThisFunc(("Pending status to host: uClientID=%RU32, uDefAction=0x%x, allActions=0x%x, strFormats=%s, rc=%Rrc\n", 1972 m_dndCtx.uClientID, uDefAction, uAllActions, strFormats.c_str(), rc2)); 1973 if (RT_SUCCESS(rc)) 1974 rc = rc2; 1975 1976 if (RT_FAILURE(rc)) /* Start over on failure. */ 1977 reset(); 1662 1978 1663 1979 LogFlowFuncLeaveRC(rc); … … 1678 1994 m_enmMode, m_enmState, strFormat.c_str(), uAction)); 1679 1995 1680 if ( m_enmMode != GH 1681 || m_enmState != Dragging) 1996 /* Currently in wrong mode? Bail out. */ 1997 if ( m_enmMode == Unknown 1998 || m_enmMode == HG) 1682 1999 { 1683 2000 return VERR_INVALID_STATE; 1684 2001 } 1685 2002 2003 if ( m_enmMode == GH 2004 && m_enmState != Dragging) 2005 { 2006 return VERR_INVALID_STATE; 2007 } 2008 1686 2009 int rc = VINF_SUCCESS; 1687 2010 1688 2011 m_enmState = Dropped; 1689 2012 1690 /* Show the proxy window, so that the sourcewill find it. */2013 /* Show the proxy window, so that the current source window will find it. */ 1691 2014 int iRootX, iRootY; 1692 2015 proxyWinShow(&iRootX, &iRootY); 1693 XFlush(m_pDisplay);1694 2016 1695 2017 #ifdef DEBUG 1696 2018 XWindowAttributes xwa; 1697 2019 XGetWindowAttributes(m_pDisplay, m_wndCur, &xwa); 1698 LogFlowThisFunc(("wndCur=%#x, x=%d, y=%d, width=%d, height=%d\n", m_wndCur, xwa.x, xwa.y, xwa.width, xwa.height)); 2020 LogFlowThisFunc(("wndProxy=%#x, wndCur=%#x, x=%d, y=%d, width=%d, height=%d\n", 2021 m_wndProxy, m_wndCur, xwa.x, xwa.y, xwa.width, xwa.height)); 1699 2022 #endif 1700 2023 1701 2024 /* We send a fake release event to the current window, cause 1702 2025 * this should have the grab. */ 1703 mouseButtonSet(m_wndCur /* Destination window */, iRootX, iRootY, 1704 1 /* Button */, false /* fPress */); 2026 #if 0 2027 //mouseButtonSet(m_wndCur /* Destination window */, xwa.x + (xwa.width / 2), xwa.y + (xwa.height / 2), 1 /* Button */, false /* fPress */); 2028 #else 2029 mouseButtonSet(m_wndCur /* Destination window */, -1 /* Root X */, -1 /* Root Y */, 1 /* Button */, false /* fPress */); 2030 #endif 1705 2031 1706 2032 /** 1707 2033 * The fake button release event above should lead to a XdndDrop event from the 1708 * source . Because of showing our proxy window, other Xdnd events can2034 * source window. Because of showing our proxy window, other Xdnd events can 1709 2035 * occur before, e.g. a XdndPosition event. We are not interested 1710 2036 * in those, so just try to get the right one. … … 1712 2038 1713 2039 XClientMessageEvent evDnDDrop; 1714 bool fDrop = waitForX11ClientMsg(evDnDDrop, xAtom(XA_XdndDrop), 5 * 1000 /* Timeout in ms*/);2040 bool fDrop = waitForX11ClientMsg(evDnDDrop, xAtom(XA_XdndDrop), 5 * 1000 /* 5s timeout */); 1715 2041 if (fDrop) 1716 2042 { … … 1719 2045 /* Request to convert the selection in the specific format and 1720 2046 * place it to our proxy window as property. */ 1721 Window wndSource = evDnDDrop.data.l[0]; /* Source window which has sent the message. */ 2047 Assert(evDnDDrop.message_type == xAtom(XA_XdndDrop)); 2048 2049 Window wndSource = evDnDDrop.data.l[XdndDropWindow]; /* Source window which has sent the message. */ 1722 2050 Assert(wndSource == m_wndCur); 1723 Atom aFormat = gX11->stringToxAtom(strFormat.c_str()); 2051 2052 Atom aFormat = gX11->stringToxAtom(strFormat.c_str()); 2053 2054 Time tsDrop; 2055 if (m_curVer >= 1) 2056 tsDrop = evDnDDrop.data.l[XdndDropTimeStamp]; 2057 else 2058 tsDrop = CurrentTime; 1724 2059 1725 2060 XConvertSelection(m_pDisplay, xAtom(XA_XdndSelection), aFormat, xAtom(XA_XdndSelection), 1726 m_wndProxy, evDnDDrop.data.l[2]);2061 m_wndProxy, tsDrop); 1727 2062 1728 2063 /* Wait for the selection notify event. */ 1729 2064 XEvent evSelNotify; 1730 2065 RT_ZERO(evSelNotify); 1731 if (waitForX11Msg(evSelNotify, SelectionNotify ))2066 if (waitForX11Msg(evSelNotify, SelectionNotify, 5 * 1000 /* 5s timeout */)) 1732 2067 { 1733 2068 bool fCancel = false; … … 1753 2088 AnyPropertyType, /* Property type */ 1754 2089 &aPropType, &iPropFormat, &cItems, &cbRemaining, &pcData); 1755 if ( RT_UNLIKELY(xRc != Success))1756 LogFlowThisFunc(("Error getting XA_XdndSelection property of proxy window=%#x: %s\n",1757 m_wndProxy, gX11->xErrorToString(xRc).c_str()));2090 if (xRc != Success) 2091 logError("Error getting XA_XdndSelection property of proxy window=%#x: %s\n", 2092 m_wndProxy, gX11->xErrorToString(xRc).c_str()); 1758 2093 1759 2094 LogFlowThisFunc(("strType=%s, iPropFormat=%d, cItems=%RU32, cbRemaining=%RU32\n", … … 1797 2132 if (RT_SUCCESS(rc)) 1798 2133 { 2134 /* Was the drop accepted by the host? That is, anything than ignoring. */ 2135 bool fDropAccepted = uAction > DND_IGNORE_ACTION; 2136 1799 2137 /* Confirm the result of the transfer to the target window. */ 1800 2138 XClientMessageEvent m; … … 1805 2143 m.message_type = xAtom(XA_XdndFinished); 1806 2144 m.format = 32; 1807 m.data.l[0] = m_wndProxy; /* Target window. */ 1808 m.data.l[1] = 0; /* Don't accept the drop to not make the guest stuck. */ 1809 m.data.l[2] = RT_SUCCESS(rc) 1810 ? toAtomAction(uAction) : None; /* Action used on success */ 2145 m.data.l[XdndFinishedWindow] = m_wndProxy; /* Target window. */ 2146 m.data.l[XdndFinishedFlags] = fDropAccepted ? RT_BIT(0) : 0; /* Was the drop accepted? */ 2147 m.data.l[XdndFinishedAction] = fDropAccepted ? toAtomAction(uAction) : None; /* Action used on accept. */ 1811 2148 1812 2149 xRc = XSendEvent(m_pDisplay, wndSource, True, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1813 if ( RT_UNLIKELY(xRc == 0))1814 LogFlowThisFunc(("Error sending XA_XdndFinished event to proxywindow=%#x: %s\n",1815 m_wndProxy, gX11->xErrorToString(xRc).c_str()));2150 if (xRc == 0) 2151 logError("Error sending XA_XdndFinished event to source window=%#x: %s\n", 2152 wndSource, gX11->xErrorToString(xRc).c_str()); 1816 2153 } 1817 2154 else … … 1823 2160 { 1824 2161 /** @todo Support incremental transfers. */ 1825 AssertMsgFailed(("Incrementally transfers are not supported yet\n")); 2162 AssertMsgFailed(("Incremental transfers are not supported yet\n")); 2163 2164 logError("Incremental transfers are not supported yet\n"); 1826 2165 rc = VERR_NOT_IMPLEMENTED; 1827 2166 } 1828 2167 else 1829 2168 { 1830 LogFlowFunc(("Not supported data type: %s\n", gX11->xAtomToString(aPropType).c_str()));2169 logError("Not supported data type: %s\n", gX11->xAtomToString(aPropType).c_str()); 1831 2170 rc = VERR_NOT_SUPPORTED; 1832 2171 } … … 1839 2178 LogFlowFunc(("Cancelling drop ...\n")); 1840 2179 1841 /* Cancel the operation -- inform the source window. */ 2180 /* Cancel the operation -- inform the source window by 2181 * sending a XdndFinished message so that the source can toss the required data. */ 1842 2182 XClientMessageEvent m; 1843 2183 RT_ZERO(m); … … 1845 2185 m.display = m_pDisplay; 1846 2186 m.window = m_wndProxy; 1847 m.message_type = xAtom(XA_Xdnd Leave);2187 m.message_type = xAtom(XA_XdndFinished); 1848 2188 m.format = 32; 1849 m.data.l[0] = wndSource; /* Source window. */ 2189 m.data.l[XdndFinishedWindow] = m_wndProxy; /* Target window. */ 2190 m.data.l[XdndFinishedFlags] = 0; /* Did not accept the drop. */ 2191 m.data.l[XdndFinishedAction] = None; /* Action used on accept. */ 1850 2192 1851 2193 xRc = XSendEvent(m_pDisplay, wndSource, False, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1852 if (RT_UNLIKELY(xRc == 0)) 1853 { 1854 logError("Error sending XA_XdndLeave event to proxy window=%#x: %s\n", 1855 m_wndProxy, gX11->xErrorToString(xRc).c_str()); 1856 } 2194 if (xRc == 0) 2195 logError("Error sending XA_XdndFinished event to source window=%#x: %s\n", 2196 wndSource, gX11->xErrorToString(xRc).c_str()); 1857 2197 } 1858 2198 … … 1874 2214 { 1875 2215 int rc2 = VbglR3DnDGHSendError(&m_dndCtx, rc); 1876 AssertRC(rc2); 2216 LogFlowThisFunc(("Sending error to host resulted in %Rrc\n", rc2)); 2217 /* This is not fatal for us, just ignore. */ 1877 2218 } 1878 2219 1879 2220 /* At this point, we have either successfully transfered any data or not. 1880 * So reset our internal state because we are done here for this transaction. */ 2221 * So reset our internal state because we are done here for the current (ongoing) 2222 * drag and drop operation. */ 1881 2223 reset(); 1882 2224 … … 1938 2280 1939 2281 int xRc = XTestFakeButtonEvent(m_pDisplay, 1, fPress ? True : False, CurrentTime); 1940 if (R T_UNLIKELY(xRc == 0))2282 if (Rc == 0) 1941 2283 logError("Error sending XTestFakeButtonEvent event: %s\n", gX11->xErrorToString(xRc).c_str()); 1942 2284 XFlush(m_pDisplay); … … 1945 2287 { 1946 2288 #endif 1947 LogFlowThisFunc(("XText extension not available or disabled\n")); 2289 LogFlowThisFunc(("Note: XText extension not available or disabled\n")); 2290 2291 if ( rx == -1 2292 && ry == -1) 2293 { 2294 Window wndTemp, wndChild; 2295 int wx, wy; unsigned int mask; 2296 XQueryPointer(m_pDisplay, m_wndRoot, &wndTemp, &wndChild, &rx, &ry, &wx, &wy, &mask); 2297 LogFlowThisFunc(("cursorRootX=%d, cursorRootY=%d\n", rx, ry)); 2298 } 1948 2299 1949 2300 XButtonEvent eBtn; … … 1967 2318 eBtn.y_root = ry; 1968 2319 1969 //XTranslateCoordinates(m_pDisplay, eBtn.root, eBtn.window, eBtn.x_root, eBtn.y_root, &eBtn.x, &eBtn.y, &eBtn.subwindow); 1970 #if 0 1971 int xRc = XSendEvent(m_pDisplay, eBtn.window, True /* fPropagate */, 2320 XTranslateCoordinates(m_pDisplay, eBtn.root, eBtn.window, eBtn.x_root, eBtn.y_root, &eBtn.x, &eBtn.y, &eBtn.subwindow); 2321 LogFlowThisFunc(("x=%d, y=%d\n", eBtn.x, eBtn.y)); 2322 #if 1 2323 int xRc = XSendEvent(m_pDisplay, wndDest, True /* fPropagate */, 1972 2324 fPress 1973 2325 ? ButtonPressMask : ButtonReleaseMask, 1974 2326 reinterpret_cast<XEvent*>(&eBtn)); 2327 if (xRc == 0) 2328 logError("Error sending XButtonEvent event to window=%#x: %s\n", wndDest, gX11->xErrorToString(xRc).c_str()); 1975 2329 #else 1976 2330 int xRc = XSendEvent(m_pDisplay, eBtn.window, False /* fPropagate */, 1977 2331 0 /* Mask */, reinterpret_cast<XEvent*>(&eBtn)); 1978 if ( RT_UNLIKELY(xRc == 0))2332 if (xRc == 0) 1979 2333 logError("Error sending XButtonEvent event to window=%#x: %s\n", wndDest, gX11->xErrorToString(xRc).c_str()); 1980 #endif1981 1982 #ifdef DEBUG1983 Window wndTemp, wndChild;1984 int wx, wy; unsigned int mask;1985 XQueryPointer(m_pDisplay, m_wndRoot, &wndTemp, &wndChild, &rx, &ry, &wx, &wy, &mask);1986 LogFlowThisFunc(("cursorRootX=%d, cursorRootY=%d\n", rx, ry));1987 2334 #endif 1988 2335 … … 2004 2351 * @param piRootX X coordinate relative to the root window's origin. Optional. 2005 2352 * @param piRootY Y coordinate relative to the root window's origin. Optional. 2006 * @param fMouseMove Whether to move the mouse cursor to the root window's origin or not. 2007 */ 2008 int DragInstance::proxyWinShow(int *piRootX /*= NULL*/, 2009 int *piRootY /*= NULL*/, 2010 bool fMouseMove /*= false */) const 2353 */ 2354 int DragInstance::proxyWinShow(int *piRootX /* = NULL */, int *piRootY /* = NULL */) const 2011 2355 { 2012 2356 /* piRootX is optional. */ … … 2018 2362 2019 2363 #if 0 2364 # ifdef VBOX_DND_WITH_XTEST 2020 2365 XTestGrabControl(m_pDisplay, False); 2366 # endif 2021 2367 #endif 2022 2368 … … 2028 2374 Window wndRoot, wndChild; 2029 2375 Bool fInRootWnd = XQueryPointer(m_pDisplay, m_wndRoot, &wndRoot, &wndChild, 2030 &iRootX, &iRootY, 2031 &iChildX, &iChildY, &iMask); 2376 &iRootX, &iRootY, &iChildX, &iChildY, &iMask); 2032 2377 2033 2378 LogFlowThisFunc(("fInRootWnd=%RTbool, wndRoot=0x%x, wndChild=0x%x, iRootX=%d, iRootY=%d\n", … … 2047 2392 /* Spawn our proxy window over the entire screen, making it an easy drop target for the host's cursor. */ 2048 2393 int iScreenID = XDefaultScreen(m_pDisplay); 2394 LogFlowThisFunc(("Proxy window screenID=%d, x=%d, y=%d, width=%d, height=%d\n", 2395 iScreenID, 0, 0, XDisplayWidth(m_pDisplay, iScreenID), XDisplayHeight(m_pDisplay, iScreenID))); 2049 2396 XMoveResizeWindow(m_pDisplay, m_wndProxy, 0, 0, XDisplayWidth(m_pDisplay, iScreenID), XDisplayHeight(m_pDisplay, iScreenID)); 2050 2397 /** @todo What about multiple screens? Test this! */ 2051 2398 2052 if (fMouseMove) 2053 rc = mouseCursorMove(iRootX, iRootY); 2399 XFlush(m_pDisplay); 2054 2400 2055 2401 XSynchronize(m_pDisplay, False /* Disable sync */); 2056 2402 2057 2403 #if 0 2404 # ifdef VBOX_DND_WITH_XTEST 2058 2405 XTestGrabControl(m_pDisplay, True); 2406 # endif 2059 2407 #endif 2060 2408 2409 LogFlowFuncLeaveRC(rc); 2061 2410 return rc; 2062 2411 } … … 2069 2418 LogFlowFuncEnter(); 2070 2419 2071 #ifndef VBOX_DND_DEBUG_WND2072 2420 XUnmapWindow(m_pDisplay, m_wndProxy); 2073 #endif 2074 m_eventQueue.clear(); 2421 XFlush(m_pDisplay); 2422 2423 m_eventQueueList.clear(); 2075 2424 2076 2425 return VINF_SUCCESS; /** @todo Add error checking. */ 2426 } 2427 2428 /** 2429 * Allocates the name (title) of an X window. 2430 * The returned pointer must be freed using RTStrFree(). 2431 * 2432 * @returns Pointer to the allocated window name. 2433 * @param wndThis Window to retrieve name for. 2434 * 2435 * @remark If the window title is not available, the text 2436 * "<No name>" will be returned. 2437 */ 2438 char *DragInstance::wndX11GetNameA(Window wndThis) const 2439 { 2440 char *pszName = NULL; 2441 2442 XTextProperty propName; 2443 if (XGetWMName(m_pDisplay, wndThis, &propName)) 2444 { 2445 if (propName.value) 2446 pszName = RTStrDup((char *)propName.value); /** @todo UTF8? */ 2447 XFree(propName.value); 2448 } 2449 2450 if (!pszName) /* No window name found? */ 2451 pszName = RTStrDup("<No name>"); 2452 2453 return pszName; 2077 2454 } 2078 2455 … … 2123 2500 } 2124 2501 2125 if ( cItems > 0 2126 && pcbData) 2127 { 2502 LogFlowThisFunc(("wndThis=%#x, cItems=%RU32, pcbData=%p\n", wndThis, cItems, pcbData)); 2503 2504 if (cItems > 0) 2505 { 2506 AssertPtr(pcbData); 2128 2507 Atom *paData = reinterpret_cast<Atom *>(pcbData); 2129 2508 2130 2509 for (unsigned i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, cItems); i++) 2131 2510 { 2132 LogFlowThisFunc(("Received action: %s\n", 2133 gX11->xAtomToString(paData[i]).c_str())); 2134 2511 LogFlowThisFunc(("\t%s\n", gX11->xAtomToString(paData[i]).c_str())); 2135 2512 lstActions.append(paData[i]); 2136 2513 } … … 2167 2544 } 2168 2545 2169 if ( cItems > 0 2170 && pcbData) 2171 { 2172 Atom *paData = reinterpret_cast<Atom*>(pcbData); 2546 LogFlowThisFunc(("wndThis=%#x, cItems=%RU32, pcbData=%p\n", wndThis, cItems, pcbData)); 2547 2548 if (cItems > 0) 2549 { 2550 AssertPtr(pcbData); 2551 Atom *paData = reinterpret_cast<Atom *>(pcbData); 2173 2552 2174 2553 for (unsigned i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, cItems); i++) 2175 2554 { 2176 LogFlowThisFunc(("Received format via XdndTypeList: %s\n", 2177 gX11->xAtomToString(paData[i]).c_str())); 2178 2555 LogFlowThisFunc(("\t%s\n", gX11->xAtomToString(paData[i]).c_str())); 2179 2556 lstTypes.append(paData[i]); 2180 2557 } … … 2220 2597 { 2221 2598 if (lstFormats.isEmpty()) 2222 return V INF_SUCCESS;2599 return VERR_INVALID_PARAMETER; 2223 2600 2224 2601 /* We support TARGETS and the data types. */ … … 2361 2738 uint32_t uActions = DND_IGNORE_ACTION; 2362 2739 2363 for (size_t i = 0; i < lstActions.size(); ++i)2740 for (size_t i = 0; i < lstActions.size(); i++) 2364 2741 uActions |= toHGCMAction(lstActions.at(i)); 2365 2742 … … 2406 2783 2407 2784 LogRel(("DnD: Started\n")); 2785 LogRel2(("DnD: %sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr())); 2408 2786 2409 2787 /* Enter the main event processing loop. */ … … 2456 2834 case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED: 2457 2835 { 2458 rc = m_pCurDnD->hgDrop( );2836 rc = m_pCurDnD->hgDrop(e.hgcm.u.a.uXpos, e.hgcm.u.a.uYpos, e.hgcm.u.a.uDefAction); 2459 2837 break; 2460 2838 } … … 2478 2856 default: 2479 2857 { 2480 LogFlowThisFunc(("Unsupported message: %RU32\n", e.hgcm.uType));2858 m_pCurDnD->logError("Received unsupported message: %RU32\n", e.hgcm.uType); 2481 2859 rc = VERR_NOT_SUPPORTED; 2482 2860 break; … … 2485 2863 2486 2864 LogFlowFunc(("Message %RU32 processed with %Rrc\n", e.hgcm.uType, rc)); 2487 if ( RT_FAILURE(rc) 2488 /* 2489 * Note: The hgXXX and ghXXX functions of the DnD instance above may return 2490 * VERR_INVALID_STATE in case we're not in the expected state they want 2491 * to operate in. As the user might drag content back and forth to/from 2492 * the host/guest we don't want to reset the overall state here in case 2493 * a VERR_INVALID_STATE occurs. Just continue in our initially set mode. 2494 */ 2495 && rc != VERR_INVALID_STATE) 2865 if (RT_FAILURE(rc)) 2496 2866 { 2497 m_pCurDnD->logError("Error: Processing message %RU32 failed with %Rrc\n", e.hgcm.uType, rc); 2867 /* Tell the user. */ 2868 m_pCurDnD->logError("Error processing message %RU32, failed with %Rrc, resetting all\n", e.hgcm.uType, rc); 2498 2869 2499 2870 /* If anything went wrong, do a reset and start over. */ … … 2653 3024 else 2654 3025 { 2655 Log FlowFunc(("Processing next message failed with rc=%Rrc\n", rc));3026 LogRel(("DnD: Processing next message failed with rc=%Rrc\n", rc)); 2656 3027 2657 3028 /* Old(er) hosts either are broken regarding DnD support or otherwise … … 2719 3090 2720 3091 RTCString strType = xAtomToString(pEvent->message_type); 2721 LogFlowFunc(("ClientMessage: %s (%RU32), serial=%RU32, wnd=%#x\n", strType.c_str(), 2722 pEvent->message_type, pEvent->serial, pEvent->window)); 2723 2724 if (pEvent->message_type == xAtom(XA_XdndPosition)) 2725 { 2726 int32_t dwPos = pEvent->data.l[2]; 2727 int32_t dwAction = pEvent->data.l[4]; 2728 2729 LogFlowFunc(("XA_XdndPosition x=%RI32, y=%RI32, dwAction=%RI32\n", 2730 RT_HIWORD(dwPos), RT_LOWORD(dwPos), dwAction)); 2731 } 2732 else if (pEvent->message_type == xAtom(XA_XdndDrop)) 2733 { 2734 LogFlowFunc(("XA_XdndDrop\n")); 2735 } 2736 3092 LogFlowFunc(("ClientMessage: %s from wnd=%#x\n", strType.c_str(), pEvent->window)); 2737 3093 break; 2738 3094 }
Note:
See TracChangeset
for help on using the changeset viewer.