Mercurial > pidgin
view src/gtkstatusselector.c @ 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 | |
children | 97ee3bf7bcf7 |
line wrap: on
line source
/** * @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); }