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