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"
48
#include "privatestackdebugger.h"
50
PluginClassStorage::Indices windowPluginClassIndices (0);
53
CompWindow::allocPluginClassIndex ()
55
unsigned int i = PluginClassStorage::allocatePluginClassIndex (windowPluginClassIndices);
57
foreach (CompWindow *w, screen->windows ())
58
if (windowPluginClassIndices.size () != w->pluginClasses.size ())
59
w->pluginClasses.resize (windowPluginClassIndices.size ());
65
CompWindow::freePluginClassIndex (unsigned int index)
67
PluginClassStorage::freePluginClassIndex (windowPluginClassIndices, index);
69
foreach (CompWindow *w, ::screen->windows ())
70
if (windowPluginClassIndices.size () != w->pluginClasses.size ())
71
w->pluginClasses.resize (windowPluginClassIndices.size ());
75
PrivateWindow::isAncestorTo (CompWindow *transient,
78
if (transient->priv->transientFor)
80
if (transient->priv->transientFor == ancestor->priv->id)
83
transient = screen->findWindow (transient->priv->transientFor);
85
return isAncestorTo (transient, ancestor);
92
PrivateWindow::recalcNormalHints ()
96
#warning fixme to max Texture size
98
maxSize -= serverGeometry.border () * 2;
100
sizeHints.x = serverGeometry.x ();
101
sizeHints.y = serverGeometry.y ();
102
sizeHints.width = serverGeometry.width ();
103
sizeHints.height = serverGeometry.height ();
105
if (!(sizeHints.flags & PBaseSize))
107
if (sizeHints.flags & PMinSize)
109
sizeHints.base_width = sizeHints.min_width;
110
sizeHints.base_height = sizeHints.min_height;
114
sizeHints.base_width = 0;
115
sizeHints.base_height = 0;
118
sizeHints.flags |= PBaseSize;
121
if (!(sizeHints.flags & PMinSize))
123
sizeHints.min_width = sizeHints.base_width;
124
sizeHints.min_height = sizeHints.base_height;
125
sizeHints.flags |= PMinSize;
128
if (!(sizeHints.flags & PMaxSize))
130
sizeHints.max_width = 65535;
131
sizeHints.max_height = 65535;
132
sizeHints.flags |= PMaxSize;
135
if (sizeHints.max_width < sizeHints.min_width)
136
sizeHints.max_width = sizeHints.min_width;
138
if (sizeHints.max_height < sizeHints.min_height)
139
sizeHints.max_height = sizeHints.min_height;
141
if (sizeHints.min_width < 1)
142
sizeHints.min_width = 1;
144
if (sizeHints.max_width < 1)
145
sizeHints.max_width = 1;
147
if (sizeHints.min_height < 1)
148
sizeHints.min_height = 1;
150
if (sizeHints.max_height < 1)
151
sizeHints.max_height = 1;
153
if (sizeHints.max_width > maxSize)
154
sizeHints.max_width = maxSize;
156
if (sizeHints.max_height > maxSize)
157
sizeHints.max_height = maxSize;
159
if (sizeHints.min_width > maxSize)
160
sizeHints.min_width = maxSize;
162
if (sizeHints.min_height > maxSize)
163
sizeHints.min_height = maxSize;
165
if (sizeHints.base_width > maxSize)
166
sizeHints.base_width = maxSize;
168
if (sizeHints.base_height > maxSize)
169
sizeHints.base_height = maxSize;
171
if (sizeHints.flags & PResizeInc)
173
if (sizeHints.width_inc == 0)
174
sizeHints.width_inc = 1;
176
if (sizeHints.height_inc == 0)
177
sizeHints.height_inc = 1;
181
sizeHints.width_inc = 1;
182
sizeHints.height_inc = 1;
183
sizeHints.flags |= PResizeInc;
186
if (sizeHints.flags & PAspect)
188
/* don't divide by 0 */
189
if (sizeHints.min_aspect.y < 1)
190
sizeHints.min_aspect.y = 1;
192
if (sizeHints.max_aspect.y < 1)
193
sizeHints.max_aspect.y = 1;
197
sizeHints.min_aspect.x = 1;
198
sizeHints.min_aspect.y = 65535;
199
sizeHints.max_aspect.x = 65535;
200
sizeHints.max_aspect.y = 1;
201
sizeHints.flags |= PAspect;
204
if (!(sizeHints.flags & PWinGravity))
206
sizeHints.win_gravity = NorthWestGravity;
207
sizeHints.flags |= PWinGravity;
212
PrivateWindow::updateNormalHints ()
217
status = XGetWMNormalHints (screen->dpy (), priv->id,
218
&priv->sizeHints, &supplied);
221
priv->sizeHints.flags = 0;
223
priv->recalcNormalHints ();
227
PrivateWindow::updateWmHints ()
231
bool iconChanged = false;
234
dFlags = hints->flags;
238
newHints = XGetWMHints (screen->dpy (), id);
241
dFlags ^= newHints->flags;
243
if (newHints->flags & InputHint)
244
inputHint = newHints->input;
248
if ((newHints->flags & IconPixmapHint) &&
249
(hints->icon_pixmap != newHints->icon_pixmap))
253
else if ((newHints->flags & IconMaskHint) &&
254
(hints->icon_mask != newHints->icon_mask))
261
iconChanged |= (dFlags & (IconPixmapHint | IconMaskHint));
273
PrivateWindow::updateClassHints ()
275
XClassHint classHint;
280
free (priv->resName);
281
priv->resName = NULL;
286
free (priv->resClass);
287
priv->resClass = NULL;
290
status = XGetClassHint (screen->dpy (),
291
priv->id, &classHint);
294
if (classHint.res_name)
296
priv->resName = strdup (classHint.res_name);
297
XFree (classHint.res_name);
300
if (classHint.res_class)
302
priv->resClass = strdup (classHint.res_class);
303
XFree (classHint.res_class);
309
PrivateWindow::updateTransientHint ()
314
priv->transientFor = None;
316
status = XGetTransientForHint (screen->dpy (),
317
priv->id, &transientFor);
321
CompWindow *ancestor;
323
ancestor = screen->findWindow (transientFor);
327
/* protect against circular transient dependencies */
328
if (transientFor == priv->id ||
329
PrivateWindow::isAncestorTo (ancestor, window))
332
priv->transientFor = transientFor;
337
PrivateWindow::updateIconGeometry ()
341
unsigned long n, left;
344
priv->iconGeometry.setGeometry (0, 0, 0, 0);
346
result = XGetWindowProperty (screen->dpy (), priv->id,
347
Atoms::wmIconGeometry,
348
0L, 1024L, False, XA_CARDINAL,
349
&actual, &format, &n, &left, &data);
351
if (result == Success && data)
355
unsigned long *geometry = (unsigned long *) data;
357
priv->iconGeometry.setX (geometry[0]);
358
priv->iconGeometry.setY (geometry[1]);
359
priv->iconGeometry.setWidth (geometry[2]);
360
priv->iconGeometry.setHeight (geometry[3]);
368
PrivateWindow::getClientLeaderOfAncestor ()
372
CompWindow *w = screen->findWindow (transientFor);
375
if (w->priv->clientLeader)
376
return w->priv->clientLeader;
378
return w->priv->getClientLeaderOfAncestor ();
386
PrivateWindow::getClientLeader ()
390
unsigned long n, left;
393
result = XGetWindowProperty (screen->dpy (), priv->id,
394
Atoms::wmClientLeader,
395
0L, 1L, False, XA_WINDOW, &actual, &format,
398
if (result == Success && data)
403
memcpy (&win, data, sizeof (Window));
405
XFree ((void *) data);
411
return priv->getClientLeaderOfAncestor ();
415
PrivateWindow::getStartupId ()
419
unsigned long n, left;
422
result = XGetWindowProperty (screen->dpy (), priv->id,
429
if (result == Success && data)
434
id = strdup ((char *) data);
435
XFree ((void *) data);
444
PrivateWindow::setFullscreenMonitors (CompFullscreenMonitorSet *monitors)
446
bool hadFsMonitors = fullscreenMonitorsSet;
447
unsigned int outputs = screen->outputDevs ().size ();
449
fullscreenMonitorsSet = false;
452
(unsigned int) monitors->left < outputs &&
453
(unsigned int) monitors->right < outputs &&
454
(unsigned int) monitors->top < outputs &&
455
(unsigned int) monitors->bottom < outputs)
457
CompRect fsRect (screen->outputDevs ()[monitors->left].x1 (),
458
screen->outputDevs ()[monitors->top].y1 (),
459
screen->outputDevs ()[monitors->right].x2 (),
460
screen->outputDevs ()[monitors->bottom].y2 ());
462
if (fsRect.x1 () < fsRect.x2 () && fsRect.y1 () < fsRect.y2 ())
464
fullscreenMonitorsSet = true;
465
fullscreenMonitorRect = fsRect;
469
if (fullscreenMonitorsSet)
473
data[0] = monitors->top;
474
data[1] = monitors->bottom;
475
data[2] = monitors->left;
476
data[3] = monitors->right;
478
XChangeProperty (screen->dpy (), id, Atoms::wmFullscreenMonitors,
479
XA_CARDINAL, 32, PropModeReplace,
480
(unsigned char *) data, 4);
482
else if (hadFsMonitors)
484
XDeleteProperty (screen->dpy (), id, Atoms::wmFullscreenMonitors);
487
if (state & CompWindowStateFullscreenMask)
488
if (fullscreenMonitorsSet || hadFsMonitors)
489
window->updateAttributes (CompStackingUpdateModeNone);
493
CompWindow::changeState (unsigned int newState)
495
unsigned int oldState;
497
if (priv->state == newState)
500
oldState = priv->state;
501
priv->state = newState;
507
screen->priv->setWindowState (priv->state, priv->id);
509
stateChangeNotify (oldState);
510
screen->matchPropertyChanged (this);
514
setWindowActions (CompScreen *s,
515
unsigned int actions,
521
if (actions & CompWindowActionMoveMask)
522
data[i++] = Atoms::winActionMove;
523
if (actions & CompWindowActionResizeMask)
524
data[i++] = Atoms::winActionResize;
525
if (actions & CompWindowActionStickMask)
526
data[i++] = Atoms::winActionStick;
527
if (actions & CompWindowActionMinimizeMask)
528
data[i++] = Atoms::winActionMinimize;
529
if (actions & CompWindowActionMaximizeHorzMask)
530
data[i++] = Atoms::winActionMaximizeHorz;
531
if (actions & CompWindowActionMaximizeVertMask)
532
data[i++] = Atoms::winActionMaximizeVert;
533
if (actions & CompWindowActionFullscreenMask)
534
data[i++] = Atoms::winActionFullscreen;
535
if (actions & CompWindowActionCloseMask)
536
data[i++] = Atoms::winActionClose;
537
if (actions & CompWindowActionShadeMask)
538
data[i++] = Atoms::winActionShade;
539
if (actions & CompWindowActionChangeDesktopMask)
540
data[i++] = Atoms::winActionChangeDesktop;
541
if (actions & CompWindowActionAboveMask)
542
data[i++] = Atoms::winActionAbove;
543
if (actions & CompWindowActionBelowMask)
544
data[i++] = Atoms::winActionBelow;
546
XChangeProperty (s->dpy (), id, Atoms::wmAllowedActions,
547
XA_ATOM, 32, PropModeReplace,
548
(unsigned char *) data, i);
552
CompWindow::recalcActions ()
554
unsigned int actions = 0;
555
unsigned int setActions, clearActions;
557
switch (priv->type) {
558
case CompWindowTypeFullscreenMask:
559
case CompWindowTypeNormalMask:
561
CompWindowActionMaximizeHorzMask |
562
CompWindowActionMaximizeVertMask |
563
CompWindowActionFullscreenMask |
564
CompWindowActionMoveMask |
565
CompWindowActionResizeMask |
566
CompWindowActionStickMask |
567
CompWindowActionMinimizeMask |
568
CompWindowActionCloseMask |
569
CompWindowActionChangeDesktopMask;
571
case CompWindowTypeUtilMask:
572
case CompWindowTypeMenuMask:
573
case CompWindowTypeToolbarMask:
575
CompWindowActionMoveMask |
576
CompWindowActionResizeMask |
577
CompWindowActionStickMask |
578
CompWindowActionCloseMask |
579
CompWindowActionChangeDesktopMask;
581
case CompWindowTypeDialogMask:
582
case CompWindowTypeModalDialogMask:
584
CompWindowActionMaximizeHorzMask |
585
CompWindowActionMaximizeVertMask |
586
CompWindowActionMoveMask |
587
CompWindowActionResizeMask |
588
CompWindowActionStickMask |
589
CompWindowActionCloseMask |
590
CompWindowActionChangeDesktopMask;
592
/* allow minimization for dialog windows if they
593
a) are not a transient (transients can be minimized
595
b) don't have the skip taskbar hint set (as those
596
have no target to be minimized to)
598
if (!priv->transientFor &&
599
!(priv->state & CompWindowStateSkipTaskbarMask))
601
actions |= CompWindowActionMinimizeMask;
608
actions |= CompWindowActionShadeMask;
610
actions |= (CompWindowActionAboveMask | CompWindowActionBelowMask);
612
switch (priv->wmType) {
613
case CompWindowTypeNormalMask:
614
actions |= CompWindowActionFullscreenMask |
615
CompWindowActionMinimizeMask;
620
if (priv->sizeHints.min_width == priv->sizeHints.max_width &&
621
priv->sizeHints.min_height == priv->sizeHints.max_height)
622
actions &= ~(CompWindowActionResizeMask |
623
CompWindowActionMaximizeHorzMask |
624
CompWindowActionMaximizeVertMask |
625
CompWindowActionFullscreenMask);
627
if (!(priv->mwmFunc & MwmFuncAll))
629
if (!(priv->mwmFunc & MwmFuncResize))
630
actions &= ~(CompWindowActionResizeMask |
631
CompWindowActionMaximizeHorzMask |
632
CompWindowActionMaximizeVertMask |
633
CompWindowActionFullscreenMask);
635
if (!(priv->mwmFunc & MwmFuncMove))
636
actions &= ~(CompWindowActionMoveMask |
637
CompWindowActionMaximizeHorzMask |
638
CompWindowActionMaximizeVertMask |
639
CompWindowActionFullscreenMask);
641
if (!(priv->mwmFunc & MwmFuncIconify))
642
actions &= ~CompWindowActionMinimizeMask;
644
if (!(priv->mwmFunc & MwmFuncClose))
645
actions &= ~CompWindowActionCloseMask;
648
getAllowedActions (setActions, clearActions);
649
actions &= ~clearActions;
650
actions |= setActions;
652
if (actions != priv->actions)
654
priv->actions = actions;
655
setWindowActions (screen, actions, priv->id);
660
CompWindow::getAllowedActions (unsigned int &setActions,
661
unsigned int &clearActions)
663
WRAPABLE_HND_FUNC (1, getAllowedActions, setActions, clearActions)
670
CompWindow::constrainWindowState (unsigned int state,
671
unsigned int actions)
673
if (!(actions & CompWindowActionMaximizeHorzMask))
674
state &= ~CompWindowStateMaximizedHorzMask;
676
if (!(actions & CompWindowActionMaximizeVertMask))
677
state &= ~CompWindowStateMaximizedVertMask;
679
if (!(actions & CompWindowActionShadeMask))
680
state &= ~CompWindowStateShadedMask;
682
if (!(actions & CompWindowActionFullscreenMask))
683
state &= ~CompWindowStateFullscreenMask;
689
PrivateWindow::windowTypeFromString (const char *str)
691
if (strcasecmp (str, "desktop") == 0)
692
return CompWindowTypeDesktopMask;
693
else if (strcasecmp (str, "dock") == 0)
694
return CompWindowTypeDockMask;
695
else if (strcasecmp (str, "toolbar") == 0)
696
return CompWindowTypeToolbarMask;
697
else if (strcasecmp (str, "menu") == 0)
698
return CompWindowTypeMenuMask;
699
else if (strcasecmp (str, "utility") == 0)
700
return CompWindowTypeUtilMask;
701
else if (strcasecmp (str, "splash") == 0)
702
return CompWindowTypeSplashMask;
703
else if (strcasecmp (str, "dialog") == 0)
704
return CompWindowTypeDialogMask;
705
else if (strcasecmp (str, "normal") == 0)
706
return CompWindowTypeNormalMask;
707
else if (strcasecmp (str, "dropdownmenu") == 0)
708
return CompWindowTypeDropdownMenuMask;
709
else if (strcasecmp (str, "popupmenu") == 0)
710
return CompWindowTypePopupMenuMask;
711
else if (strcasecmp (str, "tooltip") == 0)
712
return CompWindowTypeTooltipMask;
713
else if (strcasecmp (str, "notification") == 0)
714
return CompWindowTypeNotificationMask;
715
else if (strcasecmp (str, "combo") == 0)
716
return CompWindowTypeComboMask;
717
else if (strcasecmp (str, "dnd") == 0)
718
return CompWindowTypeDndMask;
719
else if (strcasecmp (str, "modaldialog") == 0)
720
return CompWindowTypeModalDialogMask;
721
else if (strcasecmp (str, "fullscreen") == 0)
722
return CompWindowTypeFullscreenMask;
723
else if (strcasecmp (str, "unknown") == 0)
724
return CompWindowTypeUnknownMask;
725
else if (strcasecmp (str, "any") == 0)
732
CompWindow::recalcType ()
738
if (!overrideRedirect () && priv->wmType == CompWindowTypeUnknownMask)
739
type = CompWindowTypeNormalMask;
741
if (priv->state & CompWindowStateFullscreenMask)
742
type = CompWindowTypeFullscreenMask;
744
if (type == CompWindowTypeNormalMask)
746
if (priv->transientFor)
747
type = CompWindowTypeDialogMask;
750
if (type == CompWindowTypeDockMask &&
751
(priv->state & CompWindowStateBelowMask))
753
type = CompWindowTypeNormalMask;
756
if ((type & (CompWindowTypeNormalMask | CompWindowTypeDialogMask)) &&
757
(priv->state & CompWindowStateModalMask))
759
type = CompWindowTypeModalDialogMask;
767
PrivateWindow::updateFrameWindow ()
770
unsigned int valueMask = CWX | CWY | CWWidth | CWHeight;
775
/* Flush any changes made to serverFrameGeometry or serverGeometry to the server
776
* since there is a race condition where geometries will go out-of-sync with
779
window->syncPosition ();
780
if (serverInput.left || serverInput.right || serverInput.top || serverInput.bottom)
782
int bw = serverGeometry.border () * 2;
784
xwc.x = serverGeometry.x () - serverInput.left;
785
xwc.y = serverGeometry.y () - serverInput.top;
786
xwc.width = serverGeometry.width () + serverInput.left + serverInput.right + bw;
787
xwc.height = serverGeometry.height () + serverInput.top + serverInput.bottom + bw;
790
height = serverInput.top + serverInput.bottom;
792
if (serverFrameGeometry.x () == xwc.x)
795
serverFrameGeometry.setX (xwc.x);
797
if (serverFrameGeometry.y () == xwc.y)
800
serverFrameGeometry.setY (xwc.y);
802
if (serverFrameGeometry.width () == xwc.width)
803
valueMask &= ~(CWWidth);
805
serverFrameGeometry.setWidth (xwc.width);
807
if (serverFrameGeometry.height () == xwc.height)
808
valueMask &= ~(CWHeight);
810
serverFrameGeometry.setHeight (xwc.height);
812
addPendingConfigure (xwc, valueMask);
815
/* Geometry is the same, so we're not going to get a ConfigureNotify
816
* event when the window is configured, which means that other plugins
817
* won't know that the client, frame and wrapper windows got shifted
818
* around (and might result in display corruption, eg in OpenGL */
822
XWindowAttributes attrib;
823
unsigned int nchildren = 0;
824
Window rootRet = 0, parentRet = 0;
825
Window *children = NULL;
827
xev.type = ConfigureNotify;
828
xev.event = screen->root ();
829
xev.window = priv->serverFrame;
831
XGrabServer (screen->dpy ());
833
if (XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib))
837
xev.width = attrib.width;
838
xev.height = attrib.height;
839
xev.border_width = attrib.border_width;
842
/* We need to ensure that the stacking order is
843
* based on the current server stacking order so
844
* find the sibling to this window's frame in the
845
* server side stack and stack above that */
846
XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
850
for (unsigned int i = 0; i < nchildren; i++)
852
if (i + 1 == nchildren ||
853
children[i + 1] == ROOTPARENT (window))
855
xev.above = children[i];
865
xev.above = (window->serverPrev) ? ROOTPARENT (window->serverPrev) : None;
867
xev.override_redirect = priv->attrib.override_redirect;
871
XSendEvent (screen->dpy (), screen->root (), false,
872
SubstructureNotifyMask, (XEvent *) &xev);
874
XUngrabServer (screen->dpy ());
875
XSync (screen->dpy (), false);
878
XConfigureWindow (screen->dpy (), serverFrame, valueMask, &xwc);
881
XUnmapWindow (screen->dpy (), wrapper);
885
XMapWindow (screen->dpy (), wrapper);
886
XMoveResizeWindow (screen->dpy (), wrapper, serverInput.left, serverInput.top,
887
serverGeometry.width (), serverGeometry.height ());
889
XMoveResizeWindow (screen->dpy (), id, 0, 0,
890
serverGeometry.width (), serverGeometry.height ());
891
window->sendConfigureNotify ();
892
window->windowNotify (CompWindowNotifyFrameUpdate);
896
int bw = serverGeometry.border () * 2;
898
xwc.x = serverGeometry.x ();
899
xwc.y = serverGeometry.y ();
900
xwc.width = serverGeometry.width () + bw;
901
xwc.height = serverGeometry.height () + bw;
906
if (serverFrameGeometry.x () == xwc.x)
909
serverFrameGeometry.setX (xwc.x);
911
if (serverFrameGeometry.y () == xwc.y)
914
serverFrameGeometry.setY (xwc.y);
916
if (serverFrameGeometry.width () == xwc.width)
917
valueMask &= ~(CWWidth);
919
serverFrameGeometry.setWidth (xwc.width);
921
if (serverFrameGeometry.height () == xwc.height)
922
valueMask &= ~(CWHeight);
924
serverFrameGeometry.setHeight (xwc.height);
926
addPendingConfigure (xwc, valueMask);
929
/* Geometry is the same, so we're not going to get a ConfigureNotify
930
* event when the window is configured, which means that other plugins
931
* won't know that the client, frame and wrapper windows got shifted
932
* around (and might result in display corruption, eg in OpenGL */
936
XWindowAttributes attrib;
937
unsigned int nchildren = 0;
938
Window rootRet = 0, parentRet = 0;
939
Window *children = NULL;
941
xev.type = ConfigureNotify;
942
xev.event = screen->root ();
943
xev.window = priv->serverFrame;
945
XGrabServer (screen->dpy ());
947
if (XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib))
951
xev.width = attrib.width;
952
xev.height = attrib.height;
953
xev.border_width = attrib.border_width;
956
/* We need to ensure that the stacking order is
957
* based on the current server stacking order so
958
* find the sibling to this window's frame in the
959
* server side stack and stack above that */
960
XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
964
for (unsigned int i = 0; i < nchildren; i++)
966
if (i + 1 == nchildren ||
967
children[i + 1] == ROOTPARENT (window))
969
xev.above = children[i];
979
xev.above = (window->serverPrev) ? ROOTPARENT (window->serverPrev) : None;
981
xev.override_redirect = priv->attrib.override_redirect;
985
XSendEvent (screen->dpy (), screen->root (), false,
986
SubstructureNotifyMask, (XEvent *) &xev);
988
XUngrabServer (screen->dpy ());
989
XSync (screen->dpy (), false);
992
XConfigureWindow (screen->dpy (), serverFrame, valueMask, &xwc);
996
XUnmapWindow (screen->dpy (), wrapper);
1000
XMapWindow (screen->dpy (), wrapper);
1001
XMoveResizeWindow (screen->dpy (), wrapper, 0, 0,
1002
serverGeometry.width (), serverGeometry.height ());
1005
XMoveResizeWindow (screen->dpy (), id, 0, 0,
1006
serverGeometry.width (), serverGeometry.height ());
1007
window->sendConfigureNotify ();
1008
window->windowNotify (CompWindowNotifyFrameUpdate);
1010
window->recalcActions ();
1016
CompWindow::updateWindowOutputExtents ()
1018
CompWindowExtents output (priv->output);
1020
getOutputExtents (output);
1022
if (output.left != priv->output.left ||
1023
output.right != priv->output.right ||
1024
output.top != priv->output.top ||
1025
output.bottom != priv->output.bottom)
1027
priv->output = output;
1029
resizeNotify (0, 0, 0, 0);
1034
CompWindow::getOutputExtents (CompWindowExtents& output)
1036
WRAPABLE_HND_FUNC (0, getOutputExtents, output)
1045
PrivateWindow::rectsToRegion (unsigned int n, XRectangle *rects)
1050
for (unsigned int i = 0; i < n; i++)
1052
x1 = rects[i].x + priv->geometry.border ();
1053
y1 = rects[i].y + priv->geometry.border ();
1054
x2 = x1 + rects[i].width;
1055
y2 = y1 + rects[i].height;
1061
if (x2 > priv->width)
1063
if (y2 > priv->height)
1066
if (y1 < y2 && x1 < x2)
1068
x1 += priv->geometry.x ();
1069
y1 += priv->geometry.y ();
1070
x2 += priv->geometry.x ();
1071
y2 += priv->geometry.y ();
1073
ret += CompRect (x1, y1, x2 - x1, y2 - y1);
1080
/* TODO: This function should be able to check the XShape event
1081
* kind and only get/set shape rectangles for either ShapeInput
1082
* or ShapeBounding, but not both at the same time
1086
PrivateWindow::updateRegion ()
1088
XRectangle r, *boundingShapeRects = NULL;
1089
XRectangle *inputShapeRects = NULL;
1090
int nBounding = 0, nInput = 0;
1092
priv->region = CompRegion ();
1093
priv->inputRegion = CompRegion ();
1095
if (screen->XShape ())
1099
boundingShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
1100
ShapeBounding, &nBounding, &order);
1101
inputShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
1102
ShapeInput, &nInput, &order);
1106
r.x = -priv->attrib.border_width;
1107
r.y = -priv->attrib.border_width;
1108
r.width = priv->width + priv->attrib.border_width;
1109
r.height = priv->height + priv->attrib.border_width;
1113
boundingShapeRects = &r;
1119
inputShapeRects = &r;
1123
priv->region += rectsToRegion (nBounding, boundingShapeRects);
1124
priv->inputRegion += rectsToRegion (nInput, inputShapeRects);
1126
if (boundingShapeRects && boundingShapeRects != &r)
1127
XFree (boundingShapeRects);
1128
if (inputShapeRects && inputShapeRects != &r)
1129
XFree (inputShapeRects);
1131
window->updateFrameRegion ();
1135
CompWindow::updateStruts ()
1139
unsigned long n, left;
1140
unsigned char *data;
1141
bool hasOld, hasNew;
1142
CompStruts oldStrut, newStrut;
1148
oldStrut.left = priv->struts->left;
1149
oldStrut.right = priv->struts->right;
1150
oldStrut.top = priv->struts->top;
1151
oldStrut.bottom = priv->struts->bottom;
1160
newStrut.left.x = 0;
1161
newStrut.left.y = 0;
1162
newStrut.left.width = 0;
1163
newStrut.left.height = screen->height ();
1165
newStrut.right.x = screen->width ();
1166
newStrut.right.y = 0;
1167
newStrut.right.width = 0;
1168
newStrut.right.height = screen->height ();
1172
newStrut.top.width = screen->width ();
1173
newStrut.top.height = 0;
1175
newStrut.bottom.x = 0;
1176
newStrut.bottom.y = screen->height ();
1177
newStrut.bottom.width = screen->width ();
1178
newStrut.bottom.height = 0;
1180
result = XGetWindowProperty (screen->dpy (), priv->id,
1181
Atoms::wmStrutPartial,
1182
0L, 12L, false, XA_CARDINAL, &actual, &format,
1185
if (result == Success && data)
1187
unsigned long *struts = (unsigned long *) data;
1193
newStrut.left.y = struts[4];
1194
newStrut.left.width = struts[0];
1195
newStrut.left.height = struts[5] - newStrut.left.y + 1;
1197
newStrut.right.width = struts[1];
1198
newStrut.right.x = screen->width () - newStrut.right.width;
1199
newStrut.right.y = struts[6];
1200
newStrut.right.height = struts[7] - newStrut.right.y + 1;
1202
newStrut.top.x = struts[8];
1203
newStrut.top.width = struts[9] - newStrut.top.x + 1;
1204
newStrut.top.height = struts[2];
1206
newStrut.bottom.x = struts[10];
1207
newStrut.bottom.width = struts[11] - newStrut.bottom.x + 1;
1208
newStrut.bottom.height = struts[3];
1209
newStrut.bottom.y = screen->height () - newStrut.bottom.height;
1217
result = XGetWindowProperty (screen->dpy (), priv->id,
1219
0L, 4L, false, XA_CARDINAL,
1220
&actual, &format, &n, &left, &data);
1222
if (result == Success && data)
1224
unsigned long *struts = (unsigned long *) data;
1230
newStrut.left.x = 0;
1231
newStrut.left.width = struts[0];
1233
newStrut.right.width = struts[1];
1234
newStrut.right.x = screen->width () - newStrut.right.width;
1237
newStrut.top.height = struts[2];
1239
newStrut.bottom.height = struts[3];
1240
newStrut.bottom.y = screen->height () - newStrut.bottom.height;
1249
int strutX1, strutY1, strutX2, strutY2;
1252
/* applications expect us to clip struts to xinerama edges */
1253
for (unsigned int i = 0;
1254
i < screen->screenInfo ().size (); i++)
1256
x1 = screen->screenInfo ()[i].x_org;
1257
y1 = screen->screenInfo ()[i].y_org;
1258
x2 = x1 + screen->screenInfo ()[i].width;
1259
y2 = y1 + screen->screenInfo ()[i].height;
1261
strutX1 = newStrut.left.x;
1262
strutX2 = strutX1 + newStrut.left.width;
1263
strutY1 = newStrut.left.y;
1264
strutY2 = strutY1 + newStrut.left.height;
1266
if (strutX2 > x1 && strutX2 <= x2 &&
1267
strutY1 < y2 && strutY2 > y1)
1269
newStrut.left.x = x1;
1270
newStrut.left.width = strutX2 - x1;
1273
strutX1 = newStrut.right.x;
1274
strutX2 = strutX1 + newStrut.right.width;
1275
strutY1 = newStrut.right.y;
1276
strutY2 = strutY1 + newStrut.right.height;
1278
if (strutX1 > x1 && strutX1 <= x2 &&
1279
strutY1 < y2 && strutY2 > y1)
1281
newStrut.right.x = strutX1;
1282
newStrut.right.width = x2 - strutX1;
1285
strutX1 = newStrut.top.x;
1286
strutX2 = strutX1 + newStrut.top.width;
1287
strutY1 = newStrut.top.y;
1288
strutY2 = strutY1 + newStrut.top.height;
1290
if (strutX1 < x2 && strutX2 > x1 &&
1291
strutY2 > y1 && strutY2 <= y2)
1293
newStrut.top.y = y1;
1294
newStrut.top.height = strutY2 - y1;
1297
strutX1 = newStrut.bottom.x;
1298
strutX2 = strutX1 + newStrut.bottom.width;
1299
strutY1 = newStrut.bottom.y;
1300
strutY2 = strutY1 + newStrut.bottom.height;
1302
if (strutX1 < x2 && strutX2 > x1 &&
1303
strutY1 > y1 && strutY1 <= y2)
1305
newStrut.bottom.y = strutY1;
1306
newStrut.bottom.height = y2 - strutY1;
1311
if (hasOld != hasNew ||
1312
(hasNew && hasOld &&
1313
memcmp (&newStrut, &oldStrut, sizeof (CompStruts))))
1319
priv->struts = (CompStruts *) malloc (sizeof (CompStruts));
1324
*priv->struts = newStrut;
1328
free (priv->struts);
1329
priv->struts = NULL;
1339
CompWindow::incrementDestroyReference ()
1341
priv->destroyRefCnt++;
1345
CompWindow::destroy ()
1349
CompWindow *oldServerNext, *oldServerPrev, *oldNext, *oldPrev;
1350
StackDebugger *dbg = StackDebugger::Default ();
1352
windowNotify (CompWindowNotifyBeforeDestroy);
1354
/* Don't allow frame windows to block input */
1355
XUnmapWindow (screen->dpy (), priv->serverFrame);
1356
XUnmapWindow (screen->dpy (), priv->wrapper);
1358
oldServerNext = serverNext;
1359
oldServerPrev = serverPrev;
1363
/* This is where things get tricky ... it is possible
1364
* to receive a ConfigureNotify relative to a frame window
1365
* for a destroyed window in case we process a ConfigureRequest
1366
* for the destroyed window and then a DestroyNotify for it directly
1367
* afterwards. In that case, we will receive the ConfigureNotify
1368
* for the XConfigureWindow request we made relative to that frame
1369
* window. Because of this, we must keep the frame window in the stack
1370
* as a new toplevel window so that the ConfigureNotify will be processed
1371
* properly until it too receives a DestroyNotify */
1373
if (priv->serverFrame)
1375
XWindowAttributes attrib;
1377
/* It's possible that the frame window was already destroyed because
1378
* the client was unreparented before it was destroyed (eg
1379
* UnmapNotify before DestroyNotify). In that case the frame window
1380
* is going to be an invalid window but since we haven't received
1381
* a DestroyNotify for it yet, it is possible that restacking
1382
* operations could occurr relative to it so we need to hold it
1383
* in the stack for now. Ensure that it is marked override redirect */
1384
XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib);
1386
/* Put the frame window "above" the client window
1388
CoreWindow *cw = new CoreWindow (priv->serverFrame);
1389
cw->manage (priv->id, attrib);
1390
screen->priv->createdWindows.remove (cw);
1394
/* Immediately unhook the window once destroyed
1395
* as the stacking order will be invalid if we don't
1396
* and will continue to be invalid for the period
1397
* that we keep it around in the stack. Instead, push
1398
* it to another stack and keep the next and prev members
1399
* in tact, letting plugins sort out where those windows
1400
* might be in case they need to use them relative to
1403
screen->unhookWindow (this);
1404
screen->unhookServerWindow (this);
1406
/* We must immediately insert the window into the debugging
1409
dbg->removeServerWindow (id ());
1411
/* Unhooking the window will also NULL the next/prev
1412
* linked list links but we don't want that so don't
1417
serverNext = oldServerNext;
1418
serverPrev = oldServerPrev;
1420
screen->priv->destroyedWindows.push_back (this);
1422
/* We must set the xid of this window
1423
* to zero as it no longer references
1428
priv->serverFrame = 0;
1431
priv->destroyRefCnt--;
1432
if (priv->destroyRefCnt)
1435
if (!priv->destroyed)
1437
if (!priv->serverFrame)
1439
StackDebugger *dbg = StackDebugger::Default ();
1442
dbg->addDestroyedFrame (priv->serverId);
1445
priv->destroyed = true;
1446
screen->priv->pendingDestroys++;
1452
CompWindow::sendConfigureNotify ()
1454
XConfigureEvent xev;
1455
XWindowAttributes attrib;
1456
unsigned int nchildren;
1457
Window rootRet, parentRet;
1460
xev.type = ConfigureNotify;
1461
xev.event = priv->id;
1462
xev.window = priv->id;
1464
/* in order to avoid race conditions we must use the current
1465
* server configuration */
1467
XGrabServer (screen->dpy ());
1468
XSync (screen->dpy (), false);
1470
if (XGetWindowAttributes (screen->dpy (), priv->id, &attrib))
1474
xev.width = attrib.width;
1475
xev.height = attrib.height;
1476
xev.border_width = attrib.border_width;
1481
XWindowAttributes fAttrib;
1482
XWindowAttributes wAttrib;
1484
/* Add offset between wrapper and client */
1485
if (XGetWindowAttributes (screen->dpy (), priv->wrapper, &wAttrib))
1491
/* Add offset between frame and client */
1492
if (XGetWindowAttributes (screen->dpy (), priv->frame, &fAttrib))
1499
/* We need to ensure that the stacking order is
1500
* based on the current server stacking order so
1501
* find the sibling to this window's frame in the
1502
* server side stack and stack above that */
1503
XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
1507
for (unsigned int i = 0; i < nchildren; i++)
1509
if (i + 1 == nchildren ||
1510
children[i + 1] == ROOTPARENT (this))
1512
xev.above = children[i];
1522
xev.above = (serverPrev) ? ROOTPARENT (serverPrev) : None;
1523
xev.override_redirect = priv->attrib.override_redirect;
1525
XSendEvent (screen->dpy (), priv->id, false,
1526
StructureNotifyMask, (XEvent *) &xev);
1529
XUngrabServer (screen->dpy ());
1530
XSync (screen->dpy (), false);
1536
windowNotify (CompWindowNotifyBeforeMap);
1540
if (priv->pendingMaps > 0)
1541
priv->pendingMaps = 0;
1543
priv->mapNum = screen->priv->mapNum++;
1546
screen->updateWorkarea ();
1548
if (windowClass () == InputOnly)
1551
priv->unmapRefCnt = 1;
1553
priv->attrib.map_state = IsViewable;
1555
if (!overrideRedirect ())
1556
screen->priv->setWmState (NormalState, priv->id);
1558
priv->invisible = true;
1561
priv->lastPong = screen->priv->lastPing;
1563
priv->updateRegion ();
1564
priv->updateSize ();
1566
screen->priv->updateClientList ();
1568
if (priv->type & CompWindowTypeDesktopMask)
1569
screen->priv->desktopWindowCount++;
1571
if (priv->protocols & CompWindowProtocolSyncRequestMask)
1574
sendConfigureNotify ();
1577
if (!overrideRedirect ())
1582
priv->geometry.setHeight (priv->geometry.height () + 1);
1583
resize (priv->geometry.x (), priv->geometry.y (), priv->geometry.width (),
1584
priv->geometry.height () - 1, priv->geometry.border ());
1589
windowNotify (CompWindowNotifyMap);
1593
CompWindow::incrementUnmapReference ()
1595
priv->unmapRefCnt++;
1599
CompWindow::unmap ()
1601
windowNotify (CompWindowNotifyBeforeUnmap);
1606
/* Even though we're still keeping the backing
1607
* pixmap of the window around, it's safe to
1608
* unmap the frame window since there's no use
1609
* for it at this point anyways and it just blocks
1612
XUnmapWindow (screen->dpy (), priv->wrapper);
1613
XUnmapWindow (screen->dpy (), priv->serverFrame);
1615
priv->unmapRefCnt--;
1616
if (priv->unmapRefCnt > 0)
1619
if (priv->unmanaging)
1623
int gravity = priv->sizeHints.win_gravity;
1625
/* revert gravity adjustment made at MapNotify time */
1626
xwc.x = priv->serverGeometry.x ();
1627
xwc.y = priv->serverGeometry.y ();
1631
xwcm = priv->adjustConfigureRequestForGravity (&xwc,
1636
configureXWindow (xwcm, &xwc);
1638
priv->unmanaging = false;
1641
if (priv->serverFrame)
1642
priv->unreparent ();
1645
screen->updateWorkarea ();
1647
if (priv->attrib.map_state != IsViewable)
1650
if (priv->type == CompWindowTypeDesktopMask)
1651
screen->priv->desktopWindowCount--;
1653
priv->attrib.map_state = IsUnmapped;
1655
priv->invisible = true;
1657
if (priv->shaded && priv->height)
1658
resize (priv->attrib.x, priv->attrib.y,
1659
priv->attrib.width, ++priv->attrib.height - 1,
1660
priv->attrib.border_width);
1662
screen->priv->updateClientList ();
1664
windowNotify (CompWindowNotifyUnmap);
1668
PrivateWindow::withdraw ()
1670
if (!attrib.override_redirect)
1671
screen->priv->setWmState (WithdrawnState, id);
1674
unmanaging = managed;
1679
PrivateWindow::restack (Window aboveId)
1681
if (aboveId && (aboveId == id || aboveId == serverFrame))
1682
// Don't try to raise a window above itself
1684
else if (window->prev)
1686
if (aboveId && (aboveId == window->prev->id () ||
1687
aboveId == window->prev->priv->frame))
1690
else if (aboveId == None && !window->next)
1693
if (aboveId && !screen->findTopLevelWindow (aboveId, true))
1698
screen->unhookWindow (window);
1699
screen->insertWindow (window, aboveId);
1701
/* Update the server side window list for
1702
* override redirect windows immediately
1703
* since there is no opportunity to update
1704
* the server side list when we configure them
1705
* since we never get a ConfigureRequest for those */
1706
if (attrib.override_redirect != 0)
1708
StackDebugger *dbg = StackDebugger::Default ();
1710
screen->unhookServerWindow (window);
1711
screen->insertServerWindow (window, aboveId);
1714
dbg->overrideRedirectRestack (window->id (), aboveId);
1717
screen->priv->updateClientList ();
1719
window->windowNotify (CompWindowNotifyRestack);
1725
CompWindow::resize (XWindowAttributes attr)
1727
return resize (Geometry (attr.x, attr.y, attr.width, attr.height,
1728
attr.border_width));
1732
CompWindow::resize (int x,
1738
return resize (Geometry (x, y, width, height, border));
1742
CompWindow::resize (CompWindow::Geometry gm)
1744
/* Input extents are now the last thing sent
1745
* from the server. This might not work in some
1746
* cases though because setWindowFrameExtents may
1747
* be called more than once in an event processing
1748
* cycle so every set of input extents up until the
1749
* last one will be invalid. The real solution
1750
* here is to handle ConfigureNotify events on
1751
* frame windows and client windows separately */
1753
priv->input = priv->serverInput;
1755
if (priv->geometry.width () != gm.width () ||
1756
priv->geometry.height () != gm.height () ||
1757
priv->geometry.border () != gm.border ())
1760
int dx, dy, dwidth, dheight;
1762
pw = gm.width () + gm.border () * 2;
1763
ph = gm.height () + gm.border () * 2;
1768
dx = gm.x () - priv->geometry.x ();
1769
dy = gm.y () - priv->geometry.y ();
1770
dwidth = gm.width () - priv->geometry.width ();
1771
dheight = gm.height () - priv->geometry.height ();
1773
priv->geometry.set (gm.x (), gm.y (),
1774
gm.width (), gm.height (),
1781
priv->updateRegion ();
1783
resizeNotify (dx, dy, dwidth, dheight);
1785
priv->invisible = WINDOW_INVISIBLE (priv);
1787
else if (priv->geometry.x () != gm.x () || priv->geometry.y () != gm.y ())
1791
dx = gm.x () - priv->geometry.x ();
1792
dy = gm.y () - priv->geometry.y ();
1794
priv->geometry.setX (gm.x ());
1795
priv->geometry.setY (gm.y ());
1797
priv->region.translate (dx, dy);
1798
priv->inputRegion.translate (dx, dy);
1799
if (!priv->frameRegion.isEmpty ())
1800
priv->frameRegion.translate (dx, dy);
1802
priv->invisible = WINDOW_INVISIBLE (priv);
1804
moveNotify (dx, dy, true);
1807
updateFrameRegion ();
1813
syncValueIncrement (XSyncValue *value)
1818
XSyncIntToValue (&one, 1);
1819
XSyncValueAdd (value, *value, one, &overflow);
1823
PrivateWindow::initializeSyncCounter ()
1825
XSyncAlarmAttributes values;
1828
unsigned long n, left;
1829
unsigned char *data;
1832
return syncAlarm != None;
1834
if (!(protocols & CompWindowProtocolSyncRequestMask))
1837
result = XGetWindowProperty (screen->dpy (), id,
1838
Atoms::wmSyncRequestCounter,
1839
0L, 1L, false, XA_CARDINAL, &actual, &format,
1842
if (result == Success && n && data)
1844
unsigned long *counter = (unsigned long *) data;
1846
syncCounter = *counter;
1850
XSyncIntsToValue (&syncValue, (unsigned int) rand (), 0);
1851
XSyncSetCounter (screen->dpy (),
1855
syncValueIncrement (&syncValue);
1857
values.events = true;
1859
values.trigger.counter = syncCounter;
1860
values.trigger.wait_value = syncValue;
1862
values.trigger.value_type = XSyncAbsolute;
1863
values.trigger.test_type = XSyncPositiveComparison;
1865
XSyncIntToValue (&values.delta, 1);
1867
values.events = true;
1869
CompScreen::checkForError (screen->dpy ());
1871
/* Note that by default, the alarm increments the trigger value
1872
* when it fires until the condition (counter.value < trigger.value)
1875
syncAlarm = XSyncCreateAlarm (screen->dpy (),
1884
if (CompScreen::checkForError (screen->dpy ()))
1887
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
1890
else if (result == Success && data)
1899
CompWindow::sendSyncRequest ()
1901
XClientMessageEvent xev;
1906
if (!priv->initializeSyncCounter ())
1909
xev.type = ClientMessage;
1910
xev.window = priv->id;
1911
xev.message_type = Atoms::wmProtocols;
1913
xev.data.l[0] = Atoms::wmSyncRequest;
1914
xev.data.l[1] = CurrentTime;
1915
xev.data.l[2] = XSyncValueLow32 (priv->syncValue);
1916
xev.data.l[3] = XSyncValueHigh32 (priv->syncValue);
1919
syncValueIncrement (&priv->syncValue);
1921
XSendEvent (screen->dpy (), priv->id, false, 0, (XEvent *) &xev);
1923
priv->syncWait = true;
1924
priv->syncGeometry = priv->serverGeometry;
1926
if (!priv->syncWaitTimer.active ())
1927
priv->syncWaitTimer.start ();
1931
PrivateWindow::configure (XConfigureEvent *ce)
1933
unsigned int valueMask = 0;
1938
/* remove configure event from pending configures */
1939
if (priv->geometry.x () != ce->x)
1942
if (priv->geometry.y () != ce->y)
1945
if (priv->geometry.width () != ce->width)
1946
valueMask |= CWWidth;
1948
if (priv->geometry.height () != ce->height)
1949
valueMask |= CWHeight;
1951
if (priv->geometry.border () != ce->border_width)
1952
valueMask |= CWBorderWidth;
1954
if (ROOTPARENT (window->prev) != ce->above)
1955
valueMask |= CWSibling | CWStackMode;
1957
priv->attrib.override_redirect = ce->override_redirect;
1959
priv->frameGeometry.set (ce->x, ce->y, ce->width,
1960
ce->height, ce->border_width);
1963
priv->syncGeometry.set (ce->x, ce->y, ce->width, ce->height,
1967
if (ce->override_redirect)
1969
priv->serverGeometry.set (ce->x, ce->y, ce->width, ce->height,
1973
window->resize (ce->x, ce->y, ce->width, ce->height, ce->border_width);
1976
if (ce->event == screen->root ())
1977
priv->restack (ce->above);
1981
PrivateWindow::configureFrame (XConfigureEvent *ce)
1983
int x, y, width, height;
1985
unsigned int valueMask = 0;
1986
bool handled = false;
1991
/* remove configure event from pending configures */
1992
if (priv->frameGeometry.x () != ce->x)
1995
if (priv->frameGeometry.y () != ce->y)
1998
if (priv->frameGeometry.width () != ce->width)
1999
valueMask |= CWWidth;
2001
if (priv->frameGeometry.height () != ce->height)
2002
valueMask |= CWHeight;
2004
if (priv->frameGeometry.border () != ce->border_width)
2005
valueMask |= CWBorderWidth;
2007
if (ROOTPARENT (window->prev) != ce->above)
2008
valueMask |= CWSibling | CWStackMode;
2010
for (std::list <XWCValueMask>::iterator it = pendingConfigures.begin ();
2011
it != pendingConfigures.end (); it++)
2013
XWCValueMask &xwcvm = (*it);
2016
if (xwcvm.second != valueMask)
2018
/* For stacking cases, if a client wants to raise or lower a window
2019
* then they don't need to specify CWSibling, so allow that to be
2020
* excluded in those cases */
2022
if (ce->above == ROOTPARENT (screen->windows ().back ()) ||
2025
if ((xwcvm.second & ~(CWSibling)) != valueMask)
2032
if (xwcvm.second & CWX && xwcvm.first.x != ce->x)
2035
if (xwcvm.second & CWY && xwcvm.first.y != ce->y)
2038
if (xwcvm.second & CWWidth && xwcvm.first.width != ce->width)
2041
if (xwcvm.second & CWHeight && xwcvm.first.height != ce->height)
2044
if (xwcvm.second & (CWStackMode | CWSibling) && xwcvm.first.sibling != ce->above)
2047
/* Matched ConfigureWindow request to ConfigureNotify event
2048
* remove it from the list */
2052
pendingConfigures.erase (it);
2058
compLogMessage ("core", CompLogLevelWarn, "unhandled ConfigureNotify on 0x%x!", serverFrame);
2059
compLogMessage ("core", CompLogLevelWarn, "this should never happen. you should"\
2060
"probably file a bug about this.");
2064
pendingConfigures.clear ();
2068
/* subtract the input extents last sent to the
2069
* server to calculate the client size and then
2070
* re-sync the input extents and extents last
2071
* sent to server on resize () */
2073
x = ce->x + priv->serverInput.left;
2074
y = ce->y + priv->serverInput.top;
2075
width = ce->width - priv->serverGeometry.border () * 2 - priv->serverInput.left - priv->serverInput.right;
2076
height = ce->height - priv->serverGeometry.border () * 2 - priv->serverInput.top - priv->serverInput.bottom;
2078
/* set the frame geometry */
2079
priv->frameGeometry.set (ce->x, ce->y, ce->width, ce->height, ce->border_width);
2083
priv->syncGeometry.set (x, y, width, height, ce->border_width);
2085
window->resize (x, y, width, height, ce->border_width);
2087
if (priv->restack (ce->above))
2088
priv->updatePassiveButtonGrabs ();
2090
above = screen->findWindow (ce->above);
2093
above->priv->updatePassiveButtonGrabs ();
2095
if (pendingConfigures.empty ())
2097
/* Tell plugins its ok to start doing stupid things again but
2098
* obviously FIXME */
2099
CompOption::Vector options;
2100
CompOption::Value v;
2102
options.push_back (CompOption ("window", CompOption::TypeInt));
2104
options.back ().set (v);
2105
options.push_back (CompOption ("active", CompOption::TypeInt));
2107
options.back ().set (v);
2109
/* Notify other plugins that it is unsafe to change geometry or serverGeometry
2110
* FIXME: That API should not be accessible to plugins, this is a hack to avoid
2113
screen->handleCompizEvent ("core", "lock_position", options);
2118
PrivateWindow::circulate (XCirculateEvent *ce)
2122
if (ce->place == PlaceOnTop)
2123
newAboveId = screen->priv->getTopWindow ();
2127
priv->restack (newAboveId);
2131
CompWindow::move (int dx,
2137
/* Don't allow window movement to overwrite working geometries
2138
* last received from the server if we know there are pending
2139
* ConfigureNotify events on this window. That's a clunky workaround
2140
* and a FIXME in any case, however, until we can break the API
2141
* and remove CompWindow::move, this will need to be the case */
2143
if (!priv->pendingConfigures.size ())
2145
priv->geometry.setX (priv->geometry.x () + dx);
2146
priv->geometry.setY (priv->geometry.y () + dy);
2147
priv->frameGeometry.setX (priv->frameGeometry.x () + dx);
2148
priv->frameGeometry.setY (priv->frameGeometry.y () + dy);
2150
priv->pendingPositionUpdates = true;
2152
priv->region.translate (dx, dy);
2153
priv->inputRegion.translate (dx, dy);
2154
if (!priv->frameRegion.isEmpty ())
2155
priv->frameRegion.translate (dx, dy);
2157
priv->invisible = WINDOW_INVISIBLE (priv);
2159
moveNotify (dx, dy, immediate);
2164
unsigned int valueMask = CWX | CWY;
2165
struct timeval tv, old;
2166
compLogMessage ("core", CompLogLevelDebug, "pending configure notifies on 0x%x,"\
2167
"moving window asyncrhonously!", (unsigned int) priv->serverId);
2169
old = priv->lastConfigureRequest;
2170
gettimeofday (&tv, NULL);
2172
xwc.x = priv->serverGeometry.x () + dx;
2173
xwc.y = priv->serverGeometry.y () + dy;
2175
configureXWindow (valueMask, &xwc);
2177
priv->lastConfigureRequest = old;
2179
/* FIXME: This is a hack to avoid performance regressions
2180
* and must be removed in 0.9.6 */
2181
if (tv.tv_usec - priv->lastConfigureRequest.tv_usec > 300000)
2183
compLogMessage ("core", CompLogLevelWarn, "failed to receive ConfigureNotify event from request at %i (now: %i)\n",
2184
priv->lastConfigureRequest.tv_usec, tv.tv_usec);
2185
priv->pendingConfigures.clear ();
2192
PrivateWindow::addPendingConfigure (XWindowChanges &xwc, unsigned int valueMask)
2194
CompOption::Vector options;
2195
CompOption::Value v;
2197
options.push_back (CompOption ("window", CompOption::TypeInt));
2199
options.back ().set (v);
2200
options.push_back (CompOption ("active", CompOption::TypeInt));
2202
options.back ().set (v);
2204
gettimeofday (&lastConfigureRequest, NULL);
2206
/* Notify other plugins that it is unsafe to change geometry or serverGeometry
2207
* FIXME: That API should not be accessible to plugins, this is a hack to avoid
2210
screen->handleCompizEvent ("core", "lock_position", options);
2212
priv->pendingConfigures.push_back (XWCValueMask (xwc, valueMask));
2216
CompWindow::syncPosition ()
2218
unsigned int valueMask = CWX | CWY;
2221
if (priv->pendingPositionUpdates && priv->pendingConfigures.empty ())
2223
if (priv->serverFrameGeometry.x () == priv->frameGeometry.x ())
2224
valueMask &= ~(CWX);
2225
if (priv->serverFrameGeometry.y () == priv->frameGeometry.y ())
2226
valueMask &= ~(CWY);
2228
/* Because CompWindow::move can update the geometry last
2229
* received from the server, we must indicate that no values
2230
* changed, because when the ConfigureNotify comes around
2231
* the values are going to be the same. That's obviously
2232
* broken behaviour and worthy of a FIXME, but requires
2233
* larger changes to the window movement system. */
2236
priv->addPendingConfigure (xwc, 0);
2238
priv->serverGeometry.setX (priv->geometry.x ());
2239
priv->serverGeometry.setY (priv->geometry.y ());
2240
priv->serverFrameGeometry.setX (priv->frameGeometry.x ());
2241
priv->serverFrameGeometry.setY (priv->frameGeometry.y ());
2243
xwc.x = priv->serverFrameGeometry.x ();
2244
xwc.y = priv->serverFrameGeometry.y ();
2246
XConfigureWindow (screen->dpy (), ROOTPARENT (this), valueMask, &xwc);
2248
if (priv->serverFrame)
2250
XMoveWindow (screen->dpy (), priv->wrapper,
2251
priv->serverInput.left, priv->serverInput.top);
2252
sendConfigureNotify ();
2255
priv->pendingPositionUpdates = false;
2260
CompWindow::focus ()
2262
WRAPABLE_HND_FUNC_RETURN (2, bool, focus)
2264
if (overrideRedirect ())
2267
if (!priv->managed || priv->unmanaging)
2270
if (!onCurrentDesktop ())
2273
if (priv->destroyed)
2276
if (!priv->shaded && (priv->state & CompWindowStateHiddenMask))
2279
if (priv->geometry.x () + priv->width <= 0 ||
2280
priv->geometry.y () + priv->height <= 0 ||
2281
priv->geometry.x () >= (int) screen->width ()||
2282
priv->geometry.y () >= (int) screen->height ())
2289
CompWindow::place (CompPoint &pos)
2291
WRAPABLE_HND_FUNC_RETURN (4, bool, place, pos)
2296
CompWindow::validateResizeRequest (unsigned int &mask,
2297
XWindowChanges *xwc,
2298
unsigned int source)
2300
WRAPABLE_HND_FUNC (5, validateResizeRequest, mask, xwc, source)
2302
if (!(priv->type & (CompWindowTypeDockMask |
2303
CompWindowTypeFullscreenMask |
2304
CompWindowTypeUnknownMask)))
2310
min = screen->workArea ().y () + priv->input.top;
2311
max = screen->workArea ().bottom ();
2313
if (priv->state & CompWindowStateStickyMask &&
2314
(xwc->y < min || xwc->y > max))
2316
xwc->y = priv->serverGeometry.y ();
2320
min -= screen->vp ().y () * screen->height ();
2321
max += (screen->vpSize ().height () - screen->vp ().y () - 1) *
2326
else if (xwc->y > max)
2335
min = screen->workArea ().x () + priv->input.left;
2336
max = screen->workArea ().right ();
2338
if (priv->state & CompWindowStateStickyMask &&
2339
(xwc->x < min || xwc->x > max))
2341
xwc->x = priv->serverGeometry.x ();
2345
min -= screen->vp ().x () * screen->width ();
2346
max += (screen->vpSize ().width () - screen->vp ().x () - 1) *
2351
else if (xwc->x > max)
2359
CompWindow::resizeNotify (int dx,
2363
WRAPABLE_HND_FUNC (6, resizeNotify, dx, dy, dwidth, dheight)
2366
CompWindow::moveNotify (int dx,
2369
WRAPABLE_HND_FUNC (7, moveNotify, dx, dy, immediate)
2372
CompWindow::windowNotify (CompWindowNotify n)
2373
WRAPABLE_HND_FUNC (8, windowNotify, n)
2376
CompWindow::grabNotify (int x,
2381
WRAPABLE_HND_FUNC (9, grabNotify, x, y, state, mask)
2382
priv->grabbed = true;
2386
CompWindow::ungrabNotify ()
2388
WRAPABLE_HND_FUNC (10, ungrabNotify)
2389
priv->grabbed = false;
2393
CompWindow::stateChangeNotify (unsigned int lastState)
2395
WRAPABLE_HND_FUNC (11, stateChangeNotify, lastState);
2397
/* if being made sticky */
2398
if (!(lastState & CompWindowStateStickyMask) &&
2399
(priv->state & CompWindowStateStickyMask))
2401
CompPoint vp; /* index of the window's vp */
2403
/* Find which viewport the window falls in,
2404
and check if it's the current viewport */
2405
vp = defaultViewport ();
2406
if (screen->vp () != vp)
2408
unsigned int valueMask = CWX | CWY;
2411
xwc.x = serverGeometry ().x () + (screen->vp ().x () - vp.x ()) * screen->width ();
2412
xwc.y = serverGeometry ().y () + (screen->vp ().y () - vp.y ()) * screen->height ();
2414
configureXWindow (valueMask, &xwc);
2421
PrivateWindow::isGroupTransient (Window clientLeader)
2426
if (transientFor == None || transientFor == screen->root ())
2428
if (type & (CompWindowTypeUtilMask |
2429
CompWindowTypeToolbarMask |
2430
CompWindowTypeMenuMask |
2431
CompWindowTypeDialogMask |
2432
CompWindowTypeModalDialogMask))
2434
if (this->clientLeader == clientLeader)
2443
PrivateWindow::getModalTransient ()
2445
CompWindow *w, *modalTransient;
2447
modalTransient = window;
2449
for (w = screen->windows ().back (); w; w = w->prev)
2451
if (w == modalTransient || w->priv->mapNum == 0)
2454
if (w->priv->transientFor == modalTransient->priv->id)
2456
if (w->priv->state & CompWindowStateModalMask)
2459
w = screen->windows ().back ();
2464
if (modalTransient == window)
2466
/* don't look for group transients with modal state if current window
2468
if (state & CompWindowStateModalMask)
2471
for (w = screen->windows ().back (); w; w = w->prev)
2473
if (w == modalTransient || w->priv->mapNum == 0)
2476
if (isAncestorTo (modalTransient, w))
2479
if (w->priv->isGroupTransient (modalTransient->priv->clientLeader))
2481
if (w->priv->state & CompWindowStateModalMask)
2484
w = w->priv->getModalTransient ();
2494
if (modalTransient == window)
2495
modalTransient = NULL;
2497
return modalTransient;
2501
CompWindow::moveInputFocusTo ()
2503
CompScreen *s = screen;
2504
CompWindow *modalTransient;
2506
modalTransient = priv->getModalTransient ();
2508
return modalTransient->moveInputFocusTo ();
2510
if (priv->state & CompWindowStateHiddenMask)
2512
XSetInputFocus (s->dpy (), priv->serverFrame,
2513
RevertToPointerRoot, CurrentTime);
2514
XChangeProperty (s->dpy (), s->root (), Atoms::winActive,
2515
XA_WINDOW, 32, PropModeReplace,
2516
(unsigned char *) &priv->id, 1);
2520
bool setFocus = false;
2522
if (priv->inputHint)
2524
XSetInputFocus (s->dpy (), priv->id, RevertToPointerRoot,
2529
if (priv->protocols & CompWindowProtocolTakeFocusMask)
2533
ev.type = ClientMessage;
2534
ev.xclient.window = priv->id;
2535
ev.xclient.message_type = Atoms::wmProtocols;
2536
ev.xclient.format = 32;
2537
ev.xclient.data.l[0] = Atoms::wmTakeFocus;
2538
ev.xclient.data.l[1] = s->getCurrentTime ();
2539
ev.xclient.data.l[2] = 0;
2540
ev.xclient.data.l[3] = 0;
2541
ev.xclient.data.l[4] = 0;
2543
XSendEvent (s->dpy (), priv->id, false, NoEventMask, &ev);
2550
CompWindowList dockWindows;
2554
screen->priv->nextActiveWindow = priv->id;
2556
/* Ensure that docks are stacked in the right place
2558
* When a normal window gets the focus and is above a
2559
* fullscreen window, restack the docks to be above
2560
* the highest level mapped and visible normal window,
2561
* otherwise put them above the highest fullscreen window
2563
if (PrivateWindow::stackDocks (this, dockWindows, &xwc, &mask))
2565
Window sibling = xwc.sibling;
2566
xwc.stack_mode = Above;
2568
/* Then update the dock windows */
2569
foreach (CompWindow *dw, dockWindows)
2571
xwc.sibling = sibling;
2572
dw->configureXWindow (mask, &xwc);
2577
if (!setFocus && !modalTransient)
2579
CompWindow *ancestor;
2581
/* move input to closest ancestor */
2582
for (ancestor = s->windows ().front (); ancestor;
2583
ancestor = ancestor->next)
2585
if (PrivateWindow::isAncestorTo (this, ancestor))
2587
ancestor->moveInputFocusTo ();
2596
CompWindow::moveInputFocusToOtherWindow ()
2598
if (priv->id == screen->activeWindow () ||
2599
priv->id == screen->priv->nextActiveWindow)
2601
CompWindow *ancestor;
2603
if (priv->transientFor && priv->transientFor != screen->root ())
2605
ancestor = screen->findWindow (priv->transientFor);
2607
ancestor->focus () &&
2608
!(ancestor->priv->type & (CompWindowTypeDesktopMask |
2609
CompWindowTypeDockMask)))
2611
ancestor->moveInputFocusTo ();
2614
screen->focusDefaultWindow ();
2616
else if (priv->type & (CompWindowTypeDialogMask |
2617
CompWindowTypeModalDialogMask))
2619
CompWindow *a, *focus = NULL;
2621
for (a = screen->windows ().back (); a; a = a->prev)
2623
if (a->priv->clientLeader == priv->clientLeader)
2629
if (a->priv->type & (CompWindowTypeNormalMask |
2630
CompWindowTypeDialogMask |
2631
CompWindowTypeModalDialogMask))
2633
if (priv->compareWindowActiveness (focus, a) < 0)
2643
if (focus && !(focus->priv->type & (CompWindowTypeDesktopMask |
2644
CompWindowTypeDockMask)))
2646
focus->moveInputFocusTo ();
2649
screen->focusDefaultWindow ();
2652
screen->focusDefaultWindow ();
2658
PrivateWindow::stackLayerCheck (CompWindow *w,
2659
Window clientLeader,
2662
if (isAncestorTo (w, below))
2665
if (isAncestorTo (below, w))
2668
if (clientLeader && below->priv->clientLeader == clientLeader)
2669
if (below->priv->isGroupTransient (clientLeader))
2672
if (w->priv->state & CompWindowStateAboveMask)
2676
else if (w->priv->state & CompWindowStateBelowMask)
2678
if (below->priv->state & CompWindowStateBelowMask)
2681
else if (!(below->priv->state & CompWindowStateAboveMask))
2690
PrivateWindow::avoidStackingRelativeTo (CompWindow *w)
2692
if (w->overrideRedirect ())
2695
if (w->destroyed ())
2698
if (!w->priv->shaded && !w->priv->pendingMaps)
2700
if (!w->isViewable () || !w->isMapped ())
2707
/* goes through the stack, top-down until we find a window we should
2708
stack above, normal windows can be stacked above fullscreen windows
2709
(and fullscreen windows over others in their layer) if aboveFs is true. */
2711
PrivateWindow::findSiblingBelow (CompWindow *w,
2715
CompWindow *t = screen->findWindow (w->transientFor ());
2716
Window clientLeader = w->priv->clientLeader;
2717
unsigned int type = w->priv->type;
2718
unsigned int belowMask;
2721
belowMask = CompWindowTypeDockMask;
2723
belowMask = CompWindowTypeDockMask | CompWindowTypeFullscreenMask;
2725
/* normal stacking of fullscreen windows with below state */
2726
if ((type & CompWindowTypeFullscreenMask) &&
2727
(w->priv->state & CompWindowStateBelowMask))
2728
type = CompWindowTypeNormalMask;
2730
while (t && type != CompWindowTypeDockMask)
2732
/* dock stacking of transients for docks */
2733
if (t->type () & CompWindowTypeDockMask)
2734
type = CompWindowTypeDockMask;
2736
t = screen->findWindow (t->transientFor ());
2739
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2740
clientLeader = None;
2742
for (below = screen->serverWindows ().back (); below;
2743
below = below->serverPrev)
2745
if (below == w || avoidStackingRelativeTo (below))
2748
/* always above desktop windows */
2749
if (below->priv->type & CompWindowTypeDesktopMask)
2753
case CompWindowTypeDesktopMask:
2754
/* desktop window layer */
2756
case CompWindowTypeFullscreenMask:
2759
/* otherwise fall-through */
2760
case CompWindowTypeDockMask:
2761
/* fullscreen and dock layer */
2762
if (below->priv->type & (CompWindowTypeFullscreenMask |
2763
CompWindowTypeDockMask))
2765
if (stackLayerCheck (w, clientLeader, below))
2775
bool allowedRelativeToLayer = !(below->priv->type & belowMask);
2777
t = screen->findWindow (below->transientFor ());
2779
while (t && allowedRelativeToLayer)
2781
/* dock stacking of transients for docks */
2782
allowedRelativeToLayer = !(t->priv->type & belowMask);
2784
t = screen->findWindow (t->transientFor ());
2787
/* fullscreen and normal layer */
2788
if (allowedRelativeToLayer)
2790
if (stackLayerCheck (w, clientLeader, below))
2801
/* goes through the stack, top-down and returns the lowest window we
2804
PrivateWindow::findLowestSiblingBelow (CompWindow *w)
2806
CompWindow *below, *lowest = screen->serverWindows ().back ();
2807
CompWindow *t = screen->findWindow (w->transientFor ());
2808
Window clientLeader = w->priv->clientLeader;
2809
unsigned int type = w->priv->type;
2811
/* normal stacking fullscreen windows with below state */
2812
if ((type & CompWindowTypeFullscreenMask) &&
2813
(w->priv->state & CompWindowStateBelowMask))
2814
type = CompWindowTypeNormalMask;
2816
while (t && type != CompWindowTypeDockMask)
2818
/* dock stacking of transients for docks */
2819
if (t->type () & CompWindowTypeDockMask)
2820
type = CompWindowTypeDockMask;
2822
t = screen->findWindow (t->transientFor ());
2826
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2827
clientLeader = None;
2829
for (below = screen->serverWindows ().back (); below;
2830
below = below->serverPrev)
2832
if (below == w || avoidStackingRelativeTo (below))
2835
/* always above desktop windows */
2836
if (below->priv->type & CompWindowTypeDesktopMask)
2840
case CompWindowTypeDesktopMask:
2841
/* desktop window layer - desktop windows always should be
2842
stacked at the bottom; no other window should be below them */
2845
case CompWindowTypeFullscreenMask:
2846
case CompWindowTypeDockMask:
2847
/* fullscreen and dock layer */
2848
if (below->priv->type & (CompWindowTypeFullscreenMask |
2849
CompWindowTypeDockMask))
2851
if (!stackLayerCheck (below, clientLeader, w))
2861
bool allowedRelativeToLayer = !(below->priv->type & CompWindowTypeDockMask);
2863
t = screen->findWindow (below->transientFor ());
2865
while (t && allowedRelativeToLayer)
2867
/* dock stacking of transients for docks */
2868
allowedRelativeToLayer = !(t->priv->type & CompWindowTypeDockMask);
2870
t = screen->findWindow (t->transientFor ());
2873
/* fullscreen and normal layer */
2874
if (allowedRelativeToLayer)
2876
if (!stackLayerCheck (below, clientLeader, w))
2890
PrivateWindow::validSiblingBelow (CompWindow *w,
2891
CompWindow *sibling)
2893
CompWindow *t = screen->findWindow (w->transientFor ());
2894
Window clientLeader = w->priv->clientLeader;
2895
unsigned int type = w->priv->type;
2897
/* normal stacking fullscreen windows with below state */
2898
if ((type & CompWindowTypeFullscreenMask) &&
2899
(w->priv->state & CompWindowStateBelowMask))
2900
type = CompWindowTypeNormalMask;
2902
while (t && type != CompWindowTypeDockMask)
2904
/* dock stacking of transients for docks */
2905
if (t->type () & CompWindowTypeDockMask)
2906
type = CompWindowTypeDockMask;
2908
t = screen->findWindow (t->transientFor ());
2912
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2913
clientLeader = None;
2915
if (sibling == w || avoidStackingRelativeTo (sibling))
2918
/* always above desktop windows */
2919
if (sibling->priv->type & CompWindowTypeDesktopMask)
2923
case CompWindowTypeDesktopMask:
2924
/* desktop window layer */
2926
case CompWindowTypeFullscreenMask:
2927
case CompWindowTypeDockMask:
2928
/* fullscreen and dock layer */
2929
if (sibling->priv->type & (CompWindowTypeFullscreenMask |
2930
CompWindowTypeDockMask))
2932
if (stackLayerCheck (w, clientLeader, sibling))
2942
bool allowedRelativeToLayer = !(sibling->priv->type & CompWindowTypeDockMask);
2944
t = screen->findWindow (sibling->transientFor ());
2946
while (t && allowedRelativeToLayer)
2948
/* dock stacking of transients for docks */
2949
allowedRelativeToLayer = !(t->priv->type & CompWindowTypeDockMask);
2951
t = screen->findWindow (t->transientFor ());
2954
/* fullscreen and normal layer */
2955
if (allowedRelativeToLayer)
2957
if (stackLayerCheck (w, clientLeader, sibling))
2968
PrivateWindow::saveGeometry (int mask)
2970
int m = mask & ~saveMask;
2972
/* only save geometry if window has been placed */
2977
saveWc.x = serverGeometry.x ();
2980
saveWc.y = serverGeometry.y ();
2983
saveWc.width = serverGeometry.width ();
2986
saveWc.height = serverGeometry.height ();
2988
if (m & CWBorderWidth)
2989
saveWc.border_width = serverGeometry.border ();
2995
PrivateWindow::restoreGeometry (XWindowChanges *xwc,
2998
int m = mask & saveMask;
3008
xwc->width = saveWc.width;
3010
/* This is not perfect but it works OK for now. If the saved width is
3011
the same as the current width then make it a little be smaller so
3012
the user can see that it changed and it also makes sure that
3013
windowResizeNotify is called and plugins are notified. */
3014
if (xwc->width == (int) serverGeometry.width ())
3024
xwc->height = saveWc.height;
3026
/* As above, if the saved height is the same as the current height
3027
then make it a little be smaller. */
3028
if (xwc->height == (int) serverGeometry.height ())
3036
if (m & CWBorderWidth)
3037
xwc->border_width = saveWc.border_width;
3045
PrivateWindow::reconfigureXWindow (unsigned int valueMask,
3046
XWindowChanges *xwc)
3048
unsigned int frameValueMask = valueMask;
3050
/* Immediately sync window position
3051
* if plugins were updating w->geometry () directly
3052
* in order to avoid a race condition */
3054
window->syncPosition ();
3056
/* Remove redundant bits */
3058
if (serverGeometry.x () == xwc->x)
3059
valueMask &= ~(CWX);
3061
if (serverGeometry.y () == xwc->y)
3062
valueMask &= ~(CWY);
3064
if (serverGeometry.width () == xwc->width)
3065
valueMask &= ~(CWWidth);
3067
if (serverGeometry.height () == xwc->height)
3068
valueMask &= ~(CWHeight);
3070
if (serverGeometry.border () == xwc->border_width)
3071
valueMask &= ~(CWBorderWidth);
3073
if (window->serverPrev && ROOTPARENT (window->serverPrev) == xwc->sibling)
3075
/* check if the sibling is also pending a restack,
3076
* if not, then setting this bit is useless */
3078
bool pendingRestack = false;
3080
foreach (XWCValueMask &xwcvm, window->serverPrev->priv->pendingConfigures)
3082
if (xwcvm.second & (CWSibling | CWStackMode))
3084
pendingRestack = true;
3089
if (!pendingRestack)
3090
valueMask &= ~(CWSibling | CWStackMode);
3093
if (valueMask & CWBorderWidth)
3094
serverGeometry.setBorder (xwc->border_width);
3096
if (valueMask & CWX)
3097
serverGeometry.setX (xwc->x);
3099
if (valueMask & CWY)
3100
serverGeometry.setY (xwc->y);
3102
if (valueMask & CWWidth)
3103
serverGeometry.setWidth (xwc->width);
3105
if (valueMask & CWHeight)
3106
serverGeometry.setHeight (xwc->height);
3108
/* Update the server side window list on raise, lower and restack functions.
3109
* This function should only recieve stack_mode == Above
3110
* but warn incase something else does get through, to make the cause
3111
* of any potential misbehaviour obvious. */
3112
if (valueMask & (CWSibling | CWStackMode))
3114
if (xwc->stack_mode == Above)
3118
screen->unhookServerWindow (window);
3119
screen->insertServerWindow (window, xwc->sibling);
3123
compLogMessage ("core", CompLogLevelWarn, "restack_mode not Above");
3126
if (serverFrameGeometry.x () == xwc->x - serverGeometry.border () - serverInput.left)
3127
frameValueMask &= ~(CWX);
3129
if (serverFrameGeometry.y () == xwc->y - serverGeometry.border () - serverInput.top)
3130
frameValueMask &= ~(CWY);
3132
if (serverFrameGeometry.width () == xwc->width + serverGeometry.border () * 2
3133
+ serverInput.left + serverInput.right)
3134
frameValueMask &= ~(CWWidth);
3136
if (serverFrameGeometry.height () == xwc->height + serverGeometry.border () * 2
3137
+ serverInput.top + serverInput.bottom)
3138
frameValueMask &= ~(CWHeight);
3140
/* Can't set the border width of frame windows */
3141
frameValueMask &= ~(CWBorderWidth);
3143
if (frameValueMask & CWX)
3144
serverFrameGeometry.setX (xwc->x - serverGeometry.border () - serverInput.left);
3146
if (frameValueMask & CWY)
3147
serverFrameGeometry.setY (xwc->y -serverGeometry.border () - serverInput.top);
3149
if (frameValueMask & CWWidth)
3150
serverFrameGeometry.setWidth (xwc->width + serverGeometry.border () * 2
3151
+ serverInput.left + serverInput.right);
3153
if (frameValueMask & CWHeight)
3154
serverFrameGeometry.setHeight (xwc->height + serverGeometry.border () * 2
3155
+ serverInput.top + serverInput.bottom);
3162
XWindowChanges wc = *xwc;
3164
wc.x = serverFrameGeometry.x ();
3165
wc.y = serverFrameGeometry.y ();
3166
wc.width = serverFrameGeometry.width ();
3167
wc.height = serverFrameGeometry.height ();
3169
addPendingConfigure (wc, frameValueMask);
3171
XConfigureWindow (screen->dpy (), serverFrame, frameValueMask, &wc);
3173
valueMask &= ~(CWSibling | CWStackMode);
3177
xwc->x = serverInput.left;
3178
xwc->y = serverInput.top;
3179
XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc);
3185
window->sendConfigureNotify ();
3189
XConfigureWindow (screen->dpy (), id, valueMask, xwc);
3193
PrivateWindow::stackDocks (CompWindow *w,
3194
CompWindowList &updateList,
3195
XWindowChanges *xwc,
3198
CompWindow *firstFullscreenWindow = NULL;
3199
CompWindow *belowDocks = NULL;
3201
foreach (CompWindow *dw, screen->serverWindows ())
3203
/* fullscreen window found */
3204
if (firstFullscreenWindow)
3206
/* If there is another toplevel window above the fullscreen one
3207
* then we need to stack above that */
3209
!PrivateWindow::isAncestorTo (w, dw) &&
3210
!(dw->type () & (CompWindowTypeFullscreenMask |
3211
CompWindowTypeDockMask)) &&
3212
!dw->overrideRedirect () &&
3213
dw->defaultViewport () == screen->vp () &&
3219
else if (dw->type () & CompWindowTypeFullscreenMask)
3221
/* First fullscreen window found when checking up the stack
3222
* now go back down to find a suitable candidate client
3223
* window to put the docks above */
3224
firstFullscreenWindow = dw;
3225
for (CompWindow *dww = dw->serverPrev; dww; dww = dww->serverPrev)
3227
if (!(dww->type () & (CompWindowTypeFullscreenMask |
3228
CompWindowTypeDockMask)) &&
3229
!dww->overrideRedirect () &&
3230
dww->defaultViewport () == screen->vp () &&
3242
*mask = CWSibling | CWStackMode;
3243
xwc->sibling = ROOTPARENT (belowDocks);
3245
/* Collect all dock windows first */
3246
foreach (CompWindow *dw, screen->serverWindows ())
3247
if (dw->priv->type & CompWindowTypeDockMask)
3248
updateList.push_front (dw);
3257
PrivateWindow::stackTransients (CompWindow *w,
3259
XWindowChanges *xwc,
3260
CompWindowList &updateList)
3263
Window clientLeader = w->priv->clientLeader;
3265
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
3266
clientLeader = None;
3268
for (t = screen->serverWindows ().back (); t; t = t->serverPrev)
3270
if (t == w || t == avoid)
3273
if (t->priv->transientFor == w->priv->id ||
3274
t->priv->isGroupTransient (clientLeader))
3276
if (!stackTransients (t, avoid, xwc, updateList))
3279
if (xwc->sibling == t->priv->id ||
3280
(t->priv->serverFrame && xwc->sibling == t->priv->serverFrame))
3283
if (t->priv->mapNum || t->priv->pendingMaps)
3284
updateList.push_back (t);
3292
PrivateWindow::stackAncestors (CompWindow *w,
3293
XWindowChanges *xwc,
3294
CompWindowList &updateList)
3296
CompWindow *transient = NULL;
3298
if (w->priv->transientFor)
3299
transient = screen->findWindow (w->priv->transientFor);
3302
xwc->sibling != transient->priv->id &&
3303
(!transient->priv->serverFrame || xwc->sibling != transient->priv->serverFrame))
3305
CompWindow *ancestor;
3307
ancestor = screen->findWindow (w->priv->transientFor);
3310
if (!stackTransients (ancestor, w, xwc, updateList))
3313
if (ancestor->priv->type & CompWindowTypeDesktopMask)
3316
if (ancestor->priv->type & CompWindowTypeDockMask)
3317
if (!(w->priv->type & CompWindowTypeDockMask))
3320
if (ancestor->priv->mapNum || ancestor->priv->pendingMaps)
3321
updateList.push_back (ancestor);
3323
stackAncestors (ancestor, xwc, updateList);
3326
else if (w->priv->isGroupTransient (w->priv->clientLeader))
3330
for (a = screen->serverWindows ().back (); a; a = a->serverPrev)
3332
if (a->priv->clientLeader == w->priv->clientLeader &&
3333
a->priv->transientFor == None &&
3334
!a->priv->isGroupTransient (w->priv->clientLeader))
3336
if (xwc->sibling == a->priv->id ||
3337
(a->priv->serverFrame && xwc->sibling == a->priv->serverFrame))
3340
if (!stackTransients (a, w, xwc, updateList))
3343
if (a->priv->type & CompWindowTypeDesktopMask)
3346
if (a->priv->type & CompWindowTypeDockMask)
3347
if (!(w->priv->type & CompWindowTypeDockMask))
3350
if (a->priv->mapNum || a->priv->pendingMaps)
3351
updateList.push_back (a);
3358
CompWindow::configureXWindow (unsigned int valueMask,
3359
XWindowChanges *xwc)
3361
if (priv->managed && (valueMask & (CWSibling | CWStackMode)))
3363
CompWindowList transients;
3364
CompWindowList ancestors;
3365
CompWindowList docks;
3367
/* Since the window list is being reordered in reconfigureXWindow
3368
the list of windows which need to be restacked must be stored
3369
first. The windows are stacked in the opposite order than they
3370
were previously stacked, in order that they are above xwc->sibling
3371
so that when compiz gets the ConfigureNotify event it doesn't
3372
have to restack all the windows again. */
3374
/* transient children above */
3375
if (PrivateWindow::stackTransients (this, NULL, xwc, transients))
3377
/* ancestors, siblings and sibling transients below */
3378
PrivateWindow::stackAncestors (this, xwc, ancestors);
3380
for (CompWindowList::reverse_iterator w = ancestors.rbegin ();
3381
w != ancestors.rend (); w++)
3383
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
3384
xwc->sibling = ROOTPARENT (*w);
3387
this->priv->reconfigureXWindow (valueMask, xwc);
3388
xwc->sibling = ROOTPARENT (this);
3390
for (CompWindowList::reverse_iterator w = transients.rbegin ();
3391
w != transients.rend (); w++)
3393
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
3394
xwc->sibling = ROOTPARENT (*w);
3397
if (PrivateWindow::stackDocks (this, docks, xwc, &valueMask))
3399
Window sibling = xwc->sibling;
3400
xwc->stack_mode = Above;
3402
/* Then update the dock windows */
3403
foreach (CompWindow *dw, docks)
3405
xwc->sibling = sibling;
3406
dw->priv->reconfigureXWindow (valueMask, xwc);
3413
priv->reconfigureXWindow (valueMask, xwc);
3418
PrivateWindow::addWindowSizeChanges (XWindowChanges *xwc,
3419
CompWindow::Geometry old)
3427
screen->viewportForGeometry (old, viewport);
3429
x = (viewport.x () - screen->vp ().x ()) * screen->width ();
3430
y = (viewport.y () - screen->vp ().y ()) * screen->height ();
3432
output = screen->outputDeviceForGeometry (old);
3433
workArea = screen->getWorkareaForOutput (output);
3435
if (type & CompWindowTypeFullscreenMask)
3437
saveGeometry (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3439
if (fullscreenMonitorsSet)
3441
xwc->x = x + fullscreenMonitorRect.x ();
3442
xwc->y = y + fullscreenMonitorRect.y ();
3443
xwc->width = fullscreenMonitorRect.width ();
3444
xwc->height = fullscreenMonitorRect.height ();
3448
xwc->x = x + screen->outputDevs ()[output].x ();
3449
xwc->y = y + screen->outputDevs ()[output].y ();
3450
xwc->width = screen->outputDevs ()[output].width ();
3451
xwc->height = screen->outputDevs ()[output].height ();
3454
xwc->border_width = 0;
3456
mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
3460
mask |= restoreGeometry (xwc, CWBorderWidth);
3462
if (state & CompWindowStateMaximizedVertMask)
3464
saveGeometry (CWY | CWHeight);
3466
xwc->height = workArea.height () - serverInput.top -
3467
serverInput.bottom - old.border () * 2;
3473
mask |= restoreGeometry (xwc, CWY | CWHeight);
3476
if (state & CompWindowStateMaximizedHorzMask)
3478
saveGeometry (CWX | CWWidth);
3480
xwc->width = workArea.width () - serverInput.left -
3481
serverInput.right - old.border () * 2;
3487
mask |= restoreGeometry (xwc, CWX | CWWidth);
3490
/* constrain window width if smaller than minimum width */
3491
if (!(mask & CWWidth) && (int) old.width () < sizeHints.min_width)
3493
xwc->width = sizeHints.min_width;
3497
/* constrain window width if greater than maximum width */
3498
if (!(mask & CWWidth) && (int) old.width () > sizeHints.max_width)
3500
xwc->width = sizeHints.max_width;
3504
/* constrain window height if smaller than minimum height */
3505
if (!(mask & CWHeight) && (int) old.height () < sizeHints.min_height)
3507
xwc->height = sizeHints.min_height;
3511
/* constrain window height if greater than maximum height */
3512
if (!(mask & CWHeight) && (int) old.height () > sizeHints.max_height)
3514
xwc->height = sizeHints.max_height;
3518
if (mask & (CWWidth | CWHeight))
3520
int width, height, max;
3522
width = (mask & CWWidth) ? xwc->width : old.width ();
3523
height = (mask & CWHeight) ? xwc->height : old.height ();
3525
xwc->width = old.width ();
3526
xwc->height = old.height ();
3528
window->constrainNewWindowSize (width, height, &width, &height);
3530
if (width != (int) old.width ())
3538
if (height != (int) old.height ())
3541
xwc->height = height;
3546
if (state & CompWindowStateMaximizedVertMask)
3548
if (old.y () < y + workArea.y () + serverInput.top)
3550
xwc->y = y + workArea.y () + serverInput.top;
3555
height = xwc->height + old.border () * 2;
3557
max = y + workArea.bottom ();
3558
if (old.y () + (int) old.height () + serverInput.bottom > max)
3560
xwc->y = max - height - serverInput.bottom;
3563
else if (old.y () + height + serverInput.bottom > max)
3565
xwc->y = y + workArea.y () +
3566
(workArea.height () - serverInput.top - height -
3567
serverInput.bottom) / 2 + serverInput.top;
3573
if (state & CompWindowStateMaximizedHorzMask)
3575
if (old.x () < x + workArea.x () + serverInput.left)
3577
xwc->x = x + workArea.x () + serverInput.left;
3582
width = xwc->width + old.border () * 2;
3584
max = x + workArea.right ();
3585
if (old.x () + (int) old.width () + serverInput.right > max)
3587
xwc->x = max - width - serverInput.right;
3590
else if (old.x () + width + serverInput.right > max)
3592
xwc->x = x + workArea.x () +
3593
(workArea.width () - serverInput.left - width -
3594
serverInput.right) / 2 + serverInput.left;
3602
if ((mask & CWX) && (xwc->x == old.x ()))
3605
if ((mask & CWY) && (xwc->y == old.y ()))
3608
if ((mask & CWWidth) && (xwc->width == (int) old.width ()))
3611
if ((mask & CWHeight) && (xwc->height == (int) old.height ()))
3618
PrivateWindow::adjustConfigureRequestForGravity (XWindowChanges *xwc,
3624
unsigned int mask = 0;
3629
if (xwcm & (CWX | CWWidth))
3632
case NorthWestGravity:
3634
case SouthWestGravity:
3636
newX += priv->border.left * direction;
3643
newX -= (xwc->width / 2 - priv->border.left +
3644
(priv->border.left + priv->border.right) / 2) * direction;
3646
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
3649
case NorthEastGravity:
3651
case SouthEastGravity:
3653
newX -= xwc->width + priv->border.right * direction;
3655
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
3664
if (xwcm & (CWY | CWHeight))
3667
case NorthWestGravity:
3669
case NorthEastGravity:
3671
newY = xwc->y + priv->serverInput.top * direction;
3678
newY -= (xwc->height / 2 - priv->serverInput.top +
3679
(priv->serverInput.top + priv->serverInput.bottom) / 2) * direction;
3681
newY -= ((xwc->height - priv->serverGeometry.height ()) / 2) * direction;
3684
case SouthWestGravity:
3686
case SouthEastGravity:
3688
newY -= xwc->height + priv->serverInput.bottom * direction;
3690
newY -= (xwc->height - priv->serverGeometry.height ()) * direction;
3701
xwc->x += (newX - xwc->x);
3707
xwc->y += (newY - xwc->y);
3715
CompWindow::moveResize (XWindowChanges *xwc,
3718
unsigned int source)
3720
bool placed = false;
3722
xwcm &= (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3724
if (xwcm & (CWX | CWY))
3725
if (priv->sizeHints.flags & (USPosition | PPosition))
3729
gravity = priv->sizeHints.win_gravity;
3732
xwc->x = priv->serverGeometry.x ();
3734
xwc->y = priv->serverGeometry.y ();
3735
if (!(xwcm & CWWidth))
3736
xwc->width = priv->serverGeometry.width ();
3737
if (!(xwcm & CWHeight))
3738
xwc->height = priv->serverGeometry.height ();
3740
if (xwcm & (CWWidth | CWHeight))
3744
if (constrainNewWindowSize (xwc->width, xwc->height, &width, &height))
3746
if (width != xwc->width)
3749
if (height != xwc->height)
3753
xwc->height = height;
3757
xwcm |= priv->adjustConfigureRequestForGravity (xwc, xwcm, gravity, 1);
3759
validateResizeRequest (xwcm, xwc, source);
3761
/* when horizontally maximized only allow width changes added by
3762
addWindowSizeChanges */
3763
if (priv->state & CompWindowStateMaximizedHorzMask)
3766
/* when vertically maximized only allow height changes added by
3767
addWindowSizeChanges */
3768
if (priv->state & CompWindowStateMaximizedVertMask)
3771
xwcm |= priv->addWindowSizeChanges (xwc, Geometry (xwc->x, xwc->y,
3772
xwc->width, xwc->height,
3773
xwc->border_width));
3775
/* check if the new coordinates are useful and valid (different
3776
to current size); if not, we have to clear them to make sure
3777
we send a synthetic ConfigureNotify event if all coordinates
3778
match the server coordinates */
3779
if (xwc->x == priv->serverGeometry.x ())
3782
if (xwc->y == priv->serverGeometry.y ())
3785
if (xwc->width == (int) priv->serverGeometry.width ())
3788
if (xwc->height == (int) priv->serverGeometry.height ())
3791
if (xwc->border_width == (int) priv->serverGeometry.border ())
3792
xwcm &= ~CWBorderWidth;
3794
/* update saved window coordinates - if CWX or CWY is set for fullscreen
3795
or maximized windows after addWindowSizeChanges, it should be pretty
3796
safe to assume that the saved coordinates should be updated too, e.g.
3797
because the window was moved to another viewport by some client */
3798
if ((xwcm & CWX) && (priv->saveMask & CWX))
3799
priv->saveWc.x += (xwc->x - priv->serverGeometry.x ());
3801
if ((xwcm & CWY) && (priv->saveMask & CWY))
3802
priv->saveWc.y += (xwc->y - priv->serverGeometry.y ());
3804
if (priv->mapNum && (xwcm & (CWWidth | CWHeight)))
3808
configureXWindow (xwcm, xwc);
3811
/* we have to send a configure notify on ConfigureRequest events if
3812
we decide not to do anything according to ICCCM 4.1.5 */
3813
sendConfigureNotify ();
3817
priv->placed = true;
3821
PrivateWindow::updateSize ()
3826
if (window->overrideRedirect () || !managed)
3829
mask = priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
3832
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
3833
window->sendSyncRequest ();
3835
window->configureXWindow (mask, &xwc);
3840
PrivateWindow::addWindowStackChanges (XWindowChanges *xwc,
3841
CompWindow *sibling)
3845
if (!sibling || sibling->priv->id != id)
3847
/* Alow requests to go on top of serverPrev
3848
* if serverPrev was recently restacked */
3849
if (window->serverPrev)
3853
XWindowChanges lxwc;
3854
unsigned int valueMask = CWStackMode;
3856
lxwc.stack_mode = Below;
3858
/* Below with no sibling puts the window at the bottom
3860
XConfigureWindow (screen->dpy (), ROOTPARENT (window), valueMask, &lxwc);
3863
priv->addPendingConfigure (lxwc, CWStackMode);
3865
/* Update the list of windows last sent to the server */
3866
screen->unhookServerWindow (window);
3867
screen->insertServerWindow (window, 0);
3871
bool pendingRestacks = false;
3873
foreach (XWCValueMask &xwcvm, sibling->priv->pendingConfigures)
3875
if (xwcvm.second & (CWSibling | CWStackMode))
3877
pendingRestacks = true;
3882
if (sibling->priv->id != window->serverPrev->priv->id || pendingRestacks)
3884
mask |= CWSibling | CWStackMode;
3886
xwc->stack_mode = Above;
3887
xwc->sibling = ROOTPARENT (sibling);
3893
mask |= CWSibling | CWStackMode;
3895
xwc->stack_mode = Above;
3896
xwc->sibling = ROOTPARENT (sibling);
3904
CompWindow::raise ()
3908
bool aboveFs = false;
3910
/* an active fullscreen window should be raised over all other
3911
windows in its layer */
3912
if (priv->type & CompWindowTypeFullscreenMask)
3913
if (priv->id == screen->activeWindow ())
3916
mask = priv->addWindowStackChanges (&xwc,
3917
PrivateWindow::findSiblingBelow (this, aboveFs));
3920
configureXWindow (mask, &xwc);
3924
PrivateScreen::focusTopMostWindow ()
3926
CompWindow *focus = NULL;
3927
CompWindowList::reverse_iterator it = serverWindows.rbegin ();
3929
for (; it != serverWindows.rend (); it++)
3931
CompWindow *w = *it;
3933
if (w->type () & CompWindowTypeDockMask)
3945
if (focus->id () != activeWindow)
3946
focus->moveInputFocusTo ();
3949
XSetInputFocus (dpy, root, RevertToPointerRoot,
3956
CompWindow::lower ()
3961
mask = priv->addWindowStackChanges (&xwc,
3962
PrivateWindow::findLowestSiblingBelow (this));
3964
configureXWindow (mask, &xwc);
3966
/* when lowering a window, focus the topmost window if
3967
the click-to-focus option is on */
3968
if ((screen->priv->optionGetClickToFocus ()))
3970
CompWindow *focusedWindow = screen->priv->focusTopMostWindow ();
3972
/* if the newly focused window is a desktop window,
3973
give the focus back to w */
3974
if (focusedWindow &&
3975
focusedWindow->type () & CompWindowTypeDesktopMask)
3977
moveInputFocusTo ();
3983
CompWindow::restackAbove (CompWindow *sibling)
3985
for (; sibling; sibling = sibling->serverNext)
3986
if (PrivateWindow::validSiblingBelow (this, sibling))
3994
mask = priv->addWindowStackChanges (&xwc, sibling);
3996
configureXWindow (mask, &xwc);
4000
/* finds the highest window under sibling we can stack above */
4002
PrivateWindow::findValidStackSiblingBelow (CompWindow *w,
4003
CompWindow *sibling)
4005
CompWindow *lowest, *last, *p;
4007
/* check whether we're allowed to stack under a sibling by finding
4008
* the above 'sibling' and checking whether or not we're allowed
4009
* to stack under that - if not, then there is no valid sibling
4012
for (p = sibling; p; p = p->serverNext)
4014
if (!avoidStackingRelativeTo (p))
4016
if (!validSiblingBelow (p, w))
4022
/* get lowest sibling we're allowed to stack above */
4023
lowest = last = findLowestSiblingBelow (w);
4025
/* walk from bottom up */
4026
for (p = screen->serverWindows ().front (); p; p = p->serverNext)
4028
/* stop walking when we reach the sibling we should try to stack
4033
/* skip windows that we should avoid */
4034
if (w == p || avoidStackingRelativeTo (p))
4037
if (validSiblingBelow (w, p))
4039
/* update lowest as we find windows below sibling that we're
4040
allowed to stack above. last window must be equal to the
4041
lowest as we shouldn't update lowest if we passed an
4047
/* update last pointer */
4055
CompWindow::restackBelow (CompWindow *sibling)
4060
mask = priv->addWindowStackChanges (&xwc,
4061
PrivateWindow::findValidStackSiblingBelow (this, sibling));
4064
configureXWindow (mask, &xwc);
4068
CompWindow::updateAttributes (CompStackingUpdateMode stackingMode)
4073
if (overrideRedirect () || !priv->managed)
4076
if (priv->state & CompWindowStateShadedMask)
4078
windowNotify (CompWindowNotifyShade);
4082
else if (priv->shaded)
4084
windowNotify (CompWindowNotifyUnshade);
4089
if (stackingMode != CompStackingUpdateModeNone)
4092
CompWindow *sibling;
4094
aboveFs = (stackingMode == CompStackingUpdateModeAboveFullscreen);
4095
if (priv->type & CompWindowTypeFullscreenMask)
4097
/* put active or soon-to-be-active fullscreen windows over
4098
all others in their layer */
4099
if (priv->id == screen->activeWindow () ||
4100
priv->id == screen->priv->nextActiveWindow)
4106
/* put windows that are just mapped, over fullscreen windows */
4107
if (stackingMode == CompStackingUpdateModeInitialMap)
4110
sibling = PrivateWindow::findSiblingBelow (this, aboveFs);
4113
(stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
4117
for (p = sibling; p; p = p->serverPrev)
4118
if (p->priv->id == screen->activeWindow ())
4121
/* window is above active window so we should lower it,
4122
* assuing that is allowed (if, for example, our window has
4123
* the "above" state, then lowering beneath the active
4124
* window may not be allowed). */
4125
if (p && PrivateWindow::validSiblingBelow (p, this))
4127
p = PrivateWindow::findValidStackSiblingBelow (sibling, p);
4129
/* if we found a valid sibling under the active window, it's
4130
our new sibling we want to stack above */
4137
mask |= priv->addWindowStackChanges (&xwc, sibling);
4140
mask |= priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
4142
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
4146
configureXWindow (mask, &xwc);
4150
PrivateWindow::ensureWindowVisibility ()
4153
int width = serverGeometry.width () + serverGeometry.border () * 2;
4154
int height = serverGeometry.height () + serverGeometry.border () * 2;
4158
if (struts || attrib.override_redirect)
4161
if (type & (CompWindowTypeDockMask |
4162
CompWindowTypeFullscreenMask |
4163
CompWindowTypeUnknownMask))
4166
x1 = screen->workArea ().x () - screen->width () * screen->vp ().x ();
4167
y1 = screen->workArea ().y () - screen->height () * screen->vp ().y ();
4168
x2 = x1 + screen->workArea ().width () + screen->vpSize ().width () *
4170
y2 = y1 + screen->workArea ().height () + screen->vpSize ().height () *
4173
if (serverGeometry.x () - serverInput.left >= x2)
4174
dx = (x2 - 25) - serverGeometry.x ();
4175
else if (serverGeometry.x () + width + serverInput.right <= x1)
4176
dx = (x1 + 25) - (serverGeometry.x () + width);
4178
if (serverGeometry.y () - serverInput.top >= y2)
4179
dy = (y2 - 25) - serverGeometry.y ();
4180
else if (serverGeometry.y () + height + serverInput.bottom <= y1)
4181
dy = (y1 + 25) - (serverGeometry.y () + height);
4187
xwc.x = serverGeometry.x () + dx;
4188
xwc.y = serverGeometry.y () + dy;
4190
window->configureXWindow (CWX | CWY, &xwc);
4195
PrivateWindow::reveal ()
4197
if (window->minimized ())
4198
window->unminimize ();
4200
screen->leaveShowDesktopMode (window);
4204
PrivateWindow::revealAncestors (CompWindow *w,
4205
CompWindow *transient)
4207
if (isAncestorTo (transient, w))
4209
screen->forEachWindow (boost::bind (revealAncestors, _1, w));
4215
CompWindow::activate ()
4217
WRAPABLE_HND_FUNC (3, activate)
4219
screen->priv->setCurrentDesktop (priv->desktop);
4221
screen->forEachWindow (
4222
boost::bind (PrivateWindow::revealAncestors, _1, this));
4225
if (priv->state & CompWindowStateHiddenMask)
4227
priv->state &= ~CompWindowStateShadedMask;
4232
if (priv->state & CompWindowStateHiddenMask)
4235
if (!onCurrentDesktop ())
4238
priv->ensureWindowVisibility ();
4239
updateAttributes (CompStackingUpdateModeAboveFullscreen);
4240
moveInputFocusTo ();
4244
#define PVertResizeInc (1 << 0)
4245
#define PHorzResizeInc (1 << 1)
4248
CompWindow::constrainNewWindowSize (int width,
4253
const XSizeHints *hints = &priv->sizeHints;
4254
int oldWidth = width;
4255
int oldHeight = height;
4259
int base_height = 0;
4262
int max_width = MAXSHORT;
4263
int max_height = MAXSHORT;
4264
long flags = hints->flags;
4265
long resizeIncFlags = (flags & PResizeInc) ? ~0 : 0;
4267
if (screen->priv->optionGetIgnoreHintsWhenMaximized ())
4269
if (priv->state & MAXIMIZE_STATE)
4273
if (priv->state & CompWindowStateMaximizedHorzMask)
4274
resizeIncFlags &= ~PHorzResizeInc;
4276
if (priv->state & CompWindowStateMaximizedVertMask)
4277
resizeIncFlags &= ~PVertResizeInc;
4281
/* Ater gdk_window_constrain_size(), which is partially borrowed from fvwm.
4283
* Copyright 1993, Robert Nation
4284
* You may use this code for any purpose, as long as the original
4285
* copyright remains in the source code and all documentation
4287
* which in turn borrows parts of the algorithm from uwm
4290
#define FLOOR(value, base) (((int) ((value) / (base))) * (base))
4291
#define FLOOR64(value, base) (((uint64_t) ((value) / (base))) * (base))
4293
if ((flags & PBaseSize) && (flags & PMinSize))
4295
base_width = hints->base_width;
4296
base_height = hints->base_height;
4297
min_width = hints->min_width;
4298
min_height = hints->min_height;
4300
else if (flags & PBaseSize)
4302
base_width = hints->base_width;
4303
base_height = hints->base_height;
4304
min_width = hints->base_width;
4305
min_height = hints->base_height;
4307
else if (flags & PMinSize)
4309
base_width = hints->min_width;
4310
base_height = hints->min_height;
4311
min_width = hints->min_width;
4312
min_height = hints->min_height;
4315
if (flags & PMaxSize)
4317
max_width = hints->max_width;
4318
max_height = hints->max_height;
4321
if (resizeIncFlags & PHorzResizeInc)
4322
xinc = MAX (xinc, hints->width_inc);
4324
if (resizeIncFlags & PVertResizeInc)
4325
yinc = MAX (yinc, hints->height_inc);
4327
/* clamp width and height to min and max values */
4328
width = CLAMP (width, min_width, max_width);
4329
height = CLAMP (height, min_height, max_height);
4331
/* shrink to base + N * inc */
4332
width = base_width + FLOOR (width - base_width, xinc);
4333
height = base_height + FLOOR (height - base_height, yinc);
4335
/* constrain aspect ratio, according to:
4337
* min_aspect.x width max_aspect.x
4338
* ------------ <= -------- <= -----------
4339
* min_aspect.y height max_aspect.y
4341
if ((flags & PAspect) && hints->min_aspect.y > 0 && hints->max_aspect.x > 0)
4343
/* Use 64 bit arithmetic to prevent overflow */
4345
uint64_t min_aspect_x = hints->min_aspect.x;
4346
uint64_t min_aspect_y = hints->min_aspect.y;
4347
uint64_t max_aspect_x = hints->max_aspect.x;
4348
uint64_t max_aspect_y = hints->max_aspect.y;
4351
if (min_aspect_x * height > width * min_aspect_y)
4353
delta = FLOOR64 (height - width * min_aspect_y / min_aspect_x,
4355
if (height - (int) delta >= min_height)
4359
delta = FLOOR64 (height * min_aspect_x / min_aspect_y - width,
4361
if (width + (int) delta <= max_width)
4366
if (width * max_aspect_y > max_aspect_x * height)
4368
delta = FLOOR64 (width - height * max_aspect_x / max_aspect_y,
4370
if (width - (int) delta >= min_width)
4374
delta = FLOOR64 (width * min_aspect_y / min_aspect_x - height,
4376
if (height + (int) delta <= max_height)
4386
if (width != oldWidth || height != oldHeight)
4389
*newHeight = height;
4400
priv->hidden = true;
4407
priv->hidden = false;
4412
PrivateWindow::hide ()
4414
bool onDesktop = window->onCurrentDesktop ();
4419
if (!window->minimized () && !inShowDesktopMode &&
4420
!hidden && onDesktop)
4422
if (state & CompWindowStateShadedMask)
4435
if ((state & CompWindowStateShadedMask) && serverFrame)
4436
XUnmapWindow (screen->dpy (), serverFrame);
4439
if (!pendingMaps && !window->isViewable ())
4442
window->windowNotify (CompWindowNotifyHide);
4446
if (serverFrame && !shaded)
4447
XUnmapWindow (screen->dpy (), serverFrame);
4449
XUnmapWindow (screen->dpy (), id);
4451
if (window->minimized () || inShowDesktopMode || hidden || shaded)
4452
window->changeState (state | CompWindowStateHiddenMask);
4454
if (shaded && id == screen->activeWindow ())
4455
window->moveInputFocusTo ();
4459
PrivateWindow::show ()
4461
bool onDesktop = window->onCurrentDesktop ();
4466
if (minimized || inShowDesktopMode ||
4467
hidden || !onDesktop)
4469
/* no longer hidden but not on current desktop */
4470
if (!minimized && !inShowDesktopMode && !hidden)
4471
window->changeState (state & ~CompWindowStateHiddenMask);
4476
/* transition from minimized to shaded */
4477
if (state & CompWindowStateShadedMask)
4482
XMapWindow (screen->dpy (), serverFrame);
4486
priv->geometry.setHeight (priv->geometry.height () + 1);
4487
window->resize (geometry.x (), geometry.y (),
4488
geometry.width (), geometry.height () - 1,
4489
geometry.border ());
4499
window->windowNotify (CompWindowNotifyShow);
4505
XMapWindow (screen->dpy (), serverFrame);
4506
XMapWindow (screen->dpy (), wrapper);
4509
XMapWindow (screen->dpy (), id);
4511
window->changeState (state & ~CompWindowStateHiddenMask);
4512
screen->priv->setWindowState (state, id);
4516
PrivateWindow::minimizeTransients (CompWindow *w,
4517
CompWindow *ancestor)
4519
if (w->priv->transientFor == ancestor->priv->id ||
4520
w->priv->isGroupTransient (ancestor->priv->clientLeader))
4527
CompWindow::minimize ()
4529
WRAPABLE_HND_FUNC (13, minimize);
4534
if (!priv->minimized)
4536
windowNotify (CompWindowNotifyMinimize);
4538
priv->minimized = true;
4540
screen->forEachWindow (
4541
boost::bind (PrivateWindow::minimizeTransients, _1, this));
4548
PrivateWindow::unminimizeTransients (CompWindow *w,
4549
CompWindow *ancestor)
4551
if (w->priv->transientFor == ancestor->priv->id ||
4552
w->priv->isGroupTransient (ancestor->priv->clientLeader))
4557
CompWindow::unminimize ()
4559
WRAPABLE_HND_FUNC (14, unminimize);
4560
if (priv->minimized)
4562
windowNotify (CompWindowNotifyUnminimize);
4564
priv->minimized = false;
4568
screen->forEachWindow (
4569
boost::bind (PrivateWindow::unminimizeTransients, _1, this));
4574
CompWindow::maximize (unsigned int state)
4576
if (overrideRedirect ())
4579
state = constrainWindowState (state, priv->actions);
4581
state &= MAXIMIZE_STATE;
4583
if (state == (priv->state & MAXIMIZE_STATE))
4586
state |= (priv->state & ~MAXIMIZE_STATE);
4588
changeState (state);
4589
updateAttributes (CompStackingUpdateModeNone);
4593
PrivateWindow::getUserTime (Time& time)
4597
unsigned long n, left;
4598
unsigned char *data;
4599
bool retval = false;
4601
result = XGetWindowProperty (screen->dpy (), priv->id,
4603
0L, 1L, False, XA_CARDINAL, &actual, &format,
4606
if (result == Success && data)
4612
memcpy (&value, data, sizeof (CARD32));
4614
time = (Time) value;
4617
XFree ((void *) data);
4624
PrivateWindow::setUserTime (Time time)
4626
CARD32 value = (CARD32) time;
4628
XChangeProperty (screen->dpy (), priv->id,
4630
XA_CARDINAL, 32, PropModeReplace,
4631
(unsigned char *) &value, 1);
4635
* Macros from metacity
4637
* Xserver time can wraparound, thus comparing two timestamps needs to
4638
* take this into account. Here's a little macro to help out. If no
4639
* wraparound has occurred, this is equivalent to
4641
* Of course, the rest of the ugliness of this macro comes from
4642
* accounting for the fact that wraparound can occur and the fact that
4643
* a timestamp of 0 must be special-cased since it means older than
4646
* Note that this is NOT an equivalent for time1 <= time2; if that's
4647
* what you need then you'll need to swap the order of the arguments
4648
* and negate the result.
4650
#define XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) \
4651
( (( (time1) < (time2) ) && \
4652
( (time2) - (time1) < ((unsigned long) -1) / 2 )) || \
4653
(( (time1) > (time2) ) && \
4654
( (time1) - (time2) > ((unsigned long) -1) / 2 )) \
4656
#define XSERVER_TIME_IS_BEFORE(time1, time2) \
4658
(XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS (time1, time2) && \
4663
PrivateWindow::getUsageTimestamp (Time& timestamp)
4665
if (getUserTime (timestamp))
4668
if (initialTimestampSet)
4670
timestamp = initialTimestamp;
4678
PrivateWindow::isWindowFocusAllowed (Time timestamp)
4680
CompScreen *s = screen;
4682
Time wUserTime, aUserTime;
4683
bool gotTimestamp = false;
4687
level = s->priv->optionGetFocusPreventionLevel ();
4689
if (level == CoreOptions::FocusPreventionLevelOff)
4694
/* the caller passed a timestamp, so use that
4695
instead of the window's user time */
4696
wUserTime = timestamp;
4697
gotTimestamp = true;
4701
gotTimestamp = getUsageTimestamp (wUserTime);
4704
/* if we got no timestamp for the window, try to get at least a timestamp
4705
for its transient parent, if any */
4706
if (!gotTimestamp && transientFor)
4710
parent = screen->findWindow (transientFor);
4712
gotTimestamp = parent->priv->getUsageTimestamp (wUserTime);
4715
if (gotTimestamp && !wUserTime)
4717
/* window explicitly requested no focus */
4721
/* allow focus for excluded windows */
4722
CompMatch &match = s->priv->optionGetFocusPreventionMatch ();
4723
if (!match.evaluate (window))
4726
if (level == CoreOptions::FocusPreventionLevelVeryHigh)
4729
active = s->findWindow (s->activeWindow ());
4731
/* no active window */
4732
if (!active || (active->type () & CompWindowTypeDesktopMask))
4735
/* active window belongs to same application */
4736
if (window->clientLeader () == active->clientLeader ())
4739
if (level == CoreOptions::FocusPreventionLevelHigh)
4742
/* not in current viewport or desktop */
4743
if (!window->onCurrentDesktop ())
4746
dvp = window->defaultViewport ();
4747
if (dvp.x () != s->vp ().x () || dvp.y () != s->vp ().y ())
4752
/* unsure as we have nothing to compare - allow focus in low level,
4753
don't allow in normal level */
4754
if (level == CoreOptions::FocusPreventionLevelNormal)
4760
/* can't get user time for active window */
4761
if (!active->priv->getUserTime (aUserTime))
4764
if (XSERVER_TIME_IS_BEFORE (wUserTime, aUserTime))
4771
PrivateWindow::allowWindowFocus (unsigned int noFocusMask,
4776
if (priv->id == screen->activeWindow ())
4779
/* do not focus windows of these types */
4780
if (priv->type & noFocusMask)
4783
/* window doesn't take focus */
4784
if (!priv->inputHint &&
4785
!(priv->protocols & CompWindowProtocolTakeFocusMask))
4790
retval = priv->isWindowFocusAllowed (timestamp);
4793
/* add demands attention state if focus was prevented */
4794
window->changeState (priv->state | CompWindowStateDemandsAttentionMask);
4801
CompWindow::defaultViewport ()
4805
if (priv->serverGeometry.x () < (int) screen->width () &&
4806
priv->serverGeometry.x () + priv->serverGeometry.width () > 0 &&
4807
priv->serverGeometry.y () < (int) screen->height () &&
4808
priv->serverGeometry.y ()+ priv->serverGeometry.height () > 0)
4810
return screen->vp ();
4813
screen->viewportForGeometry (priv->serverGeometry, viewport);
4819
CompWindow::initialViewport () const
4821
return priv->initialViewport;
4825
PrivateWindow::readIconHint ()
4827
XImage *image, *maskImage = NULL;
4828
Display *dpy = screen->dpy ();
4829
unsigned int width, height, dummy;
4830
unsigned int i, j, k;
4837
if (!XGetGeometry (dpy, hints->icon_pixmap, &wDummy, &iDummy,
4838
&iDummy, &width, &height, &dummy, &dummy))
4841
image = XGetImage (dpy, hints->icon_pixmap, 0, 0, width, height,
4842
AllPlanes, ZPixmap);
4846
colors = new XColor[width * height];
4849
XDestroyImage (image);
4854
for (j = 0; j < height; j++)
4855
for (i = 0; i < width; i++)
4856
colors[k++].pixel = XGetPixel (image, i, j);
4858
for (i = 0; i < k; i += 256)
4859
XQueryColors (dpy, screen->priv->colormap,
4860
&colors[i], MIN (k - i, 256));
4862
XDestroyImage (image);
4864
icon = new CompIcon (screen, width, height);
4871
if (hints->flags & IconMaskHint)
4872
maskImage = XGetImage (dpy, hints->icon_mask, 0, 0,
4873
width, height, AllPlanes, ZPixmap);
4876
p = (CARD32 *) icon->data ();
4878
for (j = 0; j < height; j++)
4880
for (i = 0; i < width; i++)
4882
if (maskImage && !XGetPixel (maskImage, i, j))
4884
else if (image->depth == 1) /* white : black */
4885
*p++ = colors[k].pixel ? 0xffffffff : 0xff000000;
4887
*p++ = 0xff000000 | /* alpha */
4888
(((colors[k].red >> 8) & 0xff) << 16) | /* red */
4889
(((colors[k].green >> 8) & 0xff) << 8) | /* green */
4890
((colors[k].blue >> 8) & 0xff); /* blue */
4898
XDestroyImage (maskImage);
4900
icons.push_back (icon);
4903
/* returns icon with dimensions as close as possible to width and height
4904
but never greater. */
4906
CompWindow::getIcon (int width,
4910
int wh, diff, oldDiff;
4913
/* need to fetch icon property */
4914
if (priv->icons.size () == 0 && !priv->noIcons)
4918
unsigned long n, left;
4919
unsigned char *data;
4921
result = XGetWindowProperty (screen->dpy (), priv->id, Atoms::wmIcon,
4922
0L, 65536L, false, XA_CARDINAL,
4923
&actual, &format, &n, &left, &data);
4925
if (result == Success && data)
4928
CARD32 alpha, red, green, blue;
4929
unsigned long iw, ih;
4931
for (i = 0; i + 2 < n; i += iw * ih + 2)
4933
unsigned long *idata = (unsigned long *) data;
4938
/* iw * ih may be larger than the value range of unsigned
4939
* long, so better do some checking for extremely weird
4940
* icon sizes first */
4941
if (iw > 2048 || ih > 2048 || iw * ih + 2 > n - i)
4947
icon = new CompIcon (screen, iw, ih);
4951
priv->icons.push_back (icon);
4953
p = (CARD32 *) (icon->data ());
4955
/* EWMH doesn't say if icon data is premultiplied or
4956
not but most applications seem to assume data should
4957
be unpremultiplied. */
4958
for (j = 0; j < iw * ih; j++)
4960
alpha = (idata[i + j + 2] >> 24) & 0xff;
4961
red = (idata[i + j + 2] >> 16) & 0xff;
4962
green = (idata[i + j + 2] >> 8) & 0xff;
4963
blue = (idata[i + j + 2] >> 0) & 0xff;
4965
red = (red * alpha) >> 8;
4966
green = (green * alpha) >> 8;
4967
blue = (blue * alpha) >> 8;
4980
else if (priv->hints && (priv->hints->flags & IconPixmapHint))
4982
priv->readIconHint ();
4985
/* don't fetch property again */
4986
if (priv->icons.size () == 0)
4987
priv->noIcons = true;
4990
/* no icons available for this window */
4995
wh = width + height;
4997
for (i = 0; i < priv->icons.size (); i++)
4999
const CompSize iconSize = *priv->icons[i];
5001
if ((int) iconSize.width () > width ||
5002
(int) iconSize.height () > height)
5007
diff = wh - (iconSize.width () + iconSize.height ());
5008
oldDiff = wh - (icon->width () + icon->height ());
5011
icon = priv->icons[i];
5014
icon = priv->icons[i];
5021
CompWindow::iconGeometry () const
5023
return priv->iconGeometry;
5027
PrivateWindow::freeIcons ()
5029
for (unsigned int i = 0; i < priv->icons.size (); i++)
5030
delete priv->icons[i];
5032
priv->icons.resize (0);
5033
priv->noIcons = false;
5037
CompWindow::outputDevice ()
5039
return screen->outputDeviceForGeometry (priv->serverGeometry);
5043
CompWindow::onCurrentDesktop ()
5045
if (priv->desktop == 0xffffffff ||
5046
priv->desktop == screen->currentDesktop ())
5055
CompWindow::setDesktop (unsigned int desktop)
5057
if (desktop != 0xffffffff)
5059
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5062
if (desktop >= screen->nDesktop ())
5066
if (desktop == priv->desktop)
5069
priv->desktop = desktop;
5071
if (desktop == 0xffffffff || desktop == screen->currentDesktop ())
5076
screen->setWindowProp (priv->id, Atoms::winDesktop, priv->desktop);
5079
/* The compareWindowActiveness function compares the two windows 'w1'
5080
and 'w2'. It returns an integer less than, equal to, or greater
5081
than zero if 'w1' is found, respectively, to activated longer time
5082
ago than, to be activated at the same time, or be activated more
5083
recently than 'w2'. */
5085
PrivateWindow::compareWindowActiveness (CompWindow *w1,
5088
CompActiveWindowHistory *history = screen->currentHistory ();
5091
/* check current window history first */
5092
for (i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
5094
if (history->id[i] == w1->priv->id)
5097
if (history->id[i] == w2->priv->id)
5100
if (!history->id[i])
5104
return w1->priv->activeNum - w2->priv->activeNum;
5108
CompWindow::onAllViewports ()
5110
if (overrideRedirect ())
5113
if (!priv->managed && !isViewable ())
5116
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5119
if (priv->state & CompWindowStateStickyMask)
5126
CompWindow::getMovementForOffset (CompPoint offset)
5128
CompScreen *s = screen;
5129
int m, vWidth, vHeight;
5130
int offX = offset.x (), offY = offset.y ();
5133
vWidth = s->width () * s->vpSize ().width ();
5134
vHeight = s->height () * s->vpSize ().height ();
5140
if (s->vpSize ().width () == 1)
5146
m = priv->geometry.x () + offX;
5147
if (m - priv->input.left < (int) s->width () - vWidth)
5148
rv.setX (offX + vWidth);
5149
else if (m + priv->width + priv->input.right > vWidth)
5150
rv.setX (offX - vWidth);
5155
if (s->vpSize ().height () == 1)
5161
m = priv->geometry.y () + offY;
5162
if (m - priv->input.top < (int) s->height () - vHeight)
5163
rv.setY (offY + vHeight);
5164
else if (m + priv->height + priv->input.bottom > vHeight)
5165
rv.setY (offY - vHeight);
5174
WindowInterface::getOutputExtents (CompWindowExtents& output)
5175
WRAPABLE_DEF (getOutputExtents, output)
5178
WindowInterface::getAllowedActions (unsigned int &setActions,
5179
unsigned int &clearActions)
5180
WRAPABLE_DEF (getAllowedActions, setActions, clearActions)
5183
WindowInterface::focus ()
5184
WRAPABLE_DEF (focus)
5187
WindowInterface::activate ()
5188
WRAPABLE_DEF (activate)
5191
WindowInterface::place (CompPoint &pos)
5192
WRAPABLE_DEF (place, pos)
5195
WindowInterface::validateResizeRequest (unsigned int &mask,
5196
XWindowChanges *xwc,
5197
unsigned int source)
5198
WRAPABLE_DEF (validateResizeRequest, mask, xwc, source)
5201
WindowInterface::resizeNotify (int dx,
5205
WRAPABLE_DEF (resizeNotify, dx, dy, dwidth, dheight)
5208
WindowInterface::moveNotify (int dx,
5211
WRAPABLE_DEF (moveNotify, dx, dy, immediate)
5214
WindowInterface::windowNotify (CompWindowNotify n)
5215
WRAPABLE_DEF (windowNotify, n)
5218
WindowInterface::grabNotify (int x,
5222
WRAPABLE_DEF (grabNotify, x, y, state, mask)
5225
WindowInterface::ungrabNotify ()
5226
WRAPABLE_DEF (ungrabNotify)
5229
WindowInterface::stateChangeNotify (unsigned int lastState)
5230
WRAPABLE_DEF (stateChangeNotify, lastState)
5233
WindowInterface::updateFrameRegion (CompRegion ®ion)
5234
WRAPABLE_DEF (updateFrameRegion, region)
5237
WindowInterface::minimize ()
5238
WRAPABLE_DEF (minimize);
5241
WindowInterface::unminimize ()
5242
WRAPABLE_DEF (unminimize);
5245
WindowInterface::minimized ()
5246
WRAPABLE_DEF (minimized);
5249
WindowInterface::alpha ()
5250
WRAPABLE_DEF (alpha);
5253
WindowInterface::isFocussable ()
5254
WRAPABLE_DEF (isFocussable);
5257
WindowInterface::managed ()
5258
WRAPABLE_DEF (managed);
5273
CompWindow::state ()
5279
CompWindow::actions ()
5281
return priv->actions;
5285
CompWindow::protocols ()
5287
return priv->protocols;
5291
CompWindow::close (Time serverTime)
5293
if (serverTime == 0)
5294
serverTime = screen->getCurrentTime ();
5298
if (priv->protocols & CompWindowProtocolDeleteMask)
5302
ev.type = ClientMessage;
5303
ev.xclient.window = priv->id;
5304
ev.xclient.message_type = Atoms::wmProtocols;
5305
ev.xclient.format = 32;
5306
ev.xclient.data.l[0] = Atoms::wmDeleteWindow;
5307
ev.xclient.data.l[1] = serverTime;
5308
ev.xclient.data.l[2] = 0;
5309
ev.xclient.data.l[3] = 0;
5310
ev.xclient.data.l[4] = 0;
5312
XSendEvent (screen->dpy (), priv->id, false, NoEventMask, &ev);
5316
XKillClient (screen->dpy (), priv->id);
5319
priv->closeRequests++;
5323
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5324
serverTime, priv->id, true, 0, 0);
5327
priv->lastCloseRequestTime = serverTime;
5331
PrivateWindow::handlePingTimeout (unsigned int lastPing)
5333
if (!window->isViewable ())
5336
if (!(priv->type & CompWindowTypeNormalMask))
5339
if (priv->protocols & CompWindowProtocolPingMask)
5341
if (priv->transientFor)
5344
if (priv->lastPong < lastPing)
5348
priv->alive = false;
5350
window->windowNotify (CompWindowNotifyAliveChanged);
5352
if (priv->closeRequests)
5354
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5355
priv->lastCloseRequestTime,
5356
priv->id, true, 0, 0);
5358
priv->closeRequests = 0;
5369
PrivateWindow::handlePing (int lastPing)
5375
window->windowNotify (CompWindowNotifyAliveChanged);
5377
if (priv->lastCloseRequestTime)
5379
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5380
priv->lastCloseRequestTime,
5381
priv->id, false, 0, 0);
5383
priv->lastCloseRequestTime = 0;
5386
priv->lastPong = lastPing;
5390
PrivateWindow::processMap ()
5393
bool initiallyMinimized;
5394
CompStackingUpdateMode stackingMode;
5396
priv->initialViewport = screen->vp ();
5398
priv->initialTimestampSet = false;
5400
screen->priv->applyStartupProperties (window);
5402
initiallyMinimized = (priv->hints &&
5403
priv->hints->initial_state == IconicState &&
5404
!window->minimized ());
5406
if (!serverFrame && !initiallyMinimized)
5409
priv->managed = true;
5413
int gravity = priv->sizeHints.win_gravity;
5417
/* adjust for gravity, but only for frame size */
5418
xwc.x = priv->serverGeometry.x ();
5419
xwc.y = priv->serverGeometry.y ();
5423
xwcm = adjustConfigureRequestForGravity (&xwc, CWX | CWY, gravity, 1);
5425
window->validateResizeRequest (xwcm, &xwc, ClientTypeApplication);
5427
CompPoint pos (xwc.x, xwc.y);
5428
if (window->place (pos))
5436
window->configureXWindow (xwcm, &xwc);
5438
priv->placed = true;
5441
allowFocus = allowWindowFocus (NO_FOCUS_MASK, 0);
5443
if (!allowFocus && (priv->type & ~NO_FOCUS_MASK))
5444
stackingMode = CompStackingUpdateModeInitialMapDeniedFocus;
5446
stackingMode = CompStackingUpdateModeInitialMap;
5448
window->updateAttributes (stackingMode);
5450
if (window->minimized () && !initiallyMinimized)
5451
window->unminimize ();
5453
screen->leaveShowDesktopMode (window);
5455
if (!initiallyMinimized)
5457
if (allowFocus && !window->onCurrentDesktop ());
5458
screen->priv->setCurrentDesktop (priv->desktop);
5460
if (!(priv->state & CompWindowStateHiddenMask))
5465
window->moveInputFocusTo ();
5466
if (!window->onCurrentDesktop ())
5467
screen->priv->setCurrentDesktop (priv->desktop);
5472
window->minimize ();
5473
window->changeState (window->state () | CompWindowStateHiddenMask);
5476
screen->priv->updateClientList ();
5480
* PrivateWindow::updatePassiveButtonGrabs
5482
* Updates the passive button grabs for a window. When
5483
* one of the specified button + modifier combinations
5484
* for this window is activated, compiz will be given
5485
* an active grab for the window (which we can turn off
5486
* by calling XAllowEvents later in ::handleEvent)
5488
* NOTE: ICCCM says that we are only allowed to grab
5489
* windows that we actually own as a client, so only
5490
* grab the frame window. Additionally, although there
5491
* isn't anything in the ICCCM that says we cannot
5492
* grab every button, some clients do not interpret
5493
* EnterNotify and LeaveNotify events caused by the
5494
* activation of the grab correctly, so ungrab button
5495
* and modifier combinations that we do not need on
5496
* active windows (but in reality we shouldn't be grabbing
5497
* for buttons that we don't actually need at that point
5502
PrivateWindow::updatePassiveButtonGrabs ()
5504
bool onlyActions = (priv->id == screen->priv->activeWindow ||
5505
!screen->priv->optionGetClickToFocus ());
5510
/* Ungrab everything */
5511
XUngrabButton (screen->priv->dpy, AnyButton, AnyModifier, frame);
5513
/* We don't need the full grab in the following cases:
5514
* - This window has the focus and either
5516
* - we don't want click raise
5521
if (screen->priv->optionGetRaiseOnClick ())
5523
CompWindow *highestSibling =
5524
PrivateWindow::findSiblingBelow (window, true);
5526
/* Check if this window is permitted to be raised */
5527
for (CompWindow *above = window->serverNext;
5528
above != NULL; above = above->serverNext)
5530
if (highestSibling == above)
5532
onlyActions = false;
5541
/* Grab only we have bindings on */
5542
foreach (PrivateScreen::ButtonGrab &bind, screen->priv->buttonGrabs)
5544
unsigned int mods = modHandler->virtualToRealModMask (bind.modifiers);
5546
if (mods & CompNoMask)
5549
for (unsigned int ignore = 0;
5550
ignore <= modHandler->ignoredModMask (); ignore++)
5552
if (ignore & ~modHandler->ignoredModMask ())
5555
XGrabButton (screen->priv->dpy,
5560
ButtonPressMask | ButtonReleaseMask |
5571
/* Grab everything */
5572
XGrabButton (screen->priv->dpy,
5576
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
5586
CompWindow::region () const
5588
return priv->region;
5592
CompWindow::frameRegion () const
5594
return priv->frameRegion;
5598
CompWindow::inShowDesktopMode ()
5600
return priv->inShowDesktopMode;
5604
CompWindow::setShowDesktopMode (bool value)
5606
priv->inShowDesktopMode = value;
5610
CompWindow::managed ()
5612
WRAPABLE_HND_FUNC_RETURN (18, bool, managed);
5613
return priv->managed;
5617
CompWindow::grabbed ()
5619
return priv->grabbed;
5623
CompWindow::pendingMaps ()
5625
return priv->pendingMaps;
5629
CompWindow::wmType ()
5631
return priv->wmType;
5635
CompWindow::activeNum ()
5637
return priv->activeNum;
5641
CompWindow::frame ()
5643
return priv->serverFrame;
5647
CompWindow::resName ()
5650
return priv->resName;
5652
return CompString ();
5656
CompWindow::mapNum () const
5658
return priv->mapNum;
5662
CompWindow::struts ()
5664
return priv->struts;
5668
CompWindow::saveMask ()
5670
return priv->saveMask;
5674
CompWindow::saveWc ()
5676
return priv->saveWc;
5680
CompWindow::moveToViewportPosition (int x,
5685
int vWidth = screen->width () * screen->vpSize ().width ();
5686
int vHeight = screen->height () * screen->vpSize ().height ();
5688
if (screen->vpSize ().width () != 1)
5690
x += screen->vp ().x () * screen->width ();
5691
x = MOD (x, vWidth);
5692
x -= screen->vp ().x () * screen->width ();
5695
if (screen->vpSize ().height () != 1)
5697
y += screen->vp ().y () * screen->height ();
5698
y = MOD (y, vHeight);
5699
y -= screen->vp ().y () * screen->height ();
5702
tx = x - priv->geometry.x ();
5703
ty = y - priv->geometry.y ();
5707
unsigned int valueMask = CWX | CWY;
5714
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5717
if (priv->state & CompWindowStateStickyMask)
5723
if (screen->vpSize ().width ()!= 1)
5725
m = priv->geometry.x () + tx;
5727
if (m - priv->output.left < (int) screen->width () - vWidth)
5729
else if (m + priv->width + priv->output.right > vWidth)
5733
if (screen->vpSize ().height () != 1)
5735
m = priv->geometry.y () + ty;
5737
if (m - priv->output.top < (int) screen->height () - vHeight)
5739
else if (m + priv->height + priv->output.bottom > vHeight)
5743
if (priv->saveMask & CWX)
5744
priv->saveWc.x += wx;
5746
if (priv->saveMask & CWY)
5747
priv->saveWc.y += wy;
5749
xwc.x = serverGeometry ().x () + wx;
5750
xwc.y = serverGeometry ().y () + wy;
5752
configureXWindow (valueMask, &xwc);
5757
CompWindow::startupId ()
5759
return priv->startupId;
5763
PrivateWindow::applyStartupProperties (CompStartupSequence *s)
5767
priv->initialViewport.setX (s->viewportX);
5768
priv->initialViewport.setY (s->viewportY);
5770
workspace = sn_startup_sequence_get_workspace (s->sequence);
5772
window->setDesktop (workspace);
5774
priv->initialTimestamp =
5775
sn_startup_sequence_get_timestamp (s->sequence);
5776
priv->initialTimestampSet = true;
5780
CompWindow::desktop ()
5782
return priv->desktop;
5786
CompWindow::clientLeader (bool checkAncestor)
5788
if (priv->clientLeader)
5789
return priv->clientLeader;
5792
return priv->getClientLeaderOfAncestor ();
5798
CompWindow::transientFor ()
5800
return priv->transientFor;
5804
CompWindow::pendingUnmaps ()
5806
return priv->pendingUnmaps;
5810
CompWindow::minimized ()
5812
WRAPABLE_HND_FUNC_RETURN (15, bool, minimized);
5813
return priv->minimized;
5817
CompWindow::placed ()
5819
return priv->placed;
5823
CompWindow::shaded ()
5825
return priv->shaded;
5829
CompWindow::border () const
5831
return priv->border;
5835
CompWindow::input () const
5837
return priv->serverInput;
5841
CompWindow::output () const
5843
return priv->output;
5847
CompWindow::sizeHints () const
5849
return priv->sizeHints;
5853
PrivateWindow::updateMwmHints ()
5855
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
5856
window->recalcActions ();
5860
PrivateWindow::updateStartupId ()
5862
char *oldId = startupId;
5865
startupId = getStartupId ();
5867
if (oldId && startupId)
5869
if (strcmp (startupId, oldId) == 0)
5873
if (managed && startupId && newId)
5880
initialTimestampSet = false;
5881
screen->priv->applyStartupProperties (window);
5883
if (initialTimestampSet)
5884
timestamp = initialTimestamp;
5886
/* as the viewport can't be transmitted via startup
5887
notification, assume the client changing the ID
5888
wanted to activate the window on the current viewport */
5890
vp = window->defaultViewport ();
5891
svp = screen->vp ();
5894
x = window->geometry ().x () + (svp.x () - vp.x ()) * size.width ();
5895
y = window->geometry ().y () + (svp.y () - vp.y ()) * size.height ();
5896
window->moveToViewportPosition (x, y, true);
5898
if (allowWindowFocus (0, timestamp))
5899
window->activate ();
5907
CompWindow::destroyed ()
5909
return priv->destroyed;
5913
CompWindow::invisible ()
5915
return priv->invisible;
5919
CompWindow::syncAlarm ()
5921
return priv->syncAlarm;
5925
CoreWindow::manage (Window aboveId, XWindowAttributes &wa)
5927
return new CompWindow (aboveId, wa, priv);
5930
CoreWindow::CoreWindow (Window id)
5932
priv = new PrivateWindow ();
5935
priv->serverId = id;
5938
CompWindow::CompWindow (Window aboveId,
5939
XWindowAttributes &wa,
5940
PrivateWindow *priv) :
5941
PluginClassStorage (windowPluginClassIndices),
5944
StackDebugger *dbg = StackDebugger::Default ();
5946
// TODO: Reparent first!
5948
priv->window = this;
5950
screen->insertWindow (this, aboveId);
5951
screen->insertServerWindow (this, aboveId);
5953
/* We must immediately insert the window into the debugging
5956
dbg->overrideRedirectRestack (priv->id, aboveId);
5958
gettimeofday (&priv->lastConfigureRequest, NULL);
5961
priv->serverGeometry.set (priv->attrib.x, priv->attrib.y,
5962
priv->attrib.width, priv->attrib.height,
5963
priv->attrib.border_width);
5964
priv->serverFrameGeometry = priv->frameGeometry = priv->syncGeometry
5965
= priv->geometry = priv->serverGeometry;
5967
priv->width = priv->attrib.width + priv->attrib.border_width * 2;
5968
priv->height = priv->attrib.height + priv->attrib.border_width * 2;
5970
priv->sizeHints.flags = 0;
5972
priv->recalcNormalHints ();
5974
priv->transientFor = None;
5975
priv->clientLeader = None;
5977
XSelectInput (screen->dpy (), priv->id,
5978
wa.your_event_mask |
5979
PropertyChangeMask |
5983
priv->alpha = (priv->attrib.depth == 32);
5984
priv->lastPong = screen->priv->lastPing;
5986
if (screen->XShape ())
5987
XShapeSelectInput (screen->dpy (), priv->id, ShapeNotifyMask);
5989
if (priv->attrib.c_class != InputOnly)
5991
priv->region = CompRegion (priv->attrib.x, priv->attrib.y,
5992
priv->width, priv->height);
5993
priv->inputRegion = priv->region;
5995
/* need to check for DisplayModal state on all windows */
5996
priv->state = screen->priv->getWindowState (priv->id);
5998
priv->updateClassHints ();
6002
priv->attrib.map_state = IsUnmapped;
6005
priv->wmType = screen->priv->getWindowType (priv->id);
6006
priv->protocols = screen->priv->getProtocols (priv->id);
6008
if (!overrideRedirect ())
6010
priv->updateNormalHints ();
6012
priv->updateWmHints ();
6013
priv->updateTransientHint ();
6015
priv->clientLeader = priv->getClientLeader ();
6016
priv->startupId = priv->getStartupId ();
6020
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
6022
if (!(priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask)))
6024
priv->desktop = screen->getWindowProp (priv->id, Atoms::winDesktop,
6026
if (priv->desktop != 0xffffffff)
6028
if (priv->desktop >= screen->nDesktop ())
6029
priv->desktop = screen->currentDesktop ();
6038
if (priv->attrib.map_state == IsViewable)
6040
priv->placed = true;
6042
if (!overrideRedirect ())
6044
// needs to happen right after maprequest
6045
if (!priv->serverFrame)
6047
priv->managed = true;
6049
if (screen->priv->getWmState (priv->id) == IconicState)
6051
if (priv->state & CompWindowStateShadedMask)
6052
priv->shaded = true;
6054
priv->minimized = true;
6058
if (priv->wmType & (CompWindowTypeDockMask |
6059
CompWindowTypeDesktopMask))
6061
setDesktop (0xffffffff);
6065
if (priv->desktop != 0xffffffff)
6066
priv->desktop = screen->currentDesktop ();
6068
screen->setWindowProp (priv->id, Atoms::winDesktop,
6074
priv->attrib.map_state = IsUnmapped;
6075
priv->pendingMaps++;
6079
updateAttributes (CompStackingUpdateModeNormal);
6081
if (priv->minimized || priv->inShowDesktopMode ||
6082
priv->hidden || priv->shaded)
6084
priv->state |= CompWindowStateHiddenMask;
6086
priv->pendingUnmaps++;
6088
if (priv->serverFrame && !priv->shaded)
6089
XUnmapWindow (screen->dpy (), priv->serverFrame);
6091
XUnmapWindow (screen->dpy (), priv->id);
6093
screen->priv->setWindowState (priv->state, priv->id);
6096
else if (!overrideRedirect ())
6098
if (screen->priv->getWmState (priv->id) == IconicState)
6100
// before everything else in maprequest
6101
if (!priv->serverFrame)
6103
priv->managed = true;
6104
priv->placed = true;
6106
if (priv->state & CompWindowStateHiddenMask)
6108
if (priv->state & CompWindowStateShadedMask)
6109
priv->shaded = true;
6111
priv->minimized = true;
6116
/* TODO: bailout properly when objectInitPlugins fails */
6117
assert (CompPlugin::windowInitPlugins (this));
6120
priv->updateIconGeometry ();
6124
priv->geometry.setHeight (priv->geometry.height () + 1);
6125
resize (priv->geometry.x (), priv->geometry.y (),
6126
priv->geometry.width (), priv->geometry.height () - 1,
6127
priv->geometry.border ());
6130
if (priv->attrib.map_state == IsViewable)
6132
priv->invisible = WINDOW_INVISIBLE (priv);
6136
CompWindow::~CompWindow ()
6138
if (priv->serverFrame)
6139
priv->unreparent ();
6141
/* Update the references of other windows
6142
* pending destroy if this was a sibling
6143
* of one of those */
6145
screen->priv->destroyedWindows.remove (this);
6147
foreach (CompWindow *dw, screen->priv->destroyedWindows)
6149
if (dw->next == this)
6150
dw->next = this->next;
6151
if (dw->prev == this)
6152
dw->prev = this->prev;
6154
if (dw->serverNext == this)
6155
dw->serverNext = this->serverNext;
6156
if (dw->serverPrev == this)
6157
dw->serverPrev = this->serverPrev;
6160
/* If this window has a detached frame, destroy it, but only
6161
* using XDestroyWindow since there may be pending restack
6162
* requests relative to it */
6164
std::map <CompWindow *, CompWindow *>::iterator it =
6165
screen->priv->detachedFrameWindows.find (this);
6167
if (it != screen->priv->detachedFrameWindows.end ())
6169
CompWindow *fw = (it->second);
6171
XDestroyWindow (screen->dpy (), fw->id ());
6172
screen->priv->detachedFrameWindows.erase (it);
6175
if (!priv->destroyed)
6177
StackDebugger *dbg = StackDebugger::Default ();
6179
screen->unhookWindow (this);
6180
screen->unhookServerWindow (this);
6182
/* We must immediately insert the window into the debugging
6185
dbg->removeServerWindow (id ());
6187
/* restore saved geometry and map if hidden */
6188
if (!priv->attrib.override_redirect)
6191
XConfigureWindow (screen->dpy (), priv->id,
6192
priv->saveMask, &priv->saveWc);
6196
if (priv->state & CompWindowStateHiddenMask)
6197
XMapWindow (screen->dpy (), priv->id);
6201
if (screen->XShape ())
6202
XShapeSelectInput (screen->dpy (), priv->id, NoEventMask);
6204
if (priv->id != screen->priv->grabWindow)
6205
XSelectInput (screen->dpy (), priv->id, NoEventMask);
6207
XUngrabButton (screen->dpy (), AnyButton, AnyModifier, priv->id);
6211
if (priv->attrib.map_state == IsViewable)
6213
if (priv->type == CompWindowTypeDesktopMask)
6214
screen->priv->desktopWindowCount--;
6216
if (priv->destroyed && priv->struts)
6217
screen->updateWorkarea ();
6220
if (priv->destroyed)
6221
screen->priv->updateClientList ();
6223
CompPlugin::windowFiniPlugins (this);
6228
PrivateWindow::PrivateWindow () :
6237
transientFor (None),
6238
clientLeader (None),
6246
type (CompWindowTypeUnknownMask),
6250
mwmDecor (MwmDecorAll),
6251
mwmFunc (MwmFuncAll),
6259
initialViewport (0, 0),
6261
initialTimestamp (0),
6262
initialTimestampSet (false),
6264
fullscreenMonitorsSet (false),
6268
inShowDesktopMode (false),
6277
pendingPositionUpdates (false),
6299
closeRequests (false),
6300
lastCloseRequestTime (0)
6307
serverInput.left = 0;
6308
serverInput.right = 0;
6309
serverInput.top = 0;
6310
serverInput.bottom = 0;
6322
syncWaitTimer.setTimes (1000, 1200);
6323
syncWaitTimer.setCallback (boost::bind (&PrivateWindow::handleSyncAlarm,
6327
PrivateWindow::~PrivateWindow ()
6330
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
6332
syncWaitTimer.stop ();
6335
XDestroyWindow (screen->dpy (), serverFrame);
6337
XDestroyWindow (screen->dpy (), frame);
6359
CompWindow::syncWait ()
6361
return priv->syncWait;
6365
CompWindow::alpha ()
6367
WRAPABLE_HND_FUNC_RETURN (16, bool, alpha);
6373
CompWindow::overrideRedirect ()
6375
return priv->attrib.override_redirect;
6379
PrivateWindow::setOverrideRedirect (bool overrideRedirect)
6381
if (overrideRedirect == window->overrideRedirect ())
6384
priv->attrib.override_redirect = overrideRedirect ? 1 : 0;
6385
window->recalcType ();
6386
window->recalcActions ();
6388
screen->matchPropertyChanged (window);
6392
CompWindow::isMapped () const
6394
return priv->mapNum > 0;
6398
CompWindow::isViewable () const
6400
return (priv->attrib.map_state == IsViewable);
6404
CompWindow::isFocussable ()
6406
WRAPABLE_HND_FUNC_RETURN (17, bool, isFocussable);
6408
if (priv->inputHint)
6411
if (priv->protocols & CompWindowProtocolTakeFocusMask)
6418
CompWindow::windowClass ()
6420
return priv->attrib.c_class;
6424
CompWindow::depth ()
6426
return priv->attrib.depth;
6430
CompWindow::alive ()
6436
CompWindow::mwmDecor ()
6438
return priv->mwmDecor;
6442
CompWindow::mwmFunc ()
6444
return priv->mwmFunc;
6447
/* TODO: This function should be able to check the XShape event
6448
* kind and only get/set shape rectangles for either ShapeInput
6449
* or ShapeBounding, but not both at the same time
6453
CompWindow::updateFrameRegion ()
6455
if (priv->serverFrame &&
6456
priv->serverGeometry.width () == priv->geometry.width () &&
6457
priv->serverGeometry.height () == priv->geometry.height ())
6462
priv->frameRegion = CompRegion ();
6464
updateFrameRegion (priv->frameRegion);
6468
r = priv->region.boundingRect ();
6469
priv->frameRegion -= r;
6471
r.setGeometry (r.x1 () - priv->input.left,
6472
r.y1 () - priv->input.top,
6473
r.width () + priv->input.right + priv->input.left,
6474
r.height () + priv->input.bottom + priv->input.top);
6476
priv->frameRegion &= CompRegion (r);
6479
x = priv->geometry.x () - priv->input.left;
6480
y = priv->geometry.y () - priv->input.top;
6482
XShapeCombineRegion (screen->dpy (), priv->serverFrame,
6483
ShapeBounding, -x, -y,
6484
priv->frameRegion.united (priv->region).handle (),
6487
XShapeCombineRegion (screen->dpy (), priv->serverFrame,
6489
priv->frameRegion.united (priv->inputRegion).handle (),
6495
CompWindow::setWindowFrameExtents (CompWindowExtents *b,
6496
CompWindowExtents *i)
6498
/* Input extents are used for frame size,
6499
* Border extents used for placement.
6505
if (priv->serverInput.left != i->left ||
6506
priv->serverInput.right != i->right ||
6507
priv->serverInput.top != i->top ||
6508
priv->serverInput.bottom != i->bottom ||
6509
priv->border.left != b->left ||
6510
priv->border.right != b->right ||
6511
priv->border.top != b->top ||
6512
priv->border.bottom != b->bottom)
6514
unsigned long data[4];
6516
priv->serverInput = *i;
6521
/* Use b for _NET_WM_FRAME_EXTENTS here because
6522
* that is the representation of the actual decoration
6523
* around the window that the user sees and should
6524
* be used for placement and such */
6529
data[3] = b->bottom;
6531
XChangeProperty (screen->dpy (), priv->id,
6532
Atoms::frameExtents,
6533
XA_CARDINAL, 32, PropModeReplace,
6534
(unsigned char *) data, 4);
6536
priv->updateSize ();
6537
priv->updateFrameWindow ();
6542
CompWindow::hasUnmapReference ()
6544
return (priv && priv->unmapRefCnt > 1);
6548
CompWindow::updateFrameRegion (CompRegion& region)
6549
WRAPABLE_HND_FUNC (12, updateFrameRegion, region)
6552
PrivateWindow::reparent ()
6554
XSetWindowAttributes attr;
6555
XWindowAttributes wa;
6558
unsigned int nchildren;
6559
Window *children, root_return, parent_return;
6560
Display *dpy = screen->dpy ();
6561
Visual *visual = DefaultVisual (screen->dpy (),
6562
screen->screenNum ());
6563
Colormap cmap = DefaultColormap (screen->dpy (),
6564
screen->screenNum ());
6572
if (!XGetWindowAttributes (dpy, id, &wa))
6574
XUngrabServer (dpy);
6579
if (wa.override_redirect)
6582
XSelectInput (dpy, id, NoEventMask);
6584
/* Don't ever reparent windows which have ended up
6585
* reparented themselves on the server side but not
6586
* on the client side */
6588
XQueryTree (dpy, id, &root_return, &parent_return, &children, &nchildren);
6590
if (parent_return != root_return)
6593
XUngrabServer (dpy);
6600
XQueryTree (dpy, root_return, &root_return, &parent_return, &children, &nchildren);
6602
XChangeSaveSet (dpy, id, SetModeInsert);
6604
/* Force border width to 0 */
6605
xwc.border_width = 0;
6606
XConfigureWindow (dpy, id, CWBorderWidth, &xwc);
6608
priv->serverGeometry.setBorder (0);
6610
mask = CWBorderPixel | CWColormap | CWBackPixmap | CWOverrideRedirect;
6618
attr.background_pixmap = None;
6619
attr.border_pixel = 0;
6620
attr.colormap = cmap;
6621
attr.override_redirect = true;
6623
/* Look for existing detached frame windows and reattach them
6624
* in case this window as reparented again after being withdrawn */
6625
std::map <CompWindow *, CompWindow *>::iterator it =
6626
screen->priv->detachedFrameWindows.find (window);
6628
if (it != screen->priv->detachedFrameWindows.end ())
6630
/* Trash the old frame window
6631
* TODO: It would be nicer if we could just
6632
* reparent back into it, but there are some
6633
* problems with that */
6635
XDestroyWindow (dpy, (it->second)->id ());
6636
screen->priv->detachedFrameWindows.erase (it);
6639
/* We need to know when the frame window is created
6641
XSelectInput (dpy, screen->root (), SubstructureNotifyMask);
6643
/* Awaiting a new frame to be given to us */
6645
serverFrame = XCreateWindow (dpy, screen->root (), 0, 0,
6646
wa.width, wa.height, 0, wa.depth,
6647
InputOutput, visual, mask, &attr);
6649
/* Do not get any events from here on */
6650
XSelectInput (dpy, screen->root (), NoEventMask);
6652
wrapper = XCreateWindow (dpy, serverFrame, 0, 0,
6653
wa.width, wa.height, 0, wa.depth,
6654
InputOutput, visual, mask, &attr);
6656
xwc.stack_mode = Above;
6658
/* Look for the client in the current server side stacking
6659
* order and put the frame above what the client is above
6664
/* client at the bottom */
6665
xwc.stack_mode = Below;
6670
for (unsigned int i = 0; i < nchildren; i++)
6672
if (i < nchildren - 1)
6674
if (children[i + 1] == id)
6676
xwc.sibling = children[i];
6680
else /* client on top */
6681
xwc.sibling = children[i];
6687
/* Make sure the frame is underneath the client */
6688
XConfigureWindow (dpy, serverFrame, CWSibling | CWStackMode, &xwc);
6690
/* Wait for the restacking to finish */
6693
/* Always need to have the wrapper window mapped */
6694
XMapWindow (dpy, wrapper);
6696
/* Reparent the client into the wrapper window */
6697
XReparentWindow (dpy, id, wrapper, 0, 0);
6699
/* Restore events */
6700
attr.event_mask = wa.your_event_mask;
6702
/* We don't care about client events on the frame, and listening for them
6703
* will probably end up fighting the client anyways, so disable them */
6705
attr.do_not_propagate_mask = KeyPressMask | KeyReleaseMask |
6706
ButtonPressMask | ButtonReleaseMask |
6707
EnterWindowMask | LeaveWindowMask |
6708
PointerMotionMask | PointerMotionHintMask |
6709
Button1MotionMask | Button2MotionMask |
6710
Button3MotionMask | Button4MotionMask |
6711
Button5MotionMask | ButtonMotionMask |
6712
KeymapStateMask | ExposureMask |
6713
VisibilityChangeMask | StructureNotifyMask |
6714
ResizeRedirectMask | SubstructureNotifyMask |
6715
SubstructureRedirectMask | FocusChangeMask |
6716
PropertyChangeMask | ColormapChangeMask |
6717
OwnerGrabButtonMask;
6719
XChangeWindowAttributes (dpy, id, CWEventMask | CWDontPropagate, &attr);
6721
if (wa.map_state == IsViewable || shaded)
6722
XMapWindow (dpy, serverFrame);
6724
attr.event_mask = SubstructureRedirectMask |
6725
SubstructureNotifyMask | EnterWindowMask |
6728
serverFrameGeometry = serverGeometry;
6730
XMoveResizeWindow (dpy, serverFrame, serverFrameGeometry.x (), serverFrameGeometry.y (),
6731
serverFrameGeometry.width (), serverFrameGeometry.height ());
6733
XSelectInput (dpy, screen->root (),
6734
SubstructureRedirectMask |
6735
SubstructureNotifyMask |
6736
StructureNotifyMask |
6737
PropertyChangeMask |
6747
XChangeWindowAttributes (dpy, serverFrame, CWEventMask, &attr);
6748
XChangeWindowAttributes (dpy, wrapper, CWEventMask, &attr);
6750
XUngrabServer (dpy);
6753
window->windowNotify (CompWindowNotifyReparent);
6759
PrivateWindow::unreparent ()
6761
Display *dpy = screen->dpy ();
6765
unsigned int nchildren;
6766
Window *children = NULL, root_return, parent_return;
6767
XWindowAttributes wa;
6768
StackDebugger *dbg = StackDebugger::Default ();
6775
if (XCheckTypedWindowEvent (dpy, id, DestroyNotify, &e))
6777
XPutBackEvent (dpy, &e);
6782
if (!XGetWindowAttributes (dpy, id, &wa))
6786
/* Also don't reparent back into root windows that have ended up
6787
* reparented into other windows (and as such we are unmanaging them) */
6791
XQueryTree (dpy, id, &root_return, &parent_return, &children, &nchildren);
6793
if (parent_return != wrapper)
6797
if ((!destroyed) && alive)
6801
XChangeSaveSet (dpy, id, SetModeDelete);
6802
XSelectInput (dpy, serverFrame, NoEventMask);
6803
XSelectInput (dpy, wrapper, NoEventMask);
6804
XSelectInput (dpy, id, NoEventMask);
6805
XSelectInput (dpy, screen->root (), NoEventMask);
6806
XReparentWindow (dpy, id, screen->root (), 0, 0);
6808
/* Wait for the reparent to finish */
6811
xwc.x = serverGeometry.x () - serverGeometry.border ();
6812
xwc.y = serverGeometry.y () - serverGeometry.border ();
6813
xwc.width = serverGeometry.width () + serverGeometry.border () * 2;
6814
xwc.height = serverGeometry.height () + serverGeometry.border () * 2;
6816
XConfigureWindow (dpy, serverFrame, CWX | CWY | CWWidth | CWHeight, &xwc);
6819
xwc.stack_mode = Below;
6820
xwc.sibling = serverFrame;
6821
XConfigureWindow (dpy, id, CWSibling | CWStackMode, &xwc);
6823
/* Wait for the window to be restacked */
6826
XUnmapWindow (dpy, serverFrame);
6828
XSelectInput (dpy, id, wa.your_event_mask);
6830
XSelectInput (dpy, screen->root (),
6831
SubstructureRedirectMask |
6832
SubstructureNotifyMask |
6833
StructureNotifyMask |
6834
PropertyChangeMask |
6844
XUngrabServer (dpy);
6847
XMoveWindow (dpy, id, serverGeometry.x (), serverGeometry.y ());
6854
dbg->addDestroyedFrame (serverFrame);
6856
/* This is where things get tricky ... it is possible
6857
* to receive a ConfigureNotify relative to a frame window
6858
* for a destroyed window in case we process a ConfigureRequest
6859
* for the destroyed window and then a DestroyNotify for it directly
6860
* afterwards. In that case, we will receive the ConfigureNotify
6861
* for the XConfigureWindow request we made relative to that frame
6862
* window. Because of this, we must keep the frame window in the stack
6863
* as a new toplevel window so that the ConfigureNotify will be processed
6864
* properly until it too receives a DestroyNotify */
6868
XWindowAttributes attrib;
6870
/* It's possible that the frame window was already destroyed because
6871
* the client was unreparented before it was destroyed (eg
6872
* UnmapNotify before DestroyNotify). In that case the frame window
6873
* is going to be an invalid window but since we haven't received
6874
* a DestroyNotify for it yet, it is possible that restacking
6875
* operations could occurr relative to it so we need to hold it
6876
* in the stack for now. Ensure that it is marked override redirect */
6877
XGetWindowAttributes (screen->dpy (), serverFrame, &attrib);
6879
/* Put the frame window "above" the client window
6881
CoreWindow *cw = new CoreWindow (serverFrame);
6882
CompWindow *fw = cw->manage (id, attrib);
6883
screen->priv->createdWindows.remove (cw);
6886
/* Put this window in the list of "detached frame windows"
6887
* so that we can reattach it or destroy it when we are
6890
screen->priv->detachedFrameWindows[window] = fw;
6893
/* Safe to destroy the wrapper but not the frame */
6894
XUnmapWindow (screen->dpy (), serverFrame);
6895
XDestroyWindow (screen->dpy (), wrapper);
6901
window->windowNotify (CompWindowNotifyUnreparent);