changeset 13907:cc60d0861337

[gaim-migrate @ 16402] This commit has 1234 lines of diff :) Windows can now be moved (alt+m, then the arrow keys, then escape/enter). Add a window to enable/disable accounts. But the 'add' etc. buttons don't have any callbacks yet. I am going to need to do some more widgets (checkbox, combobox) before I do anything else. I have also updated the test programs to work with the changes in libgnt. committer: Tailor Script <tailor@pidgin.im>
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Sun, 02 Jul 2006 22:13:06 +0000
parents b986b6e2441b
children cab785a7c766
files console/Makefile console/gntaccount.c console/gntaccount.h console/gntblist.c console/gntblist.h console/gntconv.c console/gntconv.h console/gntgaim.c console/gntui.c console/libgnt/gnt.h console/libgnt/gntbox.c console/libgnt/gntbox.h console/libgnt/gntbutton.c console/libgnt/gntmain.c console/libgnt/gnttree.c console/libgnt/gnttree.h console/libgnt/gntwidget.c console/libgnt/test/focus.c console/libgnt/test/multiwin.c console/libgnt/test/tv.c
diffstat 20 files changed, 609 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/console/Makefile	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/Makefile	Sun Jul 02 22:13:06 2006 +0000
@@ -3,16 +3,19 @@
 LDFLAGS=`pkg-config --libs gaim gobject-2.0 libxml-2.0 gnt` -pg
 
 GG_SOURCES = \
+	gntaccount.c \
 	gntblist.c \
 	gntconv.c \
 	gntui.c
 
 GG_HEADERS = \
+	gntaccount.h \
 	gntblist.h \
 	gntconv.h \
 	gntui.h
 
 GG_OBJECTS = \
+	gntaccount.o \
 	gntblist.o \
 	gntconv.o \
 	gntui.o
@@ -21,6 +24,7 @@
 
 gntgaim: gntgaim.o $(GG_OBJECTS)
 	$(CC) -o gntgaim gntgaim.o $(GG_OBJECTS) $(LDFLAGS)
