[mutter] window: Move icon management to X11 implementation



commit aeae90d5d90269c8bc687ea11af67715b951c920
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Sat Jan 29 00:02:24 2022 +0100

    window: Move icon management to X11 implementation
    
    It's still used by e.g. GNOME Shell to produce fallback icons for X11
    applications that doesn't come with a .desktop file. Geometry stays in
    the generic class because it's used for minimize animations and is
    configured by the panel (e.g. the one in gnome-shell-extensions).
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2264>

 src/core/window-private.h    |  17 +++---
 src/core/window.c            | 137 ++++++++-----------------------------------
 src/ui/frames.c              |   2 +-
 src/x11/window-props.c       |   5 +-
 src/x11/window-x11-private.h |   6 ++
 src/x11/window-x11.c         | 124 ++++++++++++++++++++++++++++++++++-----
 6 files changed, 154 insertions(+), 137 deletions(-)
---
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 8305897a47..258445d984 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -60,10 +60,9 @@ typedef enum
 {
   META_QUEUE_CALC_SHOWING = 1 << 0,
   META_QUEUE_MOVE_RESIZE  = 1 << 1,
-  META_QUEUE_UPDATE_ICON  = 1 << 2,
 } MetaQueueType;
 
-#define NUMBER_OF_QUEUES 3
+#define NUMBER_OF_QUEUES 2
 
 typedef enum
 {
@@ -185,9 +184,6 @@ struct _MetaWindow
   char *desc; /* used in debug spew */
   char *title;
 
-  cairo_surface_t *icon;
-  cairo_surface_t *mini_icon;
-
   MetaWindowType type;
 
   /* NOTE these five are not in UTF-8, we just treat them as random
@@ -608,9 +604,10 @@ struct _MetaWindowClass
   void (*get_default_skip_hints) (MetaWindow *window,
                                   gboolean   *skip_taskbar_out,
                                   gboolean   *skip_pager_out);
-  gboolean (*update_icon)        (MetaWindow       *window,
-                                  cairo_surface_t **icon,
-                                  cairo_surface_t **mini_icon);
+
+  cairo_surface_t * (*get_icon) (MetaWindow *window);
+  cairo_surface_t * (*get_mini_icon) (MetaWindow *window);
+
   pid_t (*get_client_pid)        (MetaWindow *window);
   void (*update_main_monitor)    (MetaWindow                   *window,
                                   MetaWindowUpdateMonitorFlags  flags);
@@ -867,6 +864,10 @@ MetaLogicalMonitor * meta_window_get_main_logical_monitor (MetaWindow *window);
 void meta_window_update_monitor (MetaWindow                   *window,
                                  MetaWindowUpdateMonitorFlags  flags);
 
+cairo_surface_t * meta_window_get_icon (MetaWindow *window);
+
+cairo_surface_t * meta_window_get_mini_icon (MetaWindow *window);
+
 void meta_window_set_urgent (MetaWindow *window,
                              gboolean    urgent);
 
diff --git a/src/core/window.c b/src/core/window.c
index 9a82a9e68c..262ec19581 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -26,7 +26,7 @@
  * @short_description: A display-agnostic abstraction for a window.
  *
  * #MetaWindow is the core abstraction in Mutter of a window. It has the
- * properties you'd expect, such as a title, an icon, whether it's fullscreen,
+ * properties you'd expect, such as a title, whether it's fullscreen,
  * has decorations, etc.
  *
  * Since a lot of different kinds of windows exist, each window also a
@@ -161,9 +161,6 @@ static void unminimize_window_and_all_transient_parents (MetaWindow *window);
 
 static void meta_window_propagate_focus_appearance (MetaWindow *window,
                                                     gboolean    focused);
-static void meta_window_update_icon_now (MetaWindow *window,
-                                         gboolean    force);
-
 static void set_workspace_state (MetaWindow    *window,
                                  gboolean       on_all_workspaces,
                                  MetaWorkspace *workspace);
@@ -181,7 +178,6 @@ static void update_edge_constraints (MetaWindow *window);
  */
 static gboolean idle_calc_showing (gpointer data);
 static gboolean idle_move_resize (gpointer data);
-static gboolean idle_update_icon (gpointer data);
 
 G_DEFINE_ABSTRACT_TYPE (MetaWindow, meta_window, G_TYPE_OBJECT);
 
@@ -293,16 +289,6 @@ meta_window_real_get_default_skip_hints (MetaWindow *window,
   *skip_pager_out = FALSE;
 }
 
-static gboolean
-meta_window_real_update_icon (MetaWindow       *window,
-                              cairo_surface_t **icon,
-                              cairo_surface_t **mini_icon)
-{
-  *icon = NULL;
-  *mini_icon = NULL;
-  return FALSE;
-}
-
 static pid_t
 meta_window_real_get_client_pid (MetaWindow *window)
 {
@@ -314,12 +300,6 @@ meta_window_finalize (GObject *object)
 {
   MetaWindow *window = META_WINDOW (object);
 
-  if (window->icon)
-    cairo_surface_destroy (window->icon);
-
-  if (window->mini_icon)
-    cairo_surface_destroy (window->mini_icon);
-
   if (window->frame_bounds)
     cairo_region_destroy (window->frame_bounds);
 
@@ -373,10 +353,10 @@ meta_window_get_property(GObject         *object,
       g_value_set_string (value, win->title);
       break;
     case PROP_ICON:
-      g_value_set_pointer (value, win->icon);
+      g_value_set_pointer (value, meta_window_get_icon (win));
       break;
     case PROP_MINI_ICON:
-      g_value_set_pointer (value, win->mini_icon);
+      g_value_set_pointer (value, meta_window_get_mini_icon (win));
       break;
     case PROP_DECORATED:
       g_value_set_boolean (value, win->decorated);
@@ -479,7 +459,6 @@ meta_window_class_init (MetaWindowClass *klass)
   klass->current_workspace_changed = meta_window_real_current_workspace_changed;
   klass->update_struts = meta_window_real_update_struts;
   klass->get_default_skip_hints = meta_window_real_get_default_skip_hints;
-  klass->update_icon = meta_window_real_update_icon;
   klass->get_client_pid = meta_window_real_get_client_pid;
 
   obj_props[PROP_TITLE] =
@@ -1068,8 +1047,6 @@ _meta_window_shared_new (MetaDisplay         *display,
   window->xvisual = attrs->visual;
 
   window->title = NULL;
-  window->icon = NULL;
-  window->mini_icon = NULL;
 
   window->frame = NULL;
   window->has_focus = FALSE;
@@ -1218,9 +1195,6 @@ _meta_window_shared_new (MetaDisplay         *display,
 
   meta_window_manage (window);
 
-  if (!window->override_redirect)
-    meta_window_update_icon_now (window, TRUE);
-
   if (window->initially_iconic)
     {
       /* WM_HINTS said minimized */
@@ -1578,9 +1552,9 @@ meta_window_unmanage (MetaWindow  *window,
   if (window->maximized_horizontally || window->maximized_vertically)
     unmaximize_window_before_freeing (window);
 
-  meta_window_unqueue (window, META_QUEUE_CALC_SHOWING |
-                               META_QUEUE_MOVE_RESIZE |
-                               META_QUEUE_UPDATE_ICON);
+  meta_window_unqueue (window,
+                       (META_QUEUE_CALC_SHOWING |
+                        META_QUEUE_MOVE_RESIZE));
 
   set_workspace_state (window, FALSE, NULL);
 
@@ -1805,8 +1779,8 @@ meta_window_calc_showing (MetaWindow  *window)
   implement_showing (window, meta_window_should_be_showing (window));
 }
 
-static guint queue_later[NUMBER_OF_QUEUES] = {0, 0, 0};
-static GSList *queue_pending[NUMBER_OF_QUEUES] = {NULL, NULL, NULL};
+static guint queue_later[NUMBER_OF_QUEUES] = {};
+static GSList *queue_pending[NUMBER_OF_QUEUES] = {};
 
 static int
 stackcmp (gconstpointer a, gconstpointer b)
@@ -1989,7 +1963,7 @@ idle_calc_showing (gpointer data)
 
 #ifdef WITH_VERBOSE_MODE
 static const gchar* meta_window_queue_names[NUMBER_OF_QUEUES] =
-  {"calc_showing", "move_resize", "update_icon"};
+  {"calc_showing", "move_resize", };
 #endif
 
 static void
@@ -2053,16 +2027,14 @@ meta_window_queue (MetaWindow   *window,
         {
           const MetaLaterType window_queue_later_when[NUMBER_OF_QUEUES] =
             {
-              META_LATER_CALC_SHOWING, /* CALC_SHOWING */
-              META_LATER_RESIZE,        /* MOVE_RESIZE */
-              META_LATER_BEFORE_REDRAW  /* UPDATE_ICON */
+              META_LATER_CALC_SHOWING,
+              META_LATER_RESIZE,
             };
 
           const GSourceFunc window_queue_later_handler[NUMBER_OF_QUEUES] =
             {
               idle_calc_showing,
               idle_move_resize,
-              idle_update_icon,
             };
 
           if (window->unmanaging)
@@ -5533,85 +5505,26 @@ meta_window_set_icon_geometry (MetaWindow    *window,
     }
 }
 
-static void
-redraw_icon (MetaWindow *window)
+cairo_surface_t *
+meta_window_get_icon (MetaWindow *window)
 {
-  /* We could probably be smart and just redraw the icon here,
-   * instead of the whole frame.
-   */
-  if (window->frame)
-    meta_frame_queue_draw (window->frame);
-}
+  MetaWindowClass *klass = META_WINDOW_GET_CLASS (window);
 
-static void
-meta_window_update_icon_now (MetaWindow *window,
-                             gboolean    force)
-{
-  gboolean changed;
-  cairo_surface_t *icon = NULL;
-  cairo_surface_t *mini_icon;
-
-  g_return_if_fail (!window->override_redirect);
-
-  changed = META_WINDOW_GET_CLASS (window)->update_icon (window, &icon, &mini_icon);
-
-  if (changed || force)
-    {
-      if (window->icon)
-        cairo_surface_destroy (window->icon);
-      window->icon = icon;
-
-      if (window->mini_icon)
-        cairo_surface_destroy (window->mini_icon);
-      window->mini_icon = mini_icon;
-
-      g_object_freeze_notify (G_OBJECT (window));
-      g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_ICON]);
-      g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_MINI_ICON]);
-      g_object_thaw_notify (G_OBJECT (window));
-
-      redraw_icon (window);
-    }
+  if (klass->get_icon)
+    return klass->get_icon (window);
+  else
+    return NULL;
 }
 
-static gboolean
-idle_update_icon (gpointer data)
+cairo_surface_t *
+meta_window_get_mini_icon (MetaWindow *window)
 {
-  GSList *tmp;
-  GSList *copy;
-  guint queue_index = GPOINTER_TO_INT (data);
-
-  meta_topic (META_DEBUG_GEOMETRY, "Clearing the update_icon queue");
-
-  /* Work with a copy, for reentrancy. The allowed reentrancy isn't
-   * complete; destroying a window while we're in here would result in
-   * badness. But it's OK to queue/unqueue update_icons.
-   */
-  copy = g_slist_copy (queue_pending[queue_index]);
-  g_slist_free (queue_pending[queue_index]);
-  queue_pending[queue_index] = NULL;
-  queue_later[queue_index] = 0;
-
-  destroying_windows_disallowed += 1;
-
-  tmp = copy;
-  while (tmp != NULL)
-    {
-      MetaWindow *window;
-
-      window = tmp->data;
-
-      meta_window_update_icon_now (window, FALSE);
-      window->is_in_queues &= ~META_QUEUE_UPDATE_ICON;
-
-      tmp = tmp->next;
-    }
+  MetaWindowClass *klass = META_WINDOW_GET_CLASS (window);
 
-  g_slist_free (copy);
-
-  destroying_windows_disallowed -= 1;
-
-  return FALSE;
+  if (klass->get_mini_icon)
+    return klass->get_mini_icon (window);
+  else
+    return NULL;
 }
 
 GList*
diff --git a/src/ui/frames.c b/src/ui/frames.c
index b1329b272e..cf90d477bb 100644
--- a/src/ui/frames.c
+++ b/src/ui/frames.c
@@ -1595,7 +1595,7 @@ meta_ui_frame_paint (MetaUIFrame  *frame,
   if (button_type > -1)
     button_states[button_type] = frame->button_state;
 
-  mini_icon = frame->meta_window->mini_icon;
+  mini_icon = meta_window_get_mini_icon (frame->meta_window);
   flags = meta_frame_get_flags (frame->meta_window->frame);
   type = meta_window_get_frame_type (frame->meta_window);
 
diff --git a/src/x11/window-props.c b/src/x11/window-props.c
index 1d8cf63a62..aa4fab99cd 100644
--- a/src/x11/window-props.c
+++ b/src/x11/window-props.c
@@ -296,7 +296,7 @@ reload_icon (MetaWindow    *window,
   meta_icon_cache_property_changed (&priv->icon_cache,
                                     window->display->x11_display,
                                     atom);
-  meta_window_queue(window, META_QUEUE_UPDATE_ICON);
+  meta_window_x11_queue_update_icon (window_x11);
 }
 
 static void
@@ -1694,7 +1694,8 @@ reload_wm_hints (MetaWindow    *window,
                                     window->display->x11_display,
                                     XA_WM_HINTS);
 
-  meta_window_queue (window, META_QUEUE_UPDATE_ICON | META_QUEUE_MOVE_RESIZE);
+  meta_window_x11_queue_update_icon (window_x11);
+  meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
 }
 
 static gboolean
diff --git a/src/x11/window-x11-private.h b/src/x11/window-x11-private.h
index e12f83be0c..7e5a72d034 100644
--- a/src/x11/window-x11-private.h
+++ b/src/x11/window-x11-private.h
@@ -72,6 +72,10 @@ struct _MetaWindowX11Private
   Pixmap wm_hints_pixmap;
   Pixmap wm_hints_mask;
 
+  cairo_surface_t *icon;
+  cairo_surface_t *mini_icon;
+  guint update_icon_handle_id;
+
   /* Freeze/thaw on resize (for Xwayland) */
   gboolean thaw_after_paint;
 
@@ -84,6 +88,8 @@ MetaWindowX11Private * meta_window_x11_get_private (MetaWindowX11 *window_x11);
 void meta_window_x11_set_bypass_compositor_hint (MetaWindowX11            *window_x11,
                                                  MetaBypassCompositorHint  requested_value);
 
+void meta_window_x11_queue_update_icon (MetaWindowX11 *window_x11);
+
 G_END_DECLS
 
 #endif
diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c
index 7f8e79aa52..4e8efcd75d 100644
--- a/src/x11/window-x11.c
+++ b/src/x11/window-x11.c
@@ -42,7 +42,9 @@
 #include "core/window-private.h"
 #include "core/workspace-private.h"
 #include "meta/common.h"
+#include "meta/compositor.h"
 #include "meta/meta-cursor-tracker.h"
+#include "meta/meta-later.h"
 #include "meta/meta-x11-errors.h"
 #include "meta/prefs.h"
 #include "x11/meta-x11-display-private.h"
@@ -1773,23 +1775,88 @@ meta_window_x11_get_default_skip_hints (MetaWindow *window,
   *skip_pager_out = priv->wm_state_skip_pager;
 }
 
+static void
+meta_window_x11_update_icon (MetaWindowX11 *window_x11,
+                             gboolean       force)
+{
+  MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
+  MetaWindow *window = META_WINDOW (window_x11);
+  cairo_surface_t *icon = NULL;
+  cairo_surface_t *mini_icon = NULL;
+  gboolean changed;
+
+  changed = meta_read_icons (window->display->x11_display,
+                             window->xwindow,
+                             &priv->icon_cache,
+                             priv->wm_hints_pixmap,
+                             priv->wm_hints_mask,
+                             &icon,
+                             META_ICON_WIDTH, META_ICON_HEIGHT,
+                             &mini_icon,
+                             META_MINI_ICON_WIDTH, META_MINI_ICON_HEIGHT);
+
+  if (changed || force)
+    {
+      g_clear_pointer (&priv->icon, cairo_surface_destroy);
+      g_clear_pointer (&priv->mini_icon, cairo_surface_destroy);
+      priv->icon = icon;
+      priv->mini_icon = mini_icon;
+
+      g_object_freeze_notify (G_OBJECT (window));
+      g_object_notify (G_OBJECT (window), "icon");
+      g_object_notify (G_OBJECT (window), "mini-icon");
+      g_object_thaw_notify (G_OBJECT (window));
+
+      if (window->frame)
+        meta_frame_queue_draw (window->frame);
+    }
+}
+
 static gboolean
-meta_window_x11_update_icon (MetaWindow       *window,
-                             cairo_surface_t **icon,
-                             cairo_surface_t **mini_icon)
+update_icon_before_redraw (gpointer user_data)
+{
+  MetaWindowX11 *window_x11 = META_WINDOW_X11 (user_data);
+
+  meta_window_x11_update_icon (window_x11, FALSE);
+
+  return G_SOURCE_REMOVE;
+}
+
+void
+meta_window_x11_queue_update_icon (MetaWindowX11 *window_x11)
+{
+  MetaWindowX11Private *priv =
+    meta_window_x11_get_instance_private (window_x11);
+  MetaWindow *window = META_WINDOW (window_x11);
+  MetaDisplay *display = meta_window_get_display (window);
+  MetaCompositor *compositor = meta_display_get_compositor (display);
+
+  priv->update_icon_handle_id =
+    meta_laters_add (meta_compositor_get_laters (compositor),
+                     META_LATER_BEFORE_REDRAW,
+                     update_icon_before_redraw,
+                     window,
+                     NULL);
+}
+
+static cairo_surface_t *
+meta_window_x11_get_icon (MetaWindow *window)
 {
   MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
-  MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
+  MetaWindowX11Private *priv =
+    meta_window_x11_get_instance_private (window_x11);
+
+  return priv->icon;
+}
+
+static cairo_surface_t *
+meta_window_x11_get_mini_icon (MetaWindow *window)
+{
+  MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
+  MetaWindowX11Private *priv =
+    meta_window_x11_get_instance_private (window_x11);
 
-  return meta_read_icons (window->display->x11_display,
-                          window->xwindow,
-                          &priv->icon_cache,
-                          priv->wm_hints_pixmap,
-                          priv->wm_hints_mask,
-                          icon,
-                          META_ICON_WIDTH, META_ICON_HEIGHT,
-                          mini_icon,
-                          META_MINI_ICON_WIDTH, META_MINI_ICON_HEIGHT);
+  return priv->mini_icon;
 }
 
 static void
@@ -2069,11 +2136,36 @@ meta_window_x11_is_focus_async (MetaWindow *window)
   return !window->input && priv->wm_take_focus;
 }
 
+static void
+meta_window_x11_dispose (GObject *object)
+{
+  MetaWindowX11 *window_x11 = META_WINDOW_X11 (object);
+  MetaWindowX11Private *priv =
+    meta_window_x11_get_instance_private (window_x11);
+  MetaWindow *window = META_WINDOW (window_x11);
+  MetaDisplay *display = meta_window_get_display (window);
+  MetaCompositor *compositor = meta_display_get_compositor (display);
+
+  if (priv->update_icon_handle_id)
+    {
+      meta_laters_remove (meta_compositor_get_laters (compositor),
+                          priv->update_icon_handle_id);
+    }
+
+  g_clear_pointer (&priv->icon, cairo_surface_destroy);
+  g_clear_pointer (&priv->mini_icon, cairo_surface_destroy);
+
+  G_OBJECT_CLASS (meta_window_x11_parent_class)->dispose (object);
+}
+
 static void
 meta_window_x11_class_init (MetaWindowX11Class *klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   MetaWindowClass *window_class = META_WINDOW_CLASS (klass);
 
+  object_class->dispose = meta_window_x11_dispose;
+
   window_class->manage = meta_window_x11_manage;
   window_class->unmanage = meta_window_x11_unmanage;
   window_class->ping = meta_window_x11_ping;
@@ -2086,7 +2178,8 @@ meta_window_x11_class_init (MetaWindowX11Class *klass)
   window_class->move_resize_internal = meta_window_x11_move_resize_internal;
   window_class->update_struts = meta_window_x11_update_struts;
   window_class->get_default_skip_hints = meta_window_x11_get_default_skip_hints;
-  window_class->update_icon = meta_window_x11_update_icon;
+  window_class->get_icon = meta_window_x11_get_icon;
+  window_class->get_mini_icon = meta_window_x11_get_mini_icon;
   window_class->update_main_monitor = meta_window_x11_update_main_monitor;
   window_class->main_monitor_changed = meta_window_x11_main_monitor_changed;
   window_class->get_client_pid = meta_window_x11_get_client_pid;
@@ -3692,6 +3785,9 @@ meta_window_x11_new (MetaDisplay       *display,
 
   priv->border_width = attrs.border_width;
 
+  if (!window->override_redirect)
+    meta_window_x11_update_icon (window_x11, TRUE);
+
   meta_window_grab_keys (window);
   if (window->type != META_WINDOW_DOCK && !window->override_redirect)
     {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]