Subject: Re: bug#36376: Application menu of desktop environment not automatically updated

From: Ludovic Courtès <[email-masked]>
Date: Tue, 03 Nov 2020 23:46:13 +0100

Ludovic Courtès <[email-masked]> skribis:

> This is not news to us, but as
> <https://distrowatch.com/weekly.php?issue=20190624#guixsd> notes, the
> application menu of desktop environments is not automatically updated
> when a package is installed or removed.  It’d be great if we could
> somehow notify the desktop environment.

We’ve investigated today on IRC with Maxim and Leo P. and here’s the
summary of our findings:

  • GNOME Shell, in ‘appDisplay.js’, “listens” to the
    ‘installed-changed’ GLib signals and uses that to rebuild its
    application menu.

  • In ‘shell-app-system.c’, ‘installed-changed’ is emitted when the
    GAppInfoMonitor emits ‘changed’:

      monitor = g_app_info_monitor_get ();
      g_signal_connect (monitor, "changed", G_CALLBACK (installed_changed), self);
      installed_changed (monitor, self);

  • GLib emits the ‘changed’ signal when ‘g_app_info_monitor_fire’ is
    called from ‘desktop_file_dir_changed’, itself called when one of
    the directories in $XDG_DATA_DIRS (among others) changes.  It uses
    ‘GFileMonitor’ under the hood, which is essentially inotify.

The GLib patch below is an attempt to monitor ~/.guix-profile and to
treat changes to that symlink as if they were changes to
~/.guix-profile/share/applications (which contains ‘.desktop’ files.)
It actually builds but I haven’t tested it yet.  :-)

WDYT?

If we take that route, we could add a ‘replacement’ for GLib.

Thanks,
Ludo’.

diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
index f1e2fdd..96dcc32 100644
--- a/gio/gdesktopappinfo.c
+++ b/gio/gdesktopappinfo.c
@@ -161,6 +161,7 @@ static DesktopFileDir *desktop_file_dir_user_config = NULL;  /* (owned) */
 static DesktopFileDir *desktop_file_dir_user_data = NULL;  /* (owned) */
 static GMutex          desktop_file_dir_lock;
 static const gchar    *gio_launch_desktop_path = NULL;
+static GFileMonitor   *guix_profile_monitor = NULL;
 
 /* Monitor 'changed' signal handler {{{2 */
 static void desktop_file_dir_reset (DesktopFileDir *dir);
@@ -230,6 +231,22 @@ desktop_file_dir_get_alternative_dir (DesktopFileDir *dir)
   return parent;
 }
 
+static void
+guix_profile_changed  (GFileMonitor      *monitor,
+                       GFile             *file,
+                       GFile             *other_file,
+                       GFileMonitorEvent  event_type,
+                       gpointer           user_data)
+{
+  DesktopFileDir *dir = user_data;
+
+  desktop_file_dir_reset (dir);
+
+  /* When ~/.guix-profile changes, emit the 'changed' signal so everyone
+     knows.  */
+  g_app_info_monitor_fire ();
+}
+
 static void
 desktop_file_dir_changed (GFileMonitor      *monitor,
                           GFile             *file,
@@ -1531,6 +1548,7 @@ desktop_file_dirs_lock (void)
 
   if (desktop_file_dirs == NULL || desktop_file_dirs->len == 0)
     {
+      const gchar *home;
       const char * const *dirs;
       gint i;
 
@@ -1555,6 +1573,27 @@ desktop_file_dirs_lock (void)
       for (i = 0; dirs[i]; i++)
         g_ptr_array_add (desktop_file_dirs, desktop_file_dir_new (dirs[i]));
 
+      home = g_get_home_dir ();
+      if (guix_profile_monitor == NULL && home != NULL)
+        {
+          DesktopFileDir *dir;
+          const gchar *profile, *data_dir;
+          profile = g_build_filename (home, ".guix-profile", NULL);
+          data_dir = g_build_filename (profile, "share", NULL);
+          dir = desktop_file_dir_new (data_dir);
+
+          /* Monitor ~/.guix-profile and treat modifications to
+             ~/.guix-profile as if they were modifications to
+             ~/.guix-profile/share.  */
+          guix_profile_monitor =
+            g_local_file_monitor_new_in_worker (profile, FALSE, G_FILE_MONITOR_NONE,
+                                                guix_profile_changed,
+                                                desktop_file_dir_ref (dir),
+                                                closure_notify_cb, NULL);
+
+          g_ptr_array_add (desktop_file_dirs, desktop_file_dir_ref (dir));
+        }
+
       /* The list of directories will never change after this, unless
        * g_get_user_config_dir() changes due to %G_TEST_OPTION_ISOLATE_DIRS. */
       desktop_file_dirs_config_dir = user_config_dir;