Skip to content

Commit

Permalink
dev-qt/qtgui: Fix desktop icon hover
Browse files Browse the repository at this point in the history
  • Loading branch information
a17r committed Feb 3, 2018
1 parent 6a430f6 commit 62fc0fc
Show file tree
Hide file tree
Showing 2 changed files with 343 additions and 0 deletions.
170 changes: 170 additions & 0 deletions dev-qt/qtgui/files/qtgui-5.9.4-qsimpledrag.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
From 4a7771f206d4b29be549d3827c36a46679d90de6 Mon Sep 17 00:00:00 2001
From: Eike Hein <[email protected]>
Date: Sun, 7 Jan 2018 13:02:01 +0900
Subject: [PATCH] QSimpleDrag: Fix mouse release coords for delayed event
transmission

On platforms such as XCB, the drag cursor pixmap is shown via a window
(a QShapedPixmapWindow) under the cursor.

The mouse button release event at the end of the drag is received in
this QXcbWindow, but intercepted by an event filter that QSimpleDrag
installs on the QApplication. It then resends it unmodified(!) after
the drag has ended and the drag pixmap window destroyed, causing it to
be delivered to the new top-level window.

The local coordinates in the unmodified QMouseEvent are local to the
drag pixmap window and don't match the window it is delayed-transmitted
to.

This ends up having fatal, user-visible effects particularly in Qt
Quick: QQuickWindow synthesizes a hover event once per frame using
the last received mouse coordinates, here: the release posted by
QSimpleDrag. This is done to update the hover event state for items
under the cursor when the mouse hasn't moved (e.g. QQuickMouseArea::
containsMouse). The bogus event coordinates in the release event then
usually end up causing an item near the top-left of the QQuickWindow
to assume it is hovered (because drag pixmap windows tend to be small),
even when the mouse cursor is actually far away from it at the end of
the drag.

This shows up e.g. in the Plasma 5 desktop, where dragging an icon
on the desktop will cause the icon at the top-left of the screen (if
any) to switch to hovered state, as the release coordinates on the
drag pixmap window (showing a dragged icon) fall into the geometry
of the top-left icon.

QSimpleDrag contains a topLevelAt() function to find the top-level
window under the global cursor coordinates that is not the drag
pixmap window. This is used by the drop event delivery code.

This patch uses this function to find the relevant top-level window,
then asks it to map the global cusor coordinates to its local
coordinate system, then synthesizes a new QMouseEvent with local
coordinates computed in this fashion. As a result the window now
gets a release event with coordinates that make sense and are
correct.

Task-number: QTBUG-66103
Change-Id: I04ebe6ccd4a991fdd4b540ff0227973ea8896a9d
Reviewed-by: Eike Hein <[email protected]>
Reviewed-by: Shawn Rutledge <[email protected]>
---
src/gui/kernel/qsimpledrag.cpp | 32 +++++++++++++++++++++++++++-----
src/gui/kernel/qsimpledrag_p.h | 6 +++---
2 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp
index a1e25dc..87d3ba5 100644
--- a/src/gui/kernel/qsimpledrag.cpp
+++ b/src/gui/kernel/qsimpledrag.cpp
@@ -58,6 +58,7 @@

#include <QtCore/QEventLoop>
#include <QtCore/QDebug>
+#include <QtCore/QLoggingCategory>

#include <private/qguiapplication_p.h>
#include <private/qdnd_p.h>
@@ -69,6 +70,8 @@ QT_BEGIN_NAMESPACE

#ifndef QT_NO_DRAGANDDROP

