2
* Copyright © 2005 Novell, Inc.
4
* Permission to use, copy, modify, distribute, and sell this software
5
* and its documentation for any purpose is hereby granted without
6
* fee, provided that the above copyright notice appear in all copies
7
* and that both that copyright notice and this permission notice
8
* appear in supporting documentation, and that the name of
9
* Novell, Inc. not be used in advertising or publicity pertaining to
10
* distribution of the software without specific, written prior permission.
11
* Novell, Inc. makes no representations about the suitability of this
12
* software for any purpose. It is provided "as is" without express or
15
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23
* Author: David Reveman <davidr@novell.com>
29
#include <boost/bind.hpp>
30
#include <boost/foreach.hpp>
31
#define foreach BOOST_FOREACH
34
#include <X11/Xatom.h>
35
#include <X11/extensions/shape.h>
36
#include <X11/extensions/Xrandr.h>
37
#include <X11/extensions/Xfixes.h>
39
#include <core/core.h>
40
#include <core/atoms.h>
41
#include "privatescreen.h"
42
#include "privatewindow.h"
43
#include "privatestackdebugger.h"
46
PrivateWindow::handleSyncAlarm ()
50
priv->syncWait = false;
52
if (window->resize (priv->syncGeometry))
54
window->windowNotify (CompWindowNotifySyncAlarm);
58
/* resizeWindow failing means that there is another pending
59
resize and we must send a new sync request to the client */
60
window->sendSyncRequest ();
69
autoRaiseTimeout (CompScreen *screen)
71
CompWindow *w = screen->findWindow (screen->activeWindow ());
73
if (screen->autoRaiseWindow () == screen->activeWindow () ||
74
(w && (screen->autoRaiseWindow () == w->transientFor ())))
76
w = screen->findWindow (screen->autoRaiseWindow ());
78
w->updateAttributes (CompStackingUpdateModeNormal);
84
#define REAL_MOD_MASK (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | \
85
Mod3Mask | Mod4Mask | Mod5Mask | CompNoMask)
88
isCallBackBinding (CompOption &option,
89
CompAction::BindingType type,
90
CompAction::State state)
92
if (!option.isAction ())
95
if (!(option.value ().action ().type () & type))
98
if (!(option.value ().action ().state () & state))
105
isInitiateBinding (CompOption &option,
106
CompAction::BindingType type,
107
CompAction::State state,
110
if (!isCallBackBinding (option, type, state))
113
if (option.value ().action ().initiate ().empty ())
116
*action = &option.value ().action ();
122
isTerminateBinding (CompOption &option,
123
CompAction::BindingType type,
124
CompAction::State state,
127
if (!isCallBackBinding (option, type, state))
130
if (option.value ().action ().terminate ().empty ())
133
*action = &option.value ().action ();
139
PrivateScreen::triggerButtonPressBindings (CompOption::Vector &options,
141
CompOption::Vector &arguments)
143
CompAction::State state = CompAction::StateInitButton;
145
unsigned int ignored = modHandler->ignoredModMask ();
146
unsigned int modMask = REAL_MOD_MASK & ~ignored;
147
unsigned int bindMods;
148
unsigned int edge = 0;
150
if (priv->edgeWindow)
154
if (event->root != root)
157
if (event->window != priv->edgeWindow)
159
if (grabs.empty () || event->window != root)
163
for (i = 0; i < SCREEN_EDGE_NUM; i++)
165
if (priv->edgeWindow == screenEdge[i].id)
168
arguments[1].value ().set ((int) activeWindow);
174
foreach (CompOption &option, options)
176
if (isInitiateBinding (option, CompAction::BindingTypeButton, state,
179
if (action->button ().button () == (int) event->button)
181
bindMods = modHandler->virtualToRealModMask (
182
action->button ().modifiers ());
184
if ((bindMods & modMask) == (event->state & modMask))
186
if (action->initiate () (action, state, arguments))
194
if (isInitiateBinding (option, CompAction::BindingTypeEdgeButton,
195
state | CompAction::StateInitEdge, &action))
197
if ((action->button ().button () == (int) event->button) &&
198
(action->edgeMask () & edge))
200
bindMods = modHandler->virtualToRealModMask (
201
action->button ().modifiers ());
203
if ((bindMods & modMask) == (event->state & modMask))
204
if (action->initiate () (action, state |
205
CompAction::StateInitEdge,
217
PrivateScreen::triggerButtonReleaseBindings (CompOption::Vector &options,
219
CompOption::Vector &arguments)
221
CompAction::State state = CompAction::StateTermButton;
222
CompAction::BindingType type = CompAction::BindingTypeButton |
223
CompAction::BindingTypeEdgeButton;
226
foreach (CompOption &option, options)
228
if (isTerminateBinding (option, type, state, &action))
230
if (action->button ().button () == (int) event->button)
232
if (action->terminate () (action, state, arguments))
242
PrivateScreen::triggerKeyPressBindings (CompOption::Vector &options,
244
CompOption::Vector &arguments)
246
CompAction::State state = 0;
248
unsigned int modMask = REAL_MOD_MASK & ~modHandler->ignoredModMask ();
249
unsigned int bindMods;
251
if (event->keycode == escapeKeyCode)
252
state = CompAction::StateCancel;
253
else if (event->keycode == returnKeyCode)
254
state = CompAction::StateCommit;
258
foreach (CompOption &o, options)
262
if (!o.value ().action ().terminate ().empty ())
263
o.value ().action ().terminate () (&o.value ().action (),
268
if (state == CompAction::StateCancel)
272
state = CompAction::StateInitKey;
273
foreach (CompOption &option, options)
275
if (isInitiateBinding (option, CompAction::BindingTypeKey,
278
bindMods = modHandler->virtualToRealModMask (
279
action->key ().modifiers ());
281
if (action->key ().keycode () == (int) event->keycode)
283
if ((bindMods & modMask) == (event->state & modMask))
284
if (action->initiate () (action, state, arguments))
287
else if (!xkbEvent && action->key ().keycode () == 0)
289
if (bindMods == (event->state & modMask))
290
if (action->initiate () (action, state, arguments))
300
PrivateScreen::triggerKeyReleaseBindings (CompOption::Vector &options,
302
CompOption::Vector &arguments)
304
CompAction::State state = CompAction::StateTermKey;
306
unsigned int ignored = modHandler->ignoredModMask ();
307
unsigned int modMask = REAL_MOD_MASK & ~ignored;
308
unsigned int bindMods;
311
mods = modHandler->keycodeToModifiers (event->keycode);
312
if (!xkbEvent && !mods)
315
foreach (CompOption &option, options)
317
if (isTerminateBinding (option, CompAction::BindingTypeKey,
320
bindMods = modHandler->virtualToRealModMask (action->key ().modifiers ());
322
if ((bindMods & modMask) == 0)
324
if ((unsigned int) action->key ().keycode () ==
325
(unsigned int) event->keycode)
327
if (action->terminate () (action, state, arguments))
331
else if (!xkbEvent && ((mods & modMask & bindMods) != bindMods))
333
if (action->terminate () (action, state, arguments))
343
PrivateScreen::triggerStateNotifyBindings (CompOption::Vector &options,
344
XkbStateNotifyEvent *event,
345
CompOption::Vector &arguments)
347
CompAction::State state;
349
unsigned int ignored = modHandler->ignoredModMask ();
350
unsigned int modMask = REAL_MOD_MASK & ~ignored;
351
unsigned int bindMods;
353
if (event->event_type == KeyPress)
355
state = CompAction::StateInitKey;
357
foreach (CompOption &option, options)
359
if (isInitiateBinding (option, CompAction::BindingTypeKey,
362
if (action->key ().keycode () == 0)
365
modHandler->virtualToRealModMask (action->key ().modifiers ());
367
if ((event->mods & modMask & bindMods) == bindMods)
369
if (action->initiate () (action, state, arguments))
378
state = CompAction::StateTermKey;
380
foreach (CompOption &option, options)
382
if (isTerminateBinding (option, CompAction::BindingTypeKey,
385
bindMods = modHandler->virtualToRealModMask (action->key ().modifiers ());
387
if ((event->mods & modMask & bindMods) != bindMods)
389
if (action->terminate () (action, state, arguments))
400
isBellAction (CompOption &option,
401
CompAction::State state,
404
if (option.type () != CompOption::TypeAction &&
405
option.type () != CompOption::TypeBell)
408
if (!option.value ().action ().bell ())
411
if (!(option.value ().action ().state () & state))
414
if (option.value ().action ().initiate ().empty ())
417
*action = &option.value ().action ();
423
triggerBellNotifyBindings (CompOption::Vector &options,
424
CompOption::Vector &arguments)
426
CompAction::State state = CompAction::StateInitBell;
429
foreach (CompOption &option, options)
431
if (isBellAction (option, state, &action))
433
if (action->initiate () (action, state, arguments))
442
isEdgeAction (CompOption &option,
443
CompAction::State state,
446
if (option.type () != CompOption::TypeAction &&
447
option.type () != CompOption::TypeButton &&
448
option.type () != CompOption::TypeEdge)
451
if (!(option.value ().action ().edgeMask () & edge))
454
if (!(option.value ().action ().state () & state))
461
isEdgeEnterAction (CompOption &option,
462
CompAction::State state,
463
CompAction::State delayState,
467
if (!isEdgeAction (option, state, edge))
470
if (option.value ().action ().type () & CompAction::BindingTypeEdgeButton)
473
if (option.value ().action ().initiate ().empty ())
478
if ((option.value ().action ().state () &
479
CompAction::StateNoEdgeDelay) !=
480
(delayState & CompAction::StateNoEdgeDelay))
482
/* ignore edge actions which shouldn't be delayed when invoking
483
undelayed edges (or vice versa) */
489
*action = &option.value ().action ();
495
isEdgeLeaveAction (CompOption &option,
496
CompAction::State state,
500
if (!isEdgeAction (option, state, edge))
503
if (option.value ().action ().terminate ().empty ())
506
*action = &option.value ().action ();
512
triggerEdgeEnterBindings (CompOption::Vector &options,
513
CompAction::State state,
514
CompAction::State delayState,
516
CompOption::Vector &arguments)
520
foreach (CompOption &option, options)
522
if (isEdgeEnterAction (option, state, delayState, edge, &action))
524
if (action->initiate () (action, state, arguments))
533
triggerEdgeLeaveBindings (CompOption::Vector &options,
534
CompAction::State state,
536
CompOption::Vector &arguments)
540
foreach (CompOption &option, options)
542
if (isEdgeLeaveAction (option, state, edge, &action))
544
if (action->terminate () (action, state, arguments))
553
triggerAllEdgeEnterBindings (CompAction::State state,
554
CompAction::State delayState,
556
CompOption::Vector &arguments)
558
foreach (CompPlugin *p, CompPlugin::getPlugins ())
560
CompOption::Vector &options = p->vTable->getOptions ();
561
if (triggerEdgeEnterBindings (options, state, delayState, edge,
571
delayedEdgeTimeout (CompDelayedEdgeSettings *settings)
573
triggerAllEdgeEnterBindings (settings->state,
574
~CompAction::StateNoEdgeDelay,
582
PrivateScreen::triggerEdgeEnter (unsigned int edge,
583
CompAction::State state,
584
CompOption::Vector &arguments)
588
delay = optionGetEdgeDelay ();
592
CompAction::State delayState;
593
edgeDelaySettings.edge = edge;
594
edgeDelaySettings.state = state;
595
edgeDelaySettings.options = arguments;
597
edgeDelayTimer.start (
598
boost::bind (delayedEdgeTimeout, &edgeDelaySettings),
599
delay, (unsigned int) ((float) delay * 1.2));
601
delayState = CompAction::StateNoEdgeDelay;
602
if (triggerAllEdgeEnterBindings (state, delayState, edge, arguments))
607
if (triggerAllEdgeEnterBindings (state, 0, edge, arguments))
615
PrivateScreen::handleActionEvent (XEvent *event)
617
static CompOption::Vector o (8);
620
o[0].setName ("event_window", CompOption::TypeInt);
621
o[1].setName ("window", CompOption::TypeInt);
622
o[2].setName ("modifiers", CompOption::TypeInt);
623
o[3].setName ("x", CompOption::TypeInt);
624
o[4].setName ("y", CompOption::TypeInt);
625
o[5].setName ("root", CompOption::TypeInt);
629
switch (event->type) {
631
/* We need to determine if we clicked on a parent frame
632
* window, if so, pass the appropriate child window as
633
* "window" and the frame as "event_window"
636
xid = event->xbutton.window;
638
foreach (CompWindow *w, screen->windows ())
640
if (w->priv->frame == xid)
644
o[0].value ().set ((int) event->xbutton.window);
645
o[1].value ().set ((int) xid);
646
o[2].value ().set ((int) event->xbutton.state);
647
o[3].value ().set ((int) event->xbutton.x_root);
648
o[4].value ().set ((int) event->xbutton.y_root);
649
o[5].value ().set ((int) event->xbutton.root);
651
o[6].setName ("button", CompOption::TypeInt);
652
o[7].setName ("time", CompOption::TypeInt);
654
o[6].value ().set ((int) event->xbutton.button);
655
o[7].value ().set ((int) event->xbutton.time);
657
foreach (CompPlugin *p, CompPlugin::getPlugins ())
659
CompOption::Vector &options = p->vTable->getOptions ();
660
if (triggerButtonPressBindings (options, &event->xbutton, o))
665
o[0].value ().set ((int) event->xbutton.window);
666
o[1].value ().set ((int) event->xbutton.window);
667
o[2].value ().set ((int) event->xbutton.state);
668
o[3].value ().set ((int) event->xbutton.x_root);
669
o[4].value ().set ((int) event->xbutton.y_root);
670
o[5].value ().set ((int) event->xbutton.root);
672
o[6].setName ("button", CompOption::TypeInt);
673
o[7].setName ("time", CompOption::TypeInt);
675
o[6].value ().set ((int) event->xbutton.button);
676
o[7].value ().set ((int) event->xbutton.time);
678
foreach (CompPlugin *p, CompPlugin::getPlugins ())
680
CompOption::Vector &options = p->vTable->getOptions ();
681
if (triggerButtonReleaseBindings (options, &event->xbutton, o))
686
o[0].value ().set ((int) event->xkey.window);
687
o[1].value ().set ((int) activeWindow);
688
o[2].value ().set ((int) event->xkey.state);
689
o[3].value ().set ((int) event->xkey.x_root);
690
o[4].value ().set ((int) event->xkey.y_root);
691
o[5].value ().set ((int) event->xkey.root);
693
o[6].setName ("keycode", CompOption::TypeInt);
694
o[7].setName ("time", CompOption::TypeInt);
696
o[6].value ().set ((int) event->xkey.keycode);
697
o[7].value ().set ((int) event->xkey.time);
699
foreach (CompPlugin *p, CompPlugin::getPlugins ())
701
CompOption::Vector &options = p->vTable->getOptions ();
702
if (triggerKeyPressBindings (options, &event->xkey, o))
707
o[0].value ().set ((int) event->xkey.window);
708
o[1].value ().set ((int) activeWindow);
709
o[2].value ().set ((int) event->xkey.state);
710
o[3].value ().set ((int) event->xkey.x_root);
711
o[4].value ().set ((int) event->xkey.y_root);
712
o[5].value ().set ((int) event->xkey.root);
714
o[6].setName ("keycode", CompOption::TypeInt);
715
o[7].setName ("time", CompOption::TypeInt);
717
o[6].value ().set ((int) event->xkey.keycode);
718
o[7].value ().set ((int) event->xkey.time);
720
foreach (CompPlugin *p, CompPlugin::getPlugins ())
722
CompOption::Vector &options = p->vTable->getOptions ();
723
if (triggerKeyReleaseBindings (options, &event->xkey, o))
728
if (event->xcrossing.mode != NotifyGrab &&
729
event->xcrossing.mode != NotifyUngrab &&
730
event->xcrossing.detail != NotifyInferior)
732
unsigned int edge, i;
733
CompAction::State state;
735
if (event->xcrossing.root != root)
738
if (edgeDelayTimer.active ())
739
edgeDelayTimer.stop ();
741
if (priv->edgeWindow && priv->edgeWindow != event->xcrossing.window)
743
state = CompAction::StateTermEdge;
746
for (i = 0; i < SCREEN_EDGE_NUM; i++)
748
if (priv->edgeWindow == screenEdge[i].id)
755
priv->edgeWindow = None;
757
o[0].value ().set ((int) event->xcrossing.window);
758
o[1].value ().set ((int) activeWindow);
759
o[2].value ().set ((int) event->xcrossing.state);
760
o[3].value ().set ((int) event->xcrossing.x_root);
761
o[4].value ().set ((int) event->xcrossing.y_root);
762
o[5].value ().set ((int) event->xcrossing.root);
764
o[6].setName ("time", CompOption::TypeInt);
765
o[6].value ().set ((int) event->xcrossing.time);
767
foreach (CompPlugin *p, CompPlugin::getPlugins ())
769
CompOption::Vector &options = p->vTable->getOptions ();
770
if (triggerEdgeLeaveBindings (options, state, edge, o))
777
for (i = 0; i < SCREEN_EDGE_NUM; i++)
779
if (event->xcrossing.window == screenEdge[i].id)
788
state = CompAction::StateInitEdge;
790
priv->edgeWindow = event->xcrossing.window;
792
o[0].value ().set ((int) event->xcrossing.window);
793
o[1].value ().set ((int) activeWindow);
794
o[2].value ().set ((int) event->xcrossing.state);
795
o[3].value ().set ((int) event->xcrossing.x_root);
796
o[4].value ().set ((int) event->xcrossing.y_root);
797
o[5].value ().set ((int) event->xcrossing.root);
799
o[6].setName ("time", CompOption::TypeInt);
800
o[6].value ().set ((int) event->xcrossing.time);
802
if (triggerEdgeEnter (edge, state, o))
808
if (event->xclient.message_type == Atoms::xdndEnter)
810
priv->xdndWindow = event->xclient.window;
812
else if (event->xclient.message_type == Atoms::xdndLeave)
814
unsigned int edge = 0;
815
CompAction::State state;
817
if (!priv->xdndWindow)
821
w = screen->findWindow (event->xclient.window);
826
for (i = 0; i < SCREEN_EDGE_NUM; i++)
828
if (event->xclient.window == screenEdge[i].id)
839
state = CompAction::StateTermEdgeDnd;
841
o[0].value ().set ((int) event->xclient.window);
842
o[1].value ().set ((int) activeWindow);
843
o[2].value ().set ((int) 0); /* fixme */
844
o[3].value ().set ((int) 0); /* fixme */
845
o[4].value ().set ((int) 0); /* fixme */
846
o[5].value ().set ((int) root);
848
foreach (CompPlugin *p, CompPlugin::getPlugins ())
850
CompOption::Vector &options = p->vTable->getOptions ();
851
if (triggerEdgeLeaveBindings (options, state, edge, o))
856
else if (event->xclient.message_type == Atoms::xdndPosition)
858
unsigned int edge = 0;
859
CompAction::State state;
861
if (priv->xdndWindow == event->xclient.window)
865
w = screen->findWindow (event->xclient.window);
870
for (i = 0; i < SCREEN_EDGE_NUM; i++)
872
if (priv->xdndWindow == screenEdge[i].id)
883
state = CompAction::StateInitEdgeDnd;
885
o[0].value ().set ((int) event->xclient.window);
886
o[1].value ().set ((int) activeWindow);
887
o[2].value ().set ((int) 0); /* fixme */
888
o[3].value ().set ((int) event->xclient.data.l[2] >> 16);
889
o[4].value ().set ((int) event->xclient.data.l[2] & 0xffff);
890
o[5].value ().set ((int) root);
892
if (triggerEdgeEnter (edge, state, o))
896
priv->xdndWindow = None;
900
if (event->type == xkbEvent)
902
XkbAnyEvent *xkbEvent = (XkbAnyEvent *) event;
904
if (xkbEvent->xkb_type == XkbStateNotify)
906
XkbStateNotifyEvent *stateEvent = (XkbStateNotifyEvent *) event;
908
o[0].value ().set ((int) activeWindow);
909
o[1].value ().set ((int) activeWindow);
910
o[2].value ().set ((int) stateEvent->mods);
912
o[3].setName ("time", CompOption::TypeInt);
913
o[3].value ().set ((int) xkbEvent->time);
917
foreach (CompPlugin *p, CompPlugin::getPlugins ())
919
CompOption::Vector &options = p->vTable->getOptions ();
920
if (triggerStateNotifyBindings (options, stateEvent, o))
924
else if (xkbEvent->xkb_type == XkbBellNotify)
926
o[0].value ().set ((int) activeWindow);
927
o[1].value ().set ((int) activeWindow);
929
o[2].setName ("time", CompOption::TypeInt);
930
o[2].value ().set ((int) xkbEvent->time);
936
foreach (CompPlugin *p, CompPlugin::getPlugins ())
938
CompOption::Vector &options = p->vTable->getOptions ();
939
if (triggerBellNotifyBindings (options, o))
951
PrivateScreen::setDefaultWindowAttributes (XWindowAttributes *wa)
957
wa->border_width = 0;
960
wa->root = priv->root;
961
wa->c_class = InputOnly;
962
wa->bit_gravity = NorthWestGravity;
963
wa->win_gravity = NorthWestGravity;
964
wa->backing_store = NotUseful;
965
wa->backing_planes = 0;
966
wa->backing_pixel = 0;
967
wa->save_under = false;
969
wa->map_installed = false;
970
wa->map_state = IsUnviewable;
971
wa->all_event_masks = 0;
972
wa->your_event_mask = 0;
973
wa->do_not_propagate_mask = 0;
974
wa->override_redirect = true;
975
wa->screen = ScreenOfDisplay (priv->dpy, priv->screenNum);
979
CompScreen::handleCompizEvent (const char *plugin,
981
CompOption::Vector &options)
982
WRAPABLE_HND_FUNC (7, handleCompizEvent, plugin, event, options)
985
CompScreen::handleEvent (XEvent *event)
987
WRAPABLE_HND_FUNC (6, handleEvent, event)
989
CompWindow *w = NULL;
990
XWindowAttributes wa;
991
bool actionEventHandled = false;
993
switch (event->type) {
995
if (event->xbutton.root == priv->root)
996
priv->setCurrentOutput (
997
outputDeviceForPoint (event->xbutton.x_root,
998
event->xbutton.y_root));
1001
if (event->xmotion.root == priv->root)
1002
priv->setCurrentOutput (
1003
outputDeviceForPoint (event->xmotion.x_root,
1004
event->xmotion.y_root));
1007
w = findWindow (priv->activeWindow);
1009
priv->setCurrentOutput (w->outputDevice ());
1015
if (priv->handleActionEvent (event))
1017
if (priv->grabs.empty ())
1018
XAllowEvents (priv->dpy, AsyncPointer, event->xbutton.time);
1020
actionEventHandled = true;
1023
if (priv->grabs.empty ())
1025
switch (event->type)
1028
XUngrabKeyboard (priv->dpy, event->xkey.time);
1035
if (actionEventHandled)
1038
switch (event->type) {
1039
case SelectionRequest:
1040
priv->handleSelectionRequest (event);
1042
case SelectionClear:
1043
priv->handleSelectionClear (event);
1045
case ConfigureNotify:
1046
w = findWindow (event->xconfigure.window);
1048
if (w && !w->priv->frame)
1050
w->priv->configure (&event->xconfigure);
1054
w = findTopLevelWindow (event->xconfigure.window);
1056
if (w && w->priv->frame == event->xconfigure.window)
1057
w->priv->configureFrame (&event->xconfigure);
1060
if (event->xconfigure.window == priv->root)
1061
priv->configure (&event->xconfigure);
1069
/* Failure means that window has been destroyed. We still have to add
1070
* the window to the window list as we might get configure requests
1071
* which require us to stack other windows relative to it. Setting
1072
* some default values if this is the case. */
1073
if (!XGetWindowAttributes (priv->dpy, event->xcreatewindow.window, &wa))
1074
priv->setDefaultWindowAttributes (&wa);
1076
foreach (CompWindow *w, screen->windows ())
1078
if (w->priv->serverFrame == event->xcreatewindow.window)
1080
w->priv->frame = event->xcreatewindow.window;
1081
w->priv->updatePassiveButtonGrabs ();
1086
foreach (CompWindow *w, screen->priv->destroyedWindows)
1088
if (w->priv->serverId == event->xcreatewindow.window)
1090
/* Previously destroyed window
1091
* plugins were keeping around
1092
* in order to avoid an xid conflict,
1093
* destroy it right away and manage
1096
StackDebugger *dbg = StackDebugger::Default ();
1098
while (w->priv->destroyRefCnt)
1102
dbg->removeDestroyedFrame (event->xcreatewindow.window);
1107
if (wa.root != event->xcreatewindow.parent)
1112
/* Track the window if it was created on this
1113
* screen, otherwise we still need to register
1114
* for FocusChangeMask. Also, we don't want to
1115
* manage it straight away - in reality we want
1116
* that to wait until the map request */
1117
if ((wa.root == priv->root))
1119
CoreWindow *cw = new CoreWindow (event->xcreatewindow.window);
1120
cw->manage (priv->getTopWindow (), wa);
1122
priv->createdWindows.remove (cw);
1126
XSelectInput (priv->dpy, event->xcreatewindow.window,
1130
compLogMessage ("core", CompLogLevelDebug, "refusing to manage window 0x%x", (unsigned int) event->xcreatewindow.window);
1135
w = findWindow (event->xdestroywindow.window);
1137
/* It is possible that some plugin might call
1138
* w->destroy () before the window actually receives
1139
* its first DestroyNotify event which would mean
1140
* that it is already in the list of destroyed
1141
* windows, so check that list too */
1145
foreach (CompWindow *dw, screen->priv->destroyedWindows)
1147
if (dw->priv->serverId == event->xdestroywindow.window)
1157
w->moveInputFocusToOtherWindow ();
1163
/* Search in already-created windows for this window */
1165
w = findWindow (event->xmap.window);
1169
if (w->priv->pendingMaps)
1171
/* The only case where this happens
1172
* is where the window unmaps itself
1173
* but doesn't get destroyed so when
1174
* it re-maps we need to reparent it */
1176
if (!w->priv->serverFrame)
1177
w->priv->reparent ();
1179
w->priv->managed = true;
1183
if (w->priv->height == 0)
1185
if (w->id () == priv->activeWindow)
1186
w->moveInputFocusTo ();
1194
w = findWindow (event->xunmap.window);
1197
/* Normal -> Iconic */
1198
if (w->pendingUnmaps ())
1200
priv->setWmState (IconicState, w->id ());
1201
w->priv->pendingUnmaps--;
1203
else /* X -> Withdrawn */
1205
/* Iconic -> Withdrawn:
1207
* The window is already unmapped so we need to check the
1208
* synthetic UnmapNotify that comes and withdraw the window here */
1209
if (w->state () & CompWindowStateHiddenMask)
1211
w->priv->minimized = false;
1212
w->changeState (w->state () & ~CompWindowStateHiddenMask);
1214
priv->updateClientList ();
1215
w->priv->withdraw ();
1219
* ICCCM Section 4.1.4 says that clients need to send
1220
* a synthetic UnmapNotify for every real unmap
1221
* in order to reflect the change in state, but
1222
* since we already withdraw the window on the real
1223
* UnmapNotify, no need to do it again on the synthetic
1225
else if (!event->xunmap.send_event)
1227
w->windowNotify (CompWindowNotifyClose);
1228
w->priv->withdraw ();
1232
if (!event->xunmap.send_event)
1236
if (!w->shaded () && !w->priv->pendingMaps)
1237
w->moveInputFocusToOtherWindow ();
1241
case ReparentNotify:
1242
w = findWindow (event->xreparent.window);
1244
/* It is possible that some plugin might call
1245
* w->destroy () before the window actually receives
1246
* its first ReparentNotify event which would mean
1247
* that it is already in the list of destroyed
1248
* windows, so check that list too */
1251
foreach (CompWindow *dw, screen->priv->destroyedWindows)
1253
if (dw->priv->serverId == event->xdestroywindow.window)
1261
if (!w && event->xreparent.parent == priv->root)
1263
/* Failure means that window has been destroyed. We still have to add
1264
* the window to the window list as we might get configure requests
1265
* which require us to stack other windows relative to it. Setting
1266
* some default values if this is the case. */
1267
if (!XGetWindowAttributes (priv->dpy, event->xcreatewindow.window, &wa))
1268
priv->setDefaultWindowAttributes (&wa);
1270
CoreWindow *cw = new CoreWindow (event->xcreatewindow.window);
1271
cw->manage (priv->getTopWindow (), wa);
1273
priv->createdWindows.remove (cw);
1276
else if (!(event->xreparent.parent == priv->root))
1278
/* This is the only case where a window is removed but not
1279
destroyed. We must remove our event mask and all passive
1284
if (event->xreparent.parent != w->priv->wrapper)
1286
w->moveInputFocusToOtherWindow ();
1289
XSelectInput (priv->dpy, w->id (), NoEventMask);
1290
XShapeSelectInput (priv->dpy, w->id (), NoEventMask);
1291
XUngrabButton (priv->dpy, AnyButton, AnyModifier, w->id ());
1296
case CirculateNotify:
1297
w = findWindow (event->xcirculate.window);
1299
w->priv->circulate (&event->xcirculate);
1302
if (event->xbutton.button == Button1 ||
1303
event->xbutton.button == Button2 ||
1304
event->xbutton.button == Button3)
1306
w = findTopLevelWindow (event->xbutton.window);
1309
if (priv->optionGetRaiseOnClick ())
1311
w->updateAttributes (CompStackingUpdateModeAboveFullscreen);
1314
if (w->id () != priv->activeWindow)
1315
if (!(w->type () & CompWindowTypeDockMask))
1317
w->moveInputFocusTo ();
1321
if (priv->grabs.empty ())
1322
XAllowEvents (priv->dpy, ReplayPointer, event->xbutton.time);
1325
case PropertyNotify:
1326
if (event->xproperty.atom == Atoms::winType)
1328
w = findWindow (event->xproperty.window);
1333
type = priv->getWindowType (w->id ());
1335
if (type != w->wmType ())
1337
if (w->isViewable ())
1339
if (w->type () == CompWindowTypeDesktopMask)
1340
priv->desktopWindowCount--;
1341
else if (type == CompWindowTypeDesktopMask)
1342
priv->desktopWindowCount++;
1345
w->wmType () = type;
1348
w->recalcActions ();
1350
if (type & (CompWindowTypeDockMask |
1351
CompWindowTypeDesktopMask))
1352
w->setDesktop (0xffffffff);
1354
priv->updateClientList ();
1356
matchPropertyChanged (w);
1360
else if (event->xproperty.atom == Atoms::winState)
1362
w = findWindow (event->xproperty.window);
1363
if (w && !w->managed ())
1367
state = priv->getWindowState (w->id ());
1368
state = CompWindow::constrainWindowState (state, w->actions ());
1370
/* EWMH suggests that we ignore changes
1371
to _NET_WM_STATE_HIDDEN */
1372
if (w->state () & CompWindowStateHiddenMask)
1373
state |= CompWindowStateHiddenMask;
1375
state &= ~CompWindowStateHiddenMask;
1377
w->changeState (state);
1380
else if (event->xproperty.atom == XA_WM_NORMAL_HINTS)
1382
w = findWindow (event->xproperty.window);
1385
w->priv->updateNormalHints ();
1386
w->recalcActions ();
1389
else if (event->xproperty.atom == XA_WM_HINTS)
1391
w = findWindow (event->xproperty.window);
1393
w->priv->updateWmHints ();
1395
else if (event->xproperty.atom == XA_WM_TRANSIENT_FOR)
1397
w = findWindow (event->xproperty.window);
1400
w->priv->updateTransientHint ();
1401
w->recalcActions ();
1404
else if (event->xproperty.atom == Atoms::wmClientLeader)
1406
w = findWindow (event->xproperty.window);
1408
w->priv->clientLeader = w->priv->getClientLeader ();
1410
else if (event->xproperty.atom == Atoms::wmIconGeometry)
1412
w = findWindow (event->xproperty.window);
1414
w->priv->updateIconGeometry ();
1416
else if (event->xproperty.atom == Atoms::wmStrut ||
1417
event->xproperty.atom == Atoms::wmStrutPartial)
1419
w = findWindow (event->xproperty.window);
1422
if (w->updateStruts ())
1426
else if (event->xproperty.atom == Atoms::mwmHints)
1428
w = findWindow (event->xproperty.window);
1430
w->priv->updateMwmHints ();
1432
else if (event->xproperty.atom == Atoms::wmProtocols)
1434
w = findWindow (event->xproperty.window);
1436
w->priv->protocols = priv->getProtocols (w->id ());
1438
else if (event->xproperty.atom == Atoms::wmIcon)
1440
w = findWindow (event->xproperty.window);
1442
w->priv->freeIcons ();
1444
else if (event->xproperty.atom == Atoms::startupId)
1446
w = findWindow (event->xproperty.window);
1448
w->priv->updateStartupId ();
1450
else if (event->xproperty.atom == XA_WM_CLASS)
1452
w = findWindow (event->xproperty.window);
1454
w->priv->updateClassHints ();
1460
if (event->xclient.message_type == Atoms::winActive)
1462
w = findTopLevelWindow (event->xclient.window);
1465
/* use focus stealing prevention if request came
1466
from an application */
1467
if (event->xclient.data.l[0] != ClientTypeApplication ||
1468
w->priv->allowWindowFocus (0, event->xclient.data.l[1]))
1474
else if (event->xclient.message_type == Atoms::winState)
1476
w = findWindow (event->xclient.window);
1479
unsigned long wState, state;
1482
wState = w->state ();
1484
for (i = 1; i < 3; i++)
1486
state = priv->windowStateMask (event->xclient.data.l[i]);
1487
if (state & ~CompWindowStateHiddenMask)
1490
#define _NET_WM_STATE_REMOVE 0
1491
#define _NET_WM_STATE_ADD 1
1492
#define _NET_WM_STATE_TOGGLE 2
1494
switch (event->xclient.data.l[0]) {
1495
case _NET_WM_STATE_REMOVE:
1498
case _NET_WM_STATE_ADD:
1501
case _NET_WM_STATE_TOGGLE:
1508
wState = CompWindow::constrainWindowState (wState,
1510
if (w->id () == priv->activeWindow)
1511
wState &= ~CompWindowStateDemandsAttentionMask;
1513
if (wState != w->state ())
1515
CompStackingUpdateMode stackingUpdateMode;
1516
unsigned long dState = wState ^ w->state ();
1518
stackingUpdateMode = CompStackingUpdateModeNone;
1520
/* raise the window whenever its fullscreen state,
1521
above/below state or maximization state changed */
1522
if (dState & (CompWindowStateFullscreenMask |
1523
CompWindowStateAboveMask |
1524
CompWindowStateBelowMask |
1525
CompWindowStateMaximizedHorzMask |
1526
CompWindowStateMaximizedVertMask))
1527
stackingUpdateMode = CompStackingUpdateModeNormal;
1529
w->changeState (wState);
1531
w->updateAttributes (stackingUpdateMode);
1535
else if (event->xclient.message_type == Atoms::wmProtocols)
1537
if ((unsigned long) event->xclient.data.l[0] == Atoms::wmPing)
1539
w = findWindow (event->xclient.data.l[2]);
1541
w->priv->handlePing (priv->lastPing);
1544
else if (event->xclient.message_type == Atoms::closeWindow)
1546
w = findWindow (event->xclient.window);
1548
w->close (event->xclient.data.l[0]);
1550
else if (event->xclient.message_type == Atoms::desktopGeometry)
1552
if (event->xclient.window == priv->root)
1554
CompOption::Value value;
1556
value.set ((int) (event->xclient.data.l[0] /
1559
setOptionForPlugin ("core", "hsize", value);
1561
value.set ((int) (event->xclient.data.l[1] /
1564
setOptionForPlugin ("core", "vsize", value);
1567
else if (event->xclient.message_type == Atoms::moveResizeWindow)
1569
w = findWindow (event->xclient.window);
1572
unsigned int xwcm = 0;
1576
unsigned int source;
1578
gravity = (event->xclient.data.l[0] & 0xFF);
1579
value_mask = (event->xclient.data.l[0] & 0xF00) >> 8;
1580
source = (event->xclient.data.l[0] & 0xF000) >> 12;
1582
memset (&xwc, 0, sizeof (xwc));
1584
if (value_mask & CWX)
1587
xwc.x = event->xclient.data.l[1];
1590
if (value_mask & CWY)
1593
xwc.y = event->xclient.data.l[2];
1596
if (value_mask & CWWidth)
1599
xwc.width = event->xclient.data.l[3];
1602
if (value_mask & CWHeight)
1605
xwc.height = event->xclient.data.l[4];
1608
w->moveResize (&xwc, xwcm, gravity, source);
1611
else if (event->xclient.message_type == Atoms::restackWindow)
1613
w = findWindow (event->xclient.window);
1616
/* TODO: other stack modes than Above and Below */
1617
if (event->xclient.data.l[1])
1619
CompWindow *sibling;
1621
sibling = findWindow (event->xclient.data.l[1]);
1624
if (event->xclient.data.l[2] == Above)
1625
w->restackAbove (sibling);
1626
else if (event->xclient.data.l[2] == Below)
1627
w->restackBelow (sibling);
1632
if (event->xclient.data.l[2] == Above)
1634
else if (event->xclient.data.l[2] == Below)
1639
else if (event->xclient.message_type == Atoms::wmChangeState)
1641
w = findWindow (event->xclient.window);
1644
if (event->xclient.data.l[0] == IconicState)
1646
if (w->actions () & CompWindowActionMinimizeMask)
1649
else if (event->xclient.data.l[0] == NormalState)
1655
else if (event->xclient.message_type == Atoms::showingDesktop)
1657
if (event->xclient.window == priv->root ||
1658
event->xclient.window == None)
1660
if (event->xclient.data.l[0])
1661
enterShowDesktopMode ();
1663
leaveShowDesktopMode (NULL);
1666
else if (event->xclient.message_type == Atoms::numberOfDesktops)
1668
if (event->xclient.window == priv->root)
1670
CompOption::Value value;
1672
value.set ((int) event->xclient.data.l[0]);
1674
setOptionForPlugin ("core", "number_of_desktops", value);
1677
else if (event->xclient.message_type == Atoms::currentDesktop)
1679
if (event->xclient.window == priv->root)
1680
priv->setCurrentDesktop (event->xclient.data.l[0]);
1682
else if (event->xclient.message_type == Atoms::winDesktop)
1684
w = findWindow (event->xclient.window);
1686
w->setDesktop (event->xclient.data.l[0]);
1688
else if (event->xclient.message_type == Atoms::wmFullscreenMonitors)
1690
w = findWindow (event->xclient.window);
1693
CompFullscreenMonitorSet monitors;
1695
monitors.top = event->xclient.data.l[0];
1696
monitors.bottom = event->xclient.data.l[1];
1697
monitors.left = event->xclient.data.l[2];
1698
monitors.right = event->xclient.data.l[3];
1700
w->priv->setFullscreenMonitors (&monitors);
1705
modHandler->updateModifierMappings ();
1708
w = screen->findWindow (event->xmaprequest.window);
1712
XWindowAttributes attr;
1713
bool doMapProcessing = true;
1715
/* We should check the override_redirect flag here, because the
1716
client might have changed it while being unmapped. */
1717
if (XGetWindowAttributes (priv->dpy, w->id (), &attr))
1718
w->priv->setOverrideRedirect (attr.override_redirect != 0);
1720
if (w->state () & CompWindowStateHiddenMask)
1721
if (!w->minimized () && !w->inShowDesktopMode ())
1722
doMapProcessing = false;
1724
if (doMapProcessing)
1725
w->priv->processMap ();
1727
w->priv->managed = true;
1729
setWindowProp (w->id (), Atoms::winDesktop, w->desktop ());
1733
XMapWindow (priv->dpy, event->xmaprequest.window);
1736
case ConfigureRequest:
1737
w = findWindow (event->xconfigurerequest.window);
1738
if (w && w->managed ())
1742
memset (&xwc, 0, sizeof (xwc));
1744
xwc.x = event->xconfigurerequest.x;
1745
xwc.y = event->xconfigurerequest.y;
1746
xwc.width = event->xconfigurerequest.width;
1747
xwc.height = event->xconfigurerequest.height;
1748
xwc.border_width = event->xconfigurerequest.border_width;
1750
w->moveResize (&xwc, event->xconfigurerequest.value_mask,
1751
0, ClientTypeUnknown);
1753
if (event->xconfigurerequest.value_mask & CWStackMode)
1755
Window above = None;
1756
CompWindow *sibling = NULL;
1758
if (event->xconfigurerequest.value_mask & CWSibling)
1760
above = event->xconfigurerequest.above;
1761
sibling = findTopLevelWindow (above);
1764
switch (event->xconfigurerequest.detail) {
1766
if (w->priv->allowWindowFocus (NO_FOCUS_MASK, 0))
1771
w->restackAbove (sibling);
1781
w->restackBelow (sibling);
1787
/* no handling of the TopIf, BottomIf, Opposite cases -
1788
there will hardly be any client using that */
1798
xwcm = event->xconfigurerequest.value_mask &
1799
(CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
1801
xwc.x = event->xconfigurerequest.x;
1802
xwc.y = event->xconfigurerequest.y;
1803
xwc.width = event->xconfigurerequest.width;
1804
xwc.height = event->xconfigurerequest.height;
1805
xwc.border_width = event->xconfigurerequest.border_width;
1809
/* Any window that receives a ConfigureRequest
1810
* is not override redirect, and may have changed
1811
* to being not override redirect */
1812
w->priv->setOverrideRedirect (false);
1813
w->configureXWindow (xwcm, &xwc);
1816
XConfigureWindow (priv->dpy, event->xconfigurerequest.window,
1820
case CirculateRequest:
1824
if (!XGetWindowAttributes (priv->dpy, event->xfocus.window, &wa))
1825
priv->setDefaultWindowAttributes (&wa);
1827
/* If the call to XGetWindowAttributes failed it means
1828
* the window was destroyed, so track the focus change
1829
* anyways since we need to increment activeNum
1830
* and the passive button grabs and then we will
1831
* get the DestroyNotify later and change the focus
1835
if (wa.root == priv->root)
1837
if (event->xfocus.mode != NotifyGrab)
1839
w = findTopLevelWindow (event->xfocus.window);
1840
if (w && w->managed ())
1842
unsigned int state = w->state ();
1844
if (w->id () != priv->activeWindow)
1846
CompWindow *active = screen->findWindow (priv->activeWindow);
1847
w->windowNotify (CompWindowNotifyFocusChange);
1849
priv->activeWindow = w->id ();
1850
w->priv->activeNum = priv->activeNum++;
1853
active->priv->updatePassiveButtonGrabs ();
1855
w->priv->updatePassiveButtonGrabs ();
1857
priv->addToCurrentActiveWindowHistory (w->id ());
1859
XChangeProperty (priv->dpy , priv->root,
1861
XA_WINDOW, 32, PropModeReplace,
1862
(unsigned char *) &priv->activeWindow, 1);
1865
state &= ~CompWindowStateDemandsAttentionMask;
1866
w->changeState (state);
1868
if (priv->nextActiveWindow == event->xfocus.window)
1869
priv->nextActiveWindow = None;
1871
else if (event->xfocus.window == priv->root)
1873
/* Don't ever let the focus go to the root
1874
* window except in grab cases
1876
* FIXME: There might be a case where we have to
1877
* handle root windows of other screens here, but
1878
* the other window managers should handle that
1881
if (event->xfocus.detail == NotifyDetailNone ||
1882
(event->xfocus.mode == NotifyNormal &&
1883
event->xfocus.detail == NotifyInferior))
1885
priv->activeWindow = None;
1887
if (event->xfocus.detail == NotifyDetailNone ||
1888
(event->xfocus.mode == NotifyNormal &&
1889
event->xfocus.detail == NotifyInferior))
1891
screen->focusDefaultWindow ();
1897
priv->grabbed = true;
1903
w = screen->findWindow (priv->activeWindow);
1905
priv->nextActiveWindow = None;
1906
priv->activeWindow = None;
1909
w->priv->updatePassiveButtonGrabs ();
1914
if (event->xfocus.mode == NotifyUngrab)
1915
priv->grabbed = false;
1918
if (event->xcrossing.root == priv->root)
1919
w = findTopLevelWindow (event->xcrossing.window);
1923
if (w && w->id () != priv->below)
1925
priv->below = w->id ();
1927
if (!priv->optionGetClickToFocus () &&
1928
priv->grabs.empty () &&
1929
event->xcrossing.mode != NotifyGrab &&
1930
event->xcrossing.detail != NotifyInferior)
1935
raise = priv->optionGetAutoraise ();
1936
delay = priv->optionGetAutoraiseDelay ();
1938
if (priv->autoRaiseTimer.active () &&
1939
priv->autoRaiseWindow != w->id ())
1941
priv->autoRaiseTimer.stop ();
1944
if (w->type () & ~(CompWindowTypeDockMask |
1945
CompWindowTypeDesktopMask))
1947
w->moveInputFocusTo ();
1953
priv->autoRaiseWindow = w->id ();
1954
priv->autoRaiseTimer.start (
1955
boost::bind (autoRaiseTimeout, this),
1956
delay, (unsigned int) ((float) delay * 1.2));
1960
CompStackingUpdateMode mode =
1961
CompStackingUpdateModeNormal;
1963
w->updateAttributes (mode);
1971
if (event->xcrossing.detail != NotifyInferior)
1973
if (event->xcrossing.window == priv->below)
1978
if (priv->shapeExtension &&
1979
event->type == priv->shapeEvent + ShapeNotify)
1981
w = findWindow (((XShapeEvent *) event)->window);
1985
w->priv->updateRegion ();
1988
else if (event->type == priv->syncEvent + XSyncAlarmNotify)
1990
XSyncAlarmNotifyEvent *sa;
1992
sa = (XSyncAlarmNotifyEvent *) event;
1995
foreach (w, priv->windows)
1997
if (w->priv->syncAlarm == sa->alarm)
1999
w->priv->handleSyncAlarm ();