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 <X11/Xatom.h>
30
#include <X11/Xproto.h>
31
#include <X11/extensions/shape.h>
41
#include <boost/bind.hpp>
43
#include <core/core.h>
44
#include <core/icon.h>
45
#include <core/atoms.h>
46
#include "privatewindow.h"
47
#include "privatescreen.h"
49
PluginClassStorage::Indices windowPluginClassIndices (0);
52
CompWindow::allocPluginClassIndex ()
54
unsigned int i = PluginClassStorage::allocatePluginClassIndex (windowPluginClassIndices);
56
foreach (CompWindow *w, screen->windows ())
57
if (windowPluginClassIndices.size () != w->pluginClasses.size ())
58
w->pluginClasses.resize (windowPluginClassIndices.size ());
64
CompWindow::freePluginClassIndex (unsigned int index)
66
PluginClassStorage::freePluginClassIndex (windowPluginClassIndices, index);
68
foreach (CompWindow *w, ::screen->windows ())
69
if (windowPluginClassIndices.size () != w->pluginClasses.size ())
70
w->pluginClasses.resize (windowPluginClassIndices.size ());
74
PrivateWindow::isAncestorTo (CompWindow *transient,
77
if (transient->priv->transientFor)
79
if (transient->priv->transientFor == ancestor->priv->id)
82
transient = screen->findWindow (transient->priv->transientFor);
84
return isAncestorTo (transient, ancestor);
91
PrivateWindow::recalcNormalHints ()
95
#warning fixme to max Texture size
97
maxSize -= serverGeometry.border () * 2;
99
sizeHints.x = serverGeometry.x ();
100
sizeHints.y = serverGeometry.y ();
101
sizeHints.width = serverGeometry.width ();
102
sizeHints.height = serverGeometry.height ();
104
if (!(sizeHints.flags & PBaseSize))
106
if (sizeHints.flags & PMinSize)
108
sizeHints.base_width = sizeHints.min_width;
109
sizeHints.base_height = sizeHints.min_height;
113
sizeHints.base_width = 0;
114
sizeHints.base_height = 0;
117
sizeHints.flags |= PBaseSize;
120
if (!(sizeHints.flags & PMinSize))
122
sizeHints.min_width = sizeHints.base_width;
123
sizeHints.min_height = sizeHints.base_height;
124
sizeHints.flags |= PMinSize;
127
if (!(sizeHints.flags & PMaxSize))
129
sizeHints.max_width = 65535;
130
sizeHints.max_height = 65535;
131
sizeHints.flags |= PMaxSize;
134
if (sizeHints.max_width < sizeHints.min_width)
135
sizeHints.max_width = sizeHints.min_width;
137
if (sizeHints.max_height < sizeHints.min_height)
138
sizeHints.max_height = sizeHints.min_height;
140
if (sizeHints.min_width < 1)
141
sizeHints.min_width = 1;
143
if (sizeHints.max_width < 1)
144
sizeHints.max_width = 1;
146
if (sizeHints.min_height < 1)
147
sizeHints.min_height = 1;
149
if (sizeHints.max_height < 1)
150
sizeHints.max_height = 1;
152
if (sizeHints.max_width > maxSize)
153
sizeHints.max_width = maxSize;
155
if (sizeHints.max_height > maxSize)
156
sizeHints.max_height = maxSize;
158
if (sizeHints.min_width > maxSize)
159
sizeHints.min_width = maxSize;
161
if (sizeHints.min_height > maxSize)
162
sizeHints.min_height = maxSize;
164
if (sizeHints.base_width > maxSize)
165
sizeHints.base_width = maxSize;
167
if (sizeHints.base_height > maxSize)
168
sizeHints.base_height = maxSize;
170
if (sizeHints.flags & PResizeInc)
172
if (sizeHints.width_inc == 0)
173
sizeHints.width_inc = 1;
175
if (sizeHints.height_inc == 0)
176
sizeHints.height_inc = 1;
180
sizeHints.width_inc = 1;
181
sizeHints.height_inc = 1;
182
sizeHints.flags |= PResizeInc;
185
if (sizeHints.flags & PAspect)
187
/* don't divide by 0 */
188
if (sizeHints.min_aspect.y < 1)
189
sizeHints.min_aspect.y = 1;
191
if (sizeHints.max_aspect.y < 1)
192
sizeHints.max_aspect.y = 1;
196
sizeHints.min_aspect.x = 1;
197
sizeHints.min_aspect.y = 65535;
198
sizeHints.max_aspect.x = 65535;
199
sizeHints.max_aspect.y = 1;
200
sizeHints.flags |= PAspect;
203
if (!(sizeHints.flags & PWinGravity))
205
sizeHints.win_gravity = NorthWestGravity;
206
sizeHints.flags |= PWinGravity;
211
PrivateWindow::updateNormalHints ()
216
status = XGetWMNormalHints (screen->dpy (), priv->id,
217
&priv->sizeHints, &supplied);
220
priv->sizeHints.flags = 0;
222
priv->recalcNormalHints ();
226
PrivateWindow::updateWmHints ()
230
bool iconChanged = false;
233
dFlags = hints->flags;
237
newHints = XGetWMHints (screen->dpy (), id);
240
dFlags ^= newHints->flags;
242
if (newHints->flags & InputHint)
243
inputHint = newHints->input;
247
if ((newHints->flags & IconPixmapHint) &&
248
(hints->icon_pixmap != newHints->icon_pixmap))
252
else if ((newHints->flags & IconMaskHint) &&
253
(hints->icon_mask != newHints->icon_mask))
260
iconChanged |= (dFlags & (IconPixmapHint | IconMaskHint));
272
PrivateWindow::updateClassHints ()
274
XClassHint classHint;
279
free (priv->resName);
280
priv->resName = NULL;
285
free (priv->resClass);
286
priv->resClass = NULL;
289
status = XGetClassHint (screen->dpy (),
290
priv->id, &classHint);
293
if (classHint.res_name)
295
priv->resName = strdup (classHint.res_name);
296
XFree (classHint.res_name);
299
if (classHint.res_class)
301
priv->resClass = strdup (classHint.res_class);
302
XFree (classHint.res_class);
308
PrivateWindow::updateTransientHint ()
313
priv->transientFor = None;
315
status = XGetTransientForHint (screen->dpy (),
316
priv->id, &transientFor);
320
CompWindow *ancestor;
322
ancestor = screen->findWindow (transientFor);
326
/* protect against circular transient dependencies */
327
if (transientFor == priv->id ||
328
PrivateWindow::isAncestorTo (ancestor, window))
331
priv->transientFor = transientFor;
336
PrivateWindow::updateIconGeometry ()
340
unsigned long n, left;
343
priv->iconGeometry.setGeometry (0, 0, 0, 0);
345
result = XGetWindowProperty (screen->dpy (), priv->id,
346
Atoms::wmIconGeometry,
347
0L, 1024L, False, XA_CARDINAL,
348
&actual, &format, &n, &left, &data);
350
if (result == Success && data)
354
unsigned long *geometry = (unsigned long *) data;
356
priv->iconGeometry.setX (geometry[0]);
357
priv->iconGeometry.setY (geometry[1]);
358
priv->iconGeometry.setWidth (geometry[2]);
359
priv->iconGeometry.setHeight (geometry[3]);
367
PrivateWindow::getClientLeaderOfAncestor ()
371
CompWindow *w = screen->findWindow (transientFor);
374
if (w->priv->clientLeader)
375
return w->priv->clientLeader;
377
return w->priv->getClientLeaderOfAncestor ();
385
PrivateWindow::getClientLeader ()
389
unsigned long n, left;
392
result = XGetWindowProperty (screen->dpy (), priv->id,
393
Atoms::wmClientLeader,
394
0L, 1L, False, XA_WINDOW, &actual, &format,
397
if (result == Success && data)
402
memcpy (&win, data, sizeof (Window));
404
XFree ((void *) data);
410
return priv->getClientLeaderOfAncestor ();
414
PrivateWindow::getStartupId ()
418
unsigned long n, left;
421
result = XGetWindowProperty (screen->dpy (), priv->id,
428
if (result == Success && data)
433
id = strdup ((char *) data);
434
XFree ((void *) data);
443
PrivateWindow::setFullscreenMonitors (CompFullscreenMonitorSet *monitors)
445
bool hadFsMonitors = fullscreenMonitorsSet;
446
unsigned int outputs = screen->outputDevs ().size ();
448
fullscreenMonitorsSet = false;
451
(unsigned int) monitors->left < outputs &&
452
(unsigned int) monitors->right < outputs &&
453
(unsigned int) monitors->top < outputs &&
454
(unsigned int) monitors->bottom < outputs)
456
CompRect fsRect (screen->outputDevs ()[monitors->left].x1 (),
457
screen->outputDevs ()[monitors->top].y1 (),
458
screen->outputDevs ()[monitors->right].x2 (),
459
screen->outputDevs ()[monitors->bottom].y2 ());
461
if (fsRect.x1 () < fsRect.x2 () && fsRect.y1 () < fsRect.y2 ())
463
fullscreenMonitorsSet = true;
464
fullscreenMonitorRect = fsRect;
468
if (fullscreenMonitorsSet)
472
data[0] = monitors->top;
473
data[1] = monitors->bottom;
474
data[2] = monitors->left;
475
data[3] = monitors->right;
477
XChangeProperty (screen->dpy (), id, Atoms::wmFullscreenMonitors,
478
XA_CARDINAL, 32, PropModeReplace,
479
(unsigned char *) data, 4);
481
else if (hadFsMonitors)
483
XDeleteProperty (screen->dpy (), id, Atoms::wmFullscreenMonitors);
486
if (state & CompWindowStateFullscreenMask)
487
if (fullscreenMonitorsSet || hadFsMonitors)
488
window->updateAttributes (CompStackingUpdateModeNone);
492
CompWindow::changeState (unsigned int newState)
494
unsigned int oldState;
496
if (priv->state == newState)
499
oldState = priv->state;
500
priv->state = newState;
506
screen->priv->setWindowState (priv->state, priv->id);
508
stateChangeNotify (oldState);
509
screen->matchPropertyChanged (this);
513
setWindowActions (CompScreen *s,
514
unsigned int actions,
520
if (actions & CompWindowActionMoveMask)
521
data[i++] = Atoms::winActionMove;
522
if (actions & CompWindowActionResizeMask)
523
data[i++] = Atoms::winActionResize;
524
if (actions & CompWindowActionStickMask)
525
data[i++] = Atoms::winActionStick;
526
if (actions & CompWindowActionMinimizeMask)
527
data[i++] = Atoms::winActionMinimize;
528
if (actions & CompWindowActionMaximizeHorzMask)
529
data[i++] = Atoms::winActionMaximizeHorz;
530
if (actions & CompWindowActionMaximizeVertMask)
531
data[i++] = Atoms::winActionMaximizeVert;
532
if (actions & CompWindowActionFullscreenMask)
533
data[i++] = Atoms::winActionFullscreen;
534
if (actions & CompWindowActionCloseMask)
535
data[i++] = Atoms::winActionClose;
536
if (actions & CompWindowActionShadeMask)
537
data[i++] = Atoms::winActionShade;
538
if (actions & CompWindowActionChangeDesktopMask)
539
data[i++] = Atoms::winActionChangeDesktop;
540
if (actions & CompWindowActionAboveMask)
541
data[i++] = Atoms::winActionAbove;
542
if (actions & CompWindowActionBelowMask)
543
data[i++] = Atoms::winActionBelow;
545
XChangeProperty (s->dpy (), id, Atoms::wmAllowedActions,
546
XA_ATOM, 32, PropModeReplace,
547
(unsigned char *) data, i);
551
CompWindow::recalcActions ()
553
unsigned int actions = 0;
554
unsigned int setActions, clearActions;
556
switch (priv->type) {
557
case CompWindowTypeFullscreenMask:
558
case CompWindowTypeNormalMask:
560
CompWindowActionMaximizeHorzMask |
561
CompWindowActionMaximizeVertMask |
562
CompWindowActionFullscreenMask |
563
CompWindowActionMoveMask |
564
CompWindowActionResizeMask |
565
CompWindowActionStickMask |
566
CompWindowActionMinimizeMask |
567
CompWindowActionCloseMask |
568
CompWindowActionChangeDesktopMask;
570
case CompWindowTypeUtilMask:
571
case CompWindowTypeMenuMask:
572
case CompWindowTypeToolbarMask:
574
CompWindowActionMoveMask |
575
CompWindowActionResizeMask |
576
CompWindowActionStickMask |
577
CompWindowActionCloseMask |
578
CompWindowActionChangeDesktopMask;
580
case CompWindowTypeDialogMask:
581
case CompWindowTypeModalDialogMask:
583
CompWindowActionMaximizeHorzMask |
584
CompWindowActionMaximizeVertMask |
585
CompWindowActionMoveMask |
586
CompWindowActionResizeMask |
587
CompWindowActionStickMask |
588
CompWindowActionCloseMask |
589
CompWindowActionChangeDesktopMask;
591
/* allow minimization for dialog windows if they
592
a) are not a transient (transients can be minimized
594
b) don't have the skip taskbar hint set (as those
595
have no target to be minimized to)
597
if (!priv->transientFor &&
598
!(priv->state & CompWindowStateSkipTaskbarMask))
600
actions |= CompWindowActionMinimizeMask;
607
actions |= CompWindowActionShadeMask;
609
actions |= (CompWindowActionAboveMask | CompWindowActionBelowMask);
611
switch (priv->wmType) {
612
case CompWindowTypeNormalMask:
613
actions |= CompWindowActionFullscreenMask |
614
CompWindowActionMinimizeMask;
619
if (priv->sizeHints.min_width == priv->sizeHints.max_width &&
620
priv->sizeHints.min_height == priv->sizeHints.max_height)
621
actions &= ~(CompWindowActionResizeMask |
622
CompWindowActionMaximizeHorzMask |
623
CompWindowActionMaximizeVertMask |
624
CompWindowActionFullscreenMask);
626
if (!(priv->mwmFunc & MwmFuncAll))
628
if (!(priv->mwmFunc & MwmFuncResize))
629
actions &= ~(CompWindowActionResizeMask |
630
CompWindowActionMaximizeHorzMask |
631
CompWindowActionMaximizeVertMask |
632
CompWindowActionFullscreenMask);
634
if (!(priv->mwmFunc & MwmFuncMove))
635
actions &= ~(CompWindowActionMoveMask |
636
CompWindowActionMaximizeHorzMask |
637
CompWindowActionMaximizeVertMask |
638
CompWindowActionFullscreenMask);
640
if (!(priv->mwmFunc & MwmFuncIconify))
641
actions &= ~CompWindowActionMinimizeMask;
643
if (!(priv->mwmFunc & MwmFuncClose))
644
actions &= ~CompWindowActionCloseMask;
647
getAllowedActions (setActions, clearActions);
648
actions &= ~clearActions;
649
actions |= setActions;
651
if (actions != priv->actions)
653
priv->actions = actions;
654
setWindowActions (screen, actions, priv->id);
659
CompWindow::getAllowedActions (unsigned int &setActions,
660
unsigned int &clearActions)
662
WRAPABLE_HND_FUNC (1, getAllowedActions, setActions, clearActions)
669
CompWindow::constrainWindowState (unsigned int state,
670
unsigned int actions)
672
if (!(actions & CompWindowActionMaximizeHorzMask))
673
state &= ~CompWindowStateMaximizedHorzMask;
675
if (!(actions & CompWindowActionMaximizeVertMask))
676
state &= ~CompWindowStateMaximizedVertMask;
678
if (!(actions & CompWindowActionShadeMask))
679
state &= ~CompWindowStateShadedMask;
681
if (!(actions & CompWindowActionFullscreenMask))
682
state &= ~CompWindowStateFullscreenMask;
688
PrivateWindow::windowTypeFromString (const char *str)
690
if (strcasecmp (str, "desktop") == 0)
691
return CompWindowTypeDesktopMask;
692
else if (strcasecmp (str, "dock") == 0)
693
return CompWindowTypeDockMask;
694
else if (strcasecmp (str, "toolbar") == 0)
695
return CompWindowTypeToolbarMask;
696
else if (strcasecmp (str, "menu") == 0)
697
return CompWindowTypeMenuMask;
698
else if (strcasecmp (str, "utility") == 0)
699
return CompWindowTypeUtilMask;
700
else if (strcasecmp (str, "splash") == 0)
701
return CompWindowTypeSplashMask;
702
else if (strcasecmp (str, "dialog") == 0)
703
return CompWindowTypeDialogMask;
704
else if (strcasecmp (str, "normal") == 0)
705
return CompWindowTypeNormalMask;
706
else if (strcasecmp (str, "dropdownmenu") == 0)
707
return CompWindowTypeDropdownMenuMask;
708
else if (strcasecmp (str, "popupmenu") == 0)
709
return CompWindowTypePopupMenuMask;
710
else if (strcasecmp (str, "tooltip") == 0)
711
return CompWindowTypeTooltipMask;
712
else if (strcasecmp (str, "notification") == 0)
713
return CompWindowTypeNotificationMask;
714
else if (strcasecmp (str, "combo") == 0)
715
return CompWindowTypeComboMask;
716
else if (strcasecmp (str, "dnd") == 0)
717
return CompWindowTypeDndMask;
718
else if (strcasecmp (str, "modaldialog") == 0)
719
return CompWindowTypeModalDialogMask;
720
else if (strcasecmp (str, "fullscreen") == 0)
721
return CompWindowTypeFullscreenMask;
722
else if (strcasecmp (str, "unknown") == 0)
723
return CompWindowTypeUnknownMask;
724
else if (strcasecmp (str, "any") == 0)
731
CompWindow::recalcType ()
737
if (!overrideRedirect () && priv->wmType == CompWindowTypeUnknownMask)
738
type = CompWindowTypeNormalMask;
740
if (priv->state & CompWindowStateFullscreenMask)
741
type = CompWindowTypeFullscreenMask;
743
if (type == CompWindowTypeNormalMask)
745
if (priv->transientFor)
746
type = CompWindowTypeDialogMask;
749
if (type == CompWindowTypeDockMask &&
750
(priv->state & CompWindowStateBelowMask))
752
type = CompWindowTypeNormalMask;
755
if ((type & (CompWindowTypeNormalMask | CompWindowTypeDialogMask)) &&
756
(priv->state & CompWindowStateModalMask))
758
type = CompWindowTypeModalDialogMask;
766
PrivateWindow::updateFrameWindow ()
771
if (input.left || input.right || input.top || input.bottom)
773
int x, y, width, height;
774
int bw = serverGeometry.border () * 2;
776
x = serverGeometry.x () - input.left;
777
y = serverGeometry.y () - input.top;
778
width = serverGeometry.width () + input.left + input.right + bw;
779
height = serverGeometry.height () + input.top + input.bottom + bw;
782
height = input.top + input.bottom;
784
XMoveResizeWindow (screen->dpy (), frame, x, y, width, height);
787
XUnmapWindow (screen->dpy (), wrapper);
791
XMapWindow (screen->dpy (), wrapper);
792
XMoveResizeWindow (screen->dpy (), wrapper, input.left, input.top,
793
serverGeometry.width (), serverGeometry.height ());
795
XMoveResizeWindow (screen->dpy (), id, 0, 0,
796
serverGeometry.width (), serverGeometry.height ());
797
window->sendConfigureNotify ();
799
window->updateFrameRegion ();
800
window->windowNotify (CompWindowNotifyFrameUpdate);
804
int x, y, width, height;
805
int bw = serverGeometry.border () * 2;
807
x = serverGeometry.x ();
808
y = serverGeometry.y ();
809
width = serverGeometry.width () + bw;
810
height = serverGeometry.height () + bw;
815
XMoveResizeWindow (screen->dpy (), frame, x, y, width, height);
818
XUnmapWindow (screen->dpy (), wrapper);
822
XMapWindow (screen->dpy (), wrapper);
823
XMoveResizeWindow (screen->dpy (), wrapper, 0, 0,
824
serverGeometry.width (), serverGeometry.height ());
826
XMoveResizeWindow (screen->dpy (), id, 0, 0,
827
serverGeometry.width (), serverGeometry.height ());
828
window->sendConfigureNotify ();
829
frameRegion = CompRegion ();
830
window->windowNotify (CompWindowNotifyFrameUpdate);
833
window->recalcActions ();
839
CompWindow::updateWindowOutputExtents ()
841
CompWindowExtents output;
843
getOutputExtents (output);
845
if (output.left != priv->output.left ||
846
output.right != priv->output.right ||
847
output.top != priv->output.top ||
848
output.bottom != priv->output.bottom)
850
priv->output = output;
852
resizeNotify (0, 0, 0, 0);
857
CompWindow::getOutputExtents (CompWindowExtents& output)
859
WRAPABLE_HND_FUNC (0, getOutputExtents, output)
868
PrivateWindow::rectsToRegion (unsigned int n, XRectangle *rects)
873
for (unsigned int i = 0; i < n; i++)
875
x1 = rects[i].x + priv->attrib.border_width;
876
y1 = rects[i].y + priv->attrib.border_width;
877
x2 = x1 + rects[i].width;
878
y2 = y1 + rects[i].height;
884
if (x2 > priv->width)
886
if (y2 > priv->height)
889
if (y1 < y2 && x1 < x2)
891
x1 += priv->attrib.x;
892
y1 += priv->attrib.y;
893
x2 += priv->attrib.x;
894
y2 += priv->attrib.y;
896
ret += CompRect (x1, y1, x2 - x1, y2 - y1);
903
/* TODO: This function should be able to check the XShape event
904
* kind and only get/set shape rectangles for either ShapeInput
905
* or ShapeBounding, but not both at the same time
909
PrivateWindow::updateRegion ()
911
XRectangle r, *boundingShapeRects = NULL;
912
XRectangle *inputShapeRects = NULL;
913
int nBounding = 0, nInput = 0;
915
priv->region = CompRegion ();
916
priv->inputRegion = CompRegion ();
918
if (screen->XShape ())
922
boundingShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
923
ShapeBounding, &nBounding, &order);
924
inputShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
925
ShapeInput, &nInput, &order);
929
r.x = -priv->attrib.border_width;
930
r.y = -priv->attrib.border_width;
931
r.width = priv->width + priv->attrib.border_width;
932
r.height = priv->height + priv->attrib.border_width;
936
boundingShapeRects = &r;
942
inputShapeRects = &r;
946
priv->region += rectsToRegion (nBounding, boundingShapeRects);
947
priv->inputRegion += rectsToRegion (nInput, inputShapeRects);
949
if (boundingShapeRects && boundingShapeRects != &r)
950
XFree (boundingShapeRects);
951
if (inputShapeRects && inputShapeRects != &r)
952
XFree (inputShapeRects);
954
window->updateFrameRegion ();
958
CompWindow::updateStruts ()
962
unsigned long n, left;
965
CompStruts oldStrut, newStrut;
971
oldStrut.left = priv->struts->left;
972
oldStrut.right = priv->struts->right;
973
oldStrut.top = priv->struts->top;
974
oldStrut.bottom = priv->struts->bottom;
985
newStrut.left.width = 0;
986
newStrut.left.height = screen->height ();
988
newStrut.right.x = screen->width ();
989
newStrut.right.y = 0;
990
newStrut.right.width = 0;
991
newStrut.right.height = screen->height ();
995
newStrut.top.width = screen->width ();
996
newStrut.top.height = 0;
998
newStrut.bottom.x = 0;
999
newStrut.bottom.y = screen->height ();
1000
newStrut.bottom.width = screen->width ();
1001
newStrut.bottom.height = 0;
1003
result = XGetWindowProperty (screen->dpy (), priv->id,
1004
Atoms::wmStrutPartial,
1005
0L, 12L, false, XA_CARDINAL, &actual, &format,
1008
if (result == Success && data)
1010
unsigned long *struts = (unsigned long *) data;
1016
newStrut.left.y = struts[4];
1017
newStrut.left.width = struts[0];
1018
newStrut.left.height = struts[5] - newStrut.left.y + 1;
1020
newStrut.right.width = struts[1];
1021
newStrut.right.x = screen->width () - newStrut.right.width;
1022
newStrut.right.y = struts[6];
1023
newStrut.right.height = struts[7] - newStrut.right.y + 1;
1025
newStrut.top.x = struts[8];
1026
newStrut.top.width = struts[9] - newStrut.top.x + 1;
1027
newStrut.top.height = struts[2];
1029
newStrut.bottom.x = struts[10];
1030
newStrut.bottom.width = struts[11] - newStrut.bottom.x + 1;
1031
newStrut.bottom.height = struts[3];
1032
newStrut.bottom.y = screen->height () - newStrut.bottom.height;
1040
result = XGetWindowProperty (screen->dpy (), priv->id,
1042
0L, 4L, false, XA_CARDINAL,
1043
&actual, &format, &n, &left, &data);
1045
if (result == Success && data)
1047
unsigned long *struts = (unsigned long *) data;
1053
newStrut.left.x = 0;
1054
newStrut.left.width = struts[0];
1056
newStrut.right.width = struts[1];
1057
newStrut.right.x = screen->width () - newStrut.right.width;
1060
newStrut.top.height = struts[2];
1062
newStrut.bottom.height = struts[3];
1063
newStrut.bottom.y = screen->height () - newStrut.bottom.height;
1072
int strutX1, strutY1, strutX2, strutY2;
1075
/* applications expect us to clip struts to xinerama edges */
1076
for (unsigned int i = 0;
1077
i < screen->screenInfo ().size (); i++)
1079
x1 = screen->screenInfo ()[i].x_org;
1080
y1 = screen->screenInfo ()[i].y_org;
1081
x2 = x1 + screen->screenInfo ()[i].width;
1082
y2 = y1 + screen->screenInfo ()[i].height;
1084
strutX1 = newStrut.left.x;
1085
strutX2 = strutX1 + newStrut.left.width;
1086
strutY1 = newStrut.left.y;
1087
strutY2 = strutY1 + newStrut.left.height;
1089
if (strutX2 > x1 && strutX2 <= x2 &&
1090
strutY1 < y2 && strutY2 > y1)
1092
newStrut.left.x = x1;
1093
newStrut.left.width = strutX2 - x1;
1096
strutX1 = newStrut.right.x;
1097
strutX2 = strutX1 + newStrut.right.width;
1098
strutY1 = newStrut.right.y;
1099
strutY2 = strutY1 + newStrut.right.height;
1101
if (strutX1 > x1 && strutX1 <= x2 &&
1102
strutY1 < y2 && strutY2 > y1)
1104
newStrut.right.x = strutX1;
1105
newStrut.right.width = x2 - strutX1;
1108
strutX1 = newStrut.top.x;
1109
strutX2 = strutX1 + newStrut.top.width;
1110
strutY1 = newStrut.top.y;
1111
strutY2 = strutY1 + newStrut.top.height;
1113
if (strutX1 < x2 && strutX2 > x1 &&
1114
strutY2 > y1 && strutY2 <= y2)
1116
newStrut.top.y = y1;
1117
newStrut.top.height = strutY2 - y1;
1120
strutX1 = newStrut.bottom.x;
1121
strutX2 = strutX1 + newStrut.bottom.width;
1122
strutY1 = newStrut.bottom.y;
1123
strutY2 = strutY1 + newStrut.bottom.height;
1125
if (strutX1 < x2 && strutX2 > x1 &&
1126
strutY1 > y1 && strutY1 <= y2)
1128
newStrut.bottom.y = strutY1;
1129
newStrut.bottom.height = y2 - strutY1;
1134
if (hasOld != hasNew ||
1135
(hasNew && hasOld &&
1136
memcmp (&newStrut, &oldStrut, sizeof (CompStruts))))
1142
priv->struts = (CompStruts *) malloc (sizeof (CompStruts));
1147
*priv->struts = newStrut;
1151
free (priv->struts);
1152
priv->struts = NULL;
1162
CompWindow::incrementDestroyReference ()
1164
priv->destroyRefCnt++;
1168
CompWindow::destroy ()
1170
windowNotify (CompWindowNotifyBeforeDestroy);
1172
screen->priv->eraseWindowFromMap (id ());
1177
priv->destroyRefCnt--;
1178
if (priv->destroyRefCnt)
1182
if (!priv->destroyed)
1184
priv->destroyed = true;
1185
screen->priv->pendingDestroys++;
1189
priv->unreparent ();
1194
CompWindow::sendConfigureNotify ()
1196
XConfigureEvent xev;
1198
xev.type = ConfigureNotify;
1199
xev.event = priv->id;
1200
xev.window = priv->id;
1202
/* normally we should never send configure notify events to override
1203
redirect windows but if they support the _NET_WM_SYNC_REQUEST
1204
protocol we need to do this when the window is mapped. however the
1205
only way we can make sure that the attributes we send are correct
1206
and is to grab the server. */
1207
if (priv->attrib.override_redirect)
1209
XWindowAttributes attrib;
1211
XGrabServer (screen->dpy ());
1213
if (XGetWindowAttributes (screen->dpy (), priv->id, &attrib))
1217
xev.width = attrib.width;
1218
xev.height = attrib.height;
1219
xev.border_width = attrib.border_width;
1221
xev.above = (prev) ? prev->priv->id : None;
1222
xev.override_redirect = true;
1224
XSendEvent (screen->dpy (), priv->id, false,
1225
StructureNotifyMask, (XEvent *) &xev);
1228
XUngrabServer (screen->dpy ());
1232
xev.x = priv->serverGeometry.x ();
1233
xev.y = priv->serverGeometry.y ();
1234
xev.width = priv->serverGeometry.width ();
1235
xev.height = priv->serverGeometry.height ();
1236
xev.border_width = priv->serverGeometry.border ();
1238
xev.above = (prev) ? prev->priv->id : None;
1239
xev.override_redirect = priv->attrib.override_redirect;
1241
XSendEvent (screen->dpy (), priv->id, false,
1242
StructureNotifyMask, (XEvent *) &xev);
1249
windowNotify (CompWindowNotifyBeforeMap);
1253
if (priv->pendingMaps > 0)
1254
priv->pendingMaps = 0;
1256
priv->mapNum = screen->priv->mapNum++;
1259
screen->updateWorkarea ();
1261
if (windowClass () == InputOnly)
1264
priv->unmapRefCnt = 1;
1266
priv->attrib.map_state = IsViewable;
1268
if (!overrideRedirect ())
1269
screen->priv->setWmState (NormalState, priv->id);
1271
priv->invisible = true;
1274
priv->lastPong = screen->priv->lastPing;
1276
priv->updateRegion ();
1277
priv->updateSize ();
1279
screen->priv->updateClientList ();
1281
if (priv->type & CompWindowTypeDesktopMask)
1282
screen->priv->desktopWindowCount++;
1284
if (priv->protocols & CompWindowProtocolSyncRequestMask)
1287
sendConfigureNotify ();
1290
if (!overrideRedirect ())
1294
resize (priv->attrib.x, priv->attrib.y, priv->attrib.width,
1295
++priv->attrib.height - 1, priv->attrib.border_width);
1299
windowNotify (CompWindowNotifyMap);
1303
CompWindow::incrementUnmapReference ()
1305
priv->unmapRefCnt++;
1309
CompWindow::unmap ()
1311
windowNotify (CompWindowNotifyBeforeUnmap);
1316
priv->unmapRefCnt--;
1317
if (priv->unmapRefCnt > 0)
1320
if (priv->unmanaging)
1324
int gravity = priv->sizeHints.win_gravity;
1326
/* revert gravity adjustment made at MapNotify time */
1327
xwc.x = priv->serverGeometry.x ();
1328
xwc.y = priv->serverGeometry.y ();
1332
xwcm = priv->adjustConfigureRequestForGravity (&xwc,
1337
configureXWindow (xwcm, &xwc);
1339
priv->unmanaging = false;
1343
screen->updateWorkarea ();
1345
if (priv->attrib.map_state != IsViewable)
1348
if (priv->type == CompWindowTypeDesktopMask)
1349
screen->priv->desktopWindowCount--;
1351
priv->attrib.map_state = IsUnmapped;
1353
priv->invisible = true;
1355
if (priv->shaded && priv->height)
1356
resize (priv->attrib.x, priv->attrib.y,
1357
priv->attrib.width, ++priv->attrib.height - 1,
1358
priv->attrib.border_width);
1360
screen->priv->updateClientList ();
1362
windowNotify (CompWindowNotifyUnmap);
1366
PrivateWindow::restack (Window aboveId)
1368
if (aboveId && (aboveId == id || aboveId == frame))
1369
// Don't try to raise a window above itself
1371
else if (window->prev)
1373
if (aboveId && (aboveId == window->prev->id () ||
1374
aboveId == window->prev->frame ()))
1377
else if (aboveId == None && !window->next)
1380
if (aboveId && !screen->findTopLevelWindow (aboveId, true))
1383
screen->unhookWindow (window);
1384
screen->insertWindow (window, aboveId);
1386
screen->priv->updateClientList ();
1388
window->windowNotify (CompWindowNotifyRestack);
1394
CompWindow::resize (XWindowAttributes attr)
1396
return resize (Geometry (attr.x, attr.y, attr.width, attr.height,
1397
attr.border_width));
1401
CompWindow::resize (int x,
1407
return resize (Geometry (x, y, width, height, border));
1411
CompWindow::resize (CompWindow::Geometry gm)
1413
if (priv->attrib.width != gm.width () ||
1414
priv->attrib.height != gm.height () ||
1415
priv->attrib.border_width != gm.border ())
1418
int dx, dy, dwidth, dheight;
1420
pw = gm.width () + gm.border () * 2;
1421
ph = gm.height () + gm.border () * 2;
1426
dx = gm.x () - priv->attrib.x;
1427
dy = gm.y () - priv->attrib.y;
1428
dwidth = gm.width () - priv->attrib.width;
1429
dheight = gm.height () - priv->attrib.height;
1431
priv->attrib.x = gm.x ();
1432
priv->attrib.y = gm.y ();
1433
priv->attrib.width = gm.width ();
1434
priv->attrib.height = gm.height ();
1435
priv->attrib.border_width = gm.border ();
1437
priv->geometry.set (priv->attrib.x, priv->attrib.y,
1438
priv->attrib.width, priv->attrib.height,
1439
priv->attrib.border_width);
1441
if (!priv->mapNum && priv->unmapRefCnt > 0 &&
1442
priv->attrib.map_state == IsViewable)
1444
/* keep old pixmap for windows that are unmapped on the client side,
1445
* but not yet on our side as it's pretty likely that plugins are
1446
* currently using it for animations
1456
priv->updateRegion ();
1458
resizeNotify (dx, dy, dwidth, dheight);
1460
priv->invisible = WINDOW_INVISIBLE (priv);
1461
priv->updateFrameWindow ();
1463
else if (priv->attrib.x != gm.x () || priv->attrib.y != gm.y ())
1467
dx = gm.x () - priv->attrib.x;
1468
dy = gm.y () - priv->attrib.y;
1477
syncValueIncrement (XSyncValue *value)
1482
XSyncIntToValue (&one, 1);
1483
XSyncValueAdd (value, *value, one, &overflow);
1487
PrivateWindow::initializeSyncCounter ()
1489
XSyncAlarmAttributes values;
1492
unsigned long n, left;
1493
unsigned char *data;
1496
return syncAlarm != None;
1498
if (!(protocols & CompWindowProtocolSyncRequestMask))
1501
result = XGetWindowProperty (screen->dpy (), id,
1502
Atoms::wmSyncRequestCounter,
1503
0L, 1L, false, XA_CARDINAL, &actual, &format,
1506
if (result == Success && n && data)
1508
unsigned long *counter = (unsigned long *) data;
1510
syncCounter = *counter;
1514
XSyncIntsToValue (&syncValue, (unsigned int) rand (), 0);
1515
XSyncSetCounter (screen->dpy (),
1519
syncValueIncrement (&syncValue);
1521
values.events = true;
1523
values.trigger.counter = syncCounter;
1524
values.trigger.wait_value = syncValue;
1526
values.trigger.value_type = XSyncAbsolute;
1527
values.trigger.test_type = XSyncPositiveComparison;
1529
XSyncIntToValue (&values.delta, 1);
1531
values.events = true;
1533
CompScreen::checkForError (screen->dpy ());
1535
/* Note that by default, the alarm increments the trigger value
1536
* when it fires until the condition (counter.value < trigger.value)
1539
syncAlarm = XSyncCreateAlarm (screen->dpy (),
1548
if (CompScreen::checkForError (screen->dpy ()))
1551
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
1554
else if (result == Success && data)
1563
CompWindow::sendSyncRequest ()
1565
XClientMessageEvent xev;
1570
if (!priv->initializeSyncCounter ())
1573
xev.type = ClientMessage;
1574
xev.window = priv->id;
1575
xev.message_type = Atoms::wmProtocols;
1577
xev.data.l[0] = Atoms::wmSyncRequest;
1578
xev.data.l[1] = CurrentTime;
1579
xev.data.l[2] = XSyncValueLow32 (priv->syncValue);
1580
xev.data.l[3] = XSyncValueHigh32 (priv->syncValue);
1583
syncValueIncrement (&priv->syncValue);
1585
XSendEvent (screen->dpy (), priv->id, false, 0, (XEvent *) &xev);
1587
priv->syncWait = true;
1588
priv->syncGeometry = priv->serverGeometry;
1590
if (!priv->syncWaitTimer.active ())
1591
priv->syncWaitTimer.start ();
1595
PrivateWindow::configure (XConfigureEvent *ce)
1600
priv->attrib.override_redirect = ce->override_redirect;
1604
priv->syncGeometry.set (ce->x, ce->y, ce->width, ce->height,
1609
if (ce->override_redirect)
1611
priv->serverGeometry.set (ce->x, ce->y, ce->width, ce->height,
1615
window->resize (ce->x, ce->y, ce->width, ce->height, ce->border_width);
1618
if (ce->event == screen->root ())
1619
priv->restack (ce->above);
1623
PrivateWindow::configureFrame (XConfigureEvent *ce)
1625
int x, y, width, height;
1631
x = ce->x + priv->input.left;
1632
y = ce->y + priv->input.top;
1633
width = ce->width - priv->input.left - priv->input.right;
1634
height = ce->height - priv->input.top - priv->input.bottom;
1638
priv->syncGeometry.set (x, y, width, height, ce->border_width);
1642
if (ce->override_redirect)
1644
priv->serverGeometry.set (x, y, width, height, ce->border_width);
1647
window->resize (x, y, width, height, ce->border_width);
1650
if (priv->restack (ce->above))
1651
priv->updatePassiveButtonGrabs ();
1653
above = screen->findWindow (ce->above);
1656
above->priv->updatePassiveButtonGrabs ();
1660
PrivateWindow::circulate (XCirculateEvent *ce)
1664
if (ce->place == PlaceOnTop)
1665
newAboveId = screen->priv->getTopWindow ();
1669
priv->restack (newAboveId);
1673
CompWindow::move (int dx,
1679
priv->attrib.x += dx;
1680
priv->attrib.y += dy;
1682
priv->geometry.setX (priv->attrib.x);
1683
priv->geometry.setY (priv->attrib.y);
1685
priv->region.translate (dx, dy);
1686
priv->inputRegion.translate (dx, dy);
1687
if (!priv->frameRegion.isEmpty ())
1688
priv->frameRegion.translate (dx, dy);
1690
priv->invisible = WINDOW_INVISIBLE (priv);
1692
moveNotify (dx, dy, immediate);
1697
CompWindow::syncPosition ()
1699
priv->serverGeometry.setX (priv->attrib.x);
1700
priv->serverGeometry.setY (priv->attrib.y);
1702
XMoveWindow (screen->dpy (), ROOTPARENT (this),
1703
priv->attrib.x - priv->input.left,
1704
priv->attrib.y - priv->input.top);
1708
XMoveWindow (screen->dpy (), priv->wrapper,
1709
priv->input.left, priv->input.top);
1710
sendConfigureNotify ();
1715
CompWindow::focus ()
1717
WRAPABLE_HND_FUNC_RETURN (2, bool, focus)
1719
if (overrideRedirect ())
1722
if (!priv->managed || priv->unmanaging)
1725
if (!onCurrentDesktop ())
1728
if (priv->destroyed)
1731
if (!priv->shaded && (priv->state & CompWindowStateHiddenMask))
1734
if (priv->attrib.x + priv->width <= 0 ||
1735
priv->attrib.y + priv->height <= 0 ||
1736
priv->attrib.x >= (int) screen->width ()||
1737
priv->attrib.y >= (int) screen->height ())
1744
CompWindow::place (CompPoint &pos)
1746
WRAPABLE_HND_FUNC_RETURN (4, bool, place, pos)
1751
CompWindow::validateResizeRequest (unsigned int &mask,
1752
XWindowChanges *xwc,
1753
unsigned int source)
1755
WRAPABLE_HND_FUNC (5, validateResizeRequest, mask, xwc, source)
1757
if (!(priv->type & (CompWindowTypeDockMask |
1758
CompWindowTypeFullscreenMask |
1759
CompWindowTypeUnknownMask)))
1765
min = screen->workArea ().y () + priv->input.top;
1766
max = screen->workArea ().bottom ();
1768
if (priv->state & CompWindowStateStickyMask &&
1769
(xwc->y < min || xwc->y > max))
1771
xwc->y = priv->serverGeometry.y ();
1775
min -= screen->vp ().y () * screen->height ();
1776
max += (screen->vpSize ().height () - screen->vp ().y () - 1) *
1781
else if (xwc->y > max)
1790
min = screen->workArea ().x () + priv->input.left;
1791
max = screen->workArea ().right ();
1793
if (priv->state & CompWindowStateStickyMask &&
1794
(xwc->x < min || xwc->x > max))
1796
xwc->x = priv->serverGeometry.x ();
1800
min -= screen->vp ().x () * screen->width ();
1801
max += (screen->vpSize ().width () - screen->vp ().x () - 1) *
1806
else if (xwc->x > max)
1814
CompWindow::resizeNotify (int dx,
1818
WRAPABLE_HND_FUNC (6, resizeNotify, dx, dy, dwidth, dheight)
1821
CompWindow::moveNotify (int dx,
1824
WRAPABLE_HND_FUNC (7, moveNotify, dx, dy, immediate)
1827
CompWindow::windowNotify (CompWindowNotify n)
1828
WRAPABLE_HND_FUNC (8, windowNotify, n)
1831
CompWindow::grabNotify (int x,
1836
WRAPABLE_HND_FUNC (9, grabNotify, x, y, state, mask)
1837
priv->grabbed = true;
1841
CompWindow::ungrabNotify ()
1843
WRAPABLE_HND_FUNC (10, ungrabNotify)
1844
priv->grabbed = false;
1848
CompWindow::stateChangeNotify (unsigned int lastState)
1850
WRAPABLE_HND_FUNC (11, stateChangeNotify, lastState);
1852
/* if being made sticky */
1853
if (!(lastState & CompWindowStateStickyMask) &&
1854
(priv->state & CompWindowStateStickyMask))
1856
CompPoint vp; /* index of the window's vp */
1858
/* Find which viewport the window falls in,
1859
and check if it's the current viewport */
1860
vp = defaultViewport ();
1861
if (screen->vp () != vp)
1863
int moveX = (screen->vp ().x () - vp.x ()) * screen->width ();
1864
int moveY = (screen->vp ().y () - vp.y ()) * screen->height ();
1866
move (moveX, moveY, TRUE);
1874
PrivateWindow::isGroupTransient (Window clientLeader)
1879
if (transientFor == None || transientFor == screen->root ())
1881
if (type & (CompWindowTypeUtilMask |
1882
CompWindowTypeToolbarMask |
1883
CompWindowTypeMenuMask |
1884
CompWindowTypeDialogMask |
1885
CompWindowTypeModalDialogMask))
1887
if (this->clientLeader == clientLeader)
1896
PrivateWindow::getModalTransient ()
1898
CompWindow *w, *modalTransient;
1900
modalTransient = window;
1902
for (w = screen->windows ().back (); w; w = w->prev)
1904
if (w == modalTransient || w->priv->mapNum == 0)
1907
if (w->priv->transientFor == modalTransient->priv->id)
1909
if (w->priv->state & CompWindowStateModalMask)
1912
w = screen->windows ().back ();
1917
if (modalTransient == window)
1919
/* don't look for group transients with modal state if current window
1921
if (state & CompWindowStateModalMask)
1924
for (w = screen->windows ().back (); w; w = w->prev)
1926
if (w == modalTransient || w->priv->mapNum == 0)
1929
if (isAncestorTo (modalTransient, w))
1932
if (w->priv->isGroupTransient (modalTransient->priv->clientLeader))
1934
if (w->priv->state & CompWindowStateModalMask)
1937
w = w->priv->getModalTransient ();
1947
if (modalTransient == window)
1948
modalTransient = NULL;
1950
return modalTransient;
1954
CompWindow::moveInputFocusTo ()
1956
CompScreen *s = screen;
1957
CompWindow *modalTransient;
1959
modalTransient = priv->getModalTransient ();
1961
return modalTransient->moveInputFocusTo ();
1963
if (priv->state & CompWindowStateHiddenMask)
1965
XSetInputFocus (s->dpy (), priv->frame,
1966
RevertToPointerRoot, CurrentTime);
1967
XChangeProperty (s->dpy (), s->root (), Atoms::winActive,
1968
XA_WINDOW, 32, PropModeReplace,
1969
(unsigned char *) &priv->id, 1);
1973
bool setFocus = false;
1975
if (priv->inputHint)
1977
XSetInputFocus (s->dpy (), priv->id, RevertToPointerRoot,
1982
if (priv->protocols & CompWindowProtocolTakeFocusMask)
1986
ev.type = ClientMessage;
1987
ev.xclient.window = priv->id;
1988
ev.xclient.message_type = Atoms::wmProtocols;
1989
ev.xclient.format = 32;
1990
ev.xclient.data.l[0] = Atoms::wmTakeFocus;
1991
ev.xclient.data.l[1] = s->getCurrentTime ();
1992
ev.xclient.data.l[2] = 0;
1993
ev.xclient.data.l[3] = 0;
1994
ev.xclient.data.l[4] = 0;
1996
XSendEvent (s->dpy (), priv->id, false, NoEventMask, &ev);
2002
screen->priv->nextActiveWindow = priv->id;
2004
if (!setFocus && !modalTransient)
2006
CompWindow *ancestor;
2008
/* move input to closest ancestor */
2009
for (ancestor = s->windows ().front (); ancestor;
2010
ancestor = ancestor->next)
2012
if (PrivateWindow::isAncestorTo (this, ancestor))
2014
ancestor->moveInputFocusTo ();
2023
CompWindow::moveInputFocusToOtherWindow ()
2025
if (priv->id == screen->activeWindow () ||
2026
priv->id == screen->priv->nextActiveWindow)
2028
CompWindow *ancestor;
2030
if (priv->transientFor && priv->transientFor != screen->root ())
2032
ancestor = screen->findWindow (priv->transientFor);
2034
!(ancestor->priv->type & (CompWindowTypeDesktopMask |
2035
CompWindowTypeDockMask)))
2037
ancestor->moveInputFocusTo ();
2040
screen->focusDefaultWindow ();
2042
else if (priv->type & (CompWindowTypeDialogMask |
2043
CompWindowTypeModalDialogMask))
2045
CompWindow *a, *focus = NULL;
2047
for (a = screen->windows ().back (); a; a = a->prev)
2049
if (a->priv->clientLeader == priv->clientLeader)
2055
if (a->priv->type & (CompWindowTypeNormalMask |
2056
CompWindowTypeDialogMask |
2057
CompWindowTypeModalDialogMask))
2059
if (priv->compareWindowActiveness (focus, a) < 0)
2069
if (focus && !(focus->priv->type & (CompWindowTypeDesktopMask |
2070
CompWindowTypeDockMask)))
2072
focus->moveInputFocusTo ();
2075
screen->focusDefaultWindow ();
2078
screen->focusDefaultWindow ();
2084
PrivateWindow::stackLayerCheck (CompWindow *w,
2085
Window clientLeader,
2088
if (isAncestorTo (w, below))
2091
if (isAncestorTo (below, w))
2094
if (clientLeader && below->priv->clientLeader == clientLeader)
2095
if (below->priv->isGroupTransient (clientLeader))
2098
if (w->priv->state & CompWindowStateAboveMask)
2102
else if (w->priv->state & CompWindowStateBelowMask)
2104
if (below->priv->state & CompWindowStateBelowMask)
2107
else if (!(below->priv->state & CompWindowStateAboveMask))
2116
PrivateWindow::avoidStackingRelativeTo (CompWindow *w)
2118
if (w->overrideRedirect ())
2121
if (!w->priv->shaded && !w->priv->pendingMaps)
2123
if (!w->isViewable () || !w->isMapped ())
2130
/* goes through the stack, top-down until we find a window we should
2131
stack above, normal windows can be stacked above fullscreen windows
2132
(and fullscreen windows over others in their layer) if aboveFs is true. */
2134
PrivateWindow::findSiblingBelow (CompWindow *w,
2138
Window clientLeader = w->priv->clientLeader;
2139
unsigned int type = w->priv->type;
2140
unsigned int belowMask;
2143
belowMask = CompWindowTypeDockMask;
2145
belowMask = CompWindowTypeDockMask | CompWindowTypeFullscreenMask;
2147
/* normal stacking of fullscreen windows with below state */
2148
if ((type & CompWindowTypeFullscreenMask) &&
2149
(w->priv->state & CompWindowStateBelowMask))
2150
type = CompWindowTypeNormalMask;
2152
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2153
clientLeader = None;
2155
for (below = screen->windows ().back (); below;
2156
below = below->prev)
2158
if (below == w || avoidStackingRelativeTo (below))
2161
/* always above desktop windows */
2162
if (below->priv->type & CompWindowTypeDesktopMask)
2166
case CompWindowTypeDesktopMask:
2167
/* desktop window layer */
2169
case CompWindowTypeFullscreenMask:
2172
/* otherwise fall-through */
2173
case CompWindowTypeDockMask:
2174
/* fullscreen and dock layer */
2175
if (below->priv->type & (CompWindowTypeFullscreenMask |
2176
CompWindowTypeDockMask))
2178
if (stackLayerCheck (w, clientLeader, below))
2187
/* fullscreen and normal layer */
2188
if (!(below->priv->type & belowMask))
2190
if (stackLayerCheck (w, clientLeader, below))
2200
/* goes through the stack, top-down and returns the lowest window we
2203
PrivateWindow::findLowestSiblingBelow (CompWindow *w)
2205
CompWindow *below, *lowest = screen->windows ().back ();
2206
Window clientLeader = w->priv->clientLeader;
2207
unsigned int type = w->priv->type;
2209
/* normal stacking fullscreen windows with below state */
2210
if ((type & CompWindowTypeFullscreenMask) &&
2211
(w->priv->state & CompWindowStateBelowMask))
2212
type = CompWindowTypeNormalMask;
2214
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2215
clientLeader = None;
2217
for (below = screen->windows ().back (); below;
2218
below = below->prev)
2220
if (below == w || avoidStackingRelativeTo (below))
2223
/* always above desktop windows */
2224
if (below->priv->type & CompWindowTypeDesktopMask)
2228
case CompWindowTypeDesktopMask:
2229
/* desktop window layer - desktop windows always should be
2230
stacked at the bottom; no other window should be below them */
2233
case CompWindowTypeFullscreenMask:
2234
case CompWindowTypeDockMask:
2235
/* fullscreen and dock layer */
2236
if (below->priv->type & (CompWindowTypeFullscreenMask |
2237
CompWindowTypeDockMask))
2239
if (!stackLayerCheck (below, clientLeader, w))
2248
/* fullscreen and normal layer */
2249
if (!(below->priv->type & CompWindowTypeDockMask))
2251
if (!stackLayerCheck (below, clientLeader, w))
2264
PrivateWindow::validSiblingBelow (CompWindow *w,
2265
CompWindow *sibling)
2267
Window clientLeader = w->priv->clientLeader;
2268
unsigned int type = w->priv->type;
2270
/* normal stacking fullscreen windows with below state */
2271
if ((type & CompWindowTypeFullscreenMask) &&
2272
(w->priv->state & CompWindowStateBelowMask))
2273
type = CompWindowTypeNormalMask;
2275
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2276
clientLeader = None;
2278
if (sibling == w || avoidStackingRelativeTo (sibling))
2281
/* always above desktop windows */
2282
if (sibling->priv->type & CompWindowTypeDesktopMask)
2286
case CompWindowTypeDesktopMask:
2287
/* desktop window layer */
2289
case CompWindowTypeFullscreenMask:
2290
case CompWindowTypeDockMask:
2291
/* fullscreen and dock layer */
2292
if (sibling->priv->type & (CompWindowTypeFullscreenMask |
2293
CompWindowTypeDockMask))
2295
if (stackLayerCheck (w, clientLeader, sibling))
2304
/* fullscreen and normal layer */
2305
if (!(sibling->priv->type & CompWindowTypeDockMask))
2307
if (stackLayerCheck (w, clientLeader, sibling))
2317
PrivateWindow::saveGeometry (int mask)
2319
int m = mask & ~saveMask;
2321
/* only save geometry if window has been placed */
2326
saveWc.x = serverGeometry.x ();
2329
saveWc.y = serverGeometry.y ();
2332
saveWc.width = serverGeometry.width ();
2335
saveWc.height = serverGeometry.height ();
2337
if (m & CWBorderWidth)
2338
saveWc.border_width = serverGeometry.border ();
2344
PrivateWindow::restoreGeometry (XWindowChanges *xwc,
2347
int m = mask & saveMask;
2357
xwc->width = saveWc.width;
2359
/* This is not perfect but it works OK for now. If the saved width is
2360
the same as the current width then make it a little be smaller so
2361
the user can see that it changed and it also makes sure that
2362
windowResizeNotify is called and plugins are notified. */
2363
if (xwc->width == (int) serverGeometry.width ())
2373
xwc->height = saveWc.height;
2375
/* As above, if the saved height is the same as the current height
2376
then make it a little be smaller. */
2377
if (xwc->height == (int) serverGeometry.height ())
2385
if (m & CWBorderWidth)
2386
xwc->border_width = saveWc.border_width;
2394
PrivateWindow::reconfigureXWindow (unsigned int valueMask,
2395
XWindowChanges *xwc)
2397
if (valueMask & CWX)
2398
serverGeometry.setX (xwc->x);
2400
if (valueMask & CWY)
2401
serverGeometry.setY (xwc->y);
2403
if (valueMask & CWWidth)
2404
serverGeometry.setWidth (xwc->width);
2406
if (valueMask & CWHeight)
2407
serverGeometry.setHeight (xwc->height);
2409
if (valueMask & CWBorderWidth)
2410
serverGeometry.setBorder (xwc->border_width);
2412
/* Compiz's window list is immediately restacked on reconfigureXWindow
2413
in order to ensure correct operation of the raise, lower and restacking
2414
functions. This function should only recieve stack_mode == Above
2415
but warn incase something else does get through, to make the cause
2416
of any potential misbehaviour obvious. */
2417
if (valueMask & (CWSibling | CWStackMode))
2419
if (xwc->stack_mode == Above)
2420
restack (xwc->sibling);
2422
compLogMessage ("core", CompLogLevelWarn, "restack_mode not Above");
2427
XWindowChanges wc = *xwc;
2431
wc.width += input.left + input.right;
2432
wc.height += input.top + input.bottom;
2434
XConfigureWindow (screen->dpy (), frame, valueMask, &wc);
2435
valueMask &= ~(CWSibling | CWStackMode);
2437
xwc->x = input.left;
2439
XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc);
2445
XConfigureWindow (screen->dpy (), id, valueMask, xwc);
2449
PrivateWindow::stackTransients (CompWindow *w,
2451
XWindowChanges *xwc,
2452
CompWindowList &updateList)
2455
Window clientLeader = w->priv->clientLeader;
2457
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2458
clientLeader = None;
2460
for (t = screen->windows ().back (); t; t = t->prev)
2462
if (t == w || t == avoid)
2465
if (t->priv->transientFor == w->priv->id ||
2466
t->priv->isGroupTransient (clientLeader))
2468
if (w->priv->type & CompWindowTypeDockMask)
2469
if (!(t->priv->type & CompWindowTypeDockMask))
2472
if (!stackTransients (t, avoid, xwc, updateList))
2475
if (xwc->sibling == t->priv->id ||
2476
(t->priv->frame && xwc->sibling == t->priv->frame))
2479
if (t->priv->mapNum || t->priv->pendingMaps)
2480
updateList.push_back (t);
2488
PrivateWindow::stackAncestors (CompWindow *w,
2489
XWindowChanges *xwc,
2490
CompWindowList &updateList)
2492
CompWindow *transient = NULL;
2494
if (w->priv->transientFor)
2495
transient = screen->findWindow (w->priv->transientFor);
2498
xwc->sibling != transient->priv->id &&
2499
(!transient->priv->frame || xwc->sibling != transient->priv->frame))
2501
CompWindow *ancestor;
2503
ancestor = screen->findWindow (w->priv->transientFor);
2506
if (!stackTransients (ancestor, w, xwc, updateList))
2509
if (ancestor->priv->type & CompWindowTypeDesktopMask)
2512
if (ancestor->priv->type & CompWindowTypeDockMask)
2513
if (!(w->priv->type & CompWindowTypeDockMask))
2516
if (ancestor->priv->mapNum || ancestor->priv->pendingMaps)
2517
updateList.push_back (ancestor);
2519
stackAncestors (ancestor, xwc, updateList);
2522
else if (w->priv->isGroupTransient (w->priv->clientLeader))
2526
for (a = screen->windows ().back (); a; a = a->prev)
2528
if (a->priv->clientLeader == w->priv->clientLeader &&
2529
a->priv->transientFor == None &&
2530
!a->priv->isGroupTransient (w->priv->clientLeader))
2532
if (xwc->sibling == a->priv->id ||
2533
(a->priv->frame && xwc->sibling == a->priv->frame))
2536
if (!stackTransients (a, w, xwc, updateList))
2539
if (a->priv->type & CompWindowTypeDesktopMask)
2542
if (a->priv->type & CompWindowTypeDockMask)
2543
if (!(w->priv->type & CompWindowTypeDockMask))
2546
if (a->priv->mapNum || a->priv->pendingMaps)
2547
updateList.push_back (a);
2554
CompWindow::configureXWindow (unsigned int valueMask,
2555
XWindowChanges *xwc)
2557
if (priv->managed && (valueMask & (CWSibling | CWStackMode)))
2559
CompWindowList transients;
2560
CompWindowList ancestors;
2562
/* Since the window list is being reordered in reconfigureXWindow
2563
the list of windows which need to be restacked must be stored
2564
first. The windows are stacked in the opposite order than they
2565
were previously stacked, in order that they are above xwc->sibling
2566
so that when compiz gets the ConfigureNotify event it doesn't
2567
have to restack all the windows again. */
2569
/* transient children above */
2570
if (PrivateWindow::stackTransients (this, NULL, xwc, transients))
2572
/* ancestors, siblings and sibling transients below */
2573
PrivateWindow::stackAncestors (this, xwc, ancestors);
2575
for (CompWindowList::reverse_iterator w = ancestors.rbegin ();
2576
w != ancestors.rend (); w++)
2578
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
2579
xwc->sibling = ROOTPARENT (*w);
2582
this->priv->reconfigureXWindow (valueMask, xwc);
2583
xwc->sibling = ROOTPARENT (this);
2585
for (CompWindowList::reverse_iterator w = transients.rbegin ();
2586
w != transients.rend (); w++)
2588
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
2589
xwc->sibling = ROOTPARENT (*w);
2595
priv->reconfigureXWindow (valueMask, xwc);
2600
PrivateWindow::addWindowSizeChanges (XWindowChanges *xwc,
2601
CompWindow::Geometry old)
2609
screen->viewportForGeometry (old, viewport);
2611
x = (viewport.x () - screen->vp ().x ()) * screen->width ();
2612
y = (viewport.y () - screen->vp ().y ()) * screen->height ();
2614
output = screen->outputDeviceForGeometry (old);
2615
workArea = screen->getWorkareaForOutput (output);
2617
if (type & CompWindowTypeFullscreenMask)
2619
saveGeometry (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
2621
if (fullscreenMonitorsSet)
2623
xwc->x = x + fullscreenMonitorRect.x ();
2624
xwc->y = y + fullscreenMonitorRect.y ();
2625
xwc->width = fullscreenMonitorRect.width ();
2626
xwc->height = fullscreenMonitorRect.height ();
2630
xwc->x = x + screen->outputDevs ()[output].x ();
2631
xwc->y = y + screen->outputDevs ()[output].y ();
2632
xwc->width = screen->outputDevs ()[output].width ();
2633
xwc->height = screen->outputDevs ()[output].height ();
2636
xwc->border_width = 0;
2638
mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
2642
mask |= restoreGeometry (xwc, CWBorderWidth);
2644
if (state & CompWindowStateMaximizedVertMask)
2646
saveGeometry (CWY | CWHeight);
2648
xwc->height = workArea.height () - input.top -
2649
input.bottom - old.border () * 2;
2655
mask |= restoreGeometry (xwc, CWY | CWHeight);
2658
if (state & CompWindowStateMaximizedHorzMask)
2660
saveGeometry (CWX | CWWidth);
2662
xwc->width = workArea.width () - input.left -
2663
input.right - old.border () * 2;
2669
mask |= restoreGeometry (xwc, CWX | CWWidth);
2672
/* constrain window width if smaller than minimum width */
2673
if (!(mask & CWWidth) && (int) old.width () < sizeHints.min_width)
2675
xwc->width = sizeHints.min_width;
2679
/* constrain window width if greater than maximum width */
2680
if (!(mask & CWWidth) && (int) old.width () > sizeHints.max_width)
2682
xwc->width = sizeHints.max_width;
2686
/* constrain window height if smaller than minimum height */
2687
if (!(mask & CWHeight) && (int) old.height () < sizeHints.min_height)
2689
xwc->height = sizeHints.min_height;
2693
/* constrain window height if greater than maximum height */
2694
if (!(mask & CWHeight) && (int) old.height () > sizeHints.max_height)
2696
xwc->height = sizeHints.max_height;
2700
if (mask & (CWWidth | CWHeight))
2702
int width, height, max;
2704
width = (mask & CWWidth) ? xwc->width : old.width ();
2705
height = (mask & CWHeight) ? xwc->height : old.height ();
2707
xwc->width = old.width ();
2708
xwc->height = old.height ();
2710
window->constrainNewWindowSize (width, height, &width, &height);
2712
if (width != (int) old.width ())
2720
if (height != (int) old.height ())
2723
xwc->height = height;
2728
if (state & CompWindowStateMaximizedVertMask)
2730
if (old.y () < y + workArea.y () + input.top)
2732
xwc->y = y + workArea.y () + input.top;
2737
height = xwc->height + old.border () * 2;
2739
max = y + workArea.bottom ();
2740
if (old.y () + (int) old.height () + input.bottom > max)
2742
xwc->y = max - height - input.bottom;
2745
else if (old.y () + height + input.bottom > max)
2747
xwc->y = y + workArea.y () +
2748
(workArea.height () - input.top - height -
2749
input.bottom) / 2 + input.top;
2755
if (state & CompWindowStateMaximizedHorzMask)
2757
if (old.x () < x + workArea.x () + input.left)
2759
xwc->x = x + workArea.x () + input.left;
2764
width = xwc->width + old.border () * 2;
2766
max = x + workArea.right ();
2767
if (old.x () + (int) old.width () + input.right > max)
2769
xwc->x = max - width - input.right;
2772
else if (old.x () + width + input.right > max)
2774
xwc->x = x + workArea.x () +
2775
(workArea.width () - input.left - width -
2776
input.right) / 2 + input.left;
2784
if ((mask & CWX) && (xwc->x == old.x ()))
2787
if ((mask & CWY) && (xwc->y == old.y ()))
2790
if ((mask & CWWidth) && (xwc->width == (int) old.width ()))
2793
if ((mask & CWHeight) && (xwc->height == (int) old.height ()))
2800
PrivateWindow::adjustConfigureRequestForGravity (XWindowChanges *xwc,
2806
unsigned int mask = 0;
2811
if (xwcm & (CWX | CWWidth))
2814
case NorthWestGravity:
2816
case SouthWestGravity:
2818
newX += priv->input.left * direction;
2825
newX -= (xwc->width / 2 - priv->input.left +
2826
(priv->input.left + priv->input.right) / 2) * direction;
2828
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
2831
case NorthEastGravity:
2833
case SouthEastGravity:
2835
newX -= xwc->width + priv->input.right * direction;
2837
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
2846
if (xwcm & (CWY | CWHeight))
2849
case NorthWestGravity:
2851
case NorthEastGravity:
2853
newY = xwc->y + priv->input.top * direction;
2860
newY -= (xwc->height / 2 - priv->input.top +
2861
(priv->input.top + priv->input.bottom) / 2) * direction;
2863
newY -= ((xwc->height - priv->serverGeometry.height ()) / 2) * direction;
2866
case SouthWestGravity:
2868
case SouthEastGravity:
2870
newY -= xwc->height + priv->input.bottom * direction;
2872
newY -= (xwc->height - priv->serverGeometry.height ()) * direction;
2883
xwc->x += (newX - xwc->x);
2889
xwc->y += (newY - xwc->y);
2897
CompWindow::moveResize (XWindowChanges *xwc,
2900
unsigned int source)
2902
bool placed = false;
2904
xwcm &= (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
2906
if (xwcm & (CWX | CWY))
2907
if (priv->sizeHints.flags & (USPosition | PPosition))
2911
gravity = priv->sizeHints.win_gravity;
2914
xwc->x = priv->serverGeometry.x ();
2916
xwc->y = priv->serverGeometry.y ();
2917
if (!(xwcm & CWWidth))
2918
xwc->width = priv->serverGeometry.width ();
2919
if (!(xwcm & CWHeight))
2920
xwc->height = priv->serverGeometry.height ();
2922
if (xwcm & (CWWidth | CWHeight))
2926
if (constrainNewWindowSize (xwc->width, xwc->height, &width, &height))
2928
if (width != xwc->width)
2931
if (height != xwc->height)
2935
xwc->height = height;
2939
xwcm |= priv->adjustConfigureRequestForGravity (xwc, xwcm, gravity, 1);
2941
validateResizeRequest (xwcm, xwc, source);
2943
/* when horizontally maximized only allow width changes added by
2944
addWindowSizeChanges */
2945
if (priv->state & CompWindowStateMaximizedHorzMask)
2948
/* when vertically maximized only allow height changes added by
2949
addWindowSizeChanges */
2950
if (priv->state & CompWindowStateMaximizedVertMask)
2953
xwcm |= priv->addWindowSizeChanges (xwc, Geometry (xwc->x, xwc->y,
2954
xwc->width, xwc->height,
2955
xwc->border_width));
2957
/* check if the new coordinates are useful and valid (different
2958
to current size); if not, we have to clear them to make sure
2959
we send a synthetic ConfigureNotify event if all coordinates
2960
match the server coordinates */
2961
if (xwc->x == priv->serverGeometry.x ())
2964
if (xwc->y == priv->serverGeometry.y ())
2967
if (xwc->width == (int) priv->serverGeometry.width ())
2970
if (xwc->height == (int) priv->serverGeometry.height ())
2973
if (xwc->border_width == (int) priv->serverGeometry.border ())
2974
xwcm &= ~CWBorderWidth;
2976
/* update saved window coordinates - if CWX or CWY is set for fullscreen
2977
or maximized windows after addWindowSizeChanges, it should be pretty
2978
safe to assume that the saved coordinates should be updated too, e.g.
2979
because the window was moved to another viewport by some client */
2980
if ((xwcm & CWX) && (priv->saveMask & CWX))
2981
priv->saveWc.x += (xwc->x - priv->serverGeometry.x ());
2983
if ((xwcm & CWY) && (priv->saveMask & CWY))
2984
priv->saveWc.y += (xwc->y - priv->serverGeometry.y ());
2986
if (priv->mapNum && (xwcm & (CWWidth | CWHeight)))
2990
configureXWindow (xwcm, xwc);
2993
/* we have to send a configure notify on ConfigureRequest events if
2994
we decide not to do anything according to ICCCM 4.1.5 */
2995
sendConfigureNotify ();
2999
priv->placed = true;
3003
PrivateWindow::updateSize ()
3008
if (window->overrideRedirect () || !managed)
3011
mask = priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
3014
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
3015
window->sendSyncRequest ();
3017
window->configureXWindow (mask, &xwc);
3022
PrivateWindow::addWindowStackChanges (XWindowChanges *xwc,
3023
CompWindow *sibling)
3027
if (!sibling || sibling->priv->id != id)
3033
XLowerWindow (screen->dpy (), id);
3035
XLowerWindow (screen->dpy (), frame);
3037
/* Restacking of compiz's window list happens
3038
immediately and since this path doesn't call
3039
reconfigureXWindow, restack must be called here. */
3042
else if (sibling->priv->id != window->prev->priv->id)
3044
mask |= CWSibling | CWStackMode;
3046
xwc->stack_mode = Above;
3047
xwc->sibling = ROOTPARENT (sibling);
3052
mask |= CWSibling | CWStackMode;
3054
xwc->stack_mode = Above;
3055
xwc->sibling = ROOTPARENT (sibling);
3059
if (sibling && mask)
3061
/* a normal window can be stacked above fullscreen windows but we
3062
don't want normal windows to be stacked above dock window so if
3063
the sibling we're stacking above is a fullscreen window we also
3064
update all dock windows. */
3065
if ((sibling->priv->type & CompWindowTypeFullscreenMask) &&
3066
(!(type & (CompWindowTypeFullscreenMask |
3067
CompWindowTypeDockMask))) &&
3068
!isAncestorTo (window, sibling))
3072
for (dw = screen->windows ().back (); dw; dw = dw->prev)
3076
/* Collect all dock windows first */
3077
CompWindowList dockWindows;
3078
for (; dw; dw = dw->prev)
3079
if (dw->priv->type & CompWindowTypeDockMask)
3080
dockWindows.push_back (dw);
3082
/* Then update the dock windows */
3083
foreach (CompWindow *dw, dockWindows)
3084
dw->configureXWindow (mask, xwc);
3092
CompWindow::raise ()
3096
bool aboveFs = false;
3098
/* an active fullscreen window should be raised over all other
3099
windows in its layer */
3100
if (priv->type & CompWindowTypeFullscreenMask)
3101
if (priv->id == screen->activeWindow ())
3104
mask = priv->addWindowStackChanges (&xwc,
3105
PrivateWindow::findSiblingBelow (this, aboveFs));
3108
configureXWindow (mask, &xwc);
3112
PrivateScreen::focusTopMostWindow ()
3114
CompWindow *focus = NULL;
3115
CompWindowList::reverse_iterator it = windows.rbegin ();
3117
for (; it != windows.rend (); it++)
3119
CompWindow *w = *it;
3121
if (w->type () & CompWindowTypeDockMask)
3133
if (focus->id () != activeWindow)
3134
focus->moveInputFocusTo ();
3137
XSetInputFocus (dpy, root, RevertToPointerRoot,
3144
CompWindow::lower ()
3149
mask = priv->addWindowStackChanges (&xwc,
3150
PrivateWindow::findLowestSiblingBelow (this));
3152
configureXWindow (mask, &xwc);
3154
/* when lowering a window, focus the topmost window if
3155
the click-to-focus option is on */
3156
if ((screen->priv->optionGetClickToFocus ()))
3158
Window aboveWindowId = prev ? prev->id () : None;
3159
screen->unhookWindow (this);
3160
CompWindow *focusedWindow = screen->priv->focusTopMostWindow ();
3161
screen->insertWindow (this , aboveWindowId);
3163
/* if the newly focused window is a desktop window,
3164
give the focus back to w */
3165
if (focusedWindow &&
3166
focusedWindow->type () & CompWindowTypeDesktopMask)
3168
moveInputFocusTo ();
3174
CompWindow::restackAbove (CompWindow *sibling)
3176
for (; sibling; sibling = sibling->next)
3177
if (PrivateWindow::validSiblingBelow (this, sibling))
3185
mask = priv->addWindowStackChanges (&xwc, sibling);
3187
configureXWindow (mask, &xwc);
3191
/* finds the highest window under sibling we can stack above */
3193
PrivateWindow::findValidStackSiblingBelow (CompWindow *w,
3194
CompWindow *sibling)
3196
CompWindow *lowest, *last, *p;
3198
/* check whether we're allowed to stack under a sibling by finding
3199
* the above 'sibling' and checking whether or not we're allowed
3200
* to stack under that - if not, then there is no valid sibling
3203
for (p = sibling; p; p = p->next)
3205
if (!avoidStackingRelativeTo (p))
3207
if (!validSiblingBelow (p, w))
3213
/* get lowest sibling we're allowed to stack above */
3214
lowest = last = findLowestSiblingBelow (w);
3216
/* walk from bottom up */
3217
for (p = screen->windows ().front (); p; p = p->next)
3219
/* stop walking when we reach the sibling we should try to stack
3224
/* skip windows that we should avoid */
3225
if (w == p || avoidStackingRelativeTo (p))
3228
if (validSiblingBelow (w, p))
3230
/* update lowest as we find windows below sibling that we're
3231
allowed to stack above. last window must be equal to the
3232
lowest as we shouldn't update lowest if we passed an
3238
/* update last pointer */
3246
CompWindow::restackBelow (CompWindow *sibling)
3251
mask = priv->addWindowStackChanges (&xwc,
3252
PrivateWindow::findValidStackSiblingBelow (this, sibling));
3255
configureXWindow (mask, &xwc);
3259
CompWindow::updateAttributes (CompStackingUpdateMode stackingMode)
3264
if (overrideRedirect () || !priv->managed)
3267
if (priv->state & CompWindowStateShadedMask)
3269
windowNotify (CompWindowNotifyShade);
3273
else if (priv->shaded)
3275
windowNotify (CompWindowNotifyUnshade);
3280
if (stackingMode != CompStackingUpdateModeNone)
3283
CompWindow *sibling;
3285
aboveFs = (stackingMode == CompStackingUpdateModeAboveFullscreen);
3286
if (priv->type & CompWindowTypeFullscreenMask)
3288
/* put active or soon-to-be-active fullscreen windows over
3289
all others in their layer */
3290
if (priv->id == screen->activeWindow ())
3296
/* put windows that are just mapped, over fullscreen windows */
3297
if (stackingMode == CompStackingUpdateModeInitialMap)
3300
sibling = PrivateWindow::findSiblingBelow (this, aboveFs);
3303
(stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
3307
for (p = sibling; p; p = p->prev)
3308
if (p->priv->id == screen->activeWindow ())
3311
/* window is above active window so we should lower it,
3312
* assuing that is allowed (if, for example, our window has
3313
* the "above" state, then lowering beneath the active
3314
* window may not be allowed). */
3315
if (p && PrivateWindow::validSiblingBelow (p, this))
3317
p = PrivateWindow::findValidStackSiblingBelow (sibling, p);
3319
/* if we found a valid sibling under the active window, it's
3320
our new sibling we want to stack above */
3326
mask |= priv->addWindowStackChanges (&xwc, sibling);
3329
if ((stackingMode == CompStackingUpdateModeInitialMap) ||
3330
(stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
3332
/* If we are called from the MapRequest handler, we have to
3333
immediately update the internal stack. If we don't do that,
3334
the internal stacking order is invalid until the ConfigureNotify
3335
arrives because we put the window at the top of the stack when
3337
if (mask & CWStackMode)
3339
Window above = (mask & CWSibling) ? xwc.sibling : 0;
3340
priv->restack (above);
3344
mask |= priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
3346
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
3350
configureXWindow (mask, &xwc);
3354
PrivateWindow::ensureWindowVisibility ()
3357
int width = serverGeometry.width () + serverGeometry.border () * 2;
3358
int height = serverGeometry.height () + serverGeometry.border () * 2;
3362
if (struts || attrib.override_redirect)
3365
if (type & (CompWindowTypeDockMask |
3366
CompWindowTypeFullscreenMask |
3367
CompWindowTypeUnknownMask))
3370
x1 = screen->workArea ().x () - screen->width () * screen->vp ().x ();
3371
y1 = screen->workArea ().y () - screen->height () * screen->vp ().y ();
3372
x2 = x1 + screen->workArea ().width () + screen->vpSize ().width () *
3374
y2 = y1 + screen->workArea ().height () + screen->vpSize ().height () *
3377
if (serverGeometry.x () - input.left >= x2)
3378
dx = (x2 - 25) - serverGeometry.x ();
3379
else if (serverGeometry.x () + width + input.right <= x1)
3380
dx = (x1 + 25) - (serverGeometry.x () + width);
3382
if (serverGeometry.y () - input.top >= y2)
3383
dy = (y2 - 25) - serverGeometry.y ();
3384
else if (serverGeometry.y () + height + input.bottom <= y1)
3385
dy = (y1 + 25) - (serverGeometry.y () + height);
3391
xwc.x = serverGeometry.x () + dx;
3392
xwc.y = serverGeometry.y () + dy;
3394
window->configureXWindow (CWX | CWY, &xwc);
3399
PrivateWindow::reveal ()
3401
if (window->minimized ())
3402
window->unminimize ();
3404
screen->leaveShowDesktopMode (window);
3408
PrivateWindow::revealAncestors (CompWindow *w,
3409
CompWindow *transient)
3411
if (isAncestorTo (transient, w))
3413
screen->forEachWindow (boost::bind (revealAncestors, _1, w));
3419
CompWindow::activate ()
3421
WRAPABLE_HND_FUNC (3, activate)
3423
screen->priv->setCurrentDesktop (priv->desktop);
3425
screen->forEachWindow (
3426
boost::bind (PrivateWindow::revealAncestors, _1, this));
3429
if (priv->state & CompWindowStateHiddenMask)
3431
priv->state &= ~CompWindowStateShadedMask;
3436
if (priv->state & CompWindowStateHiddenMask)
3439
if (!onCurrentDesktop ())
3442
priv->ensureWindowVisibility ();
3443
updateAttributes (CompStackingUpdateModeAboveFullscreen);
3444
moveInputFocusTo ();
3448
#define PVertResizeInc (1 << 0)
3449
#define PHorzResizeInc (1 << 1)
3452
CompWindow::constrainNewWindowSize (int width,
3457
const XSizeHints *hints = &priv->sizeHints;
3458
int oldWidth = width;
3459
int oldHeight = height;
3463
int base_height = 0;
3466
int max_width = MAXSHORT;
3467
int max_height = MAXSHORT;
3468
long flags = hints->flags;
3469
long resizeIncFlags = (flags & PResizeInc) ? ~0 : 0;
3471
if (screen->priv->optionGetIgnoreHintsWhenMaximized ())
3473
if (priv->state & MAXIMIZE_STATE)
3477
if (priv->state & CompWindowStateMaximizedHorzMask)
3478
resizeIncFlags &= ~PHorzResizeInc;
3480
if (priv->state & CompWindowStateMaximizedVertMask)
3481
resizeIncFlags &= ~PVertResizeInc;
3485
/* Ater gdk_window_constrain_size(), which is partially borrowed from fvwm.
3487
* Copyright 1993, Robert Nation
3488
* You may use this code for any purpose, as long as the original
3489
* copyright remains in the source code and all documentation
3491
* which in turn borrows parts of the algorithm from uwm
3494
#define FLOOR(value, base) (((int) ((value) / (base))) * (base))
3495
#define FLOOR64(value, base) (((uint64_t) ((value) / (base))) * (base))
3497
if ((flags & PBaseSize) && (flags & PMinSize))
3499
base_width = hints->base_width;
3500
base_height = hints->base_height;
3501
min_width = hints->min_width;
3502
min_height = hints->min_height;
3504
else if (flags & PBaseSize)
3506
base_width = hints->base_width;
3507
base_height = hints->base_height;
3508
min_width = hints->base_width;
3509
min_height = hints->base_height;
3511
else if (flags & PMinSize)
3513
base_width = hints->min_width;
3514
base_height = hints->min_height;
3515
min_width = hints->min_width;
3516
min_height = hints->min_height;
3519
if (flags & PMaxSize)
3521
max_width = hints->max_width;
3522
max_height = hints->max_height;
3525
if (resizeIncFlags & PHorzResizeInc)
3526
xinc = MAX (xinc, hints->width_inc);
3528
if (resizeIncFlags & PVertResizeInc)
3529
yinc = MAX (yinc, hints->height_inc);
3531
/* clamp width and height to min and max values */
3532
width = CLAMP (width, min_width, max_width);
3533
height = CLAMP (height, min_height, max_height);
3535
/* shrink to base + N * inc */
3536
width = base_width + FLOOR (width - base_width, xinc);
3537
height = base_height + FLOOR (height - base_height, yinc);
3539
/* constrain aspect ratio, according to:
3541
* min_aspect.x width max_aspect.x
3542
* ------------ <= -------- <= -----------
3543
* min_aspect.y height max_aspect.y
3545
if ((flags & PAspect) && hints->min_aspect.y > 0 && hints->max_aspect.x > 0)
3547
/* Use 64 bit arithmetic to prevent overflow */
3549
uint64_t min_aspect_x = hints->min_aspect.x;
3550
uint64_t min_aspect_y = hints->min_aspect.y;
3551
uint64_t max_aspect_x = hints->max_aspect.x;
3552
uint64_t max_aspect_y = hints->max_aspect.y;
3555
if (min_aspect_x * height > width * min_aspect_y)
3557
delta = FLOOR64 (height - width * min_aspect_y / min_aspect_x,
3559
if (height - (int) delta >= min_height)
3563
delta = FLOOR64 (height * min_aspect_x / min_aspect_y - width,
3565
if (width + (int) delta <= max_width)
3570
if (width * max_aspect_y > max_aspect_x * height)
3572
delta = FLOOR64 (width - height * max_aspect_x / max_aspect_y,
3574
if (width - (int) delta >= min_width)
3578
delta = FLOOR64 (width * min_aspect_y / min_aspect_x - height,
3580
if (height + (int) delta <= max_height)
3590
if (width != oldWidth || height != oldHeight)
3593
*newHeight = height;
3604
priv->hidden = true;
3611
priv->hidden = false;
3616
PrivateWindow::hide ()
3618
bool onDesktop = window->onCurrentDesktop ();
3623
if (!window->minimized () && !inShowDesktopMode &&
3624
!hidden && onDesktop)
3626
if (state & CompWindowStateShadedMask)
3639
if ((state & CompWindowStateShadedMask) && frame)
3640
XUnmapWindow (screen->dpy (), frame);
3643
if (!pendingMaps && !window->isViewable ())
3646
window->windowNotify (CompWindowNotifyHide);
3650
if (frame && !shaded)
3651
XUnmapWindow (screen->dpy (), frame);
3653
XUnmapWindow (screen->dpy (), id);
3655
if (window->minimized () || inShowDesktopMode || hidden || shaded)
3656
window->changeState (state | CompWindowStateHiddenMask);
3658
if (shaded && id == screen->activeWindow ())
3659
window->moveInputFocusTo ();
3663
PrivateWindow::show ()
3665
bool onDesktop = window->onCurrentDesktop ();
3670
if (minimized || inShowDesktopMode ||
3671
hidden || !onDesktop)
3673
/* no longer hidden but not on current desktop */
3674
if (!minimized && !inShowDesktopMode && !hidden)
3675
window->changeState (state & ~CompWindowStateHiddenMask);
3680
/* transition from minimized to shaded */
3681
if (state & CompWindowStateShadedMask)
3686
XMapWindow (screen->dpy (), frame);
3689
window->resize (attrib.x, attrib.y,
3690
attrib.width, ++attrib.height - 1,
3691
attrib.border_width);
3700
window->windowNotify (CompWindowNotifyShow);
3706
XMapWindow (screen->dpy (), frame);
3707
XMapWindow (screen->dpy (), wrapper);
3710
XMapWindow (screen->dpy (), id);
3712
window->changeState (state & ~CompWindowStateHiddenMask);
3713
screen->priv->setWindowState (state, id);
3717
PrivateWindow::minimizeTransients (CompWindow *w,
3718
CompWindow *ancestor)
3720
if (w->priv->transientFor == ancestor->priv->id ||
3721
w->priv->isGroupTransient (ancestor->priv->clientLeader))
3728
CompWindow::minimize ()
3730
WRAPABLE_HND_FUNC (13, minimize);
3735
if (!priv->minimized)
3737
windowNotify (CompWindowNotifyMinimize);
3739
priv->minimized = true;
3741
screen->forEachWindow (
3742
boost::bind (PrivateWindow::minimizeTransients, _1, this));
3749
PrivateWindow::unminimizeTransients (CompWindow *w,
3750
CompWindow *ancestor)
3752
if (w->priv->transientFor == ancestor->priv->id ||
3753
w->priv->isGroupTransient (ancestor->priv->clientLeader))
3758
CompWindow::unminimize ()
3760
WRAPABLE_HND_FUNC (14, unminimize);
3761
if (priv->minimized)
3763
windowNotify (CompWindowNotifyUnminimize);
3765
priv->minimized = false;
3769
screen->forEachWindow (
3770
boost::bind (PrivateWindow::unminimizeTransients, _1, this));
3775
CompWindow::maximize (unsigned int state)
3777
if (overrideRedirect ())
3780
state = constrainWindowState (state, priv->actions);
3782
state &= MAXIMIZE_STATE;
3784
if (state == (priv->state & MAXIMIZE_STATE))
3787
state |= (priv->state & ~MAXIMIZE_STATE);
3789
changeState (state);
3790
updateAttributes (CompStackingUpdateModeNone);
3794
PrivateWindow::getUserTime (Time& time)
3798
unsigned long n, left;
3799
unsigned char *data;
3800
bool retval = false;
3802
result = XGetWindowProperty (screen->dpy (), priv->id,
3804
0L, 1L, False, XA_CARDINAL, &actual, &format,
3807
if (result == Success && data)
3813
memcpy (&value, data, sizeof (CARD32));
3815
time = (Time) value;
3818
XFree ((void *) data);
3825
PrivateWindow::setUserTime (Time time)
3827
CARD32 value = (CARD32) time;
3829
XChangeProperty (screen->dpy (), priv->id,
3831
XA_CARDINAL, 32, PropModeReplace,
3832
(unsigned char *) &value, 1);
3836
* Macros from metacity
3838
* Xserver time can wraparound, thus comparing two timestamps needs to
3839
* take this into account. Here's a little macro to help out. If no
3840
* wraparound has occurred, this is equivalent to
3842
* Of course, the rest of the ugliness of this macro comes from
3843
* accounting for the fact that wraparound can occur and the fact that
3844
* a timestamp of 0 must be special-cased since it means older than
3847
* Note that this is NOT an equivalent for time1 <= time2; if that's
3848
* what you need then you'll need to swap the order of the arguments
3849
* and negate the result.
3851
#define XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) \
3852
( (( (time1) < (time2) ) && \
3853
( (time2) - (time1) < ((unsigned long) -1) / 2 )) || \
3854
(( (time1) > (time2) ) && \
3855
( (time1) - (time2) > ((unsigned long) -1) / 2 )) \
3857
#define XSERVER_TIME_IS_BEFORE(time1, time2) \
3859
(XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS (time1, time2) && \
3864
PrivateWindow::getUsageTimestamp (Time& timestamp)
3866
if (getUserTime (timestamp))
3869
if (initialTimestampSet)
3871
timestamp = initialTimestamp;
3879
PrivateWindow::isWindowFocusAllowed (Time timestamp)
3881
CompScreen *s = screen;
3883
Time wUserTime, aUserTime;
3884
bool gotTimestamp = false;
3888
level = s->priv->optionGetFocusPreventionLevel ();
3890
if (level == CoreOptions::FocusPreventionLevelOff)
3895
/* the caller passed a timestamp, so use that
3896
instead of the window's user time */
3897
wUserTime = timestamp;
3898
gotTimestamp = true;
3902
gotTimestamp = getUsageTimestamp (wUserTime);
3905
/* if we got no timestamp for the window, try to get at least a timestamp
3906
for its transient parent, if any */
3907
if (!gotTimestamp && transientFor)
3911
parent = screen->findWindow (transientFor);
3913
gotTimestamp = parent->priv->getUsageTimestamp (wUserTime);
3916
if (gotTimestamp && !wUserTime)
3918
/* window explicitly requested no focus */
3922
/* allow focus for excluded windows */
3923
CompMatch &match = s->priv->optionGetFocusPreventionMatch ();
3924
if (!match.evaluate (window))
3927
if (level == CoreOptions::FocusPreventionLevelVeryHigh)
3930
active = s->findWindow (s->activeWindow ());
3932
/* no active window */
3933
if (!active || (active->type () & CompWindowTypeDesktopMask))
3936
/* active window belongs to same application */
3937
if (window->clientLeader () == active->clientLeader ())
3940
if (level == CoreOptions::FocusPreventionLevelHigh)
3943
/* not in current viewport or desktop */
3944
if (!window->onCurrentDesktop ())
3947
dvp = window->defaultViewport ();
3948
if (dvp.x () != s->vp ().x () || dvp.y () != s->vp ().y ())
3953
/* unsure as we have nothing to compare - allow focus in low level,
3954
don't allow in normal level */
3955
if (level == CoreOptions::FocusPreventionLevelNormal)
3961
/* can't get user time for active window */
3962
if (!active->priv->getUserTime (aUserTime))
3965
if (XSERVER_TIME_IS_BEFORE (wUserTime, aUserTime))
3972
PrivateWindow::allowWindowFocus (unsigned int noFocusMask,
3977
if (priv->id == screen->activeWindow ())
3980
/* do not focus windows of these types */
3981
if (priv->type & noFocusMask)
3984
/* window doesn't take focus */
3985
if (!priv->inputHint &&
3986
!(priv->protocols & CompWindowProtocolTakeFocusMask))
3991
retval = priv->isWindowFocusAllowed (timestamp);
3994
/* add demands attention state if focus was prevented */
3995
window->changeState (priv->state | CompWindowStateDemandsAttentionMask);
4002
CompWindow::defaultViewport ()
4006
if (priv->serverGeometry.x () < (int) screen->width () &&
4007
priv->serverGeometry.x () + priv->serverGeometry.width () > 0 &&
4008
priv->serverGeometry.y () < (int) screen->height () &&
4009
priv->serverGeometry.y ()+ priv->serverGeometry.height () > 0)
4011
return screen->vp ();
4014
screen->viewportForGeometry (priv->serverGeometry, viewport);
4020
CompWindow::initialViewport () const
4022
return priv->initialViewport;
4026
PrivateWindow::readIconHint ()
4028
XImage *image, *maskImage = NULL;
4029
Display *dpy = screen->dpy ();
4030
unsigned int width, height, dummy;
4031
unsigned int i, j, k;
4038
if (!XGetGeometry (dpy, hints->icon_pixmap, &wDummy, &iDummy,
4039
&iDummy, &width, &height, &dummy, &dummy))
4042
image = XGetImage (dpy, hints->icon_pixmap, 0, 0, width, height,
4043
AllPlanes, ZPixmap);
4047
colors = new XColor[width * height];
4050
XDestroyImage (image);
4055
for (j = 0; j < height; j++)
4056
for (i = 0; i < width; i++)
4057
colors[k++].pixel = XGetPixel (image, i, j);
4059
for (i = 0; i < k; i += 256)
4060
XQueryColors (dpy, screen->priv->colormap,
4061
&colors[i], MIN (k - i, 256));
4063
XDestroyImage (image);
4065
icon = new CompIcon (screen, width, height);
4072
if (hints->flags & IconMaskHint)
4073
maskImage = XGetImage (dpy, hints->icon_mask, 0, 0,
4074
width, height, AllPlanes, ZPixmap);
4077
p = (CARD32 *) icon->data ();
4079
for (j = 0; j < height; j++)
4081
for (i = 0; i < width; i++)
4083
if (maskImage && !XGetPixel (maskImage, i, j))
4085
else if (image->depth == 1) /* white : black */
4086
*p++ = colors[k].pixel ? 0xffffffff : 0xff000000;
4088
*p++ = 0xff000000 | /* alpha */
4089
(((colors[k].red >> 8) & 0xff) << 16) | /* red */
4090
(((colors[k].green >> 8) & 0xff) << 8) | /* green */
4091
((colors[k].blue >> 8) & 0xff); /* blue */
4099
XDestroyImage (maskImage);
4101
icons.push_back (icon);
4104
/* returns icon with dimensions as close as possible to width and height
4105
but never greater. */
4107
CompWindow::getIcon (int width,
4111
int wh, diff, oldDiff;
4114
/* need to fetch icon property */
4115
if (priv->icons.size () == 0 && !priv->noIcons)
4119
unsigned long n, left;
4120
unsigned char *data;
4122
result = XGetWindowProperty (screen->dpy (), priv->id, Atoms::wmIcon,
4123
0L, 65536L, false, XA_CARDINAL,
4124
&actual, &format, &n, &left, &data);
4126
if (result == Success && data)
4129
CARD32 alpha, red, green, blue;
4130
unsigned long iw, ih;
4132
for (i = 0; i + 2 < n; i += iw * ih + 2)
4134
unsigned long *idata = (unsigned long *) data;
4139
/* iw * ih may be larger than the value range of unsigned
4140
* long, so better do some checking for extremely weird
4141
* icon sizes first */
4142
if (iw > 2048 || ih > 2048 || iw * ih + 2 > n - i)
4148
icon = new CompIcon (screen, iw, ih);
4152
priv->icons.push_back (icon);
4154
p = (CARD32 *) (icon->data ());
4156
/* EWMH doesn't say if icon data is premultiplied or
4157
not but most applications seem to assume data should
4158
be unpremultiplied. */
4159
for (j = 0; j < iw * ih; j++)
4161
alpha = (idata[i + j + 2] >> 24) & 0xff;
4162
red = (idata[i + j + 2] >> 16) & 0xff;
4163
green = (idata[i + j + 2] >> 8) & 0xff;
4164
blue = (idata[i + j + 2] >> 0) & 0xff;
4166
red = (red * alpha) >> 8;
4167
green = (green * alpha) >> 8;
4168
blue = (blue * alpha) >> 8;
4181
else if (priv->hints && (priv->hints->flags & IconPixmapHint))
4183
priv->readIconHint ();
4186
/* don't fetch property again */
4187
if (priv->icons.size () == 0)
4188
priv->noIcons = true;
4191
/* no icons available for this window */
4196
wh = width + height;
4198
for (i = 0; i < priv->icons.size (); i++)
4200
const CompSize iconSize = *priv->icons[i];
4202
if ((int) iconSize.width () > width ||
4203
(int) iconSize.height () > height)
4208
diff = wh - (iconSize.width () + iconSize.height ());
4209
oldDiff = wh - (icon->width () + icon->height ());
4212
icon = priv->icons[i];
4215
icon = priv->icons[i];
4222
CompWindow::iconGeometry () const
4224
return priv->iconGeometry;
4228
PrivateWindow::freeIcons ()
4230
for (unsigned int i = 0; i < priv->icons.size (); i++)
4231
delete priv->icons[i];
4233
priv->icons.resize (0);
4234
priv->noIcons = false;
4238
CompWindow::outputDevice ()
4240
return screen->outputDeviceForGeometry (priv->serverGeometry);
4244
CompWindow::onCurrentDesktop ()
4246
if (priv->desktop == 0xffffffff ||
4247
priv->desktop == screen->currentDesktop ())
4256
CompWindow::setDesktop (unsigned int desktop)
4258
if (desktop != 0xffffffff)
4260
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
4263
if (desktop >= screen->nDesktop ())
4267
if (desktop == priv->desktop)
4270
priv->desktop = desktop;
4272
if (desktop == 0xffffffff || desktop == screen->currentDesktop ())
4277
screen->setWindowProp (priv->id, Atoms::winDesktop, priv->desktop);
4280
/* The compareWindowActiveness function compares the two windows 'w1'
4281
and 'w2'. It returns an integer less than, equal to, or greater
4282
than zero if 'w1' is found, respectively, to activated longer time
4283
ago than, to be activated at the same time, or be activated more
4284
recently than 'w2'. */
4286
PrivateWindow::compareWindowActiveness (CompWindow *w1,
4289
CompActiveWindowHistory *history = screen->currentHistory ();
4292
/* check current window history first */
4293
for (i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
4295
if (history->id[i] == w1->priv->id)
4298
if (history->id[i] == w2->priv->id)
4301
if (!history->id[i])
4305
return w1->priv->activeNum - w2->priv->activeNum;
4309
CompWindow::onAllViewports ()
4311
if (overrideRedirect ())
4314
if (!priv->managed && !isViewable ())
4317
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
4320
if (priv->state & CompWindowStateStickyMask)
4327
CompWindow::getMovementForOffset (CompPoint offset)
4329
CompScreen *s = screen;
4330
int m, vWidth, vHeight;
4331
int offX = offset.x (), offY = offset.y ();
4334
vWidth = s->width () * s->vpSize ().width ();
4335
vHeight = s->height () * s->vpSize ().height ();
4341
if (s->vpSize ().width () == 1)
4347
m = priv->attrib.x + offX;
4348
if (m - priv->input.left < (int) s->width () - vWidth)
4349
rv.setX (offX + vWidth);
4350
else if (m + priv->width + priv->input.right > vWidth)
4351
rv.setX (offX - vWidth);
4356
if (s->vpSize ().height () == 1)
4362
m = priv->attrib.y + offY;
4363
if (m - priv->input.top < (int) s->height () - vHeight)
4364
rv.setY (offY + vHeight);
4365
else if (m + priv->height + priv->input.bottom > vHeight)
4366
rv.setY (offY - vHeight);
4375
WindowInterface::getOutputExtents (CompWindowExtents& output)
4376
WRAPABLE_DEF (getOutputExtents, output)
4379
WindowInterface::getAllowedActions (unsigned int &setActions,
4380
unsigned int &clearActions)
4381
WRAPABLE_DEF (getAllowedActions, setActions, clearActions)
4384
WindowInterface::focus ()
4385
WRAPABLE_DEF (focus)
4388
WindowInterface::activate ()
4389
WRAPABLE_DEF (activate)
4392
WindowInterface::place (CompPoint &pos)
4393
WRAPABLE_DEF (place, pos)
4396
WindowInterface::validateResizeRequest (unsigned int &mask,
4397
XWindowChanges *xwc,
4398
unsigned int source)
4399
WRAPABLE_DEF (validateResizeRequest, mask, xwc, source)
4402
WindowInterface::resizeNotify (int dx,
4406
WRAPABLE_DEF (resizeNotify, dx, dy, dwidth, dheight)
4409
WindowInterface::moveNotify (int dx,
4412
WRAPABLE_DEF (moveNotify, dx, dy, immediate)
4415
WindowInterface::windowNotify (CompWindowNotify n)
4416
WRAPABLE_DEF (windowNotify, n)
4419
WindowInterface::grabNotify (int x,
4423
WRAPABLE_DEF (grabNotify, x, y, state, mask)
4426
WindowInterface::ungrabNotify ()
4427
WRAPABLE_DEF (ungrabNotify)
4430
WindowInterface::stateChangeNotify (unsigned int lastState)
4431
WRAPABLE_DEF (stateChangeNotify, lastState)
4434
WindowInterface::updateFrameRegion (CompRegion ®ion)
4435
WRAPABLE_DEF (updateFrameRegion, region)
4438
WindowInterface::minimize ()
4439
WRAPABLE_DEF (minimize);
4442
WindowInterface::unminimize ()
4443
WRAPABLE_DEF (unminimize);
4446
WindowInterface::minimized ()
4447
WRAPABLE_DEF (minimized);
4450
WindowInterface::alpha ()
4451
WRAPABLE_DEF (alpha);
4454
WindowInterface::isFocussable ()
4455
WRAPABLE_DEF (isFocussable);
4458
WindowInterface::managed ()
4459
WRAPABLE_DEF (managed);
4474
CompWindow::state ()
4480
CompWindow::actions ()
4482
return priv->actions;
4486
CompWindow::protocols ()
4488
return priv->protocols;
4492
CompWindow::close (Time serverTime)
4494
if (serverTime == 0)
4495
serverTime = screen->getCurrentTime ();
4499
if (priv->protocols & CompWindowProtocolDeleteMask)
4503
ev.type = ClientMessage;
4504
ev.xclient.window = priv->id;
4505
ev.xclient.message_type = Atoms::wmProtocols;
4506
ev.xclient.format = 32;
4507
ev.xclient.data.l[0] = Atoms::wmDeleteWindow;
4508
ev.xclient.data.l[1] = serverTime;
4509
ev.xclient.data.l[2] = 0;
4510
ev.xclient.data.l[3] = 0;
4511
ev.xclient.data.l[4] = 0;
4513
XSendEvent (screen->dpy (), priv->id, false, NoEventMask, &ev);
4517
XKillClient (screen->dpy (), priv->id);
4520
priv->closeRequests++;
4524
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
4525
serverTime, priv->id, true, 0, 0);
4528
priv->lastCloseRequestTime = serverTime;
4532
PrivateWindow::handlePingTimeout (unsigned int lastPing)
4534
if (!window->isViewable ())
4537
if (!(priv->type & CompWindowTypeNormalMask))
4540
if (priv->protocols & CompWindowProtocolPingMask)
4542
if (priv->transientFor)
4545
if (priv->lastPong < lastPing)
4549
priv->alive = false;
4551
window->windowNotify (CompWindowNotifyAliveChanged);
4553
if (priv->closeRequests)
4555
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
4556
priv->lastCloseRequestTime,
4557
priv->id, true, 0, 0);
4559
priv->closeRequests = 0;
4570
PrivateWindow::handlePing (int lastPing)
4576
window->windowNotify (CompWindowNotifyAliveChanged);
4578
if (priv->lastCloseRequestTime)
4580
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
4581
priv->lastCloseRequestTime,
4582
priv->id, false, 0, 0);
4584
priv->lastCloseRequestTime = 0;
4587
priv->lastPong = lastPing;
4591
PrivateWindow::processMap ()
4594
CompStackingUpdateMode stackingMode;
4596
priv->initialViewport = screen->vp ();
4598
priv->initialTimestampSet = false;
4600
screen->priv->applyStartupProperties (window);
4604
priv->managed = true;
4608
int gravity = priv->sizeHints.win_gravity;
4612
/* adjust for gravity, but only for frame size */
4613
xwc.x = priv->serverGeometry.x ();
4614
xwc.y = priv->serverGeometry.y ();
4618
xwcm = adjustConfigureRequestForGravity (&xwc, CWX | CWY, gravity, 1);
4620
window->validateResizeRequest (xwcm, &xwc, ClientTypeApplication);
4622
CompPoint pos (xwc.x, xwc.y);
4623
if (window->place (pos))
4631
window->configureXWindow (xwcm, &xwc);
4633
priv->placed = true;
4636
allowFocus = allowWindowFocus (NO_FOCUS_MASK, 0);
4638
if (!allowFocus && (priv->type & ~NO_FOCUS_MASK))
4639
stackingMode = CompStackingUpdateModeInitialMapDeniedFocus;
4641
stackingMode = CompStackingUpdateModeInitialMap;
4643
window->updateAttributes (stackingMode);
4645
if (window->minimized ())
4646
window->unminimize ();
4648
screen->leaveShowDesktopMode (window);
4650
if (allowFocus && !window->onCurrentDesktop ())
4651
screen->priv->setCurrentDesktop (priv->desktop);
4653
if (!(priv->state & CompWindowStateHiddenMask))
4657
window->moveInputFocusTo ();
4661
* PrivateWindow::updatePassiveButtonGrabs
4663
* Updates the passive button grabs for a window. When
4664
* one of the specified button + modifier combinations
4665
* for this window is activated, compiz will be given
4666
* an active grab for the window (which we can turn off
4667
* by calling XAllowEvents later in ::handleEvent)
4669
* NOTE: ICCCM says that we are only allowed to grab
4670
* windows that we actually own as a client, so only
4671
* grab the frame window. Additionally, although there
4672
* isn't anything in the ICCCM that says we cannot
4673
* grab every button, some clients do not interpret
4674
* EnterNotify and LeaveNotify events caused by the
4675
* activation of the grab correctly, so ungrab button
4676
* and modifier combinations that we do not need on
4677
* active windows (but in reality we shouldn't be grabbing
4678
* for buttons that we don't actually need at that point
4683
PrivateWindow::updatePassiveButtonGrabs ()
4685
bool onlyActions = (priv->id == screen->priv->activeWindow ||
4686
!screen->priv->optionGetClickToFocus ());
4691
/* Ungrab everything */
4692
XUngrabButton (screen->priv->dpy, AnyButton, AnyModifier, frame);
4694
/* We don't need the full grab in the following cases:
4695
* - This window has the focus and either
4697
* - we don't want click raise
4702
if (screen->priv->optionGetRaiseOnClick ())
4704
for (CompWindow *above = window->next;
4705
above != NULL; above = above->next)
4707
if (above->priv->attrib.map_state != IsViewable)
4710
if (above->type () & CompWindowTypeDockMask)
4713
if (above->region ().intersects (region))
4715
onlyActions = false;
4724
/* Grab only we have bindings on */
4725
foreach (PrivateScreen::ButtonGrab &bind, screen->priv->buttonGrabs)
4727
unsigned int mods = modHandler->virtualToRealModMask (bind.modifiers);
4729
if (mods & CompNoMask)
4732
for (unsigned int ignore = 0;
4733
ignore <= modHandler->ignoredModMask (); ignore++)
4735
if (ignore & ~modHandler->ignoredModMask ())
4738
XGrabButton (screen->priv->dpy,
4743
ButtonPressMask | ButtonReleaseMask |
4754
/* Grab everything */
4755
XGrabButton (screen->priv->dpy,
4759
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
4769
CompWindow::region () const
4771
return priv->region;
4775
CompWindow::frameRegion () const
4777
return priv->frameRegion;
4781
CompWindow::inShowDesktopMode ()
4783
return priv->inShowDesktopMode;
4787
CompWindow::setShowDesktopMode (bool value)
4789
priv->inShowDesktopMode = value;
4793
CompWindow::managed ()
4795
WRAPABLE_HND_FUNC_RETURN (18, bool, managed);
4796
return priv->managed;
4800
CompWindow::grabbed ()
4802
return priv->grabbed;
4806
CompWindow::pendingMaps ()
4808
return priv->pendingMaps;
4812
CompWindow::wmType ()
4814
return priv->wmType;
4818
CompWindow::activeNum ()
4820
return priv->activeNum;
4824
CompWindow::frame ()
4830
CompWindow::resName ()
4833
return priv->resName;
4835
return CompString ();
4839
CompWindow::mapNum () const
4841
return priv->mapNum;
4845
CompWindow::struts ()
4847
return priv->struts;
4851
CompWindow::saveMask ()
4853
return priv->saveMask;
4857
CompWindow::saveWc ()
4859
return priv->saveWc;
4863
CompWindow::moveToViewportPosition (int x,
4868
int vWidth = screen->width () * screen->vpSize ().width ();
4869
int vHeight = screen->height () * screen->vpSize ().height ();
4871
if (screen->vpSize ().width () != 1)
4873
x += screen->vp ().x () * screen->width ();
4874
x = MOD (x, vWidth);
4875
x -= screen->vp ().x () * screen->width ();
4878
if (screen->vpSize ().height () != 1)
4880
y += screen->vp ().y () * screen->height ();
4881
y = MOD (y, vHeight);
4882
y -= screen->vp ().y () * screen->height ();
4885
tx = x - priv->attrib.x;
4886
ty = y - priv->attrib.y;
4895
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
4898
if (priv->state & CompWindowStateStickyMask)
4904
if (screen->vpSize ().width ()!= 1)
4906
m = priv->attrib.x + tx;
4908
if (m - priv->output.left < (int) screen->width () - vWidth)
4910
else if (m + priv->width + priv->output.right > vWidth)
4914
if (screen->vpSize ().height () != 1)
4916
m = priv->attrib.y + ty;
4918
if (m - priv->output.top < (int) screen->height () - vHeight)
4920
else if (m + priv->height + priv->output.bottom > vHeight)
4924
if (priv->saveMask & CWX)
4925
priv->saveWc.x += wx;
4927
if (priv->saveMask & CWY)
4928
priv->saveWc.y += wy;
4938
CompWindow::startupId ()
4940
return priv->startupId;
4944
PrivateWindow::applyStartupProperties (CompStartupSequence *s)
4948
priv->initialViewport.setX (s->viewportX);
4949
priv->initialViewport.setY (s->viewportY);
4951
workspace = sn_startup_sequence_get_workspace (s->sequence);
4953
window->setDesktop (workspace);
4955
priv->initialTimestamp =
4956
sn_startup_sequence_get_timestamp (s->sequence);
4957
priv->initialTimestampSet = true;
4961
CompWindow::desktop ()
4963
return priv->desktop;
4967
CompWindow::clientLeader (bool checkAncestor)
4969
if (priv->clientLeader)
4970
return priv->clientLeader;
4973
return priv->getClientLeaderOfAncestor ();
4979
CompWindow::transientFor ()
4981
return priv->transientFor;
4985
CompWindow::pendingUnmaps ()
4987
return priv->pendingUnmaps;
4991
CompWindow::minimized ()
4993
WRAPABLE_HND_FUNC_RETURN (15, bool, minimized);
4994
return priv->minimized;
4998
CompWindow::placed ()
5000
return priv->placed;
5004
CompWindow::shaded ()
5006
return priv->shaded;
5010
CompWindow::input () const
5012
return priv->border;
5016
CompWindow::output () const
5018
return priv->output;
5022
CompWindow::sizeHints () const
5024
return priv->sizeHints;
5028
PrivateWindow::updateMwmHints ()
5030
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
5031
window->recalcActions ();
5035
PrivateWindow::updateStartupId ()
5037
char *oldId = startupId;
5040
startupId = getStartupId ();
5044
if (strcmp (startupId, oldId) == 0)
5050
if (managed && startupId && newId)
5057
initialTimestampSet = false;
5058
screen->priv->applyStartupProperties (window);
5060
if (initialTimestampSet)
5061
timestamp = initialTimestamp;
5063
/* as the viewport can't be transmitted via startup
5064
notification, assume the client changing the ID
5065
wanted to activate the window on the current viewport */
5067
vp = window->defaultViewport ();
5068
svp = screen->vp ();
5071
x = window->geometry ().x () + (svp.x () - vp.x ()) * size.width ();
5072
y = window->geometry ().y () + (svp.y () - vp.y ()) * size.height ();
5073
window->moveToViewportPosition (x, y, true);
5075
if (allowWindowFocus (0, timestamp))
5076
window->activate ();
5081
CompWindow::destroyed ()
5083
return priv->destroyed;
5087
CompWindow::invisible ()
5089
return priv->invisible;
5093
CompWindow::syncAlarm ()
5095
return priv->syncAlarm;
5099
CoreWindow::manage (Window aboveId, XWindowAttributes &wa)
5101
screen->priv->createdWindows.remove (this);
5102
return new CompWindow (aboveId, wa, priv);
5106
* On CreateNotify we only want to do some very basic
5107
* initialization on the windows, and we need to be
5108
* tracking things like eg override-redirect windows
5109
* for compositing, although only on MapRequest do
5110
* we actually care about them (and let the plugins
5111
* care about them too)
5114
CoreWindow::CoreWindow (Window id)
5116
priv = new PrivateWindow (this);
5119
screen->priv->createdWindows.push_back (this);
5124
CompWindow::CompWindow (Window aboveId,
5125
XWindowAttributes &wa,
5126
PrivateWindow *priv) :
5127
PluginClassStorage (windowPluginClassIndices),
5130
// TODO: Reparent first!
5132
priv->window = this;
5134
screen->insertWindow (this, aboveId);
5137
priv->serverGeometry.set (priv->attrib.x, priv->attrib.y,
5138
priv->attrib.width, priv->attrib.height,
5139
priv->attrib.border_width);
5140
priv->syncGeometry.set (priv->attrib.x, priv->attrib.y,
5141
priv->attrib.width, priv->attrib.height,
5142
priv->attrib.border_width);
5143
priv->geometry.set (priv->attrib.x, priv->attrib.y,
5144
priv->attrib.width, priv->attrib.height,
5145
priv->attrib.border_width);
5147
priv->width = priv->attrib.width + priv->attrib.border_width * 2;
5148
priv->height = priv->attrib.height + priv->attrib.border_width * 2;
5150
priv->sizeHints.flags = 0;
5152
priv->recalcNormalHints ();
5154
priv->transientFor = None;
5155
priv->clientLeader = None;
5157
XSelectInput (screen->dpy (), priv->id,
5158
PropertyChangeMask |
5162
priv->alpha = (priv->attrib.depth == 32);
5163
priv->lastPong = screen->priv->lastPing;
5165
if (screen->XShape ())
5166
XShapeSelectInput (screen->dpy (), priv->id, ShapeNotifyMask);
5168
if (priv->attrib.c_class != InputOnly)
5170
priv->region = CompRegion (priv->attrib.x, priv->attrib.y,
5171
priv->width, priv->height);
5172
priv->inputRegion = priv->region;
5174
/* need to check for DisplayModal state on all windows */
5175
priv->state = screen->priv->getWindowState (priv->id);
5177
priv->updateClassHints ();
5181
priv->attrib.map_state = IsUnmapped;
5184
priv->wmType = screen->priv->getWindowType (priv->id);
5185
priv->protocols = screen->priv->getProtocols (priv->id);
5187
if (!overrideRedirect ())
5189
priv->updateNormalHints ();
5191
priv->updateWmHints ();
5192
priv->updateTransientHint ();
5194
priv->clientLeader = priv->getClientLeader ();
5195
priv->startupId = priv->getStartupId ();
5199
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
5201
if (!(priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask)))
5203
priv->desktop = screen->getWindowProp (priv->id, Atoms::winDesktop,
5205
if (priv->desktop != 0xffffffff)
5207
if (priv->desktop >= screen->nDesktop ())
5208
priv->desktop = screen->currentDesktop ();
5217
if (priv->attrib.map_state == IsViewable)
5219
priv->placed = true;
5221
if (!overrideRedirect ())
5223
// needs to happen right after maprequest
5226
priv->managed = true;
5228
if (screen->priv->getWmState (priv->id) == IconicState)
5230
if (priv->state & CompWindowStateShadedMask)
5231
priv->shaded = true;
5233
priv->minimized = true;
5237
if (priv->wmType & (CompWindowTypeDockMask |
5238
CompWindowTypeDesktopMask))
5240
setDesktop (0xffffffff);
5244
if (priv->desktop != 0xffffffff)
5245
priv->desktop = screen->currentDesktop ();
5247
screen->setWindowProp (priv->id, Atoms::winDesktop,
5253
priv->attrib.map_state = IsUnmapped;
5254
priv->pendingMaps++;
5258
updateAttributes (CompStackingUpdateModeNormal);
5260
if (priv->minimized || priv->inShowDesktopMode ||
5261
priv->hidden || priv->shaded)
5263
priv->state |= CompWindowStateHiddenMask;
5265
priv->pendingUnmaps++;
5267
if (priv->frame && !priv->shaded)
5268
XUnmapWindow (screen->dpy (), priv->frame);
5270
XUnmapWindow (screen->dpy (), priv->id);
5272
screen->priv->setWindowState (priv->state, priv->id);
5275
else if (!overrideRedirect ())
5277
if (screen->priv->getWmState (priv->id) == IconicState)
5279
// before everything else in maprequest
5282
priv->managed = true;
5283
priv->placed = true;
5285
if (priv->state & CompWindowStateHiddenMask)
5287
if (priv->state & CompWindowStateShadedMask)
5288
priv->shaded = true;
5290
priv->minimized = true;
5295
/* TODO: bailout properly when objectInitPlugins fails */
5296
assert (CompPlugin::windowInitPlugins (this));
5299
priv->updateIconGeometry ();
5302
resize (priv->attrib.x, priv->attrib.y,
5303
priv->attrib.width, ++priv->attrib.height - 1,
5304
priv->attrib.border_width);
5306
if (priv->attrib.map_state == IsViewable)
5308
priv->invisible = WINDOW_INVISIBLE (priv);
5312
CompWindow::~CompWindow ()
5314
screen->unhookWindow (this);
5316
if (!priv->destroyed)
5320
priv->unreparent ();
5323
/* restore saved geometry and map if hidden */
5324
if (!priv->attrib.override_redirect)
5327
XConfigureWindow (screen->dpy (), priv->id,
5328
priv->saveMask, &priv->saveWc);
5332
if (priv->state & CompWindowStateHiddenMask)
5333
XMapWindow (screen->dpy (), priv->id);
5337
if (screen->XShape ())
5338
XShapeSelectInput (screen->dpy (), priv->id, NoEventMask);
5340
if (priv->id != screen->priv->grabWindow)
5341
XSelectInput (screen->dpy (), priv->id, NoEventMask);
5343
XUngrabButton (screen->dpy (), AnyButton, AnyModifier, priv->id);
5346
if (priv->attrib.map_state == IsViewable)
5348
if (priv->type == CompWindowTypeDesktopMask)
5349
screen->priv->desktopWindowCount--;
5351
if (priv->destroyed && priv->struts)
5352
screen->updateWorkarea ();
5355
if (priv->destroyed)
5356
screen->priv->updateClientList ();
5358
CompPlugin::windowFiniPlugins (this);
5363
PrivateWindow::PrivateWindow (CoreWindow *window) :
5371
transientFor (None),
5372
clientLeader (None),
5380
type (CompWindowTypeUnknownMask),
5384
mwmDecor (MwmDecorAll),
5385
mwmFunc (MwmFuncAll),
5393
initialViewport (0, 0),
5395
initialTimestamp (0),
5396
initialTimestampSet (false),
5398
fullscreenMonitorsSet (false),
5402
inShowDesktopMode (false),
5432
closeRequests (false),
5433
lastCloseRequestTime (0)
5450
syncWaitTimer.setTimes (1000, 1200);
5451
syncWaitTimer.setCallback (boost::bind (&PrivateWindow::handleSyncAlarm,
5455
PrivateWindow::~PrivateWindow ()
5458
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
5460
syncWaitTimer.stop ();
5463
XDestroyWindow (screen->dpy (), frame);
5485
CompWindow::syncWait ()
5487
return priv->syncWait;
5491
CompWindow::alpha ()
5493
WRAPABLE_HND_FUNC_RETURN (16, bool, alpha);
5499
CompWindow::overrideRedirect ()
5501
return priv->attrib.override_redirect;
5505
PrivateWindow::setOverrideRedirect (bool overrideRedirect)
5507
if (overrideRedirect == window->overrideRedirect ())
5510
priv->attrib.override_redirect = overrideRedirect ? 1 : 0;
5511
window->recalcType ();
5512
window->recalcActions ();
5514
screen->matchPropertyChanged (window);
5518
CompWindow::isMapped () const
5520
return priv->mapNum > 0;
5524
CompWindow::isViewable () const
5526
return (priv->attrib.map_state == IsViewable);
5530
CompWindow::isFocussable ()
5532
WRAPABLE_HND_FUNC_RETURN (17, bool, isFocussable);
5534
if (priv->inputHint)
5537
if (priv->protocols & CompWindowProtocolTakeFocusMask)
5544
CompWindow::windowClass ()
5546
return priv->attrib.c_class;
5550
CompWindow::depth ()
5552
return priv->attrib.depth;
5556
CompWindow::alive ()
5562
CompWindow::mwmDecor ()
5564
return priv->mwmDecor;
5568
CompWindow::mwmFunc ()
5570
return priv->mwmFunc;
5573
/* TODO: This function should be able to check the XShape event
5574
* kind and only get/set shape rectangles for either ShapeInput
5575
* or ShapeBounding, but not both at the same time
5579
CompWindow::updateFrameRegion ()
5581
if (priv->frame && priv->serverGeometry.width () == priv->geometry.width () &&
5582
priv->serverGeometry.height () == priv->geometry.height ())
5587
priv->frameRegion = CompRegion ();
5589
updateFrameRegion (priv->frameRegion);
5593
r = priv->region.boundingRect ();
5594
priv->frameRegion -= r;
5596
r.setGeometry (r.x1 () - priv->input.left,
5597
r.y1 () - priv->input.top,
5598
r.width () + priv->input.right + priv->input.left,
5599
r.height () + priv->input.bottom + priv->input.top);
5601
priv->frameRegion &= CompRegion (r);
5604
x = priv->geometry.x () - priv->input.left;
5605
y = priv->geometry.y () - priv->input.top;
5607
XShapeCombineRegion (screen->dpy (), priv->frame,
5608
ShapeBounding, -x, -y,
5609
priv->frameRegion.united (priv->region).handle (),
5612
XShapeCombineRegion (screen->dpy (), priv->frame,
5614
priv->frameRegion.united (priv->inputRegion).handle (),
5620
CompWindow::setWindowFrameExtents (CompWindowExtents *b,
5621
CompWindowExtents *i)
5623
/* Input extents are used for frame size,
5624
* Border extents used for placement.
5630
if (priv->input.left != i->left ||
5631
priv->input.right != i->right ||
5632
priv->input.top != i->top ||
5633
priv->input.bottom != i->bottom)
5635
unsigned long data[4];
5645
data[3] = i->bottom;
5647
XChangeProperty (screen->dpy (), priv->id,
5648
Atoms::frameExtents,
5649
XA_CARDINAL, 32, PropModeReplace,
5650
(unsigned char *) data, 4);
5651
priv->updateSize ();
5652
priv->updateFrameWindow ();
5657
CompWindow::hasUnmapReference ()
5659
return (priv && priv->unmapRefCnt > 1);
5663
CompWindow::updateFrameRegion (CompRegion& region)
5664
WRAPABLE_HND_FUNC (12, updateFrameRegion, region)
5667
PrivateWindow::reparent ()
5669
XSetWindowAttributes attr;
5670
XWindowAttributes wa;
5673
CompWindow::Geometry &sg = serverGeometry;
5674
Display *dpy = screen->dpy ();
5675
Visual *visual = DefaultVisual (screen->dpy (),
5676
screen->screenNum ());
5677
Colormap cmap = DefaultColormap (screen->dpy (),
5678
screen->screenNum ());
5680
if (frame || attrib.override_redirect)
5686
if (!XGetWindowAttributes (dpy, id, &wa))
5688
XUngrabServer (dpy);
5693
XChangeSaveSet (dpy, id, SetModeInsert);
5694
XSelectInput (dpy, id, NoEventMask);
5695
XSelectInput (dpy, screen->root (), NoEventMask);
5697
xwc.border_width = 0;
5698
XConfigureWindow (dpy, id, CWBorderWidth, &xwc);
5700
mask = CWBorderPixel | CWColormap | CWBackPixmap;
5702
if (attrib.depth == 32)
5704
cmap = attrib.colormap;
5705
visual = attrib.visual;
5708
attr.background_pixmap = None;
5709
attr.border_pixel = 0;
5710
attr.colormap = cmap;
5712
frame = XCreateWindow (dpy, screen->root (), 0, 0,
5713
sg.width (), sg.height (), 0, attrib.depth,
5714
InputOutput, visual, mask, &attr);
5716
wrapper = XCreateWindow (dpy, frame, 0, 0,
5717
sg.width (), sg.height (), 0, attrib.depth,
5718
InputOutput, visual, mask, &attr);
5720
xwc.stack_mode = Below;
5723
/* Make sure the frame is underneath the client */
5724
XConfigureWindow (dpy, frame, CWSibling | CWStackMode, &xwc);
5726
/* Wait for the restacking to finish */
5729
/* Always need to have the wrapper window mapped */
5730
XMapWindow (dpy, wrapper);
5732
/* Reparent the client into the wrapper window */
5733
XReparentWindow (dpy, id, wrapper, 0, 0);
5735
attr.event_mask = PropertyChangeMask | FocusChangeMask |
5736
EnterWindowMask | LeaveWindowMask;
5738
/* We don't care about client events on the frame, and listening for them
5739
* will probably end up fighting the client anyways, so disable them */
5741
attr.do_not_propagate_mask = KeyPressMask | KeyReleaseMask |
5742
ButtonPressMask | ButtonReleaseMask |
5743
EnterWindowMask | LeaveWindowMask |
5744
PointerMotionMask | PointerMotionHintMask |
5745
Button1MotionMask | Button2MotionMask |
5746
Button3MotionMask | Button4MotionMask |
5747
Button5MotionMask | ButtonMotionMask |
5748
KeymapStateMask | ExposureMask |
5749
VisibilityChangeMask | StructureNotifyMask |
5750
ResizeRedirectMask | SubstructureNotifyMask |
5751
SubstructureRedirectMask | FocusChangeMask |
5752
PropertyChangeMask | ColormapChangeMask |
5753
OwnerGrabButtonMask;
5755
XChangeWindowAttributes (dpy, id, CWEventMask | CWDontPropagate, &attr);
5757
if (wa.map_state == IsViewable || shaded)
5758
XMapWindow (dpy, frame);
5760
attr.event_mask = SubstructureRedirectMask | StructureNotifyMask |
5761
SubstructureNotifyMask | EnterWindowMask |
5764
XChangeWindowAttributes (dpy, frame, CWEventMask, &attr);
5765
XChangeWindowAttributes (dpy, wrapper, CWEventMask, &attr);
5767
XSelectInput (dpy, screen->root (),
5768
SubstructureRedirectMask |
5769
SubstructureNotifyMask |
5770
StructureNotifyMask |
5771
PropertyChangeMask |
5781
XUngrabServer (dpy);
5783
XMoveResizeWindow (dpy, frame, sg.x (), sg.y (), sg.width (), sg.height ());
5785
updatePassiveButtonGrabs ();
5787
window->windowNotify (CompWindowNotifyReparent);
5793
PrivateWindow::unreparent ()
5795
Display *dpy = screen->dpy ();
5805
if (XCheckTypedWindowEvent (dpy, id, DestroyNotify, &e))
5807
XPutBackEvent (dpy, &e);
5811
if ((!destroyed) && alive)
5815
XChangeSaveSet (dpy, id, SetModeDelete);
5816
XSelectInput (dpy, frame, NoEventMask);
5817
XSelectInput (dpy, wrapper, NoEventMask);
5818
XSelectInput (dpy, id, NoEventMask);
5819
XSelectInput (dpy, screen->root (), NoEventMask);
5820
XReparentWindow (dpy, id, screen->root (), 0, 0);
5822
/* Wait for the reparent to finish */
5825
xwc.stack_mode = Below;
5826
xwc.sibling = frame;
5827
XConfigureWindow (dpy, id, CWSibling | CWStackMode, &xwc);
5829
/* Wait for the window to be restacked */
5832
XUnmapWindow (dpy, frame);
5834
XSelectInput (dpy, id, PropertyChangeMask | EnterWindowMask |
5837
XSelectInput (dpy, screen->root (),
5838
SubstructureRedirectMask |
5839
SubstructureNotifyMask |
5840
StructureNotifyMask |
5841
PropertyChangeMask |
5851
XUngrabServer (dpy);
5853
XMoveWindow (dpy, id, serverGeometry.x (), serverGeometry.y ());
5856
XDestroyWindow (dpy, wrapper);
5857
XDestroyWindow (dpy, frame);
5861
window->windowNotify (CompWindowNotifyUnreparent);