[balsa/gtk4: 92/314] Various: Use stateless GActions with targets




commit bea32a179f791435276e8cc1288f5d8aa293d0f5
Author: Peter Bloomfield <PeterBloomfield bellsouth net>
Date:   Sun Sep 13 18:05:48 2020 -0400

    Various: Use stateless GActions with targets
    
    Use stateless GActions with targets instead of setting GObject data on
    random objects.
    
    If the GAction is given a non-NULL parameter type but no state and no
    "change state" callback, it is rendered as stateless, and the target can
    be retrieved from the GVariant parameter of the "activated" callback. The
    target cannot be an arbitrary pointer, and is in fact a string in all
    these cases:
    
    * libbalsa/libbalsa-vfs.c  (libbalsa_vfs_launch_app),
      (libbalsa_vfs_launch_app_for_body), (gio_add_vfs_menu_item),
      (libbalsa_vfs_fill_menu_by_content_type),
      (libbalsa_vfs_mime_button):
    * libbalsa/libbalsa-vfs.h:
    * src/balsa-index.c  (move_to_activated), (bndx_add_actions),
      (bndx_do_popup):
    * src/balsa-mblist.c  (balsa_mblist_mru_menu),
      (balsa_mblist_mru_get_url_from_variant),
      (balsa_mblist_mru_get_mailbox_from_variant):
    * src/balsa-mblist.h:
    * src/balsa-message.c  (open_with_activated), (copy_part_activated),
      (part_add_actions), (part_create_menu):
    * src/balsa-mime-widget-callbacks.c
      (balsa_mime_widget_ctx_menu_launch_app),
      (balsa_mime_widget_ctx_menu_cb):
    * src/balsa-mime-widget-callbacks.h:
    * src/balsa-mime-widget-message.c  (copy_activated),
      (bm_header_extend_popup):
    * src/balsa-mime-widget-text.c  (open_with_activated),
      (text_view_populate_popup), (bmwt_html_open_with_activated),
      (bmwt_html_populate_popup_menu), (bmwt_html_button_press_cb):
    * src/message-window.c  (move_to_activated), (message_window_new):
    * src/sendmsg-window.c  (launch_app_activated), (open_attachment),
      (add_attachment), (add_urlref_attachment):
    
    mblist: Add guards for NULL GVariant

 ChangeLog                         |  37 +++++++++++++
 libbalsa/libbalsa-vfs.c           |  89 +++++++++++++----------------
 libbalsa/libbalsa-vfs.h           |   9 +--
 src/balsa-index.c                 |  16 +++---
 src/balsa-mblist.c                | 114 ++++++++++++--------------------------
 src/balsa-mblist.h                |  20 ++-----
 src/balsa-message.c               |  52 +++++++++--------
 src/balsa-mime-widget-callbacks.c |  10 ++--
 src/balsa-mime-widget-callbacks.h |   2 +-
 src/balsa-mime-widget-message.c   |  23 ++++----
 src/balsa-mime-widget-text.c      |  44 +++++++--------
 src/message-window.c              |  20 ++++---
 src/sendmsg-window.c              |  34 +++++-------
 13 files changed, 217 insertions(+), 253 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index de1210855..d1822122b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -187,6 +187,43 @@
        "activate-on-single-click" property to TRUE, instead of doing it
        the hard way.
 
+2020-09-13  Peter Bloomfield  <pbloomfield bellsouth net>
+
+       Various: Use stateless GActions with targets instead of setting
+       GObject data on random objects.
+
+       If the GAction is given a non-NULL parameter type but no state
+       and no "change state" callback, it is rendered as stateless, and
+       the target can be retrieved from the GVariant parameter of the
+       "activated" callback. The target cannot be an arbitrary pointer,
+       and is in fact a string in all these cases:
+
+       * libbalsa/libbalsa-vfs.c (libbalsa_vfs_launch_app),
+       (libbalsa_vfs_launch_app_for_body), (gio_add_vfs_menu_item),
+       (libbalsa_vfs_fill_menu_by_content_type),
+       (libbalsa_vfs_mime_button):
+       * libbalsa/libbalsa-vfs.h:
+       * src/balsa-index.c (move_to_activated), (bndx_add_actions),
+       (bndx_do_popup):
+       * src/balsa-mblist.c (balsa_mblist_mru_menu),
+       (balsa_mblist_mru_get_url_from_variant),
+       (balsa_mblist_mru_get_mailbox_from_variant):
+       * src/balsa-mblist.h:
+       * src/balsa-message.c (open_with_activated), (copy_part_activated),
+       (part_add_actions), (part_create_menu):
+       * src/balsa-mime-widget-callbacks.c
+       (balsa_mime_widget_ctx_menu_launch_app),
+       (balsa_mime_widget_ctx_menu_cb):
+       * src/balsa-mime-widget-callbacks.h:
+       * src/balsa-mime-widget-message.c (copy_activated),
+       (bm_header_extend_popup):
+       * src/balsa-mime-widget-text.c (open_with_activated),
+       (text_view_populate_popup), (bmwt_html_open_with_activated),
+       (bmwt_html_populate_popup_menu), (bmwt_html_button_press_cb):
+       * src/message-window.c (move_to_activated), (message_window_new):
+       * src/sendmsg-window.c (launch_app_activated), (open_attachment),
+       (add_attachment), (add_urlref_attachment):
+
 2020-09-02  Peter Bloomfield  <pbloomfield bellsouth net>
 
        balsa-index: add a timeout to verify that the scrolled-to row is
diff --git a/libbalsa/libbalsa-vfs.c b/libbalsa/libbalsa-vfs.c
index 090090fed..f82b0ee20 100644
--- a/libbalsa/libbalsa-vfs.c
+++ b/libbalsa/libbalsa-vfs.c
@@ -528,13 +528,28 @@ libbalsa_vfs_file_unlink(LibbalsaVfs * file, GError **err)
 
 
 gboolean
