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>
27
#include <X11/Xatom.h>
28
#include <X11/Xproto.h>
29
#include <X11/extensions/shape.h>
39
#include <boost/bind.hpp>
41
#include <core/icon.h>
42
#include <core/atoms.h>
43
#include "core/windowconstrainment.h"
44
#include "privatewindow.h"
45
#include "privatescreen.h"
46
#include "privatestackdebugger.h"
48
#define XWINDOWCHANGES_INIT {0, 0, 0, 0, 0, None, 0}
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
/* 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->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;
607
if (priv->serverInput.top)
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
/* Don't allow maximization or fullscreen
628
* of windows which are too big to fit
630
bool foundVert = false;
631
bool foundHorz = false;
633
foreach (CompOutput &o, screen->outputDevs ())
635
if (o.width () > (priv->sizeHints.min_width + priv->border.left + priv->border.right))
637
if (o.height () > (priv->sizeHints.min_height + priv->border.top + priv->border.bottom))
643
actions &= ~(CompWindowActionMaximizeHorzMask |
644
CompWindowActionFullscreenMask);
649
actions &= ~(CompWindowActionMaximizeVertMask |
650
CompWindowActionFullscreenMask);
653
if (!(priv->mwmFunc & MwmFuncAll))
655
if (!(priv->mwmFunc & MwmFuncResize))
656
actions &= ~(CompWindowActionResizeMask |
657
CompWindowActionMaximizeHorzMask |
658
CompWindowActionMaximizeVertMask |
659
CompWindowActionFullscreenMask);
661
if (!(priv->mwmFunc & MwmFuncMove))
662
actions &= ~(CompWindowActionMoveMask |
663
CompWindowActionMaximizeHorzMask |
664
CompWindowActionMaximizeVertMask |
665
CompWindowActionFullscreenMask);
667
if (!(priv->mwmFunc & MwmFuncIconify))
668
actions &= ~CompWindowActionMinimizeMask;
670
if (!(priv->mwmFunc & MwmFuncClose))
671
actions &= ~CompWindowActionCloseMask;
674
getAllowedActions (setActions, clearActions);
675
actions &= ~clearActions;
676
actions |= setActions;
678
if (actions != priv->actions)
680
priv->actions = actions;
681
setWindowActions (screen, actions, priv->id);
686
CompWindow::getAllowedActions (unsigned int &setActions,
687
unsigned int &clearActions)
689
WRAPABLE_HND_FUNCTN (getAllowedActions, setActions, clearActions)
696
CompWindow::constrainWindowState (unsigned int state,
697
unsigned int actions)
699
if (!(actions & CompWindowActionMaximizeHorzMask))
700
state &= ~CompWindowStateMaximizedHorzMask;
702
if (!(actions & CompWindowActionMaximizeVertMask))
703
state &= ~CompWindowStateMaximizedVertMask;
705
if (!(actions & CompWindowActionShadeMask))
706
state &= ~CompWindowStateShadedMask;
708
if (!(actions & CompWindowActionFullscreenMask))
709
state &= ~CompWindowStateFullscreenMask;
715
PrivateWindow::windowTypeFromString (const char *str)
717
if (strcasecmp (str, "desktop") == 0)
718
return CompWindowTypeDesktopMask;
719
else if (strcasecmp (str, "dock") == 0)
720
return CompWindowTypeDockMask;
721
else if (strcasecmp (str, "toolbar") == 0)
722
return CompWindowTypeToolbarMask;
723
else if (strcasecmp (str, "menu") == 0)
724
return CompWindowTypeMenuMask;
725
else if (strcasecmp (str, "utility") == 0)
726
return CompWindowTypeUtilMask;
727
else if (strcasecmp (str, "splash") == 0)
728
return CompWindowTypeSplashMask;
729
else if (strcasecmp (str, "dialog") == 0)
730
return CompWindowTypeDialogMask;
731
else if (strcasecmp (str, "normal") == 0)
732
return CompWindowTypeNormalMask;
733
else if (strcasecmp (str, "dropdownmenu") == 0)
734
return CompWindowTypeDropdownMenuMask;
735
else if (strcasecmp (str, "popupmenu") == 0)
736
return CompWindowTypePopupMenuMask;
737
else if (strcasecmp (str, "tooltip") == 0)
738
return CompWindowTypeTooltipMask;
739
else if (strcasecmp (str, "notification") == 0)
740
return CompWindowTypeNotificationMask;
741
else if (strcasecmp (str, "combo") == 0)
742
return CompWindowTypeComboMask;
743
else if (strcasecmp (str, "dnd") == 0)
744
return CompWindowTypeDndMask;
745
else if (strcasecmp (str, "modaldialog") == 0)
746
return CompWindowTypeModalDialogMask;
747
else if (strcasecmp (str, "fullscreen") == 0)
748
return CompWindowTypeFullscreenMask;
749
else if (strcasecmp (str, "unknown") == 0)
750
return CompWindowTypeUnknownMask;
751
else if (strcasecmp (str, "any") == 0)
758
CompWindow::recalcType ()
764
if (!overrideRedirect () && priv->wmType == CompWindowTypeUnknownMask)
765
type = CompWindowTypeNormalMask;
767
if (priv->state & CompWindowStateFullscreenMask)
768
type = CompWindowTypeFullscreenMask;
770
if (type == CompWindowTypeNormalMask)
772
if (priv->transientFor)
773
type = CompWindowTypeDialogMask;
776
if (type == CompWindowTypeDockMask &&
777
(priv->state & CompWindowStateBelowMask))
779
type = CompWindowTypeNormalMask;
782
if ((type & (CompWindowTypeNormalMask | CompWindowTypeDialogMask)) &&
783
(priv->state & CompWindowStateModalMask))
785
type = CompWindowTypeModalDialogMask;
793
PrivateWindow::updateFrameWindow ()
795
XWindowChanges xwc = XWINDOWCHANGES_INIT;
796
unsigned int valueMask = CWX | CWY | CWWidth | CWHeight;
802
gettimeofday (&lastConfigureRequest, NULL);
803
/* Flush any changes made to serverFrameGeometry or serverGeometry to the server
804
* since there is a race condition where geometries will go out-of-sync with
807
window->syncPosition ();
809
if (serverInput.left || serverInput.right || serverInput.top || serverInput.bottom)
811
int bw = serverGeometry.border () * 2;
813
xwc.x = serverGeometry.x () - serverInput.left;
814
xwc.y = serverGeometry.y () - serverInput.top;
815
xwc.width = serverGeometry.width () + serverInput.left + serverInput.right + bw;
817
xwc.height = serverInput.top + serverInput.bottom + bw;
819
xwc.height = serverGeometry.height () + serverInput.top + serverInput.bottom + bw;
822
height = serverInput.top + serverInput.bottom;
824
if (serverFrameGeometry.x () == xwc.x)
827
serverFrameGeometry.setX (xwc.x);
829
if (serverFrameGeometry.y () == xwc.y)
832
serverFrameGeometry.setY (xwc.y);
834
if (serverFrameGeometry.width () == xwc.width)
835
valueMask &= ~(CWWidth);
837
serverFrameGeometry.setWidth (xwc.width);
839
if (serverFrameGeometry.height () == xwc.height)
840
valueMask &= ~(CWHeight);
842
serverFrameGeometry.setHeight (xwc.height);
844
/* Geometry is the same, so we're not going to get a ConfigureNotify
845
* event when the window is configured, which means that other plugins
846
* won't know that the client, frame and wrapper windows got shifted
847
* around (and might result in display corruption, eg in OpenGL */
851
XWindowAttributes attrib;
852
unsigned int nchildren = 0;
853
Window rootRet = 0, parentRet = 0;
854
Window *children = NULL;
856
xev.type = ConfigureNotify;
857
xev.event = screen->root ();
858
xev.window = priv->serverFrame;
860
XGrabServer (screen->dpy ());
862
if (XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib))
866
xev.width = attrib.width;
867
xev.height = attrib.height;
868
xev.border_width = attrib.border_width;
871
/* We need to ensure that the stacking order is
872
* based on the current server stacking order so
873
* find the sibling to this window's frame in the
874
* server side stack and stack above that */
875
XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
879
for (unsigned int i = 0; i < nchildren; i++)
881
if (i + 1 == nchildren ||
882
children[i + 1] == ROOTPARENT (window))
884
xev.above = children[i];
894
xev.above = (window->serverPrev) ? ROOTPARENT (window->serverPrev) : None;
896
xev.override_redirect = priv->attrib.override_redirect;
900
compiz::X11::PendingEvent::Ptr pc =
901
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
902
new compiz::X11::PendingConfigureEvent (
903
screen->dpy (), serverFrame, valueMask, &xwc)));
905
pendingConfigures.add (pc);
906
if (priv->mClearCheckTimeout.active ())
907
priv->mClearCheckTimeout.stop ();
908
priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv),
911
XSendEvent (screen->dpy (), screen->root (), false,
912
SubstructureNotifyMask, (XEvent *) &xev);
914
XUngrabServer (screen->dpy ());
915
XSync (screen->dpy (), false);
919
compiz::X11::PendingEvent::Ptr pc =
920
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
921
new compiz::X11::PendingConfigureEvent (
922
screen->dpy (), serverFrame, valueMask, &xwc)));
924
pendingConfigures.add (pc);
925
if (priv->mClearCheckTimeout.active ())
926
priv->mClearCheckTimeout.stop ();
927
priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv),
929
XConfigureWindow (screen->dpy (), serverFrame, valueMask, &xwc);
934
XUnmapWindow (screen->dpy (), wrapper);
938
XMapWindow (screen->dpy (), wrapper);
939
XMoveResizeWindow (screen->dpy (), wrapper, serverInput.left, serverInput.top,
940
serverGeometry.width (), serverGeometry.height ());
942
XMoveResizeWindow (screen->dpy (), id, 0, 0,
943
serverGeometry.width (), serverGeometry.height ());
944
window->sendConfigureNotify ();
945
window->windowNotify (CompWindowNotifyFrameUpdate);
949
int bw = serverGeometry.border () * 2;
951
xwc.x = serverGeometry.x ();
952
xwc.y = serverGeometry.y ();
953
xwc.width = serverGeometry.width () + bw;
955
/* FIXME: It doesn't make much sense to allow undecorated windows to be
960
xwc.height = serverGeometry.height () + bw;
962
if (serverFrameGeometry.x () == xwc.x)
965
serverFrameGeometry.setX (xwc.x);
967
if (serverFrameGeometry.y () == xwc.y)
970
serverFrameGeometry.setY (xwc.y);
972
if (serverFrameGeometry.width () == xwc.width)
973
valueMask &= ~(CWWidth);
975
serverFrameGeometry.setWidth (xwc.width);
977
if (serverFrameGeometry.height () == xwc.height)
978
valueMask &= ~(CWHeight);
980
serverFrameGeometry.setHeight (xwc.height);
982
/* Geometry is the same, so we're not going to get a ConfigureNotify
983
* event when the window is configured, which means that other plugins
984
* won't know that the client, frame and wrapper windows got shifted
985
* around (and might result in display corruption, eg in OpenGL */
989
XWindowAttributes attrib;
990
unsigned int nchildren = 0;
991
Window rootRet = 0, parentRet = 0;
992
Window *children = NULL;
994
xev.type = ConfigureNotify;
995
xev.event = screen->root ();
996
xev.window = priv->serverFrame;
998
XGrabServer (screen->dpy ());
1000
if (XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib))
1004
xev.width = attrib.width;
1005
xev.height = attrib.height;
1006
xev.border_width = attrib.border_width;
1009
/* We need to ensure that the stacking order is
1010
* based on the current server stacking order so
1011
* find the sibling to this window's frame in the
1012
* server side stack and stack above that */
1013
XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
1017
for (unsigned int i = 0; i < nchildren; i++)
1019
if (i + 1 == nchildren ||
1020
children[i + 1] == ROOTPARENT (window))
1022
xev.above = children[i];
1032
xev.above = (window->serverPrev) ? ROOTPARENT (window->serverPrev) : None;
1034
xev.override_redirect = priv->attrib.override_redirect;
1038
compiz::X11::PendingEvent::Ptr pc =
1039
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
1040
new compiz::X11::PendingConfigureEvent (
1041
screen->dpy (), serverFrame, valueMask, &xwc)));
1043
pendingConfigures.add (pc);
1044
if (priv->mClearCheckTimeout.active ())
1045
priv->mClearCheckTimeout.stop ();
1046
priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv),
1049
XSendEvent (screen->dpy (), screen->root (), false,
1050
SubstructureNotifyMask, (XEvent *) &xev);
1052
XUngrabServer (screen->dpy ());
1053
XSync (screen->dpy (), false);
1057
compiz::X11::PendingEvent::Ptr pc =
1058
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
1059
new compiz::X11::PendingConfigureEvent (
1060
screen->dpy (), serverFrame, valueMask, &xwc)));
1062
pendingConfigures.add (pc);
1063
if (priv->mClearCheckTimeout.active ())
1064
priv->mClearCheckTimeout.stop ();
1065
priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv),
1068
XConfigureWindow (screen->dpy (), serverFrame, valueMask, &xwc);
1073
XUnmapWindow (screen->dpy (), wrapper);
1077
XMapWindow (screen->dpy (), wrapper);
1078
XMoveResizeWindow (screen->dpy (), wrapper, 0, 0,
1079
serverGeometry.width (), serverGeometry.height ());
1082
XMoveResizeWindow (screen->dpy (), id, 0, 0,
1083
serverGeometry.width (), serverGeometry.height ());
1084
window->sendConfigureNotify ();
1085
window->windowNotify (CompWindowNotifyFrameUpdate);
1087
window->recalcActions ();
1093
CompWindow::updateWindowOutputExtents ()
1095
CompWindowExtents output (priv->output);
1097
getOutputExtents (output);
1099
if (output.left != priv->output.left ||
1100
output.right != priv->output.right ||
1101
output.top != priv->output.top ||
1102
output.bottom != priv->output.bottom)
1104
priv->output = output;
1106
resizeNotify (0, 0, 0, 0);
1111
CompWindow::getOutputExtents (CompWindowExtents& output)
1113
WRAPABLE_HND_FUNCTN (getOutputExtents, output)
1122
PrivateWindow::rectsToRegion (unsigned int n, XRectangle *rects)
1127
for (unsigned int i = 0; i < n; i++)
1129
x1 = rects[i].x + priv->geometry.border ();
1130
y1 = rects[i].y + priv->geometry.border ();
1131
x2 = x1 + rects[i].width;
1132
y2 = y1 + rects[i].height;
1138
if (x2 > priv->width)
1140
if (y2 > priv->height)
1143
if (y1 < y2 && x1 < x2)
1145
x1 += priv->geometry.x ();
1146
y1 += priv->geometry.y ();
1147
x2 += priv->geometry.x ();
1148
y2 += priv->geometry.y ();
1150
ret += CompRect (x1, y1, x2 - x1, y2 - y1);
1157
/* TODO: This function should be able to check the XShape event
1158
* kind and only get/set shape rectangles for either ShapeInput
1159
* or ShapeBounding, but not both at the same time
1163
PrivateWindow::updateRegion ()
1165
XRectangle r, *boundingShapeRects = NULL;
1166
XRectangle *inputShapeRects = NULL;
1167
int nBounding = 0, nInput = 0;
1169
priv->region = CompRegion ();
1170
priv->inputRegion = CompRegion ();
1172
if (screen->XShape ())
1176
boundingShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
1177
ShapeBounding, &nBounding, &order);
1178
inputShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
1179
ShapeInput, &nInput, &order);
1183
r.x = -priv->geometry.border ();
1184
r.y = -priv->geometry.border ();
1185
r.width = priv->width + priv->geometry.border ();
1186
r.height = priv->height + priv->geometry.border ();
1190
boundingShapeRects = &r;
1196
inputShapeRects = &r;
1200
priv->region += rectsToRegion (nBounding, boundingShapeRects);
1201
priv->inputRegion += rectsToRegion (nInput, inputShapeRects);
1203
if (boundingShapeRects && boundingShapeRects != &r)
1204
XFree (boundingShapeRects);
1205
if (inputShapeRects && inputShapeRects != &r)
1206
XFree (inputShapeRects);
1208
window->updateFrameRegion ();
1212
CompWindow::updateStruts ()
1216
unsigned long n, left;
1217
unsigned char *data;
1218
bool hasOld, hasNew;
1219
CompStruts oldStrut, newStrut;
1225
oldStrut.left = priv->struts->left;
1226
oldStrut.right = priv->struts->right;
1227
oldStrut.top = priv->struts->top;
1228
oldStrut.bottom = priv->struts->bottom;
1237
newStrut.left.x = 0;
1238
newStrut.left.y = 0;
1239
newStrut.left.width = 0;
1240
newStrut.left.height = screen->height ();
1242
newStrut.right.x = screen->width ();
1243
newStrut.right.y = 0;
1244
newStrut.right.width = 0;
1245
newStrut.right.height = screen->height ();
1249
newStrut.top.width = screen->width ();
1250
newStrut.top.height = 0;
1252
newStrut.bottom.x = 0;
1253
newStrut.bottom.y = screen->height ();
1254
newStrut.bottom.width = screen->width ();
1255
newStrut.bottom.height = 0;
1257
result = XGetWindowProperty (screen->dpy (), priv->id,
1258
Atoms::wmStrutPartial,
1259
0L, 12L, false, XA_CARDINAL, &actual, &format,
1262
if (result == Success && data)
1264
unsigned long *struts = (unsigned long *) data;
1270
newStrut.left.y = struts[4];
1271
newStrut.left.width = struts[0];
1272
newStrut.left.height = struts[5] - newStrut.left.y + 1;
1274
newStrut.right.width = struts[1];
1275
newStrut.right.x = screen->width () - newStrut.right.width;
1276
newStrut.right.y = struts[6];
1277
newStrut.right.height = struts[7] - newStrut.right.y + 1;
1279
newStrut.top.x = struts[8];
1280
newStrut.top.width = struts[9] - newStrut.top.x + 1;
1281
newStrut.top.height = struts[2];
1283
newStrut.bottom.x = struts[10];
1284
newStrut.bottom.width = struts[11] - newStrut.bottom.x + 1;
1285
newStrut.bottom.height = struts[3];
1286
newStrut.bottom.y = screen->height () - newStrut.bottom.height;
1294
result = XGetWindowProperty (screen->dpy (), priv->id,
1296
0L, 4L, false, XA_CARDINAL,
1297
&actual, &format, &n, &left, &data);
1299
if (result == Success && data)
1301
unsigned long *struts = (unsigned long *) data;
1307
newStrut.left.x = 0;
1308
newStrut.left.width = struts[0];
1310
newStrut.right.width = struts[1];
1311
newStrut.right.x = screen->width () - newStrut.right.width;
1314
newStrut.top.height = struts[2];
1316
newStrut.bottom.height = struts[3];
1317
newStrut.bottom.y = screen->height () - newStrut.bottom.height;
1326
int strutX1, strutY1, strutX2, strutY2;
1329
/* applications expect us to clip struts to xinerama edges */
1330
for (unsigned int i = 0;
1331
i < screen->screenInfo ().size (); i++)
1333
x1 = screen->screenInfo ()[i].x_org;
1334
y1 = screen->screenInfo ()[i].y_org;
1335
x2 = x1 + screen->screenInfo ()[i].width;
1336
y2 = y1 + screen->screenInfo ()[i].height;
1338
strutX1 = newStrut.left.x;
1339
strutX2 = strutX1 + newStrut.left.width;
1340
strutY1 = newStrut.left.y;
1341
strutY2 = strutY1 + newStrut.left.height;
1343
if (strutX2 > x1 && strutX2 <= x2 &&
1344
strutY1 < y2 && strutY2 > y1)
1346
newStrut.left.x = x1;
1347
newStrut.left.width = strutX2 - x1;
1350
strutX1 = newStrut.right.x;
1351
strutX2 = strutX1 + newStrut.right.width;
1352
strutY1 = newStrut.right.y;
1353
strutY2 = strutY1 + newStrut.right.height;
1355
if (strutX1 > x1 && strutX1 <= x2 &&
1356
strutY1 < y2 && strutY2 > y1)
1358
newStrut.right.x = strutX1;
1359
newStrut.right.width = x2 - strutX1;
1362
strutX1 = newStrut.top.x;
1363
strutX2 = strutX1 + newStrut.top.width;
1364
strutY1 = newStrut.top.y;
1365
strutY2 = strutY1 + newStrut.top.height;
1367
if (strutX1 < x2 && strutX2 > x1 &&
1368
strutY2 > y1 && strutY2 <= y2)
1370
newStrut.top.y = y1;
1371
newStrut.top.height = strutY2 - y1;
1374
strutX1 = newStrut.bottom.x;
1375
strutX2 = strutX1 + newStrut.bottom.width;
1376
strutY1 = newStrut.bottom.y;
1377
strutY2 = strutY1 + newStrut.bottom.height;
1379
if (strutX1 < x2 && strutX2 > x1 &&
1380
strutY1 > y1 && strutY1 <= y2)
1382
newStrut.bottom.y = strutY1;
1383
newStrut.bottom.height = y2 - strutY1;
1388
if (hasOld != hasNew ||
1389
(hasNew && hasOld &&
1390
memcmp (&newStrut, &oldStrut, sizeof (CompStruts))))
1396
priv->struts = (CompStruts *) malloc (sizeof (CompStruts));
1401
*priv->struts = newStrut;
1405
free (priv->struts);
1406
priv->struts = NULL;
1416
CompWindow::incrementDestroyReference ()
1418
priv->destroyRefCnt++;
1422
CompWindow::destroy ()
1426
CompWindow *oldServerNext, *oldServerPrev, *oldNext, *oldPrev;
1427
StackDebugger *dbg = StackDebugger::Default ();
1429
windowNotify (CompWindowNotifyBeforeDestroy);
1431
/* Don't allow frame windows to block input */
1432
XUnmapWindow (screen->dpy (), priv->serverFrame);
1433
XUnmapWindow (screen->dpy (), priv->wrapper);
1435
oldServerNext = serverNext;
1436
oldServerPrev = serverPrev;
1440
/* This is where things get tricky ... it is possible
1441
* to receive a ConfigureNotify relative to a frame window
1442
* for a destroyed window in case we process a ConfigureRequest
1443
* for the destroyed window and then a DestroyNotify for it directly
1444
* afterwards. In that case, we will receive the ConfigureNotify
1445
* for the XConfigureWindow request we made relative to that frame
1446
* window. Because of this, we must keep the frame window in the stack
1447
* as a new toplevel window so that the ConfigureNotify will be processed
1448
* properly until it too receives a DestroyNotify */
1450
if (priv->serverFrame)
1452
XWindowAttributes attrib;
1454
/* It's possible that the frame window was already destroyed because
1455
* the client was unreparented before it was destroyed (eg
1456
* UnmapNotify before DestroyNotify). In that case the frame window
1457
* is going to be an invalid window but since we haven't received
1458
* a DestroyNotify for it yet, it is possible that restacking
1459
* operations could occurr relative to it so we need to hold it
1460
* in the stack for now. Ensure that it is marked override redirect */
1461
XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib);
1463
/* Put the frame window "above" the client window
1465
CoreWindow *cw = new CoreWindow (priv->serverFrame);
1466
cw->manage (priv->id, attrib);
1467
screen->removeFromCreatedWindows (cw);
1471
/* Immediately unhook the window once destroyed
1472
* as the stacking order will be invalid if we don't
1473
* and will continue to be invalid for the period
1474
* that we keep it around in the stack. Instead, push
1475
* it to another stack and keep the next and prev members
1476
* in tact, letting plugins sort out where those windows
1477
* might be in case they need to use them relative to
1480
screen->unhookWindow (this);
1481
screen->unhookServerWindow (this);
1483
/* We must immediately insert the window into the debugging
1486
dbg->removeServerWindow (id ());
1488
/* Unhooking the window will also NULL the next/prev
1489
* linked list links but we don't want that so don't
1494
serverNext = oldServerNext;
1495
serverPrev = oldServerPrev;
1497
screen->addToDestroyedWindows (this);
1499
/* We must set the xid of this window
1500
* to zero as it no longer references
1505
priv->serverFrame = 0;
1506
priv->managed = false;
1509
priv->destroyRefCnt--;
1510
if (priv->destroyRefCnt)
1513
if (!priv->destroyed)
1515
if (!priv->serverFrame)
1517
StackDebugger *dbg = StackDebugger::Default ();
1520
dbg->addDestroyedFrame (priv->serverId);
1523
priv->destroyed = true;
1524
screen->priv->pendingDestroys++;
1530
CompWindow::sendConfigureNotify ()
1532
XConfigureEvent xev;
1533
XWindowAttributes attrib;
1534
unsigned int nchildren;
1535
Window rootRet, parentRet = 0;
1538
xev.type = ConfigureNotify;
1539
xev.event = priv->id;
1540
xev.window = priv->id;
1542
/* in order to avoid race conditions we must use the current
1543
* server configuration */
1545
XGrabServer (screen->dpy ());
1546
XSync (screen->dpy (), false);
1548
if (XGetWindowAttributes (screen->dpy (), priv->id, &attrib))
1552
xev.width = attrib.width;
1553
xev.height = attrib.height;
1554
xev.border_width = attrib.border_width;
1557
/* Translate co-ordinates to root space */
1558
XTranslateCoordinates (screen->dpy (), priv->id, screen->root (), 0, 0,
1559
&xev.x, &xev.y, &parentRet);
1561
/* We need to ensure that the stacking order is
1562
* based on the current server stacking order so
1563
* find the sibling to this window's frame in the
1564
* server side stack and stack above that */
1565
XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
1569
for (unsigned int i = 0; i < nchildren; i++)
1571
if (i + 1 == nchildren ||
1572
children[i + 1] == ROOTPARENT (this))
1574
xev.above = children[i];
1584
xev.above = (serverPrev) ? ROOTPARENT (serverPrev) : None;
1585
xev.override_redirect = priv->attrib.override_redirect;
1587
XSendEvent (screen->dpy (), priv->id, false,
1588
StructureNotifyMask, (XEvent *) &xev);
1591
XUngrabServer (screen->dpy ());
1592
XSync (screen->dpy (), false);
1598
windowNotify (CompWindowNotifyBeforeMap);
1602
if (priv->pendingMaps > 0)
1603
priv->pendingMaps = 0;
1605
priv->mapNum = screen->priv->mapNum++;
1608
screen->updateWorkarea ();
1610
if (windowClass () == InputOnly)
1613
priv->unmapRefCnt = 1;
1615
priv->attrib.map_state = IsViewable;
1617
if (!overrideRedirect ())
1618
screen->priv->setWmState (NormalState, priv->id);
1620
priv->invisible = true;
1623
priv->lastPong = screen->priv->lastPing;
1625
priv->updateRegion ();
1626
priv->updateSize ();
1628
screen->priv->updateClientList ();
1630
if (priv->type & CompWindowTypeDesktopMask)
1631
screen->priv->desktopWindowCount++;
1633
if (priv->protocols & CompWindowProtocolSyncRequestMask)
1636
sendConfigureNotify ();
1639
if (!overrideRedirect ())
1644
priv->shaded = false;
1645
priv->updateFrameWindow ();
1650
windowNotify (CompWindowNotifyMap);
1654
CompWindow::incrementUnmapReference ()
1656
priv->unmapRefCnt++;
1660
CompWindow::unmap ()
1662
windowNotify (CompWindowNotifyBeforeUnmap);
1667
/* Even though we're still keeping the backing
1668
* pixmap of the window around, it's safe to
1669
* unmap the frame window since there's no use
1670
* for it at this point anyways and it just blocks
1671
* input, but keep it around if shaded */
1673
XUnmapWindow (screen->dpy (), priv->wrapper);
1676
XUnmapWindow (screen->dpy (), priv->serverFrame);
1678
priv->unmapRefCnt--;
1679
if (priv->unmapRefCnt > 0)
1682
if (priv->unmanaging)
1684
XWindowChanges xwc = XWINDOWCHANGES_INIT;
1686
int gravity = priv->sizeHints.win_gravity;
1688
/* revert gravity adjustment made at MapNotify time */
1689
xwc.x = priv->serverGeometry.x ();
1690
xwc.y = priv->serverGeometry.y ();
1694
xwcm = priv->adjustConfigureRequestForGravity (&xwc,
1699
configureXWindow (xwcm, &xwc);
1701
priv->unmanaging = false;
1704
if (priv->serverFrame && !priv->shaded)
1705
priv->unreparent ();
1708
screen->updateWorkarea ();
1710
if (priv->attrib.map_state != IsViewable)
1713
if (priv->type == CompWindowTypeDesktopMask)
1714
screen->priv->desktopWindowCount--;
1716
priv->attrib.map_state = IsUnmapped;
1717
priv->invisible = true;
1719
if (priv->shaded && priv->height)
1721
priv->updateFrameWindow ();
1724
screen->priv->updateClientList ();
1726
windowNotify (CompWindowNotifyUnmap);
1730
PrivateWindow::withdraw ()
1732
if (!attrib.override_redirect)
1733
screen->priv->setWmState (WithdrawnState, id);
1736
unmanaging = managed;
1741
PrivateWindow::restack (Window aboveId)
1743
if (aboveId && (aboveId == id || aboveId == serverFrame))
1744
// Don't try to raise a window above itself
1746
else if (window->prev)
1748
if (aboveId && (aboveId == window->prev->id () ||
1749
aboveId == window->prev->priv->frame))
1752
else if (aboveId == None && !window->next)
1755
if (aboveId && !screen->findTopLevelWindow (aboveId, true))
1760
screen->unhookWindow (window);
1761
screen->insertWindow (window, aboveId);
1763
/* Update the server side window list for
1764
* override redirect windows immediately
1765
* since there is no opportunity to update
1766
* the server side list when we configure them
1767
* since we never get a ConfigureRequest for those */
1768
if (attrib.override_redirect != 0)
1770
StackDebugger *dbg = StackDebugger::Default ();
1772
screen->unhookServerWindow (window);
1773
screen->insertServerWindow (window, aboveId);
1776
dbg->overrideRedirectRestack (window->id (), aboveId);
1779
screen->priv->updateClientList ();
1781
window->windowNotify (CompWindowNotifyRestack);
1787
CompWindow::resize (XWindowAttributes attr)
1789
return resize (Geometry (attr.x, attr.y, attr.width, attr.height,
1790
attr.border_width));
1794
CompWindow::resize (int x,
1800
return resize (Geometry (x, y, width, height, border));
1804
CompWindow::resize (CompWindow::Geometry gm)
1806
/* Input extents are now the last thing sent
1807
* from the server. This might not work in some
1808
* cases though because setWindowFrameExtents may
1809
* be called more than once in an event processing
1810
* cycle so every set of input extents up until the
1811
* last one will be invalid. The real solution
1812
* here is to handle ConfigureNotify events on
1813
* frame windows and client windows separately */
1815
priv->input = priv->serverInput;
1817
if (priv->geometry.width () != gm.width () ||
1818
priv->geometry.height () != gm.height () ||
1819
priv->geometry.border () != gm.border ())
1822
int dx, dy, dwidth, dheight;
1824
pw = gm.width () + gm.border () * 2;
1825
ph = gm.height () + gm.border () * 2;
1827
dx = gm.x () - priv->geometry.x ();
1828
dy = gm.y () - priv->geometry.y ();
1829
dwidth = gm.width () - priv->geometry.width ();
1830
dheight = gm.height () - priv->geometry.height ();
1832
priv->geometry.set (gm.x (), gm.y (),
1833
gm.width (), gm.height (),
1840
priv->updateRegion ();
1842
resizeNotify (dx, dy, dwidth, dheight);
1844
priv->invisible = WINDOW_INVISIBLE (priv);
1846
else if (priv->geometry.x () != gm.x () || priv->geometry.y () != gm.y ())
1850
dx = gm.x () - priv->geometry.x ();
1851
dy = gm.y () - priv->geometry.y ();
1853
priv->geometry.setX (gm.x ());
1854
priv->geometry.setY (gm.y ());
1856
priv->region.translate (dx, dy);
1857
priv->inputRegion.translate (dx, dy);
1858
if (!priv->frameRegion.isEmpty ())
1859
priv->frameRegion.translate (dx, dy);
1861
priv->invisible = WINDOW_INVISIBLE (priv);
1863
moveNotify (dx, dy, true);
1866
updateFrameRegion ();
1872
syncValueIncrement (XSyncValue *value)
1877
XSyncIntToValue (&one, 1);
1878
XSyncValueAdd (value, *value, one, &overflow);
1882
PrivateWindow::initializeSyncCounter ()
1884
XSyncAlarmAttributes values;
1887
unsigned long n, left;
1888
unsigned char *data;
1891
return syncAlarm != None;
1893
if (!(protocols & CompWindowProtocolSyncRequestMask))
1896
result = XGetWindowProperty (screen->dpy (), id,
1897
Atoms::wmSyncRequestCounter,
1898
0L, 1L, false, XA_CARDINAL, &actual, &format,
1901
if (result == Success && n && data)
1903
unsigned long *counter = (unsigned long *) data;
1905
syncCounter = *counter;
1909
XSyncIntsToValue (&syncValue, (unsigned int) rand (), 0);
1910
XSyncSetCounter (screen->dpy (),
1914
syncValueIncrement (&syncValue);
1916
values.events = true;
1918
values.trigger.counter = syncCounter;
1919
values.trigger.wait_value = syncValue;
1921
values.trigger.value_type = XSyncAbsolute;
1922
values.trigger.test_type = XSyncPositiveComparison;
1924
XSyncIntToValue (&values.delta, 1);
1926
values.events = true;
1928
CompScreenImpl::checkForError (screen->dpy ());
1930
/* Note that by default, the alarm increments the trigger value
1931
* when it fires until the condition (counter.value < trigger.value)
1934
syncAlarm = XSyncCreateAlarm (screen->dpy (),
1943
if (CompScreenImpl::checkForError (screen->dpy ()))
1946
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
1949
else if (result == Success && data)
1958
CompWindow::sendSyncRequest ()
1960
XClientMessageEvent xev;
1965
if (!priv->initializeSyncCounter ())
1968
xev.type = ClientMessage;
1969
xev.window = priv->id;
1970
xev.message_type = Atoms::wmProtocols;
1972
xev.data.l[0] = Atoms::wmSyncRequest;
1973
xev.data.l[1] = CurrentTime;
1974
xev.data.l[2] = XSyncValueLow32 (priv->syncValue);
1975
xev.data.l[3] = XSyncValueHigh32 (priv->syncValue);
1978
syncValueIncrement (&priv->syncValue);
1980
XSendEvent (screen->dpy (), priv->id, false, 0, (XEvent *) &xev);
1982
priv->syncWait = true;
1983
priv->syncGeometry = priv->serverGeometry;
1985
if (!priv->syncWaitTimer.active ())
1986
priv->syncWaitTimer.start ();
1990
PrivateWindow::configure (XConfigureEvent *ce)
1992
unsigned int valueMask = 0;
1997
/* remove configure event from pending configures */
1998
if (priv->geometry.x () != ce->x)
2001
if (priv->geometry.y () != ce->y)
2004
if (priv->geometry.width () != ce->width)
2005
valueMask |= CWWidth;
2007
if (priv->geometry.height () != ce->height)
2008
valueMask |= CWHeight;
2010
if (priv->geometry.border () != ce->border_width)
2011
valueMask |= CWBorderWidth;
2015
if (ROOTPARENT (window->prev) != ce->above)
2016
valueMask |= CWSibling | CWStackMode;
2021
valueMask |= CWSibling | CWStackMode;
2024
priv->attrib.override_redirect = ce->override_redirect;
2026
priv->frameGeometry.set (ce->x, ce->y, ce->width,
2027
ce->height, ce->border_width);
2030
priv->syncGeometry.set (ce->x, ce->y, ce->width, ce->height,
2034
if (ce->override_redirect)
2036
priv->serverGeometry.set (ce->x, ce->y, ce->width, ce->height,
2040
window->resize (ce->x, ce->y, ce->width, ce->height, ce->border_width);
2043
if (ce->event == screen->root ())
2044
priv->restack (ce->above);
2048
PrivateWindow::configureFrame (XConfigureEvent *ce)
2050
int x, y, width, height;
2052
unsigned int valueMask = 0;
2057
/* remove configure event from pending configures */
2058
if (priv->frameGeometry.x () != ce->x)
2061
if (priv->frameGeometry.y () != ce->y)
2064
if (priv->frameGeometry.width () != ce->width)
2065
valueMask |= CWWidth;
2067
if (priv->frameGeometry.height () != ce->height)
2068
valueMask |= CWHeight;
2070
if (priv->frameGeometry.border () != ce->border_width)
2071
valueMask |= CWBorderWidth;
2075
if (ROOTPARENT (window->prev) != ce->above)
2076
valueMask |= CWSibling | CWStackMode;
2081
valueMask |= CWSibling | CWStackMode;
2084
if (!pendingConfigures.match ((XEvent *) ce))
2086
compLogMessage ("core", CompLogLevelWarn, "unhandled ConfigureNotify on 0x%x!", serverFrame);
2087
compLogMessage ("core", CompLogLevelWarn, "this should never happen. you should "\
2088
"probably file a bug about this.");
2092
pendingConfigures.clear ();
2096
/* subtract the input extents last sent to the
2097
* server to calculate the client size and then
2098
* re-sync the input extents and extents last
2099
* sent to server on resize () */
2101
x = ce->x + priv->serverInput.left;
2102
y = ce->y + priv->serverInput.top;
2103
width = ce->width - priv->serverGeometry.border () * 2 - priv->serverInput.left - priv->serverInput.right;
2105
/* Don't use the server side frame geometry
2106
* to determine the geometry of shaded
2107
* windows since we didn't resize them
2108
* on configureXWindow */
2110
height = priv->serverGeometry.height () - priv->serverGeometry.border () * 2 - priv->serverInput.top - priv->serverInput.bottom;
2112
height = ce->height - priv->serverGeometry.border () * 2 - priv->serverInput.top - priv->serverInput.bottom;
2114
/* set the frame geometry */
2115
priv->frameGeometry.set (ce->x, ce->y, ce->width, ce->height, ce->border_width);
2119
priv->syncGeometry.set (x, y, width, height, ce->border_width);
2121
window->resize (x, y, width, height, ce->border_width);
2123
if (priv->restack (ce->above))
2124
priv->updatePassiveButtonGrabs ();
2126
above = screen->findWindow (ce->above);
2129
above->priv->updatePassiveButtonGrabs ();
2131
if (!pendingConfigures.pending ())
2133
/* Tell plugins its ok to start doing stupid things again but
2134
* obviously FIXME */
2135
CompOption::Vector options;
2136
CompOption::Value v;
2138
options.push_back (CompOption ("window", CompOption::TypeInt));
2140
options.back ().set (v);
2141
options.push_back (CompOption ("active", CompOption::TypeInt));
2143
options.back ().set (v);
2145
/* Notify other plugins that it is unsafe to change geometry or serverGeometry
2146
* FIXME: That API should not be accessible to plugins, this is a hack to avoid
2149
screen->handleCompizEvent ("core", "lock_position", options);
2154
PrivateWindow::circulate (XCirculateEvent *ce)
2158
if (ce->place == PlaceOnTop)
2159
newAboveId = screen->priv->getTopWindow ();
2163
priv->restack (newAboveId);
2167
CompWindow::move (int dx,
2173
gettimeofday (&priv->lastGeometryUpdate, NULL);
2175
/* Don't allow window movement to overwrite working geometries
2176
* last received from the server if we know there are pending
2177
* ConfigureNotify events on this window. That's a clunky workaround
2178
* and a FIXME in any case, however, until we can break the API
2179
* and remove CompWindow::move, this will need to be the case */
2181
if (!priv->pendingConfigures.pending ())
2183
priv->geometry.setX (priv->geometry.x () + dx);
2184
priv->geometry.setY (priv->geometry.y () + dy);
2185
priv->frameGeometry.setX (priv->frameGeometry.x () + dx);
2186
priv->frameGeometry.setY (priv->frameGeometry.y () + dy);
2188
priv->pendingPositionUpdates = true;
2190
priv->region.translate (dx, dy);
2191
priv->inputRegion.translate (dx, dy);
2192
if (!priv->frameRegion.isEmpty ())
2193
priv->frameRegion.translate (dx, dy);
2195
priv->invisible = WINDOW_INVISIBLE (priv);
2197
moveNotify (dx, dy, immediate);
2201
XWindowChanges xwc = XWINDOWCHANGES_INIT;
2202
unsigned int valueMask = CWX | CWY;
2203
compLogMessage ("core", CompLogLevelDebug, "pending configure notifies on 0x%x, "\
2204
"moving window asyncrhonously!", (unsigned int) priv->serverId);
2206
xwc.x = priv->serverGeometry.x () + dx;
2207
xwc.y = priv->serverGeometry.y () + dy;
2209
configureXWindow (valueMask, &xwc);
2215
compiz::X11::PendingEventQueue::pending ()
2217
return !mEvents.empty ();
2221
PrivateWindow::checkClear ()
2223
if (pendingConfigures.pending ())
2225
/* FIXME: This is a hack to avoid performance regressions
2226
* and must be removed in 0.9.6 */
2227
compLogMessage ("core", CompLogLevelWarn, "failed to receive ConfigureNotify event on 0x%x\n",
2229
pendingConfigures.dump ();
2230
pendingConfigures.clear ();
2237
compiz::X11::PendingEventQueue::add (PendingEvent::Ptr p)
2239
compLogMessage ("core", CompLogLevelDebug, "pending request:");
2242
mEvents.push_back (p);
2246
compiz::X11::PendingEventQueue::removeIfMatching (const PendingEvent::Ptr &p, XEvent *event)
2248
if (p->match (event))
2250
compLogMessage ("core", CompLogLevelDebug, "received event:");
2259
compiz::X11::PendingEvent::dump ()
2261
compLogMessage ("core", CompLogLevelDebug, "- event serial: %i", mSerial);
2262
compLogMessage ("core", CompLogLevelDebug, "- event window 0x%x", mWindow);
2266
compiz::X11::PendingConfigureEvent::dump ()
2268
compiz::X11::PendingEvent::dump ();
2270
compLogMessage ("core", CompLogLevelDebug, "- x: %i y: %i width: %i height: %i "\
2271
"border: %i, sibling: 0x%x",
2272
mXwc.x, mXwc.y, mXwc.width, mXwc.height, mXwc.border_width, mXwc.sibling);
2276
compiz::X11::PendingEventQueue::match (XEvent *event)
2278
unsigned int lastSize = mEvents.size ();
2280
mEvents.erase (std::remove_if (mEvents.begin (), mEvents.end (),
2281
boost::bind (&compiz::X11::PendingEventQueue::removeIfMatching, this, _1, event)), mEvents.end ());
2283
return lastSize != mEvents.size ();
2287
compiz::X11::PendingEventQueue::forEachIf (boost::function<bool (compiz::X11::PendingEvent::Ptr)> f)
2289
foreach (compiz::X11::PendingEvent::Ptr p, mEvents)
2299
compiz::X11::PendingEventQueue::dump ()
2301
foreach (compiz::X11::PendingEvent::Ptr p, mEvents)
2305
compiz::X11::PendingEventQueue::PendingEventQueue (Display *d)
2307
/* mClearCheckTimeout.setTimes (0, 0)
2309
* XXX: For whatever reason, calling setTimes (0, 0) here causes
2310
* the destructor of the timer object to be called twice later on
2311
* in execution and the stack gets smashed. This could be a
2312
* compiler bug, but requires further investigation */
2315
compiz::X11::PendingEventQueue::~PendingEventQueue ()
2320
compiz::X11::PendingEvent::getEventWindow (XEvent *event)
2322
return event->xany.window;
2326
compiz::X11::PendingEvent::match (XEvent *event)
2328
if (event->xany.serial != mSerial)
2330
if (getEventWindow (event)!= mWindow)
2336
compiz::X11::PendingEvent::PendingEvent (Display *d, Window w) :
2337
mSerial (XNextRequest (d)),
2342
compiz::X11::PendingEvent::~PendingEvent ()
2347
compiz::X11::PendingConfigureEvent::getEventWindow (XEvent *event)
2349
return event->xconfigure.window;
2353
compiz::X11::PendingConfigureEvent::matchVM (unsigned int valueMask)
2355
unsigned int result = mValueMask != 0 ? valueMask & mValueMask : 1;
2361
compiz::X11::PendingConfigureEvent::matchRequest (XWindowChanges &xwc, unsigned int valueMask)
2363
if (matchVM (valueMask))
2365
if (valueMask & CWX)
2366
if (xwc.x != mXwc.x)
2369
if (valueMask & CWY)
2370
if (xwc.y != mXwc.y)
2373
if (valueMask & CWWidth)
2374
if (xwc.width != mXwc.width)
2377
if (valueMask & CWHeight)
2378
if (xwc.height != mXwc.height)
2381
if (valueMask & CWBorderWidth)
2382
if (xwc.border_width != mXwc.border_width)
2385
if (valueMask & (CWStackMode | CWSibling))
2386
if (xwc.sibling != mXwc.sibling)
2396
compiz::X11::PendingConfigureEvent::match (XEvent *event)
2398
XConfigureEvent *ce = (XConfigureEvent *) event;
2399
bool matched = true;
2401
if (!compiz::X11::PendingEvent::match (event))
2404
XWindowChanges xwc = XWINDOWCHANGES_INIT;
2408
xwc.width = ce->width;
2409
xwc.height = ce->height;
2410
xwc.border_width = ce->border_width;
2411
xwc.sibling = ce->above;
2413
matched = matchRequest (xwc, mValueMask);
2415
/* Remove events from the queue
2416
* even if they didn't match what
2417
* we expected them to be, but still
2418
* complain about it */
2421
compLogMessage ("core", CompLogLevelWarn, "no exact match for ConfigureNotify on 0x%x!", mWindow);
2422
compLogMessage ("core", CompLogLevelWarn, "expected the following changes:");
2423
if (mValueMask & CWX)
2424
compLogMessage ("core", CompLogLevelWarn, "x: %i", mXwc.x);
2425
if (mValueMask & CWY)
2426
compLogMessage ("core", CompLogLevelWarn, "y: %i", mXwc.y);
2427
if (mValueMask & CWWidth)
2428
compLogMessage ("core", CompLogLevelWarn, "width: %i", mXwc.width);
2429
if (mValueMask & CWHeight)
2430
compLogMessage ("core", CompLogLevelWarn, "height: %i", mXwc.height);
2431
if (mValueMask & CWBorderWidth)
2432
compLogMessage ("core", CompLogLevelWarn, "border: %i", mXwc.border_width);
2433
if (mValueMask & (CWStackMode | CWSibling))
2434
compLogMessage ("core", CompLogLevelWarn, "sibling: 0x%x", mXwc.sibling);
2436
compLogMessage ("core", CompLogLevelWarn, "instead got:");
2437
compLogMessage ("core", CompLogLevelWarn, "x: %i", ce->x);
2438
compLogMessage ("core", CompLogLevelWarn, "y: %i", ce->y);
2439
compLogMessage ("core", CompLogLevelWarn, "width: %i", ce->width);
2440
compLogMessage ("core", CompLogLevelWarn, "height: %i", ce->height);
2441
compLogMessage ("core", CompLogLevelWarn, "above: %i", ce->above);
2442
compLogMessage ("core", CompLogLevelWarn, "this should never happen. you should "\
2443
"probably file a bug about this.");
2449
compiz::X11::PendingConfigureEvent::PendingConfigureEvent (Display *d,
2451
unsigned int valueMask,
2452
XWindowChanges *xwc) :
2453
compiz::X11::PendingEvent::PendingEvent (d, w),
2454
mValueMask (valueMask),
2457
CompOption::Vector options;
2458
CompOption::Value v;
2460
options.push_back (CompOption ("window", CompOption::TypeInt));
2462
options.back ().set (v);
2463
options.push_back (CompOption ("active", CompOption::TypeInt));
2465
options.back ().set (v);
2467
/* Notify other plugins that it is unsafe to change geometry or serverGeometry
2468
* FIXME: That API should not be accessible to plugins, this is a hack to avoid
2471
screen->handleCompizEvent ("core", "lock_position", options);
2474
compiz::X11::PendingConfigureEvent::~PendingConfigureEvent ()
2479
CompWindow::syncPosition ()
2481
gettimeofday (&priv->lastConfigureRequest, NULL);
2483
unsigned int valueMask = CWX | CWY;
2484
XWindowChanges xwc = XWINDOWCHANGES_INIT;
2486
if (priv->pendingPositionUpdates && !priv->pendingConfigures.pending ())
2488
if (priv->serverFrameGeometry.x () == priv->frameGeometry.x ())
2489
valueMask &= ~(CWX);
2490
if (priv->serverFrameGeometry.y () == priv->frameGeometry.y ())
2491
valueMask &= ~(CWY);
2493
/* Because CompWindow::move can update the geometry last
2494
* received from the server, we must indicate that no values
2495
* changed, because when the ConfigureNotify comes around
2496
* the values are going to be the same. That's obviously
2497
* broken behaviour and worthy of a FIXME, but requires
2498
* larger changes to the window movement system. */
2501
priv->serverGeometry.setX (priv->geometry.x ());
2502
priv->serverGeometry.setY (priv->geometry.y ());
2503
priv->serverFrameGeometry.setX (priv->frameGeometry.x ());
2504
priv->serverFrameGeometry.setY (priv->frameGeometry.y ());
2506
xwc.x = priv->serverFrameGeometry.x ();
2507
xwc.y = priv->serverFrameGeometry.y ();
2509
compiz::X11::PendingEvent::Ptr pc =
2510
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
2511
new compiz::X11::PendingConfigureEvent (
2512
screen->dpy (), priv->serverFrame, 0, &xwc)));
2514
priv->pendingConfigures.add (pc);
2516
/* Got 3 seconds to get its stuff together */
2517
if (priv->mClearCheckTimeout.active ())
2518
priv->mClearCheckTimeout.stop ();
2519
priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv),
2521
XConfigureWindow (screen->dpy (), ROOTPARENT (this), valueMask, &xwc);
2523
if (priv->serverFrame)
2525
XMoveWindow (screen->dpy (), priv->wrapper,
2526
priv->serverInput.left, priv->serverInput.top);
2527
sendConfigureNotify ();
2530
priv->pendingPositionUpdates = false;
2535
CompWindow::focus ()
2537
WRAPABLE_HND_FUNCTN_RETURN (bool, focus)
2539
if (overrideRedirect ())
2542
if (!priv->managed || priv->unmanaging)
2545
if (!onCurrentDesktop ())
2548
if (priv->destroyed)
2551
if (!priv->shaded && (priv->state & CompWindowStateHiddenMask))
2554
if (priv->serverGeometry.x () + priv->serverGeometry.width () <= 0 ||
2555
priv->serverGeometry.y () + priv->serverGeometry.height () <= 0 ||
2556
priv->serverGeometry.x () >= (int) screen->width ()||
2557
priv->serverGeometry.y () >= (int) screen->height ())
2564
CompWindow::place (CompPoint &pos)
2566
WRAPABLE_HND_FUNCTN_RETURN (bool, place, pos)
2571
CompWindow::validateResizeRequest (unsigned int &mask,
2572
XWindowChanges *xwc,
2573
unsigned int source)
2575
WRAPABLE_HND_FUNCTN (validateResizeRequest, mask, xwc, source)
2577
if (!(priv->type & (CompWindowTypeDockMask |
2578
CompWindowTypeFullscreenMask |
2579
CompWindowTypeUnknownMask)))
2585
min = screen->workArea ().y () + priv->input.top;
2586
max = screen->workArea ().bottom ();
2588
if (priv->state & CompWindowStateStickyMask &&
2589
(xwc->y < min || xwc->y > max))
2591
xwc->y = priv->serverGeometry.y ();
2595
min -= screen->vp ().y () * screen->height ();
2596
max += (screen->vpSize ().height () - screen->vp ().y () - 1) *
2601
else if (xwc->y > max)
2610
min = screen->workArea ().x () + priv->input.left;
2611
max = screen->workArea ().right ();
2613
if (priv->state & CompWindowStateStickyMask &&
2614
(xwc->x < min || xwc->x > max))
2616
xwc->x = priv->serverGeometry.x ();
2620
min -= screen->vp ().x () * screen->width ();
2621
max += (screen->vpSize ().width () - screen->vp ().x () - 1) *
2626
else if (xwc->x > max)
2634
CompWindow::resizeNotify (int dx,
2638
WRAPABLE_HND_FUNCTN (resizeNotify, dx, dy, dwidth, dheight)
2641
CompWindow::moveNotify (int dx,
2644
WRAPABLE_HND_FUNCTN (moveNotify, dx, dy, immediate)
2647
CompWindow::windowNotify (CompWindowNotify n)
2648
WRAPABLE_HND_FUNCTN (windowNotify, n)
2651
CompWindow::grabNotify (int x,
2656
WRAPABLE_HND_FUNCTN (grabNotify, x, y, state, mask)
2657
priv->grabbed = true;
2661
CompWindow::ungrabNotify ()
2663
WRAPABLE_HND_FUNCTN (ungrabNotify)
2664
priv->grabbed = false;
2668
CompWindow::stateChangeNotify (unsigned int lastState)
2670
WRAPABLE_HND_FUNCTN (stateChangeNotify, lastState);
2672
/* if being made sticky */
2673
if (!(lastState & CompWindowStateStickyMask) &&
2674
(priv->state & CompWindowStateStickyMask))
2676
CompPoint vp; /* index of the window's vp */
2678
/* Find which viewport the window falls in,
2679
and check if it's the current viewport */
2680
vp = defaultViewport ();
2681
if (screen->vp () != vp)
2683
unsigned int valueMask = CWX | CWY;
2684
XWindowChanges xwc = XWINDOWCHANGES_INIT;
2686
xwc.x = serverGeometry ().x () + (screen->vp ().x () - vp.x ()) * screen->width ();
2687
xwc.y = serverGeometry ().y () + (screen->vp ().y () - vp.y ()) * screen->height ();
2689
configureXWindow (valueMask, &xwc);
2696
PrivateWindow::isGroupTransient (Window clientLeader)
2701
if (transientFor == None || transientFor == screen->root ())
2703
if (type & (CompWindowTypeUtilMask |
2704
CompWindowTypeToolbarMask |
2705
CompWindowTypeMenuMask |
2706
CompWindowTypeDialogMask |
2707
CompWindowTypeModalDialogMask))
2709
if (this->clientLeader == clientLeader)
2718
PrivateWindow::getModalTransient ()
2720
CompWindow *w, *modalTransient;
2722
modalTransient = window;
2724
for (w = screen->windows ().back (); w; w = w->prev)
2726
if (w == modalTransient || w->priv->mapNum == 0)
2729
if (w->priv->transientFor == modalTransient->priv->id)
2731
if (w->priv->state & CompWindowStateModalMask)
2734
w = screen->windows ().back ();
2739
if (modalTransient == window)
2741
/* don't look for group transients with modal state if current window
2743
if (state & CompWindowStateModalMask)
2746
for (w = screen->windows ().back (); w; w = w->prev)
2748
if (w == modalTransient || w->priv->mapNum == 0)
2751
if (isAncestorTo (modalTransient, w))
2754
if (w->priv->isGroupTransient (modalTransient->priv->clientLeader))
2756
if (w->priv->state & CompWindowStateModalMask)
2759
w = w->priv->getModalTransient ();
2769
if (modalTransient == window)
2770
modalTransient = NULL;
2772
return modalTransient;
2776
CompWindow::moveInputFocusTo ()
2778
CompScreen *s = screen;
2779
CompWindow *modalTransient;
2781
modalTransient = priv->getModalTransient ();
2783
return modalTransient->moveInputFocusTo ();
2785
/* If the window is still hidden but not shaded
2786
* it probably meant that a plugin overloaded
2787
* CompWindow::focus to allow the focus to go
2788
* to this window, so only move the input focus
2789
* to the frame if the window is shaded */
2792
XSetInputFocus (s->dpy (), priv->serverFrame,
2793
RevertToPointerRoot, CurrentTime);
2794
XChangeProperty (s->dpy (), s->root (), Atoms::winActive,
2795
XA_WINDOW, 32, PropModeReplace,
2796
(unsigned char *) &priv->id, 1);
2798
screen->priv->nextActiveWindow = priv->serverFrame;
2802
bool setFocus = false;
2804
if (priv->inputHint)
2806
XSetInputFocus (s->dpy (), priv->id, RevertToPointerRoot,
2811
if (priv->protocols & CompWindowProtocolTakeFocusMask)
2815
ev.type = ClientMessage;
2816
ev.xclient.window = priv->id;
2817
ev.xclient.message_type = Atoms::wmProtocols;
2818
ev.xclient.format = 32;
2819
ev.xclient.data.l[0] = Atoms::wmTakeFocus;
2820
ev.xclient.data.l[1] = s->getCurrentTime ();
2821
ev.xclient.data.l[2] = 0;
2822
ev.xclient.data.l[3] = 0;
2823
ev.xclient.data.l[4] = 0;
2825
XSendEvent (s->dpy (), priv->id, false, NoEventMask, &ev);
2831
screen->priv->nextActiveWindow = priv->id;
2833
if (!setFocus && !modalTransient)
2835
CompWindow *ancestor;
2837
/* move input to closest ancestor */
2838
for (ancestor = s->windows ().front (); ancestor;
2839
ancestor = ancestor->next)
2841
if (PrivateWindow::isAncestorTo (this, ancestor))
2843
ancestor->moveInputFocusTo ();
2852
CompWindow::moveInputFocusToOtherWindow ()
2854
if (priv->id == screen->activeWindow () ||
2855
priv->id == screen->priv->nextActiveWindow)
2857
CompWindow *ancestor;
2858
CompWindow *nextActive = screen->findWindow (screen->priv->nextActiveWindow);
2859
Window lastNextActiveWindow = screen->priv->nextActiveWindow;
2861
/* Window pending focus */
2862
if (priv->id != screen->priv->nextActiveWindow &&
2864
nextActive->focus ())
2866
nextActive->moveInputFocusTo ();
2868
else if (priv->transientFor && priv->transientFor != screen->root ())
2870
ancestor = screen->findWindow (priv->transientFor);
2872
ancestor->focus () &&
2873
!(ancestor->priv->type & (CompWindowTypeDesktopMask |
2874
CompWindowTypeDockMask)))
2876
ancestor->moveInputFocusTo ();
2879
screen->focusDefaultWindow ();
2881
else if (priv->type & (CompWindowTypeDialogMask |
2882
CompWindowTypeModalDialogMask))
2884
CompWindow *a, *focus = NULL;
2886
for (a = screen->windows ().back (); a; a = a->prev)
2888
if (a->priv->clientLeader == priv->clientLeader)
2894
if (a->priv->type & (CompWindowTypeNormalMask |
2895
CompWindowTypeDialogMask |
2896
CompWindowTypeModalDialogMask))
2898
if (priv->compareWindowActiveness (focus, a) < 0)
2908
if (focus && !(focus->priv->type & (CompWindowTypeDesktopMask |
2909
CompWindowTypeDockMask)))
2911
focus->moveInputFocusTo ();
2914
screen->focusDefaultWindow ();
2917
screen->focusDefaultWindow ();
2920
* moveInputFocusTo and focusDefaultWindow should really
2921
* return booleans */
2922
if (lastNextActiveWindow != screen->priv->nextActiveWindow &&
2923
screen->priv->optionGetRaiseOnClick ())
2925
/* If this window just got the focus because another window
2926
* was unmanaged then we should also raise it if click raise
2927
* is on, since another plugin might have raised another window
2928
* without wanting to focus it and this window will be beneath
2929
* it in the stack but above it in the active window history
2930
* so when the focus moves here this window should be raised
2931
* That's the tradeoff for maintaining a predictable focus order
2932
* as compared to eg a predictable stacking order */
2934
CompWindow *nextActive = screen->findWindow (screen->priv->nextActiveWindow);
2936
nextActive->raise ();
2943
PrivateWindow::stackLayerCheck (CompWindow *w,
2944
Window clientLeader,
2947
if (isAncestorTo (w, below))
2950
if (isAncestorTo (below, w))
2953
if (clientLeader && below->priv->clientLeader == clientLeader)
2954
if (below->priv->isGroupTransient (clientLeader))
2957
if (w->priv->state & CompWindowStateAboveMask)
2961
else if (w->priv->state & CompWindowStateBelowMask)
2963
if (below->priv->state & CompWindowStateBelowMask)
2966
else if (!(below->priv->state & CompWindowStateAboveMask))
2975
PrivateWindow::avoidStackingRelativeTo (CompWindow *w)
2977
if (w->overrideRedirect ())
2980
if (w->destroyed ())
2983
if (!w->priv->shaded && !w->priv->pendingMaps)
2985
if (!w->isViewable () || !w->isMapped ())
2992
/* goes through the stack, top-down until we find a window we should
2993
stack above, normal windows can be stacked above fullscreen windows
2994
(and fullscreen windows over others in their layer) if aboveFs is true. */
2996
PrivateWindow::findSiblingBelow (CompWindow *w,
3000
CompWindow *t = screen->findWindow (w->transientFor ());
3001
Window clientLeader = w->priv->clientLeader;
3002
unsigned int type = w->priv->type;
3003
unsigned int belowMask;
3006
belowMask = CompWindowTypeDockMask;
3008
belowMask = CompWindowTypeDockMask | CompWindowTypeFullscreenMask;
3010
/* normal stacking of fullscreen windows with below state */
3011
if ((type & CompWindowTypeFullscreenMask) &&
3012
(w->priv->state & CompWindowStateBelowMask))
3013
type = CompWindowTypeNormalMask;
3015
while (t && type != CompWindowTypeDockMask)
3017
/* dock stacking of transients for docks */
3018
if (t->type () & CompWindowTypeDockMask)
3019
type = CompWindowTypeDockMask;
3021
t = screen->findWindow (t->transientFor ());
3024
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
3025
clientLeader = None;
3027
for (below = screen->serverWindows ().back (); below;
3028
below = below->serverPrev)
3030
if (below == w || avoidStackingRelativeTo (below))
3033
/* always above desktop windows */
3034
if (below->priv->type & CompWindowTypeDesktopMask)
3038
case CompWindowTypeDesktopMask:
3039
/* desktop window layer */
3041
case CompWindowTypeFullscreenMask:
3044
/* otherwise fall-through */
3045
case CompWindowTypeDockMask:
3046
/* fullscreen and dock layer */
3047
if (below->priv->type & (CompWindowTypeFullscreenMask |
3048
CompWindowTypeDockMask))
3050
if (stackLayerCheck (w, clientLeader, below))
3060
bool allowedRelativeToLayer = !(below->priv->type & belowMask);
3062
if (aboveFs && below->priv->type & CompWindowTypeFullscreenMask)
3063
if (!below->focus ())
3066
t = screen->findWindow (below->transientFor ());
3068
while (t && allowedRelativeToLayer)
3070
/* dock stacking of transients for docks */
3071
allowedRelativeToLayer = !(t->priv->type & belowMask);
3073
t = screen->findWindow (t->transientFor ());
3076
/* fullscreen and normal layer */
3077
if (allowedRelativeToLayer)
3079
if (stackLayerCheck (w, clientLeader, below))
3090
/* goes through the stack, top-down and returns the lowest window we
3093
PrivateWindow::findLowestSiblingBelow (CompWindow *w)
3095
CompWindow *below, *lowest = screen->serverWindows ().back ();
3096
CompWindow *t = screen->findWindow (w->transientFor ());
3097
Window clientLeader = w->priv->clientLeader;
3098
unsigned int type = w->priv->type;
3100
/* normal stacking fullscreen windows with below state */
3101
if ((type & CompWindowTypeFullscreenMask) &&
3102
(w->priv->state & CompWindowStateBelowMask))
3103
type = CompWindowTypeNormalMask;
3105
while (t && type != CompWindowTypeDockMask)
3107
/* dock stacking of transients for docks */
3108
if (t->type () & CompWindowTypeDockMask)
3109
type = CompWindowTypeDockMask;
3111
t = screen->findWindow (t->transientFor ());
3115
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
3116
clientLeader = None;
3118
for (below = screen->serverWindows ().back (); below;
3119
below = below->serverPrev)
3121
if (below == w || avoidStackingRelativeTo (below))
3124
/* always above desktop windows */
3125
if (below->priv->type & CompWindowTypeDesktopMask)
3129
case CompWindowTypeDesktopMask:
3130
/* desktop window layer - desktop windows always should be
3131
stacked at the bottom; no other window should be below them */
3134
case CompWindowTypeFullscreenMask:
3135
case CompWindowTypeDockMask:
3136
/* fullscreen and dock layer */
3137
if (below->priv->type & (CompWindowTypeFullscreenMask |
3138
CompWindowTypeDockMask))
3140
if (!stackLayerCheck (below, clientLeader, w))
3150
bool allowedRelativeToLayer = !(below->priv->type & CompWindowTypeDockMask);
3152
t = screen->findWindow (below->transientFor ());
3154
while (t && allowedRelativeToLayer)
3156
/* dock stacking of transients for docks */
3157
allowedRelativeToLayer = !(t->priv->type & CompWindowTypeDockMask);
3159
t = screen->findWindow (t->transientFor ());
3162
/* fullscreen and normal layer */
3163
if (allowedRelativeToLayer)
3165
if (!stackLayerCheck (below, clientLeader, w))
3179
PrivateWindow::validSiblingBelow (CompWindow *w,
3180
CompWindow *sibling)
3182
CompWindow *t = screen->findWindow (w->transientFor ());
3183
Window clientLeader = w->priv->clientLeader;
3184
unsigned int type = w->priv->type;
3186
/* normal stacking fullscreen windows with below state */
3187
if ((type & CompWindowTypeFullscreenMask) &&
3188
(w->priv->state & CompWindowStateBelowMask))
3189
type = CompWindowTypeNormalMask;
3191
while (t && type != CompWindowTypeDockMask)
3193
/* dock stacking of transients for docks */
3194
if (t->type () & CompWindowTypeDockMask)
3195
type = CompWindowTypeDockMask;
3197
t = screen->findWindow (t->transientFor ());
3201
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
3202
clientLeader = None;
3204
if (sibling == w || avoidStackingRelativeTo (sibling))
3207
/* always above desktop windows */
3208
if (sibling->priv->type & CompWindowTypeDesktopMask)
3212
case CompWindowTypeDesktopMask:
3213
/* desktop window layer */
3215
case CompWindowTypeFullscreenMask:
3216
case CompWindowTypeDockMask:
3217
/* fullscreen and dock layer */
3218
if (sibling->priv->type & (CompWindowTypeFullscreenMask |
3219
CompWindowTypeDockMask))
3221
if (stackLayerCheck (w, clientLeader, sibling))
3231
bool allowedRelativeToLayer = !(sibling->priv->type & CompWindowTypeDockMask);
3233
t = screen->findWindow (sibling->transientFor ());
3235
while (t && allowedRelativeToLayer)
3237
/* dock stacking of transients for docks */
3238
allowedRelativeToLayer = !(t->priv->type & CompWindowTypeDockMask);
3240
t = screen->findWindow (t->transientFor ());
3243
/* fullscreen and normal layer */
3244
if (allowedRelativeToLayer)
3246
if (stackLayerCheck (w, clientLeader, sibling))
3257
PrivateWindow::saveGeometry (int mask)
3259
int m = mask & ~saveMask;
3261
/* only save geometry if window has been placed */
3266
saveWc.x = serverGeometry.x ();
3269
saveWc.y = serverGeometry.y ();
3272
saveWc.width = serverGeometry.width ();
3275
saveWc.height = serverGeometry.height ();
3277
if (m & CWBorderWidth)
3278
saveWc.border_width = serverGeometry.border ();
3284
PrivateWindow::restoreGeometry (XWindowChanges *xwc,
3287
int m = mask & saveMask;
3297
xwc->width = saveWc.width;
3299
/* This is not perfect but it works OK for now. If the saved width is
3300
the same as the current width then make it a little be smaller so
3301
the user can see that it changed and it also makes sure that
3302
windowResizeNotify is called and plugins are notified. */
3303
if (xwc->width == (int) serverGeometry.width ())
3313
xwc->height = saveWc.height;
3315
/* As above, if the saved height is the same as the current height
3316
then make it a little be smaller. */
3317
if (xwc->height == (int) serverGeometry.height ())
3325
if (m & CWBorderWidth)
3326
xwc->border_width = saveWc.border_width;
3333
static bool isPendingRestack (compiz::X11::PendingEvent::Ptr p)
3335
compiz::X11::PendingConfigureEvent::Ptr pc = boost::shared_static_cast <compiz::X11::PendingConfigureEvent> (p);
3337
return pc->matchVM (CWStackMode | CWSibling);
3340
static bool isExistingRequest (compiz::X11::PendingEvent::Ptr p, XWindowChanges &xwc, unsigned int valueMask)
3342
compiz::X11::PendingConfigureEvent::Ptr pc = boost::shared_static_cast <compiz::X11::PendingConfigureEvent> (p);
3344
return pc->matchRequest (xwc, valueMask);
3348
PrivateWindow::reconfigureXWindow (unsigned int valueMask,
3349
XWindowChanges *xwc)
3351
unsigned int frameValueMask = 0;
3353
/* Immediately sync window position
3354
* if plugins were updating w->geometry () directly
3355
* in order to avoid a race condition */
3357
window->syncPosition ();
3359
/* Remove redundant bits */
3361
if (valueMask & CWX && serverGeometry.x () == xwc->x)
3362
valueMask &= ~(CWX);
3364
if (valueMask & CWY && serverGeometry.y () == xwc->y)
3365
valueMask &= ~(CWY);
3367
if (valueMask & CWWidth && serverGeometry.width () == xwc->width)
3368
valueMask &= ~(CWWidth);
3370
if (valueMask & CWHeight && serverGeometry.height () == xwc->height)
3371
valueMask &= ~(CWHeight);
3373
if (valueMask & CWBorderWidth && serverGeometry.border () == xwc->border_width)
3374
valueMask &= ~(CWBorderWidth);
3376
if (valueMask & CWSibling && window->serverPrev)
3378
/* check if the sibling is also pending a restack,
3379
* if not, then setting this bit is useless */
3380
if (ROOTPARENT (window->serverPrev) == xwc->sibling)
3382
bool matchingRequest = priv->pendingConfigures.forEachIf (boost::bind (isExistingRequest, _1, *xwc, valueMask));
3383
bool restackPending = window->serverPrev->priv->pendingConfigures.forEachIf (boost::bind (isPendingRestack, _1));
3384
bool remove = matchingRequest;
3387
remove = !restackPending;
3390
valueMask &= ~(CWSibling | CWStackMode);
3394
if (valueMask & CWBorderWidth)
3395
serverGeometry.setBorder (xwc->border_width);
3397
if (valueMask & CWX)
3398
serverGeometry.setX (xwc->x);
3400
if (valueMask & CWY)
3401
serverGeometry.setY (xwc->y);
3403
if (valueMask & CWWidth)
3404
serverGeometry.setWidth (xwc->width);
3406
if (valueMask & CWHeight)
3407
serverGeometry.setHeight (xwc->height);
3409
/* Update the server side window list on raise, lower and restack functions.
3410
* This function should only recieve stack_mode == Above
3411
* but warn incase something else does get through, to make the cause
3412
* of any potential misbehaviour obvious. */
3413
if (valueMask & (CWSibling | CWStackMode))
3415
if (xwc->stack_mode == Above)
3419
screen->unhookServerWindow (window);
3420
screen->insertServerWindow (window, xwc->sibling);
3424
compLogMessage ("core", CompLogLevelWarn, "restack_mode not Above");
3427
frameValueMask = valueMask;
3429
if (frameValueMask & CWX &&
3430
serverFrameGeometry.x () == xwc->x - serverGeometry.border () - serverInput.left)
3431
frameValueMask &= ~(CWX);
3433
if (frameValueMask & CWY &&
3434
serverFrameGeometry.y () == xwc->y - serverGeometry.border () - serverInput.top)
3435
frameValueMask &= ~(CWY);
3437
if (frameValueMask & CWWidth &&
3438
serverFrameGeometry.width () == xwc->width + serverGeometry.border () * 2
3439
+ serverInput.left + serverInput.right)
3440
frameValueMask &= ~(CWWidth);
3442
/* shaded windows are not allowed to have their frame window
3443
* height changed (but are allowed to have their client height
3448
if (frameValueMask & CWHeight &&
3449
serverFrameGeometry.height () == serverGeometry.border () * 2
3450
+ serverInput.top + serverInput.bottom)
3451
frameValueMask &= ~(CWHeight);
3455
if (frameValueMask & CWHeight &&
3456
serverFrameGeometry.height () == xwc->height + serverGeometry.border () * 2
3457
+ serverInput.top + serverInput.bottom)
3458
frameValueMask &= ~(CWHeight);
3461
/* Can't set the border width of frame windows */
3462
frameValueMask &= ~(CWBorderWidth);
3464
if (frameValueMask & CWX)
3465
serverFrameGeometry.setX (xwc->x - serverGeometry.border () - serverInput.left);
3467
if (frameValueMask & CWY)
3468
serverFrameGeometry.setY (xwc->y -serverGeometry.border () - serverInput.top);
3470
if (frameValueMask & CWWidth)
3471
serverFrameGeometry.setWidth (xwc->width + serverGeometry.border () * 2
3472
+ serverInput.left + serverInput.right);
3476
if (frameValueMask & CWHeight)
3477
serverFrameGeometry.setHeight (serverGeometry.border () * 2
3478
+ serverInput.top + serverInput.bottom);
3482
if (frameValueMask & CWHeight)
3483
serverFrameGeometry.setHeight (xwc->height + serverGeometry.border () * 2
3484
+ serverInput.top + serverInput.bottom);
3490
gettimeofday (&lastConfigureRequest, NULL);
3494
XWindowChanges wc = *xwc;
3496
wc.x = serverFrameGeometry.x ();
3497
wc.y = serverFrameGeometry.y ();
3498
wc.width = serverFrameGeometry.width ();
3499
wc.height = serverFrameGeometry.height ();
3501
compiz::X11::PendingEvent::Ptr pc =
3502
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
3503
new compiz::X11::PendingConfigureEvent (
3504
screen->dpy (), priv->serverFrame, frameValueMask, &wc)));
3506
pendingConfigures.add (pc);
3507
if (priv->mClearCheckTimeout.active ())
3508
priv->mClearCheckTimeout.stop ();
3509
priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv),
3512
XConfigureWindow (screen->dpy (), serverFrame, frameValueMask, &wc);
3514
valueMask &= ~(CWSibling | CWStackMode);
3518
xwc->x = serverInput.left;
3519
xwc->y = serverInput.top;
3520
XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc);
3526
window->sendConfigureNotify ();
3530
XConfigureWindow (screen->dpy (), id, valueMask, xwc);
3534
PrivateWindow::stackDocks (CompWindow *w,
3535
CompWindowList &updateList,
3536
XWindowChanges *xwc,
3539
CompWindow *firstFullscreenWindow = NULL;
3540
CompWindow *belowDocks = NULL;
3542
foreach (CompWindow *dw, screen->serverWindows ())
3544
/* fullscreen window found */
3545
if (firstFullscreenWindow)
3547
/* If there is another toplevel window above the fullscreen one
3548
* then we need to stack above that */
3549
if ((dw->priv->managed && !dw->priv->unmanaging) &&
3550
!(dw->priv->state & CompWindowStateHiddenMask) &&
3551
!PrivateWindow::isAncestorTo (w, dw) &&
3552
!(dw->type () & (CompWindowTypeFullscreenMask |
3553
CompWindowTypeDockMask)) &&
3554
!dw->overrideRedirect () &&
3560
else if (dw->type () & CompWindowTypeFullscreenMask)
3562
/* First fullscreen window found when checking up the stack
3563
* now go back down to find a suitable candidate client
3564
* window to put the docks above */
3565
firstFullscreenWindow = dw;
3566
for (CompWindow *dww = dw->serverPrev; dww; dww = dww->serverPrev)
3568
if ((dw->priv->managed && !dw->priv->unmanaging) &&
3569
!(dw->priv->state & CompWindowStateHiddenMask) &&
3570
!(dww->type () & (CompWindowTypeFullscreenMask |
3571
CompWindowTypeDockMask)) &&
3572
!dww->overrideRedirect () &&
3584
*mask = CWSibling | CWStackMode;
3585
xwc->sibling = ROOTPARENT (belowDocks);
3587
/* Collect all dock windows first */
3588
foreach (CompWindow *dw, screen->serverWindows ())
3589
if (dw->priv->type & CompWindowTypeDockMask)
3590
updateList.push_front (dw);
3599
PrivateWindow::stackTransients (CompWindow *w,
3601
XWindowChanges *xwc,
3602
CompWindowList &updateList)
3605
Window clientLeader = w->priv->clientLeader;
3607
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
3608
clientLeader = None;
3610
for (t = screen->serverWindows ().back (); t; t = t->serverPrev)
3612
if (t == w || t == avoid)
3615
if (t->priv->transientFor == w->priv->id ||
3616
t->priv->isGroupTransient (clientLeader))
3618
if (!stackTransients (t, avoid, xwc, updateList))
3621
if (xwc->sibling == t->priv->id ||
3622
(t->priv->serverFrame && xwc->sibling == t->priv->serverFrame))
3625
if (t->priv->mapNum || t->priv->pendingMaps)
3626
updateList.push_back (t);
3634
PrivateWindow::stackAncestors (CompWindow *w,
3635
XWindowChanges *xwc,
3636
CompWindowList &updateList)
3638
CompWindow *transient = NULL;
3640
if (w->priv->transientFor)
3641
transient = screen->findWindow (w->priv->transientFor);
3644
xwc->sibling != transient->priv->id &&
3645
(!transient->priv->serverFrame || xwc->sibling != transient->priv->serverFrame))
3647
CompWindow *ancestor;
3649
ancestor = screen->findWindow (w->priv->transientFor);
3652
if (!stackTransients (ancestor, w, xwc, updateList))
3655
if (ancestor->priv->type & CompWindowTypeDesktopMask)
3658
if (ancestor->priv->type & CompWindowTypeDockMask)
3659
if (!(w->priv->type & CompWindowTypeDockMask))
3662
if (ancestor->priv->mapNum || ancestor->priv->pendingMaps)
3663
updateList.push_back (ancestor);
3665
stackAncestors (ancestor, xwc, updateList);
3668
else if (w->priv->isGroupTransient (w->priv->clientLeader))
3672
for (a = screen->serverWindows ().back (); a; a = a->serverPrev)
3674
if (a->priv->clientLeader == w->priv->clientLeader &&
3675
a->priv->transientFor == None &&
3676
!a->priv->isGroupTransient (w->priv->clientLeader))
3678
if (xwc->sibling == a->priv->id ||
3679
(a->priv->serverFrame && xwc->sibling == a->priv->serverFrame))
3682
if (!stackTransients (a, w, xwc, updateList))
3685
if (a->priv->type & CompWindowTypeDesktopMask)
3688
if (a->priv->type & CompWindowTypeDockMask)
3689
if (!(w->priv->type & CompWindowTypeDockMask))
3692
if (a->priv->mapNum || a->priv->pendingMaps)
3693
updateList.push_back (a);
3700
CompWindow::configureXWindow (unsigned int valueMask,
3701
XWindowChanges *xwc)
3703
if (priv->managed && (valueMask & (CWSibling | CWStackMode)))
3705
CompWindowList transients;
3706
CompWindowList ancestors;
3707
CompWindowList docks;
3709
/* Since the window list is being reordered in reconfigureXWindow
3710
the list of windows which need to be restacked must be stored
3711
first. The windows are stacked in the opposite order than they
3712
were previously stacked, in order that they are above xwc->sibling
3713
so that when compiz gets the ConfigureNotify event it doesn't
3714
have to restack all the windows again. */
3716
/* transient children above */
3717
if (PrivateWindow::stackTransients (this, NULL, xwc, transients))
3719
/* ancestors, siblings and sibling transients below */
3720
PrivateWindow::stackAncestors (this, xwc, ancestors);
3722
for (CompWindowList::reverse_iterator w = ancestors.rbegin ();
3723
w != ancestors.rend (); w++)
3725
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
3726
xwc->sibling = ROOTPARENT (*w);
3729
this->priv->reconfigureXWindow (valueMask, xwc);
3730
xwc->sibling = ROOTPARENT (this);
3732
for (CompWindowList::reverse_iterator w = transients.rbegin ();
3733
w != transients.rend (); w++)
3735
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
3736
xwc->sibling = ROOTPARENT (*w);
3739
if (PrivateWindow::stackDocks (this, docks, xwc, &valueMask))
3741
Window sibling = xwc->sibling;
3742
xwc->stack_mode = Above;
3744
/* Then update the dock windows */
3745
foreach (CompWindow *dw, docks)
3747
xwc->sibling = sibling;
3748
dw->priv->reconfigureXWindow (valueMask, xwc);
3755
priv->reconfigureXWindow (valueMask, xwc);
3760
PrivateWindow::addWindowSizeChanges (XWindowChanges *xwc,
3761
CompWindow::Geometry old)
3769
screen->viewportForGeometry (old, viewport);
3771
x = (viewport.x () - screen->vp ().x ()) * screen->width ();
3772
y = (viewport.y () - screen->vp ().y ()) * screen->height ();
3774
/* Try to select and output device that the window is on first
3775
* and make sure if we are fullscreening or maximizing that the
3776
* window is actually able to fit on this output ... otherwise
3777
* we're going to have to use another output device which sucks
3778
* but at least the user will be able to see all of the window */
3779
output = &screen->outputDevs ().at (screen->outputDeviceForGeometry (old));
3781
if (state & CompWindowStateFullscreenMask ||
3782
state & CompWindowStateMaximizedHorzMask)
3784
int width = (mask & CWWidth) ? xwc->width : old.width ();
3785
int height = (mask & CWHeight) ? xwc->height : old.height ();
3787
window->constrainNewWindowSize (width, height, &width, &height);
3789
if (width > output->width ())
3791
int distance = std::numeric_limits <int>::max ();
3792
CompOutput *selected = output;
3793
/* That's no good ... try and find the closest output device to this one
3794
* which has a large enough size */
3795
foreach (CompOutput &o, screen->outputDevs ())
3797
if (o.workArea ().width () > width)
3799
int tDistance = sqrt (pow (abs (o.x () - output->x ()), 2) +
3800
pow (abs (o.y () - output->y ()), 2));
3802
if (tDistance < distance)
3805
tDistance = distance;
3814
if (state & CompWindowStateFullscreenMask ||
3815
state & CompWindowStateMaximizedVertMask)
3817
int width = (mask & CWWidth) ? xwc->width : old.width ();
3818
int height = (mask & CWHeight) ? xwc->height : old.height ();
3820
window->constrainNewWindowSize (width, height, &width, &height);
3822
if (height > output->height ())
3824
int distance = std::numeric_limits <int>::max ();
3825
CompOutput *selected = output;
3826
/* That's no good ... try and find the closest output device to this one
3827
* which has a large enough size */
3828
foreach (CompOutput &o, screen->outputDevs ())
3830
if (o.workArea ().height () > height)
3832
int tDistance = sqrt (pow (abs (o.x () - output->x ()), 2) +
3833
pow (abs (o.y () - output->y ()), 2));
3835
if (tDistance < distance)
3838
tDistance = distance;
3847
workArea = output->workArea ();
3849
if (type & CompWindowTypeFullscreenMask)
3851
saveGeometry (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3853
if (fullscreenMonitorsSet)
3855
xwc->x = x + fullscreenMonitorRect.x ();
3856
xwc->y = y + fullscreenMonitorRect.y ();
3857
xwc->width = fullscreenMonitorRect.width ();
3858
xwc->height = fullscreenMonitorRect.height ();
3862
xwc->x = x + output->x ();
3863
xwc->y = y + output->y ();
3864
xwc->width = output->width ();
3865
xwc->height = output->height ();
3868
xwc->border_width = 0;
3870
mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
3874
mask |= restoreGeometry (xwc, CWBorderWidth);
3875
if (state & CompWindowStateMaximizedVertMask)
3877
saveGeometry (CWY | CWHeight);
3879
xwc->height = workArea.height () - border.top -
3880
border.bottom - old.border () * 2;
3886
mask |= restoreGeometry (xwc, CWY | CWHeight);
3889
if (state & CompWindowStateMaximizedHorzMask)
3891
saveGeometry (CWX | CWWidth);
3893
xwc->width = workArea.width () - border.left -
3894
border.right - old.border () * 2;
3900
mask |= restoreGeometry (xwc, CWX | CWWidth);
3903
/* constrain window width if smaller than minimum width */
3904
if (!(mask & CWWidth) && (int) old.width () < sizeHints.min_width)
3906
xwc->width = sizeHints.min_width;
3910
/* constrain window width if greater than maximum width */
3911
if (!(mask & CWWidth) && (int) old.width () > sizeHints.max_width)
3913
xwc->width = sizeHints.max_width;
3917
/* constrain window height if smaller than minimum height */
3918
if (!(mask & CWHeight) && (int) old.height () < sizeHints.min_height)
3920
xwc->height = sizeHints.min_height;
3924
/* constrain window height if greater than maximum height */
3925
if (!(mask & CWHeight) && (int) old.height () > sizeHints.max_height)
3927
xwc->height = sizeHints.max_height;
3931
if (mask & (CWWidth | CWHeight))
3933
int width, height, max;
3935
width = (mask & CWWidth) ? xwc->width : old.width ();
3936
height = (mask & CWHeight) ? xwc->height : old.height ();
3938
xwc->width = old.width ();
3939
xwc->height = old.height ();
3941
window->constrainNewWindowSize (width, height, &width, &height);
3943
if (width != (int) old.width ())
3951
if (height != (int) old.height ())
3954
xwc->height = height;
3959
if (state & CompWindowStateMaximizedVertMask)
3961
/* If the window is still offscreen, then we need to constrain it
3962
* by the gravity value (so that the corner that the gravity specifies
3963
* is 'anchored' to that edge of the workarea) */
3965
xwc->y = y + workArea.y () + border.top;
3968
switch (priv->sizeHints.win_gravity)
3970
case SouthWestGravity:
3971
case SouthEastGravity:
3973
/* Shift the window so that the bottom meets the top of the bottom */
3974
height = xwc->height + old.border () * 2;
3976
max = y + workArea.bottom ();
3977
if (xwc->y + xwc->height + border.bottom > max)
3979
xwc->y = max - height - border.bottom;
3983
/* For EastGravity, WestGravity and CenterGravity we default to the top
3984
* of the window since the user should at least be able to close it
3985
* (but not for SouthGravity, SouthWestGravity and SouthEastGravity since
3986
* that indicates that the application has requested positioning in that area
3991
case NorthWestGravity:
3992
case NorthEastGravity:
3995
/* Shift the window so that the top meets the top of the screen */
4000
if (state & CompWindowStateMaximizedHorzMask)
4002
xwc->x = x + workArea.x () + border.left;
4005
switch (priv->sizeHints.win_gravity)
4007
case NorthEastGravity:
4008
case SouthEastGravity:
4010
width = xwc->width + old.border () * 2;
4012
max = x + workArea.right ();
4014
if (old.x () + (int) old.width () + border.right > max)
4016
xwc->x = max - width - border.right;
4019
else if (old.x () + width + border.right > max)
4021
xwc->x = x + workArea.x () +
4022
(workArea.width () - border.left - width -
4023
border.right) / 2 + border.left;
4026
/* For NorthGravity, SouthGravity and CenterGravity we default to the top
4027
* of the window since the user should at least be able to close it
4028
* (but not for SouthGravity, SouthWestGravity and SouthEastGravity since
4029
* that indicates that the application has requested positioning in that area
4034
case NorthWestGravity:
4035
case SouthWestGravity:
4044
if ((mask & CWX) && (xwc->x == old.x ()))
4047
if ((mask & CWY) && (xwc->y == old.y ()))
4050
if ((mask & CWWidth) && (xwc->width == (int) old.width ()))
4053
if ((mask & CWHeight) && (xwc->height == (int) old.height ()))
4060
PrivateWindow::adjustConfigureRequestForGravity (XWindowChanges *xwc,
4066
unsigned int mask = 0;
4071
if (xwcm & (CWX | CWWidth))
4074
case NorthWestGravity:
4076
case SouthWestGravity:
4078
newX += priv->border.left * direction;
4085
newX -= (xwc->width / 2 - priv->border.left +
4086
(priv->border.left + priv->border.right) / 2) * direction;
4088
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
4091
case NorthEastGravity:
4093
case SouthEastGravity:
4095
newX -= xwc->width + priv->border.right * direction;
4097
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
4106
if (xwcm & (CWY | CWHeight))
4109
case NorthWestGravity:
4111
case NorthEastGravity:
4113
newY = xwc->y + priv->border.top * direction;
4120
newY -= (xwc->height / 2 - priv->border.top +
4121
(priv->border.top + priv->border.bottom) / 2) * direction;
4123
newY -= ((xwc->height - priv->serverGeometry.height ()) / 2) * direction;
4126
case SouthWestGravity:
4128
case SouthEastGravity:
4130
newY -= xwc->height + priv->border.bottom * direction;
4132
newY -= (xwc->height - priv->serverGeometry.height ()) * direction;
4143
xwc->x += (newX - xwc->x);
4149
xwc->y += (newY - xwc->y);
4157
CompWindow::moveResize (XWindowChanges *xwc,
4160
unsigned int source)
4162
bool placed = false;
4164
xwcm &= (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
4166
if (xwcm & (CWX | CWY))
4167
if (priv->sizeHints.flags & (USPosition | PPosition))
4171
gravity = priv->sizeHints.win_gravity;
4174
xwc->x = priv->serverGeometry.x ();
4176
xwc->y = priv->serverGeometry.y ();
4177
if (!(xwcm & CWWidth))
4178
xwc->width = priv->serverGeometry.width ();
4179
if (!(xwcm & CWHeight))
4180
xwc->height = priv->serverGeometry.height ();
4182
if (xwcm & (CWWidth | CWHeight))
4186
if (constrainNewWindowSize (xwc->width, xwc->height, &width, &height))
4188
if (width != xwc->width)
4191
if (height != xwc->height)
4195
xwc->height = height;
4199
xwcm |= priv->adjustConfigureRequestForGravity (xwc, xwcm, gravity, 1);
4201
validateResizeRequest (xwcm, xwc, source);
4203
/* when horizontally maximized only allow width changes added by
4204
addWindowSizeChanges */
4205
if (priv->state & CompWindowStateMaximizedHorzMask)
4208
/* when vertically maximized only allow height changes added by
4209
addWindowSizeChanges */
4210
if (priv->state & CompWindowStateMaximizedVertMask)
4213
xwcm |= priv->addWindowSizeChanges (xwc, Geometry (xwc->x, xwc->y,
4214
xwc->width, xwc->height,
4215
xwc->border_width));
4217
/* check if the new coordinates are useful and valid (different
4218
to current size); if not, we have to clear them to make sure
4219
we send a synthetic ConfigureNotify event if all coordinates
4220
match the server coordinates */
4221
if (xwc->x == priv->serverGeometry.x ())
4224
if (xwc->y == priv->serverGeometry.y ())
4227
if (xwc->width == (int) priv->serverGeometry.width ())
4230
if (xwc->height == (int) priv->serverGeometry.height ())
4233
if (xwc->border_width == (int) priv->serverGeometry.border ())
4234
xwcm &= ~CWBorderWidth;
4236
/* update saved window coordinates - if CWX or CWY is set for fullscreen
4237
or maximized windows after addWindowSizeChanges, it should be pretty
4238
safe to assume that the saved coordinates should be updated too, e.g.
4239
because the window was moved to another viewport by some client */
4240
if ((xwcm & CWX) && (priv->saveMask & CWX))
4241
priv->saveWc.x += (xwc->x - priv->serverGeometry.x ());
4243
if ((xwcm & CWY) && (priv->saveMask & CWY))
4244
priv->saveWc.y += (xwc->y - priv->serverGeometry.y ());
4246
if (priv->mapNum && (xwcm & (CWWidth | CWHeight)))
4250
configureXWindow (xwcm, xwc);
4253
/* we have to send a configure notify on ConfigureRequest events if
4254
we decide not to do anything according to ICCCM 4.1.5 */
4255
sendConfigureNotify ();
4259
priv->placed = true;
4263
PrivateWindow::updateSize ()
4265
XWindowChanges xwc = XWINDOWCHANGES_INIT;
4268
if (window->overrideRedirect () || !managed)
4271
mask = priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
4274
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
4275
window->sendSyncRequest ();
4277
window->configureXWindow (mask, &xwc);
4282
PrivateWindow::addWindowStackChanges (XWindowChanges *xwc,
4283
CompWindow *sibling)
4287
if (!sibling || sibling->priv->id != id)
4289
/* Alow requests to go on top of serverPrev
4290
* if serverPrev was recently restacked */
4291
if (window->serverPrev)
4295
XWindowChanges lxwc = XWINDOWCHANGES_INIT;
4296
unsigned int valueMask = CWStackMode;
4298
lxwc.stack_mode = Below;
4302
compiz::X11::PendingEvent::Ptr pc =
4303
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
4304
new compiz::X11::PendingConfigureEvent (
4305
screen->dpy (), serverFrame, valueMask, &lxwc)));
4307
pendingConfigures.add (pc);
4308
if (priv->mClearCheckTimeout.active ())
4309
priv->mClearCheckTimeout.stop ();
4310
priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv),
4314
/* Below with no sibling puts the window at the bottom
4316
XConfigureWindow (screen->dpy (), ROOTPARENT (window), valueMask, &lxwc);
4318
/* Update the list of windows last sent to the server */
4319
screen->unhookServerWindow (window);
4320
screen->insertServerWindow (window, 0);
4324
bool matchingRequest = priv->pendingConfigures.forEachIf (boost::bind (isExistingRequest, _1, *xwc, (CWStackMode | CWSibling)));
4325
bool restackPending = window->serverPrev->priv->pendingConfigures.forEachIf (boost::bind (isPendingRestack, _1));
4326
bool processAnyways = restackPending;
4328
if (matchingRequest)
4329
processAnyways = false;
4331
if (sibling->priv->id != window->serverPrev->priv->id ||
4334
mask |= CWSibling | CWStackMode;
4336
xwc->stack_mode = Above;
4337
xwc->sibling = ROOTPARENT (sibling);
4343
mask |= CWSibling | CWStackMode;
4345
xwc->stack_mode = Above;
4346
xwc->sibling = ROOTPARENT (sibling);
4354
CompWindow::raise ()
4356
XWindowChanges xwc = XWINDOWCHANGES_INIT;
4358
bool aboveFs = false;
4360
/* an active fullscreen window should be raised over all other
4361
windows in its layer */
4362
if (priv->type & CompWindowTypeFullscreenMask)
4363
if (priv->id == screen->activeWindow ())
4366
for (CompWindow *pw = serverPrev; pw; pw = pw->serverPrev)
4368
if (pw->priv->type & CompWindowTypeFullscreenMask)
4370
if (priv->id == screen->activeWindow ())
4377
mask = priv->addWindowStackChanges (&xwc,
4378
PrivateWindow::findSiblingBelow (this, aboveFs));
4381
configureXWindow (mask, &xwc);
4385
PrivateScreen::focusTopMostWindow ()
4387
CompWindow *focus = NULL;
4388
CompWindowList::reverse_iterator it = serverWindows.rbegin ();
4390
for (; it != serverWindows.rend (); it++)
4392
CompWindow *w = *it;
4394
if (w->type () & CompWindowTypeDockMask)
4406
if (focus->id () != activeWindow)
4407
focus->moveInputFocusTo ();
4410
XSetInputFocus (dpy, root, RevertToPointerRoot,
4417
CompWindow::lower ()
4419
XWindowChanges xwc = XWINDOWCHANGES_INIT;
4422
mask = priv->addWindowStackChanges (&xwc,
4423
PrivateWindow::findLowestSiblingBelow (this));
4425
configureXWindow (mask, &xwc);
4427
/* when lowering a window, focus the topmost window if
4428
the click-to-focus option is on */
4429
if ((screen->priv->optionGetClickToFocus ()))
4431
CompWindow *focusedWindow = screen->priv->focusTopMostWindow ();
4433
/* if the newly focused window is a desktop window,
4434
give the focus back to w */
4435
if (focusedWindow &&
4436
focusedWindow->type () & CompWindowTypeDesktopMask)
4438
moveInputFocusTo ();
4444
CompWindow::restackAbove (CompWindow *sibling)
4446
for (; sibling; sibling = sibling->serverNext)
4447
if (PrivateWindow::validSiblingBelow (this, sibling))
4452
XWindowChanges xwc = XWINDOWCHANGES_INIT;
4455
mask = priv->addWindowStackChanges (&xwc, sibling);
4457
configureXWindow (mask, &xwc);
4461
/* finds the highest window under sibling we can stack above */
4463
PrivateWindow::findValidStackSiblingBelow (CompWindow *w,
4464
CompWindow *sibling)
4466
CompWindow *lowest, *last, *p;
4468
/* check whether we're allowed to stack under a sibling by finding
4469
* the above 'sibling' and checking whether or not we're allowed
4470
* to stack under that - if not, then there is no valid sibling
4473
for (p = sibling; p; p = p->serverNext)
4475
if (!avoidStackingRelativeTo (p))
4477
if (!validSiblingBelow (p, w))
4483
/* get lowest sibling we're allowed to stack above */
4484
lowest = last = findLowestSiblingBelow (w);
4486
/* walk from bottom up */
4487
for (p = screen->serverWindows ().front (); p; p = p->serverNext)
4489
/* stop walking when we reach the sibling we should try to stack
4494
/* skip windows that we should avoid */
4495
if (w == p || avoidStackingRelativeTo (p))
4498
if (validSiblingBelow (w, p))
4500
/* update lowest as we find windows below sibling that we're
4501
allowed to stack above. last window must be equal to the
4502
lowest as we shouldn't update lowest if we passed an
4508
/* update last pointer */
4516
CompWindow::restackBelow (CompWindow *sibling)
4518
XWindowChanges xwc = XWINDOWCHANGES_INIT;
4521
mask = priv->addWindowStackChanges (&xwc,
4522
PrivateWindow::findValidStackSiblingBelow (this, sibling));
4525
configureXWindow (mask, &xwc);
4529
CompWindow::updateAttributes (CompStackingUpdateMode stackingMode)
4531
XWindowChanges xwc = XWINDOWCHANGES_INIT;
4534
if (overrideRedirect () || !priv->managed)
4537
if (priv->state & CompWindowStateShadedMask && !priv->shaded)
4539
windowNotify (CompWindowNotifyShade);
4543
else if (priv->shaded)
4545
windowNotify (CompWindowNotifyUnshade);
4550
if (stackingMode != CompStackingUpdateModeNone)
4553
CompWindow *sibling;
4555
aboveFs = (stackingMode == CompStackingUpdateModeAboveFullscreen);
4556
if (priv->type & CompWindowTypeFullscreenMask)
4558
/* put active or soon-to-be-active fullscreen windows over
4559
all others in their layer */
4560
if (priv->id == screen->activeWindow () ||
4561
priv->id == screen->priv->nextActiveWindow)
4567
/* put windows that are just mapped, over fullscreen windows */
4568
if (stackingMode == CompStackingUpdateModeInitialMap)
4571
sibling = PrivateWindow::findSiblingBelow (this, aboveFs);
4574
(stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
4578
for (p = sibling; p; p = p->serverPrev)
4579
if (p->priv->id == screen->activeWindow ())
4582
/* window is above active window so we should lower it,
4583
* assuing that is allowed (if, for example, our window has
4584
* the "above" state, then lowering beneath the active
4585
* window may not be allowed). */
4586
if (p && PrivateWindow::validSiblingBelow (p, this))
4588
p = PrivateWindow::findValidStackSiblingBelow (this, p);
4590
/* if we found a valid sibling under the active window, it's
4591
our new sibling we want to stack above */
4599
mask |= priv->addWindowStackChanges (&xwc, sibling);
4603
mask |= priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
4605
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
4609
configureXWindow (mask, &xwc);
4613
PrivateWindow::ensureWindowVisibility ()
4616
int width = serverGeometry.width () + serverGeometry.border () * 2;
4617
int height = serverGeometry.height () + serverGeometry.border () * 2;
4621
if (struts || attrib.override_redirect)
4624
if (type & (CompWindowTypeDockMask |
4625
CompWindowTypeFullscreenMask |
4626
CompWindowTypeUnknownMask))
4629
x1 = screen->workArea ().x () - screen->width () * screen->vp ().x ();
4630
y1 = screen->workArea ().y () - screen->height () * screen->vp ().y ();
4631
x2 = x1 + screen->workArea ().width () + screen->vpSize ().width () *
4633
y2 = y1 + screen->workArea ().height () + screen->vpSize ().height () *
4636
if (serverGeometry.x () - serverInput.left >= x2)
4637
dx = (x2 - 25) - serverGeometry.x ();
4638
else if (serverGeometry.x () + width + serverInput.right <= x1)
4639
dx = (x1 + 25) - (serverGeometry.x () + width);
4641
if (serverGeometry.y () - serverInput.top >= y2)
4642
dy = (y2 - 25) - serverGeometry.y ();
4643
else if (serverGeometry.y () + height + serverInput.bottom <= y1)
4644
dy = (y1 + 25) - (serverGeometry.y () + height);
4648
XWindowChanges xwc = XWINDOWCHANGES_INIT;
4650
xwc.x = serverGeometry.x () + dx;
4651
xwc.y = serverGeometry.y () + dy;
4653
window->configureXWindow (CWX | CWY, &xwc);
4658
PrivateWindow::reveal ()
4660
if (window->minimized ())
4661
window->unminimize ();
4663
screen->leaveShowDesktopMode (window);
4667
PrivateWindow::revealAncestors (CompWindow *w,
4668
CompWindow *transient)
4670
if (isAncestorTo (transient, w))
4672
screen->forEachWindow (boost::bind (revealAncestors, _1, w));
4678
CompWindow::activate ()
4680
WRAPABLE_HND_FUNCTN (activate)
4682
screen->priv->setCurrentDesktop (priv->desktop);
4684
screen->forEachWindow (
4685
boost::bind (PrivateWindow::revealAncestors, _1, this));
4688
if (priv->state & CompWindowStateHiddenMask)
4690
priv->state &= ~CompWindowStateShadedMask;
4695
if (priv->state & CompWindowStateHiddenMask)
4698
if (!onCurrentDesktop ())
4701
priv->ensureWindowVisibility ();
4702
updateAttributes (CompStackingUpdateModeAboveFullscreen);
4703
moveInputFocusTo ();
4707
#define PVertResizeInc (1 << 0)
4708
#define PHorzResizeInc (1 << 1)
4711
CompWindow::constrainNewWindowSize (int width,
4716
CompSize size (width, height);
4717
long ignoredHints = 0;
4718
long ignoredResizeHints = 0;
4720
if (screen->priv->optionGetIgnoreHintsWhenMaximized ())
4722
ignoredHints |= PAspect;
4724
if (priv->state & CompWindowStateMaximizedHorzMask)
4725
ignoredResizeHints |= PHorzResizeInc;
4727
if (priv->state & CompWindowStateMaximizedVertMask)
4728
ignoredResizeHints |= PVertResizeInc;
4731
CompSize ret = compiz::window::constrainment::constrainToHints (priv->sizeHints,
4733
ignoredHints, ignoredResizeHints);
4735
*newWidth = ret.width ();
4736
*newHeight = ret.height ();
4744
priv->hidden = true;
4751
priv->hidden = false;
4756
PrivateWindow::hide ()
4758
bool onDesktop = window->onCurrentDesktop ();
4763
if (!window->minimized () && !inShowDesktopMode &&
4764
!hidden && onDesktop)
4766
if (state & CompWindowStateShadedMask)
4779
if ((state & CompWindowStateShadedMask) && serverFrame)
4780
XUnmapWindow (screen->dpy (), serverFrame);
4783
if (!pendingMaps && !window->isViewable ())
4786
window->windowNotify (CompWindowNotifyHide);
4790
if (serverFrame && !shaded)
4791
XUnmapWindow (screen->dpy (), serverFrame);
4793
XUnmapWindow (screen->dpy (), id);
4795
if (window->minimized () || inShowDesktopMode || hidden || shaded)
4796
window->changeState (state | CompWindowStateHiddenMask);
4798
if (shaded && id == screen->activeWindow ())
4799
window->moveInputFocusTo ();
4803
PrivateWindow::show ()
4805
bool onDesktop = window->onCurrentDesktop ();
4810
if (minimized || inShowDesktopMode ||
4811
hidden || !onDesktop)
4813
/* no longer hidden but not on current desktop */
4814
if (!minimized && !inShowDesktopMode && !hidden)
4815
window->changeState (state & ~CompWindowStateHiddenMask);
4820
/* transition from minimized to shaded */
4821
if (state & CompWindowStateShadedMask)
4826
XMapWindow (screen->dpy (), serverFrame);
4828
updateFrameWindow ();
4833
window->windowNotify (CompWindowNotifyShow);
4839
XMapWindow (screen->dpy (), serverFrame);
4840
XMapWindow (screen->dpy (), wrapper);
4843
XMapWindow (screen->dpy (), id);
4845
window->changeState (state & ~CompWindowStateHiddenMask);
4846
screen->priv->setWindowState (state, id);
4850
PrivateWindow::minimizeTransients (CompWindow *w,
4851
CompWindow *ancestor)
4853
if (w->priv->transientFor == ancestor->priv->id ||
4854
w->priv->isGroupTransient (ancestor->priv->clientLeader))
4861
CompWindow::minimize ()
4863
WRAPABLE_HND_FUNCTN (minimize);
4868
if (!priv->minimized)
4870
windowNotify (CompWindowNotifyMinimize);
4872
priv->minimized = true;
4874
screen->forEachWindow (
4875
boost::bind (PrivateWindow::minimizeTransients, _1, this));
4882
PrivateWindow::unminimizeTransients (CompWindow *w,
4883
CompWindow *ancestor)
4885
if (w->priv->transientFor == ancestor->priv->id ||
4886
w->priv->isGroupTransient (ancestor->priv->clientLeader))
4891
CompWindow::unminimize ()
4893
WRAPABLE_HND_FUNCTN (unminimize);
4894
if (priv->minimized)
4896
windowNotify (CompWindowNotifyUnminimize);
4898
priv->minimized = false;
4902
screen->forEachWindow (
4903
boost::bind (PrivateWindow::unminimizeTransients, _1, this));
4908
CompWindow::maximize (unsigned int state)
4910
if (overrideRedirect ())
4913
state = constrainWindowState (state, priv->actions);
4915
state &= MAXIMIZE_STATE;
4917
if (state == (priv->state & MAXIMIZE_STATE))
4920
state |= (priv->state & ~MAXIMIZE_STATE);
4922
changeState (state);
4923
updateAttributes (CompStackingUpdateModeNone);
4927
PrivateWindow::getUserTime (Time& time)
4931
unsigned long n, left;
4932
unsigned char *data;
4933
bool retval = false;
4935
result = XGetWindowProperty (screen->dpy (), priv->id,
4937
0L, 1L, False, XA_CARDINAL, &actual, &format,
4940
if (result == Success && data)
4946
memcpy (&value, data, sizeof (CARD32));
4948
time = (Time) value;
4951
XFree ((void *) data);
4958
PrivateWindow::setUserTime (Time time)
4960
CARD32 value = (CARD32) time;
4962
XChangeProperty (screen->dpy (), priv->id,
4964
XA_CARDINAL, 32, PropModeReplace,
4965
(unsigned char *) &value, 1);
4969
* Macros from metacity
4971
* Xserver time can wraparound, thus comparing two timestamps needs to
4972
* take this into account. Here's a little macro to help out. If no
4973
* wraparound has occurred, this is equivalent to
4975
* Of course, the rest of the ugliness of this macro comes from
4976
* accounting for the fact that wraparound can occur and the fact that
4977
* a timestamp of 0 must be special-cased since it means older than
4980
* Note that this is NOT an equivalent for time1 <= time2; if that's
4981
* what you need then you'll need to swap the order of the arguments
4982
* and negate the result.
4984
#define XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) \
4985
( (( (time1) < (time2) ) && \
4986
( (time2) - (time1) < ((unsigned long) -1) / 2 )) || \
4987
(( (time1) > (time2) ) && \
4988
( (time1) - (time2) > ((unsigned long) -1) / 2 )) \
4990
#define XSERVER_TIME_IS_BEFORE(time1, time2) \
4992
(XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS (time1, time2) && \
4997
PrivateWindow::getUsageTimestamp (Time& timestamp)
4999
if (getUserTime (timestamp))
5002
if (initialTimestampSet)
5004
timestamp = initialTimestamp;
5012
PrivateWindow::isWindowFocusAllowed (Time timestamp)
5014
CompScreen *s = screen;
5016
Time wUserTime, aUserTime;
5017
bool gotTimestamp = false;
5021
level = s->priv->optionGetFocusPreventionLevel ();
5023
if (level == CoreOptions::FocusPreventionLevelOff)
5028
/* the caller passed a timestamp, so use that
5029
instead of the window's user time */
5030
wUserTime = timestamp;
5031
gotTimestamp = true;
5035
gotTimestamp = getUsageTimestamp (wUserTime);
5038
/* if we got no timestamp for the window, try to get at least a timestamp
5039
for its transient parent, if any */
5040
if (!gotTimestamp && transientFor)
5044
parent = screen->findWindow (transientFor);
5046
gotTimestamp = parent->priv->getUsageTimestamp (wUserTime);
5049
if (gotTimestamp && !wUserTime)
5051
/* window explicitly requested no focus */
5055
/* allow focus for excluded windows */
5056
CompMatch &match = s->priv->optionGetFocusPreventionMatch ();
5057
if (!match.evaluate (window))
5060
if (level == CoreOptions::FocusPreventionLevelVeryHigh)
5063
active = s->findWindow (s->activeWindow ());
5065
/* no active window */
5066
if (!active || (active->type () & CompWindowTypeDesktopMask))
5069
/* active window belongs to same application */
5070
if (window->clientLeader () == active->clientLeader ())
5073
if (level == CoreOptions::FocusPreventionLevelHigh)
5076
/* not in current viewport or desktop */
5077
if (!window->onCurrentDesktop ())
5080
dvp = window->defaultViewport ();
5081
if (dvp.x () != s->vp ().x () || dvp.y () != s->vp ().y ())
5086
/* unsure as we have nothing to compare - allow focus in low level,
5087
don't allow in normal level */
5088
if (level == CoreOptions::FocusPreventionLevelNormal)
5094
/* can't get user time for active window */
5095
if (!active->priv->getUserTime (aUserTime))
5098
if (XSERVER_TIME_IS_BEFORE (wUserTime, aUserTime))
5105
PrivateWindow::allowWindowFocus (unsigned int noFocusMask,
5110
if (priv->id == screen->activeWindow ())
5113
/* do not focus windows of these types */
5114
if (priv->type & noFocusMask)
5117
/* window doesn't take focus */
5118
if (!priv->inputHint &&
5119
!(priv->protocols & CompWindowProtocolTakeFocusMask))
5124
retval = priv->isWindowFocusAllowed (timestamp);
5127
/* add demands attention state if focus was prevented */
5128
window->changeState (priv->state | CompWindowStateDemandsAttentionMask);
5135
CompWindow::defaultViewport ()
5139
if (priv->serverGeometry.x () < (int) screen->width () &&
5140
priv->serverGeometry.x () + priv->serverGeometry.width () > 0 &&
5141
priv->serverGeometry.y () < (int) screen->height () &&
5142
priv->serverGeometry.y ()+ priv->serverGeometry.height () > 0)
5144
return screen->vp ();
5147
screen->viewportForGeometry (priv->serverGeometry, viewport);
5153
CompWindow::initialViewport () const
5155
return priv->initialViewport;
5159
PrivateWindow::readIconHint ()
5161
XImage *image, *maskImage = NULL;
5162
Display *dpy = screen->dpy ();
5163
unsigned int width, height, dummy;
5164
unsigned int i, j, k;
5171
if (!XGetGeometry (dpy, hints->icon_pixmap, &wDummy, &iDummy,
5172
&iDummy, &width, &height, &dummy, &dummy))
5175
image = XGetImage (dpy, hints->icon_pixmap, 0, 0, width, height,
5176
AllPlanes, ZPixmap);
5180
colors = new XColor[width * height];
5183
XDestroyImage (image);
5188
for (j = 0; j < height; j++)
5189
for (i = 0; i < width; i++)
5190
colors[k++].pixel = XGetPixel (image, i, j);
5192
for (i = 0; i < k; i += 256)
5193
XQueryColors (dpy, screen->priv->colormap,
5194
&colors[i], MIN (k - i, 256));
5196
XDestroyImage (image);
5198
icon = new CompIcon (width, height);
5205
if (hints->flags & IconMaskHint)
5206
maskImage = XGetImage (dpy, hints->icon_mask, 0, 0,
5207
width, height, AllPlanes, ZPixmap);
5210
p = (CARD32 *) icon->data ();
5212
for (j = 0; j < height; j++)
5214
for (i = 0; i < width; i++)
5216
if (maskImage && !XGetPixel (maskImage, i, j))
5218
else if (image->depth == 1) /* white : black */
5219
*p++ = colors[k].pixel ? 0xffffffff : 0xff000000;
5221
*p++ = 0xff000000 | /* alpha */
5222
(((colors[k].red >> 8) & 0xff) << 16) | /* red */
5223
(((colors[k].green >> 8) & 0xff) << 8) | /* green */
5224
((colors[k].blue >> 8) & 0xff); /* blue */
5232
XDestroyImage (maskImage);
5234
icons.push_back (icon);
5237
/* returns icon with dimensions as close as possible to width and height
5238
but never greater. */
5240
CompWindow::getIcon (int width,
5244
int wh, diff, oldDiff;
5247
/* need to fetch icon property */
5248
if (priv->icons.size () == 0 && !priv->noIcons)
5252
unsigned long n, left;
5253
unsigned char *data;
5255
result = XGetWindowProperty (screen->dpy (), priv->id, Atoms::wmIcon,
5256
0L, 65536L, false, XA_CARDINAL,
5257
&actual, &format, &n, &left, &data);
5259
if (result == Success && data)
5262
CARD32 alpha, red, green, blue;
5263
unsigned long iw, ih;
5265
for (i = 0; i + 2 < n; i += iw * ih + 2)
5267
unsigned long *idata = (unsigned long *) data;
5272
/* iw * ih may be larger than the value range of unsigned
5273
* long, so better do some checking for extremely weird
5274
* icon sizes first */
5275
if (iw > 2048 || ih > 2048 || iw * ih + 2 > n - i)
5281
icon = new CompIcon (iw, ih);
5285
priv->icons.push_back (icon);
5287
p = (CARD32 *) (icon->data ());
5289
/* EWMH doesn't say if icon data is premultiplied or
5290
not but most applications seem to assume data should
5291
be unpremultiplied. */
5292
for (j = 0; j < iw * ih; j++)
5294
alpha = (idata[i + j + 2] >> 24) & 0xff;
5295
red = (idata[i + j + 2] >> 16) & 0xff;
5296
green = (idata[i + j + 2] >> 8) & 0xff;
5297
blue = (idata[i + j + 2] >> 0) & 0xff;
5299
red = (red * alpha) >> 8;
5300
green = (green * alpha) >> 8;
5301
blue = (blue * alpha) >> 8;
5314
else if (priv->hints && (priv->hints->flags & IconPixmapHint))
5316
priv->readIconHint ();
5319
/* don't fetch property again */
5320
if (priv->icons.size () == 0)
5321
priv->noIcons = true;
5324
/* no icons available for this window */
5329
wh = width + height;
5331
for (i = 0; i < priv->icons.size (); i++)
5333
const CompSize iconSize = *priv->icons[i];
5335
if ((int) iconSize.width () > width ||
5336
(int) iconSize.height () > height)
5341
diff = wh - (iconSize.width () + iconSize.height ());
5342
oldDiff = wh - (icon->width () + icon->height ());
5345
icon = priv->icons[i];
5348
icon = priv->icons[i];
5355
CompWindow::iconGeometry () const
5357
return priv->iconGeometry;
5361
PrivateWindow::freeIcons ()
5363
for (unsigned int i = 0; i < priv->icons.size (); i++)
5364
delete priv->icons[i];
5366
priv->icons.resize (0);
5367
priv->noIcons = false;
5371
CompWindow::outputDevice ()
5373
return screen->outputDeviceForGeometry (priv->serverGeometry);
5377
CompWindow::onCurrentDesktop ()
5379
if (priv->desktop == 0xffffffff ||
5380
priv->desktop == screen->currentDesktop ())
5389
CompWindow::setDesktop (unsigned int desktop)
5391
if (desktop != 0xffffffff)
5393
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5396
if (desktop >= screen->nDesktop ())
5400
if (desktop == priv->desktop)
5403
priv->desktop = desktop;
5405
if (desktop == 0xffffffff || desktop == screen->currentDesktop ())
5410
screen->setWindowProp (priv->id, Atoms::winDesktop, priv->desktop);
5413
/* The compareWindowActiveness function compares the two windows 'w1'
5414
and 'w2'. It returns an integer less than, equal to, or greater
5415
than zero if 'w1' is found, respectively, to activated longer time
5416
ago than, to be activated at the same time, or be activated more
5417
recently than 'w2'. */
5419
PrivateWindow::compareWindowActiveness (CompWindow *w1,
5422
CompActiveWindowHistory *history = screen->currentHistory ();
5425
/* check current window history first */
5426
for (i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
5428
if (history->id[i] == w1->priv->id)
5431
if (history->id[i] == w2->priv->id)
5434
if (!history->id[i])
5438
return w1->priv->activeNum - w2->priv->activeNum;
5442
CompWindow::onAllViewports ()
5444
if (overrideRedirect ())
5447
if (!priv->managed && !isViewable ())
5450
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5453
if (priv->state & CompWindowStateStickyMask)
5460
CompWindow::getMovementForOffset (CompPoint offset)
5462
CompScreen *s = screen;
5463
int m, vWidth, vHeight;
5464
int offX = offset.x (), offY = offset.y ();
5467
vWidth = s->width () * s->vpSize ().width ();
5468
vHeight = s->height () * s->vpSize ().height ();
5474
if (s->vpSize ().width () == 1)
5480
m = priv->geometry.x () + offX;
5481
if (m - priv->input.left < (int) s->width () - vWidth)
5482
rv.setX (offX + vWidth);
5483
else if (m + priv->width + priv->input.right > vWidth)
5484
rv.setX (offX - vWidth);
5489
if (s->vpSize ().height () == 1)
5495
m = priv->geometry.y () + offY;
5496
if (m - priv->input.top < (int) s->height () - vHeight)
5497
rv.setY (offY + vHeight);
5498
else if (m + priv->height + priv->input.bottom > vHeight)
5499
rv.setY (offY - vHeight);
5508
WindowInterface::getOutputExtents (CompWindowExtents& output)
5509
WRAPABLE_DEF (getOutputExtents, output)
5512
WindowInterface::getAllowedActions (unsigned int &setActions,
5513
unsigned int &clearActions)
5514
WRAPABLE_DEF (getAllowedActions, setActions, clearActions)
5517
WindowInterface::focus ()
5518
WRAPABLE_DEF (focus)
5521
WindowInterface::activate ()
5522
WRAPABLE_DEF (activate)
5525
WindowInterface::place (CompPoint &pos)
5526
WRAPABLE_DEF (place, pos)
5529
WindowInterface::validateResizeRequest (unsigned int &mask,
5530
XWindowChanges *xwc,
5531
unsigned int source)
5532
WRAPABLE_DEF (validateResizeRequest, mask, xwc, source)
5535
WindowInterface::resizeNotify (int dx,
5539
WRAPABLE_DEF (resizeNotify, dx, dy, dwidth, dheight)
5542
WindowInterface::moveNotify (int dx,
5545
WRAPABLE_DEF (moveNotify, dx, dy, immediate)
5548
WindowInterface::windowNotify (CompWindowNotify n)
5549
WRAPABLE_DEF (windowNotify, n)
5552
WindowInterface::grabNotify (int x,
5556
WRAPABLE_DEF (grabNotify, x, y, state, mask)
5559
WindowInterface::ungrabNotify ()
5560
WRAPABLE_DEF (ungrabNotify)
5563
WindowInterface::stateChangeNotify (unsigned int lastState)
5564
WRAPABLE_DEF (stateChangeNotify, lastState)
5567
WindowInterface::updateFrameRegion (CompRegion ®ion)
5568
WRAPABLE_DEF (updateFrameRegion, region)
5571
WindowInterface::minimize ()
5572
WRAPABLE_DEF (minimize);
5575
WindowInterface::unminimize ()
5576
WRAPABLE_DEF (unminimize);
5579
WindowInterface::minimized ()
5580
WRAPABLE_DEF (minimized);
5583
WindowInterface::alpha ()
5584
WRAPABLE_DEF (alpha);
5587
WindowInterface::isFocussable ()
5588
WRAPABLE_DEF (isFocussable);
5591
WindowInterface::managed ()
5592
WRAPABLE_DEF (managed);
5595
WindowInterface::focused ()
5596
WRAPABLE_DEF (focused);
5611
CompWindow::state ()
5617
CompWindow::actions ()
5619
return priv->actions;
5623
CompWindow::protocols ()
5625
return priv->protocols;
5629
CompWindow::close (Time serverTime)
5631
if (serverTime == 0)
5632
serverTime = screen->getCurrentTime ();
5636
if (priv->protocols & CompWindowProtocolDeleteMask)
5640
ev.type = ClientMessage;
5641
ev.xclient.window = priv->id;
5642
ev.xclient.message_type = Atoms::wmProtocols;
5643
ev.xclient.format = 32;
5644
ev.xclient.data.l[0] = Atoms::wmDeleteWindow;
5645
ev.xclient.data.l[1] = serverTime;
5646
ev.xclient.data.l[2] = 0;
5647
ev.xclient.data.l[3] = 0;
5648
ev.xclient.data.l[4] = 0;
5650
XSendEvent (screen->dpy (), priv->id, false, NoEventMask, &ev);
5654
XKillClient (screen->dpy (), priv->id);
5657
priv->closeRequests++;
5661
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5662
serverTime, priv->id, true, 0, 0);
5665
priv->lastCloseRequestTime = serverTime;
5669
PrivateWindow::handlePingTimeout (unsigned int lastPing)
5671
if (!window->isViewable ())
5674
if (!(priv->type & CompWindowTypeNormalMask))
5677
if (priv->protocols & CompWindowProtocolPingMask)
5679
if (priv->transientFor)
5682
if (priv->lastPong < lastPing)
5686
priv->alive = false;
5688
window->windowNotify (CompWindowNotifyAliveChanged);
5690
if (priv->closeRequests)
5692
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5693
priv->lastCloseRequestTime,
5694
priv->id, true, 0, 0);
5696
priv->closeRequests = 0;
5707
PrivateWindow::handlePing (int lastPing)
5713
window->windowNotify (CompWindowNotifyAliveChanged);
5715
if (priv->lastCloseRequestTime)
5717
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5718
priv->lastCloseRequestTime,
5719
priv->id, false, 0, 0);
5721
priv->lastCloseRequestTime = 0;
5724
priv->lastPong = lastPing;
5728
PrivateWindow::processMap ()
5731
bool initiallyMinimized;
5732
CompStackingUpdateMode stackingMode;
5734
priv->initialViewport = screen->vp ();
5736
priv->initialTimestampSet = false;
5738
screen->priv->applyStartupProperties (window);
5740
initiallyMinimized = (priv->hints &&
5741
priv->hints->initial_state == IconicState &&
5742
!window->minimized ());
5744
if (!serverFrame && !initiallyMinimized)
5747
priv->managed = true;
5751
int gravity = priv->sizeHints.win_gravity;
5752
XWindowChanges xwc = XWINDOWCHANGES_INIT;
5755
/* adjust for gravity, but only for frame size */
5756
xwc.x = priv->serverGeometry.x ();
5757
xwc.y = priv->serverGeometry.y ();
5761
xwcm = adjustConfigureRequestForGravity (&xwc, CWX | CWY, gravity, 1);
5763
window->validateResizeRequest (xwcm, &xwc, ClientTypeApplication);
5765
CompPoint pos (xwc.x, xwc.y);
5766
if (window->place (pos))
5774
window->configureXWindow (xwcm, &xwc);
5776
priv->placed = true;
5779
allowFocus = allowWindowFocus (NO_FOCUS_MASK, 0);
5781
if (!allowFocus && (priv->type & ~NO_FOCUS_MASK))
5782
stackingMode = CompStackingUpdateModeInitialMapDeniedFocus;
5784
stackingMode = CompStackingUpdateModeInitialMap;
5786
window->updateAttributes (stackingMode);
5788
if (window->minimized () && !initiallyMinimized)
5789
window->unminimize ();
5791
screen->leaveShowDesktopMode (window);
5793
if (!initiallyMinimized)
5795
if (allowFocus && !window->onCurrentDesktop ());
5796
screen->priv->setCurrentDesktop (priv->desktop);
5798
if (!(priv->state & CompWindowStateHiddenMask))
5803
window->moveInputFocusTo ();
5804
if (!window->onCurrentDesktop ())
5805
screen->priv->setCurrentDesktop (priv->desktop);
5810
window->minimize ();
5811
window->changeState (window->state () | CompWindowStateHiddenMask);
5814
screen->priv->updateClientList ();
5818
* PrivateWindow::updatePassiveButtonGrabs
5820
* Updates the passive button grabs for a window. When
5821
* one of the specified button + modifier combinations
5822
* for this window is activated, compiz will be given
5823
* an active grab for the window (which we can turn off
5824
* by calling XAllowEvents later in ::handleEvent)
5826
* NOTE: ICCCM says that we are only allowed to grab
5827
* windows that we actually own as a client, so only
5828
* grab the frame window. Additionally, although there
5829
* isn't anything in the ICCCM that says we cannot
5830
* grab every button, some clients do not interpret
5831
* EnterNotify and LeaveNotify events caused by the
5832
* activation of the grab correctly, so ungrab button
5833
* and modifier combinations that we do not need on
5834
* active windows (but in reality we shouldn't be grabbing
5835
* for buttons that we don't actually need at that point
5840
PrivateWindow::updatePassiveButtonGrabs ()
5842
bool onlyActions = (priv->id == screen->priv->activeWindow ||
5843
!screen->priv->optionGetClickToFocus ());
5848
/* Ungrab everything */
5849
XUngrabButton (screen->priv->dpy, AnyButton, AnyModifier, frame);
5851
/* We don't need the full grab in the following cases:
5852
* - This window has the focus and either
5854
* - we don't want click raise
5859
if (screen->priv->optionGetRaiseOnClick ())
5861
CompWindow *highestSibling =
5862
PrivateWindow::findSiblingBelow (window, true);
5864
/* Check if this window is permitted to be raised */
5865
for (CompWindow *above = window->serverNext;
5866
above != NULL; above = above->serverNext)
5868
if (highestSibling == above)
5870
onlyActions = false;
5879
/* Grab only we have bindings on */
5880
foreach (PrivateScreen::ButtonGrab &bind, screen->priv->buttonGrabs)
5882
unsigned int mods = modHandler->virtualToRealModMask (bind.modifiers);
5884
if (mods & CompNoMask)
5887
for (unsigned int ignore = 0;
5888
ignore <= modHandler->ignoredModMask (); ignore++)
5890
if (ignore & ~modHandler->ignoredModMask ())
5893
XGrabButton (screen->priv->dpy,
5898
ButtonPressMask | ButtonReleaseMask |
5909
/* Grab everything */
5910
XGrabButton (screen->priv->dpy,
5914
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
5924
CompWindow::region () const
5926
return priv->region;
5930
CompWindow::frameRegion () const
5932
return priv->frameRegion;
5936
CompWindow::inShowDesktopMode ()
5938
return priv->inShowDesktopMode;
5942
CompWindow::setShowDesktopMode (bool value)
5944
priv->inShowDesktopMode = value;
5948
CompWindow::managed ()
5950
WRAPABLE_HND_FUNCTN_RETURN (bool, managed);
5951
return priv->managed;
5955
CompWindow::focused ()
5957
WRAPABLE_HND_FUNCTN_RETURN (bool, focused);
5958
return screen->activeWindow () == id ();
5962
CompWindow::grabbed ()
5964
return priv->grabbed;
5968
CompWindow::pendingMaps ()
5970
return priv->pendingMaps;
5974
CompWindow::wmType ()
5976
return priv->wmType;
5980
CompWindow::activeNum ()
5982
return priv->activeNum;
5986
CompWindow::frame ()
5988
return priv->serverFrame;
5992
CompWindow::resName ()
5995
return priv->resName;
5997
return CompString ();
6001
CompWindow::mapNum () const
6003
return priv->mapNum;
6007
CompWindow::struts ()
6009
return priv->struts;
6013
CompWindow::saveMask ()
6015
return priv->saveMask;
6019
CompWindow::saveWc ()
6021
return priv->saveWc;
6025
CompWindow::moveToViewportPosition (int x,
6030
int vWidth = screen->width () * screen->vpSize ().width ();
6031
int vHeight = screen->height () * screen->vpSize ().height ();
6033
if (screen->vpSize ().width () != 1)
6035
x += screen->vp ().x () * screen->width ();
6036
x = compiz::core::screen::wraparound_mod (x, vWidth);
6037
x -= screen->vp ().x () * screen->width ();
6040
if (screen->vpSize ().height () != 1)
6042
y += screen->vp ().y () * screen->height ();
6043
y = compiz::core::screen::wraparound_mod (y, vHeight);
6044
y -= screen->vp ().y () * screen->height ();
6047
tx = x - priv->geometry.x ();
6048
ty = y - priv->geometry.y ();
6052
unsigned int valueMask = CWX | CWY;
6053
XWindowChanges xwc = XWINDOWCHANGES_INIT;
6059
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
6062
if (priv->state & CompWindowStateStickyMask)
6068
if (screen->vpSize ().width ()!= 1)
6070
m = priv->geometry.x () + tx;
6072
if (m - priv->output.left < (int) screen->width () - vWidth)
6074
else if (m + priv->width + priv->output.right > vWidth)
6078
if (screen->vpSize ().height () != 1)
6080
m = priv->geometry.y () + ty;
6082
if (m - priv->output.top < (int) screen->height () - vHeight)
6084
else if (m + priv->height + priv->output.bottom > vHeight)
6088
if (priv->saveMask & CWX)
6089
priv->saveWc.x += wx;
6091
if (priv->saveMask & CWY)
6092
priv->saveWc.y += wy;
6094
xwc.x = serverGeometry ().x () + wx;
6095
xwc.y = serverGeometry ().y () + wy;
6097
configureXWindow (valueMask, &xwc);
6102
CompWindow::startupId ()
6104
return priv->startupId;
6108
PrivateWindow::applyStartupProperties (CompStartupSequence *s)
6112
priv->initialViewport.setX (s->viewportX);
6113
priv->initialViewport.setY (s->viewportY);
6115
workspace = sn_startup_sequence_get_workspace (s->sequence);
6117
window->setDesktop (workspace);
6119
priv->initialTimestamp =
6120
sn_startup_sequence_get_timestamp (s->sequence);
6121
priv->initialTimestampSet = true;
6125
CompWindow::desktop ()
6127
return priv->desktop;
6131
CompWindow::clientLeader (bool checkAncestor)
6133
if (priv->clientLeader)
6134
return priv->clientLeader;
6137
return priv->getClientLeaderOfAncestor ();
6143
CompWindow::transientFor ()
6145
return priv->transientFor;
6149
CompWindow::pendingUnmaps ()
6151
return priv->pendingUnmaps;
6155
CompWindow::minimized ()
6157
WRAPABLE_HND_FUNCTN_RETURN (bool, minimized);
6158
return priv->minimized;
6162
CompWindow::placed ()
6164
return priv->placed;
6168
CompWindow::shaded ()
6170
return priv->shaded;
6174
CompWindow::border () const
6176
return priv->border;
6180
CompWindow::input () const
6182
return priv->serverInput;
6186
CompWindow::output () const
6188
return priv->output;
6192
CompWindow::sizeHints () const
6194
return priv->sizeHints;
6198
PrivateWindow::updateMwmHints ()
6200
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
6201
window->recalcActions ();
6205
PrivateWindow::updateStartupId ()
6207
char *oldId = startupId;
6210
startupId = getStartupId ();
6212
if (oldId && startupId)
6214
if (strcmp (startupId, oldId) == 0)
6218
if (managed && startupId && newId)
6225
initialTimestampSet = false;
6226
screen->priv->applyStartupProperties (window);
6228
if (initialTimestampSet)
6229
timestamp = initialTimestamp;
6231
/* as the viewport can't be transmitted via startup
6232
notification, assume the client changing the ID
6233
wanted to activate the window on the current viewport */
6235
vp = window->defaultViewport ();
6236
svp = screen->vp ();
6239
x = window->geometry ().x () + (svp.x () - vp.x ()) * size.width ();
6240
y = window->geometry ().y () + (svp.y () - vp.y ()) * size.height ();
6241
window->moveToViewportPosition (x, y, true);
6243
if (allowWindowFocus (0, timestamp))
6244
window->activate ();
6252
CompWindow::destroyed ()
6254
return priv->destroyed;
6258
CompWindow::invisible ()
6260
return priv->invisible;
6264
CompWindow::syncAlarm ()
6266
return priv->syncAlarm;
6270
CoreWindow::manage (Window aboveId, XWindowAttributes &wa)
6272
return new CompWindow (aboveId, wa, priv);
6275
CoreWindow::CoreWindow (Window id)
6277
priv = new PrivateWindow ();
6280
priv->serverId = id;
6283
CompWindow::CompWindow (Window aboveId,
6284
XWindowAttributes &wa,
6285
PrivateWindow *priv) :
6286
PluginClassStorage (windowPluginClassIndices),
6289
StackDebugger *dbg = StackDebugger::Default ();
6291
// TODO: Reparent first!
6293
priv->window = this;
6295
screen->insertWindow (this, aboveId);
6296
screen->insertServerWindow (this, aboveId);
6298
/* We must immediately insert the window into the debugging
6301
dbg->overrideRedirectRestack (priv->id, aboveId);
6304
priv->serverGeometry.set (priv->attrib.x, priv->attrib.y,
6305
priv->attrib.width, priv->attrib.height,
6306
priv->attrib.border_width);
6307
priv->serverFrameGeometry = priv->frameGeometry = priv->syncGeometry
6308
= priv->geometry = priv->serverGeometry;
6310
priv->width = priv->attrib.width + priv->attrib.border_width * 2;
6311
priv->height = priv->attrib.height + priv->attrib.border_width * 2;
6313
priv->sizeHints.flags = 0;
6315
priv->recalcNormalHints ();
6317
priv->transientFor = None;
6318
priv->clientLeader = None;
6320
XSelectInput (screen->dpy (), priv->id,
6321
wa.your_event_mask |
6322
PropertyChangeMask |
6326
priv->alpha = (priv->attrib.depth == 32);
6327
priv->lastPong = screen->priv->lastPing;
6329
if (screen->XShape ())
6330
XShapeSelectInput (screen->dpy (), priv->id, ShapeNotifyMask);
6332
if (priv->attrib.c_class != InputOnly)
6334
priv->region = CompRegion (priv->attrib.x, priv->attrib.y,
6335
priv->width, priv->height);
6336
priv->inputRegion = priv->region;
6338
/* need to check for DisplayModal state on all windows */
6339
priv->state = screen->priv->getWindowState (priv->id);
6341
priv->updateClassHints ();
6345
priv->attrib.map_state = IsUnmapped;
6348
priv->wmType = screen->priv->getWindowType (priv->id);
6349
priv->protocols = screen->priv->getProtocols (priv->id);
6351
if (!overrideRedirect ())
6353
priv->updateNormalHints ();
6355
priv->updateWmHints ();
6356
priv->updateTransientHint ();
6358
priv->clientLeader = priv->getClientLeader ();
6359
priv->startupId = priv->getStartupId ();
6363
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
6365
if (!(priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask)))
6367
priv->desktop = screen->getWindowProp (priv->id, Atoms::winDesktop,
6369
if (priv->desktop != 0xffffffff)
6371
if (priv->desktop >= screen->nDesktop ())
6372
priv->desktop = screen->currentDesktop ();
6381
if (priv->attrib.map_state == IsViewable)
6383
priv->placed = true;
6385
if (!overrideRedirect ())
6387
// needs to happen right after maprequest
6388
if (!priv->serverFrame)
6390
priv->managed = true;
6392
if (screen->priv->getWmState (priv->id) == IconicState)
6394
if (priv->state & CompWindowStateShadedMask)
6395
priv->shaded = true;
6397
priv->minimized = true;
6401
if (priv->wmType & (CompWindowTypeDockMask |
6402
CompWindowTypeDesktopMask))
6404
setDesktop (0xffffffff);
6408
if (priv->desktop != 0xffffffff)
6409
priv->desktop = screen->currentDesktop ();
6411
screen->setWindowProp (priv->id, Atoms::winDesktop,
6417
priv->attrib.map_state = IsUnmapped;
6418
priv->pendingMaps++;
6422
updateAttributes (CompStackingUpdateModeNormal);
6424
if (priv->minimized || priv->inShowDesktopMode ||
6425
priv->hidden || priv->shaded)
6427
priv->state |= CompWindowStateHiddenMask;
6429
priv->pendingUnmaps++;
6431
if (priv->serverFrame && !priv->shaded)
6432
XUnmapWindow (screen->dpy (), priv->serverFrame);
6434
XUnmapWindow (screen->dpy (), priv->id);
6436
screen->priv->setWindowState (priv->state, priv->id);
6439
else if (!overrideRedirect ())
6441
if (screen->priv->getWmState (priv->id) == IconicState)
6443
// before everything else in maprequest
6444
if (!priv->serverFrame)
6446
priv->managed = true;
6447
priv->placed = true;
6449
if (priv->state & CompWindowStateHiddenMask)
6451
if (priv->state & CompWindowStateShadedMask)
6452
priv->shaded = true;
6454
priv->minimized = true;
6459
/* TODO: bailout properly when objectInitPlugins fails */
6460
assert (CompPlugin::windowInitPlugins (this));
6463
priv->updateIconGeometry ();
6466
priv->updateFrameWindow ();
6468
if (priv->attrib.map_state == IsViewable)
6470
priv->invisible = WINDOW_INVISIBLE (priv);
6474
CompWindow::~CompWindow ()
6476
if (priv->serverFrame)
6477
priv->unreparent ();
6479
/* Update the references of other windows
6480
* pending destroy if this was a sibling
6481
* of one of those */
6483
screen->priv->destroyedWindows.remove (this);
6485
foreach (CompWindow *dw, screen->priv->destroyedWindows)
6487
if (dw->next == this)
6488
dw->next = this->next;
6489
if (dw->prev == this)
6490
dw->prev = this->prev;
6492
if (dw->serverNext == this)
6493
dw->serverNext = this->serverNext;
6494
if (dw->serverPrev == this)
6495
dw->serverPrev = this->serverPrev;
6498
/* If this window has a detached frame, destroy it, but only
6499
* using XDestroyWindow since there may be pending restack
6500
* requests relative to it */
6502
std::map <CompWindow *, CompWindow *>::iterator it =
6503
screen->priv->detachedFrameWindows.find (this);
6505
if (it != screen->priv->detachedFrameWindows.end ())
6507
CompWindow *fw = (it->second);
6509
XDestroyWindow (screen->dpy (), fw->id ());
6510
screen->priv->detachedFrameWindows.erase (it);
6513
if (!priv->destroyed)
6515
StackDebugger *dbg = StackDebugger::Default ();
6517
screen->unhookWindow (this);
6518
screen->unhookServerWindow (this);
6520
/* We must immediately insert the window into the debugging
6523
dbg->removeServerWindow (id ());
6525
/* restore saved geometry and map if hidden */
6526
if (!priv->attrib.override_redirect)
6529
XConfigureWindow (screen->dpy (), priv->id,
6530
priv->saveMask, &priv->saveWc);
6534
if (priv->state & CompWindowStateHiddenMask)
6535
XMapWindow (screen->dpy (), priv->id);
6539
if (screen->XShape ())
6540
XShapeSelectInput (screen->dpy (), priv->id, NoEventMask);
6542
if (priv->id != screen->priv->grabWindow)
6543
XSelectInput (screen->dpy (), priv->id, NoEventMask);
6545
XUngrabButton (screen->dpy (), AnyButton, AnyModifier, priv->id);
6549
if (priv->attrib.map_state == IsViewable)
6551
if (priv->type == CompWindowTypeDesktopMask)
6552
screen->priv->desktopWindowCount--;
6554
if (priv->destroyed && priv->struts)
6555
screen->updateWorkarea ();
6558
if (priv->destroyed)
6559
screen->priv->updateClientList ();
6561
CompPlugin::windowFiniPlugins (this);
6566
PrivateWindow::PrivateWindow () :
6575
transientFor (None),
6576
clientLeader (None),
6584
type (CompWindowTypeUnknownMask),
6588
mwmDecor (MwmDecorAll),
6589
mwmFunc (MwmFuncAll),
6597
initialViewport (0, 0),
6599
initialTimestamp (0),
6600
initialTimestampSet (false),
6602
fullscreenMonitorsSet (false),
6606
inShowDesktopMode (false),
6615
pendingConfigures (screen->dpy ()),
6616
pendingPositionUpdates (false),
6638
closeRequests (false),
6639
lastCloseRequestTime (0)
6646
serverInput.left = 0;
6647
serverInput.right = 0;
6648
serverInput.top = 0;
6649
serverInput.bottom = 0;
6661
syncWaitTimer.setTimes (1000, 1200);
6662
syncWaitTimer.setCallback (boost::bind (&PrivateWindow::handleSyncAlarm,
6666
PrivateWindow::~PrivateWindow ()
6669
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
6671
syncWaitTimer.stop ();
6674
XDestroyWindow (screen->dpy (), serverFrame);
6676
XDestroyWindow (screen->dpy (), frame);
6698
CompWindow::syncWait ()
6700
return priv->syncWait;
6704
CompWindow::alpha ()
6706
WRAPABLE_HND_FUNCTN_RETURN (bool, alpha);
6712
CompWindow::overrideRedirect ()
6714
return priv->attrib.override_redirect;
6718
PrivateWindow::setOverrideRedirect (bool overrideRedirect)
6720
if (overrideRedirect == window->overrideRedirect ())
6723
priv->attrib.override_redirect = overrideRedirect ? 1 : 0;
6724
window->recalcType ();
6725
window->recalcActions ();
6727
screen->matchPropertyChanged (window);
6731
CompWindow::isMapped () const
6733
return priv->mapNum > 0;
6737
CompWindow::isViewable () const
6739
return (priv->attrib.map_state == IsViewable);
6743
CompWindow::isFocussable ()
6745
WRAPABLE_HND_FUNCTN_RETURN (bool, isFocussable);
6747
if (priv->inputHint)
6750
if (priv->protocols & CompWindowProtocolTakeFocusMask)
6757
CompWindow::windowClass ()
6759
return priv->attrib.c_class;
6763
CompWindow::depth ()
6765
return priv->attrib.depth;
6769
CompWindow::alive ()
6775
CompWindow::mwmDecor ()
6777
return priv->mwmDecor;
6781
CompWindow::mwmFunc ()
6783
return priv->mwmFunc;
6786
/* TODO: This function should be able to check the XShape event
6787
* kind and only get/set shape rectangles for either ShapeInput
6788
* or ShapeBounding, but not both at the same time
6792
CompWindow::updateFrameRegion ()
6794
if (priv->serverFrame &&
6795
priv->serverGeometry.width () == priv->geometry.width () &&
6796
priv->serverGeometry.height () == priv->geometry.height ())
6801
priv->frameRegion = CompRegion ();
6803
updateFrameRegion (priv->frameRegion);
6807
r = priv->region.boundingRect ();
6808
priv->frameRegion -= r;
6810
r.setGeometry (r.x1 () - priv->input.left,
6811
r.y1 () - priv->input.top,
6812
r.width () + priv->input.right + priv->input.left,
6813
r.height () + priv->input.bottom + priv->input.top);
6815
priv->frameRegion &= CompRegion (r);
6818
x = priv->geometry.x () - priv->input.left;
6819
y = priv->geometry.y () - priv->input.top;
6821
XShapeCombineRegion (screen->dpy (), priv->serverFrame,
6822
ShapeBounding, -x, -y,
6823
priv->frameRegion.united (priv->region).handle (),
6826
XShapeCombineRegion (screen->dpy (), priv->serverFrame,
6828
priv->frameRegion.united (priv->inputRegion).handle (),
6834
CompWindow::setWindowFrameExtents (CompWindowExtents *b,
6835
CompWindowExtents *i)
6837
/* Input extents are used for frame size,
6838
* Border extents used for placement.
6844
if (priv->serverInput.left != i->left ||
6845
priv->serverInput.right != i->right ||
6846
priv->serverInput.top != i->top ||
6847
priv->serverInput.bottom != i->bottom ||
6848
priv->border.left != b->left ||
6849
priv->border.right != b->right ||
6850
priv->border.top != b->top ||
6851
priv->border.bottom != b->bottom)
6853
priv->serverInput = *i;
6858
priv->updateSize ();
6859
priv->updateFrameWindow ();
6862
/* Use b for _NET_WM_FRAME_EXTENTS here because
6863
* that is the representation of the actual decoration
6864
* around the window that the user sees and should
6865
* be used for placement and such */
6867
/* Also update frame extents regardless of whether or not
6868
* the frame extents actually changed, eg, a plugin could
6869
* suggest that a window has no frame extents and that it
6870
* might later get frame extents - this is mandatory if we
6871
* say that we support it, so set them
6872
* additionaly some applications might request frame extents
6873
* and we must respond by setting the property - ideally
6874
* this should only ever be done when some plugin actually
6875
* need to change the frame extents or the applications
6878
unsigned long data[4];
6883
data[3] = b->bottom;
6885
XChangeProperty (screen->dpy (), priv->id,
6886
Atoms::frameExtents,
6887
XA_CARDINAL, 32, PropModeReplace,
6888
(unsigned char *) data, 4);
6892
CompWindow::hasUnmapReference ()
6894
return (priv && priv->unmapRefCnt > 1);
6898
CompWindow::updateFrameRegion (CompRegion& region)
6899
WRAPABLE_HND_FUNCTN (updateFrameRegion, region)
6902
PrivateWindow::reparent ()
6904
XSetWindowAttributes attr;
6905
XWindowAttributes wa;
6906
XWindowChanges xwc = XWINDOWCHANGES_INIT;
6908
unsigned int nchildren;
6909
Window *children, root_return, parent_return;
6910
Display *dpy = screen->dpy ();
6911
Visual *visual = DefaultVisual (screen->dpy (),
6912
screen->screenNum ());
6913
Colormap cmap = DefaultColormap (screen->dpy (),
6914
screen->screenNum ());
6922
if (!XGetWindowAttributes (dpy, id, &wa))
6924
XUngrabServer (dpy);
6929
if (wa.override_redirect)
6932
/* Don't ever reparent windows which have ended up
6933
* reparented themselves on the server side but not
6934
* on the client side */
6936
XQueryTree (dpy, id, &root_return, &parent_return, &children, &nchildren);
6938
if (parent_return != root_return)
6941
XUngrabServer (dpy);
6948
XQueryTree (dpy, root_return, &root_return, &parent_return, &children, &nchildren);
6950
XChangeSaveSet (dpy, id, SetModeInsert);
6952
/* Force border width to 0 */
6953
xwc.border_width = 0;
6954
XConfigureWindow (dpy, id, CWBorderWidth, &xwc);
6956
priv->serverGeometry.setBorder (0);
6958
mask = CWBorderPixel | CWColormap | CWBackPixmap | CWOverrideRedirect;
6966
attr.background_pixmap = None;
6967
attr.border_pixel = 0;
6968
attr.colormap = cmap;
6969
attr.override_redirect = true;
6971
/* Look for existing detached frame windows and reattach them
6972
* in case this window as reparented again after being withdrawn */
6973
std::map <CompWindow *, CompWindow *>::iterator it =
6974
screen->priv->detachedFrameWindows.find (window);
6976
if (it != screen->priv->detachedFrameWindows.end ())
6978
/* Trash the old frame window
6979
* TODO: It would be nicer if we could just
6980
* reparent back into it, but there are some
6981
* problems with that */
6983
XDestroyWindow (dpy, (it->second)->id ());
6984
screen->priv->detachedFrameWindows.erase (it);
6987
/* We need to know when the frame window is created
6989
XSelectInput (dpy, screen->root (), SubstructureNotifyMask);
6991
/* Awaiting a new frame to be given to us */
6993
serverFrame = XCreateWindow (dpy, screen->root (), 0, 0,
6994
wa.width, wa.height, 0, wa.depth,
6995
InputOutput, visual, mask, &attr);
6997
/* Do not get any events from here on */
6998
XSelectInput (dpy, screen->root (), NoEventMask);
7000
wrapper = XCreateWindow (dpy, serverFrame, 0, 0,
7001
wa.width, wa.height, 0, wa.depth,
7002
InputOutput, visual, mask, &attr);
7004
xwc.stack_mode = Above;
7006
/* Look for the client in the current server side stacking
7007
* order and put the frame above what the client is above
7012
/* client at the bottom */
7013
xwc.stack_mode = Below;
7018
for (unsigned int i = 0; i < nchildren; i++)
7020
if (i < nchildren - 1)
7022
if (children[i + 1] == id)
7024
xwc.sibling = children[i];
7028
else /* client on top */
7029
xwc.sibling = children[i];
7035
/* Make sure the frame is underneath the client */
7036
XConfigureWindow (dpy, serverFrame, CWSibling | CWStackMode, &xwc);
7038
/* Wait for the restacking to finish */
7041
/* Always need to have the wrapper window mapped */
7042
XMapWindow (dpy, wrapper);
7044
/* Reparent the client into the wrapper window */
7045
XReparentWindow (dpy, id, wrapper, 0, 0);
7047
/* Restore events */
7048
attr.event_mask = wa.your_event_mask;
7050
/* We don't care about client events on the frame, and listening for them
7051
* will probably end up fighting the client anyways, so disable them */
7053
attr.do_not_propagate_mask = KeyPressMask | KeyReleaseMask |
7054
ButtonPressMask | ButtonReleaseMask |
7055
EnterWindowMask | LeaveWindowMask |
7056
PointerMotionMask | PointerMotionHintMask |
7057
Button1MotionMask | Button2MotionMask |
7058
Button3MotionMask | Button4MotionMask |
7059
Button5MotionMask | ButtonMotionMask |
7060
KeymapStateMask | ExposureMask |
7061
VisibilityChangeMask | StructureNotifyMask |
7062
ResizeRedirectMask | SubstructureNotifyMask |
7063
SubstructureRedirectMask | FocusChangeMask |
7064
PropertyChangeMask | ColormapChangeMask |
7065
OwnerGrabButtonMask;
7067
XChangeWindowAttributes (dpy, id, CWEventMask | CWDontPropagate, &attr);
7069
if (wa.map_state == IsViewable || shaded)
7070
XMapWindow (dpy, serverFrame);
7072
attr.event_mask = SubstructureRedirectMask |
7073
SubstructureNotifyMask | EnterWindowMask |
7076
serverFrameGeometry = serverGeometry;
7078
XMoveResizeWindow (dpy, serverFrame, serverFrameGeometry.x (), serverFrameGeometry.y (),
7079
serverFrameGeometry.width (), serverFrameGeometry.height ());
7081
XChangeWindowAttributes (dpy, serverFrame, CWEventMask, &attr);
7082
XChangeWindowAttributes (dpy, wrapper, CWEventMask, &attr);
7084
XSelectInput (dpy, screen->root (),
7085
SubstructureRedirectMask |
7086
SubstructureNotifyMask |
7087
StructureNotifyMask |
7088
PropertyChangeMask |
7098
XUngrabServer (dpy);
7101
window->windowNotify (CompWindowNotifyReparent);
7107
PrivateWindow::unreparent ()
7109
Display *dpy = screen->dpy ();
7112
XWindowChanges xwc = XWINDOWCHANGES_INIT;
7113
unsigned int nchildren;
7114
Window *children = NULL, root_return, parent_return;
7115
XWindowAttributes wa;
7116
StackDebugger *dbg = StackDebugger::Default ();
7123
if (XCheckTypedWindowEvent (dpy, id, DestroyNotify, &e))
7125
XPutBackEvent (dpy, &e);
7130
if (!XGetWindowAttributes (dpy, id, &wa))
7134
/* Also don't reparent back into root windows that have ended up
7135
* reparented into other windows (and as such we are unmanaging them) */
7139
XQueryTree (dpy, id, &root_return, &parent_return, &children, &nchildren);
7141
if (parent_return != wrapper)
7145
if ((!destroyed) && alive)
7149
XChangeSaveSet (dpy, id, SetModeDelete);
7150
XSelectInput (dpy, serverFrame, NoEventMask);
7151
XSelectInput (dpy, wrapper, NoEventMask);
7152
XSelectInput (dpy, id, NoEventMask);
7153
XSelectInput (dpy, screen->root (), NoEventMask);
7154
XReparentWindow (dpy, id, screen->root (), 0, 0);
7156
/* Wait for the reparent to finish */
7159
xwc.x = serverGeometry.x () - serverGeometry.border ();
7160
xwc.y = serverGeometry.y () - serverGeometry.border ();
7161
xwc.width = serverGeometry.width () + serverGeometry.border () * 2;
7162
xwc.height = serverGeometry.height () + serverGeometry.border () * 2;
7164
XConfigureWindow (dpy, serverFrame, CWX | CWY | CWWidth | CWHeight, &xwc);
7167
xwc.stack_mode = Below;
7168
xwc.sibling = serverFrame;
7169
XConfigureWindow (dpy, id, CWSibling | CWStackMode, &xwc);
7171
/* Wait for the window to be restacked */
7174
XUnmapWindow (dpy, serverFrame);
7176
XSelectInput (dpy, id, wa.your_event_mask);
7178
XSelectInput (dpy, screen->root (),
7179
SubstructureRedirectMask |
7180
SubstructureNotifyMask |
7181
StructureNotifyMask |
7182
PropertyChangeMask |
7192
XUngrabServer (dpy);
7195
XMoveWindow (dpy, id, serverGeometry.x (), serverGeometry.y ());
7202
dbg->addDestroyedFrame (serverFrame);
7204
/* This is where things get tricky ... it is possible
7205
* to receive a ConfigureNotify relative to a frame window
7206
* for a destroyed window in case we process a ConfigureRequest
7207
* for the destroyed window and then a DestroyNotify for it directly
7208
* afterwards. In that case, we will receive the ConfigureNotify
7209
* for the XConfigureWindow request we made relative to that frame
7210
* window. Because of this, we must keep the frame window in the stack
7211
* as a new toplevel window so that the ConfigureNotify will be processed
7212
* properly until it too receives a DestroyNotify */
7216
XWindowAttributes attrib;
7218
/* It's possible that the frame window was already destroyed because
7219
* the client was unreparented before it was destroyed (eg
7220
* UnmapNotify before DestroyNotify). In that case the frame window
7221
* is going to be an invalid window but since we haven't received
7222
* a DestroyNotify for it yet, it is possible that restacking
7223
* operations could occurr relative to it so we need to hold it
7224
* in the stack for now. Ensure that it is marked override redirect */
7225
XGetWindowAttributes (screen->dpy (), serverFrame, &attrib);
7227
/* Put the frame window "above" the client window
7229
CoreWindow *cw = new CoreWindow (serverFrame);
7230
CompWindow *fw = cw->manage (id, attrib);
7231
screen->removeFromCreatedWindows (cw);
7234
/* Put this window in the list of "detached frame windows"
7235
* so that we can reattach it or destroy it when we are
7238
screen->priv->detachedFrameWindows[window] = fw;
7241
/* Safe to destroy the wrapper but not the frame */
7242
XUnmapWindow (screen->dpy (), serverFrame);
7243
XDestroyWindow (screen->dpy (), wrapper);
7245
window->windowNotify (CompWindowNotifyUnreparent);
7246
/* This window is no longer "managed" in the
7247
* reparenting sense so clear its pending event
7248
* queue ... though maybe in future it would
7249
* be better to bookeep these events too and
7250
* handle the ReparentNotify */
7251
pendingConfigures.clear ();