Index: trunk/src/VBox/Additions/x11/VBoxClient/Makefile.kmk
===================================================================
--- trunk/src/VBox/Additions/x11/VBoxClient/Makefile.kmk	(revision 50714)
+++ trunk/src/VBox/Additions/x11/VBoxClient/Makefile.kmk	(revision 50724)
@@ -48,5 +48,13 @@
 	Xrandr \
 	Xt
-#	Xtst
+
+ifdef VBOX_WITH_DRAG_AND_DROP
+ ifdef VBOX_DND_WITH_XTEST
+ VBoxClient_DEFS += VBOX_DND_WITH_XTEST
+ VBoxClient_LIBS += \
+	Xtst
+ endif
+endif
+
 # These are static replacements for gcc-specific parts of libstdc++
 VBoxClient_LIBS += \
Index: trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp
===================================================================
--- trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp	(revision 50714)
+++ trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp	(revision 50724)
@@ -4,5 +4,5 @@
 
 /*
- * Copyright (C) 2011-2013 Oracle Corporation
+ * Copyright (C) 2011-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -15,13 +15,13 @@
  */
 
-#include <errno.h>
-#include <poll.h>
-
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>
-//#include <X11/extensions/XTest.h>
-
+#ifdef VBOX_DND_WITH_XTEST
+# include <X11/extensions/XTest.h>
+#endif
+
+#include <iprt/asm.h>
+#include <iprt/critsect.h>
 #include <iprt/thread.h>
-#include <iprt/asm.h>
 #include <iprt/time.h>
 
@@ -31,4 +31,8 @@
 #include <limits.h>
 
+# ifdef LOG_GROUP
+ # undef LOG_GROUP
+# endif
+#define LOG_GROUP LOG_GROUP_GUEST_DND
 #include <VBox/log.h>
 #include <VBox/VBoxGuestLib.h>
@@ -37,4 +41,10 @@
 
 #include "VBoxClient.h"
+
+/* Enable this define to see the proxy window(s) when debugging
+ * their behavior. Don't have this enabled in release builds! */
+#ifdef DEBUG
+# define VBOX_DND_DEBUG_WND
+#endif
 
 /* For X11 guest xDnD is used. See http://www.acc.umu.se/~vatten/XDND.html for
@@ -62,5 +72,5 @@
  * and some mouse event is triggered. This should be followed by an XdndEnter
  * event send to the proxy window. From this event we can fetch the necessary
- * info of the mime-types and allowed actions and send this back to the host.
+ * info of the MIME types and allowed actions and send this back to the host.
  * On a drop request from the host, we query for the selection and should get
  * the data in the specified mime-type. This data is send back to the host.
@@ -308,7 +318,9 @@
         int tmp;
         unsigned int utmp;
+
         /* Query the next child window of the parent window at the current
          * mouse position. */
         XQueryPointer(m_pDisplay, wndParent, &wndTemp, &wndChild, &tmp, &tmp, &tmp, &tmp, &utmp);
+
         /* Recursive call our self to dive into the child tree. */
         wndApp = applicationWindowBelowCursor(wndChild);
@@ -330,7 +342,8 @@
 {
 public:
+
     enum State
     {
-        Uninitialized,
+        Uninitialized = 0,
         Initialized,
         Dragging,
@@ -340,5 +353,5 @@
     enum Mode
     {
-        Unknown,
+        Unknown = 0,
         HG,
         GH
@@ -346,14 +359,23 @@
 
     DragInstance(Display *pDisplay, DragAndDropService *pParent);
+
+public:
+
     int  init(uint32_t u32ScreenId);
-    void uninit();
-    void reset();
+    void uninit(void);
+    void reset(void);
+
+    /* X11 message processing. */
+    int onX11ClientMessage(const XEvent &e);    
+    int onX11SelectionNotify(const XEvent &e);
+    int onX11SelectionRequest(const XEvent &e);
+    int onX11Event(const XEvent &e);
+    bool waitForX11Msg(XEvent &evX, int iType, RTMSINTERVAL uTimeoutMS = 100);
+    bool waitForX11ClientMsg(XClientMessageEvent &evMsg, Atom aType, RTMSINTERVAL uTimeoutMS = 100);
 
     /* H->G */
     int  hgEnter(const RTCList<RTCString> &formats, uint32_t actions);
     int  hgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t action);
-    int  hgX11ClientMessage(const XEvent& e);
     int  hgDrop();
-    int  hgX11SelectionRequest(const XEvent& e);
     int  hgDataReceived(void *pvData, uint32_t cData);
 
@@ -364,18 +386,18 @@
 #endif
 
-    /* X11 helpers */
-    int  moveCursor(uint32_t u32xPos, uint32_t u32yPos);
-    void sendButtonEvent(Window w, int rx, int ry, int button, bool fPress) const;
-    void showProxyWin(int &rx, int &ry) const;
-    void hideProxyWin() const;
+    /* X11 helpers. */
+    int  mouseCursorMove(int iPosX, int iPosY) const;
+    void mouseButtonSet(Window wndDest, int rx, int ry, int iButton, bool fPress) const;
+    int proxyWinShow(int *piRootX = NULL, int *piRootY = NULL, bool fMouseMove = false) const;
+    int proxyWinHide(void) const;
     void registerForEvents(Window w) const;
 
-    void setActionsWindowProperty(Window win, const RTCList<Atom> &actionList) const;
-    void clearActionsWindowProperty(Window win) const;
-    void setFormatsWindowProperty(Window win, Atom property) const;
-    void clearFormatsWindowProperty(Window win) const;
-
-    RTCList<Atom>        toAtomList(const RTCList<RTCString> &formatList) const;
-    RTCList<Atom>        toAtomList(void *pvData, uint32_t cData) const;
+    void setActionsWindowProperty(Window wndThis, const RTCList<Atom> &lstActions) const;
+    void clearActionsWindowProperty(Window wndThis) const;
+    void setFormatsWindowProperty(Window wndThis, Atom property) const;
+    void clearFormatsWindowProperty(Window wndThis) const;
+
+    RTCList<Atom>        toAtomList(const RTCList<RTCString> &lstFormats) const;
+    RTCList<Atom>        toAtomList(void *pvData, uint32_t cbData) const;
     static Atom          toX11Action(uint32_t uAction);
     static RTCList<Atom> toX11Actions(uint32_t uActions);
@@ -383,5 +405,6 @@
     static uint32_t      toHGCMActions(const RTCList<Atom> &actionsList);
 
-    /* Member vars */
+protected:
+
     uint32_t            m_uClientID;
     DragAndDropService *m_pParent;
@@ -395,9 +418,19 @@
     RTCList<Atom>       m_formats;
     RTCList<Atom>       m_actions;
-
-    XEvent              m_selEvent;
-
+    /** Deferred host to guest selection event for sending to the
+     *  target window as soon as data from the host arrived. */
+    XEvent              m_eventHgSelection;
+    /** Current operation mode. */
     Mode                m_mode;
+    /** Current state of operation mode. */
     State               m_state;
+    /** The instance's own X event queue. */
+    RTCMTList<XEvent>   m_eventQueue;
+    /** Critical section for providing serialized access to list
+     *  event queue's contents. */
+    RTCRITSECT          m_eventQueueCS;
+    /** Event for notifying this instance in case of a new
+     *  event. */
+    RTSEMEVENT          m_hEventSem;
 
     static const RTCList<RTCString> m_sstrStringMimeTypes;
@@ -419,10 +452,9 @@
       , m_hEventSem(NIL_RTSEMEVENT)
       , m_pCurDnD(0)
+      , m_fSrvStopping(false)
     {}
 
     virtual const char *getPidFilePath() { return ".vboxclient-draganddrop.pid"; }
 
-    /** @todo Move this part in VbglR3 and just provide a callback for the platform-specific
-              notification stuff, since this is very similar to the VBoxTray code. */
     virtual int run(bool fDaemonised = false);
 
@@ -438,7 +470,7 @@
     static int x11EventThread(RTTHREAD hThread, void *pvUser);
 
-    bool waitForXMsg(XEvent &ecm, int type, uint32_t uiMaxMS = 100);
     void clearEventQueue();
-    /* Usually XCheckMaskEvent could be used for queering selected x11 events.
+
+    /* Usually XCheckMaskEvent could be used for querying selected x11 events.
      * Unfortunately this doesn't work exactly with the events we need. So we
      * use this predicate method below and XCheckIfEvent. */
@@ -462,9 +494,15 @@
     Display             *m_pDisplay;
 
-    RTCMTList<DnDEvent>  m_eventQueue;
+    /** Our (thread-safe) event queue with
+     *  mixed events (DnD HGCM / X11). */
+    RTCMTList<DnDEvent>    m_eventQueue;
+    /** Critical section for providing serialized access to list
+     *  event queue's contents. */
+    RTCRITSECT           m_eventQueueCS;
     RTTHREAD             m_hHGCMThread;
     RTTHREAD             m_hX11Thread;
     RTSEMEVENT           m_hEventSem;
     DragInstance        *m_pCurDnD;
+    bool                 m_fSrvStopping;
 
     friend class DragInstance;
@@ -514,13 +552,17 @@
 {
     /* Hide the proxy win. */
-    hideProxyWin();
+    proxyWinHide();
+
     /* If we are currently the Xdnd selection owner, clear that. */
     Window w = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection));
     if (w == m_wndProxy)
         XSetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection), None, CurrentTime);
+
     /* Clear any other DnD specific data on the proxy win. */
     clearFormatsWindowProperty(m_wndProxy);
     clearActionsWindowProperty(m_wndProxy);
+
     /* Reset the internal state. */
+    m_actions.clear();
     m_formats.clear();
     m_wndCur = 0;
@@ -529,4 +571,5 @@
 }
 
+/** @todo Move this into VBox/GuestHost ? */
 const RTCList<RTCString> DragInstance::m_sstrStringMimeTypes = RTCList<RTCString>()
     /* Uri's */
@@ -552,4 +595,12 @@
 
         rc = VbglR3DnDConnect(&m_uClientID);
+        if (RT_FAILURE(rc))
+            break;
+
+        rc = RTSemEventCreate(&m_hEventSem);
+        if (RT_FAILURE(rc))
+            break;
+
+        rc = RTCritSectInit(&m_eventQueueCS);
         if (RT_FAILURE(rc))
             break;
@@ -586,18 +637,20 @@
         XSetWindowAttributes attr;
         RT_ZERO(attr);
-        attr.do_not_propagate_mask = 0;
+        attr.event_mask            =   EnterWindowMask  | LeaveWindowMask 
+                                     | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
+        attr.do_not_propagate_mask = NoEventMask;
         attr.override_redirect     = True;
-#if 0
+#ifdef VBOX_DND_DEBUG_WND
         attr.background_pixel      = WhitePixel(m_pDisplay, m_screenId);
 #endif
-        m_wndProxy = XCreateWindow(m_pDisplay, m_wndRoot, 0, 0, 1, 1, 0,
-                                   CopyFromParent, InputOnly, CopyFromParent,
-                                   CWOverrideRedirect | CWDontPropagate,
-                                   &attr);
-#ifdef DEBUG_andy
-        m_wndProxy = XCreateSimpleWindow(m_pDisplay, m_wndRoot, 0, 0, 50, 50, 0,
-                                         WhitePixel(m_pDisplay, m_screenId),
-                                         WhitePixel(m_pDisplay, m_screenId));
-#endif
+        m_wndProxy = XCreateWindow(m_pDisplay, m_wndRoot                 /* Parent */, 
+                                   0, 0,                                 /* Position */
+                                   1, 1,                                 /* Width + height */
+                                   0,                                    /* Border width */
+                                   CopyFromParent,                       /* Depth */
+                                   InputOnly,                            /* Class */
+                                   CopyFromParent,                       /* Visual */
+                                   CWOverrideRedirect | CWDontPropagate, /* Value mask */
+                                   &attr                                 /* Attributes for value mask */);
         if (!m_wndProxy)
         {
@@ -605,4 +658,10 @@
             break;
         }
