diff options
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbdrag.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbdrag.cpp | 336 |
1 files changed, 159 insertions, 177 deletions
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index c8ba33edf5..aa329d8cb7 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,8 +151,12 @@ void QXcbDrag::init() QXcbCursor::queryPointer(connection(), ¤t_virtual_desktop, 0); drag_types.clear(); + //current_embedding_widget = 0; + dropped = false; canceled = false; + + source_sameanswer = QRect(); } bool QXcbDrag::eventFilter(QObject *o, QEvent *e) @@ -181,11 +172,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 @@ -211,6 +201,9 @@ void QXcbDrag::startDrag() QBasicDrag::startDrag(); if (connection()->mouseGrabber() == nullptr) shapedPixmapWindow()->setMouseGrabEnabled(true); + + auto nativePixelPos = QHighDpi::toNativePixels(QCursor::pos(), initiatorWindow); + move(nativePixelPos, QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); } void QXcbDrag::endDrag() @@ -307,34 +300,13 @@ xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md return 0; } -void QXcbDrag::move(const QPoint &globalPos) +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<QPlatformScreen*>(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 +315,9 @@ void QXcbDrag::move(const QPoint &globalPos) 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 +328,11 @@ void QXcbDrag::move(const QPoint &globalPos) 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 +340,45 @@ void QXcbDrag::move(const QPoint &globalPos) } 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<QPlatformScreen*>(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 +386,7 @@ void QXcbDrag::move(const QPoint &globalPos) w = 0; } else { w = 0; - target = rootwin; + target = current_virtual_desktop->root(); } xcb_window_t proxy_target = xdndProxy(connection(), target); @@ -427,13 +428,14 @@ void QXcbDrag::move(const QPoint &globalPos) 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 +449,8 @@ void QXcbDrag::move(const QPoint &globalPos) 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,21 +465,34 @@ void QXcbDrag::move(const QPoint &globalPos) 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(); if (w) - handle_xdnd_position(w, &move); + handle_xdnd_position(w, &move, b, mods); else xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&move); } + + static const bool isUnity = qgetenv("XDG_CURRENT_DESKTOP").toLower() == "unity"; + if (isUnity && xdndCollectionWindow == XCB_NONE) { + QString name = QXcbWindow::windowTitle(connection(), target); + if (name == QStringLiteral("XdndCollectionWindowImp")) + xdndCollectionWindow = target; + } + if (target == xdndCollectionWindow) { + setCanDrop(false); + updateCursor(Qt::IgnoreAction); + } } -void QXcbDrag::drop(const QPoint &globalPos) +void QXcbDrag::drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) { - QBasicDrag::drop(globalPos); + // XdndDrop is sent from source to target to complete the drop. + QBasicDrag::drop(globalPos, b, mods); if (!current_target) return; @@ -500,7 +516,7 @@ void QXcbDrag::drop(const QPoint &globalPos) 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 +535,13 @@ void QXcbDrag::drop(const QPoint &globalPos) cleanup_timer = startTimer(XdndDropTransactionTimeout); } + qCDebug(lcQpaXDnd) << "sending drop to target:" << current_target; + if (w) { - handleDrop(w, &drop); + 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 +599,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 +640,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,11 +679,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) +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(); @@ -718,8 +697,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; } @@ -741,10 +721,19 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message supported_actions = Qt::DropActions(toDropAction(e->data.data32[4])); } - QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(w->window(),dropData,p,supported_actions); + auto buttons = currentDrag() ? b : connection()->queryMouseButtons(); + auto modifiers = currentDrag() ? mods : connection()->queryKeyboardModifiers(); + + 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; @@ -775,13 +764,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 @@ -790,12 +781,11 @@ namespace public: ClientMessageScanner(xcb_atom_t a) : atom(a) {} xcb_atom_t atom; - bool checkEvent(xcb_generic_event_t *event) const { - if (!event) + bool operator() (xcb_generic_event_t *event, int type) const { + if (type != XCB_CLIENT_MESSAGE) return false; - if ((event->response_type & 0x7f) != XCB_CLIENT_MESSAGE) - return false; - return ((xcb_client_message_event_t *)event)->type == atom; + auto clientMessage = reinterpret_cast<xcb_client_message_event_t *>(event); + return clientMessage->type == atom; } }; } @@ -803,12 +793,11 @@ namespace void QXcbDrag::handlePosition(QPlatformWindow * w, const xcb_client_message_event_t *event) { xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event); - xcb_generic_event_t *nextEvent; ClientMessageScanner scanner(atom(QXcbAtom::XdndPosition)); - while ((nextEvent = connection()->checkEvent(scanner))) { + while (auto nextEvent = connection()->eventQueue()->peek(scanner)) { if (lastEvent != event) free(lastEvent); - lastEvent = (xcb_client_message_event_t *)nextEvent; + lastEvent = reinterpret_cast<xcb_client_message_event_t *>(nextEvent); } handle_xdnd_position(w, lastEvent); @@ -818,7 +807,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) @@ -855,7 +846,7 @@ void QXcbDrag::handleStatus(const xcb_client_message_event_t *event) xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event); xcb_generic_event_t *nextEvent; ClientMessageScanner scanner(atom(QXcbAtom::XdndStatus)); - while ((nextEvent = connection()->checkEvent(scanner))) { + while ((nextEvent = connection()->eventQueue()->peek(scanner))) { if (lastEvent != event) free(lastEvent); lastEvent = (xcb_client_message_event_t *)nextEvent; @@ -864,12 +855,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 @@ -882,22 +874,19 @@ 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(),0,QPoint(),Qt::IgnoreAction); - - xdnd_dragsource = 0; - xdnd_types.clear(); - currentWindow.clear(); + QWindowSystemInterface::handleDrag(w->window(), nullptr, QPoint(), Qt::IgnoreAction, 0, 0); } void QXcbDrag::send_leave() { + // XdndLeave is sent from the source to the target to cancel the drop. if (!current_target) return; - xcb_client_message_event_t leave; leave.response_type = XCB_CLIENT_MESSAGE; leave.sequence = 0; @@ -919,21 +908,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) +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 @@ -941,16 +930,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; @@ -960,9 +947,6 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e } else { dropData = m_dropData; supported_drop_actions = accepted_drop_action; - - // Drop coming from another app? Update keyboard modifiers. - QGuiApplicationPrivate::modifier_buttons = QGuiApplication::queryKeyboardModifiers(); } if (!dropData) @@ -973,7 +957,13 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e // dropData = QDragManager::dragPrivate(X11->dndDropTransactions.at(at).object)->data; // if we can't find it, then use the data in the drag manager - QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(currentWindow.data(),dropData,currentPosition,supported_drop_actions); + auto buttons = currentDrag() ? b : connection()->queryMouseButtons(); + auto modifiers = currentDrag() ? mods : connection()->queryKeyboardModifiers(); + + QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop( + currentWindow.data(), dropData, currentPosition, supported_drop_actions, + buttons, modifiers); + setExecutedDropAction(response.acceptedAction()); xcb_client_message_event_t finished; @@ -985,34 +975,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) { @@ -1087,7 +1069,8 @@ void QXcbDrag::timerEvent(QTimerEvent* e) void QXcbDrag::cancel() { - DEBUG("QXcbDrag::cancel"); + qCDebug(lcQpaXDnd) << "dnd was canceled"; + QBasicDrag::cancel(); if (current_target) send_leave(); @@ -1098,7 +1081,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; @@ -1127,7 +1109,8 @@ static xcb_window_t findXdndAwareParent(QXcbConnection *c, xcb_window_t window) void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event) { - Q_DECLARE_XCB_EVENT(notify, xcb_selection_notify_event_t); + qCDebug(lcQpaXDnd) << "handle selection request from target:" << event->requestor; + q_padded_xcb_event<xcb_selection_notify_event_t> notify = {}; notify.response_type = XCB_SELECTION_NOTIFY; notify.requestor = event->requestor; notify.selection = event->selection; @@ -1194,10 +1177,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; @@ -1208,8 +1191,8 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on) if (!proxy_id) { desktop_proxy = new QWindow; - xdnd_widget = static_cast<QXcbWindow *>(desktop_proxy->handle()); - proxy_id = xdnd_widget->xcb_window(); + window = static_cast<QXcbWindow *>(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); @@ -1218,24 +1201,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; } @@ -1293,7 +1276,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); |