diff -ur xchat-1.9.8/src/common/cfgfiles.c xchat-1.9.8-treeview/src/common/cfgfiles.c --- xchat-1.9.8/src/common/cfgfiles.c 2002-12-25 09:17:05.000000000 +0000 +++ xchat-1.9.8-treeview/src/common/cfgfiles.c 2003-01-02 13:02:58.000000000 +0000 @@ -437,6 +437,7 @@ {"text_show_sep", P_OFFINT (show_separator), TYPE_BOOL}, {"text_stripcolor", P_OFFINT (stripcolor), TYPE_BOOL}, {"text_wordwrap", P_OFFINT (wordwrap), TYPE_BOOL}, + {"treeview", P_OFFINT (treeview), TYPE_BOOL}, {0, 0, 0}, }; diff -ur xchat-1.9.8/src/common/xchat.h xchat-1.9.8-treeview/src/common/xchat.h --- xchat-1.9.8/src/common/xchat.h 2002-12-27 09:04:53.000000000 +0000 +++ xchat-1.9.8-treeview/src/common/xchat.h 2003-01-02 13:02:40.000000000 +0000 @@ -246,6 +246,7 @@ unsigned int persist_chans; unsigned int wait_on_exit; unsigned int utf8_locale; + unsigned int treeview; unsigned int ctcp_number_limit; /*flood */ unsigned int ctcp_time_limit; /*seconds of floods */ diff -ur xchat-1.9.8/src/fe-gtk/fe-gtk.c xchat-1.9.8-treeview/src/fe-gtk/fe-gtk.c --- xchat-1.9.8/src/fe-gtk/fe-gtk.c 2002-12-25 09:46:17.000000000 +0000 +++ xchat-1.9.8-treeview/src/fe-gtk/fe-gtk.c 2003-01-01 20:12:44.000000000 +0000 @@ -35,6 +35,9 @@ #include #include #include +#include +#include +#include #include "../common/xchat.h" #include "../common/fe.h" @@ -353,10 +356,17 @@ void fe_set_hilight (struct session *sess) { + GtkTreeIter iter; + if (sess->gui->is_tab) { sess->nick_said = TRUE; tab_set_attrlist (sess->res->tab, nickseen_list); + if (treeview_iter_get (sess, &iter) == 0) + gtk_tree_store_set ( + GTK_TREE_STORE (G_tree_model), + &iter, + 1, "blue", -1); } } @@ -477,6 +487,7 @@ void fe_print_text (struct session *sess, char *text) { + GtkTreeIter iter; PrintTextRaw (sess->res->buffer, text, prefs.indent_nicks); if (prefs.limitedtabhighlight && !sess->highlight_tab) @@ -488,10 +499,23 @@ sess->gui->is_tab && !sess->nick_said) { sess->new_data = TRUE; - if (sess->msg_said) + + if (sess->msg_said) { tab_set_attrlist (sess->res->tab, newmsg_list); - else + if (treeview_iter_get (sess, &iter) == 0) + gtk_tree_store_set ( + GTK_TREE_STORE (G_tree_model), + &iter, + 1, "red", -1); + } else { + /* I'm not sure when this gets called -agl */ tab_set_attrlist (sess->res->tab, newdata_list); + if (treeview_iter_get (sess, &iter) == 0) + gtk_tree_store_set ( + GTK_TREE_STORE (G_tree_model), + &iter, + 1, "blue", -1); + } } } diff -ur xchat-1.9.8/src/fe-gtk/fe-gtk.h xchat-1.9.8-treeview/src/fe-gtk/fe-gtk.h --- xchat-1.9.8/src/fe-gtk/fe-gtk.h 2002-12-18 15:29:01.000000000 +0000 +++ xchat-1.9.8-treeview/src/fe-gtk/fe-gtk.h 2003-01-01 20:14:41.000000000 +0000 @@ -38,6 +38,11 @@ #define flag_b flag_wid[8] #define NUM_FLAG_WIDS 9 +struct _GtkTreeStore; + +/* Global model for the treeview */ +extern struct _GtkTreeStore *G_tree_model; + struct server_gui { GtkWidget *rawlog_window; diff -ur xchat-1.9.8/src/fe-gtk/maingui.c xchat-1.9.8-treeview/src/fe-gtk/maingui.c --- xchat-1.9.8/src/fe-gtk/maingui.c 2002-12-26 03:28:43.000000000 +0000 +++ xchat-1.9.8-treeview/src/fe-gtk/maingui.c 2003-01-02 13:56:10.000000000 +0000 @@ -39,6 +39,14 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include "../common/xchat.h" #include "../common/fe.h" @@ -59,7 +67,7 @@ #include "xtext.h" static void mg_create_entry (session *sess, GtkWidget *box); - +static void treeview_black (void *p); static session_gui static_mg_gui; static session_gui *mg_gui = NULL; /* the shared irc tab */ @@ -75,6 +83,7 @@ PangoAttrList *newmsg_list = NULL; static PangoAttrList *plain_list = NULL; +GtkTreeStore *G_tree_model; static PangoAttrList * mg_attr_list_create (GdkColor *col) @@ -269,6 +278,7 @@ sess->msg_said = FALSE; sess->new_data = FALSE; tab_set_attrlist (sess->res->tab, plain_list); + treeview_black (sess); } } @@ -1765,11 +1775,60 @@ } static void +tree_row_cb (GtkTreeSelection *selection, gpointer data) +{ + GtkTreeIter iter; + session *sess; + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { + if (gtk_tree_model_iter_has_child ( + GTK_TREE_MODEL (G_tree_model), &iter)) + return; + gtk_tree_model_get (GTK_TREE_MODEL (G_tree_model), + &iter, 2, &sess, -1); + if (sess->gui->is_tab) + mg_bring_tofront (sess->res->tab); + else + gtk_window_present(GTK_WINDOW (sess->gui->window)); + } +} + +static void +mg_create_treeview (session *sess, GtkWidget *hbox) +{ + GtkWidget *tree; + GtkTreeViewColumn *column; + GtkTreeSelection *select; + + if (!G_tree_model) + G_tree_model = gtk_tree_store_new (3, G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_POINTER); + + tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(G_tree_model)); + + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree)); + gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); + g_signal_connect (G_OBJECT (select), "changed", + G_CALLBACK (tree_row_cb), + NULL); + + column = gtk_tree_view_column_new_with_attributes + ("Channel", gtk_cell_renderer_text_new(), + "text", 0, + "foreground", 1, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column); + gtk_container_add (GTK_CONTAINER (hbox), tree); + gtk_widget_show (tree); +} + +static void mg_create_topwindow (session *sess) { GtkWidget *win; GtkWidget *vbox; - GtkWidget *vvbox; + GtkWidget *vvbox, *paned, *hbox; win = gtkutil_window_new ("X-Chat ["VERSION"]", prefs.mainwindow_width, prefs.mainwindow_height, FALSE); @@ -1786,9 +1845,21 @@ vbox = gtk_vbox_new (FALSE, 1); gtk_container_add (GTK_CONTAINER (win), vbox); - + vvbox = gtk_vbox_new (FALSE, 1); - gtk_container_add (GTK_CONTAINER (vbox), vvbox); + if (prefs.treeview) { + paned = gtk_hpaned_new (); + gtk_container_add (GTK_CONTAINER (vbox), paned); + hbox = gtk_hbox_new (FALSE, 1); + gtk_paned_add1 (GTK_PANED (paned), hbox); + mg_create_treeview (sess, hbox); + gtk_paned_add2 (GTK_PANED (paned), vvbox); + gtk_widget_show (paned); + gtk_widget_show (hbox); + gtk_widget_show (vvbox); + } else { + gtk_container_add (GTK_CONTAINER (vbox), vvbox); + } mg_create_topicbar (sess, vvbox, sess->channel); mg_create_center (sess, sess->gui, vvbox); @@ -1895,7 +1966,7 @@ mg_create_tabwindow (session *sess) { GtkWidget *win; - GtkWidget *vbox; + GtkWidget *vbox, *paned, *hbox, *right_vbox; GtkWidget *book; win = gtkutil_window_new ("X-Chat ["VERSION"]", prefs.mainwindow_width, @@ -1921,10 +1992,25 @@ sess->gui->main_vbox = vbox = gtk_vbox_new (FALSE, 1); gtk_container_add (GTK_CONTAINER (win), vbox); + if (prefs.treeview) { + paned = gtk_hpaned_new (); + gtk_container_add (GTK_CONTAINER (vbox), paned); + hbox = gtk_hbox_new (FALSE, 1); + gtk_paned_add1 (GTK_PANED (paned), hbox); + mg_create_treeview (sess, hbox); + right_vbox = gtk_vbox_new (FALSE, 1); + gtk_paned_add2 (GTK_PANED (paned), right_vbox); + gtk_widget_show (paned); + gtk_widget_show (hbox); + gtk_widget_show (right_vbox); + } else { + right_vbox = vbox; + } + sess->gui->note_book = book = gtk_notebook_new (); gtk_notebook_set_show_tabs (GTK_NOTEBOOK (book), FALSE); gtk_notebook_set_show_border (GTK_NOTEBOOK (book), FALSE); - gtk_container_add (GTK_CONTAINER (vbox), book); + gtk_container_add (GTK_CONTAINER (right_vbox), book); mg_create_irctab (sess, book); mg_create_tabs (sess->gui, vbox); @@ -2006,6 +2092,104 @@ gui->button_box = mg_create_userlistbuttons (gui->button_box_parent); } +/* Treeview code: + + There is a global GtkTreeStore called G_tree_store which is used by + all the GtkTreeViews. This store is updated even if prefs.treeview + is false. + + The store has 3 columns: name (string), colour (string) and serv/sess + (pointer). If a row has children then the pointer is a server, other- + wise it's a session. +*/ + +/* Recurse down the TreeStore for a row who's pointer equals @cp. Store + the iterator of that row in @o_i. Return 1 if not found, 0 if found.*/ +char +treeview_iter_get (void *cp, GtkTreeIter *o_i) +{ + GtkTreeIter i, i2; + void *p; + gboolean valid, valid2; + + valid =gtk_tree_model_get_iter_first(GTK_TREE_MODEL(G_tree_model), + &i); + + while (valid) { + gtk_tree_model_get (GTK_TREE_MODEL (G_tree_model), &i, + 2, &p, -1); + if (p == cp) { + memcpy (o_i, &i, sizeof (i)); + return 0; + } + valid2 = 1; + if (gtk_tree_model_iter_children ( + GTK_TREE_MODEL (G_tree_model), &i2, &i)) + while (valid2) { + gtk_tree_model_get ( + GTK_TREE_MODEL (G_tree_model),&i2, + 2, &p, -1); + if (p == cp) { + memcpy (o_i, &i2, sizeof (i2)); + return 0; + } + valid2 = gtk_tree_model_iter_next ( + GTK_TREE_MODEL (G_tree_model), + &i2); + } + valid = gtk_tree_model_iter_next ( + GTK_TREE_MODEL (G_tree_model), + &i); + } + + return 1; +} + +/* Remove the row with the given pointer (session or server) */ +static void +treeview_sess_remove (void *sess) +{ + GtkTreeIter iter; + + if (treeview_iter_get (sess, &iter)) + return; + gtk_tree_store_remove (GTK_TREE_STORE (G_tree_model), &iter); +} + +/* For a given row (@i), set the string and pointer */ +static void +treeview_update (GtkTreeIter *i, char *str, void *ptr) +{ + gtk_tree_store_set (G_tree_model, i, + 0, strcmp(str,"")==0?"":str, + 1, "black", + 2, ptr, + -1); +} + +static void +treeview_update_ptr (void *p, char *str, void *ptr) +{ + GtkTreeIter iter; + + if (treeview_iter_get (p, &iter)) + return; + treeview_update (&iter, str, ptr); +} + +/* Search for a row with pointer equal to @p and set its colour to black*/ +static void +treeview_black (void *p) +{ + GtkTreeIter i; + + if (treeview_iter_get (p, &i)) + return; + gtk_tree_store_set (GTK_TREE_STORE (G_tree_model), &i, + 1, "black", + -1); +} + void fe_clear_channel (session *sess) { @@ -2028,6 +2212,7 @@ } else strcpy (tbuf, _("")); + treeview_update_ptr (sess, tbuf, sess); tab_rename (sess->res->tab, tbuf); if (!sess->gui->is_tab || sess == current_tab) @@ -2162,11 +2347,16 @@ g_utf8_offset_to_pointer(buf, prefs.truncchans)[0] = 0; strcat (buf, ".."); tab_rename (sess->res->tab, buf); + treeview_update_ptr (sess, buf, sess); free (buf); } else { tab_rename (sess->res->tab, sess->channel); + treeview_update_ptr (sess, sess->channel, + sess); } + treeview_update_ptr (sess->server, sess->server->hostname, + sess->server); } void @@ -2174,6 +2364,7 @@ { int first_run = FALSE; session_gui *gui; + GtkTreeIter iter1, iter2; if (!res) { @@ -2194,7 +2385,7 @@ sess->gui = gui; mg_create_topwindow (sess); fe_set_title (sess); - return; + goto treeview_insert; } if (mg_gui == NULL) @@ -2216,6 +2407,21 @@ if (first_run || prefs.newtabstofront) tab_focus (res->tab); + + treeview_insert: + if (!G_tree_model) + G_tree_model = gtk_tree_store_new (3, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_POINTER); + + if (treeview_iter_get (sess->server, &iter1)) + gtk_tree_store_append(G_tree_model, &iter1, NULL); + treeview_update (&iter1, sess->server->hostname, + sess->server); + + gtk_tree_store_append (G_tree_model, &iter2, &iter1); + treeview_update (&iter2, sess->channel, sess); } GtkWidget * @@ -2300,6 +2506,7 @@ if (serv->gui->rawlog_window) gtk_widget_destroy (serv->gui->rawlog_window); + treeview_sess_remove (serv); free (serv->gui); } @@ -2330,7 +2537,10 @@ if (sess->gui->bartag) fe_timeout_remove (sess->gui->bartag); + treeview_sess_remove (sess); + if (sess->gui != mg_gui) free (sess->gui); + free (sess->res); } diff -ur xchat-1.9.8/src/fe-gtk/maingui.h xchat-1.9.8-treeview/src/fe-gtk/maingui.h --- xchat-1.9.8/src/fe-gtk/maingui.h 2002-12-19 07:19:13.000000000 +0000 +++ xchat-1.9.8-treeview/src/fe-gtk/maingui.h 2003-01-01 20:16:53.000000000 +0000 @@ -20,3 +20,7 @@ void mg_link_cb (GtkWidget *but, gpointer userdata); void mg_progressbar_create (session_gui *gui); void mg_progressbar_destroy (session_gui *gui); + +struct _GtkTreeIter; +char treeview_iter_get (void *cp, struct _GtkTreeIter *o_i); + diff -ur xchat-1.9.8/src/fe-gtk/setup.c xchat-1.9.8-treeview/src/fe-gtk/setup.c --- xchat-1.9.8/src/fe-gtk/setup.c 2002-12-25 09:40:06.000000000 +0000 +++ xchat-1.9.8-treeview/src/fe-gtk/setup.c 2003-01-02 13:06:37.000000000 +0000 @@ -161,6 +161,7 @@ {ST_TOGGLE, N_("Only highlight tabs on channel messages"), P_OFFINT(limitedtabhighlight), 0, 0, 0}, {ST_TOGGLE, N_("Open tab for server notices"), P_OFFINT(notices_tabs), 0, 0, 0}, {ST_TOGGLE, N_("Pop new tabs to front"), P_OFFINT(newtabstofront), 0, 0, 0}, + {ST_TOGGLE, N_("Use Treeview"), P_OFFINT(treeview), 0, 0, 0}, {ST_END, 0, 0, 0, 0, 0} };