[geary/mjog/493-undo-send: 15/25] Clean up how Composer.Widget's presentation mode is updated



commit c2c7590faa5177a94c777e822d233729de215baa
Author: Michael Gratton <mike vee net>
Date:   Tue Nov 12 11:52:49 2019 +1100

    Clean up how Composer.Widget's presentation mode is updated
    
    Rather than scattering the composer's detached/paned/inline mode all
    over the code base, make it settable only by the containers it is
    embedded in, since in that's what actually determines it.
    
    This also lets composers be re-added to the main window if needed.

 src/client/application/application-controller.vala |  28 +--
 src/client/components/main-window.vala             |  43 +++-
 src/client/composer/composer-box.vala              |   8 +
 src/client/composer/composer-embed.vala            |  11 +
 src/client/composer/composer-headerbar.vala        | 101 ++++++---
 src/client/composer/composer-widget.vala           | 238 ++++++++++++---------
 src/client/composer/composer-window.vala           |   4 +
 ui/composer-headerbar.ui                           |   3 +-
 8 files changed, 286 insertions(+), 150 deletions(-)
---
diff --git a/src/client/application/application-controller.vala 
b/src/client/application/application-controller.vala
index 5d20a421..2abb151a 100644
--- a/src/client/application/application-controller.vala
+++ b/src/client/application/application-controller.vala
@@ -1471,6 +1471,13 @@ public class Application.Controller : Geary.BaseObject {
         }
     }
 
