VirtualBox

Changeset 56651 in vbox


Ignore:
Timestamp:
Jun 26, 2015 8:27:05 AM (9 years ago)
Author:
vboxsync
Message:

DnD/VBoxClient: Got rid of the buffer selection request code, overhauled selection request handling, also makes KDE guests work.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp

    r56322 r56651  
    2424
    2525#include <iprt/asm.h>
     26#include <iprt/buildconfig.h>
    2627#include <iprt/critsect.h>
    2728#include <iprt/thread.h>
     
    5152
    5253/**
    53  * For X11 guest xDnD is used. See http://www.acc.umu.se/~vatten/XDND.html for
     54 * For X11 guest Xdnd is used. See http://www.acc.umu.se/~vatten/XDND.html for
    5455 * a walk trough.
    5556 *
     
    125126    XA_text_plain,
    126127    XA_TEXT,
    127     /* xDnD */
     128    /* Xdnd */
    128129    XA_XdndSelection,
    129130    XA_XdndAware,
     
    145146};
    146147
     148/**
     149 * Xdnd message value indexes, sorted by message type.
     150 */
     151typedef enum XdndMsg
     152{
     153    /** XdndEnter. */
     154    XdndEnterTypeCount = 3,         /* Maximum number of types in XdndEnter message. */
     155
     156    XdndEnterWindow = 0,            /* Source window (sender). */
     157    XdndEnterFlags,                 /* Version in high byte, bit 0 => more data types. */
     158    XdndEnterType1,                 /* First available data type. */
     159    XdndEnterType2,                 /* Second available data type. */
     160    XdndEnterType3,                 /* Third available data type. */
     161
     162    XdndEnterMoreTypesFlag = 1,     /* Set if there are more than XdndEnterTypeCount. */
     163    XdndEnterVersionRShift = 24,    /* Right shift to position version number. */
     164    XdndEnterVersionMask   = 0xFF,  /* Mask to get version after shifting. */
     165
     166    /** XdndHere. */
     167    XdndHereWindow = 0,             /* Source window (sender). */
     168    XdndHereFlags,                  /* Reserved. */
     169    XdndHerePt,                     /* X + Y coordinates of mouse (root window coords). */
     170    XdndHereTimeStamp,              /* Timestamp for requesting data. */
     171    XdndHereAction,                 /* Action requested by user. */
     172
     173    /** XdndPosition. */
     174    XdndPositionWindow = 0,         /* Source window (sender). */
     175    XdndPositionFlags,              /* Flags. */
     176    XdndPositionCoords,             /* X/Y coordinates of the mouse position relative to the root window. */
     177    XdndPositionTimeStamp,          /* Time stamp for retrieving the data. */
     178    XdndPositionAction,             /* Action requested by the user. */
     179
     180    /** XdndStatus. */
     181    XdndStatusWindow = 0,           /* Target window (sender).*/
     182    XdndStatusFlags,                /* Flags returned by target. */
     183    XdndStatusPt,                   /* X + Y of "no msg" rectangle (root window coords). */
     184    XdndStatusArea,                 /* Width + height of "no msg" rectangle. */
     185    XdndStatusAction,               /* Action accepted by target. */
     186
     187    XdndStatusAcceptDropFlag = 1,   /* Set if target will accept the drop. */
     188    XdndStatusSendHereFlag   = 2,   /* Set if target wants a stream of XdndPosition. */
     189
     190    /** XdndLeave. */
     191    XdndLeaveWindow = 0,            /* Source window (sender). */
     192    XdndLeaveFlags,                 /* Reserved. */
     193
     194    /** XdndDrop. */
     195    XdndDropWindow = 0,             /* Source window (sender). */
     196    XdndDropFlags,                  /* Reserved. */
     197    XdndDropTimeStamp,              /* Timestamp for requesting data. */
     198
     199    /** XdndFinished. */
     200    XdndFinishedWindow = 0,         /* Target window (sender). */
     201    XdndFinishedFlags,              /* Version 5: Bit 0 is set if the current target accepted the drop. */
     202    XdndFinishedAction              /* Version 5: Contains the action performed by the target. */
     203
     204} XdndMsg;
     205
    147206class DragAndDropService;
    148207
     
    249308    "text/plain",
    250309    "TEXT",
    251     /* xDnD */
     310    /* Xdnd */
    252311    "XdndSelection",
    253312    "XdndAware",
     
    302361    Window wndApp = 0;
    303362    int cProps = -1;
     363
    304364    /* Fetch all x11 window properties of the parent window. */
    305365    Atom *pProps = XListProperties(m_pDisplay, wndParent, &cProps);
     
    308368        /* We check the window for the WM_STATE property. */
    309369        for (int i = 0; i < cProps; ++i)
     370        {
    310371            if (pProps[i] == xAtom(XA_WM_STATE))
    311372            {
     
    314375                break;
    315376            }
     377        }
     378
    316379        /* Cleanup */
    317380        XFree(pProps);
     
    383446
    384447    /* Logging. */
     448    VBOX_DND_FN_DECL_LOG(void) logInfo(const char *pszFormat, ...);
    385449    VBOX_DND_FN_DECL_LOG(void) logError(const char *pszFormat, ...);
    386450
    387451    /* X11 message processing. */
    388452    int onX11ClientMessage(const XEvent &e);
     453    int onX11MotionNotify(const XEvent &e);
     454    int onX11SelectionClear(const XEvent &e);
    389455    int onX11SelectionNotify(const XEvent &e);
    390456    int onX11SelectionRequest(const XEvent &e);
    391457    int onX11Event(const XEvent &e);
     458    int  waitForStatusChange(uint32_t enmState, RTMSINTERVAL uTimeoutMS = 30000);
    392459    bool waitForX11Msg(XEvent &evX, int iType, RTMSINTERVAL uTimeoutMS = 100);
    393460    bool waitForX11ClientMsg(XClientMessageEvent &evMsg, Atom aType, RTMSINTERVAL uTimeoutMS = 100);
     
    396463    int hgEnter(const RTCList<RTCString> &formats, uint32_t actions);
    397464    int hgLeave(void);
    398     int hgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t action);
    399     int hgDrop(void);
     465    int hgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t uDefaultAction);
     466    int hgDrop(uint32_t u32xPos, uint32_t u32yPos, uint32_t uDefaultAction);
    400467    int hgDataReceived(const void *pvData, uint32_t cData);
    401468
     
    409476    int  mouseCursorMove(int iPosX, int iPosY) const;
    410477    void mouseButtonSet(Window wndDest, int rx, int ry, int iButton, bool fPress);
    411     int proxyWinShow(int *piRootX = NULL, int *piRootY = NULL, bool fMouseMove = false) const;
     478    int proxyWinShow(int *piRootX = NULL, int *piRootY = NULL) const;
    412479    int proxyWinHide(void);
    413480
     481    /* X11 window helpers. */
     482    char *wndX11GetNameA(Window wndThis) const;
     483
     484    /* Xdnd protocol helpers. */
    414485    void wndXDnDClearActionList(Window wndThis) const;
    415486    void wndXDnDClearFormatList(Window wndThis) const;
     
    419490    int wndXDnDSetFormatList(Window wndThis, Atom atmProp, const VBoxDnDAtomList &lstFormats) const;
    420491
     492    /* Atom / HGCM formatting helpers. */
    421493    int             toAtomList(const RTCList<RTCString> &lstFormats, VBoxDnDAtomList &lstAtoms) const;
    422494    int             toAtomList(const void *pvData, uint32_t cbData, VBoxDnDAtomList &lstAtoms) const;
     
    451523    /** List of (Atom) actions the source window supports. */
    452524    VBoxDnDAtomList             m_lstActions;
    453     /** Deferred host to guest selection event for sending to the
    454      *  target window as soon as data from the host arrived. */
    455     XEvent                      m_eventHgSelection;
     525    /** Buffer for answering the target window's selection request. */
     526    void                       *m_pvSelReqData;
     527    /** Size (in bytes) of selection request data buffer. */
     528    uint32_t                    m_cbSelReqData;
    456529    /** Current operation mode. */
    457     Mode                        m_enmMode;
     530    volatile uint32_t           m_enmMode;
    458531    /** Current state of operation mode. */
    459     State                       m_enmState;
     532    volatile uint32_t           m_enmState;
    460533    /** The instance's own X event queue. */
    461     RTCMTList<XEvent>           m_eventQueue;
     534    RTCMTList<XEvent>           m_eventQueueList;
    462535    /** Critical section for providing serialized access to list
    463536     *  event queue's contents. */
     
    465538    /** Event for notifying this instance in case of a new
    466539     *  event. */
    467     RTSEMEVENT                  m_hEventSem;
     540    RTSEMEVENT                  m_eventQueueEvent;
     541    /** Critical section for data access. */
     542    RTCRITSECT                  m_dataCS;
    468543    /** List of allowed formats. */
    469544    RTCList<RTCString>          m_lstAllowedFormats;
     
    528603    , m_wndCur(0)
    529604    , m_curVer(-1)
     605    , m_pvSelReqData(NULL)
     606    , m_cbSelReqData(0)
    530607    , m_enmMode(Unknown)
    531608    , m_enmState(Uninitialized)
    532609{
    533     uninit();
    534610}
    535611
     
    539615void DragInstance::uninit(void)
    540616{
    541     reset();
     617    LogFlowFuncEnter();
     618
    542619    if (m_wndProxy != 0)
    543620        XDestroyWindow(m_pDisplay, m_wndProxy);
    544621
    545     VbglR3DnDDisconnect(&m_dndCtx);
    546 
    547     m_enmState    = Uninitialized;
    548     m_screenId = -1;
    549     m_pScreen  = 0;
    550     m_wndRoot  = 0;
    551     m_wndProxy = 0;
     622    int rc2 = VbglR3DnDDisconnect(&m_dndCtx);
     623
     624    if (m_pvSelReqData)
     625        RTMemFree(m_pvSelReqData);
     626
     627    rc2 = RTSemEventDestroy(m_eventQueueEvent);
     628    AssertRC(rc2);
     629
     630    rc2 = RTCritSectDelete(&m_eventQueueCS);
     631    AssertRC(rc2);
     632
     633    rc2 = RTCritSectDelete(&m_dataCS);
     634    AssertRC(rc2);
    552635}
    553636
     
    562645    proxyWinHide();
    563646
    564     /* If we are currently the Xdnd selection owner, clear that. */
    565     Window w = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection));
    566     if (w == m_wndProxy)
    567         XSetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection), None, CurrentTime);
    568 
    569     /* Clear any other DnD specific data on the proxy window. */
    570     wndXDnDClearFormatList(m_wndProxy);
    571     wndXDnDClearActionList(m_wndProxy);
    572 
    573     /* Reset the internal state. */
    574     m_lstActions.clear();
    575     m_lstFormats.clear();
    576     m_wndCur    = 0;
    577     m_curVer    = -1;
    578     m_enmState  = Initialized;
    579     m_enmMode   = Unknown;
    580     m_eventQueue.clear();
     647    int rc2 = RTCritSectEnter(&m_dataCS);
     648    if (RT_SUCCESS(rc2))
     649    {
     650        /* If we are currently the Xdnd selection owner, clear that. */
     651        Window pWnd = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection));
     652        if (pWnd == m_wndProxy)
     653            XSetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection), None, CurrentTime);
     654
     655        /* Clear any other DnD specific data on the proxy window. */
     656        wndXDnDClearFormatList(m_wndProxy);
     657        wndXDnDClearActionList(m_wndProxy);
     658
     659        /* Reset the internal state. */
     660        m_lstActions.clear();
     661        m_lstFormats.clear();
     662        m_wndCur    = 0;
     663        m_curVer    = -1;
     664        m_enmState  = Initialized;
     665        m_enmMode   = Unknown;
     666        m_eventQueueList.clear();
     667
     668        /* Reset the selection request buffer. */
     669        if (m_pvSelReqData)
     670        {
     671            RTMemFree(m_pvSelReqData);
     672            m_pvSelReqData = NULL;
     673
     674            Assert(m_cbSelReqData);
     675            m_cbSelReqData = 0;
     676        }
     677
     678        RTCritSectLeave(&m_dataCS);
     679    }
    581680}
    582681
     
    593692    do
    594693    {
    595         uninit();
    596 
    597694        rc = VbglR3DnDConnect(&m_dndCtx);
    598695        if (RT_FAILURE(rc))
    599696            break;
    600697
    601         rc = RTSemEventCreate(&m_hEventSem);
     698        rc = RTSemEventCreate(&m_eventQueueEvent);
    602699        if (RT_FAILURE(rc))
    603700            break;
    604701
    605702        rc = RTCritSectInit(&m_eventQueueCS);
     703        if (RT_FAILURE(rc))
     704            break;
     705
     706        rc = RTCritSectInit(&m_dataCS);
    606707        if (RT_FAILURE(rc))
    607708            break;
     
    684785        XFlush(m_pDisplay);
    685786#endif
    686         LogFlowThisFunc(("Created proxy window 0x%x at m_wndRoot=0x%x ...\n", m_wndProxy, m_wndRoot));
     787        logInfo("Proxy window=0x%x, root window=0x%x ...\n", m_wndProxy, m_wndRoot);
    687788
    688789        /* Set the window's name for easier lookup. */
     
    697798    if (RT_SUCCESS(rc))
    698799    {
    699         m_enmState = Initialized;
     800        reset();
    700801    }
    701802    else
    702         LogRel(("DnD: Initializing drag instance for screen %RU32 failed with rc=%Rrc\n",
    703                 u32ScreenID, rc));
     803        logError("Initializing drag instance for screen %RU32 failed with rc=%Rrc\n", u32ScreenID, rc);
    704804
    705805    LogFlowFuncLeaveRC(rc);
     
    722822    AssertPtr(psz);
    723823    LogFlowFunc(("%s", psz));
     824    LogRel(("DnD: %s", psz));
     825
     826    RTStrFree(psz);
     827}
     828
     829/**
     830 * Logs an info message to the (release) logging instance.
     831 *
     832 * @param   pszFormat               Format string to log.
     833 */
     834VBOX_DND_FN_DECL_LOG(void) DragInstance::logInfo(const char *pszFormat, ...)
     835{
     836    va_list args;
     837    va_start(args, pszFormat);
     838    char *psz = NULL;
     839    RTStrAPrintfV(&psz, pszFormat, args);
     840    va_end(args);
     841
     842    AssertPtr(psz);
     843    LogFlowFunc(("%s", psz));
    724844    LogRel2(("DnD: %s", psz));
    725845
     
    737857    AssertReturn(e.type == ClientMessage, VERR_INVALID_PARAMETER);
    738858
    739     LogFlowThisFunc(("mode=%d, state=%d\n", m_enmMode, m_enmState));
     859    LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState));
    740860    LogFlowThisFunc(("Event wnd=%#x, msg=%s\n", e.xclient.window, xAtomToString(e.xclient.message_type).c_str()));
    741861
    742     int rc;
     862    int rc = VINF_SUCCESS;
    743863
    744864    switch (m_enmMode)
     
    751871             */
    752872            if (   e.xclient.message_type == xAtom(XA_XdndStatus)
    753                 && m_wndCur               == static_cast<Window>(e.xclient.data.l[0]))
     873                && m_wndCur               == static_cast<Window>(e.xclient.data.l[XdndStatusWindow]))
    754874            {
     875                bool fAcceptDrop     = ASMBitTest   (&e.xclient.data.l[XdndStatusFlags], 0); /* Does the target accept the drop? */
     876                bool fWantsPosition  = ASMBitTest   (&e.xclient.data.l[XdndStatusFlags], 1); /* Does the target want XdndPosition messages? */
     877                RTCString strActions = xAtomToString( e.xclient.data.l[XdndStatusAction]);
     878
     879                char *pszWndName = wndX11GetNameA(e.xclient.data.l[XdndStatusWindow]);
     880                AssertPtr(pszWndName);
     881
    755882                /*
    756883                 * The XdndStatus message tell us if the window will accept the DnD
     
    758885                 * the host as a response of a previous DnD message.
    759886                 */
    760                 LogFlowThisFunc(("XA_XdndStatus: wnd=%#x, accept=%RTbool, action=%s\n",
    761                                  e.xclient.data.l[0],
    762                                  ASMBitTest(&e.xclient.data.l[1], 0),
    763                                  xAtomToString(e.xclient.data.l[4]).c_str()));
    764 
    765                 uint32_t uAction = DND_IGNORE_ACTION;
     887                LogFlowThisFunc(("XA_XdndStatus: wnd=%#x ('%s'), fAcceptDrop=%RTbool, fWantsPosition=%RTbool, strActions=%s\n",
     888                                 e.xclient.data.l[XdndStatusWindow], pszWndName, fAcceptDrop, fWantsPosition, strActions.c_str()));
     889
     890                RTStrFree(pszWndName);
     891
     892                uint16_t x = RT_HI_U16((uint32_t)e.xclient.data.l[XdndStatusPt]);
     893                uint16_t y = RT_LO_U16((uint32_t)e.xclient.data.l[XdndStatusPt]);
     894                uint16_t w = RT_HI_U16((uint32_t)e.xclient.data.l[XdndStatusArea]);
     895                uint16_t h = RT_LO_U16((uint32_t)e.xclient.data.l[XdndStatusArea]);
     896                LogFlowThisFunc(("\tReported dead area: x=%RU16, y=%RU16, w=%RU16, h=%RU16\n", x, y, w, h));
     897
     898                uint32_t uAction = DND_IGNORE_ACTION; /* Default is ignoring. */
    766899                /** @todo Compare this with the allowed actions. */
    767                 if (ASMBitTest(&e.xclient.data.l[1], 0))
    768                     uAction = toHGCMAction(static_cast<Atom>(e.xclient.data.l[4]));
     900                if (fAcceptDrop)
     901                    uAction = toHGCMAction(static_cast<Atom>(e.xclient.data.l[XdndStatusAction]));
    769902
    770903                rc = VbglR3DnDHGAcknowledgeOperation(&m_dndCtx, uAction);
     
    772905            else if (e.xclient.message_type == xAtom(XA_XdndFinished))
    773906            {
    774                 rc = VINF_SUCCESS;
     907                bool fSucceeded = ASMBitTest(&e.xclient.data.l[XdndFinishedFlags], 0);
     908
     909                char *pszWndName = wndX11GetNameA(e.xclient.data.l[XdndFinishedWindow]);
     910                AssertPtr(pszWndName);
    775911
    776912                /* This message is sent on an un/successful DnD drop request. */
    777                 LogFlowThisFunc(("XA_XdndFinished: wnd=%#x, success=%RTbool, action=%s\n",
    778                                  e.xclient.data.l[0],
    779                                  ASMBitTest(&e.xclient.data.l[1], 0),
    780                                  xAtomToString(e.xclient.data.l[2]).c_str()));
    781 
    782                 proxyWinHide();
     913                LogFlowThisFunc(("XA_XdndFinished: wnd=%#x ('%s'), success=%RTbool, action=%s\n",
     914                                 e.xclient.data.l[XdndFinishedWindow], pszWndName, fSucceeded,
     915                                 xAtomToString(e.xclient.data.l[XdndFinishedAction]).c_str()));
     916
     917                RTStrFree(pszWndName);
     918
     919                reset();
    783920            }
    784921            else
    785922            {
    786                 LogFlowThisFunc(("Unhandled: wnd=%#x, msg=%s\n",
    787                                  e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str()));
     923                char *pszWndName = wndX11GetNameA(e.xclient.data.l[0]);
     924                AssertPtr(pszWndName);
     925                LogFlowThisFunc(("Unhandled: wnd=%#x ('%s'), msg=%s\n",
     926                                 e.xclient.data.l[0], pszWndName, xAtomToString(e.xclient.message_type).c_str()));
     927                RTStrFree(pszWndName);
     928
    788929                rc = VERR_NOT_SUPPORTED;
    789930            }
     
    792933        }
    793934
     935        case Unknown: /* Mode not set (yet). */
    794936        case GH:
    795         case Unknown: /* Mode not set (yet), just add what we got. */
    796937        {
    797             m_eventQueue.append(e);
    798             rc = RTSemEventSignal(m_hEventSem);
     938            /*
     939             * This message marks the beginning of a new drag and drop
     940             * operation on the guest.
     941             */
     942            if (e.xclient.message_type == xAtom(XA_XdndEnter))
     943            {
     944                LogFlowFunc(("XA_XdndEnter\n"));
     945
     946                /*
     947                 * Get the window which currently has the XA_XdndSelection
     948                 * bit set.
     949                 */
     950                Window wndSelection = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection));
     951
     952                char *pszWndName = wndX11GetNameA(wndSelection);
     953                AssertPtr(pszWndName);
     954
     955                LogFlowThisFunc(("wndSelection=%#x ('%s'), wndProxy=%#x\n", wndSelection, pszWndName, m_wndProxy));
     956
     957                RTStrFree(pszWndName);
     958
     959                mouseButtonSet(m_wndProxy, -1, -1, 1, true /* fPress */);
     960
     961                /*
     962                 * Update our state and the window handle to process.
     963                 */
     964                int rc2 = RTCritSectEnter(&m_dataCS);
     965                if (RT_SUCCESS(rc2))
     966                {
     967                    m_wndCur = wndSelection;
     968                    m_curVer = e.xclient.data.l[XdndEnterFlags] >> XdndEnterVersionRShift;
     969                    Assert(m_wndCur == (Window)e.xclient.data.l[XdndEnterWindow]); /* Source window. */
     970#ifdef DEBUG
     971                    XWindowAttributes xwa;
     972                    XGetWindowAttributes(m_pDisplay, m_wndCur, &xwa);
     973                    LogFlowThisFunc(("wndCur=%#x, x=%d, y=%d, width=%d, height=%d\n", m_wndCur, xwa.x, xwa.y, xwa.width, xwa.height));
     974#endif
     975                    /*
     976                     * Retrieve supported formats.
     977                     */
     978
     979                    /* Check if the MIME types are in the message itself or if we need
     980                     * to fetch the XdndTypeList property from the window. */
     981                    bool fMoreTypes = e.xclient.data.l[XdndEnterFlags] & XdndEnterMoreTypesFlag;
     982                    LogFlowThisFunc(("XdndVer=%d, fMoreTypes=%RTbool\n", m_curVer, fMoreTypes));
     983                    if (!fMoreTypes)
     984                    {
     985                        /* Only up to 3 format types supported. */
     986                        /* Start with index 2 (first item). */
     987                        for (int i = 2; i < 5; i++)
     988                        {
     989                            LogFlowThisFunc(("\t%s\n", gX11->xAtomToString(e.xclient.data.l[i]).c_str()));
     990                            m_lstFormats.append(e.xclient.data.l[i]);
     991                        }
     992                    }
     993                    else
     994                    {
     995                        /* More than 3 format types supported. */
     996                        rc = wndXDnDGetFormatList(wndSelection, m_lstFormats);
     997                    }
     998
     999                    /*
     1000                     * Retrieve supported actions.
     1001                     */
     1002                    if (RT_SUCCESS(rc))
     1003                    {
     1004                        if (m_curVer >= 2) /* More than one action allowed since protocol version 2. */
     1005                        {
     1006                            rc = wndXDnDGetActionList(wndSelection, m_lstActions);
     1007                        }
     1008                        else /* Only "copy" action allowed on legacy applications. */
     1009                            m_lstActions.append(XA_XdndActionCopy);
     1010                    }
     1011
     1012                    if (RT_SUCCESS(rc))
     1013                    {
     1014                        m_enmMode  = GH;
     1015                        m_enmState = Dragging;
     1016                    }
     1017
     1018                    RTCritSectLeave(&m_dataCS);
     1019                }
     1020            }
     1021            else if (   e.xclient.message_type == xAtom(XA_XdndPosition)
     1022                     && m_wndCur               == static_cast<Window>(e.xclient.data.l[XdndPositionWindow]))
     1023            {
     1024                int32_t lPos      = e.xclient.data.l[XdndPositionCoords];
     1025                Atom    atmAction = m_curVer >= 2 /* Actions other than "copy" or only supported since protocol version 2. */
     1026                                  ? e.xclient.data.l[XdndPositionAction] : xAtom(XA_XdndActionCopy);
     1027
     1028                LogFlowThisFunc(("XA_XdndPosition: wndProxy=%#x, wndCur=%#x, x=%RI32, y=%RI32, strAction=%s\n",
     1029                                 m_wndProxy, m_wndCur, RT_HIWORD(lPos), RT_LOWORD(lPos),
     1030                                 xAtomToString(atmAction).c_str()));
     1031
     1032                bool fAcceptDrop = true;
     1033
     1034                /* Reply with a XdndStatus message to tell the source whether
     1035                 * the data can be dropped or not. */
     1036                XClientMessageEvent m;
     1037                RT_ZERO(m);
     1038                m.type         = ClientMessage;
     1039                m.display      = m_pDisplay;
     1040                m.window       = e.xclient.data.l[XdndPositionWindow];
     1041                m.message_type = xAtom(XA_XdndStatus);
     1042                m.format       = 32;
     1043                m.data.l[XdndStatusWindow] = m_wndProxy;
     1044                m.data.l[XdndStatusFlags]  = fAcceptDrop ? RT_BIT(0) : 0;                        /* Whether to accept the drop or not. */
     1045                m.data.l[XdndStatusAction] = fAcceptDrop ? toAtomAction(DND_COPY_ACTION) : None; /** @todo Handle default action! */
     1046
     1047                int xRc = XSendEvent(m_pDisplay, e.xclient.data.l[XdndPositionWindow],
     1048                                     False /* Propagate */, NoEventMask, reinterpret_cast<XEvent *>(&m));
     1049                if (xRc == 0)
     1050                    logError("Error sending position XA_XdndStatus event to current window=%#x: %s\n",
     1051                              m_wndCur, gX11->xErrorToString(xRc).c_str());
     1052            }
     1053            else if (   e.xclient.message_type == xAtom(XA_XdndLeave)
     1054                     && m_wndCur               == static_cast<Window>(e.xclient.data.l[XdndLeaveWindow]))
     1055            {
     1056                LogFlowThisFunc(("XA_XdndLeave\n"));
     1057                logInfo("Guest to host transfer canceled by the guest source window\n");
     1058
     1059                /* Start over. */
     1060                reset();
     1061            }
     1062            else if (   e.xclient.message_type == xAtom(XA_XdndDrop)
     1063                     && m_wndCur               == static_cast<Window>(e.xclient.data.l[XdndDropWindow]))
     1064            {
     1065                LogFlowThisFunc(("XA_XdndDrop\n"));
     1066                logInfo("Notified guest target window that drop operation is finished\n");
     1067
     1068                m_eventQueueList.append(e);
     1069                rc = RTSemEventSignal(m_eventQueueEvent);
     1070            }
     1071            else if (   e.xclient.message_type == xAtom(XA_XdndFinished)
     1072                     && m_wndCur               == static_cast<Window>(e.xclient.data.l[XdndFinishedWindow]))
     1073            {
     1074                LogFlowThisFunc(("XA_XdndFinished\n"));
     1075                logInfo("Guest target window finished drag and drop operation\n");
     1076
     1077                m_eventQueueList.append(e);
     1078                rc = RTSemEventSignal(m_eventQueueEvent);
     1079            }
    7991080            break;
    8001081        }
     
    8121093}
    8131094
     1095int DragInstance::onX11MotionNotify(const XEvent &e)
     1096{
     1097    LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState));
     1098
     1099    return VINF_SUCCESS;
     1100}
     1101
     1102/**
     1103 * Callback handler for being notified if some other window now
     1104 * is the owner of the current selection.
     1105 *
     1106 * @return  IPRT status code.
     1107 * @param   e                       X11 event to handle.
     1108 *
     1109 * @remark
     1110 */
     1111int DragInstance::onX11SelectionClear(const XEvent &e)
     1112{
     1113    LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState));
     1114
     1115    return VINF_SUCCESS;
     1116}
     1117
    8141118/**
    8151119 * Callback handler for a XDnD selection notify from a window. This is needed
     
    8241128    AssertReturn(e.type == SelectionNotify, VERR_INVALID_PARAMETER);
    8251129
    826     LogFlowThisFunc(("m_mode=%d, m_state=%d\n", m_enmMode, m_enmState));
     1130    LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState));
    8271131
    8281132    int rc;
     
    8341138            if (m_enmState == Dropped)
    8351139            {
    836                 m_eventQueue.append(e);
    837                 rc = RTSemEventSignal(m_hEventSem);
     1140                m_eventQueueList.append(e);
     1141                rc = RTSemEventSignal(m_eventQueueEvent);
    8381142            }
     1143            else
     1144                rc = VERR_WRONG_ORDER;
    8391145            break;
    8401146        }
     
    8641170    AssertReturn(e.type == SelectionRequest, VERR_INVALID_PARAMETER);
    8651171
    866     LogFlowThisFunc(("m_mode=%d, m_state=%d\n", m_enmMode, m_enmState));
     1172    LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState));
    8671173    LogFlowThisFunc(("Event owner=%#x, requestor=%#x, selection=%s, target=%s, prop=%s, time=%u\n",
    8681174                     e.xselectionrequest.owner,
     
    8741180    int rc;
    8751181
    876     bool fSendEvent  = false;
    877     Atom atmTarget   = None;
    878     Atom atmProperty = None;
    879 
    8801182    switch (m_enmMode)
    8811183    {
     
    8841186            rc = VINF_SUCCESS;
    8851187
     1188            char *pszWndName = wndX11GetNameA(e.xselectionrequest.requestor);
     1189            AssertPtr(pszWndName);
     1190
     1191            /*
     1192             * Start by creating a refusal selection notify message.
     1193             * That way we only need to care for the success case.
     1194             */
     1195
     1196            XEvent s;
     1197            RT_ZERO(s);
     1198            s.xselection.type      = SelectionNotify;
     1199            s.xselection.display   = e.xselectionrequest.display;
     1200            s.xselection.requestor = e.xselectionrequest.requestor;
     1201            s.xselection.selection = e.xselectionrequest.selection;
     1202            s.xselection.target    = e.xselectionrequest.target;
     1203            s.xselection.property  = None;                          /* "None" means refusal. */
     1204            s.xselection.time      = e.xselectionrequest.time;
     1205
     1206            const XSelectionRequestEvent *pReq = &e.xselectionrequest;
     1207
    8861208#ifdef DEBUG
    887             XTextProperty propName;
    888             XGetWMName(m_pDisplay, e.xselectionrequest.requestor, &propName);
     1209            LogFlowFunc(("Supported formats:\n"));
     1210            for (size_t i = 0; i < m_lstFormats.size(); i++)
     1211                LogFlowFunc(("\t%s\n", xAtomToString(m_lstFormats.at(i)).c_str()));
    8891212#endif
    890             /*
    891              * A window is asking for some data. Normally here the data would be copied
    892              * into the selection buffer and send to the requestor. Obviously we can't
    893              * do that, because we first need to ask the host for the data of the
    894              * requested MIME type. This is done and later answered with the correct
    895              * data -- see DragInstance::hgDataReceived().
    896              */
    897 
    8981213            /* Is the requestor asking for the possible MIME types? */
    899             if (e.xselectionrequest.target == xAtom(XA_TARGETS))
     1214            if (pReq->target == xAtom(XA_TARGETS))
    9001215            {
    901                 LogFlowThisFunc(("wnd=%#x ('%s') asking for target list\n",
    902                                  e.xselectionrequest.requestor, propName.value ? (const char *)propName.value : "<No name>"));
     1216                logInfo("Target window %#x ('%s') asking for target list\n", e.xselectionrequest.requestor, pszWndName);
    9031217
    9041218                /* If so, set the window property with the formats on the requestor
    9051219                 * window. */
    906                 rc = wndXDnDSetFormatList(e.xselectionrequest.requestor, e.xselectionrequest.property, m_lstFormats);
     1220                rc = wndXDnDSetFormatList(pReq->requestor, pReq->property, m_lstFormats);
    9071221                if (RT_SUCCESS(rc))
    908                 {
    909                     atmTarget   = e.xselectionrequest.target;
    910                     atmProperty = e.xselectionrequest.property;
    911 
    912                     fSendEvent  = true;
    913                 }
     1222                    s.xselection.property = pReq->property;
    9141223            }
    9151224            /* Is the requestor asking for a specific MIME type (we support)? */
    916             else if (m_lstFormats.contains(e.xselectionrequest.target))
     1225            else if (m_lstFormats.contains(pReq->target))
    9171226            {
    918                 LogFlowThisFunc(("wnd=%#x ('%s') asking for data, format=%s\n",
    919                                  e.xselectionrequest.requestor, propName.value ? (const char *)propName.value : "<No name>",
    920                                  xAtomToString(e.xselectionrequest.target).c_str()));
    921 
    922                 /* If so, we need to inform the host about this request. Save the
    923                  * selection request event for later use. */
     1227                logInfo("Target window %#x ('%s') is asking for data as '%s'\n",
     1228                         pReq->requestor, pszWndName, xAtomToString(pReq->target).c_str());
     1229
     1230                /* Did we not drop our stuff to the guest yet? Bail out. */
    9241231                if (m_enmState != Dropped)
    9251232                {
    9261233                    LogFlowThisFunc(("Wrong state (%RU32), refusing request\n", m_enmState));
    927 
    928                     atmTarget   = None;
    929                     atmProperty = e.xselectionrequest.property;
    930 
    931                     fSendEvent  = true;
    9321234                }
     1235                /* Did we not store the requestor's initial selection request yet? Then do so now. */
    9331236                else
    9341237                {
    935                     LogFlowThisFunc(("Saving selection notify message of wnd=%#x ('%s')\n",
    936                                      e.xselectionrequest.requestor, propName.value ? (const char *)propName.value : "<No name>"));
    937 
    938                     memcpy(&m_eventHgSelection, &e, sizeof(XEvent));
    939 
    940                     RTCString strFormat = xAtomToString(e.xselectionrequest.target);
     1238                    /* Get the data format the requestor wants from us. */
     1239                    RTCString strFormat = xAtomToString(pReq->target);
    9411240                    Assert(strFormat.isNotEmpty());
    942 
    943                     rc = VbglR3DnDHGRequestData(&m_dndCtx, strFormat.c_str());
    944                     LogFlowThisFunc(("Requested data from host as \"%s\", rc=%Rrc\n", strFormat.c_str(), rc));
     1241                    logInfo("Target window=%#x requested data from host as '%s', rc=%Rrc\n",
     1242                            pReq->requestor, strFormat.c_str(), rc);
     1243
     1244                    /* Make a copy of the MIME data to be passed back. The X server will be become
     1245                     * the new owner of that data, so no deletion needed. */
     1246                    /** @todo Do we need to do some more conversion here? XConvertSelection? */
     1247                    void *pvData = RTMemDup(m_pvSelReqData, m_cbSelReqData);
     1248                    uint32_t cbData = m_cbSelReqData;
     1249
     1250                    /* Always return the requested property. */
     1251                    s.xselection.property = pReq->property;
     1252
     1253                    /* Note: Always seems to return BadRequest. Seems fine. */
     1254                    int xRc = XChangeProperty(s.xselection.display, s.xselection.requestor, s.xselection.property,
     1255                                              s.xselection.target, 8, PropModeReplace,
     1256                                              reinterpret_cast<const unsigned char*>(pvData), cbData);
     1257
     1258                    LogFlowFunc(("Changing property '%s' (target '%s') of window=0x%x: %s\n",
     1259                                 xAtomToString(pReq->property).c_str(),
     1260                                 xAtomToString(pReq->target).c_str(),
     1261                                 pReq->requestor,
     1262                                 gX11->xErrorToString(xRc).c_str()));
    9451263                }
    9461264            }
     
    9481266            else
    9491267            {
    950                 LogFlowThisFunc(("Refusing unknown command of wnd=%#x ('%s')\n", e.xselectionrequest.requestor,
    951                                  propName.value ? (const char *)propName.value : "<No name>"));
    952 
    953                 /* We don't understand this request message and therefore answer with an
    954                  * refusal messages. */
    955                 fSendEvent = true;
     1268                logError("Refusing unknown command/format '%s' of wnd=%#x ('%s')\n",
     1269                         xAtomToString(e.xselectionrequest.target).c_str(), pReq->requestor, pszWndName);
     1270                rc = VERR_NOT_SUPPORTED;
    9561271            }
    9571272
    958             if (   RT_SUCCESS(rc)
    959                 && fSendEvent)
    960             {
    961                 XEvent s;
    962                 RT_ZERO(s);
    963                 s.xselection.type      = SelectionNotify;
    964                 s.xselection.display   = e.xselection.display;
    965                 s.xselection.time      = e.xselectionrequest.time;
    966                 s.xselection.selection = e.xselectionrequest.selection;
    967                 s.xselection.requestor = e.xselectionrequest.requestor;
    968                 s.xselection.target    = atmTarget;
    969                 s.xselection.property  = atmProperty;
    970 
    971                 int xRc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);
    972                 if (RT_UNLIKELY(xRc == 0))
    973                     logError("Error sending SelectionNotify(1) event to wnd=%#x: %s\n", e.xselectionrequest.requestor,
    974                              gX11->xErrorToString(xRc).c_str());
    975             }
    976 
    977 #ifdef DEBUG
    978             if (propName.value)
    979                 XFree(propName.value);
    980 #endif
     1273            LogFlowThisFunc(("Offering type '%s', property '%s' to wnd=%#x ...\n",
     1274                             xAtomToString(pReq->target).c_str(),
     1275                             xAtomToString(pReq->property).c_str(), pReq->requestor));
     1276
     1277            int xRc = XSendEvent(pReq->display, pReq->requestor, True /* Propagate */, 0, &s);
     1278            if (xRc == 0)
     1279                logError("Error sending SelectionNotify(1) event to wnd=%#x: %s\n", pReq->requestor,
     1280                         gX11->xErrorToString(xRc).c_str());
     1281            XFlush(pReq->display);
     1282
     1283            if (pszWndName)
     1284                RTStrFree(pszWndName);
    9811285            break;
    9821286        }
    9831287
    9841288        default:
    985         {
    986             LogFlowThisFunc(("Unhandled message for wnd=%#x: %s\n",
    987                              e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str()));
    9881289            rc = VERR_INVALID_STATE;
    9891290            break;
    990         }
    9911291    }
    9921292
     
    10231323
    10241324        case SelectionClear:
    1025            LogFlowThisFunc(("SelectionClear\n"));
    1026            reset();
    1027            rc = VINF_SUCCESS;
    1028            break;
     1325            rc = onX11SelectionClear(e);
     1326            break;
    10291327
    10301328        case SelectionNotify:
     
    10361334            break;
    10371335
    1038         /*case MotionNotify:
    1039           hide();
    1040           break;*/
     1336        case MotionNotify:
     1337            rc = onX11MotionNotify(e);
     1338            break;
    10411339
    10421340        default:
     
    10461344
    10471345    LogFlowThisFunc(("rc=%Rrc\n", rc));
     1346    return rc;
     1347}
     1348
     1349int DragInstance::waitForStatusChange(uint32_t enmState, RTMSINTERVAL uTimeoutMS /* = 30000 */)
     1350{
     1351    const uint64_t uiStart = RTTimeMilliTS();
     1352    volatile uint32_t enmCurState;
     1353
     1354    int rc = VERR_TIMEOUT;
     1355
     1356    LogFlowFunc(("enmState=%RU32, uTimeoutMS=%RU32\n", enmState, uTimeoutMS));
     1357
     1358    do
     1359    {
     1360        enmCurState = ASMAtomicReadU32(&m_enmState);
     1361        if (enmCurState == enmState)
     1362        {
     1363            rc = VINF_SUCCESS;
     1364            break;
     1365        }
     1366    }
     1367    while (RTTimeMilliTS() - uiStart < uTimeoutMS);
     1368
     1369    LogFlowThisFunc(("Returning %Rrc\n", rc));
    10481370    return rc;
    10491371}
     
    10601382bool DragInstance::waitForX11Msg(XEvent &evX, int iType, RTMSINTERVAL uTimeoutMS /* = 100 */)
    10611383{
    1062     LogFlowThisFunc(("iType=%d, uTimeoutMS=%RU32, cEventQueue=%zu\n", iType, uTimeoutMS, m_eventQueue.size()));
     1384    LogFlowThisFunc(("iType=%d, uTimeoutMS=%RU32, cEventQueue=%zu\n", iType, uTimeoutMS, m_eventQueueList.size()));
    10631385
    10641386    bool fFound = false;
     
    10681390    {
    10691391        /* Check if there is a client message in the queue. */
    1070         for (size_t i = 0; i < m_eventQueue.size(); i++)
     1392        for (size_t i = 0; i < m_eventQueueList.size(); i++)
    10711393        {
    10721394            int rc2 = RTCritSectEnter(&m_eventQueueCS);
    10731395            if (RT_SUCCESS(rc2))
    10741396            {
    1075                 XEvent e = m_eventQueue.at(i);
     1397                XEvent e = m_eventQueueList.at(i);
    10761398
    10771399                fFound = e.type == iType;
    10781400                if (fFound)
    10791401                {
    1080                     m_eventQueue.removeAt(i);
     1402                    m_eventQueueList.removeAt(i);
    10811403                    evX = e;
    10821404                }
     
    10931415            break;
    10941416
    1095         int rc2 = RTSemEventWait(m_hEventSem, 25 /* ms */);
     1417        int rc2 = RTSemEventWait(m_eventQueueEvent, 25 /* ms */);
    10961418        if (   RT_FAILURE(rc2)
    10971419            && rc2 != VERR_TIMEOUT)
     
    11161438 */
    11171439bool DragInstance::waitForX11ClientMsg(XClientMessageEvent &evMsg, Atom aType,
    1118                                        RTMSINTERVAL uTimeoutMS /*= 100 */)
     1440                                       RTMSINTERVAL uTimeoutMS /* = 100 */)
    11191441{
    11201442    LogFlowThisFunc(("aType=%s, uTimeoutMS=%RU32, cEventQueue=%zu\n",
    1121                      xAtomToString(aType).c_str(), uTimeoutMS, m_eventQueue.size()));
     1443                     xAtomToString(aType).c_str(), uTimeoutMS, m_eventQueueList.size()));
    11221444
    11231445    bool fFound = false;
     
    11261448    {
    11271449        /* Check if there is a client message in the queue. */
    1128         for (size_t i = 0; i < m_eventQueue.size(); i++)
     1450        for (size_t i = 0; i < m_eventQueueList.size(); i++)
    11291451        {
    11301452            int rc2 = RTCritSectEnter(&m_eventQueueCS);
    11311453            if (RT_SUCCESS(rc2))
    11321454            {
    1133                 XEvent e = m_eventQueue.at(i);
     1455                XEvent e = m_eventQueueList.at(i);
     1456                if (   e.type                 == ClientMessage
     1457                    && e.xclient.message_type == aType)
     1458                {
     1459                    m_eventQueueList.removeAt(i);
     1460                    evMsg = e.xclient;
     1461
     1462                    fFound = true;
     1463                }
     1464
    11341465                if (e.type == ClientMessage)
    11351466                {
    1136                     /** @todo Check is aType matches the event's type! */
    1137 
    1138                     m_eventQueue.removeAt(i);
    1139                     evMsg = e.xclient;
    1140 
    1141                     fFound = true;
     1467                    LogFlowThisFunc(("Client message: Type=%ld (%s)\n",
     1468                                     e.xclient.message_type, xAtomToString(e.xclient.message_type).c_str()));
    11421469                }
     1470                else
     1471                    LogFlowThisFunc(("X message: Type=%d\n", e.type));
    11431472
    11441473                rc2 = RTCritSectLeave(&m_eventQueueCS);
     
    11531482            break;
    11541483
    1155         int rc2 = RTSemEventWait(m_hEventSem, 25 /* ms */);
     1484        int rc2 = RTSemEventWait(m_eventQueueEvent, 25 /* ms */);
    11561485        if (   RT_FAILURE(rc2)
    11571486            && rc2 != VERR_TIMEOUT)
     
    12201549
    12211550        /* Set the DnD selection owner to our window. */
     1551        /** @todo Don't use CurrentTime -- according to ICCCM section 2.1. */
    12221552        XSetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection), m_wndProxy, CurrentTime);
    12231553
     
    12871617                                 0, 2, False, AnyPropertyType,
    12881618                                 &atmp, &fmt, &cItems, &cbRemaining, &pcData);
    1289 
    1290         if (RT_UNLIKELY(xRc != Success))
     1619        if (xRc != Success)
     1620        {
    12911621            logError("Error getting properties of cursor window=%#x: %s\n", wndCursor, gX11->xErrorToString(xRc).c_str());
     1622        }
    12921623        else
    12931624        {
    1294             if (RT_UNLIKELY(pcData == NULL || fmt != 32 || cItems != 1))
    1295                 LogFlowThisFunc(("Wrong properties: pcData=%#x, iFmt=%d, cItems=%ul\n", pcData, fmt, cItems));
     1625            if (pcData == NULL || fmt != 32 || cItems != 1)
     1626            {
     1627                /** @todo Do we need to deal with this? */
     1628                logError("Wrong window properties for window %#x: pcData=%#x, iFmt=%d, cItems=%ul\n",
     1629                         wndCursor, pcData, fmt, cItems);
     1630            }
    12961631            else
    12971632            {
    1298                 newVer = reinterpret_cast<long*>(pcData)[0];
    1299 #ifdef DEBUG
    1300                 XTextProperty propName;
    1301                 if (XGetWMName(m_pDisplay, wndCursor, &propName))
    1302                 {
    1303                     LogFlowThisFunc(("Current: wndCursor=%#x '%s', XdndAware=%ld\n", wndCursor, propName.value, newVer));
    1304                     XFree(propName.value);
    1305                 }
    1306 #endif
     1633                /* Get the current window's Xdnd version. */
     1634                newVer = reinterpret_cast<long *>(pcData)[0];
    13071635            }
    13081636
     
    13111639    }
    13121640
    1313     /*
    1314      * Is the window under the cursor another one than our current one?
    1315      * Cancel the current drop.
    1316      */
     1641#ifdef DEBUG
     1642    char *pszNameCursor = wndX11GetNameA(wndCursor);
     1643    AssertPtr(pszNameCursor);
     1644    char *pszNameCur = wndX11GetNameA(m_wndCur);
     1645    AssertPtr(pszNameCur);
     1646
     1647    LogFlowThisFunc(("wndCursor=%x ('%s', Xdnd version %ld), wndCur=%x ('%s', Xdnd version %ld)\n",
     1648                     wndCursor, pszNameCursor, newVer, m_wndCur, pszNameCur, m_curVer));
     1649
     1650    RTStrFree(pszNameCursor);
     1651    RTStrFree(pszNameCur);
     1652#endif
     1653
    13171654    if (   wndCursor != m_wndCur
    13181655        && m_curVer  != -1)
    13191656    {
    13201657        LogFlowThisFunc(("XA_XdndLeave: window=%#x\n", m_wndCur));
     1658
     1659        char *pszWndName = wndX11GetNameA(m_wndCur);
     1660        AssertPtr(pszWndName);
     1661        logInfo("Left old window %#x ('%s'), Xdnd version=%ld\n", m_wndCur, pszWndName, newVer);
     1662        RTStrFree(pszWndName);
    13211663
    13221664        /* We left the current XdndAware window. Announce this to the current indow. */
    13231665        XClientMessageEvent m;
    13241666        RT_ZERO(m);
    1325         m.type         = ClientMessage;
    1326         m.display      = m_pDisplay;
    1327         m.window       = m_wndCur;
    1328         m.message_type = xAtom(XA_XdndLeave);
    1329         m.format       = 32;
    1330         m.data.l[0]    = m_wndProxy;                    /* Source window. */
     1667        m.type                    = ClientMessage;
     1668        m.display                 = m_pDisplay;
     1669        m.window                  = m_wndCur;
     1670        m.message_type            = xAtom(XA_XdndLeave);
     1671        m.format                  = 32;
     1672        m.data.l[XdndLeaveWindow] = m_wndProxy;
    13311673
    13321674        xRc = XSendEvent(m_pDisplay, m_wndCur, False, NoEventMask, reinterpret_cast<XEvent*>(&m));
    1333         if (RT_UNLIKELY(xRc == 0))
     1675        if (xRc == 0)
    13341676            logError("Error sending XA_XdndLeave event to old window=%#x: %s\n", m_wndCur, gX11->xErrorToString(xRc).c_str());
     1677
     1678        /* Reset our current window. */
     1679        m_wndCur = 0;
     1680        m_curVer = -1;
    13351681    }
    13361682
    13371683    /*
    1338      * Do we have a new window which now is under the cursor?
     1684     * Do we have a new Xdnd-aware window which now is under the cursor?
    13391685     */
    13401686    if (   wndCursor != m_wndCur
     
    13421688    {
    13431689        LogFlowThisFunc(("XA_XdndEnter: window=%#x\n", wndCursor));
     1690
     1691        char *pszWndName = wndX11GetNameA(wndCursor);
     1692        AssertPtr(pszWndName);
     1693        logInfo("Entered new window %#x ('%s'), supports Xdnd version=%ld\n", wndCursor, pszWndName, newVer);
     1694        RTStrFree(pszWndName);
    13441695
    13451696        /*
     
    13561707        m.message_type = xAtom(XA_XdndEnter);
    13571708        m.format       = 32;
    1358         m.data.l[0]    = m_wndProxy;                    /* Source window. */
    1359         m.data.l[1]    = RT_MAKE_U32_FROM_U8(
    1360                          /* Bit 0 is set if the source supports more than three data types. */
    1361                          m_lstFormats.size() > 3 ? 1 : 0,
    1362                          /* Reserved for future use. */
    1363                          0, 0,
    1364                          /* Protocol version to use. */
    1365                          RT_MIN(VBOX_XDND_VERSION, newVer));
    1366         m.data.l[2]    = m_lstFormats.value(0, None);  /* First data type to use. */
    1367         m.data.l[3]    = m_lstFormats.value(1, None);  /* Second data type to use. */
    1368         m.data.l[4]    = m_lstFormats.value(2, None);  /* Third data type to use. */
     1709        m.data.l[XdndEnterWindow] = m_wndProxy;
     1710        m.data.l[XdndEnterFlags]  = RT_MAKE_U32_FROM_U8(
     1711                                    /* Bit 0 is set if the source supports more than three data types. */
     1712                                    m_lstFormats.size() > 3 ? RT_BIT(0) : 0,
     1713                                    /* Reserved for future use. */
     1714                                    0, 0,
     1715                                    /* Protocol version to use. */
     1716                                    RT_MIN(VBOX_XDND_VERSION, newVer));
     1717        m.data.l[XdndEnterType1]  = m_lstFormats.value(0, None); /* First data type to use. */
     1718        m.data.l[XdndEnterType2]  = m_lstFormats.value(1, None); /* Second data type to use. */
     1719        m.data.l[XdndEnterType3]  = m_lstFormats.value(2, None); /* Third data type to use. */
    13691720
    13701721        xRc = XSendEvent(m_pDisplay, wndCursor, False, NoEventMask, reinterpret_cast<XEvent*>(&m));
    1371         if (RT_UNLIKELY(xRc == 0))
     1722        if (xRc == 0)
    13721723            logError("Error sending XA_XdndEnter event to window=%#x: %s\n", wndCursor, gX11->xErrorToString(xRc).c_str());
    13731724    }
     
    13751726    if (newVer != -1)
    13761727    {
     1728        Assert(wndCursor != None);
     1729
    13771730        LogFlowThisFunc(("XA_XdndPosition: xPos=%RU32, yPos=%RU32 to window=%#x\n", u32xPos, u32yPos, wndCursor));
    13781731
     
    13901743        m.message_type = xAtom(XA_XdndPosition);
    13911744        m.format       = 32;
    1392         m.data.l[0]    = m_wndProxy;                    /* X window ID of source window. */
    1393         m.data.l[2]    = RT_MAKE_U32(u32yPos, u32xPos); /* Cursor coordinates relative to the root window. */
    1394         m.data.l[3]    = CurrentTime;                   /* Timestamp for retrieving data. */
    1395         m.data.l[4]    = pa;                            /* Actions requested by the user. */
     1745        m.data.l[XdndPositionWindow]    = m_wndProxy;                    /* X window ID of source window. */
     1746        m.data.l[XdndPositionCoords]    = RT_MAKE_U32(u32yPos, u32xPos); /* Cursor coordinates relative to the root window. */
     1747        m.data.l[XdndPositionTimeStamp] = CurrentTime;                   /* Timestamp for retrieving data. */
     1748        m.data.l[XdndPositionAction]    = pa;                            /* Actions requested by the user. */
    13961749
    13971750        xRc = XSendEvent(m_pDisplay, wndCursor, False, NoEventMask, reinterpret_cast<XEvent*>(&m));
    1398         if (RT_UNLIKELY(xRc == 0))
     1751        if (xRc == 0)
    13991752            logError("Error sending XA_XdndPosition event to current window=%#x: %s\n", wndCursor, gX11->xErrorToString(xRc).c_str());
    14001753    }
    14011754
    1402     if (   wndCursor == None
    1403         && newVer    == -1)
     1755    if (newVer == -1)
    14041756    {
    14051757        /* No window to process, so send a ignore ack event to the host. */
     
    14081760    else
    14091761    {
     1762        Assert(wndCursor != None);
     1763
    14101764        m_wndCur = wndCursor;
    1411         m_curVer = RT_MIN(VBOX_XDND_VERSION, newVer);
     1765        m_curVer = newVer;
    14121766    }
    14131767
     
    14201774 *
    14211775 * @returns IPRT status code.
    1422  */
    1423 int DragInstance::hgDrop(void)
     1776 * @param   u32xPos                 Relative X position within the guest's display area.
     1777 * @param   u32yPos                 Relative Y position within the guest's display area.
     1778 * @param   uDefaultAction          Default action the host wants to perform on the guest
     1779 *                                  as soon as the operation successfully finishes.
     1780 */
     1781int DragInstance::hgDrop(uint32_t u32xPos, uint32_t u32yPos, uint32_t uDefaultAction)
    14241782{
    14251783    LogFlowThisFunc(("wndCur=%#x, wndProxy=%#x, mode=%RU32, state=%RU32\n", m_wndCur, m_wndProxy, m_enmMode, m_enmState));
     1784    LogFlowThisFunc(("u32xPos=%RU32, u32yPos=%RU32, uAction=%RU32\n", u32xPos, u32yPos, uDefaultAction));
    14261785
    14271786    if (   m_enmMode  != HG
     
    14311790    }
    14321791
     1792    /* Set the state accordingly. */
     1793    m_enmState = Dropped;
     1794
     1795    /*
     1796     * Ask the host to send the raw data, as we don't (yet) know which format
     1797     * the guest exactly expects. As blocking in a SelectionRequest message turned
     1798     * out to be very unreliable (e.g. with KDE apps) we request to start transferring
     1799     * file/directory data (if any) here.
     1800     */
     1801    char szFormat[] = { "text/uri-list" };
     1802
     1803    int rc = VbglR3DnDHGRequestData(&m_dndCtx, szFormat);
     1804    logInfo("Drop event from host resuled in: %Rrc\n", rc);
     1805
     1806    LogFlowFuncLeaveRC(rc);
     1807    return rc;
     1808}
     1809
     1810/**
     1811 * Host -> Guest: Event signalling that the host has finished sending drag'n drop
     1812 *                data to the guest for further processing.
     1813 *
     1814 * @returns IPRT status code.
     1815 * @param   pvData                  Pointer to (MIME) data from host.
     1816 * @param   cbData                  Size (in bytes) of data from host.
     1817 */
     1818int DragInstance::hgDataReceived(const void *pvData, uint32_t cbData)
     1819{
     1820    LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState));
     1821    LogFlowThisFunc(("pvData=%p, cbData=%RU32\n", pvData, cbData));
     1822
     1823    if (   m_enmMode  != HG
     1824        || m_enmState != Dropped)
     1825    {
     1826        return VERR_INVALID_STATE;
     1827    }
     1828
     1829    if (   pvData == NULL
     1830        || cbData == 0)
     1831    {
     1832        return VERR_INVALID_PARAMETER;
     1833    }
     1834
    14331835    int rc = VINF_SUCCESS;
    14341836
    14351837    /*
    1436      * Send a drop event to the current window and reset our DnD status.
     1838     * At this point all data needed (including sent files/directories) should
     1839     * be on the guest, so proceed working on communicating with the target window.
     1840     */
     1841    logInfo("Received %RU32 bytes MIME data from host\n", cbData);
     1842
     1843    /* Destroy any old data. */
     1844    if (m_pvSelReqData)
     1845    {
     1846        Assert(m_cbSelReqData);
     1847
     1848        RTMemFree(m_pvSelReqData); /** @todo RTMemRealloc? */
     1849        m_cbSelReqData = 0;
     1850    }
     1851
     1852    /** @todo Handle incremental transfers. */
     1853
     1854    /* Make a copy of the data. This data later then will be used to fill into
     1855     * the selection request. */
     1856    if (cbData)
     1857    {
     1858        m_pvSelReqData = RTMemAlloc(cbData);
     1859        if (!m_pvSelReqData)
     1860            return VERR_NO_MEMORY;
     1861
     1862        memcpy(m_pvSelReqData, pvData, cbData);
     1863        m_cbSelReqData = cbData;
     1864    }
     1865
     1866    /*
     1867     * Send a drop event to the current window (target).
     1868     * This window in turn then will raise a SelectionRequest message to our proxy window,
     1869     * which we will handle in our onX11SelectionRequest handler.
     1870     *
     1871     * The SelectionRequest will tell us in which format the target wants the data from the host.
    14371872     */
    14381873    XClientMessageEvent m;
     
    14431878    m.message_type = xAtom(XA_XdndDrop);
    14441879    m.format       = 32;
    1445     m.data.l[0]    = m_wndProxy;                        /* Source window. */
    1446     m.data.l[2]    = CurrentTime;                       /* Timestamp. */
    1447 
    1448     int xRc = XSendEvent(m_pDisplay, m_wndCur, False, NoEventMask, reinterpret_cast<XEvent*>(&m));
    1449     if (RT_UNLIKELY(xRc == 0))
    1450         logError("Error sending XA_XdndDrop event to wndCur=%#x: %s\n", m_wndCur, gX11->xErrorToString(xRc).c_str());
    1451 
    1452     m_wndCur = None;
    1453     m_curVer = -1;
    1454 
    1455     m_enmState = Dropped;
     1880    m.data.l[XdndDropWindow]    = m_wndProxy;  /* Source window. */
     1881    m.data.l[XdndDropFlags]     = 0;           /* Reserved for future use. */
     1882    m.data.l[XdndDropTimeStamp] = CurrentTime; /* Our DnD data does not rely on any timing, so just use the current time. */
     1883
     1884    int xRc = XSendEvent(m_pDisplay, m_wndCur, False /* Propagate */, NoEventMask, reinterpret_cast<XEvent*>(&m));
     1885    if (xRc == 0)
     1886        logError("Error sending XA_XdndDrop event to window=%#x: %s\n", m_wndCur, gX11->xErrorToString(xRc).c_str());
     1887    XFlush(m_pDisplay);
    14561888
    14571889    LogFlowFuncLeaveRC(rc);
     
    14591891}
    14601892
    1461 /**
    1462  * Host -> Guest: Event signalling that the host has sent drag'n drop (MIME) data
    1463  *                to the guest for further processing.
    1464  *
    1465  * @returns IPRT status code.
    1466  * @param   pvData                  Pointer to (MIME) data from host.
    1467  * @param   cbData                  Size (in bytes) of data from host.
    1468  */
    1469 int DragInstance::hgDataReceived(const void *pvData, uint32_t cbData)
    1470 {
    1471     LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState));
    1472 
    1473     if (   m_enmMode  != HG
    1474         || m_enmState != Dropped)
    1475     {
    1476         return VERR_INVALID_STATE;
    1477     }
    1478 
    1479     if (RT_UNLIKELY(   pvData == NULL
    1480                     || cbData  == 0))
    1481     {
    1482         return VERR_INVALID_PARAMETER;
    1483     }
    1484 
    1485     /* Make a copy of the data. The X server will become the new owner. */
    1486     void *pvNewData = RTMemAlloc(cbData);
    1487     if (RT_UNLIKELY(!pvNewData))
    1488         return VERR_NO_MEMORY;
    1489 
    1490     memcpy(pvNewData, pvData, cbData);
    1491 
    1492     /*
    1493      * The host has sent us the DnD data in the requested MIME type. This allows us
    1494      * to fill the XdndSelection property of the requestor window with the data
    1495      * and afterwards inform the host about the new status.
    1496      */
    1497     XEvent s;
    1498     RT_ZERO(s);
    1499     s.xselection.type      = SelectionNotify;
    1500     s.xselection.display   = m_eventHgSelection.xselection.display;
    1501 //    s.xselection.owner     = m_selEvent.xselectionrequest.owner;
    1502     s.xselection.time      = m_eventHgSelection.xselectionrequest.time;
    1503     s.xselection.selection = m_eventHgSelection.xselectionrequest.selection;
    1504     s.xselection.requestor = m_eventHgSelection.xselectionrequest.requestor;
    1505     s.xselection.target    = m_eventHgSelection.xselectionrequest.target;
    1506     s.xselection.property  = m_eventHgSelection.xselectionrequest.property;
    1507 
    1508     LogFlowThisFunc(("owner=%#x, requestor=%#x, sel_atom=%s, target_atom=%s, prop_atom=%s, time=%u\n",
    1509                      m_eventHgSelection.xselectionrequest.owner,
    1510                      s.xselection.requestor,
    1511                      xAtomToString(s.xselection.selection).c_str(),
    1512                      xAtomToString(s.xselection.target).c_str(),
    1513                      xAtomToString(s.xselection.property).c_str(),
    1514                      s.xselection.time));
    1515 
    1516     /* Fill up the property with the data. */
    1517     XChangeProperty(s.xselection.display, s.xselection.requestor, s.xselection.property, s.xselection.target, 8, PropModeReplace,
    1518                     reinterpret_cast<const unsigned char*>(pvNewData), cbData);
    1519     int xRc = XSendEvent(s.xselection.display, s.xselection.requestor, True, 0, &s);
    1520     if (RT_UNLIKELY(xRc == 0))
    1521         logError("Error sending SelectionNotify(2) event to window=%#x: %s\n",
    1522                  s.xselection.requestor, gX11->xErrorToString(xRc).c_str());
    1523 
    1524     /* We're finally done, reset. */
    1525     reset();
    1526 
    1527     return VINF_SUCCESS;
    1528 }
    1529 
    15301893#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    15311894/**
     
    15391902    LogFlowThisFunc(("mode=%RU32, state=%RU32\n", m_enmMode, m_enmState));
    15401903
     1904    /* Currently in wrong mode? Bail out. */
    15411905    if (m_enmMode == HG)
    15421906        return VERR_INVALID_STATE;
    15431907
     1908    /* Message already processed successfully? */
     1909    if (   m_enmMode  == GH
     1910        && (   m_enmState == Dragging
     1911            || m_enmState == Dropped)
     1912       )
     1913    {
     1914        return VERR_INVALID_STATE;
     1915    }
     1916
    15441917    int rc = VINF_SUCCESS;
     1918
     1919    /* Determine the current window which currently has the XdndSelection set. */
    15451920    Window wndSelection = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection));
    1546     LogFlowThisFunc(("Checking pending wndSelection=%#x, wndProxy=%#x\n", wndSelection, m_wndProxy));
    1547 
    1548     /* Is this another window which has a Xdnd selection than our current one? */
     1921    LogFlowThisFunc(("wndSelection=%#x, wndProxy=%#x, wndCur=%#x\n", wndSelection, m_wndProxy, m_wndCur));
     1922
     1923    RTCString strFormats = "None"; /** @todo If empty, IOCTL fails with VERR_ACCESS_DENIED. */
     1924    uint32_t uDefAction  = DND_IGNORE_ACTION;
     1925    uint32_t uAllActions = DND_IGNORE_ACTION;
     1926
     1927    /* Is this another window which has a Xdnd selection and not our proxy window? */
    15491928    if (   wndSelection
    1550         && wndSelection != m_wndProxy)
    1551     {
     1929        && wndSelection != m_wndCur)
     1930    {
     1931#ifdef DEBUG
     1932        char *pszWndName = wndX11GetNameA(wndSelection);
     1933        AssertPtr(pszWndName);
     1934        LogFlowThisFunc(("*** New source window ('%s') ***\n", pszWndName));
     1935        RTStrFree(pszWndName);
     1936#endif
     1937        /* Start over. */
     1938        reset();
     1939
    15521940        /* Map the window on the current cursor position, which should provoke
    15531941         * an XdndEnter event. */
    1554         proxyWinShow(NULL, NULL, true);
    1555 
    1556         XEvent e;
    1557         if (waitForX11Msg(e, ClientMessage))
     1942        rc = proxyWinShow(NULL, NULL);
     1943        if (RT_SUCCESS(rc))
    15581944        {
    1559             bool fAcceptDrop = false;
    1560 
    1561             int xRc;
    1562             XClientMessageEvent *pEventClient = reinterpret_cast<XClientMessageEvent*>(&e);
    1563             AssertPtr(pEventClient);
    1564 
    1565             LogFlowThisFunc(("Received event=%s\n",
    1566                              gX11->xAtomToString(pEventClient->message_type).c_str()));
    1567 
    1568             if (pEventClient->message_type == xAtom(XA_XdndEnter))
    1569             {
    1570                 LogFlowThisFunc(("XA_XdndEnter\n"));
    1571 
    1572                 /*
    1573                  * Prepare everything for our new window.
    1574                  */
    1575                 reset();
    1576 
    1577                 /*
    1578                  * Update our state and the window handle to process.
    1579                  */
    1580                 m_enmMode   = GH;
    1581                 m_enmState  = Dragging;
    1582                 m_wndCur    = wndSelection;
    1583                 Assert(m_wndCur == (Window)pEventClient->data.l[0]);
    1584 #ifdef DEBUG
    1585                 XWindowAttributes xwa;
    1586                 XGetWindowAttributes(m_pDisplay, m_wndCur, &xwa);
    1587                 LogFlowThisFunc(("m_wndCur=%#x, x=%d, y=%d, width=%d, height=%d\n",
    1588                                  m_wndCur, xwa.x, xwa.y, xwa.width, xwa.height));
    1589 #endif
    1590                 /* Check if the MIME types are in the message itself or if we need
    1591                  * to fetch the XdndTypeList property from the window. */
    1592                 if (!ASMBitTest(&pEventClient->data.l[1], 0))
    1593                 {
    1594                     for (int i = 2; i < 5; ++i)
    1595                     {
    1596                         LogFlowThisFunc(("Received format via message: %s\n",
    1597                                          gX11->xAtomToString(pEventClient->data.l[i]).c_str()));
    1598 
    1599                         m_lstFormats.append(pEventClient->data.l[i]);
    1600                     }
    1601                 }
    1602                 else
    1603                 {
    1604                     rc = wndXDnDGetFormatList(wndSelection, m_lstFormats);
    1605                 }
    1606 
    1607                 /*
    1608                  * Fetch the actions.
    1609                  */
    1610                 rc = wndXDnDGetActionList(wndSelection, m_lstActions);
    1611 
    1612                 fAcceptDrop = true;
    1613             }
    1614             /* Did the source tell us where the cursor currently is? */
    1615             else if (pEventClient->message_type == xAtom(XA_XdndPosition))
    1616             {
    1617                 LogFlowThisFunc(("XA_XdndPosition\n"));
    1618                 fAcceptDrop = true;
    1619             }
    1620             else if (pEventClient->message_type == xAtom(XA_XdndLeave))
    1621             {
    1622                 LogFlowThisFunc(("XA_XdndLeave\n"));
    1623             }
    1624 
    1625             if (fAcceptDrop)
    1626             {
    1627                 /* Reply with a XdndStatus message to tell the source whether
    1628                  * the data can be dropped or not. */
    1629                 XClientMessageEvent m;
    1630                 RT_ZERO(m);
    1631                 m.type         = ClientMessage;
    1632                 m.display      = m_pDisplay;
    1633                 m.window       = m_wndCur;
    1634                 m.message_type = xAtom(XA_XdndStatus);
    1635                 m.format       = 32;
    1636                 m.data.l[0]    = m_wndProxy;
    1637                 m.data.l[1]    = RT_BIT(0); /* Accept the drop. */
    1638                 m.data.l[4]    = xAtom(XA_XdndActionCopy); /** @todo Make the accepted action configurable. */
    1639 
    1640                 xRc = XSendEvent(m_pDisplay, m_wndCur,
    1641                                  False, 0, reinterpret_cast<XEvent*>(&m));
    1642                 if (RT_UNLIKELY(xRc == 0))
    1643                 {
    1644                     logError("Error sending position XA_XdndStatus event to current window=%#x: %s\n",
    1645                               m_wndCur, gX11->xErrorToString(xRc).c_str());
    1646                 }
    1647             }
     1945            /* Wait until we're in "Dragging" state. */
     1946            rc = waitForStatusChange(Dragging, 5 * 1000);
     1947            if (RT_SUCCESS(rc))
     1948                m_enmMode = GH;
    16481949        }
    1649 
    1650         /* Do we need to acknowledge at least one format to the host? */
    1651         if (!m_lstFormats.isEmpty())
    1652         {
    1653             RTCString strFormats = gX11->xAtomListToString(m_lstFormats);
    1654             uint32_t uDefAction = DND_COPY_ACTION; /** @todo Handle default action! */
    1655             uint32_t uAllActions = toHGCMActions(m_lstActions);
    1656 
    1657             rc = VbglR3DnDGHAcknowledgePending(&m_dndCtx, uDefAction, uAllActions, strFormats.c_str());
    1658             LogFlowThisFunc(("Acknowledging m_uClientID=%RU32, allActions=0x%x, strFormats=%s, rc=%Rrc\n",
    1659                              m_dndCtx.uClientID, uAllActions, strFormats.c_str(), rc));
    1660         }
    1661     }
     1950    }
     1951    else
     1952        RTThreadSleep(3000);
     1953
     1954    /*
     1955     * Acknowledge to the host in any case, regardless
     1956     * if something failed here or not. Be responsive.
     1957     */
     1958
     1959    int rc2 = RTCritSectEnter(&m_dataCS);
     1960    if (RT_SUCCESS(rc2))
     1961    {
     1962        strFormats   = gX11->xAtomListToString(m_lstFormats);
     1963        uDefAction   = DND_COPY_ACTION; /** @todo Handle default action! */
     1964        uAllActions  = DND_COPY_ACTION; /** @todo Ditto. */
     1965        uAllActions |= toHGCMActions(m_lstActions);
     1966
     1967        RTCritSectLeave(&m_dataCS);
     1968    }
     1969
     1970    rc2 = VbglR3DnDGHAcknowledgePending(&m_dndCtx, uDefAction, uAllActions, strFormats.c_str());
     1971    LogFlowThisFunc(("Pending status to host: uClientID=%RU32, uDefAction=0x%x, allActions=0x%x, strFormats=%s, rc=%Rrc\n",
     1972                     m_dndCtx.uClientID, uDefAction, uAllActions, strFormats.c_str(), rc2));
     1973    if (RT_SUCCESS(rc))
     1974        rc = rc2;
     1975
     1976    if (RT_FAILURE(rc)) /* Start over on failure. */
     1977        reset();
    16621978
    16631979    LogFlowFuncLeaveRC(rc);
     
    16781994                     m_enmMode, m_enmState, strFormat.c_str(), uAction));
    16791995
    1680     if (   m_enmMode  != GH
    1681         || m_enmState != Dragging)
     1996    /* Currently in wrong mode? Bail out. */
     1997    if (   m_enmMode == Unknown
     1998        || m_enmMode == HG)
    16821999    {
    16832000        return VERR_INVALID_STATE;
    16842001    }
    16852002
     2003    if (   m_enmMode  == GH
     2004        && m_enmState != Dragging)
     2005    {
     2006        return VERR_INVALID_STATE;
     2007    }
     2008
    16862009    int rc = VINF_SUCCESS;
    16872010
    16882011    m_enmState = Dropped;
    16892012
    1690     /* Show the proxy window, so that the source will find it. */
     2013    /* Show the proxy window, so that the current source window will find it. */
    16912014    int iRootX, iRootY;
    16922015    proxyWinShow(&iRootX, &iRootY);
    1693     XFlush(m_pDisplay);
    16942016
    16952017#ifdef DEBUG
    16962018    XWindowAttributes xwa;
    16972019    XGetWindowAttributes(m_pDisplay, m_wndCur, &xwa);
    1698     LogFlowThisFunc(("wndCur=%#x, x=%d, y=%d, width=%d, height=%d\n", m_wndCur, xwa.x, xwa.y, xwa.width, xwa.height));
     2020    LogFlowThisFunc(("wndProxy=%#x, wndCur=%#x, x=%d, y=%d, width=%d, height=%d\n",
     2021                     m_wndProxy, m_wndCur, xwa.x, xwa.y, xwa.width, xwa.height));
    16992022#endif
    17002023
    17012024    /* We send a fake release event to the current window, cause
    17022025     * this should have the grab. */
    1703     mouseButtonSet(m_wndCur /* Destination window */, iRootX, iRootY,
    1704                    1 /* Button */, false /* fPress */);
     2026#if 0
     2027    //mouseButtonSet(m_wndCur /* Destination window */, xwa.x + (xwa.width / 2), xwa.y + (xwa.height / 2), 1 /* Button */, false /* fPress */);
     2028#else
     2029    mouseButtonSet(m_wndCur /* Destination window */, -1 /* Root X */, -1 /* Root Y */, 1 /* Button */, false /* fPress */);
     2030#endif
    17052031
    17062032    /**
    17072033     * The fake button release event above should lead to a XdndDrop event from the
    1708      * source. Because of showing our proxy window, other Xdnd events can
     2034     * source window. Because of showing our proxy window, other Xdnd events can
    17092035     * occur before, e.g. a XdndPosition event. We are not interested
    17102036     * in those, so just try to get the right one.
     
    17122038
    17132039    XClientMessageEvent evDnDDrop;
    1714     bool fDrop = waitForX11ClientMsg(evDnDDrop, xAtom(XA_XdndDrop), 5 * 1000 /* Timeout in ms */);
     2040    bool fDrop = waitForX11ClientMsg(evDnDDrop, xAtom(XA_XdndDrop), 5 * 1000 /* 5s timeout */);
    17152041    if (fDrop)
    17162042    {
     
    17192045        /* Request to convert the selection in the specific format and
    17202046         * place it to our proxy window as property. */
    1721         Window wndSource = evDnDDrop.data.l[0]; /* Source window which has sent the message. */
     2047        Assert(evDnDDrop.message_type == xAtom(XA_XdndDrop));
     2048
     2049        Window wndSource = evDnDDrop.data.l[XdndDropWindow]; /* Source window which has sent the message. */
    17222050        Assert(wndSource == m_wndCur);
    1723         Atom aFormat  = gX11->stringToxAtom(strFormat.c_str());
     2051
     2052        Atom aFormat     = gX11->stringToxAtom(strFormat.c_str());
     2053
     2054        Time tsDrop;
     2055        if (m_curVer >= 1)
     2056            tsDrop = evDnDDrop.data.l[XdndDropTimeStamp];
     2057        else
     2058            tsDrop = CurrentTime;
    17242059
    17252060        XConvertSelection(m_pDisplay, xAtom(XA_XdndSelection), aFormat, xAtom(XA_XdndSelection),
    1726                           m_wndProxy, evDnDDrop.data.l[2]);
     2061                          m_wndProxy, tsDrop);
    17272062
    17282063        /* Wait for the selection notify event. */
    17292064        XEvent evSelNotify;
    17302065        RT_ZERO(evSelNotify);
    1731         if (waitForX11Msg(evSelNotify, SelectionNotify))
     2066        if (waitForX11Msg(evSelNotify, SelectionNotify, 5 * 1000 /* 5s timeout */))
    17322067        {
    17332068            bool fCancel = false;
     
    17532088                                             AnyPropertyType,         /* Property type */
    17542089                                             &aPropType, &iPropFormat, &cItems, &cbRemaining, &pcData);
    1755                 if (RT_UNLIKELY(xRc != Success))
    1756                     LogFlowThisFunc(("Error getting XA_XdndSelection property of proxy window=%#x: %s\n",
    1757                                      m_wndProxy, gX11->xErrorToString(xRc).c_str()));
     2090                if (xRc != Success)
     2091                    logError("Error getting XA_XdndSelection property of proxy window=%#x: %s\n",
     2092                             m_wndProxy, gX11->xErrorToString(xRc).c_str());
    17582093
    17592094                LogFlowThisFunc(("strType=%s, iPropFormat=%d, cItems=%RU32, cbRemaining=%RU32\n",
     
    17972132                    if (RT_SUCCESS(rc))
    17982133                    {
     2134                        /* Was the drop accepted by the host? That is, anything than ignoring. */
     2135                        bool fDropAccepted = uAction > DND_IGNORE_ACTION;
     2136
    17992137                        /* Confirm the result of the transfer to the target window. */
    18002138                        XClientMessageEvent m;
     
    18052143                        m.message_type = xAtom(XA_XdndFinished);
    18062144                        m.format       = 32;
    1807                         m.data.l[0]    = m_wndProxy;                   /* Target window. */
    1808                         m.data.l[1]    = 0;                            /* Don't accept the drop to not make the guest stuck. */
    1809                         m.data.l[2]    = RT_SUCCESS(rc)
    1810                                        ? toAtomAction(uAction) : None; /* Action used on success */
     2145                        m.data.l[XdndFinishedWindow] = m_wndProxy;                                   /* Target window. */
     2146                        m.data.l[XdndFinishedFlags]  = fDropAccepted ? RT_BIT(0) : 0;                /* Was the drop accepted? */
     2147                        m.data.l[XdndFinishedAction] = fDropAccepted ? toAtomAction(uAction) : None; /* Action used on accept. */
    18112148
    18122149                        xRc = XSendEvent(m_pDisplay, wndSource, True, NoEventMask, reinterpret_cast<XEvent*>(&m));
    1813                         if (RT_UNLIKELY(xRc == 0))
    1814                             LogFlowThisFunc(("Error sending XA_XdndFinished event to proxy window=%#x: %s\n",
    1815                                              m_wndProxy, gX11->xErrorToString(xRc).c_str()));
     2150                        if (xRc == 0)
     2151                            logError("Error sending XA_XdndFinished event to source window=%#x: %s\n",
     2152                                     wndSource, gX11->xErrorToString(xRc).c_str());
    18162153                    }
    18172154                    else
     
    18232160                    {
    18242161                        /** @todo Support incremental transfers. */
    1825                         AssertMsgFailed(("Incrementally transfers are not supported yet\n"));
     2162                        AssertMsgFailed(("Incremental transfers are not supported yet\n"));
     2163
     2164                        logError("Incremental transfers are not supported yet\n");
    18262165                        rc = VERR_NOT_IMPLEMENTED;
    18272166                    }
    18282167                    else
    18292168                    {
    1830                         LogFlowFunc(("Not supported data type: %s\n", gX11->xAtomToString(aPropType).c_str()));
     2169                        logError("Not supported data type: %s\n", gX11->xAtomToString(aPropType).c_str());
    18312170                        rc = VERR_NOT_SUPPORTED;
    18322171                    }
     
    18392178                    LogFlowFunc(("Cancelling drop ...\n"));
    18402179
    1841                     /* Cancel the operation -- inform the source window. */
     2180                    /* Cancel the operation -- inform the source window by
     2181                     * sending a XdndFinished message so that the source can toss the required data. */
    18422182                    XClientMessageEvent m;
    18432183                    RT_ZERO(m);
     
    18452185                    m.display      = m_pDisplay;
    18462186                    m.window       = m_wndProxy;
    1847                     m.message_type = xAtom(XA_XdndLeave);
     2187                    m.message_type = xAtom(XA_XdndFinished);
    18482188                    m.format       = 32;
    1849                     m.data.l[0]    = wndSource;         /* Source window. */
     2189                    m.data.l[XdndFinishedWindow] = m_wndProxy; /* Target window. */
     2190                    m.data.l[XdndFinishedFlags]  = 0;          /* Did not accept the drop. */
     2191                    m.data.l[XdndFinishedAction] = None;       /* Action used on accept. */
    18502192
    18512193                    xRc = XSendEvent(m_pDisplay, wndSource, False, NoEventMask, reinterpret_cast<XEvent*>(&m));
    1852                     if (RT_UNLIKELY(xRc == 0))
    1853                     {
    1854                         logError("Error sending XA_XdndLeave event to proxy window=%#x: %s\n",
    1855                                   m_wndProxy, gX11->xErrorToString(xRc).c_str());
    1856                     }
     2194                    if (xRc == 0)
     2195                        logError("Error sending XA_XdndFinished event to source window=%#x: %s\n",
     2196                                  wndSource, gX11->xErrorToString(xRc).c_str());
    18572197                }
    18582198
     
    18742214    {
    18752215        int rc2 = VbglR3DnDGHSendError(&m_dndCtx, rc);
    1876         AssertRC(rc2);
     2216        LogFlowThisFunc(("Sending error to host resulted in %Rrc\n", rc2));
     2217        /* This is not fatal for us, just ignore. */
    18772218    }
    18782219
    18792220    /* At this point, we have either successfully transfered any data or not.
    1880      * So reset our internal state because we are done here for this transaction. */
     2221     * So reset our internal state because we are done here for the current (ongoing)
     2222     * drag and drop operation. */
    18812223    reset();
    18822224
     
    19382280
    19392281        int xRc = XTestFakeButtonEvent(m_pDisplay, 1, fPress ? True : False, CurrentTime);
    1940         if (RT_UNLIKELY(xRc == 0))
     2282        if (Rc == 0)
    19412283            logError("Error sending XTestFakeButtonEvent event: %s\n", gX11->xErrorToString(xRc).c_str());
    19422284        XFlush(m_pDisplay);
     
    19452287    {
    19462288#endif
    1947         LogFlowThisFunc(("XText extension not available or disabled\n"));
     2289        LogFlowThisFunc(("Note: XText extension not available or disabled\n"));
     2290
     2291        if (   rx == -1
     2292            && ry == -1)
     2293        {
     2294            Window wndTemp, wndChild;
     2295            int wx, wy; unsigned int mask;
     2296            XQueryPointer(m_pDisplay, m_wndRoot, &wndTemp, &wndChild, &rx, &ry, &wx, &wy, &mask);
     2297            LogFlowThisFunc(("cursorRootX=%d, cursorRootY=%d\n", rx, ry));
     2298        }
    19482299
    19492300        XButtonEvent eBtn;
     
    19672318        eBtn.y_root       = ry;
    19682319
    1969         //XTranslateCoordinates(m_pDisplay, eBtn.root, eBtn.window, eBtn.x_root, eBtn.y_root, &eBtn.x, &eBtn.y, &eBtn.subwindow);
    1970 #if 0
    1971         int xRc = XSendEvent(m_pDisplay, eBtn.window, True /* fPropagate */,
     2320        XTranslateCoordinates(m_pDisplay, eBtn.root, eBtn.window, eBtn.x_root, eBtn.y_root, &eBtn.x, &eBtn.y, &eBtn.subwindow);
     2321        LogFlowThisFunc(("x=%d, y=%d\n", eBtn.x, eBtn.y));
     2322#if 1
     2323        int xRc = XSendEvent(m_pDisplay, wndDest, True /* fPropagate */,
    19722324                               fPress
    19732325                             ? ButtonPressMask : ButtonReleaseMask,
    19742326                             reinterpret_cast<XEvent*>(&eBtn));
     2327        if (xRc == 0)
     2328            logError("Error sending XButtonEvent event to window=%#x: %s\n", wndDest, gX11->xErrorToString(xRc).c_str());
    19752329#else
    19762330        int xRc = XSendEvent(m_pDisplay, eBtn.window, False /* fPropagate */,
    19772331                             0 /* Mask */, reinterpret_cast<XEvent*>(&eBtn));
    1978         if (RT_UNLIKELY(xRc == 0))
     2332        if (xRc == 0)
    19792333            logError("Error sending XButtonEvent event to window=%#x: %s\n", wndDest, gX11->xErrorToString(xRc).c_str());
    1980 #endif
    1981 
    1982 #ifdef DEBUG
    1983         Window wndTemp, wndChild;
    1984         int wx, wy; unsigned int mask;
    1985         XQueryPointer(m_pDisplay, m_wndRoot, &wndTemp, &wndChild, &rx, &ry, &wx, &wy, &mask);
    1986         LogFlowThisFunc(("cursorRootX=%d, cursorRootY=%d\n", rx, ry));
    19872334#endif
    19882335
     
    20042351 * @param   piRootX                 X coordinate relative to the root window's origin. Optional.
    20052352 * @param   piRootY                 Y coordinate relative to the root window's origin. Optional.
    2006  * @param   fMouseMove              Whether to move the mouse cursor to the root window's origin or not.
    2007  */
    2008 int DragInstance::proxyWinShow(int *piRootX /*= NULL*/,
    2009                                int *piRootY /*= NULL*/,
    2010                                bool fMouseMove /*= false */) const
     2353 */
     2354int DragInstance::proxyWinShow(int *piRootX /* = NULL */, int *piRootY /* = NULL */) const
    20112355{
    20122356    /* piRootX is optional. */
     
    20182362
    20192363#if 0
     2364# ifdef VBOX_DND_WITH_XTEST
    20202365    XTestGrabControl(m_pDisplay, False);
     2366# endif
    20212367#endif
    20222368
     
    20282374    Window wndRoot, wndChild;
    20292375    Bool fInRootWnd = XQueryPointer(m_pDisplay, m_wndRoot, &wndRoot, &wndChild,
    2030                                     &iRootX, &iRootY,
    2031                                     &iChildX, &iChildY, &iMask);
     2376                                    &iRootX, &iRootY, &iChildX, &iChildY, &iMask);
    20322377
    20332378    LogFlowThisFunc(("fInRootWnd=%RTbool, wndRoot=0x%x, wndChild=0x%x, iRootX=%d, iRootY=%d\n",
     
    20472392    /* Spawn our proxy window over the entire screen, making it an easy drop target for the host's cursor. */
    20482393    int iScreenID = XDefaultScreen(m_pDisplay);
     2394    LogFlowThisFunc(("Proxy window screenID=%d, x=%d, y=%d, width=%d, height=%d\n",
     2395                     iScreenID, 0, 0, XDisplayWidth(m_pDisplay, iScreenID), XDisplayHeight(m_pDisplay, iScreenID)));
    20492396    XMoveResizeWindow(m_pDisplay, m_wndProxy, 0, 0, XDisplayWidth(m_pDisplay, iScreenID), XDisplayHeight(m_pDisplay, iScreenID));
    20502397    /** @todo What about multiple screens? Test this! */
    20512398
    2052     if (fMouseMove)
    2053         rc = mouseCursorMove(iRootX, iRootY);
     2399    XFlush(m_pDisplay);
    20542400
    20552401    XSynchronize(m_pDisplay, False /* Disable sync */);
    20562402
    20572403#if 0
     2404# ifdef VBOX_DND_WITH_XTEST
    20582405    XTestGrabControl(m_pDisplay, True);
     2406# endif
    20592407#endif
    20602408
     2409    LogFlowFuncLeaveRC(rc);
    20612410    return rc;
    20622411}
     
    20692418    LogFlowFuncEnter();
    20702419
    2071 #ifndef VBOX_DND_DEBUG_WND
    20722420    XUnmapWindow(m_pDisplay, m_wndProxy);
    2073 #endif
    2074     m_eventQueue.clear();
     2421    XFlush(m_pDisplay);
     2422
     2423    m_eventQueueList.clear();
    20752424
    20762425    return VINF_SUCCESS; /** @todo Add error checking. */
     2426}
     2427
     2428/**
     2429 * Allocates the name (title) of an X window.
     2430 * The returned pointer must be freed using RTStrFree().
     2431 *
     2432 * @returns Pointer to the allocated window name.
     2433 * @param   wndThis                 Window to retrieve name for.
     2434 *
     2435 * @remark If the window title is not available, the text
     2436 *         "<No name>" will be returned.
     2437 */
     2438char *DragInstance::wndX11GetNameA(Window wndThis) const
     2439{
     2440    char *pszName = NULL;
     2441
     2442    XTextProperty propName;
     2443    if (XGetWMName(m_pDisplay, wndThis, &propName))
     2444    {
     2445        if (propName.value)
     2446            pszName = RTStrDup((char *)propName.value); /** @todo UTF8? */
     2447        XFree(propName.value);
     2448    }
     2449
     2450    if (!pszName) /* No window name found? */
     2451        pszName = RTStrDup("<No name>");
     2452
     2453    return pszName;
    20772454}
    20782455
     
    21232500    }
    21242501
    2125     if (   cItems > 0
    2126         && pcbData)
    2127     {
     2502    LogFlowThisFunc(("wndThis=%#x, cItems=%RU32, pcbData=%p\n", wndThis, cItems, pcbData));
     2503
     2504    if (cItems > 0)
     2505    {
     2506        AssertPtr(pcbData);
    21282507        Atom *paData = reinterpret_cast<Atom *>(pcbData);
    21292508
    21302509        for (unsigned i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, cItems); i++)
    21312510        {
    2132             LogFlowThisFunc(("Received action: %s\n",
    2133                              gX11->xAtomToString(paData[i]).c_str()));
    2134 
     2511            LogFlowThisFunc(("\t%s\n", gX11->xAtomToString(paData[i]).c_str()));
    21352512            lstActions.append(paData[i]);
    21362513        }
     
    21672544    }
    21682545
    2169     if (   cItems > 0
    2170         && pcbData)
    2171     {
    2172         Atom *paData = reinterpret_cast<Atom*>(pcbData);
     2546    LogFlowThisFunc(("wndThis=%#x, cItems=%RU32, pcbData=%p\n", wndThis, cItems, pcbData));
     2547
     2548    if (cItems > 0)
     2549    {
     2550        AssertPtr(pcbData);
     2551        Atom *paData = reinterpret_cast<Atom *>(pcbData);
    21732552
    21742553        for (unsigned i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, cItems); i++)
    21752554        {
    2176             LogFlowThisFunc(("Received format via XdndTypeList: %s\n",
    2177                              gX11->xAtomToString(paData[i]).c_str()));
    2178 
     2555            LogFlowThisFunc(("\t%s\n", gX11->xAtomToString(paData[i]).c_str()));
    21792556            lstTypes.append(paData[i]);
    21802557        }
     
    22202597{
    22212598    if (lstFormats.isEmpty())
    2222         return VINF_SUCCESS;
     2599        return VERR_INVALID_PARAMETER;
    22232600
    22242601    /* We support TARGETS and the data types. */
     
    23612738    uint32_t uActions = DND_IGNORE_ACTION;
    23622739
    2363     for (size_t i = 0; i < lstActions.size(); ++i)
     2740    for (size_t i = 0; i < lstActions.size(); i++)
    23642741        uActions |= toHGCMAction(lstActions.at(i));
    23652742
     
    24062783
    24072784        LogRel(("DnD: Started\n"));
     2785        LogRel2(("DnD: %sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr()));
    24082786
    24092787        /* Enter the main event processing loop. */
     
    24562834                    case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
    24572835                    {
    2458                         rc = m_pCurDnD->hgDrop();
     2836                        rc = m_pCurDnD->hgDrop(e.hgcm.u.a.uXpos, e.hgcm.u.a.uYpos, e.hgcm.u.a.uDefAction);
    24592837                        break;
    24602838                    }
     
    24782856                    default:
    24792857                    {
    2480                         LogFlowThisFunc(("Unsupported message: %RU32\n", e.hgcm.uType));
     2858                        m_pCurDnD->logError("Received unsupported message: %RU32\n", e.hgcm.uType);
    24812859                        rc = VERR_NOT_SUPPORTED;
    24822860                        break;
     
    24852863
    24862864                LogFlowFunc(("Message %RU32 processed with %Rrc\n", e.hgcm.uType, rc));
    2487                 if (   RT_FAILURE(rc)
    2488                     /*
    2489                      * Note: The hgXXX and ghXXX functions of the DnD instance above may return
    2490                      *       VERR_INVALID_STATE in case we're not in the expected state they want
    2491                      *       to operate in. As the user might drag content back and forth to/from
    2492                      *       the host/guest we don't want to reset the overall state here in case
    2493                      *       a VERR_INVALID_STATE occurs. Just continue in our initially set mode.
    2494                      */
    2495                     && rc != VERR_INVALID_STATE)
     2865                if (RT_FAILURE(rc))
    24962866                {
    2497                     m_pCurDnD->logError("Error: Processing message %RU32 failed with %Rrc\n", e.hgcm.uType, rc);
     2867                    /* Tell the user. */
     2868                    m_pCurDnD->logError("Error processing message %RU32, failed with %Rrc, resetting all\n", e.hgcm.uType, rc);
    24982869
    24992870                    /* If anything went wrong, do a reset and start over. */
     
    26533024        else
    26543025        {
    2655             LogFlowFunc(("Processing next message failed with rc=%Rrc\n", rc));
     3026            LogRel(("DnD: Processing next message failed with rc=%Rrc\n", rc));
    26563027
    26573028            /* Old(er) hosts either are broken regarding DnD support or otherwise
     
    27193090
    27203091                        RTCString strType = xAtomToString(pEvent->message_type);
    2721                         LogFlowFunc(("ClientMessage: %s (%RU32), serial=%RU32, wnd=%#x\n", strType.c_str(),
    2722                                      pEvent->message_type, pEvent->serial, pEvent->window));
    2723 
    2724                         if (pEvent->message_type == xAtom(XA_XdndPosition))
    2725                         {
    2726                             int32_t dwPos = pEvent->data.l[2];
    2727                             int32_t dwAction = pEvent->data.l[4];
    2728 
    2729                             LogFlowFunc(("XA_XdndPosition x=%RI32, y=%RI32, dwAction=%RI32\n",
    2730                                          RT_HIWORD(dwPos), RT_LOWORD(dwPos), dwAction));
    2731                         }
    2732                         else if (pEvent->message_type == xAtom(XA_XdndDrop))
    2733                         {
    2734                             LogFlowFunc(("XA_XdndDrop\n"));
    2735                         }
    2736 
     3092                        LogFlowFunc(("ClientMessage: %s from wnd=%#x\n", strType.c_str(), pEvent->window));
    27373093                        break;
    27383094                    }
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