+gntaccount.o: gntaccount.c $(GG_HEADERS)
 gntblist.o: gntblist.c $(GG_HEADERS)
 gntconv.o: gntconv.c $(GG_HEADERS)
 gntgaim.o: gntgaim.c gntgaim.h $(GG_HEADERS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/console/gntaccount.c	Sun Jul 02 22:13:06 2006 +0000
@@ -0,0 +1,180 @@
+#include <gnt.h>
+#include <gntbox.h>
+#include <gntbutton.h>
+#include <gntlabel.h>
+#include <gnttree.h>
+
+#include <connection.h>
+#include <notify.h>
+#include <request.h>
+
+#include "gntaccount.h"
+#include "gntgaim.h"
+
+typedef struct
+{
+	GntWidget *window;
+	GntWidget *tree;
+} GGAccountList;
+
+static GGAccountList accounts;
+
+static void
+account_toggled(GntWidget *widget, void *key, gpointer null)
+{
+	GaimAccount *account = key;
+
+	gaim_account_set_enabled(account, GAIM_GNT_UI, gnt_tree_get_choice(GNT_TREE(widget), key));
+}
+
+void gg_accounts_init()
+{
+	GList *iter;
+	GntWidget *box, *button;
+
+	accounts.window = gnt_box_new(TRUE, TRUE);
+	gnt_box_set_toplevel(GNT_BOX(accounts.window), TRUE);
+	gnt_box_set_title(GNT_BOX(accounts.window), _("Accounts"));
+	gnt_widget_set_name(accounts.window, "accounts");
+
+	gnt_box_add_widget(GNT_BOX(accounts.window),
+			gnt_label_new(_("You can enable/disable accounts from the follwing list.")));
+
+	accounts.tree = gnt_tree_new();
+	GNT_WIDGET_SET_FLAGS(accounts.tree, GNT_WIDGET_NO_BORDER);
+
+	for (iter = gaim_accounts_get_all(); iter; iter = iter->next)
+	{
+		GaimAccount *account = iter->data;
+		char *str = g_strdup_printf("%s (%s)",
+				gaim_account_get_username(account), gaim_account_get_protocol_id(account));
+
+		gnt_tree_add_choice(GNT_TREE(accounts.tree), account,
+				str, NULL, NULL);
+		gnt_tree_set_choice(GNT_TREE(accounts.tree), account,
+				gaim_account_get_enabled(account, GAIM_GNT_UI));
+		g_free(str);
+	}
+
+	g_signal_connect(G_OBJECT(accounts.tree), "toggled", G_CALLBACK(account_toggled), NULL);
+	
+	gnt_widget_set_size(accounts.tree, 40, 15);
+	gnt_box_add_widget(GNT_BOX(accounts.window), accounts.tree);
+
+	box = gnt_box_new(FALSE, FALSE);
+
+	button = gnt_button_new(_("Add"));
+	gnt_box_add_widget(GNT_BOX(box), button);
+
+	button = gnt_button_new(_("Modify"));
+	gnt_box_add_widget(GNT_BOX(box), button);
+
+	button = gnt_button_new(_("Delete"));
+	gnt_box_add_widget(GNT_BOX(box), button);
+	
+	gnt_box_add_widget(GNT_BOX(accounts.window), box);
+	
+	gnt_widget_show(accounts.window);
+}
+
+void gg_accounts_uninit()
+{
+	gnt_widget_destroy(accounts.window);
+}
+
+#if 0
+/* The following uiops stuff are copied from gtkaccount.c */
+/* Need to do some work on notify- and request-ui before this works */
+typedef struct
+{
+	GaimAccount *account;
+	char *username;
+	char *alias;
+} AddUserData;
+
+static char *
+make_info(GaimAccount *account, GaimConnection *gc, const char *remote_user,
+          const char *id, const char *alias, const char *msg)
+{
+	if (msg != NULL && *msg == '\0')
+		msg = NULL;
+
+	return g_strdup_printf(_("%s%s%s%s has made %s his or her buddy%s%s"),
+	                       remote_user,
+	                       (alias != NULL ? " ("  : ""),
+	                       (alias != NULL ? alias : ""),
+	                       (alias != NULL ? ")"   : ""),
+	                       (id != NULL
+	                        ? id
+	                        : (gaim_connection_get_display_name(gc) != NULL
+	                           ? gaim_connection_get_display_name(gc)
+	                           : gaim_account_get_username(account))),
+	                       (msg != NULL ? ": " : "."),
+	                       (msg != NULL ? msg  : ""));
+}
+
+static void
+notify_added(GaimAccount *account, const char *remote_user,
+			const char *id, const char *alias,
+			const char *msg)
+{
+	char *buffer;
+	GaimConnection *gc;
+
+	gc = gaim_account_get_connection(account);
+
+	buffer = make_info(account, gc, remote_user, id, alias, msg);
+
+	gaim_notify_info(NULL, NULL, buffer, NULL);
+
+	g_free(buffer);
+}
+
+static void
+request_add(GaimAccount *account, const char *remote_user,
+		  const char *id, const char *alias,
+		  const char *msg)
+{
+	char *buffer;
+	GaimConnection *gc;
+	AddUserData *data;
+
+	gc = gaim_account_get_connection(account);
+
+	data = g_new0(AddUserData, 1);
+	data->account  = account;
+	data->username = g_strdup(remote_user);
+	data->alias    = (alias != NULL ? g_strdup(alias) : NULL);
+
+	buffer = make_info(account, gc, remote_user, id, alias, msg);
+#if 0
+	gaim_request_action(NULL, NULL, _("Add buddy to your list?"),
+	                    buffer, GAIM_DEFAULT_ACTION_NONE, data, 2,
+	                    _("Add"),    G_CALLBACK(add_user_cb),
+	                    _("Cancel"), G_CALLBACK(free_add_user_data));
+#endif
+	g_free(buffer);
+}
+
+static GaimAccountUiOps ui_ops = 
+{
+	.notify_added = notify_added,
+	.status_changed = NULL,
+	.request_add  = request_add
+};
+#else
+
+static GaimAccountUiOps ui_ops = 
+{
+	.notify_added = NULL,
+	.status_changed = NULL,
+	.request_add  = NULL
+};
+
+#endif
+
+GaimAccountUiOps *gg_accounts_get_ui_ops()
+{
+	return &ui_ops;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/console/gntaccount.h	Sun Jul 02 22:13:06 2006 +0000
@@ -0,0 +1,7 @@
+#include "account.h"
+
+GaimAccountUiOps *gg_accounts_get_ui_ops();
+
+void gg_accounts_init();
+
+void gg_accounts_uninit();
--- a/console/gntblist.c	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/gntblist.c	Sun Jul 02 22:13:06 2006 +0000
@@ -440,3 +440,11 @@
 	g_signal_connect(G_OBJECT(ggblist->tree), "activate", G_CALLBACK(selection_activate), ggblist);
 }
 
+void gg_blist_uninit()
+{
+	gnt_widget_destroy(ggblist->window);
+	g_free(ggblist);
+	ggblist = NULL;
+}
+
+
--- a/console/gntblist.h	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/gntblist.h	Sun Jul 02 22:13:06 2006 +0000
@@ -3,3 +3,5 @@
 GaimBlistUiOps * gg_blist_get_ui_ops();
 
 void gg_blist_init();
+
+void gg_blist_uninit();
--- a/console/gntconv.c	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/gntconv.c	Sun Jul 02 22:13:06 2006 +0000
@@ -165,7 +165,8 @@
 
 	g_free(strip);
 
-	gnt_widget_set_urgent(ggconv->tv);
+	if (flags & (GAIM_MESSAGE_RECV | GAIM_MESSAGE_NICK | GAIM_MESSAGE_ERROR))
+		gnt_widget_set_urgent(ggconv->tv);
 }
 
 static void
