Merge lp:~jamespharaoh/ubuntu/oneiric/compiz/fix-881329 into lp:ubuntu/oneiric/compiz
- Oneiric (11.10)
- fix-881329
- Merge into oneiric
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 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu branches | Pending | ||
Review via email: mp+82044@code.launchpad.net |
Commit message
Description of the change
Sebastien Bacher (seb128) wrote : | # |
seems like you did a request for precise on https:/
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!
Sebastien Bacher (seb128) wrote : | # |
let we know if you need help to get that done btw
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:/
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:/
> You are the owner of lp:~jamespharaoh/ubuntu/oneiric/compiz/fix-881329.
--
James Pharaoh
Pharaoh Systems Limited
http://
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
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 | + |
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?