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
7  *   graph
8  *
9  * #MetaWindowActor is a #ClutterActor that adds a notion of a window to the
10  * Clutter scene graph. It contains a #MetaWindow which provides the windowing
11  * API, and the #MetaCompositor that handles it.  For the actual content of the
12  * window, it contains a #MetaSurfaceActor.
13  *
14  * #MetaWindowActor takes care of the rendering features you need for your
15  * window. For example, it will take the windows' requested opacity and use
16  * that for clutter_actor_set_opacity(). Furthermore, it will also draw a
17  * shadow around the window (using #MetaShadow) and deal with synchronization
18  * between events of the window and the actual render loop. See
19  * MetaWindowActor::first-frame for an example of the latter.
20  */
21 
22 #include "config.h"
23 
24 #include <gdk/gdk.h>
25 #include <math.h>
26 #include <string.h>
27 
28 #include "backends/meta-screen-cast-window.h"
29 #include "compositor/compositor-private.h"
30 #include "compositor/meta-cullable.h"
31 #include "compositor/meta-shaped-texture-private.h"
32 #include "compositor/meta-surface-actor-x11.h"
33 #include "compositor/meta-surface-actor.h"
34 #include "compositor/meta-window-actor-private.h"
35 #include "core/boxes-private.h"
36 #include "core/window-private.h"
37 #include "meta/window.h"
38 
39 #ifdef HAVE_WAYLAND
40 #include "compositor/meta-surface-actor-wayland.h"
41 #include "wayland/meta-wayland-surface.h"
42 #endif
43 
44 typedef enum
45 {
46   INITIALLY_FROZEN,
47   DRAWING_FIRST_FRAME,
48   EMITTED_FIRST_FRAME
49 } FirstFrameState;
50 
51 typedef struct _MetaWindowActorPrivate
52 {
53   MetaWindow *window;
54   MetaCompositor *compositor;
55 
56   MetaSurfaceActor *surface;
57 
58   int geometry_scale;
59 
60   /*
61    * These need to be counters rather than flags, since more plugins
62    * can implement same effect; the practicality of stacking effects
63    * might be dubious, but we have to at least handle it correctly.
64    */
65   gint              minimize_in_progress;
66   gint              unminimize_in_progress;
67   gint              size_change_in_progress;
68   gint              map_in_progress;
69   gint              destroy_in_progress;
70 
71   guint             freeze_count;
72 
73   guint		    visible                : 1;
74   guint		    disposed               : 1;
75 
76   guint		    needs_destroy	   : 1;
77 
78   guint             updates_frozen         : 1;
79   guint             first_frame_state      : 2; /* FirstFrameState */
80 } MetaWindowActorPrivate;
81 
82 enum
83 {
84   FIRST_FRAME,
85   EFFECTS_COMPLETED,
86   DAMAGED,
87   THAWED,
88 
89   LAST_SIGNAL
90 };
91 
92 static guint signals[LAST_SIGNAL] = { 0 };
93 
94 enum
95 {
96   PROP_META_WINDOW = 1,
97 };
98 
99 static void meta_window_actor_dispose    (GObject *object);
100 static void meta_window_actor_constructed (GObject *object);
101 static void meta_window_actor_set_property (GObject       *object,
102                                             guint         prop_id,
103                                             const GValue *value,
104                                             GParamSpec   *pspec);
105 static void meta_window_actor_get_property (GObject      *object,
106                                             guint         prop_id,
107                                             GValue       *value,
108                                             GParamSpec   *pspec);
109 
110 static void meta_window_actor_real_assign_surface_actor (MetaWindowActor  *self,
111                                                          MetaSurfaceActor *surface_actor);
112 
113 static void cullable_iface_init (MetaCullableInterface *iface);
114 
115 static void screen_cast_window_iface_init (MetaScreenCastWindowInterface *iface);
116 
117 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaWindowActor, meta_window_actor, CLUTTER_TYPE_ACTOR,
118                                   G_ADD_PRIVATE (MetaWindowActor)
119                                   G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)
120                                   G_IMPLEMENT_INTERFACE (META_TYPE_SCREEN_CAST_WINDOW, screen_cast_window_iface_init));
121 
122 static void
meta_window_actor_class_init(MetaWindowActorClass * klass)123 meta_window_actor_class_init (MetaWindowActorClass *klass)
124 {
125   GObjectClass *object_class = G_OBJECT_CLASS (klass);
126   GParamSpec   *pspec;
127 
128   object_class->dispose      = meta_window_actor_dispose;
129   object_class->set_property = meta_window_actor_set_property;
130   object_class->get_property = meta_window_actor_get_property;
131   object_class->constructed  = meta_window_actor_constructed;
132 
133   klass->assign_surface_actor = meta_window_actor_real_assign_surface_actor;
134 
135   /**
136    * MetaWindowActor::first-frame:
137    * @actor: the #MetaWindowActor instance
138    *
139    * The ::first-frame signal will be emitted the first time a frame
140    * of window contents has been drawn by the application and Mutter
141    * has had the chance to drawn that frame to the screen. If the
142    * window starts off initially hidden, obscured, or on on a
143    * different workspace, the ::first-frame signal will be emitted
144    * even though the user doesn't see the contents.
145    *
146    * MetaDisplay::window-created is a good place to connect to this
147    * signal - at that point, the MetaWindowActor for the window
148    * exists, but the window has reliably not yet been drawn.
149    * Connecting to an existing window that has already been drawn to
150    * the screen is not useful.
151    */
152   signals[FIRST_FRAME] =
153     g_signal_new ("first-frame",
154                   G_TYPE_FROM_CLASS (object_class),
155                   G_SIGNAL_RUN_LAST,
156                   0,
157                   NULL, NULL, NULL,
158                   G_TYPE_NONE, 0);
159 
160   /**
161    * MetaWindowActor::effects-completed:
162    * @actor: the #MetaWindowActor instance
163    *
164    * The ::effects-completed signal will be emitted once all pending compositor
165    * effects are completed.
166    */
167   signals[EFFECTS_COMPLETED] =
168     g_signal_new ("effects-completed",
169                   G_TYPE_FROM_CLASS (object_class),
170                   G_SIGNAL_RUN_LAST,
171                   0,
172                   NULL, NULL, NULL,
173                   G_TYPE_NONE, 0);
174 
175   /**
176    * MetaWindowActor::damaged:
177    * @actor: the #MetaWindowActor instance
178    *
179    * Notify that one or more of the surfaces of the window have been damaged.
180    */
181   signals[DAMAGED] =
182     g_signal_new ("damaged",
183                   G_TYPE_FROM_CLASS (object_class),
184                   G_SIGNAL_RUN_LAST,
185                   0,
186                   NULL, NULL, NULL,
187                   G_TYPE_NONE, 0);
188 
189   /**
190    * MetaWindowActor::thawed:
191    * @actor: the #MetaWindowActor instance
192    */
193   signals[THAWED] =
194     g_signal_new ("thawed",
195                   G_TYPE_FROM_CLASS (object_class),
196                   G_SIGNAL_RUN_LAST,
197                   0,
198                   NULL, NULL, NULL,
199                   G_TYPE_NONE, 0);
200 
201   pspec = g_param_spec_object ("meta-window",
202                                "MetaWindow",
203                                "The displayed MetaWindow",
204                                META_TYPE_WINDOW,
205                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
206 
207   g_object_class_install_property (object_class,
208                                    PROP_META_WINDOW,
209                                    pspec);
210 }
211 
212 static void
meta_window_actor_init(MetaWindowActor * self)213 meta_window_actor_init (MetaWindowActor *self)
214 {
215   MetaWindowActorPrivate *priv =
216     meta_window_actor_get_instance_private (self);
217 
218   priv->geometry_scale = 1;
219 }
220 
221 static void
window_appears_focused_notify(MetaWindow * mw,GParamSpec * arg1,gpointer data)222 window_appears_focused_notify (MetaWindow *mw,
223                                GParamSpec *arg1,
224                                gpointer    data)
225 {
226   clutter_actor_queue_redraw (CLUTTER_ACTOR (data));
227 }
228 
229 gboolean
meta_window_actor_is_opaque(MetaWindowActor * self)230 meta_window_actor_is_opaque (MetaWindowActor *self)
231 {
232   MetaWindowActorPrivate *priv =
233     meta_window_actor_get_instance_private (self);
234   MetaWindow *window = priv->window;
235 
236   if (window->opacity != 0xff)
237     return FALSE;
238 
239   if (!priv->surface)
240     return FALSE;
241 
242   return meta_surface_actor_is_opaque (priv->surface);
243 }
244 
245 gboolean
meta_window_actor_is_frozen(MetaWindowActor * self)246 meta_window_actor_is_frozen (MetaWindowActor *self)
247 {
248   MetaWindowActorPrivate *priv =
249     meta_window_actor_get_instance_private (self);
250 
251   return priv->surface == NULL || priv->freeze_count > 0;
252 }
253 
254 void
meta_window_actor_update_regions(MetaWindowActor * self)255 meta_window_actor_update_regions (MetaWindowActor *self)
256 {
257   META_WINDOW_ACTOR_GET_CLASS (self)->update_regions (self);
258 }
259 
260 gboolean
meta_window_actor_can_freeze_commits(MetaWindowActor * self)261 meta_window_actor_can_freeze_commits (MetaWindowActor *self)
262 {
263   g_return_val_if_fail (META_IS_WINDOW_ACTOR (self), FALSE);
264 
265   return META_WINDOW_ACTOR_GET_CLASS (self)->can_freeze_commits (self);
266 }
267 
268 static void
meta_window_actor_set_frozen(MetaWindowActor * self,gboolean frozen)269 meta_window_actor_set_frozen (MetaWindowActor *self,
270                               gboolean         frozen)
271 {
272   ClutterActor *child;
273   ClutterActorIter iter;
274 
275   clutter_actor_iter_init (&iter, CLUTTER_ACTOR (self));
276   while (clutter_actor_iter_next (&iter, &child))
277     {
278       if (META_IS_SURFACE_ACTOR (child))
279         meta_surface_actor_set_frozen (META_SURFACE_ACTOR (child), frozen);
280     }
281 
282   META_WINDOW_ACTOR_GET_CLASS (self)->set_frozen (self, frozen);
283 }
284 
285 /**
286  * meta_window_actor_freeze:
287  * @self: The #MetaWindowActor
288  *
289  * Freezes the #MetaWindowActor, which inhibits updates and geometry
290  * changes of the window. This property is refcounted, so make sure
291  * to call meta_window_actor_thaw() the exact same amount of times
292  * as this function to allow updates again.
293  */
294 void
meta_window_actor_freeze(MetaWindowActor * self)295 meta_window_actor_freeze (MetaWindowActor *self)
296 {
297   MetaWindowActorPrivate *priv;
298 
299   g_return_if_fail (META_IS_WINDOW_ACTOR (self));
300 
301   priv = meta_window_actor_get_instance_private (self);
302 
303   if (priv->freeze_count == 0 && priv->surface)
304     meta_window_actor_set_frozen (self, TRUE);
305 
306   priv->freeze_count ++;
307 }
308 
309 static void
meta_window_actor_sync_thawed_state(MetaWindowActor * self)310 meta_window_actor_sync_thawed_state (MetaWindowActor *self)
311 {
312   MetaWindowActorPrivate *priv =
313     meta_window_actor_get_instance_private (self);
314 
315   if (priv->first_frame_state == INITIALLY_FROZEN)
316     priv->first_frame_state = DRAWING_FIRST_FRAME;
317 
318   if (priv->surface)
319     meta_window_actor_set_frozen (self, FALSE);
320 
321   /* We sometimes ignore moves and resizes on frozen windows */
322   meta_window_actor_sync_actor_geometry (self, FALSE);
323 }
324 
325 /**
326  * meta_window_actor_thaw:
327  * @self: The #MetaWindowActor
328  *
329  * Thaws/unfreezes the #MetaWindowActor to allow updates and geometry
330  * changes after a window was frozen using meta_window_actor_freeze().
331  */
332 void
meta_window_actor_thaw(MetaWindowActor * self)333 meta_window_actor_thaw (MetaWindowActor *self)
334 {
335   MetaWindowActorPrivate *priv;
336 
337   g_return_if_fail (META_IS_WINDOW_ACTOR (self));
338 
339   priv = meta_window_actor_get_instance_private (self);
340 
341   if (priv->freeze_count <= 0)
342     g_error ("Error in freeze/thaw accounting");
343 
344   priv->freeze_count--;
345   if (priv->freeze_count > 0)
346     return;
347 
348   /* We still might be frozen due to lack of a MetaSurfaceActor */
349   if (meta_window_actor_is_frozen (self))
350     return;
351 
352   meta_window_actor_sync_thawed_state (self);
353 
354   g_signal_emit (self, signals[THAWED], 0);
355 }
356 
357 static void
meta_window_actor_real_assign_surface_actor(MetaWindowActor * self,MetaSurfaceActor * surface_actor)358 meta_window_actor_real_assign_surface_actor (MetaWindowActor  *self,
359                                              MetaSurfaceActor *surface_actor)
360 {
361   MetaWindowActorPrivate *priv =
362     meta_window_actor_get_instance_private (self);
363 
364   g_clear_object (&priv->surface);
365   priv->surface = g_object_ref_sink (surface_actor);
366 
367   if (meta_window_actor_is_frozen (self))
368     meta_window_actor_set_frozen (self, TRUE);
369   else
370     meta_window_actor_sync_thawed_state (self);
371 }
372 
373 void
meta_window_actor_assign_surface_actor(MetaWindowActor * self,MetaSurfaceActor * surface_actor)374 meta_window_actor_assign_surface_actor (MetaWindowActor  *self,
375                                         MetaSurfaceActor *surface_actor)
376 {
377   META_WINDOW_ACTOR_GET_CLASS (self)->assign_surface_actor (self,
378                                                             surface_actor);
379 }
380 
381 static void
init_surface_actor(MetaWindowActor * self)382 init_surface_actor (MetaWindowActor *self)
383 {
384   MetaWindowActorPrivate *priv =
385     meta_window_actor_get_instance_private (self);
386   MetaWindow *window = priv->window;
387   MetaSurfaceActor *surface_actor;
388 
389   if (!meta_is_wayland_compositor ())
390     surface_actor = meta_surface_actor_x11_new (window);
391 #ifdef HAVE_WAYLAND
392   else if (window->surface)
393     surface_actor = meta_wayland_surface_get_actor (window->surface);
394 #endif
395   else
396     surface_actor = NULL;
397 
398   if (surface_actor)
399     meta_window_actor_assign_surface_actor (self, surface_actor);
400 }
401 
402 static void
meta_window_actor_constructed(GObject * object)403 meta_window_actor_constructed (GObject *object)
404 {
405   MetaWindowActor *self = META_WINDOW_ACTOR (object);
406   MetaWindowActorPrivate *priv =
407     meta_window_actor_get_instance_private (self);
408   MetaWindow *window = priv->window;
409 
410   priv->compositor = window->display->compositor;
411 
412   /* Hang our compositor window state off the MetaWindow for fast retrieval */
413   meta_window_set_compositor_private (window, object);
414 
415   init_surface_actor (self);
416 
417   meta_window_actor_update_opacity (self);
418 
419   meta_window_actor_sync_updates_frozen (self);
420 
421   if (meta_window_actor_is_frozen (self))
422     priv->first_frame_state = INITIALLY_FROZEN;
423   else
424     priv->first_frame_state = DRAWING_FIRST_FRAME;
425 
426   meta_window_actor_sync_actor_geometry (self, priv->window->placed);
427 }
428 
429 static void
meta_window_actor_dispose(GObject * object)430 meta_window_actor_dispose (GObject *object)
431 {
432   MetaWindowActor *self = META_WINDOW_ACTOR (object);
433   MetaWindowActorPrivate *priv =
434     meta_window_actor_get_instance_private (self);
435   MetaCompositor *compositor = priv->compositor;
436 
437   if (priv->disposed)
438     {
439       G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object);
440       return;
441     }
442 
443   priv->disposed = TRUE;
444 
445   meta_compositor_remove_window_actor (compositor, self);
446 
447   g_clear_object (&priv->window);
448 
449   if (priv->surface)
450     {
451       clutter_actor_remove_child (CLUTTER_ACTOR (self),
452                                   CLUTTER_ACTOR (priv->surface));
453       g_clear_object (&priv->surface);
454     }
455 
456   G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object);
457 }
458 
459 static void
meta_window_actor_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)460 meta_window_actor_set_property (GObject      *object,
461                                 guint         prop_id,
462                                 const GValue *value,
463                                 GParamSpec   *pspec)
464 {
465   MetaWindowActor *self = META_WINDOW_ACTOR (object);
466   MetaWindowActorPrivate *priv =
467     meta_window_actor_get_instance_private (self);
468 
469   switch (prop_id)
470     {
471     case PROP_META_WINDOW:
472       priv->window = g_value_dup_object (value);
473       g_signal_connect_object (priv->window, "notify::appears-focused",
474                                G_CALLBACK (window_appears_focused_notify), self, 0);
475       break;
476     default:
477       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
478       break;
479     }
480 }
481 
482 static void
meta_window_actor_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)483 meta_window_actor_get_property (GObject      *object,
484                                 guint         prop_id,
485                                 GValue       *value,
486                                 GParamSpec   *pspec)
487 {
488   MetaWindowActor *self = META_WINDOW_ACTOR (object);
489   MetaWindowActorPrivate *priv =
490     meta_window_actor_get_instance_private (self);
491 
492   switch (prop_id)
493     {
494     case PROP_META_WINDOW:
495       g_value_set_object (value, priv->window);
496       break;
497     default:
498       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
499       break;
500     }
501 }
502 
503 /**
504  * meta_window_actor_get_meta_window:
505  * @self: a #MetaWindowActor
506  *
507  * Gets the #MetaWindow object that the the #MetaWindowActor is displaying
508  *
509  * Return value: (transfer none): the displayed #MetaWindow
510  */
511 MetaWindow *
meta_window_actor_get_meta_window(MetaWindowActor * self)512 meta_window_actor_get_meta_window (MetaWindowActor *self)
513 {
514   MetaWindowActorPrivate *priv =
515     meta_window_actor_get_instance_private (self);
516 
517   return priv->window;
518 }
519 
520 /**
521  * meta_window_actor_get_texture:
522  * @self: a #MetaWindowActor
523  *
524  * Gets the ClutterActor that is used to display the contents of the window,
525  * or NULL if no texture is shown yet, because the window is not mapped.
526  *
527  * Return value: (transfer none): the #ClutterActor for the contents
528  */
529 MetaShapedTexture *
meta_window_actor_get_texture(MetaWindowActor * self)530 meta_window_actor_get_texture (MetaWindowActor *self)
531 {
532   MetaWindowActorPrivate *priv =
533     meta_window_actor_get_instance_private (self);
534 
535   if (priv->surface)
536     return meta_surface_actor_get_texture (priv->surface);
537   else
538     return NULL;
539 }
540 
541 /**
542  * meta_window_actor_get_surface:
543  * @self: a #MetaWindowActor
544  *
545  * Gets the MetaSurfaceActor that draws the content of this window,
546  * or NULL if there is no surface yet associated with this window.
547  *
548  * Return value: (transfer none): the #MetaSurfaceActor for the contents
549  */
550 MetaSurfaceActor *
meta_window_actor_get_surface(MetaWindowActor * self)551 meta_window_actor_get_surface (MetaWindowActor *self)
552 {
553   MetaWindowActorPrivate *priv =
554     meta_window_actor_get_instance_private (self);
555 
556   return priv->surface;
557 }
558 
559 /**
560  * meta_window_actor_is_destroyed:
561  * @self: a #MetaWindowActor
562  *
563  * Gets whether the X window that the actor was displaying has been destroyed
564  *
565  * Return value: %TRUE when the window is destroyed, otherwise %FALSE
566  */
567 gboolean
meta_window_actor_is_destroyed(MetaWindowActor * self)568 meta_window_actor_is_destroyed (MetaWindowActor *self)
569 {
570   MetaWindowActorPrivate *priv =
571     meta_window_actor_get_instance_private (self);
572 
573   return priv->disposed || priv->needs_destroy;
574 }
575 
576 void
meta_window_actor_queue_frame_drawn(MetaWindowActor * self,gboolean no_delay_frame)577 meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
578                                      gboolean         no_delay_frame)
579 {
580   META_WINDOW_ACTOR_GET_CLASS (self)->queue_frame_drawn (self,
581                                                          no_delay_frame);
582 }
583 
584 gboolean
meta_window_actor_effect_in_progress(MetaWindowActor * self)585 meta_window_actor_effect_in_progress (MetaWindowActor *self)
586 {
587   MetaWindowActorPrivate *priv =
588     meta_window_actor_get_instance_private (self);
589 
590   return (priv->minimize_in_progress ||
591           priv->size_change_in_progress ||
592           priv->map_in_progress ||
593           priv->destroy_in_progress);
594 }
595 
596 static gboolean
is_freeze_thaw_effect(MetaPluginEffect event)597 is_freeze_thaw_effect (MetaPluginEffect event)
598 {
599   switch (event)
600   {
601   case META_PLUGIN_DESTROY:
602     return TRUE;
603     break;
604   default:
605     return FALSE;
606   }
607 }
608 
609 static gboolean
start_simple_effect(MetaWindowActor * self,MetaPluginEffect event)610 start_simple_effect (MetaWindowActor  *self,
611                      MetaPluginEffect  event)
612 {
613   MetaWindowActorPrivate *priv =
614     meta_window_actor_get_instance_private (self);
615   MetaCompositor *compositor = priv->compositor;
616   MetaPluginManager *plugin_mgr =
617     meta_compositor_get_plugin_manager (compositor);
618   gint *counter = NULL;
619   gboolean use_freeze_thaw = FALSE;
620 
621   g_assert (plugin_mgr != NULL);
622 
623   switch (event)
624   {
625   case META_PLUGIN_NONE:
626     return FALSE;
627   case META_PLUGIN_MINIMIZE:
628     counter = &priv->minimize_in_progress;
629     break;
630   case META_PLUGIN_UNMINIMIZE:
631     counter = &priv->unminimize_in_progress;
632     break;
633   case META_PLUGIN_MAP:
634     counter = &priv->map_in_progress;
635     break;
636   case META_PLUGIN_DESTROY:
637     counter = &priv->destroy_in_progress;
638     break;
639   case META_PLUGIN_SIZE_CHANGE:
640   case META_PLUGIN_SWITCH_WORKSPACE:
641     g_assert_not_reached ();
642     break;
643   }
644 
645   g_assert (counter);
646 
647   use_freeze_thaw = is_freeze_thaw_effect (event);
648 
649   if (use_freeze_thaw)
650     meta_window_actor_freeze (self);
651 
652   (*counter)++;
653 
654   if (!meta_plugin_manager_event_simple (plugin_mgr, self, event))
655     {
656       (*counter)--;
657       if (use_freeze_thaw)
658         meta_window_actor_thaw (self);
659       return FALSE;
660     }
661 
662   return TRUE;
663 }
664 
665 static void
meta_window_actor_after_effects(MetaWindowActor * self)666 meta_window_actor_after_effects (MetaWindowActor *self)
667 {
668   MetaWindowActorPrivate *priv =
669     meta_window_actor_get_instance_private (self);
670   ClutterStage *stage;
671   ClutterSeat *seat;
672 
673   stage = CLUTTER_STAGE (clutter_actor_get_stage (CLUTTER_ACTOR (self)));
674   seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
675 
676   if (priv->needs_destroy)
677     {
678       clutter_actor_destroy (CLUTTER_ACTOR (self));
679     }
680   else
681     {
682       g_signal_emit (self, signals[EFFECTS_COMPLETED], 0);
683       meta_window_actor_sync_visibility (self);
684       meta_window_actor_sync_actor_geometry (self, FALSE);
685     }
686 
687   clutter_stage_repick_device (stage, clutter_seat_get_pointer (seat));
688 }
689 
690 void
meta_window_actor_effect_completed(MetaWindowActor * self,MetaPluginEffect event)691 meta_window_actor_effect_completed (MetaWindowActor  *self,
692                                     MetaPluginEffect  event)
693 {
694   MetaWindowActorPrivate *priv =
695     meta_window_actor_get_instance_private (self);
696   gboolean inconsistent = FALSE;
697 
698   /* NB: Keep in mind that when effects get completed it possible
699    * that the corresponding MetaWindow may have be been destroyed.
700    * In this case priv->window will == NULL */
701 
702   switch (event)
703   {
704   case META_PLUGIN_NONE:
705     break;
706   case META_PLUGIN_MINIMIZE:
707     {
708       priv->minimize_in_progress--;
709       if (priv->minimize_in_progress < 0)
710         {
711           g_warning ("Error in minimize accounting.");
712           priv->minimize_in_progress = 0;
713           inconsistent = TRUE;
714         }
715     }
716     break;
717   case META_PLUGIN_UNMINIMIZE:
718     {
719       priv->unminimize_in_progress--;
720       if (priv->unminimize_in_progress < 0)
721        {
722          g_warning ("Error in unminimize accounting.");
723          priv->unminimize_in_progress = 0;
724          inconsistent = TRUE;
725        }
726     }
727     break;
728   case META_PLUGIN_MAP:
729     /*
730      * Make sure that the actor is at the correct place in case
731      * the plugin fscked.
732      */
733     priv->map_in_progress--;
734 
735     if (priv->map_in_progress < 0)
736       {
737         g_warning ("Error in map accounting.");
738         priv->map_in_progress = 0;
739         inconsistent = TRUE;
740       }
741     break;
742   case META_PLUGIN_DESTROY:
743     priv->destroy_in_progress--;
744 
745     if (priv->destroy_in_progress < 0)
746       {
747         g_warning ("Error in destroy accounting.");
748         priv->destroy_in_progress = 0;
749         inconsistent = TRUE;
750       }
751     break;
752   case META_PLUGIN_SIZE_CHANGE:
753     priv->size_change_in_progress--;
754     if (priv->size_change_in_progress < 0)
755       {
756         g_warning ("Error in size change accounting.");
757         priv->size_change_in_progress = 0;
758         inconsistent = TRUE;
759       }
760     break;
761   case META_PLUGIN_SWITCH_WORKSPACE:
762     g_assert_not_reached ();
763     break;
764   }
765 
766   if (is_freeze_thaw_effect (event) && !inconsistent)
767     meta_window_actor_thaw (self);
768 
769   if (!meta_window_actor_effect_in_progress (self))
770     meta_window_actor_after_effects (self);
771 }
772 
773 void
meta_window_actor_queue_destroy(MetaWindowActor * self)774 meta_window_actor_queue_destroy (MetaWindowActor *self)
775 {
776   MetaWindowActorPrivate *priv =
777     meta_window_actor_get_instance_private (self);
778   MetaWindow *window = priv->window;
779   MetaWindowType window_type = meta_window_get_window_type (window);
780 
781   meta_window_set_compositor_private (window, NULL);
782 
783   META_WINDOW_ACTOR_GET_CLASS (self)->queue_destroy (self);
784 
785   if (window_type == META_WINDOW_DROPDOWN_MENU ||
786       window_type == META_WINDOW_POPUP_MENU ||
787       window_type == META_WINDOW_TOOLTIP ||
788       window_type == META_WINDOW_NOTIFICATION ||
789       window_type == META_WINDOW_COMBO ||
790       window_type == META_WINDOW_DND ||
791       window_type == META_WINDOW_OVERRIDE_OTHER)
792     {
793       /*
794        * No effects, just kill it.
795        */
796       clutter_actor_destroy (CLUTTER_ACTOR (self));
797       return;
798     }
799 
800   priv->needs_destroy = TRUE;
801 
802   if (!meta_window_actor_effect_in_progress (self))
803     clutter_actor_destroy (CLUTTER_ACTOR (self));
804 }
805 
806 MetaWindowActorChanges
meta_window_actor_sync_actor_geometry(MetaWindowActor * self,gboolean did_placement)807 meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
808                                        gboolean         did_placement)
809 {
810   MetaWindowActorPrivate *priv =
811     meta_window_actor_get_instance_private (self);
812   MetaRectangle window_rect;
813   ClutterActor *actor = CLUTTER_ACTOR (self);
814   MetaWindowActorChanges changes = 0;
815 
816   meta_window_get_buffer_rect (priv->window, &window_rect);
817 
818   /* When running as a Wayland compositor we catch size changes when new
819    * buffers are attached */
820   if (META_IS_SURFACE_ACTOR_X11 (priv->surface))
821     meta_surface_actor_x11_set_size (META_SURFACE_ACTOR_X11 (priv->surface),
822                                      window_rect.width, window_rect.height);
823 
824   /* Normally we want freezing a window to also freeze its position; this allows
825    * windows to atomically move and resize together, either under app control,
826    * or because the user is resizing from the left/top. But on initial placement
827    * we need to assign a position, since immediately after the window
828    * is shown, the map effect will go into effect and prevent further geometry
829    * updates.
830    */
831   if (meta_window_actor_is_frozen (self) && !did_placement)
832     return META_WINDOW_ACTOR_CHANGE_POSITION | META_WINDOW_ACTOR_CHANGE_SIZE;
833 
834   if (clutter_actor_has_allocation (actor))
835     {
836       ClutterActorBox box;
837       float old_x, old_y;
838       float old_width, old_height;
839 
840       clutter_actor_get_allocation_box (actor, &box);
841 
842       old_x = box.x1;
843       old_y = box.y1;
844       old_width = box.x2 - box.x1;
845       old_height = box.y2 - box.y1;
846 
847       if (old_x != window_rect.x || old_y != window_rect.y)
848         changes |= META_WINDOW_ACTOR_CHANGE_POSITION;
849 
850       if (old_width != window_rect.width || old_height != window_rect.height)
851         changes |= META_WINDOW_ACTOR_CHANGE_SIZE;
852     }
853   else
854     {
855       changes = META_WINDOW_ACTOR_CHANGE_POSITION | META_WINDOW_ACTOR_CHANGE_SIZE;
856     }
857 
858   if (changes & META_WINDOW_ACTOR_CHANGE_POSITION)
859     clutter_actor_set_position (actor, window_rect.x, window_rect.y);
860 
861   if (changes & META_WINDOW_ACTOR_CHANGE_SIZE)
862     clutter_actor_set_size (actor, window_rect.width, window_rect.height);
863 
864   return changes;
865 }
866 
867 void
meta_window_actor_show(MetaWindowActor * self,MetaCompEffect effect)868 meta_window_actor_show (MetaWindowActor   *self,
869                         MetaCompEffect     effect)
870 {
871   MetaWindowActorPrivate *priv =
872     meta_window_actor_get_instance_private (self);
873   MetaCompositor *compositor = priv->compositor;
874   MetaPluginEffect event;
875 
876   g_return_if_fail (!priv->visible);
877 
878   priv->visible = TRUE;
879 
880   switch (effect)
881     {
882     case META_COMP_EFFECT_CREATE:
883       event = META_PLUGIN_MAP;
884       break;
885     case META_COMP_EFFECT_UNMINIMIZE:
886       event = META_PLUGIN_UNMINIMIZE;
887       break;
888     case META_COMP_EFFECT_NONE:
889       event = META_PLUGIN_NONE;
890       break;
891     default:
892       g_assert_not_reached();
893     }
894 
895   if (event == META_PLUGIN_MAP)
896     meta_window_actor_sync_actor_geometry (self, TRUE);
897 
898   if (meta_compositor_is_switching_workspace (compositor) ||
899       !start_simple_effect (self, event))
900     {
901       clutter_actor_show (CLUTTER_ACTOR (self));
902     }
903 }
904 
905 void
meta_window_actor_hide(MetaWindowActor * self,MetaCompEffect effect)906 meta_window_actor_hide (MetaWindowActor *self,
907                         MetaCompEffect   effect)
908 {
909   MetaWindowActorPrivate *priv =
910     meta_window_actor_get_instance_private (self);
911   MetaCompositor *compositor = priv->compositor;
912   MetaPluginEffect event;
913 
914   g_return_if_fail (priv->visible);
915 
916   priv->visible = FALSE;
917 
918   /* If a plugin is animating a workspace transition, we have to
919    * hold off on hiding the window, and do it after the workspace
920    * switch completes
921    */
922   if (meta_compositor_is_switching_workspace (compositor))
923     return;
924 
925   switch (effect)
926     {
927     case META_COMP_EFFECT_DESTROY:
928       event = META_PLUGIN_DESTROY;
929       break;
930     case META_COMP_EFFECT_MINIMIZE:
931       event = META_PLUGIN_MINIMIZE;
932       break;
933     case META_COMP_EFFECT_NONE:
934       event = META_PLUGIN_NONE;
935       break;
936     default:
937       g_assert_not_reached();
938     }
939 
940   if (!start_simple_effect (self, event))
941     clutter_actor_hide (CLUTTER_ACTOR (self));
942 }
943 
944 void
meta_window_actor_size_change(MetaWindowActor * self,MetaSizeChange which_change,MetaRectangle * old_frame_rect,MetaRectangle * old_buffer_rect)945 meta_window_actor_size_change (MetaWindowActor    *self,
946                                MetaSizeChange      which_change,
947                                MetaRectangle      *old_frame_rect,
948                                MetaRectangle      *old_buffer_rect)
949 {
950   MetaWindowActorPrivate *priv =
951     meta_window_actor_get_instance_private (self);
952   MetaCompositor *compositor = priv->compositor;
953   MetaPluginManager *plugin_mgr =
954     meta_compositor_get_plugin_manager (compositor);
955 
956   priv->size_change_in_progress++;
957 
958   if (!meta_plugin_manager_event_size_change (plugin_mgr, self,
959                                               which_change, old_frame_rect, old_buffer_rect))
960     priv->size_change_in_progress--;
961 }
962 
963 #if 0
964 /* Print out a region; useful for debugging */
965 static void
966 print_region (cairo_region_t *region)
967 {
968   int n_rects;
969   int i;
970 
971   n_rects = cairo_region_num_rectangles (region);
972   g_print ("[");
973   for (i = 0; i < n_rects; i++)
974     {
975       cairo_rectangle_int_t rect;
976       cairo_region_get_rectangle (region, i, &rect);
977       g_print ("+%d+%dx%dx%d ",
978                rect.x, rect.y, rect.width, rect.height);
979     }
980   g_print ("]\n");
981 }
982 #endif
983 
984 #if 0
985 /* Dump a region to a PNG file; useful for debugging */
986 static void
987 see_region (cairo_region_t *region,
988             int             width,
989             int             height,
990             char           *filename)
991 {
992   cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
993   cairo_t *cr = cairo_create (surface);
994 
995   gdk_cairo_region (cr, region);
996   cairo_fill (cr);
997 
998   cairo_surface_write_to_png (surface, filename);
999   cairo_destroy (cr);
1000   cairo_surface_destroy (surface);
1001 }
1002 #endif
1003 
1004 
1005 static void
meta_window_actor_cull_out(MetaCullable * cullable,cairo_region_t * unobscured_region,cairo_region_t * clip_region)1006 meta_window_actor_cull_out (MetaCullable   *cullable,
1007                             cairo_region_t *unobscured_region,
1008                             cairo_region_t *clip_region)
1009 {
1010   meta_cullable_cull_out_children (cullable, unobscured_region, clip_region);
1011 }
1012 
1013 static void
meta_window_actor_reset_culling(MetaCullable * cullable)1014 meta_window_actor_reset_culling (MetaCullable *cullable)
1015 {
1016   meta_cullable_reset_culling_children (cullable);
1017 }
1018 
1019 static void
cullable_iface_init(MetaCullableInterface * iface)1020 cullable_iface_init (MetaCullableInterface *iface)
1021 {
1022   iface->cull_out = meta_window_actor_cull_out;
1023   iface->reset_culling = meta_window_actor_reset_culling;
1024 }
1025 
1026 void
meta_window_actor_sync_visibility(MetaWindowActor * self)1027 meta_window_actor_sync_visibility (MetaWindowActor *self)
1028 {
1029   MetaWindowActorPrivate *priv =
1030     meta_window_actor_get_instance_private (self);
1031 
1032   if (CLUTTER_ACTOR_IS_VISIBLE (self) != priv->visible)
1033     {
1034       if (priv->visible)
1035         clutter_actor_show (CLUTTER_ACTOR (self));
1036       else
1037         clutter_actor_hide (CLUTTER_ACTOR (self));
1038     }
1039 }
1040 
1041 void
meta_window_actor_before_paint(MetaWindowActor * self,ClutterStageView * stage_view)1042 meta_window_actor_before_paint (MetaWindowActor  *self,
1043                                 ClutterStageView *stage_view)
1044 {
1045   if (meta_window_actor_is_destroyed (self))
1046     return;
1047 
1048   META_WINDOW_ACTOR_GET_CLASS (self)->before_paint (self, stage_view);
1049 }
1050 
1051 void
meta_window_actor_after_paint(MetaWindowActor * self,ClutterStageView * stage_view)1052 meta_window_actor_after_paint (MetaWindowActor  *self,
1053                                ClutterStageView *stage_view)
1054 {
1055   MetaWindowActorPrivate *priv =
1056     meta_window_actor_get_instance_private (self);
1057 
1058   META_WINDOW_ACTOR_GET_CLASS (self)->after_paint (self, stage_view);
1059 
1060   if (meta_window_actor_is_destroyed (self))
1061     return;
1062 
1063   if (priv->first_frame_state == DRAWING_FIRST_FRAME)
1064     {
1065       priv->first_frame_state = EMITTED_FIRST_FRAME;
1066       g_signal_emit (self, signals[FIRST_FRAME], 0);
1067     }
1068 }
1069 
1070 void
meta_window_actor_frame_complete(MetaWindowActor * self,ClutterFrameInfo * frame_info,gint64 presentation_time)1071 meta_window_actor_frame_complete (MetaWindowActor  *self,
1072                                   ClutterFrameInfo *frame_info,
1073                                   gint64            presentation_time)
1074 {
1075   META_WINDOW_ACTOR_GET_CLASS (self)->frame_complete (self,
1076                                                       frame_info,
1077                                                       presentation_time);
1078 }
1079 
1080 void
meta_window_actor_update_opacity(MetaWindowActor * self)1081 meta_window_actor_update_opacity (MetaWindowActor *self)
1082 {
1083   MetaWindowActorPrivate *priv =
1084     meta_window_actor_get_instance_private (self);
1085   MetaWindow *window = priv->window;
1086 
1087   if (priv->surface)
1088     clutter_actor_set_opacity (CLUTTER_ACTOR (priv->surface), window->opacity);
1089 }
1090 
1091 static void
meta_window_actor_set_updates_frozen(MetaWindowActor * self,gboolean updates_frozen)1092 meta_window_actor_set_updates_frozen (MetaWindowActor *self,
1093                                       gboolean         updates_frozen)
1094 {
1095   MetaWindowActorPrivate *priv =
1096     meta_window_actor_get_instance_private (self);
1097 
1098   updates_frozen = updates_frozen != FALSE;
1099 
1100   if (priv->updates_frozen != updates_frozen)
1101     {
1102       priv->updates_frozen = updates_frozen;
1103       if (updates_frozen)
1104         meta_window_actor_freeze (self);
1105       else
1106         meta_window_actor_thaw (self);
1107     }
1108 }
1109 
1110 void
meta_window_actor_sync_updates_frozen(MetaWindowActor * self)1111 meta_window_actor_sync_updates_frozen (MetaWindowActor *self)
1112 {
1113   MetaWindowActorPrivate *priv =
1114     meta_window_actor_get_instance_private (self);
1115   MetaWindow *window = priv->window;
1116 
1117   meta_window_actor_set_updates_frozen (self, meta_window_updates_are_frozen (window));
1118 }
1119 
1120 MetaWindowActor *
meta_window_actor_from_window(MetaWindow * window)1121 meta_window_actor_from_window (MetaWindow *window)
1122 {
1123   return META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
1124 }
1125 
1126 void
meta_window_actor_set_geometry_scale(MetaWindowActor * window_actor,int geometry_scale)1127 meta_window_actor_set_geometry_scale (MetaWindowActor *window_actor,
1128                                       int              geometry_scale)
1129 {
1130   MetaWindowActorPrivate *priv =
1131     meta_window_actor_get_instance_private (window_actor);
1132   graphene_matrix_t child_transform;
1133 
1134   if (priv->geometry_scale == geometry_scale)
1135     return;
1136 
1137   priv->geometry_scale = geometry_scale;
1138 
1139   graphene_matrix_init_scale (&child_transform,
1140                               geometry_scale,
1141                               geometry_scale,
1142                               1);
1143   clutter_actor_set_child_transform (CLUTTER_ACTOR (window_actor),
1144                                      &child_transform);
1145 }
1146 
1147 int
meta_window_actor_get_geometry_scale(MetaWindowActor * window_actor)1148 meta_window_actor_get_geometry_scale (MetaWindowActor *window_actor)
1149 {
1150   MetaWindowActorPrivate *priv =
1151     meta_window_actor_get_instance_private (window_actor);
1152 
1153   return priv->geometry_scale;
1154 }
1155 
1156 static void
meta_window_actor_get_buffer_bounds(MetaScreenCastWindow * screen_cast_window,MetaRectangle * bounds)1157 meta_window_actor_get_buffer_bounds (MetaScreenCastWindow *screen_cast_window,
1158                                      MetaRectangle        *bounds)
1159 {
1160   MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window);
1161   MetaWindowActorPrivate *priv =
1162     meta_window_actor_get_instance_private (window_actor);
1163   MetaShapedTexture *stex;
1164   int buffer_scale;
1165 
1166   stex = meta_surface_actor_get_texture (priv->surface);
1167   buffer_scale = meta_shaped_texture_get_buffer_scale (stex);
1168   *bounds = (MetaRectangle) {
1169     .width = meta_shaped_texture_get_width (stex) * buffer_scale,
1170     .height = meta_shaped_texture_get_height (stex) * buffer_scale,
1171   };
1172 }
1173 
1174 static void
meta_window_actor_transform_relative_position(MetaScreenCastWindow * screen_cast_window,double x,double y,double * x_out,double * y_out)1175 meta_window_actor_transform_relative_position (MetaScreenCastWindow *screen_cast_window,
1176                                                double                x,
1177                                                double                y,
1178                                                double               *x_out,
1179                                                double               *y_out)
1180 
1181 {
1182   MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window);
1183   MetaWindowActorPrivate *priv =
1184     meta_window_actor_get_instance_private (window_actor);
1185   MetaRectangle bounds;
1186   graphene_point3d_t v1 = { 0.f, }, v2 = { 0.f, };
1187 
1188   meta_window_actor_get_buffer_bounds (screen_cast_window, &bounds);
1189 
1190   v1.x = CLAMP ((float) x,
1191                 bounds.x,
1192                 bounds.x + bounds.width);
1193   v1.y = CLAMP ((float) y,
1194                 bounds.y,
1195                 bounds.y + bounds.height);
1196 
1197   clutter_actor_apply_transform_to_point (CLUTTER_ACTOR (priv->surface),
1198                                           &v1,
1199                                           &v2);
1200 
1201   *x_out = (double) v2.x;
1202   *y_out = (double) v2.y;
1203 }
1204 
1205 static gboolean
meta_window_actor_transform_cursor_position(MetaScreenCastWindow * screen_cast_window,MetaCursorSprite * cursor_sprite,graphene_point_t * cursor_position,float * out_cursor_scale,graphene_point_t * out_relative_cursor_position)1206 meta_window_actor_transform_cursor_position (MetaScreenCastWindow *screen_cast_window,
1207                                              MetaCursorSprite     *cursor_sprite,
1208                                              graphene_point_t     *cursor_position,
1209                                              float                *out_cursor_scale,
1210                                              graphene_point_t     *out_relative_cursor_position)
1211 {
1212   MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window);
1213   MetaWindowActorPrivate *priv =
1214     meta_window_actor_get_instance_private (window_actor);
1215   MetaWindow *window;
1216 
1217   window = priv->window;
1218   if (!meta_window_has_pointer (window))
1219     return FALSE;
1220 
1221   if (cursor_sprite &&
1222       meta_cursor_sprite_get_cogl_texture (cursor_sprite) &&
1223       out_cursor_scale)
1224     {
1225       MetaShapedTexture *stex;
1226       double texture_scale;
1227       float cursor_texture_scale;
1228 
1229       stex = meta_surface_actor_get_texture (priv->surface);
1230       texture_scale = meta_shaped_texture_get_buffer_scale (stex);
1231       cursor_texture_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite);
1232 
1233       *out_cursor_scale = texture_scale / cursor_texture_scale;
1234     }
1235 
1236   if (out_relative_cursor_position)
1237     {
1238       clutter_actor_transform_stage_point (CLUTTER_ACTOR (priv->surface),
1239                                            cursor_position->x,
1240                                            cursor_position->y,
1241                                            &out_relative_cursor_position->x,
1242                                            &out_relative_cursor_position->y);
1243     }
1244 
1245   return TRUE;
1246 }
1247 
1248 static void
meta_window_actor_capture_into(MetaScreenCastWindow * screen_cast_window,MetaRectangle * bounds,uint8_t * data)1249 meta_window_actor_capture_into (MetaScreenCastWindow *screen_cast_window,
1250                                 MetaRectangle        *bounds,
1251                                 uint8_t              *data)
1252 {
1253   MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window);
1254   cairo_surface_t *image;
1255   uint8_t *cr_data;
1256   int cr_stride;
1257   int cr_width;
1258   int cr_height;
1259   int bpp = 4;
1260 
1261   if (meta_window_actor_is_destroyed (window_actor))
1262     return;
1263 
1264   image = meta_window_actor_get_image (window_actor, bounds);
1265   cr_data = cairo_image_surface_get_data (image);
1266   cr_width = cairo_image_surface_get_width (image);
1267   cr_height = cairo_image_surface_get_height (image);
1268   cr_stride = cairo_image_surface_get_stride (image);
1269 
1270   if (cr_width == bounds->width && cr_height == bounds->height)
1271     {
1272       memcpy (data, cr_data, cr_height * cr_stride);
1273     }
1274   else
1275     {
1276       int width = MIN (bounds->width, cr_width);
1277       int height = MIN (bounds->height, cr_height);
1278       int stride = width * bpp;
1279       uint8_t *src, *dst;
1280 
1281       src = cr_data;
1282       dst = data;
1283 
1284       for (int i = 0; i < height; i++)
1285         {
1286           memcpy (dst, src, stride);
1287           if (width < bounds->width)
1288             memset (dst + stride, 0, (bounds->width * bpp) - stride);
1289 
1290           src += cr_stride;
1291           dst += bounds->width * bpp;
1292         }
1293 
1294       for (int i = height; i < bounds->height; i++)
1295         {
1296           memset (dst, 0, bounds->width * bpp);
1297           dst += bounds->width * bpp;
1298         }
1299     }
1300 
1301   cairo_surface_destroy (image);
1302 }
1303 
1304 static gboolean
meta_window_actor_blit_to_framebuffer(MetaScreenCastWindow * screen_cast_window,MetaRectangle * bounds,CoglFramebuffer * framebuffer)1305 meta_window_actor_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window,
1306                                        MetaRectangle        *bounds,
1307                                        CoglFramebuffer      *framebuffer)
1308 {
1309   MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window);
1310   ClutterActor *actor = CLUTTER_ACTOR (window_actor);
1311   ClutterPaintContext *paint_context;
1312   MetaRectangle scaled_clip;
1313   CoglColor clear_color;
1314   float resource_scale;
1315   float width, height;
1316   float x, y;
1317 
1318   if (meta_window_actor_is_destroyed (window_actor))
1319     return FALSE;
1320 
1321   clutter_actor_get_size (actor, &width, &height);
1322 
1323   if (width == 0 || height == 0)
1324     return FALSE;
1325 
1326   resource_scale = clutter_actor_get_resource_scale (actor);
1327 
1328   clutter_actor_inhibit_culling (actor);
1329 
1330   width = ceilf (width * resource_scale);
1331   height = ceilf (height * resource_scale);
1332 
1333   clutter_actor_get_position (actor, &x, &y);
1334 
1335   cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0);
1336   cogl_framebuffer_clear (framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color);
1337   cogl_framebuffer_orthographic (framebuffer, 0, 0, width, height, 0, 1.0);
1338   cogl_framebuffer_set_viewport (framebuffer, 0, 0, width, height);
1339 
1340   meta_rectangle_scale_double (bounds, resource_scale,
1341                                META_ROUNDING_STRATEGY_GROW,
1342                                &scaled_clip);
1343   meta_rectangle_intersect (&scaled_clip,
1344                             &(MetaRectangle) {
1345                               .width = width,
1346                               .height = height,
1347                             },
1348                             &scaled_clip);
1349 
1350   cogl_framebuffer_push_rectangle_clip (framebuffer,
1351                                         scaled_clip.x, scaled_clip.y,
1352                                         scaled_clip.x + scaled_clip.width,
1353                                         scaled_clip.y + scaled_clip.height);
1354 
1355   cogl_framebuffer_push_matrix (framebuffer);
1356   cogl_framebuffer_scale (framebuffer, resource_scale, resource_scale, 1);
1357   cogl_framebuffer_translate (framebuffer, -x, -y, 0);
1358 
1359   paint_context =
1360     clutter_paint_context_new_for_framebuffer (framebuffer, NULL,
1361                                                CLUTTER_PAINT_FLAG_NONE);
1362   clutter_actor_paint (actor, paint_context);
1363   clutter_paint_context_destroy (paint_context);
1364 
1365   cogl_framebuffer_pop_matrix (framebuffer);
1366   cogl_framebuffer_pop_clip (framebuffer);
1367 
1368   clutter_actor_uninhibit_culling (actor);
1369 
1370   return TRUE;
1371 }
1372 
1373 static gboolean
meta_window_actor_has_damage(MetaScreenCastWindow * screen_cast_window)1374 meta_window_actor_has_damage (MetaScreenCastWindow *screen_cast_window)
1375 {
1376   return clutter_actor_has_damage (CLUTTER_ACTOR (screen_cast_window));
1377 }
1378 
1379 static void
screen_cast_window_iface_init(MetaScreenCastWindowInterface * iface)1380 screen_cast_window_iface_init (MetaScreenCastWindowInterface *iface)
1381 {
1382   iface->get_buffer_bounds = meta_window_actor_get_buffer_bounds;
1383   iface->transform_relative_position = meta_window_actor_transform_relative_position;
1384   iface->transform_cursor_position = meta_window_actor_transform_cursor_position;
1385   iface->capture_into = meta_window_actor_capture_into;
1386   iface->blit_to_framebuffer = meta_window_actor_blit_to_framebuffer;
1387   iface->has_damage = meta_window_actor_has_damage;
1388 }
1389 
1390 MetaWindowActor *
meta_window_actor_from_actor(ClutterActor * actor)1391 meta_window_actor_from_actor (ClutterActor *actor)
1392 {
1393   if (!META_IS_SURFACE_ACTOR (actor))
1394     return NULL;
1395 
1396   do
1397     {
1398       actor = clutter_actor_get_parent (actor);
1399 
1400       if (META_IS_WINDOW_ACTOR (actor))
1401         return META_WINDOW_ACTOR (actor);
1402     }
1403   while (actor != NULL);
1404 
1405   return NULL;
1406 }
1407 
1408 void
meta_window_actor_notify_damaged(MetaWindowActor * window_actor)1409 meta_window_actor_notify_damaged (MetaWindowActor *window_actor)
1410 {
1411   g_signal_emit (window_actor, signals[DAMAGED], 0);
1412 }
1413 
1414 static CoglFramebuffer *
create_framebuffer_from_window_actor(MetaWindowActor * self,MetaRectangle * clip,GError ** error)1415 create_framebuffer_from_window_actor (MetaWindowActor  *self,
1416                                       MetaRectangle    *clip,
1417                                       GError          **error)
1418 {
1419   ClutterActor *actor = CLUTTER_ACTOR (self);
1420   MetaBackend *backend = meta_get_backend ();
1421   ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
1422   CoglContext *cogl_context =
1423     clutter_backend_get_cogl_context (clutter_backend);
1424   CoglTexture2D *texture;
1425   CoglOffscreen *offscreen;
1426   CoglFramebuffer *framebuffer;
1427   CoglColor clear_color;
1428   ClutterPaintContext *paint_context;
1429   float resource_scale;
1430 
1431   resource_scale = clutter_actor_get_resource_scale (actor);
1432 
1433   texture = cogl_texture_2d_new_with_size (cogl_context,
1434                                            clip->width * resource_scale,
1435                                            clip->height * resource_scale);
1436   if (!texture)
1437     return NULL;
1438 
1439   cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (texture),
1440                                           FALSE);
1441 
1442   offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture));
1443   framebuffer = COGL_FRAMEBUFFER (offscreen);
1444 
1445   cogl_object_unref (texture);
1446 
1447   if (!cogl_framebuffer_allocate (framebuffer, error))
1448     {
1449       g_object_unref (framebuffer);
1450       return NULL;
1451     }
1452 
1453   cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0);
1454   cogl_framebuffer_clear (framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color);
1455   cogl_framebuffer_orthographic (framebuffer, 0, 0, clip->width, clip->height,
1456                                  0, 1.0);
1457   cogl_framebuffer_translate (framebuffer, -clip->x, -clip->y, 0);
1458 
1459   paint_context =
1460     clutter_paint_context_new_for_framebuffer (framebuffer, NULL,
1461                                                CLUTTER_PAINT_FLAG_NONE);
1462   clutter_actor_paint (actor, paint_context);
1463   clutter_paint_context_destroy (paint_context);
1464 
1465   return framebuffer;
1466 }
1467 
1468 /**
1469  * meta_window_actor_get_image:
1470  * @self: A #MetaWindowActor
1471  * @clip: (nullable): A clipping rectangle, to help prevent extra processing.
1472  * In the case that the clipping rectangle is partially or fully
1473  * outside the bounds of the actor, the rectangle will be clipped.
1474  *
1475  * Flattens the layers of @self into one ARGB32 image by alpha blending
1476  * the images, and returns the flattened image.
1477  *
1478  * Returns: (nullable) (transfer full): a new cairo surface to be freed with
1479  * cairo_surface_destroy().
1480  */
1481 cairo_surface_t *
meta_window_actor_get_image(MetaWindowActor * self,MetaRectangle * clip)1482 meta_window_actor_get_image (MetaWindowActor *self,
1483                              MetaRectangle   *clip)
1484 {
1485   MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self);
1486   ClutterActor *actor = CLUTTER_ACTOR (self);
1487   MetaShapedTexture *stex;
1488   cairo_surface_t *surface = NULL;
1489   CoglFramebuffer *framebuffer;
1490   MetaRectangle framebuffer_clip;
1491   float resource_scale;
1492   float x, y, width, height;
1493 
1494   if (!priv->surface)
1495     return NULL;
1496 
1497   clutter_actor_inhibit_culling (actor);
1498 
1499   stex = meta_surface_actor_get_texture (priv->surface);
1500   if (!meta_shaped_texture_should_get_via_offscreen (stex) &&
1501       clutter_actor_get_n_children (actor) == 1)
1502     {
1503       MetaRectangle *surface_clip = NULL;
1504 
1505       if (clip)
1506         {
1507           int geometry_scale;
1508 
1509           geometry_scale =
1510             meta_window_actor_get_geometry_scale (self);
1511 
1512           surface_clip = g_alloca (sizeof (MetaRectangle));
1513           surface_clip->x = clip->x / geometry_scale,
1514           surface_clip->y = clip->y / geometry_scale;
1515           surface_clip->width = clip->width / geometry_scale;
1516           surface_clip->height = clip->height / geometry_scale;
1517         }
1518 
1519       surface = meta_shaped_texture_get_image (stex, surface_clip);
1520       goto out;
1521     }
1522 
1523   clutter_actor_get_position (actor, &x, &y);
1524   clutter_actor_get_size (actor, &width, &height);
1525 
1526   if (width == 0 || height == 0)
1527     goto out;
1528 
1529   framebuffer_clip = (MetaRectangle) {
1530     .x = floorf (x),
1531     .y = floorf (y),
1532     .width = ceilf (width),
1533     .height = ceilf (height),
1534   };
1535 
1536   if (clip)
1537     {
1538       MetaRectangle tmp_clip;
1539       MetaRectangle intersected_clip;
1540 
1541       tmp_clip = *clip;
1542       tmp_clip.x += floorf (x);
1543       tmp_clip.y += floorf (y);
1544       if (!meta_rectangle_intersect (&framebuffer_clip,
1545                                      &tmp_clip,
1546                                      &intersected_clip))
1547         goto out;
1548 
1549       framebuffer_clip = intersected_clip;
1550     }
1551 
1552   framebuffer = create_framebuffer_from_window_actor (self,
1553                                                       &framebuffer_clip,
1554                                                       NULL);
1555   if (!framebuffer)
1556     goto out;
1557 
1558   resource_scale = clutter_actor_get_resource_scale (actor);
1559   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
1560                                         framebuffer_clip.width *
1561                                         resource_scale,
1562                                         framebuffer_clip.height *
1563                                         resource_scale);
1564   cogl_framebuffer_read_pixels (framebuffer,
1565                                 0, 0,
1566                                 framebuffer_clip.width * resource_scale,
1567                                 framebuffer_clip.height * resource_scale,
1568                                 CLUTTER_CAIRO_FORMAT_ARGB32,
1569                                 cairo_image_surface_get_data (surface));
1570 
1571   g_object_unref (framebuffer);
1572 
1573   cairo_surface_mark_dirty (surface);
1574 
1575 out:
1576   clutter_actor_uninhibit_culling (actor);
1577   return surface;
1578 }
1579 
1580 /**
1581  * meta_window_actor_paint_to_content:
1582  * @self: A #MetaWindowActor
1583  * @clip: (nullable): A clipping rectangle, in actor coordinates, to help
1584  * prevent extra processing.
1585  * In the case that the clipping rectangle is partially or fully
1586  * outside the bounds of the actor, the rectangle will be clipped.
1587  * @error: A #GError to catch exceptional errors or %NULL.
1588  *
1589  * Returns: (nullable) (transfer full): a new #ClutterContent
1590  */
1591 ClutterContent *
meta_window_actor_paint_to_content(MetaWindowActor * self,MetaRectangle * clip,GError ** error)1592 meta_window_actor_paint_to_content (MetaWindowActor  *self,
1593                                     MetaRectangle    *clip,
1594                                     GError          **error)
1595 {
1596   MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self);
1597   ClutterActor *actor = CLUTTER_ACTOR (self);
1598   ClutterContent *content = NULL;
1599   CoglFramebuffer *framebuffer;
1600   CoglTexture *texture;
1601   MetaRectangle framebuffer_clip;
1602   float x, y, width, height;
1603 
1604   if (!priv->surface)
1605     return NULL;
1606 
1607   clutter_actor_inhibit_culling (actor);
1608 
1609   clutter_actor_get_position (actor, &x, &y);
1610   clutter_actor_get_size (actor, &width, &height);
1611 
1612   if (width == 0 || height == 0)
1613     goto out;
1614 
1615   framebuffer_clip = (MetaRectangle) {
1616     .x = floorf (x),
1617     .y = floorf (y),
1618     .width = ceilf (width),
1619     .height = ceilf (height),
1620   };
1621 
1622   if (clip)
1623     {
1624       MetaRectangle tmp_clip;
1625 
1626       if (!meta_rectangle_intersect (&framebuffer_clip, clip, &tmp_clip))
1627         goto out;
1628 
1629       framebuffer_clip = tmp_clip;
1630     }
1631 
1632   framebuffer = create_framebuffer_from_window_actor (self,
1633                                                       &framebuffer_clip,
1634                                                       error);
1635   if (!framebuffer)
1636     goto out;
1637 
1638   texture = cogl_offscreen_get_texture (COGL_OFFSCREEN (framebuffer));
1639   content = clutter_texture_content_new_from_texture (texture, NULL);
1640 
1641   g_object_unref (framebuffer);
1642 
1643 out:
1644   clutter_actor_uninhibit_culling (actor);
1645   return content;
1646 }
1647