[balsa/remember-mailbox-positions: 4/6] Preserve tab order of open mailboxes



commit cfd9e3ae6f085173089e7991e4e91f1cb548b96c
Author: Peter Bloomfield <PeterBloomfield bellsouth net>
Date:   Thu Feb 7 21:37:38 2019 -0500

    Preserve tab order of open mailboxes
    
    Preserve tab order of open mailboxes across instances (#12)
    
    * libbalsa/mailbox.c (libbalsa_mailbox_set_position),
      (libbalsa_mailbox_get_position): manage the mailbox's position
      in the notebook;
      (libbalsa_mailbox_set_open): unset the position when the
      mailbox is closed;
    * libbalsa/mailbox.h: new member 'position';
    * libbalsa/mailbox_local.c (lbml_set_threading): guard against
      NULL msg_tree;
    * src/balsa-app.c (position_compare_func),
      (balsa_add_open_mailbox_urls): sort the mailboxes to be opened
      by their position in the last instance;
    * src/balsa-app.h: new member 'gboolean in_destruction';
    * src/balsa-index.c (bndx_destroy), (bndx_selection_changed),
      (balsa_index_load_mailbox_node): take a strong ref on the
      BalsaMailboxNode instead of a weak ref;
    * src/mailbox-node.c (balsa_mailbox_node_dispose): do not bother
      to close the mbnode;
    * src/main-window.c (bw_notebook_page_notify_cb): callback for
      the "child-notify::position" signal;
      (bw_real_open_mbnode_idle_cb): connect to it;
      (balsa_window_destroy): set 'in_destruction';
    * src/save-restore.c (config_load_mailbox_view),
      (config_save_mailbox_view): save and restore positions;
      (config_mailbox_get_int_property),
      (config_mailbox_get_position): new functions to get position;
    * src/save-restore.h: new API.

 ChangeLog                | 31 ++++++++++++++++++++++++++++++
 libbalsa/mailbox.c       | 32 +++++++++++++++++++++++++++++--
 libbalsa/mailbox.h       |  3 +++
 libbalsa/mailbox_local.c |  3 +++
 src/balsa-app.c          | 12 ++++++++++++
 src/balsa-app.h          |  2 ++
 src/balsa-index.c        | 50 ++++++++++++++++++++++--------------------------
 src/main-window.c        | 31 ++++++++++++++++++++++++++++--
 src/save-restore.c       | 41 ++++++++++++++++++++++++++++++++++++---
 src/save-restore.h       |  1 +
 10 files changed, 172 insertions(+), 34 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index b10f53c34..05a285821 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -127,6 +127,37 @@
        * libbalsa/mailbox_pop3.c: Do not leak the filter-cmd
        * libbalsa/address-book-rubrica.c: Do not leak the completion
 
+2019-02-07  Peter Bloomfield  <pbloomfield bellsouth net>
+
+       Preserve tab order of open mailboxes across instances (#12)
+
+       * libbalsa/mailbox.c (libbalsa_mailbox_set_position),
+         (libbalsa_mailbox_get_position): manage the mailbox's position
+         in the notebook;
+         (libbalsa_mailbox_set_open): unset the position when the
+         mailbox is closed;
+       * libbalsa/mailbox.h: new member 'position';
+       * libbalsa/mailbox_local.c (lbml_set_threading): guard against
+         NULL msg_tree;
+       * src/balsa-app.c (position_compare_func),
+         (balsa_add_open_mailbox_urls): sort the mailboxes to be opened
+         by their position in the last instance;
+       * src/balsa-app.h: new member 'gboolean in_destruction';
+       * src/balsa-index.c (bndx_destroy), (bndx_selection_changed),
+         (balsa_index_load_mailbox_node): take a strong ref on the
+         BalsaMailboxNode instead of a weak ref;
+       * src/mailbox-node.c (balsa_mailbox_node_dispose): do not bother
+         to close the mbnode;
+       * src/main-window.c (bw_notebook_page_notify_cb): callback for
+         the "child-notify::position" signal;
+         (bw_real_open_mbnode_idle_cb): connect to it;
+         (balsa_window_destroy): set 'in_destruction';
+       * src/save-restore.c (config_load_mailbox_view),
+         (config_save_mailbox_view): save and restore positions;
+         (config_mailbox_get_int_property),
+         (config_mailbox_get_position): new functions to get position;
+       * src/save-restore.h: new API.
+
 2019-02-04  Peter Bloomfield  <pbloomfield bellsouth net>
 
        * meson_options.txt: make 'autocrypt' a boolean option, default
diff --git a/libbalsa/mailbox.c b/libbalsa/mailbox.c
index 7c10b3371..8df9536eb 100644
--- a/libbalsa/mailbox.c
+++ b/libbalsa/mailbox.c
@@ -2304,7 +2304,8 @@ static LibBalsaMailboxView libbalsa_mailbox_view_default = {
 #endif
     -1,                         /* total messages      */
     -1,                         /* unread messages     */
-    0                           /* mod time             */
+    0,                          /* mod time             */
+    -1                          /* position             */
 };
 
 LibBalsaMailboxView *
@@ -2465,8 +2466,11 @@ libbalsa_mailbox_set_open(LibBalsaMailbox * mailbox, gboolean open)
 
     if (view->open != open) {
        view->open = open ? 1 : 0;
-       if (mailbox)
+       if (mailbox != NULL) {
+           if (!open)
+                view->position = -1;
            view->in_sync = 0;
+        }
     }
 }
 
@@ -2549,6 +2553,23 @@ libbalsa_mailbox_set_mtime(LibBalsaMailbox * mailbox, time_t mtime)
     }
 }
 
