Changeset 55820 in vbox for trunk/src/VBox/Additions
- Timestamp:
- May 12, 2015 11:37:23 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp
r55707 r55820 17 17 18 18 #include <X11/Xlib.h> 19 #include <X11/Xutil.h> 19 20 #include <X11/Xatom.h> 20 21 #ifdef VBOX_DND_WITH_XTEST … … 287 288 } 288 289 289 /* Todo: make this iterative*/290 /** todo Make this iterative. */ 290 291 Window xHelpers::applicationWindowBelowCursor(Window wndParent) const 291 292 { … … 341 342 #endif 342 343 344 #define VBoxDnDAtomList RTCList<Atom> 345 343 346 /* For now only one DragInstance will exits when the app is running. In the 344 347 * future the support for having more than one drag and drop operation supported at the … … 353 356 Initialized, 354 357 Dragging, 355 Dropped 358 Dropped, 359 State_32BIT_Hack = 0x7fffffff 356 360 }; 357 361 … … 360 364 Unknown = 0, 361 365 HG, 362 GH 366 GH, 367 Mode_32Bit_Hack = 0x7fffffff 363 368 }; 364 369 … … 399 404 int proxyWinShow(int *piRootX = NULL, int *piRootY = NULL, bool fMouseMove = false) const; 400 405 int proxyWinHide(void); 401 void registerForEvents(Window w) const; 402 403 void setActionsWindowProperty(Window wndThis, const RTCList<Atom> &lstActions) const; 404 void clearActionsWindowProperty(Window wndThis) const; 405 void setFormatsWindowProperty(Window wndThis, Atom property) const; 406 void clearFormatsWindowProperty(Window wndThis) const; 407 408 RTCList<Atom> toAtomList(const RTCList<RTCString> &lstFormats) const; 409 RTCList<Atom> toAtomList(void *pvData, uint32_t cbData) const; 410 static Atom toX11Action(uint32_t uAction); 411 static RTCList<Atom> toX11Actions(uint32_t uActions); 412 static uint32_t toHGCMAction(Atom atom); 413 static uint32_t toHGCMActions(const RTCList<Atom> &actionsList); 406 407 void wndXDnDClearActionList(Window wndThis) const; 408 void wndXDnDClearTypeList(Window wndThis) const; 409 int wndXDnDGetActionList(Window wndThis, VBoxDnDAtomList &lstActions) const; 410 int wndXDnDGetTypeList(Window wndThis, VBoxDnDAtomList &lstTypes) const; 411 int wndXDnDSetActionList(Window wndThis, const VBoxDnDAtomList &lstActions) const; 412 int wndXDnDSetFormatList(Window wndThis, Atom property, const VBoxDnDAtomList &lstFormats) const; 413 414 int toAtomList(const RTCList<RTCString> &lstFormats, VBoxDnDAtomList &lstAtoms) const; 415 int toAtomList(const void *pvData, uint32_t cbData, VBoxDnDAtomList &lstAtoms) const; 416 static Atom toAtomAction(uint32_t uAction); 417 static int toAtomActions(uint32_t uActions, VBoxDnDAtomList &lstAtoms); 418 static uint32_t toHGCMAction(Atom atom); 419 static uint32_t toHGCMActions(const RTCList<Atom> &actionsList); 414 420 415 421 protected: … … 425 431 Window m_wndCur; 426 432 long m_curVer; 427 RTCList<Atom> m_formats;428 RTCList<Atom> m_actions;433 VBoxDnDAtomList m_lstFormats; 434 VBoxDnDAtomList m_lstActions; 429 435 /** Deferred host to guest selection event for sending to the 430 436 * target window as soon as data from the host arrived. */ 431 437 XEvent m_eventHgSelection; 432 438 /** Current operation mode. */ 433 Mode m_ mode;439 Mode m_enmMode; 434 440 /** Current state of operation mode. */ 435 State m_ state;441 State m_enmState; 436 442 /** The instance's own X event queue. */ 437 443 RTCMTList<XEvent> m_eventQueue; … … 467 473 468 474 private: 475 469 476 int x11DragAndDropInit(void); 470 477 static int hgcmEventThread(RTTHREAD hThread, void *pvUser); … … 472 479 473 480 void clearEventQueue(); 474 475 /* Usually XCheckMaskEvent could be used for querying selected x11 events.476 * Unfortunately this doesn't work exactly with the events we need. So we477 * use this predicate method below and XCheckIfEvent. */478 static bool isDnDRespondEvent(Display * /* pDisplay */, XEvent *pEvent, char *pUser)479 {480 if (!pEvent)481 return false;482 if ( pEvent->type == SelectionClear483 || pEvent->type == ClientMessage484 || pEvent->type == MotionNotify485 || pEvent->type == SelectionRequest)486 // || ( pEvent->type == ClientMessage487 // && reinterpret_cast<XClientMessageEvent*>(pEvent)->window == reinterpret_cast<Window>(pUser))488 // || ( pEvent->type == SelectionRequest489 // && reinterpret_cast<XSelectionRequestEvent*>(pEvent)->requestor == reinterpret_cast<Window>(pUser)))490 return true;491 return false;492 }493 481 494 482 /* Private member vars */ … … 524 512 , m_wndCur(0) 525 513 , m_curVer(-1) 526 , m_ mode(Unknown)527 , m_ state(Uninitialized)514 , m_enmMode(Unknown) 515 , m_enmState(Uninitialized) 528 516 { 529 517 uninit(); … … 538 526 VbglR3DnDDisconnect(&m_dndCtx); 539 527 540 m_ state = Uninitialized;528 m_enmState = Uninitialized; 541 529 m_screenId = -1; 542 530 m_pScreen = 0; … … 557 545 XSetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection), None, CurrentTime); 558 546 559 /* Clear any other DnD specific data on the proxy win . */560 clearFormatsWindowProperty(m_wndProxy);561 clearActionsWindowProperty(m_wndProxy);547 /* Clear any other DnD specific data on the proxy window. */ 548 wndXDnDClearTypeList(m_wndProxy); 549 wndXDnDClearActionList(m_wndProxy); 562 550 563 551 /* Reset the internal state. */ 564 m_ actions.clear();565 m_ formats.clear();566 m_wndCur = 0;567 m_curVer = -1;568 m_ state = Initialized;569 m_ mode = Unknown;552 m_lstActions.clear(); 553 m_lstFormats.clear(); 554 m_wndCur = 0; 555 m_curVer = -1; 556 m_enmState = Initialized; 557 m_enmMode = Unknown; 570 558 m_eventQueue.clear(); 571 559 } … … 599 587 break; 600 588 } 589 #if 0 601 590 /* Get the screen number from the x11 server. */ 602 // pDrag->screen = ScreenOfDisplay(m_pDisplay, u32ScreenId); 603 // if (!pDrag->screen) 604 // { 605 // rc = VERR_GENERAL_FAILURE; 606 // break; 607 // } 591 pDrag->screen = ScreenOfDisplay(m_pDisplay, u32ScreenId); 592 if (!pDrag->screen) 593 { 594 rc = VERR_GENERAL_FAILURE; 595 break; 596 } 597 #endif 608 598 m_screenId = u32ScreenId; 599 609 600 /* Now query the corresponding root window of this screen. */ 610 601 m_wndRoot = RootWindow(m_pDisplay, m_screenId); … … 624 615 attr.event_mask = EnterWindowMask | LeaveWindowMask 625 616 | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; 617 attr.override_redirect = True; 626 618 attr.do_not_propagate_mask = NoEventMask; 627 attr.override_redirect = True;628 619 #ifdef VBOX_DND_DEBUG_WND 629 attr.background_pixel = WhitePixel(m_pDisplay, m_screenId); 630 #endif 620 attr.background_pixel = XWhitePixel(m_pDisplay, m_screenId); 621 attr.border_pixel = XBlackPixel(m_pDisplay, m_screenId); 622 m_wndProxy = XCreateWindow(m_pDisplay, m_wndRoot /* Parent */, 623 100, 100, /* Position */ 624 100, 100, /* Width + height */ 625 2, /* Border width */ 626 CopyFromParent, /* Depth */ 627 InputOutput, /* Class */ 628 CopyFromParent, /* Visual */ 629 CWBackPixel 630 | CWBorderPixel 631 | CWOverrideRedirect 632 | CWDontPropagate, /* Value mask */ 633 &attr); /* Attributes for value mask */ 634 #else 631 635 m_wndProxy = XCreateWindow(m_pDisplay, m_wndRoot /* Parent */, 632 636 0, 0, /* Position */ … … 637 641 CopyFromParent, /* Visual */ 638 642 CWOverrideRedirect | CWDontPropagate, /* Value mask */ 639 &attr /* Attributes for value mask */); 643 &attr); /* Attributes for value mask */ 644 #endif 640 645 if (!m_wndProxy) 641 646 { … … 645 650 } 646 651 647 LogFlowThisFunc(("Created proxy window 0x%x at m_wndRoot=0x%x ...\n", 648 m_wndProxy, m_wndRoot)); 652 #ifdef VBOX_DND_DEBUG_WND 653 XFlush(m_pDisplay); 654 XMapWindow(m_pDisplay, m_wndProxy); 655 XRaiseWindow(m_pDisplay, m_wndProxy); 656 XFlush(m_pDisplay); 657 #endif 658 LogFlowThisFunc(("Created proxy window 0x%x at m_wndRoot=0x%x ...\n", m_wndProxy, m_wndRoot)); 649 659 650 660 /* Set the window's name for easier lookup. */ … … 659 669 if (RT_SUCCESS(rc)) 660 670 { 661 m_ state = Initialized;671 m_enmState = Initialized; 662 672 } 663 673 else … … 688 698 AssertReturn(e.type == ClientMessage, VERR_INVALID_PARAMETER); 689 699 690 LogFlowThisFunc(("m_mode=%d, m_state=%d\n", m_mode, m_state)); 691 LogFlowThisFunc(("Event wnd=%#x, msg=%s\n", 692 e.xclient.window, 693 xAtomToString(e.xclient.message_type).c_str())); 700 LogFlowThisFunc(("mode=%d, state=%d\n", m_enmMode, m_enmState)); 701 LogFlowThisFunc(("Event wnd=%#x, msg=%s\n", e.xclient.window, xAtomToString(e.xclient.message_type).c_str())); 702 694 703 int rc; 695 704 696 switch (m_ mode)705 switch (m_enmMode) 697 706 { 698 707 case HG: 699 708 { 700 /* Client messages are used to inform us about the status of a XdndAware 701 * window, in response of some events we send to them. */ 709 /* 710 * Client messages are used to inform us about the status of a XdndAware 711 * window, in response of some events we send to them. 712 */ 702 713 if ( e.xclient.message_type == xAtom(XA_XdndStatus) 703 714 && m_wndCur == static_cast<Window>(e.xclient.data.l[0])) 704 715 { 705 /* The XdndStatus message tell us if the window will accept the DnD 716 /* 717 * The XdndStatus message tell us if the window will accept the DnD 706 718 * event and with which action. We immediately send this info down to 707 * the host as a response of a previous DnD message. */ 708 LogFlowThisFunc(("XA_XdndStatus wnd=%#x, accept=%RTbool, action=%s\n", 719 * the host as a response of a previous DnD message. 720 */ 721 LogFlowThisFunc(("XA_XdndStatus: wnd=%#x, accept=%RTbool, action=%s\n", 709 722 e.xclient.data.l[0], 710 723 ASMBitTest(&e.xclient.data.l[1], 0), … … 722 735 rc = VINF_SUCCESS; 723 736 724 /* This message is sen d on aun/successful DnD drop request. */737 /* This message is sent on an un/successful DnD drop request. */ 725 738 LogFlowThisFunc(("XA_XdndFinished: wnd=%#x, success=%RTbool, action=%s\n", 726 739 e.xclient.data.l[0], 727 740 ASMBitTest(&e.xclient.data.l[1], 0), 728 741 xAtomToString(e.xclient.data.l[2]).c_str())); 729 reset(); 742 743 proxyWinHide(); 730 744 } 731 745 else … … 740 754 741 755 case GH: 742 { 743 LogFlowThisFunc(("Enqueuing ClientMessage\n")); 744 756 case Unknown: /* Mode not set (yet), just add what we got. */ 757 { 745 758 m_eventQueue.append(e); 746 759 rc = RTSemEventSignal(m_hEventSem); 760 break; 761 } 762 763 default: 764 { 765 AssertMsgFailed(("Drag and drop mode not implemented: %RU32\n", m_enmMode)); 766 rc = VERR_NOT_IMPLEMENTED; 767 break; 768 } 769 } 770 771 LogFlowThisFunc(("Returning rc=%Rrc\n", rc)); 772 return rc; 773 } 774 775 int DragInstance::onX11SelectionNotify(const XEvent &e) 776 { 777 AssertReturn(e.type == SelectionNotify, VERR_INVALID_PARAMETER); 778 779 LogFlowThisFunc(("m_mode=%d, m_state=%d\n", m_enmMode, m_enmState)); 780 781 int rc; 782 783 switch (m_enmMode) 784 { 785 case GH: 786 { 787 if (m_enmState == Dropped) 788 { 789 m_eventQueue.append(e); 790 rc = RTSemEventSignal(m_hEventSem); 791 } 747 792 break; 748 793 } … … 761 806 } 762 807 763 int DragInstance::onX11SelectionNotify(const XEvent &e)764 {765 AssertReturn(e.type == SelectionNotify, VERR_INVALID_PARAMETER);766 767 LogFlowThisFunc(("m_mode=%d, m_state=%d\n", m_mode, m_state));768 769 int rc = VINF_SUCCESS;770 771 switch (m_mode)772 {773 case GH:774 {775 if (m_state == Dropped)776 {777 LogFlowThisFunc(("Enqueuing SelectionNotify\n"));778 779 m_eventQueue.append(e);780 rc = RTSemEventSignal(m_hEventSem);781 }782 break;783 }784 785 default:786 {787 LogFlowThisFunc(("Unhandled: wnd=%#x, msg=%s\n",788 e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str()));789 rc = VERR_INVALID_STATE;790 break;791 }792 }793 794 LogFlowThisFunc(("Returning rc=%Rrc\n", rc));795 return rc;796 }797 798 799 808 int DragInstance::onX11SelectionRequest(const XEvent &e) 800 809 { 801 810 AssertReturn(e.type == SelectionRequest, VERR_INVALID_PARAMETER); 802 811 803 LogFlowThisFunc(("m_mode=%d, m_state=%d\n", m_ mode, m_state));812 LogFlowThisFunc(("m_mode=%d, m_state=%d\n", m_enmMode, m_enmState)); 804 813 LogFlowThisFunc(("Event owner=%#x, requestor=%#x, selection=%s, target=%s, prop=%s, time=%u\n", 805 814 e.xselectionrequest.owner, … … 811 820 int rc; 812 821 813 switch (m_mode) 822 bool fSendEvent = false; 823 Atom atmTarget = None; 824 Atom atmProperty = None; 825 826 switch (m_enmMode) 814 827 { 815 828 case HG: … … 832 845 /* If so, set the window property with the formats on the requestor 833 846 * window. */ 834 setFormatsWindowProperty(e.xselectionrequest.requestor, e.xselectionrequest.property); 835 847 rc = wndXDnDSetFormatList(e.xselectionrequest.requestor, e.xselectionrequest.property, m_lstFormats); 848 if (RT_SUCCESS(rc)) 849 { 850 atmTarget = e.xselectionrequest.target; 851 atmProperty = e.xselectionrequest.property; 852 853 fSendEvent = true; 854 } 855 } 856 /* Is the requestor asking for a specific MIME type (we support)? */ 857 else if (m_lstFormats.contains(e.xselectionrequest.target)) 858 { 859 LogFlowThisFunc(("wnd=%#x asking for data, format=%s\n", 860 e.xselectionrequest.requestor, xAtomToString(e.xselectionrequest.target).c_str())); 861 862 /* If so, we need to inform the host about this request. Save the 863 * selection request event for later use. */ 864 if (m_enmState != Dropped) 865 { 866 LogFlowThisFunc(("Wrong state (%RU32), refusing request\n", m_enmState)); 867 868 atmTarget = None; 869 atmProperty = e.xselectionrequest.property; 870 871 fSendEvent = true; 872 } 873 else 874 { 875 LogFlowThisFunc(("Saving selection notify message\n")); 876 877 memcpy(&m_eventHgSelection, &e, sizeof(XEvent)); 878 879 RTCString strFormat = xAtomToString(e.xselectionrequest.target); 880 Assert(strFormat.isNotEmpty()); 881 882 rc = VbglR3DnDHGRequestData(&m_dndCtx, strFormat.c_str()); 883 LogFlowThisFunc(("Requested data from host as \"%s\", rc=%Rrc\n", strFormat.c_str(), rc)); 884 } 885 } 886 /* Anything else. */ 887 else 888 { 889 LogFlowThisFunc(("Refusing unknown command\n")); 890 891 /* We don't understand this request message and therefore answer with an 892 * refusal messages. */ 893 fSendEvent = true; 894 } 895 896 if ( RT_SUCCESS(rc) 897 && fSendEvent) 898 { 836 899 XEvent s; 837 900 RT_ZERO(s); … … 841 904 s.xselection.selection = e.xselectionrequest.selection; 842 905 s.xselection.requestor = e.xselectionrequest.requestor; 843 s.xselection.target = e.xselectionrequest.target;844 s.xselection.property = e.xselectionrequest.property;906 s.xselection.target = atmTarget; 907 s.xselection.property = atmProperty; 845 908 846 909 int xRc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s); 847 910 if (RT_UNLIKELY(xRc == 0)) 848 LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor)); 911 logError("Error sending SelectionNotify(1) event to wnd=%#x: %s\n", e.xselectionrequest.requestor, 912 gX11->xErrorToString(xRc).c_str()); 849 913 } 850 /* Is the requestor asking for a specific MIME type (we support)? */851 else if (m_formats.contains(e.xselectionrequest.target))852 {853 LogFlowThisFunc(("wnd=%#x asking for data, format=%s\n",854 e.xselectionrequest.requestor, xAtomToString(e.xselectionrequest.target).c_str()));855 856 /* If so, we need to inform the host about this request. Save the857 * selection request event for later use. */858 if ( m_state != Dropped)859 // || m_curWin != e.xselectionrequest.requestor)860 {861 LogFlowThisFunc(("Wrong state, refusing request\n"));862 863 XEvent s;864 RT_ZERO(s);865 s.xselection.type = SelectionNotify;866 s.xselection.display = e.xselection.display;867 s.xselection.time = e.xselectionrequest.time;868 s.xselection.selection = e.xselectionrequest.selection;869 s.xselection.requestor = e.xselectionrequest.requestor;870 s.xselection.target = None;871 s.xselection.property = e.xselectionrequest.property;872 873 int xRc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);874 if (RT_UNLIKELY(xRc == 0))875 LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor));876 }877 else878 {879 LogFlowThisFunc(("Saving selection notify message\n"));880 881 memcpy(&m_eventHgSelection, &e, sizeof(XEvent));882 883 RTCString strFormat = xAtomToString(e.xselectionrequest.target);884 Assert(strFormat.isNotEmpty());885 rc = VbglR3DnDHGRequestData(&m_dndCtx, strFormat.c_str());886 LogFlowThisFunc(("Requesting data from host as \"%s\", rc=%Rrc\n",887 strFormat.c_str(), rc));888 }889 }890 /* Anything else. */891 else892 {893 LogFlowThisFunc(("Refusing unknown command\n"));894 895 /* We don't understand this request message and therefore answer with an896 * refusal messages. */897 XEvent s;898 RT_ZERO(s);899 s.xselection.type = SelectionNotify;900 s.xselection.display = e.xselection.display;901 s.xselection.time = e.xselectionrequest.time;902 s.xselection.selection = e.xselectionrequest.selection;903 s.xselection.requestor = e.xselectionrequest.requestor;904 s.xselection.target = None; /* default is refusing */905 s.xselection.property = None; /* default is refusing */906 int xRc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);907 if (RT_UNLIKELY(xRc == 0))908 LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor));909 }910 914 911 915 break; … … 914 918 default: 915 919 { 916 LogFlowThisFunc(("Unhandled : wnd=%#x, msg=%s\n",920 LogFlowThisFunc(("Unhandled message for wnd=%#x: %s\n", 917 921 e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str())); 918 922 rc = VERR_INVALID_STATE; … … 974 978 975 979 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 976 bool DragInstance::waitForX11Msg(XEvent &evX, int iType, 977 RTMSINTERVAL uTimeoutMS /* = 100 */) 980 bool DragInstance::waitForX11Msg(XEvent &evX, int iType, RTMSINTERVAL uTimeoutMS /* = 100 */) 978 981 { 979 982 LogFlowThisFunc(("iType=%d, uTimeoutMS=%RU32, cEventQueue=%zu\n", iType, uTimeoutMS, m_eventQueue.size())); … … 1070 1073 while (RTTimeMilliTS() - uiStart < uTimeoutMS); 1071 1074 1072 LogFlowThisFunc(("Returning fFound=%RTbool, msRuntime=%RU64\n", 1073 fFound, RTTimeMilliTS() - uiStart)); 1075 LogFlowThisFunc(("Returning fFound=%RTbool, msRuntime=%RU64\n", fFound, RTTimeMilliTS() - uiStart)); 1074 1076 return fFound; 1075 1077 } … … 1082 1084 int DragInstance::hgEnter(const RTCList<RTCString> &formats, uint32_t uActions) 1083 1085 { 1084 if (m_mode != Unknown) 1086 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState)); 1087 1088 if (m_enmMode != Unknown) 1085 1089 return VERR_INVALID_STATE; 1086 1090 … … 1094 1098 #endif 1095 1099 1096 m_formats = toAtomList(formats); 1097 1098 /* If we have more than 3 formats we have to use the type list extension. */ 1099 if (m_formats.size() > 3) 1100 setFormatsWindowProperty(m_wndProxy, xAtom(XA_XdndTypeList)); 1101 1102 /* Announce the possible actions */ 1103 setActionsWindowProperty(m_wndProxy, toX11Actions(uActions)); 1104 1105 /* Set the DnD selection owner to our window. */ 1106 XSetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection), m_wndProxy, CurrentTime); 1107 1108 m_mode = HG; 1109 m_state = Dragging; 1110 1111 return VINF_SUCCESS; 1100 int rc; 1101 1102 do 1103 { 1104 rc = toAtomList(formats, m_lstFormats); 1105 if (RT_FAILURE(rc)) 1106 break; 1107 1108 /* If we have more than 3 formats we have to use the type list extension. */ 1109 if (m_lstFormats.size() > 3) 1110 { 1111 rc = wndXDnDSetFormatList(m_wndProxy, xAtom(XA_XdndTypeList), m_lstFormats); 1112 if (RT_FAILURE(rc)) 1113 break; 1114 } 1115 1116 /* Announce the possible actions. */ 1117 VBoxDnDAtomList lstActions; 1118 rc = toAtomActions(uActions, lstActions); 1119 if (RT_FAILURE(rc)) 1120 break; 1121 rc = wndXDnDSetActionList(m_wndProxy, lstActions); 1122 1123 /* Set the DnD selection owner to our window. */ 1124 XSetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection), m_wndProxy, CurrentTime); 1125 1126 m_enmMode = HG; 1127 m_enmState = Dragging; 1128 1129 } while (0); 1130 1131 LogFlowFuncLeaveRC(rc); 1132 return rc; 1112 1133 } 1113 1134 1114 1135 int DragInstance::hgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t uAction) 1115 1136 { 1116 LogFlowThisFunc((" u32xPos=%RU32, u32yPos=%RU32, uAction=%RU32\n",1117 1118 1119 if ( m_ mode != HG1120 || m_ state != Dragging)1137 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState)); 1138 LogFlowThisFunc(("u32xPos=%RU32, u32yPos=%RU32, uAction=%RU32\n", u32xPos, u32yPos, uAction)); 1139 1140 if ( m_enmMode != HG 1141 || m_enmState != Dragging) 1121 1142 { 1122 1143 return VERR_INVALID_STATE; … … 1156 1177 { 1157 1178 newVer = reinterpret_cast<long*>(pcData)[0]; 1158 LogFlowThisFunc(("wndCursor=%#x, XdndAware=%ld\n", wndCursor, newVer)); 1179 1180 LogFlowThisFunc(("Current: wndCursor=%#x, XdndAware=%ld\n", wndCursor, newVer)); 1181 #ifdef DEBUG 1182 XTextProperty propName; 1183 if (XGetWMName(m_pDisplay, wndCursor, &propName)) 1184 { 1185 LogFlowThisFunc(("\tTitle: %s\n", propName.value)); 1186 XFree(propName.value); 1187 } 1188 #endif 1159 1189 } 1160 1190 … … 1164 1194 1165 1195 /* 1166 * Is the window under the cursor another one than our current one? 1196 * Is the window under the cursor another one than our current one? 1197 * Cancel the current drop. 1167 1198 */ 1168 1199 if ( wndCursor != m_wndCur 1169 1200 && m_curVer != -1) 1170 1201 { 1171 LogFlowThisFunc((" Leavingwindow=%#x\n", m_wndCur));1172 1173 /* We left the current XdndAware window. Announce this to the window. */1202 LogFlowThisFunc(("XA_XdndLeave: window=%#x\n", m_wndCur)); 1203 1204 /* We left the current XdndAware window. Announce this to the current indow. */ 1174 1205 XClientMessageEvent m; 1175 1206 RT_ZERO(m); … … 1179 1210 m.message_type = xAtom(XA_XdndLeave); 1180 1211 m.format = 32; 1181 m.data.l[0] = m_wndProxy; 1212 m.data.l[0] = m_wndProxy; /* Source window. */ 1182 1213 1183 1214 xRc = XSendEvent(m_pDisplay, m_wndCur, False, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1184 1215 if (RT_UNLIKELY(xRc == 0)) 1185 logError(" DnD:Error sending XA_XdndLeave event to old window=%#x: %s\n", m_wndCur, gX11->xErrorToString(xRc).c_str());1216 logError("Error sending XA_XdndLeave event to old window=%#x: %s\n", m_wndCur, gX11->xErrorToString(xRc).c_str()); 1186 1217 } 1187 1218 … … 1192 1223 && newVer != -1) 1193 1224 { 1194 LogFlowThisFunc((" Enteringwindow=%#x\n", wndCursor));1225 LogFlowThisFunc(("XA_XdndEnter: window=%#x\n", wndCursor)); 1195 1226 1196 1227 /* … … 1207 1238 m.message_type = xAtom(XA_XdndEnter); 1208 1239 m.format = 32; 1209 m.data.l[0] = m_wndProxy; 1210 m.data.l[1] = RT_MAKE_U32_FROM_U8(m_formats.size() > 3 ? 1 : 0, 0, 0, RT_MIN(VBOX_XDND_VERSION, newVer)); 1211 m.data.l[2] = m_formats.value(0, None); 1212 m.data.l[3] = m_formats.value(1, None); 1213 m.data.l[4] = m_formats.value(2, None); 1240 m.data.l[0] = m_wndProxy; /* Source window. */ 1241 m.data.l[1] = RT_MAKE_U32_FROM_U8( 1242 /* Bit 0 is set if the source supports more than three data types. */ 1243 m_lstFormats.size() > 3 ? 1 : 0, 1244 /* Reserved for future use. */ 1245 0, 0, 1246 /* Protocol version to use. */ 1247 RT_MIN(VBOX_XDND_VERSION, newVer)); 1248 m.data.l[2] = m_lstFormats.value(0, None); /* First data type to use. */ 1249 m.data.l[3] = m_lstFormats.value(1, None); /* Second data type to use. */ 1250 m.data.l[4] = m_lstFormats.value(2, None); /* Third data type to use. */ 1214 1251 1215 1252 xRc = XSendEvent(m_pDisplay, wndCursor, False, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1216 1253 if (RT_UNLIKELY(xRc == 0)) 1217 logError("Error sending XA_XdndEnter event to newwindow=%#x: %s\n", wndCursor, gX11->xErrorToString(xRc).c_str());1254 logError("Error sending XA_XdndEnter event to window=%#x: %s\n", wndCursor, gX11->xErrorToString(xRc).c_str()); 1218 1255 } 1219 1256 1220 1257 if (newVer != -1) 1221 1258 { 1222 LogFlowThisFunc((" Moving window=%#x, xPos=%RU32, yPos=%RU32\n", wndCursor, u32xPos, u32yPos));1259 LogFlowThisFunc(("XA_XdndPosition: xPos=%RU32, yPos=%RU32 to window=%#x\n", u32xPos, u32yPos, wndCursor)); 1223 1260 1224 1261 /* 1225 1262 * Send a XdndPosition event with the proposed action to the guest. 1226 1263 */ 1227 Atom pa = to X11Action(uAction);1264 Atom pa = toAtomAction(uAction); 1228 1265 LogFlowThisFunc(("strAction=%s\n", xAtomToString(pa).c_str())); 1229 1266 … … 1235 1272 m.message_type = xAtom(XA_XdndPosition); 1236 1273 m.format = 32; 1237 m.data.l[0] = m_wndProxy; 1238 m.data.l[2] = RT_MAKE_U32(u32yPos, u32xPos); 1239 m.data.l[3] = CurrentTime; 1240 m.data.l[4] = pa; 1274 m.data.l[0] = m_wndProxy; /* X window ID of source window. */ 1275 m.data.l[2] = RT_MAKE_U32(u32yPos, u32xPos); /* Cursor coordinates relative to the root window. */ 1276 m.data.l[3] = CurrentTime; /* Timestamp for retrieving data. */ 1277 m.data.l[4] = pa; /* Actions requested by the user. */ 1241 1278 1242 1279 xRc = XSendEvent(m_pDisplay, wndCursor, False, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1243 1280 if (RT_UNLIKELY(xRc == 0)) 1244 logError( ("Error sending XA_XdndPosition event to current window=%#x: %s\n", wndCursor, gX11->xErrorToString(xRc).c_str()));1281 logError("Error sending XA_XdndPosition event to current window=%#x: %s\n", wndCursor, gX11->xErrorToString(xRc).c_str()); 1245 1282 } 1246 1283 … … 1251 1288 rc = VbglR3DnDHGAcknowledgeOperation(&m_dndCtx, DND_IGNORE_ACTION); 1252 1289 } 1253 1254 m_wndCur = wndCursor; 1255 m_curVer = RT_MIN(VBOX_XDND_VERSION, newVer); 1290 else 1291 { 1292 m_wndCur = wndCursor; 1293 m_curVer = RT_MIN(VBOX_XDND_VERSION, newVer); 1294 } 1256 1295 1257 1296 LogFlowFuncLeaveRC(rc); … … 1261 1300 int DragInstance::hgDrop(void) 1262 1301 { 1263 LogFlowThisFunc(("wndCur=%#x, mMode=%RU32, mState=%RU32\n", 1264 m_wndCur, m_mode, m_state)); 1265 1266 if ( m_mode != HG 1267 || m_state != Dragging) 1302 LogFlowThisFunc(("wndCur=%#x, wndProxy=%#x, mode=%RU32, state=%RU32\n", m_wndProxy, m_wndCur, m_enmMode, m_enmState)); 1303 1304 if ( m_enmMode != HG 1305 || m_enmState != Dragging) 1268 1306 { 1269 1307 return VERR_INVALID_STATE; … … 1272 1310 int rc = VINF_SUCCESS; 1273 1311 1274 /* Send a drop event to the current window and reset our DnD status. */ 1312 /* 1313 * Send a drop event to the current window and reset our DnD status. 1314 */ 1275 1315 XClientMessageEvent m; 1276 1316 RT_ZERO(m); … … 1280 1320 m.message_type = xAtom(XA_XdndDrop); 1281 1321 m.format = 32; 1282 m.data.l[0] = m_wndProxy; 1283 m.data.l[2] = CurrentTime; 1322 m.data.l[0] = m_wndProxy; /* Source window. */ 1323 m.data.l[2] = CurrentTime; /* Timestamp. */ 1284 1324 1285 1325 int xRc = XSendEvent(m_pDisplay, m_wndCur, False, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1286 1326 if (RT_UNLIKELY(xRc == 0)) 1287 logError( ("Error sending XA_XdndDrop event to current window=%#x: %s\n", m_wndCur, gX11->xErrorToString(xRc).c_str()));1327 logError("Error sending XA_XdndDrop event to current window=%#x: %s\n", m_wndCur, gX11->xErrorToString(xRc).c_str()); 1288 1328 1289 1329 m_wndCur = None; 1290 1330 m_curVer = -1; 1291 1331 1292 m_ state = Dropped;1332 m_enmState = Dropped; 1293 1333 1294 1334 LogFlowFuncLeaveRC(rc); … … 1298 1338 int DragInstance::hgDataReceived(void *pvData, uint32_t cbData) 1299 1339 { 1300 if ( m_mode != HG 1301 || m_state != Dropped) 1340 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState)); 1341 1342 if ( m_enmMode != HG 1343 || m_enmState != Dropped) 1302 1344 { 1303 1345 return VERR_INVALID_STATE; … … 1310 1352 } 1311 1353 1312 if (RT_UNLIKELY(m_state != Dropped)) 1313 return VERR_INVALID_STATE; 1314 1315 /* Make a copy of the data. The xserver will become the new owner. */ 1354 /* Make a copy of the data. The X server will become the new owner. */ 1316 1355 void *pvNewData = RTMemAlloc(cbData); 1317 1356 if (RT_UNLIKELY(!pvNewData)) … … 1321 1360 1322 1361 /* 1323 * The host send us the DnD data in the requested mimetype. This allows us1362 * The host has sent us the DnD data in the requested MIME type. This allows us 1324 1363 * to fill the XdndSelection property of the requestor window with the data 1325 1364 * and afterwards inform the host about the new status. … … 1349 1388 int xRc = XSendEvent(s.xselection.display, s.xselection.requestor, True, 0, &s); 1350 1389 if (RT_UNLIKELY(xRc == 0)) 1351 { 1352 logError(("Error sending SelectionNotify event to window=%#x: %s\n", 1353 s.xselection.requestor, gX11->xErrorToString(xRc).c_str())); 1354 } 1390 logError("Error sending SelectionNotify(2) event to window=%#x: %s\n", 1391 s.xselection.requestor, gX11->xErrorToString(xRc).c_str()); 1392 1393 /* We're finally done, reset. */ 1394 reset(); 1355 1395 1356 1396 return VINF_SUCCESS; … … 1360 1400 int DragInstance::ghIsDnDPending(void) 1361 1401 { 1362 LogFlow FuncEnter();1363 1364 if (m_ mode == HG)1402 LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState)); 1403 1404 if (m_enmMode == HG) 1365 1405 return VERR_INVALID_STATE; 1366 1406 … … 1373 1413 && wndSelection != m_wndProxy) 1374 1414 { 1375 m_mode = GH;1376 1377 1415 /* Map the window on the current cursor position, which should provoke 1378 1416 * an XdndEnter event. */ 1379 proxyWinShow( );1417 proxyWinShow(NULL, NULL, true); 1380 1418 1381 1419 XEvent e; 1382 1420 if (waitForX11Msg(e, ClientMessage)) 1383 1421 { 1422 bool fAcceptDrop = false; 1423 1384 1424 int xRc; 1385 1425 XClientMessageEvent *pEventClient = reinterpret_cast<XClientMessageEvent*>(&e); … … 1391 1431 if (pEventClient->message_type == xAtom(XA_XdndEnter)) 1392 1432 { 1393 Atom type = None;1394 int f; 1395 unsigned long n, a;1396 unsigned char *ret = 0;1397 1433 LogFlowThisFunc(("XA_XdndEnter\n")); 1434 1435 /* 1436 * Prepare everything for our new window. 1437 */ 1398 1438 reset(); 1399 1439 1400 m_state = Dragging; 1401 m_wndCur = wndSelection; 1440 /* 1441 * Update our state and the window handle to process. 1442 */ 1443 m_enmMode = GH; 1444 m_enmState = Dragging; 1445 m_wndCur = wndSelection; 1402 1446 Assert(m_wndCur == (Window)pEventClient->data.l[0]); 1403 1404 LogFlowThisFunc(("XA_XdndEnter\n"));1405 1447 #ifdef DEBUG 1406 1448 XWindowAttributes xwa; … … 1418 1460 gX11->xAtomToString(pEventClient->data.l[i]).c_str())); 1419 1461 1420 m_ formats.append(pEventClient->data.l[i]);1462 m_lstFormats.append(pEventClient->data.l[i]); 1421 1463 } 1422 1464 } 1423 1465 else 1424 1466 { 1425 xRc = XGetWindowProperty(m_pDisplay, wndSelection, 1426 xAtom(XA_XdndTypeList), 1427 0, VBOX_MAX_XPROPERTIES, 1428 False, XA_ATOM, &type, &f, &n, &a, &ret); 1429 if ( xRc == Success 1430 && n > 0 1431 && ret) 1432 { 1433 Atom *data = reinterpret_cast<Atom*>(ret); 1434 for (unsigned i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, n); ++i) 1435 { 1436 LogFlowThisFunc(("Received format via XdndTypeList: %s\n", 1437 gX11->xAtomToString(data[i]).c_str())); 1438 1439 m_formats.append(data[i]); 1440 } 1441 1442 XFree(ret); 1443 } 1467 rc = wndXDnDGetTypeList(wndSelection, m_lstFormats); 1444 1468 } 1445 1469 1446 /* Fetch the possible list of actions, if this property is set. */1447 xRc = XGetWindowProperty(m_pDisplay, wndSelection,1448 xAtom(XA_XdndActionList),1449 0, VBOX_MAX_XPROPERTIES,1450 False, XA_ATOM, &type, &f, &n, &a, &ret);1451 if ( xRc == Success1452 && n > 01453 && ret)1454 {1455 Atom *data = reinterpret_cast<Atom*>(ret);1456 for (unsigned i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, n); ++i)1457 {1458 LogFlowThisFunc(("Received action: %s\n",1459 gX11->xAtomToString(data[i]).c_str()));1460 1461 m_actions.append(data[i]);1462 }1463 1464 XFree(ret);1465 }1466 1467 1470 /* 1468 * Acknowledge the event by sending a status message back to the window.1471 * Fetch the actions. 1469 1472 */ 1470 XClientMessageEvent m; 1471 RT_ZERO(m); 1472 m.type = ClientMessage; 1473 m.display = m_pDisplay; 1474 m.window = m_wndCur; 1475 m.message_type = xAtom(XA_XdndStatus); 1476 m.format = 32; 1477 m.data.l[0] = m_wndProxy; 1478 m.data.l[1] = RT_BIT(0); /* Accept the drop. */ 1479 m.data.l[4] = xAtom(XA_XdndActionCopy); /** @todo Make the accepted action configurable. */ 1480 1481 xRc = XSendEvent(m_pDisplay, m_wndCur, 1482 False, 0, reinterpret_cast<XEvent*>(&m)); 1483 if (RT_UNLIKELY(xRc == 0)) 1484 { 1485 logError(("Error sending enter XA_XdndStatus event to current window=%#x: %s\n", 1486 m_wndCur, gX11->xErrorToString(xRc).c_str())); 1487 } 1473 rc = wndXDnDGetActionList(wndSelection, m_lstActions); 1474 1475 fAcceptDrop = true; 1488 1476 } 1489 1477 /* Did the source tell us where the cursor currently is? */ … … 1491 1479 { 1492 1480 LogFlowThisFunc(("XA_XdndPosition\n")); 1493 1481 fAcceptDrop = true; 1482 } 1483 else if (pEventClient->message_type == xAtom(XA_XdndLeave)) 1484 { 1485 LogFlowThisFunc(("XA_XdndLeave\n")); 1486 } 1487 1488 if (fAcceptDrop) 1489 { 1494 1490 /* Reply with a XdndStatus message to tell the source whether 1495 1491 * the data can be dropped or not. */ … … 1509 1505 if (RT_UNLIKELY(xRc == 0)) 1510 1506 { 1511 logError( ("Error sending position XA_XdndStatus event to current window=%#x: %s\n",1512 m_wndCur, gX11->xErrorToString(xRc).c_str()) );1507 logError("Error sending position XA_XdndStatus event to current window=%#x: %s\n", 1508 m_wndCur, gX11->xErrorToString(xRc).c_str()); 1513 1509 } 1514 1510 } 1515 else if (pEventClient->message_type == xAtom(XA_XdndLeave))1516 {1517 LogFlowThisFunc(("XA_XdndLeave\n"));1518 }1519 1511 } 1520 1512 1521 1513 /* Do we need to acknowledge at least one format to the host? */ 1522 if (!m_ formats.isEmpty())1523 { 1524 RTCString strFormats = gX11->xAtomListToString(m_ formats);1514 if (!m_lstFormats.isEmpty()) 1515 { 1516 RTCString strFormats = gX11->xAtomListToString(m_lstFormats); 1525 1517 uint32_t uDefAction = DND_COPY_ACTION; /** @todo Handle default action! */ 1526 uint32_t uAllActions = toHGCMActions(m_ actions);1518 uint32_t uAllActions = toHGCMActions(m_lstActions); 1527 1519 1528 1520 rc = VbglR3DnDGHAcknowledgePending(&m_dndCtx, uDefAction, uAllActions, strFormats.c_str()); … … 1538 1530 int DragInstance::ghDropped(const RTCString &strFormat, uint32_t uAction) 1539 1531 { 1540 LogFlowThisFunc(("strFormat=%s, uAction=%RU32\n", strFormat.c_str(), uAction)); 1541 1542 if ( m_mode != GH 1543 || m_state != Dragging) 1532 LogFlowThisFunc(("mode=%RU32, state=%RU32, strFormat=%s, uAction=%RU32\n", 1533 m_enmMode, m_enmState, strFormat.c_str(), uAction)); 1534 1535 if ( m_enmMode != GH 1536 || m_enmState != Dragging) 1544 1537 { 1545 1538 return VERR_INVALID_STATE; … … 1548 1541 int rc = VINF_SUCCESS; 1549 1542 1550 m_ state = Dropped;1543 m_enmState = Dropped; 1551 1544 1552 1545 /* Show the proxy window, so that the source will find it. */ … … 1581 1574 if (fDrop) 1582 1575 { 1576 LogFlowThisFunc(("XA_XdndDrop\n")); 1577 1583 1578 /* Request to convert the selection in the specific format and 1584 1579 * place it to our proxy window as property. */ … … 1617 1612 AnyPropertyType, /* Property type */ 1618 1613 &aPropType, &iPropFormat, &cItems, &cbRemaining, &pcData); 1619 if (RT_UNLIKELY(xRc == 0))1614 if (RT_UNLIKELY(xRc != Success)) 1620 1615 LogFlowThisFunc(("Error getting XA_XdndSelection property of proxy window=%#x: %s\n", 1621 1616 m_wndProxy, gX11->xErrorToString(xRc).c_str())); … … 1671 1666 m.data.l[0] = m_wndProxy; /* Target window. */ 1672 1667 m.data.l[1] = 0; /* Don't accept the drop to not make the guest stuck. */ 1673 m.data.l[2] = RT_SUCCESS(rc) ? to X11Action(uAction) : None; /* Action used on success */1668 m.data.l[2] = RT_SUCCESS(rc) ? toAtomAction(uAction) : None; /* Action used on success */ 1674 1669 1675 1670 xRc = XSendEvent(m_pDisplay, wndSource, True, NoEventMask, reinterpret_cast<XEvent*>(&m)); … … 1716 1711 if (RT_UNLIKELY(xRc == 0)) 1717 1712 { 1718 logError( ("Error sending XA_XdndFinished event to proxy window=%#x: %s\n",1719 m_wndProxy, gX11->xErrorToString(xRc).c_str()) );1713 logError("Error sending XA_XdndFinished event to proxy window=%#x: %s\n", 1714 m_wndProxy, gX11->xErrorToString(xRc).c_str()); 1720 1715 } 1721 1716 } … … 1870 1865 LogFlowThisFuncEnter(); 1871 1866 1867 #if 0 1868 XTestGrabControl(m_pDisplay, False); 1869 #endif 1870 1871 /* Get the mouse pointer position and determine if we're on the same screen as the root window 1872 * and returns the current child window beneath our mouse pointer, if any. */ 1872 1873 int iRootX, iRootY; 1873 1874 int iChildX, iChildY; 1874 1875 unsigned int iMask; 1875 1876 Window wndRoot, wndChild; 1876 1877 // XTestGrabControl(m_pDisplay, False);1878 1879 /* Get the mouse pointer position and determine if we're on the same screen as the root window1880 * and returns the current child window beneath our mouse pointer, if any. */1881 1877 Bool fInRootWnd = XQueryPointer(m_pDisplay, m_wndRoot, &wndRoot, &wndChild, 1882 1878 &iRootX, &iRootY, … … 1897 1893 XRaiseWindow(m_pDisplay, m_wndProxy); 1898 1894 1899 /* Resize our proxy window so that it gets displayed right in center of our mouse cursor. */ 1900 const int iProxyX = RT_MAX(0, iRootX - 50); 1901 const int iProxyY = RT_MAX(0, iRootY - 50); 1902 LogFlowThisFunc(("iProxyX=%d, iProxyY=%d\n", iProxyX, iProxyY)); 1903 XMoveResizeWindow(m_pDisplay, m_wndProxy, iProxyX, iProxyY, 100, 100); 1895 /* Spawn our proxy window over the entire screen, making it an easy drop target for the host's cursor. */ 1896 int iScreenID = XDefaultScreen(m_pDisplay); 1897 XMoveResizeWindow(m_pDisplay, m_wndProxy, 0, 0, XDisplayWidth(m_pDisplay, iScreenID), XDisplayHeight(m_pDisplay, iScreenID)); 1898 /** @todo What about multiple screens? Test this! */ 1904 1899 1905 1900 if (fMouseMove) … … 1907 1902 1908 1903 XSynchronize(m_pDisplay, False /* Disable sync */); 1909 // XTestGrabControl(m_pDisplay, True); 1904 1905 #if 0 1906 XTestGrabControl(m_pDisplay, True); 1907 #endif 1910 1908 1911 1909 return VINF_SUCCESS; /** @todo Add error checking. */ … … 1916 1914 LogFlowFuncEnter(); 1917 1915 1916 #ifndef VBOX_DND_DEBUG_WND 1918 1917 XUnmapWindow(m_pDisplay, m_wndProxy); 1918 #endif 1919 1919 m_eventQueue.clear(); 1920 1920 … … 1922 1922 } 1923 1923 1924 /* Currently not used. */ 1925 /** @todo Is this function still needed? */ 1926 void DragInstance::registerForEvents(Window wndThis) const 1927 { 1928 if (wndThis == m_wndProxy) 1929 return; 1930 1931 LogFlowThisFunc(("%x\n", wndThis)); 1932 // XSelectInput(m_pDisplay, w, Button1MotionMask | Button2MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask);//| SubstructureNotifyMask); 1933 // XSelectInput(m_pDisplay, w, ButtonMotionMask); //PointerMotionMask); 1934 XSelectInput(m_pDisplay, wndThis, PointerMotionMask); //PointerMotionMask); 1935 Window hRealRoot, hParent; 1936 Window *phChildrenRaw = NULL; 1937 unsigned cChildren; 1938 if (XQueryTree(m_pDisplay, wndThis, &hRealRoot, &hParent, &phChildrenRaw, &cChildren)) 1939 { 1940 for (unsigned i = 0; i < cChildren; ++i) 1941 registerForEvents(phChildrenRaw[i]); 1942 XFree(phChildrenRaw); 1943 } 1944 } 1945 1946 void DragInstance::setActionsWindowProperty(Window wndThis, const RTCList<Atom> &lstActions) const 1924 void DragInstance::wndXDnDClearActionList(Window wndThis) const 1925 { 1926 XDeleteProperty(m_pDisplay, wndThis, xAtom(XA_XdndActionList)); 1927 } 1928 1929 void DragInstance::wndXDnDClearTypeList(Window wndThis) const 1930 { 1931 XDeleteProperty(m_pDisplay, wndThis, xAtom(XA_XdndTypeList)); 1932 } 1933 1934 int DragInstance::wndXDnDGetActionList(Window wndThis, VBoxDnDAtomList &lstActions) const 1935 { 1936 Atom iActType = None; 1937 int iActFmt; 1938 unsigned long cItems, cbData; 1939 unsigned char *pcbData = NULL; 1940 1941 /* Fetch the possible list of actions, if this property is set. */ 1942 int xRc = XGetWindowProperty(m_pDisplay, wndThis, 1943 xAtom(XA_XdndActionList), 1944 0, VBOX_MAX_XPROPERTIES, 1945 False, XA_ATOM, &iActType, &iActFmt, &cItems, &cbData, &pcbData); 1946 if (xRc != Success) 1947 { 1948 LogFlowThisFunc(("Error getting XA_XdndActionList atoms from window=%#x: %s\n", 1949 wndThis, gX11->xErrorToString(xRc).c_str())); 1950 return VERR_NOT_FOUND; 1951 } 1952 1953 if ( cItems > 0 1954 && pcbData) 1955 { 1956 Atom *paData = reinterpret_cast<Atom *>(pcbData); 1957 1958 for (unsigned i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, cItems); i++) 1959 { 1960 LogFlowThisFunc(("Received action: %s\n", 1961 gX11->xAtomToString(paData[i]).c_str())); 1962 1963 lstActions.append(paData[i]); 1964 } 1965 1966 XFree(pcbData); 1967 } 1968 1969 return VINF_SUCCESS; 1970 } 1971 1972 int DragInstance::wndXDnDGetTypeList(Window wndThis, VBoxDnDAtomList &lstTypes) const 1973 { 1974 Atom iActType = None; 1975 int iActFmt; 1976 unsigned long cItems, cbData; 1977 unsigned char *pcbData = NULL; 1978 1979 int xRc = XGetWindowProperty(m_pDisplay, wndThis, 1980 xAtom(XA_XdndTypeList), 1981 0, VBOX_MAX_XPROPERTIES, 1982 False, XA_ATOM, &iActType, &iActFmt, &cItems, &cbData, &pcbData); 1983 if (xRc != Success) 1984 { 1985 LogFlowThisFunc(("Error getting XA_XdndTypeList atoms from window=%#x: %s\n", 1986 wndThis, gX11->xErrorToString(xRc).c_str())); 1987 return VERR_NOT_FOUND; 1988 } 1989 1990 if ( cItems > 0 1991 && pcbData) 1992 { 1993 Atom *paData = reinterpret_cast<Atom*>(pcbData); 1994 1995 for (unsigned i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, cItems); i++) 1996 { 1997 LogFlowThisFunc(("Received format via XdndTypeList: %s\n", 1998 gX11->xAtomToString(paData[i]).c_str())); 1999 2000 lstTypes.append(paData[i]); 2001 } 2002 2003 XFree(pcbData); 2004 } 2005 2006 return VINF_SUCCESS; 2007 } 2008 2009 int DragInstance::wndXDnDSetActionList(Window wndThis, const VBoxDnDAtomList &lstActions) const 1947 2010 { 1948 2011 if (lstActions.isEmpty()) 1949 return ;2012 return VINF_SUCCESS; 1950 2013 1951 2014 XChangeProperty(m_pDisplay, wndThis, … … 1954 2017 reinterpret_cast<const unsigned char*>(lstActions.raw()), 1955 2018 lstActions.size()); 1956 } 1957 1958 void DragInstance::clearActionsWindowProperty(Window wndThis) const 1959 { 1960 XDeleteProperty(m_pDisplay, wndThis, xAtom(XA_XdndActionList)); 1961 } 1962 1963 void DragInstance::setFormatsWindowProperty(Window wndThis, Atom property) const 1964 { 1965 if (m_formats.isEmpty()) 1966 return; 2019 2020 return VINF_SUCCESS; 2021 } 2022 2023 int DragInstance::wndXDnDSetFormatList(Window wndThis, Atom property, const VBoxDnDAtomList &lstFormats) const 2024 { 2025 if (lstFormats.isEmpty()) 2026 return VINF_SUCCESS; 1967 2027 1968 2028 /* We support TARGETS and the data types. */ 1969 RTCList<Atom> targets(m_formats.size() + 1);1970 targets.append(xAtom(XA_TARGETS));1971 targets.append(m_formats);2029 VBoxDnDAtomList lstFormatsExt(lstFormats.size() + 1); 2030 lstFormatsExt.append(xAtom(XA_TARGETS)); 2031 lstFormatsExt.append(lstFormats); 1972 2032 1973 2033 /* Add the property with the property data to the window. */ 1974 2034 XChangeProperty(m_pDisplay, wndThis, property, 1975 2035 XA_ATOM, 32, PropModeReplace, 1976 reinterpret_cast<const unsigned char*>(targets.raw()), 1977 targets.size()); 1978 } 1979 1980 void DragInstance::clearFormatsWindowProperty(Window wndThis) const 1981 { 1982 XDeleteProperty(m_pDisplay, wndThis, 1983 xAtom(XA_XdndTypeList)); 1984 } 1985 1986 RTCList<Atom> DragInstance::toAtomList(const RTCList<RTCString> &lstFormats) const 1987 { 1988 RTCList<Atom> atomList; 2036 reinterpret_cast<const unsigned char*>(lstFormatsExt.raw()), 2037 lstFormatsExt.size()); 2038 2039 return VINF_SUCCESS; 2040 } 2041 2042 int DragInstance::toAtomList(const RTCList<RTCString> &lstFormats, VBoxDnDAtomList &lstAtoms) const 2043 { 1989 2044 for (size_t i = 0; i < lstFormats.size(); ++i) 1990 atomList.append(XInternAtom(m_pDisplay, lstFormats.at(i).c_str(), False)); 1991 1992 return atomList; 1993 } 1994 1995 RTCList<Atom> DragInstance::toAtomList(void *pvData, uint32_t cbData) const 1996 { 1997 if ( !pvData 1998 || !cbData) 1999 return RTCList<Atom>(); 2000 2001 char *pszStr = (char*)pvData; 2045 lstAtoms.append(XInternAtom(m_pDisplay, lstFormats.at(i).c_str(), False)); 2046 2047 return VINF_SUCCESS; 2048 } 2049 2050 int DragInstance::toAtomList(const void *pvData, uint32_t cbData, VBoxDnDAtomList &lstAtoms) const 2051 { 2052 AssertPtrReturn(pvData, VERR_INVALID_POINTER); 2053 AssertReturn(cbData, VERR_INVALID_PARAMETER); 2054 2055 const char *pszStr = (char *)pvData; 2002 2056 uint32_t cbStr = cbData; 2057 2058 int rc = VINF_SUCCESS; 2003 2059 2004 2060 RTCList<Atom> lstAtom; … … 2010 2066 * even if the data isn't zero terminated. */ 2011 2067 char *pszTmp = RTStrDupN(pszStr, cbSize); 2012 LogFlowThisFunc(("f: %s\n", pszTmp)); 2068 if (!pszTmp) 2069 { 2070 rc = VERR_NO_MEMORY; 2071 break; 2072 } 2073 2013 2074 lstAtom.append(XInternAtom(m_pDisplay, pszTmp, False)); 2014 2075 RTStrFree(pszTmp); 2076 2015 2077 pszStr += cbSize + 1; 2016 2078 cbStr -= cbSize + 1; 2017 2079 } 2018 2080 2019 return lstAtom;2081 return rc; 2020 2082 } 2021 2083 2022 2084 /* static */ 2023 Atom DragInstance::to X11Action(uint32_t uAction)2085 Atom DragInstance::toAtomAction(uint32_t uAction) 2024 2086 { 2025 2087 /* Ignore is None. */ … … 2031 2093 2032 2094 /* static */ 2033 RTCList<Atom> DragInstance::toX11Actions(uint32_t uActions) 2034 { 2035 RTCList<Atom> actionList; 2095 int DragInstance::toAtomActions(uint32_t uActions, VBoxDnDAtomList &lstAtoms) 2096 { 2036 2097 if (hasDnDCopyAction(uActions)) 2037 actionList.append(xAtom(XA_XdndActionCopy));2098 lstAtoms.append(xAtom(XA_XdndActionCopy)); 2038 2099 if (hasDnDMoveAction(uActions)) 2039 actionList.append(xAtom(XA_XdndActionMove));2100 lstAtoms.append(xAtom(XA_XdndActionMove)); 2040 2101 if (hasDnDLinkAction(uActions)) 2041 actionList.append(xAtom(XA_XdndActionLink));2042 2043 return actionList;2102 lstAtoms.append(xAtom(XA_XdndActionLink)); 2103 2104 return VINF_SUCCESS; 2044 2105 } 2045 2106 … … 2162 2223 if (e.hgcm.cbFormats) 2163 2224 { 2164 RTCList<RTCString> lstFormats 2165 = RTCString(e.hgcm.pszFormats, e.hgcm.cbFormats - 1).split("\r\n"); 2166 m_pCurDnD->hgEnter(lstFormats, e.hgcm.u.a.uAllActions); 2167 2225 RTCList<RTCString> lstFormats = RTCString(e.hgcm.pszFormats, e.hgcm.cbFormats - 1).split("\r\n"); 2226 rc = m_pCurDnD->hgEnter(lstFormats, e.hgcm.u.a.uAllActions); 2168 2227 /* Enter is always followed by a move event. */ 2169 2228 } 2170 else /* Invalid parameter, skip. */ 2229 else 2230 { 2231 rc = VERR_INVALID_PARAMETER; 2171 2232 break; 2233 } 2172 2234 /* Not breaking unconditionally is intentional. See comment above. */ 2173 2235 } … … 2192 2254 break; 2193 2255 } 2256 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 2194 2257 case DragAndDropSvc::HOST_DND_GH_REQ_PENDING: 2195 2258 { 2196 #ifdef VBOX_WITH_DRAG_AND_DROP_GH2197 2259 rc = m_pCurDnD->ghIsDnDPending(); 2198 #endif2199 2260 break; 2200 2261 } 2201 2262 case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED: 2202 2263 { 2203 #ifdef VBOX_WITH_DRAG_AND_DROP_GH2204 2264 rc = m_pCurDnD->ghDropped(e.hgcm.pszFormats, e.hgcm.u.a.uDefAction); 2205 #endif2206 2265 break; 2207 2266 } 2208 2267 #endif 2209 2268 default: 2269 { 2210 2270 LogFlowThisFunc(("Unsupported message: %RU32\n", e.hgcm.uType)); 2211 2271 rc = VERR_NOT_SUPPORTED; 2212 2272 break; 2273 } 2213 2274 } 2214 2275 2215 LogFlowFunc(("Returning %Rrc\n", rc)); 2276 if (RT_FAILURE(rc)) 2277 { 2278 m_pCurDnD->logError("Error: Processing message %RU32 failed with %Rrc\n", e.hgcm.uType, rc); 2279 2280 /* If anything went wrong, do a reset and start over. */ 2281 m_pCurDnD->reset(); 2282 } 2216 2283 2217 2284 /* Some messages require cleanup. */ … … 2250 2317 AssertMsgFailed(("Unknown event queue type %d\n", e.type)); 2251 2318 2252 /* Make sure that any X11 requests have actually been sent to the 2319 /* 2320 * Make sure that any X11 requests have actually been sent to the 2253 2321 * server, since we are waiting for responses using poll() on 2254 * another thread which will not automatically trigger flushing. */ 2322 * another thread which will not automatically trigger flushing. 2323 */ 2255 2324 XFlush(m_pDisplay); 2256 2325 … … 2269 2338 if (RT_FAILURE(rc)) 2270 2339 VBClFatalError(("Failed to connect to the VirtualBox kernel service, rc=%Rrc\n", rc)); 2340 2271 2341 /* Connect to the x11 server. */ 2272 2342 m_pDisplay = XOpenDisplay(NULL); … … 2292 2362 rc = RTThreadCreate(&m_hHGCMThread, hgcmEventThread, this, 2293 2363 0, RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE, 2294 " HGCM-NOTIFY");2364 "dndHGCM"); 2295 2365 if (RT_FAILURE(rc)) 2296 2366 break; … … 2299 2369 rc = RTThreadCreate(&m_hX11Thread, x11EventThread, this, 2300 2370 0, RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE, 2301 " X11-NOTIFY");2371 "dndX11"); 2302 2372 } while (0); 2303 2373 … … 2342 2412 { 2343 2413 cMsgSkippedInvalid = 0; /* Reset skipped messages count. */ 2344 2345 LogFlowFunc(("Adding new HGCM event ...\n"));2346 2414 pThis->m_eventQueue.append(e); 2347 2415 … … 2434 2502 } 2435 2503 #endif 2436 LogFlowFunc(("Adding new X11 event ...\n"));2437 2438 2504 /* At the moment we only have one drag instance. */ 2439 2505 DragInstance *pInstance = pThis->m_pCurDnD; 2440 2441 2506 AssertPtr(pInstance); 2507 2442 2508 pInstance->onX11Event(e.x11); 2443 2509 } … … 2463 2529 struct VBCLSERVICE *pInterface; 2464 2530 /** Magic number for sanity checks. */ 2465 uint32_t magic;2531 uint32_t uMagic; 2466 2532 /** Service object. */ 2467 2533 DragAndDropService mDragAndDrop; … … 2477 2543 struct DRAGANDDROPSERVICE *pSelf = (struct DRAGANDDROPSERVICE *)ppInterface; 2478 2544 2479 if (pSelf-> magic != DRAGANDDROPSERVICE_MAGIC)2545 if (pSelf->uMagic != DRAGANDDROPSERVICE_MAGIC) 2480 2546 VBClFatalError(("Bad display service object!\n")); 2481 2547 return pSelf->mDragAndDrop.run(fDaemonised); … … 2498 2564 }; 2499 2565 2500 /* Static factory */2566 /* Static factory. */ 2501 2567 struct VBCLSERVICE **VBClGetDragAndDropService(void) 2502 2568 { … … 2507 2573 VBClFatalError(("Out of memory\n")); 2508 2574 pService->pInterface = &vbclDragAndDropInterface; 2509 pService-> magic = DRAGANDDROPSERVICE_MAGIC;2575 pService->uMagic = DRAGANDDROPSERVICE_MAGIC; 2510 2576 new(&pService->mDragAndDrop) DragAndDropService(); 2511 2577 return &pService->pInterface;
Note:
See TracChangeset
for help on using the changeset viewer.