diff options
author | Florian Müllner <fmuellner@gnome.org> | 2021-07-19 00:01:24 +0200 |
---|---|---|
committer | Florian Müllner <fmuellner@gnome.org> | 2021-07-19 00:03:33 +0200 |
commit | 952865a86ebb08f97263cfdbfe38b7adc20e4560 (patch) | |
tree | 1f9347628656210b03ceee4fae83beb21491d1eb /src/compositor/meta-window-actor.c | |
parent | 7862f143937e43dca0513af3a24dabfb4d0db4fc (diff) | |
download | mutter-master.tar.gz |
Replace contents with redirect messagemaster
The default development branch is now `main`. This commit only exists
on `master` to point people towards that.
See https://gitlab.gnome.org/GNOME/glib/-/issues/2348 for details.
Diffstat (limited to 'src/compositor/meta-window-actor.c')
-rw-r--r-- | src/compositor/meta-window-actor.c | 1559 |
1 files changed, 0 insertions, 1559 deletions
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c deleted file mode 100644 index d4fc9a43a..000000000 --- a/src/compositor/meta-window-actor.c +++ /dev/null @@ -1,1559 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/** - * SECTION:meta-window-actor - * @title: MetaWindowActor - * @short_description: An actor representing a top-level window in the scene - * graph - * - * #MetaWindowActor is a #ClutterActor that adds a notion of a window to the - * Clutter scene graph. It contains a #MetaWindow which provides the windowing - * API, and the #MetaCompositor that handles it. For the actual content of the - * window, it contains a #MetaSurfaceActor. - * - * #MetaWindowActor takes care of the rendering features you need for your - * window. For example, it will take the windows' requested opacity and use - * that for clutter_actor_set_opacity(). Furthermore, it will also draw a - * shadow around the window (using #MetaShadow) and deal with synchronization - * between events of the window and the actual render loop. See - * MetaWindowActor::first-frame for an example of the latter. - */ - -#include "config.h" - -#include <gdk/gdk.h> -#include <math.h> -#include <string.h> - -#include "backends/meta-screen-cast-window.h" -#include "compositor/compositor-private.h" -#include "compositor/meta-cullable.h" -#include "compositor/meta-shaped-texture-private.h" -#include "compositor/meta-surface-actor-x11.h" -#include "compositor/meta-surface-actor.h" -#include "compositor/meta-window-actor-private.h" -#include "core/boxes-private.h" -#include "core/window-private.h" -#include "meta/window.h" - -#ifdef HAVE_WAYLAND -#include "compositor/meta-surface-actor-wayland.h" -#include "wayland/meta-wayland-surface.h" -#endif - -typedef enum -{ - INITIALLY_FROZEN, - DRAWING_FIRST_FRAME, - EMITTED_FIRST_FRAME -} FirstFrameState; - -typedef struct _MetaWindowActorPrivate -{ - MetaWindow *window; - MetaCompositor *compositor; - - MetaSurfaceActor *surface; - - int geometry_scale; - - /* - * These need to be counters rather than flags, since more plugins - * can implement same effect; the practicality of stacking effects - * might be dubious, but we have to at least handle it correctly. - */ - gint minimize_in_progress; - gint unminimize_in_progress; - gint size_change_in_progress; - gint map_in_progress; - gint destroy_in_progress; - - guint freeze_count; - - guint visible : 1; - guint disposed : 1; - - guint needs_destroy : 1; - - guint updates_frozen : 1; - guint first_frame_state : 2; /* FirstFrameState */ -} MetaWindowActorPrivate; - -enum -{ - FIRST_FRAME, - EFFECTS_COMPLETED, - DAMAGED, - THAWED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -enum -{ - PROP_META_WINDOW = 1, -}; - -static void meta_window_actor_dispose (GObject *object); -static void meta_window_actor_constructed (GObject *object); -static void meta_window_actor_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void meta_window_actor_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); - -static void meta_window_actor_real_assign_surface_actor (MetaWindowActor *self, - MetaSurfaceActor *surface_actor); - -static void cullable_iface_init (MetaCullableInterface *iface); - -static void screen_cast_window_iface_init (MetaScreenCastWindowInterface *iface); - -G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaWindowActor, meta_window_actor, CLUTTER_TYPE_ACTOR, - G_ADD_PRIVATE (MetaWindowActor) - G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init) - G_IMPLEMENT_INTERFACE (META_TYPE_SCREEN_CAST_WINDOW, screen_cast_window_iface_init)); - -static void -meta_window_actor_class_init (MetaWindowActorClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *pspec; - - object_class->dispose = meta_window_actor_dispose; - object_class->set_property = meta_window_actor_set_property; - object_class->get_property = meta_window_actor_get_property; - object_class->constructed = meta_window_actor_constructed; - - klass->assign_surface_actor = meta_window_actor_real_assign_surface_actor; - - /** - * MetaWindowActor::first-frame: - * @actor: the #MetaWindowActor instance - * - * The ::first-frame signal will be emitted the first time a frame - * of window contents has been drawn by the application and Mutter - * has had the chance to drawn that frame to the screen. If the - * window starts off initially hidden, obscured, or on on a - * different workspace, the ::first-frame signal will be emitted - * even though the user doesn't see the contents. - * - * MetaDisplay::window-created is a good place to connect to this - * signal - at that point, the MetaWindowActor for the window - * exists, but the window has reliably not yet been drawn. - * Connecting to an existing window that has already been drawn to - * the screen is not useful. - */ - signals[FIRST_FRAME] = - g_signal_new ("first-frame", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - /** - * MetaWindowActor::effects-completed: - * @actor: the #MetaWindowActor instance - * - * The ::effects-completed signal will be emitted once all pending compositor - * effects are completed. - */ - signals[EFFECTS_COMPLETED] = - g_signal_new ("effects-completed", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - /** - * MetaWindowActor::damaged: - * @actor: the #MetaWindowActor instance - * - * Notify that one or more of the surfaces of the window have been damaged. - */ - signals[DAMAGED] = - g_signal_new ("damaged", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - /** - * MetaWindowActor::thawed: - * @actor: the #MetaWindowActor instance - */ - signals[THAWED] = - g_signal_new ("thawed", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - pspec = g_param_spec_object ("meta-window", - "MetaWindow", - "The displayed MetaWindow", - META_TYPE_WINDOW, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - - g_object_class_install_property (object_class, - PROP_META_WINDOW, - pspec); -} - -static void -meta_window_actor_init (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - priv->geometry_scale = 1; -} - -static void -window_appears_focused_notify (MetaWindow *mw, - GParamSpec *arg1, - gpointer data) -{ - clutter_actor_queue_redraw (CLUTTER_ACTOR (data)); -} - -gboolean -meta_window_actor_is_opaque (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaWindow *window = priv->window; - - if (window->opacity != 0xff) - return FALSE; - - if (!priv->surface) - return FALSE; - - return meta_surface_actor_is_opaque (priv->surface); -} - -gboolean -meta_window_actor_is_frozen (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - return priv->surface == NULL || priv->freeze_count > 0; -} - -void -meta_window_actor_update_regions (MetaWindowActor *self) -{ - META_WINDOW_ACTOR_GET_CLASS (self)->update_regions (self); -} - -gboolean -meta_window_actor_can_freeze_commits (MetaWindowActor *self) -{ - g_return_val_if_fail (META_IS_WINDOW_ACTOR (self), FALSE); - - return META_WINDOW_ACTOR_GET_CLASS (self)->can_freeze_commits (self); -} - -static void -meta_window_actor_set_frozen (MetaWindowActor *self, - gboolean frozen) -{ - ClutterActor *child; - ClutterActorIter iter; - - clutter_actor_iter_init (&iter, CLUTTER_ACTOR (self)); - while (clutter_actor_iter_next (&iter, &child)) - { - if (META_IS_SURFACE_ACTOR (child)) - meta_surface_actor_set_frozen (META_SURFACE_ACTOR (child), frozen); - } - - META_WINDOW_ACTOR_GET_CLASS (self)->set_frozen (self, frozen); -} - -/** - * meta_window_actor_freeze: - * @self: The #MetaWindowActor - * - * Freezes the #MetaWindowActor, which inhibits updates and geometry - * changes of the window. This property is refcounted, so make sure - * to call meta_window_actor_thaw() the exact same amount of times - * as this function to allow updates again. - */ -void -meta_window_actor_freeze (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv; - - g_return_if_fail (META_IS_WINDOW_ACTOR (self)); - - priv = meta_window_actor_get_instance_private (self); - - if (priv->freeze_count == 0 && priv->surface) - meta_window_actor_set_frozen (self, TRUE); - - priv->freeze_count ++; -} - -static void -meta_window_actor_sync_thawed_state (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - if (priv->first_frame_state == INITIALLY_FROZEN) - priv->first_frame_state = DRAWING_FIRST_FRAME; - - if (priv->surface) - meta_window_actor_set_frozen (self, FALSE); - - /* We sometimes ignore moves and resizes on frozen windows */ - meta_window_actor_sync_actor_geometry (self, FALSE); -} - -/** - * meta_window_actor_thaw: - * @self: The #MetaWindowActor - * - * Thaws/unfreezes the #MetaWindowActor to allow updates and geometry - * changes after a window was frozen using meta_window_actor_freeze(). - */ -void -meta_window_actor_thaw (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv; - - g_return_if_fail (META_IS_WINDOW_ACTOR (self)); - - priv = meta_window_actor_get_instance_private (self); - - if (priv->freeze_count <= 0) - g_error ("Error in freeze/thaw accounting"); - - priv->freeze_count--; - if (priv->freeze_count > 0) - return; - - /* We still might be frozen due to lack of a MetaSurfaceActor */ - if (meta_window_actor_is_frozen (self)) - return; - - meta_window_actor_sync_thawed_state (self); - - g_signal_emit (self, signals[THAWED], 0); -} - -static void -meta_window_actor_real_assign_surface_actor (MetaWindowActor *self, - MetaSurfaceActor *surface_actor) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - g_clear_object (&priv->surface); - priv->surface = g_object_ref_sink (surface_actor); - - if (meta_window_actor_is_frozen (self)) - meta_window_actor_set_frozen (self, TRUE); - else - meta_window_actor_sync_thawed_state (self); -} - -void -meta_window_actor_assign_surface_actor (MetaWindowActor *self, - MetaSurfaceActor *surface_actor) -{ - META_WINDOW_ACTOR_GET_CLASS (self)->assign_surface_actor (self, - surface_actor); -} - -static void -init_surface_actor (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaWindow *window = priv->window; - MetaSurfaceActor *surface_actor; - - if (!meta_is_wayland_compositor ()) - surface_actor = meta_surface_actor_x11_new (window); -#ifdef HAVE_WAYLAND - else if (window->surface) - surface_actor = meta_wayland_surface_get_actor (window->surface); -#endif - else - surface_actor = NULL; - - if (surface_actor) - meta_window_actor_assign_surface_actor (self, surface_actor); -} - -static void -meta_window_actor_constructed (GObject *object) -{ - MetaWindowActor *self = META_WINDOW_ACTOR (object); - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaWindow *window = priv->window; - - priv->compositor = window->display->compositor; - - /* Hang our compositor window state off the MetaWindow for fast retrieval */ - meta_window_set_compositor_private (window, object); - - init_surface_actor (self); - - meta_window_actor_update_opacity (self); - - meta_window_actor_sync_updates_frozen (self); - - if (meta_window_actor_is_frozen (self)) - priv->first_frame_state = INITIALLY_FROZEN; - else - priv->first_frame_state = DRAWING_FIRST_FRAME; - - meta_window_actor_sync_actor_geometry (self, priv->window->placed); -} - -static void -meta_window_actor_dispose (GObject *object) -{ - MetaWindowActor *self = META_WINDOW_ACTOR (object); - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaCompositor *compositor = priv->compositor; - - if (priv->disposed) - { - G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object); - return; - } - - priv->disposed = TRUE; - - meta_compositor_remove_window_actor (compositor, self); - - g_clear_object (&priv->window); - - if (priv->surface) - { - clutter_actor_remove_child (CLUTTER_ACTOR (self), - CLUTTER_ACTOR (priv->surface)); - g_clear_object (&priv->surface); - } - - G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object); -} - -static void -meta_window_actor_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MetaWindowActor *self = META_WINDOW_ACTOR (object); - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - switch (prop_id) - { - case PROP_META_WINDOW: - priv->window = g_value_dup_object (value); - g_signal_connect_object (priv->window, "notify::appears-focused", - G_CALLBACK (window_appears_focused_notify), self, 0); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_window_actor_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaWindowActor *self = META_WINDOW_ACTOR (object); - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - switch (prop_id) - { - case PROP_META_WINDOW: - g_value_set_object (value, priv->window); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/** - * meta_window_actor_get_meta_window: - * @self: a #MetaWindowActor - * - * Gets the #MetaWindow object that the the #MetaWindowActor is displaying - * - * Return value: (transfer none): the displayed #MetaWindow - */ -MetaWindow * -meta_window_actor_get_meta_window (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - return priv->window; -} - -/** - * meta_window_actor_get_texture: - * @self: a #MetaWindowActor - * - * Gets the ClutterActor that is used to display the contents of the window, - * or NULL if no texture is shown yet, because the window is not mapped. - * - * Return value: (transfer none): the #ClutterActor for the contents - */ -MetaShapedTexture * -meta_window_actor_get_texture (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - if (priv->surface) - return meta_surface_actor_get_texture (priv->surface); - else - return NULL; -} - -/** - * meta_window_actor_get_surface: - * @self: a #MetaWindowActor - * - * Gets the MetaSurfaceActor that draws the content of this window, - * or NULL if there is no surface yet associated with this window. - * - * Return value: (transfer none): the #MetaSurfaceActor for the contents - */ -MetaSurfaceActor * -meta_window_actor_get_surface (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - return priv->surface; -} - -/** - * meta_window_actor_is_destroyed: - * @self: a #MetaWindowActor - * - * Gets whether the X window that the actor was displaying has been destroyed - * - * Return value: %TRUE when the window is destroyed, otherwise %FALSE - */ -gboolean -meta_window_actor_is_destroyed (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - return priv->disposed || priv->needs_destroy; -} - -void -meta_window_actor_queue_frame_drawn (MetaWindowActor *self, - gboolean no_delay_frame) -{ - META_WINDOW_ACTOR_GET_CLASS (self)->queue_frame_drawn (self, - no_delay_frame); -} - -gboolean -meta_window_actor_effect_in_progress (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - return (priv->minimize_in_progress || - priv->size_change_in_progress || - priv->map_in_progress || - priv->destroy_in_progress); -} - -static gboolean -is_freeze_thaw_effect (MetaPluginEffect event) -{ - switch (event) - { - case META_PLUGIN_DESTROY: - return TRUE; - break; - default: - return FALSE; - } -} - -static gboolean -start_simple_effect (MetaWindowActor *self, - MetaPluginEffect event) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaCompositor *compositor = priv->compositor; - MetaPluginManager *plugin_mgr = - meta_compositor_get_plugin_manager (compositor); - gint *counter = NULL; - gboolean use_freeze_thaw = FALSE; - - g_assert (plugin_mgr != NULL); - - switch (event) - { - case META_PLUGIN_NONE: - return FALSE; - case META_PLUGIN_MINIMIZE: - counter = &priv->minimize_in_progress; - break; - case META_PLUGIN_UNMINIMIZE: - counter = &priv->unminimize_in_progress; - break; - case META_PLUGIN_MAP: - counter = &priv->map_in_progress; - break; - case META_PLUGIN_DESTROY: - counter = &priv->destroy_in_progress; - break; - case META_PLUGIN_SIZE_CHANGE: - case META_PLUGIN_SWITCH_WORKSPACE: - g_assert_not_reached (); - break; - } - - g_assert (counter); - - use_freeze_thaw = is_freeze_thaw_effect (event); - - if (use_freeze_thaw) - meta_window_actor_freeze (self); - - (*counter)++; - - if (!meta_plugin_manager_event_simple (plugin_mgr, self, event)) - { - (*counter)--; - if (use_freeze_thaw) - meta_window_actor_thaw (self); - return FALSE; - } - - return TRUE; -} - -static void -meta_window_actor_after_effects (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - ClutterStage *stage; - ClutterSeat *seat; - - stage = CLUTTER_STAGE (clutter_actor_get_stage (CLUTTER_ACTOR (self))); - seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); - - if (priv->needs_destroy) - { - clutter_actor_destroy (CLUTTER_ACTOR (self)); - } - else - { - g_signal_emit (self, signals[EFFECTS_COMPLETED], 0); - meta_window_actor_sync_visibility (self); - meta_window_actor_sync_actor_geometry (self, FALSE); - } - - clutter_stage_repick_device (stage, clutter_seat_get_pointer (seat)); -} - -void -meta_window_actor_effect_completed (MetaWindowActor *self, - MetaPluginEffect event) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - gboolean inconsistent = FALSE; - - /* NB: Keep in mind that when effects get completed it possible - * that the corresponding MetaWindow may have be been destroyed. - * In this case priv->window will == NULL */ - - switch (event) - { - case META_PLUGIN_NONE: - break; - case META_PLUGIN_MINIMIZE: - { - priv->minimize_in_progress--; - if (priv->minimize_in_progress < 0) - { - g_warning ("Error in minimize accounting."); - priv->minimize_in_progress = 0; - inconsistent = TRUE; - } - } - break; - case META_PLUGIN_UNMINIMIZE: - { - priv->unminimize_in_progress--; - if (priv->unminimize_in_progress < 0) - { - g_warning ("Error in unminimize accounting."); - priv->unminimize_in_progress = 0; - inconsistent = TRUE; - } - } - break; - case META_PLUGIN_MAP: - /* - * Make sure that the actor is at the correct place in case - * the plugin fscked. - */ - priv->map_in_progress--; - - if (priv->map_in_progress < 0) - { - g_warning ("Error in map accounting."); - priv->map_in_progress = 0; - inconsistent = TRUE; - } - break; - case META_PLUGIN_DESTROY: - priv->destroy_in_progress--; - - if (priv->destroy_in_progress < 0) - { - g_warning ("Error in destroy accounting."); - priv->destroy_in_progress = 0; - inconsistent = TRUE; - } - break; - case META_PLUGIN_SIZE_CHANGE: - priv->size_change_in_progress--; - if (priv->size_change_in_progress < 0) - { - g_warning ("Error in size change accounting."); - priv->size_change_in_progress = 0; - inconsistent = TRUE; - } - break; - case META_PLUGIN_SWITCH_WORKSPACE: - g_assert_not_reached (); - break; - } - - if (is_freeze_thaw_effect (event) && !inconsistent) - meta_window_actor_thaw (self); - - if (!meta_window_actor_effect_in_progress (self)) - meta_window_actor_after_effects (self); -} - -void -meta_window_actor_queue_destroy (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaWindow *window = priv->window; - MetaWindowType window_type = meta_window_get_window_type (window); - - meta_window_set_compositor_private (window, NULL); - - META_WINDOW_ACTOR_GET_CLASS (self)->queue_destroy (self); - - if (window_type == META_WINDOW_DROPDOWN_MENU || - window_type == META_WINDOW_POPUP_MENU || - window_type == META_WINDOW_TOOLTIP || - window_type == META_WINDOW_NOTIFICATION || - window_type == META_WINDOW_COMBO || - window_type == META_WINDOW_DND || - window_type == META_WINDOW_OVERRIDE_OTHER) - { - /* - * No effects, just kill it. - */ - clutter_actor_destroy (CLUTTER_ACTOR (self)); - return; - } - - priv->needs_destroy = TRUE; - - if (!meta_window_actor_effect_in_progress (self)) - clutter_actor_destroy (CLUTTER_ACTOR (self)); -} - -MetaWindowActorChanges -meta_window_actor_sync_actor_geometry (MetaWindowActor *self, - gboolean did_placement) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaRectangle window_rect; - ClutterActor *actor = CLUTTER_ACTOR (self); - MetaWindowActorChanges changes = 0; - - meta_window_get_buffer_rect (priv->window, &window_rect); - - /* When running as a Wayland compositor we catch size changes when new - * buffers are attached */ - if (META_IS_SURFACE_ACTOR_X11 (priv->surface)) - meta_surface_actor_x11_set_size (META_SURFACE_ACTOR_X11 (priv->surface), - window_rect.width, window_rect.height); - - /* Normally we want freezing a window to also freeze its position; this allows - * windows to atomically move and resize together, either under app control, - * or because the user is resizing from the left/top. But on initial placement - * we need to assign a position, since immediately after the window - * is shown, the map effect will go into effect and prevent further geometry - * updates. - */ - if (meta_window_actor_is_frozen (self) && !did_placement) - return META_WINDOW_ACTOR_CHANGE_POSITION | META_WINDOW_ACTOR_CHANGE_SIZE; - - if (clutter_actor_has_allocation (actor)) - { - ClutterActorBox box; - float old_x, old_y; - float old_width, old_height; - - clutter_actor_get_allocation_box (actor, &box); - - old_x = box.x1; - old_y = box.y1; - old_width = box.x2 - box.x1; - old_height = box.y2 - box.y1; - - if (old_x != window_rect.x || old_y != window_rect.y) - changes |= META_WINDOW_ACTOR_CHANGE_POSITION; - - if (old_width != window_rect.width || old_height != window_rect.height) - changes |= META_WINDOW_ACTOR_CHANGE_SIZE; - } - else - { - changes = META_WINDOW_ACTOR_CHANGE_POSITION | META_WINDOW_ACTOR_CHANGE_SIZE; - } - - if (changes & META_WINDOW_ACTOR_CHANGE_POSITION) - clutter_actor_set_position (actor, window_rect.x, window_rect.y); - - if (changes & META_WINDOW_ACTOR_CHANGE_SIZE) - clutter_actor_set_size (actor, window_rect.width, window_rect.height); - - return changes; -} - -void -meta_window_actor_show (MetaWindowActor *self, - MetaCompEffect effect) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaCompositor *compositor = priv->compositor; - MetaPluginEffect event; - - g_return_if_fail (!priv->visible); - - priv->visible = TRUE; - - switch (effect) - { - case META_COMP_EFFECT_CREATE: - event = META_PLUGIN_MAP; - break; - case META_COMP_EFFECT_UNMINIMIZE: - event = META_PLUGIN_UNMINIMIZE; - break; - case META_COMP_EFFECT_NONE: - event = META_PLUGIN_NONE; - break; - default: - g_assert_not_reached(); - } - - if (event == META_PLUGIN_MAP) - meta_window_actor_sync_actor_geometry (self, TRUE); - - if (meta_compositor_is_switching_workspace (compositor) || - !start_simple_effect (self, event)) - { - clutter_actor_show (CLUTTER_ACTOR (self)); - } -} - -void -meta_window_actor_hide (MetaWindowActor *self, - MetaCompEffect effect) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaCompositor *compositor = priv->compositor; - MetaPluginEffect event; - - g_return_if_fail (priv->visible); - - priv->visible = FALSE; - - /* If a plugin is animating a workspace transition, we have to - * hold off on hiding the window, and do it after the workspace - * switch completes - */ - if (meta_compositor_is_switching_workspace (compositor)) - return; - - switch (effect) - { - case META_COMP_EFFECT_DESTROY: - event = META_PLUGIN_DESTROY; - break; - case META_COMP_EFFECT_MINIMIZE: - event = META_PLUGIN_MINIMIZE; - break; - case META_COMP_EFFECT_NONE: - event = META_PLUGIN_NONE; - break; - default: - g_assert_not_reached(); - } - - if (!start_simple_effect (self, event)) - clutter_actor_hide (CLUTTER_ACTOR (self)); -} - -void -meta_window_actor_size_change (MetaWindowActor *self, - MetaSizeChange which_change, - MetaRectangle *old_frame_rect, - MetaRectangle *old_buffer_rect) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaCompositor *compositor = priv->compositor; - MetaPluginManager *plugin_mgr = - meta_compositor_get_plugin_manager (compositor); - - priv->size_change_in_progress++; - - if (!meta_plugin_manager_event_size_change (plugin_mgr, self, - which_change, old_frame_rect, old_buffer_rect)) - priv->size_change_in_progress--; -} - -#if 0 -/* Print out a region; useful for debugging */ -static void -print_region (cairo_region_t *region) -{ - int n_rects; - int i; - - n_rects = cairo_region_num_rectangles (region); - g_print ("["); - for (i = 0; i < n_rects; i++) - { - cairo_rectangle_int_t rect; - cairo_region_get_rectangle (region, i, &rect); - g_print ("+%d+%dx%dx%d ", - rect.x, rect.y, rect.width, rect.height); - } - g_print ("]\n"); -} -#endif - -#if 0 -/* Dump a region to a PNG file; useful for debugging */ -static void -see_region (cairo_region_t *region, - int width, - int height, - char *filename) -{ - cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); - cairo_t *cr = cairo_create (surface); - - gdk_cairo_region (cr, region); - cairo_fill (cr); - - cairo_surface_write_to_png (surface, filename); - cairo_destroy (cr); - cairo_surface_destroy (surface); -} -#endif - - -static void -meta_window_actor_cull_out (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region) -{ - meta_cullable_cull_out_children (cullable, unobscured_region, clip_region); -} - -static void -meta_window_actor_reset_culling (MetaCullable *cullable) -{ - meta_cullable_reset_culling_children (cullable); -} - -static void -cullable_iface_init (MetaCullableInterface *iface) -{ - iface->cull_out = meta_window_actor_cull_out; - iface->reset_culling = meta_window_actor_reset_culling; -} - -void -meta_window_actor_sync_visibility (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - if (CLUTTER_ACTOR_IS_VISIBLE (self) != priv->visible) - { - if (priv->visible) - clutter_actor_show (CLUTTER_ACTOR (self)); - else - clutter_actor_hide (CLUTTER_ACTOR (self)); - } -} - -void -meta_window_actor_before_paint (MetaWindowActor *self, - ClutterStageView *stage_view) -{ - if (meta_window_actor_is_destroyed (self)) - return; - - META_WINDOW_ACTOR_GET_CLASS (self)->before_paint (self, stage_view); -} - -void -meta_window_actor_after_paint (MetaWindowActor *self, - ClutterStageView *stage_view) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - META_WINDOW_ACTOR_GET_CLASS (self)->after_paint (self, stage_view); - - if (meta_window_actor_is_destroyed (self)) - return; - - if (priv->first_frame_state == DRAWING_FIRST_FRAME) - { - priv->first_frame_state = EMITTED_FIRST_FRAME; - g_signal_emit (self, signals[FIRST_FRAME], 0); - } -} - -void -meta_window_actor_frame_complete (MetaWindowActor *self, - ClutterFrameInfo *frame_info, - gint64 presentation_time) -{ - META_WINDOW_ACTOR_GET_CLASS (self)->frame_complete (self, - frame_info, - presentation_time); -} - -void -meta_window_actor_update_opacity (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaWindow *window = priv->window; - - if (priv->surface) - clutter_actor_set_opacity (CLUTTER_ACTOR (priv->surface), window->opacity); -} - -static void -meta_window_actor_set_updates_frozen (MetaWindowActor *self, - gboolean updates_frozen) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - updates_frozen = updates_frozen != FALSE; - - if (priv->updates_frozen != updates_frozen) - { - priv->updates_frozen = updates_frozen; - if (updates_frozen) - meta_window_actor_freeze (self); - else - meta_window_actor_thaw (self); - } -} - -void -meta_window_actor_sync_updates_frozen (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaWindow *window = priv->window; - - meta_window_actor_set_updates_frozen (self, meta_window_updates_are_frozen (window)); -} - -MetaWindowActor * -meta_window_actor_from_window (MetaWindow *window) -{ - return META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); -} - -void -meta_window_actor_set_geometry_scale (MetaWindowActor *window_actor, - int geometry_scale) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (window_actor); - graphene_matrix_t child_transform; - - if (priv->geometry_scale == geometry_scale) - return; - - priv->geometry_scale = geometry_scale; - - graphene_matrix_init_scale (&child_transform, - geometry_scale, - geometry_scale, - 1); - clutter_actor_set_child_transform (CLUTTER_ACTOR (window_actor), - &child_transform); -} - -int -meta_window_actor_get_geometry_scale (MetaWindowActor *window_actor) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (window_actor); - - return priv->geometry_scale; -} - -static void -meta_window_actor_get_buffer_bounds (MetaScreenCastWindow *screen_cast_window, - MetaRectangle *bounds) -{ - MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (window_actor); - MetaShapedTexture *stex; - int buffer_scale; - - stex = meta_surface_actor_get_texture (priv->surface); - buffer_scale = meta_shaped_texture_get_buffer_scale (stex); - *bounds = (MetaRectangle) { - .width = meta_shaped_texture_get_width (stex) * buffer_scale, - .height = meta_shaped_texture_get_height (stex) * buffer_scale, - }; -} - -static void -meta_window_actor_transform_relative_position (MetaScreenCastWindow *screen_cast_window, - double x, - double y, - double *x_out, - double *y_out) - -{ - MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (window_actor); - MetaRectangle bounds; - graphene_point3d_t v1 = { 0.f, }, v2 = { 0.f, }; - - meta_window_actor_get_buffer_bounds (screen_cast_window, &bounds); - - v1.x = CLAMP ((float) x, - bounds.x, - bounds.x + bounds.width); - v1.y = CLAMP ((float) y, - bounds.y, - bounds.y + bounds.height); - - clutter_actor_apply_transform_to_point (CLUTTER_ACTOR (priv->surface), - &v1, - &v2); - - *x_out = (double) v2.x; - *y_out = (double) v2.y; -} - -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) -{ - MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (window_actor); - MetaWindow *window; - - window = priv->window; - if (!meta_window_has_pointer (window)) - return FALSE; - - if (cursor_sprite && - meta_cursor_sprite_get_cogl_texture (cursor_sprite) && - out_cursor_scale) - { - MetaShapedTexture *stex; - double texture_scale; - float cursor_texture_scale; - - stex = meta_surface_actor_get_texture (priv->surface); - texture_scale = meta_shaped_texture_get_buffer_scale (stex); - cursor_texture_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite); - - *out_cursor_scale = texture_scale / cursor_texture_scale; - } - - if (out_relative_cursor_position) - { - clutter_actor_transform_stage_point (CLUTTER_ACTOR (priv->surface), - cursor_position->x, - cursor_position->y, - &out_relative_cursor_position->x, - &out_relative_cursor_position->y); - } - - return TRUE; -} - -static void -meta_window_actor_capture_into (MetaScreenCastWindow *screen_cast_window, - MetaRectangle *bounds, - uint8_t *data) -{ - MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); - cairo_surface_t *image; - uint8_t *cr_data; - int cr_stride; - int cr_width; - int cr_height; - int bpp = 4; - - if (meta_window_actor_is_destroyed (window_actor)) - return; - - image = meta_window_actor_get_image (window_actor, bounds); - cr_data = cairo_image_surface_get_data (image); - cr_width = cairo_image_surface_get_width (image); - cr_height = cairo_image_surface_get_height (image); - cr_stride = cairo_image_surface_get_stride (image); - - if (cr_width == bounds->width && cr_height == bounds->height) - { - memcpy (data, cr_data, cr_height * cr_stride); - } - else - { - int width = MIN (bounds->width, cr_width); - int height = MIN (bounds->height, cr_height); - int stride = width * bpp; - uint8_t *src, *dst; - - src = cr_data; - dst = data; - - for (int i = 0; i < height; i++) - { - memcpy (dst, src, stride); - if (width < bounds->width) - memset (dst + stride, 0, (bounds->width * bpp) - stride); - - src += cr_stride; - dst += bounds->width * bpp; - } - - for (int i = height; i < bounds->height; i++) - { - memset (dst, 0, bounds->width * bpp); - dst += bounds->width * bpp; - } - } - - cairo_surface_destroy (image); -} - -static gboolean -meta_window_actor_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window, - MetaRectangle *bounds, - CoglFramebuffer *framebuffer) -{ - MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); - ClutterActor *actor = CLUTTER_ACTOR (window_actor); - ClutterPaintContext *paint_context; - MetaRectangle scaled_clip; - CoglColor clear_color; - float resource_scale; - float width, height; - float x, y; - - if (meta_window_actor_is_destroyed (window_actor)) - return FALSE; - - clutter_actor_get_size (actor, &width, &height); - - if (width == 0 || height == 0) - return FALSE; - - resource_scale = clutter_actor_get_resource_scale (actor); - - clutter_actor_inhibit_culling (actor); - - width = ceilf (width * resource_scale); - height = ceilf (height * resource_scale); - - clutter_actor_get_position (actor, &x, &y); - - cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); - cogl_framebuffer_clear (framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color); - cogl_framebuffer_orthographic (framebuffer, 0, 0, width, height, 0, 1.0); - cogl_framebuffer_set_viewport (framebuffer, 0, 0, width, height); - - meta_rectangle_scale_double (bounds, resource_scale, - META_ROUNDING_STRATEGY_GROW, - &scaled_clip); - meta_rectangle_intersect (&scaled_clip, - &(MetaRectangle) { - .width = width, - .height = height, - }, - &scaled_clip); - - cogl_framebuffer_push_rectangle_clip (framebuffer, - scaled_clip.x, scaled_clip.y, - scaled_clip.x + scaled_clip.width, - scaled_clip.y + scaled_clip.height); - - cogl_framebuffer_push_matrix (framebuffer); - cogl_framebuffer_scale (framebuffer, resource_scale, resource_scale, 1); - cogl_framebuffer_translate (framebuffer, -x, -y, 0); - - paint_context = - clutter_paint_context_new_for_framebuffer (framebuffer, NULL, - CLUTTER_PAINT_FLAG_NONE); - clutter_actor_paint (actor, paint_context); - clutter_paint_context_destroy (paint_context); - - cogl_framebuffer_pop_matrix (framebuffer); - cogl_framebuffer_pop_clip (framebuffer); - - clutter_actor_uninhibit_culling (actor); - - return TRUE; -} - -static gboolean -meta_window_actor_has_damage (MetaScreenCastWindow *screen_cast_window) -{ - return clutter_actor_has_damage (CLUTTER_ACTOR (screen_cast_window)); -} - -static void -screen_cast_window_iface_init (MetaScreenCastWindowInterface *iface) -{ - iface->get_buffer_bounds = meta_window_actor_get_buffer_bounds; - iface->transform_relative_position = meta_window_actor_transform_relative_position; - iface->transform_cursor_position = meta_window_actor_transform_cursor_position; - iface->capture_into = meta_window_actor_capture_into; - iface->blit_to_framebuffer = meta_window_actor_blit_to_framebuffer; - iface->has_damage = meta_window_actor_has_damage; -} - -MetaWindowActor * -meta_window_actor_from_actor (ClutterActor *actor) -{ - if (!META_IS_SURFACE_ACTOR (actor)) - return NULL; - - do - { - actor = clutter_actor_get_parent (actor); - - if (META_IS_WINDOW_ACTOR (actor)) - return META_WINDOW_ACTOR (actor); - } - while (actor != NULL); - - return NULL; -} - -void -meta_window_actor_notify_damaged (MetaWindowActor *window_actor) -{ - g_signal_emit (window_actor, signals[DAMAGED], 0); -} - -/** - * meta_window_actor_get_image: - * @self: A #MetaWindowActor - * @clip: (nullable): A clipping rectangle, to help prevent extra processing. - * In the case that the clipping rectangle is partially or fully - * outside the bounds of the actor, the rectangle will be clipped. - * - * Flattens the layers of @self into one ARGB32 image by alpha blending - * the images, and returns the flattened image. - * - * Returns: (nullable) (transfer full): a new cairo surface to be freed with - * cairo_surface_destroy(). - */ -cairo_surface_t * -meta_window_actor_get_image (MetaWindowActor *self, - MetaRectangle *clip) -{ - MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self); - ClutterActor *actor = CLUTTER_ACTOR (self); - MetaBackend *backend = meta_get_backend (); - ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); - CoglContext *cogl_context = - clutter_backend_get_cogl_context (clutter_backend); - float resource_scale; - float width, height; - CoglTexture2D *texture; - g_autoptr (GError) error = NULL; - CoglOffscreen *offscreen; - CoglFramebuffer *framebuffer; - CoglColor clear_color; - float x, y; - MetaRectangle scaled_clip; - ClutterPaintContext *paint_context; - cairo_surface_t *surface = NULL; - - if (!priv->surface) - return NULL; - - clutter_actor_inhibit_culling (actor); - - if (clutter_actor_get_n_children (actor) == 1) - { - MetaShapedTexture *stex; - MetaRectangle *surface_clip = NULL; - - if (clip) - { - - int geometry_scale; - - geometry_scale = - meta_window_actor_get_geometry_scale (self); - - surface_clip = g_alloca (sizeof (MetaRectangle)); - surface_clip->x = clip->x / geometry_scale, - surface_clip->y = clip->y / geometry_scale; - surface_clip->width = clip->width / geometry_scale; - surface_clip->height = clip->height / geometry_scale; - } - - stex = meta_surface_actor_get_texture (priv->surface); - surface = meta_shaped_texture_get_image (stex, surface_clip); - goto out; - } - - clutter_actor_get_size (actor, &width, &height); - - if (width == 0 || height == 0) - goto out; - - resource_scale = clutter_actor_get_resource_scale (actor); - - width = ceilf (width * resource_scale); - height = ceilf (height * resource_scale); - - texture = cogl_texture_2d_new_with_size (cogl_context, width, height); - if (!texture) - goto out; - - cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (texture), - FALSE); - - offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture)); - framebuffer = COGL_FRAMEBUFFER (offscreen); - - cogl_object_unref (texture); - - if (!cogl_framebuffer_allocate (framebuffer, &error)) - { - g_warning ("Failed to allocate framebuffer for screenshot: %s", - error->message); - g_object_unref (framebuffer); - cogl_object_unref (texture); - goto out; - } - - cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); - clutter_actor_get_position (actor, &x, &y); - - cogl_framebuffer_clear (framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color); - cogl_framebuffer_orthographic (framebuffer, 0, 0, width, height, 0, 1.0); - cogl_framebuffer_scale (framebuffer, resource_scale, resource_scale, 1); - cogl_framebuffer_translate (framebuffer, -x, -y, 0); - - paint_context = - clutter_paint_context_new_for_framebuffer (framebuffer, NULL, - CLUTTER_PAINT_FLAG_NONE); - clutter_actor_paint (actor, paint_context); - clutter_paint_context_destroy (paint_context); - - if (clip) - { - meta_rectangle_scale_double (clip, resource_scale, - META_ROUNDING_STRATEGY_GROW, - &scaled_clip); - meta_rectangle_intersect (&scaled_clip, - &(MetaRectangle) { - .width = width, - .height = height, - }, - &scaled_clip); - } - else - { - scaled_clip = (MetaRectangle) { - .width = width, - .height = height, - }; - } - - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - scaled_clip.width, scaled_clip.height); - cogl_framebuffer_read_pixels (framebuffer, - scaled_clip.x, scaled_clip.y, - scaled_clip.width, scaled_clip.height, - CLUTTER_CAIRO_FORMAT_ARGB32, - cairo_image_surface_get_data (surface)); - - g_object_unref (framebuffer); - - cairo_surface_mark_dirty (surface); - -out: - clutter_actor_uninhibit_culling (actor); - return surface; -} |