+Q_LOGGING_CATEGORY(lcDnd, "qt.gui.dnd")
+
static QWindow* topLevelAt(const QPoint &pos)
{
QWindowList list = QGuiApplication::topLevelWindows();
@@ -94,10 +97,10 @@ static QWindow* topLevelAt(const QPoint &pos)
*/

QBasicDrag::QBasicDrag() :
- m_restoreCursor(false), m_eventLoop(0),
+ m_current_window(nullptr), m_restoreCursor(false), m_eventLoop(nullptr),
m_executed_drop_action(Qt::IgnoreAction), m_can_drop(false),
- m_drag(0), m_drag_icon_window(0), m_useCompositing(true),
- m_screen(Q_NULLPTR)
+ m_drag(nullptr), m_drag_icon_window(nullptr), m_useCompositing(true),
+ m_screen(nullptr)
{
}

@@ -161,6 +164,7 @@ bool QBasicDrag::eventFilter(QObject *o, QEvent *e)
return true; // Eat all mouse move events
}
case QEvent::MouseButtonRelease:
+ {
disableEventFilter();
if (canDrop()) {
QPoint nativePosition = getNativeMousePos(e, m_drag_icon_window);
@@ -169,8 +173,25 @@ bool QBasicDrag::eventFilter(QObject *o, QEvent *e)
cancel();
}
exitDndEventLoop();
- QCoreApplication::postEvent(o, new QMouseEvent(*static_cast<QMouseEvent *>(e)));
+
+ // If a QShapedPixmapWindow (drag feedback) is being dragged along, the
+ // mouse event's localPos() will be relative to that, which is useless.
+ // We want a position relative to the window where the drag ends, if possible (?).
+ // If there is no such window (belonging to this Qt application),
+ // make the event relative to the window where the drag started. (QTBUG-66103)
+ const QMouseEvent *release = static_cast<QMouseEvent *>(e);
+ const QWindow *releaseWindow = topLevelAt(release->globalPos());
+ qCDebug(lcDnd) << "mouse released over" << releaseWindow << "after drag from" << m_current_window << "globalPos" << release->globalPos();
+ if (!releaseWindow)
+ releaseWindow = m_current_window;
+ QPoint releaseWindowPos = (releaseWindow ? releaseWindow->mapFromGlobal(release->globalPos()) : release->globalPos());
+ QMouseEvent *newRelease = new QMouseEvent(release->type(),
+ releaseWindowPos, releaseWindowPos, release->screenPos(),
+ release->button(), release->buttons(),
+ release->modifiers(), release->source());
+ QCoreApplication::postEvent(o, newRelease);
return true; // defer mouse release events until drag event loop has returned
+ }
case QEvent::MouseButtonDblClick:
case QEvent::Wheel:
return true;
@@ -349,7 +370,7 @@ static inline QPoint fromNativeGlobalPixels(const QPoint &point)
into account.
*/

-QSimpleDrag::QSimpleDrag() : m_current_window(0)
+QSimpleDrag::QSimpleDrag()
{
}

@@ -373,6 +394,7 @@ void QSimpleDrag::startDrag()
updateCursor(Qt::IgnoreAction);
}
setExecutedDropAction(Qt::IgnoreAction);
+ qCDebug(lcDnd) << "drag began from" << m_current_window<< "cursor pos" << QCursor::pos() << "can drop?" << canDrop();
}

void QSimpleDrag::cancel()
diff --git a/src/gui/kernel/qsimpledrag_p.h b/src/gui/kernel/qsimpledrag_p.h
index 0b8a0bc..bbd7f7f 100644
--- a/src/gui/kernel/qsimpledrag_p.h
+++ b/src/gui/kernel/qsimpledrag_p.h
@@ -105,6 +105,9 @@ protected:

QDrag *drag() const { return m_drag; }

+protected:
+ QWindow *m_current_window;
+
private:
void enableEventFilter();
void disableEventFilter();
@@ -132,9 +135,6 @@ protected:
virtual void cancel() Q_DECL_OVERRIDE;
virtual void move(const QPoint &globalPos) Q_DECL_OVERRIDE;
virtual void drop(const QPoint &globalPos) Q_DECL_OVERRIDE;
-
-private:
- QWindow *m_current_window;
};

#endif // QT_NO_DRAGANDDROP
--
2.7.4

173 changes: 173 additions & 0 deletions dev-qt/qtgui/qtgui-5.9.4-r1.ebuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Copyright 1999-2018 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

EAPI=6
QT5_MODULE="qtbase"
inherit qt5-build

DESCRIPTION="The GUI module and platform plugins for the Qt5 framework"

if [[ ${QT5_BUILD_TYPE} == release ]]; then
KEYWORDS="~amd64 ~arm ~arm64 ~hppa ~ppc ~ppc64 ~x86"
fi

# TODO: linuxfb

IUSE="accessibility dbus egl eglfs evdev +gif gles2 ibus
jpeg +libinput +png tslib tuio +udev vnc +xcb"
REQUIRED_USE="
|| ( eglfs xcb )
accessibility? ( dbus xcb )
eglfs? ( egl )
ibus? ( dbus )
libinput? ( udev )
xcb? ( gles2? ( egl ) )
"

