1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 
3 /*
4  * Copyright (C) 2007 Iain Holmes
5  * Based on xcompmgr - (c) 2003 Keith Packard
6  *          xfwm4    - (c) 2005-2007 Olivier Fourdan
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301, USA.
22  */
23 
24 #define _GNU_SOURCE
25 #define _XOPEN_SOURCE 500 /* for usleep() */
26 
27 #include <config.h>
28 
29 #ifdef HAVE_COMPOSITE_EXTENSIONS
30 
31 #include <stdlib.h>
32 #include <string.h>
33 #include <limits.h>
34 #include <math.h>
35 #include <unistd.h>
36 
37 #include <gdk/gdk.h>
38 #include <gdk/gdkx.h>
39 #include <gtk/gtk.h>
40 
41 #include <cairo/cairo-xlib.h>
42 
43 #include "display.h"
44 #include "../core/display-private.h"
45 #include "../core/screen-private.h"
46 #include "../core/workspace.h"
47 #include "screen.h"
48 #include "frame.h"
49 #include "errors.h"
50 #include "window.h"
51 #include "compositor-private.h"
52 #include "compositor-xrender.h"
53 #include "xprops.h"
54 #include "core.h"
55 #include <X11/Xatom.h>
56 #include <X11/extensions/shape.h>
57 #include <X11/extensions/Xcomposite.h>
58 #include <X11/extensions/Xdamage.h>
59 #include <X11/extensions/Xfixes.h>
60 #include <X11/extensions/Xrender.h>
61 
62 #ifdef HAVE_PRESENT
63 #include <X11/extensions/Xpresent.h>
64 #endif
65 
66 #define USE_IDLE_REPAINT 1
67 
68 typedef enum _MetaCompWindowType
69 {
70   META_COMP_WINDOW_NORMAL,
71   META_COMP_WINDOW_DND,
72   META_COMP_WINDOW_DESKTOP,
73   META_COMP_WINDOW_DOCK,
74   META_COMP_WINDOW_MENU,
75   META_COMP_WINDOW_DROP_DOWN_MENU,
76   META_COMP_WINDOW_TOOLTIP,
77 } MetaCompWindowType;
78 
79 typedef enum _MetaShadowType
80 {
81   META_SHADOW_SMALL,
82   META_SHADOW_MEDIUM,
83   META_SHADOW_LARGE,
84   LAST_SHADOW_TYPE
85 } MetaShadowType;
86 
87 typedef struct _MetaCompositorXRender
88 {
89   MetaCompositor compositor;
90 
91   MetaDisplay *display;
92 
93   Atom atom_x_root_pixmap;
94   Atom atom_x_set_root;
95   Atom atom_net_wm_window_opacity;
96   Atom atom_net_wm_window_type_dnd;
97 
98   Atom atom_net_wm_window_type;
99   Atom atom_net_wm_window_type_desktop;
100   Atom atom_net_wm_window_type_dock;
101   Atom atom_net_wm_window_type_menu;
102   Atom atom_net_wm_window_type_dialog;
103   Atom atom_net_wm_window_type_normal;
104   Atom atom_net_wm_window_type_utility;
105   Atom atom_net_wm_window_type_splash;
106   Atom atom_net_wm_window_type_toolbar;
107   Atom atom_net_wm_window_type_dropdown_menu;
108   Atom atom_net_wm_window_type_tooltip;
109 
110 #ifdef USE_IDLE_REPAINT
111   guint repaint_id;
112 #endif
113   guint enabled : 1;
114   guint show_redraw : 1;
115   guint debug : 1;
116 
117 #ifdef HAVE_PRESENT
118   guint has_present : 1;
119   int present_major;
120 #endif /* HAVE_PRESENT */
121 } MetaCompositorXRender;
122 
123 typedef struct _conv
124 {
125   int size;
126   double *data;
127 } conv;
128 
129 typedef struct _shadow
130 {
131   conv *gaussian_map;
132   guchar *shadow_corner;
133   guchar *shadow_top;
134 } shadow;
135 
136 #define NUM_BUFFER      2
137 typedef struct _MetaCompScreen
138 {
139   MetaScreen *screen;
140   GList *windows;
141   GHashTable *windows_by_xid;
142 
143   MetaWindow *focus_window;
144 
145   Window output;
146 
147   gboolean have_shadows;
148   shadow *shadows[LAST_SHADOW_TYPE];
149 
150   Picture root_picture;
151   Picture root_buffers[NUM_BUFFER];
152   Pixmap  root_pixmaps[NUM_BUFFER];
153   int root_current;
154   Picture black_picture;
155   Picture trans_black_picture;
156   Picture root_tile;
157   XserverRegion all_damage;
158 #ifdef HAVE_PRESENT
159   XserverRegion prev_damage;
160 
161   XID present_eid;
162   gboolean use_present;
163   gboolean present_pending;
164 #endif /* HAVE_PRESENT */
165 
166   guint overlays;
167   gboolean compositor_active;
168   gboolean clip_changed;
169 
170   GSList *dock_windows;
171 } MetaCompScreen;
172 
173 typedef struct _MetaCompWindow
174 {
175   MetaScreen *screen;
176   MetaWindow *window; /* May be NULL if this window isn't managed by Marco */
177   Window id;
178   XWindowAttributes attrs;
179 
180   Pixmap back_pixmap;
181 
182   /* When the window is shaded back_pixmap will be replaced with the pixmap
183      for the shaded window. This is a copy of the original unshaded window
184      so that we can still see what the window looked like when it is needed
185      for the _get_window_pixmap function */
186   Pixmap shaded_back_pixmap;
187 
188   int mode;
189 
190   gboolean damaged;
191   gboolean shaped;
192 
193   XRectangle shape_bounds;
194 
195   MetaCompWindowType type;
196 
197   Damage damage;
198   Picture picture;
199   Picture alpha_pict;
200 
201   gboolean needs_shadow;
202   MetaShadowType shadow_type;
203   Picture shadow_pict;
204 
205   XserverRegion border_size;
206   XserverRegion extents;
207 
208   Picture shadow;
209   int shadow_dx;
210   int shadow_dy;
211   int shadow_width;
212   int shadow_height;
213 
214   guint opacity;
215 
216   XserverRegion border_clip;
217 
218   gboolean updates_frozen;
219   gboolean update_pending;
220 } MetaCompWindow;
221 
222 #define OPAQUE 0xffffffff
223 
224 #define WINDOW_SOLID 0
225 #define WINDOW_ARGB 1
226 
227 #define SHADOW_SMALL_RADIUS 3.0
228 #define SHADOW_MEDIUM_RADIUS 6.0
229 #define SHADOW_LARGE_RADIUS 12.0
230 
231 #define SHADOW_SMALL_OFFSET_X (SHADOW_SMALL_RADIUS * -3 / 2)
232 #define SHADOW_SMALL_OFFSET_Y (SHADOW_SMALL_RADIUS * -3 / 2)
233 #define SHADOW_MEDIUM_OFFSET_X (SHADOW_MEDIUM_RADIUS * -3 / 2)
234 #define SHADOW_MEDIUM_OFFSET_Y (SHADOW_MEDIUM_RADIUS * -5 / 4)
235 #define SHADOW_LARGE_OFFSET_X -15
236 #define SHADOW_LARGE_OFFSET_Y -15
237 
238 #define SHADOW_OPACITY 0.66
239 
240 #define TRANS_OPACITY 0.75
241 
242 #define DISPLAY_COMPOSITOR(display) ((MetaCompositorXRender *) meta_display_get_compositor (display))
243 
244 /* Gaussian stuff for creating the shadows */
245 static double
gaussian(double r,double x,double y)246 gaussian (double r,
247           double x,
248           double y)
249 {
250   return ((1 / (sqrt (2 * G_PI * r))) *
251           exp ((- (x * x + y * y)) / (2 * r * r)));
252 }
253 
254 static conv *
make_gaussian_map(double r)255 make_gaussian_map (double r)
256 {
257   conv *c;
258   int size, centre;
259   int x, y;
260   double t, g;
261 
262   size = ((int) ceil ((r * 3)) + 1) & ~1;
263   centre = size / 2;
264   c = g_malloc (sizeof (conv) + size * size * sizeof (double));
265   c->size = size;
266   c->data = (double *) (c + 1);
267   t = 0.0;
268 
269   for (y = 0; y < size; y++)
270     {
271       for (x = 0; x < size; x++)
272         {
273           g = gaussian (r, (double) (x - centre), (double) (y - centre));
274           t += g;
275           c->data[y * size + x] = g;
276         }
277     }
278 
279   for (y = 0; y < size; y++)
280     {
281       for (x = 0; x < size; x++)
282         {
283           c->data[y * size + x] /= t;
284         }
285     }
286 
287   return c;
288 }
289 
290 static void
dump_xserver_region(const char * location,MetaDisplay * display,XserverRegion region)291 dump_xserver_region (const char   *location,
292                      MetaDisplay  *display,
293                      XserverRegion region)
294 {
295   MetaCompositorXRender *compositor = DISPLAY_COMPOSITOR (display);
296   Display *xdisplay = meta_display_get_xdisplay (display);
297   int nrects;
298   XRectangle *rects;
299   XRectangle bounds;
300 
301   if (!compositor->debug)
302     return;
303 
304   if (region)
305     {
306       rects = XFixesFetchRegionAndBounds (xdisplay, region, &nrects, &bounds);
307       if (nrects > 0)
308         {
309           int i;
310           fprintf (stderr, "%s (XSR): %d rects, bounds: %d,%d (%d,%d)\n",
311                    location, nrects, bounds.x, bounds.y, bounds.width, bounds.height);
312           for (i = 1; i < nrects; i++)
313             fprintf (stderr, "\t%d,%d (%d,%d)\n",
314                      rects[i].x, rects[i].y, rects[i].width, rects[i].height);
315         }
316       else
317         fprintf (stderr, "%s (XSR): empty\n", location);
318       XFree (rects);
319     }
320   else
321     fprintf (stderr, "%s (XSR): null\n", location);
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 static guchar
sum_gaussian(conv * map,double opacity,int x,int y,int width,int height)341 sum_gaussian (conv          *map,
342               double         opacity,
343               int            x,
344               int            y,
345               int            width,
346               int            height)
347 {
348   double *g_data, *g_line;
349   double v;
350   int fx, fy;
351   int fx_start, fx_end;
352   int fy_start, fy_end;
353   int g_size, centre;
354 
355   g_line = map->data;
356   g_size = map->size;
357   centre = g_size / 2;
358   fx_start = centre - x;
359   if (fx_start < 0)
360     fx_start = 0;
361 
362   fx_end = width + centre - x;
363   if (fx_end > g_size)
364     fx_end = g_size;
365 
366   fy_start = centre - y;
367   if (fy_start < 0)
368     fy_start = 0;
369 
370   fy_end = height + centre - y;
371   if (fy_end > g_size)
372     fy_end = g_size;
373 
374   g_line = g_line + fy_start * g_size + fx_start;
375 
376   v = 0.0;
377   for (fy = fy_start; fy < fy_end; fy++)
378     {
379       g_data = g_line;
380       g_line += g_size;
381 
382       for (fx = fx_start; fx < fx_end; fx++)
383         v += *g_data++;
384     }
385 
386   if (v > 1.0)
387     v = 1.0;
388 
389   return ((guchar) (v * opacity * 255.0));
390 }
391 
392 /* precompute shadow corners and sides to save time for large windows */
393 static void
presum_gaussian(shadow * shad)394 presum_gaussian (shadow *shad)
395 {
396   int centre;
397   int opacity, x, y;
398   int msize;
399   conv *map;
400 
401   map = shad->gaussian_map;
402   msize = map->size;
403   centre = map->size / 2;
404 
405   if (shad->shadow_corner)
406     g_free (shad->shadow_corner);
407   if (shad->shadow_top)
408     g_free (shad->shadow_top);
409 
410   shad->shadow_corner = (guchar *)(g_malloc ((msize + 1) * (msize + 1) * 26));
411   shad->shadow_top = (guchar *) (g_malloc ((msize + 1) * 26));
412 
413   for (x = 0; x <= msize; x++)
414     {
415 
416       shad->shadow_top[25 * (msize + 1) + x] =
417         sum_gaussian (map, 1, x - centre, centre, msize * 2, msize * 2);
418       for (opacity = 0; opacity < 25; opacity++)
419         {
420           shad->shadow_top[opacity * (msize + 1) + x] =
421             shad->shadow_top[25 * (msize + 1) + x] * opacity / 25;
422         }
423 
424       for (y = 0; y <= x; y++)
425         {
426           shad->shadow_corner[25 * (msize + 1) * (msize + 1)
427                               + y * (msize + 1)
428                               + x]
429             = sum_gaussian (map, 1, x - centre, y - centre,
430                             msize * 2, msize * 2);
431 
432           shad->shadow_corner[25 * (msize + 1) * (msize + 1)
433                               + x * (msize + 1) + y] =
434             shad->shadow_corner[25 * (msize + 1) * (msize + 1)
435                                 + y * (msize + 1) + x];
436 
437           for (opacity = 0; opacity < 25; opacity++)
438             {
439               shad->shadow_corner[opacity * (msize + 1) * (msize + 1)
440                                   + y * (msize + 1) + x]
441                 = shad->shadow_corner[opacity * (msize + 1) * (msize + 1)
442                                       + x * (msize + 1) + y]
443                 = shad->shadow_corner[25 * (msize + 1) * (msize + 1)
444                                       + y * (msize + 1) + x] * opacity / 25;
445             }
446         }
447     }
448 }
449 
450 static void
generate_shadows(MetaCompScreen * info)451 generate_shadows (MetaCompScreen *info)
452 {
453   double radii[LAST_SHADOW_TYPE] = {SHADOW_SMALL_RADIUS,
454                                     SHADOW_MEDIUM_RADIUS,
455                                     SHADOW_LARGE_RADIUS};
456   int i;
457 
458   for (i = 0; i < LAST_SHADOW_TYPE; i++) {
459     shadow *shad = g_new0 (shadow, 1);
460 
461     shad->gaussian_map = make_gaussian_map (radii[i]);
462     presum_gaussian (shad);
463 
464     info->shadows[i] = shad;
465   }
466 }
467 
468 static XImage *
make_shadow(MetaDisplay * display,MetaScreen * screen,MetaShadowType shadow_type,double opacity,int width,int height)469 make_shadow (MetaDisplay   *display,
470              MetaScreen    *screen,
471              MetaShadowType shadow_type,
472              double         opacity,
473              int            width,
474              int            height)
475 {
476   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
477   Display *xdisplay = meta_display_get_xdisplay (display);
478   XImage *ximage;
479   guchar *data;
480   shadow *shad;
481   int msize;
482   int ylimit, xlimit;
483   int swidth, sheight;
484   int centre;
485   int x, y;
486   guchar d;
487   int x_diff;
488   int opacity_int = (int)(opacity * 25);
489   int screen_number = meta_screen_get_screen_number (screen);
490 
491   if (info==NULL)
492     {
493       return NULL;
494     }
495 
496   shad = info->shadows[shadow_type];
497   msize = shad->gaussian_map->size;
498   swidth = width + msize;
499   sheight = height + msize;
500   centre = msize / 2;
501 
502   data = g_malloc (swidth * sheight * sizeof (guchar));
503 
504   ximage = XCreateImage (xdisplay, DefaultVisual (xdisplay, screen_number),
505                          8, ZPixmap, 0, (char *) data,
506                          swidth, sheight, 8, swidth * sizeof (guchar));
507   if (!ximage)
508     {
509       g_free (data);
510       return NULL;
511     }
512 
513   /*
514    * Build the gaussian in sections
515    */
516 
517   /*
518    * centre (fill the complete data array
519    */
520   if (msize > 0)
521     d = shad->shadow_top[opacity_int * (msize + 1) + msize];
522   else
523     d = sum_gaussian (shad->gaussian_map, opacity, centre,
524                       centre, width, height);
525   memset (data, d, sheight * swidth);
526 
527   /*
528    * corners
529    */
530   ylimit = msize;
531   if (ylimit > sheight / 2)
532     ylimit = (sheight + 1) / 2;
533 
534   xlimit = msize;
535   if (xlimit > swidth / 2)
536     xlimit = (swidth + 1) / 2;
537 
538   for (y = 0; y < ylimit; y++)
539     {
540       for (x = 0; x < xlimit; x++)
541         {
542 
543           if (xlimit == msize && ylimit == msize)
544             d = shad->shadow_corner[opacity_int * (msize + 1) * (msize + 1) + y * (msize + 1) + x];
545           else
546             d = sum_gaussian (shad->gaussian_map, opacity, x - centre,
547                               y - centre, width, height);
548 
549           data[y * swidth + x] = d;
550           data[(sheight - y - 1) * swidth + x] = d;
551           data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d;
552           data[y * swidth + (swidth - x - 1)] = d;
553         }
554     }
555 
556   /* top/bottom */
557   x_diff = swidth - (msize * 2);
558   if (x_diff > 0 && ylimit > 0)
559     {
560       for (y = 0; y < ylimit; y++)
561         {
562           if (ylimit == msize)
563             d = shad->shadow_top[opacity_int * (msize + 1) + y];
564           else
565             d = sum_gaussian (shad->gaussian_map, opacity, centre,
566                               y - centre, width, height);
567 
568           memset (&data[y * swidth + msize], d, x_diff);
569           memset (&data[(sheight - y - 1) * swidth + msize], d, x_diff);
570         }
571     }
572 
573   /*
574    * sides
575    */
576   for (x = 0; x < xlimit; x++)
577     {
578       if (xlimit == msize)
579         d = shad->shadow_top[opacity_int * (msize + 1) + x];
580       else
581         d = sum_gaussian (shad->gaussian_map, opacity, x - centre,
582                           centre, width, height);
583 
584       for (y = msize; y < sheight - msize; y++)
585         {
586           data[y * swidth + x] = d;
587           data[y * swidth + (swidth - x - 1)] = d;
588         }
589     }
590 
591   ximage->data = (char *) data;
592 
593   return ximage;
594 }
595 
596 double shadow_offsets_x[LAST_SHADOW_TYPE] = {SHADOW_SMALL_OFFSET_X,
597                                              SHADOW_MEDIUM_OFFSET_X,
598                                              SHADOW_LARGE_OFFSET_X};
599 double shadow_offsets_y[LAST_SHADOW_TYPE] = {SHADOW_SMALL_OFFSET_Y,
600                                              SHADOW_MEDIUM_OFFSET_Y,
601                                              SHADOW_LARGE_OFFSET_Y};
602 
603 static XserverRegion
cairo_region_to_xserver_region(Display * xdisplay,cairo_region_t * region)604 cairo_region_to_xserver_region (Display        *xdisplay,
605                                 cairo_region_t *region)
606 {
607   int n_rects, i;
608   XRectangle *rects;
609   XserverRegion xregion;
610 
611   n_rects = cairo_region_num_rectangles (region);
612   rects = g_new (XRectangle, n_rects);
613 
614   for (i = 0; i < n_rects; i++)
615     {
616       cairo_rectangle_int_t rect;
617 
618       cairo_region_get_rectangle (region, i, &rect);
619 
620       rects[i].x = rect.x;
621       rects[i].y = rect.y;
622       rects[i].width = rect.width;
623       rects[i].height = rect.height;
624     }
625 
626   xregion = XFixesCreateRegion (xdisplay, rects, n_rects);
627   g_free (rects);
628 
629   return xregion;
630 }
631 
632 static void
shadow_picture_clip(Display * xdisplay,Picture shadow_picture,MetaCompWindow * cw,MetaFrameBorders borders,int width,int height)633 shadow_picture_clip (Display          *xdisplay,
634                      Picture           shadow_picture,
635                      MetaCompWindow   *cw,
636                      MetaFrameBorders  borders,
637                      int               width,
638                      int               height)
639 {
640   int shadow_dx;
641   int shadow_dy;
642   cairo_region_t *visible_region;
643   XRectangle rect;
644   XserverRegion region1;
645   XserverRegion region2;
646 
647   if (!cw->window)
648     return;
649 
650   visible_region = meta_window_get_frame_bounds (cw->window);
651 
652   if (visible_region == NULL)
653     return;
654 
655   shadow_dx = -1 * (int) shadow_offsets_x [cw->shadow_type] - borders.invisible.left;
656   shadow_dy = -1 * (int) shadow_offsets_y [cw->shadow_type] - borders.invisible.top;
657 
658   rect.x = 0;
659   rect.y = 0;
660   rect.width = width;
661   rect.height = height;
662 
663   region1 = XFixesCreateRegion (xdisplay, &rect, 1);
664   region2 = cairo_region_to_xserver_region (xdisplay, visible_region);
665 
666   XFixesTranslateRegion (xdisplay, region2,
667                          shadow_dx, shadow_dy);
668 
669   XFixesSubtractRegion (xdisplay, region1, region1, region2);
670   XFixesSetPictureClipRegion (xdisplay, shadow_picture, 0, 0, region1);
671 
672   XFixesDestroyRegion (xdisplay, region1);
673   XFixesDestroyRegion (xdisplay, region2);
674 }
675 
676 static Picture
shadow_picture(MetaDisplay * display,MetaScreen * screen,MetaCompWindow * cw,double opacity,MetaFrameBorders borders,int width,int height,int * wp,int * hp)677 shadow_picture (MetaDisplay      *display,
678                 MetaScreen       *screen,
679                 MetaCompWindow   *cw,
680                 double            opacity,
681                 MetaFrameBorders  borders,
682                 int               width,
683                 int               height,
684                 int              *wp,
685                 int              *hp)
686 {
687   Display *xdisplay = meta_display_get_xdisplay (display);
688   XImage *shadow_image;
689   Pixmap shadow_pixmap;
690   Picture shadow_picture;
691   Window xroot = meta_screen_get_xroot (screen);
692   GC gc;
693 
694   shadow_image = make_shadow (display, screen, cw->shadow_type,
695                               opacity, width, height);
696   if (!shadow_image)
697     return None;
698 
699   shadow_pixmap = XCreatePixmap (xdisplay, xroot,
700                                  shadow_image->width, shadow_image->height, 8);
701   if (!shadow_pixmap)
702     {
703       XDestroyImage (shadow_image);
704       return None;
705     }
706 
707   shadow_picture = XRenderCreatePicture (xdisplay, shadow_pixmap,
708                                          XRenderFindStandardFormat (xdisplay, PictStandardA8),
709                                          0, 0);
710   if (!shadow_picture)
711     {
712       XDestroyImage (shadow_image);
713       XFreePixmap (xdisplay, shadow_pixmap);
714       return None;
715     }
716 
717   shadow_picture_clip (xdisplay, shadow_picture, cw, borders,
718                        shadow_image->width, shadow_image->height);
719 
720   gc = XCreateGC (xdisplay, shadow_pixmap, 0, 0);
721   if (!gc)
722     {
723       XDestroyImage (shadow_image);
724       XFreePixmap (xdisplay, shadow_pixmap);
725       XRenderFreePicture (xdisplay, shadow_picture);
726       return None;
727     }
728 
729   XPutImage (xdisplay, shadow_pixmap, gc, shadow_image, 0, 0, 0, 0,
730              shadow_image->width, shadow_image->height);
731   *wp = shadow_image->width;
732   *hp = shadow_image->height;
733 
734   XFreeGC (xdisplay, gc);
735   XDestroyImage (shadow_image);
736   XFreePixmap (xdisplay, shadow_pixmap);
737 
738   return shadow_picture;
739 }
740 
741 static MetaCompWindow *
find_window_for_screen(MetaScreen * screen,Window xwindow)742 find_window_for_screen (MetaScreen *screen,
743                         Window      xwindow)
744 {
745   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
746 
747   if (info == NULL)
748     return NULL;
749 
750   return g_hash_table_lookup (info->windows_by_xid, (gpointer) xwindow);
751 }
752 
753 static MetaCompWindow *
find_window_in_display(MetaDisplay * display,Window xwindow)754 find_window_in_display (MetaDisplay *display,
755                         Window       xwindow)
756 {
757   GSList *index;
758 
759   for (index = meta_display_get_screens (display); index; index = index->next)
760     {
761       MetaCompWindow *cw = find_window_for_screen (index->data, xwindow);
762 
763       if (cw != NULL)
764         return cw;
765     }
766 
767   return NULL;
768 }
769 
770 static MetaCompWindow *
find_window_for_child_window_in_display(MetaDisplay * display,Window xwindow)771 find_window_for_child_window_in_display (MetaDisplay *display,
772                                          Window       xwindow)
773 {
774   Window ignored1, *ignored2;
775   Window parent;
776   guint ignored_children;
777 
778   XQueryTree (meta_display_get_xdisplay (display), xwindow, &ignored1,
779               &parent, &ignored2, &ignored_children);
780 
781   if (parent != None)
782     return find_window_in_display (display, parent);
783 
784   return NULL;
785 }
786 
787 #ifdef HAVE_PRESENT
788 static MetaScreen *
find_screen_from_output(MetaDisplay * display,Window output)789 find_screen_from_output(MetaDisplay *display, Window output)
790 {
791   int i;
792   Display *xdisplay = meta_display_get_xdisplay(display);
793 
794   for (i = 0; i < ScreenCount(xdisplay); i++)
795     {
796       MetaScreen *screen = meta_display_screen_for_x_screen(display,
797                                                             ScreenOfDisplay(xdisplay, i));
798       MetaCompScreen *info = meta_screen_get_compositor_data(screen);
799 
800       if (info->output == output)
801         return screen;
802     }
803   return NULL;
804 }
805 #endif /* HAVE_PRESENT */
806 
807 static Picture
solid_picture(MetaDisplay * display,MetaScreen * screen,gboolean argb,double a,double r,double g,double b)808 solid_picture (MetaDisplay *display,
809                MetaScreen  *screen,
810                gboolean     argb,
811                double       a,
812                double       r,
813                double       g,
814                double       b)
815 {
816   Display *xdisplay = meta_display_get_xdisplay (display);
817   Pixmap pixmap;
818   Picture picture;
819   XRenderPictureAttributes pa;
820   XRenderPictFormat *render_format;
821   XRenderColor c;
822   Window xroot = meta_screen_get_xroot (screen);
823 
824   render_format = XRenderFindStandardFormat (xdisplay,
825                                              argb ? PictStandardARGB32 : PictStandardA8);
826 
827   pixmap = XCreatePixmap (xdisplay, xroot, 1, 1, argb ? 32 : 8);
828   g_return_val_if_fail (pixmap != None, None);
829 
830   pa.repeat = TRUE;
831   picture = XRenderCreatePicture (xdisplay, pixmap, render_format,
832                                   CPRepeat, &pa);
833   if (picture == None)
834     {
835       XFreePixmap (xdisplay, pixmap);
836       g_warning ("(picture != None) failed");
837       return None;
838     }
839 
840   c.alpha = (unsigned short)(a * USHRT_MAX);
841   c.red   = (unsigned short)(r * USHRT_MAX);
842   c.green = (unsigned short)(g * USHRT_MAX);
843   c.blue  = (unsigned short)(b * USHRT_MAX);
844 
845   XRenderFillRectangle (xdisplay, PictOpSrc, picture, &c, 0, 0, 1, 1);
846   XFreePixmap (xdisplay, pixmap);
847 
848   return picture;
849 }
850 
851 static Picture
root_tile(MetaScreen * screen)852 root_tile (MetaScreen *screen)
853 {
854   MetaDisplay *display = meta_screen_get_display (screen);
855   Display *xdisplay = meta_display_get_xdisplay (display);
856   Picture picture;
857   Pixmap pixmap;
858   gboolean fill = FALSE;
859   XRenderPictureAttributes pa;
860   XRenderPictFormat *format;
861   int p;
862   Atom background_atoms[2];
863   Atom pixmap_atom;
864   int screen_number = meta_screen_get_screen_number (screen);
865   Window xroot = meta_screen_get_xroot (screen);
866 
867   pixmap = None;
868   background_atoms[0] = DISPLAY_COMPOSITOR (display)->atom_x_root_pixmap;
869   background_atoms[1] = DISPLAY_COMPOSITOR (display)->atom_x_set_root;
870 
871   pixmap_atom = XInternAtom (xdisplay, "PIXMAP", False);
872   for (p = 0; p < 2; p++)
873     {
874       Atom actual_type;
875       int actual_format;
876       gulong nitems, bytes_after;
877       guchar *prop;
878 
879       if (XGetWindowProperty (xdisplay, xroot,
880                               background_atoms[p],
881                               0, 4, FALSE, AnyPropertyType,
882                               &actual_type, &actual_format,
883                               &nitems, &bytes_after, &prop) == Success)
884         {
885           if (actual_type == pixmap_atom &&
886               actual_format == 32 &&
887               nitems == 1)
888             {
889               memcpy (&pixmap, prop, 4);
890               XFree (prop);
891               fill = FALSE;
892               break;
893             }
894         }
895     }
896 
897   if (!pixmap)
898     {
899       pixmap = XCreatePixmap (xdisplay, xroot, 1, 1,
900                               DefaultDepth (xdisplay, screen_number));
901       g_return_val_if_fail (pixmap != None, None);
902       fill = TRUE;
903     }
904 
905   pa.repeat = TRUE;
906   format = XRenderFindVisualFormat (xdisplay, DefaultVisual (xdisplay,
907                                                              screen_number));
908   g_return_val_if_fail (format != NULL, None);
909 
910   picture = XRenderCreatePicture (xdisplay, pixmap, format, CPRepeat, &pa);
911   if ((picture != None) && (fill))
912     {
913       XRenderColor c;
914 
915       /* Background default to just plain black */
916       c.red = 0x0000;
917       c.green = 0x0000;
918       c.blue = 0x0000;
919       c.alpha = USHRT_MAX;
920 
921       XRenderFillRectangle (xdisplay, PictOpSrc, picture, &c, 0, 0, 1, 1);
922       XFreePixmap (xdisplay, pixmap);
923     }
924 
925   return picture;
926 }
927 
928 static Pixmap
create_root_pixmap(MetaScreen * screen)929 create_root_pixmap (MetaScreen *screen)
930 {
931   MetaDisplay *display = meta_screen_get_display (screen);
932   Display *xdisplay = meta_display_get_xdisplay (display);
933   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
934   Window xroot = meta_screen_get_xroot (screen);
935   Pixmap pixmap;
936   int depth, screen_width, screen_height, screen_number;
937 
938   if (info == NULL)
939     {
940       return None;
941     }
942 
943   meta_screen_get_size (screen, &screen_width, &screen_height);
944   screen_number = meta_screen_get_screen_number (screen);
945 
946   depth = DefaultDepth (xdisplay, screen_number);
947   pixmap = XCreatePixmap (xdisplay, xroot,
948                           screen_width, screen_height,
949                           depth);
950 
951   return pixmap;
952 }
953 
954 static Picture
create_root_buffer(MetaScreen * screen,Pixmap root_pixmap)955 create_root_buffer (MetaScreen *screen, Pixmap root_pixmap)
956 {
957   MetaDisplay *display = meta_screen_get_display (screen);
958   Display *xdisplay = meta_display_get_xdisplay (display);
959   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
960   Picture pict;
961   XRenderPictFormat *format;
962   Visual *visual;
963   int screen_number;
964 
965   if (info == NULL)
966     {
967       return None;
968     }
969   g_return_val_if_fail (root_pixmap != None, None);
970 
971   screen_number = meta_screen_get_screen_number (screen);
972   visual = DefaultVisual (xdisplay, screen_number);
973 
974   format = XRenderFindVisualFormat (xdisplay, visual);
975   g_return_val_if_fail (format != NULL, None);
976 
977   pict = XRenderCreatePicture (xdisplay, root_pixmap, format, 0, NULL);
978   return pict;
979 }
980 
981 static void
paint_root(MetaScreen * screen,Picture root_buffer)982 paint_root (MetaScreen *screen,
983             Picture     root_buffer)
984 {
985   MetaDisplay *display = meta_screen_get_display (screen);
986   Display *xdisplay = meta_display_get_xdisplay (display);
987   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
988   int width, height;
989 
990   if (info == NULL)
991     {
992       return;
993     }
994 
995   g_return_if_fail (root_buffer != None);
996 
997   if (info->root_tile == None)
998     {
999       info->root_tile = root_tile (screen);
1000       g_return_if_fail (info->root_tile != None);
1001     }
1002 
1003   meta_screen_get_size (screen, &width, &height);
1004   XRenderComposite (xdisplay, PictOpSrc, info->root_tile, None, root_buffer,
1005                     0, 0, 0, 0, 0, 0, width, height);
1006 }
1007 
1008 static gboolean
window_has_shadow(MetaCompWindow * cw)1009 window_has_shadow (MetaCompWindow *cw)
1010 {
1011   MetaCompScreen *info = meta_screen_get_compositor_data (cw->screen);
1012 
1013   if (info == NULL || info->have_shadows == FALSE)
1014     return FALSE;
1015 
1016   /* Always put a shadow around windows with a frame - This should override
1017      the restriction about not putting a shadow around shaped windows
1018      as the frame might be the reason the window is shaped */
1019   if (cw->window)
1020     {
1021       /* Do not add shadows for maximized windows */
1022       if (meta_window_is_maximized (cw->window))
1023         {
1024           meta_verbose ("Window has no shadow because it is maximized\n");
1025           return FALSE;
1026         }
1027 
1028       /* Do not add shadows for left/right tiled windows */
1029       if (meta_window_is_tiled_left (cw->window))
1030         {
1031           meta_verbose ("Window has no shadow because it is tiled left\n");
1032           return FALSE;
1033         }
1034 
1035       if (meta_window_is_tiled_right (cw->window))
1036         {
1037           meta_verbose ("Window has no shadow because it is tiled right\n");
1038           return FALSE;
1039         }
1040 
1041       if (meta_window_get_frame (cw->window)) {
1042         meta_verbose ("Window has shadow because it has a frame\n");
1043         return TRUE;
1044       }
1045     }
1046 
1047   /* Do not add shadows to ARGB windows */
1048   if (cw->mode == WINDOW_ARGB) {
1049     meta_verbose ("Window has no shadow as it is ARGB\n");
1050     return FALSE;
1051   }
1052 
1053   /* Never put a shadow around shaped windows */
1054   if (cw->shaped) {
1055     meta_verbose ("Window has no shadow as it is shaped\n");
1056     return FALSE;
1057   }
1058 
1059   /* Don't put shadow around DND icon windows */
1060   if (cw->type == META_COMP_WINDOW_DND ||
1061       cw->type == META_COMP_WINDOW_DESKTOP) {
1062     meta_verbose ("Window has no shadow as it is DND or Desktop\n");
1063     return FALSE;
1064   }
1065 
1066   if (cw->mode != WINDOW_ARGB) {
1067     meta_verbose ("Window has shadow as it is not ARGB\n");
1068     return TRUE;
1069   }
1070 
1071   if (cw->type == META_COMP_WINDOW_MENU ||
1072       cw->type == META_COMP_WINDOW_DROP_DOWN_MENU) {
1073     meta_verbose ("Window has shadow as it is a menu\n");
1074     return TRUE;
1075   }
1076 
1077   if (cw->type == META_COMP_WINDOW_TOOLTIP) {
1078     meta_verbose ("Window has shadow as it is a tooltip\n");
1079     return TRUE;
1080   }
1081 
1082   meta_verbose ("Window has no shadow as it fell through\n");
1083   return FALSE;
1084 }
1085 
1086 static XserverRegion
win_extents(MetaCompWindow * cw)1087 win_extents (MetaCompWindow *cw)
1088 {
1089   MetaScreen *screen = cw->screen;
1090   MetaDisplay *display = meta_screen_get_display (screen);
1091   Display *xdisplay = meta_display_get_xdisplay (display);
1092   XRectangle r;
1093 
1094   r.x = cw->attrs.x;
1095   r.y = cw->attrs.y;
1096   r.width = cw->attrs.width + cw->attrs.border_width * 2;
1097   r.height = cw->attrs.height + cw->attrs.border_width * 2;
1098 
1099   if (cw->needs_shadow)
1100     {
1101       MetaFrameBorders borders;
1102       XRectangle sr;
1103 
1104       meta_frame_borders_clear (&borders);
1105 
1106       if (cw->window)
1107         {
1108           MetaFrame *frame = meta_window_get_frame (cw->window);
1109 
1110           if (frame)
1111             meta_frame_calc_borders (frame, &borders);
1112         }
1113 
1114       cw->shadow_dx = (int) shadow_offsets_x [cw->shadow_type] + borders.invisible.left;
1115       cw->shadow_dy = (int) shadow_offsets_y [cw->shadow_type] + borders.invisible.top;
1116 
1117       if (!cw->shadow)
1118         {
1119           double opacity = SHADOW_OPACITY;
1120           int invisible_width = borders.invisible.left + borders.invisible.right;
1121           int invisible_height = borders.invisible.top + borders.invisible.bottom;
1122 
1123           if (cw->opacity != (guint) OPAQUE)
1124             opacity = opacity * ((double) cw->opacity) / ((double) OPAQUE);
1125 
1126           cw->shadow = shadow_picture (display, screen, cw, opacity, borders,
1127                                        cw->attrs.width - invisible_width + cw->attrs.border_width * 2,
1128                                        cw->attrs.height - invisible_height + cw->attrs.border_width * 2,
1129                                        &cw->shadow_width, &cw->shadow_height);
1130         }
1131 
1132       sr.x = cw->attrs.x + cw->shadow_dx;
1133       sr.y = cw->attrs.y + cw->shadow_dy;
1134       sr.width = cw->shadow_width;
1135       sr.height = cw->shadow_height;
1136 
1137       if (sr.x < r.x)
1138         {
1139           r.width = (r.x + r.width) - sr.x;
1140           r.x = sr.x;
1141         }
1142 
1143       if (sr.y < r.y)
1144         {
1145           r.height = (r.y + r.height) - sr.y;
1146           r.y = sr.y;
1147         }
1148 
1149       if (sr.x + sr.width > r.x + r.width)
1150         r.width = sr.x + sr.width - r.x;
1151 
1152       if (sr.y + sr.height > r.y + r.height)
1153         r.height = sr.y + sr.height - r.y;
1154     }
1155 
1156   return XFixesCreateRegion (xdisplay, &r, 1);
1157 }
1158 
1159 static XserverRegion
border_size(MetaCompWindow * cw)1160 border_size (MetaCompWindow *cw)
1161 {
1162   MetaScreen *screen = cw->screen;
1163   MetaDisplay *display = meta_screen_get_display (screen);
1164   Display *xdisplay = meta_display_get_xdisplay (display);
1165   cairo_region_t *visible_region;
1166   XserverRegion visible = None;
1167   XserverRegion border;
1168 
1169   if (cw->window)
1170     {
1171       visible_region = meta_window_get_frame_bounds (cw->window);
1172 
1173       if (visible_region != NULL)
1174         visible = cairo_region_to_xserver_region (xdisplay, visible_region);
1175     }
1176 
1177   meta_error_trap_push (display);
1178   border = XFixesCreateRegionFromWindow (xdisplay, cw->id,
1179                                          WindowRegionBounding);
1180   meta_error_trap_pop (display, FALSE);
1181 
1182   g_return_val_if_fail (border != None, None);
1183   XFixesTranslateRegion (xdisplay, border,
1184                          cw->attrs.x + cw->attrs.border_width,
1185                          cw->attrs.y + cw->attrs.border_width);
1186 
1187   if (visible != None)
1188     {
1189       XFixesTranslateRegion (xdisplay, visible,
1190                          cw->attrs.x + cw->attrs.border_width,
1191                          cw->attrs.y + cw->attrs.border_width);
1192 
1193       XFixesIntersectRegion (xdisplay, visible, visible, border);
1194       XFixesDestroyRegion (xdisplay, border);
1195 
1196       return visible;
1197     }
1198 
1199   return border;
1200 }
1201 
1202 static XRenderPictFormat *
get_window_format(MetaCompWindow * cw)1203 get_window_format (MetaCompWindow *cw)
1204 {
1205   MetaScreen *screen = cw->screen;
1206   MetaDisplay *display = meta_screen_get_display (screen);
1207   Display *xdisplay = meta_display_get_xdisplay (display);
1208   XRenderPictFormat *format;
1209   int screen_number = meta_screen_get_screen_number (screen);
1210 
1211   format = XRenderFindVisualFormat (xdisplay, cw->attrs.visual);
1212   if (!format)
1213     format = XRenderFindVisualFormat (xdisplay,
1214                                       DefaultVisual (xdisplay, screen_number));
1215   return format;
1216 }
1217 
1218 static Picture
get_window_picture(MetaCompWindow * cw)1219 get_window_picture (MetaCompWindow *cw)
1220 {
1221   MetaScreen *screen = cw->screen;
1222   MetaDisplay *display = meta_screen_get_display (screen);
1223   Display *xdisplay = meta_display_get_xdisplay (display);
1224   XRenderPictureAttributes pa;
1225   XRenderPictFormat *format;
1226   Drawable draw;
1227   int error_code;
1228 
1229   draw = cw->id;
1230 
1231   meta_error_trap_push (display);
1232 
1233   if (cw->back_pixmap == None)
1234     cw->back_pixmap = XCompositeNameWindowPixmap (xdisplay, cw->id);
1235 
1236   error_code = meta_error_trap_pop_with_return (display, FALSE);
1237   if (error_code != 0)
1238     cw->back_pixmap = None;
1239 
1240   if (cw->back_pixmap != None)
1241     draw = cw->back_pixmap;
1242 
1243   format = get_window_format (cw);
1244   if (format)
1245     {
1246       Picture pict;
1247 
1248       pa.subwindow_mode = IncludeInferiors;
1249 
1250       meta_error_trap_push (display);
1251       pict = XRenderCreatePicture (xdisplay, draw, format, CPSubwindowMode, &pa);
1252       meta_error_trap_pop (display, FALSE);
1253 
1254       return pict;
1255     }
1256 
1257   return None;
1258 }
1259 
1260 static void
paint_dock_shadows(MetaScreen * screen,Picture root_buffer,XserverRegion region)1261 paint_dock_shadows (MetaScreen   *screen,
1262                     Picture       root_buffer,
1263                     XserverRegion region)
1264 {
1265   MetaDisplay *display = meta_screen_get_display (screen);
1266   Display *xdisplay = meta_display_get_xdisplay (display);
1267   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
1268   GSList *d;
1269 
1270   if (info == NULL)
1271     {
1272       return;
1273     }
1274 
1275   for (d = info->dock_windows; d; d = d->next)
1276     {
1277       MetaCompWindow *cw = d->data;
1278       XserverRegion shadow_clip;
1279 
1280       if (cw->shadow)
1281         {
1282           shadow_clip = XFixesCreateRegion (xdisplay, NULL, 0);
1283           XFixesIntersectRegion (xdisplay, shadow_clip,
1284                                  cw->border_clip, region);
1285 
1286           XFixesSetPictureClipRegion (xdisplay, root_buffer, 0, 0, shadow_clip);
1287 
1288           XRenderComposite (xdisplay, PictOpOver, info->black_picture,
1289                             cw->shadow, root_buffer,
1290                             0, 0, 0, 0,
1291                             cw->attrs.x + cw->shadow_dx,
1292                             cw->attrs.y + cw->shadow_dy,
1293                             cw->shadow_width, cw->shadow_height);
1294           XFixesDestroyRegion (xdisplay, shadow_clip);
1295         }
1296     }
1297 }
1298 
1299 #ifdef HAVE_PRESENT
1300 static gboolean
present_flip(MetaScreen * screen,XserverRegion region,Pixmap pixmap)1301 present_flip (MetaScreen *screen, XserverRegion region, Pixmap pixmap)
1302 {
1303   static uint32_t present_serial;
1304   gboolean debug;
1305 
1306   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
1307   MetaDisplay *display = meta_screen_get_display (screen);
1308   Display *xdisplay = meta_display_get_xdisplay (display);
1309 
1310   meta_error_trap_push (display);
1311   XPresentPixmap(xdisplay,
1312                  info->output,
1313                  pixmap,
1314                  present_serial,
1315                  None,
1316                  region,
1317                  0, 0,
1318                  None, None, None, PresentOptionNone,
1319                  0, 1, 0, NULL, 0);
1320 
1321   int error_code;
1322   error_code = meta_error_trap_pop_with_return (display, FALSE);
1323   if (error_code)
1324     {
1325       debug = DISPLAY_COMPOSITOR (display)->debug;
1326 
1327       if (debug)
1328         fprintf (stderr, "XPresentPixmap window %p pixmap %p error: %i\n",
1329                  (void *)info->output, (void *)pixmap, error_code);
1330 
1331       if (error_code == BadWindow)
1332         g_warning ("XPresent is not compatible with your current system configuration.");
1333 
1334       /* Disable the Present extension for this session to prevent frozen windows */
1335       info->use_present = FALSE;
1336       return FALSE;
1337     }
1338 
1339   present_serial++;
1340 
1341   return TRUE;
1342 }
1343 #endif /* HAVE_PRESENT */
1344 
1345 static void
paint_windows(MetaScreen * screen,GList * windows,Picture root_buffer,Pixmap root_pixmap,XserverRegion region)1346 paint_windows (MetaScreen   *screen,
1347                GList        *windows,
1348                Picture       root_buffer,
1349                Pixmap        root_pixmap,
1350                XserverRegion region)
1351 {
1352   MetaDisplay *display = meta_screen_get_display (screen);
1353   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
1354   Display *xdisplay = meta_display_get_xdisplay (display);
1355   GList *index, *last;
1356   int screen_width, screen_height;
1357   MetaCompWindow *cw;
1358   XserverRegion paint_region, desktop_region;
1359 
1360   if (info == NULL)
1361     {
1362       return;
1363     }
1364 
1365   meta_screen_get_size (screen, &screen_width, &screen_height);
1366 
1367   if (region == None)
1368     {
1369       XRectangle r;
1370       r.x = 0;
1371       r.y = 0;
1372       r.width = screen_width;
1373       r.height = screen_height;
1374       paint_region = XFixesCreateRegion (xdisplay, &r, 1);
1375     }
1376   else
1377     {
1378       paint_region = XFixesCreateRegion (xdisplay, NULL, 0);
1379       XFixesCopyRegion (xdisplay, paint_region, region);
1380     }
1381 
1382   desktop_region = None;
1383 
1384   /*
1385    * Painting from top to bottom, reducing the clipping area at
1386    * each iteration. Only the opaque windows are painted 1st.
1387    */
1388   last = NULL;
1389   for (index = windows; index; index = index->next)
1390     {
1391       /* Store the last window we dealt with */
1392       last = index;
1393 
1394       cw = (MetaCompWindow *) index->data;
1395       if (!cw->damaged)
1396         {
1397           /* Not damaged */
1398           continue;
1399         }
1400 
1401       if (cw->attrs.map_state != IsViewable)
1402         continue;
1403 
1404 #if 0
1405       if ((cw->attrs.x + cw->attrs.width < 1) ||
1406           (cw->attrs.y + cw->attrs.height < 1) ||
1407           (cw->attrs.x >= screen_width) || (cw->attrs.y >= screen_height))
1408         {
1409           /* Off screen */
1410           continue;
1411         }
1412 #endif
1413 
1414       if (cw->picture == None)
1415         cw->picture = get_window_picture (cw);
1416 
1417       /* If the clip region of the screen has been changed
1418          then we need to recreate the extents of the window */
1419       if (info->clip_changed)
1420         {
1421           if (cw->border_size)
1422             {
1423               XFixesDestroyRegion (xdisplay, cw->border_size);
1424               cw->border_size = None;
1425             }
1426 
1427 #if 0
1428           if (cw->extents)
1429             {
1430               XFixesDestroyRegion (xdisplay, cw->extents);
1431               cw->extents = None;
1432             }
1433 #endif
1434         }
1435 
1436       if (cw->border_size == None)
1437         cw->border_size = border_size (cw);
1438 
1439       if (cw->extents == None)
1440         cw->extents = win_extents (cw);
1441 
1442       if (cw->mode == WINDOW_SOLID)
1443         {
1444           int x, y, wid, hei;
1445 
1446           x = cw->attrs.x;
1447           y = cw->attrs.y;
1448           wid = cw->attrs.width + cw->attrs.border_width * 2;
1449           hei = cw->attrs.height + cw->attrs.border_width * 2;
1450 
1451           XFixesSetPictureClipRegion (xdisplay, root_buffer,
1452                                       0, 0, paint_region);
1453           XRenderComposite (xdisplay, PictOpSrc, cw->picture,
1454                             None, root_buffer, 0, 0, 0, 0,
1455                             x, y, wid, hei);
1456 
1457           if (cw->type == META_COMP_WINDOW_DESKTOP)
1458             {
1459               if(desktop_region)
1460               {
1461                 XFixesUnionRegion (xdisplay, desktop_region, desktop_region, paint_region);
1462               }
1463               else
1464               {
1465                 desktop_region = XFixesCreateRegion (xdisplay, 0, 0);
1466                 XFixesCopyRegion (xdisplay, desktop_region, paint_region);
1467               }
1468             }
1469 
1470           XFixesSubtractRegion (xdisplay, paint_region,
1471                                 paint_region, cw->border_size);
1472         }
1473 
1474       if (!cw->border_clip)
1475         {
1476           cw->border_clip = XFixesCreateRegion (xdisplay, 0, 0);
1477           XFixesCopyRegion (xdisplay, cw->border_clip, paint_region);
1478         }
1479     }
1480 
1481   XFixesSetPictureClipRegion (xdisplay, root_buffer, 0, 0, paint_region);
1482   paint_root (screen, root_buffer);
1483 
1484   paint_dock_shadows (screen, root_buffer, desktop_region == None ?
1485                       paint_region : desktop_region);
1486   if (desktop_region != None)
1487     XFixesDestroyRegion (xdisplay, desktop_region);
1488 
1489   /*
1490    * Painting from bottom to top, translucent windows and shadows are painted
1491    */
1492   for (index = last; index; index = index->prev)
1493     {
1494       cw = (MetaCompWindow *) index->data;
1495 
1496       if (cw->picture)
1497         {
1498           if (cw->shadow && cw->type != META_COMP_WINDOW_DOCK)
1499             {
1500               XserverRegion shadow_clip;
1501 
1502               shadow_clip = XFixesCreateRegion (xdisplay, NULL, 0);
1503               XFixesSubtractRegion (xdisplay, shadow_clip, cw->border_clip,
1504                                     cw->border_size);
1505               XFixesSetPictureClipRegion (xdisplay, root_buffer, 0, 0,
1506                                           shadow_clip);
1507 
1508               XRenderComposite (xdisplay, PictOpOver, info->black_picture,
1509                                 cw->shadow, root_buffer,
1510                                 0, 0, 0, 0,
1511                                 cw->attrs.x + cw->shadow_dx,
1512                                 cw->attrs.y + cw->shadow_dy,
1513                                 cw->shadow_width, cw->shadow_height);
1514               if (shadow_clip)
1515                 XFixesDestroyRegion (xdisplay, shadow_clip);
1516             }
1517 
1518           if ((cw->opacity != (guint) OPAQUE) && !(cw->alpha_pict))
1519             {
1520               cw->alpha_pict = solid_picture (display, screen, FALSE,
1521                                               (double) cw->opacity / OPAQUE,
1522                                               0, 0, 0);
1523             }
1524 
1525           XFixesIntersectRegion (xdisplay, cw->border_clip, cw->border_clip,
1526                                  cw->border_size);
1527           XFixesSetPictureClipRegion (xdisplay, root_buffer, 0, 0,
1528                                       cw->border_clip);
1529           if (cw->mode == WINDOW_ARGB)
1530             {
1531               int x, y, wid, hei;
1532 
1533               x = cw->attrs.x;
1534               y = cw->attrs.y;
1535               wid = cw->attrs.width + cw->attrs.border_width * 2;
1536               hei = cw->attrs.height + cw->attrs.border_width * 2;
1537 
1538               XRenderComposite (xdisplay, PictOpOver, cw->picture,
1539                                 cw->alpha_pict, root_buffer, 0, 0, 0, 0,
1540                                 x, y, wid, hei);
1541             }
1542         }
1543 
1544       if (cw->border_clip)
1545         {
1546           XFixesDestroyRegion (xdisplay, cw->border_clip);
1547           cw->border_clip = None;
1548         }
1549     }
1550 
1551   XFixesSetPictureClipRegion (xdisplay, root_buffer, 0, 0, region);
1552 
1553 #ifdef HAVE_PRESENT
1554   if (info->use_present)
1555     info->present_pending = present_flip (screen, region, root_pixmap);
1556 
1557   if (!info->use_present || !info->present_pending)
1558 #endif /* HAVE_PRESENT */
1559     {
1560       XRenderComposite (xdisplay, PictOpSrc, root_buffer, None,
1561           info->root_picture, 0, 0, 0, 0, 0, 0,
1562           screen_width, screen_height);
1563     }
1564 
1565   XFlush (xdisplay);
1566   XFixesDestroyRegion (xdisplay, paint_region);
1567 }
1568 
1569 static void
paint_all(MetaScreen * screen,XserverRegion region,int b)1570 paint_all (MetaScreen   *screen,
1571            XserverRegion region,
1572            int           b)
1573 {
1574   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
1575   MetaDisplay *display = meta_screen_get_display (screen);
1576   Display *xdisplay = meta_display_get_xdisplay (display);
1577   int screen_width, screen_height;
1578 
1579   meta_screen_get_size (screen, &screen_width, &screen_height);
1580 
1581   if (DISPLAY_COMPOSITOR (display)->show_redraw)
1582     {
1583       Picture overlay;
1584 
1585       dump_xserver_region ("paint_all", display, region);
1586 
1587       /* Make a random colour overlay */
1588       overlay = solid_picture (display, screen, TRUE, 1, /* 0.3, alpha */
1589                                ((double) (rand () % 100)) / 100.0,
1590                                ((double) (rand () % 100)) / 100.0,
1591                                ((double) (rand () % 100)) / 100.0);
1592 
1593       /* Set clipping to the given region */
1594       XFixesSetPictureClipRegion (xdisplay, info->root_picture, 0, 0, region);
1595 
1596       XRenderComposite (xdisplay, PictOpOver, overlay, None, info->root_picture,
1597                         0, 0, 0, 0, 0, 0, screen_width, screen_height);
1598       XRenderFreePicture (xdisplay, overlay);
1599       XFlush (xdisplay);
1600       usleep (100 * 1000);
1601     }
1602 
1603   if (info->root_pixmaps[b] == None)
1604     info->root_pixmaps[b] = create_root_pixmap (screen);
1605 
1606   if (info->root_buffers[b] == None)
1607     info->root_buffers[b] = create_root_buffer (screen, info->root_pixmaps[b]);
1608 
1609   paint_windows (screen, info->windows, info->root_buffers[b], info->root_pixmaps[b], region);
1610 }
1611 
1612 static void
repair_screen(MetaScreen * screen)1613 repair_screen (MetaScreen *screen)
1614 {
1615   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
1616   MetaDisplay *display = meta_screen_get_display (screen);
1617   Display *xdisplay = meta_display_get_xdisplay (display);
1618 
1619   g_return_if_fail(info != NULL);
1620 
1621   if (info->all_damage != None)
1622     {
1623 #ifdef HAVE_PRESENT
1624       if (info->use_present)
1625         {
1626           if (!info->present_pending)
1627             {
1628               XserverRegion damage = info->all_damage;
1629               meta_error_trap_push (display);
1630               if (info->prev_damage)
1631                 {
1632                   XFixesUnionRegion(xdisplay, info->prev_damage, info->prev_damage, damage);
1633                   damage = info->prev_damage;
1634                 }
1635 
1636               paint_all (screen, damage, info->root_current);
1637 
1638               if (++info->root_current >= NUM_BUFFER)
1639                 info->root_current = 0;
1640 
1641               if (info->prev_damage)
1642                 XFixesDestroyRegion (xdisplay, info->prev_damage);
1643 
1644               info->prev_damage = info->all_damage;
1645               info->all_damage = None;
1646               info->clip_changed = FALSE;
1647               meta_error_trap_pop (display, FALSE);
1648             }
1649         }
1650       else
1651 #endif /* HAVE_PRESENT */
1652         {
1653           meta_error_trap_push (display);
1654           paint_all (screen, info->all_damage, info->root_current);
1655           XFixesDestroyRegion (xdisplay, info->all_damage);
1656           info->all_damage = None;
1657           info->clip_changed = FALSE;
1658           meta_error_trap_pop (display, FALSE);
1659         }
1660     }
1661 }
1662 
1663 static void
repair_display(MetaDisplay * display)1664 repair_display (MetaDisplay *display)
1665 {
1666   GSList *screens = meta_display_get_screens (display);
1667   MetaCompositorXRender *compositor = DISPLAY_COMPOSITOR (display);
1668 
1669 #ifdef USE_IDLE_REPAINT
1670   if (compositor->repaint_id > 0)
1671     {
1672       g_source_remove (compositor->repaint_id);
1673       compositor->repaint_id = 0;
1674     }
1675 #endif
1676 
1677   for (; screens; screens = screens->next)
1678     repair_screen ((MetaScreen *) screens->data);
1679 }
1680 
1681 #ifdef USE_IDLE_REPAINT
1682 static gboolean
compositor_idle_cb(gpointer data)1683 compositor_idle_cb (gpointer data)
1684 {
1685   MetaCompositorXRender *compositor = (MetaCompositorXRender *) data;
1686 
1687   compositor->repaint_id = 0;
1688   repair_display (compositor->display);
1689 
1690   return FALSE;
1691 }
1692 
1693 static void
add_repair(MetaDisplay * display)1694 add_repair (MetaDisplay *display)
1695 {
1696   MetaCompositorXRender *compositor = DISPLAY_COMPOSITOR (display);
1697 
1698   if (compositor->repaint_id > 0)
1699     return;
1700 
1701 #if 1
1702   compositor->repaint_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1703                                             compositor_idle_cb, compositor,
1704                                             NULL);
1705 #else
1706   /* Limit it to 50fps */
1707   compositor->repaint_id = g_timeout_add_full (G_PRIORITY_HIGH, 20,
1708                                                compositor_idle_cb, compositor,
1709                                                NULL);
1710 #endif
1711 }
1712 #endif
1713 
1714 static void
add_damage(MetaScreen * screen,XserverRegion damage)1715 add_damage (MetaScreen     *screen,
1716             XserverRegion   damage)
1717 {
1718   MetaDisplay *display = meta_screen_get_display (screen);
1719   Display *xdisplay = meta_display_get_xdisplay (display);
1720   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
1721 
1722   /*  dump_xserver_region ("add_damage", display, damage); */
1723 
1724   if (info != NULL)
1725     {
1726       if (info->all_damage)
1727         {
1728           XFixesUnionRegion (xdisplay, info->all_damage, info->all_damage, damage);
1729           XFixesDestroyRegion (xdisplay, damage);
1730         }
1731       else
1732         {
1733           info->all_damage = damage;
1734         }
1735     }
1736 
1737 #ifdef USE_IDLE_REPAINT
1738   add_repair (display);
1739 #endif
1740 }
1741 
1742 static void
damage_screen(MetaScreen * screen)1743 damage_screen (MetaScreen *screen)
1744 {
1745   MetaDisplay *display = meta_screen_get_display (screen);
1746   Display *xdisplay = meta_display_get_xdisplay (display);
1747   XserverRegion region;
1748   int width, height;
1749   XRectangle r;
1750 
1751   r.x = 0;
1752   r.y = 0;
1753   meta_screen_get_size (screen, &width, &height);
1754   r.width = width;
1755   r.height = height;
1756 
1757   region = XFixesCreateRegion (xdisplay, &r, 1);
1758   dump_xserver_region ("damage_screen", display, region);
1759   add_damage (screen, region);
1760 }
1761 
1762 static void
repair_win(MetaCompWindow * cw)1763 repair_win (MetaCompWindow *cw)
1764 {
1765   MetaScreen *screen = cw->screen;
1766   MetaDisplay *display = meta_screen_get_display (screen);
1767   Display *xdisplay = meta_display_get_xdisplay (display);
1768   XserverRegion parts;
1769 
1770   meta_error_trap_push (display);
1771   if (!cw->damaged)
1772     {
1773       parts = win_extents (cw);
1774       XDamageSubtract (xdisplay, cw->damage, None, None);
1775     }
1776   else
1777     {
1778       parts = XFixesCreateRegion (xdisplay, 0, 0);
1779       XDamageSubtract (xdisplay, cw->damage, None, parts);
1780       XFixesTranslateRegion (xdisplay, parts,
1781                              cw->attrs.x + cw->attrs.border_width,
1782                              cw->attrs.y + cw->attrs.border_width);
1783     }
1784 
1785   meta_error_trap_pop (display, FALSE);
1786 
1787   dump_xserver_region ("repair_win", display, parts);
1788   add_damage (screen, parts);
1789   cw->damaged = TRUE;
1790 }
1791 
1792 static void
free_win(MetaCompWindow * cw,gboolean destroy)1793 free_win (MetaCompWindow *cw,
1794           gboolean        destroy)
1795 {
1796   MetaDisplay *display = meta_screen_get_display (cw->screen);
1797   Display *xdisplay = meta_display_get_xdisplay (display);
1798   MetaCompScreen *info = meta_screen_get_compositor_data (cw->screen);
1799 
1800   /* See comment in map_win */
1801   if (cw->back_pixmap && destroy)
1802     {
1803       XFreePixmap (xdisplay, cw->back_pixmap);
1804       cw->back_pixmap = None;
1805     }
1806 
1807   if (cw->shaded_back_pixmap && destroy)
1808     {
1809       XFreePixmap (xdisplay, cw->shaded_back_pixmap);
1810       cw->shaded_back_pixmap = None;
1811     }
1812 
1813   if (cw->picture)
1814     {
1815       XRenderFreePicture (xdisplay, cw->picture);
1816       cw->picture = None;
1817     }
1818 
1819   if (cw->shadow)
1820     {
1821       XRenderFreePicture (xdisplay, cw->shadow);
1822       cw->shadow = None;
1823     }
1824 
1825   if (cw->alpha_pict)
1826     {
1827       XRenderFreePicture (xdisplay, cw->alpha_pict);
1828       cw->alpha_pict = None;
1829     }
1830 
1831   if (cw->shadow_pict)
1832     {
1833       XRenderFreePicture (xdisplay, cw->shadow_pict);
1834       cw->shadow_pict = None;
1835     }
1836 
1837   if (cw->border_size)
1838     {
1839       XFixesDestroyRegion (xdisplay, cw->border_size);
1840       cw->border_size = None;
1841     }
1842 
1843   if (cw->border_clip)
1844     {
1845       XFixesDestroyRegion (xdisplay, cw->border_clip);
1846       cw->border_clip = None;
1847     }
1848 
1849   if (cw->extents)
1850     {
1851       XFixesDestroyRegion (xdisplay, cw->extents);
1852       cw->extents = None;
1853     }
1854 
1855   if (destroy)
1856     {
1857       if (cw->damage != None) {
1858         meta_error_trap_push (display);
1859         XDamageDestroy (xdisplay, cw->damage);
1860         meta_error_trap_pop (display, FALSE);
1861 
1862         cw->damage = None;
1863       }
1864 
1865       /* The window may not have been added to the list in this case,
1866          but we can check anyway */
1867       if (info!=NULL && cw->type == META_COMP_WINDOW_DOCK)
1868         info->dock_windows = g_slist_remove (info->dock_windows, cw);
1869 
1870       g_free (cw);
1871     }
1872 }
1873 
1874 static void
constrain_tooltip_onscreen(MetaDisplay * display,MetaScreen * screen,MetaCompWindow * cw,Window id)1875 constrain_tooltip_onscreen (MetaDisplay    *display,
1876                             MetaScreen     *screen,
1877                             MetaCompWindow *cw,
1878                             Window          id)
1879 {
1880   MetaWorkspace *workspace;
1881   MetaRectangle work_area, win_rect;
1882   const MetaXineramaScreenInfo* xinerama;
1883   gint new_x, new_y;
1884   gint active_workspace_num;
1885 
1886   /* Why this is here:
1887    * As of gtk 3.24, tooltips are positioned differently, and can end up off the
1888    * screen in certain situations in hidpi.
1889    *
1890    * See: https://github.com/GNOME/gtk/commit/14d22cb3233e
1891    *
1892    * If the panel is too tall (around > 25 or so), tooltip positioning fails both
1893    * tests in gdkwindowimpl.c (maybe_flip_position()) skipping repositioning of the
1894    * tooltip inside the workarea. This only occurs on bottom panels.
1895    *
1896    * Since the calculations are based upon the monitor's workarea and the 'attach'
1897    * (gdk) window's rectangle, there's no way to compensate for or fool gtk into
1898    * displaying it correctly.  So here, we do our own check and adjustment. */
1899 
1900   active_workspace_num = meta_core_get_active_workspace (cw->attrs.screen);
1901 
1902   workspace = meta_screen_get_workspace_by_index (screen,
1903                                                   active_workspace_num);
1904 
1905   win_rect.x = cw->attrs.x;
1906   win_rect.y = cw->attrs.y;
1907   win_rect.width = cw->attrs.width;
1908   win_rect.height = cw->attrs.height;
1909 
1910   xinerama = meta_screen_get_xinerama_for_rect (screen,
1911                                                 &win_rect);
1912 
1913   meta_workspace_get_work_area_for_xinerama (workspace,
1914                                              xinerama->number,
1915                                              &work_area);
1916 
1917   new_x = win_rect.x;
1918   new_y = win_rect.y;
1919 
1920   /* Valid tooltip positions seem to cheat into the panel by a few pixels - maybe
1921    * accounting for shadow margin.  There's no reason the fix these, but they'd
1922    * be caught here otherwise, so 10px of overshoot in the direction of the panel
1923    * is allowed. The tooltips we're out to catch are the ones on the complete other
1924    * side of the panel (off screren), so there won't be any confusion. */
1925   if (win_rect.y < work_area.y - 10)
1926     {
1927       new_y = work_area.y;
1928     }
1929   else if (win_rect.y + win_rect.height > work_area.y + work_area.height + 10)
1930     {
1931       new_y = (work_area.y + work_area.height - win_rect.height);
1932     }
1933 
1934   if (win_rect.x < work_area.x - 10)
1935     {
1936       new_x = work_area.x;
1937     }
1938   else if (win_rect.x + win_rect.width > work_area.x + work_area.width + 10)
1939     {
1940       new_x = (work_area.x + work_area.width - win_rect.width);
1941     }
1942 
1943   if (new_x != win_rect.x || new_y != win_rect.y)
1944     {
1945       if (DISPLAY_COMPOSITOR (display)->debug)
1946         {
1947           fprintf(stderr, "Constraining tooltip onscreen   x:%d -> %d, y:%d -> %d\n",
1948                 win_rect.x,new_x, win_rect.y,new_y);
1949         }
1950 
1951       XMoveWindow (display->xdisplay, cw->id, new_x, new_y);
1952     }
1953 }
1954 
1955 static void
map_win(MetaDisplay * display,MetaScreen * screen,Window id)1956 map_win (MetaDisplay *display,
1957          MetaScreen  *screen,
1958          Window       id)
1959 {
1960   MetaCompWindow *cw = find_window_for_screen (screen, id);
1961   Display *xdisplay = meta_display_get_xdisplay (display);
1962 
1963   if (cw == NULL)
1964     return;
1965 
1966   if (cw->type == META_COMP_WINDOW_TOOLTIP)
1967     {
1968       constrain_tooltip_onscreen (display, screen, cw, id);
1969     }
1970 
1971   /* The reason we deallocate this here and not in unmap
1972      is so that we will still have a valid pixmap for
1973      whenever the window is unmapped */
1974   if (cw->back_pixmap)
1975     {
1976       XFreePixmap (xdisplay, cw->back_pixmap);
1977       cw->back_pixmap = None;
1978     }
1979 
1980   if (cw->shaded_back_pixmap)
1981     {
1982       XFreePixmap (xdisplay, cw->shaded_back_pixmap);
1983       cw->shaded_back_pixmap = None;
1984     }
1985 
1986   cw->attrs.map_state = IsViewable;
1987   cw->damaged = FALSE;
1988 }
1989 
1990 static void
unmap_win(MetaDisplay * display,MetaScreen * screen,Window id)1991 unmap_win (MetaDisplay *display,
1992            MetaScreen  *screen,
1993            Window       id)
1994 {
1995   MetaCompWindow *cw = find_window_for_screen (screen, id);
1996   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
1997 
1998   if (cw == NULL || info == NULL)
1999     {
2000       return;
2001     }
2002 
2003   if (cw->window && cw->window == info->focus_window)
2004     info->focus_window = NULL;
2005 
2006   cw->attrs.map_state = IsUnmapped;
2007   cw->damaged = FALSE;
2008 
2009   if (cw->extents != None)
2010     {
2011       dump_xserver_region ("unmap_win", display, cw->extents);
2012       add_damage (screen, cw->extents);
2013       cw->extents = None;
2014     }
2015 
2016   free_win (cw, FALSE);
2017   info->clip_changed = TRUE;
2018 }
2019 
2020 static void
determine_mode(MetaDisplay * display,MetaScreen * screen,MetaCompWindow * cw)2021 determine_mode (MetaDisplay    *display,
2022                 MetaScreen     *screen,
2023                 MetaCompWindow *cw)
2024 {
2025   XRenderPictFormat *format;
2026   Display *xdisplay = meta_display_get_xdisplay (display);
2027 
2028   if (cw->alpha_pict)
2029     {
2030       XRenderFreePicture (xdisplay, cw->alpha_pict);
2031       cw->alpha_pict = None;
2032     }
2033 
2034   if (cw->shadow_pict)
2035     {
2036       XRenderFreePicture (xdisplay, cw->shadow_pict);
2037       cw->shadow_pict = None;
2038     }
2039 
2040   if (cw->attrs.class == InputOnly)
2041     format = NULL;
2042   else
2043     format = XRenderFindVisualFormat (xdisplay, cw->attrs.visual);
2044 
2045   if ((format && format->type == PictTypeDirect && format->direct.alphaMask)
2046       || cw->opacity != (guint) OPAQUE)
2047     cw->mode = WINDOW_ARGB;
2048   else
2049     cw->mode = WINDOW_SOLID;
2050 
2051   if (cw->extents)
2052     {
2053       XserverRegion damage;
2054       damage = XFixesCreateRegion (xdisplay, NULL, 0);
2055       XFixesCopyRegion (xdisplay, damage, cw->extents);
2056 
2057       dump_xserver_region ("determine_mode", display, damage);
2058       add_damage (screen, damage);
2059     }
2060 }
2061 
2062 static gboolean
is_shaped(MetaDisplay * display,Window xwindow)2063 is_shaped (MetaDisplay *display,
2064            Window       xwindow)
2065 {
2066   Display *xdisplay = meta_display_get_xdisplay (display);
2067   int xws, yws, xbs, ybs;
2068   unsigned wws, hws, wbs, hbs;
2069   int bounding_shaped, clip_shaped;
2070 
2071   if (meta_display_has_shape (display))
2072     {
2073       XShapeQueryExtents (xdisplay, xwindow, &bounding_shaped,
2074                           &xws, &yws, &wws, &hws, &clip_shaped,
2075                           &xbs, &ybs, &wbs, &hbs);
2076       return (bounding_shaped != 0);
2077     }
2078 
2079   return FALSE;
2080 }
2081 
2082 static void
get_window_type(MetaDisplay * display,MetaCompWindow * cw)2083 get_window_type (MetaDisplay    *display,
2084                  MetaCompWindow *cw)
2085 {
2086   MetaCompositorXRender *compositor = DISPLAY_COMPOSITOR (display);
2087   int n_atoms;
2088   Atom *atoms, type_atom;
2089   int i;
2090 
2091   type_atom = None;
2092   n_atoms = 0;
2093   atoms = NULL;
2094 
2095   meta_prop_get_atom_list (display, cw->id,
2096                            compositor->atom_net_wm_window_type,
2097                            &atoms, &n_atoms);
2098 
2099   for (i = 0; i < n_atoms; i++)
2100     {
2101       if (atoms[i] == compositor->atom_net_wm_window_type_dnd ||
2102           atoms[i] == compositor->atom_net_wm_window_type_desktop ||
2103           atoms[i] == compositor->atom_net_wm_window_type_dock ||
2104           atoms[i] == compositor->atom_net_wm_window_type_toolbar ||
2105           atoms[i] == compositor->atom_net_wm_window_type_menu ||
2106           atoms[i] == compositor->atom_net_wm_window_type_dialog ||
2107           atoms[i] == compositor->atom_net_wm_window_type_normal ||
2108           atoms[i] == compositor->atom_net_wm_window_type_utility ||
2109           atoms[i] == compositor->atom_net_wm_window_type_splash ||
2110           atoms[i] == compositor->atom_net_wm_window_type_dropdown_menu ||
2111           atoms[i] == compositor->atom_net_wm_window_type_tooltip)
2112         {
2113           type_atom = atoms[i];
2114           break;
2115         }
2116     }
2117 
2118   meta_XFree (atoms);
2119 
2120   if (type_atom == compositor->atom_net_wm_window_type_dnd)
2121     cw->type = META_COMP_WINDOW_DND;
2122   else if (type_atom == compositor->atom_net_wm_window_type_desktop)
2123     cw->type = META_COMP_WINDOW_DESKTOP;
2124   else if (type_atom == compositor->atom_net_wm_window_type_dock)
2125     cw->type = META_COMP_WINDOW_DOCK;
2126   else if (type_atom == compositor->atom_net_wm_window_type_menu)
2127     cw->type = META_COMP_WINDOW_MENU;
2128   else if (type_atom == compositor->atom_net_wm_window_type_dropdown_menu)
2129     cw->type = META_COMP_WINDOW_DROP_DOWN_MENU;
2130   else if (type_atom == compositor->atom_net_wm_window_type_tooltip)
2131     cw->type = META_COMP_WINDOW_TOOLTIP;
2132   else
2133     cw->type = META_COMP_WINDOW_NORMAL;
2134 
2135 /*   meta_verbose ("Window is %d\n", cw->type); */
2136 }
2137 
2138 /* Must be called with an error trap in place */
2139 static void
add_win(MetaScreen * screen,MetaWindow * window,Window xwindow)2140 add_win (MetaScreen *screen,
2141          MetaWindow *window,
2142          Window     xwindow)
2143 {
2144   MetaDisplay *display = meta_screen_get_display (screen);
2145   Display *xdisplay = meta_display_get_xdisplay (display);
2146   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
2147   MetaCompWindow *cw;
2148   gulong event_mask;
2149 
2150   if (info == NULL)
2151     return;
2152 
2153   if (xwindow == info->output)
2154     return;
2155 
2156   /* If already added, ignore */
2157   if (find_window_for_screen (screen, xwindow) != NULL)
2158     return;
2159 
2160   cw = g_new0 (MetaCompWindow, 1);
2161   cw->screen = screen;
2162   cw->window = window;
2163   cw->id = xwindow;
2164 
2165   if (!XGetWindowAttributes (xdisplay, xwindow, &cw->attrs))
2166     {
2167       g_free (cw);
2168       return;
2169     }
2170   get_window_type (display, cw);
2171 
2172   /* If Marco has decided not to manage this window then the input events
2173      won't have been set on the window */
2174   event_mask = cw->attrs.your_event_mask | PropertyChangeMask;
2175 
2176   XSelectInput (xdisplay, xwindow, event_mask);
2177 
2178   cw->back_pixmap = None;
2179   cw->shaded_back_pixmap = None;
2180 
2181   cw->damaged = FALSE;
2182   cw->shaped = is_shaped (display, xwindow);
2183 
2184   cw->shape_bounds.x = cw->attrs.x;
2185   cw->shape_bounds.y = cw->attrs.y;
2186   cw->shape_bounds.width = cw->attrs.width;
2187   cw->shape_bounds.height = cw->attrs.height;
2188 
2189   if (cw->attrs.class == InputOnly)
2190     cw->damage = None;
2191   else
2192     cw->damage = XDamageCreate (xdisplay, xwindow, XDamageReportNonEmpty);
2193 
2194   cw->alpha_pict = None;
2195   cw->shadow_pict = None;
2196   cw->border_size = None;
2197   cw->extents = None;
2198   cw->shadow = None;
2199   cw->shadow_dx = 0;
2200   cw->shadow_dy = 0;
2201   cw->shadow_width = 0;
2202   cw->shadow_height = 0;
2203 
2204   if (window && meta_window_has_focus (window))
2205     cw->shadow_type = META_SHADOW_LARGE;
2206   else
2207     cw->shadow_type = META_SHADOW_MEDIUM;
2208 
2209   cw->opacity = OPAQUE;
2210 
2211   cw->border_clip = None;
2212 
2213   determine_mode (display, screen, cw);
2214   cw->needs_shadow = window_has_shadow (cw);
2215 
2216   /* Only add the window to the list of docks if it needs a shadow */
2217   if (cw->type == META_COMP_WINDOW_DOCK && cw->needs_shadow)
2218     {
2219       meta_verbose ("Appending %p to dock windows\n", cw);
2220       info->dock_windows = g_slist_append (info->dock_windows, cw);
2221     }
2222 
2223   /* Add this to the list at the top of the stack
2224      before it is mapped so that map_win can find it again */
2225   info->windows = g_list_prepend (info->windows, cw);
2226   g_hash_table_insert (info->windows_by_xid, (gpointer) xwindow, cw);
2227 
2228   if (cw->attrs.map_state == IsViewable)
2229     map_win (display, screen, xwindow);
2230 }
2231 
2232 static void
destroy_win(MetaDisplay * display,Window xwindow,gboolean gone)2233 destroy_win (MetaDisplay *display,
2234              Window       xwindow,
2235              gboolean     gone)
2236 {
2237   MetaScreen *screen;
2238   MetaCompScreen *info;
2239   MetaCompWindow *cw;
2240 
2241   cw = find_window_in_display (display, xwindow);
2242 
2243   if (cw == NULL)
2244     return;
2245 
2246   screen = cw->screen;
2247 
2248   if (cw->extents != None)
2249     {
2250       dump_xserver_region ("destroy_win", display, cw->extents);
2251       add_damage (screen, cw->extents);
2252       cw->extents = None;
2253     }
2254 
2255   info = meta_screen_get_compositor_data (screen);
2256   if (info != NULL)
2257     {
2258       info->windows = g_list_remove (info->windows, (gconstpointer) cw);
2259       g_hash_table_remove (info->windows_by_xid, (gpointer) xwindow);
2260     }
2261 
2262   free_win (cw, TRUE);
2263 }
2264 
2265 static void
restack_win(MetaCompWindow * cw,Window above)2266 restack_win (MetaCompWindow *cw,
2267              Window          above)
2268 {
2269   MetaScreen *screen;
2270   MetaCompScreen *info;
2271   Window previous_above;
2272   GList *sibling, *next;
2273 
2274   screen = cw->screen;
2275   info = meta_screen_get_compositor_data (screen);
2276 
2277   if (info == NULL)
2278     {
2279       return;
2280     }
2281 
2282   sibling = g_list_find (info->windows, (gconstpointer) cw);
2283   next = g_list_next (sibling);
2284   previous_above = None;
2285 
2286   if (next)
2287     {
2288       MetaCompWindow *ncw = (MetaCompWindow *) next->data;
2289       previous_above = ncw->id;
2290     }
2291 
2292   /* If above is set to None, the window whose state was changed is on
2293    * the bottom of the stack with respect to sibling.
2294    */
2295   if (above == None)
2296     {
2297       /* Insert at bottom of window stack */
2298       info->windows = g_list_delete_link (info->windows, sibling);
2299       info->windows = g_list_append (info->windows, cw);
2300     }
2301   else if (previous_above != above)
2302     {
2303       GList *index;
2304 
2305       for (index = info->windows; index; index = index->next) {
2306         MetaCompWindow *cw2 = (MetaCompWindow *) index->data;
2307         if (cw2->id == above)
2308           break;
2309       }
2310 
2311       if (index != NULL)
2312         {
2313           info->windows = g_list_delete_link (info->windows, sibling);
2314           info->windows = g_list_insert_before (info->windows, index, cw);
2315         }
2316     }
2317 }
2318 
2319 static void
resize_win(MetaCompWindow * cw,int x,int y,int width,int height,int border_width,gboolean override_redirect)2320 resize_win (MetaCompWindow *cw,
2321             int             x,
2322             int             y,
2323             int             width,
2324             int             height,
2325             int             border_width,
2326             gboolean        override_redirect)
2327 {
2328   MetaScreen *screen = cw->screen;
2329   MetaDisplay *display = meta_screen_get_display (screen);
2330   Display *xdisplay = meta_display_get_xdisplay (display);
2331   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
2332   XserverRegion damage;
2333   XserverRegion shape;
2334   gboolean debug;
2335 
2336   debug = DISPLAY_COMPOSITOR (display)->debug;
2337 
2338   if (cw->extents)
2339     {
2340       damage = XFixesCreateRegion (xdisplay, NULL, 0);
2341       XFixesCopyRegion (xdisplay, damage, cw->extents);
2342     }
2343   else
2344     {
2345       damage = None;
2346       if (debug)
2347         fprintf (stderr, "no extents to damage !\n");
2348     }
2349 
2350   /*  { // Damage whole screen each time ! ;-)
2351     XRectangle r;
2352 
2353     r.x = 0;
2354     r.y = 0;
2355     meta_screen_get_size (screen, &r.width, &r.height);
2356     fprintf (stderr, "Damage whole screen %d,%d (%d %d)\n",
2357              r.x, r.y, r.width, r.height);
2358 
2359     damage = XFixesCreateRegion (xdisplay, &r, 1);
2360     } */
2361 
2362   cw->attrs.x = x;
2363   cw->attrs.y = y;
2364 
2365   if (cw->attrs.width != width || cw->attrs.height != height)
2366     {
2367       if (cw->shaded_back_pixmap)
2368         {
2369           XFreePixmap (xdisplay, cw->shaded_back_pixmap);
2370           cw->shaded_back_pixmap = None;
2371         }
2372 
2373       if (cw->back_pixmap)
2374         {
2375           /* If the window is shaded, we store the old backing pixmap
2376              so we can return a proper image of the window */
2377           if (cw->window && meta_window_is_shaded (cw->window))
2378             {
2379               cw->shaded_back_pixmap = cw->back_pixmap;
2380               cw->back_pixmap = None;
2381             }
2382           else
2383             {
2384               XFreePixmap (xdisplay, cw->back_pixmap);
2385               cw->back_pixmap = None;
2386             }
2387         }
2388 
2389       if (cw->picture)
2390         {
2391           XRenderFreePicture (xdisplay, cw->picture);
2392           cw->picture = None;
2393         }
2394 
2395       if (cw->shadow)
2396         {
2397           XRenderFreePicture (xdisplay, cw->shadow);
2398           cw->shadow = None;
2399         }
2400     }
2401 
2402   cw->attrs.width = width;
2403   cw->attrs.height = height;
2404   cw->attrs.border_width = border_width;
2405   cw->attrs.override_redirect = override_redirect;
2406 
2407   if (cw->extents)
2408     XFixesDestroyRegion (xdisplay, cw->extents);
2409 
2410   cw->extents = win_extents (cw);
2411 
2412   if (damage)
2413     {
2414       if (debug)
2415         fprintf (stderr, "Inexplicable intersection with new extents!\n");
2416 
2417       XFixesUnionRegion (xdisplay, damage, damage, cw->extents);
2418     }
2419   else
2420     {
2421       damage = XFixesCreateRegion (xdisplay, NULL, 0);
2422       XFixesCopyRegion (xdisplay, damage, cw->extents);
2423     }
2424 
2425   shape = XFixesCreateRegion (xdisplay, &cw->shape_bounds, 1);
2426   XFixesUnionRegion (xdisplay, damage, damage, shape);
2427   XFixesDestroyRegion (xdisplay, shape);
2428 
2429   dump_xserver_region ("resize_win", display, damage);
2430   add_damage (screen, damage);
2431 
2432   if (info != NULL)
2433     {
2434       info->clip_changed = TRUE;
2435     }
2436 }
2437 
2438 /* event processors must all be called with an error trap in place */
2439 static void
process_circulate_notify(MetaCompositorXRender * compositor,XCirculateEvent * event)2440 process_circulate_notify (MetaCompositorXRender  *compositor,
2441                           XCirculateEvent        *event)
2442 {
2443   MetaCompWindow *cw = find_window_in_display (compositor->display,
2444                                                event->window);
2445   MetaCompWindow *top;
2446   MetaCompScreen *info;
2447   MetaScreen *screen;
2448   GList *first;
2449   Window above;
2450 
2451   if (!cw)
2452     return;
2453 
2454   screen = cw->screen;
2455   info = meta_screen_get_compositor_data (screen);
2456   first = info->windows;
2457   top = (MetaCompWindow *) first->data;
2458 
2459   if ((event->place == PlaceOnTop) && top)
2460     above = top->id;
2461   else
2462     above = None;
2463   restack_win (cw, above);
2464 
2465   if (info != NULL)
2466     {
2467       info->clip_changed = TRUE;
2468     }
2469 
2470 #ifdef USE_IDLE_REPAINT
2471   add_repair (compositor->display);
2472 #endif
2473 }
2474 
2475 static void
process_configure_notify(MetaCompositorXRender * compositor,XConfigureEvent * event)2476 process_configure_notify (MetaCompositorXRender  *compositor,
2477                           XConfigureEvent        *event)
2478 {
2479   MetaDisplay *display = compositor->display;
2480   Display *xdisplay = meta_display_get_xdisplay (display);
2481   MetaCompWindow *cw = find_window_in_display (display, event->window);
2482 
2483   if (cw)
2484     {
2485 #if 0
2486       int x = -1, y = -1, width = -1, height = -1;
2487       int ex = -1, ey = -1, ewidth = -1, eheight = -1;
2488       MetaRectangle *rect;
2489 
2490       if (cw->window) {
2491         rect = meta_window_get_rect (cw->window);
2492         x = rect->x;
2493         y = rect->y;
2494         width = rect->width;
2495         height = rect->height;
2496       }
2497       fprintf (stderr, "configure notify xy (%d %d) -> (%d %d), wh (%d %d) -> (%d %d)\n",
2498                x, y, event->x, event->y,
2499                width, height, event->width, event->height);
2500 #endif
2501 
2502       if (compositor->debug)
2503         {
2504           fprintf (stderr, "configure notify %d %d %d\n", cw->damaged,
2505                    cw->shaped, cw->needs_shadow);
2506           dump_xserver_region ("\textents", display, cw->extents);
2507           fprintf (stderr, "\txy (%d %d), wh (%d %d)\n",
2508                    event->x, event->y, event->width, event->height);
2509         }
2510 
2511       restack_win (cw, event->above);
2512       resize_win (cw, event->x, event->y, event->width, event->height,
2513                   event->border_width, event->override_redirect);
2514     }
2515   else
2516     {
2517       MetaScreen *screen;
2518       MetaCompScreen *info;
2519 
2520       /* Might be the root window? */
2521       screen = meta_display_screen_for_root (display, event->window);
2522       if (screen == NULL)
2523         return;
2524 
2525       info = meta_screen_get_compositor_data (screen);
2526       if (info != NULL)
2527         {
2528           int b;
2529           for (b = 0; b < NUM_BUFFER; b++)
2530             {
2531               if (info->root_buffers[b]) {
2532                 XRenderFreePicture (xdisplay, info->root_buffers[b]);
2533                 XFreePixmap (xdisplay, info->root_pixmaps[b]);
2534                 info->root_buffers[b] = None;
2535                 info->root_pixmaps[b] = None;
2536               }
2537             }
2538         }
2539 
2540       damage_screen (screen);
2541     }
2542 }
2543 
2544 static void
process_property_notify(MetaCompositorXRender * compositor,XPropertyEvent * event)2545 process_property_notify (MetaCompositorXRender *compositor,
2546                          XPropertyEvent        *event)
2547 {
2548   MetaDisplay *display = compositor->display;
2549   Display *xdisplay = meta_display_get_xdisplay (display);
2550   MetaScreen *screen;
2551   int p;
2552   Atom background_atoms[2];
2553 
2554   /* Check for the background property changing */
2555   background_atoms[0] = compositor->atom_x_root_pixmap;
2556   background_atoms[1] = compositor->atom_x_set_root;
2557 
2558   for (p = 0; p < 2; p++)
2559     {
2560       if (event->atom == background_atoms[p])
2561         {
2562           screen = meta_display_screen_for_root (display, event->window);
2563           if (screen)
2564             {
2565               MetaCompScreen *info = meta_screen_get_compositor_data (screen);
2566               Window xroot = meta_screen_get_xroot (screen);
2567 
2568               if (info != NULL && info->root_tile)
2569                 {
2570                   XClearArea (xdisplay, xroot, 0, 0, 0, 0, TRUE);
2571                   XRenderFreePicture (xdisplay, info->root_tile);
2572                   info->root_tile = None;
2573 
2574                   /* Damage the whole screen as we may need to redraw the
2575                      background ourselves */
2576                   damage_screen (screen);
2577 #ifdef USE_IDLE_REPAINT
2578                   add_repair (display);
2579 #endif
2580 
2581                   return;
2582                 }
2583             }
2584         }
2585     }
2586 
2587   /* Check for the opacity changing */
2588   if (event->atom == compositor->atom_net_wm_window_opacity)
2589     {
2590       MetaCompWindow *cw = find_window_in_display (display, event->window);
2591       gulong value;
2592 
2593       if (!cw)
2594         {
2595           /* Applications can set this for their toplevel windows, so
2596            * this must be propagated to the window managed by the compositor
2597            */
2598           cw = find_window_for_child_window_in_display (display, event->window);
2599         }
2600 
2601       if (!cw)
2602         return;
2603 
2604       if (meta_prop_get_cardinal (display, event->window,
2605                                   compositor->atom_net_wm_window_opacity,
2606                                   &value) == FALSE)
2607         value = OPAQUE;
2608 
2609       cw->opacity = (guint)value;
2610       determine_mode (display, cw->screen, cw);
2611       cw->needs_shadow = window_has_shadow (cw);
2612 
2613       if (cw->shadow)
2614         {
2615           XRenderFreePicture (xdisplay, cw->shadow);
2616           cw->shadow = None;
2617         }
2618 
2619       if (cw->extents)
2620         XFixesDestroyRegion (xdisplay, cw->extents);
2621       cw->extents = win_extents (cw);
2622 
2623       cw->damaged = TRUE;
2624 #ifdef USE_IDLE_REPAINT
2625       add_repair (display);
2626 #endif
2627 
2628       return;
2629     }
2630 
2631   if (event->atom == compositor->atom_net_wm_window_type) {
2632     MetaCompWindow *cw = find_window_in_display (display, event->window);
2633 
2634     if (!cw)
2635       return;
2636 
2637     get_window_type (display, cw);
2638     cw->needs_shadow = window_has_shadow (cw);
2639     return;
2640   }
2641 }
2642 
2643 static void
expose_area(MetaScreen * screen,XRectangle * rects,int nrects)2644 expose_area (MetaScreen *screen,
2645              XRectangle *rects,
2646              int         nrects)
2647 {
2648   MetaDisplay *display = meta_screen_get_display (screen);
2649   Display *xdisplay = meta_display_get_xdisplay (display);
2650   XserverRegion region;
2651 
2652   region = XFixesCreateRegion (xdisplay, rects, nrects);
2653 
2654   dump_xserver_region ("expose_area", display, region);
2655   add_damage (screen, region);
2656 }
2657 
2658 static void
process_expose(MetaCompositorXRender * compositor,XExposeEvent * event)2659 process_expose (MetaCompositorXRender *compositor,
2660                 XExposeEvent          *event)
2661 {
2662   MetaCompWindow *cw = find_window_in_display (compositor->display,
2663                                                event->window);
2664   MetaScreen *screen = NULL;
2665   XRectangle rect[1];
2666   int origin_x = 0, origin_y = 0;
2667 
2668   if (cw != NULL)
2669     {
2670       screen = cw->screen;
2671       origin_x = cw->attrs.x; /* + cw->attrs.border_width; ? */
2672       origin_y = cw->attrs.y; /* + cw->attrs.border_width; ? */
2673     }
2674   else
2675     {
2676       screen = meta_display_screen_for_root (compositor->display,
2677                                              event->window);
2678       if (screen == NULL)
2679         return;
2680     }
2681 
2682   rect[0].x = event->x + origin_x;
2683   rect[0].y = event->y + origin_y;
2684   rect[0].width = event->width;
2685   rect[0].height = event->height;
2686 
2687   expose_area (screen, rect, 1);
2688 }
2689 
2690 static void
process_unmap(MetaCompositorXRender * compositor,XUnmapEvent * event)2691 process_unmap (MetaCompositorXRender *compositor,
2692                XUnmapEvent           *event)
2693 {
2694   MetaCompWindow *cw;
2695 
2696   if (event->from_configure)
2697     {
2698       /* Ignore unmap caused by parent's resize */
2699       return;
2700     }
2701 
2702   cw = find_window_in_display (compositor->display, event->window);
2703   if (cw)
2704     unmap_win (compositor->display, cw->screen, event->window);
2705 }
2706 
2707 static void
process_map(MetaCompositorXRender * compositor,XMapEvent * event)2708 process_map (MetaCompositorXRender *compositor,
2709              XMapEvent             *event)
2710 {
2711   MetaCompWindow *cw = find_window_in_display (compositor->display,
2712                                                event->window);
2713 
2714   if (cw)
2715     map_win (compositor->display, cw->screen, event->window);
2716 }
2717 
2718 static void
process_reparent(MetaCompositorXRender * compositor,XReparentEvent * event,MetaWindow * window)2719 process_reparent (MetaCompositorXRender *compositor,
2720                   XReparentEvent        *event,
2721                   MetaWindow            *window)
2722 {
2723   MetaScreen *screen;
2724 
2725   screen = meta_display_screen_for_root (compositor->display, event->parent);
2726   if (screen != NULL)
2727     add_win (screen, window, event->window);
2728   else
2729     destroy_win (compositor->display, event->window, FALSE);
2730 }
2731 
2732 static void
process_create(MetaCompositorXRender * compositor,XCreateWindowEvent * event,MetaWindow * window)2733 process_create (MetaCompositorXRender *compositor,
2734                 XCreateWindowEvent    *event,
2735                 MetaWindow            *window)
2736 {
2737   MetaScreen *screen;
2738   /* We are only interested in top level windows, others will
2739      be caught by normal marco functions */
2740 
2741   screen = meta_display_screen_for_root (compositor->display, event->parent);
2742   if (screen == NULL)
2743     return;
2744 
2745   if (!find_window_in_display (compositor->display, event->window))
2746     add_win (screen, window, event->window);
2747 }
2748 
2749 static void
process_destroy(MetaCompositorXRender * compositor,XDestroyWindowEvent * event)2750 process_destroy (MetaCompositorXRender *compositor,
2751                  XDestroyWindowEvent   *event)
2752 {
2753   destroy_win (compositor->display, event->window, FALSE);
2754 }
2755 
2756 static void
process_damage(MetaCompositorXRender * compositor,XDamageNotifyEvent * event)2757 process_damage (MetaCompositorXRender *compositor,
2758                 XDamageNotifyEvent    *event)
2759 {
2760   MetaCompWindow *cw = find_window_in_display (compositor->display,
2761                                                event->drawable);
2762   if (cw == NULL)
2763     return;
2764 
2765   repair_win (cw);
2766 
2767 #ifdef USE_IDLE_REPAINT
2768   if (event->more == FALSE)
2769     add_repair (compositor->display);
2770 #endif
2771 }
2772 
2773 static void
process_shape(MetaCompositorXRender * compositor,XShapeEvent * event)2774 process_shape (MetaCompositorXRender *compositor,
2775                XShapeEvent           *event)
2776 {
2777   MetaCompWindow *cw = find_window_in_display (compositor->display,
2778                                                event->window);
2779 
2780   if (cw == NULL)
2781     return;
2782 
2783   if (event->kind == ShapeBounding)
2784     {
2785       if (!event->shaped && cw->shaped)
2786         cw->shaped = FALSE;
2787 
2788       resize_win (cw, cw->attrs.x, cw->attrs.y,
2789                   event->width + event->x, event->height + event->y,
2790                   cw->attrs.border_width, cw->attrs.override_redirect);
2791 
2792       if (event->shaped && !cw->shaped)
2793         cw->shaped = TRUE;
2794 
2795       if (event->shaped == True)
2796         {
2797           cw->shape_bounds.x = cw->attrs.x + event->x;
2798           cw->shape_bounds.y = cw->attrs.y + event->y;
2799           cw->shape_bounds.width = event->width;
2800           cw->shape_bounds.height = event->height;
2801         }
2802       else
2803         {
2804           cw->shape_bounds.x = cw->attrs.x;
2805           cw->shape_bounds.y = cw->attrs.y;
2806           cw->shape_bounds.width = cw->attrs.width;
2807           cw->shape_bounds.height = cw->attrs.height;
2808         }
2809     }
2810 }
2811 
2812 #ifdef HAVE_PRESENT
2813 static void
xrender_present_complete(MetaScreen * screen,XPresentCompleteNotifyEvent * ce)2814 xrender_present_complete(MetaScreen *screen,
2815                          XPresentCompleteNotifyEvent *ce)
2816 {
2817   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
2818 
2819   info->present_pending = False;
2820   repair_screen(screen);
2821 }
2822 #endif /* HAVE_PRESENT */
2823 
2824 static void
process_generic(MetaCompositorXRender * compositor,XGenericEvent * event)2825 process_generic(MetaCompositorXRender   *compositor,
2826                 XGenericEvent           *event)
2827 {
2828   XGenericEventCookie *ge = (XGenericEventCookie *) event;
2829   Display *xdisplay = meta_display_get_xdisplay (compositor->display);
2830   XGetEventData(xdisplay, ge);
2831 
2832   switch (ge->evtype)
2833     {
2834 #ifdef HAVE_PRESENT
2835     case PresentConfigureNotify:
2836       break;
2837     case PresentCompleteNotify:
2838       {
2839         if (ge->extension == compositor->present_major)
2840           {
2841             XPresentCompleteNotifyEvent *ce = ge->data;
2842             MetaScreen *screen = find_screen_from_output(compositor->display, ce->window);
2843             if (screen)
2844               xrender_present_complete(screen, ce);
2845           }
2846       }
2847       break;
2848 #endif /* HAVE_PRESENT */
2849     }
2850   XFreeEventData(xdisplay, ge);
2851 }
2852 
2853 static int
timeout_debug(MetaCompositorXRender * compositor)2854 timeout_debug (MetaCompositorXRender *compositor)
2855 {
2856   compositor->show_redraw = (g_getenv ("MARCO_DEBUG_REDRAWS") != NULL);
2857   compositor->debug = (g_getenv ("MARCO_DEBUG_COMPOSITOR") != NULL);
2858 
2859   return FALSE;
2860 }
2861 
2862 static void
xrender_add_window(MetaCompositor * compositor,MetaWindow * window,Window xwindow,XWindowAttributes * attrs)2863 xrender_add_window (MetaCompositor    *compositor,
2864                     MetaWindow        *window,
2865                     Window             xwindow,
2866                     XWindowAttributes *attrs)
2867 {
2868 #ifdef HAVE_COMPOSITE_EXTENSIONS
2869   MetaCompositorXRender *xrc = (MetaCompositorXRender *) compositor;
2870   MetaScreen *screen = meta_screen_for_x_screen (attrs->screen);
2871 
2872   meta_error_trap_push (xrc->display);
2873   add_win (screen, window, xwindow);
2874   meta_error_trap_pop (xrc->display, FALSE);
2875 #endif
2876 }
2877 
2878 static void
xrender_remove_window(MetaCompositor * compositor,Window xwindow)2879 xrender_remove_window (MetaCompositor *compositor,
2880                        Window          xwindow)
2881 {
2882 #ifdef HAVE_COMPOSITE_EXTENSIONS
2883 #endif
2884 }
2885 
2886 static void
show_overlay_window(MetaScreen * screen,Window cow)2887 show_overlay_window (MetaScreen *screen,
2888                      Window      cow)
2889 {
2890   MetaDisplay *display = meta_screen_get_display (screen);
2891   Display *xdisplay = meta_display_get_xdisplay (display);
2892   XserverRegion region;
2893 
2894   region = XFixesCreateRegion (xdisplay, NULL, 0);
2895 
2896   XFixesSetWindowShapeRegion (xdisplay, cow, ShapeBounding, 0, 0, 0);
2897   XFixesSetWindowShapeRegion (xdisplay, cow, ShapeInput, 0, 0, region);
2898 
2899   XFixesDestroyRegion (xdisplay, region);
2900 
2901   damage_screen (screen);
2902 }
2903 
2904 static void
hide_overlay_window(MetaScreen * screen,Window cow)2905 hide_overlay_window (MetaScreen *screen,
2906                      Window      cow)
2907 {
2908   MetaDisplay *display = meta_screen_get_display (screen);
2909   Display *xdisplay = meta_display_get_xdisplay (display);
2910   XserverRegion region;
2911 
2912   region = XFixesCreateRegion (xdisplay, NULL, 0);
2913   XFixesSetWindowShapeRegion (xdisplay, cow, ShapeBounding, 0, 0, region);
2914   XFixesDestroyRegion (xdisplay, region);
2915 }
2916 
2917 static Window
get_output_window(MetaScreen * screen)2918 get_output_window (MetaScreen *screen)
2919 {
2920   MetaDisplay *display = meta_screen_get_display (screen);
2921   Display *xdisplay = meta_display_get_xdisplay (display);
2922   Window output, xroot;
2923 
2924   xroot = meta_screen_get_xroot (screen);
2925 
2926   output = XCompositeGetOverlayWindow (xdisplay, xroot);
2927   XSelectInput (xdisplay, output, ExposureMask);
2928 
2929   return output;
2930 }
2931 
2932 static void
xrender_manage_screen(MetaCompositor * compositor,MetaScreen * screen)2933 xrender_manage_screen (MetaCompositor *compositor,
2934                        MetaScreen     *screen)
2935 {
2936 #ifdef HAVE_COMPOSITE_EXTENSIONS
2937   MetaCompositorXRender *xrc = (MetaCompositorXRender *) compositor;
2938   MetaCompScreen *info;
2939   MetaDisplay *display = meta_screen_get_display (screen);
2940   Display *xdisplay = meta_display_get_xdisplay (display);
2941   GdkDisplay *gdk_display = gdk_x11_lookup_xdisplay (xdisplay);
2942   XRenderPictureAttributes pa;
2943   XRenderPictFormat *visual_format;
2944   int screen_number = meta_screen_get_screen_number (screen);
2945   Window xroot = meta_screen_get_xroot (screen);
2946   int b;
2947 
2948   /* Check if the screen is already managed */
2949   if (meta_screen_get_compositor_data (screen))
2950     return;
2951 
2952   gdk_x11_display_error_trap_push (gdk_display);
2953   XCompositeRedirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
2954   XSync (xdisplay, FALSE);
2955 
2956   if (gdk_x11_display_error_trap_pop (gdk_display))
2957     {
2958       g_warning ("Another compositing manager is running on screen %i",
2959                  screen_number);
2960       return;
2961     }
2962 
2963   info = g_new0 (MetaCompScreen, 1);
2964   info->screen = screen;
2965 
2966   meta_screen_set_compositor_data (screen, info);
2967 
2968   visual_format = XRenderFindVisualFormat (xdisplay, DefaultVisual (xdisplay,
2969                                                                     screen_number));
2970   if (!visual_format)
2971     {
2972       g_warning ("Cannot find visual format on screen %i", screen_number);
2973       return;
2974     }
2975 
2976   info->output = get_output_window (screen);
2977 
2978   pa.subwindow_mode = IncludeInferiors;
2979   info->root_picture = XRenderCreatePicture (xdisplay, info->output,
2980                                              visual_format,
2981                                              CPSubwindowMode, &pa);
2982   if (info->root_picture == None)
2983     {
2984       g_warning ("Cannot create root picture on screen %i", screen_number);
2985       return;
2986     }
2987 
2988   for (b = 0; b < NUM_BUFFER; b++) {
2989     info->root_buffers[b] = None;
2990     info->root_pixmaps[b] = None;
2991   }
2992   info->black_picture = solid_picture (display, screen, TRUE, 1, 0, 0, 0);
2993 
2994   info->root_tile = None;
2995   info->all_damage = None;
2996 
2997   info->windows = NULL;
2998   info->windows_by_xid = g_hash_table_new (g_direct_hash, g_direct_equal);
2999 
3000   info->focus_window = meta_display_get_focus_window (display);
3001 
3002   info->compositor_active = TRUE;
3003   info->overlays = 0;
3004   info->clip_changed = TRUE;
3005 
3006   info->have_shadows = (g_getenv("META_DEBUG_NO_SHADOW") == NULL);
3007   if (info->have_shadows)
3008     {
3009       meta_verbose ("Enabling shadows\n");
3010       generate_shadows (info);
3011     }
3012   else
3013     meta_verbose ("Disabling shadows\n");
3014 
3015 #ifdef HAVE_PRESENT
3016   if (xrc->has_present)
3017     {
3018       info->present_eid = XPresentSelectInput(xdisplay, info->output,
3019                                               PresentCompleteNotifyMask);
3020       info->use_present = TRUE;
3021       info->present_pending = FALSE;
3022     }
3023   else
3024     {
3025       info->use_present = FALSE;
3026       g_warning ("XPresent not available");
3027     }
3028 #endif /* HAVE_PRESENT */
3029 
3030   XClearArea (xdisplay, info->output, 0, 0, 0, 0, TRUE);
3031 
3032   meta_screen_set_cm_selection (screen);
3033 
3034   /* Now we're up and running we can show the output if needed */
3035   show_overlay_window (screen, info->output);
3036 #endif
3037 }
3038 
3039 static void
xrender_unmanage_screen(MetaCompositor * compositor,MetaScreen * screen)3040 xrender_unmanage_screen (MetaCompositor *compositor,
3041                          MetaScreen     *screen)
3042 {
3043 #ifdef HAVE_COMPOSITE_EXTENSIONS
3044   MetaDisplay *display = meta_screen_get_display (screen);
3045   Display *xdisplay = meta_display_get_xdisplay (display);
3046   MetaCompScreen *info;
3047   Window xroot = meta_screen_get_xroot (screen);
3048   GList *index;
3049 
3050   info = meta_screen_get_compositor_data (screen);
3051 
3052   /* This screen isn't managed */
3053   if (info == NULL)
3054     return;
3055 
3056   hide_overlay_window (screen, info->output);
3057 
3058   /* Destroy the windows */
3059   for (index = info->windows; index; index = index->next)
3060     {
3061       MetaCompWindow *cw = (MetaCompWindow *) index->data;
3062       free_win (cw, TRUE);
3063     }
3064   g_list_free (info->windows);
3065   g_hash_table_destroy (info->windows_by_xid);
3066 
3067   if (info->root_picture)
3068     XRenderFreePicture (xdisplay, info->root_picture);
3069 
3070   if (info->black_picture)
3071     XRenderFreePicture (xdisplay, info->black_picture);
3072 
3073   if (info->have_shadows)
3074     {
3075       int i;
3076 
3077       for (i = 0; i < LAST_SHADOW_TYPE; i++)
3078         g_free (info->shadows[i]->gaussian_map);
3079     }
3080 
3081   XCompositeUnredirectSubwindows (xdisplay, xroot,
3082                                   CompositeRedirectManual);
3083   meta_screen_unset_cm_selection (screen);
3084 
3085   XCompositeReleaseOverlayWindow (xdisplay, info->output);
3086 
3087   g_free (info);
3088 
3089   meta_screen_set_compositor_data (screen, NULL);
3090 #endif
3091 }
3092 
3093 static void
xrender_set_updates(MetaCompositor * compositor,MetaWindow * window,gboolean updates)3094 xrender_set_updates (MetaCompositor *compositor,
3095                      MetaWindow     *window,
3096                      gboolean        updates)
3097 {
3098 #ifdef HAVE_COMPOSITE_EXTENSIONS
3099 
3100 #endif
3101 }
3102 
3103 static void
xrender_destroy(MetaCompositor * compositor)3104 xrender_destroy (MetaCompositor *compositor)
3105 {
3106 #ifdef HAVE_COMPOSITE_EXTENSIONS
3107   g_free (compositor);
3108 #endif
3109 }
3110 
3111 #if 0
3112 /* Taking these out because they're empty and never called, and the
3113  * compiler complains -- tthurman
3114  */
3115 
3116 static void
3117 xrender_begin_move (MetaCompositor *compositor,
3118                     MetaWindow     *window,
3119                     MetaRectangle  *initial,
3120                     int             grab_x,
3121                     int             grab_y)
3122 {
3123 #ifdef HAVE_COMPOSITE_EXTENSIONS
3124 #endif
3125 }
3126 
3127 static void
3128 xrender_update_move (MetaCompositor *compositor,
3129                      MetaWindow     *window,
3130                      int             x,
3131                      int             y)
3132 {
3133 #ifdef HAVE_COMPOSITE_EXTENSIONS
3134 #endif
3135 }
3136 
3137 static void
3138 xrender_end_move (MetaCompositor *compositor,
3139                   MetaWindow     *window)
3140 {
3141 #ifdef HAVE_COMPOSITE_EXTENSIONS
3142 #endif
3143 }
3144 
3145 #endif /* 0 */
3146 
3147 static void
xrender_free_window(MetaCompositor * compositor,MetaWindow * window)3148 xrender_free_window (MetaCompositor *compositor,
3149                      MetaWindow     *window)
3150 {
3151 #ifdef HAVE_COMPOSITE_EXTENSIONS
3152   MetaCompositorXRender *xrc;
3153   MetaFrame *frame;
3154   Window xwindow;
3155 
3156   xrc = (MetaCompositorXRender *) compositor;
3157   frame = meta_window_get_frame (window);
3158   xwindow = None;
3159 
3160   if (frame)
3161     {
3162       xwindow = meta_frame_get_xwindow (frame);
3163     }
3164   else
3165     {
3166       /* FIXME: When an undecorated window is hidden this is called, but the
3167        * window does not get readded if it is subsequentally shown again. See:
3168        * http://bugzilla.gnome.org/show_bug.cgi?id=504876
3169        */
3170       /* xwindow = meta_window_get_xwindow (window); */
3171     }
3172 
3173   if (xwindow != None)
3174     destroy_win (xrc->display, xwindow, FALSE);
3175 #endif
3176 }
3177 
3178 static void
xrender_process_event(MetaCompositor * compositor,XEvent * event,MetaWindow * window)3179 xrender_process_event (MetaCompositor *compositor,
3180                        XEvent         *event,
3181                        MetaWindow     *window)
3182 {
3183 #ifdef HAVE_COMPOSITE_EXTENSIONS
3184   MetaCompositorXRender *xrc = (MetaCompositorXRender *) compositor;
3185   /*
3186    * This trap is so that none of the compositor functions cause
3187    * X errors. This is really a hack, but I'm afraid I don't understand
3188    * enough about Marco/X to know how else you are supposed to do it
3189    */
3190   meta_error_trap_push (xrc->display);
3191   switch (event->type)
3192     {
3193     case CirculateNotify:
3194       process_circulate_notify (xrc, (XCirculateEvent *) event);
3195       break;
3196 
3197     case ConfigureNotify:
3198       process_configure_notify (xrc, (XConfigureEvent *) event);
3199       break;
3200 
3201     case PropertyNotify:
3202       process_property_notify (xrc, (XPropertyEvent *) event);
3203       break;
3204 
3205     case Expose:
3206       process_expose (xrc, (XExposeEvent *) event);
3207       break;
3208 
3209     case UnmapNotify:
3210       process_unmap (xrc, (XUnmapEvent *) event);
3211       break;
3212 
3213     case MapNotify:
3214       process_map (xrc, (XMapEvent *) event);
3215       break;
3216 
3217     case ReparentNotify:
3218       process_reparent (xrc, (XReparentEvent *) event, window);
3219       break;
3220 
3221     case CreateNotify:
3222       process_create (xrc, (XCreateWindowEvent *) event, window);
3223       break;
3224 
3225     case DestroyNotify:
3226       process_destroy (xrc, (XDestroyWindowEvent *) event);
3227       break;
3228 
3229     case GenericEvent:
3230       process_generic (xrc, (XGenericEvent *) event);
3231       break;
3232 
3233     default:
3234       if (event->type == meta_display_get_damage_event_base (xrc->display) + XDamageNotify)
3235         process_damage (xrc, (XDamageNotifyEvent *) event);
3236 #ifdef HAVE_SHAPE
3237       else if (event->type == meta_display_get_shape_event_base (xrc->display) + ShapeNotify)
3238         process_shape (xrc, (XShapeEvent *) event);
3239 #endif /* HAVE_SHAPE */
3240       else
3241         {
3242           meta_error_trap_pop (xrc->display, FALSE);
3243           return;
3244         }
3245       break;
3246     }
3247 
3248   meta_error_trap_pop (xrc->display, FALSE);
3249 #ifndef USE_IDLE_REPAINT
3250   repair_display (xrc->display);
3251 #endif
3252 
3253   return;
3254 #endif
3255 }
3256 
3257 static cairo_surface_t *
xrender_get_window_surface(MetaCompositor * compositor,MetaWindow * window)3258 xrender_get_window_surface (MetaCompositor *compositor,
3259                             MetaWindow     *window)
3260 {
3261 #ifdef HAVE_COMPOSITE_EXTENSIONS
3262   MetaFrame *frame;
3263   Window xwindow;
3264   MetaScreen *screen;
3265   MetaCompWindow *cw;
3266   MetaCompositorXRender *xrc;
3267   Display *display;
3268   Pixmap pixmap;
3269 
3270   frame = meta_window_get_frame (window);
3271 
3272   if (frame)
3273     xwindow = meta_frame_get_xwindow (frame);
3274   else
3275     xwindow = meta_window_get_xwindow (window);
3276 
3277   screen = meta_window_get_screen (window);
3278   cw = find_window_for_screen (screen, xwindow);
3279 
3280   if (cw == NULL)
3281     return NULL;
3282 
3283   xrc = (MetaCompositorXRender *) compositor;
3284   display = meta_display_get_xdisplay (xrc->display);
3285 
3286   if (meta_window_is_shaded (window))
3287     pixmap = cw->shaded_back_pixmap;
3288   else
3289     pixmap = cw->back_pixmap;
3290 
3291   return cairo_xlib_surface_create (display, pixmap, cw->attrs.visual,
3292                                     cw->attrs.width, cw->attrs.height);
3293 #endif
3294 }
3295 
3296 static void
xrender_set_active_window(MetaCompositor * compositor,MetaScreen * screen,MetaWindow * window)3297 xrender_set_active_window (MetaCompositor *compositor,
3298                            MetaScreen     *screen,
3299                            MetaWindow     *window)
3300 {
3301 #ifdef HAVE_COMPOSITE_EXTENSIONS
3302   MetaCompositorXRender *xrc = (MetaCompositorXRender *) compositor;
3303   MetaDisplay *display;
3304   Display *xdisplay;
3305   MetaCompWindow *old_focus = NULL, *new_focus = NULL;
3306   MetaCompScreen *info = NULL;
3307   MetaWindow *old_focus_win = NULL;
3308 
3309   if (compositor == NULL)
3310     return;
3311 
3312   display = xrc->display;
3313   xdisplay = meta_display_get_xdisplay (display);
3314   info = meta_screen_get_compositor_data (screen);
3315 
3316   if (info != NULL)
3317     {
3318       old_focus_win = info->focus_window;
3319     }
3320 
3321   if (old_focus_win)
3322     {
3323       MetaFrame *f = meta_window_get_frame (old_focus_win);
3324 
3325       old_focus = find_window_for_screen (screen,
3326                                           f ? meta_frame_get_xwindow (f) :
3327                                           meta_window_get_xwindow (old_focus_win));
3328     }
3329 
3330   if (window)
3331     {
3332       MetaFrame *f = meta_window_get_frame (window);
3333       new_focus = find_window_for_screen (screen,
3334                                           f ? meta_frame_get_xwindow (f) :
3335                                           meta_window_get_xwindow (window));
3336     }
3337 
3338   if (info != NULL)
3339     {
3340       info->focus_window = window;
3341     }
3342 
3343   if (old_focus)
3344     {
3345       XserverRegion damage;
3346 
3347       /* Tear down old shadows */
3348       old_focus->shadow_type = META_SHADOW_MEDIUM;
3349       determine_mode (display, screen, old_focus);
3350       old_focus->needs_shadow = window_has_shadow (old_focus);
3351 
3352       if (old_focus->attrs.map_state == IsViewable)
3353         {
3354           if (old_focus->shadow)
3355             {
3356               XRenderFreePicture (xdisplay, old_focus->shadow);
3357               old_focus->shadow = None;
3358             }
3359 
3360           if (old_focus->extents)
3361             {
3362               damage = XFixesCreateRegion (xdisplay, NULL, 0);
3363               XFixesCopyRegion (xdisplay, damage, old_focus->extents);
3364               XFixesDestroyRegion (xdisplay, old_focus->extents);
3365             }
3366           else
3367             damage = None;
3368 
3369           /* Build new extents */
3370           old_focus->extents = win_extents (old_focus);
3371 
3372           if (damage)
3373             XFixesUnionRegion (xdisplay, damage, damage, old_focus->extents);
3374           else
3375             {
3376               damage = XFixesCreateRegion (xdisplay, NULL, 0);
3377               XFixesCopyRegion (xdisplay, damage, old_focus->extents);
3378             }
3379 
3380           dump_xserver_region ("resize_win", display, damage);
3381           add_damage (screen, damage);
3382 
3383           if (info != NULL)
3384             {
3385               info->clip_changed = TRUE;
3386             }
3387         }
3388     }
3389 
3390   if (new_focus)
3391     {
3392       XserverRegion damage;
3393 
3394       new_focus->shadow_type = META_SHADOW_LARGE;
3395       determine_mode (display, screen, new_focus);
3396       new_focus->needs_shadow = window_has_shadow (new_focus);
3397 
3398       if (new_focus->shadow)
3399         {
3400           XRenderFreePicture (xdisplay, new_focus->shadow);
3401           new_focus->shadow = None;
3402         }
3403 
3404       if (new_focus->extents)
3405         {
3406           damage = XFixesCreateRegion (xdisplay, NULL, 0);
3407           XFixesCopyRegion (xdisplay, damage, new_focus->extents);
3408           XFixesDestroyRegion (xdisplay, new_focus->extents);
3409         }
3410       else
3411         damage = None;
3412 
3413       /* Build new extents */
3414       new_focus->extents = win_extents (new_focus);
3415 
3416       if (damage)
3417         XFixesUnionRegion (xdisplay, damage, damage, new_focus->extents);
3418       else
3419         {
3420           damage = XFixesCreateRegion (xdisplay, NULL, 0);
3421           XFixesCopyRegion (xdisplay, damage, new_focus->extents);
3422         }
3423 
3424       dump_xserver_region ("resize_win", display, damage);
3425       add_damage (screen, damage);
3426 
3427       if (info != NULL)
3428         {
3429           info->clip_changed = TRUE;
3430         }
3431     }
3432 #ifdef USE_IDLE_REPAINT
3433   add_repair (display);
3434 #endif
3435 #endif
3436 }
3437 
3438 static void
xrender_maximize_window(MetaCompositor * compositor,MetaWindow * window)3439 xrender_maximize_window (MetaCompositor *compositor,
3440                          MetaWindow     *window)
3441 {
3442 #ifdef HAVE_COMPOSITE_EXTENSIONS
3443   MetaFrame *frame = meta_window_get_frame (window);
3444   Window xid = frame ? meta_frame_get_xwindow (frame) : meta_window_get_xwindow (window);
3445   MetaCompWindow *cw = find_window_in_display (meta_window_get_display (window), xid);
3446 
3447   if (!cw)
3448     return;
3449 
3450   cw->needs_shadow = window_has_shadow (cw);
3451 #endif
3452 }
3453 
3454 static void
xrender_unmaximize_window(MetaCompositor * compositor,MetaWindow * window)3455 xrender_unmaximize_window (MetaCompositor *compositor,
3456                            MetaWindow     *window)
3457 {
3458 #ifdef HAVE_COMPOSITE_EXTENSIONS
3459   MetaFrame *frame = meta_window_get_frame (window);
3460   Window xid = frame ? meta_frame_get_xwindow (frame) : meta_window_get_xwindow (window);
3461   MetaCompWindow *cw = find_window_in_display (meta_window_get_display (window), xid);
3462 
3463   if (!cw)
3464     return;
3465 
3466   cw->needs_shadow = window_has_shadow (cw);
3467 #endif
3468 }
3469 
3470 static MetaCompositor comp_info = {
3471   xrender_destroy,
3472   xrender_manage_screen,
3473   xrender_unmanage_screen,
3474   xrender_add_window,
3475   xrender_remove_window,
3476   xrender_set_updates,
3477   xrender_process_event,
3478   xrender_get_window_surface,
3479   xrender_set_active_window,
3480   xrender_free_window,
3481   xrender_maximize_window,
3482   xrender_unmaximize_window,
3483 };
3484 
3485 MetaCompositor *
meta_compositor_xrender_new(MetaDisplay * display)3486 meta_compositor_xrender_new (MetaDisplay *display)
3487 {
3488 #ifdef HAVE_COMPOSITE_EXTENSIONS
3489   char *atom_names[] = {
3490     "_XROOTPMAP_ID",
3491     "_XSETROOT_ID",
3492     "_NET_WM_WINDOW_OPACITY",
3493     "_NET_WM_WINDOW_TYPE_DND",
3494     "_NET_WM_WINDOW_TYPE",
3495     "_NET_WM_WINDOW_TYPE_DESKTOP",
3496     "_NET_WM_WINDOW_TYPE_DOCK",
3497     "_NET_WM_WINDOW_TYPE_MENU",
3498     "_NET_WM_WINDOW_TYPE_DIALOG",
3499     "_NET_WM_WINDOW_TYPE_NORMAL",
3500     "_NET_WM_WINDOW_TYPE_UTILITY",
3501     "_NET_WM_WINDOW_TYPE_SPLASH",
3502     "_NET_WM_WINDOW_TYPE_TOOLBAR",
3503     "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU",
3504     "_NET_WM_WINDOW_TYPE_TOOLTIP"
3505   };
3506   Atom atoms[G_N_ELEMENTS(atom_names)];
3507   MetaCompositorXRender *xrc;
3508   MetaCompositor *compositor;
3509   Display *xdisplay = meta_display_get_xdisplay (display);
3510 
3511   xrc = g_new (MetaCompositorXRender, 1);
3512   xrc->compositor = comp_info;
3513 
3514   compositor = (MetaCompositor *) xrc;
3515 
3516   xrc->display = display;
3517 
3518   meta_verbose ("Creating %d atoms\n", (int) G_N_ELEMENTS (atom_names));
3519   XInternAtoms (xdisplay, atom_names, G_N_ELEMENTS (atom_names),
3520                 False, atoms);
3521 
3522   xrc->atom_x_root_pixmap = atoms[0];
3523   xrc->atom_x_set_root = atoms[1];
3524   xrc->atom_net_wm_window_opacity = atoms[2];
3525   xrc->atom_net_wm_window_type_dnd = atoms[3];
3526   xrc->atom_net_wm_window_type = atoms[4];
3527   xrc->atom_net_wm_window_type_desktop = atoms[5];
3528   xrc->atom_net_wm_window_type_dock = atoms[6];
3529   xrc->atom_net_wm_window_type_menu = atoms[7];
3530   xrc->atom_net_wm_window_type_dialog = atoms[8];
3531   xrc->atom_net_wm_window_type_normal = atoms[9];
3532   xrc->atom_net_wm_window_type_utility = atoms[10];
3533   xrc->atom_net_wm_window_type_splash = atoms[11];
3534   xrc->atom_net_wm_window_type_toolbar = atoms[12];
3535   xrc->atom_net_wm_window_type_dropdown_menu = atoms[13];
3536   xrc->atom_net_wm_window_type_tooltip = atoms[14];
3537   xrc->show_redraw = FALSE;
3538   xrc->debug = FALSE;
3539 #ifdef HAVE_PRESENT
3540   xrc->has_present = XPresentQueryExtension(xdisplay, &xrc->present_major, NULL, NULL);
3541 #endif /* HAVE_PRESENT */
3542 
3543 #ifdef USE_IDLE_REPAINT
3544   meta_verbose ("Using idle repaint\n");
3545   xrc->repaint_id = 0;
3546 #endif
3547 
3548   xrc->enabled = TRUE;
3549   g_timeout_add (2000, (GSourceFunc) timeout_debug, xrc);
3550 
3551   return compositor;
3552 #else
3553   return NULL;
3554 #endif
3555 }
3556 
3557 #endif /* HAVE_COMPOSITE_EXTENSIONS */
3558 
3559