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, ®ion.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 = ®ion.extents;
72 region.numRects = region.size = 1;
73
74 damageScreenRegion (w->screen, ®ion);
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