[balsa/gtk4: 32/311] Various: Port menus to GtkPopover




commit 167e7c9434138e815b6aab7a3ea76e2e663cea99
Author: Peter Bloomfield <PeterBloomfield bellsouth net>
Date:   Mon May 11 22:55:33 2020 -0400

    Various: Port menus to GtkPopover

 libbalsa/html.c               |   9 +-
 libbalsa/html.h               |   1 -
 src/balsa-index.c             |   6 +-
 src/balsa-mblist.c            |  26 +--
 src/balsa-message.c           |   4 +-
 src/balsa-mime-widget-image.c |   4 +-
 src/balsa-mime-widget-text.c  |  59 +-----
 src/mailbox-node.c            | 439 +++++++++++++++++++++++++++---------------
 src/mailbox-node.h            |   3 +-
 src/sendmsg-window.c          |  10 -
 10 files changed, 322 insertions(+), 239 deletions(-)
---
diff --git a/libbalsa/html.c b/libbalsa/html.c
index 4ed0f6b30..fe7c6e985 100644
--- a/libbalsa/html.c
+++ b/libbalsa/html.c
@@ -1163,15 +1163,8 @@ libbalsa_html_get_selection_bounds(GtkWidget    * widget,
 }
 
 /*
- * Get the WebKitWebView widget from the container; we need to connect
- * to its "populate-popup" signal.
+ * Get the view widget
  */
-GtkWidget *
-libbalsa_html_popup_menu_widget(GtkWidget * widget)
-{
-    return NULL;
-}
-
 GtkWidget *
 libbalsa_html_get_view_widget(GtkWidget * widget)
 {
diff --git a/libbalsa/html.h b/libbalsa/html.h
index e68867444..72ab8c9ca 100644
--- a/libbalsa/html.h
+++ b/libbalsa/html.h
@@ -70,7 +70,6 @@ gboolean libbalsa_html_get_selection_bounds(GtkWidget * widget,
                                             selection_bounds);
 
 #define LIBBALSA_HTML_POPUP_EVENT "libbalsa-html-popup-event"
-GtkWidget *libbalsa_html_popup_menu_widget(GtkWidget * widget);
 GtkWidget *libbalsa_html_get_view_widget(GtkWidget * widget);
 
 guint64 libbalsa_html_cache_size(void);
diff --git a/src/balsa-index.c b/src/balsa-index.c
index aa28b9144..2efbfef6a 100644
--- a/src/balsa-index.c
+++ b/src/balsa-index.c
@@ -244,11 +244,6 @@ bndx_destroy(GObject * obj)
         bindex->search_iter = NULL;
     }
 
-    if (bindex->popup_menu) {
-        g_object_unref(bindex->popup_menu);
-        bindex->popup_menu = NULL;
-    }
-
     if (bindex->selection_changed_idle_id != 0) {
         g_source_remove(bindex->selection_changed_idle_id);
         bindex->selection_changed_idle_id = 0;
@@ -2219,6 +2214,7 @@ bndx_do_popup(BalsaIndex * index)
     /* Replace the existing submenu */
     g_menu_remove(index->popup_menu, index->move_position);
     g_menu_insert_item(index->popup_menu, index->move_position, item);
+    g_object_unref(item);
 
     gtk_widget_get_allocation(GTK_WIDGET(index), &allocation);
     if (event != NULL && gdk_event_triggers_context_menu((GdkEvent *) event)) {
diff --git a/src/balsa-mblist.c b/src/balsa-mblist.c
index 2d299b21d..8252bb9e4 100644
--- a/src/balsa-mblist.c
+++ b/src/balsa-mblist.c
@@ -737,18 +737,22 @@ bmbl_do_popup(GtkTreeView    *tree_view,
         gtk_tree_path_free(path);
     }
 
-    menu = balsa_mailbox_node_get_context_menu(mbnode);
-    g_object_ref(menu);
-    g_object_ref_sink(menu);
-    if (event)
-        gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *) event);
-    else
-        gtk_menu_popup_at_widget(GTK_MENU(menu), GTK_WIDGET(tree_view),
-                                 GDK_GRAVITY_CENTER, GDK_GRAVITY_CENTER,
-                                 NULL);
-    g_object_unref(menu);
+    menu = balsa_mailbox_node_get_context_menu(mbnode, GTK_WIDGET(tree_view));
+
+    if (event != NULL && gdk_event_triggers_context_menu((GdkEvent *) event)) {
+        GdkRectangle rectangle;
+
+        /* Pop up above the pointer */
+        rectangle.x = event->x;
+        rectangle.width = 0;
+        rectangle.y = event->y;
+        rectangle.height = 0;
+        gtk_popover_set_pointing_to(GTK_POPOVER(menu), &rectangle);
+    }
+
+    gtk_popover_popup(GTK_POPOVER(menu));
 
-    if (mbnode)
+    if (mbnode != NULL)
        g_object_unref(mbnode);
 }
 
diff --git a/src/balsa-message.c b/src/balsa-message.c
index 19c21c54d..d6a61ae96 100644
--- a/src/balsa-message.c
+++ b/src/balsa-message.c
@@ -1757,8 +1757,10 @@ display_content(BalsaMessage * balsa_message)
 
     balsa_message->parts_menu = g_menu_new();
 
+    /* Detach any existing popup: */
     if (balsa_message->parts_popup != NULL)
-       g_object_unref(balsa_message->parts_popup);
+       gtk_popover_set_relative_to(GTK_POPOVER(balsa_message->parts_popup), NULL);
+
     balsa_message->parts_popup =
         gtk_popover_new_from_model(balsa_message->attach_button,
                                    G_MENU_MODEL(balsa_message->parts_menu));
diff --git a/src/balsa-mime-widget-image.c b/src/balsa-mime-widget-image.c
index f358b9457..ee1561057 100644
--- a/src/balsa-mime-widget-image.c
+++ b/src/balsa-mime-widget-image.c
@@ -146,7 +146,7 @@ balsa_image_button_press_cb(GtkGestureMultiPress *multi_press_gesture,
                             gdouble               y,
                             gpointer              user_data)
 {
-    GtkMenu *menu = user_data;
+    GtkPopover *menu = user_data;
     GtkGesture *gesture;
     GdkEventSequence *sequence;
     const GdkEvent *event;
@@ -156,7 +156,7 @@ balsa_image_button_press_cb(GtkGestureMultiPress *multi_press_gesture,
     event    = gtk_gesture_get_last_event(gesture, sequence);
 
     if (gdk_event_triggers_context_menu(event)) {
-        gtk_menu_popup_at_pointer(menu, event);
+        gtk_popover_popup(menu);
         gtk_gesture_set_sequence_state(gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED);
     }
 }
diff --git a/src/balsa-mime-widget-text.c b/src/balsa-mime-widget-text.c
index 23eb6f767..4c138bbdf 100644
--- a/src/balsa-mime-widget-text.c
+++ b/src/balsa-mime-widget-text.c
@@ -1210,7 +1210,7 @@ bmwt_html_populate_popup_menu(BalsaMessage * bm,
     g_object_unref(simple);
 
     open_menu = g_menu_new();
-    libbalsa_vfs_fill_menu_by_content_type(open_menu, "text/plain",
+    libbalsa_vfs_fill_menu_by_content_type(open_menu, "text/html",
                                            "text-view-popup.open-with");
     submenu = gtk_menu_new_from_model(G_MENU_MODEL(open_menu));
     g_object_unref(open_menu);
@@ -1285,39 +1285,12 @@ bmwt_html_popup_context_menu(GtkWidget * html, BalsaMessage * bm)
     return TRUE;
 }
 
-static void
-bmwt_html_gesture_pressed_cb(GtkGestureMultiPress *multi_press,
-                             gint                  n_press,
-                             gdouble               x,
-                             gdouble               y,
-                             gpointer              user_data)
-{
-    GtkGesture *gesture;
-    const GdkEvent *event;
-    BalsaMessage *bm = user_data;
-
-    gesture = GTK_GESTURE(multi_press);
-    event = gtk_gesture_get_last_event(gesture, gtk_gesture_get_last_updated_sequence(gesture));
-
-    if (gdk_event_triggers_context_menu(event)) {
-        GtkWidget *html;
-
-        html = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
-        bmwt_html_popup_context_menu(html, bm);
-    }
-}
-
-static void
-bmwt_html_populate_popup_cb(GtkWidget * widget, GtkMenu * menu, gpointer data)
+static gboolean
+balsa_gtk_html_button_press_cb(GtkWidget * html, GdkEventButton * event,
+                               BalsaMessage * bm)
 {
-    BalsaMessage *bm =
-        g_object_get_data(G_OBJECT(widget), "balsa-message");
-    GtkWidget *html = data;
-
-    /* Remove WebKitWebView's items--they're irrelevant and confusing */
-    gtk_container_foreach(GTK_CONTAINER(menu),
-                         (GtkCallback) gtk_widget_destroy, NULL);
-    bmwt_html_populate_popup_menu(bm, html, menu);
+    return(gdk_event_triggers_context_menu((GdkEvent *) event)
+           ? balsa_gtk_html_popup(html, bm) : GDK_EVENT_PROPAGATE);
 }
 
 static BalsaMimeWidget *
@@ -1326,7 +1299,6 @@ bm_widget_new_html(BalsaMessage * bm, LibBalsaMessageBody * mime_body)
     BalsaMimeWidgetText *mwt = g_object_new(BALSA_TYPE_MIME_WIDGET_TEXT, NULL);
     InternetAddressList *from;
     GtkWidget *widget;
-    GtkWidget *popup_menu;
     GtkEventController *key_controller;
 
     from = libbalsa_message_get_headers(balsa_message_get_message(bm))->from;
@@ -1343,21 +1315,10 @@ bm_widget_new_html(BalsaMessage * bm, LibBalsaMessageBody * mime_body)
     g_signal_connect(key_controller, "key-pressed",
                     G_CALLBACK(balsa_mime_widget_key_pressed), bm);
 
-    if ((popup_menu = libbalsa_html_popup_menu_widget(widget)) != NULL) {
-        g_object_set_data(G_OBJECT(popup_menu), "balsa-message", bm);
-        g_signal_connect(popup_menu, "populate-popup",
-                         G_CALLBACK(bmwt_html_populate_popup_cb), widget);
-    } else {
-        GtkGesture *gesture;
-
-        gesture = gtk_gesture_multi_press_new(widget);
-        gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 0);
-        g_signal_connect(gesture, "pressed",
-                         G_CALLBACK(bmwt_html_gesture_pressed_cb), bm);
-
-        g_signal_connect(widget, "popup-menu",
-                         G_CALLBACK(bmwt_html_popup_context_menu), bm);
-    }
+    g_signal_connect(widget, "button-press-event",
+                     G_CALLBACK(balsa_gtk_html_button_press_cb), bm);
+    g_signal_connect(widget, "popup-menu",
+                     G_CALLBACK(balsa_gtk_html_popup), bm);
 
     return (BalsaMimeWidget *) mwt;
 }
diff --git a/src/mailbox-node.c b/src/mailbox-node.c
index 03dd11189..8cc7916d4 100644
--- a/src/mailbox-node.c
+++ b/src/mailbox-node.c
@@ -89,6 +89,7 @@ static guint balsa_mailbox_node_signals[LAST_SIGNAL];
 
 struct _BalsaMailboxNode {
     GObject object;
+
     BalsaMailboxNode *parent; /* NULL for root-level folders & mailboxes */
     LibBalsaMailbox *mailbox; /* != NULL for leaves only */
     gchar *name;       /* used for folders, i.e. when mailbox == NULL */
@@ -101,6 +102,9 @@ struct _BalsaMailboxNode {
     int delim; /* IMAP delimiter so that we do not need to check it
                 * too often. */
 
+    GtkWidget *context_menu;
+    GtkWidget *relative_to;
+
     unsigned subscribed:1;     /* Used only by remote */
     unsigned list_inbox:1;     /* Used only by remote */
     unsigned scanned:1;        /* IMAP flag */
@@ -857,225 +861,358 @@ bmbn_scan_children_idle(BalsaMailboxNode ** mbnode)
 /* ---------------------------------------------------------------------
  * Context menu, helpers, and callbacks.
  * --------------------------------------------------------------------- */
+
+gboolean
+balsa_mailbox_node_is_imap(const BalsaMailboxNode *mbnode)
+{
+    return (mbnode != NULL) &&
+            (mbnode->server != NULL) &&
+            (strcmp(libbalsa_server_get_protocol(mbnode->server), "imap") == 0);
+}
+
 static void
-add_menu_entry(GtkWidget * menu, const gchar * label, GCallback cb,
-              BalsaMailboxNode * mbnode)
+add_mbox_activated(GSimpleAction *action,
+                   GVariant      *parameter,
+                   gpointer       user_data)
 {
-    GtkWidget *menuitem;
+    mailbox_conf_add_mbox_cb(NULL, user_data);
+}
 
-    menuitem = label ? gtk_menu_item_new_with_mnemonic(label)
-       : gtk_separator_menu_item_new();
+static void
+add_maildir_activated(GSimpleAction *action,
+                      GVariant      *parameter,
+                      gpointer       user_data)
+{
+    mailbox_conf_add_maildir_cb(NULL, user_data);
+}
 
-    if (cb)
-       g_signal_connect(menuitem, "activate",
-                        G_CALLBACK(cb), mbnode);
+static void
+add_mh_activated(GSimpleAction *action,
+                 GVariant      *parameter,
+                 gpointer       user_data)
+{
+    mailbox_conf_add_mh_cb(NULL, user_data);
+}
 
-    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-    gtk_widget_show(menuitem);
+static void
+add_imap_folder_activated(GSimpleAction *action,
+                          GVariant      *parameter,
+                          gpointer       user_data)
+{
+    folder_conf_add_imap_cb(NULL, user_data);
 }
 
 static void
-mb_open_cb(GtkWidget * widget, BalsaMailboxNode * mbnode)
+add_imap_subfolder_activated(GSimpleAction *action,
+                             GVariant      *parameter,
+                             gpointer       user_data)
 {
-    g_return_if_fail(LIBBALSA_IS_MAILBOX(mbnode->mailbox));
-    balsa_mblist_open_mailbox(mbnode->mailbox);
+    folder_conf_add_imap_sub_cb(NULL, user_data);
 }
 
 static void
-mb_close_cb(GtkWidget * widget, BalsaMailboxNode * mbnode)
+rescan_activated(GSimpleAction *action,
+                 GVariant      *parameter,
+                 gpointer       user_data)
 {
-    g_return_if_fail(LIBBALSA_IS_MAILBOX(mbnode->mailbox));
-    balsa_window_close_mbnode(balsa_app.main_window, mbnode);
+    BalsaMailboxNode *mbnode = user_data;
+    gchar *current_mailbox_url;
+    GPtrArray *url_array;
+
+    current_mailbox_url = g_strdup(balsa_app.current_mailbox_url);
+    balsa_mailbox_node_rescan(mbnode);
+
+    /* Reopen mailboxes */
+    url_array = g_ptr_array_new();
+    if (current_mailbox_url)
+        g_ptr_array_add(url_array, current_mailbox_url);
+    balsa_add_open_mailbox_urls(url_array);
+    g_ptr_array_add(url_array, NULL);
+    balsa_open_mailbox_list((gchar **) g_ptr_array_free(url_array, FALSE));
 }
 
 static void
-mb_conf_cb(GtkWidget * widget, BalsaMailboxNode * mbnode)
+show_properties_activated(GSimpleAction *action,
+                          GVariant      *parameter,
+                          gpointer       user_data)
 {
+    BalsaMailboxNode *mbnode = user_data;
+
     balsa_mailbox_node_show_prop_dialog(mbnode);
 }
 
 static void
-mb_del_cb(GtkWidget * widget, BalsaMailboxNode * mbnode)
+delete_activated(GSimpleAction *action,
+                 GVariant      *parameter,
+                 gpointer       user_data)
 {
-    if(mbnode->mailbox)
-       mailbox_conf_delete(mbnode);
-    else folder_conf_delete(mbnode);
+    BalsaMailboxNode *mbnode = user_data;
+
+    if (mbnode->mailbox != NULL)
+        mailbox_conf_delete(mbnode);
+    else
+        folder_conf_delete(mbnode);
 }
 
 static void
-mb_inbox_cb(GtkWidget * widget, BalsaMailboxNode * mbnode)
+context_menu_set_enabled(BalsaMailboxNode *mbnode)
 {
-    g_return_if_fail(LIBBALSA_IS_MAILBOX(mbnode->mailbox));
-    config_mailbox_set_as_special(mbnode->mailbox, SPECIAL_INBOX);
+    gboolean is_open;
+    GActionGroup *action_group;
+    GActionMap *action_map;
+    GAction *action;
+
+    action_group = gtk_widget_get_action_group(mbnode->relative_to, "mbnode");
+    action_map = G_ACTION_MAP(action_group);
+
+    is_open = MAILBOX_OPEN(mbnode->mailbox);
+
+    action = g_action_map_lookup_action(action_map, "open");
+    g_simple_action_set_enabled(G_SIMPLE_ACTION(action), !is_open);
+
+    action = g_action_map_lookup_action(action_map, "close");
+    g_simple_action_set_enabled(G_SIMPLE_ACTION(action), is_open);
 }
 
 static void
-mb_sentbox_cb(GtkWidget * widget, BalsaMailboxNode * mbnode)
+open_activated(GSimpleAction *action,
+               GVariant      *parameter,
+               gpointer       user_data)
 {
-    g_return_if_fail(LIBBALSA_IS_MAILBOX(mbnode->mailbox));
-    config_mailbox_set_as_special(mbnode->mailbox, SPECIAL_SENT);
+    BalsaMailboxNode *mbnode = user_data;
+
+    balsa_mblist_open_mailbox(mbnode->mailbox);
+    context_menu_set_enabled(mbnode);
 }
 
 static void
-mb_trash_cb(GtkWidget * widget, BalsaMailboxNode * mbnode)
+close_activated(GSimpleAction *action,
+                GVariant      *parameter,
+                gpointer       user_data)
 {
-    g_return_if_fail(LIBBALSA_IS_MAILBOX(mbnode->mailbox));
-    config_mailbox_set_as_special(mbnode->mailbox, SPECIAL_TRASH);
+    BalsaMailboxNode *mbnode = user_data;
+
+    balsa_window_close_mbnode(balsa_app.main_window, mbnode);
+    context_menu_set_enabled(mbnode);
 }
 
 static void
-mb_draftbox_cb(GtkWidget * widget, BalsaMailboxNode * mbnode)
+mark_as_inbox_activated(GSimpleAction *action,
+                        GVariant      *parameter,
+                        gpointer       user_data)
 {
-    g_return_if_fail(LIBBALSA_IS_MAILBOX(mbnode->mailbox));
-    config_mailbox_set_as_special(mbnode->mailbox, SPECIAL_DRAFT);
+    BalsaMailboxNode *mbnode = user_data;
+
+    config_mailbox_set_as_special(mbnode->mailbox, SPECIAL_INBOX);
 }
 
 static void
-mb_rescan_cb(GtkWidget * widget, BalsaMailboxNode * mbnode)
+mark_as_sentbox_activated(GSimpleAction *action,
+                          GVariant      *parameter,
+                          gpointer       user_data)
 {
-    gchar *current_mailbox_url;
-    GPtrArray *url_array;
+    BalsaMailboxNode *mbnode = user_data;
 
-    current_mailbox_url = g_strdup(balsa_app.current_mailbox_url);
-    balsa_mailbox_node_rescan(mbnode);
+    config_mailbox_set_as_special(mbnode->mailbox, SPECIAL_SENT);
+}
 
-    /* Reopen mailboxes */
-    url_array = g_ptr_array_new();
-    if (current_mailbox_url)
-        g_ptr_array_add(url_array, current_mailbox_url);
-    balsa_add_open_mailbox_urls(url_array);
-    g_ptr_array_add(url_array, NULL);
-    balsa_open_mailbox_list((gchar **) g_ptr_array_free(url_array, FALSE));
+static void
+mark_as_trash_activated(GSimpleAction *action,
+                        GVariant      *parameter,
+                        gpointer       user_data)
+{
+    BalsaMailboxNode *mbnode = user_data;
+
+    config_mailbox_set_as_special(mbnode->mailbox, SPECIAL_TRASH);
 }
 
 static void
-mb_filter_cb(GtkWidget * widget, BalsaMailboxNode * mbnode)
+mark_as_draftbox_activated(GSimpleAction *action,
+                           GVariant      *parameter,
+                           gpointer       user_data)
 {
-    if (mbnode->mailbox)
-        filters_run_dialog(mbnode->mailbox,
-                           GTK_WINDOW(balsa_app.main_window));
-    else
-       /* FIXME : Perhaps should we be able to apply filters on
-          folders (ie recurse on all mailboxes in it), but there are
-          problems of infinite recursion (when one mailbox being
-          filtered is also the destination of the filter action (eg a
-          copy)). So let's see that later :) */
-       libbalsa_information_parented(GTK_WINDOW(balsa_app.main_window),
-               LIBBALSA_INFORMATION_MESSAGE, _("You can apply filters only on mailbox"));
+    BalsaMailboxNode *mbnode = user_data;
+
+    config_mailbox_set_as_special(mbnode->mailbox, SPECIAL_DRAFT);
 }
 
 static void
-mb_empty_trash_cb(GtkWidget * widget, BalsaMailboxNode * mbnode)
+empty_trash_activated(GSimpleAction *action,
+                      GVariant      *parameter,
+                      gpointer       user_data)
 {
     empty_trash(balsa_app.main_window);
 }
 
-gboolean
-balsa_mailbox_node_is_imap(const BalsaMailboxNode *mbnode)
+static void
+filters_activated(GSimpleAction *action,
+                  GVariant      *parameter,
+                  gpointer       user_data)
 {
-       return (mbnode != NULL) &&
-               (mbnode->server != NULL) &&
-               (strcmp(libbalsa_server_get_protocol(mbnode->server), "imap") == 0);
+    BalsaMailboxNode *mbnode = user_data;
+
+    if (mbnode->mailbox != NULL) {
+        filters_run_dialog(mbnode->mailbox,
+                           GTK_WINDOW(balsa_app.main_window));
+    } else {
+        /* FIXME : Perhaps should we be able to apply filters on
+           folders (ie recurse on all mailboxes in it), but there are
+           problems of infinite recursion (when one mailbox being
+           filtered is also the destination of the filter action (eg a
+           copy)). So let's see that later :) */
+        g_print("You can apply filters only on mailbox\n");
+    }
 }
 
-GtkWidget *
-balsa_mailbox_node_get_context_menu(BalsaMailboxNode * mbnode)
-{
-    GtkWidget *menu;
-    GtkWidget *submenu;
-    GtkWidget *menuitem;
+static GtkWidget *
+create_context_menu(BalsaMailboxNode *mbnode,
+                    GtkWidget        *relative_to)
+{
+    static const GActionEntry entries[] = {
+        {"add-mbox", add_mbox_activated},
+        {"add-maildir", add_maildir_activated},
+        {"add-mh", add_mh_activated},
+        {"add-imap-folder", add_imap_folder_activated},
+        {"add-imap-subfolder", add_imap_subfolder_activated},
+        {"rescan", rescan_activated},
+        {"show-properties", show_properties_activated},
+        {"delete", delete_activated},
+        {"open", open_activated},
+        {"close", close_activated},
+        {"mark-as-inbox", mark_as_inbox_activated},
+        {"mark-as-sentbox", mark_as_sentbox_activated},
+        {"mark-as-trash", mark_as_trash_activated},
+        {"mark-as-draftbox", mark_as_draftbox_activated},
+        {"empty-trash", empty_trash_activated},
+        {"filters", filters_activated},
+    };
+    GSimpleActionGroup *simple;
+    GMenu *menu;
+    GMenu *submenu;
+    GMenu *section;
     LibBalsaMailbox *mailbox;
     gboolean special;
+    GtkWidget *context_menu;
+
+    simple = g_simple_action_group_new();
+    g_action_map_add_action_entries(G_ACTION_MAP(simple),
+                                    entries,
+                                    G_N_ELEMENTS(entries),
+                                    mbnode);
+    gtk_widget_insert_action_group(GTK_WIDGET(relative_to),
+                                   "mbnode",
+                                   G_ACTION_GROUP(simple));
+    g_object_unref(simple);
+
+    menu = g_menu_new();
+
+    /* "New" submenu */
+    submenu = g_menu_new();
+    g_menu_append(submenu, _("Local _mbox mailbox…"), "mbnode.add-mbox");
+    g_menu_append(submenu, _("Local Mail_dir mailbox…"), "mbnode.add-maildir");
+    g_menu_append(submenu, _("Local M_H mailbox…"), "mbnode.add-mh");
+
+    section = g_menu_new();
+    g_menu_append(section, _("Remote IMAP _folder…"), "mbnode.add-imap-folder");
+
+    if (balsa_mailbox_node_is_imap(mbnode))
+        g_menu_append(section, _("Remote IMAP _subfolder…"), "mbnode.add-imap-subfolder");
+
+    g_menu_append_section(submenu, NULL, G_MENU_MODEL(section));
+    g_object_unref(section);
 
-    /*  g_return_val_if_fail(mailbox != NULL, NULL); */
-
-    menu = gtk_menu_new();
-    /* it's a single-use menu, so we must destroy it when we're done */
-    g_signal_connect(menu, "selection-done",
-                     G_CALLBACK(gtk_widget_destroy), NULL);
-
-    submenu = gtk_menu_new();
-    add_menu_entry(submenu, _("Local _mbox mailbox…"),  
-                  G_CALLBACK(mailbox_conf_add_mbox_cb), NULL);
-    add_menu_entry(submenu, _("Local Mail_dir mailbox…"), 
-                  G_CALLBACK(mailbox_conf_add_maildir_cb), NULL);
-    add_menu_entry(submenu, _("Local M_H mailbox…"),
-                  G_CALLBACK(mailbox_conf_add_mh_cb), NULL);
-    add_menu_entry(submenu, NULL, NULL, mbnode);
-    add_menu_entry(submenu, _("Remote IMAP _folder…"), 
-                  G_CALLBACK(folder_conf_add_imap_cb), NULL);
-    if (balsa_mailbox_node_is_imap(mbnode)) {
-       add_menu_entry(submenu, _("Remote IMAP _subfolder…"),
-                  G_CALLBACK(folder_conf_add_imap_sub_cb), mbnode);
-    }
-    gtk_widget_show(submenu);
-    
     /* Translators: popup menu item "New" mailbox or folder */
-    menuitem = gtk_menu_item_new_with_mnemonic(C_("mailbox", "_New"));
-    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
-    gtk_widget_show(menuitem);
-    
-    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-    
-    if(mbnode == NULL) {/* clicked on the empty space */
-        add_menu_entry(menu, _("_Rescan"), G_CALLBACK(mb_rescan_cb), 
-                       NULL);
-       return menu;
+    g_menu_append_submenu(menu, C_("mailbox", "_New"), G_MENU_MODEL(submenu));
+    g_object_unref(submenu);
+
+    section = g_menu_new();
+    if (mbnode == NULL) {/* clicked on the empty space */
+        g_menu_append(section, _("_Rescan"), "mbnode.rescan");
+    } else {
+        mbnode->relative_to = relative_to;
+
+        /* If we didn't click on a mailbox node then there is only one option. */
+        if (g_signal_has_handler_pending(mbnode,
+                                         balsa_mailbox_node_signals
+                                         [SHOW_PROP_DIALOG], 0, FALSE))
+            g_menu_append(section, _("_Properties…"), "mbnode.show-properties");
+
+        if (g_signal_has_handler_pending(mbnode,
+                                         balsa_mailbox_node_signals[APPEND_SUBTREE],
+                                         0, FALSE))
+            g_menu_append(section, _("_Rescan"), "mbnode.rescan");
+
+        if (mbnode->config_prefix != NULL)
+            g_menu_append(section, _("_Delete"), "mbnode.delete");
+
+        if ((mailbox = mbnode->mailbox) != NULL) {
+            g_menu_append(section, _("_Open"), "mbnode.open");
+            g_menu_append(section, _("_Close"), "mbnode.close");
+            context_menu_set_enabled(mbnode);
+
+            special = (   mailbox == balsa_app.inbox
+                       || mailbox == balsa_app.sentbox
+                       || mailbox == balsa_app.draftbox
+                       || mailbox == balsa_app.outbox
+                       || mailbox == balsa_app.trash);
+            if (!special && !mbnode->config_prefix)
+                g_menu_append(section, _("_Delete"), "mbnode.delete");
+
+            if (!special) {
+                g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
+                g_object_unref(section);
+                section = g_menu_new();
+
+                g_menu_append(section, _("Mark as _Inbox"), "mbnode.mark-as-inbox");
+                g_menu_append(section, _("_Mark as Sentbox"), "mbnode.mark-as-sentbox");
+                g_menu_append(section, _("Mark as _Trash"), "mbnode.mark-as-trash");
+                g_menu_append(section, _("Mark as D_raftbox"), "mbnode.mark-as-draftbox");
+            } else if (mailbox == balsa_app.trash) {
+                g_menu_append(section, _("_Empty trash"), "mbnode.empty-trash");
+            }
+
+            /* FIXME : No test on mailbox type is made yet, should we ? */
+            g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
+            g_object_unref(section);
+            section = g_menu_new();
+
+            g_menu_append(section, _("_Edit/Apply filters"), "mbnode.filters");
+                           // G_CALLBACK(mb_filter_cb), mbnode);
+        }
     }
-    /* If we didn't click on a mailbox node then there is only one option. */
-    add_menu_entry(menu, NULL, NULL, NULL);
 
-    if (g_signal_has_handler_pending(mbnode,
-                                     balsa_mailbox_node_signals
-                                     [SHOW_PROP_DIALOG], 0, FALSE))
-        add_menu_entry(menu, _("_Properties…"),
-                       G_CALLBACK(mb_conf_cb), mbnode);
+    g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
+    g_object_unref(section);
 
-    if (g_signal_has_handler_pending(mbnode,
-                                    balsa_mailbox_node_signals
-                                    [APPEND_SUBTREE], 0, FALSE))
-       add_menu_entry(menu, _("_Rescan"),
-                      G_CALLBACK(mb_rescan_cb), mbnode);
+    context_menu = gtk_popover_new_from_model(relative_to, G_MENU_MODEL(menu));
+    g_object_unref(menu);
 
-    if (mbnode->config_prefix)
-       add_menu_entry(menu, _("_Delete"), G_CALLBACK(mb_del_cb),  mbnode);
+    return context_menu;
+}
 
-    if (!(mailbox = mbnode->mailbox))
-        return menu;
+GtkWidget *
+balsa_mailbox_node_get_context_menu(BalsaMailboxNode *mbnode,
+                                    GtkWidget        *relative_to)
+{
+    GtkWidget *context_menu;
 
-    if (!MAILBOX_OPEN(mailbox))
-        add_menu_entry(menu, _("_Open"),  G_CALLBACK(mb_open_cb),  mbnode);
-    else
-        add_menu_entry(menu, _("_Close"), G_CALLBACK(mb_close_cb), mbnode);
-
-    special = (   mailbox == balsa_app.inbox
-               || mailbox == balsa_app.sentbox
-               || mailbox == balsa_app.draftbox
-               || mailbox == balsa_app.outbox
-               || mailbox == balsa_app.trash);
-    if (!special && !mbnode->config_prefix)
-       add_menu_entry(menu, _("_Delete"), G_CALLBACK(mb_del_cb),  mbnode);
-
-    if (!special) {
-        add_menu_entry(menu, NULL, NULL, NULL);
-        add_menu_entry(menu, _("Mark as _Inbox"),    
-                       G_CALLBACK(mb_inbox_cb),    mbnode);
-        add_menu_entry(menu, _("_Mark as Sentbox"), 
-                       G_CALLBACK(mb_sentbox_cb),  mbnode);
-        add_menu_entry(menu, _("Mark as _Trash"),    
-                       G_CALLBACK(mb_trash_cb),    mbnode);
-        add_menu_entry(menu, _("Mark as D_raftbox"),
-                       G_CALLBACK(mb_draftbox_cb), mbnode);
-    } else if (mailbox == balsa_app.trash)
-        add_menu_entry(menu, _("_Empty trash"),    
-                       G_CALLBACK(mb_empty_trash_cb), mbnode);
-
-    /* FIXME : No test on mailbox type is made yet, should we ? */
-    add_menu_entry(menu, NULL, NULL, NULL);
-    add_menu_entry(menu, _("_Edit/Apply filters"), 
-                   G_CALLBACK(mb_filter_cb), mbnode);
-
-    return menu;
+    if (mbnode == NULL) {
+        static GtkWidget *null_context_menu;
+
+        if (null_context_menu == NULL) {
+            null_context_menu =
+                create_context_menu(NULL, relative_to);
+        }
+        context_menu = null_context_menu;
+    } else {
+        if (mbnode->context_menu == NULL) {
+            mbnode->context_menu =
+                create_context_menu(mbnode, relative_to);
+        }
+        context_menu = mbnode->context_menu;
+    }
+
+    return context_menu;
 }
 
 /* ---------------------------------------------------------------------
diff --git a/src/mailbox-node.h b/src/mailbox-node.h
index ef68b8c66..6683af0a3 100644
--- a/src/mailbox-node.h
+++ b/src/mailbox-node.h
@@ -58,7 +58,8 @@ BalsaMailboxNode *balsa_mailbox_node_new_imap_folder(LibBalsaServer* s,
                                                     const char*p);
 BalsaMailboxNode *balsa_mailbox_node_new_from_config(const gchar* prefix);
 
-GtkWidget *balsa_mailbox_node_get_context_menu(BalsaMailboxNode * mbnode);
+GtkWidget *balsa_mailbox_node_get_context_menu(BalsaMailboxNode *mbnode,
+                                               GtkWidget        *relative_to);
 void balsa_mailbox_node_show_prop_dialog(BalsaMailboxNode * mbnode);
 void balsa_mailbox_node_append_subtree(BalsaMailboxNode * mbnode);
 void balsa_mailbox_node_load_config(BalsaMailboxNode* mn, const gchar* prefix);
diff --git a/src/sendmsg-window.c b/src/sendmsg-window.c
index d99c21999..dc5c9fb19 100644
--- a/src/sendmsg-window.c
+++ b/src/sendmsg-window.c
@@ -1790,22 +1790,12 @@ add_attachment(BalsaSendmsg * bsmsg, const gchar *filename,
         g_object_unref(menu_item);
     }
 
-    if (can_inline || !is_a_temp_file) {
-        /* Need a separator */
-        menu_item = gtk_separator_menu_item_new();
-        gtk_menu_shell_append(GTK_MENU_SHELL(attach_data->popup_menu), menu_item);
-    }
-
     /* an attachment can be removed */
     section = g_menu_new();
     g_menu_append(section, _("Remove"), "attachment.remove");
     g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
     g_object_unref(section);
 
-    /* Insert another separator */
-    menu_item = gtk_separator_menu_item_new();
-    gtk_menu_shell_append(GTK_MENU_SHELL(attach_data->popup_menu), menu_item);
-
     /* add the usual vfs menu so the user can inspect what (s)he actually
        attached... (only for non-message attachments) */
     if (!is_fwd_message) {


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