changeset 18356:823b3a3191fc

merge of '32cacc02ac154597af16ab9465ee19dc75149903' and 'e2ba19f94867654f67522ab62256281645a9df9f'
author Evan Schoenberg <evan.s@dreskin.net>
date Fri, 29 Jun 2007 15:03:27 +0000
parents e356256cb8a6 (current diff) cafecb0e4147 (diff)
children 2177a11e169d
files
diffstat 18 files changed, 574 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- a/finch/gntaccount.c	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/gntaccount.c	Fri Jun 29 15:03:27 2007 +0000
@@ -645,8 +645,10 @@
 	GList *iter;
 	GntWidget *box, *button;
 
-	if (accounts.window)
+	if (accounts.window) {
+		gnt_window_present(accounts.window);
 		return;
+	}
 
 	accounts.window = gnt_vbox_new(FALSE);
 	gnt_box_set_toplevel(GNT_BOX(accounts.window), TRUE);
--- a/finch/gntblist.c	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/gntblist.c	Fri Jun 29 15:03:27 2007 +0000
@@ -2250,8 +2250,10 @@
 {
 	if (ggblist == NULL)
 		new_list(list);
-	else if (ggblist->window)
+	else if (ggblist->window) {
+		gnt_window_present(ggblist->window);
 		return;
+	}
 
 	ggblist->window = gnt_vwindow_new(FALSE);
 	gnt_widget_set_name(ggblist->window, "buddylist");
--- a/finch/gntdebug.c	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/gntdebug.c	Fri Jun 29 15:03:27 2007 +0000
@@ -221,56 +221,59 @@
 
 void finch_debug_window_show()
 {
+	GntWidget *wid, *box;
+
 	debug.paused = FALSE;
-	if (debug.window == NULL)
-	{
-		GntWidget *wid, *box;
-		debug.window = gnt_vbox_new(FALSE);
-		gnt_box_set_toplevel(GNT_BOX(debug.window), TRUE);
-		gnt_box_set_title(GNT_BOX(debug.window), _("Debug Window"));
-		gnt_box_set_pad(GNT_BOX(debug.window), 0);
-		gnt_box_set_alignment(GNT_BOX(debug.window), GNT_ALIGN_MID);
+	if (debug.window) {
+		gnt_window_present(debug.window);
+		return;
+	}
 
-		debug.tview = gnt_text_view_new();
-		gnt_box_add_widget(GNT_BOX(debug.window), debug.tview);
-		gnt_widget_set_size(debug.tview,
-				purple_prefs_get_int(PREF_ROOT "/size/width"),
-				purple_prefs_get_int(PREF_ROOT "/size/height"));
-		g_signal_connect(G_OBJECT(debug.tview), "size_changed", G_CALLBACK(size_changed_cb), NULL);
+	debug.window = gnt_vbox_new(FALSE);
+	gnt_box_set_toplevel(GNT_BOX(debug.window), TRUE);
+	gnt_box_set_title(GNT_BOX(debug.window), _("Debug Window"));
+	gnt_box_set_pad(GNT_BOX(debug.window), 0);
+	gnt_box_set_alignment(GNT_BOX(debug.window), GNT_ALIGN_MID);
 
-		gnt_box_add_widget(GNT_BOX(debug.window), gnt_line_new(FALSE));
+	debug.tview = gnt_text_view_new();
+	gnt_box_add_widget(GNT_BOX(debug.window), debug.tview);
+	gnt_widget_set_size(debug.tview,
+			purple_prefs_get_int(PREF_ROOT "/size/width"),
+			purple_prefs_get_int(PREF_ROOT "/size/height"));
+	g_signal_connect(G_OBJECT(debug.tview), "size_changed", G_CALLBACK(size_changed_cb), NULL);
 
-		box = gnt_hbox_new(FALSE);
-		gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_MID);
-		gnt_box_set_fill(GNT_BOX(box), FALSE);
+	gnt_box_add_widget(GNT_BOX(debug.window), gnt_line_new(FALSE));
+
+	box = gnt_hbox_new(FALSE);
+	gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_MID);
+	gnt_box_set_fill(GNT_BOX(box), FALSE);
 
-		/* XXX: Setting the GROW_Y for the following widgets don't make sense. But right now
-		 * it's necessary to make the width of the debug window resizable ... like I said,
-		 * it doesn't make sense. The bug is likely in the packing in gntbox.c.
-		 */
-		wid = gnt_button_new(_("Clear"));
-		g_signal_connect(G_OBJECT(wid), "activate", G_CALLBACK(clear_debug_win), debug.tview);
-		GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y);
-		gnt_box_add_widget(GNT_BOX(box), wid);
-
-		debug.search = gnt_entry_new(purple_prefs_get_string(PREF_ROOT "/filter"));
-		gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Filter: ")));
-		gnt_box_add_widget(GNT_BOX(box), debug.search);
-		g_signal_connect(G_OBJECT(debug.search), "text_changed", G_CALLBACK(update_filter_string), NULL);
+	/* XXX: Setting the GROW_Y for the following widgets don't make sense. But right now
+	 * it's necessary to make the width of the debug window resizable ... like I said,
+	 * it doesn't make sense. The bug is likely in the packing in gntbox.c.
+	 */
+	wid = gnt_button_new(_("Clear"));
+	g_signal_connect(G_OBJECT(wid), "activate", G_CALLBACK(clear_debug_win), debug.tview);
+	GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y);
+	gnt_box_add_widget(GNT_BOX(box), wid);
 
