Mercurial > pidgin.yaz
annotate src/gtkstatusbox.c @ 11756:f54c680d835c
[gaim-migrate @ 14047]
So. This fixes the status box on Gtk 2.2. Honestly, I'm not sure why or how.
It appears that trying to use the status box itself as the widget to pass to
gtk_widget_render_icon() causes things to get horribly confused or corrupted,
with some very bizarre side effects that I never really managed to debug. (I
assume it's somehow related to the fact that this code is all being called
from within the status box's own init function).
So I just used the status box's vbox instead, and bingo, it no longer lists
"Available" a billion times in the dropdown.
I've been trying to nail this issue on and off since the day the status box
landed in CVS. I'm pleased to have it working now, but also annoyed it took
so long and isn't really understandable.
I wonder how much is broken on Gtk 2.0 now?
committer: Tailor Script <tailor@pidgin.im>
author | Stu Tomlinson <stu@nosnilmot.com> |
---|---|
date | Sun, 23 Oct 2005 17:12:52 +0000 |
parents | 50496ebef401 |
children | 7584d802f0ac |
rev | line source |
---|---|
10643 | 1 /* |
2 * @file gtkstatusbox.c GTK+ Status Selection 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 | |
11627 | 26 #include "account.h" |
10643 | 27 #include "internal.h" |
11627 | 28 #include "savedstatuses.h" |
10643 | 29 #include "status.h" |
11732 | 30 #include "debug.h" |
11627 | 31 |
10643 | 32 #include "gtkgaim.h" |
11729 | 33 #include "gtksavedstatuses.h" |
10643 | 34 #include "gtkstock.h" |
35 #include "gtkstatusbox.h" | |
36 | |
37 static void imhtml_changed_cb(GtkTextBuffer *buffer, void *data); | |
11562 | 38 static void remove_typing_cb(GtkGaimStatusBox *box); |
10643 | 39 |
11732 | 40 static void gtk_gaim_status_box_regenerate(GtkGaimStatusBox *status_box); |
10643 | 41 static void gtk_gaim_status_box_changed(GtkComboBox *box); |
42 static void gtk_gaim_status_box_size_request (GtkWidget *widget, GtkRequisition *requisition); | |
43 static void gtk_gaim_status_box_size_allocate (GtkWidget *widget, GtkAllocation *allocation); | |
44 static gboolean gtk_gaim_status_box_expose_event (GtkWidget *widget, GdkEventExpose *event); | |
45 static void gtk_gaim_status_box_forall (GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data); | |
46 | |
47 static void (*combo_box_size_request)(GtkWidget *widget, GtkRequisition *requisition); | |
48 static void (*combo_box_size_allocate)(GtkWidget *widget, GtkAllocation *allocation); | |
49 static gboolean (*combo_box_expose_event)(GtkWidget *widget, GdkEventExpose *event); | |
50 static void (*combo_box_forall) (GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data); | |
11739 | 51 |
10643 | 52 enum { |
11739 | 53 TYPE_COLUMN, /* A GtkGaimStatusBoxItemType */ |
11738 | 54 ICON_COLUMN, /* This is a GdkPixbuf (the other columns are strings) */ |
55 TEXT_COLUMN, /* A string */ | |
56 TITLE_COLUMN, /* The plain-English title of this item */ | |
57 DESC_COLUMN, /* A plain-English description of this item */ | |
10643 | 58 NUM_COLUMNS |
59 }; | |
60 | |
11499 | 61 enum { |
62 PROP_0, | |
63 PROP_ACCOUNT | |
64 }; | |
65 | |
10643 | 66 static void gtk_gaim_status_box_class_init (GtkGaimStatusBoxClass *klass); |
67 static void gtk_gaim_status_box_init (GtkGaimStatusBox *status_box); | |
68 | |
69 GType | |
70 gtk_gaim_status_box_get_type (void) | |
71 { | |
10861 | 72 static GType status_box_type = 0; |
10643 | 73 |
10861 | 74 if (!status_box_type) |
75 { | |
76 static const GTypeInfo status_box_info = | |
77 { | |
78 sizeof (GtkGaimStatusBoxClass), | |
79 NULL, /* base_init */ | |
80 NULL, /* base_finalize */ | |
81 (GClassInitFunc) gtk_gaim_status_box_class_init, | |
82 NULL, /* class_finalize */ | |
83 NULL, /* class_data */ | |
84 sizeof (GtkGaimStatusBox), | |
85 0, | |
86 (GInstanceInitFunc) gtk_gaim_status_box_init | |
87 }; | |
10643 | 88 |
10861 | 89 status_box_type = g_type_register_static(GTK_TYPE_COMBO_BOX, |
90 "GtkGaimStatusBox", | |
91 &status_box_info, | |
92 0); | |
93 } | |
10643 | 94 |
10861 | 95 return status_box_type; |
10643 | 96 } |
97 | |
98 static void | |
11499 | 99 gtk_gaim_status_box_get_property(GObject *object, guint param_id, |
100 GValue *value, GParamSpec *psec) | |
101 { | |
102 GtkGaimStatusBox *statusbox = GTK_GAIM_STATUS_BOX(object); | |
103 | |
104 switch (param_id) { | |
105 case PROP_ACCOUNT: | |
106 g_value_set_pointer(value, statusbox->account); | |
107 break; | |
108 default: | |
109 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, psec); | |
110 break; | |
111 } | |
112 } | |
113 | |
114 static void | |
115 gtk_gaim_status_box_set_property(GObject *object, guint param_id, | |
116 const GValue *value, GParamSpec *pspec) | |
117 { | |
118 GtkGaimStatusBox *statusbox = GTK_GAIM_STATUS_BOX(object); | |
119 | |
120 switch (param_id) { | |
121 case PROP_ACCOUNT: | |
122 statusbox->account = g_value_get_pointer(value); | |
11732 | 123 gtk_gaim_status_box_regenerate(statusbox); |
11499 | 124 break; |
125 default: | |
126 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); | |
127 break; | |
128 } | |
129 } | |
130 | |
131 | |
132 static void | |
10643 | 133 gtk_gaim_status_box_class_init (GtkGaimStatusBoxClass *klass) |
134 { | |
10861 | 135 GObjectClass *object_class; |
136 GtkWidgetClass *widget_class; | |
137 GtkComboBoxClass *parent_class = (GtkComboBoxClass*)klass; | |
138 GtkContainerClass *container_class = (GtkContainerClass*)klass; | |
10643 | 139 |
10861 | 140 parent_class->changed = gtk_gaim_status_box_changed; |
141 widget_class = (GtkWidgetClass*)klass; | |
142 combo_box_size_request = widget_class->size_request; | |
143 widget_class->size_request = gtk_gaim_status_box_size_request; | |
144 combo_box_size_allocate = widget_class->size_allocate; | |
145 widget_class->size_allocate = gtk_gaim_status_box_size_allocate; | |
146 combo_box_expose_event = widget_class->expose_event; | |
147 widget_class->expose_event = gtk_gaim_status_box_expose_event; | |
10643 | 148 |
10861 | 149 combo_box_forall = container_class->forall; |
150 container_class->forall = gtk_gaim_status_box_forall; | |
151 | |
152 object_class = (GObjectClass *)klass; | |
11499 | 153 |
154 object_class->get_property = gtk_gaim_status_box_get_property; | |
155 object_class->set_property = gtk_gaim_status_box_set_property; | |
156 | |
157 g_object_class_install_property(object_class, | |
158 PROP_ACCOUNT, | |
159 g_param_spec_pointer("account", | |
160 "Account", | |
161 "The account, or NULL for all accounts", | |
162 G_PARAM_READWRITE | |
163 ) | |
164 ); | |
10643 | 165 } |
166 | |
167 static void | |
168 gtk_gaim_status_box_refresh(GtkGaimStatusBox *status_box) | |
169 { | |
10672
0925c898b73c
[gaim-migrate @ 12212]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10661
diff
changeset
|
170 char *text, *title; |
10643 | 171 char aa_color[8]; |
172 GdkPixbuf *pixbuf; | |
10702 | 173 GtkTreePath *path; |
10643 | 174 |
175 GtkStyle *style = gtk_widget_get_style(GTK_WIDGET(status_box)); | |
176 snprintf(aa_color, sizeof(aa_color), "#%02x%02x%02x", | |
177 style->text_aa[GTK_STATE_NORMAL].red >> 8, | |
178 style->text_aa[GTK_STATE_NORMAL].green >> 8, | |
179 style->text_aa[GTK_STATE_NORMAL].blue >> 8); | |
10672
0925c898b73c
[gaim-migrate @ 12212]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10661
diff
changeset
|
180 |
0925c898b73c
[gaim-migrate @ 12212]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10661
diff
changeset
|
181 title = status_box->title; |
0925c898b73c
[gaim-migrate @ 12212]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10661
diff
changeset
|
182 if (!title) |
0925c898b73c
[gaim-migrate @ 12212]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10661
diff
changeset
|
183 title = ""; |
0925c898b73c
[gaim-migrate @ 12212]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10661
diff
changeset
|
184 |
10643 | 185 if (status_box->error) { |
11499 | 186 text = g_strdup_printf("%s\n<span size=\"smaller\" weight=\"bold\" color=\"red\">%s</span>", |
10861 | 187 title, status_box->error); |
10643 | 188 } else if (status_box->typing) { |
10861 | 189 text = g_strdup_printf("%s\n<span size=\"smaller\" color=\"%s\">%s</span>", |
190 title, aa_color, _("Typing")); | |
10643 | 191 } else if (status_box->connecting) { |
10861 | 192 text = g_strdup_printf("%s\n<span size=\"smaller\" color=\"%s\">%s</span>", |
193 title, aa_color, _("Connecting")); | |
194 } else if (status_box->desc) { | |
195 text = g_strdup_printf("%s\n<span size=\"smaller\" color=\"%s\">%s</span>", | |
196 title, aa_color, status_box->desc); | |
10643 | 197 } else { |
10672
0925c898b73c
[gaim-migrate @ 12212]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10661
diff
changeset
|
198 text = g_strdup_printf("%s", title); |
10643 | 199 } |
10861 | 200 |
11523 | 201 if (status_box->connecting) |
202 pixbuf = status_box->connecting_pixbufs[status_box->connecting_index]; | |
203 else if (status_box->error) | |
10643 | 204 pixbuf = status_box->error_pixbuf; |
205 else if (status_box->typing) | |
206 pixbuf = status_box->typing_pixbufs[status_box->typing_index]; | |
207 else | |
208 pixbuf = status_box->pixbuf; | |
209 | |
210 gtk_list_store_set(status_box->store, &(status_box->iter), | |
11755 | 211 TYPE_COLUMN, -1, /* This field is not used in this list store */ |
10643 | 212 ICON_COLUMN, pixbuf, |
10861 | 213 TEXT_COLUMN, text, |
10672
0925c898b73c
[gaim-migrate @ 12212]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10661
diff
changeset
|
214 TITLE_COLUMN, title, |
10861 | 215 DESC_COLUMN, status_box->desc, |
11739 | 216 -1); |
10702 | 217 path = gtk_tree_path_new_from_string("0"); |
218 gtk_cell_view_set_displayed_row(GTK_CELL_VIEW(status_box->cell_view), path); | |
219 gtk_tree_path_free(path); | |
10643 | 220 |
221 g_free(text); | |
222 } | |
223 | |
11732 | 224 static GdkPixbuf * |
225 load_icon(const char *basename) | |
226 { | |
227 char basename2[BUFSIZ]; | |
228 char *filename; | |
229 GdkPixbuf *pixbuf, *scale = NULL; | |
230 | |
231 if (!strcmp(basename, "available")) | |
232 basename = "online"; | |
233 else if (!strcmp(basename, "hidden")) | |
234 basename = "invisible"; | |
235 | |
236 /* | |
237 * TODO: Find a way to fallback to the GaimStatusPrimitive | |
238 * if an icon for this id does not exist. | |
239 */ | |
240 g_snprintf(basename2, sizeof(basename2), "%s.png", | |
241 basename); | |
242 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "icons", | |
243 basename2, NULL); | |
244 pixbuf = gdk_pixbuf_new_from_file(filename, NULL); | |
245 g_free(filename); | |
246 | |
247 if (pixbuf != NULL) { | |
248 scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, | |
249 GDK_INTERP_BILINEAR); | |
250 | |
251 g_object_unref(G_OBJECT(pixbuf)); | |
252 } else { | |
253 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", | |
254 "default", basename, NULL); | |
255 scale = gdk_pixbuf_new_from_file(filename, NULL); | |
256 g_free(filename); | |
257 } | |
258 | |
259 return scale; | |
260 } | |
261 | |
262 static void | |
263 gtk_gaim_status_box_regenerate(GtkGaimStatusBox *status_box) | |
264 { | |
11739 | 265 GaimAccount *account; |
11732 | 266 GdkPixbuf *pixbuf, *pixbuf2, *pixbuf3, *pixbuf4; |
267 GtkIconSize icon_size; | |
268 const char *current_savedstatus_name; | |
269 GaimSavedStatus *saved_status; | |
270 | |
271 icon_size = gtk_icon_size_from_name(GAIM_ICON_SIZE_STATUS); | |
272 | |
273 gtk_list_store_clear(status_box->dropdown_store); | |
274 | |
11739 | 275 account = GTK_GAIM_STATUS_BOX(status_box)->account; |
276 if (account == NULL) | |
277 { | |
11756 | 278 pixbuf = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_ONLINE, |
11732 | 279 icon_size, "GtkGaimStatusBox"); |
11756 | 280 pixbuf2 = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_AWAY, |
11732 | 281 icon_size, "GtkGaimStatusBox"); |
11756 | 282 pixbuf3 = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_OFFLINE, |
11732 | 283 icon_size, "GtkGaimStatusBox"); |
11756 | 284 pixbuf4 = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_INVISIBLE, |
11732 | 285 icon_size, "GtkGaimStatusBox"); |
286 /* hacks */ | |
11739 | 287 gtk_gaim_status_box_add(GTK_GAIM_STATUS_BOX(status_box), GAIM_STATUS_AVAILABLE, pixbuf, _("Available"), NULL); |
288 gtk_gaim_status_box_add(GTK_GAIM_STATUS_BOX(status_box), GAIM_STATUS_AWAY, pixbuf2, _("Away"), NULL); | |
289 gtk_gaim_status_box_add(GTK_GAIM_STATUS_BOX(status_box), GAIM_STATUS_HIDDEN, pixbuf4, _("Invisible"), NULL); | |
290 gtk_gaim_status_box_add(GTK_GAIM_STATUS_BOX(status_box), GAIM_STATUS_OFFLINE, pixbuf3, _("Offline"), NULL); | |
11738 | 291 gtk_gaim_status_box_add_separator(GTK_GAIM_STATUS_BOX(status_box)); |
11739 | 292 gtk_gaim_status_box_add(GTK_GAIM_STATUS_BOX(status_box), GTK_GAIM_STATUS_BOX_TYPE_CUSTOM, pixbuf, _("Custom..."), NULL); |
293 gtk_gaim_status_box_add(GTK_GAIM_STATUS_BOX(status_box), GTK_GAIM_STATUS_BOX_TYPE_SAVED, pixbuf, _("Saved..."), NULL); | |
11732 | 294 |
295 current_savedstatus_name = gaim_prefs_get_string("/core/status/current"); | |
296 saved_status = gaim_savedstatus_find(current_savedstatus_name); | |
297 if (saved_status == NULL) | |
298 { | |
299 /* Default to "available" */ | |
300 gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 0); | |
301 } | |
302 else | |
303 { | |
304 GaimStatusPrimitive primitive; | |
305 const char *message; | |
306 | |
307 primitive = gaim_savedstatus_get_type(saved_status); | |
308 if (gaim_savedstatus_has_substatuses(saved_status) || | |
309 ((primitive != GAIM_STATUS_AVAILABLE) && | |
310 (primitive != GAIM_STATUS_OFFLINE) && | |
311 (primitive != GAIM_STATUS_AWAY) && | |
312 (primitive != GAIM_STATUS_HIDDEN))) | |
313 { | |
314 gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 4); | |
315 } | |
316 else | |
317 { | |
318 if (primitive == GAIM_STATUS_AVAILABLE) | |
319 gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 0); | |
320 if (primitive == GAIM_STATUS_OFFLINE) | |
321 gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 3); | |
322 else if (primitive == GAIM_STATUS_AWAY) | |
323 gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 1); | |
324 else if (primitive == GAIM_STATUS_HIDDEN) | |
325 gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 2); | |
326 } | |
327 | |
328 message = gaim_savedstatus_get_message(saved_status); | |
329 if (message != NULL) | |
330 gtk_imhtml_append_text(GTK_IMHTML(status_box->imhtml), message, 0); | |
331 } | |
332 | |
333 | |
334 } else { | |
335 const GList *l; | |
11739 | 336 |
337 for (l = gaim_account_get_status_types(account); l != NULL; l = l->next) | |
338 { | |
11732 | 339 GaimStatusType *status_type = (GaimStatusType *)l->data; |
340 | |
341 if (!gaim_status_type_is_user_settable(status_type)) | |
342 continue; | |
343 | |
11739 | 344 gtk_gaim_status_box_add(GTK_GAIM_STATUS_BOX(status_box), |
345 gaim_status_type_get_primitive(status_type), | |
346 load_icon(gaim_status_type_get_id(status_type)), | |
347 gaim_status_type_get_name(status_type), | |
348 NULL); | |
11732 | 349 } |
350 } | |
351 | |
352 } | |
353 | |
11753 | 354 #if GTK_CHECK_VERSION(2,6,0) |
11738 | 355 static gboolean |
356 dropdown_store_row_separator_func(GtkTreeModel *model, | |
357 GtkTreeIter *iter, gpointer data) | |
358 { | |
11739 | 359 GtkGaimStatusBoxItemType type; |
11738 | 360 GdkPixbuf *pixbuf; |
11739 | 361 gchar *text, *title, *description; |
11738 | 362 |
363 gtk_tree_model_get(model, iter, | |
11739 | 364 TYPE_COLUMN, &type, |
11738 | 365 ICON_COLUMN, &pixbuf, |
366 TEXT_COLUMN, &text, | |
367 TITLE_COLUMN, &title, | |
368 DESC_COLUMN, &description, | |
369 -1); | |
370 | |
11739 | 371 if (type == GTK_GAIM_STATUS_BOX_TYPE_SEPARATOR) |
11738 | 372 return TRUE; |
373 | |
374 return FALSE; | |
375 } | |
11753 | 376 #endif |
11738 | 377 |
10643 | 378 static void |
379 gtk_gaim_status_box_init (GtkGaimStatusBox *status_box) | |
380 { | |
11400 | 381 GtkCellRenderer *text_rend; |
382 GtkCellRenderer *icon_rend; | |
10643 | 383 GtkTextBuffer *buffer; |
11732 | 384 GtkTreePath *path; |
11400 | 385 GtkIconSize icon_size; |
386 | |
387 text_rend = gtk_cell_renderer_text_new(); | |
388 icon_rend = gtk_cell_renderer_pixbuf_new(); | |
389 icon_size = gtk_icon_size_from_name(GAIM_ICON_SIZE_STATUS); | |
10643 | 390 |
391 status_box->imhtml_visible = FALSE; | |
392 status_box->connecting = FALSE; | |
393 status_box->typing = FALSE; | |
394 status_box->title = NULL; | |
10861 | 395 status_box->pixbuf = NULL; |
10643 | 396 status_box->cell_view = gtk_cell_view_new(); |
397 gtk_widget_show (status_box->cell_view); | |
10861 | 398 |
11739 | 399 status_box->store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); |
400 status_box->dropdown_store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); | |
11753 | 401 #if GTK_CHECK_VERSION(2,6,0) |
11738 | 402 gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(status_box), dropdown_store_row_separator_func, NULL, NULL); |
11753 | 403 #endif |
10643 | 404 gtk_combo_box_set_model(GTK_COMBO_BOX(status_box), GTK_TREE_MODEL(status_box->dropdown_store)); |
405 gtk_cell_view_set_model(GTK_CELL_VIEW(status_box->cell_view), GTK_TREE_MODEL(status_box->store)); | |
406 gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(status_box), 0); | |
407 gtk_list_store_append(status_box->store, &(status_box->iter)); | |
408 gtk_gaim_status_box_refresh(status_box); | |
11593
4b7fb30b8926
[gaim-migrate @ 13863]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11562
diff
changeset
|
409 path = gtk_tree_path_new_from_string("0"); |
4b7fb30b8926
[gaim-migrate @ 13863]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11562
diff
changeset
|
410 gtk_cell_view_set_displayed_row(GTK_CELL_VIEW(status_box->cell_view), path); |
4b7fb30b8926
[gaim-migrate @ 13863]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11562
diff
changeset
|
411 gtk_tree_path_free(path); |
10643 | 412 gtk_container_add(GTK_CONTAINER(status_box), status_box->cell_view); |
10861 | 413 |
10643 | 414 status_box->icon_rend = gtk_cell_renderer_pixbuf_new(); |
415 status_box->text_rend = gtk_cell_renderer_text_new(); | |
416 | |
417 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(status_box), icon_rend, FALSE); | |
10861 | 418 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(status_box), text_rend, TRUE); |
10643 | 419 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(status_box), icon_rend, "pixbuf", ICON_COLUMN, NULL); |
420 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(status_box), text_rend, "markup", TEXT_COLUMN, NULL); | |
421 | |
422 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(status_box->cell_view), status_box->icon_rend, FALSE); | |
11499 | 423 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(status_box->cell_view), status_box->text_rend, TRUE); |
10643 | 424 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(status_box->cell_view), status_box->icon_rend, "pixbuf", ICON_COLUMN, NULL); |
425 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(status_box->cell_view), status_box->text_rend, "markup", TEXT_COLUMN, NULL); | |
426 | |
427 status_box->vbox = gtk_vbox_new(0, FALSE); | |
428 status_box->imhtml = gtk_imhtml_new(NULL, NULL); | |
429 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(status_box->imhtml)); | |
430 g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK(imhtml_changed_cb), status_box); | |
11562 | 431 g_signal_connect_swapped(G_OBJECT(status_box->imhtml), "message_send", G_CALLBACK(remove_typing_cb), status_box); |
10643 | 432 gtk_imhtml_set_editable(GTK_IMHTML(status_box->imhtml), TRUE); |
433 gtk_widget_set_parent(status_box->vbox, GTK_WIDGET(status_box)); | |
434 status_box->sw = gtk_scrolled_window_new(NULL, NULL); | |
435 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(status_box->sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
436 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(status_box->sw), GTK_SHADOW_IN); | |
437 gtk_container_add(GTK_CONTAINER(status_box->sw), status_box->imhtml); | |
438 gtk_box_pack_start(GTK_BOX(status_box->vbox), status_box->sw, TRUE, TRUE, 0); | |
11654 | 439 |
11756 | 440 status_box->error_pixbuf = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_OFFLINE, |
441 icon_size, "GtkGaimStatusBox"); | |
442 status_box->connecting_index = 0; | |
443 status_box->connecting_pixbufs[0] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_CONNECT0, | |
444 icon_size, "GtkGaimStatusBox"); | |
445 status_box->connecting_pixbufs[1] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_CONNECT1, | |
446 icon_size, "GtkGaimStatusBox"); | |
447 status_box->connecting_pixbufs[2] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_CONNECT2, | |
448 icon_size, "GtkGaimStatusBox"); | |
449 status_box->connecting_pixbufs[3] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_CONNECT3, | |
450 icon_size, "GtkGaimStatusBox"); | |
451 | |
452 status_box->typing_index = 0; | |
453 status_box->typing_pixbufs[0] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_TYPING0, | |
454 icon_size, "GtkGaimStatusBox"); | |
455 status_box->typing_pixbufs[1] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_TYPING1, | |
456 icon_size, "GtkGaimStatusBox"); | |
457 status_box->typing_pixbufs[2] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_TYPING2, | |
458 icon_size, "GtkGaimStatusBox"); | |
459 status_box->typing_pixbufs[3] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_TYPING3, | |
460 icon_size, "GtkGaimStatusBox"); | |
461 | |
11732 | 462 gtk_gaim_status_box_regenerate(status_box); |
10643 | 463 } |
464 | |
465 | |
466 static void | |
10861 | 467 gtk_gaim_status_box_size_request(GtkWidget *widget, |
468 GtkRequisition *requisition) | |
10643 | 469 { |
470 GtkRequisition box_req; | |
471 combo_box_size_request(widget, requisition); | |
10861 | 472 |
10643 | 473 gtk_widget_size_request(GTK_GAIM_STATUS_BOX(widget)->vbox, &box_req); |
474 if (box_req.height > 1) | |
475 requisition->height = requisition->height + box_req.height + 6; | |
10861 | 476 |
10643 | 477 requisition->width = 1; |
478 | |
479 } | |
480 | |
481 static void | |
10861 | 482 gtk_gaim_status_box_size_allocate(GtkWidget *widget, |
483 GtkAllocation *allocation) | |
10643 | 484 { |
485 GtkRequisition req = {0,0}; | |
11400 | 486 GtkAllocation parent_alc, box_alc; |
487 | |
488 parent_alc = *allocation; | |
489 box_alc = *allocation; | |
10643 | 490 combo_box_size_request(widget, &req); |
10861 | 491 |
10643 | 492 /* EVIL XXX */ |
10861 | 493 box_alc.height = 80; |
494 /* box_alc.height = MAX(1,box_alc.height - req.height - 6); */ | |
495 | |
10643 | 496 box_alc.y = box_alc.y + req.height + 6; |
497 gtk_widget_size_allocate((GTK_GAIM_STATUS_BOX(widget))->vbox, &box_alc); | |
10861 | 498 |
10643 | 499 parent_alc.height = MAX(1,req.height); |
500 combo_box_size_allocate(widget, &parent_alc); | |
501 widget->allocation = *allocation; | |
502 } | |
503 | |
504 | |
505 static gboolean | |
10861 | 506 gtk_gaim_status_box_expose_event(GtkWidget *widget, |
507 GdkEventExpose *event) | |
10643 | 508 { |
10861 | 509 GtkGaimStatusBox *status_box = GTK_GAIM_STATUS_BOX(widget); |
510 combo_box_expose_event(widget, event); | |
10643 | 511 |
10861 | 512 gtk_container_propagate_expose(GTK_CONTAINER(widget), |
513 status_box->vbox, event); | |
514 return FALSE; | |
10643 | 515 } |
516 | |
517 static void | |
10861 | 518 gtk_gaim_status_box_forall(GtkContainer *container, |
519 gboolean include_internals, | |
520 GtkCallback callback, | |
521 gpointer callback_data) | |
10643 | 522 { |
10861 | 523 GtkGaimStatusBox *status_box = GTK_GAIM_STATUS_BOX (container); |
10643 | 524 |
10861 | 525 if (include_internals) |
526 { | |
527 (* callback) (status_box->vbox, callback_data); | |
528 } | |
10643 | 529 |
10861 | 530 combo_box_forall(container, include_internals, callback, callback_data); |
10643 | 531 } |
532 | |
533 GtkWidget * | |
534 gtk_gaim_status_box_new() | |
535 { | |
536 return g_object_new(GTK_GAIM_TYPE_STATUS_BOX, NULL); | |
537 } | |
538 | |
11499 | 539 GtkWidget * |
540 gtk_gaim_status_box_new_with_account(GaimAccount *account) | |
541 { | |
542 return g_object_new(GTK_GAIM_TYPE_STATUS_BOX, "account", account, NULL); | |
543 } | |
10643 | 544 |
545 void | |
11739 | 546 gtk_gaim_status_box_add(GtkGaimStatusBox *status_box, GtkGaimStatusBoxItemType type, GdkPixbuf *pixbuf, const char *text, const char *sec_text) |
10643 | 547 { |
548 GtkTreeIter iter; | |
549 char *t; | |
10861 | 550 |
10643 | 551 if (sec_text) { |
552 char aa_color[8]; | |
553 GtkStyle *style = gtk_widget_get_style(GTK_WIDGET(status_box)); | |
554 snprintf(aa_color, sizeof(aa_color), "#%02x%02x%02x", | |
555 style->text_aa[GTK_STATE_NORMAL].red >> 8, | |
556 style->text_aa[GTK_STATE_NORMAL].green >> 8, | |
10861 | 557 style->text_aa[GTK_STATE_NORMAL].blue >> 8); |
10643 | 558 t = g_strdup_printf("%s\n<span color=\"%s\">%s</span>", text, aa_color, sec_text); |
559 } else { | |
560 t = g_strdup(text); | |
561 } | |
10861 | 562 |
10643 | 563 gtk_list_store_append(status_box->dropdown_store, &iter); |
564 gtk_list_store_set(status_box->dropdown_store, &iter, | |
11739 | 565 TYPE_COLUMN, type, |
10643 | 566 ICON_COLUMN, pixbuf, |
10861 | 567 TEXT_COLUMN, t, |
10643 | 568 TITLE_COLUMN, text, |
10861 | 569 DESC_COLUMN, sec_text, |
11739 | 570 -1); |
11638 | 571 g_free(t); |
10643 | 572 } |
573 | |
574 void | |
11738 | 575 gtk_gaim_status_box_add_separator(GtkGaimStatusBox *status_box) |
576 { | |
11756 | 577 /* Don't do anything unless GTK actually supports |
578 * gtk_combo_box_set_row_separator_func */ | |
579 #if GTK_CHECK_VERSION(2,6,0) | |
11738 | 580 GtkTreeIter iter; |
581 | |
582 gtk_list_store_append(status_box->dropdown_store, &iter); | |
583 gtk_list_store_set(status_box->dropdown_store, &iter, | |
11739 | 584 TYPE_COLUMN, GTK_GAIM_STATUS_BOX_TYPE_SEPARATOR, |
585 -1); | |
11756 | 586 #endif |
11738 | 587 } |
588 | |
589 void | |
10643 | 590 gtk_gaim_status_box_set_error(GtkGaimStatusBox *status_box, const gchar *error) |
591 { | |
11523 | 592 if (status_box->error) |
593 g_free(status_box->error); | |
10643 | 594 status_box->error = g_strdup(error); |
595 gtk_gaim_status_box_refresh(status_box); | |
596 } | |
597 | |
598 void | |
599 gtk_gaim_status_box_set_connecting(GtkGaimStatusBox *status_box, gboolean connecting) | |
600 { | |
601 if (!status_box) | |
602 return; | |
603 status_box->connecting = connecting; | |
604 gtk_gaim_status_box_refresh(status_box); | |
605 } | |
606 | |
607 void | |
608 gtk_gaim_status_box_pulse_connecting(GtkGaimStatusBox *status_box) | |
609 { | |
610 if (!status_box) | |
611 return; | |
612 if (status_box->connecting_index == 3) | |
613 status_box->connecting_index = 0; | |
10861 | 614 else |
10643 | 615 status_box->connecting_index++; |
616 gtk_gaim_status_box_refresh(status_box); | |
617 } | |
618 | |
619 void | |
620 gtk_gaim_status_box_pulse_typing(GtkGaimStatusBox *status_box) | |
621 { | |
622 if (status_box->typing_index == 3) | |
623 status_box->typing_index = 0; | |
10861 | 624 else |
10643 | 625 status_box->typing_index++; |
626 gtk_gaim_status_box_refresh(status_box); | |
627 } | |
628 | |
11654 | 629 static void |
630 activate_currently_selected_status(GtkGaimStatusBox *status_box) | |
10643 | 631 { |
11739 | 632 GtkGaimStatusBoxItemType type; |
633 gchar *title; | |
10643 | 634 GList *l; |
635 GtkTreeIter iter; | |
11654 | 636 char *message; |
637 GaimSavedStatus *saved_status; | |
10643 | 638 |
11654 | 639 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(status_box), &iter); |
640 gtk_tree_model_get(GTK_TREE_MODEL(status_box->dropdown_store), &iter, | |
11739 | 641 TYPE_COLUMN, &type, |
11638 | 642 TITLE_COLUMN, &title, -1); |
11654 | 643 message = gtk_gaim_status_box_get_message(status_box); |
11739 | 644 |
645 /* | |
646 * If the currently selected status is "Custom..." or | |
647 * "Saved..." then do nothing. | |
648 */ | |
649 if ((type < 0) || (type >= GAIM_STATUS_NUM_PRIMITIVES)) | |
650 return; | |
11654 | 651 |
652 /* TODO: Should save the previous status as a transient status? */ | |
653 | |
654 /* Save the newly selected status to prefs.xml and status.xml */ | |
655 saved_status = gaim_savedstatus_find(_("Default")); | |
656 if (saved_status == NULL) | |
11739 | 657 saved_status = gaim_savedstatus_new(_("Default"), type); |
658 gaim_savedstatus_set_type(saved_status, type); | |
11654 | 659 gaim_savedstatus_set_message(saved_status, message); |
660 gaim_prefs_set_string("/core/status/current", _("Default")); | |
661 | |
662 /* Set the status for each account */ | |
663 for (l = gaim_accounts_get_all(); l != NULL; l = l->next) | |
664 { | |
10643 | 665 GaimAccount *account = (GaimAccount*)l->data; |
666 GaimStatusType *status_type; | |
10861 | 667 |
10643 | 668 if (!gaim_account_get_enabled(account, GAIM_GTK_UI)) |
669 continue; | |
670 | |
11739 | 671 status_type = gaim_account_get_status_type_with_primitive(account, type); |
10643 | 672 |
673 if (status_type == NULL) | |
674 continue; | |
11638 | 675 |
11739 | 676 gaim_account_set_status(account, |
677 gaim_status_type_get_id(status_type), | |
678 TRUE, "message", message, NULL); | |
10643 | 679 } |
11627 | 680 |
11638 | 681 g_free(title); |
11654 | 682 g_free(message); |
683 } | |
684 | |
685 static void remove_typing_cb(GtkGaimStatusBox *status_box) | |
686 { | |
687 activate_currently_selected_status(status_box); | |
688 | |
689 g_source_remove(status_box->typing); | |
690 status_box->typing = 0; | |
691 gtk_gaim_status_box_refresh(status_box); | |
10643 | 692 } |
693 | |
694 static void gtk_gaim_status_box_changed(GtkComboBox *box) | |
695 { | |
11400 | 696 GtkGaimStatusBox *status_box; |
10643 | 697 GtkTreeIter iter; |
11739 | 698 GtkGaimStatusBoxItemType type; |
10643 | 699 char *text, *sec_text; |
700 GdkPixbuf *pixbuf; | |
11755 | 701 GList *accounts, *node; |
10643 | 702 |
11400 | 703 status_box = GTK_GAIM_STATUS_BOX(box); |
704 | |
10643 | 705 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(status_box), &iter); |
11739 | 706 gtk_tree_model_get(GTK_TREE_MODEL(status_box->dropdown_store), &iter, |
707 TYPE_COLUMN, &type, | |
708 TITLE_COLUMN, &text, | |
10861 | 709 DESC_COLUMN, &sec_text, ICON_COLUMN, &pixbuf, |
11739 | 710 -1); |
10643 | 711 if (status_box->title) |
712 g_free(status_box->title); | |
11638 | 713 status_box->title = text; |
10643 | 714 if (status_box->desc && sec_text) |
11638 | 715 g_free(status_box->desc); |
716 status_box->desc = sec_text; | |
10643 | 717 if (status_box->pixbuf) |
718 g_object_unref(status_box->pixbuf); | |
719 status_box->pixbuf = pixbuf; | |
11638 | 720 if (status_box->typing) |
721 g_source_remove(status_box->typing); | |
722 status_box->typing = 0; | |
10861 | 723 |
11739 | 724 if (type == GTK_GAIM_STATUS_BOX_TYPE_CUSTOM) |
11729 | 725 { |
726 gaim_gtk_status_editor_show(NULL); | |
727 return; | |
728 } | |
729 | |
11739 | 730 if (type == GTK_GAIM_STATUS_BOX_TYPE_SAVED) |
11729 | 731 { |
732 gaim_gtk_status_window_show(); | |
733 return; | |
734 } | |
735 | |
11654 | 736 /* |
11755 | 737 * Show the message box whenever 'type' allows for a |
738 * message attribute on any protocol that is enabled. | |
11654 | 739 */ |
11755 | 740 accounts = gaim_accounts_get_all_active(); |
741 status_box->imhtml_visible = FALSE; | |
742 for (node = accounts; node != NULL; node = node->next) | |
743 { | |
744 GaimAccount *account; | |
745 GaimStatusType *status_type; | |
746 | |
747 account = node->data; | |
748 status_type = gaim_account_get_status_type_with_primitive(account, type); | |
749 if ((status_type != NULL) && | |
750 (gaim_status_type_get_attr(status_type, "message") != NULL)) | |
751 { | |
752 status_box->imhtml_visible = TRUE; | |
753 break; | |
754 } | |
755 } | |
756 g_list_free(accounts); | |
11654 | 757 |
758 if (status_box->imhtml_visible) | |
759 { | |
10643 | 760 gtk_widget_show_all(status_box->vbox); |
761 status_box->typing = g_timeout_add(3000, (GSourceFunc)remove_typing_cb, status_box); | |
762 gtk_imhtml_clear(GTK_IMHTML(status_box->imhtml)); | |
763 gtk_widget_grab_focus(status_box->imhtml); | |
11654 | 764 } |
765 else | |
766 { | |
10643 | 767 gtk_widget_hide_all(status_box->vbox); |
11654 | 768 activate_currently_selected_status(status_box); |
10643 | 769 } |
770 gtk_gaim_status_box_refresh(status_box); | |
771 } | |
772 | |
773 static void imhtml_changed_cb(GtkTextBuffer *buffer, void *data) | |
774 { | |
775 GtkGaimStatusBox *box = (GtkGaimStatusBox*)data; | |
776 if (box->typing) { | |
777 gtk_gaim_status_box_pulse_typing(box); | |
778 g_source_remove(box->typing); | |
10861 | 779 } |
10643 | 780 box->typing = g_timeout_add(3000, (GSourceFunc)remove_typing_cb, box); |
781 gtk_gaim_status_box_refresh(box); | |
782 } | |
10649 | 783 |
11739 | 784 GtkGaimStatusBoxItemType gtk_gaim_status_box_get_active_type(GtkGaimStatusBox *status_box) |
10649 | 785 { |
786 GtkTreeIter iter; | |
11739 | 787 GtkGaimStatusBoxItemType type; |
10649 | 788 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(status_box), &iter); |
10861 | 789 gtk_tree_model_get(GTK_TREE_MODEL(status_box->dropdown_store), &iter, |
10649 | 790 TYPE_COLUMN, &type, -1); |
791 return type; | |
792 } | |
793 | |
11638 | 794 char *gtk_gaim_status_box_get_message(GtkGaimStatusBox *status_box) |
10649 | 795 { |
796 if (status_box->imhtml_visible) | |
797 return gtk_imhtml_get_markup(GTK_IMHTML(status_box->imhtml)); | |
798 else | |
799 return NULL; | |
800 } |