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 #ifdef HAVE_CONFIG_H
27 # include "../config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/poll.h>
34 #include <assert.h>
35
36 #define XK_MISCELLANY
37 #include <X11/keysymdef.h>
38
39 #include <X11/Xlib.h>
40 #include <X11/Xatom.h>
41 #include <X11/extensions/Xcomposite.h>
42 #include <X11/extensions/Xrandr.h>
43 #include <X11/extensions/shape.h>
44
45 #include <compiz-core.h>
46
47 static unsigned int virtualModMask[] = {
48 CompAltMask, CompMetaMask, CompSuperMask, CompHyperMask,
49 CompModeSwitchMask, CompNumLockMask, CompScrollLockMask
50 };
51
52 static CompScreen *targetScreen = NULL;
53 static CompOutput *targetOutput;
54
55 static Bool inHandleEvent = FALSE;
56
57 static const CompTransform identity = {
58 {
59 1.0, 0.0, 0.0, 0.0,
60 0.0, 1.0, 0.0, 0.0,
61 0.0, 0.0, 1.0, 0.0,
62 0.0, 0.0, 0.0, 1.0
63 }
64 };
65
66 int lastPointerX = 0;
67 int lastPointerY = 0;
68 int pointerX = 0;
69 int pointerY = 0;
70
71 #define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption))
72
73 static char *displayPrivateIndices = 0;
74 static int displayPrivateLen = 0;
75
76 static int
reallocDisplayPrivate(int size,void * closure)77 reallocDisplayPrivate (int size,
78 void *closure)
79 {
80 CompDisplay *d;
81 void *privates;
82
83 for (d = core.displays; d; d = d->next)
84 {
85 privates = realloc (d->base.privates, size * sizeof (CompPrivate));
86 if (!privates)
87 return FALSE;
88
89 d->base.privates = (CompPrivate *) privates;
90 }
91
92 return TRUE;
93 }
94
95 int
allocDisplayObjectPrivateIndex(CompObject * parent)96 allocDisplayObjectPrivateIndex (CompObject *parent)
97 {
98 return allocatePrivateIndex (&displayPrivateLen,
99 &displayPrivateIndices,
100 reallocDisplayPrivate,
101 0);
102 }
103
104 void
freeDisplayObjectPrivateIndex(CompObject * parent,int index)105 freeDisplayObjectPrivateIndex (CompObject *parent,
106 int index)
107 {
108 freePrivateIndex (displayPrivateLen, displayPrivateIndices, index);
109 }
110
111 CompBool
forEachDisplayObject(CompObject * parent,ObjectCallBackProc proc,void * closure)112 forEachDisplayObject (CompObject *parent,
113 ObjectCallBackProc proc,
114 void *closure)
115 {
116 if (parent->type == COMP_OBJECT_TYPE_CORE)
117 {
118 CompDisplay *d;
119
120 for (d = core.displays; d; d = d->next)
121 {
122 if (!(*proc) (&d->base, closure))
123 return FALSE;
124 }
125 }
126
127 return TRUE;
128 }
129
130 char *
nameDisplayObject(CompObject * object)131 nameDisplayObject (CompObject *object)
132 {
133 return NULL;
134 }
135
136 CompObject *
findDisplayObject(CompObject * parent,const char * name)137 findDisplayObject (CompObject *parent,
138 const char *name)
139 {
140 if (parent->type == COMP_OBJECT_TYPE_CORE)
141 {
142 if (!name || !name[0])
143 return &core.displays->base;
144 }
145
146 return NULL;
147 }
148
149 int
allocateDisplayPrivateIndex(void)150 allocateDisplayPrivateIndex (void)
151 {
152 return compObjectAllocatePrivateIndex (NULL, COMP_OBJECT_TYPE_DISPLAY);
153 }
154
155 void
freeDisplayPrivateIndex(int index)156 freeDisplayPrivateIndex (int index)
157 {
158 compObjectFreePrivateIndex (NULL, COMP_OBJECT_TYPE_DISPLAY, index);
159 }
160
161 static Bool
closeWin(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)162 closeWin (CompDisplay *d,
163 CompAction *action,
164 CompActionState state,
165 CompOption *option,
166 int nOption)
167 {
168 CompWindow *w;
169 Window xid;
170 unsigned int time;
171
172 xid = getIntOptionNamed (option, nOption, "window", 0);
173 time = getIntOptionNamed (option, nOption, "time", CurrentTime);
174
175 w = findTopLevelWindowAtDisplay (d, xid);
176 if (w && (w->actions & CompWindowActionCloseMask))
177 closeWindow (w, time);
178
179 return TRUE;
180 }
181
182 static Bool
unmaximize(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)183 unmaximize (CompDisplay *d,
184 CompAction *action,
185 CompActionState state,
186 CompOption *option,
187 int nOption)
188 {
189 CompWindow *w;
190 Window xid;
191
192 xid = getIntOptionNamed (option, nOption, "window", 0);
193
194 w = findTopLevelWindowAtDisplay (d, xid);
195 if (w)
196 maximizeWindow (w, 0);
197
198 return TRUE;
199 }
200
201 static Bool
minimize(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)202 minimize (CompDisplay *d,
203 CompAction *action,
204 CompActionState state,
205 CompOption *option,
206 int nOption)
207 {
208 CompWindow *w;
209 Window xid;
210
211 xid = getIntOptionNamed (option, nOption, "window", 0);
212
213 w = findTopLevelWindowAtDisplay (d, xid);
214 if (w && (w->actions & CompWindowActionMinimizeMask))
215 minimizeWindow (w);
216
217 return TRUE;
218 }
219
220 static Bool
maximize(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)221 maximize (CompDisplay *d,
222 CompAction *action,
223 CompActionState state,
224 CompOption *option,
225 int nOption)
226 {
227 CompWindow *w;
228 Window xid;
229
230 xid = getIntOptionNamed (option, nOption, "window", 0);
231
232 w = findTopLevelWindowAtDisplay (d, xid);
233 if (w)
234 maximizeWindow (w, MAXIMIZE_STATE);
235
236 return TRUE;
237 }
238
239 static Bool
maximizeHorizontally(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)240 maximizeHorizontally (CompDisplay *d,
241 CompAction *action,
242 CompActionState state,
243 CompOption *option,
244 int nOption)
245 {
246 CompWindow *w;
247 Window xid;
248
249 xid = getIntOptionNamed (option, nOption, "window", 0);
250
251 w = findTopLevelWindowAtDisplay (d, xid);
252 if (w)
253 maximizeWindow (w, w->state | CompWindowStateMaximizedHorzMask);
254
255 return TRUE;
256 }
257
258 static Bool
maximizeVertically(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)259 maximizeVertically (CompDisplay *d,
260 CompAction *action,
261 CompActionState state,
262 CompOption *option,
263 int nOption)
264 {
265 CompWindow *w;
266 Window xid;
267
268 xid = getIntOptionNamed (option, nOption, "window", 0);
269
270 w = findTopLevelWindowAtDisplay (d, xid);
271 if (w)
272 maximizeWindow (w, w->state | CompWindowStateMaximizedVertMask);
273
274 return TRUE;
275 }
276
277 static Bool
showDesktop(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)278 showDesktop (CompDisplay *d,
279 CompAction *action,
280 CompActionState state,
281 CompOption *option,
282 int nOption)
283 {
284 CompScreen *s;
285 Window xid;
286
287 xid = getIntOptionNamed (option, nOption, "root", 0);
288
289 s = findScreenAtDisplay (d, xid);
290 if (s)
291 {
292 if (s->showingDesktopMask == 0)
293 (*s->enterShowDesktopMode) (s);
294 else
295 (*s->leaveShowDesktopMode) (s, NULL);
296 }
297
298 return TRUE;
299 }
300
301 static Bool
toggleSlowAnimations(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)302 toggleSlowAnimations (CompDisplay *d,
303 CompAction *action,
304 CompActionState state,
305 CompOption *option,
306 int nOption)
307 {
308 CompScreen *s;
309 Window xid;
310
311 xid = getIntOptionNamed (option, nOption, "root", 0);
312
313 s = findScreenAtDisplay (d, xid);
314 if (s)
315 s->slowAnimations = !s->slowAnimations;
316
317 return TRUE;
318 }
319
320 static Bool
raiseInitiate(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)321 raiseInitiate (CompDisplay *d,
322 CompAction *action,
323 CompActionState state,
324 CompOption *option,
325 int nOption)
326 {
327 CompWindow *w;
328 Window xid;
329
330 xid = getIntOptionNamed (option, nOption, "window", 0);
331
332 w = findTopLevelWindowAtDisplay (d, xid);
333 if (w)
334 raiseWindow (w);
335
336 return TRUE;
337 }
338
339 static Bool
lowerInitiate(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)340 lowerInitiate (CompDisplay *d,
341 CompAction *action,
342 CompActionState state,
343 CompOption *option,
344 int nOption)
345 {
346 CompWindow *w;
347 Window xid;
348
349 xid = getIntOptionNamed (option, nOption, "window", 0);
350
351 w = findTopLevelWindowAtDisplay (d, xid);
352 if (w)
353 lowerWindow (w);
354
355 return TRUE;
356 }
357
358 static Bool
windowMenu(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)359 windowMenu (CompDisplay *d,
360 CompAction *action,
361 CompActionState state,
362 CompOption *option,
363 int nOption)
364 {
365 CompWindow *w;
366 Window xid;
367
368 xid = getIntOptionNamed (option, nOption, "window", 0);
369
370 w = findTopLevelWindowAtDisplay (d, xid);
371 if (w && !w->screen->maxGrab)
372 {
373 int x, y, button;
374 Time time;
375
376 time = getIntOptionNamed (option, nOption, "time", CurrentTime);
377 button = getIntOptionNamed (option, nOption, "button", 0);
378 x = getIntOptionNamed (option, nOption, "x", w->attrib.x);
379 y = getIntOptionNamed (option, nOption, "y", w->attrib.y);
380
381 toolkitAction (w->screen,
382 w->screen->display->toolkitActionWindowMenuAtom,
383 time,
384 w->id,
385 button,
386 x,
387 y);
388 }
389
390 return TRUE;
391 }
392
393 static Bool
toggleMaximized(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)394 toggleMaximized (CompDisplay *d,
395 CompAction *action,
396 CompActionState state,
397 CompOption *option,
398 int nOption)
399 {
400 CompWindow *w;
401 Window xid;
402
403 xid = getIntOptionNamed (option, nOption, "window", 0);
404
405 w = findTopLevelWindowAtDisplay (d, xid);
406 if (w)
407 {
408 if ((w->state & MAXIMIZE_STATE) == MAXIMIZE_STATE)
409 maximizeWindow (w, 0);
410 else
411 maximizeWindow (w, MAXIMIZE_STATE);
412 }
413
414 return TRUE;
415 }
416
417 static Bool
toggleMaximizedHorizontally(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)418 toggleMaximizedHorizontally (CompDisplay *d,
419 CompAction *action,
420 CompActionState state,
421 CompOption *option,
422 int nOption)
423 {
424 CompWindow *w;
425 Window xid;
426
427 xid = getIntOptionNamed (option, nOption, "window", 0);
428
429 w = findTopLevelWindowAtDisplay (d, xid);
430 if (w)
431 maximizeWindow (w, w->state ^ CompWindowStateMaximizedHorzMask);
432
433 return TRUE;
434 }
435
436 static Bool
toggleMaximizedVertically(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)437 toggleMaximizedVertically (CompDisplay *d,
438 CompAction *action,
439 CompActionState state,
440 CompOption *option,
441 int nOption)
442 {
443 CompWindow *w;
444 Window xid;
445
446 xid = getIntOptionNamed (option, nOption, "window", 0);
447
448 w = findTopLevelWindowAtDisplay (d, xid);
449 if (w)
450 maximizeWindow (w, w->state ^ CompWindowStateMaximizedVertMask);
451
452 return TRUE;
453 }
454
455 static Bool
shade(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)456 shade (CompDisplay *d,
457 CompAction *action,
458 CompActionState state,
459 CompOption *option,
460 int nOption)
461 {
462 CompWindow *w;
463 Window xid;
464
465 xid = getIntOptionNamed (option, nOption, "window", 0);
466
467 w = findTopLevelWindowAtDisplay (d, xid);
468 if (w && (w->actions & CompWindowActionShadeMask))
469 {
470 w->state ^= CompWindowStateShadedMask;
471 updateWindowAttributes (w, CompStackingUpdateModeNone);
472 }
473
474 return TRUE;
475 }
476
477 const CompMetadataOptionInfo coreDisplayOptionInfo[COMP_DISPLAY_OPTION_NUM] = {
478 { "abi", "int", 0, 0, 0 },
479 { "active_plugins", "list", "<type>string</type>", 0, 0 },
480 { "texture_filter", "int", RESTOSTRING (0, 2), 0, 0 },
481 { "click_to_focus", "bool", 0, 0, 0 },
482 { "autoraise", "bool", 0, 0, 0 },
483 { "autoraise_delay", "int", 0, 0, 0 },
484 { "close_window_key", "key", 0, closeWin, 0 },
485 { "close_window_button", "button", 0, closeWin, 0 },
486 { "slow_animations_key", "key", 0, toggleSlowAnimations, 0 },
487 { "raise_window_key", "key", 0, raiseInitiate, 0 },
488 { "raise_window_button", "button", 0, raiseInitiate, 0 },
489 { "lower_window_key", "key", 0, lowerInitiate, 0 },
490 { "lower_window_button", "button", 0, lowerInitiate, 0 },
491 { "unmaximize_window_key", "key", 0, unmaximize, 0 },
492 { "minimize_window_key", "key", 0, minimize, 0 },
493 { "minimize_window_button", "button", 0, minimize, 0 },
494 { "maximize_window_key", "key", 0, maximize, 0 },
495 { "maximize_window_horizontally_key", "key", 0, maximizeHorizontally, 0 },
496 { "maximize_window_vertically_key", "key", 0, maximizeVertically, 0 },
497 { "window_menu_button", "button", 0, windowMenu, 0 },
498 { "window_menu_key", "key", 0, windowMenu, 0 },
499 { "show_desktop_key", "key", 0, showDesktop, 0 },
500 { "show_desktop_edge", "edge", 0, showDesktop, 0 },
501 { "raise_on_click", "bool", 0, 0, 0 },
502 { "audible_bell", "bool", 0, 0, 0 },
503 { "toggle_window_maximized_key", "key", 0, toggleMaximized, 0 },
504 { "toggle_window_maximized_button", "button", 0, toggleMaximized, 0 },
505 { "toggle_window_maximized_horizontally_key", "key", 0,
506 toggleMaximizedHorizontally, 0 },
507 { "toggle_window_maximized_vertically_key", "key", 0,
508 toggleMaximizedVertically, 0 },
509 { "hide_skip_taskbar_windows", "bool", 0, 0, 0 },
510 { "toggle_window_shaded_key", "key", 0, shade, 0 },
511 { "ignore_hints_when_maximized", "bool", 0, 0, 0 },
512 { "ping_delay", "int", "<min>1000</min>", 0, 0 },
513 { "edge_delay", "int", "<min>0</min>", 0, 0 }
514 };
515
516 CompOption *
getDisplayOptions(CompPlugin * plugin,CompDisplay * display,int * count)517 getDisplayOptions (CompPlugin *plugin,
518 CompDisplay *display,
519 int *count)
520 {
521 *count = NUM_OPTIONS (display);
522 return display->opt;
523 }
524
525 static void
setAudibleBell(CompDisplay * display,Bool audible)526 setAudibleBell (CompDisplay *display,
527 Bool audible)
528 {
529 if (display->xkbExtension)
530 XkbChangeEnabledControls (display->display,
531 XkbUseCoreKbd,
532 XkbAudibleBellMask,
533 audible ? XkbAudibleBellMask : 0);
534 }
535
536 static Bool
pingTimeout(void * closure)537 pingTimeout (void *closure)
538 {
539 CompDisplay *d = closure;
540 CompScreen *s;
541 CompWindow *w;
542 XEvent ev;
543 int ping = d->lastPing + 1;
544
545 ev.type = ClientMessage;
546 ev.xclient.window = 0;
547 ev.xclient.message_type = d->wmProtocolsAtom;
548 ev.xclient.format = 32;
549 ev.xclient.data.l[0] = d->wmPingAtom;
550 ev.xclient.data.l[1] = ping;
551 ev.xclient.data.l[2] = 0;
552 ev.xclient.data.l[3] = 0;
553 ev.xclient.data.l[4] = 0;
554
555 for (s = d->screens; s; s = s->next)
556 {
557 for (w = s->windows; w; w = w->next)
558 {
559 if (w->attrib.map_state != IsViewable)
560 continue;
561
562 if (!(w->type & CompWindowTypeNormalMask))
563 continue;
564
565 if (w->protocols & CompWindowProtocolPingMask)
566 {
567 if (w->transientFor)
568 continue;
569
570 if (w->lastPong < d->lastPing)
571 {
572 if (w->alive)
573 {
574 w->alive = FALSE;
575
576 if (w->closeRequests)
577 {
578 toolkitAction (s,
579 d->toolkitActionForceQuitDialogAtom,
580 w->lastCloseRequestTime,
581 w->id,
582 TRUE,
583 0,
584 0);
585
586 w->closeRequests = 0;
587 }
588
589 addWindowDamage (w);
590 }
591 }
592
593 ev.xclient.window = w->id;
594 ev.xclient.data.l[2] = w->id;
595
596 XSendEvent (d->display, w->id, FALSE, NoEventMask, &ev);
597 }
598 }
599 }
600
601 d->lastPing = ping;
602
603 return TRUE;
604 }
605
606 Bool
setDisplayOption(CompPlugin * plugin,CompDisplay * display,const char * name,CompOptionValue * value)607 setDisplayOption (CompPlugin *plugin,
608 CompDisplay *display,
609 const char *name,
610 CompOptionValue *value)
611 {
612 CompOption *o;
613 int index;
614
615 o = compFindOption (display->opt, NUM_OPTIONS (display), name, &index);
616 if (!o)
617 return FALSE;
618
619 switch (index) {
620 case COMP_DISPLAY_OPTION_ABI:
621 break;
622 case COMP_DISPLAY_OPTION_ACTIVE_PLUGINS:
623 if (compSetOptionList (o, value))
624 {
625 display->dirtyPluginList = TRUE;
626 return TRUE;
627 }
628 break;
629 case COMP_DISPLAY_OPTION_TEXTURE_FILTER:
630 if (compSetIntOption (o, value))
631 {
632 CompScreen *s;
633
634 for (s = display->screens; s; s = s->next)
635 damageScreen (s);
636
637 if (!o->value.i)
638 display->textureFilter = GL_NEAREST;
639 else
640 display->textureFilter = GL_LINEAR;
641
642 return TRUE;
643 }
644 break;
645 case COMP_DISPLAY_OPTION_PING_DELAY:
646 if (compSetIntOption (o, value))
647 {
648 if (display->pingHandle)
649 compRemoveTimeout (display->pingHandle);
650
651 display->pingHandle =
652 compAddTimeout (o->value.i, o->value.i + 500,
653 pingTimeout, display);
654 return TRUE;
655 }
656 break;
657 case COMP_DISPLAY_OPTION_AUDIBLE_BELL:
658 if (compSetBoolOption (o, value))
659 {
660 setAudibleBell (display, o->value.b);
661 return TRUE;
662 }
663 break;
664 default:
665 if (compSetDisplayOption (display, o, value))
666 return TRUE;
667 break;
668 }
669
670 return FALSE;
671 }
672
673 static void
updatePlugins(CompDisplay * d)674 updatePlugins (CompDisplay *d)
675 {
676 CompOption *o;
677 CompPlugin *p, **pop = 0;
678 int nPop, i, j, k;
679 CompOptionValue *pList;
680 int pListCount = 1;
681
682 d->dirtyPluginList = FALSE;
683
684 o = &d->opt[COMP_DISPLAY_OPTION_ACTIVE_PLUGINS];
685
686 /* determine number of plugins, which is core + initial plugins +
687 plugins in option list additional to initial plugins */
688 for (i = 0; i < nInitialPlugins; i++)
689 if (strcmp (initialPlugins[i], "core") != 0)
690 pListCount++;
691
692 for (i = 0; i < o->value.list.nValue; i++)
693 {
694 if (strcmp (o->value.list.value[i].s, "core") == 0)
695 continue;
696
697 for (j = 0; j < nInitialPlugins; j++)
698 {
699 if (strcmp (o->value.list.value[i].s, initialPlugins[j]) == 0)
700 break;
701 }
702
703 /* plugin is not in initial plugin list */
704 if (j == nInitialPlugins)
705 pListCount++;
706 }
707
708 pList = malloc (sizeof (CompOptionValue) * pListCount);
709 if (!pList)
710 {
711 (*core.setOptionForPlugin) (&d->base, "core", o->name, &d->plugin);
712 return;
713 }
714
715 /* new plugin list needs core as first plugin */
716 pList[0].s = "core";
717
718 /* afterwards, add the initial plugins */
719 for (j = 0, k = 1; j < nInitialPlugins; j++)
720 {
721 /* avoid adding core twice */
722 if (strcmp (initialPlugins[j], "core") == 0)
723 continue;
724
725 pList[k++].s = initialPlugins[j];
726 }
727 j = k;
728
729 /* then add the plugins not in the initial plugin list */
730 for (i = 0; i < o->value.list.nValue; i++)
731 {
732 if (strcmp (o->value.list.value[i].s, "core") == 0)
733 continue;
734
735 for (k = 0; k < nInitialPlugins; k++)
736 {
737 if (strcmp (o->value.list.value[i].s, initialPlugins[k]) == 0)
738 break;
739 }
740
741 if (k == nInitialPlugins)
742 pList[j++].s = o->value.list.value[i].s;
743 }
744
745 assert (j == pListCount);
746
747 /* j is initialized to 1 to make sure we never pop the core plugin */
748 for (i = j = 1; j < d->plugin.list.nValue && i < pListCount; i++, j++)
749 {
750 if (strcmp (d->plugin.list.value[j].s, pList[i].s))
751 break;
752 }
753
754 nPop = d->plugin.list.nValue - j;
755
756 if (nPop)
757 {
758 pop = malloc (sizeof (CompPlugin *) * nPop);
759 if (!pop)
760 {
761 (*core.setOptionForPlugin) (&d->base, "core", o->name, &d->plugin);
762 free (pList);
763 return;
764 }
765 }
766
767 for (j = 0; j < nPop; j++)
768 {
769 pop[j] = popPlugin ();
770 d->plugin.list.nValue--;
771 free (d->plugin.list.value[d->plugin.list.nValue].s);
772 }
773
774 for (; i < pListCount; i++)
775 {
776 p = 0;
777 for (j = 0; j < nPop; j++)
778 {
779 if (pop[j] && strcmp (pop[j]->vTable->name, pList[i].s) == 0)
780 {
781 if (pushPlugin (pop[j]))
782 {
783 p = pop[j];
784 pop[j] = 0;
785 break;
786 }
787 }
788 }
789
790 if (p == 0)
791 {
792 p = loadPlugin (pList[i].s);
793 if (p)
794 {
795 if (!pushPlugin (p))
796 {
797 unloadPlugin (p);
798 p = 0;
799 }
800 }
801 }
802
803 if (p)
804 {
805 CompOptionValue *value;
806
807 value = realloc (d->plugin.list.value, sizeof (CompOptionValue) *
808 (d->plugin.list.nValue + 1));
809 if (value)
810 {
811 value[d->plugin.list.nValue].s = strdup (p->vTable->name);
812
813 d->plugin.list.value = value;
814 d->plugin.list.nValue++;
815 }
816 else
817 {
818 p = popPlugin ();
819 unloadPlugin (p);
820 }
821 }
822 }
823
824 for (j = 0; j < nPop; j++)
825 {
826 if (pop[j])
827 unloadPlugin (pop[j]);
828 }
829
830 if (nPop)
831 free (pop);
832
833 free (pList);
834 (*core.setOptionForPlugin) (&d->base, "core", o->name, &d->plugin);
835 }
836
837 static void
addTimeout(CompTimeout * timeout)838 addTimeout (CompTimeout *timeout)
839 {
840 CompTimeout *p = 0, *t;
841
842 for (t = core.timeouts; t; t = t->next)
843 {
844 if (timeout->minTime < t->minLeft)
845 break;
846
847 p = t;
848 }
849
850 timeout->next = t;
851 timeout->minLeft = timeout->minTime;
852 timeout->maxLeft = timeout->maxTime;
853
854 if (p)
855 p->next = timeout;
856 else
857 core.timeouts = timeout;
858 }
859
860 CompTimeoutHandle
compAddTimeout(int minTime,int maxTime,CallBackProc callBack,void * closure)861 compAddTimeout (int minTime,
862 int maxTime,
863 CallBackProc callBack,
864 void *closure)
865 {
866 CompTimeout *timeout;
867
868 timeout = malloc (sizeof (CompTimeout));
869 if (!timeout)
870 return 0;
871
872 timeout->minTime = minTime;
873 timeout->maxTime = (maxTime >= minTime) ? maxTime : minTime;
874 timeout->callBack = callBack;
875 timeout->closure = closure;
876 timeout->handle = core.lastTimeoutHandle++;
877
878 if (core.lastTimeoutHandle == MAXSHORT)
879 core.lastTimeoutHandle = 1;
880
881 addTimeout (timeout);
882
883 return timeout->handle;
884 }
885
886 void *
compRemoveTimeout(CompTimeoutHandle handle)887 compRemoveTimeout (CompTimeoutHandle handle)
888 {
889 CompTimeout *p = 0, *t;
890 void *closure = NULL;
891
892 for (t = core.timeouts; t; t = t->next)
893 {
894 if (t->handle == handle)
895 break;
896
897 p = t;
898 }
899
900 if (t)
901 {
902 if (p)
903 p->next = t->next;
904 else
905 core.timeouts = t->next;
906
907 closure = t->closure;
908
909 free (t);
910 }
911
912 return closure;
913 }
914
915 CompWatchFdHandle
compAddWatchFd(int fd,short int events,CallBackProc callBack,void * closure)916 compAddWatchFd (int fd,
917 short int events,
918 CallBackProc callBack,
919 void *closure)
920 {
921 CompWatchFd *watchFd;
922
923 watchFd = malloc (sizeof (CompWatchFd));
924 if (!watchFd)
925 return 0;
926
927 watchFd->fd = fd;
928 watchFd->callBack = callBack;
929 watchFd->closure = closure;
930 watchFd->handle = core.lastWatchFdHandle++;
931
932 if (core.lastWatchFdHandle == MAXSHORT)
933 core.lastWatchFdHandle = 1;
934
935 watchFd->next = core.watchFds;
936 core.watchFds = watchFd;
937
938 core.nWatchFds++;
939
940 core.watchPollFds = realloc (core.watchPollFds,
941 core.nWatchFds * sizeof (struct pollfd));
942
943 core.watchPollFds[core.nWatchFds - 1].fd = fd;
944 core.watchPollFds[core.nWatchFds - 1].events = events;
945
946 return watchFd->handle;
947 }
948
949 void
compRemoveWatchFd(CompWatchFdHandle handle)950 compRemoveWatchFd (CompWatchFdHandle handle)
951 {
952 CompWatchFd *p = 0, *w;
953 int i;
954
955 for (i = core.nWatchFds - 1, w = core.watchFds; w; i--, w = w->next)
956 {
957 if (w->handle == handle)
958 break;
959
960 p = w;
961 }
962
963 if (w)
964 {
965 if (p)
966 p->next = w->next;
967 else
968 core.watchFds = w->next;
969
970 core.nWatchFds--;
971
972 if (i < core.nWatchFds)
973 memmove (&core.watchPollFds[i], &core.watchPollFds[i + 1],
974 (core.nWatchFds - i) * sizeof (struct pollfd));
975
976 free (w);
977 }
978 }
979
980 short int
compWatchFdEvents(CompWatchFdHandle handle)981 compWatchFdEvents (CompWatchFdHandle handle)
982 {
983 CompWatchFd *w;
984 int i;
985
986 for (i = core.nWatchFds - 1, w = core.watchFds; w; i--, w = w->next)
987 if (w->handle == handle)
988 return core.watchPollFds[i].revents;
989
990 return 0;
991 }
992
993 #define TIMEVALDIFF(tv1, tv2) \
994 ((tv1)->tv_sec == (tv2)->tv_sec || (tv1)->tv_usec >= (tv2)->tv_usec) ? \
995 ((((tv1)->tv_sec - (tv2)->tv_sec) * 1000000) + \
996 ((tv1)->tv_usec - (tv2)->tv_usec)) / 1000 : \
997 ((((tv1)->tv_sec - 1 - (tv2)->tv_sec) * 1000000) + \
998 (1000000 + (tv1)->tv_usec - (tv2)->tv_usec)) / 1000
999
1000 static int
getTimeToNextRedraw(CompScreen * s,struct timeval * tv,struct timeval * lastTv,Bool idle)1001 getTimeToNextRedraw (CompScreen *s,
1002 struct timeval *tv,
1003 struct timeval *lastTv,
1004 Bool idle)
1005 {
1006 int diff, next;
1007
1008 diff = TIMEVALDIFF (tv, lastTv);
1009
1010 /* handle clock rollback */
1011 if (diff < 0)
1012 diff = 0;
1013
1014 if (idle ||
1015 (s->getVideoSync && s->opt[COMP_SCREEN_OPTION_SYNC_TO_VBLANK].value.b))
1016 {
1017 if (s->timeMult > 1)
1018 {
1019 s->frameStatus = -1;
1020 s->redrawTime = s->optimalRedrawTime;
1021 s->timeMult--;
1022 }
1023 }
1024 else
1025 {
1026 if (diff > s->redrawTime)
1027 {
1028 if (s->frameStatus > 0)
1029 s->frameStatus = 0;
1030
1031 next = s->optimalRedrawTime * (s->timeMult + 1);
1032 if (diff > next)
1033 {
1034 s->frameStatus--;
1035 if (s->frameStatus < -1)
1036 {
1037 s->timeMult++;
1038 s->redrawTime = diff = next;
1039 }
1040 }
1041 }
1042 else if (diff < s->redrawTime)
1043 {
1044 if (s->frameStatus < 0)
1045 s->frameStatus = 0;
1046
1047 if (s->timeMult > 1)
1048 {
1049 next = s->optimalRedrawTime * (s->timeMult - 1);
1050 if (diff < next)
1051 {
1052 s->frameStatus++;
1053 if (s->frameStatus > 4)
1054 {
1055 s->timeMult--;
1056 s->redrawTime = next;
1057 }
1058 }
1059 }
1060 }
1061 }
1062
1063 if (diff > s->redrawTime)
1064 return 0;
1065
1066 return s->redrawTime - diff;
1067 }
1068
1069 static const int maskTable[] = {
1070 ShiftMask, LockMask, ControlMask, Mod1Mask,
1071 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
1072 };
1073 static const int maskTableSize = sizeof (maskTable) / sizeof (int);
1074
1075 void
updateModifierMappings(CompDisplay * d)1076 updateModifierMappings (CompDisplay *d)
1077 {
1078 unsigned int modMask[CompModNum];
1079 int i, minKeycode, maxKeycode, keysymsPerKeycode = 0;
1080 KeySym* key;
1081
1082 for (i = 0; i < CompModNum; i++)
1083 modMask[i] = 0;
1084
1085 XDisplayKeycodes (d->display, &minKeycode, &maxKeycode);
1086 key = XGetKeyboardMapping (d->display,
1087 minKeycode, (maxKeycode - minKeycode + 1),
1088 &keysymsPerKeycode);
1089
1090 if (d->modMap)
1091 XFreeModifiermap (d->modMap);
1092
1093 d->modMap = XGetModifierMapping (d->display);
1094 if (d->modMap && d->modMap->max_keypermod > 0)
1095 {
1096 KeySym keysym;
1097 int index, size, mask;
1098
1099 size = maskTableSize * d->modMap->max_keypermod;
1100
1101 for (i = 0; i < size; i++)
1102 {
1103 if (!d->modMap->modifiermap[i])
1104 continue;
1105
1106 index = 0;
1107 do
1108 {
1109 keysym = XKeycodeToKeysym (d->display,
1110 d->modMap->modifiermap[i],
1111 index++);
1112 } while (!keysym && index < keysymsPerKeycode);
1113
1114 if (keysym)
1115 {
1116 mask = maskTable[i / d->modMap->max_keypermod];
1117
1118 if (keysym == XK_Alt_L ||
1119 keysym == XK_Alt_R)
1120 {
1121 modMask[CompModAlt] |= mask;
1122 }
1123 else if (keysym == XK_Meta_L ||
1124 keysym == XK_Meta_R)
1125 {
1126 modMask[CompModMeta] |= mask;
1127 }
1128 else if (keysym == XK_Super_L ||
1129 keysym == XK_Super_R)
1130 {
1131 modMask[CompModSuper] |= mask;
1132 }
1133 else if (keysym == XK_Hyper_L ||
1134 keysym == XK_Hyper_R)
1135 {
1136 modMask[CompModHyper] |= mask;
1137 }
1138 else if (keysym == XK_Mode_switch)
1139 {
1140 modMask[CompModModeSwitch] |= mask;
1141 }
1142 else if (keysym == XK_Scroll_Lock)
1143 {
1144 modMask[CompModScrollLock] |= mask;
1145 }
1146 else if (keysym == XK_Num_Lock)
1147 {
1148 modMask[CompModNumLock] |= mask;
1149 }
1150 }
1151 }
1152
1153 for (i = 0; i < CompModNum; i++)
1154 {
1155 if (!modMask[i])
1156 modMask[i] = CompNoMask;
1157 }
1158
1159 if (memcmp (modMask, d->modMask, sizeof (modMask)))
1160 {
1161 CompScreen *s;
1162
1163 memcpy (d->modMask, modMask, sizeof (modMask));
1164
1165 d->ignoredModMask = LockMask |
1166 (modMask[CompModNumLock] & ~CompNoMask) |
1167 (modMask[CompModScrollLock] & ~CompNoMask);
1168
1169 for (s = d->screens; s; s = s->next)
1170 updatePassiveGrabs (s);
1171 }
1172 }
1173
1174 if (key)
1175 XFree (key);
1176 }
1177
1178 unsigned int
virtualToRealModMask(CompDisplay * d,unsigned int modMask)1179 virtualToRealModMask (CompDisplay *d,
1180 unsigned int modMask)
1181 {
1182 int i;
1183
1184 for (i = 0; i < CompModNum; i++)
1185 {
1186 if (modMask & virtualModMask[i])
1187 {
1188 modMask &= ~virtualModMask[i];
1189 modMask |= d->modMask[i];
1190 }
1191 }
1192
1193 return modMask;
1194 }
1195
1196 unsigned int
keycodeToModifiers(CompDisplay * d,int keycode)1197 keycodeToModifiers (CompDisplay *d,
1198 int keycode)
1199 {
1200 unsigned int mods = 0;
1201 int mod, k;
1202
1203 for (mod = 0; mod < maskTableSize; mod++)
1204 {
1205 for (k = 0; k < d->modMap->max_keypermod; k++)
1206 {
1207 if (d->modMap->modifiermap[mod * d->modMap->max_keypermod + k] ==
1208 keycode)
1209 mods |= maskTable[mod];
1210 }
1211 }
1212
1213 return mods;
1214 }
1215
1216 static int
doPoll(int timeout)1217 doPoll (int timeout)
1218 {
1219 int rv;
1220
1221 rv = poll (core.watchPollFds, core.nWatchFds, timeout);
1222 if (rv)
1223 {
1224 CompWatchFd *w;
1225 int i;
1226
1227 for (i = core.nWatchFds - 1, w = core.watchFds; w; i--, w = w->next)
1228 {
1229 if (core.watchPollFds[i].revents != 0 && w->callBack)
1230 (*w->callBack) (w->closure);
1231 }
1232 }
1233
1234 return rv;
1235 }
1236
1237 static void
handleTimeouts(struct timeval * tv)1238 handleTimeouts (struct timeval *tv)
1239 {
1240 CompTimeout *t;
1241 int timeDiff;
1242
1243 timeDiff = TIMEVALDIFF (tv, &core.lastTimeout);
1244
1245 /* handle clock rollback */
1246 if (timeDiff < 0)
1247 timeDiff = 0;
1248
1249 for (t = core.timeouts; t; t = t->next)
1250 {
1251 t->minLeft -= timeDiff;
1252 t->maxLeft -= timeDiff;
1253 }
1254
1255 while (core.timeouts && core.timeouts->minLeft <= 0)
1256 {
1257 t = core.timeouts;
1258 if ((*t->callBack) (t->closure))
1259 {
1260 core.timeouts = t->next;
1261 addTimeout (t);
1262 }
1263 else
1264 {
1265 core.timeouts = t->next;
1266 free (t);
1267 }
1268 }
1269
1270 core.lastTimeout = *tv;
1271 }
1272
1273 static void
waitForVideoSync(CompScreen * s)1274 waitForVideoSync (CompScreen *s)
1275 {
1276 unsigned int sync;
1277
1278 if (!s->opt[COMP_SCREEN_OPTION_SYNC_TO_VBLANK].value.b)
1279 return;
1280
1281 if (s->getVideoSync)
1282 {
1283 glFlush ();
1284
1285 (*s->getVideoSync) (&sync);
1286 (*s->waitVideoSync) (2, (sync + 1) % 2, &sync);
1287 }
1288 }
1289
1290
1291 void
paintScreen(CompScreen * s,CompOutput * outputs,int numOutput,unsigned int mask)1292 paintScreen (CompScreen *s,
1293 CompOutput *outputs,
1294 int numOutput,
1295 unsigned int mask)
1296 {
1297 XRectangle r;
1298 int i;
1299
1300 for (i = 0; i < numOutput; i++)
1301 {
1302 targetScreen = s;
1303 targetOutput = &outputs[i];
1304
1305 r.x = outputs[i].region.extents.x1;
1306 r.y = s->height - outputs[i].region.extents.y2;
1307 r.width = outputs[i].width;
1308 r.height = outputs[i].height;
1309
1310 if (s->lastViewport.x != r.x ||
1311 s->lastViewport.y != r.y ||
1312 s->lastViewport.width != r.width ||
1313 s->lastViewport.height != r.height)
1314 {
1315 glViewport (r.x, r.y, r.width, r.height);
1316 s->lastViewport = r;
1317 }
1318
1319 if (mask & COMP_SCREEN_DAMAGE_ALL_MASK)
1320 {
1321 (*s->paintOutput) (s,
1322 &defaultScreenPaintAttrib,
1323 &identity,
1324 &outputs[i].region, &outputs[i],
1325 PAINT_SCREEN_REGION_MASK |
1326 PAINT_SCREEN_FULL_MASK);
1327 }
1328 else if (mask & COMP_SCREEN_DAMAGE_REGION_MASK)
1329 {
1330 XIntersectRegion (core.tmpRegion,
1331 &outputs[i].region,
1332 core.outputRegion);
1333
1334 if (!(*s->paintOutput) (s,
1335 &defaultScreenPaintAttrib,
1336 &identity,
1337 core.outputRegion, &outputs[i],
1338 PAINT_SCREEN_REGION_MASK))
1339 {
1340 (*s->paintOutput) (s,
1341 &defaultScreenPaintAttrib,
1342 &identity,
1343 &outputs[i].region, &outputs[i],
1344 PAINT_SCREEN_FULL_MASK);
1345
1346 XUnionRegion (core.tmpRegion,
1347 &outputs[i].region,
1348 core.tmpRegion);
1349
1350 }
1351 }
1352 }
1353 }
1354
1355 void
eventLoop(void)1356 eventLoop (void)
1357 {
1358 XEvent event;
1359 int timeDiff;
1360 struct timeval tv;
1361 CompDisplay *d;
1362 CompScreen *s;
1363 CompWindow *w;
1364 CompTimeout *t;
1365 int time, timeToNextRedraw = 0;
1366 unsigned int damageMask, mask;
1367
1368 for (d = core.displays; d; d = d->next)
1369 d->watchFdHandle =
1370 compAddWatchFd (ConnectionNumber (d->display), POLLIN, NULL, NULL);
1371
1372 for (;;)
1373 {
1374 if (restartSignal || shutDown)
1375 break;
1376
1377 for (d = core.displays; d; d = d->next)
1378 {
1379 if (d->dirtyPluginList)
1380 updatePlugins (d);
1381
1382 while (XPending (d->display))
1383 {
1384 XNextEvent (d->display, &event);
1385
1386 switch (event.type) {
1387 case ButtonPress:
1388 case ButtonRelease:
1389 pointerX = event.xbutton.x_root;
1390 pointerY = event.xbutton.y_root;
1391 break;
1392 case KeyPress:
1393 case KeyRelease:
1394 pointerX = event.xkey.x_root;
1395 pointerY = event.xkey.y_root;
1396 break;
1397 case MotionNotify:
1398 pointerX = event.xmotion.x_root;
1399 pointerY = event.xmotion.y_root;
1400 break;
1401 case EnterNotify:
1402 case LeaveNotify:
1403 pointerX = event.xcrossing.x_root;
1404 pointerY = event.xcrossing.y_root;
1405 break;
1406 case ClientMessage:
1407 if (event.xclient.message_type == d->xdndPositionAtom)
1408 {
1409 pointerX = event.xclient.data.l[2] >> 16;
1410 pointerY = event.xclient.data.l[2] & 0xffff;
1411 }
1412 default:
1413 break;
1414 }
1415
1416 sn_display_process_event (d->snDisplay, &event);
1417
1418 inHandleEvent = TRUE;
1419
1420 (*d->handleEvent) (d, &event);
1421
1422 inHandleEvent = FALSE;
1423
1424 lastPointerX = pointerX;
1425 lastPointerY = pointerY;
1426 }
1427 }
1428
1429 for (d = core.displays; d; d = d->next)
1430 {
1431 for (s = d->screens; s; s = s->next)
1432 {
1433 if (s->damageMask)
1434 {
1435 finishScreenDrawing (s);
1436 }
1437 else
1438 {
1439 s->idle = TRUE;
1440 }
1441 }
1442 }
1443
1444 damageMask = 0;
1445 timeToNextRedraw = MAXSHORT;
1446
1447 for (d = core.displays; d; d = d->next)
1448 {
1449 for (s = d->screens; s; s = s->next)
1450 {
1451 if (!s->damageMask)
1452 continue;
1453
1454 if (!damageMask)
1455 {
1456 gettimeofday (&tv, 0);
1457 damageMask |= s->damageMask;
1458 }
1459
1460 s->timeLeft = getTimeToNextRedraw (s, &tv, &s->lastRedraw,
1461 s->idle);
1462 if (s->timeLeft < timeToNextRedraw)
1463 timeToNextRedraw = s->timeLeft;
1464 }
1465 }
1466
1467 if (damageMask)
1468 {
1469 time = timeToNextRedraw;
1470 if (time)
1471 time = doPoll (time);
1472
1473 if (time == 0)
1474 {
1475 gettimeofday (&tv, 0);
1476
1477 if (core.timeouts)
1478 handleTimeouts (&tv);
1479
1480 for (d = core.displays; d; d = d->next)
1481 {
1482 for (s = d->screens; s; s = s->next)
1483 {
1484 if (!s->damageMask || s->timeLeft > timeToNextRedraw)
1485 continue;
1486
1487 targetScreen = s;
1488
1489 timeDiff = TIMEVALDIFF (&tv, &s->lastRedraw);
1490
1491 /* handle clock rollback */
1492 if (timeDiff < 0)
1493 timeDiff = 0;
1494
1495 makeScreenCurrent (s);
1496
1497 if (s->slowAnimations)
1498 {
1499 (*s->preparePaintScreen) (s,
1500 s->idle ? 2 :
1501 (timeDiff * 2) /
1502 s->redrawTime);
1503 }
1504 else
1505 (*s->preparePaintScreen) (s,
1506 s->idle ? s->redrawTime :
1507 timeDiff);
1508
1509 /* substract top most overlay window region */
1510 if (s->overlayWindowCount)
1511 {
1512 for (w = s->reverseWindows; w; w = w->prev)
1513 {
1514 if (w->destroyed || w->invisible)
1515 continue;
1516
1517 if (!w->redirected)
1518 XSubtractRegion (s->damage, w->region,
1519 s->damage);
1520
1521 break;
1522 }
1523
1524 if (s->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK)
1525 {
1526 s->damageMask &= ~COMP_SCREEN_DAMAGE_ALL_MASK;
1527 s->damageMask |=
1528 COMP_SCREEN_DAMAGE_REGION_MASK;
1529 }
1530 }
1531
1532 if (s->damageMask & COMP_SCREEN_DAMAGE_REGION_MASK)
1533 {
1534 XIntersectRegion (s->damage, &s->region,
1535 core.tmpRegion);
1536
1537 if (core.tmpRegion->numRects == 1 &&
1538 core.tmpRegion->rects->x1 == 0 &&
1539 core.tmpRegion->rects->y1 == 0 &&
1540 core.tmpRegion->rects->x2 == s->width &&
1541 core.tmpRegion->rects->y2 == s->height)
1542 damageScreen (s);
1543 }
1544
1545 EMPTY_REGION (s->damage);
1546
1547 mask = s->damageMask;
1548 s->damageMask = 0;
1549
1550 if (s->clearBuffers)
1551 {
1552 if (mask & COMP_SCREEN_DAMAGE_ALL_MASK)
1553 glClear (GL_COLOR_BUFFER_BIT);
1554 }
1555
1556 if (s->opt[COMP_SCREEN_OPTION_FORCE_INDEPENDENT].value.b
1557 || !s->hasOverlappingOutputs)
1558 (*s->paintScreen) (s, s->outputDev,
1559 s->nOutputDev,
1560 mask);
1561 else
1562 (*s->paintScreen) (s, &s->fullscreenOutput, 1,
1563 mask);
1564
1565 targetScreen = NULL;
1566 targetOutput = &s->outputDev[0];
1567
1568 waitForVideoSync (s);
1569
1570 if (mask & COMP_SCREEN_DAMAGE_ALL_MASK)
1571 {
1572 glXSwapBuffers (d->display, s->output);
1573 }
1574 else
1575 {
1576 BoxPtr pBox;
1577 int nBox, y;
1578
1579 pBox = core.tmpRegion->rects;
1580 nBox = core.tmpRegion->numRects;
1581
1582 if (s->copySubBuffer)
1583 {
1584 while (nBox--)
1585 {
1586 y = s->height - pBox->y2;
1587
1588 (*s->copySubBuffer) (d->display,
1589 s->output,
1590 pBox->x1, y,
1591 pBox->x2 - pBox->x1,
1592 pBox->y2 - pBox->y1);
1593
1594 pBox++;
1595 }
1596 }
1597 else
1598 {
1599 glEnable (GL_SCISSOR_TEST);
1600 glDrawBuffer (GL_FRONT);
1601
1602 while (nBox--)
1603 {
1604 y = s->height - pBox->y2;
1605
1606 glBitmap (0, 0, 0, 0,
1607 pBox->x1 - s->rasterX,
1608 y - s->rasterY,
1609 NULL);
1610
1611 s->rasterX = pBox->x1;
1612 s->rasterY = y;
1613
1614 glScissor (pBox->x1, y,
1615 pBox->x2 - pBox->x1,
1616 pBox->y2 - pBox->y1);
1617
1618 glCopyPixels (pBox->x1, y,
1619 pBox->x2 - pBox->x1,
1620 pBox->y2 - pBox->y1,
1621 GL_COLOR);
1622
1623 pBox++;
1624 }
1625
1626 glDrawBuffer (GL_BACK);
1627 glDisable (GL_SCISSOR_TEST);
1628 glFlush ();
1629 }
1630 }
1631
1632 s->lastRedraw = tv;
1633
1634 (*s->donePaintScreen) (s);
1635
1636 /* remove destroyed windows */
1637 while (s->pendingDestroys)
1638 {
1639 CompWindow *w;
1640
1641 for (w = s->windows; w; w = w->next)
1642 {
1643 if (w->destroyed)
1644 {
1645 addWindowDamage (w);
1646 removeWindow (w);
1647 break;
1648 }
1649 }
1650
1651 s->pendingDestroys--;
1652 }
1653
1654 s->idle = FALSE;
1655 }
1656 }
1657 }
1658 }
1659 else
1660 {
1661 if (core.timeouts)
1662 {
1663 if (core.timeouts->minLeft > 0)
1664 {
1665 t = core.timeouts;
1666 time = t->maxLeft;
1667 while (t && t->minLeft <= time)
1668 {
1669 if (t->maxLeft < time)
1670 time = t->maxLeft;
1671 t = t->next;
1672 }
1673 doPoll (time);
1674 }
1675
1676 gettimeofday (&tv, 0);
1677
1678 handleTimeouts (&tv);
1679 }
1680 else
1681 {
1682 doPoll (-1);
1683 }
1684 }
1685 }
1686
1687 for (d = core.displays; d; d = d->next)
1688 compRemoveWatchFd (d->watchFdHandle);
1689 }
1690
1691 static int errors = 0;
1692
1693 static int
errorHandler(Display * dpy,XErrorEvent * e)1694 errorHandler (Display *dpy,
1695 XErrorEvent *e)
1696 {
1697
1698 #ifdef DEBUG
1699 char str[128];
1700 #endif
1701
1702 errors++;
1703
1704 #ifdef DEBUG
1705 XGetErrorDatabaseText (dpy, "XlibMessage", "XError", "", str, 128);
1706 fprintf (stderr, "%s", str);
1707
1708 XGetErrorText (dpy, e->error_code, str, 128);
1709 fprintf (stderr, ": %s\n ", str);
1710
1711 XGetErrorDatabaseText (dpy, "XlibMessage", "MajorCode", "%d", str, 128);
1712 fprintf (stderr, str, e->request_code);
1713
1714 sprintf (str, "%d", e->request_code);
1715 XGetErrorDatabaseText (dpy, "XRequest", str, "", str, 128);
1716 if (strcmp (str, ""))
1717 fprintf (stderr, " (%s)", str);
1718 fprintf (stderr, "\n ");
1719
1720 XGetErrorDatabaseText (dpy, "XlibMessage", "MinorCode", "%d", str, 128);
1721 fprintf (stderr, str, e->minor_code);
1722 fprintf (stderr, "\n ");
1723
1724 XGetErrorDatabaseText (dpy, "XlibMessage", "ResourceID", "%d", str, 128);
1725 fprintf (stderr, str, e->resourceid);
1726 fprintf (stderr, "\n");
1727
1728 /* abort (); */
1729 #endif
1730
1731 return 0;
1732 }
1733
1734 int
compCheckForError(Display * dpy)1735 compCheckForError (Display *dpy)
1736 {
1737 int e;
1738
1739 XSync (dpy, FALSE);
1740
1741 e = errors;
1742 errors = 0;
1743
1744 return e;
1745 }
1746
1747 /* add actions that should be automatically added as no screens
1748 existed when they were initialized. */
1749 static void
addScreenActions(CompScreen * s)1750 addScreenActions (CompScreen *s)
1751 {
1752 int i;
1753
1754 for (i = 0; i < COMP_DISPLAY_OPTION_NUM; i++)
1755 {
1756 if (!isActionOption (&s->display->opt[i]))
1757 continue;
1758
1759 if (s->display->opt[i].value.action.state & CompActionStateAutoGrab)
1760 addScreenAction (s, &s->display->opt[i].value.action);
1761 }
1762 }
1763
1764 void
addScreenToDisplay(CompDisplay * display,CompScreen * s)1765 addScreenToDisplay (CompDisplay *display,
1766 CompScreen *s)
1767 {
1768 CompScreen *prev;
1769
1770 for (prev = display->screens; prev && prev->next; prev = prev->next);
1771
1772 if (prev)
1773 prev->next = s;
1774 else
1775 display->screens = s;
1776
1777 addScreenActions (s);
1778 }
1779
1780 static void
freeDisplay(CompDisplay * d)1781 freeDisplay (CompDisplay *d)
1782 {
1783 compFiniDisplayOptions (d, d->opt, COMP_DISPLAY_OPTION_NUM);
1784
1785 compFiniOptionValue (&d->plugin, CompOptionTypeList);
1786
1787 if (d->modMap)
1788 XFreeModifiermap (d->modMap);
1789
1790 if (d->screenInfo)
1791 XFree (d->screenInfo);
1792
1793 if (d->screenPrivateIndices)
1794 free (d->screenPrivateIndices);
1795
1796 if (d->base.privates)
1797 free (d->base.privates);
1798
1799 free (d);
1800 }
1801
1802 static Bool
aquireSelection(CompDisplay * d,int screen,const char * name,Atom selection,Window owner,Time timestamp)1803 aquireSelection (CompDisplay *d,
1804 int screen,
1805 const char *name,
1806 Atom selection,
1807 Window owner,
1808 Time timestamp)
1809 {
1810 Display *dpy = d->display;
1811 Window root = XRootWindow (dpy, screen);
1812 XEvent event;
1813
1814 XSetSelectionOwner (dpy, selection, owner, timestamp);
1815
1816 if (XGetSelectionOwner (dpy, selection) != owner)
1817 {
1818 compLogMessage ("core", CompLogLevelError,
1819 "Could not acquire %s manager "
1820 "selection on screen %d display \"%s\"",
1821 name, screen, DisplayString (dpy));
1822
1823 return FALSE;
1824 }
1825
1826 /* Send client message indicating that we are now the manager */
1827 event.xclient.type = ClientMessage;
1828 event.xclient.window = root;
1829 event.xclient.message_type = d->managerAtom;
1830 event.xclient.format = 32;
1831 event.xclient.data.l[0] = timestamp;
1832 event.xclient.data.l[1] = selection;
1833 event.xclient.data.l[2] = 0;
1834 event.xclient.data.l[3] = 0;
1835 event.xclient.data.l[4] = 0;
1836
1837 XSendEvent (dpy, root, FALSE, StructureNotifyMask, &event);
1838
1839 return TRUE;
1840 }
1841
1842 Bool
addDisplay(const char * name)1843 addDisplay (const char *name)
1844 {
1845 CompDisplay *d;
1846 CompPrivate *privates;
1847 Display *dpy;
1848 Window focus;
1849 int revertTo, i;
1850 int compositeMajor, compositeMinor;
1851 int fixesMinor;
1852 int xkbOpcode;
1853 int firstScreen, lastScreen;
1854
1855 d = malloc (sizeof (CompDisplay));
1856 if (!d)
1857 return FALSE;
1858
1859 if (displayPrivateLen)
1860 {
1861 privates = malloc (displayPrivateLen * sizeof (CompPrivate));
1862 if (!privates)
1863 {
1864 free (d);
1865 return FALSE;
1866 }
1867 }
1868 else
1869 privates = 0;
1870
1871 compObjectInit (&d->base, privates, COMP_OBJECT_TYPE_DISPLAY);
1872
1873 d->next = NULL;
1874 d->screens = NULL;
1875
1876 d->watchFdHandle = 0;
1877
1878 d->screenPrivateIndices = 0;
1879 d->screenPrivateLen = 0;
1880
1881 d->edgeDelayHandle = 0;
1882
1883 d->modMap = 0;
1884
1885 for (i = 0; i < CompModNum; i++)
1886 d->modMask[i] = CompNoMask;
1887
1888 d->ignoredModMask = LockMask;
1889
1890 compInitOptionValue (&d->plugin);
1891
1892 d->plugin.list.type = CompOptionTypeString;
1893 d->plugin.list.nValue = 1;
1894 d->plugin.list.value = malloc (sizeof (CompOptionValue));
1895
1896 if (!d->plugin.list.value) {
1897 free (d);
1898 return FALSE;
1899 }
1900
1901 d->plugin.list.value->s = strdup ("core");
1902 if (!d->plugin.list.value->s) {
1903 free (d->plugin.list.value);
1904 free (d);
1905 return FALSE;
1906 }
1907
1908 d->dirtyPluginList = TRUE;
1909
1910 d->textureFilter = GL_LINEAR;
1911 d->below = None;
1912
1913 d->activeWindow = 0;
1914
1915 d->autoRaiseHandle = 0;
1916 d->autoRaiseWindow = None;
1917
1918 d->display = dpy = XOpenDisplay (name);
1919 if (!d->display)
1920 {
1921 compLogMessage ("core", CompLogLevelFatal,
1922 "Couldn't open display %s", XDisplayName (name));
1923 return FALSE;
1924 }
1925
1926 if (!compInitDisplayOptionsFromMetadata (d,
1927 &coreMetadata,
1928 coreDisplayOptionInfo,
1929 d->opt,
1930 COMP_DISPLAY_OPTION_NUM))
1931 return FALSE;
1932
1933 d->opt[COMP_DISPLAY_OPTION_ABI].value.i = CORE_ABIVERSION;
1934
1935 snprintf (d->displayString, 255, "DISPLAY=%s", DisplayString (dpy));
1936
1937 #ifdef DEBUG
1938 XSynchronize (dpy, TRUE);
1939 #endif
1940
1941 XSetErrorHandler (errorHandler);
1942
1943 updateModifierMappings (d);
1944
1945 d->handleEvent = handleEvent;
1946 d->handleCompizEvent = handleCompizEvent;
1947
1948 d->fileToImage = fileToImage;
1949 d->imageToFile = imageToFile;
1950
1951 d->matchInitExp = matchInitExp;
1952 d->matchExpHandlerChanged = matchExpHandlerChanged;
1953 d->matchPropertyChanged = matchPropertyChanged;
1954
1955 d->supportedAtom = XInternAtom (dpy, "_NET_SUPPORTED", 0);
1956 d->supportingWmCheckAtom = XInternAtom (dpy, "_NET_SUPPORTING_WM_CHECK", 0);
1957
1958 d->utf8StringAtom = XInternAtom (dpy, "UTF8_STRING", 0);
1959
1960 d->wmNameAtom = XInternAtom (dpy, "_NET_WM_NAME", 0);
1961
1962 d->winTypeAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", 0);
1963 d->winTypeDesktopAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP",
1964 0);
1965 d->winTypeDockAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", 0);
1966 d->winTypeToolbarAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR",
1967 0);
1968 d->winTypeMenuAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", 0);
1969 d->winTypeUtilAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY",
1970 0);
1971 d->winTypeSplashAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_SPLASH", 0);
1972 d->winTypeDialogAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DIALOG", 0);
1973 d->winTypeNormalAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NORMAL", 0);
1974
1975 d->winTypeDropdownMenuAtom =
1976 XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", 0);
1977 d->winTypePopupMenuAtom =
1978 XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", 0);
1979 d->winTypeTooltipAtom =
1980 XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLTIP", 0);
1981 d->winTypeNotificationAtom =
1982 XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NOTIFICATION", 0);
1983 d->winTypeComboAtom =
1984 XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_COMBO", 0);
1985 d->winTypeDndAtom =
1986 XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DND", 0);
1987
1988 d->winOpacityAtom = XInternAtom (dpy, "_NET_WM_WINDOW_OPACITY", 0);
1989 d->winBrightnessAtom = XInternAtom (dpy, "_NET_WM_WINDOW_BRIGHTNESS", 0);
1990 d->winSaturationAtom = XInternAtom (dpy, "_NET_WM_WINDOW_SATURATION", 0);
1991
1992 d->winActiveAtom = XInternAtom (dpy, "_NET_ACTIVE_WINDOW", 0);
1993
1994 d->winDesktopAtom = XInternAtom (dpy, "_NET_WM_DESKTOP", 0);
1995
1996 d->workareaAtom = XInternAtom (dpy, "_NET_WORKAREA", 0);
1997
1998 d->desktopViewportAtom = XInternAtom (dpy, "_NET_DESKTOP_VIEWPORT", 0);
1999 d->desktopGeometryAtom = XInternAtom (dpy, "_NET_DESKTOP_GEOMETRY", 0);
2000 d->currentDesktopAtom = XInternAtom (dpy, "_NET_CURRENT_DESKTOP", 0);
2001 d->numberOfDesktopsAtom = XInternAtom (dpy, "_NET_NUMBER_OF_DESKTOPS", 0);
2002
2003 d->winStateAtom = XInternAtom (dpy, "_NET_WM_STATE", 0);
2004 d->winStateModalAtom =
2005 XInternAtom (dpy, "_NET_WM_STATE_MODAL", 0);
2006 d->winStateStickyAtom =
2007 XInternAtom (dpy, "_NET_WM_STATE_STICKY", 0);
2008 d->winStateMaximizedVertAtom =
2009 XInternAtom (dpy, "_NET_WM_STATE_MAXIMIZED_VERT", 0);
2010 d->winStateMaximizedHorzAtom =
2011 XInternAtom (dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", 0);
2012 d->winStateShadedAtom =
2013 XInternAtom (dpy, "_NET_WM_STATE_SHADED", 0);
2014 d->winStateSkipTaskbarAtom =
2015 XInternAtom (dpy, "_NET_WM_STATE_SKIP_TASKBAR", 0);
2016 d->winStateSkipPagerAtom =
2017 XInternAtom (dpy, "_NET_WM_STATE_SKIP_PAGER", 0);
2018 d->winStateHiddenAtom =
2019 XInternAtom (dpy, "_NET_WM_STATE_HIDDEN", 0);
2020 d->winStateFullscreenAtom =
2021 XInternAtom (dpy, "_NET_WM_STATE_FULLSCREEN", 0);
2022 d->winStateAboveAtom =
2023 XInternAtom (dpy, "_NET_WM_STATE_ABOVE", 0);
2024 d->winStateBelowAtom =
2025 XInternAtom (dpy, "_NET_WM_STATE_BELOW", 0);
2026 d->winStateDemandsAttentionAtom =
2027 XInternAtom (dpy, "_NET_WM_STATE_DEMANDS_ATTENTION", 0);
2028 d->winStateDisplayModalAtom =
2029 XInternAtom (dpy, "_NET_WM_STATE_DISPLAY_MODAL", 0);
2030
2031 d->winActionMoveAtom = XInternAtom (dpy, "_NET_WM_ACTION_MOVE", 0);
2032 d->winActionResizeAtom =
2033 XInternAtom (dpy, "_NET_WM_ACTION_RESIZE", 0);
2034 d->winActionStickAtom =
2035 XInternAtom (dpy, "_NET_WM_ACTION_STICK", 0);
2036 d->winActionMinimizeAtom =
2037 XInternAtom (dpy, "_NET_WM_ACTION_MINIMIZE", 0);
2038 d->winActionMaximizeHorzAtom =
2039 XInternAtom (dpy, "_NET_WM_ACTION_MAXIMIZE_HORZ", 0);
2040 d->winActionMaximizeVertAtom =
2041 XInternAtom (dpy, "_NET_WM_ACTION_MAXIMIZE_VERT", 0);
2042 d->winActionFullscreenAtom =
2043 XInternAtom (dpy, "_NET_WM_ACTION_FULLSCREEN", 0);
2044 d->winActionCloseAtom =
2045 XInternAtom (dpy, "_NET_WM_ACTION_CLOSE", 0);
2046 d->winActionShadeAtom =
2047 XInternAtom (dpy, "_NET_WM_ACTION_SHADE", 0);
2048 d->winActionChangeDesktopAtom =
2049 XInternAtom (dpy, "_NET_WM_ACTION_CHANGE_DESKTOP", 0);
2050 d->winActionAboveAtom =
2051 XInternAtom (dpy, "_NET_WM_ACTION_ABOVE", 0);
2052 d->winActionBelowAtom =
2053 XInternAtom (dpy, "_NET_WM_ACTION_BELOW", 0);
2054
2055 d->wmAllowedActionsAtom = XInternAtom (dpy, "_NET_WM_ALLOWED_ACTIONS", 0);
2056
2057 d->wmStrutAtom = XInternAtom (dpy, "_NET_WM_STRUT", 0);
2058 d->wmStrutPartialAtom = XInternAtom (dpy, "_NET_WM_STRUT_PARTIAL", 0);
2059
2060 d->wmUserTimeAtom = XInternAtom (dpy, "_NET_WM_USER_TIME", 0);
2061
2062 d->wmIconAtom = XInternAtom (dpy,"_NET_WM_ICON", 0);
2063 d->wmIconGeometryAtom = XInternAtom (dpy, "_NET_WM_ICON_GEOMETRY", 0);
2064
2065 d->clientListAtom = XInternAtom (dpy, "_NET_CLIENT_LIST", 0);
2066 d->clientListStackingAtom =
2067 XInternAtom (dpy, "_NET_CLIENT_LIST_STACKING", 0);
2068
2069 d->frameExtentsAtom = XInternAtom (dpy, "_NET_FRAME_EXTENTS", 0);
2070 d->frameWindowAtom = XInternAtom (dpy, "_NET_FRAME_WINDOW", 0);
2071
2072 d->wmStateAtom = XInternAtom (dpy, "WM_STATE", 0);
2073 d->wmChangeStateAtom = XInternAtom (dpy, "WM_CHANGE_STATE", 0);
2074 d->wmProtocolsAtom = XInternAtom (dpy, "WM_PROTOCOLS", 0);
2075 d->wmClientLeaderAtom = XInternAtom (dpy, "WM_CLIENT_LEADER", 0);
2076
2077 d->wmDeleteWindowAtom = XInternAtom (dpy, "WM_DELETE_WINDOW", 0);
2078 d->wmTakeFocusAtom = XInternAtom (dpy, "WM_TAKE_FOCUS", 0);
2079 d->wmPingAtom = XInternAtom (dpy, "_NET_WM_PING", 0);
2080
2081 d->wmSyncRequestAtom = XInternAtom (dpy, "_NET_WM_SYNC_REQUEST", 0);
2082 d->wmSyncRequestCounterAtom =
2083 XInternAtom (dpy, "_NET_WM_SYNC_REQUEST_COUNTER", 0);
2084
2085 d->wmFullscreenMonitorsAtom =
2086 XInternAtom (dpy, "_NET_WM_FULLSCREEN_MONITORS", 0);
2087
2088 d->closeWindowAtom = XInternAtom (dpy, "_NET_CLOSE_WINDOW", 0);
2089 d->wmMoveResizeAtom = XInternAtom (dpy, "_NET_WM_MOVERESIZE", 0);
2090 d->moveResizeWindowAtom = XInternAtom (dpy, "_NET_MOVERESIZE_WINDOW", 0);
2091 d->restackWindowAtom = XInternAtom (dpy, "_NET_RESTACK_WINDOW", 0);
2092
2093 d->showingDesktopAtom = XInternAtom (dpy, "_NET_SHOWING_DESKTOP", 0);
2094
2095 d->xBackgroundAtom[0] = XInternAtom (dpy, "_XSETROOT_ID", 0);
2096 d->xBackgroundAtom[1] = XInternAtom (dpy, "_XROOTPMAP_ID", 0);
2097
2098 d->toolkitActionAtom =
2099 XInternAtom (dpy, "_COMPIZ_TOOLKIT_ACTION", 0);
2100 d->toolkitActionWindowMenuAtom =
2101 XInternAtom (dpy, "_COMPIZ_TOOLKIT_ACTION_WINDOW_MENU", 0);
2102 d->toolkitActionForceQuitDialogAtom =
2103 XInternAtom (dpy, "_COMPIZ_TOOLKIT_ACTION_FORCE_QUIT_DIALOG", 0);
2104
2105 d->mwmHintsAtom = XInternAtom (dpy, "_MOTIF_WM_HINTS", 0);
2106
2107 d->xdndAwareAtom = XInternAtom (dpy, "XdndAware", 0);
2108 d->xdndEnterAtom = XInternAtom (dpy, "XdndEnter", 0);
2109 d->xdndLeaveAtom = XInternAtom (dpy, "XdndLeave", 0);
2110 d->xdndPositionAtom = XInternAtom (dpy, "XdndPosition", 0);
2111 d->xdndStatusAtom = XInternAtom (dpy, "XdndStatus", 0);
2112 d->xdndDropAtom = XInternAtom (dpy, "XdndDrop", 0);
2113
2114 d->managerAtom = XInternAtom (dpy, "MANAGER", 0);
2115 d->targetsAtom = XInternAtom (dpy, "TARGETS", 0);
2116 d->multipleAtom = XInternAtom (dpy, "MULTIPLE", 0);
2117 d->timestampAtom = XInternAtom (dpy, "TIMESTAMP", 0);
2118 d->versionAtom = XInternAtom (dpy, "VERSION", 0);
2119 d->atomPairAtom = XInternAtom (dpy, "ATOM_PAIR", 0);
2120
2121 d->startupIdAtom = XInternAtom (dpy, "_NET_STARTUP_ID", 0);
2122
2123 d->snDisplay = sn_display_new (dpy, NULL, NULL);
2124 if (!d->snDisplay)
2125 return FALSE;
2126
2127 d->lastPing = 1;
2128
2129 if (!XQueryExtension (dpy,
2130 COMPOSITE_NAME,
2131 &d->compositeOpcode,
2132 &d->compositeEvent,
2133 &d->compositeError))
2134 {
2135 compLogMessage ("core", CompLogLevelFatal,
2136 "No composite extension");
2137 return FALSE;
2138 }
2139
2140 XCompositeQueryVersion (dpy, &compositeMajor, &compositeMinor);
2141 if (compositeMajor == 0 && compositeMinor < 2)
2142 {
2143 compLogMessage ("core", CompLogLevelFatal,
2144 "Old composite extension");
2145 return FALSE;
2146 }
2147
2148 if (!XDamageQueryExtension (dpy, &d->damageEvent, &d->damageError))
2149 {
2150 compLogMessage ("core", CompLogLevelFatal,
2151 "No damage extension");
2152 return FALSE;
2153 }
2154
2155 if (!XSyncQueryExtension (dpy, &d->syncEvent, &d->syncError))
2156 {
2157 compLogMessage ("core", CompLogLevelFatal,
2158 "No sync extension");
2159 return FALSE;
2160 }
2161
2162 if (!XFixesQueryExtension (dpy, &d->fixesEvent, &d->fixesError))
2163 {
2164 compLogMessage ("core", CompLogLevelFatal,
2165 "No fixes extension");
2166 return FALSE;
2167 }
2168
2169 XFixesQueryVersion (dpy, &d->fixesVersion, &fixesMinor);
2170 /*
2171 if (d->fixesVersion < 5)
2172 {
2173 fprintf (stderr, "%s: Need fixes extension version 5 or later "
2174 "for client-side cursor\n", programName);
2175 }
2176 */
2177
2178 d->randrExtension = XRRQueryExtension (dpy,
2179 &d->randrEvent,
2180 &d->randrError);
2181
2182 d->shapeExtension = XShapeQueryExtension (dpy,
2183 &d->shapeEvent,
2184 &d->shapeError);
2185
2186 d->xkbExtension = XkbQueryExtension (dpy,
2187 &xkbOpcode,
2188 &d->xkbEvent,
2189 &d->xkbError,
2190 NULL, NULL);
2191 if (d->xkbExtension)
2192 {
2193 XkbSelectEvents (dpy,
2194 XkbUseCoreKbd,
2195 XkbBellNotifyMask | XkbStateNotifyMask,
2196 XkbAllEventsMask);
2197 }
2198 else
2199 {
2200 compLogMessage ("core", CompLogLevelFatal,
2201 "No XKB extension");
2202
2203 d->xkbEvent = d->xkbError = -1;
2204 }
2205
2206 d->screenInfo = NULL;
2207 d->nScreenInfo = 0;
2208
2209 d->xineramaExtension = XineramaQueryExtension (dpy,
2210 &d->xineramaEvent,
2211 &d->xineramaError);
2212
2213 if (d->xineramaExtension)
2214 d->screenInfo = XineramaQueryScreens (dpy, &d->nScreenInfo);
2215
2216 d->escapeKeyCode = XKeysymToKeycode (dpy, XStringToKeysym ("Escape"));
2217 d->returnKeyCode = XKeysymToKeycode (dpy, XStringToKeysym ("Return"));
2218
2219 addDisplayToCore (d);
2220
2221 /* TODO: bailout properly when objectInitPlugins fails */
2222 assert (objectInitPlugins (&d->base));
2223
2224 (*core.objectAdd) (&core.base, &d->base);
2225
2226 if (onlyCurrentScreen)
2227 {
2228 firstScreen = DefaultScreen (dpy);
2229 lastScreen = DefaultScreen (dpy);
2230 }
2231 else
2232 {
2233 firstScreen = 0;
2234 lastScreen = ScreenCount (dpy) - 1;
2235 }
2236
2237 for (i = firstScreen; i <= lastScreen; i++)
2238 {
2239 Window newWmSnOwner = None, newCmSnOwner = None;
2240 Atom wmSnAtom = 0, cmSnAtom = 0;
2241 Time wmSnTimestamp = 0;
2242 XEvent event;
2243 XSetWindowAttributes attr;
2244 Window currentWmSnOwner, currentCmSnOwner;
2245 char buf[128];
2246 Window rootDummy, childDummy;
2247 unsigned int uDummy;
2248 int x, y, dummy;
2249
2250 sprintf (buf, "WM_S%d", i);
2251 wmSnAtom = XInternAtom (dpy, buf, 0);
2252
2253 currentWmSnOwner = XGetSelectionOwner (dpy, wmSnAtom);
2254
2255 if (currentWmSnOwner != None)
2256 {
2257 if (!replaceCurrentWm)
2258 {
2259 compLogMessage ("core", CompLogLevelError,
2260 "Screen %d on display \"%s\" already "
2261 "has a window manager; try using the "
2262 "--replace option to replace the current "
2263 "window manager.",
2264 i, DisplayString (dpy));
2265
2266 continue;
2267 }
2268
2269 XSelectInput (dpy, currentWmSnOwner,
2270 StructureNotifyMask);
2271 }
2272
2273 sprintf (buf, "_NET_WM_CM_S%d", i);
2274 cmSnAtom = XInternAtom (dpy, buf, 0);
2275
2276 currentCmSnOwner = XGetSelectionOwner (dpy, cmSnAtom);
2277
2278 if (currentCmSnOwner != None)
2279 {
2280 if (!replaceCurrentWm)
2281 {
2282 compLogMessage ("core", CompLogLevelError,
2283 "Screen %d on display \"%s\" already "
2284 "has a compositing manager; try using the "
2285 "--replace option to replace the current "
2286 "compositing manager.",
2287 i, DisplayString (dpy));
2288
2289 continue;
2290 }
2291 }
2292
2293 attr.override_redirect = TRUE;
2294 attr.event_mask = PropertyChangeMask;
2295
2296 newCmSnOwner = newWmSnOwner =
2297 XCreateWindow (dpy, XRootWindow (dpy, i),
2298 -100, -100, 1, 1, 0,
2299 CopyFromParent, CopyFromParent,
2300 CopyFromParent,
2301 CWOverrideRedirect | CWEventMask,
2302 &attr);
2303
2304 XChangeProperty (dpy,
2305 newWmSnOwner,
2306 d->wmNameAtom,
2307 d->utf8StringAtom, 8,
2308 PropModeReplace,
2309 (unsigned char *) PACKAGE,
2310 strlen (PACKAGE));
2311
2312 XWindowEvent (dpy,
2313 newWmSnOwner,
2314 PropertyChangeMask,
2315 &event);
2316
2317 wmSnTimestamp = event.xproperty.time;
2318
2319 if (!aquireSelection (d, i, "window", wmSnAtom, newWmSnOwner,
2320 wmSnTimestamp))
2321 {
2322 XDestroyWindow (dpy, newWmSnOwner);
2323
2324 continue;
2325 }
2326
2327 /* Wait for old window manager to go away */
2328 if (currentWmSnOwner != None)
2329 {
2330 do {
2331 XWindowEvent (dpy, currentWmSnOwner,
2332 StructureNotifyMask, &event);
2333 } while (event.type != DestroyNotify);
2334 }
2335
2336 compCheckForError (dpy);
2337
2338 XCompositeRedirectSubwindows (dpy, XRootWindow (dpy, i),
2339 CompositeRedirectManual);
2340
2341 if (compCheckForError (dpy))
2342 {
2343 compLogMessage ("core", CompLogLevelError,
2344 "Another composite manager is already "
2345 "running on screen: %d", i);
2346
2347 continue;
2348 }
2349
2350 if (!aquireSelection (d, i, "compositing", cmSnAtom,
2351 newCmSnOwner, wmSnTimestamp))
2352 {
2353 continue;
2354 }
2355
2356 XGrabServer (dpy);
2357
2358 XSelectInput (dpy, XRootWindow (dpy, i),
2359 SubstructureRedirectMask |
2360 SubstructureNotifyMask |
2361 StructureNotifyMask |
2362 PropertyChangeMask |
2363 LeaveWindowMask |
2364 EnterWindowMask |
2365 KeyPressMask |
2366 KeyReleaseMask |
2367 ButtonPressMask |
2368 ButtonReleaseMask |
2369 FocusChangeMask |
2370 ExposureMask);
2371
2372 if (compCheckForError (dpy))
2373 {
2374 compLogMessage ("core", CompLogLevelError,
2375 "Another window manager is "
2376 "already running on screen: %d", i);
2377
2378 XUngrabServer (dpy);
2379 continue;
2380 }
2381
2382 if (!addScreen (d, i, newWmSnOwner, wmSnAtom, wmSnTimestamp))
2383 {
2384 compLogMessage ("core", CompLogLevelError,
2385 "Failed to manage screen: %d", i);
2386 }
2387
2388 if (XQueryPointer (dpy, XRootWindow (dpy, i),
2389 &rootDummy, &childDummy,
2390 &x, &y, &dummy, &dummy, &uDummy))
2391 {
2392 lastPointerX = pointerX = x;
2393 lastPointerY = pointerY = y;
2394 }
2395
2396 XUngrabServer (dpy);
2397 }
2398
2399 if (!d->screens)
2400 {
2401 compLogMessage ("core", CompLogLevelFatal,
2402 "No manageable screens found on display %s",
2403 XDisplayName (name));
2404 return FALSE;
2405 }
2406
2407 setAudibleBell (d, d->opt[COMP_DISPLAY_OPTION_AUDIBLE_BELL].value.b);
2408
2409 XGetInputFocus (dpy, &focus, &revertTo);
2410
2411 /* move input focus to root window so that we get a FocusIn event when
2412 moving it to the default window */
2413 XSetInputFocus (dpy, d->screens->root, RevertToPointerRoot, CurrentTime);
2414
2415 if (focus == None || focus == PointerRoot)
2416 {
2417 focusDefaultWindow (d->screens);
2418 }
2419 else
2420 {
2421 CompWindow *w;
2422
2423 w = findWindowAtDisplay (d, focus);
2424 if (w)
2425 {
2426 moveInputFocusToWindow (w);
2427 }
2428 else
2429 focusDefaultWindow (d->screens);
2430 }
2431
2432 d->pingHandle =
2433 compAddTimeout (d->opt[COMP_DISPLAY_OPTION_PING_DELAY].value.i,
2434 d->opt[COMP_DISPLAY_OPTION_PING_DELAY].value.i + 500,
2435 pingTimeout, d);
2436
2437 return TRUE;
2438 }
2439
2440 void
removeDisplay(CompDisplay * d)2441 removeDisplay (CompDisplay *d)
2442 {
2443 CompDisplay *p;
2444
2445 for (p = core.displays; p; p = p->next)
2446 if (p->next == d)
2447 break;
2448
2449 if (p)
2450 p->next = d->next;
2451 else
2452 core.displays = NULL;
2453
2454 while (d->screens)
2455 removeScreen (d->screens);
2456
2457 (*core.objectRemove) (&core.base, &d->base);
2458
2459 objectFiniPlugins (&d->base);
2460
2461 if (d->edgeDelayHandle)
2462 {
2463 void *closure;
2464
2465 closure = compRemoveTimeout (d->edgeDelayHandle);
2466 if (closure)
2467 free (closure);
2468 }
2469
2470 if (d->autoRaiseHandle)
2471 compRemoveTimeout (d->autoRaiseHandle);
2472
2473 compRemoveTimeout (d->pingHandle);
2474
2475 if (d->snDisplay)
2476 sn_display_unref (d->snDisplay);
2477
2478 XSync (d->display, False);
2479 XCloseDisplay (d->display);
2480
2481 freeDisplay (d);
2482 }
2483
2484 Time
getCurrentTimeFromDisplay(CompDisplay * d)2485 getCurrentTimeFromDisplay (CompDisplay *d)
2486 {
2487 XEvent event;
2488
2489 XChangeProperty (d->display, d->screens->grabWindow,
2490 XA_PRIMARY, XA_STRING, 8,
2491 PropModeAppend, NULL, 0);
2492 XWindowEvent (d->display, d->screens->grabWindow,
2493 PropertyChangeMask,
2494 &event);
2495
2496 return event.xproperty.time;
2497 }
2498
2499 CompScreen *
findScreenAtDisplay(CompDisplay * d,Window root)2500 findScreenAtDisplay (CompDisplay *d,
2501 Window root)
2502 {
2503 CompScreen *s;
2504
2505 for (s = d->screens; s; s = s->next)
2506 {
2507 if (s->root == root)
2508 return s;
2509 }
2510
2511 return 0;
2512 }
2513
2514 void
forEachWindowOnDisplay(CompDisplay * display,ForEachWindowProc proc,void * closure)2515 forEachWindowOnDisplay (CompDisplay *display,
2516 ForEachWindowProc proc,
2517 void *closure)
2518 {
2519 CompScreen *s;
2520
2521 for (s = display->screens; s; s = s->next)
2522 forEachWindowOnScreen (s, proc, closure);
2523 }
2524
2525 CompWindow *
findWindowAtDisplay(CompDisplay * d,Window id)2526 findWindowAtDisplay (CompDisplay *d,
2527 Window id)
2528 {
2529 CompScreen *s;
2530 CompWindow *w;
2531
2532 for (s = d->screens; s; s = s->next)
2533 {
2534 w = findWindowAtScreen (s, id);
2535 if (w)
2536 return w;
2537 }
2538
2539 return 0;
2540 }
2541
2542 CompWindow *
findTopLevelWindowAtDisplay(CompDisplay * d,Window id)2543 findTopLevelWindowAtDisplay (CompDisplay *d,
2544 Window id)
2545 {
2546 CompScreen *s;
2547 CompWindow *w;
2548
2549 for (s = d->screens; s; s = s->next)
2550 {
2551 w = findTopLevelWindowAtScreen (s, id);
2552 if (w)
2553 return w;
2554 }
2555
2556 return 0;
2557 }
2558
2559 static CompScreen *
findScreenForSelection(CompDisplay * display,Window owner,Atom selection)2560 findScreenForSelection (CompDisplay *display,
2561 Window owner,
2562 Atom selection)
2563 {
2564 CompScreen *s;
2565
2566 for (s = display->screens; s; s = s->next)
2567 {
2568 if (s->wmSnSelectionWindow == owner && s->wmSnAtom == selection)
2569 return s;
2570 }
2571
2572 return NULL;
2573 }
2574
2575 /* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
2576 static Bool
convertProperty(CompDisplay * display,CompScreen * screen,Window w,Atom target,Atom property)2577 convertProperty (CompDisplay *display,
2578 CompScreen *screen,
2579 Window w,
2580 Atom target,
2581 Atom property)
2582 {
2583
2584 #define N_TARGETS 4
2585
2586 Atom conversionTargets[N_TARGETS];
2587 long icccmVersion[] = { 2, 0 };
2588
2589 conversionTargets[0] = display->targetsAtom;
2590 conversionTargets[1] = display->multipleAtom;
2591 conversionTargets[2] = display->timestampAtom;
2592 conversionTargets[3] = display->versionAtom;
2593
2594 if (target == display->targetsAtom)
2595 XChangeProperty (display->display, w, property,
2596 XA_ATOM, 32, PropModeReplace,
2597 (unsigned char *) conversionTargets, N_TARGETS);
2598 else if (target == display->timestampAtom)
2599 XChangeProperty (display->display, w, property,
2600 XA_INTEGER, 32, PropModeReplace,
2601 (unsigned char *) &screen->wmSnTimestamp, 1);
2602 else if (target == display->versionAtom)
2603 XChangeProperty (display->display, w, property,
2604 XA_INTEGER, 32, PropModeReplace,
2605 (unsigned char *) icccmVersion, 2);
2606 else
2607 return FALSE;
2608
2609 /* Be sure the PropertyNotify has arrived so we
2610 * can send SelectionNotify
2611 */
2612 XSync (display->display, FALSE);
2613
2614 return TRUE;
2615 }
2616
2617 /* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
2618 void
handleSelectionRequest(CompDisplay * display,XEvent * event)2619 handleSelectionRequest (CompDisplay *display,
2620 XEvent *event)
2621 {
2622 XSelectionEvent reply;
2623 CompScreen *screen;
2624
2625 screen = findScreenForSelection (display,
2626 event->xselectionrequest.owner,
2627 event->xselectionrequest.selection);
2628 if (!screen)
2629 return;
2630
2631 reply.type = SelectionNotify;
2632 reply.display = display->display;
2633 reply.requestor = event->xselectionrequest.requestor;
2634 reply.selection = event->xselectionrequest.selection;
2635 reply.target = event->xselectionrequest.target;
2636 reply.property = None;
2637 reply.time = event->xselectionrequest.time;
2638
2639 if (event->xselectionrequest.target == display->multipleAtom)
2640 {
2641 if (event->xselectionrequest.property != None)
2642 {
2643 Atom type, *adata;
2644 int i, format;
2645 unsigned long num, rest;
2646 unsigned char *data;
2647
2648 if (XGetWindowProperty (display->display,
2649 event->xselectionrequest.requestor,
2650 event->xselectionrequest.property,
2651 0, 256, FALSE,
2652 display->atomPairAtom,
2653 &type, &format, &num, &rest,
2654 &data) != Success)
2655 return;
2656
2657 /* FIXME: to be 100% correct, should deal with rest > 0,
2658 * but since we have 4 possible targets, we will hardly ever
2659 * meet multiple requests with a length > 8
2660 */
2661 adata = (Atom *) data;
2662 i = 0;
2663 while (i < (int) num)
2664 {
2665 if (!convertProperty (display, screen,
2666 event->xselectionrequest.requestor,
2667 adata[i], adata[i + 1]))
2668 adata[i + 1] = None;
2669
2670 i += 2;
2671 }
2672
2673 XChangeProperty (display->display,
2674 event->xselectionrequest.requestor,
2675 event->xselectionrequest.property,
2676 display->atomPairAtom,
2677 32, PropModeReplace, data, num);
2678
2679 if (data)
2680 XFree (data);
2681 }
2682 }
2683 else
2684 {
2685 if (event->xselectionrequest.property == None)
2686 event->xselectionrequest.property = event->xselectionrequest.target;
2687
2688 if (convertProperty (display, screen,
2689 event->xselectionrequest.requestor,
2690 event->xselectionrequest.target,
2691 event->xselectionrequest.property))
2692 reply.property = event->xselectionrequest.property;
2693 }
2694
2695 XSendEvent (display->display,
2696 event->xselectionrequest.requestor,
2697 FALSE, 0L, (XEvent *) &reply);
2698 }
2699
2700 void
handleSelectionClear(CompDisplay * display,XEvent * event)2701 handleSelectionClear (CompDisplay *display,
2702 XEvent *event)
2703 {
2704 /* We need to unmanage the screen on which we lost the selection */
2705 CompScreen *screen;
2706
2707 screen = findScreenForSelection (display,
2708 event->xselectionclear.window,
2709 event->xselectionclear.selection);
2710
2711 if (screen)
2712 shutDown = TRUE;
2713 }
2714
2715 void
warpPointer(CompScreen * s,int dx,int dy)2716 warpPointer (CompScreen *s,
2717 int dx,
2718 int dy)
2719 {
2720 CompDisplay *display = s->display;
2721 XEvent event;
2722
2723 pointerX += dx;
2724 pointerY += dy;
2725
2726 if (pointerX >= s->width)
2727 pointerX = s->width - 1;
2728 else if (pointerX < 0)
2729 pointerX = 0;
2730
2731 if (pointerY >= s->height)
2732 pointerY = s->height - 1;
2733 else if (pointerY < 0)
2734 pointerY = 0;
2735
2736 XWarpPointer (display->display,
2737 None, s->root,
2738 0, 0, 0, 0,
2739 pointerX, pointerY);
2740
2741 XSync (display->display, FALSE);
2742
2743 while (XCheckMaskEvent (display->display,
2744 LeaveWindowMask |
2745 EnterWindowMask |
2746 PointerMotionMask,
2747 &event));
2748
2749 if (!inHandleEvent)
2750 {
2751 lastPointerX = pointerX;
2752 lastPointerY = pointerY;
2753 }
2754 }
2755
2756 Bool
setDisplayAction(CompDisplay * display,CompOption * o,CompOptionValue * value)2757 setDisplayAction (CompDisplay *display,
2758 CompOption *o,
2759 CompOptionValue *value)
2760 {
2761 CompScreen *s;
2762
2763 for (s = display->screens; s; s = s->next)
2764 if (!addScreenAction (s, &value->action))
2765 break;
2766
2767 if (s)
2768 {
2769 CompScreen *failed = s;
2770
2771 for (s = display->screens; s && s != failed; s = s->next)
2772 removeScreenAction (s, &value->action);
2773
2774 return FALSE;
2775 }
2776 else
2777 {
2778 for (s = display->screens; s; s = s->next)
2779 removeScreenAction (s, &o->value.action);
2780 }
2781
2782 if (compSetActionOption (o, value))
2783 return TRUE;
2784
2785 return FALSE;
2786 }
2787
2788 void
clearTargetOutput(CompDisplay * display,unsigned int mask)2789 clearTargetOutput (CompDisplay *display,
2790 unsigned int mask)
2791 {
2792 if (targetScreen)
2793 clearScreenOutput (targetScreen,
2794 targetOutput,
2795 mask);
2796 }
2797
2798 #define HOME_IMAGEDIR ".compiz/images"
2799
2800 Bool
readImageFromFile(CompDisplay * display,const char * name,int * width,int * height,void ** data)2801 readImageFromFile (CompDisplay *display,
2802 const char *name,
2803 int *width,
2804 int *height,
2805 void **data)
2806 {
2807 Bool status;
2808 int stride;
2809
2810 status = (*display->fileToImage) (display, NULL, name, width, height,
2811 &stride, data);
2812 if (!status)
2813 {
2814 char *home;
2815
2816 home = getenv ("HOME");
2817 if (home)
2818 {
2819 char *path;
2820
2821 path = malloc (strlen (home) + strlen (HOME_IMAGEDIR) + 2);
2822 if (path)
2823 {
2824 sprintf (path, "%s/%s", home, HOME_IMAGEDIR);
2825 status = (*display->fileToImage) (display, path, name,
2826 width, height, &stride,
2827 data);
2828
2829 free (path);
2830
2831 if (status)
2832 return TRUE;
2833 }
2834 }
2835
2836 status = (*display->fileToImage) (display, IMAGEDIR, name,
2837 width, height, &stride, data);
2838 }
2839
2840 return status;
2841 }
2842
2843 Bool
writeImageToFile(CompDisplay * display,const char * path,const char * name,const char * format,int width,int height,void * data)2844 writeImageToFile (CompDisplay *display,
2845 const char *path,
2846 const char *name,
2847 const char *format,
2848 int width,
2849 int height,
2850 void *data)
2851 {
2852 return (*display->imageToFile) (display, path, name, format, width, height,
2853 width * 4, data);
2854 }
2855
2856 Bool
fileToImage(CompDisplay * display,const char * path,const char * name,int * width,int * height,int * stride,void ** data)2857 fileToImage (CompDisplay *display,
2858 const char *path,
2859 const char *name,
2860 int *width,
2861 int *height,
2862 int *stride,
2863 void **data)
2864 {
2865 return FALSE;
2866 }
2867
2868 Bool
imageToFile(CompDisplay * display,const char * path,const char * name,const char * format,int width,int height,int stride,void * data)2869 imageToFile (CompDisplay *display,
2870 const char *path,
2871 const char *name,
2872 const char *format,
2873 int width,
2874 int height,
2875 int stride,
2876 void *data)
2877 {
2878 return FALSE;
2879 }
2880
2881 CompCursor *
findCursorAtDisplay(CompDisplay * display)2882 findCursorAtDisplay (CompDisplay *display)
2883 {
2884 CompScreen *s;
2885
2886 for (s = display->screens; s; s = s->next)
2887 if (s->cursors)
2888 return s->cursors;
2889
2890 return NULL;
2891 }
2892