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, &region_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