| 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 |
|
| 26 /* |
|
| 27 * The status box is made up of two main pieces: |
|
| 28 * - The box that displays the current status, which is made |
|
| 29 * of a GtkListStore ("status_box->store") and GtkCellView |
|
| 30 * ("status_box->cell_view"). There is always exactly 1 row |
|
| 31 * in this list store. Only the TYPE_ICON and TYPE_TEXT |
|
| 32 * columns are used in this list store. |
|
| 33 * - The dropdown menu that lets users select a status, which |
|
| 34 * is made of a GtkComboBox ("status_box") and GtkListStore |
|
| 35 * ("status_box->dropdown_store"). This dropdown is shown |
|
| 36 * when the user clicks on the box that displays the current |
|
| 37 * status. This list store contains one row for Available, |
|
| 38 * one row for Away, etc., a few rows for popular statuses, |
|
| 39 * and the "New..." and "Saved..." options. |
|
| 40 */ |
|
| 41 |
|
| 42 #include <gdk/gdkkeysyms.h> |
|
| 43 |
|
| 44 #include "account.h" |
|
| 45 #include "internal.h" |
|
| 46 #include "savedstatuses.h" |
|
| 47 #include "status.h" |
|
| 48 #include "debug.h" |
|
| 49 |
|
| 50 #include "gtkgaim.h" |
|
| 51 #include "gtksavedstatuses.h" |
|
| 52 #include "gtkstock.h" |
|
| 53 #include "gtkstatusbox.h" |
|
| 54 #include "gtkutils.h" |
|
| 55 |
|
| 56 #ifdef USE_GTKSPELL |
|
| 57 # include <gtkspell/gtkspell.h> |
|
| 58 # ifdef _WIN32 |
|
| 59 # include "wspell.h" |
|
| 60 # endif |
|
| 61 #endif |
|
| 62 |
|
| 63 #define TYPING_TIMEOUT 4000 |
|
| 64 |
|
| 65 static void imhtml_changed_cb(GtkTextBuffer *buffer, void *data); |
|
| 66 static void imhtml_format_changed_cb(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons, void *data); |
|
| 67 static void remove_typing_cb(GtkGaimStatusBox *box); |
|
| 68 static void update_size (GtkGaimStatusBox *box); |
|
| 69 static gint get_statusbox_index(GtkGaimStatusBox *box, GaimSavedStatus *saved_status); |
|
| 70 |
|
| 71 static void gtk_gaim_status_box_pulse_typing(GtkGaimStatusBox *status_box); |
|
| 72 static void gtk_gaim_status_box_refresh(GtkGaimStatusBox *status_box); |
|
| 73 static void gtk_gaim_status_box_regenerate(GtkGaimStatusBox *status_box); |
|
| 74 static void gtk_gaim_status_box_changed(GtkComboBox *box); |
|
| 75 static void gtk_gaim_status_box_size_request (GtkWidget *widget, GtkRequisition *requisition); |
|
| 76 static void gtk_gaim_status_box_size_allocate (GtkWidget *widget, GtkAllocation *allocation); |
|
| 77 static gboolean gtk_gaim_status_box_expose_event (GtkWidget *widget, GdkEventExpose *event); |
|
| 78 static void gtk_gaim_status_box_forall (GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data); |
|
| 79 |
|
| 80 static void do_colorshift (GdkPixbuf *dest, GdkPixbuf *src, int shift); |
|
| 81 static void icon_choose_cb(const char *filename, gpointer data); |
|
| 82 |
|
| 83 static void (*combo_box_size_request)(GtkWidget *widget, GtkRequisition *requisition); |
|
| 84 static void (*combo_box_size_allocate)(GtkWidget *widget, GtkAllocation *allocation); |
|
| 85 static void (*combo_box_forall) (GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data); |
|
| 86 |
|
| 87 enum { |
|
| 88 /** A GtkGaimStatusBoxItemType */ |
|
| 89 TYPE_COLUMN, |
|
| 90 |
|
| 91 /** |
|
| 92 * This is a GdkPixbuf (the other columns are strings). |
|
| 93 * This column is visible. |
|
| 94 */ |
|
| 95 ICON_COLUMN, |
|
| 96 |
|
| 97 /** The text displayed on the status box. This column is visible. */ |
|
| 98 TEXT_COLUMN, |
|
| 99 |
|
| 100 /** The plain-English title of this item */ |
|
| 101 TITLE_COLUMN, |
|
| 102 |
|
| 103 /** A plain-English description of this item */ |
|
| 104 DESC_COLUMN, |
|
| 105 |
|
| 106 /* |
|
| 107 * This value depends on TYPE_COLUMN. For POPULAR types, |
|
| 108 * this is the creation time. For PRIMITIVE types, |
|
| 109 * this is the GaimStatusPrimitive. |
|
| 110 */ |
|
| 111 DATA_COLUMN, |
|
| 112 |
|
| 113 NUM_COLUMNS |
|
| 114 }; |
|
| 115 |
|
| 116 enum { |
|
| 117 PROP_0, |
|
| 118 PROP_ACCOUNT, |
|
| 119 PROP_ICON_SEL, |
|
| 120 }; |
|
| 121 |
|
| 122 GtkComboBoxClass *parent_class = NULL; |
|
| 123 |
|
| 124 static void gtk_gaim_status_box_class_init (GtkGaimStatusBoxClass *klass); |
|
| 125 static void gtk_gaim_status_box_init (GtkGaimStatusBox *status_box); |
|
| 126 |
|
| 127 GType |
|
| 128 gtk_gaim_status_box_get_type (void) |
|
| 129 { |
|
| 130 static GType status_box_type = 0; |
|
| 131 |
|
| 132 if (!status_box_type) |
|
| 133 { |
|
| 134 static const GTypeInfo status_box_info = |
|
| 135 { |
|
| 136 sizeof (GtkGaimStatusBoxClass), |
|
| 137 NULL, /* base_init */ |
|
| 138 NULL, /* base_finalize */ |
|
| 139 (GClassInitFunc) gtk_gaim_status_box_class_init, |
|
| 140 NULL, /* class_finalize */ |
|
| 141 NULL, /* class_data */ |
|
| 142 sizeof (GtkGaimStatusBox), |
|
| 143 0, |
|
| 144 (GInstanceInitFunc) gtk_gaim_status_box_init, |
|
| 145 NULL /* value_table */ |
|
| 146 }; |
|
| 147 |
|
| 148 status_box_type = g_type_register_static(GTK_TYPE_COMBO_BOX, |
|
| 149 "GtkGaimStatusBox", |
|
| 150 &status_box_info, |
|
| 151 0); |
|
| 152 } |
|
| 153 |
|
| 154 return status_box_type; |
|
| 155 } |
|
| 156 |
|
| 157 static void |
|
| 158 gtk_gaim_status_box_get_property(GObject *object, guint param_id, |
|
| 159 GValue *value, GParamSpec *psec) |
|
| 160 { |
|
| 161 GtkGaimStatusBox *statusbox = GTK_GAIM_STATUS_BOX(object); |
|
| 162 |
|
| 163 switch (param_id) { |
|
| 164 case PROP_ACCOUNT: |
|
| 165 g_value_set_pointer(value, statusbox->account); |
|
| 166 break; |
|
| 167 case PROP_ICON_SEL: |
|
| 168 g_value_set_boolean(value, statusbox->icon_box != NULL); |
|
| 169 break; |
|
| 170 default: |
|
| 171 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, psec); |
|
| 172 break; |
|
| 173 } |
|
| 174 } |
|
| 175 |
|
| 176 static void |
|
| 177 update_to_reflect_account_status(GtkGaimStatusBox *status_box, GaimAccount *account, GaimStatus *newstatus) |
|
| 178 { |
|
| 179 const GList *l; |
|
| 180 int status_no = -1; |
|
| 181 const GaimStatusType *statustype = NULL; |
|
| 182 const char *message; |
|
| 183 |
|
| 184 statustype = gaim_status_type_find_with_id((GList *)gaim_account_get_status_types(account), |
|
| 185 (char *)gaim_status_type_get_id(gaim_status_get_type(newstatus))); |
|
| 186 |
|
| 187 for (l = gaim_account_get_status_types(account); l != NULL; l = l->next) { |
|
| 188 GaimStatusType *status_type = (GaimStatusType *)l->data; |
|
| 189 |
|
| 190 if (!gaim_status_type_is_user_settable(status_type)) |
|
| 191 continue; |
|
| 192 status_no++; |
|
| 193 if (statustype == status_type) |
|
| 194 break; |
|
| 195 } |
|
| 196 |
|
| 197 if (status_no != -1) { |
|
| 198 gtk_widget_set_sensitive(GTK_WIDGET(status_box), FALSE); |
|
| 199 gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), status_no); |
|
| 200 |
|
| 201 message = gaim_status_get_attr_string(newstatus, "message"); |
|
| 202 |
|
| 203 if (!message || !*message) |
|
| 204 { |
|
| 205 gtk_widget_hide_all(status_box->vbox); |
|
| 206 status_box->imhtml_visible = FALSE; |
|
| 207 } |
|
| 208 else |
|
| 209 { |
|
| 210 gtk_widget_show_all(status_box->vbox); |
|
| 211 status_box->imhtml_visible = TRUE; |
|
| 212 gtk_imhtml_clear(GTK_IMHTML(status_box->imhtml)); |
|
| 213 gtk_imhtml_clear_formatting(GTK_IMHTML(status_box->imhtml)); |
|
| 214 gtk_imhtml_append_text(GTK_IMHTML(status_box->imhtml), message, 0); |
|
| 215 } |
|
| 216 gtk_widget_set_sensitive(GTK_WIDGET(status_box), TRUE); |
|
| 217 gtk_gaim_status_box_refresh(status_box); |
|
| 218 } |
|
| 219 } |
|
| 220 |
|
| 221 static void |
|
| 222 account_status_changed_cb(GaimAccount *account, GaimStatus *oldstatus, GaimStatus *newstatus, GtkGaimStatusBox *status_box) |
|
| 223 { |
|
| 224 if (status_box->account == account) |
|
| 225 update_to_reflect_account_status(status_box, account, newstatus); |
|
| 226 } |
|
| 227 |
|
| 228 static gboolean |
|
| 229 icon_box_press_cb(GtkWidget *widget, GdkEventButton *event, GtkGaimStatusBox *box) |
|
| 230 { |
|
| 231 if (box->buddy_icon_sel) { |
|
| 232 gtk_window_present(GTK_WINDOW(box->buddy_icon_sel)); |
|
| 233 return FALSE; |
|
| 234 } |
|
| 235 |
|
| 236 box->buddy_icon_sel = gaim_gtk_buddy_icon_chooser_new(NULL, icon_choose_cb, box); |
|
| 237 gtk_widget_show_all(box->buddy_icon_sel); |
|
| 238 return FALSE; |
|
| 239 } |
|
| 240 |
|
| 241 static gboolean |
|
| 242 icon_box_enter_cb(GtkWidget *widget, GdkEventCrossing *event, GtkGaimStatusBox *box) |
|
| 243 { |
|
| 244 gdk_window_set_cursor(widget->window, box->hand_cursor); |
|
| 245 gtk_image_set_from_pixbuf(GTK_IMAGE(box->icon), box->buddy_icon_hover); |
|
| 246 return FALSE; |
|
| 247 } |
|
| 248 |
|
| 249 static gboolean |
|
| 250 icon_box_leave_cb(GtkWidget *widget, GdkEventCrossing *event, GtkGaimStatusBox *box) |
|
| 251 { |
|
| 252 gdk_window_set_cursor(widget->window, box->arrow_cursor); |
|
| 253 gtk_image_set_from_pixbuf(GTK_IMAGE(box->icon), box->buddy_icon) ; |
|
| 254 return FALSE; |
|
| 255 } |
|
| 256 |
|
| 257 static void |
|
| 258 setup_icon_box(GtkGaimStatusBox *status_box) |
|
| 259 { |
|
| 260 if (status_box->icon_box != NULL) |
|
| 261 return; |
|
| 262 |
|
| 263 if (status_box->account && |
|
| 264 !gaim_account_get_ui_bool(status_box->account, GAIM_GTK_UI, "use-global-buddyicon", TRUE)) |
|
| 265 { |
|
| 266 char *string = gaim_buddy_icons_get_full_path(gaim_account_get_buddy_icon(status_box->account)); |
|
| 267 gtk_gaim_status_box_set_buddy_icon(status_box, string); |
|
| 268 g_free(string); |
|
| 269 } |
|
| 270 else |
|
| 271 { |
|
| 272 gtk_gaim_status_box_set_buddy_icon(status_box, gaim_prefs_get_string("/gaim/gtk/accounts/buddyicon")); |
|
| 273 } |
|
| 274 status_box->icon = gtk_image_new_from_pixbuf(status_box->buddy_icon); |
|
| 275 status_box->icon_box = gtk_event_box_new(); |
|
| 276 status_box->hand_cursor = gdk_cursor_new (GDK_HAND2); |
|
| 277 status_box->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); |
|
| 278 |
|
| 279 g_signal_connect(G_OBJECT(status_box->icon_box), "enter-notify-event", G_CALLBACK(icon_box_enter_cb), status_box); |
|
| 280 g_signal_connect(G_OBJECT(status_box->icon_box), "leave-notify-event", G_CALLBACK(icon_box_leave_cb), status_box); |
|
| 281 g_signal_connect(G_OBJECT(status_box->icon_box), "button-press-event", G_CALLBACK(icon_box_press_cb), status_box); |
|
| 282 |
|
| 283 gtk_container_add(GTK_CONTAINER(status_box->icon_box), status_box->icon); |
|
| 284 |
|
| 285 gtk_widget_show_all(status_box->icon_box); |
|
| 286 gtk_widget_set_parent(status_box->icon_box, GTK_WIDGET(status_box)); |
|
| 287 } |
|
| 288 |
|
| 289 static void |
|
| 290 destroy_icon_box(GtkGaimStatusBox *statusbox) |
|
| 291 { |
|
| 292 if (statusbox->icon_box == NULL) |
|
| 293 return; |
|
| 294 |
|
| 295 gtk_widget_destroy(statusbox->icon_box); |
|
| 296 gdk_cursor_unref(statusbox->hand_cursor); |
|
| 297 gdk_cursor_unref(statusbox->arrow_cursor); |
|
| 298 |
|
| 299 g_object_unref(G_OBJECT(statusbox->buddy_icon)); |
|
| 300 g_object_unref(G_OBJECT(statusbox->buddy_icon_hover)); |
|
| 301 |
|
| 302 if (statusbox->buddy_icon_sel) |
|
| 303 gtk_widget_destroy(statusbox->buddy_icon_sel); |
|
| 304 |
|
| 305 g_free(statusbox->buddy_icon_path); |
|
| 306 |
|
| 307 statusbox->icon_box = NULL; |
|
| 308 statusbox->buddy_icon_path = NULL; |
|
| 309 statusbox->buddy_icon = NULL; |
|
| 310 statusbox->buddy_icon_hover = NULL; |
|
| 311 statusbox->hand_cursor = NULL; |
|
| 312 statusbox->arrow_cursor = NULL; |
|
| 313 } |
|
| 314 |
|
| 315 static void |
|
| 316 gtk_gaim_status_box_set_property(GObject *object, guint param_id, |
|
| 317 const GValue *value, GParamSpec *pspec) |
|
| 318 { |
|
| 319 GtkGaimStatusBox *statusbox = GTK_GAIM_STATUS_BOX(object); |
|
| 320 |
|
| 321 switch (param_id) { |
|
| 322 case PROP_ICON_SEL: |
|
| 323 if (g_value_get_boolean(value)) { |
|
| 324 if (statusbox->account) { |
|
| 325 GaimPlugin *plug = gaim_plugins_find_with_id(gaim_account_get_protocol_id(statusbox->account)); |
|
| 326 if (plug) { |
|
| 327 GaimPluginProtocolInfo *prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plug); |
|
| 328 if (prplinfo && prplinfo->icon_spec.format != NULL) |
|
| 329 setup_icon_box(statusbox); |
|
| 330 } |
|
| 331 } else { |
|
| 332 setup_icon_box(statusbox); |
|
| 333 } |
|
| 334 } else { |
|
| 335 destroy_icon_box(statusbox); |
|
| 336 } |
|
| 337 break; |
|
| 338 case PROP_ACCOUNT: |
|
| 339 statusbox->account = g_value_get_pointer(value); |
|
| 340 |
|
| 341 if (statusbox->status_changed_signal) { |
|
| 342 gaim_signal_disconnect(gaim_accounts_get_handle(), "account-status-changed", |
|
| 343 statusbox, GAIM_CALLBACK(account_status_changed_cb)); |
|
| 344 statusbox->status_changed_signal = 0; |
|
| 345 } |
|
| 346 |
|
| 347 if (statusbox->account) { |
|
| 348 statusbox->status_changed_signal = gaim_signal_connect(gaim_accounts_get_handle(), "account-status-changed", |
|
| 349 statusbox, GAIM_CALLBACK(account_status_changed_cb), |
|
| 350 statusbox); |
|
| 351 } |
|
| 352 gtk_gaim_status_box_regenerate(statusbox); |
|
| 353 |
|
| 354 break; |
|
| 355 default: |
|
| 356 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); |
|
| 357 break; |
|
| 358 } |
|
| 359 } |
|
| 360 |
|
| 361 static void |
|
| 362 gtk_gaim_status_box_finalize(GObject *obj) |
|
| 363 { |
|
| 364 GtkGaimStatusBox *statusbox = GTK_GAIM_STATUS_BOX(obj); |
|
| 365 |
|
| 366 if (statusbox->status_changed_signal) { |
|
| 367 gaim_signal_disconnect(gaim_accounts_get_handle(), "account-status-changed", |
|
| 368 statusbox, GAIM_CALLBACK(account_status_changed_cb)); |
|
| 369 statusbox->status_changed_signal = 0; |
|
| 370 } |
|
| 371 gaim_signals_disconnect_by_handle(statusbox); |
|
| 372 gaim_prefs_disconnect_by_handle(statusbox); |
|
| 373 |
|
| 374 gdk_cursor_unref(statusbox->hand_cursor); |
|
| 375 gdk_cursor_unref(statusbox->arrow_cursor); |
|
| 376 |
|
| 377 g_object_unref(G_OBJECT(statusbox->buddy_icon)); |
|
| 378 g_object_unref(G_OBJECT(statusbox->buddy_icon_hover)); |
|
| 379 |
|
| 380 if (statusbox->buddy_icon_sel) |
|
| 381 gtk_widget_destroy(statusbox->buddy_icon_sel); |
|
| 382 |
|
| 383 g_free(statusbox->buddy_icon_path); |
|
| 384 |
|
| 385 G_OBJECT_CLASS(parent_class)->finalize(obj); |
|
| 386 } |
|
| 387 |
|
| 388 static void |
|
| 389 gtk_gaim_status_box_class_init (GtkGaimStatusBoxClass *klass) |
|
| 390 { |
|
| 391 GObjectClass *object_class; |
|
| 392 GtkComboBoxClass *combo_class; |
|
| 393 GtkWidgetClass *widget_class; |
|
| 394 GtkContainerClass *container_class = (GtkContainerClass*)klass; |
|
| 395 |
|
| 396 parent_class = g_type_class_peek_parent(klass); |
|
| 397 |
|
| 398 combo_class = (GtkComboBoxClass*)klass; |
|
| 399 combo_class->changed = gtk_gaim_status_box_changed; |
|
| 400 |
|
| 401 widget_class = (GtkWidgetClass*)klass; |
|
| 402 combo_box_size_request = widget_class->size_request; |
|
| 403 widget_class->size_request = gtk_gaim_status_box_size_request; |
|
| 404 combo_box_size_allocate = widget_class->size_allocate; |
|
| 405 widget_class->size_allocate = gtk_gaim_status_box_size_allocate; |
|
| 406 widget_class->expose_event = gtk_gaim_status_box_expose_event; |
|
| 407 |
|
| 408 combo_box_forall = container_class->forall; |
|
| 409 container_class->forall = gtk_gaim_status_box_forall; |
|
| 410 container_class->remove = NULL; |
|
| 411 |
|
| 412 object_class = (GObjectClass *)klass; |
|
| 413 |
|
| 414 object_class->finalize = gtk_gaim_status_box_finalize; |
|
| 415 |
|
| 416 object_class->get_property = gtk_gaim_status_box_get_property; |
|
| 417 object_class->set_property = gtk_gaim_status_box_set_property; |
|
| 418 |
|
| 419 g_object_class_install_property(object_class, |
|
| 420 PROP_ACCOUNT, |
|
| 421 g_param_spec_pointer("account", |
|
| 422 "Account", |
|
| 423 "The account, or NULL for all accounts", |
|
| 424 G_PARAM_READWRITE |
|
| 425 ) |
|
| 426 ); |
|
| 427 g_object_class_install_property(object_class, |
|
| 428 PROP_ICON_SEL, |
|
| 429 g_param_spec_boolean("iconsel", |
|
| 430 "Icon Selector", |
|
| 431 "Whether the icon selector should be displayed or not.", |
|
| 432 FALSE, |
|
| 433 G_PARAM_READWRITE |
|
| 434 ) |
|
| 435 ); |
|
| 436 } |
|
| 437 |
|
| 438 /** |
|
| 439 * This updates the text displayed on the status box so that it shows |
|
| 440 * the current status. This is the only function in this file that |
|
| 441 * should modify status_box->store |
|
| 442 */ |
|
| 443 static void |
|
| 444 gtk_gaim_status_box_refresh(GtkGaimStatusBox *status_box) |
|
| 445 { |
|
| 446 gboolean show_buddy_icons; |
|
| 447 GtkIconSize icon_size; |
|
| 448 GtkStyle *style; |
|
| 449 char aa_color[8]; |
|
| 450 GaimSavedStatus *saved_status; |
|
| 451 char *primary, *secondary, *text; |
|
| 452 GdkPixbuf *pixbuf; |
|
| 453 GtkTreePath *path; |
|
| 454 |
|
| 455 show_buddy_icons = gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons"); |
|
| 456 if (show_buddy_icons) |
|
| 457 icon_size = gtk_icon_size_from_name(GAIM_ICON_SIZE_STATUS); |
|
| 458 else |
|
| 459 icon_size = gtk_icon_size_from_name(GAIM_ICON_SIZE_STATUS_SMALL); |
|
| 460 |
|
| 461 style = gtk_widget_get_style(GTK_WIDGET(status_box)); |
|
| 462 snprintf(aa_color, sizeof(aa_color), "#%02x%02x%02x", |
|
| 463 style->text_aa[GTK_STATE_NORMAL].red >> 8, |
|
| 464 style->text_aa[GTK_STATE_NORMAL].green >> 8, |
|
| 465 style->text_aa[GTK_STATE_NORMAL].blue >> 8); |
|
| 466 |
|
| 467 saved_status = gaim_savedstatus_get_current(); |
|
| 468 |
|
| 469 /* Primary */ |
|
| 470 if (status_box->typing != 0) |
|
| 471 { |
|
| 472 GtkTreeIter iter; |
|
| 473 GtkGaimStatusBoxItemType type; |
|
| 474 gpointer data; |
|
| 475 |
|
| 476 /* Primary (get the status selected in the dropdown) */ |
|
| 477 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(status_box), &iter); |
|
| 478 gtk_tree_model_get(GTK_TREE_MODEL(status_box->dropdown_store), &iter, |
|
| 479 TYPE_COLUMN, &type, |
|
| 480 DATA_COLUMN, &data, |
|
| 481 -1); |
|
| 482 if (type == GTK_GAIM_STATUS_BOX_TYPE_PRIMITIVE) |
|
| 483 primary = g_strdup(gaim_primitive_get_name_from_type(GPOINTER_TO_INT(data))); |
|
| 484 else |
|
| 485 /* This should never happen, but just in case... */ |
|
| 486 primary = g_strdup("New status"); |
|
| 487 } |
|
| 488 else if (status_box->account != NULL) |
|
| 489 { |
|
| 490 primary = g_strdup(gaim_status_get_name(gaim_account_get_active_status(status_box->account))); |
|
| 491 } |
|
| 492 else if (gaim_savedstatus_is_transient(saved_status)) |
|
| 493 primary = g_strdup(gaim_primitive_get_name_from_type(gaim_savedstatus_get_type(saved_status))); |
|
| 494 else |
|
| 495 primary = g_markup_escape_text(gaim_savedstatus_get_title(saved_status), -1); |
|
| 496 |
|
| 497 /* Secondary */ |
|
| 498 if (status_box->typing != 0) |
|
| 499 secondary = g_strdup(_("Typing")); |
|
| 500 else if (status_box->connecting) |
|
| 501 secondary = g_strdup(_("Connecting")); |
|
| 502 else if (gaim_savedstatus_is_transient(saved_status)) |
|
| 503 secondary = NULL; |
|
| 504 else |
|
| 505 { |
|
| 506 const char *message; |
|
| 507 char *tmp; |
|
| 508 message = gaim_savedstatus_get_message(saved_status); |
|
| 509 if (message != NULL) |
|
| 510 { |
|
| 511 tmp = gaim_markup_strip_html(message); |
|
| 512 gaim_util_chrreplace(tmp, '\n', ' '); |
|
| 513 secondary = g_markup_escape_text(tmp, -1); |
|
| 514 g_free(tmp); |
|
| 515 } |
|
| 516 else |
|
| 517 secondary = NULL; |
|
| 518 } |
|
| 519 |
|
| 520 /* Pixbuf */ |
|
| 521 if (status_box->typing != 0) |
|
| 522 pixbuf = status_box->typing_pixbufs[status_box->typing_index]; |
|
| 523 else if (status_box->connecting) |
|
| 524 pixbuf = status_box->connecting_pixbufs[status_box->connecting_index]; |
|
| 525 else |
|
| 526 { |
|
| 527 if (status_box->account != NULL) |
|
| 528 pixbuf = gaim_gtk_create_prpl_icon_with_status(status_box->account, |
|
| 529 gaim_status_get_type(gaim_account_get_active_status(status_box->account)), |
|
| 530 show_buddy_icons ? 1.0 : 0.5); |
|
| 531 else |
|
| 532 pixbuf = gaim_gtk_create_gaim_icon_with_status( |
|
| 533 gaim_savedstatus_get_type(saved_status), |
|
| 534 show_buddy_icons ? 1.0 : 0.5); |
|
| 535 |
|
| 536 if (!gaim_savedstatus_is_transient(saved_status)) |
|
| 537 { |
|
| 538 GdkPixbuf *emblem; |
|
| 539 |
|
| 540 /* Overlay a disk in the bottom left corner */ |
|
| 541 emblem = gtk_widget_render_icon(GTK_WIDGET(status_box->vbox), |
|
| 542 GTK_STOCK_SAVE, icon_size, "GtkGaimStatusBox"); |
|
| 543 if (emblem != NULL) |
|
| 544 { |
|
| 545 int width, height; |
|
| 546 width = gdk_pixbuf_get_width(pixbuf) / 2; |
|
| 547 height = gdk_pixbuf_get_height(pixbuf) / 2; |
|
| 548 gdk_pixbuf_composite(emblem, pixbuf, 0, height, |
|
| 549 width, height, 0, height, |
|
| 550 0.5, 0.5, GDK_INTERP_BILINEAR, 255); |
|
| 551 g_object_unref(G_OBJECT(emblem)); |
|
| 552 } |
|
| 553 } |
|
| 554 } |
|
| 555 |
|
| 556 if (status_box->account != NULL) { |
|
| 557 text = g_strdup_printf("%s%s<span size=\"smaller\" color=\"%s\">%s</span>", |
|
| 558 gaim_account_get_username(status_box->account), |
|
| 559 show_buddy_icons ? "\n" : " - ", aa_color, |
|
| 560 secondary ? secondary : primary); |
|
| 561 } else if (secondary != NULL) { |
|
| 562 char *separator; |
|
| 563 separator = show_buddy_icons ? "\n" : " - "; |
|
| 564 text = g_strdup_printf("%s<span size=\"smaller\" color=\"%s\">%s%s</span>", |
|
| 565 primary, aa_color, separator, secondary); |
|
| 566 } else { |
|
| 567 text = g_strdup(primary); |
|
| 568 } |
|
| 569 g_free(primary); |
|
| 570 g_free(secondary); |
|
| 571 |
|
| 572 /* |
|
| 573 * Only two columns are used in this list store (does it |
|
| 574 * really need to be a list store?) |
|
| 575 */ |
|
| 576 gtk_list_store_set(status_box->store, &(status_box->iter), |
|
| 577 ICON_COLUMN, pixbuf, |
|
| 578 TEXT_COLUMN, text, |
|
| 579 -1); |
|
| 580 if ((status_box->typing == 0) && (!status_box->connecting)) |
|
| 581 g_object_unref(pixbuf); |
|
| 582 g_free(text); |
|
| 583 |
|
| 584 /* Make sure to activate the only row in the tree view */ |
|
| 585 path = gtk_tree_path_new_from_string("0"); |
|
| 586 gtk_cell_view_set_displayed_row(GTK_CELL_VIEW(status_box->cell_view), path); |
|
| 587 gtk_tree_path_free(path); |
|
| 588 |
|
| 589 update_size(status_box); |
|
| 590 } |
|
| 591 |
|
| 592 /** |
|
| 593 * This updates the GtkTreeView so that it correctly shows the state |
|
| 594 * we are currently using. It is used when the current state is |
|
| 595 * updated from somewhere other than the GtkStatusBox (from a plugin, |
|
| 596 * or when signing on with the "-n" option, for example). It is |
|
| 597 * also used when the user selects the "New..." option. |
|
| 598 * |
|
| 599 * Maybe we could accomplish this by triggering off the mouse and |
|
| 600 * keyboard signals instead of the changed signal? |
|
| 601 */ |
|
| 602 static void |
|
| 603 status_menu_refresh_iter(GtkGaimStatusBox *status_box) |
|
| 604 { |
|
| 605 GaimSavedStatus *saved_status; |
|
| 606 GaimStatusPrimitive primitive; |
|
| 607 gint index; |
|
| 608 const char *message; |
|
| 609 |
|
| 610 /* this function is inappropriate for ones with accounts */ |
|
| 611 if (status_box->account) |
|
| 612 return; |
|
| 613 |
|
| 614 saved_status = gaim_savedstatus_get_current(); |
|
| 615 |
|
| 616 /* |
|
| 617 * Suppress the "changed" signal because the status |
|
| 618 * was changed programmatically. |
|
| 619 */ |
|
| 620 gtk_widget_set_sensitive(GTK_WIDGET(status_box), FALSE); |
|
| 621 |
|
| 622 /* |
|
| 623 * If the saved_status is transient, is Available, Away, Invisible |
|
| 624 * or Offline, and it does not have an substatuses, then select |
|
| 625 * the primitive in the dropdown menu. Otherwise select the |
|
| 626 * popular status in the dropdown menu. |
|
| 627 */ |
|
| 628 primitive = gaim_savedstatus_get_type(saved_status); |
|
| 629 if (gaim_savedstatus_is_transient(saved_status) && |
|
| 630 ((primitive == GAIM_STATUS_AVAILABLE) || (primitive == GAIM_STATUS_AWAY) || |
|
| 631 (primitive == GAIM_STATUS_INVISIBLE) || (primitive == GAIM_STATUS_OFFLINE)) && |
|
| 632 (!gaim_savedstatus_has_substatuses(saved_status))) |
|
| 633 { |
|
| 634 index = get_statusbox_index(status_box, saved_status); |
|
| 635 gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), index); |
|
| 636 } |
|
| 637 else |
|
| 638 { |
|
| 639 GtkTreeIter iter; |
|
| 640 GtkGaimStatusBoxItemType type; |
|
| 641 gpointer data; |
|
| 642 |
|
| 643 /* Unset the active item */ |
|
| 644 gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), -1); |
|
| 645 |
|
| 646 /* If this saved status is in the list store, then set it as the active item */ |
|
| 647 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(status_box->dropdown_store), &iter)) |
|
| 648 { |
|
| 649 do |
|
| 650 { |
|
| 651 gtk_tree_model_get(GTK_TREE_MODEL(status_box->dropdown_store), &iter, |
|
| 652 TYPE_COLUMN, &type, |
|
| 653 DATA_COLUMN, &data, |
|
| 654 -1); |
|
| 655 if ((type == GTK_GAIM_STATUS_BOX_TYPE_POPULAR) && |
|
| 656 (GPOINTER_TO_INT(data) == gaim_savedstatus_get_creation_time(saved_status))) |
|
| 657 { |
|
| 658 /* Found! */ |
|
| 659 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(status_box), &iter); |
|
| 660 break; |
|
| 661 } |
|
| 662 } |
|
| 663 while (gtk_tree_model_iter_next(GTK_TREE_MODEL(status_box->dropdown_store), &iter)); |
|
| 664 } |
|
| 665 } |
|
| 666 |
|
| 667 message = gaim_savedstatus_get_message(saved_status); |
|
| 668 if (!gaim_savedstatus_is_transient(saved_status) || !message || !*message) |
|
| 669 { |
|
| 670 status_box->imhtml_visible = FALSE; |
|
| 671 gtk_widget_hide_all(status_box->vbox); |
|
| 672 } |
|
| 673 else |
|
| 674 { |
|
| 675 status_box->imhtml_visible = TRUE; |
|
| 676 gtk_widget_show_all(status_box->vbox); |
|
| 677 |
|
| 678 /* |
|
| 679 * Suppress the "changed" signal because the status |
|
| 680 * was changed programmatically. |
|
| 681 */ |
|
| 682 gtk_widget_set_sensitive(GTK_WIDGET(status_box->imhtml), FALSE); |
|
| 683 |
|
| 684 gtk_imhtml_clear(GTK_IMHTML(status_box->imhtml)); |
|
| 685 gtk_imhtml_clear_formatting(GTK_IMHTML(status_box->imhtml)); |
|
| 686 gtk_imhtml_append_text(GTK_IMHTML(status_box->imhtml), message, 0); |
|
| 687 gtk_widget_set_sensitive(GTK_WIDGET(status_box->imhtml), TRUE); |
|
| 688 } |
|
| 689 |
|
| 690 update_size(status_box); |
|
| 691 |
|
| 692 /* Stop suppressing the "changed" signal. */ |
|
| 693 gtk_widget_set_sensitive(GTK_WIDGET(status_box), TRUE); |
|
| 694 } |
|
| 695 |
|
| 696 static void |
|
| 697 add_popular_statuses(GtkGaimStatusBox *statusbox) |
|
| 698 { |
|
| 699 gboolean show_buddy_icons; |
|
| 700 GtkIconSize icon_size; |
|
| 701 GList *list, *cur; |
|
| 702 GdkPixbuf *pixbuf, *emblem; |
|
| 703 int width, height; |
|
| 704 |
|
| 705 list = gaim_savedstatuses_get_popular(6); |
|
| 706 if (list == NULL) |
|
| 707 /* Odd... oh well, nothing we can do about it. */ |
|
| 708 return; |
|
| 709 |
|
| 710 show_buddy_icons = gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons"); |
|
| 711 if (show_buddy_icons) |
|
| 712 icon_size = gtk_icon_size_from_name(GAIM_ICON_SIZE_STATUS); |
|
| 713 else |
|
| 714 icon_size = gtk_icon_size_from_name(GAIM_ICON_SIZE_STATUS_SMALL); |
|
| 715 |
|
| 716 gtk_gaim_status_box_add_separator(statusbox); |
|
| 717 |
|
| 718 for (cur = list; cur != NULL; cur = cur->next) |
|
| 719 { |
|
| 720 GaimSavedStatus *saved = cur->data; |
|
| 721 const gchar *message; |
|
| 722 gchar *stripped = NULL; |
|
| 723 |
|
| 724 /* Get an appropriate status icon */ |
|
| 725 pixbuf = gaim_gtk_create_gaim_icon_with_status( |
|
| 726 gaim_savedstatus_get_type(saved), |
|
| 727 show_buddy_icons ? 1.0 : 0.5); |
|
| 728 |
|
| 729 if (gaim_savedstatus_is_transient(saved)) |
|
| 730 { |
|
| 731 /* |
|
| 732 * Transient statuses do not have a title, so the savedstatus |
|
| 733 * API returns the message when gaim_savedstatus_get_title() is |
|
| 734 * called, so we don't need to get the message a second time. |
|
| 735 */ |
|
| 736 } |
|
| 737 else |
|
| 738 { |
|
| 739 message = gaim_savedstatus_get_message(saved); |
|
| 740 if (message != NULL) |
|
| 741 { |
|
| 742 stripped = gaim_markup_strip_html(message); |
|
| 743 gaim_util_chrreplace(stripped, '\n', ' '); |
|
| 744 } |
|
| 745 |
|
| 746 /* Overlay a disk in the bottom left corner */ |
|
| 747 emblem = gtk_widget_render_icon(GTK_WIDGET(statusbox->vbox), |
|
| 748 GTK_STOCK_SAVE, icon_size, "GtkGaimStatusBox"); |
|
| 749 if (emblem != NULL) |
|
| 750 { |
|
| 751 width = gdk_pixbuf_get_width(pixbuf) / 2; |
|
| 752 height = gdk_pixbuf_get_height(pixbuf) / 2; |
|
| 753 gdk_pixbuf_composite(emblem, pixbuf, 0, height, |
|
| 754 width, height, 0, height, |
|
| 755 0.5, 0.5, GDK_INTERP_BILINEAR, 255); |
|
| 756 g_object_unref(G_OBJECT(emblem)); |
|
| 757 } |
|
| 758 } |
|
| 759 |
|
| 760 gtk_gaim_status_box_add(statusbox, GTK_GAIM_STATUS_BOX_TYPE_POPULAR, |
|
| 761 pixbuf, gaim_savedstatus_get_title(saved), stripped, |
|
| 762 GINT_TO_POINTER(gaim_savedstatus_get_creation_time(saved))); |
|
| 763 g_free(stripped); |
|
| 764 if (pixbuf != NULL) |
|
| 765 g_object_unref(G_OBJECT(pixbuf)); |
|
| 766 } |
|
| 767 |
|
| 768 g_list_free(list); |
|
| 769 } |
|
| 770 |
|
| 771 static void |
|
| 772 gtk_gaim_status_box_regenerate(GtkGaimStatusBox *status_box) |
|
| 773 { |
|
| 774 gboolean show_buddy_icons; |
|
| 775 GaimAccount *account; |
|
| 776 GdkPixbuf *pixbuf, *pixbuf2, *pixbuf3, *pixbuf4, *tmp; |
|
| 777 GtkIconSize icon_size; |
|
| 778 |
|
| 779 show_buddy_icons = gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons"); |
|
| 780 if (show_buddy_icons) |
|
| 781 icon_size = gtk_icon_size_from_name(GAIM_ICON_SIZE_STATUS); |
|
| 782 else |
|
| 783 icon_size = gtk_icon_size_from_name(GAIM_ICON_SIZE_STATUS_SMALL); |
|
| 784 |
|
| 785 /* Unset the model while clearing it */ |
|
| 786 gtk_combo_box_set_model(GTK_COMBO_BOX(status_box), NULL); |
|
| 787 gtk_list_store_clear(status_box->dropdown_store); |
|
| 788 /* Don't set the model until the new statuses have been added to the box. |
|
| 789 * What is presumably a bug in Gtk < 2.4 causes things to get all confused |
|
| 790 * if we do this here. */ |
|
| 791 /* gtk_combo_box_set_model(GTK_COMBO_BOX(status_box), GTK_TREE_MODEL(status_box->dropdown_store)); */ |
|
| 792 |
|
| 793 account = GTK_GAIM_STATUS_BOX(status_box)->account; |
|
| 794 if (account == NULL) |
|
| 795 { |
|
| 796 /* Global */ |
|
| 797 pixbuf = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_ONLINE, |
|
| 798 icon_size, "GtkGaimStatusBox"); |
|
| 799 pixbuf2 = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_AWAY, |
|
| 800 icon_size, "GtkGaimStatusBox"); |
|
| 801 pixbuf3 = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_OFFLINE, |
|
| 802 icon_size, "GtkGaimStatusBox"); |
|
| 803 pixbuf4 = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_INVISIBLE, |
|
| 804 icon_size, "GtkGaimStatusBox"); |
|
| 805 |
|
| 806 gtk_gaim_status_box_add(GTK_GAIM_STATUS_BOX(status_box), GTK_GAIM_STATUS_BOX_TYPE_PRIMITIVE, pixbuf, _("Available"), NULL, GINT_TO_POINTER(GAIM_STATUS_AVAILABLE)); |
|
| 807 gtk_gaim_status_box_add(GTK_GAIM_STATUS_BOX(status_box), GTK_GAIM_STATUS_BOX_TYPE_PRIMITIVE, pixbuf2, _("Away"), NULL, GINT_TO_POINTER(GAIM_STATUS_AWAY)); |
|
| 808 gtk_gaim_status_box_add(GTK_GAIM_STATUS_BOX(status_box), GTK_GAIM_STATUS_BOX_TYPE_PRIMITIVE, pixbuf4, _("Invisible"), NULL, GINT_TO_POINTER(GAIM_STATUS_INVISIBLE)); |
|
| 809 gtk_gaim_status_box_add(GTK_GAIM_STATUS_BOX(status_box), GTK_GAIM_STATUS_BOX_TYPE_PRIMITIVE, pixbuf3, _("Offline"), NULL, GINT_TO_POINTER(GAIM_STATUS_OFFLINE)); |
|
| 810 |
|
| 811 add_popular_statuses(status_box); |
|
| 812 |
|
| 813 gtk_gaim_status_box_add_separator(GTK_GAIM_STATUS_BOX(status_box)); |
|
| 814 gtk_gaim_status_box_add(GTK_GAIM_STATUS_BOX(status_box), GTK_GAIM_STATUS_BOX_TYPE_CUSTOM, pixbuf, _("New..."), NULL, NULL); |
|
| 815 gtk_gaim_status_box_add(GTK_GAIM_STATUS_BOX(status_box), GTK_GAIM_STATUS_BOX_TYPE_SAVED, pixbuf, _("Saved..."), NULL, NULL); |
|
| 816 |
|
| 817 gtk_combo_box_set_model(GTK_COMBO_BOX(status_box), GTK_TREE_MODEL(status_box->dropdown_store)); |
|
| 818 status_menu_refresh_iter(status_box); |
|
| 819 |
|
| 820 } else { |
|
| 821 /* Per-account */ |
|
| 822 const GList *l; |
|
| 823 |
|
| 824 for (l = gaim_account_get_status_types(account); l != NULL; l = l->next) |
|
| 825 { |
|
| 826 GaimStatusType *status_type = (GaimStatusType *)l->data; |
|
| 827 |
|
| 828 if (!gaim_status_type_is_user_settable(status_type)) |
|
| 829 continue; |
|
| 830 |
|
| 831 tmp = gaim_gtk_create_prpl_icon_with_status(account, status_type, |
|
| 832 show_buddy_icons ? 1.0 : 0.5); |
|
| 833 gtk_gaim_status_box_add(GTK_GAIM_STATUS_BOX(status_box), |
|
| 834 GTK_GAIM_STATUS_BOX_TYPE_PRIMITIVE, tmp, |
|
| 835 gaim_status_type_get_name(status_type), |
|
| 836 NULL, |
|
| 837 GINT_TO_POINTER(gaim_status_type_get_primitive(status_type))); |
|
| 838 if (tmp != NULL) |
|
| 839 g_object_unref(tmp); |
|
| 840 } |
|
| 841 gtk_combo_box_set_model(GTK_COMBO_BOX(status_box), GTK_TREE_MODEL(status_box->dropdown_store)); |
|
| 842 update_to_reflect_account_status(status_box, account, gaim_account_get_active_status(account)); |
|
| 843 } |
|
| 844 } |
|
| 845 |
|
| 846 static gboolean combo_box_scroll_event_cb(GtkWidget *w, GdkEventScroll *event, GtkIMHtml *imhtml) |
|
| 847 { |
|
| 848 gtk_combo_box_popup(GTK_COMBO_BOX(w)); |
|
| 849 return TRUE; |
|
| 850 } |
|
| 851 |
|
| 852 static gboolean imhtml_scroll_event_cb(GtkWidget *w, GdkEventScroll *event, GtkIMHtml *imhtml) |
|
| 853 { |
|
| 854 if (event->direction == GDK_SCROLL_UP) |
|
| 855 gtk_imhtml_page_up(imhtml); |
|
| 856 else if (event->direction == GDK_SCROLL_DOWN) |
|
| 857 gtk_imhtml_page_down(imhtml); |
|
| 858 return TRUE; |
|
| 859 } |
|
| 860 |
|
| 861 static int imhtml_remove_focus(GtkWidget *w, GdkEventKey *event, GtkGaimStatusBox *status_box) |
|
| 862 { |
|
| 863 if (event->keyval == GDK_Tab || event->keyval == GDK_KP_Tab) |
|
| 864 { |
|
| 865 /* If last inserted character is a tab, then remove the focus from here */ |
|
| 866 GtkWidget *top = gtk_widget_get_toplevel(w); |
|
| 867 g_signal_emit_by_name(G_OBJECT(top), "move_focus", |
|
| 868 (event->state & GDK_SHIFT_MASK) ? |
|
| 869 GTK_DIR_TAB_BACKWARD: GTK_DIR_TAB_FORWARD); |
|
| 870 return TRUE; |
|
| 871 } |
|
| 872 if (!status_box->typing != 0) |
|
| 873 return FALSE; |
|
| 874 |
|
| 875 /* Reset the status if Escape was pressed */ |
|
| 876 if (event->keyval == GDK_Escape) |
|
| 877 { |
|
| 878 g_source_remove(status_box->typing); |
|
| 879 status_box->typing = 0; |
|
| 880 if (status_box->account != NULL) |
|
| 881 update_to_reflect_account_status(status_box, status_box->account, |
|
| 882 gaim_account_get_active_status(status_box->account)); |
|
| 883 else |
|
| 884 status_menu_refresh_iter(status_box); |
|
| 885 return TRUE; |
|
| 886 } |
|
| 887 |
|
| 888 gtk_gaim_status_box_pulse_typing(status_box); |
|
| 889 g_source_remove(status_box->typing); |
|
| 890 status_box->typing = g_timeout_add(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, status_box); |
|
| 891 |
|
| 892 return FALSE; |
|
| 893 } |
|
| 894 |
|
| 895 #if GTK_CHECK_VERSION(2,6,0) |
|
| 896 static gboolean |
|
| 897 dropdown_store_row_separator_func(GtkTreeModel *model, |
|
| 898 GtkTreeIter *iter, gpointer data) |
|
| 899 { |
|
| 900 GtkGaimStatusBoxItemType type; |
|
| 901 |
|
| 902 gtk_tree_model_get(model, iter, TYPE_COLUMN, &type, -1); |
|
| 903 |
|
| 904 if (type == GTK_GAIM_STATUS_BOX_TYPE_SEPARATOR) |
|
| 905 return TRUE; |
|
| 906 |
|
| 907 return FALSE; |
|
| 908 } |
|
| 909 #endif |
|
| 910 |
|
| 911 static void |
|
| 912 cache_pixbufs(GtkGaimStatusBox *status_box) |
|
| 913 { |
|
| 914 GtkIconSize icon_size; |
|
| 915 |
|
| 916 if (gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons")) |
|
| 917 { |
|
| 918 g_object_set(G_OBJECT(status_box->icon_rend), "xpad", 6, NULL); |
|
| 919 icon_size = gtk_icon_size_from_name(GAIM_ICON_SIZE_STATUS_TWO_LINE); |
|
| 920 } else { |
|
| 921 g_object_set(G_OBJECT(status_box->icon_rend), "xpad", 3, NULL); |
|
| 922 icon_size = gtk_icon_size_from_name(GAIM_ICON_SIZE_STATUS_SMALL_TWO_LINE); |
|
| 923 } |
|
| 924 |
|
| 925 if (status_box->connecting_pixbufs[0] != NULL) |
|
| 926 gdk_pixbuf_unref(status_box->connecting_pixbufs[0]); |
|
| 927 if (status_box->connecting_pixbufs[1] != NULL) |
|
| 928 gdk_pixbuf_unref(status_box->connecting_pixbufs[1]); |
|
| 929 if (status_box->connecting_pixbufs[2] != NULL) |
|
| 930 gdk_pixbuf_unref(status_box->connecting_pixbufs[2]); |
|
| 931 if (status_box->connecting_pixbufs[3] != NULL) |
|
| 932 gdk_pixbuf_unref(status_box->connecting_pixbufs[3]); |
|
| 933 |
|
| 934 status_box->connecting_index = 0; |
|
| 935 status_box->connecting_pixbufs[0] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_CONNECT0, |
|
| 936 icon_size, "GtkGaimStatusBox"); |
|
| 937 status_box->connecting_pixbufs[1] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_CONNECT1, |
|
| 938 icon_size, "GtkGaimStatusBox"); |
|
| 939 status_box->connecting_pixbufs[2] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_CONNECT2, |
|
| 940 icon_size, "GtkGaimStatusBox"); |
|
| 941 status_box->connecting_pixbufs[3] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_CONNECT3, |
|
| 942 icon_size, "GtkGaimStatusBox"); |
|
| 943 |
|
| 944 if (status_box->typing_pixbufs[0] != NULL) |
|
| 945 gdk_pixbuf_unref(status_box->typing_pixbufs[0]); |
|
| 946 if (status_box->typing_pixbufs[1] != NULL) |
|
| 947 gdk_pixbuf_unref(status_box->typing_pixbufs[1]); |
|
| 948 if (status_box->typing_pixbufs[2] != NULL) |
|
| 949 gdk_pixbuf_unref(status_box->typing_pixbufs[2]); |
|
| 950 if (status_box->typing_pixbufs[3] != NULL) |
|
| 951 gdk_pixbuf_unref(status_box->typing_pixbufs[3]); |
|
| 952 |
|
| 953 status_box->typing_index = 0; |
|
| 954 status_box->typing_pixbufs[0] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_TYPING0, |
|
| 955 icon_size, "GtkGaimStatusBox"); |
|
| 956 status_box->typing_pixbufs[1] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_TYPING1, |
|
| 957 icon_size, "GtkGaimStatusBox"); |
|
| 958 status_box->typing_pixbufs[2] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_TYPING2, |
|
| 959 icon_size, "GtkGaimStatusBox"); |
|
| 960 status_box->typing_pixbufs[3] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), GAIM_STOCK_STATUS_TYPING3, |
|
| 961 icon_size, "GtkGaimStatusBox"); |
|
| 962 } |
|
| 963 |
|
| 964 static void |
|
| 965 current_savedstatus_changed_cb(GaimSavedStatus *now, GaimSavedStatus *old, gpointer data) |
|
| 966 { |
|
| 967 GtkGaimStatusBox *status_box = data; |
|
| 968 |
|
| 969 /* Make sure our current status is added to the list of popular statuses */ |
|
| 970 gtk_gaim_status_box_regenerate(status_box); |
|
| 971 |
|
| 972 if (status_box->account != NULL) |
|
| 973 update_to_reflect_account_status(status_box, status_box->account, |
|
| 974 gaim_account_get_active_status(status_box->account)); |
|
| 975 else |
|
| 976 status_menu_refresh_iter(status_box); |
|
| 977 |
|
| 978 gtk_gaim_status_box_refresh(status_box); |
|
| 979 } |
|
| 980 |
|
| 981 static void |
|
| 982 buddy_list_details_pref_changed_cb(const char *name, GaimPrefType type, |
|
| 983 gconstpointer val, gpointer data) |
|
| 984 { |
|
| 985 GtkGaimStatusBox *status_box = (GtkGaimStatusBox *)data; |
|
| 986 |
|
| 987 cache_pixbufs(status_box); |
|
| 988 gtk_gaim_status_box_regenerate(status_box); |
|
| 989 gtk_gaim_status_box_refresh(status_box); |
|
| 990 } |
|
| 991 |
|
| 992 static void |
|
| 993 spellcheck_prefs_cb(const char *name, GaimPrefType type, |
|
| 994 gconstpointer value, gpointer data) |
|
| 995 { |
|
| 996 #ifdef USE_GTKSPELL |
|
| 997 GtkGaimStatusBox *status_box = (GtkGaimStatusBox *)data; |
|
| 998 |
|
| 999 if (value) |
|
| 1000 gaim_gtk_setup_gtkspell(GTK_TEXT_VIEW(status_box->imhtml)); |
|
| 1001 else |
|
| 1002 { |
|
| 1003 GtkSpell *spell; |
|
| 1004 spell = gtkspell_get_from_text_view(GTK_TEXT_VIEW(status_box->imhtml)); |
|
| 1005 gtkspell_detach(spell); |
|
| 1006 } |
|
| 1007 #endif |
|
| 1008 } |
|
| 1009 |
|
| 1010 #if 0 |
|
| 1011 static gboolean button_released_cb(GtkWidget *widget, GdkEventButton *event, GtkGaimStatusBox *box) |
|
| 1012 { |
|
| 1013 |
|
| 1014 if (event->button != 1) |
|
| 1015 return FALSE; |
|
| 1016 gtk_combo_box_popdown(GTK_COMBO_BOX(box)); |
|
| 1017 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(box->toggle_button), FALSE); |
|
| 1018 if (!box->imhtml_visible) |
|
| 1019 g_signal_emit_by_name(G_OBJECT(box), "changed", NULL, NULL); |
|
| 1020 return TRUE; |
|
| 1021 } |
|
| 1022 |
|
| 1023 static gboolean button_pressed_cb(GtkWidget *widget, GdkEventButton *event, GtkGaimStatusBox *box) |
|
| 1024 { |
|
| 1025 if (event->button != 1) |
|
| 1026 return FALSE; |
|
| 1027 gtk_combo_box_popup(GTK_COMBO_BOX(box)); |
|
| 1028 // Disabled until button_released_cb works |
|
| 1029 // gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(box->toggle_button), TRUE); |
|
| 1030 return TRUE; |
|
| 1031 } |
|
| 1032 #endif |
|
| 1033 |
|
| 1034 static void |
|
| 1035 toggled_cb(GtkWidget *widget, GtkGaimStatusBox *box) |
|
| 1036 { |
|
| 1037 gtk_combo_box_popup(GTK_COMBO_BOX(box)); |
|
| 1038 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(box->toggle_button), FALSE); |
|
| 1039 } |
|
| 1040 |
|
| 1041 static void |
|
| 1042 icon_choose_cb(const char *filename, gpointer data) |
|
| 1043 { |
|
| 1044 GtkGaimStatusBox *box; |
|
| 1045 |
|
| 1046 box = data; |
|
| 1047 |
|
| 1048 if (filename) { |
|
| 1049 GList *accounts; |
|
| 1050 |
|
| 1051 if (box->account) { |
|
| 1052 GaimPlugin *plug = gaim_find_prpl(gaim_account_get_protocol_id(box->account)); |
|
| 1053 if (plug) { |
|
| 1054 GaimPluginProtocolInfo *prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plug); |
|
| 1055 if (prplinfo && prplinfo->icon_spec.format) { |
|
| 1056 char *icon = gaim_gtk_convert_buddy_icon(plug, filename); |
|
| 1057 gaim_account_set_buddy_icon(box->account, icon); |
|
| 1058 g_free(icon); |
|
| 1059 gaim_account_set_ui_bool(box->account, GAIM_GTK_UI, "use-global-buddyicon", FALSE); |
|
| 1060 gaim_account_set_ui_string(box->account, GAIM_GTK_UI, "non-global-buddyicon", icon); |
|
| 1061 } |
|
| 1062 } |
|
| 1063 } else { |
|
| 1064 for (accounts = gaim_accounts_get_all(); accounts != NULL; accounts = accounts->next) { |
|
| 1065 GaimAccount *account = accounts->data; |
|
| 1066 GaimPlugin *plug = gaim_find_prpl(gaim_account_get_protocol_id(account)); |
|
| 1067 if (plug) { |
|
| 1068 GaimPluginProtocolInfo *prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plug); |
|
| 1069 if (prplinfo != NULL && |
|
| 1070 gaim_account_get_ui_bool(account, GAIM_GTK_UI, "use-global-buddyicon", TRUE) && |
|
| 1071 prplinfo->icon_spec.format) { |
|
| 1072 char *icon = gaim_gtk_convert_buddy_icon(plug, filename); |
|
| 1073 gaim_account_set_buddy_icon(account, icon); |
|
| 1074 g_free(icon); |
|
| 1075 } |
|
| 1076 } |
|
| 1077 } |
|
| 1078 } |
|
| 1079 gtk_gaim_status_box_set_buddy_icon(box, filename); |
|
| 1080 } |
|
| 1081 |
|
| 1082 box->buddy_icon_sel = NULL; |
|
| 1083 } |
|
| 1084 |
|
| 1085 static void |
|
| 1086 gtk_gaim_status_box_init (GtkGaimStatusBox *status_box) |
|
| 1087 { |
|
| 1088 GtkCellRenderer *text_rend; |
|
| 1089 GtkCellRenderer *icon_rend; |
|
| 1090 GtkTextBuffer *buffer; |
|
| 1091 |
|
| 1092 status_box->imhtml_visible = FALSE; |
|
| 1093 status_box->connecting = FALSE; |
|
| 1094 status_box->typing = 0; |
|
| 1095 status_box->toggle_button = gtk_toggle_button_new(); |
|
| 1096 status_box->hbox = gtk_hbox_new(FALSE, 6); |
|
| 1097 status_box->cell_view = gtk_cell_view_new(); |
|
| 1098 status_box->vsep = gtk_vseparator_new(); |
|
| 1099 status_box->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); |
|
| 1100 |
|
| 1101 status_box->store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); |
|
| 1102 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, G_TYPE_POINTER); |
|
| 1103 gtk_combo_box_set_model(GTK_COMBO_BOX(status_box), GTK_TREE_MODEL(status_box->dropdown_store)); |
|
| 1104 gtk_cell_view_set_model(GTK_CELL_VIEW(status_box->cell_view), GTK_TREE_MODEL(status_box->store)); |
|
| 1105 gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(status_box), 0); |
|
| 1106 gtk_list_store_append(status_box->store, &(status_box->iter)); |
|
| 1107 |
|
| 1108 gtk_container_add(GTK_CONTAINER(status_box->toggle_button), status_box->hbox); |
|
| 1109 gtk_box_pack_start(GTK_BOX(status_box->hbox), status_box->cell_view, TRUE, TRUE, 0); |
|
| 1110 gtk_box_pack_start(GTK_BOX(status_box->hbox), status_box->vsep, FALSE, FALSE, 0); |
|
| 1111 gtk_box_pack_start(GTK_BOX(status_box->hbox), status_box->arrow, FALSE, FALSE, 0); |
|
| 1112 gtk_widget_show_all(status_box->toggle_button); |
|
| 1113 #if GTK_CHECK_VERSION(2,4,0) |
|
| 1114 gtk_button_set_focus_on_click(GTK_BUTTON(status_box->toggle_button), FALSE); |
|
| 1115 #endif |
|
| 1116 |
|
| 1117 text_rend = gtk_cell_renderer_text_new(); |
|
| 1118 icon_rend = gtk_cell_renderer_pixbuf_new(); |
|
| 1119 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(status_box), icon_rend, FALSE); |
|
| 1120 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(status_box), text_rend, TRUE); |
|
| 1121 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(status_box), icon_rend, "pixbuf", ICON_COLUMN, NULL); |
|
| 1122 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(status_box), text_rend, "markup", TEXT_COLUMN, NULL); |
|
| 1123 #if GTK_CHECK_VERSION(2, 6, 0) |
|
| 1124 g_object_set(text_rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL); |
|
| 1125 #endif |
|
| 1126 |
|
| 1127 status_box->icon_rend = gtk_cell_renderer_pixbuf_new(); |
|
| 1128 status_box->text_rend = gtk_cell_renderer_text_new(); |
|
| 1129 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(status_box->cell_view), status_box->icon_rend, FALSE); |
|
| 1130 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(status_box->cell_view), status_box->text_rend, TRUE); |
|
| 1131 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(status_box->cell_view), status_box->icon_rend, "pixbuf", ICON_COLUMN, NULL); |
|
| 1132 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(status_box->cell_view), status_box->text_rend, "markup", TEXT_COLUMN, NULL); |
|
| 1133 #if GTK_CHECK_VERSION(2, 6, 0) |
|
| 1134 g_object_set(status_box->text_rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL); |
|
| 1135 #endif |
|
| 1136 |
|
| 1137 status_box->vbox = gtk_vbox_new(0, FALSE); |
|
| 1138 status_box->sw = gaim_gtk_create_imhtml(FALSE, &status_box->imhtml, NULL, NULL); |
|
| 1139 gtk_imhtml_set_editable(GTK_IMHTML(status_box->imhtml), TRUE); |
|
| 1140 |
|
| 1141 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(status_box->imhtml)); |
|
| 1142 #if 0 |
|
| 1143 g_signal_connect(G_OBJECT(status_box->toggle_button), "button-press-event", |
|
| 1144 G_CALLBACK(button_pressed_cb), status_box); |
|
| 1145 g_signal_connect(G_OBJECT(status_box->toggle_button), "button-release-event", |
|
| 1146 G_CALLBACK(button_released_cb), status_box); |
|
| 1147 #endif |
|
| 1148 g_signal_connect(G_OBJECT(status_box->toggle_button), "toggled", |
|
| 1149 G_CALLBACK(toggled_cb), status_box); |
|
| 1150 g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK(imhtml_changed_cb), status_box); |
|
| 1151 g_signal_connect(G_OBJECT(status_box->imhtml), "format_function_toggle", |
|
| 1152 G_CALLBACK(imhtml_format_changed_cb), status_box); |
|
| 1153 g_signal_connect(G_OBJECT(status_box->imhtml), "key_press_event", |
|
| 1154 G_CALLBACK(imhtml_remove_focus), status_box); |
|
| 1155 g_signal_connect_swapped(G_OBJECT(status_box->imhtml), "message_send", G_CALLBACK(remove_typing_cb), status_box); |
|
| 1156 gtk_imhtml_set_editable(GTK_IMHTML(status_box->imhtml), TRUE); |
|
| 1157 #ifdef USE_GTKSPELL |
|
| 1158 if (gaim_prefs_get_bool("/gaim/gtk/conversations/spellcheck")) |
|
| 1159 gaim_gtk_setup_gtkspell(GTK_TEXT_VIEW(status_box->imhtml)); |
|
| 1160 #endif |
|
| 1161 gtk_widget_set_parent(status_box->vbox, GTK_WIDGET(status_box)); |
|
| 1162 gtk_widget_set_parent(status_box->toggle_button, GTK_WIDGET(status_box)); |
|
| 1163 GTK_BIN(status_box)->child = status_box->toggle_button; |
|
| 1164 |
|
| 1165 gtk_box_pack_start(GTK_BOX(status_box->vbox), status_box->sw, TRUE, TRUE, 0); |
|
| 1166 |
|
| 1167 g_signal_connect(G_OBJECT(status_box), "scroll_event", G_CALLBACK(combo_box_scroll_event_cb), NULL); |
|
| 1168 g_signal_connect(G_OBJECT(status_box->imhtml), "scroll_event", |
|
| 1169 G_CALLBACK(imhtml_scroll_event_cb), status_box->imhtml); |
|
| 1170 |
|
| 1171 #if GTK_CHECK_VERSION(2,6,0) |
|
| 1172 gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(status_box), dropdown_store_row_separator_func, NULL, NULL); |
|
| 1173 #endif |
|
| 1174 |
|
| 1175 cache_pixbufs(status_box); |
|
| 1176 gtk_gaim_status_box_regenerate(status_box); |
|
| 1177 gtk_gaim_status_box_refresh(status_box); |
|
| 1178 |
|
| 1179 gaim_signal_connect(gaim_savedstatuses_get_handle(), "savedstatus-changed", |
|
| 1180 status_box, |
|
| 1181 GAIM_CALLBACK(current_savedstatus_changed_cb), |
|
| 1182 status_box); |
|
| 1183 gaim_prefs_connect_callback(status_box, "/gaim/gtk/blist/show_buddy_icons", |
|
| 1184 buddy_list_details_pref_changed_cb, status_box); |
|
| 1185 gaim_prefs_connect_callback(status_box, "/gaim/gtk/conversations/spellcheck", |
|
| 1186 spellcheck_prefs_cb, status_box); |
|
| 1187 } |
|
| 1188 |
|
| 1189 static void |
|
| 1190 gtk_gaim_status_box_size_request(GtkWidget *widget, |
|
| 1191 GtkRequisition *requisition) |
|
| 1192 { |
|
| 1193 GtkRequisition box_req; |
|
| 1194 combo_box_size_request(widget, requisition); |
|
| 1195 requisition->height += 3; |
|
| 1196 |
|
| 1197 /* If the gtkimhtml is visible, then add some additional padding */ |
|
| 1198 gtk_widget_size_request(GTK_GAIM_STATUS_BOX(widget)->vbox, &box_req); |
|
| 1199 if (box_req.height > 1) |
|
| 1200 requisition->height += box_req.height + 3; |
|
| 1201 |
|
| 1202 requisition->width = 1; |
|
| 1203 |
|
| 1204 |
|
| 1205 } |
|
| 1206 |
|
| 1207 /* From gnome-panel */ |
|
| 1208 static void |
|
| 1209 do_colorshift (GdkPixbuf *dest, GdkPixbuf *src, int shift) |
|
| 1210 { |
|
| 1211 gint i, j; |
|
| 1212 gint width, height, has_alpha, srcrowstride, destrowstride; |
|
| 1213 guchar *target_pixels; |
|
| 1214 guchar *original_pixels; |
|
| 1215 guchar *pixsrc; |
|
| 1216 guchar *pixdest; |
|
| 1217 int val; |
|
| 1218 guchar r,g,b; |
|
| 1219 |
|
| 1220 has_alpha = gdk_pixbuf_get_has_alpha (src); |
|
| 1221 width = gdk_pixbuf_get_width (src); |
|
| 1222 height = gdk_pixbuf_get_height (src); |
|
| 1223 srcrowstride = gdk_pixbuf_get_rowstride (src); |
|
| 1224 destrowstride = gdk_pixbuf_get_rowstride (dest); |
|
| 1225 target_pixels = gdk_pixbuf_get_pixels (dest); |
|
| 1226 original_pixels = gdk_pixbuf_get_pixels (src); |
|
| 1227 |
|
| 1228 for (i = 0; i < height; i++) { |
|
| 1229 pixdest = target_pixels + i*destrowstride; |
|
| 1230 pixsrc = original_pixels + i*srcrowstride; |
|
| 1231 for (j = 0; j < width; j++) { |
|
| 1232 r = *(pixsrc++); |
|
| 1233 g = *(pixsrc++); |
|
| 1234 b = *(pixsrc++); |
|
| 1235 val = r + shift; |
|
| 1236 *(pixdest++) = CLAMP(val, 0, 255); |
|
| 1237 val = g + shift; |
|
| 1238 *(pixdest++) = CLAMP(val, 0, 255); |
|
| 1239 val = b + shift; |
|
| 1240 *(pixdest++) = CLAMP(val, 0, 255); |
|
| 1241 if (has_alpha) |
|
| 1242 *(pixdest++) = *(pixsrc++); |
|
| 1243 } |
|
| 1244 } |
|
| 1245 } |
|
| 1246 |
|
| 1247 static void |
|
| 1248 gtk_gaim_status_box_size_allocate(GtkWidget *widget, |
|
| 1249 GtkAllocation *allocation) |
|
| 1250 { |
|
| 1251 GtkGaimStatusBox *status_box = GTK_GAIM_STATUS_BOX(widget); |
|
| 1252 GtkRequisition req = {0,0}; |
|
| 1253 GtkAllocation parent_alc, box_alc, icon_alc; |
|
| 1254 GdkPixbuf *scaled; |
|
| 1255 |
|
| 1256 combo_box_size_request(widget, &req); |
|
| 1257 |
|
| 1258 box_alc = *allocation; |
|
| 1259 box_alc.height = MAX(1, (allocation->height - req.height - 6)); |
|
| 1260 box_alc.y += req.height + 6; |
|
| 1261 gtk_widget_size_allocate((GTK_GAIM_STATUS_BOX(widget))->vbox, &box_alc); |
|
| 1262 |
|
| 1263 parent_alc = *allocation; |
|
| 1264 parent_alc.height = MAX(1,req.height); |
|
| 1265 parent_alc.y += 3; |
|
| 1266 |
|
| 1267 if (status_box->icon_box) |
|
| 1268 { |
|
| 1269 parent_alc.width -= (parent_alc.height + 3); |
|
| 1270 icon_alc = *allocation; |
|
| 1271 icon_alc.height = MAX(1,req.height); |
|
| 1272 icon_alc.width = icon_alc.height; |
|
| 1273 icon_alc.x = allocation->width - icon_alc.width; |
|
| 1274 icon_alc.y += 3; |
|
| 1275 |
|
| 1276 if (status_box->icon_size != icon_alc.height) |
|
| 1277 { |
|
| 1278 if (status_box->buddy_icon_hover) |
|
| 1279 g_object_unref(status_box->buddy_icon_hover); |
|
| 1280 if ((status_box->buddy_icon_path != NULL) && |
|
| 1281 (*status_box->buddy_icon_path != '\0')) |
|
| 1282 { |
|
| 1283 scaled = gdk_pixbuf_new_from_file_at_scale(status_box->buddy_icon_path, |
|
| 1284 icon_alc.height, icon_alc.width, FALSE, NULL); |
|
| 1285 if (scaled != NULL) |
|
| 1286 { |
|
| 1287 status_box->buddy_icon_hover = gdk_pixbuf_copy(scaled); |
|
| 1288 do_colorshift(status_box->buddy_icon_hover, status_box->buddy_icon_hover, 30); |
|
| 1289 if (status_box->buddy_icon) |
|
| 1290 g_object_unref(status_box->buddy_icon); |
|
| 1291 status_box->buddy_icon = scaled; |
|
| 1292 gtk_image_set_from_pixbuf(GTK_IMAGE(status_box->icon), status_box->buddy_icon); |
|
| 1293 } |
|
| 1294 } |
|
| 1295 status_box->icon_size = icon_alc.height; |
|
| 1296 } |
|
| 1297 gtk_widget_size_allocate(status_box->icon_box, &icon_alc); |
|
| 1298 } |
|
| 1299 |
|
| 1300 combo_box_size_allocate(widget, &parent_alc); |
|
| 1301 gtk_widget_size_allocate(status_box->toggle_button, &parent_alc); |
|
| 1302 widget->allocation = *allocation; |
|
| 1303 } |
|
| 1304 |
|
| 1305 static gboolean |
|
| 1306 gtk_gaim_status_box_expose_event(GtkWidget *widget, |
|
| 1307 GdkEventExpose *event) |
|
| 1308 { |
|
| 1309 GtkGaimStatusBox *status_box = GTK_GAIM_STATUS_BOX(widget); |
|
| 1310 gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->vbox, event); |
|
| 1311 gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->toggle_button, event); |
|
| 1312 if (status_box->icon_box) |
|
| 1313 gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->icon_box, event); |
|
| 1314 return FALSE; |
|
| 1315 } |
|
| 1316 |
|
| 1317 static void |
|
| 1318 gtk_gaim_status_box_forall(GtkContainer *container, |
|
| 1319 gboolean include_internals, |
|
| 1320 GtkCallback callback, |
|
| 1321 gpointer callback_data) |
|
| 1322 { |
|
| 1323 GtkGaimStatusBox *status_box = GTK_GAIM_STATUS_BOX (container); |
|
| 1324 |
|
| 1325 if (include_internals) |
|
| 1326 { |
|
| 1327 (* callback) (status_box->vbox, callback_data); |
|
| 1328 (* callback) (status_box->toggle_button, callback_data); |
|
| 1329 (* callback) (status_box->arrow, callback_data); |
|
| 1330 if (status_box->icon_box) |
|
| 1331 (* callback) (status_box->icon_box, callback_data); |
|
| 1332 } |
|
| 1333 |
|
| 1334 combo_box_forall(container, include_internals, callback, callback_data); |
|
| 1335 } |
|
| 1336 |
|
| 1337 GtkWidget * |
|
| 1338 gtk_gaim_status_box_new() |
|
| 1339 { |
|
| 1340 return g_object_new(GTK_GAIM_TYPE_STATUS_BOX, "account", NULL, |
|
| 1341 "iconsel", TRUE, NULL); |
|
| 1342 } |
|
| 1343 |
|
| 1344 GtkWidget * |
|
| 1345 gtk_gaim_status_box_new_with_account(GaimAccount *account) |
|
| 1346 { |
|
| 1347 return g_object_new(GTK_GAIM_TYPE_STATUS_BOX, "account", account, |
|
| 1348 "iconsel", TRUE, NULL); |
|
| 1349 } |
|
| 1350 |
|
| 1351 /** |
|
| 1352 * Add a row to the dropdown menu. |
|
| 1353 * |
|
| 1354 * @param status_box The status box itself. |
|
| 1355 * @param type A GtkGaimStatusBoxItemType. |
|
| 1356 * @param pixbuf The icon to associate with this row in the menu. |
|
| 1357 * @param title The title of this item. For the primitive entries, |
|
| 1358 * this is something like "Available" or "Away." For |
|
| 1359 * the saved statuses, this is something like |
|
| 1360 * "My favorite away message!" This should be |
|
| 1361 * plaintext (non-markedup) (this function escapes it). |
|
| 1362 * @param desc The secondary text for this item. This will be |
|
| 1363 * placed on the row below the title, in a dimmer |
|
| 1364 * font (generally gray). This text should be plaintext |
|
| 1365 * (non-markedup) (this function escapes it). |
|
| 1366 * @param data Data to be associated with this row in the dropdown |
|
| 1367 * menu. For primitives this is the value of the |
|
| 1368 * GaimStatusPrimitive. For saved statuses this is the |
|
| 1369 * creation timestamp. |
|
| 1370 */ |
|
| 1371 void |
|
| 1372 gtk_gaim_status_box_add(GtkGaimStatusBox *status_box, GtkGaimStatusBoxItemType type, GdkPixbuf *pixbuf, const char *title, const char *desc, gpointer data) |
|
| 1373 { |
|
| 1374 GtkTreeIter iter; |
|
| 1375 char *text; |
|
| 1376 |
|
| 1377 if (desc == NULL) |
|
| 1378 { |
|
| 1379 text = g_markup_escape_text(title, -1); |
|
| 1380 } |
|
| 1381 else |
|
| 1382 { |
|
| 1383 gboolean show_buddy_icons; |
|
| 1384 GtkStyle *style; |
|
| 1385 char aa_color[8]; |
|
| 1386 gchar *escaped_title, *escaped_desc; |
|
| 1387 |
|
| 1388 show_buddy_icons = gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons"); |
|
| 1389 style = gtk_widget_get_style(GTK_WIDGET(status_box)); |
|
| 1390 snprintf(aa_color, sizeof(aa_color), "#%02x%02x%02x", |
|
| 1391 style->text_aa[GTK_STATE_NORMAL].red >> 8, |
|
| 1392 style->text_aa[GTK_STATE_NORMAL].green >> 8, |
|
| 1393 style->text_aa[GTK_STATE_NORMAL].blue >> 8); |
|
| 1394 |
|
| 1395 escaped_title = g_markup_escape_text(title, -1); |
|
| 1396 escaped_desc = g_markup_escape_text(desc, -1); |
|
| 1397 text = g_strdup_printf("%s%s<span color=\"%s\" size=\"smaller\">%s</span>", |
|
| 1398 escaped_title, |
|
| 1399 show_buddy_icons ? "\n" : " - ", |
|
| 1400 aa_color, escaped_desc); |
|
| 1401 g_free(escaped_title); |
|
| 1402 g_free(escaped_desc); |
|
| 1403 } |
|
| 1404 |
|
| 1405 gtk_list_store_append(status_box->dropdown_store, &iter); |
|
| 1406 gtk_list_store_set(status_box->dropdown_store, &iter, |
|
| 1407 TYPE_COLUMN, type, |
|
| 1408 ICON_COLUMN, pixbuf, |
|
| 1409 TEXT_COLUMN, text, |
|
| 1410 TITLE_COLUMN, title, |
|
| 1411 DESC_COLUMN, desc, |
|
| 1412 DATA_COLUMN, data, |
|
| 1413 -1); |
|
| 1414 g_free(text); |
|
| 1415 } |
|
| 1416 |
|
| 1417 void |
|
| 1418 gtk_gaim_status_box_add_separator(GtkGaimStatusBox *status_box) |
|
| 1419 { |
|
| 1420 /* Don't do anything unless GTK actually supports |
|
| 1421 * gtk_combo_box_set_row_separator_func */ |
|
| 1422 #if GTK_CHECK_VERSION(2,6,0) |
|
| 1423 GtkTreeIter iter; |
|
| 1424 |
|
| 1425 gtk_list_store_append(status_box->dropdown_store, &iter); |
|
| 1426 gtk_list_store_set(status_box->dropdown_store, &iter, |
|
| 1427 TYPE_COLUMN, GTK_GAIM_STATUS_BOX_TYPE_SEPARATOR, |
|
| 1428 -1); |
|
| 1429 #endif |
|
| 1430 } |
|
| 1431 |
|
| 1432 void |
|
| 1433 gtk_gaim_status_box_set_connecting(GtkGaimStatusBox *status_box, gboolean connecting) |
|
| 1434 { |
|
| 1435 if (!status_box) |
|
| 1436 return; |
|
| 1437 status_box->connecting = connecting; |
|
| 1438 gtk_gaim_status_box_refresh(status_box); |
|
| 1439 } |
|
| 1440 |
|
| 1441 void |
|
| 1442 gtk_gaim_status_box_set_buddy_icon(GtkGaimStatusBox *box, const char *filename) |
|
| 1443 { |
|
| 1444 GdkPixbuf *scaled; |
|
| 1445 g_free(box->buddy_icon_path); |
|
| 1446 box->buddy_icon_path = g_strdup(filename); |
|
| 1447 |
|
| 1448 if ((filename != NULL) && (*filename != '\0')) |
|
| 1449 { |
|
| 1450 if (box->buddy_icon != NULL) |
|
| 1451 g_object_unref(box->buddy_icon); |
|
| 1452 |
|
| 1453 /* This will get called before the box is shown and will not have a size */ |
|
| 1454 if (box->icon_size > 0) { |
|
| 1455 scaled = gdk_pixbuf_new_from_file_at_scale(filename, |
|
| 1456 box->icon_size, box->icon_size, FALSE, NULL); |
|
| 1457 if (scaled != NULL) |
|
| 1458 { |
|
| 1459 box->buddy_icon_hover = gdk_pixbuf_copy(scaled); |
|
| 1460 do_colorshift(box->buddy_icon_hover, box->buddy_icon_hover, 30); |
|
| 1461 box->buddy_icon = scaled; |
|
| 1462 gtk_image_set_from_pixbuf(GTK_IMAGE(box->icon), box->buddy_icon); |
|
| 1463 } |
|
| 1464 } |
|
| 1465 } |
|
| 1466 |
|
| 1467 if (box->account == NULL) |
|
| 1468 gaim_prefs_set_string("/gaim/gtk/accounts/buddyicon", filename); |
|
| 1469 } |
|
| 1470 |
|
| 1471 const char* |
|
| 1472 gtk_gaim_status_box_get_buddy_icon(GtkGaimStatusBox *box) |
|
| 1473 { |
|
| 1474 return box->buddy_icon_path; |
|
| 1475 } |
|
| 1476 |
|
| 1477 void |
|
| 1478 gtk_gaim_status_box_pulse_connecting(GtkGaimStatusBox *status_box) |
|
| 1479 { |
|
| 1480 if (!status_box) |
|
| 1481 return; |
|
| 1482 if (status_box->connecting_index == 3) |
|
| 1483 status_box->connecting_index = 0; |
|
| 1484 else |
|
| 1485 status_box->connecting_index++; |
|
| 1486 gtk_gaim_status_box_refresh(status_box); |
|
| 1487 } |
|
| 1488 |
|
| 1489 static void |
|
| 1490 gtk_gaim_status_box_pulse_typing(GtkGaimStatusBox *status_box) |
|
| 1491 { |
|
| 1492 if (status_box->typing_index == 3) |
|
| 1493 status_box->typing_index = 0; |
|
| 1494 else |
|
| 1495 status_box->typing_index++; |
|
| 1496 gtk_gaim_status_box_refresh(status_box); |
|
| 1497 } |
|
| 1498 |
|
| 1499 static GaimStatusType * |
|
| 1500 find_status_type_by_index(const GaimAccount *account, gint active) |
|
| 1501 { |
|
| 1502 const GList *l = gaim_account_get_status_types(account); |
|
| 1503 gint i; |
|
| 1504 |
|
| 1505 for (i = 0; l; l = l->next) { |
|
| 1506 GaimStatusType *status_type = l->data; |
|
| 1507 if (!gaim_status_type_is_user_settable(status_type)) |
|
| 1508 continue; |
|
| 1509 |
|
| 1510 if (active == i) |
|
| 1511 return status_type; |
|
| 1512 i++; |
|
| 1513 } |
|
| 1514 |
|
| 1515 return NULL; |
|
| 1516 } |
|
| 1517 |
|
| 1518 static gboolean |
|
| 1519 message_changed(const char *one, const char *two) |
|
| 1520 { |
|
| 1521 if (one == NULL && two == NULL) |
|
| 1522 return FALSE; |
|
| 1523 |
|
| 1524 if (one == NULL || two == NULL) |
|
| 1525 return TRUE; |
|
| 1526 |
|
| 1527 return (g_utf8_collate(one, two) != 0); |
|
| 1528 } |
|
| 1529 |
|
| 1530 static void |
|
| 1531 activate_currently_selected_status(GtkGaimStatusBox *status_box) |
|
| 1532 { |
|
| 1533 GtkGaimStatusBoxItemType type; |
|
| 1534 gpointer data; |
|
| 1535 gchar *title; |
|
| 1536 GtkTreeIter iter; |
|
| 1537 char *message; |
|
| 1538 GaimSavedStatus *saved_status; |
|
| 1539 gboolean changed = TRUE; |
|
| 1540 |
|
| 1541 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(status_box), &iter)) |
|
| 1542 return; |
|
| 1543 |
|
| 1544 gtk_tree_model_get(GTK_TREE_MODEL(status_box->dropdown_store), &iter, |
|
| 1545 TYPE_COLUMN, &type, |
|
| 1546 DATA_COLUMN, &data, |
|
| 1547 -1); |
|
| 1548 |
|
| 1549 /* |
|
| 1550 * If the currently selected status is "New..." or |
|
| 1551 * "Saved..." or a popular status then do nothing. |
|
| 1552 * Popular statuses are |
|
| 1553 * activated elsewhere, and we update the status_box |
|
| 1554 * accordingly by connecting to the savedstatus-changed |
|
| 1555 * signal and then calling status_menu_refresh_iter() |
|
| 1556 */ |
|
| 1557 if (type != GTK_GAIM_STATUS_BOX_TYPE_PRIMITIVE) |
|
| 1558 return; |
|
| 1559 |
|
| 1560 gtk_tree_model_get(GTK_TREE_MODEL(status_box->dropdown_store), &iter, |
|
| 1561 TITLE_COLUMN, &title, -1); |
|
| 1562 |
|
| 1563 message = gtk_gaim_status_box_get_message(status_box); |
|
| 1564 if (!message || !*message) |
|
| 1565 { |
|
| 1566 gtk_widget_hide_all(status_box->vbox); |
|
| 1567 status_box->imhtml_visible = FALSE; |
|
| 1568 if (message != NULL) |
|
| 1569 { |
|
| 1570 g_free(message); |
|
| 1571 message = NULL; |
|
| 1572 } |
|
| 1573 } |
|
| 1574 |
|
| 1575 if (status_box->account == NULL) { |
|
| 1576 /* Global */ |
|
| 1577 /* Save the newly selected status to prefs.xml and status.xml */ |
|
| 1578 |
|
| 1579 /* Has the status really been changed? */ |
|
| 1580 saved_status = gaim_savedstatus_get_current(); |
|
| 1581 if (gaim_savedstatus_get_type(saved_status) == GPOINTER_TO_INT(data) && |
|
| 1582 !gaim_savedstatus_has_substatuses(saved_status)) |
|
| 1583 { |
|
| 1584 if (!message_changed(gaim_savedstatus_get_message(saved_status), message)) |
|
| 1585 changed = FALSE; |
|
| 1586 } |
|
| 1587 |
|
| 1588 if (changed) |
|
| 1589 { |
|
| 1590 /* If we've used this type+message before, lookup the transient status */ |
|
| 1591 saved_status = gaim_savedstatus_find_transient_by_type_and_message( |
|
| 1592 GPOINTER_TO_INT(data), message); |
|
| 1593 |
|
| 1594 /* If this type+message is unique then create a new transient saved status */ |
|
| 1595 if (saved_status == NULL) |
|
| 1596 { |
|
| 1597 saved_status = gaim_savedstatus_new(NULL, GPOINTER_TO_INT(data)); |
|
| 1598 gaim_savedstatus_set_message(saved_status, message); |
|
| 1599 } |
|
| 1600 |
|
| 1601 /* Set the status for each account */ |
|
| 1602 gaim_savedstatus_activate(saved_status); |
|
| 1603 } |
|
| 1604 } else { |
|
| 1605 /* Per-account */ |
|
| 1606 gint active; |
|
| 1607 GaimStatusType *status_type; |
|
| 1608 GaimStatus *status; |
|
| 1609 const char *id = NULL; |
|
| 1610 |
|
| 1611 status = gaim_account_get_active_status(status_box->account); |
|
| 1612 |
|
| 1613 g_object_get(G_OBJECT(status_box), "active", &active, NULL); |
|
| 1614 |
|
| 1615 status_type = find_status_type_by_index(status_box->account, active); |
|
| 1616 id = gaim_status_type_get_id(status_type); |
|
| 1617 |
|
| 1618 if (strncmp(id, gaim_status_get_id(status), strlen(id)) == 0) |
|
| 1619 { |
|
| 1620 /* Selected status and previous status is the same */ |
|
| 1621 if (!message_changed(message, gaim_status_get_attr_string(status, "message"))) |
|
| 1622 changed = FALSE; |
|
| 1623 } |
|
| 1624 |
|
| 1625 if (changed) |
|
| 1626 { |
|
| 1627 if (message) |
|
| 1628 gaim_account_set_status(status_box->account, id, |
|
| 1629 TRUE, "message", message, NULL); |
|
| 1630 else |
|
| 1631 gaim_account_set_status(status_box->account, id, |
|
| 1632 TRUE, NULL); |
|
| 1633 } |
|
| 1634 } |
|
| 1635 |
|
| 1636 g_free(title); |
|
| 1637 g_free(message); |
|
| 1638 } |
|
| 1639 |
|
| 1640 static void update_size(GtkGaimStatusBox *status_box) |
|
| 1641 { |
|
| 1642 GtkTextBuffer *buffer; |
|
| 1643 GtkTextIter iter; |
|
| 1644 int wrapped_lines; |
|
| 1645 int lines; |
|
| 1646 GdkRectangle oneline; |
|
| 1647 int height; |
|
| 1648 int pad_top, pad_inside, pad_bottom; |
|
| 1649 |
|
| 1650 if (!status_box->imhtml_visible) |
|
| 1651 { |
|
| 1652 if (status_box->vbox != NULL) |
|
| 1653 gtk_widget_set_size_request(status_box->vbox, -1, -1); |
|
| 1654 return; |
|
| 1655 } |
|
| 1656 |
|
| 1657 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(status_box->imhtml)); |
|
| 1658 |
|
| 1659 wrapped_lines = 1; |
|
| 1660 gtk_text_buffer_get_start_iter(buffer, &iter); |
|
| 1661 while (gtk_text_view_forward_display_line(GTK_TEXT_VIEW(status_box->imhtml), &iter)) |
|
| 1662 wrapped_lines++; |
|
| 1663 |
|
| 1664 lines = gtk_text_buffer_get_line_count(buffer); |
|
| 1665 |
|
| 1666 /* Show a maximum of 4 lines */ |
|
| 1667 lines = MIN(lines, 4); |
|
| 1668 wrapped_lines = MIN(wrapped_lines, 4); |
|
| 1669 |
|
| 1670 gtk_text_buffer_get_start_iter(buffer, &iter); |
|
| 1671 gtk_text_view_get_iter_location(GTK_TEXT_VIEW(status_box->imhtml), &iter, &oneline); |
|
| 1672 |
|
| 1673 pad_top = gtk_text_view_get_pixels_above_lines(GTK_TEXT_VIEW(status_box->imhtml)); |
|
| 1674 pad_bottom = gtk_text_view_get_pixels_below_lines(GTK_TEXT_VIEW(status_box->imhtml)); |
|
| 1675 pad_inside = gtk_text_view_get_pixels_inside_wrap(GTK_TEXT_VIEW(status_box->imhtml)); |
|
| 1676 |
|
| 1677 height = (oneline.height + pad_top + pad_bottom) * lines; |
|
| 1678 height += (oneline.height + pad_inside) * (wrapped_lines - lines); |
|
| 1679 |
|
| 1680 gtk_widget_set_size_request(status_box->vbox, -1, height + GAIM_HIG_BOX_SPACE); |
|
| 1681 } |
|
| 1682 |
|
| 1683 static void remove_typing_cb(GtkGaimStatusBox *status_box) |
|
| 1684 { |
|
| 1685 if (status_box->typing == 0) |
|
| 1686 { |
|
| 1687 /* Nothing has changed, so we don't need to do anything */ |
|
| 1688 status_menu_refresh_iter(status_box); |
|
| 1689 return; |
|
| 1690 } |
|
| 1691 |
|
| 1692 g_source_remove(status_box->typing); |
|
| 1693 status_box->typing = 0; |
|
| 1694 |
|
| 1695 activate_currently_selected_status(status_box); |
|
| 1696 gtk_gaim_status_box_refresh(status_box); |
|
| 1697 } |
|
| 1698 |
|
| 1699 static void gtk_gaim_status_box_changed(GtkComboBox *box) |
|
| 1700 { |
|
| 1701 GtkGaimStatusBox *status_box; |
|
| 1702 GtkTreeIter iter; |
|
| 1703 GtkGaimStatusBoxItemType type; |
|
| 1704 gpointer data; |
|
| 1705 GList *accounts = NULL, *node; |
|
| 1706 |
|
| 1707 status_box = GTK_GAIM_STATUS_BOX(box); |
|
| 1708 |
|
| 1709 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(status_box), &iter)) |
|
| 1710 return; |
|
| 1711 gtk_tree_model_get(GTK_TREE_MODEL(status_box->dropdown_store), &iter, |
|
| 1712 TYPE_COLUMN, &type, |
|
| 1713 DATA_COLUMN, &data, |
|
| 1714 -1); |
|
| 1715 if (status_box->typing != 0) |
|
| 1716 g_source_remove(status_box->typing); |
|
| 1717 status_box->typing = 0; |
|
| 1718 |
|
| 1719 if (GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(status_box))) |
|
| 1720 { |
|
| 1721 if (type == GTK_GAIM_STATUS_BOX_TYPE_POPULAR) |
|
| 1722 { |
|
| 1723 GaimSavedStatus *saved; |
|
| 1724 saved = gaim_savedstatus_find_by_creation_time(GPOINTER_TO_INT(data)); |
|
| 1725 g_return_if_fail(saved != NULL); |
|
| 1726 gaim_savedstatus_activate(saved); |
|
| 1727 return; |
|
| 1728 } |
|
| 1729 |
|
| 1730 if (type == GTK_GAIM_STATUS_BOX_TYPE_CUSTOM) |
|
| 1731 { |
|
| 1732 GaimSavedStatus *saved_status; |
|
| 1733 saved_status = gaim_savedstatus_get_current(); |
|
| 1734 gaim_gtk_status_editor_show(FALSE, |
|
| 1735 gaim_savedstatus_is_transient(saved_status) |
|
| 1736 ? saved_status : NULL); |
|
| 1737 status_menu_refresh_iter(status_box); |
|
| 1738 return; |
|
| 1739 } |
|
| 1740 |
|
| 1741 if (type == GTK_GAIM_STATUS_BOX_TYPE_SAVED) |
|
| 1742 { |
|
| 1743 gaim_gtk_status_window_show(); |
|
| 1744 status_menu_refresh_iter(status_box); |
|
| 1745 return; |
|
| 1746 } |
|
| 1747 } |
|
| 1748 |
|
| 1749 /* |
|
| 1750 * Show the message box whenever the primitive allows for a |
|
| 1751 * message attribute on any protocol that is enabled, |
|
| 1752 * or our protocol, if we have account set |
|
| 1753 */ |
|
| 1754 if (status_box->account) |
|
| 1755 accounts = g_list_prepend(accounts, status_box->account); |
|
| 1756 else |
|
| 1757 accounts = gaim_accounts_get_all_active(); |
|
| 1758 status_box->imhtml_visible = FALSE; |
|
| 1759 for (node = accounts; node != NULL; node = node->next) |
|
| 1760 { |
|
| 1761 GaimAccount *account; |
|
| 1762 GaimStatusType *status_type; |
|
| 1763 |
|
| 1764 account = node->data; |
|
| 1765 status_type = gaim_account_get_status_type_with_primitive(account, GPOINTER_TO_INT(data)); |
|
| 1766 if ((status_type != NULL) && |
|
| 1767 (gaim_status_type_get_attr(status_type, "message") != NULL)) |
|
| 1768 { |
|
| 1769 status_box->imhtml_visible = TRUE; |
|
| 1770 break; |
|
| 1771 } |
|
| 1772 } |
|
| 1773 g_list_free(accounts); |
|
| 1774 |
|
| 1775 if (GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(status_box))) |
|
| 1776 { |
|
| 1777 if (status_box->imhtml_visible) |
|
| 1778 { |
|
| 1779 gtk_widget_show_all(status_box->vbox); |
|
| 1780 if (GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(status_box))) { |
|
| 1781 status_box->typing = g_timeout_add(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, status_box); |
|
| 1782 } |
|
| 1783 gtk_widget_grab_focus(status_box->imhtml); |
|
| 1784 gtk_imhtml_clear(GTK_IMHTML(status_box->imhtml)); |
|
| 1785 } |
|
| 1786 else |
|
| 1787 { |
|
| 1788 gtk_widget_hide_all(status_box->vbox); |
|
| 1789 if (GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(status_box))) |
|
| 1790 activate_currently_selected_status(status_box); /* This is where we actually set the status */ |
|
| 1791 } |
|
| 1792 } |
|
| 1793 gtk_gaim_status_box_refresh(status_box); |
|
| 1794 } |
|
| 1795 |
|
| 1796 static gint |
|
| 1797 get_statusbox_index(GtkGaimStatusBox *box, GaimSavedStatus *saved_status) |
|
| 1798 { |
|
| 1799 gint index; |
|
| 1800 |
|
| 1801 switch (gaim_savedstatus_get_type(saved_status)) |
|
| 1802 { |
|
| 1803 case GAIM_STATUS_AVAILABLE: |
|
| 1804 index = 0; |
|
| 1805 break; |
|
| 1806 case GAIM_STATUS_AWAY: |
|
| 1807 index = 1; |
|
| 1808 break; |
|
| 1809 case GAIM_STATUS_INVISIBLE: |
|
| 1810 index = 2; |
|
| 1811 break; |
|
| 1812 case GAIM_STATUS_OFFLINE: |
|
| 1813 index = 3; |
|
| 1814 break; |
|
| 1815 default: |
|
| 1816 index = -1; |
|
| 1817 break; |
|
| 1818 } |
|
| 1819 |
|
| 1820 return index; |
|
| 1821 } |
|
| 1822 |
|
| 1823 static void imhtml_changed_cb(GtkTextBuffer *buffer, void *data) |
|
| 1824 { |
|
| 1825 GtkGaimStatusBox *status_box = (GtkGaimStatusBox*)data; |
|
| 1826 if (GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(status_box))) |
|
| 1827 { |
|
| 1828 if (status_box->typing != 0) { |
|
| 1829 gtk_gaim_status_box_pulse_typing(status_box); |
|
| 1830 g_source_remove(status_box->typing); |
|
| 1831 } |
|
| 1832 status_box->typing = g_timeout_add(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, status_box); |
|
| 1833 } |
|
| 1834 gtk_gaim_status_box_refresh(status_box); |
|
| 1835 } |
|
| 1836 |
|
| 1837 static void imhtml_format_changed_cb(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons, void *data) |
|
| 1838 { |
|
| 1839 imhtml_changed_cb(NULL, data); |
|
| 1840 } |
|
| 1841 |
|
| 1842 char *gtk_gaim_status_box_get_message(GtkGaimStatusBox *status_box) |
|
| 1843 { |
|
| 1844 if (status_box->imhtml_visible) |
|
| 1845 return gtk_imhtml_get_markup(GTK_IMHTML(status_box->imhtml)); |
|
| 1846 else |
|
| 1847 return NULL; |
|
| 1848 } |
|