[geary/bug/728002-webkit2: 68/140] Reenable undo/redo composer actions.



commit 2bd5306d30db0d719f64475e50d11bee15db804f
Author: Michael James Gratton <mike vee net>
Date:   Wed Jan 4 18:53:28 2017 +1100

    Reenable undo/redo composer actions.
    
    * src/client/composer/composer-web-view.vala (ComposerWebView): Add new
      ::command_stack_changed signal to manage undo/redo enabled state, hook
      it up to a JS callback. Add ::is_empty property as a non-functioning
      shim in lieu of can_undo going away. Remove ::can_undo and ::can_redo,
      replace them with methods to actually fire an undo and redo.
    
    * src/client/composer/composer-widget.vala (ComposerWidget): Use
      ClientWebView::is_empty rather inplace of can_redo for determining
      editing state. Remove old undo/redo signal hookups, replace with
      ::command_stack_changed and manage action enable state from there.
      (ComposerWidget::action_entries): Add explicit actions for undo/redo,
      since they need some custom code over on on the web process side.
      (ComposerWidget::on_compose_as_html_toggled): Explciitly manage the
      visibility of rich text toolbar buttons, don't rely on obscure
      GtkBuilder magic that Glade doesn't support.
    
    * ui/composer-web-view.js: Add a mutation observer for the message body
      and explcit methods for firing undo/redo commands, so we can keep track
      of how the command stack changes. As it does, fire commandStackChanged
      messages back to the client process. Explicity set the message body as
      content-editable after the document has been mutated for quotes, etc.
    
    * ui/composer-widget.ui: Add bonus undo/redo toobar buttons for the
      composer.

 src/client/composer/composer-web-view.vala |   51 ++++--
 src/client/composer/composer-widget.vala   |   35 +++-
 ui/composer-web-view.js                    |   61 ++++++-
 ui/composer-widget.ui                      |  262 ++++++++++++++++++++--------
 4 files changed, 308 insertions(+), 101 deletions(-)
---
diff --git a/src/client/composer/composer-web-view.vala b/src/client/composer/composer-web-view.vala
index 58e61e6..bfba08b 100644
--- a/src/client/composer/composer-web-view.vala
+++ b/src/client/composer/composer-web-view.vala
@@ -12,6 +12,8 @@
 public class ComposerWebView : ClientWebView {
 
 
+    private const string COMMAND_STACK_CHANGED = "commandStackChanged";
+
     private const string HTML_BODY = """
         <html><head><title></title>
         <style>
@@ -55,7 +57,7 @@ public class ComposerWebView : ClientWebView {
         }
         </style>
         </head><body>
-        <div id="message-body" contenteditable="true" dir="auto">%s</div>
+        <div id="message-body" dir="auto">%s</div>
         </body></html>""";
     private const string CURSOR = "<span id=\"cursormarker\"></span>";
 
@@ -68,17 +70,37 @@ public class ComposerWebView : ClientWebView {
         );
     }
 
+    /** Determines if the view contains any edited text */
+    public bool is_empty { get; private set; default = false; }
+
     /** Determines if the view is in rich text mode */
     public bool is_rich_text { get; private set; default = true; }
 
     private bool is_shift_down = false;
 
 
