]> spindle.queued.net Git - midori/commitdiff
Add a new option to change behavior when closing a tab
authorAndré Stösel <andre@stoesel.de>
Wed, 8 Jun 2011 18:19:02 +0000 (20:19 +0200)
committerChristian Dywan <christian@twotoasts.de>
Wed, 8 Jun 2011 18:24:25 +0000 (20:24 +0200)
extensions/history-list.vala

index acacae11b0f43c103ce0ef7f6d3d3e1ad2f29777..e8d96b5ea4c6e2f511ed92745c24d832d9f1a196 100644 (file)
@@ -14,361 +14,508 @@ using Gdk;
 using WebKit;
 using Midori;
 
-enum TabTreeCells {
-    TREE_CELL_PIXBUF,
-    TREE_CELL_STRING,
-    TREE_CELL_POINTER,
-    TREE_CELL_COUNT
-}
+namespace HistoryList {
+    enum TabTreeCells {
+        TREE_CELL_PIXBUF,
+        TREE_CELL_STRING,
+        TREE_CELL_POINTER,
+        TREE_CELL_COUNT
+    }
 
-private abstract class HistoryWindow : Gtk.Window {
-    public Midori.Browser browser { get; construct set; }
-    protected Gtk.TreeView? treeview = null;
-    public HistoryWindow (Midori.Browser browser) {
-        GLib.Object (type: Gtk.WindowType.POPUP,
-                     window_position: Gtk.WindowPosition.CENTER,
-                     browser: browser);
+    enum TabClosingBehavior {
+        NONE,
+        LAST,
+        NEW
     }
-    public virtual void walk (int step) {
-        Gtk.TreePath? path;
-        Gtk.TreeViewColumn? column;
 
-        this.treeview.get_cursor (out path, out column);
+    enum TabClosingBehaviorModel {
+        TEXT,
+        VALUE
+    }
 
-        unowned int[] indices = path.get_indices ();
-        int new_index = indices[0] + step;
+    private abstract class HistoryWindow : Gtk.Window {
+        public Midori.Browser browser { get; construct set; }
+        protected Gtk.TreeView? treeview = null;
 
-        var model = this.treeview.get_model () as Gtk.ListStore;
+        public HistoryWindow (Midori.Browser browser) {
+            GLib.Object (type: Gtk.WindowType.POPUP,
+                         window_position: Gtk.WindowPosition.CENTER,
+                         browser: browser);
+        }
 
-        while (new_index < 0 || new_index >= model.length)
-            new_index = new_index < 0 ? model.length + new_index : new_index - model.length;
+        public virtual void walk (int step) {
+            Gtk.TreePath? path;
+            Gtk.TreeViewColumn? column;
 
-        path = new Gtk.TreePath.from_indices (new_index);
-        this.treeview.set_cursor (path, column, false);
-    }
-    public abstract void make_update ();
-}
+            this.treeview.get_cursor (out path, out column);
 
-private class TabWindow : HistoryWindow {
-    protected Gtk.HBox? hbox;
-    protected Gtk.VBox? vbox;
-    protected void store_append_row (GLib.PtrArray list, Gtk.ListStore store, out Gtk.TreeIter iter) {
-        for (var i = list.len; i > 0; i--) {
-            Midori.View view = list.index (i - 1) as Midori.View;
+            unowned int[] indices = path.get_indices ();
+            int new_index = indices[0] + step;
 
-            Gdk.Pixbuf? icon = null;
-            view.get ("icon", ref icon);
+            var model = this.treeview.get_model () as Gtk.ListStore;
 
-            unowned string title = view.get_display_title ();
+            while (new_index < 0 || new_index >= model.length)
+                new_index = new_index < 0 ? model.length + new_index : new_index - model.length;
 
-            store.append (out iter);
-            store.set (iter, TabTreeCells.TREE_CELL_PIXBUF, icon,
-                             TabTreeCells.TREE_CELL_STRING, title,
-                             TabTreeCells.TREE_CELL_POINTER, view);
+            path = new Gtk.TreePath.from_indices (new_index);
+            this.treeview.set_cursor (path, column, false);
         }
+
+        public abstract void make_update ();
     }
-    protected virtual void insert_rows (Gtk.ListStore store) {
-        Gtk.TreeIter iter;
-        unowned GLib.PtrArray list = this.browser.get_data<GLib.PtrArray> ("history-list-tab-history");
-        unowned GLib.PtrArray list_new = this.browser.get_data<GLib.PtrArray> ("history-list-tab-history-new");
-        store_append_row (list, store, out iter);
-        store_append_row (list_new, store, out iter);
-    }
-    public TabWindow (Midori.Browser browser) {
-        base (browser);
 
-        this.vbox = new Gtk.VBox (false, 1);
-        this.add (this.vbox);
+    private class TabWindow : HistoryWindow {
+        protected Gtk.HBox? hbox;
+        protected Gtk.VBox? vbox;
+
+        protected void store_append_row (GLib.PtrArray list, Gtk.ListStore store, out Gtk.TreeIter iter) {
+            for (var i = list.len; i > 0; i--) {
+                Midori.View view = list.index (i - 1) as Midori.View;
+
+                Gdk.Pixbuf? icon = null;
+                view.get ("icon", ref icon);
+
+                unowned string title = view.get_display_title ();
+
+                store.append (out iter);
+                store.set (iter, TabTreeCells.TREE_CELL_PIXBUF, icon,
+                                 TabTreeCells.TREE_CELL_STRING, title,
+                                 TabTreeCells.TREE_CELL_POINTER, view);
+            }
+        }
+
+        protected virtual void insert_rows (Gtk.ListStore store) {
+            Gtk.TreeIter iter;
+            unowned GLib.PtrArray list = this.browser.get_data<GLib.PtrArray> ("history-list-tab-history");
+            unowned GLib.PtrArray list_new = this.browser.get_data<GLib.PtrArray> ("history-list-tab-history-new");
+            store_append_row (list, store, out iter);
+            store_append_row (list_new, store, out iter);
+        }
+
+        public TabWindow (Midori.Browser browser) {
+            base (browser);
 
-        this.hbox = new Gtk.HBox (false, 1);
+            this.vbox = new Gtk.VBox (false, 1);
+            this.add (this.vbox);
 
-        var sw = new Gtk.ScrolledWindow (null, null);
-        sw.set_policy (PolicyType.NEVER , PolicyType.AUTOMATIC);
-        sw.set_shadow_type (ShadowType.ETCHED_IN);
-        this.hbox.pack_start (sw, true, true, 0);
+            this.hbox = new Gtk.HBox (false, 1);
 
-        var store = new Gtk.ListStore (TabTreeCells.TREE_CELL_COUNT,
-            typeof (Gdk.Pixbuf), typeof (string), typeof (void*));
+            var sw = new Gtk.ScrolledWindow (null, null);
+            sw.set_policy (PolicyType.NEVER , PolicyType.AUTOMATIC);
+            sw.set_shadow_type (ShadowType.ETCHED_IN);
+            this.hbox.pack_start (sw, true, true, 0);
 
-        this.insert_rows (store);
+            var store = new Gtk.ListStore (TabTreeCells.TREE_CELL_COUNT,
+                typeof (Gdk.Pixbuf), typeof (string), typeof (void*));
 
-        this.vbox.pack_start (this.hbox, true, true, 0);
+            this.insert_rows (store);
 
-        this.treeview = new Gtk.TreeView.with_model (store);
-        this.treeview.set_fixed_height_mode (true);
-        sw.add (treeview);
+            this.vbox.pack_start (this.hbox, true, true, 0);
 
-        this.treeview.set_model (store);
-        this.treeview.set ("headers-visible", false);
+            this.treeview = new Gtk.TreeView.with_model (store);
+            this.treeview.set_fixed_height_mode (true);
+            sw.add (treeview);
 
-        this.treeview.insert_column_with_attributes (
-            TabTreeCells.TREE_CELL_PIXBUF, "Icon",
-            new CellRendererPixbuf (), "pixbuf", 0);
-        this.treeview.insert_column_with_attributes (
-            TabTreeCells.TREE_CELL_STRING, "Title",
-            new CellRendererText (), "text", 1);
+            this.treeview.set_model (store);
+            this.treeview.set ("headers-visible", false);
 
-        Requisition requisition;
-        int height;
-        int max_lines = 10;
-        this.treeview.size_request (out requisition);
-        if (store.length > max_lines) {
-            height = requisition.height / store.length * max_lines + 2;
-        } else {
-            height = requisition.height + 2;
+            this.treeview.insert_column_with_attributes (
+                TabTreeCells.TREE_CELL_PIXBUF, "Icon",
+                new CellRendererPixbuf (), "pixbuf", 0);
+            this.treeview.insert_column_with_attributes (
+                TabTreeCells.TREE_CELL_STRING, "Title",
+                new CellRendererText (), "text", 1);
+
+            Requisition requisition;
+            int height;
+            int max_lines = 10;
+            this.treeview.size_request (out requisition);
+            if (store.length > max_lines) {
+                height = requisition.height / store.length * max_lines + 2;
+            } else {
+                height = requisition.height + 2;
+            }
+            sw.set_size_request (320, height);
+
+            this.show_all ();
         }
-        sw.set_size_request (320, height);
 
-        this.show_all ();
-    }
-    public override void make_update () {
-        Gtk.TreePath? path;
-        Gtk.TreeViewColumn? column;
+        public override void make_update () {
+            Gtk.TreePath? path;
+            Gtk.TreeViewColumn? column;
 
-        this.treeview.get_cursor (out path, out column);
+            this.treeview.get_cursor (out path, out column);
 
-        var model = this.treeview.get_model () as Gtk.ListStore;
+            var model = this.treeview.get_model () as Gtk.ListStore;
 
-        Gtk.TreeIter iter;
-        unowned Midori.View? view = null;
+            Gtk.TreeIter iter;
+            unowned Midori.View? view = null;
 
-        model.get_iter (out iter, path);
-        model.get (iter, TabTreeCells.TREE_CELL_POINTER, out view);
-        this.browser.set ("tab", view);
+            model.get_iter (out iter, path);
+            model.get (iter, TabTreeCells.TREE_CELL_POINTER, out view);
+            this.browser.set ("tab", view);
+        }
     }
-}
 
-private class NewTabWindow : TabWindow {
-    protected bool first_step = true;
-    protected override void insert_rows (Gtk.ListStore store) {
-        Gtk.TreeIter iter;
-        unowned GLib.PtrArray list = this.browser.get_data<GLib.PtrArray> ("history-list-tab-history-new");
-        store_append_row (list, store, out iter);
-
-        if ((int)list.len == 0) {
-            var label = new Gtk.Label (_("There are no unvisited tabs"));
-            this.vbox.pack_start (label, true, true, 0);
-            unowned GLib.PtrArray list_old = this.browser.get_data<GLib.PtrArray> ("history-list-tab-history");
-            store_append_row (list_old, store, out iter);
+    private class NewTabWindow : TabWindow {
+        protected bool first_step = true;
+
+        protected override void insert_rows (Gtk.ListStore store) {
+            Gtk.TreeIter iter;
+            unowned GLib.PtrArray list = this.browser.get_data<GLib.PtrArray> ("history-list-tab-history-new");
+            store_append_row (list, store, out iter);
+
+            if ((int)list.len == 0) {
+                var label = new Gtk.Label (_("There are no unvisited tabs"));
+                this.vbox.pack_start (label, true, true, 0);
+                unowned GLib.PtrArray list_old = this.browser.get_data<GLib.PtrArray> ("history-list-tab-history");
+                store_append_row (list_old, store, out iter);
+            }
         }
-    }
-    public override void walk (int step) {
-        if (this.first_step == false || step != 1) {
-            base.walk (step);
+
+        public override void walk (int step) {
+            if (this.first_step == false || step != 1) {
+                base.walk (step);
+            }
+            this.first_step = false;
         }
-        this.first_step = false;
-    }
-    public NewTabWindow (Midori.Browser browser) {
-        base (browser);
-    }
-}
 
-private class HistoryList : Midori.Extension {
-    protected uint escKeyval;
-    protected uint modifier_count;
-    protected HistoryWindow? history_window;
-    protected ulong[] tmp_sig_ids = new ulong[2];
-    public bool key_press (Gdk.EventKey event_key) {
-        if (event_key.is_modifier > 0) {
-            this.modifier_count++;
+        public NewTabWindow (Midori.Browser browser) {
+            base (browser);
         }
-        return false;
     }
-    public bool key_release (Gdk.EventKey event_key, Browser browser) {
-        if (event_key.is_modifier > 0) {
-            this.modifier_count--;
+
+    private class PreferencesDialog : Dialog {
+        protected Manager hl_manager;
+        protected ComboBox closing_behavior;
+
+        public PreferencesDialog (Manager manager) {
+            this.hl_manager = manager;
+
+            this.title = _("Preferences for %s").printf( _("History-List"));
+            this.has_separator = false;
+            this.border_width = 5;
+            this.set_modal (true);
+            this.set_default_size (350, 100);
+            this.create_widgets ();
+
+            this.response.connect (response_cb);
         }
-        if (this.modifier_count == 0 || event_key.keyval == this.escKeyval) {
-            browser.disconnect (this.tmp_sig_ids[0]);
-            browser.disconnect (this.tmp_sig_ids[1]);
-            if (this.modifier_count == 0) {
-                this.history_window.make_update ();
-            } else {
-                this.modifier_count = 0;
+
+        private void response_cb (Dialog source, int response_id) {
+            switch (response_id) {
+                case ResponseType.APPLY:
+                    int value;
+                    TreeIter iter;
+
+                    this.closing_behavior.get_active_iter (out iter);
+                    var model = this.closing_behavior.get_model ();
+                    model.get (iter, TabClosingBehaviorModel.VALUE, out value);
+
+                    this.hl_manager.set_integer ("TabClosingBehavior", value);
+                    this.hl_manager.preferences_changed ();
+
+                    this.destroy ();
+                    break;
+                case ResponseType.CANCEL:
+                    this.destroy ();
+                    break;
             }
-            this.history_window.destroy ();
-            this.history_window = null;
         }
-        return false;
+
+        private void create_widgets () {
+            ListStore model;
+            TreeIter iter;
+            TreeIter? active_iter = null;
+
+            var table = new Table (1, 2, true);
+            var renderer = new CellRendererText ();
+
+            var label = new Label ( _("Tab closing behavior"));
+            table.attach_defaults (label, 0, 1, 0, 1);
+
+            var tab_closing_behavior = this.hl_manager.get_integer ("TabClosingBehavior");
+
+            model = new ListStore (2, typeof (string), typeof (int));
+
+            model.append (out iter);
+            model.set (iter, TabClosingBehaviorModel.TEXT, _("Do nothing"),
+                             TabClosingBehaviorModel.VALUE, TabClosingBehavior.NONE);
+            if (TabClosingBehavior.NONE == tab_closing_behavior)
+                active_iter = iter;
+
+            model.append (out iter);
+            model.set (iter, TabClosingBehaviorModel.TEXT, _("Switch to last view tab"),
+                             TabClosingBehaviorModel.VALUE, TabClosingBehavior.LAST);
+            if (TabClosingBehavior.LAST == tab_closing_behavior)
+                active_iter = iter;
+
+            model.append (out iter);
+            model.set (iter, TabClosingBehaviorModel.TEXT, _("Switch to newest tab"),
+                             TabClosingBehaviorModel.VALUE, TabClosingBehavior.NEW);
+            if (TabClosingBehavior.NEW == tab_closing_behavior)
+                active_iter = iter;
+
+            this.closing_behavior = new ComboBox.with_model (model);
+            this.closing_behavior.set_active_iter (active_iter);
+            this.closing_behavior.pack_start (renderer, true);
+            this.closing_behavior.set_attributes (renderer, "text", 0);
+
+            table.attach_defaults (this.closing_behavior, 1, 2, 0, 1);
+
+            this.vbox.pack_start (table, false, true, 0);
+
+            this.add_button (Gtk.STOCK_CANCEL, ResponseType.CANCEL);
+            this.add_button (Gtk.STOCK_APPLY, ResponseType.APPLY);
+
+            this.show_all ();
+        }
     }
-    public void walk (Gtk.Action action, Browser browser, Type type, int step) {
-        Midori.View? view = null;
-        view = browser.get_data<Midori.View?> ("history-list-last-change");
-        if (view != null) {
-            this.tab_list_resort (browser, view);
-            browser.set_data<Midori.View?> ("history-list-last-change", null);
+
+    private class Manager : Midori.Extension {
+        public signal  void preferences_changed ();
+
+        protected uint escKeyval;
+        protected uint modifier_count;
+        protected int closing_behavior;
+        protected HistoryWindow? history_window;
+        protected ulong[] tmp_sig_ids = new ulong[2];
+
+        public void preferences_changed_cb () {
+            this.closing_behavior = this.get_integer ("TabClosingBehavior");
         }
 
-        if (this.history_window == null || this.history_window.get_type () != type) {
-            if (this.history_window == null) {
-                this.modifier_count = Midori.Sokoke.gtk_action_count_modifiers (action);
-                this.tmp_sig_ids[0] = browser.key_press_event.connect ((ek) => {
-                    return this.key_press (ek);
-                });
-                this.tmp_sig_ids[1] = browser.key_release_event.connect ((ek) => {
-                    return this.key_release (ek, browser);
-                });
-            } else {
+        public bool key_press (Gdk.EventKey event_key) {
+            if (event_key.is_modifier > 0) {
+                this.modifier_count++;
+            }
+            return false;
+        }
+
+        public bool key_release (Gdk.EventKey event_key, Browser browser) {
+            if (event_key.is_modifier > 0) {
+                this.modifier_count--;
+            }
+            if (this.modifier_count == 0 || event_key.keyval == this.escKeyval) {
+                browser.disconnect (this.tmp_sig_ids[0]);
+                browser.disconnect (this.tmp_sig_ids[1]);
+                if (this.modifier_count == 0) {
+                    this.history_window.make_update ();
+                } else {
+                    this.modifier_count = 0;
+                }
                 this.history_window.destroy ();
                 this.history_window = null;
             }
-            /*
-                Bug:  https://bugzilla.gnome.org/show_bug.cgi?id=618750
-                Code: this.history_window = (Gtk.Window) GLib.Object.new (type);
-            */
-            if (type == typeof (TabWindow)) {
-                this.history_window = new TabWindow (browser);
-            } else if (type == typeof (NewTabWindow)) {
-                this.history_window = new NewTabWindow (browser);
+            return false;
+        }
+
+        public void walk (Gtk.Action action, Browser browser, Type type, int step) {
+            Midori.View? view = null;
+            view = browser.get_data<Midori.View?> ("history-list-last-change");
+            if (view != null) {
+                this.tab_list_resort (browser, view);
+                browser.set_data<Midori.View?> ("history-list-last-change", null);
+            }
+
+            if (this.history_window == null || this.history_window.get_type () != type) {
+                if (this.history_window == null) {
+                    this.modifier_count = Midori.Sokoke.gtk_action_count_modifiers (action);
+                    this.tmp_sig_ids[0] = browser.key_press_event.connect ((ek) => {
+                        return this.key_press (ek);
+                    });
+                    this.tmp_sig_ids[1] = browser.key_release_event.connect ((ek) => {
+                        return this.key_release (ek, browser);
+                    });
+                } else {
+                    this.history_window.destroy ();
+                    this.history_window = null;
+                }
+                /*
+                    Bug:  https://bugzilla.gnome.org/show_bug.cgi?id=618750
+                    Code: this.history_window = (Gtk.Window) GLib.Object.new (type);
+                */
+                if (type == typeof (TabWindow)) {
+                    this.history_window = new TabWindow (browser);
+                } else if (type == typeof (NewTabWindow)) {
+                    this.history_window = new NewTabWindow (browser);
+                }
             }
+            var hw = this.history_window as HistoryWindow;
+            hw.walk (step);
         }
-        var hw = this.history_window as HistoryWindow;
-        hw.walk (step);
-    }
-    void browser_added (Midori.Browser browser) {
-        ulong sidTabNext, sidTabPrevious;
-        var acg = new Gtk.AccelGroup ();
-        browser.add_accel_group (acg);
-        var action_group = browser.get_action_group ();
-
-        Gtk.Action action;
-
-        action = action_group.get_action ("TabNext");
-        browser.block_action (action);
-        sidTabNext = action.activate.connect ((a) => {
-            this.walk (a, browser, typeof (TabWindow), 1);
-        });
-
-        action = action_group.get_action ("TabPrevious");
-        browser.block_action (action);
-        sidTabPrevious = action.activate.connect ((a) => {
-            this.walk (a, browser, typeof (TabWindow), -1);
-        });
-
-        action = new Gtk.Action ("HistoryListNextNewTab",
-            _("Next new Tab (History List)"),
-            _("Next new tab from history"), null);
-        action.activate.connect ((a) => {
-            this.walk (a, browser, typeof (NewTabWindow), 1);
-        });
-        action_group.add_action_with_accel (action, "<Ctrl>1");
-        action.set_accel_group (acg);
-        action.connect_accelerator ();
-
-        action = new Gtk.Action ("HistoryListPreviousNewTab",
-            _("Previous new Tab (History List)"),
-            _("Previous new tab from history"), null);
-        action.activate.connect ((a) => {
-            this.walk (a, browser, typeof (NewTabWindow), -1);
-        });
-        action_group.add_action_with_accel (action, "<Ctrl>2");
-        action.set_accel_group (acg);
-        action.connect_accelerator ();
-
-        browser.set_data<ulong> ("history-list-sid-tab-next", sidTabNext);
-        browser.set_data<ulong> ("history-list-sid-tab-previous", sidTabPrevious);
-
-        browser.set_data<GLib.PtrArray*> ("history-list-tab-history",
-                                          new GLib.PtrArray ());
-        browser.set_data<GLib.PtrArray*> ("history-list-tab-history-new",
-                                          new GLib.PtrArray ());
-        browser.set_data<Midori.View?> ("history-list-last-change", null);
-
-        foreach (var tab in browser.get_tabs ())
-            tab_added (browser, tab);
-        browser.add_tab.connect (tab_added);
-        browser.remove_tab.connect (tab_removed);
-        browser.notify["tab"].connect (this.tab_changed);
-    }
-    void browser_removed (Midori.Browser browser) {
-        string[] callbacks = { "HistoryListNextNewTab", "HistoryListPreviousNewTab" };
-        ulong sidTabNext, sidTabPrevious;
-        sidTabNext = browser.get_data<ulong> ("history-list-sid-tab-next");
-        sidTabPrevious = browser.get_data<ulong> ("history-list-sid-tab-previous");
-
-        Gtk.Action action;
-        Gtk.ActionGroup action_group;
-        action_group = browser.get_action_group ();
-
-        action = action_group.get_action ("TabNext");
-        action.disconnect (sidTabNext);
-        browser.unblock_action (action);
-        action = action_group.get_action ("TabPrevious");
-        action.disconnect (sidTabPrevious);
-        browser.unblock_action (action);
-
-        for (int i = 0; i < callbacks.length; i++) {
-            action = action_group.get_action (callbacks[i]);
-            if (action != null)
-                action_group.remove_action (action);
+
+        void browser_added (Midori.Browser browser) {
+            ulong sidTabNext, sidTabPrevious;
+            var acg = new Gtk.AccelGroup ();
+            browser.add_accel_group (acg);
+            var action_group = browser.get_action_group ();
+
+            Gtk.Action action;
+
+            action = action_group.get_action ("TabNext");
+            browser.block_action (action);
+            sidTabNext = action.activate.connect ((a) => {
+                this.walk (a, browser, typeof (TabWindow), 1);
+            });
+
+            action = action_group.get_action ("TabPrevious");
+            browser.block_action (action);
+            sidTabPrevious = action.activate.connect ((a) => {
+                this.walk (a, browser, typeof (TabWindow), -1);
+            });
+
+            action = new Gtk.Action ("HistoryListNextNewTab",
+                _("Next new Tab (History List)"),
+                _("Next new tab from history"), null);
+            action.activate.connect ((a) => {
+                this.walk (a, browser, typeof (NewTabWindow), 1);
+            });
+            action_group.add_action_with_accel (action, "<Ctrl>1");
+            action.set_accel_group (acg);
+            action.connect_accelerator ();
+
+            action = new Gtk.Action ("HistoryListPreviousNewTab",
+                _("Previous new Tab (History List)"),
+                _("Previous new tab from history"), null);
+            action.activate.connect ((a) => {
+                this.walk (a, browser, typeof (NewTabWindow), -1);
+            });
+            action_group.add_action_with_accel (action, "<Ctrl>2");
+            action.set_accel_group (acg);
+            action.connect_accelerator ();
+
+            browser.set_data<ulong> ("history-list-sid-tab-next", sidTabNext);
+            browser.set_data<ulong> ("history-list-sid-tab-previous", sidTabPrevious);
+
+            browser.set_data<GLib.PtrArray*> ("history-list-tab-history",
+                                              new GLib.PtrArray ());
+            browser.set_data<GLib.PtrArray*> ("history-list-tab-history-new",
+                                              new GLib.PtrArray ());
+            browser.set_data<Midori.View?> ("history-list-last-change", null);
+
+            foreach (var tab in browser.get_tabs ())
+                tab_added (browser, tab);
+            browser.add_tab.connect (tab_added);
+            browser.remove_tab.connect (tab_removed);
+            browser.notify["tab"].connect (this.tab_changed);
         }
 
-        browser.add_tab.disconnect (tab_added);
-        browser.remove_tab.disconnect (tab_removed);
-        browser.notify["tab"].disconnect (this.tab_changed);
-    }
-    void tab_added (Midori.Browser browser, Midori.View view) {
-        unowned GLib.PtrArray list = browser.get_data<GLib.PtrArray> ("history-list-tab-history-new");
-        list.add (view);
-    }
-    void tab_removed (Midori.Browser browser, Midori.View view) {
-        unowned GLib.PtrArray list = browser.get_data<GLib.PtrArray> ("history-list-tab-history");
-        unowned GLib.PtrArray list_new = browser.get_data<GLib.PtrArray> ("history-list-tab-history-new");
-        list.remove (view);
-        list_new.remove (view);
-        browser.set_data<Midori.View?> ("history-list-last-change", null);
-
-        if ((int) list.len > 0 || (int) list_new.len > 0) {
-            var hw = new TabWindow (browser);
-            hw.make_update ();
-            hw.destroy ();
+        void browser_removed (Midori.Browser browser) {
+            string[] callbacks = { "HistoryListNextNewTab", "HistoryListPreviousNewTab" };
+            ulong sidTabNext, sidTabPrevious;
+            sidTabNext = browser.get_data<ulong> ("history-list-sid-tab-next");
+            sidTabPrevious = browser.get_data<ulong> ("history-list-sid-tab-previous");
+
+            Gtk.Action action;
+            Gtk.ActionGroup action_group;
+            action_group = browser.get_action_group ();
+
+            action = action_group.get_action ("TabNext");
+            action.disconnect (sidTabNext);
+            browser.unblock_action (action);
+            action = action_group.get_action ("TabPrevious");
+            action.disconnect (sidTabPrevious);
+            browser.unblock_action (action);
+
+            for (int i = 0; i < callbacks.length; i++) {
+                action = action_group.get_action (callbacks[i]);
+                if (action != null)
+                    action_group.remove_action (action);
+            }
+
+            browser.add_tab.disconnect (tab_added);
+            browser.remove_tab.disconnect (tab_removed);
+            browser.notify["tab"].disconnect (this.tab_changed);
         }
-    }
-    void tab_changed (GLib.Object window, GLib.ParamSpec pspec) {
-        Midori.Browser browser = window as Midori.Browser;
-        Midori.View view = null;
-        Midori.View last_view = null;
-        browser.get ("tab", ref view);
 
-        last_view = browser.get_data<Midori.View?> ("history-list-last-change");
+        void tab_added (Midori.Browser browser, Midori.View view) {
+            unowned GLib.PtrArray list = browser.get_data<GLib.PtrArray> ("history-list-tab-history-new");
+            list.add (view);
+        }
 
-        if (last_view != null) {
-            this.tab_list_resort (browser, last_view);
+        void tab_removed (Midori.Browser browser, Midori.View view) {
+            unowned GLib.PtrArray list = browser.get_data<GLib.PtrArray> ("history-list-tab-history");
+            unowned GLib.PtrArray list_new = browser.get_data<GLib.PtrArray> ("history-list-tab-history-new");
+            list.remove (view);
+            list_new.remove (view);
+
+            if (this.closing_behavior == TabClosingBehavior.LAST || this.closing_behavior == TabClosingBehavior.NEW) {
+                browser.set_data<Midori.View?> ("history-list-last-change", null);
+
+                if ((int) list.len > 0 || (int) list_new.len > 0) {
+                    TabWindow hw;
+                    if (this.closing_behavior == TabClosingBehavior.LAST)
+                        hw = new TabWindow (browser);
+                    else
+                        hw = new NewTabWindow (browser);
+                    hw.make_update ();
+                    hw.destroy ();
+                }
+            }
+        }
+
+        void tab_changed (GLib.Object window, GLib.ParamSpec pspec) {
+            Midori.Browser browser = window as Midori.Browser;
+            Midori.View view = null;
+            Midori.View last_view = null;
+            browser.get ("tab", ref view);
+
+            last_view = browser.get_data<Midori.View?> ("history-list-last-change");
+
+            if (last_view != null) {
+                this.tab_list_resort (browser, last_view);
+            }
+            browser.set_data<Midori.View?> ("history-list-last-change", view);
+        }
+
+        void tab_list_resort (Midori.Browser browser, Midori.View view) {
+            unowned GLib.PtrArray list = browser.get_data<GLib.PtrArray> ("history-list-tab-history");
+            unowned GLib.PtrArray list_new = browser.get_data<GLib.PtrArray> ("history-list-tab-history-new");
+            list.remove (view);
+            list_new.remove (view);
+            list.add (view);
+        }
+
+        void activated (Midori.App app) {
+            this.preferences_changed ();
+            foreach (var browser in app.get_browsers ())
+                browser_added (browser);
+            app.add_browser.connect (browser_added);
+        }
+
+        void deactivated () {
+            var app = get_app ();
+            foreach (var browser in app.get_browsers ())
+                browser_removed (browser);
+            app.add_browser.disconnect (browser_added);
+        }
+
+        void show_preferences () {
+            var dialog = new PreferencesDialog (this);
+            dialog.show ();
+        }
+
+        internal Manager () {
+            GLib.Object (name: _("History List"),
+                         description: _("Move to the last used tab when switching or closing tabs"),
+                         version: "0.4",
+                         authors: "André Stösel <andre@stoesel.de>");
+
+            this.install_integer ("TabClosingBehavior", TabClosingBehavior.LAST);
+
+            this.activate.connect (activated);
+            this.deactivate.connect (deactivated);
+            this.open_preferences.connect (show_preferences);
+            this.preferences_changed.connect (preferences_changed_cb);
+        }
+        construct {
+            this.escKeyval = Gdk.keyval_from_name ("Escape");
         }
-        browser.set_data<Midori.View?> ("history-list-last-change", view);
-    }
-    void tab_list_resort (Midori.Browser browser, Midori.View view) {
-        unowned GLib.PtrArray list = browser.get_data<GLib.PtrArray> ("history-list-tab-history");
-        unowned GLib.PtrArray list_new = browser.get_data<GLib.PtrArray> ("history-list-tab-history-new");
-        list.remove (view);
-        list_new.remove (view);
-        list.add (view);
-    }
-    void activated (Midori.App app) {
-        foreach (var browser in app.get_browsers ())
-            browser_added (browser);
-        app.add_browser.connect (browser_added);
-    }
-    void deactivated () {
-        var app = get_app ();
-        foreach (var browser in app.get_browsers ())
-            browser_removed (browser);
-        app.add_browser.disconnect (browser_added);
-    }
-    internal HistoryList () {
-        GLib.Object (name: _("History List"),
-                     description: _("Switch tabs with Ctrl+Tab sorted by last usage"),
-                     version: "0.3",
-                     authors: "André Stösel <andre@stoesel.de>");
-        activate.connect (activated);
-        deactivate.connect (deactivated);
-    }
-    construct {
-        this.escKeyval = Gdk.keyval_from_name ("Escape");
     }
 }
 
 public Midori.Extension extension_init () {
-    return new HistoryList ();
+    return new HistoryList.Manager ();
 }