1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2005-2007 Imendio AB
4 * Copyright (C) 2009 Collabora Ltd.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
21 * Authors: Richard Hult <richard@imendio.com>
22 * Martyn Russell <martyn@imendio.com>
23 * Xavier Claessens <xclaesse@gmail.com>
24 * Davyd Madeley <davyd.madeley@collabora.co.uk>
32 #include <glib/gi18n-lib.h>
34 #include <gdk/gdkkeysyms.h>
36 #include <telepathy-glib/util.h>
37 #include <libmissioncontrol/mc-enum-types.h>
39 #include <libempathy/empathy-idle.h>
40 #include <libempathy/empathy-utils.h>
41 #include <libempathy/empathy-status-presets.h>
43 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
44 #include <libempathy/empathy-debug.h>
46 #include "empathy-ui-utils.h"
47 #include "empathy-images.h"
48 #include "empathy-presence-chooser.h"
49 #include "empathy-status-preset-dialog.h"
51 /* Flashing delay for icons (milliseconds). */
52 #define FLASH_TIMEOUT 500
54 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyPresenceChooser)
56 /* For custom message dialog */
64 /* For combobox's model */
70 COL_STATUS_CUSTOMISABLE,
80 ENTRY_TYPE_EDIT_CUSTOM,
81 } PresenceChooserEntryType;
86 gboolean editing_status;
87 int block_set_editing;
89 guint focus_out_idle_source;
92 PresenceChooserEntryType previous_type;
94 McPresence flash_state_1;
95 McPresence flash_state_2;
96 guint flash_timeout_id;
97 } EmpathyPresenceChooserPriv;
99 /* States to be listed in the menu.
100 * Each state has a boolean telling if it can have custom message */
101 static guint states[] = {MC_PRESENCE_AVAILABLE, TRUE,
102 MC_PRESENCE_DO_NOT_DISTURB, TRUE,
103 MC_PRESENCE_AWAY, TRUE,
104 MC_PRESENCE_HIDDEN, FALSE,
105 MC_PRESENCE_OFFLINE, FALSE};
107 static void presence_chooser_finalize (GObject *object);
108 static void presence_chooser_presence_changed_cb (EmpathyPresenceChooser *chooser);
109 static gboolean presence_chooser_flash_timeout_cb (EmpathyPresenceChooser *chooser);
110 static void presence_chooser_flash_start (EmpathyPresenceChooser *chooser,
113 static void presence_chooser_flash_stop (EmpathyPresenceChooser *chooser,
115 static void presence_chooser_menu_add_item (GtkWidget *menu,
118 static void presence_chooser_noncustom_activate_cb (GtkWidget *item,
120 static void presence_chooser_set_state (McPresence state,
121 const gchar *status);
122 static void presence_chooser_custom_activate_cb (GtkWidget *item,
125 G_DEFINE_TYPE (EmpathyPresenceChooser, empathy_presence_chooser, GTK_TYPE_COMBO_BOX_ENTRY);
128 empathy_presence_chooser_class_init (EmpathyPresenceChooserClass *klass)
130 GObjectClass *object_class = G_OBJECT_CLASS (klass);
132 object_class->finalize = presence_chooser_finalize;
134 g_type_class_add_private (object_class, sizeof (EmpathyPresenceChooserPriv));
138 presence_chooser_create_model (EmpathyPresenceChooser *self)
141 char *custom_message;
144 store = gtk_list_store_new (N_COLUMNS,
145 G_TYPE_STRING, /* COL_STATE_ICON_NAME */
146 MC_TYPE_PRESENCE, /* COL_STATE */
147 G_TYPE_STRING, /* COL_STATUS_TEXT */
148 G_TYPE_STRING, /* COL_DISPLAY_MARKUP */
149 G_TYPE_BOOLEAN, /* COL_STATUS_CUSTOMISABLE */
150 G_TYPE_INT); /* COL_TYPE */
152 custom_message = g_strdup_printf ("<i>%s</i>", _("Custom Message..."));
154 for (i = 0; i < G_N_ELEMENTS (states); i += 2) {
156 const char *status, *icon_name;
158 status = empathy_presence_get_default_message (states[i]);
159 icon_name = empathy_icon_name_for_presence (states[i]);
161 gtk_list_store_insert_with_values (store, NULL, -1,
162 COL_STATE_ICON_NAME, icon_name,
163 COL_STATE, states[i],
164 COL_STATUS_TEXT, status,
165 COL_DISPLAY_MARKUP, status,
166 COL_STATUS_CUSTOMISABLE, states[i+1],
167 COL_TYPE, ENTRY_TYPE_BUILTIN,
172 /* Set custom messages if wanted */
173 list = empathy_status_presets_get (states[i], -1);
174 list = g_list_sort (list, (GCompareFunc) g_utf8_collate);
175 for (l = list; l; l = l->next) {
176 gtk_list_store_insert_with_values (store,
178 COL_STATE_ICON_NAME, icon_name,
179 COL_STATE, states[i],
180 COL_STATUS_TEXT, l->data,
181 COL_DISPLAY_MARKUP, l->data,
182 COL_STATUS_CUSTOMISABLE, TRUE,
183 COL_TYPE, ENTRY_TYPE_SAVED,
188 gtk_list_store_insert_with_values (store, NULL, -1,
189 COL_STATE_ICON_NAME, icon_name,
190 COL_STATE, states[i],
192 COL_DISPLAY_MARKUP, custom_message,
193 COL_STATUS_CUSTOMISABLE, TRUE,
194 COL_TYPE, ENTRY_TYPE_CUSTOM,
200 /* add a separator */
201 gtk_list_store_insert_with_values (store, NULL, -1,
202 COL_TYPE, ENTRY_TYPE_SEPARATOR,
205 gtk_list_store_insert_with_values (store, NULL, -1,
206 COL_STATE_ICON_NAME, GTK_STOCK_EDIT,
208 COL_DISPLAY_MARKUP, _("Edit Custom Messages..."),
209 COL_TYPE, ENTRY_TYPE_EDIT_CUSTOM,
212 g_free (custom_message);
214 gtk_combo_box_set_model (GTK_COMBO_BOX (self), GTK_TREE_MODEL (store));
215 g_object_unref (store);
219 presence_chooser_popup_shown_cb (GObject *self,
223 EmpathyPresenceChooserPriv *priv = GET_PRIV (self);
226 g_object_get (self, "popup-shown", &shown, NULL);
231 /* see presence_chooser_entry_focus_out_cb() for what this does */
232 if (priv->focus_out_idle_source != 0) {
233 g_source_remove (priv->focus_out_idle_source);
234 priv->focus_out_idle_source = 0;
237 presence_chooser_create_model (EMPATHY_PRESENCE_CHOOSER (self));
240 static PresenceChooserEntryType
241 presence_chooser_get_entry_type (EmpathyPresenceChooser *self)
244 PresenceChooserEntryType type = -1;
246 if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self), &iter)) {
247 type = ENTRY_TYPE_CUSTOM;
252 model = gtk_combo_box_get_model (GTK_COMBO_BOX (self));
253 gtk_tree_model_get (model, &iter,
262 presence_chooser_is_preset (EmpathyPresenceChooser *self)
264 EmpathyPresenceChooserPriv *priv = GET_PRIV (self);
268 gboolean match = FALSE;
270 state = empathy_idle_get_state (priv->idle);
271 status = empathy_idle_get_status (priv->idle);
273 presets = empathy_status_presets_get (state, -1);
274 for (l = presets; l; l = l->next) {
275 char *preset = (char *) l->data;
277 if (!strcmp (status, preset)) {
283 g_list_free (presets);
285 DEBUG ("is_preset(%i, %s) = %i\n", state, status, match);
291 presence_chooser_set_favorite_icon (EmpathyPresenceChooser *self)
294 PresenceChooserEntryType type;
296 entry = gtk_bin_get_child (GTK_BIN (self));
297 type = presence_chooser_get_entry_type (self);
299 if (type == ENTRY_TYPE_CUSTOM || type == ENTRY_TYPE_SAVED) {
300 if (presence_chooser_is_preset (self)) {
301 /* saved entries can be removed from the list */
302 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry),
303 GTK_ENTRY_ICON_SECONDARY,
305 gtk_entry_set_icon_tooltip_text (GTK_ENTRY (entry),
306 GTK_ENTRY_ICON_SECONDARY,
307 _("Click to remove this status as a favorite"));
310 /* custom entries can be favorited */
311 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry),
312 GTK_ENTRY_ICON_SECONDARY,
313 "empathy-unstarred");
314 gtk_entry_set_icon_tooltip_text (GTK_ENTRY (entry),
315 GTK_ENTRY_ICON_SECONDARY,
316 _("Click to make this status a favorite"));
320 /* built-in entries cannot be favorited */
321 gtk_entry_set_icon_from_stock (GTK_ENTRY (entry),
322 GTK_ENTRY_ICON_SECONDARY,
324 gtk_entry_set_icon_tooltip_text (GTK_ENTRY (entry),
325 GTK_ENTRY_ICON_SECONDARY,
331 presence_chooser_set_status_editing (EmpathyPresenceChooser *self,
334 EmpathyPresenceChooserPriv *priv = GET_PRIV (self);
337 if (priv->block_set_editing) {
341 entry = gtk_bin_get_child (GTK_BIN (self));
343 priv->editing_status = TRUE;
345 gtk_entry_set_icon_from_stock (GTK_ENTRY (entry),
346 GTK_ENTRY_ICON_SECONDARY,
348 gtk_entry_set_icon_tooltip_text (GTK_ENTRY (entry),
349 GTK_ENTRY_ICON_SECONDARY,
351 gtk_entry_set_icon_sensitive (GTK_ENTRY (entry),
352 GTK_ENTRY_ICON_PRIMARY,
357 presence_chooser_set_favorite_icon (self);
358 gtk_entry_set_icon_sensitive (GTK_ENTRY (entry),
359 GTK_ENTRY_ICON_PRIMARY,
362 /* attempt to get the toplevel for this widget */
363 window = gtk_widget_get_toplevel (GTK_WIDGET (self));
364 if (GTK_WIDGET_TOPLEVEL (window) && GTK_IS_WINDOW (window)) {
365 /* unset the focus */
366 gtk_window_set_focus (GTK_WINDOW (window), NULL);
369 /* see presence_chooser_entry_focus_out_cb()
370 * for what this does */
371 if (priv->focus_out_idle_source != 0) {
372 g_source_remove (priv->focus_out_idle_source);
373 priv->focus_out_idle_source = 0;
376 gtk_editable_set_position (GTK_EDITABLE (entry), 0);
378 priv->editing_status = FALSE;
383 mc_set_custom_state (EmpathyPresenceChooser *self)
385 EmpathyPresenceChooserPriv *priv = GET_PRIV (self);
389 entry = gtk_bin_get_child (GTK_BIN (self));
390 /* update the status with MC */
391 status = gtk_entry_get_text (GTK_ENTRY (entry));
393 DEBUG ("Sending state to MC-> %s (%s)\n",
394 g_enum_get_value (g_type_class_peek (MC_TYPE_PRESENCE),
395 priv->state)->value_name,
398 empathy_idle_set_presence (priv->idle, priv->state, status);
402 ui_set_custom_state (EmpathyPresenceChooser *self,
406 EmpathyPresenceChooserPriv *priv = GET_PRIV (self);
408 const char *icon_name;
410 entry = gtk_bin_get_child (GTK_BIN (self));
412 priv->block_set_editing++;
413 priv->block_changed++;
415 icon_name = empathy_icon_name_for_presence (state);
416 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry),
417 GTK_ENTRY_ICON_PRIMARY,
419 gtk_entry_set_text (GTK_ENTRY (entry), status);
420 presence_chooser_set_favorite_icon (self);
422 priv->block_changed--;
423 priv->block_set_editing--;
427 presence_chooser_reset_status (EmpathyPresenceChooser *self)
429 /* recover the status that was unset */
430 presence_chooser_set_status_editing (self, FALSE);
431 presence_chooser_presence_changed_cb (self);
435 presence_chooser_entry_icon_release_cb (EmpathyPresenceChooser *self,
436 GtkEntryIconPosition icon_pos,
440 EmpathyPresenceChooserPriv *priv = GET_PRIV (self);
442 if (priv->editing_status) {
443 presence_chooser_set_status_editing (self, FALSE);
444 mc_set_custom_state (self);
447 PresenceChooserEntryType type;
451 type = presence_chooser_get_entry_type (self);
452 state = empathy_idle_get_state (priv->idle);
453 status = empathy_idle_get_status (priv->idle);
455 if (presence_chooser_is_preset (self)) {
456 /* remove the entry */
457 DEBUG ("REMOVING PRESET (%i, %s)\n", state, status);
458 empathy_status_presets_remove (state, status);
462 DEBUG ("SAVING PRESET (%i, %s)\n", state, status);
463 empathy_status_presets_set_last (state, status);
466 /* update the icon */
467 presence_chooser_set_favorite_icon (self);
472 presence_chooser_entry_activate_cb (EmpathyPresenceChooser *self,
475 presence_chooser_set_status_editing (self, FALSE);
476 mc_set_custom_state (self);
480 presence_chooser_entry_key_press_event_cb (EmpathyPresenceChooser *self,
484 EmpathyPresenceChooserPriv *priv = GET_PRIV (self);
486 if (priv->editing_status && event->keyval == GDK_Escape) {
487 /* the user pressed Escape, undo the editing */
488 presence_chooser_reset_status (self);
491 else if (event->keyval == GDK_Up || event->keyval == GDK_Down) {
496 return FALSE; /* send this event elsewhere */
500 presence_chooser_entry_button_press_event_cb (EmpathyPresenceChooser *self,
501 GdkEventButton *event,
504 EmpathyPresenceChooserPriv *priv = GET_PRIV (self);
506 if (!priv->editing_status &&
507 event->button == 1 &&
508 !GTK_WIDGET_HAS_FOCUS (entry)) {
509 gtk_widget_grab_focus (entry);
510 gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
519 presence_chooser_entry_changed_cb (EmpathyPresenceChooser *self,
522 EmpathyPresenceChooserPriv *priv = GET_PRIV (self);
524 if (priv->block_changed){
528 /* the combo is being edited to a custom entry */
529 if (!priv->editing_status) {
530 presence_chooser_set_status_editing (self, TRUE);
535 presence_chooser_changed_cb (GtkComboBox *self, gpointer user_data)
537 EmpathyPresenceChooserPriv *priv = GET_PRIV (self);
540 McPresence new_state;
541 gboolean customisable = TRUE;
542 PresenceChooserEntryType type = -1;
546 if (priv->block_changed ||
547 !gtk_combo_box_get_active_iter (self, &iter)) {
551 model = gtk_combo_box_get_model (self);
552 gtk_tree_model_get (model, &iter,
553 COL_STATE_ICON_NAME, &icon_name,
554 COL_STATE, &new_state,
555 COL_STATUS_CUSTOMISABLE, &customisable,
559 entry = gtk_bin_get_child (GTK_BIN (self));
561 /* some types of status aren't editable, set the editability of the
562 * entry appropriately. Unless we're just about to reset it anyway,
563 * in which case, don't fiddle with it */
564 if (type != ENTRY_TYPE_EDIT_CUSTOM) {
565 gtk_editable_set_editable (GTK_EDITABLE (entry), customisable);
566 priv->state = new_state;
569 if (type == ENTRY_TYPE_EDIT_CUSTOM) {
570 GtkWidget *window, *dialog;
572 presence_chooser_reset_status (EMPATHY_PRESENCE_CHOOSER (self));
574 /* attempt to get the toplevel for this widget */
575 window = gtk_widget_get_toplevel (GTK_WIDGET (self));
576 if (!GTK_WIDGET_TOPLEVEL (window) || !GTK_IS_WINDOW (window)) {
580 dialog = empathy_status_preset_dialog_new (GTK_WINDOW (window));
581 gtk_dialog_run (GTK_DIALOG (dialog));
582 gtk_widget_destroy (dialog);
584 else if (type == ENTRY_TYPE_CUSTOM) {
585 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry),
586 GTK_ENTRY_ICON_PRIMARY,
589 /* preseed the status */
590 if (priv->previous_type == ENTRY_TYPE_BUILTIN) {
591 /* if their previous entry was a builtin, don't
593 gtk_entry_set_text (GTK_ENTRY (entry), "");
595 /* else preseed the text of their currently entered
599 status = empathy_idle_get_status (priv->idle);
600 gtk_entry_set_text (GTK_ENTRY (entry), status);
604 gtk_widget_grab_focus (entry);
608 /* just in case we were setting a new status when
609 * things were changed */
610 presence_chooser_set_status_editing (
611 EMPATHY_PRESENCE_CHOOSER (self),
614 gtk_tree_model_get (model, &iter,
615 COL_STATUS_TEXT, &status,
618 empathy_idle_set_presence (priv->idle, priv->state, status);
623 if (type != ENTRY_TYPE_EDIT_CUSTOM) {
624 priv->previous_type = type;
630 combo_row_separator_func (GtkTreeModel *model,
634 PresenceChooserEntryType type;
636 gtk_tree_model_get (model, iter,
640 return (type == ENTRY_TYPE_SEPARATOR);
644 presence_chooser_entry_focus_out_idle_cb (gpointer user_data)
646 EmpathyPresenceChooser *chooser;
649 DEBUG ("Autocommiting status message\n");
651 chooser = EMPATHY_PRESENCE_CHOOSER (user_data);
652 entry = gtk_bin_get_child (GTK_BIN (chooser));
654 presence_chooser_entry_activate_cb (chooser, GTK_ENTRY (entry));
660 presence_chooser_entry_focus_out_cb (EmpathyPresenceChooser *chooser,
661 GdkEventFocus *event,
664 EmpathyPresenceChooserPriv *priv = GET_PRIV (chooser);
666 if (priv->editing_status) {
667 /* this seems a bit evil and maybe it will be fragile,
668 * someone should think of a better way to do it.
670 * The entry has focused out, but we don't know where the focus
671 * has gone. If it goes to the combo box, we don't want to
672 * do anything. If it's gone anywhere else, we want to commit
675 * Thus we install this idle handler and store its source.
676 * If the source is scheduled when the popup handler runs,
677 * it will remove it, else the callback will commit the result.
679 priv->focus_out_idle_source = g_idle_add (
680 presence_chooser_entry_focus_out_idle_cb,
684 gtk_editable_set_position (GTK_EDITABLE (entry), 0);
690 empathy_presence_chooser_init (EmpathyPresenceChooser *chooser)
692 EmpathyPresenceChooserPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (chooser,
693 EMPATHY_TYPE_PRESENCE_CHOOSER, EmpathyPresenceChooserPriv);
695 GtkCellRenderer *renderer;
697 chooser->priv = priv;
699 presence_chooser_create_model (chooser);
701 gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (chooser),
703 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser),
704 combo_row_separator_func,
707 entry = gtk_bin_get_child (GTK_BIN (chooser));
708 gtk_entry_set_icon_activatable (GTK_ENTRY (entry),
709 GTK_ENTRY_ICON_PRIMARY,
712 g_signal_connect_swapped (entry, "icon-release",
713 G_CALLBACK (presence_chooser_entry_icon_release_cb),
715 g_signal_connect_swapped (entry, "activate",
716 G_CALLBACK (presence_chooser_entry_activate_cb),
718 g_signal_connect_swapped (entry, "key-press-event",
719 G_CALLBACK (presence_chooser_entry_key_press_event_cb),
721 g_signal_connect_swapped (entry, "button-press-event",
722 G_CALLBACK (presence_chooser_entry_button_press_event_cb),
725 gtk_cell_layout_clear (GTK_CELL_LAYOUT (chooser));
727 renderer = gtk_cell_renderer_pixbuf_new ();
728 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (chooser), renderer, FALSE);
729 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (chooser), renderer,
730 "icon-name", COL_STATE_ICON_NAME,
732 g_object_set (renderer, "stock-size", GTK_ICON_SIZE_MENU, NULL);
734 renderer = gtk_cell_renderer_text_new ();
735 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (chooser), renderer, TRUE);
736 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (chooser), renderer,
737 "markup", COL_DISPLAY_MARKUP,
740 g_signal_connect (chooser, "notify::popup-shown",
741 G_CALLBACK (presence_chooser_popup_shown_cb), NULL);
742 g_signal_connect (chooser, "changed",
743 G_CALLBACK (presence_chooser_changed_cb), NULL);
744 g_signal_connect_swapped (entry, "changed",
745 G_CALLBACK (presence_chooser_entry_changed_cb),
747 g_signal_connect_swapped (entry, "focus-out-event",
748 G_CALLBACK (presence_chooser_entry_focus_out_cb),
751 priv->idle = empathy_idle_dup_singleton ();
752 presence_chooser_presence_changed_cb (chooser);
753 g_signal_connect_swapped (priv->idle, "notify",
754 G_CALLBACK (presence_chooser_presence_changed_cb),
757 /* FIXME: this string sucks */
758 gtk_widget_set_tooltip_text (GTK_WIDGET (chooser),
759 _("Set your presence and current status"));
763 presence_chooser_finalize (GObject *object)
765 EmpathyPresenceChooserPriv *priv;
767 priv = GET_PRIV (object);
769 if (priv->flash_timeout_id) {
770 g_source_remove (priv->flash_timeout_id);
773 if (priv->focus_out_idle_source) {
774 g_source_remove (priv->focus_out_idle_source);
777 g_signal_handlers_disconnect_by_func (priv->idle,
778 presence_chooser_presence_changed_cb,
780 g_object_unref (priv->idle);
782 G_OBJECT_CLASS (empathy_presence_chooser_parent_class)->finalize (object);
786 empathy_presence_chooser_new (void)
790 chooser = g_object_new (EMPATHY_TYPE_PRESENCE_CHOOSER, NULL);
796 presence_chooser_presence_changed_cb (EmpathyPresenceChooser *chooser)
798 EmpathyPresenceChooserPriv *priv;
800 McPresence flash_state;
804 gboolean valid, match_state = FALSE, match = FALSE;
806 priv = GET_PRIV (chooser);
808 if (priv->editing_status) {
812 priv->state = state = empathy_idle_get_state (priv->idle);
813 status = empathy_idle_get_status (priv->idle);
814 flash_state = empathy_idle_get_flash_state (priv->idle);
816 /* look through the model and attempt to find a matching state */
817 model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser));
818 for (valid = gtk_tree_model_get_iter_first (model, &iter);
820 valid = gtk_tree_model_iter_next (model, &iter)) {
825 gtk_tree_model_get (model, &iter,
830 if (m_type == ENTRY_TYPE_CUSTOM ||
831 m_type == ENTRY_TYPE_SEPARATOR ||
832 m_type == ENTRY_TYPE_EDIT_CUSTOM) {
835 else if (!match_state && state == m_state) {
836 /* we are now in the section that can contain our
840 else if (match_state && state != m_state) {
841 /* we have passed the section that can contain our
846 gtk_tree_model_get (model, &iter,
847 COL_STATUS_TEXT, &m_status,
850 match = !strcmp (status, m_status);
859 priv->block_changed++;
860 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (chooser), &iter);
861 presence_chooser_set_favorite_icon (chooser);
862 priv->block_changed--;
865 ui_set_custom_state (chooser, state, status);
868 if (flash_state != MC_PRESENCE_UNSET) {
869 presence_chooser_flash_start (chooser, state, flash_state);
872 presence_chooser_flash_stop (chooser, state);
877 presence_chooser_flash_timeout_cb (EmpathyPresenceChooser *chooser)
879 EmpathyPresenceChooserPriv *priv;
881 static gboolean on = FALSE;
884 priv = GET_PRIV (chooser);
887 state = priv->flash_state_1;
890 state = priv->flash_state_2;
893 entry = gtk_bin_get_child (GTK_BIN (chooser));
894 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry),
895 GTK_ENTRY_ICON_PRIMARY,
896 empathy_icon_name_for_presence (state));
904 presence_chooser_flash_start (EmpathyPresenceChooser *chooser,
908 EmpathyPresenceChooserPriv *priv;
910 g_return_if_fail (EMPATHY_IS_PRESENCE_CHOOSER (chooser));
912 priv = GET_PRIV (chooser);
914 priv->flash_state_1 = state_1;
915 priv->flash_state_2 = state_2;
917 if (!priv->flash_timeout_id) {
918 priv->flash_timeout_id = g_timeout_add (FLASH_TIMEOUT,
919 (GSourceFunc) presence_chooser_flash_timeout_cb,
925 presence_chooser_flash_stop (EmpathyPresenceChooser *chooser,
928 EmpathyPresenceChooserPriv *priv = GET_PRIV (chooser);
931 if (priv->flash_timeout_id) {
932 g_source_remove (priv->flash_timeout_id);
933 priv->flash_timeout_id = 0;
936 entry = gtk_bin_get_child (GTK_BIN (chooser));
937 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry),
938 GTK_ENTRY_ICON_PRIMARY,
939 empathy_icon_name_for_presence (state));
943 empathy_presence_chooser_create_menu (void)
951 menu = gtk_menu_new ();
953 for (i = 0; i < G_N_ELEMENTS (states); i += 2) {
956 status = empathy_presence_get_default_message (states[i]);
957 presence_chooser_menu_add_item (menu,
962 /* Set custom messages if wanted */
963 list = empathy_status_presets_get (states[i], 5);
964 for (l = list; l; l = l->next) {
965 presence_chooser_menu_add_item (menu,
975 item = gtk_menu_item_new ();
976 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
977 gtk_widget_show (item);
979 /* Custom messages */
980 item = gtk_image_menu_item_new_with_label (_("Custom messages..."));
981 image = gtk_image_new_from_stock (GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
982 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
983 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
984 gtk_widget_show (image);
985 gtk_widget_show (item);
987 g_signal_connect (item,
989 G_CALLBACK (presence_chooser_custom_activate_cb),
996 presence_chooser_menu_add_item (GtkWidget *menu,
1002 const gchar *icon_name;
1004 item = gtk_image_menu_item_new_with_label (str);
1005 icon_name = empathy_icon_name_for_presence (state);
1007 g_signal_connect (item, "activate",
1008 G_CALLBACK (presence_chooser_noncustom_activate_cb),
1011 image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
1012 gtk_widget_show (image);
1014 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
1015 gtk_widget_show (item);
1017 g_object_set_data_full (G_OBJECT (item),
1018 "status", g_strdup (str),
1019 (GDestroyNotify) g_free);
1021 g_object_set_data (G_OBJECT (item), "state", GINT_TO_POINTER (state));
1023 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1027 presence_chooser_noncustom_activate_cb (GtkWidget *item,
1031 const gchar *status;
1033 status = g_object_get_data (G_OBJECT (item), "status");
1034 state = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "state"));
1036 presence_chooser_set_state (state, status);
1040 presence_chooser_set_state (McPresence state,
1041 const gchar *status)
1045 idle = empathy_idle_dup_singleton ();
1046 empathy_idle_set_presence (idle, state, status);
1047 g_object_unref (idle);
1051 presence_chooser_custom_activate_cb (GtkWidget *item,
1056 dialog = empathy_status_preset_dialog_new (NULL);
1057 gtk_dialog_run (GTK_DIALOG (dialog));
1058 gtk_widget_destroy (dialog);