From 9f7444baa2001616f227ba9a442be824a57e56b9 Mon Sep 17 00:00:00 2001 From: TingPing Date: Wed, 31 Dec 2014 03:34:55 -0500 Subject: [PATCH] Move userlist sorting to frontend This Fixes possible crashes when the two usertrees get out of sync and a double free occurs. Also now requires restart to change sort orders. Fixes #1252 Fixes #818 (probably) --- src/common/fe.h | 3 +- src/common/hexchat.h | 4 +-- src/common/userlist.c | 58 ++++++++----------------------- src/common/userlist.h | 2 ++ src/fe-gtk/maingui.c | 4 +-- src/fe-gtk/setup.c | 2 ++ src/fe-gtk/userlistgui.c | 74 +++++++++++++++++++++++++++++++++------- src/fe-gtk/userlistgui.h | 2 +- src/fe-text/fe-text.c | 6 +--- 9 files changed, 88 insertions(+), 67 deletions(-) diff --git a/src/common/fe.h b/src/common/fe.h index 2ca15c60..9d8919ac 100644 --- a/src/common/fe.h +++ b/src/common/fe.h @@ -88,11 +88,10 @@ void fe_progressbar_start (struct session *sess); void fe_progressbar_end (struct server *serv); void fe_print_text (struct session *sess, char *text, time_t stamp, gboolean no_activity); -void fe_userlist_insert (struct session *sess, struct User *newuser, int row, int sel); +void fe_userlist_insert (struct session *sess, struct User *newuser, gboolean sel); int fe_userlist_remove (struct session *sess, struct User *user); void fe_userlist_rehash (struct session *sess, struct User *user); void fe_userlist_update (struct session *sess, struct User *user); -void fe_userlist_move (struct session *sess, struct User *user, int new_row); void fe_userlist_numbers (struct session *sess); void fe_userlist_clear (struct session *sess); void fe_userlist_set_selected (struct session *sess); diff --git a/src/common/hexchat.h b/src/common/hexchat.h index dfb1c52f..a5b61a26 100644 --- a/src/common/hexchat.h +++ b/src/common/hexchat.h @@ -37,6 +37,7 @@ #endif #include "history.h" +#include "tree.h" #ifdef USE_OPENSSL #include /* SSL_() */ @@ -369,8 +370,7 @@ typedef struct session guint8 text_strip; struct server *server; - void *usertree_alpha; /* pure alphabetical tree */ - void *usertree; /* ordered with Ops first */ + tree *usertree; /* alphabetical tree */ struct User *me; /* points to myself in the usertree */ char channel[CHANLEN]; char waitchannel[CHANLEN]; /* waiting to join channel (/join sent) */ diff --git a/src/common/userlist.c b/src/common/userlist.c index ed794ddb..aa0f8f16 100644 --- a/src/common/userlist.c +++ b/src/common/userlist.c @@ -29,7 +29,7 @@ #include "util.h" -static int +int nick_cmp_az_ops (server *serv, struct User *user1, struct User *user2) { unsigned int access1 = user1->access; @@ -52,30 +52,12 @@ nick_cmp_az_ops (server *serv, struct User *user1, struct User *user2) return serv->p_cmp (user1->nick, user2->nick); } -static int +int nick_cmp_alpha (struct User *user1, struct User *user2, server *serv) { return serv->p_cmp (user1->nick, user2->nick); } -static int -nick_cmp (struct User *user1, struct User *user2, server *serv) -{ - switch (prefs.hex_gui_ulist_sort) - { - case 0: - return nick_cmp_az_ops (serv, user1, user2); - case 1: - return serv->p_cmp (user1->nick, user2->nick); - case 2: - return -1 * nick_cmp_az_ops (serv, user1, user2); - case 3: - return -1 * serv->p_cmp (user1->nick, user2->nick); - default: - return -1; - } -} - /* insert name in appropriate place in linked list. Returns row number or: -1: duplicate @@ -86,11 +68,9 @@ userlist_insertname (session *sess, struct User *newuser) { if (!sess->usertree) { - sess->usertree = tree_new ((tree_cmp_func *)nick_cmp, sess->server); - sess->usertree_alpha = tree_new ((tree_cmp_func *)nick_cmp_alpha, sess->server); + sess->usertree = tree_new ((tree_cmp_func *)nick_cmp_alpha, sess->server); } - tree_insert (sess->usertree_alpha, newuser); return tree_insert (sess->usertree, newuser); } @@ -188,10 +168,8 @@ userlist_free (session *sess) { tree_foreach (sess->usertree, (tree_traverse_func *)free_user, NULL); tree_destroy (sess->usertree); - tree_destroy (sess->usertree_alpha); sess->usertree = NULL; - sess->usertree_alpha = NULL; sess->me = NULL; sess->ops = 0; @@ -219,8 +197,8 @@ userlist_find (struct session *sess, const char *name) { int pos; - if (sess->usertree_alpha) - return tree_find (sess->usertree_alpha, name, + if (sess->usertree) + return tree_find (sess->usertree, name, (tree_cmp_func *)find_cmp, sess->server, &pos); return NULL; @@ -283,7 +261,7 @@ userlist_update_mode (session *sess, char *name, char mode, char sign) /* remove from binary trees, before we loose track of it */ tree_remove (sess->usertree, user, &pos); - tree_remove (sess->usertree_alpha, user, &pos); + fe_userlist_remove (sess, user); /* which bit number is affected? */ access = mode_access (sess->server, mode, &prefix); @@ -313,11 +291,8 @@ userlist_update_mode (session *sess, char *name, char mode, char sign) update_counts (sess, user, prefix, level, offset); /* insert it back into its new place */ - tree_insert (sess->usertree_alpha, user); - pos = tree_insert (sess->usertree, user); - - /* let GTK move it too */ - fe_userlist_move (sess, user, pos); + tree_insert (sess->usertree, user); + fe_userlist_insert (sess, user, FALSE); fe_userlist_numbers (sess); } @@ -330,14 +305,12 @@ userlist_change (struct session *sess, char *oldname, char *newname) if (user) { tree_remove (sess->usertree, user, &pos); - tree_remove (sess->usertree_alpha, user, &pos); + fe_userlist_remove (sess, user); safe_strcpy (user->nick, newname, NICKLEN); - tree_insert (sess->usertree_alpha, user); - - fe_userlist_move (sess, user, tree_insert (sess->usertree, user)); - fe_userlist_numbers (sess); + tree_insert (sess->usertree, user); + fe_userlist_insert (sess, user, FALSE); return 1; } @@ -376,7 +349,6 @@ userlist_remove_user (struct session *sess, struct User *user) sess->me = NULL; tree_remove (sess->usertree, user, &pos); - tree_remove (sess->usertree_alpha, user, &pos); free_user (user, NULL); } @@ -442,7 +414,7 @@ userlist_add (struct session *sess, char *name, char *hostname, if (user->me) sess->me = user; - fe_userlist_insert (sess, user, row, FALSE); + fe_userlist_insert (sess, user, FALSE); fe_userlist_numbers (sess); } @@ -456,7 +428,7 @@ rehash_cb (struct User *user, session *sess) void userlist_rehash (session *sess) { - tree_foreach (sess->usertree_alpha, (tree_traverse_func *)rehash_cb, sess); + tree_foreach (sess->usertree, (tree_traverse_func *)rehash_cb, sess); } static int @@ -471,7 +443,7 @@ userlist_flat_list (session *sess) { GSList *list = NULL; - tree_foreach (sess->usertree_alpha, (tree_traverse_func *)flat_cb, &list); + tree_foreach (sess->usertree, (tree_traverse_func *)flat_cb, &list); return g_slist_reverse (list); } @@ -487,6 +459,6 @@ userlist_double_list(session *sess) { GList *list = NULL; - tree_foreach (sess->usertree_alpha, (tree_traverse_func *)double_cb, &list); + tree_foreach (sess->usertree, (tree_traverse_func *)double_cb, &list); return list; } diff --git a/src/common/userlist.h b/src/common/userlist.h index ebf95606..0c53dc71 100644 --- a/src/common/userlist.h +++ b/src/common/userlist.h @@ -61,5 +61,7 @@ void userlist_update_mode (session *sess, char *name, char mode, char sign); GSList *userlist_flat_list (session *sess); GList *userlist_double_list (session *sess); void userlist_rehash (session *sess); +int nick_cmp_az_ops (server *serv, struct User *user1, struct User *user2); +int nick_cmp_alpha (struct User *user1, struct User *user2, server *serv); #endif diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c index b1764a0a..2eabe8b7 100644 --- a/src/fe-gtk/maingui.c +++ b/src/fe-gtk/maingui.c @@ -1715,7 +1715,7 @@ mg_add_chan (session *sess) { sess->res->buffer = gtk_xtext_buffer_new (GTK_XTEXT (sess->gui->xtext)); gtk_xtext_set_time_stamp (sess->res->buffer, prefs.hex_stamp_text); - sess->res->user_model = userlist_create_model (); + sess->res->user_model = userlist_create_model (sess); } } @@ -3164,7 +3164,7 @@ mg_create_topwindow (session *sess) sess->res->buffer = gtk_xtext_buffer_new (GTK_XTEXT (sess->gui->xtext)); gtk_xtext_buffer_show (GTK_XTEXT (sess->gui->xtext), sess->res->buffer, TRUE); gtk_xtext_set_time_stamp (sess->res->buffer, prefs.hex_stamp_text); - sess->res->user_model = userlist_create_model (); + sess->res->user_model = userlist_create_model (sess); } userlist_show (sess); diff --git a/src/fe-gtk/setup.c b/src/fe-gtk/setup.c index cc5d25bf..e3969ff3 100644 --- a/src/fe-gtk/setup.c +++ b/src/fe-gtk/setup.c @@ -2114,6 +2114,8 @@ setup_apply (struct hexchatprefs *pr) noapply = TRUE; if (DIFF (hex_gui_ulist_style)) noapply = TRUE; + if (DIFF (hex_gui_ulist_sort)) + noapply = TRUE; if (DIFF (hex_gui_tab_dots)) do_layout = TRUE; diff --git a/src/fe-gtk/userlistgui.c b/src/fe-gtk/userlistgui.c index b95eb522..943bd17b 100644 --- a/src/fe-gtk/userlistgui.c +++ b/src/fe-gtk/userlistgui.c @@ -332,9 +332,9 @@ fe_userlist_rehash (session *sess, struct User *user) } void -fe_userlist_insert (session *sess, struct User *newuser, int row, int sel) +fe_userlist_insert (session *sess, struct User *newuser, gboolean sel) { - GtkTreeModel *model = sess->res->user_model; + GtkTreeModel *model = GTK_TREE_MODEL(sess->res->user_model); GdkPixbuf *pix = get_user_icon (sess->server, newuser); GtkTreeIter iter; char *nick; @@ -357,7 +357,7 @@ fe_userlist_insert (session *sess, struct User *newuser, int row, int sel) pix = NULL; } - gtk_list_store_insert_with_values (GTK_LIST_STORE (model), &iter, row, + gtk_list_store_insert_with_values (GTK_LIST_STORE (model), &iter, 0, COL_PIX, pix, COL_NICK, nick, COL_HOST, newuser->hostname, @@ -395,12 +395,6 @@ fe_userlist_insert (session *sess, struct User *newuser, int row, int sel) } } -void -fe_userlist_move (session *sess, struct User *user, int new_row) -{ - fe_userlist_insert (sess, user, new_row, fe_userlist_remove (sess, user)); -} - void fe_userlist_clear (session *sess) { @@ -459,11 +453,67 @@ userlist_dnd_leave (GtkTreeView *widget, GdkDragContext *context, guint ttime) return TRUE; } -void * -userlist_create_model (void) +static int +userlist_alpha_cmp (GtkTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b, gpointer userdata) { - return gtk_list_store_new (5, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, + struct User *user_a, *user_b; + + gtk_tree_model_get (model, iter_a, COL_USER, &user_a, -1); + gtk_tree_model_get (model, iter_b, COL_USER, &user_b, -1); + + return nick_cmp_alpha (user_a, user_b, ((session*)userdata)->server); +} + +static int +userlist_ops_cmp (GtkTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b, gpointer userdata) +{ + struct User *user_a, *user_b; + + gtk_tree_model_get (model, iter_a, COL_USER, &user_a, -1); + gtk_tree_model_get (model, iter_b, COL_USER, &user_b, -1); + + return nick_cmp_az_ops (((session*)userdata)->server, user_a, user_b); +} + +GtkListStore * +userlist_create_model (session *sess) +{ + GtkListStore *store; + GtkTreeIterCompareFunc cmp_func; + GtkSortType sort_type; + + store = gtk_list_store_new (5, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, GDK_TYPE_COLOR); + + switch (prefs.hex_gui_ulist_sort) + { + case 0: + cmp_func = userlist_ops_cmp; + sort_type = GTK_SORT_ASCENDING; + break; + case 1: + cmp_func = userlist_alpha_cmp; + sort_type = GTK_SORT_ASCENDING; + break; + case 2: + cmp_func = userlist_ops_cmp; + sort_type = GTK_SORT_DESCENDING; + break; + case 3: + cmp_func = userlist_alpha_cmp; + sort_type = GTK_SORT_DESCENDING; + break; + default: + /* No sorting */ + gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE(store), NULL, NULL, NULL); + return store; + } + + gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE(store), cmp_func, sess, NULL); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(store), + GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, sort_type); + + return store; } static void diff --git a/src/fe-gtk/userlistgui.h b/src/fe-gtk/userlistgui.h index 993fe8f0..7633246a 100644 --- a/src/fe-gtk/userlistgui.h +++ b/src/fe-gtk/userlistgui.h @@ -23,7 +23,7 @@ void userlist_set_value (GtkWidget *treeview, gfloat val); gfloat userlist_get_value (GtkWidget *treeview); GtkWidget *userlist_create (GtkWidget *box); -void *userlist_create_model (void); +void *userlist_create_model (session *sess); void userlist_show (session *sess); void userlist_select (session *sess, char *name); char **userlist_selection_list (GtkWidget *widget, int *num_ret); diff --git a/src/fe-text/fe-text.c b/src/fe-text/fe-text.c index 2dd93e2a..a709fe9e 100644 --- a/src/fe-text/fe-text.c +++ b/src/fe-text/fe-text.c @@ -678,7 +678,7 @@ fe_progressbar_end (struct server *serv) { } void -fe_userlist_insert (struct session *sess, struct User *newuser, int row, int sel) +fe_userlist_insert (struct session *sess, struct User *newuser, gboolean sel) { } int @@ -691,10 +691,6 @@ fe_userlist_rehash (struct session *sess, struct User *user) { } void -fe_userlist_move (struct session *sess, struct User *user, int new_row) -{ -} -void fe_userlist_numbers (struct session *sess) { }