+
+        LogFlowThisFunc(("Created proxy window 0x%x at m_wndRoot=0x%x ...\n", 
+                         m_wndProxy, m_wndRoot));
+
+        /* Set the window's name for easier lookup. */
+        XStoreName(m_pDisplay, m_wndProxy, "VBoxClientWndDnD");
 
         /* Make the new window Xdnd aware. */
@@ -613,9 +672,401 @@
 
     if (RT_SUCCESS(rc))
+    {
         m_state = Initialized;
+    }
+    else
+        LogRel(("DnD: Initializing drag instance for screen %RU32 failed with rc=%Rrc\n", 
+                u32ScreenId, rc));
 
     LogFlowFuncLeaveRC(rc);
     return rc;
 }
+
+int DragInstance::onX11ClientMessage(const XEvent &e)
+{
+    AssertReturn(e.type == ClientMessage, VERR_INVALID_PARAMETER);
+
+    LogFlowThisFunc(("m_mode=%d, m_state=%d\n", m_mode, m_state));
+    LogFlowThisFunc(("Event wnd=%#x, msg=%s\n",
+                     e.xclient.window,
+                     xAtomToString(e.xclient.message_type).c_str()));
+    int rc;
+
+    switch (m_mode)
+    {
+        case HG:
+        {
+            /* Client messages are used to inform us about the status of a XdndAware
+             * window, in response of some events we send to them. */
+            if (   e.xclient.message_type == xAtom(XA_XdndStatus)
+                && m_wndCur               == static_cast<Window>(e.xclient.data.l[0]))
+            {
+                /* The XdndStatus message tell us if the window will accept the DnD
+                 * event and with which action. We immediately send this info down to
+                 * the host as a response of a previous DnD message. */
+                LogFlowThisFunc(("XA_XdndStatus wnd=%#x, accept=%RTbool, action=%s\n",
+                                 e.xclient.data.l[0],
+                                 ASMBitTest(&e.xclient.data.l[1], 0),
+                                 xAtomToString(e.xclient.data.l[4]).c_str()));
+
+                uint32_t uAction = DND_IGNORE_ACTION;
+                /** @todo Compare this with the allowed actions. */
+                if (ASMBitTest(&e.xclient.data.l[1], 0))
+                    uAction = toHGCMAction(static_cast<Atom>(e.xclient.data.l[4]));
+
+                rc = VbglR3DnDHGAcknowledgeOperation(m_uClientID, uAction);
+            }
+            else if (e.xclient.message_type == xAtom(XA_XdndFinished))
+            {
+                rc = VINF_SUCCESS;
+
+                /* This message is send on a un/successful DnD drop request. */
+                LogFlowThisFunc(("XA_XdndFinished: wnd=%#x, success=%RTbool, action=%s\n",
+                                 e.xclient.data.l[0],
+                                 ASMBitTest(&e.xclient.data.l[1], 0),
+                                 xAtomToString(e.xclient.data.l[2]).c_str()));
+                reset();
+            }
+            else
+            {
+                LogFlowThisFunc(("Unhandled: wnd=%#x, msg=%s\n",
+                                 e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str()));
+                rc = VERR_NOT_SUPPORTED;
+            }
+
+            break;
+        }
+
+        case GH:
+        {
+            //if (m_state == Dropped) 
+            //{
+                LogFlowThisFunc(("Enqueuing ClientMessage\n"));
+
+                m_eventQueue.append(e);
+                rc = RTSemEventSignal(m_hEventSem);
+            //}
+
+            //rc = VINF_SUCCESS;
+            break;
+        }
+
+        default:
+        {
+            LogFlowThisFunc(("Unhandled: wnd=%#x, msg=%s\n",
+                             e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str()));
+            rc = VERR_INVALID_STATE;
+            break;
+        }
+    }
+
+    LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
+    return rc;
+}
+
+int DragInstance::onX11SelectionNotify(const XEvent &e)
+{
+    AssertReturn(e.type == SelectionNotify, VERR_INVALID_PARAMETER);
+
+    LogFlowThisFunc(("m_mode=%d, m_state=%d\n", m_mode, m_state));
+
+    int rc;
+
+    switch (m_mode)
+    {
+        case GH:
+        {
+            if (m_state == Dropped)
+            {
+                LogFlowThisFunc(("Enqueuing SelectionNotify\n"));
+
+                m_eventQueue.append(e);
+                rc = RTSemEventSignal(m_hEventSem);
+            }
+            break;
+        }
+
+        default:
+        {
+            LogFlowThisFunc(("Unhandled: wnd=%#x, msg=%s\n",
+                             e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str()));
+            rc = VERR_INVALID_STATE;
+            break;
+        }
+    }
+
+    LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
+    return rc;
+}
+
+
+int DragInstance::onX11SelectionRequest(const XEvent &e)
+{
+    AssertReturn(e.type == SelectionRequest, VERR_INVALID_PARAMETER);
+
+    LogFlowThisFunc(("m_mode=%d, m_state=%d\n", m_mode, m_state));
+    LogFlowThisFunc(("Event owner=%#x, requestor=%#x, selection=%s, target=%s, prop=%s, time=%u\n",
+                     e.xselectionrequest.owner,
+                     e.xselectionrequest.requestor,
+                     xAtomToString(e.xselectionrequest.selection).c_str(),
+                     xAtomToString(e.xselectionrequest.target).c_str(),
+                     xAtomToString(e.xselectionrequest.property).c_str(),
+                     e.xselectionrequest.time));
+    int rc;
+
+    switch (m_mode)
+    {
+        case HG:
+        {
+            rc = VINF_SUCCESS;
+
+            /*
+             * A window is asking for some data. Normally here the data would be copied
+             * into the selection buffer and send to the requestor. Obviously we can't
+             * do that, because we first need to ask the host for the data of the
+             * requested MIME type. This is done and later answered with the correct
+             * data -- see DragInstance::hgDataReceived().
+             */
+
+            /* Is the requestor asking for the possible MIME types? */
+            if (e.xselectionrequest.target == xAtom(XA_TARGETS))
+            {
+                LogFlowThisFunc(("wnd=%#x asking for target list\n", e.xselectionrequest.requestor));
+
+                /* If so, set the window property with the formats on the requestor
+                 * window. */
+                setFormatsWindowProperty(e.xselectionrequest.requestor, e.xselectionrequest.property);
+
+                XEvent s;
+                RT_ZERO(s);
+                s.xselection.type      = SelectionNotify;
+                s.xselection.display   = e.xselection.display;
+                s.xselection.time      = e.xselectionrequest.time;
+                s.xselection.selection = e.xselectionrequest.selection;
+                s.xselection.requestor = e.xselectionrequest.requestor;
+                s.xselection.target    = e.xselectionrequest.target;
+                s.xselection.property  = e.xselectionrequest.property;
+
+                int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);
+                if (RT_UNLIKELY(xrc == 0))
+                    LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor));
+            }
+            /* Is the requestor asking for a specific MIME type (we support)? */
+            else if (m_formats.contains(e.xselectionrequest.target))
+            {
+                LogFlowThisFunc(("wnd=%#x asking for data, format=%s\n",
+                                 e.xselectionrequest.requestor, xAtomToString(e.xselectionrequest.target).c_str()));
+
+                /* If so, we need to inform the host about this request. Save the
+                 * selection request event for later use. */
+                if (   m_state != Dropped)
+                    //        || m_curWin != e.xselectionrequest.requestor)
+                {
+                    LogFlowThisFunc(("Wrong state, refusing request\n"));
+
+                    XEvent s;
+                    RT_ZERO(s);
+                    s.xselection.type      = SelectionNotify;
+                    s.xselection.display   = e.xselection.display;
+                    s.xselection.time      = e.xselectionrequest.time;
+                    s.xselection.selection = e.xselectionrequest.selection;
+                    s.xselection.requestor = e.xselectionrequest.requestor;
+                    s.xselection.target    = None;
+                    s.xselection.property  = e.xselectionrequest.property;
+
+                    int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);
+                    if (RT_UNLIKELY(xrc == 0))
+                        LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor));
+                }
+                else
+                {
+                    LogFlowThisFunc(("Saving selection notify message\n"));
+
+                    memcpy(&m_eventHgSelection, &e, sizeof(XEvent));
+
+                    const char *pcszFormat = xAtomToString(e.xselectionrequest.target).c_str();
+                    AssertPtr(pcszFormat);
+                    rc = VbglR3DnDHGRequestData(m_uClientID, pcszFormat);
+                    LogFlowThisFunc(("Requesting data from host as \"%s\", rc=%Rrc\n", 
+                                     pcszFormat, rc));
+                }
+            }
+            /* Anything else. */
+            else
+            {
+                LogFlowThisFunc(("Refusing unknown command\n"));
+
+                /* We don't understand this request message and therefore answer with an
+                 * refusal messages. */
+                XEvent s;
+                RT_ZERO(s);
+                s.xselection.type      = SelectionNotify;
+                s.xselection.display   = e.xselection.display;
+                s.xselection.time      = e.xselectionrequest.time;
+                s.xselection.selection = e.xselectionrequest.selection;
+                s.xselection.requestor = e.xselectionrequest.requestor;
+                s.xselection.target    = None; /* default is refusing */
+                s.xselection.property  = None; /* default is refusing */
+                int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);
+                if (RT_UNLIKELY(xrc == 0))
+                    LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor));
+            }
+
+            break;
+        }
+
+        default:
+        {
+            LogFlowThisFunc(("Unhandled: wnd=%#x, msg=%s\n",
+                             e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str()));
+            rc = VERR_INVALID_STATE;
+            break;
+        }
+    }
+
+    LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
+    return rc;
+}
+
+int DragInstance::onX11Event(const XEvent &e)
+{
+    int rc;
+
+    LogFlowThisFunc(("X11 event, type=%d\n", e.type));
+    switch (e.type)
+    {
+        case SelectionNotify:
+            rc = onX11SelectionNotify(e); 
+            break;
+
+        case SelectionRequest: 
+            rc = onX11SelectionRequest(e); 
+            break;
+
+        case ClientMessage:    
+            rc = onX11ClientMessage(e); 
+            break;
+
+        case SelectionClear:
+           LogFlowThisFunc(("SelectionClear\n")); 
+           rc = VINF_SUCCESS;
+           break;
+
+        /*case MotionNotify: 
+          hide();
+          break;*/
+
+        default:
+            rc = VERR_NOT_IMPLEMENTED;
+            break;
+    }
+
+    LogFlowThisFunc(("rc=%Rrc\n", rc));
+    return rc;
+}
+
+#ifdef VBOX_WITH_DRAG_AND_DROP_GH
+bool DragInstance::waitForX11Msg(XEvent &evX, int iType, 
+                                 RTMSINTERVAL uTimeoutMS /* = 100 */)
+{
+    LogFlowThisFunc(("iType=%d, uTimeoutMS=%RU32, cEventQueue=%zu\n", 
+                     iType, uTimeoutMS, m_eventQueue.size()));
+
+    bool fFound = false;
+    const uint64_t uiStart = RTTimeMilliTS();
+    do
+    {
+        /* Check if there is a client message in the queue. */
+        for (size_t i = 0; i < m_eventQueue.size(); i++)
+        {
+            int rc2 = RTCritSectEnter(&m_eventQueueCS);
+            if (RT_SUCCESS(rc2))
+            {
+                XEvent e = m_eventQueue.at(i);
+
+                fFound = e.type == iType;
+                if (fFound)
+                {
+                    m_eventQueue.removeAt(i);
+                    evX = e;
+                }
+
+                rc2 = RTCritSectLeave(&m_eventQueueCS);
+                AssertRC(rc2);
+
+                if (fFound)
+                    break;
+            }
+        }
+
+        if (fFound)
+            break;
+
+        int rc2 = RTSemEventWait(m_hEventSem, 25 /* ms */);
+        if (   RT_FAILURE(rc2)
+            && rc2 != VERR_TIMEOUT)
+        {
+            LogFlowFunc(("Waiting failed with rc=%Rrc\n", rc2));
+            break;
+        }
+    }
+    while (RTTimeMilliTS() - uiStart < uTimeoutMS);
+
+    LogFlowThisFunc(("Returning fFound=%RTbool, msRuntime=%RU64\n", 
+                     fFound, RTTimeMilliTS() - uiStart));
+    return fFound;
+}
+
+bool DragInstance::waitForX11ClientMsg(XClientMessageEvent &evMsg, Atom aType, 
+                                       RTMSINTERVAL uTimeoutMS /*= 100 */)
+{
+    LogFlowThisFunc(("aType=%s, uTimeoutMS=%RU32, cEventQueue=%zu\n", 
+                     xAtomToString(aType).c_str(), uTimeoutMS, m_eventQueue.size()));
+
+    bool fFound = false;
+    const uint64_t uiStart = RTTimeMilliTS();
+    do
+    {
+        /* Check if there is a client message in the queue. */
+        for (size_t i = 0; i < m_eventQueue.size(); i++)
+        {
+            int rc2 = RTCritSectEnter(&m_eventQueueCS);
+            if (RT_SUCCESS(rc2))
+            {
+                XEvent e = m_eventQueue.at(i);                
+                if (e.type == ClientMessage)                    
+                {
+                    m_eventQueue.removeAt(i);
+                    evMsg = e.xclient;
+
+                    fFound = true;
+                }
+
+                rc2 = RTCritSectLeave(&m_eventQueueCS);
+                AssertRC(rc2);
+
+                if (fFound)
+                    break;
+            }
+        }
+
+        if (fFound)
+            break;
+
+        int rc2 = RTSemEventWait(m_hEventSem, 25 /* ms */);
+        if (   RT_FAILURE(rc2)
+            && rc2 != VERR_TIMEOUT)
+        {
+            LogFlowFunc(("Waiting failed with rc=%Rrc\n", rc2));
+            break;
+        }
+    }
+    while (RTTimeMilliTS() - uiStart < uTimeoutMS);
+
+    LogFlowThisFunc(("Returning fFound=%RTbool, msRuntime=%RU64\n", 
+                     fFound, RTTimeMilliTS() - uiStart));
+    return fFound;
+}
+#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
 
 /*
@@ -665,5 +1116,5 @@
 
     /* Move the mouse cursor within the guest. */
