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
setDefaultWindowAttributes (XWindowAttributes *wa)
1168
wa->border_width = 0;
1172
wa->c_class = InputOnly;
1173
wa->bit_gravity = NorthWestGravity;
1174
wa->win_gravity = NorthWestGravity;
1175
wa->backing_store = NotUseful;
1176
wa->backing_planes = 0;
1177
wa->backing_pixel = 0;
1178
wa->save_under = false;
1179
wa->colormap = None;
1180
wa->map_installed = false;
1181
wa->map_state = IsUnviewable;
1182
wa->all_event_masks = 0;
1183
wa->your_event_mask = 0;
1184
wa->do_not_propagate_mask = 0;
1185
wa->override_redirect = true;
1190
CompWindow::incrementDestroyReference ()
1192
priv->destroyRefCnt++;
1196
CompWindow::destroy ()
1198
windowNotify (CompWindowNotifyBeforeDestroy);
1200
screen->priv->eraseWindowFromMap (id ());
1205
priv->destroyRefCnt--;
1206
if (priv->destroyRefCnt)
1210
if (!priv->destroyed)
1212
priv->destroyed = true;
1213
screen->priv->pendingDestroys++;
1217
priv->unreparent ();
1222
CompWindow::sendConfigureNotify ()
1224
XConfigureEvent xev;
1226
xev.type = ConfigureNotify;
1227
xev.event = priv->id;
1228
xev.window = priv->id;
1230
/* normally we should never send configure notify events to override
1231
redirect windows but if they support the _NET_WM_SYNC_REQUEST
1232
protocol we need to do this when the window is mapped. however the
1233
only way we can make sure that the attributes we send are correct
1234
and is to grab the server. */
1235
if (priv->attrib.override_redirect)
1237
XWindowAttributes attrib;
1239
XGrabServer (screen->dpy ());
1241
if (XGetWindowAttributes (screen->dpy (), priv->id, &attrib))
1245
xev.width = attrib.width;
1246
xev.height = attrib.height;
1247
xev.border_width = attrib.border_width;
1249
xev.above = (prev) ? prev->priv->id : None;
1250
xev.override_redirect = true;
1252
XSendEvent (screen->dpy (), priv->id, false,
1253
StructureNotifyMask, (XEvent *) &xev);
1256
XUngrabServer (screen->dpy ());
1260
xev.x = priv->serverGeometry.x ();
1261
xev.y = priv->serverGeometry.y ();
1262
xev.width = priv->serverGeometry.width ();
1263
xev.height = priv->serverGeometry.height ();
1264
xev.border_width = priv->serverGeometry.border ();
1266
xev.above = (prev) ? prev->priv->id : None;
1267
xev.override_redirect = priv->attrib.override_redirect;
1269
XSendEvent (screen->dpy (), priv->id, false,
1270
StructureNotifyMask, (XEvent *) &xev);
1277
windowNotify (CompWindowNotifyBeforeMap);
1281
if (priv->pendingMaps > 0)
1282
priv->pendingMaps = 0;
1284
priv->mapNum = screen->priv->mapNum++;
1287
screen->updateWorkarea ();
1289
if (windowClass () == InputOnly)
1292
priv->unmapRefCnt = 1;
1294
priv->attrib.map_state = IsViewable;
1296
if (!overrideRedirect ())
1297
screen->priv->setWmState (NormalState, priv->id);
1299
priv->invisible = true;
1302
priv->lastPong = screen->priv->lastPing;
1304
priv->updateRegion ();
1305
priv->updateSize ();
1307
screen->priv->updateClientList ();
1309
if (priv->type & CompWindowTypeDesktopMask)
1310
screen->priv->desktopWindowCount++;
1312
if (priv->protocols & CompWindowProtocolSyncRequestMask)
1315
sendConfigureNotify ();
1318
if (!overrideRedirect ())
1322
resize (priv->attrib.x, priv->attrib.y, priv->attrib.width,
1323
++priv->attrib.height - 1, priv->attrib.border_width);
1327
windowNotify (CompWindowNotifyMap);
1331
CompWindow::incrementUnmapReference ()
1333
priv->unmapRefCnt++;
1337
CompWindow::unmap ()
1339
windowNotify (CompWindowNotifyBeforeUnmap);
1344
priv->unmapRefCnt--;
1345
if (priv->unmapRefCnt > 0)
1348
if (priv->unmanaging)
1352
int gravity = priv->sizeHints.win_gravity;
1354
/* revert gravity adjustment made at MapNotify time */
1355
xwc.x = priv->serverGeometry.x ();
1356
xwc.y = priv->serverGeometry.y ();
1360
xwcm = priv->adjustConfigureRequestForGravity (&xwc,
1365
configureXWindow (xwcm, &xwc);
1367
priv->unmanaging = false;
1371
screen->updateWorkarea ();
1373
if (priv->attrib.map_state != IsViewable)
1376
if (priv->type == CompWindowTypeDesktopMask)
1377
screen->priv->desktopWindowCount--;
1379
priv->attrib.map_state = IsUnmapped;
1381
priv->invisible = true;
1383
if (priv->shaded && priv->height)
1384
resize (priv->attrib.x, priv->attrib.y,
1385
priv->attrib.width, ++priv->attrib.height - 1,
1386
priv->attrib.border_width);
1388
screen->priv->updateClientList ();
1390
windowNotify (CompWindowNotifyUnmap);
1394
PrivateWindow::restack (Window aboveId)
1396
if (aboveId && (aboveId == id || aboveId == frame))
1397
// Don't try to raise a window above itself
1399
else if (window->prev)
1401
if (aboveId && (aboveId == window->prev->id () ||
1402
aboveId == window->prev->frame ()))
1405
else if (aboveId == None && !window->next)
1408
if (aboveId && !screen->findTopLevelWindow (aboveId, true))
1411
screen->unhookWindow (window);
1412
screen->insertWindow (window, aboveId);
1414
screen->priv->updateClientList ();
1416
window->windowNotify (CompWindowNotifyRestack);
1422
CompWindow::resize (XWindowAttributes attr)
1424
return resize (Geometry (attr.x, attr.y, attr.width, attr.height,
1425
attr.border_width));
1429
CompWindow::resize (int x,
1435
return resize (Geometry (x, y, width, height, border));
1439
CompWindow::resize (CompWindow::Geometry gm)
1441
if (priv->attrib.width != gm.width () ||
1442
priv->attrib.height != gm.height () ||
1443
priv->attrib.border_width != gm.border ())
1446
int dx, dy, dwidth, dheight;
1448
pw = gm.width () + gm.border () * 2;
1449
ph = gm.height () + gm.border () * 2;
1454
dx = gm.x () - priv->attrib.x;
1455
dy = gm.y () - priv->attrib.y;
1456
dwidth = gm.width () - priv->attrib.width;
1457
dheight = gm.height () - priv->attrib.height;
1459
priv->attrib.x = gm.x ();
1460
priv->attrib.y = gm.y ();
1461
priv->attrib.width = gm.width ();
1462
priv->attrib.height = gm.height ();
1463
priv->attrib.border_width = gm.border ();
1465
priv->geometry.set (priv->attrib.x, priv->attrib.y,
1466
priv->attrib.width, priv->attrib.height,
1467
priv->attrib.border_width);
1469
if (!priv->mapNum && priv->unmapRefCnt > 0 &&
1470
priv->attrib.map_state == IsViewable)
1472
/* keep old pixmap for windows that are unmapped on the client side,
1473
* but not yet on our side as it's pretty likely that plugins are
1474
* currently using it for animations
1484
priv->updateRegion ();
1486
resizeNotify (dx, dy, dwidth, dheight);
1488
priv->invisible = WINDOW_INVISIBLE (priv);
1489
priv->updateFrameWindow ();
1491
else if (priv->attrib.x != gm.x () || priv->attrib.y != gm.y ())
1495
dx = gm.x () - priv->attrib.x;
1496
dy = gm.y () - priv->attrib.y;
1505
syncValueIncrement (XSyncValue *value)
1510
XSyncIntToValue (&one, 1);
1511
XSyncValueAdd (value, *value, one, &overflow);
1515
PrivateWindow::initializeSyncCounter ()
1517
XSyncAlarmAttributes values;
1520
unsigned long n, left;
1521
unsigned char *data;
1524
return syncAlarm != None;
1526
if (!(protocols & CompWindowProtocolSyncRequestMask))
1529
result = XGetWindowProperty (screen->dpy (), id,
1530
Atoms::wmSyncRequestCounter,
1531
0L, 1L, false, XA_CARDINAL, &actual, &format,
1534
if (result == Success && n && data)
1536
unsigned long *counter = (unsigned long *) data;
1538
syncCounter = *counter;
1542
XSyncIntsToValue (&syncValue, (unsigned int) rand (), 0);
1543
XSyncSetCounter (screen->dpy (),
1547
syncValueIncrement (&syncValue);
1549
values.events = true;
1551
values.trigger.counter = syncCounter;
1552
values.trigger.wait_value = syncValue;
1554
values.trigger.value_type = XSyncAbsolute;
1555
values.trigger.test_type = XSyncPositiveComparison;
1557
XSyncIntToValue (&values.delta, 1);
1559
values.events = true;
1561
CompScreen::checkForError (screen->dpy ());
1563
/* Note that by default, the alarm increments the trigger value
1564
* when it fires until the condition (counter.value < trigger.value)
1567
syncAlarm = XSyncCreateAlarm (screen->dpy (),
1576
if (CompScreen::checkForError (screen->dpy ()))
1579
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
1582
else if (result == Success && data)
1591
CompWindow::sendSyncRequest ()
1593
XClientMessageEvent xev;
1598
if (!priv->initializeSyncCounter ())
1601
xev.type = ClientMessage;
1602
xev.window = priv->id;
1603
xev.message_type = Atoms::wmProtocols;
1605
xev.data.l[0] = Atoms::wmSyncRequest;
1606
xev.data.l[1] = CurrentTime;
1607
xev.data.l[2] = XSyncValueLow32 (priv->syncValue);
1608
xev.data.l[3] = XSyncValueHigh32 (priv->syncValue);
1611
syncValueIncrement (&priv->syncValue);
1613
XSendEvent (screen->dpy (), priv->id, false, 0, (XEvent *) &xev);
1615
priv->syncWait = true;
1616
priv->syncGeometry = priv->serverGeometry;
1618
if (!priv->syncWaitTimer.active ())
1619
priv->syncWaitTimer.start ();
1623
PrivateWindow::configure (XConfigureEvent *ce)
1628
priv->attrib.override_redirect = ce->override_redirect;
1632
priv->syncGeometry.set (ce->x, ce->y, ce->width, ce->height,
1637
if (ce->override_redirect)
1639
priv->serverGeometry.set (ce->x, ce->y, ce->width, ce->height,
1643
window->resize (ce->x, ce->y, ce->width, ce->height, ce->border_width);
1646
if (ce->event == screen->root ())
1647
priv->restack (ce->above);
1651
PrivateWindow::configureFrame (XConfigureEvent *ce)
1653
int x, y, width, height;
1659
x = ce->x + priv->input.left;
1660
y = ce->y + priv->input.top;
1661
width = ce->width - priv->input.left - priv->input.right;
1662
height = ce->height - priv->input.top - priv->input.bottom;
1666
priv->syncGeometry.set (x, y, width, height, ce->border_width);
1670
if (ce->override_redirect)
1672
priv->serverGeometry.set (x, y, width, height, ce->border_width);
1675
window->resize (x, y, width, height, ce->border_width);
1678
if (priv->restack (ce->above))
1679
priv->updatePassiveButtonGrabs ();
1681
above = screen->findWindow (ce->above);
1684
above->priv->updatePassiveButtonGrabs ();
1688
PrivateWindow::circulate (XCirculateEvent *ce)
1692
if (ce->place == PlaceOnTop)
1693
newAboveId = screen->priv->getTopWindow ();
1697
priv->restack (newAboveId);
1701
CompWindow::move (int dx,
1707
priv->attrib.x += dx;
1708
priv->attrib.y += dy;
1710
priv->geometry.setX (priv->attrib.x);
1711
priv->geometry.setY (priv->attrib.y);
1713
priv->region.translate (dx, dy);
1714
priv->inputRegion.translate (dx, dy);
1715
if (!priv->frameRegion.isEmpty ())
1716
priv->frameRegion.translate (dx, dy);
1718
priv->invisible = WINDOW_INVISIBLE (priv);
1720
moveNotify (dx, dy, immediate);
1725
CompWindow::syncPosition ()
1727
priv->serverGeometry.setX (priv->attrib.x);
1728
priv->serverGeometry.setY (priv->attrib.y);
1730
XMoveWindow (screen->dpy (), ROOTPARENT (this),
1731
priv->attrib.x - priv->input.left,
1732
priv->attrib.y - priv->input.top);
1736
XMoveWindow (screen->dpy (), priv->wrapper,
1737
priv->input.left, priv->input.top);
1738
sendConfigureNotify ();
1743
CompWindow::focus ()
1745
WRAPABLE_HND_FUNC_RETURN (2, bool, focus)
1747
if (overrideRedirect ())
1750
if (!priv->managed || priv->unmanaging)
1753
if (!onCurrentDesktop ())
1756
if (priv->destroyed)
1759
if (!priv->shaded && (priv->state & CompWindowStateHiddenMask))
1762
if (priv->attrib.x + priv->width <= 0 ||
1763
priv->attrib.y + priv->height <= 0 ||
1764
priv->attrib.x >= (int) screen->width ()||
1765
priv->attrib.y >= (int) screen->height ())
1772
CompWindow::place (CompPoint &pos)
1774
WRAPABLE_HND_FUNC_RETURN (4, bool, place, pos)
1779
CompWindow::validateResizeRequest (unsigned int &mask,
1780
XWindowChanges *xwc,
1781
unsigned int source)
1783
WRAPABLE_HND_FUNC (5, validateResizeRequest, mask, xwc, source)
1785
if (!(priv->type & (CompWindowTypeDockMask |
1786
CompWindowTypeFullscreenMask |
1787
CompWindowTypeUnknownMask)))
1793
min = screen->workArea ().y () + priv->input.top;
1794
max = screen->workArea ().bottom ();
1796
if (priv->state & CompWindowStateStickyMask &&
1797
(xwc->y < min || xwc->y > max))
1799
xwc->y = priv->serverGeometry.y ();
1803
min -= screen->vp ().y () * screen->height ();
1804
max += (screen->vpSize ().height () - screen->vp ().y () - 1) *
1809
else if (xwc->y > max)
1818
min = screen->workArea ().x () + priv->input.left;
1819
max = screen->workArea ().right ();
1821
if (priv->state & CompWindowStateStickyMask &&
1822
(xwc->x < min || xwc->x > max))
1824
xwc->x = priv->serverGeometry.x ();
1828
min -= screen->vp ().x () * screen->width ();
1829
max += (screen->vpSize ().width () - screen->vp ().x () - 1) *
1834
else if (xwc->x > max)
1842
CompWindow::resizeNotify (int dx,
1846
WRAPABLE_HND_FUNC (6, resizeNotify, dx, dy, dwidth, dheight)
1849
CompWindow::moveNotify (int dx,
1852
WRAPABLE_HND_FUNC (7, moveNotify, dx, dy, immediate)
1855
CompWindow::windowNotify (CompWindowNotify n)
1856
WRAPABLE_HND_FUNC (8, windowNotify, n)
1859
CompWindow::grabNotify (int x,
1864
WRAPABLE_HND_FUNC (9, grabNotify, x, y, state, mask)
1865
priv->grabbed = true;
1869
CompWindow::ungrabNotify ()
1871
WRAPABLE_HND_FUNC (10, ungrabNotify)
1872
priv->grabbed = false;
1876
CompWindow::stateChangeNotify (unsigned int lastState)
1878
WRAPABLE_HND_FUNC (11, stateChangeNotify, lastState);
1880
/* if being made sticky */
1881
if (!(lastState & CompWindowStateStickyMask) &&
1882
(priv->state & CompWindowStateStickyMask))
1884
CompPoint vp; /* index of the window's vp */
1886
/* Find which viewport the window falls in,
1887
and check if it's the current viewport */
1888
vp = defaultViewport ();
1889
if (screen->vp () != vp)
1891
int moveX = (screen->vp ().x () - vp.x ()) * screen->width ();
1892
int moveY = (screen->vp ().y () - vp.y ()) * screen->height ();
1894
move (moveX, moveY, TRUE);
1902
PrivateWindow::isGroupTransient (Window clientLeader)
1907
if (transientFor == None || transientFor == screen->root ())
1909
if (type & (CompWindowTypeUtilMask |
1910
CompWindowTypeToolbarMask |
1911
CompWindowTypeMenuMask |
1912
CompWindowTypeDialogMask |
1913
CompWindowTypeModalDialogMask))
1915
if (this->clientLeader == clientLeader)
1924
PrivateWindow::getModalTransient ()
1926
CompWindow *w, *modalTransient;
1928
modalTransient = window;
1930
for (w = screen->windows ().back (); w; w = w->prev)
1932
if (w == modalTransient || w->priv->mapNum == 0)
1935
if (w->priv->transientFor == modalTransient->priv->id)
1937
if (w->priv->state & CompWindowStateModalMask)
1940
w = screen->windows ().back ();
1945
if (modalTransient == window)
1947
/* don't look for group transients with modal state if current window
1949
if (state & CompWindowStateModalMask)
1952
for (w = screen->windows ().back (); w; w = w->prev)
1954
if (w == modalTransient || w->priv->mapNum == 0)
1957
if (isAncestorTo (modalTransient, w))
1960
if (w->priv->isGroupTransient (modalTransient->priv->clientLeader))
1962
if (w->priv->state & CompWindowStateModalMask)
1965
w = w->priv->getModalTransient ();
1975
if (modalTransient == window)
1976
modalTransient = NULL;
1978
return modalTransient;
1982
CompWindow::moveInputFocusTo ()
1984
CompScreen *s = screen;
1985
CompWindow *modalTransient;
1987
modalTransient = priv->getModalTransient ();
1989
return modalTransient->moveInputFocusTo ();
1991
if (priv->state & CompWindowStateHiddenMask)
1993
XSetInputFocus (s->dpy (), priv->frame,
1994
RevertToPointerRoot, CurrentTime);
1995
XChangeProperty (s->dpy (), s->root (), Atoms::winActive,
1996
XA_WINDOW, 32, PropModeReplace,
1997
(unsigned char *) &priv->id, 1);
2001
bool setFocus = false;
2003
if (priv->inputHint)
2005
XSetInputFocus (s->dpy (), priv->id, RevertToPointerRoot,
2010
if (priv->protocols & CompWindowProtocolTakeFocusMask)
2014
ev.type = ClientMessage;
2015
ev.xclient.window = priv->id;
2016
ev.xclient.message_type = Atoms::wmProtocols;
2017
ev.xclient.format = 32;
2018
ev.xclient.data.l[0] = Atoms::wmTakeFocus;
2019
ev.xclient.data.l[1] = s->getCurrentTime ();
2020
ev.xclient.data.l[2] = 0;
2021
ev.xclient.data.l[3] = 0;
2022
ev.xclient.data.l[4] = 0;
2024
XSendEvent (s->dpy (), priv->id, false, NoEventMask, &ev);
2030
screen->priv->nextActiveWindow = priv->id;
2032
if (!setFocus && !modalTransient)
2034
CompWindow *ancestor;
2036
/* move input to closest ancestor */
2037
for (ancestor = s->windows ().front (); ancestor;
2038
ancestor = ancestor->next)
2040
if (PrivateWindow::isAncestorTo (this, ancestor))
2042
ancestor->moveInputFocusTo ();
2051
CompWindow::moveInputFocusToOtherWindow ()
2053
if (priv->id == screen->activeWindow () ||
2054
priv->id == screen->priv->nextActiveWindow)
2056
CompWindow *ancestor;
2058
if (priv->transientFor && priv->transientFor != screen->root ())
2060
ancestor = screen->findWindow (priv->transientFor);
2062
!(ancestor->priv->type & (CompWindowTypeDesktopMask |
2063
CompWindowTypeDockMask)))
2065
ancestor->moveInputFocusTo ();
2068
screen->focusDefaultWindow ();
2070
else if (priv->type & (CompWindowTypeDialogMask |
2071
CompWindowTypeModalDialogMask))
2073
CompWindow *a, *focus = NULL;
2075
for (a = screen->windows ().back (); a; a = a->prev)
2077
if (a->priv->clientLeader == priv->clientLeader)
2083
if (a->priv->type & (CompWindowTypeNormalMask |
2084
CompWindowTypeDialogMask |
2085
CompWindowTypeModalDialogMask))
2087
if (priv->compareWindowActiveness (focus, a) < 0)
2097
if (focus && !(focus->priv->type & (CompWindowTypeDesktopMask |
2098
CompWindowTypeDockMask)))
2100
focus->moveInputFocusTo ();
2103
screen->focusDefaultWindow ();
2106
screen->focusDefaultWindow ();
2112
PrivateWindow::stackLayerCheck (CompWindow *w,
2113
Window clientLeader,
2116
if (isAncestorTo (w, below))
2119
if (isAncestorTo (below, w))
2122
if (clientLeader && below->priv->clientLeader == clientLeader)
2123
if (below->priv->isGroupTransient (clientLeader))
2126
if (w->priv->state & CompWindowStateAboveMask)
2130
else if (w->priv->state & CompWindowStateBelowMask)
2132
if (below->priv->state & CompWindowStateBelowMask)
2135
else if (!(below->priv->state & CompWindowStateAboveMask))
2144
PrivateWindow::avoidStackingRelativeTo (CompWindow *w)
2146
if (w->overrideRedirect ())
2149
if (!w->priv->shaded && !w->priv->pendingMaps)
2151
if (!w->isViewable () || !w->isMapped ())
2158
/* goes through the stack, top-down until we find a window we should
2159
stack above, normal windows can be stacked above fullscreen windows
2160
(and fullscreen windows over others in their layer) if aboveFs is true. */
2162
PrivateWindow::findSiblingBelow (CompWindow *w,
2166
Window clientLeader = w->priv->clientLeader;
2167
unsigned int type = w->priv->type;
2168
unsigned int belowMask;
2171
belowMask = CompWindowTypeDockMask;
2173
belowMask = CompWindowTypeDockMask | CompWindowTypeFullscreenMask;
2175
/* normal stacking of fullscreen windows with below state */
2176
if ((type & CompWindowTypeFullscreenMask) &&
2177
(w->priv->state & CompWindowStateBelowMask))
2178
type = CompWindowTypeNormalMask;
2180
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2181
clientLeader = None;
2183
for (below = screen->windows ().back (); below;
2184
below = below->prev)
2186
if (below == w || avoidStackingRelativeTo (below))
2189
/* always above desktop windows */
2190
if (below->priv->type & CompWindowTypeDesktopMask)
2194
case CompWindowTypeDesktopMask:
2195
/* desktop window layer */
2197
case CompWindowTypeFullscreenMask:
2200
/* otherwise fall-through */
2201
case CompWindowTypeDockMask:
2202
/* fullscreen and dock layer */
2203
if (below->priv->type & (CompWindowTypeFullscreenMask |
2204
CompWindowTypeDockMask))
2206
if (stackLayerCheck (w, clientLeader, below))
2215
/* fullscreen and normal layer */
2216
if (!(below->priv->type & belowMask))
2218
if (stackLayerCheck (w, clientLeader, below))
2228
/* goes through the stack, top-down and returns the lowest window we
2231
PrivateWindow::findLowestSiblingBelow (CompWindow *w)
2233
CompWindow *below, *lowest = screen->windows ().back ();
2234
Window clientLeader = w->priv->clientLeader;
2235
unsigned int type = w->priv->type;
2237
/* normal stacking fullscreen windows with below state */
2238
if ((type & CompWindowTypeFullscreenMask) &&
2239
(w->priv->state & CompWindowStateBelowMask))
2240
type = CompWindowTypeNormalMask;
2242
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2243
clientLeader = None;
2245
for (below = screen->windows ().back (); below;
2246
below = below->prev)
2248
if (below == w || avoidStackingRelativeTo (below))
2251
/* always above desktop windows */
2252
if (below->priv->type & CompWindowTypeDesktopMask)
2256
case CompWindowTypeDesktopMask:
2257
/* desktop window layer - desktop windows always should be
2258
stacked at the bottom; no other window should be below them */
2261
case CompWindowTypeFullscreenMask:
2262
case CompWindowTypeDockMask:
2263
/* fullscreen and dock layer */
2264
if (below->priv->type & (CompWindowTypeFullscreenMask |
2265
CompWindowTypeDockMask))
2267
if (!stackLayerCheck (below, clientLeader, w))
2276
/* fullscreen and normal layer */
2277
if (!(below->priv->type & CompWindowTypeDockMask))
2279
if (!stackLayerCheck (below, clientLeader, w))
2292
PrivateWindow::validSiblingBelow (CompWindow *w,
2293
CompWindow *sibling)
2295
Window clientLeader = w->priv->clientLeader;
2296
unsigned int type = w->priv->type;
2298
/* normal stacking fullscreen windows with below state */
2299
if ((type & CompWindowTypeFullscreenMask) &&
2300
(w->priv->state & CompWindowStateBelowMask))
2301
type = CompWindowTypeNormalMask;
2303
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2304
clientLeader = None;
2306
if (sibling == w || avoidStackingRelativeTo (sibling))
2309
/* always above desktop windows */
2310
if (sibling->priv->type & CompWindowTypeDesktopMask)
2314
case CompWindowTypeDesktopMask:
2315
/* desktop window layer */
2317
case CompWindowTypeFullscreenMask:
2318
case CompWindowTypeDockMask:
2319
/* fullscreen and dock layer */
2320
if (sibling->priv->type & (CompWindowTypeFullscreenMask |
2321
CompWindowTypeDockMask))
2323
if (stackLayerCheck (w, clientLeader, sibling))
2332
/* fullscreen and normal layer */
2333
if (!(sibling->priv->type & CompWindowTypeDockMask))
2335
if (stackLayerCheck (w, clientLeader, sibling))
2345
PrivateWindow::saveGeometry (int mask)
2347
int m = mask & ~saveMask;
2349
/* only save geometry if window has been placed */
2354
saveWc.x = serverGeometry.x ();
2357
saveWc.y = serverGeometry.y ();
2360
saveWc.width = serverGeometry.width ();
2363
saveWc.height = serverGeometry.height ();
2365
if (m & CWBorderWidth)
2366
saveWc.border_width = serverGeometry.border ();
2372
PrivateWindow::restoreGeometry (XWindowChanges *xwc,
2375
int m = mask & saveMask;
2385
xwc->width = saveWc.width;
2387
/* This is not perfect but it works OK for now. If the saved width is
2388
the same as the current width then make it a little be smaller so
2389
the user can see that it changed and it also makes sure that
2390
windowResizeNotify is called and plugins are notified. */
2391
if (xwc->width == (int) serverGeometry.width ())
2401
xwc->height = saveWc.height;
2403
/* As above, if the saved height is the same as the current height
2404
then make it a little be smaller. */
2405
if (xwc->height == (int) serverGeometry.height ())
2413
if (m & CWBorderWidth)
2414
xwc->border_width = saveWc.border_width;
2422
PrivateWindow::reconfigureXWindow (unsigned int valueMask,
2423
XWindowChanges *xwc)
2425
if (valueMask & CWX)
2426
serverGeometry.setX (xwc->x);
2428
if (valueMask & CWY)
2429
serverGeometry.setY (xwc->y);
2431
if (valueMask & CWWidth)
2432
serverGeometry.setWidth (xwc->width);
2434
if (valueMask & CWHeight)
2435
serverGeometry.setHeight (xwc->height);
2437
if (valueMask & CWBorderWidth)
2438
serverGeometry.setBorder (xwc->border_width);
2440
/* Compiz's window list is immediately restacked on reconfigureXWindow
2441
in order to ensure correct operation of the raise, lower and restacking
2442
functions. This function should only recieve stack_mode == Above
2443
but warn incase something else does get through, to make the cause
2444
of any potential misbehaviour obvious. */
2445
if (valueMask & (CWSibling | CWStackMode))
2447
if (xwc->stack_mode == Above)
2448
restack (xwc->sibling);
2450
compLogMessage ("core", CompLogLevelWarn, "restack_mode not Above");
2455
XWindowChanges wc = *xwc;
2459
wc.width += input.left + input.right;
2460
wc.height += input.top + input.bottom;
2462
XConfigureWindow (screen->dpy (), frame, valueMask, &wc);
2463
valueMask &= ~(CWSibling | CWStackMode);
2465
xwc->x = input.left;
2467
XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc);
2473
XConfigureWindow (screen->dpy (), id, valueMask, xwc);
2477
PrivateWindow::stackTransients (CompWindow *w,
2479
XWindowChanges *xwc,
2480
CompWindowList &updateList)
2483
Window clientLeader = w->priv->clientLeader;
2485
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2486
clientLeader = None;
2488
for (t = screen->windows ().back (); t; t = t->prev)
2490
if (t == w || t == avoid)
2493
if (t->priv->transientFor == w->priv->id ||
2494
t->priv->isGroupTransient (clientLeader))
2496
if (w->priv->type & CompWindowTypeDockMask)
2497
if (!(t->priv->type & CompWindowTypeDockMask))
2500
if (!stackTransients (t, avoid, xwc, updateList))
2503
if (xwc->sibling == t->priv->id ||
2504
(t->priv->frame && xwc->sibling == t->priv->frame))
2507
if (t->priv->mapNum || t->priv->pendingMaps)
2508
updateList.push_back (t);
2516
PrivateWindow::stackAncestors (CompWindow *w,
2517
XWindowChanges *xwc,
2518
CompWindowList &updateList)
2520
CompWindow *transient = NULL;
2522
if (w->priv->transientFor)
2523
transient = screen->findWindow (w->priv->transientFor);
2526
xwc->sibling != transient->priv->id &&
2527
(!transient->priv->frame || xwc->sibling != transient->priv->frame))
2529
CompWindow *ancestor;
2531
ancestor = screen->findWindow (w->priv->transientFor);
2534
if (!stackTransients (ancestor, w, xwc, updateList))
2537
if (ancestor->priv->type & CompWindowTypeDesktopMask)
2540
if (ancestor->priv->type & CompWindowTypeDockMask)
2541
if (!(w->priv->type & CompWindowTypeDockMask))
2544
if (ancestor->priv->mapNum || ancestor->priv->pendingMaps)
2545
updateList.push_back (ancestor);
2547
stackAncestors (ancestor, xwc, updateList);
2550
else if (w->priv->isGroupTransient (w->priv->clientLeader))
2554
for (a = screen->windows ().back (); a; a = a->prev)
2556
if (a->priv->clientLeader == w->priv->clientLeader &&
2557
a->priv->transientFor == None &&
2558
!a->priv->isGroupTransient (w->priv->clientLeader))
2560
if (xwc->sibling == a->priv->id ||
2561
(a->priv->frame && xwc->sibling == a->priv->frame))
2564
if (!stackTransients (a, w, xwc, updateList))
2567
if (a->priv->type & CompWindowTypeDesktopMask)
2570
if (a->priv->type & CompWindowTypeDockMask)
2571
if (!(w->priv->type & CompWindowTypeDockMask))
2574
if (a->priv->mapNum || a->priv->pendingMaps)
2575
updateList.push_back (a);
2582
CompWindow::configureXWindow (unsigned int valueMask,
2583
XWindowChanges *xwc)
2585
if (priv->managed && (valueMask & (CWSibling | CWStackMode)))
2587
CompWindowList transients;
2588
CompWindowList ancestors;
2590
/* Since the window list is being reordered in reconfigureXWindow
2591
the list of windows which need to be restacked must be stored
2592
first. The windows are stacked in the opposite order than they
2593
were previously stacked, in order that they are above xwc->sibling
2594
so that when compiz gets the ConfigureNotify event it doesn't
2595
have to restack all the windows again. */
2597
/* transient children above */
2598
if (PrivateWindow::stackTransients (this, NULL, xwc, transients))
2600
/* ancestors, siblings and sibling transients below */
2601
PrivateWindow::stackAncestors (this, xwc, ancestors);
2603
for (CompWindowList::reverse_iterator w = ancestors.rbegin ();
2604
w != ancestors.rend (); w++)
2606
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
2607
xwc->sibling = ROOTPARENT (*w);
2610
this->priv->reconfigureXWindow (valueMask, xwc);
2611
xwc->sibling = ROOTPARENT (this);
2613
for (CompWindowList::reverse_iterator w = transients.rbegin ();
2614
w != transients.rend (); w++)
2616
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
2617
xwc->sibling = ROOTPARENT (*w);
2623
priv->reconfigureXWindow (valueMask, xwc);
2628
PrivateWindow::addWindowSizeChanges (XWindowChanges *xwc,
2629
CompWindow::Geometry old)
2637
screen->viewportForGeometry (old, viewport);
2639
x = (viewport.x () - screen->vp ().x ()) * screen->width ();
2640
y = (viewport.y () - screen->vp ().y ()) * screen->height ();
2642
output = screen->outputDeviceForGeometry (old);
2643
workArea = screen->getWorkareaForOutput (output);
2645
if (type & CompWindowTypeFullscreenMask)
2647
saveGeometry (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
2649
if (fullscreenMonitorsSet)
2651
xwc->x = x + fullscreenMonitorRect.x ();
2652
xwc->y = y + fullscreenMonitorRect.y ();
2653
xwc->width = fullscreenMonitorRect.width ();
2654
xwc->height = fullscreenMonitorRect.height ();
2658
xwc->x = x + screen->outputDevs ()[output].x ();
2659
xwc->y = y + screen->outputDevs ()[output].y ();
2660
xwc->width = screen->outputDevs ()[output].width ();
2661
xwc->height = screen->outputDevs ()[output].height ();
2664
xwc->border_width = 0;
2666
mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
2670
mask |= restoreGeometry (xwc, CWBorderWidth);
2672
if (state & CompWindowStateMaximizedVertMask)
2674
saveGeometry (CWY | CWHeight);
2676
xwc->height = workArea.height () - input.top -
2677
input.bottom - old.border () * 2;
2683
mask |= restoreGeometry (xwc, CWY | CWHeight);
2686
if (state & CompWindowStateMaximizedHorzMask)
2688
saveGeometry (CWX | CWWidth);
2690
xwc->width = workArea.width () - input.left -
2691
input.right - old.border () * 2;
2697
mask |= restoreGeometry (xwc, CWX | CWWidth);
2700
/* constrain window width if smaller than minimum width */
2701
if (!(mask & CWWidth) && (int) old.width () < sizeHints.min_width)
2703
xwc->width = sizeHints.min_width;
2707
/* constrain window width if greater than maximum width */
2708
if (!(mask & CWWidth) && (int) old.width () > sizeHints.max_width)
2710
xwc->width = sizeHints.max_width;
2714
/* constrain window height if smaller than minimum height */
2715
if (!(mask & CWHeight) && (int) old.height () < sizeHints.min_height)
2717
xwc->height = sizeHints.min_height;
2721
/* constrain window height if greater than maximum height */
2722
if (!(mask & CWHeight) && (int) old.height () > sizeHints.max_height)
2724
xwc->height = sizeHints.max_height;
2728
if (mask & (CWWidth | CWHeight))
2730
int width, height, max;
2732
width = (mask & CWWidth) ? xwc->width : old.width ();
2733
height = (mask & CWHeight) ? xwc->height : old.height ();
2735
xwc->width = old.width ();
2736
xwc->height = old.height ();
2738
window->constrainNewWindowSize (width, height, &width, &height);
2740
if (width != (int) old.width ())
2748
if (height != (int) old.height ())
2751
xwc->height = height;
2756
if (state & CompWindowStateMaximizedVertMask)
2758
if (old.y () < y + workArea.y () + input.top)
2760
xwc->y = y + workArea.y () + input.top;
2765
height = xwc->height + old.border () * 2;
2767
max = y + workArea.bottom ();
2768
if (old.y () + (int) old.height () + input.bottom > max)
2770
xwc->y = max - height - input.bottom;
2773
else if (old.y () + height + input.bottom > max)
2775
xwc->y = y + workArea.y () +
2776
(workArea.height () - input.top - height -
2777
input.bottom) / 2 + input.top;
2783
if (state & CompWindowStateMaximizedHorzMask)
2785
if (old.x () < x + workArea.x () + input.left)
2787
xwc->x = x + workArea.x () + input.left;
2792
width = xwc->width + old.border () * 2;
2794
max = x + workArea.right ();
2795
if (old.x () + (int) old.width () + input.right > max)
2797
xwc->x = max - width - input.right;
2800
else if (old.x () + width + input.right > max)
2802
xwc->x = x + workArea.x () +
2803
(workArea.width () - input.left - width -
2804
input.right) / 2 + input.left;
2812
if ((mask & CWX) && (xwc->x == old.x ()))
2815
if ((mask & CWY) && (xwc->y == old.y ()))
2818
if ((mask & CWWidth) && (xwc->width == (int) old.width ()))
2821
if ((mask & CWHeight) && (xwc->height == (int) old.height ()))
2828
PrivateWindow::adjustConfigureRequestForGravity (XWindowChanges *xwc,
2834
unsigned int mask = 0;
2839
if (xwcm & (CWX | CWWidth))
2842
case NorthWestGravity:
2844
case SouthWestGravity:
2846
newX += priv->input.left * direction;
2853
newX -= (xwc->width / 2 - priv->input.left +
2854
(priv->input.left + priv->input.right) / 2) * direction;
2856
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
2859
case NorthEastGravity:
2861
case SouthEastGravity:
2863
newX -= xwc->width + priv->input.right * direction;
2865
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
2874
if (xwcm & (CWY | CWHeight))
2877
case NorthWestGravity:
2879
case NorthEastGravity:
2881
newY = xwc->y + priv->input.top * direction;
2888
newY -= (xwc->height / 2 - priv->input.top +
2889
(priv->input.top + priv->input.bottom) / 2) * direction;
2891
newY -= ((xwc->height - priv->serverGeometry.height ()) / 2) * direction;
2894
case SouthWestGravity:
2896
case SouthEastGravity:
2898
newY -= xwc->height + priv->input.bottom * direction;
2900
newY -= (xwc->height - priv->serverGeometry.height ()) * direction;
2911
xwc->x += (newX - xwc->x);
2917
xwc->y += (newY - xwc->y);
2925
CompWindow::moveResize (XWindowChanges *xwc,
2928
unsigned int source)
2930
bool placed = false;
2932
xwcm &= (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
2934
if (xwcm & (CWX | CWY))
2935
if (priv->sizeHints.flags & (USPosition | PPosition))
2939
gravity = priv->sizeHints.win_gravity;
2942
xwc->x = priv->serverGeometry.x ();
2944
xwc->y = priv->serverGeometry.y ();
2945
if (!(xwcm & CWWidth))
2946
xwc->width = priv->serverGeometry.width ();
2947
if (!(xwcm & CWHeight))
2948
xwc->height = priv->serverGeometry.height ();
2950
if (xwcm & (CWWidth | CWHeight))
2954
if (constrainNewWindowSize (xwc->width, xwc->height, &width, &height))
2956
if (width != xwc->width)
2959
if (height != xwc->height)
2963
xwc->height = height;
2967
xwcm |= priv->adjustConfigureRequestForGravity (xwc, xwcm, gravity, 1);
2969
validateResizeRequest (xwcm, xwc, source);
2971
/* when horizontally maximized only allow width changes added by
2972
addWindowSizeChanges */
2973
if (priv->state & CompWindowStateMaximizedHorzMask)
2976
/* when vertically maximized only allow height changes added by
2977
addWindowSizeChanges */
2978
if (priv->state & CompWindowStateMaximizedVertMask)
2981
xwcm |= priv->addWindowSizeChanges (xwc, Geometry (xwc->x, xwc->y,
2982
xwc->width, xwc->height,
2983
xwc->border_width));
2985
/* check if the new coordinates are useful and valid (different
2986
to current size); if not, we have to clear them to make sure
2987
we send a synthetic ConfigureNotify event if all coordinates
2988
match the server coordinates */
2989
if (xwc->x == priv->serverGeometry.x ())
2992
if (xwc->y == priv->serverGeometry.y ())
2995
if (xwc->width == (int) priv->serverGeometry.width ())
2998
if (xwc->height == (int) priv->serverGeometry.height ())
3001
if (xwc->border_width == (int) priv->serverGeometry.border ())
3002
xwcm &= ~CWBorderWidth;
3004
/* update saved window coordinates - if CWX or CWY is set for fullscreen
3005
or maximized windows after addWindowSizeChanges, it should be pretty
3006
safe to assume that the saved coordinates should be updated too, e.g.
3007
because the window was moved to another viewport by some client */
3008
if ((xwcm & CWX) && (priv->saveMask & CWX))
3009
priv->saveWc.x += (xwc->x - priv->serverGeometry.x ());
3011
if ((xwcm & CWY) && (priv->saveMask & CWY))
3012
priv->saveWc.y += (xwc->y - priv->serverGeometry.y ());
3014
if (priv->mapNum && (xwcm & (CWWidth | CWHeight)))
3018
configureXWindow (xwcm, xwc);
3021
/* we have to send a configure notify on ConfigureRequest events if
3022
we decide not to do anything according to ICCCM 4.1.5 */
3023
sendConfigureNotify ();
3027
priv->placed = true;
3031
PrivateWindow::updateSize ()
3036
if (window->overrideRedirect () || !managed)
3039
mask = priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
3042
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
3043
window->sendSyncRequest ();
3045
window->configureXWindow (mask, &xwc);
3050
PrivateWindow::addWindowStackChanges (XWindowChanges *xwc,
3051
CompWindow *sibling)
3055
if (!sibling || sibling->priv->id != id)
3061
XLowerWindow (screen->dpy (), id);
3063
XLowerWindow (screen->dpy (), frame);
3065
/* Restacking of compiz's window list happens
3066
immediately and since this path doesn't call
3067
reconfigureXWindow, restack must be called here. */
3070
else if (sibling->priv->id != window->prev->priv->id)
3072
mask |= CWSibling | CWStackMode;
3074
xwc->stack_mode = Above;
3075
xwc->sibling = ROOTPARENT (sibling);
3080
mask |= CWSibling | CWStackMode;
3082
xwc->stack_mode = Above;
3083
xwc->sibling = ROOTPARENT (sibling);
3087
if (sibling && mask)
3089
/* a normal window can be stacked above fullscreen windows but we
3090
don't want normal windows to be stacked above dock window so if
3091
the sibling we're stacking above is a fullscreen window we also
3092
update all dock windows. */
3093
if ((sibling->priv->type & CompWindowTypeFullscreenMask) &&
3094
(!(type & (CompWindowTypeFullscreenMask |
3095
CompWindowTypeDockMask))) &&
3096
!isAncestorTo (window, sibling))
3100
for (dw = screen->windows ().back (); dw; dw = dw->prev)
3104
/* Collect all dock windows first */
3105
CompWindowList dockWindows;
3106
for (; dw; dw = dw->prev)
3107
if (dw->priv->type & CompWindowTypeDockMask)
3108
dockWindows.push_back (dw);
3110
/* Then update the dock windows */
3111
foreach (CompWindow *dw, dockWindows)
3112
dw->configureXWindow (mask, xwc);
3120
CompWindow::raise ()
3124
bool aboveFs = false;
3126
/* an active fullscreen window should be raised over all other
3127
windows in its layer */
3128
if (priv->type & CompWindowTypeFullscreenMask)
3129
if (priv->id == screen->activeWindow ())
3132
mask = priv->addWindowStackChanges (&xwc,
3133
PrivateWindow::findSiblingBelow (this, aboveFs));
3136
configureXWindow (mask, &xwc);
3140
PrivateScreen::focusTopMostWindow ()
3142
CompWindow *focus = NULL;
3143
CompWindowList::reverse_iterator it = windows.rbegin ();
3145
for (; it != windows.rend (); it++)
3147
CompWindow *w = *it;
3149
if (w->type () & CompWindowTypeDockMask)
3161
if (focus->id () != activeWindow)
3162
focus->moveInputFocusTo ();
3165
XSetInputFocus (dpy, root, RevertToPointerRoot,
3172
CompWindow::lower ()
3177
mask = priv->addWindowStackChanges (&xwc,
3178
PrivateWindow::findLowestSiblingBelow (this));
3180
configureXWindow (mask, &xwc);
3182
/* when lowering a window, focus the topmost window if
3183
the click-to-focus option is on */
3184
if ((screen->getOption ("click_to_focus")->value ().b ()))
3186
Window aboveWindowId = prev ? prev->id () : None;
3187
screen->unhookWindow (this);
3188
CompWindow *focusedWindow = screen->priv->focusTopMostWindow ();
3189
screen->insertWindow (this , aboveWindowId);
3191
/* if the newly focused window is a desktop window,
3192
give the focus back to w */
3193
if (focusedWindow &&
3194
focusedWindow->type () & CompWindowTypeDesktopMask)
3196
moveInputFocusTo ();
3202
CompWindow::restackAbove (CompWindow *sibling)
3204
for (; sibling; sibling = sibling->next)
3205
if (PrivateWindow::validSiblingBelow (this, sibling))
3213
mask = priv->addWindowStackChanges (&xwc, sibling);
3215
configureXWindow (mask, &xwc);
3219
/* finds the highest window under sibling we can stack above */
3221
PrivateWindow::findValidStackSiblingBelow (CompWindow *w,
3222
CompWindow *sibling)
3224
CompWindow *lowest, *last, *p;
3226
/* check whether we're allowed to stack under a sibling by finding
3227
* the above 'sibling' and checking whether or not we're allowed
3228
* to stack under that - if not, then there is no valid sibling
3231
for (p = sibling; p; p = p->next)
3233
if (!avoidStackingRelativeTo (p))
3235
if (!validSiblingBelow (p, w))
3241
/* get lowest sibling we're allowed to stack above */
3242
lowest = last = findLowestSiblingBelow (w);
3244
/* walk from bottom up */
3245
for (p = screen->windows ().front (); p; p = p->next)
3247
/* stop walking when we reach the sibling we should try to stack
3252
/* skip windows that we should avoid */
3253
if (w == p || avoidStackingRelativeTo (p))
3256
if (validSiblingBelow (w, p))
3258
/* update lowest as we find windows below sibling that we're
3259
allowed to stack above. last window must be equal to the
3260
lowest as we shouldn't update lowest if we passed an
3266
/* update last pointer */
3274
CompWindow::restackBelow (CompWindow *sibling)
3279
mask = priv->addWindowStackChanges (&xwc,
3280
PrivateWindow::findValidStackSiblingBelow (this, sibling));
3283
configureXWindow (mask, &xwc);
3287
CompWindow::updateAttributes (CompStackingUpdateMode stackingMode)
3292
if (overrideRedirect () || !priv->managed)
3295
if (priv->state & CompWindowStateShadedMask)
3297
windowNotify (CompWindowNotifyShade);
3301
else if (priv->shaded)
3303
windowNotify (CompWindowNotifyUnshade);
3308
if (stackingMode != CompStackingUpdateModeNone)
3311
CompWindow *sibling;
3313
aboveFs = (stackingMode == CompStackingUpdateModeAboveFullscreen);
3314
if (priv->type & CompWindowTypeFullscreenMask)
3316
/* put active or soon-to-be-active fullscreen windows over
3317
all others in their layer */
3318
if (priv->id == screen->activeWindow ())
3324
/* put windows that are just mapped, over fullscreen windows */
3325
if (stackingMode == CompStackingUpdateModeInitialMap)
3328
sibling = PrivateWindow::findSiblingBelow (this, aboveFs);
3331
(stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
3335
for (p = sibling; p; p = p->prev)
3336
if (p->priv->id == screen->activeWindow ())
3339
/* window is above active window so we should lower it,
3340
* assuing that is allowed (if, for example, our window has
3341
* the "above" state, then lowering beneath the active
3342
* window may not be allowed). */
3343
if (p && PrivateWindow::validSiblingBelow (p, this))
3345
p = PrivateWindow::findValidStackSiblingBelow (sibling, p);
3347
/* if we found a valid sibling under the active window, it's
3348
our new sibling we want to stack above */
3354
mask |= priv->addWindowStackChanges (&xwc, sibling);
3357
if ((stackingMode == CompStackingUpdateModeInitialMap) ||
3358
(stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
3360
/* If we are called from the MapRequest handler, we have to
3361
immediately update the internal stack. If we don't do that,
3362
the internal stacking order is invalid until the ConfigureNotify
3363
arrives because we put the window at the top of the stack when
3365
if (mask & CWStackMode)
3367
Window above = (mask & CWSibling) ? xwc.sibling : 0;
3368
priv->restack (above);
3372
mask |= priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
3374
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
3378
configureXWindow (mask, &xwc);
3382
PrivateWindow::ensureWindowVisibility ()
3385
int width = serverGeometry.width () + serverGeometry.border () * 2;
3386
int height = serverGeometry.height () + serverGeometry.border () * 2;
3390
if (struts || attrib.override_redirect)
3393
if (type & (CompWindowTypeDockMask |
3394
CompWindowTypeFullscreenMask |
3395
CompWindowTypeUnknownMask))
3398
x1 = screen->workArea ().x () - screen->width () * screen->vp ().x ();
3399
y1 = screen->workArea ().y () - screen->height () * screen->vp ().y ();
3400
x2 = x1 + screen->workArea ().width () + screen->vpSize ().width () *
3402
y2 = y1 + screen->workArea ().height () + screen->vpSize ().height () *
3405
if (serverGeometry.x () - input.left >= x2)
3406
dx = (x2 - 25) - serverGeometry.x ();
3407
else if (serverGeometry.x () + width + input.right <= x1)
3408
dx = (x1 + 25) - (serverGeometry.x () + width);
3410
if (serverGeometry.y () - input.top >= y2)
3411
dy = (y2 - 25) - serverGeometry.y ();
3412
else if (serverGeometry.y () + height + input.bottom <= y1)
3413
dy = (y1 + 25) - (serverGeometry.y () + height);
3419
xwc.x = serverGeometry.x () + dx;
3420
xwc.y = serverGeometry.y () + dy;
3422
window->configureXWindow (CWX | CWY, &xwc);
3427
PrivateWindow::reveal ()
3429
if (window->minimized ())
3430
window->unminimize ();
3432
screen->leaveShowDesktopMode (window);
3436
PrivateWindow::revealAncestors (CompWindow *w,
3437
CompWindow *transient)
3439
if (isAncestorTo (transient, w))
3441
screen->forEachWindow (boost::bind (revealAncestors, _1, w));
3447
CompWindow::activate ()
3449
WRAPABLE_HND_FUNC (3, activate)
3451
screen->priv->setCurrentDesktop (priv->desktop);
3453
screen->forEachWindow (
3454
boost::bind (PrivateWindow::revealAncestors, _1, this));
3457
if (priv->state & CompWindowStateHiddenMask)
3459
priv->state &= ~CompWindowStateShadedMask;
3464
if (priv->state & CompWindowStateHiddenMask)
3467
if (!onCurrentDesktop ())
3470
priv->ensureWindowVisibility ();
3471
updateAttributes (CompStackingUpdateModeAboveFullscreen);
3472
moveInputFocusTo ();
3476
#define PVertResizeInc (1 << 0)
3477
#define PHorzResizeInc (1 << 1)
3480
CompWindow::constrainNewWindowSize (int width,
3485
const XSizeHints *hints = &priv->sizeHints;
3486
int oldWidth = width;
3487
int oldHeight = height;
3491
int base_height = 0;
3494
int max_width = MAXSHORT;
3495
int max_height = MAXSHORT;
3496
long flags = hints->flags;
3497
long resizeIncFlags = (flags & PResizeInc) ? ~0 : 0;
3499
if (screen->getOption ("ignore_hints_when_maximized")->value ().b ())
3501
if (priv->state & MAXIMIZE_STATE)
3505
if (priv->state & CompWindowStateMaximizedHorzMask)
3506
resizeIncFlags &= ~PHorzResizeInc;
3508
if (priv->state & CompWindowStateMaximizedVertMask)
3509
resizeIncFlags &= ~PVertResizeInc;
3513
/* Ater gdk_window_constrain_size(), which is partially borrowed from fvwm.
3515
* Copyright 1993, Robert Nation
3516
* You may use this code for any purpose, as long as the original
3517
* copyright remains in the source code and all documentation
3519
* which in turn borrows parts of the algorithm from uwm
3522
#define FLOOR(value, base) (((int) ((value) / (base))) * (base))
3523
#define FLOOR64(value, base) (((uint64_t) ((value) / (base))) * (base))
3524
#define CLAMPW(v, min, max) ((v) <= (min) ? (min) : (v) >= (max) ? (max) : (v))
3526
if ((flags & PBaseSize) && (flags & PMinSize))
3528
base_width = hints->base_width;
3529
base_height = hints->base_height;
3530
min_width = hints->min_width;
3531
min_height = hints->min_height;
3533
else if (flags & PBaseSize)
3535
base_width = hints->base_width;
3536
base_height = hints->base_height;
3537
min_width = hints->base_width;
3538
min_height = hints->base_height;
3540
else if (flags & PMinSize)
3542
base_width = hints->min_width;
3543
base_height = hints->min_height;
3544
min_width = hints->min_width;
3545
min_height = hints->min_height;
3548
if (flags & PMaxSize)
3550
max_width = hints->max_width;
3551
max_height = hints->max_height;
3554
if (resizeIncFlags & PHorzResizeInc)
3555
xinc = MAX (xinc, hints->width_inc);
3557
if (resizeIncFlags & PVertResizeInc)
3558
yinc = MAX (yinc, hints->height_inc);
3560
/* clamp width and height to min and max values */
3561
width = CLAMPW (width, min_width, max_width);
3562
height = CLAMPW (height, min_height, max_height);
3564
/* shrink to base + N * inc */
3565
width = base_width + FLOOR (width - base_width, xinc);
3566
height = base_height + FLOOR (height - base_height, yinc);
3568
/* constrain aspect ratio, according to:
3570
* min_aspect.x width max_aspect.x
3571
* ------------ <= -------- <= -----------
3572
* min_aspect.y height max_aspect.y
3574
if ((flags & PAspect) && hints->min_aspect.y > 0 && hints->max_aspect.x > 0)
3576
/* Use 64 bit arithmetic to prevent overflow */
3578
uint64_t min_aspect_x = hints->min_aspect.x;
3579
uint64_t min_aspect_y = hints->min_aspect.y;
3580
uint64_t max_aspect_x = hints->max_aspect.x;
3581
uint64_t max_aspect_y = hints->max_aspect.y;
3584
if (min_aspect_x * height > width * min_aspect_y)
3586
delta = FLOOR64 (height - width * min_aspect_y / min_aspect_x,
3588
if (height - (int) delta >= min_height)
3592
delta = FLOOR64 (height * min_aspect_x / min_aspect_y - width,
3594
if (width + (int) delta <= max_width)
3599
if (width * max_aspect_y > max_aspect_x * height)
3601
delta = FLOOR64 (width - height * max_aspect_x / max_aspect_y,
3603
if (width - (int) delta >= min_width)
3607
delta = FLOOR64 (width * min_aspect_y / min_aspect_x - height,
3609
if (height + (int) delta <= max_height)
3619
if (width != oldWidth || height != oldHeight)
3622
*newHeight = height;
3633
priv->hidden = true;
3640
priv->hidden = false;
3645
PrivateWindow::hide ()
3647
bool onDesktop = window->onCurrentDesktop ();
3652
if (!window->minimized () && !inShowDesktopMode &&
3653
!hidden && onDesktop)
3655
if (state & CompWindowStateShadedMask)
3668
if ((state & CompWindowStateShadedMask) && frame)
3669
XUnmapWindow (screen->dpy (), frame);
3672
if (!pendingMaps && !window->isViewable ())
3675
window->windowNotify (CompWindowNotifyHide);
3679
if (frame && !shaded)
3680
XUnmapWindow (screen->dpy (), frame);
3682
XUnmapWindow (screen->dpy (), id);
3684
if (window->minimized () || inShowDesktopMode || hidden || shaded)
3685
window->changeState (state | CompWindowStateHiddenMask);
3687
if (shaded && id == screen->activeWindow ())
3688
window->moveInputFocusTo ();
3692
PrivateWindow::show ()
3694
bool onDesktop = window->onCurrentDesktop ();
3699
if (minimized || inShowDesktopMode ||
3700
hidden || !onDesktop)
3702
/* no longer hidden but not on current desktop */
3703
if (!minimized && !inShowDesktopMode && !hidden)
3704
window->changeState (state & ~CompWindowStateHiddenMask);
3709
/* transition from minimized to shaded */
3710
if (state & CompWindowStateShadedMask)
3715
XMapWindow (screen->dpy (), frame);
3718
window->resize (attrib.x, attrib.y,
3719
attrib.width, ++attrib.height - 1,
3720
attrib.border_width);
3729
window->windowNotify (CompWindowNotifyShow);
3735
XMapWindow (screen->dpy (), frame);
3736
XMapWindow (screen->dpy (), wrapper);
3739
XMapWindow (screen->dpy (), id);
3741
window->changeState (state & ~CompWindowStateHiddenMask);
3742
screen->priv->setWindowState (state, id);
3746
PrivateWindow::minimizeTransients (CompWindow *w,
3747
CompWindow *ancestor)
3749
if (w->priv->transientFor == ancestor->priv->id ||
3750
w->priv->isGroupTransient (ancestor->priv->clientLeader))
3757
CompWindow::minimize ()
3759
WRAPABLE_HND_FUNC (13, minimize);
3764
if (!priv->minimized)
3766
windowNotify (CompWindowNotifyMinimize);
3768
priv->minimized = true;
3770
screen->forEachWindow (
3771
boost::bind (PrivateWindow::minimizeTransients, _1, this));
3778
PrivateWindow::unminimizeTransients (CompWindow *w,
3779
CompWindow *ancestor)
3781
if (w->priv->transientFor == ancestor->priv->id ||
3782
w->priv->isGroupTransient (ancestor->priv->clientLeader))
3787
CompWindow::unminimize ()
3789
WRAPABLE_HND_FUNC (14, unminimize);
3790
if (priv->minimized)
3792
windowNotify (CompWindowNotifyUnminimize);
3794
priv->minimized = false;
3798
screen->forEachWindow (
3799
boost::bind (PrivateWindow::unminimizeTransients, _1, this));
3804
CompWindow::maximize (unsigned int state)
3806
if (overrideRedirect ())
3809
state = constrainWindowState (state, priv->actions);
3811
state &= MAXIMIZE_STATE;
3813
if (state == (priv->state & MAXIMIZE_STATE))
3816
state |= (priv->state & ~MAXIMIZE_STATE);
3818
changeState (state);
3819
updateAttributes (CompStackingUpdateModeNone);
3823
PrivateWindow::getUserTime (Time& time)
3827
unsigned long n, left;
3828
unsigned char *data;
3829
bool retval = false;
3831
result = XGetWindowProperty (screen->dpy (), priv->id,
3833
0L, 1L, False, XA_CARDINAL, &actual, &format,
3836
if (result == Success && data)
3842
memcpy (&value, data, sizeof (CARD32));
3844
time = (Time) value;
3847
XFree ((void *) data);
3854
PrivateWindow::setUserTime (Time time)
3856
CARD32 value = (CARD32) time;
3858
XChangeProperty (screen->dpy (), priv->id,
3860
XA_CARDINAL, 32, PropModeReplace,
3861
(unsigned char *) &value, 1);
3865
* Macros from metacity
3867
* Xserver time can wraparound, thus comparing two timestamps needs to
3868
* take this into account. Here's a little macro to help out. If no
3869
* wraparound has occurred, this is equivalent to
3871
* Of course, the rest of the ugliness of this macro comes from
3872
* accounting for the fact that wraparound can occur and the fact that
3873
* a timestamp of 0 must be special-cased since it means older than
3876
* Note that this is NOT an equivalent for time1 <= time2; if that's
3877
* what you need then you'll need to swap the order of the arguments
3878
* and negate the result.
3880
#define XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) \
3881
( (( (time1) < (time2) ) && \
3882
( (time2) - (time1) < ((unsigned long) -1) / 2 )) || \
3883
(( (time1) > (time2) ) && \
3884
( (time1) - (time2) > ((unsigned long) -1) / 2 )) \
3886
#define XSERVER_TIME_IS_BEFORE(time1, time2) \
3888
(XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS (time1, time2) && \
3893
PrivateWindow::getUsageTimestamp (Time& timestamp)
3895
if (getUserTime (timestamp))
3898
if (initialTimestampSet)
3900
timestamp = initialTimestamp;
3908
PrivateWindow::isWindowFocusAllowed (Time timestamp)
3910
CompScreen *s = screen;
3912
Time wUserTime, aUserTime;
3913
bool gotTimestamp = false;
3917
level = s->getOption ("focus_prevention_level")->value ().i ();
3919
if (level == CoreOptions::FocusPreventionLevelOff)
3924
/* the caller passed a timestamp, so use that
3925
instead of the window's user time */
3926
wUserTime = timestamp;
3927
gotTimestamp = true;
3931
gotTimestamp = getUsageTimestamp (wUserTime);
3934
/* if we got no timestamp for the window, try to get at least a timestamp
3935
for its transient parent, if any */
3936
if (!gotTimestamp && transientFor)
3940
parent = screen->findWindow (transientFor);
3942
gotTimestamp = parent->priv->getUsageTimestamp (wUserTime);
3945
if (gotTimestamp && !wUserTime)
3947
/* window explicitly requested no focus */
3951
/* allow focus for excluded windows */
3953
s->getOption ("focus_prevention_match")->value ().match ();
3954
if (!match.evaluate (window))
3957
if (level == CoreOptions::FocusPreventionLevelVeryHigh)
3960
active = s->findWindow (s->activeWindow ());
3962
/* no active window */
3963
if (!active || (active->type () & CompWindowTypeDesktopMask))
3966
/* active window belongs to same application */
3967
if (window->clientLeader () == active->clientLeader ())
3970
if (level == CoreOptions::FocusPreventionLevelHigh)
3973
/* not in current viewport or desktop */
3974
if (!window->onCurrentDesktop ())
3977
dvp = window->defaultViewport ();
3978
if (dvp.x () != s->vp ().x () || dvp.y () != s->vp ().y ())
3983
/* unsure as we have nothing to compare - allow focus in low level,
3984
don't allow in normal level */
3985
if (level == CoreOptions::FocusPreventionLevelNormal)
3991
/* can't get user time for active window */
3992
if (!active->priv->getUserTime (aUserTime))
3995
if (XSERVER_TIME_IS_BEFORE (wUserTime, aUserTime))
4002
PrivateWindow::allowWindowFocus (unsigned int noFocusMask,
4007
if (priv->id == screen->activeWindow ())
4010
/* do not focus windows of these types */
4011
if (priv->type & noFocusMask)
4014
/* window doesn't take focus */
4015
if (!priv->inputHint &&
4016
!(priv->protocols & CompWindowProtocolTakeFocusMask))
4021
retval = priv->isWindowFocusAllowed (timestamp);
4024
/* add demands attention state if focus was prevented */
4025
window->changeState (priv->state | CompWindowStateDemandsAttentionMask);
4032
CompWindow::defaultViewport ()
4036
if (priv->serverGeometry.x () < (int) screen->width () &&
4037
priv->serverGeometry.x () + priv->serverGeometry.width () > 0 &&
4038
priv->serverGeometry.y () < (int) screen->height () &&
4039
priv->serverGeometry.y ()+ priv->serverGeometry.height () > 0)
4041
return screen->vp ();
4044
screen->viewportForGeometry (priv->serverGeometry, viewport);
4050
CompWindow::initialViewport () const
4052
return priv->initialViewport;
4056
PrivateWindow::readIconHint ()
4058
XImage *image, *maskImage = NULL;
4059
Display *dpy = screen->dpy ();
4060
unsigned int width, height, dummy;
4061
unsigned int i, j, k;
4068
if (!XGetGeometry (dpy, hints->icon_pixmap, &wDummy, &iDummy,
4069
&iDummy, &width, &height, &dummy, &dummy))
4072
image = XGetImage (dpy, hints->icon_pixmap, 0, 0, width, height,
4073
AllPlanes, ZPixmap);
4077
colors = new XColor[width * height];
4080
XDestroyImage (image);
4085
for (j = 0; j < height; j++)
4086
for (i = 0; i < width; i++)
4087
colors[k++].pixel = XGetPixel (image, i, j);
4089
for (i = 0; i < k; i += 256)
4090
XQueryColors (dpy, screen->priv->colormap,
4091
&colors[i], MIN (k - i, 256));
4093
XDestroyImage (image);
4095
icon = new CompIcon (screen, width, height);
4102
if (hints->flags & IconMaskHint)
4103
maskImage = XGetImage (dpy, hints->icon_mask, 0, 0,
4104
width, height, AllPlanes, ZPixmap);
4107
p = (CARD32 *) icon->data ();
4109
for (j = 0; j < height; j++)
4111
for (i = 0; i < width; i++)
4113
if (maskImage && !XGetPixel (maskImage, i, j))
4115
else if (image->depth == 1) /* white : black */
4116
*p++ = colors[k].pixel ? 0xffffffff : 0xff000000;
4118
*p++ = 0xff000000 | /* alpha */
4119
(((colors[k].red >> 8) & 0xff) << 16) | /* red */
4120
(((colors[k].green >> 8) & 0xff) << 8) | /* green */
4121
((colors[k].blue >> 8) & 0xff); /* blue */
4129
XDestroyImage (maskImage);
4131
icons.push_back (icon);
4134
/* returns icon with dimensions as close as possible to width and height
4135
but never greater. */
4137
CompWindow::getIcon (int width,
4141
int wh, diff, oldDiff;
4144
/* need to fetch icon property */
4145
if (priv->icons.size () == 0 && !priv->noIcons)
4149
unsigned long n, left;
4150
unsigned char *data;
4152
result = XGetWindowProperty (screen->dpy (), priv->id, Atoms::wmIcon,
4153
0L, 65536L, false, XA_CARDINAL,
4154
&actual, &format, &n, &left, &data);
4156
if (result == Success && data)
4159
CARD32 alpha, red, green, blue;
4160
unsigned long iw, ih;
4162
for (i = 0; i + 2 < n; i += iw * ih + 2)
4164
unsigned long *idata = (unsigned long *) data;
4169
/* iw * ih may be larger than the value range of unsigned
4170
* long, so better do some checking for extremely weird
4171
* icon sizes first */
4172
if (iw > 2048 || ih > 2048 || iw * ih + 2 > n - i)
4178
icon = new CompIcon (screen, iw, ih);
4182
priv->icons.push_back (icon);
4184
p = (CARD32 *) (icon->data ());
4186
/* EWMH doesn't say if icon data is premultiplied or
4187
not but most applications seem to assume data should
4188
be unpremultiplied. */
4189
for (j = 0; j < iw * ih; j++)
4191
alpha = (idata[i + j + 2] >> 24) & 0xff;
4192
red = (idata[i + j + 2] >> 16) & 0xff;
4193
green = (idata[i + j + 2] >> 8) & 0xff;
4194
blue = (idata[i + j + 2] >> 0) & 0xff;
4196
red = (red * alpha) >> 8;
4197
green = (green * alpha) >> 8;
4198
blue = (blue * alpha) >> 8;
4211
else if (priv->hints && (priv->hints->flags & IconPixmapHint))
4213
priv->readIconHint ();
4216
/* don't fetch property again */
4217
if (priv->icons.size () == 0)
4218
priv->noIcons = true;
4221
/* no icons available for this window */
4226
wh = width + height;
4228
for (i = 0; i < priv->icons.size (); i++)
4230
const CompSize iconSize = *priv->icons[i];
4232
if ((int) iconSize.width () > width ||
4233
(int) iconSize.height () > height)
4238
diff = wh - (iconSize.width () + iconSize.height ());
4239
oldDiff = wh - (icon->width () + icon->height ());
4242
icon = priv->icons[i];
4245
icon = priv->icons[i];
4252
CompWindow::iconGeometry () const
4254
return priv->iconGeometry;
4258
PrivateWindow::freeIcons ()
4260
for (unsigned int i = 0; i < priv->icons.size (); i++)
4261
delete priv->icons[i];
4263
priv->icons.resize (0);
4264
priv->noIcons = false;
4268
CompWindow::outputDevice ()
4270
return screen->outputDeviceForGeometry (priv->serverGeometry);
4274
CompWindow::onCurrentDesktop ()
4276
if (priv->desktop == 0xffffffff ||
4277
priv->desktop == screen->currentDesktop ())
4286
CompWindow::setDesktop (unsigned int desktop)
4288
if (desktop != 0xffffffff)
4290
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
4293
if (desktop >= screen->nDesktop ())
4297
if (desktop == priv->desktop)
4300
priv->desktop = desktop;
4302
if (desktop == 0xffffffff || desktop == screen->currentDesktop ())
4307
screen->setWindowProp (priv->id, Atoms::winDesktop, priv->desktop);
4310
/* The compareWindowActiveness function compares the two windows 'w1'
4311
and 'w2'. It returns an integer less than, equal to, or greater
4312
than zero if 'w1' is found, respectively, to activated longer time
4313
ago than, to be activated at the same time, or be activated more
4314
recently than 'w2'. */
4316
PrivateWindow::compareWindowActiveness (CompWindow *w1,
4319
CompActiveWindowHistory *history = screen->currentHistory ();
4322
/* check current window history first */
4323
for (i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
4325
if (history->id[i] == w1->priv->id)
4328
if (history->id[i] == w2->priv->id)
4331
if (!history->id[i])
4335
return w1->priv->activeNum - w2->priv->activeNum;
4339
CompWindow::onAllViewports ()
4341
if (overrideRedirect ())
4344
if (!priv->managed && !isViewable ())
4347
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
4350
if (priv->state & CompWindowStateStickyMask)
4357
CompWindow::getMovementForOffset (CompPoint offset)
4359
CompScreen *s = screen;
4360
int m, vWidth, vHeight;
4361
int offX = offset.x (), offY = offset.y ();
4364
vWidth = s->width () * s->vpSize ().width ();
4365
vHeight = s->height () * s->vpSize ().height ();
4371
if (s->vpSize ().width () == 1)
4377
m = priv->attrib.x + offX;
4378
if (m - priv->input.left < (int) s->width () - vWidth)
4379
rv.setX (offX + vWidth);
4380
else if (m + priv->width + priv->input.right > vWidth)
4381
rv.setX (offX - vWidth);
4386
if (s->vpSize ().height () == 1)
4392
m = priv->attrib.y + offY;
4393
if (m - priv->input.top < (int) s->height () - vHeight)
4394
rv.setY (offY + vHeight);
4395
else if (m + priv->height + priv->input.bottom > vHeight)
4396
rv.setY (offY - vHeight);
4405
WindowInterface::getOutputExtents (CompWindowExtents& output)
4406
WRAPABLE_DEF (getOutputExtents, output)
4409
WindowInterface::getAllowedActions (unsigned int &setActions,
4410
unsigned int &clearActions)
4411
WRAPABLE_DEF (getAllowedActions, setActions, clearActions)
4414
WindowInterface::focus ()
4415
WRAPABLE_DEF (focus)
4418
WindowInterface::activate ()
4419
WRAPABLE_DEF (activate)
4422
WindowInterface::place (CompPoint &pos)
4423
WRAPABLE_DEF (place, pos)
4426
WindowInterface::validateResizeRequest (unsigned int &mask,
4427
XWindowChanges *xwc,
4428
unsigned int source)
4429
WRAPABLE_DEF (validateResizeRequest, mask, xwc, source)
4432
WindowInterface::resizeNotify (int dx,
4436
WRAPABLE_DEF (resizeNotify, dx, dy, dwidth, dheight)
4439
WindowInterface::moveNotify (int dx,
4442
WRAPABLE_DEF (moveNotify, dx, dy, immediate)
4445
WindowInterface::windowNotify (CompWindowNotify n)
4446
WRAPABLE_DEF (windowNotify, n)
4449
WindowInterface::grabNotify (int x,
4453
WRAPABLE_DEF (grabNotify, x, y, state, mask)
4456
WindowInterface::ungrabNotify ()
4457
WRAPABLE_DEF (ungrabNotify)
4460
WindowInterface::stateChangeNotify (unsigned int lastState)
4461
WRAPABLE_DEF (stateChangeNotify, lastState)
4464
WindowInterface::updateFrameRegion (CompRegion ®ion)
4465
WRAPABLE_DEF (updateFrameRegion, region)
4468
WindowInterface::minimize ()
4469
WRAPABLE_DEF (minimize);
4472
WindowInterface::unminimize ()
4473
WRAPABLE_DEF (unminimize);
4476
WindowInterface::minimized ()
4477
WRAPABLE_DEF (minimized);
4480
WindowInterface::alpha ()
4481
WRAPABLE_DEF (alpha);
4484
WindowInterface::isFocussable ()
4485
WRAPABLE_DEF (isFocussable);
4488
WindowInterface::managed ()
4489
WRAPABLE_DEF (managed);
4504
CompWindow::state ()
4510
CompWindow::actions ()
4512
return priv->actions;
4516
CompWindow::protocols ()
4518
return priv->protocols;
4522
CompWindow::close (Time serverTime)
4524
if (serverTime == 0)
4525
serverTime = screen->getCurrentTime ();
4529
if (priv->protocols & CompWindowProtocolDeleteMask)
4533
ev.type = ClientMessage;
4534
ev.xclient.window = priv->id;
4535
ev.xclient.message_type = Atoms::wmProtocols;
4536
ev.xclient.format = 32;
4537
ev.xclient.data.l[0] = Atoms::wmDeleteWindow;
4538
ev.xclient.data.l[1] = serverTime;
4539
ev.xclient.data.l[2] = 0;
4540
ev.xclient.data.l[3] = 0;
4541
ev.xclient.data.l[4] = 0;
4543
XSendEvent (screen->dpy (), priv->id, false, NoEventMask, &ev);
4547
XKillClient (screen->dpy (), priv->id);
4550
priv->closeRequests++;
4554
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
4555
serverTime, priv->id, true, 0, 0);
4558
priv->lastCloseRequestTime = serverTime;
4562
PrivateWindow::handlePingTimeout (unsigned int lastPing)
4564
if (!window->isViewable ())
4567
if (!(priv->type & CompWindowTypeNormalMask))
4570
if (priv->protocols & CompWindowProtocolPingMask)
4572
if (priv->transientFor)
4575
if (priv->lastPong < lastPing)
4579
priv->alive = false;
4581
window->windowNotify (CompWindowNotifyAliveChanged);
4583
if (priv->closeRequests)
4585
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
4586
priv->lastCloseRequestTime,
4587
priv->id, true, 0, 0);
4589
priv->closeRequests = 0;
4600
PrivateWindow::handlePing (int lastPing)
4606
window->windowNotify (CompWindowNotifyAliveChanged);
4608
if (priv->lastCloseRequestTime)
4610
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
4611
priv->lastCloseRequestTime,
4612
priv->id, false, 0, 0);
4614
priv->lastCloseRequestTime = 0;
4617
priv->lastPong = lastPing;
4621
PrivateWindow::processMap ()
4624
CompStackingUpdateMode stackingMode;
4626
priv->initialViewport = screen->vp ();
4628
priv->initialTimestampSet = false;
4630
screen->priv->applyStartupProperties (window);
4634
priv->managed = true;
4638
int gravity = priv->sizeHints.win_gravity;
4642
/* adjust for gravity, but only for frame size */
4643
xwc.x = priv->serverGeometry.x ();
4644
xwc.y = priv->serverGeometry.y ();
4648
xwcm = adjustConfigureRequestForGravity (&xwc, CWX | CWY, gravity, 1);
4650
window->validateResizeRequest (xwcm, &xwc, ClientTypeApplication);
4652
CompPoint pos (xwc.x, xwc.y);
4653
if (window->place (pos))
4661
window->configureXWindow (xwcm, &xwc);
4663
priv->placed = true;
4666
allowFocus = allowWindowFocus (NO_FOCUS_MASK, 0);
4668
if (!allowFocus && (priv->type & ~NO_FOCUS_MASK))
4669
stackingMode = CompStackingUpdateModeInitialMapDeniedFocus;
4671
stackingMode = CompStackingUpdateModeInitialMap;
4673
window->updateAttributes (stackingMode);
4675
if (window->minimized ())
4676
window->unminimize ();
4678
screen->leaveShowDesktopMode (window);
4680
if (allowFocus && !window->onCurrentDesktop ())
4681
screen->priv->setCurrentDesktop (priv->desktop);
4683
if (!(priv->state & CompWindowStateHiddenMask))
4687
window->moveInputFocusTo ();
4691
* PrivateWindow::updatePassiveButtonGrabs
4693
* Updates the passive button grabs for a window. When
4694
* one of the specified button + modifier combinations
4695
* for this window is activated, compiz will be given
4696
* an active grab for the window (which we can turn off
4697
* by calling XAllowEvents later in ::handleEvent)
4699
* NOTE: ICCCM says that we are only allowed to grab
4700
* windows that we actually own as a client, so only
4701
* grab the frame window. Additionally, although there
4702
* isn't anything in the ICCCM that says we cannot
4703
* grab every button, some clients do not interpret
4704
* EnterNotify and LeaveNotify events caused by the
4705
* activation of the grab correctly, so ungrab button
4706
* and modifier combinations that we do not need on
4707
* active windows (but in reality we shouldn't be grabbing
4708
* for buttons that we don't actually need at that point
4713
PrivateWindow::updatePassiveButtonGrabs ()
4715
bool onlyActions = (priv->id == screen->priv->activeWindow ||
4716
!screen->priv->optionGetClickToFocus ());
4721
/* Ungrab everything */
4722
XUngrabButton (screen->priv->dpy, AnyButton, AnyModifier, frame);
4724
/* We don't need the full grab in the following cases:
4725
* - This window has the focus and either
4727
* - we don't want click raise
4732
if (screen->priv->optionGetRaiseOnClick ())
4734
for (CompWindow *above = window->next;
4735
above != NULL; above = above->next)
4737
if (above->priv->attrib.map_state != IsViewable)
4740
if (above->type () & CompWindowTypeDockMask)
4743
if (above->region ().intersects (region))
4745
onlyActions = false;
4754
/* Grab only we have bindings on */
4755
foreach (PrivateScreen::ButtonGrab &bind, screen->priv->buttonGrabs)
4757
for (unsigned int ignore = 0;
4758
ignore <= modHandler->ignoredModMask (); ignore++)
4760
if (ignore & ~modHandler->ignoredModMask ())
4762
XGrabButton (screen->priv->dpy,
4764
bind.modifiers | ignore,
4767
ButtonPressMask | ButtonReleaseMask |
4779
/* Grab everything */
4780
XGrabButton (screen->priv->dpy,
4784
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
4794
CompWindow::region () const
4796
return priv->region;
4800
CompWindow::frameRegion () const
4802
return priv->frameRegion;
4806
CompWindow::inShowDesktopMode ()
4808
return priv->inShowDesktopMode;
4812
CompWindow::setShowDesktopMode (bool value)
4814
priv->inShowDesktopMode = value;
4818
CompWindow::managed ()
4820
WRAPABLE_HND_FUNC_RETURN (18, bool, managed);
4821
return priv->managed;
4825
CompWindow::grabbed ()
4827
return priv->grabbed;
4831
CompWindow::pendingMaps ()
4833
return priv->pendingMaps;
4837
CompWindow::wmType ()
4839
return priv->wmType;
4843
CompWindow::activeNum ()
4845
return priv->activeNum;
4849
CompWindow::frame ()
4855
CompWindow::resName ()
4858
return priv->resName;
4860
return CompString ();
4864
CompWindow::mapNum () const
4866
return priv->mapNum;
4870
CompWindow::struts ()
4872
return priv->struts;
4876
CompWindow::saveMask ()
4878
return priv->saveMask;
4882
CompWindow::saveWc ()
4884
return priv->saveWc;
4888
CompWindow::moveToViewportPosition (int x,
4893
int vWidth = screen->width () * screen->vpSize ().width ();
4894
int vHeight = screen->height () * screen->vpSize ().height ();
4896
if (screen->vpSize ().width () != 1)
4898
x += screen->vp ().x () * screen->width ();
4899
x = MOD (x, vWidth);
4900
x -= screen->vp ().x () * screen->width ();
4903
if (screen->vpSize ().height () != 1)
4905
y += screen->vp ().y () * screen->height ();
4906
y = MOD (y, vHeight);
4907
y -= screen->vp ().y () * screen->height ();
4910
tx = x - priv->attrib.x;
4911
ty = y - priv->attrib.y;
4920
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
4923
if (priv->state & CompWindowStateStickyMask)
4929
if (screen->vpSize ().width ()!= 1)
4931
m = priv->attrib.x + tx;
4933
if (m - priv->output.left < (int) screen->width () - vWidth)
4935
else if (m + priv->width + priv->output.right > vWidth)
4939
if (screen->vpSize ().height () != 1)
4941
m = priv->attrib.y + ty;
4943
if (m - priv->output.top < (int) screen->height () - vHeight)
4945
else if (m + priv->height + priv->output.bottom > vHeight)
4949
if (priv->saveMask & CWX)
4950
priv->saveWc.x += wx;
4952
if (priv->saveMask & CWY)
4953
priv->saveWc.y += wy;
4963
CompWindow::startupId ()
4965
return priv->startupId;
4969
PrivateWindow::applyStartupProperties (CompStartupSequence *s)
4973
priv->initialViewport.setX (s->viewportX);
4974
priv->initialViewport.setY (s->viewportY);
4976
workspace = sn_startup_sequence_get_workspace (s->sequence);
4978
window->setDesktop (workspace);
4980
priv->initialTimestamp =
4981
sn_startup_sequence_get_timestamp (s->sequence);
4982
priv->initialTimestampSet = true;
4986
CompWindow::desktop ()
4988
return priv->desktop;
4992
CompWindow::clientLeader (bool checkAncestor)
4994
if (priv->clientLeader)
4995
return priv->clientLeader;
4998
return priv->getClientLeaderOfAncestor ();
5004
CompWindow::transientFor ()
5006
return priv->transientFor;
5010
CompWindow::pendingUnmaps ()
5012
return priv->pendingUnmaps;
5016
CompWindow::minimized ()
5018
WRAPABLE_HND_FUNC_RETURN (15, bool, minimized);
5019
return priv->minimized;
5023
CompWindow::placed ()
5025
return priv->placed;
5029
CompWindow::shaded ()
5031
return priv->shaded;
5035
CompWindow::input () const
5041
CompWindow::output () const
5043
return priv->output;
5047
CompWindow::sizeHints () const
5049
return priv->sizeHints;
5053
PrivateWindow::updateMwmHints ()
5055
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
5056
window->recalcActions ();
5060
PrivateWindow::updateStartupId ()
5062
char *oldId = startupId;
5065
startupId = getStartupId ();
5069
if (strcmp (startupId, oldId) == 0)
5075
if (managed && startupId && newId)
5082
initialTimestampSet = false;
5083
screen->priv->applyStartupProperties (window);
5085
if (initialTimestampSet)
5086
timestamp = initialTimestamp;
5088
/* as the viewport can't be transmitted via startup
5089
notification, assume the client changing the ID
5090
wanted to activate the window on the current viewport */
5092
vp = window->defaultViewport ();
5093
svp = screen->vp ();
5096
x = window->geometry ().x () + (svp.x () - vp.x ()) * size.width ();
5097
y = window->geometry ().y () + (svp.y () - vp.y ()) * size.height ();
5098
window->moveToViewportPosition (x, y, true);
5100
if (allowWindowFocus (0, timestamp))
5101
window->activate ();
5106
CompWindow::destroyed ()
5108
return priv->destroyed;
5112
CompWindow::invisible ()
5114
return priv->invisible;
5118
CompWindow::syncAlarm ()
5120
return priv->syncAlarm;
5124
CompWindow::CompWindow (Window id,
5126
PluginClassStorage (windowPluginClassIndices)
5128
priv = new PrivateWindow (this);
5131
/* Failure means that window has been destroyed. We still have to add the
5132
window to the window list as we might get configure requests which
5133
require us to stack other windows relative to it. Setting some default
5134
values if this is the case. */
5135
if (!XGetWindowAttributes (screen->dpy (), id, &priv->attrib))
5136
setDefaultWindowAttributes (&priv->attrib);
5138
priv->serverGeometry.set (priv->attrib.x, priv->attrib.y,
5139
priv->attrib.width, priv->attrib.height,
5140
priv->attrib.border_width);
5141
priv->syncGeometry.set (priv->attrib.x, priv->attrib.y,
5142
priv->attrib.width, priv->attrib.height,
5143
priv->attrib.border_width);
5144
priv->geometry.set (priv->attrib.x, priv->attrib.y,
5145
priv->attrib.width, priv->attrib.height,
5146
priv->attrib.border_width);
5148
priv->width = priv->attrib.width + priv->attrib.border_width * 2;
5149
priv->height = priv->attrib.height + priv->attrib.border_width * 2;
5151
priv->sizeHints.flags = 0;
5153
priv->recalcNormalHints ();
5155
priv->transientFor = None;
5156
priv->clientLeader = None;
5158
XSelectInput (screen->dpy (), id,
5160
PropertyChangeMask |
5165
priv->alpha = (depth () == 32);
5166
priv->lastPong = screen->priv->lastPing;
5168
if (screen->XShape ())
5169
XShapeSelectInput (screen->dpy (), id, ShapeNotifyMask);
5171
screen->insertWindow (this, aboveId);
5173
if (windowClass () != InputOnly)
5175
priv->region = CompRegion (priv->attrib.x, priv->attrib.y,
5176
priv->width, priv->height);
5177
priv->inputRegion = priv->region;
5179
/* need to check for DisplayModal state on all windows */
5180
priv->state = screen->priv->getWindowState (priv->id);
5182
priv->updateClassHints ();
5186
priv->attrib.map_state = IsUnmapped;
5189
priv->wmType = screen->priv->getWindowType (priv->id);
5190
priv->protocols = screen->priv->getProtocols (priv->id);
5192
if (!overrideRedirect ())
5194
priv->updateNormalHints ();
5196
priv->updateWmHints ();
5197
priv->updateTransientHint ();
5199
priv->clientLeader = priv->getClientLeader ();
5200
priv->startupId = priv->getStartupId ();
5204
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
5206
if (!(priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask)))
5208
priv->desktop = screen->getWindowProp (priv->id, Atoms::winDesktop,
5210
if (priv->desktop != 0xffffffff)
5212
if (priv->desktop >= screen->nDesktop ())
5213
priv->desktop = screen->currentDesktop ();
5222
if (priv->attrib.map_state == IsViewable)
5224
priv->placed = true;
5226
if (!overrideRedirect ())
5230
priv->managed = true;
5232
if (screen->priv->getWmState (priv->id) == IconicState)
5234
if (priv->state & CompWindowStateShadedMask)
5235
priv->shaded = true;
5237
priv->minimized = true;
5241
if (priv->wmType & (CompWindowTypeDockMask |
5242
CompWindowTypeDesktopMask))
5244
setDesktop (0xffffffff);
5248
if (priv->desktop != 0xffffffff)
5249
priv->desktop = screen->currentDesktop ();
5251
screen->setWindowProp (priv->id, Atoms::winDesktop,
5257
priv->attrib.map_state = IsUnmapped;
5258
priv->pendingMaps++;
5262
updateAttributes (CompStackingUpdateModeNormal);
5264
if (priv->minimized || priv->inShowDesktopMode ||
5265
priv->hidden || priv->shaded)
5267
priv->state |= CompWindowStateHiddenMask;
5269
priv->pendingUnmaps++;
5271
if (priv->frame && !priv->shaded)
5272
XUnmapWindow (screen->dpy (), priv->frame);
5274
XUnmapWindow (screen->dpy (), priv->id);
5276
screen->priv->setWindowState (priv->state, priv->id);
5279
else if (!overrideRedirect ())
5281
if (screen->priv->getWmState (priv->id) == IconicState)
5285
priv->managed = true;
5286
priv->placed = true;
5288
if (priv->state & CompWindowStateHiddenMask)
5290
if (priv->state & CompWindowStateShadedMask)
5291
priv->shaded = true;
5293
priv->minimized = true;
5298
/* TODO: bailout properly when objectInitPlugins fails */
5299
assert (CompPlugin::windowInitPlugins (this));
5302
priv->updateIconGeometry ();
5305
resize (priv->attrib.x, priv->attrib.y,
5306
priv->attrib.width, ++priv->attrib.height - 1,
5307
priv->attrib.border_width);
5309
if (priv->attrib.map_state == IsViewable)
5311
priv->invisible = WINDOW_INVISIBLE (priv);
5315
CompWindow::~CompWindow ()
5317
screen->unhookWindow (this);
5319
if (!priv->destroyed)
5323
priv->unreparent ();
5326
/* restore saved geometry and map if hidden */
5327
if (!priv->attrib.override_redirect)
5330
XConfigureWindow (screen->dpy (), priv->id,
5331
priv->saveMask, &priv->saveWc);
5335
if (priv->state & CompWindowStateHiddenMask)
5336
XMapWindow (screen->dpy (), priv->id);
5340
if (screen->XShape ())
5341
XShapeSelectInput (screen->dpy (), priv->id, NoEventMask);
5343
if (priv->id != screen->priv->grabWindow)
5344
XSelectInput (screen->dpy (), priv->id, NoEventMask);
5346
XUngrabButton (screen->dpy (), AnyButton, AnyModifier, priv->id);
5349
if (priv->attrib.map_state == IsViewable)
5351
if (priv->type == CompWindowTypeDesktopMask)
5352
screen->priv->desktopWindowCount--;
5354
if (priv->destroyed && priv->struts)
5355
screen->updateWorkarea ();
5358
if (priv->destroyed)
5359
screen->priv->updateClientList ();
5361
CompPlugin::windowFiniPlugins (this);
5366
PrivateWindow::PrivateWindow (CompWindow *window) :
5375
transientFor (None),
5376
clientLeader (None),
5384
type (CompWindowTypeUnknownMask),
5388
mwmDecor (MwmDecorAll),
5389
mwmFunc (MwmFuncAll),
5397
initialViewport (0, 0),
5399
initialTimestamp (0),
5400
initialTimestampSet (false),
5402
fullscreenMonitorsSet (false),
5406
inShowDesktopMode (false),
5436
closeRequests (false),
5437
lastCloseRequestTime (0)
5449
syncWaitTimer.setTimes (1000, 1200);
5450
syncWaitTimer.setCallback (boost::bind (&PrivateWindow::handleSyncAlarm,
5454
PrivateWindow::~PrivateWindow ()
5457
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
5459
syncWaitTimer.stop ();
5462
XDestroyWindow (screen->dpy (), frame);
5484
CompWindow::syncWait ()
5486
return priv->syncWait;
5490
CompWindow::alpha ()
5492
WRAPABLE_HND_FUNC_RETURN (16, bool, alpha);
5498
CompWindow::overrideRedirect ()
5500
return priv->attrib.override_redirect;
5504
PrivateWindow::setOverrideRedirect (bool overrideRedirect)
5506
if (overrideRedirect == window->overrideRedirect ())
5509
priv->attrib.override_redirect = overrideRedirect ? 1 : 0;
5510
window->recalcType ();
5511
window->recalcActions ();
5513
screen->matchPropertyChanged (window);
5517
CompWindow::isMapped () const
5519
return priv->mapNum > 0;
5523
CompWindow::isViewable () const
5525
return (priv->attrib.map_state == IsViewable);
5529
CompWindow::isFocussable ()
5531
WRAPABLE_HND_FUNC_RETURN (17, bool, isFocussable);
5533
if (priv->inputHint)
5536
if (priv->protocols & CompWindowProtocolTakeFocusMask)
5543
CompWindow::windowClass ()
5545
return priv->attrib.c_class;
5549
CompWindow::depth ()
5551
return priv->attrib.depth;
5555
CompWindow::alive ()
5561
CompWindow::mwmDecor ()
5563
return priv->mwmDecor;
5567
CompWindow::mwmFunc ()
5569
return priv->mwmFunc;
5572
/* TODO: This function should be able to check the XShape event
5573
* kind and only get/set shape rectangles for either ShapeInput
5574
* or ShapeBounding, but not both at the same time
5578
CompWindow::updateFrameRegion ()
5580
if (priv->frame && priv->serverGeometry.width () == priv->geometry.width () &&
5581
priv->serverGeometry.height () == priv->geometry.height ())
5586
priv->frameRegion = CompRegion ();
5588
updateFrameRegion (priv->frameRegion);
5592
r = priv->region.boundingRect ();
5593
priv->frameRegion -= r;
5595
r.setGeometry (r.x1 () - priv->input.left,
5596
r.y1 () - priv->input.top,
5597
r.width () + priv->input.right + priv->input.left,
5598
r.height () + priv->input.bottom + priv->input.top);
5600
priv->frameRegion &= CompRegion (r);
5603
x = priv->geometry.x () - priv->input.left;
5604
y = priv->geometry.y () - priv->input.top;
5606
XShapeCombineRegion (screen->dpy (), priv->frame,
5607
ShapeBounding, -x, -y,
5608
priv->frameRegion.united (priv->region).handle (),
5611
XShapeCombineRegion (screen->dpy (), priv->frame,
5613
priv->frameRegion.united (priv->inputRegion).handle (),
5619
CompWindow::setWindowFrameExtents (CompWindowExtents *i)
5621
if (priv->input.left != i->left ||
5622
priv->input.right != i->right ||
5623
priv->input.top != i->top ||
5624
priv->input.bottom != i->bottom)
5626
unsigned long data[4];
5630
priv->updateFrameWindow ();
5631
priv->updateSize ();
5637
data[3] = i->bottom;
5639
XChangeProperty (screen->dpy (), priv->id,
5640
Atoms::frameExtents,
5641
XA_CARDINAL, 32, PropModeReplace,
5642
(unsigned char *) data, 4);
5647
CompWindow::hasUnmapReference ()
5649
return (priv && priv->unmapRefCnt > 1);
5653
CompWindow::updateFrameRegion (CompRegion& region)
5654
WRAPABLE_HND_FUNC (12, updateFrameRegion, region)
5657
PrivateWindow::reparent ()
5659
XSetWindowAttributes attr;
5660
XWindowAttributes wa;
5663
CompWindow::Geometry sg = serverGeometry;
5664
Display *dpy = screen->dpy ();
5665
CompWindow *sibling = window->next ? window->next : window->prev;
5666
bool above = window->next ? false : true;
5668
unsigned int uidummy;
5670
Visual *visual = DefaultVisual (screen->dpy (),
5671
screen->screenNum ());
5672
Colormap cmap = DefaultColormap (screen->dpy (),
5673
screen->screenNum ());
5675
if (frame || attrib.override_redirect)
5681
if (!XGetGeometry (screen->dpy (), id, &root_ret, &idummy, &idummy, &uidummy, &uidummy, &uidummy, &uidummy) ||
5682
!XGetWindowAttributes (dpy, id, &wa))
5684
XUngrabServer (dpy);
5689
XChangeSaveSet (dpy, id, SetModeInsert);
5690
XSelectInput (dpy, id, NoEventMask);
5691
XSelectInput (dpy, screen->root (), NoEventMask);
5693
xwc.border_width = 0;
5694
XConfigureWindow (dpy, id, CWBorderWidth, &xwc);
5696
mask = CWBorderPixel | CWColormap | CWBackPixmap;
5698
if (attrib.depth == 32)
5700
cmap = attrib.colormap;
5701
visual = attrib.visual;
5704
attr.background_pixmap = None;
5705
attr.border_pixel = 0;
5706
attr.colormap = cmap;
5708
frame = XCreateWindow (dpy, screen->root (), 0, 0,
5709
sg.width (), sg.height (), 0, attrib.depth,
5710
InputOutput, visual, mask, &attr);
5712
wrapper = XCreateWindow (dpy, frame, 0, 0,
5713
sg.width (), sg.height (), 0, attrib.depth,
5714
InputOutput, visual, mask, &attr);
5716
XMapWindow (dpy, wrapper);
5717
XReparentWindow (dpy, id, wrapper, 0, 0);
5719
attr.event_mask = PropertyChangeMask | FocusChangeMask |
5720
EnterWindowMask | LeaveWindowMask;
5722
/* We don't care about client events on the frame, and listening for them
5723
* will probably end up fighting the client anyways, so disable them */
5724
attr.do_not_propagate_mask = KeyPressMask | KeyReleaseMask |
5725
ButtonPressMask | ButtonReleaseMask |
5726
EnterWindowMask | LeaveWindowMask |
5727
PointerMotionMask | PointerMotionHintMask |
5728
Button1MotionMask | Button2MotionMask |
5729
Button3MotionMask | Button4MotionMask |
5730
Button5MotionMask | ButtonMotionMask |
5731
KeymapStateMask | ExposureMask |
5732
VisibilityChangeMask | StructureNotifyMask |
5733
ResizeRedirectMask | SubstructureNotifyMask |
5734
SubstructureRedirectMask | FocusChangeMask |
5735
PropertyChangeMask | ColormapChangeMask |
5736
OwnerGrabButtonMask;
5738
XChangeWindowAttributes (dpy, id, CWEventMask | CWDontPropagate, &attr);
5740
if (wa.map_state == IsViewable || shaded)
5741
XMapWindow (dpy, frame);
5743
attr.event_mask = SubstructureRedirectMask | StructureNotifyMask |
5744
SubstructureNotifyMask | EnterWindowMask |
5747
XChangeWindowAttributes (dpy, frame, CWEventMask, &attr);
5748
XChangeWindowAttributes (dpy, wrapper, CWEventMask, &attr);
5750
XSelectInput (dpy, screen->root (),
5751
SubstructureRedirectMask |
5752
SubstructureNotifyMask |
5753
StructureNotifyMask |
5754
PropertyChangeMask |
5764
XUngrabServer (dpy);
5766
XMoveResizeWindow (dpy, frame, sg.x (), sg.y (), sg.width (), sg.height ());
5768
/* Try to use a relative window as a stacking anchor point */
5772
window->restackAbove (sibling);
5774
priv->restack (sibling->id ());
5777
window->windowNotify (CompWindowNotifyReparent);
5783
PrivateWindow::unreparent ()
5785
Display *dpy = screen->dpy ();
5795
if (XCheckTypedWindowEvent (dpy, id, DestroyNotify, &e))
5797
XPutBackEvent (dpy, &e);
5801
if ((!destroyed) && alive)
5805
XChangeSaveSet (dpy, id, SetModeDelete);
5806
XSelectInput (dpy, frame, NoEventMask);
5807
XSelectInput (dpy, id, NoEventMask);
5808
XSelectInput (dpy, screen->root (), NoEventMask);
5809
XReparentWindow (dpy, id, screen->root (), 0, 0);
5811
xwc.stack_mode = Below;
5812
xwc.sibling = frame;
5813
XConfigureWindow (dpy, id, CWSibling | CWStackMode, &xwc);
5815
XUnmapWindow (dpy, frame);
5817
XSelectInput (dpy, id, PropertyChangeMask | EnterWindowMask |
5820
XSelectInput (dpy, screen->root (),
5821
SubstructureRedirectMask |
5822
SubstructureNotifyMask |
5823
StructureNotifyMask |
5824
PropertyChangeMask |
5834
XUngrabServer (dpy);
5836
XMoveWindow (dpy, id, serverGeometry.x (), serverGeometry.y ());
5839
XDestroyWindow (dpy, wrapper);
5840
XDestroyWindow (dpy, frame);
5844
window->windowNotify (CompWindowNotifyUnreparent);