draganddrop.cpp revision 7aa42d10cb8b82c5a71c7929d6ec98c6dda96410
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * X11 guest client - Drag and Drop.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Copyright (C) 2011-2014 Oracle Corporation
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * available from http://www.virtualbox.org. This file is free software;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * you can redistribute it and/or modify it under the terms of the GNU
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * General Public License (GPL) as published by the Free Software
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/* Enable this define to see the proxy window(s) when debugging
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * their behavior. Don't have this enabled in release builds! */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/* For X11 guest xDnD is used. See http://www.acc.umu.se/~vatten/XDND.html for
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * a walk trough.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * For X11 this means mainly forwarding all the events from HGCM to the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * appropriate X11 events. There exists a proxy window, which is invisible and
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * used for all the X11 communication. On a HGCM Enter event, we set our proxy
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * window as XdndSelection owner with the given mime-types. On every HGCM move
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * event, we move the X11 mouse cursor to the new position and query for the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * window below that position. Depending on if it is XdndAware, a new window or
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * a known window, we send the appropriate X11 messages to it. On HGCM drop, we
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * send a XdndDrop message to the current window and wait for a X11
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * SelectionMessage from the target window. Because we didn't have the data in
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * the requested mime-type, yet, we save that message and ask the host for the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * data. When the data is successfully received from the host, we put the data
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * as a property to the window and send a X11 SelectionNotify event to the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * target window.
struct DnDEvent
enum DnDEventType
enum XA_Type
XA_WM_STATE = 0,
class DragAndDropService;
class xHelpers
if (!m_pInstance)
return m_pInstance;
return strAtom;
return format;
for (int i = 0; i < XA_End; ++i)
switch (xrc)
if(wndParent == 0)
if (cProps > 0)
for (int i = 0; i < cProps; ++i)
if (!wndApp)
int tmp;
unsigned int utmp;
return wndApp;
class DragInstance
enum State
Uninitialized = 0,
enum Mode
Unknown = 0,
HG,
void uninit(void);
void reset(void);
int hgDrop();
#ifdef VBOX_WITH_DRAG_AND_DROP_GH
int ghIsDnDPending();
int proxyWinHide(void) const;
int m_screenId;
long m_curVer;
DragAndDropService(void)
: m_pDisplay(0)
, m_pCurDnD(0)
, m_fSrvStopping(false)
virtual void cleanup(void)
int x11DragAndDropInit(void);
void clearEventQueue();
if (!pEvent)
// && reinterpret_cast<XSelectionRequestEvent*>(pEvent)->requestor == reinterpret_cast<Window>(pUser)))
bool m_fSrvStopping;
friend class DragInstance;
: m_uClientID(0)
, m_pScreen(0)
, m_wndRoot(0)
, m_wndProxy(0)
, m_wndCur(0)
uninit();
reset();
if (m_wndProxy != 0)
if (m_uClientID)
m_uClientID = 0;
m_pScreen = 0;
m_wndRoot = 0;
m_wndProxy = 0;
proxyWinHide();
if (w == m_wndProxy)
m_wndCur = 0;
<< "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\""
<< "application/x-openoffice-drawing;windows_formatname=\"Drawing Format\"";
int rc;
uninit();
if (!m_wndRoot)
#ifdef VBOX_DND_DEBUG_WND
if (!m_wndProxy)
return rc;
int rc;
switch (m_mode)
case HG:
/* This message is send on a un/successful DnD drop request. */
reset();
case GH:
return rc;
int rc;
switch (m_mode)
case GH:
return rc;
int rc;
switch (m_mode)
case HG:
XEvent s;
RT_ZERO(s);
LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor));
XEvent s;
RT_ZERO(s);
LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor));
XEvent s;
RT_ZERO(s);
LogFlowThisFunc(("Error sending SelectionNotify event to wnd=%#x\n", e.xselectionrequest.requestor));
return rc;
int rc;
switch (e.type)
case SelectionNotify:
case SelectionRequest:
case ClientMessage:
case SelectionClear:
return rc;
#ifdef VBOX_WITH_DRAG_AND_DROP_GH
bool fFound = false;
if (fFound)
evX = e;
if (fFound)
if (fFound)
return fFound;
bool fFound = false;
fFound = true;
if (fFound)
if (fFound)
return fFound;
reset();
#ifdef DEBUG
return VINF_SUCCESS;
return VERR_INVALID_STATE;
int fmt;
RT_ZERO(m);
RT_ZERO(m);
m.data.l[1] = RT_MAKE_U32_FROM_U8(m_formats.size() > 3 ? 1 : 0, 0, 0, RT_MIN(VBOX_XDND_VERSION, newVer));
RT_ZERO(m);
return rc;
return VERR_INVALID_STATE;
RT_ZERO(m);
return rc;
return VERR_INVALID_STATE;
|| cData == 0))
return VERR_INVALID_PARAMETER;
return VERR_INVALID_STATE;
return VERR_NO_MEMORY;
XEvent s;
RT_ZERO(s);
XChangeProperty(s.xselection.display, s.xselection.requestor, s.xselection.property, s.xselection.target, 8, PropModeReplace,
return VINF_SUCCESS;
#ifdef VBOX_WITH_DRAG_AND_DROP_GH
if ( wndSelection
proxyWinShow();
XEvent e;
int xRc;
unsigned char *ret = 0;
reset();
#ifdef DEBUG
&& ret)
&& ret)
RT_ZERO(m);
RT_ZERO(m);
proxyWinHide();
return rc;
#ifdef DEBUG
if (fDrop)
int iPropFormat;
&& cItems > 0
&& cbRemaining == 0)
if (pvDataTmp)
RT_ZERO(m);
RT_ZERO(m);
m_wndCur = 0;
if (pcData)
reset();
return rc;
return VINF_SUCCESS;
#ifdef VBOX_DND_WITH_XTEST
//XTranslateCoordinates(m_pDisplay, eBtn.root, eBtn.window, eBtn.x_root, eBtn.y_root, &eBtn.x, &eBtn.y, &eBtn.subwindow);
#ifdef DEBUG
#ifdef VBOX_DND_WITH_XTEST
unsigned int iMask;
#ifdef DEBUG_andy
if (piRootX)
if (piRootY)
if (fMouseMove)
// XSelectInput(m_pDisplay, w, Button1MotionMask | Button2MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask);//| SubstructureNotifyMask);
unsigned cChildren;
for (unsigned i = 0; i < cChildren; ++i)
return atomList;
if ( !pvData
|| !cbData)
while (cbStr)
return lstAtom;
None);
return actionList;
return uAction;
return uActions;
if ( !pvData
|| !cbData)
while (cbStr > 0)
return lstString;
int rc;
if (!m_pCurDnD)
DnDEvent e;
RT_ZERO(e);
#ifdef VBOX_WITH_DRAG_AND_DROP_GH
#ifdef VBOX_WITH_DRAG_AND_DROP_GH
#ifdef VBOX_WITH_DRAG_AND_DROP_GH
return rc;
if (!m_pDisplay)
return VERR_NOT_FOUND;
if (!pHelpers)
return VERR_NO_MEMORY;
return rc;
return rc;
int cMsgSkippedInvalid = 0;
DnDEvent e;
RT_ZERO(e);
return rc;
DnDEvent e;
RT_ZERO(e);
#ifdef DEBUG
case ClientMessage:
return rc;
return pService;