Mercurial > pidgin
changeset 10178:96a850ab30c8
[gaim-migrate @ 11293]
Added a status selector widget and stuck it at the bottom of the blist.
Despite conversations regarding this, nobody has done it yet, so here's a
basic one that people can build off of. It'll at the very least allow
people to figure out what needs fixing with prpls and status (and a lot of
fixes are needed!)
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Sun, 14 Nov 2004 20:15:09 +0000 |
parents | 82c1322c4b56 |
children | 97ee3bf7bcf7 |
files | src/Makefile.am src/gtkblist.c src/gtkstatusselector.c src/gtkstatusselector.h |
diffstat | 4 files changed, 535 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/src/Makefile.am Sun Nov 14 20:14:00 2004 +0000 +++ b/src/Makefile.am Sun Nov 14 20:15:09 2004 +0000 @@ -163,6 +163,7 @@ gtkroomlist.c \ gtksound.c \ gtksourceiter.c \ + gtkstatusselector.c \ gtkutils.c \ idle.c \ main.c \ @@ -198,6 +199,7 @@ gtkroomlist.h \ gtksound.h \ gtksourceiter.h \ + gtkstatusselector.h \ gtkutils.h \ internal.h \ stock.h
--- a/src/gtkblist.c Sun Nov 14 20:14:00 2004 +0000 +++ b/src/gtkblist.c Sun Nov 14 20:15:09 2004 +0000 @@ -49,6 +49,7 @@ #include "gtkprivacy.h" #include "gtkroomlist.h" #include "gtksound.h" +#include "gtkstatusselector.h" #include "gtkutils.h" #include "gaim.h" @@ -3090,7 +3091,9 @@ void *handle; GtkCellRenderer *rend; GtkTreeViewColumn *column; + GtkWidget *menu; GtkWidget *sw; + GtkWidget *selector; GtkAccelGroup *accel_group; GtkTreeSelection *selection; GtkTargetEntry dte[] = {{"GAIM_BLIST_NODE", GTK_TARGET_SAME_APP, DRAG_ROW}, @@ -3113,6 +3116,7 @@ gtk_window_set_title(GTK_WINDOW(gtkblist->window), _("Buddy List")); gtkblist->vbox = gtk_vbox_new(FALSE, 0); + gtk_widget_show(gtkblist->vbox); gtk_container_add(GTK_CONTAINER(gtkblist->window), gtkblist->vbox); g_signal_connect(G_OBJECT(gtkblist->window), "delete_event", G_CALLBACK(gtk_blist_delete_cb), NULL); @@ -3133,7 +3137,9 @@ gaim_gtk_load_accels(); g_signal_connect(G_OBJECT(accel_group), "accel-changed", G_CALLBACK(gaim_gtk_save_accels_cb), NULL); - gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtk_item_factory_get_widget(gtkblist->ift, "<GaimMain>"), FALSE, FALSE, 0); + menu = gtk_item_factory_get_widget(gtkblist->ift, "<GaimMain>"); + 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")); @@ -3152,6 +3158,7 @@ gaim_gtk_blist_update_plugin_actions(); /****************************** GtkTreeView **********************************/ sw = gtk_scrolled_window_new(NULL,NULL); + gtk_widget_show(sw); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); @@ -3160,6 +3167,7 @@ G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_POINTER); gtkblist->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(gtkblist->treemodel)); + gtk_widget_show(gtkblist->treeview); gtk_widget_set_name(gtkblist->treeview, "gaim_gtkblist_treeview"); /* Set up selection stuff */ @@ -3233,6 +3241,10 @@ gtk_container_add(GTK_CONTAINER(sw), gtkblist->treeview); gaim_gtk_blist_update_columns(); + selector = gaim_gtk_status_selector_new(); + gtk_widget_show(selector); + gtk_box_pack_start(GTK_BOX(gtkblist->vbox), selector, FALSE, TRUE, 0); + /* set the Show Offline Buddies option. must be done * after the treeview or faceprint gets mad. -Robot101 */ @@ -3248,7 +3260,7 @@ /* OK... let's show this bad boy. */ gaim_gtk_blist_refresh(list); gaim_gtk_blist_restore_position(); - gtk_widget_show_all(gtkblist->window); + gtk_widget_show(gtkblist->window); /* start the refresh timer */ if (gaim_prefs_get_bool("/gaim/gtk/blist/show_idle_time") ||
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gtkstatusselector.c Sun Nov 14 20:15:09 2004 +0000 @@ -0,0 +1,434 @@ +/** + * @file gtkstatusselector.c Status selector widget + * @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 "internal.h" +#include "gtkgaim.h" +#include "gtkimhtml.h" +#include "gtkstatusselector.h" +#include "gtkutils.h" + +#include "account.h" +#include "debug.h" +#include "prefs.h" + +struct _GaimGtkStatusSelectorPrivate +{ + GtkWidget *combo; + GtkWidget *entry; + GtkWidget *sw; + +#if GTK_CHECK_VERSION(2,4,0) + GtkListStore *model; +#endif + + GHashTable *icon_table; +}; + +#if GTK_CHECK_VERSION(2,4,0) +enum +{ + COLUMN_STATUS_TYPE_ID, + COLUMN_ICON, + COLUMN_NAME, + NUM_COLUMNS +}; +#endif /* GTK >= 2.4.0 */ + +static void gaim_gtk_status_selector_class_init(GaimGtkStatusSelectorClass *klass); +static void gaim_gtk_status_selector_init(GaimGtkStatusSelector *selector); +static void gaim_gtk_status_selector_finalize(GObject *obj); +static void gaim_gtk_status_selector_destroy(GtkObject *obj); +static void status_switched_cb(GtkWidget *combo, GaimGtkStatusSelector *selector); +static void signed_on_off_cb(GaimConnection *gc, GaimGtkStatusSelector *selector); +static void rebuild_list(GaimGtkStatusSelector *selector); + +static GtkVBox *parent_class = NULL; + +GType +gaim_gtk_status_selector_get_type(void) +{ + static GType type = 0; + + if (!type) + { + static const GTypeInfo info = + { + sizeof(GaimGtkStatusSelectorClass), + NULL, + NULL, + (GClassInitFunc)gaim_gtk_status_selector_class_init, + NULL, + NULL, + sizeof(GaimGtkStatusSelector), + 0, + (GInstanceInitFunc)gaim_gtk_status_selector_init + }; + + type = g_type_register_static(GTK_TYPE_VBOX, + "GaimGtkStatusSelector", &info, 0); + } + + return type; +} + +static void +gaim_gtk_status_selector_class_init(GaimGtkStatusSelectorClass *klass) +{ + GObjectClass *gobject_class; + GtkObjectClass *object_class; + + parent_class = g_type_class_peek_parent(klass); + + gobject_class = G_OBJECT_CLASS(klass); + object_class = GTK_OBJECT_CLASS(klass); + + gobject_class->finalize = gaim_gtk_status_selector_finalize; + + object_class->destroy = gaim_gtk_status_selector_destroy; +} + +static void +gaim_gtk_status_selector_init(GaimGtkStatusSelector *selector) +{ + GtkWidget *combo; + GtkWidget *entry; + GtkWidget *sw; +#if GTK_CHECK_VERSION(2,4,0) + GtkCellRenderer *renderer; +#endif + + selector->priv = g_new0(GaimGtkStatusSelectorPrivate, 1); + + selector->priv->icon_table = + g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + + g_hash_table_insert(selector->priv->icon_table, + "online", "available.png"); + g_hash_table_insert(selector->priv->icon_table, + "away", "away.png"); + +#if GTK_CHECK_VERSION(2,4,0) + selector->priv->model = gtk_list_store_new(NUM_COLUMNS, G_TYPE_POINTER, + GDK_TYPE_PIXBUF, G_TYPE_STRING); + + combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(selector->priv->model)); + selector->priv->combo = combo; + + g_object_unref(G_OBJECT(selector->priv->model)); + + renderer = gtk_cell_renderer_pixbuf_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, FALSE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), renderer, + "pixbuf", COLUMN_ICON, + NULL); + + renderer = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), renderer, + "text", COLUMN_NAME, + NULL); + + g_signal_connect(G_OBJECT(combo), "changed", + G_CALLBACK(status_switched_cb), selector); +#else /* GTK < 2.4.0 */ + + /* TODO */ + +#endif /* GTK < 2.4.0 */ + + gtk_widget_show(combo); + gtk_box_pack_start(GTK_BOX(selector), combo, FALSE, FALSE, 0); + + selector->priv->sw = sw = gtk_scrolled_window_new(NULL, NULL); + gtk_box_pack_start(GTK_BOX(selector), sw, TRUE, TRUE, 0); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), + GTK_SHADOW_IN); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + + selector->priv->entry = entry = gtk_imhtml_new(NULL, NULL); + gtk_widget_show(entry); + gtk_container_add(GTK_CONTAINER(sw), entry); + gtk_widget_set_name(entry, "gaim_gtk_status_selector_imhtml"); + gtk_imhtml_set_editable(GTK_IMHTML(entry), TRUE); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(entry), GTK_WRAP_WORD_CHAR); + + if (gaim_prefs_get_bool("/gaim/gtk/conversations/spellcheck")) + gaim_gtk_setup_gtkspell(GTK_TEXT_VIEW(entry)); + + gaim_signal_connect(gaim_connections_get_handle(), "signed-on", + selector, GAIM_CALLBACK(signed_on_off_cb), + selector); + gaim_signal_connect(gaim_connections_get_handle(), "signed-off", + selector, GAIM_CALLBACK(signed_on_off_cb), + selector); + + rebuild_list(selector); +} + +static void +gaim_gtk_status_selector_finalize(GObject *obj) +{ + GaimGtkStatusSelector *selector; + + g_return_if_fail(obj != NULL); + g_return_if_fail(GAIM_GTK_IS_STATUS_SELECTOR(obj)); + + selector = GAIM_GTK_STATUS_SELECTOR(obj); + + g_free(selector->priv); + + if (G_OBJECT_CLASS(parent_class)->finalize) + G_OBJECT_CLASS(parent_class)->finalize(obj); +} + +static void +gaim_gtk_status_selector_destroy(GtkObject *obj) +{ + GaimGtkStatusSelector *selector; + + g_return_if_fail(obj != NULL); + g_return_if_fail(GAIM_GTK_IS_STATUS_SELECTOR(obj)); + + selector = GAIM_GTK_STATUS_SELECTOR(obj); + + if (selector->priv->icon_table != NULL) + { + g_hash_table_destroy(selector->priv->icon_table); + selector->priv->icon_table = NULL; + } + + if (GTK_OBJECT_CLASS(parent_class)->destroy) + GTK_OBJECT_CLASS(parent_class)->destroy(obj); +} + +static void +status_switched_cb(GtkWidget *combo, GaimGtkStatusSelector *selector) +{ + GtkTreeIter iter; + + if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(selector->priv->combo), + &iter)) + { + const char *status_type_id; + char *text; + GList *l; + + gtk_tree_model_get(GTK_TREE_MODEL(selector->priv->model), &iter, + COLUMN_NAME, &text, + COLUMN_STATUS_TYPE_ID, &status_type_id, + -1); + + if (!strcmp(text, _("New status"))) + { + /* TODO */ + } + else + { + const char *message = ""; + GtkTextBuffer *buffer; + gboolean allow_message = FALSE; + + buffer = + gtk_text_view_get_buffer(GTK_TEXT_VIEW(selector->priv->entry)); + + gtk_text_buffer_set_text(buffer, message, -1); + + for (l = gaim_connections_get_all(); l != NULL; l = l->next) + { + GaimConnection *gc = (GaimConnection *)l->data; + GaimAccount *account = gaim_connection_get_account(gc); + GaimStatusType *status_type; + + status_type = gaim_account_get_status_type(account, + status_type_id); + + if (status_type == NULL) + continue; + + if (gaim_status_type_get_attr(status_type, "message") != NULL) + { + gaim_account_set_status(account, + "away", TRUE, + "message", message, + NULL); + + allow_message = TRUE; + } + else + { + gaim_account_set_status(gaim_connection_get_account(gc), + "away", TRUE, + NULL); + } + } + + if (allow_message) + gtk_widget_show(selector->priv->sw); + else + gtk_widget_hide(selector->priv->sw); + } + } +} + +static void +signed_on_off_cb(GaimConnection *gc, GaimGtkStatusSelector *selector) +{ + rebuild_list(selector); +} + +static GdkPixbuf * +load_icon(const char *basename) +{ + char *filename; + GdkPixbuf *pixbuf, *scale = NULL; + + if (!strcmp(basename, "available.png")) + basename = "online.png"; + else if (!strcmp(basename, "hidden.png")) + basename = "invisible.png"; + + filename = g_build_filename(DATADIR, "pixmaps", "gaim", "icons", + basename, NULL); + pixbuf = gdk_pixbuf_new_from_file(filename, NULL); + g_free(filename); + + if (pixbuf != NULL) + { + scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, + GDK_INTERP_BILINEAR); + + g_object_unref(G_OBJECT(pixbuf)); + } + else + { + filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", + "default", basename, NULL); + scale = gdk_pixbuf_new_from_file(filename, NULL); + g_free(filename); + } + + return scale; +} + +static void +add_item(GaimGtkStatusSelector *selector, const char *status_type_id, + const char *text, GdkPixbuf *pixbuf) +{ + GtkTreeIter iter; + + gtk_list_store_append(selector->priv->model, &iter); + gtk_list_store_set(selector->priv->model, &iter, + COLUMN_STATUS_TYPE_ID, status_type_id, + COLUMN_ICON, pixbuf, + COLUMN_NAME, text, + -1); + + if (pixbuf != NULL) + g_object_unref(G_OBJECT(pixbuf)); +} + +static void +rebuild_list(GaimGtkStatusSelector *selector) +{ + gboolean single_prpl = TRUE; + GaimAccount *first_account = NULL; + const char *first_prpl_type = NULL; + GList *l; + + g_return_if_fail(selector != NULL); + g_return_if_fail(GAIM_GTK_IS_STATUS_SELECTOR(selector)); + + gtk_list_store_clear(selector->priv->model); + + /* + * If the user only has one IM account or one type of IM account + * connected, they'll see all their statuses. This is ideal for those + * who use only one account, or one single protocol. Everyone else + * gets Available and Away and a list of saved statuses. + */ + for (l = gaim_connections_get_all(); l != NULL && single_prpl; l = l->next) + { + GaimConnection *gc = (GaimConnection *)l->data; + GaimAccount *account = gaim_connection_get_account(gc); + GaimPluginProtocolInfo *prpl_info; + const char *basename; + + prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); + basename = prpl_info->list_icon(account, NULL); + + if (first_prpl_type == NULL) + { + first_prpl_type = basename; + first_account = account; + } + else if (!strcmp(first_prpl_type, basename)) + single_prpl = FALSE; + } + + if (single_prpl) + { + const GList *l; + + for (l = gaim_account_get_status_types(first_account); + l != NULL; + l = l->next) + { + GaimStatusType *status_type = (GaimStatusType *)l->data; + char filename[BUFSIZ]; + + if (!gaim_status_type_is_user_settable(status_type)) + continue; + + g_snprintf(filename, sizeof(filename), "%s.png", + gaim_status_type_get_id(status_type)); + + add_item(selector, + gaim_status_type_get_id(status_type), + gaim_status_type_get_name(status_type), + load_icon(filename)); + } + } + else + { + add_item(selector, "available", _("Available"), + load_icon("online.png")); + add_item(selector, "away", _("Away"), load_icon("away.png")); + } + + add_item(selector, NULL, _("New Status"), + gtk_widget_render_icon(GTK_WIDGET(selector), GTK_STOCK_NEW, + GTK_ICON_SIZE_MENU, NULL)); +} + +GtkWidget * +gaim_gtk_status_selector_new(void) +{ + GaimGtkStatusSelector *selector; + + selector = g_object_new(GAIM_GTK_TYPE_STATUS_SELECTOR, NULL); + + return GTK_WIDGET(selector); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gtkstatusselector.h Sun Nov 14 20:15:09 2004 +0000 @@ -0,0 +1,85 @@ +/** + * @file gtkstatusselector.h Status selector widget + * @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_GTKSTATUSSELECTOR_H_ +#define _GAIM_GTKSTATUSSELECTOR_H_ + +#include <gtk/gtkvbox.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define GAIM_GTK_TYPE_STATUS_SELECTOR (gaim_gtk_status_selector_get_type()) +#define GAIM_GTK_STATUS_SELECTOR(obj) (GTK_CHECK_CAST((obj), GAIM_GTK_TYPE_STATUS_SELECTOR, GaimGtkStatusSelector)) +#define GAIM_GTK_STATUS_SELECTOR_CLASS(klass) (GTK_CHECK_CLASS_CAST((klass), GAIM_GTK_TYPE_STATUS_SELECTOR, GaimGtkStatusSelectorClass)) +#define GAIM_GTK_IS_STATUS_SELECTOR(obj) (GTK_CHECK_TYPE((obj), GAIM_GTK_TYPE_STATUS_SELECTOR)) +#define GAIM_GTK_IS_STATUS_SELECTOR_CLASS(klass) (GTK_CHECK_CLASS_TYPE((klass), GAIM_GTK_TYPE_STATUS_SELECTOR)) + +typedef struct _GaimGtkStatusSelector GaimGtkStatusSelector; +typedef struct _GaimGtkStatusSelectorClass GaimGtkStatusSelectorClass; +typedef struct _GaimGtkStatusSelectorPrivate GaimGtkStatusSelectorPrivate; + +struct _GaimGtkStatusSelector +{ + GtkVBox parent_object; + + GaimGtkStatusSelectorPrivate *priv; + + void (*_gtk_reserved1)(void); + void (*_gtk_reserved2)(void); + void (*_gtk_reserved3)(void); + void (*_gtk_reserved4)(void); +}; + +struct _GaimGtkStatusSelectorClass +{ + GtkVBoxClass parent_class; + + void (*_gtk_reserved1)(void); + void (*_gtk_reserved2)(void); + void (*_gtk_reserved3)(void); + void (*_gtk_reserved4)(void); +}; + + +/** + * Returns the status selector widget's GType. + * + * @return GaimGtkStatusSelector's GType. + */ +GType gaim_gtk_status_selector_get_type(void); + +/** + * Creates a new status selector widget. + * + * @return The new status selector widget. + */ +GtkWidget *gaim_gtk_status_selector_new(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _GAIM_GTKSTATUSSELECTOR_H_ */