1 /*
2 * Copyright © 2005 Novell, Inc.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without
6 * fee, provided that the above copyright notice appear in all copies
7 * and that both that copyright notice and this permission notice
8 * appear in supporting documentation, and that the name of
9 * Novell, Inc. not be used in advertising or publicity pertaining to
10 * distribution of the software without specific, written prior permission.
11 * Novell, Inc. makes no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
13 * implied warranty.
14 *
15 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Author: David Reveman <davidr@novell.com>
24 */
25
26 #include <X11/Xlib.h>
27 #include <X11/Xatom.h>
28 #include <X11/Xproto.h>
29 #include <X11/extensions/shape.h>
30 #include <X11/extensions/Xcomposite.h>
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <stdlib.h>
36 #include <stdint.h>
37 #include <assert.h>
38
39 #include <compiz-core.h>
40
41 #define MwmHintsFunctions (1L << 0)
42 #define MwmHintsDecorations (1L << 1)
43
44 #define PropMotifWmHintElements 3
45
46 typedef struct {
47 unsigned long flags;
48 unsigned long functions;
49 unsigned long decorations;
50 } MwmHints;
51
52 static int
reallocWindowPrivates(int size,void * closure)53 reallocWindowPrivates (int size,
54 void *closure)
55 {
56 CompScreen *s = (CompScreen *) closure;
57 CompWindow *w;
58 void *privates;
59
60 for (w = s->windows; w; w = w->next)
61 {
62 privates = realloc (w->base.privates, size * sizeof (CompPrivate));
63 if (!privates)
64 return FALSE;
65
66 w->base.privates = (CompPrivate *) privates;
67 }
68
69 return TRUE;
70 }
71
72 int
allocWindowObjectPrivateIndex(CompObject * parent)73 allocWindowObjectPrivateIndex (CompObject *parent)
74 {
75 CompScreen *screen = (CompScreen *) parent;
76
77 return allocatePrivateIndex (&screen->windowPrivateLen,
78 &screen->windowPrivateIndices,
79 reallocWindowPrivates,
80 (void *) screen);
81 }
82
83 void
freeWindowObjectPrivateIndex(CompObject * parent,int index)84 freeWindowObjectPrivateIndex (CompObject *parent,
85 int index)
86 {
87 CompScreen *screen = (CompScreen *) parent;
88
89 freePrivateIndex (screen->windowPrivateLen,
90 screen->windowPrivateIndices,
91 index);
92 }
93
94 CompBool
forEachWindowObject(CompObject * parent,ObjectCallBackProc proc,void * closure)95 forEachWindowObject (CompObject *parent,
96 ObjectCallBackProc proc,
97 void *closure)
98 {
99 if (parent->type == COMP_OBJECT_TYPE_SCREEN)
100 {
101 CompWindow *w;
102
103 CORE_SCREEN (parent);
104
105 for (w = s->windows; w; w = w->next)
106 {
107 if (!(*proc) (&w->base, closure))
108 return FALSE;
109 }
110 }
111
112 return TRUE;
113 }
114
115 char *
nameWindowObject(CompObject * object)116 nameWindowObject (CompObject *object)
117 {
118 char tmp[256];
119
120 CORE_WINDOW (object);
121
122 snprintf (tmp, 256, "0x%lu", w->id);
123
124 return strdup (tmp);
125 }
126
127 CompObject *
findWindowObject(CompObject * parent,const char * name)128 findWindowObject (CompObject *parent,
129 const char *name)
130 {
131 if (parent->type == COMP_OBJECT_TYPE_SCREEN)
132 {
133 CompWindow *w;
134 Window id = atoi (name);
135
136 CORE_SCREEN (parent);
137
138 for (w = s->windows; w; w = w->next)
139 if (w->id == id)
140 return &w->base;
141 }
142
143 return NULL;
144 }
145
146 int
allocateWindowPrivateIndex(CompScreen * screen)147 allocateWindowPrivateIndex (CompScreen *screen)
148 {
149 return compObjectAllocatePrivateIndex (&screen->base,
150 COMP_OBJECT_TYPE_WINDOW);
151 }
152
153 void
freeWindowPrivateIndex(CompScreen * screen,int index)154 freeWindowPrivateIndex (CompScreen *screen,
155 int index)
156 {
157 compObjectFreePrivateIndex (&screen->base,
158 COMP_OBJECT_TYPE_WINDOW,
159 index);
160 }
161
162 static Bool
isAncestorTo(CompWindow * transient,CompWindow * ancestor)163 isAncestorTo (CompWindow *transient,
164 CompWindow *ancestor)
165 {
166 if (transient->transientFor)
167 {
168 if (transient->transientFor == ancestor->id)
169 return TRUE;
170
171 transient = findWindowAtScreen (transient->screen,
172 transient->transientFor);
173 if (transient)
174 return isAncestorTo (transient, ancestor);
175 }
176
177 return FALSE;
178 }
179
180 static void
recalcNormalHints(CompWindow * window)181 recalcNormalHints (CompWindow *window)
182 {
183 int maxSize;
184
185 maxSize = window->screen->maxTextureSize;
186 maxSize -= window->serverBorderWidth * 2;
187
188 window->sizeHints.x = window->serverX;
189 window->sizeHints.y = window->serverY;
190 window->sizeHints.width = window->serverWidth;
191 window->sizeHints.height = window->serverHeight;
192
193 if (!(window->sizeHints.flags & PBaseSize))
194 {
195 if (window->sizeHints.flags & PMinSize)
196 {
197 window->sizeHints.base_width = window->sizeHints.min_width;
198 window->sizeHints.base_height = window->sizeHints.min_height;
199 }
200 else
201 {
202 window->sizeHints.base_width = 0;
203 window->sizeHints.base_height = 0;
204 }
205
206 window->sizeHints.flags |= PBaseSize;
207 }
208
209 if (!(window->sizeHints.flags & PMinSize))
210 {
211 window->sizeHints.min_width = window->sizeHints.base_width;
212 window->sizeHints.min_height = window->sizeHints.base_height;
213 window->sizeHints.flags |= PMinSize;
214 }
215
216 if (!(window->sizeHints.flags & PMaxSize))
217 {
218 window->sizeHints.max_width = 65535;
219 window->sizeHints.max_height = 65535;
220 window->sizeHints.flags |= PMaxSize;
221 }
222
223 if (window->sizeHints.max_width < window->sizeHints.min_width)
224 window->sizeHints.max_width = window->sizeHints.min_width;
225
226 if (window->sizeHints.max_height < window->sizeHints.min_height)
227 window->sizeHints.max_height = window->sizeHints.min_height;
228
229 if (window->sizeHints.min_width < 1)
230 window->sizeHints.min_width = 1;
231
232 if (window->sizeHints.max_width < 1)
233 window->sizeHints.max_width = 1;
234
235 if (window->sizeHints.min_height < 1)
236 window->sizeHints.min_height = 1;
237
238 if (window->sizeHints.max_height < 1)
239 window->sizeHints.max_height = 1;
240
241 if (window->sizeHints.max_width > maxSize)
242 window->sizeHints.max_width = maxSize;
243
244 if (window->sizeHints.max_height > maxSize)
245 window->sizeHints.max_height = maxSize;
246
247 if (window->sizeHints.min_width > maxSize)
248 window->sizeHints.min_width = maxSize;
249
250 if (window->sizeHints.min_height > maxSize)
251 window->sizeHints.min_height = maxSize;
252
253 if (window->sizeHints.base_width > maxSize)
254 window->sizeHints.base_width = maxSize;
255
256 if (window->sizeHints.base_height > maxSize)
257 window->sizeHints.base_height = maxSize;
258
259 if (window->sizeHints.flags & PResizeInc)
260 {
261 if (window->sizeHints.width_inc == 0)
262 window->sizeHints.width_inc = 1;
263
264 if (window->sizeHints.height_inc == 0)
265 window->sizeHints.height_inc = 1;
266 }
267 else
268 {
269 window->sizeHints.width_inc = 1;
270 window->sizeHints.height_inc = 1;
271 window->sizeHints.flags |= PResizeInc;
272 }
273
274 if (window->sizeHints.flags & PAspect)
275 {
276 /* don't divide by 0 */
277 if (window->sizeHints.min_aspect.y < 1)
278 window->sizeHints.min_aspect.y = 1;
279
280 if (window->sizeHints.max_aspect.y < 1)
281 window->sizeHints.max_aspect.y = 1;
282 }
283 else
284 {
285 window->sizeHints.min_aspect.x = 1;
286 window->sizeHints.min_aspect.y = 65535;
287 window->sizeHints.max_aspect.x = 65535;
288 window->sizeHints.max_aspect.y = 1;
289 window->sizeHints.flags |= PAspect;
290 }
291
292 if (!(window->sizeHints.flags & PWinGravity))
293 {
294 window->sizeHints.win_gravity = NorthWestGravity;
295 window->sizeHints.flags |= PWinGravity;
296 }
297 }
298
299 void
updateNormalHints(CompWindow * w)300 updateNormalHints (CompWindow *w)
301 {
302 Status status;
303 long supplied;
304
305 status = XGetWMNormalHints (w->screen->display->display, w->id,
306 &w->sizeHints, &supplied);
307
308 if (!status)
309 w->sizeHints.flags = 0;
310
311 recalcNormalHints (w);
312 }
313
314 void
updateWmHints(CompWindow * w)315 updateWmHints (CompWindow *w)
316 {
317 XWMHints *hints;
318 long dFlags = 0;
319 Bool iconChanged = FALSE;
320
321 if (w->hints)
322 dFlags = w->hints->flags;
323
324 w->inputHint = TRUE;
325
326 hints = XGetWMHints (w->screen->display->display, w->id);
327 if (hints)
328 {
329 dFlags ^= hints->flags;
330
331 if (hints->flags & InputHint)
332 w->inputHint = hints->input;
333
334 if (w->hints)
335 {
336 if ((hints->flags & IconPixmapHint) &&
337 (w->hints->icon_pixmap != hints->icon_pixmap))
338 {
339 iconChanged = TRUE;
340 }
341 else if ((hints->flags & IconMaskHint) &&
342 (w->hints->icon_mask != hints->icon_mask))
343 {
344 iconChanged = TRUE;
345 }
346 }
347 }
348
349 iconChanged |= (dFlags & (IconPixmapHint | IconMaskHint));
350
351 if (iconChanged)
352 freeWindowIcons (w);
353
354 if (w->hints)
355 XFree (w->hints);
356
357 w->hints = hints;
358 }
359
360 void
updateWindowClassHints(CompWindow * w)361 updateWindowClassHints (CompWindow *w)
362 {
363 XClassHint classHint;
364 int status;
365
366 if (w->resName)
367 {
368 free (w->resName);
369 w->resName = NULL;
370 }
371
372 if (w->resClass)
373 {
374 free (w->resClass);
375 w->resClass = NULL;
376 }
377
378 status = XGetClassHint (w->screen->display->display, w->id, &classHint);
379 if (status)
380 {
381 if (classHint.res_name)
382 {
383 w->resName = strdup (classHint.res_name);
384 XFree (classHint.res_name);
385 }
386
387 if (classHint.res_class)
388 {
389 w->resClass = strdup (classHint.res_class);
390 XFree (classHint.res_class);
391 }
392 }
393 }
394
395 void
updateTransientHint(CompWindow * w)396 updateTransientHint (CompWindow *w)
397 {
398 Window transientFor;
399 Status status;
400
401 w->transientFor = None;
402
403 status = XGetTransientForHint (w->screen->display->display,
404 w->id, &transientFor);
405
406 if (status)
407 {
408 CompWindow *ancestor;
409
410 ancestor = findWindowAtScreen (w->screen, transientFor);
411 if (!ancestor)
412 return;
413
414 /* protect against circular transient dependencies */
415 if (transientFor == w->id || isAncestorTo (ancestor, w))
416 return;
417
418 w->transientFor = transientFor;
419 }
420 }
421
422 void
updateIconGeometry(CompWindow * w)423 updateIconGeometry (CompWindow *w)
424 {
425 Atom actual;
426 int result, format;
427 unsigned long n, left;
428 unsigned char *data;
429
430 result = XGetWindowProperty (w->screen->display->display, w->id,
431 w->screen->display->wmIconGeometryAtom,
432 0L, 1024L, False, XA_CARDINAL,
433 &actual, &format, &n, &left, &data);
434
435 w->iconGeometrySet = FALSE;
436
437 if (result == Success && data)
438 {
439 if (n == 4)
440 {
441 unsigned long *geometry = (unsigned long *) data;
442
443 w->iconGeometry.x = geometry[0];
444 w->iconGeometry.y = geometry[1];
445 w->iconGeometry.width = geometry[2];
446 w->iconGeometry.height = geometry[3];
447
448 w->iconGeometrySet = TRUE;
449 }
450
451 XFree (data);
452 }
453 }
454
455 static Window
getClientLeaderOfAncestor(CompWindow * w)456 getClientLeaderOfAncestor (CompWindow *w)
457 {
458 if (w->transientFor)
459 {
460 w = findWindowAtScreen (w->screen, w->transientFor);
461 if (w)
462 {
463 if (w->clientLeader)
464 return w->clientLeader;
465
466 return getClientLeaderOfAncestor (w);
467 }
468 }
469
470 return None;
471 }
472
473 Window
getClientLeader(CompWindow * w)474 getClientLeader (CompWindow *w)
475 {
476 Atom actual;
477 int result, format;
478 unsigned long n, left;
479 unsigned char *data;
480
481 result = XGetWindowProperty (w->screen->display->display, w->id,
482 w->screen->display->wmClientLeaderAtom,
483 0L, 1L, False, XA_WINDOW, &actual, &format,
484 &n, &left, &data);
485
486 if (result == Success && data)
487 {
488 Window win = None;
489
490 if (n)
491 memcpy (&win, data, sizeof (Window));
492 XFree ((void *) data);
493
494 if (win)
495 return win;
496 }
497
498 return getClientLeaderOfAncestor (w);
499 }
500
501 char *
getStartupId(CompWindow * w)502 getStartupId (CompWindow *w)
503 {
504 Atom actual;
505 int result, format;
506 unsigned long n, left;
507 unsigned char *data;
508
509 result = XGetWindowProperty (w->screen->display->display, w->id,
510 w->screen->display->startupIdAtom,
511 0L, 1024L, False,
512 w->screen->display->utf8StringAtom,
513 &actual, &format,
514 &n, &left, &data);
515
516 if (result == Success && data)
517 {
518 char *id = NULL;
519
520 if (n)
521 id = strdup ((char *) data);
522 XFree ((void *) data);
523
524 return id;
525 }
526
527 return NULL;
528 }
529
530 int
getWmState(CompDisplay * display,Window id)531 getWmState (CompDisplay *display,
532 Window id)
533 {
534 Atom actual;
535 int result, format;
536 unsigned long n, left;
537 unsigned char *data;
538 unsigned long state = NormalState;
539
540 result = XGetWindowProperty (display->display, id,
541 display->wmStateAtom, 0L, 2L, FALSE,
542 display->wmStateAtom, &actual, &format,
543 &n, &left, &data);
544
545 if (result == Success && data)
546 {
547 if (n)
548 memcpy (&state, data, sizeof (unsigned long));
549 XFree ((void *) data);
550 }
551
552 return state;
553 }
554
555 void
setWmState(CompDisplay * display,int state,Window id)556 setWmState (CompDisplay *display,
557 int state,
558 Window id)
559 {
560 unsigned long data[2];
561
562 data[0] = state;
563 data[1] = None;
564
565 XChangeProperty (display->display, id,
566 display->wmStateAtom, display->wmStateAtom,
567 32, PropModeReplace, (unsigned char *) data, 2);
568 }
569
570 unsigned int
windowStateMask(CompDisplay * display,Atom state)571 windowStateMask (CompDisplay *display,
572 Atom state)
573 {
574 if (state == display->winStateModalAtom)
575 return CompWindowStateModalMask;
576 else if (state == display->winStateStickyAtom)
577 return CompWindowStateStickyMask;
578 else if (state == display->winStateMaximizedVertAtom)
579 return CompWindowStateMaximizedVertMask;
580 else if (state == display->winStateMaximizedHorzAtom)
581 return CompWindowStateMaximizedHorzMask;
582 else if (state == display->winStateShadedAtom)
583 return CompWindowStateShadedMask;
584 else if (state == display->winStateSkipTaskbarAtom)
585 return CompWindowStateSkipTaskbarMask;
586 else if (state == display->winStateSkipPagerAtom)
587 return CompWindowStateSkipPagerMask;
588 else if (state == display->winStateHiddenAtom)
589 return CompWindowStateHiddenMask;
590 else if (state == display->winStateFullscreenAtom)
591 return CompWindowStateFullscreenMask;
592 else if (state == display->winStateAboveAtom)
593 return CompWindowStateAboveMask;
594 else if (state == display->winStateBelowAtom)
595 return CompWindowStateBelowMask;
596 else if (state == display->winStateDemandsAttentionAtom)
597 return CompWindowStateDemandsAttentionMask;
598 else if (state == display->winStateDisplayModalAtom)
599 return CompWindowStateDisplayModalMask;
600
601 return 0;
602 }
603
604 unsigned int
windowStateFromString(const char * str)605 windowStateFromString (const char *str)
606 {
607 if (strcasecmp (str, "modal") == 0)
608 return CompWindowStateModalMask;
609 else if (strcasecmp (str, "sticky") == 0)
610 return CompWindowStateStickyMask;
611 else if (strcasecmp (str, "maxvert") == 0)
612 return CompWindowStateMaximizedVertMask;
613 else if (strcasecmp (str, "maxhorz") == 0)
614 return CompWindowStateMaximizedHorzMask;
615 else if (strcasecmp (str, "shaded") == 0)
616 return CompWindowStateShadedMask;
617 else if (strcasecmp (str, "skiptaskbar") == 0)
618 return CompWindowStateSkipTaskbarMask;
619 else if (strcasecmp (str, "skippager") == 0)
620 return CompWindowStateSkipPagerMask;
621 else if (strcasecmp (str, "hidden") == 0)
622 return CompWindowStateHiddenMask;
623 else if (strcasecmp (str, "fullscreen") == 0)
624 return CompWindowStateFullscreenMask;
625 else if (strcasecmp (str, "above") == 0)
626 return CompWindowStateAboveMask;
627 else if (strcasecmp (str, "below") == 0)
628 return CompWindowStateBelowMask;
629 else if (strcasecmp (str, "demandsattention") == 0)
630 return CompWindowStateDemandsAttentionMask;
631
632 return 0;
633 }
634
635 unsigned int
getWindowState(CompDisplay * display,Window id)636 getWindowState (CompDisplay *display,
637 Window id)
638 {
639 Atom actual;
640 int result, format;
641 unsigned long n, left;
642 unsigned char *data;
643 unsigned int state = 0;
644
645 result = XGetWindowProperty (display->display, id, display->winStateAtom,
646 0L, 1024L, FALSE, XA_ATOM, &actual, &format,
647 &n, &left, &data);
648
649 if (result == Success && data)
650 {
651 Atom *a = (Atom *) data;
652
653 while (n--)
654 state |= windowStateMask (display, *a++);
655
656 XFree ((void *) data);
657 }
658
659 return state;
660 }
661
662 void
setWindowState(CompDisplay * display,unsigned int state,Window id)663 setWindowState (CompDisplay *display,
664 unsigned int state,
665 Window id)
666 {
667 Atom data[32];
668 int i = 0;
669
670 if (state & CompWindowStateModalMask)
671 data[i++] = display->winStateModalAtom;
672 if (state & CompWindowStateStickyMask)
673 data[i++] = display->winStateStickyAtom;
674 if (state & CompWindowStateMaximizedVertMask)
675 data[i++] = display->winStateMaximizedVertAtom;
676 if (state & CompWindowStateMaximizedHorzMask)
677 data[i++] = display->winStateMaximizedHorzAtom;
678 if (state & CompWindowStateShadedMask)
679 data[i++] = display->winStateShadedAtom;
680 if (state & CompWindowStateSkipTaskbarMask)
681 data[i++] = display->winStateSkipTaskbarAtom;
682 if (state & CompWindowStateSkipPagerMask)
683 data[i++] = display->winStateSkipPagerAtom;
684 if (state & CompWindowStateHiddenMask)
685 data[i++] = display->winStateHiddenAtom;
686 if (state & CompWindowStateFullscreenMask)
687 data[i++] = display->winStateFullscreenAtom;
688 if (state & CompWindowStateAboveMask)
689 data[i++] = display->winStateAboveAtom;
690 if (state & CompWindowStateBelowMask)
691 data[i++] = display->winStateBelowAtom;
692 if (state & CompWindowStateDemandsAttentionMask)
693 data[i++] = display->winStateDemandsAttentionAtom;
694 if (state & CompWindowStateDisplayModalMask)
695 data[i++] = display->winStateDisplayModalAtom;
696
697 XChangeProperty (display->display, id, display->winStateAtom,
698 XA_ATOM, 32, PropModeReplace,
699 (unsigned char *) data, i);
700 }
701
702 void
changeWindowState(CompWindow * w,unsigned int newState)703 changeWindowState (CompWindow *w,
704 unsigned int newState)
705 {
706 CompDisplay *d = w->screen->display;
707 unsigned int oldState;
708
709 if (w->state == newState)
710 return;
711
712 oldState = w->state;
713 w->state = newState;
714
715 recalcWindowType (w);
716 recalcWindowActions (w);
717
718 if (w->managed)
719 setWindowState (d, w->state, w->id);
720
721 (*w->screen->windowStateChangeNotify) (w, oldState);
722 (*d->matchPropertyChanged) (d, w);
723 }
724
725 static void
setWindowActions(CompDisplay * display,unsigned int actions,Window id)726 setWindowActions (CompDisplay *display,
727 unsigned int actions,
728 Window id)
729 {
730 Atom data[32];
731 int i = 0;
732
733 if (actions & CompWindowActionMoveMask)
734 data[i++] = display->winActionMoveAtom;
735 if (actions & CompWindowActionResizeMask)
736 data[i++] = display->winActionResizeAtom;
737 if (actions & CompWindowActionStickMask)
738 data[i++] = display->winActionStickAtom;
739 if (actions & CompWindowActionMinimizeMask)
740 data[i++] = display->winActionMinimizeAtom;
741 if (actions & CompWindowActionMaximizeHorzMask)
742 data[i++] = display->winActionMaximizeHorzAtom;
743 if (actions & CompWindowActionMaximizeVertMask)
744 data[i++] = display->winActionMaximizeVertAtom;
745 if (actions & CompWindowActionFullscreenMask)
746 data[i++] = display->winActionFullscreenAtom;
747 if (actions & CompWindowActionCloseMask)
748 data[i++] = display->winActionCloseAtom;
749 if (actions & CompWindowActionShadeMask)
750 data[i++] = display->winActionShadeAtom;
751 if (actions & CompWindowActionChangeDesktopMask)
752 data[i++] = display->winActionChangeDesktopAtom;
753 if (actions & CompWindowActionAboveMask)
754 data[i++] = display->winActionAboveAtom;
755 if (actions & CompWindowActionBelowMask)
756 data[i++] = display->winActionBelowAtom;
757
758 XChangeProperty (display->display, id, display->wmAllowedActionsAtom,
759 XA_ATOM, 32, PropModeReplace,
760 (unsigned char *) data, i);
761 }
762
763 void
recalcWindowActions(CompWindow * w)764 recalcWindowActions (CompWindow *w)
765 {
766 unsigned int actions = 0;
767 unsigned int setActions, clearActions;
768
769 switch (w->type) {
770 case CompWindowTypeFullscreenMask:
771 case CompWindowTypeNormalMask:
772 actions =
773 CompWindowActionMaximizeHorzMask |
774 CompWindowActionMaximizeVertMask |
775 CompWindowActionFullscreenMask |
776 CompWindowActionMoveMask |
777 CompWindowActionResizeMask |
778 CompWindowActionStickMask |
779 CompWindowActionMinimizeMask |
780 CompWindowActionCloseMask |
781 CompWindowActionChangeDesktopMask;
782 break;
783 case CompWindowTypeUtilMask:
784 case CompWindowTypeMenuMask:
785 case CompWindowTypeToolbarMask:
786 actions =
787 CompWindowActionMoveMask |
788 CompWindowActionResizeMask |
789 CompWindowActionStickMask |
790 CompWindowActionCloseMask |
791 CompWindowActionChangeDesktopMask;
792 break;
793 case CompWindowTypeDialogMask:
794 case CompWindowTypeModalDialogMask:
795 actions =
796 CompWindowActionMaximizeHorzMask |
797 CompWindowActionMaximizeVertMask |
798 CompWindowActionMoveMask |
799 CompWindowActionResizeMask |
800 CompWindowActionStickMask |
801 CompWindowActionCloseMask |
802 CompWindowActionChangeDesktopMask;
803
804 /* allow minimization for dialog windows if they
805 a) are not a transient (transients can be minimized
806 with their parent)
807 b) don't have the skip taskbar hint set (as those
808 have no target to be minimized to)
809 */
810 if (!w->transientFor &&
811 !(w->state & CompWindowStateSkipTaskbarMask))
812 {
813 actions |= CompWindowActionMinimizeMask;
814 }
815 default:
816 break;
817 }
818
819 if (w->input.top)
820 actions |= CompWindowActionShadeMask;
821
822 actions |= (CompWindowActionAboveMask | CompWindowActionBelowMask);
823
824 switch (w->wmType) {
825 case CompWindowTypeNormalMask:
826 actions |= CompWindowActionFullscreenMask |
827 CompWindowActionMinimizeMask;
828 default:
829 break;
830 }
831
832 if (w->sizeHints.min_width == w->sizeHints.max_width &&
833 w->sizeHints.min_height == w->sizeHints.max_height)
834 actions &= ~(CompWindowActionResizeMask |
835 CompWindowActionMaximizeHorzMask |
836 CompWindowActionMaximizeVertMask |
837 CompWindowActionFullscreenMask);
838
839 if (!(w->mwmFunc & MwmFuncAll))
840 {
841 if (!(w->mwmFunc & MwmFuncResize))
842 actions &= ~(CompWindowActionResizeMask |
843 CompWindowActionMaximizeHorzMask |
844 CompWindowActionMaximizeVertMask |
845 CompWindowActionFullscreenMask);
846
847 if (!(w->mwmFunc & MwmFuncMove))
848 actions &= ~(CompWindowActionMoveMask |
849 CompWindowActionMaximizeHorzMask |
850 CompWindowActionMaximizeVertMask |
851 CompWindowActionFullscreenMask);
852
853 if (!(w->mwmFunc & MwmFuncIconify))
854 actions &= ~CompWindowActionMinimizeMask;
855
856 if (!(w->mwmFunc & MwmFuncClose))
857 actions &= ~CompWindowActionCloseMask;
858 }
859
860 (*w->screen->getAllowedActionsForWindow) (w, &setActions, &clearActions);
861 actions &= ~clearActions;
862 actions |= setActions;
863
864 if (actions != w->actions)
865 {
866 w->actions = actions;
867 setWindowActions (w->screen->display, actions, w->id);
868 }
869 }
870
871 void
getAllowedActionsForWindow(CompWindow * w,unsigned int * setActions,unsigned int * clearActions)872 getAllowedActionsForWindow (CompWindow *w,
873 unsigned int *setActions,
874 unsigned int *clearActions)
875 {
876 *setActions = 0;
877 *clearActions = 0;
878 }
879
880 unsigned int
constrainWindowState(unsigned int state,unsigned int actions)881 constrainWindowState (unsigned int state,
882 unsigned int actions)
883 {
884 if (!(actions & CompWindowActionMaximizeHorzMask))
885 state &= ~CompWindowStateMaximizedHorzMask;
886
887 if (!(actions & CompWindowActionMaximizeVertMask))
888 state &= ~CompWindowStateMaximizedVertMask;
889
890 if (!(actions & CompWindowActionShadeMask))
891 state &= ~CompWindowStateShadedMask;
892
893 if (!(actions & CompWindowActionFullscreenMask))
894 state &= ~CompWindowStateFullscreenMask;
895
896 return state;
897 }
898
899 unsigned int
windowTypeFromString(const char * str)900 windowTypeFromString (const char *str)
901 {
902 if (strcasecmp (str, "desktop") == 0)
903 return CompWindowTypeDesktopMask;
904 else if (strcasecmp (str, "dock") == 0)
905 return CompWindowTypeDockMask;
906 else if (strcasecmp (str, "toolbar") == 0)
907 return CompWindowTypeToolbarMask;
908 else if (strcasecmp (str, "menu") == 0)
909 return CompWindowTypeMenuMask;
910 else if (strcasecmp (str, "utility") == 0)
911 return CompWindowTypeUtilMask;
912 else if (strcasecmp (str, "splash") == 0)
913 return CompWindowTypeSplashMask;
914 else if (strcasecmp (str, "dialog") == 0)
915 return CompWindowTypeDialogMask;
916 else if (strcasecmp (str, "normal") == 0)
917 return CompWindowTypeNormalMask;
918 else if (strcasecmp (str, "dropdownmenu") == 0)
919 return CompWindowTypeDropdownMenuMask;
920 else if (strcasecmp (str, "popupmenu") == 0)
921 return CompWindowTypePopupMenuMask;
922 else if (strcasecmp (str, "tooltip") == 0)
923 return CompWindowTypeTooltipMask;
924 else if (strcasecmp (str, "notification") == 0)
925 return CompWindowTypeNotificationMask;
926 else if (strcasecmp (str, "combo") == 0)
927 return CompWindowTypeComboMask;
928 else if (strcasecmp (str, "dnd") == 0)
929 return CompWindowTypeDndMask;
930 else if (strcasecmp (str, "modaldialog") == 0)
931 return CompWindowTypeModalDialogMask;
932 else if (strcasecmp (str, "fullscreen") == 0)
933 return CompWindowTypeFullscreenMask;
934 else if (strcasecmp (str, "unknown") == 0)
935 return CompWindowTypeUnknownMask;
936 else if (strcasecmp (str, "any") == 0)
937 return ~0;
938
939 return 0;
940 }
941
942 unsigned int
getWindowType(CompDisplay * display,Window id)943 getWindowType (CompDisplay *display,
944 Window id)
945 {
946 Atom actual, a = None;
947 int result, format;
948 unsigned long n, left;
949 unsigned char *data;
950
951 result = XGetWindowProperty (display->display, id, display->winTypeAtom,
952 0L, 1L, FALSE, XA_ATOM, &actual, &format,
953 &n, &left, &data);
954
955 if (result == Success && data)
956 {
957 if (n)
958 memcpy (&a, data, sizeof (Atom));
959
960 XFree ((void *) data);
961 }
962
963 if (a)
964 {
965 if (a == display->winTypeNormalAtom)
966 return CompWindowTypeNormalMask;
967 else if (a == display->winTypeMenuAtom)
968 return CompWindowTypeMenuMask;
969 else if (a == display->winTypeDesktopAtom)
970 return CompWindowTypeDesktopMask;
971 else if (a == display->winTypeDockAtom)
972 return CompWindowTypeDockMask;
973 else if (a == display->winTypeToolbarAtom)
974 return CompWindowTypeToolbarMask;
975 else if (a == display->winTypeUtilAtom)
976 return CompWindowTypeUtilMask;
977 else if (a == display->winTypeSplashAtom)
978 return CompWindowTypeSplashMask;
979 else if (a == display->winTypeDialogAtom)
980 return CompWindowTypeDialogMask;
981 else if (a == display->winTypeDropdownMenuAtom)
982 return CompWindowTypeDropdownMenuMask;
983 else if (a == display->winTypePopupMenuAtom)
984 return CompWindowTypePopupMenuMask;
985 else if (a == display->winTypeTooltipAtom)
986 return CompWindowTypeTooltipMask;
987 else if (a == display->winTypeNotificationAtom)
988 return CompWindowTypeNotificationMask;
989 else if (a == display->winTypeComboAtom)
990 return CompWindowTypeComboMask;
991 else if (a == display->winTypeDndAtom)
992 return CompWindowTypeDndMask;
993 }
994
995 return CompWindowTypeUnknownMask;
996 }
997
998 void
recalcWindowType(CompWindow * w)999 recalcWindowType (CompWindow *w)
1000 {
1001 unsigned int type;
1002
1003 type = w->wmType;
1004
1005 if (!w->attrib.override_redirect && w->wmType == CompWindowTypeUnknownMask)
1006 type = CompWindowTypeNormalMask;
1007
1008 if (w->state & CompWindowStateFullscreenMask)
1009 type = CompWindowTypeFullscreenMask;
1010
1011 if (type == CompWindowTypeNormalMask)
1012 {
1013 if (w->transientFor)
1014 type = CompWindowTypeDialogMask;
1015 }
1016
1017 if (type == CompWindowTypeDockMask && (w->state & CompWindowStateBelowMask))
1018 type = CompWindowTypeNormalMask;
1019
1020 if ((type & (CompWindowTypeNormalMask | CompWindowTypeDialogMask)) &&
1021 (w->state & CompWindowStateModalMask))
1022 type = CompWindowTypeModalDialogMask;
1023
1024 w->type = type;
1025 }
1026
1027 void
getMwmHints(CompDisplay * display,Window id,unsigned int * func,unsigned int * decor)1028 getMwmHints (CompDisplay *display,
1029 Window id,
1030 unsigned int *func,
1031 unsigned int *decor)
1032 {
1033 Atom actual;
1034 int result, format;
1035 unsigned long n, left;
1036 unsigned char *data;
1037
1038 *func = MwmFuncAll;
1039 *decor = MwmDecorAll;
1040
1041 result = XGetWindowProperty (display->display, id, display->mwmHintsAtom,
1042 0L, 20L, FALSE, display->mwmHintsAtom,
1043 &actual, &format, &n, &left, &data);
1044
1045 if (result == Success && data)
1046 {
1047 MwmHints *mwmHints = (MwmHints *) data;
1048
1049 if (n >= PropMotifWmHintElements)
1050 {
1051 if (mwmHints->flags & MwmHintsDecorations)
1052 *decor = mwmHints->decorations;
1053
1054 if (mwmHints->flags & MwmHintsFunctions)
1055 *func = mwmHints->functions;
1056 }
1057
1058 XFree (data);
1059 }
1060 }
1061
1062 unsigned int
getProtocols(CompDisplay * display,Window id)1063 getProtocols (CompDisplay *display,
1064 Window id)
1065 {
1066 Atom *protocol;
1067 int count;
1068 unsigned int protocols = 0;
1069
1070 if (XGetWMProtocols (display->display, id, &protocol, &count))
1071 {
1072 int i;
1073
1074 for (i = 0; i < count; i++)
1075 {
1076 if (protocol[i] == display->wmDeleteWindowAtom)
1077 protocols |= CompWindowProtocolDeleteMask;
1078 else if (protocol[i] == display->wmTakeFocusAtom)
1079 protocols |= CompWindowProtocolTakeFocusMask;
1080 else if (protocol[i] == display->wmPingAtom)
1081 protocols |= CompWindowProtocolPingMask;
1082 else if (protocol[i] == display->wmSyncRequestAtom)
1083 protocols |= CompWindowProtocolSyncRequestMask;
1084 }
1085
1086 XFree (protocol);
1087 }
1088
1089 return protocols;
1090 }
1091
1092 unsigned int
getWindowProp(CompDisplay * display,Window id,Atom property,unsigned int defaultValue)1093 getWindowProp (CompDisplay *display,
1094 Window id,
1095 Atom property,
1096 unsigned int defaultValue)
1097 {
1098 Atom actual;
1099 int result, format;
1100 unsigned long n, left;
1101 unsigned char *data;
1102 unsigned int retval = defaultValue;
1103
1104 result = XGetWindowProperty (display->display, id, property,
1105 0L, 1L, FALSE, XA_CARDINAL, &actual, &format,
1106 &n, &left, &data);
1107
1108 if (result == Success && data)
1109 {
1110 if (n)
1111 {
1112 unsigned long value;
1113
1114 memcpy (&value, data, sizeof (unsigned long));
1115 retval = (unsigned int) value;
1116 }
1117
1118 XFree (data);
1119 }
1120
1121 return retval;
1122 }
1123
1124 void
setWindowProp(CompDisplay * display,Window id,Atom property,unsigned int value)1125 setWindowProp (CompDisplay *display,
1126 Window id,
1127 Atom property,
1128 unsigned int value)
1129 {
1130 unsigned long data = value;
1131
1132 XChangeProperty (display->display, id, property,
1133 XA_CARDINAL, 32, PropModeReplace,
1134 (unsigned char *) &data, 1);
1135 }
1136
1137 Bool
readWindowProp32(CompDisplay * display,Window id,Atom property,unsigned short * returnValue)1138 readWindowProp32 (CompDisplay *display,
1139 Window id,
1140 Atom property,
1141 unsigned short *returnValue)
1142 {
1143 Atom actual;
1144 int result, format;
1145 unsigned long n, left;
1146 unsigned char *data;
1147 Bool retval = FALSE;
1148
1149 result = XGetWindowProperty (display->display, id, property,
1150 0L, 1L, FALSE, XA_CARDINAL, &actual, &format,
1151 &n, &left, &data);
1152
1153 if (result == Success && data)
1154 {
1155 if (n)
1156 {
1157 CARD32 value;
1158 memcpy (&value, data, sizeof (CARD32));
1159
1160 retval = TRUE;
1161 *returnValue = value >> 16;
1162 }
1163
1164 XFree (data);
1165 }
1166
1167 return retval;
1168 }
1169
1170 unsigned short
getWindowProp32(CompDisplay * display,Window id,Atom property,unsigned short defaultValue)1171 getWindowProp32 (CompDisplay *display,
1172 Window id,
1173 Atom property,
1174 unsigned short defaultValue)
1175 {
1176 unsigned short result;
1177
1178 if (readWindowProp32 (display, id, property, &result))
1179 return result;
1180
1181 return defaultValue;
1182 }
1183
1184 void
setWindowProp32(CompDisplay * display,Window id,Atom property,unsigned short value)1185 setWindowProp32 (CompDisplay *display,
1186 Window id,
1187 Atom property,
1188 unsigned short value)
1189 {
1190 CARD32 value32;
1191
1192 value32 = value << 16 | value;
1193
1194 XChangeProperty (display->display, id, property,
1195 XA_CARDINAL, 32, PropModeReplace,
1196 (unsigned char *) &value32, 1);
1197 }
1198
1199 static void
updateFrameWindow(CompWindow * w)1200 updateFrameWindow (CompWindow *w)
1201 {
1202 CompDisplay *d = w->screen->display;
1203
1204 if (w->input.left || w->input.right || w->input.top || w->input.bottom)
1205 {
1206 XRectangle rects[4];
1207 int x, y, width, height;
1208 int i = 0;
1209 int bw = w->serverBorderWidth * 2;
1210
1211 x = w->serverX - w->input.left;
1212 y = w->serverY - w->input.top;
1213 width = w->serverWidth + w->input.left + w->input.right + bw;
1214 height = w->serverHeight + w->input.top + w->input.bottom + bw;
1215
1216 if (w->shaded)
1217 height = w->input.top + w->input.bottom;
1218
1219 if (!w->frame)
1220 {
1221 XSetWindowAttributes attr;
1222 XWindowChanges xwc;
1223
1224 attr.event_mask = 0;
1225 attr.override_redirect = TRUE;
1226
1227 w->frame = XCreateWindow (d->display, w->screen->root,
1228 x, y, width, height, 0,
1229 CopyFromParent,
1230 InputOnly,
1231 CopyFromParent,
1232 CWOverrideRedirect | CWEventMask, &attr);
1233
1234 XGrabButton (d->display, AnyButton, AnyModifier, w->frame, TRUE,
1235 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
1236 GrabModeSync, GrabModeSync, None, None);
1237
1238 xwc.stack_mode = Below;
1239 xwc.sibling = w->id;
1240
1241 XConfigureWindow (d->display, w->frame,
1242 CWSibling | CWStackMode, &xwc);
1243
1244 if (w->mapNum || w->shaded)
1245 XMapWindow (d->display, w->frame);
1246
1247 XChangeProperty (d->display, w->id, d->frameWindowAtom,
1248 XA_WINDOW, 32, PropModeReplace,
1249 (unsigned char *) &w->frame, 1);
1250 }
1251
1252 XMoveResizeWindow (d->display, w->frame, x, y, width, height);
1253
1254 rects[i].x = 0;
1255 rects[i].y = 0;
1256 rects[i].width = width;
1257 rects[i].height = w->input.top;
1258
1259 if (rects[i].width && rects[i].height)
1260 i++;
1261
1262 rects[i].x = 0;
1263 rects[i].y = w->input.top;
1264 rects[i].width = w->input.left;
1265 rects[i].height = height - w->input.top - w->input.bottom;
1266
1267 if (rects[i].width && rects[i].height)
1268 i++;
1269
1270 rects[i].x = width - w->input.right;
1271 rects[i].y = w->input.top;
1272 rects[i].width = w->input.right;
1273 rects[i].height = height - w->input.top - w->input.bottom;
1274
1275 if (rects[i].width && rects[i].height)
1276 i++;
1277
1278 rects[i].x = 0;
1279 rects[i].y = height - w->input.bottom;
1280 rects[i].width = width;
1281 rects[i].height = w->input.bottom;
1282
1283 if (rects[i].width && rects[i].height)
1284 i++;
1285
1286 XShapeCombineRectangles (d->display,
1287 w->frame,
1288 ShapeInput,
1289 0,
1290 0,
1291 rects,
1292 i,
1293 ShapeSet,
1294 YXBanded);
1295 }
1296 else
1297 {
1298 if (w->frame)
1299 {
1300 XDeleteProperty (d->display, w->id, d->frameWindowAtom);
1301 XDestroyWindow (d->display, w->frame);
1302 w->frame = None;
1303 }
1304 }
1305
1306 recalcWindowActions (w);
1307 }
1308
1309 void
setWindowFrameExtents(CompWindow * w,CompWindowExtents * input)1310 setWindowFrameExtents (CompWindow *w,
1311 CompWindowExtents *input)
1312 {
1313 if (input->left != w->input.left ||
1314 input->right != w->input.right ||
1315 input->top != w->input.top ||
1316 input->bottom != w->input.bottom)
1317 {
1318 unsigned long data[4];
1319
1320 w->input = *input;
1321
1322 data[0] = input->left;
1323 data[1] = input->right;
1324 data[2] = input->top;
1325 data[3] = input->bottom;
1326
1327 updateWindowSize (w);
1328 updateFrameWindow (w);
1329 recalcWindowActions (w);
1330
1331 XChangeProperty (w->screen->display->display, w->id,
1332 w->screen->display->frameExtentsAtom,
1333 XA_CARDINAL, 32, PropModeReplace,
1334 (unsigned char *) data, 4);
1335 }
1336 }
1337
1338 void
updateWindowOutputExtents(CompWindow * w)1339 updateWindowOutputExtents (CompWindow *w)
1340 {
1341 CompWindowExtents output;
1342
1343 (*w->screen->getOutputExtentsForWindow) (w, &output);
1344
1345 if (output.left != w->output.left ||
1346 output.right != w->output.right ||
1347 output.top != w->output.top ||
1348 output.bottom != w->output.bottom)
1349 {
1350 w->output = output;
1351
1352 (*w->screen->windowResizeNotify) (w, 0, 0, 0, 0);
1353 }
1354 }
1355
1356 void
setWindowFullscreenMonitors(CompWindow * w,CompFullscreenMonitorSet * monitors)1357 setWindowFullscreenMonitors (CompWindow *w,
1358 CompFullscreenMonitorSet *monitors)
1359 {
1360 CompScreen *s = w->screen;
1361 CompDisplay *d = s->display;
1362 Bool hadFsMonitors = w->fullscreenMonitorsSet;
1363
1364 w->fullscreenMonitorsSet = FALSE;
1365
1366 if (monitors &&
1367 monitors->left < s->nOutputDev &&
1368 monitors->right < s->nOutputDev &&
1369 monitors->top < s->nOutputDev &&
1370 monitors->bottom < s->nOutputDev)
1371 {
1372 BOX fsBox;
1373
1374 fsBox.x1 = s->outputDev[monitors->left].region.extents.x1;
1375 fsBox.y1 = s->outputDev[monitors->top].region.extents.y1;
1376 fsBox.x2 = s->outputDev[monitors->right].region.extents.x2;
1377 fsBox.y2 = s->outputDev[monitors->bottom].region.extents.y2;
1378
1379 if (fsBox.x1 < fsBox.x2 && fsBox.y1 < fsBox.y2)
1380 {
1381 w->fullscreenMonitorsSet = TRUE;
1382
1383 w->fullscreenMonitorRect.x = fsBox.x1;
1384 w->fullscreenMonitorRect.y = fsBox.y1;
1385 w->fullscreenMonitorRect.width = fsBox.x2 - fsBox.x1;
1386 w->fullscreenMonitorRect.height = fsBox.y2 - fsBox.y1;
1387 }
1388 }
1389
1390 if (w->fullscreenMonitorsSet)
1391 {
1392 long data[4];
1393
1394 data[0] = monitors->top;
1395 data[1] = monitors->bottom;
1396 data[2] = monitors->left;
1397 data[3] = monitors->right;
1398
1399 XChangeProperty (d->display, w->id, d->wmFullscreenMonitorsAtom,
1400 XA_CARDINAL, 32, PropModeReplace,
1401 (unsigned char *) data, 4);
1402 }
1403 else if (hadFsMonitors)
1404 {
1405 XDeleteProperty (d->display, w->id, d->wmFullscreenMonitorsAtom);
1406 }
1407
1408 if (w->state & CompWindowStateFullscreenMask)
1409 if (w->fullscreenMonitorsSet || hadFsMonitors)
1410 updateWindowAttributes (w, CompStackingUpdateModeNone);
1411 }
1412
1413 static void
setWindowMatrix(CompWindow * w)1414 setWindowMatrix (CompWindow *w)
1415 {
1416 w->matrix = w->texture->matrix;
1417 w->matrix.x0 -= (w->attrib.x * w->matrix.xx);
1418 w->matrix.y0 -= (w->attrib.y * w->matrix.yy);
1419 }
1420
1421 Bool
bindWindow(CompWindow * w)1422 bindWindow (CompWindow *w)
1423 {
1424 redirectWindow (w);
1425
1426 if (!w->pixmap)
1427 {
1428 XWindowAttributes attr;
1429 Display *dpy = w->screen->display->display;
1430
1431 /* don't try to bind window again if it failed previously */
1432 if (w->bindFailed)
1433 return FALSE;
1434
1435 /* We have to grab the server here to make sure that window
1436 is mapped when getting the window pixmap */
1437 XGrabServer (dpy);
1438
1439 if (!XGetWindowAttributes (dpy, w->id, &attr) ||
1440 attr.map_state != IsViewable)
1441 {
1442 XUngrabServer (dpy);
1443 finiTexture (w->screen, w->texture);
1444 w->bindFailed = TRUE;
1445 return FALSE;
1446 }
1447
1448 w->pixmap = XCompositeNameWindowPixmap (dpy, w->id);
1449 w->width = attr.width + attr.border_width * 2;
1450 w->height = attr.height + attr.border_width * 2;
1451
1452 XUngrabServer (dpy);
1453 }
1454
1455 if (!bindPixmapToTexture (w->screen, w->texture, w->pixmap,
1456 w->width, w->height,
1457 w->attrib.depth))
1458 {
1459 compLogMessage ("core", CompLogLevelInfo,
1460 "Couldn't bind redirected window 0x%x to "
1461 "texture\n", (int) w->id);
1462 }
1463
1464 setWindowMatrix (w);
1465
1466 return TRUE;
1467 }
1468
1469 void
releaseWindow(CompWindow * w)1470 releaseWindow (CompWindow *w)
1471 {
1472 if (w->pixmap)
1473 {
1474 CompTexture *texture;
1475
1476 texture = createTexture (w->screen);
1477 if (texture)
1478 {
1479 destroyTexture (w->screen, w->texture);
1480
1481 w->texture = texture;
1482 }
1483
1484 XFreePixmap (w->screen->display->display, w->pixmap);
1485
1486 w->pixmap = None;
1487 }
1488 }
1489
1490 static void
freeWindow(CompWindow * w)1491 freeWindow (CompWindow *w)
1492 {
1493 releaseWindow (w);
1494
1495 if (w->syncAlarm)
1496 XSyncDestroyAlarm (w->screen->display->display, w->syncAlarm);
1497
1498 if (w->syncWaitHandle)
1499 compRemoveTimeout (w->syncWaitHandle);
1500
1501 destroyTexture (w->screen, w->texture);
1502
1503 if (w->frame)
1504 XDestroyWindow (w->screen->display->display, w->frame);
1505
1506 if (w->clip)
1507 XDestroyRegion (w->clip);
1508
1509 if (w->region)
1510 XDestroyRegion (w->region);
1511
1512 if (w->hints)
1513 XFree (w->hints);
1514
1515 if (w->base.privates)
1516 free (w->base.privates);
1517
1518 if (w->sizeDamage)
1519 free (w->damageRects);
1520
1521 if (w->vertices)
1522 free (w->vertices);
1523
1524 if (w->indices)
1525 free (w->indices);
1526
1527 if (w->struts)
1528 free (w->struts);
1529
1530 if (w->icon)
1531 freeWindowIcons (w);
1532
1533 if (w->startupId)
1534 free (w->startupId);
1535
1536 if (w->resName)
1537 free (w->resName);
1538
1539 if (w->resClass)
1540 free (w->resClass);
1541
1542 free (w);
1543 }
1544
1545 void
damageTransformedWindowRect(CompWindow * w,float xScale,float yScale,float xTranslate,float yTranslate,BoxPtr rect)1546 damageTransformedWindowRect (CompWindow *w,
1547 float xScale,
1548 float yScale,
1549 float xTranslate,
1550 float yTranslate,
1551 BoxPtr rect)
1552 {
1553 REGION reg;
1554
1555 reg.rects = ®.extents;
1556 reg.numRects = 1;
1557
1558 reg.extents.x1 = (rect->x1 * xScale) - 1;
1559 reg.extents.y1 = (rect->y1 * yScale) - 1;
1560 reg.extents.x2 = (rect->x2 * xScale + 0.5f) + 1;
1561 reg.extents.y2 = (rect->y2 * yScale + 0.5f) + 1;
1562
1563 reg.extents.x1 += xTranslate;
1564 reg.extents.y1 += yTranslate;
1565 reg.extents.x2 += (xTranslate + 0.5f);
1566 reg.extents.y2 += (yTranslate + 0.5f);
1567
1568 if (reg.extents.x2 > reg.extents.x1 && reg.extents.y2 > reg.extents.y1)
1569 {
1570 reg.extents.x1 += w->attrib.x + w->attrib.border_width;
1571 reg.extents.y1 += w->attrib.y + w->attrib.border_width;
1572 reg.extents.x2 += w->attrib.x + w->attrib.border_width;
1573 reg.extents.y2 += w->attrib.y + w->attrib.border_width;
1574
1575 damageScreenRegion (w->screen, ®);
1576 }
1577 }
1578
1579 void
damageWindowOutputExtents(CompWindow * w)1580 damageWindowOutputExtents (CompWindow *w)
1581 {
1582 if (w->screen->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK)
1583 return;
1584
1585 if (w->shaded || (w->attrib.map_state == IsViewable && w->damaged))
1586 {
1587 BoxRec box;
1588
1589 /* top */
1590 box.x1 = -w->output.left - w->attrib.border_width;
1591 box.y1 = -w->output.top - w->attrib.border_width;
1592 box.x2 = w->width + w->output.right - w->attrib.border_width;
1593 box.y2 = -w->attrib.border_width;
1594
1595 if (box.x1 < box.x2 && box.y1 < box.y2)
1596 addWindowDamageRect (w, &box);
1597
1598 /* bottom */
1599 box.y1 = w->height - w->attrib.border_width;
1600 box.y2 = box.y1 + w->output.bottom - w->attrib.border_width;
1601
1602 if (box.x1 < box.x2 && box.y1 < box.y2)
1603 addWindowDamageRect (w, &box);
1604
1605 /* left */
1606 box.x1 = -w->output.left - w->attrib.border_width;
1607 box.y1 = -w->attrib.border_width;
1608 box.x2 = -w->attrib.border_width;
1609 box.y2 = w->height - w->attrib.border_width;
1610
1611 if (box.x1 < box.x2 && box.y1 < box.y2)
1612 addWindowDamageRect (w, &box);
1613
1614 /* right */
1615 box.x1 = w->width - w->attrib.border_width;
1616 box.x2 = box.x1 + w->output.right - w->attrib.border_width;
1617
1618 if (box.x1 < box.x2 && box.y1 < box.y2)
1619 addWindowDamageRect (w, &box);
1620 }
1621 }
1622
1623 Bool
damageWindowRect(CompWindow * w,Bool initial,BoxPtr rect)1624 damageWindowRect (CompWindow *w,
1625 Bool initial,
1626 BoxPtr rect)
1627 {
1628 return FALSE;
1629 }
1630
1631 void
addWindowDamageRect(CompWindow * w,BoxPtr rect)1632 addWindowDamageRect (CompWindow *w,
1633 BoxPtr rect)
1634 {
1635 REGION region;
1636
1637 if (w->screen->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK)
1638 return;
1639
1640 region.extents = *rect;
1641
1642 if (!(*w->screen->damageWindowRect) (w, FALSE, ®ion.extents))
1643 {
1644 region.extents.x1 += w->attrib.x + w->attrib.border_width;
1645 region.extents.y1 += w->attrib.y + w->attrib.border_width;
1646 region.extents.x2 += w->attrib.x + w->attrib.border_width;
1647 region.extents.y2 += w->attrib.y + w->attrib.border_width;
1648
1649 region.rects = ®ion.extents;
1650 region.numRects = region.size = 1;
1651
1652 damageScreenRegion (w->screen, ®ion);
1653 }
1654 }
1655
1656 void
getOutputExtentsForWindow(CompWindow * w,CompWindowExtents * output)1657 getOutputExtentsForWindow (CompWindow *w,
1658 CompWindowExtents *output)
1659 {
1660 output->left = 0;
1661 output->right = 0;
1662 output->top = 0;
1663 output->bottom = 0;
1664 }
1665
1666 void
addWindowDamage(CompWindow * w)1667 addWindowDamage (CompWindow *w)
1668 {
1669 if (w->screen->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK)
1670 return;
1671
1672 if (w->shaded || (w->attrib.map_state == IsViewable && w->damaged))
1673 {
1674 BoxRec box;
1675
1676 box.x1 = -w->output.left - w->attrib.border_width;
1677 box.y1 = -w->output.top - w->attrib.border_width;
1678 box.x2 = w->width + w->output.right;
1679 box.y2 = w->height + w->output.bottom;
1680
1681 addWindowDamageRect (w, &box);
1682 }
1683 }
1684
1685 void
updateWindowRegion(CompWindow * w)1686 updateWindowRegion (CompWindow *w)
1687 {
1688 REGION rect;
1689 XRectangle r, *rects, *shapeRects = 0;
1690 int i, n = 0;
1691
1692 EMPTY_REGION (w->region);
1693
1694 if (w->screen->display->shapeExtension)
1695 {
1696 int order;
1697
1698 shapeRects = XShapeGetRectangles (w->screen->display->display, w->id,
1699 ShapeBounding, &n, &order);
1700 }
1701
1702 if (n < 1)
1703 {
1704 r.x = -w->attrib.border_width;
1705 r.y = -w->attrib.border_width;
1706 r.width = w->attrib.width + w->attrib.border_width;
1707 r.height = w->attrib.height + w->attrib.border_width;
1708
1709 rects = &r;
1710 n = 1;
1711 }
1712 else
1713 {
1714 rects = shapeRects;
1715 }
1716
1717 rect.rects = &rect.extents;
1718 rect.numRects = rect.size = 1;
1719
1720 for (i = 0; i < n; i++)
1721 {
1722 rect.extents.x1 = rects[i].x + w->attrib.border_width;
1723 rect.extents.y1 = rects[i].y + w->attrib.border_width;
1724 rect.extents.x2 = rect.extents.x1 + rects[i].width +
1725 w->attrib.border_width;
1726 rect.extents.y2 = rect.extents.y1 + rects[i].height +
1727 w->attrib.border_width;
1728
1729 if (rect.extents.x1 < 0)
1730 rect.extents.x1 = 0;
1731 if (rect.extents.y1 < 0)
1732 rect.extents.y1 = 0;
1733 if (rect.extents.x2 > w->width)
1734 rect.extents.x2 = w->width;
1735 if (rect.extents.y2 > w->height)
1736 rect.extents.y2 = w->height;
1737
1738 if (rect.extents.y1 < rect.extents.y2 &&
1739 rect.extents.x1 < rect.extents.x2)
1740 {
1741 rect.extents.x1 += w->attrib.x;
1742 rect.extents.y1 += w->attrib.y;
1743 rect.extents.x2 += w->attrib.x;
1744 rect.extents.y2 += w->attrib.y;
1745
1746 XUnionRegion (&rect, w->region, w->region);
1747 }
1748 }
1749
1750 if (shapeRects)
1751 XFree (shapeRects);
1752 }
1753
1754 Bool
updateWindowStruts(CompWindow * w)1755 updateWindowStruts (CompWindow *w)
1756 {
1757 Atom actual;
1758 int result, format;
1759 unsigned long n, left;
1760 unsigned char *data;
1761 Bool hasOld, hasNew;
1762 CompStruts old, new;
1763
1764 if (w->struts)
1765 {
1766 hasOld = TRUE;
1767
1768 old.left = w->struts->left;
1769 old.right = w->struts->right;
1770 old.top = w->struts->top;
1771 old.bottom = w->struts->bottom;
1772 }
1773 else
1774 {
1775 hasOld = FALSE;
1776 }
1777
1778 hasNew = FALSE;
1779
1780 new.left.x = 0;
1781 new.left.y = 0;
1782 new.left.width = 0;
1783 new.left.height = w->screen->height;
1784
1785 new.right.x = w->screen->width;
1786 new.right.y = 0;
1787 new.right.width = 0;
1788 new.right.height = w->screen->height;
1789
1790 new.top.x = 0;
1791 new.top.y = 0;
1792 new.top.width = w->screen->width;
1793 new.top.height = 0;
1794
1795 new.bottom.x = 0;
1796 new.bottom.y = w->screen->height;
1797 new.bottom.width = w->screen->width;
1798 new.bottom.height = 0;
1799
1800 result = XGetWindowProperty (w->screen->display->display, w->id,
1801 w->screen->display->wmStrutPartialAtom,
1802 0L, 12L, FALSE, XA_CARDINAL, &actual, &format,
1803 &n, &left, &data);
1804
1805 if (result == Success && data)
1806 {
1807 unsigned long *struts = (unsigned long *) data;
1808
1809 if (n == 12)
1810 {
1811 hasNew = TRUE;
1812
1813 new.left.y = struts[4];
1814 new.left.width = struts[0];
1815 new.left.height = struts[5] - new.left.y + 1;
1816
1817 new.right.width = struts[1];
1818 new.right.x = w->screen->width - new.right.width;
1819 new.right.y = struts[6];
1820 new.right.height = struts[7] - new.right.y + 1;
1821
1822 new.top.x = struts[8];
1823 new.top.width = struts[9] - new.top.x + 1;
1824 new.top.height = struts[2];
1825
1826 new.bottom.x = struts[10];
1827 new.bottom.width = struts[11] - new.bottom.x + 1;
1828 new.bottom.height = struts[3];
1829 new.bottom.y = w->screen->height - new.bottom.height;
1830 }
1831
1832 XFree (data);
1833 }
1834
1835 if (!hasNew)
1836 {
1837 result = XGetWindowProperty (w->screen->display->display, w->id,
1838 w->screen->display->wmStrutAtom,
1839 0L, 4L, FALSE, XA_CARDINAL,
1840 &actual, &format, &n, &left, &data);
1841
1842 if (result == Success && data)
1843 {
1844 unsigned long *struts = (unsigned long *) data;
1845
1846 if (n == 4)
1847 {
1848 hasNew = TRUE;
1849
1850 new.left.x = 0;
1851 new.left.width = struts[0];
1852
1853 new.right.width = struts[1];
1854 new.right.x = w->screen->width - new.right.width;
1855
1856 new.top.y = 0;
1857 new.top.height = struts[2];
1858
1859 new.bottom.height = struts[3];
1860 new.bottom.y = w->screen->height - new.bottom.height;
1861 }
1862
1863 XFree (data);
1864 }
1865 }
1866
1867 if (hasNew)
1868 {
1869 int strutX1, strutY1, strutX2, strutY2;
1870 int x1, y1, x2, y2;
1871 int i;
1872
1873 /* applications expect us to clip struts to xinerama edges */
1874 for (i = 0; i < w->screen->display->nScreenInfo; i++)
1875 {
1876 x1 = w->screen->display->screenInfo[i].x_org;
1877 y1 = w->screen->display->screenInfo[i].y_org;
1878 x2 = x1 + w->screen->display->screenInfo[i].width;
1879 y2 = y1 + w->screen->display->screenInfo[i].height;
1880
1881 strutX1 = new.left.x;
1882 strutX2 = strutX1 + new.left.width;
1883 strutY1 = new.left.y;
1884 strutY2 = strutY1 + new.left.height;
1885
1886 if (strutX2 > x1 && strutX2 <= x2 &&
1887 strutY1 < y2 && strutY2 > y1)
1888 {
1889 new.left.x = x1;
1890 new.left.width = strutX2 - x1;
1891 }
1892
1893 strutX1 = new.right.x;
1894 strutX2 = strutX1 + new.right.width;
1895 strutY1 = new.right.y;
1896 strutY2 = strutY1 + new.right.height;
1897
1898 if (strutX1 > x1 && strutX1 <= x2 &&
1899 strutY1 < y2 && strutY2 > y1)
1900 {
1901 new.right.x = strutX1;
1902 new.right.width = x2 - strutX1;
1903 }
1904
1905 strutX1 = new.top.x;
1906 strutX2 = strutX1 + new.top.width;
1907 strutY1 = new.top.y;
1908 strutY2 = strutY1 + new.top.height;
1909
1910 if (strutX1 < x2 && strutX2 > x1 &&
1911 strutY2 > y1 && strutY2 <= y2)
1912 {
1913 new.top.y = y1;
1914 new.top.height = strutY2 - y1;
1915 }
1916
1917 strutX1 = new.bottom.x;
1918 strutX2 = strutX1 + new.bottom.width;
1919 strutY1 = new.bottom.y;
1920 strutY2 = strutY1 + new.bottom.height;
1921
1922 if (strutX1 < x2 && strutX2 > x1 &&
1923 strutY1 > y1 && strutY1 <= y2)
1924 {
1925 new.bottom.y = strutY1;
1926 new.bottom.height = y2 - strutY1;
1927 }
1928 }
1929 }
1930
1931 if (hasOld != hasNew || (hasNew && hasOld &&
1932 memcmp (&new, &old, sizeof (CompStruts))))
1933 {
1934 if (hasNew)
1935 {
1936 if (!w->struts)
1937 {
1938 w->struts = malloc (sizeof (CompStruts));
1939 if (!w->struts)
1940 return FALSE;
1941 }
1942
1943 *w->struts = new;
1944 }
1945 else
1946 {
1947 free (w->struts);
1948 w->struts = NULL;
1949 }
1950
1951 return TRUE;
1952 }
1953
1954 return FALSE;
1955 }
1956
1957 static void
setDefaultWindowAttributes(XWindowAttributes * wa)1958 setDefaultWindowAttributes (XWindowAttributes *wa)
1959 {
1960 wa->x = 0;
1961 wa->y = 0;
1962 wa->width = 1;
1963 wa->height = 1;
1964 wa->border_width = 0;
1965 wa->depth = 0;
1966 wa->visual = NULL;
1967 wa->root = None;
1968 wa->class = InputOnly;
1969 wa->bit_gravity = NorthWestGravity;
1970 wa->win_gravity = NorthWestGravity;
1971 wa->backing_store = NotUseful;
1972 wa->backing_planes = 0;
1973 wa->backing_pixel = 0;
1974 wa->save_under = FALSE;
1975 wa->colormap = None;
1976 wa->map_installed = FALSE;
1977 wa->map_state = IsUnviewable;
1978 wa->all_event_masks = 0;
1979 wa->your_event_mask = 0;
1980 wa->do_not_propagate_mask = 0;
1981 wa->override_redirect = TRUE;
1982 wa->screen = NULL;
1983 }
1984
1985 void
addWindow(CompScreen * screen,Window id,Window aboveId)1986 addWindow (CompScreen *screen,
1987 Window id,
1988 Window aboveId)
1989 {
1990 CompWindow *w;
1991 CompPrivate *privates;
1992 CompDisplay *d = screen->display;
1993
1994 w = (CompWindow *) malloc (sizeof (CompWindow));
1995 if (!w)
1996 return;
1997
1998 w->next = NULL;
1999 w->prev = NULL;
2000
2001 w->mapNum = 0;
2002 w->activeNum = 0;
2003
2004 w->frame = None;
2005
2006 w->placed = FALSE;
2007 w->minimized = FALSE;
2008 w->inShowDesktopMode = FALSE;
2009 w->shaded = FALSE;
2010 w->hidden = FALSE;
2011 w->grabbed = FALSE;
2012
2013 w->desktop = screen->currentDesktop;
2014
2015 w->initialViewportX = screen->x;
2016 w->initialViewportY = screen->y;
2017
2018 w->initialTimestamp = 0;
2019 w->initialTimestampSet = FALSE;
2020
2021 w->pendingUnmaps = 0;
2022 w->pendingMaps = 0;
2023
2024 w->startupId = NULL;
2025 w->resName = NULL;
2026 w->resClass = NULL;
2027
2028 w->texture = createTexture (screen);
2029 if (!w->texture)
2030 {
2031 free (w);
2032 return;
2033 }
2034
2035 w->screen = screen;
2036 w->pixmap = None;
2037 w->destroyed = FALSE;
2038 w->damaged = FALSE;
2039 w->redirected = TRUE;
2040 w->managed = FALSE;
2041 w->unmanaging = FALSE;
2042 w->bindFailed = FALSE;
2043
2044 w->destroyRefCnt = 1;
2045 w->unmapRefCnt = 1;
2046
2047 w->group = NULL;
2048 w->hints = NULL;
2049
2050 w->damageRects = 0;
2051 w->sizeDamage = 0;
2052 w->nDamage = 0;
2053
2054 w->vertices = 0;
2055 w->vertexSize = 0;
2056 w->vertexStride = 0;
2057 w->indices = 0;
2058 w->indexSize = 0;
2059 w->vCount = 0;
2060 w->indexCount = 0;
2061 w->texCoordSize = 2;
2062
2063 w->drawWindowGeometry = NULL;
2064
2065 w->struts = 0;
2066
2067 w->icon = 0;
2068 w->nIcon = 0;
2069
2070 w->iconGeometry.x = 0;
2071 w->iconGeometry.y = 0;
2072 w->iconGeometry.width = 0;
2073 w->iconGeometry.height = 0;
2074 w->iconGeometrySet = FALSE;
2075
2076 w->input.left = 0;
2077 w->input.right = 0;
2078 w->input.top = 0;
2079 w->input.bottom = 0;
2080
2081 w->output.left = 0;
2082 w->output.right = 0;
2083 w->output.top = 0;
2084 w->output.bottom = 0;
2085
2086 w->paint.xScale = 1.0f;
2087 w->paint.yScale = 1.0f;
2088 w->paint.xTranslate = 0.0f;
2089 w->paint.yTranslate = 0.0f;
2090
2091 w->alive = TRUE;
2092
2093 w->mwmDecor = MwmDecorAll;
2094 w->mwmFunc = MwmFuncAll;
2095
2096 w->syncAlarm = None;
2097 w->syncCounter = 0;
2098 w->syncWaitHandle = 0;
2099
2100 w->closeRequests = 0;
2101 w->lastCloseRequestTime = 0;
2102
2103 w->fullscreenMonitorsSet = FALSE;
2104 w->overlayWindow = FALSE;
2105
2106 if (screen->windowPrivateLen)
2107 {
2108 privates = malloc (screen->windowPrivateLen * sizeof (CompPrivate));
2109 if (!privates)
2110 {
2111 destroyTexture (screen, w->texture);
2112 free (w);
2113 return;
2114 }
2115 }
2116 else
2117 privates = 0;
2118
2119 compObjectInit (&w->base, privates, COMP_OBJECT_TYPE_WINDOW);
2120
2121 w->region = XCreateRegion ();
2122 if (!w->region)
2123 {
2124 freeWindow (w);
2125 return;
2126 }
2127
2128 w->clip = XCreateRegion ();
2129 if (!w->clip)
2130 {
2131 freeWindow (w);
2132 return;
2133 }
2134
2135 /* Failure means that window has been destroyed. We still have to add the
2136 window to the window list as we might get configure requests which
2137 require us to stack other windows relative to it. Setting some default
2138 values if this is the case. */
2139 if (!XGetWindowAttributes (d->display, id, &w->attrib))
2140 setDefaultWindowAttributes (&w->attrib);
2141
2142 w->serverWidth = w->attrib.width;
2143 w->serverHeight = w->attrib.height;
2144 w->serverBorderWidth = w->attrib.border_width;
2145
2146 w->width = w->attrib.width + w->attrib.border_width * 2;
2147 w->height = w->attrib.height + w->attrib.border_width * 2;
2148
2149 w->sizeHints.flags = 0;
2150
2151 recalcNormalHints (w);
2152
2153 w->transientFor = None;
2154 w->clientLeader = None;
2155
2156 w->serverX = w->attrib.x;
2157 w->serverY = w->attrib.y;
2158
2159 w->syncWait = FALSE;
2160 w->syncX = w->attrib.x;
2161 w->syncY = w->attrib.y;
2162 w->syncWidth = w->attrib.width;
2163 w->syncHeight = w->attrib.height;
2164 w->syncBorderWidth = w->attrib.border_width;
2165
2166 w->saveMask = 0;
2167
2168 XSelectInput (d->display, id,
2169 PropertyChangeMask |
2170 EnterWindowMask |
2171 FocusChangeMask);
2172
2173 w->id = id;
2174
2175 XGrabButton (d->display, AnyButton, AnyModifier, w->id, TRUE,
2176 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
2177 GrabModeSync, GrabModeSync, None, None);
2178
2179 w->inputHint = TRUE;
2180 w->alpha = (w->attrib.depth == 32);
2181 w->wmType = 0;
2182 w->state = 0;
2183 w->actions = 0;
2184 w->protocols = 0;
2185 w->type = CompWindowTypeUnknownMask;
2186 w->lastPong = d->lastPing;
2187
2188 if (d->shapeExtension)
2189 XShapeSelectInput (d->display, id, ShapeNotifyMask);
2190
2191 insertWindowIntoScreen (screen, w, aboveId);
2192
2193 EMPTY_REGION (w->region);
2194
2195 if (w->attrib.class != InputOnly)
2196 {
2197 REGION rect;
2198
2199 rect.rects = &rect.extents;
2200 rect.numRects = rect.size = 1;
2201
2202 rect.extents.x1 = w->attrib.x;
2203 rect.extents.y1 = w->attrib.y;
2204 rect.extents.x2 = w->attrib.x + w->width;
2205 rect.extents.y2 = w->attrib.y + w->height;
2206
2207 XUnionRegion (&rect, w->region, w->region);
2208
2209 w->damage = XDamageCreate (d->display, id,
2210 XDamageReportRawRectangles);
2211
2212 /* need to check for DisplayModal state on all windows */
2213 w->state = getWindowState (d, w->id);
2214
2215 updateWindowClassHints (w);
2216 }
2217 else
2218 {
2219 w->damage = None;
2220 w->attrib.map_state = IsUnmapped;
2221 }
2222
2223 w->invisible = TRUE;
2224
2225 w->wmType = getWindowType (d, w->id);
2226 w->protocols = getProtocols (d, w->id);
2227
2228 if (!w->attrib.override_redirect)
2229 {
2230 updateNormalHints (w);
2231 updateWindowStruts (w);
2232 updateWmHints (w);
2233 updateTransientHint (w);
2234
2235 w->clientLeader = getClientLeader (w);
2236 if (!w->clientLeader)
2237 w->startupId = getStartupId (w);
2238
2239 recalcWindowType (w);
2240
2241 getMwmHints (d, w->id, &w->mwmFunc, &w->mwmDecor);
2242
2243 if (!(w->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask)))
2244 {
2245 w->desktop = getWindowProp (d, w->id, d->winDesktopAtom,
2246 w->desktop);
2247 if (w->desktop != 0xffffffff)
2248 {
2249 if (w->desktop >= screen->nDesktop)
2250 w->desktop = screen->currentDesktop;
2251 }
2252 }
2253 }
2254 else
2255 {
2256 recalcWindowType (w);
2257 }
2258
2259 if (w->type & CompWindowTypeDesktopMask)
2260 w->paint.opacity = OPAQUE;
2261 else
2262 w->paint.opacity = getWindowProp32 (d, w->id,
2263 d->winOpacityAtom, OPAQUE);
2264
2265 w->paint.brightness = getWindowProp32 (d, w->id,
2266 d->winBrightnessAtom, BRIGHT);
2267
2268 if (!screen->canDoSaturated)
2269 w->paint.saturation = COLOR;
2270 else
2271 w->paint.saturation = getWindowProp32 (d, w->id,
2272 d->winSaturationAtom, COLOR);
2273
2274 w->lastPaint = w->paint;
2275
2276 if (w->attrib.map_state == IsViewable)
2277 {
2278 w->placed = TRUE;
2279
2280 if (!w->attrib.override_redirect)
2281 {
2282 w->managed = TRUE;
2283
2284 if (getWmState (d, w->id) == IconicState)
2285 {
2286 if (w->state & CompWindowStateShadedMask)
2287 w->shaded = TRUE;
2288 else
2289 w->minimized = TRUE;
2290 }
2291 else
2292 {
2293 if (w->wmType & (CompWindowTypeDockMask |
2294 CompWindowTypeDesktopMask))
2295 {
2296 setDesktopForWindow (w, 0xffffffff);
2297 }
2298 else
2299 {
2300 if (w->desktop != 0xffffffff)
2301 w->desktop = screen->currentDesktop;
2302
2303 setWindowProp (d, w->id, d->winDesktopAtom, w->desktop);
2304 }
2305 }
2306 }
2307
2308 w->attrib.map_state = IsUnmapped;
2309 w->pendingMaps++;
2310
2311 mapWindow (w);
2312
2313 updateWindowAttributes (w, CompStackingUpdateModeInitialMap);
2314
2315 if (w->minimized || w->inShowDesktopMode || w->hidden || w->shaded)
2316 {
2317 w->state |= CompWindowStateHiddenMask;
2318
2319 w->pendingUnmaps++;
2320
2321 XUnmapWindow (d->display, w->id);
2322
2323 setWindowState (d, w->state, w->id);
2324 }
2325 }
2326 else if (!w->attrib.override_redirect)
2327 {
2328 if (getWmState (d, w->id) == IconicState)
2329 {
2330 w->managed = TRUE;
2331 w->placed = TRUE;
2332
2333 if (w->state & CompWindowStateHiddenMask)
2334 {
2335 if (w->state & CompWindowStateShadedMask)
2336 w->shaded = TRUE;
2337 else
2338 w->minimized = TRUE;
2339 }
2340 }
2341 }
2342
2343 /* TODO: bailout properly when objectInitPlugins fails */
2344 assert (objectInitPlugins (&w->base));
2345
2346 (*core.objectAdd) (&screen->base, &w->base);
2347
2348 recalcWindowActions (w);
2349 updateIconGeometry (w);
2350
2351 if (w->shaded)
2352 resizeWindow (w,
2353 w->attrib.x, w->attrib.y,
2354 w->attrib.width, ++w->attrib.height - 1,
2355 w->attrib.border_width);
2356 }
2357
2358 void
removeWindow(CompWindow * w)2359 removeWindow (CompWindow *w)
2360 {
2361 unhookWindowFromScreen (w->screen, w);
2362
2363 if (!w->destroyed)
2364 {
2365 CompDisplay *d = w->screen->display;
2366
2367 /* restore saved geometry and map if hidden */
2368 if (!w->attrib.override_redirect)
2369 {
2370 if (w->saveMask)
2371 XConfigureWindow (d->display, w->id, w->saveMask, &w->saveWc);
2372
2373 if (!w->hidden)
2374 {
2375 if (w->state & CompWindowStateHiddenMask)
2376 XMapWindow (d->display, w->id);
2377 }
2378 }
2379
2380 if (w->damage)
2381 XDamageDestroy (d->display, w->damage);
2382
2383 if (d->shapeExtension)
2384 XShapeSelectInput (d->display, w->id, NoEventMask);
2385
2386 XSelectInput (d->display, w->id, NoEventMask);
2387
2388 XUngrabButton (d->display, AnyButton, AnyModifier, w->id);
2389 }
2390
2391 if (w->attrib.map_state == IsViewable && w->damaged)
2392 {
2393 if (w->type == CompWindowTypeDesktopMask)
2394 w->screen->desktopWindowCount--;
2395
2396 if (w->destroyed && w->struts)
2397 updateWorkareaForScreen (w->screen);
2398 }
2399
2400 if (w->destroyed)
2401 updateClientListForScreen (w->screen);
2402
2403 if (!w->redirected)
2404 {
2405 w->screen->overlayWindowCount--;
2406
2407 if (w->screen->overlayWindowCount < 1)
2408 showOutputWindow (w->screen);
2409 }
2410
2411 (*core.objectRemove) (&w->screen->base, &w->base);
2412
2413 objectFiniPlugins (&w->base);
2414
2415 freeWindow (w);
2416 }
2417
2418 void
destroyWindow(CompWindow * w)2419 destroyWindow (CompWindow *w)
2420 {
2421 w->id = 1;
2422 w->mapNum = 0;
2423
2424 w->destroyRefCnt--;
2425 if (w->destroyRefCnt)
2426 return;
2427
2428 if (!w->destroyed)
2429 {
2430 w->destroyed = TRUE;
2431 w->screen->pendingDestroys++;
2432 }
2433 }
2434
2435 void
sendConfigureNotify(CompWindow * w)2436 sendConfigureNotify (CompWindow *w)
2437 {
2438 XConfigureEvent xev;
2439
2440 xev.type = ConfigureNotify;
2441 xev.event = w->id;
2442 xev.window = w->id;
2443
2444 /* normally we should never send configure notify events to override
2445 redirect windows but if they support the _NET_WM_SYNC_REQUEST
2446 protocol we need to do this when the window is mapped. however the
2447 only way we can make sure that the attributes we send are correct
2448 and is to grab the server. */
2449 if (w->attrib.override_redirect)
2450 {
2451 XWindowAttributes attrib;
2452
2453 XGrabServer (w->screen->display->display);
2454
2455 if (XGetWindowAttributes (w->screen->display->display, w->id, &attrib))
2456 {
2457 xev.x = attrib.x;
2458 xev.y = attrib.y;
2459 xev.width = attrib.width;
2460 xev.height = attrib.height;
2461 xev.border_width = attrib.border_width;
2462
2463 xev.above = (w->prev) ? w->prev->id : None;
2464 xev.override_redirect = TRUE;
2465
2466 XSendEvent (w->screen->display->display, w->id, FALSE,
2467 StructureNotifyMask, (XEvent *) &xev);
2468 }
2469
2470 XUngrabServer (w->screen->display->display);
2471 }
2472 else
2473 {
2474 xev.x = w->serverX;
2475 xev.y = w->serverY;
2476 xev.width = w->serverWidth;
2477 xev.height = w->serverHeight;
2478 xev.border_width = w->serverBorderWidth;
2479
2480 xev.above = (w->prev) ? w->prev->id : None;
2481 xev.override_redirect = w->attrib.override_redirect;
2482
2483 XSendEvent (w->screen->display->display, w->id, FALSE,
2484 StructureNotifyMask, (XEvent *) &xev);
2485 }
2486 }
2487
2488 void
mapWindow(CompWindow * w)2489 mapWindow (CompWindow *w)
2490 {
2491 if (w->attrib.map_state == IsViewable)
2492 return;
2493
2494 if (w->pendingMaps > 0)
2495 w->pendingMaps--;
2496
2497 w->mapNum = w->screen->mapNum++;
2498
2499 if (w->struts)
2500 updateWorkareaForScreen (w->screen);
2501
2502 if (w->attrib.class == InputOnly)
2503 return;
2504
2505 w->unmapRefCnt = 1;
2506
2507 w->attrib.map_state = IsViewable;
2508
2509 if (!w->attrib.override_redirect)
2510 setWmState (w->screen->display, NormalState, w->id);
2511
2512 w->invisible = TRUE;
2513 w->damaged = FALSE;
2514 w->alive = TRUE;
2515 w->bindFailed = FALSE;
2516
2517 w->lastPong = w->screen->display->lastPing;
2518
2519 updateWindowRegion (w);
2520 updateWindowSize (w);
2521
2522 if (w->frame)
2523 XMapWindow (w->screen->display->display, w->frame);
2524
2525 updateClientListForScreen (w->screen);
2526
2527 if (w->type & CompWindowTypeDesktopMask)
2528 w->screen->desktopWindowCount++;
2529
2530 if (w->protocols & CompWindowProtocolSyncRequestMask)
2531 {
2532 sendSyncRequest (w);
2533 sendConfigureNotify (w);
2534 }
2535
2536 if (!w->attrib.override_redirect)
2537 {
2538 /* been shaded */
2539 if (!w->height)
2540 resizeWindow (w,
2541 w->attrib.x, w->attrib.y,
2542 w->attrib.width, ++w->attrib.height - 1,
2543 w->attrib.border_width);
2544 }
2545 }
2546
2547 void
unmapWindow(CompWindow * w)2548 unmapWindow (CompWindow *w)
2549 {
2550 if (w->mapNum)
2551 {
2552 if (w->frame && !w->shaded)
2553 XUnmapWindow (w->screen->display->display, w->frame);
2554
2555 w->mapNum = 0;
2556 }
2557
2558 w->unmapRefCnt--;
2559 if (w->unmapRefCnt > 0)
2560 return;
2561
2562 if (w->unmanaging)
2563 {
2564 XWindowChanges xwc;
2565 unsigned int xwcm;
2566 int gravity = w->sizeHints.win_gravity;
2567
2568 /* revert gravity adjustment made at MapRequest time */
2569 xwc.x = w->serverX;
2570 xwc.y = w->serverY;
2571 xwc.width = 0;
2572 xwc.height = 0;
2573
2574 xwcm = adjustConfigureRequestForGravity (w, &xwc,
2575 CWX | CWY,
2576 gravity, -1);
2577
2578 if (xwcm)
2579 configureXWindow (w, xwcm, &xwc);
2580
2581 w->unmanaging = FALSE;
2582 }
2583
2584 if (w->struts)
2585 updateWorkareaForScreen (w->screen);
2586
2587 if (w->attrib.map_state != IsViewable)
2588 return;
2589
2590 if (w->type == CompWindowTypeDesktopMask)
2591 w->screen->desktopWindowCount--;
2592
2593 addWindowDamage (w);
2594
2595 w->attrib.map_state = IsUnmapped;
2596
2597 w->invisible = TRUE;
2598
2599 releaseWindow (w);
2600
2601 if (w->shaded && w->height)
2602 resizeWindow (w,
2603 w->attrib.x, w->attrib.y,
2604 w->attrib.width, ++w->attrib.height - 1,
2605 w->attrib.border_width);
2606
2607 updateClientListForScreen (w->screen);
2608
2609 if (!w->redirected)
2610 redirectWindow (w);
2611 }
2612
2613 static int
restackWindow(CompWindow * w,Window aboveId)2614 restackWindow (CompWindow *w,
2615 Window aboveId)
2616 {
2617 if (w->prev)
2618 {
2619 if (aboveId && aboveId == w->prev->id)
2620 return 0;
2621 }
2622 else if (aboveId == None && !w->next)
2623 return 0;
2624
2625 unhookWindowFromScreen (w->screen, w);
2626 insertWindowIntoScreen (w->screen, w, aboveId);
2627
2628 updateClientListForScreen (w->screen);
2629
2630 return 1;
2631 }
2632
2633 Bool
resizeWindow(CompWindow * w,int x,int y,int width,int height,int borderWidth)2634 resizeWindow (CompWindow *w,
2635 int x,
2636 int y,
2637 int width,
2638 int height,
2639 int borderWidth)
2640 {
2641 if (w->attrib.width != width ||
2642 w->attrib.height != height ||
2643 w->attrib.border_width != borderWidth)
2644 {
2645 unsigned int pw, ph, actualWidth, actualHeight, ui;
2646 int dx, dy, dwidth, dheight;
2647 Pixmap pixmap = None;
2648 Window root;
2649 Status result;
2650 int i;
2651
2652 pw = width + borderWidth * 2;
2653 ph = height + borderWidth * 2;
2654
2655 if (w->mapNum && w->redirected)
2656 {
2657 pixmap = XCompositeNameWindowPixmap (w->screen->display->display,
2658 w->id);
2659 result = XGetGeometry (w->screen->display->display, pixmap, &root,
2660 &i, &i, &actualWidth, &actualHeight,
2661 &ui, &ui);
2662
2663 if (!result || actualWidth != pw || actualHeight != ph)
2664 {
2665 XFreePixmap (w->screen->display->display, pixmap);
2666
2667 return FALSE;
2668 }
2669 }
2670 else if (w->shaded)
2671 {
2672 ph = 0;
2673 }
2674
2675 addWindowDamage (w);
2676
2677 dx = x - w->attrib.x;
2678 dy = y - w->attrib.y;
2679 dwidth = width - w->attrib.width;
2680 dheight = height - w->attrib.height;
2681
2682 w->attrib.x = x;
2683 w->attrib.y = y;
2684 w->attrib.width = width;
2685 w->attrib.height = height;
2686 w->attrib.border_width = borderWidth;
2687
2688 if (!w->mapNum && w->unmapRefCnt > 0 &&
2689 w->attrib.map_state == IsViewable)
2690 {
2691 /* keep old pixmap for windows that are unmapped on the client side,
2692 * but not yet on our side as it's pretty likely that plugins are
2693 * currently using it for animations
2694 */
2695 }
2696 else
2697 {
2698 w->width = pw;
2699 w->height = ph;
2700
2701 releaseWindow (w);
2702
2703 w->pixmap = pixmap;
2704 }
2705
2706 if (w->mapNum)
2707 updateWindowRegion (w);
2708
2709 (*w->screen->windowResizeNotify) (w, dx, dy, dwidth, dheight);
2710
2711 addWindowDamage (w);
2712
2713 w->invisible = WINDOW_INVISIBLE (w);
2714
2715 updateFrameWindow (w);
2716 }
2717 else if (w->attrib.x != x || w->attrib.y != y)
2718 {
2719 int dx, dy;
2720
2721 dx = x - w->attrib.x;
2722 dy = y - w->attrib.y;
2723
2724 moveWindow (w, dx, dy, TRUE, TRUE);
2725
2726 if (w->frame)
2727 XMoveWindow (w->screen->display->display, w->frame,
2728 w->attrib.x - w->input.left,
2729 w->attrib.y - w->input.top);
2730 }
2731
2732 return TRUE;
2733 }
2734
2735 static void
syncValueIncrement(XSyncValue * value)2736 syncValueIncrement (XSyncValue *value)
2737 {
2738 XSyncValue one;
2739 int overflow;
2740
2741 XSyncIntToValue (&one, 1);
2742 XSyncValueAdd (value, *value, one, &overflow);
2743 }
2744
2745 static Bool
initializeSyncCounter(CompWindow * w)2746 initializeSyncCounter (CompWindow *w)
2747 {
2748 XSyncAlarmAttributes values;
2749 Atom actual;
2750 int result, format;
2751 unsigned long n, left;
2752 unsigned char *data;
2753
2754 if (w->syncCounter)
2755 return w->syncAlarm != None;
2756
2757 if (!(w->protocols & CompWindowProtocolSyncRequestMask))
2758 return FALSE;
2759
2760 result = XGetWindowProperty (w->screen->display->display, w->id,
2761 w->screen->display->wmSyncRequestCounterAtom,
2762 0L, 1L, FALSE, XA_CARDINAL, &actual, &format,
2763 &n, &left, &data);
2764
2765 if (result == Success && n && data)
2766 {
2767 unsigned long *counter = (unsigned long *) data;
2768
2769 w->syncCounter = *counter;
2770
2771 XFree (data);
2772
2773 XSyncIntsToValue (&w->syncValue, (unsigned int) rand (), 0);
2774 XSyncSetCounter (w->screen->display->display,
2775 w->syncCounter,
2776 w->syncValue);
2777
2778 syncValueIncrement (&w->syncValue);
2779
2780 values.events = TRUE;
2781
2782 values.trigger.counter = w->syncCounter;
2783 values.trigger.wait_value = w->syncValue;
2784
2785 values.trigger.value_type = XSyncAbsolute;
2786 values.trigger.test_type = XSyncPositiveComparison;
2787
2788 XSyncIntToValue (&values.delta, 1);
2789
2790 values.events = TRUE;
2791
2792 compCheckForError (w->screen->display->display);
2793
2794 /* Note that by default, the alarm increments the trigger value
2795 * when it fires until the condition (counter.value < trigger.value)
2796 * is FALSE again.
2797 */
2798 w->syncAlarm = XSyncCreateAlarm (w->screen->display->display,
2799 XSyncCACounter |
2800 XSyncCAValue |
2801 XSyncCAValueType |
2802 XSyncCATestType |
2803 XSyncCADelta |
2804 XSyncCAEvents,
2805 &values);
2806
2807 if (!compCheckForError (w->screen->display->display))
2808 return TRUE;
2809
2810 XSyncDestroyAlarm (w->screen->display->display, w->syncAlarm);
2811 w->syncAlarm = None;
2812 }
2813 else if (result == Success && data)
2814 {
2815 XFree (data);
2816 }
2817
2818 return FALSE;
2819 }
2820
2821 static Bool
syncWaitTimeout(void * closure)2822 syncWaitTimeout (void *closure)
2823 {
2824 CompWindow *w = closure;
2825
2826 w->syncWaitHandle = 0;
2827 handleSyncAlarm (w);
2828
2829 return FALSE;
2830 }
2831
2832 void
sendSyncRequest(CompWindow * w)2833 sendSyncRequest (CompWindow *w)
2834 {
2835 XClientMessageEvent xev;
2836
2837 if (w->syncWait)
2838 return;
2839
2840 if (!initializeSyncCounter (w))
2841 return;
2842
2843 xev.type = ClientMessage;
2844 xev.window = w->id;
2845 xev.message_type = w->screen->display->wmProtocolsAtom;
2846 xev.format = 32;
2847 xev.data.l[0] = w->screen->display->wmSyncRequestAtom;
2848 xev.data.l[1] = CurrentTime;
2849 xev.data.l[2] = XSyncValueLow32 (w->syncValue);
2850 xev.data.l[3] = XSyncValueHigh32 (w->syncValue);
2851 xev.data.l[4] = 0;
2852
2853 syncValueIncrement (&w->syncValue);
2854
2855 XSendEvent (w->screen->display->display, w->id, FALSE, 0, (XEvent *) &xev);
2856
2857 w->syncWait = TRUE;
2858 w->syncX = w->serverX;
2859 w->syncY = w->serverY;
2860 w->syncWidth = w->serverWidth;
2861 w->syncHeight = w->serverHeight;
2862 w->syncBorderWidth = w->serverBorderWidth;
2863
2864 if (!w->syncWaitHandle)
2865 w->syncWaitHandle = compAddTimeout (1000, 1200, syncWaitTimeout, w);
2866 }
2867
2868 void
configureWindow(CompWindow * w,XConfigureEvent * ce)2869 configureWindow (CompWindow *w,
2870 XConfigureEvent *ce)
2871 {
2872 if (w->syncWait)
2873 {
2874 w->syncX = ce->x;
2875 w->syncY = ce->y;
2876 w->syncWidth = ce->width;
2877 w->syncHeight = ce->height;
2878 w->syncBorderWidth = ce->border_width;
2879 }
2880 else
2881 {
2882 if (ce->override_redirect)
2883 {
2884 w->serverX = ce->x;
2885 w->serverY = ce->y;
2886 w->serverWidth = ce->width;
2887 w->serverHeight = ce->height;
2888 w->serverBorderWidth = ce->border_width;
2889 }
2890
2891 resizeWindow (w, ce->x, ce->y, ce->width, ce->height,
2892 ce->border_width);
2893 }
2894
2895 w->attrib.override_redirect = ce->override_redirect;
2896
2897 if (restackWindow (w, ce->above))
2898 addWindowDamage (w);
2899 }
2900
2901 void
circulateWindow(CompWindow * w,XCirculateEvent * ce)2902 circulateWindow (CompWindow *w,
2903 XCirculateEvent *ce)
2904 {
2905 Window newAboveId;
2906
2907 if (ce->place == PlaceOnTop)
2908 newAboveId = getTopWindow (w->screen);
2909 else
2910 newAboveId = 0;
2911
2912 if (restackWindow (w, newAboveId))
2913 addWindowDamage (w);
2914 }
2915
2916 void
moveWindow(CompWindow * w,int dx,int dy,Bool damage,Bool immediate)2917 moveWindow (CompWindow *w,
2918 int dx,
2919 int dy,
2920 Bool damage,
2921 Bool immediate)
2922 {
2923 if (dx || dy)
2924 {
2925 if (damage)
2926 addWindowDamage (w);
2927
2928 w->attrib.x += dx;
2929 w->attrib.y += dy;
2930
2931 XOffsetRegion (w->region, dx, dy);
2932
2933 setWindowMatrix (w);
2934
2935 w->invisible = WINDOW_INVISIBLE (w);
2936
2937 (*w->screen->windowMoveNotify) (w, dx, dy, immediate);
2938
2939 if (damage)
2940 addWindowDamage (w);
2941 }
2942 }
2943
2944 void
syncWindowPosition(CompWindow * w)2945 syncWindowPosition (CompWindow *w)
2946 {
2947 w->serverX = w->attrib.x;
2948 w->serverY = w->attrib.y;
2949
2950 XMoveWindow (w->screen->display->display, w->id, w->attrib.x, w->attrib.y);
2951
2952 if (w->frame)
2953 XMoveWindow (w->screen->display->display, w->frame,
2954 w->serverX - w->input.left,
2955 w->serverY - w->input.top);
2956 }
2957
2958 Bool
focusWindow(CompWindow * w)2959 focusWindow (CompWindow *w)
2960 {
2961 if (w->attrib.override_redirect)
2962 return FALSE;
2963
2964 if (!w->managed || w->unmanaging)
2965 return FALSE;
2966
2967 if (w->destroyed)
2968 return FALSE;
2969
2970 if (!onCurrentDesktop (w))
2971 return FALSE;
2972
2973 if (!w->shaded && (w->state & CompWindowStateHiddenMask))
2974 return FALSE;
2975
2976 if (w->attrib.x + w->width <= 0 ||
2977 w->attrib.y + w->height <= 0 ||
2978 w->attrib.x >= w->screen->width ||
2979 w->attrib.y >= w->screen->height)
2980 return FALSE;
2981
2982 return TRUE;
2983 }
2984
2985 Bool
placeWindow(CompWindow * w,int x,int y,int * newX,int * newY)2986 placeWindow (CompWindow *w,
2987 int x,
2988 int y,
2989 int *newX,
2990 int *newY)
2991 {
2992 return FALSE;
2993 }
2994
2995 void
validateWindowResizeRequest(CompWindow * w,unsigned int * mask,XWindowChanges * xwc,unsigned int source)2996 validateWindowResizeRequest (CompWindow *w,
2997 unsigned int *mask,
2998 XWindowChanges *xwc,
2999 unsigned int source)
3000 {
3001 CompScreen *s = w->screen;
3002
3003 if (w->type & (CompWindowTypeDockMask |
3004 CompWindowTypeFullscreenMask |
3005 CompWindowTypeUnknownMask))
3006 return;
3007
3008 if (*mask & CWY)
3009 {
3010 int min, max;
3011
3012 min = s->workArea.y + w->input.top;
3013 max = s->workArea.y + s->workArea.height;
3014
3015 if (w->state & CompWindowStateStickyMask &&
3016 (xwc->y < min || xwc->y > max))
3017 {
3018 xwc->y = w->serverY;
3019 }
3020 else
3021 {
3022 min -= s->y * s->height;
3023 max += (s->vsize - s->y - 1) * s->height;
3024
3025 if (xwc->y < min)
3026 xwc->y = min;
3027 else if (xwc->y > max)
3028 xwc->y = max;
3029 }
3030 }
3031
3032 if (*mask & CWX)
3033 {
3034 int min, max;
3035
3036 min = s->workArea.x + w->input.left;
3037 max = s->workArea.x + s->workArea.width;
3038
3039 if (w->state & CompWindowStateStickyMask &&
3040 (xwc->x < min || xwc->x > max))
3041 {
3042 xwc->x = w->serverX;
3043 }
3044 else
3045 {
3046 min -= s->x * s->width;
3047 max += (s->hsize - s->x - 1) * s->width;
3048
3049 if (xwc->x < min)
3050 xwc->x = min;
3051 else if (xwc->x > max)
3052 xwc->x = max;
3053 }
3054 }
3055 }
3056
3057 void
windowResizeNotify(CompWindow * w,int dx,int dy,int dwidth,int dheight)3058 windowResizeNotify (CompWindow *w,
3059 int dx,
3060 int dy,
3061 int dwidth,
3062 int dheight)
3063 {
3064 }
3065
3066 void
windowMoveNotify(CompWindow * w,int dx,int dy,Bool immediate)3067 windowMoveNotify (CompWindow *w,
3068 int dx,
3069 int dy,
3070 Bool immediate)
3071 {
3072 }
3073
3074 void
windowGrabNotify(CompWindow * w,int x,int y,unsigned int state,unsigned int mask)3075 windowGrabNotify (CompWindow *w,
3076 int x,
3077 int y,
3078 unsigned int state,
3079 unsigned int mask)
3080 {
3081 w->grabbed = TRUE;
3082 }
3083
3084 void
windowUngrabNotify(CompWindow * w)3085 windowUngrabNotify (CompWindow *w)
3086 {
3087 w->grabbed = FALSE;
3088 }
3089
3090 void
windowStateChangeNotify(CompWindow * w,unsigned int lastState)3091 windowStateChangeNotify (CompWindow *w,
3092 unsigned int lastState)
3093 {
3094 /* if being made sticky */
3095 if (!(lastState & CompWindowStateStickyMask) &&
3096 (w->state & CompWindowStateStickyMask))
3097 {
3098 CompScreen *s = w->screen;
3099 int vpX; /* x index of the window's vp */
3100 int vpY; /* y index of the window's vp */
3101
3102 /* Find which viewport the window falls in,
3103 and check if it's the current viewport */
3104 defaultViewportForWindow (w, &vpX, &vpY);
3105 if (s->x != vpX || s->y != vpY)
3106 {
3107 int moveX = (s->x - vpX) * s->width;
3108 int moveY = (s->y - vpY) * s->height;
3109
3110 moveWindow (w, moveX, moveY, TRUE, TRUE);
3111 syncWindowPosition (w);
3112 }
3113 }
3114 }
3115
3116 static Bool
isGroupTransient(CompWindow * w,Window clientLeader)3117 isGroupTransient (CompWindow *w,
3118 Window clientLeader)
3119 {
3120 if (!clientLeader)
3121 return FALSE;
3122
3123 if (w->transientFor == None || w->transientFor == w->screen->root)
3124 {
3125 if (w->type & (CompWindowTypeUtilMask |
3126 CompWindowTypeToolbarMask |
3127 CompWindowTypeMenuMask |
3128 CompWindowTypeDialogMask |
3129 CompWindowTypeModalDialogMask))
3130 {
3131 if (w->clientLeader == clientLeader)
3132 return TRUE;
3133 }
3134 }
3135
3136 return FALSE;
3137 }
3138
3139 static CompWindow *
getModalTransient(CompWindow * window)3140 getModalTransient (CompWindow *window)
3141 {
3142 CompWindow *w, *modalTransient;
3143
3144 modalTransient = window;
3145
3146 for (w = window->screen->reverseWindows; w; w = w->prev)
3147 {
3148 if (w == modalTransient || w->mapNum == 0)
3149 continue;
3150
3151 if (w->transientFor == modalTransient->id)
3152 {
3153 if (w->state & CompWindowStateModalMask)
3154 {
3155 modalTransient = w;
3156 w = window->screen->reverseWindows;
3157 }
3158 }
3159 }
3160
3161 if (modalTransient == window)
3162 {
3163 /* don't look for group transients with modal state if current window
3164 has modal state */
3165 if (window->state & CompWindowStateModalMask)
3166 return NULL;
3167
3168 for (w = window->screen->reverseWindows; w; w = w->prev)
3169 {
3170 if (w == modalTransient || w->mapNum == 0)
3171 continue;
3172
3173 if (isAncestorTo (modalTransient, w))
3174 continue;
3175
3176 if (isGroupTransient (w, modalTransient->clientLeader))
3177 {
3178 if (w->state & CompWindowStateModalMask)
3179 {
3180 modalTransient = w;
3181 w = getModalTransient (w);
3182 if (w)
3183 modalTransient = w;
3184
3185 break;
3186 }
3187 }
3188 }
3189 }
3190
3191 if (modalTransient == window)
3192 modalTransient = NULL;
3193
3194 return modalTransient;
3195 }
3196
3197 void
moveInputFocusToWindow(CompWindow * w)3198 moveInputFocusToWindow (CompWindow *w)
3199 {
3200 CompScreen *s = w->screen;
3201 CompDisplay *d = s->display;
3202 CompWindow *modalTransient;
3203
3204 modalTransient = getModalTransient (w);
3205 if (modalTransient)
3206 w = modalTransient;
3207
3208 if (w->state & CompWindowStateHiddenMask)
3209 {
3210 XSetInputFocus (d->display, w->frame, RevertToPointerRoot, CurrentTime);
3211 XChangeProperty (d->display, s->root, d->winActiveAtom,
3212 XA_WINDOW, 32, PropModeReplace,
3213 (unsigned char *) &w->id, 1);
3214 }
3215 else
3216 {
3217 Bool setFocus = FALSE;
3218
3219 if (w->inputHint)
3220 {
3221 XSetInputFocus (d->display, w->id, RevertToPointerRoot,
3222 CurrentTime);
3223 setFocus = TRUE;
3224 }
3225
3226 if (w->protocols & CompWindowProtocolTakeFocusMask)
3227 {
3228 XEvent ev;
3229
3230 ev.type = ClientMessage;
3231 ev.xclient.window = w->id;
3232 ev.xclient.message_type = d->wmProtocolsAtom;
3233 ev.xclient.format = 32;
3234 ev.xclient.data.l[0] = d->wmTakeFocusAtom;
3235 ev.xclient.data.l[1] =
3236 getCurrentTimeFromDisplay (d);
3237 ev.xclient.data.l[2] = 0;
3238 ev.xclient.data.l[3] = 0;
3239 ev.xclient.data.l[4] = 0;
3240
3241 XSendEvent (d->display, w->id, FALSE, NoEventMask, &ev);
3242
3243 setFocus = TRUE;
3244 }
3245
3246 if (setFocus)
3247 d->nextActiveWindow = w->id;
3248
3249 if (!setFocus && !modalTransient)
3250 {
3251 CompWindow *ancestor;
3252
3253 /* move input to closest ancestor */
3254 for (ancestor = s->windows; ancestor; ancestor = ancestor->next)
3255 {
3256 if (isAncestorTo (w, ancestor))
3257 {
3258 moveInputFocusToWindow (ancestor);
3259 break;
3260 }
3261 }
3262 }
3263 }
3264 }
3265
3266 static Bool
stackLayerCheck(CompWindow * w,Window clientLeader,CompWindow * below)3267 stackLayerCheck (CompWindow *w,
3268 Window clientLeader,
3269 CompWindow *below)
3270 {
3271 if (isAncestorTo (w, below))
3272 return TRUE;
3273
3274 if (isAncestorTo (below, w))
3275 return FALSE;
3276
3277 if (clientLeader && below->clientLeader == clientLeader)
3278 if (isGroupTransient (below, clientLeader))
3279 return FALSE;
3280
3281 if (w->state & CompWindowStateAboveMask)
3282 {
3283 return TRUE;
3284 }
3285 else if (w->state & CompWindowStateBelowMask)
3286 {
3287 if (below->state & CompWindowStateBelowMask)
3288 return TRUE;
3289 }
3290 else if (!(below->state & CompWindowStateAboveMask))
3291 {
3292 return TRUE;
3293 }
3294
3295 return FALSE;
3296 }
3297
3298 static Bool
avoidStackingRelativeTo(CompWindow * w)3299 avoidStackingRelativeTo (CompWindow *w)
3300 {
3301 if (w->attrib.override_redirect)
3302 return TRUE;
3303
3304 if (!w->shaded && !w->pendingMaps)
3305 {
3306 if (w->attrib.map_state != IsViewable || w->mapNum == 0)
3307 return TRUE;
3308 }
3309
3310 return FALSE;
3311 }
3312
3313 /* goes through the stack, top-down until we find a window we should
3314 stack above, normal windows can be stacked above fullscreen windows
3315 (and fullscreen windows over others in their layer) if aboveFs
3316 is TRUE. */
3317 static CompWindow *
findSiblingBelow(CompWindow * w,Bool aboveFs)3318 findSiblingBelow (CompWindow *w,
3319 Bool aboveFs)
3320 {
3321 CompWindow *below;
3322 Window clientLeader = w->clientLeader;
3323 unsigned int type = w->type;
3324 unsigned int belowMask;
3325
3326 if (aboveFs)
3327 belowMask = CompWindowTypeDockMask;
3328 else
3329 belowMask = CompWindowTypeDockMask | CompWindowTypeFullscreenMask;
3330
3331 /* normal stacking of fullscreen windows with below state */
3332 if ((type & CompWindowTypeFullscreenMask) &&
3333 (w->state & CompWindowStateBelowMask))
3334 type = CompWindowTypeNormalMask;
3335
3336 if (w->transientFor || isGroupTransient (w, clientLeader))
3337 clientLeader = None;
3338
3339 for (below = w->screen->reverseWindows; below; below = below->prev)
3340 {
3341 if (below == w || avoidStackingRelativeTo (below))
3342 continue;
3343
3344 /* always above desktop windows */
3345 if (below->type & CompWindowTypeDesktopMask)
3346 return below;
3347
3348 switch (type) {
3349 case CompWindowTypeDesktopMask:
3350 /* desktop window layer */
3351 break;
3352 case CompWindowTypeFullscreenMask:
3353 if (aboveFs)
3354 return below;
3355 /* otherwise fall-through */
3356 case CompWindowTypeDockMask:
3357 /* fullscreen and dock layer */
3358 if (below->type & (CompWindowTypeFullscreenMask |
3359 CompWindowTypeDockMask))
3360 {
3361 if (stackLayerCheck (w, clientLeader, below))
3362 return below;
3363 }
3364 else
3365 {
3366 return below;
3367 }
3368 break;
3369 default:
3370 /* fullscreen and normal layer */
3371 if (!(below->type & belowMask))
3372 {
3373 if (stackLayerCheck (w, clientLeader, below))
3374 return below;
3375 }
3376 break;
3377 }
3378 }
3379
3380 return NULL;
3381 }
3382
3383 /* goes through the stack, top-down and returns the lowest window we
3384 can stack above. */
3385 static CompWindow *
findLowestSiblingBelow(CompWindow * w)3386 findLowestSiblingBelow (CompWindow *w)
3387 {
3388 CompWindow *below, *lowest = w->screen->reverseWindows;
3389 Window clientLeader = w->clientLeader;
3390 unsigned int type = w->type;
3391
3392 /* normal stacking fullscreen windows with below state */
3393 if ((type & CompWindowTypeFullscreenMask) &&
3394 (w->state & CompWindowStateBelowMask))
3395 type = CompWindowTypeNormalMask;
3396
3397 if (w->transientFor || isGroupTransient (w, clientLeader))
3398 clientLeader = None;
3399
3400 for (below = w->screen->reverseWindows; below; below = below->prev)
3401 {
3402 if (below == w || avoidStackingRelativeTo (below))
3403 continue;
3404
3405 /* always above desktop windows */
3406 if (below->type & CompWindowTypeDesktopMask)
3407 return below;
3408
3409 switch (type) {
3410 case CompWindowTypeDesktopMask:
3411 /* desktop window layer - desktop windows always should be
3412 stacked at the bottom; no other window should be below them */
3413 return NULL;
3414 break;
3415 case CompWindowTypeFullscreenMask:
3416 case CompWindowTypeDockMask:
3417 /* fullscreen and dock layer */
3418 if (below->type & (CompWindowTypeFullscreenMask |
3419 CompWindowTypeDockMask))
3420 {
3421 if (!stackLayerCheck (below, clientLeader, w))
3422 return lowest;
3423 }
3424 else
3425 {
3426 return lowest;
3427 }
3428 break;
3429 default:
3430 /* fullscreen and normal layer */
3431 if (!(below->type & CompWindowTypeDockMask))
3432 {
3433 if (!stackLayerCheck (below, clientLeader, w))
3434 return lowest;
3435 }
3436 break;
3437 }
3438
3439 lowest = below;
3440 }
3441
3442 return lowest;
3443 }
3444
3445 static Bool
validSiblingBelow(CompWindow * w,CompWindow * sibling)3446 validSiblingBelow (CompWindow *w,
3447 CompWindow *sibling)
3448 {
3449 Window clientLeader = w->clientLeader;
3450 unsigned int type = w->type;
3451
3452 /* normal stacking fullscreen windows with below state */
3453 if ((type & CompWindowTypeFullscreenMask) &&
3454 (w->state & CompWindowStateBelowMask))
3455 type = CompWindowTypeNormalMask;
3456
3457 if (w->transientFor || isGroupTransient (w, clientLeader))
3458 clientLeader = None;
3459
3460 if (sibling == w || avoidStackingRelativeTo (sibling))
3461 return FALSE;
3462
3463 /* always above desktop windows */
3464 if (sibling->type & CompWindowTypeDesktopMask)
3465 return TRUE;
3466
3467 switch (type) {
3468 case CompWindowTypeDesktopMask:
3469 /* desktop window layer */
3470 break;
3471 case CompWindowTypeFullscreenMask:
3472 case CompWindowTypeDockMask:
3473 /* fullscreen and dock layer */
3474 if (sibling->type & (CompWindowTypeFullscreenMask |
3475 CompWindowTypeDockMask))
3476 {
3477 if (stackLayerCheck (w, clientLeader, sibling))
3478 return TRUE;
3479 }
3480 else
3481 {
3482 return TRUE;
3483 }
3484 break;
3485 default:
3486 /* fullscreen and normal layer */
3487 if (!(sibling->type & CompWindowTypeDockMask))
3488 {
3489 if (stackLayerCheck (w, clientLeader, sibling))
3490 return TRUE;
3491 }
3492 break;
3493 }
3494
3495 return FALSE;
3496 }
3497
3498 static void
saveWindowGeometry(CompWindow * w,int mask)3499 saveWindowGeometry (CompWindow *w,
3500 int mask)
3501 {
3502 int m = mask & ~w->saveMask;
3503
3504 /* only save geometry if window has been placed */
3505 if (!w->placed)
3506 return;
3507
3508 if (m & CWX)
3509 w->saveWc.x = w->serverX;
3510
3511 if (m & CWY)
3512 w->saveWc.y = w->serverY;
3513
3514 if (m & CWWidth)
3515 w->saveWc.width = w->serverWidth;
3516
3517 if (m & CWHeight)
3518 w->saveWc.height = w->serverHeight;
3519
3520 if (m & CWBorderWidth)
3521 w->saveWc.border_width = w->serverBorderWidth;
3522
3523 w->saveMask |= m;
3524 }
3525
3526 static int
restoreWindowGeometry(CompWindow * w,XWindowChanges * xwc,int mask)3527 restoreWindowGeometry (CompWindow *w,
3528 XWindowChanges *xwc,
3529 int mask)
3530 {
3531 int m = mask & w->saveMask;
3532
3533 if (m & CWX)
3534 xwc->x = w->saveWc.x;
3535
3536 if (m & CWY)
3537 xwc->y = w->saveWc.y;
3538
3539 if (m & CWWidth)
3540 {
3541 xwc->width = w->saveWc.width;
3542
3543 /* This is not perfect but it works OK for now. If the saved width is
3544 the same as the current width then make it a little be smaller so
3545 the user can see that it changed and it also makes sure that
3546 windowResizeNotify is called and plugins are notified. */
3547 if (xwc->width == w->serverWidth)
3548 {
3549 xwc->width -= 10;
3550 if (m & CWX)
3551 xwc->x += 5;
3552 }
3553 }
3554
3555 if (m & CWHeight)
3556 {
3557 xwc->height = w->saveWc.height;
3558
3559 /* As above, if the saved height is the same as the current height
3560 then make it a little be smaller. */
3561 if (xwc->height == w->serverHeight)
3562 {
3563 xwc->height -= 10;
3564 if (m & CWY)
3565 xwc->y += 5;
3566 }
3567 }
3568
3569 if (m & CWBorderWidth)
3570 xwc->border_width = w->saveWc.border_width;
3571
3572 w->saveMask &= ~mask;
3573
3574 return m;
3575 }
3576
3577 static void
reconfigureXWindow(CompWindow * w,unsigned int valueMask,XWindowChanges * xwc)3578 reconfigureXWindow (CompWindow *w,
3579 unsigned int valueMask,
3580 XWindowChanges *xwc)
3581 {
3582 if (valueMask & CWX)
3583 w->serverX = xwc->x;
3584
3585 if (valueMask & CWY)
3586 w->serverY = xwc->y;
3587
3588 if (valueMask & CWWidth)
3589 w->serverWidth = xwc->width;
3590
3591 if (valueMask & CWHeight)
3592 w->serverHeight = xwc->height;
3593
3594 if (valueMask & CWBorderWidth)
3595 w->serverBorderWidth = xwc->border_width;
3596
3597 XConfigureWindow (w->screen->display->display, w->id, valueMask, xwc);
3598
3599 if (w->frame && (valueMask & (CWSibling | CWStackMode)))
3600 XConfigureWindow (w->screen->display->display, w->frame,
3601 valueMask & (CWSibling | CWStackMode), xwc);
3602 }
3603
3604 static Bool
stackTransients(CompWindow * w,CompWindow * avoid,XWindowChanges * xwc)3605 stackTransients (CompWindow *w,
3606 CompWindow *avoid,
3607 XWindowChanges *xwc)
3608 {
3609 CompWindow *t;
3610 Window clientLeader = w->clientLeader;
3611
3612 if (w->transientFor || isGroupTransient (w, clientLeader))
3613 clientLeader = None;
3614
3615 for (t = w->screen->reverseWindows; t; t = t->prev)
3616 {
3617 if (t == w || t == avoid)
3618 continue;
3619
3620 if (t->transientFor == w->id || isGroupTransient (t, clientLeader))
3621 {
3622 if (w->type & CompWindowTypeDockMask)
3623 if (!(t->type & CompWindowTypeDockMask))
3624 return FALSE;
3625
3626 if (!stackTransients (t, avoid, xwc))
3627 return FALSE;
3628
3629 if (xwc->sibling == t->id)
3630 return FALSE;
3631
3632 if (t->mapNum || t->pendingMaps)
3633 reconfigureXWindow (t, CWSibling | CWStackMode, xwc);
3634 }
3635 }
3636
3637 return TRUE;
3638 }
3639
3640 static void
stackAncestors(CompWindow * w,XWindowChanges * xwc)3641 stackAncestors (CompWindow *w,
3642 XWindowChanges *xwc)
3643 {
3644 if (w->transientFor && xwc->sibling != w->transientFor)
3645 {
3646 CompWindow *ancestor;
3647
3648 ancestor = findWindowAtScreen (w->screen, w->transientFor);
3649 if (ancestor)
3650 {
3651 if (!stackTransients (ancestor, w, xwc))
3652 return;
3653
3654 if (ancestor->type & CompWindowTypeDesktopMask)
3655 return;
3656
3657 if (ancestor->type & CompWindowTypeDockMask)
3658 if (!(w->type & CompWindowTypeDockMask))
3659 return;
3660
3661 if (ancestor->mapNum || ancestor->pendingMaps)
3662 reconfigureXWindow (ancestor,
3663 CWSibling | CWStackMode,
3664 xwc);
3665
3666 stackAncestors (ancestor, xwc);
3667 }
3668 }
3669 else if (isGroupTransient (w, w->clientLeader))
3670 {
3671 CompWindow *a;
3672
3673 for (a = w->screen->reverseWindows; a; a = a->prev)
3674 {
3675 if (a->clientLeader == w->clientLeader &&
3676 a->transientFor == None &&
3677 !isGroupTransient (a, w->clientLeader))
3678 {
3679 if (xwc->sibling == a->id)
3680 break;
3681
3682 if (!stackTransients (a, w, xwc))
3683 break;
3684
3685 if (a->type & CompWindowTypeDesktopMask)
3686 continue;
3687
3688 if (a->type & CompWindowTypeDockMask)
3689 if (!(w->type & CompWindowTypeDockMask))
3690 break;
3691
3692 if (a->mapNum || a->pendingMaps)
3693 reconfigureXWindow (a,
3694 CWSibling | CWStackMode,
3695 xwc);
3696 }
3697 }
3698 }
3699 }
3700
3701 void
configureXWindow(CompWindow * w,unsigned int valueMask,XWindowChanges * xwc)3702 configureXWindow (CompWindow *w,
3703 unsigned int valueMask,
3704 XWindowChanges *xwc)
3705 {
3706 if (w->managed && (valueMask & (CWSibling | CWStackMode)))
3707 {
3708 /* transient children above */
3709 if (stackTransients (w, NULL, xwc))
3710 {
3711 reconfigureXWindow (w, valueMask, xwc);
3712
3713 /* ancestors, siblings and sibling transients below */
3714 stackAncestors (w, xwc);
3715 }
3716 }
3717 else
3718 {
3719 reconfigureXWindow (w, valueMask, xwc);
3720 }
3721 }
3722
3723 static int
addWindowSizeChanges(CompWindow * w,XWindowChanges * xwc,int oldX,int oldY,int oldWidth,int oldHeight,int oldBorderWidth)3724 addWindowSizeChanges (CompWindow *w,
3725 XWindowChanges *xwc,
3726 int oldX,
3727 int oldY,
3728 int oldWidth,
3729 int oldHeight,
3730 int oldBorderWidth)
3731 {
3732 XRectangle workArea;
3733 int mask = 0;
3734 int x, y;
3735 int vx, vy;
3736 int output;
3737
3738 viewportForGeometry (w->screen,
3739 oldX,
3740 oldY,
3741 oldWidth,
3742 oldHeight,
3743 oldBorderWidth,
3744 &vx, &vy);
3745
3746 x = (vx - w->screen->x) * w->screen->width;
3747 y = (vy - w->screen->y) * w->screen->height;
3748
3749 output = outputDeviceForGeometry (w->screen,
3750 oldX,
3751 oldY,
3752 oldWidth,
3753 oldHeight,
3754 oldBorderWidth);
3755 getWorkareaForOutput (w->screen, output, &workArea);
3756
3757 if (w->type & CompWindowTypeFullscreenMask)
3758 {
3759 saveWindowGeometry (w, CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3760
3761 if (w->fullscreenMonitorsSet)
3762 {
3763 xwc->x = x + w->fullscreenMonitorRect.x;
3764 xwc->y = y + w->fullscreenMonitorRect.y;
3765 xwc->width = w->fullscreenMonitorRect.width;
3766 xwc->height = w->fullscreenMonitorRect.height;
3767 }
3768 else
3769 {
3770 xwc->x = x + w->screen->outputDev[output].region.extents.x1;
3771 xwc->y = y + w->screen->outputDev[output].region.extents.y1;
3772 xwc->width = w->screen->outputDev[output].width;
3773 xwc->height = w->screen->outputDev[output].height;
3774 }
3775
3776 xwc->border_width = 0;
3777
3778 mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
3779 }
3780 else
3781 {
3782 mask |= restoreWindowGeometry (w, xwc, CWBorderWidth);
3783
3784 if (w->state & CompWindowStateMaximizedVertMask)
3785 {
3786 saveWindowGeometry (w, CWY | CWHeight);
3787
3788 xwc->height = workArea.height - w->input.top -
3789 w->input.bottom - oldBorderWidth * 2;
3790
3791 mask |= CWHeight;
3792 }
3793 else
3794 {
3795 mask |= restoreWindowGeometry (w, xwc, CWY | CWHeight);
3796 }
3797
3798 if (w->state & CompWindowStateMaximizedHorzMask)
3799 {
3800 saveWindowGeometry (w, CWX | CWWidth);
3801
3802 xwc->width = workArea.width - w->input.left -
3803 w->input.right - oldBorderWidth * 2;
3804
3805 mask |= CWWidth;
3806 }
3807 else
3808 {
3809 mask |= restoreWindowGeometry (w, xwc, CWX | CWWidth);
3810 }
3811
3812 /* constrain window width if smaller than minimum width */
3813 if (!(mask & CWWidth) && oldWidth < w->sizeHints.min_width)
3814 {
3815 xwc->width = w->sizeHints.min_width;
3816 mask |= CWWidth;
3817 }
3818
3819 /* constrain window width if greater than maximum width */
3820 if (!(mask & CWWidth) && oldWidth > w->sizeHints.max_width)
3821 {
3822 xwc->width = w->sizeHints.max_width;
3823 mask |= CWWidth;
3824 }
3825
3826 /* constrain window height if smaller than minimum height */
3827 if (!(mask & CWHeight) && oldHeight < w->sizeHints.min_height)
3828 {
3829 xwc->height = w->sizeHints.min_height;
3830 mask |= CWHeight;
3831 }
3832
3833 /* constrain window height if greater than maximum height */
3834 if (!(mask & CWHeight) && oldHeight > w->sizeHints.max_height)
3835 {
3836 xwc->height = w->sizeHints.max_height;
3837 mask |= CWHeight;
3838 }
3839
3840 if (mask & (CWWidth | CWHeight))
3841 {
3842 int width, height, max;
3843
3844 width = (mask & CWWidth) ? xwc->width : oldWidth;
3845 height = (mask & CWHeight) ? xwc->height : oldHeight;
3846
3847 xwc->width = oldWidth;
3848 xwc->height = oldHeight;
3849
3850 constrainNewWindowSize (w, width, height, &width, &height);
3851
3852 if (width != oldWidth)
3853 {
3854 mask |= CWWidth;
3855 xwc->width = width;
3856 }
3857 else
3858 mask &= ~CWWidth;
3859
3860 if (height != oldHeight)
3861 {
3862 mask |= CWHeight;
3863 xwc->height = height;
3864 }
3865 else
3866 mask &= ~CWHeight;
3867
3868 if (w->state & CompWindowStateMaximizedVertMask)
3869 {
3870 if (oldY < y + workArea.y + w->input.top)
3871 {
3872 xwc->y = y + workArea.y + w->input.top;
3873 mask |= CWY;
3874 }
3875 else
3876 {
3877 height = xwc->height + oldBorderWidth * 2;
3878
3879 max = y + workArea.y + workArea.height;
3880 if (oldY + oldHeight + w->input.bottom > max)
3881 {
3882 xwc->y = max - height - w->input.bottom;
3883 mask |= CWY;
3884 }
3885 else if (oldY + height + w->input.bottom > max)
3886 {
3887 xwc->y = y + workArea.y +
3888 (workArea.height - w->input.top - height -
3889 w->input.bottom) / 2 + w->input.top;
3890 mask |= CWY;
3891 }
3892 }
3893 }
3894
3895 if (w->state & CompWindowStateMaximizedHorzMask)
3896 {
3897 if (oldX < x + workArea.x + w->input.left)
3898 {
3899 xwc->x = x + workArea.x + w->input.left;
3900 mask |= CWX;
3901 }
3902 else
3903 {
3904 width = xwc->width + oldBorderWidth * 2;
3905
3906 max = x + workArea.x + workArea.width;
3907 if (oldX + oldWidth + w->input.right > max)
3908 {
3909 xwc->x = max - width - w->input.right;
3910 mask |= CWX;
3911 }
3912 else if (oldX + width + w->input.right > max)
3913 {
3914 xwc->x = x + workArea.x +
3915 (workArea.width - w->input.left - width -
3916 w->input.right) / 2 + w->input.left;
3917 mask |= CWX;
3918 }
3919 }
3920 }
3921 }
3922 }
3923
3924 if ((mask & CWX) && (xwc->x == oldX))
3925 mask &= ~CWX;
3926
3927 if ((mask & CWY) && (xwc->y == oldY))
3928 mask &= ~CWY;
3929
3930 if ((mask & CWWidth) && (xwc->width == oldWidth))
3931 mask &= ~CWWidth;
3932
3933 if ((mask & CWHeight) && (xwc->height == oldHeight))
3934 mask &= ~CWHeight;
3935
3936 return mask;
3937 }
3938
3939 unsigned int
adjustConfigureRequestForGravity(CompWindow * w,XWindowChanges * xwc,unsigned int xwcm,int gravity,int direction)3940 adjustConfigureRequestForGravity (CompWindow *w,
3941 XWindowChanges *xwc,
3942 unsigned int xwcm,
3943 int gravity,
3944 int direction)
3945 {
3946 int newX, newY;
3947 unsigned int mask = 0;
3948
3949 newX = xwc->x;
3950 newY = xwc->y;
3951
3952 if (xwcm & (CWX | CWWidth))
3953 {
3954 switch (gravity) {
3955 case NorthWestGravity:
3956 case WestGravity:
3957 case SouthWestGravity:
3958 if (xwcm & CWX)
3959 newX += w->input.left;
3960 break;
3961
3962 case NorthGravity:
3963 case CenterGravity:
3964 case SouthGravity:
3965 if (xwcm & CWX)
3966 newX -= xwc->width / 2 - w->input.left +
3967 (w->input.left + w->input.right) / 2;
3968 else
3969 newX -= (xwc->width - w->serverWidth) / 2;
3970 break;
3971
3972 case NorthEastGravity:
3973 case EastGravity:
3974 case SouthEastGravity:
3975 if (xwcm & CWX)
3976 newX -= xwc->width + w->input.right;
3977 else
3978 newX -= xwc->width - w->serverWidth;
3979 break;
3980
3981 case StaticGravity:
3982 default:
3983 break;
3984 }
3985 }
3986
3987 if (xwcm & (CWY | CWHeight))
3988 {
3989 switch (gravity) {
3990 case NorthWestGravity:
3991 case NorthGravity:
3992 case NorthEastGravity:
3993 if (xwcm & CWY)
3994 newY += w->input.top;
3995 break;
3996
3997 case WestGravity:
3998 case CenterGravity:
3999 case EastGravity:
4000 if (xwcm & CWY)
4001 newY -= xwc->height / 2 - w->input.top +
4002 (w->input.top + w->input.bottom) / 2;
4003 else
4004 newY -= (xwc->height - w->serverHeight) / 2;
4005 break;
4006
4007 case SouthWestGravity:
4008 case SouthGravity:
4009 case SouthEastGravity:
4010 if (xwcm & CWY)
4011 newY -= xwc->height + w->input.bottom;
4012 else
4013 newY -= xwc->height - w->serverHeight;
4014 break;
4015
4016 case StaticGravity:
4017 default:
4018 break;
4019 }
4020 }
4021
4022 if (newX != xwc->x)
4023 {
4024 xwc->x += (newX - xwc->x) * direction;
4025 mask |= CWX;
4026 }
4027
4028 if (newY != xwc->y)
4029 {
4030 xwc->y += (newY - xwc->y) * direction;
4031 mask |= CWY;
4032 }
4033
4034 return mask;
4035 }
4036
4037 void
moveResizeWindow(CompWindow * w,XWindowChanges * xwc,unsigned int xwcm,int gravity,unsigned int source)4038 moveResizeWindow (CompWindow *w,
4039 XWindowChanges *xwc,
4040 unsigned int xwcm,
4041 int gravity,
4042 unsigned int source)
4043 {
4044 Bool placed = FALSE;
4045
4046 xwcm &= (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
4047
4048 if (xwcm & (CWX | CWY))
4049 if (w->sizeHints.flags & (USPosition | PPosition))
4050 placed = TRUE;
4051
4052 if (gravity == 0)
4053 gravity = w->sizeHints.win_gravity;
4054
4055 if (!(xwcm & CWX))
4056 xwc->x = w->serverX;
4057 if (!(xwcm & CWY))
4058 xwc->y = w->serverY;
4059 if (!(xwcm & CWWidth))
4060 xwc->width = w->serverWidth;
4061 if (!(xwcm & CWHeight))
4062 xwc->height = w->serverHeight;
4063
4064 /* when horizontally maximized only allow width changes added by
4065 addWindowSizeChanges or constrainNewWindowState */
4066 if (w->state & CompWindowStateMaximizedHorzMask)
4067 xwcm &= ~CWWidth;
4068
4069 /* when vertically maximized only allow height changes added by
4070 addWindowSizeChanges or constrainNewWindowState */
4071 if (w->state & CompWindowStateMaximizedVertMask)
4072 xwcm &= ~CWHeight;
4073
4074 if (xwcm & (CWWidth | CWHeight))
4075 {
4076 int width, height;
4077
4078 if (constrainNewWindowSize (w,
4079 xwc->width, xwc->height,
4080 &width, &height))
4081 {
4082 if (width != xwc->width)
4083 xwcm |= CWWidth;
4084
4085 if (height != xwc->height)
4086 xwcm |= CWHeight;
4087
4088 xwc->width = width;
4089 xwc->height = height;
4090 }
4091 }
4092
4093 xwcm |= adjustConfigureRequestForGravity (w, xwc, xwcm, gravity, 1);
4094
4095 (*w->screen->validateWindowResizeRequest) (w, &xwcm, xwc, source);
4096
4097 xwcm |= addWindowSizeChanges (w, xwc,
4098 xwc->x, xwc->y,
4099 xwc->width, xwc->height,
4100 xwc->border_width);
4101
4102 /* check if the new coordinates are useful and valid (different
4103 to current size); if not, we have to clear them to make sure
4104 we send a synthetic ConfigureNotify event if all coordinates
4105 match the server coordinates */
4106 if (xwc->x == w->serverX)
4107 xwcm &= ~CWX;
4108
4109 if (xwc->y == w->serverY)
4110 xwcm &= ~CWY;
4111
4112 if (xwc->width == w->serverWidth)
4113 xwcm &= ~CWWidth;
4114
4115 if (xwc->height == w->serverHeight)
4116 xwcm &= ~CWHeight;
4117
4118 if (xwc->border_width == w->serverBorderWidth)
4119 xwcm &= ~CWBorderWidth;
4120
4121 /* update saved window coordinates - if CWX or CWY is set for fullscreen
4122 or maximized windows after addWindowSizeChanges, it should be pretty
4123 safe to assume that the saved coordinates should be updated too, e.g.
4124 because the window was moved to another viewport by some client */
4125 if ((xwcm & CWX) && (w->saveMask & CWX))
4126 w->saveWc.x += (xwc->x - w->serverX);
4127
4128 if ((xwcm & CWY) && (w->saveMask & CWY))
4129 w->saveWc.y += (xwc->y - w->serverY);
4130
4131 if (w->mapNum && (xwcm & (CWWidth | CWHeight)))
4132 sendSyncRequest (w);
4133
4134 if (xwcm)
4135 configureXWindow (w, xwcm, xwc);
4136 else
4137 {
4138 /* we have to send a configure notify on ConfigureRequest events if
4139 we decide not to do anything according to ICCCM 4.1.5 */
4140 sendConfigureNotify (w);
4141 }
4142
4143 if (placed)
4144 w->placed = TRUE;
4145 }
4146
4147 void
updateWindowSize(CompWindow * w)4148 updateWindowSize (CompWindow *w)
4149 {
4150 XWindowChanges xwc;
4151 int mask;
4152
4153 if (w->attrib.override_redirect || !w->managed)
4154 return;
4155
4156 mask = addWindowSizeChanges (w, &xwc,
4157 w->serverX, w->serverY,
4158 w->serverWidth, w->serverHeight,
4159 w->serverBorderWidth);
4160 if (mask)
4161 {
4162 if (w->mapNum && (mask & (CWWidth | CWHeight)))
4163 sendSyncRequest (w);
4164
4165 configureXWindow (w, mask, &xwc);
4166 }
4167 }
4168
4169 static int
addWindowStackChanges(CompWindow * w,XWindowChanges * xwc,CompWindow * sibling)4170 addWindowStackChanges (CompWindow *w,
4171 XWindowChanges *xwc,
4172 CompWindow *sibling)
4173 {
4174 int mask = 0;
4175
4176 if (!sibling || sibling->id != w->id)
4177 {
4178 CompWindow *prev = w->prev;
4179
4180 /* the frame window is always our next sibling window in the stack,
4181 although we're searching for the next 'real' sibling, so skip
4182 the frame window */
4183 if (prev && prev->id == w->frame)
4184 prev = prev->prev;
4185
4186 if (prev)
4187 {
4188 if (!sibling)
4189 {
4190 XLowerWindow (w->screen->display->display, w->id);
4191 if (w->frame)
4192 XLowerWindow (w->screen->display->display, w->frame);
4193 }
4194 else if (sibling->id != prev->id)
4195 {
4196 mask |= CWSibling | CWStackMode;
4197
4198 xwc->stack_mode = Above;
4199 xwc->sibling = sibling->id;
4200 }
4201 }
4202 else if (sibling)
4203 {
4204 mask |= CWSibling | CWStackMode;
4205
4206 xwc->stack_mode = Above;
4207 xwc->sibling = sibling->id;
4208 }
4209 }
4210
4211 if (sibling && mask)
4212 {
4213 /* a normal window can be stacked above fullscreen windows but we
4214 don't want normal windows to be stacked above dock window so if
4215 the sibling we're stacking above is a fullscreen window we also
4216 update all dock windows. */
4217 if ((sibling->type & CompWindowTypeFullscreenMask) &&
4218 (!(w->type & (CompWindowTypeFullscreenMask |
4219 CompWindowTypeDockMask))) &&
4220 !isAncestorTo (w, sibling))
4221 {
4222 CompWindow *dw;
4223
4224 for (dw = w->screen->reverseWindows; dw; dw = dw->prev)
4225 if (dw == sibling)
4226 break;
4227
4228 for (; dw; dw = dw->prev)
4229 if (dw->type & CompWindowTypeDockMask)
4230 configureXWindow (dw, mask, xwc);
4231 }
4232 }
4233
4234 return mask;
4235 }
4236
4237 void
raiseWindow(CompWindow * w)4238 raiseWindow (CompWindow *w)
4239 {
4240 XWindowChanges xwc;
4241 int mask;
4242 Bool aboveFs = FALSE;
4243
4244 /* an active fullscreen window should be raised over all other
4245 windows in its layer */
4246 if (w->type & CompWindowTypeFullscreenMask)
4247 if (w->id == w->screen->display->activeWindow)
4248 aboveFs = TRUE;
4249
4250 mask = addWindowStackChanges (w, &xwc, findSiblingBelow (w, aboveFs));
4251 if (mask)
4252 configureXWindow (w, mask, &xwc);
4253 }
4254
4255 static CompWindow *
focusTopmostWindow(CompScreen * s)4256 focusTopmostWindow (CompScreen *s)
4257 {
4258 CompDisplay *d = s->display;
4259 CompWindow *w;
4260 CompWindow *focus = NULL;
4261
4262 for (w = s->reverseWindows; w; w = w->prev)
4263 {
4264 if (w->type & CompWindowTypeDockMask)
4265 continue;
4266
4267 if ((*s->focusWindow) (w))
4268 {
4269 focus = w;
4270 break;
4271 }
4272 }
4273
4274 if (focus)
4275 {
4276 if (focus->id != d->activeWindow)
4277 moveInputFocusToWindow (focus);
4278 }
4279 else
4280 XSetInputFocus (d->display, s->root, RevertToPointerRoot,
4281 CurrentTime);
4282
4283 return focus;
4284 }
4285
4286 void
lowerWindow(CompWindow * w)4287 lowerWindow (CompWindow *w)
4288 {
4289 XWindowChanges xwc;
4290 int mask;
4291 CompDisplay *d = w->screen->display;
4292
4293 mask = addWindowStackChanges (w, &xwc, findLowestSiblingBelow (w));
4294 if (mask)
4295 configureXWindow (w, mask, &xwc);
4296
4297 /* when lowering a window, focus the topmost window if the click-to-focus option is on */
4298 if (d->opt[COMP_DISPLAY_OPTION_CLICK_TO_FOCUS].value.b)
4299 {
4300 Window aboveId = w->prev ? w->prev->id : None;
4301 CompWindow *focusedWindow;
4302
4303 unhookWindowFromScreen (w->screen, w);
4304 focusedWindow = focusTopmostWindow (w->screen);
4305 insertWindowIntoScreen (w->screen, w, aboveId);
4306
4307 /* if the newly focused window is a desktop window,
4308 give the focus back to w */
4309 if (focusedWindow && focusedWindow->type & CompWindowTypeDesktopMask)
4310 moveInputFocusToWindow (w);
4311 }
4312 }
4313
4314 void
restackWindowAbove(CompWindow * w,CompWindow * sibling)4315 restackWindowAbove (CompWindow *w,
4316 CompWindow *sibling)
4317 {
4318 for (; sibling; sibling = sibling->next)
4319 if (validSiblingBelow (w, sibling))
4320 break;
4321
4322 if (sibling)
4323 {
4324 XWindowChanges xwc;
4325 int mask;
4326
4327 mask = addWindowStackChanges (w, &xwc, sibling);
4328 if (mask)
4329 configureXWindow (w, mask, &xwc);
4330 }
4331 }
4332
4333 /* finds the highest window under sibling we can stack above */
4334 static CompWindow *
findValidStackSiblingBelow(CompWindow * w,CompWindow * sibling)4335 findValidStackSiblingBelow (CompWindow *w,
4336 CompWindow *sibling)
4337 {
4338 CompWindow *lowest, *last, *p;
4339
4340 /* check whether we're actually allowed to stack under sibling by
4341 finding the sibling above 'sibling' and checking whether we're
4342 allowed to stack under that - if not, there's no valid sibling
4343 under it */
4344 for (p = sibling; p; p = p->next)
4345 {
4346 if (!avoidStackingRelativeTo (p))
4347 {
4348 if (!validSiblingBelow (p, w))
4349 return NULL;
4350 break;
4351 }
4352 }
4353
4354 /* get lowest sibling we're allowed to stack above */
4355 lowest = last = findLowestSiblingBelow (w);
4356
4357 /* walk from bottom up */
4358 for (p = w->screen->windows; p; p = p->next)
4359 {
4360 /* stop walking when we reach the sibling we should try to stack
4361 below */
4362 if (p == sibling)
4363 return lowest;
4364
4365 /* skip windows that we should avoid */
4366 if (w == p || avoidStackingRelativeTo (p))
4367 continue;
4368
4369 if (validSiblingBelow (w, p))
4370 {
4371 /* update lowest as we find windows below sibling that we're
4372 allowed to stack above. last window must be equal to the
4373 lowest as we shouldn't update lowest if we passed an
4374 invalid window */
4375 if (last == lowest)
4376 lowest = p;
4377 }
4378
4379 /* update last pointer */
4380 last = p;
4381 }
4382
4383 return lowest;
4384 }
4385
4386 void
restackWindowBelow(CompWindow * w,CompWindow * sibling)4387 restackWindowBelow (CompWindow *w,
4388 CompWindow *sibling)
4389 {
4390 XWindowChanges xwc;
4391 unsigned int mask;
4392
4393 mask = addWindowStackChanges (w, &xwc,
4394 findValidStackSiblingBelow (w, sibling));
4395
4396 if (mask)
4397 configureXWindow (w, mask, &xwc);
4398 }
4399
4400 void
updateWindowAttributes(CompWindow * w,CompStackingUpdateMode stackingMode)4401 updateWindowAttributes (CompWindow *w,
4402 CompStackingUpdateMode stackingMode)
4403 {
4404 XWindowChanges xwc;
4405 int mask = 0;
4406
4407 if (w->attrib.override_redirect || !w->managed)
4408 return;
4409
4410 if (w->state & CompWindowStateShadedMask)
4411 {
4412 hideWindow (w);
4413 }
4414 else if (w->shaded)
4415 {
4416 showWindow (w);
4417 }
4418
4419 if (stackingMode != CompStackingUpdateModeNone)
4420 {
4421 Bool aboveFs;
4422 CompWindow *sibling;
4423
4424 aboveFs = (stackingMode == CompStackingUpdateModeAboveFullscreen);
4425 if (w->type & CompWindowTypeFullscreenMask)
4426 {
4427 /* put active or soon-to-be-active fullscreen windows over
4428 all others in their layer */
4429 if (w->id == w->screen->display->activeWindow)
4430 {
4431 aboveFs = TRUE;
4432 }
4433 }
4434
4435 /* put windows that are just mapped, over fullscreen windows */
4436 if (stackingMode == CompStackingUpdateModeInitialMap)
4437 aboveFs = TRUE;
4438
4439 sibling = findSiblingBelow (w, aboveFs);
4440
4441 if (sibling &&
4442 (stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
4443 {
4444 CompWindow *p;
4445
4446 for (p = sibling; p; p = p->prev)
4447 if (p->id == w->screen->display->activeWindow)
4448 break;
4449
4450 /* window is above active window so we should lower it, assuming that
4451 * is allowed (if, for example, our window has the "above" state,
4452 * then lowering beneath the active window may not be allowed.)
4453 */
4454 if (p && validSiblingBelow (p, w))
4455 {
4456 p = findValidStackSiblingBelow (sibling, p);
4457
4458 /* if we found a valid sibling under the active window, it's
4459 our new sibling we want to stack above */
4460 if (p)
4461 sibling = p;
4462 }
4463 }
4464
4465 mask |= addWindowStackChanges (w, &xwc, sibling);
4466 }
4467
4468 if ((stackingMode == CompStackingUpdateModeInitialMap) ||
4469 (stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
4470 {
4471 /* If we are called from the MapRequest handler, we have to
4472 immediately update the internal stack. If we don't do that,
4473 the internal stacking order is invalid until the ConfigureNotify
4474 arrives because we put the window at the top of the stack when
4475 it was created */
4476 if (mask & CWStackMode)
4477 {
4478 Window above = (mask & CWSibling) ? xwc.sibling : 0;
4479 restackWindow (w, above);
4480 }
4481 }
4482
4483 mask |= addWindowSizeChanges (w, &xwc,
4484 w->serverX, w->serverY,
4485 w->serverWidth, w->serverHeight,
4486 w->serverBorderWidth);
4487
4488 if (w->mapNum && (mask & (CWWidth | CWHeight)))
4489 sendSyncRequest (w);
4490
4491 if (mask)
4492 configureXWindow (w, mask, &xwc);
4493 }
4494
4495 static void
ensureWindowVisibility(CompWindow * w)4496 ensureWindowVisibility (CompWindow *w)
4497 {
4498 int x1, y1, x2, y2;
4499 int width = w->serverWidth + w->serverBorderWidth * 2;
4500 int height = w->serverHeight + w->serverBorderWidth * 2;
4501 int dx = 0;
4502 int dy = 0;
4503
4504 if (w->struts || w->attrib.override_redirect)
4505 return;
4506
4507 if (w->type & (CompWindowTypeDockMask |
4508 CompWindowTypeFullscreenMask |
4509 CompWindowTypeUnknownMask))
4510 return;
4511
4512 x1 = w->screen->workArea.x - w->screen->width * w->screen->x;
4513 y1 = w->screen->workArea.y - w->screen->height * w->screen->y;
4514 x2 = x1 + w->screen->workArea.width + w->screen->hsize * w->screen->width;
4515 y2 = y1 + w->screen->workArea.height + w->screen->vsize * w->screen->height;
4516
4517 if (w->serverX - w->input.left >= x2)
4518 dx = (x2 - 25) - w->serverX;
4519 else if (w->serverX + width + w->input.right <= x1)
4520 dx = (x1 + 25) - (w->serverX + width);
4521
4522 if (w->serverY - w->input.top >= y2)
4523 dy = (y2 - 25) - w->serverY;
4524 else if (w->serverY + height + w->input.bottom <= y1)
4525 dy = (y1 + 25) - (w->serverY + height);
4526
4527 if (dx || dy)
4528 {
4529 XWindowChanges xwc;
4530
4531 xwc.x = w->serverX + dx;
4532 xwc.y = w->serverY + dy;
4533
4534 configureXWindow (w, CWX | CWY, &xwc);
4535 }
4536 }
4537
4538 static void
revealWindow(CompWindow * w)4539 revealWindow (CompWindow *w)
4540 {
4541 if (w->minimized)
4542 unminimizeWindow (w);
4543
4544 (*w->screen->leaveShowDesktopMode) (w->screen, w);
4545 }
4546
4547 static void
revealAncestors(CompWindow * w,void * closure)4548 revealAncestors (CompWindow *w,
4549 void *closure)
4550 {
4551 CompWindow *transient = closure;
4552
4553 if (isAncestorTo (transient, w))
4554 {
4555 forEachWindowOnScreen (w->screen, revealAncestors, (void *) w);
4556 revealWindow (w);
4557 }
4558 }
4559
4560 void
activateWindow(CompWindow * w)4561 activateWindow (CompWindow *w)
4562 {
4563 setCurrentDesktop (w->screen, w->desktop);
4564
4565 forEachWindowOnScreen (w->screen, revealAncestors, (void *) w);
4566 revealWindow (w);
4567
4568 if (w->state & CompWindowStateHiddenMask)
4569 {
4570 w->state &= ~CompWindowStateShadedMask;
4571 if (w->shaded)
4572 showWindow (w);
4573 }
4574
4575 if (w->state & CompWindowStateHiddenMask)
4576 return;
4577
4578 if (!onCurrentDesktop (w))
4579 return;
4580
4581 ensureWindowVisibility (w);
4582 updateWindowAttributes (w, CompStackingUpdateModeAboveFullscreen);
4583 moveInputFocusToWindow (w);
4584 }
4585
4586 void
closeWindow(CompWindow * w,Time serverTime)4587 closeWindow (CompWindow *w,
4588 Time serverTime)
4589 {
4590 CompDisplay *display = w->screen->display;
4591
4592 if (serverTime == 0)
4593 serverTime = getCurrentTimeFromDisplay (display);
4594
4595 if (w->alive)
4596 {
4597 if (w->protocols & CompWindowProtocolDeleteMask)
4598 {
4599 XEvent ev;
4600
4601 ev.type = ClientMessage;
4602 ev.xclient.window = w->id;
4603 ev.xclient.message_type = display->wmProtocolsAtom;
4604 ev.xclient.format = 32;
4605 ev.xclient.data.l[0] = display->wmDeleteWindowAtom;
4606 ev.xclient.data.l[1] = serverTime;
4607 ev.xclient.data.l[2] = 0;
4608 ev.xclient.data.l[3] = 0;
4609 ev.xclient.data.l[4] = 0;
4610
4611 XSendEvent (display->display, w->id, FALSE, NoEventMask, &ev);
4612 }
4613 else
4614 {
4615 XKillClient (display->display, w->id);
4616 }
4617
4618 w->closeRequests++;
4619 }
4620 else
4621 {
4622 toolkitAction (w->screen,
4623 w->screen->display->toolkitActionForceQuitDialogAtom,
4624 serverTime,
4625 w->id,
4626 TRUE,
4627 0,
4628 0);
4629 }
4630
4631 w->lastCloseRequestTime = serverTime;
4632 }
4633
4634 #define PVertResizeInc (1 << 0)
4635 #define PHorzResizeInc (1 << 1)
4636
4637 Bool
constrainNewWindowSize(CompWindow * w,int width,int height,int * newWidth,int * newHeight)4638 constrainNewWindowSize (CompWindow *w,
4639 int width,
4640 int height,
4641 int *newWidth,
4642 int *newHeight)
4643 {
4644 CompDisplay *d = w->screen->display;
4645 const XSizeHints *hints = &w->sizeHints;
4646 int oldWidth = width;
4647 int oldHeight = height;
4648 int min_width = 0;
4649 int min_height = 0;
4650 int base_width = 0;
4651 int base_height = 0;
4652 int xinc = 1;
4653 int yinc = 1;
4654 int max_width = MAXSHORT;
4655 int max_height = MAXSHORT;
4656 long flags = hints->flags;
4657 long resizeIncFlags = (flags & PResizeInc) ? ~0 : 0;
4658
4659 if (d->opt[COMP_DISPLAY_OPTION_IGNORE_HINTS_WHEN_MAXIMIZED].value.b)
4660 {
4661 if (w->state & MAXIMIZE_STATE)
4662 {
4663 flags &= ~PAspect;
4664
4665 if (w->state & CompWindowStateMaximizedHorzMask)
4666 resizeIncFlags &= ~PHorzResizeInc;
4667
4668 if (w->state & CompWindowStateMaximizedVertMask)
4669 resizeIncFlags &= ~PVertResizeInc;
4670 }
4671 }
4672
4673 /* Ater gdk_window_constrain_size(), which is partially borrowed from fvwm.
4674 *
4675 * Copyright 1993, Robert Nation
4676 * You may use this code for any purpose, as long as the original
4677 * copyright remains in the source code and all documentation
4678 *
4679 * which in turn borrows parts of the algorithm from uwm
4680 */
4681
4682 #define FLOOR(value, base) (((int) ((value) / (base))) * (base))
4683 #define FLOOR64(value, base) (((uint64_t) ((value) / (base))) * (base))
4684 #define CLAMP(v, min, max) ((v) <= (min) ? (min) : (v) >= (max) ? (max) : (v))
4685
4686 if ((flags & PBaseSize) && (flags & PMinSize))
4687 {
4688 base_width = hints->base_width;
4689 base_height = hints->base_height;
4690 min_width = hints->min_width;
4691 min_height = hints->min_height;
4692 }
4693 else if (flags & PBaseSize)
4694 {
4695 base_width = hints->base_width;
4696 base_height = hints->base_height;
4697 min_width = hints->base_width;
4698 min_height = hints->base_height;
4699 }
4700 else if (flags & PMinSize)
4701 {
4702 base_width = hints->min_width;
4703 base_height = hints->min_height;
4704 min_width = hints->min_width;
4705 min_height = hints->min_height;
4706 }
4707
4708 if (flags & PMaxSize)
4709 {
4710 max_width = hints->max_width;
4711 max_height = hints->max_height;
4712 }
4713
4714 if (resizeIncFlags & PHorzResizeInc)
4715 xinc = MAX (xinc, hints->width_inc);
4716
4717 if (resizeIncFlags & PVertResizeInc)
4718 yinc = MAX (yinc, hints->height_inc);
4719
4720 /* clamp width and height to min and max values */
4721 width = CLAMP (width, min_width, max_width);
4722 height = CLAMP (height, min_height, max_height);
4723
4724 /* shrink to base + N * inc */
4725 width = base_width + FLOOR (width - base_width, xinc);
4726 height = base_height + FLOOR (height - base_height, yinc);
4727
4728 /* constrain aspect ratio, according to:
4729 *
4730 * min_aspect.x width max_aspect.x
4731 * ------------ <= -------- <= -----------
4732 * min_aspect.y height max_aspect.y
4733 */
4734 if ((flags & PAspect) && hints->min_aspect.y > 0 && hints->max_aspect.x > 0)
4735 {
4736 /* Use 64 bit arithmetic to prevent overflow */
4737
4738 uint64_t min_aspect_x = hints->min_aspect.x;
4739 uint64_t min_aspect_y = hints->min_aspect.y;
4740 uint64_t max_aspect_x = hints->max_aspect.x;
4741 uint64_t max_aspect_y = hints->max_aspect.y;
4742 uint64_t delta;
4743
4744 if (min_aspect_x * height > width * min_aspect_y)
4745 {
4746 delta = FLOOR64 (height - width * min_aspect_y / min_aspect_x,
4747 yinc);
4748 if (height - delta >= min_height)
4749 height -= delta;
4750 else
4751 {
4752 delta = FLOOR64 (height * min_aspect_x / min_aspect_y - width,
4753 xinc);
4754 if (width + delta <= max_width)
4755 width += delta;
4756 }
4757 }
4758
4759 if (width * max_aspect_y > max_aspect_x * height)
4760 {
4761 delta = FLOOR64 (width - height * max_aspect_x / max_aspect_y,
4762 xinc);
4763 if (width - delta >= min_width)
4764 width -= delta;
4765 else
4766 {
4767 delta = FLOOR64 (width * min_aspect_y / min_aspect_x - height,
4768 yinc);
4769 if (height + delta <= max_height)
4770 height += delta;
4771 }
4772 }
4773 }
4774
4775 #undef CLAMP
4776 #undef FLOOR64
4777 #undef FLOOR
4778
4779 if (width != oldWidth || height != oldHeight)
4780 {
4781 *newWidth = width;
4782 *newHeight = height;
4783
4784 return TRUE;
4785 }
4786
4787 return FALSE;
4788 }
4789
4790 void
hideWindow(CompWindow * w)4791 hideWindow (CompWindow *w)
4792 {
4793 Bool onDesktop = onCurrentDesktop (w);
4794
4795 if (!w->managed)
4796 return;
4797
4798 if (!w->minimized && !w->inShowDesktopMode && !w->hidden && onDesktop)
4799 {
4800 if (w->state & CompWindowStateShadedMask)
4801 {
4802 w->shaded = TRUE;
4803 }
4804 else
4805 {
4806 return;
4807 }
4808 }
4809 else
4810 {
4811 addWindowDamage (w);
4812
4813 w->shaded = FALSE;
4814
4815 if ((w->state & CompWindowStateShadedMask) && w->frame)
4816 XUnmapWindow (w->screen->display->display, w->frame);
4817 }
4818
4819 if (!w->pendingMaps && w->attrib.map_state != IsViewable)
4820 return;
4821
4822 w->pendingUnmaps++;
4823
4824 XUnmapWindow (w->screen->display->display, w->id);
4825
4826 if (w->minimized || w->inShowDesktopMode || w->hidden || w->shaded)
4827 changeWindowState (w, w->state | CompWindowStateHiddenMask);
4828
4829 if (w->shaded && w->id == w->screen->display->activeWindow)
4830 moveInputFocusToWindow (w);
4831 }
4832
4833 void
showWindow(CompWindow * w)4834 showWindow (CompWindow *w)
4835 {
4836 Bool onDesktop = onCurrentDesktop (w);
4837
4838 if (!w->managed)
4839 return;
4840
4841 if (w->minimized || w->inShowDesktopMode || w->hidden || !onDesktop)
4842 {
4843 /* no longer hidden but not on current desktop */
4844 if (!w->minimized && !w->inShowDesktopMode && !w->hidden)
4845 changeWindowState (w, w->state & ~CompWindowStateHiddenMask);
4846
4847 return;
4848 }
4849
4850 /* transition from minimized to shaded */
4851 if (w->state & CompWindowStateShadedMask)
4852 {
4853 w->shaded = TRUE;
4854
4855 if (w->frame)
4856 XMapWindow (w->screen->display->display, w->frame);
4857
4858 if (w->height)
4859 resizeWindow (w,
4860 w->attrib.x, w->attrib.y,
4861 w->attrib.width, ++w->attrib.height - 1,
4862 w->attrib.border_width);
4863
4864 addWindowDamage (w);
4865
4866 return;
4867 }
4868 else
4869 {
4870 w->shaded = FALSE;
4871 }
4872
4873 w->pendingMaps++;
4874
4875 XMapWindow (w->screen->display->display, w->id);
4876
4877 changeWindowState (w, w->state & ~CompWindowStateHiddenMask);
4878 setWindowState (w->screen->display, w->state, w->id);
4879 }
4880
4881 static void
minimizeTransients(CompWindow * w,void * closure)4882 minimizeTransients (CompWindow *w,
4883 void *closure)
4884 {
4885 CompWindow *ancestor = closure;
4886
4887 if (w->transientFor == ancestor->id ||
4888 isGroupTransient (w, ancestor->clientLeader))
4889 {
4890 minimizeWindow (w);
4891 }
4892 }
4893
4894 void
minimizeWindow(CompWindow * w)4895 minimizeWindow (CompWindow *w)
4896 {
4897 if (!w->managed)
4898 return;
4899
4900 if (!w->minimized)
4901 {
4902 w->minimized = TRUE;
4903
4904 forEachWindowOnScreen (w->screen, minimizeTransients, (void *) w);
4905
4906 hideWindow (w);
4907 }
4908 }
4909
4910 static void
unminimizeTransients(CompWindow * w,void * closure)4911 unminimizeTransients (CompWindow *w,
4912 void *closure)
4913 {
4914 CompWindow *ancestor = closure;
4915
4916 if (w->transientFor == ancestor->id ||
4917 isGroupTransient (w, ancestor->clientLeader))
4918 unminimizeWindow (w);
4919 }
4920
4921 void
unminimizeWindow(CompWindow * w)4922 unminimizeWindow (CompWindow *w)
4923 {
4924 if (w->minimized)
4925 {
4926 w->minimized = FALSE;
4927
4928 showWindow (w);
4929
4930 forEachWindowOnScreen (w->screen, unminimizeTransients, (void *) w);
4931 }
4932 }
4933
4934 void
maximizeWindow(CompWindow * w,int state)4935 maximizeWindow (CompWindow *w,
4936 int state)
4937 {
4938 if (w->attrib.override_redirect)
4939 return;
4940
4941 state = constrainWindowState (state, w->actions);
4942
4943 state &= MAXIMIZE_STATE;
4944
4945 if (state == (w->state & MAXIMIZE_STATE))
4946 return;
4947
4948 state |= (w->state & ~MAXIMIZE_STATE);
4949
4950 changeWindowState (w, state);
4951 updateWindowAttributes (w, CompStackingUpdateModeNone);
4952 }
4953
4954 Bool
getWindowUserTime(CompWindow * w,Time * time)4955 getWindowUserTime (CompWindow *w,
4956 Time *time)
4957 {
4958 Atom actual;
4959 int result, format;
4960 unsigned long n, left;
4961 unsigned char *data;
4962 Bool retval = FALSE;
4963
4964 result = XGetWindowProperty (w->screen->display->display, w->id,
4965 w->screen->display->wmUserTimeAtom,
4966 0L, 1L, False, XA_CARDINAL, &actual, &format,
4967 &n, &left, &data);
4968
4969 if (result == Success && data)
4970 {
4971 if (n)
4972 {
4973 CARD32 value;
4974
4975 memcpy (&value, data, sizeof (CARD32));
4976 retval = TRUE;
4977 *time = (Time) value;
4978 }
4979
4980 XFree ((void *) data);
4981 }
4982
4983 return retval;
4984 }
4985
4986 void
setWindowUserTime(CompWindow * w,Time time)4987 setWindowUserTime (CompWindow *w,
4988 Time time)
4989 {
4990 CARD32 value = (CARD32) time;
4991
4992 XChangeProperty (w->screen->display->display, w->id,
4993 w->screen->display->wmUserTimeAtom,
4994 XA_CARDINAL, 32, PropModeReplace,
4995 (unsigned char *) &value, 1);
4996 }
4997
4998 /*
4999 * Macros from metacity
5000 *
5001 * Xserver time can wraparound, thus comparing two timestamps needs to
5002 * take this into account. Here's a little macro to help out. If no
5003 * wraparound has occurred, this is equivalent to
5004 * time1 < time2
5005 * Of course, the rest of the ugliness of this macro comes from
5006 * accounting for the fact that wraparound can occur and the fact that
5007 * a timestamp of 0 must be special-cased since it means older than
5008 * anything else.
5009 *
5010 * Note that this is NOT an equivalent for time1 <= time2; if that's
5011 * what you need then you'll need to swap the order of the arguments
5012 * and negate the result.
5013 */
5014 #define XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) \
5015 ( (( (time1) < (time2) ) && \
5016 ( (time2) - (time1) < ((unsigned long) -1) / 2 )) || \
5017 (( (time1) > (time2) ) && \
5018 ( (time1) - (time2) > ((unsigned long) -1) / 2 )) \
5019 )
5020 #define XSERVER_TIME_IS_BEFORE(time1, time2) \
5021 ( (time1) == 0 || \
5022 (XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS (time1, time2) && \
5023 (time2) != 0) \
5024 )
5025
5026 static Bool
getUsageTimestampForWindow(CompWindow * w,Time * timestamp)5027 getUsageTimestampForWindow (CompWindow *w,
5028 Time *timestamp)
5029 {
5030 if (getWindowUserTime (w, timestamp))
5031 return TRUE;
5032
5033 if (w->initialTimestampSet)
5034 {
5035 *timestamp = w->initialTimestamp;
5036 return TRUE;
5037 }
5038
5039 return FALSE;
5040 }
5041
5042 static Bool
getFocusWindowUsageTimestamp(CompWindow * w,Time * timestamp)5043 getFocusWindowUsageTimestamp (CompWindow *w,
5044 Time *timestamp)
5045 {
5046 if (getUsageTimestampForWindow (w, timestamp))
5047 return TRUE;
5048
5049 /* if we got no timestamp for the window, try to get at least a timestamp
5050 for its transient parent, if any */
5051 if (w->transientFor)
5052 {
5053 CompWindow *parent;
5054
5055 parent = findWindowAtScreen (w->screen, w->transientFor);
5056 if (parent && getUsageTimestampForWindow (parent, timestamp))
5057 return TRUE;
5058 }
5059
5060 return FALSE;
5061 }
5062
5063 static Bool
isWindowFocusAllowed(CompWindow * w,unsigned int viewportX,unsigned int viewportY,Time timestamp)5064 isWindowFocusAllowed (CompWindow *w,
5065 unsigned int viewportX,
5066 unsigned int viewportY,
5067 Time timestamp)
5068 {
5069 CompDisplay *d = w->screen->display;
5070 CompScreen *s = w->screen;
5071 CompWindow *active;
5072 Time aUserTime;
5073 CompMatch *match;
5074 int level, vx, vy;
5075
5076 level = s->opt[COMP_SCREEN_OPTION_FOCUS_PREVENTION_LEVEL].value.i;
5077
5078 if (level == FOCUS_PREVENTION_LEVEL_NONE)
5079 return TRUE;
5080
5081 /* allow focus for excluded windows */
5082 match = &s->opt[COMP_SCREEN_OPTION_FOCUS_PREVENTION_MATCH].value.match;
5083 if (!matchEval (match, w))
5084 return TRUE;
5085
5086 if (level == FOCUS_PREVENTION_LEVEL_VERYHIGH)
5087 return FALSE;
5088
5089 active = findWindowAtDisplay (d, d->activeWindow);
5090
5091 /* no active window */
5092 if (!active || (active->type & CompWindowTypeDesktopMask))
5093 return TRUE;
5094
5095 /* active window belongs to same application */
5096 if (w->clientLeader == active->clientLeader)
5097 return TRUE;
5098
5099 if (level == FOCUS_PREVENTION_LEVEL_HIGH)
5100 return FALSE;
5101
5102 /* not in current viewport or desktop */
5103 if (!onCurrentDesktop (w))
5104 return FALSE;
5105
5106 defaultViewportForWindow (w, &vx, &vy);
5107 if (vx != viewportX || vy != viewportY)
5108 return FALSE;
5109
5110 if (!timestamp)
5111 {
5112 /* unsure as we have nothing to compare - allow focus in low level,
5113 don't allow in normal level */
5114 if (level == FOCUS_PREVENTION_LEVEL_NORMAL)
5115 return FALSE;
5116
5117 return TRUE;
5118 }
5119
5120 /* can't get user time for active window */
5121 if (!getWindowUserTime (active, &aUserTime))
5122 return TRUE;
5123
5124 if (XSERVER_TIME_IS_BEFORE (timestamp, aUserTime))
5125 return FALSE;
5126
5127 return TRUE;
5128 }
5129
5130 CompFocusResult
allowWindowFocus(CompWindow * w,unsigned int noFocusMask,unsigned int viewportX,unsigned int viewportY,Time timestamp)5131 allowWindowFocus (CompWindow *w,
5132 unsigned int noFocusMask,
5133 unsigned int viewportX,
5134 unsigned int viewportY,
5135 Time timestamp)
5136 {
5137 Bool status;
5138
5139 if (w->id == w->screen->display->activeWindow)
5140 return CompFocusAllowed;
5141
5142 /* do not focus windows of these types */
5143 if (w->type & noFocusMask)
5144 return CompFocusPrevent;
5145
5146 /* window doesn't take focus */
5147 if (!w->inputHint && !(w->protocols & CompWindowProtocolTakeFocusMask))
5148 return CompFocusPrevent;
5149
5150 if (!timestamp)
5151 {
5152 /* if the window has a 0 timestamp, it explicitly requested no focus */
5153 if (getFocusWindowUsageTimestamp (w, ×tamp) && !timestamp)
5154 return CompFocusPrevent;
5155 }
5156
5157 status = isWindowFocusAllowed (w, viewportX, viewportY, timestamp);
5158 if (!status)
5159 {
5160 /* add demands attention state if focus was prevented */
5161 changeWindowState (w, w->state | CompWindowStateDemandsAttentionMask);
5162 return CompFocusDenied;
5163 }
5164
5165 return CompFocusAllowed;
5166 }
5167
5168 void
unredirectWindow(CompWindow * w)5169 unredirectWindow (CompWindow *w)
5170 {
5171 if (!w->redirected)
5172 return;
5173
5174 releaseWindow (w);
5175
5176 XCompositeUnredirectWindow (w->screen->display->display, w->id,
5177 CompositeRedirectManual);
5178
5179 w->redirected = FALSE;
5180 w->overlayWindow = TRUE;
5181 w->screen->overlayWindowCount++;
5182
5183 if (w->screen->overlayWindowCount > 0)
5184 updateOutputWindow (w->screen);
5185 }
5186
5187 void
redirectWindow(CompWindow * w)5188 redirectWindow (CompWindow *w)
5189 {
5190 if (w->redirected)
5191 return;
5192
5193 XCompositeRedirectWindow (w->screen->display->display, w->id,
5194 CompositeRedirectManual);
5195
5196 w->redirected = TRUE;
5197
5198 if (w->overlayWindow)
5199 {
5200 w->screen->overlayWindowCount--;
5201 w->overlayWindow = FALSE;
5202 }
5203
5204 if (w->screen->overlayWindowCount < 1)
5205 showOutputWindow (w->screen);
5206 else
5207 updateOutputWindow (w->screen);
5208 }
5209
5210 void
defaultViewportForWindow(CompWindow * w,int * vx,int * vy)5211 defaultViewportForWindow (CompWindow *w,
5212 int *vx,
5213 int *vy)
5214 {
5215 CompScreen *s = w->screen;
5216
5217 /* return the current viewport if a part of the window is
5218 visible on it */
5219 if ((w->serverX < s->width && w->serverX + w->serverWidth > 0) &&
5220 (w->serverY < s->height && w->serverY + w->serverHeight > 0))
5221 {
5222 if (vx)
5223 *vx = s->x;
5224
5225 if (vy)
5226 *vy = s->y;
5227
5228 return;
5229 }
5230
5231 viewportForGeometry (s,
5232 w->serverX, w->serverY,
5233 w->serverWidth, w->serverHeight,
5234 w->serverBorderWidth,
5235 vx, vy);
5236 }
5237
5238 static CARD32 *
allocateWindowIcon(CompWindow * w,unsigned int width,unsigned int height)5239 allocateWindowIcon (CompWindow *w,
5240 unsigned int width,
5241 unsigned int height)
5242 {
5243 CompIcon *icon, **pIcon;
5244
5245 icon = malloc (sizeof (CompIcon) +
5246 width * height * sizeof (CARD32));
5247 if (!icon)
5248 return NULL;
5249
5250 pIcon = realloc (w->icon, sizeof (CompIcon *) * (w->nIcon + 1));
5251 if (!pIcon)
5252 {
5253 free (icon);
5254 return NULL;
5255 }
5256
5257 w->icon = pIcon;
5258 w->icon[w->nIcon] = icon;
5259 w->nIcon++;
5260
5261 icon->width = width;
5262 icon->height = height;
5263
5264 initTexture (w->screen, &icon->texture);
5265
5266 return (CARD32 *) (icon + 1);
5267 }
5268
5269 static void
readWindowIconHint(CompWindow * w)5270 readWindowIconHint (CompWindow *w)
5271 {
5272 XImage *image, *maskImage = NULL;
5273 Display *dpy = w->screen->display->display;
5274 unsigned int width, height, dummy;
5275 int i, j, k, iDummy;
5276 Window wDummy;
5277 CARD32 *p;
5278 XColor *colors;
5279
5280 if (!XGetGeometry (dpy, w->hints->icon_pixmap, &wDummy, &iDummy,
5281 &iDummy, &width, &height, &dummy, &dummy))
5282 return;
5283
5284 image = XGetImage (dpy, w->hints->icon_pixmap, 0, 0, width, height,
5285 AllPlanes, ZPixmap);
5286 if (!image)
5287 return;
5288
5289 colors = malloc (width * height * sizeof (XColor));
5290 if (!colors)
5291 {
5292 XDestroyImage (image);
5293 return;
5294 }
5295
5296 k = 0;
5297 for (j = 0; j < height; j++)
5298 for (i = 0; i < width; i++)
5299 colors[k++].pixel = XGetPixel (image, i, j);
5300
5301 for (i = 0; i < k; i += 256)
5302 XQueryColors (dpy, w->screen->colormap,
5303 &colors[i], MIN (k - i, 256));
5304
5305 XDestroyImage (image);
5306
5307 p = allocateWindowIcon (w, width, height);
5308 if (!p)
5309 {
5310 free (colors);
5311 return;
5312 }
5313
5314 if (w->hints->flags & IconMaskHint)
5315 maskImage = XGetImage (dpy, w->hints->icon_mask, 0, 0,
5316 width, height, AllPlanes, ZPixmap);
5317
5318 k = 0;
5319 for (j = 0; j < height; j++)
5320 {
5321 for (i = 0; i < width; i++)
5322 {
5323 if (maskImage && !XGetPixel (maskImage, i, j))
5324 *p++ = 0;
5325 else if (image->depth == 1)
5326 *p++ = colors[k].pixel ? 0xffffffff : 0xff000000;
5327 else
5328 *p++ = 0xff000000 | /* alpha */
5329 (((colors[k].red >> 8) & 0xff) << 16) | /* red */
5330 (((colors[k].green >> 8) & 0xff) << 8) | /* green */
5331 ((colors[k].blue >> 8) & 0xff); /* blue */
5332
5333 k++;
5334 }
5335 }
5336
5337 free (colors);
5338 if (maskImage)
5339 XDestroyImage (maskImage);
5340 }
5341
5342 /* returns icon with dimensions as close as possible to width and height
5343 but never greater. */
5344 CompIcon *
getWindowIcon(CompWindow * w,int width,int height)5345 getWindowIcon (CompWindow *w,
5346 int width,
5347 int height)
5348 {
5349 CompIcon *icon;
5350 int i, wh, diff, oldDiff;
5351
5352 /* need to fetch icon property */
5353 if (w->nIcon == 0)
5354 {
5355 Atom actual;
5356 int result, format;
5357 unsigned long n, left;
5358 unsigned char *data;
5359
5360 result = XGetWindowProperty (w->screen->display->display, w->id,
5361 w->screen->display->wmIconAtom,
5362 0L, 65536L,
5363 FALSE, XA_CARDINAL,
5364 &actual, &format, &n,
5365 &left, &data);
5366
5367 if (result == Success && data)
5368 {
5369 CARD32 *p;
5370 CARD32 alpha, red, green, blue;
5371 unsigned long iw, ih;
5372
5373 for (i = 0; i + 2 < n; i += iw * ih + 2)
5374 {
5375 unsigned long *idata = (unsigned long *) data;
5376 unsigned long j;
5377
5378 iw = idata[i];
5379 ih = idata[i + 1];
5380
5381 /* iw * ih may be larger than the value range of unsigned
5382 long, so better do some checking for extremely weird
5383 icon sizes first */
5384 if (iw > 2048 || ih > 2048 || iw * ih + 2 > n - i)
5385 break;
5386
5387 if (iw && ih)
5388 {
5389 p = allocateWindowIcon (w, iw, ih);
5390 if (!p)
5391 continue;
5392
5393 /* EWMH doesn't say if icon data is premultiplied or
5394 not but most applications seem to assume data should
5395 be unpremultiplied. */
5396 for (j = 0; j < iw * ih; j++)
5397 {
5398 alpha = (idata[i + j + 2] >> 24) & 0xff;
5399 red = (idata[i + j + 2] >> 16) & 0xff;
5400 green = (idata[i + j + 2] >> 8) & 0xff;
5401 blue = (idata[i + j + 2] >> 0) & 0xff;
5402
5403 red = (red * alpha) >> 8;
5404 green = (green * alpha) >> 8;
5405 blue = (blue * alpha) >> 8;
5406
5407 p[j] =
5408 (alpha << 24) |
5409 (red << 16) |
5410 (green << 8) |
5411 (blue << 0);
5412 }
5413 }
5414 }
5415
5416 XFree (data);
5417 }
5418 else if (w->hints && (w->hints->flags & IconPixmapHint))
5419 readWindowIconHint (w);
5420
5421 /* don't fetch property again */
5422 if (w->nIcon == 0)
5423 w->nIcon = -1;
5424 }
5425
5426 /* no icons available for this window */
5427 if (w->nIcon == -1)
5428 return NULL;
5429
5430 icon = NULL;
5431 wh = width + height;
5432
5433 for (i = 0; i < w->nIcon; i++)
5434 {
5435 if (w->icon[i]->width > width || w->icon[i]->height > height)
5436 continue;
5437
5438 if (icon)
5439 {
5440 diff = wh - (w->icon[i]->width + w->icon[i]->height);
5441 oldDiff = wh - (icon->width + icon->height);
5442
5443 if (diff < oldDiff)
5444 icon = w->icon[i];
5445 }
5446 else
5447 icon = w->icon[i];
5448 }
5449
5450 return icon;
5451 }
5452
5453 void
freeWindowIcons(CompWindow * w)5454 freeWindowIcons (CompWindow *w)
5455 {
5456 int i;
5457
5458 for (i = 0; i < w->nIcon; i++)
5459 {
5460 finiTexture (w->screen, &w->icon[i]->texture);
5461 free (w->icon[i]);
5462 }
5463
5464 if (w->icon)
5465 {
5466 free (w->icon);
5467 w->icon = NULL;
5468 }
5469
5470 w->nIcon = 0;
5471 }
5472
5473 int
outputDeviceForWindow(CompWindow * w)5474 outputDeviceForWindow (CompWindow *w)
5475 {
5476 return outputDeviceForGeometry (w->screen,
5477 w->serverX, w->serverY,
5478 w->serverWidth, w->serverHeight,
5479 w->serverBorderWidth);
5480 }
5481
5482 Bool
onCurrentDesktop(CompWindow * w)5483 onCurrentDesktop (CompWindow *w)
5484 {
5485 if (w->desktop == 0xffffffff || w->desktop == w->screen->currentDesktop)
5486 return TRUE;
5487
5488 return FALSE;
5489 }
5490
5491 void
setDesktopForWindow(CompWindow * w,unsigned int desktop)5492 setDesktopForWindow (CompWindow *w,
5493 unsigned int desktop)
5494 {
5495 if (desktop != 0xffffffff)
5496 {
5497 if (w->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5498 return;
5499
5500 if (desktop >= w->screen->nDesktop)
5501 return;
5502 }
5503
5504 if (desktop == w->desktop)
5505 return;
5506
5507 w->desktop = desktop;
5508
5509 if (desktop == 0xffffffff || desktop == w->screen->currentDesktop)
5510 showWindow (w);
5511 else
5512 hideWindow (w);
5513
5514 setWindowProp (w->screen->display, w->id,
5515 w->screen->display->winDesktopAtom,
5516 w->desktop);
5517 }
5518
5519 /* The compareWindowActiveness function compares the two windows 'w1'
5520 and 'w2'. It returns an integer less than, equal to, or greater
5521 than zero if 'w1' is found, respectively, to activated longer time
5522 ago than, to be activated at the same time, or be activated more
5523 recently than 'w2'. */
5524 int
compareWindowActiveness(CompWindow * w1,CompWindow * w2)5525 compareWindowActiveness (CompWindow *w1,
5526 CompWindow *w2)
5527 {
5528 CompScreen *s = w1->screen;
5529 CompActiveWindowHistory *history = &s->history[s->currentHistory];
5530 int i;
5531
5532 /* check current window history first */
5533 for (i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
5534 {
5535 if (history->id[i] == w1->id)
5536 return 1;
5537
5538 if (history->id[i] == w2->id)
5539 return -1;
5540
5541 if (!history->id[i])
5542 break;
5543 }
5544
5545 return w1->activeNum - w2->activeNum;
5546 }
5547
5548 Bool
windowOnAllViewports(CompWindow * w)5549 windowOnAllViewports (CompWindow *w)
5550 {
5551 if (w->attrib.override_redirect)
5552 return TRUE;
5553
5554 if (!w->managed && w->attrib.map_state != IsViewable)
5555 return TRUE;
5556
5557 if (w->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5558 return TRUE;
5559
5560 if (w->state & CompWindowStateStickyMask)
5561 return TRUE;
5562
5563 return FALSE;
5564 }
5565
5566 void
getWindowMovementForOffset(CompWindow * w,int offX,int offY,int * retX,int * retY)5567 getWindowMovementForOffset (CompWindow *w,
5568 int offX,
5569 int offY,
5570 int *retX,
5571 int *retY)
5572 {
5573 CompScreen *s = w->screen;
5574 int m, vWidth, vHeight;
5575
5576 vWidth = s->width * s->hsize;
5577 vHeight = s->height * s->vsize;
5578
5579 offX %= s->width * s->hsize;
5580 offY %= s->height * s->vsize;
5581
5582 /* x */
5583 if (s->hsize == 1)
5584 {
5585 (*retX) = offX;
5586 }
5587 else
5588 {
5589 m = w->attrib.x + offX;
5590 if (m - w->input.left < s->width - vWidth)
5591 *retX = offX + vWidth;
5592 else if (m + w->width + w->input.right > vWidth)
5593 *retX = offX - vWidth;
5594 else
5595 *retX = offX;
5596 }
5597
5598 if (s->vsize == 1)
5599 {
5600 *retY = offY;
5601 }
5602 else
5603 {
5604 m = w->attrib.y + offY;
5605 if (m - w->input.top < s->height - vHeight)
5606 *retY = offY + vHeight;
5607 else if (m + w->height + w->input.bottom > vHeight)
5608 *retY = offY - vHeight;
5609 else
5610 *retY = offY;
5611 }
5612
5613 }
5614