1 /* $Id$
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., Inc., 51 Franklin Street, Fifth Floor, Boston,
16 MA 02110-1301, USA.
17
18
19 xcompmgr - (c) 2003 Keith Packard
20 metacity - (c) 2003, 2004 Red Hat, Inc.
21 xfwm4 - (c) 2005-2020 Olivier Fourdan
22
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/Xatom.h>
32 #include <X11/extensions/shape.h>
33
34 #include <glib.h>
35 #include <math.h>
36 #include <string.h>
37 #include <libxfce4util/libxfce4util.h>
38
39 #ifdef HAVE_EPOXY
40 #include <epoxy/gl.h>
41 #include <epoxy/glx.h>
42 #ifdef HAVE_XSYNC_EXTENSION
43 #include <X11/extensions/sync.h>
44 #endif /* HAVE_XSYNC_EXTENSION */
45 #endif /* HAVE_EPOXY */
46
47 #ifdef HAVE_PRESENT_EXTENSION
48 #ifndef PRESENT_FUTURE_VERSION
49 #define PRESENT_FUTURE_VERSION 0
50 #endif /* PRESENT_FUTURE_VERSION */
51 #include <X11/extensions/Xpresent.h>
52 #endif /* HAVE_PRESENT_EXTENSION */
53
54 #include "display.h"
55 #include "screen.h"
56 #include "client.h"
57 #include "frame.h"
58 #include "hints.h"
59 #include "compositor.h"
60
61 #ifdef HAVE_COMPOSITOR
62 #include "common/xfwm-common.h"
63
64 #include <X11/extensions/Xcomposite.h>
65 #include <X11/extensions/Xdamage.h>
66 #include <X11/extensions/Xrender.h>
67
68 #ifndef SHADOW_RADIUS
69 #define SHADOW_RADIUS 12
70 #endif /* SHADOW_RADIUS */
71
72 #ifndef SHADOW_OFFSET_X
73 #define SHADOW_OFFSET_X (-3 * SHADOW_RADIUS / 2)
74 #endif /* SHADOW_OFFSET_X */
75
76 #ifndef SHADOW_OFFSET_Y
77 #define SHADOW_OFFSET_Y (-3 * SHADOW_RADIUS / 2)
78 #endif /* SHADOW_OFFSET_Y */
79
80 /* Some convenient macros */
81 #define WIN_HAS_CLIENT(cw) (cw->c)
82 #define WIN_HAS_FRAME(cw) (WIN_HAS_CLIENT(cw) && CLIENT_HAS_FRAME(cw->c))
83 #define WIN_NO_SHADOW(cw) ((cw->c) && \
84 (FLAG_TEST (cw->c->flags, CLIENT_FLAG_FULLSCREEN | CLIENT_FLAG_BELOW) || \
85 (cw->c->type & WINDOW_DESKTOP)))
86 #define WIN_IS_DOCK(cw) (WIN_HAS_CLIENT(cw) && (cw->c->type & WINDOW_DOCK))
87 #define WIN_IS_OVERRIDE(cw) (cw->attr.override_redirect)
88 #define WIN_IS_ARGB(cw) (cw->argb)
89 #define WIN_IS_OPAQUE(cw) ((cw->opacity == NET_WM_OPAQUE) && !WIN_IS_ARGB(cw))
90 #define WIN_IS_NATIVE_OPAQUE(cw) ((cw->native_opacity) && !WIN_IS_ARGB(cw))
91 #define WIN_IS_FULLSCREEN(cw) ((cw->attr.x <= 0) && \
92 (cw->attr.y <= 0) && \
93 (cw->attr.width + 2 * cw->attr.border_width >= cw->screen_info->width) && \
94 (cw->attr.height + 2 * cw->attr.border_width >= cw->screen_info->height))
95 #define WIN_IS_SHAPED(cw) ((WIN_HAS_CLIENT(cw) && FLAG_TEST (cw->c->flags, CLIENT_FLAG_HAS_SHAPE)) || \
96 (WIN_IS_OVERRIDE(cw) && (cw->shaped)))
97 #define WIN_IS_MAXIMIZED(cw) (WIN_HAS_CLIENT(cw) && FLAG_TEST_ALL (cw->c->flags, CLIENT_FLAG_MAXIMIZED))
98 #define WIN_IS_VIEWABLE(cw) (cw->viewable)
99 #define WIN_HAS_DAMAGE(cw) (cw->damage)
100 #define WIN_IS_VISIBLE(cw) (WIN_IS_VIEWABLE(cw) && WIN_HAS_DAMAGE(cw))
101 #define WIN_IS_DAMAGED(cw) (cw->damaged)
102 #define WIN_IS_REDIRECTED(cw) (cw->redirected)
103 #define WIN_IS_SHADED(cw) (WIN_HAS_CLIENT(cw) && FLAG_TEST (cw->c->flags, CLIENT_FLAG_SHADED))
104
105 #ifndef TIMEOUT_REPAINT_PRIORITY
106 #define TIMEOUT_REPAINT_PRIORITY 1
107 #endif /* TIMEOUT_REPAINT_PRIORITY */
108
109 #ifndef TIMEOUT_REPAINT_MS
110 #define TIMEOUT_REPAINT_MS 1
111 #endif /* TIMEOUT_REPAINT_MS */
112
113 #ifndef MONITOR_ROOT_PIXMAP
114 #define MONITOR_ROOT_PIXMAP 1
115 #endif /* MONITOR_ROOT_PIXMAP */
116
117 #ifndef MONITOR_ROOT_PIXMAP
118 #define MONITOR_ROOT_PIXMAP 1
119 #endif /* MONITOR_ROOT_PIXMAP */
120
121 typedef struct _CWindow CWindow;
122 struct _CWindow
123 {
124 ScreenInfo *screen_info;
125 Client *c;
126 Window id;
127 XWindowAttributes attr;
128
129 gboolean damaged;
130 gboolean viewable;
131 gboolean shaped;
132 gboolean redirected;
133 gboolean fulloverlay;
134 gboolean argb;
135 gboolean skipped;
136 gboolean native_opacity;
137 gboolean opacity_locked;
138
139 Damage damage;
140 #if HAVE_NAME_WINDOW_PIXMAP
141 Pixmap name_window_pixmap;
142 #endif /* HAVE_NAME_WINDOW_PIXMAP */
143 Picture picture;
144 Picture saved_picture;
145 Picture shadow;
146 Picture alphaPict;
147 Picture shadowPict;
148 Picture alphaBorderPict;
149
150 XserverRegion borderSize;
151 XserverRegion clientSize;
152 XserverRegion borderClip;
153 XserverRegion extents;
154 XserverRegion opaque_region;
155
156 gint shadow_dx;
157 gint shadow_dy;
158 gint shadow_width;
159 gint shadow_height;
160
161 guint32 opacity;
162 guint32 bypass_compositor;
163 };
164
165 static CWindow*
find_cwindow_in_screen(ScreenInfo * screen_info,Window id)166 find_cwindow_in_screen (ScreenInfo *screen_info, Window id)
167 {
168 g_return_val_if_fail (id != None, NULL);
169 g_return_val_if_fail (screen_info != NULL, NULL);
170 TRACE ("window 0x%lx", id);
171
172 return g_hash_table_lookup(screen_info->cwindow_hash, (gpointer) id);
173 }
174
175 static CWindow*
find_cwindow_in_display(DisplayInfo * display_info,Window id)176 find_cwindow_in_display (DisplayInfo *display_info, Window id)
177 {
178 GSList *list;
179
180 g_return_val_if_fail (id != None, NULL);
181 g_return_val_if_fail (display_info != NULL, NULL);
182 TRACE ("window 0x%lx", id);
183
184 for (list = display_info->screens; list; list = g_slist_next (list))
185 {
186 ScreenInfo *screen_info = (ScreenInfo *) list->data;
187 CWindow *cw;
188
189 if (!compositorIsActive (screen_info))
190 {
191 continue;
192 }
193
194 cw = find_cwindow_in_screen (screen_info, id);
195 if (cw)
196 {
197 return (cw);
198 }
199 }
200 return NULL;
201 }
202
203 static gboolean
is_output(DisplayInfo * display_info,Window id)204 is_output (DisplayInfo *display_info, Window id)
205 {
206 GSList *list;
207
208 g_return_val_if_fail (id != None, FALSE);
209 g_return_val_if_fail (display_info != NULL, FALSE);
210 TRACE ("window 0x%lx", id);
211
212 for (list = display_info->screens; list; list = g_slist_next (list))
213 {
214 ScreenInfo *screen_info = (ScreenInfo *) list->data;
215 #if HAVE_OVERLAYS
216 if (id == screen_info->output || id == screen_info->overlay)
217 #else
218 if (id == screen_info->output)
219 #endif
220 {
221 return TRUE;
222 }
223 }
224 return FALSE;
225 }
226
227 static gboolean
is_shaped(DisplayInfo * display_info,Window id)228 is_shaped (DisplayInfo *display_info, Window id)
229 {
230 int xws, yws, xbs, ybs;
231 unsigned wws, hws, wbs, hbs;
232 int boundingShaped, clipShaped;
233 int result;
234
235 g_return_val_if_fail (display_info != NULL, FALSE);
236
237 if (display_info->have_shape)
238 {
239 myDisplayErrorTrapPush (display_info);
240 XShapeQueryExtents (display_info->dpy, id, &boundingShaped, &xws, &yws, &wws,
241 &hws, &clipShaped, &xbs, &ybs, &wbs, &hbs);
242 result = myDisplayErrorTrapPop (display_info);
243
244 return ((result == Success) && (boundingShaped != 0));
245 }
246 return FALSE;
247 }
248
249 static gboolean
is_fullscreen(CWindow * cw)250 is_fullscreen (CWindow *cw)
251 {
252 GdkRectangle rect;
253
254 /* First, check the good old way, the window is larger than the screen size */
255 if (WIN_IS_FULLSCREEN(cw))
256 {
257 return TRUE;
258 }
259
260 /* Next check against the monitors which compose the entire screen */
261 myScreenFindMonitorAtPoint (cw->screen_info,
262 cw->attr.x + (cw->attr.width + 2 * cw->attr.border_width) / 2,
263 cw->attr.y + (cw->attr.height + 2 * cw->attr.border_width) / 2,
264 &rect);
265
266 return ((cw->attr.x == rect.x) &&
267 (cw->attr.y == rect.y) &&
268 (cw->attr.width + 2 * cw->attr.border_width == rect.width) &&
269 (cw->attr.height + 2 * cw->attr.border_width == rect.height));
270 }
271
272 static gboolean
is_on_compositor(CWindow * cw)273 is_on_compositor (CWindow *cw)
274 {
275 return (cw && compositorIsActive (cw->screen_info));
276 }
277
278 static gdouble
gaussian(gdouble r,gdouble x,gdouble y)279 gaussian (gdouble r, gdouble x, gdouble y)
280 {
281 return ((1 / (sqrt (2 * G_PI * r))) *
282 exp ((- (x * x + y * y)) / (2 * r * r)));
283 }
284
285 static gaussian_conv *
make_gaussian_map(gdouble r)286 make_gaussian_map (gdouble r)
287 {
288 gaussian_conv *c;
289 gint size, center;
290 gint x, y;
291 gdouble t;
292 gdouble g;
293
294 TRACE ("entering");
295
296 size = ((gint) ceil ((r * 3)) + 1) & ~1;
297 center = size / 2;
298 c = g_malloc0 (sizeof (gaussian_conv) + size * size * sizeof (gdouble));
299 c->size = size;
300 c->data = (gdouble *) (c + 1);
301 t = 0.0;
302
303 for (y = 0; y < size; y++)
304 {
305 for (x = 0; x < size; x++)
306 {
307 g = gaussian (r, (gdouble) (x - center), (gdouble) (y - center));
308 t += g;
309 c->data[y * size + x] = g;
310 }
311 }
312
313 for (y = 0; y < size; y++)
314 {
315 for (x = 0; x < size; x++)
316 {
317 c->data[y*size + x] /= t;
318 }
319 }
320
321 return c;
322 }
323
324 /*
325 * A picture will help
326 *
327 * -center 0 width width+center
328 * -center +-----+-------------------+-----+
329 * | | | |
330 * | | | |
331 * 0 +-----+-------------------+-----+
332 * | | | |
333 * | | | |
334 * | | | |
335 * height +-----+-------------------+-----+
336 * | | | |
337 * height+ | | | |
338 * center +-----+-------------------+-----+
339 */
340
341 static guchar
sum_gaussian(gaussian_conv * map,gdouble opacity,gint x,gint y,gint width,gint height)342 sum_gaussian (gaussian_conv *map, gdouble opacity, gint x, gint y, gint width, gint height)
343 {
344 gdouble *g_data, *g_line;
345 gdouble v;
346 gint fx, fy;
347 gint fx_start, fx_end;
348 gint fy_start, fy_end;
349 gint g_size, center;
350
351 g_return_val_if_fail (map != NULL, (guchar) 255.0);
352 TRACE ("(%i,%i) [%i×%i]", x, y, width, height);
353
354 g_line = map->data;
355 g_size = map->size;
356 center = g_size / 2;
357 fx_start = center - x;
358 if (fx_start < 0)
359 {
360 fx_start = 0;
361 }
362 fx_end = width + center - x;
363 if (fx_end > g_size)
364 {
365 fx_end = g_size;
366 }
367
368 fy_start = center - y;
369 if (fy_start < 0)
370 {
371 fy_start = 0;
372 }
373 fy_end = height + center - y;
374 if (fy_end > g_size)
375 {
376 fy_end = g_size;
377 }
378 g_line = g_line + fy_start * g_size + fx_start;
379
380 v = 0;
381 for (fy = fy_start; fy < fy_end; fy++)
382 {
383 g_data = g_line;
384 g_line += g_size;
385
386 for (fx = fx_start; fx < fx_end; fx++)
387 {
388 v += *g_data++;
389 }
390 }
391 if (v > 1)
392 {
393 v = 1;
394 }
395
396 return ((guchar) (v * opacity * 255.0));
397 }
398
399 /* precompute shadow corners and sides to save time for large windows */
400 static void
presum_gaussian(ScreenInfo * screen_info)401 presum_gaussian (ScreenInfo *screen_info)
402 {
403 gint center;
404 gint opacity, x, y;
405 gaussian_conv * map;
406
407 g_return_if_fail (screen_info != NULL);
408 g_return_if_fail (screen_info->gaussianMap != NULL);
409 TRACE ("entering");
410
411 map = screen_info->gaussianMap;
412 screen_info->gaussianSize = map->size;
413 center = map->size / 2;
414
415 if (screen_info->shadowCorner)
416 {
417 g_free (screen_info->shadowCorner);
418 }
419 if (screen_info->shadowTop)
420 {
421 g_free (screen_info->shadowTop);
422 }
423
424 screen_info->shadowCorner = (guchar *) (g_malloc0 ((screen_info->gaussianSize + 1)
425 * (screen_info->gaussianSize + 1) * 26));
426 screen_info->shadowTop = (guchar *) (g_malloc0 ((screen_info->gaussianSize + 1) * 26));
427
428 for (x = 0; x <= screen_info->gaussianSize; x++)
429 {
430 screen_info->shadowTop[25 * (screen_info->gaussianSize + 1) + x] =
431 sum_gaussian (map, 1, x - center, center,
432 screen_info->gaussianSize * 2,
433 screen_info->gaussianSize * 2);
434
435 for(opacity = 0; opacity < 25; opacity++)
436 {
437 screen_info->shadowTop[opacity * (screen_info->gaussianSize + 1) + x] =
438 screen_info->shadowTop[25 * (screen_info->gaussianSize + 1) + x] * opacity / 25;
439 }
440
441 for(y = 0; y <= x; y++)
442 {
443 screen_info->shadowCorner[25 * (screen_info->gaussianSize + 1)
444 * (screen_info->gaussianSize + 1)
445 + y * (screen_info->gaussianSize + 1) + x]
446 = sum_gaussian (map, 1, x - center,
447 y - center,
448 screen_info->gaussianSize * 2,
449 screen_info->gaussianSize * 2);
450 screen_info->shadowCorner[25 * (screen_info->gaussianSize + 1)
451 * (screen_info->gaussianSize + 1)
452 + x * (screen_info->gaussianSize + 1) + y]
453 = screen_info->shadowCorner[25 * (screen_info->gaussianSize + 1)
454 * (screen_info->gaussianSize + 1)
455 + y * (screen_info->gaussianSize + 1) + x];
456
457 for(opacity = 0; opacity < 25; opacity++)
458 {
459 screen_info->shadowCorner[opacity * (screen_info->gaussianSize + 1)
460 * (screen_info->gaussianSize + 1)
461 + y * (screen_info->gaussianSize + 1) + x]
462 = screen_info->shadowCorner[opacity * (screen_info->gaussianSize + 1)
463 * (screen_info->gaussianSize + 1)
464 + x * (screen_info->gaussianSize + 1) + y]
465 = screen_info->shadowCorner[25 * (screen_info->gaussianSize + 1)
466 * (screen_info->gaussianSize + 1)
467 + y * (screen_info->gaussianSize + 1) + x] * opacity / 25;
468 }
469 }
470 }
471 }
472
473 static XImage *
make_shadow(ScreenInfo * screen_info,gdouble opacity,gint width,gint height)474 make_shadow (ScreenInfo *screen_info, gdouble opacity, gint width, gint height)
475 {
476 DisplayInfo *display_info;
477 XImage *ximage;
478 guchar *data;
479 guchar d;
480 gint gaussianSize;
481 gint ylimit, xlimit;
482 gint swidth;
483 gint sheight;
484 gint center;
485 gint x, y;
486 gint x_diff;
487 gint opacity_int;
488 gint x_swidth;
489 gint y_swidth;
490
491 g_return_val_if_fail (screen_info != NULL, NULL);
492 TRACE ("entering");
493
494 display_info = screen_info->display_info;
495 gaussianSize = screen_info->gaussianMap->size;
496 swidth = width + gaussianSize - screen_info->params->shadow_delta_width - screen_info->params->shadow_delta_x;
497 sheight = height + gaussianSize - screen_info->params->shadow_delta_height - screen_info->params->shadow_delta_y;
498 center = gaussianSize / 2;
499 opacity_int = (gint) (opacity * 25);
500
501 if ((swidth < 1) || (sheight < 1))
502 {
503 return NULL;
504 }
505
506 data = g_malloc0 (swidth * sheight * sizeof (guchar));
507
508 ximage = XCreateImage (display_info->dpy,
509 DefaultVisual(display_info->dpy, screen_info->screen),
510 8, ZPixmap, 0, (char *) data,
511 swidth, sheight, 8, swidth * sizeof (guchar));
512 if (ximage == NULL)
513 {
514 g_free (data);
515 g_warning ("(ximage != NULL) failed");
516 return NULL;
517 }
518
519 /*
520 * Build the gaussian in sections
521 */
522
523 if (screen_info->gaussianSize > 0)
524 {
525 d = screen_info->shadowTop[opacity_int * (screen_info->gaussianSize + 1) + screen_info->gaussianSize];
526 }
527 else
528 {
529 d = sum_gaussian (screen_info->gaussianMap, opacity, center, center, width, height);
530 }
531 memset(data, d, sheight * swidth);
532
533 /*
534 * corners
535 */
536
537 ylimit = gaussianSize;
538 if (ylimit > sheight / 2)
539 {
540 ylimit = (sheight + 1) / 2;
541 }
542 xlimit = gaussianSize;
543 if (xlimit > swidth / 2)
544 {
545 xlimit = (swidth + 1) / 2;
546 }
547 for (y = 0; y < ylimit; y++)
548 {
549 for (x = 0; x < xlimit; x++)
550 {
551 if ((xlimit == screen_info->gaussianSize) && (ylimit == screen_info->gaussianSize))
552 {
553 d = screen_info->shadowCorner[opacity_int * (screen_info->gaussianSize + 1)
554 * (screen_info->gaussianSize + 1)
555 + y * (screen_info->gaussianSize + 1) + x];
556 }
557 else
558 {
559 d = sum_gaussian (screen_info->gaussianMap, opacity,
560 x - center, y - center, width, height);
561 }
562
563 data[y * swidth + x] = d;
564 data[(sheight - y - 1) * swidth + x] = d;
565 data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d;
566 data[y * swidth + (swidth - x - 1)] = d;
567 }
568 }
569
570 /*
571 * top/bottom
572 */
573
574 x_diff = swidth - (gaussianSize * 2);
575 if (x_diff > 0 && ylimit > 0)
576 {
577 for (y = 0; y < ylimit; y++)
578 {
579 if (ylimit == screen_info->gaussianSize)
580 {
581 d = screen_info->shadowTop[opacity_int * (screen_info->gaussianSize + 1) + y];
582 }
583 else
584 {
585 d = sum_gaussian (screen_info->gaussianMap, opacity, center, y - center, width, height);
586 }
587 memset (&data[y * swidth + gaussianSize], d, x_diff);
588 memset (&data[(sheight - y - 1) * swidth + gaussianSize], d, x_diff);
589 }
590 }
591
592 /*
593 * sides
594 */
595
596 for (x = 0; x < xlimit; x++)
597 {
598 if (xlimit == screen_info->gaussianSize)
599 {
600 d = screen_info->shadowTop[opacity_int * (screen_info->gaussianSize + 1) + x];
601 }
602 else
603 {
604 d = sum_gaussian (screen_info->gaussianMap, opacity, x - center, center, width, height);
605 }
606 x_swidth = swidth - x - 1;
607 for (y = gaussianSize; y < sheight - gaussianSize; y++)
608 {
609 y_swidth = y * swidth;
610 data[y_swidth + x] = d;
611 data[y_swidth + x_swidth] = d;
612 }
613 }
614
615 return ximage;
616 }
617
618 static Picture
shadow_picture(ScreenInfo * screen_info,gdouble opacity,gint width,gint height,gint * wp,gint * hp)619 shadow_picture (ScreenInfo *screen_info, gdouble opacity,
620 gint width, gint height, gint *wp, gint *hp)
621 {
622 DisplayInfo *display_info;
623 XImage *shadowImage;
624 Pixmap shadowPixmap;
625 Picture shadowPicture;
626 XRenderPictFormat *render_format;
627 GC gc;
628
629 g_return_val_if_fail (screen_info != NULL, None);
630 TRACE ("entering");
631
632 display_info = screen_info->display_info;
633 render_format = XRenderFindStandardFormat (display_info->dpy, PictStandardA8);
634 g_return_val_if_fail (render_format != NULL, None);
635
636 shadowImage = make_shadow (screen_info, opacity, width, height);
637 if (shadowImage == NULL)
638 {
639 *wp = *hp = 0;
640 g_warning ("(shadowImage != NULL) failed");
641 return (None);
642 }
643
644 shadowPixmap = XCreatePixmap (display_info->dpy, screen_info->output,
645 shadowImage->width, shadowImage->height, 8);
646 if (shadowPixmap == None)
647 {
648 XDestroyImage (shadowImage);
649 g_warning ("(shadowPixmap != None) failed");
650 return None;
651 }
652
653 shadowPicture = XRenderCreatePicture (display_info->dpy,
654 shadowPixmap, render_format, 0, NULL);
655 if (shadowPicture == None)
656 {
657 XDestroyImage (shadowImage);
658 XFreePixmap (display_info->dpy, shadowPixmap);
659 g_warning ("(shadowPicture != None) failed");
660 return None;
661 }
662
663 gc = XCreateGC (display_info->dpy, shadowPixmap, 0, NULL);
664 XPutImage (display_info->dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0,
665 shadowImage->width, shadowImage->height);
666
667 *wp = shadowImage->width;
668 *hp = shadowImage->height;
669
670 XFreeGC (display_info->dpy, gc);
671 XDestroyImage (shadowImage);
672 XFreePixmap (display_info->dpy, shadowPixmap);
673
674 return shadowPicture;
675 }
676
677 static Picture
solid_picture(ScreenInfo * screen_info,gboolean argb,gdouble a,gdouble r,gdouble g,gdouble b)678 solid_picture (ScreenInfo *screen_info, gboolean argb,
679 gdouble a, gdouble r, gdouble g, gdouble b)
680 {
681 DisplayInfo *display_info;
682 Pixmap pixmap;
683 Picture picture;
684 XRenderPictureAttributes pa;
685 XRenderPictFormat *render_format;
686 XRenderColor c;
687
688 g_return_val_if_fail (screen_info, None);
689 TRACE ("entering");
690
691 display_info = screen_info->display_info;
692 render_format = XRenderFindStandardFormat (display_info->dpy,
693 argb ? PictStandardARGB32 : PictStandardA8);
694 g_return_val_if_fail (render_format != NULL , None);
695
696 pixmap = XCreatePixmap (display_info->dpy,
697 screen_info->output, 1, 1, argb ? 32 : 8);
698 g_return_val_if_fail (pixmap != None, None);
699
700 pa.repeat = TRUE;
701 picture = XRenderCreatePicture (display_info->dpy, pixmap,
702 render_format, CPRepeat, &pa);
703 if (picture == None)
704 {
705 XFreePixmap (display_info->dpy, pixmap);
706 g_warning ("(picture != None) failed");
707 return None;
708 }
709
710 c.alpha = a * 0xffff;
711 c.red = r * 0xffff;
712 c.green = g * 0xffff;
713 c.blue = b * 0xffff;
714
715 XRenderFillRectangle (display_info->dpy, PictOpSrc,
716 picture, &c, 0, 0, 1, 1);
717 XFreePixmap (display_info->dpy, pixmap);
718
719 return picture;
720 }
721
722 static void
translate_to_client_region(CWindow * cw,XserverRegion region)723 translate_to_client_region (CWindow *cw, XserverRegion region)
724 {
725 DisplayInfo *display_info;
726 ScreenInfo *screen_info;
727 int x, y;
728
729 g_return_if_fail (cw != NULL);
730 TRACE ("window 0x%lx", cw->id);
731
732 screen_info = cw->screen_info;
733 display_info = screen_info->display_info;
734
735 if (WIN_HAS_FRAME(cw))
736 {
737 x = frameX (cw->c) + frameLeft (cw->c);
738 y = frameY (cw->c) + frameTop (cw->c);
739 }
740 else
741 {
742 x = cw->attr.x + cw->attr.border_width;
743 y = cw->attr.y + cw->attr.border_width;
744 }
745
746 XFixesTranslateRegion (display_info->dpy, region, x, y);
747 }
748
749 static XserverRegion
client_size(CWindow * cw)750 client_size (CWindow *cw)
751 {
752 DisplayInfo *display_info;
753 ScreenInfo *screen_info;
754 XserverRegion border;
755
756 g_return_val_if_fail (cw != NULL, None);
757 TRACE ("window 0x%lx", cw->id);
758
759 screen_info = cw->screen_info;
760 display_info = screen_info->display_info;
761 border = None;
762
763 if (WIN_HAS_FRAME(cw))
764 {
765 XRectangle r;
766 Client *c;
767
768 c = cw->c;
769 r.x = frameX (c) + frameLeft (c);
770 r.y = frameY (c) + frameTop (c);
771 r.width = frameWidth (c) - frameLeft (c) - frameRight (c);
772 r.height = frameHeight (c) - frameTop (c) - frameBottom (c);
773 border = XFixesCreateRegion (display_info->dpy, &r, 1);
774 }
775
776 return border;
777 }
778
779 static XserverRegion
border_size(CWindow * cw)780 border_size (CWindow *cw)
781 {
782 DisplayInfo *display_info;
783 ScreenInfo *screen_info;
784 XserverRegion border;
785
786 g_return_val_if_fail (cw != NULL, None);
787 TRACE ("window 0x%lx", cw->id);
788
789 screen_info = cw->screen_info;
790 display_info = screen_info->display_info;
791 myDisplayErrorTrapPush (display_info);
792 border = XFixesCreateRegionFromWindow (display_info->dpy,
793 cw->id, WindowRegionBounding);
794 XFixesSetPictureClipRegion (display_info->dpy, cw->picture, 0, 0, border);
795 XFixesTranslateRegion (display_info->dpy, border,
796 cw->attr.x + cw->attr.border_width,
797 cw->attr.y + cw->attr.border_width);
798
799 if (myDisplayErrorTrapPop (display_info) != Success)
800 {
801 return None;
802 }
803
804 return border;
805 }
806
807 static void
free_win_data(CWindow * cw,gboolean delete)808 free_win_data (CWindow *cw, gboolean delete)
809 {
810 DisplayInfo *display_info;
811 ScreenInfo *screen_info;
812
813 screen_info = cw->screen_info;
814 display_info = screen_info->display_info;
815
816 myDisplayErrorTrapPush (display_info);
817 #if HAVE_NAME_WINDOW_PIXMAP
818 if (cw->name_window_pixmap)
819 {
820 XFreePixmap (display_info->dpy, cw->name_window_pixmap);
821 cw->name_window_pixmap = None;
822 }
823 #endif
824
825 if (cw->shadow)
826 {
827 XRenderFreePicture (display_info->dpy, cw->shadow);
828 cw->shadow = None;
829 }
830
831 if (cw->alphaPict)
832 {
833 XRenderFreePicture (display_info->dpy, cw->alphaPict);
834 cw->alphaPict = None;
835 }
836
837 if (cw->shadowPict)
838 {
839 XRenderFreePicture (display_info->dpy, cw->shadowPict);
840 cw->shadowPict = None;
841 }
842
843 if (cw->alphaBorderPict)
844 {
845 XRenderFreePicture (display_info->dpy, cw->alphaBorderPict);
846 cw->alphaBorderPict = None;
847 }
848
849 if (cw->borderSize)
850 {
851 XFixesDestroyRegion (display_info->dpy, cw->borderSize);
852 cw->borderSize = None;
853 }
854
855 if (cw->clientSize)
856 {
857 XFixesDestroyRegion (display_info->dpy, cw->clientSize);
858 cw->clientSize = None;
859 }
860
861 if (cw->borderClip)
862 {
863 XFixesDestroyRegion (display_info->dpy, cw->borderClip);
864 cw->borderClip = None;
865 }
866
867 if (cw->extents)
868 {
869 XFixesDestroyRegion (display_info->dpy, cw->extents);
870 cw->extents = None;
871 }
872
873 if (delete)
874 {
875 if (cw->picture)
876 {
877 XRenderFreePicture (display_info->dpy, cw->picture);
878 cw->picture = None;
879 }
880 /* No need to keep this around */
881 if (cw->saved_picture)
882 {
883 XRenderFreePicture (display_info->dpy, cw->saved_picture);
884 cw->saved_picture = None;
885 }
886
887 if (cw->damage)
888 {
889 XDamageDestroy (display_info->dpy, cw->damage);
890 cw->damage = None;
891 }
892
893 if (cw->opaque_region)
894 {
895 XFixesDestroyRegion (display_info->dpy, cw->opaque_region);
896 cw->opaque_region = None;
897 }
898
899 g_slice_free (CWindow, cw);
900 }
901 else
902 {
903 if (cw->saved_picture)
904 {
905 XRenderFreePicture (display_info->dpy, cw->saved_picture);
906 }
907 cw->saved_picture = cw->picture;
908 cw->picture = None;
909 }
910 myDisplayErrorTrapPopIgnored (display_info);
911 }
912
913 static Picture
root_tile(ScreenInfo * screen_info)914 root_tile (ScreenInfo *screen_info)
915 {
916 DisplayInfo *display_info;
917 Display *dpy;
918 Picture picture = None;
919 #if MONITOR_ROOT_PIXMAP
920 Pixmap pixmap;
921 XRenderPictureAttributes pa;
922 XRenderPictFormat *format;
923 gint p;
924 Atom backgroundProps[2];
925 #endif
926
927 g_return_val_if_fail (screen_info != NULL, None);
928 TRACE ("entering");
929
930 display_info = screen_info->display_info;
931 dpy = display_info->dpy;
932 #if MONITOR_ROOT_PIXMAP
933 backgroundProps[0] = display_info->atoms[XROOTPMAP];
934 backgroundProps[1] = display_info->atoms[XSETROOT];
935
936 for (p = 0; p < 2; p++)
937 {
938 Atom actual_type;
939 gint actual_format;
940 unsigned long nitems;
941 unsigned long bytes_after;
942 guchar *prop;
943 gint result;
944
945 result = XGetWindowProperty (dpy, screen_info->xroot, backgroundProps[p],
946 0, 4, False, AnyPropertyType,
947 &actual_type, &actual_format, &nitems, &bytes_after, &prop);
948
949 if ((result == Success) &&
950 (actual_type == display_info->atoms[PIXMAP]) &&
951 (actual_format == 32) &&
952 (nitems == 1))
953 {
954 memcpy (&pixmap, prop, 4);
955 XFree (prop);
956 pa.repeat = TRUE;
957 format = XRenderFindVisualFormat (dpy, screen_info->visual);
958 g_return_val_if_fail (format != NULL, None);
959 picture = XRenderCreatePicture (dpy, pixmap, format, CPRepeat, &pa);
960 break;
961 }
962 }
963 #endif
964 if (picture == None)
965 {
966 XRenderColor c;
967
968 /* Background default to just plain black */
969 c.red = 0x0000;
970 c.green = 0x0000;
971 c.blue = 0x0000;
972 c.alpha = 0xffff;
973 picture = XRenderCreateSolidFill (dpy, &c);
974 }
975 return picture;
976 }
977
978 static Pixmap
create_root_pixmap(ScreenInfo * screen_info)979 create_root_pixmap (ScreenInfo *screen_info)
980 {
981 return XCreatePixmap (myScreenGetXDisplay (screen_info),
982 screen_info->xroot,
983 screen_info->width,
984 screen_info->height,
985 screen_info->depth);
986 }
987
988 static Picture
create_root_buffer(ScreenInfo * screen_info,Pixmap pixmap)989 create_root_buffer (ScreenInfo *screen_info, Pixmap pixmap)
990 {
991 DisplayInfo *display_info;
992 Picture pict;
993 XRenderPictFormat *format;
994
995 g_return_val_if_fail (screen_info != NULL, None);
996 g_return_val_if_fail (pixmap != None, None);
997 TRACE ("entering");
998
999 display_info = screen_info->display_info;
1000 format = XRenderFindVisualFormat (display_info->dpy, screen_info->visual);
1001 g_return_val_if_fail (format != NULL, None);
1002
1003 pict = XRenderCreatePicture (display_info->dpy,
1004 pixmap, format, 0, NULL);
1005
1006 return pict;
1007 }
1008
1009 static Picture
cursor_to_picture(ScreenInfo * screen_info,XFixesCursorImage * cursor)1010 cursor_to_picture (ScreenInfo *screen_info, XFixesCursorImage *cursor)
1011 {
1012 DisplayInfo *display_info;
1013 XRenderPictFormat *render_format;
1014 XImage *ximage;
1015 guint32 *data;
1016 Pixmap pixmap;
1017 Picture picture;
1018 GC gc;
1019 gint i;
1020
1021 g_return_val_if_fail (screen_info != NULL, None);
1022 TRACE ("entering");
1023
1024 display_info = screen_info->display_info;
1025
1026 /* XFixesGetCursorImage() returns an array of long but actual data is 32bit */
1027 data = g_malloc0 (cursor->width * cursor->height * sizeof (guint32));
1028 for (i = 0; i < cursor->width * cursor->height; i++)
1029 {
1030 data[i] = cursor->pixels[i];
1031 }
1032
1033 ximage = XCreateImage (display_info->dpy,
1034 screen_info->visual,
1035 32, ZPixmap, 0, (char *) data,
1036 cursor->width, cursor->height, 32,
1037 cursor->width * sizeof (guint32));
1038
1039 if (!ximage)
1040 {
1041 g_warning ("Failed to create the cursor image");
1042 return None;
1043 }
1044
1045 pixmap = XCreatePixmap (display_info->dpy,
1046 screen_info->output,
1047 cursor->width,
1048 cursor->height,
1049 32);
1050
1051 gc = XCreateGC (display_info->dpy, pixmap, 0, NULL);
1052 XPutImage (display_info->dpy, pixmap, gc, ximage,
1053 0, 0, 0, 0, cursor->width, cursor->height);
1054 XFreeGC (display_info->dpy, gc);
1055 XDestroyImage (ximage);
1056
1057 render_format = XRenderFindStandardFormat (display_info->dpy,
1058 PictStandardARGB32);
1059 picture = XRenderCreatePicture (display_info->dpy,
1060 pixmap,
1061 render_format,
1062 0, NULL);
1063 XFreePixmap (display_info->dpy, pixmap);
1064
1065 return picture;
1066 }
1067
1068 #ifdef HAVE_EPOXY
1069 static gboolean
check_gl_error(void)1070 check_gl_error (void)
1071 {
1072 gboolean clean = TRUE;
1073 #ifdef DEBUG /* glGetError() is expensive, keep it for debug only */
1074 GLenum error;
1075
1076 error = glGetError();
1077 while (error != GL_NO_ERROR)
1078 {
1079 clean = FALSE;
1080 switch (error)
1081 {
1082 case GL_INVALID_ENUM:
1083 g_warning ("GL error: Invalid enum");
1084 break;
1085 case GL_INVALID_VALUE:
1086 g_warning ("GL error: Invalid value");
1087 break;
1088 case GL_INVALID_OPERATION:
1089 g_warning ("GL error: Invalid operation");
1090 break;
1091 case GL_INVALID_FRAMEBUFFER_OPERATION:
1092 g_warning ("GL error: Invalid frame buffer operation");
1093 break;
1094 case GL_OUT_OF_MEMORY:
1095 g_warning ("GL error: Out of memory");
1096 break;
1097 default:
1098 break;
1099 }
1100 error = glGetError();
1101 }
1102 #endif
1103 return clean;
1104 }
1105
1106 static gboolean
check_glx_renderer(ScreenInfo * screen_info)1107 check_glx_renderer (ScreenInfo *screen_info)
1108 {
1109 const char *glRenderer;
1110 const char *blacklisted[] = {
1111 "Software Rasterizer",
1112 "Mesa X11",
1113 "llvmpipe",
1114 "SVGA3D",
1115 NULL
1116 };
1117 #if HAVE_PRESENT_EXTENSION
1118 const char *prefer_xpresent[] = {
1119 "Intel",
1120 /* Cannot add AMD and Radeon until the fix for
1121 * https://gitlab.freedesktop.org/xorg/driver/xf86-video-amdgpu/-/issues/10
1122 * is included in a release.
1123 */
1124 /* "AMD", */
1125 /* "Radeon", */
1126 NULL
1127 };
1128 #endif /* HAVE_PRESENT_EXTENSION */
1129 int i;
1130
1131 g_return_val_if_fail (screen_info != NULL, FALSE);
1132 TRACE ("entering");
1133
1134 glRenderer = (const char *) glGetString (GL_RENDERER);
1135 if (glRenderer == NULL)
1136 {
1137 g_warning ("Cannot identify GLX renderer.");
1138 return FALSE;
1139 }
1140 DBG ("Using GL renderer: %s", glRenderer);
1141
1142 #if HAVE_PRESENT_EXTENSION
1143 if (screen_info->vblank_mode == VBLANK_AUTO)
1144 {
1145 i = 0;
1146 while (prefer_xpresent[i] && !strcasestr (glRenderer, prefer_xpresent[i]))
1147 i++;
1148 if (prefer_xpresent[i])
1149 {
1150 g_info ("Prefer XPresent with %s", glRenderer);
1151 return FALSE;
1152 }
1153 }
1154 #endif /* HAVE_PRESENT_EXTENSION */
1155
1156 i = 0;
1157 while (blacklisted[i] && !strcasestr (glRenderer, blacklisted[i]))
1158 i++;
1159 if (blacklisted[i])
1160 {
1161 g_warning ("Unsupported GL renderer (%s).", glRenderer);
1162 return FALSE;
1163 }
1164
1165 return TRUE;
1166 }
1167
1168 static gboolean
check_gl_extensions(ScreenInfo * screen_info)1169 check_gl_extensions (ScreenInfo *screen_info)
1170 {
1171 g_return_val_if_fail (screen_info != NULL, FALSE);
1172
1173 /* Note: the GL context must be current for this to work */
1174 if (screen_info->texture_type == GL_TEXTURE_2D)
1175 {
1176 /*
1177 * If all we have is GL_TEXTURE_2D then we ought to have
1178 * GL_ARB_texture_non_power_of_two, otherwise we'll fail.
1179 */
1180 return (epoxy_has_gl_extension ("GL_ARB_texture_non_power_of_two"));
1181 }
1182
1183 return TRUE;
1184 }
1185
1186 static gboolean
choose_glx_settings(ScreenInfo * screen_info)1187 choose_glx_settings (ScreenInfo *screen_info)
1188 {
1189 static GLint visual_attribs[] = {
1190 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT | GLX_WINDOW_BIT,
1191 GLX_X_RENDERABLE, True,
1192 GLX_DOUBLEBUFFER, True,
1193 GLX_CONFIG_CAVEAT, GLX_NONE,
1194 GLX_DEPTH_SIZE, 1,
1195 GLX_RED_SIZE, 1,
1196 GLX_GREEN_SIZE, 1,
1197 GLX_BLUE_SIZE, 1,
1198 GLX_RENDER_TYPE, GLX_RGBA_BIT,
1199 None
1200 };
1201 GLint texture_type = 0;
1202 GLint texture_target = 0;
1203 GLint texture_format = 0;
1204 gboolean texture_inverted = FALSE;
1205 int n_configs, i;
1206 int value, status;
1207 GLXFBConfig *configs, fb_config;
1208 XVisualInfo *visual_info;
1209 gboolean fb_match;
1210 VisualID xvisual_id;
1211
1212 g_return_val_if_fail (screen_info != NULL, FALSE);
1213 TRACE ("entering");
1214
1215 configs = glXChooseFBConfig (myScreenGetXDisplay (screen_info),
1216 screen_info->screen,
1217 visual_attribs,
1218 &n_configs);
1219 if (configs == NULL)
1220 {
1221 g_warning ("Cannot retrieve GLX frame buffer config.");
1222 return FALSE;
1223 }
1224
1225 fb_match = FALSE;
1226 xvisual_id = XVisualIDFromVisual (screen_info->visual);
1227 for (i = 0; i < n_configs; i++)
1228 {
1229 visual_info = glXGetVisualFromFBConfig (myScreenGetXDisplay (screen_info),
1230 configs[i]);
1231 if (!visual_info)
1232 {
1233 DBG ("%i/%i: no visual info, skipped", i + 1, n_configs);
1234 continue;
1235 }
1236
1237 if (visual_info->visualid != xvisual_id)
1238 {
1239 DBG ("%i/%i: xvisual id 0x%lx != 0x%lx, skipped", i + 1, n_configs, visual_info->visualid, xvisual_id);
1240 XFree (visual_info);
1241 continue;
1242 }
1243 XFree (visual_info);
1244
1245 status = glXGetFBConfigAttrib (myScreenGetXDisplay (screen_info),
1246 configs[i],
1247 GLX_DRAWABLE_TYPE, &value);
1248
1249 if (status != Success || !(value & GLX_PIXMAP_BIT))
1250 {
1251 DBG ("%i/%i: No GLX_PIXMAP_BIT, skipped", i + 1, n_configs);
1252 continue;
1253 }
1254
1255 status = glXGetFBConfigAttrib (myScreenGetXDisplay (screen_info),
1256 configs[i],
1257 GLX_BIND_TO_TEXTURE_TARGETS_EXT,
1258 &value);
1259 if (status != Success)
1260 {
1261 DBG ("%i/%i: No GLX_BIND_TO_TEXTURE_TARGETS_EXT, skipped", i + 1, n_configs);
1262 continue;
1263 }
1264
1265 if (value & GLX_TEXTURE_RECTANGLE_BIT_EXT)
1266 {
1267 DBG ("Using texture GL_TEXTURE_RECTANGLE_ARB target GLX_TEXTURE_RECTANGLE_EXT");
1268 texture_type = GL_TEXTURE_RECTANGLE_ARB;
1269 texture_target = GLX_TEXTURE_RECTANGLE_EXT;
1270 }
1271 else if (value & GLX_TEXTURE_2D_BIT_EXT)
1272 {
1273 DBG ("Using texture GL_TEXTURE_2D target GLX_TEXTURE_2D_EXT");
1274 texture_type = GL_TEXTURE_2D;
1275 texture_target = GLX_TEXTURE_2D_EXT;
1276 }
1277 else
1278 {
1279 DBG ("%i/%i: No GLX_TEXTURE_*_BIT_EXT, skipped", i + 1, n_configs);
1280 continue;
1281 }
1282
1283 status = glXGetFBConfigAttrib (myScreenGetXDisplay (screen_info),
1284 configs[i],
1285 GLX_RED_SIZE,
1286 &value);
1287 if (status == Success && value > 8)
1288 {
1289 DBG ("%i/%i: RGB10 config, skipped", i + 1, n_configs);
1290 continue;
1291 }
1292
1293 status = glXGetFBConfigAttrib (myScreenGetXDisplay (screen_info),
1294 configs[i],
1295 GLX_BIND_TO_TEXTURE_RGBA_EXT,
1296 &value);
1297 if (status == Success && value == TRUE)
1298 {
1299 DBG ("Using texture format GLX_TEXTURE_FORMAT_RGBA_EXT");
1300 texture_format = GLX_TEXTURE_FORMAT_RGBA_EXT;
1301 }
1302 else
1303 {
1304 status = glXGetFBConfigAttrib (myScreenGetXDisplay (screen_info),
1305 configs[i],
1306 GLX_BIND_TO_TEXTURE_RGB_EXT,
1307 &value);
1308 if (status == Success && value == TRUE)
1309 {
1310 DBG ("Using texture format GLX_TEXTURE_FORMAT_RGB_EXT");
1311 texture_format = GLX_TEXTURE_FORMAT_RGB_EXT;
1312 }
1313 else
1314 {
1315 DBG ("%i/%i: No GLX_BIND_TO_TEXTURE_RGB/RGBA_EXT, skipped", i + 1, n_configs);
1316 continue;
1317 }
1318 }
1319 #if 0
1320 status = glXGetFBConfigAttrib (myScreenGetXDisplay (screen_info),
1321 configs[i],
1322 GLX_Y_INVERTED_EXT,
1323 &value);
1324 texture_inverted = (status == Success && value == True);
1325 if (texture_inverted)
1326 {
1327 DBG ("Using texture attribute GLX_Y_INVERTED_EXT");
1328 }
1329 #endif
1330 fb_config = configs[i];
1331 fb_match = TRUE;
1332 break;
1333 }
1334 XFree(configs);
1335
1336 if (fb_match == FALSE)
1337 {
1338 g_warning ("Cannot find a matching visual for the frame buffer config.");
1339 return FALSE;
1340 }
1341 DBG ("Selected texture type 0x%x target 0x%x format 0x%x (%s)",
1342 texture_type, texture_target, texture_format,
1343 texture_inverted ? "inverted" : "non inverted");
1344
1345 screen_info->texture_type = texture_type;
1346 screen_info->texture_target = texture_target;
1347 screen_info->texture_format = texture_format;
1348 screen_info->texture_inverted = texture_inverted;
1349 screen_info->glx_fbconfig = fb_config;
1350
1351 return TRUE;
1352 }
1353
1354 static void
free_glx_data(ScreenInfo * screen_info)1355 free_glx_data (ScreenInfo *screen_info)
1356 {
1357 DisplayInfo *display_info;
1358
1359 g_return_if_fail (screen_info != NULL);
1360
1361 display_info = screen_info->display_info;
1362 myDisplayErrorTrapPush (display_info);
1363
1364 glXMakeCurrent (myScreenGetXDisplay (screen_info), None, NULL);
1365
1366 if (screen_info->glx_context)
1367 {
1368 glXDestroyContext (myScreenGetXDisplay (screen_info), screen_info->glx_context);
1369 screen_info->glx_context = None;
1370 }
1371
1372 if (screen_info->glx_window)
1373 {
1374 glXDestroyWindow (myScreenGetXDisplay (screen_info), screen_info->glx_window);
1375 screen_info->glx_window = None;
1376 }
1377
1378 if (screen_info->has_ext_arb_sync && screen_info->gl_sync)
1379 {
1380 #if defined (glDeleteSync)
1381 glDeleteSync (screen_info->gl_sync);
1382 #else
1383 #warning glDeleteSync() not supported by libepoxy, please update your version of libepoxy
1384 #endif
1385 screen_info->gl_sync = 0;
1386 }
1387 myDisplayErrorTrapPopIgnored (display_info);
1388 }
1389
1390 static gboolean
init_glx(ScreenInfo * screen_info)1391 init_glx (ScreenInfo *screen_info)
1392 {
1393 int error_base, event_base;
1394 int version;
1395
1396 g_return_val_if_fail (screen_info != NULL, FALSE);
1397 TRACE ("entering");
1398
1399 if (!glXQueryExtension (myScreenGetXDisplay (screen_info), &error_base, &event_base))
1400 {
1401 g_warning ("GLX extension missing, GLX support disabled.");
1402 return FALSE;
1403 }
1404
1405 version = epoxy_glx_version (myScreenGetXDisplay (screen_info), screen_info->screen);
1406 DBG ("Using GLX version %d", version);
1407 if (version < 13)
1408 {
1409 g_warning ("GLX version %d is too old, GLX support disabled.", version);
1410 return FALSE;
1411 }
1412
1413 if (!choose_glx_settings (screen_info))
1414 {
1415 g_warning ("Cannot find a matching GLX config, vsync disabled.");
1416 return FALSE;
1417 }
1418
1419 screen_info->glx_context = glXCreateNewContext (myScreenGetXDisplay (screen_info),
1420 screen_info->glx_fbconfig,
1421 GLX_RGBA_TYPE,
1422 0,
1423 TRUE);
1424 if (!screen_info->glx_context)
1425 {
1426 g_warning ("Could not create GLX context.");
1427 return FALSE;
1428 }
1429
1430 screen_info->glx_window = glXCreateWindow (myScreenGetXDisplay (screen_info),
1431 screen_info->glx_fbconfig,
1432 screen_info->output,
1433 NULL);
1434 if (!screen_info->glx_window)
1435 {
1436 g_warning ("Could not create GLX window.");
1437 free_glx_data (screen_info);
1438
1439 return FALSE;
1440 }
1441
1442 if (!glXMakeCurrent (myScreenGetXDisplay (screen_info),
1443 screen_info->glx_window,
1444 screen_info->glx_context))
1445 {
1446 g_warning ("Could not make GL context current.");
1447 free_glx_data (screen_info);
1448
1449 return FALSE;
1450 }
1451
1452 if (!check_glx_renderer (screen_info))
1453 {
1454 free_glx_data (screen_info);
1455
1456 return FALSE;
1457 }
1458
1459 if (!check_gl_extensions (screen_info))
1460 {
1461 g_warning ("Screen is missing required GL extension, GL support disabled.");
1462 free_glx_data (screen_info);
1463
1464 return FALSE;
1465 }
1466 glDisable(GL_DEPTH_TEST);
1467 glDepthMask(GL_FALSE);
1468 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1469 glDisable(GL_BLEND);
1470
1471 glLoadIdentity();
1472
1473 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1474
1475 /* Swap control methods available */
1476 screen_info->has_mesa_swap_control =
1477 epoxy_has_glx_extension (myScreenGetXDisplay (screen_info),
1478 screen_info->screen, "GLX_MESA_swap_control");
1479 screen_info->has_ext_swap_control =
1480 epoxy_has_glx_extension (myScreenGetXDisplay (screen_info),
1481 screen_info->screen, "GLX_EXT_swap_control");
1482
1483 /* Sync */
1484 screen_info->has_ext_arb_sync = epoxy_has_gl_extension ("GL_ARB_sync");
1485
1486 check_gl_error();
1487
1488 return TRUE;
1489 }
1490
1491 static void
enable_glx_texture(ScreenInfo * screen_info)1492 enable_glx_texture (ScreenInfo *screen_info)
1493 {
1494 g_return_if_fail (screen_info != NULL);
1495 TRACE ("entering");
1496
1497 glBindTexture(screen_info->texture_type, screen_info->rootTexture);
1498 glEnable(screen_info->texture_type);
1499 }
1500
1501 static void
disable_glx_texture(ScreenInfo * screen_info)1502 disable_glx_texture (ScreenInfo *screen_info)
1503 {
1504 g_return_if_fail (screen_info != NULL);
1505 TRACE ("entering");
1506
1507 glBindTexture(screen_info->texture_type, None);
1508 glDisable(screen_info->texture_type);
1509 }
1510
1511 static void
fence_create(ScreenInfo * screen_info,gushort buffer)1512 fence_create (ScreenInfo *screen_info, gushort buffer)
1513 {
1514 #ifdef HAVE_XSYNC
1515 if (screen_info->fence[buffer] == None)
1516 {
1517 DBG ("Create fence for buffer %i", buffer);
1518 screen_info->fence[buffer] =
1519 XSyncCreateFence (myScreenGetXDisplay (screen_info),
1520 screen_info->rootPixmap[buffer], FALSE);
1521 }
1522 #endif /* HAVE_XSYNC */
1523 }
1524
1525 static void
fence_reset(ScreenInfo * screen_info,gushort buffer)1526 fence_reset (ScreenInfo *screen_info, gushort buffer)
1527 {
1528 #ifdef HAVE_XSYNC
1529 if (screen_info->fence[buffer] == None)
1530 {
1531 return;
1532 }
1533 DBG ("Reset fence for buffer %i", buffer);
1534 XSyncResetFence(myScreenGetXDisplay (screen_info),
1535 screen_info->fence[buffer]);
1536 #endif /* HAVE_XSYNC */
1537 }
1538
1539 static gboolean
is_fence_triggered(ScreenInfo * screen_info,gushort buffer)1540 is_fence_triggered (ScreenInfo *screen_info, gushort buffer)
1541 {
1542 #ifdef HAVE_XSYNC
1543 Bool triggered = False;
1544
1545 if (screen_info->fence[buffer] == None)
1546 {
1547 DBG ("No fence for buffer %i", buffer);
1548 return TRUE;
1549 }
1550
1551 if (!XSyncQueryFence(myScreenGetXDisplay (screen_info),
1552 screen_info->fence[buffer], &triggered))
1553 {
1554 DBG ("Cannot query fence for buffer %i", buffer);
1555 return TRUE;
1556 }
1557
1558 DBG ("Fence for buffer %i is %striggered", buffer, triggered ? "" : "not ");
1559 return (gboolean) triggered;
1560 #else
1561 return TRUE;
1562 #endif /* HAVE_XSYNC */
1563 }
1564
1565 static void
fence_sync(ScreenInfo * screen_info,gushort buffer)1566 fence_sync (ScreenInfo *screen_info, gushort buffer)
1567 {
1568 #ifdef HAVE_XSYNC
1569 #ifdef DEBUG
1570 gint64 t1, t2;
1571 #endif /* DEBUG */
1572 if (is_fence_triggered (screen_info, buffer))
1573 {
1574 DBG ("Fence for buffer %i already triggered", buffer);
1575 return;
1576 }
1577
1578 TRACE ("Awaiting fence for buffer %i", buffer);
1579 #ifdef DEBUG
1580 t1 = g_get_monotonic_time ();
1581 #endif /* DEBUG */
1582 XSyncTriggerFence(myScreenGetXDisplay (screen_info),
1583 screen_info->fence[buffer]);
1584 XSyncAwaitFence(myScreenGetXDisplay (screen_info),
1585 &screen_info->fence[buffer], 1);
1586 #ifdef DEBUG
1587 t2 = g_get_monotonic_time ();
1588 DBG ("Fence sync time %luμs", t2 - t1);
1589 #endif /* DEBUG */
1590
1591 fence_reset (screen_info, buffer);
1592 #else
1593 XSync (myScreenGetXDisplay (screen_info), FALSE);
1594 glXWaitX ();
1595 #endif /* HAVE_XSYNC */
1596 }
1597
1598 static void
fence_destroy(ScreenInfo * screen_info,gushort buffer)1599 fence_destroy (ScreenInfo *screen_info, gushort buffer)
1600 {
1601 #ifdef HAVE_XSYNC
1602 if (screen_info->fence[buffer])
1603 {
1604 DBG ("Destroying fence for buffer %i", buffer);
1605 XSyncDestroyFence (myScreenGetXDisplay (screen_info),
1606 screen_info->fence[buffer]);
1607 screen_info->fence[buffer] = None;
1608 }
1609 #endif /* HAVE_XSYNC */
1610 }
1611
1612 static void
set_swap_interval(ScreenInfo * screen_info,gushort buffer,int interval)1613 set_swap_interval (ScreenInfo *screen_info, gushort buffer, int interval)
1614 {
1615 #if defined (glXSwapIntervalEXT)
1616 if (screen_info->has_ext_swap_control)
1617 {
1618 DBG ("Setting swap interval to %d using GLX_EXT_swap_control", interval);
1619 glXSwapIntervalEXT (myScreenGetXDisplay (screen_info),
1620 screen_info->glx_drawable[buffer],
1621 interval);
1622 return;
1623 }
1624 #else
1625 #warning glXSwapIntervalEXT() not supported by libepoxy, please update your version of libepoxy
1626 #endif
1627
1628 #if defined (glXSwapIntervalMESA)
1629 if (screen_info->has_mesa_swap_control)
1630 {
1631 DBG ("Setting swap interval to %d using GLX_MESA_swap_control", interval);
1632 glXSwapIntervalMESA(interval);
1633 return;
1634 }
1635 #else
1636 #warning glXSwapIntervalMESA() not supported by libepoxy, please update your version of libepoxy
1637 #endif
1638
1639 DBG ("No swap control available");
1640 }
1641
1642 static void
create_glx_drawable(ScreenInfo * screen_info,gushort buffer)1643 create_glx_drawable (ScreenInfo *screen_info, gushort buffer)
1644 {
1645 int pixmap_attribs[] = {
1646 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
1647 GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT,
1648 None
1649 };
1650
1651 g_return_if_fail (screen_info != NULL);
1652 TRACE ("entering");
1653
1654 pixmap_attribs[1] = screen_info->texture_target;
1655 pixmap_attribs[3] = screen_info->texture_format;
1656
1657 screen_info->glx_drawable[buffer] =
1658 glXCreatePixmap (myScreenGetXDisplay (screen_info),
1659 screen_info->glx_fbconfig,
1660 screen_info->rootPixmap[buffer],
1661 pixmap_attribs);
1662 check_gl_error();
1663 TRACE ("created GLX pixmap 0x%lx for buffer %i",
1664 screen_info->glx_drawable[buffer], buffer);
1665 }
1666
1667 static void
bind_glx_texture(ScreenInfo * screen_info,gushort buffer)1668 bind_glx_texture (ScreenInfo *screen_info, gushort buffer)
1669 {
1670 g_return_if_fail (screen_info != NULL);
1671 TRACE ("entering");
1672
1673 if (screen_info->rootTexture == None)
1674 {
1675 glGenTextures(1, &screen_info->rootTexture);
1676 TRACE ("generated texture 0x%x", screen_info->rootTexture);
1677 }
1678 if (screen_info->glx_drawable[buffer] == None)
1679 {
1680 create_glx_drawable (screen_info, buffer);
1681 set_swap_interval (screen_info, buffer, 1);
1682 }
1683 TRACE ("(re)Binding GLX pixmap 0x%lx to texture 0x%x",
1684 screen_info->glx_drawable[buffer], screen_info->rootTexture);
1685 enable_glx_texture (screen_info);
1686 glXBindTexImageEXT (myScreenGetXDisplay (screen_info),
1687 screen_info->glx_drawable[buffer], GLX_FRONT_EXT, NULL);
1688
1689 check_gl_error();
1690 }
1691
1692 static void
unbind_glx_texture(ScreenInfo * screen_info,gushort buffer)1693 unbind_glx_texture (ScreenInfo *screen_info, gushort buffer)
1694 {
1695 g_return_if_fail (screen_info != NULL);
1696 TRACE ("entering");
1697
1698 if (screen_info->glx_drawable[buffer])
1699 {
1700 TRACE ("unbinding GLX drawable 0x%lx", screen_info->glx_drawable[buffer]);
1701 glXReleaseTexImageEXT (myScreenGetXDisplay (screen_info),
1702 screen_info->glx_drawable[buffer], GLX_FRONT_EXT);
1703 }
1704 }
1705
1706 static void
destroy_glx_drawable(ScreenInfo * screen_info,gushort buffer)1707 destroy_glx_drawable (ScreenInfo *screen_info, gushort buffer)
1708 {
1709 g_return_if_fail (screen_info != NULL);
1710 TRACE ("entering");
1711
1712 if (screen_info->glx_drawable[buffer])
1713 {
1714 unbind_glx_texture (screen_info, buffer);
1715 glXDestroyPixmap(myScreenGetXDisplay (screen_info),
1716 screen_info->glx_drawable[buffer]);
1717 screen_info->glx_drawable[buffer] = None;
1718 }
1719
1720 if (screen_info->rootTexture)
1721 {
1722 disable_glx_texture (screen_info);
1723 glDeleteTextures (1, &screen_info->rootTexture);
1724 screen_info->rootTexture = None;
1725 }
1726 check_gl_error();
1727 }
1728
1729 static void
set_glx_scale(ScreenInfo * screen_info,gint width,gint height,double scale)1730 set_glx_scale (ScreenInfo *screen_info, gint width, gint height, double scale)
1731 {
1732 if (screen_info->texture_type == GL_TEXTURE_RECTANGLE_ARB)
1733 {
1734 glScaled ((double) width * scale, (double) height * scale, 1.0);
1735 }
1736 else
1737 {
1738 glScaled(1.0 * scale, 1.0 * scale, 1.0);
1739 }
1740 }
1741
1742 static void
redraw_glx_rects(ScreenInfo * screen_info,XRectangle * rects,int nrects)1743 redraw_glx_rects (ScreenInfo *screen_info, XRectangle *rects, int nrects)
1744 {
1745 int i;
1746
1747 glBegin(GL_QUADS);
1748 for (i = 0; i < nrects; i++)
1749 {
1750 double texture_x1 = (double) (rects[i].x) / screen_info->width;
1751 double texture_y1 = (double) (rects[i].y) / screen_info->height;
1752 double texture_x2 = (double) (rects[i].x + rects[i].width) / screen_info->width;
1753 double texture_y2 = (double) (rects[i].y + rects[i].height) / screen_info->height;
1754 double vertice_x1 = 2 * texture_x1 - 1.0;
1755 double vertice_y1 = -2 * texture_y1 + 1.0;
1756 double vertice_x2 = 2 * texture_x2 - 1.0;
1757 double vertice_y2 = -2 * texture_y2 + 1.0;
1758
1759 if (screen_info->texture_inverted)
1760 {
1761 texture_y1 = 1.0 - texture_y1;
1762 texture_y2 = texture_y2 - 1.0;
1763 }
1764
1765 TRACE ("Rect#%i: Texture (%.2f,%.2f,%.2f,%.2f) to vertice (%.2f,%.2f,%.2f,%.2f)", i,
1766 texture_x1, texture_y1, texture_x2, texture_y2,
1767 vertice_x1, vertice_y1, vertice_x2, vertice_y2);
1768
1769 glTexCoord2f (texture_x1, texture_y1);
1770 glVertex2f (vertice_x1, vertice_y1);
1771 glTexCoord2f (texture_x2, texture_y1);
1772 glVertex2f (vertice_x2, vertice_y1);
1773 glTexCoord2f (texture_x2, texture_y2);
1774 glVertex2f (vertice_x2, vertice_y2);
1775 glTexCoord2f (texture_x1, texture_y2);
1776 glVertex2f (vertice_x1, vertice_y2);
1777 }
1778 glEnd();
1779 }
1780
1781 static void
redraw_glx_screen(ScreenInfo * screen_info)1782 redraw_glx_screen (ScreenInfo *screen_info)
1783 {
1784 XRectangle root_rect = { 0, 0, screen_info->width, screen_info->height};
1785
1786 redraw_glx_rects (screen_info, &root_rect, 1);
1787 }
1788
1789 static void
redraw_glx_texture(ScreenInfo * screen_info,gushort buffer)1790 redraw_glx_texture (ScreenInfo *screen_info, gushort buffer)
1791 {
1792 #ifdef DEBUG
1793 gint64 t1, t2;
1794 #endif /* DEBUG */
1795 g_return_if_fail (screen_info != NULL);
1796 TRACE ("(re)Drawing GLX pixmap 0x%lx/texture 0x%x",
1797 screen_info->glx_drawable[buffer], screen_info->rootTexture);
1798
1799 fence_sync (screen_info, buffer);
1800 #ifdef DEBUG
1801 t1 = g_get_monotonic_time ();
1802 #endif /* DEBUG */
1803
1804 if (screen_info->has_ext_arb_sync)
1805 {
1806 #if defined (glDeleteSync)
1807 glDeleteSync (screen_info->gl_sync);
1808 #else
1809 #warning glDeleteSync() not supported by libepoxy, please update your version of libepoxy
1810 #endif
1811 screen_info->gl_sync = 0;
1812 }
1813
1814 bind_glx_texture (screen_info, buffer);
1815
1816 glDrawBuffer (GL_BACK);
1817 glViewport(0, 0, screen_info->width, screen_info->height);
1818
1819 glMatrixMode(GL_TEXTURE);
1820 glPushMatrix();
1821
1822 if (screen_info->zoomed)
1823 {
1824 /* Reuse the values from the XRender matrix */
1825 XFixed zf = screen_info->transform.matrix[0][0];
1826 XFixed xp = screen_info->transform.matrix[0][2];
1827 XFixed yp = screen_info->transform.matrix[1][2];
1828
1829 double zoom = XFixedToDouble (zf);
1830 double x = XFixedToDouble (xp) / (screen_info->width * zoom);
1831 double y = XFixedToDouble (yp) / (screen_info->height * zoom);
1832
1833 glTexParameteri(screen_info->texture_type,
1834 GL_TEXTURE_MIN_FILTER,
1835 screen_info->texture_filter);
1836 glTexParameteri(screen_info->texture_type,
1837 GL_TEXTURE_MAG_FILTER,
1838 screen_info->texture_filter);
1839
1840 set_glx_scale (screen_info, screen_info->width, screen_info->height, zoom);
1841 glTranslated (x, y, 0.0);
1842 }
1843 else
1844 {
1845 set_glx_scale (screen_info, screen_info->width, screen_info->height, 1.0);
1846 glTranslated (0.0, 0.0, 0.0);
1847 }
1848
1849 redraw_glx_screen (screen_info);
1850
1851 glXSwapBuffers (myScreenGetXDisplay (screen_info),
1852 screen_info->glx_window);
1853
1854 glPopMatrix();
1855
1856 unbind_glx_texture (screen_info, buffer);
1857
1858 if (screen_info->has_ext_arb_sync)
1859 {
1860 #if defined (glFenceSync)
1861 screen_info->gl_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1862 #else
1863 #warning glFenceSync() not supported by libepoxy, please update your version of libepoxy
1864 #endif
1865 }
1866
1867 #ifdef DEBUG
1868 t2 = g_get_monotonic_time ();
1869 DBG ("Swap buffer time %luμs", t2 - t1);
1870 #endif /* DEBUG */
1871
1872 check_gl_error();
1873 }
1874 #endif /* HAVE_EPOXY */
1875
1876 #ifdef HAVE_PRESENT_EXTENSION
1877 static void
present_error(ScreenInfo * screen_info,int error_code)1878 present_error (ScreenInfo *screen_info, int error_code)
1879 {
1880 char buf[64];
1881
1882 XGetErrorText (myScreenGetXDisplay (screen_info), error_code, buf, 63);
1883 g_warning ("Dismissing XPresent as unusable, error %i (%s)", error_code, buf);
1884
1885 screen_info->present_pending = FALSE;
1886 screen_info->use_present = FALSE;
1887 }
1888
1889 static void
present_flip(ScreenInfo * screen_info,XserverRegion region,gushort buffer)1890 present_flip (ScreenInfo *screen_info, XserverRegion region, gushort buffer)
1891 {
1892 static guint32 present_serial;
1893 DisplayInfo *display_info;
1894 int result;
1895
1896 g_return_if_fail (screen_info != NULL);
1897 g_return_if_fail (region != None);
1898 TRACE ("serial %d", present_serial);
1899
1900 display_info = screen_info->display_info;
1901 myDisplayErrorTrapPush (display_info);
1902 XPresentPixmap (display_info->dpy, screen_info->output,
1903 screen_info->rootPixmap[buffer],
1904 present_serial++, None, region, 0, 0, None, None, None,
1905 PresentOptionNone, 0, 1, 0, NULL, 0);
1906 result = myDisplayErrorTrapPop (display_info);
1907
1908 if (result != 0)
1909 {
1910 present_error (screen_info, result);
1911 return;
1912 }
1913
1914 screen_info->present_pending = TRUE;
1915 DBG ("present flip requested, present pending...");
1916 }
1917 #endif /* HAVE_PRESENT_EXTENSION */
1918
1919 static XserverRegion
win_extents(CWindow * cw)1920 win_extents (CWindow *cw)
1921 {
1922 DisplayInfo *display_info;
1923 ScreenInfo *screen_info;
1924 XRectangle r;
1925
1926 g_return_val_if_fail (cw != NULL, None);
1927 TRACE ("window 0x%lx", cw->id);
1928
1929 screen_info = cw->screen_info;
1930 display_info = screen_info->display_info;
1931 r.x = cw->attr.x;
1932 r.y = cw->attr.y;
1933 r.width = cw->attr.width + cw->attr.border_width * 2;
1934 r.height = cw->attr.height + cw->attr.border_width * 2;
1935
1936 /*
1937 We apply a shadow to the window if:
1938 - It's a window with a frame and the user asked for shadows under regular
1939 windows,
1940 - it's an override redirect window that is not shaped, not an argb and
1941 the user asked for shadows on so called "popup" windows.
1942 */
1943
1944 if ((screen_info->params->show_popup_shadow &&
1945 WIN_IS_OVERRIDE(cw) &&
1946 !(WIN_IS_ARGB(cw) || WIN_IS_SHAPED(cw)) &&
1947 !WIN_IS_FULLSCREEN(cw)) ||
1948 (screen_info->params->show_frame_shadow &&
1949 !WIN_IS_OVERRIDE(cw) &&
1950 !WIN_NO_SHADOW(cw) &&
1951 !WIN_IS_DOCK(cw) &&
1952 !WIN_IS_MAXIMIZED(cw) &&
1953 (WIN_HAS_FRAME(cw) || !(WIN_IS_ARGB(cw) || WIN_IS_SHAPED(cw)))) ||
1954 (screen_info->params->show_dock_shadow &&
1955 WIN_IS_DOCK(cw) &&
1956 !WIN_NO_SHADOW(cw) &&
1957 !WIN_IS_OVERRIDE(cw) &&
1958 (!WIN_IS_SHAPED(cw))))
1959 {
1960 XRectangle sr;
1961
1962 TRACE ("window 0x%lx has extents", cw->id);
1963 cw->shadow_dx = SHADOW_OFFSET_X + screen_info->params->shadow_delta_x;
1964 cw->shadow_dy = SHADOW_OFFSET_Y + screen_info->params->shadow_delta_y;
1965
1966 if (!(cw->shadow))
1967 {
1968 double shadow_opacity;
1969 shadow_opacity = (double) screen_info->params->frame_opacity
1970 * (screen_info->params->shadow_opacity / 100.0)
1971 * cw->opacity
1972 / (NET_WM_OPAQUE * 100.0);
1973
1974 cw->shadow = shadow_picture (screen_info, shadow_opacity,
1975 cw->attr.width + 2 * cw->attr.border_width,
1976 cw->attr.height + 2 * cw->attr.border_width,
1977 &cw->shadow_width, &cw->shadow_height);
1978 }
1979
1980 sr.x = cw->attr.x + cw->shadow_dx;
1981 sr.y = cw->attr.y + cw->shadow_dy;
1982 sr.width = cw->shadow_width;
1983 sr.height = cw->shadow_height;
1984
1985 if (sr.x < r.x)
1986 {
1987 r.width = (r.x + r.width) - sr.x;
1988 r.x = sr.x;
1989 }
1990 if (sr.y < r.y)
1991 {
1992 r.height = (r.y + r.height) - sr.y;
1993 r.y = sr.y;
1994 }
1995 if (sr.x + sr.width > r.x + r.width)
1996 {
1997 r.width = sr.x + sr.width - r.x;
1998 }
1999 if (sr.y + sr.height > r.y + r.height)
2000 {
2001 r.height = sr.y + sr.height - r.y;
2002 }
2003 }
2004 else if (cw->shadow)
2005 {
2006 XRenderFreePicture (display_info->dpy, cw->shadow);
2007 cw->shadow = None;
2008 }
2009 return XFixesCreateRegion (display_info->dpy, &r, 1);
2010 }
2011
2012 static void
get_paint_bounds(CWindow * cw,gint * x,gint * y,guint * w,guint * h)2013 get_paint_bounds (CWindow *cw, gint *x, gint *y, guint *w, guint *h)
2014 {
2015 g_return_if_fail (cw != NULL);
2016 TRACE ("window 0x%lx", cw->id);
2017
2018 #if HAVE_NAME_WINDOW_PIXMAP
2019 *x = cw->attr.x;
2020 *y = cw->attr.y;
2021 *w = cw->attr.width + 2 * cw->attr.border_width;
2022 *h = cw->attr.height + 2 * cw->attr.border_width;
2023 #else
2024 *x = cw->attr.x + cw->attr.border_width;
2025 *y = cw->attr.y + cw->attr.border_width;
2026 *w = cw->attr.width;
2027 *h = cw->attr.height;
2028 #endif
2029 }
2030
2031 static XRenderPictFormat *
get_window_format(CWindow * cw)2032 get_window_format (CWindow *cw)
2033 {
2034 DisplayInfo *display_info;
2035 ScreenInfo *screen_info;
2036 XRenderPictFormat *format;
2037
2038 g_return_val_if_fail (cw != NULL, NULL);
2039 TRACE ("window 0x%lx", cw->id);
2040
2041 screen_info = cw->screen_info;
2042 display_info = screen_info->display_info;
2043 format = XRenderFindVisualFormat (display_info->dpy, cw->attr.visual);
2044 if (!format)
2045 {
2046 format = XRenderFindVisualFormat (display_info->dpy,
2047 DefaultVisual (display_info->dpy,
2048 screen_info->screen));
2049 }
2050
2051 return format;
2052 }
2053
2054 static Picture
get_window_picture(CWindow * cw)2055 get_window_picture (CWindow *cw)
2056 {
2057 DisplayInfo *display_info;
2058 ScreenInfo *screen_info;
2059 XRenderPictureAttributes pa;
2060 XRenderPictFormat *format;
2061 Drawable draw;
2062
2063 g_return_val_if_fail (cw != NULL, None);
2064 TRACE ("window 0x%lx", cw->id);
2065
2066 draw = cw->id;
2067 screen_info = cw->screen_info;
2068 display_info = screen_info->display_info;
2069
2070 #if HAVE_NAME_WINDOW_PIXMAP
2071 myDisplayErrorTrapPush (display_info);
2072 if ((display_info->have_name_window_pixmap) && (cw->name_window_pixmap == None))
2073 {
2074 cw->name_window_pixmap = XCompositeNameWindowPixmap (display_info->dpy, cw->id);
2075 }
2076 if ((myDisplayErrorTrapPop (display_info) == Success) && (cw->name_window_pixmap != None))
2077 {
2078 draw = cw->name_window_pixmap;
2079 }
2080 #endif
2081 format = get_window_format (cw);
2082 if (format)
2083 {
2084 Picture pict;
2085
2086 myDisplayErrorTrapPush (display_info);
2087 pa.subwindow_mode = IncludeInferiors;
2088 pict = XRenderCreatePicture (display_info->dpy, draw, format, CPSubwindowMode, &pa);
2089 if (myDisplayErrorTrapPop (display_info) == Success)
2090 {
2091 return pict;
2092 }
2093 }
2094
2095 return None;
2096 }
2097
2098 static XserverRegion
get_screen_region(ScreenInfo * screen_info)2099 get_screen_region (ScreenInfo *screen_info)
2100 {
2101 DisplayInfo *display_info;
2102 XserverRegion region;
2103 XRectangle r;
2104
2105 display_info = screen_info->display_info;
2106 if (screen_info->width > 0 && screen_info->height > 0)
2107 {
2108 r.x = 0;
2109 r.y = 0;
2110 r.width = screen_info->width;
2111 r.height = screen_info->height;
2112 region = XFixesCreateRegion (display_info->dpy, &r, 1);
2113 }
2114 else
2115 {
2116 region = XFixesCreateRegion (display_info->dpy, NULL, 0);
2117 }
2118
2119 return region;
2120 }
2121
2122 static void
unredirect_win(CWindow * cw)2123 unredirect_win (CWindow *cw)
2124 {
2125 ScreenInfo *screen_info;
2126 DisplayInfo *display_info;
2127
2128 g_return_if_fail (cw != NULL);
2129 TRACE ("window 0x%lx", cw->id);
2130
2131 if (WIN_IS_REDIRECTED(cw))
2132 {
2133 screen_info = cw->screen_info;
2134 display_info = screen_info->display_info;
2135
2136 myDisplayErrorTrapPush (display_info);
2137 XCompositeUnredirectWindow (display_info->dpy, cw->id, CompositeRedirectManual);
2138 myDisplayErrorTrapPopIgnored (display_info);
2139
2140 free_win_data (cw, FALSE);
2141 cw->redirected = FALSE;
2142 TRACE ("window 0x%lx unredirected, wins_unredirected is %i",
2143 cw->id, screen_info->wins_unredirected);
2144 }
2145 }
2146
2147 static void
paint_root(ScreenInfo * screen_info,Picture paint_buffer)2148 paint_root (ScreenInfo *screen_info, Picture paint_buffer)
2149 {
2150 g_return_if_fail (screen_info != NULL);
2151 TRACE ("entering");
2152
2153 if (screen_info->rootTile == None)
2154 {
2155 screen_info->rootTile = root_tile (screen_info);
2156 g_return_if_fail (screen_info->rootTile != None);
2157 }
2158
2159 XRenderComposite (myScreenGetXDisplay (screen_info),
2160 PictOpSrc,
2161 screen_info->rootTile,
2162 None, paint_buffer,
2163 0, 0, 0, 0, 0, 0,
2164 screen_info->width,
2165 screen_info->height);
2166 }
2167
2168 static void
paint_cursor(ScreenInfo * screen_info,XserverRegion region,Picture paint_buffer)2169 paint_cursor (ScreenInfo *screen_info, XserverRegion region, Picture paint_buffer)
2170 {
2171 XFixesSetPictureClipRegion (myScreenGetXDisplay (screen_info),
2172 paint_buffer, 0, 0, region);
2173 XRenderComposite (myScreenGetXDisplay (screen_info),
2174 PictOpOver,
2175 screen_info->cursorPicture,
2176 None, paint_buffer,
2177 0, 0, 0, 0,
2178 screen_info->cursorLocation.x,
2179 screen_info->cursorLocation.y,
2180 screen_info->cursorLocation.width,
2181 screen_info->cursorLocation.height);
2182 }
2183
2184 static void
paint_win(CWindow * cw,XserverRegion region,Picture paint_buffer,gboolean solid_part)2185 paint_win (CWindow *cw, XserverRegion region, Picture paint_buffer, gboolean solid_part)
2186 {
2187 ScreenInfo *screen_info;
2188 DisplayInfo *display_info;
2189 gboolean paint_solid;
2190
2191 g_return_if_fail (cw != NULL);
2192 TRACE ("window 0x%lx", cw->id);
2193
2194 screen_info = cw->screen_info;
2195 display_info = screen_info->display_info;
2196 paint_solid = (solid_part && WIN_IS_OPAQUE(cw));
2197
2198 if (WIN_HAS_FRAME(cw) && (screen_info->params->frame_opacity < 100))
2199 {
2200 int frame_x, frame_y, frame_width, frame_height;
2201 int frame_top, frame_bottom, frame_left, frame_right;
2202 frame_x = cw->attr.x;
2203 frame_y = cw->attr.y;
2204 frame_width = cw->attr.width;
2205 frame_height = cw->attr.height;
2206 frame_top = frameTop (cw->c);
2207 frame_bottom = frameBottom (cw->c);
2208 frame_left = frameLeft (cw->c);
2209 frame_right = frameRight (cw->c);
2210 if (!solid_part)
2211 {
2212 if (!cw->alphaBorderPict)
2213 {
2214 double frame_opacity;
2215 frame_opacity = (double) cw->opacity
2216 * screen_info->params->frame_opacity
2217 / (NET_WM_OPAQUE * 100.0);
2218
2219 cw->alphaBorderPict = solid_picture (screen_info,
2220 FALSE,
2221 frame_opacity,
2222 0.0, /* red */
2223 0.0, /* green */
2224 0.0 /* blue */);
2225 }
2226
2227 /* Top Border (title bar) */
2228 XRenderComposite (display_info->dpy, PictOpOver, cw->picture, cw->alphaBorderPict,
2229 paint_buffer,
2230 0, 0,
2231 0, 0,
2232 frame_x, frame_y,
2233 frame_width, frame_top);
2234
2235 /* Bottom Border */
2236 XRenderComposite (display_info->dpy, PictOpOver, cw->picture, cw->alphaBorderPict,
2237 paint_buffer,
2238 0, frame_height - frame_bottom,
2239 0, 0,
2240 frame_x, frame_y + frame_height - frame_bottom,
2241 frame_width, frame_bottom);
2242 /* Left Border */
2243 XRenderComposite (display_info->dpy, PictOpOver, cw->picture, cw->alphaBorderPict,
2244 paint_buffer,
2245 0, frame_top,
2246 0, 0,
2247 frame_x, frame_y + frame_top,
2248 frame_left, frame_height - frame_top - frame_bottom);
2249
2250 /* Right Border */
2251 XRenderComposite (display_info->dpy, PictOpOver, cw->picture, cw->alphaBorderPict,
2252 paint_buffer,
2253 frame_width - frame_right, frame_top,
2254 0, 0,
2255 frame_x + frame_width - frame_right,
2256 frame_y + frame_top, frame_right,
2257 frame_height - frame_top - frame_bottom);
2258 }
2259 /* Client Window */
2260 if (paint_solid)
2261 {
2262 XFixesSetPictureClipRegion (display_info->dpy, paint_buffer, 0, 0, region);
2263 XRenderComposite (display_info->dpy, PictOpSrc, cw->picture, None,
2264 paint_buffer,
2265 frame_left, frame_top,
2266 0, 0,
2267 frame_x + frame_left, frame_y + frame_top,
2268 frame_width - frame_left - frame_right, frame_height - frame_top - frame_bottom);
2269
2270 /* clientSize is set in paint_all() prior to calling paint_win() */
2271 XFixesSubtractRegion (display_info->dpy, region, region, cw->clientSize);
2272 }
2273 else if (!solid_part)
2274 {
2275 XRenderComposite (display_info->dpy, PictOpOver, cw->picture, cw->alphaPict,
2276 paint_buffer,
2277 frame_left, frame_top,
2278 0, 0,
2279 frame_x + frame_left, frame_y + frame_top,
2280 frame_width - frame_left - frame_right, frame_height - frame_top - frame_bottom);
2281 }
2282 }
2283 else
2284 {
2285 gint x, y;
2286 guint w, h;
2287
2288 get_paint_bounds (cw, &x, &y, &w, &h);
2289 if (paint_solid)
2290 {
2291 XFixesSetPictureClipRegion (display_info->dpy, paint_buffer, 0, 0, region);
2292 XRenderComposite (display_info->dpy, PictOpSrc,
2293 cw->picture, None,
2294 paint_buffer,
2295 0, 0, 0, 0, x, y, w, h);
2296 XFixesSubtractRegion (display_info->dpy, region, region, cw->borderSize);
2297 }
2298 else if (!solid_part)
2299 {
2300 XRenderComposite (display_info->dpy, PictOpOver,
2301 cw->picture, cw->alphaPict,
2302 paint_buffer,
2303 0, 0, 0, 0, x, y, w, h);
2304 }
2305 }
2306 }
2307
2308 static void
clip_opaque_region(CWindow * cw,XserverRegion region)2309 clip_opaque_region (CWindow *cw, XserverRegion region)
2310 {
2311 ScreenInfo *screen_info;
2312 DisplayInfo *display_info;
2313 XserverRegion opaque_region;
2314
2315 g_return_if_fail (cw != NULL);
2316 TRACE ("window 0x%lx", cw->id);
2317
2318 if (cw->opaque_region == None)
2319 {
2320 TRACE ("window 0x%lx has no opaque region", cw->id);
2321 return;
2322 }
2323
2324 screen_info = cw->screen_info;
2325 display_info = screen_info->display_info;
2326
2327 opaque_region = XFixesCreateRegion (display_info->dpy, NULL, 0);
2328 XFixesCopyRegion (display_info->dpy, opaque_region, cw->opaque_region);
2329 translate_to_client_region (cw, opaque_region);
2330 /* cw->borderSize and cw->clientSize are already updated in paint_all() */
2331 if (cw->clientSize)
2332 {
2333 XFixesIntersectRegion (display_info->dpy, opaque_region, opaque_region, cw->clientSize);
2334 }
2335 XFixesIntersectRegion (display_info->dpy, opaque_region, opaque_region, cw->borderSize);
2336 XFixesSubtractRegion (display_info->dpy, region, region, opaque_region);
2337 XFixesDestroyRegion (display_info->dpy, opaque_region);
2338 }
2339
2340 static int
get_region_bounds(Display * dpy,XserverRegion region,XRectangle * bounds)2341 get_region_bounds (Display *dpy, XserverRegion region, XRectangle *bounds)
2342 {
2343 XRectangle *rects;
2344 int nrects;
2345
2346 rects = XFixesFetchRegionAndBounds (dpy, region, &nrects, bounds);
2347 XFree (rects);
2348
2349 return nrects;
2350 }
2351
2352 static gboolean
is_region_empty(Display * dpy,XserverRegion region)2353 is_region_empty (Display *dpy, XserverRegion region)
2354 {
2355 XRectangle bounds;
2356 int nrects;
2357
2358 nrects = get_region_bounds (dpy, region, &bounds);
2359
2360 return (nrects == 0 || bounds.width == 0 || bounds.height == 0);
2361 }
2362
2363 static void
paint_all(ScreenInfo * screen_info,XserverRegion region,gushort buffer)2364 paint_all (ScreenInfo *screen_info, XserverRegion region, gushort buffer)
2365 {
2366 DisplayInfo *display_info;
2367 XserverRegion paint_region;
2368 XRectangle region_bounds;
2369 Picture paint_buffer;
2370 Display *dpy;
2371 GList *list;
2372 gint screen_width;
2373 gint screen_height;
2374 CWindow *cw;
2375
2376 TRACE ("buffer %d", buffer);
2377 g_return_if_fail (screen_info);
2378
2379 display_info = screen_info->display_info;
2380 dpy = display_info->dpy;
2381 screen_width = screen_info->width;
2382 screen_height = screen_info->height;
2383
2384 myDisplayErrorTrapPush (display_info);
2385
2386 /* Create root buffer if not done yet */
2387 if (screen_info->rootPixmap[buffer] == None)
2388 {
2389 screen_info->rootPixmap[buffer] = create_root_pixmap (screen_info);
2390 #ifdef HAVE_EPOXY
2391 if (screen_info->use_glx)
2392 {
2393 fence_create (screen_info, buffer);
2394 }
2395 #endif /* HAVE_EPOXY */
2396 }
2397
2398 if (screen_info->rootBuffer[buffer] == None)
2399 {
2400 screen_info->rootBuffer[buffer] =
2401 create_root_buffer (screen_info, screen_info->rootPixmap[buffer]);
2402 }
2403
2404 if (screen_info->zoomed && !screen_info->use_glx)
2405 {
2406 if (screen_info->zoomBuffer == None)
2407 {
2408 Pixmap pixmap;
2409
2410 pixmap = create_root_pixmap (screen_info);
2411 screen_info->zoomBuffer = create_root_buffer (screen_info, pixmap);
2412 XFreePixmap (display_info->dpy, pixmap);
2413 }
2414 paint_buffer = screen_info->zoomBuffer;
2415 }
2416 else
2417 {
2418 paint_buffer = screen_info->rootBuffer[buffer];
2419 }
2420 /* Copy the original given region */
2421 paint_region = XFixesCreateRegion (dpy, NULL, 0);
2422 XFixesCopyRegion (dpy, paint_region, region);
2423
2424 /*
2425 * Painting from top to bottom, reducing the clipping area at each iteration.
2426 * Only the opaque windows are painted 1st.
2427 */
2428 for (list = screen_info->cwindows; list; list = g_list_next (list))
2429 {
2430 cw = (CWindow *) list->data;
2431 TRACE ("painting forward 0x%lx", cw->id);
2432 if (!WIN_IS_VISIBLE(cw) || !WIN_IS_DAMAGED(cw))
2433 {
2434 TRACE ("skipped, not damaged or not viewable 0x%lx", cw->id);
2435 cw->skipped = TRUE;
2436 continue;
2437 }
2438
2439 if (!WIN_IS_REDIRECTED(cw))
2440 {
2441 TRACE ("skipped, not redirected 0x%lx", cw->id);
2442 cw->skipped = TRUE;
2443 continue;
2444 }
2445
2446 if ((cw->attr.x + cw->attr.width < 1) || (cw->attr.y + cw->attr.height < 1) ||
2447 (cw->attr.x >= screen_width) || (cw->attr.y >= screen_height))
2448 {
2449 TRACE ("skipped, off screen 0x%lx", cw->id);
2450 cw->skipped = TRUE;
2451 continue;
2452 }
2453
2454 if (cw->extents == None)
2455 {
2456 cw->extents = win_extents (cw);
2457 }
2458 if (cw->picture == None)
2459 {
2460 cw->picture = get_window_picture (cw);
2461 }
2462 if (cw->borderSize == None)
2463 {
2464 cw->borderSize = border_size (cw);
2465 }
2466 if (cw->clientSize == None)
2467 {
2468 cw->clientSize = client_size (cw);
2469 }
2470 if (WIN_IS_OPAQUE(cw))
2471 {
2472 paint_win (cw, paint_region, paint_buffer, TRUE);
2473 }
2474
2475 if (cw->borderClip == None)
2476 {
2477 cw->borderClip = XFixesCreateRegion (dpy, NULL, 0);
2478 XFixesCopyRegion (dpy, cw->borderClip, paint_region);
2479 }
2480
2481 if ((cw->opacity == NET_WM_OPAQUE) && !WIN_IS_SHADED(cw))
2482 {
2483 clip_opaque_region (cw, paint_region);
2484 }
2485
2486 cw->skipped = FALSE;
2487 }
2488
2489 /*
2490 * region has changed because of the XFixesSubtractRegion (),
2491 * reapply clipping for the last iteration.
2492 */
2493 XFixesSetPictureClipRegion (dpy, paint_buffer, 0, 0, paint_region);
2494 if (!is_region_empty (dpy, paint_region))
2495 {
2496 paint_root (screen_info, paint_buffer);
2497 }
2498
2499 /*
2500 * Painting from bottom to top, translucent windows and shadows are painted now...
2501 */
2502 for (list = g_list_last(screen_info->cwindows); list; list = g_list_previous (list))
2503 {
2504 XserverRegion shadowClip;
2505
2506 cw = (CWindow *) list->data;
2507 shadowClip = None;
2508 TRACE ("painting backward 0x%lx", cw->id);
2509
2510 if (cw->skipped)
2511 {
2512 TRACE ("skipped 0x%lx", cw->id);
2513 continue;
2514 }
2515
2516 if (cw->shadow)
2517 {
2518 shadowClip = XFixesCreateRegion (dpy, NULL, 0);
2519 XFixesSubtractRegion (dpy, shadowClip, cw->borderClip, cw->borderSize);
2520
2521 XFixesSetPictureClipRegion (dpy, paint_buffer, 0, 0, shadowClip);
2522 XRenderComposite (dpy, PictOpOver, screen_info->blackPicture, cw->shadow,
2523 paint_buffer, 0, 0, 0, 0,
2524 cw->attr.x + cw->shadow_dx,
2525 cw->attr.y + cw->shadow_dy,
2526 cw->shadow_width, cw->shadow_height);
2527 }
2528
2529 if (cw->picture)
2530 {
2531 if ((cw->opacity != NET_WM_OPAQUE) && !(cw->alphaPict))
2532 {
2533 cw->alphaPict = solid_picture (screen_info, FALSE,
2534 (double) cw->opacity / NET_WM_OPAQUE,
2535 0.0, /* red */
2536 0.0, /* green */
2537 0.0 /* blue */);
2538 }
2539 XFixesIntersectRegion (dpy, cw->borderClip, cw->borderClip, cw->borderSize);
2540 XFixesSetPictureClipRegion (dpy, paint_buffer, 0, 0, cw->borderClip);
2541 paint_win (cw, paint_region, paint_buffer, FALSE);
2542 }
2543
2544 if (shadowClip)
2545 {
2546 XFixesDestroyRegion (dpy, shadowClip);
2547 }
2548
2549 if (cw->borderClip)
2550 {
2551 XFixesDestroyRegion (dpy, cw->borderClip);
2552 cw->borderClip = None;
2553 }
2554 }
2555
2556 TRACE ("copying data back to screen");
2557 #ifdef HAVE_EPOXY
2558 if (screen_info->use_glx)
2559 {
2560 if (screen_info->zoomed && screen_info->cursor_is_zoomed)
2561 {
2562 paint_cursor (screen_info, region, paint_buffer);
2563 }
2564 fence_reset (screen_info, buffer);
2565 }
2566 else
2567 #endif /* HAVE_EPOXY */
2568 {
2569 if (screen_info->zoomed)
2570 {
2571 if (screen_info->cursor_is_zoomed)
2572 {
2573 paint_cursor (screen_info, region, paint_buffer);
2574 }
2575 /* Fixme: copy back whole screen if zoomed
2576 It would be better to scale the clipping region if possible. */
2577 XFixesSetPictureClipRegion (dpy, screen_info->rootBuffer[buffer], 0, 0, None);
2578 XFixesSetPictureClipRegion (dpy, paint_buffer, 0, 0, None);
2579 }
2580 else
2581 {
2582 /* Set clipping back to the given region */
2583 XFixesSetPictureClipRegion (dpy, screen_info->rootBuffer[buffer], 0, 0, region);
2584 }
2585 }
2586
2587 #ifdef HAVE_PRESENT_EXTENSION
2588 if (screen_info->use_present)
2589 {
2590 if (screen_info->zoomed)
2591 {
2592 XRenderComposite (dpy, PictOpSrc,
2593 screen_info->zoomBuffer,
2594 None, screen_info->rootBuffer[buffer],
2595 0, 0, 0, 0, 0, 0, screen_width, screen_height);
2596 }
2597 present_flip (screen_info, region, buffer);
2598 }
2599 else
2600 #endif /* HAVE_PRESENT_EXTENSION */
2601 #ifdef HAVE_EPOXY
2602 if (screen_info->use_glx)
2603 {
2604 redraw_glx_texture (screen_info, buffer);
2605 }
2606 else
2607 #endif /* HAVE_EPOXY */
2608 {
2609 if (screen_info->zoomed)
2610 {
2611 XRenderComposite (dpy, PictOpSrc,
2612 screen_info->zoomBuffer,
2613 None, screen_info->rootPicture,
2614 0, 0, 0, 0, 0, 0, screen_width, screen_height);
2615 }
2616 else
2617 {
2618 get_region_bounds (dpy, region, ®ion_bounds);
2619 XRenderComposite (dpy, PictOpSrc, paint_buffer,
2620 None, screen_info->rootPicture,
2621 region_bounds.x, region_bounds.y,
2622 region_bounds.x, region_bounds.y,
2623 region_bounds.x, region_bounds.y,
2624 region_bounds.width, region_bounds.height);
2625 }
2626 XFlush (dpy);
2627 }
2628
2629 XFixesDestroyRegion (dpy, paint_region);
2630
2631 myDisplayErrorTrapPopIgnored (display_info);
2632 }
2633
2634 static void
remove_timeouts(ScreenInfo * screen_info)2635 remove_timeouts (ScreenInfo *screen_info)
2636 {
2637 if (screen_info->compositor_timeout_id != 0)
2638 {
2639 g_source_remove (screen_info->compositor_timeout_id);
2640 screen_info->compositor_timeout_id = 0;
2641 }
2642 }
2643
2644 static gboolean
repair_screen(ScreenInfo * screen_info)2645 repair_screen (ScreenInfo *screen_info)
2646 {
2647 DisplayInfo *display_info;
2648 XserverRegion damage;
2649
2650 g_return_val_if_fail (screen_info, FALSE);
2651 TRACE ("entering");
2652
2653 if (!screen_info->compositor_active)
2654 {
2655 return FALSE;
2656 }
2657
2658 if (screen_info->width == 0 || screen_info->height == 0)
2659 {
2660 return FALSE;
2661 }
2662
2663 #ifdef HAVE_PRESENT_EXTENSION
2664 /*
2665 * We do not paint the screen because we are waiting for
2666 * a pending present notification, do not cancel the callback yet...
2667 */
2668 if (screen_info->use_present && screen_info->present_pending)
2669 {
2670 DBG ("Waiting for Present");
2671 return (screen_info->allDamage != None);
2672 }
2673 #endif /* HAVE_PRESENT_EXTENSION */
2674
2675 #ifdef HAVE_EPOXY
2676 /*
2677 * We do not paint the screen because we are waiting for
2678 * the GL pipeline to complete, do not cancel the callback yet...
2679 */
2680 if (screen_info->use_glx && screen_info->gl_sync)
2681 {
2682 #if defined (GL_SIGNALED)
2683 GLint status = GL_SIGNALED;
2684 #if defined (glGetSynciv)
2685 glGetSynciv(screen_info->gl_sync, GL_SYNC_STATUS, sizeof(GLint), NULL, &status);
2686 #else
2687 #warning glGetSynciv() not supported by libepoxy, please update your version of libepoxy
2688 #endif
2689 if (status != GL_SIGNALED)
2690 {
2691 DBG ("Waiting for GL pipeline");
2692 return (screen_info->allDamage != None);
2693 }
2694 }
2695 #else
2696 #warning GL_SIGNALED not supported by libepoxy, please update your version of libepoxy
2697 #endif
2698 #endif /* HAVE_EPOXY */
2699 display_info = screen_info->display_info;
2700 damage = screen_info->allDamage;
2701 if (damage)
2702 {
2703 if (screen_info->use_n_buffers > 1)
2704 {
2705 if (screen_info->prevDamage)
2706 {
2707 XFixesUnionRegion(display_info->dpy,
2708 screen_info->prevDamage,
2709 screen_info->prevDamage,
2710 damage);
2711 damage = screen_info->prevDamage;
2712 }
2713 }
2714
2715 remove_timeouts (screen_info);
2716 paint_all (screen_info, damage, screen_info->current_buffer);
2717
2718 if (screen_info->use_n_buffers > 1)
2719 {
2720 screen_info->current_buffer =
2721 (screen_info->current_buffer + 1) % screen_info->use_n_buffers;
2722
2723 if (screen_info->prevDamage)
2724 {
2725 XFixesDestroyRegion (display_info->dpy, screen_info->prevDamage);
2726 }
2727
2728 screen_info->prevDamage = screen_info->allDamage;
2729 }
2730 else
2731 {
2732 XFixesDestroyRegion (display_info->dpy, screen_info->allDamage);
2733 }
2734 screen_info->allDamage = None;
2735 }
2736
2737 return FALSE;
2738 }
2739
2740 static gboolean
compositor_timeout_cb(gpointer data)2741 compositor_timeout_cb (gpointer data)
2742 {
2743 ScreenInfo *screen_info;
2744
2745 screen_info = (ScreenInfo *) data;
2746 screen_info->compositor_timeout_id = 0;
2747 return repair_screen (screen_info);
2748 }
2749
2750 static void
add_repair(ScreenInfo * screen_info)2751 add_repair (ScreenInfo *screen_info)
2752 {
2753 if (screen_info->compositor_timeout_id == 0)
2754 {
2755 screen_info->compositor_timeout_id =
2756 g_timeout_add_full (G_PRIORITY_DEFAULT + TIMEOUT_REPAINT_PRIORITY,
2757 TIMEOUT_REPAINT_MS,
2758 compositor_timeout_cb, screen_info, NULL);
2759 }
2760 }
2761
2762 static void
add_damage(ScreenInfo * screen_info,XserverRegion damage)2763 add_damage (ScreenInfo *screen_info, XserverRegion damage)
2764 {
2765 DisplayInfo *display_info;
2766
2767 TRACE ("entering");
2768
2769 if (damage == None)
2770 {
2771 return;
2772 }
2773
2774 if (screen_info->screenRegion == None)
2775 {
2776 screen_info->screenRegion = get_screen_region (screen_info);
2777 }
2778
2779 display_info = screen_info->display_info;
2780 XFixesIntersectRegion (display_info->dpy,
2781 damage,
2782 damage,
2783 screen_info->screenRegion);
2784 if (screen_info->allDamage != None)
2785 {
2786 XFixesUnionRegion (display_info->dpy,
2787 screen_info->allDamage,
2788 screen_info->allDamage,
2789 damage);
2790 XFixesDestroyRegion (display_info->dpy, damage);
2791 }
2792 else
2793 {
2794 screen_info->allDamage = damage;
2795 }
2796
2797 /* The per-screen allDamage region is freed by repair_screen () */
2798 add_repair (screen_info);
2799 }
2800
2801 static void
fix_region(CWindow * cw,XserverRegion region)2802 fix_region (CWindow *cw, XserverRegion region)
2803 {
2804 GList *list;
2805 ScreenInfo *screen_info;
2806 DisplayInfo *display_info;
2807
2808 screen_info = cw->screen_info;
2809 display_info = screen_info->display_info;
2810
2811 /* Exclude opaque windows in front of the given area */
2812 for (list = screen_info->cwindows; list; list = g_list_next (list))
2813 {
2814 CWindow *cw2;
2815
2816 cw2 = (CWindow *) list->data;
2817 if (cw2 == cw)
2818 {
2819 break;
2820 }
2821 else if (WIN_IS_OPAQUE(cw2) && WIN_IS_VISIBLE(cw2))
2822 {
2823 /* Make sure the window's areas are up-to-date... */
2824 if (cw2->picture == None)
2825 {
2826 cw2->picture = get_window_picture (cw2);
2827 }
2828 if (cw2->borderSize == None)
2829 {
2830 cw2->borderSize = border_size (cw2);
2831 }
2832 if (cw2->clientSize == None)
2833 {
2834 cw2->clientSize = client_size (cw2);
2835 }
2836 /* ...before subtracting them from the damaged zone. */
2837 if ((cw2->clientSize) && (screen_info->params->frame_opacity < 100))
2838 {
2839 XFixesSubtractRegion (display_info->dpy, region,
2840 region, cw2->clientSize);
2841 }
2842 else if (cw2->borderSize)
2843 {
2844 XFixesSubtractRegion (display_info->dpy, region,
2845 region, cw2->borderSize);
2846 }
2847 }
2848 }
2849 }
2850
2851 static void
repair_win(CWindow * cw,XRectangle * r)2852 repair_win (CWindow *cw, XRectangle *r)
2853 {
2854 DisplayInfo *display_info;
2855 ScreenInfo *screen_info;
2856 XserverRegion parts;
2857
2858 g_return_if_fail (cw != NULL);
2859
2860 TRACE ("entering");
2861 screen_info = cw->screen_info;
2862 display_info = screen_info->display_info;
2863
2864 if (!(cw->damage))
2865 {
2866 /* Input Only have no damage */
2867 return;
2868 }
2869
2870 myDisplayErrorTrapPush (display_info);
2871 if (cw->damaged)
2872 {
2873 parts = XFixesCreateRegion (display_info->dpy, NULL, 0);
2874 /* Copy the damage region to parts, subtracting it from the window's damage */
2875 XDamageSubtract (display_info->dpy, cw->damage, None, parts);
2876 XFixesTranslateRegion (display_info->dpy, parts,
2877 cw->attr.x + cw->attr.border_width,
2878 cw->attr.y + cw->attr.border_width);
2879 }
2880 else
2881 {
2882 parts = win_extents (cw);
2883 /* Subtract all damage from the window's damage */
2884 XDamageSubtract (display_info->dpy, cw->damage, None, None);
2885 }
2886 myDisplayErrorTrapPopIgnored (display_info);
2887
2888 if (parts)
2889 {
2890 fix_region (cw, parts);
2891 /* parts region will be destroyed by add_damage () */
2892 add_damage (cw->screen_info, parts);
2893 cw->damaged = TRUE;
2894 }
2895 }
2896
2897 static void
damage_screen(ScreenInfo * screen_info)2898 damage_screen (ScreenInfo *screen_info)
2899 {
2900 XserverRegion region;
2901
2902 region = get_screen_region (screen_info);
2903 /* region will be freed by add_damage () */
2904 add_damage (screen_info, region);
2905 }
2906
2907 static void
damage_win(CWindow * cw)2908 damage_win (CWindow *cw)
2909 {
2910 XserverRegion extents;
2911
2912 g_return_if_fail (cw != NULL);
2913 TRACE ("window 0x%lx", cw->id);
2914
2915 extents = win_extents (cw);
2916 fix_region (cw, extents);
2917 /* extents region will be freed by add_damage () */
2918 add_damage (cw->screen_info, extents);
2919 }
2920
2921 static void
update_extents(CWindow * cw)2922 update_extents (CWindow *cw)
2923 {
2924 DisplayInfo *display_info;
2925 ScreenInfo *screen_info;
2926
2927 g_return_if_fail (cw != NULL);
2928 TRACE ("window 0x%lx", cw->id);
2929
2930 screen_info = cw->screen_info;
2931 display_info = screen_info->display_info;
2932
2933 if (WIN_IS_VISIBLE(cw))
2934 {
2935 damage_win (cw);
2936 }
2937
2938 if (cw->extents)
2939 {
2940 XFixesDestroyRegion (display_info->dpy, cw->extents);
2941 cw->extents = None;
2942 }
2943 }
2944
2945 static void
determine_mode(CWindow * cw)2946 determine_mode (CWindow *cw)
2947 {
2948 DisplayInfo *display_info;
2949 ScreenInfo *screen_info;
2950 XRenderPictFormat *format;
2951
2952 g_return_if_fail (cw != NULL);
2953 TRACE ("window 0x%lx", cw->id);
2954
2955 screen_info = cw->screen_info;
2956 display_info = screen_info->display_info;
2957 format = NULL;
2958
2959 if (cw->alphaPict)
2960 {
2961 XRenderFreePicture (display_info->dpy, cw->alphaPict);
2962 cw->alphaPict = None;
2963 }
2964 if (cw->shadowPict)
2965 {
2966 XRenderFreePicture (display_info->dpy, cw->shadowPict);
2967 cw->shadowPict = None;
2968 }
2969
2970 if (cw->alphaBorderPict)
2971 {
2972 XRenderFreePicture (display_info->dpy, cw->alphaBorderPict);
2973 cw->alphaBorderPict = None;
2974 }
2975
2976 format = XRenderFindVisualFormat (display_info->dpy, cw->attr.visual);
2977 cw->argb = ((format) && (format->type == PictTypeDirect) && (format->direct.alphaMask));
2978
2979 if (cw->extents)
2980 {
2981 XserverRegion damage;
2982
2983 damage = XFixesCreateRegion (display_info->dpy, NULL, 0);
2984 XFixesCopyRegion (display_info->dpy, damage, cw->extents);
2985 fix_region (cw, damage);
2986 /* damage region will be destroyed by add_damage () */
2987 add_damage (screen_info, damage);
2988 }
2989 }
2990
2991 static void
expose_area(ScreenInfo * screen_info,XRectangle * rects,gint nrects)2992 expose_area (ScreenInfo *screen_info, XRectangle *rects, gint nrects)
2993 {
2994 DisplayInfo *display_info;
2995 XserverRegion region;
2996
2997 g_return_if_fail (rects != NULL);
2998 g_return_if_fail (nrects > 0);
2999 TRACE ("entering");
3000
3001 display_info = screen_info->display_info;
3002 region = XFixesCreateRegion (display_info->dpy, rects, nrects);
3003 /* region will be destroyed by add_damage () */
3004 add_damage (screen_info, region);
3005 }
3006
3007 static void
set_win_opacity(CWindow * cw,guint32 opacity)3008 set_win_opacity (CWindow *cw, guint32 opacity)
3009 {
3010 DisplayInfo *display_info;
3011 ScreenInfo *screen_info;
3012
3013 g_return_if_fail (cw != NULL);
3014 TRACE ("window 0x%lx", cw->id);
3015
3016 screen_info = cw->screen_info;
3017 display_info = screen_info->display_info;
3018
3019 cw->opacity = opacity;
3020 determine_mode(cw);
3021 if (cw->shadow)
3022 {
3023 XRenderFreePicture (display_info->dpy, cw->shadow);
3024 cw->shadow = None;
3025 if (cw->extents)
3026 {
3027 XFixesDestroyRegion (display_info->dpy, cw->extents);
3028 }
3029 cw->extents = win_extents (cw);
3030 add_repair (screen_info);
3031 }
3032 }
3033
3034 static void
map_win(CWindow * cw)3035 map_win (CWindow *cw)
3036 {
3037 ScreenInfo *screen_info;
3038 DisplayInfo *display_info;
3039
3040 g_return_if_fail (cw != NULL);
3041 TRACE ("window 0x%lx", cw->id);
3042
3043 screen_info = cw->screen_info;
3044 display_info = screen_info->display_info;
3045
3046 if (!WIN_IS_REDIRECTED(cw))
3047 {
3048 cw->fulloverlay = is_fullscreen (cw);
3049 if (cw->fulloverlay)
3050 {
3051 /*
3052 * To be safe, we only count the fullscreen un-redirected windows.
3053 * We do not want a smaller override redirect such as a tooltip
3054 * for example to prevent the overlay to be remapped and leave
3055 * a black screen until the tooltip is unmapped...
3056 */
3057 screen_info->wins_unredirected++;
3058 TRACE ("mapping fullscreen window 0x%lx, wins_unredirected increased to %i", cw->id, screen_info->wins_unredirected);
3059 }
3060 TRACE ("mapping unredirected window 0x%lx, wins_unredirected is now %i", cw->id, screen_info->wins_unredirected);
3061 #if HAVE_OVERLAYS
3062 if ((screen_info->wins_unredirected == 1) && (display_info->have_overlays))
3063 {
3064 TRACE ("unmapping overlay window");
3065 XUnmapWindow (myScreenGetXDisplay (screen_info), screen_info->overlay);
3066 }
3067 #endif /* HAVE_OVERLAYS */
3068 return;
3069 }
3070
3071 cw->viewable = TRUE;
3072 cw->damaged = FALSE;
3073
3074 /* Check for new windows to un-redirect. */
3075 if (WIN_HAS_DAMAGE(cw) && WIN_IS_NATIVE_OPAQUE(cw) &&
3076 WIN_IS_REDIRECTED(cw) && !WIN_IS_SHAPED(cw) &&
3077 ((screen_info->wins_unredirected > 0) || is_fullscreen (cw)))
3078 {
3079 /* Make those opaque, we don't want them to be transparent */
3080 cw->opacity = NET_WM_OPAQUE;
3081
3082 /* For NET_WM_BYPASS_COMPOSITOR, 0 indicates no preference, 1 hints
3083 * the compositor to disabling compositing.
3084 */
3085 if ((cw->bypass_compositor == 1) ||
3086 (screen_info->params->unredirect_overlays &&
3087 WIN_IS_OVERRIDE(cw) && cw->bypass_compositor == 0))
3088 {
3089 TRACE ("unredirecting toplevel window 0x%lx", cw->id);
3090 unredirect_win (cw);
3091 }
3092 }
3093 }
3094
3095 static void
unmap_win(CWindow * cw)3096 unmap_win (CWindow *cw)
3097 {
3098 ScreenInfo *screen_info;
3099 DisplayInfo *display_info;
3100
3101 g_return_if_fail (cw != NULL);
3102 TRACE ("window 0x%lx", cw->id);
3103
3104 screen_info = cw->screen_info;
3105 display_info = screen_info->display_info;
3106
3107 if (!WIN_IS_REDIRECTED(cw) && (screen_info->wins_unredirected > 0))
3108 {
3109 if (cw->fulloverlay)
3110 {
3111 screen_info->wins_unredirected--;
3112 TRACE ("unmapping fullscreen window 0x%lx, wins_unredirected decreased to %i",
3113 cw->id, screen_info->wins_unredirected);
3114 }
3115 TRACE ("unmapped window 0x%lx, wins_unredirected is now %i", cw->id, screen_info->wins_unredirected);
3116 if (!screen_info->wins_unredirected)
3117 {
3118 /* Restore the overlay if that was the last unredirected window */
3119 #if HAVE_OVERLAYS
3120 if (display_info->have_overlays)
3121 {
3122 TRACE ("remapping overlay window");
3123 XMapWindow (myScreenGetXDisplay (screen_info), screen_info->overlay);
3124 }
3125 #endif /* HAVE_OVERLAYS */
3126 damage_screen (screen_info);
3127 }
3128 }
3129 else if (WIN_IS_VISIBLE(cw))
3130 {
3131 damage_win (cw);
3132 }
3133
3134 cw->viewable = FALSE;
3135 cw->damaged = FALSE;
3136 cw->redirected = TRUE;
3137 cw->fulloverlay = FALSE;
3138
3139 free_win_data (cw, FALSE);
3140 }
3141
3142 static void
init_opacity(CWindow * cw)3143 init_opacity (CWindow *cw)
3144 {
3145 ScreenInfo *screen_info;
3146 DisplayInfo *display_info;
3147 Client *c;
3148
3149 g_return_if_fail (cw != NULL);
3150 TRACE ("window 0x%lx", cw->id);
3151
3152 screen_info = cw->screen_info;
3153 display_info = screen_info->display_info;
3154 c = cw->c;
3155
3156 cw->native_opacity = FALSE;
3157 if (c)
3158 {
3159 cw->opacity_locked = FLAG_TEST (c->xfwm_flags, XFWM_FLAG_OPACITY_LOCKED);
3160 cw->opacity = c->opacity_applied;
3161 cw->native_opacity = WIN_IS_OPAQUE(cw);
3162 }
3163 else if (getOpacity (display_info, cw->id, &cw->opacity))
3164 {
3165 cw->native_opacity = WIN_IS_OPAQUE(cw);
3166 cw->opacity_locked = getOpacityLock (display_info, cw->id);
3167 }
3168 else
3169 {
3170 cw->opacity = (double) (screen_info->params->popup_opacity / 100.0) * NET_WM_OPAQUE;
3171 cw->native_opacity = TRUE;
3172 cw->opacity_locked = getOpacityLock (display_info, cw->id);
3173 }
3174 }
3175
3176 static void
update_opaque_region(CWindow * cw,Window id)3177 update_opaque_region (CWindow *cw, Window id)
3178 {
3179 DisplayInfo *display_info;
3180 ScreenInfo *screen_info;
3181 XRectangle *rects = NULL;
3182 unsigned int nrects;
3183 XserverRegion old_opaque_region;
3184
3185 g_return_if_fail (cw != NULL);
3186 TRACE ("window 0x%lx", cw->id);
3187
3188 screen_info = cw->screen_info;
3189 display_info = screen_info->display_info;
3190
3191 old_opaque_region = cw->opaque_region;
3192
3193 nrects = getOpaqueRegionRects (display_info, id, &rects);
3194 if (nrects)
3195 {
3196 cw->opaque_region = XFixesCreateRegion (display_info->dpy, rects, nrects);
3197 g_free (rects);
3198 }
3199 else
3200 {
3201 cw->opaque_region = None;
3202 }
3203
3204 if (old_opaque_region != None)
3205 {
3206 if (!WIN_IS_VISIBLE(cw) || !WIN_IS_REDIRECTED(cw))
3207 {
3208 XFixesDestroyRegion (display_info->dpy, old_opaque_region);
3209 }
3210 else
3211 {
3212 if (cw->opaque_region)
3213 {
3214 XFixesSubtractRegion (display_info->dpy, old_opaque_region,
3215 old_opaque_region, cw->opaque_region);
3216 }
3217 translate_to_client_region (cw, old_opaque_region);
3218 /* old_opaque_region region will be destroyed by add_damage () */
3219 add_damage (screen_info, old_opaque_region);
3220 }
3221 }
3222 }
3223
3224 static void
add_win(DisplayInfo * display_info,Window id,Client * c)3225 add_win (DisplayInfo *display_info, Window id, Client *c)
3226 {
3227 ScreenInfo *screen_info;
3228 CWindow *new;
3229 int result, status;
3230
3231 TRACE ("window 0x%lx", id);
3232
3233 if (is_output (display_info, id))
3234 {
3235 TRACE ("not adding output window 0x%lx", id);
3236 return;
3237 }
3238
3239 new = find_cwindow_in_display (display_info, id);
3240 if (new)
3241 {
3242 TRACE ("window 0x%lx already added", id);
3243 return;
3244 }
3245
3246 new = g_slice_alloc0 (sizeof(CWindow));
3247 myDisplayGrabServer (display_info);
3248 myDisplayErrorTrapPush (display_info);
3249 status = XGetWindowAttributes (display_info->dpy, id, &new->attr);
3250 result = myDisplayErrorTrapPop (display_info);
3251
3252 if ((result != Success) || !status)
3253 {
3254 g_slice_free (CWindow, new);
3255 myDisplayUngrabServer (display_info);
3256 TRACE ("an error occurred getting window attributes, 0x%lx not added", id);
3257 return;
3258 }
3259
3260 if (c)
3261 {
3262 screen_info = c->screen_info;
3263 }
3264 else
3265 {
3266 screen_info = myDisplayGetScreenFromRoot (display_info, new->attr.root);
3267 }
3268
3269 if (!screen_info)
3270 {
3271 g_slice_free (CWindow, new);
3272 myDisplayUngrabServer (display_info);
3273 TRACE ("couldn't get screen from window, 0x%lx not added", id);
3274 return;
3275 }
3276
3277 if (!screen_info->compositor_active)
3278 {
3279 g_slice_free (CWindow, new);
3280 myDisplayUngrabServer (display_info);
3281 TRACE ("compositor not active on screen %i, 0x%lx not added", screen_info->screen, id);
3282 return;
3283 }
3284
3285 myDisplayErrorTrapPush (display_info);
3286 if (c == NULL)
3287 {
3288 /* We must be notified of property changes for transparency, even if the win is not managed */
3289 XSelectInput (display_info->dpy, id, new->attr.your_event_mask | PropertyChangeMask | StructureNotifyMask);
3290 }
3291
3292 /* Listen for XShape events if applicable */
3293 if (display_info->have_shape)
3294 {
3295 XShapeSelectInput (display_info->dpy, id, ShapeNotifyMask);
3296 }
3297 myDisplayErrorTrapPopIgnored (display_info);
3298
3299 new->c = c;
3300 new->screen_info = screen_info;
3301 new->id = id;
3302 new->damaged = FALSE;
3303 new->redirected = TRUE;
3304 new->fulloverlay = FALSE;
3305 new->shaped = is_shaped (display_info, id);
3306 new->viewable = (new->attr.map_state == IsViewable);
3307
3308 if (new->attr.class != InputOnly)
3309 {
3310 myDisplayErrorTrapPush (display_info);
3311 new->damage = XDamageCreate (display_info->dpy, id, XDamageReportNonEmpty);
3312 if (myDisplayErrorTrapPop (display_info) != Success)
3313 {
3314 new->damage = None;
3315 }
3316 }
3317 else
3318 {
3319 new->damage = None;
3320 }
3321 #if HAVE_NAME_WINDOW_PIXMAP
3322 new->name_window_pixmap = None;
3323 #endif
3324 new->picture = None;
3325 new->saved_picture = None;
3326 new->alphaPict = None;
3327 new->alphaBorderPict = None;
3328 new->shadowPict = None;
3329 new->borderSize = None;
3330 new->clientSize = None;
3331 new->extents = None;
3332 new->shadow = None;
3333 new->shadow_dx = 0;
3334 new->shadow_dy = 0;
3335 new->shadow_width = 0;
3336 new->shadow_height = 0;
3337 new->borderClip = None;
3338
3339 if (c)
3340 {
3341 update_opaque_region (new, c->window);
3342 }
3343 else
3344 {
3345 update_opaque_region (new, id);
3346 }
3347 getBypassCompositor (display_info, id, &new->bypass_compositor);
3348 init_opacity (new);
3349 determine_mode (new);
3350
3351 /* Insert window at top of stack */
3352 screen_info->cwindows = g_list_prepend (screen_info->cwindows, new);
3353 g_hash_table_insert(screen_info->cwindow_hash, (gpointer) new->id, new);
3354
3355 if (WIN_IS_VISIBLE(new))
3356 {
3357 map_win (new);
3358 }
3359
3360 TRACE ("window 0x%lx added", id);
3361
3362 myDisplayUngrabServer (display_info);
3363 }
3364
3365 static void
restack_win(CWindow * cw,Window above)3366 restack_win (CWindow *cw, Window above)
3367 {
3368 ScreenInfo *screen_info;
3369 Window previous_above;
3370 GList *sibling;
3371 GList *next;
3372
3373 g_return_if_fail (cw != NULL);
3374 TRACE ("window 0x%lx above 0x%lx", cw->id, above);
3375
3376 screen_info = cw->screen_info;
3377 sibling = g_list_find (screen_info->cwindows, (gconstpointer) cw);
3378 next = g_list_next (sibling);
3379 previous_above = None;
3380
3381 if (next)
3382 {
3383 CWindow *ncw = (CWindow *) next;
3384 previous_above = ncw->id;
3385 }
3386
3387 /* If above is set to None, the window whose state was changed is on
3388 * the bottom of the stack with respect to sibling.
3389 */
3390 if (above == None)
3391 {
3392 /* Insert at bottom of window stack */
3393 screen_info->cwindows = g_list_delete_link (screen_info->cwindows, sibling);
3394 screen_info->cwindows = g_list_append (screen_info->cwindows, cw);
3395 }
3396 else if (previous_above != above)
3397 {
3398 GList *list;
3399
3400 for (list = screen_info->cwindows; list; list = g_list_next (list))
3401 {
3402 CWindow *cw2 = (CWindow *) list->data;
3403 if (cw2->id == above)
3404 {
3405 break;
3406 }
3407 }
3408
3409 if (list != NULL)
3410 {
3411 screen_info->cwindows = g_list_delete_link (screen_info->cwindows, sibling);
3412 screen_info->cwindows = g_list_insert_before (screen_info->cwindows, list, cw);
3413 }
3414 }
3415 }
3416
3417 static void
resize_win(CWindow * cw,gint x,gint y,gint width,gint height,gint bw)3418 resize_win (CWindow *cw, gint x, gint y, gint width, gint height, gint bw)
3419 {
3420 DisplayInfo *display_info;
3421 ScreenInfo *screen_info;
3422 XserverRegion damage;
3423
3424 g_return_if_fail (cw != NULL);
3425 TRACE ("window 0x%lx, (%i,%i) %ix%i", cw->id, x, y, width, height);
3426
3427 screen_info = cw->screen_info;
3428 display_info = screen_info->display_info;
3429 damage = None;
3430
3431 myDisplayErrorTrapPush (display_info);
3432
3433 if (WIN_IS_VISIBLE(cw))
3434 {
3435 damage = XFixesCreateRegion (display_info->dpy, NULL, 0);
3436 if (cw->extents)
3437 {
3438 XFixesCopyRegion (display_info->dpy, damage, cw->extents);
3439 }
3440 }
3441
3442 if (cw->extents)
3443 {
3444 XFixesDestroyRegion (display_info->dpy, cw->extents);
3445 cw->extents = None;
3446 }
3447
3448 if ((cw->attr.width != width) || (cw->attr.height != height))
3449 {
3450 #if HAVE_NAME_WINDOW_PIXMAP
3451 if (cw->name_window_pixmap)
3452 {
3453 XFreePixmap (display_info->dpy, cw->name_window_pixmap);
3454 cw->name_window_pixmap = None;
3455 }
3456 #endif
3457 if (cw->picture)
3458 {
3459 XRenderFreePicture (display_info->dpy, cw->picture);
3460 cw->picture = None;
3461 }
3462
3463 if (cw->saved_picture)
3464 {
3465 XRenderFreePicture (display_info->dpy, cw->saved_picture);
3466 cw->saved_picture = None;
3467 }
3468
3469 if (cw->shadow)
3470 {
3471 XRenderFreePicture (display_info->dpy, cw->shadow);
3472 cw->shadow = None;
3473 }
3474 }
3475
3476 if ((cw->attr.width != width) || (cw->attr.height != height) ||
3477 (cw->attr.x != x) || (cw->attr.y != y))
3478 {
3479 if (cw->borderSize)
3480 {
3481 XFixesDestroyRegion (display_info->dpy, cw->borderSize);
3482 cw->borderSize = None;
3483 }
3484
3485 if (cw->clientSize)
3486 {
3487 XFixesDestroyRegion (display_info->dpy, cw->clientSize);
3488 cw->clientSize = None;
3489 }
3490 }
3491
3492 cw->attr.x = x;
3493 cw->attr.y = y;
3494 cw->attr.width = width;
3495 cw->attr.height = height;
3496 cw->attr.border_width = bw;
3497
3498 if (damage)
3499 {
3500 cw->extents = win_extents (cw);
3501 XFixesUnionRegion (display_info->dpy, damage, damage, cw->extents);
3502
3503 fix_region (cw, damage);
3504 /* damage region will be destroyed by add_damage () */
3505 add_damage (screen_info, damage);
3506 }
3507
3508 myDisplayErrorTrapPopIgnored (display_info);
3509 }
3510
3511 static void
reshape_win(CWindow * cw)3512 reshape_win (CWindow *cw)
3513 {
3514 DisplayInfo *display_info;
3515 ScreenInfo *screen_info;
3516 XserverRegion damage;
3517
3518 g_return_if_fail (cw != NULL);
3519 TRACE ("window 0x%lx", cw->id);
3520
3521 screen_info = cw->screen_info;
3522 display_info = screen_info->display_info;
3523
3524 damage = None;
3525
3526 myDisplayErrorTrapPush (display_info);
3527
3528 if (WIN_IS_VISIBLE(cw))
3529 {
3530 damage = XFixesCreateRegion (display_info->dpy, NULL, 0);
3531 if (cw->extents)
3532 {
3533 XFixesCopyRegion (display_info->dpy, damage, cw->extents);
3534 }
3535 }
3536
3537 if (cw->extents)
3538 {
3539 XFixesDestroyRegion (display_info->dpy, cw->extents);
3540 cw->extents = None;
3541 }
3542
3543 if (cw->shadow)
3544 {
3545 XRenderFreePicture (display_info->dpy, cw->shadow);
3546 cw->shadow = None;
3547 }
3548
3549 if (cw->borderSize)
3550 {
3551 XFixesDestroyRegion (display_info->dpy, cw->borderSize);
3552 cw->borderSize = None;
3553 }
3554
3555 if (cw->clientSize)
3556 {
3557 XFixesDestroyRegion (display_info->dpy, cw->clientSize);
3558 cw->clientSize = None;
3559 }
3560
3561 if (damage)
3562 {
3563 cw->extents = win_extents (cw);
3564 XFixesUnionRegion (display_info->dpy, damage, damage, cw->extents);
3565
3566 /* A shape notify will likely change the shadows too, so clear the extents */
3567 XFixesDestroyRegion (display_info->dpy, cw->extents);
3568 cw->extents = None;
3569
3570 fix_region (cw, damage);
3571 /* damage region will be destroyed by add_damage () */
3572 add_damage (screen_info, damage);
3573 }
3574
3575 myDisplayErrorTrapPopIgnored (display_info);
3576 }
3577
3578 static void
destroy_win(DisplayInfo * display_info,Window id)3579 destroy_win (DisplayInfo *display_info, Window id)
3580 {
3581 CWindow *cw;
3582
3583 g_return_if_fail (display_info != NULL);
3584 g_return_if_fail (id != None);
3585 TRACE ("window 0x%lx", id);
3586
3587 cw = find_cwindow_in_display (display_info, id);
3588 if (is_on_compositor (cw))
3589 {
3590 ScreenInfo *screen_info;
3591
3592 if (WIN_IS_VIEWABLE (cw))
3593 {
3594 unmap_win (cw);
3595 }
3596 screen_info = cw->screen_info;
3597 g_hash_table_remove(screen_info->cwindow_hash, (gpointer) cw->id);
3598 screen_info->cwindows = g_list_remove (screen_info->cwindows, (gconstpointer) cw);
3599
3600 free_win_data (cw, TRUE);
3601 }
3602 }
3603
3604 static void
update_cursor(ScreenInfo * screen_info)3605 update_cursor (ScreenInfo *screen_info)
3606 {
3607 XFixesCursorImage *cursor;
3608
3609 g_return_if_fail (screen_info != NULL);
3610 TRACE ("entering");
3611
3612 cursor = XFixesGetCursorImage (screen_info->display_info->dpy);
3613 if (cursor == NULL)
3614 {
3615 g_warning ("Failed to retrieve cursor image!");
3616 return;
3617 }
3618
3619 if (screen_info->cursorSerial != cursor->cursor_serial)
3620 {
3621 if (screen_info->zoomed)
3622 {
3623 expose_area (screen_info, &screen_info->cursorLocation, 1);
3624 }
3625
3626 if (screen_info->cursorPicture)
3627 {
3628 XRenderFreePicture (screen_info->display_info->dpy, screen_info->cursorPicture);
3629 }
3630 screen_info->cursorPicture = cursor_to_picture (screen_info, cursor);
3631
3632 screen_info->cursorSerial = cursor->cursor_serial;
3633 screen_info->cursorOffsetX = cursor->xhot;
3634 screen_info->cursorOffsetY = cursor->yhot;
3635 screen_info->cursorLocation.x = cursor->x - cursor->xhot;
3636 screen_info->cursorLocation.y = cursor->y - cursor->yhot;
3637 screen_info->cursorLocation.width = cursor->width;
3638 screen_info->cursorLocation.height = cursor->height;
3639
3640 if (screen_info->zoomed)
3641 {
3642 expose_area (screen_info, &screen_info->cursorLocation, 1);
3643 }
3644 }
3645
3646 XFree (cursor);
3647 }
3648
3649 static void
recenter_zoomed_area(ScreenInfo * screen_info,int x_root,int y_root)3650 recenter_zoomed_area (ScreenInfo *screen_info, int x_root, int y_root)
3651 {
3652 int zf = screen_info->transform.matrix[0][0];
3653 double zoom = XFixedToDouble (zf);
3654
3655 if (screen_info->zoomed)
3656 {
3657 int xp = x_root * (1 - zoom);
3658 int yp = y_root * (1 - zoom);
3659 screen_info->transform.matrix[0][2] = (xp << 16);
3660 screen_info->transform.matrix[1][2] = (yp << 16);
3661 }
3662
3663 if (zf > (1 << 14) && zf < (1 << 16))
3664 {
3665 #ifdef HAVE_EPOXY
3666 if (screen_info->use_glx)
3667 {
3668 screen_info->texture_filter = GL_LINEAR;
3669 }
3670 #endif /* HAVE_EPOXY */
3671 if (screen_info->zoomBuffer)
3672 {
3673 XRenderSetPictureFilter (myScreenGetXDisplay (screen_info),
3674 screen_info->zoomBuffer,
3675 FilterBilinear, NULL, 0);
3676 }
3677 }
3678 else
3679 {
3680 #ifdef HAVE_EPOXY
3681 if (screen_info->use_glx)
3682 {
3683 screen_info->texture_filter = GL_NEAREST;
3684 }
3685 #endif /* HAVE_EPOXY */
3686 if (screen_info->zoomBuffer)
3687 {
3688 XRenderSetPictureFilter (myScreenGetXDisplay (screen_info),
3689 screen_info->zoomBuffer,
3690 FilterNearest, NULL, 0);
3691 }
3692 }
3693 /* zoomBuffer might be None if we're using GLX */
3694 if (screen_info->zoomBuffer)
3695 {
3696 XRenderSetPictureTransform (myScreenGetXDisplay (screen_info),
3697 screen_info->zoomBuffer,
3698 &screen_info->transform);
3699 }
3700
3701 damage_screen (screen_info);
3702 }
3703
3704 static gboolean
zoom_timeout_cb(gpointer data)3705 zoom_timeout_cb (gpointer data)
3706 {
3707 ScreenInfo *screen_info;
3708 int x_root, y_root;
3709
3710 screen_info = (ScreenInfo *) data;
3711
3712 if (!screen_info->zoomed)
3713 {
3714 screen_info->zoom_timeout_id = 0;
3715
3716 if (screen_info->zoomBuffer)
3717 {
3718 XRenderFreePicture (myScreenGetXDisplay (screen_info),
3719 screen_info->zoomBuffer);
3720 screen_info->zoomBuffer = None;
3721 }
3722
3723 return FALSE; /* stop calling this callback */
3724 }
3725
3726 getMouseXY (screen_info, &x_root, &y_root);
3727
3728 if (screen_info->cursorLocation.x + screen_info->cursorOffsetX != x_root ||
3729 screen_info->cursorLocation.y + screen_info->cursorOffsetY != y_root)
3730 {
3731 screen_info->cursorLocation.x = x_root - screen_info->cursorOffsetX;
3732 screen_info->cursorLocation.y = y_root - screen_info->cursorOffsetY;
3733 recenter_zoomed_area (screen_info, x_root, y_root);
3734 }
3735
3736 return TRUE;
3737 }
3738
3739 static void
compositorHandleDamage(DisplayInfo * display_info,XDamageNotifyEvent * ev)3740 compositorHandleDamage (DisplayInfo *display_info, XDamageNotifyEvent *ev)
3741 {
3742 ScreenInfo *screen_info;
3743 CWindow *cw;
3744
3745 g_return_if_fail (display_info != NULL);
3746 g_return_if_fail (ev != NULL);
3747 TRACE ("drawable 0x%lx", ev->drawable);
3748
3749 /*
3750 ev->drawable is the window ID of the damaged window
3751 ev->geometry is the geometry of the damaged window
3752 ev->area is the bounding rect for the damaged area
3753 ev->damage is the damage handle returned by XDamageCreate()
3754 */
3755
3756 cw = find_cwindow_in_display (display_info, ev->drawable);
3757 if (is_on_compositor (cw) && WIN_IS_REDIRECTED(cw))
3758 {
3759 screen_info = cw->screen_info;
3760 repair_win (cw, &ev->area);
3761 screen_info->damages_pending = ev->more;
3762 }
3763 }
3764
3765 static void
compositorHandlePropertyNotify(DisplayInfo * display_info,XPropertyEvent * ev)3766 compositorHandlePropertyNotify (DisplayInfo *display_info, XPropertyEvent *ev)
3767 {
3768 #if MONITOR_ROOT_PIXMAP
3769 gint p;
3770 Atom backgroundProps[2];
3771 #endif
3772
3773 g_return_if_fail (display_info != NULL);
3774 g_return_if_fail (ev != NULL);
3775 TRACE ("window 0x%lx", ev->window);
3776
3777 #if MONITOR_ROOT_PIXMAP
3778 backgroundProps[0] = display_info->atoms[XROOTPMAP];
3779 backgroundProps[1] = display_info->atoms[XSETROOT];
3780
3781 for (p = 0; p < 2; p++)
3782 {
3783 if (ev->atom == backgroundProps[p] && ev->state == PropertyNewValue)
3784 {
3785 ScreenInfo *screen_info = myDisplayGetScreenFromRoot (display_info, ev->window);
3786 if ((screen_info) && (screen_info->compositor_active) && (screen_info->rootTile))
3787 {
3788 myDisplayErrorTrapPush (display_info);
3789 XClearArea (display_info->dpy, screen_info->output, 0, 0, 0, 0, TRUE);
3790 XRenderFreePicture (display_info->dpy, screen_info->rootTile);
3791 myDisplayErrorTrapPopIgnored (display_info);
3792
3793 screen_info->rootTile = None;
3794 damage_screen (screen_info);
3795
3796 return;
3797 }
3798 }
3799 }
3800 #endif
3801
3802 /* check if Trans property was changed */
3803 if (ev->atom == display_info->atoms[NET_WM_WINDOW_OPACITY])
3804 {
3805 CWindow *cw = find_cwindow_in_display (display_info, ev->window);
3806 TRACE ("window 0x%lx", ev->window);
3807
3808 if (is_on_compositor (cw))
3809 {
3810 Client *c = cw->c;
3811
3812 TRACE ("NET_WM_WINDOW_OPACITY changed for 0x%lx", cw->id);
3813 if (!getOpacity (display_info, cw->id, &cw->opacity))
3814 {
3815 /* The property was removed */
3816 cw->opacity = NET_WM_OPAQUE;
3817 }
3818 set_win_opacity (cw, cw->opacity);
3819 cw->native_opacity = WIN_IS_OPAQUE(cw);
3820
3821 /* Transset changes the property on the frame, not the client
3822 window. We need to check and update the client "opacity"
3823 value accordingly.
3824 */
3825 if (c)
3826 {
3827 if (c->opacity != cw->opacity)
3828 {
3829 clientSetOpacity (c, cw->opacity, 0, 0);
3830 }
3831 }
3832 }
3833 }
3834 else if (ev->atom == display_info->atoms[NET_WM_WINDOW_OPACITY_LOCKED])
3835 {
3836 CWindow *cw = find_cwindow_in_display (display_info, ev->window);
3837 TRACE ("NET_WM_WINDOW_OPACITY_LOCKED changed for id 0x%lx", ev->window);
3838
3839 if (is_on_compositor (cw))
3840 {
3841 cw->opacity_locked = getOpacityLock (display_info, cw->id);
3842 if (cw->c)
3843 {
3844 if (cw->opacity_locked)
3845 {
3846 FLAG_SET (cw->c->xfwm_flags, XFWM_FLAG_OPACITY_LOCKED);
3847 }
3848 else
3849 {
3850 FLAG_UNSET (cw->c->xfwm_flags, XFWM_FLAG_OPACITY_LOCKED);
3851 }
3852 }
3853 }
3854 }
3855 else if (ev->atom == display_info->atoms[NET_WM_BYPASS_COMPOSITOR])
3856 {
3857 CWindow *cw = find_cwindow_in_display (display_info, ev->window);
3858 TRACE ("NET_WM_BYPASS_COMPOSITOR changed for id 0x%lx", ev->window);
3859
3860 if (is_on_compositor (cw))
3861 {
3862 getBypassCompositor (display_info, cw->id, &cw->bypass_compositor);
3863 }
3864 }
3865 else if (ev->atom == display_info->atoms[NET_WM_OPAQUE_REGION])
3866 {
3867 Client* c;
3868 CWindow *cw;
3869
3870 c = myDisplayGetClientFromWindow (display_info, ev->window, SEARCH_WINDOW);
3871 if (c)
3872 {
3873 cw = find_cwindow_in_display (display_info, c->frame);
3874 }
3875 else
3876 {
3877 cw = find_cwindow_in_display (display_info, ev->window);
3878 }
3879
3880 if (is_on_compositor (cw))
3881 {
3882 update_opaque_region (cw, ev->window);
3883 }
3884 }
3885 else
3886 {
3887 TRACE ("no compositor property changed for id 0x%lx", ev->window);
3888 }
3889 }
3890
3891 static void
compositorHandleExpose(DisplayInfo * display_info,XExposeEvent * ev)3892 compositorHandleExpose (DisplayInfo *display_info, XExposeEvent *ev)
3893 {
3894 ScreenInfo *screen_info;
3895 XRectangle rect[1];
3896 CWindow *cw;
3897
3898 g_return_if_fail (display_info);
3899 TRACE ("window 0x%lx", ev->window);
3900
3901 cw = find_cwindow_in_display (display_info, ev->window);
3902 if (cw != NULL)
3903 {
3904 screen_info = cw->screen_info;
3905 }
3906 else
3907 {
3908 /* Get the screen structure from the root of the event */
3909 screen_info = myDisplayGetScreenFromRoot (display_info, ev->window);
3910 }
3911
3912 if (!screen_info || !compositorIsActive (screen_info))
3913 {
3914 return;
3915 }
3916
3917 rect[0].x = ev->x;
3918 rect[0].y = ev->y;
3919 rect[0].width = ev->width;
3920 rect[0].height = ev->height;
3921
3922 expose_area (screen_info, rect, 1);
3923 }
3924
3925 static void
compositorHandleConfigureNotify(DisplayInfo * display_info,XConfigureEvent * ev)3926 compositorHandleConfigureNotify (DisplayInfo *display_info, XConfigureEvent *ev)
3927 {
3928 CWindow *cw;
3929
3930 g_return_if_fail (display_info != NULL);
3931 g_return_if_fail (ev != NULL);
3932 TRACE ("window 0x%lx", ev->window);
3933
3934 cw = find_cwindow_in_display (display_info, ev->window);
3935 if (is_on_compositor (cw))
3936 {
3937 restack_win (cw, ev->above);
3938 resize_win (cw, ev->x, ev->y, ev->width, ev->height, ev->border_width);
3939 }
3940 }
3941
3942 static void
compositorHandleCirculateNotify(DisplayInfo * display_info,XCirculateEvent * ev)3943 compositorHandleCirculateNotify (DisplayInfo *display_info, XCirculateEvent *ev)
3944 {
3945 CWindow *cw;
3946 CWindow *top;
3947 GList *first;
3948 Window above;
3949
3950 g_return_if_fail (display_info != NULL);
3951 g_return_if_fail (ev != NULL);
3952 TRACE ("window 0x%lx", ev->window);
3953
3954 cw = find_cwindow_in_display (display_info, ev->window);
3955 if (!(is_on_compositor (cw)))
3956 {
3957 return;
3958 }
3959
3960 first = cw->screen_info->cwindows;
3961 top = (CWindow *) first;
3962
3963 if ((ev->place == PlaceOnTop) && (top))
3964 {
3965 above = top->id;
3966 }
3967 else
3968 {
3969 above = None;
3970 }
3971 restack_win (cw, above);
3972 }
3973
3974 static void
compositorHandleCreateNotify(DisplayInfo * display_info,XCreateWindowEvent * ev)3975 compositorHandleCreateNotify (DisplayInfo *display_info, XCreateWindowEvent *ev)
3976 {
3977 g_return_if_fail (display_info != NULL);
3978 g_return_if_fail (ev != NULL);
3979 TRACE ("window 0x%lx", ev->window);
3980
3981 /*
3982 We are only interested in top level windows, other will
3983 be caught by the WM.
3984 */
3985
3986 if (myDisplayGetScreenFromRoot (display_info, ev->parent) != NULL)
3987 {
3988 if (!find_cwindow_in_display (display_info, ev->window))
3989 {
3990 add_win (display_info, ev->window, NULL);
3991 }
3992 }
3993 }
3994
3995 static void
compositorHandleReparentNotify(DisplayInfo * display_info,XReparentEvent * ev)3996 compositorHandleReparentNotify (DisplayInfo *display_info, XReparentEvent *ev)
3997 {
3998 g_return_if_fail (display_info != NULL);
3999 g_return_if_fail (ev != NULL);
4000 TRACE ("window 0x%lx", ev->window);
4001
4002 if (myDisplayGetScreenFromRoot (display_info, ev->parent) != NULL)
4003 {
4004 add_win (display_info, ev->window, NULL);
4005 }
4006 else
4007 {
4008 destroy_win (display_info, ev->window);
4009 }
4010 }
4011
4012 static void
compositorHandleDestroyNotify(DisplayInfo * display_info,XDestroyWindowEvent * ev)4013 compositorHandleDestroyNotify (DisplayInfo *display_info, XDestroyWindowEvent *ev)
4014 {
4015 g_return_if_fail (display_info != NULL);
4016 g_return_if_fail (ev != NULL);
4017 TRACE ("window 0x%lx", ev->window);
4018
4019 destroy_win (display_info, ev->window);
4020 }
4021
4022 static void
compositorHandleMapNotify(DisplayInfo * display_info,XMapEvent * ev)4023 compositorHandleMapNotify (DisplayInfo *display_info, XMapEvent *ev)
4024 {
4025 CWindow *cw;
4026
4027 g_return_if_fail (display_info != NULL);
4028 g_return_if_fail (ev != NULL);
4029 TRACE ("window 0x%lx", ev->window);
4030
4031 cw = find_cwindow_in_display (display_info, ev->window);
4032 if (is_on_compositor (cw))
4033 {
4034 map_win (cw);
4035 }
4036 }
4037
4038 static void
compositorHandleUnmapNotify(DisplayInfo * display_info,XUnmapEvent * ev)4039 compositorHandleUnmapNotify (DisplayInfo *display_info, XUnmapEvent *ev)
4040 {
4041 CWindow *cw;
4042
4043 g_return_if_fail (display_info != NULL);
4044 g_return_if_fail (ev != NULL);
4045 TRACE ("window 0x%lx", ev->window);
4046
4047 if (ev->from_configure)
4048 {
4049 TRACE ("ignoring UnmapNotify caused by parent's resize");
4050 return;
4051 }
4052
4053 cw = find_cwindow_in_display (display_info, ev->window);
4054 if (is_on_compositor (cw))
4055 {
4056 if (WIN_IS_VIEWABLE (cw))
4057 {
4058 unmap_win (cw);
4059 }
4060 }
4061 }
4062
4063 static void
compositorHandleShapeNotify(DisplayInfo * display_info,XShapeEvent * ev)4064 compositorHandleShapeNotify (DisplayInfo *display_info, XShapeEvent *ev)
4065 {
4066 CWindow *cw;
4067
4068 g_return_if_fail (display_info != NULL);
4069 g_return_if_fail (ev != NULL);
4070 TRACE ("window 0x%lx", ev->window);
4071
4072 cw = find_cwindow_in_display (display_info, ev->window);
4073 if (is_on_compositor (cw))
4074 {
4075 if (ev->kind == ShapeBounding)
4076 {
4077 if (!(ev->shaped) && (cw->shaped))
4078 {
4079 cw->shaped = FALSE;
4080 }
4081 reshape_win (cw);
4082 if ((ev->shaped) && !(cw->shaped))
4083 {
4084 cw->shaped = TRUE;
4085 }
4086 }
4087 }
4088 }
4089
4090 static void
compositorHandleCursorNotify(DisplayInfo * display_info,XFixesCursorNotifyEvent * ev)4091 compositorHandleCursorNotify (DisplayInfo *display_info, XFixesCursorNotifyEvent *ev)
4092 {
4093 ScreenInfo *screen_info;
4094
4095 g_return_if_fail (display_info != NULL);
4096 g_return_if_fail (ev != NULL);
4097 TRACE ("window 0x%lx", ev->window);
4098
4099 screen_info = myDisplayGetScreenFromRoot (display_info, ev->window);
4100 if (screen_info && screen_info->cursor_is_zoomed)
4101 {
4102 update_cursor (screen_info);
4103 }
4104 }
4105
4106 static gboolean
compositorCheckCMSelection(ScreenInfo * screen_info)4107 compositorCheckCMSelection (ScreenInfo *screen_info)
4108 {
4109 DisplayInfo *display_info;
4110 gchar selection[32];
4111 Atom a;
4112
4113 display_info = screen_info->display_info;
4114
4115 /* Newer EWMH standard property "_NET_WM_CM_S<n>" */
4116 g_snprintf (selection, sizeof (selection), "_NET_WM_CM_S%d", screen_info->screen);
4117 a = XInternAtom (display_info->dpy, selection, FALSE);
4118 if (XGetSelectionOwner (display_info->dpy, a) != None)
4119 {
4120 return TRUE;
4121 }
4122
4123 /* Older property "COMPOSITING_MANAGER" */
4124 if (XGetSelectionOwner (display_info->dpy, display_info->atoms[COMPOSITING_MANAGER]) != None)
4125 {
4126 return TRUE;
4127 }
4128
4129 return FALSE;
4130 }
4131
4132 #ifdef HAVE_PRESENT_EXTENSION
4133 static void
compositorHandlePresentCompleteNotify(DisplayInfo * display_info,XPresentCompleteNotifyEvent * ev)4134 compositorHandlePresentCompleteNotify (DisplayInfo *display_info, XPresentCompleteNotifyEvent *ev)
4135 {
4136 ScreenInfo *screen_info;
4137 GSList *list;
4138
4139 g_return_if_fail (display_info != NULL);
4140 g_return_if_fail (ev != NULL);
4141 TRACE ("window 0x%lx", ev->window);
4142
4143 for (list = display_info->screens; list; list = g_slist_next (list))
4144 {
4145 screen_info = (ScreenInfo *) list->data;
4146 if (screen_info->output == ev->window)
4147 {
4148 DBG ("present completed, present pending cleared");
4149 screen_info->present_pending = FALSE;
4150 break;
4151 }
4152 }
4153 }
4154
4155 static void
compositorHandleGenericEvent(DisplayInfo * display_info,XGenericEvent * ev)4156 compositorHandleGenericEvent(DisplayInfo *display_info, XGenericEvent *ev)
4157 {
4158 XGenericEventCookie *ev_cookie = (XGenericEventCookie *) ev;
4159
4160 g_return_if_fail (display_info != NULL);
4161 g_return_if_fail (ev != NULL);
4162 TRACE ("entering");
4163
4164 if (ev_cookie->extension == display_info->present_opcode)
4165 {
4166 XGetEventData (display_info->dpy, ev_cookie);
4167 if (ev_cookie->evtype == PresentCompleteNotify)
4168 {
4169 compositorHandlePresentCompleteNotify (display_info,
4170 (XPresentCompleteNotifyEvent *) ev_cookie->data);
4171 }
4172 XFreeEventData (display_info->dpy, ev_cookie);
4173 }
4174 }
4175 #endif /* HAVE_PRESENT_EXTENSION */
4176
4177 static void
compositorSetCMSelection(ScreenInfo * screen_info,Window w)4178 compositorSetCMSelection (ScreenInfo *screen_info, Window w)
4179 {
4180 DisplayInfo *display_info;
4181 gchar selection[32];
4182 Atom a;
4183
4184 g_return_if_fail (screen_info != NULL);
4185
4186 display_info = screen_info->display_info;
4187 /* Newer EWMH standard property "_NET_WM_CM_S<n>" */
4188 g_snprintf (selection, sizeof (selection), "_NET_WM_CM_S%d", screen_info->screen);
4189 a = XInternAtom (display_info->dpy, selection, FALSE);
4190 setXAtomManagerOwner (display_info, a, screen_info->xroot, w);
4191
4192 /* Older property "COMPOSITING_MANAGER" */
4193 setAtomIdManagerOwner (display_info, COMPOSITING_MANAGER, screen_info->xroot, w);
4194 }
4195
4196 static Pixmap
compositorScaleWindowPixmap(CWindow * cw,guint * width,guint * height)4197 compositorScaleWindowPixmap (CWindow *cw, guint *width, guint *height)
4198 {
4199 Display *dpy;
4200 ScreenInfo *screen_info;
4201 DisplayInfo *display_info;
4202 Picture srcPicture, tmpPicture, destPicture;
4203 Pixmap tmpPixmap, dstPixmap;
4204 XTransform transform;
4205 XRenderPictFormat *render_format;
4206 double scale;
4207 int tx, ty;
4208 int src_x, src_y;
4209 int src_size, dest_size;
4210 unsigned int src_w, src_h;
4211 unsigned int dst_w, dst_h;
4212 XRenderColor c = { 0x7fff, 0x7fff, 0x7fff, 0xffff };
4213
4214 screen_info = cw->screen_info;
4215 display_info = screen_info->display_info;
4216 dpy = myScreenGetXDisplay (screen_info);
4217
4218 srcPicture = cw->picture;
4219 if (!srcPicture)
4220 {
4221 srcPicture = cw->saved_picture;
4222 }
4223 /* Could not get a usable picture, bail out */
4224 if (!srcPicture)
4225 {
4226 return None;
4227 }
4228
4229 /* Get the source pixmap size to compute the scale */
4230 get_paint_bounds (cw, &tx, &ty, &src_w, &src_h);
4231 if (WIN_HAS_CLIENT(cw))
4232 {
4233 src_x = ABS(frameExtentLeft (cw->c));
4234 src_y = ABS(frameExtentTop (cw->c));
4235 src_w = src_w - src_x - ABS(frameExtentRight (cw->c));
4236 src_h = src_h - src_y - ABS(frameExtentBottom (cw->c));
4237 }
4238 else
4239 {
4240 src_x = 0;
4241 src_y = 0;
4242 }
4243 src_size = MAX (src_w, src_h);
4244
4245 /* Shaped windows have no height */
4246 if (src_w == 0 || src_h == 0)
4247 {
4248 return None;
4249 }
4250
4251 /*/
4252 * Caller may pass either NULL or 0.
4253 * If 0, we return the actual unscalled size.
4254 */
4255 dst_w = (width != NULL && *width > 0) ? *width : src_w;
4256 dst_h = (height != NULL && *height > 0) ? *height : src_h;
4257 dest_size = MIN (dst_w, dst_h);
4258
4259 scale = (double) dest_size / (double) src_size;
4260 dst_w = src_w * scale;
4261 dst_h = src_h * scale;
4262
4263 transform.matrix[0][0] = XDoubleToFixed (1.0);
4264 transform.matrix[0][1] = XDoubleToFixed (0.0);
4265 transform.matrix[0][2] = XDoubleToFixed (0.0);
4266 transform.matrix[1][0] = XDoubleToFixed (0.0);
4267 transform.matrix[1][1] = XDoubleToFixed (1.0);
4268 transform.matrix[1][2] = XDoubleToFixed (0.0);
4269 transform.matrix[2][0] = XDoubleToFixed (0.0);
4270 transform.matrix[2][1] = XDoubleToFixed (0.0);
4271 transform.matrix[2][2] = XDoubleToFixed (scale);
4272
4273 tmpPixmap = XCreatePixmap (dpy, screen_info->output, src_w, src_h, 32);
4274 if (!tmpPixmap)
4275 {
4276 return None;
4277 }
4278
4279 dstPixmap = XCreatePixmap (dpy, screen_info->output, dst_w, dst_h, 32);
4280 if (!dstPixmap)
4281 {
4282 XFreePixmap (dpy, tmpPixmap);
4283 return None;
4284 }
4285
4286 render_format = get_window_format (cw);
4287 if (!render_format)
4288 {
4289 XFreePixmap (dpy, dstPixmap);
4290 XFreePixmap (dpy, tmpPixmap);
4291 return None;
4292 }
4293
4294 myDisplayErrorTrapPush (display_info);
4295 render_format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
4296 tmpPicture = XRenderCreatePicture (dpy, tmpPixmap, render_format, 0, NULL);
4297 XRenderFillRectangle (dpy, PictOpSrc, tmpPicture, &c, 0, 0, src_w, src_h);
4298 XFixesSetPictureClipRegion (dpy, tmpPicture, 0, 0, None);
4299 XRenderComposite (dpy, PictOpOver, srcPicture, None, tmpPicture,
4300 src_x, src_y, 0, 0, 0, 0, src_w, src_h);
4301
4302 XRenderSetPictureFilter (dpy, tmpPicture, FilterBest, NULL, 0);
4303 XRenderSetPictureTransform (dpy, tmpPicture, &transform);
4304
4305 destPicture = XRenderCreatePicture (dpy, dstPixmap, render_format, 0, NULL);
4306 XRenderComposite (dpy, PictOpOver, tmpPicture, None, destPicture,
4307 0, 0, 0, 0, 0, 0, dst_w, dst_h);
4308
4309 XRenderFreePicture (dpy, tmpPicture);
4310 XRenderFreePicture (dpy, destPicture);
4311 XFreePixmap (dpy, tmpPixmap);
4312
4313 /* Update given size if requested */
4314 if (width != NULL)
4315 {
4316 *width = dst_w;
4317 }
4318 if (height != NULL)
4319 {
4320 *height = dst_h;
4321 }
4322 myDisplayErrorTrapPopIgnored (display_info);
4323
4324 return dstPixmap;
4325 }
4326
4327 #endif /* HAVE_COMPOSITOR */
4328
4329 gboolean
compositorIsUsable(DisplayInfo * display_info)4330 compositorIsUsable (DisplayInfo *display_info)
4331 {
4332 #ifdef HAVE_COMPOSITOR
4333 return display_info->enable_compositor;
4334 #endif /* HAVE_COMPOSITOR */
4335 return FALSE;
4336 }
4337
4338 gboolean
compositorIsActive(ScreenInfo * screen_info)4339 compositorIsActive (ScreenInfo *screen_info)
4340 {
4341 #ifdef HAVE_COMPOSITOR
4342 g_return_val_if_fail (screen_info != NULL, FALSE);
4343
4344 return screen_info->compositor_active;
4345 #endif /* HAVE_COMPOSITOR */
4346 return FALSE;
4347 }
4348
4349 void
compositorAddWindow(DisplayInfo * display_info,Window id,Client * c)4350 compositorAddWindow (DisplayInfo *display_info, Window id, Client *c)
4351 {
4352 #ifdef HAVE_COMPOSITOR
4353 g_return_if_fail (display_info != NULL);
4354 g_return_if_fail (id != None);
4355 TRACE ("window 0x%lx", id);
4356
4357 if (!compositorIsUsable (display_info))
4358 {
4359 return;
4360 }
4361
4362 if (!compositorSetClient (display_info, id, c))
4363 {
4364 add_win (display_info, id, c);
4365 }
4366 #endif /* HAVE_COMPOSITOR */
4367 }
4368
4369 gboolean
compositorSetClient(DisplayInfo * display_info,Window id,Client * c)4370 compositorSetClient (DisplayInfo *display_info, Window id, Client *c)
4371 {
4372 #ifdef HAVE_COMPOSITOR
4373 CWindow *cw;
4374
4375 g_return_val_if_fail (display_info != NULL, FALSE);
4376 g_return_val_if_fail (id != None, FALSE);
4377 TRACE ("window 0x%lx", id);
4378
4379 if (!compositorIsUsable (display_info))
4380 {
4381 return FALSE;
4382 }
4383
4384 cw = find_cwindow_in_display (display_info, id);
4385 if (is_on_compositor (cw))
4386 {
4387 if (cw->c != c)
4388 {
4389 update_extents (cw);
4390 cw->c = c;
4391 }
4392 return TRUE;
4393 }
4394 #endif /* HAVE_COMPOSITOR */
4395 return FALSE;
4396 }
4397
4398 void
compositorRemoveWindow(DisplayInfo * display_info,Window id)4399 compositorRemoveWindow (DisplayInfo *display_info, Window id)
4400 {
4401 #ifdef HAVE_COMPOSITOR
4402 g_return_if_fail (display_info != NULL);
4403 g_return_if_fail (id != None);
4404 TRACE ("window 0x%lx", id);
4405
4406 if (!compositorIsUsable (display_info))
4407 {
4408 return;
4409 }
4410
4411 destroy_win (display_info, id);
4412 #endif /* HAVE_COMPOSITOR */
4413 }
4414
4415 void
compositorDamageWindow(DisplayInfo * display_info,Window id)4416 compositorDamageWindow (DisplayInfo *display_info, Window id)
4417 {
4418 #ifdef HAVE_COMPOSITOR
4419 CWindow *cw;
4420
4421 g_return_if_fail (display_info != NULL);
4422 g_return_if_fail (id != None);
4423 TRACE ("window 0x%lx", id);
4424
4425 if (!compositorIsUsable (display_info))
4426 {
4427 return;
4428 }
4429
4430 cw = find_cwindow_in_display (display_info, id);
4431 if (is_on_compositor (cw))
4432 {
4433 /* that will also damage the window */
4434 update_extents (cw);
4435 }
4436 #endif /* HAVE_COMPOSITOR */
4437 }
4438
4439 void
compositorResizeWindow(DisplayInfo * display_info,Window id,int x,int y,int width,int height)4440 compositorResizeWindow (DisplayInfo *display_info, Window id, int x, int y, int width, int height)
4441 {
4442 #ifdef HAVE_COMPOSITOR
4443 CWindow *cw;
4444
4445 g_return_if_fail (display_info != NULL);
4446 g_return_if_fail (id != None);
4447 TRACE ("window 0x%lx", id);
4448
4449 if (!compositorIsUsable (display_info))
4450 {
4451 return;
4452 }
4453
4454 cw = find_cwindow_in_display (display_info, id);
4455 if (is_on_compositor (cw))
4456 {
4457 resize_win (cw, x, y, width, height, 0);
4458 }
4459 #endif /* HAVE_COMPOSITOR */
4460 }
4461
4462 /* May return None if:
4463 * - The xserver does not support name window pixmaps
4464 * - The compositor is disabled at run time
4465 * - The compositor is disabled at build time
4466 * The pixmap may be an older copy of the last know good pixmap
4467 * if the window is unmapped.
4468 */
4469 Pixmap
compositorGetWindowPixmapAtSize(ScreenInfo * screen_info,Window id,guint * width,guint * height)4470 compositorGetWindowPixmapAtSize (ScreenInfo *screen_info, Window id, guint *width, guint *height)
4471 {
4472 #ifdef HAVE_NAME_WINDOW_PIXMAP
4473 #ifdef HAVE_COMPOSITOR
4474 CWindow *cw;
4475
4476 TRACE ("window 0x%lx", id);
4477
4478 if (!screen_info->compositor_active)
4479 {
4480 return None;
4481 }
4482
4483 g_return_val_if_fail (id != None, None);
4484
4485 if (!compositorIsActive (screen_info))
4486 {
4487 return None;
4488 }
4489
4490 cw = find_cwindow_in_screen (screen_info, id);
4491 if (is_on_compositor (cw))
4492 {
4493 return compositorScaleWindowPixmap (cw, width, height);
4494 }
4495 #endif /* HAVE_COMPOSITOR */
4496 #endif /* HAVE_NAME_WINDOW_PIXMAP */
4497
4498 return None;
4499 }
4500
4501 void
compositorHandleEvent(DisplayInfo * display_info,XEvent * ev)4502 compositorHandleEvent (DisplayInfo *display_info, XEvent *ev)
4503 {
4504 #ifdef HAVE_COMPOSITOR
4505 g_return_if_fail (display_info != NULL);
4506 g_return_if_fail (ev != NULL);
4507 TRACE ("event type %i", ev->type);
4508
4509 if (!compositorIsUsable (display_info))
4510 {
4511 return;
4512 }
4513 else if (ev->type == CreateNotify)
4514 {
4515 compositorHandleCreateNotify (display_info, (XCreateWindowEvent *) ev);
4516 }
4517 else if (ev->type == DestroyNotify)
4518 {
4519 compositorHandleDestroyNotify (display_info, (XDestroyWindowEvent *) ev);
4520 }
4521 else if (ev->type == ConfigureNotify)
4522 {
4523 compositorHandleConfigureNotify (display_info, (XConfigureEvent *) ev);
4524 }
4525 else if (ev->type == ReparentNotify)
4526 {
4527 compositorHandleReparentNotify (display_info, (XReparentEvent *) ev);
4528 }
4529 else if (ev->type == Expose)
4530 {
4531 compositorHandleExpose (display_info, (XExposeEvent *) ev);
4532 }
4533 else if (ev->type == CirculateNotify)
4534 {
4535 compositorHandleCirculateNotify (display_info, (XCirculateEvent *) ev);
4536 }
4537 else if (ev->type == PropertyNotify)
4538 {
4539 compositorHandlePropertyNotify (display_info, (XPropertyEvent *) ev);
4540 }
4541 else if (ev->type == MapNotify)
4542 {
4543 compositorHandleMapNotify (display_info, (XMapEvent *) ev);
4544 }
4545 else if (ev->type == UnmapNotify)
4546 {
4547 compositorHandleUnmapNotify (display_info, (XUnmapEvent *) ev);
4548 }
4549 else if (ev->type == (display_info->damage_event_base + XDamageNotify))
4550 {
4551 compositorHandleDamage (display_info, (XDamageNotifyEvent *) ev);
4552 }
4553 else if (ev->type == (display_info->shape_event_base + ShapeNotify))
4554 {
4555 compositorHandleShapeNotify (display_info, (XShapeEvent *) ev);
4556 }
4557 else if (ev->type == (display_info->fixes_event_base + XFixesCursorNotify))
4558 {
4559 compositorHandleCursorNotify (display_info, (XFixesCursorNotifyEvent *) ev);
4560 }
4561 #ifdef HAVE_PRESENT_EXTENSION
4562 else if (ev->type == GenericEvent)
4563 {
4564 compositorHandleGenericEvent (display_info, (XGenericEvent *) ev);
4565 }
4566 #endif /* HAVE_PRESENT_EXTENSION */
4567
4568 #endif /* HAVE_COMPOSITOR */
4569 }
4570
4571 void
compositorZoomIn(ScreenInfo * screen_info,XfwmEventButton * event)4572 compositorZoomIn (ScreenInfo *screen_info, XfwmEventButton *event)
4573 {
4574 TRACE ("entering");
4575
4576 #ifdef HAVE_COMPOSITOR
4577 if (!screen_info->compositor_active)
4578 {
4579 return;
4580 }
4581
4582 screen_info->transform.matrix[0][0] -= 4096;
4583 screen_info->transform.matrix[1][1] -= 4096;
4584
4585 if (screen_info->transform.matrix[0][0] < (1 << 10))
4586 {
4587 screen_info->transform.matrix[0][0] = (1 << 10);
4588 screen_info->transform.matrix[1][1] = (1 << 10);
4589 }
4590
4591 if (!screen_info->zoomed)
4592 {
4593 screen_info->cursor_is_zoomed = screen_info->params->zoom_pointer;
4594
4595 if (screen_info->cursor_is_zoomed)
4596 {
4597 XFixesHideCursor (screen_info->display_info->dpy, screen_info->xroot);
4598 screen_info->cursorLocation.x = event->x_root - screen_info->cursorOffsetX;
4599 screen_info->cursorLocation.y = event->y_root - screen_info->cursorOffsetY;
4600 update_cursor (screen_info);
4601 }
4602 }
4603
4604 screen_info->zoomed = TRUE;
4605 if (!screen_info->zoom_timeout_id)
4606 {
4607 gint timeout_rate;
4608
4609 timeout_rate = xfwm_get_primary_refresh_rate (screen_info->gscr);
4610 screen_info->zoom_timeout_id = g_timeout_add ((1000 / timeout_rate /* per second */),
4611 zoom_timeout_cb, screen_info);
4612 }
4613 recenter_zoomed_area (screen_info, event->x_root, event->y_root);
4614 #endif /* HAVE_COMPOSITOR */
4615 }
4616
4617 void
compositorZoomOut(ScreenInfo * screen_info,XfwmEventButton * event)4618 compositorZoomOut (ScreenInfo *screen_info, XfwmEventButton *event)
4619 {
4620 TRACE ("entering");
4621
4622 #ifdef HAVE_COMPOSITOR
4623 if (!screen_info->compositor_active)
4624 {
4625 return;
4626 }
4627
4628 /* don't do anything if the user disabled the zoom feature */
4629 if (screen_info->zoomed)
4630 {
4631 screen_info->transform.matrix[0][0] += 4096;
4632 screen_info->transform.matrix[1][1] += 4096;
4633
4634 if (screen_info->transform.matrix[0][0] >= (1 << 16))
4635 {
4636 screen_info->transform.matrix[0][0] = (1 << 16);
4637 screen_info->transform.matrix[1][1] = (1 << 16);
4638 screen_info->transform.matrix[0][2] = 0;
4639 screen_info->transform.matrix[1][2] = 0;
4640 screen_info->zoomed = FALSE;
4641
4642 if (screen_info->cursor_is_zoomed)
4643 {
4644 XFixesShowCursor (screen_info->display_info->dpy, screen_info->xroot);
4645 }
4646 }
4647 recenter_zoomed_area (screen_info, event->x_root, event->y_root);
4648 }
4649 #endif /* HAVE_COMPOSITOR */
4650 }
4651
4652 void
compositorInitDisplay(DisplayInfo * display_info)4653 compositorInitDisplay (DisplayInfo *display_info)
4654 {
4655 #ifdef HAVE_COMPOSITOR
4656 int composite_major, composite_minor;
4657
4658 composite_major = 0;
4659 composite_minor = 0;
4660
4661 if (!XCompositeQueryExtension (display_info->dpy,
4662 &display_info->composite_event_base,
4663 &display_info->composite_error_base))
4664 {
4665 g_warning ("The display does not support the XComposite extension.");
4666 display_info->have_composite = FALSE;
4667 display_info->composite_event_base = 0;
4668 display_info->composite_error_base = 0;
4669 }
4670 else
4671 {
4672 display_info->have_composite = TRUE;
4673 XCompositeQueryVersion (display_info->dpy, &composite_major, &composite_minor);
4674
4675 DBG ("composite event base: %i", display_info->composite_event_base);
4676 DBG ("composite error base: %i", display_info->composite_error_base);
4677 DBG ("composite version: %i.%i", composite_major, composite_minor);
4678 }
4679
4680 if (!XDamageQueryExtension (display_info->dpy,
4681 &display_info->damage_event_base,
4682 &display_info->damage_error_base))
4683 {
4684 g_warning ("The display does not support the XDamage extension.");
4685 display_info->have_damage = FALSE;
4686 display_info->damage_event_base = 0;
4687 display_info->damage_error_base = 0;
4688 }
4689 else
4690 {
4691 display_info->have_damage = TRUE;
4692
4693 DBG ("damage event base: %i", display_info->damage_event_base);
4694 DBG ("damage error base: %i", display_info->damage_error_base);
4695 }
4696
4697 if (!XFixesQueryExtension (display_info->dpy,
4698 &display_info->fixes_event_base,
4699 &display_info->fixes_error_base))
4700 {
4701 g_warning ("The display does not support the XFixes extension.");
4702 display_info->have_fixes = FALSE;
4703 display_info->fixes_event_base = 0;
4704 display_info->fixes_error_base = 0;
4705 }
4706 else
4707 {
4708 display_info->have_fixes = TRUE;
4709
4710 DBG ("fixes event base: %i", display_info->fixes_event_base);
4711 DBG ("fixes error base: %i", display_info->fixes_error_base);
4712 }
4713
4714 #ifdef HAVE_PRESENT_EXTENSION
4715 if (!XPresentQueryExtension (display_info->dpy,
4716 &display_info->present_opcode,
4717 &display_info->present_event_base,
4718 &display_info->present_error_base))
4719 {
4720 g_warning ("The display does not support the XPresent extension.");
4721 display_info->have_present = FALSE;
4722 display_info->present_opcode = 0;
4723 display_info->present_event_base = 0;
4724 display_info->present_error_base = 0;
4725 }
4726 else
4727 {
4728 display_info->have_present = TRUE;
4729 DBG ("present opcode: %i", display_info->present_opcode);
4730 DBG ("present event base: %i", display_info->present_event_base);
4731 DBG ("present error base: %i", display_info->present_error_base);
4732 }
4733 #endif /* HAVE_PRESENT_EXTENSION */
4734
4735 display_info->enable_compositor = ((display_info->have_render)
4736 && (display_info->have_composite)
4737 && (display_info->have_damage)
4738 && (display_info->have_fixes));
4739 if (!display_info->enable_compositor)
4740 {
4741 g_warning ("Compositing manager disabled.");
4742 }
4743
4744 #if HAVE_NAME_WINDOW_PIXMAP
4745 display_info->have_name_window_pixmap = ((composite_major > 0) || (composite_minor >= 2));
4746 #else /* HAVE_NAME_WINDOW_PIXMAP */
4747 display_info->have_name_window_pixmap = FALSE;
4748 #endif /* HAVE_NAME_WINDOW_PIXMAP */
4749
4750 #if HAVE_OVERLAYS
4751 display_info->have_overlays = ((composite_major > 0) || (composite_minor >= 3));
4752 #endif /* HAVE_OVERLAYS */
4753
4754 #else /* HAVE_COMPOSITOR */
4755 display_info->enable_compositor = FALSE;
4756 #endif /* HAVE_COMPOSITOR */
4757 }
4758
4759 gboolean
compositorManageScreen(ScreenInfo * screen_info)4760 compositorManageScreen (ScreenInfo *screen_info)
4761 {
4762 #ifdef HAVE_COMPOSITOR
4763 DisplayInfo *display_info;
4764 XRenderPictureAttributes pa;
4765 XRenderPictFormat *visual_format;
4766 gushort buffer;
4767
4768 g_return_val_if_fail (screen_info != NULL, FALSE);
4769 TRACE ("entering compositorManageScreen");
4770
4771 if (compositorCheckCMSelection (screen_info))
4772 {
4773 g_warning ("Another compositing manager is running on screen %i", screen_info->screen);
4774 return FALSE;
4775 }
4776
4777 compositorSetCMSelection (screen_info, screen_info->xfwm4_win);
4778 display_info = screen_info->display_info;
4779
4780 screen_info->output = screen_info->xroot;
4781 #if HAVE_OVERLAYS
4782 if (display_info->have_overlays)
4783 {
4784 screen_info->overlay = XCompositeGetOverlayWindow (display_info->dpy, screen_info->xroot);
4785 if (screen_info->overlay != None)
4786 {
4787 XserverRegion region;
4788 XSetWindowAttributes attributes;
4789
4790 XMapRaised (display_info->dpy, screen_info->overlay);
4791
4792 region = XFixesCreateRegion (display_info->dpy, NULL, 0);
4793 XFixesSetWindowShapeRegion (display_info->dpy, screen_info->overlay,
4794 ShapeBounding, 0, 0, 0);
4795 XFixesSetWindowShapeRegion (display_info->dpy, screen_info->overlay,
4796 ShapeInput, 0, 0, region);
4797 XFixesDestroyRegion (display_info->dpy, region);
4798
4799 screen_info->root_overlay = XCreateWindow (display_info->dpy, screen_info->overlay,
4800 0, 0, screen_info->width, screen_info->height, 0, screen_info->depth,
4801 InputOutput, screen_info->visual, 0, &attributes);
4802 XMapRaised (display_info->dpy, screen_info->root_overlay);
4803
4804 screen_info->output = screen_info->root_overlay;
4805 DBG ("Overlay enabled (0x%lx -> 0x%lx)", screen_info->overlay, screen_info->root_overlay);
4806 }
4807 else
4808 {
4809 /* Something is wrong with overlay support */
4810 DBG ("Cannot get root window overlay, overlay support disabled");
4811 display_info->have_overlays = FALSE;
4812 }
4813 }
4814 #endif /* HAVE_OVERLAYS */
4815 DBG ("Window used for output: 0x%lx (%s)", screen_info->output, display_info->have_overlays ? "overlay" : "root");
4816
4817 XCompositeRedirectSubwindows (display_info->dpy, screen_info->xroot, CompositeRedirectManual);
4818 screen_info->compositor_active = TRUE;
4819
4820 visual_format = XRenderFindVisualFormat (display_info->dpy,
4821 DefaultVisual (display_info->dpy,
4822 screen_info->screen));
4823 if (!visual_format)
4824 {
4825 g_warning ("Cannot find visual format on screen %i", screen_info->screen);
4826 compositorUnmanageScreen (screen_info);
4827 return FALSE;
4828 }
4829
4830 pa.subwindow_mode = IncludeInferiors;
4831 screen_info->rootPicture = XRenderCreatePicture (display_info->dpy, screen_info->output,
4832 visual_format, CPSubwindowMode, &pa);
4833
4834 if (screen_info->rootPicture == None)
4835 {
4836 g_warning ("Cannot create root picture on screen %i", screen_info->screen);
4837 compositorUnmanageScreen (screen_info);
4838 return FALSE;
4839 }
4840
4841 screen_info->gaussianSize = -1;
4842 screen_info->gaussianMap = make_gaussian_map(SHADOW_RADIUS);
4843 presum_gaussian (screen_info);
4844 screen_info->cursorPicture = None;
4845 /* Change following argb values to play with shadow colors */
4846 screen_info->blackPicture = solid_picture (screen_info,
4847 TRUE,
4848 1.0, /* alpha */
4849 0.0, /* red */
4850 0.0, /* green */
4851 0.0 /* blue */);
4852 screen_info->rootTile = None;
4853 screen_info->allDamage = None;
4854 screen_info->prevDamage = None;
4855 screen_info->screenRegion = get_screen_region (screen_info);
4856 screen_info->cwindows = NULL;
4857 screen_info->cwindow_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
4858 screen_info->wins_unredirected = 0;
4859 screen_info->compositor_timeout_id = 0;
4860 screen_info->zoomed = FALSE;
4861 screen_info->zoom_timeout_id = 0;
4862 screen_info->damages_pending = FALSE;
4863 screen_info->current_buffer = 0;
4864 memset(screen_info->transform.matrix, 0, 9);
4865 screen_info->transform.matrix[0][0] = 1 << 16;
4866 screen_info->transform.matrix[1][1] = 1 << 16;
4867 screen_info->transform.matrix[2][2] = 1 << 16;
4868 screen_info->zoomBuffer = None;
4869 screen_info->use_n_buffers = 1;
4870 for (buffer = 0; buffer < N_BUFFERS; buffer++)
4871 {
4872 screen_info->rootPixmap[buffer] = None;
4873 screen_info->rootBuffer[buffer] = None;
4874 #ifdef HAVE_EPOXY
4875 screen_info->glx_drawable[buffer] = None;
4876 #ifdef HAVE_XSYNC
4877 screen_info->fence[buffer] = None;
4878 #endif /* HAVE_XSYNC */
4879 #endif /* HAVE_EPOXY */
4880 }
4881 XClearArea (display_info->dpy, screen_info->output, 0, 0, 0, 0, TRUE);
4882 TRACE ("manual compositing enabled");
4883
4884 #ifdef HAVE_EPOXY
4885 screen_info->use_glx = (screen_info->vblank_mode == VBLANK_AUTO ||
4886 screen_info->vblank_mode == VBLANK_GLX);
4887 #ifdef HAVE_XSYNC
4888 screen_info->use_glx &= display_info->have_xsync;
4889 #endif /* HAVE_XSYNC */
4890
4891 if (screen_info->use_glx)
4892 {
4893 screen_info->use_n_buffers = 1;
4894 screen_info->glx_context = None;
4895 screen_info->glx_window = None;
4896 screen_info->rootTexture = None;
4897 screen_info->texture_filter = GL_LINEAR;
4898 screen_info->gl_sync = 0;
4899 screen_info->use_glx = init_glx (screen_info);
4900 }
4901 #else /* HAVE_EPOXY */
4902 screen_info->use_glx = FALSE;
4903 #endif /* HAVE_EPOXY */
4904
4905 #ifdef HAVE_PRESENT_EXTENSION
4906 screen_info->use_present = display_info->have_present &&
4907 #ifdef HAVE_EPOXY
4908 !screen_info->use_glx &&
4909 #endif /* HAVE_EPOXY */
4910 (screen_info->vblank_mode == VBLANK_AUTO ||
4911 screen_info->vblank_mode == VBLANK_XPRESENT);
4912 if (screen_info->use_present)
4913 {
4914 screen_info->use_n_buffers = N_BUFFERS;
4915 screen_info->present_pending = FALSE;
4916 XPresentSelectInput (display_info->dpy,
4917 screen_info->output,
4918 PresentCompleteNotifyMask);
4919 }
4920 #else /* HAVE_PRESENT_EXTENSION */
4921 screen_info->use_present = FALSE;
4922 #endif /* HAVE_PRESENT_EXTENSION */
4923
4924 if (screen_info->use_present)
4925 {
4926 g_info ("Compositor using XPresent for vsync");
4927 }
4928 else if (screen_info->use_glx)
4929 {
4930 g_info ("Compositor using GLX for vsync");
4931 }
4932 else
4933 {
4934 g_info ("No vsync support in compositor");
4935 }
4936
4937 XFixesSelectCursorInput (display_info->dpy,
4938 screen_info->xroot,
4939 XFixesDisplayCursorNotifyMask);
4940
4941 return TRUE;
4942 #else
4943 return FALSE;
4944 #endif /* HAVE_COMPOSITOR */
4945 }
4946
4947 void
compositorUnmanageScreen(ScreenInfo * screen_info)4948 compositorUnmanageScreen (ScreenInfo *screen_info)
4949 {
4950 #ifdef HAVE_COMPOSITOR
4951 DisplayInfo *display_info;
4952 GList *list;
4953 gushort buffer;
4954
4955 g_return_if_fail (screen_info != NULL);
4956 TRACE ("entering compositorUnmanageScreen");
4957
4958 display_info = screen_info->display_info;
4959 if (!compositorIsUsable (display_info))
4960 {
4961 return;
4962 }
4963
4964 if (!screen_info->compositor_active)
4965 {
4966 TRACE ("compositor not active on screen %i", screen_info->screen);
4967 return;
4968 }
4969 screen_info->compositor_active = FALSE;
4970
4971 remove_timeouts (screen_info);
4972
4973 myDisplayErrorTrapPush (display_info);
4974
4975 for (list = screen_info->cwindows; list; list = g_list_next (list))
4976 {
4977 CWindow *cw2 = (CWindow *) list->data;
4978 free_win_data (cw2, TRUE);
4979 }
4980
4981 g_hash_table_destroy(screen_info->cwindow_hash);
4982 screen_info->cwindow_hash = NULL;
4983 g_list_free (screen_info->cwindows);
4984 screen_info->cwindows = NULL;
4985
4986 #ifdef HAVE_EPOXY
4987 if (screen_info->use_glx)
4988 {
4989 free_glx_data (screen_info);
4990 for (buffer = 0; buffer < screen_info->use_n_buffers; buffer++)
4991 {
4992 destroy_glx_drawable (screen_info, buffer);
4993 }
4994 }
4995 #endif /* HAVE_EPOXY */
4996
4997 for (buffer = 0; buffer < screen_info->use_n_buffers; buffer++)
4998 {
4999 if (screen_info->rootPixmap[buffer])
5000 {
5001 XFreePixmap (display_info->dpy, screen_info->rootPixmap[buffer]);
5002 screen_info->rootPixmap[buffer] = None;
5003 }
5004 if (screen_info->rootBuffer[buffer])
5005 {
5006 XRenderFreePicture (display_info->dpy, screen_info->rootBuffer[buffer]);
5007 screen_info->rootBuffer[buffer] = None;
5008 }
5009 #ifdef HAVE_EPOXY
5010 fence_destroy (screen_info, buffer);
5011 #endif /* HAVE_EPOXY */
5012 }
5013
5014 if (screen_info->allDamage)
5015 {
5016 XFixesDestroyRegion (display_info->dpy, screen_info->allDamage);
5017 screen_info->allDamage = None;
5018 }
5019
5020 if (screen_info->prevDamage)
5021 {
5022 XFixesDestroyRegion (display_info->dpy, screen_info->prevDamage);
5023 screen_info->prevDamage = None;
5024 }
5025
5026 if (screen_info->screenRegion)
5027 {
5028 XFixesDestroyRegion (display_info->dpy, screen_info->screenRegion);
5029 screen_info->screenRegion = None;
5030 }
5031
5032 if (screen_info->zoomBuffer)
5033 {
5034 XRenderFreePicture (display_info->dpy, screen_info->zoomBuffer);
5035 screen_info->zoomBuffer = None;
5036 }
5037
5038 if (screen_info->rootPicture)
5039 {
5040 XRenderFreePicture (display_info->dpy, screen_info->rootPicture);
5041 screen_info->rootPicture = None;
5042 }
5043
5044 if (screen_info->blackPicture)
5045 {
5046 XRenderFreePicture (display_info->dpy, screen_info->blackPicture);
5047 screen_info->blackPicture = None;
5048 }
5049 if (screen_info->cursorPicture)
5050 {
5051 XRenderFreePicture (display_info->dpy, screen_info->cursorPicture);
5052 screen_info->cursorPicture = None;
5053 }
5054
5055 if (screen_info->shadowTop)
5056 {
5057 g_free (screen_info->shadowTop);
5058 screen_info->shadowTop = NULL;
5059 }
5060
5061 if (screen_info->shadowCorner)
5062 {
5063 g_free (screen_info->shadowCorner);
5064 screen_info->shadowCorner = NULL;
5065 }
5066
5067 if (screen_info->gaussianMap)
5068 {
5069 g_free (screen_info->gaussianMap);
5070 screen_info->gaussianMap = NULL;
5071 }
5072
5073 #if HAVE_OVERLAYS
5074 if (display_info->have_overlays)
5075 {
5076 XDestroyWindow (display_info->dpy, screen_info->root_overlay);
5077 screen_info->root_overlay = None;
5078
5079 XCompositeReleaseOverlayWindow (display_info->dpy, screen_info->overlay);
5080 screen_info->overlay = None;
5081 }
5082 #endif /* HAVE_OVERLAYS */
5083
5084 screen_info->gaussianSize = -1;
5085 screen_info->wins_unredirected = 0;
5086
5087 if (screen_info->zoomed)
5088 {
5089 XFixesShowCursor (display_info->dpy, screen_info->xroot);
5090 }
5091
5092 XCompositeUnredirectSubwindows (display_info->dpy, screen_info->xroot,
5093 CompositeRedirectManual);
5094 screen_info->output = screen_info->xroot;
5095
5096 compositorSetCMSelection (screen_info, None);
5097
5098 myDisplayErrorTrapPopIgnored (display_info);
5099 #endif /* HAVE_COMPOSITOR */
5100 }
5101
5102 void
compositorAddAllWindows(ScreenInfo * screen_info)5103 compositorAddAllWindows (ScreenInfo *screen_info)
5104 {
5105 #ifdef HAVE_COMPOSITOR
5106 DisplayInfo *display_info;
5107 Window w1, w2, *wins;
5108 unsigned int count, i;
5109
5110 TRACE ("entering");
5111
5112 display_info = screen_info->display_info;
5113 if (!compositorIsUsable (display_info))
5114 {
5115 return;
5116 }
5117
5118 myDisplayGrabServer (display_info);
5119 XQueryTree (display_info->dpy, screen_info->xroot, &w1, &w2, &wins, &count);
5120
5121 for (i = 0; i < count; i++)
5122 {
5123 Client *c;
5124
5125 c = myScreenGetClientFromWindow (screen_info, wins[i], SEARCH_FRAME);
5126 compositorAddWindow (display_info, wins[i], c);
5127 }
5128 if (wins)
5129 {
5130 XFree (wins);
5131 }
5132 myDisplayUngrabServer (display_info);
5133 #endif /* HAVE_COMPOSITOR */
5134 }
5135
5136 gboolean
compositorActivateScreen(ScreenInfo * screen_info,gboolean active)5137 compositorActivateScreen (ScreenInfo *screen_info, gboolean active)
5138 {
5139 #ifdef HAVE_COMPOSITOR
5140 DisplayInfo *display_info;
5141
5142 g_return_val_if_fail (screen_info != NULL, FALSE);
5143 TRACE ("active %s", active ? "TRUE" : "FALSE");
5144
5145 display_info = screen_info->display_info;
5146 if (!compositorIsUsable (display_info))
5147 {
5148 return FALSE;
5149 }
5150
5151 if (screen_info->compositor_active == active)
5152 {
5153 return FALSE;
5154 }
5155
5156 if (active)
5157 {
5158 compositorManageScreen (screen_info);
5159 compositorAddAllWindows (screen_info);
5160 }
5161 else
5162 {
5163 compositorUnmanageScreen (screen_info);
5164 }
5165
5166 return TRUE;
5167 #else /* HAVE_COMPOSITOR */
5168 return FALSE;
5169 #endif /* HAVE_COMPOSITOR */
5170 }
5171
5172 void
compositorUpdateScreenSize(ScreenInfo * screen_info)5173 compositorUpdateScreenSize (ScreenInfo *screen_info)
5174 {
5175 #ifdef HAVE_COMPOSITOR
5176 DisplayInfo *display_info;
5177 gushort buffer;
5178
5179 g_return_if_fail (screen_info != NULL);
5180 TRACE ("entering");
5181
5182 display_info = screen_info->display_info;
5183 if (!compositorIsUsable (display_info))
5184 {
5185 return;
5186 }
5187
5188 myDisplayErrorTrapPush (display_info);
5189 #if HAVE_OVERLAYS
5190 if (display_info->have_overlays)
5191 {
5192 XResizeWindow (display_info->dpy, screen_info->overlay, screen_info->width, screen_info->height);
5193 XResizeWindow (display_info->dpy, screen_info->root_overlay, screen_info->width, screen_info->height);
5194 }
5195 #endif
5196 if (screen_info->zoomBuffer)
5197 {
5198 XRenderFreePicture (display_info->dpy, screen_info->zoomBuffer);
5199 screen_info->zoomBuffer = None;
5200 }
5201
5202 #ifdef HAVE_EPOXY
5203 if (screen_info->use_glx)
5204 {
5205 for (buffer = 0; buffer < screen_info->use_n_buffers; buffer++)
5206 {
5207 destroy_glx_drawable (screen_info, buffer);
5208 }
5209 }
5210 #endif /* HAVE_EPOXY */
5211
5212 for (buffer = 0; buffer < screen_info->use_n_buffers; buffer++)
5213 {
5214 if (screen_info->rootPixmap[buffer])
5215 {
5216 XFreePixmap (display_info->dpy, screen_info->rootPixmap[buffer]);
5217 screen_info->rootPixmap[buffer] = None;
5218 }
5219 if (screen_info->rootBuffer[buffer])
5220 {
5221 XRenderFreePicture (display_info->dpy, screen_info->rootBuffer[buffer]);
5222 screen_info->rootBuffer[buffer] = None;
5223 }
5224 #ifdef HAVE_EPOXY
5225 fence_destroy (screen_info, buffer);
5226 #endif /* HAVE_EPOXY */
5227 }
5228
5229 if (screen_info->screenRegion)
5230 {
5231 XFixesDestroyRegion (display_info->dpy, screen_info->screenRegion);
5232 screen_info->screenRegion = None;
5233 }
5234
5235 damage_screen (screen_info);
5236 myDisplayErrorTrapPopIgnored (display_info);
5237 #endif /* HAVE_COMPOSITOR */
5238 }
5239
5240 void
compositorWindowSetOpacity(DisplayInfo * display_info,Window id,guint32 opacity)5241 compositorWindowSetOpacity (DisplayInfo *display_info, Window id, guint32 opacity)
5242 {
5243 #ifdef HAVE_COMPOSITOR
5244 CWindow *cw;
5245
5246 g_return_if_fail (display_info != NULL);
5247 g_return_if_fail (id != None);
5248 TRACE ("window 0x%lx", id);
5249
5250 if (!compositorIsUsable (display_info))
5251 {
5252 return;
5253 }
5254
5255 cw = find_cwindow_in_display (display_info, id);
5256 if (cw)
5257 {
5258 set_win_opacity (cw, opacity);
5259 }
5260 #endif /* HAVE_COMPOSITOR */
5261 }
5262
5263 void
compositorRebuildScreen(ScreenInfo * screen_info)5264 compositorRebuildScreen (ScreenInfo *screen_info)
5265 {
5266 #ifdef HAVE_COMPOSITOR
5267 DisplayInfo *display_info;
5268 GList *list;
5269
5270 g_return_if_fail (screen_info != NULL);
5271 TRACE ("entering");
5272
5273 display_info = screen_info->display_info;
5274 if (!compositorIsUsable (display_info))
5275 {
5276 return;
5277 }
5278
5279 for (list = screen_info->cwindows; list; list = g_list_next (list))
5280 {
5281 CWindow *cw2 = (CWindow *) list->data;
5282 free_win_data (cw2, FALSE);
5283 init_opacity (cw2);
5284 }
5285 damage_screen (screen_info);
5286 #endif /* HAVE_COMPOSITOR */
5287 }
5288
5289 gboolean
compositorTestServer(DisplayInfo * display_info)5290 compositorTestServer (DisplayInfo *display_info)
5291 {
5292 #ifdef HAVE_COMPOSITOR
5293 char *vendor;
5294
5295 g_return_val_if_fail (display_info != NULL, FALSE);
5296 TRACE ("entering");
5297
5298 vendor = ServerVendor (display_info->dpy);
5299
5300 if (vendor && (!strstr ("X.Org", vendor)))
5301 {
5302 /*
5303 Check the version, X.org 6.8.x has some bugs that makes
5304 it not suitable for use with xfwm4 compositor
5305 */
5306 if ((VendorRelease(display_info->dpy) / 10) <= 68)
5307 {
5308 return FALSE;
5309 }
5310 }
5311 return TRUE;
5312 #else /* HAVE_COMPOSITOR */
5313 return FALSE;
5314 #endif /* HAVE_COMPOSITOR */
5315 }
5316
5317 vblankMode
compositorParseVblankMode(const gchar * vblank_setting)5318 compositorParseVblankMode (const gchar *vblank_setting)
5319 {
5320 #ifdef HAVE_PRESENT_EXTENSION
5321 if (g_ascii_strcasecmp (vblank_setting, "xpresent") == 0)
5322 {
5323 return VBLANK_XPRESENT;
5324 }
5325 else
5326 #endif /* HAVE_PRESENT_EXTENSION */
5327 #ifdef HAVE_EPOXY
5328 if (g_ascii_strcasecmp (vblank_setting, "glx") == 0)
5329 {
5330 return VBLANK_GLX;
5331 }
5332 else
5333 #endif /* HAVE_EPOXY */
5334 if (g_ascii_strcasecmp (vblank_setting, "off") == 0)
5335 {
5336 return VBLANK_OFF;
5337 }
5338
5339 return VBLANK_AUTO;
5340 }
5341
5342 void
compositorSetVblankMode(ScreenInfo * screen_info,vblankMode vblank_mode)5343 compositorSetVblankMode (ScreenInfo *screen_info,
5344 vblankMode vblank_mode)
5345 {
5346 #ifdef HAVE_COMPOSITOR
5347 g_return_if_fail (screen_info != NULL);
5348 TRACE ("entering");
5349
5350 screen_info->vblank_mode = vblank_mode;
5351 #endif /* HAVE_COMPOSITOR */
5352 }
5353