Zenity dialogs in a snap

In this other thread, @jdstrand suggested to use a zenity dialog to inform users of a snap’s deprecation (in favour of another snap).
I finally got around to implementing this, and since this was less straightforward than I had hoped, I thought I’d share my notes here for others to use in similar use cases.

I had initially hoped to stage zenity and invoke it, but it turns out it’s not relocatable, it looks for its UI definition file in /usr/share/zenity/zenity.ui and there’s no way to prepend $SNAP to that location that doesn’t involve rebuilding zenity.

Here is a custom zenity part:

zenity:
  source: https://gitlab.gnome.org/GNOME/zenity.git
  source-tag: 3.28.1
  plugin: autotools
  configflags:
    - --disable-libnotify
    - --disable-webkitgtk
  build-packages:
    - gnome-pkg-tools
    - gnome-common
    - yelp-tools
    - gettext
    - libglib2.0-dev
    - libgtk-3-dev
  override-build: |
    set -eux
    patch -d . -p1 < ../../../snap/zenity-ui-snap-aware.patch
    snapcraftctl build

It uses a patch to make zenity snap-aware:

diff --git a/src/util.c b/src/util.c
index 0c10186..86c24a6 100644
--- a/src/util.c
+++ b/src/util.c
@@ -58,6 +58,8 @@ zenity_util_load_ui_file (const gchar *root_widget, ...) {
 	GError *error = NULL;
 	gchar **objects;
 	guint result = 0;
+	const gchar *env_var = NULL;
+	const gchar *zenity_ui_file_fullpath = NULL;
 
 	gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE);
 
@@ -86,9 +88,16 @@ zenity_util_load_ui_file (const gchar *root_widget, ...) {
 			builder, ZENITY_UI_FILE_RELATIVEPATH, objects, NULL);
 	}
 
-	if (result == 0)
+	if (result == 0) {
+		env_var = g_getenv ("SNAP");
+		if (env_var)
+			zenity_ui_file_fullpath = g_strconcat (env_var, ZENITY_UI_FILE_FULLPATH, NULL);
+		else
+			zenity_ui_file_fullpath = g_strdup (ZENITY_UI_FILE_FULLPATH);
 		result = gtk_builder_add_objects_from_file (
-			builder, ZENITY_UI_FILE_FULLPATH, objects, &error);
+			builder, zenity_ui_file_fullpath, objects, &error);
+		g_free (zenity_ui_file_fullpath);
+    }
 
 	g_strfreev (objects);

Don’t forget to use the desktop-gtk3 remote part to pull in all required dependencies and run zenity through the desktop-launch script.

And here is a complete example of all the pieces put together.

2 Likes

FWIW in the TrackMania Nations Forever snap we use yad which we found simpler, easier to bundle and is a drop-in replacement for zenity. Might also be worth a look.

3 Likes

how about making either of the two solutions a remote part one can easily include ?

1 Like

Yad doesn’t need a remote part really. It’s just a stage package. That’s what makes it more attractive than Zenity in my opinion. You just need to know how to drive it.

I’m also testing yad with wine snaps its quiet impressive indeed.

Some teaser

ts

4 Likes

I wish I had known of yad earlier, that would have saved me work. We should document it as the preferred option for dialog boxes in snap scripts.
Given how simple it seems to integrate as a stage package, there’s probably no point in exposing a remote part for zenity.

I’m not going to rewrite my play0ad deprecation warning using yad though, as I already have something that does the job.

3 Likes

I have created a remote part for zenity based on this recipe: The Zenity Remote Part

Guess this is no longer the case by using the layouts snapd feature?

True, layouts make this trick irrelevant.

For snaps that uses bases one can leverage The Zenity integration stage snap.

I realized that the extensions feature might be the perfect way to integrate Zenity, has anyone implemented it?

The following layout will work if zenity is a folder in the base snap

layout:
  /usr/share/zenity:
    bind: $SNAP/usr/share/zenity

Otherwise you can try with:

layout:
  /usr/share/zenity:
    symlink: $SNAP/usr/share/zenity

I do know that, however the configuration is split across parts(stage-packages, or independent part definition) and layouts stanza, which is not neat IMO.