-		wid = gnt_check_box_new(_("Pause"));
-		g_signal_connect(G_OBJECT(wid), "toggled", G_CALLBACK(toggle_pause), NULL);
-		GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y);
-		gnt_box_add_widget(GNT_BOX(box), wid);
+	debug.search = gnt_entry_new(purple_prefs_get_string(PREF_ROOT "/filter"));
+	gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Filter: ")));
+	gnt_box_add_widget(GNT_BOX(box), debug.search);
+	g_signal_connect(G_OBJECT(debug.search), "text_changed", G_CALLBACK(update_filter_string), NULL);
 
-		gnt_box_add_widget(GNT_BOX(debug.window), box);
-		GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_GROW_Y);
+	wid = gnt_check_box_new(_("Pause"));
+	g_signal_connect(G_OBJECT(wid), "toggled", G_CALLBACK(toggle_pause), NULL);
+	GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y);
+	gnt_box_add_widget(GNT_BOX(box), wid);
 
-		gnt_widget_set_name(debug.window, "debug-window");
+	gnt_box_add_widget(GNT_BOX(debug.window), box);
+	GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_GROW_Y);
 
-		g_signal_connect(G_OBJECT(debug.window), "destroy", G_CALLBACK(reset_debug_win), NULL);
-		gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(debug.tview), debug.window);
-	}
+	gnt_widget_set_name(debug.window, "debug-window");
+
+	g_signal_connect(G_OBJECT(debug.window), "destroy", G_CALLBACK(reset_debug_win), NULL);
+	gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(debug.tview), debug.window);
 
 	gnt_widget_show(debug.window);
 }
--- a/finch/gntft.c	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/gntft.c	Fri Jun 29 15:03:27 2007 +0000
@@ -262,6 +262,8 @@
 {
 	if (xfer_dialog == NULL)
 		finch_xfer_dialog_new();
+	else
+		gnt_window_present(xfer_dialog->window);
 }
 
 void
--- a/finch/gntnotify.c	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/gntnotify.c	Fri Jun 29 15:03:27 2007 +0000
@@ -304,7 +304,7 @@
 	PurpleAccount *account = g_object_get_data(G_OBJECT(widget), "notify-account");
 	gpointer data = g_object_get_data(G_OBJECT(widget), "notify-data");
 
-	list = gnt_tree_get_selection_text_list(GNT_TREE(widget));
+	list = gnt_tree_get_selection_text_list(GNT_TREE(g_object_get_data(G_OBJECT(widget), "notify-tree")));
 
 	b->callback(purple_account_get_connection(account), list, data);
 	g_list_foreach(list, (GFunc)g_free, NULL);
