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 <stdlib.h>
27 #include <string.h>
28 
29 #include <X11/Xlib.h>
30 #include <X11/Xatom.h>
31 #include <X11/extensions/shape.h>
32 #include <X11/extensions/Xrandr.h>
33 #include <X11/extensions/Xfixes.h>
34 
35 #include <compiz-core.h>
36 
37 static Window xdndWindow = None;
38 static Window edgeWindow = None;
39 
40 static void
handleWindowDamageRect(CompWindow * w,int x,int y,int width,int height)41 handleWindowDamageRect (CompWindow *w,
42 			int	   x,
43 			int	   y,
44 			int	   width,
45 			int	   height)
46 {
47     REGION region;
48     Bool   initial = FALSE;
49 
50     if (!w->redirected || w->bindFailed)
51 	return;
52 
53     if (!w->damaged)
54     {
55 	w->damaged = initial = TRUE;
56 	w->invisible = WINDOW_INVISIBLE (w);
57     }
58 
59     region.extents.x1 = x;
60     region.extents.y1 = y;
61     region.extents.x2 = region.extents.x1 + width;
62     region.extents.y2 = region.extents.y1 + height;
63 
64     if (!(*w->screen->damageWindowRect) (w, initial, &region.extents))
65     {
66 	region.extents.x1 += w->attrib.x + w->attrib.border_width;
67 	region.extents.y1 += w->attrib.y + w->attrib.border_width;
68 	region.extents.x2 += w->attrib.x + w->attrib.border_width;
69 	region.extents.y2 += w->attrib.y + w->attrib.border_width;
70 
71 	region.rects = &region.extents;
72 	region.numRects = region.size = 1;
73 
74 	damageScreenRegion (w->screen, &region);
75     }
76 
77     if (initial)
78 	damageWindowOutputExtents (w);
79 }
80 
81 void
handleSyncAlarm(CompWindow * w)82 handleSyncAlarm (CompWindow *w)
83 {
84     if (w->syncWait)
85     {
86 	if (w->syncWaitHandle)
87 	{
88 	    compRemoveTimeout (w->syncWaitHandle);
89 	    w->syncWaitHandle = 0;
90 	}
91 
92 	w->syncWait = FALSE;
93 
94 	if (resizeWindow (w,
95 			  w->syncX, w->syncY,
96 			  w->syncWidth, w->syncHeight,
97 			  w->syncBorderWidth))
98 	{
99 	    XRectangle *rects;
100 	    int	       nDamage;
101 
102 	    nDamage = w->nDamage;
103 	    rects   = w->damageRects;
104 	    while (nDamage--)
105 	    {
106 		handleWindowDamageRect (w,
107 					rects[nDamage].x,
108 					rects[nDamage].y,
109 					rects[nDamage].width,
110 					rects[nDamage].height);
111 	    }
112 
113 	    w->nDamage = 0;
114 	}
115 	else
116 	{
117 	    /* resizeWindow failing means that there is another pending
118 	       resize and we must send a new sync request to the client */
119 	    sendSyncRequest (w);
120 	}
121     }
122 }
123 
124 static void
moveInputFocusToOtherWindow(CompWindow * w)125 moveInputFocusToOtherWindow (CompWindow *w)
126 {
127     CompScreen  *s = w->screen;
128     CompDisplay *d = s->display;
129     Bool        focussedAny = FALSE;
130 
131     if (w->id != d->activeWindow && w->id != d->nextActiveWindow)
132 	if (d->activeWindow != None)
133 	    return;
134 
135     if (w->transientFor && w->transientFor != s->root)
136     {
137 	CompWindow *ancestor = findWindowAtDisplay (d, w->transientFor);
138 	if (ancestor && !(ancestor->type & (CompWindowTypeDesktopMask |
139 					    CompWindowTypeDockMask)))
140 	{
141 	    moveInputFocusToWindow (ancestor);
142 	    focussedAny = TRUE;
143 	}
144     }
145     else if (w->type & (CompWindowTypeDialogMask |
146 			CompWindowTypeModalDialogMask))
147     {
148 	CompWindow *a, *focus = NULL;
149 
150 	for (a = s->reverseWindows; a; a = a->prev)
151 	{
152 	    if (a->clientLeader != w->clientLeader)
153 		continue;
154 
155 	    if (!(*s->focusWindow) (a))
156 		continue;
157 
158 	    if (!focus)
159 	    {
160 		focus = a;
161 		continue;
162 	    }
163 
164 	    if (a->type & (CompWindowTypeNormalMask |
165 			   CompWindowTypeDialogMask |
166 			   CompWindowTypeModalDialogMask))
167 	    {
168 		if (compareWindowActiveness (focus, a) < 0)
169 		    focus = a;
170 	    }
171 	}
172 
173 	if (focus && !(focus->type & (CompWindowTypeDesktopMask |
174 				      CompWindowTypeDockMask)))
175 	{
176 	    moveInputFocusToWindow (focus);
177 	    focussedAny = TRUE;
178 	}
179     }
180 
181     if (!focussedAny)
182 	focusDefaultWindow (s);
183 }
184 
185 static Bool
autoRaiseTimeout(void * closure)186 autoRaiseTimeout (void *closure)
187 {
188     CompDisplay *display = closure;
189     CompWindow  *w = findWindowAtDisplay (display, display->activeWindow);
190 
191     if (display->autoRaiseWindow == display->activeWindow ||
192 	(w && (display->autoRaiseWindow == w->transientFor)))
193     {
194 	w = findWindowAtDisplay (display, display->autoRaiseWindow);
195 	if (w)
196 	    updateWindowAttributes (w, CompStackingUpdateModeNormal);
197     }
198 
199     return FALSE;
200 }
201 
202 #define REAL_MOD_MASK (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | \
203 		       Mod3Mask | Mod4Mask | Mod5Mask | CompNoMask)
204 
205 static Bool
isCallBackBinding(CompOption * option,CompBindingType type,CompActionState state)206 isCallBackBinding (CompOption	   *option,
207 		   CompBindingType type,
208 		   CompActionState state)
209 {
210     if (!isActionOption (option))
211 	return FALSE;
212 
213     if (!(option->value.action.type & type))
214 	return FALSE;
215 
216     if (!(option->value.action.state & state))
217 	return FALSE;
218 
219     return TRUE;
220 }
221 
222 static Bool
isInitiateBinding(CompOption * option,CompBindingType type,CompActionState state,CompAction ** action)223 isInitiateBinding (CompOption	   *option,
224 		   CompBindingType type,
225 		   CompActionState state,
226 		   CompAction	   **action)
227 {
228     if (!isCallBackBinding (option, type, state))
229 	return FALSE;
230 
231     if (!option->value.action.initiate)
232 	return FALSE;
233 
234     *action = &option->value.action;
235 
236     return TRUE;
237 }
238 
239 static Bool
isTerminateBinding(CompOption * option,CompBindingType type,CompActionState state,CompAction ** action)240 isTerminateBinding (CompOption	    *option,
241 		    CompBindingType type,
242 		    CompActionState state,
243 		    CompAction      **action)
244 {
245     if (!isCallBackBinding (option, type, state))
246 	return FALSE;
247 
248     if (!option->value.action.terminate)
249 	return FALSE;
250 
251     *action = &option->value.action;
252 
253     return TRUE;
254 }
255 
256 static Bool
triggerButtonPressBindings(CompDisplay * d,CompOption * option,int nOption,XButtonEvent * event,CompOption * argument,int nArgument)257 triggerButtonPressBindings (CompDisplay  *d,
258 			    CompOption   *option,
259 			    int		 nOption,
260 			    XButtonEvent *event,
261 			    CompOption   *argument,
262 			    int		 nArgument)
263 {
264     CompActionState state = CompActionStateInitButton;
265     CompAction	    *action;
266     unsigned int    modMask = REAL_MOD_MASK & ~d->ignoredModMask;
267     unsigned int    bindMods;
268     unsigned int    edge = 0;
269 
270     if (edgeWindow)
271     {
272 	CompScreen   *s;
273 	unsigned int i;
274 
275 	s = findScreenAtDisplay (d, event->root);
276 	if (!s)
277 	    return FALSE;
278 
279 	if (event->window != edgeWindow)
280 	{
281 	    if (!s->maxGrab || event->window != s->root)
282 		return FALSE;
283 	}
284 
285 	for (i = 0; i < SCREEN_EDGE_NUM; i++)
286 	{
287 	    if (edgeWindow == s->screenEdge[i].id)
288 	    {
289 		edge = 1 << i;
290 		argument[1].value.i = d->activeWindow;
291 		break;
292 	    }
293 	}
294     }
295 
296     while (nOption--)
297     {
298 	if (isInitiateBinding (option, CompBindingTypeButton, state, &action))
299 	{
300 	    if (action->button.button == event->button)
301 	    {
302 		bindMods = virtualToRealModMask (d, action->button.modifiers);
303 
304 		if ((bindMods & modMask) == (event->state & modMask))
305 		    if ((*action->initiate) (d, action, state,
306 					     argument, nArgument))
307 			return TRUE;
308 	    }
309 	}
310 
311 	if (edge)
312 	{
313 	    if (isInitiateBinding (option, CompBindingTypeEdgeButton,
314 				   state | CompActionStateInitEdge, &action))
315 	    {
316 		if ((action->button.button == event->button) &&
317 		    (action->edgeMask & edge))
318 		{
319 		    bindMods = virtualToRealModMask (d,
320 						     action->button.modifiers);
321 
322 		    if ((bindMods & modMask) == (event->state & modMask))
323 			if ((*action->initiate) (d, action, state |
324 						 CompActionStateInitEdge,
325 						 argument, nArgument))
326 			    return TRUE;
327 		}
328 	    }
329 	}
330 
331 	option++;
332     }
333 
334     return FALSE;
335 }
336 
337 static Bool
triggerButtonReleaseBindings(CompDisplay * d,CompOption * option,int nOption,XButtonEvent * event,CompOption * argument,int nArgument)338 triggerButtonReleaseBindings (CompDisplay  *d,
339 			      CompOption   *option,
340 			      int	   nOption,
341 			      XButtonEvent *event,
342 			      CompOption   *argument,
343 			      int	   nArgument)
344 {
345     CompActionState state = CompActionStateTermButton;
346     CompBindingType type  = CompBindingTypeButton | CompBindingTypeEdgeButton;
347     CompAction	    *action;
348 
349     while (nOption--)
350     {
351 	if (isTerminateBinding (option, type, state, &action))
352 	{
353 	    if (action->button.button == event->button)
354 	    {
355 		if ((*action->terminate) (d, action, state,
356 					  argument, nArgument))
357 		    return TRUE;
358 	    }
359 	}
360 
361 	option++;
362     }
363 
364     return FALSE;
365 }
366 
367 static Bool
triggerKeyPressBindings(CompDisplay * d,CompOption * option,int nOption,XKeyEvent * event,CompOption * argument,int nArgument)368 triggerKeyPressBindings (CompDisplay *d,
369 			 CompOption  *option,
370 			 int	     nOption,
371 			 XKeyEvent   *event,
372 			 CompOption  *argument,
373 			 int	     nArgument)
374 {
375     CompActionState state = 0;
376     CompAction	    *action;
377     unsigned int    modMask = REAL_MOD_MASK & ~d->ignoredModMask;
378     unsigned int    bindMods;
379 
380     if (event->keycode == d->escapeKeyCode)
381 	state = CompActionStateCancel;
382     else if (event->keycode == d->returnKeyCode)
383 	state = CompActionStateCommit;
384 
385     if (state)
386     {
387 	CompOption *o = option;
388 	int	   n = nOption;
389 
390 	while (n--)
391 	{
392 	    if (isActionOption (o))
393 	    {
394 		if (o->value.action.terminate)
395 		    (*o->value.action.terminate) (d, &o->value.action,
396 						  state, NULL, 0);
397 	    }
398 
399 	    o++;
400 	}
401 
402 	if (state == CompActionStateCancel)
403 	    return FALSE;
404     }
405 
406     state = CompActionStateInitKey;
407     while (nOption--)
408     {
409 	if (isInitiateBinding (option, CompBindingTypeKey, state, &action))
410 	{
411 	    bindMods = virtualToRealModMask (d, action->key.modifiers);
412 
413 	    if (action->key.keycode == event->keycode)
414 	    {
415 		if ((bindMods & modMask) == (event->state & modMask))
416 		    if ((*action->initiate) (d, action, state,
417 					     argument, nArgument))
418 			return TRUE;
419 	    }
420 	    else if (!d->xkbEvent && action->key.keycode == 0)
421 	    {
422 		if (bindMods == (event->state & modMask))
423 		    if ((*action->initiate) (d, action, state,
424 					     argument, nArgument))
425 			return TRUE;
426 	    }
427 	}
428 
429 	option++;
430     }
431 
432     return FALSE;
433 }
434 
435 static Bool
triggerKeyReleaseBindings(CompDisplay * d,CompOption * option,int nOption,XKeyEvent * event,CompOption * argument,int nArgument)436 triggerKeyReleaseBindings (CompDisplay *d,
437 			   CompOption  *option,
438 			   int	       nOption,
439 			   XKeyEvent   *event,
440 			   CompOption  *argument,
441 			   int	       nArgument)
442 {
443     CompActionState state = CompActionStateTermKey;
444     CompAction	    *action;
445     unsigned int    modMask = REAL_MOD_MASK & ~d->ignoredModMask;
446     unsigned int    bindMods;
447     unsigned int    mods;
448 
449     mods = keycodeToModifiers (d, event->keycode);
450     if (!d->xkbEvent && !mods)
451 	return FALSE;
452 
453     while (nOption--)
454     {
455 	if (isTerminateBinding (option, CompBindingTypeKey, state, &action))
456 	{
457 	    bindMods = virtualToRealModMask (d, action->key.modifiers);
458 
459 	    if ((bindMods & modMask) == 0)
460 	    {
461 		if (action->key.keycode == event->keycode)
462 		{
463 		    if ((*action->terminate) (d, action, state,
464 					      argument, nArgument))
465 			return TRUE;
466 		}
467 	    }
468 	    else if (!d->xkbEvent && ((mods & modMask & bindMods) != bindMods))
469 	    {
470 		if ((*action->terminate) (d, action, state,
471 					  argument, nArgument))
472 		    return TRUE;
473 	    }
474 	}
475 
476 	option++;
477     }
478 
479     return FALSE;
480 }
481 
482 static Bool
triggerStateNotifyBindings(CompDisplay * d,CompOption * option,int nOption,XkbStateNotifyEvent * event,CompOption * argument,int nArgument)483 triggerStateNotifyBindings (CompDisplay		*d,
484 			    CompOption		*option,
485 			    int			nOption,
486 			    XkbStateNotifyEvent *event,
487 			    CompOption		*argument,
488 			    int			nArgument)
489 {
490     CompActionState state;
491     CompAction      *action;
492     unsigned int    modMask = REAL_MOD_MASK & ~d->ignoredModMask;
493     unsigned int    bindMods;
494 
495     if (event->event_type == KeyPress)
496     {
497 	state = CompActionStateInitKey;
498 
499 	while (nOption--)
500 	{
501 	    if (isInitiateBinding (option, CompBindingTypeKey, state, &action))
502 	    {
503 		if (action->key.keycode == 0)
504 		{
505 		    bindMods = virtualToRealModMask (d, action->key.modifiers);
506 
507 		    if ((event->mods & modMask & bindMods) == bindMods)
508 		    {
509 			if ((*action->initiate) (d, action, state,
510 						 argument, nArgument))
511 			    return TRUE;
512 		    }
513 		}
514 	    }
515 
516 	    option++;
517 	}
518     }
519     else
520     {
521 	state = CompActionStateTermKey;
522 
523 	while (nOption--)
524 	{
525 	    if (isTerminateBinding (option, CompBindingTypeKey, state, &action))
526 	    {
527 		bindMods = virtualToRealModMask (d, action->key.modifiers);
528 
529 		if ((event->mods & modMask & bindMods) != bindMods)
530 		{
531 		    if ((*action->terminate) (d, action, state,
532 					      argument, nArgument))
533 			return TRUE;
534 		}
535 	    }
536 
537 	    option++;
538 	}
539     }
540 
541     return FALSE;
542 }
543 
544 static Bool
isBellAction(CompOption * option,CompActionState state,CompAction ** action)545 isBellAction (CompOption      *option,
546 	      CompActionState state,
547 	      CompAction      **action)
548 {
549     if (option->type != CompOptionTypeAction &&
550 	option->type != CompOptionTypeBell)
551 	return FALSE;
552 
553     if (!option->value.action.bell)
554 	return FALSE;
555 
556     if (!(option->value.action.state & state))
557 	return FALSE;
558 
559     if (!option->value.action.initiate)
560 	return FALSE;
561 
562     *action = &option->value.action;
563 
564     return TRUE;
565 }
566 
567 static Bool
triggerBellNotifyBindings(CompDisplay * d,CompOption * option,int nOption,CompOption * argument,int nArgument)568 triggerBellNotifyBindings (CompDisplay *d,
569 			   CompOption  *option,
570 			   int	       nOption,
571 			   CompOption  *argument,
572 			   int	       nArgument)
573 {
574     CompActionState state = CompActionStateInitBell;
575     CompAction      *action;
576 
577     while (nOption--)
578     {
579 	if (isBellAction (option, state, &action))
580 	{
581 	    if ((*action->initiate) (d, action, state, argument, nArgument))
582 		return TRUE;
583 	}
584 
585 	option++;
586     }
587 
588     return FALSE;
589 }
590 
591 static Bool
isEdgeAction(CompOption * option,CompActionState state,unsigned int edge)592 isEdgeAction (CompOption      *option,
593 	      CompActionState state,
594 	      unsigned int    edge)
595 {
596     if (option->type != CompOptionTypeAction &&
597 	option->type != CompOptionTypeButton &&
598 	option->type != CompOptionTypeEdge)
599 	return FALSE;
600 
601     if (!(option->value.action.edgeMask & edge))
602 	return FALSE;
603 
604     if (!(option->value.action.state & state))
605 	return FALSE;
606 
607     return TRUE;
608 }
609 
610 static Bool
isEdgeEnterAction(CompOption * option,CompActionState state,CompActionState delayState,unsigned int edge,CompAction ** action)611 isEdgeEnterAction (CompOption      *option,
612 		   CompActionState state,
613 		   CompActionState delayState,
614 		   unsigned int    edge,
615 		   CompAction      **action)
616 {
617     if (!isEdgeAction (option, state, edge))
618 	return FALSE;
619 
620     if (option->value.action.type & CompBindingTypeEdgeButton)
621 	return FALSE;
622 
623     if (!option->value.action.initiate)
624 	return FALSE;
625 
626     if (delayState)
627     {
628 	if ((option->value.action.state & CompActionStateNoEdgeDelay) !=
629 	    (delayState & CompActionStateNoEdgeDelay))
630 	{
631 	    /* ignore edge actions which shouldn't be delayed when invoking
632 	       undelayed edges (or vice versa) */
633 	    return FALSE;
634 	}
635     }
636 
637 
638     *action = &option->value.action;
639 
640     return TRUE;
641 }
642 
643 static Bool
isEdgeLeaveAction(CompOption * option,CompActionState state,unsigned int edge,CompAction ** action)644 isEdgeLeaveAction (CompOption      *option,
645 		   CompActionState state,
646 		   unsigned int    edge,
647 		   CompAction      **action)
648 {
649     if (!isEdgeAction (option, state, edge))
650 	return FALSE;
651 
652     if (!option->value.action.terminate)
653 	return FALSE;
654 
655     *action = &option->value.action;
656 
657     return TRUE;
658 }
659 
660 static Bool
triggerEdgeEnterBindings(CompDisplay * d,CompOption * option,int nOption,CompActionState state,CompActionState delayState,unsigned int edge,CompOption * argument,int nArgument)661 triggerEdgeEnterBindings (CompDisplay	  *d,
662 			  CompOption	  *option,
663 			  int		  nOption,
664 			  CompActionState state,
665 			  CompActionState delayState,
666 			  unsigned int	  edge,
667 			  CompOption	  *argument,
668 			  int		  nArgument)
669 {
670     CompAction *action;
671 
672     while (nOption--)
673     {
674 	if (isEdgeEnterAction (option, state, delayState, edge, &action))
675 	{
676 	    if ((*action->initiate) (d, action, state, argument, nArgument))
677 		return TRUE;
678 	}
679 
680 	option++;
681     }
682 
683     return FALSE;
684 }
685 
686 static Bool
triggerEdgeLeaveBindings(CompDisplay * d,CompOption * option,int nOption,CompActionState state,unsigned int edge,CompOption * argument,int nArgument)687 triggerEdgeLeaveBindings (CompDisplay	  *d,
688 			  CompOption	  *option,
689 			  int		  nOption,
690 			  CompActionState state,
691 			  unsigned int	  edge,
692 			  CompOption	  *argument,
693 			  int		  nArgument)
694 {
695     CompAction *action;
696 
697     while (nOption--)
698     {
699 	if (isEdgeLeaveAction (option, state, edge, &action))
700 	{
701 	    if ((*action->terminate) (d, action, state, argument, nArgument))
702 		return TRUE;
703 	}
704 
705 	option++;
706     }
707 
708     return FALSE;
709 }
710 
711 static Bool
triggerAllEdgeEnterBindings(CompDisplay * d,CompActionState state,CompActionState delayState,unsigned int edge,CompOption * argument,int nArgument)712 triggerAllEdgeEnterBindings (CompDisplay     *d,
713 			     CompActionState state,
714 			     CompActionState delayState,
715 			     unsigned int    edge,
716 			     CompOption	     *argument,
717 			     int	     nArgument)
718 {
719     CompOption *option;
720     int        nOption;
721     CompPlugin *p;
722 
723     for (p = getPlugins (); p; p = p->next)
724     {
725 	if (p->vTable->getObjectOptions)
726 	{
727 	    option = (*p->vTable->getObjectOptions) (p, &d->base, &nOption);
728 	    if (triggerEdgeEnterBindings (d,
729 					  option, nOption,
730 					  state, delayState, edge,
731 					  argument, nArgument))
732 	    {
733 		return TRUE;
734 	    }
735 	}
736     }
737     return FALSE;
738 }
739 
740 static Bool
delayedEdgeTimeout(void * closure)741 delayedEdgeTimeout (void *closure)
742 {
743     CompDelayedEdgeSettings *settings = (CompDelayedEdgeSettings *) closure;
744 
745     triggerAllEdgeEnterBindings (settings->d,
746 				 settings->state,
747 				 ~CompActionStateNoEdgeDelay,
748 				 settings->edge,
749 				 settings->option,
750 				 settings->nOption);
751 
752     free (settings);
753 
754     return FALSE;
755 }
756 
757 static Bool
triggerEdgeEnter(CompDisplay * d,unsigned int edge,CompActionState state,CompOption * argument,unsigned int nArgument)758 triggerEdgeEnter (CompDisplay     *d,
759 		  unsigned int    edge,
760 		  CompActionState state,
761 		  CompOption      *argument,
762 		  unsigned int    nArgument)
763 {
764     int                     delay;
765     CompDelayedEdgeSettings *delayedSettings = NULL;
766 
767     delay = d->opt[COMP_DISPLAY_OPTION_EDGE_DELAY].value.i;
768 
769     if (nArgument > 7)
770 	nArgument = 7;
771 
772     if (delay > 0)
773     {
774 	delayedSettings = malloc (sizeof (CompDelayedEdgeSettings));
775 	if (delayedSettings)
776 	{
777 	    delayedSettings->d       = d;
778 	    delayedSettings->edge    = edge;
779 	    delayedSettings->state   = state;
780 	    delayedSettings->nOption = nArgument;
781 	}
782     }
783 
784     if (delayedSettings)
785     {
786 	CompActionState delayState;
787 	int             i;
788 
789 	for (i = 0; i < nArgument; i++)
790 	    delayedSettings->option[i] = argument[i];
791 
792 	d->edgeDelayHandle = compAddTimeout (delay, (float) delay * 1.2,
793 					     delayedEdgeTimeout,
794 					     delayedSettings);
795 
796 	delayState = CompActionStateNoEdgeDelay;
797 	if (triggerAllEdgeEnterBindings (d, state, delayState,
798 					 edge, argument, nArgument))
799 	    return TRUE;
800     }
801     else
802     {
803 	if (triggerAllEdgeEnterBindings (d, state, 0, edge,
804 					 argument, nArgument))
805 	    return TRUE;
806     }
807 
808     return FALSE;
809 }
810 
811 static Bool
handleActionEvent(CompDisplay * d,XEvent * event)812 handleActionEvent (CompDisplay *d,
813 		   XEvent      *event)
814 {
815     CompObject *obj = &d->base;
816     CompOption *option;
817     int	       nOption;
818     CompPlugin *p;
819     CompOption o[8];
820 
821     o[0].type = CompOptionTypeInt;
822     o[0].name = "event_window";
823 
824     o[1].type = CompOptionTypeInt;
825     o[1].name = "window";
826 
827     o[2].type = CompOptionTypeInt;
828     o[2].name = "modifiers";
829 
830     o[3].type = CompOptionTypeInt;
831     o[3].name = "x";
832 
833     o[4].type = CompOptionTypeInt;
834     o[4].name = "y";
835 
836     o[5].type = CompOptionTypeInt;
837     o[5].name = "root";
838 
839     switch (event->type) {
840     case ButtonPress:
841 	o[0].value.i = event->xbutton.window;
842 	o[1].value.i = event->xbutton.window;
843 	o[2].value.i = event->xbutton.state;
844 	o[3].value.i = event->xbutton.x_root;
845 	o[4].value.i = event->xbutton.y_root;
846 	o[5].value.i = event->xbutton.root;
847 
848 	o[6].type    = CompOptionTypeInt;
849 	o[6].name    = "button";
850 	o[6].value.i = event->xbutton.button;
851 
852 	o[7].type    = CompOptionTypeInt;
853 	o[7].name    = "time";
854 	o[7].value.i = event->xbutton.time;
855 
856 	for (p = getPlugins (); p; p = p->next)
857 	{
858 	    if (!p->vTable->getObjectOptions)
859 		continue;
860 
861 	    option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
862 	    if (triggerButtonPressBindings (d, option, nOption,
863 					    &event->xbutton, o, 8))
864 		return TRUE;
865 	}
866 	break;
867     case ButtonRelease:
868 	o[0].value.i = event->xbutton.window;
869 	o[1].value.i = event->xbutton.window;
870 	o[2].value.i = event->xbutton.state;
871 	o[3].value.i = event->xbutton.x_root;
872 	o[4].value.i = event->xbutton.y_root;
873 	o[5].value.i = event->xbutton.root;
874 
875 	o[6].type    = CompOptionTypeInt;
876 	o[6].name    = "button";
877 	o[6].value.i = event->xbutton.button;
878 
879 	o[7].type    = CompOptionTypeInt;
880 	o[7].name    = "time";
881 	o[7].value.i = event->xbutton.time;
882 
883 	for (p = getPlugins (); p; p = p->next)
884 	{
885 	    if (!p->vTable->getObjectOptions)
886 		continue;
887 
888 	    option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
889 	    if (triggerButtonReleaseBindings (d, option, nOption,
890 					      &event->xbutton, o, 8))
891 		return TRUE;
892 	}
893 	break;
894     case KeyPress:
895 	o[0].value.i = event->xkey.window;
896 	o[1].value.i = d->activeWindow;
897 	o[2].value.i = event->xkey.state;
898 	o[3].value.i = event->xkey.x_root;
899 	o[4].value.i = event->xkey.y_root;
900 	o[5].value.i = event->xkey.root;
901 
902 	o[6].type    = CompOptionTypeInt;
903 	o[6].name    = "keycode";
904 	o[6].value.i = event->xkey.keycode;
905 
906 	o[7].type    = CompOptionTypeInt;
907 	o[7].name    = "time";
908 	o[7].value.i = event->xkey.time;
909 
910 	for (p = getPlugins (); p; p = p->next)
911 	{
912 	    if (!p->vTable->getObjectOptions)
913 		continue;
914 
915 	    option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
916 	    if (triggerKeyPressBindings (d, option, nOption,
917 					 &event->xkey, o, 8))
918 		return TRUE;
919 	}
920 	break;
921     case KeyRelease:
922 	o[0].value.i = event->xkey.window;
923 	o[1].value.i = d->activeWindow;
924 	o[2].value.i = event->xkey.state;
925 	o[3].value.i = event->xkey.x_root;
926 	o[4].value.i = event->xkey.y_root;
927 	o[5].value.i = event->xkey.root;
928 
929 	o[6].type    = CompOptionTypeInt;
930 	o[6].name    = "keycode";
931 	o[6].value.i = event->xkey.keycode;
932 
933 	o[7].type    = CompOptionTypeInt;
934 	o[7].name    = "time";
935 	o[7].value.i = event->xkey.time;
936 
937 	for (p = getPlugins (); p; p = p->next)
938 	{
939 	    if (!p->vTable->getObjectOptions)
940 		continue;
941 	    option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
942 	    if (triggerKeyReleaseBindings (d, option, nOption,
943 					   &event->xkey, o, 8))
944 		return TRUE;
945 	}
946 	break;
947     case EnterNotify:
948 	if (event->xcrossing.mode   != NotifyGrab   &&
949 	    event->xcrossing.mode   != NotifyUngrab &&
950 	    event->xcrossing.detail != NotifyInferior)
951 	{
952 	    CompScreen	    *s;
953 	    unsigned int    edge, i;
954 	    CompActionState state;
955 
956 	    s = findScreenAtDisplay (d, event->xcrossing.root);
957 	    if (!s)
958 		return FALSE;
959 
960 	    if (d->edgeDelayHandle)
961 	    {
962 		void *closure;
963 
964 		closure = compRemoveTimeout (d->edgeDelayHandle);
965 		if (closure)
966 		    free (closure);
967 		d->edgeDelayHandle = 0;
968 	    }
969 
970 	    if (edgeWindow && edgeWindow != event->xcrossing.window)
971 	    {
972 		state = CompActionStateTermEdge;
973 		edge  = 0;
974 
975 		for (i = 0; i < SCREEN_EDGE_NUM; i++)
976 		{
977 		    if (edgeWindow == s->screenEdge[i].id)
978 		    {
979 			edge = 1 << i;
980 			break;
981 		    }
982 		}
983 
984 		edgeWindow = None;
985 
986 		o[0].value.i = event->xcrossing.window;
987 		o[1].value.i = d->activeWindow;
988 		o[2].value.i = event->xcrossing.state;
989 		o[3].value.i = event->xcrossing.x_root;
990 		o[4].value.i = event->xcrossing.y_root;
991 		o[5].value.i = event->xcrossing.root;
992 
993 		o[6].type    = CompOptionTypeInt;
994 		o[6].name    = "time";
995 		o[6].value.i = event->xcrossing.time;
996 
997 		for (p = getPlugins (); p; p = p->next)
998 		{
999 		    if (!p->vTable->getObjectOptions)
1000 			continue;
1001 
1002 		    option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
1003 		    if (triggerEdgeLeaveBindings (d, option, nOption, state,
1004 						  edge, o, 7))
1005 			return TRUE;
1006 		}
1007 	    }
1008 
1009 	    edge = 0;
1010 
1011 	    for (i = 0; i < SCREEN_EDGE_NUM; i++)
1012 	    {
1013 		if (event->xcrossing.window == s->screenEdge[i].id)
1014 		{
1015 		    edge = 1 << i;
1016 		    break;
1017 		}
1018 	    }
1019 
1020 	    if (edge)
1021 	    {
1022 		state = CompActionStateInitEdge;
1023 
1024 		edgeWindow = event->xcrossing.window;
1025 
1026 		o[0].value.i = event->xcrossing.window;
1027 		o[1].value.i = d->activeWindow;
1028 		o[2].value.i = event->xcrossing.state;
1029 		o[3].value.i = event->xcrossing.x_root;
1030 		o[4].value.i = event->xcrossing.y_root;
1031 		o[5].value.i = event->xcrossing.root;
1032 
1033 		o[6].type    = CompOptionTypeInt;
1034 		o[6].name    = "time";
1035 		o[6].value.i = event->xcrossing.time;
1036 
1037 		if (triggerEdgeEnter (d, edge, state, o, 7))
1038 		    return TRUE;
1039 	    }
1040 	}
1041 	break;
1042     case ClientMessage:
1043 	if (event->xclient.message_type == d->xdndEnterAtom)
1044 	{
1045 	    xdndWindow = event->xclient.window;
1046 	}
1047 	else if (event->xclient.message_type == d->xdndLeaveAtom)
1048 	{
1049 	    unsigned int    edge = 0;
1050 	    CompActionState state;
1051 	    Window	    root = None;
1052 
1053 	    if (!xdndWindow)
1054 	    {
1055 		CompWindow *w;
1056 
1057 		w = findWindowAtDisplay (d, event->xclient.window);
1058 		if (w)
1059 		{
1060 		    CompScreen   *s = w->screen;
1061 		    unsigned int i;
1062 
1063 		    for (i = 0; i < SCREEN_EDGE_NUM; i++)
1064 		    {
1065 			if (event->xclient.window == s->screenEdge[i].id)
1066 			{
1067 			    edge = 1 << i;
1068 			    root = s->root;
1069 			    break;
1070 			}
1071 		    }
1072 		}
1073 	    }
1074 
1075 	    if (edge)
1076 	    {
1077 		state = CompActionStateTermEdgeDnd;
1078 
1079 		o[0].value.i = event->xclient.window;
1080 		o[1].value.i = d->activeWindow;
1081 		o[2].value.i = 0; /* fixme */
1082 		o[3].value.i = 0; /* fixme */
1083 		o[4].value.i = 0; /* fixme */
1084 		o[5].value.i = root;
1085 
1086 		for (p = getPlugins (); p; p = p->next)
1087 		{
1088 		    if (!p->vTable->getObjectOptions)
1089 			continue;
1090 
1091 		    option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
1092 		    if (triggerEdgeLeaveBindings (d, option, nOption, state,
1093 						  edge, o, 6))
1094 			return TRUE;
1095 		}
1096 	    }
1097 	}
1098 	else if (event->xclient.message_type == d->xdndPositionAtom)
1099 	{
1100 	    unsigned int    edge = 0;
1101 	    CompActionState state;
1102 	    Window	    root = None;
1103 
1104 	    if (xdndWindow == event->xclient.window)
1105 	    {
1106 		CompWindow *w;
1107 
1108 		w = findWindowAtDisplay (d, event->xclient.window);
1109 		if (w)
1110 		{
1111 		    CompScreen   *s = w->screen;
1112 		    unsigned int i;
1113 
1114 		    for (i = 0; i < SCREEN_EDGE_NUM; i++)
1115 		    {
1116 			if (xdndWindow == s->screenEdge[i].id)
1117 			{
1118 			    edge = 1 << i;
1119 			    root = s->root;
1120 			    break;
1121 			}
1122 		    }
1123 		}
1124 	    }
1125 
1126 	    if (edge)
1127 	    {
1128 		state = CompActionStateInitEdgeDnd;
1129 
1130 		o[0].value.i = event->xclient.window;
1131 		o[1].value.i = d->activeWindow;
1132 		o[2].value.i = 0; /* fixme */
1133 		o[3].value.i = event->xclient.data.l[2] >> 16;
1134 		o[4].value.i = event->xclient.data.l[2] & 0xffff;
1135 		o[5].value.i = root;
1136 
1137 		if (triggerEdgeEnter (d, edge, state, o, 6))
1138 		    return TRUE;
1139 	    }
1140 
1141 	    xdndWindow = None;
1142 	}
1143 	break;
1144     default:
1145 	if (event->type == d->fixesEvent + XFixesCursorNotify)
1146 	{
1147 	    /*
1148 	    XFixesCursorNotifyEvent *ce = (XFixesCursorNotifyEvent *) event;
1149 	    CompCursor		    *cursor;
1150 
1151 	    cursor = findCursorAtDisplay (d);
1152 	    if (cursor)
1153 		updateCursor (cursor, ce->x, ce->y, ce->cursor_serial);
1154 	    */
1155 	}
1156 	else if (event->type == d->xkbEvent)
1157 	{
1158 	    XkbAnyEvent *xkbEvent = (XkbAnyEvent *) event;
1159 
1160 	    if (xkbEvent->xkb_type == XkbStateNotify)
1161 	    {
1162 		XkbStateNotifyEvent *stateEvent = (XkbStateNotifyEvent *) event;
1163 
1164 		o[0].value.i = d->activeWindow;
1165 		o[1].value.i = d->activeWindow;
1166 		o[2].value.i = stateEvent->mods;
1167 
1168 		o[3].type    = CompOptionTypeInt;
1169 		o[3].name    = "time";
1170 		o[3].value.i = xkbEvent->time;
1171 
1172 		for (p = getPlugins (); p; p = p->next)
1173 		{
1174 		    if (!p->vTable->getObjectOptions)
1175 			continue;
1176 
1177 		    option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
1178 		    if (triggerStateNotifyBindings (d, option, nOption,
1179 						    stateEvent, o, 4))
1180 			return TRUE;
1181 		}
1182 	    }
1183 	    else if (xkbEvent->xkb_type == XkbBellNotify)
1184 	    {
1185 		o[0].value.i = d->activeWindow;
1186 		o[1].value.i = d->activeWindow;
1187 
1188 		o[2].type    = CompOptionTypeInt;
1189 		o[2].name    = "time";
1190 		o[2].value.i = xkbEvent->time;
1191 
1192 		for (p = getPlugins (); p; p = p->next)
1193 		{
1194 		    if (!p->vTable->getObjectOptions)
1195 			continue;
1196 
1197 		    option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
1198 		    if (triggerBellNotifyBindings (d, option, nOption, o, 3))
1199 			return TRUE;
1200 		}
1201 	    }
1202 	}
1203 	break;
1204     }
1205 
1206     return FALSE;
1207 }
1208 
1209 void
handleCompizEvent(CompDisplay * d,const char * pluginName,const char * eventName,CompOption * option,int nOption)1210 handleCompizEvent (CompDisplay *d,
1211 		   const char  *pluginName,
1212 		   const char  *eventName,
1213 		   CompOption  *option,
1214 		   int         nOption)
1215 {
1216 }
1217 
1218 void
handleEvent(CompDisplay * d,XEvent * event)1219 handleEvent (CompDisplay *d,
1220 	     XEvent      *event)
1221 {
1222     CompScreen *s;
1223     CompWindow *w;
1224 
1225     switch (event->type) {
1226     case ButtonPress:
1227 	s = findScreenAtDisplay (d, event->xbutton.root);
1228 	if (s)
1229 	    setCurrentOutput (s, outputDeviceForPoint (s,
1230 						       event->xbutton.x_root,
1231 						       event->xbutton.y_root));
1232 	break;
1233     case MotionNotify:
1234 	s = findScreenAtDisplay (d, event->xmotion.root);
1235 	if (s)
1236 	    setCurrentOutput (s, outputDeviceForPoint (s,
1237 						       event->xmotion.x_root,
1238 						       event->xmotion.y_root));
1239 	break;
1240     case KeyPress:
1241 	w = findWindowAtDisplay (d, d->activeWindow);
1242 	if (w)
1243 	    setCurrentOutput (w->screen, outputDeviceForWindow (w));
1244     default:
1245 	break;
1246     }
1247 
1248     if (handleActionEvent (d, event))
1249     {
1250 	if (!d->screens->maxGrab)
1251 	    XAllowEvents (d->display, AsyncPointer, event->xbutton.time);
1252 
1253 	return;
1254     }
1255 
1256     switch (event->type) {
1257     case Expose:
1258 	for (s = d->screens; s; s = s->next)
1259 	    if (s->output == event->xexpose.window)
1260 		break;
1261 
1262 	if (s)
1263 	{
1264 	    int more = event->xexpose.count + 1;
1265 
1266 	    if (s->nExpose == s->sizeExpose)
1267 	    {
1268 		s->exposeRects = realloc (s->exposeRects,
1269 					      (s->sizeExpose + more) *
1270 					      sizeof (XRectangle));
1271 		s->sizeExpose += more;
1272 	    }
1273 
1274 	    s->exposeRects[s->nExpose].x      = event->xexpose.x;
1275 	    s->exposeRects[s->nExpose].y      = event->xexpose.y;
1276 	    s->exposeRects[s->nExpose].width  = event->xexpose.width;
1277 	    s->exposeRects[s->nExpose].height = event->xexpose.height;
1278 	    s->nExpose++;
1279 
1280 	    if (event->xexpose.count == 0)
1281 	    {
1282 		REGION rect;
1283 
1284 		rect.rects = &rect.extents;
1285 		rect.numRects = rect.size = 1;
1286 
1287 		while (s->nExpose--)
1288 		{
1289 		    rect.extents.x1 = s->exposeRects[s->nExpose].x;
1290 		    rect.extents.y1 = s->exposeRects[s->nExpose].y;
1291 		    rect.extents.x2 = rect.extents.x1 +
1292 			s->exposeRects[s->nExpose].width;
1293 		    rect.extents.y2 = rect.extents.y1 +
1294 			s->exposeRects[s->nExpose].height;
1295 
1296 		    damageScreenRegion (s, &rect);
1297 		}
1298 		s->nExpose = 0;
1299 	    }
1300 	}
1301 	break;
1302     case SelectionRequest:
1303 	handleSelectionRequest (d, event);
1304 	break;
1305     case SelectionClear:
1306 	handleSelectionClear (d, event);
1307 	break;
1308     case ConfigureNotify:
1309 	w = findWindowAtDisplay (d, event->xconfigure.window);
1310 	if (w)
1311 	{
1312 	    configureWindow (w, &event->xconfigure);
1313 	}
1314 	else
1315 	{
1316 	    s = findScreenAtDisplay (d, event->xconfigure.window);
1317 	    if (s)
1318 		configureScreen (s, &event->xconfigure);
1319 	}
1320 	break;
1321     case CreateNotify:
1322 	s = findScreenAtDisplay (d, event->xcreatewindow.parent);
1323 	if (s)
1324 	{
1325 	    /* The first time some client asks for the composite
1326 	     * overlay window, the X server creates it, which causes
1327 	     * an errorneous CreateNotify event.  We catch it and
1328 	     * ignore it. */
1329 	    if (s->overlay != event->xcreatewindow.window)
1330 		addWindow (s, event->xcreatewindow.window, getTopWindow (s));
1331 	}
1332 	break;
1333     case DestroyNotify:
1334 	w = findWindowAtDisplay (d, event->xdestroywindow.window);
1335 	if (w)
1336 	{
1337 	    moveInputFocusToOtherWindow (w);
1338 	    destroyWindow (w);
1339 	}
1340 	break;
1341     case MapNotify:
1342 	w = findWindowAtDisplay (d, event->xmap.window);
1343 	if (w)
1344 	{
1345 	    if (w->pendingMaps)
1346 		w->managed = TRUE;
1347 
1348 	    /* been shaded */
1349 	    if (w->height == 0)
1350 	    {
1351 		if (w->id == d->activeWindow)
1352 		    moveInputFocusToWindow (w);
1353 	    }
1354 
1355 	    mapWindow (w);
1356 	}
1357 	break;
1358     case UnmapNotify:
1359 	w = findWindowAtDisplay (d, event->xunmap.window);
1360 	if (w)
1361 	{
1362 	    /* Normal -> Iconic */
1363 	    if (w->pendingUnmaps)
1364 	    {
1365 		setWmState (d, IconicState, w->id);
1366 		w->pendingUnmaps--;
1367 	    }
1368 	    else /* X -> Withdrawn */
1369 	    {
1370 		/* Iconic -> Withdrawn */
1371 		if (w->state & CompWindowStateHiddenMask)
1372 		{
1373 		    w->minimized = FALSE;
1374 
1375 		    changeWindowState (w,
1376 				       w->state & ~CompWindowStateHiddenMask);
1377 
1378 		    updateClientListForScreen (w->screen);
1379 		}
1380 
1381 		if (!w->attrib.override_redirect)
1382 		    setWmState (d, WithdrawnState, w->id);
1383 
1384 		w->placed     = FALSE;
1385 		w->unmanaging = w->managed;
1386 		w->managed    = FALSE;
1387 	    }
1388 
1389 	    unmapWindow (w);
1390 
1391 	    if (!w->shaded)
1392 		moveInputFocusToOtherWindow (w);
1393 	}
1394 	break;
1395     case ReparentNotify:
1396 	w = findWindowAtDisplay (d, event->xreparent.window);
1397 	s = findScreenAtDisplay (d, event->xreparent.parent);
1398 	if (s && !w)
1399 	{
1400 	    addWindow (s, event->xreparent.window, getTopWindow (s));
1401 	}
1402 	else if (w)
1403 	{
1404 	    /* This is the only case where a window is removed but not
1405 	       destroyed. We must remove our event mask and all passive
1406 	       grabs. */
1407 	    XSelectInput (d->display, w->id, NoEventMask);
1408 	    XShapeSelectInput (d->display, w->id, NoEventMask);
1409 	    XUngrabButton (d->display, AnyButton, AnyModifier, w->id);
1410 
1411 	    moveInputFocusToOtherWindow (w);
1412 
1413 	    destroyWindow (w);
1414 	}
1415 	break;
1416     case CirculateNotify:
1417 	w = findWindowAtDisplay (d, event->xcirculate.window);
1418 	if (w)
1419 	    circulateWindow (w, &event->xcirculate);
1420 	break;
1421     case ButtonPress:
1422 	s = findScreenAtDisplay (d, event->xbutton.root);
1423 	if (s)
1424 	{
1425 	    if (event->xbutton.button == Button1 ||
1426 		event->xbutton.button == Button2 ||
1427 		event->xbutton.button == Button3)
1428 	    {
1429 		w = findTopLevelWindowAtScreen (s, event->xbutton.window);
1430 		if (w)
1431 		{
1432 		    if (d->opt[COMP_DISPLAY_OPTION_RAISE_ON_CLICK].value.b)
1433 			updateWindowAttributes (w,
1434 					CompStackingUpdateModeAboveFullscreen);
1435 
1436 		    if (w->id != d->activeWindow)
1437 			if (!(w->type & CompWindowTypeDockMask))
1438 			    if ((*s->focusWindow) (w))
1439 				moveInputFocusToWindow (w);
1440 		}
1441 	    }
1442 
1443 	    if (!s->maxGrab)
1444 		XAllowEvents (d->display, ReplayPointer, event->xbutton.time);
1445 	}
1446 	break;
1447     case PropertyNotify:
1448 	if (event->xproperty.atom == d->winTypeAtom)
1449 	{
1450 	    w = findWindowAtDisplay (d, event->xproperty.window);
1451 	    if (w)
1452 	    {
1453 		unsigned int type;
1454 
1455 		type = getWindowType (d, w->id);
1456 
1457 		if (type != w->wmType)
1458 		{
1459 		    if (w->attrib.map_state == IsViewable)
1460 		    {
1461 			if (w->type == CompWindowTypeDesktopMask)
1462 			    w->screen->desktopWindowCount--;
1463 			else if (type == CompWindowTypeDesktopMask)
1464 			    w->screen->desktopWindowCount++;
1465 		    }
1466 
1467 		    w->wmType = type;
1468 
1469 		    recalcWindowType (w);
1470 		    recalcWindowActions (w);
1471 
1472 		    if (w->type & CompWindowTypeDesktopMask)
1473 			w->paint.opacity = OPAQUE;
1474 
1475 		    if (type & (CompWindowTypeDockMask |
1476 				CompWindowTypeDesktopMask))
1477 			setDesktopForWindow (w, 0xffffffff);
1478 
1479 		    updateClientListForScreen (w->screen);
1480 
1481 		    (*d->matchPropertyChanged) (d, w);
1482 		}
1483 	    }
1484 	}
1485 	else if (event->xproperty.atom == d->winStateAtom)
1486 	{
1487 	    w = findWindowAtDisplay (d, event->xproperty.window);
1488 	    if (w && !w->managed)
1489 	    {
1490 		unsigned int state;
1491 
1492 		state = getWindowState (d, w->id);
1493 		state = constrainWindowState (state, w->actions);
1494 
1495 		/* EWMH suggests that we ignore changes
1496 		   to _NET_WM_STATE_HIDDEN */
1497 		if (w->state & CompWindowStateHiddenMask)
1498 		    state |= CompWindowStateHiddenMask;
1499 		else
1500 		    state &= ~CompWindowStateHiddenMask;
1501 
1502 		if (state != w->state)
1503 		{
1504 		    if (w->type & CompWindowTypeDesktopMask)
1505 			w->paint.opacity = OPAQUE;
1506 
1507 		    changeWindowState (w, state);
1508 		}
1509 	    }
1510 	}
1511 	else if (event->xproperty.atom == XA_WM_NORMAL_HINTS)
1512 	{
1513 	    w = findWindowAtDisplay (d, event->xproperty.window);
1514 	    if (w)
1515 	    {
1516 		updateNormalHints (w);
1517 		recalcWindowActions (w);
1518 	    }
1519 	}
1520 	else if (event->xproperty.atom == XA_WM_HINTS)
1521 	{
1522 	    w = findWindowAtDisplay (d, event->xproperty.window);
1523 	    if (w)
1524 		updateWmHints (w);
1525 	}
1526 	else if (event->xproperty.atom == XA_WM_TRANSIENT_FOR)
1527 	{
1528 	    w = findWindowAtDisplay (d, event->xproperty.window);
1529 	    if (w)
1530 	    {
1531 		updateTransientHint (w);
1532 		recalcWindowActions (w);
1533 	    }
1534 	}
1535 	else if (event->xproperty.atom == d->wmClientLeaderAtom)
1536 	{
1537 	    w = findWindowAtDisplay (d, event->xproperty.window);
1538 	    if (w)
1539 		w->clientLeader = getClientLeader (w);
1540 	}
1541 	else if (event->xproperty.atom == d->wmIconGeometryAtom)
1542 	{
1543 	    w = findWindowAtDisplay (d, event->xproperty.window);
1544 	    if (w)
1545 		updateIconGeometry (w);
1546 	}
1547 	else if (event->xproperty.atom == d->winOpacityAtom)
1548 	{
1549 	    w = findWindowAtDisplay (d, event->xproperty.window);
1550 	    if (w && !(w->type & CompWindowTypeDesktopMask))
1551 	    {
1552 		int opacity;
1553 
1554 		opacity = getWindowProp32 (d, w->id, d->winOpacityAtom, OPAQUE);
1555 		if (opacity != w->paint.opacity)
1556 		{
1557 		    w->paint.opacity = opacity;
1558 		    addWindowDamage (w);
1559 		}
1560 	    }
1561 	}
1562 	else if (event->xproperty.atom == d->winBrightnessAtom)
1563 	{
1564 	    w = findWindowAtDisplay (d, event->xproperty.window);
1565 	    if (w)
1566 	    {
1567 		int brightness;
1568 
1569 		brightness = getWindowProp32 (d, w->id,
1570 	     				      d->winBrightnessAtom, BRIGHT);
1571 		if (brightness != w->paint.brightness)
1572 		{
1573 		    w->paint.brightness = brightness;
1574 		    addWindowDamage (w);
1575 		}
1576 	    }
1577 	}
1578 	else if (event->xproperty.atom == d->winSaturationAtom)
1579 	{
1580 	    w = findWindowAtDisplay (d, event->xproperty.window);
1581 	    if (w && w->screen->canDoSaturated)
1582 	    {
1583 		int saturation;
1584 
1585 		saturation = getWindowProp32 (d, w->id,
1586 					      d->winSaturationAtom, COLOR);
1587 		if (saturation != w->paint.saturation)
1588 		{
1589 		    w->paint.saturation = saturation;
1590 		    addWindowDamage (w);
1591 		}
1592 	    }
1593 	}
1594 	else if (event->xproperty.atom == d->xBackgroundAtom[0] ||
1595 		 event->xproperty.atom == d->xBackgroundAtom[1])
1596 	{
1597 	    s = findScreenAtDisplay (d, event->xproperty.window);
1598 	    if (s)
1599 	    {
1600 		finiTexture (s, &s->backgroundTexture);
1601 		initTexture (s, &s->backgroundTexture);
1602 
1603 		if (s->backgroundLoaded)
1604 		{
1605 		    s->backgroundLoaded = FALSE;
1606 		    damageScreen (s);
1607 		}
1608 	    }
1609 	}
1610 	else if (event->xproperty.atom == d->wmStrutAtom ||
1611 		 event->xproperty.atom == d->wmStrutPartialAtom)
1612 	{
1613 	    w = findWindowAtDisplay (d, event->xproperty.window);
1614 	    if (w)
1615 	    {
1616 		if (updateWindowStruts (w))
1617 		    updateWorkareaForScreen (w->screen);
1618 	    }
1619 	}
1620 	else if (event->xproperty.atom == d->mwmHintsAtom)
1621 	{
1622 	    w = findWindowAtDisplay (d, event->xproperty.window);
1623 	    if (w)
1624 	    {
1625 		getMwmHints (d, w->id, &w->mwmFunc, &w->mwmDecor);
1626 
1627 		recalcWindowActions (w);
1628 	    }
1629 	}
1630 	else if (event->xproperty.atom == d->wmProtocolsAtom)
1631 	{
1632 	    w = findWindowAtDisplay (d, event->xproperty.window);
1633 	    if (w)
1634 		w->protocols = getProtocols (d, w->id);
1635 	}
1636 	else if (event->xproperty.atom == d->wmIconAtom)
1637 	{
1638 	    w = findWindowAtDisplay (d, event->xproperty.window);
1639 	    if (w)
1640 		freeWindowIcons (w);
1641 	}
1642 	else if (event->xproperty.atom == d->startupIdAtom)
1643 	{
1644 	    w = findWindowAtDisplay (d, event->xproperty.window);
1645 	    if (w)
1646 	    {
1647 		s = w->screen;
1648 
1649 		if (w->startupId)
1650 		    free (w->startupId);
1651 
1652 		w->startupId = getStartupId (w);
1653 
1654 		if (w->managed && w->startupId)
1655 		{
1656 		    Time            timestamp = 0;
1657 		    int             vx, vy, x, y;
1658 		    CompFocusResult focus;
1659 
1660 		    w->initialTimestampSet = FALSE;
1661 		    applyStartupProperties (s, w);
1662 
1663 		    if (w->initialTimestampSet)
1664 			timestamp = w->initialTimestamp;
1665 
1666 		    /* as the viewport can't be transmitted via startup
1667 		       notification, assume the client changing the ID
1668 		       wanted to activate the window on the current viewport */
1669 
1670 		    defaultViewportForWindow (w, &vx, &vy);
1671 		    x = w->attrib.x + (s->x - vx) * s->width;
1672 		    y = w->attrib.y + (s->y - vy) * s->height;
1673 		    moveWindowToViewportPosition (w, x, y, TRUE);
1674 
1675 		    focus = allowWindowFocus (w, 0,
1676 					      w->initialViewportX,
1677 					      w->initialViewportY,
1678 					      timestamp);
1679 
1680 		    if (focus == CompFocusAllowed)
1681 			(*s->activateWindow) (w);
1682 		}
1683 	    }
1684 	}
1685 	else if (event->xproperty.atom == XA_WM_CLASS)
1686 	{
1687 	    w = findWindowAtDisplay (d, event->xproperty.window);
1688 	    if (w)
1689 		updateWindowClassHints (w);
1690 	}
1691 	break;
1692     case MotionNotify:
1693 	break;
1694     case ClientMessage:
1695 	if (event->xclient.message_type == d->winActiveAtom)
1696 	{
1697 	    w = findTopLevelWindowAtDisplay (d, event->xclient.window);
1698 	    if (w)
1699 	    {
1700 		CompFocusResult focus = CompFocusAllowed;
1701 
1702 		/* use focus stealing prevention if request came
1703 		   from an application */
1704 		if (event->xclient.data.l[0] == ClientTypeApplication)
1705 		    focus = allowWindowFocus (w, 0,
1706 					      w->screen->x,
1707 					      w->screen->y,
1708 					      event->xclient.data.l[1]);
1709 
1710 		if (focus == CompFocusAllowed)
1711 		    (*w->screen->activateWindow) (w);
1712 	    }
1713 	}
1714 	else if (event->xclient.message_type == d->winOpacityAtom)
1715 	{
1716 	    w = findWindowAtDisplay (d, event->xclient.window);
1717 	    if (w && !(w->type & CompWindowTypeDesktopMask))
1718 	    {
1719 		GLushort opacity = event->xclient.data.l[0] >> 16;
1720 
1721 		setWindowProp32 (d, w->id, d->winOpacityAtom, opacity);
1722 	    }
1723 	}
1724 	else if (event->xclient.message_type == d->winBrightnessAtom)
1725 	{
1726 	    w = findWindowAtDisplay (d, event->xclient.window);
1727 	    if (w)
1728 	    {
1729 		GLushort brightness = event->xclient.data.l[0] >> 16;
1730 
1731 		setWindowProp32 (d, w->id, d->winBrightnessAtom, brightness);
1732 	    }
1733 	}
1734 	else if (event->xclient.message_type == d->winSaturationAtom)
1735 	{
1736 	    w = findWindowAtDisplay (d, event->xclient.window);
1737 	    if (w && w->screen->canDoSaturated)
1738 	    {
1739 		GLushort saturation = event->xclient.data.l[0] >> 16;
1740 
1741 		setWindowProp32 (d, w->id, d->winSaturationAtom, saturation);
1742 	    }
1743 	}
1744 	else if (event->xclient.message_type == d->winStateAtom)
1745 	{
1746 	    w = findWindowAtDisplay (d, event->xclient.window);
1747 	    if (w)
1748 	    {
1749 		unsigned long wState, state;
1750 		int	      i;
1751 
1752 		wState = w->state;
1753 
1754 		for (i = 1; i < 3; i++)
1755 		{
1756 		    state = windowStateMask (d, event->xclient.data.l[i]);
1757 		    if (state & ~CompWindowStateHiddenMask)
1758 		    {
1759 
1760 #define _NET_WM_STATE_REMOVE 0
1761 #define _NET_WM_STATE_ADD    1
1762 #define _NET_WM_STATE_TOGGLE 2
1763 
1764 			switch (event->xclient.data.l[0]) {
1765 			case _NET_WM_STATE_REMOVE:
1766 			    wState &= ~state;
1767 			    break;
1768 			case _NET_WM_STATE_ADD:
1769 			    wState |= state;
1770 			    break;
1771 			case _NET_WM_STATE_TOGGLE:
1772 			    wState ^= state;
1773 			    break;
1774 			}
1775 		    }
1776 		}
1777 
1778 		wState = constrainWindowState (wState, w->actions);
1779 		if (w->id == d->activeWindow)
1780 		    wState &= ~CompWindowStateDemandsAttentionMask;
1781 
1782 		if (wState != w->state)
1783 		{
1784 		    CompStackingUpdateMode stackingUpdateMode;
1785 		    unsigned long          dState = wState ^ w->state;
1786 
1787 		    stackingUpdateMode = CompStackingUpdateModeNone;
1788 
1789 		    /* raise the window whenever its fullscreen state,
1790 		       above/below state or maximization state changed */
1791 		    if (dState & CompWindowStateFullscreenMask)
1792 			stackingUpdateMode = CompStackingUpdateModeAboveFullscreen;
1793 		    else if (dState & (CompWindowStateAboveMask         |
1794 				       CompWindowStateBelowMask         |
1795 				       CompWindowStateMaximizedHorzMask |
1796 				       CompWindowStateMaximizedVertMask))
1797 			stackingUpdateMode = CompStackingUpdateModeNormal;
1798 
1799 		    changeWindowState (w, wState);
1800 
1801 		    updateWindowAttributes (w, stackingUpdateMode);
1802 		}
1803 	    }
1804 	}
1805 	else if (event->xclient.message_type == d->wmProtocolsAtom)
1806 	{
1807 	    if (event->xclient.data.l[0] == d->wmPingAtom)
1808 	    {
1809 		w = findWindowAtDisplay (d, event->xclient.data.l[2]);
1810 		if (w)
1811 		{
1812 		    if (!w->alive)
1813 		    {
1814 			w->alive = TRUE;
1815 
1816 			if (w->lastCloseRequestTime)
1817 			{
1818 			    toolkitAction (w->screen,
1819 					   d->toolkitActionForceQuitDialogAtom,
1820 					   w->lastCloseRequestTime,
1821 					   w->id,
1822 					   FALSE,
1823 					   0,
1824 					   0);
1825 
1826 			    w->lastCloseRequestTime = 0;
1827 			}
1828 		    }
1829 		    w->lastPong = d->lastPing;
1830 		}
1831 	    }
1832 	}
1833 	else if (event->xclient.message_type == d->closeWindowAtom)
1834 	{
1835 	    w = findWindowAtDisplay (d, event->xclient.window);
1836 	    if (w)
1837 		closeWindow (w, event->xclient.data.l[0]);
1838 	}
1839 	else if (event->xclient.message_type == d->desktopGeometryAtom)
1840 	{
1841 	    s = findScreenAtDisplay (d, event->xclient.window);
1842 	    if (s)
1843 	    {
1844 		CompOptionValue value;
1845 
1846 		value.i = event->xclient.data.l[0] / s->width;
1847 
1848 		(*core.setOptionForPlugin) (&s->base, "core", "hsize", &value);
1849 
1850 		value.i = event->xclient.data.l[1] / s->height;
1851 
1852 		(*core.setOptionForPlugin) (&s->base, "core", "vsize", &value);
1853 	    }
1854 	}
1855 	else if (event->xclient.message_type == d->moveResizeWindowAtom)
1856 	{
1857 	    w = findWindowAtDisplay (d, event->xclient.window);
1858 	    if (w)
1859 	    {
1860 		unsigned int   xwcm = 0;
1861 		XWindowChanges xwc;
1862 		int            gravity;
1863 		unsigned int   source;
1864 
1865 		memset (&xwc, 0, sizeof (xwc));
1866 
1867 		if (event->xclient.data.l[0] & (1 << 8))
1868 		{
1869 		    xwcm |= CWX;
1870 		    xwc.x = event->xclient.data.l[1];
1871 		}
1872 
1873 		if (event->xclient.data.l[0] & (1 << 9))
1874 		{
1875 		    xwcm |= CWY;
1876 		    xwc.y = event->xclient.data.l[2];
1877 		}
1878 
1879 		if (event->xclient.data.l[0] & (1 << 10))
1880 		{
1881 		    xwcm |= CWWidth;
1882 		    xwc.width = event->xclient.data.l[3];
1883 		}
1884 
1885 		if (event->xclient.data.l[0] & (1 << 11))
1886 		{
1887 		    xwcm |= CWHeight;
1888 		    xwc.height = event->xclient.data.l[4];
1889 		}
1890 
1891 		gravity = event->xclient.data.l[0] & 0xFF;
1892 		source  = (event->xclient.data.l[0] >> 12) & 0xF;
1893 
1894 		moveResizeWindow (w, &xwc, xwcm, gravity, source);
1895 	    }
1896 	}
1897 	else if (event->xclient.message_type == d->restackWindowAtom)
1898 	{
1899 	    w = findWindowAtDisplay (d, event->xclient.window);
1900 	    if (w)
1901 	    {
1902 		/* TODO: other stack modes than Above and Below */
1903 		if (event->xclient.data.l[1])
1904 		{
1905 		    CompWindow *sibling;
1906 
1907 		    sibling = findWindowAtDisplay (d, event->xclient.data.l[1]);
1908 		    if (sibling)
1909 		    {
1910 			if (event->xclient.data.l[2] == Above)
1911 			    restackWindowAbove (w, sibling);
1912 			else if (event->xclient.data.l[2] == Below)
1913 			    restackWindowBelow (w, sibling);
1914 		    }
1915 		}
1916 		else
1917 		{
1918 		    if (event->xclient.data.l[2] == Above)
1919 			raiseWindow (w);
1920 		    else if (event->xclient.data.l[2] == Below)
1921 			lowerWindow (w);
1922 		}
1923 	    }
1924 	}
1925 	else if (event->xclient.message_type == d->wmChangeStateAtom)
1926 	{
1927 	    w = findWindowAtDisplay (d, event->xclient.window);
1928 	    if (w)
1929 	    {
1930 		if (event->xclient.data.l[0] == IconicState)
1931 		{
1932 		    if (w->actions & CompWindowActionMinimizeMask)
1933 			minimizeWindow (w);
1934 		}
1935 		else if (event->xclient.data.l[0] == NormalState)
1936 		    unminimizeWindow (w);
1937 	    }
1938 	}
1939 	else if (event->xclient.message_type == d->showingDesktopAtom)
1940 	{
1941 	    for (s = d->screens; s; s = s->next)
1942 	    {
1943 		if (event->xclient.window == s->root ||
1944 		    event->xclient.window == None)
1945 		{
1946 		    if (event->xclient.data.l[0])
1947 			(*s->enterShowDesktopMode) (s);
1948 		    else
1949 			(*s->leaveShowDesktopMode) (s, NULL);
1950 		}
1951 	    }
1952 	}
1953 	else if (event->xclient.message_type == d->numberOfDesktopsAtom)
1954 	{
1955 	    s = findScreenAtDisplay (d, event->xclient.window);
1956 	    if (s)
1957 	    {
1958 		CompOptionValue value;
1959 
1960 		value.i = event->xclient.data.l[0];
1961 
1962 		(*core.setOptionForPlugin) (&s->base,
1963 					    "core", "number_of_desktops",
1964 					    &value);
1965 	    }
1966 	}
1967 	else if (event->xclient.message_type == d->currentDesktopAtom)
1968 	{
1969 	    s = findScreenAtDisplay (d, event->xclient.window);
1970 	    if (s)
1971 		setCurrentDesktop (s, event->xclient.data.l[0]);
1972 	}
1973 	else if (event->xclient.message_type == d->winDesktopAtom)
1974 	{
1975 	    w = findWindowAtDisplay (d, event->xclient.window);
1976 	    if (w)
1977 		setDesktopForWindow (w, event->xclient.data.l[0]);
1978 	}
1979 	else if (event->xclient.message_type == d->wmFullscreenMonitorsAtom)
1980 	{
1981 	    w = findWindowAtDisplay (d, event->xclient.window);
1982 	    if (w)
1983 	    {
1984 		CompFullscreenMonitorSet monitors;
1985 
1986 		monitors.top    = event->xclient.data.l[0];
1987 		monitors.bottom = event->xclient.data.l[1];
1988 		monitors.left   = event->xclient.data.l[2];
1989 		monitors.right  = event->xclient.data.l[3];
1990 
1991 		setWindowFullscreenMonitors (w, &monitors);
1992 	    }
1993 	}
1994 	break;
1995     case MappingNotify:
1996 	updateModifierMappings (d);
1997 	break;
1998     case MapRequest:
1999 	w = findWindowAtDisplay (d, event->xmaprequest.window);
2000 	if (w)
2001 	{
2002 	    XWindowAttributes attr;
2003 	    Bool              doMapProcessing = TRUE;
2004 
2005 	    /* We should check the override_redirect flag here, because the
2006 	       client might have changed it while being unmapped. */
2007 	    if (XGetWindowAttributes (d->display, w->id, &attr))
2008 	    {
2009 		if (w->attrib.override_redirect != attr.override_redirect)
2010 		{
2011 		    w->attrib.override_redirect = attr.override_redirect;
2012 		    recalcWindowType (w);
2013 		    recalcWindowActions (w);
2014 
2015 		    (*d->matchPropertyChanged) (d, w);
2016 		}
2017 	    }
2018 
2019 	    if (w->state & CompWindowStateHiddenMask)
2020 		if (!w->minimized && !w->inShowDesktopMode)
2021 		    doMapProcessing = FALSE;
2022 
2023 	    if (doMapProcessing)
2024 	    {
2025 		w->initialViewportX = w->screen->x;
2026 		w->initialViewportY = w->screen->y;
2027 
2028 		w->initialTimestampSet = FALSE;
2029 
2030 		applyStartupProperties (w->screen, w);
2031 	    }
2032 
2033 	    w->managed = TRUE;
2034 
2035 	    if (doMapProcessing)
2036 	    {
2037 		CompFocusResult        focus;
2038 		CompStackingUpdateMode stackingMode;
2039 
2040 		if (!w->placed)
2041 		{
2042 		    int            newX, newY;
2043 		    int            gravity = w->sizeHints.win_gravity;
2044 		    XWindowChanges xwc;
2045 		    unsigned int   xwcm, source;
2046 
2047 		    /* adjust for gravity, but only for frame size */
2048 		    xwc.x      = w->serverX;
2049 		    xwc.y      = w->serverY;
2050 		    xwc.width  = 0;
2051 		    xwc.height = 0;
2052 
2053 		    xwcm = adjustConfigureRequestForGravity (w, &xwc,
2054 							     CWX | CWY,
2055 							     gravity, 1);
2056 
2057 		    source = ClientTypeApplication;
2058 		    (*w->screen->validateWindowResizeRequest) (w, &xwcm, &xwc,
2059 							       source);
2060 
2061 		    if (xwcm)
2062 			configureXWindow (w, xwcm, &xwc);
2063 
2064 		    if ((*w->screen->placeWindow) (w, xwc.x, xwc.y,
2065 						   &newX, &newY))
2066 		    {
2067 			xwc.x = newX;
2068 			xwc.y = newY;
2069 			configureXWindow (w, CWX | CWY, &xwc);
2070 		    }
2071 
2072 		    w->placed   = TRUE;
2073 		}
2074 
2075 		focus = allowWindowFocus (w, NO_FOCUS_MASK,
2076 					  w->screen->x, w->screen->y, 0);
2077 
2078 		if (focus == CompFocusDenied)
2079 		    stackingMode = CompStackingUpdateModeInitialMapDeniedFocus;
2080 		else
2081 		    stackingMode = CompStackingUpdateModeInitialMap;
2082 
2083 		updateWindowAttributes (w, stackingMode);
2084 
2085 		if (w->minimized)
2086 		    unminimizeWindow (w);
2087 
2088 		(*w->screen->leaveShowDesktopMode) (w->screen, w);
2089 
2090 		if (focus == CompFocusAllowed && !onCurrentDesktop (w))
2091 		    setCurrentDesktop (w->screen, w->desktop);
2092 
2093 		if (!(w->state & CompWindowStateHiddenMask))
2094 		    showWindow (w);
2095 
2096 		if (focus == CompFocusAllowed)
2097 		    moveInputFocusToWindow (w);
2098 	    }
2099 
2100 	    setWindowProp (d, w->id, d->winDesktopAtom, w->desktop);
2101 	}
2102 	else
2103 	{
2104 	    XMapWindow (d->display, event->xmaprequest.window);
2105 	}
2106 	break;
2107     case ConfigureRequest:
2108 	w = findWindowAtDisplay (d, event->xconfigurerequest.window);
2109 	if (w && w->managed)
2110 	{
2111 	    XWindowChanges xwc;
2112 
2113 	    memset (&xwc, 0, sizeof (xwc));
2114 
2115 	    xwc.x	     = event->xconfigurerequest.x;
2116 	    xwc.y	     = event->xconfigurerequest.y;
2117 	    xwc.width	     = event->xconfigurerequest.width;
2118 	    xwc.height       = event->xconfigurerequest.height;
2119 	    xwc.border_width = event->xconfigurerequest.border_width;
2120 
2121 	    moveResizeWindow (w, &xwc, event->xconfigurerequest.value_mask,
2122 			      0, ClientTypeUnknown);
2123 
2124 	    if (event->xconfigurerequest.value_mask & CWStackMode)
2125 	    {
2126 		Window          above    = None;
2127 		CompWindow      *sibling = NULL;
2128 		CompFocusResult focus;
2129 
2130 		if (event->xconfigurerequest.value_mask & CWSibling)
2131 		{
2132 		    above   = event->xconfigurerequest.above;
2133 		    sibling = findTopLevelWindowAtDisplay (d, above);
2134 		}
2135 
2136 		switch (event->xconfigurerequest.detail) {
2137 		case Above:
2138 		    focus = allowWindowFocus (w, NO_FOCUS_MASK,
2139 					      w->screen->x, w->screen->y, 0);
2140 		    if (focus == CompFocusAllowed)
2141 		    {
2142 			if (above)
2143 			{
2144 			    if (sibling)
2145 				restackWindowAbove (w, sibling);
2146 			}
2147 			else
2148 			    raiseWindow (w);
2149 		    }
2150 		    break;
2151 		case Below:
2152 		    if (above)
2153 		    {
2154 			if (sibling)
2155 			    restackWindowBelow (w, sibling);
2156 		    }
2157 		    else
2158 			lowerWindow (w);
2159 		    break;
2160 		default:
2161 		    /* no handling of the TopIf, BottomIf, Opposite cases -
2162 		       there will hardly be any client using that */
2163 		    break;
2164 		}
2165 	    }
2166 	}
2167 	else
2168 	{
2169 	    XWindowChanges xwc;
2170 	    unsigned int   xwcm;
2171 
2172 	    xwcm = event->xconfigurerequest.value_mask &
2173 		(CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
2174 
2175 	    xwc.x	     = event->xconfigurerequest.x;
2176 	    xwc.y	     = event->xconfigurerequest.y;
2177 	    xwc.width	     = event->xconfigurerequest.width;
2178 	    xwc.height	     = event->xconfigurerequest.height;
2179 	    xwc.border_width = event->xconfigurerequest.border_width;
2180 
2181 	    if (w)
2182 		configureXWindow (w, xwcm, &xwc);
2183 	    else
2184 		XConfigureWindow (d->display, event->xconfigurerequest.window,
2185 				  xwcm, &xwc);
2186 	}
2187 	break;
2188     case CirculateRequest:
2189 	break;
2190     case FocusIn:
2191 	if (event->xfocus.mode != NotifyGrab)
2192 	{
2193 	    w = findTopLevelWindowAtDisplay (d, event->xfocus.window);
2194 	    if (w && w->managed)
2195 	    {
2196 		unsigned int state = w->state;
2197 
2198 		if (w->id != d->activeWindow)
2199 		{
2200 		    d->activeWindow = w->id;
2201 		    w->activeNum = w->screen->activeNum++;
2202 
2203 		    addToCurrentActiveWindowHistory (w->screen, w->id);
2204 
2205 		    XChangeProperty (d->display, w->screen->root,
2206 				     d->winActiveAtom,
2207 				     XA_WINDOW, 32, PropModeReplace,
2208 				     (unsigned char *) &w->id, 1);
2209 		}
2210 
2211 		state &= ~CompWindowStateDemandsAttentionMask;
2212 		changeWindowState (w, state);
2213 	    }
2214 	    else
2215 	    {
2216 		d->activeWindow = None;
2217 
2218 		s = findScreenAtDisplay (d, event->xfocus.window);
2219 		if (s)
2220 		{
2221 		    if (event->xfocus.detail == NotifyDetailNone ||
2222 			(event->xfocus.mode == NotifyNormal &&
2223 			 event->xfocus.detail == NotifyInferior))
2224 		    {
2225 			/* we don't want the root window to get focus */
2226 			focusDefaultWindow (s);
2227 		    }
2228 		}
2229 	    }
2230 
2231 	    if (d->nextActiveWindow == event->xfocus.window)
2232 		d->nextActiveWindow = None;
2233 	}
2234 	break;
2235     case EnterNotify:
2236 	s = findScreenAtDisplay (d, event->xcrossing.root);
2237 	if (s)
2238 	    w = findTopLevelWindowAtScreen (s, event->xcrossing.window);
2239 	else
2240 	    w = NULL;
2241 
2242 	if (w && w->id != d->below)
2243 	{
2244 	    d->below = w->id;
2245 
2246 	    if (!d->opt[COMP_DISPLAY_OPTION_CLICK_TO_FOCUS].value.b &&
2247 		!s->maxGrab				            &&
2248 		event->xcrossing.mode   != NotifyGrab		    &&
2249 		event->xcrossing.detail != NotifyInferior)
2250 	    {
2251 		Bool raise, focus;
2252 		int  delay;
2253 
2254 		raise = d->opt[COMP_DISPLAY_OPTION_AUTORAISE].value.b;
2255 		delay = d->opt[COMP_DISPLAY_OPTION_AUTORAISE_DELAY].value.i;
2256 
2257 		if (d->autoRaiseHandle && d->autoRaiseWindow != w->id)
2258 		{
2259 		    compRemoveTimeout (d->autoRaiseHandle);
2260 		    d->autoRaiseHandle = 0;
2261 		}
2262 
2263 		if (w->type & NO_FOCUS_MASK)
2264 		    focus = FALSE;
2265 		else
2266 		    focus = (*w->screen->focusWindow) (w);
2267 
2268 		if (focus)
2269 		{
2270 		    moveInputFocusToWindow (w);
2271 
2272 		    if (raise)
2273 		    {
2274 			if (delay > 0)
2275 			{
2276 			    d->autoRaiseWindow = w->id;
2277 			    d->autoRaiseHandle =
2278 				compAddTimeout (delay, (float) delay * 1.2,
2279 						autoRaiseTimeout, d);
2280 			}
2281 			else
2282 			{
2283 			    CompStackingUpdateMode mode =
2284 				CompStackingUpdateModeNormal;
2285 
2286 			    updateWindowAttributes (w, mode);
2287 			}
2288 		    }
2289 		}
2290 	    }
2291 	}
2292 	break;
2293     case LeaveNotify:
2294 	if (event->xcrossing.detail != NotifyInferior)
2295 	{
2296 	    if (event->xcrossing.window == d->below)
2297 		d->below = None;
2298 	}
2299 	break;
2300     default:
2301 	if (event->type == d->damageEvent + XDamageNotify)
2302 	{
2303 	    XDamageNotifyEvent *de = (XDamageNotifyEvent *) event;
2304 
2305 	    if (lastDamagedWindow && de->drawable == lastDamagedWindow->id)
2306 	    {
2307 		w = lastDamagedWindow;
2308 	    }
2309 	    else
2310 	    {
2311 		w = findWindowAtDisplay (d, de->drawable);
2312 		if (w)
2313 		    lastDamagedWindow = w;
2314 	    }
2315 
2316 	    if (w)
2317 	    {
2318 		w->texture->oldMipmaps = TRUE;
2319 
2320 		if (w->syncWait)
2321 		{
2322 		    if (w->nDamage == w->sizeDamage)
2323 		    {
2324 			w->damageRects = realloc (w->damageRects,
2325 						  (w->sizeDamage + 1) *
2326 						  sizeof (XRectangle));
2327 			w->sizeDamage += 1;
2328 		    }
2329 
2330 		    w->damageRects[w->nDamage].x      = de->area.x;
2331 		    w->damageRects[w->nDamage].y      = de->area.y;
2332 		    w->damageRects[w->nDamage].width  = de->area.width;
2333 		    w->damageRects[w->nDamage].height = de->area.height;
2334 		    w->nDamage++;
2335 		}
2336 		else
2337 		{
2338 		    handleWindowDamageRect (w,
2339 					    de->area.x,
2340 					    de->area.y,
2341 					    de->area.width,
2342 					    de->area.height);
2343 		}
2344 	    }
2345 	}
2346 	else if (d->shapeExtension &&
2347 		 event->type == d->shapeEvent + ShapeNotify)
2348 	{
2349 	    w = findWindowAtDisplay (d, ((XShapeEvent *) event)->window);
2350 	    if (w)
2351 	    {
2352 		if (w->mapNum)
2353 		{
2354 		    addWindowDamage (w);
2355 		    updateWindowRegion (w);
2356 		    addWindowDamage (w);
2357 		}
2358 	    }
2359 	}
2360 	else if (d->randrExtension &&
2361 		 event->type == d->randrEvent + RRScreenChangeNotify)
2362 	{
2363 	    XRRScreenChangeNotifyEvent *rre;
2364 
2365 	    rre = (XRRScreenChangeNotifyEvent *) event;
2366 
2367 	    s = findScreenAtDisplay (d, rre->root);
2368 	    if (s)
2369 		detectRefreshRateOfScreen (s);
2370 	}
2371 	else if (event->type == d->syncEvent + XSyncAlarmNotify)
2372 	{
2373 	    XSyncAlarmNotifyEvent *sa;
2374 
2375 	    sa = (XSyncAlarmNotifyEvent *) event;
2376 
2377 	    for (s = d->screens; s; s = s->next)
2378 	    {
2379 		for (w = s->windows; w; w = w->next)
2380 		{
2381 		    if (w->syncAlarm == sa->alarm)
2382 			break;
2383 		}
2384 
2385 		if (w)
2386 		{
2387 		    handleSyncAlarm (w);
2388 		    /* it makes no sense to search for the already
2389 		       found window on other screens, so leave screen loop */
2390 		    break;
2391 		}
2392 	    }
2393 	}
2394 	break;
2395     }
2396 }
2397