RDEPEND="
dev-libs/glib:2
~dev-qt/qtcore-${PV}
media-libs/fontconfig
>=media-libs/freetype-2.6.1:2
>=media-libs/harfbuzz-1.0.6:=
>=sys-libs/zlib-1.2.5
virtual/opengl
dbus? ( ~dev-qt/qtdbus-${PV} )
egl? ( media-libs/mesa[egl] )
eglfs? (
media-libs/mesa[gbm]
x11-libs/libdrm
)
evdev? ( sys-libs/mtdev )
gles2? ( media-libs/mesa[gles2] )
jpeg? ( virtual/jpeg:0 )
libinput? (
dev-libs/libinput:=
x11-libs/libxkbcommon
)
png? ( media-libs/libpng:0= )
tslib? ( x11-libs/tslib )
tuio? ( ~dev-qt/qtnetwork-${PV} )
udev? ( virtual/libudev:= )
vnc? ( ~dev-qt/qtnetwork-${PV} )
xcb? (
x11-libs/libICE
x11-libs/libSM
x11-libs/libX11
>=x11-libs/libXi-1.7.5
>=x11-libs/libxcb-1.10:=[xkb]
>=x11-libs/libxkbcommon-0.4.1[X]
x11-libs/xcb-util-image
x11-libs/xcb-util-keysyms
x11-libs/xcb-util-renderutil
x11-libs/xcb-util-wm
)
"
DEPEND="${RDEPEND}
evdev? ( sys-kernel/linux-headers )
udev? ( sys-kernel/linux-headers )
"
PDEPEND="
ibus? ( app-i18n/ibus )
"

PATCHES=(
"${FILESDIR}/${P}-qsimpledrag.patch" # QTBUG-66103
)

QT5_TARGET_SUBDIRS=(
src/gui
src/openglextensions
src/platformheaders
src/platformsupport
src/plugins/generic
src/plugins/imageformats
src/plugins/platforms
src/plugins/platforminputcontexts
)

QT5_GENTOO_CONFIG=(
accessibility:accessibility-atspi-bridge
egl
eglfs
eglfs:eglfs_egldevice:
eglfs:eglfs_gbm:
evdev
evdev:mtdev:
:fontconfig
:system-freetype:FREETYPE
!:no-freetype:
!gif:no-gif:
gles2::OPENGL_ES
gles2:opengles2:OPENGL_ES_2
!:no-gui:
:system-harfbuzz:HARFBUZZ
!:no-harfbuzz:
jpeg:system-jpeg:IMAGEFORMAT_JPEG
!jpeg:no-jpeg:
libinput
libinput:xkbcommon-evdev:
:opengl
png:png:
png:system-png:IMAGEFORMAT_PNG
!png:no-png:
tslib
udev:libudev:
xcb:xcb:
xcb:xcb-glx:
xcb:xcb-plugin:
xcb:xcb-render:
xcb:xcb-sm:
xcb:xcb-xlib:
xcb:xinput2:
xcb::XKB
)

QT5_GENTOO_PRIVATE_CONFIG=(
:gui
)

src_prepare() {
# egl_x11 is activated when both egl and xcb are enabled
use egl && QT5_GENTOO_CONFIG+=(xcb:egl_x11) || QT5_GENTOO_CONFIG+=(egl:egl_x11)

qt_use_disable_config dbus dbus \
src/platformsupport/themes/genericunix/genericunix.pri

qt_use_disable_config tuio udpsocket src/plugins/generic/generic.pro

qt_use_disable_mod ibus dbus \
src/plugins/platforminputcontexts/platforminputcontexts.pro

use vnc || sed -i -e '/SUBDIRS += vnc/d' \
src/plugins/platforms/platforms.pro || die

qt5-build_src_prepare
}

src_configure() {
local myconf=(
$(usex dbus -dbus-linked '')
$(qt_use egl)
$(qt_use eglfs)
$(usex eglfs '-gbm -kms' '')
$(qt_use evdev)
$(qt_use evdev mtdev)
-fontconfig
-system-freetype
$(usex gif '' -no-gif)
-gui
-system-harfbuzz
$(qt_use jpeg libjpeg system)
$(qt_use libinput)
$(qt_use libinput xkbcommon-evdev)
-opengl $(usex gles2 es2 desktop)
$(qt_use png libpng system)
$(qt_use tslib)
$(qt_use udev libudev)
$(qt_use xcb xcb system)
$(qt_use xcb xkbcommon-x11 system)
$(usex xcb '-xcb-xlib -xinput2 -xkb' '')
)
qt5-build_src_configure
}

0 comments on commit 62fc0fc

Please sign in to comment.