-libbalsa_vfs_launch_app(LibbalsaVfs * file, GAppInfo *app, GError **err)
-{
+libbalsa_vfs_launch_app(LibbalsaVfs *file,
+                        const gchar *app_name,
+                        GError     **err)
+ {
+    GList *app_list;
+    GList *list;
+    GAppInfo *app = NULL;
     GList * args;
     gboolean result;
 
     g_return_val_if_fail(LIBBALSA_IS_VFS(file), FALSE);
-    g_return_val_if_fail(app == NULL || G_IS_APP_INFO(app), FALSE);
+    g_return_val_if_fail(app_name != NULL, FALSE);
+
+    app_list = g_app_info_get_all();
+    for (list = app_list; list != NULL; list = list->next) {
+        GAppInfo *this_app = G_APP_INFO(list->data);
+        if (strcmp(app_name, g_app_info_get_name(this_app)) == 0) {
+            app = g_object_ref(this_app);
+            break;
+        }
+    }
+    g_list_free_full(app_list, g_object_unref);
 
     if (app == NULL) {
         g_set_error(err, LIBBALSA_VFS_ERROR_QUARK, -1,
@@ -545,6 +560,7 @@ libbalsa_vfs_launch_app(LibbalsaVfs * file, GAppInfo *app, GError **err)
     args = g_list_prepend(NULL, file->gio_gfile);
     result = g_app_info_launch(app, args, NULL, err);
     g_list_free(args);
+    g_object_unref(app);
 
     return result;
 }
@@ -552,7 +568,7 @@ libbalsa_vfs_launch_app(LibbalsaVfs * file, GAppInfo *app, GError **err)
 
 gboolean
 libbalsa_vfs_launch_app_for_body(LibBalsaMessageBody *mime_body,
-                                 GAppInfo            *app,
+                                 const gchar         *app_name,
                                  GError             **err)
 {
     gchar *uri;
@@ -560,7 +576,7 @@ libbalsa_vfs_launch_app_for_body(LibBalsaMessageBody *mime_body,
     gboolean result;
 
     g_return_val_if_fail(mime_body != NULL, FALSE);
-    g_return_val_if_fail(app == NULL || G_IS_APP_INFO(app), FALSE);
+    g_return_val_if_fail(app_name != NULL, FALSE);
 
     if (!libbalsa_message_body_save_temporary(mime_body, err))
         return FALSE;
@@ -569,7 +585,7 @@ libbalsa_vfs_launch_app_for_body(LibBalsaMessageBody *mime_body,
     file = libbalsa_vfs_new_from_uri(uri);
     g_free(uri);
 
-    result = libbalsa_vfs_launch_app(file, app, err);
+    result = libbalsa_vfs_launch_app(file, app_name, err);
     g_object_unref(file);
 
     return result;
@@ -602,52 +618,26 @@ libbalsa_vfs_content_type_of_buffer(const guchar * buffer,
     return retval;
 }
 
-/*
- * GAppInfo support
- */
 
 static void
 gio_add_vfs_menu_item(GMenu       *menu,
                       GAppInfo    *app,
-                      GActionMap  *action_map,
-                      const gchar *action_namespace,
-                      GCallback    callback,
-                      GObject     *object)
+                      const gchar *action)
 {
-    const gchar *app_name;
+    const gchar *name;
     gchar *menu_label;
-    gchar *action_name;
-    gchar *p;
-    GSimpleAction *action;
+    GMenuItem *menu_item;
 
-    app_name = g_app_info_get_name(app);
+    name = g_app_info_get_name(app);
 
-    action_name = g_strstrip(g_strdup(app_name));
-
-    for (p = action_name; *p != '\0'; p++) {
-        if (!g_ascii_isalnum(*p))
-            *p = '-';
-    }
-
-    action = g_simple_action_new(action_name, NULL);
-    g_signal_connect(action, "activate", callback, object);
-    g_action_map_add_action(action_map, G_ACTION(action));
-    g_object_unref(action);
-
-    g_object_set_data_full(object, action_name, g_object_ref(app), g_object_unref);
-
-    if (action_namespace != NULL) {
-        gchar *prefixed_action_name;
+    menu_label = g_strdup_printf(_("Open with %s"), name);
+    menu_item = g_menu_item_new(menu_label, NULL);
+    g_free(menu_label);
 
-        prefixed_action_name = g_strdup_printf("%s.%s", action_namespace, action_name);
-        g_free(action_name);
-        action_name = prefixed_action_name;
-    }
+    g_menu_item_set_action_and_target_value(menu_item, action, g_variant_new_string(name));
 
-    menu_label = g_strdup_printf(_("Open with %s"), app_name);
-    g_menu_append(menu, menu_label, action_name);
-    g_free(menu_label);
-    g_free(action_name);
+    g_menu_append_item(menu, menu_item);
+    g_object_unref(menu_item);
 }
 
 
@@ -655,22 +645,19 @@ gio_add_vfs_menu_item(GMenu       *menu,
 void
 libbalsa_vfs_fill_menu_by_content_type(GMenu       *menu,
                                        const gchar *content_type,
-                                       GActionMap  *action_map,
-                                       const gchar *action_namespace,
-                                       GCallback    callback,
-                                       GObject     *object)
+                                       const gchar *action)
 {
     GList* list;
     GAppInfo *def_app;
     GList *app_list;
 
     g_return_if_fail(G_IS_MENU(menu));
-    g_return_if_fail(G_IS_ACTION_MAP(action_map));
-    g_return_if_fail(G_IS_OBJECT(object));
+    g_return_if_fail(content_type != NULL);
+    g_return_if_fail(action != NULL);
 
     def_app = g_app_info_get_default_for_type(content_type, FALSE);
     if (def_app != NULL)
-        gio_add_vfs_menu_item(menu, def_app, action_map, action_namespace, callback, object);
+        gio_add_vfs_menu_item(menu, def_app, action);
 
     app_list = g_app_info_get_all_for_type(content_type);
     for (list = app_list; list != NULL; list = list->next) {
@@ -678,7 +665,7 @@ libbalsa_vfs_fill_menu_by_content_type(GMenu       *menu,
 
         if (app != NULL && g_app_info_should_show(app) &&
             (def_app == NULL || !g_app_info_equal(app, def_app)))
-            gio_add_vfs_menu_item(menu, app, action_map, action_namespace, callback, object);
+            gio_add_vfs_menu_item(menu, app, action);
     }
     g_list_free_full(app_list, g_object_unref);
 
@@ -702,7 +689,7 @@ libbalsa_vfs_mime_button(const gchar * content_type, GCallback callback, gpointe
        g_free(msg);
 
        g_object_set_data_full(G_OBJECT(button), LIBBALSA_VFS_MIME_ACTION,
-                               app, g_object_unref);
+                              g_strdup(app_name), g_free);
 
        g_signal_connect(button, "clicked", callback, data);
     }
diff --git a/libbalsa/libbalsa-vfs.h b/libbalsa/libbalsa-vfs.h
index b4f3f4608..84ff8f205 100644
--- a/libbalsa/libbalsa-vfs.h
+++ b/libbalsa/libbalsa-vfs.h
@@ -70,17 +70,14 @@ gint libbalsa_vfs_file_unlink(LibbalsaVfs * file,
 
 /* application launch helpers */
 gboolean libbalsa_vfs_launch_app(LibbalsaVfs *file,
-                                 GAppInfo    *app,
+                                 const gchar *app_name,
                                  GError     **err);
 gboolean libbalsa_vfs_launch_app_for_body(LibBalsaMessageBody *mime_body,
-                                          GAppInfo            *app,
+                                          const gchar         *app_name,
                                           GError             **err);
 void libbalsa_vfs_fill_menu_by_content_type(GMenu       *menu,
                                             const gchar *content_type,
-                                            GActionMap  *action_map,
-                                            const gchar *action_namespace,
-                                            GCallback    callback,
-                                            GObject     *object);
+                                            const gchar *action);
 GtkWidget * libbalsa_vfs_mime_button(const gchar * content_type,
                                      GCallback     callback,
                                      gpointer      data);
diff --git a/src/balsa-index.c b/src/balsa-index.c
index 99934b77d..5540fdbc8 100644
--- a/src/balsa-index.c
+++ b/src/balsa-index.c
@@ -2039,7 +2039,8 @@ move_to_activated(GSimpleAction *action,
     BalsaIndex *bindex = user_data;
     LibBalsaMailbox *mailbox;
 
-    mailbox = balsa_mblist_mru_get_mailbox(action, GTK_WIDGET(bindex), user_data);
+    mailbox =
+        balsa_mblist_mru_get_mailbox_from_variant(parameter, GTK_WIDGET(bindex));
 
     if (mailbox != NULL) {
         balsa_mblist_mru_add(&balsa_app.folder_mru, libbalsa_mailbox_get_url(mailbox));
@@ -2049,6 +2050,9 @@ move_to_activated(GSimpleAction *action,
             balsa_index_selected_msgnos_free(bindex, selected);
         }
     }
+
+    if (GTK_IS_POPOVER(bindex->popup_widget))
+        gtk_popover_popdown((GtkPopover *) bindex->popup_widget);
 }
 
 /*
@@ -2072,7 +2076,8 @@ bndx_add_actions(BalsaIndex  *bindex,
         {"trash",            move_to_trash_activated},
         {"toggle-flagged",   toggle_flagged_activated},
         {"toggle-unread",    toggle_unread_activated},
-        {"view-source",      view_source_activated}
+        {"view-source",      view_source_activated},
+        {"move-to",          move_to_activated, "s"}
     };
 
     simple = g_simple_action_group_new();
@@ -2206,16 +2211,13 @@ bndx_do_popup(BalsaIndex * index, const GdkEvent *event)
     bndx_action_set_enabled(index, "popup", "trash", any && !readonly && mailbox != balsa_app.trash);
     bndx_action_set_enabled(index, "popup", "toggle-flagged", any && !readonly);
     bndx_action_set_enabled(index, "popup", "toggle-unread", any && !readonly);
+    bndx_action_set_enabled(index, "popup", "move-to", any && !readonly);
 
     /* The move-to submenu */
     item = g_menu_item_new_from_model(G_MENU_MODEL(index->popup_menu),
                                       index->move_position);
 
-    mru_menu = balsa_mblist_mru_menu(&balsa_app.folder_mru,
-                                     G_ACTION_MAP(gtk_widget_get_action_group(GTK_WIDGET(index),
-                                                                              "popup")),
-                                     any && !readonly, NULL,
-                                     G_CALLBACK(move_to_activated), index);
+    mru_menu = balsa_mblist_mru_menu(&balsa_app.folder_mru, "move-to");
     g_menu_item_set_submenu(item, G_MENU_MODEL(mru_menu));
     g_object_unref(mru_menu);
 
diff --git a/src/balsa-mblist.c b/src/balsa-mblist.c
index 5c93af6ba..e9b01c5bc 100644
--- a/src/balsa-mblist.c
+++ b/src/balsa-mblist.c
@@ -1689,66 +1689,17 @@ static void bmbl_mru_activated_cb(GtkTreeView * tree_view,
  * that resolves to a mailbox, labeled with the mailbox name, with a
  * last entry that pops up the whole mailbox tree.
  */
-
-#define BALSA_MBLIST_MRU_MENU_OTHER "-"
-
-static void
-bmbl_add_action(GMenu       *section,
-                const gchar *url,
-                GActionMap  *action_map,
-                gboolean     action_enabled,
-                const gchar *action_namespace,
-                const gchar *label,
-                GCallback    callback,
-                gpointer     user_data)
-{
-    gchar *action_name;
-    gchar *p;
-    GSimpleAction *action;
-
-    action_name = g_strstrip(g_strdup(url));
-
-    /* Make the action name valid. */
-    for (p = action_name; *p != '\0'; p++) {
-        if (!g_ascii_isalnum(*p))
-            *p = '-';
-    }
-
-    action = g_simple_action_new(action_name, NULL);
-    g_signal_connect(action, "activate", callback, user_data);
-    g_simple_action_set_enabled(action, action_enabled),
-    g_action_map_add_action(action_map, G_ACTION(action));
-    g_object_unref(action);
-
-    if (strcmp(url, BALSA_MBLIST_MRU_MENU_OTHER) != 0)
-        g_object_set_data_full(user_data, action_name, g_strdup(url), g_free);
-
-    if (action_namespace != NULL) {
-        gchar *prefixed_action_name;
-
-        prefixed_action_name = g_strdup_printf("%s.%s", action_namespace, action_name);
-        g_free(action_name);
-        action_name = prefixed_action_name;
-    }
-
-    g_menu_append(section, label, action_name);
-    g_free(action_name);
-}
-
 GMenu *
-balsa_mblist_mru_menu(GList      **url_list,
-                      GActionMap  *action_map,
-                      gboolean     action_enabled,
-                      const gchar *action_namespace,
-                      GCallback    callback,
-                      gpointer     user_data)
+balsa_mblist_mru_menu(GList ** url_list,
+                      const gchar *action)
 {
     GMenu *menu;
     GMenu *section;
     GList *list;
+    GMenuItem *item;
 
     g_return_val_if_fail(url_list != NULL, NULL);
-    g_return_val_if_fail(G_IS_ACTION_MAP(action_map), NULL);
+    g_return_val_if_fail(action != NULL, NULL);
 
     menu = g_menu_new();
 
@@ -1759,18 +1710,25 @@ balsa_mblist_mru_menu(GList      **url_list,
         LibBalsaMailbox *mailbox = balsa_find_mailbox_by_url(url);
 
         if (mailbox != NULL) {
-            bmbl_add_action(section, url, action_map, action_enabled, action_namespace,
-                            libbalsa_mailbox_get_name(mailbox), callback, user_data);
+            const gchar *name = libbalsa_mailbox_get_name(mailbox);
+
+            item = g_menu_item_new(name, NULL);
+            g_menu_item_set_action_and_target_value(item, action, g_variant_new_string(url));
+            g_menu_append_item(section, item);
+            g_object_unref(item);
         }
     }
 
     g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
     g_object_unref(section);
 
-    /* Other… section */
     section = g_menu_new();
-    bmbl_add_action(section, BALSA_MBLIST_MRU_MENU_OTHER, action_map, action_enabled,
-                    action_namespace, _("_Other…"), callback, user_data);
+
+    item = g_menu_item_new(_("_Other…"), NULL);
+    g_menu_item_set_action_and_target_value(item, action, g_variant_new_string(""));
+    g_menu_append_item(section, item);
+    g_object_unref(item);
+
     g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
     g_object_unref(section);
 
@@ -2413,57 +2371,57 @@ bmbl_choose_mailbox(GtkWidget *widget)
 }
 
 /*
- * balsa_mblist_mru_get_url,
- * balsa_mblist_mru_get_mailbox:
+ * balsa_mblist_mru_get_url_from_variant,
+ * balsa_mblist_mru_get_mailbox_from_variant:
  *
  * Helpers for "_change_state" actions of mru_menus
  *
- * Get the url as GObject data from the object parameter. If it is NULL,
+ * Get the url from the GVariant parameter. If it is an empty string,
  * the user selected "Other...", so we must pop up the mailbox list dialog
  * and let the user choose the mailbox. That dialog can be canceled,
  * returning a NULL mailbox, so we must be careful; the caller must be
- * prepared for the return of a NULL url or mailbox, respectively.
+ * prepared for the return of an empty url string or a NULL mailbox,
  */
 
 const gchar *
-balsa_mblist_mru_get_url(GSimpleAction *action, GtkWidget *widget, GObject *object)
+balsa_mblist_mru_get_url_from_variant(GVariant *parameter, GtkWidget *widget)
 {
-    const gchar *action_name;
     const gchar *url;
 
-    g_return_val_if_fail(G_IS_ACTION(action), NULL);
+    g_return_val_if_fail(parameter != NULL, NULL);
+    g_return_val_if_fail(g_variant_is_of_type(parameter, G_VARIANT_TYPE_STRING), NULL);
     g_return_val_if_fail(GTK_IS_WIDGET(widget), NULL);
-    g_return_val_if_fail(G_IS_OBJECT(object), NULL);
 
-    action_name = g_action_get_name((GAction *) action);
-    url = g_object_get_data(object, action_name);
+    url = g_variant_get_string(parameter, NULL);
 
-    if (url == NULL) {
+    if (url[0] == '\0') {
         LibBalsaMailbox *mailbox;
 
         mailbox = bmbl_choose_mailbox(widget);
 
-        url = mailbox != NULL ? libbalsa_mailbox_get_url(mailbox) : NULL;
+        if (mailbox != NULL)
+            url = libbalsa_mailbox_get_url(mailbox);
     }
 
     return url;
 }
 
 LibBalsaMailbox *
-balsa_mblist_mru_get_mailbox(GSimpleAction *action, GtkWidget *widget, GObject *object)
+balsa_mblist_mru_get_mailbox_from_variant(GVariant *parameter, GtkWidget *widget)
 {
-    const gchar *action_name;
-    const gchar *url;
     LibBalsaMailbox *mailbox;
+    const gchar *url;
 
-    g_return_val_if_fail(G_IS_ACTION(action), NULL);
+    g_return_val_if_fail(parameter != NULL, NULL);
+    g_return_val_if_fail(g_variant_is_of_type(parameter, G_VARIANT_TYPE_STRING), NULL);
     g_return_val_if_fail(GTK_IS_WIDGET(widget), NULL);
-    g_return_val_if_fail(G_IS_OBJECT(object), NULL);
 
-    action_name = g_action_get_name((GAction *) action);
-    url = g_object_get_data(object, action_name);
+    url = g_variant_get_string(parameter, NULL);
 
-    mailbox = url == NULL ? bmbl_choose_mailbox(widget) : balsa_find_mailbox_by_url(url);
+    if (url[0] == '\0')
+        mailbox = bmbl_choose_mailbox(widget);
+    else
+        mailbox = balsa_find_mailbox_by_url(url);
 
     return mailbox;
 }
diff --git a/src/balsa-mblist.h b/src/balsa-mblist.h
index 165118592..c07318e3f 100644
--- a/src/balsa-mblist.h
+++ b/src/balsa-mblist.h
@@ -50,27 +50,19 @@ BalsaMailboxNode *balsa_mblist_get_selected_node(BalsaMBList * mblist);
 BalsaMailboxNode *balsa_mblist_get_node_by_mailbox(BalsaMBList * mblist,
                                                    LibBalsaMailbox *
                                                    mailbox);
-
-GMenu * balsa_mblist_mru_menu(GList      **url_list,
-                              GActionMap  *action_map,
-                              gboolean     action_enabled,
-                              const gchar *action_namespace,
-                              GCallback    callback,
-                              gpointer     user_data);
+GMenu *balsa_mblist_mru_menu(GList ** url_list,
+                             const gchar *action);
 void balsa_mblist_mru_add(GList ** url_list, const gchar * url);
 void balsa_mblist_mru_drop(GList ** url_list, const gchar * url);
-const gchar     *balsa_mblist_mru_get_url    (GSimpleAction *action,
-                                              GtkWidget     *widget,
-                                              GObject       *object);
-LibBalsaMailbox *balsa_mblist_mru_get_mailbox(GSimpleAction *action,
-                                              GtkWidget     *widget,
-                                              GObject       *object);
-
 GtkWidget *balsa_mblist_mru_option_menu(GtkWindow * window, 
                                         GList ** url_list);
 void balsa_mblist_mru_option_menu_set(GtkWidget * option_menu,
                                       const gchar * url);
 const gchar *balsa_mblist_mru_option_menu_get(GtkWidget * option_menu);
+const gchar *balsa_mblist_mru_get_url_from_variant(GVariant  *parameter,
+                                                   GtkWidget *widget);
+LibBalsaMailbox *balsa_mblist_mru_get_mailbox_from_variant(GVariant  *parameter,
+                                                           GtkWidget *widget);
 
 /* BalsaMailboxNode methods */
 void balsa_mblist_mailbox_node_append(BalsaMailboxNode * root,
diff --git a/src/balsa-message.c b/src/balsa-message.c
index 08cca13b6..4c5a6ba01 100644
--- a/src/balsa-message.c
+++ b/src/balsa-message.c
@@ -1804,14 +1804,10 @@ open_with_activated(GSimpleAction *action,
                     GVariant      *parameter,
                     gpointer       user_data)
 {
+    const gchar *app_name = g_variant_get_string(parameter, NULL);
     BalsaPartInfo *info = user_data;
-    const gchar *action_name;
-    GAppInfo *app;
 
-    action_name = g_action_get_name(G_ACTION(action));
-    app = g_object_get_data(user_data, action_name);
-
-    balsa_mime_widget_ctx_menu_launch_app(app, info->body);
+    balsa_mime_widget_ctx_menu_launch_app(app_name, info->body);
 
     if (GTK_IS_POPOVER(info->popup_widget))
         gtk_popover_popdown((GtkPopover *) info->popup_widget);
@@ -1825,28 +1821,37 @@ copy_part_activated(GSimpleAction *action,
     BalsaPartInfo *info = user_data;
     const gchar *url;
 
-    url = balsa_mblist_mru_get_url(action, info->popup_widget, user_data);
+    url = balsa_mblist_mru_get_url_from_variant(parameter, info->popup_widget);
 
-    if (url != NULL) {
+    if (url[0] != '\0') {
         balsa_mblist_mru_add(&balsa_app.folder_mru, url);
         balsa_message_copy_part(url, info->body);
     }
+
+    if (GTK_IS_POPOVER(info->popup_widget))
+        gtk_popover_popdown((GtkPopover *) info->popup_widget);
 }
 
-static GSimpleActionGroup *
+static void
 part_add_actions(BalsaMessage *balsa_message,
+                 const gchar  *action_namespace,
                  gpointer      user_data)
 {
     GSimpleActionGroup *simple;
     static const GActionEntry entries[] = {
-        {"save", save_activated}
+        {"save", save_activated},
+        {"open-with", open_with_activated, "s"},
+        {"copy-part", copy_part_activated, "s"}
     };
 
     simple = g_simple_action_group_new();
     g_action_map_add_action_entries(G_ACTION_MAP(simple),
                                     entries, G_N_ELEMENTS(entries),
                                     user_data);
-    return simple;
+    gtk_widget_insert_action_group(GTK_WIDGET(balsa_message),
+                                   action_namespace,
+                                   G_ACTION_GROUP(simple));
+    g_object_unref(simple);
 }
 
 static void
@@ -1858,35 +1863,28 @@ part_create_menu(BalsaMessage *balsa_message, BalsaPartInfo *info)
             3) GnomeVFS shortlist applications, with the default one (sometimes
                included on shortlist, sometimes not) excluded. */
 {
-    GMenu *menu;
-    gchar *content_type;
-    GSimpleActionGroup *simple;
     static int menu_number;
     gchar *namespace;
+    GMenu *menu;
+    gchar *content_type;
 
-    menu = g_menu_new();
-    content_type = libbalsa_message_body_get_mime_type (info->body);
-    simple = part_add_actions(balsa_message, info);
+    namespace = g_strdup_printf("menu-%d", ++menu_number);
 
-    libbalsa_vfs_fill_menu_by_content_type(menu, content_type,
-                                           G_ACTION_MAP(simple), NULL,
-                                           G_CALLBACK(open_with_activated),
-                                           G_OBJECT(info));
+    part_add_actions(balsa_message, namespace, info);
 
-    namespace = g_strdup_printf("menu-%d", ++menu_number);
-    gtk_widget_insert_action_group(GTK_WIDGET(balsa_message), namespace, G_ACTION_GROUP(simple));
+    menu = g_menu_new();
+
+    content_type = libbalsa_message_body_get_mime_type (info->body);
+    libbalsa_vfs_fill_menu_by_content_type(menu, content_type, "open-with");
 
     g_menu_append(menu, _("Save…"), "save");
 
     if (strcmp(content_type, "message/rfc822") == 0) {
         GMenu *submenu;
 
-        submenu = balsa_mblist_mru_menu(&balsa_app.folder_mru, G_ACTION_MAP(simple),
-                                        TRUE, NULL,
-                                        G_CALLBACK(copy_part_activated), info);
+        submenu = balsa_mblist_mru_menu(&balsa_app.folder_mru, "copy-part");
         g_menu_append_submenu(menu, _("_Copy to folder…"), G_MENU_MODEL(submenu));
     }
-    g_object_unref(simple);
     g_free(content_type);
 
     info->popup_widget =
diff --git a/src/balsa-mime-widget-callbacks.c b/src/balsa-mime-widget-callbacks.c
index e6466f299..1f3850229 100644
--- a/src/balsa-mime-widget-callbacks.c
+++ b/src/balsa-mime-widget-callbacks.c
@@ -37,7 +37,7 @@
 
 
 void
-balsa_mime_widget_ctx_menu_launch_app(GAppInfo            *app,
+balsa_mime_widget_ctx_menu_launch_app(const gchar         *app_name,
                                       LibBalsaMessageBody *mime_body)
 {
     GError *err = NULL;
@@ -45,7 +45,7 @@ balsa_mime_widget_ctx_menu_launch_app(GAppInfo            *app,
 
     g_return_if_fail(mime_body != NULL);
 
-    result = libbalsa_vfs_launch_app_for_body(mime_body, app, &err);
+    result = libbalsa_vfs_launch_app_for_body(mime_body, app_name, &err);
     if (!result)
         balsa_information(LIBBALSA_INFORMATION_WARNING,
                           _("Could not launch application: %s"),
@@ -58,10 +58,10 @@ balsa_mime_widget_ctx_menu_cb(GtkWidget *button,
                               gpointer   user_data)
 {
     LibBalsaMessageBody *mime_body = user_data;
-    GAppInfo *app;
+    const gchar *app_name;
 
-    app = g_object_get_data(G_OBJECT(button), LIBBALSA_VFS_MIME_ACTION);
-    balsa_mime_widget_ctx_menu_launch_app(app, mime_body);
+    app_name = g_object_get_data(G_OBJECT(button), LIBBALSA_VFS_MIME_ACTION);
+    balsa_mime_widget_ctx_menu_launch_app(app_name, mime_body);
 }
 
 /** Pops up a "save part" dialog for a message part.
diff --git a/src/balsa-mime-widget-callbacks.h b/src/balsa-mime-widget-callbacks.h
index 892ca2e1c..2b496e9b8 100644
--- a/src/balsa-mime-widget-callbacks.h
+++ b/src/balsa-mime-widget-callbacks.h
@@ -27,7 +27,7 @@
 G_BEGIN_DECLS
 
 
-void balsa_mime_widget_ctx_menu_launch_app(GAppInfo            *app,
+void balsa_mime_widget_ctx_menu_launch_app(const gchar         *app_name,
                                            LibBalsaMessageBody *mime_body);
 void balsa_mime_widget_ctx_menu_cb(GtkWidget * button,
                                    gpointer    user_data);
diff --git a/src/balsa-mime-widget-message.c b/src/balsa-mime-widget-message.c
index a448a51c6..220c80ab1 100644
--- a/src/balsa-mime-widget-message.c
+++ b/src/balsa-mime-widget-message.c
@@ -442,13 +442,11 @@ copy_activated(GSimpleAction *action,
                GVariant      *parameter,
                gpointer       user_data)
 {
-    LibBalsaMessageBody *part = g_object_get_data(user_data, "part");
-    GtkWidget *widget = user_data;
-    const gchar *url;
+    LibBalsaMessageBody *part = user_data;
+    const gchar *url =
+        balsa_mblist_mru_get_url_from_variant(parameter, part->user_data);
 
-    url = balsa_mblist_mru_get_url(action, widget, user_data);
-
-    if (url != NULL) {
+    if (url[0] != '\0') {
         balsa_mblist_mru_add(&balsa_app.folder_mru, url);
         balsa_message_copy_part(url, part);
     }
@@ -459,6 +457,9 @@ bm_header_extend_popup(GtkWidget * widget, GtkMenu * menu, gpointer arg)
 {
     LibBalsaMessageBody *part = arg;
     GSimpleActionGroup *simple;
+    static const GActionEntry header_popup_entries[] = {
+        {"copy", copy_activated, "s"},
+    };
     GMenu *mru_menu;
     GtkWidget *menu_item, *submenu;
     GtkWidget *separator = gtk_separator_menu_item_new();
@@ -475,15 +476,17 @@ bm_header_extend_popup(GtkWidget * widget, GtkMenu * menu, gpointer arg)
     gtk_widget_show(menu_item);
 
     simple = g_simple_action_group_new();
-    g_object_set_data(G_OBJECT(part->user_data), "part", part);
-    mru_menu = balsa_mblist_mru_menu(&balsa_app.folder_mru, G_ACTION_MAP(simple),
-                                     TRUE, "header-popup",
-                                     G_CALLBACK(copy_activated), part->user_data);
+    g_action_map_add_action_entries(G_ACTION_MAP(simple),
+                                    header_popup_entries,
+                                    G_N_ELEMENTS(header_popup_entries),
+                                    part);
     gtk_widget_insert_action_group(widget,
                                    "header-popup",
                                    G_ACTION_GROUP(simple));
     g_object_unref(simple);
 
+    mru_menu =
+        balsa_mblist_mru_menu(&balsa_app.folder_mru, "header-popup.copy");
     submenu = gtk_menu_new_from_model(G_MENU_MODEL(mru_menu));
     g_object_unref(mru_menu);
 
diff --git a/src/balsa-mime-widget-text.c b/src/balsa-mime-widget-text.c
index 84d05f44a..f29346f83 100644
--- a/src/balsa-mime-widget-text.c
+++ b/src/balsa-mime-widget-text.c
@@ -606,15 +606,10 @@ open_with_activated(GSimpleAction *action,
                     GVariant      *parameter,
                     gpointer       user_data)
 {
-    BalsaMimeWidgetText *mwt = user_data;
-    LibBalsaMessageBody *part = mwt->mime_body;
-    const gchar *action_name;
-    GAppInfo *app;
-
-    action_name = g_action_get_name(G_ACTION(action));
-    app = g_object_get_data(user_data, action_name);
+    const gchar *app_name = g_variant_get_string(parameter, NULL);
+    LibBalsaMessageBody *part = user_data;
 
-    balsa_mime_widget_ctx_menu_launch_app(app, part);
+    balsa_mime_widget_ctx_menu_launch_app(app_name, part);
 }
 
 static void
@@ -624,6 +619,9 @@ text_view_populate_popup(GtkWidget *widget, GtkMenu *menu,
     BalsaMimeWidgetText *mwt = user_data;
     GtkWidget *menu_item;
     GSimpleActionGroup *simple;
+    static const GActionEntry text_view_popup_entries[] = {
+        {"open-with", open_with_activated, "s"}
+    };
     GMenu *open_menu;
     GtkWidget *submenu;
 
@@ -644,18 +642,18 @@ text_view_populate_popup(GtkWidget *widget, GtkMenu *menu,
                          gtk_separator_menu_item_new());
 
     /* Set up the "open-with" action: */
-    open_menu = g_menu_new();
     simple = g_simple_action_group_new();
-    libbalsa_vfs_fill_menu_by_content_type(open_menu, "text/plain",
-                                           G_ACTION_MAP(simple), "text-view-popup",
-                                           G_CALLBACK(open_with_activated),
-                                           G_OBJECT(mwt));
+    g_action_map_add_action_entries(G_ACTION_MAP(simple),
+                                    text_view_popup_entries,
+                                    G_N_ELEMENTS(text_view_popup_entries),
+                                    mwt->mime_body);
     gtk_widget_insert_action_group(GTK_WIDGET(menu),
                                    "text-view-popup",
                                    G_ACTION_GROUP(simple));
-
     g_object_unref(simple);
 
+    open_menu = g_menu_new();
+    libbalsa_vfs_fill_menu_by_content_type(open_menu, "text/plain", "open-with");
     submenu = gtk_menu_new_from_model(G_MENU_MODEL(open_menu));
     g_object_unref(open_menu);
 
@@ -1175,13 +1173,12 @@ bmwt_html_open_with_activated(GSimpleAction *action,
 {
     GtkWidget *html = user_data;
     gpointer mime_body = g_object_get_data(G_OBJECT(html), "mime-body");
-    const gchar *action_name;
-    GAppInfo *app;
+    GtkWidget *popup_widget = g_object_get_data(G_OBJECT(html), "popup-widget");
 
-    action_name = g_action_get_name(G_ACTION(action));
-    app = g_object_get_data(user_data, action_name);
+    open_with_activated(action, parameter, mime_body);
 
-    balsa_mime_widget_ctx_menu_launch_app(app, mime_body);
+    if (GTK_IS_POPOVER(popup_widget))
+        gtk_popover_popdown((GtkPopover *) popup_widget);
 }
 
 static void
@@ -1269,6 +1266,7 @@ bmwt_html_populate_popup_menu(BalsaMessage * bm,
                                    G_ACTION_GROUP(simple));
 
     print_action = g_action_map_lookup_action(G_ACTION_MAP(simple), "print");
+    g_object_unref(simple);
 
     section = g_menu_new();
 
@@ -1289,11 +1287,7 @@ bmwt_html_populate_popup_menu(BalsaMessage * bm,
     section = g_menu_new();
 
     open_menu = g_menu_new();
-    libbalsa_vfs_fill_menu_by_content_type(open_menu, "text/html",
-                                           G_ACTION_MAP(simple), NULL,
-                                           G_CALLBACK(bmwt_html_open_with_activated),
-                                           G_OBJECT(html));
-    g_object_unref(simple);
+    libbalsa_vfs_fill_menu_by_content_type(open_menu, "text/html", "open-with");
 
     g_menu_append_submenu(section, _("Open…"), G_MENU_MODEL(open_menu));
     g_object_unref(open_menu);
@@ -1385,7 +1379,7 @@ bmwt_html_button_press_cb(GtkGestureMultiPress *multi_press,
 
     if (gdk_event_triggers_context_menu(event)) {
         GtkWidget *html = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
-        bmwt_html_popup_context_menu(html, bm);
+        bmwt_html_popup_context_menu(html, bm) ;
     }
 }
 
diff --git a/src/message-window.c b/src/message-window.c
index ef071403d..62b09fc71 100644
--- a/src/message-window.c
+++ b/src/message-window.c
@@ -799,14 +799,12 @@ move_to_activated(GSimpleAction *action,
                   GVariant      *parameter,
                   gpointer       user_data)
 {
-    GtkWidget *window = user_data;
+    MessageWindow *mw = user_data;
     LibBalsaMailbox *mailbox;
 
-    mailbox = balsa_mblist_mru_get_mailbox(action, window, user_data);
+    mailbox = balsa_mblist_mru_get_mailbox_from_variant(parameter, mw->window);
 
     if (mailbox != NULL) {
-        MessageWindow *mw = g_object_get_data(G_OBJECT(window), "mw");
-
         balsa_mblist_mru_add(&balsa_app.folder_mru, libbalsa_mailbox_get_url(mailbox));
         message_window_move_message(mw, mailbox);
     }
@@ -828,6 +826,9 @@ message_window_new(LibBalsaMailbox * mailbox, guint msgno)
     const gchar resource_path[] = "/org/desktop/Balsa/message-window.ui";
     GAction *action;
     GSimpleActionGroup *simple;
+    static const GActionEntry message_window_entries[] = {
+        {"move-to", move_to_activated, "s"},
+    };
     GMenu *mru_menu;
 
     if (!mailbox || !msgno)
@@ -895,16 +896,17 @@ message_window_new(LibBalsaMailbox * mailbox, guint msgno)
 
     /* Set up the "move-to" action */
     simple = g_simple_action_group_new();
-    g_object_set_data(G_OBJECT(mw->window), "mw", mw);
-    mru_menu = balsa_mblist_mru_menu(&balsa_app.folder_mru,
-                                     G_ACTION_MAP(simple), TRUE,
-                                     "message-window",
-                                     G_CALLBACK(move_to_activated), mw->window);
+    g_action_map_add_action_entries(G_ACTION_MAP(simple),
+                                    message_window_entries,
+                                    G_N_ELEMENTS(message_window_entries),
+                                    mw);
     gtk_widget_insert_action_group(GTK_WIDGET(mw->window),
                                    "message-window",
                                    G_ACTION_GROUP(simple));
     g_object_unref(simple);
 
+    mru_menu =
+        balsa_mblist_mru_menu(&balsa_app.folder_mru, "message-window.move-to");
     submenu = gtk_menu_new_from_model(G_MENU_MODEL(mru_menu));
     g_object_unref(mru_menu);
 
diff --git a/src/sendmsg-window.c b/src/sendmsg-window.c
index 30898847b..3c0853388 100644
--- a/src/sendmsg-window.c
+++ b/src/sendmsg-window.c
@@ -1372,20 +1372,16 @@ change_attach_mode(GSimpleAction *action,
 
 /* attachment vfs menu - right mouse button callback */
 static void
-attachment_menu_vfs_cb(GSimpleAction *action,
-                       GVariant      *parameter,
-                       gpointer       user_data)
+launch_app_activated(GSimpleAction *action,
+                     GVariant      *parameter,
+                     gpointer       user_data)
 {
+    const gchar *app_name = g_variant_get_string(parameter, NULL);
     BalsaAttachInfo *info = user_data;
-    const gchar *action_name;
-    GAppInfo *app;
     GError *err = NULL;
     gboolean result;
 
-    action_name = g_action_get_name(G_ACTION(action));
-    app = g_object_get_data(user_data, action_name);
-
-    result = libbalsa_vfs_launch_app(info->file_uri, app, &err);
+    result = libbalsa_vfs_launch_app(info->file_uri, app_name, &err);
     if (!result)
         balsa_information(LIBBALSA_INFORMATION_WARNING,
                           _("Could not launch application: %s"),
@@ -1399,9 +1395,9 @@ attachment_menu_vfs_cb(GSimpleAction *action,
 
 /* URL external body - right mouse button callback */
 static void
-on_open_url_cb(GSimpleAction *action,
-               GVariant      *parameter,
-               gpointer       user_data)
+open_attachment(GSimpleAction *action,
+                GVariant      *parameter,
+                gpointer       user_data)
 {
     BalsaAttachInfo *info = user_data;
     GtkWidget *toplevel;
@@ -1653,7 +1649,8 @@ add_attachment(BalsaSendmsg * bsmsg, const gchar *filename,
     GSimpleActionGroup *simple;
     static GActionEntry attachment_entries[] = {
         {"new-mode", NULL, "i", "1", change_attach_mode},
-        {"remove", remove_attachment}
+        {"remove", remove_attachment},
+        {"launch-app", launch_app_activated, "s"}
     };
     GMenu *menu;
     GMenu *section;
@@ -1758,6 +1755,7 @@ add_attachment(BalsaSendmsg * bsmsg, const gchar *filename,
     gtk_widget_insert_action_group(bsmsg->window,
                                    attachment_namespace,
                                    G_ACTION_GROUP(simple));
+    g_object_unref(simple);
 
     menu = g_menu_new();
 
@@ -1801,14 +1799,10 @@ add_attachment(BalsaSendmsg * bsmsg, const gchar *filename,
        attached... (only for non-message attachments) */
     if (!is_fwd_message) {
         section = g_menu_new();
-        libbalsa_vfs_fill_menu_by_content_type(section, content_type,
-                                               G_ACTION_MAP(simple), NULL,
-                                               G_CALLBACK(attachment_menu_vfs_cb),
-                                               G_OBJECT(attach_data));
+        libbalsa_vfs_fill_menu_by_content_type(section, content_type, "launch-app");
         g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
         g_object_unref(section);
     }
-    g_object_unref(simple);
 
     attach_data->popup_menu =
         libbalsa_popup_widget_new(bsmsg->tree_view, G_MENU_MODEL(menu), attachment_namespace);
@@ -1848,7 +1842,7 @@ add_urlref_attachment(BalsaSendmsg * bsmsg, const gchar *url)
     GSimpleActionGroup *simple;
     static GActionEntry attachment_entries[] = {
         {"remove", remove_attachment},
-        {"open", on_open_url_cb}
+        {"open", open_attachment, "s"}
     };
     GMenu *menu;
     GMenu *section;
@@ -1903,7 +1897,7 @@ add_urlref_attachment(BalsaSendmsg * bsmsg, const gchar *url)
     g_object_unref(section);
 
     attach_data->popup_menu =
-        libbalsa_popup_widget_new(bsmsg->tree_view, G_MENU_MODEL(menu), "urlref-attachment");
+        libbalsa_popup_widget_new(bsmsg->window, G_MENU_MODEL(menu), "urlref-attachment");
     g_object_unref(menu);
 
     /* append to the list store */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]