Merge lp:~jamespharaoh/ubuntu/oneiric/compiz/fix-881329 into lp:ubuntu/oneiric/compiz

Proposed by James Pharaoh
Status: Work in progress
Proposed branch: lp:~jamespharaoh/ubuntu/oneiric/compiz/fix-881329
Merge into: lp:ubuntu/oneiric/compiz
Diff against target: 72218 lines (+71073/-281)
49 files modified
.pc/.quilt_patches (+1/-0)
.pc/.quilt_series (+1/-0)
.pc/applied-patches (+10/-0)
.pc/fix-748840.patch/src/window.cpp (+6916/-0)
.pc/fix-832150.patch/src/screen.cpp (+4901/-0)
.pc/fix-832150.patch/src/window.cpp (+7071/-0)
.pc/fix-863328.patch/plugins/scale/src/privates.h (+187/-0)
.pc/fix-863328.patch/plugins/scale/src/scale.cpp (+1810/-0)
.pc/fix-864330.patch/plugins/move/src/move.cpp (+756/-0)
.pc/fix-864330.patch/src/privatescreen.h (+545/-0)
.pc/fix-864330.patch/src/privatewindow.h (+350/-0)
.pc/fix-864330.patch/src/window.cpp (+7095/-0)
.pc/fix-864478.patch/plugins/decor/src/decor.cpp (+2210/-0)
.pc/fix-864478.patch/src/event.cpp (+2083/-0)
.pc/fix-864478.patch/src/window.cpp (+7073/-0)
.pc/fix-865863.patch/src/event.cpp (+2006/-0)
.pc/fix-866752.patch/src/privatescreen.h (+480/-0)
.pc/fix-866752.patch/src/privatewindow.h (+350/-0)
.pc/fix-866752.patch/src/window.cpp (+6916/-0)
.pc/fix-869316_869919.patch/src/event.cpp (+2013/-0)
.pc/fix-869316_869919.patch/src/stackdebugger.cpp (+491/-0)
.pc/fix-869316_869919.patch/src/window.cpp (+7058/-0)
.pc/fix-869967.patch/src/window.cpp (+7048/-0)
.pc/fix-881329.patch/plugins/move/src/move.cpp (+756/-0)
.pc/fix-881329.patch/plugins/move/src/move.h (+135/-0)
debian/changelog (+41/-0)
debian/control (+0/-1)
debian/patches/fix-748840.patch (+14/-0)
debian/patches/fix-832150.patch (+50/-0)
debian/patches/fix-863328.patch (+56/-0)
debian/patches/fix-864330.patch (+541/-0)
debian/patches/fix-864478.patch (+283/-0)
debian/patches/fix-865863.patch (+110/-0)
debian/patches/fix-866752.patch (+597/-0)
debian/patches/fix-869316_869919.patch (+259/-0)
debian/patches/fix-869967.patch (+49/-0)
debian/patches/fix-881329.patch (+49/-0)
debian/patches/series (+10/-0)
plugins/decor/src/decor.cpp (+0/-2)
plugins/move/src/move.cpp (+11/-2)
plugins/move/src/move.h (+2/-0)
plugins/scale/src/privates.h (+1/-0)
plugins/scale/src/scale.cpp (+15/-0)
src/event.cpp (+135/-57)
src/privatescreen.h (+71/-0)
src/privatewindow.h (+3/-2)
src/screen.cpp (+17/-9)
src/stackdebugger.cpp (+5/-5)
src/window.cpp (+492/-203)
To merge this branch: bzr merge lp:~jamespharaoh/ubuntu/oneiric/compiz/fix-881329
Reviewer Review Type Date Requested Status
Ubuntu branches Pending
Review via email: mp+82044@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Sebastien Bacher (seb128) wrote :

Thank you for your work, it seems the diff list quite some other patches that already got uploaded, do you think you could target the merge request against lp:ubuntu/compiz rather than the oneiric serie?

Revision history for this message
Sebastien Bacher (seb128) wrote :

seems like you did a request for precise on https://code.launchpad.net/~jamespharaoh/ubuntu/precise/compiz/fix-881329/+merge/80314 which got approved, did you do an upstream merge request as commented by Sam on the other review?
If you want to do a sru for the fix it should first land in trunk and then you should do a merge request against the oneiric-proposed serie rather than the oneiric one

thank you for working on this!

Revision history for this message
Sebastien Bacher (seb128) wrote :

let we know if you need help to get that done btw

Revision history for this message
Martin Pitt (pitti) wrote :

