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;
1429
priv->managed = false;
1432
priv->destroyRefCnt--;
1433
if (priv->destroyRefCnt)
1436
if (!priv->destroyed)
1438
if (!priv->serverFrame)
1440
StackDebugger *dbg = StackDebugger::Default ();
1443
dbg->addDestroyedFrame (priv->serverId);
1446
priv->destroyed = true;
1447
screen->priv->pendingDestroys++;
1453
CompWindow::sendConfigureNotify ()
1455
XConfigureEvent xev;
1456
XWindowAttributes attrib;
1457
unsigned int nchildren;
1458
Window rootRet, parentRet;
1461
xev.type = ConfigureNotify;
1462
xev.event = priv->id;
1463
xev.window = priv->id;
1465
/* in order to avoid race conditions we must use the current
1466
* server configuration */
1468
XGrabServer (screen->dpy ());
1469
XSync (screen->dpy (), false);
1471
if (XGetWindowAttributes (screen->dpy (), priv->id, &attrib))
1475
xev.width = attrib.width;
1476
xev.height = attrib.height;
1477
xev.border_width = attrib.border_width;
1482
XWindowAttributes fAttrib;
1483
XWindowAttributes wAttrib;
1485
/* Add offset between wrapper and client */
1486
if (XGetWindowAttributes (screen->dpy (), priv->wrapper, &wAttrib))
1492
/* Add offset between frame and client */
1493
if (XGetWindowAttributes (screen->dpy (), priv->frame, &fAttrib))
1500
/* We need to ensure that the stacking order is
1501
* based on the current server stacking order so
1502
* find the sibling to this window's frame in the
1503
* server side stack and stack above that */
1504
XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
1508
for (unsigned int i = 0; i < nchildren; i++)
1510
if (i + 1 == nchildren ||
1511
children[i + 1] == ROOTPARENT (this))
1513
xev.above = children[i];
1523
xev.above = (serverPrev) ? ROOTPARENT (serverPrev) : None;
1524
xev.override_redirect = priv->attrib.override_redirect;
1526
XSendEvent (screen->dpy (), priv->id, false,
1527
StructureNotifyMask, (XEvent *) &xev);
1530
XUngrabServer (screen->dpy ());
1531
XSync (screen->dpy (), false);
1537
windowNotify (CompWindowNotifyBeforeMap);
1541
if (priv->pendingMaps > 0)
1542
priv->pendingMaps = 0;
1544
priv->mapNum = screen->priv->mapNum++;
1547
screen->updateWorkarea ();
1549
if (windowClass () == InputOnly)
1552
priv->unmapRefCnt = 1;
1554
priv->attrib.map_state = IsViewable;
1556
if (!overrideRedirect ())
1557
screen->priv->setWmState (NormalState, priv->id);
1559
priv->invisible = true;
1562
priv->lastPong = screen->priv->lastPing;
1564
priv->updateRegion ();
1565
priv->updateSize ();
1567
screen->priv->updateClientList ();
1569
if (priv->type & CompWindowTypeDesktopMask)
1570
screen->priv->desktopWindowCount++;
1572
if (priv->protocols & CompWindowProtocolSyncRequestMask)
1575
sendConfigureNotify ();
1578
if (!overrideRedirect ())
1583
priv->geometry.setHeight (priv->geometry.height () + 1);
1584
resize (priv->geometry.x (), priv->geometry.y (), priv->geometry.width (),
1585
priv->geometry.height () - 1, priv->geometry.border ());
1590
windowNotify (CompWindowNotifyMap);
1594
CompWindow::incrementUnmapReference ()
1596
priv->unmapRefCnt++;
1600
CompWindow::unmap ()
1602
windowNotify (CompWindowNotifyBeforeUnmap);
1607
/* Even though we're still keeping the backing
1608
* pixmap of the window around, it's safe to
1609
* unmap the frame window since there's no use
1610
* for it at this point anyways and it just blocks
1613
XUnmapWindow (screen->dpy (), priv->wrapper);
1614
XUnmapWindow (screen->dpy (), priv->serverFrame);
1616
priv->unmapRefCnt--;
1617
if (priv->unmapRefCnt > 0)
1620
if (priv->unmanaging)
1624
int gravity = priv->sizeHints.win_gravity;
1626
/* revert gravity adjustment made at MapNotify time */
1627
xwc.x = priv->serverGeometry.x ();
1628
xwc.y = priv->serverGeometry.y ();
1632
xwcm = priv->adjustConfigureRequestForGravity (&xwc,
1637
configureXWindow (xwcm, &xwc);
1639
priv->unmanaging = false;
1642
if (priv->serverFrame)
1643
priv->unreparent ();
1646
screen->updateWorkarea ();
1648
if (priv->attrib.map_state != IsViewable)
1651
if (priv->type == CompWindowTypeDesktopMask)
1652
screen->priv->desktopWindowCount--;
1654
priv->attrib.map_state = IsUnmapped;
1656
priv->invisible = true;
1658
if (priv->shaded && priv->height)
1659
resize (priv->attrib.x, priv->attrib.y,
1660
priv->attrib.width, ++priv->attrib.height - 1,
1661
priv->attrib.border_width);
1663
screen->priv->updateClientList ();
1665
windowNotify (CompWindowNotifyUnmap);
1669
PrivateWindow::withdraw ()
1671
if (!attrib.override_redirect)
1672
screen->priv->setWmState (WithdrawnState, id);
1675
unmanaging = managed;
1680
PrivateWindow::restack (Window aboveId)
1682
if (aboveId && (aboveId == id || aboveId == serverFrame))
1683
// Don't try to raise a window above itself
1685
else if (window->prev)
1687
if (aboveId && (aboveId == window->prev->id () ||
1688
aboveId == window->prev->priv->frame))
1691
else if (aboveId == None && !window->next)
1694
if (aboveId && !screen->findTopLevelWindow (aboveId, true))
1699
screen->unhookWindow (window);
1700
screen->insertWindow (window, aboveId);
1702
/* Update the server side window list for
1703
* override redirect windows immediately
1704
* since there is no opportunity to update
1705
* the server side list when we configure them
1706
* since we never get a ConfigureRequest for those */
1707
if (attrib.override_redirect != 0)
1709
StackDebugger *dbg = StackDebugger::Default ();
1711
screen->unhookServerWindow (window);
1712
screen->insertServerWindow (window, aboveId);
1715
dbg->overrideRedirectRestack (window->id (), aboveId);
1718
screen->priv->updateClientList ();
1720
window->windowNotify (CompWindowNotifyRestack);
1726
CompWindow::resize (XWindowAttributes attr)
1728
return resize (Geometry (attr.x, attr.y, attr.width, attr.height,
1729
attr.border_width));
1733
CompWindow::resize (int x,
1739
return resize (Geometry (x, y, width, height, border));
1743
CompWindow::resize (CompWindow::Geometry gm)
1745
/* Input extents are now the last thing sent
1746
* from the server. This might not work in some
1747
* cases though because setWindowFrameExtents may
1748
* be called more than once in an event processing
1749
* cycle so every set of input extents up until the
1750
* last one will be invalid. The real solution
1751
* here is to handle ConfigureNotify events on
1752
* frame windows and client windows separately */
1754
priv->input = priv->serverInput;
1756
if (priv->geometry.width () != gm.width () ||
1757
priv->geometry.height () != gm.height () ||
1758
priv->geometry.border () != gm.border ())
1761
int dx, dy, dwidth, dheight;
1763
pw = gm.width () + gm.border () * 2;
1764
ph = gm.height () + gm.border () * 2;
1769
dx = gm.x () - priv->geometry.x ();
1770
dy = gm.y () - priv->geometry.y ();
1771
dwidth = gm.width () - priv->geometry.width ();
1772
dheight = gm.height () - priv->geometry.height ();
1774
priv->geometry.set (gm.x (), gm.y (),
1775
gm.width (), gm.height (),
1782
priv->updateRegion ();
1784
resizeNotify (dx, dy, dwidth, dheight);
1786
priv->invisible = WINDOW_INVISIBLE (priv);
1788
else if (priv->geometry.x () != gm.x () || priv->geometry.y () != gm.y ())
1792
dx = gm.x () - priv->geometry.x ();
1793
dy = gm.y () - priv->geometry.y ();
1795
priv->geometry.setX (gm.x ());
1796
priv->geometry.setY (gm.y ());
1798
priv->region.translate (dx, dy);
1799
priv->inputRegion.translate (dx, dy);
1800
if (!priv->frameRegion.isEmpty ())
1801
priv->frameRegion.translate (dx, dy);
1803
priv->invisible = WINDOW_INVISIBLE (priv);
1805
moveNotify (dx, dy, true);
1808
updateFrameRegion ();
1814
syncValueIncrement (XSyncValue *value)
1819
XSyncIntToValue (&one, 1);
1820
XSyncValueAdd (value, *value, one, &overflow);
1824
PrivateWindow::initializeSyncCounter ()
1826
XSyncAlarmAttributes values;
1829
unsigned long n, left;
1830
unsigned char *data;
1833
return syncAlarm != None;
1835
if (!(protocols & CompWindowProtocolSyncRequestMask))
1838
result = XGetWindowProperty (screen->dpy (), id,
1839
Atoms::wmSyncRequestCounter,
1840
0L, 1L, false, XA_CARDINAL, &actual, &format,
1843
if (result == Success && n && data)
1845
unsigned long *counter = (unsigned long *) data;
1847
syncCounter = *counter;
1851
XSyncIntsToValue (&syncValue, (unsigned int) rand (), 0);
1852
XSyncSetCounter (screen->dpy (),
1856
syncValueIncrement (&syncValue);
1858
values.events = true;
1860
values.trigger.counter = syncCounter;
1861
values.trigger.wait_value = syncValue;
1863
values.trigger.value_type = XSyncAbsolute;
1864
values.trigger.test_type = XSyncPositiveComparison;
1866
XSyncIntToValue (&values.delta, 1);
1868
values.events = true;
1870
CompScreen::checkForError (screen->dpy ());
1872
/* Note that by default, the alarm increments the trigger value
1873
* when it fires until the condition (counter.value < trigger.value)
1876
syncAlarm = XSyncCreateAlarm (screen->dpy (),
1885
if (CompScreen::checkForError (screen->dpy ()))
1888
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
1891
else if (result == Success && data)
1900
CompWindow::sendSyncRequest ()
1902
XClientMessageEvent xev;
1907
if (!priv->initializeSyncCounter ())
1910
xev.type = ClientMessage;
1911
xev.window = priv->id;
1912
xev.message_type = Atoms::wmProtocols;
1914
xev.data.l[0] = Atoms::wmSyncRequest;
1915
xev.data.l[1] = CurrentTime;
1916
xev.data.l[2] = XSyncValueLow32 (priv->syncValue);
1917
xev.data.l[3] = XSyncValueHigh32 (priv->syncValue);
1920
syncValueIncrement (&priv->syncValue);
1922
XSendEvent (screen->dpy (), priv->id, false, 0, (XEvent *) &xev);
1924
priv->syncWait = true;
1925
priv->syncGeometry = priv->serverGeometry;
1927
if (!priv->syncWaitTimer.active ())
1928
priv->syncWaitTimer.start ();
1932
PrivateWindow::configure (XConfigureEvent *ce)
1934
unsigned int valueMask = 0;
1939
/* remove configure event from pending configures */
1940
if (priv->geometry.x () != ce->x)
1943
if (priv->geometry.y () != ce->y)
1946
if (priv->geometry.width () != ce->width)
1947
valueMask |= CWWidth;
1949
if (priv->geometry.height () != ce->height)
1950
valueMask |= CWHeight;
1952
if (priv->geometry.border () != ce->border_width)
1953
valueMask |= CWBorderWidth;
1955
if (ROOTPARENT (window->prev) != ce->above)
1956
valueMask |= CWSibling | CWStackMode;
1958
priv->attrib.override_redirect = ce->override_redirect;
1960
priv->frameGeometry.set (ce->x, ce->y, ce->width,
1961
ce->height, ce->border_width);
1964
priv->syncGeometry.set (ce->x, ce->y, ce->width, ce->height,
1968
if (ce->override_redirect)
1970
priv->serverGeometry.set (ce->x, ce->y, ce->width, ce->height,
1974
window->resize (ce->x, ce->y, ce->width, ce->height, ce->border_width);
1977
if (ce->event == screen->root ())
1978
priv->restack (ce->above);
1982
PrivateWindow::configureFrame (XConfigureEvent *ce)
1984
int x, y, width, height;
1986
unsigned int valueMask = 0;
1987
bool handled = false;
1992
/* remove configure event from pending configures */
1993
if (priv->frameGeometry.x () != ce->x)
1996
if (priv->frameGeometry.y () != ce->y)
1999
if (priv->frameGeometry.width () != ce->width)
2000
valueMask |= CWWidth;
2002
if (priv->frameGeometry.height () != ce->height)
2003
valueMask |= CWHeight;
2005
if (priv->frameGeometry.border () != ce->border_width)
2006
valueMask |= CWBorderWidth;
2010
if (ROOTPARENT (window->prev) != ce->above)
2011
valueMask |= CWSibling | CWStackMode;
2016
valueMask |= CWSibling | CWStackMode;
2019
for (std::list <XWCValueMask>::iterator it = pendingConfigures.begin ();
2020
it != pendingConfigures.end (); it++)
2022
XWCValueMask &xwcvm = (*it);
2025
if (xwcvm.second != valueMask)
2027
/* For stacking cases, if a client wants to raise or lower a window
2028
* then they don't need to specify CWSibling, so allow that to be
2029
* excluded in those cases */
2031
if (ce->above == ROOTPARENT (screen->windows ().back ()) ||
2034
if ((xwcvm.second & ~(CWSibling)) != valueMask)
2041
if (xwcvm.second & CWX && xwcvm.first.x != ce->x)
2044
if (xwcvm.second & CWY && xwcvm.first.y != ce->y)
2047
if (xwcvm.second & CWWidth && xwcvm.first.width != ce->width)
2050
if (xwcvm.second & CWHeight && xwcvm.first.height != ce->height)
2053
if (xwcvm.second & (CWStackMode | CWSibling) && xwcvm.first.sibling != ce->above)
2056
/* Matched ConfigureWindow request to ConfigureNotify event
2057
* remove it from the list */
2061
pendingConfigures.erase (it);
2067
compLogMessage ("core", CompLogLevelWarn, "unhandled ConfigureNotify on 0x%x!", serverFrame);
2068
compLogMessage ("core", CompLogLevelWarn, "this should never happen. you should"\
2069
"probably file a bug about this.");
2073
pendingConfigures.clear ();
2077
/* subtract the input extents last sent to the
2078
* server to calculate the client size and then
2079
* re-sync the input extents and extents last
2080
* sent to server on resize () */
2082
x = ce->x + priv->serverInput.left;
2083
y = ce->y + priv->serverInput.top;
2084
width = ce->width - priv->serverGeometry.border () * 2 - priv->serverInput.left - priv->serverInput.right;
2085
height = ce->height - priv->serverGeometry.border () * 2 - priv->serverInput.top - priv->serverInput.bottom;
2087
/* set the frame geometry */
2088
priv->frameGeometry.set (ce->x, ce->y, ce->width, ce->height, ce->border_width);
2092
priv->syncGeometry.set (x, y, width, height, ce->border_width);
2094
window->resize (x, y, width, height, ce->border_width);
2096
if (priv->restack (ce->above))
2097
priv->updatePassiveButtonGrabs ();
2099
above = screen->findWindow (ce->above);
2102
above->priv->updatePassiveButtonGrabs ();
2104
if (pendingConfigures.empty ())
2106
/* Tell plugins its ok to start doing stupid things again but
2107
* obviously FIXME */
2108
CompOption::Vector options;
2109
CompOption::Value v;
2111
options.push_back (CompOption ("window", CompOption::TypeInt));
2113
options.back ().set (v);
2114
options.push_back (CompOption ("active", CompOption::TypeInt));
2116
options.back ().set (v);
2118
/* Notify other plugins that it is unsafe to change geometry or serverGeometry
2119
* FIXME: That API should not be accessible to plugins, this is a hack to avoid
2122
screen->handleCompizEvent ("core", "lock_position", options);
2127
PrivateWindow::circulate (XCirculateEvent *ce)
2131
if (ce->place == PlaceOnTop)
2132
newAboveId = screen->priv->getTopWindow ();
2136
priv->restack (newAboveId);
2140
CompWindow::move (int dx,
2146
/* Don't allow window movement to overwrite working geometries
2147
* last received from the server if we know there are pending
2148
* ConfigureNotify events on this window. That's a clunky workaround
2149
* and a FIXME in any case, however, until we can break the API
2150
* and remove CompWindow::move, this will need to be the case */
2152
if (!priv->pendingConfigures.size ())
2154
priv->geometry.setX (priv->geometry.x () + dx);
2155
priv->geometry.setY (priv->geometry.y () + dy);
2156
priv->frameGeometry.setX (priv->frameGeometry.x () + dx);
2157
priv->frameGeometry.setY (priv->frameGeometry.y () + dy);
2159
priv->pendingPositionUpdates = true;
2161
priv->region.translate (dx, dy);
2162
priv->inputRegion.translate (dx, dy);
2163
if (!priv->frameRegion.isEmpty ())
2164
priv->frameRegion.translate (dx, dy);
2166
priv->invisible = WINDOW_INVISIBLE (priv);
2168
moveNotify (dx, dy, immediate);
2173
unsigned int valueMask = CWX | CWY;
2174
struct timeval tv, old;
2175
compLogMessage ("core", CompLogLevelDebug, "pending configure notifies on 0x%x,"\
2176
"moving window asyncrhonously!", (unsigned int) priv->serverId);
2178
old = priv->lastConfigureRequest;
2179
gettimeofday (&tv, NULL);
2181
xwc.x = priv->serverGeometry.x () + dx;
2182
xwc.y = priv->serverGeometry.y () + dy;
2184
configureXWindow (valueMask, &xwc);
2186
priv->lastConfigureRequest = old;
2188
/* FIXME: This is a hack to avoid performance regressions
2189
* and must be removed in 0.9.6 */
2190
if (tv.tv_usec - priv->lastConfigureRequest.tv_usec > 300000)
2192
compLogMessage ("core", CompLogLevelWarn, "failed to receive ConfigureNotify event from request at %i (now: %i)\n",
2193
priv->lastConfigureRequest.tv_usec, tv.tv_usec);
2194
priv->pendingConfigures.clear ();
2201
PrivateWindow::addPendingConfigure (XWindowChanges &xwc, unsigned int valueMask)
2203
CompOption::Vector options;
2204
CompOption::Value v;
2206
options.push_back (CompOption ("window", CompOption::TypeInt));
2208
options.back ().set (v);
2209
options.push_back (CompOption ("active", CompOption::TypeInt));
2211
options.back ().set (v);
2213
gettimeofday (&lastConfigureRequest, NULL);
2215
/* Notify other plugins that it is unsafe to change geometry or serverGeometry
2216
* FIXME: That API should not be accessible to plugins, this is a hack to avoid
2219
screen->handleCompizEvent ("core", "lock_position", options);
2221
priv->pendingConfigures.push_back (XWCValueMask (xwc, valueMask));
2225
CompWindow::syncPosition ()
2227
unsigned int valueMask = CWX | CWY;
2230
if (priv->pendingPositionUpdates && priv->pendingConfigures.empty ())
2232
if (priv->serverFrameGeometry.x () == priv->frameGeometry.x ())
2233
valueMask &= ~(CWX);
2234
if (priv->serverFrameGeometry.y () == priv->frameGeometry.y ())
2235
valueMask &= ~(CWY);
2237
/* Because CompWindow::move can update the geometry last
2238
* received from the server, we must indicate that no values
2239
* changed, because when the ConfigureNotify comes around
2240
* the values are going to be the same. That's obviously
2241
* broken behaviour and worthy of a FIXME, but requires
2242
* larger changes to the window movement system. */
2245
priv->addPendingConfigure (xwc, 0);
2247
priv->serverGeometry.setX (priv->geometry.x ());
2248
priv->serverGeometry.setY (priv->geometry.y ());
2249
priv->serverFrameGeometry.setX (priv->frameGeometry.x ());
2250
priv->serverFrameGeometry.setY (priv->frameGeometry.y ());
2252
xwc.x = priv->serverFrameGeometry.x ();
2253
xwc.y = priv->serverFrameGeometry.y ();
2255
XConfigureWindow (screen->dpy (), ROOTPARENT (this), valueMask, &xwc);
2257
if (priv->serverFrame)
2259
XMoveWindow (screen->dpy (), priv->wrapper,
2260
priv->serverInput.left, priv->serverInput.top);
2261
sendConfigureNotify ();
2264
priv->pendingPositionUpdates = false;
2269
CompWindow::focus ()
2271
WRAPABLE_HND_FUNC_RETURN (2, bool, focus)
2273
if (overrideRedirect ())
2276
if (!priv->managed || priv->unmanaging)
2279
if (!onCurrentDesktop ())
2282
if (priv->destroyed)
2285
if (!priv->shaded && (priv->state & CompWindowStateHiddenMask))
2288
if (priv->geometry.x () + priv->width <= 0 ||
2289
priv->geometry.y () + priv->height <= 0 ||
2290
priv->geometry.x () >= (int) screen->width ()||
2291
priv->geometry.y () >= (int) screen->height ())
2298
CompWindow::place (CompPoint &pos)
2300
WRAPABLE_HND_FUNC_RETURN (4, bool, place, pos)
2305
CompWindow::validateResizeRequest (unsigned int &mask,
2306
XWindowChanges *xwc,
2307
unsigned int source)
2309
WRAPABLE_HND_FUNC (5, validateResizeRequest, mask, xwc, source)
2311
if (!(priv->type & (CompWindowTypeDockMask |
2312
CompWindowTypeFullscreenMask |
2313
CompWindowTypeUnknownMask)))
2319
min = screen->workArea ().y () + priv->input.top;
2320
max = screen->workArea ().bottom ();
2322
if (priv->state & CompWindowStateStickyMask &&
2323
(xwc->y < min || xwc->y > max))
2325
xwc->y = priv->serverGeometry.y ();
2329
min -= screen->vp ().y () * screen->height ();
2330
max += (screen->vpSize ().height () - screen->vp ().y () - 1) *
2335
else if (xwc->y > max)
2344
min = screen->workArea ().x () + priv->input.left;
2345
max = screen->workArea ().right ();
2347
if (priv->state & CompWindowStateStickyMask &&
2348
(xwc->x < min || xwc->x > max))
2350
xwc->x = priv->serverGeometry.x ();
2354
min -= screen->vp ().x () * screen->width ();
2355
max += (screen->vpSize ().width () - screen->vp ().x () - 1) *
2360
else if (xwc->x > max)
2368
CompWindow::resizeNotify (int dx,
2372
WRAPABLE_HND_FUNC (6, resizeNotify, dx, dy, dwidth, dheight)
2375
CompWindow::moveNotify (int dx,
2378
WRAPABLE_HND_FUNC (7, moveNotify, dx, dy, immediate)
2381
CompWindow::windowNotify (CompWindowNotify n)
2382
WRAPABLE_HND_FUNC (8, windowNotify, n)
2385
CompWindow::grabNotify (int x,
2390
WRAPABLE_HND_FUNC (9, grabNotify, x, y, state, mask)
2391
priv->grabbed = true;
2395
CompWindow::ungrabNotify ()
2397
WRAPABLE_HND_FUNC (10, ungrabNotify)
2398
priv->grabbed = false;
2402
CompWindow::stateChangeNotify (unsigned int lastState)
2404
WRAPABLE_HND_FUNC (11, stateChangeNotify, lastState);
2406
/* if being made sticky */
2407
if (!(lastState & CompWindowStateStickyMask) &&
2408
(priv->state & CompWindowStateStickyMask))
2410
CompPoint vp; /* index of the window's vp */
2412
/* Find which viewport the window falls in,
2413
and check if it's the current viewport */
2414
vp = defaultViewport ();
2415
if (screen->vp () != vp)
2417
unsigned int valueMask = CWX | CWY;
2420
xwc.x = serverGeometry ().x () + (screen->vp ().x () - vp.x ()) * screen->width ();
2421
xwc.y = serverGeometry ().y () + (screen->vp ().y () - vp.y ()) * screen->height ();
2423
configureXWindow (valueMask, &xwc);
2430
PrivateWindow::isGroupTransient (Window clientLeader)
2435
if (transientFor == None || transientFor == screen->root ())
2437
if (type & (CompWindowTypeUtilMask |
2438
CompWindowTypeToolbarMask |
2439
CompWindowTypeMenuMask |
2440
CompWindowTypeDialogMask |
2441
CompWindowTypeModalDialogMask))
2443
if (this->clientLeader == clientLeader)
2452
PrivateWindow::getModalTransient ()
2454
CompWindow *w, *modalTransient;
2456
modalTransient = window;
2458
for (w = screen->windows ().back (); w; w = w->prev)
2460
if (w == modalTransient || w->priv->mapNum == 0)
2463
if (w->priv->transientFor == modalTransient->priv->id)
2465
if (w->priv->state & CompWindowStateModalMask)
2468
w = screen->windows ().back ();
2473
if (modalTransient == window)
2475
/* don't look for group transients with modal state if current window
2477
if (state & CompWindowStateModalMask)
2480
for (w = screen->windows ().back (); w; w = w->prev)
2482
if (w == modalTransient || w->priv->mapNum == 0)
2485
if (isAncestorTo (modalTransient, w))
2488
if (w->priv->isGroupTransient (modalTransient->priv->clientLeader))
2490
if (w->priv->state & CompWindowStateModalMask)
2493
w = w->priv->getModalTransient ();
2503
if (modalTransient == window)
2504
modalTransient = NULL;
2506
return modalTransient;
2510
CompWindow::moveInputFocusTo ()
2512
CompScreen *s = screen;
2513
CompWindow *modalTransient;
2515
modalTransient = priv->getModalTransient ();
2517
return modalTransient->moveInputFocusTo ();
2519
/* If the window is still hidden but not shaded
2520
* it probably meant that a plugin overloaded
2521
* CompWindow::focus to allow the focus to go
2522
* to this window, so only move the input focus
2523
* to the frame if the window is shaded */
2526
XSetInputFocus (s->dpy (), priv->serverFrame,
2527
RevertToPointerRoot, CurrentTime);
2528
XChangeProperty (s->dpy (), s->root (), Atoms::winActive,
2529
XA_WINDOW, 32, PropModeReplace,
2530
(unsigned char *) &priv->id, 1);
2534
bool setFocus = false;
2536
if (priv->inputHint)
2538
XSetInputFocus (s->dpy (), priv->id, RevertToPointerRoot,
2543
if (priv->protocols & CompWindowProtocolTakeFocusMask)
2547
ev.type = ClientMessage;
2548
ev.xclient.window = priv->id;
2549
ev.xclient.message_type = Atoms::wmProtocols;
2550
ev.xclient.format = 32;
2551
ev.xclient.data.l[0] = Atoms::wmTakeFocus;
2552
ev.xclient.data.l[1] = s->getCurrentTime ();
2553
ev.xclient.data.l[2] = 0;
2554
ev.xclient.data.l[3] = 0;
2555
ev.xclient.data.l[4] = 0;
2557
XSendEvent (s->dpy (), priv->id, false, NoEventMask, &ev);
2564
CompWindowList dockWindows;
2568
screen->priv->nextActiveWindow = priv->id;
2570
/* Ensure that docks are stacked in the right place
2572
* When a normal window gets the focus and is above a
2573
* fullscreen window, restack the docks to be above
2574
* the highest level mapped and visible normal window,
2575
* otherwise put them above the highest fullscreen window
2577
if (PrivateWindow::stackDocks (this, dockWindows, &xwc, &mask))
2579
Window sibling = xwc.sibling;
2580
xwc.stack_mode = Above;
2582
/* Then update the dock windows */
2583
foreach (CompWindow *dw, dockWindows)
2585
xwc.sibling = sibling;
2586
dw->configureXWindow (mask, &xwc);
2591
if (!setFocus && !modalTransient)
2593
CompWindow *ancestor;
2595
/* move input to closest ancestor */
2596
for (ancestor = s->windows ().front (); ancestor;
2597
ancestor = ancestor->next)
2599
if (PrivateWindow::isAncestorTo (this, ancestor))
2601
ancestor->moveInputFocusTo ();
2610
CompWindow::moveInputFocusToOtherWindow ()
2612
if (priv->id == screen->activeWindow () ||
2613
priv->id == screen->priv->nextActiveWindow)
2615
CompWindow *ancestor;
2617
if (priv->transientFor && priv->transientFor != screen->root ())
2619
ancestor = screen->findWindow (priv->transientFor);
2621
ancestor->focus () &&
2622
!(ancestor->priv->type & (CompWindowTypeDesktopMask |
2623
CompWindowTypeDockMask)))
2625
ancestor->moveInputFocusTo ();
2628
screen->focusDefaultWindow ();
2630
else if (priv->type & (CompWindowTypeDialogMask |
2631
CompWindowTypeModalDialogMask))
2633
CompWindow *a, *focus = NULL;
2635
for (a = screen->windows ().back (); a; a = a->prev)
2637
if (a->priv->clientLeader == priv->clientLeader)
2643
if (a->priv->type & (CompWindowTypeNormalMask |
2644
CompWindowTypeDialogMask |
2645
CompWindowTypeModalDialogMask))
2647
if (priv->compareWindowActiveness (focus, a) < 0)
2657
if (focus && !(focus->priv->type & (CompWindowTypeDesktopMask |
2658
CompWindowTypeDockMask)))
2660
focus->moveInputFocusTo ();
2663
screen->focusDefaultWindow ();
2666
screen->focusDefaultWindow ();
2672
PrivateWindow::stackLayerCheck (CompWindow *w,
2673
Window clientLeader,
2676
if (isAncestorTo (w, below))
2679
if (isAncestorTo (below, w))
2682
if (clientLeader && below->priv->clientLeader == clientLeader)
2683
if (below->priv->isGroupTransient (clientLeader))
2686
if (w->priv->state & CompWindowStateAboveMask)
2690
else if (w->priv->state & CompWindowStateBelowMask)
2692
if (below->priv->state & CompWindowStateBelowMask)
2695
else if (!(below->priv->state & CompWindowStateAboveMask))
2704
PrivateWindow::avoidStackingRelativeTo (CompWindow *w)
2706
if (w->overrideRedirect ())
2709
if (w->destroyed ())
2712
if (!w->priv->shaded && !w->priv->pendingMaps)
2714
if (!w->isViewable () || !w->isMapped ())
2721
/* goes through the stack, top-down until we find a window we should
2722
stack above, normal windows can be stacked above fullscreen windows
2723
(and fullscreen windows over others in their layer) if aboveFs is true. */
2725
PrivateWindow::findSiblingBelow (CompWindow *w,
2729
CompWindow *t = screen->findWindow (w->transientFor ());
2730
Window clientLeader = w->priv->clientLeader;
2731
unsigned int type = w->priv->type;
2732
unsigned int belowMask;
2735
belowMask = CompWindowTypeDockMask;
2737
belowMask = CompWindowTypeDockMask | CompWindowTypeFullscreenMask;
2739
/* normal stacking of fullscreen windows with below state */
2740
if ((type & CompWindowTypeFullscreenMask) &&
2741
(w->priv->state & CompWindowStateBelowMask))
2742
type = CompWindowTypeNormalMask;
2744
while (t && type != CompWindowTypeDockMask)
2746
/* dock stacking of transients for docks */
2747
if (t->type () & CompWindowTypeDockMask)
2748
type = CompWindowTypeDockMask;
2750
t = screen->findWindow (t->transientFor ());
2753
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2754
clientLeader = None;
2756
for (below = screen->serverWindows ().back (); below;
2757
below = below->serverPrev)
2759
if (below == w || avoidStackingRelativeTo (below))
2762
/* always above desktop windows */
2763
if (below->priv->type & CompWindowTypeDesktopMask)
2767
case CompWindowTypeDesktopMask:
2768
/* desktop window layer */
2770
case CompWindowTypeFullscreenMask:
2773
/* otherwise fall-through */
2774
case CompWindowTypeDockMask:
2775
/* fullscreen and dock layer */
2776
if (below->priv->type & (CompWindowTypeFullscreenMask |
2777
CompWindowTypeDockMask))
2779
if (stackLayerCheck (w, clientLeader, below))
2789
bool allowedRelativeToLayer = !(below->priv->type & belowMask);
2791
t = screen->findWindow (below->transientFor ());
2793
while (t && allowedRelativeToLayer)
2795
/* dock stacking of transients for docks */
2796
allowedRelativeToLayer = !(t->priv->type & belowMask);
2798
t = screen->findWindow (t->transientFor ());
2801
/* fullscreen and normal layer */
2802
if (allowedRelativeToLayer)
2804
if (stackLayerCheck (w, clientLeader, below))
2815
/* goes through the stack, top-down and returns the lowest window we
2818
PrivateWindow::findLowestSiblingBelow (CompWindow *w)
2820
CompWindow *below, *lowest = screen->serverWindows ().back ();
2821
CompWindow *t = screen->findWindow (w->transientFor ());
2822
Window clientLeader = w->priv->clientLeader;
2823
unsigned int type = w->priv->type;
2825
/* normal stacking fullscreen windows with below state */
2826
if ((type & CompWindowTypeFullscreenMask) &&
2827
(w->priv->state & CompWindowStateBelowMask))
2828
type = CompWindowTypeNormalMask;
2830
while (t && type != CompWindowTypeDockMask)
2832
/* dock stacking of transients for docks */
2833
if (t->type () & CompWindowTypeDockMask)
2834
type = CompWindowTypeDockMask;
2836
t = screen->findWindow (t->transientFor ());
2840
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2841
clientLeader = None;
2843
for (below = screen->serverWindows ().back (); below;
2844
below = below->serverPrev)
2846
if (below == w || avoidStackingRelativeTo (below))
2849
/* always above desktop windows */
2850
if (below->priv->type & CompWindowTypeDesktopMask)
2854
case CompWindowTypeDesktopMask:
2855
/* desktop window layer - desktop windows always should be
2856
stacked at the bottom; no other window should be below them */
2859
case CompWindowTypeFullscreenMask:
2860
case CompWindowTypeDockMask:
2861
/* fullscreen and dock layer */
2862
if (below->priv->type & (CompWindowTypeFullscreenMask |
2863
CompWindowTypeDockMask))
2865
if (!stackLayerCheck (below, clientLeader, w))
2875
bool allowedRelativeToLayer = !(below->priv->type & CompWindowTypeDockMask);
2877
t = screen->findWindow (below->transientFor ());
2879
while (t && allowedRelativeToLayer)
2881
/* dock stacking of transients for docks */
2882
allowedRelativeToLayer = !(t->priv->type & CompWindowTypeDockMask);
2884
t = screen->findWindow (t->transientFor ());
2887
/* fullscreen and normal layer */
2888
if (allowedRelativeToLayer)
2890
if (!stackLayerCheck (below, clientLeader, w))
2904
PrivateWindow::validSiblingBelow (CompWindow *w,
2905
CompWindow *sibling)
2907
CompWindow *t = screen->findWindow (w->transientFor ());
2908
Window clientLeader = w->priv->clientLeader;
2909
unsigned int type = w->priv->type;
2911
/* normal stacking fullscreen windows with below state */
2912
if ((type & CompWindowTypeFullscreenMask) &&
2913
(w->priv->state & CompWindowStateBelowMask))
2914
type = CompWindowTypeNormalMask;
2916
while (t && type != CompWindowTypeDockMask)
2918
/* dock stacking of transients for docks */
2919
if (t->type () & CompWindowTypeDockMask)
2920
type = CompWindowTypeDockMask;
2922
t = screen->findWindow (t->transientFor ());
2926
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2927
clientLeader = None;
2929
if (sibling == w || avoidStackingRelativeTo (sibling))
2932
/* always above desktop windows */
2933
if (sibling->priv->type & CompWindowTypeDesktopMask)
2937
case CompWindowTypeDesktopMask:
2938
/* desktop window layer */
2940
case CompWindowTypeFullscreenMask:
2941
case CompWindowTypeDockMask:
2942
/* fullscreen and dock layer */
2943
if (sibling->priv->type & (CompWindowTypeFullscreenMask |
2944
CompWindowTypeDockMask))
2946
if (stackLayerCheck (w, clientLeader, sibling))
2956
bool allowedRelativeToLayer = !(sibling->priv->type & CompWindowTypeDockMask);
2958
t = screen->findWindow (sibling->transientFor ());
2960
while (t && allowedRelativeToLayer)
2962
/* dock stacking of transients for docks */
2963
allowedRelativeToLayer = !(t->priv->type & CompWindowTypeDockMask);
2965
t = screen->findWindow (t->transientFor ());
2968
/* fullscreen and normal layer */
2969
if (allowedRelativeToLayer)
2971
if (stackLayerCheck (w, clientLeader, sibling))
2982
PrivateWindow::saveGeometry (int mask)
2984
int m = mask & ~saveMask;
2986
/* only save geometry if window has been placed */
2991
saveWc.x = serverGeometry.x ();
2994
saveWc.y = serverGeometry.y ();
2997
saveWc.width = serverGeometry.width ();
3000
saveWc.height = serverGeometry.height ();
3002
if (m & CWBorderWidth)
3003
saveWc.border_width = serverGeometry.border ();
3009
PrivateWindow::restoreGeometry (XWindowChanges *xwc,
3012
int m = mask & saveMask;
3022
xwc->width = saveWc.width;
3024
/* This is not perfect but it works OK for now. If the saved width is
3025
the same as the current width then make it a little be smaller so
3026
the user can see that it changed and it also makes sure that
3027
windowResizeNotify is called and plugins are notified. */
3028
if (xwc->width == (int) serverGeometry.width ())
3038
xwc->height = saveWc.height;
3040
/* As above, if the saved height is the same as the current height
3041
then make it a little be smaller. */
3042
if (xwc->height == (int) serverGeometry.height ())
3050
if (m & CWBorderWidth)
3051
xwc->border_width = saveWc.border_width;
3059
PrivateWindow::reconfigureXWindow (unsigned int valueMask,
3060
XWindowChanges *xwc)
3062
unsigned int frameValueMask = valueMask;
3064
/* Immediately sync window position
3065
* if plugins were updating w->geometry () directly
3066
* in order to avoid a race condition */
3068
window->syncPosition ();
3070
/* Remove redundant bits */
3072
if (serverGeometry.x () == xwc->x)
3073
valueMask &= ~(CWX);
3075
if (serverGeometry.y () == xwc->y)
3076
valueMask &= ~(CWY);
3078
if (serverGeometry.width () == xwc->width)
3079
valueMask &= ~(CWWidth);
3081
if (serverGeometry.height () == xwc->height)
3082
valueMask &= ~(CWHeight);
3084
if (serverGeometry.border () == xwc->border_width)
3085
valueMask &= ~(CWBorderWidth);
3087
if (window->serverPrev && ROOTPARENT (window->serverPrev) == xwc->sibling)
3089
/* check if the sibling is also pending a restack,
3090
* if not, then setting this bit is useless */
3092
bool pendingRestack = false;
3094
foreach (XWCValueMask &xwcvm, window->serverPrev->priv->pendingConfigures)
3096
if (xwcvm.second & (CWSibling | CWStackMode))
3098
pendingRestack = true;
3103
if (!pendingRestack)
3104
valueMask &= ~(CWSibling | CWStackMode);
3107
if (valueMask & CWBorderWidth)
3108
serverGeometry.setBorder (xwc->border_width);
3110
if (valueMask & CWX)
3111
serverGeometry.setX (xwc->x);
3113
if (valueMask & CWY)
3114
serverGeometry.setY (xwc->y);
3116
if (valueMask & CWWidth)
3117
serverGeometry.setWidth (xwc->width);
3119
if (valueMask & CWHeight)
3120
serverGeometry.setHeight (xwc->height);
3122
/* Update the server side window list on raise, lower and restack functions.
3123
* This function should only recieve stack_mode == Above
3124
* but warn incase something else does get through, to make the cause
3125
* of any potential misbehaviour obvious. */
3126
if (valueMask & (CWSibling | CWStackMode))
3128
if (xwc->stack_mode == Above)
3132
screen->unhookServerWindow (window);
3133
screen->insertServerWindow (window, xwc->sibling);
3137
compLogMessage ("core", CompLogLevelWarn, "restack_mode not Above");
3140
if (serverFrameGeometry.x () == xwc->x - serverGeometry.border () - serverInput.left)
3141
frameValueMask &= ~(CWX);
3143
if (serverFrameGeometry.y () == xwc->y - serverGeometry.border () - serverInput.top)
3144
frameValueMask &= ~(CWY);
3146
if (serverFrameGeometry.width () == xwc->width + serverGeometry.border () * 2
3147
+ serverInput.left + serverInput.right)
3148
frameValueMask &= ~(CWWidth);
3150
if (serverFrameGeometry.height () == xwc->height + serverGeometry.border () * 2
3151
+ serverInput.top + serverInput.bottom)
3152
frameValueMask &= ~(CWHeight);
3154
/* Can't set the border width of frame windows */
3155
frameValueMask &= ~(CWBorderWidth);
3157
if (frameValueMask & CWX)
3158
serverFrameGeometry.setX (xwc->x - serverGeometry.border () - serverInput.left);
3160
if (frameValueMask & CWY)
3161
serverFrameGeometry.setY (xwc->y -serverGeometry.border () - serverInput.top);
3163
if (frameValueMask & CWWidth)
3164
serverFrameGeometry.setWidth (xwc->width + serverGeometry.border () * 2
3165
+ serverInput.left + serverInput.right);
3167
if (frameValueMask & CWHeight)
3168
serverFrameGeometry.setHeight (xwc->height + serverGeometry.border () * 2
3169
+ serverInput.top + serverInput.bottom);
3176
XWindowChanges wc = *xwc;
3178
wc.x = serverFrameGeometry.x ();
3179
wc.y = serverFrameGeometry.y ();
3180
wc.width = serverFrameGeometry.width ();
3181
wc.height = serverFrameGeometry.height ();
3183
addPendingConfigure (wc, frameValueMask);
3185
XConfigureWindow (screen->dpy (), serverFrame, frameValueMask, &wc);
3187
valueMask &= ~(CWSibling | CWStackMode);
3191
xwc->x = serverInput.left;
3192
xwc->y = serverInput.top;
3193
XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc);
3199
window->sendConfigureNotify ();
3203
XConfigureWindow (screen->dpy (), id, valueMask, xwc);
3207
PrivateWindow::stackDocks (CompWindow *w,
3208
CompWindowList &updateList,
3209
XWindowChanges *xwc,
3212
CompWindow *firstFullscreenWindow = NULL;
3213
CompWindow *belowDocks = NULL;
3215
foreach (CompWindow *dw, screen->serverWindows ())
3217
/* fullscreen window found */
3218
if (firstFullscreenWindow)
3220
/* If there is another toplevel window above the fullscreen one
3221
* then we need to stack above that */
3223
!PrivateWindow::isAncestorTo (w, dw) &&
3224
!(dw->type () & (CompWindowTypeFullscreenMask |
3225
CompWindowTypeDockMask)) &&
3226
!dw->overrideRedirect () &&
3227
dw->defaultViewport () == screen->vp () &&
3233
else if (dw->type () & CompWindowTypeFullscreenMask)
3235
/* First fullscreen window found when checking up the stack
3236
* now go back down to find a suitable candidate client
3237
* window to put the docks above */
3238
firstFullscreenWindow = dw;
3239
for (CompWindow *dww = dw->serverPrev; dww; dww = dww->serverPrev)
3241
if (!(dww->type () & (CompWindowTypeFullscreenMask |
3242
CompWindowTypeDockMask)) &&
3243
!dww->overrideRedirect () &&
3244
dww->defaultViewport () == screen->vp () &&
3256
*mask = CWSibling | CWStackMode;
3257
xwc->sibling = ROOTPARENT (belowDocks);
3259
/* Collect all dock windows first */
3260
foreach (CompWindow *dw, screen->serverWindows ())
3261
if (dw->priv->type & CompWindowTypeDockMask)
3262
updateList.push_front (dw);
3271
PrivateWindow::stackTransients (CompWindow *w,
3273
XWindowChanges *xwc,
3274
CompWindowList &updateList)
3277
Window clientLeader = w->priv->clientLeader;
3279
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
3280
clientLeader = None;
3282
for (t = screen->serverWindows ().back (); t; t = t->serverPrev)
3284
if (t == w || t == avoid)
3287
if (t->priv->transientFor == w->priv->id ||
3288
t->priv->isGroupTransient (clientLeader))
3290
if (!stackTransients (t, avoid, xwc, updateList))
3293
if (xwc->sibling == t->priv->id ||
3294
(t->priv->serverFrame && xwc->sibling == t->priv->serverFrame))
3297
if (t->priv->mapNum || t->priv->pendingMaps)
3298
updateList.push_back (t);
3306
PrivateWindow::stackAncestors (CompWindow *w,
3307
XWindowChanges *xwc,
3308
CompWindowList &updateList)
3310
CompWindow *transient = NULL;
3312
if (w->priv->transientFor)
3313
transient = screen->findWindow (w->priv->transientFor);
3316
xwc->sibling != transient->priv->id &&
3317
(!transient->priv->serverFrame || xwc->sibling != transient->priv->serverFrame))
3319
CompWindow *ancestor;
3321
ancestor = screen->findWindow (w->priv->transientFor);
3324
if (!stackTransients (ancestor, w, xwc, updateList))
3327
if (ancestor->priv->type & CompWindowTypeDesktopMask)
3330
if (ancestor->priv->type & CompWindowTypeDockMask)
3331
if (!(w->priv->type & CompWindowTypeDockMask))
3334
if (ancestor->priv->mapNum || ancestor->priv->pendingMaps)
3335
updateList.push_back (ancestor);
3337
stackAncestors (ancestor, xwc, updateList);
3340
else if (w->priv->isGroupTransient (w->priv->clientLeader))
3344
for (a = screen->serverWindows ().back (); a; a = a->serverPrev)
3346
if (a->priv->clientLeader == w->priv->clientLeader &&
3347
a->priv->transientFor == None &&
3348
!a->priv->isGroupTransient (w->priv->clientLeader))
3350
if (xwc->sibling == a->priv->id ||
3351
(a->priv->serverFrame && xwc->sibling == a->priv->serverFrame))
3354
if (!stackTransients (a, w, xwc, updateList))
3357
if (a->priv->type & CompWindowTypeDesktopMask)
3360
if (a->priv->type & CompWindowTypeDockMask)
3361
if (!(w->priv->type & CompWindowTypeDockMask))
3364
if (a->priv->mapNum || a->priv->pendingMaps)
3365
updateList.push_back (a);
3372
CompWindow::configureXWindow (unsigned int valueMask,
3373
XWindowChanges *xwc)
3375
if (priv->managed && (valueMask & (CWSibling | CWStackMode)))
3377
CompWindowList transients;
3378
CompWindowList ancestors;
3379
CompWindowList docks;
3381
/* Since the window list is being reordered in reconfigureXWindow
3382
the list of windows which need to be restacked must be stored
3383
first. The windows are stacked in the opposite order than they
3384
were previously stacked, in order that they are above xwc->sibling
3385
so that when compiz gets the ConfigureNotify event it doesn't
3386
have to restack all the windows again. */
3388
/* transient children above */
3389
if (PrivateWindow::stackTransients (this, NULL, xwc, transients))
3391
/* ancestors, siblings and sibling transients below */
3392
PrivateWindow::stackAncestors (this, xwc, ancestors);
3394
for (CompWindowList::reverse_iterator w = ancestors.rbegin ();
3395
w != ancestors.rend (); w++)
3397
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
3398
xwc->sibling = ROOTPARENT (*w);
3401
this->priv->reconfigureXWindow (valueMask, xwc);
3402
xwc->sibling = ROOTPARENT (this);
3404
for (CompWindowList::reverse_iterator w = transients.rbegin ();
3405
w != transients.rend (); w++)
3407
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
3408
xwc->sibling = ROOTPARENT (*w);
3411
if (PrivateWindow::stackDocks (this, docks, xwc, &valueMask))
3413
Window sibling = xwc->sibling;
3414
xwc->stack_mode = Above;
3416
/* Then update the dock windows */
3417
foreach (CompWindow *dw, docks)
3419
xwc->sibling = sibling;
3420
dw->priv->reconfigureXWindow (valueMask, xwc);
3427
priv->reconfigureXWindow (valueMask, xwc);
3432
PrivateWindow::addWindowSizeChanges (XWindowChanges *xwc,
3433
CompWindow::Geometry old)
3441
screen->viewportForGeometry (old, viewport);
3443
x = (viewport.x () - screen->vp ().x ()) * screen->width ();
3444
y = (viewport.y () - screen->vp ().y ()) * screen->height ();
3446
output = screen->outputDeviceForGeometry (old);
3447
workArea = screen->getWorkareaForOutput (output);
3449
if (type & CompWindowTypeFullscreenMask)
3451
saveGeometry (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3453
if (fullscreenMonitorsSet)
3455
xwc->x = x + fullscreenMonitorRect.x ();
3456
xwc->y = y + fullscreenMonitorRect.y ();
3457
xwc->width = fullscreenMonitorRect.width ();
3458
xwc->height = fullscreenMonitorRect.height ();
3462
xwc->x = x + screen->outputDevs ()[output].x ();
3463
xwc->y = y + screen->outputDevs ()[output].y ();
3464
xwc->width = screen->outputDevs ()[output].width ();
3465
xwc->height = screen->outputDevs ()[output].height ();
3468
xwc->border_width = 0;
3470
mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
3474
mask |= restoreGeometry (xwc, CWBorderWidth);
3476
if (state & CompWindowStateMaximizedVertMask)
3478
saveGeometry (CWY | CWHeight);
3480
xwc->height = workArea.height () - serverInput.top -
3481
serverInput.bottom - old.border () * 2;
3487
mask |= restoreGeometry (xwc, CWY | CWHeight);
3490
if (state & CompWindowStateMaximizedHorzMask)
3492
saveGeometry (CWX | CWWidth);
3494
xwc->width = workArea.width () - serverInput.left -
3495
serverInput.right - old.border () * 2;
3501
mask |= restoreGeometry (xwc, CWX | CWWidth);
3504
/* constrain window width if smaller than minimum width */
3505
if (!(mask & CWWidth) && (int) old.width () < sizeHints.min_width)
3507
xwc->width = sizeHints.min_width;
3511
/* constrain window width if greater than maximum width */
3512
if (!(mask & CWWidth) && (int) old.width () > sizeHints.max_width)
3514
xwc->width = sizeHints.max_width;
3518
/* constrain window height if smaller than minimum height */
3519
if (!(mask & CWHeight) && (int) old.height () < sizeHints.min_height)
3521
xwc->height = sizeHints.min_height;
3525
/* constrain window height if greater than maximum height */
3526
if (!(mask & CWHeight) && (int) old.height () > sizeHints.max_height)
3528
xwc->height = sizeHints.max_height;
3532
if (mask & (CWWidth | CWHeight))
3534
int width, height, max;
3536
width = (mask & CWWidth) ? xwc->width : old.width ();
3537
height = (mask & CWHeight) ? xwc->height : old.height ();
3539
xwc->width = old.width ();
3540
xwc->height = old.height ();
3542
window->constrainNewWindowSize (width, height, &width, &height);
3544
if (width != (int) old.width ())
3552
if (height != (int) old.height ())
3555
xwc->height = height;
3560
if (state & CompWindowStateMaximizedVertMask)
3562
if (old.y () < y + workArea.y () + serverInput.top)
3564
xwc->y = y + workArea.y () + serverInput.top;
3569
height = xwc->height + old.border () * 2;
3571
max = y + workArea.bottom ();
3572
if (old.y () + (int) old.height () + serverInput.bottom > max)
3574
xwc->y = max - height - serverInput.bottom;
3577
else if (old.y () + height + serverInput.bottom > max)
3579
xwc->y = y + workArea.y () +
3580
(workArea.height () - serverInput.top - height -
3581
serverInput.bottom) / 2 + serverInput.top;
3587
if (state & CompWindowStateMaximizedHorzMask)
3589
if (old.x () < x + workArea.x () + serverInput.left)
3591
xwc->x = x + workArea.x () + serverInput.left;
3596
width = xwc->width + old.border () * 2;
3598
max = x + workArea.right ();
3599
if (old.x () + (int) old.width () + serverInput.right > max)
3601
xwc->x = max - width - serverInput.right;
3604
else if (old.x () + width + serverInput.right > max)
3606
xwc->x = x + workArea.x () +
3607
(workArea.width () - serverInput.left - width -
3608
serverInput.right) / 2 + serverInput.left;
3616
if ((mask & CWX) && (xwc->x == old.x ()))
3619
if ((mask & CWY) && (xwc->y == old.y ()))
3622
if ((mask & CWWidth) && (xwc->width == (int) old.width ()))
3625
if ((mask & CWHeight) && (xwc->height == (int) old.height ()))
3632
PrivateWindow::adjustConfigureRequestForGravity (XWindowChanges *xwc,
3638
unsigned int mask = 0;
3643
if (xwcm & (CWX | CWWidth))
3646
case NorthWestGravity:
3648
case SouthWestGravity:
3650
newX += priv->border.left * direction;
3657
newX -= (xwc->width / 2 - priv->border.left +
3658
(priv->border.left + priv->border.right) / 2) * direction;
3660
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
3663
case NorthEastGravity:
3665
case SouthEastGravity:
3667
newX -= xwc->width + priv->border.right * direction;
3669
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
3678
if (xwcm & (CWY | CWHeight))
3681
case NorthWestGravity:
3683
case NorthEastGravity:
3685
newY = xwc->y + priv->serverInput.top * direction;
3692
newY -= (xwc->height / 2 - priv->serverInput.top +
3693
(priv->serverInput.top + priv->serverInput.bottom) / 2) * direction;
3695
newY -= ((xwc->height - priv->serverGeometry.height ()) / 2) * direction;
3698
case SouthWestGravity:
3700
case SouthEastGravity:
3702
newY -= xwc->height + priv->serverInput.bottom * direction;
3704
newY -= (xwc->height - priv->serverGeometry.height ()) * direction;
3715
xwc->x += (newX - xwc->x);
3721
xwc->y += (newY - xwc->y);
3729
CompWindow::moveResize (XWindowChanges *xwc,
3732
unsigned int source)
3734
bool placed = false;
3736
xwcm &= (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3738
if (xwcm & (CWX | CWY))
3739
if (priv->sizeHints.flags & (USPosition | PPosition))
3743
gravity = priv->sizeHints.win_gravity;
3746
xwc->x = priv->serverGeometry.x ();
3748
xwc->y = priv->serverGeometry.y ();
3749
if (!(xwcm & CWWidth))
3750
xwc->width = priv->serverGeometry.width ();
3751
if (!(xwcm & CWHeight))
3752
xwc->height = priv->serverGeometry.height ();
3754
if (xwcm & (CWWidth | CWHeight))
3758
if (constrainNewWindowSize (xwc->width, xwc->height, &width, &height))
3760
if (width != xwc->width)
3763
if (height != xwc->height)
3767
xwc->height = height;
3771
xwcm |= priv->adjustConfigureRequestForGravity (xwc, xwcm, gravity, 1);
3773
validateResizeRequest (xwcm, xwc, source);
3775
/* when horizontally maximized only allow width changes added by
3776
addWindowSizeChanges */
3777
if (priv->state & CompWindowStateMaximizedHorzMask)
3780
/* when vertically maximized only allow height changes added by
3781
addWindowSizeChanges */
3782
if (priv->state & CompWindowStateMaximizedVertMask)
3785
xwcm |= priv->addWindowSizeChanges (xwc, Geometry (xwc->x, xwc->y,
3786
xwc->width, xwc->height,
3787
xwc->border_width));
3789
/* check if the new coordinates are useful and valid (different
3790
to current size); if not, we have to clear them to make sure
3791
we send a synthetic ConfigureNotify event if all coordinates
3792
match the server coordinates */
3793
if (xwc->x == priv->serverGeometry.x ())
3796
if (xwc->y == priv->serverGeometry.y ())
3799
if (xwc->width == (int) priv->serverGeometry.width ())
3802
if (xwc->height == (int) priv->serverGeometry.height ())
3805
if (xwc->border_width == (int) priv->serverGeometry.border ())
3806
xwcm &= ~CWBorderWidth;
3808
/* update saved window coordinates - if CWX or CWY is set for fullscreen
3809
or maximized windows after addWindowSizeChanges, it should be pretty
3810
safe to assume that the saved coordinates should be updated too, e.g.
3811
because the window was moved to another viewport by some client */
3812
if ((xwcm & CWX) && (priv->saveMask & CWX))
3813
priv->saveWc.x += (xwc->x - priv->serverGeometry.x ());
3815
if ((xwcm & CWY) && (priv->saveMask & CWY))
3816
priv->saveWc.y += (xwc->y - priv->serverGeometry.y ());
3818
if (priv->mapNum && (xwcm & (CWWidth | CWHeight)))
3822
configureXWindow (xwcm, xwc);
3825
/* we have to send a configure notify on ConfigureRequest events if
3826
we decide not to do anything according to ICCCM 4.1.5 */
3827
sendConfigureNotify ();
3831
priv->placed = true;
3835
PrivateWindow::updateSize ()
3840
if (window->overrideRedirect () || !managed)
3843
mask = priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
3846
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
3847
window->sendSyncRequest ();
3849
window->configureXWindow (mask, &xwc);
3854
PrivateWindow::addWindowStackChanges (XWindowChanges *xwc,
3855
CompWindow *sibling)
3859
if (!sibling || sibling->priv->id != id)
3861
/* Alow requests to go on top of serverPrev
3862
* if serverPrev was recently restacked */
3863
if (window->serverPrev)
3867
XWindowChanges lxwc;
3868
unsigned int valueMask = CWStackMode;
3870
lxwc.stack_mode = Below;
3872
/* Below with no sibling puts the window at the bottom
3874
XConfigureWindow (screen->dpy (), ROOTPARENT (window), valueMask, &lxwc);
3877
priv->addPendingConfigure (lxwc, CWStackMode);
3879
/* Update the list of windows last sent to the server */
3880
screen->unhookServerWindow (window);
3881
screen->insertServerWindow (window, 0);
3885
bool pendingRestacks = false;
3887
foreach (XWCValueMask &xwcvm, sibling->priv->pendingConfigures)
3889
if (xwcvm.second & (CWSibling | CWStackMode))
3891
pendingRestacks = true;
3896
if (sibling->priv->id != window->serverPrev->priv->id || pendingRestacks)
3898
mask |= CWSibling | CWStackMode;
3900
xwc->stack_mode = Above;
3901
xwc->sibling = ROOTPARENT (sibling);
3907
mask |= CWSibling | CWStackMode;
3909
xwc->stack_mode = Above;
3910
xwc->sibling = ROOTPARENT (sibling);
3918
CompWindow::raise ()
3922
bool aboveFs = false;
3924
/* an active fullscreen window should be raised over all other
3925
windows in its layer */
3926
if (priv->type & CompWindowTypeFullscreenMask)
3927
if (priv->id == screen->activeWindow ())
3930
mask = priv->addWindowStackChanges (&xwc,
3931
PrivateWindow::findSiblingBelow (this, aboveFs));
3934
configureXWindow (mask, &xwc);
3938
PrivateScreen::focusTopMostWindow ()
3940
CompWindow *focus = NULL;
3941
CompWindowList::reverse_iterator it = serverWindows.rbegin ();
3943
for (; it != serverWindows.rend (); it++)
3945
CompWindow *w = *it;
3947
if (w->type () & CompWindowTypeDockMask)
3959
if (focus->id () != activeWindow)
3960
focus->moveInputFocusTo ();
3963
XSetInputFocus (dpy, root, RevertToPointerRoot,
3970
CompWindow::lower ()
3975
mask = priv->addWindowStackChanges (&xwc,
3976
PrivateWindow::findLowestSiblingBelow (this));
3978
configureXWindow (mask, &xwc);
3980
/* when lowering a window, focus the topmost window if
3981
the click-to-focus option is on */
3982
if ((screen->priv->optionGetClickToFocus ()))
3984
CompWindow *focusedWindow = screen->priv->focusTopMostWindow ();
3986
/* if the newly focused window is a desktop window,
3987
give the focus back to w */
3988
if (focusedWindow &&
3989
focusedWindow->type () & CompWindowTypeDesktopMask)
3991
moveInputFocusTo ();
3997
CompWindow::restackAbove (CompWindow *sibling)
3999
for (; sibling; sibling = sibling->serverNext)
4000
if (PrivateWindow::validSiblingBelow (this, sibling))
4008
mask = priv->addWindowStackChanges (&xwc, sibling);
4010
configureXWindow (mask, &xwc);
4014
/* finds the highest window under sibling we can stack above */
4016
PrivateWindow::findValidStackSiblingBelow (CompWindow *w,
4017
CompWindow *sibling)
4019
CompWindow *lowest, *last, *p;
4021
/* check whether we're allowed to stack under a sibling by finding
4022
* the above 'sibling' and checking whether or not we're allowed
4023
* to stack under that - if not, then there is no valid sibling
4026
for (p = sibling; p; p = p->serverNext)
4028
if (!avoidStackingRelativeTo (p))
4030
if (!validSiblingBelow (p, w))
4036
/* get lowest sibling we're allowed to stack above */
4037
lowest = last = findLowestSiblingBelow (w);
4039
/* walk from bottom up */
4040
for (p = screen->serverWindows ().front (); p; p = p->serverNext)
4042
/* stop walking when we reach the sibling we should try to stack
4047
/* skip windows that we should avoid */
4048
if (w == p || avoidStackingRelativeTo (p))
4051
if (validSiblingBelow (w, p))
4053
/* update lowest as we find windows below sibling that we're
4054
allowed to stack above. last window must be equal to the
4055
lowest as we shouldn't update lowest if we passed an
4061
/* update last pointer */
4069
CompWindow::restackBelow (CompWindow *sibling)
4074
mask = priv->addWindowStackChanges (&xwc,
4075
PrivateWindow::findValidStackSiblingBelow (this, sibling));
4078
configureXWindow (mask, &xwc);
4082
CompWindow::updateAttributes (CompStackingUpdateMode stackingMode)
4087
if (overrideRedirect () || !priv->managed)
4090
if (priv->state & CompWindowStateShadedMask)
4092
windowNotify (CompWindowNotifyShade);
4096
else if (priv->shaded)
4098
windowNotify (CompWindowNotifyUnshade);
4103
if (stackingMode != CompStackingUpdateModeNone)
4106
CompWindow *sibling;
4108
aboveFs = (stackingMode == CompStackingUpdateModeAboveFullscreen);
4109
if (priv->type & CompWindowTypeFullscreenMask)
4111
/* put active or soon-to-be-active fullscreen windows over
4112
all others in their layer */
4113
if (priv->id == screen->activeWindow () ||
4114
priv->id == screen->priv->nextActiveWindow)
4120
/* put windows that are just mapped, over fullscreen windows */
4121
if (stackingMode == CompStackingUpdateModeInitialMap)
4124
sibling = PrivateWindow::findSiblingBelow (this, aboveFs);
4127
(stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
4131
for (p = sibling; p; p = p->serverPrev)
4132
if (p->priv->id == screen->activeWindow ())
4135
/* window is above active window so we should lower it,
4136
* assuing that is allowed (if, for example, our window has
4137
* the "above" state, then lowering beneath the active
4138
* window may not be allowed). */
4139
if (p && PrivateWindow::validSiblingBelow (p, this))
4141
p = PrivateWindow::findValidStackSiblingBelow (sibling, p);
4143
/* if we found a valid sibling under the active window, it's
4144
our new sibling we want to stack above */
4151
mask |= priv->addWindowStackChanges (&xwc, sibling);
4154
mask |= priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
4156
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
4160
configureXWindow (mask, &xwc);
4164
PrivateWindow::ensureWindowVisibility ()
4167
int width = serverGeometry.width () + serverGeometry.border () * 2;
4168
int height = serverGeometry.height () + serverGeometry.border () * 2;
4172
if (struts || attrib.override_redirect)
4175
if (type & (CompWindowTypeDockMask |
4176
CompWindowTypeFullscreenMask |
4177
CompWindowTypeUnknownMask))
4180
x1 = screen->workArea ().x () - screen->width () * screen->vp ().x ();
4181
y1 = screen->workArea ().y () - screen->height () * screen->vp ().y ();
4182
x2 = x1 + screen->workArea ().width () + screen->vpSize ().width () *
4184
y2 = y1 + screen->workArea ().height () + screen->vpSize ().height () *
4187
if (serverGeometry.x () - serverInput.left >= x2)
4188
dx = (x2 - 25) - serverGeometry.x ();
4189
else if (serverGeometry.x () + width + serverInput.right <= x1)
4190
dx = (x1 + 25) - (serverGeometry.x () + width);
4192
if (serverGeometry.y () - serverInput.top >= y2)
4193
dy = (y2 - 25) - serverGeometry.y ();
4194
else if (serverGeometry.y () + height + serverInput.bottom <= y1)
4195
dy = (y1 + 25) - (serverGeometry.y () + height);
4201
xwc.x = serverGeometry.x () + dx;
4202
xwc.y = serverGeometry.y () + dy;
4204
window->configureXWindow (CWX | CWY, &xwc);
4209
PrivateWindow::reveal ()
4211
if (window->minimized ())
4212
window->unminimize ();
4214
screen->leaveShowDesktopMode (window);
4218
PrivateWindow::revealAncestors (CompWindow *w,
4219
CompWindow *transient)
4221
if (isAncestorTo (transient, w))
4223
screen->forEachWindow (boost::bind (revealAncestors, _1, w));
4229
CompWindow::activate ()
4231
WRAPABLE_HND_FUNC (3, activate)
4233
screen->priv->setCurrentDesktop (priv->desktop);
4235
screen->forEachWindow (
4236
boost::bind (PrivateWindow::revealAncestors, _1, this));
4239
if (priv->state & CompWindowStateHiddenMask)
4241
priv->state &= ~CompWindowStateShadedMask;
4246
if (priv->state & CompWindowStateHiddenMask)
4249
if (!onCurrentDesktop ())
4252
priv->ensureWindowVisibility ();
4253
updateAttributes (CompStackingUpdateModeAboveFullscreen);
4254
moveInputFocusTo ();
4258
#define PVertResizeInc (1 << 0)
4259
#define PHorzResizeInc (1 << 1)
4262
CompWindow::constrainNewWindowSize (int width,
4267
const XSizeHints *hints = &priv->sizeHints;
4268
int oldWidth = width;
4269
int oldHeight = height;
4273
int base_height = 0;
4276
int max_width = MAXSHORT;
4277
int max_height = MAXSHORT;
4278
long flags = hints->flags;
4279
long resizeIncFlags = (flags & PResizeInc) ? ~0 : 0;
4281
if (screen->priv->optionGetIgnoreHintsWhenMaximized ())
4283
if (priv->state & MAXIMIZE_STATE)
4287
if (priv->state & CompWindowStateMaximizedHorzMask)
4288
resizeIncFlags &= ~PHorzResizeInc;
4290
if (priv->state & CompWindowStateMaximizedVertMask)
4291
resizeIncFlags &= ~PVertResizeInc;
4295
/* Ater gdk_window_constrain_size(), which is partially borrowed from fvwm.
4297
* Copyright 1993, Robert Nation
4298
* You may use this code for any purpose, as long as the original
4299
* copyright remains in the source code and all documentation
4301
* which in turn borrows parts of the algorithm from uwm
4304
#define FLOOR(value, base) (((int) ((value) / (base))) * (base))
4305
#define FLOOR64(value, base) (((uint64_t) ((value) / (base))) * (base))
4307
if ((flags & PBaseSize) && (flags & PMinSize))
4309
base_width = hints->base_width;
4310
base_height = hints->base_height;
4311
min_width = hints->min_width;
4312
min_height = hints->min_height;
4314
else if (flags & PBaseSize)
4316
base_width = hints->base_width;
4317
base_height = hints->base_height;
4318
min_width = hints->base_width;
4319
min_height = hints->base_height;
4321
else if (flags & PMinSize)
4323
base_width = hints->min_width;
4324
base_height = hints->min_height;
4325
min_width = hints->min_width;
4326
min_height = hints->min_height;
4329
if (flags & PMaxSize)
4331
max_width = hints->max_width;
4332
max_height = hints->max_height;
4335
if (resizeIncFlags & PHorzResizeInc)
4336
xinc = MAX (xinc, hints->width_inc);
4338
if (resizeIncFlags & PVertResizeInc)
4339
yinc = MAX (yinc, hints->height_inc);
4341
/* clamp width and height to min and max values */
4342
width = CLAMP (width, min_width, max_width);
4343
height = CLAMP (height, min_height, max_height);
4345
/* shrink to base + N * inc */
4346
width = base_width + FLOOR (width - base_width, xinc);
4347
height = base_height + FLOOR (height - base_height, yinc);
4349
/* constrain aspect ratio, according to:
4351
* min_aspect.x width max_aspect.x
4352
* ------------ <= -------- <= -----------
4353
* min_aspect.y height max_aspect.y
4355
if ((flags & PAspect) && hints->min_aspect.y > 0 && hints->max_aspect.x > 0)
4357
/* Use 64 bit arithmetic to prevent overflow */
4359
uint64_t min_aspect_x = hints->min_aspect.x;
4360
uint64_t min_aspect_y = hints->min_aspect.y;
4361
uint64_t max_aspect_x = hints->max_aspect.x;
4362
uint64_t max_aspect_y = hints->max_aspect.y;
4365
if (min_aspect_x * height > width * min_aspect_y)
4367
delta = FLOOR64 (height - width * min_aspect_y / min_aspect_x,
4369
if (height - (int) delta >= min_height)
4373
delta = FLOOR64 (height * min_aspect_x / min_aspect_y - width,
4375
if (width + (int) delta <= max_width)
4380
if (width * max_aspect_y > max_aspect_x * height)
4382
delta = FLOOR64 (width - height * max_aspect_x / max_aspect_y,
4384
if (width - (int) delta >= min_width)
4388
delta = FLOOR64 (width * min_aspect_y / min_aspect_x - height,
4390
if (height + (int) delta <= max_height)
4400
if (width != oldWidth || height != oldHeight)
4403
*newHeight = height;
4414
priv->hidden = true;
4421
priv->hidden = false;
4426
PrivateWindow::hide ()
4428
bool onDesktop = window->onCurrentDesktop ();
4433
if (!window->minimized () && !inShowDesktopMode &&
4434
!hidden && onDesktop)
4436
if (state & CompWindowStateShadedMask)
4449
if ((state & CompWindowStateShadedMask) && serverFrame)
4450
XUnmapWindow (screen->dpy (), serverFrame);
4453
if (!pendingMaps && !window->isViewable ())
4456
window->windowNotify (CompWindowNotifyHide);
4460
if (serverFrame && !shaded)
4461
XUnmapWindow (screen->dpy (), serverFrame);
4463
XUnmapWindow (screen->dpy (), id);
4465
if (window->minimized () || inShowDesktopMode || hidden || shaded)
4466
window->changeState (state | CompWindowStateHiddenMask);
4468
if (shaded && id == screen->activeWindow ())
4469
window->moveInputFocusTo ();
4473
PrivateWindow::show ()
4475
bool onDesktop = window->onCurrentDesktop ();
4480
if (minimized || inShowDesktopMode ||
4481
hidden || !onDesktop)
4483
/* no longer hidden but not on current desktop */
4484
if (!minimized && !inShowDesktopMode && !hidden)
4485
window->changeState (state & ~CompWindowStateHiddenMask);
4490
/* transition from minimized to shaded */
4491
if (state & CompWindowStateShadedMask)
4496
XMapWindow (screen->dpy (), serverFrame);
4500
priv->geometry.setHeight (priv->geometry.height () + 1);
4501
window->resize (geometry.x (), geometry.y (),
4502
geometry.width (), geometry.height () - 1,
4503
geometry.border ());
4513
window->windowNotify (CompWindowNotifyShow);
4519
XMapWindow (screen->dpy (), serverFrame);
4520
XMapWindow (screen->dpy (), wrapper);
4523
XMapWindow (screen->dpy (), id);
4525
window->changeState (state & ~CompWindowStateHiddenMask);
4526
screen->priv->setWindowState (state, id);
4530
PrivateWindow::minimizeTransients (CompWindow *w,
4531
CompWindow *ancestor)
4533
if (w->priv->transientFor == ancestor->priv->id ||
4534
w->priv->isGroupTransient (ancestor->priv->clientLeader))
4541
CompWindow::minimize ()
4543
WRAPABLE_HND_FUNC (13, minimize);
4548
if (!priv->minimized)
4550
windowNotify (CompWindowNotifyMinimize);
4552
priv->minimized = true;
4554
screen->forEachWindow (
4555
boost::bind (PrivateWindow::minimizeTransients, _1, this));
4562
PrivateWindow::unminimizeTransients (CompWindow *w,
4563
CompWindow *ancestor)
4565
if (w->priv->transientFor == ancestor->priv->id ||
4566
w->priv->isGroupTransient (ancestor->priv->clientLeader))
4571
CompWindow::unminimize ()
4573
WRAPABLE_HND_FUNC (14, unminimize);
4574
if (priv->minimized)
4576
windowNotify (CompWindowNotifyUnminimize);
4578
priv->minimized = false;
4582
screen->forEachWindow (
4583
boost::bind (PrivateWindow::unminimizeTransients, _1, this));
4588
CompWindow::maximize (unsigned int state)
4590
if (overrideRedirect ())
4593
state = constrainWindowState (state, priv->actions);
4595
state &= MAXIMIZE_STATE;
4597
if (state == (priv->state & MAXIMIZE_STATE))
4600
state |= (priv->state & ~MAXIMIZE_STATE);
4602
changeState (state);
4603
updateAttributes (CompStackingUpdateModeNone);
4607
PrivateWindow::getUserTime (Time& time)
4611
unsigned long n, left;
4612
unsigned char *data;
4613
bool retval = false;
4615
result = XGetWindowProperty (screen->dpy (), priv->id,
4617
0L, 1L, False, XA_CARDINAL, &actual, &format,
4620
if (result == Success && data)
4626
memcpy (&value, data, sizeof (CARD32));
4628
time = (Time) value;
4631
XFree ((void *) data);
4638
PrivateWindow::setUserTime (Time time)
4640
CARD32 value = (CARD32) time;
4642
XChangeProperty (screen->dpy (), priv->id,
4644
XA_CARDINAL, 32, PropModeReplace,
4645
(unsigned char *) &value, 1);
4649
* Macros from metacity
4651
* Xserver time can wraparound, thus comparing two timestamps needs to
4652
* take this into account. Here's a little macro to help out. If no
4653
* wraparound has occurred, this is equivalent to
4655
* Of course, the rest of the ugliness of this macro comes from
4656
* accounting for the fact that wraparound can occur and the fact that
4657
* a timestamp of 0 must be special-cased since it means older than
4660
* Note that this is NOT an equivalent for time1 <= time2; if that's
4661
* what you need then you'll need to swap the order of the arguments
4662
* and negate the result.
4664
#define XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) \
4665
( (( (time1) < (time2) ) && \
4666
( (time2) - (time1) < ((unsigned long) -1) / 2 )) || \
4667
(( (time1) > (time2) ) && \
4668
( (time1) - (time2) > ((unsigned long) -1) / 2 )) \
4670
#define XSERVER_TIME_IS_BEFORE(time1, time2) \
4672
(XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS (time1, time2) && \
4677
PrivateWindow::getUsageTimestamp (Time& timestamp)
4679
if (getUserTime (timestamp))
4682
if (initialTimestampSet)
4684
timestamp = initialTimestamp;
4692
PrivateWindow::isWindowFocusAllowed (Time timestamp)
4694
CompScreen *s = screen;
4696
Time wUserTime, aUserTime;
4697
bool gotTimestamp = false;
4701
level = s->priv->optionGetFocusPreventionLevel ();
4703
if (level == CoreOptions::FocusPreventionLevelOff)
4708
/* the caller passed a timestamp, so use that
4709
instead of the window's user time */
4710
wUserTime = timestamp;
4711
gotTimestamp = true;
4715
gotTimestamp = getUsageTimestamp (wUserTime);
4718
/* if we got no timestamp for the window, try to get at least a timestamp
4719
for its transient parent, if any */
4720
if (!gotTimestamp && transientFor)
4724
parent = screen->findWindow (transientFor);
4726
gotTimestamp = parent->priv->getUsageTimestamp (wUserTime);
4729
if (gotTimestamp && !wUserTime)
4731
/* window explicitly requested no focus */
4735
/* allow focus for excluded windows */
4736
CompMatch &match = s->priv->optionGetFocusPreventionMatch ();
4737
if (!match.evaluate (window))
4740
if (level == CoreOptions::FocusPreventionLevelVeryHigh)
4743
active = s->findWindow (s->activeWindow ());
4745
/* no active window */
4746
if (!active || (active->type () & CompWindowTypeDesktopMask))
4749
/* active window belongs to same application */
4750
if (window->clientLeader () == active->clientLeader ())
4753
if (level == CoreOptions::FocusPreventionLevelHigh)
4756
/* not in current viewport or desktop */
4757
if (!window->onCurrentDesktop ())
4760
dvp = window->defaultViewport ();
4761
if (dvp.x () != s->vp ().x () || dvp.y () != s->vp ().y ())
4766
/* unsure as we have nothing to compare - allow focus in low level,
4767
don't allow in normal level */
4768
if (level == CoreOptions::FocusPreventionLevelNormal)
4774
/* can't get user time for active window */
4775
if (!active->priv->getUserTime (aUserTime))
4778
if (XSERVER_TIME_IS_BEFORE (wUserTime, aUserTime))
4785
PrivateWindow::allowWindowFocus (unsigned int noFocusMask,
4790
if (priv->id == screen->activeWindow ())
4793
/* do not focus windows of these types */
4794
if (priv->type & noFocusMask)
4797
/* window doesn't take focus */
4798
if (!priv->inputHint &&
4799
!(priv->protocols & CompWindowProtocolTakeFocusMask))
4804
retval = priv->isWindowFocusAllowed (timestamp);
4807
/* add demands attention state if focus was prevented */
4808
window->changeState (priv->state | CompWindowStateDemandsAttentionMask);
4815
CompWindow::defaultViewport ()
4819
if (priv->serverGeometry.x () < (int) screen->width () &&
4820
priv->serverGeometry.x () + priv->serverGeometry.width () > 0 &&
4821
priv->serverGeometry.y () < (int) screen->height () &&
4822
priv->serverGeometry.y ()+ priv->serverGeometry.height () > 0)
4824
return screen->vp ();
4827
screen->viewportForGeometry (priv->serverGeometry, viewport);
4833
CompWindow::initialViewport () const
4835
return priv->initialViewport;
4839
PrivateWindow::readIconHint ()
4841
XImage *image, *maskImage = NULL;
4842
Display *dpy = screen->dpy ();
4843
unsigned int width, height, dummy;
4844
unsigned int i, j, k;
4851
if (!XGetGeometry (dpy, hints->icon_pixmap, &wDummy, &iDummy,
4852
&iDummy, &width, &height, &dummy, &dummy))
4855
image = XGetImage (dpy, hints->icon_pixmap, 0, 0, width, height,
4856
AllPlanes, ZPixmap);
4860
colors = new XColor[width * height];
4863
XDestroyImage (image);
4868
for (j = 0; j < height; j++)
4869
for (i = 0; i < width; i++)
4870
colors[k++].pixel = XGetPixel (image, i, j);
4872
for (i = 0; i < k; i += 256)
4873
XQueryColors (dpy, screen->priv->colormap,
4874
&colors[i], MIN (k - i, 256));
4876
XDestroyImage (image);
4878
icon = new CompIcon (screen, width, height);
4885
if (hints->flags & IconMaskHint)
4886
maskImage = XGetImage (dpy, hints->icon_mask, 0, 0,
4887
width, height, AllPlanes, ZPixmap);
4890
p = (CARD32 *) icon->data ();
4892
for (j = 0; j < height; j++)
4894
for (i = 0; i < width; i++)
4896
if (maskImage && !XGetPixel (maskImage, i, j))
4898
else if (image->depth == 1) /* white : black */
4899
*p++ = colors[k].pixel ? 0xffffffff : 0xff000000;
4901
*p++ = 0xff000000 | /* alpha */
4902
(((colors[k].red >> 8) & 0xff) << 16) | /* red */
4903
(((colors[k].green >> 8) & 0xff) << 8) | /* green */
4904
((colors[k].blue >> 8) & 0xff); /* blue */
4912
XDestroyImage (maskImage);
4914
icons.push_back (icon);
4917
/* returns icon with dimensions as close as possible to width and height
4918
but never greater. */
4920
CompWindow::getIcon (int width,
4924
int wh, diff, oldDiff;
4927
/* need to fetch icon property */
4928
if (priv->icons.size () == 0 && !priv->noIcons)
4932
unsigned long n, left;
4933
unsigned char *data;
4935
result = XGetWindowProperty (screen->dpy (), priv->id, Atoms::wmIcon,
4936
0L, 65536L, false, XA_CARDINAL,
4937
&actual, &format, &n, &left, &data);
4939
if (result == Success && data)
4942
CARD32 alpha, red, green, blue;
4943
unsigned long iw, ih;
4945
for (i = 0; i + 2 < n; i += iw * ih + 2)
4947
unsigned long *idata = (unsigned long *) data;
4952
/* iw * ih may be larger than the value range of unsigned
4953
* long, so better do some checking for extremely weird
4954
* icon sizes first */
4955
if (iw > 2048 || ih > 2048 || iw * ih + 2 > n - i)
4961
icon = new CompIcon (screen, iw, ih);
4965
priv->icons.push_back (icon);
4967
p = (CARD32 *) (icon->data ());
4969
/* EWMH doesn't say if icon data is premultiplied or
4970
not but most applications seem to assume data should
4971
be unpremultiplied. */
4972
for (j = 0; j < iw * ih; j++)
4974
alpha = (idata[i + j + 2] >> 24) & 0xff;
4975
red = (idata[i + j + 2] >> 16) & 0xff;
4976
green = (idata[i + j + 2] >> 8) & 0xff;
4977
blue = (idata[i + j + 2] >> 0) & 0xff;
4979
red = (red * alpha) >> 8;
4980
green = (green * alpha) >> 8;
4981
blue = (blue * alpha) >> 8;
4994
else if (priv->hints && (priv->hints->flags & IconPixmapHint))
4996
priv->readIconHint ();
4999
/* don't fetch property again */
5000
if (priv->icons.size () == 0)
5001
priv->noIcons = true;
5004
/* no icons available for this window */
5009
wh = width + height;
5011
for (i = 0; i < priv->icons.size (); i++)
5013
const CompSize iconSize = *priv->icons[i];
5015
if ((int) iconSize.width () > width ||
5016
(int) iconSize.height () > height)
5021
diff = wh - (iconSize.width () + iconSize.height ());
5022
oldDiff = wh - (icon->width () + icon->height ());
5025
icon = priv->icons[i];
5028
icon = priv->icons[i];
5035
CompWindow::iconGeometry () const
5037
return priv->iconGeometry;
5041
PrivateWindow::freeIcons ()
5043
for (unsigned int i = 0; i < priv->icons.size (); i++)
5044
delete priv->icons[i];
5046
priv->icons.resize (0);
5047
priv->noIcons = false;
5051
CompWindow::outputDevice ()
5053
return screen->outputDeviceForGeometry (priv->serverGeometry);
5057
CompWindow::onCurrentDesktop ()
5059
if (priv->desktop == 0xffffffff ||
5060
priv->desktop == screen->currentDesktop ())
5069
CompWindow::setDesktop (unsigned int desktop)
5071
if (desktop != 0xffffffff)
5073
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5076
if (desktop >= screen->nDesktop ())
5080
if (desktop == priv->desktop)
5083
priv->desktop = desktop;
5085
if (desktop == 0xffffffff || desktop == screen->currentDesktop ())
5090
screen->setWindowProp (priv->id, Atoms::winDesktop, priv->desktop);
5093
/* The compareWindowActiveness function compares the two windows 'w1'
5094
and 'w2'. It returns an integer less than, equal to, or greater
5095
than zero if 'w1' is found, respectively, to activated longer time
5096
ago than, to be activated at the same time, or be activated more
5097
recently than 'w2'. */
5099
PrivateWindow::compareWindowActiveness (CompWindow *w1,
5102
CompActiveWindowHistory *history = screen->currentHistory ();
5105
/* check current window history first */
5106
for (i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
5108
if (history->id[i] == w1->priv->id)
5111
if (history->id[i] == w2->priv->id)
5114
if (!history->id[i])
5118
return w1->priv->activeNum - w2->priv->activeNum;
5122
CompWindow::onAllViewports ()
5124
if (overrideRedirect ())
5127
if (!priv->managed && !isViewable ())
5130
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5133
if (priv->state & CompWindowStateStickyMask)
5140
CompWindow::getMovementForOffset (CompPoint offset)
5142
CompScreen *s = screen;
5143
int m, vWidth, vHeight;
5144
int offX = offset.x (), offY = offset.y ();
5147
vWidth = s->width () * s->vpSize ().width ();
5148
vHeight = s->height () * s->vpSize ().height ();
5154
if (s->vpSize ().width () == 1)
5160
m = priv->geometry.x () + offX;
5161
if (m - priv->input.left < (int) s->width () - vWidth)
5162
rv.setX (offX + vWidth);
5163
else if (m + priv->width + priv->input.right > vWidth)
5164
rv.setX (offX - vWidth);
5169
if (s->vpSize ().height () == 1)
5175
m = priv->geometry.y () + offY;
5176
if (m - priv->input.top < (int) s->height () - vHeight)
5177
rv.setY (offY + vHeight);
5178
else if (m + priv->height + priv->input.bottom > vHeight)
5179
rv.setY (offY - vHeight);
5188
WindowInterface::getOutputExtents (CompWindowExtents& output)
5189
WRAPABLE_DEF (getOutputExtents, output)
5192
WindowInterface::getAllowedActions (unsigned int &setActions,
5193
unsigned int &clearActions)
5194
WRAPABLE_DEF (getAllowedActions, setActions, clearActions)
5197
WindowInterface::focus ()
5198
WRAPABLE_DEF (focus)
5201
WindowInterface::activate ()
5202
WRAPABLE_DEF (activate)
5205
WindowInterface::place (CompPoint &pos)
5206
WRAPABLE_DEF (place, pos)
5209
WindowInterface::validateResizeRequest (unsigned int &mask,
5210
XWindowChanges *xwc,
5211
unsigned int source)
5212
WRAPABLE_DEF (validateResizeRequest, mask, xwc, source)
5215
WindowInterface::resizeNotify (int dx,
5219
WRAPABLE_DEF (resizeNotify, dx, dy, dwidth, dheight)
5222
WindowInterface::moveNotify (int dx,
5225
WRAPABLE_DEF (moveNotify, dx, dy, immediate)
5228
WindowInterface::windowNotify (CompWindowNotify n)
5229
WRAPABLE_DEF (windowNotify, n)
5232
WindowInterface::grabNotify (int x,
5236
WRAPABLE_DEF (grabNotify, x, y, state, mask)
5239
WindowInterface::ungrabNotify ()
5240
WRAPABLE_DEF (ungrabNotify)
5243
WindowInterface::stateChangeNotify (unsigned int lastState)
5244
WRAPABLE_DEF (stateChangeNotify, lastState)
5247
WindowInterface::updateFrameRegion (CompRegion ®ion)
5248
WRAPABLE_DEF (updateFrameRegion, region)
5251
WindowInterface::minimize ()
5252
WRAPABLE_DEF (minimize);
5255
WindowInterface::unminimize ()
5256
WRAPABLE_DEF (unminimize);
5259
WindowInterface::minimized ()
5260
WRAPABLE_DEF (minimized);
5263
WindowInterface::alpha ()
5264
WRAPABLE_DEF (alpha);
5267
WindowInterface::isFocussable ()
5268
WRAPABLE_DEF (isFocussable);
5271
WindowInterface::managed ()
5272
WRAPABLE_DEF (managed);
5287
CompWindow::state ()
5293
CompWindow::actions ()
5295
return priv->actions;
5299
CompWindow::protocols ()
5301
return priv->protocols;
5305
CompWindow::close (Time serverTime)
5307
if (serverTime == 0)
5308
serverTime = screen->getCurrentTime ();
5312
if (priv->protocols & CompWindowProtocolDeleteMask)
5316
ev.type = ClientMessage;
5317
ev.xclient.window = priv->id;
5318
ev.xclient.message_type = Atoms::wmProtocols;
5319
ev.xclient.format = 32;
5320
ev.xclient.data.l[0] = Atoms::wmDeleteWindow;
5321
ev.xclient.data.l[1] = serverTime;
5322
ev.xclient.data.l[2] = 0;
5323
ev.xclient.data.l[3] = 0;
5324
ev.xclient.data.l[4] = 0;
5326
XSendEvent (screen->dpy (), priv->id, false, NoEventMask, &ev);
5330
XKillClient (screen->dpy (), priv->id);
5333
priv->closeRequests++;
5337
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5338
serverTime, priv->id, true, 0, 0);
5341
priv->lastCloseRequestTime = serverTime;
5345
PrivateWindow::handlePingTimeout (unsigned int lastPing)
5347
if (!window->isViewable ())
5350
if (!(priv->type & CompWindowTypeNormalMask))
5353
if (priv->protocols & CompWindowProtocolPingMask)
5355
if (priv->transientFor)
5358
if (priv->lastPong < lastPing)
5362
priv->alive = false;
5364
window->windowNotify (CompWindowNotifyAliveChanged);
5366
if (priv->closeRequests)
5368
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5369
priv->lastCloseRequestTime,
5370
priv->id, true, 0, 0);
5372
priv->closeRequests = 0;
5383
PrivateWindow::handlePing (int lastPing)
5389
window->windowNotify (CompWindowNotifyAliveChanged);
5391
if (priv->lastCloseRequestTime)
5393
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5394
priv->lastCloseRequestTime,
5395
priv->id, false, 0, 0);
5397
priv->lastCloseRequestTime = 0;
5400
priv->lastPong = lastPing;
5404
PrivateWindow::processMap ()
5407
bool initiallyMinimized;
5408
CompStackingUpdateMode stackingMode;
5410
priv->initialViewport = screen->vp ();
5412
priv->initialTimestampSet = false;
5414
screen->priv->applyStartupProperties (window);
5416
initiallyMinimized = (priv->hints &&
5417
priv->hints->initial_state == IconicState &&
5418
!window->minimized ());
5420
if (!serverFrame && !initiallyMinimized)
5423
priv->managed = true;
5427
int gravity = priv->sizeHints.win_gravity;
5431
/* adjust for gravity, but only for frame size */
5432
xwc.x = priv->serverGeometry.x ();
5433
xwc.y = priv->serverGeometry.y ();
5437
xwcm = adjustConfigureRequestForGravity (&xwc, CWX | CWY, gravity, 1);
5439
window->validateResizeRequest (xwcm, &xwc, ClientTypeApplication);
5441
CompPoint pos (xwc.x, xwc.y);
5442
if (window->place (pos))
5450
window->configureXWindow (xwcm, &xwc);
5452
priv->placed = true;
5455
allowFocus = allowWindowFocus (NO_FOCUS_MASK, 0);
5457
if (!allowFocus && (priv->type & ~NO_FOCUS_MASK))
5458
stackingMode = CompStackingUpdateModeInitialMapDeniedFocus;
5460
stackingMode = CompStackingUpdateModeInitialMap;
5462
window->updateAttributes (stackingMode);
5464
if (window->minimized () && !initiallyMinimized)
5465
window->unminimize ();
5467
screen->leaveShowDesktopMode (window);
5469
if (!initiallyMinimized)
5471
if (allowFocus && !window->onCurrentDesktop ());
5472
screen->priv->setCurrentDesktop (priv->desktop);
5474
if (!(priv->state & CompWindowStateHiddenMask))
5479
window->moveInputFocusTo ();
5480
if (!window->onCurrentDesktop ())
5481
screen->priv->setCurrentDesktop (priv->desktop);
5486
window->minimize ();
5487
window->changeState (window->state () | CompWindowStateHiddenMask);
5490
screen->priv->updateClientList ();
5494
* PrivateWindow::updatePassiveButtonGrabs
5496
* Updates the passive button grabs for a window. When
5497
* one of the specified button + modifier combinations
5498
* for this window is activated, compiz will be given
5499
* an active grab for the window (which we can turn off
5500
* by calling XAllowEvents later in ::handleEvent)
5502
* NOTE: ICCCM says that we are only allowed to grab
5503
* windows that we actually own as a client, so only
5504
* grab the frame window. Additionally, although there
5505
* isn't anything in the ICCCM that says we cannot
5506
* grab every button, some clients do not interpret
5507
* EnterNotify and LeaveNotify events caused by the
5508
* activation of the grab correctly, so ungrab button
5509
* and modifier combinations that we do not need on
5510
* active windows (but in reality we shouldn't be grabbing
5511
* for buttons that we don't actually need at that point
5516
PrivateWindow::updatePassiveButtonGrabs ()
5518
bool onlyActions = (priv->id == screen->priv->activeWindow ||
5519
!screen->priv->optionGetClickToFocus ());
5524
/* Ungrab everything */
5525
XUngrabButton (screen->priv->dpy, AnyButton, AnyModifier, frame);
5527
/* We don't need the full grab in the following cases:
5528
* - This window has the focus and either
5530
* - we don't want click raise
5535
if (screen->priv->optionGetRaiseOnClick ())
5537
CompWindow *highestSibling =
5538
PrivateWindow::findSiblingBelow (window, true);
5540
/* Check if this window is permitted to be raised */
5541
for (CompWindow *above = window->serverNext;
5542
above != NULL; above = above->serverNext)
5544
if (highestSibling == above)
5546
onlyActions = false;
5555
/* Grab only we have bindings on */
5556
foreach (PrivateScreen::ButtonGrab &bind, screen->priv->buttonGrabs)
5558
unsigned int mods = modHandler->virtualToRealModMask (bind.modifiers);
5560
if (mods & CompNoMask)
5563
for (unsigned int ignore = 0;
5564
ignore <= modHandler->ignoredModMask (); ignore++)
5566
if (ignore & ~modHandler->ignoredModMask ())
5569
XGrabButton (screen->priv->dpy,
5574
ButtonPressMask | ButtonReleaseMask |
5585
/* Grab everything */
5586
XGrabButton (screen->priv->dpy,
5590
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
5600
CompWindow::region () const
5602
return priv->region;
5606
CompWindow::frameRegion () const
5608
return priv->frameRegion;
5612
CompWindow::inShowDesktopMode ()
5614
return priv->inShowDesktopMode;
5618
CompWindow::setShowDesktopMode (bool value)
5620
priv->inShowDesktopMode = value;
5624
CompWindow::managed ()
5626
WRAPABLE_HND_FUNC_RETURN (18, bool, managed);
5627
return priv->managed;
5631
CompWindow::grabbed ()
5633
return priv->grabbed;
5637
CompWindow::pendingMaps ()
5639
return priv->pendingMaps;
5643
CompWindow::wmType ()
5645
return priv->wmType;
5649
CompWindow::activeNum ()
5651
return priv->activeNum;
5655
CompWindow::frame ()
5657
return priv->serverFrame;
5661
CompWindow::resName ()
5664
return priv->resName;
5666
return CompString ();
5670
CompWindow::mapNum () const
5672
return priv->mapNum;
5676
CompWindow::struts ()
5678
return priv->struts;
5682
CompWindow::saveMask ()
5684
return priv->saveMask;
5688
CompWindow::saveWc ()
5690
return priv->saveWc;
5694
CompWindow::moveToViewportPosition (int x,
5699
int vWidth = screen->width () * screen->vpSize ().width ();
5700
int vHeight = screen->height () * screen->vpSize ().height ();
5702
if (screen->vpSize ().width () != 1)
5704
x += screen->vp ().x () * screen->width ();
5705
x = MOD (x, vWidth);
5706
x -= screen->vp ().x () * screen->width ();
5709
if (screen->vpSize ().height () != 1)
5711
y += screen->vp ().y () * screen->height ();
5712
y = MOD (y, vHeight);
5713
y -= screen->vp ().y () * screen->height ();
5716
tx = x - priv->geometry.x ();
5717
ty = y - priv->geometry.y ();
5721
unsigned int valueMask = CWX | CWY;
5728
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5731
if (priv->state & CompWindowStateStickyMask)
5737
if (screen->vpSize ().width ()!= 1)
5739
m = priv->geometry.x () + tx;
5741
if (m - priv->output.left < (int) screen->width () - vWidth)
5743
else if (m + priv->width + priv->output.right > vWidth)
5747
if (screen->vpSize ().height () != 1)
5749
m = priv->geometry.y () + ty;
5751
if (m - priv->output.top < (int) screen->height () - vHeight)
5753
else if (m + priv->height + priv->output.bottom > vHeight)
5757
if (priv->saveMask & CWX)
5758
priv->saveWc.x += wx;
5760
if (priv->saveMask & CWY)
5761
priv->saveWc.y += wy;
5763
xwc.x = serverGeometry ().x () + wx;
5764
xwc.y = serverGeometry ().y () + wy;
5766
configureXWindow (valueMask, &xwc);
5771
CompWindow::startupId ()
5773
return priv->startupId;
5777
PrivateWindow::applyStartupProperties (CompStartupSequence *s)
5781
priv->initialViewport.setX (s->viewportX);
5782
priv->initialViewport.setY (s->viewportY);
5784
workspace = sn_startup_sequence_get_workspace (s->sequence);
5786
window->setDesktop (workspace);
5788
priv->initialTimestamp =
5789
sn_startup_sequence_get_timestamp (s->sequence);
5790
priv->initialTimestampSet = true;
5794
CompWindow::desktop ()
5796
return priv->desktop;
5800
CompWindow::clientLeader (bool checkAncestor)
5802
if (priv->clientLeader)
5803
return priv->clientLeader;
5806
return priv->getClientLeaderOfAncestor ();
5812
CompWindow::transientFor ()
5814
return priv->transientFor;
5818
CompWindow::pendingUnmaps ()
5820
return priv->pendingUnmaps;
5824
CompWindow::minimized ()
5826
WRAPABLE_HND_FUNC_RETURN (15, bool, minimized);
5827
return priv->minimized;
5831
CompWindow::placed ()
5833
return priv->placed;
5837
CompWindow::shaded ()
5839
return priv->shaded;
5843
CompWindow::border () const
5845
return priv->border;
5849
CompWindow::input () const
5851
return priv->serverInput;
5855
CompWindow::output () const
5857
return priv->output;
5861
CompWindow::sizeHints () const
5863
return priv->sizeHints;
5867
PrivateWindow::updateMwmHints ()
5869
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
5870
window->recalcActions ();
5874
PrivateWindow::updateStartupId ()
5876
char *oldId = startupId;
5879
startupId = getStartupId ();
5881
if (oldId && startupId)
5883
if (strcmp (startupId, oldId) == 0)
5887
if (managed && startupId && newId)
5894
initialTimestampSet = false;
5895
screen->priv->applyStartupProperties (window);
5897
if (initialTimestampSet)
5898
timestamp = initialTimestamp;
5900
/* as the viewport can't be transmitted via startup
5901
notification, assume the client changing the ID
5902
wanted to activate the window on the current viewport */
5904
vp = window->defaultViewport ();
5905
svp = screen->vp ();
5908
x = window->geometry ().x () + (svp.x () - vp.x ()) * size.width ();
5909
y = window->geometry ().y () + (svp.y () - vp.y ()) * size.height ();
5910
window->moveToViewportPosition (x, y, true);
5912
if (allowWindowFocus (0, timestamp))
5913
window->activate ();
5921
CompWindow::destroyed ()
5923
return priv->destroyed;
5927
CompWindow::invisible ()
5929
return priv->invisible;
5933
CompWindow::syncAlarm ()
5935
return priv->syncAlarm;
5939
CoreWindow::manage (Window aboveId, XWindowAttributes &wa)
5941
return new CompWindow (aboveId, wa, priv);
5944
CoreWindow::CoreWindow (Window id)
5946
priv = new PrivateWindow ();
5949
priv->serverId = id;
5952
CompWindow::CompWindow (Window aboveId,
5953
XWindowAttributes &wa,
5954
PrivateWindow *priv) :
5955
PluginClassStorage (windowPluginClassIndices),
5958
StackDebugger *dbg = StackDebugger::Default ();
5960
// TODO: Reparent first!
5962
priv->window = this;
5964
screen->insertWindow (this, aboveId);
5965
screen->insertServerWindow (this, aboveId);
5967
/* We must immediately insert the window into the debugging
5970
dbg->overrideRedirectRestack (priv->id, aboveId);
5972
gettimeofday (&priv->lastConfigureRequest, NULL);
5975
priv->serverGeometry.set (priv->attrib.x, priv->attrib.y,
5976
priv->attrib.width, priv->attrib.height,
5977
priv->attrib.border_width);
5978
priv->serverFrameGeometry = priv->frameGeometry = priv->syncGeometry
5979
= priv->geometry = priv->serverGeometry;
5981
priv->width = priv->attrib.width + priv->attrib.border_width * 2;
5982
priv->height = priv->attrib.height + priv->attrib.border_width * 2;
5984
priv->sizeHints.flags = 0;
5986
priv->recalcNormalHints ();
5988
priv->transientFor = None;
5989
priv->clientLeader = None;
5991
XSelectInput (screen->dpy (), priv->id,
5992
wa.your_event_mask |
5993
PropertyChangeMask |
5997
priv->alpha = (priv->attrib.depth == 32);
5998
priv->lastPong = screen->priv->lastPing;
6000
if (screen->XShape ())
6001
XShapeSelectInput (screen->dpy (), priv->id, ShapeNotifyMask);
6003
if (priv->attrib.c_class != InputOnly)
6005
priv->region = CompRegion (priv->attrib.x, priv->attrib.y,
6006
priv->width, priv->height);
6007
priv->inputRegion = priv->region;
6009
/* need to check for DisplayModal state on all windows */
6010
priv->state = screen->priv->getWindowState (priv->id);
6012
priv->updateClassHints ();
6016
priv->attrib.map_state = IsUnmapped;
6019
priv->wmType = screen->priv->getWindowType (priv->id);
6020
priv->protocols = screen->priv->getProtocols (priv->id);
6022
if (!overrideRedirect ())
6024
priv->updateNormalHints ();
6026
priv->updateWmHints ();
6027
priv->updateTransientHint ();
6029
priv->clientLeader = priv->getClientLeader ();
6030
priv->startupId = priv->getStartupId ();
6034
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
6036
if (!(priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask)))
6038
priv->desktop = screen->getWindowProp (priv->id, Atoms::winDesktop,
6040
if (priv->desktop != 0xffffffff)
6042
if (priv->desktop >= screen->nDesktop ())
6043
priv->desktop = screen->currentDesktop ();
6052
if (priv->attrib.map_state == IsViewable)
6054
priv->placed = true;
6056
if (!overrideRedirect ())
6058
// needs to happen right after maprequest
6059
if (!priv->serverFrame)
6061
priv->managed = true;
6063
if (screen->priv->getWmState (priv->id) == IconicState)
6065
if (priv->state & CompWindowStateShadedMask)
6066
priv->shaded = true;
6068
priv->minimized = true;
6072
if (priv->wmType & (CompWindowTypeDockMask |
6073
CompWindowTypeDesktopMask))
6075
setDesktop (0xffffffff);
6079
if (priv->desktop != 0xffffffff)
6080
priv->desktop = screen->currentDesktop ();
6082
screen->setWindowProp (priv->id, Atoms::winDesktop,
6088
priv->attrib.map_state = IsUnmapped;
6089
priv->pendingMaps++;
6093
updateAttributes (CompStackingUpdateModeNormal);
6095
if (priv->minimized || priv->inShowDesktopMode ||
6096
priv->hidden || priv->shaded)
6098
priv->state |= CompWindowStateHiddenMask;
6100
priv->pendingUnmaps++;
6102
if (priv->serverFrame && !priv->shaded)
6103
XUnmapWindow (screen->dpy (), priv->serverFrame);
6105
XUnmapWindow (screen->dpy (), priv->id);
6107
screen->priv->setWindowState (priv->state, priv->id);
6110
else if (!overrideRedirect ())
6112
if (screen->priv->getWmState (priv->id) == IconicState)
6114
// before everything else in maprequest
6115
if (!priv->serverFrame)
6117
priv->managed = true;
6118
priv->placed = true;
6120
if (priv->state & CompWindowStateHiddenMask)
6122
if (priv->state & CompWindowStateShadedMask)
6123
priv->shaded = true;
6125
priv->minimized = true;
6130
/* TODO: bailout properly when objectInitPlugins fails */
6131
assert (CompPlugin::windowInitPlugins (this));
6134
priv->updateIconGeometry ();
6138
priv->geometry.setHeight (priv->geometry.height () + 1);
6139
resize (priv->geometry.x (), priv->geometry.y (),
6140
priv->geometry.width (), priv->geometry.height () - 1,
6141
priv->geometry.border ());
6144
if (priv->attrib.map_state == IsViewable)
6146
priv->invisible = WINDOW_INVISIBLE (priv);
6150
CompWindow::~CompWindow ()
6152
if (priv->serverFrame)
6153
priv->unreparent ();
6155
/* Update the references of other windows
6156
* pending destroy if this was a sibling
6157
* of one of those */
6159
screen->priv->destroyedWindows.remove (this);
6161
foreach (CompWindow *dw, screen->priv->destroyedWindows)
6163
if (dw->next == this)
6164
dw->next = this->next;
6165
if (dw->prev == this)
6166
dw->prev = this->prev;
6168
if (dw->serverNext == this)
6169
dw->serverNext = this->serverNext;
6170
if (dw->serverPrev == this)
6171
dw->serverPrev = this->serverPrev;
6174
/* If this window has a detached frame, destroy it, but only
6175
* using XDestroyWindow since there may be pending restack
6176
* requests relative to it */
6178
std::map <CompWindow *, CompWindow *>::iterator it =
6179
screen->priv->detachedFrameWindows.find (this);
6181
if (it != screen->priv->detachedFrameWindows.end ())
6183
CompWindow *fw = (it->second);
6185
XDestroyWindow (screen->dpy (), fw->id ());
6186
screen->priv->detachedFrameWindows.erase (it);
6189
if (!priv->destroyed)
6191
StackDebugger *dbg = StackDebugger::Default ();
6193
screen->unhookWindow (this);
6194
screen->unhookServerWindow (this);
6196
/* We must immediately insert the window into the debugging
6199
dbg->removeServerWindow (id ());
6201
/* restore saved geometry and map if hidden */
6202
if (!priv->attrib.override_redirect)
6205
XConfigureWindow (screen->dpy (), priv->id,
6206
priv->saveMask, &priv->saveWc);
6210
if (priv->state & CompWindowStateHiddenMask)
6211
XMapWindow (screen->dpy (), priv->id);
6215
if (screen->XShape ())
6216
XShapeSelectInput (screen->dpy (), priv->id, NoEventMask);
6218
if (priv->id != screen->priv->grabWindow)
6219
XSelectInput (screen->dpy (), priv->id, NoEventMask);
6221
XUngrabButton (screen->dpy (), AnyButton, AnyModifier, priv->id);
6225
if (priv->attrib.map_state == IsViewable)
6227
if (priv->type == CompWindowTypeDesktopMask)
6228
screen->priv->desktopWindowCount--;
6230
if (priv->destroyed && priv->struts)
6231
screen->updateWorkarea ();
6234
if (priv->destroyed)
6235
screen->priv->updateClientList ();
6237
CompPlugin::windowFiniPlugins (this);
6242
PrivateWindow::PrivateWindow () :
6251
transientFor (None),
6252
clientLeader (None),
6260
type (CompWindowTypeUnknownMask),
6264
mwmDecor (MwmDecorAll),
6265
mwmFunc (MwmFuncAll),
6273
initialViewport (0, 0),
6275
initialTimestamp (0),
6276
initialTimestampSet (false),
6278
fullscreenMonitorsSet (false),
6282
inShowDesktopMode (false),
6291
pendingPositionUpdates (false),
6313
closeRequests (false),
6314
lastCloseRequestTime (0)
6321
serverInput.left = 0;
6322
serverInput.right = 0;
6323
serverInput.top = 0;
6324
serverInput.bottom = 0;
6336
syncWaitTimer.setTimes (1000, 1200);
6337
syncWaitTimer.setCallback (boost::bind (&PrivateWindow::handleSyncAlarm,
6341
PrivateWindow::~PrivateWindow ()
6344
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
6346
syncWaitTimer.stop ();
6349
XDestroyWindow (screen->dpy (), serverFrame);
6351
XDestroyWindow (screen->dpy (), frame);
6373
CompWindow::syncWait ()
6375
return priv->syncWait;
6379
CompWindow::alpha ()
6381
WRAPABLE_HND_FUNC_RETURN (16, bool, alpha);
6387
CompWindow::overrideRedirect ()
6389
return priv->attrib.override_redirect;
6393
PrivateWindow::setOverrideRedirect (bool overrideRedirect)
6395
if (overrideRedirect == window->overrideRedirect ())
6398
priv->attrib.override_redirect = overrideRedirect ? 1 : 0;
6399
window->recalcType ();
6400
window->recalcActions ();
6402
screen->matchPropertyChanged (window);
6406
CompWindow::isMapped () const
6408
return priv->mapNum > 0;
6412
CompWindow::isViewable () const
6414
return (priv->attrib.map_state == IsViewable);
6418
CompWindow::isFocussable ()
6420
WRAPABLE_HND_FUNC_RETURN (17, bool, isFocussable);
6422
if (priv->inputHint)
6425
if (priv->protocols & CompWindowProtocolTakeFocusMask)
6432
CompWindow::windowClass ()
6434
return priv->attrib.c_class;
6438
CompWindow::depth ()
6440
return priv->attrib.depth;
6444
CompWindow::alive ()
6450
CompWindow::mwmDecor ()
6452
return priv->mwmDecor;
6456
CompWindow::mwmFunc ()
6458
return priv->mwmFunc;
6461
/* TODO: This function should be able to check the XShape event
6462
* kind and only get/set shape rectangles for either ShapeInput
6463
* or ShapeBounding, but not both at the same time
6467
CompWindow::updateFrameRegion ()
6469
if (priv->serverFrame &&
6470
priv->serverGeometry.width () == priv->geometry.width () &&
6471
priv->serverGeometry.height () == priv->geometry.height ())
6476
priv->frameRegion = CompRegion ();
6478
updateFrameRegion (priv->frameRegion);
6482
r = priv->region.boundingRect ();
6483
priv->frameRegion -= r;
6485
r.setGeometry (r.x1 () - priv->input.left,
6486
r.y1 () - priv->input.top,
6487
r.width () + priv->input.right + priv->input.left,
6488
r.height () + priv->input.bottom + priv->input.top);
6490
priv->frameRegion &= CompRegion (r);
6493
x = priv->geometry.x () - priv->input.left;
6494
y = priv->geometry.y () - priv->input.top;
6496
XShapeCombineRegion (screen->dpy (), priv->serverFrame,
6497
ShapeBounding, -x, -y,
6498
priv->frameRegion.united (priv->region).handle (),
6501
XShapeCombineRegion (screen->dpy (), priv->serverFrame,
6503
priv->frameRegion.united (priv->inputRegion).handle (),
6509
CompWindow::setWindowFrameExtents (CompWindowExtents *b,
6510
CompWindowExtents *i)
6512
/* Input extents are used for frame size,
6513
* Border extents used for placement.
6519
if (priv->serverInput.left != i->left ||
6520
priv->serverInput.right != i->right ||
6521
priv->serverInput.top != i->top ||
6522
priv->serverInput.bottom != i->bottom ||
6523
priv->border.left != b->left ||
6524
priv->border.right != b->right ||
6525
priv->border.top != b->top ||
6526
priv->border.bottom != b->bottom)
6528
unsigned long data[4];
6530
priv->serverInput = *i;
6535
/* Use b for _NET_WM_FRAME_EXTENTS here because
6536
* that is the representation of the actual decoration
6537
* around the window that the user sees and should
6538
* be used for placement and such */
6543
data[3] = b->bottom;
6545
XChangeProperty (screen->dpy (), priv->id,
6546
Atoms::frameExtents,
6547
XA_CARDINAL, 32, PropModeReplace,
6548
(unsigned char *) data, 4);
6550
priv->updateSize ();
6551
priv->updateFrameWindow ();
6556
CompWindow::hasUnmapReference ()
6558
return (priv && priv->unmapRefCnt > 1);
6562
CompWindow::updateFrameRegion (CompRegion& region)
6563
WRAPABLE_HND_FUNC (12, updateFrameRegion, region)
6566
PrivateWindow::reparent ()
6568
XSetWindowAttributes attr;
6569
XWindowAttributes wa;
6572
unsigned int nchildren;
6573
Window *children, root_return, parent_return;
6574
Display *dpy = screen->dpy ();
6575
Visual *visual = DefaultVisual (screen->dpy (),
6576
screen->screenNum ());
6577
Colormap cmap = DefaultColormap (screen->dpy (),
6578
screen->screenNum ());
6586
if (!XGetWindowAttributes (dpy, id, &wa))
6588
XUngrabServer (dpy);
6593
if (wa.override_redirect)
6596
XSelectInput (dpy, id, NoEventMask);
6598
/* Don't ever reparent windows which have ended up
6599
* reparented themselves on the server side but not
6600
* on the client side */
6602
XQueryTree (dpy, id, &root_return, &parent_return, &children, &nchildren);
6604
if (parent_return != root_return)
6607
XUngrabServer (dpy);
6614
XQueryTree (dpy, root_return, &root_return, &parent_return, &children, &nchildren);
6616
XChangeSaveSet (dpy, id, SetModeInsert);
6618
/* Force border width to 0 */
6619
xwc.border_width = 0;
6620
XConfigureWindow (dpy, id, CWBorderWidth, &xwc);
6622
priv->serverGeometry.setBorder (0);
6624
mask = CWBorderPixel | CWColormap | CWBackPixmap | CWOverrideRedirect;
6632
attr.background_pixmap = None;
6633
attr.border_pixel = 0;
6634
attr.colormap = cmap;
6635
attr.override_redirect = true;
6637
/* Look for existing detached frame windows and reattach them
6638
* in case this window as reparented again after being withdrawn */
6639
std::map <CompWindow *, CompWindow *>::iterator it =
6640
screen->priv->detachedFrameWindows.find (window);
6642
if (it != screen->priv->detachedFrameWindows.end ())
6644
/* Trash the old frame window
6645
* TODO: It would be nicer if we could just
6646
* reparent back into it, but there are some
6647
* problems with that */
6649
XDestroyWindow (dpy, (it->second)->id ());
6650
screen->priv->detachedFrameWindows.erase (it);
6653
/* We need to know when the frame window is created
6655
XSelectInput (dpy, screen->root (), SubstructureNotifyMask);
6657
/* Awaiting a new frame to be given to us */
6659
serverFrame = XCreateWindow (dpy, screen->root (), 0, 0,
6660
wa.width, wa.height, 0, wa.depth,
6661
InputOutput, visual, mask, &attr);
6663
/* Do not get any events from here on */
6664
XSelectInput (dpy, screen->root (), NoEventMask);
6666
wrapper = XCreateWindow (dpy, serverFrame, 0, 0,
6667
wa.width, wa.height, 0, wa.depth,
6668
InputOutput, visual, mask, &attr);
6670
xwc.stack_mode = Above;
6672
/* Look for the client in the current server side stacking
6673
* order and put the frame above what the client is above
6678
/* client at the bottom */
6679
xwc.stack_mode = Below;
6684
for (unsigned int i = 0; i < nchildren; i++)
6686
if (i < nchildren - 1)
6688
if (children[i + 1] == id)
6690
xwc.sibling = children[i];
6694
else /* client on top */
6695
xwc.sibling = children[i];
6701
/* Make sure the frame is underneath the client */
6702
XConfigureWindow (dpy, serverFrame, CWSibling | CWStackMode, &xwc);
6704
/* Wait for the restacking to finish */
6707
/* Always need to have the wrapper window mapped */
6708
XMapWindow (dpy, wrapper);
6710
/* Reparent the client into the wrapper window */
6711
XReparentWindow (dpy, id, wrapper, 0, 0);
6713
/* Restore events */
6714
attr.event_mask = wa.your_event_mask;
6716
/* We don't care about client events on the frame, and listening for them
6717
* will probably end up fighting the client anyways, so disable them */
6719
attr.do_not_propagate_mask = KeyPressMask | KeyReleaseMask |
6720
ButtonPressMask | ButtonReleaseMask |
6721
EnterWindowMask | LeaveWindowMask |
6722
PointerMotionMask | PointerMotionHintMask |
6723
Button1MotionMask | Button2MotionMask |
6724
Button3MotionMask | Button4MotionMask |
6725
Button5MotionMask | ButtonMotionMask |
6726
KeymapStateMask | ExposureMask |
6727
VisibilityChangeMask | StructureNotifyMask |
6728
ResizeRedirectMask | SubstructureNotifyMask |
6729
SubstructureRedirectMask | FocusChangeMask |
6730
PropertyChangeMask | ColormapChangeMask |
6731
OwnerGrabButtonMask;
6733
XChangeWindowAttributes (dpy, id, CWEventMask | CWDontPropagate, &attr);
6735
if (wa.map_state == IsViewable || shaded)
6736
XMapWindow (dpy, serverFrame);
6738
attr.event_mask = SubstructureRedirectMask |
6739
SubstructureNotifyMask | EnterWindowMask |
6742
serverFrameGeometry = serverGeometry;
6744
XMoveResizeWindow (dpy, serverFrame, serverFrameGeometry.x (), serverFrameGeometry.y (),
6745
serverFrameGeometry.width (), serverFrameGeometry.height ());
6747
XSelectInput (dpy, screen->root (),
6748
SubstructureRedirectMask |
6749
SubstructureNotifyMask |
6750
StructureNotifyMask |
6751
PropertyChangeMask |
6761
XChangeWindowAttributes (dpy, serverFrame, CWEventMask, &attr);
6762
XChangeWindowAttributes (dpy, wrapper, CWEventMask, &attr);
6764
XUngrabServer (dpy);
6767
window->windowNotify (CompWindowNotifyReparent);
6773
PrivateWindow::unreparent ()
6775
Display *dpy = screen->dpy ();
6779
unsigned int nchildren;
6780
Window *children = NULL, root_return, parent_return;
6781
XWindowAttributes wa;
6782
StackDebugger *dbg = StackDebugger::Default ();
6789
if (XCheckTypedWindowEvent (dpy, id, DestroyNotify, &e))
6791
XPutBackEvent (dpy, &e);
6796
if (!XGetWindowAttributes (dpy, id, &wa))
6800
/* Also don't reparent back into root windows that have ended up
6801
* reparented into other windows (and as such we are unmanaging them) */
6805
XQueryTree (dpy, id, &root_return, &parent_return, &children, &nchildren);
6807
if (parent_return != wrapper)
6811
if ((!destroyed) && alive)
6815
XChangeSaveSet (dpy, id, SetModeDelete);
6816
XSelectInput (dpy, serverFrame, NoEventMask);
6817
XSelectInput (dpy, wrapper, NoEventMask);
6818
XSelectInput (dpy, id, NoEventMask);
6819
XSelectInput (dpy, screen->root (), NoEventMask);
6820
XReparentWindow (dpy, id, screen->root (), 0, 0);
6822
/* Wait for the reparent to finish */
6825
xwc.x = serverGeometry.x () - serverGeometry.border ();
6826
xwc.y = serverGeometry.y () - serverGeometry.border ();
6827
xwc.width = serverGeometry.width () + serverGeometry.border () * 2;
6828
xwc.height = serverGeometry.height () + serverGeometry.border () * 2;
6830
XConfigureWindow (dpy, serverFrame, CWX | CWY | CWWidth | CWHeight, &xwc);
6833
xwc.stack_mode = Below;
6834
xwc.sibling = serverFrame;
6835
XConfigureWindow (dpy, id, CWSibling | CWStackMode, &xwc);
6837
/* Wait for the window to be restacked */
6840
XUnmapWindow (dpy, serverFrame);
6842
XSelectInput (dpy, id, wa.your_event_mask);
6844
XSelectInput (dpy, screen->root (),
6845
SubstructureRedirectMask |
6846
SubstructureNotifyMask |
6847
StructureNotifyMask |
6848
PropertyChangeMask |
6858
XUngrabServer (dpy);
6861
XMoveWindow (dpy, id, serverGeometry.x (), serverGeometry.y ());
6868
dbg->addDestroyedFrame (serverFrame);
6870
/* This is where things get tricky ... it is possible
6871
* to receive a ConfigureNotify relative to a frame window
6872
* for a destroyed window in case we process a ConfigureRequest
6873
* for the destroyed window and then a DestroyNotify for it directly
6874
* afterwards. In that case, we will receive the ConfigureNotify
6875
* for the XConfigureWindow request we made relative to that frame
6876
* window. Because of this, we must keep the frame window in the stack
6877
* as a new toplevel window so that the ConfigureNotify will be processed
6878
* properly until it too receives a DestroyNotify */
6882
XWindowAttributes attrib;
6884
/* It's possible that the frame window was already destroyed because
6885
* the client was unreparented before it was destroyed (eg
6886
* UnmapNotify before DestroyNotify). In that case the frame window
6887
* is going to be an invalid window but since we haven't received
6888
* a DestroyNotify for it yet, it is possible that restacking
6889
* operations could occurr relative to it so we need to hold it
6890
* in the stack for now. Ensure that it is marked override redirect */
6891
XGetWindowAttributes (screen->dpy (), serverFrame, &attrib);
6893
/* Put the frame window "above" the client window
6895
CoreWindow *cw = new CoreWindow (serverFrame);
6896
CompWindow *fw = cw->manage (id, attrib);
6897
screen->priv->createdWindows.remove (cw);
6900
/* Put this window in the list of "detached frame windows"
6901
* so that we can reattach it or destroy it when we are
6904
screen->priv->detachedFrameWindows[window] = fw;
6907
/* Safe to destroy the wrapper but not the frame */
6908
XUnmapWindow (screen->dpy (), serverFrame);
6909
XDestroyWindow (screen->dpy (), wrapper);
6915
window->windowNotify (CompWindowNotifyUnreparent);