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/atoms.h>
40
#include "privatescreen.h"
41
#include "privatewindow.h"
42
#include "privatestackdebugger.h"
45
PrivateWindow::handleSyncAlarm ()
49
priv->syncWait = false;
51
if (window->resize (priv->syncGeometry))
53
window->windowNotify (CompWindowNotifySyncAlarm);
57
/* resizeWindow failing means that there is another pending
58
resize and we must send a new sync request to the client */
59
window->sendSyncRequest ();
68
autoRaiseTimeout (CompScreen *screen)
70
CompWindow *w = screen->findWindow (screen->activeWindow ());
72
if (screen->autoRaiseWindow () == screen->activeWindow () ||
73
(w && (screen->autoRaiseWindow () == w->transientFor ())))
75
w = screen->findWindow (screen->autoRaiseWindow ());
77
w->updateAttributes (CompStackingUpdateModeNormal);
83
#define REAL_MOD_MASK (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | \
84
Mod3Mask | Mod4Mask | Mod5Mask | CompNoMask)
87
isCallBackBinding (CompOption &option,
88
CompAction::BindingType type,
89
CompAction::State state)
91
if (!option.isAction ())
94
if (!(option.value ().action ().type () & type))
97
if (!(option.value ().action ().state () & state))
104
isInitiateBinding (CompOption &option,
105
CompAction::BindingType type,
106
CompAction::State state,
109
if (!isCallBackBinding (option, type, state))
112
if (option.value ().action ().initiate ().empty ())
115
*action = &option.value ().action ();
121
isTerminateBinding (CompOption &option,
122
CompAction::BindingType type,
123
CompAction::State state,
126
if (!isCallBackBinding (option, type, state))
129
if (option.value ().action ().terminate ().empty ())
132
*action = &option.value ().action ();
138
PrivateScreen::triggerButtonPressBindings (CompOption::Vector &options,
140
CompOption::Vector &arguments)
142
CompAction::State state = CompAction::StateInitButton;
144
unsigned int ignored = modHandler->ignoredModMask ();
145
unsigned int modMask = REAL_MOD_MASK & ~ignored;
146
unsigned int bindMods;
147
unsigned int edge = 0;
153
if (event->root != root)
156
if (event->window != edgeWindow)
158
if (grabs.empty () || event->window != root)
162
for (i = 0; i < SCREEN_EDGE_NUM; i++)
164
if (edgeWindow == screenEdge[i].id)
167
arguments[1].value ().set ((int) activeWindow);
173
foreach (CompOption &option, options)
175
if (isInitiateBinding (option, CompAction::BindingTypeButton, state,
178
if (action->button ().button () == (int) event->button)
180
bindMods = modHandler->virtualToRealModMask (
181
action->button ().modifiers ());
183
if ((bindMods & modMask) == (event->state & modMask))
185
if (action->initiate () (action, state, arguments))
193
if (isInitiateBinding (option, CompAction::BindingTypeEdgeButton,
194
state | CompAction::StateInitEdge, &action))
196
if ((action->button ().button () == (int) event->button) &&
197
(action->edgeMask () & edge))
199
bindMods = modHandler->virtualToRealModMask (
200
action->button ().modifiers ());
202
if ((bindMods & modMask) == (event->state & modMask))
203
if (action->initiate () (action, state |
204
CompAction::StateInitEdge,
216
PrivateScreen::triggerButtonReleaseBindings (CompOption::Vector &options,
218
CompOption::Vector &arguments)
220
CompAction::State state = CompAction::StateTermButton;
221
CompAction::BindingType type = CompAction::BindingTypeButton |
222
CompAction::BindingTypeEdgeButton;
225
foreach (CompOption &option, options)
227
if (isTerminateBinding (option, type, state, &action))
229
if (action->button ().button () == (int) event->button)
231
if (action->terminate () (action, state, arguments))
241
PrivateScreen::triggerKeyPressBindings (CompOption::Vector &options,
243
CompOption::Vector &arguments)
245
CompAction::State state = 0;
247
unsigned int modMask = REAL_MOD_MASK & ~modHandler->ignoredModMask ();
248
unsigned int bindMods;
250
if (event->keycode == escapeKeyCode)
251
state = CompAction::StateCancel;
252
else if (event->keycode == returnKeyCode)
253
state = CompAction::StateCommit;
257
foreach (CompOption &o, options)
261
if (!o.value ().action ().terminate ().empty ())
262
o.value ().action ().terminate () (&o.value ().action (),
267
if (state == CompAction::StateCancel)
271
state = CompAction::StateInitKey;
272
foreach (CompOption &option, options)
274
if (isInitiateBinding (option, CompAction::BindingTypeKey,
277
bindMods = modHandler->virtualToRealModMask (
278
action->key ().modifiers ());
280
if (action->key ().keycode () == (int) event->keycode)
282
if ((bindMods & modMask) == (event->state & modMask))
283
if (action->initiate () (action, state, arguments))
286
else if (!xkbEvent && action->key ().keycode () == 0)
288
if (bindMods == (event->state & modMask))
289
if (action->initiate () (action, state, arguments))
299
PrivateScreen::triggerKeyReleaseBindings (CompOption::Vector &options,
301
CompOption::Vector &arguments)
303
CompAction::State state = CompAction::StateTermKey;
305
unsigned int ignored = modHandler->ignoredModMask ();
306
unsigned int modMask = REAL_MOD_MASK & ~ignored;
307
unsigned int bindMods;
310
mods = modHandler->keycodeToModifiers (event->keycode);
311
if (!xkbEvent && !mods)
314
foreach (CompOption &option, options)
316
if (isTerminateBinding (option, CompAction::BindingTypeKey,
319
bindMods = modHandler->virtualToRealModMask (action->key ().modifiers ());
321
if ((bindMods & modMask) == 0)
323
if ((unsigned int) action->key ().keycode () ==
324
(unsigned int) event->keycode)
326
if (action->terminate () (action, state, arguments))
330
else if (!xkbEvent && ((mods & modMask & bindMods) != bindMods))
332
if (action->terminate () (action, state, arguments))
342
PrivateScreen::triggerStateNotifyBindings (CompOption::Vector &options,
343
XkbStateNotifyEvent *event,
344
CompOption::Vector &arguments)
346
CompAction::State state;
348
unsigned int ignored = modHandler->ignoredModMask ();
349
unsigned int modMask = REAL_MOD_MASK & ~ignored;
350
unsigned int bindMods;
352
if (event->event_type == KeyPress)
354
state = CompAction::StateInitKey;
356
foreach (CompOption &option, options)
358
if (isInitiateBinding (option, CompAction::BindingTypeKey,
361
if (action->key ().keycode () == 0)
364
modHandler->virtualToRealModMask (action->key ().modifiers ());
366
if ((event->mods & modMask & bindMods) == bindMods)
368
if (action->initiate () (action, state, arguments))
377
state = CompAction::StateTermKey;
379
foreach (CompOption &option, options)
381
if (isTerminateBinding (option, CompAction::BindingTypeKey,
384
bindMods = modHandler->virtualToRealModMask (action->key ().modifiers ());
386
if ((event->mods & modMask & bindMods) != bindMods)
388
if (action->terminate () (action, state, arguments))
399
isBellAction (CompOption &option,
400
CompAction::State state,
403
if (option.type () != CompOption::TypeAction &&
404
option.type () != CompOption::TypeBell)
407
if (!option.value ().action ().bell ())
410
if (!(option.value ().action ().state () & state))
413
if (option.value ().action ().initiate ().empty ())
416
*action = &option.value ().action ();
422
triggerBellNotifyBindings (CompOption::Vector &options,
423
CompOption::Vector &arguments)
425
CompAction::State state = CompAction::StateInitBell;
428
foreach (CompOption &option, options)
430
if (isBellAction (option, state, &action))
432
if (action->initiate () (action, state, arguments))
441
isEdgeAction (CompOption &option,
442
CompAction::State state,
445
if (option.type () != CompOption::TypeAction &&
446
option.type () != CompOption::TypeButton &&
447
option.type () != CompOption::TypeEdge)
450
if (!(option.value ().action ().edgeMask () & edge))
453
if (!(option.value ().action ().state () & state))
460
isEdgeEnterAction (CompOption &option,
461
CompAction::State state,
462
CompAction::State delayState,
466
if (!isEdgeAction (option, state, edge))
469
if (option.value ().action ().type () & CompAction::BindingTypeEdgeButton)
472
if (option.value ().action ().initiate ().empty ())
477
if ((option.value ().action ().state () &
478
CompAction::StateNoEdgeDelay) !=
479
(delayState & CompAction::StateNoEdgeDelay))
481
/* ignore edge actions which shouldn't be delayed when invoking
482
undelayed edges (or vice versa) */
488
*action = &option.value ().action ();
494
isEdgeLeaveAction (CompOption &option,
495
CompAction::State state,
499
if (!isEdgeAction (option, state, edge))
502
if (option.value ().action ().terminate ().empty ())
505
*action = &option.value ().action ();
511
triggerEdgeEnterBindings (CompOption::Vector &options,
512
CompAction::State state,
513
CompAction::State delayState,
515
CompOption::Vector &arguments)
519
foreach (CompOption &option, options)
521
if (isEdgeEnterAction (option, state, delayState, edge, &action))
523
if (action->initiate () (action, state, arguments))
532
triggerEdgeLeaveBindings (CompOption::Vector &options,
533
CompAction::State state,
535
CompOption::Vector &arguments)
539
foreach (CompOption &option, options)
541
if (isEdgeLeaveAction (option, state, edge, &action))
543
if (action->terminate () (action, state, arguments))
552
triggerAllEdgeEnterBindings (CompAction::State state,
553
CompAction::State delayState,
555
CompOption::Vector &arguments)
557
foreach (CompPlugin *p, CompPlugin::getPlugins ())
559
CompOption::Vector &options = p->vTable->getOptions ();
560
if (triggerEdgeEnterBindings (options, state, delayState, edge,
570
delayedEdgeTimeout (CompDelayedEdgeSettings *settings)
572
triggerAllEdgeEnterBindings (settings->state,
573
~CompAction::StateNoEdgeDelay,
581
PrivateScreen::triggerEdgeEnter (unsigned int edge,
582
CompAction::State state,
583
CompOption::Vector &arguments)
587
delay = optionGetEdgeDelay ();
591
CompAction::State delayState;
592
edgeDelaySettings.edge = edge;
593
edgeDelaySettings.state = state;
594
edgeDelaySettings.options = arguments;
596
edgeDelayTimer.start (
597
boost::bind (delayedEdgeTimeout, &edgeDelaySettings),
598
delay, (unsigned int) ((float) delay * 1.2));
600
delayState = CompAction::StateNoEdgeDelay;
601
if (triggerAllEdgeEnterBindings (state, delayState, edge, arguments))
606
if (triggerAllEdgeEnterBindings (state, 0, edge, arguments))
614
PrivateScreen::handleActionEvent (XEvent *event)
616
static CompOption::Vector o (8);
619
o[0].setName ("event_window", CompOption::TypeInt);
620
o[1].setName ("window", CompOption::TypeInt);
621
o[2].setName ("modifiers", CompOption::TypeInt);
622
o[3].setName ("x", CompOption::TypeInt);
623
o[4].setName ("y", CompOption::TypeInt);
624
o[5].setName ("root", CompOption::TypeInt);
628
switch (event->type) {
630
/* We need to determine if we clicked on a parent frame
631
* window, if so, pass the appropriate child window as
632
* "window" and the frame as "event_window"
635
xid = event->xbutton.window;
637
foreach (CompWindow *w, screen->windows ())
639
if (w->priv->frame == xid)
643
o[0].value ().set ((int) event->xbutton.window);
644
o[1].value ().set ((int) xid);
645
o[2].value ().set ((int) event->xbutton.state);
646
o[3].value ().set ((int) event->xbutton.x_root);
647
o[4].value ().set ((int) event->xbutton.y_root);
648
o[5].value ().set ((int) event->xbutton.root);
650
o[6].setName ("button", CompOption::TypeInt);
651
o[7].setName ("time", CompOption::TypeInt);
653
o[6].value ().set ((int) event->xbutton.button);
654
o[7].value ().set ((int) event->xbutton.time);
656
foreach (CompPlugin *p, CompPlugin::getPlugins ())
658
CompOption::Vector &options = p->vTable->getOptions ();
659
if (triggerButtonPressBindings (options, &event->xbutton, o))
664
o[0].value ().set ((int) event->xbutton.window);
665
o[1].value ().set ((int) event->xbutton.window);
666
o[2].value ().set ((int) event->xbutton.state);
667
o[3].value ().set ((int) event->xbutton.x_root);
668
o[4].value ().set ((int) event->xbutton.y_root);
669
o[5].value ().set ((int) event->xbutton.root);
671
o[6].setName ("button", CompOption::TypeInt);
672
o[7].setName ("time", CompOption::TypeInt);
674
o[6].value ().set ((int) event->xbutton.button);
675
o[7].value ().set ((int) event->xbutton.time);
677
foreach (CompPlugin *p, CompPlugin::getPlugins ())
679
CompOption::Vector &options = p->vTable->getOptions ();
680
if (triggerButtonReleaseBindings (options, &event->xbutton, o))
685
o[0].value ().set ((int) event->xkey.window);
686
o[1].value ().set ((int) activeWindow);
687
o[2].value ().set ((int) event->xkey.state);
688
o[3].value ().set ((int) event->xkey.x_root);
689
o[4].value ().set ((int) event->xkey.y_root);
690
o[5].value ().set ((int) event->xkey.root);
692
o[6].setName ("keycode", CompOption::TypeInt);
693
o[7].setName ("time", CompOption::TypeInt);
695
o[6].value ().set ((int) event->xkey.keycode);
696
o[7].value ().set ((int) event->xkey.time);
698
foreach (CompPlugin *p, CompPlugin::getPlugins ())
700
CompOption::Vector &options = p->vTable->getOptions ();
701
if (triggerKeyPressBindings (options, &event->xkey, o))
706
o[0].value ().set ((int) event->xkey.window);
707
o[1].value ().set ((int) activeWindow);
708
o[2].value ().set ((int) event->xkey.state);
709
o[3].value ().set ((int) event->xkey.x_root);
710
o[4].value ().set ((int) event->xkey.y_root);
711
o[5].value ().set ((int) event->xkey.root);
713
o[6].setName ("keycode", CompOption::TypeInt);
714
o[7].setName ("time", CompOption::TypeInt);
716
o[6].value ().set ((int) event->xkey.keycode);
717
o[7].value ().set ((int) event->xkey.time);
719
foreach (CompPlugin *p, CompPlugin::getPlugins ())
721
CompOption::Vector &options = p->vTable->getOptions ();
722
if (triggerKeyReleaseBindings (options, &event->xkey, o))
727
if (event->xcrossing.mode != NotifyGrab &&
728
event->xcrossing.mode != NotifyUngrab &&
729
event->xcrossing.detail != NotifyInferior)
731
unsigned int edge, i;
732
CompAction::State state;
734
if (event->xcrossing.root != root)
737
if (edgeDelayTimer.active ())
738
edgeDelayTimer.stop ();
740
if (edgeWindow && edgeWindow != event->xcrossing.window)
742
state = CompAction::StateTermEdge;
745
for (i = 0; i < SCREEN_EDGE_NUM; i++)
747
if (edgeWindow == screenEdge[i].id)
756
o[0].value ().set ((int) event->xcrossing.window);
757
o[1].value ().set ((int) activeWindow);
758
o[2].value ().set ((int) event->xcrossing.state);
759
o[3].value ().set ((int) event->xcrossing.x_root);
760
o[4].value ().set ((int) event->xcrossing.y_root);
761
o[5].value ().set ((int) event->xcrossing.root);
763
o[6].setName ("time", CompOption::TypeInt);
764
o[6].value ().set ((int) event->xcrossing.time);
766
foreach (CompPlugin *p, CompPlugin::getPlugins ())
768
CompOption::Vector &options = p->vTable->getOptions ();
769
if (triggerEdgeLeaveBindings (options, state, edge, o))
776
for (i = 0; i < SCREEN_EDGE_NUM; i++)
778
if (event->xcrossing.window == screenEdge[i].id)
787
state = CompAction::StateInitEdge;
789
edgeWindow = event->xcrossing.window;
791
o[0].value ().set ((int) event->xcrossing.window);
792
o[1].value ().set ((int) activeWindow);
793
o[2].value ().set ((int) event->xcrossing.state);
794
o[3].value ().set ((int) event->xcrossing.x_root);
795
o[4].value ().set ((int) event->xcrossing.y_root);
796
o[5].value ().set ((int) event->xcrossing.root);
798
o[6].setName ("time", CompOption::TypeInt);
799
o[6].value ().set ((int) event->xcrossing.time);
801
if (triggerEdgeEnter (edge, state, o))
807
if (event->xclient.message_type == Atoms::xdndEnter)
809
xdndWindow = event->xclient.window;
811
else if (event->xclient.message_type == Atoms::xdndLeave)
813
unsigned int edge = 0;
814
CompAction::State state;
820
w = screen->findWindow (event->xclient.window);
825
for (i = 0; i < SCREEN_EDGE_NUM; i++)
827
if (event->xclient.window == screenEdge[i].id)
838
state = CompAction::StateTermEdgeDnd;
840
o[0].value ().set ((int) event->xclient.window);
841
o[1].value ().set ((int) activeWindow);
842
o[2].value ().set ((int) 0); /* fixme */
843
o[3].value ().set ((int) 0); /* fixme */
844
o[4].value ().set ((int) 0); /* fixme */
845
o[5].value ().set ((int) root);
847
foreach (CompPlugin *p, CompPlugin::getPlugins ())
849
CompOption::Vector &options = p->vTable->getOptions ();
850
if (triggerEdgeLeaveBindings (options, state, edge, o))
855
else if (event->xclient.message_type == Atoms::xdndPosition)
857
unsigned int edge = 0;
858
CompAction::State state;
860
if (xdndWindow == event->xclient.window)
864
w = screen->findWindow (event->xclient.window);
869
for (i = 0; i < SCREEN_EDGE_NUM; i++)
871
if (xdndWindow == screenEdge[i].id)
882
state = CompAction::StateInitEdgeDnd;
884
o[0].value ().set ((int) event->xclient.window);
885
o[1].value ().set ((int) activeWindow);
886
o[2].value ().set ((int) 0); /* fixme */
887
o[3].value ().set ((int) event->xclient.data.l[2] >> 16);
888
o[4].value ().set ((int) event->xclient.data.l[2] & 0xffff);
889
o[5].value ().set ((int) root);
891
if (triggerEdgeEnter (edge, state, o))
899
if (event->type == xkbEvent)
901
XkbAnyEvent *xkbEvent = (XkbAnyEvent *) event;
903
if (xkbEvent->xkb_type == XkbStateNotify)
905
XkbStateNotifyEvent *stateEvent = (XkbStateNotifyEvent *) event;
907
o[0].value ().set ((int) activeWindow);
908
o[1].value ().set ((int) activeWindow);
909
o[2].value ().set ((int) stateEvent->mods);
911
o[3].setName ("time", CompOption::TypeInt);
912
o[3].value ().set ((int) xkbEvent->time);
916
foreach (CompPlugin *p, CompPlugin::getPlugins ())
918
CompOption::Vector &options = p->vTable->getOptions ();
919
if (triggerStateNotifyBindings (options, stateEvent, o))
923
else if (xkbEvent->xkb_type == XkbBellNotify)
925
o[0].value ().set ((int) activeWindow);
926
o[1].value ().set ((int) activeWindow);
928
o[2].setName ("time", CompOption::TypeInt);
929
o[2].value ().set ((int) xkbEvent->time);
935
foreach (CompPlugin *p, CompPlugin::getPlugins ())
937
CompOption::Vector &options = p->vTable->getOptions ();
938
if (triggerBellNotifyBindings (options, o))
950
PrivateScreen::setDefaultWindowAttributes (XWindowAttributes *wa)
956
wa->border_width = 0;
960
wa->c_class = InputOnly;
961
wa->bit_gravity = NorthWestGravity;
962
wa->win_gravity = NorthWestGravity;
963
wa->backing_store = NotUseful;
964
wa->backing_planes = 0;
965
wa->backing_pixel = 0;
966
wa->save_under = false;
968
wa->map_installed = false;
969
wa->map_state = IsUnviewable;
970
wa->all_event_masks = 0;
971
wa->your_event_mask = 0;
972
wa->do_not_propagate_mask = 0;
973
wa->override_redirect = true;
974
wa->screen = ScreenOfDisplay (dpy, screenNum);
978
CompScreen::handleCompizEvent (const char *plugin,
980
CompOption::Vector &options)
982
WRAPABLE_HND_FUNCTN (handleCompizEvent, plugin, event, options);
983
_handleCompizEvent (plugin, event, options);
987
CompScreenImpl::_handleCompizEvent (const char *plugin,
989
CompOption::Vector &options)
994
CompScreen::handleEvent (XEvent *event)
996
WRAPABLE_HND_FUNCTN (handleEvent, event)
997
_handleEvent (event);
1001
CompScreenImpl::_handleEvent (XEvent *event)
1003
CompWindow *w = NULL;
1004
XWindowAttributes wa;
1005
bool actionEventHandled = false;
1007
switch (event->type) {
1009
if (event->xbutton.root == priv->root)
1010
priv->setCurrentOutput (
1011
outputDeviceForPoint (event->xbutton.x_root,
1012
event->xbutton.y_root));
1015
if (event->xmotion.root == priv->root)
1016
priv->setCurrentOutput (
1017
outputDeviceForPoint (event->xmotion.x_root,
1018
event->xmotion.y_root));
1021
w = findWindow (priv->activeWindow);
1023
priv->setCurrentOutput (w->outputDevice ());
1029
if (priv->handleActionEvent (event))
1031
if (priv->grabs.empty ())
1032
XAllowEvents (priv->dpy, AsyncPointer, event->xbutton.time);
1034
actionEventHandled = true;
1037
if (priv->grabs.empty ())
1039
switch (event->type)
1042
XUngrabKeyboard (priv->dpy, event->xkey.time);
1049
if (actionEventHandled)
1052
switch (event->type) {
1053
case SelectionRequest:
1054
priv->handleSelectionRequest (event);
1056
case SelectionClear:
1057
priv->handleSelectionClear (event);
1059
case ConfigureNotify:
1060
w = findWindow (event->xconfigure.window);
1062
if (w && !w->priv->frame)
1064
w->priv->configure (&event->xconfigure);
1068
w = findTopLevelWindow (event->xconfigure.window);
1070
if (w && w->priv->frame == event->xconfigure.window)
1071
w->priv->configureFrame (&event->xconfigure);
1074
if (event->xconfigure.window == priv->root)
1075
priv->configure (&event->xconfigure);
1083
/* Failure means that window has been destroyed. We still have to add
1084
* the window to the window list as we might get configure requests
1085
* which require us to stack other windows relative to it. Setting
1086
* some default values if this is the case. */
1087
if (!XGetWindowAttributes (priv->dpy, event->xcreatewindow.window, &wa))
1088
priv->setDefaultWindowAttributes (&wa);
1090
foreach (CompWindow *w, screen->windows ())
1092
if (w->priv->serverFrame == event->xcreatewindow.window)
1094
w->priv->frame = event->xcreatewindow.window;
1095
w->priv->updatePassiveButtonGrabs ();
1100
foreach (CompWindow *w, priv->destroyedWindows)
1102
if (w->priv->serverId == event->xcreatewindow.window)
1104
/* Previously destroyed window
1105
* plugins were keeping around
1106
* in order to avoid an xid conflict,
1107
* destroy it right away and manage
1110
StackDebugger *dbg = StackDebugger::Default ();
1112
while (w->priv->destroyRefCnt)
1116
dbg->removeDestroyedFrame (event->xcreatewindow.window);
1121
if (wa.root != event->xcreatewindow.parent)
1126
/* Track the window if it was created on this
1127
* screen, otherwise we still need to register
1128
* for FocusChangeMask. Also, we don't want to
1129
* manage it straight away - in reality we want
1130
* that to wait until the map request */
1131
if ((wa.root == priv->root))
1133
CoreWindow *cw = new CoreWindow (event->xcreatewindow.window);
1134
cw->manage (priv->getTopWindow (), wa);
1136
removeFromCreatedWindows (cw);
1140
XSelectInput (priv->dpy, event->xcreatewindow.window,
1144
compLogMessage ("core", CompLogLevelDebug, "refusing to manage window 0x%x", (unsigned int) event->xcreatewindow.window);
1149
w = findWindow (event->xdestroywindow.window);
1151
/* It is possible that some plugin might call
1152
* w->destroy () before the window actually receives
1153
* its first DestroyNotify event which would mean
1154
* that it is already in the list of destroyed
1155
* windows, so check that list too */
1159
foreach (CompWindow *dw, priv->destroyedWindows)
1161
if (dw->priv->serverId == event->xdestroywindow.window)
1171
w->moveInputFocusToOtherWindow ();
1177
/* Search in already-created windows for this window */
1179
w = findWindow (event->xmap.window);
1183
if (w->priv->pendingMaps)
1185
/* The only case where this happens
1186
* is where the window unmaps itself
1187
* but doesn't get destroyed so when
1188
* it re-maps we need to reparent it */
1190
if (!w->priv->serverFrame)
1191
w->priv->reparent ();
1193
w->priv->managed = true;
1197
if (w->priv->height == 0)
1199
if (w->id () == priv->activeWindow)
1200
w->moveInputFocusTo ();
1208
w = findWindow (event->xunmap.window);
1211
/* Normal -> Iconic */
1212
if (w->pendingUnmaps ())
1214
priv->setWmState (IconicState, w->id ());
1215
w->priv->pendingUnmaps--;
1217
else /* X -> Withdrawn */
1219
/* Iconic -> Withdrawn:
1221
* The window is already unmapped so we need to check the
1222
* synthetic UnmapNotify that comes and withdraw the window here */
1223
if (w->state () & CompWindowStateHiddenMask)
1225
w->priv->minimized = false;
1226
w->changeState (w->state () & ~CompWindowStateHiddenMask);
1228
priv->updateClientList ();
1229
w->priv->withdraw ();
1233
* ICCCM Section 4.1.4 says that clients need to send
1234
* a synthetic UnmapNotify for every real unmap
1235
* in order to reflect the change in state, but
1236
* since we already withdraw the window on the real
1237
* UnmapNotify, no need to do it again on the synthetic
1239
else if (!event->xunmap.send_event)
1241
w->windowNotify (CompWindowNotifyClose);
1242
w->priv->withdraw ();
1246
if (!event->xunmap.send_event)
1250
if (!w->shaded () && !w->priv->pendingMaps)
1251
w->moveInputFocusToOtherWindow ();
1255
case ReparentNotify:
1257
w = findWindow (event->xreparent.window);
1259
/* If this window isn't part of our tracked window
1260
* list and was reparented into the root window then
1261
* we need to track it */
1264
if (event->xreparent.parent == priv->root)
1266
/* Failure means that window has been destroyed. We still have to add
1267
* the window to the window list as we might get configure requests
1268
* which require us to stack other windows relative to it. Setting
1269
* some default values if this is the case. */
1270
if (!XGetWindowAttributes (priv->dpy, event->xcreatewindow.window, &wa))
1271
priv->setDefaultWindowAttributes (&wa);
1273
CoreWindow *cw = new CoreWindow (event->xcreatewindow.window);
1274
cw->manage (priv->getTopWindow (), wa);
1276
removeFromCreatedWindows (cw);
1282
/* It is possible that some plugin might call
1283
* w->destroy () before the window actually receives
1284
* its first ReparentNotify event which would mean
1285
* that it is already in the list of destroyed
1286
* windows, so check that list too */
1288
foreach (CompWindow *dw, priv->destroyedWindows)
1290
if (dw->priv->serverId == event->xreparent.window)
1299
/* This is the only case where a window is removed but not
1300
destroyed. We must remove our event mask and all passive
1305
if (event->xreparent.parent != w->priv->wrapper)
1307
w->moveInputFocusToOtherWindow ();
1310
XSelectInput (priv->dpy, w->id (), NoEventMask);
1311
XShapeSelectInput (priv->dpy, w->id (), NoEventMask);
1312
XUngrabButton (priv->dpy, AnyButton, AnyModifier, w->id ());
1317
case CirculateNotify:
1318
w = findWindow (event->xcirculate.window);
1320
w->priv->circulate (&event->xcirculate);
1323
if (event->xbutton.button == Button1 ||
1324
event->xbutton.button == Button2 ||
1325
event->xbutton.button == Button3)
1327
w = findTopLevelWindow (event->xbutton.window);
1330
if (priv->optionGetRaiseOnClick ())
1332
w->updateAttributes (CompStackingUpdateModeAboveFullscreen);
1335
if (w->id () != priv->activeWindow)
1336
if (!(w->type () & CompWindowTypeDockMask))
1338
w->moveInputFocusTo ();
1342
if (priv->grabs.empty ())
1343
XAllowEvents (priv->dpy, ReplayPointer, event->xbutton.time);
1346
case PropertyNotify:
1347
if (event->xproperty.atom == Atoms::winType)
1349
w = findWindow (event->xproperty.window);
1354
type = priv->getWindowType (w->id ());
1356
if (type != w->wmType ())
1358
if (w->isViewable ())
1360
if (w->type () == CompWindowTypeDesktopMask)
1361
priv->desktopWindowCount--;
1362
else if (type == CompWindowTypeDesktopMask)
1363
priv->desktopWindowCount++;
1366
w->wmType () = type;
1369
w->recalcActions ();
1371
if (type & (CompWindowTypeDockMask |
1372
CompWindowTypeDesktopMask))
1373
w->setDesktop (0xffffffff);
1375
priv->updateClientList ();
1377
matchPropertyChanged (w);
1381
else if (event->xproperty.atom == Atoms::winState)
1383
w = findWindow (event->xproperty.window);
1384
if (w && !w->managed ())
1388
state = priv->getWindowState (w->id ());
1389
state = CompWindow::constrainWindowState (state, w->actions ());
1391
/* EWMH suggests that we ignore changes
1392
to _NET_WM_STATE_HIDDEN */
1393
if (w->state () & CompWindowStateHiddenMask)
1394
state |= CompWindowStateHiddenMask;
1396
state &= ~CompWindowStateHiddenMask;
1398
w->changeState (state);
1401
else if (event->xproperty.atom == XA_WM_NORMAL_HINTS)
1403
w = findWindow (event->xproperty.window);
1406
w->priv->updateNormalHints ();
1407
w->recalcActions ();
1410
else if (event->xproperty.atom == XA_WM_HINTS)
1412
w = findWindow (event->xproperty.window);
1414
w->priv->updateWmHints ();
1416
else if (event->xproperty.atom == XA_WM_TRANSIENT_FOR)
1418
w = findWindow (event->xproperty.window);
1421
w->priv->updateTransientHint ();
1422
w->recalcActions ();
1425
else if (event->xproperty.atom == Atoms::wmClientLeader)
1427
w = findWindow (event->xproperty.window);
1429
w->priv->clientLeader = w->priv->getClientLeader ();
1431
else if (event->xproperty.atom == Atoms::wmIconGeometry)
1433
w = findWindow (event->xproperty.window);
1435
w->priv->updateIconGeometry ();
1437
else if (event->xproperty.atom == Atoms::wmStrut ||
1438
event->xproperty.atom == Atoms::wmStrutPartial)
1440
w = findWindow (event->xproperty.window);
1443
if (w->updateStruts ())
1447
else if (event->xproperty.atom == Atoms::mwmHints)
1449
w = findWindow (event->xproperty.window);
1451
w->priv->updateMwmHints ();
1453
else if (event->xproperty.atom == Atoms::wmProtocols)
1455
w = findWindow (event->xproperty.window);
1457
w->priv->protocols = priv->getProtocols (w->id ());
1459
else if (event->xproperty.atom == Atoms::wmIcon)
1461
w = findWindow (event->xproperty.window);
1463
w->priv->freeIcons ();
1465
else if (event->xproperty.atom == Atoms::startupId)
1467
w = findWindow (event->xproperty.window);
1469
w->priv->updateStartupId ();
1471
else if (event->xproperty.atom == XA_WM_CLASS)
1473
w = findWindow (event->xproperty.window);
1475
w->priv->updateClassHints ();
1481
if (event->xclient.message_type == Atoms::winActive)
1483
w = findTopLevelWindow (event->xclient.window);
1486
/* use focus stealing prevention if request came
1487
from an application */
1488
if (event->xclient.data.l[0] != ClientTypeApplication ||
1489
w->priv->allowWindowFocus (0, event->xclient.data.l[1]))
1495
else if (event->xclient.message_type == Atoms::winState)
1497
w = findWindow (event->xclient.window);
1500
unsigned long wState, state;
1503
wState = w->state ();
1505
for (i = 1; i < 3; i++)
1507
state = priv->windowStateMask (event->xclient.data.l[i]);
1508
if (state & ~CompWindowStateHiddenMask)
1511
#define _NET_WM_STATE_REMOVE 0
1512
#define _NET_WM_STATE_ADD 1
1513
#define _NET_WM_STATE_TOGGLE 2
1515
switch (event->xclient.data.l[0]) {
1516
case _NET_WM_STATE_REMOVE:
1519
case _NET_WM_STATE_ADD:
1522
case _NET_WM_STATE_TOGGLE:
1529
wState = CompWindow::constrainWindowState (wState,
1531
if (w->id () == priv->activeWindow)
1532
wState &= ~CompWindowStateDemandsAttentionMask;
1534
if (wState != w->state ())
1536
CompStackingUpdateMode stackingUpdateMode;
1537
unsigned long dState = wState ^ w->state ();
1539
stackingUpdateMode = CompStackingUpdateModeNone;
1541
/* raise the window whenever its fullscreen state,
1542
above/below state or maximization state changed */
1543
if (dState & (CompWindowStateFullscreenMask |
1544
CompWindowStateAboveMask |
1545
CompWindowStateBelowMask |
1546
CompWindowStateMaximizedHorzMask |
1547
CompWindowStateMaximizedVertMask))
1548
stackingUpdateMode = CompStackingUpdateModeNormal;
1550
w->changeState (wState);
1552
w->updateAttributes (stackingUpdateMode);
1556
else if (event->xclient.message_type == Atoms::wmProtocols)
1558
if ((unsigned long) event->xclient.data.l[0] == Atoms::wmPing)
1560
w = findWindow (event->xclient.data.l[2]);
1562
w->priv->handlePing (priv->lastPing);
1565
else if (event->xclient.message_type == Atoms::closeWindow)
1567
w = findWindow (event->xclient.window);
1569
w->close (event->xclient.data.l[0]);
1571
else if (event->xclient.message_type == Atoms::desktopGeometry)
1573
if (event->xclient.window == priv->root)
1575
CompOption::Value value;
1577
value.set ((int) (event->xclient.data.l[0] /
1580
setOptionForPlugin ("core", "hsize", value);
1582
value.set ((int) (event->xclient.data.l[1] /
1585
setOptionForPlugin ("core", "vsize", value);
1588
else if (event->xclient.message_type == Atoms::moveResizeWindow)
1590
w = findWindow (event->xclient.window);
1593
unsigned int xwcm = 0;
1597
unsigned int source;
1599
gravity = (event->xclient.data.l[0] & 0xFF);
1600
value_mask = (event->xclient.data.l[0] & 0xF00) >> 8;
1601
source = (event->xclient.data.l[0] & 0xF000) >> 12;
1603
memset (&xwc, 0, sizeof (xwc));
1605
if (value_mask & CWX)
1608
xwc.x = event->xclient.data.l[1];
1611
if (value_mask & CWY)
1614
xwc.y = event->xclient.data.l[2];
1617
if (value_mask & CWWidth)
1620
xwc.width = event->xclient.data.l[3];
1623
if (value_mask & CWHeight)
1626
xwc.height = event->xclient.data.l[4];
1629
w->moveResize (&xwc, xwcm, gravity, source);
1632
else if (event->xclient.message_type == Atoms::restackWindow)
1634
w = findWindow (event->xclient.window);
1637
/* TODO: other stack modes than Above and Below */
1638
if (event->xclient.data.l[1])
1640
CompWindow *sibling;
1642
sibling = findWindow (event->xclient.data.l[1]);
1645
if (event->xclient.data.l[2] == Above)
1646
w->restackAbove (sibling);
1647
else if (event->xclient.data.l[2] == Below)
1648
w->restackBelow (sibling);
1653
if (event->xclient.data.l[2] == Above)
1655
else if (event->xclient.data.l[2] == Below)
1660
else if (event->xclient.message_type == Atoms::wmChangeState)
1662
w = findWindow (event->xclient.window);
1665
if (event->xclient.data.l[0] == IconicState)
1667
if (w->actions () & CompWindowActionMinimizeMask)
1670
else if (event->xclient.data.l[0] == NormalState)
1676
else if (event->xclient.message_type == Atoms::showingDesktop)
1678
if (event->xclient.window == priv->root ||
1679
event->xclient.window == None)
1681
if (event->xclient.data.l[0])
1682
enterShowDesktopMode ();
1684
leaveShowDesktopMode (NULL);
1687
else if (event->xclient.message_type == Atoms::numberOfDesktops)
1689
if (event->xclient.window == priv->root)
1691
CompOption::Value value;
1693
value.set ((int) event->xclient.data.l[0]);
1695
setOptionForPlugin ("core", "number_of_desktops", value);
1698
else if (event->xclient.message_type == Atoms::currentDesktop)
1700
if (event->xclient.window == priv->root)
1701
priv->setCurrentDesktop (event->xclient.data.l[0]);
1703
else if (event->xclient.message_type == Atoms::winDesktop)
1705
w = findWindow (event->xclient.window);
1707
w->setDesktop (event->xclient.data.l[0]);
1709
else if (event->xclient.message_type == Atoms::wmFullscreenMonitors)
1711
w = findWindow (event->xclient.window);
1714
CompFullscreenMonitorSet monitors;
1716
monitors.top = event->xclient.data.l[0];
1717
monitors.bottom = event->xclient.data.l[1];
1718
monitors.left = event->xclient.data.l[2];
1719
monitors.right = event->xclient.data.l[3];
1721
w->priv->setFullscreenMonitors (&monitors);
1726
modHandler->updateModifierMappings ();
1729
w = screen->findWindow (event->xmaprequest.window);
1733
XWindowAttributes attr;
1734
bool doMapProcessing = true;
1736
/* We should check the override_redirect flag here, because the
1737
client might have changed it while being unmapped. */
1738
if (XGetWindowAttributes (priv->dpy, w->id (), &attr))
1739
w->priv->setOverrideRedirect (attr.override_redirect != 0);
1741
if (w->state () & CompWindowStateHiddenMask)
1742
if (!w->minimized () && !w->inShowDesktopMode ())
1743
doMapProcessing = false;
1745
if (doMapProcessing)
1746
w->priv->processMap ();
1748
w->priv->managed = true;
1750
setWindowProp (w->id (), Atoms::winDesktop, w->desktop ());
1754
XMapWindow (priv->dpy, event->xmaprequest.window);
1757
case ConfigureRequest:
1758
w = findWindow (event->xconfigurerequest.window);
1759
if (w && w->managed ())
1763
memset (&xwc, 0, sizeof (xwc));
1765
xwc.x = event->xconfigurerequest.x;
1766
xwc.y = event->xconfigurerequest.y;
1767
xwc.width = event->xconfigurerequest.width;
1768
xwc.height = event->xconfigurerequest.height;
1769
xwc.border_width = event->xconfigurerequest.border_width;
1771
w->moveResize (&xwc, event->xconfigurerequest.value_mask,
1772
0, ClientTypeUnknown);
1774
if (event->xconfigurerequest.value_mask & CWStackMode)
1776
Window above = None;
1777
CompWindow *sibling = NULL;
1779
if (event->xconfigurerequest.value_mask & CWSibling)
1781
above = event->xconfigurerequest.above;
1782
sibling = findTopLevelWindow (above);
1785
switch (event->xconfigurerequest.detail) {
1787
if (w->priv->allowWindowFocus (NO_FOCUS_MASK, 0))
1792
w->restackAbove (sibling);
1802
w->restackBelow (sibling);
1808
/* no handling of the TopIf, BottomIf, Opposite cases -
1809
there will hardly be any client using that */
1819
xwcm = event->xconfigurerequest.value_mask &
1820
(CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
1822
xwc.x = event->xconfigurerequest.x;
1823
xwc.y = event->xconfigurerequest.y;
1824
xwc.width = event->xconfigurerequest.width;
1825
xwc.height = event->xconfigurerequest.height;
1826
xwc.border_width = event->xconfigurerequest.border_width;
1830
/* Any window that receives a ConfigureRequest
1831
* is not override redirect, and may have changed
1832
* to being not override redirect */
1833
w->priv->setOverrideRedirect (false);
1834
w->configureXWindow (xwcm, &xwc);
1837
XConfigureWindow (priv->dpy, event->xconfigurerequest.window,
1841
case CirculateRequest:
1845
if (!XGetWindowAttributes (priv->dpy, event->xfocus.window, &wa))
1846
priv->setDefaultWindowAttributes (&wa);
1848
/* If the call to XGetWindowAttributes failed it means
1849
* the window was destroyed, so track the focus change
1850
* anyways since we need to increment activeNum
1851
* and the passive button grabs and then we will
1852
* get the DestroyNotify later and change the focus
1856
if (wa.root == priv->root)
1858
if (event->xfocus.mode == NotifyGrab)
1859
priv->grabbed = true;
1860
else if (event->xfocus.mode == NotifyUngrab)
1861
priv->grabbed = false;
1864
CompWindowList dockWindows;
1868
w = findTopLevelWindow (event->xfocus.window);
1869
if (w && w->managed ())
1871
unsigned int state = w->state ();
1873
if (priv->nextActiveWindow == event->xfocus.window)
1874
priv->nextActiveWindow = None;
1876
if (w->id () != priv->activeWindow)
1878
CompWindow *active = screen->findWindow (priv->activeWindow);
1880
priv->activeWindow = w->id ();
1881
w->priv->activeNum = priv->activeNum++;
1885
CompWindowList windowsLostFocus;
1886
/* If this window lost focus and was above a fullscreen window
1887
* and is no longer capable of being focused (eg, it is
1888
* not visible on this viewport) then we need to check if
1889
* any other windows below it are also now no longer capable
1890
* of being focused and restack them in the highest position
1891
* below docks that they are allowed to take */
1892
if (!active->focus ())
1894
windowsLostFocus.push_back (active);
1895
for (CompWindow *fsw = active->prev; fsw; fsw = fsw->prev)
1897
if (!fsw->focus () &&
1899
!(fsw->type () & (CompWindowTypeDockMask |
1900
CompWindowTypeFullscreenMask)) &&
1901
!fsw->overrideRedirect ())
1902
windowsLostFocus.push_back (fsw);
1904
if (fsw->type () & CompWindowTypeFullscreenMask)
1906
/* This will be the window that we must lower relative to */
1907
CompWindow *sibling = PrivateWindow::findValidStackSiblingBelow (active, fsw);
1911
for (CompWindowList::reverse_iterator rit = windowsLostFocus.rbegin ();
1912
rit != windowsLostFocus.rend (); rit++)
1914
(*rit)->restackAbove (sibling);
1923
active->changeState (active->focused () ?
1924
active->state () | CompWindowStateFocusedMask :
1925
active->state () & ~CompWindowStateFocusedMask);
1927
active->priv->updatePassiveButtonGrabs ();
1931
state |= w->state () | CompWindowStateFocusedMask;
1933
state &= w->state () & ~CompWindowStateFocusedMask;
1935
w->priv->updatePassiveButtonGrabs ();
1937
priv->addToCurrentActiveWindowHistory (w->id ());
1939
XChangeProperty (priv->dpy , priv->root,
1941
XA_WINDOW, 32, PropModeReplace,
1942
(unsigned char *) &priv->activeWindow, 1);
1944
w->windowNotify (CompWindowNotifyFocusChange);
1947
state &= ~CompWindowStateDemandsAttentionMask;
1948
w->changeState (state);
1950
else if (event->xfocus.window == priv->root)
1952
/* Don't ever let the focus go to the root
1953
* window except in grab cases
1955
* FIXME: There might be a case where we have to
1956
* handle root windows of other screens here, but
1957
* the other window managers should handle that
1960
if (event->xfocus.detail == NotifyDetailNone ||
1961
(event->xfocus.mode == NotifyNormal &&
1962
event->xfocus.detail == NotifyInferior))
1964
priv->activeWindow = None;
1966
if (event->xfocus.detail == NotifyDetailNone ||
1967
(event->xfocus.mode == NotifyNormal &&
1968
event->xfocus.detail == NotifyInferior))
1970
screen->focusDefaultWindow ();
1975
/* Ensure that docks are stacked in the right place
1977
* When a normal window gets the focus and is above a
1978
* fullscreen window, restack the docks to be above
1979
* the highest level mapped and visible normal window,
1980
* otherwise put them above the highest fullscreen window
1984
if (PrivateWindow::stackDocks (w, dockWindows, &xwc, &mask))
1986
Window sibling = xwc.sibling;
1987
xwc.stack_mode = Above;
1989
/* Then update the dock windows */
1990
foreach (CompWindow *dw, dockWindows)
1992
xwc.sibling = sibling;
1993
dw->configureXWindow (mask, &xwc);
2004
w = screen->findWindow (priv->activeWindow);
2006
priv->nextActiveWindow = None;
2007
priv->activeWindow = None;
2010
w->priv->updatePassiveButtonGrabs ();
2015
if (event->xfocus.mode == NotifyUngrab)
2016
priv->grabbed = false;
2019
if (event->xcrossing.root == priv->root)
2020
w = findTopLevelWindow (event->xcrossing.window);
2024
if (w && w->id () != priv->below)
2026
priv->below = w->id ();
2028
if (!priv->optionGetClickToFocus () &&
2029
priv->grabs.empty () &&
2030
event->xcrossing.mode != NotifyGrab &&
2031
event->xcrossing.detail != NotifyInferior)
2036
raise = priv->optionGetAutoraise ();
2037
delay = priv->optionGetAutoraiseDelay ();
2039
if (priv->autoRaiseTimer.active () &&
2040
priv->autoRaiseWindow != w->id ())
2042
priv->autoRaiseTimer.stop ();
2045
if (w->type () & ~(CompWindowTypeDockMask |
2046
CompWindowTypeDesktopMask))
2048
w->moveInputFocusTo ();
2054
priv->autoRaiseWindow = w->id ();
2055
priv->autoRaiseTimer.start (
2056
boost::bind (autoRaiseTimeout, this),
2057
delay, (unsigned int) ((float) delay * 1.2));
2061
CompStackingUpdateMode mode =
2062
CompStackingUpdateModeNormal;
2064
w->updateAttributes (mode);
2072
if (event->xcrossing.detail != NotifyInferior)
2074
if (event->xcrossing.window == priv->below)
2079
if (priv->shapeExtension &&
2080
event->type == priv->shapeEvent + ShapeNotify)
2082
w = findWindow (((XShapeEvent *) event)->window);
2086
w->priv->updateRegion ();
2089
else if (event->type == priv->syncEvent + XSyncAlarmNotify)
2091
XSyncAlarmNotifyEvent *sa;
2093
sa = (XSyncAlarmNotifyEvent *) event;
2096
foreach (w, priv->windows)
2098
if (w->priv->syncAlarm == sa->alarm)
2100
w->priv->handleSyncAlarm ();