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