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
/* Geometry is the same, so we're not going to get a ConfigureNotify
785
* event when the window is configured, which means that other plugins
786
* won't know that the client, frame and wrapper windows got shifted
787
* around (and might result in display corruption, eg in OpenGL */
788
if (geometry.x () - input.left == x &&
789
geometry.y () - input.top == y &&
790
geometry.width () + input.left + input.right + bw == width &&
791
geometry.height () + input.top + input.bottom + bw == height)
795
xev.type = ConfigureNotify;
796
xev.event = screen->root ();
797
xev.window = priv->frame;
803
xev.border_width = window->priv->attrib.border_width;
805
xev.above = (window->prev) ? ROOTPARENT (window->prev) : None;
806
xev.override_redirect = window->priv->attrib.override_redirect;
808
XSendEvent (screen->dpy (), screen->root (), false,
809
SubstructureNotifyMask, (XEvent *) &xev);
812
XMoveResizeWindow (screen->dpy (), frame, x, y, width, height);
816
XUnmapWindow (screen->dpy (), wrapper);
820
XMapWindow (screen->dpy (), wrapper);
821
XMoveResizeWindow (screen->dpy (), wrapper, input.left, input.top,
822
serverGeometry.width (), serverGeometry.height ());
824
XMoveResizeWindow (screen->dpy (), id, 0, 0,
825
serverGeometry.width (), serverGeometry.height ());
826
window->sendConfigureNotify ();
828
window->updateFrameRegion ();
829
window->windowNotify (CompWindowNotifyFrameUpdate);
833
int x, y, width, height;
834
int bw = serverGeometry.border () * 2;
836
x = serverGeometry.x ();
837
y = serverGeometry.y ();
838
width = serverGeometry.width () + bw;
839
height = serverGeometry.height () + bw;
844
XMoveResizeWindow (screen->dpy (), frame, x, y, width, height);
847
XUnmapWindow (screen->dpy (), wrapper);
851
XMapWindow (screen->dpy (), wrapper);
852
XMoveResizeWindow (screen->dpy (), wrapper, 0, 0,
853
serverGeometry.width (), serverGeometry.height ());
856
XMoveResizeWindow (screen->dpy (), id, 0, 0,
857
serverGeometry.width (), serverGeometry.height ());
858
window->sendConfigureNotify ();
859
frameRegion = CompRegion ();
860
window->windowNotify (CompWindowNotifyFrameUpdate);
862
window->recalcActions ();
868
CompWindow::updateWindowOutputExtents ()
870
CompWindowExtents output (priv->output);
872
getOutputExtents (output);
874
if (output.left != priv->output.left ||
875
output.right != priv->output.right ||
876
output.top != priv->output.top ||
877
output.bottom != priv->output.bottom)
879
priv->output = output;
881
resizeNotify (0, 0, 0, 0);
886
CompWindow::getOutputExtents (CompWindowExtents& output)
888
WRAPABLE_HND_FUNC (0, getOutputExtents, output)
897
PrivateWindow::rectsToRegion (unsigned int n, XRectangle *rects)
902
for (unsigned int i = 0; i < n; i++)
904
x1 = rects[i].x + priv->geometry.border ();
905
y1 = rects[i].y + priv->geometry.border ();
906
x2 = x1 + rects[i].width;
907
y2 = y1 + rects[i].height;
913
if (x2 > priv->width)
915
if (y2 > priv->height)
918
if (y1 < y2 && x1 < x2)
920
x1 += priv->geometry.x ();
921
y1 += priv->geometry.y ();
922
x2 += priv->geometry.x ();
923
y2 += priv->geometry.y ();
925
ret += CompRect (x1, y1, x2 - x1, y2 - y1);
932
/* TODO: This function should be able to check the XShape event
933
* kind and only get/set shape rectangles for either ShapeInput
934
* or ShapeBounding, but not both at the same time
938
PrivateWindow::updateRegion ()
940
XRectangle r, *boundingShapeRects = NULL;
941
XRectangle *inputShapeRects = NULL;
942
int nBounding = 0, nInput = 0;
944
priv->region = CompRegion ();
945
priv->inputRegion = CompRegion ();
947
if (screen->XShape ())
951
boundingShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
952
ShapeBounding, &nBounding, &order);
953
inputShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
954
ShapeInput, &nInput, &order);
958
r.x = -priv->attrib.border_width;
959
r.y = -priv->attrib.border_width;
960
r.width = priv->width + priv->attrib.border_width;
961
r.height = priv->height + priv->attrib.border_width;
965
boundingShapeRects = &r;
971
inputShapeRects = &r;
975
priv->region += rectsToRegion (nBounding, boundingShapeRects);
976
priv->inputRegion += rectsToRegion (nInput, inputShapeRects);
978
if (boundingShapeRects && boundingShapeRects != &r)
979
XFree (boundingShapeRects);
980
if (inputShapeRects && inputShapeRects != &r)
981
XFree (inputShapeRects);
983
window->updateFrameRegion ();
987
CompWindow::updateStruts ()
991
unsigned long n, left;
994
CompStruts oldStrut, newStrut;
1000
oldStrut.left = priv->struts->left;
1001
oldStrut.right = priv->struts->right;
1002
oldStrut.top = priv->struts->top;
1003
oldStrut.bottom = priv->struts->bottom;
1012
newStrut.left.x = 0;
1013
newStrut.left.y = 0;
1014
newStrut.left.width = 0;
1015
newStrut.left.height = screen->height ();
1017
newStrut.right.x = screen->width ();
1018
newStrut.right.y = 0;
1019
newStrut.right.width = 0;
1020
newStrut.right.height = screen->height ();
1024
newStrut.top.width = screen->width ();
1025
newStrut.top.height = 0;
1027
newStrut.bottom.x = 0;
1028
newStrut.bottom.y = screen->height ();
1029
newStrut.bottom.width = screen->width ();
1030
newStrut.bottom.height = 0;
1032
result = XGetWindowProperty (screen->dpy (), priv->id,
1033
Atoms::wmStrutPartial,
1034
0L, 12L, false, XA_CARDINAL, &actual, &format,
1037
if (result == Success && data)
1039
unsigned long *struts = (unsigned long *) data;
1045
newStrut.left.y = struts[4];
1046
newStrut.left.width = struts[0];
1047
newStrut.left.height = struts[5] - newStrut.left.y + 1;
1049
newStrut.right.width = struts[1];
1050
newStrut.right.x = screen->width () - newStrut.right.width;
1051
newStrut.right.y = struts[6];
1052
newStrut.right.height = struts[7] - newStrut.right.y + 1;
1054
newStrut.top.x = struts[8];
1055
newStrut.top.width = struts[9] - newStrut.top.x + 1;
1056
newStrut.top.height = struts[2];
1058
newStrut.bottom.x = struts[10];
1059
newStrut.bottom.width = struts[11] - newStrut.bottom.x + 1;
1060
newStrut.bottom.height = struts[3];
1061
newStrut.bottom.y = screen->height () - newStrut.bottom.height;
1069
result = XGetWindowProperty (screen->dpy (), priv->id,
1071
0L, 4L, false, XA_CARDINAL,
1072
&actual, &format, &n, &left, &data);
1074
if (result == Success && data)
1076
unsigned long *struts = (unsigned long *) data;
1082
newStrut.left.x = 0;
1083
newStrut.left.width = struts[0];
1085
newStrut.right.width = struts[1];
1086
newStrut.right.x = screen->width () - newStrut.right.width;
1089
newStrut.top.height = struts[2];
1091
newStrut.bottom.height = struts[3];
1092
newStrut.bottom.y = screen->height () - newStrut.bottom.height;
1101
int strutX1, strutY1, strutX2, strutY2;
1104
/* applications expect us to clip struts to xinerama edges */
1105
for (unsigned int i = 0;
1106
i < screen->screenInfo ().size (); i++)
1108
x1 = screen->screenInfo ()[i].x_org;
1109
y1 = screen->screenInfo ()[i].y_org;
1110
x2 = x1 + screen->screenInfo ()[i].width;
1111
y2 = y1 + screen->screenInfo ()[i].height;
1113
strutX1 = newStrut.left.x;
1114
strutX2 = strutX1 + newStrut.left.width;
1115
strutY1 = newStrut.left.y;
1116
strutY2 = strutY1 + newStrut.left.height;
1118
if (strutX2 > x1 && strutX2 <= x2 &&
1119
strutY1 < y2 && strutY2 > y1)
1121
newStrut.left.x = x1;
1122
newStrut.left.width = strutX2 - x1;
1125
strutX1 = newStrut.right.x;
1126
strutX2 = strutX1 + newStrut.right.width;
1127
strutY1 = newStrut.right.y;
1128
strutY2 = strutY1 + newStrut.right.height;
1130
if (strutX1 > x1 && strutX1 <= x2 &&
1131
strutY1 < y2 && strutY2 > y1)
1133
newStrut.right.x = strutX1;
1134
newStrut.right.width = x2 - strutX1;
1137
strutX1 = newStrut.top.x;
1138
strutX2 = strutX1 + newStrut.top.width;
1139
strutY1 = newStrut.top.y;
1140
strutY2 = strutY1 + newStrut.top.height;
1142
if (strutX1 < x2 && strutX2 > x1 &&
1143
strutY2 > y1 && strutY2 <= y2)
1145
newStrut.top.y = y1;
1146
newStrut.top.height = strutY2 - y1;
1149
strutX1 = newStrut.bottom.x;
1150
strutX2 = strutX1 + newStrut.bottom.width;
1151
strutY1 = newStrut.bottom.y;
1152
strutY2 = strutY1 + newStrut.bottom.height;
1154
if (strutX1 < x2 && strutX2 > x1 &&
1155
strutY1 > y1 && strutY1 <= y2)
1157
newStrut.bottom.y = strutY1;
1158
newStrut.bottom.height = y2 - strutY1;
1163
if (hasOld != hasNew ||
1164
(hasNew && hasOld &&
1165
memcmp (&newStrut, &oldStrut, sizeof (CompStruts))))
1171
priv->struts = (CompStruts *) malloc (sizeof (CompStruts));
1176
*priv->struts = newStrut;
1180
free (priv->struts);
1181
priv->struts = NULL;
1191
CompWindow::incrementDestroyReference ()
1193
priv->destroyRefCnt++;
1197
CompWindow::destroy ()
1199
windowNotify (CompWindowNotifyBeforeDestroy);
1201
screen->priv->eraseWindowFromMap (id ());
1206
priv->destroyRefCnt--;
1207
if (priv->destroyRefCnt)
1211
if (!priv->destroyed)
1213
priv->destroyed = true;
1214
screen->priv->pendingDestroys++;
1218
priv->unreparent ();
1223
CompWindow::sendConfigureNotify ()
1225
XConfigureEvent xev;
1227
xev.type = ConfigureNotify;
1228
xev.event = priv->id;
1229
xev.window = priv->id;
1231
/* normally we should never send configure notify events to override
1232
redirect windows but if they support the _NET_WM_SYNC_REQUEST
1233
protocol we need to do this when the window is mapped. however the
1234
only way we can make sure that the attributes we send are correct
1235
and is to grab the server. */
1236
if (priv->attrib.override_redirect)
1238
XWindowAttributes attrib;
1240
XGrabServer (screen->dpy ());
1242
if (XGetWindowAttributes (screen->dpy (), priv->id, &attrib))
1246
xev.width = attrib.width;
1247
xev.height = attrib.height;
1248
xev.border_width = attrib.border_width;
1250
xev.above = (prev) ? prev->priv->id : None;
1251
xev.override_redirect = true;
1253
XSendEvent (screen->dpy (), priv->id, false,
1254
StructureNotifyMask, (XEvent *) &xev);
1257
XUngrabServer (screen->dpy ());
1261
xev.x = priv->serverGeometry.x ();
1262
xev.y = priv->serverGeometry.y ();
1263
xev.width = priv->serverGeometry.width ();
1264
xev.height = priv->serverGeometry.height ();
1265
xev.border_width = priv->serverGeometry.border ();
1267
xev.above = (prev) ? prev->priv->id : None;
1268
xev.override_redirect = priv->attrib.override_redirect;
1270
XSendEvent (screen->dpy (), priv->id, false,
1271
StructureNotifyMask, (XEvent *) &xev);
1278
windowNotify (CompWindowNotifyBeforeMap);
1282
if (priv->pendingMaps > 0)
1283
priv->pendingMaps = 0;
1285
priv->mapNum = screen->priv->mapNum++;
1288
screen->updateWorkarea ();
1290
if (windowClass () == InputOnly)
1293
priv->unmapRefCnt = 1;
1295
priv->attrib.map_state = IsViewable;
1297
if (!overrideRedirect ())
1298
screen->priv->setWmState (NormalState, priv->id);
1300
priv->invisible = true;
1303
priv->lastPong = screen->priv->lastPing;
1305
priv->updateRegion ();
1306
priv->updateSize ();
1308
screen->priv->updateClientList ();
1310
if (priv->type & CompWindowTypeDesktopMask)
1311
screen->priv->desktopWindowCount++;
1313
if (priv->protocols & CompWindowProtocolSyncRequestMask)
1316
sendConfigureNotify ();
1319
if (!overrideRedirect ())
1324
priv->geometry.setHeight (priv->geometry.height () + 1);
1325
resize (priv->geometry.x (), priv->geometry.y (), priv->geometry.width (),
1326
priv->geometry.height () - 1, priv->geometry.border ());
1331
windowNotify (CompWindowNotifyMap);
1335
CompWindow::incrementUnmapReference ()
1337
priv->unmapRefCnt++;
1341
CompWindow::unmap ()
1343
windowNotify (CompWindowNotifyBeforeUnmap);
1348
/* Even though we're still keeping the backing
1349
* pixmap of the window around, it's safe to
1350
* unmap the frame window since there's no use
1351
* for it at this point anyways and it just blocks
1354
XUnmapWindow (screen->dpy (), priv->wrapper);
1355
XUnmapWindow (screen->dpy (), priv->frame);
1357
priv->unmapRefCnt--;
1358
if (priv->unmapRefCnt > 0)
1361
if (priv->unmanaging)
1365
int gravity = priv->sizeHints.win_gravity;
1368
priv->unreparent ();
1370
/* revert gravity adjustment made at MapNotify time */
1371
xwc.x = priv->serverGeometry.x ();
1372
xwc.y = priv->serverGeometry.y ();
1376
xwcm = priv->adjustConfigureRequestForGravity (&xwc,
1381
configureXWindow (xwcm, &xwc);
1383
priv->unmanaging = false;
1387
screen->updateWorkarea ();
1389
if (priv->attrib.map_state != IsViewable)
1392
if (priv->type == CompWindowTypeDesktopMask)
1393
screen->priv->desktopWindowCount--;
1395
priv->attrib.map_state = IsUnmapped;
1397
priv->invisible = true;
1399
if (priv->shaded && priv->height)
1400
resize (priv->attrib.x, priv->attrib.y,
1401
priv->attrib.width, ++priv->attrib.height - 1,
1402
priv->attrib.border_width);
1404
screen->priv->updateClientList ();
1406
windowNotify (CompWindowNotifyUnmap);
1410
PrivateWindow::withdraw ()
1412
if (!attrib.override_redirect)
1413
screen->priv->setWmState (WithdrawnState, id);
1416
unmanaging = managed;
1421
PrivateWindow::restack (Window aboveId)
1423
if (aboveId && (aboveId == id || aboveId == frame))
1424
// Don't try to raise a window above itself
1426
else if (window->prev)
1428
if (aboveId && (aboveId == window->prev->id () ||
1429
aboveId == window->prev->frame ()))
1432
else if (aboveId == None && !window->next)
1435
if (aboveId && !screen->findTopLevelWindow (aboveId, true))
1438
screen->unhookWindow (window);
1439
screen->insertWindow (window, aboveId);
1441
screen->priv->updateClientList ();
1443
window->windowNotify (CompWindowNotifyRestack);
1449
CompWindow::resize (XWindowAttributes attr)
1451
return resize (Geometry (attr.x, attr.y, attr.width, attr.height,
1452
attr.border_width));
1456
CompWindow::resize (int x,
1462
return resize (Geometry (x, y, width, height, border));
1466
CompWindow::resize (CompWindow::Geometry gm)
1468
if (priv->geometry.width () != gm.width () ||
1469
priv->geometry.height () != gm.height () ||
1470
priv->geometry.border () != gm.border ())
1473
int dx, dy, dwidth, dheight;
1475
pw = gm.width () + gm.border () * 2;
1476
ph = gm.height () + gm.border () * 2;
1481
dx = gm.x () - priv->geometry.x ();
1482
dy = gm.y () - priv->geometry.y ();
1483
dwidth = gm.width () - priv->geometry.width ();
1484
dheight = gm.height () - priv->geometry.height ();
1486
priv->geometry.set (gm.x (), gm.y (),
1487
gm.width (), gm.height (),
1494
priv->updateRegion ();
1496
resizeNotify (dx, dy, dwidth, dheight);
1498
priv->invisible = WINDOW_INVISIBLE (priv);
1499
priv->updateFrameWindow ();
1501
else if (priv->geometry.x () != gm.x () || priv->geometry.y () != gm.y ())
1505
dx = gm.x () - priv->geometry.x ();
1506
dy = gm.y () - priv->geometry.y ();
1515
syncValueIncrement (XSyncValue *value)
1520
XSyncIntToValue (&one, 1);
1521
XSyncValueAdd (value, *value, one, &overflow);
1525
PrivateWindow::initializeSyncCounter ()
1527
XSyncAlarmAttributes values;
1530
unsigned long n, left;
1531
unsigned char *data;
1534
return syncAlarm != None;
1536
if (!(protocols & CompWindowProtocolSyncRequestMask))
1539
result = XGetWindowProperty (screen->dpy (), id,
1540
Atoms::wmSyncRequestCounter,
1541
0L, 1L, false, XA_CARDINAL, &actual, &format,
1544
if (result == Success && n && data)
1546
unsigned long *counter = (unsigned long *) data;
1548
syncCounter = *counter;
1552
XSyncIntsToValue (&syncValue, (unsigned int) rand (), 0);
1553
XSyncSetCounter (screen->dpy (),
1557
syncValueIncrement (&syncValue);
1559
values.events = true;
1561
values.trigger.counter = syncCounter;
1562
values.trigger.wait_value = syncValue;
1564
values.trigger.value_type = XSyncAbsolute;
1565
values.trigger.test_type = XSyncPositiveComparison;
1567
XSyncIntToValue (&values.delta, 1);
1569
values.events = true;
1571
CompScreen::checkForError (screen->dpy ());
1573
/* Note that by default, the alarm increments the trigger value
1574
* when it fires until the condition (counter.value < trigger.value)
1577
syncAlarm = XSyncCreateAlarm (screen->dpy (),
1586
if (CompScreen::checkForError (screen->dpy ()))
1589
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
1592
else if (result == Success && data)
1601
CompWindow::sendSyncRequest ()
1603
XClientMessageEvent xev;
1608
if (!priv->initializeSyncCounter ())
1611
xev.type = ClientMessage;
1612
xev.window = priv->id;
1613
xev.message_type = Atoms::wmProtocols;
1615
xev.data.l[0] = Atoms::wmSyncRequest;
1616
xev.data.l[1] = CurrentTime;
1617
xev.data.l[2] = XSyncValueLow32 (priv->syncValue);
1618
xev.data.l[3] = XSyncValueHigh32 (priv->syncValue);
1621
syncValueIncrement (&priv->syncValue);
1623
XSendEvent (screen->dpy (), priv->id, false, 0, (XEvent *) &xev);
1625
priv->syncWait = true;
1626
priv->syncGeometry = priv->serverGeometry;
1628
if (!priv->syncWaitTimer.active ())
1629
priv->syncWaitTimer.start ();
1633
PrivateWindow::configure (XConfigureEvent *ce)
1638
priv->attrib.override_redirect = ce->override_redirect;
1641
priv->syncGeometry.set (ce->x, ce->y, ce->width, ce->height,
1645
if (ce->override_redirect)
1647
priv->serverGeometry.set (ce->x, ce->y, ce->width, ce->height,
1651
window->resize (ce->x, ce->y, ce->width, ce->height, ce->border_width);
1654
if (ce->event == screen->root ())
1655
priv->restack (ce->above);
1659
PrivateWindow::configureFrame (XConfigureEvent *ce)
1661
int x, y, width, height;
1667
x = ce->x + priv->input.left;
1668
y = ce->y + priv->input.top;
1669
width = ce->width - priv->serverGeometry.border () * 2 - priv->input.left - priv->input.right;
1670
height = ce->height - priv->serverGeometry.border () * 2 - priv->input.top - priv->input.bottom;
1674
priv->syncGeometry.set (x, y, width, height, ce->border_width);
1678
if (ce->override_redirect)
1680
priv->serverGeometry.set (x, y, width, height, ce->border_width);
1683
window->resize (x, y, width, height, ce->border_width);
1686
if (priv->restack (ce->above))
1687
priv->updatePassiveButtonGrabs ();
1689
above = screen->findWindow (ce->above);
1692
above->priv->updatePassiveButtonGrabs ();
1696
PrivateWindow::circulate (XCirculateEvent *ce)
1700
if (ce->place == PlaceOnTop)
1701
newAboveId = screen->priv->getTopWindow ();
1705
priv->restack (newAboveId);
1709
CompWindow::move (int dx,
1716
priv->attrib.x += dx;
1717
priv->attrib.y += dy;
1719
priv->geometry.setX (priv->geometry.x () + dx);
1720
priv->geometry.setY (priv->geometry.y () + dy);
1722
priv->region.translate (dx, dy);
1723
priv->inputRegion.translate (dx, dy);
1724
if (!priv->frameRegion.isEmpty ())
1725
priv->frameRegion.translate (dx, dy);
1727
priv->invisible = WINDOW_INVISIBLE (priv);
1729
moveNotify (dx, dy, immediate);
1734
CompWindow::syncPosition ()
1736
priv->serverGeometry.setX (priv->geometry.x ());
1737
priv->serverGeometry.setY (priv->geometry.y ());
1739
XMoveWindow (screen->dpy (), ROOTPARENT (this),
1740
priv->geometry.x () - priv->input.left,
1741
priv->geometry.y () - priv->input.top);
1745
XMoveWindow (screen->dpy (), priv->wrapper,
1746
priv->input.left, priv->input.top);
1747
sendConfigureNotify ();
1752
CompWindow::focus ()
1754
WRAPABLE_HND_FUNC_RETURN (2, bool, focus)
1756
if (overrideRedirect ())
1759
if (!priv->managed || priv->unmanaging)
1762
if (!onCurrentDesktop ())
1765
if (priv->destroyed)
1768
if (!priv->shaded && (priv->state & CompWindowStateHiddenMask))
1771
if (priv->geometry.x () + priv->width <= 0 ||
1772
priv->geometry.y () + priv->height <= 0 ||
1773
priv->geometry.x () >= (int) screen->width ()||
1774
priv->geometry.y () >= (int) screen->height ())
1781
CompWindow::place (CompPoint &pos)
1783
WRAPABLE_HND_FUNC_RETURN (4, bool, place, pos)
1788
CompWindow::validateResizeRequest (unsigned int &mask,
1789
XWindowChanges *xwc,
1790
unsigned int source)
1792
WRAPABLE_HND_FUNC (5, validateResizeRequest, mask, xwc, source)
1794
if (!(priv->type & (CompWindowTypeDockMask |
1795
CompWindowTypeFullscreenMask |
1796
CompWindowTypeUnknownMask)))
1802
min = screen->workArea ().y () + priv->input.top;
1803
max = screen->workArea ().bottom ();
1805
if (priv->state & CompWindowStateStickyMask &&
1806
(xwc->y < min || xwc->y > max))
1808
xwc->y = priv->serverGeometry.y ();
1812
min -= screen->vp ().y () * screen->height ();
1813
max += (screen->vpSize ().height () - screen->vp ().y () - 1) *
1818
else if (xwc->y > max)
1827
min = screen->workArea ().x () + priv->input.left;
1828
max = screen->workArea ().right ();
1830
if (priv->state & CompWindowStateStickyMask &&
1831
(xwc->x < min || xwc->x > max))
1833
xwc->x = priv->serverGeometry.x ();
1837
min -= screen->vp ().x () * screen->width ();
1838
max += (screen->vpSize ().width () - screen->vp ().x () - 1) *
1843
else if (xwc->x > max)
1851
CompWindow::resizeNotify (int dx,
1855
WRAPABLE_HND_FUNC (6, resizeNotify, dx, dy, dwidth, dheight)
1858
CompWindow::moveNotify (int dx,
1861
WRAPABLE_HND_FUNC (7, moveNotify, dx, dy, immediate)
1864
CompWindow::windowNotify (CompWindowNotify n)
1865
WRAPABLE_HND_FUNC (8, windowNotify, n)
1868
CompWindow::grabNotify (int x,
1873
WRAPABLE_HND_FUNC (9, grabNotify, x, y, state, mask)
1874
priv->grabbed = true;
1878
CompWindow::ungrabNotify ()
1880
WRAPABLE_HND_FUNC (10, ungrabNotify)
1881
priv->grabbed = false;
1885
CompWindow::stateChangeNotify (unsigned int lastState)
1887
WRAPABLE_HND_FUNC (11, stateChangeNotify, lastState);
1889
/* if being made sticky */
1890
if (!(lastState & CompWindowStateStickyMask) &&
1891
(priv->state & CompWindowStateStickyMask))
1893
CompPoint vp; /* index of the window's vp */
1895
/* Find which viewport the window falls in,
1896
and check if it's the current viewport */
1897
vp = defaultViewport ();
1898
if (screen->vp () != vp)
1900
int moveX = (screen->vp ().x () - vp.x ()) * screen->width ();
1901
int moveY = (screen->vp ().y () - vp.y ()) * screen->height ();
1903
move (moveX, moveY, TRUE);
1911
PrivateWindow::isGroupTransient (Window clientLeader)
1916
if (transientFor == None || transientFor == screen->root ())
1918
if (type & (CompWindowTypeUtilMask |
1919
CompWindowTypeToolbarMask |
1920
CompWindowTypeMenuMask |
1921
CompWindowTypeDialogMask |
1922
CompWindowTypeModalDialogMask))
1924
if (this->clientLeader == clientLeader)
1933
PrivateWindow::getModalTransient ()
1935
CompWindow *w, *modalTransient;
1937
modalTransient = window;
1939
for (w = screen->windows ().back (); w; w = w->prev)
1941
if (w == modalTransient || w->priv->mapNum == 0)
1944
if (w->priv->transientFor == modalTransient->priv->id)
1946
if (w->priv->state & CompWindowStateModalMask)
1949
w = screen->windows ().back ();
1954
if (modalTransient == window)
1956
/* don't look for group transients with modal state if current window
1958
if (state & CompWindowStateModalMask)
1961
for (w = screen->windows ().back (); w; w = w->prev)
1963
if (w == modalTransient || w->priv->mapNum == 0)
1966
if (isAncestorTo (modalTransient, w))
1969
if (w->priv->isGroupTransient (modalTransient->priv->clientLeader))
1971
if (w->priv->state & CompWindowStateModalMask)
1974
w = w->priv->getModalTransient ();
1984
if (modalTransient == window)
1985
modalTransient = NULL;
1987
return modalTransient;
1991
CompWindow::moveInputFocusTo ()
1993
CompScreen *s = screen;
1994
CompWindow *modalTransient;
1996
modalTransient = priv->getModalTransient ();
1998
return modalTransient->moveInputFocusTo ();
2000
if (priv->state & CompWindowStateHiddenMask)
2002
XSetInputFocus (s->dpy (), priv->frame,
2003
RevertToPointerRoot, CurrentTime);
2004
XChangeProperty (s->dpy (), s->root (), Atoms::winActive,
2005
XA_WINDOW, 32, PropModeReplace,
2006
(unsigned char *) &priv->id, 1);
2010
bool setFocus = false;
2012
if (priv->inputHint)
2014
XSetInputFocus (s->dpy (), priv->id, RevertToPointerRoot,
2019
if (priv->protocols & CompWindowProtocolTakeFocusMask)
2023
ev.type = ClientMessage;
2024
ev.xclient.window = priv->id;
2025
ev.xclient.message_type = Atoms::wmProtocols;
2026
ev.xclient.format = 32;
2027
ev.xclient.data.l[0] = Atoms::wmTakeFocus;
2028
ev.xclient.data.l[1] = s->getCurrentTime ();
2029
ev.xclient.data.l[2] = 0;
2030
ev.xclient.data.l[3] = 0;
2031
ev.xclient.data.l[4] = 0;
2033
XSendEvent (s->dpy (), priv->id, false, NoEventMask, &ev);
2040
CompWindowList dockWindows;
2044
screen->priv->nextActiveWindow = priv->id;
2046
/* Ensure that docks are stacked in the right place
2048
* When a normal window gets the focus and is above a
2049
* fullscreen window, restack the docks to be above
2050
* the highest level mapped and visible normal window,
2051
* otherwise put them above the highest fullscreen window
2053
if (PrivateWindow::stackDocks (this, dockWindows, &xwc, &mask))
2055
Window sibling = xwc.sibling;
2056
xwc.stack_mode = Above;
2058
/* Then update the dock windows */
2059
foreach (CompWindow *dw, dockWindows)
2061
xwc.sibling = sibling;
2062
dw->configureXWindow (mask, &xwc);
2067
if (!setFocus && !modalTransient)
2069
CompWindow *ancestor;
2071
/* move input to closest ancestor */
2072
for (ancestor = s->windows ().front (); ancestor;
2073
ancestor = ancestor->next)
2075
if (PrivateWindow::isAncestorTo (this, ancestor))
2077
ancestor->moveInputFocusTo ();
2086
CompWindow::moveInputFocusToOtherWindow ()
2088
if (priv->id == screen->activeWindow () ||
2089
priv->id == screen->priv->nextActiveWindow)
2091
CompWindow *ancestor;
2093
if (priv->transientFor && priv->transientFor != screen->root ())
2095
ancestor = screen->findWindow (priv->transientFor);
2097
ancestor->focus () &&
2098
!(ancestor->priv->type & (CompWindowTypeDesktopMask |
2099
CompWindowTypeDockMask)))
2101
ancestor->moveInputFocusTo ();
2104
screen->focusDefaultWindow ();
2106
else if (priv->type & (CompWindowTypeDialogMask |
2107
CompWindowTypeModalDialogMask))
2109
CompWindow *a, *focus = NULL;
2111
for (a = screen->windows ().back (); a; a = a->prev)
2113
if (a->priv->clientLeader == priv->clientLeader)
2119
if (a->priv->type & (CompWindowTypeNormalMask |
2120
CompWindowTypeDialogMask |
2121
CompWindowTypeModalDialogMask))
2123
if (priv->compareWindowActiveness (focus, a) < 0)
2133
if (focus && !(focus->priv->type & (CompWindowTypeDesktopMask |
2134
CompWindowTypeDockMask)))
2136
focus->moveInputFocusTo ();
2139
screen->focusDefaultWindow ();
2142
screen->focusDefaultWindow ();
2148
PrivateWindow::stackLayerCheck (CompWindow *w,
2149
Window clientLeader,
2152
if (isAncestorTo (w, below))
2155
if (isAncestorTo (below, w))
2158
if (clientLeader && below->priv->clientLeader == clientLeader)
2159
if (below->priv->isGroupTransient (clientLeader))
2162
if (w->priv->state & CompWindowStateAboveMask)
2166
else if (w->priv->state & CompWindowStateBelowMask)
2168
if (below->priv->state & CompWindowStateBelowMask)
2171
else if (!(below->priv->state & CompWindowStateAboveMask))
2180
PrivateWindow::avoidStackingRelativeTo (CompWindow *w)
2182
if (w->overrideRedirect ())
2185
if (!w->priv->shaded && !w->priv->pendingMaps)
2187
if (!w->isViewable () || !w->isMapped ())
2194
/* goes through the stack, top-down until we find a window we should
2195
stack above, normal windows can be stacked above fullscreen windows
2196
(and fullscreen windows over others in their layer) if aboveFs is true. */
2198
PrivateWindow::findSiblingBelow (CompWindow *w,
2202
Window clientLeader = w->priv->clientLeader;
2203
unsigned int type = w->priv->type;
2204
unsigned int belowMask;
2207
belowMask = CompWindowTypeDockMask;
2209
belowMask = CompWindowTypeDockMask | CompWindowTypeFullscreenMask;
2211
/* normal stacking of fullscreen windows with below state */
2212
if ((type & CompWindowTypeFullscreenMask) &&
2213
(w->priv->state & CompWindowStateBelowMask))
2214
type = CompWindowTypeNormalMask;
2216
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2217
clientLeader = None;
2219
for (below = screen->windows ().back (); below;
2220
below = below->prev)
2222
if (below == w || avoidStackingRelativeTo (below))
2225
/* always above desktop windows */
2226
if (below->priv->type & CompWindowTypeDesktopMask)
2230
case CompWindowTypeDesktopMask:
2231
/* desktop window layer */
2233
case CompWindowTypeFullscreenMask:
2236
/* otherwise fall-through */
2237
case CompWindowTypeDockMask:
2238
/* fullscreen and dock layer */
2239
if (below->priv->type & (CompWindowTypeFullscreenMask |
2240
CompWindowTypeDockMask))
2242
if (stackLayerCheck (w, clientLeader, below))
2251
/* fullscreen and normal layer */
2252
if (!(below->priv->type & belowMask))
2254
if (stackLayerCheck (w, clientLeader, below))
2264
/* goes through the stack, top-down and returns the lowest window we
2267
PrivateWindow::findLowestSiblingBelow (CompWindow *w)
2269
CompWindow *below, *lowest = screen->windows ().back ();
2270
Window clientLeader = w->priv->clientLeader;
2271
unsigned int type = w->priv->type;
2273
/* normal stacking fullscreen windows with below state */
2274
if ((type & CompWindowTypeFullscreenMask) &&
2275
(w->priv->state & CompWindowStateBelowMask))
2276
type = CompWindowTypeNormalMask;
2278
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2279
clientLeader = None;
2281
for (below = screen->windows ().back (); below;
2282
below = below->prev)
2284
if (below == w || avoidStackingRelativeTo (below))
2287
/* always above desktop windows */
2288
if (below->priv->type & CompWindowTypeDesktopMask)
2292
case CompWindowTypeDesktopMask:
2293
/* desktop window layer - desktop windows always should be
2294
stacked at the bottom; no other window should be below them */
2297
case CompWindowTypeFullscreenMask:
2298
case CompWindowTypeDockMask:
2299
/* fullscreen and dock layer */
2300
if (below->priv->type & (CompWindowTypeFullscreenMask |
2301
CompWindowTypeDockMask))
2303
if (!stackLayerCheck (below, clientLeader, w))
2312
/* fullscreen and normal layer */
2313
if (!(below->priv->type & CompWindowTypeDockMask))
2315
if (!stackLayerCheck (below, clientLeader, w))
2328
PrivateWindow::validSiblingBelow (CompWindow *w,
2329
CompWindow *sibling)
2331
Window clientLeader = w->priv->clientLeader;
2332
unsigned int type = w->priv->type;
2334
/* normal stacking fullscreen windows with below state */
2335
if ((type & CompWindowTypeFullscreenMask) &&
2336
(w->priv->state & CompWindowStateBelowMask))
2337
type = CompWindowTypeNormalMask;
2339
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2340
clientLeader = None;
2342
if (sibling == w || avoidStackingRelativeTo (sibling))
2345
/* always above desktop windows */
2346
if (sibling->priv->type & CompWindowTypeDesktopMask)
2350
case CompWindowTypeDesktopMask:
2351
/* desktop window layer */
2353
case CompWindowTypeFullscreenMask:
2354
case CompWindowTypeDockMask:
2355
/* fullscreen and dock layer */
2356
if (sibling->priv->type & (CompWindowTypeFullscreenMask |
2357
CompWindowTypeDockMask))
2359
if (stackLayerCheck (w, clientLeader, sibling))
2368
/* fullscreen and normal layer */
2369
if (!(sibling->priv->type & CompWindowTypeDockMask))
2371
if (stackLayerCheck (w, clientLeader, sibling))
2381
PrivateWindow::saveGeometry (int mask)
2383
int m = mask & ~saveMask;
2385
/* only save geometry if window has been placed */
2390
saveWc.x = serverGeometry.x ();
2393
saveWc.y = serverGeometry.y ();
2396
saveWc.width = serverGeometry.width ();
2399
saveWc.height = serverGeometry.height ();
2401
if (m & CWBorderWidth)
2402
saveWc.border_width = serverGeometry.border ();
2408
PrivateWindow::restoreGeometry (XWindowChanges *xwc,
2411
int m = mask & saveMask;
2421
xwc->width = saveWc.width;
2423
/* This is not perfect but it works OK for now. If the saved width is
2424
the same as the current width then make it a little be smaller so
2425
the user can see that it changed and it also makes sure that
2426
windowResizeNotify is called and plugins are notified. */
2427
if (xwc->width == (int) serverGeometry.width ())
2437
xwc->height = saveWc.height;
2439
/* As above, if the saved height is the same as the current height
2440
then make it a little be smaller. */
2441
if (xwc->height == (int) serverGeometry.height ())
2449
if (m & CWBorderWidth)
2450
xwc->border_width = saveWc.border_width;
2458
PrivateWindow::reconfigureXWindow (unsigned int valueMask,
2459
XWindowChanges *xwc)
2461
if (valueMask & CWX)
2462
serverGeometry.setX (xwc->x);
2464
if (valueMask & CWY)
2465
serverGeometry.setY (xwc->y);
2467
if (valueMask & CWWidth)
2468
serverGeometry.setWidth (xwc->width);
2470
if (valueMask & CWHeight)
2471
serverGeometry.setHeight (xwc->height);
2473
if (valueMask & CWBorderWidth)
2474
serverGeometry.setBorder (xwc->border_width);
2478
XWindowChanges wc = *xwc;
2480
wc.x -= input.left - serverGeometry.border ();
2481
wc.y -= input.top - serverGeometry.border ();
2482
wc.width += input.left + input.right + serverGeometry.border ();
2483
wc.height += input.top + input.bottom + serverGeometry.border ();
2485
XConfigureWindow (screen->dpy (), frame, valueMask, &wc);
2486
valueMask &= ~(CWSibling | CWStackMode);
2488
xwc->x = input.left;
2490
XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc);
2496
XConfigureWindow (screen->dpy (), id, valueMask, xwc);
2498
/* Compiz's window list is immediately restacked on reconfigureXWindow
2499
in order to ensure correct operation of the raise, lower and restacking
2500
functions. This function should only recieve stack_mode == Above
2501
but warn incase something else does get through, to make the cause
2502
of any potential misbehaviour obvious. */
2503
if (valueMask & (CWSibling | CWStackMode))
2505
if (xwc->stack_mode == Above)
2507
/* FIXME: We shouldn't need to sync here, however
2508
* considering the fact that we are immediately
2509
* restacking the windows, we need to ensure
2510
* that when a client tries to restack a window
2511
* relative to this window that the window
2512
* actually goes where the client expects it to go
2513
* and not anywhere else
2515
* The real solution here is to have a list of windows
2516
* last sent to server and a list of windows last
2517
* received from server or to have a sync () function
2518
* on the stack which looks through the last recieved
2519
* window stack and the current window stack then
2520
* sends the changes */
2521
XSync (screen->dpy (), false);
2522
restack (xwc->sibling);
2525
compLogMessage ("core", CompLogLevelWarn, "restack_mode not Above");
2530
PrivateWindow::stackDocks (CompWindow *w,
2531
CompWindowList &updateList,
2532
XWindowChanges *xwc,
2535
CompWindow *firstFullscreenWindow = NULL;
2536
CompWindow *belowDocks = NULL;
2538
foreach (CompWindow *dw, screen->windows ())
2540
/* fullscreen window found */
2541
if (firstFullscreenWindow)
2543
/* If there is another toplevel window above the fullscreen one
2544
* then we need to stack above that */
2546
!PrivateWindow::isAncestorTo (w, dw) &&
2547
!(dw->type () & (CompWindowTypeFullscreenMask |
2548
CompWindowTypeDockMask)) &&
2549
!dw->overrideRedirect () &&
2550
dw->defaultViewport () == screen->vp () &&
2556
else if (dw->type () & CompWindowTypeFullscreenMask)
2558
/* First fullscreen window found when checking up the stack
2559
* now go back down to find a suitable candidate client
2560
* window to put the docks above */
2561
firstFullscreenWindow = dw;
2562
for (CompWindow *dww = dw->prev; dww; dww = dww->prev)
2564
if (!(dww->type () & (CompWindowTypeFullscreenMask |
2565
CompWindowTypeDockMask)) &&
2566
!dww->overrideRedirect () &&
2567
dww->defaultViewport () == screen->vp () &&
2579
*mask = CWSibling | CWStackMode;
2580
xwc->sibling = ROOTPARENT (belowDocks);
2582
/* Collect all dock windows first */
2583
foreach (CompWindow *dw, screen->windows ())
2584
if (dw->priv->type & CompWindowTypeDockMask)
2585
updateList.push_front (dw);
2594
PrivateWindow::stackTransients (CompWindow *w,
2596
XWindowChanges *xwc,
2597
CompWindowList &updateList)
2600
Window clientLeader = w->priv->clientLeader;
2602
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2603
clientLeader = None;
2605
for (t = screen->windows ().back (); t; t = t->prev)
2607
if (t == w || t == avoid)
2610
if (t->priv->transientFor == w->priv->id ||
2611
t->priv->isGroupTransient (clientLeader))
2613
if (w->priv->type & CompWindowTypeDockMask)
2614
if (!(t->priv->type & CompWindowTypeDockMask))
2617
if (!stackTransients (t, avoid, xwc, updateList))
2620
if (xwc->sibling == t->priv->id ||
2621
(t->priv->frame && xwc->sibling == t->priv->frame))
2624
if (t->priv->mapNum || t->priv->pendingMaps)
2625
updateList.push_back (t);
2633
PrivateWindow::stackAncestors (CompWindow *w,
2634
XWindowChanges *xwc,
2635
CompWindowList &updateList)
2637
CompWindow *transient = NULL;
2639
if (w->priv->transientFor)
2640
transient = screen->findWindow (w->priv->transientFor);
2643
xwc->sibling != transient->priv->id &&
2644
(!transient->priv->frame || xwc->sibling != transient->priv->frame))
2646
CompWindow *ancestor;
2648
ancestor = screen->findWindow (w->priv->transientFor);
2651
if (!stackTransients (ancestor, w, xwc, updateList))
2654
if (ancestor->priv->type & CompWindowTypeDesktopMask)
2657
if (ancestor->priv->type & CompWindowTypeDockMask)
2658
if (!(w->priv->type & CompWindowTypeDockMask))
2661
if (ancestor->priv->mapNum || ancestor->priv->pendingMaps)
2662
updateList.push_back (ancestor);
2664
stackAncestors (ancestor, xwc, updateList);
2667
else if (w->priv->isGroupTransient (w->priv->clientLeader))
2671
for (a = screen->windows ().back (); a; a = a->prev)
2673
if (a->priv->clientLeader == w->priv->clientLeader &&
2674
a->priv->transientFor == None &&
2675
!a->priv->isGroupTransient (w->priv->clientLeader))
2677
if (xwc->sibling == a->priv->id ||
2678
(a->priv->frame && xwc->sibling == a->priv->frame))
2681
if (!stackTransients (a, w, xwc, updateList))
2684
if (a->priv->type & CompWindowTypeDesktopMask)
2687
if (a->priv->type & CompWindowTypeDockMask)
2688
if (!(w->priv->type & CompWindowTypeDockMask))
2691
if (a->priv->mapNum || a->priv->pendingMaps)
2692
updateList.push_back (a);
2699
CompWindow::configureXWindow (unsigned int valueMask,
2700
XWindowChanges *xwc)
2702
if (priv->managed && (valueMask & (CWSibling | CWStackMode)))
2704
CompWindowList transients;
2705
CompWindowList ancestors;
2706
CompWindowList docks;
2708
/* Since the window list is being reordered in reconfigureXWindow
2709
the list of windows which need to be restacked must be stored
2710
first. The windows are stacked in the opposite order than they
2711
were previously stacked, in order that they are above xwc->sibling
2712
so that when compiz gets the ConfigureNotify event it doesn't
2713
have to restack all the windows again. */
2715
/* transient children above */
2716
if (PrivateWindow::stackTransients (this, NULL, xwc, transients))
2718
/* ancestors, siblings and sibling transients below */
2719
PrivateWindow::stackAncestors (this, xwc, ancestors);
2721
for (CompWindowList::reverse_iterator w = ancestors.rbegin ();
2722
w != ancestors.rend (); w++)
2724
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
2725
xwc->sibling = ROOTPARENT (*w);
2728
this->priv->reconfigureXWindow (valueMask, xwc);
2729
xwc->sibling = ROOTPARENT (this);
2731
for (CompWindowList::reverse_iterator w = transients.rbegin ();
2732
w != transients.rend (); w++)
2734
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
2735
xwc->sibling = ROOTPARENT (*w);
2738
if (PrivateWindow::stackDocks (this, docks, xwc, &valueMask))
2740
Window sibling = xwc->sibling;
2741
xwc->stack_mode = Above;
2743
/* Then update the dock windows */
2744
foreach (CompWindow *dw, docks)
2746
xwc->sibling = sibling;
2747
dw->priv->reconfigureXWindow (valueMask, xwc);
2754
priv->reconfigureXWindow (valueMask, xwc);
2759
PrivateWindow::addWindowSizeChanges (XWindowChanges *xwc,
2760
CompWindow::Geometry old)
2768
screen->viewportForGeometry (old, viewport);
2770
x = (viewport.x () - screen->vp ().x ()) * screen->width ();
2771
y = (viewport.y () - screen->vp ().y ()) * screen->height ();
2773
output = screen->outputDeviceForGeometry (old);
2774
workArea = screen->getWorkareaForOutput (output);
2776
if (type & CompWindowTypeFullscreenMask)
2778
saveGeometry (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
2780
if (fullscreenMonitorsSet)
2782
xwc->x = x + fullscreenMonitorRect.x ();
2783
xwc->y = y + fullscreenMonitorRect.y ();
2784
xwc->width = fullscreenMonitorRect.width ();
2785
xwc->height = fullscreenMonitorRect.height ();
2789
xwc->x = x + screen->outputDevs ()[output].x ();
2790
xwc->y = y + screen->outputDevs ()[output].y ();
2791
xwc->width = screen->outputDevs ()[output].width ();
2792
xwc->height = screen->outputDevs ()[output].height ();
2795
xwc->border_width = 0;
2797
mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
2801
mask |= restoreGeometry (xwc, CWBorderWidth);
2803
if (state & CompWindowStateMaximizedVertMask)
2805
saveGeometry (CWY | CWHeight);
2807
xwc->height = workArea.height () - input.top -
2808
input.bottom - old.border () * 2;
2814
mask |= restoreGeometry (xwc, CWY | CWHeight);
2817
if (state & CompWindowStateMaximizedHorzMask)
2819
saveGeometry (CWX | CWWidth);
2821
xwc->width = workArea.width () - input.left -
2822
input.right - old.border () * 2;
2828
mask |= restoreGeometry (xwc, CWX | CWWidth);
2831
/* constrain window width if smaller than minimum width */
2832
if (!(mask & CWWidth) && (int) old.width () < sizeHints.min_width)
2834
xwc->width = sizeHints.min_width;
2838
/* constrain window width if greater than maximum width */
2839
if (!(mask & CWWidth) && (int) old.width () > sizeHints.max_width)
2841
xwc->width = sizeHints.max_width;
2845
/* constrain window height if smaller than minimum height */
2846
if (!(mask & CWHeight) && (int) old.height () < sizeHints.min_height)
2848
xwc->height = sizeHints.min_height;
2852
/* constrain window height if greater than maximum height */
2853
if (!(mask & CWHeight) && (int) old.height () > sizeHints.max_height)
2855
xwc->height = sizeHints.max_height;
2859
if (mask & (CWWidth | CWHeight))
2861
int width, height, max;
2863
width = (mask & CWWidth) ? xwc->width : old.width ();
2864
height = (mask & CWHeight) ? xwc->height : old.height ();
2866
xwc->width = old.width ();
2867
xwc->height = old.height ();
2869
window->constrainNewWindowSize (width, height, &width, &height);
2871
if (width != (int) old.width ())
2879
if (height != (int) old.height ())
2882
xwc->height = height;
2887
if (state & CompWindowStateMaximizedVertMask)
2889
if (old.y () < y + workArea.y () + input.top)
2891
xwc->y = y + workArea.y () + input.top;
2896
height = xwc->height + old.border () * 2;
2898
max = y + workArea.bottom ();
2899
if (old.y () + (int) old.height () + input.bottom > max)
2901
xwc->y = max - height - input.bottom;
2904
else if (old.y () + height + input.bottom > max)
2906
xwc->y = y + workArea.y () +
2907
(workArea.height () - input.top - height -
2908
input.bottom) / 2 + input.top;
2914
if (state & CompWindowStateMaximizedHorzMask)
2916
if (old.x () < x + workArea.x () + input.left)
2918
xwc->x = x + workArea.x () + input.left;
2923
width = xwc->width + old.border () * 2;
2925
max = x + workArea.right ();
2926
if (old.x () + (int) old.width () + input.right > max)
2928
xwc->x = max - width - input.right;
2931
else if (old.x () + width + input.right > max)
2933
xwc->x = x + workArea.x () +
2934
(workArea.width () - input.left - width -
2935
input.right) / 2 + input.left;
2943
if ((mask & CWX) && (xwc->x == old.x ()))
2946
if ((mask & CWY) && (xwc->y == old.y ()))
2949
if ((mask & CWWidth) && (xwc->width == (int) old.width ()))
2952
if ((mask & CWHeight) && (xwc->height == (int) old.height ()))
2959
PrivateWindow::adjustConfigureRequestForGravity (XWindowChanges *xwc,
2965
unsigned int mask = 0;
2970
if (xwcm & (CWX | CWWidth))
2973
case NorthWestGravity:
2975
case SouthWestGravity:
2977
newX += priv->border.left * direction;
2984
newX -= (xwc->width / 2 - priv->border.left +
2985
(priv->border.left + priv->border.right) / 2) * direction;
2987
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
2990
case NorthEastGravity:
2992
case SouthEastGravity:
2994
newX -= xwc->width + priv->border.right * direction;
2996
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
3005
if (xwcm & (CWY | CWHeight))
3008
case NorthWestGravity:
3010
case NorthEastGravity:
3012
newY = xwc->y + priv->input.top * direction;
3019
newY -= (xwc->height / 2 - priv->input.top +
3020
(priv->input.top + priv->input.bottom) / 2) * direction;
3022
newY -= ((xwc->height - priv->serverGeometry.height ()) / 2) * direction;
3025
case SouthWestGravity:
3027
case SouthEastGravity:
3029
newY -= xwc->height + priv->input.bottom * direction;
3031
newY -= (xwc->height - priv->serverGeometry.height ()) * direction;
3042
xwc->x += (newX - xwc->x);
3048
xwc->y += (newY - xwc->y);
3056
CompWindow::moveResize (XWindowChanges *xwc,
3059
unsigned int source)
3061
bool placed = false;
3063
xwcm &= (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3065
if (xwcm & (CWX | CWY))
3066
if (priv->sizeHints.flags & (USPosition | PPosition))
3070
gravity = priv->sizeHints.win_gravity;
3073
xwc->x = priv->serverGeometry.x ();
3075
xwc->y = priv->serverGeometry.y ();
3076
if (!(xwcm & CWWidth))
3077
xwc->width = priv->serverGeometry.width ();
3078
if (!(xwcm & CWHeight))
3079
xwc->height = priv->serverGeometry.height ();
3081
if (xwcm & (CWWidth | CWHeight))
3085
if (constrainNewWindowSize (xwc->width, xwc->height, &width, &height))
3087
if (width != xwc->width)
3090
if (height != xwc->height)
3094
xwc->height = height;
3098
xwcm |= priv->adjustConfigureRequestForGravity (xwc, xwcm, gravity, 1);
3100
validateResizeRequest (xwcm, xwc, source);
3102
/* when horizontally maximized only allow width changes added by
3103
addWindowSizeChanges */
3104
if (priv->state & CompWindowStateMaximizedHorzMask)
3107
/* when vertically maximized only allow height changes added by
3108
addWindowSizeChanges */
3109
if (priv->state & CompWindowStateMaximizedVertMask)
3112
xwcm |= priv->addWindowSizeChanges (xwc, Geometry (xwc->x, xwc->y,
3113
xwc->width, xwc->height,
3114
xwc->border_width));
3116
/* check if the new coordinates are useful and valid (different
3117
to current size); if not, we have to clear them to make sure
3118
we send a synthetic ConfigureNotify event if all coordinates
3119
match the server coordinates */
3120
if (xwc->x == priv->serverGeometry.x ())
3123
if (xwc->y == priv->serverGeometry.y ())
3126
if (xwc->width == (int) priv->serverGeometry.width ())
3129
if (xwc->height == (int) priv->serverGeometry.height ())
3132
if (xwc->border_width == (int) priv->serverGeometry.border ())
3133
xwcm &= ~CWBorderWidth;
3135
/* update saved window coordinates - if CWX or CWY is set for fullscreen
3136
or maximized windows after addWindowSizeChanges, it should be pretty
3137
safe to assume that the saved coordinates should be updated too, e.g.
3138
because the window was moved to another viewport by some client */
3139
if ((xwcm & CWX) && (priv->saveMask & CWX))
3140
priv->saveWc.x += (xwc->x - priv->serverGeometry.x ());
3142
if ((xwcm & CWY) && (priv->saveMask & CWY))
3143
priv->saveWc.y += (xwc->y - priv->serverGeometry.y ());
3145
if (priv->mapNum && (xwcm & (CWWidth | CWHeight)))
3149
configureXWindow (xwcm, xwc);
3152
/* we have to send a configure notify on ConfigureRequest events if
3153
we decide not to do anything according to ICCCM 4.1.5 */
3154
sendConfigureNotify ();
3158
priv->placed = true;
3162
PrivateWindow::updateSize ()
3167
if (window->overrideRedirect () || !managed)
3170
mask = priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
3173
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
3174
window->sendSyncRequest ();
3176
window->configureXWindow (mask, &xwc);
3181
PrivateWindow::addWindowStackChanges (XWindowChanges *xwc,
3182
CompWindow *sibling)
3186
if (!sibling || sibling->priv->id != id)
3193
XLowerWindow (screen->dpy (), frame);
3194
XLowerWindow (screen->dpy (), id);
3196
/* Restacking of compiz's window list happens
3197
* immediately and since this path doesn't call
3198
* reconfigureXWindow, restack must be called here.
3200
* FIXME: We shouldn't need to sync here, however
3201
* considering the fact that we are immediately
3202
* restacking the windows, we need to ensure
3203
* that when a client tries to restack a window
3204
* relative to this window that the window
3205
* actually goes where the client expects it to go
3206
* and not anywhere else
3208
* The real solution here is to have a list of windows
3209
* last sent to server and a list of windows last
3210
* received from server or to have a sync () function
3211
* on the stack which looks through the last recieved
3212
* window stack and the current window stack then
3213
* sends the changes */
3214
XSync (screen->dpy (), false);
3217
else if (sibling->priv->id != window->prev->priv->id)
3219
mask |= CWSibling | CWStackMode;
3221
xwc->stack_mode = Above;
3222
xwc->sibling = ROOTPARENT (sibling);
3227
mask |= CWSibling | CWStackMode;
3229
xwc->stack_mode = Above;
3230
xwc->sibling = ROOTPARENT (sibling);
3238
CompWindow::raise ()
3242
bool aboveFs = false;
3244
/* an active fullscreen window should be raised over all other
3245
windows in its layer */
3246
if (priv->type & CompWindowTypeFullscreenMask)
3247
if (priv->id == screen->activeWindow ())
3250
mask = priv->addWindowStackChanges (&xwc,
3251
PrivateWindow::findSiblingBelow (this, aboveFs));
3254
configureXWindow (mask, &xwc);
3258
PrivateScreen::focusTopMostWindow ()
3260
CompWindow *focus = NULL;
3261
CompWindowList::reverse_iterator it = windows.rbegin ();
3263
for (; it != windows.rend (); it++)
3265
CompWindow *w = *it;
3267
if (w->type () & CompWindowTypeDockMask)
3279
if (focus->id () != activeWindow)
3280
focus->moveInputFocusTo ();
3283
XSetInputFocus (dpy, root, RevertToPointerRoot,
3290
CompWindow::lower ()
3295
mask = priv->addWindowStackChanges (&xwc,
3296
PrivateWindow::findLowestSiblingBelow (this));
3298
configureXWindow (mask, &xwc);
3300
/* when lowering a window, focus the topmost window if
3301
the click-to-focus option is on */
3302
if ((screen->priv->optionGetClickToFocus ()))
3304
Window aboveWindowId = prev ? prev->id () : None;
3305
screen->unhookWindow (this);
3306
CompWindow *focusedWindow = screen->priv->focusTopMostWindow ();
3307
screen->insertWindow (this , aboveWindowId);
3309
/* if the newly focused window is a desktop window,
3310
give the focus back to w */
3311
if (focusedWindow &&
3312
focusedWindow->type () & CompWindowTypeDesktopMask)
3314
moveInputFocusTo ();
3320
CompWindow::restackAbove (CompWindow *sibling)
3322
for (; sibling; sibling = sibling->next)
3323
if (PrivateWindow::validSiblingBelow (this, sibling))
3331
mask = priv->addWindowStackChanges (&xwc, sibling);
3333
configureXWindow (mask, &xwc);
3337
/* finds the highest window under sibling we can stack above */
3339
PrivateWindow::findValidStackSiblingBelow (CompWindow *w,
3340
CompWindow *sibling)
3342
CompWindow *lowest, *last, *p;
3344
/* check whether we're allowed to stack under a sibling by finding
3345
* the above 'sibling' and checking whether or not we're allowed
3346
* to stack under that - if not, then there is no valid sibling
3349
for (p = sibling; p; p = p->next)
3351
if (!avoidStackingRelativeTo (p))
3353
if (!validSiblingBelow (p, w))
3359
/* get lowest sibling we're allowed to stack above */
3360
lowest = last = findLowestSiblingBelow (w);
3362
/* walk from bottom up */
3363
for (p = screen->windows ().front (); p; p = p->next)
3365
/* stop walking when we reach the sibling we should try to stack
3370
/* skip windows that we should avoid */
3371
if (w == p || avoidStackingRelativeTo (p))
3374
if (validSiblingBelow (w, p))
3376
/* update lowest as we find windows below sibling that we're
3377
allowed to stack above. last window must be equal to the
3378
lowest as we shouldn't update lowest if we passed an
3384
/* update last pointer */
3392
CompWindow::restackBelow (CompWindow *sibling)
3397
mask = priv->addWindowStackChanges (&xwc,
3398
PrivateWindow::findValidStackSiblingBelow (this, sibling));
3401
configureXWindow (mask, &xwc);
3405
CompWindow::updateAttributes (CompStackingUpdateMode stackingMode)
3410
if (overrideRedirect () || !priv->managed)
3413
if (priv->state & CompWindowStateShadedMask)
3415
windowNotify (CompWindowNotifyShade);
3419
else if (priv->shaded)
3421
windowNotify (CompWindowNotifyUnshade);
3426
if (stackingMode != CompStackingUpdateModeNone)
3429
CompWindow *sibling;
3431
aboveFs = (stackingMode == CompStackingUpdateModeAboveFullscreen);
3432
if (priv->type & CompWindowTypeFullscreenMask)
3434
/* put active or soon-to-be-active fullscreen windows over
3435
all others in their layer */
3436
if (priv->id == screen->activeWindow () ||
3437
priv->id == screen->priv->nextActiveWindow)
3443
/* put windows that are just mapped, over fullscreen windows */
3444
if (stackingMode == CompStackingUpdateModeInitialMap)
3447
sibling = PrivateWindow::findSiblingBelow (this, aboveFs);
3450
(stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
3454
for (p = sibling; p; p = p->prev)
3455
if (p->priv->id == screen->activeWindow ())
3458
/* window is above active window so we should lower it,
3459
* assuing that is allowed (if, for example, our window has
3460
* the "above" state, then lowering beneath the active
3461
* window may not be allowed). */
3462
if (p && PrivateWindow::validSiblingBelow (p, this))
3464
p = PrivateWindow::findValidStackSiblingBelow (sibling, p);
3466
/* if we found a valid sibling under the active window, it's
3467
our new sibling we want to stack above */
3473
mask |= priv->addWindowStackChanges (&xwc, sibling);
3476
mask |= priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
3478
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
3482
configureXWindow (mask, &xwc);
3484
if ((stackingMode == CompStackingUpdateModeInitialMap) ||
3485
(stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
3487
/* If we are called from the MapRequest handler, we have to
3488
immediately update the internal stack. If we don't do that,
3489
the internal stacking order is invalid until the ConfigureNotify
3490
arrives because we put the window at the top of the stack when
3492
if (mask & CWStackMode)
3494
/* FIXME: We shouldn't need to sync here, however
3495
* considering the fact that we are immediately
3496
* restacking the windows, we need to ensure
3497
* that when a client tries to restack a window
3498
* relative to this window that the window
3499
* actually goes where the client expects it to go
3500
* and not anywhere else
3502
* The real solution here is to have a list of windows
3503
* last sent to server and a list of windows last
3504
* received from server or to have a sync () function
3505
* on the stack which looks through the last recieved
3506
* window stack and the current window stack then
3507
* sends the changes */
3508
XSync (screen->dpy (), false);
3510
Window above = (mask & CWSibling) ? xwc.sibling : 0;
3511
priv->restack (above);
3517
PrivateWindow::ensureWindowVisibility ()
3520
int width = serverGeometry.width () + serverGeometry.border () * 2;
3521
int height = serverGeometry.height () + serverGeometry.border () * 2;
3525
if (struts || attrib.override_redirect)
3528
if (type & (CompWindowTypeDockMask |
3529
CompWindowTypeFullscreenMask |
3530
CompWindowTypeUnknownMask))
3533
x1 = screen->workArea ().x () - screen->width () * screen->vp ().x ();
3534
y1 = screen->workArea ().y () - screen->height () * screen->vp ().y ();
3535
x2 = x1 + screen->workArea ().width () + screen->vpSize ().width () *
3537
y2 = y1 + screen->workArea ().height () + screen->vpSize ().height () *
3540
if (serverGeometry.x () - input.left >= x2)
3541
dx = (x2 - 25) - serverGeometry.x ();
3542
else if (serverGeometry.x () + width + input.right <= x1)
3543
dx = (x1 + 25) - (serverGeometry.x () + width);
3545
if (serverGeometry.y () - input.top >= y2)
3546
dy = (y2 - 25) - serverGeometry.y ();
3547
else if (serverGeometry.y () + height + input.bottom <= y1)
3548
dy = (y1 + 25) - (serverGeometry.y () + height);
3554
xwc.x = serverGeometry.x () + dx;
3555
xwc.y = serverGeometry.y () + dy;
3557
window->configureXWindow (CWX | CWY, &xwc);
3562
PrivateWindow::reveal ()
3564
if (window->minimized ())
3565
window->unminimize ();
3567
screen->leaveShowDesktopMode (window);
3571
PrivateWindow::revealAncestors (CompWindow *w,
3572
CompWindow *transient)
3574
if (isAncestorTo (transient, w))
3576
screen->forEachWindow (boost::bind (revealAncestors, _1, w));
3582
CompWindow::activate ()
3584
WRAPABLE_HND_FUNC (3, activate)
3586
screen->priv->setCurrentDesktop (priv->desktop);
3588
screen->forEachWindow (
3589
boost::bind (PrivateWindow::revealAncestors, _1, this));
3592
if (priv->state & CompWindowStateHiddenMask)
3594
priv->state &= ~CompWindowStateShadedMask;
3599
if (priv->state & CompWindowStateHiddenMask)
3602
if (!onCurrentDesktop ())
3605
priv->ensureWindowVisibility ();
3606
updateAttributes (CompStackingUpdateModeAboveFullscreen);
3607
moveInputFocusTo ();
3611
#define PVertResizeInc (1 << 0)
3612
#define PHorzResizeInc (1 << 1)
3615
CompWindow::constrainNewWindowSize (int width,
3620
const XSizeHints *hints = &priv->sizeHints;
3621
int oldWidth = width;
3622
int oldHeight = height;
3626
int base_height = 0;
3629
int max_width = MAXSHORT;
3630
int max_height = MAXSHORT;
3631
long flags = hints->flags;
3632
long resizeIncFlags = (flags & PResizeInc) ? ~0 : 0;
3634
if (screen->priv->optionGetIgnoreHintsWhenMaximized ())
3636
if (priv->state & MAXIMIZE_STATE)
3640
if (priv->state & CompWindowStateMaximizedHorzMask)
3641
resizeIncFlags &= ~PHorzResizeInc;
3643
if (priv->state & CompWindowStateMaximizedVertMask)
3644
resizeIncFlags &= ~PVertResizeInc;
3648
/* Ater gdk_window_constrain_size(), which is partially borrowed from fvwm.
3650
* Copyright 1993, Robert Nation
3651
* You may use this code for any purpose, as long as the original
3652
* copyright remains in the source code and all documentation
3654
* which in turn borrows parts of the algorithm from uwm
3657
#define FLOOR(value, base) (((int) ((value) / (base))) * (base))
3658
#define FLOOR64(value, base) (((uint64_t) ((value) / (base))) * (base))
3660
if ((flags & PBaseSize) && (flags & PMinSize))
3662
base_width = hints->base_width;
3663
base_height = hints->base_height;
3664
min_width = hints->min_width;
3665
min_height = hints->min_height;
3667
else if (flags & PBaseSize)
3669
base_width = hints->base_width;
3670
base_height = hints->base_height;
3671
min_width = hints->base_width;
3672
min_height = hints->base_height;
3674
else if (flags & PMinSize)
3676
base_width = hints->min_width;
3677
base_height = hints->min_height;
3678
min_width = hints->min_width;
3679
min_height = hints->min_height;
3682
if (flags & PMaxSize)
3684
max_width = hints->max_width;
3685
max_height = hints->max_height;
3688
if (resizeIncFlags & PHorzResizeInc)
3689
xinc = MAX (xinc, hints->width_inc);
3691
if (resizeIncFlags & PVertResizeInc)
3692
yinc = MAX (yinc, hints->height_inc);
3694
/* clamp width and height to min and max values */
3695
width = CLAMP (width, min_width, max_width);
3696
height = CLAMP (height, min_height, max_height);
3698
/* shrink to base + N * inc */
3699
width = base_width + FLOOR (width - base_width, xinc);
3700
height = base_height + FLOOR (height - base_height, yinc);
3702
/* constrain aspect ratio, according to:
3704
* min_aspect.x width max_aspect.x
3705
* ------------ <= -------- <= -----------
3706
* min_aspect.y height max_aspect.y
3708
if ((flags & PAspect) && hints->min_aspect.y > 0 && hints->max_aspect.x > 0)
3710
/* Use 64 bit arithmetic to prevent overflow */
3712
uint64_t min_aspect_x = hints->min_aspect.x;
3713
uint64_t min_aspect_y = hints->min_aspect.y;
3714
uint64_t max_aspect_x = hints->max_aspect.x;
3715
uint64_t max_aspect_y = hints->max_aspect.y;
3718
if (min_aspect_x * height > width * min_aspect_y)
3720
delta = FLOOR64 (height - width * min_aspect_y / min_aspect_x,
3722
if (height - (int) delta >= min_height)
3726
delta = FLOOR64 (height * min_aspect_x / min_aspect_y - width,
3728
if (width + (int) delta <= max_width)
3733
if (width * max_aspect_y > max_aspect_x * height)
3735
delta = FLOOR64 (width - height * max_aspect_x / max_aspect_y,
3737
if (width - (int) delta >= min_width)
3741
delta = FLOOR64 (width * min_aspect_y / min_aspect_x - height,
3743
if (height + (int) delta <= max_height)
3753
if (width != oldWidth || height != oldHeight)
3756
*newHeight = height;
3767
priv->hidden = true;
3774
priv->hidden = false;
3779
PrivateWindow::hide ()
3781
bool onDesktop = window->onCurrentDesktop ();
3786
if (!window->minimized () && !inShowDesktopMode &&
3787
!hidden && onDesktop)
3789
if (state & CompWindowStateShadedMask)
3802
if ((state & CompWindowStateShadedMask) && frame)
3803
XUnmapWindow (screen->dpy (), frame);
3806
if (!pendingMaps && !window->isViewable ())
3809
window->windowNotify (CompWindowNotifyHide);
3813
if (frame && !shaded)
3814
XUnmapWindow (screen->dpy (), frame);
3816
XUnmapWindow (screen->dpy (), id);
3818
if (window->minimized () || inShowDesktopMode || hidden || shaded)
3819
window->changeState (state | CompWindowStateHiddenMask);
3821
if (shaded && id == screen->activeWindow ())
3822
window->moveInputFocusTo ();
3826
PrivateWindow::show ()
3828
bool onDesktop = window->onCurrentDesktop ();
3833
if (minimized || inShowDesktopMode ||
3834
hidden || !onDesktop)
3836
/* no longer hidden but not on current desktop */
3837
if (!minimized && !inShowDesktopMode && !hidden)
3838
window->changeState (state & ~CompWindowStateHiddenMask);
3843
/* transition from minimized to shaded */
3844
if (state & CompWindowStateShadedMask)
3849
XMapWindow (screen->dpy (), frame);
3853
priv->geometry.setHeight (priv->geometry.height () + 1);
3854
window->resize (geometry.x (), geometry.y (),
3855
geometry.width (), geometry.height () - 1,
3856
geometry.border ());
3866
window->windowNotify (CompWindowNotifyShow);
3872
XMapWindow (screen->dpy (), frame);
3873
XMapWindow (screen->dpy (), wrapper);
3876
XMapWindow (screen->dpy (), id);
3878
window->changeState (state & ~CompWindowStateHiddenMask);
3879
screen->priv->setWindowState (state, id);
3883
PrivateWindow::minimizeTransients (CompWindow *w,
3884
CompWindow *ancestor)
3886
if (w->priv->transientFor == ancestor->priv->id ||
3887
w->priv->isGroupTransient (ancestor->priv->clientLeader))
3894
CompWindow::minimize ()
3896
WRAPABLE_HND_FUNC (13, minimize);
3901
if (!priv->minimized)
3903
windowNotify (CompWindowNotifyMinimize);
3905
priv->minimized = true;
3907
screen->forEachWindow (
3908
boost::bind (PrivateWindow::minimizeTransients, _1, this));
3915
PrivateWindow::unminimizeTransients (CompWindow *w,
3916
CompWindow *ancestor)
3918
if (w->priv->transientFor == ancestor->priv->id ||
3919
w->priv->isGroupTransient (ancestor->priv->clientLeader))
3924
CompWindow::unminimize ()
3926
WRAPABLE_HND_FUNC (14, unminimize);
3927
if (priv->minimized)
3929
windowNotify (CompWindowNotifyUnminimize);
3931
priv->minimized = false;
3935
screen->forEachWindow (
3936
boost::bind (PrivateWindow::unminimizeTransients, _1, this));
3941
CompWindow::maximize (unsigned int state)
3943
if (overrideRedirect ())
3946
state = constrainWindowState (state, priv->actions);
3948
state &= MAXIMIZE_STATE;
3950
if (state == (priv->state & MAXIMIZE_STATE))
3953
state |= (priv->state & ~MAXIMIZE_STATE);
3955
changeState (state);
3956
updateAttributes (CompStackingUpdateModeNone);
3960
PrivateWindow::getUserTime (Time& time)
3964
unsigned long n, left;
3965
unsigned char *data;
3966
bool retval = false;
3968
result = XGetWindowProperty (screen->dpy (), priv->id,
3970
0L, 1L, False, XA_CARDINAL, &actual, &format,
3973
if (result == Success && data)
3979
memcpy (&value, data, sizeof (CARD32));
3981
time = (Time) value;
3984
XFree ((void *) data);
3991
PrivateWindow::setUserTime (Time time)
3993
CARD32 value = (CARD32) time;
3995
XChangeProperty (screen->dpy (), priv->id,
3997
XA_CARDINAL, 32, PropModeReplace,
3998
(unsigned char *) &value, 1);
4002
* Macros from metacity
4004
* Xserver time can wraparound, thus comparing two timestamps needs to
4005
* take this into account. Here's a little macro to help out. If no
4006
* wraparound has occurred, this is equivalent to
4008
* Of course, the rest of the ugliness of this macro comes from
4009
* accounting for the fact that wraparound can occur and the fact that
4010
* a timestamp of 0 must be special-cased since it means older than
4013
* Note that this is NOT an equivalent for time1 <= time2; if that's
4014
* what you need then you'll need to swap the order of the arguments
4015
* and negate the result.
4017
#define XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) \
4018
( (( (time1) < (time2) ) && \
4019
( (time2) - (time1) < ((unsigned long) -1) / 2 )) || \
4020
(( (time1) > (time2) ) && \
4021
( (time1) - (time2) > ((unsigned long) -1) / 2 )) \
4023
#define XSERVER_TIME_IS_BEFORE(time1, time2) \
4025
(XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS (time1, time2) && \
4030
PrivateWindow::getUsageTimestamp (Time& timestamp)
4032
if (getUserTime (timestamp))
4035
if (initialTimestampSet)
4037
timestamp = initialTimestamp;
4045
PrivateWindow::isWindowFocusAllowed (Time timestamp)
4047
CompScreen *s = screen;
4049
Time wUserTime, aUserTime;
4050
bool gotTimestamp = false;
4054
level = s->priv->optionGetFocusPreventionLevel ();
4056
if (level == CoreOptions::FocusPreventionLevelOff)
4061
/* the caller passed a timestamp, so use that
4062
instead of the window's user time */
4063
wUserTime = timestamp;
4064
gotTimestamp = true;
4068
gotTimestamp = getUsageTimestamp (wUserTime);
4071
/* if we got no timestamp for the window, try to get at least a timestamp
4072
for its transient parent, if any */
4073
if (!gotTimestamp && transientFor)
4077
parent = screen->findWindow (transientFor);
4079
gotTimestamp = parent->priv->getUsageTimestamp (wUserTime);
4082
if (gotTimestamp && !wUserTime)
4084
/* window explicitly requested no focus */
4088
/* allow focus for excluded windows */
4089
CompMatch &match = s->priv->optionGetFocusPreventionMatch ();
4090
if (!match.evaluate (window))
4093
if (level == CoreOptions::FocusPreventionLevelVeryHigh)
4096
active = s->findWindow (s->activeWindow ());
4098
/* no active window */
4099
if (!active || (active->type () & CompWindowTypeDesktopMask))
4102
/* active window belongs to same application */
4103
if (window->clientLeader () == active->clientLeader ())
4106
if (level == CoreOptions::FocusPreventionLevelHigh)
4109
/* not in current viewport or desktop */
4110
if (!window->onCurrentDesktop ())
4113
dvp = window->defaultViewport ();
4114
if (dvp.x () != s->vp ().x () || dvp.y () != s->vp ().y ())
4119
/* unsure as we have nothing to compare - allow focus in low level,
4120
don't allow in normal level */
4121
if (level == CoreOptions::FocusPreventionLevelNormal)
4127
/* can't get user time for active window */
4128
if (!active->priv->getUserTime (aUserTime))
4131
if (XSERVER_TIME_IS_BEFORE (wUserTime, aUserTime))
4138
PrivateWindow::allowWindowFocus (unsigned int noFocusMask,
4143
if (priv->id == screen->activeWindow ())
4146
/* do not focus windows of these types */
4147
if (priv->type & noFocusMask)
4150
/* window doesn't take focus */
4151
if (!priv->inputHint &&
4152
!(priv->protocols & CompWindowProtocolTakeFocusMask))
4157
retval = priv->isWindowFocusAllowed (timestamp);
4160
/* add demands attention state if focus was prevented */
4161
window->changeState (priv->state | CompWindowStateDemandsAttentionMask);
4168
CompWindow::defaultViewport ()
4172
if (priv->serverGeometry.x () < (int) screen->width () &&
4173
priv->serverGeometry.x () + priv->serverGeometry.width () > 0 &&
4174
priv->serverGeometry.y () < (int) screen->height () &&
4175
priv->serverGeometry.y ()+ priv->serverGeometry.height () > 0)
4177
return screen->vp ();
4180
screen->viewportForGeometry (priv->serverGeometry, viewport);
4186
CompWindow::initialViewport () const
4188
return priv->initialViewport;
4192
PrivateWindow::readIconHint ()
4194
XImage *image, *maskImage = NULL;
4195
Display *dpy = screen->dpy ();
4196
unsigned int width, height, dummy;
4197
unsigned int i, j, k;
4204
if (!XGetGeometry (dpy, hints->icon_pixmap, &wDummy, &iDummy,
4205
&iDummy, &width, &height, &dummy, &dummy))
4208
image = XGetImage (dpy, hints->icon_pixmap, 0, 0, width, height,
4209
AllPlanes, ZPixmap);
4213
colors = new XColor[width * height];
4216
XDestroyImage (image);
4221
for (j = 0; j < height; j++)
4222
for (i = 0; i < width; i++)
4223
colors[k++].pixel = XGetPixel (image, i, j);
4225
for (i = 0; i < k; i += 256)
4226
XQueryColors (dpy, screen->priv->colormap,
4227
&colors[i], MIN (k - i, 256));
4229
XDestroyImage (image);
4231
icon = new CompIcon (screen, width, height);
4238
if (hints->flags & IconMaskHint)
4239
maskImage = XGetImage (dpy, hints->icon_mask, 0, 0,
4240
width, height, AllPlanes, ZPixmap);
4243
p = (CARD32 *) icon->data ();
4245
for (j = 0; j < height; j++)
4247
for (i = 0; i < width; i++)
4249
if (maskImage && !XGetPixel (maskImage, i, j))
4251
else if (image->depth == 1) /* white : black */
4252
*p++ = colors[k].pixel ? 0xffffffff : 0xff000000;
4254
*p++ = 0xff000000 | /* alpha */
4255
(((colors[k].red >> 8) & 0xff) << 16) | /* red */
4256
(((colors[k].green >> 8) & 0xff) << 8) | /* green */
4257
((colors[k].blue >> 8) & 0xff); /* blue */
4265
XDestroyImage (maskImage);
4267
icons.push_back (icon);
4270
/* returns icon with dimensions as close as possible to width and height
4271
but never greater. */
4273
CompWindow::getIcon (int width,
4277
int wh, diff, oldDiff;
4280
/* need to fetch icon property */
4281
if (priv->icons.size () == 0 && !priv->noIcons)
4285
unsigned long n, left;
4286
unsigned char *data;
4288
result = XGetWindowProperty (screen->dpy (), priv->id, Atoms::wmIcon,
4289
0L, 65536L, false, XA_CARDINAL,
4290
&actual, &format, &n, &left, &data);
4292
if (result == Success && data)
4295
CARD32 alpha, red, green, blue;
4296
unsigned long iw, ih;
4298
for (i = 0; i + 2 < n; i += iw * ih + 2)
4300
unsigned long *idata = (unsigned long *) data;
4305
/* iw * ih may be larger than the value range of unsigned
4306
* long, so better do some checking for extremely weird
4307
* icon sizes first */
4308
if (iw > 2048 || ih > 2048 || iw * ih + 2 > n - i)
4314
icon = new CompIcon (screen, iw, ih);
4318
priv->icons.push_back (icon);
4320
p = (CARD32 *) (icon->data ());
4322
/* EWMH doesn't say if icon data is premultiplied or
4323
not but most applications seem to assume data should
4324
be unpremultiplied. */
4325
for (j = 0; j < iw * ih; j++)
4327
alpha = (idata[i + j + 2] >> 24) & 0xff;
4328
red = (idata[i + j + 2] >> 16) & 0xff;
4329
green = (idata[i + j + 2] >> 8) & 0xff;
4330
blue = (idata[i + j + 2] >> 0) & 0xff;
4332
red = (red * alpha) >> 8;
4333
green = (green * alpha) >> 8;
4334
blue = (blue * alpha) >> 8;
4347
else if (priv->hints && (priv->hints->flags & IconPixmapHint))
4349
priv->readIconHint ();
4352
/* don't fetch property again */
4353
if (priv->icons.size () == 0)
4354
priv->noIcons = true;
4357
/* no icons available for this window */
4362
wh = width + height;
4364
for (i = 0; i < priv->icons.size (); i++)
4366
const CompSize iconSize = *priv->icons[i];
4368
if ((int) iconSize.width () > width ||
4369
(int) iconSize.height () > height)
4374
diff = wh - (iconSize.width () + iconSize.height ());
4375
oldDiff = wh - (icon->width () + icon->height ());
4378
icon = priv->icons[i];
4381
icon = priv->icons[i];
4388
CompWindow::iconGeometry () const
4390
return priv->iconGeometry;
4394
PrivateWindow::freeIcons ()
4396
for (unsigned int i = 0; i < priv->icons.size (); i++)
4397
delete priv->icons[i];
4399
priv->icons.resize (0);
4400
priv->noIcons = false;
4404
CompWindow::outputDevice ()
4406
return screen->outputDeviceForGeometry (priv->serverGeometry);
4410
CompWindow::onCurrentDesktop ()
4412
if (priv->desktop == 0xffffffff ||
4413
priv->desktop == screen->currentDesktop ())
4422
CompWindow::setDesktop (unsigned int desktop)
4424
if (desktop != 0xffffffff)
4426
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
4429
if (desktop >= screen->nDesktop ())
4433
if (desktop == priv->desktop)
4436
priv->desktop = desktop;
4438
if (desktop == 0xffffffff || desktop == screen->currentDesktop ())
4443
screen->setWindowProp (priv->id, Atoms::winDesktop, priv->desktop);
4446
/* The compareWindowActiveness function compares the two windows 'w1'
4447
and 'w2'. It returns an integer less than, equal to, or greater
4448
than zero if 'w1' is found, respectively, to activated longer time
4449
ago than, to be activated at the same time, or be activated more
4450
recently than 'w2'. */
4452
PrivateWindow::compareWindowActiveness (CompWindow *w1,
4455
CompActiveWindowHistory *history = screen->currentHistory ();
4458
/* check current window history first */
4459
for (i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
4461
if (history->id[i] == w1->priv->id)
4464
if (history->id[i] == w2->priv->id)
4467
if (!history->id[i])
4471
return w1->priv->activeNum - w2->priv->activeNum;
4475
CompWindow::onAllViewports ()
4477
if (overrideRedirect ())
4480
if (!priv->managed && !isViewable ())
4483
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
4486
if (priv->state & CompWindowStateStickyMask)
4493
CompWindow::getMovementForOffset (CompPoint offset)
4495
CompScreen *s = screen;
4496
int m, vWidth, vHeight;
4497
int offX = offset.x (), offY = offset.y ();
4500
vWidth = s->width () * s->vpSize ().width ();
4501
vHeight = s->height () * s->vpSize ().height ();
4507
if (s->vpSize ().width () == 1)
4513
m = priv->geometry.x () + offX;
4514
if (m - priv->input.left < (int) s->width () - vWidth)
4515
rv.setX (offX + vWidth);
4516
else if (m + priv->width + priv->input.right > vWidth)
4517
rv.setX (offX - vWidth);
4522
if (s->vpSize ().height () == 1)
4528
m = priv->attrib.y + offY;
4529
if (m - priv->input.top < (int) s->height () - vHeight)
4530
rv.setY (offY + vHeight);
4531
else if (m + priv->height + priv->input.bottom > vHeight)
4532
rv.setY (offY - vHeight);
4541
WindowInterface::getOutputExtents (CompWindowExtents& output)
4542
WRAPABLE_DEF (getOutputExtents, output)
4545
WindowInterface::getAllowedActions (unsigned int &setActions,
4546
unsigned int &clearActions)
4547
WRAPABLE_DEF (getAllowedActions, setActions, clearActions)
4550
WindowInterface::focus ()
4551
WRAPABLE_DEF (focus)
4554
WindowInterface::activate ()
4555
WRAPABLE_DEF (activate)
4558
WindowInterface::place (CompPoint &pos)
4559
WRAPABLE_DEF (place, pos)
4562
WindowInterface::validateResizeRequest (unsigned int &mask,
4563
XWindowChanges *xwc,
4564
unsigned int source)
4565
WRAPABLE_DEF (validateResizeRequest, mask, xwc, source)
4568
WindowInterface::resizeNotify (int dx,
4572
WRAPABLE_DEF (resizeNotify, dx, dy, dwidth, dheight)
4575
WindowInterface::moveNotify (int dx,
4578
WRAPABLE_DEF (moveNotify, dx, dy, immediate)
4581
WindowInterface::windowNotify (CompWindowNotify n)
4582
WRAPABLE_DEF (windowNotify, n)
4585
WindowInterface::grabNotify (int x,
4589
WRAPABLE_DEF (grabNotify, x, y, state, mask)
4592
WindowInterface::ungrabNotify ()
4593
WRAPABLE_DEF (ungrabNotify)
4596
WindowInterface::stateChangeNotify (unsigned int lastState)
4597
WRAPABLE_DEF (stateChangeNotify, lastState)
4600
WindowInterface::updateFrameRegion (CompRegion ®ion)
4601
WRAPABLE_DEF (updateFrameRegion, region)
4604
WindowInterface::minimize ()
4605
WRAPABLE_DEF (minimize);
4608
WindowInterface::unminimize ()
4609
WRAPABLE_DEF (unminimize);
4612
WindowInterface::minimized ()
4613
WRAPABLE_DEF (minimized);
4616
WindowInterface::alpha ()
4617
WRAPABLE_DEF (alpha);
4620
WindowInterface::isFocussable ()
4621
WRAPABLE_DEF (isFocussable);
4624
WindowInterface::managed ()
4625
WRAPABLE_DEF (managed);
4640
CompWindow::state ()
4646
CompWindow::actions ()
4648
return priv->actions;
4652
CompWindow::protocols ()
4654
return priv->protocols;
4658
CompWindow::close (Time serverTime)
4660
if (serverTime == 0)
4661
serverTime = screen->getCurrentTime ();
4665
if (priv->protocols & CompWindowProtocolDeleteMask)
4669
ev.type = ClientMessage;
4670
ev.xclient.window = priv->id;
4671
ev.xclient.message_type = Atoms::wmProtocols;
4672
ev.xclient.format = 32;
4673
ev.xclient.data.l[0] = Atoms::wmDeleteWindow;
4674
ev.xclient.data.l[1] = serverTime;
4675
ev.xclient.data.l[2] = 0;
4676
ev.xclient.data.l[3] = 0;
4677
ev.xclient.data.l[4] = 0;
4679
XSendEvent (screen->dpy (), priv->id, false, NoEventMask, &ev);
4683
XKillClient (screen->dpy (), priv->id);
4686
priv->closeRequests++;
4690
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
4691
serverTime, priv->id, true, 0, 0);
4694
priv->lastCloseRequestTime = serverTime;
4698
PrivateWindow::handlePingTimeout (unsigned int lastPing)
4700
if (!window->isViewable ())
4703
if (!(priv->type & CompWindowTypeNormalMask))
4706
if (priv->protocols & CompWindowProtocolPingMask)
4708
if (priv->transientFor)
4711
if (priv->lastPong < lastPing)
4715
priv->alive = false;
4717
window->windowNotify (CompWindowNotifyAliveChanged);
4719
if (priv->closeRequests)
4721
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
4722
priv->lastCloseRequestTime,
4723
priv->id, true, 0, 0);
4725
priv->closeRequests = 0;
4736
PrivateWindow::handlePing (int lastPing)
4742
window->windowNotify (CompWindowNotifyAliveChanged);
4744
if (priv->lastCloseRequestTime)
4746
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
4747
priv->lastCloseRequestTime,
4748
priv->id, false, 0, 0);
4750
priv->lastCloseRequestTime = 0;
4753
priv->lastPong = lastPing;
4757
PrivateWindow::processMap ()
4760
bool initiallyMinimized;
4761
CompStackingUpdateMode stackingMode;
4763
priv->initialViewport = screen->vp ();
4765
priv->initialTimestampSet = false;
4767
screen->priv->applyStartupProperties (window);
4771
priv->managed = true;
4775
int gravity = priv->sizeHints.win_gravity;
4779
/* adjust for gravity, but only for frame size */
4780
xwc.x = priv->serverGeometry.x ();
4781
xwc.y = priv->serverGeometry.y ();
4785
xwcm = adjustConfigureRequestForGravity (&xwc, CWX | CWY, gravity, 1);
4787
window->validateResizeRequest (xwcm, &xwc, ClientTypeApplication);
4789
CompPoint pos (xwc.x, xwc.y);
4790
if (window->place (pos))
4798
window->configureXWindow (xwcm, &xwc);
4800
priv->placed = true;
4803
initiallyMinimized = (priv->hints &&
4804
priv->hints->initial_state == IconicState &&
4805
!window->minimized ());
4806
allowFocus = allowWindowFocus (NO_FOCUS_MASK, 0);
4808
if (!allowFocus && (priv->type & ~NO_FOCUS_MASK))
4809
stackingMode = CompStackingUpdateModeInitialMapDeniedFocus;
4811
stackingMode = CompStackingUpdateModeInitialMap;
4813
window->updateAttributes (stackingMode);
4815
if (window->minimized () && !initiallyMinimized)
4816
window->unminimize ();
4818
if (!initiallyMinimized)
4820
if (allowFocus && !window->onCurrentDesktop ());
4821
screen->priv->setCurrentDesktop (priv->desktop);
4823
if (!(priv->state & CompWindowStateHiddenMask))
4827
window->moveInputFocusTo ();
4831
window->minimize ();
4832
window->changeState (window->state () | CompWindowStateHiddenMask);
4833
screen->priv->updateClientList ();
4836
screen->leaveShowDesktopMode (window);
4838
if (allowFocus && !window->onCurrentDesktop ())
4839
screen->priv->setCurrentDesktop (priv->desktop);
4841
if (!(priv->state & CompWindowStateHiddenMask))
4845
window->moveInputFocusTo ();
4849
* PrivateWindow::updatePassiveButtonGrabs
4851
* Updates the passive button grabs for a window. When
4852
* one of the specified button + modifier combinations
4853
* for this window is activated, compiz will be given
4854
* an active grab for the window (which we can turn off
4855
* by calling XAllowEvents later in ::handleEvent)
4857
* NOTE: ICCCM says that we are only allowed to grab
4858
* windows that we actually own as a client, so only
4859
* grab the frame window. Additionally, although there
4860
* isn't anything in the ICCCM that says we cannot
4861
* grab every button, some clients do not interpret
4862
* EnterNotify and LeaveNotify events caused by the
4863
* activation of the grab correctly, so ungrab button
4864
* and modifier combinations that we do not need on
4865
* active windows (but in reality we shouldn't be grabbing
4866
* for buttons that we don't actually need at that point
4871
PrivateWindow::updatePassiveButtonGrabs ()
4873
bool onlyActions = (priv->id == screen->priv->activeWindow ||
4874
!screen->priv->optionGetClickToFocus ());
4879
/* Ungrab everything */
4880
XUngrabButton (screen->priv->dpy, AnyButton, AnyModifier, frame);
4882
/* We don't need the full grab in the following cases:
4883
* - This window has the focus and either
4885
* - we don't want click raise
4890
if (screen->priv->optionGetRaiseOnClick ())
4892
for (CompWindow *above = window->next;
4893
above != NULL; above = above->next)
4895
if (above->priv->attrib.map_state != IsViewable)
4898
if (above->type () & CompWindowTypeDockMask)
4901
if (above->region ().intersects (region))
4903
onlyActions = false;
4912
/* Grab only we have bindings on */
4913
foreach (PrivateScreen::ButtonGrab &bind, screen->priv->buttonGrabs)
4915
unsigned int mods = modHandler->virtualToRealModMask (bind.modifiers);
4917
if (mods & CompNoMask)
4920
for (unsigned int ignore = 0;
4921
ignore <= modHandler->ignoredModMask (); ignore++)
4923
if (ignore & ~modHandler->ignoredModMask ())
4926
XGrabButton (screen->priv->dpy,
4931
ButtonPressMask | ButtonReleaseMask |
4942
/* Grab everything */
4943
XGrabButton (screen->priv->dpy,
4947
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
4957
CompWindow::region () const
4959
return priv->region;
4963
CompWindow::frameRegion () const
4965
return priv->frameRegion;
4969
CompWindow::inShowDesktopMode ()
4971
return priv->inShowDesktopMode;
4975
CompWindow::setShowDesktopMode (bool value)
4977
priv->inShowDesktopMode = value;
4981
CompWindow::managed ()
4983
WRAPABLE_HND_FUNC_RETURN (18, bool, managed);
4984
return priv->managed;
4988
CompWindow::grabbed ()
4990
return priv->grabbed;
4994
CompWindow::pendingMaps ()
4996
return priv->pendingMaps;
5000
CompWindow::wmType ()
5002
return priv->wmType;
5006
CompWindow::activeNum ()
5008
return priv->activeNum;
5012
CompWindow::frame ()
5018
CompWindow::resName ()
5021
return priv->resName;
5023
return CompString ();
5027
CompWindow::mapNum () const
5029
return priv->mapNum;
5033
CompWindow::struts ()
5035
return priv->struts;
5039
CompWindow::saveMask ()
5041
return priv->saveMask;
5045
CompWindow::saveWc ()
5047
return priv->saveWc;
5051
CompWindow::moveToViewportPosition (int x,
5056
int vWidth = screen->width () * screen->vpSize ().width ();
5057
int vHeight = screen->height () * screen->vpSize ().height ();
5059
if (screen->vpSize ().width () != 1)
5061
x += screen->vp ().x () * screen->width ();
5062
x = MOD (x, vWidth);
5063
x -= screen->vp ().x () * screen->width ();
5066
if (screen->vpSize ().height () != 1)
5068
y += screen->vp ().y () * screen->height ();
5069
y = MOD (y, vHeight);
5070
y -= screen->vp ().y () * screen->height ();
5073
tx = x - priv->geometry.x ();
5074
ty = y - priv->geometry.y ();
5083
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5086
if (priv->state & CompWindowStateStickyMask)
5092
if (screen->vpSize ().width ()!= 1)
5094
m = priv->geometry.x () + tx;
5096
if (m - priv->output.left < (int) screen->width () - vWidth)
5098
else if (m + priv->width + priv->output.right > vWidth)
5102
if (screen->vpSize ().height () != 1)
5104
m = priv->geometry.y () + ty;
5106
if (m - priv->output.top < (int) screen->height () - vHeight)
5108
else if (m + priv->height + priv->output.bottom > vHeight)
5112
if (priv->saveMask & CWX)
5113
priv->saveWc.x += wx;
5115
if (priv->saveMask & CWY)
5116
priv->saveWc.y += wy;
5126
CompWindow::startupId ()
5128
return priv->startupId;
5132
PrivateWindow::applyStartupProperties (CompStartupSequence *s)
5136
priv->initialViewport.setX (s->viewportX);
5137
priv->initialViewport.setY (s->viewportY);
5139
workspace = sn_startup_sequence_get_workspace (s->sequence);
5141
window->setDesktop (workspace);
5143
priv->initialTimestamp =
5144
sn_startup_sequence_get_timestamp (s->sequence);
5145
priv->initialTimestampSet = true;
5149
CompWindow::desktop ()
5151
return priv->desktop;
5155
CompWindow::clientLeader (bool checkAncestor)
5157
if (priv->clientLeader)
5158
return priv->clientLeader;
5161
return priv->getClientLeaderOfAncestor ();
5167
CompWindow::transientFor ()
5169
return priv->transientFor;
5173
CompWindow::pendingUnmaps ()
5175
return priv->pendingUnmaps;
5179
CompWindow::minimized ()
5181
WRAPABLE_HND_FUNC_RETURN (15, bool, minimized);
5182
return priv->minimized;
5186
CompWindow::placed ()
5188
return priv->placed;
5192
CompWindow::shaded ()
5194
return priv->shaded;
5198
CompWindow::border () const
5200
return priv->border;
5204
CompWindow::input () const
5210
CompWindow::output () const
5212
return priv->output;
5216
CompWindow::sizeHints () const
5218
return priv->sizeHints;
5222
PrivateWindow::updateMwmHints ()
5224
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
5225
window->recalcActions ();
5229
PrivateWindow::updateStartupId ()
5231
char *oldId = startupId;
5234
startupId = getStartupId ();
5236
if (oldId && startupId)
5238
if (strcmp (startupId, oldId) == 0)
5242
if (managed && startupId && newId)
5249
initialTimestampSet = false;
5250
screen->priv->applyStartupProperties (window);
5252
if (initialTimestampSet)
5253
timestamp = initialTimestamp;
5255
/* as the viewport can't be transmitted via startup
5256
notification, assume the client changing the ID
5257
wanted to activate the window on the current viewport */
5259
vp = window->defaultViewport ();
5260
svp = screen->vp ();
5263
x = window->geometry ().x () + (svp.x () - vp.x ()) * size.width ();
5264
y = window->geometry ().y () + (svp.y () - vp.y ()) * size.height ();
5265
window->moveToViewportPosition (x, y, true);
5267
if (allowWindowFocus (0, timestamp))
5268
window->activate ();
5276
CompWindow::destroyed ()
5278
return priv->destroyed;
5282
CompWindow::invisible ()
5284
return priv->invisible;
5288
CompWindow::syncAlarm ()
5290
return priv->syncAlarm;
5294
CoreWindow::manage (Window aboveId, XWindowAttributes &wa)
5296
return new CompWindow (aboveId, wa, priv);
5299
CoreWindow::CoreWindow (Window id)
5301
priv = new PrivateWindow ();
5306
CompWindow::CompWindow (Window aboveId,
5307
XWindowAttributes &wa,
5308
PrivateWindow *priv) :
5309
PluginClassStorage (windowPluginClassIndices),
5312
// TODO: Reparent first!
5314
priv->window = this;
5316
screen->insertWindow (this, aboveId);
5319
priv->serverGeometry.set (priv->attrib.x, priv->attrib.y,
5320
priv->attrib.width, priv->attrib.height,
5321
priv->attrib.border_width);
5322
priv->syncGeometry.set (priv->attrib.x, priv->attrib.y,
5323
priv->attrib.width, priv->attrib.height,
5324
priv->attrib.border_width);
5325
priv->geometry.set (priv->attrib.x, priv->attrib.y,
5326
priv->attrib.width, priv->attrib.height,
5327
priv->attrib.border_width);
5329
priv->width = priv->attrib.width + priv->attrib.border_width * 2;
5330
priv->height = priv->attrib.height + priv->attrib.border_width * 2;
5332
priv->sizeHints.flags = 0;
5334
priv->recalcNormalHints ();
5336
priv->transientFor = None;
5337
priv->clientLeader = None;
5339
XSelectInput (screen->dpy (), priv->id,
5340
wa.your_event_mask |
5341
PropertyChangeMask |
5345
priv->alpha = (priv->attrib.depth == 32);
5346
priv->lastPong = screen->priv->lastPing;
5348
if (screen->XShape ())
5349
XShapeSelectInput (screen->dpy (), priv->id, ShapeNotifyMask);
5351
if (priv->attrib.c_class != InputOnly)
5353
priv->region = CompRegion (priv->attrib.x, priv->attrib.y,
5354
priv->width, priv->height);
5355
priv->inputRegion = priv->region;
5357
/* need to check for DisplayModal state on all windows */
5358
priv->state = screen->priv->getWindowState (priv->id);
5360
priv->updateClassHints ();
5364
priv->attrib.map_state = IsUnmapped;
5367
priv->wmType = screen->priv->getWindowType (priv->id);
5368
priv->protocols = screen->priv->getProtocols (priv->id);
5370
if (!overrideRedirect ())
5372
priv->updateNormalHints ();
5374
priv->updateWmHints ();
5375
priv->updateTransientHint ();
5377
priv->clientLeader = priv->getClientLeader ();
5378
priv->startupId = priv->getStartupId ();
5382
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
5384
if (!(priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask)))
5386
priv->desktop = screen->getWindowProp (priv->id, Atoms::winDesktop,
5388
if (priv->desktop != 0xffffffff)
5390
if (priv->desktop >= screen->nDesktop ())
5391
priv->desktop = screen->currentDesktop ();
5400
if (priv->attrib.map_state == IsViewable)
5402
priv->placed = true;
5404
if (!overrideRedirect ())
5406
// needs to happen right after maprequest
5409
priv->managed = true;
5411
if (screen->priv->getWmState (priv->id) == IconicState)
5413
if (priv->state & CompWindowStateShadedMask)
5414
priv->shaded = true;
5416
priv->minimized = true;
5420
if (priv->wmType & (CompWindowTypeDockMask |
5421
CompWindowTypeDesktopMask))
5423
setDesktop (0xffffffff);
5427
if (priv->desktop != 0xffffffff)
5428
priv->desktop = screen->currentDesktop ();
5430
screen->setWindowProp (priv->id, Atoms::winDesktop,
5436
priv->attrib.map_state = IsUnmapped;
5437
priv->pendingMaps++;
5441
updateAttributes (CompStackingUpdateModeNormal);
5443
if (priv->minimized || priv->inShowDesktopMode ||
5444
priv->hidden || priv->shaded)
5446
priv->state |= CompWindowStateHiddenMask;
5448
priv->pendingUnmaps++;
5450
if (priv->frame && !priv->shaded)
5451
XUnmapWindow (screen->dpy (), priv->frame);
5453
XUnmapWindow (screen->dpy (), priv->id);
5455
screen->priv->setWindowState (priv->state, priv->id);
5458
else if (!overrideRedirect ())
5460
if (screen->priv->getWmState (priv->id) == IconicState)
5462
// before everything else in maprequest
5465
priv->managed = true;
5466
priv->placed = true;
5468
if (priv->state & CompWindowStateHiddenMask)
5470
if (priv->state & CompWindowStateShadedMask)
5471
priv->shaded = true;
5473
priv->minimized = true;
5478
/* TODO: bailout properly when objectInitPlugins fails */
5479
assert (CompPlugin::windowInitPlugins (this));
5482
priv->updateIconGeometry ();
5486
priv->geometry.setHeight (priv->geometry.height () + 1);
5487
resize (priv->geometry.x (), priv->geometry.y (),
5488
priv->geometry.width (), priv->geometry.height () - 1,
5489
priv->geometry.border ());
5492
if (priv->attrib.map_state == IsViewable)
5494
priv->invisible = WINDOW_INVISIBLE (priv);
5498
CompWindow::~CompWindow ()
5500
screen->unhookWindow (this);
5502
if (!priv->destroyed)
5506
priv->unreparent ();
5509
/* restore saved geometry and map if hidden */
5510
if (!priv->attrib.override_redirect)
5513
XConfigureWindow (screen->dpy (), priv->id,
5514
priv->saveMask, &priv->saveWc);
5518
if (priv->state & CompWindowStateHiddenMask)
5519
XMapWindow (screen->dpy (), priv->id);
5523
if (screen->XShape ())
5524
XShapeSelectInput (screen->dpy (), priv->id, NoEventMask);
5526
if (priv->id != screen->priv->grabWindow)
5527
XSelectInput (screen->dpy (), priv->id, NoEventMask);
5529
XUngrabButton (screen->dpy (), AnyButton, AnyModifier, priv->id);
5532
if (priv->attrib.map_state == IsViewable)
5534
if (priv->type == CompWindowTypeDesktopMask)
5535
screen->priv->desktopWindowCount--;
5537
if (priv->destroyed && priv->struts)
5538
screen->updateWorkarea ();
5541
if (priv->destroyed)
5542
screen->priv->updateClientList ();
5544
CompPlugin::windowFiniPlugins (this);
5549
PrivateWindow::PrivateWindow () :
5557
transientFor (None),
5558
clientLeader (None),
5566
type (CompWindowTypeUnknownMask),
5570
mwmDecor (MwmDecorAll),
5571
mwmFunc (MwmFuncAll),
5579
initialViewport (0, 0),
5581
initialTimestamp (0),
5582
initialTimestampSet (false),
5584
fullscreenMonitorsSet (false),
5588
inShowDesktopMode (false),
5618
closeRequests (false),
5619
lastCloseRequestTime (0)
5636
syncWaitTimer.setTimes (1000, 1200);
5637
syncWaitTimer.setCallback (boost::bind (&PrivateWindow::handleSyncAlarm,
5641
PrivateWindow::~PrivateWindow ()
5644
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
5646
syncWaitTimer.stop ();
5649
XDestroyWindow (screen->dpy (), frame);
5671
CompWindow::syncWait ()
5673
return priv->syncWait;
5677
CompWindow::alpha ()
5679
WRAPABLE_HND_FUNC_RETURN (16, bool, alpha);
5685
CompWindow::overrideRedirect ()
5687
return priv->attrib.override_redirect;
5691
PrivateWindow::setOverrideRedirect (bool overrideRedirect)
5693
if (overrideRedirect == window->overrideRedirect ())
5696
priv->attrib.override_redirect = overrideRedirect ? 1 : 0;
5697
window->recalcType ();
5698
window->recalcActions ();
5700
screen->matchPropertyChanged (window);
5704
CompWindow::isMapped () const
5706
return priv->mapNum > 0;
5710
CompWindow::isViewable () const
5712
return (priv->attrib.map_state == IsViewable);
5716
CompWindow::isFocussable ()
5718
WRAPABLE_HND_FUNC_RETURN (17, bool, isFocussable);
5720
if (priv->inputHint)
5723
if (priv->protocols & CompWindowProtocolTakeFocusMask)
5730
CompWindow::windowClass ()
5732
return priv->attrib.c_class;
5736
CompWindow::depth ()
5738
return priv->attrib.depth;
5742
CompWindow::alive ()
5748
CompWindow::mwmDecor ()
5750
return priv->mwmDecor;
5754
CompWindow::mwmFunc ()
5756
return priv->mwmFunc;
5759
/* TODO: This function should be able to check the XShape event
5760
* kind and only get/set shape rectangles for either ShapeInput
5761
* or ShapeBounding, but not both at the same time
5765
CompWindow::updateFrameRegion ()
5767
if (priv->frame && priv->serverGeometry.width () == priv->geometry.width () &&
5768
priv->serverGeometry.height () == priv->geometry.height ())
5773
priv->frameRegion = CompRegion ();
5775
updateFrameRegion (priv->frameRegion);
5779
r = priv->region.boundingRect ();
5780
priv->frameRegion -= r;
5782
r.setGeometry (r.x1 () - priv->input.left,
5783
r.y1 () - priv->input.top,
5784
r.width () + priv->input.right + priv->input.left,
5785
r.height () + priv->input.bottom + priv->input.top);
5787
priv->frameRegion &= CompRegion (r);
5790
x = priv->geometry.x () - priv->input.left;
5791
y = priv->geometry.y () - priv->input.top;
5793
XShapeCombineRegion (screen->dpy (), priv->frame,
5794
ShapeBounding, -x, -y,
5795
priv->frameRegion.united (priv->region).handle (),
5798
XShapeCombineRegion (screen->dpy (), priv->frame,
5800
priv->frameRegion.united (priv->inputRegion).handle (),
5806
CompWindow::setWindowFrameExtents (CompWindowExtents *b,
5807
CompWindowExtents *i)
5809
/* Input extents are used for frame size,
5810
* Border extents used for placement.
5816
if (priv->input.left != i->left ||
5817
priv->input.right != i->right ||
5818
priv->input.top != i->top ||
5819
priv->input.bottom != i->bottom)
5821
unsigned long data[4];
5828
/* Use b for _NET_WM_FRAME_EXTENTS here because
5829
* that is the representation of the actual decoration
5830
* around the window that the user sees and should
5831
* be used for placement and such */
5836
data[3] = b->bottom;
5838
XChangeProperty (screen->dpy (), priv->id,
5839
Atoms::frameExtents,
5840
XA_CARDINAL, 32, PropModeReplace,
5841
(unsigned char *) data, 4);
5843
priv->updateSize ();
5844
priv->updateFrameWindow ();
5849
CompWindow::hasUnmapReference ()
5851
return (priv && priv->unmapRefCnt > 1);
5855
CompWindow::updateFrameRegion (CompRegion& region)
5856
WRAPABLE_HND_FUNC (12, updateFrameRegion, region)
5859
PrivateWindow::reparent ()
5861
XSetWindowAttributes attr;
5864
unsigned int nchildren;
5865
Window *children, root_return, parent_return;
5866
CompWindow::Geometry &sg = serverGeometry;
5867
Display *dpy = screen->dpy ();
5868
Visual *visual = DefaultVisual (screen->dpy (),
5869
screen->screenNum ());
5870
Colormap cmap = DefaultColormap (screen->dpy (),
5871
screen->screenNum ());
5879
if (!XGetWindowAttributes (dpy, id, &attrib))
5881
XUngrabServer (dpy);
5886
if (attrib.override_redirect)
5889
/* Don't ever reparent windows which have ended up
5890
* reparented themselves on the server side but not
5891
* on the client side */
5893
XQueryTree (dpy, id, &root_return, &parent_return, &children, &nchildren);
5895
if (parent_return != root_return)
5898
XUngrabServer (dpy);
5905
XChangeSaveSet (dpy, id, SetModeInsert);
5906
XSelectInput (dpy, id, NoEventMask);
5907
XSelectInput (dpy, screen->root (), NoEventMask);
5909
xwc.border_width = 0;
5910
XConfigureWindow (dpy, id, CWBorderWidth, &xwc);
5912
mask = CWBorderPixel | CWColormap | CWBackPixmap;
5914
if (attrib.depth == 32)
5916
cmap = attrib.colormap;
5917
visual = attrib.visual;
5920
attr.background_pixmap = None;
5921
attr.border_pixel = 0;
5922
attr.colormap = cmap;
5924
frame = XCreateWindow (dpy, screen->root (), 0, 0,
5925
sg.width (), sg.height (), 0, attrib.depth,
5926
InputOutput, visual, mask, &attr);
5928
wrapper = XCreateWindow (dpy, frame, 0, 0,
5929
sg.width (), sg.height (), 0, attrib.depth,
5930
InputOutput, visual, mask, &attr);
5932
xwc.stack_mode = Below;
5935
/* Make sure the frame is underneath the client */
5936
XConfigureWindow (dpy, frame, CWSibling | CWStackMode, &xwc);
5938
/* Wait for the restacking to finish */
5941
/* Always need to have the wrapper window mapped */
5942
XMapWindow (dpy, wrapper);
5944
/* Reparent the client into the wrapper window */
5945
XReparentWindow (dpy, id, wrapper, 0, 0);
5947
/* Restore events */
5948
attr.event_mask = attrib.your_event_mask;
5950
/* We don't care about client events on the frame, and listening for them
5951
* will probably end up fighting the client anyways, so disable them */
5953
attr.do_not_propagate_mask = KeyPressMask | KeyReleaseMask |
5954
ButtonPressMask | ButtonReleaseMask |
5955
EnterWindowMask | LeaveWindowMask |
5956
PointerMotionMask | PointerMotionHintMask |
5957
Button1MotionMask | Button2MotionMask |
5958
Button3MotionMask | Button4MotionMask |
5959
Button5MotionMask | ButtonMotionMask |
5960
KeymapStateMask | ExposureMask |
5961
VisibilityChangeMask | StructureNotifyMask |
5962
ResizeRedirectMask | SubstructureNotifyMask |
5963
SubstructureRedirectMask | FocusChangeMask |
5964
PropertyChangeMask | ColormapChangeMask |
5965
OwnerGrabButtonMask;
5967
XChangeWindowAttributes (dpy, id, CWEventMask | CWDontPropagate, &attr);
5969
if (attrib.map_state == IsViewable || shaded)
5970
XMapWindow (dpy, frame);
5972
attr.event_mask = SubstructureRedirectMask |
5973
SubstructureNotifyMask | EnterWindowMask |
5976
XChangeWindowAttributes (dpy, frame, CWEventMask, &attr);
5977
XChangeWindowAttributes (dpy, wrapper, CWEventMask, &attr);
5979
XSelectInput (dpy, screen->root (),
5980
SubstructureRedirectMask |
5981
SubstructureNotifyMask |
5982
StructureNotifyMask |
5983
PropertyChangeMask |
5993
XUngrabServer (dpy);
5995
XMoveResizeWindow (dpy, frame, sg.x (), sg.y (), sg.width (), sg.height ());
5997
updatePassiveButtonGrabs ();
5999
window->windowNotify (CompWindowNotifyReparent);
6005
PrivateWindow::unreparent ()
6007
Display *dpy = screen->dpy ();
6011
unsigned int nchildren;
6012
Window *children = NULL, root_return, parent_return;
6013
XWindowAttributes wa;
6020
if (XCheckTypedWindowEvent (dpy, id, DestroyNotify, &e))
6022
XPutBackEvent (dpy, &e);
6027
if (!XGetWindowAttributes (dpy, id, &wa))
6031
/* Also don't reparent back into root windows that have ended up
6032
* reparented into other windows (and as such we are unmanaging them) */
6036
XQueryTree (dpy, id, &root_return, &parent_return, &children, &nchildren);
6038
if (parent_return != wrapper)
6042
if ((!destroyed) && alive)
6046
XChangeSaveSet (dpy, id, SetModeDelete);
6047
XSelectInput (dpy, frame, NoEventMask);
6048
XSelectInput (dpy, wrapper, NoEventMask);
6049
XSelectInput (dpy, id, NoEventMask);
6050
XSelectInput (dpy, screen->root (), NoEventMask);
6051
XReparentWindow (dpy, id, screen->root (), 0, 0);
6053
/* Wait for the reparent to finish */
6056
xwc.stack_mode = Below;
6057
xwc.sibling = frame;
6058
XConfigureWindow (dpy, id, CWSibling | CWStackMode, &xwc);
6060
/* Wait for the window to be restacked */
6063
XUnmapWindow (dpy, frame);
6065
XSelectInput (dpy, id, wa.your_event_mask);
6067
XSelectInput (dpy, screen->root (),
6068
SubstructureRedirectMask |
6069
SubstructureNotifyMask |
6070
StructureNotifyMask |
6071
PropertyChangeMask |
6081
XUngrabServer (dpy);
6083
XMoveWindow (dpy, id, serverGeometry.x (), serverGeometry.y ());
6089
XDestroyWindow (dpy, wrapper);
6090
XDestroyWindow (dpy, frame);
6094
window->windowNotify (CompWindowNotifyUnreparent);