@@ -261,3 +262,9 @@
 	ggconvs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, destroy_ggconv);
 }
 
+void gg_conversation_uninit()
+{
+	g_hash_table_destroy(ggconvs);
+	ggconvs = NULL;
+}
+
--- a/console/gntconv.h	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/gntconv.h	Sun Jul 02 22:13:06 2006 +0000
@@ -3,3 +3,5 @@
 GaimConversationUiOps *gg_conv_get_ui_ops();
 
 void gg_conversation_init();
+
+void gg_conversation_uninit();
--- a/console/gntgaim.c	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/gntgaim.c	Sun Jul 02 22:13:06 2006 +0000
@@ -178,7 +178,7 @@
 	/* Enable the accounts and restore the status */
 	gaim_accounts_restore_current_statuses();
 
-	/* Initialize the UI */
+	/* Initialize and run the UI */
 	init_gnt_ui();
 
 	gaim_core_quit();
--- a/console/gntui.c	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/gntui.c	Sun Jul 02 22:13:06 2006 +0000
@@ -1,4 +1,6 @@
 #include "gntui.h"
+
+#include "gntaccount.h"
 #include "gntblist.h"
 #include "gntconv.h"
 
@@ -6,9 +8,9 @@
 {
 	gnt_init();
 
-	wbkgdset(stdscr, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL));
-	werase(stdscr);
-	wrefresh(stdscr);
+	/* Accounts */
+	gg_accounts_init();
+	gaim_accounts_set_ui_ops(gg_accounts_get_ui_ops());
 
 	/* Initialize the buddy list */
 	gg_blist_init();
@@ -19,5 +21,16 @@
 	gaim_conversations_set_ui_ops(gg_conv_get_ui_ops());
 
 	gnt_main();
+
+	gaim_accounts_set_ui_ops(NULL);
+	gg_accounts_uninit();
+
+	gaim_blist_set_ui_ops(NULL);
+	gg_blist_uninit();
+
+	gaim_conversations_set_ui_ops(NULL);
+	gg_conversation_uninit();
+
+	gnt_quit();
 }
 
--- a/console/libgnt/gnt.h	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/libgnt/gnt.h	Sun Jul 02 22:13:06 2006 +0000
@@ -18,3 +18,6 @@
 gboolean gnt_widget_has_focus(GntWidget *widget);
 
 void gnt_widget_set_urgent(GntWidget *widget);
+
+void gnt_quit();
+
--- a/console/libgnt/gntbox.c	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/libgnt/gntbox.c	Sun Jul 02 22:13:06 2006 +0000
@@ -13,10 +13,25 @@
 static GntWidget * find_focusable_widget(GntBox *box);
 
 static void
+add_to_focus(gpointer value, gpointer data)
+{
+	GntBox *box = GNT_BOX(data);
+	GntWidget *w = GNT_WIDGET(value);
+
+	if (GNT_IS_BOX(w))
+		g_list_foreach(GNT_BOX(w)->list, add_to_focus, box);
+	else if (GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_CAN_TAKE_FOCUS))
+		box->focus = g_list_append(box->focus, w);
+}
+
+static void
 gnt_box_draw(GntWidget *widget)
 {
 	GntBox *box = GNT_BOX(widget);
 
+	if (box->focus == NULL && widget->parent == NULL)
+		g_list_foreach(box->list, add_to_focus, box);
+
 	g_list_foreach(box->list, (GFunc)gnt_widget_draw, NULL);
 
 	gnt_box_sync_children(box);
@@ -152,12 +167,18 @@
 	DEBUG;
 }
 
+#if 0
 static GntWidget *
 find_next_focus(GntBox *box)
 {
 	GntWidget *w = box->active;
 	GList *iter;
 
+	if (w == NULL)
+	{
+		return find_focusable_widget(box);
+	}
+
 	while (w && !(iter = g_list_find(box->list, w)))
 		w = w->parent;
 
@@ -167,12 +188,20 @@
 	{
 		GntWidget *next = NULL;
 		
-		do
+		while (!next && (iter = iter->next))
 		{
-			next = find_next_focus(iter->data);
-			box->active = next;
-			iter = iter->next;
-		} while (!next && iter);
+			if (GNT_IS_BOX(iter->data))
+				next = find_next_focus(iter->data);
+			else
+			{
+				if (GNT_WIDGET_IS_FLAG_SET(iter->data, GNT_WIDGET_CAN_TAKE_FOCUS) &&
+						GNT_WIDGET_IS_FLAG_SET(iter->data, GNT_WIDGET_HAS_FOCUS))
+					next = iter->data;
+				else
+					next = NULL;
+			}
+		}
+		box->active = next;
 	}
 
 	if (box->active == NULL && GNT_WIDGET(box)->parent == NULL)
@@ -185,16 +214,21 @@
 
 	return box->active;
 }
