1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 
3 /**
4  * SECTION:meta-window-actor
5  * @title: MetaWindowActor
6  * @short_description: An actor representing a top-level window in the scene graph
7  */
8 
9 #include <config.h>
10 
11 #include <math.h>
12 
13 #include <X11/extensions/shape.h>
14 #include <X11/extensions/Xcomposite.h>
15 #include <X11/extensions/Xdamage.h>
16 #include <X11/extensions/Xrender.h>
17 
18 #include <clutter/x11/clutter-x11.h>
19 #include <cogl/winsys/cogl-texture-pixmap-x11.h>
20 #include <gdk/gdk.h> /* for gdk_rectangle_union() */
21 
22 #include <meta/display.h>
23 #include <meta/errors.h>
24 #include "frame.h"
25 #include <meta/window.h>
26 #include <meta/meta-shaped-texture.h>
27 #include "xprops.h"
28 
29 #include "compositor-private.h"
30 #include "meta-shaped-texture-private.h"
31 #include "meta-shadow-factory-private.h"
32 #include "meta-window-actor-private.h"
33 
34 enum {
35   POSITION_CHANGED,
36   SIZE_CHANGED,
37   LAST_SIGNAL
38 };
39 
40 static guint signals[LAST_SIGNAL] = {0};
41 
42 
43 struct _MetaWindowActorPrivate
44 {
45   MetaWindow       *window;
46   Window            xwindow;
47   MetaScreen       *screen;
48 
49   ClutterActor     *actor;
50 
51   /* MetaShadowFactory only caches shadows that are actually in use;
52    * to avoid unnecessary recomputation we do two things: 1) we store
53    * both a focused and unfocused shadow for the window. If the window
54    * doesn't have different focused and unfocused shadow parameters,
55    * these will be the same. 2) when the shadow potentially changes we
56    * don't immediately unreference the old shadow, we just flag it as
57    * dirty and recompute it when we next need it (recompute_focused_shadow,
58    * recompute_unfocused_shadow.) Because of our extraction of
59    * size-invariant window shape, we'll often find that the new shadow
60    * is the same as the old shadow.
61    */
62   MetaShadow       *focused_shadow;
63   MetaShadow       *unfocused_shadow;
64 
65   Pixmap            back_pixmap;
66 
67   Damage            damage;
68 
69   guint8            opacity;
70 
71   /* If the window is shaped, a region that matches the shape */
72   cairo_region_t   *shape_region;
73   /* The opaque region, from _NET_WM_OPAQUE_REGION, intersected with
74    * the shape region. */
75   cairo_region_t   *opaque_region;
76   /* The region we should clip to when painting the shadow */
77   cairo_region_t   *shadow_clip;
78 
79    /* The region that is visible, used to optimize out redraws */
80   cairo_region_t   *unobscured_region;
81 
82   /* Extracted size-invariant shape used for shadows */
83   MetaWindowShape  *shadow_shape;
84 
85   gint              last_width;
86   gint              last_height;
87   gint              last_x;
88   gint              last_y;
89 
90   gint              freeze_count;
91 
92   char *            shadow_class;
93 
94   /*
95    * These need to be counters rather than flags, since more plugins
96    * can implement same effect; the practicality of stacking effects
97    * might be dubious, but we have to at least handle it correctly.
98    */
99   gint              minimize_in_progress;
100   gint              maximize_in_progress;
101   gint              unmaximize_in_progress;
102   gint              tile_in_progress;
103   gint              map_in_progress;
104   gint              destroy_in_progress;
105 
106   /* List of FrameData for recent frames */
107   GList            *frames;
108 
109   guint		    visible                : 1;
110   guint		    argb32                 : 1;
111   guint		    disposed               : 1;
112   guint             redecorating           : 1;
113 
114   guint		    needs_damage_all       : 1;
115   guint		    received_damage        : 1;
116   guint             repaint_scheduled      : 1;
117 
118   /* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
119    * client message using the most recent frame in ->frames */
120   guint             send_frame_messages_timer;
121   gint64            frame_drawn_time;
122   guint             needs_frame_drawn      : 1;
123 
124   guint             size_changed_id;
125   guint             opacity_changed_id;
126 
127   guint		    needs_pixmap           : 1;
128   guint             needs_reshape          : 1;
129   guint             recompute_focused_shadow   : 1;
130   guint             recompute_unfocused_shadow : 1;
131   guint             size_changed               : 1;
132   guint             position_changed           : 1;
133   guint             updates_frozen         : 1;
134 
135   guint		    needs_destroy	   : 1;
136 
137   guint             no_shadow              : 1;
138 
139   guint             unredirected           : 1;
140 
141   /* This is used to detect fullscreen windows that need to be unredirected */
142   guint             full_damage_frames_count;
143   guint             does_full_damage  : 1;
144 
145   guint             has_desat_effect : 1;
146 
147   guint             reshapes;
148   guint             should_have_shadow : 1;
149 };
150 
151 typedef struct _FrameData FrameData;
152 
153 struct _FrameData
154 {
155   int64_t frame_counter;
156   guint64 sync_request_serial;
157   gint64 frame_drawn_time;
158 };
159 
160 enum
161 {
162   PROP_META_WINDOW = 1,
163   PROP_META_SCREEN,
164   PROP_X_WINDOW,
165   PROP_X_WINDOW_ATTRIBUTES,
166   PROP_NO_SHADOW,
167   PROP_SHADOW_CLASS
168 };
169 
170 #define DEFAULT_SHADOW_RADIUS 12
171 #define DEFAULT_SHADOW_X_OFFSET 0
172 #define DEFAULT_SHADOW_Y_OFFSET 8
173 
174 static void meta_window_actor_dispose    (GObject *object);
175 static void meta_window_actor_finalize   (GObject *object);
176 static void meta_window_actor_constructed (GObject *object);
177 static void meta_window_actor_set_property (GObject       *object,
178                                             guint         prop_id,
179                                             const GValue *value,
180                                             GParamSpec   *pspec);
181 static void meta_window_actor_get_property (GObject      *object,
182                                             guint         prop_id,
183                                             GValue       *value,
184                                             GParamSpec   *pspec);
185 
186 static void meta_window_actor_pick (ClutterActor       *actor,
187 			                              const ClutterColor *color);
188 static void meta_window_actor_paint (ClutterActor *actor);
189 
190 static gboolean meta_window_actor_get_paint_volume (ClutterActor       *actor,
191                                                     ClutterPaintVolume *volume);
192 
193 
194 static void     meta_window_actor_detach     (MetaWindowActor *self);
195 static gboolean meta_window_actor_has_shadow (MetaWindowActor *self);
196 
197 static void meta_window_actor_handle_updates (MetaWindowActor *self);
198 
199 static void check_needs_reshape (MetaWindowActor *self);
200 
201 static void do_send_frame_drawn (MetaWindowActor *self, FrameData *frame);
202 static void do_send_frame_timings (MetaWindowActor  *self,
203                                    FrameData        *frame,
204                                    gint             refresh_interval,
205                                    gint64           presentation_time);
206 
207 G_DEFINE_TYPE (MetaWindowActor, meta_window_actor, CLUTTER_TYPE_ACTOR);
208 
209 static void
frame_data_free(FrameData * frame)210 frame_data_free (FrameData *frame)
211 {
212   g_slice_free (FrameData, frame);
213 }
214 
215 static void
meta_window_actor_class_init(MetaWindowActorClass * klass)216 meta_window_actor_class_init (MetaWindowActorClass *klass)
217 {
218   GObjectClass *object_class = G_OBJECT_CLASS (klass);
219   ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
220   GParamSpec   *pspec;
221 
222   g_type_class_add_private (klass, sizeof (MetaWindowActorPrivate));
223 
224   object_class->dispose      = meta_window_actor_dispose;
225   object_class->finalize     = meta_window_actor_finalize;
226   object_class->set_property = meta_window_actor_set_property;
227   object_class->get_property = meta_window_actor_get_property;
228   object_class->constructed  = meta_window_actor_constructed;
229 
230   actor_class->pick = meta_window_actor_pick;
231   actor_class->paint = meta_window_actor_paint;
232   actor_class->get_paint_volume = meta_window_actor_get_paint_volume;
233 
234   pspec = g_param_spec_object ("meta-window",
235                                "MetaWindow",
236                                "The displayed MetaWindow",
237                                META_TYPE_WINDOW,
238                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
239 
240   g_object_class_install_property (object_class,
241                                    PROP_META_WINDOW,
242                                    pspec);
243 
244   pspec = g_param_spec_pointer ("meta-screen",
245 				"MetaScreen",
246 				"MetaScreen",
247 				G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
248 
249   g_object_class_install_property (object_class,
250                                    PROP_META_SCREEN,
251                                    pspec);
252 
253   pspec = g_param_spec_ulong ("x-window",
254 			      "Window",
255 			      "Window",
256 			      0,
257 			      G_MAXULONG,
258 			      0,
259 			      G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
260 
261   g_object_class_install_property (object_class,
262                                    PROP_X_WINDOW,
263                                    pspec);
264 
265   pspec = g_param_spec_boolean ("no-shadow",
266                                 "No shadow",
267                                 "Do not add shaddow to this window",
268                                 FALSE,
269                                 G_PARAM_READWRITE);
270 
271   g_object_class_install_property (object_class,
272                                    PROP_NO_SHADOW,
273                                    pspec);
274 
275   pspec = g_param_spec_string ("shadow-class",
276                                "Name of the shadow class for this window.",
277                                "NULL means to use the default shadow class for this window type",
278                                NULL,
279                                G_PARAM_READWRITE);
280 
281   g_object_class_install_property (object_class,
282                                    PROP_SHADOW_CLASS,
283                                    pspec);
284 
285   signals[POSITION_CHANGED] =
286     g_signal_new ("position-changed",
287                   G_TYPE_FROM_CLASS (klass),
288                   G_SIGNAL_RUN_LAST,
289                   0, NULL, NULL, NULL,
290                   G_TYPE_NONE, 0);
291   signals[SIZE_CHANGED] =
292     g_signal_new ("size-changed",
293                   G_TYPE_FROM_CLASS (klass),
294                   G_SIGNAL_RUN_LAST,
295                   0, NULL, NULL, NULL,
296                   G_TYPE_NONE, 0);
297 }
298 
299 static void
meta_window_actor_init(MetaWindowActor * self)300 meta_window_actor_init (MetaWindowActor *self)
301 {
302   MetaWindowActorPrivate *priv;
303 
304   priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
305 						   META_TYPE_WINDOW_ACTOR,
306 						   MetaWindowActorPrivate);
307   priv->opacity = 0xff;
308   priv->shadow_class = NULL;
309   priv->has_desat_effect = FALSE;
310   priv->reshapes = 0;
311   priv->should_have_shadow = FALSE;
312 }
313 
314 static void
meta_window_actor_reset_mask_texture(MetaWindowActor * self,cairo_region_t * shape_region,gboolean force)315 meta_window_actor_reset_mask_texture (MetaWindowActor *self,
316                                       cairo_region_t  *shape_region,
317                                       gboolean force)
318 {
319   MetaShapedTexture *stex = META_SHAPED_TEXTURE (self->priv->actor);
320   if (force)
321     meta_shaped_texture_dirty_mask (stex);
322   meta_shaped_texture_ensure_mask (stex, shape_region, self->priv->window->frame != NULL);
323 }
324 
325 static void
maybe_desaturate_window(ClutterActor * actor)326 maybe_desaturate_window (ClutterActor *actor)
327 {
328   MetaWindowActor *window = META_WINDOW_ACTOR (actor);
329   MetaWindowActorPrivate *priv = window->priv;
330 
331   if (!priv->should_have_shadow && !priv->has_desat_effect)
332     return;
333 
334   guint8 opacity = clutter_actor_get_opacity (actor);
335 
336   if (opacity < 255)
337     {
338       if (priv->has_desat_effect)
339         {
340           return;
341         }
342       else
343         {
344           ClutterEffect *effect = clutter_desaturate_effect_new (0.0);
345           clutter_actor_add_effect_with_name (actor, "desaturate-for-transparency", effect);
346           priv->has_desat_effect = TRUE;
347         }
348     }
349   else
350     {
351       /* This is will tend to get called fairly often - opening new windows, various
352          events on the window, like minimizing... but it's inexpensive - if the ClutterActor
353          priv->effects is NULL, it simply returns.  By default cinnamon and muffin add no
354          other effects except the special case of dimmed windows (attached modal dialogs), which
355          isn't a frequent occurrence. */
356 
357       clutter_actor_remove_effect_by_name (actor, "desaturate-for-transparency");
358       priv->has_desat_effect = FALSE;
359     }
360 }
361 
362 static void
window_decorated_notify(MetaWindow * mw,GParamSpec * arg1,gpointer data)363 window_decorated_notify (MetaWindow *mw,
364                          GParamSpec *arg1,
365                          gpointer    data)
366 {
367   MetaWindowActor        *self     = META_WINDOW_ACTOR (data);
368   MetaWindowActorPrivate *priv     = self->priv;
369   MetaFrame              *frame    = meta_window_get_frame (mw);
370   MetaScreen             *screen   = priv->screen;
371   MetaDisplay            *display  = meta_screen_get_display (screen);
372   Display                *xdisplay = meta_display_get_xdisplay (display);
373   Window                  new_xwindow;
374 
375   /*
376    * Basically, we have to reconstruct the the internals of this object
377    * from scratch, as everything has changed.
378    */
379   priv->redecorating = TRUE;
380 
381   if (frame)
382     new_xwindow = meta_frame_get_xwindow (frame);
383   else
384     new_xwindow = meta_window_get_xwindow (mw);
385 
386   meta_window_actor_detach (self);
387 
388   /*
389    * First of all, clean up any resources we are currently using and will
390    * be replacing.
391    */
392   if (priv->damage != None)
393     {
394       meta_error_trap_push (display);
395       XDamageDestroy (xdisplay, priv->damage);
396       meta_error_trap_pop (display);
397       priv->damage = None;
398     }
399 
400   priv->xwindow = new_xwindow;
401 
402   /*
403    * Recreate the contents.
404    */
405   meta_window_actor_constructed (G_OBJECT (self));
406 }
407 
408 static void
window_appears_focused_notify(MetaWindow * mw,GParamSpec * arg1,gpointer data)409 window_appears_focused_notify (MetaWindow *mw,
410                                GParamSpec *arg1,
411                                gpointer    data)
412 {
413   clutter_actor_queue_redraw (CLUTTER_ACTOR (data));
414 }
415 
416 static void
clutter_actor_opacity_notify(ClutterActor * actor,GParamSpec * arg1m,gpointer data)417 clutter_actor_opacity_notify (ClutterActor *actor,
418                               GParamSpec   *arg1m,
419                               gpointer      data)
420 {
421   maybe_desaturate_window (actor);
422 }
423 
424 static void
texture_size_changed(MetaWindow * mw,gpointer data)425 texture_size_changed (MetaWindow *mw,
426                      gpointer    data)
427 {
428   MetaWindowActor *self = META_WINDOW_ACTOR (data);
429 
430   g_signal_emit (self, signals[SIZE_CHANGED], 0); // Compatibility
431 }
432 
433 static void
window_position_changed(MetaWindow * mw,gpointer data)434 window_position_changed (MetaWindow *mw,
435                      gpointer    data)
436 {
437   MetaWindowActor *self = META_WINDOW_ACTOR (data);
438 
439   g_signal_emit (self, signals[POSITION_CHANGED], 0); // Compatibility
440 }
441 
442 static void
meta_window_actor_constructed(GObject * object)443 meta_window_actor_constructed (GObject *object)
444 {
445   MetaWindowActor        *self     = META_WINDOW_ACTOR (object);
446   MetaWindowActorPrivate *priv     = self->priv;
447   MetaScreen             *screen   = priv->screen;
448   MetaDisplay            *display  = meta_screen_get_display (screen);
449   Window                  xwindow  = priv->xwindow;
450   MetaWindow             *window   = priv->window;
451   Display                *xdisplay = meta_display_get_xdisplay (display);
452   XRenderPictFormat      *format;
453 
454   priv->damage = XDamageCreate (xdisplay, xwindow,
455                                 XDamageReportBoundingBox);
456 
457   format = XRenderFindVisualFormat (xdisplay, window->xvisual);
458 
459   if (format && format->type == PictTypeDirect && format->direct.alphaMask)
460     priv->argb32 = TRUE;
461 
462   if (!priv->actor)
463     {
464       priv->actor = meta_shaped_texture_new ();
465 
466       priv->size_changed_id = g_signal_connect (priv->actor, "size-changed",
467                                                 G_CALLBACK (texture_size_changed), self);
468       clutter_actor_add_child (CLUTTER_ACTOR (self), priv->actor);
469 
470       /*
471        * Since we are holding a pointer to this actor independently of the
472        * ClutterContainer internals, and provide a public API to access it,
473        * add a reference here, so that if someone is messing about with us
474        * via the container interface, we do not end up with a dangling pointer.
475        * We will release it in dispose().
476        */
477       g_object_ref (priv->actor);
478       priv->opacity_changed_id = g_signal_connect (self, "notify::opacity",
479                                                    G_CALLBACK (clutter_actor_opacity_notify), NULL);
480 
481       /* Fix for the case when clients try to re-map their windows after re-decorating while
482          effects are enabled. For reasons currently unknown, the re-shape doesn't happen when
483          #meta_plugin_map_completed is called after a delay. #window_decorated_notify is not
484          always called on re-decoration, and when it is, its only called before the actor is
485          disposed in this case - we can't track after that. */
486       if (meta_prefs_get_desktop_effects () &&
487           window->frame != NULL &&
488           window->decorated &&
489           !window->pending_compositor_effect &&
490           !window->unmaps_pending)
491         priv->needs_reshape = TRUE;
492     }
493   else
494     {
495       /*
496        * This is the case where existing window is gaining/loosing frame.
497        * Just ensure the actor is top most (i.e., above shadow).
498        */
499       g_signal_handler_disconnect (priv->actor, priv->size_changed_id);
500       g_signal_handler_disconnect (self, priv->opacity_changed_id);
501       clutter_actor_set_child_above_sibling (CLUTTER_ACTOR (self), priv->actor, NULL);
502     }
503 
504   meta_window_actor_update_opacity (self);
505   maybe_desaturate_window (CLUTTER_ACTOR (self));
506 
507   priv->shape_region = cairo_region_create();
508 }
509 
510 static void
meta_window_actor_dispose(GObject * object)511 meta_window_actor_dispose (GObject *object)
512 {
513   MetaWindowActor        *self = META_WINDOW_ACTOR (object);
514   MetaWindowActorPrivate *priv = self->priv;
515   MetaScreen *screen;
516   MetaDisplay *display;
517   Display *xdisplay;
518   MetaCompositor *compositor;
519 
520   if (priv->disposed)
521     return;
522 
523   priv->disposed = TRUE;
524 
525   if (priv->send_frame_messages_timer != 0)
526     {
527       g_source_remove (priv->send_frame_messages_timer);
528       priv->send_frame_messages_timer = 0;
529     }
530 
531   screen = priv->screen;
532   display = screen->display;
533   xdisplay = display->xdisplay;
534   compositor = display->compositor;
535 
536   meta_window_actor_detach (self);
537 
538   g_clear_pointer (&priv->unobscured_region, cairo_region_destroy);
539   g_clear_pointer (&priv->shape_region, cairo_region_destroy);
540   g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
541   g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
542 
543   g_clear_pointer (&priv->shadow_class, free);
544   g_clear_pointer (&priv->focused_shadow, meta_shadow_unref);
545   g_clear_pointer (&priv->unfocused_shadow, meta_shadow_unref);
546   g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref);
547 
548   if (priv->damage != None)
549     {
550       meta_error_trap_push (display);
551       XDamageDestroy (xdisplay, priv->damage);
552       meta_error_trap_pop (display);
553 
554       priv->damage = None;
555     }
556 
557   compositor->windows = g_list_remove (compositor->windows, (gconstpointer) self);
558 
559   g_clear_object (&priv->window);
560 
561   /*
562    * Release the extra reference we took on the actor.
563    */
564   g_clear_object (&priv->actor);
565 
566   G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object);
567 }
568 
569 static void
meta_window_actor_finalize(GObject * object)570 meta_window_actor_finalize (GObject *object)
571 {
572   MetaWindowActor        *self = META_WINDOW_ACTOR (object);
573   MetaWindowActorPrivate *priv = self->priv;
574   g_list_free_full (priv->frames, (GDestroyNotify) frame_data_free);
575   G_OBJECT_CLASS (meta_window_actor_parent_class)->finalize (object);
576 }
577 
578 static void
meta_window_actor_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)579 meta_window_actor_set_property (GObject      *object,
580                                 guint         prop_id,
581                                 const GValue *value,
582                                 GParamSpec   *pspec)
583 {
584   MetaWindowActor        *self   = META_WINDOW_ACTOR (object);
585   MetaWindowActorPrivate *priv = self->priv;
586 
587   switch (prop_id)
588     {
589     case PROP_META_WINDOW:
590       {
591         if (priv->window)
592           g_object_unref (priv->window);
593         priv->window = g_value_dup_object (value);
594 
595         g_signal_connect_object (priv->window, "notify::decorated",
596                                  G_CALLBACK (window_decorated_notify), self, 0);
597         g_signal_connect_object (priv->window, "notify::appears-focused",
598                                  G_CALLBACK (window_appears_focused_notify), self, 0);
599         g_signal_connect_object (priv->window, "position-changed",
600                                  G_CALLBACK (window_position_changed), self, 0);
601       }
602       break;
603     case PROP_META_SCREEN:
604       priv->screen = g_value_get_pointer (value);
605       break;
606     case PROP_X_WINDOW:
607       priv->xwindow = g_value_get_ulong (value);
608       break;
609     case PROP_NO_SHADOW:
610       {
611         gboolean newv = g_value_get_boolean (value);
612 
613         if (newv == priv->no_shadow)
614           return;
615 
616         priv->no_shadow = newv;
617 
618         meta_window_actor_invalidate_shadow (self);
619       }
620       break;
621     case PROP_SHADOW_CLASS:
622       {
623         const char *newv = g_value_get_string (value);
624 
625         if (g_strcmp0 (newv, priv->shadow_class) == 0)
626           return;
627 
628         free (priv->shadow_class);
629         priv->shadow_class = g_strdup (newv);
630 
631         meta_window_actor_invalidate_shadow (self);
632       }
633       break;
634     default:
635       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
636       break;
637     }
638 }
639 
640 static void
meta_window_actor_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)641 meta_window_actor_get_property (GObject      *object,
642                                 guint         prop_id,
643                                 GValue       *value,
644                                 GParamSpec   *pspec)
645 {
646   MetaWindowActorPrivate *priv = META_WINDOW_ACTOR (object)->priv;
647 
648   switch (prop_id)
649     {
650     case PROP_META_WINDOW:
651       g_value_set_object (value, priv->window);
652       break;
653     case PROP_META_SCREEN:
654       g_value_set_pointer (value, priv->screen);
655       break;
656     case PROP_X_WINDOW:
657       g_value_set_ulong (value, priv->xwindow);
658       break;
659     case PROP_NO_SHADOW:
660       g_value_set_boolean (value, priv->no_shadow);
661       break;
662     case PROP_SHADOW_CLASS:
663       g_value_set_string (value, priv->shadow_class);
664       break;
665     default:
666       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
667       break;
668     }
669 }
670 
671 static const char *
meta_window_actor_get_shadow_class(MetaWindowActor * self)672 meta_window_actor_get_shadow_class (MetaWindowActor *self)
673 {
674   MetaWindowActorPrivate *priv = self->priv;
675 
676   if (priv->shadow_class != NULL)
677     return priv->shadow_class;
678   else
679     {
680       MetaWindowType window_type = meta_window_get_window_type (priv->window);
681 
682       switch (window_type)
683         {
684         case META_WINDOW_DROPDOWN_MENU:
685           return "dropdown-menu";
686         case META_WINDOW_POPUP_MENU:
687           return "popup-menu";
688         default:
689           {
690             MetaFrameType frame_type = meta_window_get_frame_type (priv->window);
691             return meta_frame_type_to_string (frame_type);
692           }
693         }
694     }
695 }
696 
697 static void
meta_window_actor_get_shadow_params(MetaWindowActor * self,gboolean appears_focused,MetaShadowParams * params)698 meta_window_actor_get_shadow_params (MetaWindowActor  *self,
699                                      gboolean          appears_focused,
700                                      MetaShadowParams *params)
701 {
702   const char *shadow_class = meta_window_actor_get_shadow_class (self);
703 
704   meta_shadow_factory_get_params (meta_shadow_factory_get_default (),
705                                   shadow_class, appears_focused,
706                                   params);
707 }
708 
709 LOCAL_SYMBOL void
meta_window_actor_get_shape_bounds(MetaWindowActor * self,cairo_rectangle_int_t * bounds)710 meta_window_actor_get_shape_bounds (MetaWindowActor       *self,
711                                     cairo_rectangle_int_t *bounds)
712 {
713   MetaWindowActorPrivate *priv = self->priv;
714 
715   /* We need to be defensive here because there are corner cases
716    * where getting the shape fails on a window being destroyed
717    * and similar.
718    */
719   if (priv->shape_region)
720     cairo_region_get_extents (priv->shape_region, bounds);
721   else
722     bounds->x = bounds->y = bounds->width = bounds->height = 0;
723 }
724 
725 static void
meta_window_actor_get_shadow_bounds(MetaWindowActor * self,gboolean appears_focused,cairo_rectangle_int_t * bounds)726 meta_window_actor_get_shadow_bounds (MetaWindowActor       *self,
727                                      gboolean               appears_focused,
728                                      cairo_rectangle_int_t *bounds)
729 {
730   MetaWindowActorPrivate *priv = self->priv;
731   MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow;
732   cairo_rectangle_int_t shape_bounds;
733   MetaShadowParams params;
734 
735   meta_window_actor_get_shape_bounds (self, &shape_bounds);
736   meta_window_actor_get_shadow_params (self, appears_focused, &params);
737 
738   meta_shadow_get_bounds (shadow,
739                           params.x_offset + shape_bounds.x,
740                           params.y_offset + shape_bounds.y,
741                           shape_bounds.width,
742                           shape_bounds.height,
743                           bounds);
744 }
745 
746 /* If we have an ARGB32 window that we decorate with a frame, it's
747  * probably something like a translucent terminal - something where
748  * the alpha channel represents transparency rather than a shape.  We
749  * don't want to show the shadow through the translucent areas since
750  * the shadow is wrong for translucent windows (it should be
751  * translucent itself and colored), and not only that, will /look/
752  * horribly wrong - a misplaced big black blob. As a hack, what we
753  * want to do is just draw the shadow as normal outside the frame, and
754  * inside the frame draw no shadow.  This is also not even close to
755  * the right result, but looks OK. We also apply this approach to
756  * windows set to be partially translucent with _NET_WM_WINDOW_OPACITY.
757  */
758 static gboolean
clip_shadow_under_window(MetaWindowActor * self)759 clip_shadow_under_window (MetaWindowActor *self)
760 {
761   MetaWindowActorPrivate *priv = self->priv;
762 
763   return (priv->argb32 || priv->opacity != 0xff) && priv->window->frame;
764 }
765 
766 static void
assign_frame_counter_to_frames(MetaWindowActor * self)767 assign_frame_counter_to_frames (MetaWindowActor *self)
768 {
769   MetaWindowActorPrivate *priv = self->priv;
770   ClutterStage *stage = priv->window->display->compositor->stage;
771   GList *l;
772 
773   /* If the window is obscured, then we're expecting to deal with sending
774    * frame messages in a timeout, rather than in this paint cycle.
775    */
776   if (priv->send_frame_messages_timer != 0)
777     return;
778 
779   for (l = priv->frames; l; l = l->next)
780     {
781       FrameData *frame = l->data;
782 
783       if (frame->frame_counter == -1)
784         frame->frame_counter = clutter_stage_get_frame_counter (stage);
785     }
786 }
787 
788 static void
meta_window_actor_pick(ClutterActor * actor,const ClutterColor * color)789 meta_window_actor_pick (ClutterActor       *actor,
790 			                  const ClutterColor *color)
791 {
792   if (!clutter_actor_should_pick_paint (actor))
793     return;
794 
795   MetaWindowActor *self = (MetaWindowActor *) actor;
796   MetaWindowActorPrivate *priv = self->priv;
797   ClutterActorIter iter;
798   ClutterActor *child;
799 
800   /* If there is no region then use the regular pick */
801   if (priv->shape_region == NULL)
802     CLUTTER_ACTOR_CLASS (meta_window_actor_parent_class)->pick (actor, color);
803   else
804     {
805       int n_rects;
806       float *rectangles;
807       int i;
808       CoglPipeline *pipeline;
809       CoglContext *ctx;
810       CoglFramebuffer *fb;
811       CoglColor cogl_color;
812 
813       n_rects = cairo_region_num_rectangles (priv->shape_region);
814       rectangles = g_alloca (sizeof (float) * 4 * n_rects);
815 
816       for (i = 0; i < n_rects; i++)
817         {
818           cairo_rectangle_int_t rect;
819           int pos = i * 4;
820 
821           cairo_region_get_rectangle (priv->shape_region, i, &rect);
822 
823           rectangles[pos + 0] = rect.x;
824           rectangles[pos + 1] = rect.y;
825           rectangles[pos + 2] = rect.x + rect.width;
826           rectangles[pos + 3] = rect.y + rect.height;
827         }
828 
829       ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
830       fb = cogl_get_draw_framebuffer ();
831 
832       cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha);
833 
834       pipeline = cogl_pipeline_new (ctx);
835       cogl_pipeline_set_color (pipeline, &cogl_color);
836       cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects);
837       cogl_object_unref (pipeline);
838     }
839 
840   clutter_actor_iter_init (&iter, actor);
841 
842   while (clutter_actor_iter_next (&iter, &child))
843     clutter_actor_paint (child);
844 }
845 
846 static void
meta_window_actor_paint(ClutterActor * actor)847 meta_window_actor_paint (ClutterActor *actor)
848 {
849   MetaWindowActor *self = META_WINDOW_ACTOR (actor);
850   MetaWindowActorPrivate *priv = self->priv;
851   CoglFramebuffer *framebuffer = NULL;
852   gboolean appears_focused = meta_window_appears_focused (priv->window);
853   MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow;
854 
855   if (!priv->window->display->shadows_enabled) {
856       shadow = NULL;
857   }
858 
859  /* This window got damage when obscured; we set up a timer
860   * to send frame completion events, but since we're drawing
861   * the window now (for some other reason) cancel the timer
862   * and send the completion events normally */
863   if (priv->send_frame_messages_timer != 0)
864     {
865       g_source_remove (priv->send_frame_messages_timer);
866       priv->send_frame_messages_timer = 0;
867 
868       assign_frame_counter_to_frames (self);
869     }
870 
871   if (shadow != NULL)
872     {
873       MetaShadowParams params;
874       cairo_rectangle_int_t shape_bounds;
875       cairo_region_t *clip = priv->shadow_clip;
876 
877       meta_window_actor_get_shape_bounds (self, &shape_bounds);
878       meta_window_actor_get_shadow_params (self, appears_focused, &params);
879 
880       /* The frame bounds are already subtracted from priv->shadow_clip
881        * if that exists.
882        */
883       if (!clip && clip_shadow_under_window (self))
884         {
885           cairo_rectangle_int_t bounds;
886 
887           meta_window_actor_get_shadow_bounds (self, appears_focused, &bounds);
888           clip = cairo_region_create_rectangle (&bounds);
889 
890           cairo_region_subtract (clip, meta_window_get_frame_bounds (priv->window));
891         }
892 
893       framebuffer = cogl_get_draw_framebuffer ();
894 
895       meta_shadow_paint (shadow,
896                          framebuffer,
897                          params.x_offset + shape_bounds.x,
898                          params.y_offset + shape_bounds.y,
899                          shape_bounds.width,
900                          shape_bounds.height,
901                          (clutter_actor_get_paint_opacity (actor) * params.opacity * priv->opacity) / (255 * 255),
902                          clip,
903                          clip_shadow_under_window (self)); /* clip_strictly - not just as an optimization */
904 
905       if (clip && clip != priv->shadow_clip)
906         cairo_region_destroy (clip);
907     }
908 
909   CLUTTER_ACTOR_CLASS (meta_window_actor_parent_class)->paint (actor);
910 }
911 
912 static gboolean
meta_window_actor_get_paint_volume(ClutterActor * actor,ClutterPaintVolume * volume)913 meta_window_actor_get_paint_volume (ClutterActor       *actor,
914                                     ClutterPaintVolume *volume)
915 {
916   MetaWindowActor *self = META_WINDOW_ACTOR (actor);
917   MetaWindowActorPrivate *priv = self->priv;
918   gboolean appears_focused = meta_window_appears_focused (priv->window);
919 
920   /* The paint volume is computed before paint functions are called
921    * so our bounds might not be updated yet. Force an update. */
922   meta_window_actor_handle_updates (self);
923 
924   if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow)
925     {
926       cairo_rectangle_int_t shadow_bounds;
927       ClutterActorBox shadow_box;
928 
929       /* We could compute an full clip region as we do for the window
930        * texture, but the shadow is relatively cheap to draw, and
931        * a little more complex to clip, so we just catch the case where
932        * the shadow is completely obscured and doesn't need to be drawn
933        * at all.
934        */
935 
936       meta_window_actor_get_shadow_bounds (self, appears_focused, &shadow_bounds);
937       shadow_box.x1 = shadow_bounds.x;
938       shadow_box.x2 = shadow_bounds.x + shadow_bounds.width;
939       shadow_box.y1 = shadow_bounds.y;
940       shadow_box.y2 = shadow_bounds.y + shadow_bounds.height;
941 
942       clutter_paint_volume_union_box (volume, &shadow_box);
943     }
944 
945   if (priv->actor)
946     {
947       const ClutterPaintVolume *child_volume;
948 
949       child_volume = clutter_actor_get_transformed_paint_volume (CLUTTER_ACTOR (priv->actor), actor);
950       if (!child_volume)
951         return FALSE;
952 
953       clutter_paint_volume_union (volume, child_volume);
954     }
955 
956   return TRUE;
957 }
958 
959 static gboolean
meta_window_actor_has_shadow(MetaWindowActor * self)960 meta_window_actor_has_shadow (MetaWindowActor *self)
961 {
962   MetaWindowActorPrivate *priv = self->priv;
963   MetaWindowType window_type = meta_window_get_window_type (priv->window);
964 
965   if (priv->no_shadow)
966     return FALSE;
967 
968   /* Leaving out shadows for maximized and fullscreen windows is an effeciency
969    * win and also prevents the unsightly effect of the shadow of maximized
970    * window appearing on an adjacent window */
971   if ((meta_window_get_maximized (priv->window) == (META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL)) ||
972       meta_window_is_fullscreen (priv->window))
973     return FALSE;
974 
975   /* Don't shadow tiled windows of any type */
976 
977   if (meta_window_get_tile_type (priv->window) != META_WINDOW_TILE_TYPE_NONE)
978     return FALSE;
979 
980   /*
981    * Always put a shadow around windows with a frame - This should override
982    * the restriction about not putting a shadow around ARGB windows.
983    */
984   if (priv->window)
985     {
986       if (meta_window_get_frame (priv->window))
987         return TRUE;
988     }
989 
990   /*
991    * Do not add shadows to ARGB windows; eventually we should generate a
992    * shadow from the input shape for such windows.
993    */
994   if (priv->argb32 || priv->opacity != 0xff)
995     return FALSE;
996   /*
997    * Add shadows to override redirect windows (e.g., Gtk menus).
998    */
999   if (priv->window->override_redirect)
1000     return TRUE;
1001 
1002   /*
1003    * If a window specifies that it has custom frame extents, that likely
1004    * means that it is drawing a shadow itself. Don't draw our own.
1005    */
1006   if (priv->window->has_custom_frame_extents)
1007     return FALSE;
1008 
1009   /*
1010    * Don't put shadow around DND icon windows
1011    */
1012   if (window_type == META_WINDOW_DND ||
1013       window_type == META_WINDOW_DESKTOP ||
1014       window_type == META_WINDOW_DOCK)
1015     return FALSE;
1016 
1017   if (window_type == META_WINDOW_MENU
1018 #if 0
1019       || window_type == META_WINDOW_DROPDOWN_MENU
1020 #endif
1021       )
1022     return TRUE;
1023 
1024   if (meta_window_is_client_decorated (priv->window))
1025     {
1026       return FALSE;
1027     }
1028 
1029 #if 0
1030   if (window_type == META_WINDOW_TOOLTIP)
1031     return TRUE;
1032 #endif
1033 
1034   return FALSE;
1035 }
1036 
1037 /**
1038  * meta_window_actor_get_x_window: (skip)
1039  *
1040  */
1041 Window
meta_window_actor_get_x_window(MetaWindowActor * self)1042 meta_window_actor_get_x_window (MetaWindowActor *self)
1043 {
1044   if (!self)
1045     return None;
1046 
1047   return self->priv->xwindow;
1048 }
1049 
1050 /**
1051  * meta_window_actor_get_meta_window:
1052  *
1053  * Gets the #MetaWindow object that the the #MetaWindowActor is displaying
1054  *
1055  * Return value: (transfer none): the displayed #MetaWindow
1056  */
1057 MetaWindow *
meta_window_actor_get_meta_window(MetaWindowActor * self)1058 meta_window_actor_get_meta_window (MetaWindowActor *self)
1059 {
1060   return self->priv->window;
1061 }
1062 
1063 /**
1064  * meta_window_actor_get_texture:
1065  *
1066  * Gets the ClutterActor that is used to display the contents of the window
1067  *
1068  * Return value: (transfer none): the #ClutterActor for the contents
1069  */
1070 ClutterActor *
meta_window_actor_get_texture(MetaWindowActor * self)1071 meta_window_actor_get_texture (MetaWindowActor *self)
1072 {
1073   return self->priv->actor;
1074 }
1075 
1076 /**
1077  * meta_window_actor_is_destroyed:
1078  *
1079  * Gets whether the X window that the actor was displaying has been destroyed
1080  *
1081  * Return value: %TRUE when the window is destroyed, otherwise %FALSE
1082  */
1083 gboolean
meta_window_actor_is_destroyed(MetaWindowActor * self)1084 meta_window_actor_is_destroyed (MetaWindowActor *self)
1085 {
1086   return self->priv->disposed || self->priv->needs_destroy;
1087 }
1088 
1089 static gboolean
send_frame_messages_timeout(gpointer data)1090 send_frame_messages_timeout (gpointer data)
1091 {
1092   MetaWindowActor *self = (MetaWindowActor *) data;
1093   MetaWindowActorPrivate *priv = self->priv;
1094   GList *l;
1095 
1096   for (l = priv->frames; l;)
1097     {
1098       GList *l_next = l->next;
1099       FrameData *frame = l->data;
1100 
1101       if (frame->frame_counter == -1)
1102         {
1103           do_send_frame_drawn (self, frame);
1104           do_send_frame_timings (self, frame, 0, 0);
1105 
1106           priv->frames = g_list_delete_link (priv->frames, l);
1107           frame_data_free (frame);
1108         }
1109 
1110       l = l_next;
1111     }
1112 
1113   priv->needs_frame_drawn = FALSE;
1114   priv->send_frame_messages_timer = 0;
1115 
1116   return FALSE;
1117 }
1118 
1119 static void
queue_send_frame_messages_timeout(MetaWindowActor * self)1120 queue_send_frame_messages_timeout (MetaWindowActor *self)
1121 {
1122   MetaWindowActorPrivate *priv = self->priv;
1123   MetaWindow *window = meta_window_actor_get_meta_window (self);
1124   MetaDisplay *display = meta_screen_get_display (priv->screen);
1125   int64_t current_time;
1126   float refresh_rate;
1127   int interval, offset;
1128 
1129   if (priv->send_frame_messages_timer != 0)
1130     return;
1131 
1132   if (window->monitor)
1133     {
1134       refresh_rate = window->monitor->refresh_rate;
1135     }
1136   else
1137     {
1138       refresh_rate = 60.0f;
1139     }
1140 
1141   current_time =
1142     meta_compositor_monotonic_time_to_server_time (display,
1143                                                    g_get_monotonic_time ());
1144   interval = (int)(1000000 / refresh_rate) * 6;
1145   offset = MAX (0, priv->frame_drawn_time + interval - current_time) / 1000;
1146 
1147  /* The clutter master clock source has already been added with META_PRIORITY_REDRAW,
1148   * so the timer will run *after* the clutter frame handling, if a frame is ready
1149   * to be drawn when the timer expires.
1150   */
1151   priv->send_frame_messages_timer = g_timeout_add_full (META_PRIORITY_REDRAW, offset, send_frame_messages_timeout, self, NULL);
1152   g_source_set_name_by_id (priv->send_frame_messages_timer, "[muffin] send_frame_messages_timeout");
1153 }
1154 
1155 gboolean
meta_window_actor_is_override_redirect(MetaWindowActor * self)1156 meta_window_actor_is_override_redirect (MetaWindowActor *self)
1157 {
1158   return meta_window_is_override_redirect (self->priv->window);
1159 }
1160 
1161 /**
1162  * meta_window_actor_get_workspace:
1163  * @self: #MetaWindowActor
1164  *
1165  * Returns the index of workspace on which this window is located; if the
1166  * window is sticky, or is not currently located on any workspace, returns -1.
1167  * This function is deprecated  and should not be used in newly written code;
1168  * meta_window_get_workspace() instead.
1169  *
1170  * Return value: index of workspace on which this window is
1171  * located.
1172  */
1173 gint
meta_window_actor_get_workspace(MetaWindowActor * self)1174 meta_window_actor_get_workspace (MetaWindowActor *self)
1175 {
1176   MetaWindowActorPrivate *priv;
1177   MetaWorkspace          *workspace;
1178 
1179   if (!self)
1180     return -1;
1181 
1182   priv = self->priv;
1183 
1184   if (!priv->window || meta_window_is_on_all_workspaces (priv->window))
1185     return -1;
1186 
1187   workspace = meta_window_get_workspace (priv->window);
1188 
1189   if (!workspace)
1190     return -1;
1191 
1192   return meta_workspace_index (workspace);
1193 }
1194 
1195 gboolean
meta_window_actor_showing_on_its_workspace(MetaWindowActor * self)1196 meta_window_actor_showing_on_its_workspace (MetaWindowActor *self)
1197 {
1198   if (!self)
1199     return FALSE;
1200 
1201   /* If override redirect: */
1202   if (!self->priv->window)
1203     return TRUE;
1204 
1205   return meta_window_showing_on_its_workspace (self->priv->window);
1206 }
1207 
1208 static void
meta_window_actor_freeze(MetaWindowActor * self)1209 meta_window_actor_freeze (MetaWindowActor *self)
1210 {
1211   self->priv->freeze_count++;
1212 }
1213 
1214 static void
update_area(MetaWindowActor * self,int x,int y,int width,int height)1215 update_area (MetaWindowActor *self,
1216              int x, int y, int width, int height)
1217 {
1218   MetaWindowActorPrivate *priv = self->priv;
1219   CoglTexture *texture;
1220 
1221   texture = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor));
1222 
1223   cogl_texture_pixmap_x11_update_area (COGL_TEXTURE_PIXMAP_X11 (texture),
1224                                        x, y, width, height);
1225 }
1226 
1227 static void
meta_window_actor_damage_all(MetaWindowActor * self)1228 meta_window_actor_damage_all (MetaWindowActor *self)
1229 {
1230   MetaWindowActorPrivate *priv = self->priv;
1231   CoglTexture *texture;
1232 
1233   if (!priv->needs_damage_all || !priv->window->mapped || priv->needs_pixmap)
1234     return;
1235 
1236   texture = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor));
1237 
1238   priv->needs_damage_all = FALSE;
1239 
1240   update_area (self, 0, 0, cogl_texture_get_width (texture), cogl_texture_get_height (texture));
1241   priv->repaint_scheduled = meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
1242                                    0, 0,
1243                                    cogl_texture_get_width (texture),
1244                                    cogl_texture_get_height (texture),
1245                                    clutter_actor_has_mapped_clones (priv->actor) ? NULL : priv->unobscured_region);
1246 }
1247 
1248 static void
meta_window_actor_thaw(MetaWindowActor * self)1249 meta_window_actor_thaw (MetaWindowActor *self)
1250 {
1251   self->priv->freeze_count--;
1252 
1253   if (G_UNLIKELY (self->priv->freeze_count < 0))
1254     {
1255       g_warning ("Error in freeze/thaw accounting.");
1256       self->priv->freeze_count = 0;
1257       return;
1258     }
1259 
1260   if (self->priv->freeze_count)
1261     return;
1262 
1263   /* We sometimes ignore moves and resizes on frozen windows */
1264   meta_window_actor_sync_actor_geometry (self, FALSE);
1265 
1266   /* We do this now since we might be going right back into the
1267    * frozen state */
1268   meta_window_actor_handle_updates (self);
1269 
1270   /* Since we ignore damage events while a window is frozen for certain effects
1271    * we may need to issue an update_area() covering the whole pixmap if we
1272    * don't know what real damage has happened. */
1273   if (self->priv->needs_damage_all)
1274     meta_window_actor_damage_all (self);
1275 }
1276 
1277 void
meta_window_actor_queue_frame_drawn(MetaWindowActor * self,gboolean no_delay_frame)1278 meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
1279                                      gboolean         no_delay_frame)
1280 {
1281   MetaWindowActorPrivate *priv = self->priv;
1282   FrameData *frame;
1283 
1284   if (meta_window_actor_is_destroyed (self))
1285     return;
1286 
1287   frame = g_slice_new0 (FrameData);
1288   frame->frame_counter = -1;
1289 
1290   priv->needs_frame_drawn = TRUE;
1291 
1292 #ifdef HAVE_XSYNC
1293   frame->sync_request_serial = priv->window->sync_request_serial;
1294 #else
1295   frame->sync_request_serial = 0;
1296 #endif
1297 
1298   priv->frames = g_list_prepend (priv->frames, frame);
1299 
1300   if (no_delay_frame)
1301     {
1302       ClutterActor *stage = priv->window->display->compositor->stage;
1303       clutter_stage_skip_sync_delay (CLUTTER_STAGE (stage));
1304     }
1305 
1306   if (!priv->repaint_scheduled)
1307     {
1308       gboolean is_obscured = FALSE;
1309        /* Find out whether the window is completly obscured */
1310       if (priv->unobscured_region)
1311         {
1312           cairo_region_t *unobscured_window_region;
1313           unobscured_window_region = cairo_region_copy (priv->shape_region);
1314           cairo_region_intersect (unobscured_window_region, priv->unobscured_region);
1315           is_obscured = cairo_region_is_empty (unobscured_window_region);
1316           cairo_region_destroy (unobscured_window_region);
1317         }
1318 
1319       /* A frame was marked by the client without actually doing any
1320        * damage, or while we had the window frozen (e.g. during an
1321        * interactive resize.) We need to make sure that the
1322        * pre_paint/post_paint functions get called, enabling us to
1323        * send a _NET_WM_FRAME_DRAWN. We do a 1-pixel redraw to get
1324        * consistent timing with non-empty frames.
1325        */
1326       if (is_obscured)
1327         {
1328           queue_send_frame_messages_timeout (self);
1329         }
1330       else if (priv->window->mapped && !priv->needs_pixmap)
1331         {
1332           const cairo_rectangle_int_t clip = { 0, 0, 1, 1 };
1333           clutter_actor_queue_redraw_with_clip (priv->actor, &clip);
1334           priv->repaint_scheduled = TRUE;
1335         }
1336     }
1337 }
1338 
1339 LOCAL_SYMBOL gboolean
meta_window_actor_effect_in_progress(MetaWindowActor * self)1340 meta_window_actor_effect_in_progress (MetaWindowActor *self)
1341 {
1342   return (self->priv->minimize_in_progress ||
1343 	  self->priv->maximize_in_progress ||
1344 	  self->priv->unmaximize_in_progress ||
1345 	  self->priv->map_in_progress ||
1346       self->priv->tile_in_progress ||
1347 	  self->priv->destroy_in_progress);
1348 }
1349 
1350 static gboolean
is_frozen(MetaWindowActor * self)1351 is_frozen (MetaWindowActor *self)
1352 {
1353   return self->priv->freeze_count ? TRUE : FALSE;
1354 }
1355 
1356 static gboolean
is_freeze_thaw_effect(gulong event)1357 is_freeze_thaw_effect (gulong event)
1358 {
1359   switch (event)
1360   {
1361   case META_PLUGIN_DESTROY:
1362   case META_PLUGIN_MAXIMIZE:
1363   case META_PLUGIN_UNMAXIMIZE:
1364   case META_PLUGIN_TILE:
1365     return TRUE;
1366     break;
1367   default:
1368     return FALSE;
1369   }
1370 }
1371 
1372 static gboolean
start_simple_effect(MetaWindowActor * self,gulong event)1373 start_simple_effect (MetaWindowActor *self,
1374                      gulong        event)
1375 {
1376   MetaWindowActorPrivate *priv = self->priv;
1377   MetaCompositor *compositor = priv->screen->display->compositor;
1378   gint *counter = NULL;
1379   gboolean use_freeze_thaw = FALSE;
1380 
1381   if (!compositor->plugin_mgr)
1382     return FALSE;
1383 
1384   switch (event)
1385   {
1386   case META_PLUGIN_MINIMIZE:
1387     counter = &priv->minimize_in_progress;
1388     break;
1389   case META_PLUGIN_MAP:
1390     counter = &priv->map_in_progress;
1391     break;
1392   case META_PLUGIN_DESTROY:
1393     counter = &priv->destroy_in_progress;
1394     break;
1395   case META_PLUGIN_UNMAXIMIZE:
1396   case META_PLUGIN_MAXIMIZE:
1397   case META_PLUGIN_SWITCH_WORKSPACE:
1398   case META_PLUGIN_TILE:
1399     g_assert_not_reached ();
1400     break;
1401   }
1402 
1403   g_assert (counter);
1404 
1405   use_freeze_thaw = is_freeze_thaw_effect (event);
1406 
1407   if (use_freeze_thaw)
1408     meta_window_actor_freeze (self);
1409 
1410   (*counter)++;
1411 
1412   if (!meta_plugin_manager_event_simple (compositor->plugin_mgr,
1413                                          self,
1414                                          event))
1415     {
1416       (*counter)--;
1417       if (use_freeze_thaw)
1418         meta_window_actor_thaw (self);
1419       return FALSE;
1420     }
1421 
1422   return TRUE;
1423 }
1424 
1425 static void
meta_window_actor_after_effects(MetaWindowActor * self)1426 meta_window_actor_after_effects (MetaWindowActor *self)
1427 {
1428   MetaWindowActorPrivate *priv = self->priv;
1429 
1430   if (priv->needs_destroy)
1431     {
1432       clutter_actor_destroy (CLUTTER_ACTOR (self));
1433       return;
1434     }
1435 
1436   meta_window_actor_sync_visibility (self);
1437   meta_window_actor_sync_actor_geometry (self, FALSE);
1438 
1439   if (priv->needs_pixmap)
1440     clutter_actor_queue_redraw (priv->actor);
1441 }
1442 
1443 LOCAL_SYMBOL void
meta_window_actor_effect_completed(MetaWindowActor * self,gulong event)1444 meta_window_actor_effect_completed (MetaWindowActor *self,
1445                                     gulong           event)
1446 {
1447   MetaWindowActorPrivate *priv   = self->priv;
1448 
1449   /* NB: Keep in mind that when effects get completed it possible
1450    * that the corresponding MetaWindow may have be been destroyed.
1451    * In this case priv->window will == NULL */
1452 
1453   switch (event)
1454   {
1455   case META_PLUGIN_MINIMIZE:
1456     {
1457       priv->minimize_in_progress--;
1458       if (priv->minimize_in_progress < 0)
1459 	{
1460 	  g_warning ("Error in minimize accounting.");
1461 	  priv->minimize_in_progress = 0;
1462 	}
1463     }
1464     break;
1465   case META_PLUGIN_MAP:
1466     /*
1467      * Make sure that the actor is at the correct place in case
1468      * the plugin fscked.
1469      */
1470     priv->map_in_progress--;
1471     priv->position_changed = TRUE;
1472     if (priv->map_in_progress < 0)
1473       {
1474 	g_warning ("Error in map accounting.");
1475 	priv->map_in_progress = 0;
1476       }
1477     break;
1478   case META_PLUGIN_DESTROY:
1479     priv->destroy_in_progress--;
1480 
1481     if (priv->destroy_in_progress < 0)
1482       {
1483 	g_warning ("Error in destroy accounting.");
1484 	priv->destroy_in_progress = 0;
1485       }
1486     break;
1487   case META_PLUGIN_UNMAXIMIZE:
1488     priv->unmaximize_in_progress--;
1489     if (priv->unmaximize_in_progress < 0)
1490       {
1491 	g_warning ("Error in unmaximize accounting.");
1492 	priv->unmaximize_in_progress = 0;
1493       }
1494     break;
1495   case META_PLUGIN_MAXIMIZE:
1496     priv->maximize_in_progress--;
1497     if (priv->maximize_in_progress < 0)
1498       {
1499 	g_warning ("Error in maximize accounting.");
1500 	priv->maximize_in_progress = 0;
1501       }
1502     break;
1503   case META_PLUGIN_TILE:
1504     priv->tile_in_progress--;
1505     if (priv->tile_in_progress < 0)
1506       {
1507     g_warning ("Error in tile accounting.");
1508     priv->tile_in_progress = 0;
1509       }
1510     break;
1511   case META_PLUGIN_SWITCH_WORKSPACE:
1512     g_assert_not_reached ();
1513     break;
1514   }
1515 
1516   if (is_freeze_thaw_effect (event))
1517     meta_window_actor_thaw (self);
1518 
1519   if (!meta_window_actor_effect_in_progress (self))
1520     meta_window_actor_after_effects (self);
1521 }
1522 
1523 /* Called to drop our reference to a window backing pixmap that we
1524  * previously obtained with XCompositeNameWindowPixmap. We do this
1525  * when the window is unmapped or when we want to update to a new
1526  * pixmap for a new size.
1527  */
1528 static void
meta_window_actor_detach(MetaWindowActor * self)1529 meta_window_actor_detach (MetaWindowActor *self)
1530 {
1531   MetaWindowActorPrivate *priv     = self->priv;
1532   MetaScreen            *screen   = priv->screen;
1533   MetaDisplay           *display  = meta_screen_get_display (screen);
1534   Display               *xdisplay = meta_display_get_xdisplay (display);
1535 
1536   if (!priv->back_pixmap)
1537     return;
1538 
1539   /* Get rid of all references to the pixmap before freeing it; it's unclear whether
1540    * you are supposed to be able to free a GLXPixmap after freeing the underlying
1541    * pixmap, but it certainly doesn't work with current DRI/Mesa
1542    */
1543   meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), NULL);
1544 
1545   cogl_flush();
1546 
1547   XFreePixmap (xdisplay, priv->back_pixmap);
1548   priv->back_pixmap = None;
1549 
1550   priv->needs_pixmap = TRUE;
1551 }
1552 
1553 LOCAL_SYMBOL gboolean
meta_window_actor_should_unredirect(MetaWindowActor * self)1554 meta_window_actor_should_unredirect (MetaWindowActor *self)
1555 {
1556   MetaWindow *metaWindow = meta_window_actor_get_meta_window (self);
1557   MetaWindowActorPrivate *priv = self->priv;
1558 
1559   if (meta_window_actor_is_destroyed (self))
1560     return FALSE;
1561 
1562   if (meta_window_requested_dont_bypass_compositor (metaWindow))
1563     return FALSE;
1564 
1565   if (priv->opacity != 0xff)
1566     return FALSE;
1567 
1568   if (metaWindow->has_shape)
1569     return FALSE;
1570 
1571   if (priv->argb32 && !meta_window_requested_bypass_compositor (metaWindow))
1572     return FALSE;
1573 
1574   if (!meta_window_is_monitor_sized (metaWindow))
1575     return FALSE;
1576 
1577   if (meta_window_requested_bypass_compositor (metaWindow))
1578     return TRUE;
1579 
1580   if (meta_window_is_override_redirect (metaWindow))
1581     return TRUE;
1582 
1583   if (priv->does_full_damage && meta_prefs_get_unredirect_fullscreen_windows ())
1584     return TRUE;
1585 
1586   return FALSE;
1587 }
1588 
1589 LOCAL_SYMBOL void
meta_window_actor_set_redirected(MetaWindowActor * self,gboolean state)1590 meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state)
1591 {
1592   MetaWindowActorPrivate *priv = self->priv;
1593   MetaWindow *metaWindow = priv->window;
1594   MetaDisplay *display = metaWindow->display;
1595 
1596   Display *xdisplay = meta_display_get_xdisplay (display);
1597   Window  xwin = meta_window_actor_get_x_window (self);
1598 
1599   if (priv->unredirected != state)
1600     return;
1601 
1602   meta_error_trap_push (display);
1603 
1604   if (state)
1605     {
1606       XCompositeRedirectWindow (xdisplay, xwin, CompositeRedirectManual);
1607       meta_window_actor_detach (self);
1608       priv->unredirected = FALSE;
1609     }
1610   else
1611     {
1612       XCompositeUnredirectWindow (xdisplay, xwin, CompositeRedirectManual);
1613       priv->repaint_scheduled = TRUE;
1614       priv->unredirected = TRUE;
1615     }
1616 
1617   meta_error_trap_pop (display);
1618 }
1619 
1620 LOCAL_SYMBOL void
meta_window_actor_destroy(MetaWindowActor * self)1621 meta_window_actor_destroy (MetaWindowActor *self)
1622 {
1623   MetaWindow *window;
1624   MetaWindowActorPrivate *priv = self->priv;
1625   MetaWindowType window_type;
1626 
1627   window = priv->window;
1628   window_type = meta_window_get_window_type (window);
1629   meta_window_set_compositor_private (window, NULL);
1630 
1631   if (priv->send_frame_messages_timer != 0)
1632     {
1633       g_source_remove (priv->send_frame_messages_timer);
1634       priv->send_frame_messages_timer = 0;
1635     }
1636 
1637   if (window_type == META_WINDOW_DROPDOWN_MENU ||
1638       window_type == META_WINDOW_POPUP_MENU ||
1639       window_type == META_WINDOW_TOOLTIP ||
1640       window_type == META_WINDOW_NOTIFICATION ||
1641       window_type == META_WINDOW_COMBO ||
1642       window_type == META_WINDOW_DND ||
1643       window_type == META_WINDOW_OVERRIDE_OTHER)
1644     {
1645       /*
1646        * No effects, just kill it.
1647        */
1648       clutter_actor_destroy (CLUTTER_ACTOR (self));
1649       return;
1650     }
1651 
1652   priv->needs_destroy = TRUE;
1653 
1654   if (!meta_window_actor_effect_in_progress (self))
1655     clutter_actor_destroy (CLUTTER_ACTOR (self));
1656 }
1657 
1658 LOCAL_SYMBOL void
meta_window_actor_sync_actor_geometry(MetaWindowActor * self,gboolean did_placement)1659 meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
1660                                        gboolean         did_placement)
1661 {
1662   MetaWindowActorPrivate *priv = self->priv;
1663   MetaRectangle window_rect;
1664 
1665   meta_window_get_input_rect (priv->window, &window_rect);
1666 
1667   if (priv->last_width != window_rect.width ||
1668       priv->last_height != window_rect.height)
1669     {
1670       priv->size_changed = TRUE;
1671       priv->last_width = window_rect.width;
1672       priv->last_height = window_rect.height;
1673     }
1674 
1675   if (priv->last_x != window_rect.x ||
1676       priv->last_y != window_rect.y)
1677     {
1678       priv->position_changed = TRUE;
1679       priv->last_x = window_rect.x;
1680       priv->last_y = window_rect.y;
1681     }
1682 
1683   /* Normally we want freezing a window to also freeze its position; this allows
1684    * windows to atomically move and resize together, either under app control,
1685    * or because the user is resizing from the left/top. But on initial placement
1686    * we need to assign a position, since immediately after the window
1687    * is shown, the map effect will go into effect and prevent further geometry
1688    * updates.
1689    */
1690   if (is_frozen (self) && !did_placement)
1691     return;
1692 
1693   if (meta_window_actor_effect_in_progress (self))
1694     return;
1695 
1696   if (priv->size_changed)
1697     {
1698       priv->needs_pixmap = TRUE;
1699       meta_window_actor_update_shape (self);
1700 
1701       clutter_actor_set_size (CLUTTER_ACTOR (self),
1702                               window_rect.width, window_rect.height);
1703     }
1704 
1705   if (priv->position_changed)
1706     {
1707       clutter_actor_set_position (CLUTTER_ACTOR (self),
1708                                   window_rect.x, window_rect.y);
1709     }
1710 }
1711 
1712 void
meta_window_actor_show(MetaWindowActor * self,MetaCompEffect effect)1713 meta_window_actor_show (MetaWindowActor   *self,
1714                         MetaCompEffect     effect)
1715 {
1716   MetaWindowActorPrivate *priv = self->priv;
1717   gulong event;
1718 
1719   g_return_if_fail (!priv->visible);
1720 
1721   priv->visible = TRUE;
1722 
1723   event = 0;
1724   switch (effect)
1725     {
1726     case META_COMP_EFFECT_CREATE:
1727       event = META_PLUGIN_MAP;
1728       break;
1729     case META_COMP_EFFECT_UNMINIMIZE:
1730       /* FIXME: should have META_PLUGIN_UNMINIMIZE */
1731       event = META_PLUGIN_MAP;
1732       break;
1733     case META_COMP_EFFECT_NONE:
1734       break;
1735     case META_COMP_EFFECT_DESTROY:
1736     case META_COMP_EFFECT_MINIMIZE:
1737       g_assert_not_reached();
1738     }
1739 
1740   if (priv->redecorating ||
1741       priv->screen->display->compositor->switch_workspace_in_progress ||
1742       event == 0 ||
1743       !meta_prefs_get_desktop_effects () ||
1744       !start_simple_effect (self, event))
1745     {
1746       clutter_actor_show (CLUTTER_ACTOR (self));
1747       priv->redecorating = FALSE;
1748     }
1749 }
1750 
1751 LOCAL_SYMBOL void
meta_window_actor_hide(MetaWindowActor * self,MetaCompEffect effect)1752 meta_window_actor_hide (MetaWindowActor *self,
1753                         MetaCompEffect   effect)
1754 {
1755   MetaWindowActorPrivate *priv = self->priv;
1756   MetaCompositor *compositor = priv->screen->display->compositor;
1757   gulong event;
1758 
1759   g_return_if_fail (priv->visible || (!priv->visible && meta_window_is_attached_dialog (priv->window)));
1760 
1761   priv->visible = FALSE;
1762 
1763   /* If a plugin is animating a workspace transition, we have to
1764    * hold off on hiding the window, and do it after the workspace
1765    * switch completes
1766    */
1767   if (compositor->switch_workspace_in_progress)
1768     return;
1769 
1770   event = 0;
1771   switch (effect)
1772     {
1773     case META_COMP_EFFECT_DESTROY:
1774       event = META_PLUGIN_DESTROY;
1775       break;
1776     case META_COMP_EFFECT_MINIMIZE:
1777       event = META_PLUGIN_MINIMIZE;
1778       break;
1779     case META_COMP_EFFECT_NONE:
1780       break;
1781     case META_COMP_EFFECT_UNMINIMIZE:
1782     case META_COMP_EFFECT_CREATE:
1783       g_assert_not_reached();
1784     }
1785 
1786   if (event == 0 ||
1787       !meta_prefs_get_desktop_effects () ||
1788       !start_simple_effect (self, event))
1789     clutter_actor_hide (CLUTTER_ACTOR (self));
1790 }
1791 
1792 LOCAL_SYMBOL void
meta_window_actor_maximize(MetaWindowActor * self,MetaRectangle * old_rect,MetaRectangle * new_rect)1793 meta_window_actor_maximize (MetaWindowActor    *self,
1794                             MetaRectangle      *old_rect,
1795                             MetaRectangle      *new_rect)
1796 {
1797   MetaCompositor *compositor = self->priv->screen->display->compositor;
1798   /* The window has already been resized (in order to compute new_rect),
1799    * which by side effect caused the actor to be resized. Restore it to the
1800    * old size and position */
1801   clutter_actor_set_position (CLUTTER_ACTOR (self), old_rect->x, old_rect->y);
1802   clutter_actor_set_size (CLUTTER_ACTOR (self), old_rect->width, old_rect->height);
1803 
1804   self->priv->maximize_in_progress++;
1805   meta_window_actor_freeze (self);
1806 
1807   if (!compositor->plugin_mgr ||
1808       !meta_plugin_manager_event_maximize (compositor->plugin_mgr,
1809                                            self,
1810                                            META_PLUGIN_MAXIMIZE,
1811                                            new_rect->x, new_rect->y,
1812                                            new_rect->width, new_rect->height))
1813 
1814     {
1815       self->priv->maximize_in_progress--;
1816       meta_window_actor_thaw (self);
1817     }
1818 }
1819 
1820 LOCAL_SYMBOL void
meta_window_actor_unmaximize(MetaWindowActor * self,MetaRectangle * old_rect,MetaRectangle * new_rect)1821 meta_window_actor_unmaximize (MetaWindowActor   *self,
1822                               MetaRectangle     *old_rect,
1823                               MetaRectangle     *new_rect)
1824 {
1825   MetaCompositor *compositor = self->priv->screen->display->compositor;
1826 
1827   /* The window has already been resized (in order to compute new_rect),
1828    * which by side effect caused the actor to be resized. Restore it to the
1829    * old size and position */
1830   clutter_actor_set_position (CLUTTER_ACTOR (self), old_rect->x, old_rect->y);
1831   clutter_actor_set_size (CLUTTER_ACTOR (self), old_rect->width, old_rect->height);
1832 
1833   self->priv->unmaximize_in_progress++;
1834   meta_window_actor_freeze (self);
1835 
1836   if (!compositor->plugin_mgr ||
1837       !meta_plugin_manager_event_maximize (compositor->plugin_mgr,
1838                                            self,
1839                                            META_PLUGIN_UNMAXIMIZE,
1840                                            new_rect->x, new_rect->y,
1841                                            new_rect->width, new_rect->height))
1842     {
1843       self->priv->unmaximize_in_progress--;
1844       meta_window_actor_thaw (self);
1845     }
1846 }
1847 
1848 LOCAL_SYMBOL void
meta_window_actor_tile(MetaWindowActor * self,MetaRectangle * old_rect,MetaRectangle * new_rect)1849 meta_window_actor_tile (MetaWindowActor    *self,
1850                         MetaRectangle      *old_rect,
1851                         MetaRectangle      *new_rect)
1852 {
1853   MetaCompositor *compositor = self->priv->screen->display->compositor;
1854 
1855   /* The window has already been resized (in order to compute new_rect),
1856    * which by side effect caused the actor to be resized. Restore it to the
1857    * old size and position */
1858   clutter_actor_set_position (CLUTTER_ACTOR (self), old_rect->x, old_rect->y);
1859   clutter_actor_set_size (CLUTTER_ACTOR (self), old_rect->width, old_rect->height);
1860 
1861   self->priv->tile_in_progress++;
1862   meta_window_actor_freeze (self);
1863 
1864   if (!compositor->plugin_mgr ||
1865       !meta_plugin_manager_event_maximize (compositor->plugin_mgr,
1866                                            self,
1867                                            META_PLUGIN_TILE,
1868                                            new_rect->x, new_rect->y,
1869                                            new_rect->width, new_rect->height))
1870 
1871     {
1872       self->priv->tile_in_progress--;
1873       meta_window_actor_thaw (self);
1874     }
1875 }
1876 
1877 static void
ensure_tooltip_visible(MetaWindow * window)1878 ensure_tooltip_visible (MetaWindow *window)
1879 {
1880   const MetaMonitorInfo *wmonitor;
1881   MetaRectangle work_area, win_rect;
1882   gint new_x, new_y;
1883 
1884   /* Why this is here:
1885    * As of gtk 3.24, tooltips for GtkStatusIcons began displaying their tool tip
1886    * off the screen in certain situations.
1887    *
1888    * See: https://github.com/GNOME/gtk/commit/14d22cb3233e
1889    *
1890    * If the status icon is too small relative to its panel (which has been assigned
1891    * as a strut to muffin), tooltip positioning fails both tests in gdkwindowimpl.c
1892    * (maybe_flip_position()) skipping repositioning of the tooltip inside the workarea.
1893    * This only occurs on bottom panels, and only begins happening when the status icon
1894    * becomes 10px or more smaller than the panel it's *centered* on.
1895    *
1896    * Since the calculations are based upon the monitor's workarea and the status icon
1897    * plug window's size, there's no way to compensate for or fool gtk into displaying it
1898    * correctly.  So here, we do our own check and adjustment if a part of the tooltip
1899    * window falls outside the current monitor's work area.  This is also useful since
1900    * muffin knows *exactly* the work area for each monitor, whereas gtk only has
1901    * _NET_WORKAREA to go by, which only keeps track of (primary monitor * n_workspaces),
1902    * so an odd monitor layout would trip this up anyhow.
1903    *
1904    * This may cause regressions - see: https://github.com/linuxmint/muffin/commit/050038690,
1905    * but without being able to reproduce the issue mentioned there, we'll just have to address
1906    * it if it appears again as a result of this change. */
1907 
1908   wmonitor = meta_screen_get_monitor_for_window (window->screen, window);
1909 
1910   meta_workspace_get_work_area_for_monitor (meta_screen_get_active_workspace (window->screen),
1911                                             wmonitor->number,
1912                                             &work_area);
1913 
1914   meta_window_get_outer_rect (window, &win_rect);
1915 
1916   new_x = win_rect.x;
1917   new_y = win_rect.y;
1918 
1919   if (win_rect.y < work_area.y)
1920     {
1921       new_y = work_area.y;
1922     }
1923   else if (win_rect.y + win_rect.height > work_area.y + work_area.height)
1924     {
1925       new_y = (work_area.y + work_area.height - win_rect.height);
1926     }
1927 
1928   if (win_rect.x < work_area.x)
1929     {
1930       new_x = work_area.x;
1931     }
1932   else if (win_rect.x + win_rect.width > work_area.x + work_area.width)
1933     {
1934       new_x = (work_area.x + work_area.width - win_rect.width);
1935     }
1936 
1937   if (new_x != win_rect.x || new_y != win_rect.y)
1938     {
1939       meta_window_move(window, FALSE, new_x, new_y);
1940     }
1941 }
1942 
1943 LOCAL_SYMBOL MetaWindowActor *
meta_window_actor_new(MetaWindow * window)1944 meta_window_actor_new (MetaWindow *window)
1945 {
1946   MetaScreen *screen = window->screen;
1947   MetaCompositor *compositor = screen->display->compositor;
1948   MetaWindowActor *self;
1949   MetaWindowActorPrivate *priv;
1950   MetaFrame		 *frame;
1951   Window		  top_window;
1952   ClutterActor           *window_group;
1953 
1954   frame = meta_window_get_frame (window);
1955   if (frame)
1956     top_window = meta_frame_get_xwindow (frame);
1957   else
1958     top_window = meta_window_get_xwindow (window);
1959 
1960   meta_verbose ("add window: Meta %p, xwin 0x%x\n", window, (guint)top_window);
1961 
1962   self = g_object_new (META_TYPE_WINDOW_ACTOR,
1963                        "meta-window",         window,
1964                        "x-window",            top_window,
1965                        "meta-screen",         screen,
1966                        NULL);
1967 
1968   priv = self->priv;
1969 
1970   priv->last_width = -1;
1971   priv->last_height = -1;
1972   priv->last_x = -1;
1973   priv->last_y = -1;
1974 
1975   priv->needs_pixmap = TRUE;
1976 
1977   meta_window_actor_set_updates_frozen (self,
1978                                         meta_window_updates_are_frozen (priv->window));
1979 
1980   /* If a window doesn't start off with updates frozen, we should
1981    * we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn.
1982    */
1983   if (priv->window->extended_sync_request_counter && !priv->updates_frozen)
1984     meta_window_actor_queue_frame_drawn (self, FALSE);
1985 
1986   meta_window_actor_sync_actor_geometry (self, priv->window->placed);
1987 
1988   /* Hang our compositor window state off the MetaWindow for fast retrieval */
1989   meta_window_set_compositor_private (window, G_OBJECT (self));
1990 
1991   if (window->type == META_WINDOW_DND)
1992     window_group = compositor->window_group;
1993   else if (window->layer == META_LAYER_OVERRIDE_REDIRECT)
1994     {
1995       if (window->type == META_WINDOW_TOOLTIP)
1996         {
1997           ensure_tooltip_visible (window);
1998         }
1999 
2000       window_group = compositor->top_window_group;
2001     }
2002   else if (window->type == META_WINDOW_DESKTOP)
2003     window_group = compositor->bottom_window_group;
2004   else
2005     window_group = compositor->window_group;
2006 
2007   clutter_actor_add_child (window_group, CLUTTER_ACTOR (self));
2008 
2009   clutter_actor_hide (CLUTTER_ACTOR (self));
2010 
2011   /* Initial position in the stack is arbitrary; stacking will be synced
2012    * before we first paint.
2013    */
2014   compositor->windows = g_list_append (compositor->windows, self);
2015 
2016   return self;
2017 }
2018 
2019 static void
meta_window_actor_update_shape_region(MetaWindowActor * self,cairo_region_t * region)2020 meta_window_actor_update_shape_region (MetaWindowActor *self,
2021                                        cairo_region_t  *region)
2022 {
2023   MetaWindowActorPrivate *priv = self->priv;
2024 
2025   g_clear_pointer (&priv->shape_region, cairo_region_destroy);
2026 
2027   /* region must be non-null */
2028   priv->shape_region = region;
2029   cairo_region_reference (region);
2030 }
2031 
2032 /**
2033  * meta_window_actor_get_obscured_region:
2034  * @self: a #MetaWindowActor
2035  *
2036  * Gets the region that is completely obscured by the window. Coordinates
2037  * are relative to the upper-left of the window.
2038  *
2039  * Return value: (transfer none): the area obscured by the window,
2040  *  %NULL is the same as an empty region.
2041  */
2042 LOCAL_SYMBOL cairo_region_t *
meta_window_actor_get_obscured_region(MetaWindowActor * self)2043 meta_window_actor_get_obscured_region (MetaWindowActor *self)
2044 {
2045   MetaWindowActorPrivate *priv = self->priv;
2046 
2047   if (priv->back_pixmap && priv->opacity == 0xff)
2048     return priv->opaque_region;
2049   else
2050     return NULL;
2051 }
2052 
2053 #if 0
2054 /* Print out a region; useful for debugging */
2055 static void
2056 dump_region (cairo_region_t *region)
2057 {
2058   int n_rects;
2059   int i;
2060 
2061   n_rects = cairo_region_num_rectangles (region);
2062   g_print ("[");
2063   for (i = 0; i < n_rects; i++)
2064     {
2065       cairo_rectangle_int_t rect;
2066       cairo_region_get_rectangle (region, i, &rect);
2067       g_print ("+%d+%dx%dx%d ",
2068                rect.x, rect.y, rect.width, rect.height);
2069     }
2070   g_print ("]\n");
2071 }
2072 #endif
2073 
2074 /**
2075  * meta_window_actor_set_unobscured_region:
2076  * @self: a #MetaWindowActor
2077  * @unobscured_region: the region of the screen that isn't completely
2078  *  obscured.
2079  *
2080  * Provides a hint as to what areas of the window need to queue
2081  * redraws when damaged. Regions not in @unobscured_region are completely obscured.
2082  * Unlike meta_window_actor_set_clip_region(), the region here
2083  * doesn't take into account any clipping that is in effect while drawing.
2084  */
2085 void
meta_window_actor_set_unobscured_region(MetaWindowActor * self,cairo_region_t * unobscured_region)2086 meta_window_actor_set_unobscured_region (MetaWindowActor *self,
2087                                          cairo_region_t  *unobscured_region)
2088 {
2089   MetaWindowActorPrivate *priv = self->priv;
2090 
2091   if (priv->unobscured_region)
2092     cairo_region_destroy (priv->unobscured_region);
2093 
2094   if (unobscured_region)
2095     priv->unobscured_region = cairo_region_copy (unobscured_region);
2096   else
2097     priv->unobscured_region = NULL;
2098 }
2099 
2100 /**
2101  * meta_window_actor_set_visible_region:
2102  * @self: a #MetaWindowActor
2103  * @visible_region: the region of the screen that isn't completely
2104  *  obscured.
2105  *
2106  * Provides a hint as to what areas of the window need to be
2107  * drawn. Regions not in @visible_region are completely obscured.
2108  * This will be set before painting then unset afterwards.
2109  */
2110 LOCAL_SYMBOL void
meta_window_actor_set_visible_region(MetaWindowActor * self,cairo_region_t * visible_region)2111 meta_window_actor_set_visible_region (MetaWindowActor *self,
2112                                       cairo_region_t  *visible_region)
2113 {
2114   MetaWindowActorPrivate *priv = self->priv;
2115 
2116   meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor),
2117                                        visible_region);
2118 }
2119 
2120 /**
2121  * meta_window_actor_set_visible_region_beneath:
2122  * @self: a #MetaWindowActor
2123  * @visible_region: the region of the screen that isn't completely
2124  *  obscured beneath the main window texture.
2125  *
2126  * Provides a hint as to what areas need to be drawn *beneath*
2127  * the main window texture.  This is the relevant visible region
2128  * when drawing the shadow, properly accounting for areas of the
2129  * shadow hid by the window itself. This will be set before painting
2130  * then unset afterwards.
2131  */
2132 LOCAL_SYMBOL void
meta_window_actor_set_visible_region_beneath(MetaWindowActor * self,cairo_region_t * beneath_region)2133 meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
2134                                               cairo_region_t  *beneath_region)
2135 {
2136   MetaWindowActorPrivate *priv = self->priv;
2137   gboolean appears_focused = meta_window_appears_focused (priv->window);
2138 
2139   if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow)
2140     {
2141       g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
2142       priv->shadow_clip = cairo_region_copy (beneath_region);
2143 
2144       if (clip_shadow_under_window (self))
2145         cairo_region_subtract (priv->shadow_clip,
2146                                 meta_window_get_frame_bounds (priv->window));
2147     }
2148 }
2149 
2150 /**
2151  * meta_window_actor_reset_visible_regions:
2152  * @self: a #MetaWindowActor
2153  *
2154  * Unsets the regions set by meta_window_actor_reset_visible_region() and
2155  * meta_window_actor_reset_visible_region_beneath()
2156  */
2157 LOCAL_SYMBOL void
meta_window_actor_reset_visible_regions(MetaWindowActor * self)2158 meta_window_actor_reset_visible_regions (MetaWindowActor *self)
2159 {
2160   MetaWindowActorPrivate *priv = self->priv;
2161 
2162   meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor),
2163                                        NULL);
2164   g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
2165 }
2166 
2167 static void
check_needs_pixmap(MetaWindowActor * self)2168 check_needs_pixmap (MetaWindowActor *self)
2169 {
2170   MetaWindowActorPrivate *priv = self->priv;
2171   MetaScreen *screen = priv->screen;
2172   MetaDisplay *display = screen->display;
2173   Display *xdisplay = display->xdisplay;
2174   MetaCompositor *compositor = display->compositor;
2175   Window xwindow = priv->xwindow;
2176 
2177   if ((!priv->window->mapped && !priv->window->shaded) || !priv->needs_pixmap)
2178     return;
2179 
2180   if (xwindow == screen->xroot ||
2181       xwindow == clutter_x11_get_stage_window (compositor->stage))
2182     return;
2183 
2184   if (priv->size_changed)
2185     {
2186       meta_window_actor_detach (self);
2187       priv->size_changed = FALSE;
2188     }
2189 
2190   if (priv->position_changed)
2191     priv->position_changed = FALSE;
2192 
2193   meta_error_trap_push (display);
2194 
2195   if (priv->back_pixmap == None)
2196     {
2197       CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
2198       CoglTexture *texture;
2199 
2200       meta_error_trap_push (display);
2201 
2202       priv->back_pixmap = XCompositeNameWindowPixmap (xdisplay, xwindow);
2203 
2204       if (meta_error_trap_pop_with_return (display) != Success)
2205         {
2206           /* Probably a BadMatch if the window isn't viewable; we could
2207            * GrabServer/GetWindowAttributes/NameWindowPixmap/UngrabServer/Sync
2208            * to avoid this, but there's no reason to take two round trips
2209            * when one will do. (We need that Sync if we want to handle failures
2210            * for any reason other than !viewable. That's unlikely, but maybe
2211            * we'll BadAlloc or something.)
2212            */
2213           priv->back_pixmap = None;
2214         }
2215 
2216       if (priv->back_pixmap == None)
2217         {
2218           meta_verbose ("Unable to get named pixmap for %p\n", self);
2219           goto out;
2220         }
2221 
2222       if (compositor->no_mipmaps)
2223         meta_shaped_texture_set_create_mipmaps (META_SHAPED_TEXTURE (priv->actor),
2224                                                 FALSE);
2225 
2226       texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->back_pixmap, FALSE, NULL));
2227 
2228       /*
2229        * This only works *after* actually setting the pixmap, so we have to
2230        * do it here.
2231        * See: http://bugzilla.clutter-project.org/show_bug.cgi?id=2236
2232        */
2233       if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (texture)))
2234         g_warning ("NOTE: Not using GLX TFP!\n");
2235 
2236       meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), texture);
2237     }
2238 
2239   priv->needs_pixmap = FALSE;
2240 
2241  out:
2242   meta_error_trap_pop (display);
2243 }
2244 
2245 static void
check_needs_shadow(MetaWindowActor * self)2246 check_needs_shadow (MetaWindowActor *self)
2247 {
2248   if (!self->priv->window->display->shadows_enabled) {
2249       return;
2250   }
2251 
2252   MetaWindowActorPrivate *priv = self->priv;
2253   MetaShadow *old_shadow = NULL;
2254   MetaShadow **shadow_location;
2255   gboolean recompute_shadow;
2256   gboolean should_have_shadow;
2257   gboolean appears_focused;
2258 
2259   if (!priv->window->mapped && !priv->window->shaded)
2260     return;
2261 
2262   /* Calling meta_window_actor_has_shadow() here at every pre-paint is cheap
2263    * and avoids the need to explicitly handle window type changes, which
2264    * we would do if tried to keep track of when we might be adding or removing
2265    * a shadow more explicitly. We only keep track of changes to the *shape* of
2266    * the shadow with priv->recompute_shadow.
2267    */
2268 
2269   should_have_shadow = meta_window_actor_has_shadow (self);
2270   priv->should_have_shadow = should_have_shadow;
2271   appears_focused = meta_window_appears_focused (priv->window);
2272 
2273   if (appears_focused)
2274     {
2275       recompute_shadow = priv->recompute_focused_shadow;
2276       priv->recompute_focused_shadow = FALSE;
2277       shadow_location = &priv->focused_shadow;
2278     }
2279   else
2280     {
2281       recompute_shadow = priv->recompute_unfocused_shadow;
2282       priv->recompute_unfocused_shadow = FALSE;
2283       shadow_location = &priv->unfocused_shadow;
2284     }
2285 
2286   if (!should_have_shadow || recompute_shadow)
2287     {
2288       if (*shadow_location != NULL)
2289         {
2290           old_shadow = *shadow_location;
2291           *shadow_location = NULL;
2292         }
2293     }
2294 
2295   if (*shadow_location == NULL && should_have_shadow)
2296     {
2297       if (priv->shadow_shape == NULL)
2298         {
2299           if (priv->shape_region)
2300             priv->shadow_shape = meta_window_shape_new (priv->shape_region);
2301         }
2302 
2303       if (priv->shadow_shape != NULL)
2304         {
2305           MetaShadowFactory *factory = meta_shadow_factory_get_default ();
2306           const char *shadow_class = meta_window_actor_get_shadow_class (self);
2307           cairo_rectangle_int_t shape_bounds;
2308 
2309           meta_window_actor_get_shape_bounds (self, &shape_bounds);
2310           *shadow_location = meta_shadow_factory_get_shadow (factory,
2311                                                              priv->shadow_shape,
2312                                                              shape_bounds.width, shape_bounds.height,
2313                                                              shadow_class, appears_focused);
2314         }
2315     }
2316 
2317   if (old_shadow != NULL)
2318     meta_shadow_unref (old_shadow);
2319 }
2320 
2321 LOCAL_SYMBOL void
meta_window_actor_process_damage(MetaWindowActor * self,XDamageNotifyEvent * event)2322 meta_window_actor_process_damage (MetaWindowActor    *self,
2323                                   XDamageNotifyEvent *event)
2324 {
2325   MetaWindowActorPrivate *priv = self->priv;
2326   MetaCompositor *compositor = priv->window->display->compositor;
2327 
2328   priv->received_damage = TRUE;
2329 
2330   /* Drop damage event for unredirected windows */
2331   if (priv->unredirected)
2332     return;
2333 
2334   if (meta_window_is_fullscreen (priv->window) && g_list_last (compositor->windows)->data == self)
2335     {
2336       MetaRectangle window_rect;
2337       meta_window_get_outer_rect (priv->window, &window_rect);
2338 
2339       if (event->area.x == 0 &&
2340           event->area.y == 0 &&
2341           window_rect.width == event->area.width &&
2342           window_rect.height == event->area.height)
2343         priv->full_damage_frames_count++;
2344       else
2345         priv->full_damage_frames_count = 0;
2346 
2347       if (priv->full_damage_frames_count >= 100)
2348         priv->does_full_damage = TRUE;
2349     }
2350 
2351   if (priv->freeze_count)
2352     {
2353       /* The window is frozen due to an effect in progress: we ignore damage
2354        * here on the off chance that this will stop the corresponding
2355        * texture_from_pixmap from being update.
2356        *
2357        * needs_damage_all tracks that some unknown damage happened while the
2358        * window was frozen so that when the window becomes unfrozen we can
2359        * issue a full window update to cover any lost damage.
2360        *
2361        * It should be noted that this is an unreliable mechanism since it's
2362        * quite likely that drivers will aim to provide a zero-copy
2363        * implementation of the texture_from_pixmap extension and in those cases
2364        * any drawing done to the window is always immediately reflected in the
2365        * texture regardless of damage event handling.
2366        */
2367       priv->needs_damage_all = TRUE;
2368       return;
2369     }
2370 
2371   if (!priv->window->mapped || priv->needs_pixmap)
2372     return;
2373 
2374   update_area (self, event->area.x, event->area.y, event->area.width, event->area.height);
2375   priv->repaint_scheduled = meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
2376                                    event->area.x,
2377                                    event->area.y,
2378                                    event->area.width,
2379                                    event->area.height,
2380                                    clutter_actor_has_mapped_clones (priv->actor) ? NULL : priv->unobscured_region);
2381 }
2382 
2383 LOCAL_SYMBOL void
meta_window_actor_sync_visibility(MetaWindowActor * self)2384 meta_window_actor_sync_visibility (MetaWindowActor *self)
2385 {
2386   MetaWindowActorPrivate *priv = self->priv;
2387 
2388   if (CLUTTER_ACTOR_IS_VISIBLE (self) != priv->visible)
2389     {
2390       if (priv->visible)
2391         clutter_actor_show (CLUTTER_ACTOR (self));
2392       else
2393         clutter_actor_hide (CLUTTER_ACTOR (self));
2394     }
2395 }
2396 
2397 static inline void
set_integral_bounding_rect(cairo_rectangle_int_t * rect,double x,double y,double width,double height)2398 set_integral_bounding_rect (cairo_rectangle_int_t *rect,
2399                             double x, double y,
2400                             double width, double height)
2401 {
2402   rect->x = floor(x);
2403   rect->y = floor(y);
2404   rect->width = ceil(x + width) - rect->x;
2405   rect->height = ceil(y + height) - rect->y;
2406 }
2407 
2408 static void
update_corners(MetaWindowActor * self)2409 update_corners (MetaWindowActor   *self)
2410 {
2411   MetaWindowActorPrivate *priv = self->priv;
2412   MetaRectangle outer = priv->window->frame->rect;
2413   MetaFrameBorders borders;
2414   cairo_rectangle_int_t corner_rects[4];
2415   cairo_region_t *corner_region;
2416   cairo_path_t *corner_path;
2417   float top_left, top_right, bottom_left, bottom_right;
2418   float x, y;
2419 
2420   /* need these to build a path */
2421   cairo_t *cr;
2422   cairo_surface_t *surface;
2423 
2424   meta_frame_calc_borders (priv->window->frame, &borders);
2425 
2426   outer.width -= borders.invisible.left + borders.invisible.right;
2427   outer.height -= borders.invisible.top  + borders.invisible.bottom;
2428 
2429   meta_frame_get_corner_radiuses (priv->window->frame,
2430                                   &top_left,
2431                                   &top_right,
2432                                   &bottom_left,
2433                                   &bottom_right);
2434 
2435   /* Unfortunately, cairo does not allow us to create a context
2436    * without a surface. Create a 0x0 image surface to "paint to"
2437    * so we can get the path. */
2438   surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
2439                                         0, 0);
2440 
2441   cr = cairo_create (surface);
2442 
2443   /* top left */
2444   x = borders.invisible.left;
2445   y = borders.invisible.top;
2446 
2447   set_integral_bounding_rect (&corner_rects[0],
2448                               x, y, top_left, top_left);
2449 
2450   cairo_arc (cr,
2451              x + top_left,
2452              y + top_left,
2453              top_left,
2454              0, M_PI*2);
2455 
2456 
2457   /* top right */
2458   x = x + outer.width - top_right;
2459 
2460   set_integral_bounding_rect (&corner_rects[1],
2461                               x, y, top_right, top_right);
2462 
2463   cairo_arc (cr,
2464              x,
2465              y + top_right,
2466              top_right,
2467              0, M_PI*2);
2468 
2469   /* bottom right */
2470   x = borders.invisible.left + outer.width - bottom_right;
2471   y = y + outer.height - bottom_right;
2472 
2473   set_integral_bounding_rect (&corner_rects[2],
2474                               x, y, bottom_right, bottom_right);
2475 
2476   cairo_arc (cr,
2477              x,
2478              y,
2479              bottom_right,
2480              0, M_PI*2);
2481 
2482   /* bottom left */
2483   x = borders.invisible.left;
2484   y = borders.invisible.top + outer.height - bottom_left;
2485 
2486   set_integral_bounding_rect (&corner_rects[3],
2487                               x, y, bottom_left, bottom_left);
2488 
2489   cairo_arc (cr,
2490              x + bottom_left,
2491              y,
2492              bottom_left,
2493              0, M_PI*2);
2494 
2495   corner_path = cairo_copy_path (cr);
2496 
2497   cairo_surface_destroy (surface);
2498   cairo_destroy (cr);
2499 
2500   corner_region = cairo_region_create_rectangles (corner_rects, 4);
2501 
2502   meta_shaped_texture_set_overlay_path (META_SHAPED_TEXTURE (priv->actor),
2503                                         corner_region, corner_path);
2504 
2505 
2506   cairo_region_destroy (corner_region);
2507 }
2508 
2509 static void
check_needs_reshape(MetaWindowActor * self)2510 check_needs_reshape (MetaWindowActor *self)
2511 {
2512   MetaWindowActorPrivate *priv = self->priv;
2513   MetaScreen *screen = priv->screen;
2514   MetaDisplay *display = meta_screen_get_display (screen);
2515   cairo_region_t *region = NULL;
2516   cairo_rectangle_int_t client_area;
2517   gboolean full_mask_reset = priv->window->fullscreen;
2518 
2519   if ((!priv->window->mapped && !priv->window->shaded) || !priv->needs_reshape)
2520     return;
2521 
2522   g_clear_pointer (&priv->shape_region, cairo_region_destroy);
2523   g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref);
2524   g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
2525 
2526   meta_window_get_client_area_rect (priv->window, &client_area);
2527 
2528   if (priv->window->frame)
2529     region = meta_window_get_frame_bounds (priv->window);
2530 
2531   if (region != NULL)
2532     {
2533       /* This returns the window's internal frame bounds region,
2534        * so we need to copy it because we modify it below. */
2535       region = cairo_region_copy (region);
2536     }
2537   else
2538     {
2539       /* If we have no region, we have no frame. We have no frame,
2540        * so just use the client_area instead */
2541       region = cairo_region_create_rectangle (&client_area);
2542     }
2543 
2544 #ifdef HAVE_SHAPE
2545   if (priv->window->has_shape)
2546     {
2547       Display *xdisplay = meta_display_get_xdisplay (display);
2548       XRectangle *rects;
2549       int n_rects, ordering;
2550 
2551       /* Punch out client area. */
2552       cairo_region_subtract_rectangle (region, &client_area);
2553 
2554       meta_error_trap_push (display);
2555       rects = XShapeGetRectangles (xdisplay,
2556                                    priv->window->xwindow,
2557                                    ShapeBounding,
2558                                    &n_rects,
2559                                    &ordering);
2560       meta_error_trap_pop (display);
2561 
2562       if (rects)
2563         {
2564           int i;
2565           for (i = 0; i < n_rects; i ++)
2566             {
2567               cairo_rectangle_int_t rect = { rects[i].x + client_area.x,
2568                                              rects[i].y + client_area.y,
2569                                              rects[i].width,
2570                                              rects[i].height };
2571               cairo_region_union_rectangle (region, &rect);
2572             }
2573           XFree (rects);
2574         }
2575     }
2576 #endif
2577 
2578   if (priv->argb32 && priv->window->opaque_region != NULL)
2579     {
2580       /* The opaque region is defined to be a part of the
2581        * window which ARGB32 will always paint with opaque
2582        * pixels. For these regions, we want to avoid painting
2583        * windows and shadows beneath them.
2584        *
2585        * If the client gives bad coordinates where it does not
2586        * fully paint, the behavior is defined by the specification
2587        * to be undefined, and considered a client bug. In mutter's
2588        * case, graphical glitches will occur.
2589        */
2590       priv->opaque_region = cairo_region_copy (priv->window->opaque_region);
2591       cairo_region_translate (priv->opaque_region, client_area.x, client_area.y);
2592       cairo_region_intersect (priv->opaque_region, region);
2593     }
2594   else if (priv->argb32)
2595     priv->opaque_region = NULL;
2596   else
2597     priv->opaque_region = cairo_region_reference (region);
2598 
2599   if (priv->window->frame)
2600     update_corners (self);
2601   else if (priv->window->has_shape && priv->reshapes == 1)
2602     full_mask_reset = TRUE;
2603   else if (priv->reshapes < 2)
2604     priv->reshapes++;
2605 
2606   if (priv->window->frame != NULL || priv->window->has_shape)
2607     meta_window_actor_reset_mask_texture (self, region, full_mask_reset);
2608 
2609   meta_window_actor_update_shape_region (self, region);
2610 
2611   cairo_region_destroy (region);
2612 
2613   priv->needs_reshape = FALSE;
2614   meta_window_actor_invalidate_shadow (self);
2615 }
2616 
2617 LOCAL_SYMBOL void
meta_window_actor_update_shape(MetaWindowActor * self)2618 meta_window_actor_update_shape (MetaWindowActor *self)
2619 {
2620   MetaWindowActorPrivate *priv = self->priv;
2621 
2622   priv->needs_reshape = TRUE;
2623 
2624   if (is_frozen (self))
2625     return;
2626 
2627   clutter_actor_queue_redraw (priv->actor);
2628 }
2629 
2630 LOCAL_SYMBOL void
meta_window_actor_handle_updates(MetaWindowActor * self)2631 meta_window_actor_handle_updates (MetaWindowActor *self)
2632 {
2633   MetaWindowActorPrivate *priv = self->priv;
2634   MetaScreen          *screen   = priv->screen;
2635   MetaDisplay         *display  = meta_screen_get_display (screen);
2636   Display             *xdisplay = meta_display_get_xdisplay (display);
2637 
2638   if (is_frozen (self))
2639     {
2640       /* The window is frozen due to a pending animation: we'll wait until
2641        * the animation finishes to reshape and repair the window */
2642       return;
2643     }
2644 
2645   if (priv->unredirected)
2646     {
2647       /* Nothing to do here until/if the window gets redirected again */
2648       return;
2649     }
2650 
2651   if (!priv->visible && !priv->needs_pixmap)
2652     return;
2653 
2654   if (priv->received_damage)
2655     {
2656       meta_error_trap_push (display);
2657       XDamageSubtract (xdisplay, priv->damage, None, None);
2658       meta_error_trap_pop (display);
2659 
2660       priv->received_damage = FALSE;
2661     }
2662 
2663   check_needs_pixmap (self);
2664   check_needs_reshape (self);
2665   check_needs_shadow (self);
2666 }
2667 
2668 void
meta_window_actor_pre_paint(MetaWindowActor * self)2669 meta_window_actor_pre_paint (MetaWindowActor *self)
2670 {
2671   if (meta_window_actor_is_destroyed (self))
2672     return;
2673 
2674   meta_window_actor_handle_updates (self);
2675 
2676   assign_frame_counter_to_frames (self);
2677 }
2678 
2679 static void
do_send_frame_drawn(MetaWindowActor * self,FrameData * frame)2680 do_send_frame_drawn (MetaWindowActor *self, FrameData *frame)
2681 {
2682   MetaWindowActorPrivate *priv = self->priv;
2683   MetaDisplay *display = meta_screen_get_display (priv->screen);
2684   MetaWindow *window = meta_window_actor_get_meta_window (self);
2685   Display *xdisplay = meta_display_get_xdisplay (display);
2686 
2687   XClientMessageEvent ev = { 0, };
2688 
2689   frame->frame_drawn_time = meta_compositor_monotonic_time_to_server_time (display,
2690                                                                            g_get_monotonic_time ());
2691   priv->frame_drawn_time = frame->frame_drawn_time;
2692 
2693   ev.type = ClientMessage;
2694   ev.window = meta_window_get_xwindow (window);
2695   ev.message_type = display->atom__NET_WM_FRAME_DRAWN;
2696   ev.format = 32;
2697   ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT(0xffffffff);
2698   ev.data.l[1] = frame->sync_request_serial >> 32;
2699   ev.data.l[2] = frame->frame_drawn_time & G_GUINT64_CONSTANT(0xffffffff);
2700   ev.data.l[3] = frame->frame_drawn_time >> 32;
2701 
2702   meta_error_trap_push (display);
2703   XSendEvent (xdisplay, ev.window, False, 0, (XEvent*) &ev);
2704   XFlush (xdisplay);
2705   meta_error_trap_pop (display);
2706 }
2707 
2708 
2709 void
meta_window_actor_post_paint(MetaWindowActor * self)2710 meta_window_actor_post_paint (MetaWindowActor *self)
2711 {
2712   MetaWindowActorPrivate *priv = self->priv;
2713 
2714   priv->repaint_scheduled = FALSE;
2715 
2716   if (meta_window_actor_is_destroyed (self))
2717     return;
2718 
2719   /* If the window had damage, but wasn't actually redrawn because
2720    * it is obscured, we should wait until timer expiration before
2721    * sending _NET_WM_FRAME_* messages.
2722    */
2723   if (priv->send_frame_messages_timer == 0 &&
2724       priv->needs_frame_drawn)
2725     {
2726       GList *l;
2727 
2728       for (l = priv->frames; l; l = l->next)
2729         {
2730           FrameData *frame = l->data;
2731 
2732           if (frame->frame_drawn_time == 0)
2733             do_send_frame_drawn (self, frame);
2734         }
2735 
2736       priv->needs_frame_drawn = FALSE;
2737     }
2738 }
2739 
2740 static void
do_send_frame_timings(MetaWindowActor * self,FrameData * frame,gint refresh_interval,gint64 presentation_time)2741 do_send_frame_timings (MetaWindowActor  *self,
2742                        FrameData        *frame,
2743                        gint             refresh_interval,
2744                        gint64           presentation_time)
2745 {
2746   MetaWindowActorPrivate *priv = self->priv;
2747   MetaDisplay *display = meta_screen_get_display (priv->screen);
2748   MetaWindow *window = meta_window_actor_get_meta_window (self);
2749   Display *xdisplay = meta_display_get_xdisplay (display);
2750 
2751   XClientMessageEvent ev = { 0, };
2752 
2753   ev.type = ClientMessage;
2754   ev.window = meta_window_get_xwindow (window);
2755   ev.message_type = display->atom__NET_WM_FRAME_TIMINGS;
2756   ev.format = 32;
2757   ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT(0xffffffff);
2758   ev.data.l[1] = frame->sync_request_serial >> 32;
2759 
2760   if (presentation_time != 0)
2761     {
2762       gint64 presentation_time_server = meta_compositor_monotonic_time_to_server_time (display,
2763                                                                                        presentation_time);
2764       gint64 presentation_time_offset = presentation_time_server - frame->frame_drawn_time;
2765       if (presentation_time_offset == 0)
2766         presentation_time_offset = 1;
2767 
2768       if ((gint32)presentation_time_offset == presentation_time_offset)
2769         ev.data.l[2] = presentation_time_offset;
2770     }
2771 
2772   ev.data.l[3] = refresh_interval;
2773   ev.data.l[4] = 1000 * META_SYNC_DELAY;
2774 
2775   meta_error_trap_push (display);
2776   XSendEvent (xdisplay, ev.window, False, 0, (XEvent*) &ev);
2777   XFlush (xdisplay);
2778   meta_error_trap_pop (display);
2779 }
2780 
2781 static void
send_frame_timings(MetaWindowActor * self,FrameData * frame,CoglFrameInfo * frame_info,gint64 presentation_time)2782 send_frame_timings (MetaWindowActor  *self,
2783                     FrameData        *frame,
2784                     CoglFrameInfo    *frame_info,
2785                     gint64            presentation_time)
2786 {
2787   MetaWindow *window = meta_window_actor_get_meta_window (self);
2788   float refresh_rate;
2789   int refresh_interval;
2790 
2791   refresh_rate = window->monitor->refresh_rate;
2792   /* 0.0 is a flag for not known, but sanity-check against other odd numbers */
2793   if (refresh_rate >= 1.0)
2794     refresh_interval = (int) (0.5 + 1000000 / refresh_rate);
2795   else
2796     refresh_interval = 0;
2797 
2798   do_send_frame_timings (self, frame, refresh_interval, presentation_time);
2799 }
2800 
2801 void
meta_window_actor_frame_complete(MetaWindowActor * self,ClutterFrameInfo * frame_info,gint64 presentation_time)2802 meta_window_actor_frame_complete (MetaWindowActor  *self,
2803                                   ClutterFrameInfo *frame_info,
2804                                   gint64            presentation_time)
2805 {
2806   MetaWindowActorPrivate *priv = self->priv;
2807   GList *l;
2808 
2809   if (meta_window_actor_is_destroyed (self))
2810     return;
2811 
2812   for (l = priv->frames; l;)
2813     {
2814       GList *l_next = l->next;
2815       FrameData *frame = l->data;
2816       gint64 frame_counter = frame_info->frame_counter;
2817 
2818       if (frame->frame_counter != -1 && frame->frame_counter <= frame_counter)
2819         {
2820           if (G_UNLIKELY (frame->frame_drawn_time == 0))
2821             g_warning ("%s: Frame has assigned frame counter but no frame drawn time",
2822                        priv->window->desc);
2823           if (G_UNLIKELY (frame->frame_counter < frame_counter))
2824             g_warning ("%s: frame_complete callback never occurred for frame %" G_GINT64_FORMAT,
2825                        priv->window->desc, frame->frame_counter);
2826 
2827           priv->frames = g_list_delete_link (priv->frames, l);
2828           send_frame_timings (self, frame, frame_info, presentation_time);
2829           frame_data_free (frame);
2830         }
2831 
2832       l = l_next;
2833     }
2834 }
2835 
2836 LOCAL_SYMBOL void
meta_window_actor_invalidate_shadow(MetaWindowActor * self)2837 meta_window_actor_invalidate_shadow (MetaWindowActor *self)
2838 {
2839   MetaWindowActorPrivate *priv = self->priv;
2840 
2841   priv->recompute_focused_shadow = TRUE;
2842   priv->recompute_unfocused_shadow = TRUE;
2843 
2844   if (is_frozen (self))
2845     return;
2846 
2847   clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
2848 }
2849 
2850 LOCAL_SYMBOL void
meta_window_actor_update_opacity(MetaWindowActor * self)2851 meta_window_actor_update_opacity (MetaWindowActor *self)
2852 {
2853   MetaWindowActorPrivate *priv = self->priv;
2854   MetaDisplay *display = meta_screen_get_display (priv->screen);
2855   MetaCompositor *compositor = meta_display_get_compositor (display);
2856   Window xwin = meta_window_get_xwindow (priv->window);
2857   gulong value;
2858   guint8 opacity;
2859 
2860   if (meta_prop_get_cardinal (display, xwin,
2861                               compositor->atom_net_wm_window_opacity,
2862                               &value))
2863     {
2864       opacity = (guint8)((gfloat)value * 255.0 / ((gfloat)0xffffffff));
2865     }
2866   else
2867     opacity = 255;
2868 
2869   self->priv->opacity = opacity;
2870   clutter_actor_set_opacity (self->priv->actor, opacity);
2871 }
2872 
2873 void
meta_window_actor_set_updates_frozen(MetaWindowActor * self,gboolean updates_frozen)2874 meta_window_actor_set_updates_frozen (MetaWindowActor *self,
2875                                       gboolean         updates_frozen)
2876 {
2877   MetaWindowActorPrivate *priv = self->priv;
2878 
2879   updates_frozen = updates_frozen != FALSE;
2880 
2881   if (priv->updates_frozen != updates_frozen)
2882     {
2883       priv->updates_frozen = updates_frozen;
2884       if (updates_frozen)
2885         meta_window_actor_freeze (self);
2886       else
2887         meta_window_actor_thaw (self);
2888     }
2889 }
2890