diff options
author | Gatis Paeglis <gatis.paeglis@qt.io> | 2018-05-05 20:51:15 +0200 |
---|---|---|
committer | Gatis Paeglis <gatis.paeglis@qt.io> | 2018-06-22 06:09:36 +0000 |
commit | 47aebe3587c7be28ed4fde23b77848657482ed66 (patch) | |
tree | 99f7dee2e21482ef6bf3c326996e144c225f3ab5 /src/plugins/platforms | |
parent | 6a28a2cc34d938417affc96d2495a7e3d2e2b869 (diff) |
xcb: account for misbehaving Unity DnD Manager
... which may cause dnd data to be lost.
As soon as Unity sees that dnd operation has started (it monitors
for changes on XdndSelection) it creates an invisible window
named XdndCollectionWindowImp that fill entire screen and starts to
act as DnD target. Once it has fetched the mime data it moves
XdndCollectionWindowImp away without sending any DnD termination
events. XdndCollectionWindowImp does not respect the XDnD protocol.
Only when its gone we can start a normal dnd operation - looking for
real DnD target. We ask windows if they are XdndAware on the initial
mouse press and subsequent mouse move events. This patch sets a cursor
to Qt::ForbiddenCursor while DnD is interfered by XdndCollectionWindowImp.
A user will see the real DnD action (reflected by cursor) only after
the next mouse move when XdndCollectionWindowImp has stopped interfering.
We also setCanDrop(false) while DnD target is XdndCollectionWindowImp.
Temporary seeing ForbiddenCursor is better than losing DnD data.
Dropping in this state means that drop will simply be ignored.
It is unclear what Unity developers expected DnD source window to do when
user releases mouse while XdndCollectionWindowImp is stealing the data.
Looking at Unity code, it appears that they were hoping to be quick
enough that it would never happen.
Task-number: QTBUG-49464
Change-Id: I10880073f6d843572be44fe9a3c4f78194466299
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbdrag.cpp | 13 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbdrag.h | 3 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 9 |
3 files changed, 25 insertions, 0 deletions
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index dce0cccf87..999ae16897 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -155,6 +155,8 @@ void QXcbDrag::init() dropped = false; canceled = false; + + source_sameanswer = QRect(); } bool QXcbDrag::eventFilter(QObject *o, QEvent *e) @@ -471,6 +473,17 @@ void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod 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, Qt::MouseButtons b, Qt::KeyboardModifiers mods) diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h index bbdf75f170..c19008c04b 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.h +++ b/src/plugins/platforms/xcb/qxcbdrag.h @@ -143,6 +143,9 @@ private: bool dropped; bool canceled; + // A window from Unity DnD Manager, which does not respect the XDnD spec + xcb_window_t xdndCollectionWindow = XCB_NONE; + // top-level window we sent position to last. xcb_window_t current_target; // window to send events to (always valid if current_target) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 97dac4cfc1..4988ed9657 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2839,6 +2839,15 @@ QString QXcbWindow::windowTitle(const QXcbConnection *conn, xcb_window_t window) const char *name = reinterpret_cast<const char *>(xcb_get_property_value(reply.get())); return QString::fromUtf8(name, xcb_get_property_value_length(reply.get())); } + + reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, conn->xcb_connection(), + false, window, conn->atom(QXcbAtom::WM_NAME), + XCB_ATOM_STRING, 0, 1024); + if (reply && reply->format == 8 && reply->type == XCB_ATOM_STRING) { + const char *name = reinterpret_cast<const char *>(xcb_get_property_value(reply.get())); + return QString::fromLatin1(name, xcb_get_property_value_length(reply.get())); + } + return QString(); } |