+#endif
 
 /* Ensures that the current widget can take focus */
 static GntWidget *
 find_focusable_widget(GntBox *box)
 {
-	int investigated = 0;
-	int total;
-	GntWidget *w = NULL;
-	GList *iter;
+	if (box->focus == NULL && GNT_WIDGET(box)->parent == NULL)
+		g_list_foreach(box->list, add_to_focus, box);
 
+	if (box->active == NULL && box->focus)
+		box->active = box->focus->data;
+
+	return box->active;
+
+#if 0
 	for (iter = box->list; iter; iter = iter->next)
 	{
 		w = iter->data;
@@ -248,6 +282,7 @@
 	if (w && w != box->active->data)
 		gnt_widget_set_focus(w, FALSE);
 #endif
+#endif
 }
 
 static gboolean
@@ -263,35 +298,44 @@
 	
 	if (text[0] == 27)
 	{
-#if 0
-		GList *now = NULL;
+		GntWidget *now = box->active;
 		if (strcmp(text+1, GNT_KEY_LEFT) == 0)
 		{
-			now = box->active->prev;
-			if (now == NULL)
-				now = g_list_last(box->list);
+			GList *iter = g_list_find(box->focus, box->active);
+			if ((!iter || !iter->prev) && box->focus)
+			{
+				box->active = box->focus->data;
+			}
+			else
+			{
+				box->active = iter->prev->data;
+			}
 		}
 		else if (strcmp(text+1, GNT_KEY_RIGHT) == 0)
 		{
-			now = box->active->next;
-			if (now == NULL)
-				now = box->list;
+			GList *iter = g_list_find(box->focus, box->active);
+			if (iter && iter->next)
+			{
+				box->active = iter->next->data;
+			}
+			else if (box->focus)
+			{
+				box->active = box->focus->data;
+			}
 		}
 
 		if (now && now != box->active)
 		{
-			gnt_widget_set_focus(box->active->data, FALSE);
-			box->active = now;
-			gnt_widget_set_focus(box->active->data, TRUE);
-
+			gnt_widget_set_focus(now, FALSE);
+			gnt_widget_set_focus(box->active, TRUE);
 			return TRUE;
 		}
-#endif
 	}
 
 	return FALSE;
 }
 
+#if 0
 static GntWidget *find_focused_widget(GntBox *box)
 {
 	GList *iter;
@@ -314,6 +358,7 @@
 	}
 	return NULL;
 }
+#endif
 
 #if 0
 static void
