[kwinrules] Use native event filter for mouse button release detection

The event filtering on Qt level does not work any more. The information
is not updated properly. Grabbing the mouse through QWidget resets the
cursor shape to the default shape, so it cannot be used.

As we don't want Qt to ever see the events it's a good idea to use a
native event filter to filter the events away before they are delivered
to Qt.

To simplify the handling the grabber widget is put into a QScopedPointer.
This commit is contained in:
Martin Gräßlin 2013-09-30 09:47:22 +02:00
parent 3956c73c53
commit 7d21d612fe
2 changed files with 19 additions and 16 deletions

View file

@ -49,7 +49,7 @@ DetectWidget::DetectWidget(QWidget* parent)
DetectDialog::DetectDialog(QWidget* parent, const char* name)
: KDialog(parent),
grabber(NULL)
grabber()
{
setObjectName(name);
setModal(true);
@ -168,7 +168,7 @@ void DetectDialog::selectWindow()
// use a dialog, so that all user input is blocked
// use WX11BypassWM and moving away so that it's not actually visible
// grab only mouse, so that keyboard can be used e.g. for switching windows
grabber = new KDialog(0, Qt::X11BypassWindowManagerHint);
grabber.reset(new KDialog(0, Qt::X11BypassWindowManagerHint));
grabber->move(-1000, -1000);
grabber->setModal(true);
grabber->show();
@ -177,24 +177,26 @@ void DetectDialog::selectWindow()
if (XGrabPointer(QX11Info::display(), grabber->winId(), false, ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None, QCursor(Qt::CrossCursor).handle(),
CurrentTime) == Success) { // ...so we use the far more convincing CurrentTime
grabber->grabMouse(Qt::CrossCursor); // do anyway, so that Qt updates the mouseGrabber info
grabber->installEventFilter(this);
QCoreApplication::instance()->installNativeEventFilter(this);
} else {
// ... and if we fail, cleanup, so we won't receive random events
delete grabber;
grabber = 0;
grabber.reset();
}
}
bool DetectDialog::eventFilter(QObject* o, QEvent* e)
bool DetectDialog::nativeEventFilter(const QByteArray &eventType, void *message, long int*)
{
if (o != grabber)
if (eventType != QByteArrayLiteral("xcb_generic_event_t")) {
return false;
if (e->type() != QEvent::MouseButtonRelease)
}
auto *event = reinterpret_cast<xcb_generic_event_t *>(message);
if ((event->response_type & ~0x80) != XCB_BUTTON_RELEASE) {
return false;
delete grabber;
grabber = NULL;
if (static_cast< QMouseEvent* >(e)->button() != Qt::LeftButton) {
}
QCoreApplication::instance()->removeNativeEventFilter(this);
grabber.reset();
auto *me = reinterpret_cast<xcb_button_press_event_t*>(event);
if (me->detail != XCB_BUTTON_INDEX_1) {
emit detectionDone(false);
return true;
}

View file

@ -22,6 +22,7 @@
#include <KDialog>
#include <kwindowsystem.h>
#include <QAbstractNativeEventFilter>
#include "../../rules.h"
//Added by qt3to4:
@ -42,7 +43,7 @@ public:
};
class DetectDialog
: public KDialog
: public KDialog, public QAbstractNativeEventFilter
{
Q_OBJECT
public:
@ -57,10 +58,10 @@ public:
Rules::StringMatch titleMatch() const;
QByteArray selectedMachine() const;
const KWindowInfo& windowInfo() const;
virtual bool nativeEventFilter(const QByteArray& eventType, void* message, long int* result) override;
Q_SIGNALS:
void detectionDone(bool);
protected:
virtual bool eventFilter(QObject* o, QEvent* e);
private Q_SLOTS:
void selectWindow();
private:
@ -75,7 +76,7 @@ private:
QByteArray extrarole;
QByteArray machine;
DetectWidget* widget;
KDialog* grabber;
QScopedPointer<KDialog> grabber;
KWindowInfo info;
};