From 6a28a2cc34d938417affc96d2495a7e3d2e2b869 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Sat, 5 May 2018 20:50:16 +0200 Subject: xcb: qxcbdrag.cpp cleanups - moved finding of XdndAware target logic in its own function to reduce size of QXcbDrag::move(). - switched to use categorized logging with more consistent logging messages - added more comments to avoid constatly looking at the specification for the meanings of Xdnd* actions and who sends/receives the action. - removed dead code (findXdndAwareParent), which should have been removed in 269fdbdd2bedda5f5eacb751224d3a3fc3eed5bc when reimplementing this logic in XCB. - removed needless reseting of state variables in various places as this is handled in QXcbDrag::init() on DnD start. - renamed variable in QXcbDrag::dndEnable(): xdnd_widget -> window - and other minor cleanups Change-Id: Ib667f80ceb4c07b7409a90c041044c98665877f3 Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbconnection.cpp | 1 + src/plugins/platforms/xcb/qxcbconnection.h | 1 + src/plugins/platforms/xcb/qxcbdrag.cpp | 268 ++++++++++++--------------- src/plugins/platforms/xcb/qxcbdrag.h | 2 + 4 files changed, 118 insertions(+), 154 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 1342a82e6e..32e4b9dbba 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -116,6 +116,7 @@ Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events") Q_LOGGING_CATEGORY(lcQpaXcb, "qt.qpa.xcb") // for general (uncategorized) XCB logging Q_LOGGING_CATEGORY(lcQpaPeeker, "qt.qpa.peeker") Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard") +Q_LOGGING_CATEGORY(lcQpaXDnd, "qt.qpa.xdnd") // this event type was added in libxcb 1.10, // but we support also older version diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 7bacbad40b..3a6c9db69c 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -83,6 +83,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaEvents) Q_DECLARE_LOGGING_CATEGORY(lcQpaXcb) Q_DECLARE_LOGGING_CATEGORY(lcQpaPeeker) Q_DECLARE_LOGGING_CATEGORY(lcQpaKeyboard) +Q_DECLARE_LOGGING_CATEGORY(lcQpaXDnd) class QXcbVirtualDesktop; class QXcbScreen; diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index fb2049f87f..dce0cccf87 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -63,19 +63,6 @@ QT_BEGIN_NAMESPACE -//#define DND_DEBUG -#ifdef DND_DEBUG -#define DEBUG qDebug -#else -#define DEBUG if(0) qDebug -#endif - -#ifdef DND_DEBUG -#define DNDDEBUG qDebug() -#else -#define DNDDEBUG if(0) qDebug() -#endif - const int xdnd_version = 5; static inline xcb_window_t xcb_window(QPlatformWindow *w) @@ -164,6 +151,8 @@ void QXcbDrag::init() QXcbCursor::queryPointer(connection(), ¤t_virtual_desktop, 0); drag_types.clear(); + //current_embedding_widget = 0; + dropped = false; canceled = false; } @@ -181,11 +170,10 @@ bool QXcbDrag::eventFilter(QObject *o, QEvent *e) void QXcbDrag::startDrag() { - // #fixme enableEventFilter(); - init(); #ifndef QT_NO_CLIPBOARD + qCDebug(lcQpaXDnd) << "starting drag where source:" << connection()->clipboard()->owner(); xcb_set_selection_owner(xcb_connection(), connection()->clipboard()->owner(), atom(QXcbAtom::XdndSelection), connection()->time()); #endif @@ -307,34 +295,13 @@ xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md return 0; } -void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +bool QXcbDrag::findXdndAwareTarget(const QPoint &globalPos, xcb_window_t *target_out) { - - if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid()) - return; - - QXcbVirtualDesktop *virtualDesktop = nullptr; - QPoint cursorPos; - QXcbCursor::queryPointer(connection(), &virtualDesktop, &cursorPos); - QXcbScreen *screen = virtualDesktop->screenAt(cursorPos); - QPoint deviceIndependentPos = QHighDpiScaling::mapPositionFromNative(globalPos, screen); - - if (virtualDesktop != current_virtual_desktop) { - setUseCompositing(virtualDesktop->compositingActive()); - recreateShapedPixmapWindow(static_cast(screen)->screen(), deviceIndependentPos); - if (connection()->mouseGrabber() == nullptr) - shapedPixmapWindow()->setMouseGrabEnabled(true); - - current_virtual_desktop = virtualDesktop; - } else { - QBasicDrag::moveShapedPixmapWindow(deviceIndependentPos); - } - xcb_window_t rootwin = current_virtual_desktop->root(); - auto translate = Q_XCB_REPLY(xcb_translate_coordinates, connection()->xcb_connection(), + auto translate = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(), rootwin, rootwin, globalPos.x(), globalPos.y()); if (!translate) - return; + return false; xcb_window_t target = translate->child; int lx = translate->dst_x; @@ -343,10 +310,9 @@ void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod if (target && target != rootwin) { xcb_window_t src = rootwin; while (target != 0) { - DNDDEBUG << "checking target for XdndAware" << target << lx << ly; + qCDebug(lcQpaXDnd) << "checking target for XdndAware" << target; - // translate coordinates - auto translate = Q_XCB_REPLY(xcb_translate_coordinates, connection()->xcb_connection(), + auto translate = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(), src, target, lx, ly); if (!translate) { target = 0; @@ -357,12 +323,11 @@ void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod src = target; xcb_window_t child = translate->child; - // check if it has XdndAware auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), false, target, atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0); bool aware = reply && reply->type != XCB_NONE; if (aware) { - DNDDEBUG << "Found XdndAware on " << target; + qCDebug(lcQpaXDnd) << "found XdndAware on" << target; break; } @@ -370,14 +335,45 @@ void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod } if (!target || target == shapedPixmapWindow()->handle()->winId()) { - DNDDEBUG << "need to find real window"; + qCDebug(lcQpaXDnd) << "need to find real window"; target = findRealWindow(globalPos, rootwin, 6, true); if (target == 0) target = findRealWindow(globalPos, rootwin, 6, false); - DNDDEBUG << "real window found" << target; + qCDebug(lcQpaXDnd) << "real window found" << target; } } + *target_out = target; + return true; +} + +void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +{ + // The source sends XdndEnter and XdndPosition to the target. + if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid()) + return; + + QXcbVirtualDesktop *virtualDesktop = nullptr; + QPoint cursorPos; + QXcbCursor::queryPointer(connection(), &virtualDesktop, &cursorPos); + QXcbScreen *screen = virtualDesktop->screenAt(cursorPos); + QPoint deviceIndependentPos = QHighDpiScaling::mapPositionFromNative(globalPos, screen); + + if (virtualDesktop != current_virtual_desktop) { + setUseCompositing(virtualDesktop->compositingActive()); + recreateShapedPixmapWindow(static_cast(screen)->screen(), deviceIndependentPos); + if (connection()->mouseGrabber() == nullptr) + shapedPixmapWindow()->setMouseGrabEnabled(true); + + current_virtual_desktop = virtualDesktop; + } else { + QBasicDrag::moveShapedPixmapWindow(deviceIndependentPos); + } + + xcb_window_t target; + if (!findXdndAwareTarget(globalPos, &target)) + return; + QXcbWindow *w = 0; if (target) { w = connection()->platformWindowFromId(target); @@ -385,7 +381,7 @@ void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod w = 0; } else { w = 0; - target = rootwin; + target = current_virtual_desktop->root(); } xcb_window_t proxy_target = xdndProxy(connection(), target); @@ -427,13 +423,14 @@ void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod enter.data.data32[0] = 0; #endif enter.data.data32[1] = flags; - enter.data.data32[2] = drag_types.size()>0 ? drag_types.at(0) : 0; - enter.data.data32[3] = drag_types.size()>1 ? drag_types.at(1) : 0; - enter.data.data32[4] = drag_types.size()>2 ? drag_types.at(2) : 0; + enter.data.data32[2] = drag_types.size() > 0 ? drag_types.at(0) : 0; + enter.data.data32[3] = drag_types.size() > 1 ? drag_types.at(1) : 0; + enter.data.data32[4] = drag_types.size() > 2 ? drag_types.at(2) : 0; // provisionally set the rectangle to 5x5 pixels... - source_sameanswer = QRect(globalPos.x() - 2, globalPos.y() -2 , 5, 5); + source_sameanswer = QRect(globalPos.x() - 2, globalPos.y() - 2 , 5, 5); + + qCDebug(lcQpaXDnd) << "sending XdndEnter to target:" << target; - DEBUG() << "sending Xdnd enter source=" << enter.data.data32[0]; if (w) handleEnter(w, &enter, current_proxy_target); else if (target) @@ -447,7 +444,8 @@ void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod if (target) { waiting_for_status = true; - + // The source sends a ClientMessage of type XdndPosition. This tells the target the + // position of the mouse and the action that the user requested. xcb_client_message_event_t move; move.response_type = XCB_CLIENT_MESSAGE; move.sequence = 0; @@ -462,8 +460,9 @@ void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod move.data.data32[1] = 0; // flags move.data.data32[2] = (globalPos.x() << 16) + globalPos.y(); move.data.data32[3] = connection()->time(); - move.data.data32[4] = toXdndAction(defaultAction(currentDrag()->supportedActions(), QGuiApplication::keyboardModifiers())); - DEBUG() << "sending Xdnd position source=" << move.data.data32[0] << "target=" << move.window; + move.data.data32[4] = toXdndAction(defaultAction(currentDrag()->supportedActions(), mods)); + + qCDebug(lcQpaXDnd) << "sending XdndPosition to target:" << target; source_time = connection()->time(); @@ -476,6 +475,7 @@ void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod void QXcbDrag::drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) { + // XdndDrop is sent from source to target to complete the drop. QBasicDrag::drop(globalPos, b, mods); if (!current_target) @@ -500,7 +500,7 @@ void QXcbDrag::drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod QXcbWindow *w = connection()->platformWindowFromId(current_proxy_target); - if (w && (w->window()->type() == Qt::Desktop) /*&& !w->acceptDrops()*/) + if (w && w->window()->type() == Qt::Desktop) // && !w->acceptDrops() w = 0; Transaction t = { @@ -519,16 +519,13 @@ void QXcbDrag::drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod cleanup_timer = startTimer(XdndDropTransactionTimeout); } + qCDebug(lcQpaXDnd) << "sending drop to target:" << current_target; + if (w) { handleDrop(w, &drop, b, mods); } else { xcb_send_event(xcb_connection(), false, current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&drop); } - - current_target = 0; - current_proxy_target = 0; - source_time = 0; -// current_embedding_widget = 0; } Qt::DropAction QXcbDrag::toDropAction(xcb_atom_t a) const @@ -586,44 +583,6 @@ int QXcbDrag::findTransactionByTime(xcb_timestamp_t timestamp) } #if 0 - -// find an ancestor with XdndAware on it -static Window findXdndAwareParent(Window window) -{ - Window target = 0; - forever { - // check if window has XdndAware - Atom type = 0; - int f; - unsigned long n, a; - unsigned char *data = 0; - if (XGetWindowProperty(X11->display, window, ATOM(XdndAware), 0, 0, False, - AnyPropertyType, &type, &f,&n,&a,&data) == Success) { - if (data) - XFree(data); - if (type) { - target = window; - break; - } - } - - // try window's parent - Window root; - Window parent; - Window *children; - uint unused; - if (!XQueryTree(X11->display, window, &root, &parent, &children, &unused)) - break; - if (children) - XFree(children); - if (window == root) - break; - window = parent; - } - return target; -} - - // for embedding only static QWidget* current_embedding_widget = 0; static xcb_client_message_event_t last_enter_event; @@ -665,11 +624,10 @@ static bool checkEmbedded(QWidget* w, const XEvent* xe) } #endif - -void QXcbDrag::handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event, xcb_window_t proxy) +void QXcbDrag::handleEnter(QPlatformWindow *, const xcb_client_message_event_t *event, xcb_window_t proxy) { - Q_UNUSED(window); - DEBUG() << "handleEnter" << window; + // The target receives XdndEnter. + qCDebug(lcQpaXDnd) << "target:" << event->window << "received XdndEnter"; xdnd_types.clear(); @@ -705,12 +663,16 @@ void QXcbDrag::handleEnter(QPlatformWindow *window, const xcb_client_message_eve } } for(int i = 0; i < xdnd_types.length(); ++i) - DEBUG() << " " << connection()->atomName(xdnd_types.at(i)); + qCDebug(lcQpaXDnd) << " " << connection()->atomName(xdnd_types.at(i)); } void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *e, Qt::MouseButtons b, Qt::KeyboardModifiers mods) { + // The target receives XdndPosition. The target window must determine which widget the mouse + // is in and ask it whether or not it will accept the drop. + qCDebug(lcQpaXDnd) << "target:" << e->window << "received XdndPosition"; + QPoint p((e->data.data32[2] & 0xffff0000) >> 16, e->data.data32[2] & 0x0000ffff); Q_ASSERT(w); QRect geometry = w->geometry(); @@ -719,8 +681,9 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message if (!w || !w->window() || (w->window()->type() == Qt::Desktop)) return; - if (e->data.data32[0] != xdnd_dragsource) { - DEBUG("xdnd drag position from unexpected source (%x not %x)", e->data.data32[0], xdnd_dragsource); + if (Q_UNLIKELY(e->data.data32[0] != xdnd_dragsource)) { + qCDebug(lcQpaXDnd, "xdnd drag position from unexpected source (%x not %x)", + e->data.data32[0], xdnd_dragsource); return; } @@ -748,9 +711,13 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag( w->window(), dropData, p, supported_actions, buttons, modifiers); + // ### FIXME ? - answerRect appears to be unused. QRect answerRect(p + geometry.topLeft(), QSize(1,1)); answerRect = qt_response.answerRect().translated(geometry.topLeft()).intersected(geometry); + // The target sends a ClientMessage of type XdndStatus. This tells the source whether or not + // it will accept the drop, and, if so, what action will be taken. It also includes a rectangle + // that means "don't send another XdndPosition message until the mouse moves out of here". xcb_client_message_event_t response; response.response_type = XCB_CLIENT_MESSAGE; response.sequence = 0; @@ -781,13 +748,15 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message // reset target_time = XCB_CURRENT_TIME; + qCDebug(lcQpaXDnd) << "sending XdndStatus to source:" << xdnd_dragsource; + #ifndef QT_NO_CLIPBOARD if (xdnd_dragsource == connection()->clipboard()->owner()) handle_xdnd_status(&response); else #endif - xcb_send_event(xcb_connection(), false, current_proxy_target, - XCB_EVENT_MASK_NO_EVENT, (const char *)&response); + xcb_send_event(xcb_connection(), false, current_proxy_target, + XCB_EVENT_MASK_NO_EVENT, (const char *)&response); } namespace @@ -824,7 +793,9 @@ void QXcbDrag::handlePosition(QPlatformWindow * w, const xcb_client_message_even void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event) { - DEBUG("xdndHandleStatus"); + // The source receives XdndStatus. It can use the action to change the cursor to indicate + // whether or not the user's requested action will be performed. + qCDebug(lcQpaXDnd) << "source:" << event->window << "received XdndStatus"; waiting_for_status = false; // ignore late status messages if (event->data.data32[0] && event->data.data32[0] != current_target) @@ -870,12 +841,13 @@ void QXcbDrag::handleStatus(const xcb_client_message_event_t *event) handle_xdnd_status(lastEvent); if (lastEvent != event) free(lastEvent); - DEBUG("xdndHandleStatus end"); } void QXcbDrag::handleLeave(QPlatformWindow *w, const xcb_client_message_event_t *event) { - DEBUG("xdnd leave"); + // If the target receives XdndLeave, it frees any cached data and forgets the whole incident. + qCDebug(lcQpaXDnd) << "target:" << event->window << "received XdndLeave"; + if (!currentWindow || w != currentWindow.data()->handle()) return; // sanity @@ -888,18 +860,16 @@ void QXcbDrag::handleLeave(QPlatformWindow *w, const xcb_client_message_event_t if (event->data.data32[0] != xdnd_dragsource) { // This often happens - leave other-process window quickly - DEBUG("xdnd drag leave from unexpected source (%x not %x", event->data.data32[0], xdnd_dragsource); + qCDebug(lcQpaXDnd, "xdnd drag leave from unexpected source (%x not %x", + event->data.data32[0], xdnd_dragsource); } QWindowSystemInterface::handleDrag(w->window(), nullptr, QPoint(), Qt::IgnoreAction, 0, 0); - - xdnd_dragsource = 0; - xdnd_types.clear(); - currentWindow.clear(); } void QXcbDrag::send_leave() { + // XdndLeave is sent from the source to the target to cancel the drop. if (!current_target) return; @@ -924,22 +894,21 @@ void QXcbDrag::send_leave() if (w && (w->window()->type() == Qt::Desktop) /*&& !w->acceptDrops()*/) w = 0; + qCDebug(lcQpaXDnd) << "sending XdndLeave to target:" << current_target; + if (w) handleLeave(w, (const xcb_client_message_event_t *)&leave); else xcb_send_event(xcb_connection(), false,current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&leave); - - current_target = 0; - current_proxy_target = 0; - source_time = XCB_CURRENT_TIME; - waiting_for_status = false; } void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event, Qt::MouseButtons b, Qt::KeyboardModifiers mods) { - DEBUG("xdndHandleDrop"); + // Target receives XdndDrop. Once it is finished processing the drop, it sends XdndFinished. + qCDebug(lcQpaXDnd) << "target:" << event->window << "received XdndDrop"; + if (!currentWindow) { xdnd_dragsource = 0; return; // sanity @@ -947,16 +916,14 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e const uint32_t *l = event->data.data32; - DEBUG("xdnd drop"); - if (l[0] != xdnd_dragsource) { - DEBUG("xdnd drop from unexpected source (%x not %x", l[0], xdnd_dragsource); + qCDebug(lcQpaXDnd, "xdnd drop from unexpected source (%x not %x", l[0], xdnd_dragsource); return; } // update the "user time" from the timestamp in the event. if (l[2] != 0) - target_time = /*X11->userTime =*/ l[2]; + target_time = l[2]; Qt::DropActions supported_drop_actions; QMimeData *dropData = 0; @@ -994,34 +961,26 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e finished.data.data32[0] = currentWindow ? xcb_window(currentWindow.data()) : XCB_NONE; finished.data.data32[1] = response.isAccepted(); // flags finished.data.data32[2] = toXdndAction(response.acceptedAction()); - xcb_send_event(xcb_connection(), false, current_proxy_target, - XCB_EVENT_MASK_NO_EVENT, (char *)&finished); - xdnd_dragsource = 0; - currentWindow.clear(); - waiting_for_status = false; + qCDebug(lcQpaXDnd) << "sending XdndFinished to source:" << xdnd_dragsource; - // reset - target_time = XCB_CURRENT_TIME; + xcb_send_event(xcb_connection(), false, current_proxy_target, + XCB_EVENT_MASK_NO_EVENT, (char *)&finished); dropped = true; } - void QXcbDrag::handleFinished(const xcb_client_message_event_t *event) { - DEBUG("xdndHandleFinished"); + // Source receives XdndFinished when target is done processing the drop data. + qCDebug(lcQpaXDnd) << "source:" << event->window << "received XdndFinished"; + #ifndef QT_NO_CLIPBOARD if (event->window != connection()->clipboard()->owner()) return; #endif const unsigned long *l = (const unsigned long *)event->data.data32; - - DNDDEBUG << "xdndHandleFinished, l[0]" << l[0] - << "current_target" << current_target - << "qt_xdnd_current_proxy_targe" << current_proxy_target; - if (l[0]) { int at = findTransactionByWindow(l[0]); if (at != -1) { @@ -1096,7 +1055,8 @@ void QXcbDrag::timerEvent(QTimerEvent* e) void QXcbDrag::cancel() { - DEBUG("QXcbDrag::cancel"); + qCDebug(lcQpaXDnd) << "dnd was canceled"; + QBasicDrag::cancel(); if (current_target) send_leave(); @@ -1107,7 +1067,6 @@ void QXcbDrag::cancel() canceled = true; } -// find an ancestor with XdndAware on it static xcb_window_t findXdndAwareParent(QXcbConnection *c, xcb_window_t window) { xcb_window_t target = 0; @@ -1136,6 +1095,8 @@ static xcb_window_t findXdndAwareParent(QXcbConnection *c, xcb_window_t window) void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event) { + qCDebug(lcQpaXDnd) << "handle selection request from target:" << event->requestor; + Q_DECLARE_XCB_EVENT(notify, xcb_selection_notify_event_t); notify.response_type = XCB_SELECTION_NOTIFY; notify.requestor = event->requestor; @@ -1203,10 +1164,10 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event bool QXcbDrag::dndEnable(QXcbWindow *w, bool on) { - DNDDEBUG << "xdndEnable" << w << on; + // Windows announce that they support the XDND protocol by creating a window property XdndAware. if (on) { - QXcbWindow *xdnd_widget = 0; - if ((w->window()->type() == Qt::Desktop)) { + QXcbWindow *window = nullptr; + if (w->window()->type() == Qt::Desktop) { if (desktop_proxy) // *WE* already have one. return false; @@ -1217,8 +1178,8 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on) if (!proxy_id) { desktop_proxy = new QWindow; - xdnd_widget = static_cast(desktop_proxy->handle()); - proxy_id = xdnd_widget->xcb_window(); + window = static_cast(desktop_proxy->handle()); + proxy_id = window->xcb_window(); xcb_atom_t xdnd_proxy = atom(QXcbAtom::XdndProxy); xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, w->xcb_window(), xdnd_proxy, XCB_ATOM_WINDOW, 32, 1, &proxy_id); @@ -1227,24 +1188,24 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on) } } else { - xdnd_widget = w; + window = w; } - if (xdnd_widget) { - DNDDEBUG << "setting XdndAware for" << xdnd_widget << xdnd_widget->xcb_window(); + if (window) { + qCDebug(lcQpaXDnd) << "setting XdndAware for" << window->xcb_window(); xcb_atom_t atm = xdnd_version; - xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, xdnd_widget->xcb_window(), + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window->xcb_window(), atom(QXcbAtom::XdndAware), XCB_ATOM_ATOM, 32, 1, &atm); return true; } else { return false; } } else { - if ((w->window()->type() == Qt::Desktop)) { + if (w->window()->type() == Qt::Desktop) { xcb_delete_property(xcb_connection(), w->xcb_window(), atom(QXcbAtom::XdndProxy)); delete desktop_proxy; desktop_proxy = 0; } else { - DNDDEBUG << "not deleting XDndAware"; + qCDebug(lcQpaXDnd) << "not deleting XDndAware"; } return true; } @@ -1302,7 +1263,6 @@ QVariant QXcbDropData::xdndObtainData(const QByteArray &format, QVariant::Type r return mimeConvertToFormat(c, a, result, QLatin1String(format), requestedType, encoding); } - bool QXcbDropData::hasFormat_sys(const QString &format) const { return formats().contains(format); diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h index fc012b4938..bbdf75f170 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.h +++ b/src/plugins/platforms/xcb/qxcbdrag.h @@ -101,6 +101,8 @@ public: protected: void timerEvent(QTimerEvent* e) override; + bool findXdndAwareTarget(const QPoint &globalPos, xcb_window_t *target_out); + private: friend class QXcbDropData; -- cgit v1.2.3