summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/core/window.h1
-rw-r--r--src/event.cpp108
-rw-r--r--src/modifierhandler.cpp3
-rw-r--r--src/privatewindow.h2
-rw-r--r--src/screen.cpp24
-rw-r--r--src/window.cpp137
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);