[gnome-shell] shell/app: Explicitly handle (X11) fallback icon changes



commit 4a7c5890a8b65068a0620ad6c173274013683348
Author: Florian Müllner <fmuellner gnome org>
Date:   Fri Mar 12 23:10:42 2021 +0100

    shell/app: Explicitly handle (X11) fallback icon changes
    
    Since commit 770231, StImageContent implements the GIcon interface, which
    allowed us to represent all application icons as GIcon (app-info, X11 icon
    property or themed fallback icon).
    
    While that change made for a nicer ShellApp API, it did introduce a
    conceptual issue in st_texture_cache_bind_cairo_surface_property():
    GIcons usually represent static icons, while the ClutterContent
    returned by that method updates automatically when the bound property
    changes.
    
    Address this by tracking the MetaWindow:icon property in ShellApp, and
    update the fallback icon when it changes. With that, a GIcon object
    always represents the same icon, and any icon change is reflected
    by a corresponding GIcon change.
    
    Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1761>

 src/shell-app.c | 42 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 35 insertions(+), 7 deletions(-)
---
diff --git a/src/shell-app.c b/src/shell-app.c
index d86b05a22d..62ba2ec73a 100644
--- a/src/shell-app.c
+++ b/src/shell-app.c
@@ -38,6 +38,8 @@ typedef struct {
   /* Signal connection to dirty window sort list on workspace changes */
   gulong workspace_switch_id;
 
+  gulong icon_changed_id;
+
   GSList *windows;
 
   guint interesting_windows;
@@ -185,6 +187,32 @@ window_backed_app_get_window (ShellApp     *app)
     return NULL;
 }
 
+static GIcon *
+x11_window_create_fallback_gicon (MetaWindow *window)
+{
+  StTextureCache *texture_cache;
+  cairo_surface_t *surface;
+
+  g_object_get (window, "icon", &surface, NULL);
+
+  texture_cache = st_texture_cache_get_default ();
+  return st_texture_cache_load_cairo_surface_to_gicon (texture_cache, surface);
+}
+
+static void
+on_window_icon_changed (GObject          *object,
+                        const GParamSpec *pspec,
+                        gpointer          user_data)
+{
+  MetaWindow *window = META_WINDOW (object);
+  ShellApp *app = user_data;
+
+  g_clear_object (&app->fallback_icon);
+  app->fallback_icon = x11_window_create_fallback_gicon (window);
+
+  g_object_notify (G_OBJECT (app), "icon");
+}
+
 /**
  * shell_app_get_icon:
  *
@@ -215,10 +243,10 @@ shell_app_get_icon (ShellApp *app)
   if (window &&
       meta_window_get_client_type (window) == META_WINDOW_CLIENT_TYPE_X11)
     {
-      app->fallback_icon =
-        st_texture_cache_bind_cairo_surface_property (st_texture_cache_get_default (),
-                                                      G_OBJECT (window),
-                                                      "icon");
+      app->fallback_icon = x11_window_create_fallback_gicon (window);
+      app->running_state->icon_changed_id =
+        g_signal_connect (G_OBJECT (window),
+                         "notify::icon", G_CALLBACK (on_window_icon_changed), app);
     }
   else
     {
@@ -240,15 +268,13 @@ ClutterActor *
 shell_app_create_icon_texture (ShellApp   *app,
                                int         size)
 {
-  GIcon *icon;
   ClutterActor *ret;
 
   ret = st_icon_new ();
   st_icon_set_icon_size (ST_ICON (ret), size);
   st_icon_set_fallback_icon_name (ST_ICON (ret), "application-x-executable");
 
-  icon = shell_app_get_icon (app);
-  st_icon_set_gicon (ST_ICON (ret), icon);
+  g_object_bind_property (app, "icon", ret, "gicon", G_BINDING_SYNC_CREATE);
 
   if (shell_app_is_window_backed (app))
     st_widget_add_style_class_name (ST_WIDGET (ret), "fallback-app-icon");
@@ -1121,6 +1147,8 @@ _shell_app_remove_window (ShellApp   *app,
   g_signal_handlers_disconnect_by_func (window, G_CALLBACK(shell_app_on_skip_taskbar_changed), app);
   app->running_state->windows = g_slist_remove (app->running_state->windows, window);
 
+  g_clear_signal_handler (&app->running_state->icon_changed_id, window);
+
   if (!meta_window_is_skip_taskbar (window))
     app->running_state->interesting_windows--;
   shell_app_sync_running_state (app);


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