+    /** Emitted when the web view's undo/redo stack has changed. */
+    public signal void command_stack_changed(bool can_undo, bool can_redo);
+
     public ComposerWebView(Configuration config) {
         base(config);
         this.user_content_manager.add_script(ComposerWebView.app_script);
         // this.should_insert_text.connect(on_should_insert_text);
         this.key_press_event.connect(on_key_press_event);
+
+        this.user_content_manager.script_message_received[COMMAND_STACK_CHANGED].connect(
+            (result) => {
+                try {
+                    string[] values = WebKitUtil.to_string(result).split(",");
+                    command_stack_changed(values[0] == "true", values[1] == "true");
+                } catch (Geary.JS.Error err) {
+                    debug("Could not get command stack state: %s", err.message);
+                } finally {
+                    result.unref();
+                }
+            });
+                    result.unref();
+        register_message_handler(COMMAND_STACK_CHANGED);
     }
 
     /**
@@ -98,24 +120,19 @@ public class ComposerWebView : ClientWebView {
         base.load_html(HTML_BODY.printf(html));
     }
 
-    public bool can_undo() {
-        // can_execute_editing_command.begin(
-        //     WebKit.EDITING_COMMAND_UNDO,
-        //     null,
-        //     (obj, res) => {
-        //         return can_execute_editing_command.end(res);
-        //     });
-        return false;
+
+    /**
+     * Undoes the last edit operation.
+     */
+    public void undo() {
+        this.run_javascript.begin("geary.undo();", null);
     }
 
