pidgin/gtkstatusbox.c

changeset 18545
5af898e91ec2
parent 18318
146d6831fc3d
child 18319
e5f4aef72165
equal deleted inserted replaced
17398:1edf059a4a26 18545:5af898e91ec2
39 * and the "New..." and "Saved..." options. 39 * and the "New..." and "Saved..." options.
40 */ 40 */
41 41
42 #include <gdk/gdkkeysyms.h> 42 #include <gdk/gdkkeysyms.h>
43 43
44 #include "internal.h"
45
44 #include "account.h" 46 #include "account.h"
45 #include "buddyicon.h" 47 #include "buddyicon.h"
46 #include "core.h" 48 #include "core.h"
47 #include "internal.h"
48 #include "imgstore.h" 49 #include "imgstore.h"
49 #include "network.h" 50 #include "network.h"
51 #include "request.h"
50 #include "savedstatuses.h" 52 #include "savedstatuses.h"
51 #include "status.h" 53 #include "status.h"
52 #include "debug.h" 54 #include "debug.h"
53 55
54 #include "pidgin.h" 56 #include "pidgin.h"
189 } 191 }
190 192
191 static void 193 static void
192 update_to_reflect_account_status(PidginStatusBox *status_box, PurpleAccount *account, PurpleStatus *newstatus) 194 update_to_reflect_account_status(PidginStatusBox *status_box, PurpleAccount *account, PurpleStatus *newstatus)
193 { 195 {
194 const GList *l; 196 GList *l;
195 int status_no = -1; 197 int status_no = -1;
196 const PurpleStatusType *statustype = NULL; 198 const PurpleStatusType *statustype = NULL;
197 const char *message; 199 const char *message;
198 200
199 statustype = purple_status_type_find_with_id((GList *)purple_account_get_status_types(account), 201 statustype = purple_status_type_find_with_id((GList *)purple_account_get_status_types(account),
730 } 732 }
731 733
732 static PurpleStatusType * 734 static PurpleStatusType *
733 find_status_type_by_index(const PurpleAccount *account, gint active) 735 find_status_type_by_index(const PurpleAccount *account, gint active)
734 { 736 {
735 const GList *l = purple_account_get_status_types(account); 737 GList *l = purple_account_get_status_types(account);
736 gint i; 738 gint i;
737 739
738 for (i = 0; l; l = l->next) { 740 for (i = 0; l; l = l->next) {
739 PurpleStatusType *status_type = l->data; 741 PurpleStatusType *status_type = l->data;
740 if (!purple_status_type_is_user_settable(status_type)) 742 if (!purple_status_type_is_user_settable(status_type))
939 * statuses and a token account if they do */ 941 * statuses and a token account if they do */
940 static PurpleAccount* check_active_accounts_for_identical_statuses() 942 static PurpleAccount* check_active_accounts_for_identical_statuses()
941 { 943 {
942 PurpleAccount *acct = NULL, *acct2; 944 PurpleAccount *acct = NULL, *acct2;
943 GList *tmp, *tmp2, *active_accts = purple_accounts_get_all_active(); 945 GList *tmp, *tmp2, *active_accts = purple_accounts_get_all_active();
944 const GList *s, *s1, *s2; 946 GList *s, *s1, *s2;
945 947
946 for (tmp = active_accts; tmp; tmp = tmp->next) { 948 for (tmp = active_accts; tmp; tmp = tmp->next) {
947 acct = tmp->data; 949 acct = tmp->data;
948 s = purple_account_get_status_types(acct); 950 s = purple_account_get_status_types(acct);
949 for (tmp2 = tmp->next; tmp2; tmp2 = tmp2->next) { 951 for (tmp2 = tmp->next; tmp2; tmp2 = tmp2->next) {
987 989
988 static void 990 static void
989 add_account_statuses(PidginStatusBox *status_box, PurpleAccount *account) 991 add_account_statuses(PidginStatusBox *status_box, PurpleAccount *account)
990 { 992 {
991 /* Per-account */ 993 /* Per-account */
992 const GList *l; 994 GList *l;
993 GdkPixbuf *pixbuf; 995 GdkPixbuf *pixbuf;
994 996
995 for (l = purple_account_get_status_types(account); l != NULL; l = l->next) 997 for (l = purple_account_get_status_types(account); l != NULL; l = l->next)
996 { 998 {
997 PurpleStatusType *status_type = (PurpleStatusType *)l->data; 999 PurpleStatusType *status_type = (PurpleStatusType *)l->data;
1012 if (pixbuf != NULL) 1014 if (pixbuf != NULL)
1013 g_object_unref(pixbuf); 1015 g_object_unref(pixbuf);
1014 } 1016 }
1015 } 1017 }
1016 1018
1017 static void 1019 static gboolean
1018 pidgin_status_box_regenerate(PidginStatusBox *status_box) 1020 pidgin_status_box_regenerate_real(PidginStatusBox *status_box)
1019 { 1021 {
1020 GdkPixbuf *pixbuf, *pixbuf2, *pixbuf3, *pixbuf4; 1022 GdkPixbuf *pixbuf, *pixbuf2, *pixbuf3, *pixbuf4, *pixbuf5;
1021 GtkIconSize icon_size; 1023 GtkIconSize icon_size;
1022 1024
1023 icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL); 1025 icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL);
1024 1026
1025 /* Unset the model while clearing it */ 1027 /* Unset the model while clearing it */
1045 icon_size, "PidginStatusBox"); 1047 icon_size, "PidginStatusBox");
1046 pixbuf3 = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), PIDGIN_STOCK_STATUS_OFFLINE, 1048 pixbuf3 = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), PIDGIN_STOCK_STATUS_OFFLINE,
1047 icon_size, "PidginStatusBox"); 1049 icon_size, "PidginStatusBox");
1048 pixbuf4 = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), PIDGIN_STOCK_STATUS_INVISIBLE, 1050 pixbuf4 = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), PIDGIN_STOCK_STATUS_INVISIBLE,
1049 icon_size, "PidginStatusBox"); 1051 icon_size, "PidginStatusBox");
1052 pixbuf5 = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), PIDGIN_STOCK_STATUS_BUSY,
1053 icon_size, "PidginStatusBox");
1050 1054
1051 pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf, _("Available"), NULL, GINT_TO_POINTER(PURPLE_STATUS_AVAILABLE)); 1055 pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf, _("Available"), NULL, GINT_TO_POINTER(PURPLE_STATUS_AVAILABLE));
1052 pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf2, _("Away"), NULL, GINT_TO_POINTER(PURPLE_STATUS_AWAY)); 1056 pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf2, _("Away"), NULL, GINT_TO_POINTER(PURPLE_STATUS_AWAY));
1057 pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf5, _("Do not disturb"), NULL, GINT_TO_POINTER(PURPLE_STATUS_UNAVAILABLE));
1053 pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf4, _("Invisible"), NULL, GINT_TO_POINTER(PURPLE_STATUS_INVISIBLE)); 1058 pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf4, _("Invisible"), NULL, GINT_TO_POINTER(PURPLE_STATUS_INVISIBLE));
1054 pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf3, _("Offline"), NULL, GINT_TO_POINTER(PURPLE_STATUS_OFFLINE)); 1059 pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf3, _("Offline"), NULL, GINT_TO_POINTER(PURPLE_STATUS_OFFLINE));
1055 1060
1056 if (pixbuf2) g_object_unref(G_OBJECT(pixbuf2)); 1061 if (pixbuf2) g_object_unref(G_OBJECT(pixbuf2));
1057 if (pixbuf3) g_object_unref(G_OBJECT(pixbuf3)); 1062 if (pixbuf3) g_object_unref(G_OBJECT(pixbuf3));
1058 if (pixbuf4) g_object_unref(G_OBJECT(pixbuf4)); 1063 if (pixbuf4) g_object_unref(G_OBJECT(pixbuf4));
1064 if (pixbuf5) g_object_unref(G_OBJECT(pixbuf5));
1059 } 1065 }
1060 1066
1061 add_popular_statuses(status_box); 1067 add_popular_statuses(status_box);
1062 1068
1063 pidgin_status_box_add_separator(PIDGIN_STATUS_BOX(status_box)); 1069 pidgin_status_box_add_separator(PIDGIN_STATUS_BOX(status_box));
1073 update_to_reflect_account_status(status_box, status_box->account, 1079 update_to_reflect_account_status(status_box, status_box->account,
1074 purple_account_get_active_status(status_box->account)); 1080 purple_account_get_active_status(status_box->account));
1075 } 1081 }
1076 gtk_tree_view_set_model(GTK_TREE_VIEW(status_box->tree_view), GTK_TREE_MODEL(status_box->dropdown_store)); 1082 gtk_tree_view_set_model(GTK_TREE_VIEW(status_box->tree_view), GTK_TREE_MODEL(status_box->dropdown_store));
1077 gtk_tree_view_set_search_column(GTK_TREE_VIEW(status_box->tree_view), TEXT_COLUMN); 1083 gtk_tree_view_set_search_column(GTK_TREE_VIEW(status_box->tree_view), TEXT_COLUMN);
1084
1085 return FALSE;
1086 }
1087
1088 static void
1089 pidgin_status_box_regenerate(PidginStatusBox *status_box)
1090 {
1091 /* we have to do this in a timeout, so we avoid recursing
1092 * to infinity (and beyond) */
1093 purple_timeout_add(0, (GSourceFunc)pidgin_status_box_regenerate_real, status_box);
1078 } 1094 }
1079 1095
1080 static gboolean combo_box_scroll_event_cb(GtkWidget *w, GdkEventScroll *event, GtkIMHtml *imhtml) 1096 static gboolean combo_box_scroll_event_cb(GtkWidget *w, GdkEventScroll *event, GtkIMHtml *imhtml)
1081 { 1097 {
1082 pidgin_status_box_popup(PIDGIN_STATUS_BOX(w)); 1098 pidgin_status_box_popup(PIDGIN_STATUS_BOX(w));
1083 return TRUE; 1099 return TRUE;
1084 } 1100 }
1085 1101
1086 static gboolean imhtml_scroll_event_cb(GtkWidget *w, GdkEventScroll *event, GtkIMHtml *imhtml) 1102 static gboolean imhtml_scroll_event_cb(GtkWidget *w, GdkEventScroll *event, GtkIMHtml *imhtml)
1087 { 1103 {
1221 /* Make sure our current status is added to the list of popular statuses */ 1237 /* Make sure our current status is added to the list of popular statuses */
1222 pidgin_status_box_regenerate(status_box); 1238 pidgin_status_box_regenerate(status_box);
1223 } 1239 }
1224 1240
1225 static void 1241 static void
1242 saved_status_updated_cb(PurpleSavedStatus *status, PidginStatusBox *status_box)
1243 {
1244 pidgin_status_box_regenerate(status_box);
1245 }
1246
1247 static void
1226 spellcheck_prefs_cb(const char *name, PurplePrefType type, 1248 spellcheck_prefs_cb(const char *name, PurplePrefType type,
1227 gconstpointer value, gpointer data) 1249 gconstpointer value, gpointer data)
1228 { 1250 {
1229 #ifdef USE_GTKSPELL 1251 #ifdef USE_GTKSPELL
1230 PidginStatusBox *status_box = (PidginStatusBox *)data; 1252 PidginStatusBox *status_box = (PidginStatusBox *)data;
1512 status_box->active_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(status_box->dropdown_store), path); 1534 status_box->active_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(status_box->dropdown_store), path);
1513 pidgin_status_box_popdown (status_box); 1535 pidgin_status_box_popdown (status_box);
1514 pidgin_status_box_changed(status_box); 1536 pidgin_status_box_changed(status_box);
1515 } 1537 }
1516 1538
1539 static void tree_view_delete_current_selection_cb(gpointer data)
1540 {
1541 PurpleSavedStatus *saved;
1542
1543 saved = purple_savedstatus_find_by_creation_time(GPOINTER_TO_INT(data));
1544 g_return_if_fail(saved != NULL);
1545
1546 if (purple_savedstatus_get_current() != saved)
1547 purple_savedstatus_delete_by_status(saved);
1548 }
1549
1550 static void
1551 tree_view_delete_current_selection(PidginStatusBox *status_box, GtkTreePath *path)
1552 {
1553 GtkTreeIter iter;
1554 gpointer data;
1555 PurpleSavedStatus *saved;
1556 gchar *msg;
1557
1558 if (status_box->active_row) {
1559 /* don't delete active status */
1560 if (gtk_tree_path_compare(path, gtk_tree_row_reference_get_path(status_box->active_row)) == 0)
1561 return;
1562 }
1563
1564 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL(status_box->dropdown_store), &iter, path))
1565 return;
1566
1567 gtk_tree_model_get(GTK_TREE_MODEL(status_box->dropdown_store), &iter,
1568 DATA_COLUMN, &data,
1569 -1);
1570
1571 saved = purple_savedstatus_find_by_creation_time(GPOINTER_TO_INT(data));
1572 g_return_if_fail(saved != NULL);
1573 if (saved == purple_savedstatus_get_current())
1574 return;
1575
1576 msg = g_strdup_printf(_("Are you sure you want to delete %s?"), purple_savedstatus_get_title(saved));
1577
1578 purple_request_action(saved, NULL, msg, NULL, 0,
1579 NULL, NULL, NULL,
1580 data, 2,
1581 _("Delete"), tree_view_delete_current_selection_cb,
1582 _("Cancel"), NULL);
1583
1584 g_free(msg);
1585
1586 pidgin_status_box_popdown(status_box);
1587 }
1588
1517 static gboolean 1589 static gboolean
1518 treeview_button_release_cb(GtkWidget *widget, GdkEventButton *event, PidginStatusBox *status_box) 1590 treeview_button_release_cb(GtkWidget *widget, GdkEventButton *event, PidginStatusBox *status_box)
1519 { 1591 {
1520 GtkTreePath *path = NULL; 1592 GtkTreePath *path = NULL;
1521 int ret; 1593 int ret;
1559 { 1631 {
1560 if (box->popup_in_progress) { 1632 if (box->popup_in_progress) {
1561 if (event->keyval == GDK_Escape) { 1633 if (event->keyval == GDK_Escape) {
1562 pidgin_status_box_popdown(box); 1634 pidgin_status_box_popdown(box);
1563 return TRUE; 1635 return TRUE;
1564 } else if (event->keyval == GDK_Return) { 1636 } else {
1565 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(box->tree_view)); 1637 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(box->tree_view));
1566 GtkTreeIter iter; 1638 GtkTreeIter iter;
1567 GtkTreePath *path; 1639 GtkTreePath *path;
1568 1640
1569 if (gtk_tree_selection_get_selected(sel, NULL, &iter)) { 1641 if (gtk_tree_selection_get_selected(sel, NULL, &iter)) {
1642 gboolean ret = TRUE;
1570 path = gtk_tree_model_get_path(GTK_TREE_MODEL(box->dropdown_store), &iter); 1643 path = gtk_tree_model_get_path(GTK_TREE_MODEL(box->dropdown_store), &iter);
1571 treeview_activate_current_selection(box, path); 1644 if (event->keyval == GDK_Return) {
1645 treeview_activate_current_selection(box, path);
1646 } else if (event->keyval == GDK_Delete) {
1647 tree_view_delete_current_selection(box, path);
1648 } else
1649 ret = FALSE;
1650
1572 gtk_tree_path_free (path); 1651 gtk_tree_path_free (path);
1573 return TRUE; 1652 return ret;
1574 } 1653 }
1575 } 1654 }
1576 } 1655 }
1577 return FALSE; 1656 return FALSE;
1578 } 1657 }
1579 1658
1580 static void 1659 static void
1740 1819
1741 purple_signal_connect(purple_savedstatuses_get_handle(), "savedstatus-changed", 1820 purple_signal_connect(purple_savedstatuses_get_handle(), "savedstatus-changed",
1742 status_box, 1821 status_box,
1743 PURPLE_CALLBACK(current_savedstatus_changed_cb), 1822 PURPLE_CALLBACK(current_savedstatus_changed_cb),
1744 status_box); 1823 status_box);
1824 purple_signal_connect(purple_savedstatuses_get_handle(),
1825 "savedstatus-added", status_box,
1826 PURPLE_CALLBACK(saved_status_updated_cb), status_box);
1827 purple_signal_connect(purple_savedstatuses_get_handle(),
1828 "savedstatus-deleted", status_box,
1829 PURPLE_CALLBACK(saved_status_updated_cb), status_box);
1830 purple_signal_connect(purple_savedstatuses_get_handle(),
1831 "savedstatus-modified", status_box,
1832 PURPLE_CALLBACK(saved_status_updated_cb), status_box);
1745 purple_signal_connect(purple_accounts_get_handle(), "account-enabled", status_box, 1833 purple_signal_connect(purple_accounts_get_handle(), "account-enabled", status_box,
1746 PURPLE_CALLBACK(account_enabled_cb), 1834 PURPLE_CALLBACK(account_enabled_cb),
1747 status_box); 1835 status_box);
1748 purple_signal_connect(purple_accounts_get_handle(), "account-disabled", status_box, 1836 purple_signal_connect(purple_accounts_get_handle(), "account-disabled", status_box,
1749 PURPLE_CALLBACK(account_enabled_cb), 1837 PURPLE_CALLBACK(account_enabled_cb),
2027 { 2115 {
2028 #if GTK_CHECK_VERSION(2,2,0) 2116 #if GTK_CHECK_VERSION(2,2,0)
2029 int w, h; 2117 int w, h;
2030 GtkIconSize icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_MEDIUM); 2118 GtkIconSize icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_MEDIUM);
2031 gtk_icon_size_lookup(icon_size, &w, &h); 2119 gtk_icon_size_lookup(icon_size, &w, &h);
2120 if (height > width)
2121 w = width * h / height;
2122 else if (width > height)
2123 h = height * w / width;
2032 gdk_pixbuf_loader_set_size(loader, w, h); 2124 gdk_pixbuf_loader_set_size(loader, w, h);
2033 #endif 2125 #endif
2034 } 2126 }
2035 2127
2036 static void 2128 static void
2217 2309
2218 if (changed) 2310 if (changed)
2219 { 2311 {
2220 /* Manually find the appropriate transient acct */ 2312 /* Manually find the appropriate transient acct */
2221 if (status_box->token_status_account) { 2313 if (status_box->token_status_account) {
2222 const GList *iter = purple_savedstatuses_get_all(); 2314 GList *iter = purple_savedstatuses_get_all();
2223 GList *tmp, *active_accts = purple_accounts_get_all_active(); 2315 GList *tmp, *active_accts = purple_accounts_get_all_active();
2224 2316
2225 for (; iter != NULL; iter = iter->next) { 2317 for (; iter != NULL; iter = iter->next) {
2226 PurpleSavedStatus *ss = iter->data; 2318 PurpleSavedStatus *ss = iter->data;
2227 const char *ss_msg = purple_savedstatus_get_message(ss); 2319 const char *ss_msg = purple_savedstatus_get_message(ss);

mercurial