Windows: Fix QColorDialog's live updates while picking outside color

Microsoft's SetCapture() doesn't work on windows owned by other processes,
so instead we use a timer. This is the same approach as used by qttools/src/pixeltool.

The mouse move approach however is more elegant and doesn't hammer the CPU with
QCursor::pos() calls when idle. For this reason the workaround is Q_OS_WIN only.

Task-number: QTBUG-34538
Change-Id: I40a6f7df5bf2a3a29ade8fe4a92f5b5c4ece7efb
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@theqtcompany.com>
This commit is contained in:
Sérgio Martins 2014-12-12 12:33:04 +00:00
parent b699ac070c
commit 38a3158d2f
3 changed files with 48 additions and 5 deletions

View File

@ -57,6 +57,7 @@
#include "qdialogbuttonbox.h"
#include "qscreen.h"
#include "qcursor.h"
#include "qtimer.h"
#include <algorithm>
@ -1577,6 +1578,11 @@ void QColorDialogPrivate::_q_pickScreenColor()
#else
q->grabMouse();
#endif
#ifdef Q_OS_WIN
// On Windows mouse tracking doesn't work over other processes's windows
updateTimer->start(30);
#endif
q->grabKeyboard();
/* With setMouseTracking(true) the desired color can be more precisedly picked up,
* and continuously pushing the mouse button is not necessary.
@ -1600,6 +1606,9 @@ void QColorDialogPrivate::releaseColorPicking()
cp->setCrossVisible(true);
q->removeEventFilter(colorPickingEventFilter);
q->releaseMouse();
#ifdef Q_OS_WIN
updateTimer->stop();
#endif
q->releaseKeyboard();
q->setMouseTracking(false);
lblScreenColorInfo->setText(QLatin1String("\n"));
@ -1782,6 +1791,10 @@ void QColorDialogPrivate::initWidgets()
cancel = buttons->addButton(QDialogButtonBox::Cancel);
QObject::connect(cancel, SIGNAL(clicked()), q, SLOT(reject()));
#ifdef Q_OS_WIN
updateTimer = new QTimer(q);
QObject::connect(updateTimer, SIGNAL(timeout()), q, SLOT(_q_updateColorPicking()));
#endif
retranslateStrings();
}
@ -2196,18 +2209,37 @@ void QColorDialog::changeEvent(QEvent *e)
QDialog::changeEvent(e);
}
bool QColorDialogPrivate::handleColorPickingMouseMove(QMouseEvent *e)
void QColorDialogPrivate::_q_updateColorPicking()
{
// If the cross is visible the grabbed color will be black most of the times
cp->setCrossVisible(!cp->geometry().contains(e->pos()));
#ifndef QT_NO_CURSOR
Q_Q(QColorDialog);
static QPoint lastGlobalPos;
QPoint newGlobalPos = QCursor::pos();
if (lastGlobalPos == newGlobalPos)
return;
lastGlobalPos = newGlobalPos;
const QPoint globalPos = e->globalPos();
if (!q->rect().contains(q->mapFromGlobal(newGlobalPos))) // Inside the dialog mouse tracking works, handleColorPickingMouseMove will be called
updateColorPicking(newGlobalPos);
#endif // ! QT_NO_CURSOR
}
void QColorDialogPrivate::updateColorPicking(const QPoint &globalPos)
{
const QColor color = grabScreenColor(globalPos);
// QTBUG-39792, do not change standard, custom color selectors while moving as
// otherwise it is not possible to pre-select a custom cell for assignment.
setCurrentColor(color, ShowColor);
lblScreenColorInfo->setText(QColorDialog::tr("Cursor at %1, %2, color: %3\nPress ESC to cancel")
.arg(globalPos.x()).arg(globalPos.y()).arg(color.name()));
}
bool QColorDialogPrivate::handleColorPickingMouseMove(QMouseEvent *e)
{
// If the cross is visible the grabbed color will be black most of the times
cp->setCrossVisible(!cp->geometry().contains(e->pos()));
updateColorPicking(e->globalPos());
return true;
}

View File

@ -116,6 +116,7 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_newCustom(int, int))
Q_PRIVATE_SLOT(d_func(), void _q_newStandard(int, int))
Q_PRIVATE_SLOT(d_func(), void _q_pickScreenColor())
Q_PRIVATE_SLOT(d_func(), void _q_updateColorPicking())
friend class QColorShower;
};

View File

@ -63,6 +63,7 @@ class QVBoxLayout;
class QPushButton;
class QWellArray;
class QColorPickingEventFilter;
class QTimer;
class QColorDialogPrivate : public QDialogPrivate
{
@ -75,7 +76,11 @@ public:
SetColorAll = ShowColor | SelectColor
};
QColorDialogPrivate() : options(new QColorDialogOptions) {}
QColorDialogPrivate() : options(new QColorDialogOptions)
#ifdef Q_OS_WIN
, updateTimer(0)
#endif
{}
QPlatformColorDialogHelper *platformColorDialogHelper() const
{ return static_cast<QPlatformColorDialogHelper *>(platformHelper()); }
@ -104,6 +109,8 @@ public:
void _q_newCustom(int, int);
void _q_newStandard(int, int);
void _q_pickScreenColor();
void _q_updateColorPicking();
void updateColorPicking(const QPoint &pos);
void releaseColorPicking();
bool handleColorPickingMouseMove(QMouseEvent *e);
bool handleColorPickingMouseButtonRelease(QMouseEvent *e);
@ -136,6 +143,9 @@ public:
QPointer<QObject> receiverToDisconnectOnClose;
QByteArray memberToDisconnectOnClose;
#ifdef Q_OS_WIN
QTimer *updateTimer;
#endif
#ifdef Q_WS_MAC
void openCocoaColorPanel(const QColor &initial,