-    moveCursor(u32xPos, u32yPos);
+    mouseCursorMove(u32xPos, u32yPos);
 
     long newVer = -1; /* This means the current window is _not_ XdndAware. */
@@ -793,49 +1244,4 @@
 }
 
-int DragInstance::hgX11ClientMessage(const XEvent& e)
-{
-    if (   m_mode  != HG)
-//        || m_state != Dragging)
-        return VERR_INVALID_STATE;
-
-    /* Client messages are used to inform us about the status of a XdndAware
-     * window, in response of some events we send to them. */
-    int rc = VINF_SUCCESS;
-    if (   e.xclient.message_type == xAtom(XA_XdndStatus)
-        && m_wndCur               == static_cast<Window>(e.xclient.data.l[0]))
-    {
-        /* The XdndStatus message tell us if the window will accept the DnD
-         * event and with which action. We immediately send this info down to
-         * the host as a response of a previous DnD message. */
-        LogFlowThisFunc(("XA_XdndStatus wnd=%#x, accept=%RTbool, action='%s'\n",
-                         e.xclient.data.l[0],
-                         ASMBitTest(&e.xclient.data.l[1], 0),
-                         xAtomToString(e.xclient.data.l[4]).c_str()));
-
-        uint32_t uAction = DND_IGNORE_ACTION;
-        /** @todo Compare this with the allowed actions. */
-        if (ASMBitTest(&e.xclient.data.l[1], 0))
-            uAction = toHGCMAction(static_cast<Atom>(e.xclient.data.l[4]));
-
-        rc = VbglR3DnDHGAcknowledgeOperation(m_uClientID, uAction);
-    }
-    else if (e.xclient.message_type == xAtom(XA_XdndFinished))
-    {
-        /* This message is send on a un/successful DnD drop request. */
-        LogFlowThisFunc(("XA_XdndFinished: wnd=%#x, success=%RTbool, action='%s'\n",
-            e.xclient.data.l[0],
-            ASMBitTest(&e.xclient.data.l[1], 0),
-            xAtomToString(e.xclient.data.l[2]).c_str()));
-
-        reset();
-    }
-    else
-        LogFlowThisFunc(("Unhandled: wnd=%#x, msg='%s'\n",
-                         e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str()));
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
 int DragInstance::hgDrop(void)
 {
@@ -873,113 +1279,4 @@
 }
 
-int DragInstance::hgX11SelectionRequest(const XEvent& e)
-{
-    AssertReturn(e.type == SelectionRequest, VERR_INVALID_PARAMETER);
-
-    if (   m_mode  != HG)
-//        || m_state != D)
-        return VERR_INVALID_STATE;
-
-    LogFlowThisFunc(("owner=%#x, requestor=%#x, sel_atom='%s', tar_atom='%s', prop_atom='%s', time=%u\n",
-                     e.xselectionrequest.owner,
-                     e.xselectionrequest.requestor,
-                     xAtomToString(e.xselectionrequest.selection).c_str(),
-                     xAtomToString(e.xselectionrequest.target).c_str(),
-                     xAtomToString(e.xselectionrequest.property).c_str(),
-                     e.xselectionrequest.time));
-
-    int rc = VINF_SUCCESS;
-
-    /*
-     * A window is asking for some data. Normally here the data would be copied
-     * into the selection buffer and send to the requestor. Obviously we can't
-     * do that, cause we first need to ask the host for the data of the
-     * requested mime type. This is done and later answered with the correct
-     * data (s. dataReceived).
-     */
-
-    /* Is the requestor asking for the possible mime types? */
-    if(e.xselectionrequest.target == xAtom(XA_TARGETS))
-    {
-        LogFlowThisFunc(("wnd=%#x asking for target list\n", e.xselectionrequest.requestor));
-
-        /* If so, set the window property with the formats on the requestor
-         * window. */
-        setFormatsWindowProperty(e.xselectionrequest.requestor, e.xselectionrequest.property);
-
-        XEvent s;
-        RT_ZERO(s);
-        s.xselection.type      = SelectionNotify;
-        s.xselection.display   = e.xselection.display;
-        s.xselection.time      = e.xselectionrequest.time;
-        s.xselection.selection = e.xselectionrequest.selection;
-        s.xselection.requestor = e.xselectionrequest.requestor;
-        s.xselection.target    = e.xselectionrequest.target;
-        s.xselection.property  = e.xselectionrequest.property;
-
-        int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);
-        if (RT_UNLIKELY(xrc == 0))
-            LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor));
-    }
-    /* Is the requestor asking for a specific mime type (we support)? */
-    else if(m_formats.contains(e.xselectionrequest.target))
-    {
-        LogFlowThisFunc(("wnd=%#x asking for data (format='%s')\n",
-                         e.xselectionrequest.requestor, xAtomToString(e.xselectionrequest.target).c_str()));
-
-        /* If so, we need to inform the host about this request. Save the
-         * selection request event for later use. */
-        if (   m_state != Dropped)
-            //        || m_curWin != e.xselectionrequest.requestor)
-        {
-            LogFlowThisFunc(("Refusing ...\n"));
-
-            XEvent s;
-            RT_ZERO(s);
-            s.xselection.type      = SelectionNotify;
-            s.xselection.display   = e.xselection.display;
-            s.xselection.time      = e.xselectionrequest.time;
-            s.xselection.selection = e.xselectionrequest.selection;
-            s.xselection.requestor = e.xselectionrequest.requestor;
-            s.xselection.target    = None;
-            s.xselection.property  = e.xselectionrequest.property;
-
-            int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);
-            if (RT_UNLIKELY(xrc == 0))
-                LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor));
-        }
-        else
-        {
-            LogFlowThisFunc(("Copying data from host ...\n"));
-
-            memcpy(&m_selEvent, &e, sizeof(XEvent));
-            rc = VbglR3DnDHGRequestData(m_uClientID, xAtomToString(e.xselectionrequest.target).c_str());
-        }
-    }
-    /* Anything else. */
-    else
-    {
-        LogFlowThisFunc(("Refusing unknown command\n"));
-
-        /* We don't understand this request message and therefore answer with an
-         * refusal messages. */
-        XEvent s;
-        RT_ZERO(s);
-        s.xselection.type      = SelectionNotify;
-        s.xselection.display   = e.xselection.display;
-        s.xselection.time      = e.xselectionrequest.time;
-        s.xselection.selection = e.xselectionrequest.selection;
-        s.xselection.requestor = e.xselectionrequest.requestor;
-        s.xselection.target    = None; /* default is refusing */
-        s.xselection.property  = None; /* default is refusing */
-        int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);
-        if (RT_UNLIKELY(xrc == 0))
-            LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor));
-    }
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
 int DragInstance::hgDataReceived(void *pvData, uint32_t cData)
 {
@@ -1004,19 +1301,19 @@
      * The host send us the DnD data in the requested mime type. This allows us
      * to fill the XdndSelection property of the requestor window with the data
-     * and afterwards inform him about the new status.
+     * and afterwards inform the host about the new status.
      */
     XEvent s;
     RT_ZERO(s);
     s.xselection.type      = SelectionNotify;
-    s.xselection.display   = m_selEvent.xselection.display;
+    s.xselection.display   = m_eventHgSelection.xselection.display;
 //    s.xselection.owner     = m_selEvent.xselectionrequest.owner;
-    s.xselection.time      = m_selEvent.xselectionrequest.time;
-    s.xselection.selection = m_selEvent.xselectionrequest.selection;
-    s.xselection.requestor = m_selEvent.xselectionrequest.requestor;
-    s.xselection.target    = m_selEvent.xselectionrequest.target;
-    s.xselection.property  = m_selEvent.xselectionrequest.property;
-
-    LogFlowThisFunc(("owner=%#x,requestor=%#x,sel_atom='%s',tar_atom='%s',prop_atom='%s',time=%u\n",
-                     m_selEvent.xselectionrequest.owner,
+    s.xselection.time      = m_eventHgSelection.xselectionrequest.time;
+    s.xselection.selection = m_eventHgSelection.xselectionrequest.selection;
+    s.xselection.requestor = m_eventHgSelection.xselectionrequest.requestor;
+    s.xselection.target    = m_eventHgSelection.xselectionrequest.target;
+    s.xselection.property  = m_eventHgSelection.xselectionrequest.property;
+
+    LogFlowThisFunc(("owner=%#x, requestor=%#x, sel_atom=%s, target_atom=%s, prop_atom=%s, time=%u\n",
+                     m_eventHgSelection.xselectionrequest.owner,
                      s.xselection.requestor,
                      xAtomToString(s.xselection.selection).c_str(),
@@ -1039,22 +1336,28 @@
 {
     int rc = VINF_SUCCESS;
-    Window wndOwner = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection));
-    LogFlowThisFunc(("Checking pending wndOwner=%#x wndProxy=%#x\n", wndOwner, m_wndProxy));
-
-    /* Is there someone own the Xdnd selection which aren't we. */
-    if (   wndOwner
-        && wndOwner != m_wndProxy)
-    {
+    Window wndSelection = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection));
+    LogFlowThisFunc(("Checking pending wndSelection=%#x, wndProxy=%#x\n", wndSelection, m_wndProxy));
+
+    /* Is this another window which has a Xdnd selection than our current one? */
+    if (   wndSelection
+        && wndSelection != m_wndProxy)
+    {
+        m_mode  = GH;
+
         /* Map the window on the current cursor position, which should provoke
          * an XdndEnter event. */
-        int rx, ry;
-        showProxyWin(rx, ry);
+        proxyWinShow();
+
         XEvent e;
-        if (m_pParent->waitForXMsg(e, ClientMessage))
+        if (waitForX11Msg(e, ClientMessage))
         {
-            int xrc = Success;
-            XClientMessageEvent *clme = reinterpret_cast<XClientMessageEvent*>(&e);
-            LogFlowThisFunc(("Next X event %s\n", gX11->xAtomToString(clme->message_type).c_str()));
-            if (clme->message_type == xAtom(XA_XdndEnter))
+            int xRc;
+            XClientMessageEvent *pEventClient = reinterpret_cast<XClientMessageEvent*>(&e);
+            AssertPtr(pEventClient);
+
+            LogFlowThisFunc(("Next X event is: %s\n", 
+                             gX11->xAtomToString(pEventClient->message_type).c_str()));
+
+            if (pEventClient->message_type == xAtom(XA_XdndEnter))
             {
                 Atom type = None;
@@ -1062,27 +1365,36 @@
                 unsigned long n, a;
                 unsigned char *ret = 0;
+
                 reset();
 
-                m_formats.clear();
-                m_actions.clear();
-                m_wndCur = wndOwner;
+                m_state = Dragging;
+                m_wndCur = wndSelection;
+
                 LogFlowThisFunc(("XA_XdndEnter\n"));
-                /* Check if the mime types are in the msg itself or if we need
+#ifdef DEBUG
+                XWindowAttributes xwa;
+                XGetWindowAttributes(m_pDisplay, m_wndCur, &xwa);
+                LogFlowThisFunc(("m_wndCur=%#x, x=%d, y=%d, width=%d, height=%d\n", 
+                                 m_wndCur, xwa.x, xwa.y, xwa.width, xwa.height));
+#endif
+                /* Check if the MIME types are in the message itself or if we need
                  * to fetch the XdndTypeList property from the window. */
-                if (!ASMBitTest(&clme->data.l[1], 0))
+                if (!ASMBitTest(&pEventClient->data.l[1], 0))
                 {
                     for (int i = 2; i < 5; ++i)
                     {
-                        LogFlowThisFunc(("Receive list msg: %s\n", gX11->xAtomToString(clme->data.l[i]).c_str()));
-                        m_formats.append(clme->data.l[i]);
+                        LogFlowThisFunc(("Received format via message: %s\n", 
+                                         gX11->xAtomToString(pEventClient->data.l[i]).c_str()));
+
+                        m_formats.append(pEventClient->data.l[i]);
                     }
                 }
                 else
                 {
-                    xrc = XGetWindowProperty(m_pDisplay, wndOwner, 
+                    xRc = XGetWindowProperty(m_pDisplay, wndSelection, 
                                              xAtom(XA_XdndTypeList), 
                                              0, VBOX_MAX_XPROPERTIES, 
                                              False, XA_ATOM, &type, &f, &n, &a, &ret);
-                    if (   xrc == Success
+                    if (   xRc == Success
                         && n > 0
                         && ret)
@@ -1091,7 +1403,10 @@
                         for (int i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, n); ++i)
                         {
-                            LogFlowThisFunc(("Receive list: %s\n", gX11->xAtomToString(data[i]).c_str()));
+                            LogFlowThisFunc(("Received format via XdndTypeList: %s\n", 
+                                             gX11->xAtomToString(data[i]).c_str()));
+
                             m_formats.append(data[i]);
                         }
+
                         XFree(ret);
                     }
@@ -1099,9 +1414,9 @@
 
                 /* Fetch the possible list of actions, if this property is set. */
-                xrc = XGetWindowProperty(m_pDisplay, wndOwner, 
+                xRc = XGetWindowProperty(m_pDisplay, wndSelection, 
                                          xAtom(XA_XdndActionList), 
                                          0, VBOX_MAX_XPROPERTIES, 
                                          False, XA_ATOM, &type, &f, &n, &a, &ret);
-                if (   xrc == Success
+                if (   xRc == Success
                     && n > 0
                     && ret)
@@ -1110,5 +1425,7 @@
                     for (int i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, n); ++i)
                     {
-                        LogFlowThisFunc(("Receive actions: %s\n", gX11->xAtomToString(data[i]).c_str()));
+                        LogFlowThisFunc(("Received action: %s\n", 
+                                         gX11->xAtomToString(data[i]).c_str()));
+
                         m_actions.append(data[i]);
                     }
@@ -1116,7 +1433,4 @@
                     XFree(ret);
                 }
-
-                m_state = Dragging;
-                m_mode  = GH;
 
                 /* Acknowledge the event by sending a Status msg back to the
@@ -1124,7 +1438,8 @@
                 XClientMessageEvent m;
                 RT_ZERO(m);
+
                 m.type         = ClientMessage;
                 m.display      = m_pDisplay;
-                m.window       = clme->data.l[0];
+                m.window       = pEventClient->data.l[0];
                 m.message_type = xAtom(XA_XdndStatus);
                 m.format       = 32;
@@ -1132,34 +1447,52 @@
                 m.data.l[1]    = 1;
                 m.data.l[4]    = xAtom(XA_XdndActionCopy);
-                xrc = XSendEvent(m_pDisplay, clme->data.l[0], False, 0, reinterpret_cast<XEvent*>(&m));
-                if (RT_UNLIKELY(xrc == 0))
-                    LogFlowThisFunc(("Error sending xevent\n"));
+
+                xRc = XSendEvent(m_pDisplay, pEventClient->data.l[0], 
+                                 False, 0, reinterpret_cast<XEvent*>(&m));
+                if (RT_UNLIKELY(xRc == 0))
+                    LogFlowThisFunc(("Error sending xEvent\n"));
             }
-            else if (clme->message_type == xAtom(XA_XdndPosition))
+            /* Did the source tell us where the cursor currently is? */
+            else if (pEventClient->message_type == xAtom(XA_XdndPosition))
             {
                 LogFlowThisFunc(("XA_XdndPosition\n"));
+
+                /* Reply with a XdndStatus message to tell the source whether
+                 * the data can be dropped or not. */
                 XClientMessageEvent m;
                 RT_ZERO(m);
                 m.type         = ClientMessage;
                 m.display      = m_pDisplay;
-                m.window       = clme->data.l[0];
+                m.window       = pEventClient->data.l[0];
                 m.message_type = xAtom(XA_XdndStatus);
                 m.format       = 32;
                 m.data.l[0]    = m_wndProxy;
                 m.data.l[1]    = 1;
-                m.data.l[4]    = clme->data.l[4];
-                xrc = XSendEvent(m_pDisplay, clme->data.l[0], False, 0, reinterpret_cast<XEvent*>(&m));
-                if (RT_UNLIKELY(xrc == 0))
-                    LogFlowThisFunc(("Error sending xevent\n"));
+                m.data.l[4]    = pEventClient->data.l[4];
+
+                xRc = XSendEvent(m_pDisplay, pEventClient->data.l[0], 
+                                 False, 0, reinterpret_cast<XEvent*>(&m));
+                if (RT_UNLIKELY(xRc == 0))
+                    LogFlowThisFunc(("Error sending xEvent\n"));
             }
-            else if (clme->message_type == xAtom(XA_XdndLeave))
+            else if (pEventClient->message_type == xAtom(XA_XdndLeave))
             {
+                LogFlowThisFunc(("XA_XdndLeave\n"));
             }
         }
 
-        hideProxyWin();
-
-        rc = VbglR3DnDGHAcknowledgePending(m_uClientID, DND_COPY_ACTION, toHGCMActions(m_actions),
-                                           gX11->xAtomListToString(m_formats).c_str());
+        proxyWinHide();
+
+        /* Do we need to acknowledge at least one format to the host? */
+        if (!m_formats.isEmpty())
+        {
+            RTCString strFormats = gX11->xAtomListToString(m_formats);
+            uint32_t uDefAction = DND_COPY_ACTION; /** @todo Handle default action! */
+            uint32_t uAllActions = toHGCMActions(m_actions);
+
+            rc = VbglR3DnDGHAcknowledgePending(m_uClientID, uDefAction, uAllActions, strFormats.c_str());
+            LogFlowThisFunc(("Acknowledging m_uClientID=%RU32, allActions=0x%x, strFormats=%s, rc=%Rrc\n", 
+                             m_uClientID, uAllActions, strFormats.c_str(), rc));
+        }
     }
 
@@ -1175,165 +1508,169 @@
     int rc = VINF_SUCCESS;
 
+    m_state = Dropped;
+
     /* Show the proxy window, so that the source will find it. */
-    int rx, ry;
-    showProxyWin(rx, ry);
+    int iRootX, iRootY;
+    proxyWinShow(&iRootX, &iRootY);
     XFlush(m_pDisplay);
+
+#ifdef DEBUG
+    XWindowAttributes xwa;
+    XGetWindowAttributes(m_pDisplay, m_wndCur, &xwa);
+    LogFlowThisFunc(("m_wndCur=%#x, x=%d, y=%d, width=%d, height=%d\n", 
+                     m_wndCur, xwa.x, xwa.y, xwa.width, xwa.height));
+
+    iRootX = xwa.x;
+    iRootY = xwa.y;
+#endif
 
     /* We send a fake release event to the current window, cause
      * this should have the grab. */
-    sendButtonEvent(m_wndCur, rx, ry, 1, false);
-
-    /* The fake button release event, should lead to an XdndDrop event from the
-     * source. Because of the showing of the proxy window, sometimes other Xdnd
-     * events occurs before, like a XdndPosition event. We are not interested
-     * in those, so try to get the right one. */
-    XEvent e;
-    XClientMessageEvent *clme = 0;
-    RT_ZERO(e);
-
-    int cRetries = 3;
-    for (int i = 0; i < cRetries; i++) 
-    {
-        if (m_pParent->waitForXMsg(e, ClientMessage))
+    mouseButtonSet(m_wndCur, iRootX, iRootY, 
+                   1 /* Button */, false /* Release button */);
+
+    /* The fake button release event should lead to a XdndDrop event from the
+     * source. Because of showing our proxy window, other Xdnd events can 
+     * occur before, e.g. a XdndPosition event. We are not interested
+     * in those, so just try to get the right one. */
+
+    XClientMessageEvent evDnDDrop;
+    bool fDrop = waitForX11ClientMsg(evDnDDrop, xAtom(XA_XdndDrop), 
+                                     5 * 1000 /* Timeout in ms */);
+    if (fDrop)
+    {
+        /* Request to convert the selection in the specific format and
+         * place it to our proxy window as property. */
+        Window srcWin = m_wndCur;//clme->data.l[0];
+        Atom aFormat  = gX11->stringToxAtom(strFormat.c_str());
+
+        XConvertSelection(m_pDisplay, xAtom(XA_XdndSelection), 
+                          aFormat, xAtom(XA_XdndSelection), 
+                          m_wndProxy, evDnDDrop.data.l[2]);
+
+        /* Wait for the selection notify event. */
+        XEvent evSelNotify;
+        RT_ZERO(evSelNotify);
+        if (waitForX11Msg(evSelNotify, SelectionNotify))
         {
-            if (reinterpret_cast<XClientMessageEvent*>(&e)->message_type == xAtom(XA_XdndDrop))
+            /* Make some paranoid checks. */
+            if (   evSelNotify.xselection.type      == SelectionNotify
+                && evSelNotify.xselection.display   == m_pDisplay
+                && evSelNotify.xselection.selection == xAtom(XA_XdndSelection)
+                && evSelNotify.xselection.requestor == m_wndProxy
+                && evSelNotify.xselection.target    == aFormat)
             {
-                clme = reinterpret_cast<XClientMessageEvent*>(&e);
-                break;
-            }
-        }
-    }
-
-    if (clme)
-    {
-        /* Make some paranoid checks. */
-        if (clme->message_type == xAtom(XA_XdndDrop))
-        {
-            /* Request to convert the selection in the specific format and
-             * place it to our proxy window as property. */
-            Window srcWin = m_wndCur;//clme->data.l[0];
-            Atom aFormat  = gX11->stringToxAtom(strFormat.c_str());
-
-            XConvertSelection(m_pDisplay, xAtom(XA_XdndSelection), 
-                              aFormat, xAtom(XA_XdndSelection), 
-                              m_wndProxy, clme->data.l[2]);
-
-            /* Wait for the selection notify event. */
-            RT_ZERO(e);
-            if (m_pParent->waitForXMsg(e, SelectionNotify))
-            {
-                /* Make some paranoid checks. */
-                if (   e.xselection.type      == SelectionNotify
-                    && e.xselection.display   == m_pDisplay
-                    && e.xselection.selection == xAtom(XA_XdndSelection)
-                    && e.xselection.requestor == m_wndProxy
-                    && e.xselection.target    == aFormat)
+                LogFlowThisFunc(("Selection notfiy (from wnd=%#x)\n", m_wndCur));
+
+                Atom aPropType;
+                int iPropFormat;
+                unsigned long cItems, cbRemaining;
+                unsigned char *pcData = NULL;
+                XGetWindowProperty(m_pDisplay, m_wndProxy, 
+                                   xAtom(XA_XdndSelection) /* Property */,
+                                   0 /* Offset */,
+                                   VBOX_MAX_XPROPERTIES /* Length of 32-bit multiples */,
+                                   True /* Delete property? */, 
+                                   AnyPropertyType, /* Property type */
+                                   &aPropType, &iPropFormat, &cItems, &cbRemaining, &pcData);
+
+                LogFlowThisFunc(("strType=%s, iPropFormat=%d, cItems=%RU32, cbRemaining=%RU32\n", 
+                                 gX11->xAtomToString(aPropType).c_str(), iPropFormat, cItems, cbRemaining));
+
+                if (   aPropType   != None
+                    && pcData      != NULL
+                    && iPropFormat >= 8
+                    && cItems      >  0
+                    && cbRemaining == 0)
                 {
-                    LogFlowThisFunc(("Selection notfiy (from: %x)\n", m_wndCur));
-
-                    Atom type;
-                    int format;
-                    unsigned long cItems, cbRemaining;
-                    unsigned char *ucData = 0;
-                    XGetWindowProperty(m_pDisplay, m_wndProxy, xAtom(XA_XdndSelection),
-                                       0, VBOX_MAX_XPROPERTIES, True, AnyPropertyType,
-                                       &type, &format, &cItems, &cbRemaining, &ucData);
-                    LogFlowThisFunc(("%s %d %d %s\n", gX11->xAtomToString(type).c_str(), cItems, format, ucData));
-                    if (   type        != None
-                        && ucData      != NULL
-                        && format      >= 8
-                        && cItems      >  0
-                        && cbRemaining == 0)
+                    size_t cbData = cItems * (iPropFormat / 8);
+                    LogFlowThisFunc(("cbData=%zu\n", cbData));
+
+                    /* For whatever reason some of the string MIME types are not
+                     * zero terminated. Check that and correct it when necessary,
+                     * because the guest side wants this in any case. */
+                    if (   m_sstrStringMimeTypes.contains(strFormat)
+                        && pcData[cbData - 1] != '\0')
                     {
-                        size_t cbData = cItems * (format / 8);
-                        /* For whatever reason some of the string mime-types are not
-                         * zero terminated. Check that and correct it when necessary,
-                         * cause the guest side wants this always. */
-                        if (   m_sstrStringMimeTypes.contains(strFormat)
-                            && ucData[cbData - 1] != '\0')
+                        unsigned char *pvDataTmp = static_cast<unsigned char*>(RTMemAlloc(cbData + 1));
+                        if (pvDataTmp)
                         {
-                            LogFlowThisFunc(("Rebuild %u\n", cbData));
-                            unsigned char *ucData1 = static_cast<unsigned char*>(RTMemAlloc(cbData + 1));
-                            if (ucData1)
-                            {
-                                memcpy(ucData1, ucData, cbData);
-                                ucData1[cbData++] = '\0';
-
-                                /* Got the data and its fully transfered. */
-                                rc = VbglR3DnDGHSendData(m_uClientID, strFormat.c_str(), 
-                                                         ucData1, cbData);
-                                RTMemFree(ucData1);
-                            }
-                            else
-                                rc = VERR_NO_MEMORY;
+                            memcpy(pvDataTmp, pcData, cbData);
+                            pvDataTmp[cbData++] = '\0';
+                            
+                            rc = VbglR3DnDGHSendData(m_uClientID, strFormat.c_str(), 
+                                                     pvDataTmp, cbData);
+                            RTMemFree(pvDataTmp);
                         }
                         else
-                        {
-                            /* Just send the data to the host. */
-                            rc = VbglR3DnDGHSendData(m_uClientID, strFormat.c_str(),
-                                                     ucData, cbData);
-                        }
-
-                        LogFlowThisFunc(("send responce\n"));
-                        /* Confirm the result of the transfer to the source window. */
-                        XClientMessageEvent m;
-                        RT_ZERO(m);
-                        m.type         = ClientMessage;
-                        m.display      = m_pDisplay;
-                        m.window       = srcWin;
-                        m.message_type = xAtom(XA_XdndFinished);
-                        m.format       = 32;
-                        m.data.l[0]    = m_wndProxy;
-                        m.data.l[1]    = RT_SUCCESS(rc) ?                   1 : 0;    /* Confirm or deny success */
-                        m.data.l[2]    = RT_SUCCESS(rc) ? toX11Action(uAction) : None; /* Action used on success */
-
-                        int xrc = XSendEvent(m_pDisplay, srcWin, True, NoEventMask, reinterpret_cast<XEvent*>(&m));
-                        if (RT_UNLIKELY(xrc == 0))
-                            LogFlowThisFunc(("Error sending xevent\n"));
+                            rc = VERR_NO_MEMORY;
                     }
                     else
                     {
-                        if (type == xAtom(XA_INCR))
-                        {
-                            /** @todo Support incremental transfers. */
-                            AssertMsgFailed(("Incrementally transfers are not supported, yet\n"));
-                            rc = VERR_NOT_IMPLEMENTED;
-                        }
-                        else
-                        {
-                            AssertMsgFailed(("Not supported data type\n"));
-                            rc = VERR_INVALID_PARAMETER;
-                        }
-
-                        /* Cancel this. */
-                        XClientMessageEvent m;
-                        RT_ZERO(m);
-                        m.type         = ClientMessage;
-                        m.display      = m_pDisplay;
-                        m.window       = srcWin;
-                        m.message_type = xAtom(XA_XdndFinished);
-                        m.format       = 32;
-                        m.data.l[0]    = m_wndProxy;
-                        m.data.l[1]    = 0;
-                        m.data.l[2]    = None;
-
-                        int xrc = XSendEvent(m_pDisplay, srcWin, False, NoEventMask, reinterpret_cast<XEvent*>(&m));
-                        if (RT_UNLIKELY(xrc == 0))
-                            LogFlowThisFunc(("Error sending xevent\n"));
-                        m_wndCur = 0;
+                        /* Send the raw data to the host. */
+                        rc = VbglR3DnDGHSendData(m_uClientID, strFormat.c_str(),
+                                                 pcData, cbData);
                     }
 
-                    /* Cleanup */
-                    if (ucData)
-                        XFree(ucData);
+                    LogFlowThisFunc(("Sent strFormat=%s with rc=%Rrc\n", 
+                                     strFormat.c_str(), rc));
+
+                    /* Confirm the result of the transfer to the source window. */
+                    XClientMessageEvent m;
+                    RT_ZERO(m);
+                    m.type         = ClientMessage;
+                    m.display      = m_pDisplay;
+                    m.window       = srcWin;
+                    m.message_type = xAtom(XA_XdndFinished);
+                    m.format       = 32;
+                    m.data.l[0]    = m_wndProxy;
+                    m.data.l[1]    = RT_SUCCESS(rc) ? 1 : 0;                       /* Confirm or deny success */
+                    m.data.l[2]    = RT_SUCCESS(rc) ? toX11Action(uAction) : None; /* Action used on success */
+
+                    int xrc = XSendEvent(m_pDisplay, srcWin, True, NoEventMask, reinterpret_cast<XEvent*>(&m));
+                    if (RT_UNLIKELY(xrc == 0))
+                        LogFlowThisFunc(("Error sending xEvent\n"));
                 }
                 else
-                    rc = VERR_INVALID_PARAMETER;
+                {
+                    if (aPropType == xAtom(XA_INCR))
+                    {
+                        /** @todo Support incremental transfers. */
+                        AssertMsgFailed(("Incrementally transfers are not supported yet\n"));
+                        rc = VERR_NOT_IMPLEMENTED;
+                    }
+                    else
+                    {
+                        AssertMsgFailed(("Not supported data type\n"));
+                        rc = VERR_INVALID_PARAMETER;
+                    }
+
+                    /* Cancel this. */
+                    XClientMessageEvent m;
+                    RT_ZERO(m);
+                    m.type         = ClientMessage;
+                    m.display      = m_pDisplay;
+                    m.window       = srcWin;
+                    m.message_type = xAtom(XA_XdndFinished);
+                    m.format       = 32;
+                    m.data.l[0]    = m_wndProxy;
+                    m.data.l[1]    = 0;
+                    m.data.l[2]    = None;
+
+                    int xrc = XSendEvent(m_pDisplay, srcWin, False, NoEventMask, reinterpret_cast<XEvent*>(&m));
+                    if (RT_UNLIKELY(xrc == 0))
+                        LogFlowThisFunc(("Error sending xEvent\n"));
+                    m_wndCur = 0;
+                }
+
+                /* Cleanup. */
+                if (pcData)
+                    XFree(pcData);
             }
             else
-                rc = VERR_TIMEOUT;
+                rc = VERR_INVALID_PARAMETER;
         }
         else
-            rc = VERR_WRONG_ORDER;
+            rc = VERR_TIMEOUT;
     }
     else
@@ -1342,8 +1679,11 @@
     /* Inform the host on error. */
     if (RT_FAILURE(rc))
-        VbglR3DnDGHSendError(m_uClientID, rc);
+    {
+        int rc2 = VbglR3DnDGHSendError(m_uClientID, rc);
+        AssertRC(rc2);
+    }
 
     /* At this point, we have either successfully transfered any data or not.
-     * So reset our internal state, cause we are done. */
+     * So reset our internal state because we are done here for this transaction. */
     reset();
 
@@ -1357,69 +1697,171 @@
  */
 
-int DragInstance::moveCursor(uint32_t u32xPos, uint32_t u32yPos)
-{
+int DragInstance::mouseCursorMove(int iPosX, int iPosY) const
+{
+    LogFlowThisFunc(("iPosX=%d, iPosY=%d\n", iPosX, iPosY));
+
     /* Move the guest pointer to the DnD position, so we can find the window
      * below that position. */
-    XWarpPointer(m_pDisplay, None, m_wndRoot, 0, 0, 0, 0, u32xPos, u32yPos);
+    XWarpPointer(m_pDisplay, None, m_wndRoot, 0, 0, 0, 0, iPosX, iPosY);
     return VINF_SUCCESS;
 }
 
-void DragInstance::sendButtonEvent(Window w, int rx, int ry, int button, bool fPress) const
-{
-//    XTestFakeMotionEvent(m_pDisplay, -1, rx, ry, CurrentTime);
-//    XTestFakeMotionEvent(m_pDisplay, -1, rx + 1, ry + 1, CurrentTime);
-//    int rc = XTestFakeButtonEvent(m_pDisplay, 1, False, CurrentTime);
-//    if (rc != 0)
-    {
-        XButtonEvent be;
-        RT_ZERO(be);
-        be.display      = m_pDisplay;
-        be.root         = m_wndRoot;
-        be.window       = w;
-        be.subwindow    = None;
-        be.same_screen  = True;
-        be.time         = CurrentTime;
-        be.button       = button;
-        be.state       |= button == 1 ? Button1MotionMask :
-                          button == 2 ? Button2MotionMask :
-                          button == 3 ? Button3MotionMask :
-                          button == 4 ? Button4MotionMask :
-                          button == 5 ? Button5MotionMask : 0;
-        be.type         = fPress ? ButtonPress : ButtonRelease;
-        be.x_root       = rx;
-        be.y_root       = ry;
-        XTranslateCoordinates(m_pDisplay, be.root, be.window, be.x_root, be.y_root, &be.x, &be.y, &be.subwindow);
-        int xrc = XSendEvent(m_pDisplay, be.window, True, ButtonPressMask, reinterpret_cast<XEvent*>(&be));
+void DragInstance::mouseButtonSet(Window wndDest, int rx, int ry, int iButton, bool fPress) const
+{
+    LogFlowThisFunc(("wndDest=%#x, rx=%d, ry=%d, iBtn=%d, fPress=%RTbool\n",
+                     wndDest, rx, ry, iButton, fPress));
+#if 0
+ // Create and setting up the event
+    XEvent event;
+    memset (&event, 0, sizeof (event));
+    event.xbutton.button = iButton;
+    event.xbutton.same_screen = True;
+    event.xbutton.subwindow = DefaultRootWindow (m_pDisplay);
+
+    while (event.xbutton.subwindow)
+    {
+        event.xbutton.window = event.xbutton.subwindow;
+        XQueryPointer (m_pDisplay, event.xbutton.window,
+                        &event.xbutton.root, &event.xbutton.subwindow,
+                        &event.xbutton.x_root, &event.xbutton.y_root,
+                        &event.xbutton.x, &event.xbutton.y,
+                        &event.xbutton.state);
+    }
+    // Press
+    event.type = ButtonPress;
+    if (XSendEvent (m_pDisplay, PointerWindow, True, ButtonPressMask, &event) == 0)
+        LogFlowThisFunc(("Error sending XTestFakeButtonEvent event\n"));
+    XFlush (m_pDisplay);
+    
+    // Release
+    event.type = ButtonRelease;
+    if (XSendEvent (m_pDisplay, PointerWindow, True, ButtonReleaseMask, &event) == 0)
+        LogFlowThisFunc(("Error sending XTestFakeButtonEvent event\n"));
+    XFlush (m_pDisplay);
+    
+#else
+#ifdef VBOX_DND_WITH_XTEST
+    /** @todo Make this check run only once. */
+    int ev, er, ma, mi;
+    if (XTestQueryExtension(m_pDisplay, &ev, &er, &ma, &mi))
+    {
+        LogFlowThisFunc(("XText extension available\n"));
+
+        int xrc = XTestFakeButtonEvent(m_pDisplay, 1, fPress ? True : False, CurrentTime);
         if (RT_UNLIKELY(xrc == 0))
-            LogFlowThisFunc(("Error sending xevent\n"));
-    }
-}
-
-void DragInstance::showProxyWin(int &rx, int &ry) const
-{
-    int cx, cy;
-    unsigned int m;
-    Window r, c;
+            LogFlowThisFunc(("Error sending XTestFakeButtonEvent event\n"));
+        XFlush(m_pDisplay);
+    }
+    else
+    {
+#endif
+        LogFlowThisFunc(("XText extension not available or disabled\n"));
+
+        XButtonEvent eBtn;
+        RT_ZERO(eBtn);
+
+        eBtn.display      = m_pDisplay;
+        eBtn.root         = m_wndRoot;
+        eBtn.window       = wndDest;
+        eBtn.subwindow    = None;
+        eBtn.same_screen  = True;
+        eBtn.time         = CurrentTime;
+        eBtn.button       = iButton;
+        eBtn.state       |= iButton == 1 ? Button1Mask /*:
+                            iButton == 2 ? Button2MotionMask :
+                            iButton == 3 ? Button3MotionMask :
+                            iButton == 4 ? Button4MotionMask :
+                            iButton == 5 ? Button5MotionMask*/ : 0;
+        eBtn.type         = fPress ? ButtonPress : ButtonRelease;
+        eBtn.send_event   = False;
+        eBtn.x_root       = rx;
+        eBtn.y_root       = ry;
+
+        //XTranslateCoordinates(m_pDisplay, eBtn.root, eBtn.window, eBtn.x_root, eBtn.y_root, &eBtn.x, &eBtn.y, &eBtn.subwindow);
+#if 0
+        int xrc = XSendEvent(m_pDisplay, eBtn.window, True /* fPropagate */, 
+                               fPress 
+                             ? ButtonPressMask : ButtonReleaseMask, 
+                             reinterpret_cast<XEvent*>(&eBtn));
+#else
+        int xrc = XSendEvent(m_pDisplay, eBtn.window, False /* fPropagate */, 
+                             0 /* Mask */,
+                             reinterpret_cast<XEvent*>(&eBtn));
+#endif
+        if (RT_UNLIKELY(xrc == 0))
+            LogFlowThisFunc(("Error sending XSendEvent\n"));
+
+#ifdef DEBUG
+        Window wndTemp, wndChild;
+        int wx, wy; unsigned int mask;
+        XQueryPointer(m_pDisplay, m_wndRoot, &wndTemp, &wndChild, &rx, &ry, &wx, &wy, &mask);
+        LogFlowFunc(("cursorRootX=%d, cursorRootY=%d\n", rx, ry));
+#endif
+
+#ifdef VBOX_DND_WITH_XTEST
+    }
+#endif
+#endif
+}
+
+int DragInstance::proxyWinShow(int *piRootX /*= NULL*/, 
+                               int *piRootY /*= NULL*/,
+                               bool fMouseMove /*= false */) const
+{
+    /* piRootX is optional. */
+    /* piRootY is optional. */
+
+    LogFlowThisFuncEnter();
+
+    int iRootX, iRootY;
+    int iChildX, iChildY;
+    unsigned int iMask;
+    Window wndRoot, wndChild;
+
 //    XTestGrabControl(m_pDisplay, False);
-    XQueryPointer(m_pDisplay, m_wndRoot, &r, &c, &rx, &ry, &cx, &cy, &m);
-    XSynchronize(m_pDisplay, True);
+    Bool fInRootWnd = XQueryPointer(m_pDisplay, m_wndRoot, &wndRoot, &wndChild, 
+                                    &iRootX, &iRootY, 
+                                    &iChildX, &iChildY, &iMask);
+#ifdef DEBUG_andy
+    LogFlowThisFunc(("fInRootWnd=%RTbool, wndRoot=0x%x, wndChild=0x%x, iRootX=%d, iRootY=%d\n", 
+                     RT_BOOL(fInRootWnd), wndRoot, wndChild, iRootX, iRootY));
+#endif
+
+    if (piRootX)
+        *piRootX = iRootX;
+    if (piRootY)
+        *piRootY = iRootY;
+
+    XSynchronize(m_pDisplay, True /* Enable sync */);
+
     XMapWindow(m_pDisplay, m_wndProxy);
     XRaiseWindow(m_pDisplay, m_wndProxy);
-    XMoveResizeWindow(m_pDisplay, m_wndProxy, rx, ry, 1, 1);
-    XWarpPointer(m_pDisplay, None, m_wndRoot, 0, 0, 0, 0, rx , ry);
-    XSynchronize(m_pDisplay, False);
+    XMoveResizeWindow(m_pDisplay, m_wndProxy, iRootX, iRootY, 100, 100);
+
+    if (fMouseMove)
+        XWarpPointer(m_pDisplay, None, m_wndRoot, 0, 0, 0, 0, iRootX, iRootY);
+
+    XSynchronize(m_pDisplay, False /* Disable sync */);
 //    XTestGrabControl(m_pDisplay, True);
-}
-
-void DragInstance::hideProxyWin(void) const
-{
+
+    return VINF_SUCCESS; /** @todo Add error checking. */
+}
+
+int DragInstance::proxyWinHide(void) const
+{
+    LogFlowThisFuncEnter();
+    return 0;
+
     XUnmapWindow(m_pDisplay, m_wndProxy);
-}
-
-/* Currently, not used */
+
+    return VINF_SUCCESS; /** @todo Add error checking. */
+}
+
+/* Currently not used. */
+/** @todo Is this function still needed? */
 void DragInstance::registerForEvents(Window wndThis) const
 {
-//    if (w == m_proxyWin)
-//        return;
+    if (wndThis == m_wndProxy)
+        return;
 
     LogFlowThisFunc(("%x\n", wndThis));
@@ -1438,11 +1880,15 @@
 }
 
-void DragInstance::setActionsWindowProperty(Window wndThis, const RTCList<Atom> &actionList) const
-{
-    if (actionList.isEmpty())
+void DragInstance::setActionsWindowProperty(Window wndThis, 
+                                            const RTCList<Atom> &lstActions) const
+{
+    if (lstActions.isEmpty())
         return;
 
-    XChangeProperty(m_pDisplay, wndThis, xAtom(XA_XdndActionList), XA_ATOM, 32, PropModeReplace,
-                    reinterpret_cast<const unsigned char*>(actionList.raw()), actionList.size());
+    XChangeProperty(m_pDisplay, wndThis, 
+                    xAtom(XA_XdndActionList), 
+                    XA_ATOM, 32, PropModeReplace,
+                    reinterpret_cast<const unsigned char*>(lstActions.raw()), 
+                    lstActions.size());
 }
 
@@ -1452,5 +1898,6 @@
 }
 
-void DragInstance::setFormatsWindowProperty(Window wndThis, Atom property) const
+void DragInstance::setFormatsWindowProperty(Window wndThis, 
+                                            Atom property) const
 {
     if (m_formats.isEmpty())
@@ -1463,45 +1910,50 @@
 
     /* Add the property with the property data to the window. */
-    XChangeProperty(m_pDisplay, wndThis, property, XA_ATOM, 32, PropModeReplace,
-                    reinterpret_cast<const unsigned char*>(targets.raw()), targets.size());
+    XChangeProperty(m_pDisplay, wndThis, property, 
+                    XA_ATOM, 32, PropModeReplace,
+                    reinterpret_cast<const unsigned char*>(targets.raw()), 
+                    targets.size());
 }
 
 void DragInstance::clearFormatsWindowProperty(Window wndThis) const
 {
-    XDeleteProperty(m_pDisplay, wndThis, xAtom(XA_XdndTypeList));
-}
-
-RTCList<Atom> DragInstance::toAtomList(const RTCList<RTCString> &formatList) const
+    XDeleteProperty(m_pDisplay, wndThis, 
+                    xAtom(XA_XdndTypeList));
+}
+
+RTCList<Atom> DragInstance::toAtomList(const RTCList<RTCString> &lstFormats) const
 {
     RTCList<Atom> atomList;
-    for (size_t i = 0; i < formatList.size(); ++i)
-        atomList.append(XInternAtom(m_pDisplay, formatList.at(i).c_str(), False));
+    for (size_t i = 0; i < lstFormats.size(); ++i)
+        atomList.append(XInternAtom(m_pDisplay, lstFormats.at(i).c_str(), False));
 
     return atomList;
 }
 
-RTCList<Atom> DragInstance::toAtomList(void *pvData, uint32_t cData) const
+RTCList<Atom> DragInstance::toAtomList(void *pvData, uint32_t cbData) const
 {
     if (   !pvData
-        || !cData)
+        || !cbData)
         return RTCList<Atom>();
+
     char *pszStr = (char*)pvData;
-    uint32_t cStr = cData;
-
-    RTCList<Atom> atomList;
-    while (cStr > 0)
-    {
-        size_t cSize = RTStrNLen(pszStr, cStr);
+    uint32_t cbStr = cbData;
+
+    RTCList<Atom> lstAtom;
+    while (cbStr)
+    {
+        size_t cbSize = RTStrNLen(pszStr, cbStr);
+
         /* Create a copy with max N chars, so that we are on the save side,
          * even if the data isn't zero terminated. */
-        char *pszTmp = RTStrDupN(pszStr, cSize);
+        char *pszTmp = RTStrDupN(pszStr, cbSize);
         LogFlowThisFunc(("f: %s\n", pszTmp));
-        atomList.append(XInternAtom(m_pDisplay, pszTmp, False));
+        lstAtom.append(XInternAtom(m_pDisplay, pszTmp, False));
         RTStrFree(pszTmp);
-        pszStr += cSize + 1;
-        cStr   -= cSize + 1;
-    }
-
-    return atomList;
+        pszStr  += cbSize + 1;
+        cbStr   -= cbSize + 1;
+    }
+
+    return lstAtom;
 }
 
@@ -1509,5 +1961,5 @@
 Atom DragInstance::toX11Action(uint32_t uAction)
 {
-    /* Ignore is None */
+    /* Ignore is None. */
     return (isDnDCopyAction(uAction) ? xAtom(XA_XdndActionCopy) :
             isDnDMoveAction(uAction) ? xAtom(XA_XdndActionMove) :
@@ -1534,4 +1986,5 @@
 {
     uint32_t uAction = DND_IGNORE_ACTION;
+
     if (atom == xAtom(XA_XdndActionCopy))
         uAction = DND_COPY_ACTION;
@@ -1540,4 +1993,5 @@
     else if (atom == xAtom(XA_XdndActionLink))
         uAction = DND_LINK_ACTION;
+
     return uAction;
 }
@@ -1547,88 +2001,57 @@
 {
     uint32_t uActions = DND_IGNORE_ACTION;
+
     for (size_t i = 0; i < actionsList.size(); ++i)
         uActions |= toHGCMAction(actionsList.at(i));
+
     return uActions;
 }
 
-/*******************************************************************************
- *
- * DragAndDropService Implementation
- *
- ******************************************************************************/
-
-RTCList<RTCString> toStringList(void *pvData, uint32_t cData)
+/** @todo Replace by DnDURIList?  */
+RTCList<RTCString> toStringList(const void *pvData, uint32_t cbData)
 {
     if (   !pvData
-        || !cData)
+        || !cbData)
         return RTCList<RTCString>();
-    char *pszStr = (char*)pvData;
-    uint32_t cStr = cData;
-
-    RTCList<RTCString> strList;
-    while (cStr > 0)
-    {
-        size_t cSize = RTStrNLen(pszStr, cStr);
+
+    const char *pszStr = (char*)pvData;
+    uint32_t cbStr = cbData;
+
+    RTCList<RTCString> lstString;
+    while (cbStr > 0)
+    {
+        size_t cbSize = RTStrNLen(pszStr, cbStr);
+
         /* Create a copy with max N chars, so that we are on the save side,
          * even if the data isn't zero terminated. */
-        char *pszTmp = RTStrDupN(pszStr, cSize);
-        strList.append(pszTmp);
+        char *pszTmp = RTStrDupN(pszStr, cbSize);
+        lstString.append(pszTmp);
         RTStrFree(pszTmp);
-        pszStr += cSize + 1;
-        cStr   -= cSize + 1;
-    }
-
-    return strList;
-}
-
-#ifdef VBOX_WITH_DRAG_AND_DROP_GH
-
-bool DragAndDropService::waitForXMsg(XEvent &ecm, int type, uint32_t uiMaxMS /* = 100 */)
-{
-    const uint64_t uiStart = RTTimeProgramMilliTS();
+        pszStr  += cbSize + 1;
+        cbStr   -= cbSize + 1;
+    }
+
+    return lstString;
+}
+
+/** @todo Is this function really needed?  */
+void DragAndDropService::clearEventQueue(void)
+{
+    LogFlowThisFuncEnter();
+    m_eventQueue.clear();
+}
+
+/*******************************************************************************
+ * DragAndDropService implementation.
+ ******************************************************************************/
+
+int DragAndDropService::run(bool fDaemonised /* = false */)
+{
+    LogFlowThisFunc(("fDaemonised=%RTbool\n", fDaemonised));
+
+    int rc;
     do
     {
-        if (!m_eventQueue.isEmpty())
-        {
-            LogFlowThisFunc(("new msg size %d\n", m_eventQueue.size()));
-            /* Check if there is a client message in the queue. */
-            for (size_t i = 0; i < m_eventQueue.size(); ++i)
-            {
-                DnDEvent e = m_eventQueue.at(i);
-                if(   e.type     == DnDEvent::X11_Type)
-                    LogFlowThisFunc(("new msg\n"));
-                if(   e.type     == DnDEvent::X11_Type
-                   && e.x11.type == type)
-                {
-                    m_eventQueue.removeAt(i);
-                    ecm = e.x11;
-                    return true;
-                }
-            }
-        }
-        int rc = RTSemEventWait(m_hEventSem, 25);
-//        if (RT_FAILURE(rc))
-//            return false;
-    }
-    while (RTTimeProgramMilliTS() - uiStart < uiMaxMS);
-
-    return false;
-}
-
-#endif
-
-void DragAndDropService::clearEventQueue()
-{
-    m_eventQueue.clear();
-}
-
-int DragAndDropService::run(bool fDaemonised /* = false */)
-{
-    int rc = VINF_SUCCESS;
-    LogRelFlowFunc(("\n"));
-
-    do
-    {
-        /* Initialize X11 DND */
+        /* Initialize X11 DnD. */
         rc = x11DragAndDropInit();
         if (RT_FAILURE(rc))
@@ -1641,4 +2064,5 @@
             break;
         }
+
         /* Note: For multiple screen support in VBox it is not necessary to use
          * another screen number than zero. Maybe in the future it will become
@@ -1648,114 +2072,129 @@
             break;
 
-        /* Loop over new events */
+        LogRel(("DnD: Started\n"));
+
+        /* Enter the main event processing loop. */
         do
         {
             DnDEvent e;
             RT_ZERO(e);
-            if (m_eventQueue.isEmpty())
-                rc = RTSemEventWait(m_hEventSem, RT_INDEFINITE_WAIT);
-            if (!m_eventQueue.isEmpty())
+
+            LogFlowFunc(("Waiting for new event ...\n"));
+            rc = RTSemEventWait(m_hEventSem, RT_INDEFINITE_WAIT);
+            if (RT_FAILURE(rc)) 
+                break;
+
+            AssertMsg(m_eventQueue.size(),
+                      ("Event queue is empty when it shouldn't\n"));
+
+            e = m_eventQueue.first();
+            m_eventQueue.removeFirst();
+
+            if (e.type == DnDEvent::HGCM_Type)
             {
-                e = m_eventQueue.first();
-                m_eventQueue.removeFirst();
-                LogFlowThisFunc(("new msg %d\n", e.type));
-                if (e.type == DnDEvent::HGCM_Type)
+                LogFlowThisFunc(("HGCM event, type=%RU32\n", e.hgcm.uType));
+                switch (e.hgcm.uType)
                 {
-                    switch (e.hgcm.uType)
+                    case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
                     {
-                        case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
+                        if (e.hgcm.cbFormats) 
                         {
-                            RTCList<RTCString> formats = RTCString(e.hgcm.pszFormats, e.hgcm.cbFormats - 1).split("\r\n");
-                            m_pCurDnD->hgEnter(formats, e.hgcm.u.a.uAllActions);
+                            RTCList<RTCString> lstFormats 
+                                = RTCString(e.hgcm.pszFormats, e.hgcm.cbFormats - 1).split("\r\n");
+                            m_pCurDnD->hgEnter(lstFormats, e.hgcm.u.a.uAllActions);
+
                             /* Enter is always followed by a move event. */
                         }
-                        case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
-                        {
-                            m_pCurDnD->hgMove(e.hgcm.u.a.uXpos, e.hgcm.u.a.uYpos, e.hgcm.u.a.uDefAction);
+                        else /* Invalid parameter, skip. */
                             break;
-                        }
-                        case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
-                        {
-                            m_pCurDnD->reset();
-                            /* Not sure if this is really right! */
-                            clearEventQueue();
-                            break;
-                        }
-                        case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
-                        {
-                            m_pCurDnD->hgDrop();
-                            break;
-                        }
-                        case DragAndDropSvc::HOST_DND_HG_SND_DATA:
-                        {
-                            m_pCurDnD->hgDataReceived(e.hgcm.u.b.pvData, e.hgcm.u.b.cbData);
-                            break;
-                        }
+                        /* Not breaking unconditionally is intentional. See comment above. */
+                    }
+                    case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
+                    {
+                        m_pCurDnD->hgMove(e.hgcm.u.a.uXpos, e.hgcm.u.a.uYpos, 
+                                          e.hgcm.u.a.uDefAction);
+                        break;
+                    }
+                    case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
+                    {
+                        m_pCurDnD->reset();
+                        break;
+                    }
+                    case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
+                    {
+                        m_pCurDnD->hgDrop();
+                        break;
+                    }
+                    case DragAndDropSvc::HOST_DND_HG_SND_DATA:
+                    {
+                        m_pCurDnD->hgDataReceived(e.hgcm.u.b.pvData, e.hgcm.u.b.cbData);
+                        break;
+                    }
+                    case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
+                    {
 #ifdef VBOX_WITH_DRAG_AND_DROP_GH
-                        case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
-                        {
-                            m_pCurDnD->ghIsDnDPending();
-                            break;
-                        }
-                        case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
-                        {
-                            m_pCurDnD->ghDropped(e.hgcm.pszFormats, e.hgcm.u.a.uDefAction);
-                            /* Not sure if this is really right! */
-                            clearEventQueue();
-                            break;
-                        }
+                        m_pCurDnD->ghIsDnDPending();
 #endif
-                        default:
-                            LogFlowThisFunc(("Unknown message: %RU32\n", e.hgcm.uType));
-                            break;
+                        break;
                     }
-
-                    /* Some messages require cleanup. */
-                    switch (e.hgcm.uType)
+                    case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
                     {
-                        case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
-                        case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
-                        case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
 #ifdef VBOX_WITH_DRAG_AND_DROP_GH
-                        case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
+                        m_pCurDnD->ghDropped(e.hgcm.pszFormats, 
+                                             e.hgcm.u.a.uDefAction);
 #endif
-                        {
-                            if (e.hgcm.pszFormats)
-                                RTMemFree(e.hgcm.pszFormats);
-                            break;
-                        }
-                        case DragAndDropSvc::HOST_DND_HG_SND_DATA:
-                        {
-                            if (e.hgcm.pszFormats)
-                                RTMemFree(e.hgcm.pszFormats);
-                            if (e.hgcm.u.b.pvData)
-                                RTMemFree(e.hgcm.u.b.pvData);
-                            break;
-                        }
-                        default:
-                            break;
+                        break;
                     }
+
+                    default:
+                        LogFlowThisFunc(("Unknown message: %RU32\n", e.hgcm.uType));
+                        break;
                 }
-                else if(e.type == DnDEvent::X11_Type)
+
+                /* Some messages require cleanup. */
+                switch (e.hgcm.uType)
                 {
-                    LogFlowThisFunc(("X11 type: %u\n", e.x11.type));
-                    /* Now the X11 event stuff */
-                    switch (e.x11.type)
+                    case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
+                    case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
+                    case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
+#ifdef VBOX_WITH_DRAG_AND_DROP_GH
+                    case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
+#endif
                     {
-                        case SelectionRequest: m_pCurDnD->hgX11SelectionRequest(e.x11); break;
-                        case ClientMessage:    m_pCurDnD->hgX11ClientMessage(e.x11); break;
-                        case SelectionClear:   LogFlowThisFunc(("DnD_CLER\n")); break;
-//                      case MotionNotify: m_pCurDnD->hide(); break;
+                        if (e.hgcm.pszFormats)
+                            RTMemFree(e.hgcm.pszFormats);
+                        break;
                     }
+
+                    case DragAndDropSvc::HOST_DND_HG_SND_DATA:
+                    {
+                        if (e.hgcm.pszFormats)
+                            RTMemFree(e.hgcm.pszFormats);
+                        if (e.hgcm.u.b.pvData)
+                            RTMemFree(e.hgcm.u.b.pvData);
+                        break;
+                    }
+
+                    default:
+                        break;
                 }
             }
+            else if (e.type == DnDEvent::X11_Type)
+            {
+                m_pCurDnD->onX11Event(e.x11); 
+            }
+            else
+                AssertMsgFailed(("Unknown event queue type %d\n", e.type));
+
             /* Make sure that any X11 requests have actually been sent to the
              * server, since we are waiting for responses using poll() on
              * another thread which will not automatically trigger flushing. */
             XFlush(m_pDisplay);
-        } while (1);
+
+        } while (!ASMAtomicReadBool(&m_fSrvStopping));
+
     } while (0);
 
-    LogFlowFuncLeaveRC(rc);
+    LogRel(("DnD: Stopped with rc=%Rrc\n", rc));
     return rc;
 }
@@ -1766,5 +2205,5 @@
     m_pDisplay = XOpenDisplay(NULL);
     if (!m_pDisplay)
-        /* todo: correct errors */
+        /** @todo Correct errors. */
         return VERR_NOT_FOUND;
 
@@ -1776,8 +2215,12 @@
     do
     {
-        /* Signal a new event to our main loop. */
         rc = RTSemEventCreate(&m_hEventSem);
         if (RT_FAILURE(rc))
             break;
+
+        rc = RTCritSectInit(&m_eventQueueCS);
+        if (RT_FAILURE(rc))
+            break;
+
         /* Event thread for events coming from the HGCM device. */
         rc = RTThreadCreate(&m_hHGCMThread, hgcmEventThread, this,
@@ -1786,4 +2229,5 @@
         if (RT_FAILURE(rc))
             break;
+
         /* Event thread for events coming from the x11 system. */
         rc = RTThreadCreate(&m_hX11Thread, x11EventThread, this,
@@ -1794,4 +2238,6 @@
     /* No clean-up code for now, as we have no good way of testing it and things
      * should get cleaned up when the user process/X11 client exits. */
+    if (RT_FAILURE(rc)) 
+        LogRel(("DnD: Failed to start, rc=%Rrc\n", rc));
 
     return rc;
@@ -1803,10 +2249,11 @@
     AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
     DragAndDropService *pThis = static_cast<DragAndDropService*>(pvUser);
-    DnDEvent e;
+    AssertPtr(pThis);
 
     uint32_t uClientID;
     int rc = VbglR3DnDConnect(&uClientID);
-    if (RT_FAILURE(rc)) {
-        LogFlowFunc(("Unable to connect to HGCM service, rc=%Rrc\n", rc));
+    if (RT_FAILURE(rc)) 
+    {
+        LogRel(("DnD: Unable to connect to drag'n drop service, rc=%Rrc\n", rc));
         return rc;
     }
@@ -1814,4 +2261,5 @@
     /* Number of invalid messages skipped in a row. */
     int cMsgSkippedInvalid = 0;
+    DnDEvent e;
 
     do
@@ -1819,5 +2267,6 @@
         RT_ZERO(e);
         e.type = DnDEvent::HGCM_Type;
-        /* Wait for new events */
+
+        /* Wait for new events. */
         rc = VbglR3DnDProcessNextMessage(uClientID, &e.hgcm);
         if (RT_SUCCESS(rc))
@@ -1825,8 +2274,10 @@
             cMsgSkippedInvalid = 0; /* Reset skipped messages count. */
 
+            LogFlowFunc(("Adding new HGCM event ...\n"));
             pThis->m_eventQueue.append(e);
+
             rc = RTSemEventSignal(pThis->m_hEventSem);
             if (RT_FAILURE(rc))
-                return rc;
+                break;
         }
         else
@@ -1839,14 +2290,15 @@
             if (cMsgSkippedInvalid > 3)
             {
-                LogFlowFunc(("Too many invalid/skipped messages from host, exiting ...\n"));
+                LogRel(("DnD: Too many invalid/skipped messages from host, exiting ...\n"));
                 break;
             }
         }
 
-    } while (1);
+    } while (!ASMAtomicReadBool(&pThis->m_fSrvStopping));
 
     VbglR3DnDDisconnect(uClientID);
 
-    return VINF_SUCCESS;
+    LogFlowFuncLeaveRC(rc);
+    return rc;
 }
 
@@ -1856,44 +2308,75 @@
     AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
     DragAndDropService *pThis = static_cast<DragAndDropService*>(pvUser);
+    AssertPtr(pThis);
+
+    int rc = VINF_SUCCESS;
+
     DnDEvent e;
     do
     {
-        /* Wait for new events. We can't use XIfEvent here, because this locks
+        /* 
+         * Wait for new events. We can't use XIfEvent here, cause this locks
          * the window connection with a mutex and if no X11 events occurs this
-         * blocks any other calls we made to X11. So instead poll for new events
-         * on the connection file descriptor. */
-        /** @todo Make sure the locking is right - Xlib displays should never be
-         * used from two threads at once. */
+         * blocks any other calls we made to X11. So instead check for new
+         * events and if there are not any new one, sleep for a certain amount
+         * of time. 
+         */ 
         if (XEventsQueued(pThis->m_pDisplay, QueuedAfterFlush) > 0)
         {
             RT_ZERO(e);
             e.type = DnDEvent::X11_Type;
+
+            /* XNextEvent will block until a new X event becomes available. */
             XNextEvent(pThis->m_pDisplay, &e.x11);
-            {
-                /* Appending makes a copy of the event structure. */
-                pThis->m_eventQueue.append(e);
-                int rc = RTSemEventSignal(pThis->m_hEventSem);
-                if (RT_FAILURE(rc))
-                    return rc;
+            {           
+#ifdef DEBUG
+                switch (e.x11.type)
+                {
+                    case ClientMessage:
+                    {
+                        XClientMessageEvent *pEvent = reinterpret_cast<XClientMessageEvent*>(&e);
+                        AssertPtr(pEvent);
+
+                        RTCString strType = xAtomToString(pEvent->message_type);
+                        LogFlowFunc(("ClientMessage: %s (%RU32), serial=%RU32, wnd=%#x\n", strType.c_str(),
+                                     pEvent->message_type, pEvent->serial, pEvent->window));
+
+                        if (pEvent->message_type == xAtom(XA_XdndPosition))
+                        {
+                            int32_t dwPos = pEvent->data.l[2];
+                            int32_t dwAction = pEvent->data.l[4];
+
+                            LogFlowFunc(("XA_XdndPosition x=%RI32, y=%RI32, dwAction=%RI32\n", 
+                                         RT_HIWORD(dwPos), RT_LOWORD(dwPos), dwAction));
+                        }
+                        else if (pEvent->message_type == xAtom(XA_XdndDrop))
+                        {
+                            LogFlowFunc(("XA_XdndDrop\n"));
+                        }
+
+                        break;
+                    }
+
+                    default:
+                        LogFlowFunc(("Received X event type=%d\n", e.x11.type));
+                        break;
+                }               
+#endif
+                LogFlowFunc(("Adding new X11 event ...\n"));
+
+                /* At the moment we only have one drag instance. */
+                DragInstance *pInstance = pThis->m_pCurDnD;
+
+                AssertPtr(pInstance);
+                pInstance->onX11Event(e.x11);
             }
         }
         else
-        {
-            struct pollfd pollFD;
-
-            pollFD.fd = ConnectionNumber(pThis->m_pDisplay);
-            pollFD.events = POLLIN | POLLPRI;
-            if (   (poll(&pollFD, 1, -1) < 0 && errno != EINTR)
-                || pollFD.revents & POLLNVAL)
-            {
-                LogRel(("X11 event thread: poll failed, stopping.\n"));
-                /** @todo Just stop the whole service.  What use is it just
-                 *        to stop one thread? */
-                return RTErrConvertFromErrno(errno);
-            }
-        }
-    } while (1);
-
-    return VINF_SUCCESS;
+            RTThreadSleep(25 /* ms */);
+
+    } while (!ASMAtomicReadBool(&pThis->m_fSrvStopping));
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
 }
 
