changeset 10325:1657438d537b

[gaim-migrate @ 11532] I wanted to get this out of my local tree. I don't know how much of this we'll end up using, but I have a feeling we can use some of it. I think it's hard to know what UI will work best without actually using a few of them... I'm going to try to get reading from status.xml working again this week. I think we'll be able to use the same format, just extend it a little bit. If anyone has done any work on that please let me know so I don't duplicate anyone's work. I imagine I'll start by seeing how much of the old status.xml-reading code is usable (I'm guessing a lot of it). committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Tue, 07 Dec 2004 04:59:27 +0000
parents 1034e77ff0ce
children 72f671a4e153
files src/Makefile.am src/Makefile.mingw src/gtkblist.c src/gtkstatus.c src/gtkstatus.h
diffstat 5 files changed, 691 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/src/Makefile.am	Mon Dec 06 01:03:38 2004 +0000
+++ b/src/Makefile.am	Tue Dec 07 04:59:27 2004 +0000
@@ -168,6 +168,7 @@
 	gtkroomlist.c \
 	gtksound.c \
 	gtksourceiter.c \
+	gtkstatus.c \
 	gtkstatusselector.c \
 	gtkstock.c \
 	gtkthemes.c \
@@ -203,6 +204,7 @@
 	gtkroomlist.h \
 	gtksound.h \
 	gtksourceiter.h \
+	gtkstatus.h \
 	gtkstatusselector.h \
 	gtkstock.h \
 	gtkutils.h \
--- a/src/Makefile.mingw	Mon Dec 06 01:03:38 2004 +0000
+++ b/src/Makefile.mingw	Tue Dec 07 04:59:27 2004 +0000
@@ -113,6 +113,7 @@
 			gtkroomlist.c \
 			gtksound.c \
 			gtksourceiter.c \
+			gtkstatus.c \
 			gtkstatusselector.c \
 			gtkstock.c \
 			gtkthemes.c \
--- a/src/gtkblist.c	Mon Dec 06 01:03:38 2004 +0000
+++ b/src/gtkblist.c	Tue Dec 07 04:59:27 2004 +0000
@@ -52,11 +52,10 @@
 #include "gtkprivacy.h"
 #include "gtkroomlist.h"
 #include "gtksound.h"
+#include "gtkstatus.h"
 #include "gtkstatusselector.h"
 #include "gtkutils.h"
 
-#include "gaim.h"
-
 #include <gdk/gdkkeysyms.h>
 #include <gtk/gtk.h>
 #include <gdk/gdk.h>
@@ -107,7 +106,6 @@
 
 
 static GtkWidget *protomenu = NULL;
-static GtkWidget *awaymenu = NULL;
 static GtkWidget *pluginmenu = NULL;
 
 GSList *gaim_gtk_blist_sort_methods = NULL;
@@ -992,7 +990,7 @@
 	struct _gaim_gtk_blist_node *gtknode;
 	GtkTreeIter iter, parent;
 	GaimBlistNode *bnode;
-	GtkTreePath *path;		
+	GtkTreePath *path;
 
 	if(!GAIM_BLIST_NODE_IS_CONTACT(node))
 		return;
@@ -2378,18 +2376,18 @@
 
 	/* Tools */
 	{ N_("/_Tools"), NULL, NULL, 0, "<Branch>" },
-	{ N_("/Tools/_Away"), NULL, NULL, 0, "<Branch>" },
 	{ N_("/Tools/Buddy _Pounce"), NULL, NULL, 0, "<Branch>" },
 	{ N_("/Tools/Account Ac_tions"), NULL, NULL, 0, "<Branch>" },
 	{ N_("/Tools/Pl_ugin Actions"), NULL, NULL, 0, "<Branch>" },
 	{ "/Tools/sep1", NULL, NULL, 0, "<Separator>" },
+	{ N_("/Tools/_Statuses"), NULL, gaim_gtk_status_window_show, 0, "<StockItem>", GAIM_STOCK_ICON_AWAY },
 	{ N_("/Tools/A_ccounts"), "<CTL>A", gaim_gtk_accounts_window_show, 0, "<StockItem>", GAIM_STOCK_ACCOUNTS },
+	{ N_("/Tools/Pr_eferences"), "<CTL>P", gaim_gtk_prefs_show, 0, "<StockItem>", GTK_STOCK_PREFERENCES },
+	{ N_("/Tools/Pr_ivacy"), NULL, gaim_gtk_privacy_dialog_show, 0, NULL },
 	{ N_("/Tools/_File Transfers"), "<CTL>T", gaim_show_xfer_dialog, 0, "<StockItem>", GAIM_STOCK_FILE_TRANSFER },
 	{ N_("/Tools/R_oom List"), NULL, gaim_gtk_roomlist_dialog_show, 0, NULL },
-	{ N_("/Tools/Pr_eferences"), "<CTL>P", gaim_gtk_prefs_show, 0, "<StockItem>", GTK_STOCK_PREFERENCES },
-	{ N_("/Tools/Pr_ivacy"), NULL, gaim_gtk_privacy_dialog_show, 0, NULL },
+	{ "/Tools/sep2", NULL, NULL, 0, "<Separator>" },
 	{ N_("/Tools/Mute _Sounds"), "<CTL>S", gaim_gtk_blist_mute_sounds_cb, 0, "<CheckItem>"},
-	{ "/Tools/sep2", NULL, NULL, 0, "<Separator>" },
 	{ N_("/Tools/View System _Log"), NULL, gtk_blist_show_systemlog_cb, 0, NULL },
 
 	/* Help */
@@ -3143,13 +3141,6 @@
 	gtk_widget_show(menu);
 	gtk_box_pack_start(GTK_BOX(gtkblist->vbox), menu, FALSE, FALSE, 0);
 
-	awaymenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Away"));
-
-	/* FIXME: Status */
-#if 0
-	do_away_menu();
-#endif
-
 	gtkblist->bpmenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Buddy Pounce"));
 	gaim_gtkpounce_menu_build(gtkblist->bpmenu);
 
@@ -3158,6 +3149,7 @@
 
 	pluginmenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Plugin Actions"));
 	gaim_gtk_blist_update_plugin_actions();
+
 	/****************************** GtkTreeView **********************************/
 	sw = gtk_scrolled_window_new(NULL,NULL);
 	gtk_widget_show(sw);
@@ -3808,7 +3800,6 @@
 	g_object_unref(G_OBJECT(gtkblist->ift));
 	protomenu = NULL;
 	pluginmenu = NULL;
-	awaymenu = NULL;
 	gtkblist = NULL;
 
 	gaim_prefs_disconnect_by_handle(gaim_gtk_blist_get_handle());
@@ -3818,9 +3809,9 @@
 {
 	if (!(gtkblist && gtkblist->window))
 		return;
-	
+
 	gaim_prefs_set_bool("/gaim/gtk/blist/list_visible", show);
-	
+
 	if (show) {
 		gaim_gtk_blist_restore_position();
 		gtk_window_present(GTK_WINDOW(gtkblist->window));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gtkstatus.c	Tue Dec 07 04:59:27 2004 +0000
@@ -0,0 +1,622 @@
+/**
+ * @file gtkstatus.c GTK+ Status Editor UI
+ * @ingroup gtkui
+ *
+ * gaim
+ *
+ * Gaim 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 program 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 "account.h"
+#include "internal.h"
+#include "status.h"
+
+#include "gtkblist.h"
+#include "gtkgaim.h"
+#include "gtkgaim-disclosure.h"
+#include "gtkimhtml.h"
+#include "gtkimhtmltoolbar.h"
+#include "gtkstatus.h"
+#include "gtkstock.h"
+#include "gtkutils.h"
+
+enum
+{
+	STATUS_EDITOR_COLUMN_CUSTOM_STATUS,
+	STATUS_EDITOR_COLUMN_ICON,
+	STATUS_EDITOR_COLUMN_SCREENNAME,
+	STATUS_EDITOR_NUM_COLUMNS
+};
+
+typedef struct
+{
+	GtkWidget *window;
+	GtkListStore *model;
+	GtkWidget *treeview;
+} StatusEditor;
+
+typedef struct
+{
+	GtkWidget *window;
+	GtkListStore *model;
+	GtkWidget *treeview;
+	GtkWidget *modify_button;
+	GtkWidget *delete_button;
+} StatusWindow;
+
+static StatusWindow *status_window = NULL;
+
+static gboolean
+status_editor_destroy_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
+{
+	StatusWindow *dialog = user_data;
+
+	g_free(dialog);
+
+	return FALSE;
+}
+
+static void
+status_editor_cancel_cb(GtkButton *button, gpointer user_data)
+{
+	StatusWindow *dialog = user_data;
+
+	gtk_widget_destroy(dialog->window);
+
+	g_free(dialog);
+}
+
+static void
+status_editor_save_cb(GtkButton *button, gpointer user_data)
+{
+	/* TODO: Save the status */
+}
+
+/* TODO: Can this menu be created more automatically? */
+static GtkWidget *
+create_status_type_menu()
+{
+	GtkWidget *dropdown;
+	GtkWidget *menu;
+	GtkWidget *item;
+
+	dropdown = gtk_option_menu_new();
+	menu = gtk_menu_new();
+
+	/* GAIM_STATUS_AVAILABLE */
+	item = gtk_menu_item_new_with_label(_("Available"));
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+	gtk_widget_show(item);
+
+	/* GAIM_STATUS_UNAVAILABLE */
+	item = gtk_menu_item_new_with_label(_("Unavailable"));
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+	gtk_widget_show(item);
+
+	/* GAIM_STATUS_HIDDEN */
+	item = gtk_menu_item_new_with_label(_("Hidden"));
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+	gtk_widget_show(item);
+
+	/* GAIM_STATUS_AWAY */
+	item = gtk_menu_item_new_with_label(_("Away"));
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+	gtk_widget_show(item);
+
+	/* GAIM_STATUS_EXTENDED_AWAY */
+	item = gtk_menu_item_new_with_label(_("Extended Away"));
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+	gtk_widget_show(item);
+
+	gtk_option_menu_set_menu(GTK_OPTION_MENU(dropdown), menu);
+	gtk_widget_show(menu);
+
+	return dropdown;
+}
+
+static void
+status_editor_custom_status_cb(GtkCellRendererToggle *renderer, gchar *path_str, gpointer data)
+{
+	/* StatusEditor *dialog = (StatusEditor *)data; */
+
+	/* TODO: Need to allow user to set a custom status for the highlighted account, somehow */
+}
+
+static void
+status_editor_add_columns(StatusEditor *dialog)
+{
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+
+	/* Custom status column */
+	renderer = gtk_cell_renderer_toggle_new();
+	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(dialog->treeview),
+						    -1, _("Custom status"),
+						    renderer,
+						    "active", STATUS_EDITOR_COLUMN_CUSTOM_STATUS,
+						    NULL);
+	column = gtk_tree_view_get_column(GTK_TREE_VIEW(dialog->treeview), 1);
+	g_signal_connect(G_OBJECT(renderer), "toggled",
+			 G_CALLBACK(status_editor_custom_status_cb), dialog);
+
+	/* Screen Name column */
+	column = gtk_tree_view_column_new();
+	gtk_tree_view_column_set_resizable(column, TRUE);
+	gtk_tree_view_column_set_title(column, _("Screen Name"));
+	gtk_tree_view_insert_column(GTK_TREE_VIEW(dialog->treeview), column, -1);
+	gtk_tree_view_column_set_resizable(column, TRUE);
+
+	/* Icon */
+	renderer = gtk_cell_renderer_pixbuf_new();
+	gtk_tree_view_column_pack_start(column, renderer, FALSE);
+	gtk_tree_view_column_add_attribute(column, renderer, "pixbuf",
+									   STATUS_EDITOR_COLUMN_ICON);
+
+	/* Screen Name */
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_column_pack_start(column, renderer, TRUE);
+	gtk_tree_view_column_add_attribute(column, renderer, "text",
+									   STATUS_EDITOR_COLUMN_SCREENNAME);
+}
+
+static void
+status_editor_set_account(GtkListStore *store, GaimAccount *account, GtkTreeIter *iter)
+{
+	GdkPixbuf *pixbuf;
+	GdkPixbuf *scale;
+
+	scale = NULL;
+
+	pixbuf = create_prpl_icon(account);
+
+	if (pixbuf != NULL)
+	{
+		scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR);
+
+		if (!gaim_account_is_connected(account))
+			gdk_pixbuf_saturate_and_pixelate(scale, scale, 0.0, FALSE);
+	}
+
+	gtk_list_store_set(store, iter,
+			STATUS_EDITOR_COLUMN_ICON, scale,
+			STATUS_EDITOR_COLUMN_SCREENNAME, gaim_account_get_username(account),
+			-1);
+
+	if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf));
+	if (scale  != NULL) g_object_unref(G_OBJECT(scale));
+}
+
+static void
+status_editor_add_account(StatusEditor *dialog, GaimAccount *account)
+{
+	GtkTreeIter iter;
+
+	gtk_list_store_append(dialog->model, &iter);
+
+	status_editor_set_account(dialog->model, account, &iter);
+}
+
+static void
+status_editor_populate_list(StatusEditor *dialog)
+{
+	GList *l;
+
+	gtk_list_store_clear(dialog->model);
+
+	for (l = gaim_accounts_get_all(); l != NULL; l = l->next)
+		status_editor_add_account(dialog, (GaimAccount *)l->data);
+}
+
+void
+gaim_gtk_status_editor_show(void)
+{
+	StatusEditor *dialog;
+	GtkSizeGroup *sg;
+	GtkWidget *bbox;
+	GtkWidget *button;
+	GtkWidget *dbox;
+	GtkWidget *disclosure;
+	GtkWidget *dropdown;
+	GtkWidget *entry;
+	GtkWidget *frame;
+	GtkWidget *hbox;
+	GtkWidget *label;
+	GtkWidget *sep;
+	GtkWidget *sw;
+	GtkWidget *text;
+	GtkWidget *toolbar;
+	GtkWidget *vbox;
+	GtkWidget *win;
+
+	dialog = g_new0(StatusEditor, 1);
+
+	dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_role(GTK_WINDOW(win), "status");
+	gtk_window_set_title(GTK_WINDOW(win), _("Status"));
+	gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
+	gtk_container_set_border_width(GTK_CONTAINER(win), 12);
+
+	g_signal_connect(G_OBJECT(win), "delete_event",
+					 G_CALLBACK(status_editor_destroy_cb), dialog);
+
+	/* Setup the vbox */
+	vbox = gtk_vbox_new(FALSE, 12);
+	gtk_container_add(GTK_CONTAINER(win), vbox);
+	gtk_widget_show(vbox);
+
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+
+	/* Title */
+	hbox = gtk_hbox_new(FALSE, 6);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+	gtk_widget_show(hbox);
+
+	label = gtk_label_new_with_mnemonic(_("_Title:"));
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+	gtk_widget_show(label);
+	gtk_size_group_add_widget(sg, label);
+
+	entry = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(entry), _("Out of the office"));
+	gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
+	gtk_widget_show(entry);
+
+	/* Status type */
+	hbox = gtk_hbox_new(FALSE, 6);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+	gtk_widget_show(hbox);
+
+	label = gtk_label_new_with_mnemonic(_("_Status:"));
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+	gtk_widget_show(label);
+	gtk_size_group_add_widget(sg, label);
+
+	dropdown = create_status_type_menu();
+	gtk_box_pack_start(GTK_BOX(hbox), dropdown, TRUE, TRUE, 0);
+	gtk_widget_show(dropdown);
+
+	/* Status message */
+	hbox = gtk_hbox_new(FALSE, 6);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+	gtk_widget_show(hbox);
+
+	label = gtk_label_new_with_mnemonic(_("_Message:"));
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+	gtk_widget_show(label);
+	gtk_size_group_add_widget(sg, label);
+
+	frame = gaim_gtk_create_imhtml(TRUE, &text, &toolbar);
+	gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0);
+	gtk_widget_show(frame);
+
+	/* Custom status message disclosure */
+	disclosure = gaim_disclosure_new(_("Use a different status for some accounts"),
+									 _("Use a different status for some accounts"));
+	gtk_box_pack_start(GTK_BOX(vbox), disclosure, FALSE, FALSE, 0);
+	gtk_widget_show(disclosure);
+
+	/* Setup the box that the disclosure will cover */
+	dbox = gtk_vbox_new(FALSE, 18);
+	gtk_box_pack_start(GTK_BOX(vbox), dbox, FALSE, FALSE, 0);
+	gaim_disclosure_set_container(GAIM_DISCLOSURE(disclosure), dbox);
+
+	/* Custom status message treeview */
+	sw = gtk_scrolled_window_new(NULL, NULL);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
+								   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
+										GTK_SHADOW_IN);
+	gtk_box_pack_start(GTK_BOX(dbox), sw, TRUE, TRUE, 0);
+	gtk_widget_show(sw);
+
+	/* Create the list model */
+	dialog->model = gtk_list_store_new(STATUS_EDITOR_NUM_COLUMNS,
+									   G_TYPE_BOOLEAN,
+									   GDK_TYPE_PIXBUF, G_TYPE_STRING);
+
+	/* Create the treeview */
+	dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
+	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE);
+	gtk_widget_set_size_request(dialog->treeview, 400, 250);
+	gtk_container_add(GTK_CONTAINER(sw), dialog->treeview);
+	gtk_widget_show(dialog->treeview);
+
+	/* Add columns */
+	status_editor_add_columns(dialog);
+
+	/* Populate list */
+	status_editor_populate_list(dialog);
+
+	/* Separator */
+	sep = gtk_hseparator_new();
+	gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
+	gtk_widget_show(sep);
+
+	/* Button box */
+	bbox = gtk_hbutton_box_new();
+	gtk_box_set_spacing(GTK_BOX(bbox), 6);
+	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+	gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0);
+	gtk_widget_show(bbox);
+
+	/* Cancel button */
+	button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
+	gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
+	gtk_widget_show(button);
+
+	g_signal_connect(G_OBJECT(button), "clicked",
+					 G_CALLBACK(status_editor_cancel_cb), dialog);
+
+	/* Save button */
+	/* TODO: This button needs to be made sensitive when the title box contains text */
+	button = gtk_button_new_from_stock(GTK_STOCK_SAVE);
+	gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
+	gtk_widget_set_sensitive(button, FALSE);
+	gtk_widget_show(button);
+
+	g_signal_connect(G_OBJECT(button), "clicked",
+					 G_CALLBACK(status_editor_save_cb), dialog);
+
+	gtk_widget_show(win);
+}
+
+static gboolean
+status_window_destroy_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
+{
+	StatusWindow *dialog = user_data;
+
+	dialog->window = NULL;
+	gaim_gtk_status_window_hide();
+
+	return FALSE;
+}
+
+static void
+status_window_add_cb(GtkButton *button, gpointer user_data)
+{
+	gaim_gtk_status_editor_show();
+}
+
+static void
+status_window_modify_cb(GtkButton *button, gpointer user_data)
+{
+	/* TODO: Need to show a pre-populated status editor */
+}
+
+static void
+status_window_delete_cb(GtkButton *button, gpointer user_data)
+{
+	/* TODO: Need to delete a status from the list */
+}
+
+static void
+status_window_close_cb(GtkButton *button, gpointer user_data)
+{
+	gaim_gtk_status_window_hide();
+}
+
+/*
+ * TODO: This needs to use the user's saved statuses.
+ */
+static void
+populate_saved_status_list(StatusWindow *dialog)
+{
+	GtkTreeIter iter;
+
+	gtk_list_store_clear(dialog->model);
+
+	gtk_list_store_append(dialog->model, &iter);
+	gtk_list_store_set(dialog->model, &iter, 0, "Dinner time!", -1);
+
+	gtk_list_store_append(dialog->model, &iter);
+	gtk_list_store_set(dialog->model, &iter, 0, "I am not here because I am cow tipping with Jimmy.", -1);
+
+	gtk_list_store_append(dialog->model, &iter);
+	gtk_list_store_set(dialog->model, &iter, 0, "Picking up the kids from the zoo.", -1);
+
+	gtk_list_store_append(dialog->model, &iter);
+	gtk_list_store_set(dialog->model, &iter, 0, "In a meeting discussing what to do when King Kong gets here.", -1);
+}
+
+static GtkWidget *
+create_saved_status_list(StatusWindow *dialog)
+{
+	GtkWidget *sw;
+	GtkWidget *treeview;
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *renderer;
+
+	/* Create the scrolled window */
+	sw = gtk_scrolled_window_new(0, 0);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
+								   GTK_POLICY_AUTOMATIC,
+								   GTK_POLICY_ALWAYS);
+	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
+										GTK_SHADOW_IN);
+	gtk_widget_show(sw);
+
+	/* Create the list model */
+	dialog->model = gtk_list_store_new(1, G_TYPE_STRING);
+
+	/* Create the treeview */
+	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
+	dialog->treeview = treeview;
+	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
+
+	gtk_container_add(GTK_CONTAINER(sw), treeview);
+	gtk_widget_show(treeview);
+
+	/* Add columns */
+	column = gtk_tree_view_column_new();
+	gtk_tree_view_column_set_title(column, _("Title"));
+	gtk_tree_view_column_set_resizable(column, TRUE);
+	gtk_tree_view_column_set_sort_column_id(column, 0);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_column_pack_start(column, renderer, TRUE);
+	gtk_tree_view_column_add_attribute(column, renderer, "text", 0);
+
+	/* Populate list */
+	populate_saved_status_list(dialog);
+
+	return sw;
+}
+
+static gboolean
+configure_cb(GtkWidget *widget, GdkEventConfigure *event, StatusWindow *dialog)
+{
+	if (GTK_WIDGET_VISIBLE(widget)) {
+		gaim_prefs_set_int("/gaim/gtk/status/dialog/width",  event->width);
+		gaim_prefs_set_int("/gaim/gtk/status/dialog/height", event->height);
+	}
+
+	return FALSE;
+}
+
+void
+gaim_gtk_status_window_show(void)
+{
+	StatusWindow *dialog;
+	GtkWidget *bbox;
+	GtkWidget *button;
+	GtkWidget *list;
+	GtkWidget *sep;
+	GtkWidget *vbox;
+	GtkWidget *win;
+	int width, height;
+
+	if (status_window != NULL) {
+		gtk_window_present(GTK_WINDOW(status_window->window));
+		return;
+	}
+
+	status_window = dialog = g_new0(StatusWindow, 1);
+
+	width  = gaim_prefs_get_int("/gaim/gtk/status/dialog/width");
+	height = gaim_prefs_get_int("/gaim/gtk/status/dialog/height");
+
+	dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_default_size(GTK_WINDOW(win), width, height);
+	gtk_window_set_role(GTK_WINDOW(win), "statuses");
+	gtk_window_set_title(GTK_WINDOW(win), _("Saved Statuses"));
+	gtk_container_set_border_width(GTK_CONTAINER(win), 12);
+
+	g_signal_connect(G_OBJECT(win), "delete_event",
+					 G_CALLBACK(status_window_destroy_cb), dialog);
+	g_signal_connect(G_OBJECT(win), "configure_event",
+					 G_CALLBACK(configure_cb), dialog);
+
+	/* Setup the vbox */
+	vbox = gtk_vbox_new(FALSE, 12);
+	gtk_container_add(GTK_CONTAINER(win), vbox);
+	gtk_widget_show(vbox);
+
+	/* List of saved status states */
+	list = create_saved_status_list(dialog);
+	gtk_box_pack_start(GTK_BOX(vbox), list, TRUE, TRUE, 0);
+
+	/* Separator... */
+	sep = gtk_hseparator_new();
+	gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
+	gtk_widget_show(sep);
+
+	/* Button box. */
+	bbox = gtk_hbutton_box_new();
+	gtk_box_set_spacing(GTK_BOX(bbox), 6);
+	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+	gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0);
+	gtk_widget_show(bbox);
+
+	/* Add button */
+	button = gtk_button_new_from_stock(GTK_STOCK_ADD);
+	gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
+	gtk_widget_show(button);
+
+	g_signal_connect(G_OBJECT(button), "clicked",
+					 G_CALLBACK(status_window_add_cb), dialog);
+
+	/* Modify button */
+	button = gtk_button_new_from_stock(GAIM_STOCK_MODIFY);
+	dialog->modify_button = button;
+	gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
+	gtk_widget_set_sensitive(button, FALSE);
+	gtk_widget_show(button);
+
+	g_signal_connect(G_OBJECT(button), "clicked",
+					 G_CALLBACK(status_window_modify_cb), dialog);
+
+	/* Delete button */
+	button = gtk_button_new_from_stock(GTK_STOCK_DELETE);
+	dialog->delete_button = button;
+	gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
+	gtk_widget_set_sensitive(button, FALSE);
+	gtk_widget_show(button);
+
+	g_signal_connect(G_OBJECT(button), "clicked",
+					 G_CALLBACK(status_window_delete_cb), dialog);
+
+	/* Close button */
+	button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+	gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
+	gtk_widget_show(button);
+
+	g_signal_connect(G_OBJECT(button), "clicked",
+					 G_CALLBACK(status_window_close_cb), dialog);
+
+	gtk_widget_show(win);
+}
+
+void
+gaim_gtk_status_window_hide(void)
+{
+	if (status_window == NULL)
+		return;
+
+	if (status_window->window != NULL)
+		gtk_widget_destroy(status_window->window);
+
+	g_free(status_window);
+	status_window = NULL;
+}
+
+void *
+gaim_gtk_status_get_handle()
+{
+	static int handle;
+
+	return &handle;
+}
+
+void
+gaim_gtk_status_init(void)
+{
+	gaim_prefs_add_none("/gaim/gtk/status");
+	gaim_prefs_add_none("/gaim/gtk/status/dialog");
+	gaim_prefs_add_int("/gaim/gtk/status/dialog/width",  550);
+	gaim_prefs_add_int("/gaim/gtk/status/dialog/height", 250);
+}
+
+void
+gaim_gtk_status_uninit(void)
+{
+	gaim_gtk_status_window_hide();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gtkstatus.h	Tue Dec 07 04:59:27 2004 +0000
@@ -0,0 +1,57 @@
+/**
+ * @file gtkstatus.h GTK+ Status Editor UI
+ * @ingroup gtkui
+ *
+ * gaim
+ *
+ * Gaim 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 program 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 _GAIM_GTKSTATUS_H_
+#define _GAIM_GTKSTATUS_H_
+
+#include "status.h"
+
+/**
+ * Shows the status window.
+ */
+void gaim_gtk_status_window_show(void);
+
+/**
+ * Hides the status window.
+ */
+void gaim_gtk_status_window_hide(void);
+
+/**
+ * Returns the gtkstatus handle.
+ *
+ * @return The handle to the GTK+ status system.
+ */
+void *gaim_gtk_status_get_handle(void);
+
+/**
+ * Initializes the GTK+ status system.
+ */
+void gaim_gtk_status_init(void);
+
+/**
+ * Uninitializes the GTK+ status system.
+ */
+void gaim_gtk_status_uninit(void);
+
+#endif /* _GAIM_GTKSTATUS_H_ */