@@ -483,6 +528,10 @@
 	for (iter = box->list; iter; iter = iter->next)
 	{
 		GntWidget *w = GNT_WIDGET(iter->data);
+
+		if (GNT_IS_BOX(w))
+			gnt_box_sync_children(GNT_BOX(w));
+
 		copywin(w->window, widget->window, 0, 0,
 				w->priv.y - widget->priv.y,
 				w->priv.x - widget->priv.x,
--- a/console/libgnt/gntbox.h	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/libgnt/gntbox.h	Sun Jul 02 22:13:06 2006 +0000
@@ -26,6 +26,7 @@
 	int pad;			/* Number of spaces to use between widgets */
 
 	char *title;
+	GList *focus;		/* List of widgets to cycle focus (only valid for parent boxes) */
 
     void (*gnt_reserved1)(void);
     void (*gnt_reserved2)(void);
--- a/console/libgnt/gntbutton.c	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/libgnt/gntbutton.c	Sun Jul 02 22:13:06 2006 +0000
@@ -16,10 +16,11 @@
 	GntButton *button = GNT_BUTTON(widget);
 	GntColorType type;
 
-	if (GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_HAS_FOCUS)
+	if (gnt_widget_has_focus(widget))
 		type = GNT_COLOR_HIGHLIGHT;
 	else
 		type = GNT_COLOR_NORMAL;
+	
 	wbkgdset(widget->window, '\0' | COLOR_PAIR(type));
 	mvwprintw(widget->window, 1, 1, button->priv->text);
 
--- a/console/libgnt/gntmain.c	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/libgnt/gntmain.c	Sun Jul 02 22:13:06 2006 +0000
@@ -10,8 +10,12 @@
 #include <string.h>
 
 static GList *focus_list;
-static int max_x;
-static int max_y;
+static int X_MIN;
+static int X_MAX;
+static int Y_MIN;
+static int Y_MAX;
+
+static GMainLoop *loop;
 
 typedef struct
 {
@@ -20,6 +24,14 @@
 	GList *above;		/* List of widgets above me */
 } GntNode;
 
+typedef enum
+{
+	GNT_KP_MODE_NORMAL,
+	GNT_KP_MODE_RESIZE,
+	GNT_KP_MODE_MOVE,
+	GNT_KP_MODE_MENU,
+} GntKeyPressMode;
+
 static GHashTable *nodes;
 
 static void free_node(gpointer data);
@@ -28,9 +40,15 @@
 void gnt_screen_take_focus(GntWidget *widget)
 {
 	GntWidget *w = NULL;
+
 	if (focus_list)
 		w = focus_list->data;
-	focus_list = g_list_prepend(focus_list, widget);
+
+	/* XXX: ew */
+	focus_list = g_list_first(focus_list);
+	focus_list = g_list_append(focus_list, widget);
+	focus_list = g_list_find(focus_list, widget);
+
 	gnt_widget_set_focus(widget, TRUE);
 	if (w)
 		gnt_widget_set_focus(w, FALSE);
@@ -39,7 +57,18 @@
 
 void gnt_screen_remove_widget(GntWidget *widget)
 {
+	int pos = g_list_index(g_list_first(focus_list), widget);
+	GList *next;
+
+	if (pos == -1)
+		return;
+
+	focus_list = g_list_first(focus_list);
 	focus_list = g_list_remove(focus_list, widget);
+	next = g_list_nth(focus_list, pos - 1);
+	if (next)
+		focus_list = next;
+
 	if (focus_list)
 	{
 		gnt_widget_set_focus(focus_list->data, TRUE);
@@ -82,6 +111,7 @@
 		taskbar = newwin(1, getmaxx(stdscr), getmaxy(stdscr) - 1, 0);
 	}
 
+	wbkgdset(taskbar, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL));
 	werase(taskbar);
 
 	n = g_list_length(g_list_first(focus_list));
@@ -116,10 +146,45 @@
 	wrefresh(taskbar);
 }
 
+static void
+switch_window(int direction)
+{
+	GntWidget *w = NULL;
+	if (focus_list)
+		w = focus_list->data;
+
+	if (direction == 1)
+	{
+		if (focus_list && focus_list->next)
+			focus_list = focus_list->next;
+		else
+			focus_list = g_list_first(focus_list);
+	}
+	else if (direction == -1)
+	{
+		if (focus_list && focus_list->prev)
+			focus_list = focus_list->prev;
+		else
+			focus_list = g_list_last(focus_list);
+	}
+	
+	if (focus_list)
+	{
+		gnt_widget_set_focus(focus_list->data, TRUE);
+		bring_on_top(focus_list->data);
+		gnt_widget_draw(focus_list->data);
+	}
+
+	if (w && (!focus_list || w != focus_list->data))
+		gnt_widget_set_focus(w, FALSE);
+}		
+
 static gboolean
 io_invoke(GIOChannel *source, GIOCondition cond, gpointer null)
 {
 	char buffer[256];
+	static GntKeyPressMode mode = GNT_KP_MODE_NORMAL;
+	gboolean ret = FALSE;
 
 	int rd = read(0, buffer, sizeof(buffer) - 1);
 	if (rd < 0)
@@ -137,52 +202,109 @@
 
 	buffer[rd] = 0;
 
-	if (focus_list)
-	{
-		gboolean ret = FALSE;
-		ret = gnt_widget_key_pressed(focus_list->data, buffer);
-	}
-
-	if (buffer[0] == 27)
+	if (mode == GNT_KP_MODE_NORMAL)
 	{
-		/* Some special key has been pressed */
-		if (strcmp(buffer+1, GNT_KEY_POPUP) == 0)
-		{}
-		else if (strcmp(buffer + 1, "c") == 0)
+		if (focus_list)
+		{
+			ret = gnt_widget_key_pressed(focus_list->data, buffer);
+		}
+
+		if (!ret)
 		{
-			/* Alt + c was pressed. I am going to use it to close a window. */
-			if (focus_list)
+			if (buffer[0] == 27)
 			{
-				gnt_widget_destroy(focus_list->data);
-				gnt_screen_remove_widget(focus_list->data);
+				/* Some special key has been pressed */
+				if (strcmp(buffer+1, GNT_KEY_POPUP) == 0)
+				{}
+				else if (strcmp(buffer + 1, "c") == 0)
+				{
+					/* Alt + c was pressed. I am going to use it to close a window. */
+					if (focus_list)
+					{
+						gnt_widget_destroy(focus_list->data);
+					}
+				}
+				else if (strcmp(buffer + 1, "q") == 0)
+				{
+					/* I am going to use Alt + q to quit. */
+					g_main_loop_quit(loop);
+				}
+				else if (strcmp(buffer + 1, "n") == 0)
+				{
+					/* Alt + n to go to the next window */
+					switch_window(1);
+				}
+				else if (strcmp(buffer + 1, "p") == 0)
+				{
+					/* Alt + p to go to the previous window */
+					switch_window(-1);
+				}
+				else if (strcmp(buffer + 1, "m") == 0 && focus_list)
+				{
+					mode = GNT_KP_MODE_MOVE;
+				}
 			}
 		}
-		else if (strcmp(buffer + 1, "q") == 0)
-		{
-			/* I am going to use Alt + q to quit. */
-			endwin();
-			exit(1);
-		}
-		else if (strcmp(buffer + 1, "n") == 0)
+	}
+	else if (mode == GNT_KP_MODE_MOVE && focus_list)
+	{
+		if (buffer[0] == 27)
 		{
-			/* Alt + n to go to the next window */
-			GntWidget *w = NULL;
-			if (focus_list)
-				w = focus_list->data;
+			gboolean changed = FALSE;
+			int x, y, w, h;
+			GntWidget *widget = GNT_WIDGET(focus_list->data);
+
+			gnt_widget_get_position(widget, &x, &y);
+			gnt_widget_get_size(widget, &w, &h);
 
-			if (focus_list && focus_list->next)
-				focus_list = focus_list->next;
-			else
-				focus_list = g_list_first(focus_list);
-			if (focus_list)
+			if (strcmp(buffer + 1, GNT_KEY_LEFT) == 0)
+			{
+				if (x > X_MIN)
+				{
+					x--;
+					changed = TRUE;
+				}
+			}
+			else if (strcmp(buffer + 1, GNT_KEY_RIGHT) == 0)
+			{
+				if (x + w < X_MAX)
+				{
+					x++;
+					changed = TRUE;
+				}
+			}
+			else if (strcmp(buffer + 1, GNT_KEY_UP) == 0)
 			{
-				gnt_widget_set_focus(focus_list->data, TRUE);
-				bring_on_top(focus_list->data);
-				gnt_widget_draw(focus_list->data);
+				if (y > Y_MIN)
+				{
+					y--;
+					changed = TRUE;
+				}						
+			}
+			else if (strcmp(buffer + 1, GNT_KEY_DOWN) == 0)
+			{
+				if (y + h < Y_MAX)
+				{
+					y++;
+					changed = TRUE;
+				}
+			}
+			else if (buffer[1] == 0)
+			{
+				mode = GNT_KP_MODE_NORMAL;
+				changed = TRUE;
 			}
 
-			if (w && w != focus_list->data)
-				gnt_widget_set_focus(w, FALSE);
+			if (changed)
+			{
+				gnt_widget_hide(widget);
+				gnt_widget_set_position(widget, x, y);
+				gnt_widget_show(widget);
+			}
+		}
+		else if (*buffer == '\r')
+		{
+			mode = GNT_KP_MODE_NORMAL;
 		}
 	}
 
@@ -209,8 +331,10 @@
 	start_color();
 	gnt_init_colors();
 
-	max_x = getmaxx(stdscr);
-	max_y = getmaxy(stdscr);
+	X_MIN = 0;
+	Y_MIN = 0;
+	X_MAX = getmaxx(stdscr);
+	Y_MAX = getmaxy(stdscr) - 1;
 
 	nodes = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_node);
 
@@ -218,13 +342,17 @@
 	noecho();
 	refresh();
 	mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL);
+	wbkgdset(stdscr, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL));
+	werase(stdscr);
+	wrefresh(stdscr);
+
 	g_type_init();
 }
 
 void gnt_main()
 {
-	GMainLoop *loop = g_main_new(FALSE);
-	g_main_run(loop);
+	loop = g_main_loop_new(NULL, FALSE);
+	g_main_loop_run(loop);
 }
 
 /*********************************
@@ -290,6 +418,9 @@
 	WINDOW *win;
 	GList *iter;
 	GntNode *node = g_hash_table_lookup(nodes, widget);
+
+	gnt_screen_remove_widget(widget);
+
 	if (node == NULL)	/* Yay! Nothing to do. */
 		return;
 