@@ -335,23 +335,31 @@
 {
 	GntWidget *window, *tree, *box, *button;
 	GList *iter;
+	int columns, i;
 
 	window = gnt_vbox_new(FALSE);
 	gnt_box_set_toplevel(GNT_BOX(window), TRUE);
 	gnt_box_set_title(GNT_BOX(window), title);
-	gnt_box_set_fill(GNT_BOX(window), FALSE);
+	gnt_box_set_fill(GNT_BOX(window), TRUE);
 	gnt_box_set_pad(GNT_BOX(window), 0);
 	gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
 
-	gnt_box_add_widget(GNT_BOX(window),
+	if (primary)
+		gnt_box_add_widget(GNT_BOX(window),
 			gnt_label_new_with_format(primary, GNT_TEXT_FLAG_BOLD));
-	gnt_box_add_widget(GNT_BOX(window),
+	if (secondary)
+		gnt_box_add_widget(GNT_BOX(window),
 			gnt_label_new_with_format(secondary, GNT_TEXT_FLAG_NORMAL));
 
-	tree = gnt_tree_new_with_columns(g_list_length(results->columns));
+	columns = purple_notify_searchresults_get_columns_count(results);
+	tree = gnt_tree_new_with_columns(columns);
 	gnt_tree_set_show_title(GNT_TREE(tree), TRUE);
 	gnt_box_add_widget(GNT_BOX(window), tree);
 
+	for (i = 0; i < columns; i++)
+		gnt_tree_set_column_title(GNT_TREE(tree), i, 
+				purple_notify_searchresults_column_get_title(results, i));
+
 	box = gnt_hbox_new(TRUE);
 
 	for (iter = results->buttons; iter; iter = iter->next)
@@ -389,7 +397,8 @@
 		button = gnt_button_new(text);
 		g_object_set_data(G_OBJECT(button), "notify-account", purple_connection_get_account(gc));
 		g_object_set_data(G_OBJECT(button), "notify-data", data);
-		g_signal_connect_swapped(G_OBJECT(button), "activate",
+		g_object_set_data(G_OBJECT(button), "notify-tree", tree);
+		g_signal_connect(G_OBJECT(button), "activate",
 				G_CALLBACK(notify_button_activated), b);
 
 		gnt_box_add_widget(GNT_BOX(box), button);
--- a/finch/gntplugin.c	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/gntplugin.c	Fri Jun 29 15:03:27 2007 +0000
@@ -242,8 +242,10 @@
 	GList *iter;
 	GList *seen;
 
-	if (plugins.window)
+	if (plugins.window) {
+		gnt_window_present(plugins.window);
 		return;
+	}
 
 	purple_plugins_probe(G_MODULE_SUFFIX);
 
--- a/finch/gntpounce.c	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/gntpounce.c	Fri Jun 29 15:03:27 2007 +0000
@@ -672,6 +672,7 @@
 	GntWidget *win;
 
 	if (pounces_manager != NULL) {
+		gnt_window_present(pounces_manager->window);
 		return;
 	}
 
--- a/finch/gntprefs.c	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/gntprefs.c	Fri Jun 29 15:03:27 2007 +0000
@@ -30,9 +30,16 @@
 #include "gntprefs.h"
 #include "gntrequest.h"
 
+#include "gnt.h"
+#include "gntwidget.h"
+
 #include <string.h>
 
-static GList *freestrings;  /* strings to be freed when the pref-window is closed */
+static struct {
+	GList *freestrings;  /* strings to be freed when the pref-window is closed */
+	gboolean showing;
+	GntWidget *window;
+} pref_request;
 
 void finch_prefs_init()
 {
@@ -98,7 +105,7 @@
 		str = g_strdup_printf("%ld", purple_savedstatus_get_creation_time(iter->data));
 		list = g_list_append(list, (char*)purple_savedstatus_get_title(iter->data));
 		list = g_list_append(list, str);
-		freestrings = g_list_prepend(freestrings, str);
+		pref_request.freestrings = g_list_prepend(pref_request.freestrings, str);
 	}
 	return list;
 }
@@ -190,22 +197,22 @@
 	{PURPLE_PREF_NONE, NULL, NULL, NULL},
 };
 
-/* XXX: Translate after the freeze */
 static Prefs idle[] =
 {
-	{PURPLE_PREF_STRING, "/purple/away/idle_reporting", "Report Idle time", get_idle_options},
-	{PURPLE_PREF_BOOLEAN, "/purple/away/away_when_idle", "Change status when idle", NULL},
-	{PURPLE_PREF_INT, "/purple/away/mins_before_away", "Minutes before changing status", NULL},
-	{PURPLE_PREF_INT, "/purple/savedstatus/idleaway", "Change status to", get_status_titles},
+	{PURPLE_PREF_STRING, "/purple/away/idle_reporting", N_("Report Idle time"), get_idle_options},
+	{PURPLE_PREF_BOOLEAN, "/purple/away/away_when_idle", N_("Change status when idle"), NULL},
+	{PURPLE_PREF_INT, "/purple/away/mins_before_away", N_("Minutes before changing status"), NULL},
+	{PURPLE_PREF_INT, "/purple/savedstatus/idleaway", N_("Change status to"), get_status_titles},
 	{PURPLE_PREF_NONE, NULL, NULL, NULL},
 };
 
 static void
 free_strings()
 {
-	g_list_foreach(freestrings, (GFunc)g_free, NULL);
-	g_list_free(freestrings);
-	freestrings = NULL;
+	g_list_foreach(pref_request.freestrings, (GFunc)g_free, NULL);
+	g_list_free(pref_request.freestrings);
+	pref_request.freestrings = NULL;
+	pref_request.showing = FALSE;
 }
 
 static void
@@ -236,6 +243,11 @@
 {
 	PurpleRequestFields *fields;
 
+	if (pref_request.showing) {
+		gnt_window_present(pref_request.window);
+		return;
+	}
+
 	fields = purple_request_fields_new();
 
 	add_pref_group(fields, _("Buddy List"), blist);
@@ -243,7 +255,8 @@
 	add_pref_group(fields, _("Logging"), logging);
 	add_pref_group(fields, _("Idle"), idle);
 
-	purple_request_fields(NULL, _("Preferences"), NULL, NULL, fields,
+	pref_request.showing = TRUE;
+	pref_request.window = purple_request_fields(NULL, _("Preferences"), NULL, NULL, fields,
 			_("Save"), G_CALLBACK(save_cb), _("Cancel"), free_strings,
 			NULL, NULL, NULL,
 			NULL);
--- a/finch/gntrequest.c	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/gntrequest.c	Fri Jun 29 15:03:27 2007 +0000
@@ -67,8 +67,35 @@
 	return window;
 }
 
+/**
+ * If the window is closed by the wm (ie, without triggering any of
+ * the buttons, then do some default callback.
+ */
+static void
+setup_default_callback(GntWidget *window, gpointer default_cb, gpointer data)
+{
+	g_object_set_data(G_OBJECT(window), "default-callback", default_cb);
+	g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(default_cb), data);
+}
+
+static void
+action_performed(GntWidget *button, gpointer data)
+{
+	g_signal_handlers_disconnect_matched(data, G_SIGNAL_MATCH_FUNC,
+			0, 0, NULL,
+			g_object_get_data(data, "default-callback"),
+			 NULL);
+}
+
+/**
+ * window: this is the window
+ * userdata: the userdata to pass to the primary callbacks
+ * cb: the callback
+ * data: data for the callback
+ * (text, primary-callback) pairs, ended by a NULL
+ */
 static GntWidget *
-setup_button_box(gpointer userdata, gpointer cb, gpointer data, ...)
+setup_button_box(GntWidget *win, gpointer userdata, gpointer cb, gpointer data, ...)
 {
 	GntWidget *box, *button;
 	va_list list;
@@ -86,6 +113,7 @@
 		gnt_box_add_widget(GNT_BOX(box), button);
 		g_object_set_data(G_OBJECT(button), "activate-callback", callback);
 		g_object_set_data(G_OBJECT(button), "activate-userdata", userdata);
+		g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(action_performed), win);
 		g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(cb), data);
 	}
 
