From 25f360543041bdbf1321e7b36871d0ee854f7d4b Mon Sep 17 00:00:00 2001 From: Sam Spilsbury Date: Sun, 13 Mar 2011 23:50:39 +0800 Subject: [PATCH] Process changes to edge windows when skipping events on pointer warp There's a condition that can happen where we skip the events generated by XWarpPointer and this causes the edge window reference to stay on the same window, which is a problem when using edges since certain button bindings would stop working. The new behaviour is to always update the edge window reference whenever processing enter and leave events caused by pointer warps --- src/event.cpp | 31 ++++++++++++++----------------- src/privatescreen.h | 3 +++ src/screen.cpp | 37 ++++++++++++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/event.cpp b/src/event.cpp index 4d954b9..d7f77f6 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -41,11 +41,6 @@ #include "privatescreen.h" #include "privatewindow.h" -static Window xdndWindow = None; -static Window edgeWindow = None; - - - bool PrivateWindow::handleSyncAlarm () { @@ -151,14 +146,14 @@ PrivateScreen::triggerButtonPressBindings (CompOption::Vector &options, unsigned int bindMods; unsigned int edge = 0; - if (edgeWindow) + if (priv->edgeWindow) { unsigned int i; if (event->root != root) return false; - if (event->window != edgeWindow) + if (event->window != priv->edgeWindow) { if (grabs.empty () || event->window != root) return false; @@ -166,7 +161,7 @@ PrivateScreen::triggerButtonPressBindings (CompOption::Vector &options, for (i = 0; i < SCREEN_EDGE_NUM; i++) { - if (edgeWindow == screenEdge[i].id) + if (priv->edgeWindow == screenEdge[i].id) { edge = 1 << i; arguments[1].value ().set ((int) activeWindow); @@ -186,8 +181,10 @@ PrivateScreen::triggerButtonPressBindings (CompOption::Vector &options, action->button ().modifiers ()); if ((bindMods & modMask) == (event->state & modMask)) + { if (action->initiate () (action, state, arguments)) return true; + } } } @@ -740,21 +737,21 @@ PrivateScreen::handleActionEvent (XEvent *event) if (edgeDelayTimer.active ()) edgeDelayTimer.stop (); - if (edgeWindow && edgeWindow != event->xcrossing.window) + if (priv->edgeWindow && priv->edgeWindow != event->xcrossing.window) { state = CompAction::StateTermEdge; edge = 0; for (i = 0; i < SCREEN_EDGE_NUM; i++) { - if (edgeWindow == screenEdge[i].id) + if (priv->edgeWindow == screenEdge[i].id) { edge = 1 << i; break; } } - edgeWindow = None; + priv->edgeWindow = None; o[0].value ().set ((int) event->xcrossing.window); o[1].value ().set ((int) activeWindow); @@ -789,7 +786,7 @@ PrivateScreen::handleActionEvent (XEvent *event) { state = CompAction::StateInitEdge; - edgeWindow = event->xcrossing.window; + priv->edgeWindow = event->xcrossing.window; o[0].value ().set ((int) event->xcrossing.window); o[1].value ().set ((int) activeWindow); @@ -809,14 +806,14 @@ PrivateScreen::handleActionEvent (XEvent *event) case ClientMessage: if (event->xclient.message_type == Atoms::xdndEnter) { - xdndWindow = event->xclient.window; + priv->xdndWindow = event->xclient.window; } else if (event->xclient.message_type == Atoms::xdndLeave) { unsigned int edge = 0; CompAction::State state; - if (!xdndWindow) + if (!priv->xdndWindow) { CompWindow *w; @@ -860,7 +857,7 @@ PrivateScreen::handleActionEvent (XEvent *event) unsigned int edge = 0; CompAction::State state; - if (xdndWindow == event->xclient.window) + if (priv->xdndWindow == event->xclient.window) { CompWindow *w; @@ -871,7 +868,7 @@ PrivateScreen::handleActionEvent (XEvent *event) for (i = 0; i < SCREEN_EDGE_NUM; i++) { - if (xdndWindow == screenEdge[i].id) + if (priv->xdndWindow == screenEdge[i].id) { edge = 1 << i; break; @@ -895,7 +892,7 @@ PrivateScreen::handleActionEvent (XEvent *event) return true; } - xdndWindow = None; + priv->xdndWindow = None; } break; default: diff --git a/src/privatescreen.h b/src/privatescreen.h index 60682a3..850e6ec 100644 --- a/src/privatescreen.h +++ b/src/privatescreen.h @@ -513,6 +513,9 @@ class PrivateScreen : public CoreOptions { unsigned long *desktopHintData; int desktopHintSize; + Window edgeWindow; + Window xdndWindow; + bool initialized; }; diff --git a/src/screen.cpp b/src/screen.cpp index 0068719..4ea9c26 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -3994,11 +3994,44 @@ CompScreen::warpPointer (int dx, XSync (priv->dpy, false); + /* XWarpPointer will generate Leave, Enter and PointerMotion + * events as if the user had instantaneously moved the cursor + * from one position to another. Because most of this is + * useless to process, we just throw out the events and update + * the pointer position. However, we do need to process some + * crossing events since they tell us which edge windows are + * hovered. Note that we don't actually trigger the bindings + * in the case where we warped from one edge window to + * another. + * + * FIXME: Probably don't need to process *all* the crossing + * events here ... maybe there is a way to check only the last + * event in the output buffer without roundtripping a lot */ while (XCheckMaskEvent (priv->dpy, LeaveWindowMask | EnterWindowMask | PointerMotionMask, - &event)); + &event)) + { + if (event.type == EnterNotify) + { + if (event.xcrossing.mode != NotifyGrab || + event.xcrossing.mode != NotifyUngrab || + event.xcrossing.mode != NotifyInferior) + { + priv->edgeWindow = 0; + + for (unsigned int i = 0; i < SCREEN_EDGE_NUM; i++) + { + if (event.xcrossing.window == priv->screenEdge[i].id) + { + priv->edgeWindow = 1 << i; + break; + } + } + } + } + } if (!inHandleEvent) { @@ -4733,6 +4766,8 @@ PrivateScreen::PrivateScreen (CompScreen *screen) : showingDesktopMask (0), desktopHintData (0), desktopHintSize (0), + edgeWindow (None), + xdndWindow (None), initialized (false) { gettimeofday (&lastTimeout, 0); -- 1.7.4.1