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"
44
static Window xdndWindow = None;
45
static Window edgeWindow = None;
50
PrivateWindow::handleSyncAlarm ()
54
priv->syncWait = false;
56
if (window->resize (priv->syncGeometry))
58
window->windowNotify (CompWindowNotifySyncAlarm);
62
/* resizeWindow failing means that there is another pending
63
resize and we must send a new sync request to the client */
64
window->sendSyncRequest ();
73
autoRaiseTimeout (CompScreen *screen)
75
CompWindow *w = screen->findWindow (screen->activeWindow ());
77
if (screen->autoRaiseWindow () == screen->activeWindow () ||
78
(w && (screen->autoRaiseWindow () == w->transientFor ())))
80
w = screen->findWindow (screen->autoRaiseWindow ());
82
w->updateAttributes (CompStackingUpdateModeNormal);
88
#define REAL_MOD_MASK (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | \
89
Mod3Mask | Mod4Mask | Mod5Mask | CompNoMask)
92
isCallBackBinding (CompOption &option,
93
CompAction::BindingType type,
94
CompAction::State state)
96
if (!option.isAction ())
99
if (!(option.value ().action ().type () & type))
102
if (!(option.value ().action ().state () & state))
109
isInitiateBinding (CompOption &option,
110
CompAction::BindingType type,
111
CompAction::State state,
114
if (!isCallBackBinding (option, type, state))
117
if (option.value ().action ().initiate ().empty ())
120
*action = &option.value ().action ();
126
isTerminateBinding (CompOption &option,
127
CompAction::BindingType type,
128
CompAction::State state,
131
if (!isCallBackBinding (option, type, state))
134
if (option.value ().action ().terminate ().empty ())
137
*action = &option.value ().action ();
143
PrivateScreen::triggerButtonPressBindings (CompOption::Vector &options,
145
CompOption::Vector &arguments)
147
CompAction::State state = CompAction::StateInitButton;
149
unsigned int ignored = modHandler->ignoredModMask ();
150
unsigned int modMask = REAL_MOD_MASK & ~ignored;
151
unsigned int bindMods;
152
unsigned int edge = 0;
158
if (event->root != root)
161
if (event->window != edgeWindow)
163
if (grabs.empty () || event->window != root)
167
for (i = 0; i < SCREEN_EDGE_NUM; i++)
169
if (edgeWindow == screenEdge[i].id)
172
arguments[1].value ().set ((int) activeWindow);
178
foreach (CompOption &option, options)
180
if (isInitiateBinding (option, CompAction::BindingTypeButton, state,
183
if (action->button ().button () == (int) event->button)
185
bindMods = modHandler->virtualToRealModMask (
186
action->button ().modifiers ());
188
if ((bindMods & modMask) == (event->state & modMask))
189
if (action->initiate () (action, state, arguments))
196
if (isInitiateBinding (option, CompAction::BindingTypeEdgeButton,
197
state | CompAction::StateInitEdge, &action))
199
if ((action->button ().button () == (int) event->button) &&
200
(action->edgeMask () & edge))
202
bindMods = modHandler->virtualToRealModMask (
203
action->button ().modifiers ());
205
if ((bindMods & modMask) == (event->state & modMask))
206
if (action->initiate () (action, state |
207
CompAction::StateInitEdge,
219
PrivateScreen::triggerButtonReleaseBindings (CompOption::Vector &options,
221
CompOption::Vector &arguments)
223
CompAction::State state = CompAction::StateTermButton;
224
CompAction::BindingType type = CompAction::BindingTypeButton |
225
CompAction::BindingTypeEdgeButton;
228
foreach (CompOption &option, options)
230
if (isTerminateBinding (option, type, state, &action))
232
if (action->button ().button () == (int) event->button)
234
if (action->terminate () (action, state, arguments))
244
PrivateScreen::triggerKeyPressBindings (CompOption::Vector &options,
246
CompOption::Vector &arguments)
248
CompAction::State state = 0;
250
unsigned int modMask = REAL_MOD_MASK & ~modHandler->ignoredModMask ();
251
unsigned int bindMods;
253
if (event->keycode == escapeKeyCode)
254
state = CompAction::StateCancel;
255
else if (event->keycode == returnKeyCode)
256
state = CompAction::StateCommit;
260
foreach (CompOption &o, options)
264
if (!o.value ().action ().terminate ().empty ())
265
o.value ().action ().terminate () (&o.value ().action (),
270
if (state == CompAction::StateCancel)
274
state = CompAction::StateInitKey;
275
foreach (CompOption &option, options)
277
if (isInitiateBinding (option, CompAction::BindingTypeKey,
280
bindMods = modHandler->virtualToRealModMask (
281
action->key ().modifiers ());
283
if (action->key ().keycode () == (int) event->keycode)
285
if ((bindMods & modMask) == (event->state & modMask))
286
if (action->initiate () (action, state, arguments))
289
else if (!xkbEvent && action->key ().keycode () == 0)
291
if (bindMods == (event->state & modMask))
292
if (action->initiate () (action, state, arguments))
302
PrivateScreen::triggerKeyReleaseBindings (CompOption::Vector &options,
304
CompOption::Vector &arguments)
306
CompAction::State state = CompAction::StateTermKey;
308
unsigned int ignored = modHandler->ignoredModMask ();
309
unsigned int modMask = REAL_MOD_MASK & ~ignored;
310
unsigned int bindMods;
313
mods = modHandler->keycodeToModifiers (event->keycode);
314
if (!xkbEvent && !mods)
317
foreach (CompOption &option, options)
319
if (isTerminateBinding (option, CompAction::BindingTypeKey,
322
bindMods = modHandler->virtualToRealModMask (action->key ().modifiers ());
324
if ((bindMods & modMask) == 0)
326
if ((unsigned int) action->key ().keycode () ==
327
(unsigned int) event->keycode)
329
if (action->terminate () (action, state, arguments))
333
else if (!xkbEvent && ((mods & modMask & bindMods) != bindMods))
335
if (action->terminate () (action, state, arguments))
345
PrivateScreen::triggerStateNotifyBindings (CompOption::Vector &options,
346
XkbStateNotifyEvent *event,
347
CompOption::Vector &arguments)
349
CompAction::State state;
351
unsigned int ignored = modHandler->ignoredModMask ();
352
unsigned int modMask = REAL_MOD_MASK & ~ignored;
353
unsigned int bindMods;
355
if (event->event_type == KeyPress)
357
state = CompAction::StateInitKey;
359
foreach (CompOption &option, options)
361
if (isInitiateBinding (option, CompAction::BindingTypeKey,
364
if (action->key ().keycode () == 0)
367
modHandler->virtualToRealModMask (action->key ().modifiers ());
369
if ((event->mods & modMask & bindMods) == bindMods)
371
if (action->initiate () (action, state, arguments))
380
state = CompAction::StateTermKey;
382
foreach (CompOption &option, options)
384
if (isTerminateBinding (option, CompAction::BindingTypeKey,
387
bindMods = modHandler->virtualToRealModMask (action->key ().modifiers ());
389
if ((event->mods & modMask & bindMods) != bindMods)
391
if (action->terminate () (action, state, arguments))
402
isBellAction (CompOption &option,
403
CompAction::State state,
406
if (option.type () != CompOption::TypeAction &&
407
option.type () != CompOption::TypeBell)
410
if (!option.value ().action ().bell ())
413
if (!(option.value ().action ().state () & state))
416
if (option.value ().action ().initiate ().empty ())
419
*action = &option.value ().action ();
425
triggerBellNotifyBindings (CompOption::Vector &options,
426
CompOption::Vector &arguments)
428
CompAction::State state = CompAction::StateInitBell;
431
foreach (CompOption &option, options)
433
if (isBellAction (option, state, &action))
435
if (action->initiate () (action, state, arguments))
444
isEdgeAction (CompOption &option,
445
CompAction::State state,
448
if (option.type () != CompOption::TypeAction &&
449
option.type () != CompOption::TypeButton &&
450
option.type () != CompOption::TypeEdge)
453
if (!(option.value ().action ().edgeMask () & edge))
456
if (!(option.value ().action ().state () & state))
463
isEdgeEnterAction (CompOption &option,
464
CompAction::State state,
465
CompAction::State delayState,
469
if (!isEdgeAction (option, state, edge))
472
if (option.value ().action ().type () & CompAction::BindingTypeEdgeButton)
475
if (option.value ().action ().initiate ().empty ())
480
if ((option.value ().action ().state () &
481
CompAction::StateNoEdgeDelay) !=
482
(delayState & CompAction::StateNoEdgeDelay))
484
/* ignore edge actions which shouldn't be delayed when invoking
485
undelayed edges (or vice versa) */
491
*action = &option.value ().action ();
497
isEdgeLeaveAction (CompOption &option,
498
CompAction::State state,
502
if (!isEdgeAction (option, state, edge))
505
if (option.value ().action ().terminate ().empty ())
508
*action = &option.value ().action ();
514
triggerEdgeEnterBindings (CompOption::Vector &options,
515
CompAction::State state,
516
CompAction::State delayState,
518
CompOption::Vector &arguments)
522
foreach (CompOption &option, options)
524
if (isEdgeEnterAction (option, state, delayState, edge, &action))
526
if (action->initiate () (action, state, arguments))
535
triggerEdgeLeaveBindings (CompOption::Vector &options,
536
CompAction::State state,
538
CompOption::Vector &arguments)
542
foreach (CompOption &option, options)
544
if (isEdgeLeaveAction (option, state, edge, &action))
546
if (action->terminate () (action, state, arguments))
555
triggerAllEdgeEnterBindings (CompAction::State state,
556
CompAction::State delayState,
558
CompOption::Vector &arguments)
560
foreach (CompPlugin *p, CompPlugin::getPlugins ())
562
CompOption::Vector &options = p->vTable->getOptions ();
563
if (triggerEdgeEnterBindings (options, state, delayState, edge,
573
delayedEdgeTimeout (CompDelayedEdgeSettings *settings)
575
triggerAllEdgeEnterBindings (settings->state,
576
~CompAction::StateNoEdgeDelay,
584
PrivateScreen::triggerEdgeEnter (unsigned int edge,
585
CompAction::State state,
586
CompOption::Vector &arguments)
590
delay = optionGetEdgeDelay ();
594
CompAction::State delayState;
595
edgeDelaySettings.edge = edge;
596
edgeDelaySettings.state = state;
597
edgeDelaySettings.options = arguments;
599
edgeDelayTimer.start (
600
boost::bind (delayedEdgeTimeout, &edgeDelaySettings),
601
delay, (unsigned int) ((float) delay * 1.2));
603
delayState = CompAction::StateNoEdgeDelay;
604
if (triggerAllEdgeEnterBindings (state, delayState, edge, arguments))
609
if (triggerAllEdgeEnterBindings (state, 0, edge, arguments))
617
PrivateScreen::handleActionEvent (XEvent *event)
619
static CompOption::Vector o (8);
622
o[0].setName ("event_window", CompOption::TypeInt);
623
o[1].setName ("window", CompOption::TypeInt);
624
o[2].setName ("modifiers", CompOption::TypeInt);
625
o[3].setName ("x", CompOption::TypeInt);
626
o[4].setName ("y", CompOption::TypeInt);
627
o[5].setName ("root", CompOption::TypeInt);
631
switch (event->type) {
633
/* We need to determine if we clicked on a parent frame
634
* window, if so, pass the appropriate child window as
635
* "window" and the frame as "event_window"
638
xid = event->xbutton.window;
640
foreach (CompWindow *w, screen->windows ())
642
if (w->frame () == xid)
646
o[0].value ().set ((int) event->xbutton.window);
647
o[1].value ().set ((int) xid);
648
o[2].value ().set ((int) event->xbutton.state);
649
o[3].value ().set ((int) event->xbutton.x_root);
650
o[4].value ().set ((int) event->xbutton.y_root);
651
o[5].value ().set ((int) event->xbutton.root);
653
o[6].setName ("button", CompOption::TypeInt);
654
o[7].setName ("time", CompOption::TypeInt);
656
o[6].value ().set ((int) event->xbutton.button);
657
o[7].value ().set ((int) event->xbutton.time);
659
foreach (CompPlugin *p, CompPlugin::getPlugins ())
661
CompOption::Vector &options = p->vTable->getOptions ();
662
if (triggerButtonPressBindings (options, &event->xbutton, o))
667
o[0].value ().set ((int) event->xbutton.window);
668
o[1].value ().set ((int) event->xbutton.window);
669
o[2].value ().set ((int) event->xbutton.state);
670
o[3].value ().set ((int) event->xbutton.x_root);
671
o[4].value ().set ((int) event->xbutton.y_root);
672
o[5].value ().set ((int) event->xbutton.root);
674
o[6].setName ("button", CompOption::TypeInt);
675
o[7].setName ("time", CompOption::TypeInt);
677
o[6].value ().set ((int) event->xbutton.button);
678
o[7].value ().set ((int) event->xbutton.time);
680
foreach (CompPlugin *p, CompPlugin::getPlugins ())
682
CompOption::Vector &options = p->vTable->getOptions ();
683
if (triggerButtonReleaseBindings (options, &event->xbutton, o))
688
o[0].value ().set ((int) event->xkey.window);
689
o[1].value ().set ((int) activeWindow);
690
o[2].value ().set ((int) event->xkey.state);
691
o[3].value ().set ((int) event->xkey.x_root);
692
o[4].value ().set ((int) event->xkey.y_root);
693
o[5].value ().set ((int) event->xkey.root);
695
o[6].setName ("keycode", CompOption::TypeInt);
696
o[7].setName ("time", CompOption::TypeInt);
698
o[6].value ().set ((int) event->xkey.keycode);
699
o[7].value ().set ((int) event->xkey.time);
701
foreach (CompPlugin *p, CompPlugin::getPlugins ())
703
CompOption::Vector &options = p->vTable->getOptions ();
704
if (triggerKeyPressBindings (options, &event->xkey, o))
709
o[0].value ().set ((int) event->xkey.window);
710
o[1].value ().set ((int) activeWindow);
711
o[2].value ().set ((int) event->xkey.state);
712
o[3].value ().set ((int) event->xkey.x_root);
713
o[4].value ().set ((int) event->xkey.y_root);
714
o[5].value ().set ((int) event->xkey.root);
716
o[6].setName ("keycode", CompOption::TypeInt);
717
o[7].setName ("time", CompOption::TypeInt);
719
o[6].value ().set ((int) event->xkey.keycode);
720
o[7].value ().set ((int) event->xkey.time);
722
foreach (CompPlugin *p, CompPlugin::getPlugins ())
724
CompOption::Vector &options = p->vTable->getOptions ();
725
if (triggerKeyReleaseBindings (options, &event->xkey, o))
730
if (event->xcrossing.mode != NotifyGrab &&
731
event->xcrossing.mode != NotifyUngrab &&
732
event->xcrossing.detail != NotifyInferior)
734
unsigned int edge, i;
735
CompAction::State state;
737
if (event->xcrossing.root != root)
740
if (edgeDelayTimer.active ())
741
edgeDelayTimer.stop ();
743
if (edgeWindow && edgeWindow != event->xcrossing.window)
745
state = CompAction::StateTermEdge;
748
for (i = 0; i < SCREEN_EDGE_NUM; i++)
750
if (edgeWindow == screenEdge[i].id)
759
o[0].value ().set ((int) event->xcrossing.window);
760
o[1].value ().set ((int) activeWindow);
761
o[2].value ().set ((int) event->xcrossing.state);
762
o[3].value ().set ((int) event->xcrossing.x_root);
763
o[4].value ().set ((int) event->xcrossing.y_root);
764
o[5].value ().set ((int) event->xcrossing.root);
766
o[6].setName ("time", CompOption::TypeInt);
767
o[6].value ().set ((int) event->xcrossing.time);
769
foreach (CompPlugin *p, CompPlugin::getPlugins ())
771
CompOption::Vector &options = p->vTable->getOptions ();
772
if (triggerEdgeLeaveBindings (options, state, edge, o))
779
for (i = 0; i < SCREEN_EDGE_NUM; i++)
781
if (event->xcrossing.window == screenEdge[i].id)
790
state = CompAction::StateInitEdge;
792
edgeWindow = event->xcrossing.window;
794
o[0].value ().set ((int) event->xcrossing.window);
795
o[1].value ().set ((int) activeWindow);
796
o[2].value ().set ((int) event->xcrossing.state);
797
o[3].value ().set ((int) event->xcrossing.x_root);
798
o[4].value ().set ((int) event->xcrossing.y_root);
799
o[5].value ().set ((int) event->xcrossing.root);
801
o[6].setName ("time", CompOption::TypeInt);
802
o[6].value ().set ((int) event->xcrossing.time);
804
if (triggerEdgeEnter (edge, state, o))
810
if (event->xclient.message_type == Atoms::xdndEnter)
812
xdndWindow = event->xclient.window;
814
else if (event->xclient.message_type == Atoms::xdndLeave)
816
unsigned int edge = 0;
817
CompAction::State state;
823
w = screen->findWindow (event->xclient.window);
828
for (i = 0; i < SCREEN_EDGE_NUM; i++)
830
if (event->xclient.window == screenEdge[i].id)
841
state = CompAction::StateTermEdgeDnd;
843
o[0].value ().set ((int) event->xclient.window);
844
o[1].value ().set ((int) activeWindow);
845
o[2].value ().set ((int) 0); /* fixme */
846
o[3].value ().set ((int) 0); /* fixme */
847
o[4].value ().set ((int) 0); /* fixme */
848
o[5].value ().set ((int) root);
850
foreach (CompPlugin *p, CompPlugin::getPlugins ())
852
CompOption::Vector &options = p->vTable->getOptions ();
853
if (triggerEdgeLeaveBindings (options, state, edge, o))
858
else if (event->xclient.message_type == Atoms::xdndPosition)
860
unsigned int edge = 0;
861
CompAction::State state;
863
if (xdndWindow == event->xclient.window)
867
w = screen->findWindow (event->xclient.window);
872
for (i = 0; i < SCREEN_EDGE_NUM; i++)
874
if (xdndWindow == screenEdge[i].id)
885
state = CompAction::StateInitEdgeDnd;
887
o[0].value ().set ((int) event->xclient.window);
888
o[1].value ().set ((int) activeWindow);
889
o[2].value ().set ((int) 0); /* fixme */
890
o[3].value ().set ((int) event->xclient.data.l[2] >> 16);
891
o[4].value ().set ((int) event->xclient.data.l[2] & 0xffff);
892
o[5].value ().set ((int) root);
894
if (triggerEdgeEnter (edge, state, o))
902
if (event->type == xkbEvent)
904
XkbAnyEvent *xkbEvent = (XkbAnyEvent *) event;
906
if (xkbEvent->xkb_type == XkbStateNotify)
908
XkbStateNotifyEvent *stateEvent = (XkbStateNotifyEvent *) event;
910
o[0].value ().set ((int) activeWindow);
911
o[1].value ().set ((int) activeWindow);
912
o[2].value ().set ((int) stateEvent->mods);
914
o[3].setName ("time", CompOption::TypeInt);
915
o[3].value ().set ((int) xkbEvent->time);
919
foreach (CompPlugin *p, CompPlugin::getPlugins ())
921
CompOption::Vector &options = p->vTable->getOptions ();
922
if (triggerStateNotifyBindings (options, stateEvent, o))
926
else if (xkbEvent->xkb_type == XkbBellNotify)
928
o[0].value ().set ((int) activeWindow);
929
o[1].value ().set ((int) activeWindow);
931
o[2].setName ("time", CompOption::TypeInt);
932
o[2].value ().set ((int) xkbEvent->time);
938
foreach (CompPlugin *p, CompPlugin::getPlugins ())
940
CompOption::Vector &options = p->vTable->getOptions ();
941
if (triggerBellNotifyBindings (options, o))
953
PrivateScreen::setDefaultWindowAttributes (XWindowAttributes *wa)
959
wa->border_width = 0;
963
wa->c_class = InputOnly;
964
wa->bit_gravity = NorthWestGravity;
965
wa->win_gravity = NorthWestGravity;
966
wa->backing_store = NotUseful;
967
wa->backing_planes = 0;
968
wa->backing_pixel = 0;
969
wa->save_under = false;
971
wa->map_installed = false;
972
wa->map_state = IsUnviewable;
973
wa->all_event_masks = 0;
974
wa->your_event_mask = 0;
975
wa->do_not_propagate_mask = 0;
976
wa->override_redirect = true;
981
CompScreen::handleCompizEvent (const char *plugin,
983
CompOption::Vector &options)
984
WRAPABLE_HND_FUNC (7, handleCompizEvent, plugin, event, options)
987
CompScreen::handleEvent (XEvent *event)
989
WRAPABLE_HND_FUNC (6, handleEvent, event)
991
CompWindow *w = NULL;
992
XWindowAttributes wa;
994
switch (event->type) {
996
if (event->xbutton.root == priv->root)
997
priv->setCurrentOutput (
998
outputDeviceForPoint (event->xbutton.x_root,
999
event->xbutton.y_root));
1002
if (event->xmotion.root == priv->root)
1003
priv->setCurrentOutput (
1004
outputDeviceForPoint (event->xmotion.x_root,
1005
event->xmotion.y_root));
1008
w = findWindow (priv->activeWindow);
1010
priv->setCurrentOutput (w->outputDevice ());
1016
if (priv->handleActionEvent (event))
1018
if (priv->grabs.empty ())
1019
XAllowEvents (priv->dpy, AsyncPointer, event->xbutton.time);
1024
switch (event->type) {
1025
case SelectionRequest:
1026
priv->handleSelectionRequest (event);
1028
case SelectionClear:
1029
priv->handleSelectionClear (event);
1031
case ConfigureNotify:
1032
w = findWindow (event->xconfigure.window);
1033
if (w && !w->frame ())
1035
w->priv->configure (&event->xconfigure);
1039
w = findTopLevelWindow (event->xconfigure.window);
1041
if (w && w->frame () == event->xconfigure.window)
1043
w->priv->configureFrame (&event->xconfigure);
1047
if (event->xconfigure.window == priv->root)
1048
priv->configure (&event->xconfigure);
1054
bool failure = false;
1056
/* Failure means that window has been destroyed. We still have to add
1057
* the window to the window list as we might get configure requests
1058
* which require us to stack other windows relative to it. Setting
1059
* some default values if this is the case. */
1060
if ((failure = !XGetWindowAttributes (priv->dpy, event->xcreatewindow.window, &wa)))
1061
priv->setDefaultWindowAttributes (&wa);
1063
w = findTopLevelWindow (event->xcreatewindow.window, true);
1065
if ((event->xcreatewindow.parent == wa.root || failure) &&
1066
(!w || w->frame () != event->xcreatewindow.window))
1068
/* Track the window if it was created on this
1069
* screen, otherwise we still need to register
1070
* for FocusChangeMask. Also, we don't want to
1071
* manage it straight away - in reality we want
1072
* that to wait until the map request */
1073
if (failure || (wa.root == priv->root))
1075
/* Our SubstructureRedirectMask doesn't work on OverrideRedirect
1076
* windows so we need to track them directly here */
1077
if (!event->xcreatewindow.override_redirect)
1078
new CoreWindow (event->xcreatewindow.window, wa);
1082
new CoreWindow (event->xcreatewindow.window, wa);
1086
w = cw->manage (priv->getTopWindow ());
1092
XSelectInput (priv->dpy, event->xcreatewindow.window,
1098
w = findWindow (event->xdestroywindow.window);
1101
w->moveInputFocusToOtherWindow ();
1107
/* Some broken applications and toolkits (eg QT) will lie to
1108
* us about their override-redirect mask - not setting it on
1109
* the initial CreateNotify and then setting it later on
1110
* just after creation. Unfortunately, this means that QT
1111
* has successfully bypassed both of our window tracking
1112
* mechanisms (eg, not override-redirect at CreateNotify time
1113
* and then bypassing MapRequest because it *is* override-redirect
1114
* at XMapWindow time, so we need to catch this case and make
1115
* sure that windows are tracked here */
1117
foreach (CoreWindow *cw, priv->createdWindows)
1119
if (cw->priv->id == event->xmap.window)
1121
w = cw->manage (priv->getTopWindow ());
1127
/* Search in already-created windows for this window */
1129
w = findWindow (event->xmap.window);
1133
if (w->priv->pendingMaps)
1135
/* The only case where this happens
1136
* is where the window unmaps itself
1137
* but doesn't get destroyed so when
1138
* it re-maps we need to reparent it */
1140
if (!w->priv->frame)
1141
w->priv->reparent ();
1142
w->priv->managed = true;
1146
if (w->priv->height == 0)
1148
if (w->id () == priv->activeWindow)
1149
w->moveInputFocusTo ();
1157
w = findWindow (event->xunmap.window);
1160
/* Normal -> Iconic */
1161
if (w->pendingUnmaps ())
1163
priv->setWmState (IconicState, w->id ());
1164
w->priv->pendingUnmaps--;
1166
else /* X -> Withdrawn */
1168
/* Iconic -> Withdrawn */
1169
if (w->state () & CompWindowStateHiddenMask)
1171
w->priv->minimized = false;
1173
w->changeState (w->state () & ~CompWindowStateHiddenMask);
1175
priv->updateClientList ();
1178
w->windowNotify (CompWindowNotifyClose);
1180
if (!w->overrideRedirect ())
1181
priv->setWmState (WithdrawnState, w->id ());
1183
w->priv->placed = false;
1184
w->priv->managed = false;
1185
w->priv->unmanaging = true;
1189
w->priv->unreparent ();
1195
if (!w->shaded () && !w->priv->pendingMaps)
1196
w->moveInputFocusToOtherWindow ();
1199
case ReparentNotify:
1200
w = findWindow (event->xreparent.window);
1201
if (!w && event->xreparent.parent == priv->root)
1203
/* Failure means that window has been destroyed. We still have to add
1204
* the window to the window list as we might get configure requests
1205
* which require us to stack other windows relative to it. Setting
1206
* some default values if this is the case. */
1207
if (!XGetWindowAttributes (priv->dpy, event->xcreatewindow.window, &wa))
1208
priv->setDefaultWindowAttributes (&wa);
1210
CoreWindow *cw = new CoreWindow (event->xreparent.window, wa);
1214
cw->manage (priv->getTopWindow ());
1218
else if (w && !(event->xreparent.parent == w->priv->wrapper ||
1219
event->xreparent.parent == priv->root))
1221
/* This is the only case where a window is removed but not
1222
destroyed. We must remove our event mask and all passive
1224
XSelectInput (priv->dpy, w->id (), NoEventMask);
1225
XShapeSelectInput (priv->dpy, w->id (), NoEventMask);
1226
XUngrabButton (priv->dpy, AnyButton, AnyModifier, w->id ());
1228
w->moveInputFocusToOtherWindow ();
1233
case CirculateNotify:
1234
w = findWindow (event->xcirculate.window);
1236
w->priv->circulate (&event->xcirculate);
1239
if (event->xbutton.button == Button1 ||
1240
event->xbutton.button == Button2 ||
1241
event->xbutton.button == Button3)
1243
w = findTopLevelWindow (event->xbutton.window);
1246
if (priv->optionGetRaiseOnClick ())
1247
w->updateAttributes (CompStackingUpdateModeAboveFullscreen);
1249
if (w->id () != priv->activeWindow)
1250
if (!(w->type () & CompWindowTypeDockMask))
1252
w->moveInputFocusTo ();
1256
if (priv->grabs.empty ())
1257
XAllowEvents (priv->dpy, ReplayPointer, event->xbutton.time);
1260
case PropertyNotify:
1261
if (event->xproperty.atom == Atoms::winType)
1263
w = findWindow (event->xproperty.window);
1268
type = priv->getWindowType (w->id ());
1270
if (type != w->wmType ())
1272
if (w->isViewable ())
1274
if (w->type () == CompWindowTypeDesktopMask)
1275
priv->desktopWindowCount--;
1276
else if (type == CompWindowTypeDesktopMask)
1277
priv->desktopWindowCount++;
1280
w->wmType () = type;
1283
w->recalcActions ();
1285
if (type & (CompWindowTypeDockMask |
1286
CompWindowTypeDesktopMask))
1287
w->setDesktop (0xffffffff);
1289
priv->updateClientList ();
1291
matchPropertyChanged (w);
1295
else if (event->xproperty.atom == Atoms::winState)
1297
w = findWindow (event->xproperty.window);
1298
if (w && !w->managed ())
1302
state = priv->getWindowState (w->id ());
1303
state = CompWindow::constrainWindowState (state, w->actions ());
1305
/* EWMH suggests that we ignore changes
1306
to _NET_WM_STATE_HIDDEN */
1307
if (w->state () & CompWindowStateHiddenMask)
1308
state |= CompWindowStateHiddenMask;
1310
state &= ~CompWindowStateHiddenMask;
1312
w->changeState (state);
1315
else if (event->xproperty.atom == XA_WM_NORMAL_HINTS)
1317
w = findWindow (event->xproperty.window);
1320
w->priv->updateNormalHints ();
1321
w->recalcActions ();
1324
else if (event->xproperty.atom == XA_WM_HINTS)
1326
w = findWindow (event->xproperty.window);
1328
w->priv->updateWmHints ();
1330
else if (event->xproperty.atom == XA_WM_TRANSIENT_FOR)
1332
w = findWindow (event->xproperty.window);
1335
w->priv->updateTransientHint ();
1336
w->recalcActions ();
1339
else if (event->xproperty.atom == Atoms::wmClientLeader)
1341
w = findWindow (event->xproperty.window);
1343
w->priv->clientLeader = w->priv->getClientLeader ();
1345
else if (event->xproperty.atom == Atoms::wmIconGeometry)
1347
w = findWindow (event->xproperty.window);
1349
w->priv->updateIconGeometry ();
1351
else if (event->xproperty.atom == Atoms::wmStrut ||
1352
event->xproperty.atom == Atoms::wmStrutPartial)
1354
w = findWindow (event->xproperty.window);
1357
if (w->updateStruts ())
1361
else if (event->xproperty.atom == Atoms::mwmHints)
1363
w = findWindow (event->xproperty.window);
1365
w->priv->updateMwmHints ();
1367
else if (event->xproperty.atom == Atoms::wmProtocols)
1369
w = findWindow (event->xproperty.window);
1371
w->priv->protocols = priv->getProtocols (w->id ());
1373
else if (event->xproperty.atom == Atoms::wmIcon)
1375
w = findWindow (event->xproperty.window);
1377
w->priv->freeIcons ();
1379
else if (event->xproperty.atom == Atoms::startupId)
1381
w = findWindow (event->xproperty.window);
1383
w->priv->updateStartupId ();
1385
else if (event->xproperty.atom == XA_WM_CLASS)
1387
w = findWindow (event->xproperty.window);
1389
w->priv->updateClassHints ();
1395
if (event->xclient.message_type == Atoms::winActive)
1397
w = findWindow (event->xclient.window);
1400
/* use focus stealing prevention if request came
1401
from an application */
1402
if (event->xclient.data.l[0] != ClientTypeApplication ||
1403
w->priv->allowWindowFocus (0, event->xclient.data.l[1]))
1409
else if (event->xclient.message_type == Atoms::winState)
1411
w = findWindow (event->xclient.window);
1414
unsigned long wState, state;
1417
wState = w->state ();
1419
for (i = 1; i < 3; i++)
1421
state = priv->windowStateMask (event->xclient.data.l[i]);
1422
if (state & ~CompWindowStateHiddenMask)
1425
#define _NET_WM_STATE_REMOVE 0
1426
#define _NET_WM_STATE_ADD 1
1427
#define _NET_WM_STATE_TOGGLE 2
1429
switch (event->xclient.data.l[0]) {
1430
case _NET_WM_STATE_REMOVE:
1433
case _NET_WM_STATE_ADD:
1436
case _NET_WM_STATE_TOGGLE:
1443
wState = CompWindow::constrainWindowState (wState,
1445
if (w->id () == priv->activeWindow)
1446
wState &= ~CompWindowStateDemandsAttentionMask;
1448
if (wState != w->state ())
1450
CompStackingUpdateMode stackingUpdateMode;
1451
unsigned long dState = wState ^ w->state ();
1453
stackingUpdateMode = CompStackingUpdateModeNone;
1455
/* raise the window whenever its fullscreen state,
1456
above/below state or maximization state changed */
1457
if (dState & (CompWindowStateFullscreenMask |
1458
CompWindowStateAboveMask |
1459
CompWindowStateBelowMask |
1460
CompWindowStateMaximizedHorzMask |
1461
CompWindowStateMaximizedVertMask))
1462
stackingUpdateMode = CompStackingUpdateModeNormal;
1464
w->changeState (wState);
1466
w->updateAttributes (stackingUpdateMode);
1470
else if (event->xclient.message_type == Atoms::wmProtocols)
1472
if ((unsigned long) event->xclient.data.l[0] == Atoms::wmPing)
1474
w = findWindow (event->xclient.data.l[2]);
1476
w->priv->handlePing (priv->lastPing);
1479
else if (event->xclient.message_type == Atoms::closeWindow)
1481
w = findWindow (event->xclient.window);
1483
w->close (event->xclient.data.l[0]);
1485
else if (event->xclient.message_type == Atoms::desktopGeometry)
1487
if (event->xclient.window == priv->root)
1489
CompOption::Value value;
1491
value.set ((int) (event->xclient.data.l[0] /
1494
setOptionForPlugin ("core", "hsize", value);
1496
value.set ((int) (event->xclient.data.l[1] /
1499
setOptionForPlugin ("core", "vsize", value);
1502
else if (event->xclient.message_type == Atoms::moveResizeWindow)
1504
w = findWindow (event->xclient.window);
1507
unsigned int xwcm = 0;
1511
unsigned int source;
1513
gravity = (event->xclient.data.l[0] & 0xFF);
1514
value_mask = (event->xclient.data.l[0] & 0xF00) >> 8;
1515
source = (event->xclient.data.l[0] & 0xF000) >> 12;
1517
memset (&xwc, 0, sizeof (xwc));
1519
if (value_mask & CWX)
1522
xwc.x = event->xclient.data.l[1];
1525
if (value_mask & CWY)
1528
xwc.y = event->xclient.data.l[2];
1531
if (value_mask & CWWidth)
1534
xwc.width = event->xclient.data.l[3];
1537
if (value_mask & CWHeight)
1540
xwc.height = event->xclient.data.l[4];
1543
w->moveResize (&xwc, xwcm, gravity, source);
1546
else if (event->xclient.message_type == Atoms::restackWindow)
1548
w = findWindow (event->xclient.window);
1551
/* TODO: other stack modes than Above and Below */
1552
if (event->xclient.data.l[1])
1554
CompWindow *sibling;
1556
sibling = findWindow (event->xclient.data.l[1]);
1559
if (event->xclient.data.l[2] == Above)
1560
w->restackAbove (sibling);
1561
else if (event->xclient.data.l[2] == Below)
1562
w->restackBelow (sibling);
1567
if (event->xclient.data.l[2] == Above)
1569
else if (event->xclient.data.l[2] == Below)
1574
else if (event->xclient.message_type == Atoms::wmChangeState)
1576
w = findWindow (event->xclient.window);
1579
if (event->xclient.data.l[0] == IconicState)
1581
if (w->actions () & CompWindowActionMinimizeMask)
1584
else if (event->xclient.data.l[0] == NormalState)
1590
else if (event->xclient.message_type == Atoms::showingDesktop)
1592
if (event->xclient.window == priv->root ||
1593
event->xclient.window == None)
1595
if (event->xclient.data.l[0])
1596
enterShowDesktopMode ();
1598
leaveShowDesktopMode (NULL);
1601
else if (event->xclient.message_type == Atoms::numberOfDesktops)
1603
if (event->xclient.window == priv->root)
1605
CompOption::Value value;
1607
value.set ((int) event->xclient.data.l[0]);
1609
setOptionForPlugin ("core", "number_of_desktops", value);
1612
else if (event->xclient.message_type == Atoms::currentDesktop)
1614
if (event->xclient.window == priv->root)
1615
priv->setCurrentDesktop (event->xclient.data.l[0]);
1617
else if (event->xclient.message_type == Atoms::winDesktop)
1619
w = findWindow (event->xclient.window);
1621
w->setDesktop (event->xclient.data.l[0]);
1623
else if (event->xclient.message_type == Atoms::wmFullscreenMonitors)
1625
w = findWindow (event->xclient.window);
1628
CompFullscreenMonitorSet monitors;
1630
monitors.top = event->xclient.data.l[0];
1631
monitors.bottom = event->xclient.data.l[1];
1632
monitors.left = event->xclient.data.l[2];
1633
monitors.right = event->xclient.data.l[3];
1635
w->priv->setFullscreenMonitors (&monitors);
1640
modHandler->updateModifierMappings ();
1643
/* Create the CompWindow structure here */
1646
foreach (CoreWindow *cw, priv->createdWindows)
1648
if (cw->priv->id == event->xmaprequest.window)
1650
w = cw->manage (priv->getTopWindow ());
1657
w = screen->findWindow (event->xmaprequest.window);
1661
XWindowAttributes attr;
1662
bool doMapProcessing = true;
1664
/* We should check the override_redirect flag here, because the
1665
client might have changed it while being unmapped. */
1666
if (XGetWindowAttributes (priv->dpy, w->id (), &attr))
1667
w->priv->setOverrideRedirect (attr.override_redirect != 0);
1669
if (w->state () & CompWindowStateHiddenMask)
1670
if (!w->minimized () && !w->inShowDesktopMode ())
1671
doMapProcessing = false;
1673
if (doMapProcessing)
1674
w->priv->processMap ();
1676
w->priv->managed = true;
1678
setWindowProp (w->id (), Atoms::winDesktop, w->desktop ());
1682
XMapWindow (priv->dpy, event->xmaprequest.window);
1685
case ConfigureRequest:
1686
w = findWindow (event->xconfigurerequest.window);
1687
if (w && w->managed ())
1691
memset (&xwc, 0, sizeof (xwc));
1693
xwc.x = event->xconfigurerequest.x;
1694
xwc.y = event->xconfigurerequest.y;
1695
xwc.width = event->xconfigurerequest.width;
1696
xwc.height = event->xconfigurerequest.height;
1697
xwc.border_width = event->xconfigurerequest.border_width;
1699
w->moveResize (&xwc, event->xconfigurerequest.value_mask,
1700
0, ClientTypeUnknown);
1702
if (event->xconfigurerequest.value_mask & CWStackMode)
1704
Window above = None;
1705
CompWindow *sibling = NULL;
1707
if (event->xconfigurerequest.value_mask & CWSibling)
1709
above = event->xconfigurerequest.above;
1710
sibling = findTopLevelWindow (above);
1713
switch (event->xconfigurerequest.detail) {
1715
if (w->priv->allowWindowFocus (NO_FOCUS_MASK, 0))
1720
w->restackAbove (sibling);
1730
w->restackBelow (sibling);
1736
/* no handling of the TopIf, BottomIf, Opposite cases -
1737
there will hardly be any client using that */
1747
xwcm = event->xconfigurerequest.value_mask &
1748
(CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
1750
xwc.x = event->xconfigurerequest.x;
1751
xwc.y = event->xconfigurerequest.y;
1752
xwc.width = event->xconfigurerequest.width;
1753
xwc.height = event->xconfigurerequest.height;
1754
xwc.border_width = event->xconfigurerequest.border_width;
1757
w->configureXWindow (xwcm, &xwc);
1759
XConfigureWindow (priv->dpy, event->xconfigurerequest.window,
1763
case CirculateRequest:
1766
XGetWindowAttributes (priv->dpy, event->xfocus.window, &wa);
1768
if (wa.root == priv->root)
1770
if (event->xfocus.mode != NotifyGrab)
1772
w = findTopLevelWindow (event->xfocus.window);
1773
if (w && w->managed ())
1775
unsigned int state = w->state ();
1777
if (w->id () != priv->activeWindow)
1779
CompWindow *active = screen->findWindow (priv->activeWindow);
1780
w->windowNotify (CompWindowNotifyFocusChange);
1782
priv->activeWindow = w->id ();
1783
w->priv->activeNum = priv->activeNum++;
1786
active->priv->updatePassiveButtonGrabs ();
1788
w->priv->updatePassiveButtonGrabs ();
1790
priv->addToCurrentActiveWindowHistory (w->id ());
1792
XChangeProperty (priv->dpy , priv->root,
1794
XA_WINDOW, 32, PropModeReplace,
1795
(unsigned char *) &priv->activeWindow, 1);
1798
state &= ~CompWindowStateDemandsAttentionMask;
1799
w->changeState (state);
1801
if (priv->nextActiveWindow == event->xfocus.window)
1802
priv->nextActiveWindow = None;
1806
priv->grabbed = true;
1812
w = screen->findWindow (priv->activeWindow);
1814
priv->nextActiveWindow = None;
1815
priv->activeWindow = None;
1818
w->priv->updatePassiveButtonGrabs ();
1823
if (event->xfocus.mode == NotifyUngrab)
1824
priv->grabbed = false;
1827
if (event->xcrossing.root == priv->root)
1828
w = findTopLevelWindow (event->xcrossing.window);
1832
if (w && w->id () != priv->below)
1834
priv->below = w->id ();
1836
if (!priv->optionGetClickToFocus () &&
1837
priv->grabs.empty () &&
1838
event->xcrossing.mode != NotifyGrab &&
1839
event->xcrossing.detail != NotifyInferior)
1844
raise = priv->optionGetAutoraise ();
1845
delay = priv->optionGetAutoraiseDelay ();
1847
if (priv->autoRaiseTimer.active () &&
1848
priv->autoRaiseWindow != w->id ())
1850
priv->autoRaiseTimer.stop ();
1853
if (w->type () & ~(CompWindowTypeDockMask |
1854
CompWindowTypeDesktopMask))
1856
w->moveInputFocusTo ();
1862
priv->autoRaiseWindow = w->id ();
1863
priv->autoRaiseTimer.start (
1864
boost::bind (autoRaiseTimeout, this),
1865
delay, (unsigned int) ((float) delay * 1.2));
1869
CompStackingUpdateMode mode =
1870
CompStackingUpdateModeNormal;
1872
w->updateAttributes (mode);
1880
if (event->xcrossing.detail != NotifyInferior)
1882
if (event->xcrossing.window == priv->below)
1887
if (priv->shapeExtension &&
1888
event->type == priv->shapeEvent + ShapeNotify)
1890
w = findWindow (((XShapeEvent *) event)->window);
1894
w->priv->updateRegion ();
1897
else if (event->type == priv->syncEvent + XSyncAlarmNotify)
1899
XSyncAlarmNotifyEvent *sa;
1901
sa = (XSyncAlarmNotifyEvent *) event;
1904
foreach (w, priv->windows)
1906
if (w->priv->syncAlarm == sa->alarm)
1908
w->priv->handleSyncAlarm ();