Mercurial > pidgin.yaz
comparison 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 |
comparison
equal
deleted
inserted
replaced
10177:82c1322c4b56 | 10178:96a850ab30c8 |
---|---|
1 /** | |
2 * @file gtkstatusselector.c Status selector widget | |
3 * @ingroup gtkui | |
4 * | |
5 * gaim | |
6 * | |
7 * Gaim is the legal property of its developers, whose names are too numerous | |
8 * to list here. Please refer to the COPYRIGHT file distributed with this | |
9 * source distribution. | |
10 * | |
11 * This program is free software; you can redistribute it and/or modify | |
12 * it under the terms of the GNU General Public License as published by | |
13 * the Free Software Foundation; either version 2 of the License, or | |
14 * (at your option) any later version. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
24 */ | |
25 #include "internal.h" | |
26 #include "gtkgaim.h" | |
27 #include "gtkimhtml.h" | |
28 #include "gtkstatusselector.h" | |
29 #include "gtkutils.h" | |
30 | |
31 #include "account.h" | |
32 #include "debug.h" | |
33 #include "prefs.h" | |
34 | |
35 struct _GaimGtkStatusSelectorPrivate | |
36 { | |
37 GtkWidget *combo; | |
38 GtkWidget *entry; | |
39 GtkWidget *sw; | |
40 | |
41 #if GTK_CHECK_VERSION(2,4,0) | |
42 GtkListStore *model; | |
43 #endif | |
44 | |
45 GHashTable *icon_table; | |
46 }; | |
47 | |
48 #if GTK_CHECK_VERSION(2,4,0) | |
49 enum | |
50 { | |
51 COLUMN_STATUS_TYPE_ID, | |
52 COLUMN_ICON, | |
53 COLUMN_NAME, | |
54 NUM_COLUMNS | |
55 }; | |
56 #endif /* GTK >= 2.4.0 */ | |
57 | |
58 static void gaim_gtk_status_selector_class_init(GaimGtkStatusSelectorClass *klass); | |
59 static void gaim_gtk_status_selector_init(GaimGtkStatusSelector *selector); | |
60 static void gaim_gtk_status_selector_finalize(GObject *obj); | |
61 static void gaim_gtk_status_selector_destroy(GtkObject *obj); | |
62 static void status_switched_cb(GtkWidget *combo, GaimGtkStatusSelector *selector); | |
63 static void signed_on_off_cb(GaimConnection *gc, GaimGtkStatusSelector *selector); | |
64 static void rebuild_list(GaimGtkStatusSelector *selector); | |
65 | |
66 static GtkVBox *parent_class = NULL; | |
67 | |
68 GType | |
69 gaim_gtk_status_selector_get_type(void) | |
70 { | |
71 static GType type = 0; | |
72 | |
73 if (!type) | |
74 { | |
75 static const GTypeInfo info = | |
76 { | |
77 sizeof(GaimGtkStatusSelectorClass), | |
78 NULL, | |
79 NULL, | |
80 (GClassInitFunc)gaim_gtk_status_selector_class_init, | |
81 NULL, | |
82 NULL, | |
83 sizeof(GaimGtkStatusSelector), | |
84 0, | |
85 (GInstanceInitFunc)gaim_gtk_status_selector_init | |
86 }; | |
87 | |
88 type = g_type_register_static(GTK_TYPE_VBOX, | |
89 "GaimGtkStatusSelector", &info, 0); | |
90 } | |
91 | |
92 return type; | |
93 } | |
94 | |
95 static void | |
96 gaim_gtk_status_selector_class_init(GaimGtkStatusSelectorClass *klass) | |
97 { | |
98 GObjectClass *gobject_class; | |
99 GtkObjectClass *object_class; | |
100 | |
101 parent_class = g_type_class_peek_parent(klass); | |
102 | |
103 gobject_class = G_OBJECT_CLASS(klass); | |
104 object_class = GTK_OBJECT_CLASS(klass); | |
105 | |
106 gobject_class->finalize = gaim_gtk_status_selector_finalize; | |
107 | |
108 object_class->destroy = gaim_gtk_status_selector_destroy; | |
109 } | |
110 | |
111 static void | |
112 gaim_gtk_status_selector_init(GaimGtkStatusSelector *selector) | |
113 { | |
114 GtkWidget *combo; | |
115 GtkWidget *entry; | |
116 GtkWidget *sw; | |
117 #if GTK_CHECK_VERSION(2,4,0) | |
118 GtkCellRenderer *renderer; | |
119 #endif | |
120 | |
121 selector->priv = g_new0(GaimGtkStatusSelectorPrivate, 1); | |
122 | |
123 selector->priv->icon_table = | |
124 g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
125 | |
126 g_hash_table_insert(selector->priv->icon_table, | |
127 "online", "available.png"); | |
128 g_hash_table_insert(selector->priv->icon_table, | |
129 "away", "away.png"); | |
130 | |
131 #if GTK_CHECK_VERSION(2,4,0) | |
132 selector->priv->model = gtk_list_store_new(NUM_COLUMNS, G_TYPE_POINTER, | |
133 GDK_TYPE_PIXBUF, G_TYPE_STRING); | |
134 | |
135 combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(selector->priv->model)); | |
136 selector->priv->combo = combo; | |
137 | |
138 g_object_unref(G_OBJECT(selector->priv->model)); | |
139 | |
140 renderer = gtk_cell_renderer_pixbuf_new(); | |
141 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, FALSE); | |
142 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), renderer, | |
143 "pixbuf", COLUMN_ICON, | |
144 NULL); | |
145 | |
146 renderer = gtk_cell_renderer_text_new(); | |
147 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, TRUE); | |
148 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), renderer, | |
149 "text", COLUMN_NAME, | |
150 NULL); | |
151 | |
152 g_signal_connect(G_OBJECT(combo), "changed", | |
153 G_CALLBACK(status_switched_cb), selector); | |
154 #else /* GTK < 2.4.0 */ | |
155 | |
156 /* TODO */ | |
157 | |
158 #endif /* GTK < 2.4.0 */ | |
159 | |
160 gtk_widget_show(combo); | |
161 gtk_box_pack_start(GTK_BOX(selector), combo, FALSE, FALSE, 0); | |
162 | |
163 selector->priv->sw = sw = gtk_scrolled_window_new(NULL, NULL); | |
164 gtk_box_pack_start(GTK_BOX(selector), sw, TRUE, TRUE, 0); | |
165 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), | |
166 GTK_SHADOW_IN); | |
167 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), | |
168 GTK_POLICY_NEVER, | |
169 GTK_POLICY_AUTOMATIC); | |
170 | |
171 selector->priv->entry = entry = gtk_imhtml_new(NULL, NULL); | |
172 gtk_widget_show(entry); | |
173 gtk_container_add(GTK_CONTAINER(sw), entry); | |
174 gtk_widget_set_name(entry, "gaim_gtk_status_selector_imhtml"); | |
175 gtk_imhtml_set_editable(GTK_IMHTML(entry), TRUE); | |
176 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(entry), GTK_WRAP_WORD_CHAR); | |
177 | |
178 if (gaim_prefs_get_bool("/gaim/gtk/conversations/spellcheck")) | |
179 gaim_gtk_setup_gtkspell(GTK_TEXT_VIEW(entry)); | |
180 | |
181 gaim_signal_connect(gaim_connections_get_handle(), "signed-on", | |
182 selector, GAIM_CALLBACK(signed_on_off_cb), | |
183 selector); | |
184 gaim_signal_connect(gaim_connections_get_handle(), "signed-off", | |
185 selector, GAIM_CALLBACK(signed_on_off_cb), | |
186 selector); | |
187 | |
188 rebuild_list(selector); | |
189 } | |
190 | |
191 static void | |
192 gaim_gtk_status_selector_finalize(GObject *obj) | |
193 { | |
194 GaimGtkStatusSelector *selector; | |
195 | |
196 g_return_if_fail(obj != NULL); | |
197 g_return_if_fail(GAIM_GTK_IS_STATUS_SELECTOR(obj)); | |
198 | |
199 selector = GAIM_GTK_STATUS_SELECTOR(obj); | |
200 | |
201 g_free(selector->priv); | |
202 | |
203 if (G_OBJECT_CLASS(parent_class)->finalize) | |
204 G_OBJECT_CLASS(parent_class)->finalize(obj); | |
205 } | |
206 | |
207 static void | |
208 gaim_gtk_status_selector_destroy(GtkObject *obj) | |
209 { | |
210 GaimGtkStatusSelector *selector; | |
211 | |
212 g_return_if_fail(obj != NULL); | |
213 g_return_if_fail(GAIM_GTK_IS_STATUS_SELECTOR(obj)); | |
214 | |
215 selector = GAIM_GTK_STATUS_SELECTOR(obj); | |
216 | |
217 if (selector->priv->icon_table != NULL) | |
218 { | |
219 g_hash_table_destroy(selector->priv->icon_table); | |
220 selector->priv->icon_table = NULL; | |
221 } | |
222 | |
223 if (GTK_OBJECT_CLASS(parent_class)->destroy) | |
224 GTK_OBJECT_CLASS(parent_class)->destroy(obj); | |
225 } | |
226 | |
227 static void | |
228 status_switched_cb(GtkWidget *combo, GaimGtkStatusSelector *selector) | |
229 { | |
230 GtkTreeIter iter; | |
231 | |
232 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(selector->priv->combo), | |
233 &iter)) | |
234 { | |
235 const char *status_type_id; | |
236 char *text; | |
237 GList *l; | |
238 | |
239 gtk_tree_model_get(GTK_TREE_MODEL(selector->priv->model), &iter, | |
240 COLUMN_NAME, &text, | |
241 COLUMN_STATUS_TYPE_ID, &status_type_id, | |
242 -1); | |
243 | |
244 if (!strcmp(text, _("New status"))) | |
245 { | |
246 /* TODO */ | |
247 } | |
248 else | |
249 { | |
250 const char *message = ""; | |
251 GtkTextBuffer *buffer; | |
252 gboolean allow_message = FALSE; | |
253 | |
254 buffer = | |
255 gtk_text_view_get_buffer(GTK_TEXT_VIEW(selector->priv->entry)); | |
256 | |
257 gtk_text_buffer_set_text(buffer, message, -1); | |
258 | |
259 for (l = gaim_connections_get_all(); l != NULL; l = l->next) | |
260 { | |
261 GaimConnection *gc = (GaimConnection *)l->data; | |
262 GaimAccount *account = gaim_connection_get_account(gc); | |
263 GaimStatusType *status_type; | |
264 | |
265 status_type = gaim_account_get_status_type(account, | |
266 status_type_id); | |
267 | |
268 if (status_type == NULL) | |
269 continue; | |
270 | |
271 if (gaim_status_type_get_attr(status_type, "message") != NULL) | |
272 { | |
273 gaim_account_set_status(account, | |
274 "away", TRUE, | |
275 "message", message, | |
276 NULL); | |
277 | |
278 allow_message = TRUE; | |
279 } | |
280 else | |
281 { | |
282 gaim_account_set_status(gaim_connection_get_account(gc), | |
283 "away", TRUE, | |
284 NULL); | |
285 } | |
286 } | |
287 | |
288 if (allow_message) | |
289 gtk_widget_show(selector->priv->sw); | |
290 else | |
291 gtk_widget_hide(selector->priv->sw); | |
292 } | |
293 } | |
294 } | |
295 | |
296 static void | |
297 signed_on_off_cb(GaimConnection *gc, GaimGtkStatusSelector *selector) | |
298 { | |
299 rebuild_list(selector); | |
300 } | |
301 | |
302 static GdkPixbuf * | |
303 load_icon(const char *basename) | |
304 { | |
305 char *filename; | |
306 GdkPixbuf *pixbuf, *scale = NULL; | |
307 | |
308 if (!strcmp(basename, "available.png")) | |
309 basename = "online.png"; | |
310 else if (!strcmp(basename, "hidden.png")) | |
311 basename = "invisible.png"; | |
312 | |
313 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "icons", | |
314 basename, NULL); | |
315 pixbuf = gdk_pixbuf_new_from_file(filename, NULL); | |
316 g_free(filename); | |
317 | |
318 if (pixbuf != NULL) | |
319 { | |
320 scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, | |
321 GDK_INTERP_BILINEAR); | |
322 | |
323 g_object_unref(G_OBJECT(pixbuf)); | |
324 } | |
325 else | |
326 { | |
327 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", | |
328 "default", basename, NULL); | |
329 scale = gdk_pixbuf_new_from_file(filename, NULL); | |
330 g_free(filename); | |
331 } | |
332 | |
333 return scale; | |
334 } | |
335 | |
336 static void | |
337 add_item(GaimGtkStatusSelector *selector, const char *status_type_id, | |
338 const char *text, GdkPixbuf *pixbuf) | |
339 { | |
340 GtkTreeIter iter; | |
341 | |
342 gtk_list_store_append(selector->priv->model, &iter); | |
343 gtk_list_store_set(selector->priv->model, &iter, | |
344 COLUMN_STATUS_TYPE_ID, status_type_id, | |
345 COLUMN_ICON, pixbuf, | |
346 COLUMN_NAME, text, | |
347 -1); | |
348 | |
349 if (pixbuf != NULL) | |
350 g_object_unref(G_OBJECT(pixbuf)); | |
351 } | |
352 | |
353 static void | |
354 rebuild_list(GaimGtkStatusSelector *selector) | |
355 { | |
356 gboolean single_prpl = TRUE; | |
357 GaimAccount *first_account = NULL; | |
358 const char *first_prpl_type = NULL; | |
359 GList *l; | |
360 | |
361 g_return_if_fail(selector != NULL); | |
362 g_return_if_fail(GAIM_GTK_IS_STATUS_SELECTOR(selector)); | |
363 | |
364 gtk_list_store_clear(selector->priv->model); | |
365 | |
366 /* | |
367 * If the user only has one IM account or one type of IM account | |
368 * connected, they'll see all their statuses. This is ideal for those | |
369 * who use only one account, or one single protocol. Everyone else | |
370 * gets Available and Away and a list of saved statuses. | |
371 */ | |
372 for (l = gaim_connections_get_all(); l != NULL && single_prpl; l = l->next) | |
373 { | |
374 GaimConnection *gc = (GaimConnection *)l->data; | |
375 GaimAccount *account = gaim_connection_get_account(gc); | |
376 GaimPluginProtocolInfo *prpl_info; | |
377 const char *basename; | |
378 | |
379 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
380 basename = prpl_info->list_icon(account, NULL); | |
381 | |
382 if (first_prpl_type == NULL) | |
383 { | |
384 first_prpl_type = basename; | |
385 first_account = account; | |
386 } | |
387 else if (!strcmp(first_prpl_type, basename)) | |
388 single_prpl = FALSE; | |
389 } | |
390 | |
391 if (single_prpl) | |
392 { | |
393 const GList *l; | |
394 | |
395 for (l = gaim_account_get_status_types(first_account); | |
396 l != NULL; | |
397 l = l->next) | |
398 { | |
399 GaimStatusType *status_type = (GaimStatusType *)l->data; | |
400 char filename[BUFSIZ]; | |
401 | |
402 if (!gaim_status_type_is_user_settable(status_type)) | |
403 continue; | |
404 | |
405 g_snprintf(filename, sizeof(filename), "%s.png", | |
406 gaim_status_type_get_id(status_type)); | |
407 | |
408 add_item(selector, | |
409 gaim_status_type_get_id(status_type), | |
410 gaim_status_type_get_name(status_type), | |
411 load_icon(filename)); | |
412 } | |
413 } | |
414 else | |
415 { | |
416 add_item(selector, "available", _("Available"), | |
417 load_icon("online.png")); | |
418 add_item(selector, "away", _("Away"), load_icon("away.png")); | |
419 } | |
420 | |
421 add_item(selector, NULL, _("New Status"), | |
422 gtk_widget_render_icon(GTK_WIDGET(selector), GTK_STOCK_NEW, | |
423 GTK_ICON_SIZE_MENU, NULL)); | |
424 } | |
425 | |
426 GtkWidget * | |
427 gaim_gtk_status_selector_new(void) | |
428 { | |
429 GaimGtkStatusSelector *selector; | |
430 | |
431 selector = g_object_new(GAIM_GTK_TYPE_STATUS_SELECTOR, NULL); | |
432 | |
433 return GTK_WIDGET(selector); | |
434 } |