diff --git a/src/core/atomnames.h b/src/core/atomnames.h index cea869d06..2e9e6c8d5 100644 --- a/src/core/atomnames.h +++ b/src/core/atomnames.h @@ -60,6 +60,7 @@ item(_MARCO_SET_KEYBINDINGS_MESSAGE) item(_MARCO_TOGGLE_VERBOSE) item(_GTK_THEME_VARIANT) item(_GTK_FRAME_EXTENTS) +item(_GTK_APPLICATION_ID) item(_GTK_SHOW_WINDOW_MENU) item(_GTK_WORKAREAS) item(_MATE_PANEL_ACTION) @@ -76,6 +77,11 @@ item(TIMESTAMP) item(VERSION) item(ATOM_PAIR) +/* This is only used if BAMF is installed and the daemon is running. + * Otherwise it's a no-op + */ +item(_BAMF_DESKTOP_FILE) + /* Oddities: These are used, and we need atoms for them, * but when we need all _NET_WM hints (i.e. when we're making * lists of which _NET_WM hints we support in order to advertise diff --git a/src/core/iconcache.c b/src/core/iconcache.c index a45d3d99a..580a521c9 100644 --- a/src/core/iconcache.c +++ b/src/core/iconcache.c @@ -31,7 +31,7 @@ /* The icon-reading code is also in libwnck, please sync bugfixes */ -static void +static gboolean get_fallback_icons (MetaScreen *screen, GdkPixbuf **iconp, int ideal_width, @@ -45,6 +45,11 @@ get_fallback_icons (MetaScreen *screen, */ *iconp = meta_ui_get_default_window_icon (screen->ui); *mini_iconp = meta_ui_get_default_mini_icon (screen->ui); + + if (*iconp && *mini_iconp) + return TRUE; + + return FALSE; } static gboolean @@ -524,6 +529,7 @@ meta_icon_cache_init (MetaIconCache *icon_cache) icon_cache->wm_hints_dirty = TRUE; icon_cache->kwm_win_icon_dirty = TRUE; icon_cache->net_wm_icon_dirty = TRUE; + icon_cache->g_desktop_app_icon_dirty = TRUE; icon_cache->wm_hints_dirty_forced = FALSE; icon_cache->kwm_win_icon_dirty_forced = FALSE; @@ -551,6 +557,7 @@ clear_icon_cache (MetaIconCache *icon_cache, icon_cache->wm_hints_dirty = TRUE; icon_cache->kwm_win_icon_dirty = TRUE; icon_cache->net_wm_icon_dirty = TRUE; + icon_cache->g_desktop_app_icon_dirty = TRUE; } } @@ -566,6 +573,7 @@ meta_icon_cache_invalidate (MetaIconCache *icon_cache) icon_cache->wm_hints_dirty = TRUE; icon_cache->kwm_win_icon_dirty = TRUE; icon_cache->net_wm_icon_dirty = TRUE; + icon_cache->g_desktop_app_icon_dirty = TRUE; icon_cache->wm_hints_dirty_forced = TRUE; icon_cache->kwm_win_icon_dirty_forced = TRUE; @@ -594,6 +602,9 @@ meta_icon_cache_get_icon_invalidated (MetaIconCache *icon_cache) else if (icon_cache->origin <= USING_WM_HINTS && icon_cache->wm_hints_dirty) return TRUE; + else if (icon_cache->origin <= USING_G_DESKTOP_APP && + icon_cache->g_desktop_app_icon_dirty) + return TRUE; else if (icon_cache->origin <= USING_NET_WM_ICON && icon_cache->net_wm_icon_dirty) return TRUE; @@ -691,7 +702,7 @@ scaled_from_pixdata (guchar *pixdata, gboolean meta_read_icons (MetaScreen *screen, Window xwindow, - char *res_name, + char *desktop_id, MetaIconCache *icon_cache, Pixmap wm_hints_pixmap, Pixmap wm_hints_mask, @@ -743,6 +754,31 @@ meta_read_icons (MetaScreen *screen, * we haven't done that since the last change. */ + if (icon_cache->origin <= USING_G_DESKTOP_APP && + icon_cache->g_desktop_app_icon_dirty && + desktop_id != NULL) + { + icon_cache->g_desktop_app_icon_dirty = FALSE; + + *iconp = meta_ui_get_window_icon_from_desktop_id (screen->ui, desktop_id); + *mini_iconp = meta_ui_get_mini_icon_from_desktop_id (screen->ui, desktop_id); + + if (*iconp && *mini_iconp) + { + replace_cache (icon_cache, USING_G_DESKTOP_APP, + *iconp, *mini_iconp); + + return TRUE; + } + else + { + if (*iconp) + g_object_unref (G_OBJECT (*iconp)); + if (*mini_iconp) + g_object_unref (G_OBJECT (*mini_iconp)); + } + } + if (icon_cache->origin <= USING_NET_WM_ICON && icon_cache->net_wm_icon_dirty) @@ -849,25 +885,19 @@ meta_read_icons (MetaScreen *screen, { icon_cache->fallback_icon_dirty_forced = FALSE; - if (res_name != NULL) + if (get_fallback_icons (screen, + iconp, + ideal_width, + ideal_height, + mini_iconp, + ideal_mini_width, + ideal_mini_height)) { - *iconp = meta_ui_get_window_icon_from_name (screen->ui, res_name); - *mini_iconp = meta_ui_get_mini_icon_from_name (screen->ui, res_name); - } - - if (*iconp == NULL || *mini_iconp == NULL) - get_fallback_icons (screen, - iconp, - ideal_width, - ideal_height, - mini_iconp, - ideal_mini_width, - ideal_mini_height); + replace_cache (icon_cache, USING_FALLBACK_ICON, + *iconp, *mini_iconp); - replace_cache (icon_cache, USING_FALLBACK_ICON, - *iconp, *mini_iconp); - - return TRUE; + return TRUE; + } } if (!icon_cache->want_fallback && diff --git a/src/core/iconcache.h b/src/core/iconcache.h index 7e9a1f6d5..353787c7f 100644 --- a/src/core/iconcache.h +++ b/src/core/iconcache.h @@ -38,7 +38,8 @@ typedef enum USING_FALLBACK_ICON, USING_KWM_WIN_ICON, USING_WM_HINTS, - USING_NET_WM_ICON + USING_NET_WM_ICON, + USING_G_DESKTOP_APP } IconOrigin; struct _MetaIconCache @@ -51,6 +52,7 @@ struct _MetaIconCache guint wm_hints_dirty : 1; guint kwm_win_icon_dirty : 1; guint net_wm_icon_dirty : 1; + guint g_desktop_app_icon_dirty : 1; guint wm_hints_dirty_forced : 1; guint kwm_win_icon_dirty_forced : 1; @@ -67,7 +69,7 @@ gboolean meta_icon_cache_get_icon_invalidated (MetaIconCache *icon_cache); gboolean meta_read_icons (MetaScreen *screen, Window xwindow, - char *res_name, + char *desktop_id, MetaIconCache *icon_cache, Pixmap wm_hints_pixmap, Pixmap wm_hints_mask, diff --git a/src/core/window-private.h b/src/core/window-private.h index 02b7df425..52864a869 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -133,6 +133,8 @@ struct _MetaWindow char *wm_client_machine; char *startup_id; char *gtk_theme_variant; + char *gtk_application_id; + char *bamf_desktop_file; int net_wm_pid; diff --git a/src/core/window-props.c b/src/core/window-props.c index e1275817b..4d9600c24 100644 --- a/src/core/window-props.c +++ b/src/core/window-props.c @@ -1603,6 +1603,53 @@ reload_gtk_theme_variant (MetaWindow *window, meta_ui_update_frame_style (window->screen->ui, window->frame->xwindow); } } + +static void +reload_gtk_application_id (MetaWindow *window, + MetaPropValue *value, + gboolean initial) +{ + char *requested = NULL; + char *current = window->gtk_application_id; + + if (value->type != META_PROP_VALUE_INVALID) + { + requested = value->v.str; + meta_verbose ("Requested \"%s\" gtk-application-id for window %s.\n", + requested, window->desc); + } + + if (g_strcmp0 (requested, current) != 0) + { + g_free (current); + + window->gtk_application_id = g_strdup (requested); + } +} + +static void +reload_bamf_desktop_file (MetaWindow *window, + MetaPropValue *value, + gboolean initial) +{ + char *requested = NULL; + char *current = window->bamf_desktop_file; + + if (value->type != META_PROP_VALUE_INVALID) + { + requested = value->v.str; + meta_verbose ("Requested _BAMF_DESKTOP_FILE \"%s\" for window %s.\n", + requested, window->desc); + } + + if (g_strcmp0 (requested, current) != 0) + { + g_free (current); + + window->bamf_desktop_file = g_strdup (requested); + } +} + /** * Initialises the property hooks system. Each row in the table named "hooks" * represents an action to take when a property is found on a newly-created @@ -1652,6 +1699,8 @@ meta_display_init_window_prop_hooks (MetaDisplay *display) { display->atom__NET_WM_USER_TIME_WINDOW, META_PROP_VALUE_WINDOW, reload_net_wm_user_time_window }, { display->atom__GTK_THEME_VARIANT, META_PROP_VALUE_UTF8, reload_gtk_theme_variant, }, { display->atom__GTK_FRAME_EXTENTS, META_PROP_VALUE_CARDINAL_LIST, reload_gtk_frame_extents }, + { display->atom__GTK_APPLICATION_ID, META_PROP_VALUE_UTF8, reload_gtk_application_id }, + { display->atom__BAMF_DESKTOP_FILE, META_PROP_VALUE_STRING, reload_bamf_desktop_file }, { 0 }, }; diff --git a/src/core/window.c b/src/core/window.c index c1702dd8d..050c89f85 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -263,7 +263,7 @@ meta_window_new_with_attrs (MetaDisplay *display, gulong existing_wm_state; gulong event_mask; MetaMoveResizeFlags flags; -#define N_INITIAL_PROPS 20 +#define N_INITIAL_PROPS 22 Atom initial_props[N_INITIAL_PROPS]; int i; gboolean has_shape; @@ -563,6 +563,8 @@ meta_window_new_with_attrs (MetaDisplay *display, window->wm_client_machine = NULL; window->startup_id = NULL; window->gtk_theme_variant = NULL; + window->gtk_application_id = NULL; + window->bamf_desktop_file = NULL; window->net_wm_pid = -1; @@ -621,6 +623,8 @@ meta_window_new_with_attrs (MetaDisplay *display, initial_props[i++] = display->atom__NET_WM_USER_TIME_WINDOW; initial_props[i++] = display->atom__NET_WM_FULLSCREEN_MONITORS; initial_props[i++] = display->atom__GTK_THEME_VARIANT; + initial_props[i++] = display->atom__GTK_APPLICATION_ID; + initial_props[i++] = display->atom__BAMF_DESKTOP_FILE; g_assert (N_INITIAL_PROPS == i); meta_window_reload_properties (window, initial_props, N_INITIAL_PROPS, TRUE); @@ -6107,6 +6111,33 @@ redraw_icon (MetaWindow *window) meta_ui_queue_frame_draw (window->screen->ui, window->frame->xwindow); } +static gchar* +meta_window_get_desktop_id (MetaWindow *window) +{ + gchar* desktop_id = NULL; + + if (window->gtk_application_id != NULL) + { + meta_verbose ("Request desktop ID from _GTK_APPLICATION_ID '%s'\n", window->gtk_application_id); + + /* Generate a desktop extension to the application ID (e.g. org.mate.Caja.desktop). */ + desktop_id = g_strconcat(window->gtk_application_id, ".desktop", NULL); + } + else if (window->bamf_desktop_file != NULL) + { + meta_verbose ("Request desktop ID from _BAMF_DESKTOP_FILE '%s'\n", window->bamf_desktop_file); + + /* Remove any paths to separate the application ID */ + gchar **path_parts = g_strsplit (window->bamf_desktop_file, "/", -1); + /* Generate a desktop ID the application ID (e.g. org.mate.Caja.desktop). */ + if (g_strv_length(path_parts) > 0) + desktop_id = g_strdup (path_parts[g_strv_length(path_parts)-1]); + g_strfreev (path_parts); + } + + return desktop_id; +} + void meta_window_update_icon_now (MetaWindow *window) { @@ -6117,10 +6148,11 @@ meta_window_update_icon_now (MetaWindow *window) mini_icon = NULL; int icon_size = meta_prefs_get_icon_size(); + gchar* desktop_id = meta_window_get_desktop_id (window); if (meta_read_icons (window->screen, window->xwindow, - window->res_name, + desktop_id, &window->icon_cache, window->wm_hints_pixmap, window->wm_hints_mask, @@ -6143,6 +6175,8 @@ meta_window_update_icon_now (MetaWindow *window) redraw_icon (window); } + g_free (desktop_id); + g_assert (window->icon); g_assert (window->mini_icon); } @@ -9015,6 +9049,8 @@ meta_window_finalize (GObject *object) g_clear_pointer (&window->icon_name, g_free); g_clear_pointer (&window->desc, g_free); g_clear_pointer (&window->gtk_theme_variant, g_free); + g_clear_pointer (&window->gtk_application_id, g_free); + g_clear_pointer (&window->bamf_desktop_file, g_free); G_OBJECT_CLASS (meta_window_parent_class)->finalize (object); } diff --git a/src/include/ui.h b/src/include/ui.h index 9d95e37af..8eb6dd5eb 100644 --- a/src/include/ui.h +++ b/src/include/ui.h @@ -157,8 +157,8 @@ void meta_ui_pop_delay_exposes (MetaUI *ui); GdkPixbuf* meta_ui_get_default_window_icon (MetaUI *ui); GdkPixbuf* meta_ui_get_default_mini_icon (MetaUI *ui); -GdkPixbuf* meta_ui_get_window_icon_from_name (MetaUI *ui, char *name); -GdkPixbuf* meta_ui_get_mini_icon_from_name (MetaUI *ui, char *name); +GdkPixbuf* meta_ui_get_window_icon_from_desktop_id (MetaUI *ui, char *desktop_id); +GdkPixbuf* meta_ui_get_mini_icon_from_desktop_id (MetaUI *ui, char *desktop_id); gboolean meta_ui_window_should_not_cause_focus (Display *xdisplay, Window xwindow); diff --git a/src/ui/ui.c b/src/ui/ui.c index 2b15cc82d..00500c030 100644 --- a/src/ui/ui.c +++ b/src/ui/ui.c @@ -650,43 +650,22 @@ meta_ui_get_default_mini_icon (MetaUI *ui) } static GdkPixbuf * -load_window_icon_from_name (char *name, int size, int scale) +load_window_icon_from_desktop_id (char *desktop_id, int size, int scale) { GtkIconTheme *theme = gtk_icon_theme_get_default (); GdkPixbuf *pixbuf = NULL; - /* If the res_name window property maps to an icon, use that */ - pixbuf = gtk_icon_theme_load_icon_for_scale (theme, name, size, scale, GTK_ICON_LOOKUP_FORCE_SIZE, NULL); - if (pixbuf != NULL) - return pixbuf; - - char ***results; - gchar *desktop_id = NULL; - gint i, j; GDesktopAppInfo *info; GIcon *gicon; GtkIconInfo *icon_info; - /* Find a proper desktop file based on the window property name */ - results = g_desktop_app_info_search (name); - - for (i = 0; results[i]; i++) - { - for (j = 0; results[i][j]; j++) - { - /* We are only interested in the top ranking result, so we use that and free up the rest */ - if (desktop_id == NULL) - desktop_id = g_strdup(results[i][j]); - } - g_strfreev (results[i]); - } - g_free (results); - - if (desktop_id == NULL) + if (desktop_id == NULL || !g_str_has_suffix (desktop_id, ".desktop")) return NULL; - /* Now that we have the desktop file ID, we extract the icon from it and render it */ info = g_desktop_app_info_new (desktop_id); + if (info == NULL) + return NULL; + gicon = g_app_info_get_icon (G_APP_INFO (info)); icon_info = gtk_icon_theme_lookup_by_gicon_for_scale (theme, gicon, size, scale, GTK_ICON_LOOKUP_FORCE_SIZE); if (icon_info) @@ -695,13 +674,11 @@ load_window_icon_from_name (char *name, int size, int scale) g_object_unref (icon_info); } - g_free (desktop_id); - return pixbuf; } GdkPixbuf* -meta_ui_get_window_icon_from_name (MetaUI *ui, char *name) +meta_ui_get_window_icon_from_desktop_id (MetaUI *ui, char *desktop_id) { int scale; int size; @@ -709,11 +686,11 @@ meta_ui_get_window_icon_from_name (MetaUI *ui, char *name) scale = gtk_widget_get_scale_factor (GTK_WIDGET (ui->frames)); size = meta_prefs_get_icon_size() / scale; - return load_window_icon_from_name (name, size, scale); + return load_window_icon_from_desktop_id (desktop_id, size, scale); } GdkPixbuf* -meta_ui_get_mini_icon_from_name (MetaUI *ui, char *name) +meta_ui_get_mini_icon_from_desktop_id (MetaUI *ui, char *desktop_id) { int scale; int size; @@ -721,7 +698,7 @@ meta_ui_get_mini_icon_from_name (MetaUI *ui, char *name) scale = gtk_widget_get_scale_factor (GTK_WIDGET (ui->frames)); size = META_MINI_ICON_WIDTH / scale; - return load_window_icon_from_name (name, size, scale); + return load_window_icon_from_desktop_id (desktop_id, size, scale); } gboolean