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 <stdarg.h>
33 #include <math.h>
34 #include <dlfcn.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38 #include <assert.h>
39 #include <limits.h>
40 
41 #include <X11/Xlib.h>
42 #include <X11/Xatom.h>
43 #include <X11/Xproto.h>
44 #include <X11/extensions/Xrandr.h>
45 #include <X11/extensions/shape.h>
46 #include <X11/cursorfont.h>
47 
48 #include <compiz-core.h>
49 
50 #define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
51 
52 static int
reallocScreenPrivate(int size,void * closure)53 reallocScreenPrivate (int  size,
54 		      void *closure)
55 {
56     CompDisplay *d = (CompDisplay *) closure;
57     CompScreen  *s;
58     void        *privates;
59 
60     for (s = d->screens; s; s = s->next)
61     {
62 	privates = realloc (s->base.privates, size * sizeof (CompPrivate));
63 	if (!privates)
64 	    return FALSE;
65 
66 	s->base.privates = (CompPrivate *) privates;
67     }
68 
69     return TRUE;
70 }
71 
72 int
allocScreenObjectPrivateIndex(CompObject * parent)73 allocScreenObjectPrivateIndex (CompObject *parent)
74 {
75     CompDisplay *display = (CompDisplay *) parent;
76 
77     return allocatePrivateIndex (&display->screenPrivateLen,
78 				 &display->screenPrivateIndices,
79 				 reallocScreenPrivate,
80 				 (void *) display);
81 }
82 
83 void
freeScreenObjectPrivateIndex(CompObject * parent,int index)84 freeScreenObjectPrivateIndex (CompObject *parent,
85 			      int	 index)
86 {
87     CompDisplay *display = (CompDisplay *) parent;
88 
89     freePrivateIndex (display->screenPrivateLen,
90 		      display->screenPrivateIndices,
91 		      index);
92 }
93 
94 CompBool
forEachScreenObject(CompObject * parent,ObjectCallBackProc proc,void * closure)95 forEachScreenObject (CompObject	        *parent,
96 		     ObjectCallBackProc proc,
97 		     void	        *closure)
98 {
99     if (parent->type == COMP_OBJECT_TYPE_DISPLAY)
100     {
101 	CompScreen *s;
102 
103 	CORE_DISPLAY (parent);
104 
105 	for (s = d->screens; s; s = s->next)
106 	{
107 	    if (!(*proc) (&s->base, closure))
108 		return FALSE;
109 	}
110     }
111 
112     return TRUE;
113 }
114 
115 char *
nameScreenObject(CompObject * object)116 nameScreenObject (CompObject *object)
117 {
118     char tmp[256];
119 
120     CORE_SCREEN (object);
121 
122     snprintf (tmp, 256, "%d", s->screenNum);
123 
124     return strdup (tmp);
125 }
126 
127 CompObject *
findScreenObject(CompObject * parent,const char * name)128 findScreenObject (CompObject *parent,
129 		  const char *name)
130 {
131     if (parent->type == COMP_OBJECT_TYPE_DISPLAY)
132     {
133 	CompScreen *s;
134 	int	   screenNum = atoi (name);
135 
136 	CORE_DISPLAY (parent);
137 
138 	for (s = d->screens; s; s = s->next)
139 	    if (s->screenNum == screenNum)
140 		return &s->base;
141     }
142 
143     return NULL;
144 }
145 
146 int
allocateScreenPrivateIndex(CompDisplay * display)147 allocateScreenPrivateIndex (CompDisplay *display)
148 {
149     return compObjectAllocatePrivateIndex (&display->base,
150 					   COMP_OBJECT_TYPE_SCREEN);
151 }
152 
153 void
freeScreenPrivateIndex(CompDisplay * display,int index)154 freeScreenPrivateIndex (CompDisplay *display,
155 			int	    index)
156 {
157     compObjectFreePrivateIndex (&display->base,
158 				COMP_OBJECT_TYPE_SCREEN,
159 				index);
160 }
161 
162 static Bool
desktopHintEqual(CompScreen * s,unsigned long * data,int size,int offset,int hintSize)163 desktopHintEqual (CompScreen	*s,
164 		  unsigned long *data,
165 		  int		size,
166 		  int		offset,
167 		  int		hintSize)
168 {
169     if (size != s->desktopHintSize)
170 	return FALSE;
171 
172     if (memcmp (data + offset,
173 		s->desktopHintData + offset,
174 		hintSize * sizeof (unsigned long)) == 0)
175 	return TRUE;
176 
177     return FALSE;
178 }
179 
180 static void
setDesktopHints(CompScreen * s)181 setDesktopHints (CompScreen *s)
182 {
183     CompDisplay   *d = s->display;
184     unsigned long *data;
185     int		  size, offset, hintSize, i;
186 
187     size = s->nDesktop * 2 + s->nDesktop * 2 + s->nDesktop * 4 + 1;
188 
189     data = malloc (sizeof (unsigned long) * size);
190     if (!data)
191 	return;
192 
193     offset   = 0;
194     hintSize = s->nDesktop * 2;
195 
196     for (i = 0; i < s->nDesktop; i++)
197     {
198 	data[offset + i * 2 + 0] = s->x * s->width;
199 	data[offset + i * 2 + 1] = s->y * s->height;
200     }
201 
202     if (!desktopHintEqual (s, data, size, offset, hintSize))
203 	XChangeProperty (d->display, s->root, d->desktopViewportAtom,
204 			 XA_CARDINAL, 32, PropModeReplace,
205 			 (unsigned char *) &data[offset], hintSize);
206 
207     offset += hintSize;
208 
209     for (i = 0; i < s->nDesktop; i++)
210     {
211 	data[offset + i * 2 + 0] = s->width  * s->hsize;
212 	data[offset + i * 2 + 1] = s->height * s->vsize;
213     }
214 
215     if (!desktopHintEqual (s, data, size, offset, hintSize))
216 	XChangeProperty (d->display, s->root, d->desktopGeometryAtom,
217 			 XA_CARDINAL, 32, PropModeReplace,
218 			 (unsigned char *) &data[offset], hintSize);
219 
220     offset += hintSize;
221     hintSize = s->nDesktop * 4;
222 
223     for (i = 0; i < s->nDesktop; i++)
224     {
225 	data[offset + i * 4 + 0] = s->workArea.x;
226 	data[offset + i * 4 + 1] = s->workArea.y;
227 	data[offset + i * 4 + 2] = s->workArea.width;
228 	data[offset + i * 4 + 3] = s->workArea.height;
229     }
230 
231     if (!desktopHintEqual (s, data, size, offset, hintSize))
232 	XChangeProperty (d->display, s->root, d->workareaAtom,
233 			 XA_CARDINAL, 32, PropModeReplace,
234 			 (unsigned char *) &data[offset], hintSize);
235 
236     offset += hintSize;
237 
238     data[offset] = s->nDesktop;
239     hintSize = 1;
240 
241     if (!desktopHintEqual (s, data, size, offset, hintSize))
242 	XChangeProperty (d->display, s->root, d->numberOfDesktopsAtom,
243 			 XA_CARDINAL, 32, PropModeReplace,
244 			 (unsigned char *) &data[offset], hintSize);
245 
246     if (s->desktopHintData)
247 	free (s->desktopHintData);
248 
249     s->desktopHintData = data;
250     s->desktopHintSize = size;
251 }
252 
253 static void
setVirtualScreenSize(CompScreen * screen,int hsize,int vsize)254 setVirtualScreenSize (CompScreen *screen,
255 		      int	 hsize,
256 		      int	 vsize)
257 {
258     /* if hsize or vsize is being reduced */
259     if (hsize < screen->hsize ||
260 	vsize < screen->vsize)
261     {
262 	CompWindow *w;
263 	int        tx = 0;
264 	int        ty = 0;
265 
266 	if (screen->x >= hsize)
267 	    tx = screen->x - (hsize - 1);
268 	if (screen->y >= vsize)
269 	    ty = screen->y - (vsize - 1);
270 
271 	if (tx != 0 || ty != 0)
272 	    moveScreenViewport (screen, tx, ty, TRUE);
273 
274 	/* Move windows that were in one of the deleted viewports into the
275 	   closest viewport */
276 	for (w = screen->windows; w; w = w->next)
277 	{
278 	    int moveX = 0;
279 	    int moveY = 0;
280 
281 	    if (windowOnAllViewports (w))
282 		continue;
283 
284 	    /* Find which viewport the (inner) window's top-left corner falls
285 	       in, and check if it's outside the new viewport horizontal and
286 	       vertical index range */
287 	    if (hsize < screen->hsize)
288 	    {
289 		int vpX;   /* x index of a window's vp */
290 
291 		vpX = w->serverX / screen->width;
292 		if (w->serverX < 0)
293 		    vpX -= 1;
294 
295 		vpX += screen->x; /* Convert relative to absolute vp index */
296 
297 		/* Move windows too far right to left */
298 		if (vpX >= hsize)
299 		    moveX = ((hsize - 1) - vpX) * screen->width;
300 	    }
301 	    if (vsize < screen->vsize)
302 	    {
303 		int vpY;   /* y index of a window's vp */
304 
305 		vpY = w->serverY / screen->height;
306 		if (w->serverY < 0)
307 		    vpY -= 1;
308 
309 		vpY += screen->y; /* Convert relative to absolute vp index */
310 
311 		/* Move windows too far right to left */
312 		if (vpY >= vsize)
313 		    moveY = ((vsize - 1) - vpY) * screen->height;
314 	    }
315 
316 	    if (moveX != 0 || moveY != 0)
317 	    {
318 		moveWindow (w, moveX, moveY, TRUE, TRUE);
319 		syncWindowPosition (w);
320 	    }
321 	}
322     }
323 
324     screen->hsize = hsize;
325     screen->vsize = vsize;
326 
327     setDesktopHints (screen);
328 }
329 
330 static void
updateOutputDevices(CompScreen * s)331 updateOutputDevices (CompScreen	*s)
332 {
333     CompOutput	  *o, *output = NULL;
334     CompListValue *list = &s->opt[COMP_SCREEN_OPTION_OUTPUTS].value.list;
335     int		  nOutput = 0;
336     int		  x, y, i, j, bits;
337     unsigned int  width, height;
338     int		  x1, y1, x2, y2;
339     Region	  region;
340     CompWindow    *w;
341 
342     for (i = 0; i < list->nValue; i++)
343     {
344 	if (!list->value[i].s)
345 	    continue;
346 
347 	x      = 0;
348 	y      = 0;
349 	width  = s->width;
350 	height = s->height;
351 
352 	bits = XParseGeometry (list->value[i].s, &x, &y, &width, &height);
353 
354 	if (bits & XNegative)
355 	    x = s->width + x - width;
356 
357 	if (bits & YNegative)
358 	    y = s->height + y - height;
359 
360 	x1 = x;
361 	y1 = y;
362 	x2 = x + width;
363 	y2 = y + height;
364 
365 	if (x1 < 0)
366 	    x1 = 0;
367 	if (y1 < 0)
368 	    y1 = 0;
369 	if (x2 > s->width)
370 	    x2 = s->width;
371 	if (y2 > s->height)
372 	    y2 = s->height;
373 
374 	if (x1 < x2 && y1 < y2)
375 	{
376 	    o = realloc (output, sizeof (CompOutput) * (nOutput + 1));
377 	    if (o)
378 	    {
379 		o[nOutput].region.extents.x1 = x1;
380 		o[nOutput].region.extents.y1 = y1;
381 		o[nOutput].region.extents.x2 = x2;
382 		o[nOutput].region.extents.y2 = y2;
383 
384 		output = o;
385 		nOutput++;
386 	    }
387 	}
388     }
389 
390     /* make sure we have at least one output */
391     if (!nOutput)
392     {
393 	output = malloc (sizeof (CompOutput));
394 	if (!output)
395 	    return;
396 
397 	output->region.extents.x1 = 0;
398 	output->region.extents.y1 = 0;
399 	output->region.extents.x2 = s->width;
400 	output->region.extents.y2 = s->height;
401 
402 	nOutput = 1;
403     }
404 
405     /* set name, width, height and update rect pointers in all regions */
406     for (i = 0; i < nOutput; i++)
407     {
408 	output[i].name = malloc (sizeof (char) * 10);
409 	if (output[i].name)
410 	    snprintf (output[i].name, 10, "Output %d", nOutput);
411 
412 	output[i].region.rects = &output[i].region.extents;
413 	output[i].region.numRects = 1;
414 
415 	output[i].width  = output[i].region.extents.x2 -
416 	    output[i].region.extents.x1;
417 	output[i].height = output[i].region.extents.y2 -
418 	    output[i].region.extents.y1;
419 
420 	output[i].workArea.x      = output[i].region.extents.x1;
421 	output[i].workArea.y      = output[i].region.extents.x1;
422 	output[i].workArea.width  = output[i].width;
423 	output[i].workArea.height = output[i].height;
424 
425 	output[i].id = i;
426     }
427 
428     if (s->outputDev)
429     {
430 	for (i = 0; i < s->nOutputDev; i++)
431 	    if (s->outputDev[i].name)
432 		free (s->outputDev[i].name);
433 
434 	free (s->outputDev);
435     }
436 
437     s->outputDev             = output;
438     s->nOutputDev            = nOutput;
439     s->hasOverlappingOutputs = FALSE;
440 
441     setCurrentOutput (s, s->currentOutputDev);
442 
443     /* clear out fullscreen monitor hints of all windows as
444        suggested on monitor layout changes in EWMH */
445     for (w = s->windows; w; w = w->next)
446 	if (w->fullscreenMonitorsSet)
447 	    setWindowFullscreenMonitors (w, NULL);
448 
449     updateWorkareaForScreen (s);
450 
451     setDefaultViewport (s);
452     damageScreen (s);
453 
454     region = XCreateRegion ();
455     if (region)
456     {
457 	REGION r;
458 
459 	r.rects = &r.extents;
460 	r.numRects = 1;
461 
462 	for (i = 0; i < nOutput - 1; i++)
463 	    for (j = i + 1; j < nOutput; j++)
464             {
465 		XIntersectRegion (&output[i].region,
466 				  &output[j].region,
467 				  region);
468 		if (REGION_NOT_EMPTY (region))
469 		    s->hasOverlappingOutputs = TRUE;
470 	    }
471 	XSubtractRegion (&emptyRegion, &emptyRegion, region);
472 
473 	if (s->display->nScreenInfo)
474 	{
475 	    for (i = 0; i < s->display->nScreenInfo; i++)
476 	    {
477 		r.extents.x1 = s->display->screenInfo[i].x_org;
478 		r.extents.y1 = s->display->screenInfo[i].y_org;
479 		r.extents.x2 = r.extents.x1 + s->display->screenInfo[i].width;
480 		r.extents.y2 = r.extents.y1 + s->display->screenInfo[i].height;
481 
482 		XUnionRegion (region, &r, region);
483 	    }
484 	}
485 	else
486 	{
487 	    r.extents.x1 = 0;
488 	    r.extents.y1 = 0;
489 	    r.extents.x2 = s->width;
490 	    r.extents.y2 = s->height;
491 
492 	    XUnionRegion (region, &r, region);
493 	}
494 
495 	/* remove all output regions from visible screen region */
496 	for (i = 0; i < s->nOutputDev; i++)
497 	    XSubtractRegion (region, &s->outputDev[i].region, region);
498 
499 	/* we should clear color buffers before swapping if we have visible
500 	   regions without output */
501 	s->clearBuffers = REGION_NOT_EMPTY (region);
502 
503 	XDestroyRegion (region);
504     }
505 
506     (*s->outputChangeNotify) (s);
507 }
508 
509 static void
detectOutputDevices(CompScreen * s)510 detectOutputDevices (CompScreen *s)
511 {
512     if (!noDetection && s->opt[COMP_SCREEN_OPTION_DETECT_OUTPUTS].value.b)
513     {
514 	char		*name;
515 	CompOptionValue	value;
516 	char		output[1024];
517 	int		i, size = sizeof (output);
518 
519 	if (s->display->nScreenInfo)
520 	{
521 	    int n = s->display->nScreenInfo;
522 
523 	    value.list.nValue = n;
524 	    value.list.value  = malloc (sizeof (CompOptionValue) * n);
525 	    if (!value.list.value)
526 		return;
527 
528 	    for (i = 0; i < n; i++)
529 	    {
530 		snprintf (output, size, "%dx%d+%d+%d",
531 			  s->display->screenInfo[i].width,
532 			  s->display->screenInfo[i].height,
533 			  s->display->screenInfo[i].x_org,
534 			  s->display->screenInfo[i].y_org);
535 
536 		value.list.value[i].s = strdup (output);
537 	    }
538 	}
539 	else
540 	{
541 	    value.list.nValue = 1;
542 	    value.list.value  = malloc (sizeof (CompOptionValue));
543 	    if (!value.list.value)
544 		return;
545 
546 	    snprintf (output, size, "%dx%d+%d+%d", s->width, s->height, 0, 0);
547 
548 	    value.list.value->s = strdup (output);
549 	}
550 
551 	name = s->opt[COMP_SCREEN_OPTION_OUTPUTS].name;
552 
553 	s->opt[COMP_SCREEN_OPTION_DETECT_OUTPUTS].value.b = FALSE;
554 	(*core.setOptionForPlugin) (&s->base, "core", name, &value);
555 	s->opt[COMP_SCREEN_OPTION_DETECT_OUTPUTS].value.b = TRUE;
556 
557 	for (i = 0; i < value.list.nValue; i++)
558 	    if (value.list.value[i].s)
559 		free (value.list.value[i].s);
560 
561 	free (value.list.value);
562     }
563     else
564     {
565 	updateOutputDevices (s);
566     }
567 }
568 
569 CompOption *
getScreenOptions(CompPlugin * plugin,CompScreen * screen,int * count)570 getScreenOptions (CompPlugin *plugin,
571 		  CompScreen *screen,
572 		  int	     *count)
573 {
574     *count = NUM_OPTIONS (screen);
575     return screen->opt;
576 }
577 
578 Bool
setScreenOption(CompPlugin * plugin,CompScreen * screen,const char * name,CompOptionValue * value)579 setScreenOption (CompPlugin	 *plugin,
580 		 CompScreen      *screen,
581 		 const char	 *name,
582 		 CompOptionValue *value)
583 {
584     CompOption *o;
585     int	       index;
586 
587     o = compFindOption (screen->opt, NUM_OPTIONS (screen), name, &index);
588     if (!o)
589 	return FALSE;
590 
591     switch (index) {
592     case COMP_SCREEN_OPTION_DETECT_REFRESH_RATE:
593 	if (compSetBoolOption (o, value))
594 	{
595 	    if (value->b)
596 		detectRefreshRateOfScreen (screen);
597 
598 	    return TRUE;
599 	}
600 	break;
601     case COMP_SCREEN_OPTION_DETECT_OUTPUTS:
602 	if (compSetBoolOption (o, value))
603 	{
604 	    if (value->b)
605 		detectOutputDevices (screen);
606 
607 	    return TRUE;
608 	}
609 	break;
610     case COMP_SCREEN_OPTION_REFRESH_RATE:
611 	if (screen->opt[COMP_SCREEN_OPTION_DETECT_REFRESH_RATE].value.b)
612 	    return FALSE;
613 
614 	if (compSetIntOption (o, value))
615 	{
616 	    screen->redrawTime = 1000 / o->value.i;
617 	    screen->optimalRedrawTime = screen->redrawTime;
618 	    return TRUE;
619 	}
620 	break;
621     case COMP_SCREEN_OPTION_HSIZE:
622 	if (compSetIntOption (o, value))
623 	{
624 	    CompOption *vsize;
625 
626 	    vsize = compFindOption (screen->opt, NUM_OPTIONS (screen),
627 				    "vsize", NULL);
628 
629 	    if (!vsize)
630 		return FALSE;
631 
632 	    if (o->value.i * screen->width > MAXSHORT)
633 		return FALSE;
634 
635 	    setVirtualScreenSize (screen, o->value.i, vsize->value.i);
636 	    return TRUE;
637 	}
638 	break;
639     case COMP_SCREEN_OPTION_VSIZE:
640 	if (compSetIntOption (o, value))
641 	{
642 	    CompOption *hsize;
643 
644 	    hsize = compFindOption (screen->opt, NUM_OPTIONS (screen),
645 				    "hsize", NULL);
646 
647 	    if (!hsize)
648 		return FALSE;
649 
650 	    if (o->value.i * screen->height > MAXSHORT)
651 		return FALSE;
652 
653 	    setVirtualScreenSize (screen, hsize->value.i, o->value.i);
654 	    return TRUE;
655 	}
656 	break;
657     case COMP_SCREEN_OPTION_NUMBER_OF_DESKTOPS:
658 	if (compSetIntOption (o, value))
659 	{
660 	    setNumberOfDesktops (screen, o->value.i);
661 	    return TRUE;
662 	}
663 	break;
664     case COMP_SCREEN_OPTION_DEFAULT_ICON:
665 	if (compSetStringOption (o, value))
666 	    return updateDefaultIcon (screen);
667 	break;
668     case COMP_SCREEN_OPTION_OUTPUTS:
669 	if (!noDetection &&
670 	    screen->opt[COMP_SCREEN_OPTION_DETECT_OUTPUTS].value.b)
671 	    return FALSE;
672 
673 	if (compSetOptionList (o, value))
674 	{
675 	    updateOutputDevices (screen);
676 	    return TRUE;
677 	}
678 	break;
679      case COMP_SCREEN_OPTION_FORCE_INDEPENDENT:
680 	if (compSetBoolOption (o, value))
681 	{
682 	    updateOutputDevices (screen);
683 	    return TRUE;
684 	}
685 	break;
686     default:
687 	if (compSetScreenOption (screen, o, value))
688 	    return TRUE;
689 	break;
690     }
691 
692     return FALSE;
693 }
694 
695 const CompMetadataOptionInfo coreScreenOptionInfo[COMP_SCREEN_OPTION_NUM] = {
696     { "detect_refresh_rate", "bool", 0, 0, 0 },
697     { "lighting", "bool", 0, 0, 0 },
698     { "refresh_rate", "int", "<min>1</min>", 0, 0 },
699     { "hsize", "int", "<min>1</min><max>32</max>", 0, 0 },
700     { "vsize", "int", "<min>1</min><max>32</max>", 0, 0 },
701     { "unredirect_fullscreen_windows", "bool", 0, 0, 0 },
702     { "default_icon", "string", 0, 0, 0 },
703     { "sync_to_vblank", "bool", 0, 0, 0 },
704     { "number_of_desktops", "int", "<min>1</min>", 0, 0 },
705     { "detect_outputs", "bool", 0, 0, 0 },
706     { "outputs", "list", "<type>string</type>", 0, 0 },
707     { "overlapping_outputs", "int",
708       RESTOSTRING (0, OUTPUT_OVERLAP_MODE_LAST), 0, 0 },
709     { "focus_prevention_level", "int",
710       RESTOSTRING (0, FOCUS_PREVENTION_LEVEL_LAST), 0, 0 },
711     { "focus_prevention_match", "match", 0, 0, 0 },
712     { "texture_compression", "bool", 0, 0, 0 },
713     { "force_independent_output_painting", "bool", 0, 0, 0 }
714 };
715 
716 static void
updateStartupFeedback(CompScreen * s)717 updateStartupFeedback (CompScreen *s)
718 {
719     if (s->startupSequences)
720 	XDefineCursor (s->display->display, s->root, s->busyCursor);
721     else
722 	XDefineCursor (s->display->display, s->root, s->normalCursor);
723 }
724 
725 #define STARTUP_TIMEOUT_DELAY 15000
726 
727 static Bool
startupSequenceTimeout(void * data)728 startupSequenceTimeout (void *data)
729 {
730     CompScreen		*screen = data;
731     CompStartupSequence *s;
732     struct timeval	now, active;
733     double		elapsed;
734 
735     gettimeofday (&now, NULL);
736 
737     for (s = screen->startupSequences; s; s = s->next)
738     {
739 	sn_startup_sequence_get_last_active_time (s->sequence,
740 						  &active.tv_sec,
741 						  &active.tv_usec);
742 
743 	elapsed = ((((double) now.tv_sec - active.tv_sec) * 1000000.0 +
744 		    (now.tv_usec - active.tv_usec))) / 1000.0;
745 
746 	if (elapsed > STARTUP_TIMEOUT_DELAY)
747 	    sn_startup_sequence_complete (s->sequence);
748     }
749 
750     return TRUE;
751 }
752 
753 static void
addSequence(CompScreen * screen,SnStartupSequence * sequence)754 addSequence (CompScreen        *screen,
755 	     SnStartupSequence *sequence)
756 {
757     CompStartupSequence *s;
758 
759     s = malloc (sizeof (CompStartupSequence));
760     if (!s)
761 	return;
762 
763     sn_startup_sequence_ref (sequence);
764 
765     s->next     = screen->startupSequences;
766     s->sequence = sequence;
767     s->viewportX = screen->x;
768     s->viewportY = screen->y;
769 
770     screen->startupSequences = s;
771 
772     if (!screen->startupSequenceTimeoutHandle)
773 	screen->startupSequenceTimeoutHandle =
774 	    compAddTimeout (1000, 1500,
775 			    startupSequenceTimeout,
776 			    screen);
777 
778     updateStartupFeedback (screen);
779 }
780 
781 static void
removeSequence(CompScreen * screen,SnStartupSequence * sequence)782 removeSequence (CompScreen        *screen,
783 		SnStartupSequence *sequence)
784 {
785     CompStartupSequence *s, *p = NULL;
786 
787     for (s = screen->startupSequences; s; s = s->next)
788     {
789 	if (s->sequence == sequence)
790 	    break;
791 
792 	p = s;
793     }
794 
795     if (!s)
796 	return;
797 
798     sn_startup_sequence_unref (sequence);
799 
800     if (p)
801 	p->next = s->next;
802     else
803 	screen->startupSequences = NULL;
804 
805     free (s);
806 
807     if (!screen->startupSequences && screen->startupSequenceTimeoutHandle)
808     {
809 	compRemoveTimeout (screen->startupSequenceTimeoutHandle);
810 	screen->startupSequenceTimeoutHandle = 0;
811     }
812 
813     updateStartupFeedback (screen);
814 }
815 
816 static void
removeAllSequences(CompScreen * screen)817 removeAllSequences (CompScreen *screen)
818 {
819     CompStartupSequence *s;
820     CompStartupSequence *sNext;
821 
822     for (s = screen->startupSequences; s; s = sNext)
823     {
824 	sNext = s->next;
825 	sn_startup_sequence_unref (s->sequence);
826 	free (s);
827     }
828     screen->startupSequences = NULL;
829 
830     if (screen->startupSequenceTimeoutHandle)
831     {
832 	compRemoveTimeout (screen->startupSequenceTimeoutHandle);
833 	screen->startupSequenceTimeoutHandle = 0;
834     }
835     updateStartupFeedback (screen);
836 }
837 
838 static void
compScreenSnEvent(SnMonitorEvent * event,void * userData)839 compScreenSnEvent (SnMonitorEvent *event,
840 		   void           *userData)
841 {
842     CompScreen	      *screen = userData;
843     SnStartupSequence *sequence;
844 
845     sequence = sn_monitor_event_get_startup_sequence (event);
846 
847     switch (sn_monitor_event_get_type (event)) {
848     case SN_MONITOR_EVENT_INITIATED:
849 	addSequence (screen, sequence);
850 	break;
851     case SN_MONITOR_EVENT_COMPLETED:
852 	removeSequence (screen, sn_monitor_event_get_startup_sequence (event));
853 	break;
854     case SN_MONITOR_EVENT_CHANGED:
855     case SN_MONITOR_EVENT_CANCELED:
856 	break;
857     }
858 }
859 
860 static void
updateScreenEdges(CompScreen * s)861 updateScreenEdges (CompScreen *s)
862 {
863     struct screenEdgeGeometry {
864 	int xw, x0;
865 	int yh, y0;
866 	int ww, w0;
867 	int hh, h0;
868     } geometry[SCREEN_EDGE_NUM] = {
869 	{ 0,  0,   0,  2,   0,  2,   1, -4 }, /* left */
870 	{ 1, -2,   0,  2,   0,  2,   1, -4 }, /* right */
871 	{ 0,  2,   0,  0,   1, -4,   0,  2 }, /* top */
872 	{ 0,  2,   1, -2,   1, -4,   0,  2 }, /* bottom */
873 	{ 0,  0,   0,  0,   0,  2,   0,  2 }, /* top-left */
874 	{ 1, -2,   0,  0,   0,  2,   0,  2 }, /* top-right */
875 	{ 0,  0,   1, -2,   0,  2,   0,  2 }, /* bottom-left */
876 	{ 1, -2,   1, -2,   0,  2,   0,  2 }  /* bottom-right */
877     };
878     int i;
879 
880     for (i = 0; i < SCREEN_EDGE_NUM; i++)
881     {
882 	if (s->screenEdge[i].id)
883 	    XMoveResizeWindow (s->display->display, s->screenEdge[i].id,
884 			       geometry[i].xw * s->width  + geometry[i].x0,
885 			       geometry[i].yh * s->height + geometry[i].y0,
886 			       geometry[i].ww * s->width  + geometry[i].w0,
887 			       geometry[i].hh * s->height + geometry[i].h0);
888     }
889 }
890 
891 static void
frustum(GLfloat * m,GLfloat left,GLfloat right,GLfloat bottom,GLfloat top,GLfloat nearval,GLfloat farval)892 frustum (GLfloat *m,
893 	 GLfloat left,
894 	 GLfloat right,
895 	 GLfloat bottom,
896 	 GLfloat top,
897 	 GLfloat nearval,
898 	 GLfloat farval)
899 {
900     GLfloat x, y, a, b, c, d;
901 
902     x = (2.0 * nearval) / (right - left);
903     y = (2.0 * nearval) / (top - bottom);
904     a = (right + left) / (right - left);
905     b = (top + bottom) / (top - bottom);
906     c = -(farval + nearval) / ( farval - nearval);
907     d = -(2.0 * farval * nearval) / (farval - nearval);
908 
909 #define M(row,col)  m[col*4+row]
910     M(0,0) = x;     M(0,1) = 0.0f;  M(0,2) = a;      M(0,3) = 0.0f;
911     M(1,0) = 0.0f;  M(1,1) = y;     M(1,2) = b;      M(1,3) = 0.0f;
912     M(2,0) = 0.0f;  M(2,1) = 0.0f;  M(2,2) = c;      M(2,3) = d;
913     M(3,0) = 0.0f;  M(3,1) = 0.0f;  M(3,2) = -1.0f;  M(3,3) = 0.0f;
914 #undef M
915 
916 }
917 
918 static void
perspective(GLfloat * m,GLfloat fovy,GLfloat aspect,GLfloat zNear,GLfloat zFar)919 perspective (GLfloat *m,
920 	     GLfloat fovy,
921 	     GLfloat aspect,
922 	     GLfloat zNear,
923 	     GLfloat zFar)
924 {
925     GLfloat xmin, xmax, ymin, ymax;
926 
927     ymax = zNear * tan (fovy * M_PI / 360.0);
928     ymin = -ymax;
929     xmin = ymin * aspect;
930     xmax = ymax * aspect;
931 
932     frustum (m, xmin, xmax, ymin, ymax, zNear, zFar);
933 }
934 
935 void
setCurrentOutput(CompScreen * s,int outputNum)936 setCurrentOutput (CompScreen *s,
937 		  int	     outputNum)
938 {
939     if (outputNum >= s->nOutputDev)
940 	outputNum = 0;
941 
942     s->currentOutputDev = outputNum;
943 }
944 
945 static void
reshape(CompScreen * s,int w,int h)946 reshape (CompScreen *s,
947 	 int	    w,
948 	 int	    h)
949 {
950 
951 #ifdef USE_COW
952     if (useCow)
953 	XMoveResizeWindow (s->display->display, s->overlay, 0, 0, w, h);
954 #endif
955 
956     if (s->display->xineramaExtension)
957     {
958 	CompDisplay *d = s->display;
959 
960 	if (d->screenInfo)
961 	    XFree (d->screenInfo);
962 
963 	d->nScreenInfo = 0;
964 	d->screenInfo = XineramaQueryScreens (d->display, &d->nScreenInfo);
965     }
966 
967     glMatrixMode (GL_PROJECTION);
968     glLoadIdentity ();
969     glMatrixMode (GL_MODELVIEW);
970     glLoadIdentity ();
971     glDepthRange (0, 1);
972     glViewport (-1, -1, 2, 2);
973     glRasterPos2f (0, 0);
974 
975     s->rasterX = s->rasterY = 0;
976 
977     perspective (s->projection, 60.0f, 1.0f, 0.1f, 100.0f);
978 
979     glMatrixMode (GL_PROJECTION);
980     glLoadIdentity ();
981     glMultMatrixf (s->projection);
982     glMatrixMode (GL_MODELVIEW);
983 
984     s->region.rects = &s->region.extents;
985     s->region.numRects = 1;
986     s->region.extents.x1 = 0;
987     s->region.extents.y1 = 0;
988     s->region.extents.x2 = w;
989     s->region.extents.y2 = h;
990     s->region.size = 1;
991 
992     s->width  = w;
993     s->height = h;
994 
995     s->fullscreenOutput.name             = "fullscreen";
996     s->fullscreenOutput.id               = ~0;
997     s->fullscreenOutput.width            = w;
998     s->fullscreenOutput.height           = h;
999     s->fullscreenOutput.region           = s->region;
1000     s->fullscreenOutput.workArea.x       = 0;
1001     s->fullscreenOutput.workArea.y       = 0;
1002     s->fullscreenOutput.workArea.width   = w;
1003     s->fullscreenOutput.workArea.height  = h;
1004 
1005     updateScreenEdges (s);
1006 }
1007 
1008 void
configureScreen(CompScreen * s,XConfigureEvent * ce)1009 configureScreen (CompScreen	 *s,
1010 		 XConfigureEvent *ce)
1011 {
1012     if (s->attrib.width  != ce->width ||
1013 	s->attrib.height != ce->height)
1014     {
1015 	s->attrib.width  = ce->width;
1016 	s->attrib.height = ce->height;
1017 
1018 	reshape (s, ce->width, ce->height);
1019 
1020 	detectOutputDevices (s);
1021 
1022 	damageScreen (s);
1023     }
1024 }
1025 
1026 static FuncPtr
getProcAddress(CompScreen * s,const char * name)1027 getProcAddress (CompScreen *s,
1028 		const char *name)
1029 {
1030     static void *dlhand = NULL;
1031     FuncPtr     funcPtr = NULL;
1032 
1033     if (s->getProcAddress)
1034 	funcPtr = s->getProcAddress ((GLubyte *) name);
1035 
1036     if (!funcPtr)
1037     {
1038 	if (!dlhand)
1039 	    dlhand = dlopen (NULL, RTLD_LAZY);
1040 
1041 	if (dlhand)
1042 	{
1043 	    dlerror ();
1044 	    funcPtr = (FuncPtr) dlsym (dlhand, name);
1045 	    if (dlerror () != NULL)
1046 		funcPtr = NULL;
1047 	}
1048     }
1049 
1050     return funcPtr;
1051 }
1052 
1053 void
updateScreenBackground(CompScreen * screen,CompTexture * texture)1054 updateScreenBackground (CompScreen  *screen,
1055 			CompTexture *texture)
1056 {
1057     Display	  *dpy = screen->display->display;
1058     Atom	  pixmapAtom, actualType;
1059     int		  actualFormat, i, status;
1060     unsigned int  width = 1, height = 1, depth = 0;
1061     unsigned long nItems;
1062     unsigned long bytesAfter;
1063     unsigned char *prop;
1064     Pixmap	  pixmap = 0;
1065 
1066     pixmapAtom = XInternAtom (dpy, "PIXMAP", FALSE);
1067 
1068     for (i = 0; pixmap == 0 && i < 2; i++)
1069     {
1070 	status = XGetWindowProperty (dpy, screen->root,
1071 				     screen->display->xBackgroundAtom[i],
1072 				     0, 4, FALSE, AnyPropertyType,
1073 				     &actualType, &actualFormat, &nItems,
1074 				     &bytesAfter, &prop);
1075 
1076 	if (status == Success && prop)
1077 	{
1078 	    if (actualType   == pixmapAtom &&
1079 		actualFormat == 32         &&
1080 		nItems	     == 1)
1081 	    {
1082 		Pixmap p;
1083 
1084 		memcpy (&p, prop, 4);
1085 
1086 		if (p)
1087 		{
1088 		    unsigned int ui;
1089 		    int		 i;
1090 		    Window	 w;
1091 
1092 		    if (XGetGeometry (dpy, p, &w, &i, &i,
1093 				      &width, &height, &ui, &depth))
1094 		    {
1095 			if (depth == screen->attrib.depth)
1096 			    pixmap = p;
1097 		    }
1098 		}
1099 	    }
1100 
1101 	    XFree (prop);
1102 	}
1103     }
1104 
1105     if (pixmap)
1106     {
1107 	if (pixmap == texture->pixmap)
1108 	    return;
1109 
1110 	finiTexture (screen, texture);
1111 	initTexture (screen, texture);
1112 
1113 	if (!bindPixmapToTexture (screen, texture, pixmap,
1114 				  width, height, depth))
1115 	{
1116 	    compLogMessage ("core", CompLogLevelWarn,
1117 			    "Couldn't bind background pixmap 0x%x to "
1118 			    "texture", (int) pixmap);
1119 	}
1120     }
1121     else
1122     {
1123 	finiTexture (screen, texture);
1124 	initTexture (screen, texture);
1125     }
1126 
1127     if (!texture->name && backgroundImage)
1128 	readImageToTexture (screen, texture, backgroundImage, &width, &height);
1129 
1130     if (texture->target == GL_TEXTURE_2D)
1131     {
1132 	glBindTexture (texture->target, texture->name);
1133 	glTexParameteri (texture->target, GL_TEXTURE_WRAP_S, GL_REPEAT);
1134 	glTexParameteri (texture->target, GL_TEXTURE_WRAP_T, GL_REPEAT);
1135 	glBindTexture (texture->target, 0);
1136     }
1137 }
1138 
1139 void
detectRefreshRateOfScreen(CompScreen * s)1140 detectRefreshRateOfScreen (CompScreen *s)
1141 {
1142     if (!noDetection && s->opt[COMP_SCREEN_OPTION_DETECT_REFRESH_RATE].value.b)
1143     {
1144 	char		*name;
1145 	CompOptionValue	value;
1146 
1147 	value.i = 0;
1148 
1149 	if (s->display->randrExtension)
1150 	{
1151 	    XRRScreenConfiguration *config;
1152 
1153 	    config  = XRRGetScreenInfo (s->display->display, s->root);
1154 	    value.i = (int) XRRConfigCurrentRate (config);
1155 
1156 	    XRRFreeScreenConfigInfo (config);
1157 	}
1158 
1159 	if (value.i == 0)
1160 	    value.i = defaultRefreshRate;
1161 
1162 	name = s->opt[COMP_SCREEN_OPTION_REFRESH_RATE].name;
1163 
1164 	s->opt[COMP_SCREEN_OPTION_DETECT_REFRESH_RATE].value.b = FALSE;
1165 	(*core.setOptionForPlugin) (&s->base, "core", name, &value);
1166 	s->opt[COMP_SCREEN_OPTION_DETECT_REFRESH_RATE].value.b = TRUE;
1167     }
1168     else
1169     {
1170 	s->redrawTime = 1000 / s->opt[COMP_SCREEN_OPTION_REFRESH_RATE].value.i;
1171 	s->optimalRedrawTime = s->redrawTime;
1172     }
1173 }
1174 
1175 static void
setSupportingWmCheck(CompScreen * s)1176 setSupportingWmCheck (CompScreen *s)
1177 {
1178     CompDisplay *d = s->display;
1179 
1180     XChangeProperty (d->display, s->grabWindow, d->supportingWmCheckAtom,
1181 		     XA_WINDOW, 32, PropModeReplace,
1182 		     (unsigned char *) &s->grabWindow, 1);
1183 
1184     XChangeProperty (d->display, s->grabWindow, d->wmNameAtom,
1185 		     d->utf8StringAtom, 8, PropModeReplace,
1186 		     (unsigned char *) PACKAGE, strlen (PACKAGE));
1187     XChangeProperty (d->display, s->grabWindow, d->winStateAtom,
1188 		     XA_ATOM, 32, PropModeReplace,
1189 		     (unsigned char *) &d->winStateSkipTaskbarAtom, 1);
1190     XChangeProperty (d->display, s->grabWindow, d->winStateAtom,
1191 		     XA_ATOM, 32, PropModeAppend,
1192 		     (unsigned char *) &d->winStateSkipPagerAtom, 1);
1193     XChangeProperty (d->display, s->grabWindow, d->winStateAtom,
1194 		     XA_ATOM, 32, PropModeAppend,
1195 		     (unsigned char *) &d->winStateHiddenAtom, 1);
1196 
1197     XChangeProperty (d->display, s->root, d->supportingWmCheckAtom,
1198 		     XA_WINDOW, 32, PropModeReplace,
1199 		     (unsigned char *) &s->grabWindow, 1);
1200 }
1201 
1202 static unsigned int
addSupportedAtoms(CompScreen * s,Atom * atoms,unsigned int size)1203 addSupportedAtoms (CompScreen   *s,
1204 		   Atom         *atoms,
1205 		   unsigned int size)
1206 {
1207     CompDisplay  *d = s->display;
1208     unsigned int count = 0;
1209 
1210     atoms[count++] = d->utf8StringAtom;
1211 
1212     atoms[count++] = d->clientListAtom;
1213     atoms[count++] = d->clientListStackingAtom;
1214 
1215     atoms[count++] = d->winActiveAtom;
1216 
1217     atoms[count++] = d->desktopViewportAtom;
1218     atoms[count++] = d->desktopGeometryAtom;
1219     atoms[count++] = d->currentDesktopAtom;
1220     atoms[count++] = d->numberOfDesktopsAtom;
1221     atoms[count++] = d->showingDesktopAtom;
1222 
1223     atoms[count++] = d->workareaAtom;
1224 
1225     atoms[count++] = d->wmNameAtom;
1226 
1227     atoms[count++] = d->wmStrutAtom;
1228     atoms[count++] = d->wmStrutPartialAtom;
1229 
1230     atoms[count++] = d->wmUserTimeAtom;
1231     atoms[count++] = d->frameExtentsAtom;
1232     atoms[count++] = d->frameWindowAtom;
1233 
1234     atoms[count++] = d->winStateAtom;
1235     atoms[count++] = d->winStateModalAtom;
1236     atoms[count++] = d->winStateStickyAtom;
1237     atoms[count++] = d->winStateMaximizedVertAtom;
1238     atoms[count++] = d->winStateMaximizedHorzAtom;
1239     atoms[count++] = d->winStateShadedAtom;
1240     atoms[count++] = d->winStateSkipTaskbarAtom;
1241     atoms[count++] = d->winStateSkipPagerAtom;
1242     atoms[count++] = d->winStateHiddenAtom;
1243     atoms[count++] = d->winStateFullscreenAtom;
1244     atoms[count++] = d->winStateAboveAtom;
1245     atoms[count++] = d->winStateBelowAtom;
1246     atoms[count++] = d->winStateDemandsAttentionAtom;
1247 
1248     atoms[count++] = d->winOpacityAtom;
1249     atoms[count++] = d->winBrightnessAtom;
1250 
1251     if (s->canDoSaturated)
1252     {
1253 	atoms[count++] = d->winSaturationAtom;
1254 	atoms[count++] = d->winStateDisplayModalAtom;
1255     }
1256 
1257     atoms[count++] = d->wmAllowedActionsAtom;
1258 
1259     atoms[count++] = d->winActionMoveAtom;
1260     atoms[count++] = d->winActionResizeAtom;
1261     atoms[count++] = d->winActionStickAtom;
1262     atoms[count++] = d->winActionMinimizeAtom;
1263     atoms[count++] = d->winActionMaximizeHorzAtom;
1264     atoms[count++] = d->winActionMaximizeVertAtom;
1265     atoms[count++] = d->winActionFullscreenAtom;
1266     atoms[count++] = d->winActionCloseAtom;
1267     atoms[count++] = d->winActionShadeAtom;
1268     atoms[count++] = d->winActionChangeDesktopAtom;
1269     atoms[count++] = d->winActionAboveAtom;
1270     atoms[count++] = d->winActionBelowAtom;
1271 
1272     atoms[count++] = d->winTypeAtom;
1273     atoms[count++] = d->winTypeDesktopAtom;
1274     atoms[count++] = d->winTypeDockAtom;
1275     atoms[count++] = d->winTypeToolbarAtom;
1276     atoms[count++] = d->winTypeMenuAtom;
1277     atoms[count++] = d->winTypeSplashAtom;
1278     atoms[count++] = d->winTypeDialogAtom;
1279     atoms[count++] = d->winTypeUtilAtom;
1280     atoms[count++] = d->winTypeNormalAtom;
1281 
1282     atoms[count++] = d->wmDeleteWindowAtom;
1283     atoms[count++] = d->wmPingAtom;
1284 
1285     atoms[count++] = d->wmMoveResizeAtom;
1286     atoms[count++] = d->moveResizeWindowAtom;
1287     atoms[count++] = d->restackWindowAtom;
1288 
1289     atoms[count++] = d->wmFullscreenMonitorsAtom;
1290 
1291     assert (count < size);
1292 
1293     return count;
1294 }
1295 
1296 void
setSupportedWmHints(CompScreen * s)1297 setSupportedWmHints (CompScreen *s)
1298 {
1299     CompDisplay  *d = s->display;
1300     Atom	 data[256];
1301     unsigned int count = 0;
1302 
1303     data[count++] = d->supportedAtom;
1304     data[count++] = d->supportingWmCheckAtom;
1305 
1306     count += (*s->addSupportedAtoms) (s, data + count, 256 - count);
1307 
1308     XChangeProperty (d->display, s->root, d->supportedAtom, XA_ATOM, 32,
1309 		     PropModeReplace, (unsigned char *) data, count);
1310 }
1311 
1312 static void
getDesktopHints(CompScreen * s)1313 getDesktopHints (CompScreen *s)
1314 {
1315     CompDisplay   *d = s->display;
1316     unsigned long data[2];
1317     Atom	  actual;
1318     int		  result, format;
1319     unsigned long n, left;
1320     unsigned char *propData;
1321 
1322     if (useDesktopHints)
1323     {
1324 	result = XGetWindowProperty (s->display->display, s->root,
1325 				     d->numberOfDesktopsAtom, 0L, 1L, FALSE,
1326 				     XA_CARDINAL, &actual, &format,
1327 				     &n, &left, &propData);
1328 
1329 	if (result == Success && propData)
1330 	{
1331 	    if (n)
1332 	    {
1333 		memcpy (data, propData, sizeof (unsigned long));
1334 
1335 		if (data[0] > 0 && data[0] < 0xffffffff)
1336 		    s->nDesktop = data[0];
1337 	    }
1338 	    XFree (propData);
1339 	}
1340 
1341 	result = XGetWindowProperty (s->display->display, s->root,
1342 				     d->currentDesktopAtom, 0L, 1L, FALSE,
1343 				     XA_CARDINAL, &actual, &format,
1344 				     &n, &left, &propData);
1345 
1346 	if (result == Success && propData)
1347 	{
1348 	    if (n)
1349 	    {
1350 		memcpy (data, propData, sizeof (unsigned long));
1351 
1352 		if (data[0] < s->nDesktop)
1353 		    s->currentDesktop = data[0];
1354 	    }
1355 
1356 	    XFree (propData);
1357 	}
1358     }
1359 
1360     result = XGetWindowProperty (s->display->display, s->root,
1361 				 d->desktopViewportAtom, 0L, 2L,
1362 				 FALSE, XA_CARDINAL, &actual, &format,
1363 				 &n, &left, &propData);
1364 
1365     if (result == Success && propData)
1366     {
1367 	if (n == 2)
1368 	{
1369 	    memcpy (data, propData, sizeof (unsigned long) * 2);
1370 
1371 	    if (data[0] / s->width < s->hsize - 1)
1372 		s->x = data[0] / s->width;
1373 
1374 	    if (data[1] / s->height < s->vsize - 1)
1375 		s->y = data[1] / s->height;
1376 	}
1377 
1378 	XFree (propData);
1379     }
1380 
1381     result = XGetWindowProperty (s->display->display, s->root,
1382 				 d->showingDesktopAtom, 0L, 1L, FALSE,
1383 				 XA_CARDINAL, &actual, &format,
1384 				 &n, &left, &propData);
1385 
1386     if (result == Success && propData)
1387     {
1388 	if (n)
1389 	{
1390 	    memcpy (data, propData, sizeof (unsigned long));
1391 
1392 	    if (data[0])
1393 		(*s->enterShowDesktopMode) (s);
1394 	}
1395 	XFree (propData);
1396     }
1397 
1398     data[0] = s->currentDesktop;
1399 
1400     XChangeProperty (d->display, s->root, d->currentDesktopAtom,
1401 		     XA_CARDINAL, 32, PropModeReplace,
1402 		     (unsigned char *) data, 1);
1403 
1404     data[0] = s->showingDesktopMask ? TRUE : FALSE;
1405 
1406     XChangeProperty (d->display, s->root, d->showingDesktopAtom,
1407 		     XA_CARDINAL, 32, PropModeReplace,
1408 		     (unsigned char *) data, 1);
1409 }
1410 
1411 void
showOutputWindow(CompScreen * s)1412 showOutputWindow (CompScreen *s)
1413 {
1414 
1415 #ifdef USE_COW
1416     if (useCow)
1417     {
1418 	Display       *dpy = s->display->display;
1419 	XserverRegion region;
1420 
1421 	region = XFixesCreateRegion (dpy, NULL, 0);
1422 
1423 	XFixesSetWindowShapeRegion (dpy,
1424 				    s->output,
1425 				    ShapeBounding,
1426 				    0, 0, 0);
1427 	XFixesSetWindowShapeRegion (dpy,
1428 				    s->output,
1429 				    ShapeInput,
1430 				    0, 0, region);
1431 
1432 	XFixesDestroyRegion (dpy, region);
1433 
1434 	damageScreen (s);
1435     }
1436 #endif
1437 
1438 }
1439 
1440 void
hideOutputWindow(CompScreen * s)1441 hideOutputWindow (CompScreen *s)
1442 {
1443 
1444 #ifdef USE_COW
1445     if (useCow)
1446     {
1447 	Display       *dpy = s->display->display;
1448 	XserverRegion region;
1449 
1450 	region = XFixesCreateRegion (dpy, NULL, 0);
1451 
1452 	XFixesSetWindowShapeRegion (dpy,
1453 				    s->output,
1454 				    ShapeBounding,
1455 				    0, 0, region);
1456 
1457 	XFixesDestroyRegion (dpy, region);
1458     }
1459 #endif
1460 
1461 }
1462 
1463 void
updateOutputWindow(CompScreen * s)1464 updateOutputWindow (CompScreen *s)
1465 {
1466 
1467 #ifdef USE_COW
1468     if (useCow)
1469     {
1470 	Display       *dpy = s->display->display;
1471 	XserverRegion region;
1472 	static Region tmpRegion = NULL;
1473 	CompWindow    *w;
1474 
1475 	if (!tmpRegion)
1476 	{
1477 	    tmpRegion = XCreateRegion ();
1478 	    if (!tmpRegion)
1479 		return;
1480 	}
1481 
1482 	XSubtractRegion (&s->region, &emptyRegion, tmpRegion);
1483 
1484 	for (w = s->reverseWindows; w; w = w->prev)
1485 	    if (w->overlayWindow)
1486 	    {
1487 		XSubtractRegion (tmpRegion, w->region, tmpRegion);
1488 	    }
1489 
1490 	XShapeCombineRegion (dpy, s->output, ShapeBounding,
1491 			     0, 0, tmpRegion, ShapeSet);
1492 
1493 
1494 	region = XFixesCreateRegion (dpy, NULL, 0);
1495 
1496 	XFixesSetWindowShapeRegion (dpy,
1497 				    s->output,
1498 				    ShapeInput,
1499 				    0, 0, region);
1500 
1501 	XFixesDestroyRegion (dpy, region);
1502     }
1503 #endif
1504 
1505 }
1506 
1507 static void
makeOutputWindow(CompScreen * s)1508 makeOutputWindow (CompScreen *s)
1509 {
1510 
1511 #ifdef USE_COW
1512     if (useCow)
1513     {
1514 	s->overlay = XCompositeGetOverlayWindow (s->display->display, s->root);
1515 	s->output  = s->overlay;
1516 
1517 	XSelectInput (s->display->display, s->output, ExposureMask);
1518     }
1519     else
1520 #endif
1521 
1522 	s->output = s->overlay = s->root;
1523 
1524     showOutputWindow (s);
1525 }
1526 
1527 static void
enterShowDesktopMode(CompScreen * s)1528 enterShowDesktopMode (CompScreen *s)
1529 {
1530     CompDisplay   *d = s->display;
1531     CompWindow    *w;
1532     unsigned long data = 1;
1533     int		  count = 0;
1534     CompOption    *st = &d->opt[COMP_DISPLAY_OPTION_HIDE_SKIP_TASKBAR_WINDOWS];
1535 
1536     s->showingDesktopMask = ~(CompWindowTypeDesktopMask |
1537 			      CompWindowTypeDockMask);
1538 
1539     for (w = s->windows; w; w = w->next)
1540     {
1541 	if ((s->showingDesktopMask & w->wmType) &&
1542 	    (!(w->state & CompWindowStateSkipTaskbarMask) || st->value.b))
1543 	{
1544 	    if (!w->inShowDesktopMode && !w->grabbed &&
1545 		w->managed && (*s->focusWindow) (w))
1546 	    {
1547 		w->inShowDesktopMode = TRUE;
1548 		hideWindow (w);
1549 	    }
1550 	}
1551 
1552 	if (w->inShowDesktopMode)
1553 	    count++;
1554     }
1555 
1556     if (!count)
1557     {
1558 	s->showingDesktopMask = 0;
1559 	data = 0;
1560     }
1561 
1562     XChangeProperty (s->display->display, s->root,
1563 		     s->display->showingDesktopAtom,
1564 		     XA_CARDINAL, 32, PropModeReplace,
1565 		     (unsigned char *) &data, 1);
1566 }
1567 
1568 static void
leaveShowDesktopMode(CompScreen * s,CompWindow * window)1569 leaveShowDesktopMode (CompScreen *s,
1570 		      CompWindow *window)
1571 {
1572     CompWindow    *w;
1573     unsigned long data = 0;
1574 
1575     if (window)
1576     {
1577 	if (!window->inShowDesktopMode)
1578 	    return;
1579 
1580 	window->inShowDesktopMode = FALSE;
1581 	showWindow (window);
1582 
1583 	/* return if some other window is still in show desktop mode */
1584 	for (w = s->windows; w; w = w->next)
1585 	    if (w->inShowDesktopMode)
1586 		return;
1587 
1588 	s->showingDesktopMask = 0;
1589     }
1590     else
1591     {
1592 	s->showingDesktopMask = 0;
1593 
1594 	for (w = s->windows; w; w = w->next)
1595 	{
1596 	    if (!w->inShowDesktopMode)
1597 		continue;
1598 
1599 	    w->inShowDesktopMode = FALSE;
1600 	    showWindow (w);
1601 	}
1602 
1603 	/* focus default window - most likely this will be the window
1604 	   which had focus before entering showdesktop mode */
1605 	focusDefaultWindow (s);
1606     }
1607 
1608     XChangeProperty (s->display->display, s->root,
1609 		     s->display->showingDesktopAtom,
1610 		     XA_CARDINAL, 32, PropModeReplace,
1611 		     (unsigned char *) &data, 1);
1612 }
1613 
1614 static CompWindow *
walkFirst(CompScreen * s)1615 walkFirst (CompScreen *s)
1616 {
1617     return s->windows;
1618 }
1619 
1620 static CompWindow *
walkLast(CompScreen * s)1621 walkLast (CompScreen *s)
1622 {
1623     return s->reverseWindows;
1624 }
1625 
1626 static CompWindow *
walkNext(CompWindow * w)1627 walkNext (CompWindow *w)
1628 {
1629     return w->next;
1630 }
1631 
1632 static CompWindow *
walkPrev(CompWindow * w)1633 walkPrev (CompWindow *w)
1634 {
1635     return w->prev;
1636 }
1637 
1638 static void
initWindowWalker(CompScreen * screen,CompWalker * walker)1639 initWindowWalker (CompScreen *screen,
1640 		  CompWalker *walker)
1641 {
1642     walker->fini  = NULL;
1643     walker->first = walkFirst;
1644     walker->last  = walkLast;
1645     walker->next  = walkNext;
1646     walker->prev  = walkPrev;
1647 }
1648 
1649 static void
freeScreen(CompScreen * s)1650 freeScreen (CompScreen *s)
1651 {
1652     int i, j;
1653 
1654     if (s->outputDev)
1655     {
1656 	for (i = 0; i < s->nOutputDev; i++)
1657 	    if (s->outputDev[i].name)
1658 		free (s->outputDev[i].name);
1659 
1660 	free (s->outputDev);
1661     }
1662 
1663     if (s->clientList)
1664 	free (s->clientList);
1665 
1666     if (s->desktopHintData)
1667 	free (s->desktopHintData);
1668 
1669     if (s->buttonGrab)
1670 	free (s->buttonGrab);
1671 
1672     if (s->keyGrab)
1673 	free (s->keyGrab);
1674 
1675     if (s->snContext)
1676 	sn_monitor_context_unref (s->snContext);
1677 
1678     if (s->damage)
1679 	XDestroyRegion (s->damage);
1680 
1681     if (s->grabs)
1682 	free (s->grabs);
1683 
1684     if (s->exposeRects)
1685 	free (s->exposeRects);
1686 
1687     /* XXX: Maybe we should free all fragment functions here? But
1688        the definition of CompFunction is private to fragment.c ... */
1689     for (i = 0; i < 2; i++)
1690 	for (j = 0; j < 64; j++)
1691 	    if (s->saturateFunction[i][j])
1692 		destroyFragmentFunction (s, s->saturateFunction[i][j]);
1693 
1694     compFiniScreenOptions (s, s->opt, COMP_SCREEN_OPTION_NUM);
1695 
1696     if (s->windowPrivateIndices)
1697 	free (s->windowPrivateIndices);
1698 
1699     if (s->base.privates)
1700 	free (s->base.privates);
1701 
1702     free (s);
1703 }
1704 
1705 Bool
addScreen(CompDisplay * display,int screenNum,Window wmSnSelectionWindow,Atom wmSnAtom,Time wmSnTimestamp)1706 addScreen (CompDisplay *display,
1707 	   int	       screenNum,
1708 	   Window      wmSnSelectionWindow,
1709 	   Atom	       wmSnAtom,
1710 	   Time	       wmSnTimestamp)
1711 {
1712     CompScreen		 *s;
1713     CompPrivate		 *privates;
1714     Display		 *dpy = display->display;
1715     static char		 data = 0;
1716     XColor		 black;
1717     Pixmap		 bitmap;
1718     XVisualInfo		 templ;
1719     XVisualInfo		 *visinfo;
1720     GLXFBConfig		 *fbConfigs;
1721     Window		 rootReturn, parentReturn;
1722     Window		 *children;
1723     unsigned int	 nchildren;
1724     int			 defaultDepth, nvisinfo, nElements, value, i;
1725     const char		 *glxExtensions, *glExtensions;
1726     XSetWindowAttributes attrib;
1727     GLfloat		 globalAmbient[]  = { 0.1f, 0.1f,  0.1f, 0.1f };
1728     GLfloat		 ambientLight[]   = { 0.0f, 0.0f,  0.0f, 0.0f };
1729     GLfloat		 diffuseLight[]   = { 0.9f, 0.9f,  0.9f, 0.9f };
1730     GLfloat		 light0Position[] = { -0.5f, 0.5f, -9.0f, 1.0f };
1731     CompWindow		 *w;
1732 
1733     s = malloc (sizeof (CompScreen));
1734     if (!s)
1735 	return FALSE;
1736 
1737     s->windowPrivateIndices = 0;
1738     s->windowPrivateLen     = 0;
1739 
1740     if (display->screenPrivateLen)
1741     {
1742 	privates = malloc (display->screenPrivateLen * sizeof (CompPrivate));
1743 	if (!privates)
1744 	{
1745 	    free (s);
1746 	    return FALSE;
1747 	}
1748     }
1749     else
1750 	privates = 0;
1751 
1752     compObjectInit (&s->base, privates, COMP_OBJECT_TYPE_SCREEN);
1753 
1754     s->display = display;
1755 
1756     if (!compInitScreenOptionsFromMetadata (s,
1757 					    &coreMetadata,
1758 					    coreScreenOptionInfo,
1759 					    s->opt,
1760 					    COMP_SCREEN_OPTION_NUM))
1761 	return FALSE;
1762 
1763     s->snContext = NULL;
1764 
1765     s->damage = XCreateRegion ();
1766     if (!s->damage)
1767 	return FALSE;
1768 
1769     s->x     = 0;
1770     s->y     = 0;
1771     s->hsize = s->opt[COMP_SCREEN_OPTION_HSIZE].value.i;
1772     s->vsize = s->opt[COMP_SCREEN_OPTION_VSIZE].value.i;
1773 
1774     s->windowOffsetX = 0;
1775     s->windowOffsetY = 0;
1776 
1777     s->nDesktop	      = 1;
1778     s->currentDesktop = 0;
1779 
1780     for (i = 0; i < SCREEN_EDGE_NUM; i++)
1781     {
1782 	s->screenEdge[i].id    = None;
1783 	s->screenEdge[i].count = 0;
1784     }
1785 
1786     s->buttonGrab  = 0;
1787     s->nButtonGrab = 0;
1788     s->keyGrab     = 0;
1789     s->nKeyGrab    = 0;
1790 
1791     s->grabs    = 0;
1792     s->grabSize = 0;
1793     s->maxGrab  = 0;
1794 
1795     s->pendingDestroys = 0;
1796 
1797     s->clientList  = 0;
1798     s->nClientList = 0;
1799 
1800     s->screenNum = screenNum;
1801     s->colormap  = DefaultColormap (dpy, screenNum);
1802     s->root	 = XRootWindow (dpy, screenNum);
1803 
1804     s->mapNum    = 1;
1805     s->activeNum = 1;
1806 
1807     s->groups = NULL;
1808 
1809     s->snContext = sn_monitor_context_new (display->snDisplay,
1810 					   screenNum,
1811 					   compScreenSnEvent, s,
1812 					   NULL);
1813 
1814     s->startupSequences		    = NULL;
1815     s->startupSequenceTimeoutHandle = 0;
1816 
1817     s->wmSnSelectionWindow = wmSnSelectionWindow;
1818     s->wmSnAtom		   = wmSnAtom;
1819     s->wmSnTimestamp	   = wmSnTimestamp;
1820 
1821     s->damageMask  = COMP_SCREEN_DAMAGE_ALL_MASK;
1822     s->next	   = 0;
1823     s->exposeRects = 0;
1824     s->sizeExpose  = 0;
1825     s->nExpose     = 0;
1826 
1827     s->rasterX = 0;
1828     s->rasterY = 0;
1829 
1830     s->outputDev	= NULL;
1831     s->nOutputDev	= 0;
1832     s->currentOutputDev = 0;
1833 
1834     s->windows = 0;
1835     s->reverseWindows = 0;
1836 
1837     s->nextRedraw  = 0;
1838     s->frameStatus = 0;
1839     s->timeMult    = 1;
1840     s->idle	   = TRUE;
1841     s->timeLeft    = 0;
1842 
1843     s->pendingCommands = TRUE;
1844 
1845     s->lastFunctionId = 0;
1846 
1847     s->fragmentFunctions = NULL;
1848     s->fragmentPrograms = NULL;
1849 
1850     memset (s->saturateFunction, 0, sizeof (s->saturateFunction));
1851 
1852     s->showingDesktopMask = 0;
1853 
1854     memset (s->history, 0, sizeof (s->history));
1855     s->currentHistory = 0;
1856 
1857     s->overlayWindowCount = 0;
1858 
1859     s->desktopHintData = NULL;
1860     s->desktopHintSize = 0;
1861 
1862     s->cursors = NULL;
1863 
1864     s->clearBuffers = TRUE;
1865 
1866     gettimeofday (&s->lastRedraw, 0);
1867 
1868     s->preparePaintScreen	   = preparePaintScreen;
1869     s->donePaintScreen		   = donePaintScreen;
1870     s->paintScreen		   = paintScreen;
1871     s->paintOutput		   = paintOutput;
1872     s->paintTransformedOutput	   = paintTransformedOutput;
1873     s->enableOutputClipping	   = enableOutputClipping;
1874     s->disableOutputClipping	   = disableOutputClipping;
1875     s->applyScreenTransform	   = applyScreenTransform;
1876     s->paintWindow		   = paintWindow;
1877     s->drawWindow		   = drawWindow;
1878     s->addWindowGeometry	   = addWindowGeometry;
1879     s->drawWindowTexture	   = drawWindowTexture;
1880     s->damageWindowRect		   = damageWindowRect;
1881     s->getOutputExtentsForWindow   = getOutputExtentsForWindow;
1882     s->getAllowedActionsForWindow  = getAllowedActionsForWindow;
1883     s->focusWindow		   = focusWindow;
1884     s->activateWindow              = activateWindow;
1885     s->placeWindow                 = placeWindow;
1886     s->validateWindowResizeRequest = validateWindowResizeRequest;
1887 
1888     s->paintCursor      = paintCursor;
1889     s->damageCursorRect	= damageCursorRect;
1890 
1891     s->windowResizeNotify = windowResizeNotify;
1892     s->windowMoveNotify	  = windowMoveNotify;
1893     s->windowGrabNotify   = windowGrabNotify;
1894     s->windowUngrabNotify = windowUngrabNotify;
1895 
1896     s->enterShowDesktopMode = enterShowDesktopMode;
1897     s->leaveShowDesktopMode = leaveShowDesktopMode;
1898 
1899     s->windowStateChangeNotify = windowStateChangeNotify;
1900 
1901     s->outputChangeNotify = outputChangeNotify;
1902     s->addSupportedAtoms  = addSupportedAtoms;
1903 
1904     s->initWindowWalker = initWindowWalker;
1905 
1906     s->getProcAddress = 0;
1907 
1908     if (!XGetWindowAttributes (dpy, s->root, &s->attrib))
1909 	return FALSE;
1910 
1911     s->workArea.x      = 0;
1912     s->workArea.y      = 0;
1913     s->workArea.width  = s->attrib.width;
1914     s->workArea.height = s->attrib.height;
1915 
1916     s->grabWindow = None;
1917 
1918     makeOutputWindow (s);
1919 
1920     templ.visualid = XVisualIDFromVisual (s->attrib.visual);
1921 
1922     visinfo = XGetVisualInfo (dpy, VisualIDMask, &templ, &nvisinfo);
1923     if (!nvisinfo)
1924     {
1925 	compLogMessage ("core", CompLogLevelFatal,
1926 			"Couldn't get visual info for default visual");
1927 	return FALSE;
1928     }
1929 
1930     defaultDepth = visinfo->depth;
1931 
1932     black.red = black.green = black.blue = 0;
1933 
1934     if (!XAllocColor (dpy, s->colormap, &black))
1935     {
1936 	compLogMessage ("core", CompLogLevelFatal, "Couldn't allocate color");
1937 	XFree (visinfo);
1938 	return FALSE;
1939     }
1940 
1941     bitmap = XCreateBitmapFromData (dpy, s->root, &data, 1, 1);
1942     if (!bitmap)
1943     {
1944 	compLogMessage ("core", CompLogLevelFatal, "Couldn't create bitmap");
1945 	XFree (visinfo);
1946 	return FALSE;
1947     }
1948 
1949     s->invisibleCursor = XCreatePixmapCursor (dpy, bitmap, bitmap,
1950 					      &black, &black, 0, 0);
1951     if (!s->invisibleCursor)
1952     {
1953 	compLogMessage ("core", CompLogLevelFatal,
1954 			"Couldn't create invisible cursor");
1955 	XFree (visinfo);
1956 	return FALSE;
1957     }
1958 
1959     XFreePixmap (dpy, bitmap);
1960     XFreeColors (dpy, s->colormap, &black.pixel, 1, 0);
1961 
1962     glXGetConfig (dpy, visinfo, GLX_USE_GL, &value);
1963     if (!value)
1964     {
1965 	compLogMessage ("core", CompLogLevelFatal,
1966 			"Root visual is not a GL visual");
1967 	XFree (visinfo);
1968 	return FALSE;
1969     }
1970 
1971     glXGetConfig (dpy, visinfo, GLX_DOUBLEBUFFER, &value);
1972     if (!value)
1973     {
1974 	compLogMessage ("core", CompLogLevelFatal,
1975 			"Root visual is not a double buffered GL visual");
1976 	XFree (visinfo);
1977 	return FALSE;
1978     }
1979 
1980     s->ctx = glXCreateContext (dpy, visinfo, NULL, !indirectRendering);
1981     if (!s->ctx)
1982     {
1983 	compLogMessage ("core", CompLogLevelFatal, "glXCreateContext failed");
1984 	XFree (visinfo);
1985 
1986 	return FALSE;
1987     }
1988 
1989     glxExtensions = glXQueryExtensionsString (dpy, screenNum);
1990     if (!strstr (glxExtensions, "GLX_EXT_texture_from_pixmap"))
1991     {
1992 	compLogMessage ("core", CompLogLevelFatal,
1993 			"GLX_EXT_texture_from_pixmap is missing");
1994 	XFree (visinfo);
1995 
1996 	return FALSE;
1997     }
1998 
1999     XFree (visinfo);
2000 
2001     if (!strstr (glxExtensions, "GLX_SGIX_fbconfig"))
2002     {
2003 	compLogMessage ("core", CompLogLevelFatal,
2004 			"GLX_SGIX_fbconfig is missing");
2005 	return FALSE;
2006     }
2007 
2008     s->getProcAddress = (GLXGetProcAddressProc)
2009 	getProcAddress (s, "glXGetProcAddressARB");
2010     s->bindTexImage = (GLXBindTexImageProc)
2011 	getProcAddress (s, "glXBindTexImageEXT");
2012     s->releaseTexImage = (GLXReleaseTexImageProc)
2013 	getProcAddress (s, "glXReleaseTexImageEXT");
2014     s->queryDrawable = (GLXQueryDrawableProc)
2015 	getProcAddress (s, "glXQueryDrawable");
2016     s->getFBConfigs = (GLXGetFBConfigsProc)
2017 	getProcAddress (s, "glXGetFBConfigs");
2018     s->getFBConfigAttrib = (GLXGetFBConfigAttribProc)
2019 	getProcAddress (s, "glXGetFBConfigAttrib");
2020     s->createPixmap = (GLXCreatePixmapProc)
2021 	getProcAddress (s, "glXCreatePixmap");
2022     s->destroyPixmap = (GLXDestroyPixmapProc)
2023 	getProcAddress (s, "glXDestroyPixmap");
2024 
2025     if (!s->bindTexImage)
2026     {
2027 	compLogMessage ("core", CompLogLevelFatal,
2028 			"glXBindTexImageEXT is missing");
2029 	return FALSE;
2030     }
2031 
2032     if (!s->releaseTexImage)
2033     {
2034 	compLogMessage ("core", CompLogLevelFatal,
2035 			"glXReleaseTexImageEXT is missing");
2036 	return FALSE;
2037     }
2038 
2039     if (!s->queryDrawable     ||
2040 	!s->getFBConfigs      ||
2041 	!s->getFBConfigAttrib ||
2042 	!s->createPixmap      ||
2043 	!s->destroyPixmap)
2044     {
2045 	compLogMessage ("core", CompLogLevelFatal,
2046 			"fbconfig functions missing");
2047 	return FALSE;
2048     }
2049 
2050     s->copySubBuffer = NULL;
2051     if (strstr (glxExtensions, "GLX_MESA_copy_sub_buffer"))
2052 	s->copySubBuffer = (GLXCopySubBufferProc)
2053 	    getProcAddress (s, "glXCopySubBufferMESA");
2054 
2055     s->getVideoSync = NULL;
2056     s->waitVideoSync = NULL;
2057     if (strstr (glxExtensions, "GLX_SGI_video_sync"))
2058     {
2059 	s->getVideoSync = (GLXGetVideoSyncProc)
2060 	    getProcAddress (s, "glXGetVideoSyncSGI");
2061 
2062 	s->waitVideoSync = (GLXWaitVideoSyncProc)
2063 	    getProcAddress (s, "glXWaitVideoSyncSGI");
2064     }
2065 
2066     glXMakeCurrent (dpy, s->output, s->ctx);
2067     currentRoot = s->root;
2068 
2069     glExtensions = (const char *) glGetString (GL_EXTENSIONS);
2070     if (!glExtensions)
2071     {
2072 	compLogMessage ("core", CompLogLevelFatal,
2073 			"No valid GL extensions string found.");
2074 	return FALSE;
2075     }
2076 
2077     s->textureNonPowerOfTwo = 0;
2078     if (strstr (glExtensions, "GL_ARB_texture_non_power_of_two"))
2079 	s->textureNonPowerOfTwo = 1;
2080 
2081     glGetIntegerv (GL_MAX_TEXTURE_SIZE, &s->maxTextureSize);
2082 
2083     s->textureRectangle = 0;
2084     if (strstr (glExtensions, "GL_NV_texture_rectangle")  ||
2085 	strstr (glExtensions, "GL_EXT_texture_rectangle") ||
2086 	strstr (glExtensions, "GL_ARB_texture_rectangle"))
2087     {
2088 	s->textureRectangle = 1;
2089 
2090 	if (!s->textureNonPowerOfTwo)
2091 	{
2092 	    GLint maxTextureSize;
2093 
2094 	    glGetIntegerv (GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, &maxTextureSize);
2095 	    if (maxTextureSize > s->maxTextureSize)
2096 		s->maxTextureSize = maxTextureSize;
2097 	}
2098     }
2099 
2100     if (!(s->textureRectangle || s->textureNonPowerOfTwo))
2101     {
2102 	compLogMessage ("core", CompLogLevelFatal,
2103 			"Support for non power of two textures missing");
2104 	return FALSE;
2105     }
2106 
2107     s->textureEnvCombine = s->textureEnvCrossbar = 0;
2108     if (strstr (glExtensions, "GL_ARB_texture_env_combine"))
2109     {
2110 	s->textureEnvCombine = 1;
2111 
2112 	/* XXX: GL_NV_texture_env_combine4 need special code but it seams to
2113 	   be working anyway for now... */
2114 	if (strstr (glExtensions, "GL_ARB_texture_env_crossbar") ||
2115 	    strstr (glExtensions, "GL_NV_texture_env_combine4"))
2116 	    s->textureEnvCrossbar = 1;
2117     }
2118 
2119     s->textureBorderClamp = 0;
2120     if (strstr (glExtensions, "GL_ARB_texture_border_clamp") ||
2121 	strstr (glExtensions, "GL_SGIS_texture_border_clamp"))
2122 	s->textureBorderClamp = 1;
2123 
2124     s->activeTexture       = NULL;
2125     s->clientActiveTexture = NULL;
2126     s->multiTexCoord2f     = NULL;
2127 
2128     s->maxTextureUnits = 1;
2129     if (strstr (glExtensions, "GL_ARB_multitexture"))
2130     {
2131 	s->activeTexture = (GLActiveTextureProc)
2132 	    getProcAddress (s, "glActiveTexture");
2133 	s->clientActiveTexture = (GLClientActiveTextureProc)
2134 	    getProcAddress (s, "glClientActiveTexture");
2135 	s->multiTexCoord2f = (GLMultiTexCoord2fProc)
2136 	    getProcAddress (s, "glMultiTexCoord2f");
2137 
2138 	if (s->activeTexture && s->clientActiveTexture && s->multiTexCoord2f)
2139 	    glGetIntegerv (GL_MAX_TEXTURE_UNITS_ARB, &s->maxTextureUnits);
2140     }
2141 
2142     s->genPrograms             = NULL;
2143     s->deletePrograms          = NULL;
2144     s->bindProgram             = NULL;
2145     s->programString           = NULL;
2146     s->programEnvParameter4f   = NULL;
2147     s->programLocalParameter4f = NULL;
2148     s->getProgramiv            = NULL;
2149 
2150     s->fragmentProgram = 0;
2151     if (strstr (glExtensions, "GL_ARB_fragment_program"))
2152     {
2153 	s->genPrograms = (GLGenProgramsProc)
2154 	    getProcAddress (s, "glGenProgramsARB");
2155 	s->deletePrograms = (GLDeleteProgramsProc)
2156 	    getProcAddress (s, "glDeleteProgramsARB");
2157 	s->bindProgram = (GLBindProgramProc)
2158 	    getProcAddress (s, "glBindProgramARB");
2159 	s->programString = (GLProgramStringProc)
2160 	    getProcAddress (s, "glProgramStringARB");
2161 	s->programEnvParameter4f = (GLProgramParameter4fProc)
2162 	    getProcAddress (s, "glProgramEnvParameter4fARB");
2163 	s->programLocalParameter4f = (GLProgramParameter4fProc)
2164 	    getProcAddress (s, "glProgramLocalParameter4fARB");
2165 	s->getProgramiv = (GLGetProgramivProc)
2166 	    getProcAddress (s, "glGetProgramivARB");
2167 
2168 	if (s->genPrograms	       &&
2169 	    s->deletePrograms	       &&
2170 	    s->bindProgram	       &&
2171 	    s->programString	       &&
2172 	    s->programEnvParameter4f   &&
2173 	    s->programLocalParameter4f &&
2174 	    s->getProgramiv)
2175 	    s->fragmentProgram = 1;
2176     }
2177 
2178     s->genFramebuffers        = NULL;
2179     s->deleteFramebuffers     = NULL;
2180     s->bindFramebuffer        = NULL;
2181     s->checkFramebufferStatus = NULL;
2182     s->framebufferTexture2D   = NULL;
2183     s->generateMipmap         = NULL;
2184 
2185     s->fbo = 0;
2186     if (strstr (glExtensions, "GL_EXT_framebuffer_object"))
2187     {
2188 	s->genFramebuffers = (GLGenFramebuffersProc)
2189 	    getProcAddress (s, "glGenFramebuffersEXT");
2190 	s->deleteFramebuffers = (GLDeleteFramebuffersProc)
2191 	    getProcAddress (s, "glDeleteFramebuffersEXT");
2192 	s->bindFramebuffer = (GLBindFramebufferProc)
2193 	    getProcAddress (s, "glBindFramebufferEXT");
2194 	s->checkFramebufferStatus = (GLCheckFramebufferStatusProc)
2195 	    getProcAddress (s, "glCheckFramebufferStatusEXT");
2196 	s->framebufferTexture2D = (GLFramebufferTexture2DProc)
2197 	    getProcAddress (s, "glFramebufferTexture2DEXT");
2198 	s->generateMipmap = (GLGenerateMipmapProc)
2199 	    getProcAddress (s, "glGenerateMipmapEXT");
2200 
2201 	if (s->genFramebuffers	      &&
2202 	    s->deleteFramebuffers     &&
2203 	    s->bindFramebuffer	      &&
2204 	    s->checkFramebufferStatus &&
2205 	    s->framebufferTexture2D   &&
2206 	    s->generateMipmap)
2207 	    s->fbo = 1;
2208     }
2209 
2210     s->textureCompression = 0;
2211     if (strstr (glExtensions, "GL_ARB_texture_compression"))
2212 	s->textureCompression = 1;
2213 
2214     fbConfigs = (*s->getFBConfigs) (dpy,
2215 				    screenNum,
2216 				    &nElements);
2217 
2218     for (i = 0; i <= MAX_DEPTH; i++)
2219     {
2220 	int j, db, stencil, depth, alpha, mipmap, rgba;
2221 
2222 	s->glxPixmapFBConfigs[i].fbConfig       = NULL;
2223 	s->glxPixmapFBConfigs[i].mipmap         = 0;
2224 	s->glxPixmapFBConfigs[i].yInverted      = 0;
2225 	s->glxPixmapFBConfigs[i].textureFormat  = 0;
2226 	s->glxPixmapFBConfigs[i].textureTargets = 0;
2227 
2228 	db      = MAXSHORT;
2229 	stencil = MAXSHORT;
2230 	depth   = MAXSHORT;
2231 	mipmap  = 0;
2232 	rgba    = 0;
2233 
2234 	for (j = 0; j < nElements; j++)
2235 	{
2236 	    XVisualInfo *vi;
2237 	    int		visualDepth;
2238 
2239 	    vi = glXGetVisualFromFBConfig (dpy, fbConfigs[j]);
2240 	    if (vi == NULL)
2241 		continue;
2242 
2243 	    visualDepth = vi->depth;
2244 
2245 	    XFree (vi);
2246 
2247 	    if (visualDepth != i)
2248 		continue;
2249 
2250 	    (*s->getFBConfigAttrib) (dpy,
2251 				     fbConfigs[j],
2252 				     GLX_ALPHA_SIZE,
2253 				     &alpha);
2254 	    (*s->getFBConfigAttrib) (dpy,
2255 				     fbConfigs[j],
2256 				     GLX_BUFFER_SIZE,
2257 				     &value);
2258 	    if (value != i && (value - alpha) != i)
2259 		continue;
2260 
2261 	    value = 0;
2262 	    if (i == 32)
2263 	    {
2264 		(*s->getFBConfigAttrib) (dpy,
2265 					 fbConfigs[j],
2266 					 GLX_BIND_TO_TEXTURE_RGBA_EXT,
2267 					 &value);
2268 
2269 		if (value)
2270 		{
2271 		    rgba = 1;
2272 
2273 		    s->glxPixmapFBConfigs[i].textureFormat =
2274 			GLX_TEXTURE_FORMAT_RGBA_EXT;
2275 		}
2276 	    }
2277 
2278 	    if (!value)
2279 	    {
2280 		if (rgba)
2281 		    continue;
2282 
2283 		(*s->getFBConfigAttrib) (dpy,
2284 					 fbConfigs[j],
2285 					 GLX_BIND_TO_TEXTURE_RGB_EXT,
2286 					 &value);
2287 		if (!value)
2288 		    continue;
2289 
2290 		s->glxPixmapFBConfigs[i].textureFormat =
2291 		    GLX_TEXTURE_FORMAT_RGB_EXT;
2292 	    }
2293 
2294 	    (*s->getFBConfigAttrib) (dpy,
2295 				     fbConfigs[j],
2296 				     GLX_DOUBLEBUFFER,
2297 				     &value);
2298 	    if (value > db)
2299 		continue;
2300 
2301 	    db = value;
2302 
2303 	    (*s->getFBConfigAttrib) (dpy,
2304 				     fbConfigs[j],
2305 				     GLX_STENCIL_SIZE,
2306 				     &value);
2307 	    if (value > stencil)
2308 		continue;
2309 
2310 	    stencil = value;
2311 
2312 	    (*s->getFBConfigAttrib) (dpy,
2313 				     fbConfigs[j],
2314 				     GLX_DEPTH_SIZE,
2315 				     &value);
2316 	    if (value > depth)
2317 		continue;
2318 
2319 	    depth = value;
2320 
2321 	    if (s->fbo)
2322 	    {
2323 		(*s->getFBConfigAttrib) (dpy,
2324 					 fbConfigs[j],
2325 					 GLX_BIND_TO_MIPMAP_TEXTURE_EXT,
2326 					 &value);
2327 		if (value < mipmap)
2328 		    continue;
2329 
2330 		mipmap = value;
2331 	    }
2332 
2333 	    (*s->getFBConfigAttrib) (dpy,
2334 				     fbConfigs[j],
2335 				     GLX_Y_INVERTED_EXT,
2336 				     &value);
2337 
2338 	    s->glxPixmapFBConfigs[i].yInverted = value;
2339 
2340 	    (*s->getFBConfigAttrib) (dpy,
2341 				     fbConfigs[j],
2342 				     GLX_BIND_TO_TEXTURE_TARGETS_EXT,
2343 				     &value);
2344 
2345 	    s->glxPixmapFBConfigs[i].textureTargets = value;
2346 
2347 	    s->glxPixmapFBConfigs[i].fbConfig = fbConfigs[j];
2348 	    s->glxPixmapFBConfigs[i].mipmap   = mipmap;
2349 	}
2350     }
2351 
2352     if (nElements)
2353 	XFree (fbConfigs);
2354 
2355     if (!s->glxPixmapFBConfigs[defaultDepth].fbConfig)
2356     {
2357 	compLogMessage ("core", CompLogLevelFatal,
2358 			"No GLXFBConfig for default depth, "
2359 			"this isn't going to work.");
2360 	return FALSE;
2361     }
2362 
2363     initTexture (s, &s->backgroundTexture);
2364     s->backgroundLoaded = FALSE;
2365 
2366     s->defaultIcon = NULL;
2367 
2368     s->desktopWindowCount = 0;
2369 
2370     glClearColor (0.0, 0.0, 0.0, 1.0);
2371     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
2372     glEnable (GL_CULL_FACE);
2373     glDisable (GL_BLEND);
2374     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2375     glColor4usv (defaultColor);
2376     glEnableClientState (GL_VERTEX_ARRAY);
2377     glEnableClientState (GL_TEXTURE_COORD_ARRAY);
2378 
2379     s->canDoSaturated = s->canDoSlightlySaturated = FALSE;
2380     if (s->textureEnvCombine && s->maxTextureUnits >= 2)
2381     {
2382 	s->canDoSaturated = TRUE;
2383 	if (s->textureEnvCrossbar && s->maxTextureUnits >= 4)
2384 	    s->canDoSlightlySaturated = TRUE;
2385     }
2386 
2387     s->redrawTime = 1000 / defaultRefreshRate;
2388     s->optimalRedrawTime = s->redrawTime;
2389 
2390     reshape (s, s->attrib.width, s->attrib.height);
2391 
2392     detectRefreshRateOfScreen (s);
2393     detectOutputDevices (s);
2394     updateOutputDevices (s);
2395 
2396     glLightModelfv (GL_LIGHT_MODEL_AMBIENT, globalAmbient);
2397 
2398     glEnable (GL_LIGHT0);
2399     glLightfv (GL_LIGHT0, GL_AMBIENT, ambientLight);
2400     glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuseLight);
2401     glLightfv (GL_LIGHT0, GL_POSITION, light0Position);
2402 
2403     glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
2404 
2405     glNormal3f (0.0f, 0.0f, -1.0f);
2406 
2407     s->lighting	      = FALSE;
2408     s->slowAnimations = FALSE;
2409 
2410     addScreenToDisplay (display, s);
2411 
2412     getDesktopHints (s);
2413 
2414     /* TODO: bailout properly when objectInitPlugins fails */
2415     assert (objectInitPlugins (&s->base));
2416 
2417     (*core.objectAdd) (&display->base, &s->base);
2418 
2419     XQueryTree (dpy, s->root,
2420 		&rootReturn, &parentReturn,
2421 		&children, &nchildren);
2422 
2423     for (i = 0; i < nchildren; i++)
2424 	addWindow (s, children[i], i ? children[i - 1] : 0);
2425 
2426     for (w = s->windows; w; w = w->next)
2427     {
2428 	if (w->attrib.map_state == IsViewable)
2429 	{
2430 	    w->activeNum = s->activeNum++;
2431 	    w->damaged   = TRUE;
2432 	    w->invisible = WINDOW_INVISIBLE (w);
2433 	}
2434     }
2435 
2436     /* enforce restack on all windows */
2437     for (i = 0, w = s->reverseWindows; w && i < nchildren; i++, w = w->prev)
2438 	children[i] = w->id;
2439     XRestackWindows (dpy, children, i);
2440 
2441     XFree (children);
2442 
2443     attrib.override_redirect = 1;
2444     attrib.event_mask	     = PropertyChangeMask;
2445 
2446     s->grabWindow = XCreateWindow (dpy, s->root, -100, -100, 1, 1, 0,
2447 				   CopyFromParent, InputOnly, CopyFromParent,
2448 				   CWOverrideRedirect | CWEventMask,
2449 				   &attrib);
2450     XMapWindow (dpy, s->grabWindow);
2451 
2452     for (i = 0; i < SCREEN_EDGE_NUM; i++)
2453     {
2454 	long xdndVersion = 3;
2455 
2456 	s->screenEdge[i].id = XCreateWindow (dpy, s->root, -100, -100, 1, 1, 0,
2457 					     CopyFromParent, InputOnly,
2458 					     CopyFromParent, CWOverrideRedirect,
2459 					     &attrib);
2460 
2461 	XChangeProperty (dpy, s->screenEdge[i].id, display->xdndAwareAtom,
2462 			 XA_ATOM, 32, PropModeReplace,
2463 			 (unsigned char *) &xdndVersion, 1);
2464 
2465 	XSelectInput (dpy, s->screenEdge[i].id,
2466 		      EnterWindowMask   |
2467 		      LeaveWindowMask   |
2468 		      ButtonPressMask   |
2469 		      ButtonReleaseMask |
2470 		      PointerMotionMask);
2471     }
2472 
2473     updateScreenEdges (s);
2474 
2475     setDesktopHints (s);
2476     setSupportingWmCheck (s);
2477     setSupportedWmHints (s);
2478 
2479     s->normalCursor = XCreateFontCursor (dpy, XC_left_ptr);
2480     s->busyCursor   = XCreateFontCursor (dpy, XC_watch);
2481 
2482     XDefineCursor (dpy, s->root, s->normalCursor);
2483 
2484     s->filter[NOTHING_TRANS_FILTER] = COMP_TEXTURE_FILTER_FAST;
2485     s->filter[SCREEN_TRANS_FILTER]  = COMP_TEXTURE_FILTER_GOOD;
2486     s->filter[WINDOW_TRANS_FILTER]  = COMP_TEXTURE_FILTER_GOOD;
2487 
2488     return TRUE;
2489 }
2490 
2491 void
removeScreen(CompScreen * s)2492 removeScreen (CompScreen *s)
2493 {
2494     CompDisplay *d = s->display;
2495     CompScreen  *p;
2496     int		i;
2497 
2498     for (p = d->screens; p; p = p->next)
2499 	if (p->next == s)
2500 	    break;
2501 
2502     if (p)
2503 	p->next = s->next;
2504     else
2505 	d->screens = NULL;
2506 
2507     removeAllSequences (s);
2508 
2509     while (s->windows)
2510 	removeWindow (s->windows);
2511 
2512     (*core.objectRemove) (&d->base, &s->base);
2513 
2514     objectFiniPlugins (&s->base);
2515 
2516     XUngrabKey (d->display, AnyKey, AnyModifier, s->root);
2517 
2518     for (i = 0; i < SCREEN_EDGE_NUM; i++)
2519 	XDestroyWindow (d->display, s->screenEdge[i].id);
2520 
2521     XDestroyWindow (d->display, s->grabWindow);
2522 
2523     finiTexture (s, &s->backgroundTexture);
2524 
2525     if (s->defaultIcon)
2526     {
2527 	finiTexture (s, &s->defaultIcon->texture);
2528 	free (s->defaultIcon);
2529     }
2530 
2531     glXDestroyContext (d->display, s->ctx);
2532 
2533     XFreeCursor (d->display, s->invisibleCursor);
2534 
2535 #ifdef USE_COW
2536     if (useCow)
2537 	XCompositeReleaseOverlayWindow (s->display->display, s->root);
2538 #endif
2539 
2540     freeScreen (s);
2541 }
2542 
2543 void
damageScreenRegion(CompScreen * screen,Region region)2544 damageScreenRegion (CompScreen *screen,
2545 		    Region     region)
2546 {
2547     if (screen->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK)
2548 	return;
2549 
2550     XUnionRegion (screen->damage, region, screen->damage);
2551 
2552     screen->damageMask |= COMP_SCREEN_DAMAGE_REGION_MASK;
2553 
2554     /* if the number of damage rectangles grows two much between repaints,
2555        we have a lot of overhead just for doing the damage tracking -
2556        in order to make sure we're not having too much overhead, damage
2557        the whole screen if we have a lot of damage rects */
2558     if (screen->damage->numRects > 100)
2559 	damageScreen (screen);
2560 }
2561 
2562 void
damageScreen(CompScreen * s)2563 damageScreen (CompScreen *s)
2564 {
2565     s->damageMask |= COMP_SCREEN_DAMAGE_ALL_MASK;
2566     s->damageMask &= ~COMP_SCREEN_DAMAGE_REGION_MASK;
2567 }
2568 
2569 void
damagePendingOnScreen(CompScreen * s)2570 damagePendingOnScreen (CompScreen *s)
2571 {
2572     s->damageMask |= COMP_SCREEN_DAMAGE_PENDING_MASK;
2573 }
2574 
2575 void
forEachWindowOnScreen(CompScreen * screen,ForEachWindowProc proc,void * closure)2576 forEachWindowOnScreen (CompScreen	 *screen,
2577 		       ForEachWindowProc proc,
2578 		       void		 *closure)
2579 {
2580     CompWindow *w;
2581 
2582     for (w = screen->windows; w; w = w->next)
2583 	(*proc) (w, closure);
2584 }
2585 
2586 void
focusDefaultWindow(CompScreen * s)2587 focusDefaultWindow (CompScreen *s)
2588 {
2589     CompDisplay *d = s->display;
2590     CompWindow  *w;
2591     CompWindow  *focus = NULL;
2592 
2593     if (!d->opt[COMP_DISPLAY_OPTION_CLICK_TO_FOCUS].value.b)
2594     {
2595 	w = findTopLevelWindowAtDisplay (d, d->below);
2596 
2597 	if (w && (*w->screen->focusWindow) (w))
2598 	{
2599 	    if (!(w->type & (CompWindowTypeDesktopMask |
2600 			     CompWindowTypeDockMask)))
2601 		focus = w;
2602 	}
2603 	else
2604 	{
2605 	    Bool         status;
2606 	    Window       rootReturn, childReturn;
2607 	    int          dummyInt;
2608 	    unsigned int dummyUInt;
2609 
2610 	    /* huh, we didn't find d->below ... perhaps it's out of date;
2611 	       try grabbing it through the server */
2612 
2613 	    status = XQueryPointer (d->display, s->root, &rootReturn,
2614 				    &childReturn, &dummyInt, &dummyInt,
2615 				    &dummyInt, &dummyInt, &dummyUInt);
2616 
2617 	    if (status && rootReturn == s->root)
2618 	    {
2619 		w = findTopLevelWindowAtDisplay (d, childReturn);
2620 
2621 		if (w && (*s->focusWindow) (w))
2622 		{
2623 		    if (!(w->type & (CompWindowTypeDesktopMask |
2624 				     CompWindowTypeDockMask)))
2625 			focus = w;
2626 		}
2627 	    }
2628 	}
2629     }
2630 
2631     if (!focus)
2632     {
2633 	for (w = s->reverseWindows; w; w = w->prev)
2634 	{
2635 	    if (w->type & CompWindowTypeDockMask)
2636 		continue;
2637 
2638 	    if (!(*s->focusWindow) (w))
2639 		continue;
2640 
2641 	    if (!focus)
2642 	    {
2643 		focus = w;
2644 		continue;
2645 	    }
2646 
2647 	    if (w->type & (CompWindowTypeNormalMask |
2648 			   CompWindowTypeDialogMask |
2649 			   CompWindowTypeModalDialogMask))
2650 	    {
2651 		if (compareWindowActiveness (focus, w) < 0)
2652 		    focus = w;
2653 	    }
2654 	}
2655     }
2656 
2657     if (focus)
2658     {
2659 	if (focus->id != d->activeWindow)
2660 	    moveInputFocusToWindow (focus);
2661     }
2662     else
2663     {
2664 	XSetInputFocus (d->display, s->root, RevertToPointerRoot,
2665 			CurrentTime);
2666     }
2667 }
2668 
2669 CompWindow *
findWindowAtScreen(CompScreen * s,Window id)2670 findWindowAtScreen (CompScreen *s,
2671 		    Window     id)
2672 {
2673     if (lastFoundWindow && lastFoundWindow->id == id)
2674     {
2675 	return lastFoundWindow;
2676     }
2677     else
2678     {
2679 	CompWindow *w;
2680 
2681 	for (w = s->windows; w; w = w->next)
2682 	    if (w->id == id)
2683 		return (lastFoundWindow = w);
2684     }
2685 
2686     return 0;
2687 }
2688 
2689 CompWindow *
findTopLevelWindowAtScreen(CompScreen * s,Window id)2690 findTopLevelWindowAtScreen (CompScreen *s,
2691 			    Window     id)
2692 {
2693     CompWindow *w;
2694 
2695     w = findWindowAtScreen (s, id);
2696     if (!w)
2697 	return NULL;
2698 
2699     if (w->attrib.override_redirect)
2700     {
2701 	/* likely a frame window */
2702 	if (w->attrib.class == InputOnly)
2703 	{
2704 	    for (w = s->windows; w; w = w->next)
2705 		if (w->frame == id)
2706 		    return w;
2707 	}
2708 
2709 	return NULL;
2710     }
2711 
2712     return w;
2713 }
2714 
2715 void
insertWindowIntoScreen(CompScreen * s,CompWindow * w,Window aboveId)2716 insertWindowIntoScreen (CompScreen *s,
2717 			CompWindow *w,
2718 			Window	   aboveId)
2719 {
2720     CompWindow *p;
2721 
2722     if (s->windows)
2723     {
2724 	if (!aboveId)
2725 	{
2726 	    w->next = s->windows;
2727 	    w->prev = NULL;
2728 	    s->windows->prev = w;
2729 	    s->windows = w;
2730 	}
2731 	else
2732 	{
2733 	    for (p = s->windows; p; p = p->next)
2734 	    {
2735 		if (p->id == aboveId)
2736 		{
2737 		    if (p->next)
2738 		    {
2739 			w->next = p->next;
2740 			w->prev = p;
2741 			p->next->prev = w;
2742 			p->next = w;
2743 		    }
2744 		    else
2745 		    {
2746 			p->next = w;
2747 			w->next = NULL;
2748 			w->prev = p;
2749 			s->reverseWindows = w;
2750 		    }
2751 		    break;
2752 		}
2753 	    }
2754 
2755 #ifdef DEBUG
2756 	    if (!p)
2757 		abort ();
2758 #endif
2759 
2760 	}
2761     }
2762     else
2763     {
2764 	s->reverseWindows = s->windows = w;
2765 	w->prev = w->next = NULL;
2766     }
2767 }
2768 
2769 void
unhookWindowFromScreen(CompScreen * s,CompWindow * w)2770 unhookWindowFromScreen (CompScreen *s,
2771 			CompWindow *w)
2772 {
2773     CompWindow *next, *prev;
2774 
2775     next = w->next;
2776     prev = w->prev;
2777 
2778     if (next || prev)
2779     {
2780 	if (next)
2781 	{
2782 	    if (prev)
2783 	    {
2784 		next->prev = prev;
2785 	    }
2786 	    else
2787 	    {
2788 		s->windows = next;
2789 		next->prev = NULL;
2790 	    }
2791 	}
2792 
2793 	if (prev)
2794 	{
2795 	    if (next)
2796 	    {
2797 		prev->next = next;
2798 	    }
2799 	    else
2800 	    {
2801 		s->reverseWindows = prev;
2802 		prev->next = NULL;
2803 	    }
2804 	}
2805     }
2806     else
2807     {
2808 	s->windows = s->reverseWindows = NULL;
2809     }
2810 
2811     if (w == lastFoundWindow)
2812 	lastFoundWindow = NULL;
2813     if (w == lastDamagedWindow)
2814 	lastDamagedWindow = NULL;
2815 }
2816 
2817 #define POINTER_GRAB_MASK (ButtonReleaseMask | \
2818 			   ButtonPressMask   | \
2819 			   PointerMotionMask)
2820 int
pushScreenGrab(CompScreen * s,Cursor cursor,const char * name)2821 pushScreenGrab (CompScreen *s,
2822 		Cursor     cursor,
2823 		const char *name)
2824 {
2825     if (s->maxGrab == 0)
2826     {
2827 	int status;
2828 
2829 	status = XGrabPointer (s->display->display, s->grabWindow, TRUE,
2830 			       POINTER_GRAB_MASK,
2831 			       GrabModeAsync, GrabModeAsync,
2832 			       s->root, cursor,
2833 			       CurrentTime);
2834 
2835 	if (status == GrabSuccess)
2836 	{
2837 	    status = XGrabKeyboard (s->display->display,
2838 				    s->grabWindow, TRUE,
2839 				    GrabModeAsync, GrabModeAsync,
2840 				    CurrentTime);
2841 	    if (status != GrabSuccess)
2842 	    {
2843 		XUngrabPointer (s->display->display, CurrentTime);
2844 		return 0;
2845 	    }
2846 	}
2847 	else
2848 	    return 0;
2849     }
2850     else
2851     {
2852 	XChangeActivePointerGrab (s->display->display, POINTER_GRAB_MASK,
2853 				  cursor, CurrentTime);
2854     }
2855 
2856     if (s->grabSize <= s->maxGrab)
2857     {
2858 	s->grabs = realloc (s->grabs, sizeof (CompGrab) * (s->maxGrab + 1));
2859 	if (!s->grabs)
2860 	    return 0;
2861 
2862 	s->grabSize = s->maxGrab + 1;
2863     }
2864 
2865     s->grabs[s->maxGrab].cursor = cursor;
2866     s->grabs[s->maxGrab].active = TRUE;
2867     s->grabs[s->maxGrab].name   = name;
2868 
2869     s->maxGrab++;
2870 
2871     return s->maxGrab;
2872 }
2873 
2874 void
updateScreenGrab(CompScreen * s,int index,Cursor cursor)2875 updateScreenGrab (CompScreen *s,
2876 		  int        index,
2877 		  Cursor     cursor)
2878 {
2879   index--;
2880 
2881 #ifdef DEBUG
2882     if (index < 0 || index >= s->maxGrab)
2883 	abort ();
2884 #endif
2885 
2886   XChangeActivePointerGrab (s->display->display, POINTER_GRAB_MASK,
2887 			    cursor, CurrentTime);
2888 
2889   s->grabs[index].cursor = cursor;
2890 }
2891 
2892 void
removeScreenGrab(CompScreen * s,int index,XPoint * restorePointer)2893 removeScreenGrab (CompScreen *s,
2894 		  int	     index,
2895 		  XPoint     *restorePointer)
2896 {
2897     int maxGrab;
2898 
2899     index--;
2900 
2901 #ifdef DEBUG
2902     if (index < 0 || index >= s->maxGrab)
2903 	abort ();
2904 #endif
2905 
2906     s->grabs[index].cursor = None;
2907     s->grabs[index].active = FALSE;
2908 
2909     for (maxGrab = s->maxGrab; maxGrab; maxGrab--)
2910 	if (s->grabs[maxGrab - 1].active)
2911 	    break;
2912 
2913     if (maxGrab != s->maxGrab)
2914     {
2915 	if (maxGrab)
2916 	{
2917 	    XChangeActivePointerGrab (s->display->display,
2918 				      POINTER_GRAB_MASK,
2919 				      s->grabs[maxGrab - 1].cursor,
2920 				      CurrentTime);
2921 	}
2922 	else
2923 	{
2924 	    if (restorePointer)
2925 		warpPointer (s,
2926 			     restorePointer->x - pointerX,
2927 			     restorePointer->y - pointerY);
2928 
2929 	    XUngrabPointer (s->display->display, CurrentTime);
2930 	    XUngrabKeyboard (s->display->display, CurrentTime);
2931 	}
2932 
2933 	s->maxGrab = maxGrab;
2934     }
2935 }
2936 
2937 /* otherScreenGrabExist takes a series of strings terminated by a NULL.
2938    It returns TRUE if a grab exists but it is NOT held by one of the
2939    plugins listed, returns FALSE otherwise. */
2940 
2941 Bool
otherScreenGrabExist(CompScreen * s,...)2942 otherScreenGrabExist (CompScreen *s, ...)
2943 {
2944     va_list ap;
2945     char    *name;
2946     int	    i;
2947 
2948     for (i = 0; i < s->maxGrab; i++)
2949     {
2950 	if (s->grabs[i].active)
2951 	{
2952 	    va_start (ap, s);
2953 
2954 	    name = va_arg (ap, char *);
2955 	    while (name)
2956 	    {
2957 		if (strcmp (name, s->grabs[i].name) == 0)
2958 		    break;
2959 
2960 		name = va_arg (ap, char *);
2961 	    }
2962 
2963 	    va_end (ap);
2964 
2965 	    if (!name)
2966 		return TRUE;
2967 	}
2968     }
2969 
2970     return FALSE;
2971 }
2972 
2973 static void
grabUngrabOneKey(CompScreen * s,unsigned int modifiers,int keycode,Bool grab)2974 grabUngrabOneKey (CompScreen   *s,
2975 		  unsigned int modifiers,
2976 		  int          keycode,
2977 		  Bool         grab)
2978 {
2979     if (grab)
2980     {
2981 	XGrabKey (s->display->display,
2982 		  keycode,
2983 		  modifiers,
2984 		  s->root,
2985 		  TRUE,
2986 		  GrabModeAsync,
2987 		  GrabModeAsync);
2988     }
2989     else
2990     {
2991 	XUngrabKey (s->display->display,
2992 		    keycode,
2993 		    modifiers,
2994 		    s->root);
2995     }
2996 }
2997 
2998 static Bool
grabUngrabKeys(CompScreen * s,unsigned int modifiers,int keycode,Bool grab)2999 grabUngrabKeys (CompScreen   *s,
3000 		unsigned int modifiers,
3001 		int          keycode,
3002 		Bool         grab)
3003 {
3004     XModifierKeymap *modMap = s->display->modMap;
3005     int ignore, mod, k;
3006 
3007     compCheckForError (s->display->display);
3008 
3009     for (ignore = 0; ignore <= s->display->ignoredModMask; ignore++)
3010     {
3011 	if (ignore & ~s->display->ignoredModMask)
3012 	    continue;
3013 
3014 	if (keycode != 0)
3015 	{
3016 	    grabUngrabOneKey (s, modifiers | ignore, keycode, grab);
3017 	}
3018 	else
3019 	{
3020 	    for (mod = 0; mod < 8; mod++)
3021 	    {
3022 		if (modifiers & (1 << mod))
3023 		{
3024 		    for (k = mod * modMap->max_keypermod;
3025 			 k < (mod + 1) * modMap->max_keypermod;
3026 			 k++)
3027 		    {
3028 			if (modMap->modifiermap[k])
3029 			{
3030 			    grabUngrabOneKey (
3031 				s,
3032 				(modifiers & ~(1 << mod)) | ignore,
3033 				modMap->modifiermap[k],
3034 				grab);
3035 			}
3036 		    }
3037 		}
3038 	    }
3039 	}
3040 
3041 	if (compCheckForError (s->display->display))
3042 	    return FALSE;
3043     }
3044 
3045     return TRUE;
3046 }
3047 
3048 static Bool
addPassiveKeyGrab(CompScreen * s,CompKeyBinding * key)3049 addPassiveKeyGrab (CompScreen	  *s,
3050 		   CompKeyBinding *key)
3051 {
3052     CompKeyGrab  *keyGrab;
3053     unsigned int mask;
3054     int          i;
3055 
3056     mask = virtualToRealModMask (s->display, key->modifiers);
3057 
3058     for (i = 0; i < s->nKeyGrab; i++)
3059     {
3060 	if (key->keycode == s->keyGrab[i].keycode &&
3061 	    mask         == s->keyGrab[i].modifiers)
3062 	{
3063 	    s->keyGrab[i].count++;
3064 	    return TRUE;
3065 	}
3066     }
3067 
3068     keyGrab = realloc (s->keyGrab, sizeof (CompKeyGrab) * (s->nKeyGrab + 1));
3069     if (!keyGrab)
3070 	return FALSE;
3071 
3072     s->keyGrab = keyGrab;
3073 
3074     if (!(mask & CompNoMask))
3075     {
3076 	if (!grabUngrabKeys (s, mask, key->keycode, TRUE))
3077 	    return FALSE;
3078     }
3079 
3080     s->keyGrab[s->nKeyGrab].keycode   = key->keycode;
3081     s->keyGrab[s->nKeyGrab].modifiers = mask;
3082     s->keyGrab[s->nKeyGrab].count     = 1;
3083 
3084     s->nKeyGrab++;
3085 
3086     return TRUE;
3087 }
3088 
3089 static void
removePassiveKeyGrab(CompScreen * s,CompKeyBinding * key)3090 removePassiveKeyGrab (CompScreen     *s,
3091 		      CompKeyBinding *key)
3092 {
3093     unsigned int mask;
3094     int          i;
3095 
3096     for (i = 0; i < s->nKeyGrab; i++)
3097     {
3098 	mask = virtualToRealModMask (s->display, key->modifiers);
3099 	if (key->keycode == s->keyGrab[i].keycode &&
3100 	    mask         == s->keyGrab[i].modifiers)
3101 	{
3102 	    s->keyGrab[i].count--;
3103 	    if (s->keyGrab[i].count)
3104 		return;
3105 
3106 	    memmove (s->keyGrab + i, s->keyGrab + i + 1,
3107 		     (s->nKeyGrab - (i + 1)) * sizeof (CompKeyGrab));
3108 
3109 	    s->nKeyGrab--;
3110 	    s->keyGrab = realloc (s->keyGrab,
3111 				  sizeof (CompKeyGrab) * s->nKeyGrab);
3112 
3113 	    if (!(mask & CompNoMask))
3114 		grabUngrabKeys (s, mask, key->keycode, FALSE);
3115 	}
3116     }
3117 }
3118 
3119 static void
updatePassiveKeyGrabs(CompScreen * s)3120 updatePassiveKeyGrabs (CompScreen *s)
3121 {
3122     int i;
3123 
3124     XUngrabKey (s->display->display, AnyKey, AnyModifier, s->root);
3125 
3126     for (i = 0; i < s->nKeyGrab; i++)
3127     {
3128 	if (!(s->keyGrab[i].modifiers & CompNoMask))
3129 	{
3130 	    grabUngrabKeys (s, s->keyGrab[i].modifiers,
3131 			    s->keyGrab[i].keycode, TRUE);
3132 	}
3133     }
3134 }
3135 
3136 static Bool
addPassiveButtonGrab(CompScreen * s,CompButtonBinding * button)3137 addPassiveButtonGrab (CompScreen        *s,
3138 		      CompButtonBinding *button)
3139 {
3140     CompButtonGrab *buttonGrab;
3141     int            i;
3142 
3143     for (i = 0; i < s->nButtonGrab; i++)
3144     {
3145 	if (button->button    == s->buttonGrab[i].button &&
3146 	    button->modifiers == s->buttonGrab[i].modifiers)
3147 	{
3148 	    s->buttonGrab[i].count++;
3149 	    return TRUE;
3150 	}
3151     }
3152 
3153     buttonGrab = realloc (s->buttonGrab,
3154 			  sizeof (CompButtonGrab) * (s->nButtonGrab + 1));
3155     if (!buttonGrab)
3156 	return FALSE;
3157 
3158     s->buttonGrab = buttonGrab;
3159 
3160     s->buttonGrab[s->nButtonGrab].button    = button->button;
3161     s->buttonGrab[s->nButtonGrab].modifiers = button->modifiers;
3162     s->buttonGrab[s->nButtonGrab].count     = 1;
3163 
3164     s->nButtonGrab++;
3165 
3166     return TRUE;
3167 }
3168 
3169 static void
removePassiveButtonGrab(CompScreen * s,CompButtonBinding * button)3170 removePassiveButtonGrab (CompScreen        *s,
3171 			 CompButtonBinding *button)
3172 {
3173     int          i;
3174 
3175     for (i = 0; i < s->nButtonGrab; i++)
3176     {
3177 	if (button->button    == s->buttonGrab[i].button &&
3178 	    button->modifiers == s->buttonGrab[i].modifiers)
3179 	{
3180 	    s->buttonGrab[i].count--;
3181 	    if (s->buttonGrab[i].count)
3182 		return;
3183 
3184 	    memmove (s->buttonGrab + i, s->buttonGrab + i + 1,
3185 		     (s->nButtonGrab - (i + 1)) * sizeof (CompButtonGrab));
3186 
3187 	    s->nButtonGrab--;
3188 	    s->buttonGrab = realloc (s->buttonGrab,
3189 				     sizeof (CompButtonGrab) * s->nButtonGrab);
3190 	}
3191     }
3192 }
3193 
3194 Bool
addScreenAction(CompScreen * s,CompAction * action)3195 addScreenAction (CompScreen *s,
3196 		 CompAction *action)
3197 {
3198     if (action->type & CompBindingTypeKey)
3199     {
3200 	if (!addPassiveKeyGrab (s, &action->key))
3201 	    return FALSE;
3202     }
3203 
3204     if (action->type & CompBindingTypeButton)
3205     {
3206 	if (!addPassiveButtonGrab (s, &action->button))
3207 	{
3208 	    if (action->type & CompBindingTypeKey)
3209 		removePassiveKeyGrab (s, &action->key);
3210 
3211 	    return FALSE;
3212 	}
3213     }
3214 
3215     if (action->edgeMask)
3216     {
3217 	int i;
3218 
3219 	for (i = 0; i < SCREEN_EDGE_NUM; i++)
3220 	    if (action->edgeMask & (1 << i))
3221 		enableScreenEdge (s, i);
3222     }
3223 
3224     return TRUE;
3225 }
3226 
3227 void
removeScreenAction(CompScreen * s,CompAction * action)3228 removeScreenAction (CompScreen *s,
3229 		    CompAction *action)
3230 {
3231     if (action->type & CompBindingTypeKey)
3232 	removePassiveKeyGrab (s, &action->key);
3233 
3234     if (action->type & CompBindingTypeButton)
3235 	removePassiveButtonGrab (s, &action->button);
3236 
3237     if (action->edgeMask)
3238     {
3239 	int i;
3240 
3241 	for (i = 0; i < SCREEN_EDGE_NUM; i++)
3242 	    if (action->edgeMask & (1 << i))
3243 		disableScreenEdge (s, i);
3244     }
3245 }
3246 
3247 void
updatePassiveGrabs(CompScreen * s)3248 updatePassiveGrabs (CompScreen *s)
3249 {
3250     updatePassiveKeyGrabs (s);
3251 }
3252 
3253 static void
computeWorkareaForBox(CompScreen * s,BoxPtr pBox,XRectangle * area)3254 computeWorkareaForBox (CompScreen *s,
3255 		       BoxPtr     pBox,
3256 		       XRectangle *area)
3257 {
3258     CompWindow *w;
3259     Region     region;
3260     REGION     r;
3261     int	       x1, y1, x2, y2;
3262 
3263     region = XCreateRegion ();
3264     if (!region)
3265     {
3266 	area->x      = pBox->x1;
3267 	area->y      = pBox->y1;
3268 	area->width  = pBox->x1 - pBox->x1;
3269 	area->height = pBox->y2 - pBox->y1;
3270 
3271 	return;
3272     }
3273 
3274     r.rects    = &r.extents;
3275     r.numRects = r.size = 1;
3276     r.extents  = *pBox;
3277 
3278     XUnionRegion (&r, region, region);
3279 
3280     for (w = s->windows; w; w = w->next)
3281     {
3282 	if (!w->mapNum)
3283 	    continue;
3284 
3285 	if (!w->struts)
3286 	    continue;
3287 
3288 	r.extents.y1 = pBox->y1;
3289 	r.extents.y2 = pBox->y2;
3290 
3291 	x1 = w->struts->left.x;
3292 	y1 = w->struts->left.y;
3293 	x2 = x1 + w->struts->left.width;
3294 	y2 = y1 + w->struts->left.height;
3295 
3296 	if (y1 < pBox->y2 && y2 > pBox->y1)
3297 	{
3298 	    r.extents.x1 = x1;
3299 	    r.extents.x2 = x2;
3300 
3301 	    XSubtractRegion (region, &r, region);
3302 	}
3303 
3304 	x1 = w->struts->right.x;
3305 	y1 = w->struts->right.y;
3306 	x2 = x1 + w->struts->right.width;
3307 	y2 = y1 + w->struts->right.height;
3308 
3309 	if (y1 < pBox->y2 && y2 > pBox->y1)
3310 	{
3311 	    r.extents.x1 = x1;
3312 	    r.extents.x2 = x2;
3313 
3314 	    XSubtractRegion (region, &r, region);
3315 	}
3316 
3317 	r.extents.x1 = pBox->x1;
3318 	r.extents.x2 = pBox->x2;
3319 
3320 	x1 = w->struts->top.x;
3321 	y1 = w->struts->top.y;
3322 	x2 = x1 + w->struts->top.width;
3323 	y2 = y1 + w->struts->top.height;
3324 
3325 	if (x1 < pBox->x2 && x2 > pBox->x1)
3326 	{
3327 	    r.extents.y1 = y1;
3328 	    r.extents.y2 = y2;
3329 
3330 	    XSubtractRegion (region, &r, region);
3331 	}
3332 
3333 	x1 = w->struts->bottom.x;
3334 	y1 = w->struts->bottom.y;
3335 	x2 = x1 + w->struts->bottom.width;
3336 	y2 = y1 + w->struts->bottom.height;
3337 
3338 	if (x1 < pBox->x2 && x2 > pBox->x1)
3339 	{
3340 	    r.extents.y1 = y1;
3341 	    r.extents.y2 = y2;
3342 
3343 	    XSubtractRegion (region, &r, region);
3344 	}
3345     }
3346 
3347     if (XEmptyRegion (region))
3348     {
3349 	compLogMessage ("core", CompLogLevelWarn,
3350 			"Empty box after applying struts, ignoring struts");
3351 	region->extents = *pBox;
3352     }
3353 
3354     area->x      = region->extents.x1;
3355     area->y      = region->extents.y1;
3356     area->width  = region->extents.x2 - region->extents.x1;
3357     area->height = region->extents.y2 - region->extents.y1;
3358 
3359     XDestroyRegion (region);
3360 }
3361 
3362 void
updateWorkareaForScreen(CompScreen * s)3363 updateWorkareaForScreen (CompScreen *s)
3364 {
3365     XRectangle workArea;
3366     BoxRec     box;
3367     int        i;
3368     Bool       workAreaChanged = FALSE;
3369 
3370     for (i = 0; i < s->nOutputDev; i++)
3371     {
3372 	computeWorkareaForBox (s, &s->outputDev[i].region.extents, &workArea);
3373 	if (memcmp (&workArea, &s->outputDev[i].workArea, sizeof (XRectangle)))
3374 	{
3375 	    workAreaChanged = TRUE;
3376 	    s->outputDev[i].workArea = workArea;
3377 	}
3378     }
3379 
3380     box.x1 = 0;
3381     box.y1 = 0;
3382     box.x2 = s->width;
3383     box.y2 = s->height;
3384 
3385     computeWorkareaForBox (s, &box, &workArea);
3386 
3387     if (memcmp (&workArea, &s->workArea, sizeof (XRectangle)))
3388     {
3389 	workAreaChanged = TRUE;
3390 	s->workArea = workArea;
3391 
3392 	setDesktopHints (s);
3393     }
3394 
3395     if (workAreaChanged)
3396     {
3397 	CompWindow *w;
3398 
3399 	/* as work area changed, update all maximized windows on this
3400 	   screen to snap to the new work area */
3401 	for (w = s->windows; w; w = w->next)
3402 	    updateWindowSize (w);
3403     }
3404 }
3405 
3406 static Bool
isClientListWindow(CompWindow * w)3407 isClientListWindow (CompWindow *w)
3408 {
3409     /* windows with client id less than 2 have been destroyed and only exists
3410        because some plugin keeps a reference to them. they should not be in
3411        client lists */
3412     if (w->id < 2)
3413 	return FALSE;
3414 
3415     if (w->attrib.override_redirect)
3416 	return FALSE;
3417 
3418     if (w->attrib.map_state != IsViewable)
3419     {
3420 	if (!(w->state & CompWindowStateHiddenMask))
3421 	    return FALSE;
3422     }
3423 
3424     return TRUE;
3425 }
3426 
3427 static void
countClientListWindow(CompWindow * w,void * closure)3428 countClientListWindow (CompWindow *w,
3429 		       void       *closure)
3430 {
3431     if (isClientListWindow (w))
3432     {
3433 	int *num = (int *) closure;
3434 
3435 	*num = *num + 1;
3436     }
3437 }
3438 
3439 static void
addClientListWindow(CompWindow * w,void * closure)3440 addClientListWindow (CompWindow *w,
3441 		     void       *closure)
3442 {
3443     if (isClientListWindow (w))
3444     {
3445 	int *num = (int *) closure;
3446 
3447 	w->screen->clientList[*num] = w;
3448 	*num = *num + 1;
3449     }
3450 }
3451 
3452 static int
compareMappingOrder(const void * w1,const void * w2)3453 compareMappingOrder (const void *w1,
3454 		     const void *w2)
3455 {
3456     return (*((CompWindow **) w1))->mapNum - (*((CompWindow **) w2))->mapNum;
3457 }
3458 
3459 void
updateClientListForScreen(CompScreen * s)3460 updateClientListForScreen (CompScreen *s)
3461 {
3462     Window *clientList;
3463     Window *clientListStacking;
3464     Bool   updateClientList = FALSE;
3465     Bool   updateClientListStacking = FALSE;
3466     int	   i, n = 0;
3467 
3468     forEachWindowOnScreen (s, countClientListWindow, (void *) &n);
3469 
3470     if (n == 0)
3471     {
3472 	if (n != s->nClientList)
3473 	{
3474 	    free (s->clientList);
3475 
3476 	    s->clientList  = NULL;
3477 	    s->nClientList = 0;
3478 
3479 	    XChangeProperty (s->display->display, s->root,
3480 			     s->display->clientListAtom,
3481 			     XA_WINDOW, 32, PropModeReplace,
3482 			     (unsigned char *) &s->grabWindow, 1);
3483 	    XChangeProperty (s->display->display, s->root,
3484 			     s->display->clientListStackingAtom,
3485 			     XA_WINDOW, 32, PropModeReplace,
3486 			     (unsigned char *) &s->grabWindow, 1);
3487 	}
3488 
3489 	return;
3490     }
3491 
3492     if (n != s->nClientList)
3493     {
3494 	CompWindow **list;
3495 
3496 	list = realloc (s->clientList,
3497 			(sizeof (CompWindow *) + sizeof (Window) * 2) * n);
3498 	if (!list)
3499 	    return;
3500 
3501 	s->clientList  = list;
3502 	s->nClientList = n;
3503 
3504 	updateClientList = updateClientListStacking = TRUE;
3505     }
3506 
3507     clientList	       = (Window *) (s->clientList + n);
3508     clientListStacking = clientList + n;
3509 
3510     i = 0;
3511     forEachWindowOnScreen (s, addClientListWindow, (void *) &i);
3512 
3513     for (i = 0; i < n; i++)
3514     {
3515 	if (!updateClientListStacking)
3516 	{
3517 	    if (clientListStacking[i] != s->clientList[i]->id)
3518 		updateClientListStacking = TRUE;
3519 	}
3520 
3521 	clientListStacking[i] = s->clientList[i]->id;
3522     }
3523 
3524     /* sort window list in mapping order */
3525     qsort (s->clientList, n, sizeof (CompWindow *), compareMappingOrder);
3526 
3527     for (i = 0; i < n; i++)
3528     {
3529 	if (!updateClientList)
3530 	{
3531 	    if (clientList[i] != s->clientList[i]->id)
3532 		updateClientList = TRUE;
3533 	}
3534 
3535 	clientList[i] = s->clientList[i]->id;
3536     }
3537 
3538     if (updateClientList)
3539 	XChangeProperty (s->display->display, s->root,
3540 			 s->display->clientListAtom,
3541 			 XA_WINDOW, 32, PropModeReplace,
3542 			 (unsigned char *) clientList, s->nClientList);
3543 
3544     if (updateClientListStacking)
3545 	XChangeProperty (s->display->display, s->root,
3546 			 s->display->clientListStackingAtom,
3547 			 XA_WINDOW, 32, PropModeReplace,
3548 			 (unsigned char *) clientListStacking, s->nClientList);
3549 }
3550 
3551 Window
getActiveWindow(CompDisplay * display,Window root)3552 getActiveWindow (CompDisplay *display,
3553 		 Window      root)
3554 {
3555     Atom	  actual;
3556     int		  result, format;
3557     unsigned long n, left;
3558     unsigned char *data;
3559     Window	  w = None;
3560 
3561     result = XGetWindowProperty (display->display, root,
3562 				 display->winActiveAtom, 0L, 1L, FALSE,
3563 				 XA_WINDOW, &actual, &format,
3564 				 &n, &left, &data);
3565 
3566     if (result == Success && data)
3567     {
3568 	if (n)
3569 	    memcpy (&w, data, sizeof (Window));
3570 	XFree (data);
3571     }
3572 
3573     return w;
3574 }
3575 
3576 void
toolkitAction(CompScreen * s,Atom toolkitAction,Time eventTime,Window window,long data0,long data1,long data2)3577 toolkitAction (CompScreen *s,
3578 	       Atom	  toolkitAction,
3579 	       Time       eventTime,
3580 	       Window	  window,
3581 	       long	  data0,
3582 	       long	  data1,
3583 	       long	  data2)
3584 {
3585     XEvent ev;
3586 
3587     ev.type		    = ClientMessage;
3588     ev.xclient.window	    = window;
3589     ev.xclient.message_type = s->display->toolkitActionAtom;
3590     ev.xclient.format	    = 32;
3591     ev.xclient.data.l[0]    = toolkitAction;
3592     ev.xclient.data.l[1]    = eventTime;
3593     ev.xclient.data.l[2]    = data0;
3594     ev.xclient.data.l[3]    = data1;
3595     ev.xclient.data.l[4]    = data2;
3596 
3597     XUngrabPointer (s->display->display, CurrentTime);
3598     XUngrabKeyboard (s->display->display, CurrentTime);
3599 
3600     XSendEvent (s->display->display, s->root, FALSE, StructureNotifyMask, &ev);
3601 }
3602 
3603 void
runCommand(CompScreen * s,const char * command)3604 runCommand (CompScreen *s,
3605 	    const char *command)
3606 {
3607     if (*command == '\0')
3608 	return;
3609 
3610     if (fork () == 0)
3611     {
3612 	/* build a display string that uses the right screen number */
3613 	/* 5 extra chars should be enough for pretty much every situation */
3614 	int  stringLen = strlen (s->display->displayString) + 5;
3615 	char screenString[stringLen];
3616 	char *pos, *delimiter, *colon;
3617 
3618 	setsid ();
3619 
3620 	strcpy (screenString, s->display->displayString);
3621 	delimiter = strrchr (screenString, ':');
3622 	if (delimiter)
3623 	{
3624 	    colon = "";
3625 	    delimiter = strchr (delimiter, '.');
3626 	    if (delimiter)
3627 		*delimiter = '\0';
3628 	}
3629 	else
3630 	{
3631 	    /* insert :0 to keep the syntax correct */
3632 	    colon = ":0";
3633 	}
3634 	pos = screenString + strlen (screenString);
3635 
3636 	snprintf (pos, stringLen - (pos - screenString),
3637 		  "%s.%d", colon, s->screenNum);
3638 
3639 	putenv (screenString);
3640 
3641 	exit (execl ("/bin/sh", "/bin/sh", "-c", command, NULL));
3642     }
3643 }
3644 
3645 void
moveScreenViewport(CompScreen * s,int tx,int ty,Bool sync)3646 moveScreenViewport (CompScreen *s,
3647 		    int	       tx,
3648 		    int	       ty,
3649 		    Bool       sync)
3650 {
3651     CompWindow *w;
3652     int         wx, wy;
3653 
3654     tx = s->x - tx;
3655     tx = MOD (tx, s->hsize);
3656     tx -= s->x;
3657 
3658     ty = s->y - ty;
3659     ty = MOD (ty, s->vsize);
3660     ty -= s->y;
3661 
3662     if (!tx && !ty)
3663 	return;
3664 
3665     s->x += tx;
3666     s->y += ty;
3667 
3668     tx *= -s->width;
3669     ty *= -s->height;
3670 
3671     for (w = s->windows; w; w = w->next)
3672     {
3673 	if (windowOnAllViewports (w))
3674 	    continue;
3675 
3676 	getWindowMovementForOffset (w, tx, ty, &wx, &wy);
3677 
3678 	if (w->saveMask & CWX)
3679 	    w->saveWc.x += wx;
3680 
3681 	if (w->saveMask & CWY)
3682 	    w->saveWc.y += wy;
3683 
3684 	/* move */
3685 	moveWindow (w, wx, wy, sync, TRUE);
3686 
3687 	if (sync)
3688 	    syncWindowPosition (w);
3689     }
3690 
3691     if (sync)
3692     {
3693 	setDesktopHints (s);
3694 
3695 	setCurrentActiveWindowHistory (s, s->x, s->y);
3696 
3697 	w = findWindowAtDisplay (s->display, s->display->activeWindow);
3698 	if (w)
3699 	{
3700 	    int x, y;
3701 
3702 	    defaultViewportForWindow (w, &x, &y);
3703 
3704 	    /* add window to current history if it's default viewport is
3705 	       still the current one. */
3706 	    if (s->x == x && s->y == y)
3707 		addToCurrentActiveWindowHistory (s, w->id);
3708 	}
3709     }
3710 }
3711 
3712 void
moveWindowToViewportPosition(CompWindow * w,int x,int y,Bool sync)3713 moveWindowToViewportPosition (CompWindow *w,
3714 			      int	 x,
3715 			      int        y,
3716 			      Bool       sync)
3717 {
3718     int	tx, vWidth = w->screen->width * w->screen->hsize;
3719     int ty, vHeight = w->screen->height * w->screen->vsize;
3720 
3721     if (w->screen->hsize != 1)
3722     {
3723 	x += w->screen->x * w->screen->width;
3724 	x = MOD (x, vWidth);
3725 	x -= w->screen->x * w->screen->width;
3726     }
3727 
3728     if (w->screen->vsize != 1)
3729     {
3730 	y += w->screen->y * w->screen->height;
3731 	y = MOD (y, vHeight);
3732 	y -= w->screen->y * w->screen->height;
3733     }
3734 
3735     tx = x - w->attrib.x;
3736     ty = y - w->attrib.y;
3737 
3738     if (tx || ty)
3739     {
3740 	int m, wx, wy;
3741 
3742 	if (!w->managed)
3743 	    return;
3744 
3745 	if (w->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
3746 	    return;
3747 
3748 	if (w->state & CompWindowStateStickyMask)
3749 	    return;
3750 
3751 	wx = tx;
3752 	wy = ty;
3753 
3754 	if (w->screen->hsize != 1)
3755 	{
3756 	    m = w->attrib.x + tx;
3757 
3758 	    if (m - w->output.left < w->screen->width - vWidth)
3759 		wx = tx + vWidth;
3760 	    else if (m + w->width + w->output.right > vWidth)
3761 		wx = tx - vWidth;
3762 	}
3763 
3764 	if (w->screen->vsize != 1)
3765 	{
3766 	    m = w->attrib.y + ty;
3767 
3768 	    if (m - w->output.top < w->screen->height - vHeight)
3769 		wy = ty + vHeight;
3770 	    else if (m + w->height + w->output.bottom > vHeight)
3771 		wy = ty - vHeight;
3772 	}
3773 
3774 	if (w->saveMask & CWX)
3775 	    w->saveWc.x += wx;
3776 
3777 	if (w->saveMask & CWY)
3778 	    w->saveWc.y += wy;
3779 
3780 	moveWindow (w, wx, wy, sync, TRUE);
3781 
3782 	if (sync)
3783 	    syncWindowPosition (w);
3784     }
3785 }
3786 
3787 CompGroup *
addGroupToScreen(CompScreen * s,Window id)3788 addGroupToScreen (CompScreen *s,
3789 		  Window     id)
3790 {
3791     CompGroup *group;
3792 
3793     group = malloc (sizeof (CompGroup));
3794     if (!group)
3795 	return NULL;
3796 
3797     group->next   = s->groups;
3798     group->refCnt = 1;
3799     group->id     = id;
3800 
3801     s->groups = group;
3802 
3803     return group;
3804 }
3805 
3806 void
removeGroupFromScreen(CompScreen * s,CompGroup * group)3807 removeGroupFromScreen (CompScreen *s,
3808 		       CompGroup  *group)
3809 {
3810     group->refCnt--;
3811     if (group->refCnt)
3812 	return;
3813 
3814     if (group == s->groups)
3815     {
3816 	s->groups = group->next;
3817     }
3818     else
3819     {
3820 	CompGroup *g;
3821 
3822 	for (g = s->groups; g; g = g->next)
3823 	{
3824 	    if (g->next == group)
3825 	    {
3826 		g->next = group->next;
3827 		break;
3828 	    }
3829 	}
3830     }
3831 
3832     free (group);
3833 }
3834 
3835 CompGroup *
findGroupAtScreen(CompScreen * s,Window id)3836 findGroupAtScreen (CompScreen *s,
3837 		   Window     id)
3838 {
3839     CompGroup *g;
3840 
3841     for (g = s->groups; g; g = g->next)
3842 	if (g->id == id)
3843 	    return g;
3844 
3845     return NULL;
3846 }
3847 
3848 void
applyStartupProperties(CompScreen * screen,CompWindow * window)3849 applyStartupProperties (CompScreen *screen,
3850 			CompWindow *window)
3851 {
3852     CompStartupSequence *s;
3853     const char	        *startupId = window->startupId;
3854 
3855     if (!startupId)
3856     {
3857 	CompWindow *leader;
3858 
3859 	leader = findWindowAtScreen (screen, window->clientLeader);
3860 	if (leader)
3861 	    startupId = leader->startupId;
3862 
3863 	if (!startupId)
3864 	    return;
3865     }
3866 
3867     for (s = screen->startupSequences; s; s = s->next)
3868     {
3869 	const char *id;
3870 
3871 	id = sn_startup_sequence_get_id (s->sequence);
3872 	if (strcmp (id, startupId) == 0)
3873 	    break;
3874     }
3875 
3876     if (s)
3877     {
3878 	int workspace;
3879 
3880 	window->initialViewportX = s->viewportX;
3881 	window->initialViewportY = s->viewportY;
3882 
3883 	workspace = sn_startup_sequence_get_workspace (s->sequence);
3884 	if (workspace >= 0)
3885 	    setDesktopForWindow (window, workspace);
3886 
3887 	window->initialTimestamp    =
3888 	    sn_startup_sequence_get_timestamp (s->sequence);
3889 	window->initialTimestampSet = TRUE;
3890     }
3891 }
3892 
3893 void
sendWindowActivationRequest(CompScreen * s,Window id)3894 sendWindowActivationRequest (CompScreen *s,
3895 			     Window	id)
3896 {
3897     XEvent xev;
3898 
3899     xev.xclient.type    = ClientMessage;
3900     xev.xclient.display = s->display->display;
3901     xev.xclient.format  = 32;
3902 
3903     xev.xclient.message_type = s->display->winActiveAtom;
3904     xev.xclient.window	     = id;
3905 
3906     xev.xclient.data.l[0] = ClientTypePager;
3907     xev.xclient.data.l[1] = 0;
3908     xev.xclient.data.l[2] = 0;
3909     xev.xclient.data.l[3] = 0;
3910     xev.xclient.data.l[4] = 0;
3911 
3912     XSendEvent (s->display->display,
3913 		s->root,
3914 		FALSE,
3915 		SubstructureRedirectMask | SubstructureNotifyMask,
3916 		&xev);
3917 }
3918 
3919 void
screenTexEnvMode(CompScreen * s,GLenum mode)3920 screenTexEnvMode (CompScreen *s,
3921 		  GLenum     mode)
3922 {
3923     if (s->lighting)
3924 	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
3925     else
3926 	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode);
3927 }
3928 
3929 void
screenLighting(CompScreen * s,Bool lighting)3930 screenLighting (CompScreen *s,
3931 		Bool       lighting)
3932 {
3933     if (s->lighting != lighting)
3934     {
3935 	if (!s->opt[COMP_SCREEN_OPTION_LIGHTING].value.b)
3936 	    lighting = FALSE;
3937 
3938 	if (lighting)
3939 	{
3940 	    glEnable (GL_COLOR_MATERIAL);
3941 	    glEnable (GL_LIGHTING);
3942 	}
3943 	else
3944 	{
3945 	    glDisable (GL_COLOR_MATERIAL);
3946 	    glDisable (GL_LIGHTING);
3947 	}
3948 
3949 	s->lighting = lighting;
3950 
3951 	screenTexEnvMode (s, GL_REPLACE);
3952     }
3953 }
3954 
3955 void
enableScreenEdge(CompScreen * s,int edge)3956 enableScreenEdge (CompScreen *s,
3957 		  int	     edge)
3958 {
3959     s->screenEdge[edge].count++;
3960     if (s->screenEdge[edge].count == 1)
3961 	XMapRaised (s->display->display, s->screenEdge[edge].id);
3962 }
3963 
3964 void
disableScreenEdge(CompScreen * s,int edge)3965 disableScreenEdge (CompScreen *s,
3966 		   int	      edge)
3967 {
3968     s->screenEdge[edge].count--;
3969     if (s->screenEdge[edge].count == 0)
3970 	XUnmapWindow (s->display->display, s->screenEdge[edge].id);
3971 }
3972 
3973 Window
getTopWindow(CompScreen * s)3974 getTopWindow (CompScreen *s)
3975 {
3976     CompWindow *w;
3977 
3978     /* return first window that has not been destroyed */
3979     for (w = s->reverseWindows; w; w = w->prev)
3980     {
3981 	if (w->id > 1)
3982 	    return w->id;
3983     }
3984 
3985     return None;
3986 }
3987 
3988 void
makeScreenCurrent(CompScreen * s)3989 makeScreenCurrent (CompScreen *s)
3990 {
3991     if (currentRoot != s->root)
3992     {
3993 	glXMakeCurrent (s->display->display, s->output, s->ctx);
3994 	currentRoot = s->root;
3995     }
3996 
3997     s->pendingCommands = TRUE;
3998 }
3999 
4000 void
finishScreenDrawing(CompScreen * s)4001 finishScreenDrawing (CompScreen *s)
4002 {
4003     if (s->pendingCommands)
4004     {
4005 	makeScreenCurrent (s);
4006 	glFinish ();
4007 
4008 	s->pendingCommands = FALSE;
4009     }
4010 }
4011 
4012 int
outputDeviceForPoint(CompScreen * s,int x,int y)4013 outputDeviceForPoint (CompScreen *s,
4014 		      int	 x,
4015 		      int	 y)
4016 {
4017     return outputDeviceForGeometry (s, x, y, 1, 1, 0);
4018 }
4019 
4020 void
getCurrentOutputExtents(CompScreen * s,int * x1,int * y1,int * x2,int * y2)4021 getCurrentOutputExtents (CompScreen *s,
4022 			 int	    *x1,
4023 			 int	    *y1,
4024 			 int	    *x2,
4025 			 int	    *y2)
4026 {
4027     if (x1)
4028 	*x1 = s->outputDev[s->currentOutputDev].region.extents.x1;
4029 
4030     if (y1)
4031 	*y1 = s->outputDev[s->currentOutputDev].region.extents.y1;
4032 
4033     if (x2)
4034 	*x2 = s->outputDev[s->currentOutputDev].region.extents.x2;
4035 
4036     if (y2)
4037 	*y2 = s->outputDev[s->currentOutputDev].region.extents.y2;
4038 }
4039 
4040 void
setNumberOfDesktops(CompScreen * s,unsigned int nDesktop)4041 setNumberOfDesktops (CompScreen   *s,
4042 		     unsigned int nDesktop)
4043 {
4044     CompWindow *w;
4045 
4046     if (nDesktop < 1 || nDesktop >= 0xffffffff)
4047 	return;
4048 
4049     if (nDesktop == s->nDesktop)
4050 	return;
4051 
4052     if (s->currentDesktop >= nDesktop)
4053 	s->currentDesktop = nDesktop - 1;
4054 
4055     for (w = s->windows; w; w = w->next)
4056     {
4057 	if (w->desktop == 0xffffffff)
4058 	    continue;
4059 
4060 	if (w->desktop >= nDesktop)
4061 	    setDesktopForWindow (w, nDesktop - 1);
4062     }
4063 
4064     s->nDesktop = nDesktop;
4065 
4066     setDesktopHints (s);
4067 }
4068 
4069 void
setCurrentDesktop(CompScreen * s,unsigned int desktop)4070 setCurrentDesktop (CompScreen   *s,
4071 		   unsigned int desktop)
4072 {
4073     unsigned long data;
4074     CompWindow    *w;
4075 
4076     if (desktop >= s->nDesktop)
4077 	return;
4078 
4079     if (desktop == s->currentDesktop)
4080 	return;
4081 
4082     s->currentDesktop = desktop;
4083 
4084     for (w = s->windows; w; w = w->next)
4085     {
4086 	if (w->desktop == 0xffffffff)
4087 	    continue;
4088 
4089 	if (w->desktop == desktop)
4090 	    showWindow (w);
4091 	else
4092 	    hideWindow (w);
4093     }
4094 
4095     data = desktop;
4096 
4097     XChangeProperty (s->display->display, s->root,
4098 		     s->display->currentDesktopAtom,
4099 		     XA_CARDINAL, 32, PropModeReplace,
4100 		     (unsigned char *) &data, 1);
4101 }
4102 
4103 void
getWorkareaForOutput(CompScreen * s,int output,XRectangle * area)4104 getWorkareaForOutput (CompScreen *s,
4105 		      int	 output,
4106 		      XRectangle *area)
4107 {
4108     *area = s->outputDev[output].workArea;
4109 }
4110 
4111 void
setDefaultViewport(CompScreen * s)4112 setDefaultViewport (CompScreen *s)
4113 {
4114     s->lastViewport.x	   = s->outputDev->region.extents.x1;
4115     s->lastViewport.y	   = s->height - s->outputDev->region.extents.y2;
4116     s->lastViewport.width  = s->outputDev->width;
4117     s->lastViewport.height = s->outputDev->height;
4118 
4119     glViewport (s->lastViewport.x,
4120 		s->lastViewport.y,
4121 		s->lastViewport.width,
4122 		s->lastViewport.height);
4123 }
4124 
4125 void
outputChangeNotify(CompScreen * s)4126 outputChangeNotify (CompScreen *s)
4127 {
4128 }
4129 
4130 void
clearScreenOutput(CompScreen * s,CompOutput * output,unsigned int mask)4131 clearScreenOutput (CompScreen	*s,
4132 		   CompOutput	*output,
4133 		   unsigned int mask)
4134 {
4135     BoxPtr pBox = &output->region.extents;
4136 
4137     if (pBox->x1 != 0	     ||
4138 	pBox->y1 != 0	     ||
4139 	pBox->x2 != s->width ||
4140 	pBox->y2 != s->height)
4141     {
4142 	glPushAttrib (GL_SCISSOR_BIT);
4143 
4144 	glEnable (GL_SCISSOR_TEST);
4145 	glScissor (pBox->x1,
4146 		   s->height - pBox->y2,
4147 		   pBox->x2 - pBox->x1,
4148 		   pBox->y2 - pBox->y1);
4149 	glClear (mask);
4150 
4151 	glPopAttrib ();
4152     }
4153     else
4154     {
4155 	glClear (mask);
4156     }
4157 }
4158 
4159 /* Returns default viewport for some window geometry. If the window spans
4160    more than one viewport the most appropriate viewport is returned. How the
4161    most appropriate viewport is computed can be made optional if necessary. It
4162    is currently computed as the viewport where the center of the window is
4163    located. */
4164 void
viewportForGeometry(CompScreen * s,int x,int y,int width,int height,int borderWidth,int * viewportX,int * viewportY)4165 viewportForGeometry (CompScreen *s,
4166 		     int	x,
4167 		     int	y,
4168 		     int	width,
4169 		     int	height,
4170 		     int	borderWidth,
4171 		     int	*viewportX,
4172 		     int	*viewportY)
4173 {
4174     int	centerX;
4175     int	centerY;
4176 
4177     width  += borderWidth * 2;
4178     height += borderWidth * 2;
4179 
4180     if (viewportX)
4181     {
4182 	centerX = x + (width >> 1);
4183 	if (centerX < 0)
4184 	    *viewportX = s->x + ((centerX / s->width) - 1) % s->hsize;
4185 	else
4186 	    *viewportX = s->x + (centerX / s->width) % s->hsize;
4187     }
4188 
4189     if (viewportY)
4190     {
4191 	centerY = y + (height >> 1);
4192 	if (centerY < 0)
4193 	    *viewportY = s->y + ((centerY / s->height) - 1) % s->vsize;
4194 	else
4195 	    *viewportY = s->y + (centerY / s->height) % s->vsize;
4196     }
4197 }
4198 
4199 static int
rectangleOverlapArea(BOX * rect1,BOX * rect2)4200 rectangleOverlapArea (BOX *rect1,
4201 		      BOX *rect2)
4202 {
4203     int left, right, top, bottom;
4204 
4205     /* extents of overlapping rectangle */
4206     left = MAX (rect1->x1, rect2->x1);
4207     right = MIN (rect1->x2, rect2->x2);
4208     top = MAX (rect1->y1, rect2->y1);
4209     bottom = MIN (rect1->y2, rect2->y2);
4210 
4211     if (left > right || top > bottom)
4212     {
4213 	/* no overlap */
4214 	return 0;
4215     }
4216 
4217     return (right - left) * (bottom - top);
4218 }
4219 
4220 int
outputDeviceForGeometry(CompScreen * s,int x,int y,int width,int height,int borderWidth)4221 outputDeviceForGeometry (CompScreen *s,
4222 			 int	    x,
4223 			 int	    y,
4224 			 int	    width,
4225 			 int	    height,
4226 			 int	    borderWidth)
4227 {
4228     int overlapAreas[s->nOutputDev];
4229     int i, highest, seen, highestScore;
4230     int strategy;
4231     BOX geomRect;
4232 
4233     if (s->nOutputDev == 1)
4234 	return 0;
4235 
4236     strategy = s->opt[COMP_SCREEN_OPTION_OVERLAPPING_OUTPUTS].value.i;
4237 
4238     if (strategy == OUTPUT_OVERLAP_MODE_SMART)
4239     {
4240 	int centerX, centerY;
4241 
4242 	/* for smart mode, calculate the overlap of the whole rectangle
4243 	   with the output device rectangle */
4244 	geomRect.x2 = width + 2 * borderWidth;
4245 	geomRect.y2 = height + 2 * borderWidth;
4246 
4247 	geomRect.x1 = x % s->width;
4248 	centerX = geomRect.x1 + (geomRect.x2 / 2);
4249 	if (centerX < 0)
4250 	    geomRect.x1 += s->width;
4251 	else if (centerX > s->width)
4252 	    geomRect.x1 -= s->width;
4253 
4254 	geomRect.y1 = y % s->height;
4255 	centerY = geomRect.y1 + (geomRect.y2 / 2);
4256 	if (centerY < 0)
4257 	    geomRect.y1 += s->height;
4258 	else if (centerY > s->height)
4259 	    geomRect.y1 -= s->height;
4260 
4261 	geomRect.x2 += geomRect.x1;
4262 	geomRect.y2 += geomRect.y1;
4263     }
4264     else
4265     {
4266 	/* for biggest/smallest modes, only use the window center to determine
4267 	   the correct output device */
4268 	geomRect.x1 = (x + (width / 2) + borderWidth) % s->width;
4269 	if (geomRect.x1 < 0)
4270 	    geomRect.x1 += s->width;
4271 	geomRect.y1 = (y + (height / 2) + borderWidth) % s->height;
4272 	if (geomRect.y1 < 0)
4273 	    geomRect.y1 += s->height;
4274 
4275 	geomRect.x2 = geomRect.x1 + 1;
4276 	geomRect.y2 = geomRect.y1 + 1;
4277     }
4278 
4279     /* get amount of overlap on all output devices */
4280     for (i = 0; i < s->nOutputDev; i++)
4281 	overlapAreas[i] = rectangleOverlapArea (&s->outputDev[i].region.extents,
4282 						&geomRect);
4283 
4284     /* find output with largest overlap */
4285     for (i = 0, highest = 0, highestScore = 0; i < s->nOutputDev; i++)
4286 	if (overlapAreas[i] > highestScore)
4287 	{
4288 	    highest = i;
4289 	    highestScore = overlapAreas[i];
4290 	}
4291 
4292     /* look if the highest score is unique */
4293     for (i = 0, seen = 0; i < s->nOutputDev; i++)
4294 	if (overlapAreas[i] == highestScore)
4295 	    seen++;
4296 
4297     if (seen > 1)
4298     {
4299 	/* it's not unique, select one output of the matching ones and use the
4300 	   user preferred strategy for that */
4301 	unsigned int currentSize, bestOutputSize;
4302 	Bool         searchLargest;
4303 
4304 	searchLargest = (strategy != OUTPUT_OVERLAP_MODE_PREFER_SMALLER);
4305 	if (searchLargest)
4306 	    bestOutputSize = 0;
4307 	else
4308 	    bestOutputSize = UINT_MAX;
4309 
4310 	for (i = 0, highest = 0; i < s->nOutputDev; i++)
4311 	    if (overlapAreas[i] == highestScore)
4312 	    {
4313 		BOX  *box = &s->outputDev[i].region.extents;
4314 		Bool bestFit;
4315 
4316 		currentSize = (box->x2 - box->x1) * (box->y2 - box->y1);
4317 
4318 		if (searchLargest)
4319 		    bestFit = (currentSize > bestOutputSize);
4320 		else
4321 		    bestFit = (currentSize < bestOutputSize);
4322 
4323 		if (bestFit)
4324 		{
4325 		    highest = i;
4326 		    bestOutputSize = currentSize;
4327 		}
4328 	    }
4329     }
4330 
4331     return highest;
4332 }
4333 
4334 Bool
updateDefaultIcon(CompScreen * screen)4335 updateDefaultIcon (CompScreen *screen)
4336 {
4337     CompIcon *icon;
4338     char     *file = screen->opt[COMP_SCREEN_OPTION_DEFAULT_ICON].value.s;
4339     void     *data;
4340     int      width, height;
4341 
4342     if (screen->defaultIcon)
4343     {
4344 	finiTexture (screen, &screen->defaultIcon->texture);
4345 	free (screen->defaultIcon);
4346 	screen->defaultIcon = NULL;
4347     }
4348 
4349     if (!readImageFromFile (screen->display, file, &width, &height, &data))
4350 	return FALSE;
4351 
4352     icon = malloc (sizeof (CompIcon) + width * height * sizeof (CARD32));
4353     if (!icon)
4354     {
4355 	free (data);
4356 	return FALSE;
4357     }
4358 
4359     initTexture (screen, &icon->texture);
4360 
4361     icon->width  = width;
4362     icon->height = height;
4363 
4364     memcpy (icon + 1, data, + width * height * sizeof (CARD32));
4365 
4366     screen->defaultIcon = icon;
4367 
4368     free (data);
4369 
4370     return TRUE;
4371 }
4372 
4373 CompCursor *
findCursorAtScreen(CompScreen * screen)4374 findCursorAtScreen (CompScreen *screen)
4375 {
4376     return screen->cursors;
4377 }
4378 
4379 CompCursorImage *
findCursorImageAtScreen(CompScreen * screen,unsigned long serial)4380 findCursorImageAtScreen (CompScreen    *screen,
4381 			 unsigned long serial)
4382 {
4383     CompCursorImage *image;
4384 
4385     for (image = screen->cursorImages; image; image = image->next)
4386 	if (image->serial == serial)
4387 	    return image;
4388 
4389     return NULL;
4390 }
4391 
4392 void
setCurrentActiveWindowHistory(CompScreen * s,int x,int y)4393 setCurrentActiveWindowHistory (CompScreen *s,
4394 			       int	  x,
4395 			       int	  y)
4396 {
4397     int	i, min = 0;
4398 
4399     for (i = 0; i < ACTIVE_WINDOW_HISTORY_NUM; i++)
4400     {
4401 	if (s->history[i].x == x && s->history[i].y == y)
4402 	{
4403 	    s->currentHistory = i;
4404 	    return;
4405 	}
4406     }
4407 
4408     for (i = 1; i < ACTIVE_WINDOW_HISTORY_NUM; i++)
4409 	if (s->history[i].activeNum < s->history[min].activeNum)
4410 	    min = i;
4411 
4412     s->currentHistory = min;
4413 
4414     s->history[min].activeNum = s->activeNum;
4415     s->history[min].x	      = x;
4416     s->history[min].y	      = y;
4417 
4418     memset (s->history[min].id, 0, sizeof (s->history[min].id));
4419 }
4420 
4421 void
addToCurrentActiveWindowHistory(CompScreen * s,Window id)4422 addToCurrentActiveWindowHistory (CompScreen *s,
4423 				 Window	    id)
4424 {
4425     CompActiveWindowHistory *history = &s->history[s->currentHistory];
4426     Window		    tmp, next = id;
4427     int			    i;
4428 
4429     /* walk and move history */
4430     for (i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
4431     {
4432 	tmp = history->id[i];
4433 	history->id[i] = next;
4434 	next = tmp;
4435 
4436 	/* we're done when we find an old instance or an empty slot */
4437 	if (tmp == id || tmp == None)
4438 	    break;
4439     }
4440 
4441     history->activeNum = s->activeNum;
4442 }
4443 
4444 void
setWindowPaintOffset(CompScreen * s,int x,int y)4445 setWindowPaintOffset (CompScreen *s,
4446 		      int        x,
4447 		      int        y)
4448 {
4449     s->windowOffsetX = x;
4450     s->windowOffsetY = y;
4451 }
4452