Setting to "work in progress" to get it off the sponsoring queue, as this is currently blocked on the precise MP (https://code.launchpad.net/~jamespharaoh/ubuntu/precise/compiz/fix-881329/+merge/80314). Thanks!

Revision history for this message
James Pharaoh (jamespharaoh) wrote :

Sorry for taking ages but I'm trying to do this now. I think I do need
help. I have checked out lp:compiz and can see just a debian
directory. I assume I need to get the upstream package from somewhere
and create a patch for it using quilt or something. But I'm not sure
which upstream version I should get or how any of that is managed.

Is there some documentation for this kind of thing somewhere? I've had
a look but all I can find is the documentation I used before which
looks at packages which already have the upstream code expanded into
them. Are these generated automatically or something?

2011/11/24 Sebastien Bacher <email address hidden>:
> let we know if you need help to get that done btw
> --
> https://code.launchpad.net/~jamespharaoh/ubuntu/oneiric/compiz/fix-881329/+merge/82044
> You are the owner of lp:~jamespharaoh/ubuntu/oneiric/compiz/fix-881329.

--
James Pharaoh
Pharaoh Systems Limited
http://phsys.co.uk/contact

Unmerged revisions

253. By James Pharaoh

* debian/patches/fix-881329.patch:
  - Alt+click should raise with raise-on-click disabled (LP: #881329)

252. By Didier Roche-Tolomelli

* debian/patches/fix-864330.patch:
  - fix windows which can have towed moving (LP: #864330)
* debian/patches/fix-864478.patch:
  - Window shading is broken (LP: #864478)

251. By Didier Roche-Tolomelli

* debian/control:
  - don't suggest nvidia-glx, it's part of the old initial packaging
    and probably a bad hint on non nvidia system (LP: #844218)
* Cherry-pick upstream patches:
  - Windows should not automatically be focused when opened if the focus
    is on another application (LP: #748840)
  - Launcher - If a spread contains minimised windows, when the spread
    exits, the minimised windows momentarily appear on the desktop
    before disappearing (LP: #863328)
  - reproducible stacking bug in compiz (LP: #869316)
  - Click-dragging a window that's stacked above a fullscreen window will
    cause it to go underneath the fullscreen window (LP: #869919)
  - sometimes the keyboard input doesn't go to the apparently focussed
    dialog (LP: #869967)
  - Opening mumble can cause it to be stacked above the dash if you
    open the dash at the same time (LP: #865863)
  - Sometimes configure events are missed and windows move slow as a result
    (LP: #866752)
  - Workaround ubuntu desktop unity. Mouse at the left side doesn't reveal
    launcher (LP: #832150)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file '.pc/.quilt_patches'
2--- .pc/.quilt_patches 1970-01-01 00:00:00 +0000
3+++ .pc/.quilt_patches 2011-11-12 05:42:36 +0000
4@@ -0,0 +1,1 @@
5+debian/patches
6
7=== added file '.pc/.quilt_series'
8--- .pc/.quilt_series 1970-01-01 00:00:00 +0000
9+++ .pc/.quilt_series 2011-11-12 05:42:36 +0000
10@@ -0,0 +1,1 @@
11+series
12
13=== modified file '.pc/applied-patches'
14--- .pc/applied-patches 2011-10-04 13:49:01 +0000
15+++ .pc/applied-patches 2011-11-12 05:42:36 +0000
16@@ -3,3 +3,13 @@
17 03_fix_configureframe.patch
18 04_fix_insertServerWindow_crash.patch
19 05_fix_reconfigureXWindow_crash.patch
20+fix-748840.patch
21+fix-863328.patch
22+fix-865863.patch
23+fix-866752.patch
24+fix-869316_869919.patch
25+fix-869967.patch
26+fix-832150.patch
27+fix-864478.patch
28+fix-864330.patch
29+fix-881329.patch
30
31=== added directory '.pc/fix-748840.patch'
32=== added directory '.pc/fix-748840.patch/src'
33=== added file '.pc/fix-748840.patch/src/window.cpp'
34--- .pc/fix-748840.patch/src/window.cpp 1970-01-01 00:00:00 +0000
35+++ .pc/fix-748840.patch/src/window.cpp 2011-11-12 05:42:36 +0000
36@@ -0,0 +1,6916 @@
37+/*
38+ * Copyright © 2005 Novell, Inc.
39+ *
40+ * Permission to use, copy, modify, distribute, and sell this software
41+ * and its documentation for any purpose is hereby granted without
42+ * fee, provided that the above copyright notice appear in all copies
43+ * and that both that copyright notice and this permission notice
44+ * appear in supporting documentation, and that the name of
45+ * Novell, Inc. not be used in advertising or publicity pertaining to
46+ * distribution of the software without specific, written prior permission.
47+ * Novell, Inc. makes no representations about the suitability of this
48+ * software for any purpose. It is provided "as is" without express or
49+ * implied warranty.
50+ *
51+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
52+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
53+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
54+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
55+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
56+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
57+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
58+ *
59+ * Author: David Reveman <davidr@novell.com>
60+ */
61+
62+#include <compiz.h>
63+
64+#include <X11/Xlib.h>
65+#include <X11/Xatom.h>
66+#include <X11/Xproto.h>
67+#include <X11/extensions/shape.h>
68+
69+#include <stdio.h>
70+#include <string.h>
71+#include <strings.h>
72+#include <stdlib.h>
73+#include <stdint.h>
74+#include <assert.h>
75+#include <math.h>
76+
77+#include <boost/bind.hpp>
78+
79+#include <core/core.h>
80+#include <core/icon.h>
81+#include <core/atoms.h>
82+#include "privatewindow.h"
83+#include "privatescreen.h"
84+#include "privatestackdebugger.h"
85+
86+PluginClassStorage::Indices windowPluginClassIndices (0);
87+
88+unsigned int
89+CompWindow::allocPluginClassIndex ()
90+{
91+ unsigned int i = PluginClassStorage::allocatePluginClassIndex (windowPluginClassIndices);
92+
93+ foreach (CompWindow *w, screen->windows ())
94+ if (windowPluginClassIndices.size () != w->pluginClasses.size ())
95+ w->pluginClasses.resize (windowPluginClassIndices.size ());
96+
97+ return i;
98+}
99+
100+void
101+CompWindow::freePluginClassIndex (unsigned int index)
102+{
103+ PluginClassStorage::freePluginClassIndex (windowPluginClassIndices, index);
104+
105+ foreach (CompWindow *w, ::screen->windows ())
106+ if (windowPluginClassIndices.size () != w->pluginClasses.size ())
107+ w->pluginClasses.resize (windowPluginClassIndices.size ());
108+}
109+
110+bool
111+PrivateWindow::isAncestorTo (CompWindow *transient,
112+ CompWindow *ancestor)
113+{
114+ if (transient->priv->transientFor)
115+ {
116+ if (transient->priv->transientFor == ancestor->priv->id)
117+ return true;
118+
119+ transient = screen->findWindow (transient->priv->transientFor);
120+ if (transient)
121+ return isAncestorTo (transient, ancestor);
122+ }
123+
124+ return false;
125+}
126+
127+void
128+PrivateWindow::recalcNormalHints ()
129+{
130+ int maxSize;
131+
132+#warning fixme to max Texture size
133+ maxSize = MAXSHORT;
134+ maxSize -= serverGeometry.border () * 2;
135+
136+ sizeHints.x = serverGeometry.x ();
137+ sizeHints.y = serverGeometry.y ();
138+ sizeHints.width = serverGeometry.width ();
139+ sizeHints.height = serverGeometry.height ();
140+
141+ if (!(sizeHints.flags & PBaseSize))
142+ {
143+ if (sizeHints.flags & PMinSize)
144+ {
145+ sizeHints.base_width = sizeHints.min_width;
146+ sizeHints.base_height = sizeHints.min_height;
147+ }
148+ else
149+ {
150+ sizeHints.base_width = 0;
151+ sizeHints.base_height = 0;
152+ }
153+
154+ sizeHints.flags |= PBaseSize;
155+ }
156+
157+ if (!(sizeHints.flags & PMinSize))
158+ {
159+ sizeHints.min_width = sizeHints.base_width;
160+ sizeHints.min_height = sizeHints.base_height;
161+ sizeHints.flags |= PMinSize;
162+ }
163+
164+ if (!(sizeHints.flags & PMaxSize))
165+ {
166+ sizeHints.max_width = 65535;
167+ sizeHints.max_height = 65535;
168+ sizeHints.flags |= PMaxSize;
169+ }
170+
171+ if (sizeHints.max_width < sizeHints.min_width)
172+ sizeHints.max_width = sizeHints.min_width;
173+
174+ if (sizeHints.max_height < sizeHints.min_height)
175+ sizeHints.max_height = sizeHints.min_height;
176+
177+ if (sizeHints.min_width < 1)
178+ sizeHints.min_width = 1;
179+
180+ if (sizeHints.max_width < 1)
181+ sizeHints.max_width = 1;
182+
183+ if (sizeHints.min_height < 1)
184+ sizeHints.min_height = 1;
185+
186+ if (sizeHints.max_height < 1)
187+ sizeHints.max_height = 1;
188+
189+ if (sizeHints.max_width > maxSize)
190+ sizeHints.max_width = maxSize;
191+
192+ if (sizeHints.max_height > maxSize)
193+ sizeHints.max_height = maxSize;
194+
195+ if (sizeHints.min_width > maxSize)
196+ sizeHints.min_width = maxSize;
197+
198+ if (sizeHints.min_height > maxSize)
199+ sizeHints.min_height = maxSize;
200+
201+ if (sizeHints.base_width > maxSize)
202+ sizeHints.base_width = maxSize;
203+
204+ if (sizeHints.base_height > maxSize)
205+ sizeHints.base_height = maxSize;
206+
207+ if (sizeHints.flags & PResizeInc)
208+ {
209+ if (sizeHints.width_inc == 0)
210+ sizeHints.width_inc = 1;
211+
212+ if (sizeHints.height_inc == 0)
213+ sizeHints.height_inc = 1;
214+ }
215+ else
216+ {
217+ sizeHints.width_inc = 1;
218+ sizeHints.height_inc = 1;
219+ sizeHints.flags |= PResizeInc;
220+ }
221+
222+ if (sizeHints.flags & PAspect)
223+ {
224+ /* don't divide by 0 */
225+ if (sizeHints.min_aspect.y < 1)
226+ sizeHints.min_aspect.y = 1;
227+
228+ if (sizeHints.max_aspect.y < 1)
229+ sizeHints.max_aspect.y = 1;
230+ }
231+ else
232+ {
233+ sizeHints.min_aspect.x = 1;
234+ sizeHints.min_aspect.y = 65535;
235+ sizeHints.max_aspect.x = 65535;
236+ sizeHints.max_aspect.y = 1;
237+ sizeHints.flags |= PAspect;
238+ }
239+
240+ if (!(sizeHints.flags & PWinGravity))
241+ {
242+ sizeHints.win_gravity = NorthWestGravity;
243+ sizeHints.flags |= PWinGravity;
244+ }
245+}
246+
247+void
248+PrivateWindow::updateNormalHints ()
249+{
250+ Status status;
251+ long supplied;
252+
253+ status = XGetWMNormalHints (screen->dpy (), priv->id,
254+ &priv->sizeHints, &supplied);
255+
256+ if (!status)
257+ priv->sizeHints.flags = 0;
258+
259+ priv->recalcNormalHints ();
260+}
261+
262+void
263+PrivateWindow::updateWmHints ()
264+{
265+ XWMHints *newHints;
266+ long dFlags = 0;
267+ bool iconChanged = false;
268+
269+ if (hints)
270+ dFlags = hints->flags;
271+
272+ inputHint = true;
273+
274+ newHints = XGetWMHints (screen->dpy (), id);
275+ if (newHints)
276+ {
277+ dFlags ^= newHints->flags;
278+
279+ if (newHints->flags & InputHint)
280+ inputHint = newHints->input;
281+
282+ if (hints)
283+ {
284+ if ((newHints->flags & IconPixmapHint) &&
285+ (hints->icon_pixmap != newHints->icon_pixmap))
286+ {
287+ iconChanged = true;
288+ }
289+ else if ((newHints->flags & IconMaskHint) &&
290+ (hints->icon_mask != newHints->icon_mask))
291+ {
292+ iconChanged = true;
293+ }
294+ }
295+ }
296+
297+ iconChanged |= (dFlags & (IconPixmapHint | IconMaskHint));
298+
299+ if (iconChanged)
300+ freeIcons ();
301+
302+ if (hints)
303+ XFree (hints);
304+
305+ hints = newHints;
306+}
307+
308+void
309+PrivateWindow::updateClassHints ()
310+{
311+ XClassHint classHint;
312+ int status;
313+
314+ if (priv->resName)
315+ {
316+ free (priv->resName);
317+ priv->resName = NULL;
318+ }
319+
320+ if (priv->resClass)
321+ {
322+ free (priv->resClass);
323+ priv->resClass = NULL;
324+ }
325+
326+ status = XGetClassHint (screen->dpy (),
327+ priv->id, &classHint);
328+ if (status)
329+ {
330+ if (classHint.res_name)
331+ {
332+ priv->resName = strdup (classHint.res_name);
333+ XFree (classHint.res_name);
334+ }
335+
336+ if (classHint.res_class)
337+ {
338+ priv->resClass = strdup (classHint.res_class);
339+ XFree (classHint.res_class);
340+ }
341+ }
342+}
343+
344+void
345+PrivateWindow::updateTransientHint ()
346+{
347+ Window transientFor;
348+ Status status;
349+
350+ priv->transientFor = None;
351+
352+ status = XGetTransientForHint (screen->dpy (),
353+ priv->id, &transientFor);
354+
355+ if (status)
356+ {
357+ CompWindow *ancestor;
358+
359+ ancestor = screen->findWindow (transientFor);
360+ if (!ancestor)
361+ return;
362+
363+ /* protect against circular transient dependencies */
364+ if (transientFor == priv->id ||
365+ PrivateWindow::isAncestorTo (ancestor, window))
366+ return;
367+
368+ priv->transientFor = transientFor;
369+ }
370+}
371+
372+void
373+PrivateWindow::updateIconGeometry ()
374+{
375+ Atom actual;
376+ int result, format;
377+ unsigned long n, left;
378+ unsigned char *data;
379+
380+ priv->iconGeometry.setGeometry (0, 0, 0, 0);
381+
382+ result = XGetWindowProperty (screen->dpy (), priv->id,
383+ Atoms::wmIconGeometry,
384+ 0L, 1024L, False, XA_CARDINAL,
385+ &actual, &format, &n, &left, &data);
386+
387+ if (result == Success && data)
388+ {
389+ if (n == 4)
390+ {
391+ unsigned long *geometry = (unsigned long *) data;
392+
393+ priv->iconGeometry.setX (geometry[0]);
394+ priv->iconGeometry.setY (geometry[1]);
395+ priv->iconGeometry.setWidth (geometry[2]);
396+ priv->iconGeometry.setHeight (geometry[3]);
397+ }
398+
399+ XFree (data);
400+ }
401+}
402+
403+Window
404+PrivateWindow::getClientLeaderOfAncestor ()
405+{
406+ if (transientFor)
407+ {
408+ CompWindow *w = screen->findWindow (transientFor);
409+ if (w)
410+ {
411+ if (w->priv->clientLeader)
412+ return w->priv->clientLeader;
413+
414+ return w->priv->getClientLeaderOfAncestor ();
415+ }
416+ }
417+
418+ return None;
419+}
420+
421+Window
422+PrivateWindow::getClientLeader ()
423+{
424+ Atom actual;
425+ int result, format;
426+ unsigned long n, left;
427+ unsigned char *data;
428+
429+ result = XGetWindowProperty (screen->dpy (), priv->id,
430+ Atoms::wmClientLeader,
431+ 0L, 1L, False, XA_WINDOW, &actual, &format,
432+ &n, &left, &data);
433+
434+ if (result == Success && data)
435+ {
436+ Window win = None;
437+
438+ if (n)
439+ memcpy (&win, data, sizeof (Window));
440+
441+ XFree ((void *) data);
442+
443+ if (win)
444+ return win;
445+ }
446+
447+ return priv->getClientLeaderOfAncestor ();
448+}
449+
450+char *
451+PrivateWindow::getStartupId ()
452+{
453+ Atom actual;
454+ int result, format;
455+ unsigned long n, left;
456+ unsigned char *data;
457+
458+ result = XGetWindowProperty (screen->dpy (), priv->id,
459+ Atoms::startupId,
460+ 0L, 1024L, False,
461+ Atoms::utf8String,
462+ &actual, &format,
463+ &n, &left, &data);
464+
465+ if (result == Success && data)
466+ {
467+ char *id = NULL;
468+
469+ if (n)
470+ id = strdup ((char *) data);
471+ XFree ((void *) data);
472+
473+ return id;
474+ }
475+
476+ return NULL;
477+}
478+
479+void
480+PrivateWindow::setFullscreenMonitors (CompFullscreenMonitorSet *monitors)
481+{
482+ bool hadFsMonitors = fullscreenMonitorsSet;
483+ unsigned int outputs = screen->outputDevs ().size ();
484+
485+ fullscreenMonitorsSet = false;
486+
487+ if (monitors &&
488+ (unsigned int) monitors->left < outputs &&
489+ (unsigned int) monitors->right < outputs &&
490+ (unsigned int) monitors->top < outputs &&
491+ (unsigned int) monitors->bottom < outputs)
492+ {
493+ CompRect fsRect (screen->outputDevs ()[monitors->left].x1 (),
494+ screen->outputDevs ()[monitors->top].y1 (),
495+ screen->outputDevs ()[monitors->right].x2 (),
496+ screen->outputDevs ()[monitors->bottom].y2 ());
497+
498+ if (fsRect.x1 () < fsRect.x2 () && fsRect.y1 () < fsRect.y2 ())
499+ {
500+ fullscreenMonitorsSet = true;
501+ fullscreenMonitorRect = fsRect;
502+ }
503+ }
504+
505+ if (fullscreenMonitorsSet)
506+ {
507+ long data[4];
508+
509+ data[0] = monitors->top;
510+ data[1] = monitors->bottom;
511+ data[2] = monitors->left;
512+ data[3] = monitors->right;
513+
514+ XChangeProperty (screen->dpy (), id, Atoms::wmFullscreenMonitors,
515+ XA_CARDINAL, 32, PropModeReplace,
516+ (unsigned char *) data, 4);
517+ }
518+ else if (hadFsMonitors)
519+ {
520+ XDeleteProperty (screen->dpy (), id, Atoms::wmFullscreenMonitors);
521+ }
522+
523+ if (state & CompWindowStateFullscreenMask)
524+ if (fullscreenMonitorsSet || hadFsMonitors)
525+ window->updateAttributes (CompStackingUpdateModeNone);
526+}
527+
528+void
529+CompWindow::changeState (unsigned int newState)
530+{
531+ unsigned int oldState;
532+
533+ if (priv->state == newState)
534+ return;
535+
536+ oldState = priv->state;
537+ priv->state = newState;
538+
539+ recalcType ();
540+ recalcActions ();
541+
542+ if (priv->managed)
543+ screen->priv->setWindowState (priv->state, priv->id);
544+
545+ stateChangeNotify (oldState);
546+ screen->matchPropertyChanged (this);
547+}
548+
549+static void
550+setWindowActions (CompScreen *s,
551+ unsigned int actions,
552+ Window id)
553+{
554+ Atom data[32];
555+ int i = 0;
556+
557+ if (actions & CompWindowActionMoveMask)
558+ data[i++] = Atoms::winActionMove;
559+ if (actions & CompWindowActionResizeMask)
560+ data[i++] = Atoms::winActionResize;
561+ if (actions & CompWindowActionStickMask)
562+ data[i++] = Atoms::winActionStick;
563+ if (actions & CompWindowActionMinimizeMask)
564+ data[i++] = Atoms::winActionMinimize;
565+ if (actions & CompWindowActionMaximizeHorzMask)
566+ data[i++] = Atoms::winActionMaximizeHorz;
567+ if (actions & CompWindowActionMaximizeVertMask)
568+ data[i++] = Atoms::winActionMaximizeVert;
569+ if (actions & CompWindowActionFullscreenMask)
570+ data[i++] = Atoms::winActionFullscreen;
571+ if (actions & CompWindowActionCloseMask)
572+ data[i++] = Atoms::winActionClose;
573+ if (actions & CompWindowActionShadeMask)
574+ data[i++] = Atoms::winActionShade;
575+ if (actions & CompWindowActionChangeDesktopMask)
576+ data[i++] = Atoms::winActionChangeDesktop;
577+ if (actions & CompWindowActionAboveMask)
578+ data[i++] = Atoms::winActionAbove;
579+ if (actions & CompWindowActionBelowMask)
580+ data[i++] = Atoms::winActionBelow;
581+
582+ XChangeProperty (s->dpy (), id, Atoms::wmAllowedActions,
583+ XA_ATOM, 32, PropModeReplace,
584+ (unsigned char *) data, i);
585+}
586+
587+void
588+CompWindow::recalcActions ()
589+{
590+ unsigned int actions = 0;
591+ unsigned int setActions, clearActions;
592+
593+ switch (priv->type) {
594+ case CompWindowTypeFullscreenMask:
595+ case CompWindowTypeNormalMask:
596+ actions =
597+ CompWindowActionMaximizeHorzMask |
598+ CompWindowActionMaximizeVertMask |
599+ CompWindowActionFullscreenMask |
600+ CompWindowActionMoveMask |
601+ CompWindowActionResizeMask |
602+ CompWindowActionStickMask |
603+ CompWindowActionMinimizeMask |
604+ CompWindowActionCloseMask |
605+ CompWindowActionChangeDesktopMask;
606+ break;
607+ case CompWindowTypeUtilMask:
608+ case CompWindowTypeMenuMask:
609+ case CompWindowTypeToolbarMask:
610+ actions =
611+ CompWindowActionMoveMask |
612+ CompWindowActionResizeMask |
613+ CompWindowActionStickMask |
614+ CompWindowActionCloseMask |
615+ CompWindowActionChangeDesktopMask;
616+ break;
617+ case CompWindowTypeDialogMask:
618+ case CompWindowTypeModalDialogMask:
619+ actions =
620+ CompWindowActionMaximizeHorzMask |
621+ CompWindowActionMaximizeVertMask |
622+ CompWindowActionMoveMask |
623+ CompWindowActionResizeMask |
624+ CompWindowActionStickMask |
625+ CompWindowActionCloseMask |
626+ CompWindowActionChangeDesktopMask;
627+
628+ /* allow minimization for dialog windows if they
629+ a) are not a transient (transients can be minimized
630+ with their parent)
631+ b) don't have the skip taskbar hint set (as those
632+ have no target to be minimized to)
633+ */
634+ if (!priv->transientFor &&
635+ !(priv->state & CompWindowStateSkipTaskbarMask))
636+ {
637+ actions |= CompWindowActionMinimizeMask;
638+ }
639+ default:
640+ break;
641+ }
642+
643+ if (priv->input.top)
644+ actions |= CompWindowActionShadeMask;
645+
646+ actions |= (CompWindowActionAboveMask | CompWindowActionBelowMask);
647+
648+ switch (priv->wmType) {
649+ case CompWindowTypeNormalMask:
650+ actions |= CompWindowActionFullscreenMask |
651+ CompWindowActionMinimizeMask;
652+ default:
653+ break;
654+ }
655+
656+ if (priv->sizeHints.min_width == priv->sizeHints.max_width &&
657+ priv->sizeHints.min_height == priv->sizeHints.max_height)
658+ actions &= ~(CompWindowActionResizeMask |
659+ CompWindowActionMaximizeHorzMask |
660+ CompWindowActionMaximizeVertMask |
661+ CompWindowActionFullscreenMask);
662+
663+ if (!(priv->mwmFunc & MwmFuncAll))
664+ {
665+ if (!(priv->mwmFunc & MwmFuncResize))
666+ actions &= ~(CompWindowActionResizeMask |
667+ CompWindowActionMaximizeHorzMask |
668+ CompWindowActionMaximizeVertMask |
669+ CompWindowActionFullscreenMask);
670+
671+ if (!(priv->mwmFunc & MwmFuncMove))
672+ actions &= ~(CompWindowActionMoveMask |
673+ CompWindowActionMaximizeHorzMask |
674+ CompWindowActionMaximizeVertMask |
675+ CompWindowActionFullscreenMask);
676+
677+ if (!(priv->mwmFunc & MwmFuncIconify))
678+ actions &= ~CompWindowActionMinimizeMask;
679+
680+ if (!(priv->mwmFunc & MwmFuncClose))
681+ actions &= ~CompWindowActionCloseMask;
682+ }
683+
684+ getAllowedActions (setActions, clearActions);
685+ actions &= ~clearActions;
686+ actions |= setActions;
687+
688+ if (actions != priv->actions)
689+ {
690+ priv->actions = actions;
691+ setWindowActions (screen, actions, priv->id);
692+ }
693+}
694+
695+void
696+CompWindow::getAllowedActions (unsigned int &setActions,
697+ unsigned int &clearActions)
698+{
699+ WRAPABLE_HND_FUNC (1, getAllowedActions, setActions, clearActions)
700+
701+ setActions = 0;
702+ clearActions = 0;
703+}
704+
705+unsigned int
706+CompWindow::constrainWindowState (unsigned int state,
707+ unsigned int actions)
708+{
709+ if (!(actions & CompWindowActionMaximizeHorzMask))
710+ state &= ~CompWindowStateMaximizedHorzMask;
711+
712+ if (!(actions & CompWindowActionMaximizeVertMask))
713+ state &= ~CompWindowStateMaximizedVertMask;
714+
715+ if (!(actions & CompWindowActionShadeMask))
716+ state &= ~CompWindowStateShadedMask;
717+
718+ if (!(actions & CompWindowActionFullscreenMask))
719+ state &= ~CompWindowStateFullscreenMask;
720+
721+ return state;
722+}
723+
724+unsigned int
725+PrivateWindow::windowTypeFromString (const char *str)
726+{
727+ if (strcasecmp (str, "desktop") == 0)
728+ return CompWindowTypeDesktopMask;
729+ else if (strcasecmp (str, "dock") == 0)
730+ return CompWindowTypeDockMask;
731+ else if (strcasecmp (str, "toolbar") == 0)
732+ return CompWindowTypeToolbarMask;
733+ else if (strcasecmp (str, "menu") == 0)
734+ return CompWindowTypeMenuMask;
735+ else if (strcasecmp (str, "utility") == 0)
736+ return CompWindowTypeUtilMask;
737+ else if (strcasecmp (str, "splash") == 0)
738+ return CompWindowTypeSplashMask;
739+ else if (strcasecmp (str, "dialog") == 0)
740+ return CompWindowTypeDialogMask;
741+ else if (strcasecmp (str, "normal") == 0)
742+ return CompWindowTypeNormalMask;
743+ else if (strcasecmp (str, "dropdownmenu") == 0)
744+ return CompWindowTypeDropdownMenuMask;
745+ else if (strcasecmp (str, "popupmenu") == 0)
746+ return CompWindowTypePopupMenuMask;
747+ else if (strcasecmp (str, "tooltip") == 0)
748+ return CompWindowTypeTooltipMask;
749+ else if (strcasecmp (str, "notification") == 0)
750+ return CompWindowTypeNotificationMask;
751+ else if (strcasecmp (str, "combo") == 0)
752+ return CompWindowTypeComboMask;
753+ else if (strcasecmp (str, "dnd") == 0)
754+ return CompWindowTypeDndMask;
755+ else if (strcasecmp (str, "modaldialog") == 0)
756+ return CompWindowTypeModalDialogMask;
757+ else if (strcasecmp (str, "fullscreen") == 0)
758+ return CompWindowTypeFullscreenMask;
759+ else if (strcasecmp (str, "unknown") == 0)
760+ return CompWindowTypeUnknownMask;
761+ else if (strcasecmp (str, "any") == 0)
762+ return ~0;
763+
764+ return 0;
765+}
766+
767+void
768+CompWindow::recalcType ()
769+{
770+ unsigned int type;
771+
772+ type = priv->wmType;
773+
774+ if (!overrideRedirect () && priv->wmType == CompWindowTypeUnknownMask)
775+ type = CompWindowTypeNormalMask;
776+
777+ if (priv->state & CompWindowStateFullscreenMask)
778+ type = CompWindowTypeFullscreenMask;
779+
780+ if (type == CompWindowTypeNormalMask)
781+ {
782+ if (priv->transientFor)
783+ type = CompWindowTypeDialogMask;
784+ }
785+
786+ if (type == CompWindowTypeDockMask &&
787+ (priv->state & CompWindowStateBelowMask))
788+ {
789+ type = CompWindowTypeNormalMask;
790+ }
791+
792+ if ((type & (CompWindowTypeNormalMask | CompWindowTypeDialogMask)) &&
793+ (priv->state & CompWindowStateModalMask))
794+ {
795+ type = CompWindowTypeModalDialogMask;
796+ }
797+
798+ priv->type = type;
799+}
800+
801+
802+void
803+PrivateWindow::updateFrameWindow ()
804+{
805+ XWindowChanges xwc;
806+ unsigned int valueMask = CWX | CWY | CWWidth | CWHeight;
807+
808+ if (!serverFrame)
809+ return;
810+
811+ /* Flush any changes made to serverFrameGeometry or serverGeometry to the server
812+ * since there is a race condition where geometries will go out-of-sync with
813+ * window movement */
814+
815+ window->syncPosition ();
816+ if (serverInput.left || serverInput.right || serverInput.top || serverInput.bottom)
817+ {
818+ int bw = serverGeometry.border () * 2;
819+
820+ xwc.x = serverGeometry.x () - serverInput.left;
821+ xwc.y = serverGeometry.y () - serverInput.top;
822+ xwc.width = serverGeometry.width () + serverInput.left + serverInput.right + bw;
823+ xwc.height = serverGeometry.height () + serverInput.top + serverInput.bottom + bw;
824+
825+ if (shaded)
826+ height = serverInput.top + serverInput.bottom;
827+
828+ if (serverFrameGeometry.x () == xwc.x)
829+ valueMask &= ~(CWX);
830+ else
831+ serverFrameGeometry.setX (xwc.x);
832+
833+ if (serverFrameGeometry.y () == xwc.y)
834+ valueMask &= ~(CWY);
835+ else
836+ serverFrameGeometry.setY (xwc.y);
837+
838+ if (serverFrameGeometry.width () == xwc.width)
839+ valueMask &= ~(CWWidth);
840+ else
841+ serverFrameGeometry.setWidth (xwc.width);
842+
843+ if (serverFrameGeometry.height () == xwc.height)
844+ valueMask &= ~(CWHeight);
845+ else
846+ serverFrameGeometry.setHeight (xwc.height);
847+
848+ addPendingConfigure (xwc, valueMask);
849+
850+
851+ /* Geometry is the same, so we're not going to get a ConfigureNotify
852+ * event when the window is configured, which means that other plugins
853+ * won't know that the client, frame and wrapper windows got shifted
854+ * around (and might result in display corruption, eg in OpenGL */
855+ if (valueMask == 0)
856+ {
857+ XConfigureEvent xev;
858+ XWindowAttributes attrib;
859+ unsigned int nchildren = 0;
860+ Window rootRet = 0, parentRet = 0;
861+ Window *children = NULL;
862+
863+ xev.type = ConfigureNotify;
864+ xev.event = screen->root ();
865+ xev.window = priv->serverFrame;
866+
867+ XGrabServer (screen->dpy ());
868+
869+ if (XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib))
870+ {
871+ xev.x = attrib.x;
872+ xev.y = attrib.y;
873+ xev.width = attrib.width;
874+ xev.height = attrib.height;
875+ xev.border_width = attrib.border_width;
876+ xev.above = None;
877+
878+ /* We need to ensure that the stacking order is
879+ * based on the current server stacking order so
880+ * find the sibling to this window's frame in the
881+ * server side stack and stack above that */
882+ XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
883+
884+ if (nchildren)
885+ {
886+ for (unsigned int i = 0; i < nchildren; i++)
887+ {
888+ if (i + 1 == nchildren ||
889+ children[i + 1] == ROOTPARENT (window))
890+ {
891+ xev.above = children[i];
892+ break;
893+ }
894+ }
895+ }
896+
897+ if (children)
898+ XFree (children);
899+
900+ if (!xev.above)
901+ xev.above = (window->serverPrev) ? ROOTPARENT (window->serverPrev) : None;
902+
903+ xev.override_redirect = priv->attrib.override_redirect;
904+
905+ }
906+
907+ XSendEvent (screen->dpy (), screen->root (), false,
908+ SubstructureNotifyMask, (XEvent *) &xev);
909+
910+ XUngrabServer (screen->dpy ());
911+ XSync (screen->dpy (), false);
912+ }
913+ else
914+ XConfigureWindow (screen->dpy (), serverFrame, valueMask, &xwc);
915+ if (shaded)
916+ {
917+ XUnmapWindow (screen->dpy (), wrapper);
918+ }
919+ else
920+ {
921+ XMapWindow (screen->dpy (), wrapper);
922+ XMoveResizeWindow (screen->dpy (), wrapper, serverInput.left, serverInput.top,
923+ serverGeometry.width (), serverGeometry.height ());
924+ }
925+ XMoveResizeWindow (screen->dpy (), id, 0, 0,
926+ serverGeometry.width (), serverGeometry.height ());
927+ window->sendConfigureNotify ();
928+ window->windowNotify (CompWindowNotifyFrameUpdate);
929+ }
930+ else
931+ {
932+ int bw = serverGeometry.border () * 2;
933+
934+ xwc.x = serverGeometry.x ();
935+ xwc.y = serverGeometry.y ();
936+ xwc.width = serverGeometry.width () + bw;
937+ xwc.height = serverGeometry.height () + bw;
938+
939+ if (shaded)
940+ height = 0;
941+
942+ if (serverFrameGeometry.x () == xwc.x)
943+ valueMask &= ~(CWX);
944+ else
945+ serverFrameGeometry.setX (xwc.x);
946+
947+ if (serverFrameGeometry.y () == xwc.y)
948+ valueMask &= ~(CWY);
949+ else
950+ serverFrameGeometry.setY (xwc.y);
951+
952+ if (serverFrameGeometry.width () == xwc.width)
953+ valueMask &= ~(CWWidth);
954+ else
955+ serverFrameGeometry.setWidth (xwc.width);
956+
957+ if (serverFrameGeometry.height () == xwc.height)
958+ valueMask &= ~(CWHeight);
959+ else
960+ serverFrameGeometry.setHeight (xwc.height);
961+
962+ addPendingConfigure (xwc, valueMask);
963+
964+
965+ /* Geometry is the same, so we're not going to get a ConfigureNotify
966+ * event when the window is configured, which means that other plugins
967+ * won't know that the client, frame and wrapper windows got shifted
968+ * around (and might result in display corruption, eg in OpenGL */
969+ if (valueMask == 0)
970+ {
971+ XConfigureEvent xev;
972+ XWindowAttributes attrib;
973+ unsigned int nchildren = 0;
974+ Window rootRet = 0, parentRet = 0;
975+ Window *children = NULL;
976+
977+ xev.type = ConfigureNotify;
978+ xev.event = screen->root ();
979+ xev.window = priv->serverFrame;
980+
981+ XGrabServer (screen->dpy ());
982+
983+ if (XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib))
984+ {
985+ xev.x = attrib.x;
986+ xev.y = attrib.y;
987+ xev.width = attrib.width;
988+ xev.height = attrib.height;
989+ xev.border_width = attrib.border_width;
990+ xev.above = None;
991+
992+ /* We need to ensure that the stacking order is
993+ * based on the current server stacking order so
994+ * find the sibling to this window's frame in the
995+ * server side stack and stack above that */
996+ XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
997+
998+ if (nchildren)
999+ {
1000+ for (unsigned int i = 0; i < nchildren; i++)
1001+ {
1002+ if (i + 1 == nchildren ||
1003+ children[i + 1] == ROOTPARENT (window))
1004+ {
1005+ xev.above = children[i];
1006+ break;
1007+ }
1008+ }
1009+ }
1010+
1011+ if (children)
1012+ XFree (children);
1013+
1014+ if (!xev.above)
1015+ xev.above = (window->serverPrev) ? ROOTPARENT (window->serverPrev) : None;
1016+
1017+ xev.override_redirect = priv->attrib.override_redirect;
1018+
1019+ }
1020+
1021+ XSendEvent (screen->dpy (), screen->root (), false,
1022+ SubstructureNotifyMask, (XEvent *) &xev);
1023+
1024+ XUngrabServer (screen->dpy ());
1025+ XSync (screen->dpy (), false);
1026+ }
1027+ else
1028+ XConfigureWindow (screen->dpy (), serverFrame, valueMask, &xwc);
1029+
1030+ if (shaded)
1031+ {
1032+ XUnmapWindow (screen->dpy (), wrapper);
1033+ }
1034+ else
1035+ {
1036+ XMapWindow (screen->dpy (), wrapper);
1037+ XMoveResizeWindow (screen->dpy (), wrapper, 0, 0,
1038+ serverGeometry.width (), serverGeometry.height ());
1039+ }
1040+
1041+ XMoveResizeWindow (screen->dpy (), id, 0, 0,
1042+ serverGeometry.width (), serverGeometry.height ());
1043+ window->sendConfigureNotify ();
1044+ window->windowNotify (CompWindowNotifyFrameUpdate);
1045+ }
1046+ window->recalcActions ();
1047+}
1048+
1049+
1050+
1051+void
1052+CompWindow::updateWindowOutputExtents ()
1053+{
1054+ CompWindowExtents output (priv->output);
1055+
1056+ getOutputExtents (output);
1057+
1058+ if (output.left != priv->output.left ||
1059+ output.right != priv->output.right ||
1060+ output.top != priv->output.top ||
1061+ output.bottom != priv->output.bottom)
1062+ {
1063+ priv->output = output;
1064+
1065+ resizeNotify (0, 0, 0, 0);
1066+ }
1067+}
1068+
1069+void
1070+CompWindow::getOutputExtents (CompWindowExtents& output)
1071+{
1072+ WRAPABLE_HND_FUNC (0, getOutputExtents, output)
1073+
1074+ output.left = 0;
1075+ output.right = 0;
1076+ output.top = 0;
1077+ output.bottom = 0;
1078+}
1079+
1080+CompRegion
1081+PrivateWindow::rectsToRegion (unsigned int n, XRectangle *rects)
1082+{
1083+ CompRegion ret;
1084+ int x1, x2, y1, y2;
1085+
1086+ for (unsigned int i = 0; i < n; i++)
1087+ {
1088+ x1 = rects[i].x + priv->geometry.border ();
1089+ y1 = rects[i].y + priv->geometry.border ();
1090+ x2 = x1 + rects[i].width;
1091+ y2 = y1 + rects[i].height;
1092+
1093+ if (x1 < 0)
1094+ x1 = 0;
1095+ if (y1 < 0)
1096+ y1 = 0;
1097+ if (x2 > priv->width)
1098+ x2 = priv->width;
1099+ if (y2 > priv->height)
1100+ y2 = priv->height;
1101+
1102+ if (y1 < y2 && x1 < x2)
1103+ {
1104+ x1 += priv->geometry.x ();
1105+ y1 += priv->geometry.y ();
1106+ x2 += priv->geometry.x ();
1107+ y2 += priv->geometry.y ();
1108+
1109+ ret += CompRect (x1, y1, x2 - x1, y2 - y1);
1110+ }
1111+ }
1112+
1113+ return ret;
1114+}
1115+
1116+/* TODO: This function should be able to check the XShape event
1117+ * kind and only get/set shape rectangles for either ShapeInput
1118+ * or ShapeBounding, but not both at the same time
1119+ */
1120+
1121+void
1122+PrivateWindow::updateRegion ()
1123+{
1124+ XRectangle r, *boundingShapeRects = NULL;
1125+ XRectangle *inputShapeRects = NULL;
1126+ int nBounding = 0, nInput = 0;
1127+
1128+ priv->region = CompRegion ();
1129+ priv->inputRegion = CompRegion ();
1130+
1131+ if (screen->XShape ())
1132+ {
1133+ int order;
1134+
1135+ boundingShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
1136+ ShapeBounding, &nBounding, &order);
1137+ inputShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
1138+ ShapeInput, &nInput, &order);
1139+
1140+ }
1141+
1142+ r.x = -priv->attrib.border_width;
1143+ r.y = -priv->attrib.border_width;
1144+ r.width = priv->width + priv->attrib.border_width;
1145+ r.height = priv->height + priv->attrib.border_width;
1146+
1147+ if (nBounding < 1)
1148+ {
1149+ boundingShapeRects = &r;
1150+ nBounding = 1;
1151+ }
1152+
1153+ if (nInput < 1)
1154+ {
1155+ inputShapeRects = &r;
1156+ nBounding = 1;
1157+ }
1158+
1159+ priv->region += rectsToRegion (nBounding, boundingShapeRects);
1160+ priv->inputRegion += rectsToRegion (nInput, inputShapeRects);
1161+
1162+ if (boundingShapeRects && boundingShapeRects != &r)
1163+ XFree (boundingShapeRects);
1164+ if (inputShapeRects && inputShapeRects != &r)
1165+ XFree (inputShapeRects);
1166+
1167+ window->updateFrameRegion ();
1168+}
1169+
1170+bool
1171+CompWindow::updateStruts ()
1172+{
1173+ Atom actual;
1174+ int result, format;
1175+ unsigned long n, left;
1176+ unsigned char *data;
1177+ bool hasOld, hasNew;
1178+ CompStruts oldStrut, newStrut;
1179+
1180+ if (priv->struts)
1181+ {
1182+ hasOld = true;
1183+
1184+ oldStrut.left = priv->struts->left;
1185+ oldStrut.right = priv->struts->right;
1186+ oldStrut.top = priv->struts->top;
1187+ oldStrut.bottom = priv->struts->bottom;
1188+ }
1189+ else
1190+ {
1191+ hasOld = false;
1192+ }
1193+
1194+ hasNew = false;
1195+
1196+ newStrut.left.x = 0;
1197+ newStrut.left.y = 0;
1198+ newStrut.left.width = 0;
1199+ newStrut.left.height = screen->height ();
1200+
1201+ newStrut.right.x = screen->width ();
1202+ newStrut.right.y = 0;
1203+ newStrut.right.width = 0;
1204+ newStrut.right.height = screen->height ();
1205+
1206+ newStrut.top.x = 0;
1207+ newStrut.top.y = 0;
1208+ newStrut.top.width = screen->width ();
1209+ newStrut.top.height = 0;
1210+
1211+ newStrut.bottom.x = 0;
1212+ newStrut.bottom.y = screen->height ();
1213+ newStrut.bottom.width = screen->width ();
1214+ newStrut.bottom.height = 0;
1215+
1216+ result = XGetWindowProperty (screen->dpy (), priv->id,
1217+ Atoms::wmStrutPartial,
1218+ 0L, 12L, false, XA_CARDINAL, &actual, &format,
1219+ &n, &left, &data);
1220+
1221+ if (result == Success && data)
1222+ {
1223+ unsigned long *struts = (unsigned long *) data;
1224+
1225+ if (n == 12)
1226+ {
1227+ hasNew = true;
1228+
1229+ newStrut.left.y = struts[4];
1230+ newStrut.left.width = struts[0];
1231+ newStrut.left.height = struts[5] - newStrut.left.y + 1;
1232+
1233+ newStrut.right.width = struts[1];
1234+ newStrut.right.x = screen->width () - newStrut.right.width;
1235+ newStrut.right.y = struts[6];
1236+ newStrut.right.height = struts[7] - newStrut.right.y + 1;
1237+
1238+ newStrut.top.x = struts[8];
1239+ newStrut.top.width = struts[9] - newStrut.top.x + 1;
1240+ newStrut.top.height = struts[2];
1241+
1242+ newStrut.bottom.x = struts[10];
1243+ newStrut.bottom.width = struts[11] - newStrut.bottom.x + 1;
1244+ newStrut.bottom.height = struts[3];
1245+ newStrut.bottom.y = screen->height () - newStrut.bottom.height;
1246+ }
1247+
1248+ XFree (data);
1249+ }
1250+
1251+ if (!hasNew)
1252+ {
1253+ result = XGetWindowProperty (screen->dpy (), priv->id,
1254+ Atoms::wmStrut,
1255+ 0L, 4L, false, XA_CARDINAL,
1256+ &actual, &format, &n, &left, &data);
1257+
1258+ if (result == Success && data)
1259+ {
1260+ unsigned long *struts = (unsigned long *) data;
1261+
1262+ if (n == 4)
1263+ {
1264+ hasNew = true;
1265+
1266+ newStrut.left.x = 0;
1267+ newStrut.left.width = struts[0];
1268+
1269+ newStrut.right.width = struts[1];
1270+ newStrut.right.x = screen->width () - newStrut.right.width;
1271+
1272+ newStrut.top.y = 0;
1273+ newStrut.top.height = struts[2];
1274+
1275+ newStrut.bottom.height = struts[3];
1276+ newStrut.bottom.y = screen->height () - newStrut.bottom.height;
1277+ }
1278+
1279+ XFree (data);
1280+ }
1281+ }
1282+
1283+ if (hasNew)
1284+ {
1285+ int strutX1, strutY1, strutX2, strutY2;
1286+ int x1, y1, x2, y2;
1287+
1288+ /* applications expect us to clip struts to xinerama edges */
1289+ for (unsigned int i = 0;
1290+ i < screen->screenInfo ().size (); i++)
1291+ {
1292+ x1 = screen->screenInfo ()[i].x_org;
1293+ y1 = screen->screenInfo ()[i].y_org;
1294+ x2 = x1 + screen->screenInfo ()[i].width;
1295+ y2 = y1 + screen->screenInfo ()[i].height;
1296+
1297+ strutX1 = newStrut.left.x;
1298+ strutX2 = strutX1 + newStrut.left.width;
1299+ strutY1 = newStrut.left.y;
1300+ strutY2 = strutY1 + newStrut.left.height;
1301+
1302+ if (strutX2 > x1 && strutX2 <= x2 &&
1303+ strutY1 < y2 && strutY2 > y1)
1304+ {
1305+ newStrut.left.x = x1;
1306+ newStrut.left.width = strutX2 - x1;
1307+ }
1308+
1309+ strutX1 = newStrut.right.x;
1310+ strutX2 = strutX1 + newStrut.right.width;
1311+ strutY1 = newStrut.right.y;
1312+ strutY2 = strutY1 + newStrut.right.height;
1313+
1314+ if (strutX1 > x1 && strutX1 <= x2 &&
1315+ strutY1 < y2 && strutY2 > y1)
1316+ {
1317+ newStrut.right.x = strutX1;
1318+ newStrut.right.width = x2 - strutX1;
1319+ }
1320+
1321+ strutX1 = newStrut.top.x;
1322+ strutX2 = strutX1 + newStrut.top.width;
1323+ strutY1 = newStrut.top.y;
1324+ strutY2 = strutY1 + newStrut.top.height;
1325+
1326+ if (strutX1 < x2 && strutX2 > x1 &&
1327+ strutY2 > y1 && strutY2 <= y2)
1328+ {
1329+ newStrut.top.y = y1;
1330+ newStrut.top.height = strutY2 - y1;
1331+ }
1332+
1333+ strutX1 = newStrut.bottom.x;
1334+ strutX2 = strutX1 + newStrut.bottom.width;
1335+ strutY1 = newStrut.bottom.y;
1336+ strutY2 = strutY1 + newStrut.bottom.height;
1337+
1338+ if (strutX1 < x2 && strutX2 > x1 &&
1339+ strutY1 > y1 && strutY1 <= y2)
1340+ {
1341+ newStrut.bottom.y = strutY1;
1342+ newStrut.bottom.height = y2 - strutY1;
1343+ }
1344+ }
1345+ }
1346+
1347+ if (hasOld != hasNew ||
1348+ (hasNew && hasOld &&
1349+ memcmp (&newStrut, &oldStrut, sizeof (CompStruts))))
1350+ {
1351+ if (hasNew)
1352+ {
1353+ if (!priv->struts)
1354+ {
1355+ priv->struts = (CompStruts *) malloc (sizeof (CompStruts));
1356+ if (!priv->struts)
1357+ return false;
1358+ }
1359+
1360+ *priv->struts = newStrut;
1361+ }
1362+ else
1363+ {
1364+ free (priv->struts);
1365+ priv->struts = NULL;
1366+ }
1367+
1368+ return true;
1369+ }
1370+
1371+ return false;
1372+}
1373+
1374+void
1375+CompWindow::incrementDestroyReference ()
1376+{
1377+ priv->destroyRefCnt++;
1378+}
1379+
1380+void
1381+CompWindow::destroy ()
1382+{
1383+ if (priv->id)
1384+ {
1385+ CompWindow *oldServerNext, *oldServerPrev, *oldNext, *oldPrev;
1386+ StackDebugger *dbg = StackDebugger::Default ();
1387+
1388+ windowNotify (CompWindowNotifyBeforeDestroy);
1389+
1390+ /* Don't allow frame windows to block input */
1391+ XUnmapWindow (screen->dpy (), priv->serverFrame);
1392+ XUnmapWindow (screen->dpy (), priv->wrapper);
1393+
1394+ oldServerNext = serverNext;
1395+ oldServerPrev = serverPrev;
1396+ oldNext = next;
1397+ oldPrev = prev;
1398+
1399+ /* This is where things get tricky ... it is possible
1400+ * to receive a ConfigureNotify relative to a frame window
1401+ * for a destroyed window in case we process a ConfigureRequest
1402+ * for the destroyed window and then a DestroyNotify for it directly
1403+ * afterwards. In that case, we will receive the ConfigureNotify
1404+ * for the XConfigureWindow request we made relative to that frame
1405+ * window. Because of this, we must keep the frame window in the stack
1406+ * as a new toplevel window so that the ConfigureNotify will be processed
1407+ * properly until it too receives a DestroyNotify */
1408+
1409+ if (priv->serverFrame)
1410+ {
1411+ XWindowAttributes attrib;
1412+
1413+ /* It's possible that the frame window was already destroyed because
1414+ * the client was unreparented before it was destroyed (eg
1415+ * UnmapNotify before DestroyNotify). In that case the frame window
1416+ * is going to be an invalid window but since we haven't received
1417+ * a DestroyNotify for it yet, it is possible that restacking
1418+ * operations could occurr relative to it so we need to hold it
1419+ * in the stack for now. Ensure that it is marked override redirect */
1420+ XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib);
1421+
1422+ /* Put the frame window "above" the client window
1423+ * in the stack */
1424+ CoreWindow *cw = new CoreWindow (priv->serverFrame);
1425+ cw->manage (priv->id, attrib);
1426+ screen->priv->createdWindows.remove (cw);
1427+ delete cw;
1428+ }
1429+
1430+ /* Immediately unhook the window once destroyed
1431+ * as the stacking order will be invalid if we don't
1432+ * and will continue to be invalid for the period
1433+ * that we keep it around in the stack. Instead, push
1434+ * it to another stack and keep the next and prev members
1435+ * in tact, letting plugins sort out where those windows
1436+ * might be in case they need to use them relative to
1437+ * other windows */
1438+
1439+ screen->unhookWindow (this);
1440+ screen->unhookServerWindow (this);
1441+
1442+ /* We must immediately insert the window into the debugging
1443+ * stack */
1444+ if (dbg)
1445+ dbg->removeServerWindow (id ());
1446+
1447+ /* Unhooking the window will also NULL the next/prev
1448+ * linked list links but we don't want that so don't
1449+ * do that */
1450+
1451+ next = oldNext;
1452+ prev = oldPrev;
1453+ serverNext = oldServerNext;
1454+ serverPrev = oldServerPrev;
1455+
1456+ screen->priv->destroyedWindows.push_back (this);
1457+
1458+ /* We must set the xid of this window
1459+ * to zero as it no longer references
1460+ * a valid window */
1461+ priv->mapNum = 0;
1462+ priv->id = 0;
1463+ priv->frame = 0;
1464+ priv->serverFrame = 0;
1465+ priv->managed = false;
1466+ }
1467+
1468+ priv->destroyRefCnt--;
1469+ if (priv->destroyRefCnt)
1470+ return;
1471+
1472+ if (!priv->destroyed)
1473+ {
1474+ if (!priv->serverFrame)
1475+ {
1476+ StackDebugger *dbg = StackDebugger::Default ();
1477+
1478+ if (dbg)
1479+ dbg->addDestroyedFrame (priv->serverId);
1480+ }
1481+
1482+ priv->destroyed = true;
1483+ screen->priv->pendingDestroys++;
1484+ }
1485+
1486+}
1487+
1488+void
1489+CompWindow::sendConfigureNotify ()
1490+{
1491+ XConfigureEvent xev;
1492+ XWindowAttributes attrib;
1493+ unsigned int nchildren;
1494+ Window rootRet, parentRet;
1495+ Window *children;
1496+
1497+ xev.type = ConfigureNotify;
1498+ xev.event = priv->id;
1499+ xev.window = priv->id;
1500+
1501+ /* in order to avoid race conditions we must use the current
1502+ * server configuration */
1503+
1504+ XGrabServer (screen->dpy ());
1505+ XSync (screen->dpy (), false);
1506+
1507+ if (XGetWindowAttributes (screen->dpy (), priv->id, &attrib))
1508+ {
1509+ xev.x = attrib.x;
1510+ xev.y = attrib.y;
1511+ xev.width = attrib.width;
1512+ xev.height = attrib.height;
1513+ xev.border_width = attrib.border_width;
1514+ xev.above = None;
1515+
1516+ if (priv->frame)
1517+ {
1518+ XWindowAttributes fAttrib;
1519+ XWindowAttributes wAttrib;
1520+
1521+ /* Add offset between wrapper and client */
1522+ if (XGetWindowAttributes (screen->dpy (), priv->wrapper, &wAttrib))
1523+ {
1524+ xev.x += wAttrib.x;
1525+ xev.y += wAttrib.y;
1526+ }
1527+
1528+ /* Add offset between frame and client */
1529+ if (XGetWindowAttributes (screen->dpy (), priv->frame, &fAttrib))
1530+ {
1531+ xev.x += fAttrib.x;
1532+ xev.y += fAttrib.y;
1533+ }
1534+ }
1535+
1536+ /* We need to ensure that the stacking order is
1537+ * based on the current server stacking order so
1538+ * find the sibling to this window's frame in the
1539+ * server side stack and stack above that */
1540+ XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren);
1541+
1542+ if (nchildren)
1543+ {
1544+ for (unsigned int i = 0; i < nchildren; i++)
1545+ {
1546+ if (i + 1 == nchildren ||
1547+ children[i + 1] == ROOTPARENT (this))
1548+ {
1549+ xev.above = children[i];
1550+ break;
1551+ }
1552+ }
1553+ }
1554+
1555+ if (children)
1556+ XFree (children);
1557+
1558+ if (!xev.above)
1559+ xev.above = (serverPrev) ? ROOTPARENT (serverPrev) : None;
1560+ xev.override_redirect = priv->attrib.override_redirect;
1561+
1562+ XSendEvent (screen->dpy (), priv->id, false,
1563+ StructureNotifyMask, (XEvent *) &xev);
1564+ }
1565+
1566+ XUngrabServer (screen->dpy ());
1567+ XSync (screen->dpy (), false);
1568+}
1569+
1570+void
1571+CompWindow::map ()
1572+{
1573+ windowNotify (CompWindowNotifyBeforeMap);
1574+
1575+ if (!isViewable ())
1576+ {
1577+ if (priv->pendingMaps > 0)
1578+ priv->pendingMaps = 0;
1579+
1580+ priv->mapNum = screen->priv->mapNum++;
1581+
1582+ if (priv->struts)
1583+ screen->updateWorkarea ();
1584+
1585+ if (windowClass () == InputOnly)
1586+ return;
1587+
1588+ priv->unmapRefCnt = 1;
1589+
1590+ priv->attrib.map_state = IsViewable;
1591+
1592+ if (!overrideRedirect ())
1593+ screen->priv->setWmState (NormalState, priv->id);
1594+
1595+ priv->invisible = true;
1596+ priv->alive = true;
1597+
1598+ priv->lastPong = screen->priv->lastPing;
1599+
1600+ priv->updateRegion ();
1601+ priv->updateSize ();
1602+
1603+ screen->priv->updateClientList ();
1604+
1605+ if (priv->type & CompWindowTypeDesktopMask)
1606+ screen->priv->desktopWindowCount++;
1607+
1608+ if (priv->protocols & CompWindowProtocolSyncRequestMask)
1609+ {
1610+ sendSyncRequest ();
1611+ sendConfigureNotify ();
1612+ }
1613+
1614+ if (!overrideRedirect ())
1615+ {
1616+ /* been shaded */
1617+ if (!priv->height)
1618+ {
1619+ priv->geometry.setHeight (priv->geometry.height () + 1);
1620+ resize (priv->geometry.x (), priv->geometry.y (), priv->geometry.width (),
1621+ priv->geometry.height () - 1, priv->geometry.border ());
1622+ }
1623+ }
1624+ }
1625+
1626+ windowNotify (CompWindowNotifyMap);
1627+}
1628+
1629+void
1630+CompWindow::incrementUnmapReference ()
1631+{
1632+ priv->unmapRefCnt++;
1633+}
1634+
1635+void
1636+CompWindow::unmap ()
1637+{
1638+ windowNotify (CompWindowNotifyBeforeUnmap);
1639+
1640+ if (priv->mapNum)
1641+ priv->mapNum = 0;
1642+
1643+ /* Even though we're still keeping the backing
1644+ * pixmap of the window around, it's safe to
1645+ * unmap the frame window since there's no use
1646+ * for it at this point anyways and it just blocks
1647+ * input */
1648+
1649+ XUnmapWindow (screen->dpy (), priv->wrapper);
1650+ XUnmapWindow (screen->dpy (), priv->serverFrame);
1651+
1652+ priv->unmapRefCnt--;
1653+ if (priv->unmapRefCnt > 0)
1654+ return;
1655+
1656+ if (priv->unmanaging)
1657+ {
1658+ XWindowChanges xwc;
1659+ unsigned int xwcm;
1660+ int gravity = priv->sizeHints.win_gravity;
1661+
1662+ /* revert gravity adjustment made at MapNotify time */
1663+ xwc.x = priv->serverGeometry.x ();
1664+ xwc.y = priv->serverGeometry.y ();
1665+ xwc.width = 0;
1666+ xwc.height = 0;
1667+
1668+ xwcm = priv->adjustConfigureRequestForGravity (&xwc,
1669+ CWX | CWY,
1670+ gravity,
1671+ -1);
1672+ if (xwcm)
1673+ configureXWindow (xwcm, &xwc);
1674+
1675+ priv->unmanaging = false;
1676+ }
1677+
1678+ if (priv->serverFrame)
1679+ priv->unreparent ();
1680+
1681+ if (priv->struts)
1682+ screen->updateWorkarea ();
1683+
1684+ if (priv->attrib.map_state != IsViewable)
1685+ return;
1686+
1687+ if (priv->type == CompWindowTypeDesktopMask)
1688+ screen->priv->desktopWindowCount--;
1689+
1690+ priv->attrib.map_state = IsUnmapped;
1691+
1692+ priv->invisible = true;
1693+
1694+ if (priv->shaded && priv->height)
1695+ resize (priv->attrib.x, priv->attrib.y,
1696+ priv->attrib.width, ++priv->attrib.height - 1,
1697+ priv->attrib.border_width);
1698+
1699+ screen->priv->updateClientList ();
1700+
1701+ windowNotify (CompWindowNotifyUnmap);
1702+}
1703+
1704+void
1705+PrivateWindow::withdraw ()
1706+{
1707+ if (!attrib.override_redirect)
1708+ screen->priv->setWmState (WithdrawnState, id);
1709+
1710+ placed = false;
1711+ unmanaging = managed;
1712+ managed = false;
1713+}
1714+
1715+bool
1716+PrivateWindow::restack (Window aboveId)
1717+{
1718+ if (aboveId && (aboveId == id || aboveId == serverFrame))
1719+ // Don't try to raise a window above itself
1720+ return false;
1721+ else if (window->prev)
1722+ {
1723+ if (aboveId && (aboveId == window->prev->id () ||
1724+ aboveId == window->prev->priv->frame))
1725+ return false;
1726+ }
1727+ else if (aboveId == None && !window->next)
1728+ return false;
1729+
1730+ if (aboveId && !screen->findTopLevelWindow (aboveId, true))
1731+ {
1732+ return false;
1733+ }
1734+
1735+ screen->unhookWindow (window);
1736+ screen->insertWindow (window, aboveId);
1737+
1738+ /* Update the server side window list for
1739+ * override redirect windows immediately
1740+ * since there is no opportunity to update
1741+ * the server side list when we configure them
1742+ * since we never get a ConfigureRequest for those */
1743+ if (attrib.override_redirect != 0)
1744+ {
1745+ StackDebugger *dbg = StackDebugger::Default ();
1746+
1747+ screen->unhookServerWindow (window);
1748+ screen->insertServerWindow (window, aboveId);
1749+
1750+ if (dbg)
1751+ dbg->overrideRedirectRestack (window->id (), aboveId);
1752+ }
1753+
1754+ screen->priv->updateClientList ();
1755+
1756+ window->windowNotify (CompWindowNotifyRestack);
1757+
1758+ return true;
1759+}
1760+
1761+bool
1762+CompWindow::resize (XWindowAttributes attr)
1763+{
1764+ return resize (Geometry (attr.x, attr.y, attr.width, attr.height,
1765+ attr.border_width));
1766+}
1767+
1768+bool
1769+CompWindow::resize (int x,
1770+ int y,
1771+ int width,
1772+ int height,
1773+ int border)
1774+{
1775+ return resize (Geometry (x, y, width, height, border));
1776+}
1777+
1778+bool
1779+CompWindow::resize (CompWindow::Geometry gm)
1780+{
1781+ /* Input extents are now the last thing sent
1782+ * from the server. This might not work in some
1783+ * cases though because setWindowFrameExtents may
1784+ * be called more than once in an event processing
1785+ * cycle so every set of input extents up until the
1786+ * last one will be invalid. The real solution
1787+ * here is to handle ConfigureNotify events on
1788+ * frame windows and client windows separately */
1789+
1790+ priv->input = priv->serverInput;
1791+
1792+ if (priv->geometry.width () != gm.width () ||
1793+ priv->geometry.height () != gm.height () ||
1794+ priv->geometry.border () != gm.border ())
1795+ {
1796+ int pw, ph;
1797+ int dx, dy, dwidth, dheight;
1798+
1799+ pw = gm.width () + gm.border () * 2;
1800+ ph = gm.height () + gm.border () * 2;
1801+
1802+ if (priv->shaded)
1803+ ph = 0;
1804+
1805+ dx = gm.x () - priv->geometry.x ();
1806+ dy = gm.y () - priv->geometry.y ();
1807+ dwidth = gm.width () - priv->geometry.width ();
1808+ dheight = gm.height () - priv->geometry.height ();
1809+
1810+ priv->geometry.set (gm.x (), gm.y (),
1811+ gm.width (), gm.height (),
1812+ gm.border ());
1813+
1814+ priv->width = pw;
1815+ priv->height = ph;
1816+
1817+ if (priv->mapNum)
1818+ priv->updateRegion ();
1819+
1820+ resizeNotify (dx, dy, dwidth, dheight);
1821+
1822+ priv->invisible = WINDOW_INVISIBLE (priv);
1823+ }
1824+ else if (priv->geometry.x () != gm.x () || priv->geometry.y () != gm.y ())
1825+ {
1826+ int dx, dy;
1827+
1828+ dx = gm.x () - priv->geometry.x ();
1829+ dy = gm.y () - priv->geometry.y ();
1830+
1831+ priv->geometry.setX (gm.x ());
1832+ priv->geometry.setY (gm.y ());
1833+
1834+ priv->region.translate (dx, dy);
1835+ priv->inputRegion.translate (dx, dy);
1836+ if (!priv->frameRegion.isEmpty ())
1837+ priv->frameRegion.translate (dx, dy);
1838+
1839+ priv->invisible = WINDOW_INVISIBLE (priv);
1840+
1841+ moveNotify (dx, dy, true);
1842+ }
1843+
1844+ updateFrameRegion ();
1845+
1846+ return true;
1847+}
1848+
1849+static void
1850+syncValueIncrement (XSyncValue *value)
1851+{
1852+ XSyncValue one;
1853+ int overflow;
1854+
1855+ XSyncIntToValue (&one, 1);
1856+ XSyncValueAdd (value, *value, one, &overflow);
1857+}
1858+
1859+bool
1860+PrivateWindow::initializeSyncCounter ()
1861+{
1862+ XSyncAlarmAttributes values;
1863+ Atom actual;
1864+ int result, format;
1865+ unsigned long n, left;
1866+ unsigned char *data;
1867+
1868+ if (syncCounter)
1869+ return syncAlarm != None;
1870+
1871+ if (!(protocols & CompWindowProtocolSyncRequestMask))
1872+ return false;
1873+
1874+ result = XGetWindowProperty (screen->dpy (), id,
1875+ Atoms::wmSyncRequestCounter,
1876+ 0L, 1L, false, XA_CARDINAL, &actual, &format,
1877+ &n, &left, &data);
1878+
1879+ if (result == Success && n && data)
1880+ {
1881+ unsigned long *counter = (unsigned long *) data;
1882+
1883+ syncCounter = *counter;
1884+
1885+ XFree (data);
1886+
1887+ XSyncIntsToValue (&syncValue, (unsigned int) rand (), 0);
1888+ XSyncSetCounter (screen->dpy (),
1889+ syncCounter,
1890+ syncValue);
1891+
1892+ syncValueIncrement (&syncValue);
1893+
1894+ values.events = true;
1895+
1896+ values.trigger.counter = syncCounter;
1897+ values.trigger.wait_value = syncValue;
1898+
1899+ values.trigger.value_type = XSyncAbsolute;
1900+ values.trigger.test_type = XSyncPositiveComparison;
1901+
1902+ XSyncIntToValue (&values.delta, 1);
1903+
1904+ values.events = true;
1905+
1906+ CompScreen::checkForError (screen->dpy ());
1907+
1908+ /* Note that by default, the alarm increments the trigger value
1909+ * when it fires until the condition (counter.value < trigger.value)
1910+ * is false again.
1911+ */
1912+ syncAlarm = XSyncCreateAlarm (screen->dpy (),
1913+ XSyncCACounter |
1914+ XSyncCAValue |
1915+ XSyncCAValueType |
1916+ XSyncCATestType |
1917+ XSyncCADelta |
1918+ XSyncCAEvents,
1919+ &values);
1920+
1921+ if (CompScreen::checkForError (screen->dpy ()))
1922+ return true;
1923+
1924+ XSyncDestroyAlarm (screen->dpy (), syncAlarm);
1925+ syncAlarm = None;
1926+ }
1927+ else if (result == Success && data)
1928+ {
1929+ XFree (data);
1930+ }
1931+
1932+ return false;
1933+}
1934+
1935+void
1936+CompWindow::sendSyncRequest ()
1937+{
1938+ XClientMessageEvent xev;
1939+
1940+ if (priv->syncWait)
1941+ return;
1942+
1943+ if (!priv->initializeSyncCounter ())
1944+ return;
1945+
1946+ xev.type = ClientMessage;
1947+ xev.window = priv->id;
1948+ xev.message_type = Atoms::wmProtocols;
1949+ xev.format = 32;
1950+ xev.data.l[0] = Atoms::wmSyncRequest;
1951+ xev.data.l[1] = CurrentTime;
1952+ xev.data.l[2] = XSyncValueLow32 (priv->syncValue);
1953+ xev.data.l[3] = XSyncValueHigh32 (priv->syncValue);
1954+ xev.data.l[4] = 0;
1955+
1956+ syncValueIncrement (&priv->syncValue);
1957+
1958+ XSendEvent (screen->dpy (), priv->id, false, 0, (XEvent *) &xev);
1959+
1960+ priv->syncWait = true;
1961+ priv->syncGeometry = priv->serverGeometry;
1962+
1963+ if (!priv->syncWaitTimer.active ())
1964+ priv->syncWaitTimer.start ();
1965+}
1966+
1967+void
1968+PrivateWindow::configure (XConfigureEvent *ce)
1969+{
1970+ unsigned int valueMask = 0;
1971+
1972+ if (priv->frame)
1973+ return;
1974+
1975+ /* remove configure event from pending configures */
1976+ if (priv->geometry.x () != ce->x)
1977+ valueMask |= CWX;
1978+
1979+ if (priv->geometry.y () != ce->y)
1980+ valueMask |= CWY;
1981+
1982+ if (priv->geometry.width () != ce->width)
1983+ valueMask |= CWWidth;
1984+
1985+ if (priv->geometry.height () != ce->height)
1986+ valueMask |= CWHeight;
1987+
1988+ if (priv->geometry.border () != ce->border_width)
1989+ valueMask |= CWBorderWidth;
1990+
1991+ if (ROOTPARENT (window->prev) != ce->above)
1992+ valueMask |= CWSibling | CWStackMode;
1993+
1994+ priv->attrib.override_redirect = ce->override_redirect;
1995+
1996+ priv->frameGeometry.set (ce->x, ce->y, ce->width,
1997+ ce->height, ce->border_width);
1998+
1999+ if (priv->syncWait)
2000+ priv->syncGeometry.set (ce->x, ce->y, ce->width, ce->height,
2001+ ce->border_width);
2002+ else
2003+ {
2004+ if (ce->override_redirect)
2005+ {
2006+ priv->serverGeometry.set (ce->x, ce->y, ce->width, ce->height,
2007+ ce->border_width);
2008+ }
2009+
2010+ window->resize (ce->x, ce->y, ce->width, ce->height, ce->border_width);
2011+ }
2012+
2013+ if (ce->event == screen->root ())
2014+ priv->restack (ce->above);
2015+}
2016+
2017+void
2018+PrivateWindow::configureFrame (XConfigureEvent *ce)
2019+{
2020+ int x, y, width, height;
2021+ CompWindow *above;
2022+ unsigned int valueMask = 0;
2023+ bool handled = false;
2024+
2025+ if (!priv->frame)
2026+ return;
2027+
2028+ /* remove configure event from pending configures */
2029+ if (priv->frameGeometry.x () != ce->x)
2030+ valueMask |= CWX;
2031+
2032+ if (priv->frameGeometry.y () != ce->y)
2033+ valueMask |= CWY;
2034+
2035+ if (priv->frameGeometry.width () != ce->width)
2036+ valueMask |= CWWidth;
2037+
2038+ if (priv->frameGeometry.height () != ce->height)
2039+ valueMask |= CWHeight;
2040+
2041+ if (priv->frameGeometry.border () != ce->border_width)
2042+ valueMask |= CWBorderWidth;
2043+
2044+ if (window->prev)
2045+ {
2046+ if (ROOTPARENT (window->prev) != ce->above)
2047+ valueMask |= CWSibling | CWStackMode;
2048+ }
2049+ else
2050+ {
2051+ if (ce->above != 0)
2052+ valueMask |= CWSibling | CWStackMode;
2053+ }
2054+
2055+ for (std::list <XWCValueMask>::iterator it = pendingConfigures.begin ();
2056+ it != pendingConfigures.end (); it++)
2057+ {
2058+ XWCValueMask &xwcvm = (*it);
2059+
2060+
2061+ if (xwcvm.second != valueMask)
2062+ {
2063+ /* For stacking cases, if a client wants to raise or lower a window
2064+ * then they don't need to specify CWSibling, so allow that to be
2065+ * excluded in those cases */
2066+
2067+ if (ce->above == ROOTPARENT (screen->windows ().back ()) ||
2068+ ce->above == 0)
2069+ {
2070+ if ((xwcvm.second & ~(CWSibling)) != valueMask)
2071+ continue;
2072+ }
2073+ else
2074+ continue;
2075+ }
2076+
2077+ if (xwcvm.second & CWX && xwcvm.first.x != ce->x)
2078+ continue;
2079+
2080+ if (xwcvm.second & CWY && xwcvm.first.y != ce->y)
2081+ continue;
2082+
2083+ if (xwcvm.second & CWWidth && xwcvm.first.width != ce->width)
2084+ continue;
2085+
2086+ if (xwcvm.second & CWHeight && xwcvm.first.height != ce->height)
2087+ continue;
2088+
2089+ if (xwcvm.second & (CWStackMode | CWSibling) && xwcvm.first.sibling != ce->above)
2090+ continue;
2091+
2092+ /* Matched ConfigureWindow request to ConfigureNotify event
2093+ * remove it from the list */
2094+
2095+ handled = true;
2096+
2097+ pendingConfigures.erase (it);
2098+ break;
2099+ }
2100+
2101+ if (!handled)
2102+ {
2103+ compLogMessage ("core", CompLogLevelWarn, "unhandled ConfigureNotify on 0x%x!", serverFrame);
2104+ compLogMessage ("core", CompLogLevelWarn, "this should never happen. you should"\
2105+ "probably file a bug about this.");
2106+#ifdef DEBUG
2107+ abort ();
2108+#else
2109+ pendingConfigures.clear ();
2110+#endif
2111+ }
2112+
2113+ /* subtract the input extents last sent to the
2114+ * server to calculate the client size and then
2115+ * re-sync the input extents and extents last
2116+ * sent to server on resize () */
2117+
2118+ x = ce->x + priv->serverInput.left;
2119+ y = ce->y + priv->serverInput.top;
2120+ width = ce->width - priv->serverGeometry.border () * 2 - priv->serverInput.left - priv->serverInput.right;
2121+ height = ce->height - priv->serverGeometry.border () * 2 - priv->serverInput.top - priv->serverInput.bottom;
2122+
2123+ /* set the frame geometry */
2124+ priv->frameGeometry.set (ce->x, ce->y, ce->width, ce->height, ce->border_width);
2125+
2126+
2127+ if (priv->syncWait)
2128+ priv->syncGeometry.set (x, y, width, height, ce->border_width);
2129+ else
2130+ window->resize (x, y, width, height, ce->border_width);
2131+
2132+ if (priv->restack (ce->above))
2133+ priv->updatePassiveButtonGrabs ();
2134+
2135+ above = screen->findWindow (ce->above);
2136+
2137+ if (above)
2138+ above->priv->updatePassiveButtonGrabs ();
2139+
2140+ if (pendingConfigures.empty ())
2141+ {
2142+ /* Tell plugins its ok to start doing stupid things again but
2143+ * obviously FIXME */
2144+ CompOption::Vector options;
2145+ CompOption::Value v;
2146+
2147+ options.push_back (CompOption ("window", CompOption::TypeInt));
2148+ v.set ((int) id);
2149+ options.back ().set (v);
2150+ options.push_back (CompOption ("active", CompOption::TypeInt));
2151+ v.set ((int) 0);
2152+ options.back ().set (v);
2153+
2154+ /* Notify other plugins that it is unsafe to change geometry or serverGeometry
2155+ * FIXME: That API should not be accessible to plugins, this is a hack to avoid
2156+ * breaking ABI */
2157+
2158+ screen->handleCompizEvent ("core", "lock_position", options);
2159+ }
2160+}
2161+
2162+void
2163+PrivateWindow::circulate (XCirculateEvent *ce)
2164+{
2165+ Window newAboveId;
2166+
2167+ if (ce->place == PlaceOnTop)
2168+ newAboveId = screen->priv->getTopWindow ();
2169+ else
2170+ newAboveId = 0;
2171+
2172+ priv->restack (newAboveId);
2173+}
2174+
2175+void
2176+CompWindow::move (int dx,
2177+ int dy,
2178+ bool immediate)
2179+{
2180+ if (dx || dy)
2181+ {
2182+ /* Don't allow window movement to overwrite working geometries
2183+ * last received from the server if we know there are pending
2184+ * ConfigureNotify events on this window. That's a clunky workaround
2185+ * and a FIXME in any case, however, until we can break the API
2186+ * and remove CompWindow::move, this will need to be the case */
2187+
2188+ if (!priv->pendingConfigures.size ())
2189+ {
2190+ priv->geometry.setX (priv->geometry.x () + dx);
2191+ priv->geometry.setY (priv->geometry.y () + dy);
2192+ priv->frameGeometry.setX (priv->frameGeometry.x () + dx);
2193+ priv->frameGeometry.setY (priv->frameGeometry.y () + dy);
2194+
2195+ priv->pendingPositionUpdates = true;
2196+
2197+ priv->region.translate (dx, dy);
2198+ priv->inputRegion.translate (dx, dy);
2199+ if (!priv->frameRegion.isEmpty ())
2200+ priv->frameRegion.translate (dx, dy);
2201+
2202+ priv->invisible = WINDOW_INVISIBLE (priv);
2203+
2204+ moveNotify (dx, dy, immediate);
2205+ }
2206+ else
2207+ {
2208+ XWindowChanges xwc;
2209+ unsigned int valueMask = CWX | CWY;
2210+ struct timeval tv, old;
2211+ compLogMessage ("core", CompLogLevelDebug, "pending configure notifies on 0x%x,"\
2212+ "moving window asyncrhonously!", (unsigned int) priv->serverId);
2213+
2214+ old = priv->lastConfigureRequest;
2215+ gettimeofday (&tv, NULL);
2216+
2217+ xwc.x = priv->serverGeometry.x () + dx;
2218+ xwc.y = priv->serverGeometry.y () + dy;
2219+
2220+ configureXWindow (valueMask, &xwc);
2221+
2222+ priv->lastConfigureRequest = old;
2223+
2224+ /* FIXME: This is a hack to avoid performance regressions
2225+ * and must be removed in 0.9.6 */
2226+ if (tv.tv_usec - priv->lastConfigureRequest.tv_usec > 300000)
2227+ {
2228+ compLogMessage ("core", CompLogLevelWarn, "failed to receive ConfigureNotify event from request at %i (now: %i)\n",
2229+ priv->lastConfigureRequest.tv_usec, tv.tv_usec);
2230+ priv->pendingConfigures.clear ();
2231+ }
2232+ }
2233+ }
2234+}
2235+
2236+void
2237+PrivateWindow::addPendingConfigure (XWindowChanges &xwc, unsigned int valueMask)
2238+{
2239+ CompOption::Vector options;
2240+ CompOption::Value v;
2241+
2242+ options.push_back (CompOption ("window", CompOption::TypeInt));
2243+ v.set ((int) id);
2244+ options.back ().set (v);
2245+ options.push_back (CompOption ("active", CompOption::TypeInt));
2246+ v.set ((int) 1);
2247+ options.back ().set (v);
2248+
2249+ gettimeofday (&lastConfigureRequest, NULL);
2250+
2251+ /* Notify other plugins that it is unsafe to change geometry or serverGeometry
2252+ * FIXME: That API should not be accessible to plugins, this is a hack to avoid
2253+ * breaking ABI */
2254+
2255+ screen->handleCompizEvent ("core", "lock_position", options);
2256+
2257+ priv->pendingConfigures.push_back (XWCValueMask (xwc, valueMask));
2258+}
2259+
2260+void
2261+CompWindow::syncPosition ()
2262+{
2263+ unsigned int valueMask = CWX | CWY;
2264+ XWindowChanges xwc;
2265+
2266+ if (priv->pendingPositionUpdates && priv->pendingConfigures.empty ())
2267+ {
2268+ if (priv->serverFrameGeometry.x () == priv->frameGeometry.x ())
2269+ valueMask &= ~(CWX);
2270+ if (priv->serverFrameGeometry.y () == priv->frameGeometry.y ())
2271+ valueMask &= ~(CWY);
2272+
2273+ /* Because CompWindow::move can update the geometry last
2274+ * received from the server, we must indicate that no values
2275+ * changed, because when the ConfigureNotify comes around
2276+ * the values are going to be the same. That's obviously
2277+ * broken behaviour and worthy of a FIXME, but requires
2278+ * larger changes to the window movement system. */
2279+ if (valueMask)
2280+ {
2281+ priv->addPendingConfigure (xwc, 0);
2282+
2283+ priv->serverGeometry.setX (priv->geometry.x ());
2284+ priv->serverGeometry.setY (priv->geometry.y ());
2285+ priv->serverFrameGeometry.setX (priv->frameGeometry.x ());
2286+ priv->serverFrameGeometry.setY (priv->frameGeometry.y ());
2287+
2288+ xwc.x = priv->serverFrameGeometry.x ();
2289+ xwc.y = priv->serverFrameGeometry.y ();
2290+
2291+ XConfigureWindow (screen->dpy (), ROOTPARENT (this), valueMask, &xwc);
2292+
2293+ if (priv->serverFrame)
2294+ {
2295+ XMoveWindow (screen->dpy (), priv->wrapper,
2296+ priv->serverInput.left, priv->serverInput.top);
2297+ sendConfigureNotify ();
2298+ }
2299+ }
2300+ priv->pendingPositionUpdates = false;
2301+ }
2302+}
2303+
2304+bool
2305+CompWindow::focus ()
2306+{
2307+ WRAPABLE_HND_FUNC_RETURN (2, bool, focus)
2308+
2309+ if (overrideRedirect ())
2310+ return false;
2311+
2312+ if (!priv->managed || priv->unmanaging)
2313+ return false;
2314+
2315+ if (!onCurrentDesktop ())
2316+ return false;
2317+
2318+ if (priv->destroyed)
2319+ return false;
2320+
2321+ if (!priv->shaded && (priv->state & CompWindowStateHiddenMask))
2322+ return false;
2323+
2324+ if (priv->geometry.x () + priv->width <= 0 ||
2325+ priv->geometry.y () + priv->height <= 0 ||
2326+ priv->geometry.x () >= (int) screen->width ()||
2327+ priv->geometry.y () >= (int) screen->height ())
2328+ return false;
2329+
2330+ return true;
2331+}
2332+
2333+bool
2334+CompWindow::place (CompPoint &pos)
2335+{
2336+ WRAPABLE_HND_FUNC_RETURN (4, bool, place, pos)
2337+ return false;
2338+}
2339+
2340+void
2341+CompWindow::validateResizeRequest (unsigned int &mask,
2342+ XWindowChanges *xwc,
2343+ unsigned int source)
2344+{
2345+ WRAPABLE_HND_FUNC (5, validateResizeRequest, mask, xwc, source)
2346+
2347+ if (!(priv->type & (CompWindowTypeDockMask |
2348+ CompWindowTypeFullscreenMask |
2349+ CompWindowTypeUnknownMask)))
2350+ {
2351+ if (mask & CWY)
2352+ {
2353+ int min, max;
2354+
2355+ min = screen->workArea ().y () + priv->input.top;
2356+ max = screen->workArea ().bottom ();
2357+
2358+ if (priv->state & CompWindowStateStickyMask &&
2359+ (xwc->y < min || xwc->y > max))
2360+ {
2361+ xwc->y = priv->serverGeometry.y ();
2362+ }
2363+ else
2364+ {
2365+ min -= screen->vp ().y () * screen->height ();
2366+ max += (screen->vpSize ().height () - screen->vp ().y () - 1) *
2367+ screen->height ();
2368+
2369+ if (xwc->y < min)
2370+ xwc->y = min;
2371+ else if (xwc->y > max)
2372+ xwc->y = max;
2373+ }
2374+ }
2375+
2376+ if (mask & CWX)
2377+ {
2378+ int min, max;
2379+
2380+ min = screen->workArea ().x () + priv->input.left;
2381+ max = screen->workArea ().right ();
2382+
2383+ if (priv->state & CompWindowStateStickyMask &&
2384+ (xwc->x < min || xwc->x > max))
2385+ {
2386+ xwc->x = priv->serverGeometry.x ();
2387+ }
2388+ else
2389+ {
2390+ min -= screen->vp ().x () * screen->width ();
2391+ max += (screen->vpSize ().width () - screen->vp ().x () - 1) *
2392+ screen->width ();
2393+
2394+ if (xwc->x < min)
2395+ xwc->x = min;
2396+ else if (xwc->x > max)
2397+ xwc->x = max;
2398+ }
2399+ }
2400+ }
2401+}
2402+
2403+void
2404+CompWindow::resizeNotify (int dx,
2405+ int dy,
2406+ int dwidth,
2407+ int dheight)
2408+ WRAPABLE_HND_FUNC (6, resizeNotify, dx, dy, dwidth, dheight)
2409+
2410+void
2411+CompWindow::moveNotify (int dx,
2412+ int dy,
2413+ bool immediate)
2414+ WRAPABLE_HND_FUNC (7, moveNotify, dx, dy, immediate)
2415+
2416+void
2417+CompWindow::windowNotify (CompWindowNotify n)
2418+ WRAPABLE_HND_FUNC (8, windowNotify, n)
2419+
2420+void
2421+CompWindow::grabNotify (int x,
2422+ int y,
2423+ unsigned int state,
2424+ unsigned int mask)
2425+{
2426+ WRAPABLE_HND_FUNC (9, grabNotify, x, y, state, mask)
2427+ priv->grabbed = true;
2428+}
2429+
2430+void
2431+CompWindow::ungrabNotify ()
2432+{
2433+ WRAPABLE_HND_FUNC (10, ungrabNotify)
2434+ priv->grabbed = false;
2435+}
2436+
2437+void
2438+CompWindow::stateChangeNotify (unsigned int lastState)
2439+{
2440+ WRAPABLE_HND_FUNC (11, stateChangeNotify, lastState);
2441+
2442+ /* if being made sticky */
2443+ if (!(lastState & CompWindowStateStickyMask) &&
2444+ (priv->state & CompWindowStateStickyMask))
2445+ {
2446+ CompPoint vp; /* index of the window's vp */
2447+
2448+ /* Find which viewport the window falls in,
2449+ and check if it's the current viewport */
2450+ vp = defaultViewport ();
2451+ if (screen->vp () != vp)
2452+ {
2453+ unsigned int valueMask = CWX | CWY;
2454+ XWindowChanges xwc;
2455+
2456+ xwc.x = serverGeometry ().x () + (screen->vp ().x () - vp.x ()) * screen->width ();
2457+ xwc.y = serverGeometry ().y () + (screen->vp ().y () - vp.y ()) * screen->height ();
2458+
2459+ configureXWindow (valueMask, &xwc);
2460+ }
2461+ }
2462+}
2463+
2464+
2465+bool
2466+PrivateWindow::isGroupTransient (Window clientLeader)
2467+{
2468+ if (!clientLeader)
2469+ return false;
2470+
2471+ if (transientFor == None || transientFor == screen->root ())
2472+ {
2473+ if (type & (CompWindowTypeUtilMask |
2474+ CompWindowTypeToolbarMask |
2475+ CompWindowTypeMenuMask |
2476+ CompWindowTypeDialogMask |
2477+ CompWindowTypeModalDialogMask))
2478+ {
2479+ if (this->clientLeader == clientLeader)
2480+ return true;
2481+ }
2482+ }
2483+
2484+ return false;
2485+}
2486+
2487+CompWindow *
2488+PrivateWindow::getModalTransient ()
2489+{
2490+ CompWindow *w, *modalTransient;
2491+
2492+ modalTransient = window;
2493+
2494+ for (w = screen->windows ().back (); w; w = w->prev)
2495+ {
2496+ if (w == modalTransient || w->priv->mapNum == 0)
2497+ continue;
2498+
2499+ if (w->priv->transientFor == modalTransient->priv->id)
2500+ {
2501+ if (w->priv->state & CompWindowStateModalMask)
2502+ {
2503+ modalTransient = w;
2504+ w = screen->windows ().back ();
2505+ }
2506+ }
2507+ }
2508+
2509+ if (modalTransient == window)
2510+ {
2511+ /* don't look for group transients with modal state if current window
2512+ has modal state */
2513+ if (state & CompWindowStateModalMask)
2514+ return NULL;
2515+
2516+ for (w = screen->windows ().back (); w; w = w->prev)
2517+ {
2518+ if (w == modalTransient || w->priv->mapNum == 0)
2519+ continue;
2520+
2521+ if (isAncestorTo (modalTransient, w))
2522+ continue;
2523+
2524+ if (w->priv->isGroupTransient (modalTransient->priv->clientLeader))
2525+ {
2526+ if (w->priv->state & CompWindowStateModalMask)
2527+ {
2528+ modalTransient = w;
2529+ w = w->priv->getModalTransient ();
2530+ if (w)
2531+ modalTransient = w;
2532+
2533+ break;
2534+ }
2535+ }
2536+ }
2537+ }
2538+
2539+ if (modalTransient == window)
2540+ modalTransient = NULL;
2541+
2542+ return modalTransient;
2543+}
2544+
2545+void
2546+CompWindow::moveInputFocusTo ()
2547+{
2548+ CompScreen *s = screen;
2549+ CompWindow *modalTransient;
2550+
2551+ modalTransient = priv->getModalTransient ();
2552+ if (modalTransient)
2553+ return modalTransient->moveInputFocusTo ();
2554+
2555+ /* If the window is still hidden but not shaded
2556+ * it probably meant that a plugin overloaded
2557+ * CompWindow::focus to allow the focus to go
2558+ * to this window, so only move the input focus
2559+ * to the frame if the window is shaded */
2560+ if (shaded ())
2561+ {
2562+ XSetInputFocus (s->dpy (), priv->serverFrame,
2563+ RevertToPointerRoot, CurrentTime);
2564+ XChangeProperty (s->dpy (), s->root (), Atoms::winActive,
2565+ XA_WINDOW, 32, PropModeReplace,
2566+ (unsigned char *) &priv->id, 1);
2567+ }
2568+ else
2569+ {
2570+ bool setFocus = false;
2571+
2572+ if (priv->inputHint)
2573+ {
2574+ XSetInputFocus (s->dpy (), priv->id, RevertToPointerRoot,
2575+ CurrentTime);
2576+ setFocus = true;
2577+ }
2578+
2579+ if (priv->protocols & CompWindowProtocolTakeFocusMask)
2580+ {
2581+ XEvent ev;
2582+
2583+ ev.type = ClientMessage;
2584+ ev.xclient.window = priv->id;
2585+ ev.xclient.message_type = Atoms::wmProtocols;
2586+ ev.xclient.format = 32;
2587+ ev.xclient.data.l[0] = Atoms::wmTakeFocus;
2588+ ev.xclient.data.l[1] = s->getCurrentTime ();
2589+ ev.xclient.data.l[2] = 0;
2590+ ev.xclient.data.l[3] = 0;
2591+ ev.xclient.data.l[4] = 0;
2592+
2593+ XSendEvent (s->dpy (), priv->id, false, NoEventMask, &ev);
2594+
2595+ setFocus = true;
2596+ }
2597+
2598+ if (setFocus)
2599+ {
2600+ CompWindowList dockWindows;
2601+ XWindowChanges xwc;
2602+ unsigned int mask;
2603+
2604+ screen->priv->nextActiveWindow = priv->id;
2605+
2606+ /* Ensure that docks are stacked in the right place
2607+ *
2608+ * When a normal window gets the focus and is above a
2609+ * fullscreen window, restack the docks to be above
2610+ * the highest level mapped and visible normal window,
2611+ * otherwise put them above the highest fullscreen window
2612+ */
2613+ if (PrivateWindow::stackDocks (this, dockWindows, &xwc, &mask))
2614+ {
2615+ Window sibling = xwc.sibling;
2616+ xwc.stack_mode = Above;
2617+
2618+ /* Then update the dock windows */
2619+ foreach (CompWindow *dw, dockWindows)
2620+ {
2621+ xwc.sibling = sibling;
2622+ dw->configureXWindow (mask, &xwc);
2623+ }
2624+ }
2625+ }
2626+
2627+ if (!setFocus && !modalTransient)
2628+ {
2629+ CompWindow *ancestor;
2630+
2631+ /* move input to closest ancestor */
2632+ for (ancestor = s->windows ().front (); ancestor;
2633+ ancestor = ancestor->next)
2634+ {
2635+ if (PrivateWindow::isAncestorTo (this, ancestor))
2636+ {
2637+ ancestor->moveInputFocusTo ();
2638+ break;
2639+ }
2640+ }
2641+ }
2642+ }
2643+}
2644+
2645+void
2646+CompWindow::moveInputFocusToOtherWindow ()
2647+{
2648+ if (priv->id == screen->activeWindow () ||
2649+ priv->id == screen->priv->nextActiveWindow)
2650+ {
2651+ CompWindow *ancestor;
2652+
2653+ if (priv->transientFor && priv->transientFor != screen->root ())
2654+ {
2655+ ancestor = screen->findWindow (priv->transientFor);
2656+ if (ancestor &&
2657+ ancestor->focus () &&
2658+ !(ancestor->priv->type & (CompWindowTypeDesktopMask |
2659+ CompWindowTypeDockMask)))
2660+ {
2661+ ancestor->moveInputFocusTo ();
2662+ }
2663+ else
2664+ screen->focusDefaultWindow ();
2665+ }
2666+ else if (priv->type & (CompWindowTypeDialogMask |
2667+ CompWindowTypeModalDialogMask))
2668+ {
2669+ CompWindow *a, *focus = NULL;
2670+
2671+ for (a = screen->windows ().back (); a; a = a->prev)
2672+ {
2673+ if (a->priv->clientLeader == priv->clientLeader)
2674+ {
2675+ if (a->focus ())
2676+ {
2677+ if (focus)
2678+ {
2679+ if (a->priv->type & (CompWindowTypeNormalMask |
2680+ CompWindowTypeDialogMask |
2681+ CompWindowTypeModalDialogMask))
2682+ {
2683+ if (priv->compareWindowActiveness (focus, a) < 0)
2684+ focus = a;
2685+ }
2686+ }
2687+ else
2688+ focus = a;
2689+ }
2690+ }
2691+ }
2692+
2693+ if (focus && !(focus->priv->type & (CompWindowTypeDesktopMask |
2694+ CompWindowTypeDockMask)))
2695+ {
2696+ focus->moveInputFocusTo ();
2697+ }
2698+ else
2699+ screen->focusDefaultWindow ();
2700+ }
2701+ else
2702+ screen->focusDefaultWindow ();
2703+ }
2704+}
2705+
2706+
2707+bool
2708+PrivateWindow::stackLayerCheck (CompWindow *w,
2709+ Window clientLeader,
2710+ CompWindow *below)
2711+{
2712+ if (isAncestorTo (w, below))
2713+ return true;
2714+
2715+ if (isAncestorTo (below, w))
2716+ return false;
2717+
2718+ if (clientLeader && below->priv->clientLeader == clientLeader)
2719+ if (below->priv->isGroupTransient (clientLeader))
2720+ return false;
2721+
2722+ if (w->priv->state & CompWindowStateAboveMask)
2723+ {
2724+ return true;
2725+ }
2726+ else if (w->priv->state & CompWindowStateBelowMask)
2727+ {
2728+ if (below->priv->state & CompWindowStateBelowMask)
2729+ return true;
2730+ }
2731+ else if (!(below->priv->state & CompWindowStateAboveMask))
2732+ {
2733+ return true;
2734+ }
2735+
2736+ return false;
2737+}
2738+
2739+bool
2740+PrivateWindow::avoidStackingRelativeTo (CompWindow *w)
2741+{
2742+ if (w->overrideRedirect ())
2743+ return true;
2744+
2745+ if (w->destroyed ())
2746+ return true;
2747+
2748+ if (!w->priv->shaded && !w->priv->pendingMaps)
2749+ {
2750+ if (!w->isViewable () || !w->isMapped ())
2751+ return true;
2752+ }
2753+
2754+ return false;
2755+}
2756+
2757+/* goes through the stack, top-down until we find a window we should
2758+ stack above, normal windows can be stacked above fullscreen windows
2759+ (and fullscreen windows over others in their layer) if aboveFs is true. */
2760+CompWindow *
2761+PrivateWindow::findSiblingBelow (CompWindow *w,
2762+ bool aboveFs)
2763+{
2764+ CompWindow *below;
2765+ CompWindow *t = screen->findWindow (w->transientFor ());
2766+ Window clientLeader = w->priv->clientLeader;
2767+ unsigned int type = w->priv->type;
2768+ unsigned int belowMask;
2769+
2770+ if (aboveFs)
2771+ belowMask = CompWindowTypeDockMask;
2772+ else
2773+ belowMask = CompWindowTypeDockMask | CompWindowTypeFullscreenMask;
2774+
2775+ /* normal stacking of fullscreen windows with below state */
2776+ if ((type & CompWindowTypeFullscreenMask) &&
2777+ (w->priv->state & CompWindowStateBelowMask))
2778+ type = CompWindowTypeNormalMask;
2779+
2780+ while (t && type != CompWindowTypeDockMask)
2781+ {
2782+ /* dock stacking of transients for docks */
2783+ if (t->type () & CompWindowTypeDockMask)
2784+ type = CompWindowTypeDockMask;
2785+
2786+ t = screen->findWindow (t->transientFor ());
2787+ }
2788+
2789+ if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2790+ clientLeader = None;
2791+
2792+ for (below = screen->serverWindows ().back (); below;
2793+ below = below->serverPrev)
2794+ {
2795+ if (below == w || avoidStackingRelativeTo (below))
2796+ continue;
2797+
2798+ /* always above desktop windows */
2799+ if (below->priv->type & CompWindowTypeDesktopMask)
2800+ return below;
2801+
2802+ switch (type) {
2803+ case CompWindowTypeDesktopMask:
2804+ /* desktop window layer */
2805+ break;
2806+ case CompWindowTypeFullscreenMask:
2807+ if (aboveFs)
2808+ return below;
2809+ /* otherwise fall-through */
2810+ case CompWindowTypeDockMask:
2811+ /* fullscreen and dock layer */
2812+ if (below->priv->type & (CompWindowTypeFullscreenMask |
2813+ CompWindowTypeDockMask))
2814+ {
2815+ if (stackLayerCheck (w, clientLeader, below))
2816+ return below;
2817+ }
2818+ else
2819+ {
2820+ return below;
2821+ }
2822+ break;
2823+ default:
2824+ {
2825+ bool allowedRelativeToLayer = !(below->priv->type & belowMask);
2826+
2827+ t = screen->findWindow (below->transientFor ());
2828+
2829+ while (t && allowedRelativeToLayer)
2830+ {
2831+ /* dock stacking of transients for docks */
2832+ allowedRelativeToLayer = !(t->priv->type & belowMask);
2833+
2834+ t = screen->findWindow (t->transientFor ());
2835+ }
2836+
2837+ /* fullscreen and normal layer */
2838+ if (allowedRelativeToLayer)
2839+ {
2840+ if (stackLayerCheck (w, clientLeader, below))
2841+ return below;
2842+ }
2843+ break;
2844+ }
2845+ }
2846+ }
2847+
2848+ return NULL;
2849+}
2850+
2851+/* goes through the stack, top-down and returns the lowest window we
2852+ can stack above. */
2853+CompWindow *
2854+PrivateWindow::findLowestSiblingBelow (CompWindow *w)
2855+{
2856+ CompWindow *below, *lowest = screen->serverWindows ().back ();
2857+ CompWindow *t = screen->findWindow (w->transientFor ());
2858+ Window clientLeader = w->priv->clientLeader;
2859+ unsigned int type = w->priv->type;
2860+
2861+ /* normal stacking fullscreen windows with below state */
2862+ if ((type & CompWindowTypeFullscreenMask) &&
2863+ (w->priv->state & CompWindowStateBelowMask))
2864+ type = CompWindowTypeNormalMask;
2865+
2866+ while (t && type != CompWindowTypeDockMask)
2867+ {
2868+ /* dock stacking of transients for docks */
2869+ if (t->type () & CompWindowTypeDockMask)
2870+ type = CompWindowTypeDockMask;
2871+
2872+ t = screen->findWindow (t->transientFor ());
2873+ }
2874+
2875+
2876+ if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2877+ clientLeader = None;
2878+
2879+ for (below = screen->serverWindows ().back (); below;
2880+ below = below->serverPrev)
2881+ {
2882+ if (below == w || avoidStackingRelativeTo (below))
2883+ continue;
2884+
2885+ /* always above desktop windows */
2886+ if (below->priv->type & CompWindowTypeDesktopMask)
2887+ return below;
2888+
2889+ switch (type) {
2890+ case CompWindowTypeDesktopMask:
2891+ /* desktop window layer - desktop windows always should be
2892+ stacked at the bottom; no other window should be below them */
2893+ return NULL;
2894+ break;
2895+ case CompWindowTypeFullscreenMask:
2896+ case CompWindowTypeDockMask:
2897+ /* fullscreen and dock layer */
2898+ if (below->priv->type & (CompWindowTypeFullscreenMask |
2899+ CompWindowTypeDockMask))
2900+ {
2901+ if (!stackLayerCheck (below, clientLeader, w))
2902+ return lowest;
2903+ }
2904+ else
2905+ {
2906+ return lowest;
2907+ }
2908+ break;
2909+ default:
2910+ {
2911+ bool allowedRelativeToLayer = !(below->priv->type & CompWindowTypeDockMask);
2912+
2913+ t = screen->findWindow (below->transientFor ());
2914+
2915+ while (t && allowedRelativeToLayer)
2916+ {
2917+ /* dock stacking of transients for docks */
2918+ allowedRelativeToLayer = !(t->priv->type & CompWindowTypeDockMask);
2919+
2920+ t = screen->findWindow (t->transientFor ());
2921+ }
2922+
2923+ /* fullscreen and normal layer */
2924+ if (allowedRelativeToLayer)
2925+ {
2926+ if (!stackLayerCheck (below, clientLeader, w))
2927+ return lowest;
2928+ }
2929+ break;
2930+ }
2931+ }
2932+
2933+ lowest = below;
2934+ }
2935+
2936+ return lowest;
2937+}
2938+
2939+bool
2940+PrivateWindow::validSiblingBelow (CompWindow *w,
2941+ CompWindow *sibling)
2942+{
2943+ CompWindow *t = screen->findWindow (w->transientFor ());
2944+ Window clientLeader = w->priv->clientLeader;
2945+ unsigned int type = w->priv->type;
2946+
2947+ /* normal stacking fullscreen windows with below state */
2948+ if ((type & CompWindowTypeFullscreenMask) &&
2949+ (w->priv->state & CompWindowStateBelowMask))
2950+ type = CompWindowTypeNormalMask;
2951+
2952+ while (t && type != CompWindowTypeDockMask)
2953+ {
2954+ /* dock stacking of transients for docks */
2955+ if (t->type () & CompWindowTypeDockMask)
2956+ type = CompWindowTypeDockMask;
2957+
2958+ t = screen->findWindow (t->transientFor ());
2959+ }
2960+
2961+
2962+ if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2963+ clientLeader = None;
2964+
2965+ if (sibling == w || avoidStackingRelativeTo (sibling))
2966+ return false;
2967+
2968+ /* always above desktop windows */
2969+ if (sibling->priv->type & CompWindowTypeDesktopMask)
2970+ return true;
2971+
2972+ switch (type) {
2973+ case CompWindowTypeDesktopMask:
2974+ /* desktop window layer */
2975+ break;
2976+ case CompWindowTypeFullscreenMask:
2977+ case CompWindowTypeDockMask:
2978+ /* fullscreen and dock layer */
2979+ if (sibling->priv->type & (CompWindowTypeFullscreenMask |
2980+ CompWindowTypeDockMask))
2981+ {
2982+ if (stackLayerCheck (w, clientLeader, sibling))
2983+ return true;
2984+ }
2985+ else
2986+ {
2987+ return true;
2988+ }
2989+ break;
2990+ default:
2991+ {
2992+ bool allowedRelativeToLayer = !(sibling->priv->type & CompWindowTypeDockMask);
2993+
2994+ t = screen->findWindow (sibling->transientFor ());
2995+
2996+ while (t && allowedRelativeToLayer)
2997+ {
2998+ /* dock stacking of transients for docks */
2999+ allowedRelativeToLayer = !(t->priv->type & CompWindowTypeDockMask);
3000+
3001+ t = screen->findWindow (t->transientFor ());
3002+ }
3003+
3004+ /* fullscreen and normal layer */
3005+ if (allowedRelativeToLayer)
3006+ {
3007+ if (stackLayerCheck (w, clientLeader, sibling))
3008+ return true;
3009+ }
3010+ break;
3011+ }
3012+ }
3013+
3014+ return false;
3015+}
3016+
3017+void
3018+PrivateWindow::saveGeometry (int mask)
3019+{
3020+ int m = mask & ~saveMask;
3021+
3022+ /* only save geometry if window has been placed */
3023+ if (!placed)
3024+ return;
3025+
3026+ if (m & CWX)
3027+ saveWc.x = serverGeometry.x ();
3028+
3029+ if (m & CWY)
3030+ saveWc.y = serverGeometry.y ();
3031+
3032+ if (m & CWWidth)
3033+ saveWc.width = serverGeometry.width ();
3034+
3035+ if (m & CWHeight)
3036+ saveWc.height = serverGeometry.height ();
3037+
3038+ if (m & CWBorderWidth)
3039+ saveWc.border_width = serverGeometry.border ();
3040+
3041+ saveMask |= m;
3042+}
3043+
3044+int
3045+PrivateWindow::restoreGeometry (XWindowChanges *xwc,
3046+ int mask)
3047+{
3048+ int m = mask & saveMask;
3049+
3050+ if (m & CWX)
3051+ xwc->x = saveWc.x;
3052+
3053+ if (m & CWY)
3054+ xwc->y = saveWc.y;
3055+
3056+ if (m & CWWidth)
3057+ {
3058+ xwc->width = saveWc.width;
3059+
3060+ /* This is not perfect but it works OK for now. If the saved width is
3061+ the same as the current width then make it a little be smaller so
3062+ the user can see that it changed and it also makes sure that
3063+ windowResizeNotify is called and plugins are notified. */
3064+ if (xwc->width == (int) serverGeometry.width ())
3065+ {
3066+ xwc->width -= 10;
3067+ if (m & CWX)
3068+ xwc->x += 5;
3069+ }
3070+ }
3071+
3072+ if (m & CWHeight)
3073+ {
3074+ xwc->height = saveWc.height;
3075+
3076+ /* As above, if the saved height is the same as the current height
3077+ then make it a little be smaller. */
3078+ if (xwc->height == (int) serverGeometry.height ())
3079+ {
3080+ xwc->height -= 10;
3081+ if (m & CWY)
3082+ xwc->y += 5;
3083+ }
3084+ }
3085+
3086+ if (m & CWBorderWidth)
3087+ xwc->border_width = saveWc.border_width;
3088+
3089+ saveMask &= ~mask;
3090+
3091+ return m;
3092+}
3093+
3094+void
3095+PrivateWindow::reconfigureXWindow (unsigned int valueMask,
3096+ XWindowChanges *xwc)
3097+{
3098+ unsigned int frameValueMask = valueMask;
3099+
3100+ /* Immediately sync window position
3101+ * if plugins were updating w->geometry () directly
3102+ * in order to avoid a race condition */
3103+
3104+ window->syncPosition ();
3105+
3106+ /* Remove redundant bits */
3107+
3108+ if (serverGeometry.x () == xwc->x)
3109+ valueMask &= ~(CWX);
3110+
3111+ if (serverGeometry.y () == xwc->y)
3112+ valueMask &= ~(CWY);
3113+
3114+ if (serverGeometry.width () == xwc->width)
3115+ valueMask &= ~(CWWidth);
3116+
3117+ if (serverGeometry.height () == xwc->height)
3118+ valueMask &= ~(CWHeight);
3119+
3120+ if (serverGeometry.border () == xwc->border_width)
3121+ valueMask &= ~(CWBorderWidth);
3122+
3123+ if (window->serverPrev && ROOTPARENT (window->serverPrev) == xwc->sibling)
3124+ {
3125+ /* check if the sibling is also pending a restack,
3126+ * if not, then setting this bit is useless */
3127+
3128+ bool pendingRestack = false;
3129+
3130+ foreach (XWCValueMask &xwcvm, window->serverPrev->priv->pendingConfigures)
3131+ {
3132+ if (xwcvm.second & (CWSibling | CWStackMode))
3133+ {
3134+ pendingRestack = true;
3135+ break;
3136+ }
3137+ }
3138+
3139+ if (!pendingRestack)
3140+ valueMask &= ~(CWSibling | CWStackMode);
3141+ }
3142+
3143+ if (valueMask & CWBorderWidth)
3144+ serverGeometry.setBorder (xwc->border_width);
3145+
3146+ if (valueMask & CWX)
3147+ serverGeometry.setX (xwc->x);
3148+
3149+ if (valueMask & CWY)
3150+ serverGeometry.setY (xwc->y);
3151+
3152+ if (valueMask & CWWidth)
3153+ serverGeometry.setWidth (xwc->width);
3154+
3155+ if (valueMask & CWHeight)
3156+ serverGeometry.setHeight (xwc->height);
3157+
3158+ /* Update the server side window list on raise, lower and restack functions.
3159+ * This function should only recieve stack_mode == Above
3160+ * but warn incase something else does get through, to make the cause
3161+ * of any potential misbehaviour obvious. */
3162+ if (valueMask & (CWSibling | CWStackMode))
3163+ {
3164+ if (xwc->stack_mode == Above)
3165+ {
3166+ if (xwc->sibling)
3167+ {
3168+ screen->unhookServerWindow (window);
3169+ screen->insertServerWindow (window, xwc->sibling);
3170+ }
3171+ }
3172+ else
3173+ compLogMessage ("core", CompLogLevelWarn, "restack_mode not Above");
3174+ }
3175+
3176+ if (serverFrameGeometry.x () == xwc->x - serverGeometry.border () - serverInput.left)
3177+ frameValueMask &= ~(CWX);
3178+
3179+ if (serverFrameGeometry.y () == xwc->y - serverGeometry.border () - serverInput.top)
3180+ frameValueMask &= ~(CWY);
3181+
3182+ if (serverFrameGeometry.width () == xwc->width + serverGeometry.border () * 2
3183+ + serverInput.left + serverInput.right)
3184+ frameValueMask &= ~(CWWidth);
3185+
3186+ if (serverFrameGeometry.height () == xwc->height + serverGeometry.border () * 2
3187+ + serverInput.top + serverInput.bottom)
3188+ frameValueMask &= ~(CWHeight);
3189+
3190+ /* Can't set the border width of frame windows */
3191+ frameValueMask &= ~(CWBorderWidth);
3192+
3193+ if (frameValueMask & CWX)
3194+ serverFrameGeometry.setX (xwc->x - serverGeometry.border () - serverInput.left);
3195+
3196+ if (frameValueMask & CWY)
3197+ serverFrameGeometry.setY (xwc->y -serverGeometry.border () - serverInput.top);
3198+
3199+ if (frameValueMask & CWWidth)
3200+ serverFrameGeometry.setWidth (xwc->width + serverGeometry.border () * 2
3201+ + serverInput.left + serverInput.right);
3202+
3203+ if (frameValueMask & CWHeight)
3204+ serverFrameGeometry.setHeight (xwc->height + serverGeometry.border () * 2
3205+ + serverInput.top + serverInput.bottom);
3206+
3207+
3208+ if (serverFrame)
3209+ {
3210+ if (frameValueMask)
3211+ {
3212+ XWindowChanges wc = *xwc;
3213+
3214+ wc.x = serverFrameGeometry.x ();
3215+ wc.y = serverFrameGeometry.y ();
3216+ wc.width = serverFrameGeometry.width ();
3217+ wc.height = serverFrameGeometry.height ();
3218+
3219+ addPendingConfigure (wc, frameValueMask);
3220+
3221+ XConfigureWindow (screen->dpy (), serverFrame, frameValueMask, &wc);
3222+ }
3223+ valueMask &= ~(CWSibling | CWStackMode);
3224+
3225+ if (valueMask)
3226+ {
3227+ xwc->x = serverInput.left;
3228+ xwc->y = serverInput.top;
3229+ XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc);
3230+
3231+ xwc->x = 0;
3232+ xwc->y = 0;
3233+ }
3234+
3235+ window->sendConfigureNotify ();
3236+ }
3237+
3238+ if (valueMask)
3239+ XConfigureWindow (screen->dpy (), id, valueMask, xwc);
3240+}
3241+
3242+bool
3243+PrivateWindow::stackDocks (CompWindow *w,
3244+ CompWindowList &updateList,
3245+ XWindowChanges *xwc,
3246+ unsigned int *mask)
3247+{
3248+ CompWindow *firstFullscreenWindow = NULL;
3249+ CompWindow *belowDocks = NULL;
3250+
3251+ foreach (CompWindow *dw, screen->serverWindows ())
3252+ {
3253+ /* fullscreen window found */
3254+ if (firstFullscreenWindow)
3255+ {
3256+ /* If there is another toplevel window above the fullscreen one
3257+ * then we need to stack above that */
3258+ if (dw->focus () &&
3259+ !PrivateWindow::isAncestorTo (w, dw) &&
3260+ !(dw->type () & (CompWindowTypeFullscreenMask |
3261+ CompWindowTypeDockMask)) &&
3262+ !dw->overrideRedirect () &&
3263+ dw->defaultViewport () == screen->vp () &&
3264+ dw->isViewable ())
3265+ {
3266+ belowDocks = dw;
3267+ }
3268+ }
3269+ else if (dw->type () & CompWindowTypeFullscreenMask)
3270+ {
3271+ /* First fullscreen window found when checking up the stack
3272+ * now go back down to find a suitable candidate client
3273+ * window to put the docks above */
3274+ firstFullscreenWindow = dw;
3275+ for (CompWindow *dww = dw->serverPrev; dww; dww = dww->serverPrev)
3276+ {
3277+ if (!(dww->type () & (CompWindowTypeFullscreenMask |
3278+ CompWindowTypeDockMask)) &&
3279+ !dww->overrideRedirect () &&
3280+ dww->defaultViewport () == screen->vp () &&
3281+ dww->isViewable ())
3282+ {
3283+ belowDocks = dww;
3284+ break;
3285+ }
3286+ }
3287+ }
3288+ }
3289+
3290+ if (belowDocks)
3291+ {
3292+ *mask = CWSibling | CWStackMode;
3293+ xwc->sibling = ROOTPARENT (belowDocks);
3294+
3295+ /* Collect all dock windows first */
3296+ foreach (CompWindow *dw, screen->serverWindows ())
3297+ if (dw->priv->type & CompWindowTypeDockMask)
3298+ updateList.push_front (dw);
3299+
3300+ return true;
3301+ }
3302+
3303+ return false;
3304+}
3305+
3306+bool
3307+PrivateWindow::stackTransients (CompWindow *w,
3308+ CompWindow *avoid,
3309+ XWindowChanges *xwc,
3310+ CompWindowList &updateList)
3311+{
3312+ CompWindow *t;
3313+ Window clientLeader = w->priv->clientLeader;
3314+
3315+ if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
3316+ clientLeader = None;
3317+
3318+ for (t = screen->serverWindows ().back (); t; t = t->serverPrev)
3319+ {
3320+ if (t == w || t == avoid)
3321+ continue;
3322+
3323+ if (t->priv->transientFor == w->priv->id ||
3324+ t->priv->isGroupTransient (clientLeader))
3325+ {
3326+ if (!stackTransients (t, avoid, xwc, updateList))
3327+ return false;
3328+
3329+ if (xwc->sibling == t->priv->id ||
3330+ (t->priv->serverFrame && xwc->sibling == t->priv->serverFrame))
3331+ return false;
3332+
3333+ if (t->priv->mapNum || t->priv->pendingMaps)
3334+ updateList.push_back (t);
3335+ }
3336+ }
3337+
3338+ return true;
3339+}
3340+
3341+void
3342+PrivateWindow::stackAncestors (CompWindow *w,
3343+ XWindowChanges *xwc,
3344+ CompWindowList &updateList)
3345+{
3346+ CompWindow *transient = NULL;
3347+
3348+ if (w->priv->transientFor)
3349+ transient = screen->findWindow (w->priv->transientFor);
3350+
3351+ if (transient &&
3352+ xwc->sibling != transient->priv->id &&
3353+ (!transient->priv->serverFrame || xwc->sibling != transient->priv->serverFrame))
3354+ {
3355+ CompWindow *ancestor;
3356+
3357+ ancestor = screen->findWindow (w->priv->transientFor);
3358+ if (ancestor)
3359+ {
3360+ if (!stackTransients (ancestor, w, xwc, updateList))
3361+ return;
3362+
3363+ if (ancestor->priv->type & CompWindowTypeDesktopMask)
3364+ return;
3365+
3366+ if (ancestor->priv->type & CompWindowTypeDockMask)
3367+ if (!(w->priv->type & CompWindowTypeDockMask))
3368+ return;
3369+
3370+ if (ancestor->priv->mapNum || ancestor->priv->pendingMaps)
3371+ updateList.push_back (ancestor);
3372+
3373+ stackAncestors (ancestor, xwc, updateList);
3374+ }
3375+ }
3376+ else if (w->priv->isGroupTransient (w->priv->clientLeader))
3377+ {
3378+ CompWindow *a;
3379+
3380+ for (a = screen->serverWindows ().back (); a; a = a->serverPrev)
3381+ {
3382+ if (a->priv->clientLeader == w->priv->clientLeader &&
3383+ a->priv->transientFor == None &&
3384+ !a->priv->isGroupTransient (w->priv->clientLeader))
3385+ {
3386+ if (xwc->sibling == a->priv->id ||
3387+ (a->priv->serverFrame && xwc->sibling == a->priv->serverFrame))
3388+ break;
3389+
3390+ if (!stackTransients (a, w, xwc, updateList))
3391+ break;
3392+
3393+ if (a->priv->type & CompWindowTypeDesktopMask)
3394+ continue;
3395+
3396+ if (a->priv->type & CompWindowTypeDockMask)
3397+ if (!(w->priv->type & CompWindowTypeDockMask))
3398+ break;
3399+
3400+ if (a->priv->mapNum || a->priv->pendingMaps)
3401+ updateList.push_back (a);
3402+ }
3403+ }
3404+ }
3405+}
3406+
3407+void
3408+CompWindow::configureXWindow (unsigned int valueMask,
3409+ XWindowChanges *xwc)
3410+{
3411+ if (priv->managed && (valueMask & (CWSibling | CWStackMode)))
3412+ {
3413+ CompWindowList transients;
3414+ CompWindowList ancestors;
3415+ CompWindowList docks;
3416+
3417+ /* Since the window list is being reordered in reconfigureXWindow
3418+ the list of windows which need to be restacked must be stored
3419+ first. The windows are stacked in the opposite order than they
3420+ were previously stacked, in order that they are above xwc->sibling
3421+ so that when compiz gets the ConfigureNotify event it doesn't
3422+ have to restack all the windows again. */
3423+
3424+ /* transient children above */
3425+ if (PrivateWindow::stackTransients (this, NULL, xwc, transients))
3426+ {
3427+ /* ancestors, siblings and sibling transients below */
3428+ PrivateWindow::stackAncestors (this, xwc, ancestors);
3429+
3430+ for (CompWindowList::reverse_iterator w = ancestors.rbegin ();
3431+ w != ancestors.rend (); w++)
3432+ {
3433+ (*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
3434+ xwc->sibling = ROOTPARENT (*w);
3435+ }
3436+
3437+ this->priv->reconfigureXWindow (valueMask, xwc);
3438+ xwc->sibling = ROOTPARENT (this);
3439+
3440+ for (CompWindowList::reverse_iterator w = transients.rbegin ();
3441+ w != transients.rend (); w++)
3442+ {
3443+ (*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
3444+ xwc->sibling = ROOTPARENT (*w);
3445+ }
3446+
3447+ if (PrivateWindow::stackDocks (this, docks, xwc, &valueMask))
3448+ {
3449+ Window sibling = xwc->sibling;
3450+ xwc->stack_mode = Above;
3451+
3452+ /* Then update the dock windows */
3453+ foreach (CompWindow *dw, docks)
3454+ {
3455+ xwc->sibling = sibling;
3456+ dw->priv->reconfigureXWindow (valueMask, xwc);
3457+ }
3458+ }
3459+ }
3460+ }
3461+ else if (priv->id)
3462+ {
3463+ priv->reconfigureXWindow (valueMask, xwc);
3464+ }
3465+}
3466+
3467+int
3468+PrivateWindow::addWindowSizeChanges (XWindowChanges *xwc,
3469+ CompWindow::Geometry old)
3470+{
3471+ CompRect workArea;
3472+ int mask = 0;
3473+ int x, y;
3474+ int output;
3475+ CompPoint viewport;
3476+
3477+ screen->viewportForGeometry (old, viewport);
3478+
3479+ x = (viewport.x () - screen->vp ().x ()) * screen->width ();
3480+ y = (viewport.y () - screen->vp ().y ()) * screen->height ();
3481+
3482+ output = screen->outputDeviceForGeometry (old);
3483+ workArea = screen->getWorkareaForOutput (output);
3484+
3485+ if (type & CompWindowTypeFullscreenMask)
3486+ {
3487+ saveGeometry (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3488+
3489+ if (fullscreenMonitorsSet)
3490+ {
3491+ xwc->x = x + fullscreenMonitorRect.x ();
3492+ xwc->y = y + fullscreenMonitorRect.y ();
3493+ xwc->width = fullscreenMonitorRect.width ();
3494+ xwc->height = fullscreenMonitorRect.height ();
3495+ }
3496+ else
3497+ {
3498+ xwc->x = x + screen->outputDevs ()[output].x ();
3499+ xwc->y = y + screen->outputDevs ()[output].y ();
3500+ xwc->width = screen->outputDevs ()[output].width ();
3501+ xwc->height = screen->outputDevs ()[output].height ();
3502+ }
3503+
3504+ xwc->border_width = 0;
3505+
3506+ mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
3507+ }
3508+ else
3509+ {
3510+ mask |= restoreGeometry (xwc, CWBorderWidth);
3511+
3512+ if (state & CompWindowStateMaximizedVertMask)
3513+ {
3514+ saveGeometry (CWY | CWHeight);
3515+
3516+ xwc->height = workArea.height () - serverInput.top -
3517+ serverInput.bottom - old.border () * 2;
3518+
3519+ mask |= CWHeight;
3520+ }
3521+ else
3522+ {
3523+ mask |= restoreGeometry (xwc, CWY | CWHeight);
3524+ }
3525+
3526+ if (state & CompWindowStateMaximizedHorzMask)
3527+ {
3528+ saveGeometry (CWX | CWWidth);
3529+
3530+ xwc->width = workArea.width () - serverInput.left -
3531+ serverInput.right - old.border () * 2;
3532+
3533+ mask |= CWWidth;
3534+ }
3535+ else
3536+ {
3537+ mask |= restoreGeometry (xwc, CWX | CWWidth);
3538+ }
3539+
3540+ /* constrain window width if smaller than minimum width */
3541+ if (!(mask & CWWidth) && (int) old.width () < sizeHints.min_width)
3542+ {
3543+ xwc->width = sizeHints.min_width;
3544+ mask |= CWWidth;
3545+ }
3546+
3547+ /* constrain window width if greater than maximum width */
3548+ if (!(mask & CWWidth) && (int) old.width () > sizeHints.max_width)
3549+ {
3550+ xwc->width = sizeHints.max_width;
3551+ mask |= CWWidth;
3552+ }
3553+
3554+ /* constrain window height if smaller than minimum height */
3555+ if (!(mask & CWHeight) && (int) old.height () < sizeHints.min_height)
3556+ {
3557+ xwc->height = sizeHints.min_height;
3558+ mask |= CWHeight;
3559+ }
3560+
3561+ /* constrain window height if greater than maximum height */
3562+ if (!(mask & CWHeight) && (int) old.height () > sizeHints.max_height)
3563+ {
3564+ xwc->height = sizeHints.max_height;
3565+ mask |= CWHeight;
3566+ }
3567+
3568+ if (mask & (CWWidth | CWHeight))
3569+ {
3570+ int width, height, max;
3571+
3572+ width = (mask & CWWidth) ? xwc->width : old.width ();
3573+ height = (mask & CWHeight) ? xwc->height : old.height ();
3574+
3575+ xwc->width = old.width ();
3576+ xwc->height = old.height ();
3577+
3578+ window->constrainNewWindowSize (width, height, &width, &height);
3579+
3580+ if (width != (int) old.width ())
3581+ {
3582+ mask |= CWWidth;
3583+ xwc->width = width;
3584+ }
3585+ else
3586+ mask &= ~CWWidth;
3587+
3588+ if (height != (int) old.height ())
3589+ {
3590+ mask |= CWHeight;
3591+ xwc->height = height;
3592+ }
3593+ else
3594+ mask &= ~CWHeight;
3595+
3596+ if (state & CompWindowStateMaximizedVertMask)
3597+ {
3598+ if (old.y () < y + workArea.y () + serverInput.top)
3599+ {
3600+ xwc->y = y + workArea.y () + serverInput.top;
3601+ mask |= CWY;
3602+ }
3603+ else
3604+ {
3605+ height = xwc->height + old.border () * 2;
3606+
3607+ max = y + workArea.bottom ();
3608+ if (old.y () + (int) old.height () + serverInput.bottom > max)
3609+ {
3610+ xwc->y = max - height - serverInput.bottom;
3611+ mask |= CWY;
3612+ }
3613+ else if (old.y () + height + serverInput.bottom > max)
3614+ {
3615+ xwc->y = y + workArea.y () +
3616+ (workArea.height () - serverInput.top - height -
3617+ serverInput.bottom) / 2 + serverInput.top;
3618+ mask |= CWY;
3619+ }
3620+ }
3621+ }
3622+
3623+ if (state & CompWindowStateMaximizedHorzMask)
3624+ {
3625+ if (old.x () < x + workArea.x () + serverInput.left)
3626+ {
3627+ xwc->x = x + workArea.x () + serverInput.left;
3628+ mask |= CWX;
3629+ }
3630+ else
3631+ {
3632+ width = xwc->width + old.border () * 2;
3633+
3634+ max = x + workArea.right ();
3635+ if (old.x () + (int) old.width () + serverInput.right > max)
3636+ {
3637+ xwc->x = max - width - serverInput.right;
3638+ mask |= CWX;
3639+ }
3640+ else if (old.x () + width + serverInput.right > max)
3641+ {
3642+ xwc->x = x + workArea.x () +
3643+ (workArea.width () - serverInput.left - width -
3644+ serverInput.right) / 2 + serverInput.left;
3645+ mask |= CWX;
3646+ }
3647+ }
3648+ }
3649+ }
3650+ }
3651+
3652+ if ((mask & CWX) && (xwc->x == old.x ()))
3653+ mask &= ~CWX;
3654+
3655+ if ((mask & CWY) && (xwc->y == old.y ()))
3656+ mask &= ~CWY;
3657+
3658+ if ((mask & CWWidth) && (xwc->width == (int) old.width ()))
3659+ mask &= ~CWWidth;
3660+
3661+ if ((mask & CWHeight) && (xwc->height == (int) old.height ()))
3662+ mask &= ~CWHeight;
3663+
3664+ return mask;
3665+}
3666+
3667+unsigned int
3668+PrivateWindow::adjustConfigureRequestForGravity (XWindowChanges *xwc,
3669+ unsigned int xwcm,
3670+ int gravity,
3671+ int direction)
3672+{
3673+ int newX, newY;
3674+ unsigned int mask = 0;
3675+
3676+ newX = xwc->x;
3677+ newY = xwc->y;
3678+
3679+ if (xwcm & (CWX | CWWidth))
3680+ {
3681+ switch (gravity) {
3682+ case NorthWestGravity:
3683+ case WestGravity:
3684+ case SouthWestGravity:
3685+ if (xwcm & CWX)
3686+ newX += priv->border.left * direction;
3687+ break;
3688+
3689+ case NorthGravity:
3690+ case CenterGravity:
3691+ case SouthGravity:
3692+ if (xwcm & CWX)
3693+ newX -= (xwc->width / 2 - priv->border.left +
3694+ (priv->border.left + priv->border.right) / 2) * direction;
3695+ else
3696+ newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
3697+ break;
3698+
3699+ case NorthEastGravity:
3700+ case EastGravity:
3701+ case SouthEastGravity:
3702+ if (xwcm & CWX)
3703+ newX -= xwc->width + priv->border.right * direction;
3704+ else
3705+ newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
3706+ break;
3707+
3708+ case StaticGravity:
3709+ default:
3710+ break;
3711+ }
3712+ }
3713+
3714+ if (xwcm & (CWY | CWHeight))
3715+ {
3716+ switch (gravity) {
3717+ case NorthWestGravity:
3718+ case NorthGravity:
3719+ case NorthEastGravity:
3720+ if (xwcm & CWY)
3721+ newY = xwc->y + priv->serverInput.top * direction;
3722+ break;
3723+
3724+ case WestGravity:
3725+ case CenterGravity:
3726+ case EastGravity:
3727+ if (xwcm & CWY)
3728+ newY -= (xwc->height / 2 - priv->serverInput.top +
3729+ (priv->serverInput.top + priv->serverInput.bottom) / 2) * direction;
3730+ else
3731+ newY -= ((xwc->height - priv->serverGeometry.height ()) / 2) * direction;
3732+ break;
3733+
3734+ case SouthWestGravity:
3735+ case SouthGravity:
3736+ case SouthEastGravity:
3737+ if (xwcm & CWY)
3738+ newY -= xwc->height + priv->serverInput.bottom * direction;
3739+ else
3740+ newY -= (xwc->height - priv->serverGeometry.height ()) * direction;
3741+ break;
3742+
3743+ case StaticGravity:
3744+ default:
3745+ break;
3746+ }
3747+ }
3748+
3749+ if (newX != xwc->x)
3750+ {
3751+ xwc->x += (newX - xwc->x);
3752+ mask |= CWX;
3753+ }
3754+
3755+ if (newY != xwc->y)
3756+ {
3757+ xwc->y += (newY - xwc->y);
3758+ mask |= CWY;
3759+ }
3760+
3761+ return mask;
3762+}
3763+
3764+void
3765+CompWindow::moveResize (XWindowChanges *xwc,
3766+ unsigned int xwcm,
3767+ int gravity,
3768+ unsigned int source)
3769+{
3770+ bool placed = false;
3771+
3772+ xwcm &= (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3773+
3774+ if (xwcm & (CWX | CWY))
3775+ if (priv->sizeHints.flags & (USPosition | PPosition))
3776+ placed = true;
3777+
3778+ if (gravity == 0)
3779+ gravity = priv->sizeHints.win_gravity;
3780+
3781+ if (!(xwcm & CWX))
3782+ xwc->x = priv->serverGeometry.x ();
3783+ if (!(xwcm & CWY))
3784+ xwc->y = priv->serverGeometry.y ();
3785+ if (!(xwcm & CWWidth))
3786+ xwc->width = priv->serverGeometry.width ();
3787+ if (!(xwcm & CWHeight))
3788+ xwc->height = priv->serverGeometry.height ();
3789+
3790+ if (xwcm & (CWWidth | CWHeight))
3791+ {
3792+ int width, height;
3793+
3794+ if (constrainNewWindowSize (xwc->width, xwc->height, &width, &height))
3795+ {
3796+ if (width != xwc->width)
3797+ xwcm |= CWWidth;
3798+
3799+ if (height != xwc->height)
3800+ xwcm |= CWHeight;
3801+
3802+ xwc->width = width;
3803+ xwc->height = height;
3804+ }
3805+ }
3806+
3807+ xwcm |= priv->adjustConfigureRequestForGravity (xwc, xwcm, gravity, 1);
3808+
3809+ validateResizeRequest (xwcm, xwc, source);
3810+
3811+ /* when horizontally maximized only allow width changes added by
3812+ addWindowSizeChanges */
3813+ if (priv->state & CompWindowStateMaximizedHorzMask)
3814+ xwcm &= ~CWWidth;
3815+
3816+ /* when vertically maximized only allow height changes added by
3817+ addWindowSizeChanges */
3818+ if (priv->state & CompWindowStateMaximizedVertMask)
3819+ xwcm &= ~CWHeight;
3820+
3821+ xwcm |= priv->addWindowSizeChanges (xwc, Geometry (xwc->x, xwc->y,
3822+ xwc->width, xwc->height,
3823+ xwc->border_width));
3824+
3825+ /* check if the new coordinates are useful and valid (different
3826+ to current size); if not, we have to clear them to make sure
3827+ we send a synthetic ConfigureNotify event if all coordinates
3828+ match the server coordinates */
3829+ if (xwc->x == priv->serverGeometry.x ())
3830+ xwcm &= ~CWX;
3831+
3832+ if (xwc->y == priv->serverGeometry.y ())
3833+ xwcm &= ~CWY;
3834+
3835+ if (xwc->width == (int) priv->serverGeometry.width ())
3836+ xwcm &= ~CWWidth;
3837+
3838+ if (xwc->height == (int) priv->serverGeometry.height ())
3839+ xwcm &= ~CWHeight;
3840+
3841+ if (xwc->border_width == (int) priv->serverGeometry.border ())
3842+ xwcm &= ~CWBorderWidth;
3843+
3844+ /* update saved window coordinates - if CWX or CWY is set for fullscreen
3845+ or maximized windows after addWindowSizeChanges, it should be pretty
3846+ safe to assume that the saved coordinates should be updated too, e.g.
3847+ because the window was moved to another viewport by some client */
3848+ if ((xwcm & CWX) && (priv->saveMask & CWX))
3849+ priv->saveWc.x += (xwc->x - priv->serverGeometry.x ());
3850+
3851+ if ((xwcm & CWY) && (priv->saveMask & CWY))
3852+ priv->saveWc.y += (xwc->y - priv->serverGeometry.y ());
3853+
3854+ if (priv->mapNum && (xwcm & (CWWidth | CWHeight)))
3855+ sendSyncRequest ();
3856+
3857+ if (xwcm)
3858+ configureXWindow (xwcm, xwc);
3859+ else
3860+ {
3861+ /* we have to send a configure notify on ConfigureRequest events if
3862+ we decide not to do anything according to ICCCM 4.1.5 */
3863+ sendConfigureNotify ();
3864+ }
3865+
3866+ if (placed)
3867+ priv->placed = true;
3868+}
3869+
3870+void
3871+PrivateWindow::updateSize ()
3872+{
3873+ XWindowChanges xwc;
3874+ int mask;
3875+
3876+ if (window->overrideRedirect () || !managed)
3877+ return;
3878+
3879+ mask = priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
3880+ if (mask)
3881+ {
3882+ if (priv->mapNum && (mask & (CWWidth | CWHeight)))
3883+ window->sendSyncRequest ();
3884+
3885+ window->configureXWindow (mask, &xwc);
3886+ }
3887+}
3888+
3889+int
3890+PrivateWindow::addWindowStackChanges (XWindowChanges *xwc,
3891+ CompWindow *sibling)
3892+{
3893+ int mask = 0;
3894+
3895+ if (!sibling || sibling->priv->id != id)
3896+ {
3897+ /* Alow requests to go on top of serverPrev
3898+ * if serverPrev was recently restacked */
3899+ if (window->serverPrev)
3900+ {
3901+ if (!sibling && id)
3902+ {
3903+ XWindowChanges lxwc;
3904+ unsigned int valueMask = CWStackMode;
3905+
3906+ lxwc.stack_mode = Below;
3907+
3908+ /* Below with no sibling puts the window at the bottom
3909+ * of the stack */
3910+ XConfigureWindow (screen->dpy (), ROOTPARENT (window), valueMask, &lxwc);
3911+
3912+ if (serverFrame)
3913+ priv->addPendingConfigure (lxwc, CWStackMode);
3914+
3915+ /* Update the list of windows last sent to the server */
3916+ screen->unhookServerWindow (window);
3917+ screen->insertServerWindow (window, 0);
3918+ }
3919+ else if (sibling)
3920+ {
3921+ bool pendingRestacks = false;
3922+
3923+ foreach (XWCValueMask &xwcvm, sibling->priv->pendingConfigures)
3924+ {
3925+ if (xwcvm.second & (CWSibling | CWStackMode))
3926+ {
3927+ pendingRestacks = true;
3928+ break;
3929+ }
3930+ }
3931+
3932+ if (sibling->priv->id != window->serverPrev->priv->id || pendingRestacks)
3933+ {
3934+ mask |= CWSibling | CWStackMode;
3935+
3936+ xwc->stack_mode = Above;
3937+ xwc->sibling = ROOTPARENT (sibling);
3938+ }
3939+ }
3940+ }
3941+ else if (sibling)
3942+ {
3943+ mask |= CWSibling | CWStackMode;
3944+
3945+ xwc->stack_mode = Above;
3946+ xwc->sibling = ROOTPARENT (sibling);
3947+ }
3948+ }
3949+
3950+ return mask;
3951+}
3952+
3953+void
3954+CompWindow::raise ()
3955+{
3956+ XWindowChanges xwc;
3957+ int mask;
3958+ bool aboveFs = false;
3959+
3960+ /* an active fullscreen window should be raised over all other
3961+ windows in its layer */
3962+ if (priv->type & CompWindowTypeFullscreenMask)
3963+ if (priv->id == screen->activeWindow ())
3964+ aboveFs = true;
3965+
3966+ mask = priv->addWindowStackChanges (&xwc,
3967+ PrivateWindow::findSiblingBelow (this, aboveFs));
3968+
3969+ if (mask)
3970+ configureXWindow (mask, &xwc);
3971+}
3972+
3973+CompWindow *
3974+PrivateScreen::focusTopMostWindow ()
3975+{
3976+ CompWindow *focus = NULL;
3977+ CompWindowList::reverse_iterator it = serverWindows.rbegin ();
3978+
3979+ for (; it != serverWindows.rend (); it++)
3980+ {
3981+ CompWindow *w = *it;
3982+
3983+ if (w->type () & CompWindowTypeDockMask)
3984+ continue;
3985+
3986+ if (w->focus ())
3987+ {
3988+ focus = w;
3989+ break;
3990+ }
3991+ }
3992+
3993+ if (focus)
3994+ {
3995+ if (focus->id () != activeWindow)
3996+ focus->moveInputFocusTo ();
3997+ }
3998+ else
3999+ XSetInputFocus (dpy, root, RevertToPointerRoot,
4000+ CurrentTime);
4001+ return focus;
4002+}
4003+
4004+
4005+void
4006+CompWindow::lower ()
4007+{
4008+ XWindowChanges xwc;
4009+ int mask;
4010+
4011+ mask = priv->addWindowStackChanges (&xwc,
4012+ PrivateWindow::findLowestSiblingBelow (this));
4013+ if (mask)
4014+ configureXWindow (mask, &xwc);
4015+
4016+ /* when lowering a window, focus the topmost window if
4017+ the click-to-focus option is on */
4018+ if ((screen->priv->optionGetClickToFocus ()))
4019+ {
4020+ CompWindow *focusedWindow = screen->priv->focusTopMostWindow ();
4021+
4022+ /* if the newly focused window is a desktop window,
4023+ give the focus back to w */
4024+ if (focusedWindow &&
4025+ focusedWindow->type () & CompWindowTypeDesktopMask)
4026+ {
4027+ moveInputFocusTo ();
4028+ }
4029+ }
4030+}
4031+
4032+void
4033+CompWindow::restackAbove (CompWindow *sibling)
4034+{
4035+ for (; sibling; sibling = sibling->serverNext)
4036+ if (PrivateWindow::validSiblingBelow (this, sibling))
4037+ break;
4038+
4039+ if (sibling)
4040+ {
4041+ XWindowChanges xwc;
4042+ int mask;
4043+
4044+ mask = priv->addWindowStackChanges (&xwc, sibling);
4045+ if (mask)
4046+ configureXWindow (mask, &xwc);
4047+ }
4048+}
4049+
4050+/* finds the highest window under sibling we can stack above */
4051+CompWindow *
4052+PrivateWindow::findValidStackSiblingBelow (CompWindow *w,
4053+ CompWindow *sibling)
4054+{
4055+ CompWindow *lowest, *last, *p;
4056+
4057+ /* check whether we're allowed to stack under a sibling by finding
4058+ * the above 'sibling' and checking whether or not we're allowed
4059+ * to stack under that - if not, then there is no valid sibling
4060+ * underneath it */
4061+
4062+ for (p = sibling; p; p = p->serverNext)
4063+ {
4064+ if (!avoidStackingRelativeTo (p))
4065+ {
4066+ if (!validSiblingBelow (p, w))
4067+ return NULL;
4068+ break;
4069+ }
4070+ }
4071+
4072+ /* get lowest sibling we're allowed to stack above */
4073+ lowest = last = findLowestSiblingBelow (w);
4074+
4075+ /* walk from bottom up */
4076+ for (p = screen->serverWindows ().front (); p; p = p->serverNext)
4077+ {
4078+ /* stop walking when we reach the sibling we should try to stack
4079+ below */
4080+ if (p == sibling)
4081+ return lowest;
4082+
4083+ /* skip windows that we should avoid */
4084+ if (w == p || avoidStackingRelativeTo (p))
4085+ continue;
4086+
4087+ if (validSiblingBelow (w, p))
4088+ {
4089+ /* update lowest as we find windows below sibling that we're
4090+ allowed to stack above. last window must be equal to the
4091+ lowest as we shouldn't update lowest if we passed an
4092+ invalid window */
4093+ if (last == lowest)
4094+ lowest = p;
4095+ }
4096+
4097+ /* update last pointer */
4098+ last = p;
4099+ }
4100+
4101+ return lowest;
4102+}
4103+
4104+void
4105+CompWindow::restackBelow (CompWindow *sibling)
4106+{
4107+ XWindowChanges xwc;
4108+ unsigned int mask;
4109+
4110+ mask = priv->addWindowStackChanges (&xwc,
4111+ PrivateWindow::findValidStackSiblingBelow (this, sibling));
4112+
4113+ if (mask)
4114+ configureXWindow (mask, &xwc);
4115+}
4116+
4117+void
4118+CompWindow::updateAttributes (CompStackingUpdateMode stackingMode)
4119+{
4120+ XWindowChanges xwc;
4121+ int mask = 0;
4122+
4123+ if (overrideRedirect () || !priv->managed)
4124+ return;
4125+
4126+ if (priv->state & CompWindowStateShadedMask)
4127+ {
4128+ windowNotify (CompWindowNotifyShade);
4129+
4130+ priv->hide ();
4131+ }
4132+ else if (priv->shaded)
4133+ {
4134+ windowNotify (CompWindowNotifyUnshade);
4135+
4136+ priv->show ();
4137+ }
4138+
4139+ if (stackingMode != CompStackingUpdateModeNone)
4140+ {
4141+ bool aboveFs;
4142+ CompWindow *sibling;
4143+
4144+ aboveFs = (stackingMode == CompStackingUpdateModeAboveFullscreen);
4145+ if (priv->type & CompWindowTypeFullscreenMask)
4146+ {
4147+ /* put active or soon-to-be-active fullscreen windows over
4148+ all others in their layer */
4149+ if (priv->id == screen->activeWindow () ||
4150+ priv->id == screen->priv->nextActiveWindow)
4151+ {
4152+ aboveFs = true;
4153+ }
4154+ }
4155+
4156+ /* put windows that are just mapped, over fullscreen windows */
4157+ if (stackingMode == CompStackingUpdateModeInitialMap)
4158+ aboveFs = true;
4159+
4160+ sibling = PrivateWindow::findSiblingBelow (this, aboveFs);
4161+
4162+ if (sibling &&
4163+ (stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
4164+ {
4165+ CompWindow *p;
4166+
4167+ for (p = sibling; p; p = p->serverPrev)
4168+ if (p->priv->id == screen->activeWindow ())
4169+ break;
4170+
4171+ /* window is above active window so we should lower it,
4172+ * assuing that is allowed (if, for example, our window has
4173+ * the "above" state, then lowering beneath the active
4174+ * window may not be allowed). */
4175+ if (p && PrivateWindow::validSiblingBelow (p, this))
4176+ {
4177+ p = PrivateWindow::findValidStackSiblingBelow (sibling, p);
4178+
4179+ /* if we found a valid sibling under the active window, it's
4180+ our new sibling we want to stack above */
4181+ if (p)
4182+ sibling = p;
4183+ }
4184+ }
4185+
4186+ if (sibling)
4187+ mask |= priv->addWindowStackChanges (&xwc, sibling);
4188+ }
4189+
4190+ mask |= priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
4191+
4192+ if (priv->mapNum && (mask & (CWWidth | CWHeight)))
4193+ sendSyncRequest ();
4194+
4195+ if (mask)
4196+ configureXWindow (mask, &xwc);
4197+}
4198+
4199+void
4200+PrivateWindow::ensureWindowVisibility ()
4201+{
4202+ int x1, y1, x2, y2;
4203+ int width = serverGeometry.width () + serverGeometry.border () * 2;
4204+ int height = serverGeometry.height () + serverGeometry.border () * 2;
4205+ int dx = 0;
4206+ int dy = 0;
4207+
4208+ if (struts || attrib.override_redirect)
4209+ return;
4210+
4211+ if (type & (CompWindowTypeDockMask |
4212+ CompWindowTypeFullscreenMask |
4213+ CompWindowTypeUnknownMask))
4214+ return;
4215+
4216+ x1 = screen->workArea ().x () - screen->width () * screen->vp ().x ();
4217+ y1 = screen->workArea ().y () - screen->height () * screen->vp ().y ();
4218+ x2 = x1 + screen->workArea ().width () + screen->vpSize ().width () *
4219+ screen->width ();
4220+ y2 = y1 + screen->workArea ().height () + screen->vpSize ().height () *
4221+ screen->height ();
4222+
4223+ if (serverGeometry.x () - serverInput.left >= x2)
4224+ dx = (x2 - 25) - serverGeometry.x ();
4225+ else if (serverGeometry.x () + width + serverInput.right <= x1)
4226+ dx = (x1 + 25) - (serverGeometry.x () + width);
4227+
4228+ if (serverGeometry.y () - serverInput.top >= y2)
4229+ dy = (y2 - 25) - serverGeometry.y ();
4230+ else if (serverGeometry.y () + height + serverInput.bottom <= y1)
4231+ dy = (y1 + 25) - (serverGeometry.y () + height);
4232+
4233+ if (dx || dy)
4234+ {
4235+ XWindowChanges xwc;
4236+
4237+ xwc.x = serverGeometry.x () + dx;
4238+ xwc.y = serverGeometry.y () + dy;
4239+
4240+ window->configureXWindow (CWX | CWY, &xwc);
4241+ }
4242+}
4243+
4244+void
4245+PrivateWindow::reveal ()
4246+{
4247+ if (window->minimized ())
4248+ window->unminimize ();
4249+
4250+ screen->leaveShowDesktopMode (window);
4251+}
4252+
4253+void
4254+PrivateWindow::revealAncestors (CompWindow *w,
4255+ CompWindow *transient)
4256+{
4257+ if (isAncestorTo (transient, w))
4258+ {
4259+ screen->forEachWindow (boost::bind (revealAncestors, _1, w));
4260+ w->priv->reveal ();
4261+ }
4262+}
4263+
4264+void
4265+CompWindow::activate ()
4266+{
4267+ WRAPABLE_HND_FUNC (3, activate)
4268+
4269+ screen->priv->setCurrentDesktop (priv->desktop);
4270+
4271+ screen->forEachWindow (
4272+ boost::bind (PrivateWindow::revealAncestors, _1, this));
4273+ priv->reveal ();
4274+
4275+ if (priv->state & CompWindowStateHiddenMask)
4276+ {
4277+ priv->state &= ~CompWindowStateShadedMask;
4278+ if (priv->shaded)
4279+ priv->show ();
4280+ }
4281+
4282+ if (priv->state & CompWindowStateHiddenMask)
4283+ return;
4284+
4285+ if (!onCurrentDesktop ())
4286+ return;
4287+
4288+ priv->ensureWindowVisibility ();
4289+ updateAttributes (CompStackingUpdateModeAboveFullscreen);
4290+ moveInputFocusTo ();
4291+}
4292+
4293+
4294+#define PVertResizeInc (1 << 0)
4295+#define PHorzResizeInc (1 << 1)
4296+
4297+bool
4298+CompWindow::constrainNewWindowSize (int width,
4299+ int height,
4300+ int *newWidth,
4301+ int *newHeight)
4302+{
4303+ const XSizeHints *hints = &priv->sizeHints;
4304+ int oldWidth = width;
4305+ int oldHeight = height;
4306+ int min_width = 0;
4307+ int min_height = 0;
4308+ int base_width = 0;
4309+ int base_height = 0;
4310+ int xinc = 1;
4311+ int yinc = 1;
4312+ int max_width = MAXSHORT;
4313+ int max_height = MAXSHORT;
4314+ long flags = hints->flags;
4315+ long resizeIncFlags = (flags & PResizeInc) ? ~0 : 0;
4316+
4317+ if (screen->priv->optionGetIgnoreHintsWhenMaximized ())
4318+ {
4319+ if (priv->state & MAXIMIZE_STATE)
4320+ {
4321+ flags &= ~PAspect;
4322+
4323+ if (priv->state & CompWindowStateMaximizedHorzMask)
4324+ resizeIncFlags &= ~PHorzResizeInc;
4325+
4326+ if (priv->state & CompWindowStateMaximizedVertMask)
4327+ resizeIncFlags &= ~PVertResizeInc;
4328+ }
4329+ }
4330+
4331+ /* Ater gdk_window_constrain_size(), which is partially borrowed from fvwm.
4332+ *
4333+ * Copyright 1993, Robert Nation
4334+ * You may use this code for any purpose, as long as the original
4335+ * copyright remains in the source code and all documentation
4336+ *
4337+ * which in turn borrows parts of the algorithm from uwm
4338+ */
4339+
4340+#define FLOOR(value, base) (((int) ((value) / (base))) * (base))
4341+#define FLOOR64(value, base) (((uint64_t) ((value) / (base))) * (base))
4342+
4343+ if ((flags & PBaseSize) && (flags & PMinSize))
4344+ {
4345+ base_width = hints->base_width;
4346+ base_height = hints->base_height;
4347+ min_width = hints->min_width;
4348+ min_height = hints->min_height;
4349+ }
4350+ else if (flags & PBaseSize)
4351+ {
4352+ base_width = hints->base_width;
4353+ base_height = hints->base_height;
4354+ min_width = hints->base_width;
4355+ min_height = hints->base_height;
4356+ }
4357+ else if (flags & PMinSize)
4358+ {
4359+ base_width = hints->min_width;
4360+ base_height = hints->min_height;
4361+ min_width = hints->min_width;
4362+ min_height = hints->min_height;
4363+ }
4364+
4365+ if (flags & PMaxSize)
4366+ {
4367+ max_width = hints->max_width;
4368+ max_height = hints->max_height;
4369+ }
4370+
4371+ if (resizeIncFlags & PHorzResizeInc)
4372+ xinc = MAX (xinc, hints->width_inc);
4373+
4374+ if (resizeIncFlags & PVertResizeInc)
4375+ yinc = MAX (yinc, hints->height_inc);
4376+
4377+ /* clamp width and height to min and max values */
4378+ width = CLAMP (width, min_width, max_width);
4379+ height = CLAMP (height, min_height, max_height);
4380+
4381+ /* shrink to base + N * inc */
4382+ width = base_width + FLOOR (width - base_width, xinc);
4383+ height = base_height + FLOOR (height - base_height, yinc);
4384+
4385+ /* constrain aspect ratio, according to:
4386+ *
4387+ * min_aspect.x width max_aspect.x
4388+ * ------------ <= -------- <= -----------
4389+ * min_aspect.y height max_aspect.y
4390+ */
4391+ if ((flags & PAspect) && hints->min_aspect.y > 0 && hints->max_aspect.x > 0)
4392+ {
4393+ /* Use 64 bit arithmetic to prevent overflow */
4394+
4395+ uint64_t min_aspect_x = hints->min_aspect.x;
4396+ uint64_t min_aspect_y = hints->min_aspect.y;
4397+ uint64_t max_aspect_x = hints->max_aspect.x;
4398+ uint64_t max_aspect_y = hints->max_aspect.y;
4399+ uint64_t delta;
4400+
4401+ if (min_aspect_x * height > width * min_aspect_y)
4402+ {
4403+ delta = FLOOR64 (height - width * min_aspect_y / min_aspect_x,
4404+ yinc);
4405+ if (height - (int) delta >= min_height)
4406+ height -= delta;
4407+ else
4408+ {
4409+ delta = FLOOR64 (height * min_aspect_x / min_aspect_y - width,
4410+ xinc);
4411+ if (width + (int) delta <= max_width)
4412+ width += delta;
4413+ }
4414+ }
4415+
4416+ if (width * max_aspect_y > max_aspect_x * height)
4417+ {
4418+ delta = FLOOR64 (width - height * max_aspect_x / max_aspect_y,
4419+ xinc);
4420+ if (width - (int) delta >= min_width)
4421+ width -= delta;
4422+ else
4423+ {
4424+ delta = FLOOR64 (width * min_aspect_y / min_aspect_x - height,
4425+ yinc);
4426+ if (height + (int) delta <= max_height)
4427+ height += delta;
4428+ }
4429+ }
4430+ }
4431+
4432+#undef CLAMP
4433+#undef FLOOR64
4434+#undef FLOOR
4435+
4436+ if (width != oldWidth || height != oldHeight)
4437+ {
4438+ *newWidth = width;
4439+ *newHeight = height;
4440+
4441+ return true;
4442+ }
4443+
4444+ return false;
4445+}
4446+
4447+void
4448+CompWindow::hide ()
4449+{
4450+ priv->hidden = true;
4451+ priv->hide ();
4452+}
4453+
4454+void
4455+CompWindow::show ()
4456+{
4457+ priv->hidden = false;
4458+ priv->show ();
4459+}
4460+
4461+void
4462+PrivateWindow::hide ()
4463+{
4464+ bool onDesktop = window->onCurrentDesktop ();
4465+
4466+ if (!managed)
4467+ return;
4468+
4469+ if (!window->minimized () && !inShowDesktopMode &&
4470+ !hidden && onDesktop)
4471+ {
4472+ if (state & CompWindowStateShadedMask)
4473+ {
4474+ shaded = true;
4475+ }
4476+ else
4477+ {
4478+ return;
4479+ }
4480+ }
4481+ else
4482+ {
4483+ shaded = false;
4484+
4485+ if ((state & CompWindowStateShadedMask) && serverFrame)
4486+ XUnmapWindow (screen->dpy (), serverFrame);
4487+ }
4488+
4489+ if (!pendingMaps && !window->isViewable ())
4490+ return;
4491+
4492+ window->windowNotify (CompWindowNotifyHide);
4493+
4494+ pendingUnmaps++;
4495+
4496+ if (serverFrame && !shaded)
4497+ XUnmapWindow (screen->dpy (), serverFrame);
4498+
4499+ XUnmapWindow (screen->dpy (), id);
4500+
4501+ if (window->minimized () || inShowDesktopMode || hidden || shaded)
4502+ window->changeState (state | CompWindowStateHiddenMask);
4503+
4504+ if (shaded && id == screen->activeWindow ())
4505+ window->moveInputFocusTo ();
4506+}
4507+
4508+void
4509+PrivateWindow::show ()
4510+{
4511+ bool onDesktop = window->onCurrentDesktop ();
4512+
4513+ if (!managed)
4514+ return;
4515+
4516+ if (minimized || inShowDesktopMode ||
4517+ hidden || !onDesktop)
4518+ {
4519+ /* no longer hidden but not on current desktop */
4520+ if (!minimized && !inShowDesktopMode && !hidden)
4521+ window->changeState (state & ~CompWindowStateHiddenMask);
4522+
4523+ return;
4524+ }
4525+
4526+ /* transition from minimized to shaded */
4527+ if (state & CompWindowStateShadedMask)
4528+ {
4529+ shaded = true;
4530+
4531+ if (serverFrame)
4532+ XMapWindow (screen->dpy (), serverFrame);
4533+
4534+ if (height)
4535+ {
4536+ priv->geometry.setHeight (priv->geometry.height () + 1);
4537+ window->resize (geometry.x (), geometry.y (),
4538+ geometry.width (), geometry.height () - 1,
4539+ geometry.border ());
4540+ }
4541+
4542+ return;
4543+ }
4544+ else
4545+ {
4546+ shaded = false;
4547+ }
4548+
4549+ window->windowNotify (CompWindowNotifyShow);
4550+
4551+ pendingMaps++;
4552+
4553+ if (serverFrame)
4554+ {
4555+ XMapWindow (screen->dpy (), serverFrame);
4556+ XMapWindow (screen->dpy (), wrapper);
4557+ }
4558+
4559+ XMapWindow (screen->dpy (), id);
4560+
4561+ window->changeState (state & ~CompWindowStateHiddenMask);
4562+ screen->priv->setWindowState (state, id);
4563+}
4564+
4565+void
4566+PrivateWindow::minimizeTransients (CompWindow *w,
4567+ CompWindow *ancestor)
4568+{
4569+ if (w->priv->transientFor == ancestor->priv->id ||
4570+ w->priv->isGroupTransient (ancestor->priv->clientLeader))
4571+ {
4572+ w->minimize ();
4573+ }
4574+}
4575+
4576+void
4577+CompWindow::minimize ()
4578+{
4579+ WRAPABLE_HND_FUNC (13, minimize);
4580+
4581+ if (!priv->managed)
4582+ return;
4583+
4584+ if (!priv->minimized)
4585+ {
4586+ windowNotify (CompWindowNotifyMinimize);
4587+
4588+ priv->minimized = true;
4589+
4590+ screen->forEachWindow (
4591+ boost::bind (PrivateWindow::minimizeTransients, _1, this));
4592+
4593+ priv->hide ();
4594+ }
4595+}
4596+
4597+void
4598+PrivateWindow::unminimizeTransients (CompWindow *w,
4599+ CompWindow *ancestor)
4600+{
4601+ if (w->priv->transientFor == ancestor->priv->id ||
4602+ w->priv->isGroupTransient (ancestor->priv->clientLeader))
4603+ w->unminimize ();
4604+}
4605+
4606+void
4607+CompWindow::unminimize ()
4608+{
4609+ WRAPABLE_HND_FUNC (14, unminimize);
4610+ if (priv->minimized)
4611+ {
4612+ windowNotify (CompWindowNotifyUnminimize);
4613+
4614+ priv->minimized = false;
4615+
4616+ priv->show ();
4617+
4618+ screen->forEachWindow (
4619+ boost::bind (PrivateWindow::unminimizeTransients, _1, this));
4620+ }
4621+}
4622+
4623+void
4624+CompWindow::maximize (unsigned int state)
4625+{
4626+ if (overrideRedirect ())
4627+ return;
4628+
4629+ state = constrainWindowState (state, priv->actions);
4630+
4631+ state &= MAXIMIZE_STATE;
4632+
4633+ if (state == (priv->state & MAXIMIZE_STATE))
4634+ return;
4635+
4636+ state |= (priv->state & ~MAXIMIZE_STATE);
4637+
4638+ changeState (state);
4639+ updateAttributes (CompStackingUpdateModeNone);
4640+}
4641+
4642+bool
4643+PrivateWindow::getUserTime (Time& time)
4644+{
4645+ Atom actual;
4646+ int result, format;
4647+ unsigned long n, left;
4648+ unsigned char *data;
4649+ bool retval = false;
4650+
4651+ result = XGetWindowProperty (screen->dpy (), priv->id,
4652+ Atoms::wmUserTime,
4653+ 0L, 1L, False, XA_CARDINAL, &actual, &format,
4654+ &n, &left, &data);
4655+
4656+ if (result == Success && data)
4657+ {
4658+ if (n)
4659+ {
4660+ CARD32 value;
4661+
4662+ memcpy (&value, data, sizeof (CARD32));
4663+ retval = true;
4664+ time = (Time) value;
4665+ }
4666+
4667+ XFree ((void *) data);
4668+ }
4669+
4670+ return retval;
4671+}
4672+
4673+void
4674+PrivateWindow::setUserTime (Time time)
4675+{
4676+ CARD32 value = (CARD32) time;
4677+
4678+ XChangeProperty (screen->dpy (), priv->id,
4679+ Atoms::wmUserTime,
4680+ XA_CARDINAL, 32, PropModeReplace,
4681+ (unsigned char *) &value, 1);
4682+}
4683+
4684+/*
4685+ * Macros from metacity
4686+ *
4687+ * Xserver time can wraparound, thus comparing two timestamps needs to
4688+ * take this into account. Here's a little macro to help out. If no
4689+ * wraparound has occurred, this is equivalent to
4690+ * time1 < time2
4691+ * Of course, the rest of the ugliness of this macro comes from
4692+ * accounting for the fact that wraparound can occur and the fact that
4693+ * a timestamp of 0 must be special-cased since it means older than
4694+ * anything else.
4695+ *
4696+ * Note that this is NOT an equivalent for time1 <= time2; if that's
4697+ * what you need then you'll need to swap the order of the arguments
4698+ * and negate the result.
4699+ */
4700+#define XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) \
4701+ ( (( (time1) < (time2) ) && \
4702+ ( (time2) - (time1) < ((unsigned long) -1) / 2 )) || \
4703+ (( (time1) > (time2) ) && \
4704+ ( (time1) - (time2) > ((unsigned long) -1) / 2 )) \
4705+ )
4706+#define XSERVER_TIME_IS_BEFORE(time1, time2) \
4707+ ( (time1) == 0 || \
4708+ (XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS (time1, time2) && \
4709+ (time2) != 0) \
4710+ )
4711+
4712+bool
4713+PrivateWindow::getUsageTimestamp (Time& timestamp)
4714+{
4715+ if (getUserTime (timestamp))
4716+ return true;
4717+
4718+ if (initialTimestampSet)
4719+ {
4720+ timestamp = initialTimestamp;
4721+ return true;
4722+ }
4723+
4724+ return false;
4725+}
4726+
4727+bool
4728+PrivateWindow::isWindowFocusAllowed (Time timestamp)
4729+{
4730+ CompScreen *s = screen;
4731+ CompWindow *active;
4732+ Time wUserTime, aUserTime;
4733+ bool gotTimestamp = false;
4734+ int level;
4735+ CompPoint dvp;
4736+
4737+ level = s->priv->optionGetFocusPreventionLevel ();
4738+
4739+ if (level == CoreOptions::FocusPreventionLevelOff)
4740+ return true;
4741+
4742+ if (timestamp)
4743+ {
4744+ /* the caller passed a timestamp, so use that
4745+ instead of the window's user time */
4746+ wUserTime = timestamp;
4747+ gotTimestamp = true;
4748+ }
4749+ else
4750+ {
4751+ gotTimestamp = getUsageTimestamp (wUserTime);
4752+ }
4753+
4754+ /* if we got no timestamp for the window, try to get at least a timestamp
4755+ for its transient parent, if any */
4756+ if (!gotTimestamp && transientFor)
4757+ {
4758+ CompWindow *parent;
4759+
4760+ parent = screen->findWindow (transientFor);
4761+ if (parent)
4762+ gotTimestamp = parent->priv->getUsageTimestamp (wUserTime);
4763+ }
4764+
4765+ if (gotTimestamp && !wUserTime)
4766+ {
4767+ /* window explicitly requested no focus */
4768+ return false;
4769+ }
4770+
4771+ /* allow focus for excluded windows */
4772+ CompMatch &match = s->priv->optionGetFocusPreventionMatch ();
4773+ if (!match.evaluate (window))
4774+ return true;
4775+
4776+ if (level == CoreOptions::FocusPreventionLevelVeryHigh)
4777+ return false;
4778+
4779+ active = s->findWindow (s->activeWindow ());
4780+
4781+ /* no active window */
4782+ if (!active || (active->type () & CompWindowTypeDesktopMask))
4783+ return true;
4784+
4785+ /* active window belongs to same application */
4786+ if (window->clientLeader () == active->clientLeader ())
4787+ return true;
4788+
4789+ if (level == CoreOptions::FocusPreventionLevelHigh)
4790+ return false;
4791+
4792+ /* not in current viewport or desktop */
4793+ if (!window->onCurrentDesktop ())
4794+ return false;
4795+
4796+ dvp = window->defaultViewport ();
4797+ if (dvp.x () != s->vp ().x () || dvp.y () != s->vp ().y ())
4798+ return false;
4799+
4800+ if (!gotTimestamp)
4801+ {
4802+ /* unsure as we have nothing to compare - allow focus in low level,
4803+ don't allow in normal level */
4804+ if (level == CoreOptions::FocusPreventionLevelNormal)
4805+ return false;
4806+
4807+ return true;
4808+ }
4809+
4810+ /* can't get user time for active window */
4811+ if (!active->priv->getUserTime (aUserTime))
4812+ return true;
4813+
4814+ if (XSERVER_TIME_IS_BEFORE (wUserTime, aUserTime))
4815+ return false;
4816+
4817+ return true;
4818+}
4819+
4820+bool
4821+PrivateWindow::allowWindowFocus (unsigned int noFocusMask,
4822+ Time timestamp)
4823+{
4824+ bool retval;
4825+
4826+ if (priv->id == screen->activeWindow ())
4827+ return true;
4828+
4829+ /* do not focus windows of these types */
4830+ if (priv->type & noFocusMask)
4831+ return false;
4832+
4833+ /* window doesn't take focus */
4834+ if (!priv->inputHint &&
4835+ !(priv->protocols & CompWindowProtocolTakeFocusMask))
4836+ {
4837+ return false;
4838+ }
4839+
4840+ retval = priv->isWindowFocusAllowed (timestamp);
4841+ if (!retval)
4842+ {
4843+ /* add demands attention state if focus was prevented */
4844+ window->changeState (priv->state | CompWindowStateDemandsAttentionMask);
4845+ }
4846+
4847+ return retval;
4848+}
4849+
4850+CompPoint
4851+CompWindow::defaultViewport ()
4852+{
4853+ CompPoint viewport;
4854+
4855+ if (priv->serverGeometry.x () < (int) screen->width () &&
4856+ priv->serverGeometry.x () + priv->serverGeometry.width () > 0 &&
4857+ priv->serverGeometry.y () < (int) screen->height () &&
4858+ priv->serverGeometry.y ()+ priv->serverGeometry.height () > 0)
4859+ {
4860+ return screen->vp ();
4861+ }
4862+
4863+ screen->viewportForGeometry (priv->serverGeometry, viewport);
4864+
4865+ return viewport;
4866+}
4867+
4868+CompPoint &
4869+CompWindow::initialViewport () const
4870+{
4871+ return priv->initialViewport;
4872+}
4873+
4874+void
4875+PrivateWindow::readIconHint ()
4876+{
4877+ XImage *image, *maskImage = NULL;
4878+ Display *dpy = screen->dpy ();
4879+ unsigned int width, height, dummy;
4880+ unsigned int i, j, k;
4881+ int iDummy;
4882+ Window wDummy;
4883+ CompIcon *icon;
4884+ XColor *colors;
4885+ CARD32 *p;
4886+
4887+ if (!XGetGeometry (dpy, hints->icon_pixmap, &wDummy, &iDummy,
4888+ &iDummy, &width, &height, &dummy, &dummy))
4889+ return;
4890+
4891+ image = XGetImage (dpy, hints->icon_pixmap, 0, 0, width, height,
4892+ AllPlanes, ZPixmap);
4893+ if (!image)
4894+ return;
4895+
4896+ colors = new XColor[width * height];
4897+ if (!colors)
4898+ {
4899+ XDestroyImage (image);
4900+ return;
4901+ }
4902+
4903+ k = 0;
4904+ for (j = 0; j < height; j++)
4905+ for (i = 0; i < width; i++)
4906+ colors[k++].pixel = XGetPixel (image, i, j);
4907+
4908+ for (i = 0; i < k; i += 256)
4909+ XQueryColors (dpy, screen->priv->colormap,
4910+ &colors[i], MIN (k - i, 256));
4911+
4912+ XDestroyImage (image);
4913+
4914+ icon = new CompIcon (screen, width, height);
4915+ if (!icon)
4916+ {
4917+ delete [] colors;
4918+ return;
4919+ }
4920+
4921+ if (hints->flags & IconMaskHint)
4922+ maskImage = XGetImage (dpy, hints->icon_mask, 0, 0,
4923+ width, height, AllPlanes, ZPixmap);
4924+
4925+ k = 0;
4926+ p = (CARD32 *) icon->data ();
4927+
4928+ for (j = 0; j < height; j++)
4929+ {
4930+ for (i = 0; i < width; i++)
4931+ {
4932+ if (maskImage && !XGetPixel (maskImage, i, j))
4933+ *p++ = 0;
4934+ else if (image->depth == 1) /* white : black */
4935+ *p++ = colors[k].pixel ? 0xffffffff : 0xff000000;
4936+ else
4937+ *p++ = 0xff000000 | /* alpha */
4938+ (((colors[k].red >> 8) & 0xff) << 16) | /* red */
4939+ (((colors[k].green >> 8) & 0xff) << 8) | /* green */
4940+ ((colors[k].blue >> 8) & 0xff); /* blue */
4941+
4942+ k++;
4943+ }
4944+ }
4945+
4946+ delete [] colors;
4947+ if (maskImage)
4948+ XDestroyImage (maskImage);
4949+
4950+ icons.push_back (icon);
4951+}
4952+
4953+/* returns icon with dimensions as close as possible to width and height
4954+ but never greater. */
4955+CompIcon *
4956+CompWindow::getIcon (int width,
4957+ int height)
4958+{
4959+ CompIcon *icon;
4960+ int wh, diff, oldDiff;
4961+ unsigned int i;
4962+
4963+ /* need to fetch icon property */
4964+ if (priv->icons.size () == 0 && !priv->noIcons)
4965+ {
4966+ Atom actual;
4967+ int result, format;
4968+ unsigned long n, left;
4969+ unsigned char *data;
4970+
4971+ result = XGetWindowProperty (screen->dpy (), priv->id, Atoms::wmIcon,
4972+ 0L, 65536L, false, XA_CARDINAL,
4973+ &actual, &format, &n, &left, &data);
4974+
4975+ if (result == Success && data)
4976+ {
4977+ CARD32 *p;
4978+ CARD32 alpha, red, green, blue;
4979+ unsigned long iw, ih;
4980+
4981+ for (i = 0; i + 2 < n; i += iw * ih + 2)
4982+ {
4983+ unsigned long *idata = (unsigned long *) data;
4984+
4985+ iw = idata[i];
4986+ ih = idata[i + 1];
4987+
4988+ /* iw * ih may be larger than the value range of unsigned
4989+ * long, so better do some checking for extremely weird
4990+ * icon sizes first */
4991+ if (iw > 2048 || ih > 2048 || iw * ih + 2 > n - i)
4992+ break;
4993+
4994+ if (iw && ih)
4995+ {
4996+ unsigned long j;
4997+ icon = new CompIcon (screen, iw, ih);
4998+ if (!icon)
4999+ continue;
5000+
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: