| 18 * along with this program; if not, write to the Free Software |
20 * along with this program; if not, write to the Free Software |
| 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA |
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA |
| 20 */ |
22 */ |
| 21 #include <gtk/gtk.h> |
23 #include <gtk/gtk.h> |
| 22 |
24 |
| 23 #include "gtkutils.h" |
|
| 24 #include "pidginaccountchooser.h" |
25 #include "pidginaccountchooser.h" |
| 25 |
26 |
| 26 /****************************************************************************** |
27 #include "pidginaccountstore.h" |
| 27 * Enums |
|
| 28 *****************************************************************************/ |
|
| 29 |
28 |
| 30 enum |
29 struct _PidginAccountChooser { |
| 31 { |
30 GtkComboBox parent; |
| 32 AOP_ICON_COLUMN, |
31 |
| 33 AOP_NAME_COLUMN, |
32 PurpleFilterAccountFunc filter_func; |
| 34 AOP_DATA_COLUMN, |
|
| 35 AOP_COLUMN_COUNT |
|
| 36 }; |
33 }; |
| 37 |
34 |
| 38 enum |
35 enum |
| 39 { |
36 { |
| 40 PROP_0, |
37 PROP_0, |
| 41 PROP_ACCOUNT, |
38 PROP_ACCOUNT, |
| 42 PROP_SHOW_ALL, |
|
| 43 PROP_LAST |
39 PROP_LAST |
| 44 }; |
40 }; |
| 45 |
41 |
| 46 /****************************************************************************** |
42 static GParamSpec *properties[PROP_LAST] = {NULL}; |
| 47 * Structs |
|
| 48 *****************************************************************************/ |
|
| 49 |
|
| 50 struct _PidginAccountChooser { |
|
| 51 GtkComboBox parent; |
|
| 52 |
|
| 53 GtkListStore *model; |
|
| 54 |
|
| 55 PurpleFilterAccountFunc filter_func; |
|
| 56 gboolean show_all; |
|
| 57 }; |
|
| 58 |
43 |
| 59 /****************************************************************************** |
44 /****************************************************************************** |
| 60 * Code |
45 * Callbacks |
| 61 *****************************************************************************/ |
46 *****************************************************************************/ |
| 62 static GParamSpec *properties[PROP_LAST] = {NULL}; |
|
| 63 |
|
| 64 G_DEFINE_TYPE(PidginAccountChooser, pidgin_account_chooser, GTK_TYPE_COMBO_BOX) |
|
| 65 |
|
| 66 static gpointer |
|
| 67 account_chooser_get_selected(PidginAccountChooser *chooser) |
|
| 68 { |
|
| 69 gpointer data = NULL; |
|
| 70 GtkTreeIter iter; |
|
| 71 |
|
| 72 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(chooser), &iter)) { |
|
| 73 gtk_tree_model_get( |
|
| 74 gtk_combo_box_get_model(GTK_COMBO_BOX(chooser)), &iter, |
|
| 75 AOP_DATA_COLUMN, &data, -1); |
|
| 76 } |
|
| 77 |
|
| 78 return data; |
|
| 79 } |
|
| 80 |
|
| 81 static void |
47 static void |
| 82 account_chooser_select_by_data(GtkWidget *chooser, gpointer data) |
48 pidgin_account_chooser_changed_cb(GtkComboBox *widget, gpointer user_data) { |
| 83 { |
|
| 84 GtkTreeModel *model; |
|
| 85 GtkTreeIter iter; |
|
| 86 gpointer iter_data; |
|
| 87 model = gtk_combo_box_get_model(GTK_COMBO_BOX(chooser)); |
|
| 88 if (gtk_tree_model_get_iter_first(model, &iter)) { |
|
| 89 do { |
|
| 90 gtk_tree_model_get(model, &iter, AOP_DATA_COLUMN, |
|
| 91 &iter_data, -1); |
|
| 92 if (iter_data == data) { |
|
| 93 gtk_combo_box_set_active_iter( |
|
| 94 GTK_COMBO_BOX(chooser), &iter); |
|
| 95 return; |
|
| 96 } |
|
| 97 } while (gtk_tree_model_iter_next(model, &iter)); |
|
| 98 } |
|
| 99 } |
|
| 100 |
|
| 101 static void |
|
| 102 set_account_menu(PidginAccountChooser *chooser, PurpleAccount *default_account) |
|
| 103 { |
|
| 104 PurpleAccount *account; |
|
| 105 GdkPixbuf *pixbuf = NULL; |
|
| 106 GList *list; |
|
| 107 GList *p; |
|
| 108 GtkTreeIter iter; |
|
| 109 gint default_item = 0; |
|
| 110 gint i; |
|
| 111 gchar buf[256]; |
|
| 112 |
|
| 113 if (chooser->show_all) { |
|
| 114 list = purple_accounts_get_all(); |
|
| 115 } else { |
|
| 116 list = purple_connections_get_all(); |
|
| 117 } |
|
| 118 |
|
| 119 gtk_list_store_clear(chooser->model); |
|
| 120 for (p = list, i = 0; p != NULL; p = p->next, i++) { |
|
| 121 if (chooser->show_all) { |
|
| 122 account = (PurpleAccount *)p->data; |
|
| 123 } else { |
|
| 124 PurpleConnection *gc = (PurpleConnection *)p->data; |
|
| 125 |
|
| 126 account = purple_connection_get_account(gc); |
|
| 127 } |
|
| 128 |
|
| 129 if (chooser->filter_func && !chooser->filter_func(account)) { |
|
| 130 i--; |
|
| 131 continue; |
|
| 132 } |
|
| 133 |
|
| 134 pixbuf = pidgin_create_protocol_icon( |
|
| 135 account, PIDGIN_PROTOCOL_ICON_SMALL); |
|
| 136 |
|
| 137 if (pixbuf) { |
|
| 138 if (purple_account_is_disconnected(account) && |
|
| 139 chooser->show_all && purple_connections_get_all()) { |
|
| 140 gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, |
|
| 141 0.0, FALSE); |
|
| 142 } |
|
| 143 } |
|
| 144 |
|
| 145 if (purple_account_get_private_alias(account)) { |
|
| 146 g_snprintf(buf, sizeof(buf), "%s (%s) (%s)", |
|
| 147 purple_account_get_username(account), |
|
| 148 purple_account_get_private_alias(account), |
|
| 149 purple_account_get_protocol_name(account)); |
|
| 150 } else { |
|
| 151 g_snprintf(buf, sizeof(buf), "%s (%s)", |
|
| 152 purple_account_get_username(account), |
|
| 153 purple_account_get_protocol_name(account)); |
|
| 154 } |
|
| 155 |
|
| 156 gtk_list_store_append(chooser->model, &iter); |
|
| 157 gtk_list_store_set(chooser->model, &iter, AOP_ICON_COLUMN, |
|
| 158 pixbuf, AOP_NAME_COLUMN, buf, |
|
| 159 AOP_DATA_COLUMN, account, -1); |
|
| 160 |
|
| 161 if (pixbuf) { |
|
| 162 g_object_unref(pixbuf); |
|
| 163 } |
|
| 164 |
|
| 165 if (default_account && account == default_account) { |
|
| 166 default_item = i; |
|
| 167 } |
|
| 168 } |
|
| 169 |
|
| 170 gtk_combo_box_set_active(GTK_COMBO_BOX(chooser), default_item); |
|
| 171 } |
|
| 172 |
|
| 173 static void |
|
| 174 regenerate_account_menu(PidginAccountChooser *chooser) |
|
| 175 { |
|
| 176 PurpleAccount *account; |
|
| 177 |
|
| 178 account = (PurpleAccount *)account_chooser_get_selected(chooser); |
|
| 179 |
|
| 180 set_account_menu(chooser, account); |
|
| 181 } |
|
| 182 |
|
| 183 static void |
|
| 184 account_menu_sign_on_off_cb(PurpleConnection *gc, PidginAccountChooser *chooser) |
|
| 185 { |
|
| 186 regenerate_account_menu(chooser); |
|
| 187 } |
|
| 188 |
|
| 189 static void |
|
| 190 account_menu_added_removed_cb(PurpleAccount *account, |
|
| 191 PidginAccountChooser *chooser) |
|
| 192 { |
|
| 193 regenerate_account_menu(chooser); |
|
| 194 } |
|
| 195 |
|
| 196 static gboolean |
|
| 197 account_menu_destroyed_cb(GtkWidget *chooser, GdkEvent *event, void *user_data) |
|
| 198 { |
|
| 199 purple_signals_disconnect_by_handle(chooser); |
|
| 200 |
|
| 201 return FALSE; |
|
| 202 } |
|
| 203 |
|
| 204 static void |
|
| 205 pidgin_account_chooser_changed_cb(GtkComboBox *widget, gpointer user_data) |
|
| 206 { |
|
| 207 g_object_notify_by_pspec(G_OBJECT(widget), properties[PROP_ACCOUNT]); |
49 g_object_notify_by_pspec(G_OBJECT(widget), properties[PROP_ACCOUNT]); |
| 208 } |
50 } |
| 209 |
51 |
| 210 /****************************************************************************** |
52 /****************************************************************************** |
| 211 * GObject implementation |
53 * GObject implementation |
| 212 *****************************************************************************/ |
54 *****************************************************************************/ |
| |
55 G_DEFINE_TYPE(PidginAccountChooser, pidgin_account_chooser, GTK_TYPE_COMBO_BOX) |
| |
56 |
| 213 static void |
57 static void |
| 214 pidgin_account_chooser_get_property(GObject *object, guint prop_id, |
58 pidgin_account_chooser_get_property(GObject *object, guint prop_id, |
| 215 GValue *value, GParamSpec *pspec) |
59 GValue *value, GParamSpec *pspec) |
| 216 { |
60 { |
| 217 PidginAccountChooser *chooser = PIDGIN_ACCOUNT_CHOOSER(object); |
61 PidginAccountChooser *chooser = PIDGIN_ACCOUNT_CHOOSER(object); |
| 218 |
62 |
| 219 switch (prop_id) { |
63 switch (prop_id) { |
| 220 case PROP_ACCOUNT: |
64 case PROP_ACCOUNT: |
| 221 g_value_set_object(value, account_chooser_get_selected(chooser)); |
65 g_value_set_object(value, pidgin_account_chooser_get_selected(chooser)); |
| 222 break; |
|
| 223 case PROP_SHOW_ALL: |
|
| 224 g_value_set_boolean(value, chooser->show_all); |
|
| 225 break; |
66 break; |
| 226 default: |
67 default: |
| 227 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); |
68 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); |
| 228 break; |
69 break; |
| 229 } |
70 } |
| 261 |
99 |
| 262 properties[PROP_ACCOUNT] = g_param_spec_object( |
100 properties[PROP_ACCOUNT] = g_param_spec_object( |
| 263 "account", "Account", "The account that is currently selected.", |
101 "account", "Account", "The account that is currently selected.", |
| 264 PURPLE_TYPE_ACCOUNT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); |
102 PURPLE_TYPE_ACCOUNT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); |
| 265 |
103 |
| 266 properties[PROP_SHOW_ALL] = g_param_spec_boolean( |
|
| 267 "show-all", "Show all", |
|
| 268 "Whether to show all accounts, or just online ones.", FALSE, |
|
| 269 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | |
|
| 270 G_PARAM_STATIC_STRINGS); |
|
| 271 |
|
| 272 g_object_class_install_properties(obj_class, PROP_LAST, properties); |
104 g_object_class_install_properties(obj_class, PROP_LAST, properties); |
| 273 |
105 |
| 274 /* Widget template */ |
106 /* Widget template */ |
| 275 |
|
| 276 gtk_widget_class_set_template_from_resource( |
107 gtk_widget_class_set_template_from_resource( |
| 277 widget_class, "/im/pidgin/Pidgin/Accounts/chooser.ui"); |
108 widget_class, "/im/pidgin/Pidgin/Accounts/chooser.ui"); |
| 278 |
|
| 279 gtk_widget_class_bind_template_child(widget_class, PidginAccountChooser, |
|
| 280 model); |
|
| 281 |
|
| 282 gtk_widget_class_bind_template_callback(widget_class, |
|
| 283 account_menu_destroyed_cb); |
|
| 284 } |
109 } |
| 285 |
110 |
| 286 static void |
111 static void |
| 287 pidgin_account_chooser_init(PidginAccountChooser *chooser) |
112 pidgin_account_chooser_init(PidginAccountChooser *chooser) { |
| 288 { |
|
| 289 gtk_widget_init_template(GTK_WIDGET(chooser)); |
113 gtk_widget_init_template(GTK_WIDGET(chooser)); |
| 290 |
114 |
| 291 set_account_menu(chooser, NULL); |
115 /* this callback emits the notify for the account property */ |
| 292 |
|
| 293 g_signal_connect(chooser, "changed", |
116 g_signal_connect(chooser, "changed", |
| 294 G_CALLBACK(pidgin_account_chooser_changed_cb), NULL); |
117 G_CALLBACK(pidgin_account_chooser_changed_cb), NULL); |
| 295 |
|
| 296 /* Register the purple sign on/off event callbacks. */ |
|
| 297 purple_signal_connect( |
|
| 298 purple_connections_get_handle(), "signed-on", chooser, |
|
| 299 PURPLE_CALLBACK(account_menu_sign_on_off_cb), chooser); |
|
| 300 purple_signal_connect( |
|
| 301 purple_connections_get_handle(), "signed-off", chooser, |
|
| 302 PURPLE_CALLBACK(account_menu_sign_on_off_cb), chooser); |
|
| 303 purple_signal_connect( |
|
| 304 purple_accounts_get_handle(), "account-added", chooser, |
|
| 305 PURPLE_CALLBACK(account_menu_added_removed_cb), chooser); |
|
| 306 purple_signal_connect( |
|
| 307 purple_accounts_get_handle(), "account-removed", chooser, |
|
| 308 PURPLE_CALLBACK(account_menu_added_removed_cb), chooser); |
|
| 309 } |
118 } |
| 310 |
119 |
| 311 /****************************************************************************** |
120 /****************************************************************************** |
| 312 * Public API |
121 * Public API |
| 313 *****************************************************************************/ |
122 *****************************************************************************/ |
| 314 GtkWidget * |
123 GtkWidget * |
| 315 pidgin_account_chooser_new(PurpleAccount *default_account, gboolean show_all) |
124 pidgin_account_chooser_new(void) { |
| 316 { |
|
| 317 PidginAccountChooser *chooser = NULL; |
125 PidginAccountChooser *chooser = NULL; |
| 318 |
126 |
| 319 chooser = g_object_new(PIDGIN_TYPE_ACCOUNT_CHOOSER, "account", |
127 chooser = g_object_new(PIDGIN_TYPE_ACCOUNT_CHOOSER, NULL); |
| 320 default_account, "show-all", show_all, NULL); |
|
| 321 |
128 |
| 322 return GTK_WIDGET(chooser); |
129 return GTK_WIDGET(chooser); |
| 323 } |
130 } |
| 324 |
131 |
| 325 void |
132 void |
| 327 PurpleFilterAccountFunc filter_func) |
134 PurpleFilterAccountFunc filter_func) |
| 328 { |
135 { |
| 329 g_return_if_fail(PIDGIN_IS_ACCOUNT_CHOOSER(chooser)); |
136 g_return_if_fail(PIDGIN_IS_ACCOUNT_CHOOSER(chooser)); |
| 330 |
137 |
| 331 chooser->filter_func = filter_func; |
138 chooser->filter_func = filter_func; |
| 332 regenerate_account_menu(chooser); |
|
| 333 } |
139 } |
| 334 |
140 |
| 335 PurpleAccount * |
141 PurpleAccount * |
| 336 pidgin_account_chooser_get_selected(GtkWidget *chooser) |
142 pidgin_account_chooser_get_selected(PidginAccountChooser *chooser) { |
| 337 { |
143 GtkTreeIter iter; |
| |
144 gpointer account = NULL; |
| |
145 |
| 338 g_return_val_if_fail(PIDGIN_IS_ACCOUNT_CHOOSER(chooser), NULL); |
146 g_return_val_if_fail(PIDGIN_IS_ACCOUNT_CHOOSER(chooser), NULL); |
| 339 |
147 |
| 340 return (PurpleAccount *)account_chooser_get_selected( |
148 if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(chooser), &iter)) { |
| 341 PIDGIN_ACCOUNT_CHOOSER(chooser)); |
149 GtkTreeModel *model = gtk_combo_box_get_model(GTK_COMBO_BOX(chooser)); |
| |
150 gtk_tree_model_get(model, &iter, |
| |
151 PIDGIN_ACCOUNT_STORE_COLUMN_ACCOUNT, &account, -1); |
| |
152 } |
| |
153 |
| |
154 return account; |
| 342 } |
155 } |
| 343 |
156 |
| 344 void |
157 void |
| 345 pidgin_account_chooser_set_selected(GtkWidget *chooser, PurpleAccount *account) |
158 pidgin_account_chooser_set_selected(PidginAccountChooser *chooser, |
| |
159 PurpleAccount *account) |
| 346 { |
160 { |
| |
161 GtkTreeModel *model = NULL; |
| |
162 GtkTreeIter iter; |
| |
163 PurpleAccount *acc = NULL; |
| |
164 |
| 347 g_return_if_fail(PIDGIN_IS_ACCOUNT_CHOOSER(chooser)); |
165 g_return_if_fail(PIDGIN_IS_ACCOUNT_CHOOSER(chooser)); |
| 348 |
166 |
| 349 account_chooser_select_by_data(chooser, account); |
167 model = gtk_combo_box_get_model(GTK_COMBO_BOX(chooser)); |
| |
168 g_return_if_fail(GTK_IS_TREE_MODEL(model)); |
| 350 |
169 |
| 351 /* NOTE: Property notification occurs in 'changed' signal callback. */ |
170 if(gtk_tree_model_get_iter_first(model, &iter)) { |
| |
171 do { |
| |
172 gtk_tree_model_get(model, &iter, |
| |
173 PIDGIN_ACCOUNT_STORE_COLUMN_ACCOUNT, &acc, -1); |
| |
174 if(acc == account) { |
| |
175 /* NOTE: Property notification occurs in 'changed' signal |
| |
176 * callback. |
| |
177 */ |
| |
178 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(chooser), &iter); |
| |
179 |
| |
180 g_object_unref(G_OBJECT(acc)); |
| |
181 |
| |
182 return; |
| |
183 } |
| |
184 g_object_unref(G_OBJECT(acc)); |
| |
185 } while(gtk_tree_model_iter_next(model, &iter)); |
| |
186 } |
| 352 } |
187 } |
| 353 |
188 |
| 354 gboolean |
|
| 355 pidgin_account_chooser_get_show_all(GtkWidget *chooser) |
|
| 356 { |
|
| 357 g_return_val_if_fail(PIDGIN_IS_ACCOUNT_CHOOSER(chooser), FALSE); |
|
| 358 |
|
| 359 return PIDGIN_ACCOUNT_CHOOSER(chooser)->show_all; |
|
| 360 } |
|