@@ -384,15 +515,15 @@
 
 	while (widget->parent)
 	{
-		fprintf(stderr, "%p %p\n", widget, widget->parent);
 		widget = widget->parent;
 	}
-	fprintf(stderr, "%p %p\n", widget, widget->parent);
 
-	if (focus_list && focus_list->data == widget &&
-			(!GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_CAN_TAKE_FOCUS) ||
-			GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_HAS_FOCUS)))
-		return TRUE;
+	if (focus_list && focus_list->data == widget)
+	{
+		if (GNT_IS_BOX(widget) &&
+				(GNT_BOX(widget)->active == w || widget == w))
+			return TRUE;
+	}
 
 	return FALSE;
 }
@@ -409,3 +540,8 @@
 	draw_taskbar();
 }
 
+void gnt_quit()
+{
+	endwin();
+}
+
--- a/console/libgnt/gnttree.c	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/libgnt/gnttree.c	Sun Jul 02 22:13:06 2006 +0000
@@ -7,6 +7,7 @@
 {
 	SIG_SELECTION_CHANGED,
 	SIG_SCROLLED,
+	SIG_TOGGLED,
 	SIGS,
 };
 
@@ -21,6 +22,9 @@
 	void *data;		/* XXX: unused */
 
 	gboolean collapsed;
+	gboolean choice;            /* Is this a choice-box?
+	                               If choice is true, then child will be NULL */
+	gboolean isselected;
 
 	GntTreeRow *parent;
 	GntTreeRow *child;
@@ -188,6 +192,10 @@
 			else
 				strcpy(format, "- ");
 		}
