2
* Copyright © 2005 Novell, Inc.
4
* Permission to use, copy, modify, distribute, and sell this software
5
* and its documentation for any purpose is hereby granted without
6
* fee, provided that the above copyright notice appear in all copies
7
* and that both that copyright notice and this permission notice
8
* appear in supporting documentation, and that the name of
9
* Novell, Inc. not be used in advertising or publicity pertaining to
10
* distribution of the software without specific, written prior permission.
11
* Novell, Inc. makes no representations about the suitability of this
12
* software for any purpose. It is provided "as is" without express or
15
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23
* Author: David Reveman <davidr@novell.com>
29
#include <X11/Xatom.h>
30
#include <X11/Xproto.h>
31
#include <X11/extensions/shape.h>
41
#include <boost/bind.hpp>
43
#include <core/core.h>
44
#include <core/icon.h>
45
#include <core/atoms.h>
46
#include "privatewindow.h"
47
#include "privatescreen.h"
48
#include "privatestackdebugger.h"
50
PluginClassStorage::Indices windowPluginClassIndices (0);
53
CompWindow::allocPluginClassIndex ()
55
unsigned int i = PluginClassStorage::allocatePluginClassIndex (windowPluginClassIndices);
57
foreach (CompWindow *w, screen->windows ())
58
if (windowPluginClassIndices.size () != w->pluginClasses.size ())
59
w->pluginClasses.resize (windowPluginClassIndices.size ());
65
CompWindow::freePluginClassIndex (unsigned int index)
67
PluginClassStorage::freePluginClassIndex (windowPluginClassIndices, index);
69
foreach (CompWindow *w, ::screen->windows ())
70
if (windowPluginClassIndices.size () != w->pluginClasses.size ())
71
w->pluginClasses.resize (windowPluginClassIndices.size ());
75
PrivateWindow::isAncestorTo (CompWindow *transient,
78
if (transient->priv->transientFor)
80
if (transient->priv->transientFor == ancestor->priv->id)
83
transient = screen->findWindow (transient->priv->transientFor);
85
return isAncestorTo (transient, ancestor);
92
PrivateWindow::recalcNormalHints ()
96
#warning fixme to max Texture size
98
maxSize -= serverGeometry.border () * 2;
100
sizeHints.x = serverGeometry.x ();
101
sizeHints.y = serverGeometry.y ();
102
sizeHints.width = serverGeometry.width ();
103
sizeHints.height = serverGeometry.height ();
105
if (!(sizeHints.flags & PBaseSize))
107
if (sizeHints.flags & PMinSize)
109
sizeHints.base_width = sizeHints.min_width;
110
sizeHints.base_height = sizeHints.min_height;
114
sizeHints.base_width = 0;
115
sizeHints.base_height = 0;
118
sizeHints.flags |= PBaseSize;
121
if (!(sizeHints.flags & PMinSize))
123
sizeHints.min_width = sizeHints.base_width;
124
sizeHints.min_height = sizeHints.base_height;
125
sizeHints.flags |= PMinSize;
128
if (!(sizeHints.flags & PMaxSize))
130
sizeHints.max_width = 65535;
131
sizeHints.max_height = 65535;
132
sizeHints.flags |= PMaxSize;
135
if (sizeHints.max_width < sizeHints.min_width)
136
sizeHints.max_width = sizeHints.min_width;
138
if (sizeHints.max_height < sizeHints.min_height)
139
sizeHints.max_height = sizeHints.min_height;
141
if (sizeHints.min_width < 1)
142
sizeHints.min_width = 1;
144
if (sizeHints.max_width < 1)
145
sizeHints.max_width = 1;
147
if (sizeHints.min_height < 1)
148
sizeHints.min_height = 1;
150
if (sizeHints.max_height < 1)
151
sizeHints.max_height = 1;
153
if (sizeHints.max_width > maxSize)
154
sizeHints.max_width = maxSize;
156
if (sizeHints.max_height > maxSize)
157
sizeHints.max_height = maxSize;
159
if (sizeHints.min_width > maxSize)
160
sizeHints.min_width = maxSize;
162
if (sizeHints.min_height > maxSize)
163
sizeHints.min_height = maxSize;
165
if (sizeHints.base_width > maxSize)
166
sizeHints.base_width = maxSize;
168
if (sizeHints.base_height > maxSize)
169
sizeHints.base_height = maxSize;
171
if (sizeHints.flags & PResizeInc)
173
if (sizeHints.width_inc == 0)
174
sizeHints.width_inc = 1;
176
if (sizeHints.height_inc == 0)
177
sizeHints.height_inc = 1;
181
sizeHints.width_inc = 1;
182
sizeHints.height_inc = 1;
183
sizeHints.flags |= PResizeInc;
186
if (sizeHints.flags & PAspect)
188
/* don't divide by 0 */
189
if (sizeHints.min_aspect.y < 1)
190
sizeHints.min_aspect.y = 1;
192
if (sizeHints.max_aspect.y < 1)
193
sizeHints.max_aspect.y = 1;
197
sizeHints.min_aspect.x = 1;
198
sizeHints.min_aspect.y = 65535;
199
sizeHints.max_aspect.x = 65535;
200
sizeHints.max_aspect.y = 1;
201
sizeHints.flags |= PAspect;
204
if (!(sizeHints.flags & PWinGravity))
206
sizeHints.win_gravity = NorthWestGravity;
207
sizeHints.flags |= PWinGravity;
212
PrivateWindow::updateNormalHints ()
217
status = XGetWMNormalHints (screen->dpy (), priv->id,
218
&priv->sizeHints, &supplied);
221
priv->sizeHints.flags = 0;
223
priv->recalcNormalHints ();
227
PrivateWindow::updateWmHints ()
231
bool iconChanged = false;
234
dFlags = hints->flags;
238
newHints = XGetWMHints (screen->dpy (), id);
241
dFlags ^= newHints->flags;
243
if (newHints->flags & InputHint)
244
inputHint = newHints->input;
248
if ((newHints->flags & IconPixmapHint) &&
249
(hints->icon_pixmap != newHints->icon_pixmap))
253
else if ((newHints->flags & IconMaskHint) &&
254
(hints->icon_mask != newHints->icon_mask))
261
iconChanged |= (dFlags & (IconPixmapHint | IconMaskHint));
273
PrivateWindow::updateClassHints ()
275
XClassHint classHint;
280
free (priv->resName);
281
priv->resName = NULL;
286
free (priv->resClass);
287
priv->resClass = NULL;
290
status = XGetClassHint (screen->dpy (),
291
priv->id, &classHint);
294
if (classHint.res_name)
296
priv->resName = strdup (classHint.res_name);
297
XFree (classHint.res_name);
300
if (classHint.res_class)
302
priv->resClass = strdup (classHint.res_class);
303
XFree (classHint.res_class);
309
PrivateWindow::updateTransientHint ()
314
priv->transientFor = None;
316
status = XGetTransientForHint (screen->dpy (),
317
priv->id, &transientFor);
321
CompWindow *ancestor;
323
ancestor = screen->findWindow (transientFor);
327
/* protect against circular transient dependencies */
328
if (transientFor == priv->id ||
329
PrivateWindow::isAncestorTo (ancestor, window))
332
priv->transientFor = transientFor;
337
PrivateWindow::updateIconGeometry ()
341
unsigned long n, left;
344
priv->iconGeometry.setGeometry (0, 0, 0, 0);
346
result = XGetWindowProperty (screen->dpy (), priv->id,
347
Atoms::wmIconGeometry,
348
0L, 1024L, False, XA_CARDINAL,
349
&actual, &format, &n, &left, &data);
351
if (result == Success && data)
355
unsigned long *geometry = (unsigned long *) data;
357
priv->iconGeometry.setX (geometry[0]);
358
priv->iconGeometry.setY (geometry[1]);
359
priv->iconGeometry.setWidth (geometry[2]);
360
priv->iconGeometry.setHeight (geometry[3]);
368
PrivateWindow::getClientLeaderOfAncestor ()
372
CompWindow *w = screen->findWindow (transientFor);
375
if (w->priv->clientLeader)
376
return w->priv->clientLeader;
378
return w->priv->getClientLeaderOfAncestor ();
386
PrivateWindow::getClientLeader ()
390
unsigned long n, left;
393
result = XGetWindowProperty (screen->dpy (), priv->id,
394
Atoms::wmClientLeader,
395
0L, 1L, False, XA_WINDOW, &actual, &format,
398
if (result == Success && data)
403
memcpy (&win, data, sizeof (Window));
405
XFree ((void *) data);
411
return priv->getClientLeaderOfAncestor ();
415
PrivateWindow::getStartupId ()
419
unsigned long n, left;
422
result = XGetWindowProperty (screen->dpy (), priv->id,
429
if (result == Success && data)
434
id = strdup ((char *) data);
435
XFree ((void *) data);
444
PrivateWindow::setFullscreenMonitors (CompFullscreenMonitorSet *monitors)
446
bool hadFsMonitors = fullscreenMonitorsSet;
447
unsigned int outputs = screen->outputDevs ().size ();
449
fullscreenMonitorsSet = false;
452
(unsigned int) monitors->left < outputs &&
453
(unsigned int) monitors->right < outputs &&
454
(unsigned int) monitors->top < outputs &&
455
(unsigned int) monitors->bottom < outputs)
457
CompRect fsRect (screen->outputDevs ()[monitors->left].x1 (),
458
screen->outputDevs ()[monitors->top].y1 (),
459
screen->outputDevs ()[monitors->right].x2 (),
460
screen->outputDevs ()[monitors->bottom].y2 ());
462
if (fsRect.x1 () < fsRect.x2 () && fsRect.y1 () < fsRect.y2 ())
464
fullscreenMonitorsSet = true;
465
fullscreenMonitorRect = fsRect;
469
if (fullscreenMonitorsSet)
473
data[0] = monitors->top;
474
data[1] = monitors->bottom;
475
data[2] = monitors->left;
476
data[3] = monitors->right;
478
XChangeProperty (screen->dpy (), id, Atoms::wmFullscreenMonitors,
479
XA_CARDINAL, 32, PropModeReplace,
480
(unsigned char *) data, 4);
482
else if (hadFsMonitors)
484
XDeleteProperty (screen->dpy (), id, Atoms::wmFullscreenMonitors);
487
if (state & CompWindowStateFullscreenMask)
488
if (fullscreenMonitorsSet || hadFsMonitors)
489
window->updateAttributes (CompStackingUpdateModeNone);
493
CompWindow::changeState (unsigned int newState)
495
unsigned int oldState;
497
if (priv->state == newState)
500
oldState = priv->state;
501
priv->state = newState;
507
screen->priv->setWindowState (priv->state, priv->id);
509
stateChangeNotify (oldState);
510
screen->matchPropertyChanged (this);
514
setWindowActions (CompScreen *s,
515
unsigned int actions,
521
if (actions & CompWindowActionMoveMask)
522
data[i++] = Atoms::winActionMove;
523
if (actions & CompWindowActionResizeMask)
524
data[i++] = Atoms::winActionResize;
525
if (actions & CompWindowActionStickMask)
526
data[i++] = Atoms::winActionStick;
527
if (actions & CompWindowActionMinimizeMask)
528
data[i++] = Atoms::winActionMinimize;
529
if (actions & CompWindowActionMaximizeHorzMask)
530
data[i++] = Atoms::winActionMaximizeHorz;
531
if (actions & CompWindowActionMaximizeVertMask)
532
data[i++] = Atoms::winActionMaximizeVert;
533
if (actions & CompWindowActionFullscreenMask)
534
data[i++] = Atoms::winActionFullscreen;
535
if (actions & CompWindowActionCloseMask)
536
data[i++] = Atoms::winActionClose;
537
if (actions & CompWindowActionShadeMask)
538
data[i++] = Atoms::winActionShade;
539
if (actions & CompWindowActionChangeDesktopMask)
540
data[i++] = Atoms::winActionChangeDesktop;
541
if (actions & CompWindowActionAboveMask)
542
data[i++] = Atoms::winActionAbove;
543
if (actions & CompWindowActionBelowMask)
544
data[i++] = Atoms::winActionBelow;
546
XChangeProperty (s->dpy (), id, Atoms::wmAllowedActions,
547
XA_ATOM, 32, PropModeReplace,
548
(unsigned char *) data, i);
552
CompWindow::recalcActions ()
554
unsigned int actions = 0;
555
unsigned int setActions, clearActions;
557
switch (priv->type) {
558
case CompWindowTypeFullscreenMask:
559
case CompWindowTypeNormalMask:
561
CompWindowActionMaximizeHorzMask |
562
CompWindowActionMaximizeVertMask |
563
CompWindowActionFullscreenMask |
564
CompWindowActionMoveMask |
565
CompWindowActionResizeMask |
566
CompWindowActionStickMask |
567
CompWindowActionMinimizeMask |
568
CompWindowActionCloseMask |
569
CompWindowActionChangeDesktopMask;
571
case CompWindowTypeUtilMask:
572
case CompWindowTypeMenuMask:
573
case CompWindowTypeToolbarMask:
575
CompWindowActionMoveMask |
576
CompWindowActionResizeMask |
577
CompWindowActionStickMask |
578
CompWindowActionCloseMask |
579
CompWindowActionChangeDesktopMask;
581
case CompWindowTypeDialogMask:
582
case CompWindowTypeModalDialogMask:
584
CompWindowActionMaximizeHorzMask |
585
CompWindowActionMaximizeVertMask |
586
CompWindowActionMoveMask |
587
CompWindowActionResizeMask |
588
CompWindowActionStickMask |
589
CompWindowActionCloseMask |
590
CompWindowActionChangeDesktopMask;
592
/* allow minimization for dialog windows if they
593
a) are not a transient (transients can be minimized
595
b) don't have the skip taskbar hint set (as those
596
have no target to be minimized to)
598
if (!priv->transientFor &&
599
!(priv->state & CompWindowStateSkipTaskbarMask))
601
actions |= CompWindowActionMinimizeMask;
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
if (!(priv->mwmFunc & MwmFuncAll))
629
if (!(priv->mwmFunc & MwmFuncResize))
630
actions &= ~(CompWindowActionResizeMask |
631
CompWindowActionMaximizeHorzMask |
632
CompWindowActionMaximizeVertMask |
633
CompWindowActionFullscreenMask);
635
if (!(priv->mwmFunc & MwmFuncMove))
636
actions &= ~(CompWindowActionMoveMask |
637
CompWindowActionMaximizeHorzMask |
638
CompWindowActionMaximizeVertMask |
639
CompWindowActionFullscreenMask);
641
if (!(priv->mwmFunc & MwmFuncIconify))
642
actions &= ~CompWindowActionMinimizeMask;
644
if (!(priv->mwmFunc & MwmFuncClose))
645
actions &= ~CompWindowActionCloseMask;
648
getAllowedActions (setActions, clearActions);
649
actions &= ~clearActions;
650
actions |= setActions;
652
if (actions != priv->actions)
654
priv->actions = actions;
655
setWindowActions (screen, actions, priv->id);
660
CompWindow::getAllowedActions (unsigned int &setActions,
661
unsigned int &clearActions)
663
WRAPABLE_HND_FUNC (1, getAllowedActions, setActions, clearActions)
670
CompWindow::constrainWindowState (unsigned int state,
671
unsigned int actions)
673
if (!(actions & CompWindowActionMaximizeHorzMask))
674
state &= ~CompWindowStateMaximizedHorzMask;
676
if (!(actions & CompWindowActionMaximizeVertMask))
677
state &= ~CompWindowStateMaximizedVertMask;
679
if (!(actions & CompWindowActionShadeMask))
680
state &= ~CompWindowStateShadedMask;
682
if (!(actions & CompWindowActionFullscreenMask))
683
state &= ~CompWindowStateFullscreenMask;
689
PrivateWindow::windowTypeFromString (const char *str)
691
if (strcasecmp (str, "desktop") == 0)
692
return CompWindowTypeDesktopMask;
693
else if (strcasecmp (str, "dock") == 0)
694
return CompWindowTypeDockMask;
695
else if (strcasecmp (str, "toolbar") == 0)
696
return CompWindowTypeToolbarMask;
697
else if (strcasecmp (str, "menu") == 0)
698
return CompWindowTypeMenuMask;
699
else if (strcasecmp (str, "utility") == 0)
700
return CompWindowTypeUtilMask;
701
else if (strcasecmp (str, "splash") == 0)
702
return CompWindowTypeSplashMask;
703
else if (strcasecmp (str, "dialog") == 0)
704
return CompWindowTypeDialogMask;
705
else if (strcasecmp (str, "normal") == 0)
706
return CompWindowTypeNormalMask;
707
else if (strcasecmp (str, "dropdownmenu") == 0)
708
return CompWindowTypeDropdownMenuMask;
709
else if (strcasecmp (str, "popupmenu") == 0)
710
return CompWindowTypePopupMenuMask;
711
else if (strcasecmp (str, "tooltip") == 0)
712
return CompWindowTypeTooltipMask;
713
else if (strcasecmp (str, "notification") == 0)
714
return CompWindowTypeNotificationMask;
715
else if (strcasecmp (str, "combo") == 0)
716
return CompWindowTypeComboMask;
717
else if (strcasecmp (str, "dnd") == 0)
718
return CompWindowTypeDndMask;
719
else if (strcasecmp (str, "modaldialog") == 0)
720
return CompWindowTypeModalDialogMask;
721
else if (strcasecmp (str, "fullscreen") == 0)
722
return CompWindowTypeFullscreenMask;
723
else if (strcasecmp (str, "unknown") == 0)
724
return CompWindowTypeUnknownMask;
725
else if (strcasecmp (str, "any") == 0)
732
CompWindow::recalcType ()
738
if (!overrideRedirect () && priv->wmType == CompWindowTypeUnknownMask)
739
type = CompWindowTypeNormalMask;
741
if (priv->state & CompWindowStateFullscreenMask)
742
type = CompWindowTypeFullscreenMask;
744
if (type == CompWindowTypeNormalMask)
746
if (priv->transientFor)
747
type = CompWindowTypeDialogMask;
750
if (type == CompWindowTypeDockMask &&
751
(priv->state & CompWindowStateBelowMask))
753
type = CompWindowTypeNormalMask;
756
if ((type & (CompWindowTypeNormalMask | CompWindowTypeDialogMask)) &&
757
(priv->state & CompWindowStateModalMask))
759
type = CompWindowTypeModalDialogMask;
767
PrivateWindow::updateFrameWindow ()
770
unsigned int valueMask = CWX | CWY | CWWidth | CWHeight;
775
/* Flush any changes made to serverFrameGeometry or serverGeometry to the server
776
* since there is a race condition where geometries will go out-of-sync with
779
window->syncPosition ();
780
if (serverInput.left || serverInput.right || serverInput.top || serverInput.bottom)
782
int bw = serverGeometry.border () * 2;
784
xwc.x = serverGeometry.x () - serverInput.left;
785
xwc.y = serverGeometry.y () - serverInput.top;
786
xwc.width = serverGeometry.width () + serverInput.left + serverInput.right + bw;
788
xwc.height = serverInput.top + serverInput.bottom + bw;
790
xwc.height = serverGeometry.height () + serverInput.top + serverInput.bottom + bw;
793
height = serverInput.top + serverInput.bottom;
795
if (serverFrameGeometry.x () == xwc.x)
798
serverFrameGeometry.setX (xwc.x);
800
if (serverFrameGeometry.y () == xwc.y)
803
serverFrameGeometry.setY (xwc.y);
805
if (serverFrameGeometry.width () == xwc.width)
806
valueMask &= ~(CWWidth);
808
serverFrameGeometry.setWidth (xwc.width);
810
if (serverFrameGeometry.height () == xwc.height)
811
valueMask &= ~(CWHeight);
813
serverFrameGeometry.setHeight (xwc.height);
815
/* Geometry is the same, so we're not going to get a ConfigureNotify
816
* event when the window is configured, which means that other plugins
817
* won't know that the client, frame and wrapper windows got shifted
818
* around (and might result in display corruption, eg in OpenGL */
822
XWindowAttributes attrib;
823
unsigned int nchildren = 0;
824
Window rootRet = 0, parentRet = 0;
825
Window *children = NULL;
827
xev.type = ConfigureNotify;
828
xev.event = screen->root ();
829
xev.window = priv->serverFrame;
831
XGrabServer (screen->dpy ());
833
if (XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib))
837
xev.width = attrib.width;
838
xev.height = attrib.height;
839
xev.border_width = attrib.border_width;
842
/* We need to ensure that the stacking order is
843
* based on the current server stacking order so
844
* find the sibling to this window's frame in the
845
* server side stack and stack above that */
846
XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
850
for (unsigned int i = 0; i < nchildren; i++)
852
if (i + 1 == nchildren ||
853
children[i + 1] == ROOTPARENT (window))
855
xev.above = children[i];
865
xev.above = (window->serverPrev) ? ROOTPARENT (window->serverPrev) : None;
867
xev.override_redirect = priv->attrib.override_redirect;
871
gettimeofday (&lastConfigureRequest, NULL);
872
compiz::X11::PendingEvent::Ptr pc =
873
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
874
new compiz::X11::PendingConfigureEvent (
875
screen->dpy (), serverFrame, valueMask, &xwc)));
877
pendingConfigures.add (pc);
879
XSendEvent (screen->dpy (), screen->root (), false,
880
SubstructureNotifyMask, (XEvent *) &xev);
882
XUngrabServer (screen->dpy ());
883
XSync (screen->dpy (), false);
887
gettimeofday (&lastConfigureRequest, NULL);
888
compiz::X11::PendingEvent::Ptr pc =
889
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
890
new compiz::X11::PendingConfigureEvent (
891
screen->dpy (), serverFrame, valueMask, &xwc)));
893
pendingConfigures.add (pc);
894
XConfigureWindow (screen->dpy (), serverFrame, valueMask, &xwc);
899
XUnmapWindow (screen->dpy (), wrapper);
903
XMapWindow (screen->dpy (), wrapper);
904
XMoveResizeWindow (screen->dpy (), wrapper, serverInput.left, serverInput.top,
905
serverGeometry.width (), serverGeometry.height ());
907
XMoveResizeWindow (screen->dpy (), id, 0, 0,
908
serverGeometry.width (), serverGeometry.height ());
909
window->sendConfigureNotify ();
910
window->windowNotify (CompWindowNotifyFrameUpdate);
914
int bw = serverGeometry.border () * 2;
916
xwc.x = serverGeometry.x ();
917
xwc.y = serverGeometry.y ();
918
xwc.width = serverGeometry.width () + bw;
920
/* FIXME: It doesn't make much sense to allow undecorated windows to be
930
if (serverFrameGeometry.x () == xwc.x)
933
serverFrameGeometry.setX (xwc.x);
935
if (serverFrameGeometry.y () == xwc.y)
938
serverFrameGeometry.setY (xwc.y);
940
if (serverFrameGeometry.width () == xwc.width)
941
valueMask &= ~(CWWidth);
943
serverFrameGeometry.setWidth (xwc.width);
945
if (serverFrameGeometry.height () == xwc.height)
946
valueMask &= ~(CWHeight);
948
serverFrameGeometry.setHeight (xwc.height);
951
/* Geometry is the same, so we're not going to get a ConfigureNotify
952
* event when the window is configured, which means that other plugins
953
* won't know that the client, frame and wrapper windows got shifted
954
* around (and might result in display corruption, eg in OpenGL */
958
XWindowAttributes attrib;
959
unsigned int nchildren = 0;
960
Window rootRet = 0, parentRet = 0;
961
Window *children = NULL;
963
xev.type = ConfigureNotify;
964
xev.event = screen->root ();
965
xev.window = priv->serverFrame;
967
XGrabServer (screen->dpy ());
969
if (XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib))
973
xev.width = attrib.width;
974
xev.height = attrib.height;
975
xev.border_width = attrib.border_width;
978
/* We need to ensure that the stacking order is
979
* based on the current server stacking order so
980
* find the sibling to this window's frame in the
981
* server side stack and stack above that */
982
XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
986
for (unsigned int i = 0; i < nchildren; i++)
988
if (i + 1 == nchildren ||
989
children[i + 1] == ROOTPARENT (window))
991
xev.above = children[i];
1001
xev.above = (window->serverPrev) ? ROOTPARENT (window->serverPrev) : None;
1003
xev.override_redirect = priv->attrib.override_redirect;
1007
XSendEvent (screen->dpy (), screen->root (), false,
1008
SubstructureNotifyMask, (XEvent *) &xev);
1010
XUngrabServer (screen->dpy ());
1011
XSync (screen->dpy (), false);
1015
gettimeofday (&lastConfigureRequest, NULL);
1016
compiz::X11::PendingEvent::Ptr pc =
1017
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
1018
new compiz::X11::PendingConfigureEvent (
1019
screen->dpy (), serverFrame, valueMask, &xwc)));
1021
pendingConfigures.add (pc);
1022
XConfigureWindow (screen->dpy (), serverFrame, valueMask, &xwc);
1027
XUnmapWindow (screen->dpy (), wrapper);
1031
XMapWindow (screen->dpy (), wrapper);
1032
XMoveResizeWindow (screen->dpy (), wrapper, 0, 0,
1033
serverGeometry.width (), serverGeometry.height ());
1036
XMoveResizeWindow (screen->dpy (), id, 0, 0,
1037
serverGeometry.width (), serverGeometry.height ());
1038
window->sendConfigureNotify ();
1039
window->windowNotify (CompWindowNotifyFrameUpdate);
1041
window->recalcActions ();
1047
CompWindow::updateWindowOutputExtents ()
1049
CompWindowExtents output (priv->output);
1051
getOutputExtents (output);
1053
if (output.left != priv->output.left ||
1054
output.right != priv->output.right ||
1055
output.top != priv->output.top ||
1056
output.bottom != priv->output.bottom)
1058
priv->output = output;
1060
resizeNotify (0, 0, 0, 0);
1065
CompWindow::getOutputExtents (CompWindowExtents& output)
1067
WRAPABLE_HND_FUNC (0, getOutputExtents, output)
1076
PrivateWindow::rectsToRegion (unsigned int n, XRectangle *rects)
1081
for (unsigned int i = 0; i < n; i++)
1083
x1 = rects[i].x + priv->geometry.border ();
1084
y1 = rects[i].y + priv->geometry.border ();
1085
x2 = x1 + rects[i].width;
1086
y2 = y1 + rects[i].height;
1092
if (x2 > priv->width)
1094
if (y2 > priv->height)
1097
if (y1 < y2 && x1 < x2)
1099
x1 += priv->geometry.x ();
1100
y1 += priv->geometry.y ();
1101
x2 += priv->geometry.x ();
1102
y2 += priv->geometry.y ();
1104
ret += CompRect (x1, y1, x2 - x1, y2 - y1);
1111
/* TODO: This function should be able to check the XShape event
1112
* kind and only get/set shape rectangles for either ShapeInput
1113
* or ShapeBounding, but not both at the same time
1117
PrivateWindow::updateRegion ()
1119
XRectangle r, *boundingShapeRects = NULL;
1120
XRectangle *inputShapeRects = NULL;
1121
int nBounding = 0, nInput = 0;
1123
priv->region = CompRegion ();
1124
priv->inputRegion = CompRegion ();
1126
if (screen->XShape ())
1130
boundingShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
1131
ShapeBounding, &nBounding, &order);
1132
inputShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
1133
ShapeInput, &nInput, &order);
1137
r.x = -priv->geometry.border ();
1138
r.y = -priv->geometry.border ();
1139
r.width = priv->width + priv->geometry.border ();
1140
r.height = priv->height + priv->geometry.border ();
1144
boundingShapeRects = &r;
1150
inputShapeRects = &r;
1154
priv->region += rectsToRegion (nBounding, boundingShapeRects);
1155
priv->inputRegion += rectsToRegion (nInput, inputShapeRects);
1157
if (boundingShapeRects && boundingShapeRects != &r)
1158
XFree (boundingShapeRects);
1159
if (inputShapeRects && inputShapeRects != &r)
1160
XFree (inputShapeRects);
1162
window->updateFrameRegion ();
1166
CompWindow::updateStruts ()
1170
unsigned long n, left;
1171
unsigned char *data;
1172
bool hasOld, hasNew;
1173
CompStruts oldStrut, newStrut;
1179
oldStrut.left = priv->struts->left;
1180
oldStrut.right = priv->struts->right;
1181
oldStrut.top = priv->struts->top;
1182
oldStrut.bottom = priv->struts->bottom;
1191
newStrut.left.x = 0;
1192
newStrut.left.y = 0;
1193
newStrut.left.width = 0;
1194
newStrut.left.height = screen->height ();
1196
newStrut.right.x = screen->width ();
1197
newStrut.right.y = 0;
1198
newStrut.right.width = 0;
1199
newStrut.right.height = screen->height ();
1203
newStrut.top.width = screen->width ();
1204
newStrut.top.height = 0;
1206
newStrut.bottom.x = 0;
1207
newStrut.bottom.y = screen->height ();
1208
newStrut.bottom.width = screen->width ();
1209
newStrut.bottom.height = 0;
1211
result = XGetWindowProperty (screen->dpy (), priv->id,
1212
Atoms::wmStrutPartial,
1213
0L, 12L, false, XA_CARDINAL, &actual, &format,
1216
if (result == Success && data)
1218
unsigned long *struts = (unsigned long *) data;
1224
newStrut.left.y = struts[4];
1225
newStrut.left.width = struts[0];
1226
newStrut.left.height = struts[5] - newStrut.left.y + 1;
1228
newStrut.right.width = struts[1];
1229
newStrut.right.x = screen->width () - newStrut.right.width;
1230
newStrut.right.y = struts[6];
1231
newStrut.right.height = struts[7] - newStrut.right.y + 1;
1233
newStrut.top.x = struts[8];
1234
newStrut.top.width = struts[9] - newStrut.top.x + 1;
1235
newStrut.top.height = struts[2];
1237
newStrut.bottom.x = struts[10];
1238
newStrut.bottom.width = struts[11] - newStrut.bottom.x + 1;
1239
newStrut.bottom.height = struts[3];
1240
newStrut.bottom.y = screen->height () - newStrut.bottom.height;
1248
result = XGetWindowProperty (screen->dpy (), priv->id,
1250
0L, 4L, false, XA_CARDINAL,
1251
&actual, &format, &n, &left, &data);
1253
if (result == Success && data)
1255
unsigned long *struts = (unsigned long *) data;
1261
newStrut.left.x = 0;
1262
newStrut.left.width = struts[0];
1264
newStrut.right.width = struts[1];
1265
newStrut.right.x = screen->width () - newStrut.right.width;
1268
newStrut.top.height = struts[2];
1270
newStrut.bottom.height = struts[3];
1271
newStrut.bottom.y = screen->height () - newStrut.bottom.height;
1280
int strutX1, strutY1, strutX2, strutY2;
1283
/* applications expect us to clip struts to xinerama edges */
1284
for (unsigned int i = 0;
1285
i < screen->screenInfo ().size (); i++)
1287
x1 = screen->screenInfo ()[i].x_org;
1288
y1 = screen->screenInfo ()[i].y_org;
1289
x2 = x1 + screen->screenInfo ()[i].width;
1290
y2 = y1 + screen->screenInfo ()[i].height;
1292
strutX1 = newStrut.left.x;
1293
strutX2 = strutX1 + newStrut.left.width;
1294
strutY1 = newStrut.left.y;
1295
strutY2 = strutY1 + newStrut.left.height;
1297
if (strutX2 > x1 && strutX2 <= x2 &&
1298
strutY1 < y2 && strutY2 > y1)
1300
newStrut.left.x = x1;
1301
newStrut.left.width = strutX2 - x1;
1304
strutX1 = newStrut.right.x;
1305
strutX2 = strutX1 + newStrut.right.width;
1306
strutY1 = newStrut.right.y;
1307
strutY2 = strutY1 + newStrut.right.height;
1309
if (strutX1 > x1 && strutX1 <= x2 &&
1310
strutY1 < y2 && strutY2 > y1)
1312
newStrut.right.x = strutX1;
1313
newStrut.right.width = x2 - strutX1;
1316
strutX1 = newStrut.top.x;
1317
strutX2 = strutX1 + newStrut.top.width;
1318
strutY1 = newStrut.top.y;
1319
strutY2 = strutY1 + newStrut.top.height;
1321
if (strutX1 < x2 && strutX2 > x1 &&
1322
strutY2 > y1 && strutY2 <= y2)
1324
newStrut.top.y = y1;
1325
newStrut.top.height = strutY2 - y1;
1328
strutX1 = newStrut.bottom.x;
1329
strutX2 = strutX1 + newStrut.bottom.width;
1330
strutY1 = newStrut.bottom.y;
1331
strutY2 = strutY1 + newStrut.bottom.height;
1333
if (strutX1 < x2 && strutX2 > x1 &&
1334
strutY1 > y1 && strutY1 <= y2)
1336
newStrut.bottom.y = strutY1;
1337
newStrut.bottom.height = y2 - strutY1;
1342
if (hasOld != hasNew ||
1343
(hasNew && hasOld &&
1344
memcmp (&newStrut, &oldStrut, sizeof (CompStruts))))
1350
priv->struts = (CompStruts *) malloc (sizeof (CompStruts));
1355
*priv->struts = newStrut;
1359
free (priv->struts);
1360
priv->struts = NULL;
1370
CompWindow::incrementDestroyReference ()
1372
priv->destroyRefCnt++;
1376
CompWindow::destroy ()
1380
CompWindow *oldServerNext, *oldServerPrev, *oldNext, *oldPrev;
1381
StackDebugger *dbg = StackDebugger::Default ();
1383
windowNotify (CompWindowNotifyBeforeDestroy);
1385
/* Don't allow frame windows to block input */
1386
XUnmapWindow (screen->dpy (), priv->serverFrame);
1387
XUnmapWindow (screen->dpy (), priv->wrapper);
1389
oldServerNext = serverNext;
1390
oldServerPrev = serverPrev;
1394
/* This is where things get tricky ... it is possible
1395
* to receive a ConfigureNotify relative to a frame window
1396
* for a destroyed window in case we process a ConfigureRequest
1397
* for the destroyed window and then a DestroyNotify for it directly
1398
* afterwards. In that case, we will receive the ConfigureNotify
1399
* for the XConfigureWindow request we made relative to that frame
1400
* window. Because of this, we must keep the frame window in the stack
1401
* as a new toplevel window so that the ConfigureNotify will be processed
1402
* properly until it too receives a DestroyNotify */
1404
if (priv->serverFrame)
1406
XWindowAttributes attrib;
1408
/* It's possible that the frame window was already destroyed because
1409
* the client was unreparented before it was destroyed (eg
1410
* UnmapNotify before DestroyNotify). In that case the frame window
1411
* is going to be an invalid window but since we haven't received
1412
* a DestroyNotify for it yet, it is possible that restacking
1413
* operations could occurr relative to it so we need to hold it
1414
* in the stack for now. Ensure that it is marked override redirect */
1415
XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib);
1417
/* Put the frame window "above" the client window
1419
CoreWindow *cw = new CoreWindow (priv->serverFrame);
1420
cw->manage (priv->id, attrib);
1421
screen->priv->createdWindows.remove (cw);
1425
/* Immediately unhook the window once destroyed
1426
* as the stacking order will be invalid if we don't
1427
* and will continue to be invalid for the period
1428
* that we keep it around in the stack. Instead, push
1429
* it to another stack and keep the next and prev members
1430
* in tact, letting plugins sort out where those windows
1431
* might be in case they need to use them relative to
1434
screen->unhookWindow (this);
1435
screen->unhookServerWindow (this);
1437
/* We must immediately insert the window into the debugging
1440
dbg->removeServerWindow (id ());
1442
/* Unhooking the window will also NULL the next/prev
1443
* linked list links but we don't want that so don't
1448
serverNext = oldServerNext;
1449
serverPrev = oldServerPrev;
1451
screen->priv->destroyedWindows.push_back (this);
1453
/* We must set the xid of this window
1454
* to zero as it no longer references
1459
priv->serverFrame = 0;
1460
priv->managed = false;
1463
priv->destroyRefCnt--;
1464
if (priv->destroyRefCnt)
1467
if (!priv->destroyed)
1469
if (!priv->serverFrame)
1471
StackDebugger *dbg = StackDebugger::Default ();
1474
dbg->addDestroyedFrame (priv->serverId);
1477
priv->destroyed = true;
1478
screen->priv->pendingDestroys++;
1484
CompWindow::sendConfigureNotify ()
1486
XConfigureEvent xev;
1487
XWindowAttributes attrib;
1488
unsigned int nchildren;
1489
Window rootRet, parentRet;
1492
xev.type = ConfigureNotify;
1493
xev.event = priv->id;
1494
xev.window = priv->id;
1496
/* in order to avoid race conditions we must use the current
1497
* server configuration */
1499
XGrabServer (screen->dpy ());
1500
XSync (screen->dpy (), false);
1502
if (XGetWindowAttributes (screen->dpy (), priv->id, &attrib))
1506
xev.width = attrib.width;
1507
xev.height = attrib.height;
1508
xev.border_width = attrib.border_width;
1513
XWindowAttributes fAttrib;
1514
XWindowAttributes wAttrib;
1516
/* Add offset between wrapper and client */
1517
if (XGetWindowAttributes (screen->dpy (), priv->wrapper, &wAttrib))
1523
/* Add offset between frame and client */
1524
if (XGetWindowAttributes (screen->dpy (), priv->frame, &fAttrib))
1531
/* We need to ensure that the stacking order is
1532
* based on the current server stacking order so
1533
* find the sibling to this window's frame in the
1534
* server side stack and stack above that */
1535
XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
1539
for (unsigned int i = 0; i < nchildren; i++)
1541
if (i + 1 == nchildren ||
1542
children[i + 1] == ROOTPARENT (this))
1544
xev.above = children[i];
1554
xev.above = (serverPrev) ? ROOTPARENT (serverPrev) : None;
1555
xev.override_redirect = priv->attrib.override_redirect;
1557
XSendEvent (screen->dpy (), priv->id, false,
1558
StructureNotifyMask, (XEvent *) &xev);
1561
XUngrabServer (screen->dpy ());
1562
XSync (screen->dpy (), false);
1568
windowNotify (CompWindowNotifyBeforeMap);
1572
if (priv->pendingMaps > 0)
1573
priv->pendingMaps = 0;
1575
priv->mapNum = screen->priv->mapNum++;
1578
screen->updateWorkarea ();
1580
if (windowClass () == InputOnly)
1583
priv->unmapRefCnt = 1;
1585
priv->attrib.map_state = IsViewable;
1587
if (!overrideRedirect ())
1588
screen->priv->setWmState (NormalState, priv->id);
1590
priv->invisible = true;
1593
priv->lastPong = screen->priv->lastPing;
1595
priv->updateRegion ();
1596
priv->updateSize ();
1598
screen->priv->updateClientList ();
1600
if (priv->type & CompWindowTypeDesktopMask)
1601
screen->priv->desktopWindowCount++;
1603
if (priv->protocols & CompWindowProtocolSyncRequestMask)
1606
sendConfigureNotify ();
1609
if (!overrideRedirect ())
1614
priv->shaded = false;
1615
priv->updateFrameWindow ();
1620
windowNotify (CompWindowNotifyMap);
1624
CompWindow::incrementUnmapReference ()
1626
priv->unmapRefCnt++;
1630
CompWindow::unmap ()
1632
windowNotify (CompWindowNotifyBeforeUnmap);
1637
/* Even though we're still keeping the backing
1638
* pixmap of the window around, it's safe to
1639
* unmap the frame window since there's no use
1640
* for it at this point anyways and it just blocks
1641
* input, but keep it around if shaded */
1643
XUnmapWindow (screen->dpy (), priv->wrapper);
1646
XUnmapWindow (screen->dpy (), priv->serverFrame);
1648
priv->unmapRefCnt--;
1649
if (priv->unmapRefCnt > 0)
1652
if (priv->unmanaging)
1656
int gravity = priv->sizeHints.win_gravity;
1658
/* revert gravity adjustment made at MapNotify time */
1659
xwc.x = priv->serverGeometry.x ();
1660
xwc.y = priv->serverGeometry.y ();
1664
xwcm = priv->adjustConfigureRequestForGravity (&xwc,
1669
configureXWindow (xwcm, &xwc);
1671
priv->unmanaging = false;
1674
if (priv->serverFrame && !priv->shaded)
1675
priv->unreparent ();
1678
screen->updateWorkarea ();
1680
if (priv->attrib.map_state != IsViewable)
1683
if (priv->type == CompWindowTypeDesktopMask)
1684
screen->priv->desktopWindowCount--;
1686
priv->attrib.map_state = IsUnmapped;
1687
priv->invisible = true;
1689
if (priv->shaded && priv->height)
1691
priv->updateFrameWindow ();
1694
screen->priv->updateClientList ();
1696
windowNotify (CompWindowNotifyUnmap);
1700
PrivateWindow::withdraw ()
1702
if (!attrib.override_redirect)
1703
screen->priv->setWmState (WithdrawnState, id);
1706
unmanaging = managed;
1711
PrivateWindow::restack (Window aboveId)
1713
if (aboveId && (aboveId == id || aboveId == serverFrame))
1714
// Don't try to raise a window above itself
1716
else if (window->prev)
1718
if (aboveId && (aboveId == window->prev->id () ||
1719
aboveId == window->prev->priv->frame))
1722
else if (aboveId == None && !window->next)
1725
if (aboveId && !screen->findTopLevelWindow (aboveId, true))
1730
screen->unhookWindow (window);
1731
screen->insertWindow (window, aboveId);
1733
/* Update the server side window list for
1734
* override redirect windows immediately
1735
* since there is no opportunity to update
1736
* the server side list when we configure them
1737
* since we never get a ConfigureRequest for those */
1738
if (attrib.override_redirect != 0)
1740
StackDebugger *dbg = StackDebugger::Default ();
1742
screen->unhookServerWindow (window);
1743
screen->insertServerWindow (window, aboveId);
1746
dbg->overrideRedirectRestack (window->id (), aboveId);
1749
screen->priv->updateClientList ();
1751
window->windowNotify (CompWindowNotifyRestack);
1757
CompWindow::resize (XWindowAttributes attr)
1759
return resize (Geometry (attr.x, attr.y, attr.width, attr.height,
1760
attr.border_width));
1764
CompWindow::resize (int x,
1770
return resize (Geometry (x, y, width, height, border));
1774
CompWindow::resize (CompWindow::Geometry gm)
1776
/* Input extents are now the last thing sent
1777
* from the server. This might not work in some
1778
* cases though because setWindowFrameExtents may
1779
* be called more than once in an event processing
1780
* cycle so every set of input extents up until the
1781
* last one will be invalid. The real solution
1782
* here is to handle ConfigureNotify events on
1783
* frame windows and client windows separately */
1785
priv->input = priv->serverInput;
1787
if (priv->geometry.width () != gm.width () ||
1788
priv->geometry.height () != gm.height () ||
1789
priv->geometry.border () != gm.border ())
1792
int dx, dy, dwidth, dheight;
1794
pw = gm.width () + gm.border () * 2;
1795
ph = gm.height () + gm.border () * 2;
1797
dx = gm.x () - priv->geometry.x ();
1798
dy = gm.y () - priv->geometry.y ();
1799
dwidth = gm.width () - priv->geometry.width ();
1800
dheight = gm.height () - priv->geometry.height ();
1802
priv->geometry.set (gm.x (), gm.y (),
1803
gm.width (), gm.height (),
1810
priv->updateRegion ();
1812
resizeNotify (dx, dy, dwidth, dheight);
1814
priv->invisible = WINDOW_INVISIBLE (priv);
1816
else if (priv->geometry.x () != gm.x () || priv->geometry.y () != gm.y ())
1820
dx = gm.x () - priv->geometry.x ();
1821
dy = gm.y () - priv->geometry.y ();
1823
priv->geometry.setX (gm.x ());
1824
priv->geometry.setY (gm.y ());
1826
priv->region.translate (dx, dy);
1827
priv->inputRegion.translate (dx, dy);
1828
if (!priv->frameRegion.isEmpty ())
1829
priv->frameRegion.translate (dx, dy);
1831
priv->invisible = WINDOW_INVISIBLE (priv);
1833
moveNotify (dx, dy, true);
1836
updateFrameRegion ();
1842
syncValueIncrement (XSyncValue *value)
1847
XSyncIntToValue (&one, 1);
1848
XSyncValueAdd (value, *value, one, &overflow);
1852
PrivateWindow::initializeSyncCounter ()
1854
XSyncAlarmAttributes values;
1857
unsigned long n, left;
1858
unsigned char *data;
1861
return syncAlarm != None;
1863
if (!(protocols & CompWindowProtocolSyncRequestMask))
1866
result = XGetWindowProperty (screen->dpy (), id,
1867
Atoms::wmSyncRequestCounter,
1868
0L, 1L, false, XA_CARDINAL, &actual, &format,
1871
if (result == Success && n && data)
1873
unsigned long *counter = (unsigned long *) data;
1875
syncCounter = *counter;
1879
XSyncIntsToValue (&syncValue, (unsigned int) rand (), 0);
1880
XSyncSetCounter (screen->dpy (),
1884
syncValueIncrement (&syncValue);
1886
values.events = true;
1888
values.trigger.counter = syncCounter;
1889
values.trigger.wait_value = syncValue;
1891
values.trigger.value_type = XSyncAbsolute;
1892
values.trigger.test_type = XSyncPositiveComparison;
1894
XSyncIntToValue (&values.delta, 1);
1896
values.events = true;
1898
CompScreen::checkForError (screen->dpy ());
1900
/* Note that by default, the alarm increments the trigger value
1901
* when it fires until the condition (counter.value < trigger.value)
1904
syncAlarm = XSyncCreateAlarm (screen->dpy (),
1913
if (CompScreen::checkForError (screen->dpy ()))
1916
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
1919
else if (result == Success && data)
1928
CompWindow::sendSyncRequest ()
1930
XClientMessageEvent xev;
1935
if (!priv->initializeSyncCounter ())
1938
xev.type = ClientMessage;
1939
xev.window = priv->id;
1940
xev.message_type = Atoms::wmProtocols;
1942
xev.data.l[0] = Atoms::wmSyncRequest;
1943
xev.data.l[1] = CurrentTime;
1944
xev.data.l[2] = XSyncValueLow32 (priv->syncValue);
1945
xev.data.l[3] = XSyncValueHigh32 (priv->syncValue);
1948
syncValueIncrement (&priv->syncValue);
1950
XSendEvent (screen->dpy (), priv->id, false, 0, (XEvent *) &xev);
1952
priv->syncWait = true;
1953
priv->syncGeometry = priv->serverGeometry;
1955
if (!priv->syncWaitTimer.active ())
1956
priv->syncWaitTimer.start ();
1960
PrivateWindow::configure (XConfigureEvent *ce)
1962
unsigned int valueMask = 0;
1967
/* remove configure event from pending configures */
1968
if (priv->geometry.x () != ce->x)
1971
if (priv->geometry.y () != ce->y)
1974
if (priv->geometry.width () != ce->width)
1975
valueMask |= CWWidth;
1977
if (priv->geometry.height () != ce->height)
1978
valueMask |= CWHeight;
1980
if (priv->geometry.border () != ce->border_width)
1981
valueMask |= CWBorderWidth;
1983
if (ROOTPARENT (window->prev) != ce->above)
1984
valueMask |= CWSibling | CWStackMode;
1986
priv->attrib.override_redirect = ce->override_redirect;
1988
priv->frameGeometry.set (ce->x, ce->y, ce->width,
1989
ce->height, ce->border_width);
1992
priv->syncGeometry.set (ce->x, ce->y, ce->width, ce->height,
1996
if (ce->override_redirect)
1998
priv->serverGeometry.set (ce->x, ce->y, ce->width, ce->height,
2002
window->resize (ce->x, ce->y, ce->width, ce->height, ce->border_width);
2005
if (ce->event == screen->root ())
2006
priv->restack (ce->above);
2010
PrivateWindow::configureFrame (XConfigureEvent *ce)
2012
int x, y, width, height;
2014
unsigned int valueMask = 0;
2019
/* remove configure event from pending configures */
2020
if (priv->frameGeometry.x () != ce->x)
2023
if (priv->frameGeometry.y () != ce->y)
2026
if (priv->frameGeometry.width () != ce->width)
2027
valueMask |= CWWidth;
2029
if (priv->frameGeometry.height () != ce->height)
2030
valueMask |= CWHeight;
2032
if (priv->frameGeometry.border () != ce->border_width)
2033
valueMask |= CWBorderWidth;
2037
if (ROOTPARENT (window->prev) != ce->above)
2038
valueMask |= CWSibling | CWStackMode;
2043
valueMask |= CWSibling | CWStackMode;
2046
if (!pendingConfigures.match ((XEvent *) ce))
2048
compLogMessage ("core", CompLogLevelWarn, "unhandled ConfigureNotify on 0x%x!", serverFrame);
2049
compLogMessage ("core", CompLogLevelWarn, "this should never happen. you should "\
2050
"probably file a bug about this.");
2054
pendingConfigures = compiz::X11::PendingEventQueue (screen->dpy ());
2058
/* subtract the input extents last sent to the
2059
* server to calculate the client size and then
2060
* re-sync the input extents and extents last
2061
* sent to server on resize () */
2063
x = ce->x + priv->serverInput.left;
2064
y = ce->y + priv->serverInput.top;
2065
width = ce->width - priv->serverGeometry.border () * 2 - priv->serverInput.left - priv->serverInput.right;
2067
/* Don't use the server side frame geometry
2068
* to determine the geometry of shaded
2069
* windows since we didn't resize them
2070
* on configureXWindow */
2072
height = priv->serverGeometry.height () - priv->serverGeometry.border () * 2 - priv->serverInput.top - priv->serverInput.bottom;
2074
height = ce->height - priv->serverGeometry.border () * 2 - priv->serverInput.top - priv->serverInput.bottom;
2076
/* set the frame geometry */
2077
priv->frameGeometry.set (ce->x, ce->y, ce->width, ce->height, ce->border_width);
2081
priv->syncGeometry.set (x, y, width, height, ce->border_width);
2083
window->resize (x, y, width, height, ce->border_width);
2085
if (priv->restack (ce->above))
2086
priv->updatePassiveButtonGrabs ();
2088
above = screen->findWindow (ce->above);
2091
above->priv->updatePassiveButtonGrabs ();
2093
if (!pendingConfigures.pending ())
2095
/* Tell plugins its ok to start doing stupid things again but
2096
* obviously FIXME */
2097
CompOption::Vector options;
2098
CompOption::Value v;
2100
options.push_back (CompOption ("window", CompOption::TypeInt));
2102
options.back ().set (v);
2103
options.push_back (CompOption ("active", CompOption::TypeInt));
2105
options.back ().set (v);
2107
/* Notify other plugins that it is unsafe to change geometry or serverGeometry
2108
* FIXME: That API should not be accessible to plugins, this is a hack to avoid
2111
screen->handleCompizEvent ("core", "lock_position", options);
2116
PrivateWindow::circulate (XCirculateEvent *ce)
2120
if (ce->place == PlaceOnTop)
2121
newAboveId = screen->priv->getTopWindow ();
2125
priv->restack (newAboveId);
2129
CompWindow::move (int dx,
2135
/* Don't allow window movement to overwrite working geometries
2136
* last received from the server if we know there are pending
2137
* ConfigureNotify events on this window. That's a clunky workaround
2138
* and a FIXME in any case, however, until we can break the API
2139
* and remove CompWindow::move, this will need to be the case */
2141
if (!priv->pendingConfigures.pending ())
2143
priv->geometry.setX (priv->geometry.x () + dx);
2144
priv->geometry.setY (priv->geometry.y () + dy);
2145
priv->frameGeometry.setX (priv->frameGeometry.x () + dx);
2146
priv->frameGeometry.setY (priv->frameGeometry.y () + dy);
2148
priv->pendingPositionUpdates = true;
2150
priv->region.translate (dx, dy);
2151
priv->inputRegion.translate (dx, dy);
2152
if (!priv->frameRegion.isEmpty ())
2153
priv->frameRegion.translate (dx, dy);
2155
priv->invisible = WINDOW_INVISIBLE (priv);
2157
moveNotify (dx, dy, immediate);
2162
unsigned int valueMask = CWX | CWY;
2163
struct timeval tv, old;
2164
compLogMessage ("core", CompLogLevelDebug, "pending configure notifies on 0x%x,"\
2165
"moving window asyncrhonously!", (unsigned int) priv->serverId);
2167
old = priv->lastConfigureRequest;
2168
gettimeofday (&tv, NULL);
2170
xwc.x = priv->serverGeometry.x () + dx;
2171
xwc.y = priv->serverGeometry.y () + dy;
2173
configureXWindow (valueMask, &xwc);
2175
priv->lastConfigureRequest = old;
2177
/* FIXME: This is a hack to avoid performance regressions
2178
* and must be removed in 0.9.6 */
2179
if (tv.tv_usec - priv->lastConfigureRequest.tv_usec > 300000)
2181
compLogMessage ("core", CompLogLevelWarn, "failed to receive ConfigureNotify event from request at %i (now: %i)\n",
2182
priv->lastConfigureRequest.tv_usec, tv.tv_usec);
2183
priv->pendingConfigures = compiz::X11::PendingEventQueue (screen->dpy ());
2190
compiz::X11::PendingEventQueue::pending ()
2192
return !mEvents.empty ();
2196
compiz::X11::PendingEventQueue::add (PendingEvent::Ptr p)
2198
mEvents.push_back (p);
2202
compiz::X11::PendingEventQueue::removeIfMatching (const PendingEvent::Ptr &p, XEvent *event)
2204
return p->match (event);
2208
compiz::X11::PendingEventQueue::match (XEvent *event)
2210
unsigned int lastSize = mEvents.size ();
2212
mEvents.erase (std::remove_if (mEvents.begin (), mEvents.end (),
2213
boost::bind (&compiz::X11::PendingEventQueue::removeIfMatching, this, _1, event)), mEvents.end ());
2215
return lastSize != mEvents.size ();
2219
compiz::X11::PendingEventQueue::forEachIf (boost::function<bool (compiz::X11::PendingEvent::Ptr)> f)
2221
foreach (compiz::X11::PendingEvent::Ptr p, mEvents)
2230
compiz::X11::PendingEventQueue::PendingEventQueue (Display *d)
2234
compiz::X11::PendingEventQueue::~PendingEventQueue ()
2239
compiz::X11::PendingEvent::getEventWindow (XEvent *event)
2241
return event->xany.window;
2245
compiz::X11::PendingEvent::match (XEvent *event)
2247
if (event->xany.serial != mSerial)
2249
if (getEventWindow (event)!= mWindow)
2255
compiz::X11::PendingEvent::PendingEvent (Display *d, Window w) :
2256
mSerial (XNextRequest (d)),
2261
compiz::X11::PendingEvent::~PendingEvent ()
2266
compiz::X11::PendingConfigureEvent::getEventWindow (XEvent *event)
2268
return event->xconfigure.window;
2272
compiz::X11::PendingConfigureEvent::matchVM (unsigned int valueMask)
2274
return valueMask & mValueMask;
2278
compiz::X11::PendingConfigureEvent::match (XEvent *event)
2280
XConfigureEvent *ce = (XConfigureEvent *) event;
2281
bool matched = true;
2283
if (!compiz::X11::PendingEvent::match (event))
2286
if (mValueMask & CWX)
2287
if (ce->x != mXwc.x)
2290
if (mValueMask & CWY)
2291
if (ce->y != mXwc.y)
2294
if (mValueMask & CWWidth)
2295
if (ce->width != mXwc.width)
2298
if (mValueMask & CWHeight)
2299
if (ce->height != mXwc.height)
2302
if (mValueMask & CWBorderWidth)
2303
if (ce->border_width != mXwc.border_width)
2306
if (mValueMask & (CWStackMode | CWSibling))
2307
if (ce->above != mXwc.sibling)
2310
/* Remove events from the queue
2311
* even if they didn't match what
2312
* we expected them to be, but still
2313
* complain about it */
2316
compLogMessage ("core", CompLogLevelWarn, "no exact match for ConfigureNotify on 0x%x!", mWindow);
2317
compLogMessage ("core", CompLogLevelWarn, "expected the following changes:");
2318
if (mValueMask & CWX)
2319
compLogMessage ("core", CompLogLevelWarn, "x: %i", mXwc.x);
2320
if (mValueMask & CWY)
2321
compLogMessage ("core", CompLogLevelWarn, "y: %i", mXwc.y);
2322
if (mValueMask & CWWidth)
2323
compLogMessage ("core", CompLogLevelWarn, "width: %i", mXwc.width);
2324
if (mValueMask & CWHeight)
2325
compLogMessage ("core", CompLogLevelWarn, "height: %i", mXwc.height);
2326
if (mValueMask & CWBorderWidth)
2327
compLogMessage ("core", CompLogLevelWarn, "border: %i", mXwc.border_width);
2328
if (mValueMask & (CWStackMode | CWSibling))
2329
compLogMessage ("core", CompLogLevelWarn, "sibling: 0x%x", mXwc.sibling);
2331
compLogMessage ("core", CompLogLevelWarn, "instead got:");
2332
compLogMessage ("core", CompLogLevelWarn, "x: %i", ce->x);
2333
compLogMessage ("core", CompLogLevelWarn, "y: %i", ce->y);
2334
compLogMessage ("core", CompLogLevelWarn, "width: %i", ce->width);
2335
compLogMessage ("core", CompLogLevelWarn, "height: %i", ce->height);
2336
compLogMessage ("core", CompLogLevelWarn, "above: %i", ce->above);
2337
compLogMessage ("core", CompLogLevelWarn, "this should never happen. you should "\
2338
"probably file a bug about this.");
2344
compiz::X11::PendingConfigureEvent::PendingConfigureEvent (Display *d,
2346
unsigned int valueMask,
2347
XWindowChanges *xwc) :
2348
compiz::X11::PendingEvent::PendingEvent (d, w),
2349
mValueMask (valueMask),
2352
CompOption::Vector options;
2353
CompOption::Value v;
2355
options.push_back (CompOption ("window", CompOption::TypeInt));
2357
options.back ().set (v);
2358
options.push_back (CompOption ("active", CompOption::TypeInt));
2360
options.back ().set (v);
2362
/* Notify other plugins that it is unsafe to change geometry or serverGeometry
2363
* FIXME: That API should not be accessible to plugins, this is a hack to avoid
2366
screen->handleCompizEvent ("core", "lock_position", options);
2369
compiz::X11::PendingConfigureEvent::~PendingConfigureEvent ()
2374
CompWindow::syncPosition ()
2376
unsigned int valueMask = CWX | CWY;
2379
if (priv->pendingPositionUpdates && !priv->pendingConfigures.pending ())
2381
if (priv->serverFrameGeometry.x () == priv->frameGeometry.x ())
2382
valueMask &= ~(CWX);
2383
if (priv->serverFrameGeometry.y () == priv->frameGeometry.y ())
2384
valueMask &= ~(CWY);
2386
/* Because CompWindow::move can update the geometry last
2387
* received from the server, we must indicate that no values
2388
* changed, because when the ConfigureNotify comes around
2389
* the values are going to be the same. That's obviously
2390
* broken behaviour and worthy of a FIXME, but requires
2391
* larger changes to the window movement system. */
2394
priv->serverGeometry.setX (priv->geometry.x ());
2395
priv->serverGeometry.setY (priv->geometry.y ());
2396
priv->serverFrameGeometry.setX (priv->frameGeometry.x ());
2397
priv->serverFrameGeometry.setY (priv->frameGeometry.y ());
2399
xwc.x = priv->serverFrameGeometry.x ();
2400
xwc.y = priv->serverFrameGeometry.y ();
2402
gettimeofday (&priv->lastConfigureRequest, NULL);
2403
compiz::X11::PendingEvent::Ptr pc =
2404
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
2405
new compiz::X11::PendingConfigureEvent (
2406
screen->dpy (), priv->serverFrame, 0, &xwc)));
2408
priv->pendingConfigures.add (pc);
2410
XConfigureWindow (screen->dpy (), ROOTPARENT (this), valueMask, &xwc);
2412
if (priv->serverFrame)
2414
XMoveWindow (screen->dpy (), priv->wrapper,
2415
priv->serverInput.left, priv->serverInput.top);
2416
sendConfigureNotify ();
2419
priv->pendingPositionUpdates = false;
2424
CompWindow::focus ()
2426
WRAPABLE_HND_FUNC_RETURN (2, bool, focus)
2428
if (overrideRedirect ())
2431
if (!priv->managed || priv->unmanaging)
2434
if (!onCurrentDesktop ())
2437
if (priv->destroyed)
2440
if (!priv->shaded && (priv->state & CompWindowStateHiddenMask))
2443
if (priv->geometry.x () + priv->width <= 0 ||
2444
priv->geometry.y () + priv->height <= 0 ||
2445
priv->geometry.x () >= (int) screen->width ()||
2446
priv->geometry.y () >= (int) screen->height ())
2453
CompWindow::place (CompPoint &pos)
2455
WRAPABLE_HND_FUNC_RETURN (4, bool, place, pos)
2460
CompWindow::validateResizeRequest (unsigned int &mask,
2461
XWindowChanges *xwc,
2462
unsigned int source)
2464
WRAPABLE_HND_FUNC (5, validateResizeRequest, mask, xwc, source)
2466
if (!(priv->type & (CompWindowTypeDockMask |
2467
CompWindowTypeFullscreenMask |
2468
CompWindowTypeUnknownMask)))
2474
min = screen->workArea ().y () + priv->input.top;
2475
max = screen->workArea ().bottom ();
2477
if (priv->state & CompWindowStateStickyMask &&
2478
(xwc->y < min || xwc->y > max))
2480
xwc->y = priv->serverGeometry.y ();
2484
min -= screen->vp ().y () * screen->height ();
2485
max += (screen->vpSize ().height () - screen->vp ().y () - 1) *
2490
else if (xwc->y > max)
2499
min = screen->workArea ().x () + priv->input.left;
2500
max = screen->workArea ().right ();
2502
if (priv->state & CompWindowStateStickyMask &&
2503
(xwc->x < min || xwc->x > max))
2505
xwc->x = priv->serverGeometry.x ();
2509
min -= screen->vp ().x () * screen->width ();
2510
max += (screen->vpSize ().width () - screen->vp ().x () - 1) *
2515
else if (xwc->x > max)
2523
CompWindow::resizeNotify (int dx,
2527
WRAPABLE_HND_FUNC (6, resizeNotify, dx, dy, dwidth, dheight)
2530
CompWindow::moveNotify (int dx,
2533
WRAPABLE_HND_FUNC (7, moveNotify, dx, dy, immediate)
2536
CompWindow::windowNotify (CompWindowNotify n)
2537
WRAPABLE_HND_FUNC (8, windowNotify, n)
2540
CompWindow::grabNotify (int x,
2545
WRAPABLE_HND_FUNC (9, grabNotify, x, y, state, mask)
2546
priv->grabbed = true;
2550
CompWindow::ungrabNotify ()
2552
WRAPABLE_HND_FUNC (10, ungrabNotify)
2553
priv->grabbed = false;
2557
CompWindow::stateChangeNotify (unsigned int lastState)
2559
WRAPABLE_HND_FUNC (11, stateChangeNotify, lastState);
2561
/* if being made sticky */
2562
if (!(lastState & CompWindowStateStickyMask) &&
2563
(priv->state & CompWindowStateStickyMask))
2565
CompPoint vp; /* index of the window's vp */
2567
/* Find which viewport the window falls in,
2568
and check if it's the current viewport */
2569
vp = defaultViewport ();
2570
if (screen->vp () != vp)
2572
unsigned int valueMask = CWX | CWY;
2575
xwc.x = serverGeometry ().x () + (screen->vp ().x () - vp.x ()) * screen->width ();
2576
xwc.y = serverGeometry ().y () + (screen->vp ().y () - vp.y ()) * screen->height ();
2578
configureXWindow (valueMask, &xwc);
2585
PrivateWindow::isGroupTransient (Window clientLeader)
2590
if (transientFor == None || transientFor == screen->root ())
2592
if (type & (CompWindowTypeUtilMask |
2593
CompWindowTypeToolbarMask |
2594
CompWindowTypeMenuMask |
2595
CompWindowTypeDialogMask |
2596
CompWindowTypeModalDialogMask))
2598
if (this->clientLeader == clientLeader)
2607
PrivateWindow::getModalTransient ()
2609
CompWindow *w, *modalTransient;
2611
modalTransient = window;
2613
for (w = screen->windows ().back (); w; w = w->prev)
2615
if (w == modalTransient || w->priv->mapNum == 0)
2618
if (w->priv->transientFor == modalTransient->priv->id)
2620
if (w->priv->state & CompWindowStateModalMask)
2623
w = screen->windows ().back ();
2628
if (modalTransient == window)
2630
/* don't look for group transients with modal state if current window
2632
if (state & CompWindowStateModalMask)
2635
for (w = screen->windows ().back (); w; w = w->prev)
2637
if (w == modalTransient || w->priv->mapNum == 0)
2640
if (isAncestorTo (modalTransient, w))
2643
if (w->priv->isGroupTransient (modalTransient->priv->clientLeader))
2645
if (w->priv->state & CompWindowStateModalMask)
2648
w = w->priv->getModalTransient ();
2658
if (modalTransient == window)
2659
modalTransient = NULL;
2661
return modalTransient;
2665
CompWindow::moveInputFocusTo ()
2667
CompScreen *s = screen;
2668
CompWindow *modalTransient;
2670
modalTransient = priv->getModalTransient ();
2672
return modalTransient->moveInputFocusTo ();
2674
/* If the window is still hidden but not shaded
2675
* it probably meant that a plugin overloaded
2676
* CompWindow::focus to allow the focus to go
2677
* to this window, so only move the input focus
2678
* to the frame if the window is shaded */
2681
XSetInputFocus (s->dpy (), priv->serverFrame,
2682
RevertToPointerRoot, CurrentTime);
2683
XChangeProperty (s->dpy (), s->root (), Atoms::winActive,
2684
XA_WINDOW, 32, PropModeReplace,
2685
(unsigned char *) &priv->id, 1);
2687
screen->priv->nextActiveWindow = priv->serverFrame;
2691
bool setFocus = false;
2693
if (priv->inputHint)
2695
XSetInputFocus (s->dpy (), priv->id, RevertToPointerRoot,
2700
if (priv->protocols & CompWindowProtocolTakeFocusMask)
2704
ev.type = ClientMessage;
2705
ev.xclient.window = priv->id;
2706
ev.xclient.message_type = Atoms::wmProtocols;
2707
ev.xclient.format = 32;
2708
ev.xclient.data.l[0] = Atoms::wmTakeFocus;
2709
ev.xclient.data.l[1] = s->getCurrentTime ();
2710
ev.xclient.data.l[2] = 0;
2711
ev.xclient.data.l[3] = 0;
2712
ev.xclient.data.l[4] = 0;
2714
XSendEvent (s->dpy (), priv->id, false, NoEventMask, &ev);
2720
screen->priv->nextActiveWindow = priv->id;
2722
if (!setFocus && !modalTransient)
2724
CompWindow *ancestor;
2726
/* move input to closest ancestor */
2727
for (ancestor = s->windows ().front (); ancestor;
2728
ancestor = ancestor->next)
2730
if (PrivateWindow::isAncestorTo (this, ancestor))
2732
ancestor->moveInputFocusTo ();
2741
CompWindow::moveInputFocusToOtherWindow ()
2743
if (priv->id == screen->activeWindow () ||
2744
priv->id == screen->priv->nextActiveWindow)
2746
CompWindow *ancestor;
2747
Window lastNextActiveWindow = screen->priv->nextActiveWindow;
2749
if (priv->transientFor && priv->transientFor != screen->root ())
2751
ancestor = screen->findWindow (priv->transientFor);
2753
ancestor->focus () &&
2754
!(ancestor->priv->type & (CompWindowTypeDesktopMask |
2755
CompWindowTypeDockMask)))
2757
ancestor->moveInputFocusTo ();
2760
screen->focusDefaultWindow ();
2762
else if (priv->type & (CompWindowTypeDialogMask |
2763
CompWindowTypeModalDialogMask))
2765
CompWindow *a, *focus = NULL;
2767
for (a = screen->windows ().back (); a; a = a->prev)
2769
if (a->priv->clientLeader == priv->clientLeader)
2775
if (a->priv->type & (CompWindowTypeNormalMask |
2776
CompWindowTypeDialogMask |
2777
CompWindowTypeModalDialogMask))
2779
if (priv->compareWindowActiveness (focus, a) < 0)
2789
if (focus && !(focus->priv->type & (CompWindowTypeDesktopMask |
2790
CompWindowTypeDockMask)))
2792
focus->moveInputFocusTo ();
2795
screen->focusDefaultWindow ();
2798
screen->focusDefaultWindow ();
2801
* moveInputFocusTo and focusDefaultWindow should really
2802
* return booleans */
2803
if (lastNextActiveWindow != screen->priv->nextActiveWindow &&
2804
screen->priv->optionGetRaiseOnClick ())
2806
/* If this window just got the focus because another window
2807
* was unmanaged then we should also raise it if click raise
2808
* is on, since another plugin might have raised another window
2809
* without wanting to focus it and this window will be beneath
2810
* it in the stack but above it in the active window history
2811
* so when the focus moves here this window should be raised
2812
* That's the tradeoff for maintaining a predictable focus order
2813
* as compared to eg a predictable stacking order */
2815
CompWindow *nextActive = screen->findWindow (screen->priv->nextActiveWindow);
2817
nextActive->raise ();
2824
PrivateWindow::stackLayerCheck (CompWindow *w,
2825
Window clientLeader,
2828
if (isAncestorTo (w, below))
2831
if (isAncestorTo (below, w))
2834
if (clientLeader && below->priv->clientLeader == clientLeader)
2835
if (below->priv->isGroupTransient (clientLeader))
2838
if (w->priv->state & CompWindowStateAboveMask)
2842
else if (w->priv->state & CompWindowStateBelowMask)
2844
if (below->priv->state & CompWindowStateBelowMask)
2847
else if (!(below->priv->state & CompWindowStateAboveMask))
2856
PrivateWindow::avoidStackingRelativeTo (CompWindow *w)
2858
if (w->overrideRedirect ())
2861
if (w->destroyed ())
2864
if (!w->priv->shaded && !w->priv->pendingMaps)
2866
if (!w->isViewable () || !w->isMapped ())
2873
/* goes through the stack, top-down until we find a window we should
2874
stack above, normal windows can be stacked above fullscreen windows
2875
(and fullscreen windows over others in their layer) if aboveFs is true. */
2877
PrivateWindow::findSiblingBelow (CompWindow *w,
2881
CompWindow *t = screen->findWindow (w->transientFor ());
2882
Window clientLeader = w->priv->clientLeader;
2883
unsigned int type = w->priv->type;
2884
unsigned int belowMask;
2887
belowMask = CompWindowTypeDockMask;
2889
belowMask = CompWindowTypeDockMask | CompWindowTypeFullscreenMask;
2891
/* normal stacking of fullscreen windows with below state */
2892
if ((type & CompWindowTypeFullscreenMask) &&
2893
(w->priv->state & CompWindowStateBelowMask))
2894
type = CompWindowTypeNormalMask;
2896
while (t && type != CompWindowTypeDockMask)
2898
/* dock stacking of transients for docks */
2899
if (t->type () & CompWindowTypeDockMask)
2900
type = CompWindowTypeDockMask;
2902
t = screen->findWindow (t->transientFor ());
2905
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2906
clientLeader = None;
2908
for (below = screen->serverWindows ().back (); below;
2909
below = below->serverPrev)
2911
if (below == w || avoidStackingRelativeTo (below))
2914
/* always above desktop windows */
2915
if (below->priv->type & CompWindowTypeDesktopMask)
2919
case CompWindowTypeDesktopMask:
2920
/* desktop window layer */
2922
case CompWindowTypeFullscreenMask:
2925
/* otherwise fall-through */
2926
case CompWindowTypeDockMask:
2927
/* fullscreen and dock layer */
2928
if (below->priv->type & (CompWindowTypeFullscreenMask |
2929
CompWindowTypeDockMask))
2931
if (stackLayerCheck (w, clientLeader, below))
2941
bool allowedRelativeToLayer = !(below->priv->type & belowMask);
2943
if (aboveFs && below->priv->type & CompWindowTypeFullscreenMask)
2944
if (!below->focus ())
2947
t = screen->findWindow (below->transientFor ());
2949
while (t && allowedRelativeToLayer)
2951
/* dock stacking of transients for docks */
2952
allowedRelativeToLayer = !(t->priv->type & belowMask);
2954
t = screen->findWindow (t->transientFor ());
2957
/* fullscreen and normal layer */
2958
if (allowedRelativeToLayer)
2960
if (stackLayerCheck (w, clientLeader, below))
2971
/* goes through the stack, top-down and returns the lowest window we
2974
PrivateWindow::findLowestSiblingBelow (CompWindow *w)
2976
CompWindow *below, *lowest = screen->serverWindows ().back ();
2977
CompWindow *t = screen->findWindow (w->transientFor ());
2978
Window clientLeader = w->priv->clientLeader;
2979
unsigned int type = w->priv->type;
2981
/* normal stacking fullscreen windows with below state */
2982
if ((type & CompWindowTypeFullscreenMask) &&
2983
(w->priv->state & CompWindowStateBelowMask))
2984
type = CompWindowTypeNormalMask;
2986
while (t && type != CompWindowTypeDockMask)
2988
/* dock stacking of transients for docks */
2989
if (t->type () & CompWindowTypeDockMask)
2990
type = CompWindowTypeDockMask;
2992
t = screen->findWindow (t->transientFor ());
2996
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2997
clientLeader = None;
2999
for (below = screen->serverWindows ().back (); below;
3000
below = below->serverPrev)
3002
if (below == w || avoidStackingRelativeTo (below))
3005
/* always above desktop windows */
3006
if (below->priv->type & CompWindowTypeDesktopMask)
3010
case CompWindowTypeDesktopMask:
3011
/* desktop window layer - desktop windows always should be
3012
stacked at the bottom; no other window should be below them */
3015
case CompWindowTypeFullscreenMask:
3016
case CompWindowTypeDockMask:
3017
/* fullscreen and dock layer */
3018
if (below->priv->type & (CompWindowTypeFullscreenMask |
3019
CompWindowTypeDockMask))
3021
if (!stackLayerCheck (below, clientLeader, w))
3031
bool allowedRelativeToLayer = !(below->priv->type & CompWindowTypeDockMask);
3033
t = screen->findWindow (below->transientFor ());
3035
while (t && allowedRelativeToLayer)
3037
/* dock stacking of transients for docks */
3038
allowedRelativeToLayer = !(t->priv->type & CompWindowTypeDockMask);
3040
t = screen->findWindow (t->transientFor ());
3043
/* fullscreen and normal layer */
3044
if (allowedRelativeToLayer)
3046
if (!stackLayerCheck (below, clientLeader, w))
3060
PrivateWindow::validSiblingBelow (CompWindow *w,
3061
CompWindow *sibling)
3063
CompWindow *t = screen->findWindow (w->transientFor ());
3064
Window clientLeader = w->priv->clientLeader;
3065
unsigned int type = w->priv->type;
3067
/* normal stacking fullscreen windows with below state */
3068
if ((type & CompWindowTypeFullscreenMask) &&
3069
(w->priv->state & CompWindowStateBelowMask))
3070
type = CompWindowTypeNormalMask;
3072
while (t && type != CompWindowTypeDockMask)
3074
/* dock stacking of transients for docks */
3075
if (t->type () & CompWindowTypeDockMask)
3076
type = CompWindowTypeDockMask;
3078
t = screen->findWindow (t->transientFor ());
3082
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
3083
clientLeader = None;
3085
if (sibling == w || avoidStackingRelativeTo (sibling))
3088
/* always above desktop windows */
3089
if (sibling->priv->type & CompWindowTypeDesktopMask)
3093
case CompWindowTypeDesktopMask:
3094
/* desktop window layer */
3096
case CompWindowTypeFullscreenMask:
3097
case CompWindowTypeDockMask:
3098
/* fullscreen and dock layer */
3099
if (sibling->priv->type & (CompWindowTypeFullscreenMask |
3100
CompWindowTypeDockMask))
3102
if (stackLayerCheck (w, clientLeader, sibling))
3112
bool allowedRelativeToLayer = !(sibling->priv->type & CompWindowTypeDockMask);
3114
t = screen->findWindow (sibling->transientFor ());
3116
while (t && allowedRelativeToLayer)
3118
/* dock stacking of transients for docks */
3119
allowedRelativeToLayer = !(t->priv->type & CompWindowTypeDockMask);
3121
t = screen->findWindow (t->transientFor ());
3124
/* fullscreen and normal layer */
3125
if (allowedRelativeToLayer)
3127
if (stackLayerCheck (w, clientLeader, sibling))
3138
PrivateWindow::saveGeometry (int mask)
3140
int m = mask & ~saveMask;
3142
/* only save geometry if window has been placed */
3147
saveWc.x = serverGeometry.x ();
3150
saveWc.y = serverGeometry.y ();
3153
saveWc.width = serverGeometry.width ();
3156
saveWc.height = serverGeometry.height ();
3158
if (m & CWBorderWidth)
3159
saveWc.border_width = serverGeometry.border ();
3165
PrivateWindow::restoreGeometry (XWindowChanges *xwc,
3168
int m = mask & saveMask;
3178
xwc->width = saveWc.width;
3180
/* This is not perfect but it works OK for now. If the saved width is
3181
the same as the current width then make it a little be smaller so
3182
the user can see that it changed and it also makes sure that
3183
windowResizeNotify is called and plugins are notified. */
3184
if (xwc->width == (int) serverGeometry.width ())
3194
xwc->height = saveWc.height;
3196
/* As above, if the saved height is the same as the current height
3197
then make it a little be smaller. */
3198
if (xwc->height == (int) serverGeometry.height ())
3206
if (m & CWBorderWidth)
3207
xwc->border_width = saveWc.border_width;
3214
static bool isPendingRestack (compiz::X11::PendingEvent::Ptr p)
3216
compiz::X11::PendingConfigureEvent::Ptr pc = boost::shared_static_cast <compiz::X11::PendingConfigureEvent> (p);
3218
return pc->matchVM (CWStackMode | CWSibling);
3222
PrivateWindow::reconfigureXWindow (unsigned int valueMask,
3223
XWindowChanges *xwc)
3225
unsigned int frameValueMask = valueMask;
3227
/* Immediately sync window position
3228
* if plugins were updating w->geometry () directly
3229
* in order to avoid a race condition */
3231
window->syncPosition ();
3233
/* Remove redundant bits */
3235
if (serverGeometry.x () == xwc->x)
3236
valueMask &= ~(CWX);
3238
if (serverGeometry.y () == xwc->y)
3239
valueMask &= ~(CWY);
3241
if (serverGeometry.width () == xwc->width)
3242
valueMask &= ~(CWWidth);
3244
if (serverGeometry.height () == xwc->height)
3245
valueMask &= ~(CWHeight);
3247
if (serverGeometry.border () == xwc->border_width)
3248
valueMask &= ~(CWBorderWidth);
3250
if (window->serverPrev && ROOTPARENT (window->serverPrev) == xwc->sibling)
3252
/* check if the sibling is also pending a restack,
3253
* if not, then setting this bit is useless */
3255
if (window->serverPrev->priv->pendingConfigures.forEachIf (boost::bind (isPendingRestack, _1)))
3256
valueMask &= ~(CWSibling | CWStackMode);
3259
if (valueMask & CWBorderWidth)
3260
serverGeometry.setBorder (xwc->border_width);
3262
if (valueMask & CWX)
3263
serverGeometry.setX (xwc->x);
3265
if (valueMask & CWY)
3266
serverGeometry.setY (xwc->y);
3268
if (valueMask & CWWidth)
3269
serverGeometry.setWidth (xwc->width);
3271
if (valueMask & CWHeight)
3272
serverGeometry.setHeight (xwc->height);
3274
/* Update the server side window list on raise, lower and restack functions.
3275
* This function should only recieve stack_mode == Above
3276
* but warn incase something else does get through, to make the cause
3277
* of any potential misbehaviour obvious. */
3278
if (valueMask & (CWSibling | CWStackMode))
3280
if (xwc->stack_mode == Above)
3284
screen->unhookServerWindow (window);
3285
screen->insertServerWindow (window, xwc->sibling);
3289
compLogMessage ("core", CompLogLevelWarn, "restack_mode not Above");
3292
if (serverFrameGeometry.x () == xwc->x - serverGeometry.border () - serverInput.left)
3293
frameValueMask &= ~(CWX);
3295
if (serverFrameGeometry.y () == xwc->y - serverGeometry.border () - serverInput.top)
3296
frameValueMask &= ~(CWY);
3298
if (serverFrameGeometry.width () == xwc->width + serverGeometry.border () * 2
3299
+ serverInput.left + serverInput.right)
3300
frameValueMask &= ~(CWWidth);
3302
/* shaded windows are not allowed to have their frame window
3303
* height changed (but are allowed to have their client height
3308
if (serverFrameGeometry.height () == serverGeometry.border () * 2
3309
+ serverInput.top + serverInput.bottom)
3310
frameValueMask &= ~(CWHeight);
3314
if (serverFrameGeometry.height () == xwc->height + serverGeometry.border () * 2
3315
+ serverInput.top + serverInput.bottom)
3316
frameValueMask &= ~(CWHeight);
3319
/* Can't set the border width of frame windows */
3320
frameValueMask &= ~(CWBorderWidth);
3322
if (frameValueMask & CWX)
3323
serverFrameGeometry.setX (xwc->x - serverGeometry.border () - serverInput.left);
3325
if (frameValueMask & CWY)
3326
serverFrameGeometry.setY (xwc->y -serverGeometry.border () - serverInput.top);
3328
if (frameValueMask & CWWidth)
3329
serverFrameGeometry.setWidth (xwc->width + serverGeometry.border () * 2
3330
+ serverInput.left + serverInput.right);
3334
if (frameValueMask & CWHeight)
3335
serverFrameGeometry.setHeight (serverGeometry.border () * 2
3336
+ serverInput.top + serverInput.bottom);
3340
if (frameValueMask & CWHeight)
3341
serverFrameGeometry.setHeight (xwc->height + serverGeometry.border () * 2
3342
+ serverInput.top + serverInput.bottom);
3350
XWindowChanges wc = *xwc;
3352
wc.x = serverFrameGeometry.x ();
3353
wc.y = serverFrameGeometry.y ();
3354
wc.width = serverFrameGeometry.width ();
3355
wc.height = serverFrameGeometry.height ();
3357
gettimeofday (&lastConfigureRequest, NULL);
3359
compiz::X11::PendingEvent::Ptr pc =
3360
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
3361
new compiz::X11::PendingConfigureEvent (
3362
screen->dpy (), priv->serverFrame, frameValueMask, &wc)));
3364
pendingConfigures.add (pc);
3366
XConfigureWindow (screen->dpy (), serverFrame, frameValueMask, &wc);
3368
valueMask &= ~(CWSibling | CWStackMode);
3372
xwc->x = serverInput.left;
3373
xwc->y = serverInput.top;
3374
XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc);
3380
window->sendConfigureNotify ();
3384
XConfigureWindow (screen->dpy (), id, valueMask, xwc);
3386
screen->priv->updateScreenEdges ();
3390
PrivateWindow::stackDocks (CompWindow *w,
3391
CompWindowList &updateList,
3392
XWindowChanges *xwc,
3395
CompWindow *firstFullscreenWindow = NULL;
3396
CompWindow *belowDocks = NULL;
3398
foreach (CompWindow *dw, screen->serverWindows ())
3400
/* fullscreen window found */
3401
if (firstFullscreenWindow)
3403
/* If there is another toplevel window above the fullscreen one
3404
* then we need to stack above that */
3405
if ((dw->priv->managed && !dw->priv->unmanaging) &&
3406
!(dw->priv->state & CompWindowStateHiddenMask) &&
3407
!PrivateWindow::isAncestorTo (w, dw) &&
3408
!(dw->type () & (CompWindowTypeFullscreenMask |
3409
CompWindowTypeDockMask)) &&
3410
!dw->overrideRedirect () &&
3416
else if (dw->type () & CompWindowTypeFullscreenMask)
3418
/* First fullscreen window found when checking up the stack
3419
* now go back down to find a suitable candidate client
3420
* window to put the docks above */
3421
firstFullscreenWindow = dw;
3422
for (CompWindow *dww = dw->serverPrev; dww; dww = dww->serverPrev)
3424
if ((dw->priv->managed && !dw->priv->unmanaging) &&
3425
!(dw->priv->state & CompWindowStateHiddenMask) &&
3426
!(dww->type () & (CompWindowTypeFullscreenMask |
3427
CompWindowTypeDockMask)) &&
3428
!dww->overrideRedirect () &&
3440
*mask = CWSibling | CWStackMode;
3441
xwc->sibling = ROOTPARENT (belowDocks);
3443
/* Collect all dock windows first */
3444
foreach (CompWindow *dw, screen->serverWindows ())
3445
if (dw->priv->type & CompWindowTypeDockMask)
3446
updateList.push_front (dw);
3455
PrivateWindow::stackTransients (CompWindow *w,
3457
XWindowChanges *xwc,
3458
CompWindowList &updateList)
3461
Window clientLeader = w->priv->clientLeader;
3463
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
3464
clientLeader = None;
3466
for (t = screen->serverWindows ().back (); t; t = t->serverPrev)
3468
if (t == w || t == avoid)
3471
if (t->priv->transientFor == w->priv->id ||
3472
t->priv->isGroupTransient (clientLeader))
3474
if (!stackTransients (t, avoid, xwc, updateList))
3477
if (xwc->sibling == t->priv->id ||
3478
(t->priv->serverFrame && xwc->sibling == t->priv->serverFrame))
3481
if (t->priv->mapNum || t->priv->pendingMaps)
3482
updateList.push_back (t);
3490
PrivateWindow::stackAncestors (CompWindow *w,
3491
XWindowChanges *xwc,
3492
CompWindowList &updateList)
3494
CompWindow *transient = NULL;
3496
if (w->priv->transientFor)
3497
transient = screen->findWindow (w->priv->transientFor);
3500
xwc->sibling != transient->priv->id &&
3501
(!transient->priv->serverFrame || xwc->sibling != transient->priv->serverFrame))
3503
CompWindow *ancestor;
3505
ancestor = screen->findWindow (w->priv->transientFor);
3508
if (!stackTransients (ancestor, w, xwc, updateList))
3511
if (ancestor->priv->type & CompWindowTypeDesktopMask)
3514
if (ancestor->priv->type & CompWindowTypeDockMask)
3515
if (!(w->priv->type & CompWindowTypeDockMask))
3518
if (ancestor->priv->mapNum || ancestor->priv->pendingMaps)
3519
updateList.push_back (ancestor);
3521
stackAncestors (ancestor, xwc, updateList);
3524
else if (w->priv->isGroupTransient (w->priv->clientLeader))
3528
for (a = screen->serverWindows ().back (); a; a = a->serverPrev)
3530
if (a->priv->clientLeader == w->priv->clientLeader &&
3531
a->priv->transientFor == None &&
3532
!a->priv->isGroupTransient (w->priv->clientLeader))
3534
if (xwc->sibling == a->priv->id ||
3535
(a->priv->serverFrame && xwc->sibling == a->priv->serverFrame))
3538
if (!stackTransients (a, w, xwc, updateList))
3541
if (a->priv->type & CompWindowTypeDesktopMask)
3544
if (a->priv->type & CompWindowTypeDockMask)
3545
if (!(w->priv->type & CompWindowTypeDockMask))
3548
if (a->priv->mapNum || a->priv->pendingMaps)
3549
updateList.push_back (a);
3556
CompWindow::configureXWindow (unsigned int valueMask,
3557
XWindowChanges *xwc)
3559
if (priv->managed && (valueMask & (CWSibling | CWStackMode)))
3561
CompWindowList transients;
3562
CompWindowList ancestors;
3563
CompWindowList docks;
3565
/* Since the window list is being reordered in reconfigureXWindow
3566
the list of windows which need to be restacked must be stored
3567
first. The windows are stacked in the opposite order than they
3568
were previously stacked, in order that they are above xwc->sibling
3569
so that when compiz gets the ConfigureNotify event it doesn't
3570
have to restack all the windows again. */
3572
/* transient children above */
3573
if (PrivateWindow::stackTransients (this, NULL, xwc, transients))
3575
/* ancestors, siblings and sibling transients below */
3576
PrivateWindow::stackAncestors (this, xwc, ancestors);
3578
for (CompWindowList::reverse_iterator w = ancestors.rbegin ();
3579
w != ancestors.rend (); w++)
3581
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
3582
xwc->sibling = ROOTPARENT (*w);
3585
this->priv->reconfigureXWindow (valueMask, xwc);
3586
xwc->sibling = ROOTPARENT (this);
3588
for (CompWindowList::reverse_iterator w = transients.rbegin ();
3589
w != transients.rend (); w++)
3591
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
3592
xwc->sibling = ROOTPARENT (*w);
3595
if (PrivateWindow::stackDocks (this, docks, xwc, &valueMask))
3597
Window sibling = xwc->sibling;
3598
xwc->stack_mode = Above;
3600
/* Then update the dock windows */
3601
foreach (CompWindow *dw, docks)
3603
xwc->sibling = sibling;
3604
dw->priv->reconfigureXWindow (valueMask, xwc);
3611
priv->reconfigureXWindow (valueMask, xwc);
3616
PrivateWindow::addWindowSizeChanges (XWindowChanges *xwc,
3617
CompWindow::Geometry old)
3625
screen->viewportForGeometry (old, viewport);
3627
x = (viewport.x () - screen->vp ().x ()) * screen->width ();
3628
y = (viewport.y () - screen->vp ().y ()) * screen->height ();
3630
output = screen->outputDeviceForGeometry (old);
3631
workArea = screen->getWorkareaForOutput (output);
3633
if (type & CompWindowTypeFullscreenMask)
3635
saveGeometry (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3637
if (fullscreenMonitorsSet)
3639
xwc->x = x + fullscreenMonitorRect.x ();
3640
xwc->y = y + fullscreenMonitorRect.y ();
3641
xwc->width = fullscreenMonitorRect.width ();
3642
xwc->height = fullscreenMonitorRect.height ();
3646
xwc->x = x + screen->outputDevs ()[output].x ();
3647
xwc->y = y + screen->outputDevs ()[output].y ();
3648
xwc->width = screen->outputDevs ()[output].width ();
3649
xwc->height = screen->outputDevs ()[output].height ();
3652
xwc->border_width = 0;
3654
mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
3658
mask |= restoreGeometry (xwc, CWBorderWidth);
3660
if (state & CompWindowStateMaximizedVertMask)
3662
saveGeometry (CWY | CWHeight);
3664
xwc->height = workArea.height () - serverInput.top -
3665
serverInput.bottom - old.border () * 2;
3671
mask |= restoreGeometry (xwc, CWY | CWHeight);
3674
if (state & CompWindowStateMaximizedHorzMask)
3676
saveGeometry (CWX | CWWidth);
3678
xwc->width = workArea.width () - serverInput.left -
3679
serverInput.right - old.border () * 2;
3685
mask |= restoreGeometry (xwc, CWX | CWWidth);
3688
/* constrain window width if smaller than minimum width */
3689
if (!(mask & CWWidth) && (int) old.width () < sizeHints.min_width)
3691
xwc->width = sizeHints.min_width;
3695
/* constrain window width if greater than maximum width */
3696
if (!(mask & CWWidth) && (int) old.width () > sizeHints.max_width)
3698
xwc->width = sizeHints.max_width;
3702
/* constrain window height if smaller than minimum height */
3703
if (!(mask & CWHeight) && (int) old.height () < sizeHints.min_height)
3705
xwc->height = sizeHints.min_height;
3709
/* constrain window height if greater than maximum height */
3710
if (!(mask & CWHeight) && (int) old.height () > sizeHints.max_height)
3712
xwc->height = sizeHints.max_height;
3716
if (mask & (CWWidth | CWHeight))
3718
int width, height, max;
3720
width = (mask & CWWidth) ? xwc->width : old.width ();
3721
height = (mask & CWHeight) ? xwc->height : old.height ();
3723
xwc->width = old.width ();
3724
xwc->height = old.height ();
3726
window->constrainNewWindowSize (width, height, &width, &height);
3728
if (width != (int) old.width ())
3736
if (height != (int) old.height ())
3739
xwc->height = height;
3744
if (state & CompWindowStateMaximizedVertMask)
3746
if (old.y () < y + workArea.y () + serverInput.top)
3748
xwc->y = y + workArea.y () + serverInput.top;
3753
height = xwc->height + old.border () * 2;
3755
max = y + workArea.bottom ();
3756
if (old.y () + (int) old.height () + serverInput.bottom > max)
3758
xwc->y = max - height - serverInput.bottom;
3761
else if (old.y () + height + serverInput.bottom > max)
3763
xwc->y = y + workArea.y () +
3764
(workArea.height () - serverInput.top - height -
3765
serverInput.bottom) / 2 + serverInput.top;
3771
if (state & CompWindowStateMaximizedHorzMask)
3773
if (old.x () < x + workArea.x () + serverInput.left)
3775
xwc->x = x + workArea.x () + serverInput.left;
3780
width = xwc->width + old.border () * 2;
3782
max = x + workArea.right ();
3783
if (old.x () + (int) old.width () + serverInput.right > max)
3785
xwc->x = max - width - serverInput.right;
3788
else if (old.x () + width + serverInput.right > max)
3790
xwc->x = x + workArea.x () +
3791
(workArea.width () - serverInput.left - width -
3792
serverInput.right) / 2 + serverInput.left;
3800
if ((mask & CWX) && (xwc->x == old.x ()))
3803
if ((mask & CWY) && (xwc->y == old.y ()))
3806
if ((mask & CWWidth) && (xwc->width == (int) old.width ()))
3809
if ((mask & CWHeight) && (xwc->height == (int) old.height ()))
3816
PrivateWindow::adjustConfigureRequestForGravity (XWindowChanges *xwc,
3822
unsigned int mask = 0;
3827
if (xwcm & (CWX | CWWidth))
3830
case NorthWestGravity:
3832
case SouthWestGravity:
3834
newX += priv->border.left * direction;
3841
newX -= (xwc->width / 2 - priv->border.left +
3842
(priv->border.left + priv->border.right) / 2) * direction;
3844
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
3847
case NorthEastGravity:
3849
case SouthEastGravity:
3851
newX -= xwc->width + priv->border.right * direction;
3853
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
3862
if (xwcm & (CWY | CWHeight))
3865
case NorthWestGravity:
3867
case NorthEastGravity:
3869
newY = xwc->y + priv->serverInput.top * direction;
3876
newY -= (xwc->height / 2 - priv->serverInput.top +
3877
(priv->serverInput.top + priv->serverInput.bottom) / 2) * direction;
3879
newY -= ((xwc->height - priv->serverGeometry.height ()) / 2) * direction;
3882
case SouthWestGravity:
3884
case SouthEastGravity:
3886
newY -= xwc->height + priv->serverInput.bottom * direction;
3888
newY -= (xwc->height - priv->serverGeometry.height ()) * direction;
3899
xwc->x += (newX - xwc->x);
3905
xwc->y += (newY - xwc->y);
3913
CompWindow::moveResize (XWindowChanges *xwc,
3916
unsigned int source)
3918
bool placed = false;
3920
xwcm &= (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3922
if (xwcm & (CWX | CWY))
3923
if (priv->sizeHints.flags & (USPosition | PPosition))
3927
gravity = priv->sizeHints.win_gravity;
3930
xwc->x = priv->serverGeometry.x ();
3932
xwc->y = priv->serverGeometry.y ();
3933
if (!(xwcm & CWWidth))
3934
xwc->width = priv->serverGeometry.width ();
3935
if (!(xwcm & CWHeight))
3936
xwc->height = priv->serverGeometry.height ();
3938
if (xwcm & (CWWidth | CWHeight))
3942
if (constrainNewWindowSize (xwc->width, xwc->height, &width, &height))
3944
if (width != xwc->width)
3947
if (height != xwc->height)
3951
xwc->height = height;
3955
xwcm |= priv->adjustConfigureRequestForGravity (xwc, xwcm, gravity, 1);
3957
validateResizeRequest (xwcm, xwc, source);
3959
/* when horizontally maximized only allow width changes added by
3960
addWindowSizeChanges */
3961
if (priv->state & CompWindowStateMaximizedHorzMask)
3964
/* when vertically maximized only allow height changes added by
3965
addWindowSizeChanges */
3966
if (priv->state & CompWindowStateMaximizedVertMask)
3969
xwcm |= priv->addWindowSizeChanges (xwc, Geometry (xwc->x, xwc->y,
3970
xwc->width, xwc->height,
3971
xwc->border_width));
3973
/* check if the new coordinates are useful and valid (different
3974
to current size); if not, we have to clear them to make sure
3975
we send a synthetic ConfigureNotify event if all coordinates
3976
match the server coordinates */
3977
if (xwc->x == priv->serverGeometry.x ())
3980
if (xwc->y == priv->serverGeometry.y ())
3983
if (xwc->width == (int) priv->serverGeometry.width ())
3986
if (xwc->height == (int) priv->serverGeometry.height ())
3989
if (xwc->border_width == (int) priv->serverGeometry.border ())
3990
xwcm &= ~CWBorderWidth;
3992
/* update saved window coordinates - if CWX or CWY is set for fullscreen
3993
or maximized windows after addWindowSizeChanges, it should be pretty
3994
safe to assume that the saved coordinates should be updated too, e.g.
3995
because the window was moved to another viewport by some client */
3996
if ((xwcm & CWX) && (priv->saveMask & CWX))
3997
priv->saveWc.x += (xwc->x - priv->serverGeometry.x ());
3999
if ((xwcm & CWY) && (priv->saveMask & CWY))
4000
priv->saveWc.y += (xwc->y - priv->serverGeometry.y ());
4002
if (priv->mapNum && (xwcm & (CWWidth | CWHeight)))
4006
configureXWindow (xwcm, xwc);
4009
/* we have to send a configure notify on ConfigureRequest events if
4010
we decide not to do anything according to ICCCM 4.1.5 */
4011
sendConfigureNotify ();
4015
priv->placed = true;
4019
PrivateWindow::updateSize ()
4024
if (window->overrideRedirect () || !managed)
4027
mask = priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
4030
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
4031
window->sendSyncRequest ();
4033
window->configureXWindow (mask, &xwc);
4038
PrivateWindow::addWindowStackChanges (XWindowChanges *xwc,
4039
CompWindow *sibling)
4043
if (!sibling || sibling->priv->id != id)
4045
/* Alow requests to go on top of serverPrev
4046
* if serverPrev was recently restacked */
4047
if (window->serverPrev)
4051
XWindowChanges lxwc;
4052
unsigned int valueMask = CWStackMode;
4054
lxwc.stack_mode = Below;
4058
gettimeofday (&lastConfigureRequest, NULL);
4059
compiz::X11::PendingEvent::Ptr pc =
4060
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
4061
new compiz::X11::PendingConfigureEvent (
4062
screen->dpy (), serverFrame, valueMask, &lxwc)));
4064
pendingConfigures.add (pc);
4067
/* Below with no sibling puts the window at the bottom
4069
XConfigureWindow (screen->dpy (), ROOTPARENT (window), valueMask, &lxwc);
4071
/* Update the list of windows last sent to the server */
4072
screen->unhookServerWindow (window);
4073
screen->insertServerWindow (window, 0);
4077
if (sibling->priv->id != window->serverPrev->priv->id ||
4078
window->serverPrev->priv->pendingConfigures.forEachIf (boost::bind (isPendingRestack, _1)))
4080
mask |= CWSibling | CWStackMode;
4082
xwc->stack_mode = Above;
4083
xwc->sibling = ROOTPARENT (sibling);
4089
mask |= CWSibling | CWStackMode;
4091
xwc->stack_mode = Above;
4092
xwc->sibling = ROOTPARENT (sibling);
4100
CompWindow::raise ()
4104
bool aboveFs = false;
4106
/* an active fullscreen window should be raised over all other
4107
windows in its layer */
4108
if (priv->type & CompWindowTypeFullscreenMask)
4109
if (priv->id == screen->activeWindow ())
4112
for (CompWindow *pw = serverPrev; pw; pw = pw->serverPrev)
4114
if (pw->priv->type & CompWindowTypeFullscreenMask)
4116
if (priv->id == screen->activeWindow ())
4123
mask = priv->addWindowStackChanges (&xwc,
4124
PrivateWindow::findSiblingBelow (this, aboveFs));
4127
configureXWindow (mask, &xwc);
4131
PrivateScreen::focusTopMostWindow ()
4133
CompWindow *focus = NULL;
4134
CompWindowList::reverse_iterator it = serverWindows.rbegin ();
4136
for (; it != serverWindows.rend (); it++)
4138
CompWindow *w = *it;
4140
if (w->type () & CompWindowTypeDockMask)
4152
if (focus->id () != activeWindow)
4153
focus->moveInputFocusTo ();
4156
XSetInputFocus (dpy, root, RevertToPointerRoot,
4163
CompWindow::lower ()
4168
mask = priv->addWindowStackChanges (&xwc,
4169
PrivateWindow::findLowestSiblingBelow (this));
4171
configureXWindow (mask, &xwc);
4173
/* when lowering a window, focus the topmost window if
4174
the click-to-focus option is on */
4175
if ((screen->priv->optionGetClickToFocus ()))
4177
CompWindow *focusedWindow = screen->priv->focusTopMostWindow ();
4179
/* if the newly focused window is a desktop window,
4180
give the focus back to w */
4181
if (focusedWindow &&
4182
focusedWindow->type () & CompWindowTypeDesktopMask)
4184
moveInputFocusTo ();
4190
CompWindow::restackAbove (CompWindow *sibling)
4192
for (; sibling; sibling = sibling->serverNext)
4193
if (PrivateWindow::validSiblingBelow (this, sibling))
4201
mask = priv->addWindowStackChanges (&xwc, sibling);
4203
configureXWindow (mask, &xwc);
4207
/* finds the highest window under sibling we can stack above */
4209
PrivateWindow::findValidStackSiblingBelow (CompWindow *w,
4210
CompWindow *sibling)
4212
CompWindow *lowest, *last, *p;
4214
/* check whether we're allowed to stack under a sibling by finding
4215
* the above 'sibling' and checking whether or not we're allowed
4216
* to stack under that - if not, then there is no valid sibling
4219
for (p = sibling; p; p = p->serverNext)
4221
if (!avoidStackingRelativeTo (p))
4223
if (!validSiblingBelow (p, w))
4229
/* get lowest sibling we're allowed to stack above */
4230
lowest = last = findLowestSiblingBelow (w);
4232
/* walk from bottom up */
4233
for (p = screen->serverWindows ().front (); p; p = p->serverNext)
4235
/* stop walking when we reach the sibling we should try to stack
4240
/* skip windows that we should avoid */
4241
if (w == p || avoidStackingRelativeTo (p))
4244
if (validSiblingBelow (w, p))
4246
/* update lowest as we find windows below sibling that we're
4247
allowed to stack above. last window must be equal to the
4248
lowest as we shouldn't update lowest if we passed an
4254
/* update last pointer */
4262
CompWindow::restackBelow (CompWindow *sibling)
4267
mask = priv->addWindowStackChanges (&xwc,
4268
PrivateWindow::findValidStackSiblingBelow (this, sibling));
4271
configureXWindow (mask, &xwc);
4275
CompWindow::updateAttributes (CompStackingUpdateMode stackingMode)
4280
if (overrideRedirect () || !priv->managed)
4283
if (priv->state & CompWindowStateShadedMask && !priv->shaded)
4285
windowNotify (CompWindowNotifyShade);
4289
else if (priv->shaded)
4291
windowNotify (CompWindowNotifyUnshade);
4296
if (stackingMode != CompStackingUpdateModeNone)
4299
CompWindow *sibling;
4301
aboveFs = (stackingMode == CompStackingUpdateModeAboveFullscreen);
4302
if (priv->type & CompWindowTypeFullscreenMask)
4304
/* put active or soon-to-be-active fullscreen windows over
4305
all others in their layer */
4306
if (priv->id == screen->activeWindow () ||
4307
priv->id == screen->priv->nextActiveWindow)
4313
/* put windows that are just mapped, over fullscreen windows */
4314
if (stackingMode == CompStackingUpdateModeInitialMap)
4317
sibling = PrivateWindow::findSiblingBelow (this, aboveFs);
4320
(stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
4324
for (p = sibling; p; p = p->serverPrev)
4325
if (p->priv->id == screen->activeWindow ())
4328
/* window is above active window so we should lower it,
4329
* assuing that is allowed (if, for example, our window has
4330
* the "above" state, then lowering beneath the active
4331
* window may not be allowed). */
4332
if (p && PrivateWindow::validSiblingBelow (p, this))
4334
p = PrivateWindow::findValidStackSiblingBelow (this, p);
4336
/* if we found a valid sibling under the active window, it's
4337
our new sibling we want to stack above */
4344
mask |= priv->addWindowStackChanges (&xwc, sibling);
4347
mask |= priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
4349
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
4353
configureXWindow (mask, &xwc);
4357
PrivateWindow::ensureWindowVisibility ()
4360
int width = serverGeometry.width () + serverGeometry.border () * 2;
4361
int height = serverGeometry.height () + serverGeometry.border () * 2;
4365
if (struts || attrib.override_redirect)
4368
if (type & (CompWindowTypeDockMask |
4369
CompWindowTypeFullscreenMask |
4370
CompWindowTypeUnknownMask))
4373
x1 = screen->workArea ().x () - screen->width () * screen->vp ().x ();
4374
y1 = screen->workArea ().y () - screen->height () * screen->vp ().y ();
4375
x2 = x1 + screen->workArea ().width () + screen->vpSize ().width () *
4377
y2 = y1 + screen->workArea ().height () + screen->vpSize ().height () *
4380
if (serverGeometry.x () - serverInput.left >= x2)
4381
dx = (x2 - 25) - serverGeometry.x ();
4382
else if (serverGeometry.x () + width + serverInput.right <= x1)
4383
dx = (x1 + 25) - (serverGeometry.x () + width);
4385
if (serverGeometry.y () - serverInput.top >= y2)
4386
dy = (y2 - 25) - serverGeometry.y ();
4387
else if (serverGeometry.y () + height + serverInput.bottom <= y1)
4388
dy = (y1 + 25) - (serverGeometry.y () + height);
4394
xwc.x = serverGeometry.x () + dx;
4395
xwc.y = serverGeometry.y () + dy;
4397
window->configureXWindow (CWX | CWY, &xwc);
4402
PrivateWindow::reveal ()
4404
if (window->minimized ())
4405
window->unminimize ();
4407
screen->leaveShowDesktopMode (window);
4411
PrivateWindow::revealAncestors (CompWindow *w,
4412
CompWindow *transient)
4414
if (isAncestorTo (transient, w))
4416
screen->forEachWindow (boost::bind (revealAncestors, _1, w));
4422
CompWindow::activate ()
4424
WRAPABLE_HND_FUNC (3, activate)
4426
screen->priv->setCurrentDesktop (priv->desktop);
4428
screen->forEachWindow (
4429
boost::bind (PrivateWindow::revealAncestors, _1, this));
4432
if (priv->state & CompWindowStateHiddenMask)
4434
priv->state &= ~CompWindowStateShadedMask;
4439
if (priv->state & CompWindowStateHiddenMask)
4442
if (!onCurrentDesktop ())
4445
priv->ensureWindowVisibility ();
4446
updateAttributes (CompStackingUpdateModeAboveFullscreen);
4447
moveInputFocusTo ();
4451
#define PVertResizeInc (1 << 0)
4452
#define PHorzResizeInc (1 << 1)
4455
CompWindow::constrainNewWindowSize (int width,
4460
const XSizeHints *hints = &priv->sizeHints;
4461
int oldWidth = width;
4462
int oldHeight = height;
4466
int base_height = 0;
4469
int max_width = MAXSHORT;
4470
int max_height = MAXSHORT;
4471
long flags = hints->flags;
4472
long resizeIncFlags = (flags & PResizeInc) ? ~0 : 0;
4474
if (screen->priv->optionGetIgnoreHintsWhenMaximized ())
4476
if (priv->state & MAXIMIZE_STATE)
4480
if (priv->state & CompWindowStateMaximizedHorzMask)
4481
resizeIncFlags &= ~PHorzResizeInc;
4483
if (priv->state & CompWindowStateMaximizedVertMask)
4484
resizeIncFlags &= ~PVertResizeInc;
4488
/* Ater gdk_window_constrain_size(), which is partially borrowed from fvwm.
4490
* Copyright 1993, Robert Nation
4491
* You may use this code for any purpose, as long as the original
4492
* copyright remains in the source code and all documentation
4494
* which in turn borrows parts of the algorithm from uwm
4497
#define FLOOR(value, base) (((int) ((value) / (base))) * (base))
4498
#define FLOOR64(value, base) (((uint64_t) ((value) / (base))) * (base))
4500
if ((flags & PBaseSize) && (flags & PMinSize))
4502
base_width = hints->base_width;
4503
base_height = hints->base_height;
4504
min_width = hints->min_width;
4505
min_height = hints->min_height;
4507
else if (flags & PBaseSize)
4509
base_width = hints->base_width;
4510
base_height = hints->base_height;
4511
min_width = hints->base_width;
4512
min_height = hints->base_height;
4514
else if (flags & PMinSize)
4516
base_width = hints->min_width;
4517
base_height = hints->min_height;
4518
min_width = hints->min_width;
4519
min_height = hints->min_height;
4522
if (flags & PMaxSize)
4524
max_width = hints->max_width;
4525
max_height = hints->max_height;
4528
if (resizeIncFlags & PHorzResizeInc)
4529
xinc = MAX (xinc, hints->width_inc);
4531
if (resizeIncFlags & PVertResizeInc)
4532
yinc = MAX (yinc, hints->height_inc);
4534
/* clamp width and height to min and max values */
4535
width = CLAMP (width, min_width, max_width);
4536
height = CLAMP (height, min_height, max_height);
4538
/* shrink to base + N * inc */
4539
width = base_width + FLOOR (width - base_width, xinc);
4540
height = base_height + FLOOR (height - base_height, yinc);
4542
/* constrain aspect ratio, according to:
4544
* min_aspect.x width max_aspect.x
4545
* ------------ <= -------- <= -----------
4546
* min_aspect.y height max_aspect.y
4548
if ((flags & PAspect) && hints->min_aspect.y > 0 && hints->max_aspect.x > 0)
4550
/* Use 64 bit arithmetic to prevent overflow */
4552
uint64_t min_aspect_x = hints->min_aspect.x;
4553
uint64_t min_aspect_y = hints->min_aspect.y;
4554
uint64_t max_aspect_x = hints->max_aspect.x;
4555
uint64_t max_aspect_y = hints->max_aspect.y;
4558
if (min_aspect_x * height > width * min_aspect_y)
4560
delta = FLOOR64 (height - width * min_aspect_y / min_aspect_x,
4562
if (height - (int) delta >= min_height)
4566
delta = FLOOR64 (height * min_aspect_x / min_aspect_y - width,
4568
if (width + (int) delta <= max_width)
4573
if (width * max_aspect_y > max_aspect_x * height)
4575
delta = FLOOR64 (width - height * max_aspect_x / max_aspect_y,
4577
if (width - (int) delta >= min_width)
4581
delta = FLOOR64 (width * min_aspect_y / min_aspect_x - height,
4583
if (height + (int) delta <= max_height)
4593
if (width != oldWidth || height != oldHeight)
4596
*newHeight = height;
4607
priv->hidden = true;
4614
priv->hidden = false;
4619
PrivateWindow::hide ()
4621
bool onDesktop = window->onCurrentDesktop ();
4626
if (!window->minimized () && !inShowDesktopMode &&
4627
!hidden && onDesktop)
4629
if (state & CompWindowStateShadedMask)
4642
if ((state & CompWindowStateShadedMask) && serverFrame)
4643
XUnmapWindow (screen->dpy (), serverFrame);
4646
if (!pendingMaps && !window->isViewable ())
4649
window->windowNotify (CompWindowNotifyHide);
4653
if (serverFrame && !shaded)
4654
XUnmapWindow (screen->dpy (), serverFrame);
4656
XUnmapWindow (screen->dpy (), id);
4658
if (window->minimized () || inShowDesktopMode || hidden || shaded)
4659
window->changeState (state | CompWindowStateHiddenMask);
4661
if (shaded && id == screen->activeWindow ())
4662
window->moveInputFocusTo ();
4666
PrivateWindow::show ()
4668
bool onDesktop = window->onCurrentDesktop ();
4673
if (minimized || inShowDesktopMode ||
4674
hidden || !onDesktop)
4676
/* no longer hidden but not on current desktop */
4677
if (!minimized && !inShowDesktopMode && !hidden)
4678
window->changeState (state & ~CompWindowStateHiddenMask);
4683
/* transition from minimized to shaded */
4684
if (state & CompWindowStateShadedMask)
4689
XMapWindow (screen->dpy (), serverFrame);
4691
updateFrameWindow ();
4696
window->windowNotify (CompWindowNotifyShow);
4702
XMapWindow (screen->dpy (), serverFrame);
4703
XMapWindow (screen->dpy (), wrapper);
4706
XMapWindow (screen->dpy (), id);
4708
window->changeState (state & ~CompWindowStateHiddenMask);
4709
screen->priv->setWindowState (state, id);
4713
PrivateWindow::minimizeTransients (CompWindow *w,
4714
CompWindow *ancestor)
4716
if (w->priv->transientFor == ancestor->priv->id ||
4717
w->priv->isGroupTransient (ancestor->priv->clientLeader))
4724
CompWindow::minimize ()
4726
WRAPABLE_HND_FUNC (13, minimize);
4731
if (!priv->minimized)
4733
windowNotify (CompWindowNotifyMinimize);
4735
priv->minimized = true;
4737
screen->forEachWindow (
4738
boost::bind (PrivateWindow::minimizeTransients, _1, this));
4745
PrivateWindow::unminimizeTransients (CompWindow *w,
4746
CompWindow *ancestor)
4748
if (w->priv->transientFor == ancestor->priv->id ||
4749
w->priv->isGroupTransient (ancestor->priv->clientLeader))
4754
CompWindow::unminimize ()
4756
WRAPABLE_HND_FUNC (14, unminimize);
4757
if (priv->minimized)
4759
windowNotify (CompWindowNotifyUnminimize);
4761
priv->minimized = false;
4765
screen->forEachWindow (
4766
boost::bind (PrivateWindow::unminimizeTransients, _1, this));
4771
CompWindow::maximize (unsigned int state)
4773
if (overrideRedirect ())
4776
state = constrainWindowState (state, priv->actions);
4778
state &= MAXIMIZE_STATE;
4780
if (state == (priv->state & MAXIMIZE_STATE))
4783
state |= (priv->state & ~MAXIMIZE_STATE);
4785
changeState (state);
4786
updateAttributes (CompStackingUpdateModeNone);
4790
PrivateWindow::getUserTime (Time& time)
4794
unsigned long n, left;
4795
unsigned char *data;
4796
bool retval = false;
4798
result = XGetWindowProperty (screen->dpy (), priv->id,
4800
0L, 1L, False, XA_CARDINAL, &actual, &format,
4803
if (result == Success && data)
4809
memcpy (&value, data, sizeof (CARD32));
4811
time = (Time) value;
4814
XFree ((void *) data);
4821
PrivateWindow::setUserTime (Time time)
4823
CARD32 value = (CARD32) time;
4825
XChangeProperty (screen->dpy (), priv->id,
4827
XA_CARDINAL, 32, PropModeReplace,
4828
(unsigned char *) &value, 1);
4832
* Macros from metacity
4834
* Xserver time can wraparound, thus comparing two timestamps needs to
4835
* take this into account. Here's a little macro to help out. If no
4836
* wraparound has occurred, this is equivalent to
4838
* Of course, the rest of the ugliness of this macro comes from
4839
* accounting for the fact that wraparound can occur and the fact that
4840
* a timestamp of 0 must be special-cased since it means older than
4843
* Note that this is NOT an equivalent for time1 <= time2; if that's
4844
* what you need then you'll need to swap the order of the arguments
4845
* and negate the result.
4847
#define XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) \
4848
( (( (time1) < (time2) ) && \
4849
( (time2) - (time1) < ((unsigned long) -1) / 2 )) || \
4850
(( (time1) > (time2) ) && \
4851
( (time1) - (time2) > ((unsigned long) -1) / 2 )) \
4853
#define XSERVER_TIME_IS_BEFORE(time1, time2) \
4855
(XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS (time1, time2) && \
4860
PrivateWindow::getUsageTimestamp (Time& timestamp)
4862
if (getUserTime (timestamp))
4865
if (initialTimestampSet)
4867
timestamp = initialTimestamp;
4875
PrivateWindow::isWindowFocusAllowed (Time timestamp)
4877
CompScreen *s = screen;
4879
Time wUserTime, aUserTime;
4880
bool gotTimestamp = false;
4884
level = s->priv->optionGetFocusPreventionLevel ();
4886
if (level == CoreOptions::FocusPreventionLevelOff)
4891
/* the caller passed a timestamp, so use that
4892
instead of the window's user time */
4893
wUserTime = timestamp;
4894
gotTimestamp = true;
4898
gotTimestamp = getUsageTimestamp (wUserTime);
4901
/* if we got no timestamp for the window, try to get at least a timestamp
4902
for its transient parent, if any */
4903
if (!gotTimestamp && transientFor)
4907
parent = screen->findWindow (transientFor);
4909
gotTimestamp = parent->priv->getUsageTimestamp (wUserTime);
4912
if (gotTimestamp && !wUserTime)
4914
/* window explicitly requested no focus */
4918
/* allow focus for excluded windows */
4919
CompMatch &match = s->priv->optionGetFocusPreventionMatch ();
4920
if (!match.evaluate (window))
4923
if (level == CoreOptions::FocusPreventionLevelVeryHigh)
4926
active = s->findWindow (s->activeWindow ());
4928
/* no active window */
4929
if (!active || (active->type () & CompWindowTypeDesktopMask))
4932
/* active window belongs to same application */
4933
if (window->clientLeader () == active->clientLeader ())
4936
if (level == CoreOptions::FocusPreventionLevelHigh)
4939
/* not in current viewport or desktop */
4940
if (!window->onCurrentDesktop ())
4943
dvp = window->defaultViewport ();
4944
if (dvp.x () != s->vp ().x () || dvp.y () != s->vp ().y ())
4949
/* unsure as we have nothing to compare - allow focus in low level,
4950
don't allow in normal level */
4951
if (level == CoreOptions::FocusPreventionLevelNormal)
4957
/* can't get user time for active window */
4958
if (!active->priv->getUserTime (aUserTime))
4961
if (XSERVER_TIME_IS_BEFORE (wUserTime, aUserTime))
4968
PrivateWindow::allowWindowFocus (unsigned int noFocusMask,
4973
if (priv->id == screen->activeWindow ())
4976
/* do not focus windows of these types */
4977
if (priv->type & noFocusMask)
4980
/* window doesn't take focus */
4981
if (!priv->inputHint &&
4982
!(priv->protocols & CompWindowProtocolTakeFocusMask))
4987
retval = priv->isWindowFocusAllowed (timestamp);
4990
/* add demands attention state if focus was prevented */
4991
window->changeState (priv->state | CompWindowStateDemandsAttentionMask);
4998
CompWindow::defaultViewport ()
5002
if (priv->serverGeometry.x () < (int) screen->width () &&
5003
priv->serverGeometry.x () + priv->serverGeometry.width () > 0 &&
5004
priv->serverGeometry.y () < (int) screen->height () &&
5005
priv->serverGeometry.y ()+ priv->serverGeometry.height () > 0)
5007
return screen->vp ();
5010
screen->viewportForGeometry (priv->serverGeometry, viewport);
5016
CompWindow::initialViewport () const
5018
return priv->initialViewport;
5022
PrivateWindow::readIconHint ()
5024
XImage *image, *maskImage = NULL;
5025
Display *dpy = screen->dpy ();
5026
unsigned int width, height, dummy;
5027
unsigned int i, j, k;
5034
if (!XGetGeometry (dpy, hints->icon_pixmap, &wDummy, &iDummy,
5035
&iDummy, &width, &height, &dummy, &dummy))
5038
image = XGetImage (dpy, hints->icon_pixmap, 0, 0, width, height,
5039
AllPlanes, ZPixmap);
5043
colors = new XColor[width * height];
5046
XDestroyImage (image);
5051
for (j = 0; j < height; j++)
5052
for (i = 0; i < width; i++)
5053
colors[k++].pixel = XGetPixel (image, i, j);
5055
for (i = 0; i < k; i += 256)
5056
XQueryColors (dpy, screen->priv->colormap,
5057
&colors[i], MIN (k - i, 256));
5059
XDestroyImage (image);
5061
icon = new CompIcon (screen, width, height);
5068
if (hints->flags & IconMaskHint)
5069
maskImage = XGetImage (dpy, hints->icon_mask, 0, 0,
5070
width, height, AllPlanes, ZPixmap);
5073
p = (CARD32 *) icon->data ();
5075
for (j = 0; j < height; j++)
5077
for (i = 0; i < width; i++)
5079
if (maskImage && !XGetPixel (maskImage, i, j))
5081
else if (image->depth == 1) /* white : black */
5082
*p++ = colors[k].pixel ? 0xffffffff : 0xff000000;
5084
*p++ = 0xff000000 | /* alpha */
5085
(((colors[k].red >> 8) & 0xff) << 16) | /* red */
5086
(((colors[k].green >> 8) & 0xff) << 8) | /* green */
5087
((colors[k].blue >> 8) & 0xff); /* blue */
5095
XDestroyImage (maskImage);
5097
icons.push_back (icon);
5100
/* returns icon with dimensions as close as possible to width and height
5101
but never greater. */
5103
CompWindow::getIcon (int width,
5107
int wh, diff, oldDiff;
5110
/* need to fetch icon property */
5111
if (priv->icons.size () == 0 && !priv->noIcons)
5115
unsigned long n, left;
5116
unsigned char *data;
5118
result = XGetWindowProperty (screen->dpy (), priv->id, Atoms::wmIcon,
5119
0L, 65536L, false, XA_CARDINAL,
5120
&actual, &format, &n, &left, &data);
5122
if (result == Success && data)
5125
CARD32 alpha, red, green, blue;
5126
unsigned long iw, ih;
5128
for (i = 0; i + 2 < n; i += iw * ih + 2)
5130
unsigned long *idata = (unsigned long *) data;
5135
/* iw * ih may be larger than the value range of unsigned
5136
* long, so better do some checking for extremely weird
5137
* icon sizes first */
5138
if (iw > 2048 || ih > 2048 || iw * ih + 2 > n - i)
5144
icon = new CompIcon (screen, iw, ih);
5148
priv->icons.push_back (icon);
5150
p = (CARD32 *) (icon->data ());
5152
/* EWMH doesn't say if icon data is premultiplied or
5153
not but most applications seem to assume data should
5154
be unpremultiplied. */
5155
for (j = 0; j < iw * ih; j++)
5157
alpha = (idata[i + j + 2] >> 24) & 0xff;
5158
red = (idata[i + j + 2] >> 16) & 0xff;
5159
green = (idata[i + j + 2] >> 8) & 0xff;
5160
blue = (idata[i + j + 2] >> 0) & 0xff;
5162
red = (red * alpha) >> 8;
5163
green = (green * alpha) >> 8;
5164
blue = (blue * alpha) >> 8;
5177
else if (priv->hints && (priv->hints->flags & IconPixmapHint))
5179
priv->readIconHint ();
5182
/* don't fetch property again */
5183
if (priv->icons.size () == 0)
5184
priv->noIcons = true;
5187
/* no icons available for this window */
5192
wh = width + height;
5194
for (i = 0; i < priv->icons.size (); i++)
5196
const CompSize iconSize = *priv->icons[i];
5198
if ((int) iconSize.width () > width ||
5199
(int) iconSize.height () > height)
5204
diff = wh - (iconSize.width () + iconSize.height ());
5205
oldDiff = wh - (icon->width () + icon->height ());
5208
icon = priv->icons[i];
5211
icon = priv->icons[i];
5218
CompWindow::iconGeometry () const
5220
return priv->iconGeometry;
5224
PrivateWindow::freeIcons ()
5226
for (unsigned int i = 0; i < priv->icons.size (); i++)
5227
delete priv->icons[i];
5229
priv->icons.resize (0);
5230
priv->noIcons = false;
5234
CompWindow::outputDevice ()
5236
return screen->outputDeviceForGeometry (priv->serverGeometry);
5240
CompWindow::onCurrentDesktop ()
5242
if (priv->desktop == 0xffffffff ||
5243
priv->desktop == screen->currentDesktop ())
5252
CompWindow::setDesktop (unsigned int desktop)
5254
if (desktop != 0xffffffff)
5256
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5259
if (desktop >= screen->nDesktop ())
5263
if (desktop == priv->desktop)
5266
priv->desktop = desktop;
5268
if (desktop == 0xffffffff || desktop == screen->currentDesktop ())
5273
screen->setWindowProp (priv->id, Atoms::winDesktop, priv->desktop);
5276
/* The compareWindowActiveness function compares the two windows 'w1'
5277
and 'w2'. It returns an integer less than, equal to, or greater
5278
than zero if 'w1' is found, respectively, to activated longer time
5279
ago than, to be activated at the same time, or be activated more
5280
recently than 'w2'. */
5282
PrivateWindow::compareWindowActiveness (CompWindow *w1,
5285
CompActiveWindowHistory *history = screen->currentHistory ();
5288
/* check current window history first */
5289
for (i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
5291
if (history->id[i] == w1->priv->id)
5294
if (history->id[i] == w2->priv->id)
5297
if (!history->id[i])
5301
return w1->priv->activeNum - w2->priv->activeNum;
5305
CompWindow::onAllViewports ()
5307
if (overrideRedirect ())
5310
if (!priv->managed && !isViewable ())
5313
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5316
if (priv->state & CompWindowStateStickyMask)
5323
CompWindow::getMovementForOffset (CompPoint offset)
5325
CompScreen *s = screen;
5326
int m, vWidth, vHeight;
5327
int offX = offset.x (), offY = offset.y ();
5330
vWidth = s->width () * s->vpSize ().width ();
5331
vHeight = s->height () * s->vpSize ().height ();
5337
if (s->vpSize ().width () == 1)
5343
m = priv->geometry.x () + offX;
5344
if (m - priv->input.left < (int) s->width () - vWidth)
5345
rv.setX (offX + vWidth);
5346
else if (m + priv->width + priv->input.right > vWidth)
5347
rv.setX (offX - vWidth);
5352
if (s->vpSize ().height () == 1)
5358
m = priv->geometry.y () + offY;
5359
if (m - priv->input.top < (int) s->height () - vHeight)
5360
rv.setY (offY + vHeight);
5361
else if (m + priv->height + priv->input.bottom > vHeight)
5362
rv.setY (offY - vHeight);
5371
WindowInterface::getOutputExtents (CompWindowExtents& output)
5372
WRAPABLE_DEF (getOutputExtents, output)
5375
WindowInterface::getAllowedActions (unsigned int &setActions,
5376
unsigned int &clearActions)
5377
WRAPABLE_DEF (getAllowedActions, setActions, clearActions)
5380
WindowInterface::focus ()
5381
WRAPABLE_DEF (focus)
5384
WindowInterface::activate ()
5385
WRAPABLE_DEF (activate)
5388
WindowInterface::place (CompPoint &pos)
5389
WRAPABLE_DEF (place, pos)
5392
WindowInterface::validateResizeRequest (unsigned int &mask,
5393
XWindowChanges *xwc,
5394
unsigned int source)
5395
WRAPABLE_DEF (validateResizeRequest, mask, xwc, source)
5398
WindowInterface::resizeNotify (int dx,
5402
WRAPABLE_DEF (resizeNotify, dx, dy, dwidth, dheight)
5405
WindowInterface::moveNotify (int dx,
5408
WRAPABLE_DEF (moveNotify, dx, dy, immediate)
5411
WindowInterface::windowNotify (CompWindowNotify n)
5412
WRAPABLE_DEF (windowNotify, n)
5415
WindowInterface::grabNotify (int x,
5419
WRAPABLE_DEF (grabNotify, x, y, state, mask)
5422
WindowInterface::ungrabNotify ()
5423
WRAPABLE_DEF (ungrabNotify)
5426
WindowInterface::stateChangeNotify (unsigned int lastState)
5427
WRAPABLE_DEF (stateChangeNotify, lastState)
5430
WindowInterface::updateFrameRegion (CompRegion ®ion)
5431
WRAPABLE_DEF (updateFrameRegion, region)
5434
WindowInterface::minimize ()
5435
WRAPABLE_DEF (minimize);
5438
WindowInterface::unminimize ()
5439
WRAPABLE_DEF (unminimize);
5442
WindowInterface::minimized ()
5443
WRAPABLE_DEF (minimized);
5446
WindowInterface::alpha ()
5447
WRAPABLE_DEF (alpha);
5450
WindowInterface::isFocussable ()
5451
WRAPABLE_DEF (isFocussable);
5454
WindowInterface::managed ()
5455
WRAPABLE_DEF (managed);
5470
CompWindow::state ()
5476
CompWindow::actions ()
5478
return priv->actions;
5482
CompWindow::protocols ()
5484
return priv->protocols;
5488
CompWindow::close (Time serverTime)
5490
if (serverTime == 0)
5491
serverTime = screen->getCurrentTime ();
5495
if (priv->protocols & CompWindowProtocolDeleteMask)
5499
ev.type = ClientMessage;
5500
ev.xclient.window = priv->id;
5501
ev.xclient.message_type = Atoms::wmProtocols;
5502
ev.xclient.format = 32;
5503
ev.xclient.data.l[0] = Atoms::wmDeleteWindow;
5504
ev.xclient.data.l[1] = serverTime;
5505
ev.xclient.data.l[2] = 0;
5506
ev.xclient.data.l[3] = 0;
5507
ev.xclient.data.l[4] = 0;
5509
XSendEvent (screen->dpy (), priv->id, false, NoEventMask, &ev);
5513
XKillClient (screen->dpy (), priv->id);
5516
priv->closeRequests++;
5520
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5521
serverTime, priv->id, true, 0, 0);
5524
priv->lastCloseRequestTime = serverTime;
5528
PrivateWindow::handlePingTimeout (unsigned int lastPing)
5530
if (!window->isViewable ())
5533
if (!(priv->type & CompWindowTypeNormalMask))
5536
if (priv->protocols & CompWindowProtocolPingMask)
5538
if (priv->transientFor)
5541
if (priv->lastPong < lastPing)
5545
priv->alive = false;
5547
window->windowNotify (CompWindowNotifyAliveChanged);
5549
if (priv->closeRequests)
5551
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5552
priv->lastCloseRequestTime,
5553
priv->id, true, 0, 0);
5555
priv->closeRequests = 0;
5566
PrivateWindow::handlePing (int lastPing)
5572
window->windowNotify (CompWindowNotifyAliveChanged);
5574
if (priv->lastCloseRequestTime)
5576
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5577
priv->lastCloseRequestTime,
5578
priv->id, false, 0, 0);
5580
priv->lastCloseRequestTime = 0;
5583
priv->lastPong = lastPing;
5587
PrivateWindow::processMap ()
5590
bool initiallyMinimized;
5591
CompStackingUpdateMode stackingMode;
5593
priv->initialViewport = screen->vp ();
5595
priv->initialTimestampSet = false;
5597
screen->priv->applyStartupProperties (window);
5599
initiallyMinimized = (priv->hints &&
5600
priv->hints->initial_state == IconicState &&
5601
!window->minimized ());
5603
if (!serverFrame && !initiallyMinimized)
5606
priv->managed = true;
5610
int gravity = priv->sizeHints.win_gravity;
5614
/* adjust for gravity, but only for frame size */
5615
xwc.x = priv->serverGeometry.x ();
5616
xwc.y = priv->serverGeometry.y ();
5620
xwcm = adjustConfigureRequestForGravity (&xwc, CWX | CWY, gravity, 1);
5622
window->validateResizeRequest (xwcm, &xwc, ClientTypeApplication);
5624
CompPoint pos (xwc.x, xwc.y);
5625
if (window->place (pos))
5633
window->configureXWindow (xwcm, &xwc);
5635
priv->placed = true;
5638
allowFocus = allowWindowFocus (NO_FOCUS_MASK, 0);
5640
if (!allowFocus && (priv->type & ~NO_FOCUS_MASK))
5641
stackingMode = CompStackingUpdateModeInitialMapDeniedFocus;
5643
stackingMode = CompStackingUpdateModeInitialMap;
5645
window->updateAttributes (stackingMode);
5647
if (window->minimized () && !initiallyMinimized)
5648
window->unminimize ();
5650
screen->leaveShowDesktopMode (window);
5652
if (!initiallyMinimized)
5654
if (allowFocus && !window->onCurrentDesktop ());
5655
screen->priv->setCurrentDesktop (priv->desktop);
5657
if (!(priv->state & CompWindowStateHiddenMask))
5662
window->moveInputFocusTo ();
5663
if (!window->onCurrentDesktop ())
5664
screen->priv->setCurrentDesktop (priv->desktop);
5669
window->minimize ();
5670
window->changeState (window->state () | CompWindowStateHiddenMask);
5673
screen->priv->updateClientList ();
5677
* PrivateWindow::updatePassiveButtonGrabs
5679
* Updates the passive button grabs for a window. When
5680
* one of the specified button + modifier combinations
5681
* for this window is activated, compiz will be given
5682
* an active grab for the window (which we can turn off
5683
* by calling XAllowEvents later in ::handleEvent)
5685
* NOTE: ICCCM says that we are only allowed to grab
5686
* windows that we actually own as a client, so only
5687
* grab the frame window. Additionally, although there
5688
* isn't anything in the ICCCM that says we cannot
5689
* grab every button, some clients do not interpret
5690
* EnterNotify and LeaveNotify events caused by the
5691
* activation of the grab correctly, so ungrab button
5692
* and modifier combinations that we do not need on
5693
* active windows (but in reality we shouldn't be grabbing
5694
* for buttons that we don't actually need at that point
5699
PrivateWindow::updatePassiveButtonGrabs ()
5701
bool onlyActions = (priv->id == screen->priv->activeWindow ||
5702
!screen->priv->optionGetClickToFocus ());
5707
/* Ungrab everything */
5708
XUngrabButton (screen->priv->dpy, AnyButton, AnyModifier, frame);
5710
/* We don't need the full grab in the following cases:
5711
* - This window has the focus and either
5713
* - we don't want click raise
5718
if (screen->priv->optionGetRaiseOnClick ())
5720
CompWindow *highestSibling =
5721
PrivateWindow::findSiblingBelow (window, true);
5723
/* Check if this window is permitted to be raised */
5724
for (CompWindow *above = window->serverNext;
5725
above != NULL; above = above->serverNext)
5727
if (highestSibling == above)
5729
onlyActions = false;
5738
/* Grab only we have bindings on */
5739
foreach (PrivateScreen::ButtonGrab &bind, screen->priv->buttonGrabs)
5741
unsigned int mods = modHandler->virtualToRealModMask (bind.modifiers);
5743
if (mods & CompNoMask)
5746
for (unsigned int ignore = 0;
5747
ignore <= modHandler->ignoredModMask (); ignore++)
5749
if (ignore & ~modHandler->ignoredModMask ())
5752
XGrabButton (screen->priv->dpy,
5757
ButtonPressMask | ButtonReleaseMask |
5768
/* Grab everything */
5769
XGrabButton (screen->priv->dpy,
5773
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
5783
CompWindow::region () const
5785
return priv->region;
5789
CompWindow::frameRegion () const
5791
return priv->frameRegion;
5795
CompWindow::inShowDesktopMode ()
5797
return priv->inShowDesktopMode;
5801
CompWindow::setShowDesktopMode (bool value)
5803
priv->inShowDesktopMode = value;
5807
CompWindow::managed ()
5809
WRAPABLE_HND_FUNC_RETURN (18, bool, managed);
5810
return priv->managed;
5814
CompWindow::grabbed ()
5816
return priv->grabbed;
5820
CompWindow::pendingMaps ()
5822
return priv->pendingMaps;
5826
CompWindow::wmType ()
5828
return priv->wmType;
5832
CompWindow::activeNum ()
5834
return priv->activeNum;
5838
CompWindow::frame ()
5840
return priv->serverFrame;
5844
CompWindow::resName ()
5847
return priv->resName;
5849
return CompString ();
5853
CompWindow::mapNum () const
5855
return priv->mapNum;
5859
CompWindow::struts ()
5861
return priv->struts;
5865
CompWindow::saveMask ()
5867
return priv->saveMask;
5871
CompWindow::saveWc ()
5873
return priv->saveWc;
5877
CompWindow::moveToViewportPosition (int x,
5882
int vWidth = screen->width () * screen->vpSize ().width ();
5883
int vHeight = screen->height () * screen->vpSize ().height ();
5885
if (screen->vpSize ().width () != 1)
5887
x += screen->vp ().x () * screen->width ();
5888
x = MOD (x, vWidth);
5889
x -= screen->vp ().x () * screen->width ();
5892
if (screen->vpSize ().height () != 1)
5894
y += screen->vp ().y () * screen->height ();
5895
y = MOD (y, vHeight);
5896
y -= screen->vp ().y () * screen->height ();
5899
tx = x - priv->geometry.x ();
5900
ty = y - priv->geometry.y ();
5904
unsigned int valueMask = CWX | CWY;
5911
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5914
if (priv->state & CompWindowStateStickyMask)
5920
if (screen->vpSize ().width ()!= 1)
5922
m = priv->geometry.x () + tx;
5924
if (m - priv->output.left < (int) screen->width () - vWidth)
5926
else if (m + priv->width + priv->output.right > vWidth)
5930
if (screen->vpSize ().height () != 1)
5932
m = priv->geometry.y () + ty;
5934
if (m - priv->output.top < (int) screen->height () - vHeight)
5936
else if (m + priv->height + priv->output.bottom > vHeight)
5940
if (priv->saveMask & CWX)
5941
priv->saveWc.x += wx;
5943
if (priv->saveMask & CWY)
5944
priv->saveWc.y += wy;
5946
xwc.x = serverGeometry ().x () + wx;
5947
xwc.y = serverGeometry ().y () + wy;
5949
configureXWindow (valueMask, &xwc);
5954
CompWindow::startupId ()
5956
return priv->startupId;
5960
PrivateWindow::applyStartupProperties (CompStartupSequence *s)
5964
priv->initialViewport.setX (s->viewportX);
5965
priv->initialViewport.setY (s->viewportY);
5967
workspace = sn_startup_sequence_get_workspace (s->sequence);
5969
window->setDesktop (workspace);
5971
priv->initialTimestamp =
5972
sn_startup_sequence_get_timestamp (s->sequence);
5973
priv->initialTimestampSet = true;
5977
CompWindow::desktop ()
5979
return priv->desktop;
5983
CompWindow::clientLeader (bool checkAncestor)
5985
if (priv->clientLeader)
5986
return priv->clientLeader;
5989
return priv->getClientLeaderOfAncestor ();
5995
CompWindow::transientFor ()
5997
return priv->transientFor;
6001
CompWindow::pendingUnmaps ()
6003
return priv->pendingUnmaps;
6007
CompWindow::minimized ()
6009
WRAPABLE_HND_FUNC_RETURN (15, bool, minimized);
6010
return priv->minimized;
6014
CompWindow::placed ()
6016
return priv->placed;
6020
CompWindow::shaded ()
6022
return priv->shaded;
6026
CompWindow::border () const
6028
return priv->border;
6032
CompWindow::input () const
6034
return priv->serverInput;
6038
CompWindow::output () const
6040
return priv->output;
6044
CompWindow::sizeHints () const
6046
return priv->sizeHints;
6050
PrivateWindow::updateMwmHints ()
6052
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
6053
window->recalcActions ();
6057
PrivateWindow::updateStartupId ()
6059
char *oldId = startupId;
6062
startupId = getStartupId ();
6064
if (oldId && startupId)
6066
if (strcmp (startupId, oldId) == 0)
6070
if (managed && startupId && newId)
6077
initialTimestampSet = false;
6078
screen->priv->applyStartupProperties (window);
6080
if (initialTimestampSet)
6081
timestamp = initialTimestamp;
6083
/* as the viewport can't be transmitted via startup
6084
notification, assume the client changing the ID
6085
wanted to activate the window on the current viewport */
6087
vp = window->defaultViewport ();
6088
svp = screen->vp ();
6091
x = window->geometry ().x () + (svp.x () - vp.x ()) * size.width ();
6092
y = window->geometry ().y () + (svp.y () - vp.y ()) * size.height ();
6093
window->moveToViewportPosition (x, y, true);
6095
if (allowWindowFocus (0, timestamp))
6096
window->activate ();
6104
CompWindow::destroyed ()
6106
return priv->destroyed;
6110
CompWindow::invisible ()
6112
return priv->invisible;
6116
CompWindow::syncAlarm ()
6118
return priv->syncAlarm;
6122
CoreWindow::manage (Window aboveId, XWindowAttributes &wa)
6124
return new CompWindow (aboveId, wa, priv);
6127
CoreWindow::CoreWindow (Window id)
6129
priv = new PrivateWindow ();
6132
priv->serverId = id;
6135
CompWindow::CompWindow (Window aboveId,
6136
XWindowAttributes &wa,
6137
PrivateWindow *priv) :
6138
PluginClassStorage (windowPluginClassIndices),
6141
StackDebugger *dbg = StackDebugger::Default ();
6143
// TODO: Reparent first!
6145
priv->window = this;
6147
screen->insertWindow (this, aboveId);
6148
screen->insertServerWindow (this, aboveId);
6150
/* We must immediately insert the window into the debugging
6153
dbg->overrideRedirectRestack (priv->id, aboveId);
6155
gettimeofday (&priv->lastConfigureRequest, NULL);
6158
priv->serverGeometry.set (priv->attrib.x, priv->attrib.y,
6159
priv->attrib.width, priv->attrib.height,
6160
priv->attrib.border_width);
6161
priv->serverFrameGeometry = priv->frameGeometry = priv->syncGeometry
6162
= priv->geometry = priv->serverGeometry;
6164
priv->width = priv->attrib.width + priv->attrib.border_width * 2;
6165
priv->height = priv->attrib.height + priv->attrib.border_width * 2;
6167
priv->sizeHints.flags = 0;
6169
priv->recalcNormalHints ();
6171
priv->transientFor = None;
6172
priv->clientLeader = None;
6174
XSelectInput (screen->dpy (), priv->id,
6175
wa.your_event_mask |
6176
PropertyChangeMask |
6180
priv->alpha = (priv->attrib.depth == 32);
6181
priv->lastPong = screen->priv->lastPing;
6183
if (screen->XShape ())
6184
XShapeSelectInput (screen->dpy (), priv->id, ShapeNotifyMask);
6186
if (priv->attrib.c_class != InputOnly)
6188
priv->region = CompRegion (priv->attrib.x, priv->attrib.y,
6189
priv->width, priv->height);
6190
priv->inputRegion = priv->region;
6192
/* need to check for DisplayModal state on all windows */
6193
priv->state = screen->priv->getWindowState (priv->id);
6195
priv->updateClassHints ();
6199
priv->attrib.map_state = IsUnmapped;
6202
priv->wmType = screen->priv->getWindowType (priv->id);
6203
priv->protocols = screen->priv->getProtocols (priv->id);
6205
if (!overrideRedirect ())
6207
priv->updateNormalHints ();
6209
priv->updateWmHints ();
6210
priv->updateTransientHint ();
6212
priv->clientLeader = priv->getClientLeader ();
6213
priv->startupId = priv->getStartupId ();
6217
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
6219
if (!(priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask)))
6221
priv->desktop = screen->getWindowProp (priv->id, Atoms::winDesktop,
6223
if (priv->desktop != 0xffffffff)
6225
if (priv->desktop >= screen->nDesktop ())
6226
priv->desktop = screen->currentDesktop ();
6235
if (priv->attrib.map_state == IsViewable)
6237
priv->placed = true;
6239
if (!overrideRedirect ())
6241
// needs to happen right after maprequest
6242
if (!priv->serverFrame)
6244
priv->managed = true;
6246
if (screen->priv->getWmState (priv->id) == IconicState)
6248
if (priv->state & CompWindowStateShadedMask)
6249
priv->shaded = true;
6251
priv->minimized = true;
6255
if (priv->wmType & (CompWindowTypeDockMask |
6256
CompWindowTypeDesktopMask))
6258
setDesktop (0xffffffff);
6262
if (priv->desktop != 0xffffffff)
6263
priv->desktop = screen->currentDesktop ();
6265
screen->setWindowProp (priv->id, Atoms::winDesktop,
6271
priv->attrib.map_state = IsUnmapped;
6272
priv->pendingMaps++;
6276
updateAttributes (CompStackingUpdateModeNormal);
6278
if (priv->minimized || priv->inShowDesktopMode ||
6279
priv->hidden || priv->shaded)
6281
priv->state |= CompWindowStateHiddenMask;
6283
priv->pendingUnmaps++;
6285
if (priv->serverFrame && !priv->shaded)
6286
XUnmapWindow (screen->dpy (), priv->serverFrame);
6288
XUnmapWindow (screen->dpy (), priv->id);
6290
screen->priv->setWindowState (priv->state, priv->id);
6293
else if (!overrideRedirect ())
6295
if (screen->priv->getWmState (priv->id) == IconicState)
6297
// before everything else in maprequest
6298
if (!priv->serverFrame)
6300
priv->managed = true;
6301
priv->placed = true;
6303
if (priv->state & CompWindowStateHiddenMask)
6305
if (priv->state & CompWindowStateShadedMask)
6306
priv->shaded = true;
6308
priv->minimized = true;
6313
/* TODO: bailout properly when objectInitPlugins fails */
6314
assert (CompPlugin::windowInitPlugins (this));
6317
priv->updateIconGeometry ();
6320
priv->updateFrameWindow ();
6322
if (priv->attrib.map_state == IsViewable)
6324
priv->invisible = WINDOW_INVISIBLE (priv);
6328
CompWindow::~CompWindow ()
6330
if (priv->serverFrame)
6331
priv->unreparent ();
6333
/* Update the references of other windows
6334
* pending destroy if this was a sibling
6335
* of one of those */
6337
screen->priv->destroyedWindows.remove (this);
6339
foreach (CompWindow *dw, screen->priv->destroyedWindows)
6341
if (dw->next == this)
6342
dw->next = this->next;
6343
if (dw->prev == this)
6344
dw->prev = this->prev;
6346
if (dw->serverNext == this)
6347
dw->serverNext = this->serverNext;
6348
if (dw->serverPrev == this)
6349
dw->serverPrev = this->serverPrev;
6352
/* If this window has a detached frame, destroy it, but only
6353
* using XDestroyWindow since there may be pending restack
6354
* requests relative to it */
6356
std::map <CompWindow *, CompWindow *>::iterator it =
6357
screen->priv->detachedFrameWindows.find (this);
6359
if (it != screen->priv->detachedFrameWindows.end ())
6361
CompWindow *fw = (it->second);
6363
XDestroyWindow (screen->dpy (), fw->id ());
6364
screen->priv->detachedFrameWindows.erase (it);
6367
if (!priv->destroyed)
6369
StackDebugger *dbg = StackDebugger::Default ();
6371
screen->unhookWindow (this);
6372
screen->unhookServerWindow (this);
6374
/* We must immediately insert the window into the debugging
6377
dbg->removeServerWindow (id ());
6379
/* restore saved geometry and map if hidden */
6380
if (!priv->attrib.override_redirect)
6383
XConfigureWindow (screen->dpy (), priv->id,
6384
priv->saveMask, &priv->saveWc);
6388
if (priv->state & CompWindowStateHiddenMask)
6389
XMapWindow (screen->dpy (), priv->id);
6393
if (screen->XShape ())
6394
XShapeSelectInput (screen->dpy (), priv->id, NoEventMask);
6396
if (priv->id != screen->priv->grabWindow)
6397
XSelectInput (screen->dpy (), priv->id, NoEventMask);
6399
XUngrabButton (screen->dpy (), AnyButton, AnyModifier, priv->id);
6403
if (priv->attrib.map_state == IsViewable)
6405
if (priv->type == CompWindowTypeDesktopMask)
6406
screen->priv->desktopWindowCount--;
6408
if (priv->destroyed && priv->struts)
6409
screen->updateWorkarea ();
6412
if (priv->destroyed)
6413
screen->priv->updateClientList ();
6415
CompPlugin::windowFiniPlugins (this);
6420
PrivateWindow::PrivateWindow () :
6429
transientFor (None),
6430
clientLeader (None),
6438
type (CompWindowTypeUnknownMask),
6442
mwmDecor (MwmDecorAll),
6443
mwmFunc (MwmFuncAll),
6451
initialViewport (0, 0),
6453
initialTimestamp (0),
6454
initialTimestampSet (false),
6456
fullscreenMonitorsSet (false),
6460
inShowDesktopMode (false),
6469
pendingConfigures (screen->dpy ()),
6470
pendingPositionUpdates (false),
6492
closeRequests (false),
6493
lastCloseRequestTime (0)
6500
serverInput.left = 0;
6501
serverInput.right = 0;
6502
serverInput.top = 0;
6503
serverInput.bottom = 0;
6515
syncWaitTimer.setTimes (1000, 1200);
6516
syncWaitTimer.setCallback (boost::bind (&PrivateWindow::handleSyncAlarm,
6520
PrivateWindow::~PrivateWindow ()
6523
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
6525
syncWaitTimer.stop ();
6528
XDestroyWindow (screen->dpy (), serverFrame);
6530
XDestroyWindow (screen->dpy (), frame);
6552
CompWindow::syncWait ()
6554
return priv->syncWait;
6558
CompWindow::alpha ()
6560
WRAPABLE_HND_FUNC_RETURN (16, bool, alpha);
6566
CompWindow::overrideRedirect ()
6568
return priv->attrib.override_redirect;
6572
PrivateWindow::setOverrideRedirect (bool overrideRedirect)
6574
if (overrideRedirect == window->overrideRedirect ())
6577
priv->attrib.override_redirect = overrideRedirect ? 1 : 0;
6578
window->recalcType ();
6579
window->recalcActions ();
6581
screen->matchPropertyChanged (window);
6585
CompWindow::isMapped () const
6587
return priv->mapNum > 0;
6591
CompWindow::isViewable () const
6593
return (priv->attrib.map_state == IsViewable);
6597
CompWindow::isFocussable ()
6599
WRAPABLE_HND_FUNC_RETURN (17, bool, isFocussable);
6601
if (priv->inputHint)
6604
if (priv->protocols & CompWindowProtocolTakeFocusMask)
6611
CompWindow::windowClass ()
6613
return priv->attrib.c_class;
6617
CompWindow::depth ()
6619
return priv->attrib.depth;
6623
CompWindow::alive ()
6629
CompWindow::mwmDecor ()
6631
return priv->mwmDecor;
6635
CompWindow::mwmFunc ()
6637
return priv->mwmFunc;
6640
/* TODO: This function should be able to check the XShape event
6641
* kind and only get/set shape rectangles for either ShapeInput
6642
* or ShapeBounding, but not both at the same time
6646
CompWindow::updateFrameRegion ()
6648
if (priv->serverFrame &&
6649
priv->serverGeometry.width () == priv->geometry.width () &&
6650
priv->serverGeometry.height () == priv->geometry.height ())
6655
priv->frameRegion = CompRegion ();
6657
updateFrameRegion (priv->frameRegion);
6661
r = priv->region.boundingRect ();
6662
priv->frameRegion -= r;
6664
r.setGeometry (r.x1 () - priv->input.left,
6665
r.y1 () - priv->input.top,
6666
r.width () + priv->input.right + priv->input.left,
6667
r.height () + priv->input.bottom + priv->input.top);
6669
priv->frameRegion &= CompRegion (r);
6672
x = priv->geometry.x () - priv->input.left;
6673
y = priv->geometry.y () - priv->input.top;
6675
XShapeCombineRegion (screen->dpy (), priv->serverFrame,
6676
ShapeBounding, -x, -y,
6677
priv->frameRegion.united (priv->region).handle (),
6680
XShapeCombineRegion (screen->dpy (), priv->serverFrame,
6682
priv->frameRegion.united (priv->inputRegion).handle (),
6688
CompWindow::setWindowFrameExtents (CompWindowExtents *b,
6689
CompWindowExtents *i)
6691
/* Input extents are used for frame size,
6692
* Border extents used for placement.
6698
if (priv->serverInput.left != i->left ||
6699
priv->serverInput.right != i->right ||
6700
priv->serverInput.top != i->top ||
6701
priv->serverInput.bottom != i->bottom ||
6702
priv->border.left != b->left ||
6703
priv->border.right != b->right ||
6704
priv->border.top != b->top ||
6705
priv->border.bottom != b->bottom)
6707
unsigned long data[4];
6709
priv->serverInput = *i;
6714
/* Use b for _NET_WM_FRAME_EXTENTS here because
6715
* that is the representation of the actual decoration
6716
* around the window that the user sees and should
6717
* be used for placement and such */
6722
data[3] = b->bottom;
6724
XChangeProperty (screen->dpy (), priv->id,
6725
Atoms::frameExtents,
6726
XA_CARDINAL, 32, PropModeReplace,
6727
(unsigned char *) data, 4);
6729
priv->updateSize ();
6730
priv->updateFrameWindow ();
6735
CompWindow::hasUnmapReference ()
6737
return (priv && priv->unmapRefCnt > 1);
6741
CompWindow::updateFrameRegion (CompRegion& region)
6742
WRAPABLE_HND_FUNC (12, updateFrameRegion, region)
6745
PrivateWindow::reparent ()
6747
XSetWindowAttributes attr;
6748
XWindowAttributes wa;
6751
unsigned int nchildren;
6752
Window *children, root_return, parent_return;
6753
Display *dpy = screen->dpy ();
6754
Visual *visual = DefaultVisual (screen->dpy (),
6755
screen->screenNum ());
6756
Colormap cmap = DefaultColormap (screen->dpy (),
6757
screen->screenNum ());
6765
if (!XGetWindowAttributes (dpy, id, &wa))
6767
XUngrabServer (dpy);
6772
if (wa.override_redirect)
6775
XSelectInput (dpy, id, NoEventMask);
6777
/* Don't ever reparent windows which have ended up
6778
* reparented themselves on the server side but not
6779
* on the client side */
6781
XQueryTree (dpy, id, &root_return, &parent_return, &children, &nchildren);
6783
if (parent_return != root_return)
6786
XUngrabServer (dpy);
6793
XQueryTree (dpy, root_return, &root_return, &parent_return, &children, &nchildren);
6795
XChangeSaveSet (dpy, id, SetModeInsert);
6797
/* Force border width to 0 */
6798
xwc.border_width = 0;
6799
XConfigureWindow (dpy, id, CWBorderWidth, &xwc);
6801
priv->serverGeometry.setBorder (0);
6803
mask = CWBorderPixel | CWColormap | CWBackPixmap | CWOverrideRedirect;
6811
attr.background_pixmap = None;
6812
attr.border_pixel = 0;
6813
attr.colormap = cmap;
6814
attr.override_redirect = true;
6816
/* Look for existing detached frame windows and reattach them
6817
* in case this window as reparented again after being withdrawn */
6818
std::map <CompWindow *, CompWindow *>::iterator it =
6819
screen->priv->detachedFrameWindows.find (window);
6821
if (it != screen->priv->detachedFrameWindows.end ())
6823
/* Trash the old frame window
6824
* TODO: It would be nicer if we could just
6825
* reparent back into it, but there are some
6826
* problems with that */
6828
XDestroyWindow (dpy, (it->second)->id ());
6829
screen->priv->detachedFrameWindows.erase (it);
6832
/* We need to know when the frame window is created
6834
XSelectInput (dpy, screen->root (), SubstructureNotifyMask);
6836
/* Awaiting a new frame to be given to us */
6838
serverFrame = XCreateWindow (dpy, screen->root (), 0, 0,
6839
wa.width, wa.height, 0, wa.depth,
6840
InputOutput, visual, mask, &attr);
6842
/* Do not get any events from here on */
6843
XSelectInput (dpy, screen->root (), NoEventMask);
6845
wrapper = XCreateWindow (dpy, serverFrame, 0, 0,
6846
wa.width, wa.height, 0, wa.depth,
6847
InputOutput, visual, mask, &attr);
6849
xwc.stack_mode = Above;
6851
/* Look for the client in the current server side stacking
6852
* order and put the frame above what the client is above
6857
/* client at the bottom */
6858
xwc.stack_mode = Below;
6863
for (unsigned int i = 0; i < nchildren; i++)
6865
if (i < nchildren - 1)
6867
if (children[i + 1] == id)
6869
xwc.sibling = children[i];
6873
else /* client on top */
6874
xwc.sibling = children[i];
6880
/* Make sure the frame is underneath the client */
6881
XConfigureWindow (dpy, serverFrame, CWSibling | CWStackMode, &xwc);
6883
/* Wait for the restacking to finish */
6886
/* Always need to have the wrapper window mapped */
6887
XMapWindow (dpy, wrapper);
6889
/* Reparent the client into the wrapper window */
6890
XReparentWindow (dpy, id, wrapper, 0, 0);
6892
/* Restore events */
6893
attr.event_mask = wa.your_event_mask;
6895
/* We don't care about client events on the frame, and listening for them
6896
* will probably end up fighting the client anyways, so disable them */
6898
attr.do_not_propagate_mask = KeyPressMask | KeyReleaseMask |
6899
ButtonPressMask | ButtonReleaseMask |
6900
EnterWindowMask | LeaveWindowMask |
6901
PointerMotionMask | PointerMotionHintMask |
6902
Button1MotionMask | Button2MotionMask |
6903
Button3MotionMask | Button4MotionMask |
6904
Button5MotionMask | ButtonMotionMask |
6905
KeymapStateMask | ExposureMask |
6906
VisibilityChangeMask | StructureNotifyMask |
6907
ResizeRedirectMask | SubstructureNotifyMask |
6908
SubstructureRedirectMask | FocusChangeMask |
6909
PropertyChangeMask | ColormapChangeMask |
6910
OwnerGrabButtonMask;
6912
XChangeWindowAttributes (dpy, id, CWEventMask | CWDontPropagate, &attr);
6914
if (wa.map_state == IsViewable || shaded)
6915
XMapWindow (dpy, serverFrame);
6917
attr.event_mask = SubstructureRedirectMask |
6918
SubstructureNotifyMask | EnterWindowMask |
6921
serverFrameGeometry = serverGeometry;
6923
XMoveResizeWindow (dpy, serverFrame, serverFrameGeometry.x (), serverFrameGeometry.y (),
6924
serverFrameGeometry.width (), serverFrameGeometry.height ());
6926
XSelectInput (dpy, screen->root (),
6927
SubstructureRedirectMask |
6928
SubstructureNotifyMask |
6929
StructureNotifyMask |
6930
PropertyChangeMask |
6940
XChangeWindowAttributes (dpy, serverFrame, CWEventMask, &attr);
6941
XChangeWindowAttributes (dpy, wrapper, CWEventMask, &attr);
6943
XUngrabServer (dpy);
6946
window->windowNotify (CompWindowNotifyReparent);
6952
PrivateWindow::unreparent ()
6954
Display *dpy = screen->dpy ();
6958
unsigned int nchildren;
6959
Window *children = NULL, root_return, parent_return;
6960
XWindowAttributes wa;
6961
StackDebugger *dbg = StackDebugger::Default ();
6968
if (XCheckTypedWindowEvent (dpy, id, DestroyNotify, &e))
6970
XPutBackEvent (dpy, &e);
6975
if (!XGetWindowAttributes (dpy, id, &wa))
6979
/* Also don't reparent back into root windows that have ended up
6980
* reparented into other windows (and as such we are unmanaging them) */
6984
XQueryTree (dpy, id, &root_return, &parent_return, &children, &nchildren);
6986
if (parent_return != wrapper)
6990
if ((!destroyed) && alive)
6994
XChangeSaveSet (dpy, id, SetModeDelete);
6995
XSelectInput (dpy, serverFrame, NoEventMask);
6996
XSelectInput (dpy, wrapper, NoEventMask);
6997
XSelectInput (dpy, id, NoEventMask);
6998
XSelectInput (dpy, screen->root (), NoEventMask);
6999
XReparentWindow (dpy, id, screen->root (), 0, 0);
7001
/* Wait for the reparent to finish */
7004
xwc.x = serverGeometry.x () - serverGeometry.border ();
7005
xwc.y = serverGeometry.y () - serverGeometry.border ();
7006
xwc.width = serverGeometry.width () + serverGeometry.border () * 2;
7007
xwc.height = serverGeometry.height () + serverGeometry.border () * 2;
7009
XConfigureWindow (dpy, serverFrame, CWX | CWY | CWWidth | CWHeight, &xwc);
7012
xwc.stack_mode = Below;
7013
xwc.sibling = serverFrame;
7014
XConfigureWindow (dpy, id, CWSibling | CWStackMode, &xwc);
7016
/* Wait for the window to be restacked */
7019
XUnmapWindow (dpy, serverFrame);
7021
XSelectInput (dpy, id, wa.your_event_mask);
7023
XSelectInput (dpy, screen->root (),
7024
SubstructureRedirectMask |
7025
SubstructureNotifyMask |
7026
StructureNotifyMask |
7027
PropertyChangeMask |
7037
XUngrabServer (dpy);
7040
XMoveWindow (dpy, id, serverGeometry.x (), serverGeometry.y ());
7047
dbg->addDestroyedFrame (serverFrame);
7049
/* This is where things get tricky ... it is possible
7050
* to receive a ConfigureNotify relative to a frame window
7051
* for a destroyed window in case we process a ConfigureRequest
7052
* for the destroyed window and then a DestroyNotify for it directly
7053
* afterwards. In that case, we will receive the ConfigureNotify
7054
* for the XConfigureWindow request we made relative to that frame
7055
* window. Because of this, we must keep the frame window in the stack
7056
* as a new toplevel window so that the ConfigureNotify will be processed
7057
* properly until it too receives a DestroyNotify */
7061
XWindowAttributes attrib;
7063
/* It's possible that the frame window was already destroyed because
7064
* the client was unreparented before it was destroyed (eg
7065
* UnmapNotify before DestroyNotify). In that case the frame window
7066
* is going to be an invalid window but since we haven't received
7067
* a DestroyNotify for it yet, it is possible that restacking
7068
* operations could occurr relative to it so we need to hold it
7069
* in the stack for now. Ensure that it is marked override redirect */
7070
XGetWindowAttributes (screen->dpy (), serverFrame, &attrib);
7072
/* Put the frame window "above" the client window
7074
CoreWindow *cw = new CoreWindow (serverFrame);
7075
CompWindow *fw = cw->manage (id, attrib);
7076
screen->priv->createdWindows.remove (cw);
7079
/* Put this window in the list of "detached frame windows"
7080
* so that we can reattach it or destroy it when we are
7083
screen->priv->detachedFrameWindows[window] = fw;
7086
/* Safe to destroy the wrapper but not the frame */
7087
XUnmapWindow (screen->dpy (), serverFrame);
7088
XDestroyWindow (screen->dpy (), wrapper);
7094
window->windowNotify (CompWindowNotifyUnreparent);