+void
+libbalsa_mailbox_set_position(LibBalsaMailbox * mailbox, gint position)
+{
+    LibBalsaMailboxView *view;
+
+    /* Changing the default is not allowed. */
+    g_return_if_fail(mailbox != NULL);
+
+    view = lbm_get_view(mailbox);
+    view->used = 1;
+
+    if (view->position != position) {
+       view->position = position;
+        view->in_sync = 0;
+    }
+}
+
 /* End of set methods. */
 
 /* Get methods; NULL mailbox is valid, and returns the default value. */
@@ -2663,6 +2684,13 @@ libbalsa_mailbox_get_mtime(LibBalsaMailbox * mailbox)
        mailbox->view->mtime : libbalsa_mailbox_view_default.mtime;
 }
 
+gint
+libbalsa_mailbox_get_position(LibBalsaMailbox * mailbox)
+{
+    return (mailbox && mailbox->view) ?
+       mailbox->view->position : libbalsa_mailbox_view_default.position;
+}
+
 /* End of get methods. */
 
 /* =================================================================== *
diff --git a/libbalsa/mailbox.h b/libbalsa/mailbox.h
index 96c76231f..4d57a669a 100644
--- a/libbalsa/mailbox.h
+++ b/libbalsa/mailbox.h
@@ -184,6 +184,7 @@ struct _LibBalsaMailboxView {
     int unread;
     int total;
     time_t mtime;       /* Mailbox mtime when counts were cached. */
