2
* Copyright © 2005 Novell, Inc.
4
* Permission to use, copy, modify, distribute, and sell this software
5
* and its documentation for any purpose is hereby granted without
6
* fee, provided that the above copyright notice appear in all copies
7
* and that both that copyright notice and this permission notice
8
* appear in supporting documentation, and that the name of
9
* Novell, Inc. not be used in advertising or publicity pertaining to
10
* distribution of the software without specific, written prior permission.
11
* Novell, Inc. makes no representations about the suitability of this
12
* software for any purpose. It is provided "as is" without express or
15
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23
* Author: David Reveman <davidr@novell.com>
29
#include <X11/Xatom.h>
30
#include <X11/Xproto.h>
31
#include <X11/extensions/shape.h>
41
#include <boost/bind.hpp>
43
#include <core/core.h>
44
#include <core/icon.h>
45
#include <core/atoms.h>
46
#include "privatewindow.h"
47
#include "privatescreen.h"
48
#include "privatestackdebugger.h"
50
PluginClassStorage::Indices windowPluginClassIndices (0);
53
CompWindow::allocPluginClassIndex ()
55
unsigned int i = PluginClassStorage::allocatePluginClassIndex (windowPluginClassIndices);
57
foreach (CompWindow *w, screen->windows ())
58
if (windowPluginClassIndices.size () != w->pluginClasses.size ())
59
w->pluginClasses.resize (windowPluginClassIndices.size ());
65
CompWindow::freePluginClassIndex (unsigned int index)
67
PluginClassStorage::freePluginClassIndex (windowPluginClassIndices, index);
69
foreach (CompWindow *w, ::screen->windows ())
70
if (windowPluginClassIndices.size () != w->pluginClasses.size ())
71
w->pluginClasses.resize (windowPluginClassIndices.size ());
75
PrivateWindow::isAncestorTo (CompWindow *transient,
78
if (transient->priv->transientFor)
80
if (transient->priv->transientFor == ancestor->priv->id)
83
transient = screen->findWindow (transient->priv->transientFor);
85
return isAncestorTo (transient, ancestor);
92
PrivateWindow::recalcNormalHints ()
96
#warning fixme to max Texture size
98
maxSize -= serverGeometry.border () * 2;
100
sizeHints.x = serverGeometry.x ();
101
sizeHints.y = serverGeometry.y ();
102
sizeHints.width = serverGeometry.width ();
103
sizeHints.height = serverGeometry.height ();
105
if (!(sizeHints.flags & PBaseSize))
107
if (sizeHints.flags & PMinSize)
109
sizeHints.base_width = sizeHints.min_width;
110
sizeHints.base_height = sizeHints.min_height;
114
sizeHints.base_width = 0;
115
sizeHints.base_height = 0;
118
sizeHints.flags |= PBaseSize;
121
if (!(sizeHints.flags & PMinSize))
123
sizeHints.min_width = sizeHints.base_width;
124
sizeHints.min_height = sizeHints.base_height;
125
sizeHints.flags |= PMinSize;
128
if (!(sizeHints.flags & PMaxSize))
130
sizeHints.max_width = 65535;
131
sizeHints.max_height = 65535;
132
sizeHints.flags |= PMaxSize;
135
if (sizeHints.max_width < sizeHints.min_width)
136
sizeHints.max_width = sizeHints.min_width;
138
if (sizeHints.max_height < sizeHints.min_height)
139
sizeHints.max_height = sizeHints.min_height;
141
if (sizeHints.min_width < 1)
142
sizeHints.min_width = 1;
144
if (sizeHints.max_width < 1)
145
sizeHints.max_width = 1;
147
if (sizeHints.min_height < 1)
148
sizeHints.min_height = 1;
150
if (sizeHints.max_height < 1)
151
sizeHints.max_height = 1;
153
if (sizeHints.max_width > maxSize)
154
sizeHints.max_width = maxSize;
156
if (sizeHints.max_height > maxSize)
157
sizeHints.max_height = maxSize;
159
if (sizeHints.min_width > maxSize)
160
sizeHints.min_width = maxSize;
162
if (sizeHints.min_height > maxSize)
163
sizeHints.min_height = maxSize;
165
if (sizeHints.base_width > maxSize)
166
sizeHints.base_width = maxSize;
168
if (sizeHints.base_height > maxSize)
169
sizeHints.base_height = maxSize;
171
if (sizeHints.flags & PResizeInc)
173
if (sizeHints.width_inc == 0)
174
sizeHints.width_inc = 1;
176
if (sizeHints.height_inc == 0)
177
sizeHints.height_inc = 1;
181
sizeHints.width_inc = 1;
182
sizeHints.height_inc = 1;
183
sizeHints.flags |= PResizeInc;
186
if (sizeHints.flags & PAspect)
188
/* don't divide by 0 */
189
if (sizeHints.min_aspect.y < 1)
190
sizeHints.min_aspect.y = 1;
192
if (sizeHints.max_aspect.y < 1)
193
sizeHints.max_aspect.y = 1;
197
sizeHints.min_aspect.x = 1;
198
sizeHints.min_aspect.y = 65535;
199
sizeHints.max_aspect.x = 65535;
200
sizeHints.max_aspect.y = 1;
201
sizeHints.flags |= PAspect;
204
if (!(sizeHints.flags & PWinGravity))
206
sizeHints.win_gravity = NorthWestGravity;
207
sizeHints.flags |= PWinGravity;
212
PrivateWindow::updateNormalHints ()
217
status = XGetWMNormalHints (screen->dpy (), priv->id,
218
&priv->sizeHints, &supplied);
221
priv->sizeHints.flags = 0;
223
priv->recalcNormalHints ();
227
PrivateWindow::updateWmHints ()
231
bool iconChanged = false;
234
dFlags = hints->flags;
238
newHints = XGetWMHints (screen->dpy (), id);
241
dFlags ^= newHints->flags;
243
if (newHints->flags & InputHint)
244
inputHint = newHints->input;
248
if ((newHints->flags & IconPixmapHint) &&
249
(hints->icon_pixmap != newHints->icon_pixmap))
253
else if ((newHints->flags & IconMaskHint) &&
254
(hints->icon_mask != newHints->icon_mask))
261
iconChanged |= (dFlags & (IconPixmapHint | IconMaskHint));
273
PrivateWindow::updateClassHints ()
275
XClassHint classHint;
280
free (priv->resName);
281
priv->resName = NULL;
286
free (priv->resClass);
287
priv->resClass = NULL;
290
status = XGetClassHint (screen->dpy (),
291
priv->id, &classHint);
294
if (classHint.res_name)
296
priv->resName = strdup (classHint.res_name);
297
XFree (classHint.res_name);
300
if (classHint.res_class)
302
priv->resClass = strdup (classHint.res_class);
303
XFree (classHint.res_class);
309
PrivateWindow::updateTransientHint ()
314
priv->transientFor = None;
316
status = XGetTransientForHint (screen->dpy (),
317
priv->id, &transientFor);
321
CompWindow *ancestor;
323
ancestor = screen->findWindow (transientFor);
327
/* protect against circular transient dependencies */
328
if (transientFor == priv->id ||
329
PrivateWindow::isAncestorTo (ancestor, window))
332
priv->transientFor = transientFor;
337
PrivateWindow::updateIconGeometry ()
341
unsigned long n, left;
344
priv->iconGeometry.setGeometry (0, 0, 0, 0);
346
result = XGetWindowProperty (screen->dpy (), priv->id,
347
Atoms::wmIconGeometry,
348
0L, 1024L, False, XA_CARDINAL,
349
&actual, &format, &n, &left, &data);
351
if (result == Success && data)
355
unsigned long *geometry = (unsigned long *) data;
357
priv->iconGeometry.setX (geometry[0]);
358
priv->iconGeometry.setY (geometry[1]);
359
priv->iconGeometry.setWidth (geometry[2]);
360
priv->iconGeometry.setHeight (geometry[3]);
368
PrivateWindow::getClientLeaderOfAncestor ()
372
CompWindow *w = screen->findWindow (transientFor);
375
if (w->priv->clientLeader)
376
return w->priv->clientLeader;
378
return w->priv->getClientLeaderOfAncestor ();
386
PrivateWindow::getClientLeader ()
390
unsigned long n, left;
393
result = XGetWindowProperty (screen->dpy (), priv->id,
394
Atoms::wmClientLeader,
395
0L, 1L, False, XA_WINDOW, &actual, &format,
398
if (result == Success && data)
403
memcpy (&win, data, sizeof (Window));
405
XFree ((void *) data);
411
return priv->getClientLeaderOfAncestor ();
415
PrivateWindow::getStartupId ()
419
unsigned long n, left;
422
result = XGetWindowProperty (screen->dpy (), priv->id,
429
if (result == Success && data)
434
id = strdup ((char *) data);
435
XFree ((void *) data);
444
PrivateWindow::setFullscreenMonitors (CompFullscreenMonitorSet *monitors)
446
bool hadFsMonitors = fullscreenMonitorsSet;
447
unsigned int outputs = screen->outputDevs ().size ();
449
fullscreenMonitorsSet = false;
452
(unsigned int) monitors->left < outputs &&
453
(unsigned int) monitors->right < outputs &&
454
(unsigned int) monitors->top < outputs &&
455
(unsigned int) monitors->bottom < outputs)
457
CompRect fsRect (screen->outputDevs ()[monitors->left].x1 (),
458
screen->outputDevs ()[monitors->top].y1 (),
459
screen->outputDevs ()[monitors->right].x2 (),
460
screen->outputDevs ()[monitors->bottom].y2 ());
462
if (fsRect.x1 () < fsRect.x2 () && fsRect.y1 () < fsRect.y2 ())
464
fullscreenMonitorsSet = true;
465
fullscreenMonitorRect = fsRect;
469
if (fullscreenMonitorsSet)
473
data[0] = monitors->top;
474
data[1] = monitors->bottom;
475
data[2] = monitors->left;
476
data[3] = monitors->right;
478
XChangeProperty (screen->dpy (), id, Atoms::wmFullscreenMonitors,
479
XA_CARDINAL, 32, PropModeReplace,
480
(unsigned char *) data, 4);
482
else if (hadFsMonitors)
484
XDeleteProperty (screen->dpy (), id, Atoms::wmFullscreenMonitors);
487
if (state & CompWindowStateFullscreenMask)
488
if (fullscreenMonitorsSet || hadFsMonitors)
489
window->updateAttributes (CompStackingUpdateModeNone);
493
CompWindow::changeState (unsigned int newState)
495
unsigned int oldState;
497
if (priv->state == newState)
500
oldState = priv->state;
501
priv->state = newState;
507
screen->priv->setWindowState (priv->state, priv->id);
509
stateChangeNotify (oldState);
510
screen->matchPropertyChanged (this);
514
setWindowActions (CompScreen *s,
515
unsigned int actions,
521
if (actions & CompWindowActionMoveMask)
522
data[i++] = Atoms::winActionMove;
523
if (actions & CompWindowActionResizeMask)
524
data[i++] = Atoms::winActionResize;
525
if (actions & CompWindowActionStickMask)
526
data[i++] = Atoms::winActionStick;
527
if (actions & CompWindowActionMinimizeMask)
528
data[i++] = Atoms::winActionMinimize;
529
if (actions & CompWindowActionMaximizeHorzMask)
530
data[i++] = Atoms::winActionMaximizeHorz;
531
if (actions & CompWindowActionMaximizeVertMask)
532
data[i++] = Atoms::winActionMaximizeVert;
533
if (actions & CompWindowActionFullscreenMask)
534
data[i++] = Atoms::winActionFullscreen;
535
if (actions & CompWindowActionCloseMask)
536
data[i++] = Atoms::winActionClose;
537
if (actions & CompWindowActionShadeMask)
538
data[i++] = Atoms::winActionShade;
539
if (actions & CompWindowActionChangeDesktopMask)
540
data[i++] = Atoms::winActionChangeDesktop;
541
if (actions & CompWindowActionAboveMask)
542
data[i++] = Atoms::winActionAbove;
543
if (actions & CompWindowActionBelowMask)
544
data[i++] = Atoms::winActionBelow;
546
XChangeProperty (s->dpy (), id, Atoms::wmAllowedActions,
547
XA_ATOM, 32, PropModeReplace,
548
(unsigned char *) data, i);
552
CompWindow::recalcActions ()
554
unsigned int actions = 0;
555
unsigned int setActions, clearActions;
557
switch (priv->type) {
558
case CompWindowTypeFullscreenMask:
559
case CompWindowTypeNormalMask:
561
CompWindowActionMaximizeHorzMask |
562
CompWindowActionMaximizeVertMask |
563
CompWindowActionFullscreenMask |
564
CompWindowActionMoveMask |
565
CompWindowActionResizeMask |
566
CompWindowActionStickMask |
567
CompWindowActionMinimizeMask |
568
CompWindowActionCloseMask |
569
CompWindowActionChangeDesktopMask;
571
case CompWindowTypeUtilMask:
572
case CompWindowTypeMenuMask:
573
case CompWindowTypeToolbarMask:
575
CompWindowActionMoveMask |
576
CompWindowActionResizeMask |
577
CompWindowActionStickMask |
578
CompWindowActionCloseMask |
579
CompWindowActionChangeDesktopMask;
581
case CompWindowTypeDialogMask:
582
case CompWindowTypeModalDialogMask:
584
CompWindowActionMaximizeHorzMask |
585
CompWindowActionMaximizeVertMask |
586
CompWindowActionMoveMask |
587
CompWindowActionResizeMask |
588
CompWindowActionStickMask |
589
CompWindowActionCloseMask |
590
CompWindowActionChangeDesktopMask;
592
/* allow minimization for dialog windows if they
593
a) are not a transient (transients can be minimized
595
b) don't have the skip taskbar hint set (as those
596
have no target to be minimized to)
598
if (!priv->transientFor &&
599
!(priv->state & CompWindowStateSkipTaskbarMask))
601
actions |= CompWindowActionMinimizeMask;
608
actions |= CompWindowActionShadeMask;
610
actions |= (CompWindowActionAboveMask | CompWindowActionBelowMask);
612
switch (priv->wmType) {
613
case CompWindowTypeNormalMask:
614
actions |= CompWindowActionFullscreenMask |
615
CompWindowActionMinimizeMask;
620
if (priv->sizeHints.min_width == priv->sizeHints.max_width &&
621
priv->sizeHints.min_height == priv->sizeHints.max_height)
622
actions &= ~(CompWindowActionResizeMask |
623
CompWindowActionMaximizeHorzMask |
624
CompWindowActionMaximizeVertMask |
625
CompWindowActionFullscreenMask);
627
if (!(priv->mwmFunc & MwmFuncAll))
629
if (!(priv->mwmFunc & MwmFuncResize))
630
actions &= ~(CompWindowActionResizeMask |
631
CompWindowActionMaximizeHorzMask |
632
CompWindowActionMaximizeVertMask |
633
CompWindowActionFullscreenMask);
635
if (!(priv->mwmFunc & MwmFuncMove))
636
actions &= ~(CompWindowActionMoveMask |
637
CompWindowActionMaximizeHorzMask |
638
CompWindowActionMaximizeVertMask |
639
CompWindowActionFullscreenMask);
641
if (!(priv->mwmFunc & MwmFuncIconify))
642
actions &= ~CompWindowActionMinimizeMask;
644
if (!(priv->mwmFunc & MwmFuncClose))
645
actions &= ~CompWindowActionCloseMask;
648
getAllowedActions (setActions, clearActions);
649
actions &= ~clearActions;
650
actions |= setActions;
652
if (actions != priv->actions)
654
priv->actions = actions;
655
setWindowActions (screen, actions, priv->id);
660
CompWindow::getAllowedActions (unsigned int &setActions,
661
unsigned int &clearActions)
663
WRAPABLE_HND_FUNC (1, getAllowedActions, setActions, clearActions)
670
CompWindow::constrainWindowState (unsigned int state,
671
unsigned int actions)
673
if (!(actions & CompWindowActionMaximizeHorzMask))
674
state &= ~CompWindowStateMaximizedHorzMask;
676
if (!(actions & CompWindowActionMaximizeVertMask))
677
state &= ~CompWindowStateMaximizedVertMask;
679
if (!(actions & CompWindowActionShadeMask))
680
state &= ~CompWindowStateShadedMask;
682
if (!(actions & CompWindowActionFullscreenMask))
683
state &= ~CompWindowStateFullscreenMask;
689
PrivateWindow::windowTypeFromString (const char *str)
691
if (strcasecmp (str, "desktop") == 0)
692
return CompWindowTypeDesktopMask;
693
else if (strcasecmp (str, "dock") == 0)
694
return CompWindowTypeDockMask;
695
else if (strcasecmp (str, "toolbar") == 0)
696
return CompWindowTypeToolbarMask;
697
else if (strcasecmp (str, "menu") == 0)
698
return CompWindowTypeMenuMask;
699
else if (strcasecmp (str, "utility") == 0)
700
return CompWindowTypeUtilMask;
701
else if (strcasecmp (str, "splash") == 0)
702
return CompWindowTypeSplashMask;
703
else if (strcasecmp (str, "dialog") == 0)
704
return CompWindowTypeDialogMask;
705
else if (strcasecmp (str, "normal") == 0)
706
return CompWindowTypeNormalMask;
707
else if (strcasecmp (str, "dropdownmenu") == 0)
708
return CompWindowTypeDropdownMenuMask;
709
else if (strcasecmp (str, "popupmenu") == 0)
710
return CompWindowTypePopupMenuMask;
711
else if (strcasecmp (str, "tooltip") == 0)
712
return CompWindowTypeTooltipMask;
713
else if (strcasecmp (str, "notification") == 0)
714
return CompWindowTypeNotificationMask;
715
else if (strcasecmp (str, "combo") == 0)
716
return CompWindowTypeComboMask;
717
else if (strcasecmp (str, "dnd") == 0)
718
return CompWindowTypeDndMask;
719
else if (strcasecmp (str, "modaldialog") == 0)
720
return CompWindowTypeModalDialogMask;
721
else if (strcasecmp (str, "fullscreen") == 0)
722
return CompWindowTypeFullscreenMask;
723
else if (strcasecmp (str, "unknown") == 0)
724
return CompWindowTypeUnknownMask;
725
else if (strcasecmp (str, "any") == 0)
732
CompWindow::recalcType ()
738
if (!overrideRedirect () && priv->wmType == CompWindowTypeUnknownMask)
739
type = CompWindowTypeNormalMask;
741
if (priv->state & CompWindowStateFullscreenMask)
742
type = CompWindowTypeFullscreenMask;
744
if (type == CompWindowTypeNormalMask)
746
if (priv->transientFor)
747
type = CompWindowTypeDialogMask;
750
if (type == CompWindowTypeDockMask &&
751
(priv->state & CompWindowStateBelowMask))
753
type = CompWindowTypeNormalMask;
756
if ((type & (CompWindowTypeNormalMask | CompWindowTypeDialogMask)) &&
757
(priv->state & CompWindowStateModalMask))
759
type = CompWindowTypeModalDialogMask;
767
PrivateWindow::updateFrameWindow ()
770
unsigned int valueMask = CWX | CWY | CWWidth | CWHeight;
775
/* Flush any changes made to serverFrameGeometry or serverGeometry to the server
776
* since there is a race condition where geometries will go out-of-sync with
779
window->syncPosition ();
780
if (serverInput.left || serverInput.right || serverInput.top || serverInput.bottom)
782
int bw = serverGeometry.border () * 2;
784
xwc.x = serverGeometry.x () - serverInput.left;
785
xwc.y = serverGeometry.y () - serverInput.top;
786
xwc.width = serverGeometry.width () + serverInput.left + serverInput.right + bw;
787
xwc.height = serverGeometry.height () + serverInput.top + serverInput.bottom + bw;
790
height = serverInput.top + serverInput.bottom;
792
if (serverFrameGeometry.x () == xwc.x)
795
serverFrameGeometry.setX (xwc.x);
797
if (serverFrameGeometry.y () == xwc.y)
800
serverFrameGeometry.setY (xwc.y);
802
if (serverFrameGeometry.width () == xwc.width)
803
valueMask &= ~(CWWidth);
805
serverFrameGeometry.setWidth (xwc.width);
807
if (serverFrameGeometry.height () == xwc.height)
808
valueMask &= ~(CWHeight);
810
serverFrameGeometry.setHeight (xwc.height);
812
/* Geometry is the same, so we're not going to get a ConfigureNotify
813
* event when the window is configured, which means that other plugins
814
* won't know that the client, frame and wrapper windows got shifted
815
* around (and might result in display corruption, eg in OpenGL */
819
XWindowAttributes attrib;
820
unsigned int nchildren = 0;
821
Window rootRet = 0, parentRet = 0;
822
Window *children = NULL;
824
xev.type = ConfigureNotify;
825
xev.event = screen->root ();
826
xev.window = priv->serverFrame;
828
XGrabServer (screen->dpy ());
830
if (XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib))
834
xev.width = attrib.width;
835
xev.height = attrib.height;
836
xev.border_width = attrib.border_width;
839
/* We need to ensure that the stacking order is
840
* based on the current server stacking order so
841
* find the sibling to this window's frame in the
842
* server side stack and stack above that */
843
XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
847
for (unsigned int i = 0; i < nchildren; i++)
849
if (i + 1 == nchildren ||
850
children[i + 1] == ROOTPARENT (window))
852
xev.above = children[i];
862
xev.above = (window->serverPrev) ? ROOTPARENT (window->serverPrev) : None;
864
xev.override_redirect = priv->attrib.override_redirect;
868
gettimeofday (&lastConfigureRequest, NULL);
869
compiz::X11::PendingEvent::Ptr pc =
870
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
871
new compiz::X11::PendingConfigureEvent (
872
screen->dpy (), serverFrame, valueMask, &xwc)));
874
pendingConfigures.add (pc);
876
XSendEvent (screen->dpy (), screen->root (), false,
877
SubstructureNotifyMask, (XEvent *) &xev);
879
XUngrabServer (screen->dpy ());
880
XSync (screen->dpy (), false);
884
gettimeofday (&lastConfigureRequest, NULL);
885
compiz::X11::PendingEvent::Ptr pc =
886
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
887
new compiz::X11::PendingConfigureEvent (
888
screen->dpy (), serverFrame, valueMask, &xwc)));
890
pendingConfigures.add (pc);
891
XConfigureWindow (screen->dpy (), serverFrame, valueMask, &xwc);
895
XUnmapWindow (screen->dpy (), wrapper);
899
XMapWindow (screen->dpy (), wrapper);
900
XMoveResizeWindow (screen->dpy (), wrapper, serverInput.left, serverInput.top,
901
serverGeometry.width (), serverGeometry.height ());
903
XMoveResizeWindow (screen->dpy (), id, 0, 0,
904
serverGeometry.width (), serverGeometry.height ());
905
window->sendConfigureNotify ();
906
window->windowNotify (CompWindowNotifyFrameUpdate);
910
int bw = serverGeometry.border () * 2;
912
xwc.x = serverGeometry.x ();
913
xwc.y = serverGeometry.y ();
914
xwc.width = serverGeometry.width () + bw;
915
xwc.height = serverGeometry.height () + bw;
920
if (serverFrameGeometry.x () == xwc.x)
923
serverFrameGeometry.setX (xwc.x);
925
if (serverFrameGeometry.y () == xwc.y)
928
serverFrameGeometry.setY (xwc.y);
930
if (serverFrameGeometry.width () == xwc.width)
931
valueMask &= ~(CWWidth);
933
serverFrameGeometry.setWidth (xwc.width);
935
if (serverFrameGeometry.height () == xwc.height)
936
valueMask &= ~(CWHeight);
938
serverFrameGeometry.setHeight (xwc.height);
941
/* Geometry is the same, so we're not going to get a ConfigureNotify
942
* event when the window is configured, which means that other plugins
943
* won't know that the client, frame and wrapper windows got shifted
944
* around (and might result in display corruption, eg in OpenGL */
948
XWindowAttributes attrib;
949
unsigned int nchildren = 0;
950
Window rootRet = 0, parentRet = 0;
951
Window *children = NULL;
953
xev.type = ConfigureNotify;
954
xev.event = screen->root ();
955
xev.window = priv->serverFrame;
957
XGrabServer (screen->dpy ());
959
if (XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib))
963
xev.width = attrib.width;
964
xev.height = attrib.height;
965
xev.border_width = attrib.border_width;
968
/* We need to ensure that the stacking order is
969
* based on the current server stacking order so
970
* find the sibling to this window's frame in the
971
* server side stack and stack above that */
972
XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
976
for (unsigned int i = 0; i < nchildren; i++)
978
if (i + 1 == nchildren ||
979
children[i + 1] == ROOTPARENT (window))
981
xev.above = children[i];
991
xev.above = (window->serverPrev) ? ROOTPARENT (window->serverPrev) : None;
993
xev.override_redirect = priv->attrib.override_redirect;
997
XSendEvent (screen->dpy (), screen->root (), false,
998
SubstructureNotifyMask, (XEvent *) &xev);
1000
XUngrabServer (screen->dpy ());
1001
XSync (screen->dpy (), false);
1005
gettimeofday (&lastConfigureRequest, NULL);
1006
compiz::X11::PendingEvent::Ptr pc =
1007
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
1008
new compiz::X11::PendingConfigureEvent (
1009
screen->dpy (), serverFrame, valueMask, &xwc)));
1011
pendingConfigures.add (pc);
1012
XConfigureWindow (screen->dpy (), serverFrame, valueMask, &xwc);
1017
XUnmapWindow (screen->dpy (), wrapper);
1021
XMapWindow (screen->dpy (), wrapper);
1022
XMoveResizeWindow (screen->dpy (), wrapper, 0, 0,
1023
serverGeometry.width (), serverGeometry.height ());
1026
XMoveResizeWindow (screen->dpy (), id, 0, 0,
1027
serverGeometry.width (), serverGeometry.height ());
1028
window->sendConfigureNotify ();
1029
window->windowNotify (CompWindowNotifyFrameUpdate);
1031
window->recalcActions ();
1037
CompWindow::updateWindowOutputExtents ()
1039
CompWindowExtents output (priv->output);
1041
getOutputExtents (output);
1043
if (output.left != priv->output.left ||
1044
output.right != priv->output.right ||
1045
output.top != priv->output.top ||
1046
output.bottom != priv->output.bottom)
1048
priv->output = output;
1050
resizeNotify (0, 0, 0, 0);
1055
CompWindow::getOutputExtents (CompWindowExtents& output)
1057
WRAPABLE_HND_FUNC (0, getOutputExtents, output)
1066
PrivateWindow::rectsToRegion (unsigned int n, XRectangle *rects)
1071
for (unsigned int i = 0; i < n; i++)
1073
x1 = rects[i].x + priv->geometry.border ();
1074
y1 = rects[i].y + priv->geometry.border ();
1075
x2 = x1 + rects[i].width;
1076
y2 = y1 + rects[i].height;
1082
if (x2 > priv->width)
1084
if (y2 > priv->height)
1087
if (y1 < y2 && x1 < x2)
1089
x1 += priv->geometry.x ();
1090
y1 += priv->geometry.y ();
1091
x2 += priv->geometry.x ();
1092
y2 += priv->geometry.y ();
1094
ret += CompRect (x1, y1, x2 - x1, y2 - y1);
1101
/* TODO: This function should be able to check the XShape event
1102
* kind and only get/set shape rectangles for either ShapeInput
1103
* or ShapeBounding, but not both at the same time
1107
PrivateWindow::updateRegion ()
1109
XRectangle r, *boundingShapeRects = NULL;
1110
XRectangle *inputShapeRects = NULL;
1111
int nBounding = 0, nInput = 0;
1113
priv->region = CompRegion ();
1114
priv->inputRegion = CompRegion ();
1116
if (screen->XShape ())
1120
boundingShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
1121
ShapeBounding, &nBounding, &order);
1122
inputShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
1123
ShapeInput, &nInput, &order);
1127
r.x = -priv->attrib.border_width;
1128
r.y = -priv->attrib.border_width;
1129
r.width = priv->width + priv->attrib.border_width;
1130
r.height = priv->height + priv->attrib.border_width;
1134
boundingShapeRects = &r;
1140
inputShapeRects = &r;
1144
priv->region += rectsToRegion (nBounding, boundingShapeRects);
1145
priv->inputRegion += rectsToRegion (nInput, inputShapeRects);
1147
if (boundingShapeRects && boundingShapeRects != &r)
1148
XFree (boundingShapeRects);
1149
if (inputShapeRects && inputShapeRects != &r)
1150
XFree (inputShapeRects);
1152
window->updateFrameRegion ();
1156
CompWindow::updateStruts ()
1160
unsigned long n, left;
1161
unsigned char *data;
1162
bool hasOld, hasNew;
1163
CompStruts oldStrut, newStrut;
1169
oldStrut.left = priv->struts->left;
1170
oldStrut.right = priv->struts->right;
1171
oldStrut.top = priv->struts->top;
1172
oldStrut.bottom = priv->struts->bottom;
1181
newStrut.left.x = 0;
1182
newStrut.left.y = 0;
1183
newStrut.left.width = 0;
1184
newStrut.left.height = screen->height ();
1186
newStrut.right.x = screen->width ();
1187
newStrut.right.y = 0;
1188
newStrut.right.width = 0;
1189
newStrut.right.height = screen->height ();
1193
newStrut.top.width = screen->width ();
1194
newStrut.top.height = 0;
1196
newStrut.bottom.x = 0;
1197
newStrut.bottom.y = screen->height ();
1198
newStrut.bottom.width = screen->width ();
1199
newStrut.bottom.height = 0;
1201
result = XGetWindowProperty (screen->dpy (), priv->id,
1202
Atoms::wmStrutPartial,
1203
0L, 12L, false, XA_CARDINAL, &actual, &format,
1206
if (result == Success && data)
1208
unsigned long *struts = (unsigned long *) data;
1214
newStrut.left.y = struts[4];
1215
newStrut.left.width = struts[0];
1216
newStrut.left.height = struts[5] - newStrut.left.y + 1;
1218
newStrut.right.width = struts[1];
1219
newStrut.right.x = screen->width () - newStrut.right.width;
1220
newStrut.right.y = struts[6];
1221
newStrut.right.height = struts[7] - newStrut.right.y + 1;
1223
newStrut.top.x = struts[8];
1224
newStrut.top.width = struts[9] - newStrut.top.x + 1;
1225
newStrut.top.height = struts[2];
1227
newStrut.bottom.x = struts[10];
1228
newStrut.bottom.width = struts[11] - newStrut.bottom.x + 1;
1229
newStrut.bottom.height = struts[3];
1230
newStrut.bottom.y = screen->height () - newStrut.bottom.height;
1238
result = XGetWindowProperty (screen->dpy (), priv->id,
1240
0L, 4L, false, XA_CARDINAL,
1241
&actual, &format, &n, &left, &data);
1243
if (result == Success && data)
1245
unsigned long *struts = (unsigned long *) data;
1251
newStrut.left.x = 0;
1252
newStrut.left.width = struts[0];
1254
newStrut.right.width = struts[1];
1255
newStrut.right.x = screen->width () - newStrut.right.width;
1258
newStrut.top.height = struts[2];
1260
newStrut.bottom.height = struts[3];
1261
newStrut.bottom.y = screen->height () - newStrut.bottom.height;
1270
int strutX1, strutY1, strutX2, strutY2;
1273
/* applications expect us to clip struts to xinerama edges */
1274
for (unsigned int i = 0;
1275
i < screen->screenInfo ().size (); i++)
1277
x1 = screen->screenInfo ()[i].x_org;
1278
y1 = screen->screenInfo ()[i].y_org;
1279
x2 = x1 + screen->screenInfo ()[i].width;
1280
y2 = y1 + screen->screenInfo ()[i].height;
1282
strutX1 = newStrut.left.x;
1283
strutX2 = strutX1 + newStrut.left.width;
1284
strutY1 = newStrut.left.y;
1285
strutY2 = strutY1 + newStrut.left.height;
1287
if (strutX2 > x1 && strutX2 <= x2 &&
1288
strutY1 < y2 && strutY2 > y1)
1290
newStrut.left.x = x1;
1291
newStrut.left.width = strutX2 - x1;
1294
strutX1 = newStrut.right.x;
1295
strutX2 = strutX1 + newStrut.right.width;
1296
strutY1 = newStrut.right.y;
1297
strutY2 = strutY1 + newStrut.right.height;
1299
if (strutX1 > x1 && strutX1 <= x2 &&
1300
strutY1 < y2 && strutY2 > y1)
1302
newStrut.right.x = strutX1;
1303
newStrut.right.width = x2 - strutX1;
1306
strutX1 = newStrut.top.x;
1307
strutX2 = strutX1 + newStrut.top.width;
1308
strutY1 = newStrut.top.y;
1309
strutY2 = strutY1 + newStrut.top.height;
1311
if (strutX1 < x2 && strutX2 > x1 &&
1312
strutY2 > y1 && strutY2 <= y2)
1314
newStrut.top.y = y1;
1315
newStrut.top.height = strutY2 - y1;
1318
strutX1 = newStrut.bottom.x;
1319
strutX2 = strutX1 + newStrut.bottom.width;
1320
strutY1 = newStrut.bottom.y;
1321
strutY2 = strutY1 + newStrut.bottom.height;
1323
if (strutX1 < x2 && strutX2 > x1 &&
1324
strutY1 > y1 && strutY1 <= y2)
1326
newStrut.bottom.y = strutY1;
1327
newStrut.bottom.height = y2 - strutY1;
1332
if (hasOld != hasNew ||
1333
(hasNew && hasOld &&
1334
memcmp (&newStrut, &oldStrut, sizeof (CompStruts))))
1340
priv->struts = (CompStruts *) malloc (sizeof (CompStruts));
1345
*priv->struts = newStrut;
1349
free (priv->struts);
1350
priv->struts = NULL;
1360
CompWindow::incrementDestroyReference ()
1362
priv->destroyRefCnt++;
1366
CompWindow::destroy ()
1370
CompWindow *oldServerNext, *oldServerPrev, *oldNext, *oldPrev;
1371
StackDebugger *dbg = StackDebugger::Default ();
1373
windowNotify (CompWindowNotifyBeforeDestroy);
1375
/* Don't allow frame windows to block input */
1376
XUnmapWindow (screen->dpy (), priv->serverFrame);
1377
XUnmapWindow (screen->dpy (), priv->wrapper);
1379
oldServerNext = serverNext;
1380
oldServerPrev = serverPrev;
1384
/* This is where things get tricky ... it is possible
1385
* to receive a ConfigureNotify relative to a frame window
1386
* for a destroyed window in case we process a ConfigureRequest
1387
* for the destroyed window and then a DestroyNotify for it directly
1388
* afterwards. In that case, we will receive the ConfigureNotify
1389
* for the XConfigureWindow request we made relative to that frame
1390
* window. Because of this, we must keep the frame window in the stack
1391
* as a new toplevel window so that the ConfigureNotify will be processed
1392
* properly until it too receives a DestroyNotify */
1394
if (priv->serverFrame)
1396
XWindowAttributes attrib;
1398
/* It's possible that the frame window was already destroyed because
1399
* the client was unreparented before it was destroyed (eg
1400
* UnmapNotify before DestroyNotify). In that case the frame window
1401
* is going to be an invalid window but since we haven't received
1402
* a DestroyNotify for it yet, it is possible that restacking
1403
* operations could occurr relative to it so we need to hold it
1404
* in the stack for now. Ensure that it is marked override redirect */
1405
XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib);
1407
/* Put the frame window "above" the client window
1409
CoreWindow *cw = new CoreWindow (priv->serverFrame);
1410
cw->manage (priv->id, attrib);
1411
screen->priv->createdWindows.remove (cw);
1415
/* Immediately unhook the window once destroyed
1416
* as the stacking order will be invalid if we don't
1417
* and will continue to be invalid for the period
1418
* that we keep it around in the stack. Instead, push
1419
* it to another stack and keep the next and prev members
1420
* in tact, letting plugins sort out where those windows
1421
* might be in case they need to use them relative to
1424
screen->unhookWindow (this);
1425
screen->unhookServerWindow (this);
1427
/* We must immediately insert the window into the debugging
1430
dbg->removeServerWindow (id ());
1432
/* Unhooking the window will also NULL the next/prev
1433
* linked list links but we don't want that so don't
1438
serverNext = oldServerNext;
1439
serverPrev = oldServerPrev;
1441
screen->priv->destroyedWindows.push_back (this);
1443
/* We must set the xid of this window
1444
* to zero as it no longer references
1449
priv->serverFrame = 0;
1450
priv->managed = false;
1453
priv->destroyRefCnt--;
1454
if (priv->destroyRefCnt)
1457
if (!priv->destroyed)
1459
if (!priv->serverFrame)
1461
StackDebugger *dbg = StackDebugger::Default ();
1464
dbg->addDestroyedFrame (priv->serverId);
1467
priv->destroyed = true;
1468
screen->priv->pendingDestroys++;
1474
CompWindow::sendConfigureNotify ()
1476
XConfigureEvent xev;
1477
XWindowAttributes attrib;
1478
unsigned int nchildren;
1479
Window rootRet, parentRet;
1482
xev.type = ConfigureNotify;
1483
xev.event = priv->id;
1484
xev.window = priv->id;
1486
/* in order to avoid race conditions we must use the current
1487
* server configuration */
1489
XGrabServer (screen->dpy ());
1490
XSync (screen->dpy (), false);
1492
if (XGetWindowAttributes (screen->dpy (), priv->id, &attrib))
1496
xev.width = attrib.width;
1497
xev.height = attrib.height;
1498
xev.border_width = attrib.border_width;
1503
XWindowAttributes fAttrib;
1504
XWindowAttributes wAttrib;
1506
/* Add offset between wrapper and client */
1507
if (XGetWindowAttributes (screen->dpy (), priv->wrapper, &wAttrib))
1513
/* Add offset between frame and client */
1514
if (XGetWindowAttributes (screen->dpy (), priv->frame, &fAttrib))
1521
/* We need to ensure that the stacking order is
1522
* based on the current server stacking order so
1523
* find the sibling to this window's frame in the
1524
* server side stack and stack above that */
1525
XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
1529
for (unsigned int i = 0; i < nchildren; i++)
1531
if (i + 1 == nchildren ||
1532
children[i + 1] == ROOTPARENT (this))
1534
xev.above = children[i];
1544
xev.above = (serverPrev) ? ROOTPARENT (serverPrev) : None;
1545
xev.override_redirect = priv->attrib.override_redirect;
1547
XSendEvent (screen->dpy (), priv->id, false,
1548
StructureNotifyMask, (XEvent *) &xev);
1551
XUngrabServer (screen->dpy ());
1552
XSync (screen->dpy (), false);
1558
windowNotify (CompWindowNotifyBeforeMap);
1562
if (priv->pendingMaps > 0)
1563
priv->pendingMaps = 0;
1565
priv->mapNum = screen->priv->mapNum++;
1568
screen->updateWorkarea ();
1570
if (windowClass () == InputOnly)
1573
priv->unmapRefCnt = 1;
1575
priv->attrib.map_state = IsViewable;
1577
if (!overrideRedirect ())
1578
screen->priv->setWmState (NormalState, priv->id);
1580
priv->invisible = true;
1583
priv->lastPong = screen->priv->lastPing;
1585
priv->updateRegion ();
1586
priv->updateSize ();
1588
screen->priv->updateClientList ();
1590
if (priv->type & CompWindowTypeDesktopMask)
1591
screen->priv->desktopWindowCount++;
1593
if (priv->protocols & CompWindowProtocolSyncRequestMask)
1596
sendConfigureNotify ();
1599
if (!overrideRedirect ())
1604
priv->geometry.setHeight (priv->geometry.height () + 1);
1605
resize (priv->geometry.x (), priv->geometry.y (), priv->geometry.width (),
1606
priv->geometry.height () - 1, priv->geometry.border ());
1611
windowNotify (CompWindowNotifyMap);
1615
CompWindow::incrementUnmapReference ()
1617
priv->unmapRefCnt++;
1621
CompWindow::unmap ()
1623
windowNotify (CompWindowNotifyBeforeUnmap);
1628
/* Even though we're still keeping the backing
1629
* pixmap of the window around, it's safe to
1630
* unmap the frame window since there's no use
1631
* for it at this point anyways and it just blocks
1634
XUnmapWindow (screen->dpy (), priv->wrapper);
1635
XUnmapWindow (screen->dpy (), priv->serverFrame);
1637
priv->unmapRefCnt--;
1638
if (priv->unmapRefCnt > 0)
1641
if (priv->unmanaging)
1645
int gravity = priv->sizeHints.win_gravity;
1647
/* revert gravity adjustment made at MapNotify time */
1648
xwc.x = priv->serverGeometry.x ();
1649
xwc.y = priv->serverGeometry.y ();
1653
xwcm = priv->adjustConfigureRequestForGravity (&xwc,
1658
configureXWindow (xwcm, &xwc);
1660
priv->unmanaging = false;
1663
if (priv->serverFrame)
1664
priv->unreparent ();
1667
screen->updateWorkarea ();
1669
if (priv->attrib.map_state != IsViewable)
1672
if (priv->type == CompWindowTypeDesktopMask)
1673
screen->priv->desktopWindowCount--;
1675
priv->attrib.map_state = IsUnmapped;
1677
priv->invisible = true;
1679
if (priv->shaded && priv->height)
1680
resize (priv->attrib.x, priv->attrib.y,
1681
priv->attrib.width, ++priv->attrib.height - 1,
1682
priv->attrib.border_width);
1684
screen->priv->updateClientList ();
1686
windowNotify (CompWindowNotifyUnmap);
1690
PrivateWindow::withdraw ()
1692
if (!attrib.override_redirect)
1693
screen->priv->setWmState (WithdrawnState, id);
1696
unmanaging = managed;
1701
PrivateWindow::restack (Window aboveId)
1703
if (aboveId && (aboveId == id || aboveId == serverFrame))
1704
// Don't try to raise a window above itself
1706
else if (window->prev)
1708
if (aboveId && (aboveId == window->prev->id () ||
1709
aboveId == window->prev->priv->frame))
1712
else if (aboveId == None && !window->next)
1715
if (aboveId && !screen->findTopLevelWindow (aboveId, true))
1720
screen->unhookWindow (window);
1721
screen->insertWindow (window, aboveId);
1723
/* Update the server side window list for
1724
* override redirect windows immediately
1725
* since there is no opportunity to update
1726
* the server side list when we configure them
1727
* since we never get a ConfigureRequest for those */
1728
if (attrib.override_redirect != 0)
1730
StackDebugger *dbg = StackDebugger::Default ();
1732
screen->unhookServerWindow (window);
1733
screen->insertServerWindow (window, aboveId);
1736
dbg->overrideRedirectRestack (window->id (), aboveId);
1739
screen->priv->updateClientList ();
1741
window->windowNotify (CompWindowNotifyRestack);
1747
CompWindow::resize (XWindowAttributes attr)
1749
return resize (Geometry (attr.x, attr.y, attr.width, attr.height,
1750
attr.border_width));
1754
CompWindow::resize (int x,
1760
return resize (Geometry (x, y, width, height, border));
1764
CompWindow::resize (CompWindow::Geometry gm)
1766
/* Input extents are now the last thing sent
1767
* from the server. This might not work in some
1768
* cases though because setWindowFrameExtents may
1769
* be called more than once in an event processing
1770
* cycle so every set of input extents up until the
1771
* last one will be invalid. The real solution
1772
* here is to handle ConfigureNotify events on
1773
* frame windows and client windows separately */
1775
priv->input = priv->serverInput;
1777
if (priv->geometry.width () != gm.width () ||
1778
priv->geometry.height () != gm.height () ||
1779
priv->geometry.border () != gm.border ())
1782
int dx, dy, dwidth, dheight;
1784
pw = gm.width () + gm.border () * 2;
1785
ph = gm.height () + gm.border () * 2;
1790
dx = gm.x () - priv->geometry.x ();
1791
dy = gm.y () - priv->geometry.y ();
1792
dwidth = gm.width () - priv->geometry.width ();
1793
dheight = gm.height () - priv->geometry.height ();
1795
priv->geometry.set (gm.x (), gm.y (),
1796
gm.width (), gm.height (),
1803
priv->updateRegion ();
1805
resizeNotify (dx, dy, dwidth, dheight);
1807
priv->invisible = WINDOW_INVISIBLE (priv);
1809
else if (priv->geometry.x () != gm.x () || priv->geometry.y () != gm.y ())
1813
dx = gm.x () - priv->geometry.x ();
1814
dy = gm.y () - priv->geometry.y ();
1816
priv->geometry.setX (gm.x ());
1817
priv->geometry.setY (gm.y ());
1819
priv->region.translate (dx, dy);
1820
priv->inputRegion.translate (dx, dy);
1821
if (!priv->frameRegion.isEmpty ())
1822
priv->frameRegion.translate (dx, dy);
1824
priv->invisible = WINDOW_INVISIBLE (priv);
1826
moveNotify (dx, dy, true);
1829
updateFrameRegion ();
1835
syncValueIncrement (XSyncValue *value)
1840
XSyncIntToValue (&one, 1);
1841
XSyncValueAdd (value, *value, one, &overflow);
1845
PrivateWindow::initializeSyncCounter ()
1847
XSyncAlarmAttributes values;
1850
unsigned long n, left;
1851
unsigned char *data;
1854
return syncAlarm != None;
1856
if (!(protocols & CompWindowProtocolSyncRequestMask))
1859
result = XGetWindowProperty (screen->dpy (), id,
1860
Atoms::wmSyncRequestCounter,
1861
0L, 1L, false, XA_CARDINAL, &actual, &format,
1864
if (result == Success && n && data)
1866
unsigned long *counter = (unsigned long *) data;
1868
syncCounter = *counter;
1872
XSyncIntsToValue (&syncValue, (unsigned int) rand (), 0);
1873
XSyncSetCounter (screen->dpy (),
1877
syncValueIncrement (&syncValue);
1879
values.events = true;
1881
values.trigger.counter = syncCounter;
1882
values.trigger.wait_value = syncValue;
1884
values.trigger.value_type = XSyncAbsolute;
1885
values.trigger.test_type = XSyncPositiveComparison;
1887
XSyncIntToValue (&values.delta, 1);
1889
values.events = true;
1891
CompScreen::checkForError (screen->dpy ());
1893
/* Note that by default, the alarm increments the trigger value
1894
* when it fires until the condition (counter.value < trigger.value)
1897
syncAlarm = XSyncCreateAlarm (screen->dpy (),
1906
if (CompScreen::checkForError (screen->dpy ()))
1909
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
1912
else if (result == Success && data)
1921
CompWindow::sendSyncRequest ()
1923
XClientMessageEvent xev;
1928
if (!priv->initializeSyncCounter ())
1931
xev.type = ClientMessage;
1932
xev.window = priv->id;
1933
xev.message_type = Atoms::wmProtocols;
1935
xev.data.l[0] = Atoms::wmSyncRequest;
1936
xev.data.l[1] = CurrentTime;
1937
xev.data.l[2] = XSyncValueLow32 (priv->syncValue);
1938
xev.data.l[3] = XSyncValueHigh32 (priv->syncValue);
1941
syncValueIncrement (&priv->syncValue);
1943
XSendEvent (screen->dpy (), priv->id, false, 0, (XEvent *) &xev);
1945
priv->syncWait = true;
1946
priv->syncGeometry = priv->serverGeometry;
1948
if (!priv->syncWaitTimer.active ())
1949
priv->syncWaitTimer.start ();
1953
PrivateWindow::configure (XConfigureEvent *ce)
1955
unsigned int valueMask = 0;
1960
/* remove configure event from pending configures */
1961
if (priv->geometry.x () != ce->x)
1964
if (priv->geometry.y () != ce->y)
1967
if (priv->geometry.width () != ce->width)
1968
valueMask |= CWWidth;
1970
if (priv->geometry.height () != ce->height)
1971
valueMask |= CWHeight;
1973
if (priv->geometry.border () != ce->border_width)
1974
valueMask |= CWBorderWidth;
1976
if (ROOTPARENT (window->prev) != ce->above)
1977
valueMask |= CWSibling | CWStackMode;
1979
priv->attrib.override_redirect = ce->override_redirect;
1981
priv->frameGeometry.set (ce->x, ce->y, ce->width,
1982
ce->height, ce->border_width);
1985
priv->syncGeometry.set (ce->x, ce->y, ce->width, ce->height,
1989
if (ce->override_redirect)
1991
priv->serverGeometry.set (ce->x, ce->y, ce->width, ce->height,
1995
window->resize (ce->x, ce->y, ce->width, ce->height, ce->border_width);
1998
if (ce->event == screen->root ())
1999
priv->restack (ce->above);
2003
PrivateWindow::configureFrame (XConfigureEvent *ce)
2005
int x, y, width, height;
2007
unsigned int valueMask = 0;
2012
/* remove configure event from pending configures */
2013
if (priv->frameGeometry.x () != ce->x)
2016
if (priv->frameGeometry.y () != ce->y)
2019
if (priv->frameGeometry.width () != ce->width)
2020
valueMask |= CWWidth;
2022
if (priv->frameGeometry.height () != ce->height)
2023
valueMask |= CWHeight;
2025
if (priv->frameGeometry.border () != ce->border_width)
2026
valueMask |= CWBorderWidth;
2030
if (ROOTPARENT (window->prev) != ce->above)
2031
valueMask |= CWSibling | CWStackMode;
2036
valueMask |= CWSibling | CWStackMode;
2039
if (!pendingConfigures.match ((XEvent *) ce))
2041
compLogMessage ("core", CompLogLevelWarn, "unhandled ConfigureNotify on 0x%x!", serverFrame);
2042
compLogMessage ("core", CompLogLevelWarn, "this should never happen. you should "\
2043
"probably file a bug about this.");
2047
pendingConfigures = compiz::X11::PendingEventQueue (screen->dpy ());
2051
/* subtract the input extents last sent to the
2052
* server to calculate the client size and then
2053
* re-sync the input extents and extents last
2054
* sent to server on resize () */
2056
x = ce->x + priv->serverInput.left;
2057
y = ce->y + priv->serverInput.top;
2058
width = ce->width - priv->serverGeometry.border () * 2 - priv->serverInput.left - priv->serverInput.right;
2059
height = ce->height - priv->serverGeometry.border () * 2 - priv->serverInput.top - priv->serverInput.bottom;
2061
/* set the frame geometry */
2062
priv->frameGeometry.set (ce->x, ce->y, ce->width, ce->height, ce->border_width);
2066
priv->syncGeometry.set (x, y, width, height, ce->border_width);
2068
window->resize (x, y, width, height, ce->border_width);
2070
if (priv->restack (ce->above))
2071
priv->updatePassiveButtonGrabs ();
2073
above = screen->findWindow (ce->above);
2076
above->priv->updatePassiveButtonGrabs ();
2078
if (!pendingConfigures.pending ())
2080
/* Tell plugins its ok to start doing stupid things again but
2081
* obviously FIXME */
2082
CompOption::Vector options;
2083
CompOption::Value v;
2085
options.push_back (CompOption ("window", CompOption::TypeInt));
2087
options.back ().set (v);
2088
options.push_back (CompOption ("active", CompOption::TypeInt));
2090
options.back ().set (v);
2092
/* Notify other plugins that it is unsafe to change geometry or serverGeometry
2093
* FIXME: That API should not be accessible to plugins, this is a hack to avoid
2096
screen->handleCompizEvent ("core", "lock_position", options);
2101
PrivateWindow::circulate (XCirculateEvent *ce)
2105
if (ce->place == PlaceOnTop)
2106
newAboveId = screen->priv->getTopWindow ();
2110
priv->restack (newAboveId);
2114
CompWindow::move (int dx,
2120
/* Don't allow window movement to overwrite working geometries
2121
* last received from the server if we know there are pending
2122
* ConfigureNotify events on this window. That's a clunky workaround
2123
* and a FIXME in any case, however, until we can break the API
2124
* and remove CompWindow::move, this will need to be the case */
2126
if (!priv->pendingConfigures.pending ())
2128
priv->geometry.setX (priv->geometry.x () + dx);
2129
priv->geometry.setY (priv->geometry.y () + dy);
2130
priv->frameGeometry.setX (priv->frameGeometry.x () + dx);
2131
priv->frameGeometry.setY (priv->frameGeometry.y () + dy);
2133
priv->pendingPositionUpdates = true;
2135
priv->region.translate (dx, dy);
2136
priv->inputRegion.translate (dx, dy);
2137
if (!priv->frameRegion.isEmpty ())
2138
priv->frameRegion.translate (dx, dy);
2140
priv->invisible = WINDOW_INVISIBLE (priv);
2142
moveNotify (dx, dy, immediate);
2147
unsigned int valueMask = CWX | CWY;
2148
struct timeval tv, old;
2149
compLogMessage ("core", CompLogLevelDebug, "pending configure notifies on 0x%x,"\
2150
"moving window asyncrhonously!", (unsigned int) priv->serverId);
2152
old = priv->lastConfigureRequest;
2153
gettimeofday (&tv, NULL);
2155
xwc.x = priv->serverGeometry.x () + dx;
2156
xwc.y = priv->serverGeometry.y () + dy;
2158
configureXWindow (valueMask, &xwc);
2160
priv->lastConfigureRequest = old;
2162
/* FIXME: This is a hack to avoid performance regressions
2163
* and must be removed in 0.9.6 */
2164
if (tv.tv_usec - priv->lastConfigureRequest.tv_usec > 300000)
2166
compLogMessage ("core", CompLogLevelWarn, "failed to receive ConfigureNotify event from request at %i (now: %i)\n",
2167
priv->lastConfigureRequest.tv_usec, tv.tv_usec);
2168
priv->pendingConfigures = compiz::X11::PendingEventQueue (screen->dpy ());
2175
compiz::X11::PendingEventQueue::pending ()
2177
return !mEvents.empty ();
2181
compiz::X11::PendingEventQueue::add (PendingEvent::Ptr p)
2183
mEvents.push_back (p);
2187
compiz::X11::PendingEventQueue::removeIfMatching (const PendingEvent::Ptr &p, XEvent *event)
2189
return p->match (event);
2193
compiz::X11::PendingEventQueue::match (XEvent *event)
2195
unsigned int lastSize = mEvents.size ();
2197
mEvents.erase (std::remove_if (mEvents.begin (), mEvents.end (),
2198
boost::bind (&compiz::X11::PendingEventQueue::removeIfMatching, this, _1, event)), mEvents.end ());
2200
return lastSize != mEvents.size ();
2204
compiz::X11::PendingEventQueue::forEachIf (boost::function<bool (compiz::X11::PendingEvent::Ptr)> f)
2206
foreach (compiz::X11::PendingEvent::Ptr p, mEvents)
2215
compiz::X11::PendingEventQueue::PendingEventQueue (Display *d)
2219
compiz::X11::PendingEventQueue::~PendingEventQueue ()
2224
compiz::X11::PendingEvent::getEventWindow (XEvent *event)
2226
return event->xany.window;
2230
compiz::X11::PendingEvent::match (XEvent *event)
2232
if (event->xany.serial != mSerial)
2234
if (getEventWindow (event)!= mWindow)
2240
compiz::X11::PendingEvent::PendingEvent (Display *d, Window w) :
2241
mSerial (XNextRequest (d)),
2246
compiz::X11::PendingEvent::~PendingEvent ()
2251
compiz::X11::PendingConfigureEvent::getEventWindow (XEvent *event)
2253
return event->xconfigure.window;
2257
compiz::X11::PendingConfigureEvent::matchVM (unsigned int valueMask)
2259
return valueMask & mValueMask;
2263
compiz::X11::PendingConfigureEvent::match (XEvent *event)
2265
XConfigureEvent *ce = (XConfigureEvent *) event;
2266
bool matched = true;
2268
if (!compiz::X11::PendingEvent::match (event))
2271
if (mValueMask & CWX)
2272
if (ce->x != mXwc.x)
2275
if (mValueMask & CWY)
2276
if (ce->y != mXwc.y)
2279
if (mValueMask & CWWidth)
2280
if (ce->width != mXwc.width)
2283
if (mValueMask & CWHeight)
2284
if (ce->height != mXwc.height)
2287
if (mValueMask & CWBorderWidth)
2288
if (ce->border_width != mXwc.border_width)
2291
if (mValueMask & (CWStackMode | CWSibling))
2292
if (ce->above != mXwc.sibling)
2295
/* Remove events from the queue
2296
* even if they didn't match what
2297
* we expected them to be, but still
2298
* complain about it */
2301
compLogMessage ("core", CompLogLevelWarn, "no exact match for ConfigureNotify on 0x%x!", mWindow);
2302
compLogMessage ("core", CompLogLevelWarn, "expected the following changes:");
2303
if (mValueMask & CWX)
2304
compLogMessage ("core", CompLogLevelWarn, "x: %i", mXwc.x);
2305
if (mValueMask & CWY)
2306
compLogMessage ("core", CompLogLevelWarn, "y: %i", mXwc.y);
2307
if (mValueMask & CWWidth)
2308
compLogMessage ("core", CompLogLevelWarn, "width: %i", mXwc.width);
2309
if (mValueMask & CWHeight)
2310
compLogMessage ("core", CompLogLevelWarn, "height: %i", mXwc.height);
2311
if (mValueMask & CWBorderWidth)
2312
compLogMessage ("core", CompLogLevelWarn, "border: %i", mXwc.border_width);
2313
if (mValueMask & (CWStackMode | CWSibling))
2314
compLogMessage ("core", CompLogLevelWarn, "sibling: 0x%x", mXwc.sibling);
2316
compLogMessage ("core", CompLogLevelWarn, "instead got:");
2317
compLogMessage ("core", CompLogLevelWarn, "x: %i", ce->x);
2318
compLogMessage ("core", CompLogLevelWarn, "y: %i", ce->y);
2319
compLogMessage ("core", CompLogLevelWarn, "width: %i", ce->width);
2320
compLogMessage ("core", CompLogLevelWarn, "height: %i", ce->height);
2321
compLogMessage ("core", CompLogLevelWarn, "above: %i", ce->above);
2322
compLogMessage ("core", CompLogLevelWarn, "this should never happen. you should "\
2323
"probably file a bug about this.");
2329
compiz::X11::PendingConfigureEvent::PendingConfigureEvent (Display *d,
2331
unsigned int valueMask,
2332
XWindowChanges *xwc) :
2333
compiz::X11::PendingEvent::PendingEvent (d, w),
2334
mValueMask (valueMask),
2337
CompOption::Vector options;
2338
CompOption::Value v;
2340
options.push_back (CompOption ("window", CompOption::TypeInt));
2342
options.back ().set (v);
2343
options.push_back (CompOption ("active", CompOption::TypeInt));
2345
options.back ().set (v);
2347
/* Notify other plugins that it is unsafe to change geometry or serverGeometry
2348
* FIXME: That API should not be accessible to plugins, this is a hack to avoid
2351
screen->handleCompizEvent ("core", "lock_position", options);
2354
compiz::X11::PendingConfigureEvent::~PendingConfigureEvent ()
2359
CompWindow::syncPosition ()
2361
unsigned int valueMask = CWX | CWY;
2364
if (priv->pendingPositionUpdates && !priv->pendingConfigures.pending ())
2366
if (priv->serverFrameGeometry.x () == priv->frameGeometry.x ())
2367
valueMask &= ~(CWX);
2368
if (priv->serverFrameGeometry.y () == priv->frameGeometry.y ())
2369
valueMask &= ~(CWY);
2371
/* Because CompWindow::move can update the geometry last
2372
* received from the server, we must indicate that no values
2373
* changed, because when the ConfigureNotify comes around
2374
* the values are going to be the same. That's obviously
2375
* broken behaviour and worthy of a FIXME, but requires
2376
* larger changes to the window movement system. */
2379
priv->serverGeometry.setX (priv->geometry.x ());
2380
priv->serverGeometry.setY (priv->geometry.y ());
2381
priv->serverFrameGeometry.setX (priv->frameGeometry.x ());
2382
priv->serverFrameGeometry.setY (priv->frameGeometry.y ());
2384
xwc.x = priv->serverFrameGeometry.x ();
2385
xwc.y = priv->serverFrameGeometry.y ();
2387
gettimeofday (&priv->lastConfigureRequest, NULL);
2388
compiz::X11::PendingEvent::Ptr pc =
2389
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
2390
new compiz::X11::PendingConfigureEvent (
2391
screen->dpy (), priv->serverFrame, 0, &xwc)));
2393
priv->pendingConfigures.add (pc);
2395
XConfigureWindow (screen->dpy (), ROOTPARENT (this), valueMask, &xwc);
2397
if (priv->serverFrame)
2399
XMoveWindow (screen->dpy (), priv->wrapper,
2400
priv->serverInput.left, priv->serverInput.top);
2401
sendConfigureNotify ();
2404
priv->pendingPositionUpdates = false;
2409
CompWindow::focus ()
2411
WRAPABLE_HND_FUNC_RETURN (2, bool, focus)
2413
if (overrideRedirect ())
2416
if (!priv->managed || priv->unmanaging)
2419
if (!onCurrentDesktop ())
2422
if (priv->destroyed)
2425
if (!priv->shaded && (priv->state & CompWindowStateHiddenMask))
2428
if (priv->geometry.x () + priv->width <= 0 ||
2429
priv->geometry.y () + priv->height <= 0 ||
2430
priv->geometry.x () >= (int) screen->width ()||
2431
priv->geometry.y () >= (int) screen->height ())
2438
CompWindow::place (CompPoint &pos)
2440
WRAPABLE_HND_FUNC_RETURN (4, bool, place, pos)
2445
CompWindow::validateResizeRequest (unsigned int &mask,
2446
XWindowChanges *xwc,
2447
unsigned int source)
2449
WRAPABLE_HND_FUNC (5, validateResizeRequest, mask, xwc, source)
2451
if (!(priv->type & (CompWindowTypeDockMask |
2452
CompWindowTypeFullscreenMask |
2453
CompWindowTypeUnknownMask)))
2459
min = screen->workArea ().y () + priv->input.top;
2460
max = screen->workArea ().bottom ();
2462
if (priv->state & CompWindowStateStickyMask &&
2463
(xwc->y < min || xwc->y > max))
2465
xwc->y = priv->serverGeometry.y ();
2469
min -= screen->vp ().y () * screen->height ();
2470
max += (screen->vpSize ().height () - screen->vp ().y () - 1) *
2475
else if (xwc->y > max)
2484
min = screen->workArea ().x () + priv->input.left;
2485
max = screen->workArea ().right ();
2487
if (priv->state & CompWindowStateStickyMask &&
2488
(xwc->x < min || xwc->x > max))
2490
xwc->x = priv->serverGeometry.x ();
2494
min -= screen->vp ().x () * screen->width ();
2495
max += (screen->vpSize ().width () - screen->vp ().x () - 1) *
2500
else if (xwc->x > max)
2508
CompWindow::resizeNotify (int dx,
2512
WRAPABLE_HND_FUNC (6, resizeNotify, dx, dy, dwidth, dheight)
2515
CompWindow::moveNotify (int dx,
2518
WRAPABLE_HND_FUNC (7, moveNotify, dx, dy, immediate)
2521
CompWindow::windowNotify (CompWindowNotify n)
2522
WRAPABLE_HND_FUNC (8, windowNotify, n)
2525
CompWindow::grabNotify (int x,
2530
WRAPABLE_HND_FUNC (9, grabNotify, x, y, state, mask)
2531
priv->grabbed = true;
2535
CompWindow::ungrabNotify ()
2537
WRAPABLE_HND_FUNC (10, ungrabNotify)
2538
priv->grabbed = false;
2542
CompWindow::stateChangeNotify (unsigned int lastState)
2544
WRAPABLE_HND_FUNC (11, stateChangeNotify, lastState);
2546
/* if being made sticky */
2547
if (!(lastState & CompWindowStateStickyMask) &&
2548
(priv->state & CompWindowStateStickyMask))
2550
CompPoint vp; /* index of the window's vp */
2552
/* Find which viewport the window falls in,
2553
and check if it's the current viewport */
2554
vp = defaultViewport ();
2555
if (screen->vp () != vp)
2557
unsigned int valueMask = CWX | CWY;
2560
xwc.x = serverGeometry ().x () + (screen->vp ().x () - vp.x ()) * screen->width ();
2561
xwc.y = serverGeometry ().y () + (screen->vp ().y () - vp.y ()) * screen->height ();
2563
configureXWindow (valueMask, &xwc);
2570
PrivateWindow::isGroupTransient (Window clientLeader)
2575
if (transientFor == None || transientFor == screen->root ())
2577
if (type & (CompWindowTypeUtilMask |
2578
CompWindowTypeToolbarMask |
2579
CompWindowTypeMenuMask |
2580
CompWindowTypeDialogMask |
2581
CompWindowTypeModalDialogMask))
2583
if (this->clientLeader == clientLeader)
2592
PrivateWindow::getModalTransient ()
2594
CompWindow *w, *modalTransient;
2596
modalTransient = window;
2598
for (w = screen->windows ().back (); w; w = w->prev)
2600
if (w == modalTransient || w->priv->mapNum == 0)
2603
if (w->priv->transientFor == modalTransient->priv->id)
2605
if (w->priv->state & CompWindowStateModalMask)
2608
w = screen->windows ().back ();
2613
if (modalTransient == window)
2615
/* don't look for group transients with modal state if current window
2617
if (state & CompWindowStateModalMask)
2620
for (w = screen->windows ().back (); w; w = w->prev)
2622
if (w == modalTransient || w->priv->mapNum == 0)
2625
if (isAncestorTo (modalTransient, w))
2628
if (w->priv->isGroupTransient (modalTransient->priv->clientLeader))
2630
if (w->priv->state & CompWindowStateModalMask)
2633
w = w->priv->getModalTransient ();
2643
if (modalTransient == window)
2644
modalTransient = NULL;
2646
return modalTransient;
2650
CompWindow::moveInputFocusTo ()
2652
CompScreen *s = screen;
2653
CompWindow *modalTransient;
2655
modalTransient = priv->getModalTransient ();
2657
return modalTransient->moveInputFocusTo ();
2659
/* If the window is still hidden but not shaded
2660
* it probably meant that a plugin overloaded
2661
* CompWindow::focus to allow the focus to go
2662
* to this window, so only move the input focus
2663
* to the frame if the window is shaded */
2666
XSetInputFocus (s->dpy (), priv->serverFrame,
2667
RevertToPointerRoot, CurrentTime);
2668
XChangeProperty (s->dpy (), s->root (), Atoms::winActive,
2669
XA_WINDOW, 32, PropModeReplace,
2670
(unsigned char *) &priv->id, 1);
2674
bool setFocus = false;
2676
if (priv->inputHint)
2678
XSetInputFocus (s->dpy (), priv->id, RevertToPointerRoot,
2683
if (priv->protocols & CompWindowProtocolTakeFocusMask)
2687
ev.type = ClientMessage;
2688
ev.xclient.window = priv->id;
2689
ev.xclient.message_type = Atoms::wmProtocols;
2690
ev.xclient.format = 32;
2691
ev.xclient.data.l[0] = Atoms::wmTakeFocus;
2692
ev.xclient.data.l[1] = s->getCurrentTime ();
2693
ev.xclient.data.l[2] = 0;
2694
ev.xclient.data.l[3] = 0;
2695
ev.xclient.data.l[4] = 0;
2697
XSendEvent (s->dpy (), priv->id, false, NoEventMask, &ev);
2703
screen->priv->nextActiveWindow = priv->id;
2705
if (!setFocus && !modalTransient)
2707
CompWindow *ancestor;
2709
/* move input to closest ancestor */
2710
for (ancestor = s->windows ().front (); ancestor;
2711
ancestor = ancestor->next)
2713
if (PrivateWindow::isAncestorTo (this, ancestor))
2715
ancestor->moveInputFocusTo ();
2724
CompWindow::moveInputFocusToOtherWindow ()
2726
if (priv->id == screen->activeWindow () ||
2727
priv->id == screen->priv->nextActiveWindow)
2729
CompWindow *ancestor;
2731
if (priv->transientFor && priv->transientFor != screen->root ())
2733
ancestor = screen->findWindow (priv->transientFor);
2735
ancestor->focus () &&
2736
!(ancestor->priv->type & (CompWindowTypeDesktopMask |
2737
CompWindowTypeDockMask)))
2739
ancestor->moveInputFocusTo ();
2742
screen->focusDefaultWindow ();
2744
else if (priv->type & (CompWindowTypeDialogMask |
2745
CompWindowTypeModalDialogMask))
2747
CompWindow *a, *focus = NULL;
2749
for (a = screen->windows ().back (); a; a = a->prev)
2751
if (a->priv->clientLeader == priv->clientLeader)
2757
if (a->priv->type & (CompWindowTypeNormalMask |
2758
CompWindowTypeDialogMask |
2759
CompWindowTypeModalDialogMask))
2761
if (priv->compareWindowActiveness (focus, a) < 0)
2771
if (focus && !(focus->priv->type & (CompWindowTypeDesktopMask |
2772
CompWindowTypeDockMask)))
2774
focus->moveInputFocusTo ();
2777
screen->focusDefaultWindow ();
2780
screen->focusDefaultWindow ();
2786
PrivateWindow::stackLayerCheck (CompWindow *w,
2787
Window clientLeader,
2790
if (isAncestorTo (w, below))
2793
if (isAncestorTo (below, w))
2796
if (clientLeader && below->priv->clientLeader == clientLeader)
2797
if (below->priv->isGroupTransient (clientLeader))
2800
if (w->priv->state & CompWindowStateAboveMask)
2804
else if (w->priv->state & CompWindowStateBelowMask)
2806
if (below->priv->state & CompWindowStateBelowMask)
2809
else if (!(below->priv->state & CompWindowStateAboveMask))
2818
PrivateWindow::avoidStackingRelativeTo (CompWindow *w)
2820
if (w->overrideRedirect ())
2823
if (w->destroyed ())
2826
if (!w->priv->shaded && !w->priv->pendingMaps)
2828
if (!w->isViewable () || !w->isMapped ())
2835
/* goes through the stack, top-down until we find a window we should
2836
stack above, normal windows can be stacked above fullscreen windows
2837
(and fullscreen windows over others in their layer) if aboveFs is true. */
2839
PrivateWindow::findSiblingBelow (CompWindow *w,
2843
CompWindow *t = screen->findWindow (w->transientFor ());
2844
Window clientLeader = w->priv->clientLeader;
2845
unsigned int type = w->priv->type;
2846
unsigned int belowMask;
2849
belowMask = CompWindowTypeDockMask;
2851
belowMask = CompWindowTypeDockMask | CompWindowTypeFullscreenMask;
2853
/* normal stacking of fullscreen windows with below state */
2854
if ((type & CompWindowTypeFullscreenMask) &&
2855
(w->priv->state & CompWindowStateBelowMask))
2856
type = CompWindowTypeNormalMask;
2858
while (t && type != CompWindowTypeDockMask)
2860
/* dock stacking of transients for docks */
2861
if (t->type () & CompWindowTypeDockMask)
2862
type = CompWindowTypeDockMask;
2864
t = screen->findWindow (t->transientFor ());
2867
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2868
clientLeader = None;
2870
for (below = screen->serverWindows ().back (); below;
2871
below = below->serverPrev)
2873
if (below == w || avoidStackingRelativeTo (below))
2876
/* always above desktop windows */
2877
if (below->priv->type & CompWindowTypeDesktopMask)
2881
case CompWindowTypeDesktopMask:
2882
/* desktop window layer */
2884
case CompWindowTypeFullscreenMask:
2887
/* otherwise fall-through */
2888
case CompWindowTypeDockMask:
2889
/* fullscreen and dock layer */
2890
if (below->priv->type & (CompWindowTypeFullscreenMask |
2891
CompWindowTypeDockMask))
2893
if (stackLayerCheck (w, clientLeader, below))
2903
bool allowedRelativeToLayer = !(below->priv->type & belowMask);
2905
if (aboveFs && below->priv->type & CompWindowTypeFullscreenMask)
2906
if (!below->focus ())
2909
t = screen->findWindow (below->transientFor ());
2911
while (t && allowedRelativeToLayer)
2913
/* dock stacking of transients for docks */
2914
allowedRelativeToLayer = !(t->priv->type & belowMask);
2916
t = screen->findWindow (t->transientFor ());
2919
/* fullscreen and normal layer */
2920
if (allowedRelativeToLayer)
2922
if (stackLayerCheck (w, clientLeader, below))
2933
/* goes through the stack, top-down and returns the lowest window we
2936
PrivateWindow::findLowestSiblingBelow (CompWindow *w)
2938
CompWindow *below, *lowest = screen->serverWindows ().back ();
2939
CompWindow *t = screen->findWindow (w->transientFor ());
2940
Window clientLeader = w->priv->clientLeader;
2941
unsigned int type = w->priv->type;
2943
/* normal stacking fullscreen windows with below state */
2944
if ((type & CompWindowTypeFullscreenMask) &&
2945
(w->priv->state & CompWindowStateBelowMask))
2946
type = CompWindowTypeNormalMask;
2948
while (t && type != CompWindowTypeDockMask)
2950
/* dock stacking of transients for docks */
2951
if (t->type () & CompWindowTypeDockMask)
2952
type = CompWindowTypeDockMask;
2954
t = screen->findWindow (t->transientFor ());
2958
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2959
clientLeader = None;
2961
for (below = screen->serverWindows ().back (); below;
2962
below = below->serverPrev)
2964
if (below == w || avoidStackingRelativeTo (below))
2967
/* always above desktop windows */
2968
if (below->priv->type & CompWindowTypeDesktopMask)
2972
case CompWindowTypeDesktopMask:
2973
/* desktop window layer - desktop windows always should be
2974
stacked at the bottom; no other window should be below them */
2977
case CompWindowTypeFullscreenMask:
2978
case CompWindowTypeDockMask:
2979
/* fullscreen and dock layer */
2980
if (below->priv->type & (CompWindowTypeFullscreenMask |
2981
CompWindowTypeDockMask))
2983
if (!stackLayerCheck (below, clientLeader, w))
2993
bool allowedRelativeToLayer = !(below->priv->type & CompWindowTypeDockMask);
2995
t = screen->findWindow (below->transientFor ());
2997
while (t && allowedRelativeToLayer)
2999
/* dock stacking of transients for docks */
3000
allowedRelativeToLayer = !(t->priv->type & CompWindowTypeDockMask);
3002
t = screen->findWindow (t->transientFor ());
3005
/* fullscreen and normal layer */
3006
if (allowedRelativeToLayer)
3008
if (!stackLayerCheck (below, clientLeader, w))
3022
PrivateWindow::validSiblingBelow (CompWindow *w,
3023
CompWindow *sibling)
3025
CompWindow *t = screen->findWindow (w->transientFor ());
3026
Window clientLeader = w->priv->clientLeader;
3027
unsigned int type = w->priv->type;
3029
/* normal stacking fullscreen windows with below state */
3030
if ((type & CompWindowTypeFullscreenMask) &&
3031
(w->priv->state & CompWindowStateBelowMask))
3032
type = CompWindowTypeNormalMask;
3034
while (t && type != CompWindowTypeDockMask)
3036
/* dock stacking of transients for docks */
3037
if (t->type () & CompWindowTypeDockMask)
3038
type = CompWindowTypeDockMask;
3040
t = screen->findWindow (t->transientFor ());
3044
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
3045
clientLeader = None;
3047
if (sibling == w || avoidStackingRelativeTo (sibling))
3050
/* always above desktop windows */
3051
if (sibling->priv->type & CompWindowTypeDesktopMask)
3055
case CompWindowTypeDesktopMask:
3056
/* desktop window layer */
3058
case CompWindowTypeFullscreenMask:
3059
case CompWindowTypeDockMask:
3060
/* fullscreen and dock layer */
3061
if (sibling->priv->type & (CompWindowTypeFullscreenMask |
3062
CompWindowTypeDockMask))
3064
if (stackLayerCheck (w, clientLeader, sibling))
3074
bool allowedRelativeToLayer = !(sibling->priv->type & CompWindowTypeDockMask);
3076
t = screen->findWindow (sibling->transientFor ());
3078
while (t && allowedRelativeToLayer)
3080
/* dock stacking of transients for docks */
3081
allowedRelativeToLayer = !(t->priv->type & CompWindowTypeDockMask);
3083
t = screen->findWindow (t->transientFor ());
3086
/* fullscreen and normal layer */
3087
if (allowedRelativeToLayer)
3089
if (stackLayerCheck (w, clientLeader, sibling))
3100
PrivateWindow::saveGeometry (int mask)
3102
int m = mask & ~saveMask;
3104
/* only save geometry if window has been placed */
3109
saveWc.x = serverGeometry.x ();
3112
saveWc.y = serverGeometry.y ();
3115
saveWc.width = serverGeometry.width ();
3118
saveWc.height = serverGeometry.height ();
3120
if (m & CWBorderWidth)
3121
saveWc.border_width = serverGeometry.border ();
3127
PrivateWindow::restoreGeometry (XWindowChanges *xwc,
3130
int m = mask & saveMask;
3140
xwc->width = saveWc.width;
3142
/* This is not perfect but it works OK for now. If the saved width is
3143
the same as the current width then make it a little be smaller so
3144
the user can see that it changed and it also makes sure that
3145
windowResizeNotify is called and plugins are notified. */
3146
if (xwc->width == (int) serverGeometry.width ())
3156
xwc->height = saveWc.height;
3158
/* As above, if the saved height is the same as the current height
3159
then make it a little be smaller. */
3160
if (xwc->height == (int) serverGeometry.height ())
3168
if (m & CWBorderWidth)
3169
xwc->border_width = saveWc.border_width;
3176
static bool isPendingRestack (compiz::X11::PendingEvent::Ptr p)
3178
compiz::X11::PendingConfigureEvent::Ptr pc = boost::shared_static_cast <compiz::X11::PendingConfigureEvent> (p);
3180
return pc->matchVM (CWStackMode | CWSibling);
3184
PrivateWindow::reconfigureXWindow (unsigned int valueMask,
3185
XWindowChanges *xwc)
3187
unsigned int frameValueMask = valueMask;
3189
/* Immediately sync window position
3190
* if plugins were updating w->geometry () directly
3191
* in order to avoid a race condition */
3193
window->syncPosition ();
3195
/* Remove redundant bits */
3197
if (serverGeometry.x () == xwc->x)
3198
valueMask &= ~(CWX);
3200
if (serverGeometry.y () == xwc->y)
3201
valueMask &= ~(CWY);
3203
if (serverGeometry.width () == xwc->width)
3204
valueMask &= ~(CWWidth);
3206
if (serverGeometry.height () == xwc->height)
3207
valueMask &= ~(CWHeight);
3209
if (serverGeometry.border () == xwc->border_width)
3210
valueMask &= ~(CWBorderWidth);
3212
if (window->serverPrev && ROOTPARENT (window->serverPrev) == xwc->sibling)
3214
/* check if the sibling is also pending a restack,
3215
* if not, then setting this bit is useless */
3217
if (window->serverPrev->priv->pendingConfigures.forEachIf (boost::bind (isPendingRestack, _1)))
3218
valueMask &= ~(CWSibling | CWStackMode);
3221
if (valueMask & CWBorderWidth)
3222
serverGeometry.setBorder (xwc->border_width);
3224
if (valueMask & CWX)
3225
serverGeometry.setX (xwc->x);
3227
if (valueMask & CWY)
3228
serverGeometry.setY (xwc->y);
3230
if (valueMask & CWWidth)
3231
serverGeometry.setWidth (xwc->width);
3233
if (valueMask & CWHeight)
3234
serverGeometry.setHeight (xwc->height);
3236
/* Update the server side window list on raise, lower and restack functions.
3237
* This function should only recieve stack_mode == Above
3238
* but warn incase something else does get through, to make the cause
3239
* of any potential misbehaviour obvious. */
3240
if (valueMask & (CWSibling | CWStackMode))
3242
if (xwc->stack_mode == Above)
3246
screen->unhookServerWindow (window);
3247
screen->insertServerWindow (window, xwc->sibling);
3251
compLogMessage ("core", CompLogLevelWarn, "restack_mode not Above");
3254
if (serverFrameGeometry.x () == xwc->x - serverGeometry.border () - serverInput.left)
3255
frameValueMask &= ~(CWX);
3257
if (serverFrameGeometry.y () == xwc->y - serverGeometry.border () - serverInput.top)
3258
frameValueMask &= ~(CWY);
3260
if (serverFrameGeometry.width () == xwc->width + serverGeometry.border () * 2
3261
+ serverInput.left + serverInput.right)
3262
frameValueMask &= ~(CWWidth);
3264
if (serverFrameGeometry.height () == xwc->height + serverGeometry.border () * 2
3265
+ serverInput.top + serverInput.bottom)
3266
frameValueMask &= ~(CWHeight);
3268
/* Can't set the border width of frame windows */
3269
frameValueMask &= ~(CWBorderWidth);
3271
if (frameValueMask & CWX)
3272
serverFrameGeometry.setX (xwc->x - serverGeometry.border () - serverInput.left);
3274
if (frameValueMask & CWY)
3275
serverFrameGeometry.setY (xwc->y -serverGeometry.border () - serverInput.top);
3277
if (frameValueMask & CWWidth)
3278
serverFrameGeometry.setWidth (xwc->width + serverGeometry.border () * 2
3279
+ serverInput.left + serverInput.right);
3281
if (frameValueMask & CWHeight)
3282
serverFrameGeometry.setHeight (xwc->height + serverGeometry.border () * 2
3283
+ serverInput.top + serverInput.bottom);
3290
XWindowChanges wc = *xwc;
3292
wc.x = serverFrameGeometry.x ();
3293
wc.y = serverFrameGeometry.y ();
3294
wc.width = serverFrameGeometry.width ();
3295
wc.height = serverFrameGeometry.height ();
3297
gettimeofday (&lastConfigureRequest, NULL);
3299
compiz::X11::PendingEvent::Ptr pc =
3300
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
3301
new compiz::X11::PendingConfigureEvent (
3302
screen->dpy (), priv->serverFrame, frameValueMask, &wc)));
3304
pendingConfigures.add (pc);
3306
XConfigureWindow (screen->dpy (), serverFrame, frameValueMask, &wc);
3308
valueMask &= ~(CWSibling | CWStackMode);
3312
xwc->x = serverInput.left;
3313
xwc->y = serverInput.top;
3314
XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc);
3320
window->sendConfigureNotify ();
3324
XConfigureWindow (screen->dpy (), id, valueMask, xwc);
3328
PrivateWindow::stackDocks (CompWindow *w,
3329
CompWindowList &updateList,
3330
XWindowChanges *xwc,
3333
CompWindow *firstFullscreenWindow = NULL;
3334
CompWindow *belowDocks = NULL;
3336
foreach (CompWindow *dw, screen->serverWindows ())
3338
/* fullscreen window found */
3339
if (firstFullscreenWindow)
3341
/* If there is another toplevel window above the fullscreen one
3342
* then we need to stack above that */
3343
if ((dw->priv->managed && !dw->priv->unmanaging) &&
3344
!(dw->priv->state & CompWindowStateHiddenMask) &&
3345
!PrivateWindow::isAncestorTo (w, dw) &&
3346
!(dw->type () & (CompWindowTypeFullscreenMask |
3347
CompWindowTypeDockMask)) &&
3348
!dw->overrideRedirect () &&
3354
else if (dw->type () & CompWindowTypeFullscreenMask)
3356
/* First fullscreen window found when checking up the stack
3357
* now go back down to find a suitable candidate client
3358
* window to put the docks above */
3359
firstFullscreenWindow = dw;
3360
for (CompWindow *dww = dw->serverPrev; dww; dww = dww->serverPrev)
3362
if ((dw->priv->managed && !dw->priv->unmanaging) &&
3363
!(dw->priv->state & CompWindowStateHiddenMask) &&
3364
!(dww->type () & (CompWindowTypeFullscreenMask |
3365
CompWindowTypeDockMask)) &&
3366
!dww->overrideRedirect () &&
3378
*mask = CWSibling | CWStackMode;
3379
xwc->sibling = ROOTPARENT (belowDocks);
3381
/* Collect all dock windows first */
3382
foreach (CompWindow *dw, screen->serverWindows ())
3383
if (dw->priv->type & CompWindowTypeDockMask)
3384
updateList.push_front (dw);
3393
PrivateWindow::stackTransients (CompWindow *w,
3395
XWindowChanges *xwc,
3396
CompWindowList &updateList)
3399
Window clientLeader = w->priv->clientLeader;
3401
if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
3402
clientLeader = None;
3404
for (t = screen->serverWindows ().back (); t; t = t->serverPrev)
3406
if (t == w || t == avoid)
3409
if (t->priv->transientFor == w->priv->id ||
3410
t->priv->isGroupTransient (clientLeader))
3412
if (!stackTransients (t, avoid, xwc, updateList))
3415
if (xwc->sibling == t->priv->id ||
3416
(t->priv->serverFrame && xwc->sibling == t->priv->serverFrame))
3419
if (t->priv->mapNum || t->priv->pendingMaps)
3420
updateList.push_back (t);
3428
PrivateWindow::stackAncestors (CompWindow *w,
3429
XWindowChanges *xwc,
3430
CompWindowList &updateList)
3432
CompWindow *transient = NULL;
3434
if (w->priv->transientFor)
3435
transient = screen->findWindow (w->priv->transientFor);
3438
xwc->sibling != transient->priv->id &&
3439
(!transient->priv->serverFrame || xwc->sibling != transient->priv->serverFrame))
3441
CompWindow *ancestor;
3443
ancestor = screen->findWindow (w->priv->transientFor);
3446
if (!stackTransients (ancestor, w, xwc, updateList))
3449
if (ancestor->priv->type & CompWindowTypeDesktopMask)
3452
if (ancestor->priv->type & CompWindowTypeDockMask)
3453
if (!(w->priv->type & CompWindowTypeDockMask))
3456
if (ancestor->priv->mapNum || ancestor->priv->pendingMaps)
3457
updateList.push_back (ancestor);
3459
stackAncestors (ancestor, xwc, updateList);
3462
else if (w->priv->isGroupTransient (w->priv->clientLeader))
3466
for (a = screen->serverWindows ().back (); a; a = a->serverPrev)
3468
if (a->priv->clientLeader == w->priv->clientLeader &&
3469
a->priv->transientFor == None &&
3470
!a->priv->isGroupTransient (w->priv->clientLeader))
3472
if (xwc->sibling == a->priv->id ||
3473
(a->priv->serverFrame && xwc->sibling == a->priv->serverFrame))
3476
if (!stackTransients (a, w, xwc, updateList))
3479
if (a->priv->type & CompWindowTypeDesktopMask)
3482
if (a->priv->type & CompWindowTypeDockMask)
3483
if (!(w->priv->type & CompWindowTypeDockMask))
3486
if (a->priv->mapNum || a->priv->pendingMaps)
3487
updateList.push_back (a);
3494
CompWindow::configureXWindow (unsigned int valueMask,
3495
XWindowChanges *xwc)
3497
if (priv->managed && (valueMask & (CWSibling | CWStackMode)))
3499
CompWindowList transients;
3500
CompWindowList ancestors;
3501
CompWindowList docks;
3503
/* Since the window list is being reordered in reconfigureXWindow
3504
the list of windows which need to be restacked must be stored
3505
first. The windows are stacked in the opposite order than they
3506
were previously stacked, in order that they are above xwc->sibling
3507
so that when compiz gets the ConfigureNotify event it doesn't
3508
have to restack all the windows again. */
3510
/* transient children above */
3511
if (PrivateWindow::stackTransients (this, NULL, xwc, transients))
3513
/* ancestors, siblings and sibling transients below */
3514
PrivateWindow::stackAncestors (this, xwc, ancestors);
3516
for (CompWindowList::reverse_iterator w = ancestors.rbegin ();
3517
w != ancestors.rend (); w++)
3519
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
3520
xwc->sibling = ROOTPARENT (*w);
3523
this->priv->reconfigureXWindow (valueMask, xwc);
3524
xwc->sibling = ROOTPARENT (this);
3526
for (CompWindowList::reverse_iterator w = transients.rbegin ();
3527
w != transients.rend (); w++)
3529
(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
3530
xwc->sibling = ROOTPARENT (*w);
3533
if (PrivateWindow::stackDocks (this, docks, xwc, &valueMask))
3535
Window sibling = xwc->sibling;
3536
xwc->stack_mode = Above;
3538
/* Then update the dock windows */
3539
foreach (CompWindow *dw, docks)
3541
xwc->sibling = sibling;
3542
dw->priv->reconfigureXWindow (valueMask, xwc);
3549
priv->reconfigureXWindow (valueMask, xwc);
3554
PrivateWindow::addWindowSizeChanges (XWindowChanges *xwc,
3555
CompWindow::Geometry old)
3563
screen->viewportForGeometry (old, viewport);
3565
x = (viewport.x () - screen->vp ().x ()) * screen->width ();
3566
y = (viewport.y () - screen->vp ().y ()) * screen->height ();
3568
output = screen->outputDeviceForGeometry (old);
3569
workArea = screen->getWorkareaForOutput (output);
3571
if (type & CompWindowTypeFullscreenMask)
3573
saveGeometry (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3575
if (fullscreenMonitorsSet)
3577
xwc->x = x + fullscreenMonitorRect.x ();
3578
xwc->y = y + fullscreenMonitorRect.y ();
3579
xwc->width = fullscreenMonitorRect.width ();
3580
xwc->height = fullscreenMonitorRect.height ();
3584
xwc->x = x + screen->outputDevs ()[output].x ();
3585
xwc->y = y + screen->outputDevs ()[output].y ();
3586
xwc->width = screen->outputDevs ()[output].width ();
3587
xwc->height = screen->outputDevs ()[output].height ();
3590
xwc->border_width = 0;
3592
mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
3596
mask |= restoreGeometry (xwc, CWBorderWidth);
3598
if (state & CompWindowStateMaximizedVertMask)
3600
saveGeometry (CWY | CWHeight);
3602
xwc->height = workArea.height () - serverInput.top -
3603
serverInput.bottom - old.border () * 2;
3609
mask |= restoreGeometry (xwc, CWY | CWHeight);
3612
if (state & CompWindowStateMaximizedHorzMask)
3614
saveGeometry (CWX | CWWidth);
3616
xwc->width = workArea.width () - serverInput.left -
3617
serverInput.right - old.border () * 2;
3623
mask |= restoreGeometry (xwc, CWX | CWWidth);
3626
/* constrain window width if smaller than minimum width */
3627
if (!(mask & CWWidth) && (int) old.width () < sizeHints.min_width)
3629
xwc->width = sizeHints.min_width;
3633
/* constrain window width if greater than maximum width */
3634
if (!(mask & CWWidth) && (int) old.width () > sizeHints.max_width)
3636
xwc->width = sizeHints.max_width;
3640
/* constrain window height if smaller than minimum height */
3641
if (!(mask & CWHeight) && (int) old.height () < sizeHints.min_height)
3643
xwc->height = sizeHints.min_height;
3647
/* constrain window height if greater than maximum height */
3648
if (!(mask & CWHeight) && (int) old.height () > sizeHints.max_height)
3650
xwc->height = sizeHints.max_height;
3654
if (mask & (CWWidth | CWHeight))
3656
int width, height, max;
3658
width = (mask & CWWidth) ? xwc->width : old.width ();
3659
height = (mask & CWHeight) ? xwc->height : old.height ();
3661
xwc->width = old.width ();
3662
xwc->height = old.height ();
3664
window->constrainNewWindowSize (width, height, &width, &height);
3666
if (width != (int) old.width ())
3674
if (height != (int) old.height ())
3677
xwc->height = height;
3682
if (state & CompWindowStateMaximizedVertMask)
3684
if (old.y () < y + workArea.y () + serverInput.top)
3686
xwc->y = y + workArea.y () + serverInput.top;
3691
height = xwc->height + old.border () * 2;
3693
max = y + workArea.bottom ();
3694
if (old.y () + (int) old.height () + serverInput.bottom > max)
3696
xwc->y = max - height - serverInput.bottom;
3699
else if (old.y () + height + serverInput.bottom > max)
3701
xwc->y = y + workArea.y () +
3702
(workArea.height () - serverInput.top - height -
3703
serverInput.bottom) / 2 + serverInput.top;
3709
if (state & CompWindowStateMaximizedHorzMask)
3711
if (old.x () < x + workArea.x () + serverInput.left)
3713
xwc->x = x + workArea.x () + serverInput.left;
3718
width = xwc->width + old.border () * 2;
3720
max = x + workArea.right ();
3721
if (old.x () + (int) old.width () + serverInput.right > max)
3723
xwc->x = max - width - serverInput.right;
3726
else if (old.x () + width + serverInput.right > max)
3728
xwc->x = x + workArea.x () +
3729
(workArea.width () - serverInput.left - width -
3730
serverInput.right) / 2 + serverInput.left;
3738
if ((mask & CWX) && (xwc->x == old.x ()))
3741
if ((mask & CWY) && (xwc->y == old.y ()))
3744
if ((mask & CWWidth) && (xwc->width == (int) old.width ()))
3747
if ((mask & CWHeight) && (xwc->height == (int) old.height ()))
3754
PrivateWindow::adjustConfigureRequestForGravity (XWindowChanges *xwc,
3760
unsigned int mask = 0;
3765
if (xwcm & (CWX | CWWidth))
3768
case NorthWestGravity:
3770
case SouthWestGravity:
3772
newX += priv->border.left * direction;
3779
newX -= (xwc->width / 2 - priv->border.left +
3780
(priv->border.left + priv->border.right) / 2) * direction;
3782
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
3785
case NorthEastGravity:
3787
case SouthEastGravity:
3789
newX -= xwc->width + priv->border.right * direction;
3791
newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
3800
if (xwcm & (CWY | CWHeight))
3803
case NorthWestGravity:
3805
case NorthEastGravity:
3807
newY = xwc->y + priv->serverInput.top * direction;
3814
newY -= (xwc->height / 2 - priv->serverInput.top +
3815
(priv->serverInput.top + priv->serverInput.bottom) / 2) * direction;
3817
newY -= ((xwc->height - priv->serverGeometry.height ()) / 2) * direction;
3820
case SouthWestGravity:
3822
case SouthEastGravity:
3824
newY -= xwc->height + priv->serverInput.bottom * direction;
3826
newY -= (xwc->height - priv->serverGeometry.height ()) * direction;
3837
xwc->x += (newX - xwc->x);
3843
xwc->y += (newY - xwc->y);
3851
CompWindow::moveResize (XWindowChanges *xwc,
3854
unsigned int source)
3856
bool placed = false;
3858
xwcm &= (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3860
if (xwcm & (CWX | CWY))
3861
if (priv->sizeHints.flags & (USPosition | PPosition))
3865
gravity = priv->sizeHints.win_gravity;
3868
xwc->x = priv->serverGeometry.x ();
3870
xwc->y = priv->serverGeometry.y ();
3871
if (!(xwcm & CWWidth))
3872
xwc->width = priv->serverGeometry.width ();
3873
if (!(xwcm & CWHeight))
3874
xwc->height = priv->serverGeometry.height ();
3876
if (xwcm & (CWWidth | CWHeight))
3880
if (constrainNewWindowSize (xwc->width, xwc->height, &width, &height))
3882
if (width != xwc->width)
3885
if (height != xwc->height)
3889
xwc->height = height;
3893
xwcm |= priv->adjustConfigureRequestForGravity (xwc, xwcm, gravity, 1);
3895
validateResizeRequest (xwcm, xwc, source);
3897
/* when horizontally maximized only allow width changes added by
3898
addWindowSizeChanges */
3899
if (priv->state & CompWindowStateMaximizedHorzMask)
3902
/* when vertically maximized only allow height changes added by
3903
addWindowSizeChanges */
3904
if (priv->state & CompWindowStateMaximizedVertMask)
3907
xwcm |= priv->addWindowSizeChanges (xwc, Geometry (xwc->x, xwc->y,
3908
xwc->width, xwc->height,
3909
xwc->border_width));
3911
/* check if the new coordinates are useful and valid (different
3912
to current size); if not, we have to clear them to make sure
3913
we send a synthetic ConfigureNotify event if all coordinates
3914
match the server coordinates */
3915
if (xwc->x == priv->serverGeometry.x ())
3918
if (xwc->y == priv->serverGeometry.y ())
3921
if (xwc->width == (int) priv->serverGeometry.width ())
3924
if (xwc->height == (int) priv->serverGeometry.height ())
3927
if (xwc->border_width == (int) priv->serverGeometry.border ())
3928
xwcm &= ~CWBorderWidth;
3930
/* update saved window coordinates - if CWX or CWY is set for fullscreen
3931
or maximized windows after addWindowSizeChanges, it should be pretty
3932
safe to assume that the saved coordinates should be updated too, e.g.
3933
because the window was moved to another viewport by some client */
3934
if ((xwcm & CWX) && (priv->saveMask & CWX))
3935
priv->saveWc.x += (xwc->x - priv->serverGeometry.x ());
3937
if ((xwcm & CWY) && (priv->saveMask & CWY))
3938
priv->saveWc.y += (xwc->y - priv->serverGeometry.y ());
3940
if (priv->mapNum && (xwcm & (CWWidth | CWHeight)))
3944
configureXWindow (xwcm, xwc);
3947
/* we have to send a configure notify on ConfigureRequest events if
3948
we decide not to do anything according to ICCCM 4.1.5 */
3949
sendConfigureNotify ();
3953
priv->placed = true;
3957
PrivateWindow::updateSize ()
3962
if (window->overrideRedirect () || !managed)
3965
mask = priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
3968
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
3969
window->sendSyncRequest ();
3971
window->configureXWindow (mask, &xwc);
3976
PrivateWindow::addWindowStackChanges (XWindowChanges *xwc,
3977
CompWindow *sibling)
3981
if (!sibling || sibling->priv->id != id)
3983
/* Alow requests to go on top of serverPrev
3984
* if serverPrev was recently restacked */
3985
if (window->serverPrev)
3989
XWindowChanges lxwc;
3990
unsigned int valueMask = CWStackMode;
3992
lxwc.stack_mode = Below;
3996
gettimeofday (&lastConfigureRequest, NULL);
3997
compiz::X11::PendingEvent::Ptr pc =
3998
boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
3999
new compiz::X11::PendingConfigureEvent (
4000
screen->dpy (), serverFrame, valueMask, &lxwc)));
4002
pendingConfigures.add (pc);
4005
/* Below with no sibling puts the window at the bottom
4007
XConfigureWindow (screen->dpy (), ROOTPARENT (window), valueMask, &lxwc);
4009
/* Update the list of windows last sent to the server */
4010
screen->unhookServerWindow (window);
4011
screen->insertServerWindow (window, 0);
4015
if (sibling->priv->id != window->serverPrev->priv->id ||
4016
window->serverPrev->priv->pendingConfigures.forEachIf (boost::bind (isPendingRestack, _1)))
4018
mask |= CWSibling | CWStackMode;
4020
xwc->stack_mode = Above;
4021
xwc->sibling = ROOTPARENT (sibling);
4027
mask |= CWSibling | CWStackMode;
4029
xwc->stack_mode = Above;
4030
xwc->sibling = ROOTPARENT (sibling);
4038
CompWindow::raise ()
4042
bool aboveFs = false;
4044
/* an active fullscreen window should be raised over all other
4045
windows in its layer */
4046
if (priv->type & CompWindowTypeFullscreenMask)
4047
if (priv->id == screen->activeWindow ())
4050
for (CompWindow *pw = serverPrev; pw; pw = pw->serverPrev)
4052
if (pw->priv->type & CompWindowTypeFullscreenMask)
4054
if (priv->id == screen->activeWindow ())
4061
mask = priv->addWindowStackChanges (&xwc,
4062
PrivateWindow::findSiblingBelow (this, aboveFs));
4065
configureXWindow (mask, &xwc);
4069
PrivateScreen::focusTopMostWindow ()
4071
CompWindow *focus = NULL;
4072
CompWindowList::reverse_iterator it = serverWindows.rbegin ();
4074
for (; it != serverWindows.rend (); it++)
4076
CompWindow *w = *it;
4078
if (w->type () & CompWindowTypeDockMask)
4090
if (focus->id () != activeWindow)
4091
focus->moveInputFocusTo ();
4094
XSetInputFocus (dpy, root, RevertToPointerRoot,
4101
CompWindow::lower ()
4106
mask = priv->addWindowStackChanges (&xwc,
4107
PrivateWindow::findLowestSiblingBelow (this));
4109
configureXWindow (mask, &xwc);
4111
/* when lowering a window, focus the topmost window if
4112
the click-to-focus option is on */
4113
if ((screen->priv->optionGetClickToFocus ()))
4115
CompWindow *focusedWindow = screen->priv->focusTopMostWindow ();
4117
/* if the newly focused window is a desktop window,
4118
give the focus back to w */
4119
if (focusedWindow &&
4120
focusedWindow->type () & CompWindowTypeDesktopMask)
4122
moveInputFocusTo ();
4128
CompWindow::restackAbove (CompWindow *sibling)
4130
for (; sibling; sibling = sibling->serverNext)
4131
if (PrivateWindow::validSiblingBelow (this, sibling))
4139
mask = priv->addWindowStackChanges (&xwc, sibling);
4141
configureXWindow (mask, &xwc);
4145
/* finds the highest window under sibling we can stack above */
4147
PrivateWindow::findValidStackSiblingBelow (CompWindow *w,
4148
CompWindow *sibling)
4150
CompWindow *lowest, *last, *p;
4152
/* check whether we're allowed to stack under a sibling by finding
4153
* the above 'sibling' and checking whether or not we're allowed
4154
* to stack under that - if not, then there is no valid sibling
4157
for (p = sibling; p; p = p->serverNext)
4159
if (!avoidStackingRelativeTo (p))
4161
if (!validSiblingBelow (p, w))
4167
/* get lowest sibling we're allowed to stack above */
4168
lowest = last = findLowestSiblingBelow (w);
4170
/* walk from bottom up */
4171
for (p = screen->serverWindows ().front (); p; p = p->serverNext)
4173
/* stop walking when we reach the sibling we should try to stack
4178
/* skip windows that we should avoid */
4179
if (w == p || avoidStackingRelativeTo (p))
4182
if (validSiblingBelow (w, p))
4184
/* update lowest as we find windows below sibling that we're
4185
allowed to stack above. last window must be equal to the
4186
lowest as we shouldn't update lowest if we passed an
4192
/* update last pointer */
4200
CompWindow::restackBelow (CompWindow *sibling)
4205
mask = priv->addWindowStackChanges (&xwc,
4206
PrivateWindow::findValidStackSiblingBelow (this, sibling));
4209
configureXWindow (mask, &xwc);
4213
CompWindow::updateAttributes (CompStackingUpdateMode stackingMode)
4218
if (overrideRedirect () || !priv->managed)
4221
if (priv->state & CompWindowStateShadedMask)
4223
windowNotify (CompWindowNotifyShade);
4227
else if (priv->shaded)
4229
windowNotify (CompWindowNotifyUnshade);
4234
if (stackingMode != CompStackingUpdateModeNone)
4237
CompWindow *sibling;
4239
aboveFs = (stackingMode == CompStackingUpdateModeAboveFullscreen);
4240
if (priv->type & CompWindowTypeFullscreenMask)
4242
/* put active or soon-to-be-active fullscreen windows over
4243
all others in their layer */
4244
if (priv->id == screen->activeWindow () ||
4245
priv->id == screen->priv->nextActiveWindow)
4251
/* put windows that are just mapped, over fullscreen windows */
4252
if (stackingMode == CompStackingUpdateModeInitialMap)
4255
sibling = PrivateWindow::findSiblingBelow (this, aboveFs);
4258
(stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
4262
for (p = sibling; p; p = p->serverPrev)
4263
if (p->priv->id == screen->activeWindow ())
4266
/* window is above active window so we should lower it,
4267
* assuing that is allowed (if, for example, our window has
4268
* the "above" state, then lowering beneath the active
4269
* window may not be allowed). */
4270
if (p && PrivateWindow::validSiblingBelow (p, this))
4272
p = PrivateWindow::findValidStackSiblingBelow (this, p);
4274
/* if we found a valid sibling under the active window, it's
4275
our new sibling we want to stack above */
4282
mask |= priv->addWindowStackChanges (&xwc, sibling);
4285
mask |= priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
4287
if (priv->mapNum && (mask & (CWWidth | CWHeight)))
4291
configureXWindow (mask, &xwc);
4295
PrivateWindow::ensureWindowVisibility ()
4298
int width = serverGeometry.width () + serverGeometry.border () * 2;
4299
int height = serverGeometry.height () + serverGeometry.border () * 2;
4303
if (struts || attrib.override_redirect)
4306
if (type & (CompWindowTypeDockMask |
4307
CompWindowTypeFullscreenMask |
4308
CompWindowTypeUnknownMask))
4311
x1 = screen->workArea ().x () - screen->width () * screen->vp ().x ();
4312
y1 = screen->workArea ().y () - screen->height () * screen->vp ().y ();
4313
x2 = x1 + screen->workArea ().width () + screen->vpSize ().width () *
4315
y2 = y1 + screen->workArea ().height () + screen->vpSize ().height () *
4318
if (serverGeometry.x () - serverInput.left >= x2)
4319
dx = (x2 - 25) - serverGeometry.x ();
4320
else if (serverGeometry.x () + width + serverInput.right <= x1)
4321
dx = (x1 + 25) - (serverGeometry.x () + width);
4323
if (serverGeometry.y () - serverInput.top >= y2)
4324
dy = (y2 - 25) - serverGeometry.y ();
4325
else if (serverGeometry.y () + height + serverInput.bottom <= y1)
4326
dy = (y1 + 25) - (serverGeometry.y () + height);
4332
xwc.x = serverGeometry.x () + dx;
4333
xwc.y = serverGeometry.y () + dy;
4335
window->configureXWindow (CWX | CWY, &xwc);
4340
PrivateWindow::reveal ()
4342
if (window->minimized ())
4343
window->unminimize ();
4345
screen->leaveShowDesktopMode (window);
4349
PrivateWindow::revealAncestors (CompWindow *w,
4350
CompWindow *transient)
4352
if (isAncestorTo (transient, w))
4354
screen->forEachWindow (boost::bind (revealAncestors, _1, w));
4360
CompWindow::activate ()
4362
WRAPABLE_HND_FUNC (3, activate)
4364
screen->priv->setCurrentDesktop (priv->desktop);
4366
screen->forEachWindow (
4367
boost::bind (PrivateWindow::revealAncestors, _1, this));
4370
if (priv->state & CompWindowStateHiddenMask)
4372
priv->state &= ~CompWindowStateShadedMask;
4377
if (priv->state & CompWindowStateHiddenMask)
4380
if (!onCurrentDesktop ())
4383
priv->ensureWindowVisibility ();
4384
updateAttributes (CompStackingUpdateModeAboveFullscreen);
4385
moveInputFocusTo ();
4389
#define PVertResizeInc (1 << 0)
4390
#define PHorzResizeInc (1 << 1)
4393
CompWindow::constrainNewWindowSize (int width,
4398
const XSizeHints *hints = &priv->sizeHints;
4399
int oldWidth = width;
4400
int oldHeight = height;
4404
int base_height = 0;
4407
int max_width = MAXSHORT;
4408
int max_height = MAXSHORT;
4409
long flags = hints->flags;
4410
long resizeIncFlags = (flags & PResizeInc) ? ~0 : 0;
4412
if (screen->priv->optionGetIgnoreHintsWhenMaximized ())
4414
if (priv->state & MAXIMIZE_STATE)
4418
if (priv->state & CompWindowStateMaximizedHorzMask)
4419
resizeIncFlags &= ~PHorzResizeInc;
4421
if (priv->state & CompWindowStateMaximizedVertMask)
4422
resizeIncFlags &= ~PVertResizeInc;
4426
/* Ater gdk_window_constrain_size(), which is partially borrowed from fvwm.
4428
* Copyright 1993, Robert Nation
4429
* You may use this code for any purpose, as long as the original
4430
* copyright remains in the source code and all documentation
4432
* which in turn borrows parts of the algorithm from uwm
4435
#define FLOOR(value, base) (((int) ((value) / (base))) * (base))
4436
#define FLOOR64(value, base) (((uint64_t) ((value) / (base))) * (base))
4438
if ((flags & PBaseSize) && (flags & PMinSize))
4440
base_width = hints->base_width;
4441
base_height = hints->base_height;
4442
min_width = hints->min_width;
4443
min_height = hints->min_height;
4445
else if (flags & PBaseSize)
4447
base_width = hints->base_width;
4448
base_height = hints->base_height;
4449
min_width = hints->base_width;
4450
min_height = hints->base_height;
4452
else if (flags & PMinSize)
4454
base_width = hints->min_width;
4455
base_height = hints->min_height;
4456
min_width = hints->min_width;
4457
min_height = hints->min_height;
4460
if (flags & PMaxSize)
4462
max_width = hints->max_width;
4463
max_height = hints->max_height;
4466
if (resizeIncFlags & PHorzResizeInc)
4467
xinc = MAX (xinc, hints->width_inc);
4469
if (resizeIncFlags & PVertResizeInc)
4470
yinc = MAX (yinc, hints->height_inc);
4472
/* clamp width and height to min and max values */
4473
width = CLAMP (width, min_width, max_width);
4474
height = CLAMP (height, min_height, max_height);
4476
/* shrink to base + N * inc */
4477
width = base_width + FLOOR (width - base_width, xinc);
4478
height = base_height + FLOOR (height - base_height, yinc);
4480
/* constrain aspect ratio, according to:
4482
* min_aspect.x width max_aspect.x
4483
* ------------ <= -------- <= -----------
4484
* min_aspect.y height max_aspect.y
4486
if ((flags & PAspect) && hints->min_aspect.y > 0 && hints->max_aspect.x > 0)
4488
/* Use 64 bit arithmetic to prevent overflow */
4490
uint64_t min_aspect_x = hints->min_aspect.x;
4491
uint64_t min_aspect_y = hints->min_aspect.y;
4492
uint64_t max_aspect_x = hints->max_aspect.x;
4493
uint64_t max_aspect_y = hints->max_aspect.y;
4496
if (min_aspect_x * height > width * min_aspect_y)
4498
delta = FLOOR64 (height - width * min_aspect_y / min_aspect_x,
4500
if (height - (int) delta >= min_height)
4504
delta = FLOOR64 (height * min_aspect_x / min_aspect_y - width,
4506
if (width + (int) delta <= max_width)
4511
if (width * max_aspect_y > max_aspect_x * height)
4513
delta = FLOOR64 (width - height * max_aspect_x / max_aspect_y,
4515
if (width - (int) delta >= min_width)
4519
delta = FLOOR64 (width * min_aspect_y / min_aspect_x - height,
4521
if (height + (int) delta <= max_height)
4531
if (width != oldWidth || height != oldHeight)
4534
*newHeight = height;
4545
priv->hidden = true;
4552
priv->hidden = false;
4557
PrivateWindow::hide ()
4559
bool onDesktop = window->onCurrentDesktop ();
4564
if (!window->minimized () && !inShowDesktopMode &&
4565
!hidden && onDesktop)
4567
if (state & CompWindowStateShadedMask)
4580
if ((state & CompWindowStateShadedMask) && serverFrame)
4581
XUnmapWindow (screen->dpy (), serverFrame);
4584
if (!pendingMaps && !window->isViewable ())
4587
window->windowNotify (CompWindowNotifyHide);
4591
if (serverFrame && !shaded)
4592
XUnmapWindow (screen->dpy (), serverFrame);
4594
XUnmapWindow (screen->dpy (), id);
4596
if (window->minimized () || inShowDesktopMode || hidden || shaded)
4597
window->changeState (state | CompWindowStateHiddenMask);
4599
if (shaded && id == screen->activeWindow ())
4600
window->moveInputFocusTo ();
4604
PrivateWindow::show ()
4606
bool onDesktop = window->onCurrentDesktop ();
4611
if (minimized || inShowDesktopMode ||
4612
hidden || !onDesktop)
4614
/* no longer hidden but not on current desktop */
4615
if (!minimized && !inShowDesktopMode && !hidden)
4616
window->changeState (state & ~CompWindowStateHiddenMask);
4621
/* transition from minimized to shaded */
4622
if (state & CompWindowStateShadedMask)
4627
XMapWindow (screen->dpy (), serverFrame);
4631
priv->geometry.setHeight (priv->geometry.height () + 1);
4632
window->resize (geometry.x (), geometry.y (),
4633
geometry.width (), geometry.height () - 1,
4634
geometry.border ());
4644
window->windowNotify (CompWindowNotifyShow);
4650
XMapWindow (screen->dpy (), serverFrame);
4651
XMapWindow (screen->dpy (), wrapper);
4654
XMapWindow (screen->dpy (), id);
4656
window->changeState (state & ~CompWindowStateHiddenMask);
4657
screen->priv->setWindowState (state, id);
4661
PrivateWindow::minimizeTransients (CompWindow *w,
4662
CompWindow *ancestor)
4664
if (w->priv->transientFor == ancestor->priv->id ||
4665
w->priv->isGroupTransient (ancestor->priv->clientLeader))
4672
CompWindow::minimize ()
4674
WRAPABLE_HND_FUNC (13, minimize);
4679
if (!priv->minimized)
4681
windowNotify (CompWindowNotifyMinimize);
4683
priv->minimized = true;
4685
screen->forEachWindow (
4686
boost::bind (PrivateWindow::minimizeTransients, _1, this));
4693
PrivateWindow::unminimizeTransients (CompWindow *w,
4694
CompWindow *ancestor)
4696
if (w->priv->transientFor == ancestor->priv->id ||
4697
w->priv->isGroupTransient (ancestor->priv->clientLeader))
4702
CompWindow::unminimize ()
4704
WRAPABLE_HND_FUNC (14, unminimize);
4705
if (priv->minimized)
4707
windowNotify (CompWindowNotifyUnminimize);
4709
priv->minimized = false;
4713
screen->forEachWindow (
4714
boost::bind (PrivateWindow::unminimizeTransients, _1, this));
4719
CompWindow::maximize (unsigned int state)
4721
if (overrideRedirect ())
4724
state = constrainWindowState (state, priv->actions);
4726
state &= MAXIMIZE_STATE;
4728
if (state == (priv->state & MAXIMIZE_STATE))
4731
state |= (priv->state & ~MAXIMIZE_STATE);
4733
changeState (state);
4734
updateAttributes (CompStackingUpdateModeNone);
4738
PrivateWindow::getUserTime (Time& time)
4742
unsigned long n, left;
4743
unsigned char *data;
4744
bool retval = false;
4746
result = XGetWindowProperty (screen->dpy (), priv->id,
4748
0L, 1L, False, XA_CARDINAL, &actual, &format,
4751
if (result == Success && data)
4757
memcpy (&value, data, sizeof (CARD32));
4759
time = (Time) value;
4762
XFree ((void *) data);
4769
PrivateWindow::setUserTime (Time time)
4771
CARD32 value = (CARD32) time;
4773
XChangeProperty (screen->dpy (), priv->id,
4775
XA_CARDINAL, 32, PropModeReplace,
4776
(unsigned char *) &value, 1);
4780
* Macros from metacity
4782
* Xserver time can wraparound, thus comparing two timestamps needs to
4783
* take this into account. Here's a little macro to help out. If no
4784
* wraparound has occurred, this is equivalent to
4786
* Of course, the rest of the ugliness of this macro comes from
4787
* accounting for the fact that wraparound can occur and the fact that
4788
* a timestamp of 0 must be special-cased since it means older than
4791
* Note that this is NOT an equivalent for time1 <= time2; if that's
4792
* what you need then you'll need to swap the order of the arguments
4793
* and negate the result.
4795
#define XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) \
4796
( (( (time1) < (time2) ) && \
4797
( (time2) - (time1) < ((unsigned long) -1) / 2 )) || \
4798
(( (time1) > (time2) ) && \
4799
( (time1) - (time2) > ((unsigned long) -1) / 2 )) \
4801
#define XSERVER_TIME_IS_BEFORE(time1, time2) \
4803
(XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS (time1, time2) && \
4808
PrivateWindow::getUsageTimestamp (Time& timestamp)
4810
if (getUserTime (timestamp))
4813
if (initialTimestampSet)
4815
timestamp = initialTimestamp;
4823
PrivateWindow::isWindowFocusAllowed (Time timestamp)
4825
CompScreen *s = screen;
4827
Time wUserTime, aUserTime;
4828
bool gotTimestamp = false;
4832
level = s->priv->optionGetFocusPreventionLevel ();
4834
if (level == CoreOptions::FocusPreventionLevelOff)
4839
/* the caller passed a timestamp, so use that
4840
instead of the window's user time */
4841
wUserTime = timestamp;
4842
gotTimestamp = true;
4846
gotTimestamp = getUsageTimestamp (wUserTime);
4849
/* if we got no timestamp for the window, try to get at least a timestamp
4850
for its transient parent, if any */
4851
if (!gotTimestamp && transientFor)
4855
parent = screen->findWindow (transientFor);
4857
gotTimestamp = parent->priv->getUsageTimestamp (wUserTime);
4860
if (gotTimestamp && !wUserTime)
4862
/* window explicitly requested no focus */
4866
/* allow focus for excluded windows */
4867
CompMatch &match = s->priv->optionGetFocusPreventionMatch ();
4868
if (!match.evaluate (window))
4871
if (level == CoreOptions::FocusPreventionLevelVeryHigh)
4874
active = s->findWindow (s->activeWindow ());
4876
/* no active window */
4877
if (!active || (active->type () & CompWindowTypeDesktopMask))
4880
/* active window belongs to same application */
4881
if (window->clientLeader () == active->clientLeader ())
4884
if (level == CoreOptions::FocusPreventionLevelHigh)
4887
/* not in current viewport or desktop */
4888
if (!window->onCurrentDesktop ())
4891
dvp = window->defaultViewport ();
4892
if (dvp.x () != s->vp ().x () || dvp.y () != s->vp ().y ())
4897
/* unsure as we have nothing to compare - allow focus in low level,
4898
don't allow in normal level */
4899
if (level == CoreOptions::FocusPreventionLevelNormal)
4905
/* can't get user time for active window */
4906
if (!active->priv->getUserTime (aUserTime))
4909
if (XSERVER_TIME_IS_BEFORE (wUserTime, aUserTime))
4916
PrivateWindow::allowWindowFocus (unsigned int noFocusMask,
4921
if (priv->id == screen->activeWindow ())
4924
/* do not focus windows of these types */
4925
if (priv->type & noFocusMask)
4928
/* window doesn't take focus */
4929
if (!priv->inputHint &&
4930
!(priv->protocols & CompWindowProtocolTakeFocusMask))
4935
retval = priv->isWindowFocusAllowed (timestamp);
4938
/* add demands attention state if focus was prevented */
4939
window->changeState (priv->state | CompWindowStateDemandsAttentionMask);
4946
CompWindow::defaultViewport ()
4950
if (priv->serverGeometry.x () < (int) screen->width () &&
4951
priv->serverGeometry.x () + priv->serverGeometry.width () > 0 &&
4952
priv->serverGeometry.y () < (int) screen->height () &&
4953
priv->serverGeometry.y ()+ priv->serverGeometry.height () > 0)
4955
return screen->vp ();
4958
screen->viewportForGeometry (priv->serverGeometry, viewport);
4964
CompWindow::initialViewport () const
4966
return priv->initialViewport;
4970
PrivateWindow::readIconHint ()
4972
XImage *image, *maskImage = NULL;
4973
Display *dpy = screen->dpy ();
4974
unsigned int width, height, dummy;
4975
unsigned int i, j, k;
4982
if (!XGetGeometry (dpy, hints->icon_pixmap, &wDummy, &iDummy,
4983
&iDummy, &width, &height, &dummy, &dummy))
4986
image = XGetImage (dpy, hints->icon_pixmap, 0, 0, width, height,
4987
AllPlanes, ZPixmap);
4991
colors = new XColor[width * height];
4994
XDestroyImage (image);
4999
for (j = 0; j < height; j++)
5000
for (i = 0; i < width; i++)
5001
colors[k++].pixel = XGetPixel (image, i, j);
5003
for (i = 0; i < k; i += 256)
5004
XQueryColors (dpy, screen->priv->colormap,
5005
&colors[i], MIN (k - i, 256));
5007
XDestroyImage (image);
5009
icon = new CompIcon (screen, width, height);
5016
if (hints->flags & IconMaskHint)
5017
maskImage = XGetImage (dpy, hints->icon_mask, 0, 0,
5018
width, height, AllPlanes, ZPixmap);
5021
p = (CARD32 *) icon->data ();
5023
for (j = 0; j < height; j++)
5025
for (i = 0; i < width; i++)
5027
if (maskImage && !XGetPixel (maskImage, i, j))
5029
else if (image->depth == 1) /* white : black */
5030
*p++ = colors[k].pixel ? 0xffffffff : 0xff000000;
5032
*p++ = 0xff000000 | /* alpha */
5033
(((colors[k].red >> 8) & 0xff) << 16) | /* red */
5034
(((colors[k].green >> 8) & 0xff) << 8) | /* green */
5035
((colors[k].blue >> 8) & 0xff); /* blue */
5043
XDestroyImage (maskImage);
5045
icons.push_back (icon);
5048
/* returns icon with dimensions as close as possible to width and height
5049
but never greater. */
5051
CompWindow::getIcon (int width,
5055
int wh, diff, oldDiff;
5058
/* need to fetch icon property */
5059
if (priv->icons.size () == 0 && !priv->noIcons)
5063
unsigned long n, left;
5064
unsigned char *data;
5066
result = XGetWindowProperty (screen->dpy (), priv->id, Atoms::wmIcon,
5067
0L, 65536L, false, XA_CARDINAL,
5068
&actual, &format, &n, &left, &data);
5070
if (result == Success && data)
5073
CARD32 alpha, red, green, blue;
5074
unsigned long iw, ih;
5076
for (i = 0; i + 2 < n; i += iw * ih + 2)
5078
unsigned long *idata = (unsigned long *) data;
5083
/* iw * ih may be larger than the value range of unsigned
5084
* long, so better do some checking for extremely weird
5085
* icon sizes first */
5086
if (iw > 2048 || ih > 2048 || iw * ih + 2 > n - i)
5092
icon = new CompIcon (screen, iw, ih);
5096
priv->icons.push_back (icon);
5098
p = (CARD32 *) (icon->data ());
5100
/* EWMH doesn't say if icon data is premultiplied or
5101
not but most applications seem to assume data should
5102
be unpremultiplied. */
5103
for (j = 0; j < iw * ih; j++)
5105
alpha = (idata[i + j + 2] >> 24) & 0xff;
5106
red = (idata[i + j + 2] >> 16) & 0xff;
5107
green = (idata[i + j + 2] >> 8) & 0xff;
5108
blue = (idata[i + j + 2] >> 0) & 0xff;
5110
red = (red * alpha) >> 8;
5111
green = (green * alpha) >> 8;
5112
blue = (blue * alpha) >> 8;
5125
else if (priv->hints && (priv->hints->flags & IconPixmapHint))
5127
priv->readIconHint ();
5130
/* don't fetch property again */
5131
if (priv->icons.size () == 0)
5132
priv->noIcons = true;
5135
/* no icons available for this window */
5140
wh = width + height;
5142
for (i = 0; i < priv->icons.size (); i++)
5144
const CompSize iconSize = *priv->icons[i];
5146
if ((int) iconSize.width () > width ||
5147
(int) iconSize.height () > height)
5152
diff = wh - (iconSize.width () + iconSize.height ());
5153
oldDiff = wh - (icon->width () + icon->height ());
5156
icon = priv->icons[i];
5159
icon = priv->icons[i];
5166
CompWindow::iconGeometry () const
5168
return priv->iconGeometry;
5172
PrivateWindow::freeIcons ()
5174
for (unsigned int i = 0; i < priv->icons.size (); i++)
5175
delete priv->icons[i];
5177
priv->icons.resize (0);
5178
priv->noIcons = false;
5182
CompWindow::outputDevice ()
5184
return screen->outputDeviceForGeometry (priv->serverGeometry);
5188
CompWindow::onCurrentDesktop ()
5190
if (priv->desktop == 0xffffffff ||
5191
priv->desktop == screen->currentDesktop ())
5200
CompWindow::setDesktop (unsigned int desktop)
5202
if (desktop != 0xffffffff)
5204
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5207
if (desktop >= screen->nDesktop ())
5211
if (desktop == priv->desktop)
5214
priv->desktop = desktop;
5216
if (desktop == 0xffffffff || desktop == screen->currentDesktop ())
5221
screen->setWindowProp (priv->id, Atoms::winDesktop, priv->desktop);
5224
/* The compareWindowActiveness function compares the two windows 'w1'
5225
and 'w2'. It returns an integer less than, equal to, or greater
5226
than zero if 'w1' is found, respectively, to activated longer time
5227
ago than, to be activated at the same time, or be activated more
5228
recently than 'w2'. */
5230
PrivateWindow::compareWindowActiveness (CompWindow *w1,
5233
CompActiveWindowHistory *history = screen->currentHistory ();
5236
/* check current window history first */
5237
for (i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
5239
if (history->id[i] == w1->priv->id)
5242
if (history->id[i] == w2->priv->id)
5245
if (!history->id[i])
5249
return w1->priv->activeNum - w2->priv->activeNum;
5253
CompWindow::onAllViewports ()
5255
if (overrideRedirect ())
5258
if (!priv->managed && !isViewable ())
5261
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5264
if (priv->state & CompWindowStateStickyMask)
5271
CompWindow::getMovementForOffset (CompPoint offset)
5273
CompScreen *s = screen;
5274
int m, vWidth, vHeight;
5275
int offX = offset.x (), offY = offset.y ();
5278
vWidth = s->width () * s->vpSize ().width ();
5279
vHeight = s->height () * s->vpSize ().height ();
5285
if (s->vpSize ().width () == 1)
5291
m = priv->geometry.x () + offX;
5292
if (m - priv->input.left < (int) s->width () - vWidth)
5293
rv.setX (offX + vWidth);
5294
else if (m + priv->width + priv->input.right > vWidth)
5295
rv.setX (offX - vWidth);
5300
if (s->vpSize ().height () == 1)
5306
m = priv->geometry.y () + offY;
5307
if (m - priv->input.top < (int) s->height () - vHeight)
5308
rv.setY (offY + vHeight);
5309
else if (m + priv->height + priv->input.bottom > vHeight)
5310
rv.setY (offY - vHeight);
5319
WindowInterface::getOutputExtents (CompWindowExtents& output)
5320
WRAPABLE_DEF (getOutputExtents, output)
5323
WindowInterface::getAllowedActions (unsigned int &setActions,
5324
unsigned int &clearActions)
5325
WRAPABLE_DEF (getAllowedActions, setActions, clearActions)
5328
WindowInterface::focus ()
5329
WRAPABLE_DEF (focus)
5332
WindowInterface::activate ()
5333
WRAPABLE_DEF (activate)
5336
WindowInterface::place (CompPoint &pos)
5337
WRAPABLE_DEF (place, pos)
5340
WindowInterface::validateResizeRequest (unsigned int &mask,
5341
XWindowChanges *xwc,
5342
unsigned int source)
5343
WRAPABLE_DEF (validateResizeRequest, mask, xwc, source)
5346
WindowInterface::resizeNotify (int dx,
5350
WRAPABLE_DEF (resizeNotify, dx, dy, dwidth, dheight)
5353
WindowInterface::moveNotify (int dx,
5356
WRAPABLE_DEF (moveNotify, dx, dy, immediate)
5359
WindowInterface::windowNotify (CompWindowNotify n)
5360
WRAPABLE_DEF (windowNotify, n)
5363
WindowInterface::grabNotify (int x,
5367
WRAPABLE_DEF (grabNotify, x, y, state, mask)
5370
WindowInterface::ungrabNotify ()
5371
WRAPABLE_DEF (ungrabNotify)
5374
WindowInterface::stateChangeNotify (unsigned int lastState)
5375
WRAPABLE_DEF (stateChangeNotify, lastState)
5378
WindowInterface::updateFrameRegion (CompRegion ®ion)
5379
WRAPABLE_DEF (updateFrameRegion, region)
5382
WindowInterface::minimize ()
5383
WRAPABLE_DEF (minimize);
5386
WindowInterface::unminimize ()
5387
WRAPABLE_DEF (unminimize);
5390
WindowInterface::minimized ()
5391
WRAPABLE_DEF (minimized);
5394
WindowInterface::alpha ()
5395
WRAPABLE_DEF (alpha);
5398
WindowInterface::isFocussable ()
5399
WRAPABLE_DEF (isFocussable);
5402
WindowInterface::managed ()
5403
WRAPABLE_DEF (managed);
5418
CompWindow::state ()
5424
CompWindow::actions ()
5426
return priv->actions;
5430
CompWindow::protocols ()
5432
return priv->protocols;
5436
CompWindow::close (Time serverTime)
5438
if (serverTime == 0)
5439
serverTime = screen->getCurrentTime ();
5443
if (priv->protocols & CompWindowProtocolDeleteMask)
5447
ev.type = ClientMessage;
5448
ev.xclient.window = priv->id;
5449
ev.xclient.message_type = Atoms::wmProtocols;
5450
ev.xclient.format = 32;
5451
ev.xclient.data.l[0] = Atoms::wmDeleteWindow;
5452
ev.xclient.data.l[1] = serverTime;
5453
ev.xclient.data.l[2] = 0;
5454
ev.xclient.data.l[3] = 0;
5455
ev.xclient.data.l[4] = 0;
5457
XSendEvent (screen->dpy (), priv->id, false, NoEventMask, &ev);
5461
XKillClient (screen->dpy (), priv->id);
5464
priv->closeRequests++;
5468
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5469
serverTime, priv->id, true, 0, 0);
5472
priv->lastCloseRequestTime = serverTime;
5476
PrivateWindow::handlePingTimeout (unsigned int lastPing)
5478
if (!window->isViewable ())
5481
if (!(priv->type & CompWindowTypeNormalMask))
5484
if (priv->protocols & CompWindowProtocolPingMask)
5486
if (priv->transientFor)
5489
if (priv->lastPong < lastPing)
5493
priv->alive = false;
5495
window->windowNotify (CompWindowNotifyAliveChanged);
5497
if (priv->closeRequests)
5499
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5500
priv->lastCloseRequestTime,
5501
priv->id, true, 0, 0);
5503
priv->closeRequests = 0;
5514
PrivateWindow::handlePing (int lastPing)
5520
window->windowNotify (CompWindowNotifyAliveChanged);
5522
if (priv->lastCloseRequestTime)
5524
screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5525
priv->lastCloseRequestTime,
5526
priv->id, false, 0, 0);
5528
priv->lastCloseRequestTime = 0;
5531
priv->lastPong = lastPing;
5535
PrivateWindow::processMap ()
5538
bool initiallyMinimized;
5539
CompStackingUpdateMode stackingMode;
5541
priv->initialViewport = screen->vp ();
5543
priv->initialTimestampSet = false;
5545
screen->priv->applyStartupProperties (window);
5547
initiallyMinimized = (priv->hints &&
5548
priv->hints->initial_state == IconicState &&
5549
!window->minimized ());
5551
if (!serverFrame && !initiallyMinimized)
5554
priv->managed = true;
5558
int gravity = priv->sizeHints.win_gravity;
5562
/* adjust for gravity, but only for frame size */
5563
xwc.x = priv->serverGeometry.x ();
5564
xwc.y = priv->serverGeometry.y ();
5568
xwcm = adjustConfigureRequestForGravity (&xwc, CWX | CWY, gravity, 1);
5570
window->validateResizeRequest (xwcm, &xwc, ClientTypeApplication);
5572
CompPoint pos (xwc.x, xwc.y);
5573
if (window->place (pos))
5581
window->configureXWindow (xwcm, &xwc);
5583
priv->placed = true;
5586
allowFocus = allowWindowFocus (NO_FOCUS_MASK, 0);
5588
if (!allowFocus && (priv->type & ~NO_FOCUS_MASK))
5589
stackingMode = CompStackingUpdateModeInitialMapDeniedFocus;
5591
stackingMode = CompStackingUpdateModeInitialMap;
5593
window->updateAttributes (stackingMode);
5595
if (window->minimized () && !initiallyMinimized)
5596
window->unminimize ();
5598
screen->leaveShowDesktopMode (window);
5600
if (!initiallyMinimized)
5602
if (allowFocus && !window->onCurrentDesktop ());
5603
screen->priv->setCurrentDesktop (priv->desktop);
5605
if (!(priv->state & CompWindowStateHiddenMask))
5610
window->moveInputFocusTo ();
5611
if (!window->onCurrentDesktop ())
5612
screen->priv->setCurrentDesktop (priv->desktop);
5617
window->minimize ();
5618
window->changeState (window->state () | CompWindowStateHiddenMask);
5621
screen->priv->updateClientList ();
5625
* PrivateWindow::updatePassiveButtonGrabs
5627
* Updates the passive button grabs for a window. When
5628
* one of the specified button + modifier combinations
5629
* for this window is activated, compiz will be given
5630
* an active grab for the window (which we can turn off
5631
* by calling XAllowEvents later in ::handleEvent)
5633
* NOTE: ICCCM says that we are only allowed to grab
5634
* windows that we actually own as a client, so only
5635
* grab the frame window. Additionally, although there
5636
* isn't anything in the ICCCM that says we cannot
5637
* grab every button, some clients do not interpret
5638
* EnterNotify and LeaveNotify events caused by the
5639
* activation of the grab correctly, so ungrab button
5640
* and modifier combinations that we do not need on
5641
* active windows (but in reality we shouldn't be grabbing
5642
* for buttons that we don't actually need at that point
5647
PrivateWindow::updatePassiveButtonGrabs ()
5649
bool onlyActions = (priv->id == screen->priv->activeWindow ||
5650
!screen->priv->optionGetClickToFocus ());
5655
/* Ungrab everything */
5656
XUngrabButton (screen->priv->dpy, AnyButton, AnyModifier, frame);
5658
/* We don't need the full grab in the following cases:
5659
* - This window has the focus and either
5661
* - we don't want click raise
5666
if (screen->priv->optionGetRaiseOnClick ())
5668
CompWindow *highestSibling =
5669
PrivateWindow::findSiblingBelow (window, true);
5671
/* Check if this window is permitted to be raised */
5672
for (CompWindow *above = window->serverNext;
5673
above != NULL; above = above->serverNext)
5675
if (highestSibling == above)
5677
onlyActions = false;
5686
/* Grab only we have bindings on */
5687
foreach (PrivateScreen::ButtonGrab &bind, screen->priv->buttonGrabs)
5689
unsigned int mods = modHandler->virtualToRealModMask (bind.modifiers);
5691
if (mods & CompNoMask)
5694
for (unsigned int ignore = 0;
5695
ignore <= modHandler->ignoredModMask (); ignore++)
5697
if (ignore & ~modHandler->ignoredModMask ())
5700
XGrabButton (screen->priv->dpy,
5705
ButtonPressMask | ButtonReleaseMask |
5716
/* Grab everything */
5717
XGrabButton (screen->priv->dpy,
5721
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
5731
CompWindow::region () const
5733
return priv->region;
5737
CompWindow::frameRegion () const
5739
return priv->frameRegion;
5743
CompWindow::inShowDesktopMode ()
5745
return priv->inShowDesktopMode;
5749
CompWindow::setShowDesktopMode (bool value)
5751
priv->inShowDesktopMode = value;
5755
CompWindow::managed ()
5757
WRAPABLE_HND_FUNC_RETURN (18, bool, managed);
5758
return priv->managed;
5762
CompWindow::grabbed ()
5764
return priv->grabbed;
5768
CompWindow::pendingMaps ()
5770
return priv->pendingMaps;
5774
CompWindow::wmType ()
5776
return priv->wmType;
5780
CompWindow::activeNum ()
5782
return priv->activeNum;
5786
CompWindow::frame ()
5788
return priv->serverFrame;
5792
CompWindow::resName ()
5795
return priv->resName;
5797
return CompString ();
5801
CompWindow::mapNum () const
5803
return priv->mapNum;
5807
CompWindow::struts ()
5809
return priv->struts;
5813
CompWindow::saveMask ()
5815
return priv->saveMask;
5819
CompWindow::saveWc ()
5821
return priv->saveWc;
5825
CompWindow::moveToViewportPosition (int x,
5830
int vWidth = screen->width () * screen->vpSize ().width ();
5831
int vHeight = screen->height () * screen->vpSize ().height ();
5833
if (screen->vpSize ().width () != 1)
5835
x += screen->vp ().x () * screen->width ();
5836
x = MOD (x, vWidth);
5837
x -= screen->vp ().x () * screen->width ();
5840
if (screen->vpSize ().height () != 1)
5842
y += screen->vp ().y () * screen->height ();
5843
y = MOD (y, vHeight);
5844
y -= screen->vp ().y () * screen->height ();
5847
tx = x - priv->geometry.x ();
5848
ty = y - priv->geometry.y ();
5852
unsigned int valueMask = CWX | CWY;
5859
if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5862
if (priv->state & CompWindowStateStickyMask)
5868
if (screen->vpSize ().width ()!= 1)
5870
m = priv->geometry.x () + tx;
5872
if (m - priv->output.left < (int) screen->width () - vWidth)
5874
else if (m + priv->width + priv->output.right > vWidth)
5878
if (screen->vpSize ().height () != 1)
5880
m = priv->geometry.y () + ty;
5882
if (m - priv->output.top < (int) screen->height () - vHeight)
5884
else if (m + priv->height + priv->output.bottom > vHeight)
5888
if (priv->saveMask & CWX)
5889
priv->saveWc.x += wx;
5891
if (priv->saveMask & CWY)
5892
priv->saveWc.y += wy;
5894
xwc.x = serverGeometry ().x () + wx;
5895
xwc.y = serverGeometry ().y () + wy;
5897
configureXWindow (valueMask, &xwc);
5902
CompWindow::startupId ()
5904
return priv->startupId;
5908
PrivateWindow::applyStartupProperties (CompStartupSequence *s)
5912
priv->initialViewport.setX (s->viewportX);
5913
priv->initialViewport.setY (s->viewportY);
5915
workspace = sn_startup_sequence_get_workspace (s->sequence);
5917
window->setDesktop (workspace);
5919
priv->initialTimestamp =
5920
sn_startup_sequence_get_timestamp (s->sequence);
5921
priv->initialTimestampSet = true;
5925
CompWindow::desktop ()
5927
return priv->desktop;
5931
CompWindow::clientLeader (bool checkAncestor)
5933
if (priv->clientLeader)
5934
return priv->clientLeader;
5937
return priv->getClientLeaderOfAncestor ();
5943
CompWindow::transientFor ()
5945
return priv->transientFor;
5949
CompWindow::pendingUnmaps ()
5951
return priv->pendingUnmaps;
5955
CompWindow::minimized ()
5957
WRAPABLE_HND_FUNC_RETURN (15, bool, minimized);
5958
return priv->minimized;
5962
CompWindow::placed ()
5964
return priv->placed;
5968
CompWindow::shaded ()
5970
return priv->shaded;
5974
CompWindow::border () const
5976
return priv->border;
5980
CompWindow::input () const
5982
return priv->serverInput;
5986
CompWindow::output () const
5988
return priv->output;
5992
CompWindow::sizeHints () const
5994
return priv->sizeHints;
5998
PrivateWindow::updateMwmHints ()
6000
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
6001
window->recalcActions ();
6005
PrivateWindow::updateStartupId ()
6007
char *oldId = startupId;
6010
startupId = getStartupId ();
6012
if (oldId && startupId)
6014
if (strcmp (startupId, oldId) == 0)
6018
if (managed && startupId && newId)
6025
initialTimestampSet = false;
6026
screen->priv->applyStartupProperties (window);
6028
if (initialTimestampSet)
6029
timestamp = initialTimestamp;
6031
/* as the viewport can't be transmitted via startup
6032
notification, assume the client changing the ID
6033
wanted to activate the window on the current viewport */
6035
vp = window->defaultViewport ();
6036
svp = screen->vp ();
6039
x = window->geometry ().x () + (svp.x () - vp.x ()) * size.width ();
6040
y = window->geometry ().y () + (svp.y () - vp.y ()) * size.height ();
6041
window->moveToViewportPosition (x, y, true);
6043
if (allowWindowFocus (0, timestamp))
6044
window->activate ();
6052
CompWindow::destroyed ()
6054
return priv->destroyed;
6058
CompWindow::invisible ()
6060
return priv->invisible;
6064
CompWindow::syncAlarm ()
6066
return priv->syncAlarm;
6070
CoreWindow::manage (Window aboveId, XWindowAttributes &wa)
6072
return new CompWindow (aboveId, wa, priv);
6075
CoreWindow::CoreWindow (Window id)
6077
priv = new PrivateWindow ();
6080
priv->serverId = id;
6083
CompWindow::CompWindow (Window aboveId,
6084
XWindowAttributes &wa,
6085
PrivateWindow *priv) :
6086
PluginClassStorage (windowPluginClassIndices),
6089
StackDebugger *dbg = StackDebugger::Default ();
6091
// TODO: Reparent first!
6093
priv->window = this;
6095
screen->insertWindow (this, aboveId);
6096
screen->insertServerWindow (this, aboveId);
6098
/* We must immediately insert the window into the debugging
6101
dbg->overrideRedirectRestack (priv->id, aboveId);
6103
gettimeofday (&priv->lastConfigureRequest, NULL);
6106
priv->serverGeometry.set (priv->attrib.x, priv->attrib.y,
6107
priv->attrib.width, priv->attrib.height,
6108
priv->attrib.border_width);
6109
priv->serverFrameGeometry = priv->frameGeometry = priv->syncGeometry
6110
= priv->geometry = priv->serverGeometry;
6112
priv->width = priv->attrib.width + priv->attrib.border_width * 2;
6113
priv->height = priv->attrib.height + priv->attrib.border_width * 2;
6115
priv->sizeHints.flags = 0;
6117
priv->recalcNormalHints ();
6119
priv->transientFor = None;
6120
priv->clientLeader = None;
6122
XSelectInput (screen->dpy (), priv->id,
6123
wa.your_event_mask |
6124
PropertyChangeMask |
6128
priv->alpha = (priv->attrib.depth == 32);
6129
priv->lastPong = screen->priv->lastPing;
6131
if (screen->XShape ())
6132
XShapeSelectInput (screen->dpy (), priv->id, ShapeNotifyMask);
6134
if (priv->attrib.c_class != InputOnly)
6136
priv->region = CompRegion (priv->attrib.x, priv->attrib.y,
6137
priv->width, priv->height);
6138
priv->inputRegion = priv->region;
6140
/* need to check for DisplayModal state on all windows */
6141
priv->state = screen->priv->getWindowState (priv->id);
6143
priv->updateClassHints ();
6147
priv->attrib.map_state = IsUnmapped;
6150
priv->wmType = screen->priv->getWindowType (priv->id);
6151
priv->protocols = screen->priv->getProtocols (priv->id);
6153
if (!overrideRedirect ())
6155
priv->updateNormalHints ();
6157
priv->updateWmHints ();
6158
priv->updateTransientHint ();
6160
priv->clientLeader = priv->getClientLeader ();
6161
priv->startupId = priv->getStartupId ();
6165
screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
6167
if (!(priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask)))
6169
priv->desktop = screen->getWindowProp (priv->id, Atoms::winDesktop,
6171
if (priv->desktop != 0xffffffff)
6173
if (priv->desktop >= screen->nDesktop ())
6174
priv->desktop = screen->currentDesktop ();
6183
if (priv->attrib.map_state == IsViewable)
6185
priv->placed = true;
6187
if (!overrideRedirect ())
6189
// needs to happen right after maprequest
6190
if (!priv->serverFrame)
6192
priv->managed = true;
6194
if (screen->priv->getWmState (priv->id) == IconicState)
6196
if (priv->state & CompWindowStateShadedMask)
6197
priv->shaded = true;
6199
priv->minimized = true;
6203
if (priv->wmType & (CompWindowTypeDockMask |
6204
CompWindowTypeDesktopMask))
6206
setDesktop (0xffffffff);
6210
if (priv->desktop != 0xffffffff)
6211
priv->desktop = screen->currentDesktop ();
6213
screen->setWindowProp (priv->id, Atoms::winDesktop,
6219
priv->attrib.map_state = IsUnmapped;
6220
priv->pendingMaps++;
6224
updateAttributes (CompStackingUpdateModeNormal);
6226
if (priv->minimized || priv->inShowDesktopMode ||
6227
priv->hidden || priv->shaded)
6229
priv->state |= CompWindowStateHiddenMask;
6231
priv->pendingUnmaps++;
6233
if (priv->serverFrame && !priv->shaded)
6234
XUnmapWindow (screen->dpy (), priv->serverFrame);
6236
XUnmapWindow (screen->dpy (), priv->id);
6238
screen->priv->setWindowState (priv->state, priv->id);
6241
else if (!overrideRedirect ())
6243
if (screen->priv->getWmState (priv->id) == IconicState)
6245
// before everything else in maprequest
6246
if (!priv->serverFrame)
6248
priv->managed = true;
6249
priv->placed = true;
6251
if (priv->state & CompWindowStateHiddenMask)
6253
if (priv->state & CompWindowStateShadedMask)
6254
priv->shaded = true;
6256
priv->minimized = true;
6261
/* TODO: bailout properly when objectInitPlugins fails */
6262
assert (CompPlugin::windowInitPlugins (this));
6265
priv->updateIconGeometry ();
6269
priv->geometry.setHeight (priv->geometry.height () + 1);
6270
resize (priv->geometry.x (), priv->geometry.y (),
6271
priv->geometry.width (), priv->geometry.height () - 1,
6272
priv->geometry.border ());
6275
if (priv->attrib.map_state == IsViewable)
6277
priv->invisible = WINDOW_INVISIBLE (priv);
6281
CompWindow::~CompWindow ()
6283
if (priv->serverFrame)
6284
priv->unreparent ();
6286
/* Update the references of other windows
6287
* pending destroy if this was a sibling
6288
* of one of those */
6290
screen->priv->destroyedWindows.remove (this);
6292
foreach (CompWindow *dw, screen->priv->destroyedWindows)
6294
if (dw->next == this)
6295
dw->next = this->next;
6296
if (dw->prev == this)
6297
dw->prev = this->prev;
6299
if (dw->serverNext == this)
6300
dw->serverNext = this->serverNext;
6301
if (dw->serverPrev == this)
6302
dw->serverPrev = this->serverPrev;
6305
/* If this window has a detached frame, destroy it, but only
6306
* using XDestroyWindow since there may be pending restack
6307
* requests relative to it */
6309
std::map <CompWindow *, CompWindow *>::iterator it =
6310
screen->priv->detachedFrameWindows.find (this);
6312
if (it != screen->priv->detachedFrameWindows.end ())
6314
CompWindow *fw = (it->second);
6316
XDestroyWindow (screen->dpy (), fw->id ());
6317
screen->priv->detachedFrameWindows.erase (it);
6320
if (!priv->destroyed)
6322
StackDebugger *dbg = StackDebugger::Default ();
6324
screen->unhookWindow (this);
6325
screen->unhookServerWindow (this);
6327
/* We must immediately insert the window into the debugging
6330
dbg->removeServerWindow (id ());
6332
/* restore saved geometry and map if hidden */
6333
if (!priv->attrib.override_redirect)
6336
XConfigureWindow (screen->dpy (), priv->id,
6337
priv->saveMask, &priv->saveWc);
6341
if (priv->state & CompWindowStateHiddenMask)
6342
XMapWindow (screen->dpy (), priv->id);
6346
if (screen->XShape ())
6347
XShapeSelectInput (screen->dpy (), priv->id, NoEventMask);
6349
if (priv->id != screen->priv->grabWindow)
6350
XSelectInput (screen->dpy (), priv->id, NoEventMask);
6352
XUngrabButton (screen->dpy (), AnyButton, AnyModifier, priv->id);
6356
if (priv->attrib.map_state == IsViewable)
6358
if (priv->type == CompWindowTypeDesktopMask)
6359
screen->priv->desktopWindowCount--;
6361
if (priv->destroyed && priv->struts)
6362
screen->updateWorkarea ();
6365
if (priv->destroyed)
6366
screen->priv->updateClientList ();
6368
CompPlugin::windowFiniPlugins (this);
6373
PrivateWindow::PrivateWindow () :
6382
transientFor (None),
6383
clientLeader (None),
6391
type (CompWindowTypeUnknownMask),
6395
mwmDecor (MwmDecorAll),
6396
mwmFunc (MwmFuncAll),
6404
initialViewport (0, 0),
6406
initialTimestamp (0),
6407
initialTimestampSet (false),
6409
fullscreenMonitorsSet (false),
6413
inShowDesktopMode (false),
6422
pendingConfigures (screen->dpy ()),
6423
pendingPositionUpdates (false),
6445
closeRequests (false),
6446
lastCloseRequestTime (0)
6453
serverInput.left = 0;
6454
serverInput.right = 0;
6455
serverInput.top = 0;
6456
serverInput.bottom = 0;
6468
syncWaitTimer.setTimes (1000, 1200);
6469
syncWaitTimer.setCallback (boost::bind (&PrivateWindow::handleSyncAlarm,
6473
PrivateWindow::~PrivateWindow ()
6476
XSyncDestroyAlarm (screen->dpy (), syncAlarm);
6478
syncWaitTimer.stop ();
6481
XDestroyWindow (screen->dpy (), serverFrame);
6483
XDestroyWindow (screen->dpy (), frame);
6505
CompWindow::syncWait ()
6507
return priv->syncWait;
6511
CompWindow::alpha ()
6513
WRAPABLE_HND_FUNC_RETURN (16, bool, alpha);
6519
CompWindow::overrideRedirect ()
6521
return priv->attrib.override_redirect;
6525
PrivateWindow::setOverrideRedirect (bool overrideRedirect)
6527
if (overrideRedirect == window->overrideRedirect ())
6530
priv->attrib.override_redirect = overrideRedirect ? 1 : 0;
6531
window->recalcType ();
6532
window->recalcActions ();
6534
screen->matchPropertyChanged (window);
6538
CompWindow::isMapped () const
6540
return priv->mapNum > 0;
6544
CompWindow::isViewable () const
6546
return (priv->attrib.map_state == IsViewable);
6550
CompWindow::isFocussable ()
6552
WRAPABLE_HND_FUNC_RETURN (17, bool, isFocussable);
6554
if (priv->inputHint)
6557
if (priv->protocols & CompWindowProtocolTakeFocusMask)
6564
CompWindow::windowClass ()
6566
return priv->attrib.c_class;
6570
CompWindow::depth ()
6572
return priv->attrib.depth;
6576
CompWindow::alive ()
6582
CompWindow::mwmDecor ()
6584
return priv->mwmDecor;
6588
CompWindow::mwmFunc ()
6590
return priv->mwmFunc;
6593
/* TODO: This function should be able to check the XShape event
6594
* kind and only get/set shape rectangles for either ShapeInput
6595
* or ShapeBounding, but not both at the same time
6599
CompWindow::updateFrameRegion ()
6601
if (priv->serverFrame &&
6602
priv->serverGeometry.width () == priv->geometry.width () &&
6603
priv->serverGeometry.height () == priv->geometry.height ())
6608
priv->frameRegion = CompRegion ();
6610
updateFrameRegion (priv->frameRegion);
6614
r = priv->region.boundingRect ();
6615
priv->frameRegion -= r;
6617
r.setGeometry (r.x1 () - priv->input.left,
6618
r.y1 () - priv->input.top,
6619
r.width () + priv->input.right + priv->input.left,
6620
r.height () + priv->input.bottom + priv->input.top);
6622
priv->frameRegion &= CompRegion (r);
6625
x = priv->geometry.x () - priv->input.left;
6626
y = priv->geometry.y () - priv->input.top;
6628
XShapeCombineRegion (screen->dpy (), priv->serverFrame,
6629
ShapeBounding, -x, -y,
6630
priv->frameRegion.united (priv->region).handle (),
6633
XShapeCombineRegion (screen->dpy (), priv->serverFrame,
6635
priv->frameRegion.united (priv->inputRegion).handle (),
6641
CompWindow::setWindowFrameExtents (CompWindowExtents *b,
6642
CompWindowExtents *i)
6644
/* Input extents are used for frame size,
6645
* Border extents used for placement.
6651
if (priv->serverInput.left != i->left ||
6652
priv->serverInput.right != i->right ||
6653
priv->serverInput.top != i->top ||
6654
priv->serverInput.bottom != i->bottom ||
6655
priv->border.left != b->left ||
6656
priv->border.right != b->right ||
6657
priv->border.top != b->top ||
6658
priv->border.bottom != b->bottom)
6660
unsigned long data[4];
6662
priv->serverInput = *i;
6667
/* Use b for _NET_WM_FRAME_EXTENTS here because
6668
* that is the representation of the actual decoration
6669
* around the window that the user sees and should
6670
* be used for placement and such */
6675
data[3] = b->bottom;
6677
XChangeProperty (screen->dpy (), priv->id,
6678
Atoms::frameExtents,
6679
XA_CARDINAL, 32, PropModeReplace,
6680
(unsigned char *) data, 4);
6682
priv->updateSize ();
6683
priv->updateFrameWindow ();
6688
CompWindow::hasUnmapReference ()
6690
return (priv && priv->unmapRefCnt > 1);
6694
CompWindow::updateFrameRegion (CompRegion& region)
6695
WRAPABLE_HND_FUNC (12, updateFrameRegion, region)
6698
PrivateWindow::reparent ()
6700
XSetWindowAttributes attr;
6701
XWindowAttributes wa;
6704
unsigned int nchildren;
6705
Window *children, root_return, parent_return;
6706
Display *dpy = screen->dpy ();
6707
Visual *visual = DefaultVisual (screen->dpy (),
6708
screen->screenNum ());
6709
Colormap cmap = DefaultColormap (screen->dpy (),
6710
screen->screenNum ());
6718
if (!XGetWindowAttributes (dpy, id, &wa))
6720
XUngrabServer (dpy);
6725
if (wa.override_redirect)
6728
XSelectInput (dpy, id, NoEventMask);
6730
/* Don't ever reparent windows which have ended up
6731
* reparented themselves on the server side but not
6732
* on the client side */
6734
XQueryTree (dpy, id, &root_return, &parent_return, &children, &nchildren);
6736
if (parent_return != root_return)
6739
XUngrabServer (dpy);
6746
XQueryTree (dpy, root_return, &root_return, &parent_return, &children, &nchildren);
6748
XChangeSaveSet (dpy, id, SetModeInsert);
6750
/* Force border width to 0 */
6751
xwc.border_width = 0;
6752
XConfigureWindow (dpy, id, CWBorderWidth, &xwc);
6754
priv->serverGeometry.setBorder (0);
6756
mask = CWBorderPixel | CWColormap | CWBackPixmap | CWOverrideRedirect;
6764
attr.background_pixmap = None;
6765
attr.border_pixel = 0;
6766
attr.colormap = cmap;
6767
attr.override_redirect = true;
6769
/* Look for existing detached frame windows and reattach them
6770
* in case this window as reparented again after being withdrawn */
6771
std::map <CompWindow *, CompWindow *>::iterator it =
6772
screen->priv->detachedFrameWindows.find (window);
6774
if (it != screen->priv->detachedFrameWindows.end ())
6776
/* Trash the old frame window
6777
* TODO: It would be nicer if we could just
6778
* reparent back into it, but there are some
6779
* problems with that */
6781
XDestroyWindow (dpy, (it->second)->id ());
6782
screen->priv->detachedFrameWindows.erase (it);
6785
/* We need to know when the frame window is created
6787
XSelectInput (dpy, screen->root (), SubstructureNotifyMask);
6789
/* Awaiting a new frame to be given to us */
6791
serverFrame = XCreateWindow (dpy, screen->root (), 0, 0,
6792
wa.width, wa.height, 0, wa.depth,
6793
InputOutput, visual, mask, &attr);
6795
/* Do not get any events from here on */
6796
XSelectInput (dpy, screen->root (), NoEventMask);
6798
wrapper = XCreateWindow (dpy, serverFrame, 0, 0,
6799
wa.width, wa.height, 0, wa.depth,
6800
InputOutput, visual, mask, &attr);
6802
xwc.stack_mode = Above;
6804
/* Look for the client in the current server side stacking
6805
* order and put the frame above what the client is above
6810
/* client at the bottom */
6811
xwc.stack_mode = Below;
6816
for (unsigned int i = 0; i < nchildren; i++)
6818
if (i < nchildren - 1)
6820
if (children[i + 1] == id)
6822
xwc.sibling = children[i];
6826
else /* client on top */
6827
xwc.sibling = children[i];
6833
/* Make sure the frame is underneath the client */
6834
XConfigureWindow (dpy, serverFrame, CWSibling | CWStackMode, &xwc);
6836
/* Wait for the restacking to finish */
6839
/* Always need to have the wrapper window mapped */
6840
XMapWindow (dpy, wrapper);
6842
/* Reparent the client into the wrapper window */
6843
XReparentWindow (dpy, id, wrapper, 0, 0);
6845
/* Restore events */
6846
attr.event_mask = wa.your_event_mask;
6848
/* We don't care about client events on the frame, and listening for them
6849
* will probably end up fighting the client anyways, so disable them */
6851
attr.do_not_propagate_mask = KeyPressMask | KeyReleaseMask |
6852
ButtonPressMask | ButtonReleaseMask |
6853
EnterWindowMask | LeaveWindowMask |
6854
PointerMotionMask | PointerMotionHintMask |
6855
Button1MotionMask | Button2MotionMask |
6856
Button3MotionMask | Button4MotionMask |
6857
Button5MotionMask | ButtonMotionMask |
6858
KeymapStateMask | ExposureMask |
6859
VisibilityChangeMask | StructureNotifyMask |
6860
ResizeRedirectMask | SubstructureNotifyMask |
6861
SubstructureRedirectMask | FocusChangeMask |
6862
PropertyChangeMask | ColormapChangeMask |
6863
OwnerGrabButtonMask;
6865
XChangeWindowAttributes (dpy, id, CWEventMask | CWDontPropagate, &attr);
6867
if (wa.map_state == IsViewable || shaded)
6868
XMapWindow (dpy, serverFrame);
6870
attr.event_mask = SubstructureRedirectMask |
6871
SubstructureNotifyMask | EnterWindowMask |
6874
serverFrameGeometry = serverGeometry;
6876
XMoveResizeWindow (dpy, serverFrame, serverFrameGeometry.x (), serverFrameGeometry.y (),
6877
serverFrameGeometry.width (), serverFrameGeometry.height ());
6879
XSelectInput (dpy, screen->root (),
6880
SubstructureRedirectMask |
6881
SubstructureNotifyMask |
6882
StructureNotifyMask |
6883
PropertyChangeMask |
6893
XChangeWindowAttributes (dpy, serverFrame, CWEventMask, &attr);
6894
XChangeWindowAttributes (dpy, wrapper, CWEventMask, &attr);
6896
XUngrabServer (dpy);
6899
window->windowNotify (CompWindowNotifyReparent);
6905
PrivateWindow::unreparent ()
6907
Display *dpy = screen->dpy ();
6911
unsigned int nchildren;
6912
Window *children = NULL, root_return, parent_return;
6913
XWindowAttributes wa;
6914
StackDebugger *dbg = StackDebugger::Default ();
6921
if (XCheckTypedWindowEvent (dpy, id, DestroyNotify, &e))
6923
XPutBackEvent (dpy, &e);
6928
if (!XGetWindowAttributes (dpy, id, &wa))
6932
/* Also don't reparent back into root windows that have ended up
6933
* reparented into other windows (and as such we are unmanaging them) */
6937
XQueryTree (dpy, id, &root_return, &parent_return, &children, &nchildren);
6939
if (parent_return != wrapper)
6943
if ((!destroyed) && alive)
6947
XChangeSaveSet (dpy, id, SetModeDelete);
6948
XSelectInput (dpy, serverFrame, NoEventMask);
6949
XSelectInput (dpy, wrapper, NoEventMask);
6950
XSelectInput (dpy, id, NoEventMask);
6951
XSelectInput (dpy, screen->root (), NoEventMask);
6952
XReparentWindow (dpy, id, screen->root (), 0, 0);
6954
/* Wait for the reparent to finish */
6957
xwc.x = serverGeometry.x () - serverGeometry.border ();
6958
xwc.y = serverGeometry.y () - serverGeometry.border ();
6959
xwc.width = serverGeometry.width () + serverGeometry.border () * 2;
6960
xwc.height = serverGeometry.height () + serverGeometry.border () * 2;
6962
XConfigureWindow (dpy, serverFrame, CWX | CWY | CWWidth | CWHeight, &xwc);
6965
xwc.stack_mode = Below;
6966
xwc.sibling = serverFrame;
6967
XConfigureWindow (dpy, id, CWSibling | CWStackMode, &xwc);
6969
/* Wait for the window to be restacked */
6972
XUnmapWindow (dpy, serverFrame);
6974
XSelectInput (dpy, id, wa.your_event_mask);
6976
XSelectInput (dpy, screen->root (),
6977
SubstructureRedirectMask |
6978
SubstructureNotifyMask |
6979
StructureNotifyMask |
6980
PropertyChangeMask |
6990
XUngrabServer (dpy);
6993
XMoveWindow (dpy, id, serverGeometry.x (), serverGeometry.y ());
7000
dbg->addDestroyedFrame (serverFrame);
7002
/* This is where things get tricky ... it is possible
7003
* to receive a ConfigureNotify relative to a frame window
7004
* for a destroyed window in case we process a ConfigureRequest
7005
* for the destroyed window and then a DestroyNotify for it directly
7006
* afterwards. In that case, we will receive the ConfigureNotify
7007
* for the XConfigureWindow request we made relative to that frame
7008
* window. Because of this, we must keep the frame window in the stack
7009
* as a new toplevel window so that the ConfigureNotify will be processed
7010
* properly until it too receives a DestroyNotify */
7014
XWindowAttributes attrib;
7016
/* It's possible that the frame window was already destroyed because
7017
* the client was unreparented before it was destroyed (eg
7018
* UnmapNotify before DestroyNotify). In that case the frame window
7019
* is going to be an invalid window but since we haven't received
7020
* a DestroyNotify for it yet, it is possible that restacking
7021
* operations could occurr relative to it so we need to hold it
7022
* in the stack for now. Ensure that it is marked override redirect */
7023
XGetWindowAttributes (screen->dpy (), serverFrame, &attrib);
7025
/* Put the frame window "above" the client window
7027
CoreWindow *cw = new CoreWindow (serverFrame);
7028
CompWindow *fw = cw->manage (id, attrib);
7029
screen->priv->createdWindows.remove (cw);
7032
/* Put this window in the list of "detached frame windows"
7033
* so that we can reattach it or destroy it when we are
7036
screen->priv->detachedFrameWindows[window] = fw;
7039
/* Safe to destroy the wrapper but not the frame */
7040
XUnmapWindow (screen->dpy (), serverFrame);
7041
XDestroyWindow (screen->dpy (), wrapper);
7047
window->windowNotify (CompWindowNotifyUnreparent);