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