Merge lp:~3v1n0/libappindicator/incons-paths-on-snap into lp:libappindicator/16.10

Proposed by Marco Trevisan (Treviño)
Status: Merged
Approved by: Andrea Azzarone
Approved revision: 288
Merged at revision: 277
Proposed branch: lp:~3v1n0/libappindicator/incons-paths-on-snap
Merge into: lp:libappindicator/16.10
Diff against target: 353 lines (+124/-14)
5 files modified
configure.ac (+1/-1)
debian/control (+1/-0)
debian/rules (+0/-2)
example/simple-client-vala.vala (+1/-1)
src/app-indicator.c (+121/-10)
To merge this branch: bzr merge lp:~3v1n0/libappindicator/incons-paths-on-snap
Reviewer Review Type Date Requested Status
Andrea Azzarone (community) Approve
unity-api-1-bot continuous-integration Needs Fixing
Review via email: mp+311424@code.launchpad.net

Commit message

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.

Description of the change

See gtk2/gtk3 examples using this at https://github.com/3v1n0/indicators-examples-snaps

To post a comment you must log in.
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Andrea Azzarone (azzar1) wrote :

LGTM.

review: Approve
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

Actually I've noticed that this is not correct when the developer uses an hardcoded path suc has /snap/$SNAP_NAME/current.

So it needs some tuning.

288. By Marco Trevisan (Treviño)

app-indicator: get real path on snap when trying to transform it

So when pointing to /snap/<name>/current will be automatically translated
to /snap/<name>/<current_revision>/...

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

