QColorDialog: Don't loose focus while color picking

On Windows mouse grabbing doesn't work across processes, which
means we're interacting with other windows when picking colors.

Workaround that by having a transparent 1x1 window below the cursor
at all times so we catch the mouse click. Clicking before the window is below
the cursor won't happen because our timer interval is 30ms, so it's quite fast.

It's hacky but it's what we can do for a feature which was very broken on Windows.

Task-number: QTBUG-43663
Change-Id: I295378e033ddc6d9c2230335f0953a727c21e1dd
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@theqtcompany.com>
bb10
Sérgio Martins 2015-01-06 18:13:27 +00:00
parent b077ed746a
commit 6e217f0678
2 changed files with 23 additions and 7 deletions

View File

@ -1579,12 +1579,17 @@ void QColorDialogPrivate::_q_pickScreenColor()
q->grabMouse();
#endif
#ifdef Q_OS_WIN
#ifdef Q_OS_WIN32 // excludes WinCE and WinRT
// On Windows mouse tracking doesn't work over other processes's windows
updateTimer->start(30);
// HACK: Because mouse grabbing doesn't work across processes, we have to have a dummy,
// invisible window to catch the mouse click, otherwise we will click whatever we clicked
// and loose focus.
dummyTransparentWindow.show();
#endif
q->grabKeyboard();
/* With setMouseTracking(true) the desired color can be more precisedly picked up,
/* With setMouseTracking(true) the desired color can be more precisely picked up,
* and continuously pushing the mouse button is not necessary.
*/
q->setMouseTracking(true);
@ -1606,8 +1611,9 @@ void QColorDialogPrivate::releaseColorPicking()
cp->setCrossVisible(true);
q->removeEventFilter(colorPickingEventFilter);
q->releaseMouse();
#ifdef Q_OS_WIN
#ifdef Q_OS_WIN32
updateTimer->stop();
dummyTransparentWindow.setVisible(false);
#endif
q->releaseKeyboard();
q->setMouseTracking(false);
@ -1635,6 +1641,10 @@ void QColorDialogPrivate::init(const QColor &initial)
#ifdef Q_WS_MAC
delegate = 0;
#endif
#ifdef Q_OS_WIN32
dummyTransparentWindow.resize(1, 1);
dummyTransparentWindow.setFlags(Qt::Tool | Qt::FramelessWindowHint);
#endif
q->setCurrentColor(initial);
}
@ -1791,7 +1801,7 @@ void QColorDialogPrivate::initWidgets()
cancel = buttons->addButton(QDialogButtonBox::Cancel);
QObject::connect(cancel, SIGNAL(clicked()), q, SLOT(reject()));
#ifdef Q_OS_WIN
#ifdef Q_OS_WIN32
updateTimer = new QTimer(q);
QObject::connect(updateTimer, SIGNAL(timeout()), q, SLOT(_q_updateColorPicking()));
#endif
@ -2219,8 +2229,12 @@ void QColorDialogPrivate::_q_updateColorPicking()
return;
lastGlobalPos = newGlobalPos;
if (!q->rect().contains(q->mapFromGlobal(newGlobalPos))) // Inside the dialog mouse tracking works, handleColorPickingMouseMove will be called
if (!q->rect().contains(q->mapFromGlobal(newGlobalPos))) { // Inside the dialog mouse tracking works, handleColorPickingMouseMove will be called
updateColorPicking(newGlobalPos);
#ifdef Q_OS_WIN32
dummyTransparentWindow.setPosition(newGlobalPos);
#endif
}
#endif // ! QT_NO_CURSOR
}

View File

@ -49,6 +49,7 @@
#include "private/qdialog_p.h"
#include "qcolordialog.h"
#include "qsharedpointer.h"
#include "qwindow.h"
#ifndef QT_NO_COLORDIALOG
@ -77,7 +78,7 @@ public:
};
QColorDialogPrivate() : options(new QColorDialogOptions)
#ifdef Q_OS_WIN
#ifdef Q_OS_WIN32
, updateTimer(0)
#endif
{}
@ -143,8 +144,9 @@ public:
QPointer<QObject> receiverToDisconnectOnClose;
QByteArray memberToDisconnectOnClose;
#ifdef Q_OS_WIN
#ifdef Q_OS_WIN32
QTimer *updateTimer;
QWindow dummyTransparentWindow;
#endif
#ifdef Q_WS_MAC