+    /** Displays a composer on the last active main window. */
+    internal void show_composer(Composer.Widget composer,
+                                Gee.Collection<Geary.EmailIdentifier>? refers_to) {
+        this.main_window.show_composer(composer, refers_to);
+        composer.set_focus();
+    }
+
     internal bool close_composition_windows(bool main_window_only = false) {
         Gee.List<Composer.Widget> composers_to_destroy = new Gee.ArrayList<Composer.Widget>();
         bool quit_cancelled = false;
@@ -1547,14 +1554,13 @@ public class Application.Controller : Geary.BaseObject {
                                        bool is_draft) {
         // There's a few situations where we can re-use an existing
         // composer, check for these first.
-
         if (compose_type == NEW_MESSAGE && !is_draft) {
             // We're creating a new message that isn't a draft, if
             // there's already a composer open, just use that
             Composer.Widget? existing =
                 this.main_window.conversation_viewer.current_composer;
             if (existing != null &&
-                existing.state == PANED &&
+                existing.current_mode == PANED &&
                 existing.is_blank) {
                 existing.present();
                 return;
@@ -1565,8 +1571,8 @@ public class Application.Controller : Geary.BaseObject {
             // reply/forward for that message, or there is a quote
             // to insert into it.
             foreach (Composer.Widget existing in this.composer_widgets) {
-                if ((existing.state == INLINE ||
-                     existing.state == INLINE_COMPACT) &&
+                if ((existing.current_mode == INLINE ||
+                     existing.current_mode == INLINE_COMPACT) &&
                     (referred.id in existing.get_referred_ids() ||
                      quote != null)) {
                     try {
@@ -1600,15 +1606,10 @@ public class Application.Controller : Geary.BaseObject {
         }
 
         add_composer(widget);
-
-        if (widget.state == INLINE || widget.state == INLINE_COMPACT) {
-            this.main_window.conversation_viewer.do_compose_embedded(
-                widget,
-                referred
-            );
-        } else {
-            this.main_window.show_composer(widget);
-        }
+        show_composer(
+            widget,
+            referred != null ? Geary.Collection.single(referred.id) : null
+        );
 
         this.load_composer.begin(
             account,
@@ -1648,7 +1649,6 @@ public class Application.Controller : Geary.BaseObject {
         } catch (GLib.Error err) {
             report_problem(new Geary.ProblemReport(err));
         }
-        widget.set_focus();
     }
 
     private void on_composer_widget_destroy(Gtk.Widget sender) {
diff --git a/src/client/components/main-window.vala b/src/client/components/main-window.vala
index 3690d0a6..b64cc6e5 100644
--- a/src/client/components/main-window.vala
+++ b/src/client/components/main-window.vala
@@ -570,17 +570,50 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
             this.application, this.selected_folder.account, to
         );
         this.application.controller.add_composer(composer);
-        show_composer(composer);
+        show_composer(composer, null);
         composer.load.begin(null, false, null, null);
     }
 
-    /** Displays a composer in the window if possible, else in a new window. */
-    public void show_composer(Composer.Widget composer) {
+    /**
+     * Displays a composer in the window if possible, else in a new window.
+     *
+     * If the given collection of identifiers is not null and any are
+     * contained in the current conversation then the composer will be
+     * displayed inline under the latest matching message. If null,
+     * the composer's {@link Composer.Widget.get_referred_ids} will be
+     * used.
+     */
+    public void show_composer(Composer.Widget composer,
+                              Gee.Collection<Geary.EmailIdentifier>? refers_to) {
         if (this.has_composer) {
             composer.detach();
         } else {
-            this.conversation_viewer.do_compose(composer);
-            get_window_action(ACTION_FIND_IN_CONVERSATION).set_enabled(false);
+            // See if the currently displayed conversation contains
+            // any of the composer's referred emails (preferring the
+            // latest), and if so add it inline, otherwise add it full
+            // paned.
+            Geary.Email? latest_referred = null;
+            if (this.conversation_viewer.current_list != null) {
+                Gee.Collection<Geary.EmailIdentifier>? referrants = refers_to;
+                if (referrants == null) {
+                    referrants = composer.get_referred_ids();
+                }
+                Geary.App.Conversation selected =
+                    this.conversation_viewer.current_list.conversation;
+                latest_referred = selected.get_emails(
+                    RECV_DATE_DESCENDING
+                ).first_match(
+                    (email) => email.id in referrants
+                );
+            }
+
+            if (latest_referred != null) {
+                this.conversation_viewer.do_compose_embedded(
+                    composer, latest_referred
+                );
+            } else {
+                this.conversation_viewer.do_compose(composer);
+            }
         }
     }
 
diff --git a/src/client/composer/composer-box.vala b/src/client/composer/composer-box.vala
index d2a455af..971f0fae 100644
--- a/src/client/composer/composer-box.vala
+++ b/src/client/composer/composer-box.vala
@@ -8,6 +8,9 @@
 
 /**
  * A container for full-height paned composers in the main window.
+ *
+ * Adding a composer to this container places it in {@link
+ * PresentationMode.PANED} mode.
  */
 public class Composer.Box : Gtk.Frame, Container {
 
@@ -28,6 +31,7 @@ public class Composer.Box : Gtk.Frame, Container {
 
     public Box(Widget composer, MainToolbar main_toolbar) {
         this.composer = composer;
+        this.composer.set_mode(PANED);
 
         this.main_toolbar = main_toolbar;
         this.main_toolbar.set_conversation_header(composer.header);
@@ -50,4 +54,8 @@ public class Composer.Box : Gtk.Frame, Container {
         destroy();
     }
 
+    public override void destroy() {
+        debug("Composer.Box::destroy");
+    }
+
 }
diff --git a/src/client/composer/composer-embed.vala b/src/client/composer/composer-embed.vala
index 4d188c5e..e124dc95 100644
--- a/src/client/composer/composer-embed.vala
+++ b/src/client/composer/composer-embed.vala
@@ -8,6 +8,10 @@
 
 /**
  * A container for full-height paned composers in the main window.
+ *
+ * Adding a composer to this container places it in {@link
+ * PresentationMode.INLINE} or {@link PresentationMode.INLINE_COMPACT}
+ * mode.
  */
 public class Composer.Embed : Gtk.EventBox, Container {
 
@@ -38,6 +42,13 @@ public class Composer.Embed : Gtk.EventBox, Container {
         this.composer = composer;
         this.composer.embed_header();
 
+        Widget.PresentationMode mode = INLINE_COMPACT;
+        if (composer.compose_type == FORWARD ||
+            composer.has_multiple_from_addresses) {
+            mode = INLINE;
+        }
+        composer.set_mode(mode);
+
         this.outer_scroller = outer_scroller;
 
         get_style_context().add_class("geary-composer-embed");
diff --git a/src/client/composer/composer-headerbar.vala b/src/client/composer/composer-headerbar.vala
index 16c41ce7..4fde97cd 100644
--- a/src/client/composer/composer-headerbar.vala
+++ b/src/client/composer/composer-headerbar.vala
@@ -7,14 +7,15 @@
 [GtkTemplate (ui = "/org/gnome/Geary/composer-headerbar.ui")]
 public class Composer.Headerbar : Gtk.HeaderBar {
 
-    public Application.Configuration config { get; set; }
 
-    public Widget.ComposerState state { get; set; }
+    public bool show_save_and_close {
+        get { return this.save_and_close_button.visible; }
+        set { this.save_and_close_button.visible = value; }
+    }
 
-    public bool show_pending_attachments { get; set; default = false; }
+    private Application.Configuration config;
 
-    [GtkChild]
-    internal Gtk.Button save_and_close_button; // { get; private set; }
+    private bool is_attached = true;
 
     [GtkChild]
     private Gtk.Box detach_start;
@@ -28,49 +29,87 @@ public class Composer.Headerbar : Gtk.HeaderBar {
     private Gtk.Button new_message_attach_button;
     [GtkChild]
     private Gtk.Box conversation_attach_buttons;
+    [GtkChild]
+    private Gtk.Button save_and_close_button;
+
 
     /** Fired when the user wants to expand a compact composer. */
     public signal void expand_composer();
 
-    public Headerbar(Application.Configuration config, bool is_compact) {
-        this.config = config;
-
-        this.recipients_button.set_visible(is_compact);
-        this.recipients_button.clicked.connect(() => {
-                this.recipients_button.hide();
-                expand_composer();
-            });
-
-        bind_property("show-pending-attachments", new_message_attach_button, "visible",
-            BindingFlags.SYNC_CREATE | BindingFlags.INVERT_BOOLEAN);
-        bind_property("show-pending-attachments", conversation_attach_buttons, "visible",
-            BindingFlags.SYNC_CREATE);
 
-        set_detach_button_side();
+    public Headerbar(Application.Configuration config) {
+        this.config = config;
         Gtk.Settings.get_default().notify["gtk-decoration-layout"].connect(
-            () => { set_detach_button_side(); }
+            on_gtk_decoration_layout_changed
         );
     }
 
+    public override void destroy() {
+        Gtk.Settings.get_default().notify["gtk-decoration-layout"].disconnect(
+            on_gtk_decoration_layout_changed
+        );
+        base.destroy();
+    }
+
     public void set_recipients(string label, string tooltip) {
         recipients_label.label = label;
         recipients_button.tooltip_text = tooltip;
     }
 
-    public void detached() {
-        notify["decoration-layout"].disconnect(set_detach_button_side);
-        this.recipients_button.hide();
-        this.detach_start.visible = this.detach_end.visible = false;
+    public void set_show_pending_attachments(bool show) {
+        this.new_message_attach_button.visible = !show;
+        this.conversation_attach_buttons.visible = show;
     }
 
-    private void set_detach_button_side() {
-        if (config.desktop_environment == UNITY) {
-            detach_start.visible = false;
-            detach_end.visible = true;
+    internal void set_mode(Widget.PresentationMode mode) {
+        switch (mode) {
+        case Widget.PresentationMode.DETACHED:
+            this.recipients_button.visible = false;
+            this.set_attached(false);
+            break;
+
+        case Widget.PresentationMode.PANED:
+        case Widget.PresentationMode.INLINE:
+            this.recipients_button.visible = false;
+            this.set_attached(true);
+            break;
+
+        case Widget.PresentationMode.INLINE_COMPACT:
+            this.recipients_button.visible = true;
+            this.set_attached(true);
+            break;
+        }
+    }
+
+    private void set_attached(bool is_attached) {
+        this.is_attached = is_attached;
+        if (is_attached) {
+            set_detach_button_side();
         } else {
-            bool at_end = Util.Gtk.close_button_at_end();
-            detach_start.visible = !at_end;
-            detach_end.visible = at_end;
+            this.detach_start.visible = this.detach_end.visible = false;
+        }
+    }
+
+    private void set_detach_button_side() {
+        if (this.is_attached) {
+            if (this.config.desktop_environment == UNITY) {
+                this.detach_start.visible = false;
+                this.detach_end.visible = true;
+            } else {
+                bool at_end = Util.Gtk.close_button_at_end();
+                this.detach_start.visible = !at_end;
+                this.detach_end.visible = at_end;
+            }
         }
     }
+
+    [GtkCallback]
+    private void on_recipients_button_clicked() {
+        expand_composer();
+    }
+
+    private void on_gtk_decoration_layout_changed() {
+        set_detach_button_side();
+    }
+
 }
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index 39dba06e..100ee314 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -37,10 +37,37 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
         CANCEL_CLOSE
     }
 
-    public enum ComposerState {
+    /** Defines different supported user interface modes. */
+    public enum PresentationMode {
+        /** Composer is not currently visible. */
+        NONE,
+
+        /**
+         * Composer is in its own window, not in a main windows.
+         *
+         * @see Window
+         */
         DETACHED,
+
+        /**
+         * Composer is in a full-height box in a main window.
+         *
+         * @see Box
+         */
         PANED,
+
+        /**
+         * Composer is embedded inline in a conversation.
+         *
+         * @see Embed
+         */
         INLINE,
+
+        /**
+         * Composer is embedded inline with header fields hidden.
+         *
+         * @see Embed
+         */
         INLINE_COMPACT
     }
 
@@ -195,7 +222,8 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
         }
     }
 
-    public ComposerState state { get; private set; }
+    /** Determines the composer's current presentation mode. */
+    public PresentationMode current_mode { get; set; default = NONE; }
 
     /** Determines the type of email being composed. */
     public ComposeType compose_type { get; private set; default = ComposeType.NEW_MESSAGE; }
@@ -217,6 +245,15 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
 
     internal Headerbar header { get; private set; }
 
+    internal bool has_multiple_from_addresses {
+        get {
+            return (
+                this.accounts.size > 1 ||
+                this.account.information.has_sender_aliases
+            );
+        }
+    }
+
     internal string subject {
         get { return this.subject_entry.get_text(); }
         private set { this.subject_entry.set_text(value); }
@@ -431,27 +468,9 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
         }
 
         this.compose_type = compose_type;
-        if (this.compose_type == ComposeType.NEW_MESSAGE) {
-            this.state = ComposerState.PANED;
-        }
-        else if (this.compose_type == ComposeType.FORWARD ||
-                 this.accounts.size > 1 || this.account.information.has_sender_aliases) {
-            this.state = ComposerState.INLINE;
-        }
-        else {
-            this.state = ComposerState.INLINE_COMPACT;
-        }
 
-        this.header = new Headerbar(
-            application.config,
-            this.state == ComposerState.INLINE_COMPACT
-        );
-        this.header.expand_composer.connect(() => {
-                if (this.state == ComposerState.INLINE_COMPACT) {
-                    this.state = ComposerState.INLINE;
-                    update_composer_view();
-                }
-            });
+        this.header = new Headerbar(application.config);
+        this.header.expand_composer.connect(on_expand_compact_headers);
 
         // Setup drag 'n drop
         const Gtk.TargetEntry[] target_entries = { { URI_LIST_MIME_TYPE, 0, 0 } };
@@ -553,7 +572,6 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
         this.editor.mouse_target_changed.connect(on_mouse_target_changed);
         this.editor.selection_changed.connect(on_selection_changed);
 
-        update_composer_view();
         load_entry_completions();
     }
 
@@ -660,10 +678,6 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
             }
         }
 
-        if (this.state == ComposerState.INLINE_COMPACT)
-            set_compact_header_recipients();
-
-        update_composer_view();
         update_attachments_view();
         update_pending_attachments(this.pending_include, true);
 
@@ -686,44 +700,41 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
 
     /** Detaches the composer and opens it in a new window. */
     public void detach() {
-        if (this.state != ComposerState.DETACHED) {
-            Gtk.Widget? focused_widget = this.container.top_window.get_focus();
-            if (this.container != null) {
-                this.container.close();
-            }
-            Window new_window = new Window(this, this.application);
-
-            // Workaround a GTK+ crasher, Bug 771812. When the
-            // composer is re-parented, its menu_button's popover
-            // keeps a reference to the conversation window's
-            // viewport, so when that is removed it has a null parent
-            // and we crash. To reproduce: Reply inline, detach the
-            // composer, then choose a different conversation back in
-            // the main window. The workaround here sets a new menu
-            // model and hence the menu_button constructs a new
-            // popover.
-            this.composer_actions.change_action_state(
-                ACTION_COMPOSE_AS_HTML,
-                this.application.config.compose_as_html
-            );
+        Gtk.Widget? focused_widget = this.container.top_window.get_focus();
+        if (this.container != null) {
+            this.container.close();
+        }
+        Window new_window = new Window(this, this.application);
+
+        // Workaround a GTK+ crasher, Bug 771812. When the
+        // composer is re-parented, its menu_button's popover
+        // keeps a reference to the conversation window's
+        // viewport, so when that is removed it has a null parent
+        // and we crash. To reproduce: Reply inline, detach the
+        // composer, then choose a different conversation back in
+        // the main window. The workaround here sets a new menu
+        // model and hence the menu_button constructs a new
+        // popover.
+        this.composer_actions.change_action_state(
+            ACTION_COMPOSE_AS_HTML,
+            this.application.config.compose_as_html
+        );
 
-            this.state = DETACHED;
-            update_composer_view();
-
-            // If the previously focused widget is in the new composer
-            // window then focus that, else focus something useful.
-            bool refocus = true;
-            if (focused_widget != null) {
-                Window? focused_window = focused_widget.get_toplevel() as Window;
-                if (new_window == focused_window) {
-                    focused_widget.grab_focus();
-                    refocus = false;
-                }
-            }
-            if (refocus) {
-                set_focus();
+        set_mode(DETACHED);
+
+        // If the previously focused widget is in the new composer
+        // window then focus that, else focus something useful.
+        bool refocus = true;
+        if (focused_widget != null) {
+            Window? focused_window = focused_widget.get_toplevel() as Window;
+            if (new_window == focused_window) {
+                focused_widget.grab_focus();
+                refocus = false;
             }
         }
+        if (refocus) {
+            set_focus();
+        }
     }
 
     /** Closes the composer unconditionally. */
@@ -768,6 +779,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
      * and will stop periodically saving drafts.
      */
     public void set_enabled(bool enabled) {
+        this.current_mode = NONE;
         this.is_closing = !enabled;
         this.set_sensitive(enabled);
 
@@ -856,14 +868,24 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
         if (bcc != "")
             this.bcc_entry.modified = true;
 
-        if (in_reply_to.size > 1) {
-            this.state = ComposerState.PANED;
-        } else if (this.compose_type == ComposeType.FORWARD || this.to_entry.modified
-                   || this.cc_entry.modified || this.bcc_entry.modified
-                   || this.accounts.size > 1 || this.account.information.has_sender_aliases) {
-            this.state = ComposerState.INLINE;
-        } else {
-            this.state = ComposerState.INLINE_COMPACT;
+        // We're in compact inline mode, but there are modified email
+        // addresses, so set us to use plain inline mode instead so
+        // the modified addresses can be seen. If there are CC
+        if (this.current_mode == INLINE_COMPACT && (
+                this.to_entry.modified ||
+                this.cc_entry.modified ||
+                this.bcc_entry.modified ||
+                this.reply_to_entry.modified)) {
+            set_mode(INLINE);
+        }
+
+        // If there's a modified header that would normally be hidden,
+        // show full fields.
+        if (this.bcc_entry.modified ||
+            this.reply_to_entry.modified) {
+            this.editor_actions.change_action_state(
+                ACTION_SHOW_EXTENDED_HEADERS, true
+            );
         }
     }
 
@@ -949,7 +971,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
     }
 
     public void set_focus() {
-        bool not_compact = (this.state != ComposerState.INLINE_COMPACT);
+        bool not_compact = this.current_mode != INLINE_COMPACT;
         if (not_compact && Geary.String.is_empty(to))
             this.to_entry.grab_focus();
         else if (not_compact && Geary.String.is_empty(subject))
@@ -1196,8 +1218,6 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
                 )
             );
         }
-
-        update_composer_view();
     }
 
     private void add_recipients_and_ids(ComposeType type, Geary.Email referred,
@@ -1318,6 +1338,35 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
         return check_send_on_return(event) && base.key_press_event(event);
     }
 
+    internal void set_mode(PresentationMode new_mode) {
+        this.current_mode = new_mode;
+        this.header.set_mode(new_mode);
+
+        switch (new_mode) {
+        case PresentationMode.DETACHED:
+        case PresentationMode.PANED:
+            this.recipients.set_visible(true);
+            this.subject_label.set_visible(true);
+            this.subject_entry.set_visible(true);
+            break;
+
+        case PresentationMode.INLINE:
+            this.recipients.set_visible(true);
+            this.subject_label.set_visible(false);
+            this.subject_entry.set_visible(false);
+            break;
+
+        case PresentationMode.INLINE_COMPACT:
+            this.recipients.set_visible(false);
+            this.subject_label.set_visible(false);
+            this.subject_entry.set_visible(false);
+            set_compact_header_recipients();
+            break;
+        }
+
+        update_from_field();
+    }
+
     internal void embed_header() {
         if (this.header.parent == null) {
             this.header_area.add(this.header);
@@ -1328,20 +1377,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
     internal void free_header() {
         if (this.header.parent != null) {
             this.header.parent.remove(this.header);
-    }
-
-    // Updates the composer's UI after its state has changed
-    private void update_composer_view() {
-        this.recipients.set_visible(this.state != ComposerState.INLINE_COMPACT);
-
-        bool not_inline = (this.state != ComposerState.INLINE &&
-                           this.state != ComposerState.INLINE_COMPACT);
-        this.subject_label.set_visible(not_inline);
-        this.subject_entry.set_visible(not_inline);
-
-        this.header.state = this.state;
-
-        update_from_field();
+        }
     }
 
     private async bool should_send() {
@@ -1423,7 +1459,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
                                                 GLib.Cancellable? cancellable)
         throws GLib.Error {
         if (!this.account.information.save_drafts) {
-            this.header.save_and_close_button.hide();
+            this.header.show_save_and_close = false;
             return;
         }
 
@@ -1445,7 +1481,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
             yield new_manager.open_async(editing_draft_id, internal_cancellable);
             debug("Draft manager opened");
         } catch (GLib.Error err) {
-            this.header.save_and_close_button.hide();
+            this.header.show_save_and_close = false;
             throw err;
         } finally {
             this.draft_manager_opening = null;
@@ -1461,8 +1497,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
 
         update_draft_state();
         get_action(ACTION_CLOSE_AND_SAVE).set_enabled(true);
-        this.header.save_and_close_button.show();
-
+        this.header.show_save_and_close = true;
     }
 
     /**
@@ -1651,7 +1686,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
                 }
             }
         }
-        this.header.show_pending_attachments = manual_enabled;
+        this.header.set_show_pending_attachments(manual_enabled);
         return have_added;
     }
 
@@ -1919,7 +1954,8 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
         this.application.config.compose_as_html = compose_as_html;
     }
 
-    private void on_show_extended_toggled(SimpleAction? action, Variant? new_state) {
+    private void on_show_extended_headers_toggled(GLib.SimpleAction? action,
+                                                  GLib.Variant? new_state) {
         bool show_extended = new_state.get_boolean();
         action.set_state(show_extended);
         this.bcc_label.visible =
@@ -1927,9 +1963,8 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
             this.reply_to_label.visible =
             this.reply_to_entry.visible = show_extended;
 
-        if (show_extended && this.state == ComposerState.INLINE_COMPACT) {
-            this.state = ComposerState.INLINE;
-            update_composer_view();
+        if (show_extended && this.current_mode == INLINE_COMPACT) {
+            set_mode(INLINE);
         }
     }
 
@@ -2184,9 +2219,10 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
         // Don't show in inline unless the current account has
         // multiple email accounts or aliases, since these will be replies to a
         // conversation
-        if ((this.state == ComposerState.INLINE || this.state == ComposerState.INLINE_COMPACT) &&
-            !(this.accounts.size > 1 || this.account.information.has_sender_aliases)) {
-            return false;         
+        if ((this.current_mode == INLINE ||
+             this.current_mode == INLINE_COMPACT) &&
+            !this.has_multiple_from_addresses) {
+            return false;
         }
 
         // If there's only one account and it not have any aliases,
@@ -2390,6 +2426,10 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
         }
     }
 
+    private void on_expand_compact_headers() {
+        set_mode(INLINE);
+    }
+
     private void on_detach() {
         detach();
     }
diff --git a/src/client/composer/composer-window.vala b/src/client/composer/composer-window.vala
index 33650e42..cd4deee8 100644
--- a/src/client/composer/composer-window.vala
+++ b/src/client/composer/composer-window.vala
@@ -8,6 +8,9 @@
 
 /**
  * A container detached composers, i.e. in their own separate window.
+ *
+ * Adding a composer to this container places it in {@link
+ * PresentationMode.DETACHED} mode.
  */
 public class Composer.Window : Gtk.ApplicationWindow, Container {
 
@@ -33,6 +36,7 @@ public class Composer.Window : Gtk.ApplicationWindow, Container {
     public Window(Widget composer, GearyApplication application) {
         Object(application: application, type: Gtk.WindowType.TOPLEVEL);
         this.composer = composer;
+        this.composer.set_mode(DETACHED);
 
         // XXX Bug 764622
         set_property("name", "GearyComposerWindow");
diff --git a/ui/composer-headerbar.ui b/ui/composer-headerbar.ui
index d3337550..52ec320c 100644
--- a/ui/composer-headerbar.ui
+++ b/ui/composer-headerbar.ui
@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
 <interface>
   <requires lib="gtk+" version="3.20"/>
   <template class="ComposerHeaderbar" parent="GtkHeaderBar">
@@ -72,7 +73,6 @@
     </child>
     <child>
       <object class="GtkBox" id="conversation_attach_buttons">
-        <property name="visible">True</property>
         <property name="can_focus">False</property>
         <child>
           <object class="GtkButton" id="conversation_attach_new_button">
@@ -137,6 +137,7 @@
         <property name="focus_on_click">False</property>
         <property name="receives_default">False</property>
         <property name="relief">none</property>
+        <signal name="clicked" handler="on_recipients_button_clicked" swapped="no"/>
         <child>
           <object class="GtkLabel" id="recipients_label">
             <property name="visible">True</property>


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