Done this part too...

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Continuous integration, rev:288
https://jenkins.canonical.com/unity-api-1/job/lp-libappindicator-ci/7/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/1208/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/1215
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1000
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1000/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1000
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1000/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1000/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1000/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1000/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1000
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1000/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-libappindicator-ci/7/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Andrea Azzarone (azzar1) wrote :

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'configure.ac'
--- configure.ac 2013-01-29 17:50:13 +0000
+++ configure.ac 2016-11-29 17:27:34 +0000
@@ -121,7 +121,7 @@
121 RUNTIME=mono121 RUNTIME=mono
122 fi122 fi
123123
124 AC_PATH_PROG(CSC, gmcs, no)124 AC_PATH_PROG(CSC, mono-csc, no)
125 LIB_PREFIX=.so125 LIB_PREFIX=.so
126 LIB_SUFFIX=126 LIB_SUFFIX=
127fi127fi
128128
=== modified file 'debian/control'
--- debian/control 2013-12-19 14:37:54 +0000
+++ debian/control 2016-11-29 17:27:34 +0000
@@ -8,6 +8,7 @@
8 python-all-dev,8 python-all-dev,
9 at-spi2-core,9 at-spi2-core,
10 cli-common-dev (>= 0.5.7) [!arm64 !ppc64el],10 cli-common-dev (>= 0.5.7) [!arm64 !ppc64el],
11 gnome-common,
11 gobject-introspection,12 gobject-introspection,
12 intltool,13 intltool,
13 gtk-doc-tools,14 gtk-doc-tools,
1415
=== modified file 'debian/rules'
--- debian/rules 2013-12-19 14:37:54 +0000
+++ debian/rules 2016-11-29 17:27:34 +0000
@@ -15,8 +15,6 @@
15CONFIGURE_FLAGS_gtk2 = --with-gtk=2 --enable-gtk-doc15CONFIGURE_FLAGS_gtk2 = --with-gtk=2 --enable-gtk-doc
16CONFIGURE_FLAGS_gtk3 = --with-gtk=3 --enable-gtk-doc=no16CONFIGURE_FLAGS_gtk3 = --with-gtk=3 --enable-gtk-doc=no
1717
18export CSC=/usr/bin/mono-csc
19
20export DPKG_GENSYMBOLS_CHECK_LEVEL = 418export DPKG_GENSYMBOLS_CHECK_LEVEL = 4
2119
22CFLAGS += -fPIC20CFLAGS += -fPIC
2321
=== modified file 'example/simple-client-vala.vala'
--- example/simple-client-vala.vala 2012-03-21 18:02:41 +0000
+++ example/simple-client-vala.vala 2016-11-29 17:27:34 +0000
@@ -104,7 +104,7 @@
104 print(@"Got scroll event! delta: $delta, direction: $direction\n");104 print(@"Got scroll event! delta: $delta, direction: $direction\n");
105 });105 });
106106
107 Timeout.add_seconds(1, () => {107 GLib.Timeout.add_seconds(1, () => {
108 percentage = (percentage + 1) % 100;108 percentage = (percentage + 1) % 100;
109 if (can_haz_label) {109 if (can_haz_label) {
110 ci.set_label(@"$(percentage+1)%", "");110 ci.set_label(@"$(percentage+1)%", "");
111111
=== modified file 'src/app-indicator.c'
--- src/app-indicator.c 2015-07-02 17:03:37 +0000
+++ src/app-indicator.c 2016-11-29 17:27:34 +0000
@@ -38,6 +38,8 @@
3838
39#include <libindicator/indicator-desktop-shortcuts.h>39#include <libindicator/indicator-desktop-shortcuts.h>
4040
41#include <stdlib.h>
42
41#include "app-indicator.h"43#include "app-indicator.h"
42#include "app-indicator-enum-types.h"44#include "app-indicator-enum-types.h"
43#include "application-service-marshal.h"45#include "application-service-marshal.h"
@@ -71,8 +73,11 @@
71 AppIndicatorCategory category;73 AppIndicatorCategory category;
72 AppIndicatorStatus status;74 AppIndicatorStatus status;
73 gchar *icon_name;75 gchar *icon_name;
76 gchar *absolute_icon_name;
74 gchar *attention_icon_name;77 gchar *attention_icon_name;
78 gchar *absolute_attention_icon_name;
75 gchar *icon_theme_path;79 gchar *icon_theme_path;
80 gchar *absolute_icon_theme_path;
76 DbusmenuServer *menuservice;81 DbusmenuServer *menuservice;
77 GtkWidget *menu;82 GtkWidget *menu;
78 GtkWidget *sec_activate_target;83 GtkWidget *sec_activate_target;
@@ -190,6 +195,8 @@
190static void status_icon_menu_activate (GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data);195static void status_icon_menu_activate (GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data);
191static void unfallback (AppIndicator * self, GtkStatusIcon * status_icon);196static void unfallback (AppIndicator * self, GtkStatusIcon * status_icon);
192static gchar * append_panel_icon_suffix (const gchar * icon_name);197static gchar * append_panel_icon_suffix (const gchar * icon_name);
198static gchar * get_real_theme_path (AppIndicator * self);
199static gchar * append_snap_prefix (const gchar * path);
193static void theme_changed_cb (GtkIconTheme * theme, gpointer user_data);200static void theme_changed_cb (GtkIconTheme * theme, gpointer user_data);
194static void sec_activate_target_parent_changed(GtkWidget *menuitem, GtkWidget *old_parent, gpointer user_data);201static void sec_activate_target_parent_changed(GtkWidget *menuitem, GtkWidget *old_parent, gpointer user_data);
195static GVariant * bus_get_prop (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * property, GError ** error, gpointer user_data);202static 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 @@
389 "An additional place to look for icon names that may be installed by the application.",396 "An additional place to look for icon names that may be installed by the application.",
390 NULL,397 NULL,
391 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));398 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
392 399
393 /**400 /**
394 * AppIndicator:connected:401 * AppIndicator:connected:
395 * 402 *
@@ -640,6 +647,7 @@
640app_indicator_init (AppIndicator *self)647app_indicator_init (AppIndicator *self)
641{648{
642 AppIndicatorPrivate * priv = APP_INDICATOR_GET_PRIVATE(self);649 AppIndicatorPrivate * priv = APP_INDICATOR_GET_PRIVATE(self);
650 self->priv = priv;
643651
644 priv->id = NULL;652 priv->id = NULL;
645 priv->clean_id = NULL;653 priv->clean_id = NULL;
@@ -648,6 +656,7 @@
648 priv->icon_name = NULL;656 priv->icon_name = NULL;
649 priv->attention_icon_name = NULL;657 priv->attention_icon_name = NULL;
650 priv->icon_theme_path = NULL;658 priv->icon_theme_path = NULL;
659 priv->absolute_icon_theme_path = get_real_theme_path (self);
651 priv->menu = NULL;660 priv->menu = NULL;
652 priv->menuservice = NULL;661 priv->menuservice = NULL;
653 priv->ordering_index = 0;662 priv->ordering_index = 0;
@@ -676,8 +685,6 @@
676 (GBusNameVanishedCallback) name_vanished_handler,685 (GBusNameVanishedCallback) name_vanished_handler,
677 self, NULL);686 self, NULL);
678687
679 self->priv = priv;
680
681 /* Start getting the session bus */688 /* Start getting the session bus */
682 g_object_ref(self); /* ref for the bus creation callback */689 g_object_ref(self); /* ref for the bus creation callback */
683 g_bus_get(G_BUS_TYPE_SESSION, NULL, bus_creation, self);690 g_bus_get(G_BUS_TYPE_SESSION, NULL, bus_creation, self);
@@ -794,16 +801,31 @@
794 priv->icon_name = NULL;801 priv->icon_name = NULL;
795 }802 }
796803
804 if (priv->absolute_icon_name != NULL) {
805 g_free(priv->absolute_icon_name);
806 priv->absolute_icon_name = NULL;
807 }
808
797 if (priv->attention_icon_name != NULL) {809 if (priv->attention_icon_name != NULL) {
798 g_free(priv->attention_icon_name);810 g_free(priv->attention_icon_name);
799 priv->attention_icon_name = NULL;811 priv->attention_icon_name = NULL;
800 }812 }
801813
814 if (priv->absolute_attention_icon_name != NULL) {
815 g_free(priv->absolute_attention_icon_name);
816 priv->absolute_attention_icon_name = NULL;
817 }
818
802 if (priv->icon_theme_path != NULL) {819 if (priv->icon_theme_path != NULL) {
803 g_free(priv->icon_theme_path);820 g_free(priv->icon_theme_path);
804 priv->icon_theme_path = NULL;821 priv->icon_theme_path = NULL;
805 }822 }
806 823
824 if (priv->absolute_icon_theme_path != NULL) {
825 g_free(priv->absolute_icon_theme_path);
826 priv->absolute_icon_theme_path = NULL;
827 }
828
807 if (priv->title != NULL) {829 if (priv->title != NULL) {
808 g_free(priv->title);830 g_free(priv->title);
809 priv->title = NULL;831 priv->title = NULL;
@@ -1188,8 +1210,14 @@
1188 enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (APP_INDICATOR_TYPE_INDICATOR_STATUS), priv->status);1210 enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (APP_INDICATOR_TYPE_INDICATOR_STATUS), priv->status);
1189 return g_variant_new_string(enum_value->value_nick ? enum_value->value_nick : "");1211 return g_variant_new_string(enum_value->value_nick ? enum_value->value_nick : "");
1190 } else if (g_strcmp0(property, "IconName") == 0) {1212 } else if (g_strcmp0(property, "IconName") == 0) {
1213 if (priv->absolute_icon_name) {
1214 return g_variant_new_string(priv->absolute_icon_name);
1215 }
1191 return g_variant_new_string(priv->icon_name ? priv->icon_name : "");1216 return g_variant_new_string(priv->icon_name ? priv->icon_name : "");
1192 } else if (g_strcmp0(property, "AttentionIconName") == 0) {1217 } else if (g_strcmp0(property, "AttentionIconName") == 0) {
1218 if (priv->absolute_attention_icon_name) {
1219 return g_variant_new_string(priv->absolute_attention_icon_name);
1220 }
1193 return g_variant_new_string(priv->attention_icon_name ? priv->attention_icon_name : "");1221 return g_variant_new_string(priv->attention_icon_name ? priv->attention_icon_name : "");
1194 } else if (g_strcmp0(property, "Title") == 0) {1222 } else if (g_strcmp0(property, "Title") == 0) {
1195 const gchar * output = NULL;1223 const gchar * output = NULL;
@@ -1205,6 +1233,9 @@
1205 }1233 }
1206 return g_variant_new_string(output);1234 return g_variant_new_string(output);
1207 } else if (g_strcmp0(property, "IconThemePath") == 0) {1235 } else if (g_strcmp0(property, "IconThemePath") == 0) {
1236 if (priv->absolute_icon_theme_path) {
1237 return g_variant_new_string(priv->absolute_icon_theme_path);
1238 }
1208 return g_variant_new_string(priv->icon_theme_path ? priv->icon_theme_path : "");1239 return g_variant_new_string(priv->icon_theme_path ? priv->icon_theme_path : "");
1209 } else if (g_strcmp0(property, "Menu") == 0) {1240 } else if (g_strcmp0(property, "Menu") == 0) {
1210 if (priv->menuservice != NULL) {1241 if (priv->menuservice != NULL) {
@@ -1571,19 +1602,23 @@
15711602
1572 /* add the icon_theme_path once if needed */1603 /* add the icon_theme_path once if needed */
1573 GtkIconTheme *icon_theme = gtk_icon_theme_get_default();1604 GtkIconTheme *icon_theme = gtk_icon_theme_get_default();
1574 if (self->priv->icon_theme_path != NULL) {1605 const gchar *theme_path = self->priv->absolute_icon_theme_path ?
1606 self->priv->absolute_icon_theme_path :
1607 self->priv->icon_theme_path;
1608
1609 if (theme_path != NULL) {
1575 gchar **path;1610 gchar **path;
1576 gint n_elements, i;1611 gint n_elements, i;
1577 gboolean found=FALSE;1612 gboolean found=FALSE;
1578 gtk_icon_theme_get_search_path(icon_theme, &path, &n_elements);1613 gtk_icon_theme_get_search_path(icon_theme, &path, &n_elements);
1579 for (i=0; i< n_elements || path[i] == NULL; i++) {1614 for (i=0; i< n_elements || path[i] == NULL; i++) {
1580 if(g_strcmp0(path[i], self->priv->icon_theme_path) == 0) {1615 if(g_strcmp0(path[i], theme_path) == 0) {
1581 found=TRUE;1616 found=TRUE;
1582 break;1617 break;
1583 }1618 }
1584 }1619 }
1585 if(!found) {1620 if(!found) {
1586 gtk_icon_theme_append_search_path(icon_theme, self->priv->icon_theme_path);1621 gtk_icon_theme_append_search_path(icon_theme, theme_path);
1587 }1622 }
1588 g_strfreev (path);1623 g_strfreev (path);
1589 }1624 }
@@ -1607,8 +1642,12 @@
1607 };1642 };
16081643
1609 if (icon_name != NULL) {1644 if (icon_name != NULL) {
1645 gchar *snapped_icon = append_snap_prefix(icon_name);
1646
1610 if (g_file_test(icon_name, G_FILE_TEST_EXISTS)) {1647 if (g_file_test(icon_name, G_FILE_TEST_EXISTS)) {
1611 gtk_status_icon_set_from_file(icon, icon_name);1648 gtk_status_icon_set_from_file(icon, icon_name);
1649 } else if (snapped_icon && g_file_test(snapped_icon, G_FILE_TEST_EXISTS)) {
1650 gtk_status_icon_set_from_file(icon, snapped_icon);
1612 } else {1651 } else {
1613 gchar *longname = append_panel_icon_suffix(icon_name);1652 gchar *longname = append_panel_icon_suffix(icon_name);
16141653
@@ -1620,6 +1659,8 @@
16201659
1621 g_free(longname);1660 g_free(longname);
1622 }1661 }
1662
1663 g_free(snapped_icon);
1623 }1664 }
16241665
1625 return;1666 return;
@@ -1633,7 +1674,7 @@
1633 GtkMenu * menu = app_indicator_get_menu(APP_INDICATOR(data));1674 GtkMenu * menu = app_indicator_get_menu(APP_INDICATOR(data));
1634 if (menu == NULL)1675 if (menu == NULL)
1635 return;1676 return;
1636 1677
1637 gtk_menu_popup(menu,1678 gtk_menu_popup(menu,
1638 NULL, /* Parent Menu */1679 NULL, /* Parent Menu */
1639 NULL, /* Parent item */1680 NULL, /* Parent item */
@@ -1681,7 +1722,7 @@
1681 long_name = g_strdup (icon_name);1722 long_name = g_strdup (icon_name);
1682 }1723 }
16831724
1684 return long_name; 1725 return long_name;
1685}1726}
16861727
1687static gboolean1728static gboolean
@@ -1858,6 +1899,14 @@
1858 if (g_strcmp0 (self->priv->attention_icon_name, icon_name) != 0) {1899 if (g_strcmp0 (self->priv->attention_icon_name, icon_name) != 0) {
1859 g_free (self->priv->attention_icon_name);1900 g_free (self->priv->attention_icon_name);
1860 self->priv->attention_icon_name = g_strdup (icon_name);1901 self->priv->attention_icon_name = g_strdup (icon_name);
1902
1903 g_free(self->priv->absolute_attention_icon_name);
1904 self->priv->absolute_attention_icon_name = NULL;
1905
1906 if (icon_name && icon_name[0] == '/') {
1907 self->priv->absolute_attention_icon_name = append_snap_prefix (icon_name);
1908 }
1909
1861 changed = TRUE;1910 changed = TRUE;
1862 }1911 }
18631912
@@ -1933,6 +1982,14 @@
1933 }1982 }
19341983
1935 self->priv->icon_name = g_strdup(icon_name);1984 self->priv->icon_name = g_strdup(icon_name);
1985
1986 g_free(self->priv->absolute_icon_name);
1987 self->priv->absolute_icon_name = NULL;
1988
1989 if (icon_name && icon_name[0] == '/') {
1990 self->priv->absolute_icon_name = append_snap_prefix (icon_name);
1991 }
1992
1936 changed = TRUE;1993 changed = TRUE;
1937 }1994 }
19381995
@@ -1994,6 +2051,54 @@
1994 return;2051 return;
1995}2052}
19962053
2054static const gchar *
2055get_snap_prefix ()
2056{
2057 const gchar *snap = g_getenv ("SNAP");
2058 return (snap && *snap != '\0') ? snap : NULL;
2059}
2060
2061static gchar *
2062append_snap_prefix (const gchar *path)
2063{
2064 gchar real_path[PATH_MAX];
2065 const gchar *snap = get_snap_prefix ();
2066
2067 if (snap != NULL && path != NULL) {
2068 if (realpath (path, real_path) != NULL) {
2069 path = real_path;
2070 }
2071
2072 if (g_str_has_prefix (path, "/tmp/")) {
2073 g_warning ("Using '/tmp' paths in SNAP environment will lead to unreadable resources");
2074 return NULL;
2075 }
2076
2077 if (g_str_has_prefix (path, snap)) {
2078 return g_strdup (path);
2079 }
2080
2081 return g_build_path (G_DIR_SEPARATOR_S, snap, path, NULL);
2082 }
2083
2084 return NULL;
2085}
2086
2087static gchar *
2088get_real_theme_path (AppIndicator * self)
2089{
2090 const gchar *theme_path = self->priv->icon_theme_path;
2091 gchar *snapped_path = append_snap_prefix (theme_path);
2092
2093 if (snapped_path != NULL) {
2094 return snapped_path;
2095 } else if (get_snap_prefix ()) {
2096 return g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (), "icons", NULL);
2097 }
2098
2099 return NULL;
2100}
2101
1997/**2102/**
1998 * app_indicator_set_icon_theme_path:2103 * app_indicator_set_icon_theme_path:
1999 * @self: The #AppIndicator object to use2104 * @self: The #AppIndicator object to use
@@ -2012,9 +2117,15 @@
20122117
2013 self->priv->icon_theme_path = g_strdup(icon_theme_path);2118 self->priv->icon_theme_path = g_strdup(icon_theme_path);
20142119
2120 g_free (self->priv->absolute_icon_theme_path);
2121 self->priv->absolute_icon_theme_path = get_real_theme_path (self);
2122
2015 g_signal_emit (self, signals[NEW_ICON_THEME_PATH], 0, self->priv->icon_theme_path, TRUE);2123 g_signal_emit (self, signals[NEW_ICON_THEME_PATH], 0, self->priv->icon_theme_path, TRUE);
20162124
2017 if (self->priv->dbus_registration != 0 && self->priv->connection != NULL) {2125 if (self->priv->dbus_registration != 0 && self->priv->connection != NULL) {
2126 const gchar *theme_path = self->priv->absolute_icon_theme_path ?
2127 self->priv->absolute_icon_theme_path :
2128 self->priv->icon_theme_path;
2018 GError * error = NULL;2129 GError * error = NULL;
20192130
2020 g_dbus_connection_emit_signal(self->priv->connection,2131 g_dbus_connection_emit_signal(self->priv->connection,
@@ -2022,7 +2133,7 @@
2022 self->priv->path,2133 self->priv->path,
2023 NOTIFICATION_ITEM_DBUS_IFACE,2134 NOTIFICATION_ITEM_DBUS_IFACE,
2024 "NewIconThemePath",2135 "NewIconThemePath",
2025 g_variant_new("(s)", self->priv->icon_theme_path),2136 g_variant_new("(s)", theme_path ? theme_path : ""),
2026 &error);2137 &error);
20272138
2028 if (error != NULL) {2139 if (error != NULL) {

Subscribers

People subscribed via source and target branches