@@ -127,10 +155,11 @@
 		gnt_entry_set_masked(GNT_ENTRY(entry), TRUE);
 	gnt_box_add_widget(GNT_BOX(window), entry);
 
-	box = setup_button_box(user_data, notify_input_cb, entry,
+	box = setup_button_box(window, user_data, notify_input_cb, entry,
 			ok_text, ok_cb, cancel_text, cancel_cb, NULL);
 	gnt_box_add_widget(GNT_BOX(window), box);
 
+	setup_default_callback(window, cancel_cb, user_data);
 	gnt_widget_show(window);
 
 	return window;
@@ -189,10 +218,11 @@
 	}
 	gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), GINT_TO_POINTER(default_value + 1));
 
-	box = setup_button_box(user_data, request_choice_cb, combo,
+	box = setup_button_box(window, user_data, request_choice_cb, combo,
 			ok_text, ok_cb, cancel_text, cancel_cb, NULL);
 	gnt_box_add_widget(GNT_BOX(window), box);
 
+	setup_default_callback(window, cancel_cb, user_data);
 	gnt_widget_show(window);
 	
 	return window;
@@ -538,10 +568,11 @@
 	}
 	gnt_box_add_widget(GNT_BOX(window), box);
 
-	box = setup_button_box(userdata, request_fields_cb, allfields,
+	box = setup_button_box(window, userdata, request_fields_cb, allfields,
 			ok, ok_cb, cancel, cancel_cb, NULL);
 	gnt_box_add_widget(GNT_BOX(window), box);
 
+	setup_default_callback(window, cancel_cb, userdata);
 	gnt_widget_show(window);
 
 	g_object_set_data(G_OBJECT(window), "fields", allfields);
--- a/finch/gntstatus.c	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/gntstatus.c	Fri Jun 29 15:03:27 2007 +0000
@@ -163,8 +163,10 @@
 void finch_savedstatus_show_all()
 {
 	GntWidget *window, *tree, *box, *button;
-	if (statuses.window)
+	if (statuses.window) {
+		gnt_window_present(statuses.window);
 		return;
+	}
 
 	statuses.window = window = gnt_vbox_new(FALSE);
 	gnt_box_set_toplevel(GNT_BOX(window), TRUE);
--- a/finch/libgnt/Makefile.am	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/libgnt/Makefile.am	Fri Jun 29 15:03:27 2007 +0000
@@ -26,6 +26,7 @@
 	gntmenu.c \
 	gntmenuitem.c \
 	gntmenuitemcheck.c \
+	gntslider.c \
 	gntstyle.c \
 	gnttextview.c \
 	gnttree.c \
@@ -53,6 +54,7 @@
 	gntmenu.h \
 	gntmenuitem.h \
 	gntmenuitemcheck.h \
+	gntslider.h \
 	gntstyle.h \
 	gnttextview.h \
 	gnttree.h \
--- a/finch/libgnt/gntentry.c	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/libgnt/gntentry.c	Fri Jun 29 15:03:27 2007 +0000
@@ -179,7 +179,7 @@
 
 	stop = gnt_util_onscreen_width(entry->scroll, entry->end);
 	if (stop < widget->priv.width)
-		whline(widget->window, ENTRY_CHAR, widget->priv.width - stop);
+		mvwhline(widget->window, 0, stop, ENTRY_CHAR, widget->priv.width - stop);
 
 	if (focus)
 		mvwchgat(widget->window, 0, gnt_util_onscreen_width(entry->scroll, entry->cursor),
--- a/finch/libgnt/gntlabel.c	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/libgnt/gntlabel.c	Fri Jun 29 15:03:27 2007 +0000
@@ -138,8 +138,7 @@
 
 	if (GNT_WIDGET(label)->window)
 	{
-		gnt_widget_hide(GNT_WIDGET(label));
-		gnt_label_size_request(GNT_WIDGET(label));
+		werase(GNT_WIDGET(label)->window);
 		gnt_widget_draw(GNT_WIDGET(label));
 	}
 }
--- a/finch/libgnt/gntmain.c	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/libgnt/gntmain.c	Fri Jun 29 15:03:27 2007 +0000
@@ -488,8 +488,12 @@
  * Stuff for 'window management' *
  *********************************/
 
-void gnt_window_present(GntWidget *window) {
-	gnt_wm_raise_window(wm, window);
+void gnt_window_present(GntWidget *window)
+{
+	if (wm->event_stack)
+		gnt_wm_raise_window(wm, window);
+	else
+		gnt_widget_set_urgent(window);
 }
 
 void gnt_screen_occupy(GntWidget *widget)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/finch/libgnt/gntslider.c	Fri Jun 29 15:03:27 2007 +0000
@@ -0,0 +1,277 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "gntcolors.h"
+#include "gntkeys.h"
+#include "gntslider.h"
+#include "gntstyle.h"
+
+enum
+{
+	SIG_VALUE_CHANGED,
+	SIGS,
+};
+
+static guint signals[SIGS] = { 0 };
+
+static GntWidgetClass *parent_class = NULL;
+
+/* returns TRUE if the value was changed */
+static gboolean
+sanitize_value(GntSlider *slider)
+{
+	if (slider->current < slider->min)
+		slider->current = slider->min;
+	else if (slider->current > slider->max)
+		slider->current = slider->max;
+	else
+		return FALSE;
+	return TRUE;
+}
+
+static void
+redraw_slider(GntSlider *slider)
+{
+	GntWidget *widget = GNT_WIDGET(slider);
+	if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED))
+		gnt_widget_draw(widget);
+}
+
+static void
+slider_value_changed(GntSlider *slider)
+{
+	g_signal_emit(slider, signals[SIG_VALUE_CHANGED], 0, slider->current);
+}
+
+static void
+gnt_slider_draw(GntWidget *widget)
+{
+	GntSlider *slider = GNT_SLIDER(widget);
+	int attr = 0;
+	int position, size = 0;
+
+	if (slider->vertical)
+		size = widget->priv.height;
+	else
+		size = widget->priv.width;
+
+	if (gnt_widget_has_focus(widget))
+		attr |= GNT_COLOR_HIGHLIGHT;
+	else
+		attr |= GNT_COLOR_HIGHLIGHT_D;
+
+	if (slider->max != slider->min)
+		position = ((size - 1) * (slider->current - slider->min)) / (slider->max - slider->min);
+	else
+		position = 0;
+	if (slider->vertical) {
+		mvwvline(widget->window, size-position, 0, ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL) | A_BOLD,
+				position);
+		mvwvline(widget->window, 0, 0, ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL),
+				size-position);
+	} else {
+		mvwhline(widget->window, 0, 0, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL) | A_BOLD,
+				position);
+		mvwhline(widget->window, 0, position, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL),
+				size - position);
+	}
+
+	mvwaddch(widget->window,
+			slider->vertical ? (size - position - 1) : 0,
+			slider->vertical ? 0 : position,
+			ACS_CKBOARD | COLOR_PAIR(attr));
+}
+
+static void
+gnt_slider_size_request(GntWidget *widget)
+{
+	if (GNT_SLIDER(widget)->vertical) {
+		widget->priv.width = 1;
+		widget->priv.height = 5;
+	} else {
+		widget->priv.width = 5;
+		widget->priv.height = 1;
+	}
+}
+
+static void
+gnt_slider_map(GntWidget *widget)
+{
+	if (widget->priv.width == 0 || widget->priv.height == 0)
+		gnt_widget_size_request(widget);
+	GNTDEBUG;
+}
+
+static gboolean
+step_back(GntBindable *bindable, GList *null)
+{
+	GntSlider *slider = GNT_SLIDER(bindable);
+	if (slider->current <= slider->min)
+		return FALSE;
+	gnt_slider_advance_step(slider, -1);
+	return TRUE;
+}
+
+static gboolean
+step_forward(GntBindable *bindable, GList *list)
+{
+	GntSlider *slider = GNT_SLIDER(bindable);
+	if (slider->current >= slider->max)
+		return FALSE;
+	gnt_slider_advance_step(slider, 1);
+	return TRUE;
+}
+
+static void
+gnt_slider_class_init(GntSliderClass *klass)
+{
+	GntBindableClass *bindable = GNT_BINDABLE_CLASS(klass);
+	parent_class = GNT_WIDGET_CLASS(klass);
+	parent_class->draw = gnt_slider_draw;
+	parent_class->map = gnt_slider_map;
+	parent_class->size_request = gnt_slider_size_request;
+
+	klass->changed = NULL;
+
+	signals[SIG_VALUE_CHANGED] =
+		g_signal_new("changed",
+		             G_TYPE_FROM_CLASS(klass),
+		             G_SIGNAL_RUN_LAST,
+		             G_STRUCT_OFFSET(GntSliderClass, changed),
+		             NULL, NULL,
+		             g_cclosure_marshal_VOID__INT,
+		             G_TYPE_NONE, 1, G_TYPE_INT);
+
+	gnt_bindable_class_register_action(bindable, "step-backward", step_back, GNT_KEY_LEFT, NULL);
+	gnt_bindable_register_binding(bindable, "step-backward", GNT_KEY_DOWN, NULL);
+	gnt_bindable_class_register_action(bindable, "step-forward", step_forward, GNT_KEY_RIGHT, NULL);
+	gnt_bindable_register_binding(bindable, "step-forward", GNT_KEY_UP, NULL);
+
+	/* XXX: how would home/end work? */
+
+	gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass));
+}
+
+static void
+gnt_slider_init(GTypeInstance *instance, gpointer class)
+{
+	GntWidget *widget = GNT_WIDGET(instance);
+	GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_SHADOW | GNT_WIDGET_NO_BORDER | GNT_WIDGET_CAN_TAKE_FOCUS);
+	widget->priv.minw = 1;
+	widget->priv.minh = 1;
+	GNTDEBUG;
+}
+
+/******************************************************************************
+ * GntSlider API
+ *****************************************************************************/
+GType
+gnt_slider_get_gtype(void)
+{
+	static GType type = 0;
+
+	if(type == 0)
+	{
+		static const GTypeInfo info = {
+			sizeof(GntSliderClass),
+			NULL,                   /* base_init        */
+			NULL,                   /* base_finalize    */
+			(GClassInitFunc)gnt_slider_class_init,
+			NULL,                   /* class_finalize   */
+			NULL,                   /* class_data       */
+			sizeof(GntSlider),
+			0,                      /* n_preallocs      */
+			gnt_slider_init,        /* instance_init    */
+			NULL                    /* value_table      */
+		};
+
+		type = g_type_register_static(GNT_TYPE_WIDGET,
+		                              "GntSlider",
+		                              &info, 0);
+	}
+
+	return type;
+}
+
+GntWidget *gnt_slider_new(gboolean vertical, int max, int min)
+{
+	GntWidget *widget = g_object_new(GNT_TYPE_SLIDER, NULL);
+	GntSlider *slider = GNT_SLIDER(widget);
+
+	slider->vertical = vertical;
+
+	if (vertical) {
+		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_Y);
+	} else {
+		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X);
+	}
+
+	gnt_slider_set_range(slider, max, min);
+	slider->step = 1;
+
+	return widget;
+}
+
+void gnt_slider_set_value(GntSlider *slider, int value)
+{
+	if (slider->current == value)
+		return;
+	slider->current = value;
+	sanitize_value(slider);
+	redraw_slider(slider);
+	slider_value_changed(slider);
+}
+
+int gnt_slider_advance_step(GntSlider *slider, int steps)
+{
+	slider->current += steps * slider->step;
+	sanitize_value(slider);
+	redraw_slider(slider);
+	slider_value_changed(slider);
+	return slider->current;
+}
+
+void gnt_slider_set_step(GntSlider *slider, int step)
+{
+	slider->step = step;
+}
+
+void gnt_slider_set_range(GntSlider *slider, int max, int min)
+{
+	slider->max = MAX(max, min);
+	slider->min = MIN(max, min);
+	sanitize_value(slider);
+}
+
+static void
+update_label(GntSlider *slider, int current_value, GntLabel *label)
+{
+	char value[256];
+	g_snprintf(value, sizeof(value), "%d/%d", current_value, slider->max);
+	gnt_label_set_text(label, value);
+}
+
+void gnt_slider_reflect_label(GntSlider *slider, GntLabel *label)
+{
+	g_signal_connect(G_OBJECT(slider), "changed", G_CALLBACK(update_label), label);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/finch/libgnt/gntslider.h	Fri Jun 29 15:03:27 2007 +0000
@@ -0,0 +1,139 @@
+/**
+ * @file gntslider.h Slider API
+ * @ingroup gnt
+ */
+/*
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef GNT_SLIDER_H
+#define GNT_SLIDER_H
+
+#include "gntwidget.h"
+#include "gnt.h"
+#include "gntlabel.h"
+
+#define GNT_TYPE_SLIDER             (gnt_slider_get_gtype())
+#define GNT_SLIDER(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_SLIDER, GntSlider))
+#define GNT_SLIDER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_SLIDER, GntSliderClass))
+#define GNT_IS_SLIDER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_SLIDER))
+#define GNT_IS_SLIDER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_SLIDER))
+#define GNT_SLIDER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_SLIDER, GntSliderClass))
+
+#define GNT_SLIDER_FLAGS(obj)                (GNT_SLIDER(obj)->priv.flags)
+#define GNT_SLIDER_SET_FLAGS(obj, flags)     (GNT_SLIDER_FLAGS(obj) |= flags)
+#define GNT_SLIDER_UNSET_FLAGS(obj, flags)   (GNT_SLIDER_FLAGS(obj) &= ~(flags))
+
+typedef struct _GntSlider			GntSlider;
+typedef struct _GntSliderPriv		GntSliderPriv;
+typedef struct _GntSliderClass		GntSliderClass;
+
+struct _GntSlider
+{
+	GntWidget parent;
+
+	gboolean vertical;
+
+	int max;        /* maximum value */
+	int min;        /* minimum value */
+	int step;       /* amount to change at each step */
+	int current;    /* current value */
+};
+
+struct _GntSliderClass
+{
+	GntWidgetClass parent;
+
+	void (*changed)(GntSlider *slider, int);
+	void (*gnt_reserved1)(void);
+	void (*gnt_reserved2)(void);
+	void (*gnt_reserved3)(void);
+	void (*gnt_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+/**
+ * @return The GType for GntSlider
+ */
+GType gnt_slider_get_gtype(void);
+
+#define gnt_hslider_new(max, min) gnt_slider_new(FALSE, max, min)
+#define gnt_vslider_new(max, min) gnt_slider_new(TRUE, max, min)
+
+/**
+ * Create a new slider.
+ *
+ * @param orient A vertical slider is created if @c TRUE, otherwise the slider is horizontal.
+ * @param max    The maximum value for the slider
+ * @param min    The minimum value for the slider
+ *
+ * @return  The newly created slider
+ */
+GntWidget * gnt_slider_new(gboolean orient, int max, int min);
+
+/**
+ * Set the range of the slider.
+ *
+ * @param slider  The slider
+ * @param max     The maximum value
+ * @param min     The minimum value
+ */
+void gnt_slider_set_range(GntSlider *slider, int max, int min);
+
+/**
+ * Sets the amount of change at each step.
+ * 
+ * @param slider  The slider
+ * @param step    The amount for each ste
+ */
+void gnt_slider_set_step(GntSlider *slider, int step);
+
+/**
+ * Advance the slider forward or backward.
+ *
+ * @param slider   The slider
+ * @param steps    The number of amounts to change, positive to change
+ *                 forward, negative to change backward
+ *
+ * @return   The value of the slider after the change
+ */
+int gnt_slider_advance_step(GntSlider *slider, int steps);
+
+/**
+ * Set the current value for the slider.
+ *
+ * @param slider  The slider
+ * @param value   The current value
+ */
+void gnt_slider_set_value(GntSlider *slider, int value);
+
+/**
+ * Update a label with the value of the slider whenever the value changes.
+ *
+ * @param slider   The slider
+ * @param label    The label to update
+ */
+void gnt_slider_reflect_label(GntSlider *slider, GntLabel *label);
+
+G_END_DECLS
+
+#endif /* GNT_SLIDER_H */
--- a/finch/libgnt/gnttree.c	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/libgnt/gnttree.c	Fri Jun 29 15:03:27 2007 +0000
@@ -1526,6 +1526,12 @@
 	tree->columns[col].width = width;
 }
 
+void gnt_tree_set_column_title(GntTree *tree, int index, const char *title)
+{
+	g_free(tree->columns[index].title);
+	tree->columns[index].title = g_strdup(title);
+}
+
 void gnt_tree_set_column_titles(GntTree *tree, ...)
 {
 	int i;
--- a/finch/libgnt/gnttree.h	Fri Jun 29 15:00:50 2007 +0000
+++ b/finch/libgnt/gnttree.h	Fri Jun 29 15:03:27 2007 +0000
@@ -302,6 +302,15 @@
 void gnt_tree_set_col_width(GntTree *tree, int col, int width);
 
 /**
+ * Set the title for a column.
+ *
+ * @param tree   The tree
+ * @param index  The index of the column
+ * @param title  The title for the column
+ */
+void gnt_tree_set_column_title(GntTree *tree, int index, const char *title);
+
+/**
  * 
  * @param tree
  */