+		else if (row->choice)
+		{
+			g_snprintf(format, sizeof(format) - 1, "[%c] ", row->isselected ? 'X' : ' ');
+		}
 
 		if ((wr = g_snprintf(str, widget->priv.width, "%s%s", format, row->text)) >= widget->priv.width)
 		{
@@ -206,7 +214,7 @@
 			if (gnt_widget_has_focus(widget))
 				wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT));
 			else
-				wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D)); /* XXX: This, somehow, doesn't work */
+				wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D));
 			mvwprintw(widget->window, start, pos, str);
 			wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL));
 		}
@@ -306,10 +314,19 @@
 			row->collapsed = !row->collapsed;
 			redraw_tree(tree);
 		}
+		else if (row && row->choice)
+		{
+			row->isselected = !row->isselected;
+			g_signal_emit(tree, signals[SIG_TOGGLED], 0, row->key);
+			redraw_tree(tree);
+		}
 	}
 
 	if (old != tree->current)
+	{
 		tree_selection_changed(tree, old, tree->current);
+		return TRUE;
+	}
 
 	return FALSE;
 }
@@ -349,6 +366,14 @@
 					 NULL, NULL,
 					 g_cclosure_marshal_VOID__INT,
 					 G_TYPE_NONE, 1, G_TYPE_INT);
+	signals[SIG_TOGGLED] = 
+		g_signal_new("toggled",
+					 G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST,
+					 0,
+					 NULL, NULL,
+					 g_cclosure_marshal_VOID__POINTER,
+					 G_TYPE_NONE, 1, G_TYPE_POINTER);
 
 	DEBUG;
 }
@@ -616,4 +641,39 @@
 	}
 }
 
+GntTreeRow *gnt_tree_add_choice(GntTree *tree, void *key, const char *text, void *parent, void *bigbro)
+{
+	GntTreeRow *row;
 
+	row = g_hash_table_lookup(tree->hash, key);
+	g_return_val_if_fail(!row || !row->choice, NULL);
+		
+	row = gnt_tree_add_row_after(tree, key, text, parent, bigbro);
+	row->choice = TRUE;
+
+	return row;
+}
+
+void gnt_tree_set_choice(GntTree *tree, void *key, gboolean set)
+{
+	GntTreeRow *row = g_hash_table_lookup(tree->hash, key);
+
+	if (!row)
+		return;
+	g_return_if_fail(row->choice);
+
+	row->isselected = set;
+	redraw_tree(tree);
+}
+
+gboolean gnt_tree_get_choice(GntTree *tree, void *key)
+{
+	GntTreeRow *row = g_hash_table_lookup(tree->hash, key);
+
+	if (!row)
+		return;
+	g_return_val_if_fail(row->choice, FALSE);
+
+	return row->isselected;
+}
+
--- a/console/libgnt/gnttree.h	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/libgnt/gnttree.h	Sun Jul 02 22:13:06 2006 +0000
@@ -73,6 +73,12 @@
 
 void gnt_tree_change_text(GntTree *tree, gpointer key, const char *text);
 
+GntTreeRow *gnt_tree_add_choice(GntTree *tree, void *key, const char *text, void *parent, void *bigbro);
+
+void gnt_tree_set_choice(GntTree *tree, void *key, gboolean set);
+
+gboolean gnt_tree_get_choice(GntTree *tree, void *key);
+
 G_END_DECLS
 
 #endif /* GNT_TREE_H */
--- a/console/libgnt/gntwidget.c	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/libgnt/gntwidget.c	Sun Jul 02 22:13:06 2006 +0000
@@ -239,11 +239,11 @@
 gnt_widget_show(GntWidget *widget)
 {
 	/* Draw the widget and take focus */
-	gnt_widget_draw(widget);
 	if (GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_CAN_TAKE_FOCUS)
 	{
 		gnt_widget_take_focus(widget);
 	}
+	gnt_widget_draw(widget);
 }
 
 void
@@ -267,7 +267,7 @@
 		widget->window = newwin(widget->priv.height, widget->priv.width,
 						widget->priv.y, widget->priv.x);
 		wbkgd(widget->window, COLOR_PAIR(GNT_COLOR_NORMAL));
-	
+
 		if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_NO_BORDER))
 			box(widget->window, 0, 0);
 		else
@@ -316,8 +316,8 @@
 gnt_widget_hide(GntWidget *widget)
 {
 	wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL));
-	werase(widget->window);
 	gnt_screen_release(widget);
+	GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_MAPPED);
 }
 
 void
@@ -326,6 +326,8 @@
 	/* XXX: Need to install properties for these and g_object_notify */
 	wid->priv.x = x;
 	wid->priv.y = y;
+	if (wid->window)
+		mvwin(wid->window, y, x);
 	g_signal_emit(wid, signals[SIG_POSITION], 0, x, y);
 }
 
--- a/console/libgnt/test/focus.c	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/libgnt/test/focus.c	Sun Jul 02 22:13:06 2006 +0000
@@ -6,44 +6,79 @@
 #include "gntentry.h"
 #include "gntlabel.h"
 
