Changeset 50724 in vbox for trunk/src/VBox/Additions/x11
- Timestamp:
- Mar 7, 2014 10:54:59 AM (11 years ago)
- Location:
- trunk/src/VBox/Additions/x11/VBoxClient
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/x11/VBoxClient/Makefile.kmk
r50570 r50724 48 48 Xrandr \ 49 49 Xt 50 # Xtst 50 51 ifdef VBOX_WITH_DRAG_AND_DROP 52 ifdef VBOX_DND_WITH_XTEST 53 VBoxClient_DEFS += VBOX_DND_WITH_XTEST 54 VBoxClient_LIBS += \ 55 Xtst 56 endif 57 endif 58 51 59 # These are static replacements for gcc-specific parts of libstdc++ 52 60 VBoxClient_LIBS += \ -
trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp
r50643 r50724 4 4 5 5 /* 6 * Copyright (C) 2011-201 3Oracle Corporation6 * Copyright (C) 2011-2014 Oracle Corporation 7 7 * 8 8 * This file is part of VirtualBox Open Source Edition (OSE), as … … 15 15 */ 16 16 17 #include <errno.h>18 #include <poll.h>19 20 17 #include <X11/Xlib.h> 21 18 #include <X11/Xatom.h> 22 //#include <X11/extensions/XTest.h> 23 19 #ifdef VBOX_DND_WITH_XTEST 20 # include <X11/extensions/XTest.h> 21 #endif 22 23 #include <iprt/asm.h> 24 #include <iprt/critsect.h> 24 25 #include <iprt/thread.h> 25 #include <iprt/asm.h>26 26 #include <iprt/time.h> 27 27 … … 31 31 #include <limits.h> 32 32 33 # ifdef LOG_GROUP 34 # undef LOG_GROUP 35 # endif 36 #define LOG_GROUP LOG_GROUP_GUEST_DND 33 37 #include <VBox/log.h> 34 38 #include <VBox/VBoxGuestLib.h> … … 37 41 38 42 #include "VBoxClient.h" 43 44 /* Enable this define to see the proxy window(s) when debugging 45 * their behavior. Don't have this enabled in release builds! */ 46 #ifdef DEBUG 47 # define VBOX_DND_DEBUG_WND 48 #endif 39 49 40 50 /* For X11 guest xDnD is used. See http://www.acc.umu.se/~vatten/XDND.html for … … 62 72 * and some mouse event is triggered. This should be followed by an XdndEnter 63 73 * event send to the proxy window. From this event we can fetch the necessary 64 * info of the mime-types and allowed actions and send this back to the host.74 * info of the MIME types and allowed actions and send this back to the host. 65 75 * On a drop request from the host, we query for the selection and should get 66 76 * the data in the specified mime-type. This data is send back to the host. … … 308 318 int tmp; 309 319 unsigned int utmp; 320 310 321 /* Query the next child window of the parent window at the current 311 322 * mouse position. */ 312 323 XQueryPointer(m_pDisplay, wndParent, &wndTemp, &wndChild, &tmp, &tmp, &tmp, &tmp, &utmp); 324 313 325 /* Recursive call our self to dive into the child tree. */ 314 326 wndApp = applicationWindowBelowCursor(wndChild); … … 330 342 { 331 343 public: 344 332 345 enum State 333 346 { 334 Uninitialized ,347 Uninitialized = 0, 335 348 Initialized, 336 349 Dragging, … … 340 353 enum Mode 341 354 { 342 Unknown ,355 Unknown = 0, 343 356 HG, 344 357 GH … … 346 359 347 360 DragInstance(Display *pDisplay, DragAndDropService *pParent); 361 362 public: 363 348 364 int init(uint32_t u32ScreenId); 349 void uninit(); 350 void reset(); 365 void uninit(void); 366 void reset(void); 367 368 /* X11 message processing. */ 369 int onX11ClientMessage(const XEvent &e); 370 int onX11SelectionNotify(const XEvent &e); 371 int onX11SelectionRequest(const XEvent &e); 372 int onX11Event(const XEvent &e); 373 bool waitForX11Msg(XEvent &evX, int iType, RTMSINTERVAL uTimeoutMS = 100); 374 bool waitForX11ClientMsg(XClientMessageEvent &evMsg, Atom aType, RTMSINTERVAL uTimeoutMS = 100); 351 375 352 376 /* H->G */ 353 377 int hgEnter(const RTCList<RTCString> &formats, uint32_t actions); 354 378 int hgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t action); 355 int hgX11ClientMessage(const XEvent& e);356 379 int hgDrop(); 357 int hgX11SelectionRequest(const XEvent& e);358 380 int hgDataReceived(void *pvData, uint32_t cData); 359 381 … … 364 386 #endif 365 387 366 /* X11 helpers */367 int mo veCursor(uint32_t u32xPos, uint32_t u32yPos);368 void sendButtonEvent(Window w, int rx, int ry, int button, bool fPress) const;369 void showProxyWin(int &rx, int &ry) const;370 void hideProxyWin() const;388 /* X11 helpers. */ 389 int mouseCursorMove(int iPosX, int iPosY) const; 390 void mouseButtonSet(Window wndDest, int rx, int ry, int iButton, bool fPress) const; 391 int proxyWinShow(int *piRootX = NULL, int *piRootY = NULL, bool fMouseMove = false) const; 392 int proxyWinHide(void) const; 371 393 void registerForEvents(Window w) const; 372 394 373 void setActionsWindowProperty(Window w in, const RTCList<Atom> &actionList) const;374 void clearActionsWindowProperty(Window w in) const;375 void setFormatsWindowProperty(Window w in, Atom property) const;376 void clearFormatsWindowProperty(Window w in) const;377 378 RTCList<Atom> toAtomList(const RTCList<RTCString> & formatList) const;379 RTCList<Atom> toAtomList(void *pvData, uint32_t c Data) const;395 void setActionsWindowProperty(Window wndThis, const RTCList<Atom> &lstActions) const; 396 void clearActionsWindowProperty(Window wndThis) const; 397 void setFormatsWindowProperty(Window wndThis, Atom property) const; 398 void clearFormatsWindowProperty(Window wndThis) const; 399 400 RTCList<Atom> toAtomList(const RTCList<RTCString> &lstFormats) const; 401 RTCList<Atom> toAtomList(void *pvData, uint32_t cbData) const; 380 402 static Atom toX11Action(uint32_t uAction); 381 403 static RTCList<Atom> toX11Actions(uint32_t uActions); … … 383 405 static uint32_t toHGCMActions(const RTCList<Atom> &actionsList); 384 406 385 /* Member vars */ 407 protected: 408 386 409 uint32_t m_uClientID; 387 410 DragAndDropService *m_pParent; … … 395 418 RTCList<Atom> m_formats; 396 419 RTCList<Atom> m_actions; 397 398 XEvent m_selEvent; 399 420 /** Deferred host to guest selection event for sending to the 421 * target window as soon as data from the host arrived. */ 422 XEvent m_eventHgSelection; 423 /** Current operation mode. */ 400 424 Mode m_mode; 425 /** Current state of operation mode. */ 401 426 State m_state; 427 /** The instance's own X event queue. */ 428 RTCMTList<XEvent> m_eventQueue; 429 /** Critical section for providing serialized access to list 430 * event queue's contents. */ 431 RTCRITSECT m_eventQueueCS; 432 /** Event for notifying this instance in case of a new 433 * event. */ 434 RTSEMEVENT m_hEventSem; 402 435 403 436 static const RTCList<RTCString> m_sstrStringMimeTypes; … … 419 452 , m_hEventSem(NIL_RTSEMEVENT) 420 453 , m_pCurDnD(0) 454 , m_fSrvStopping(false) 421 455 {} 422 456 423 457 virtual const char *getPidFilePath() { return ".vboxclient-draganddrop.pid"; } 424 458 425 /** @todo Move this part in VbglR3 and just provide a callback for the platform-specific426 notification stuff, since this is very similar to the VBoxTray code. */427 459 virtual int run(bool fDaemonised = false); 428 460 … … 438 470 static int x11EventThread(RTTHREAD hThread, void *pvUser); 439 471 440 bool waitForXMsg(XEvent &ecm, int type, uint32_t uiMaxMS = 100);441 472 void clearEventQueue(); 442 /* Usually XCheckMaskEvent could be used for queering selected x11 events. 473 474 /* Usually XCheckMaskEvent could be used for querying selected x11 events. 443 475 * Unfortunately this doesn't work exactly with the events we need. So we 444 476 * use this predicate method below and XCheckIfEvent. */ … … 462 494 Display *m_pDisplay; 463 495 464 RTCMTList<DnDEvent> m_eventQueue; 496 /** Our (thread-safe) event queue with 497 * mixed events (DnD HGCM / X11). */ 498 RTCMTList<DnDEvent> m_eventQueue; 499 /** Critical section for providing serialized access to list 500 * event queue's contents. */ 501 RTCRITSECT m_eventQueueCS; 465 502 RTTHREAD m_hHGCMThread; 466 503 RTTHREAD m_hX11Thread; 467 504 RTSEMEVENT m_hEventSem; 468 505 DragInstance *m_pCurDnD; 506 bool m_fSrvStopping; 469 507 470 508 friend class DragInstance; … … 514 552 { 515 553 /* Hide the proxy win. */ 516 hideProxyWin(); 554 proxyWinHide(); 555 517 556 /* If we are currently the Xdnd selection owner, clear that. */ 518 557 Window w = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection)); 519 558 if (w == m_wndProxy) 520 559 XSetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection), None, CurrentTime); 560 521 561 /* Clear any other DnD specific data on the proxy win. */ 522 562 clearFormatsWindowProperty(m_wndProxy); 523 563 clearActionsWindowProperty(m_wndProxy); 564 524 565 /* Reset the internal state. */ 566 m_actions.clear(); 525 567 m_formats.clear(); 526 568 m_wndCur = 0; … … 529 571 } 530 572 573 /** @todo Move this into VBox/GuestHost ? */ 531 574 const RTCList<RTCString> DragInstance::m_sstrStringMimeTypes = RTCList<RTCString>() 532 575 /* Uri's */ … … 552 595 553 596 rc = VbglR3DnDConnect(&m_uClientID); 597 if (RT_FAILURE(rc)) 598 break; 599 600 rc = RTSemEventCreate(&m_hEventSem); 601 if (RT_FAILURE(rc)) 602 break; 603 604 rc = RTCritSectInit(&m_eventQueueCS); 554 605 if (RT_FAILURE(rc)) 555 606 break; … … 586 637 XSetWindowAttributes attr; 587 638 RT_ZERO(attr); 588 attr.do_not_propagate_mask = 0; 639 attr.event_mask = EnterWindowMask | LeaveWindowMask 640 | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; 641 attr.do_not_propagate_mask = NoEventMask; 589 642 attr.override_redirect = True; 590 #if 0643 #ifdef VBOX_DND_DEBUG_WND 591 644 attr.background_pixel = WhitePixel(m_pDisplay, m_screenId); 592 645 #endif 593 m_wndProxy = XCreateWindow(m_pDisplay, m_wndRoot , 0, 0, 1, 1, 0,594 CopyFromParent, InputOnly, CopyFromParent,595 CWOverrideRedirect | CWDontPropagate,596 &attr);597 #ifdef DEBUG_andy 598 m_wndProxy = XCreateSimpleWindow(m_pDisplay, m_wndRoot, 0, 0, 50, 50, 0,599 WhitePixel(m_pDisplay, m_screenId),600 WhitePixel(m_pDisplay, m_screenId));601 #endif 646 m_wndProxy = XCreateWindow(m_pDisplay, m_wndRoot /* Parent */, 647 0, 0, /* Position */ 648 1, 1, /* Width + height */ 649 0, /* Border width */ 650 CopyFromParent, /* Depth */ 651 InputOnly, /* Class */ 652 CopyFromParent, /* Visual */ 653 CWOverrideRedirect | CWDontPropagate, /* Value mask */ 654 &attr /* Attributes for value mask */); 602 655 if (!m_wndProxy) 603 656 { … … 605 658 break; 606 659 } 660 661 LogFlowThisFunc(("Created proxy window 0x%x at m_wndRoot=0x%x ...\n", 662 m_wndProxy, m_wndRoot)); 663 664 /* Set the window's name for easier lookup. */ 665 XStoreName(m_pDisplay, m_wndProxy, "VBoxClientWndDnD"); 607 666 608 667 /* Make the new window Xdnd aware. */ … … 613 672 614 673 if (RT_SUCCESS(rc)) 674 { 615 675 m_state = Initialized; 676 } 677 else 678 LogRel(("DnD: Initializing drag instance for screen %RU32 failed with rc=%Rrc\n", 679 u32ScreenId, rc)); 616 680 617 681 LogFlowFuncLeaveRC(rc); 618 682 return rc; 619 683 } 684 685 int DragInstance::onX11ClientMessage(const XEvent &e) 686 { 687 AssertReturn(e.type == ClientMessage, VERR_INVALID_PARAMETER); 688 689 LogFlowThisFunc(("m_mode=%d, m_state=%d\n", m_mode, m_state)); 690 LogFlowThisFunc(("Event wnd=%#x, msg=%s\n", 691 e.xclient.window, 692 xAtomToString(e.xclient.message_type).c_str())); 693 int rc; 694 695 switch (m_mode) 696 { 697 case HG: 698 { 699 /* Client messages are used to inform us about the status of a XdndAware 700 * window, in response of some events we send to them. */ 701 if ( e.xclient.message_type == xAtom(XA_XdndStatus) 702 && m_wndCur == static_cast<Window>(e.xclient.data.l[0])) 703 { 704 /* The XdndStatus message tell us if the window will accept the DnD 705 * event and with which action. We immediately send this info down to 706 * the host as a response of a previous DnD message. */ 707 LogFlowThisFunc(("XA_XdndStatus wnd=%#x, accept=%RTbool, action=%s\n", 708 e.xclient.data.l[0], 709 ASMBitTest(&e.xclient.data.l[1], 0), 710 xAtomToString(e.xclient.data.l[4]).c_str())); 711 712 uint32_t uAction = DND_IGNORE_ACTION; 713 /** @todo Compare this with the allowed actions. */ 714 if (ASMBitTest(&e.xclient.data.l[1], 0)) 715 uAction = toHGCMAction(static_cast<Atom>(e.xclient.data.l[4])); 716 717 rc = VbglR3DnDHGAcknowledgeOperation(m_uClientID, uAction); 718 } 719 else if (e.xclient.message_type == xAtom(XA_XdndFinished)) 720 { 721 rc = VINF_SUCCESS; 722 723 /* This message is send on a un/successful DnD drop request. */ 724 LogFlowThisFunc(("XA_XdndFinished: wnd=%#x, success=%RTbool, action=%s\n", 725 e.xclient.data.l[0], 726 ASMBitTest(&e.xclient.data.l[1], 0), 727 xAtomToString(e.xclient.data.l[2]).c_str())); 728 reset(); 729 } 730 else 731 { 732 LogFlowThisFunc(("Unhandled: wnd=%#x, msg=%s\n", 733 e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str())); 734 rc = VERR_NOT_SUPPORTED; 735 } 736 737 break; 738 } 739 740 case GH: 741 { 742 //if (m_state == Dropped) 743 //{ 744 LogFlowThisFunc(("Enqueuing ClientMessage\n")); 745 746 m_eventQueue.append(e); 747 rc = RTSemEventSignal(m_hEventSem); 748 //} 749 750 //rc = VINF_SUCCESS; 751 break; 752 } 753 754 default: 755 { 756 LogFlowThisFunc(("Unhandled: wnd=%#x, msg=%s\n", 757 e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str())); 758 rc = VERR_INVALID_STATE; 759 break; 760 } 761 } 762 763 LogFlowThisFunc(("Returning rc=%Rrc\n", rc)); 764 return rc; 765 } 766 767 int DragInstance::onX11SelectionNotify(const XEvent &e) 768 { 769 AssertReturn(e.type == SelectionNotify, VERR_INVALID_PARAMETER); 770 771 LogFlowThisFunc(("m_mode=%d, m_state=%d\n", m_mode, m_state)); 772 773 int rc; 774 775 switch (m_mode) 776 { 777 case GH: 778 { 779 if (m_state == Dropped) 780 { 781 LogFlowThisFunc(("Enqueuing SelectionNotify\n")); 782 783 m_eventQueue.append(e); 784 rc = RTSemEventSignal(m_hEventSem); 785 } 786 break; 787 } 788 789 default: 790 { 791 LogFlowThisFunc(("Unhandled: wnd=%#x, msg=%s\n", 792 e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str())); 793 rc = VERR_INVALID_STATE; 794 break; 795 } 796 } 797 798 LogFlowThisFunc(("Returning rc=%Rrc\n", rc)); 799 return rc; 800 } 801 802 803 int DragInstance::onX11SelectionRequest(const XEvent &e) 804 { 805 AssertReturn(e.type == SelectionRequest, VERR_INVALID_PARAMETER); 806 807 LogFlowThisFunc(("m_mode=%d, m_state=%d\n", m_mode, m_state)); 808 LogFlowThisFunc(("Event owner=%#x, requestor=%#x, selection=%s, target=%s, prop=%s, time=%u\n", 809 e.xselectionrequest.owner, 810 e.xselectionrequest.requestor, 811 xAtomToString(e.xselectionrequest.selection).c_str(), 812 xAtomToString(e.xselectionrequest.target).c_str(), 813 xAtomToString(e.xselectionrequest.property).c_str(), 814 e.xselectionrequest.time)); 815 int rc; 816 817 switch (m_mode) 818 { 819 case HG: 820 { 821 rc = VINF_SUCCESS; 822 823 /* 824 * A window is asking for some data. Normally here the data would be copied 825 * into the selection buffer and send to the requestor. Obviously we can't 826 * do that, because we first need to ask the host for the data of the 827 * requested MIME type. This is done and later answered with the correct 828 * data -- see DragInstance::hgDataReceived(). 829 */ 830 831 /* Is the requestor asking for the possible MIME types? */ 832 if (e.xselectionrequest.target == xAtom(XA_TARGETS)) 833 { 834 LogFlowThisFunc(("wnd=%#x asking for target list\n", e.xselectionrequest.requestor)); 835 836 /* If so, set the window property with the formats on the requestor 837 * window. */ 838 setFormatsWindowProperty(e.xselectionrequest.requestor, e.xselectionrequest.property); 839 840 XEvent s; 841 RT_ZERO(s); 842 s.xselection.type = SelectionNotify; 843 s.xselection.display = e.xselection.display; 844 s.xselection.time = e.xselectionrequest.time; 845 s.xselection.selection = e.xselectionrequest.selection; 846 s.xselection.requestor = e.xselectionrequest.requestor; 847 s.xselection.target = e.xselectionrequest.target; 848 s.xselection.property = e.xselectionrequest.property; 849 850 int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s); 851 if (RT_UNLIKELY(xrc == 0)) 852 LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor)); 853 } 854 /* Is the requestor asking for a specific MIME type (we support)? */ 855 else if (m_formats.contains(e.xselectionrequest.target)) 856 { 857 LogFlowThisFunc(("wnd=%#x asking for data, format=%s\n", 858 e.xselectionrequest.requestor, xAtomToString(e.xselectionrequest.target).c_str())); 859 860 /* If so, we need to inform the host about this request. Save the 861 * selection request event for later use. */ 862 if ( m_state != Dropped) 863 // || m_curWin != e.xselectionrequest.requestor) 864 { 865 LogFlowThisFunc(("Wrong state, refusing request\n")); 866 867 XEvent s; 868 RT_ZERO(s); 869 s.xselection.type = SelectionNotify; 870 s.xselection.display = e.xselection.display; 871 s.xselection.time = e.xselectionrequest.time; 872 s.xselection.selection = e.xselectionrequest.selection; 873 s.xselection.requestor = e.xselectionrequest.requestor; 874 s.xselection.target = None; 875 s.xselection.property = e.xselectionrequest.property; 876 877 int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s); 878 if (RT_UNLIKELY(xrc == 0)) 879 LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor)); 880 } 881 else 882 { 883 LogFlowThisFunc(("Saving selection notify message\n")); 884 885 memcpy(&m_eventHgSelection, &e, sizeof(XEvent)); 886 887 const char *pcszFormat = xAtomToString(e.xselectionrequest.target).c_str(); 888 AssertPtr(pcszFormat); 889 rc = VbglR3DnDHGRequestData(m_uClientID, pcszFormat); 890 LogFlowThisFunc(("Requesting data from host as \"%s\", rc=%Rrc\n", 891 pcszFormat, rc)); 892 } 893 } 894 /* Anything else. */ 895 else 896 { 897 LogFlowThisFunc(("Refusing unknown command\n")); 898 899 /* We don't understand this request message and therefore answer with an 900 * refusal messages. */ 901 XEvent s; 902 RT_ZERO(s); 903 s.xselection.type = SelectionNotify; 904 s.xselection.display = e.xselection.display; 905 s.xselection.time = e.xselectionrequest.time; 906 s.xselection.selection = e.xselectionrequest.selection; 907 s.xselection.requestor = e.xselectionrequest.requestor; 908 s.xselection.target = None; /* default is refusing */ 909 s.xselection.property = None; /* default is refusing */ 910 int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s); 911 if (RT_UNLIKELY(xrc == 0)) 912 LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor)); 913 } 914 915 break; 916 } 917 918 default: 919 { 920 LogFlowThisFunc(("Unhandled: wnd=%#x, msg=%s\n", 921 e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str())); 922 rc = VERR_INVALID_STATE; 923 break; 924 } 925 } 926 927 LogFlowThisFunc(("Returning rc=%Rrc\n", rc)); 928 return rc; 929 } 930 931 int DragInstance::onX11Event(const XEvent &e) 932 { 933 int rc; 934 935 LogFlowThisFunc(("X11 event, type=%d\n", e.type)); 936 switch (e.type) 937 { 938 case SelectionNotify: 939 rc = onX11SelectionNotify(e); 940 break; 941 942 case SelectionRequest: 943 rc = onX11SelectionRequest(e); 944 break; 945 946 case ClientMessage: 947 rc = onX11ClientMessage(e); 948 break; 949 950 case SelectionClear: 951 LogFlowThisFunc(("SelectionClear\n")); 952 rc = VINF_SUCCESS; 953 break; 954 955 /*case MotionNotify: 956 hide(); 957 break;*/ 958 959 default: 960 rc = VERR_NOT_IMPLEMENTED; 961 break; 962 } 963 964 LogFlowThisFunc(("rc=%Rrc\n", rc)); 965 return rc; 966 } 967 968 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 969 bool DragInstance::waitForX11Msg(XEvent &evX, int iType, 970 RTMSINTERVAL uTimeoutMS /* = 100 */) 971 { 972 LogFlowThisFunc(("iType=%d, uTimeoutMS=%RU32, cEventQueue=%zu\n", 973 iType, uTimeoutMS, m_eventQueue.size())); 974 975 bool fFound = false; 976 const uint64_t uiStart = RTTimeMilliTS(); 977 do 978 { 979 /* Check if there is a client message in the queue. */ 980 for (size_t i = 0; i < m_eventQueue.size(); i++) 981 { 982 int rc2 = RTCritSectEnter(&m_eventQueueCS); 983 if (RT_SUCCESS(rc2)) 984 { 985 XEvent e = m_eventQueue.at(i); 986 987 fFound = e.type == iType; 988 if (fFound) 989 { 990 m_eventQueue.removeAt(i); 991 evX = e; 992 } 993 994 rc2 = RTCritSectLeave(&m_eventQueueCS); 995 AssertRC(rc2); 996 997 if (fFound) 998 break; 999 } 1000 } 1001 1002 if (fFound) 1003 break; 1004 1005 int rc2 = RTSemEventWait(m_hEventSem, 25 /* ms */); 1006 if ( RT_FAILURE(rc2) 1007 && rc2 != VERR_TIMEOUT) 1008 { 1009 LogFlowFunc(("Waiting failed with rc=%Rrc\n", rc2)); 1010 break; 1011 } 1012 } 1013 while (RTTimeMilliTS() - uiStart < uTimeoutMS); 1014 1015 LogFlowThisFunc(("Returning fFound=%RTbool, msRuntime=%RU64\n", 1016 fFound, RTTimeMilliTS() - uiStart)); 1017 return fFound; 1018 } 1019 1020 bool DragInstance::waitForX11ClientMsg(XClientMessageEvent &evMsg, Atom aType, 1021 RTMSINTERVAL uTimeoutMS /*= 100 */) 1022 { 1023 LogFlowThisFunc(("aType=%s, uTimeoutMS=%RU32, cEventQueue=%zu\n", 1024 xAtomToString(aType).c_str(), uTimeoutMS, m_eventQueue.size())); 1025 1026 bool fFound = false; 1027 const uint64_t uiStart = RTTimeMilliTS(); 1028 do 1029 { 1030 /* Check if there is a client message in the queue. */ 1031 for (size_t i = 0; i < m_eventQueue.size(); i++) 1032 { 1033 int rc2 = RTCritSectEnter(&m_eventQueueCS); 1034 if (RT_SUCCESS(rc2)) 1035 { 1036 XEvent e = m_eventQueue.at(i); 1037 if (e.type == ClientMessage) 1038 { 1039 m_eventQueue.removeAt(i); 1040 evMsg = e.xclient; 1041 1042 fFound = true; 1043 } 1044 1045 rc2 = RTCritSectLeave(&m_eventQueueCS); 1046 AssertRC(rc2); 1047 1048 if (fFound) 1049 break; 1050 } 1051 } 1052 1053 if (fFound) 1054 break; 1055 1056 int rc2 = RTSemEventWait(m_hEventSem, 25 /* ms */); 1057 if ( RT_FAILURE(rc2) 1058 && rc2 != VERR_TIMEOUT) 1059 { 1060 LogFlowFunc(("Waiting failed with rc=%Rrc\n", rc2)); 1061 break; 1062 } 1063 } 1064 while (RTTimeMilliTS() - uiStart < uTimeoutMS); 1065 1066 LogFlowThisFunc(("Returning fFound=%RTbool, msRuntime=%RU64\n", 1067 fFound, RTTimeMilliTS() - uiStart)); 1068 return fFound; 1069 } 1070 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */ 620 1071 621 1072 /* … … 665 1116 666 1117 /* Move the mouse cursor within the guest. */ 667 mo veCursor(u32xPos, u32yPos);1118 mouseCursorMove(u32xPos, u32yPos); 668 1119 669 1120 long newVer = -1; /* This means the current window is _not_ XdndAware. */ … … 793 1244 } 794 1245 795 int DragInstance::hgX11ClientMessage(const XEvent& e)796 {797 if ( m_mode != HG)798 // || m_state != Dragging)799 return VERR_INVALID_STATE;800 801 /* Client messages are used to inform us about the status of a XdndAware802 * window, in response of some events we send to them. */803 int rc = VINF_SUCCESS;804 if ( e.xclient.message_type == xAtom(XA_XdndStatus)805 && m_wndCur == static_cast<Window>(e.xclient.data.l[0]))806 {807 /* The XdndStatus message tell us if the window will accept the DnD808 * event and with which action. We immediately send this info down to809 * the host as a response of a previous DnD message. */810 LogFlowThisFunc(("XA_XdndStatus wnd=%#x, accept=%RTbool, action='%s'\n",811 e.xclient.data.l[0],812 ASMBitTest(&e.xclient.data.l[1], 0),813 xAtomToString(e.xclient.data.l[4]).c_str()));814 815 uint32_t uAction = DND_IGNORE_ACTION;816 /** @todo Compare this with the allowed actions. */817 if (ASMBitTest(&e.xclient.data.l[1], 0))818 uAction = toHGCMAction(static_cast<Atom>(e.xclient.data.l[4]));819 820 rc = VbglR3DnDHGAcknowledgeOperation(m_uClientID, uAction);821 }822 else if (e.xclient.message_type == xAtom(XA_XdndFinished))823 {824 /* This message is send on a un/successful DnD drop request. */825 LogFlowThisFunc(("XA_XdndFinished: wnd=%#x, success=%RTbool, action='%s'\n",826 e.xclient.data.l[0],827 ASMBitTest(&e.xclient.data.l[1], 0),828 xAtomToString(e.xclient.data.l[2]).c_str()));829 830 reset();831 }832 else833 LogFlowThisFunc(("Unhandled: wnd=%#x, msg='%s'\n",834 e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str()));835 836 LogFlowFuncLeaveRC(rc);837 return rc;838 }839 840 1246 int DragInstance::hgDrop(void) 841 1247 { … … 873 1279 } 874 1280 875 int DragInstance::hgX11SelectionRequest(const XEvent& e)876 {877 AssertReturn(e.type == SelectionRequest, VERR_INVALID_PARAMETER);878 879 if ( m_mode != HG)880 // || m_state != D)881 return VERR_INVALID_STATE;882 883 LogFlowThisFunc(("owner=%#x, requestor=%#x, sel_atom='%s', tar_atom='%s', prop_atom='%s', time=%u\n",884 e.xselectionrequest.owner,885 e.xselectionrequest.requestor,886 xAtomToString(e.xselectionrequest.selection).c_str(),887 xAtomToString(e.xselectionrequest.target).c_str(),888 xAtomToString(e.xselectionrequest.property).c_str(),889 e.xselectionrequest.time));890 891 int rc = VINF_SUCCESS;892 893 /*894 * A window is asking for some data. Normally here the data would be copied895 * into the selection buffer and send to the requestor. Obviously we can't896 * do that, cause we first need to ask the host for the data of the897 * requested mime type. This is done and later answered with the correct898 * data (s. dataReceived).899 */900 901 /* Is the requestor asking for the possible mime types? */902 if(e.xselectionrequest.target == xAtom(XA_TARGETS))903 {904 LogFlowThisFunc(("wnd=%#x asking for target list\n", e.xselectionrequest.requestor));905 906 /* If so, set the window property with the formats on the requestor907 * window. */908 setFormatsWindowProperty(e.xselectionrequest.requestor, e.xselectionrequest.property);909 910 XEvent s;911 RT_ZERO(s);912 s.xselection.type = SelectionNotify;913 s.xselection.display = e.xselection.display;914 s.xselection.time = e.xselectionrequest.time;915 s.xselection.selection = e.xselectionrequest.selection;916 s.xselection.requestor = e.xselectionrequest.requestor;917 s.xselection.target = e.xselectionrequest.target;918 s.xselection.property = e.xselectionrequest.property;919 920 int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);921 if (RT_UNLIKELY(xrc == 0))922 LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor));923 }924 /* Is the requestor asking for a specific mime type (we support)? */925 else if(m_formats.contains(e.xselectionrequest.target))926 {927 LogFlowThisFunc(("wnd=%#x asking for data (format='%s')\n",928 e.xselectionrequest.requestor, xAtomToString(e.xselectionrequest.target).c_str()));929 930 /* If so, we need to inform the host about this request. Save the931 * selection request event for later use. */932 if ( m_state != Dropped)933 // || m_curWin != e.xselectionrequest.requestor)934 {935 LogFlowThisFunc(("Refusing ...\n"));936 937 XEvent s;938 RT_ZERO(s);939 s.xselection.type = SelectionNotify;940 s.xselection.display = e.xselection.display;941 s.xselection.time = e.xselectionrequest.time;942 s.xselection.selection = e.xselectionrequest.selection;943 s.xselection.requestor = e.xselectionrequest.requestor;944 s.xselection.target = None;945 s.xselection.property = e.xselectionrequest.property;946 947 int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);948 if (RT_UNLIKELY(xrc == 0))949 LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor));950 }951 else952 {953 LogFlowThisFunc(("Copying data from host ...\n"));954 955 memcpy(&m_selEvent, &e, sizeof(XEvent));956 rc = VbglR3DnDHGRequestData(m_uClientID, xAtomToString(e.xselectionrequest.target).c_str());957 }958 }959 /* Anything else. */960 else961 {962 LogFlowThisFunc(("Refusing unknown command\n"));963 964 /* We don't understand this request message and therefore answer with an965 * refusal messages. */966 XEvent s;967 RT_ZERO(s);968 s.xselection.type = SelectionNotify;969 s.xselection.display = e.xselection.display;970 s.xselection.time = e.xselectionrequest.time;971 s.xselection.selection = e.xselectionrequest.selection;972 s.xselection.requestor = e.xselectionrequest.requestor;973 s.xselection.target = None; /* default is refusing */974 s.xselection.property = None; /* default is refusing */975 int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);976 if (RT_UNLIKELY(xrc == 0))977 LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor));978 }979 980 LogFlowFuncLeaveRC(rc);981 return rc;982 }983 984 1281 int DragInstance::hgDataReceived(void *pvData, uint32_t cData) 985 1282 { … … 1004 1301 * The host send us the DnD data in the requested mime type. This allows us 1005 1302 * to fill the XdndSelection property of the requestor window with the data 1006 * and afterwards inform himabout the new status.1303 * and afterwards inform the host about the new status. 1007 1304 */ 1008 1305 XEvent s; 1009 1306 RT_ZERO(s); 1010 1307 s.xselection.type = SelectionNotify; 1011 s.xselection.display = m_ selEvent.xselection.display;1308 s.xselection.display = m_eventHgSelection.xselection.display; 1012 1309 // s.xselection.owner = m_selEvent.xselectionrequest.owner; 1013 s.xselection.time = m_ selEvent.xselectionrequest.time;1014 s.xselection.selection = m_ selEvent.xselectionrequest.selection;1015 s.xselection.requestor = m_ selEvent.xselectionrequest.requestor;1016 s.xselection.target = m_ selEvent.xselectionrequest.target;1017 s.xselection.property = m_ selEvent.xselectionrequest.property;1018 1019 LogFlowThisFunc(("owner=%#x, requestor=%#x,sel_atom='%s',tar_atom='%s',prop_atom='%s',time=%u\n",1020 m_ selEvent.xselectionrequest.owner,1310 s.xselection.time = m_eventHgSelection.xselectionrequest.time; 1311 s.xselection.selection = m_eventHgSelection.xselectionrequest.selection; 1312 s.xselection.requestor = m_eventHgSelection.xselectionrequest.requestor; 1313 s.xselection.target = m_eventHgSelection.xselectionrequest.target; 1314 s.xselection.property = m_eventHgSelection.xselectionrequest.property; 1315 1316 LogFlowThisFunc(("owner=%#x, requestor=%#x, sel_atom=%s, target_atom=%s, prop_atom=%s, time=%u\n", 1317 m_eventHgSelection.xselectionrequest.owner, 1021 1318 s.xselection.requestor, 1022 1319 xAtomToString(s.xselection.selection).c_str(), … … 1039 1336 { 1040 1337 int rc = VINF_SUCCESS; 1041 Window wndOwner = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection)); 1042 LogFlowThisFunc(("Checking pending wndOwner=%#x wndProxy=%#x\n", wndOwner, m_wndProxy)); 1043 1044 /* Is there someone own the Xdnd selection which aren't we. */ 1045 if ( wndOwner 1046 && wndOwner != m_wndProxy) 1047 { 1338 Window wndSelection = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection)); 1339 LogFlowThisFunc(("Checking pending wndSelection=%#x, wndProxy=%#x\n", wndSelection, m_wndProxy)); 1340 1341 /* Is this another window which has a Xdnd selection than our current one? */ 1342 if ( wndSelection 1343 && wndSelection != m_wndProxy) 1344 { 1345 m_mode = GH; 1346 1048 1347 /* Map the window on the current cursor position, which should provoke 1049 1348 * an XdndEnter event. */ 1050 int rx, ry;1051 showProxyWin(rx, ry); 1349 proxyWinShow(); 1350 1052 1351 XEvent e; 1053 if ( m_pParent->waitForXMsg(e, ClientMessage))1352 if (waitForX11Msg(e, ClientMessage)) 1054 1353 { 1055 int xrc = Success; 1056 XClientMessageEvent *clme = reinterpret_cast<XClientMessageEvent*>(&e); 1057 LogFlowThisFunc(("Next X event %s\n", gX11->xAtomToString(clme->message_type).c_str())); 1058 if (clme->message_type == xAtom(XA_XdndEnter)) 1354 int xRc; 1355 XClientMessageEvent *pEventClient = reinterpret_cast<XClientMessageEvent*>(&e); 1356 AssertPtr(pEventClient); 1357 1358 LogFlowThisFunc(("Next X event is: %s\n", 1359 gX11->xAtomToString(pEventClient->message_type).c_str())); 1360 1361 if (pEventClient->message_type == xAtom(XA_XdndEnter)) 1059 1362 { 1060 1363 Atom type = None; … … 1062 1365 unsigned long n, a; 1063 1366 unsigned char *ret = 0; 1367 1064 1368 reset(); 1065 1369 1066 m_ formats.clear();1067 m_ actions.clear();1068 m_wndCur = wndOwner; 1370 m_state = Dragging; 1371 m_wndCur = wndSelection; 1372 1069 1373 LogFlowThisFunc(("XA_XdndEnter\n")); 1070 /* Check if the mime types are in the msg itself or if we need 1374 #ifdef DEBUG 1375 XWindowAttributes xwa; 1376 XGetWindowAttributes(m_pDisplay, m_wndCur, &xwa); 1377 LogFlowThisFunc(("m_wndCur=%#x, x=%d, y=%d, width=%d, height=%d\n", 1378 m_wndCur, xwa.x, xwa.y, xwa.width, xwa.height)); 1379 #endif 1380 /* Check if the MIME types are in the message itself or if we need 1071 1381 * to fetch the XdndTypeList property from the window. */ 1072 if (!ASMBitTest(& clme->data.l[1], 0))1382 if (!ASMBitTest(&pEventClient->data.l[1], 0)) 1073 1383 { 1074 1384 for (int i = 2; i < 5; ++i) 1075 1385 { 1076 LogFlowThisFunc(("Receive list msg: %s\n", gX11->xAtomToString(clme->data.l[i]).c_str())); 1077 m_formats.append(clme->data.l[i]); 1386 LogFlowThisFunc(("Received format via message: %s\n", 1387 gX11->xAtomToString(pEventClient->data.l[i]).c_str())); 1388 1389 m_formats.append(pEventClient->data.l[i]); 1078 1390 } 1079 1391 } 1080 1392 else 1081 1393 { 1082 x rc = XGetWindowProperty(m_pDisplay, wndOwner,1394 xRc = XGetWindowProperty(m_pDisplay, wndSelection, 1083 1395 xAtom(XA_XdndTypeList), 1084 1396 0, VBOX_MAX_XPROPERTIES, 1085 1397 False, XA_ATOM, &type, &f, &n, &a, &ret); 1086 if ( x rc == Success1398 if ( xRc == Success 1087 1399 && n > 0 1088 1400 && ret) … … 1091 1403 for (int i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, n); ++i) 1092 1404 { 1093 LogFlowThisFunc(("Receive list: %s\n", gX11->xAtomToString(data[i]).c_str())); 1405 LogFlowThisFunc(("Received format via XdndTypeList: %s\n", 1406 gX11->xAtomToString(data[i]).c_str())); 1407 1094 1408 m_formats.append(data[i]); 1095 1409 } 1410 1096 1411 XFree(ret); 1097 1412 } … … 1099 1414 1100 1415 /* Fetch the possible list of actions, if this property is set. */ 1101 x rc = XGetWindowProperty(m_pDisplay, wndOwner,1416 xRc = XGetWindowProperty(m_pDisplay, wndSelection, 1102 1417 xAtom(XA_XdndActionList), 1103 1418 0, VBOX_MAX_XPROPERTIES, 1104 1419 False, XA_ATOM, &type, &f, &n, &a, &ret); 1105 if ( x rc == Success1420 if ( xRc == Success 1106 1421 && n > 0 1107 1422 && ret) … … 1110 1425 for (int i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, n); ++i) 1111 1426 { 1112 LogFlowThisFunc(("Receive actions: %s\n", gX11->xAtomToString(data[i]).c_str())); 1427 LogFlowThisFunc(("Received action: %s\n", 1428 gX11->xAtomToString(data[i]).c_str())); 1429 1113 1430 m_actions.append(data[i]); 1114 1431 } … … 1116 1433 XFree(ret); 1117 1434 } 1118 1119 m_state = Dragging;1120 m_mode = GH;1121 1435 1122 1436 /* Acknowledge the event by sending a Status msg back to the … … 1124 1438 XClientMessageEvent m; 1125 1439 RT_ZERO(m); 1440 1126 1441 m.type = ClientMessage; 1127 1442 m.display = m_pDisplay; 1128 m.window = clme->data.l[0];1443 m.window = pEventClient->data.l[0]; 1129 1444 m.message_type = xAtom(XA_XdndStatus); 1130 1445 m.format = 32; … … 1132 1447 m.data.l[1] = 1; 1133 1448 m.data.l[4] = xAtom(XA_XdndActionCopy); 1134 xrc = XSendEvent(m_pDisplay, clme->data.l[0], False, 0, reinterpret_cast<XEvent*>(&m)); 1135 if (RT_UNLIKELY(xrc == 0)) 1136 LogFlowThisFunc(("Error sending xevent\n")); 1449 1450 xRc = XSendEvent(m_pDisplay, pEventClient->data.l[0], 1451 False, 0, reinterpret_cast<XEvent*>(&m)); 1452 if (RT_UNLIKELY(xRc == 0)) 1453 LogFlowThisFunc(("Error sending xEvent\n")); 1137 1454 } 1138 else if (clme->message_type == xAtom(XA_XdndPosition)) 1455 /* Did the source tell us where the cursor currently is? */ 1456 else if (pEventClient->message_type == xAtom(XA_XdndPosition)) 1139 1457 { 1140 1458 LogFlowThisFunc(("XA_XdndPosition\n")); 1459 1460 /* Reply with a XdndStatus message to tell the source whether 1461 * the data can be dropped or not. */ 1141 1462 XClientMessageEvent m; 1142 1463 RT_ZERO(m); 1143 1464 m.type = ClientMessage; 1144 1465 m.display = m_pDisplay; 1145 m.window = clme->data.l[0];1466 m.window = pEventClient->data.l[0]; 1146 1467 m.message_type = xAtom(XA_XdndStatus); 1147 1468 m.format = 32; 1148 1469 m.data.l[0] = m_wndProxy; 1149 1470 m.data.l[1] = 1; 1150 m.data.l[4] = clme->data.l[4]; 1151 xrc = XSendEvent(m_pDisplay, clme->data.l[0], False, 0, reinterpret_cast<XEvent*>(&m)); 1152 if (RT_UNLIKELY(xrc == 0)) 1153 LogFlowThisFunc(("Error sending xevent\n")); 1471 m.data.l[4] = pEventClient->data.l[4]; 1472 1473 xRc = XSendEvent(m_pDisplay, pEventClient->data.l[0], 1474 False, 0, reinterpret_cast<XEvent*>(&m)); 1475 if (RT_UNLIKELY(xRc == 0)) 1476 LogFlowThisFunc(("Error sending xEvent\n")); 1154 1477 } 1155 else if ( clme->message_type == xAtom(XA_XdndLeave))1478 else if (pEventClient->message_type == xAtom(XA_XdndLeave)) 1156 1479 { 1480 LogFlowThisFunc(("XA_XdndLeave\n")); 1157 1481 } 1158 1482 } 1159 1483 1160 hideProxyWin(); 1161 1162 rc = VbglR3DnDGHAcknowledgePending(m_uClientID, DND_COPY_ACTION, toHGCMActions(m_actions), 1163 gX11->xAtomListToString(m_formats).c_str()); 1484 proxyWinHide(); 1485 1486 /* Do we need to acknowledge at least one format to the host? */ 1487 if (!m_formats.isEmpty()) 1488 { 1489 RTCString strFormats = gX11->xAtomListToString(m_formats); 1490 uint32_t uDefAction = DND_COPY_ACTION; /** @todo Handle default action! */ 1491 uint32_t uAllActions = toHGCMActions(m_actions); 1492 1493 rc = VbglR3DnDGHAcknowledgePending(m_uClientID, uDefAction, uAllActions, strFormats.c_str()); 1494 LogFlowThisFunc(("Acknowledging m_uClientID=%RU32, allActions=0x%x, strFormats=%s, rc=%Rrc\n", 1495 m_uClientID, uAllActions, strFormats.c_str(), rc)); 1496 } 1164 1497 } 1165 1498 … … 1175 1508 int rc = VINF_SUCCESS; 1176 1509 1510 m_state = Dropped; 1511 1177 1512 /* Show the proxy window, so that the source will find it. */ 1178 int rx, ry;1179 showProxyWin(rx, ry);1513 int iRootX, iRootY; 1514 proxyWinShow(&iRootX, &iRootY); 1180 1515 XFlush(m_pDisplay); 1516 1517 #ifdef DEBUG 1518 XWindowAttributes xwa; 1519 XGetWindowAttributes(m_pDisplay, m_wndCur, &xwa); 1520 LogFlowThisFunc(("m_wndCur=%#x, x=%d, y=%d, width=%d, height=%d\n", 1521 m_wndCur, xwa.x, xwa.y, xwa.width, xwa.height)); 1522 1523 iRootX = xwa.x; 1524 iRootY = xwa.y; 1525 #endif 1181 1526 1182 1527 /* We send a fake release event to the current window, cause 1183 1528 * this should have the grab. */ 1184 sendButtonEvent(m_wndCur, rx, ry, 1, false); 1185 1186 /* The fake button release event, should lead to an XdndDrop event from the 1187 * source. Because of the showing of the proxy window, sometimes other Xdnd 1188 * events occurs before, like a XdndPosition event. We are not interested 1189 * in those, so try to get the right one. */ 1190 XEvent e; 1191 XClientMessageEvent *clme = 0; 1192 RT_ZERO(e); 1193 1194 int cRetries = 3; 1195 for (int i = 0; i < cRetries; i++) 1196 { 1197 if (m_pParent->waitForXMsg(e, ClientMessage)) 1529 mouseButtonSet(m_wndCur, iRootX, iRootY, 1530 1 /* Button */, false /* Release button */); 1531 1532 /* The fake button release event should lead to a XdndDrop event from the 1533 * source. Because of showing our proxy window, other Xdnd events can 1534 * occur before, e.g. a XdndPosition event. We are not interested 1535 * in those, so just try to get the right one. */ 1536 1537 XClientMessageEvent evDnDDrop; 1538 bool fDrop = waitForX11ClientMsg(evDnDDrop, xAtom(XA_XdndDrop), 1539 5 * 1000 /* Timeout in ms */); 1540 if (fDrop) 1541 { 1542 /* Request to convert the selection in the specific format and 1543 * place it to our proxy window as property. */ 1544 Window srcWin = m_wndCur;//clme->data.l[0]; 1545 Atom aFormat = gX11->stringToxAtom(strFormat.c_str()); 1546 1547 XConvertSelection(m_pDisplay, xAtom(XA_XdndSelection), 1548 aFormat, xAtom(XA_XdndSelection), 1549 m_wndProxy, evDnDDrop.data.l[2]); 1550 1551 /* Wait for the selection notify event. */ 1552 XEvent evSelNotify; 1553 RT_ZERO(evSelNotify); 1554 if (waitForX11Msg(evSelNotify, SelectionNotify)) 1198 1555 { 1199 if (reinterpret_cast<XClientMessageEvent*>(&e)->message_type == xAtom(XA_XdndDrop)) 1556 /* Make some paranoid checks. */ 1557 if ( evSelNotify.xselection.type == SelectionNotify 1558 && evSelNotify.xselection.display == m_pDisplay 1559 && evSelNotify.xselection.selection == xAtom(XA_XdndSelection) 1560 && evSelNotify.xselection.requestor == m_wndProxy 1561 && evSelNotify.xselection.target == aFormat) 1200 1562 { 1201 clme = reinterpret_cast<XClientMessageEvent*>(&e); 1202 break; 1203 } 1204 } 1205 } 1206 1207 if (clme) 1208 { 1209 /* Make some paranoid checks. */ 1210 if (clme->message_type == xAtom(XA_XdndDrop)) 1211 { 1212 /* Request to convert the selection in the specific format and 1213 * place it to our proxy window as property. */ 1214 Window srcWin = m_wndCur;//clme->data.l[0]; 1215 Atom aFormat = gX11->stringToxAtom(strFormat.c_str()); 1216 1217 XConvertSelection(m_pDisplay, xAtom(XA_XdndSelection), 1218 aFormat, xAtom(XA_XdndSelection), 1219 m_wndProxy, clme->data.l[2]); 1220 1221 /* Wait for the selection notify event. */ 1222 RT_ZERO(e); 1223 if (m_pParent->waitForXMsg(e, SelectionNotify)) 1224 { 1225 /* Make some paranoid checks. */ 1226 if ( e.xselection.type == SelectionNotify 1227 && e.xselection.display == m_pDisplay 1228 && e.xselection.selection == xAtom(XA_XdndSelection) 1229 && e.xselection.requestor == m_wndProxy 1230 && e.xselection.target == aFormat) 1563 LogFlowThisFunc(("Selection notfiy (from wnd=%#x)\n", m_wndCur)); 1564 1565 Atom aPropType; 1566 int iPropFormat; 1567 unsigned long cItems, cbRemaining; 1568 unsigned char *pcData = NULL; 1569 XGetWindowProperty(m_pDisplay, m_wndProxy, 1570 xAtom(XA_XdndSelection) /* Property */, 1571 0 /* Offset */, 1572 VBOX_MAX_XPROPERTIES /* Length of 32-bit multiples */, 1573 True /* Delete property? */, 1574 AnyPropertyType, /* Property type */ 1575 &aPropType, &iPropFormat, &cItems, &cbRemaining, &pcData); 1576 1577 LogFlowThisFunc(("strType=%s, iPropFormat=%d, cItems=%RU32, cbRemaining=%RU32\n", 1578 gX11->xAtomToString(aPropType).c_str(), iPropFormat, cItems, cbRemaining)); 1579 1580 if ( aPropType != None 1581 && pcData != NULL 1582 && iPropFormat >= 8 1583 && cItems > 0 1584 && cbRemaining == 0) 1231 1585 { 1232 LogFlowThisFunc(("Selection notfiy (from: %x)\n", m_wndCur)); 1233 1234 Atom type; 1235 int format; 1236 unsigned long cItems, cbRemaining; 1237 unsigned char *ucData = 0; 1238 XGetWindowProperty(m_pDisplay, m_wndProxy, xAtom(XA_XdndSelection), 1239 0, VBOX_MAX_XPROPERTIES, True, AnyPropertyType, 1240 &type, &format, &cItems, &cbRemaining, &ucData); 1241 LogFlowThisFunc(("%s %d %d %s\n", gX11->xAtomToString(type).c_str(), cItems, format, ucData)); 1242 if ( type != None 1243 && ucData != NULL 1244 && format >= 8 1245 && cItems > 0 1246 && cbRemaining == 0) 1586 size_t cbData = cItems * (iPropFormat / 8); 1587 LogFlowThisFunc(("cbData=%zu\n", cbData)); 1588 1589 /* For whatever reason some of the string MIME types are not 1590 * zero terminated. Check that and correct it when necessary, 1591 * because the guest side wants this in any case. */ 1592 if ( m_sstrStringMimeTypes.contains(strFormat) 1593 && pcData[cbData - 1] != '\0') 1247 1594 { 1248 size_t cbData = cItems * (format / 8); 1249 /* For whatever reason some of the string mime-types are not 1250 * zero terminated. Check that and correct it when necessary, 1251 * cause the guest side wants this always. */ 1252 if ( m_sstrStringMimeTypes.contains(strFormat) 1253 && ucData[cbData - 1] != '\0') 1595 unsigned char *pvDataTmp = static_cast<unsigned char*>(RTMemAlloc(cbData + 1)); 1596 if (pvDataTmp) 1254 1597 { 1255 LogFlowThisFunc(("Rebuild %u\n", cbData)); 1256 unsigned char *ucData1 = static_cast<unsigned char*>(RTMemAlloc(cbData + 1)); 1257 if (ucData1) 1258 { 1259 memcpy(ucData1, ucData, cbData); 1260 ucData1[cbData++] = '\0'; 1261 1262 /* Got the data and its fully transfered. */ 1263 rc = VbglR3DnDGHSendData(m_uClientID, strFormat.c_str(), 1264 ucData1, cbData); 1265 RTMemFree(ucData1); 1266 } 1267 else 1268 rc = VERR_NO_MEMORY; 1598 memcpy(pvDataTmp, pcData, cbData); 1599 pvDataTmp[cbData++] = '\0'; 1600 1601 rc = VbglR3DnDGHSendData(m_uClientID, strFormat.c_str(), 1602 pvDataTmp, cbData); 1603 RTMemFree(pvDataTmp); 1269 1604 } 1270 1605 else 1271 { 1272 /* Just send the data to the host. */ 1273 rc = VbglR3DnDGHSendData(m_uClientID, strFormat.c_str(), 1274 ucData, cbData); 1275 } 1276 1277 LogFlowThisFunc(("send responce\n")); 1278 /* Confirm the result of the transfer to the source window. */ 1279 XClientMessageEvent m; 1280 RT_ZERO(m); 1281 m.type = ClientMessage; 1282 m.display = m_pDisplay; 1283 m.window = srcWin; 1284 m.message_type = xAtom(XA_XdndFinished); 1285 m.format = 32; 1286 m.data.l[0] = m_wndProxy; 1287 m.data.l[1] = RT_SUCCESS(rc) ? 1 : 0; /* Confirm or deny success */ 1288 m.data.l[2] = RT_SUCCESS(rc) ? toX11Action(uAction) : None; /* Action used on success */ 1289 1290 int xrc = XSendEvent(m_pDisplay, srcWin, True, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1291 if (RT_UNLIKELY(xrc == 0)) 1292 LogFlowThisFunc(("Error sending xevent\n")); 1606 rc = VERR_NO_MEMORY; 1293 1607 } 1294 1608 else 1295 1609 { 1296 if (type == xAtom(XA_INCR)) 1297 { 1298 /** @todo Support incremental transfers. */ 1299 AssertMsgFailed(("Incrementally transfers are not supported, yet\n")); 1300 rc = VERR_NOT_IMPLEMENTED; 1301 } 1302 else 1303 { 1304 AssertMsgFailed(("Not supported data type\n")); 1305 rc = VERR_INVALID_PARAMETER; 1306 } 1307 1308 /* Cancel this. */ 1309 XClientMessageEvent m; 1310 RT_ZERO(m); 1311 m.type = ClientMessage; 1312 m.display = m_pDisplay; 1313 m.window = srcWin; 1314 m.message_type = xAtom(XA_XdndFinished); 1315 m.format = 32; 1316 m.data.l[0] = m_wndProxy; 1317 m.data.l[1] = 0; 1318 m.data.l[2] = None; 1319 1320 int xrc = XSendEvent(m_pDisplay, srcWin, False, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1321 if (RT_UNLIKELY(xrc == 0)) 1322 LogFlowThisFunc(("Error sending xevent\n")); 1323 m_wndCur = 0; 1610 /* Send the raw data to the host. */ 1611 rc = VbglR3DnDGHSendData(m_uClientID, strFormat.c_str(), 1612 pcData, cbData); 1324 1613 } 1325 1614 1326 /* Cleanup */ 1327 if (ucData) 1328 XFree(ucData); 1615 LogFlowThisFunc(("Sent strFormat=%s with rc=%Rrc\n", 1616 strFormat.c_str(), rc)); 1617 1618 /* Confirm the result of the transfer to the source window. */ 1619 XClientMessageEvent m; 1620 RT_ZERO(m); 1621 m.type = ClientMessage; 1622 m.display = m_pDisplay; 1623 m.window = srcWin; 1624 m.message_type = xAtom(XA_XdndFinished); 1625 m.format = 32; 1626 m.data.l[0] = m_wndProxy; 1627 m.data.l[1] = RT_SUCCESS(rc) ? 1 : 0; /* Confirm or deny success */ 1628 m.data.l[2] = RT_SUCCESS(rc) ? toX11Action(uAction) : None; /* Action used on success */ 1629 1630 int xrc = XSendEvent(m_pDisplay, srcWin, True, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1631 if (RT_UNLIKELY(xrc == 0)) 1632 LogFlowThisFunc(("Error sending xEvent\n")); 1329 1633 } 1330 1634 else 1331 rc = VERR_INVALID_PARAMETER; 1635 { 1636 if (aPropType == xAtom(XA_INCR)) 1637 { 1638 /** @todo Support incremental transfers. */ 1639 AssertMsgFailed(("Incrementally transfers are not supported yet\n")); 1640 rc = VERR_NOT_IMPLEMENTED; 1641 } 1642 else 1643 { 1644 AssertMsgFailed(("Not supported data type\n")); 1645 rc = VERR_INVALID_PARAMETER; 1646 } 1647 1648 /* Cancel this. */ 1649 XClientMessageEvent m; 1650 RT_ZERO(m); 1651 m.type = ClientMessage; 1652 m.display = m_pDisplay; 1653 m.window = srcWin; 1654 m.message_type = xAtom(XA_XdndFinished); 1655 m.format = 32; 1656 m.data.l[0] = m_wndProxy; 1657 m.data.l[1] = 0; 1658 m.data.l[2] = None; 1659 1660 int xrc = XSendEvent(m_pDisplay, srcWin, False, NoEventMask, reinterpret_cast<XEvent*>(&m)); 1661 if (RT_UNLIKELY(xrc == 0)) 1662 LogFlowThisFunc(("Error sending xEvent\n")); 1663 m_wndCur = 0; 1664 } 1665 1666 /* Cleanup. */ 1667 if (pcData) 1668 XFree(pcData); 1332 1669 } 1333 1670 else 1334 rc = VERR_ TIMEOUT;1671 rc = VERR_INVALID_PARAMETER; 1335 1672 } 1336 1673 else 1337 rc = VERR_ WRONG_ORDER;1674 rc = VERR_TIMEOUT; 1338 1675 } 1339 1676 else … … 1342 1679 /* Inform the host on error. */ 1343 1680 if (RT_FAILURE(rc)) 1344 VbglR3DnDGHSendError(m_uClientID, rc); 1681 { 1682 int rc2 = VbglR3DnDGHSendError(m_uClientID, rc); 1683 AssertRC(rc2); 1684 } 1345 1685 1346 1686 /* At this point, we have either successfully transfered any data or not. 1347 * So reset our internal state , cause we are done. */1687 * So reset our internal state because we are done here for this transaction. */ 1348 1688 reset(); 1349 1689 … … 1357 1697 */ 1358 1698 1359 int DragInstance::moveCursor(uint32_t u32xPos, uint32_t u32yPos) 1360 { 1699 int DragInstance::mouseCursorMove(int iPosX, int iPosY) const 1700 { 1701 LogFlowThisFunc(("iPosX=%d, iPosY=%d\n", iPosX, iPosY)); 1702 1361 1703 /* Move the guest pointer to the DnD position, so we can find the window 1362 1704 * below that position. */ 1363 XWarpPointer(m_pDisplay, None, m_wndRoot, 0, 0, 0, 0, u32xPos, u32yPos);1705 XWarpPointer(m_pDisplay, None, m_wndRoot, 0, 0, 0, 0, iPosX, iPosY); 1364 1706 return VINF_SUCCESS; 1365 1707 } 1366 1708 1367 void DragInstance::sendButtonEvent(Window w, int rx, int ry, int button, bool fPress) const 1368 { 1369 // XTestFakeMotionEvent(m_pDisplay, -1, rx, ry, CurrentTime); 1370 // XTestFakeMotionEvent(m_pDisplay, -1, rx + 1, ry + 1, CurrentTime); 1371 // int rc = XTestFakeButtonEvent(m_pDisplay, 1, False, CurrentTime); 1372 // if (rc != 0) 1373 { 1374 XButtonEvent be; 1375 RT_ZERO(be); 1376 be.display = m_pDisplay; 1377 be.root = m_wndRoot; 1378 be.window = w; 1379 be.subwindow = None; 1380 be.same_screen = True; 1381 be.time = CurrentTime; 1382 be.button = button; 1383 be.state |= button == 1 ? Button1MotionMask : 1384 button == 2 ? Button2MotionMask : 1385 button == 3 ? Button3MotionMask : 1386 button == 4 ? Button4MotionMask : 1387 button == 5 ? Button5MotionMask : 0; 1388 be.type = fPress ? ButtonPress : ButtonRelease; 1389 be.x_root = rx; 1390 be.y_root = ry; 1391 XTranslateCoordinates(m_pDisplay, be.root, be.window, be.x_root, be.y_root, &be.x, &be.y, &be.subwindow); 1392 int xrc = XSendEvent(m_pDisplay, be.window, True, ButtonPressMask, reinterpret_cast<XEvent*>(&be)); 1709 void DragInstance::mouseButtonSet(Window wndDest, int rx, int ry, int iButton, bool fPress) const 1710 { 1711 LogFlowThisFunc(("wndDest=%#x, rx=%d, ry=%d, iBtn=%d, fPress=%RTbool\n", 1712 wndDest, rx, ry, iButton, fPress)); 1713 #if 0 1714 // Create and setting up the event 1715 XEvent event; 1716 memset (&event, 0, sizeof (event)); 1717 event.xbutton.button = iButton; 1718 event.xbutton.same_screen = True; 1719 event.xbutton.subwindow = DefaultRootWindow (m_pDisplay); 1720 1721 while (event.xbutton.subwindow) 1722 { 1723 event.xbutton.window = event.xbutton.subwindow; 1724 XQueryPointer (m_pDisplay, event.xbutton.window, 1725 &event.xbutton.root, &event.xbutton.subwindow, 1726 &event.xbutton.x_root, &event.xbutton.y_root, 1727 &event.xbutton.x, &event.xbutton.y, 1728 &event.xbutton.state); 1729 } 1730 // Press 1731 event.type = ButtonPress; 1732 if (XSendEvent (m_pDisplay, PointerWindow, True, ButtonPressMask, &event) == 0) 1733 LogFlowThisFunc(("Error sending XTestFakeButtonEvent event\n")); 1734 XFlush (m_pDisplay); 1735 1736 // Release 1737 event.type = ButtonRelease; 1738 if (XSendEvent (m_pDisplay, PointerWindow, True, ButtonReleaseMask, &event) == 0) 1739 LogFlowThisFunc(("Error sending XTestFakeButtonEvent event\n")); 1740 XFlush (m_pDisplay); 1741 1742 #else 1743 #ifdef VBOX_DND_WITH_XTEST 1744 /** @todo Make this check run only once. */ 1745 int ev, er, ma, mi; 1746 if (XTestQueryExtension(m_pDisplay, &ev, &er, &ma, &mi)) 1747 { 1748 LogFlowThisFunc(("XText extension available\n")); 1749 1750 int xrc = XTestFakeButtonEvent(m_pDisplay, 1, fPress ? True : False, CurrentTime); 1393 1751 if (RT_UNLIKELY(xrc == 0)) 1394 LogFlowThisFunc(("Error sending xevent\n")); 1395 } 1396 } 1397 1398 void DragInstance::showProxyWin(int &rx, int &ry) const 1399 { 1400 int cx, cy; 1401 unsigned int m; 1402 Window r, c; 1752 LogFlowThisFunc(("Error sending XTestFakeButtonEvent event\n")); 1753 XFlush(m_pDisplay); 1754 } 1755 else 1756 { 1757 #endif 1758 LogFlowThisFunc(("XText extension not available or disabled\n")); 1759 1760 XButtonEvent eBtn; 1761 RT_ZERO(eBtn); 1762 1763 eBtn.display = m_pDisplay; 1764 eBtn.root = m_wndRoot; 1765 eBtn.window = wndDest; 1766 eBtn.subwindow = None; 1767 eBtn.same_screen = True; 1768 eBtn.time = CurrentTime; 1769 eBtn.button = iButton; 1770 eBtn.state |= iButton == 1 ? Button1Mask /*: 1771 iButton == 2 ? Button2MotionMask : 1772 iButton == 3 ? Button3MotionMask : 1773 iButton == 4 ? Button4MotionMask : 1774 iButton == 5 ? Button5MotionMask*/ : 0; 1775 eBtn.type = fPress ? ButtonPress : ButtonRelease; 1776 eBtn.send_event = False; 1777 eBtn.x_root = rx; 1778 eBtn.y_root = ry; 1779 1780 //XTranslateCoordinates(m_pDisplay, eBtn.root, eBtn.window, eBtn.x_root, eBtn.y_root, &eBtn.x, &eBtn.y, &eBtn.subwindow); 1781 #if 0 1782 int xrc = XSendEvent(m_pDisplay, eBtn.window, True /* fPropagate */, 1783 fPress 1784 ? ButtonPressMask : ButtonReleaseMask, 1785 reinterpret_cast<XEvent*>(&eBtn)); 1786 #else 1787 int xrc = XSendEvent(m_pDisplay, eBtn.window, False /* fPropagate */, 1788 0 /* Mask */, 1789 reinterpret_cast<XEvent*>(&eBtn)); 1790 #endif 1791 if (RT_UNLIKELY(xrc == 0)) 1792 LogFlowThisFunc(("Error sending XSendEvent\n")); 1793 1794 #ifdef DEBUG 1795 Window wndTemp, wndChild; 1796 int wx, wy; unsigned int mask; 1797 XQueryPointer(m_pDisplay, m_wndRoot, &wndTemp, &wndChild, &rx, &ry, &wx, &wy, &mask); 1798 LogFlowFunc(("cursorRootX=%d, cursorRootY=%d\n", rx, ry)); 1799 #endif 1800 1801 #ifdef VBOX_DND_WITH_XTEST 1802 } 1803 #endif 1804 #endif 1805 } 1806 1807 int DragInstance::proxyWinShow(int *piRootX /*= NULL*/, 1808 int *piRootY /*= NULL*/, 1809 bool fMouseMove /*= false */) const 1810 { 1811 /* piRootX is optional. */ 1812 /* piRootY is optional. */ 1813 1814 LogFlowThisFuncEnter(); 1815 1816 int iRootX, iRootY; 1817 int iChildX, iChildY; 1818 unsigned int iMask; 1819 Window wndRoot, wndChild; 1820 1403 1821 // XTestGrabControl(m_pDisplay, False); 1404 XQueryPointer(m_pDisplay, m_wndRoot, &r, &c, &rx, &ry, &cx, &cy, &m); 1405 XSynchronize(m_pDisplay, True); 1822 Bool fInRootWnd = XQueryPointer(m_pDisplay, m_wndRoot, &wndRoot, &wndChild, 1823 &iRootX, &iRootY, 1824 &iChildX, &iChildY, &iMask); 1825 #ifdef DEBUG_andy 1826 LogFlowThisFunc(("fInRootWnd=%RTbool, wndRoot=0x%x, wndChild=0x%x, iRootX=%d, iRootY=%d\n", 1827 RT_BOOL(fInRootWnd), wndRoot, wndChild, iRootX, iRootY)); 1828 #endif 1829 1830 if (piRootX) 1831 *piRootX = iRootX; 1832 if (piRootY) 1833 *piRootY = iRootY; 1834 1835 XSynchronize(m_pDisplay, True /* Enable sync */); 1836 1406 1837 XMapWindow(m_pDisplay, m_wndProxy); 1407 1838 XRaiseWindow(m_pDisplay, m_wndProxy); 1408 XMoveResizeWindow(m_pDisplay, m_wndProxy, rx, ry, 1, 1); 1409 XWarpPointer(m_pDisplay, None, m_wndRoot, 0, 0, 0, 0, rx , ry); 1410 XSynchronize(m_pDisplay, False); 1839 XMoveResizeWindow(m_pDisplay, m_wndProxy, iRootX, iRootY, 100, 100); 1840 1841 if (fMouseMove) 1842 XWarpPointer(m_pDisplay, None, m_wndRoot, 0, 0, 0, 0, iRootX, iRootY); 1843 1844 XSynchronize(m_pDisplay, False /* Disable sync */); 1411 1845 // XTestGrabControl(m_pDisplay, True); 1412 } 1413 1414 void DragInstance::hideProxyWin(void) const 1415 { 1846 1847 return VINF_SUCCESS; /** @todo Add error checking. */ 1848 } 1849 1850 int DragInstance::proxyWinHide(void) const 1851 { 1852 LogFlowThisFuncEnter(); 1853 return 0; 1854 1416 1855 XUnmapWindow(m_pDisplay, m_wndProxy); 1417 } 1418 1419 /* Currently, not used */ 1856 1857 return VINF_SUCCESS; /** @todo Add error checking. */ 1858 } 1859 1860 /* Currently not used. */ 1861 /** @todo Is this function still needed? */ 1420 1862 void DragInstance::registerForEvents(Window wndThis) const 1421 1863 { 1422 // if (w == m_proxyWin)1423 //return;1864 if (wndThis == m_wndProxy) 1865 return; 1424 1866 1425 1867 LogFlowThisFunc(("%x\n", wndThis)); … … 1438 1880 } 1439 1881 1440 void DragInstance::setActionsWindowProperty(Window wndThis, const RTCList<Atom> &actionList) const 1441 { 1442 if (actionList.isEmpty()) 1882 void DragInstance::setActionsWindowProperty(Window wndThis, 1883 const RTCList<Atom> &lstActions) const 1884 { 1885 if (lstActions.isEmpty()) 1443 1886 return; 1444 1887 1445 XChangeProperty(m_pDisplay, wndThis, xAtom(XA_XdndActionList), XA_ATOM, 32, PropModeReplace, 1446 reinterpret_cast<const unsigned char*>(actionList.raw()), actionList.size()); 1888 XChangeProperty(m_pDisplay, wndThis, 1889 xAtom(XA_XdndActionList), 1890 XA_ATOM, 32, PropModeReplace, 1891 reinterpret_cast<const unsigned char*>(lstActions.raw()), 1892 lstActions.size()); 1447 1893 } 1448 1894 … … 1452 1898 } 1453 1899 1454 void DragInstance::setFormatsWindowProperty(Window wndThis, Atom property) const 1900 void DragInstance::setFormatsWindowProperty(Window wndThis, 1901 Atom property) const 1455 1902 { 1456 1903 if (m_formats.isEmpty()) … … 1463 1910 1464 1911 /* Add the property with the property data to the window. */ 1465 XChangeProperty(m_pDisplay, wndThis, property, XA_ATOM, 32, PropModeReplace, 1466 reinterpret_cast<const unsigned char*>(targets.raw()), targets.size()); 1912 XChangeProperty(m_pDisplay, wndThis, property, 1913 XA_ATOM, 32, PropModeReplace, 1914 reinterpret_cast<const unsigned char*>(targets.raw()), 1915 targets.size()); 1467 1916 } 1468 1917 1469 1918 void DragInstance::clearFormatsWindowProperty(Window wndThis) const 1470 1919 { 1471 XDeleteProperty(m_pDisplay, wndThis, xAtom(XA_XdndTypeList)); 1472 } 1473 1474 RTCList<Atom> DragInstance::toAtomList(const RTCList<RTCString> &formatList) const 1920 XDeleteProperty(m_pDisplay, wndThis, 1921 xAtom(XA_XdndTypeList)); 1922 } 1923 1924 RTCList<Atom> DragInstance::toAtomList(const RTCList<RTCString> &lstFormats) const 1475 1925 { 1476 1926 RTCList<Atom> atomList; 1477 for (size_t i = 0; i < formatList.size(); ++i)1478 atomList.append(XInternAtom(m_pDisplay, formatList.at(i).c_str(), False));1927 for (size_t i = 0; i < lstFormats.size(); ++i) 1928 atomList.append(XInternAtom(m_pDisplay, lstFormats.at(i).c_str(), False)); 1479 1929 1480 1930 return atomList; 1481 1931 } 1482 1932 1483 RTCList<Atom> DragInstance::toAtomList(void *pvData, uint32_t c Data) const1933 RTCList<Atom> DragInstance::toAtomList(void *pvData, uint32_t cbData) const 1484 1934 { 1485 1935 if ( !pvData 1486 || !c Data)1936 || !cbData) 1487 1937 return RTCList<Atom>(); 1938 1488 1939 char *pszStr = (char*)pvData; 1489 uint32_t cStr = cData; 1490 1491 RTCList<Atom> atomList; 1492 while (cStr > 0) 1493 { 1494 size_t cSize = RTStrNLen(pszStr, cStr); 1940 uint32_t cbStr = cbData; 1941 1942 RTCList<Atom> lstAtom; 1943 while (cbStr) 1944 { 1945 size_t cbSize = RTStrNLen(pszStr, cbStr); 1946 1495 1947 /* Create a copy with max N chars, so that we are on the save side, 1496 1948 * even if the data isn't zero terminated. */ 1497 char *pszTmp = RTStrDupN(pszStr, c Size);1949 char *pszTmp = RTStrDupN(pszStr, cbSize); 1498 1950 LogFlowThisFunc(("f: %s\n", pszTmp)); 1499 atomList.append(XInternAtom(m_pDisplay, pszTmp, False));1951 lstAtom.append(XInternAtom(m_pDisplay, pszTmp, False)); 1500 1952 RTStrFree(pszTmp); 1501 pszStr += cSize + 1;1502 c Str -= cSize + 1;1503 } 1504 1505 return atomList;1953 pszStr += cbSize + 1; 1954 cbStr -= cbSize + 1; 1955 } 1956 1957 return lstAtom; 1506 1958 } 1507 1959 … … 1509 1961 Atom DragInstance::toX11Action(uint32_t uAction) 1510 1962 { 1511 /* Ignore is None */1963 /* Ignore is None. */ 1512 1964 return (isDnDCopyAction(uAction) ? xAtom(XA_XdndActionCopy) : 1513 1965 isDnDMoveAction(uAction) ? xAtom(XA_XdndActionMove) : … … 1534 1986 { 1535 1987 uint32_t uAction = DND_IGNORE_ACTION; 1988 1536 1989 if (atom == xAtom(XA_XdndActionCopy)) 1537 1990 uAction = DND_COPY_ACTION; … … 1540 1993 else if (atom == xAtom(XA_XdndActionLink)) 1541 1994 uAction = DND_LINK_ACTION; 1995 1542 1996 return uAction; 1543 1997 } … … 1547 2001 { 1548 2002 uint32_t uActions = DND_IGNORE_ACTION; 2003 1549 2004 for (size_t i = 0; i < actionsList.size(); ++i) 1550 2005 uActions |= toHGCMAction(actionsList.at(i)); 2006 1551 2007 return uActions; 1552 2008 } 1553 2009 1554 /******************************************************************************* 1555 * 1556 * DragAndDropService Implementation 1557 * 1558 ******************************************************************************/ 1559 1560 RTCList<RTCString> toStringList(void *pvData, uint32_t cData) 2010 /** @todo Replace by DnDURIList? */ 2011 RTCList<RTCString> toStringList(const void *pvData, uint32_t cbData) 1561 2012 { 1562 2013 if ( !pvData 1563 || !c Data)2014 || !cbData) 1564 2015 return RTCList<RTCString>(); 1565 char *pszStr = (char*)pvData; 1566 uint32_t cStr = cData; 1567 1568 RTCList<RTCString> strList; 1569 while (cStr > 0) 1570 { 1571 size_t cSize = RTStrNLen(pszStr, cStr); 2016 2017 const char *pszStr = (char*)pvData; 2018 uint32_t cbStr = cbData; 2019 2020 RTCList<RTCString> lstString; 2021 while (cbStr > 0) 2022 { 2023 size_t cbSize = RTStrNLen(pszStr, cbStr); 2024 1572 2025 /* Create a copy with max N chars, so that we are on the save side, 1573 2026 * even if the data isn't zero terminated. */ 1574 char *pszTmp = RTStrDupN(pszStr, c Size);1575 strList.append(pszTmp);2027 char *pszTmp = RTStrDupN(pszStr, cbSize); 2028 lstString.append(pszTmp); 1576 2029 RTStrFree(pszTmp); 1577 pszStr += cSize + 1; 1578 cStr -= cSize + 1; 1579 } 1580 1581 return strList; 1582 } 1583 1584 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 1585 1586 bool DragAndDropService::waitForXMsg(XEvent &ecm, int type, uint32_t uiMaxMS /* = 100 */) 1587 { 1588 const uint64_t uiStart = RTTimeProgramMilliTS(); 2030 pszStr += cbSize + 1; 2031 cbStr -= cbSize + 1; 2032 } 2033 2034 return lstString; 2035 } 2036 2037 /** @todo Is this function really needed? */ 2038 void DragAndDropService::clearEventQueue(void) 2039 { 2040 LogFlowThisFuncEnter(); 2041 m_eventQueue.clear(); 2042 } 2043 2044 /******************************************************************************* 2045 * DragAndDropService implementation. 2046 ******************************************************************************/ 2047 2048 int DragAndDropService::run(bool fDaemonised /* = false */) 2049 { 2050 LogFlowThisFunc(("fDaemonised=%RTbool\n", fDaemonised)); 2051 2052 int rc; 1589 2053 do 1590 2054 { 1591 if (!m_eventQueue.isEmpty()) 1592 { 1593 LogFlowThisFunc(("new msg size %d\n", m_eventQueue.size())); 1594 /* Check if there is a client message in the queue. */ 1595 for (size_t i = 0; i < m_eventQueue.size(); ++i) 1596 { 1597 DnDEvent e = m_eventQueue.at(i); 1598 if( e.type == DnDEvent::X11_Type) 1599 LogFlowThisFunc(("new msg\n")); 1600 if( e.type == DnDEvent::X11_Type 1601 && e.x11.type == type) 1602 { 1603 m_eventQueue.removeAt(i); 1604 ecm = e.x11; 1605 return true; 1606 } 1607 } 1608 } 1609 int rc = RTSemEventWait(m_hEventSem, 25); 1610 // if (RT_FAILURE(rc)) 1611 // return false; 1612 } 1613 while (RTTimeProgramMilliTS() - uiStart < uiMaxMS); 1614 1615 return false; 1616 } 1617 1618 #endif 1619 1620 void DragAndDropService::clearEventQueue() 1621 { 1622 m_eventQueue.clear(); 1623 } 1624 1625 int DragAndDropService::run(bool fDaemonised /* = false */) 1626 { 1627 int rc = VINF_SUCCESS; 1628 LogRelFlowFunc(("\n")); 1629 1630 do 1631 { 1632 /* Initialize X11 DND */ 2055 /* Initialize X11 DnD. */ 1633 2056 rc = x11DragAndDropInit(); 1634 2057 if (RT_FAILURE(rc)) … … 1641 2064 break; 1642 2065 } 2066 1643 2067 /* Note: For multiple screen support in VBox it is not necessary to use 1644 2068 * another screen number than zero. Maybe in the future it will become … … 1648 2072 break; 1649 2073 1650 /* Loop over new events */ 2074 LogRel(("DnD: Started\n")); 2075 2076 /* Enter the main event processing loop. */ 1651 2077 do 1652 2078 { 1653 2079 DnDEvent e; 1654 2080 RT_ZERO(e); 1655 if (m_eventQueue.isEmpty()) 1656 rc = RTSemEventWait(m_hEventSem, RT_INDEFINITE_WAIT); 1657 if (!m_eventQueue.isEmpty()) 2081 2082 LogFlowFunc(("Waiting for new event ...\n")); 2083 rc = RTSemEventWait(m_hEventSem, RT_INDEFINITE_WAIT); 2084 if (RT_FAILURE(rc)) 2085 break; 2086 2087 AssertMsg(m_eventQueue.size(), 2088 ("Event queue is empty when it shouldn't\n")); 2089 2090 e = m_eventQueue.first(); 2091 m_eventQueue.removeFirst(); 2092 2093 if (e.type == DnDEvent::HGCM_Type) 1658 2094 { 1659 e = m_eventQueue.first(); 1660 m_eventQueue.removeFirst(); 1661 LogFlowThisFunc(("new msg %d\n", e.type)); 1662 if (e.type == DnDEvent::HGCM_Type) 2095 LogFlowThisFunc(("HGCM event, type=%RU32\n", e.hgcm.uType)); 2096 switch (e.hgcm.uType) 1663 2097 { 1664 switch (e.hgcm.uType)2098 case DragAndDropSvc::HOST_DND_HG_EVT_ENTER: 1665 2099 { 1666 case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:2100 if (e.hgcm.cbFormats) 1667 2101 { 1668 RTCList<RTCString> formats = RTCString(e.hgcm.pszFormats, e.hgcm.cbFormats - 1).split("\r\n"); 1669 m_pCurDnD->hgEnter(formats, e.hgcm.u.a.uAllActions); 2102 RTCList<RTCString> lstFormats 2103 = RTCString(e.hgcm.pszFormats, e.hgcm.cbFormats - 1).split("\r\n"); 2104 m_pCurDnD->hgEnter(lstFormats, e.hgcm.u.a.uAllActions); 2105 1670 2106 /* Enter is always followed by a move event. */ 1671 2107 } 1672 case DragAndDropSvc::HOST_DND_HG_EVT_MOVE: 1673 { 1674 m_pCurDnD->hgMove(e.hgcm.u.a.uXpos, e.hgcm.u.a.uYpos, e.hgcm.u.a.uDefAction); 2108 else /* Invalid parameter, skip. */ 1675 2109 break; 1676 } 1677 case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE: 1678 { 1679 m_pCurDnD->reset(); 1680 /* Not sure if this is really right! */ 1681 clearEventQueue(); 1682 break; 1683 } 1684 case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED: 1685 { 1686 m_pCurDnD->hgDrop(); 1687 break; 1688 } 1689 case DragAndDropSvc::HOST_DND_HG_SND_DATA: 1690 { 1691 m_pCurDnD->hgDataReceived(e.hgcm.u.b.pvData, e.hgcm.u.b.cbData); 1692 break; 1693 } 2110 /* Not breaking unconditionally is intentional. See comment above. */ 2111 } 2112 case DragAndDropSvc::HOST_DND_HG_EVT_MOVE: 2113 { 2114 m_pCurDnD->hgMove(e.hgcm.u.a.uXpos, e.hgcm.u.a.uYpos, 2115 e.hgcm.u.a.uDefAction); 2116 break; 2117 } 2118 case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE: 2119 { 2120 m_pCurDnD->reset(); 2121 break; 2122 } 2123 case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED: 2124 { 2125 m_pCurDnD->hgDrop(); 2126 break; 2127 } 2128 case DragAndDropSvc::HOST_DND_HG_SND_DATA: 2129 { 2130 m_pCurDnD->hgDataReceived(e.hgcm.u.b.pvData, e.hgcm.u.b.cbData); 2131 break; 2132 } 2133 case DragAndDropSvc::HOST_DND_GH_REQ_PENDING: 2134 { 1694 2135 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 1695 case DragAndDropSvc::HOST_DND_GH_REQ_PENDING: 1696 { 1697 m_pCurDnD->ghIsDnDPending(); 1698 break; 1699 } 1700 case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED: 1701 { 1702 m_pCurDnD->ghDropped(e.hgcm.pszFormats, e.hgcm.u.a.uDefAction); 1703 /* Not sure if this is really right! */ 1704 clearEventQueue(); 1705 break; 1706 } 2136 m_pCurDnD->ghIsDnDPending(); 1707 2137 #endif 1708 default: 1709 LogFlowThisFunc(("Unknown message: %RU32\n", e.hgcm.uType)); 1710 break; 2138 break; 1711 2139 } 1712 1713 /* Some messages require cleanup. */ 1714 switch (e.hgcm.uType) 2140 case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED: 1715 2141 { 1716 case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:1717 case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:1718 case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:1719 2142 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 1720 case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED: 2143 m_pCurDnD->ghDropped(e.hgcm.pszFormats, 2144 e.hgcm.u.a.uDefAction); 1721 2145 #endif 1722 { 1723 if (e.hgcm.pszFormats) 1724 RTMemFree(e.hgcm.pszFormats); 1725 break; 1726 } 1727 case DragAndDropSvc::HOST_DND_HG_SND_DATA: 1728 { 1729 if (e.hgcm.pszFormats) 1730 RTMemFree(e.hgcm.pszFormats); 1731 if (e.hgcm.u.b.pvData) 1732 RTMemFree(e.hgcm.u.b.pvData); 1733 break; 1734 } 1735 default: 1736 break; 2146 break; 1737 2147 } 2148 2149 default: 2150 LogFlowThisFunc(("Unknown message: %RU32\n", e.hgcm.uType)); 2151 break; 1738 2152 } 1739 else if(e.type == DnDEvent::X11_Type) 2153 2154 /* Some messages require cleanup. */ 2155 switch (e.hgcm.uType) 1740 2156 { 1741 LogFlowThisFunc(("X11 type: %u\n", e.x11.type)); 1742 /* Now the X11 event stuff */ 1743 switch (e.x11.type) 2157 case DragAndDropSvc::HOST_DND_HG_EVT_ENTER: 2158 case DragAndDropSvc::HOST_DND_HG_EVT_MOVE: 2159 case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED: 2160 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 2161 case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED: 2162 #endif 1744 2163 { 1745 case SelectionRequest: m_pCurDnD->hgX11SelectionRequest(e.x11); break; 1746 case ClientMessage: m_pCurDnD->hgX11ClientMessage(e.x11); break; 1747 case SelectionClear: LogFlowThisFunc(("DnD_CLER\n")); break; 1748 // case MotionNotify: m_pCurDnD->hide(); break; 2164 if (e.hgcm.pszFormats) 2165 RTMemFree(e.hgcm.pszFormats); 2166 break; 1749 2167 } 2168 2169 case DragAndDropSvc::HOST_DND_HG_SND_DATA: 2170 { 2171 if (e.hgcm.pszFormats) 2172 RTMemFree(e.hgcm.pszFormats); 2173 if (e.hgcm.u.b.pvData) 2174 RTMemFree(e.hgcm.u.b.pvData); 2175 break; 2176 } 2177 2178 default: 2179 break; 1750 2180 } 1751 2181 } 2182 else if (e.type == DnDEvent::X11_Type) 2183 { 2184 m_pCurDnD->onX11Event(e.x11); 2185 } 2186 else 2187 AssertMsgFailed(("Unknown event queue type %d\n", e.type)); 2188 1752 2189 /* Make sure that any X11 requests have actually been sent to the 1753 2190 * server, since we are waiting for responses using poll() on 1754 2191 * another thread which will not automatically trigger flushing. */ 1755 2192 XFlush(m_pDisplay); 1756 } while (1); 2193 2194 } while (!ASMAtomicReadBool(&m_fSrvStopping)); 2195 1757 2196 } while (0); 1758 2197 1759 Log FlowFuncLeaveRC(rc);2198 LogRel(("DnD: Stopped with rc=%Rrc\n", rc)); 1760 2199 return rc; 1761 2200 } … … 1766 2205 m_pDisplay = XOpenDisplay(NULL); 1767 2206 if (!m_pDisplay) 1768 /* todo: correct errors*/2207 /** @todo Correct errors. */ 1769 2208 return VERR_NOT_FOUND; 1770 2209 … … 1776 2215 do 1777 2216 { 1778 /* Signal a new event to our main loop. */1779 2217 rc = RTSemEventCreate(&m_hEventSem); 1780 2218 if (RT_FAILURE(rc)) 1781 2219 break; 2220 2221 rc = RTCritSectInit(&m_eventQueueCS); 2222 if (RT_FAILURE(rc)) 2223 break; 2224 1782 2225 /* Event thread for events coming from the HGCM device. */ 1783 2226 rc = RTThreadCreate(&m_hHGCMThread, hgcmEventThread, this, … … 1786 2229 if (RT_FAILURE(rc)) 1787 2230 break; 2231 1788 2232 /* Event thread for events coming from the x11 system. */ 1789 2233 rc = RTThreadCreate(&m_hX11Thread, x11EventThread, this, … … 1794 2238 /* No clean-up code for now, as we have no good way of testing it and things 1795 2239 * should get cleaned up when the user process/X11 client exits. */ 2240 if (RT_FAILURE(rc)) 2241 LogRel(("DnD: Failed to start, rc=%Rrc\n", rc)); 1796 2242 1797 2243 return rc; … … 1803 2249 AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER); 1804 2250 DragAndDropService *pThis = static_cast<DragAndDropService*>(pvUser); 1805 DnDEvent e;2251 AssertPtr(pThis); 1806 2252 1807 2253 uint32_t uClientID; 1808 2254 int rc = VbglR3DnDConnect(&uClientID); 1809 if (RT_FAILURE(rc)) { 1810 LogFlowFunc(("Unable to connect to HGCM service, rc=%Rrc\n", rc)); 2255 if (RT_FAILURE(rc)) 2256 { 2257 LogRel(("DnD: Unable to connect to drag'n drop service, rc=%Rrc\n", rc)); 1811 2258 return rc; 1812 2259 } … … 1814 2261 /* Number of invalid messages skipped in a row. */ 1815 2262 int cMsgSkippedInvalid = 0; 2263 DnDEvent e; 1816 2264 1817 2265 do … … 1819 2267 RT_ZERO(e); 1820 2268 e.type = DnDEvent::HGCM_Type; 1821 /* Wait for new events */ 2269 2270 /* Wait for new events. */ 1822 2271 rc = VbglR3DnDProcessNextMessage(uClientID, &e.hgcm); 1823 2272 if (RT_SUCCESS(rc)) … … 1825 2274 cMsgSkippedInvalid = 0; /* Reset skipped messages count. */ 1826 2275 2276 LogFlowFunc(("Adding new HGCM event ...\n")); 1827 2277 pThis->m_eventQueue.append(e); 2278 1828 2279 rc = RTSemEventSignal(pThis->m_hEventSem); 1829 2280 if (RT_FAILURE(rc)) 1830 return rc;2281 break; 1831 2282 } 1832 2283 else … … 1839 2290 if (cMsgSkippedInvalid > 3) 1840 2291 { 1841 Log FlowFunc(("Too many invalid/skipped messages from host, exiting ...\n"));2292 LogRel(("DnD: Too many invalid/skipped messages from host, exiting ...\n")); 1842 2293 break; 1843 2294 } 1844 2295 } 1845 2296 1846 } while ( 1);2297 } while (!ASMAtomicReadBool(&pThis->m_fSrvStopping)); 1847 2298 1848 2299 VbglR3DnDDisconnect(uClientID); 1849 2300 1850 return VINF_SUCCESS; 2301 LogFlowFuncLeaveRC(rc); 2302 return rc; 1851 2303 } 1852 2304 … … 1856 2308 AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER); 1857 2309 DragAndDropService *pThis = static_cast<DragAndDropService*>(pvUser); 2310 AssertPtr(pThis); 2311 2312 int rc = VINF_SUCCESS; 2313 1858 2314 DnDEvent e; 1859 2315 do 1860 2316 { 1861 /* Wait for new events. We can't use XIfEvent here, because this locks 2317 /* 2318 * Wait for new events. We can't use XIfEvent here, cause this locks 1862 2319 * the window connection with a mutex and if no X11 events occurs this 1863 * blocks any other calls we made to X11. So instead poll for new events1864 * on the connection file descriptor. */1865 /** @todo Make sure the locking is right - Xlib displays should never be1866 * used from two threads at once. */2320 * blocks any other calls we made to X11. So instead check for new 2321 * events and if there are not any new one, sleep for a certain amount 2322 * of time. 2323 */ 1867 2324 if (XEventsQueued(pThis->m_pDisplay, QueuedAfterFlush) > 0) 1868 2325 { 1869 2326 RT_ZERO(e); 1870 2327 e.type = DnDEvent::X11_Type; 2328 2329 /* XNextEvent will block until a new X event becomes available. */ 1871 2330 XNextEvent(pThis->m_pDisplay, &e.x11); 1872 { 1873 /* Appending makes a copy of the event structure. */ 1874 pThis->m_eventQueue.append(e); 1875 int rc = RTSemEventSignal(pThis->m_hEventSem); 1876 if (RT_FAILURE(rc)) 1877 return rc; 2331 { 2332 #ifdef DEBUG 2333 switch (e.x11.type) 2334 { 2335 case ClientMessage: 2336 { 2337 XClientMessageEvent *pEvent = reinterpret_cast<XClientMessageEvent*>(&e); 2338 AssertPtr(pEvent); 2339 2340 RTCString strType = xAtomToString(pEvent->message_type); 2341 LogFlowFunc(("ClientMessage: %s (%RU32), serial=%RU32, wnd=%#x\n", strType.c_str(), 2342 pEvent->message_type, pEvent->serial, pEvent->window)); 2343 2344 if (pEvent->message_type == xAtom(XA_XdndPosition)) 2345 { 2346 int32_t dwPos = pEvent->data.l[2]; 2347 int32_t dwAction = pEvent->data.l[4]; 2348 2349 LogFlowFunc(("XA_XdndPosition x=%RI32, y=%RI32, dwAction=%RI32\n", 2350 RT_HIWORD(dwPos), RT_LOWORD(dwPos), dwAction)); 2351 } 2352 else if (pEvent->message_type == xAtom(XA_XdndDrop)) 2353 { 2354 LogFlowFunc(("XA_XdndDrop\n")); 2355 } 2356 2357 break; 2358 } 2359 2360 default: 2361 LogFlowFunc(("Received X event type=%d\n", e.x11.type)); 2362 break; 2363 } 2364 #endif 2365 LogFlowFunc(("Adding new X11 event ...\n")); 2366 2367 /* At the moment we only have one drag instance. */ 2368 DragInstance *pInstance = pThis->m_pCurDnD; 2369 2370 AssertPtr(pInstance); 2371 pInstance->onX11Event(e.x11); 1878 2372 } 1879 2373 } 1880 2374 else 1881 { 1882 struct pollfd pollFD; 1883 1884 pollFD.fd = ConnectionNumber(pThis->m_pDisplay); 1885 pollFD.events = POLLIN | POLLPRI; 1886 if ( (poll(&pollFD, 1, -1) < 0 && errno != EINTR) 1887 || pollFD.revents & POLLNVAL) 1888 { 1889 LogRel(("X11 event thread: poll failed, stopping.\n")); 1890 /** @todo Just stop the whole service. What use is it just 1891 * to stop one thread? */ 1892 return RTErrConvertFromErrno(errno); 1893 } 1894 } 1895 } while (1); 1896 1897 return VINF_SUCCESS; 2375 RTThreadSleep(25 /* ms */); 2376 2377 } while (!ASMAtomicReadBool(&pThis->m_fSrvStopping)); 2378 2379 LogFlowFuncLeaveRC(rc); 2380 return rc; 1898 2381 } 1899 2382
Note:
See TracChangeset
for help on using the changeset viewer.