VirtualBox

Changeset 50724 in vbox for trunk/src/VBox/Additions/x11


Ignore:
Timestamp:
Mar 7, 2014 10:54:59 AM (11 years ago)
Author:
vboxsync
Message:

DnD: Implemented guest->host drag'n drop for X11-based guests.

Location:
trunk/src/VBox/Additions/x11/VBoxClient
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/x11/VBoxClient/Makefile.kmk

    r50570 r50724  
    4848        Xrandr \
    4949        Xt
    50 #       Xtst
     50
     51ifdef 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
     57endif
     58
    5159# These are static replacements for gcc-specific parts of libstdc++
    5260VBoxClient_LIBS += \
  • trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp

    r50643 r50724  
    44
    55/*
    6  * Copyright (C) 2011-2013 Oracle Corporation
     6 * Copyright (C) 2011-2014 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1515 */
    1616
    17 #include <errno.h>
    18 #include <poll.h>
    19 
    2017#include <X11/Xlib.h>
    2118#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>
    2425#include <iprt/thread.h>
    25 #include <iprt/asm.h>
    2626#include <iprt/time.h>
    2727
     
    3131#include <limits.h>
    3232
     33# ifdef LOG_GROUP
     34 # undef LOG_GROUP
     35# endif
     36#define LOG_GROUP LOG_GROUP_GUEST_DND
    3337#include <VBox/log.h>
    3438#include <VBox/VBoxGuestLib.h>
     
    3741
    3842#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
    3949
    4050/* For X11 guest xDnD is used. See http://www.acc.umu.se/~vatten/XDND.html for
     
    6272 * and some mouse event is triggered. This should be followed by an XdndEnter
    6373 * 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.
    6575 * On a drop request from the host, we query for the selection and should get
    6676 * the data in the specified mime-type. This data is send back to the host.
     
    308318        int tmp;
    309319        unsigned int utmp;
     320
    310321        /* Query the next child window of the parent window at the current
    311322         * mouse position. */
    312323        XQueryPointer(m_pDisplay, wndParent, &wndTemp, &wndChild, &tmp, &tmp, &tmp, &tmp, &utmp);
     324
    313325        /* Recursive call our self to dive into the child tree. */
    314326        wndApp = applicationWindowBelowCursor(wndChild);
     
    330342{
    331343public:
     344
    332345    enum State
    333346    {
    334         Uninitialized,
     347        Uninitialized = 0,
    335348        Initialized,
    336349        Dragging,
     
    340353    enum Mode
    341354    {
    342         Unknown,
     355        Unknown = 0,
    343356        HG,
    344357        GH
     
    346359
    347360    DragInstance(Display *pDisplay, DragAndDropService *pParent);
     361
     362public:
     363
    348364    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);
    351375
    352376    /* H->G */
    353377    int  hgEnter(const RTCList<RTCString> &formats, uint32_t actions);
    354378    int  hgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t action);
    355     int  hgX11ClientMessage(const XEvent& e);
    356379    int  hgDrop();
    357     int  hgX11SelectionRequest(const XEvent& e);
    358380    int  hgDataReceived(void *pvData, uint32_t cData);
    359381
     
    364386#endif
    365387
    366     /* X11 helpers */
    367     int  moveCursor(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;
    371393    void registerForEvents(Window w) const;
    372394
    373     void setActionsWindowProperty(Window win, const RTCList<Atom> &actionList) const;
    374     void clearActionsWindowProperty(Window win) const;
    375     void setFormatsWindowProperty(Window win, Atom property) const;
    376     void clearFormatsWindowProperty(Window win) const;
    377 
    378     RTCList<Atom>        toAtomList(const RTCList<RTCString> &formatList) const;
    379     RTCList<Atom>        toAtomList(void *pvData, uint32_t cData) 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;
    380402    static Atom          toX11Action(uint32_t uAction);
    381403    static RTCList<Atom> toX11Actions(uint32_t uActions);
     
    383405    static uint32_t      toHGCMActions(const RTCList<Atom> &actionsList);
    384406
    385     /* Member vars */
     407protected:
     408
    386409    uint32_t            m_uClientID;
    387410    DragAndDropService *m_pParent;
     
    395418    RTCList<Atom>       m_formats;
    396419    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. */
    400424    Mode                m_mode;
     425    /** Current state of operation mode. */
    401426    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;
    402435
    403436    static const RTCList<RTCString> m_sstrStringMimeTypes;
     
    419452      , m_hEventSem(NIL_RTSEMEVENT)
    420453      , m_pCurDnD(0)
     454      , m_fSrvStopping(false)
    421455    {}
    422456
    423457    virtual const char *getPidFilePath() { return ".vboxclient-draganddrop.pid"; }
    424458
    425     /** @todo Move this part in VbglR3 and just provide a callback for the platform-specific
    426               notification stuff, since this is very similar to the VBoxTray code. */
    427459    virtual int run(bool fDaemonised = false);
    428460
     
    438470    static int x11EventThread(RTTHREAD hThread, void *pvUser);
    439471
    440     bool waitForXMsg(XEvent &ecm, int type, uint32_t uiMaxMS = 100);
    441472    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.
    443475     * Unfortunately this doesn't work exactly with the events we need. So we
    444476     * use this predicate method below and XCheckIfEvent. */
     
    462494    Display             *m_pDisplay;
    463495
    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;
    465502    RTTHREAD             m_hHGCMThread;
    466503    RTTHREAD             m_hX11Thread;
    467504    RTSEMEVENT           m_hEventSem;
    468505    DragInstance        *m_pCurDnD;
     506    bool                 m_fSrvStopping;
    469507
    470508    friend class DragInstance;
     
    514552{
    515553    /* Hide the proxy win. */
    516     hideProxyWin();
     554    proxyWinHide();
     555
    517556    /* If we are currently the Xdnd selection owner, clear that. */
    518557    Window w = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection));
    519558    if (w == m_wndProxy)
    520559        XSetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection), None, CurrentTime);
     560
    521561    /* Clear any other DnD specific data on the proxy win. */
    522562    clearFormatsWindowProperty(m_wndProxy);
    523563    clearActionsWindowProperty(m_wndProxy);
     564
    524565    /* Reset the internal state. */
     566    m_actions.clear();
    525567    m_formats.clear();
    526568    m_wndCur = 0;
     
    529571}
    530572
     573/** @todo Move this into VBox/GuestHost ? */
    531574const RTCList<RTCString> DragInstance::m_sstrStringMimeTypes = RTCList<RTCString>()
    532575    /* Uri's */
     
    552595
    553596        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);
    554605        if (RT_FAILURE(rc))
    555606            break;
     
    586637        XSetWindowAttributes attr;
    587638        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;
    589642        attr.override_redirect     = True;
    590 #if 0
     643#ifdef VBOX_DND_DEBUG_WND
    591644        attr.background_pixel      = WhitePixel(m_pDisplay, m_screenId);
    592645#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 */);
    602655        if (!m_wndProxy)
    603656        {
     
    605658            break;
    606659        }
     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");
    607666
    608667        /* Make the new window Xdnd aware. */
     
    613672
    614673    if (RT_SUCCESS(rc))
     674    {
    615675        m_state = Initialized;
     676    }
     677    else
     678        LogRel(("DnD: Initializing drag instance for screen %RU32 failed with rc=%Rrc\n",
     679                u32ScreenId, rc));
    616680
    617681    LogFlowFuncLeaveRC(rc);
    618682    return rc;
    619683}
     684
     685int 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
     767int 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
     803int 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
     931int 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
     969bool 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
     1020bool 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 */
    6201071
    6211072/*
     
    6651116
    6661117    /* Move the mouse cursor within the guest. */
    667     moveCursor(u32xPos, u32yPos);
     1118    mouseCursorMove(u32xPos, u32yPos);
    6681119
    6691120    long newVer = -1; /* This means the current window is _not_ XdndAware. */
     
    7931244}
    7941245
    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 XdndAware
    802      * 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 DnD
    808          * event and with which action. We immediately send this info down to
    809          * 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     else
    833         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 
    8401246int DragInstance::hgDrop(void)
    8411247{
     
    8731279}
    8741280
    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 copied
    895      * into the selection buffer and send to the requestor. Obviously we can't
    896      * do that, cause we first need to ask the host for the data of the
    897      * requested mime type. This is done and later answered with the correct
    898      * 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 requestor
    907          * 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 the
    931          * 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         else
    952         {
    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     else
    961     {
    962         LogFlowThisFunc(("Refusing unknown command\n"));
    963 
    964         /* We don't understand this request message and therefore answer with an
    965          * 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 
    9841281int DragInstance::hgDataReceived(void *pvData, uint32_t cData)
    9851282{
     
    10041301     * The host send us the DnD data in the requested mime type. This allows us
    10051302     * to fill the XdndSelection property of the requestor window with the data
    1006      * and afterwards inform him about the new status.
     1303     * and afterwards inform the host about the new status.
    10071304     */
    10081305    XEvent s;
    10091306    RT_ZERO(s);
    10101307    s.xselection.type      = SelectionNotify;
    1011     s.xselection.display   = m_selEvent.xselection.display;
     1308    s.xselection.display   = m_eventHgSelection.xselection.display;
    10121309//    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,
    10211318                     s.xselection.requestor,
    10221319                     xAtomToString(s.xselection.selection).c_str(),
     
    10391336{
    10401337    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
    10481347        /* Map the window on the current cursor position, which should provoke
    10491348         * an XdndEnter event. */
    1050         int rx, ry;
    1051         showProxyWin(rx, ry);
     1349        proxyWinShow();
     1350
    10521351        XEvent e;
    1053         if (m_pParent->waitForXMsg(e, ClientMessage))
     1352        if (waitForX11Msg(e, ClientMessage))
    10541353        {
    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))
    10591362            {
    10601363                Atom type = None;
     
    10621365                unsigned long n, a;
    10631366                unsigned char *ret = 0;
     1367
    10641368                reset();
    10651369
    1066                 m_formats.clear();
    1067                 m_actions.clear();
    1068                 m_wndCur = wndOwner;
     1370                m_state = Dragging;
     1371                m_wndCur = wndSelection;
     1372
    10691373                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
    10711381                 * to fetch the XdndTypeList property from the window. */
    1072                 if (!ASMBitTest(&clme->data.l[1], 0))
     1382                if (!ASMBitTest(&pEventClient->data.l[1], 0))
    10731383                {
    10741384                    for (int i = 2; i < 5; ++i)
    10751385                    {
    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]);
    10781390                    }
    10791391                }
    10801392                else
    10811393                {
    1082                     xrc = XGetWindowProperty(m_pDisplay, wndOwner,
     1394                    xRc = XGetWindowProperty(m_pDisplay, wndSelection,
    10831395                                             xAtom(XA_XdndTypeList),
    10841396                                             0, VBOX_MAX_XPROPERTIES,
    10851397                                             False, XA_ATOM, &type, &f, &n, &a, &ret);
    1086                     if (   xrc == Success
     1398                    if (   xRc == Success
    10871399                        && n > 0
    10881400                        && ret)
     
    10911403                        for (int i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, n); ++i)
    10921404                        {
    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
    10941408                            m_formats.append(data[i]);
    10951409                        }
     1410
    10961411                        XFree(ret);
    10971412                    }
     
    10991414
    11001415                /* Fetch the possible list of actions, if this property is set. */
    1101                 xrc = XGetWindowProperty(m_pDisplay, wndOwner,
     1416                xRc = XGetWindowProperty(m_pDisplay, wndSelection,
    11021417                                         xAtom(XA_XdndActionList),
    11031418                                         0, VBOX_MAX_XPROPERTIES,
    11041419                                         False, XA_ATOM, &type, &f, &n, &a, &ret);
    1105                 if (   xrc == Success
     1420                if (   xRc == Success
    11061421                    && n > 0
    11071422                    && ret)
     
    11101425                    for (int i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, n); ++i)
    11111426                    {
    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
    11131430                        m_actions.append(data[i]);
    11141431                    }
     
    11161433                    XFree(ret);
    11171434                }
    1118 
    1119                 m_state = Dragging;
    1120                 m_mode  = GH;
    11211435
    11221436                /* Acknowledge the event by sending a Status msg back to the
     
    11241438                XClientMessageEvent m;
    11251439                RT_ZERO(m);
     1440
    11261441                m.type         = ClientMessage;
    11271442                m.display      = m_pDisplay;
    1128                 m.window       = clme->data.l[0];
     1443                m.window       = pEventClient->data.l[0];
    11291444                m.message_type = xAtom(XA_XdndStatus);
    11301445                m.format       = 32;
     
    11321447                m.data.l[1]    = 1;
    11331448                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"));
    11371454            }
    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))
    11391457            {
    11401458                LogFlowThisFunc(("XA_XdndPosition\n"));
     1459
     1460                /* Reply with a XdndStatus message to tell the source whether
     1461                 * the data can be dropped or not. */
    11411462                XClientMessageEvent m;
    11421463                RT_ZERO(m);
    11431464                m.type         = ClientMessage;
    11441465                m.display      = m_pDisplay;
    1145                 m.window       = clme->data.l[0];
     1466                m.window       = pEventClient->data.l[0];
    11461467                m.message_type = xAtom(XA_XdndStatus);
    11471468                m.format       = 32;
    11481469                m.data.l[0]    = m_wndProxy;
    11491470                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"));
    11541477            }
    1155             else if (clme->message_type == xAtom(XA_XdndLeave))
     1478            else if (pEventClient->message_type == xAtom(XA_XdndLeave))
    11561479            {
     1480                LogFlowThisFunc(("XA_XdndLeave\n"));
    11571481            }
    11581482        }
    11591483
    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        }
    11641497    }
    11651498
     
    11751508    int rc = VINF_SUCCESS;
    11761509
     1510    m_state = Dropped;
     1511
    11771512    /* 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);
    11801515    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
    11811526
    11821527    /* We send a fake release event to the current window, cause
    11831528     * 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))
    11981555        {
    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)
    12001562            {
    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)
    12311585                {
    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')
    12471594                    {
    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)
    12541597                        {
    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);
    12691604                        }
    12701605                        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;
    12931607                    }
    12941608                    else
    12951609                    {
    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);
    13241613                    }
    13251614
    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"));
    13291633                }
    13301634                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);
    13321669            }
    13331670            else
    1334                 rc = VERR_TIMEOUT;
     1671                rc = VERR_INVALID_PARAMETER;
    13351672        }
    13361673        else
    1337             rc = VERR_WRONG_ORDER;
     1674            rc = VERR_TIMEOUT;
    13381675    }
    13391676    else
     
    13421679    /* Inform the host on error. */
    13431680    if (RT_FAILURE(rc))
    1344         VbglR3DnDGHSendError(m_uClientID, rc);
     1681    {
     1682        int rc2 = VbglR3DnDGHSendError(m_uClientID, rc);
     1683        AssertRC(rc2);
     1684    }
    13451685
    13461686    /* 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. */
    13481688    reset();
    13491689
     
    13571697 */
    13581698
    1359 int DragInstance::moveCursor(uint32_t u32xPos, uint32_t u32yPos)
    1360 {
     1699int DragInstance::mouseCursorMove(int iPosX, int iPosY) const
     1700{
     1701    LogFlowThisFunc(("iPosX=%d, iPosY=%d\n", iPosX, iPosY));
     1702
    13611703    /* Move the guest pointer to the DnD position, so we can find the window
    13621704     * 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);
    13641706    return VINF_SUCCESS;
    13651707}
    13661708
    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));
     1709void 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);
    13931751        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
     1807int 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
    14031821//    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
    14061837    XMapWindow(m_pDisplay, m_wndProxy);
    14071838    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 */);
    14111845//    XTestGrabControl(m_pDisplay, True);
    1412 }
    1413 
    1414 void DragInstance::hideProxyWin(void) const
    1415 {
     1846
     1847    return VINF_SUCCESS; /** @todo Add error checking. */
     1848}
     1849
     1850int DragInstance::proxyWinHide(void) const
     1851{
     1852    LogFlowThisFuncEnter();
     1853    return 0;
     1854
    14161855    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? */
    14201862void DragInstance::registerForEvents(Window wndThis) const
    14211863{
    1422 //    if (w == m_proxyWin)
    1423 //        return;
     1864    if (wndThis == m_wndProxy)
     1865        return;
    14241866
    14251867    LogFlowThisFunc(("%x\n", wndThis));
     
    14381880}
    14391881
    1440 void DragInstance::setActionsWindowProperty(Window wndThis, const RTCList<Atom> &actionList) const
    1441 {
    1442     if (actionList.isEmpty())
     1882void DragInstance::setActionsWindowProperty(Window wndThis,
     1883                                            const RTCList<Atom> &lstActions) const
     1884{
     1885    if (lstActions.isEmpty())
    14431886        return;
    14441887
    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());
    14471893}
    14481894
     
    14521898}
    14531899
    1454 void DragInstance::setFormatsWindowProperty(Window wndThis, Atom property) const
     1900void DragInstance::setFormatsWindowProperty(Window wndThis,
     1901                                            Atom property) const
    14551902{
    14561903    if (m_formats.isEmpty())
     
    14631910
    14641911    /* 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());
    14671916}
    14681917
    14691918void DragInstance::clearFormatsWindowProperty(Window wndThis) const
    14701919{
    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
     1924RTCList<Atom> DragInstance::toAtomList(const RTCList<RTCString> &lstFormats) const
    14751925{
    14761926    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));
    14791929
    14801930    return atomList;
    14811931}
    14821932
    1483 RTCList<Atom> DragInstance::toAtomList(void *pvData, uint32_t cData) const
     1933RTCList<Atom> DragInstance::toAtomList(void *pvData, uint32_t cbData) const
    14841934{
    14851935    if (   !pvData
    1486         || !cData)
     1936        || !cbData)
    14871937        return RTCList<Atom>();
     1938
    14881939    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
    14951947        /* Create a copy with max N chars, so that we are on the save side,
    14961948         * even if the data isn't zero terminated. */
    1497         char *pszTmp = RTStrDupN(pszStr, cSize);
     1949        char *pszTmp = RTStrDupN(pszStr, cbSize);
    14981950        LogFlowThisFunc(("f: %s\n", pszTmp));
    1499         atomList.append(XInternAtom(m_pDisplay, pszTmp, False));
     1951        lstAtom.append(XInternAtom(m_pDisplay, pszTmp, False));
    15001952        RTStrFree(pszTmp);
    1501         pszStr += cSize + 1;
    1502         cStr   -= cSize + 1;
    1503     }
    1504 
    1505     return atomList;
     1953        pszStr  += cbSize + 1;
     1954        cbStr   -= cbSize + 1;
     1955    }
     1956
     1957    return lstAtom;
    15061958}
    15071959
     
    15091961Atom DragInstance::toX11Action(uint32_t uAction)
    15101962{
    1511     /* Ignore is None */
     1963    /* Ignore is None. */
    15121964    return (isDnDCopyAction(uAction) ? xAtom(XA_XdndActionCopy) :
    15131965            isDnDMoveAction(uAction) ? xAtom(XA_XdndActionMove) :
     
    15341986{
    15351987    uint32_t uAction = DND_IGNORE_ACTION;
     1988
    15361989    if (atom == xAtom(XA_XdndActionCopy))
    15371990        uAction = DND_COPY_ACTION;
     
    15401993    else if (atom == xAtom(XA_XdndActionLink))
    15411994        uAction = DND_LINK_ACTION;
     1995
    15421996    return uAction;
    15431997}
     
    15472001{
    15482002    uint32_t uActions = DND_IGNORE_ACTION;
     2003
    15492004    for (size_t i = 0; i < actionsList.size(); ++i)
    15502005        uActions |= toHGCMAction(actionsList.at(i));
     2006
    15512007    return uActions;
    15522008}
    15532009
    1554 /*******************************************************************************
    1555  *
    1556  * DragAndDropService Implementation
    1557  *
    1558  ******************************************************************************/
    1559 
    1560 RTCList<RTCString> toStringList(void *pvData, uint32_t cData)
     2010/** @todo Replace by DnDURIList?  */
     2011RTCList<RTCString> toStringList(const void *pvData, uint32_t cbData)
    15612012{
    15622013    if (   !pvData
    1563         || !cData)
     2014        || !cbData)
    15642015        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
    15722025        /* Create a copy with max N chars, so that we are on the save side,
    15732026         * even if the data isn't zero terminated. */
    1574         char *pszTmp = RTStrDupN(pszStr, cSize);
    1575         strList.append(pszTmp);
     2027        char *pszTmp = RTStrDupN(pszStr, cbSize);
     2028        lstString.append(pszTmp);
    15762029        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?  */
     2038void DragAndDropService::clearEventQueue(void)
     2039{
     2040    LogFlowThisFuncEnter();
     2041    m_eventQueue.clear();
     2042}
     2043
     2044/*******************************************************************************
     2045 * DragAndDropService implementation.
     2046 ******************************************************************************/
     2047
     2048int DragAndDropService::run(bool fDaemonised /* = false */)
     2049{
     2050    LogFlowThisFunc(("fDaemonised=%RTbool\n", fDaemonised));
     2051
     2052    int rc;
    15892053    do
    15902054    {
    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. */
    16332056        rc = x11DragAndDropInit();
    16342057        if (RT_FAILURE(rc))
     
    16412064            break;
    16422065        }
     2066
    16432067        /* Note: For multiple screen support in VBox it is not necessary to use
    16442068         * another screen number than zero. Maybe in the future it will become
     
    16482072            break;
    16492073
    1650         /* Loop over new events */
     2074        LogRel(("DnD: Started\n"));
     2075
     2076        /* Enter the main event processing loop. */
    16512077        do
    16522078        {
    16532079            DnDEvent e;
    16542080            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)
    16582094            {
    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)
    16632097                {
    1664                     switch (e.hgcm.uType)
     2098                    case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
    16652099                    {
    1666                         case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
     2100                        if (e.hgcm.cbFormats)
    16672101                        {
    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
    16702106                            /* Enter is always followed by a move event. */
    16712107                        }
    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. */
    16752109                            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                    {
    16942135#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();
    17072137#endif
    1708                         default:
    1709                             LogFlowThisFunc(("Unknown message: %RU32\n", e.hgcm.uType));
    1710                             break;
     2138                        break;
    17112139                    }
    1712 
    1713                     /* Some messages require cleanup. */
    1714                     switch (e.hgcm.uType)
     2140                    case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
    17152141                    {
    1716                         case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
    1717                         case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
    1718                         case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
    17192142#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);
    17212145#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;
    17372147                    }
     2148
     2149                    default:
     2150                        LogFlowThisFunc(("Unknown message: %RU32\n", e.hgcm.uType));
     2151                        break;
    17382152                }
    1739                 else if(e.type == DnDEvent::X11_Type)
     2153
     2154                /* Some messages require cleanup. */
     2155                switch (e.hgcm.uType)
    17402156                {
    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
    17442163                    {
    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;
    17492167                    }
     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;
    17502180                }
    17512181            }
     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
    17522189            /* Make sure that any X11 requests have actually been sent to the
    17532190             * server, since we are waiting for responses using poll() on
    17542191             * another thread which will not automatically trigger flushing. */
    17552192            XFlush(m_pDisplay);
    1756         } while (1);
     2193
     2194        } while (!ASMAtomicReadBool(&m_fSrvStopping));
     2195
    17572196    } while (0);
    17582197
    1759     LogFlowFuncLeaveRC(rc);
     2198    LogRel(("DnD: Stopped with rc=%Rrc\n", rc));
    17602199    return rc;
    17612200}
     
    17662205    m_pDisplay = XOpenDisplay(NULL);
    17672206    if (!m_pDisplay)
    1768         /* todo: correct errors */
     2207        /** @todo Correct errors. */
    17692208        return VERR_NOT_FOUND;
    17702209
     
    17762215    do
    17772216    {
    1778         /* Signal a new event to our main loop. */
    17792217        rc = RTSemEventCreate(&m_hEventSem);
    17802218        if (RT_FAILURE(rc))
    17812219            break;
     2220
     2221        rc = RTCritSectInit(&m_eventQueueCS);
     2222        if (RT_FAILURE(rc))
     2223            break;
     2224
    17822225        /* Event thread for events coming from the HGCM device. */
    17832226        rc = RTThreadCreate(&m_hHGCMThread, hgcmEventThread, this,
     
    17862229        if (RT_FAILURE(rc))
    17872230            break;
     2231
    17882232        /* Event thread for events coming from the x11 system. */
    17892233        rc = RTThreadCreate(&m_hX11Thread, x11EventThread, this,
     
    17942238    /* No clean-up code for now, as we have no good way of testing it and things
    17952239     * 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));
    17962242
    17972243    return rc;
     
    18032249    AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
    18042250    DragAndDropService *pThis = static_cast<DragAndDropService*>(pvUser);
    1805     DnDEvent e;
     2251    AssertPtr(pThis);
    18062252
    18072253    uint32_t uClientID;
    18082254    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));
    18112258        return rc;
    18122259    }
     
    18142261    /* Number of invalid messages skipped in a row. */
    18152262    int cMsgSkippedInvalid = 0;
     2263    DnDEvent e;
    18162264
    18172265    do
     
    18192267        RT_ZERO(e);
    18202268        e.type = DnDEvent::HGCM_Type;
    1821         /* Wait for new events */
     2269
     2270        /* Wait for new events. */
    18222271        rc = VbglR3DnDProcessNextMessage(uClientID, &e.hgcm);
    18232272        if (RT_SUCCESS(rc))
     
    18252274            cMsgSkippedInvalid = 0; /* Reset skipped messages count. */
    18262275
     2276            LogFlowFunc(("Adding new HGCM event ...\n"));
    18272277            pThis->m_eventQueue.append(e);
     2278
    18282279            rc = RTSemEventSignal(pThis->m_hEventSem);
    18292280            if (RT_FAILURE(rc))
    1830                 return rc;
     2281                break;
    18312282        }
    18322283        else
     
    18392290            if (cMsgSkippedInvalid > 3)
    18402291            {
    1841                 LogFlowFunc(("Too many invalid/skipped messages from host, exiting ...\n"));
     2292                LogRel(("DnD: Too many invalid/skipped messages from host, exiting ...\n"));
    18422293                break;
    18432294            }
    18442295        }
    18452296
    1846     } while (1);
     2297    } while (!ASMAtomicReadBool(&pThis->m_fSrvStopping));
    18472298
    18482299    VbglR3DnDDisconnect(uClientID);
    18492300
    1850     return VINF_SUCCESS;
     2301    LogFlowFuncLeaveRC(rc);
     2302    return rc;
    18512303}
    18522304
     
    18562308    AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
    18572309    DragAndDropService *pThis = static_cast<DragAndDropService*>(pvUser);
     2310    AssertPtr(pThis);
     2311
     2312    int rc = VINF_SUCCESS;
     2313
    18582314    DnDEvent e;
    18592315    do
    18602316    {
    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
    18622319         * 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 events
    1864          * on the connection file descriptor. */
    1865         /** @todo Make sure the locking is right - Xlib displays should never be
    1866          * 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         */
    18672324        if (XEventsQueued(pThis->m_pDisplay, QueuedAfterFlush) > 0)
    18682325        {
    18692326            RT_ZERO(e);
    18702327            e.type = DnDEvent::X11_Type;
     2328
     2329            /* XNextEvent will block until a new X event becomes available. */
    18712330            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);
    18782372            }
    18792373        }
    18802374        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;
    18982381}
    18992382
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette