[evolution] Show a menu button in the header bar when the menu bar is hidden



commit 7cb572cf7a9663377c8dd785271c68f43ba74223
Author: Milan Crha <mcrha redhat com>
Date:   Fri Aug 5 09:04:54 2022 +0200

    Show a menu button in the header bar when the menu bar is hidden
    
    Since there is a header bar now, there can be shown a menu button
    when the menu bar is hidden to make it easier to access the menu.

 src/calendar/gui/e-comp-editor.c     |  25 +++---
 src/composer/e-composer-private.c    |  28 ++++---
 src/composer/e-composer-private.h    |   4 +-
 src/e-util/e-mail-signature-editor.c |  16 ++--
 src/e-util/e-menu-bar.c              | 146 ++++++++++++++++++++++++++++-------
 src/e-util/e-menu-bar.h              |   5 +-
 src/mail/e-mail-browser.c            |  46 ++++++-----
 src/mail/e-mail-notes.c              |  17 ++--
 src/shell/e-shell-headerbar.c        | 106 +++++++++++++++++++------
 src/shell/e-shell-headerbar.h        |   3 +-
 src/shell/e-shell-window-private.c   |  15 ++--
 src/shell/e-shell-window-private.h   |   4 +-
 12 files changed, 302 insertions(+), 113 deletions(-)
---
diff --git a/src/calendar/gui/e-comp-editor.c b/src/calendar/gui/e-comp-editor.c
index b4ed425059..49883a0b24 100644
--- a/src/calendar/gui/e-comp-editor.c
+++ b/src/calendar/gui/e-comp-editor.c
@@ -51,7 +51,7 @@ struct _ECompEditorPrivate {
        ICalComponent *component;
        guint32 flags;
 
-       GtkWidget *menu_bar;
+       EMenuBar *menu_bar;
 
        EFocusTracker *focus_tracker;
        GtkUIManager *ui_manager;
@@ -1925,28 +1925,34 @@ e_comp_editor_set_shell (ECompEditor *comp_editor,
 }
 
 static GtkWidget *
-comp_editor_construct_header_bar (ECompEditor *comp_editor)
+comp_editor_construct_header_bar (ECompEditor *comp_editor,
+                                 GtkWidget *menu_button)
 {
        GtkWidget *widget;
        GtkWidget *button;
        GtkAction *action;
+       GtkHeaderBar *header_bar;
 
        widget = gtk_header_bar_new ();
        gtk_widget_show (widget);
-       gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (widget), TRUE);
+       header_bar = GTK_HEADER_BAR (widget);
+       gtk_header_bar_set_show_close_button (header_bar, TRUE);
+
+       if (menu_button)
+               gtk_header_bar_pack_end (header_bar, menu_button);
 
        action = e_comp_editor_get_action (comp_editor, "save-and-close");
 
        button = e_header_bar_button_new (_("Save and Close"), action);
        e_header_bar_button_css_add_class (E_HEADER_BAR_BUTTON (button), "suggested-action");
        gtk_widget_show (button);
-       gtk_header_bar_pack_start (GTK_HEADER_BAR (widget), button);
+       gtk_header_bar_pack_start (header_bar, button);
 
        action = e_comp_editor_get_action (comp_editor, "save");
 
        button = e_header_bar_button_new (NULL, action);
        gtk_widget_show (button);
-       gtk_header_bar_pack_start (GTK_HEADER_BAR (widget), button);
+       gtk_header_bar_pack_start (header_bar, button);
 
        return widget;
 }
@@ -2316,6 +2322,7 @@ e_comp_editor_constructed (GObject *object)
 
        ECompEditor *comp_editor = E_COMP_EDITOR (object);
        GtkWidget *widget;
+       GtkWidget *menu_button = NULL;
        GtkBox *vbox;
        GtkAction *action;
        GtkActionGroup *action_group;
@@ -2426,13 +2433,13 @@ e_comp_editor_constructed (GObject *object)
        gtk_container_add (GTK_CONTAINER (comp_editor), widget);
 
        /* Construct the main menu and headerbar. */
-       widget = comp_editor_construct_header_bar (comp_editor);
-       gtk_window_set_titlebar (GTK_WINDOW (comp_editor), widget);
-
        widget = e_comp_editor_get_managed_widget (comp_editor, "/main-menu");
-       comp_editor->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (comp_editor));
+       comp_editor->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (comp_editor), 
&menu_button);
        gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
 
+       widget = comp_editor_construct_header_bar (comp_editor, menu_button);
+       gtk_window_set_titlebar (GTK_WINDOW (comp_editor), widget);
+
        widget = e_comp_editor_get_managed_widget (comp_editor, "/main-toolbar");
        gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
        gtk_widget_show (widget);
diff --git a/src/composer/e-composer-private.c b/src/composer/e-composer-private.c
index 224d218e40..563547448f 100644
--- a/src/composer/e-composer-private.c
+++ b/src/composer/e-composer-private.c
@@ -82,34 +82,40 @@ composer_update_gallery_visibility (EMsgComposer *composer)
 }
 
 static GtkWidget *
-composer_construct_header_bar (EMsgComposer *composer)
+composer_construct_header_bar (EMsgComposer *composer,
+                              GtkWidget *menu_button)
 {
        GtkWidget *widget;
        GtkWidget *button;
+       GtkHeaderBar *header_bar;
 
        widget = gtk_header_bar_new ();
        gtk_widget_show (widget);
-       gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (widget), TRUE);
+       header_bar = GTK_HEADER_BAR (widget);
+       gtk_header_bar_set_show_close_button (header_bar, TRUE);
+
+       if (menu_button)
+               gtk_header_bar_pack_end (header_bar, menu_button);
 
        button = e_header_bar_button_new (_("Send"), ACTION (SEND));
        e_header_bar_button_css_add_class (E_HEADER_BAR_BUTTON (button), "suggested-action");
        gtk_widget_show (button);
-       gtk_header_bar_pack_start (GTK_HEADER_BAR (widget), button);
+       gtk_header_bar_pack_start (header_bar, button);
 
        button = e_header_bar_button_new (NULL, ACTION (SAVE_DRAFT));
        e_header_bar_button_css_add_class (E_HEADER_BAR_BUTTON (button), "flat");
        gtk_widget_show (button);
-       gtk_header_bar_pack_start (GTK_HEADER_BAR (widget), button);
+       gtk_header_bar_pack_start (header_bar, button);
 
        button = e_header_bar_button_new (NULL, ACTION (PRIORITIZE_MESSAGE));
        e_header_bar_button_css_add_class (E_HEADER_BAR_BUTTON (button), "flat");
        gtk_widget_show (button);
-       gtk_header_bar_pack_end (GTK_HEADER_BAR (widget), button);
+       gtk_header_bar_pack_end (header_bar, button);
 
        button = e_header_bar_button_new (NULL, ACTION (REQUEST_READ_RECEIPT));
        e_header_bar_button_css_add_class (E_HEADER_BAR_BUTTON (button), "flat");
        gtk_widget_show (button);
-       gtk_header_bar_pack_end (GTK_HEADER_BAR (widget), button);
+       gtk_header_bar_pack_end (header_bar, button);
 
        return widget;
 }
@@ -227,6 +233,7 @@ e_composer_private_constructed (EMsgComposer *composer)
        GtkAction *action;
        GtkWidget *container;
        GtkWidget *widget;
+       GtkWidget *menu_button = NULL;
        GtkWindow *window;
        GSettings *settings;
        gchar *filename, *gallery_path;
@@ -297,14 +304,13 @@ e_composer_private_constructed (EMsgComposer *composer)
 
        /* Construct the main menu and headerbar. */
 
-       widget = composer_construct_header_bar (composer);
-       gtk_window_set_titlebar (window, widget);
-
        widget = e_html_editor_get_managed_widget (editor, "/main-menu");
-
-       priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), window);
+       priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), window, &menu_button);
        gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 
+       widget = composer_construct_header_bar (composer, menu_button);
+       gtk_window_set_titlebar (window, widget);
+
        widget = e_html_editor_get_managed_widget (editor, "/main-toolbar");
        gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
        gtk_widget_show (widget);
diff --git a/src/composer/e-composer-private.h b/src/composer/e-composer-private.h
index 677411cb02..366b89afc5 100644
--- a/src/composer/e-composer-private.h
+++ b/src/composer/e-composer-private.h
@@ -31,6 +31,8 @@
 
 #include <libebackend/libebackend.h>
 
+#include "e-util/e-util.h"
+
 #include "e-composer-actions.h"
 #include "e-composer-header-table.h"
 
@@ -81,7 +83,7 @@ struct _EMsgComposerPrivate {
 
        GtkWidget *address_dialog;
 
-       GtkWidget *menu_bar;
+       EMenuBar *menu_bar;
 
        gchar *mime_type;
        gchar *mime_body;
diff --git a/src/e-util/e-mail-signature-editor.c b/src/e-util/e-mail-signature-editor.c
index 4227dce950..deeea264dc 100644
--- a/src/e-util/e-mail-signature-editor.c
+++ b/src/e-util/e-mail-signature-editor.c
@@ -46,7 +46,7 @@ struct _EMailSignatureEditorPrivate {
 
        GtkWidget *entry;               /* not referenced */
 
-       GtkWidget *menu_bar;
+       EMenuBar *menu_bar;
 };
 
 struct _AsyncContext {
@@ -520,6 +520,8 @@ mail_signature_editor_constructed (GObject *object)
        GtkWidget *widget;
        GtkWidget *button;
        GtkWidget *hbox;
+       GtkWidget *menu_button = NULL;
+       GtkHeaderBar *header_bar;
        const gchar *display_name;
        GError *error = NULL;
 
@@ -569,20 +571,24 @@ mail_signature_editor_constructed (GObject *object)
 
        widget = gtk_header_bar_new ();
        gtk_widget_show (widget);
-       gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (widget), TRUE);
-       gtk_header_bar_set_title (GTK_HEADER_BAR (widget), _("Edit Signature"));
+       header_bar = GTK_HEADER_BAR (widget);
+       gtk_header_bar_set_show_close_button (header_bar, TRUE);
+       gtk_header_bar_set_title (header_bar, _("Edit Signature"));
        gtk_window_set_titlebar (GTK_WINDOW (window), widget);
 
        action = gtk_action_group_get_action (window->priv->action_group, "save-and-close");
        button = e_header_bar_button_new (_("Save"), action);
        e_header_bar_button_css_add_class (E_HEADER_BAR_BUTTON (button), "suggested-action");
        gtk_widget_show (button);
-       gtk_header_bar_pack_start (GTK_HEADER_BAR (widget), button);
+       gtk_header_bar_pack_start (header_bar, button);
 
        widget = e_html_editor_get_managed_widget (editor, "/main-menu");
-       window->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (window));
+       window->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (window), &menu_button);
        gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 
