diff options
-rw-r--r-- | include/core/window.h | 1 | ||||
-rw-r--r-- | src/event.cpp | 108 | ||||
-rw-r--r-- | src/modifierhandler.cpp | 3 | ||||
-rw-r--r-- | src/privatewindow.h | 2 | ||||
-rw-r--r-- | src/screen.cpp | 24 | ||||
-rw-r--r-- | src/window.cpp | 137 |
6 files changed, 226 insertions, 49 deletions
diff --git a/include/core/window.h b/include/core/window.h index 7ef9737..6b07a56 100644 --- a/include/core/window.h +++ b/include/core/window.h @@ -551,6 +551,7 @@ class CompWindow : friend class PrivateWindow; friend class CompScreen; friend class PrivateScreen; + friend class ModifierHandler; private: PrivateWindow *priv; diff --git a/src/event.cpp b/src/event.cpp index fb4b592..1810070 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -961,6 +961,7 @@ CompScreen::handleEvent (XEvent *event) WRAPABLE_HND_FUNC (6, handleEvent, event) CompWindow *w; + XWindowAttributes wa; switch (event->type) { case ButtonPress: @@ -1020,13 +1021,21 @@ CompScreen::handleEvent (XEvent *event) } break; case CreateNotify: + XGetWindowAttributes (priv->dpy, event->xcreatewindow.window, &wa); w = findTopLevelWindow (event->xcreatewindow.window, true); - if (event->xcreatewindow.parent == priv->root && + if (event->xcreatewindow.parent == wa.root && (!w || w->frame () != event->xcreatewindow.window)) { - new CompWindow (event->xcreatewindow.window, priv->getTopWindow ()); - } + /* Track the window if it was created on this + * screen, otherwise we still need to register + * for FocusChangeMask */ + if (wa.root == priv->root) + new CompWindow (event->xcreatewindow.window, priv->getTopWindow ()); + else + XSelectInput (priv->dpy, event->xcreatewindow.window, + FocusChangeMask); + } break; case DestroyNotify: w = findWindow (event->xdestroywindow.window); @@ -1127,27 +1136,26 @@ CompScreen::handleEvent (XEvent *event) w->priv->circulate (&event->xcirculate); break; case ButtonPress: - if (event->xbutton.root == priv->root) + if (event->xbutton.button == Button1 || + event->xbutton.button == Button2 || + event->xbutton.button == Button3) { - if (event->xbutton.button == Button1 || - event->xbutton.button == Button2 || - event->xbutton.button == Button3) + w = findTopLevelWindow (event->xbutton.window); + if (w) { - w = findTopLevelWindow (event->xbutton.window); - if (w) - { - if (priv->optionGetRaiseOnClick ()) - w->updateAttributes ( - CompStackingUpdateModeAboveFullscreen); + if (priv->optionGetRaiseOnClick ()) + w->updateAttributes (CompStackingUpdateModeAboveFullscreen); + if (w->id () != priv->activeWindow) if (!(w->type () & CompWindowTypeDockMask)) - w->moveInputFocusTo (); - } + if (w->focus ()) + w->moveInputFocusTo (); } - - if (priv->grabs.empty ()) - XAllowEvents (priv->dpy, ReplayPointer, event->xbutton.time); } + + if (priv->grabs.empty ()) + XAllowEvents (priv->dpy, ReplayPointer, event->xbutton.time); + break; case PropertyNotify: if (event->xproperty.atom == Atoms::winType) @@ -1640,37 +1648,61 @@ CompScreen::handleEvent (XEvent *event) case CirculateRequest: break; case FocusIn: - if (event->xfocus.mode != NotifyGrab) + XGetWindowAttributes (priv->dpy, event->xfocus.window, &wa); + + if (wa.root == priv->root) { - w = findTopLevelWindow (event->xfocus.window); - if (w && w->managed ()) + if (event->xfocus.mode != NotifyGrab) { - unsigned int state = w->state (); - - if (w->id () != priv->activeWindow) + w = findTopLevelWindow (event->xfocus.window); + if (w && w->managed ()) { - w->windowNotify (CompWindowNotifyFocusChange); + unsigned int state = w->state (); + + if (w->id () != priv->activeWindow) + { + CompWindow *active = screen->findWindow (priv->activeWindow); + w->windowNotify (CompWindowNotifyFocusChange); - priv->activeWindow = w->id (); - w->priv->activeNum = priv->activeNum++; + priv->activeWindow = w->id (); + w->priv->activeNum = priv->activeNum++; - priv->addToCurrentActiveWindowHistory (w->id ()); + if (active) + active->priv->updatePassiveButtonGrabs (); - XChangeProperty (priv->dpy , priv->root, - Atoms::winActive, - XA_WINDOW, 32, PropModeReplace, - (unsigned char *) &priv->activeWindow, 1); - } + w->priv->updatePassiveButtonGrabs (); - state &= ~CompWindowStateDemandsAttentionMask; - w->changeState (state); + priv->addToCurrentActiveWindowHistory (w->id ()); - if (priv->nextActiveWindow == event->xfocus.window) - priv->nextActiveWindow = None; + XChangeProperty (priv->dpy , priv->root, + Atoms::winActive, + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &priv->activeWindow, 1); + } + + state &= ~CompWindowStateDemandsAttentionMask; + w->changeState (state); + + if (priv->nextActiveWindow == event->xfocus.window) + priv->nextActiveWindow = None; + } } + else + priv->grabbed = true; } else - priv->grabbed = true; + { + CompWindow *w; + + w = screen->findWindow (priv->activeWindow); + + priv->nextActiveWindow = None; + priv->activeWindow = None; + + if (w) + w->priv->updatePassiveButtonGrabs (); + } + break; case FocusOut: if (event->xfocus.mode == NotifyUngrab) diff --git a/src/modifierhandler.cpp b/src/modifierhandler.cpp index 3e7c480..77263fd 100644 --- a/src/modifierhandler.cpp +++ b/src/modifierhandler.cpp @@ -28,6 +28,7 @@ #include <core/screen.h> #include "privatescreen.h" +#include "privatewindow.h" const unsigned int ModifierHandler::virtualModMask[7] = { CompAltMask, CompMetaMask, CompSuperMask, CompHyperMask, @@ -144,6 +145,8 @@ ModifierHandler::updateModifierMappings () (modMask[CompModScrollLock] & ~CompNoMask); screen->priv->updatePassiveKeyGrabs (); + foreach (CompWindow *w, screen->windows ()) + w->priv->updatePassiveButtonGrabs (); } } diff --git a/src/privatewindow.h b/src/privatewindow.h index f750674..09a31e1 100644 --- a/src/privatewindow.h +++ b/src/privatewindow.h @@ -191,6 +191,8 @@ class PrivateWindow { void processMap (); + void updatePassiveButtonGrabs (); + void setFullscreenMonitors (CompFullscreenMonitorSet *monitors); static unsigned int windowTypeFromString (const char *str); diff --git a/src/screen.cpp b/src/screen.cpp index 09ae503..d87a3f1 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -3000,6 +3000,9 @@ PrivateScreen::addPassiveButtonGrab (CompAction::ButtonBinding &button) buttonGrabs.push_back (newButtonGrab); + foreach (CompWindow *w, screen->windows ()) + w->priv->updatePassiveButtonGrabs (); + return true; } @@ -3018,6 +3021,9 @@ PrivateScreen::removePassiveButtonGrab (CompAction::ButtonBinding &button) return; it = buttonGrabs.erase (it); + + foreach (CompWindow *w, screen->windows ()) + w->priv->updatePassiveButtonGrabs (); } } } @@ -4344,6 +4350,24 @@ CompScreen::init (const char *name) FocusChangeMask | ExposureMask); + /* We need to register for EnterWindowMask | + * ButtonPressMask | FocusChangeMask on other + * root windows as well because focus happens + * on a display level and we need to check + * if the screen we are running on lost focus */ + + for (unsigned int i = 0; i <= ScreenCount (dpy) - 1; i++) + { + Window rt = XRootWindow (dpy, i); + + if (rt == root) + continue; + + XSelectInput (dpy, rt, + FocusChangeMask | + SubstructureNotifyMask); + } + if (CompScreen::checkForError (dpy)) { compLogMessage ("core", CompLogLevelError, diff --git a/src/window.cpp b/src/window.cpp index 3a75b34..c51e791 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1651,6 +1651,7 @@ void PrivateWindow::configureFrame (XConfigureEvent *ce) { int x, y, width, height; + CompWindow *above; if (!priv->frame) return; @@ -1674,7 +1675,13 @@ PrivateWindow::configureFrame (XConfigureEvent *ce) window->resize (x, y, width, height, ce->border_width); } - priv->restack (ce->above); + if (priv->restack (ce->above)) + priv->updatePassiveButtonGrabs (); + + above = screen->findWindow (ce->above); + + if (above) + above->priv->updatePassiveButtonGrabs (); } void @@ -4680,6 +4687,108 @@ PrivateWindow::processMap () window->moveInputFocusTo (); } +/* + * PrivateWindow::updatePassiveButtonGrabs + * + * Updates the passive button grabs for a window. When + * one of the specified button + modifier combinations + * for this window is activated, compiz will be given + * an active grab for the window (which we can turn off + * by calling XAllowEvents later in ::handleEvent) + * + * NOTE: ICCCM says that we are only allowed to grab + * windows that we actually own as a client, so only + * grab the frame window. Additionally, although there + * isn't anything in the ICCCM that says we cannot + * grab every button, some clients do not interpret + * EnterNotify and LeaveNotify events caused by the + * activation of the grab correctly, so ungrab button + * and modifier combinations that we do not need on + * active windows (but in reality we shouldn't be grabbing + * for buttons that we don't actually need at that point + * anyways) + */ + +void +PrivateWindow::updatePassiveButtonGrabs () +{ + bool onlyActions = (priv->id == screen->priv->activeWindow || + !screen->priv->optionGetClickToFocus ()); + + if (!priv->frame) + return; + + /* Ungrab everything */ + XUngrabButton (screen->priv->dpy, AnyButton, AnyModifier, frame); + + /* We don't need the full grab in the following cases: + * - This window has the focus and either + * - it is raised or + * - we don't want click raise + */ + + if (onlyActions) + { + if (screen->priv->optionGetRaiseOnClick ()) + { + for (CompWindow *above = window->next; + above != NULL; above = above->next) + { + if (above->priv->attrib.map_state != IsViewable) + continue; + + if (above->type () & CompWindowTypeDockMask) + continue; + + if (above->region ().intersects (region)) + { + onlyActions = false; + break; + } + } + } + } + + if (onlyActions) + { + /* Grab only we have bindings on */ + foreach (PrivateScreen::ButtonGrab &bind, screen->priv->buttonGrabs) + { + for (unsigned int ignore = 0; + ignore <= modHandler->ignoredModMask (); ignore++) + { + if (ignore & ~modHandler->ignoredModMask ()) + { + XGrabButton (screen->priv->dpy, + bind.button, + bind.modifiers | ignore, + frame, + false, + ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask, + GrabModeSync, + GrabModeAsync, + None, + None); + } + } + } + } + else + { + /* Grab everything */ + XGrabButton (screen->priv->dpy, + AnyButton, + AnyModifier, + frame, false, + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, + GrabModeSync, + GrabModeAsync, + None, + None); + } +} + const CompRegion & CompWindow::region () const @@ -5053,10 +5162,6 @@ CompWindow::CompWindow (Window id, priv->id = id; - XGrabButton (screen->dpy (), AnyButton, AnyModifier, priv->id, true, - ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, - GrabModeSync, GrabModeSync, None, None); - priv->alpha = (depth () == 32); priv->lastPong = screen->priv->lastPing; @@ -5608,17 +5713,27 @@ PrivateWindow::reparent () sg.width (), sg.height (), 0, attrib.depth, InputOutput, visual, mask, &attr); - XGrabButton (dpy, AnyButton, AnyModifier, frame, true, - ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, - GrabModeSync, GrabModeSync, None, None); - XMapWindow (dpy, wrapper); XReparentWindow (dpy, id, wrapper, 0, 0); attr.event_mask = PropertyChangeMask | FocusChangeMask | EnterWindowMask | LeaveWindowMask; - attr.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask; + + /* We don't care about client events on the frame, and listening for them + * will probably end up fighting the client anyways, so disable them */ + attr.do_not_propagate_mask = KeyPressMask | KeyReleaseMask | + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask | + PointerMotionMask | PointerMotionHintMask | + Button1MotionMask | Button2MotionMask | + Button3MotionMask | Button4MotionMask | + Button5MotionMask | ButtonMotionMask | + KeymapStateMask | ExposureMask | + VisibilityChangeMask | StructureNotifyMask | + ResizeRedirectMask | SubstructureNotifyMask | + SubstructureRedirectMask | FocusChangeMask | + PropertyChangeMask | ColormapChangeMask | + OwnerGrabButtonMask; XChangeWindowAttributes (dpy, id, CWEventMask | CWDontPropagate, &attr); |