From 5b851ffc2d9360970eac46b031f1b9278b3978a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Mon, 15 May 2017 11:52:54 +0200 Subject: AppIndicator: fix icon and theme paths when running in $SNAP environment Prepend $SNAP path to icons and theme paths when running in a sandboxed environment, this allows to run app indicators without caring about the fact they've been designed or compiled to run in a snap world or not. (LP: #1600136) --- src/app-indicator.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 121 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/app-indicator.c b/src/app-indicator.c index c063717..d05689d 100644 --- a/src/app-indicator.c +++ b/src/app-indicator.c @@ -38,6 +38,8 @@ License version 3 and version 2.1 along with this program. If not, see #include +#include + #include "app-indicator.h" #include "app-indicator-enum-types.h" #include "application-service-marshal.h" @@ -71,8 +73,11 @@ struct _AppIndicatorPrivate { AppIndicatorCategory category; AppIndicatorStatus status; gchar *icon_name; + gchar *absolute_icon_name; gchar *attention_icon_name; + gchar *absolute_attention_icon_name; gchar *icon_theme_path; + gchar *absolute_icon_theme_path; DbusmenuServer *menuservice; GtkWidget *menu; GtkWidget *sec_activate_target; @@ -190,6 +195,8 @@ static void status_icon_activate (GtkStatusIcon * icon, gpointer data); static void status_icon_menu_activate (GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data); static void unfallback (AppIndicator * self, GtkStatusIcon * status_icon); static gchar * append_panel_icon_suffix (const gchar * icon_name); +static gchar * get_real_theme_path (AppIndicator * self); +static gchar * append_snap_prefix (const gchar * path); static void theme_changed_cb (GtkIconTheme * theme, gpointer user_data); static void sec_activate_target_parent_changed(GtkWidget *menuitem, GtkWidget *old_parent, gpointer user_data); static GVariant * bus_get_prop (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * property, GError ** error, gpointer user_data); @@ -389,7 +396,7 @@ app_indicator_class_init (AppIndicatorClass *klass) "An additional place to look for icon names that may be installed by the application.", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT)); - + /** * AppIndicator:connected: * @@ -640,6 +647,7 @@ static void app_indicator_init (AppIndicator *self) { AppIndicatorPrivate * priv = APP_INDICATOR_GET_PRIVATE(self); + self->priv = priv; priv->id = NULL; priv->clean_id = NULL; @@ -648,6 +656,7 @@ app_indicator_init (AppIndicator *self) priv->icon_name = NULL; priv->attention_icon_name = NULL; priv->icon_theme_path = NULL; + priv->absolute_icon_theme_path = get_real_theme_path (self); priv->menu = NULL; priv->menuservice = NULL; priv->ordering_index = 0; @@ -676,8 +685,6 @@ app_indicator_init (AppIndicator *self) (GBusNameVanishedCallback) name_vanished_handler, self, NULL); - self->priv = priv; - /* Start getting the session bus */ g_object_ref(self); /* ref for the bus creation callback */ g_bus_get(G_BUS_TYPE_SESSION, NULL, bus_creation, self); @@ -794,16 +801,31 @@ app_indicator_finalize (GObject *object) priv->icon_name = NULL; } + if (priv->absolute_icon_name != NULL) { + g_free(priv->absolute_icon_name); + priv->absolute_icon_name = NULL; + } + if (priv->attention_icon_name != NULL) { g_free(priv->attention_icon_name); priv->attention_icon_name = NULL; } + if (priv->absolute_attention_icon_name != NULL) { + g_free(priv->absolute_attention_icon_name); + priv->absolute_attention_icon_name = NULL; + } + if (priv->icon_theme_path != NULL) { g_free(priv->icon_theme_path); priv->icon_theme_path = NULL; } - + + if (priv->absolute_icon_theme_path != NULL) { + g_free(priv->absolute_icon_theme_path); + priv->absolute_icon_theme_path = NULL; + } + if (priv->title != NULL) { g_free(priv->title); priv->title = NULL; @@ -1188,8 +1210,14 @@ bus_get_prop (GDBusConnection * connection, const gchar * sender, const gchar * enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (APP_INDICATOR_TYPE_INDICATOR_STATUS), priv->status); return g_variant_new_string(enum_value->value_nick ? enum_value->value_nick : ""); } else if (g_strcmp0(property, "IconName") == 0) { + if (priv->absolute_icon_name) { + return g_variant_new_string(priv->absolute_icon_name); + } return g_variant_new_string(priv->icon_name ? priv->icon_name : ""); } else if (g_strcmp0(property, "AttentionIconName") == 0) { + if (priv->absolute_attention_icon_name) { + return g_variant_new_string(priv->absolute_attention_icon_name); + } return g_variant_new_string(priv->attention_icon_name ? priv->attention_icon_name : ""); } else if (g_strcmp0(property, "Title") == 0) { const gchar * output = NULL; @@ -1205,6 +1233,9 @@ bus_get_prop (GDBusConnection * connection, const gchar * sender, const gchar * } return g_variant_new_string(output); } else if (g_strcmp0(property, "IconThemePath") == 0) { + if (priv->absolute_icon_theme_path) { + return g_variant_new_string(priv->absolute_icon_theme_path); + } return g_variant_new_string(priv->icon_theme_path ? priv->icon_theme_path : ""); } else if (g_strcmp0(property, "Menu") == 0) { if (priv->menuservice != NULL) { @@ -1571,19 +1602,23 @@ status_icon_changes (AppIndicator * self, gpointer data) /* add the icon_theme_path once if needed */ GtkIconTheme *icon_theme = gtk_icon_theme_get_default(); - if (self->priv->icon_theme_path != NULL) { + const gchar *theme_path = self->priv->absolute_icon_theme_path ? + self->priv->absolute_icon_theme_path : + self->priv->icon_theme_path; + + if (theme_path != NULL) { gchar **path; gint n_elements, i; gboolean found=FALSE; gtk_icon_theme_get_search_path(icon_theme, &path, &n_elements); for (i=0; i< n_elements || path[i] == NULL; i++) { - if(g_strcmp0(path[i], self->priv->icon_theme_path) == 0) { + if(g_strcmp0(path[i], theme_path) == 0) { found=TRUE; break; } } if(!found) { - gtk_icon_theme_append_search_path(icon_theme, self->priv->icon_theme_path); + gtk_icon_theme_append_search_path(icon_theme, theme_path); } g_strfreev (path); } @@ -1607,8 +1642,12 @@ status_icon_changes (AppIndicator * self, gpointer data) }; if (icon_name != NULL) { + gchar *snapped_icon = append_snap_prefix(icon_name); + if (g_file_test(icon_name, G_FILE_TEST_EXISTS)) { gtk_status_icon_set_from_file(icon, icon_name); + } else if (snapped_icon && g_file_test(snapped_icon, G_FILE_TEST_EXISTS)) { + gtk_status_icon_set_from_file(icon, snapped_icon); } else { gchar *longname = append_panel_icon_suffix(icon_name); @@ -1620,6 +1659,8 @@ status_icon_changes (AppIndicator * self, gpointer data) g_free(longname); } + + g_free(snapped_icon); } return; @@ -1633,7 +1674,7 @@ status_icon_activate (GtkStatusIcon * icon, gpointer data) GtkMenu * menu = app_indicator_get_menu(APP_INDICATOR(data)); if (menu == NULL) return; - + gtk_menu_popup(menu, NULL, /* Parent Menu */ NULL, /* Parent item */ @@ -1681,7 +1722,7 @@ append_panel_icon_suffix (const gchar *icon_name) long_name = g_strdup (icon_name); } - return long_name; + return long_name; } static gboolean @@ -1858,6 +1899,14 @@ app_indicator_set_attention_icon_full (AppIndicator *self, const gchar *icon_nam if (g_strcmp0 (self->priv->attention_icon_name, icon_name) != 0) { g_free (self->priv->attention_icon_name); self->priv->attention_icon_name = g_strdup (icon_name); + + g_free(self->priv->absolute_attention_icon_name); + self->priv->absolute_attention_icon_name = NULL; + + if (icon_name && icon_name[0] == '/') { + self->priv->absolute_attention_icon_name = append_snap_prefix (icon_name); + } + changed = TRUE; } @@ -1933,6 +1982,14 @@ app_indicator_set_icon_full (AppIndicator *self, const gchar *icon_name, const g } self->priv->icon_name = g_strdup(icon_name); + + g_free(self->priv->absolute_icon_name); + self->priv->absolute_icon_name = NULL; + + if (icon_name && icon_name[0] == '/') { + self->priv->absolute_icon_name = append_snap_prefix (icon_name); + } + changed = TRUE; } @@ -1994,6 +2051,54 @@ app_indicator_set_label (AppIndicator *self, const gchar * label, const gchar * return; } +static const gchar * +get_snap_prefix () +{ + const gchar *snap = g_getenv ("SNAP"); + return (snap && *snap != '\0') ? snap : NULL; +} + +static gchar * +append_snap_prefix (const gchar *path) +{ + gchar real_path[PATH_MAX]; + const gchar *snap = get_snap_prefix (); + + if (snap != NULL && path != NULL) { + if (realpath (path, real_path) != NULL) { + path = real_path; + } + + if (g_str_has_prefix (path, "/tmp/")) { + g_warning ("Using '/tmp' paths in SNAP environment will lead to unreadable resources"); + return NULL; + } + + if (g_str_has_prefix (path, snap)) { + return g_strdup (path); + } + + return g_build_path (G_DIR_SEPARATOR_S, snap, path, NULL); + } + + return NULL; +} + +static gchar * +get_real_theme_path (AppIndicator * self) +{ + const gchar *theme_path = self->priv->icon_theme_path; + gchar *snapped_path = append_snap_prefix (theme_path); + + if (snapped_path != NULL) { + return snapped_path; + } else if (get_snap_prefix ()) { + return g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (), "icons", NULL); + } + + return NULL; +} + /** * app_indicator_set_icon_theme_path: * @self: The #AppIndicator object to use @@ -2012,9 +2117,15 @@ app_indicator_set_icon_theme_path (AppIndicator *self, const gchar *icon_theme_p self->priv->icon_theme_path = g_strdup(icon_theme_path); + g_free (self->priv->absolute_icon_theme_path); + self->priv->absolute_icon_theme_path = get_real_theme_path (self); + g_signal_emit (self, signals[NEW_ICON_THEME_PATH], 0, self->priv->icon_theme_path, TRUE); if (self->priv->dbus_registration != 0 && self->priv->connection != NULL) { + const gchar *theme_path = self->priv->absolute_icon_theme_path ? + self->priv->absolute_icon_theme_path : + self->priv->icon_theme_path; GError * error = NULL; g_dbus_connection_emit_signal(self->priv->connection, @@ -2022,7 +2133,7 @@ app_indicator_set_icon_theme_path (AppIndicator *self, const gchar *icon_theme_p self->priv->path, NOTIFICATION_ITEM_DBUS_IFACE, "NewIconThemePath", - g_variant_new("(s)", self->priv->icon_theme_path), + g_variant_new("(s)", theme_path ? theme_path : ""), &error); if (error != NULL) { -- cgit v1.2.3