+static void
+toggled(GntWidget *tree, gpointer key, gpointer null)
+{
+	GntWidget *w = gnt_box_new(FALSE, FALSE);
+
+	gnt_box_set_toplevel(GNT_BOX(w), TRUE);
+
+	gnt_box_add_widget(GNT_BOX(w),
+			gnt_label_new(gnt_tree_get_choice(GNT_TREE(tree), key) ? "Selected" : "NOT"));
+	gnt_widget_show(w);
+}
+
 int main()
 {
 	gnt_init();
 
 	GntWidget *label = gnt_label_new("So wassup dudes and dudettes!!\nSo this is, like,\nthe third line!! \\o/");
-	GntWidget *vbox, *hbox, *tree;
+	GntWidget *vbox, *hbox, *tree, *box, *button;
 	WINDOW *test;
 
 	box(stdscr, 0, 0);
 	wrefresh(stdscr);
 
 	vbox = gnt_box_new(FALSE, FALSE);
-	hbox = gnt_box_new(FALSE, TRUE);
+	hbox = gnt_box_new(TRUE, TRUE);
 
 	gnt_widget_set_name(vbox, "vbox");
 	gnt_widget_set_name(hbox, "hbox");
 
 	gnt_box_add_widget(GNT_BOX(hbox), label);
-	gnt_box_add_widget(GNT_BOX(hbox), vbox);
+
+	GntWidget *entry = gnt_entry_new("a");
+	gnt_widget_set_name(entry, "entry");
+	gnt_box_add_widget(GNT_BOX(hbox), entry);
 
-	gnt_box_add_widget(GNT_BOX(hbox), gnt_entry_new("a"));
-
+	box = gnt_box_new(FALSE, FALSE);
 	tree = gnt_tree_new();
-	gnt_box_add_widget(GNT_BOX(hbox), tree);
+	gnt_widget_set_name(tree, "tree");
+	gnt_box_add_widget(GNT_BOX(box), tree);
+	gnt_box_add_widget(GNT_BOX(hbox), box);
 
 	gnt_tree_add_row_after(GNT_TREE(tree), "a", "a", NULL, NULL);
 	gnt_tree_add_row_after(GNT_TREE(tree), "c", "c", NULL, NULL);
 	gnt_tree_add_row_after(GNT_TREE(tree), "d", "d", NULL, NULL);
 	gnt_tree_add_row_after(GNT_TREE(tree), "e", "e", "a", NULL);
-	gnt_tree_add_row_after(GNT_TREE(tree), "b", "b", "d", NULL);
+	gnt_tree_add_choice(GNT_TREE(tree), "b", "b", "d", NULL);
 
 	GNT_WIDGET_UNSET_FLAGS(hbox, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW);
 	gnt_box_set_title(GNT_BOX(hbox), "This is the title …");
 
+
+	g_signal_connect(G_OBJECT(tree), "toggled", G_CALLBACK(toggled), NULL);
+
+	button = gnt_button_new("one");
+	gnt_widget_set_name(button, "one");
+	gnt_box_add_widget(GNT_BOX(vbox), button);
+
+	button = gnt_button_new("two");
+	gnt_widget_set_name(button, "two");
+	gnt_box_add_widget(GNT_BOX(vbox), button);
+
+	button = gnt_button_new("three");
+	gnt_widget_set_name(button, "three");
+	gnt_box_add_widget(GNT_BOX(vbox), button);
+
+	gnt_box_add_widget(GNT_BOX(hbox), vbox);
+	
 	gnt_widget_show(hbox);
 
 	gnt_main();
 
+	gnt_quit();
+
 	return 0;
 }
 
--- a/console/libgnt/test/multiwin.c	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/libgnt/test/multiwin.c	Sun Jul 02 22:13:06 2006 +0000
@@ -49,7 +49,7 @@
 	gnt_tree_add_row_after(GNT_TREE(tree), "e", "e", "a", NULL);
 	gnt_tree_add_row_after(GNT_TREE(tree), "b", "b", "d", NULL);
 
-	gnt_tree_add_row_after(GNT_TREE(tree), "1", "1", NULL, NULL);
+	gnt_tree_add_choice(GNT_TREE(tree), "1", "1", NULL, NULL);
 	gnt_tree_add_row_after(GNT_TREE(tree), "2", "2", NULL, NULL);
 	gnt_tree_add_row_after(GNT_TREE(tree), "3", "3", NULL, NULL);
 	gnt_tree_add_row_after(GNT_TREE(tree), "4", "4", "a", NULL);
@@ -60,6 +60,8 @@
 
 	gnt_main();
 
+	gnt_quit();
+
 	return 0;
 }
 
--- a/console/libgnt/test/tv.c	Sun Jul 02 21:52:06 2006 +0000
+++ b/console/libgnt/test/tv.c	Sun Jul 02 22:13:06 2006 +0000
@@ -66,6 +66,8 @@
 
 	gnt_main();
 
+	gnt_quit();
+
 	return 0;
 }