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    = &reg.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, &reg);
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, &region.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 = &region.extents;
1650 	region.numRects = region.size = 1;
1651 
1652 	damageScreenRegion (w->screen, &region);
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, &timestamp) && !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