+    gint position;      /* Position in the notebook */
 };
 
 struct _LibBalsaMailbox {
@@ -555,6 +556,7 @@ gboolean libbalsa_mailbox_set_crypto_mode(LibBalsaMailbox * mailbox,
 void libbalsa_mailbox_set_unread(LibBalsaMailbox * mailbox, gint unread);
 void libbalsa_mailbox_set_total (LibBalsaMailbox * mailbox, gint total);
 void libbalsa_mailbox_set_mtime (LibBalsaMailbox * mailbox, time_t mtime);
+void libbalsa_mailbox_set_position(LibBalsaMailbox * mailbox, gint position);
 
 const gchar *libbalsa_mailbox_get_identity_name(LibBalsaMailbox * mailbox);
 LibBalsaMailboxThreadingType
@@ -576,6 +578,7 @@ LibBalsaChkCryptoMode libbalsa_mailbox_get_crypto_mode(LibBalsaMailbox * mailbox
 gint libbalsa_mailbox_get_unread(LibBalsaMailbox * mailbox);
 gint libbalsa_mailbox_get_total (LibBalsaMailbox * mailbox);
 time_t libbalsa_mailbox_get_mtime(LibBalsaMailbox * mailbox);
+gint libbalsa_mailbox_get_position(LibBalsaMailbox * mailbox);
 
 /** force update of given msgno */
 void libbalsa_mailbox_msgno_changed(LibBalsaMailbox  *mailbox, guint seqno);
diff --git a/libbalsa/mailbox_local.c b/libbalsa/mailbox_local.c
index d2a6bad4f..f32fdfbf4 100644
--- a/libbalsa/mailbox_local.c
+++ b/libbalsa/mailbox_local.c
@@ -1109,6 +1109,9 @@ static void
 lbml_set_threading(LibBalsaMailbox * mailbox,
                    LibBalsaMailboxThreadingType thread_type)
 {
+    if (mailbox->msg_tree == NULL)
+        return;
+
     switch (thread_type) {
     case LB_MAILBOX_THREADING_JWZ:
         lbml_thread_messages(mailbox, TRUE);
diff --git a/src/balsa-app.c b/src/balsa-app.c
index 6bc80f15d..1ecb18dc0 100644
--- a/src/balsa-app.c
+++ b/src/balsa-app.c
@@ -557,12 +557,24 @@ balsa_open_mailbox_list(gchar ** urls)
     g_strfreev(urls);
 }
 
+static gint
+position_compare_func(gconstpointer a,
+                      gconstpointer b)
+{
+    const gchar *url_a = *(const gchar **) a;
+    const gchar *url_b = *(const gchar **) b;
+
+    return config_mailbox_get_position(url_a) - config_mailbox_get_position(url_b);
+}
+
 void
 balsa_add_open_mailbox_urls(GPtrArray * url_array)
 {
     libbalsa_conf_foreach_group(VIEW_BY_URL_SECTION_PREFIX,
                                 (LibBalsaConfForeachFunc)
                                 append_url_if_open, url_array);
+
+    g_ptr_array_sort(url_array, position_compare_func);
 }
 
 /* 
diff --git a/src/balsa-app.h b/src/balsa-app.h
index 9ec45c0f9..58159de8c 100644
--- a/src/balsa-app.h
+++ b/src/balsa-app.h
@@ -371,6 +371,8 @@ extern struct BalsaApplication {
 
     /* use as default email client for GNOME */
     int default_client;
+
+    gboolean in_destruction;
 } balsa_app;
 
 #define BALSA_IS_MAILBOX_SPECIAL(a) ((a)==balsa_app.inbox || (a)==balsa_app.trash || 
(a)==balsa_app.outbox||(a)==balsa_app.draftbox || (a)==balsa_app.sentbox)
diff --git a/src/balsa-index.c b/src/balsa-index.c
index 195397609..4bd7b722e 100644
--- a/src/balsa-index.c
+++ b/src/balsa-index.c
@@ -199,13 +199,6 @@ bndx_class_init(BalsaIndexClass * klass)
 }
 
 /* Object class destroy method. */
-static void
-bndx_mbnode_weak_notify(gpointer data, GObject *where_the_object_was)
-{
-    BalsaIndex *bindex = data;
-    bindex->mailbox_node = NULL;
-    gtk_widget_destroy(GTK_WIDGET(bindex));
-}
 
 static void
 bndx_destroy(GObject * obj)
@@ -215,22 +208,23 @@ bndx_destroy(GObject * obj)
     g_return_if_fail(obj != NULL);
     index = BALSA_INDEX(obj);
 
-    if (index->mailbox_node) {
-       LibBalsaMailbox* mailbox;
+    if (index->mailbox_node != NULL) {
+        LibBalsaMailbox *mailbox;
 
-       if ((mailbox = index->mailbox_node->mailbox)) {
-           g_signal_handlers_disconnect_matched(mailbox,
-                                                G_SIGNAL_MATCH_DATA,
-                                                0, 0, NULL, NULL, index);
-           gtk_tree_view_set_model(GTK_TREE_VIEW(index), NULL);
-           libbalsa_mailbox_close(mailbox, balsa_app.expunge_on_close);
-       }
+        mailbox = index->mailbox_node->mailbox;
+        if (mailbox != NULL)
+            g_object_ref(mailbox);
 
-       if (index->mailbox_node) {
-            g_object_weak_unref(G_OBJECT(index->mailbox_node),
-                                (GWeakNotify) bndx_mbnode_weak_notify,
-                                index);
-            index->mailbox_node = NULL;
+        g_object_unref(index->mailbox_node);
+        index->mailbox_node = NULL;
+
+        if (mailbox != NULL) {
+            g_signal_handlers_disconnect_matched(mailbox,
+                                                 G_SIGNAL_MATCH_DATA,
+                                                 0, 0, NULL, NULL, index);
+            gtk_tree_view_set_model(GTK_TREE_VIEW(index), NULL);
+            libbalsa_mailbox_close(mailbox, balsa_app.expunge_on_close);
+            g_object_unref(mailbox);
         }
     }
 
@@ -244,10 +238,10 @@ bndx_destroy(GObject * obj)
         index->popup_menu = NULL;
     }
 
-    g_free(index->filter_string); index->filter_string = NULL;
+    g_free(index->filter_string);
+    index->filter_string = NULL;
 
-    if (G_OBJECT_CLASS(parent_class)->dispose)
-        (*G_OBJECT_CLASS(parent_class)->dispose) (obj);
+    G_OBJECT_CLASS(parent_class)->dispose(obj);
 }
 
 /* Widget class popup menu method. */
@@ -561,6 +555,9 @@ bndx_selection_changed_func(GtkTreeModel * model, GtkTreePath * path,
 static void
 bndx_selection_changed(GtkTreeSelection * selection, BalsaIndex * index)
 {
+    if (index->mailbox_node == NULL)
+        return;
+
     index->next_msgno = 0;
     gtk_tree_selection_selected_foreach(selection,
                                         (GtkTreeSelectionForeachFunc)
@@ -966,9 +963,8 @@ balsa_index_load_mailbox_node(BalsaIndex * index,
     /*
      * set the new mailbox
      */
-    index->mailbox_node = mbnode;
-    g_object_weak_ref(G_OBJECT(mbnode),
-                      (GWeakNotify) bndx_mbnode_weak_notify, index);
+    index->mailbox_node = g_object_ref(mbnode);
+
     /*
      * rename "from" column to "to" for outgoing mail
      */
diff --git a/src/main-window.c b/src/main-window.c
index 53d063289..42e691e6f 100644
--- a/src/main-window.c
+++ b/src/main-window.c
@@ -171,6 +171,9 @@ static gboolean bw_notebook_drag_motion_cb(GtkWidget* widget,
                                            GdkDragContext* context,
                                            gint x, gint y, guint time,
                                            gpointer user_data);
+static void bw_notebook_page_notify_cb(GtkWidget  *child,
+                                       GParamSpec *child_property,
+                                       gpointer    user_data);
 
 
 static GtkWidget *bw_notebook_label_new (BalsaMailboxNode* mbnode);
@@ -2820,6 +2823,8 @@ bw_real_open_mbnode_idle_cb(BalsaWindowRealOpenMbnodeInfo * info)
                                    GTK_POLICY_AUTOMATIC);
     gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(index));
     gtk_widget_show(scroll);
+    g_signal_connect(scroll, "child-notify::position",
+                     G_CALLBACK(bw_notebook_page_notify_cb), window->notebook);
     page_num = gtk_notebook_append_page(GTK_NOTEBOOK(window->notebook),
                                         scroll, label);
     gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(window->notebook),
@@ -3088,8 +3093,8 @@ balsa_window_destroy(GObject * object)
         window->network_changed_source_id = 0;
     }
 
-    if (G_OBJECT_CLASS(balsa_window_parent_class)->dispose != NULL)
-        G_OBJECT_CLASS(balsa_window_parent_class)->dispose(object);
+    balsa_app.in_destruction = TRUE;
+    G_OBJECT_CLASS(balsa_window_parent_class)->dispose(object);
 
     balsa_unregister_pixmaps();
 }
@@ -4349,6 +4354,28 @@ static gboolean bw_notebook_drag_motion_cb(GtkWidget * widget,
     return FALSE;
 }
 
+static void
+bw_notebook_page_notify_cb(GtkWidget  *widget,
+                           GParamSpec *child_property,
+                           gpointer    notebook)
+{
+    GtkWidget *child;
+
+    if (balsa_app.in_destruction)
+        return;
+
+    child = gtk_bin_get_child(GTK_BIN(widget));
+
+    if (child != NULL) {
+        LibBalsaMailbox *mailbox;
+        gint page_num;
+
+        mailbox = BALSA_INDEX(child)->mailbox_node->mailbox;
+        page_num = gtk_notebook_page_num(notebook, widget);
+        libbalsa_mailbox_set_position(mailbox, page_num);
+    }
+}
+
 /* bw_progress_timeout
  *
  * This function is called at a preset interval to cause the progress
diff --git a/src/save-restore.c b/src/save-restore.c
index 23313fb9c..75fc19ac7 100644
--- a/src/save-restore.c
+++ b/src/save-restore.c
@@ -1783,6 +1783,9 @@ config_load_mailbox_view(const gchar * url)
     if (libbalsa_conf_has_key("Open"))
         view->open = libbalsa_conf_get_bool("Open");
 
+    if (libbalsa_conf_has_key("Position"))
+        view->position = libbalsa_conf_get_int("Position");
+
 #ifdef HAVE_GPGME
     if (libbalsa_conf_has_key("CryptoMode"))
         view->gpg_chk_mode = libbalsa_conf_get_int("CryptoMode");
@@ -1836,9 +1839,12 @@ config_save_mailbox_view(const gchar * url, LibBalsaMailboxView * view)
        libbalsa_conf_set_int("Subscribe",   view->subscribe);
     if (view->exposed        != libbalsa_mailbox_get_exposed(NULL))
        libbalsa_conf_set_bool("Exposed",    view->exposed);
-    if (balsa_app.remember_open_mboxes &&
-        view->open           != libbalsa_mailbox_get_open(NULL))
-       libbalsa_conf_set_bool("Open",       view->open);
+    if (balsa_app.remember_open_mboxes) {
+        if (view->open       != libbalsa_mailbox_get_open(NULL))
+            libbalsa_conf_set_bool("Open",   view->open);
+        if (view->position   != libbalsa_mailbox_get_position(NULL))
+            libbalsa_conf_set_int("Position", view->position);
+    }
 #ifdef HAVE_GPGME
     if (view->gpg_chk_mode   != libbalsa_mailbox_get_crypto_mode(NULL))
        libbalsa_conf_set_int("CryptoMode",  view->gpg_chk_mode);
@@ -2111,3 +2117,32 @@ config_mailbox_was_exposed(const gchar * url)
 {
     return config_mailbox_had_property(url, "Exposed");
 }
+
+static gint
+config_mailbox_get_int_property(const gchar * url, const gchar * key)
+{
+    gchar *prefix;
+    gint retval = -1;
+
+    prefix = view_by_url_prefix(url);
+    if (!libbalsa_conf_has_group(prefix)) {
+        g_free(prefix);
+        return retval;
+    }
+
+    libbalsa_conf_push_group(prefix);
+
+    if (libbalsa_conf_has_key(key))
+        retval = libbalsa_conf_get_int(key);
+
+    libbalsa_conf_pop_group();
+    g_free(prefix);
+
+    return retval;
+}
+
+gint
+config_mailbox_get_position(const gchar * url)
+{
+    return config_mailbox_get_int_property(url, "Position");
+}
diff --git a/src/save-restore.h b/src/save-restore.h
index adc2c9222..f6bb24587 100644
--- a/src/save-restore.h
+++ b/src/save-restore.h
@@ -65,6 +65,7 @@ void config_save_mailbox_view(const gchar * url, LibBalsaMailboxView * view);
 
 gboolean config_mailbox_was_open(const gchar * url);
 gboolean config_mailbox_was_exposed(const gchar * url);
+gint config_mailbox_get_position(const gchar * url);
 
 void config_filters_save(void);
 void config_mailbox_filters_save(LibBalsaMailbox * mbox);


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