+       if (menu_button)
+               gtk_header_bar_pack_end (header_bar, menu_button);
+
        /* Construct the signature name entry. */
 
        widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
diff --git a/src/e-util/e-menu-bar.c b/src/e-util/e-menu-bar.c
index 700142bb94..8cb919a0c8 100644
--- a/src/e-util/e-menu-bar.c
+++ b/src/e-util/e-menu-bar.c
@@ -11,6 +11,7 @@
 
 struct _EMenuBarPrivate {
        GtkWidget *inner_menu_bar;
+       GtkWidget *menu_button;
 
        guint visible : 1;
        gulong delayed_show_id;
@@ -20,7 +21,6 @@ struct _EMenuBarPrivate {
 G_DEFINE_TYPE_WITH_CODE (EMenuBar, e_menu_bar, G_TYPE_OBJECT,
        G_ADD_PRIVATE (EMenuBar))
 
-
 enum {
        PROP_0,
        PROP_VISIBLE
@@ -39,22 +39,66 @@ menu_bar_visible_settings_changed_cb (GSettings *settings,
 }
 
 static void
-menu_bar_dispose (GObject *menu_bar)
+menu_bar_move_items_to (GtkMenuShell *des,
+                       GtkMenuShell *src)
 {
-       EMenuBar *self = E_MENU_BAR (menu_bar);
+       GList *children, *link;
+       GtkContainer *des_container;
+       GtkContainer *src_container;
 
-       if (self->priv->delayed_show_id) {
-               g_source_remove (self->priv->delayed_show_id);
-               self->priv->delayed_show_id = 0;
-       }
+       des_container = GTK_CONTAINER (des);
+       src_container = GTK_CONTAINER (src);
 
-       if (self->priv->delayed_hide_id) {
-               g_source_remove (self->priv->delayed_hide_id);
-               self->priv->delayed_hide_id = 0;
+       children = gtk_container_get_children (src_container);
+
+       for (link = children; link; link = g_list_next (link)) {
+               GtkWidget *widget = link->data;
+
+               g_object_ref (widget);
+               gtk_container_remove (src_container, widget);
+               gtk_container_add (des_container, widget);
+               g_object_unref (widget);
        }
 
-       /* Chain up to parent's method. */
-       G_OBJECT_CLASS (e_menu_bar_parent_class)->dispose (menu_bar);
+       g_list_free (children);
+}
+
+static void
+menu_bar_menu_deactivate_cb (GtkMenuShell *menu,
+                            gpointer user_data)
+{
+       EMenuBar *menu_bar = user_data;
+
+       menu_bar_move_items_to (GTK_MENU_SHELL (menu_bar->priv->inner_menu_bar), menu);
+
+       gtk_menu_detach (GTK_MENU (menu));
+}
+
+static void
+e_menu_bar_popup_menu (EMenuBar *self)
+{
+       GtkMenu *menu;
+
+       g_return_if_fail (E_IS_MENU_BAR (self));
+
+       if (!self->priv->menu_button)
+               return;
+
+       menu = GTK_MENU (gtk_menu_new ());
+
+       menu_bar_move_items_to (GTK_MENU_SHELL (menu), GTK_MENU_SHELL (self->priv->inner_menu_bar));
+
+       g_signal_connect_object (menu, "deactivate", G_CALLBACK (menu_bar_menu_deactivate_cb), self, 0);
+
+       gtk_menu_attach_to_widget (menu, self->priv->menu_button, NULL);
+
+       g_object_set (menu,
+                     "anchor-hints", (GDK_ANCHOR_FLIP_Y |
+                                      GDK_ANCHOR_SLIDE |
+                                      GDK_ANCHOR_RESIZE),
+                     NULL);
+
+       gtk_menu_popup_at_widget (menu, self->priv->menu_button, GDK_GRAVITY_SOUTH_WEST, 
GDK_GRAVITY_NORTH_WEST, NULL);
 }
 
 static void
@@ -94,15 +138,36 @@ menu_bar_get_property (GObject *object,
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
+static void
+menu_bar_dispose (GObject *menu_bar)
+{
+       EMenuBar *self = E_MENU_BAR (menu_bar);
+
+       if (self->priv->delayed_show_id) {
+               g_source_remove (self->priv->delayed_show_id);
+               self->priv->delayed_show_id = 0;
+       }
+
+       if (self->priv->delayed_hide_id) {
+               g_source_remove (self->priv->delayed_hide_id);
+               self->priv->delayed_hide_id = 0;
+       }
+
+       g_clear_object (&self->priv->menu_button);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_menu_bar_parent_class)->dispose (menu_bar);
+}
+
 static void
 e_menu_bar_class_init (EMenuBarClass *klass)
 {
        GObjectClass *object_class;
 
        object_class = G_OBJECT_CLASS (klass);
-       object_class->dispose = menu_bar_dispose;
        object_class->set_property = menu_bar_set_property;
        object_class->get_property = menu_bar_get_property;
+       object_class->dispose = menu_bar_dispose;
 
        g_object_class_install_property (
                object_class,
@@ -168,13 +233,15 @@ e_menu_bar_window_event_after_cb (GtkWindow *window,
 
        if (event->type == GDK_KEY_PRESS) {
                GdkEventKey *key_event;
+               gboolean has_modifier_pressed;
 
                key_event = (GdkEventKey *) event;
+               has_modifier_pressed = (key_event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK |
+                                       GDK_SUPER_MASK | GDK_HYPER_MASK |
+                                       GDK_META_MASK)) != 0;
 
                if ((key_event->keyval == GDK_KEY_Alt_L || key_event->keyval == GDK_KEY_Alt_R) &&
-                   !(key_event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK |
-                                         GDK_SUPER_MASK | GDK_HYPER_MASK |
-                                         GDK_META_MASK))) {
+                   !has_modifier_pressed) {
                        if (self->priv->delayed_hide_id) {
                                g_source_remove (self->priv->delayed_hide_id);
                                self->priv->delayed_hide_id = 0;
@@ -191,6 +258,9 @@ e_menu_bar_window_event_after_cb (GtkWindow *window,
                                self->priv->delayed_show_id =
                                        g_timeout_add (250, delayed_show_cb, self);
                        }
+               } else if (key_event->keyval == GDK_KEY_F10 && !has_modifier_pressed && 
self->priv->menu_button &&
+                          gtk_widget_get_visible (self->priv->menu_button)) {
+                       e_menu_bar_popup_menu (self);
                }
        } else if (event->type != GDK_BUTTON_RELEASE || !(event->button.state & GDK_MOD1_MASK)) {
                if (self->priv->delayed_show_id) {
@@ -210,40 +280,64 @@ e_menu_bar_window_event_after_cb (GtkWindow *window,
  * e_menu_bar_new:
  * @inner_menu_bar: #GtkMenuBar to handle
  * @window: monitor #GtkWindow for &lt;Alt&gt; key event
+ * @out_menu_button: (out) (optional) (transfer full): an output argument to set the menu button instance 
to, or %NULL
  *
- * Creates a new #EMenuBar showing @inner_menu_bar on demand
+ * Creates a new #EMenuBar showing @inner_menu_bar on demand. The @out_menu_button
+ * is set to a menu button, which should be placed into the window's header bar.
+ * The menu button is shown when the menu bar is hidden.
  *
  * Returns: (transfer full): a new #EMenuBar
  *
  * Since: 3.46
  **/
-GtkWidget *
+EMenuBar *
 e_menu_bar_new (GtkMenuBar *inner_menu_bar,
-               GtkWindow *window)
+               GtkWindow *window,
+               GtkWidget **out_menu_button)
 {
-       GtkWidget *menu_bar;
+       EMenuBar *self;
        GSettings *settings;
 
        g_return_val_if_fail (GTK_IS_MENU_BAR (inner_menu_bar), NULL);
        g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
 
-       menu_bar = g_object_new (E_TYPE_MENU_BAR, NULL);
-       E_MENU_BAR (menu_bar)->priv->inner_menu_bar = GTK_WIDGET (inner_menu_bar);
+       self = g_object_new (E_TYPE_MENU_BAR, NULL);
+       self->priv->inner_menu_bar = GTK_WIDGET (inner_menu_bar);
 
        settings = e_util_ref_settings ("org.gnome.evolution.shell");
        g_signal_connect_object (
                settings, "changed::menubar-visible",
                G_CALLBACK (menu_bar_visible_settings_changed_cb),
-               menu_bar, 0);
+               self, 0);
        e_menu_bar_set_visible (
-               E_MENU_BAR (menu_bar),
+               self,
                g_settings_get_boolean (settings, "menubar-visible"));
+
+       if (out_menu_button) {
+               GtkWidget *button;
+
+               button = gtk_button_new_from_icon_name ("open-menu", GTK_ICON_SIZE_MENU);
+               gtk_button_set_always_show_image (GTK_BUTTON (button), TRUE);
+
+               g_settings_bind (
+                       settings, "menubar-visible",
+                       button, "visible",
+                       G_SETTINGS_BIND_GET | G_SETTINGS_BIND_INVERT_BOOLEAN | 
G_SETTINGS_BIND_NO_SENSITIVITY);
+
+               g_signal_connect_object (button, "clicked",
+                       G_CALLBACK (e_menu_bar_popup_menu), self, G_CONNECT_SWAPPED);
+
+               self->priv->menu_button = g_object_ref_sink (button);
+
+               *out_menu_button = button;
+       }
+
        g_object_unref (settings);
 
        g_signal_connect_object (window, "event-after",
-               G_CALLBACK (e_menu_bar_window_event_after_cb), menu_bar, G_CONNECT_AFTER);
+               G_CALLBACK (e_menu_bar_window_event_after_cb), self, G_CONNECT_AFTER);
 
-       return menu_bar;
+       return self;
 }
 
 /**
diff --git a/src/e-util/e-menu-bar.h b/src/e-util/e-menu-bar.h
index c293f876f5..2173f9f5c2 100644
--- a/src/e-util/e-menu-bar.h
+++ b/src/e-util/e-menu-bar.h
@@ -49,8 +49,9 @@ struct _EMenuBarClass {
 };
 
 GType          e_menu_bar_get_type     (void);
-GtkWidget *    e_menu_bar_new          (GtkMenuBar *widget,
-                                        GtkWindow *window);
+EMenuBar *     e_menu_bar_new          (GtkMenuBar *widget,
+                                        GtkWindow *window,
+                                        GtkWidget **out_menu_button);
 gboolean       e_menu_bar_get_visible  (EMenuBar *menu_bar);
 void           e_menu_bar_set_visible  (EMenuBar *menu_bar,
                                         gboolean visible);
diff --git a/src/mail/e-mail-browser.c b/src/mail/e-mail-browser.c
index e4a5c0f196..a6a078dcc7 100644
--- a/src/mail/e-mail-browser.c
+++ b/src/mail/e-mail-browser.c
@@ -51,7 +51,7 @@ struct _EMailBrowserPrivate {
        EMailFormatterMode display_mode;
        EAutomaticActionPolicy close_on_reply_policy;
 
-       GtkWidget *menu_bar;
+       EMenuBar *menu_bar;
        GtkWidget *main_toolbar;
        GtkWidget *message_list;
        GtkWidget *preview_pane;
@@ -516,49 +516,54 @@ mail_browser_set_display_mode (EMailBrowser *browser,
 }
 
 static GtkWidget *
-mail_browser_construct_header_bar (EMailReader *reader)
+mail_browser_construct_header_bar (EMailReader *reader,
+                                  GtkWidget *menu_button)
 {
        GtkWidget *widget;
-       GtkWidget *button;
        GtkAction *action;
+       GtkHeaderBar *header_bar;
        const gchar *action_name;
 
        widget = gtk_header_bar_new ();
        gtk_widget_show (widget);
-       gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (widget), TRUE);
+       header_bar = GTK_HEADER_BAR (widget);
+       gtk_header_bar_set_show_close_button (header_bar, TRUE);
+
+       if (menu_button)
+               gtk_header_bar_pack_end (header_bar, menu_button);
 
        action_name = "mail-forward";
        action = e_mail_reader_get_action (reader, action_name);
-       button = e_header_bar_button_new (_("Forward"), action);
+       widget = e_header_bar_button_new (_("Forward"), action);
        gtk_widget_set_name (widget, "e-mail-shell-view-forward");
        e_header_bar_button_take_menu (
-               E_HEADER_BAR_BUTTON (button),
+               E_HEADER_BAR_BUTTON (widget),
                e_mail_reader_create_forward_menu (reader));
-       gtk_widget_show (button);
+       gtk_widget_show (widget);
 
-       gtk_header_bar_pack_end (GTK_HEADER_BAR (widget), button);
+       gtk_header_bar_pack_end (header_bar, widget);
 
        action_name = "mail-reply-group";
        action = e_mail_reader_get_action (reader, action_name);
-       button = e_header_bar_button_new (_("Group Reply"), action);
+       widget = e_header_bar_button_new (_("Group Reply"), action);
        gtk_widget_set_name (widget, "e-mail-shell-view-reply-group");
-       gtk_widget_show (button);
+       gtk_widget_show (widget);
 
        e_header_bar_button_take_menu (
-               E_HEADER_BAR_BUTTON (button),
+               E_HEADER_BAR_BUTTON (widget),
                e_mail_reader_create_reply_menu (reader));
 
-       gtk_header_bar_pack_end (GTK_HEADER_BAR (widget), button);
+       gtk_header_bar_pack_end (header_bar, widget);
 
        action_name = "mail-reply-sender";
        action = e_mail_reader_get_action (reader, action_name);
-       button = e_header_bar_button_new (_("Reply"), action);
+       widget = e_header_bar_button_new (_("Reply"), action);
        gtk_widget_set_name (widget, "e-mail-shell-view-reply-sender");
-       gtk_widget_show (button);
+       gtk_widget_show (widget);
 
-       gtk_header_bar_pack_end (GTK_HEADER_BAR (widget), button);
+       gtk_header_bar_pack_end (header_bar, widget);
 
-       return widget;
+       return GTK_WIDGET (header_bar);
 }
 
 static void
@@ -793,6 +798,7 @@ mail_browser_constructed (GObject *object)
        GtkWidget *container;
        GtkWidget *display;
        GtkWidget *widget;
+       GtkWidget *menu_button = NULL;
        const gchar *domain;
        const gchar *id;
        guint merge_id;
@@ -944,7 +950,10 @@ mail_browser_constructed (GObject *object)
 
        widget = gtk_ui_manager_get_widget (ui_manager, "/main-menu");
        gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
-       browser->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (browser));
+       browser->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (browser), &menu_button);
+
+       widget = mail_browser_construct_header_bar (reader, menu_button);
+       gtk_window_set_titlebar (GTK_WINDOW (object), widget);
 
        widget = gtk_ui_manager_get_widget (ui_manager, "/main-toolbar");
        gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
@@ -962,9 +971,6 @@ mail_browser_constructed (GObject *object)
                browser->priv->preview_pane,
                TRUE, TRUE, 0);
 
-       widget = mail_browser_construct_header_bar (reader);
-       gtk_window_set_titlebar (GTK_WINDOW (object), widget);
-
        attachment_store = e_mail_display_get_attachment_store (E_MAIL_DISPLAY (display));
        widget = GTK_WIDGET (e_mail_display_get_attachment_view (E_MAIL_DISPLAY (display)));
        gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
diff --git a/src/mail/e-mail-notes.c b/src/mail/e-mail-notes.c
index 2f6e580c42..b30274dbef 100644
--- a/src/mail/e-mail-notes.c
+++ b/src/mail/e-mail-notes.c
@@ -52,7 +52,7 @@ struct _EMailNotesEditor {
        EFocusTracker *focus_tracker;
        GtkActionGroup *action_group;
        GBinding *attachment_paned_binding;
-       GtkWidget *menu_bar;
+       EMenuBar *menu_bar;
 
        gboolean had_message;
        CamelMimeMessage *message;
@@ -1126,9 +1126,10 @@ e_mail_notes_editor_new_with_editor (EHTMLEditor *html_editor,
        EFocusTracker *focus_tracker;
        EActivityBar *activity_bar;
        GtkUIManager *ui_manager;
-       GtkWidget *widget, *content, *button;
+       GtkWidget *widget, *content, *button, *menu_button = NULL;
        GtkActionGroup *action_group;
        GtkAction *action;
+       GtkHeaderBar *header_bar;
        GSettings *settings;
        GError *local_error = NULL;
 
@@ -1178,20 +1179,24 @@ e_mail_notes_editor_new_with_editor (EHTMLEditor *html_editor,
 
        widget = gtk_header_bar_new ();
        gtk_widget_show (widget);
-       gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (widget), TRUE);
-       gtk_header_bar_set_title (GTK_HEADER_BAR (widget), _("Edit Message Note"));
+       header_bar = GTK_HEADER_BAR (widget);
+       gtk_header_bar_set_show_close_button (header_bar, TRUE);
+       gtk_header_bar_set_title (header_bar, _("Edit Message Note"));
        gtk_window_set_titlebar (GTK_WINDOW (notes_editor), widget);
 
        action = gtk_action_group_get_action (notes_editor->action_group, "save-and-close");
        button = e_header_bar_button_new (_("Save"), action);
        e_header_bar_button_css_add_class (E_HEADER_BAR_BUTTON (button), "suggested-action");
        gtk_widget_show (button);
-       gtk_header_bar_pack_start (GTK_HEADER_BAR (widget), button);
+       gtk_header_bar_pack_start (header_bar, button);
 
        widget = e_html_editor_get_managed_widget (notes_editor->editor, "/main-menu");
-       notes_editor->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (notes_editor));
+       notes_editor->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (notes_editor), 
&menu_button);
        gtk_box_pack_start (GTK_BOX (content), widget, FALSE, FALSE, 0);
 
+       if (menu_button)
+               gtk_header_bar_pack_end (header_bar, menu_button);
+
        widget = GTK_WIDGET (notes_editor->editor);
        g_object_set (G_OBJECT (widget),
                "halign", GTK_ALIGN_FILL,
diff --git a/src/shell/e-shell-headerbar.c b/src/shell/e-shell-headerbar.c
index feedce68b4..b824bea34d 100644
--- a/src/shell/e-shell-headerbar.c
+++ b/src/shell/e-shell-headerbar.c
@@ -13,6 +13,7 @@
 
 struct _EShellHeaderBarPrivate {
        GWeakRef shell_window;
+       GtkWidget *menu_button;
 
        GtkWidget *new_button;
        GtkWidget *start_buttons;
@@ -23,6 +24,7 @@ struct _EShellHeaderBarPrivate {
 
 enum {
        PROP_0,
+       PROP_MENU_BUTTON,
        PROP_SHELL_WINDOW
 };
 
@@ -55,6 +57,16 @@ shell_header_bar_dup_shell_window (EShellHeaderBar *headerbar)
        return g_weak_ref_get (&headerbar->priv->shell_window);
 }
 
+static void
+shell_header_bar_set_menu_button (EShellHeaderBar *headerbar,
+                                 GtkWidget *menu_button)
+{
+       g_return_if_fail (GTK_IS_WIDGET (menu_button));
+       g_return_if_fail (headerbar->priv->menu_button == NULL);
+
+       headerbar->priv->menu_button = g_object_ref_sink (menu_button);
+}
+
 static void
 shell_header_bar_set_shell_window (EShellHeaderBar *headerbar,
                                   EShellWindow *shell_window)
@@ -96,6 +108,12 @@ shell_header_bar_set_property (GObject *object,
                               GParamSpec *pspec)
 {
        switch (property_id) {
+               case PROP_MENU_BUTTON:
+                       shell_header_bar_set_menu_button (
+                               E_SHELL_HEADER_BAR (object),
+                               g_value_get_object (value));
+                       return;
+
                case PROP_SHELL_WINDOW:
                        shell_header_bar_set_shell_window (
                                E_SHELL_HEADER_BAR (object),
@@ -126,23 +144,44 @@ shell_header_bar_get_property (GObject *object,
 static void
 shell_header_bar_constructed (GObject *object)
 {
-       EShellHeaderBar *headerbar = E_SHELL_HEADER_BAR (object);
-       EShellWindow *shell_window = shell_header_bar_dup_shell_window (headerbar);
-       GtkUIManager *ui_manager = e_shell_window_get_ui_manager (shell_window);
+       EShellHeaderBar *self = E_SHELL_HEADER_BAR (object);
+       EShellWindow *shell_window;
+       GtkUIManager *ui_manager;
+       GtkWidget *new_button;
 
        /* Chain up to parent's method. */
        G_OBJECT_CLASS (e_shell_header_bar_parent_class)->constructed (object);
 
+       shell_window = shell_header_bar_dup_shell_window (self);
+
        g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
 
+       ui_manager = e_shell_window_get_ui_manager (shell_window);
+
+       new_button = e_header_bar_button_new (C_("toolbar-button", "New"), NULL);
+       gtk_header_bar_pack_start (GTK_HEADER_BAR (self), new_button);
+       gtk_widget_show (new_button);
+       self->priv->new_button = g_object_ref (new_button);
+
+       self->priv->start_buttons = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
+       gtk_header_bar_pack_start (GTK_HEADER_BAR (self), self->priv->start_buttons);
+       gtk_widget_show (self->priv->start_buttons);
+
+       if (self->priv->menu_button)
+               gtk_header_bar_pack_end (GTK_HEADER_BAR (self), self->priv->menu_button);
+
+       self->priv->end_buttons = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
+       gtk_header_bar_pack_end (GTK_HEADER_BAR (self), self->priv->end_buttons);
+       gtk_widget_show (self->priv->end_buttons);
+
        e_header_bar_button_add_accelerator (
-               E_HEADER_BAR_BUTTON (headerbar->priv->new_button),
+               E_HEADER_BAR_BUTTON (self->priv->new_button),
                gtk_ui_manager_get_accel_group (ui_manager),
                GDK_KEY_N, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
 
-       headerbar->priv->prefered_item_notify_id = e_signal_connect_notify (
+       self->priv->prefered_item_notify_id = e_signal_connect_notify (
                shell_window, "notify::active-view",
-               G_CALLBACK (shell_header_bar_update_new_menu), headerbar);
+               G_CALLBACK (shell_header_bar_update_new_menu), self);
 
        g_object_unref (shell_window);
 }
@@ -168,10 +207,23 @@ shell_header_bar_dispose (GObject *object)
                headerbar->priv->prefered_item_notify_id = 0;
        }
 
+       g_clear_object (&headerbar->priv->menu_button);
+
        /* Chain up to parent's method. */
        G_OBJECT_CLASS (e_shell_header_bar_parent_class)->dispose (object);
 }
 
+static void
+shell_header_bar_finalize (GObject *object)
+{
+       EShellHeaderBar *self = E_SHELL_HEADER_BAR (object);
+
+       g_weak_ref_clear (&self->priv->shell_window);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_shell_header_bar_parent_class)->finalize (object);
+}
+
 static void
 e_shell_header_bar_class_init (EShellHeaderBarClass *klass)
 {
@@ -180,8 +232,22 @@ e_shell_header_bar_class_init (EShellHeaderBarClass *klass)
        object_class = G_OBJECT_CLASS (klass);
        object_class->set_property = shell_header_bar_set_property;
        object_class->get_property = shell_header_bar_get_property;
-       object_class->dispose = shell_header_bar_dispose;
        object_class->constructed = shell_header_bar_constructed;
+       object_class->dispose = shell_header_bar_dispose;
+       object_class->finalize = shell_header_bar_finalize;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_MENU_BUTTON,
+               g_param_spec_object (
+                       "menu-button",
+                       "Menu Button",
+                       "Menu button to add to the header bar",
+                       GTK_TYPE_WIDGET,
+                       G_PARAM_WRITABLE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_EXPLICIT_NOTIFY |
+                       G_PARAM_STATIC_STRINGS));
 
        /**
         * EShellHeaderbar:shell-window
@@ -205,28 +271,16 @@ e_shell_header_bar_class_init (EShellHeaderBarClass *klass)
 static void
 e_shell_header_bar_init (EShellHeaderBar *self)
 {
-       GtkWidget *new_button;
-
        self->priv = e_shell_header_bar_get_instance_private (self);
-       gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (self), TRUE);
-
-       new_button = e_header_bar_button_new (C_("toolbar-button", "New"), NULL);
-       gtk_header_bar_pack_start (GTK_HEADER_BAR (self), new_button);
-       gtk_widget_show (new_button);
-       self->priv->new_button = g_object_ref (new_button);
+       g_weak_ref_init (&self->priv->shell_window, NULL);
 
-       self->priv->start_buttons = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
-       gtk_header_bar_pack_start (GTK_HEADER_BAR (self), self->priv->start_buttons);
-       gtk_widget_show (self->priv->start_buttons);
-
-       self->priv->end_buttons = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
-       gtk_header_bar_pack_end (GTK_HEADER_BAR (self), self->priv->end_buttons);
-       gtk_widget_show (self->priv->end_buttons);
+       gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (self), TRUE);
 }
 
 /**
  * e_shell_header_bar_new:
  * @shel_window: The #EShellWindow to which the headerbar belongs
+ * @menu_button: a menu button to add to the header bar
  *
  * Creates a new #EShellHeaderBar
  *
@@ -235,9 +289,13 @@ e_shell_header_bar_init (EShellHeaderBar *self)
  * Since: 3.46
  **/
 GtkWidget *
-e_shell_header_bar_new (EShellWindow *shell_window)
+e_shell_header_bar_new (EShellWindow *shell_window,
+                       GtkWidget *menu_button)
 {
-       return g_object_new (E_TYPE_SHELL_HEADER_BAR, "shell-window", shell_window, NULL);
+       return g_object_new (E_TYPE_SHELL_HEADER_BAR,
+               "shell-window", shell_window,
+               "menu-button", menu_button,
+               NULL);
 }
 
 /**
diff --git a/src/shell/e-shell-headerbar.h b/src/shell/e-shell-headerbar.h
index 2aaabf009b..86068c9564 100644
--- a/src/shell/e-shell-headerbar.h
+++ b/src/shell/e-shell-headerbar.h
@@ -46,7 +46,8 @@ struct _EShellHeaderBarClass {
 };
 
 GType                  e_shell_header_bar_get_type                     (void);
-GtkWidget *            e_shell_header_bar_new                          (EShellWindow *shell_window);
+GtkWidget *            e_shell_header_bar_new                          (EShellWindow *shell_window,
+                                                                        GtkWidget *menu_button);
 GtkWidget *            e_shell_header_bar_get_new_button               (EShellHeaderBar *headerbar);
 void                   e_shell_header_bar_pack_start                   (EShellHeaderBar *headerbar,
                                                                         GtkWidget *widget);
diff --git a/src/shell/e-shell-window-private.c b/src/shell/e-shell-window-private.c
index 7dce9252e6..1a7f7b1cad 100644
--- a/src/shell/e-shell-window-private.c
+++ b/src/shell/e-shell-window-private.c
@@ -326,7 +326,7 @@ e_shell_window_private_constructed (EShellWindow *shell_window)
        GtkUIManager *ui_manager;
        GtkBox *box;
        GtkPaned *paned;
-       GtkWidget *widget;
+       GtkWidget *widget, *menubar, *menu_button = NULL;
        GtkWindow *window;
        guint merge_id;
        const gchar *id;
@@ -358,7 +358,11 @@ e_shell_window_private_constructed (EShellWindow *shell_window)
 
        /* Construct window widgets. */
 
-       priv->headerbar = e_shell_header_bar_new (shell_window);
+       menubar = shell_window_construct_menubar (shell_window);
+       if (menubar)
+               shell_window->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (menubar), window, &menu_button);
+
+       priv->headerbar = e_shell_header_bar_new (shell_window, menu_button);
        gtk_window_set_titlebar (window, priv->headerbar);
        gtk_widget_show (priv->headerbar);
 
@@ -368,11 +372,8 @@ e_shell_window_private_constructed (EShellWindow *shell_window)
 
        box = GTK_BOX (widget);
 
-       widget = shell_window_construct_menubar (shell_window);
-       if (widget != NULL) {
-               shell_window->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), window);
-               gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
-       }
+       if (menubar)
+               gtk_box_pack_start (box, menubar, FALSE, FALSE, 0);
 
        widget = shell_window_construct_toolbar (shell_window);
        if (widget != NULL)
diff --git a/src/shell/e-shell-window-private.h b/src/shell/e-shell-window-private.h
index 6fecfef838..502ef38cb6 100644
--- a/src/shell/e-shell-window-private.h
+++ b/src/shell/e-shell-window-private.h
@@ -28,6 +28,8 @@
 
 #include <libebackend/libebackend.h>
 
+#include "e-util/e-util.h"
+
 #include "shell/e-shell.h"
 #include "shell/e-shell-content.h"
 #include "shell/e-shell-headerbar.h"
@@ -82,7 +84,7 @@ struct _EShellWindowPrivate {
        GtkWidget *tooltip_label;
        GtkWidget *status_notebook;
        GtkWidget *headerbar;
-       GtkWidget *menu_bar;
+       EMenuBar *menu_bar;
 
        /* Shell signal handlers. */
        GArray *signal_handler_ids;


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