-    public bool can_redo() {
-        // can_execute_editing_command.begin(
-        //     WebKit.EDITING_COMMAND_REDO,
-        //     null,
-        //     (obj, res) => {
-        //         return can_execute_editing_command.end(res);
-        //     });
-        return false;
+    /**
+     * Redoes the last undone edit operation.
+     */
+    public void redo() {
+        this.run_javascript.begin("geary.redo();", null);
     }
 
     /**
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index b725f40..6c53658 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -87,8 +87,8 @@ public class ComposerWidget : Gtk.EventBox {
 
     private const ActionEntry[] action_entries = {
         // Editor commands
-        {ACTION_UNDO,                     on_action                                     },
-        {ACTION_REDO,                     on_action                                     },
+        {ACTION_UNDO,                     on_undo                                       },
+        {ACTION_REDO,                     on_redo                                       },
         {ACTION_CUT,                      on_cut                                        },
         {ACTION_COPY,                     on_copy                                       },
         {ACTION_COPY_LINK,                on_copy_link                                  },
@@ -209,7 +209,7 @@ public class ComposerWidget : Gtk.EventBox {
                 this.bcc_entry.empty &&
                 this.reply_to_entry.empty &&
                 this.subject_entry.buffer.length == 0 &&
-                !this.editor.can_undo() &&
+                !this.editor.is_empty &&
                 this.attached_files.size == 0;
         }
     }
@@ -286,8 +286,13 @@ public class ComposerWidget : Gtk.EventBox {
     [GtkChild]
     private Gtk.Box header_area;
     [GtkChild]
+
     private Gtk.Box composer_toolbar;
     [GtkChild]
+    private Gtk.Box insert_buttons;
+    [GtkChild]
+    private Gtk.Box font_style_buttons;
+    [GtkChild]
     private Gtk.Button remove_format_button;
     [GtkChild]
     private Gtk.Button select_dictionary_button;
@@ -295,6 +300,7 @@ public class ComposerWidget : Gtk.EventBox {
     private Gtk.MenuButton menu_button;
     [GtkChild]
     private Gtk.Label info_label;
+
     [GtkChild]
     private Gtk.Box message_area;
 
@@ -465,12 +471,11 @@ public class ComposerWidget : Gtk.EventBox {
         this.bcc_entry.changed.connect(validate_send_button);
         this.reply_to_entry.changed.connect(validate_send_button);
         this.editor.context_menu.connect(on_context_menu);
+        this.editor.command_stack_changed.connect(on_command_state_changed);
         this.editor.load_changed.connect(on_load_changed);
         this.editor.mouse_target_changed.connect(on_mouse_target_changed);
         this.editor.get_editor_state().notify["typing-attributes"].connect(on_typing_attributes_changed);
         // this.editor.move_focus.connect(update_actions);
-        // this.editor.undo.connect(update_actions);
-        // this.editor.redo.connect(update_actions);
         this.editor.selection_changed.connect(on_selection_changed);
         this.editor.key_press_event.connect(on_editor_key_press);
         //this.editor.user_changed_contents.connect(reset_draft_timer);
@@ -554,6 +559,8 @@ public class ComposerWidget : Gtk.EventBox {
         this.header.insert_action_group("cmh", this.actions);
 
         update_actions();
+        get_action(ACTION_UNDO).set_enabled(false);
+        get_action(ACTION_REDO).set_enabled(false);
     }
 
     /**
@@ -1033,7 +1040,7 @@ public class ComposerWidget : Gtk.EventBox {
     private bool can_save() {
         return this.draft_manager != null
             && this.draft_manager.is_open
-            && this.editor.can_undo()
+            && this.editor.is_empty
             && this.account.information.save_drafts;
     }
 
@@ -1614,6 +1621,14 @@ public class ComposerWidget : Gtk.EventBox {
         this.editor.execute_editing_command(action_name);
     }
 
+    private void on_undo(SimpleAction action, Variant? param) {
+        this.editor.undo();
+    }
+
+    private void on_redo(SimpleAction action, Variant? param) {
+        this.editor.redo();
+    }
+
     private void on_cut(SimpleAction action, Variant? param) {
         if (this.container.get_focus() == this.editor)
             this.editor.cut_clipboard();
@@ -1669,6 +1684,9 @@ public class ComposerWidget : Gtk.EventBox {
 
         foreach (string html_action in html_actions)
             get_action(html_action).set_enabled(compose_as_html);
+
+        this.insert_buttons.visible = compose_as_html;
+        this.font_style_buttons.visible = compose_as_html;
         this.remove_format_button.visible = compose_as_html;
 
         this.menu_button.menu_model = (compose_as_html) ? this.html_menu : this.plain_menu;
@@ -2215,6 +2233,11 @@ public class ComposerWidget : Gtk.EventBox {
         this.signature_html = account_sig;
     }
 
+    private void on_command_state_changed(bool can_undo, bool can_redo) {
+        get_action(ACTION_UNDO).set_enabled(can_undo);
+        get_action(ACTION_REDO).set_enabled(can_redo);
+    }
+
     private void on_selection_changed(bool has_selection) {
         get_action(ACTION_CUT).set_enabled(has_selection);
         get_action(ACTION_COPY).set_enabled(has_selection);
diff --git a/ui/composer-web-view.js b/ui/composer-web-view.js
index 3c7023e..62a648d 100644
--- a/ui/composer-web-view.js
+++ b/ui/composer-web-view.js
@@ -22,14 +22,26 @@ ComposerPageState.prototype = {
     init: function() {
         PageState.prototype.init.apply(this, []);
 
+        this.messageBody = null;
+
+        this.undoEnabled = false;
+        this.redoEnabled = false;
+
         let state = this;
+
         document.addEventListener("click", function(e) {
             if (e.target.tagName == "A") {
                 state.linkClicked(e.target);
             }
         }, true);
+
+        this.bodyObserver = new MutationObserver(function() {
+            state.checkCommandStack();
+        });
     },
     loaded: function() {
+        this.messageBody = document.getElementById(ComposerPageState.BODY_ID);
+
         // Search for and remove a particular styling when we quote
         // text. If that style exists in the quoted text, we alter it
         // slightly so we don't mess with it later.
@@ -58,17 +70,28 @@ ComposerPageState.prototype = {
             cursor.parentNode.removeChild(cursor);
         }
 
+        // Enable editing and observation machinery only after
+        // modifying the body above.
+        this.messageBody.contentEditable = true;
+        this.setBodyObserverEnabled(true);
+
         // Chain up here so we continue to a preferred size update
         // after munging the HTML above.
         PageState.prototype.loaded.apply(this, []);
     },
+    undo: function() {
+        document.execCommand("undo", false, null);
+        this.checkCommandStack();
+    },
+    redo: function() {
+        document.execCommand("redo", false, null);
+        this.checkCommandStack();
+    },
     getHtml: function() {
-        return document.getElementById(ComposerPageState.BODY_ID).innerHTML;
+        return this.messageBody.innerHTML;
     },
     getText: function() {
-        return ComposerPageState.htmlToQuotedText(
-            document.getElementById(ComposerPageState.BODY_ID)
-        );
+        return ComposerPageState.htmlToQuotedText(this.messageBody);
     },
     setRichText: function(enabled) {
         if (enabled) {
@@ -77,6 +100,36 @@ ComposerPageState.prototype = {
             document.body.classList.add("plain");
         }
     },
+    setBodyObserverEnabled: function(enabled) {
+        if (enabled) {
+            let config = {
+                attributes: true,
+                childList: true,
+                characterData: true,
+                subtree: true
+            };
+            this.bodyObserver.observe(this.messageBody, config);
+        } else {
+            this.bodyObserver.disconnect();
+        }
+    },
+    checkCommandStack: function() {
+        let canUndo = document.queryCommandEnabled("undo");
+        let canRedo = document.queryCommandEnabled("redo");
+
+        // Update the body observer - if we can undo we don't need to
+        // keep an eye on mutations any more, until we can't undo
+        // again.
+        this.setBodyObserverEnabled(!canUndo);
+
+        if (canUndo != this.undoEnabled || canRedo != this.redoEnabled) {
+            this.undoEnabled = canUndo;
+            this.redoEnabled = canRedo;
+            window.webkit.messageHandlers.commandStackChanged.postMessage(
+                this.undoEnabled + "," + this.redoEnabled
+            );
+        }
+    },
     undoBlockquoteStyle: function() {
         let nodeList = document.querySelectorAll(
             "blockquote[style=\"margin: 0 0 0 40px; border: none; padding: 0px;\"]"
diff --git a/ui/composer-widget.ui b/ui/composer-widget.ui
index 9461bea..df1bdba 100644
--- a/ui/composer-widget.ui
+++ b/ui/composer-widget.ui
@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
 <interface>
   <requires lib="gtk+" version="3.14"/>
   <template class="ComposerWidget" parent="GtkEventBox">
@@ -44,18 +45,17 @@
                     <property name="margin_start">6</property>
                     <property name="margin_end">6</property>
                     <property name="margin_top">6</property>
-                    <property name="row_spacing">0</property>
                     <property name="column_spacing">6</property>
                     <child>
                       <object class="GtkLabel" id="to_label">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="halign">end</property>
+                        <property name="margin_top">6</property>
                         <property name="label" translatable="yes" comments="Address(es) e-mail is to be sent 
to">_To</property>
                         <property name="use_underline">True</property>
                         <property name="justify">right</property>
                         <property name="mnemonic_widget">to_box</property>
-                        <property name="margin_top">6</property>
                         <style>
                           <class name="dim-label"/>
                         </style>
@@ -63,8 +63,6 @@
                       <packing>
                         <property name="left_attach">0</property>
                         <property name="top_attach">1</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
                       </packing>
                     </child>
                     <child>
@@ -72,11 +70,11 @@
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="halign">end</property>
+                        <property name="margin_top">6</property>
                         <property name="label" translatable="yes">_Cc</property>
                         <property name="use_underline">True</property>
                         <property name="justify">right</property>
                         <property name="mnemonic_widget">to_box</property>
-                        <property name="margin_top">6</property>
                         <style>
                           <class name="dim-label"/>
                         </style>
@@ -84,8 +82,6 @@
                       <packing>
                         <property name="left_attach">0</property>
                         <property name="top_attach">2</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
                       </packing>
                     </child>
                     <child>
@@ -97,8 +93,6 @@
                       <packing>
                         <property name="left_attach">1</property>
                         <property name="top_attach">1</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
                       </packing>
                     </child>
                     <child>
@@ -110,25 +104,20 @@
                       <packing>
                         <property name="left_attach">1</property>
                         <property name="top_attach">2</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
                       </packing>
                     </child>
                     <child>
                       <object class="GtkEntry" id="subject_entry">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
+                        <property name="margin_top">6</property>
                         <property name="hexpand">True</property>
                         <property name="invisible_char">•</property>
-                        <property name="invisible_char_set">True</property>
-                        <property name="margin_top">6</property>
                         <signal name="changed" handler="on_subject_changed" swapped="no"/>
                       </object>
                       <packing>
                         <property name="left_attach">1</property>
                         <property name="top_attach">5</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
                       </packing>
                     </child>
                     <child>
@@ -136,11 +125,11 @@
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="halign">end</property>
+                        <property name="margin_top">6</property>
                         <property name="label" translatable="yes">_Subject</property>
                         <property name="use_underline">True</property>
                         <property name="justify">right</property>
                         <property name="mnemonic_widget">subject_entry</property>
-                        <property name="margin_top">6</property>
                         <style>
                           <class name="dim-label"/>
                         </style>
@@ -148,8 +137,6 @@
                       <packing>
                         <property name="left_attach">0</property>
                         <property name="top_attach">5</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
                       </packing>
                     </child>
                     <child>
@@ -157,11 +144,11 @@
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="halign">end</property>
+                        <property name="margin_top">6</property>
                         <property name="label" translatable="yes">_Bcc</property>
                         <property name="use_underline">True</property>
                         <property name="justify">right</property>
                         <property name="mnemonic_widget">to_box</property>
-                        <property name="margin_top">6</property>
                         <style>
                           <class name="dim-label"/>
                         </style>
@@ -169,8 +156,6 @@
                       <packing>
                         <property name="left_attach">0</property>
                         <property name="top_attach">3</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
                       </packing>
                     </child>
                     <child>
@@ -182,8 +167,6 @@
                       <packing>
                         <property name="left_attach">1</property>
                         <property name="top_attach">3</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
                       </packing>
                     </child>
                     <child>
@@ -191,11 +174,11 @@
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="halign">end</property>
+                        <property name="margin_top">6</property>
                         <property name="label" translatable="yes">_Reply-To</property>
                         <property name="use_underline">True</property>
                         <property name="justify">right</property>
                         <property name="mnemonic_widget">to_box</property>
-                        <property name="margin_top">6</property>
                         <style>
                           <class name="dim-label"/>
                         </style>
@@ -203,8 +186,6 @@
                       <packing>
                         <property name="left_attach">0</property>
                         <property name="top_attach">4</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
                       </packing>
                     </child>
                     <child>
@@ -216,8 +197,6 @@
                       <packing>
                         <property name="left_attach">1</property>
                         <property name="top_attach">4</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
                       </packing>
                     </child>
                     <child>
@@ -225,8 +204,8 @@
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="halign">end</property>
-                        <property name="use_underline">True</property>
                         <property name="label" translatable="yes" comments="Geary account mail will be sent 
from">From</property>
+                        <property name="use_underline">True</property>
                         <property name="justify">right</property>
                         <property name="mnemonic_widget">to_box</property>
                         <style>
@@ -236,8 +215,6 @@
                       <packing>
                         <property name="left_attach">0</property>
                         <property name="top_attach">0</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
                       </packing>
                     </child>
                     <child>
@@ -261,8 +238,6 @@
                           <object class="GtkComboBoxText" id="from_multiple">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
-                            <property name="entry_text_column">0</property>
-                            <property name="id_column">1</property>
                           </object>
                           <packing>
                             <property name="expand">False</property>
@@ -274,8 +249,6 @@
                       <packing>
                         <property name="left_attach">1</property>
                         <property name="top_attach">0</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
                       </packing>
                     </child>
                   </object>
@@ -289,6 +262,7 @@
               <packing>
                 <property name="expand">True</property>
                 <property name="fill">True</property>
+                <property name="position">0</property>
               </packing>
             </child>
           </object>
@@ -342,6 +316,7 @@
               <packing>
                 <property name="expand">True</property>
                 <property name="fill">True</property>
+                <property name="position">0</property>
               </packing>
             </child>
           </object>
@@ -354,144 +329,249 @@
         <child>
           <object class="GtkBox" id="composer_toolbar">
             <property name="visible">True</property>
-            <property name="orientation">horizontal</property>
             <property name="can_focus">False</property>
             <property name="margin_start">6</property>
             <property name="margin_end">6</property>
             <property name="spacing">6</property>
             <child>
-              <object class="GtkBox" id="font_style_buttons">
+              <object class="GtkBox" id="command_buttons">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkButton">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="focus_on_click">False</property>
+                    <property name="receives_default">False</property>
+                    <property name="tooltip_text" translatable="yes">Undo last edit (Ctrl+Z)</property>
+                    <property name="action_name">cmp.undo</property>
+                    <property name="always_show_image">True</property>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="can_focus">False</property>
+                        <property name="pixel_size">16</property>
+                        <property name="icon_name">edit-undo-symbolic</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="focus_on_click">False</property>
+                    <property name="receives_default">False</property>
+                    <property name="tooltip_text" translatable="yes">Redo last edit  
(Ctrl+Shift+Z)</property>
+                    <property name="action_name">cmp.redo</property>
+                    <property name="always_show_image">True</property>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="can_focus">False</property>
+                        <property name="pixel_size">16</property>
+                        <property name="icon_name">edit-redo-symbolic</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
                 <style>
                   <class name="linked"/>
                 </style>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="font_style_buttons">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
                 <child>
                   <object class="GtkToggleButton" id="bold_button">
-                    <property name="visible" bind-source="bold_button" bind-property="sensitive" />
-                    <property name="always_show_image">True</property>
-                    <property name="action_name">cmp.bold</property>
                     <property name="can_focus">True</property>
                     <property name="focus_on_click">False</property>
+                    <property name="receives_default">False</property>
                     <property name="tooltip_text" translatable="yes">Bold (Ctrl+B)</property>
+                    <property name="action_name">cmp.bold</property>
+                    <property name="always_show_image">True</property>
                     <child>
                       <object class="GtkImage" id="bold_image">
+                        <property name="can_focus">False</property>
+                        <property name="pixel_size">16</property>
                         <property name="icon_name">format-text-bold-symbolic</property>
-                        <property name="pixel-size">16</property>
                       </object>
                     </child>
                   </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
                 </child>
                 <child>
                   <object class="GtkToggleButton" id="italics_button">
-                    <property name="visible" bind-source="italics_button" bind-property="sensitive" />
                     <property name="can_focus">True</property>
                     <property name="focus_on_click">False</property>
+                    <property name="receives_default">False</property>
+                    <property name="tooltip_text" translatable="yes">Italic (Ctrl+I)</property>
                     <property name="action_name">cmp.italic</property>
                     <property name="always_show_image">True</property>
-                    <property name="tooltip_text" translatable="yes">Italic (Ctrl+I)</property>
                     <child>
                       <object class="GtkImage" id="italics_image">
+                        <property name="can_focus">False</property>
+                        <property name="pixel_size">16</property>
                         <property name="icon_name">format-text-italic-symbolic</property>
-                        <property name="pixel-size">16</property>
                       </object>
                     </child>
                   </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
                 </child>
                 <child>
                   <object class="GtkToggleButton" id="underline_button">
-                    <property name="visible" bind-source="underline_button" bind-property="sensitive" />
                     <property name="can_focus">True</property>
                     <property name="focus_on_click">False</property>
+                    <property name="receives_default">False</property>
+                    <property name="tooltip_text" translatable="yes">Underline (Ctrl+U)</property>
                     <property name="action_name">cmp.underline</property>
                     <property name="always_show_image">True</property>
-                    <property name="tooltip_text" translatable="yes">Underline (Ctrl+U)</property>
                     <child>
                       <object class="GtkImage" id="underline_image">
+                        <property name="can_focus">False</property>
+                        <property name="pixel_size">16</property>
                         <property name="icon_name">format-text-underline-symbolic</property>
-                        <property name="pixel-size">16</property>
                       </object>
                     </child>
                   </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
                 </child>
                 <child>
                   <object class="GtkToggleButton" id="strikethrough_button">
-                    <property name="visible" bind-source="strikethrough_button" bind-property="sensitive" />
                     <property name="can_focus">True</property>
                     <property name="focus_on_click">False</property>
+                    <property name="receives_default">False</property>
+                    <property name="tooltip_text" translatable="yes">Strikethrough (Ctrl+K)</property>
                     <property name="action_name">cmp.strikethrough</property>
                     <property name="always_show_image">True</property>
-                    <property name="tooltip_text" translatable="yes">Strikethrough (Ctrl+K)</property>
                     <child>
                       <object class="GtkImage" id="strikethrough_image">
+                        <property name="can_focus">False</property>
+                        <property name="pixel_size">16</property>
                         <property name="icon_name">format-text-strikethrough-symbolic</property>
-                        <property name="pixel-size">16</property>
                       </object>
                     </child>
                   </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">3</property>
+                  </packing>
                 </child>
+                <style>
+                  <class name="linked"/>
+                </style>
               </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
             </child>
             <child>
               <object class="GtkBox" id="indentation_buttons">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <style>
-                  <class name="linked"/>
-                </style>
                 <child>
                   <object class="GtkButton" id="indent_button">
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="focus_on_click">False</property>
+                    <property name="receives_default">False</property>
+                    <property name="tooltip_text" translatable="yes">Quote text  (Ctrl+])</property>
                     <property name="action_name">cmp.indent</property>
                     <property name="always_show_image">True</property>
-                    <property name="tooltip_text" translatable="yes">Quote text  (Ctrl+])</property>
                     <child>
                       <object class="GtkImage" id="indent_image">
+                        <property name="can_focus">False</property>
+                        <property name="pixel_size">16</property>
                         <property name="icon_name">format-indent-more-symbolic</property>
-                        <property name="pixel-size">16</property>
                       </object>
                     </child>
                   </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
                 </child>
                 <child>
                   <object class="GtkButton" id="outdent_button">
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="focus_on_click">False</property>
+                    <property name="receives_default">False</property>
+                    <property name="tooltip_text" translatable="yes">Unquote text  (Ctrl+[)</property>
                     <property name="action_name">cmp.outdent</property>
                     <property name="always_show_image">True</property>
-                    <property name="tooltip_text" translatable="yes">Unquote text  (Ctrl+[)</property>
                     <child>
                       <object class="GtkImage" id="outdent_image">
+                        <property name="can_focus">False</property>
+                        <property name="pixel_size">16</property>
                         <property name="icon_name">format-indent-less-symbolic</property>
-                        <property name="pixel-size">16</property>
                       </object>
                     </child>
                   </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
                 </child>
+                <style>
+                  <class name="linked"/>
+                </style>
               </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
             </child>
             <child>
               <object class="GtkBox" id="insert_buttons">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <style>
-                  <class name="linked"/>
-                </style>
                 <child>
                   <object class="GtkButton" id="insert_link_button">
-                    <property name="visible" bind-source="insert_link_button" bind-property="sensitive" />
                     <property name="can_focus">True</property>
                     <property name="focus_on_click">False</property>
+                    <property name="receives_default">False</property>
+                    <property name="tooltip_text" translatable="yes">Link (Ctrl+L)</property>
                     <property name="action_name">cmp.insert-link</property>
                     <property name="always_show_image">True</property>
-                    <property name="tooltip_text" translatable="yes">Link (Ctrl+L)</property>
                     <child>
                       <object class="GtkImage" id="insert_link_image">
+                        <property name="can_focus">False</property>
+                        <property name="pixel_size">16</property>
                         <property name="icon_name">insert-link-symbolic</property>
-                        <property name="pixel-size">16</property>
                       </object>
                     </child>
                   </object>
@@ -503,7 +583,6 @@
                 </child>
                 <child>
                   <object class="GtkButton" id="insert_image_button">
-                    <property name="visible" bind-source="insert_image_button" bind-property="sensitive" />
                     <property name="can_focus">True</property>
                     <property name="focus_on_click">False</property>
                     <property name="receives_default">False</property>
@@ -524,48 +603,77 @@
                     <property name="position">1</property>
                   </packing>
                 </child>
+                <style>
+                  <class name="linked"/>
+                </style>
               </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">3</property>
+              </packing>
             </child>
             <child>
               <object class="GtkButton" id="remove_format_button">
                 <property name="visible">True</property>
-                <property name="always_show_image">True</property>
-                <property name="action_name">cmp.remove-format</property>
                 <property name="can_focus">True</property>
                 <property name="focus_on_click">False</property>
+                <property name="receives_default">False</property>
                 <property name="tooltip_text" translatable="yes">Remove formatting (Ctrl+Space)</property>
+                <property name="action_name">cmp.remove-format</property>
+                <property name="always_show_image">True</property>
                 <child>
                   <object class="GtkImage" id="remove_format_image">
+                    <property name="can_focus">False</property>
+                    <property name="pixel_size">16</property>
                     <property name="icon_name">format-text-remove-symbolic</property>
-                    <property name="pixel-size">16</property>
                   </object>
                 </child>
               </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">4</property>
+              </packing>
             </child>
             <child>
               <object class="GtkButton" id="select_dictionary_button">
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="focus_on_click">False</property>
+                <property name="receives_default">False</property>
+                <property name="tooltip_text" translatable="yes">Select spell checking language</property>
                 <property name="action_name">cmp.select-dictionary</property>
                 <property name="always_show_image">True</property>
-                <property name="tooltip_text" translatable="yes">Select spell checking language</property>
                 <child>
                   <object class="GtkImage" id="select_dictionary_image">
+                    <property name="can_focus">False</property>
+                    <property name="pixel_size">16</property>
                     <property name="icon_name">accessories-dictionary-symbolic</property>
-                    <property name="pixel-size">16</property>
                   </object>
                 </child>
               </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">5</property>
+              </packing>
             </child>
             <child>
               <object class="GtkMenuButton" id="menu_button">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
                 <property name="focus_on_click">False</property>
+                <property name="receives_default">False</property>
+                <child>
+                  <placeholder/>
+                </child>
               </object>
               <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
                 <property name="pack_type">end</property>
+                <property name="position">5</property>
               </packing>
             </child>
             <child>
@@ -577,7 +685,10 @@
                 </style>
               </object>
               <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
                 <property name="pack_type">end</property>
+                <property name="position">6</property>
               </packing>
             </child>
           </object>
@@ -591,6 +702,7 @@
           <object class="GtkFrame">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
+            <property name="label_xalign">0</property>
             <property name="shadow_type">in</property>
             <child>
               <object class="GtkBox" id="message_area">
@@ -598,19 +710,20 @@
                 <property name="can_focus">False</property>
                 <child>
                   <object class="GtkOverlay" id="message_overlay">
-                  <property name="visible">True</property>
-                  <property name="can_focus">False</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
                     <child>
                       <object class="GtkScrolledWindow" id="editor_scrolled">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
-                        <property name="hscrollbar_policy">automatic</property>
-                        <property name="vscrollbar_policy">automatic</property>
                         <property name="min_content_height">200</property>
                         <child>
-                          <placeholder />
+                          <placeholder/>
                         </child>
                       </object>
+                      <packing>
+                        <property name="index">-1</property>
+                      </packing>
                     </child>
                     <child type="overlay">
                       <object class="GtkLabel" id="message_overlay_label">
@@ -626,6 +739,7 @@
                   <packing>
                     <property name="expand">True</property>
                     <property name="fill">True</property>
+                    <property name="position">0</property>
                   </packing>
                 </child>
               </object>



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