comparison pidgin/gtkdisco.c @ 26331:a5010188c01e

Add the files I forgot to `mtn add` earlier (also, alphabetized disco.h enum a bit)
author Paul Aurich <paul@darkrain42.org>
date Sun, 29 Mar 2009 19:43:32 +0000
parents
children 31e05bafd7a3
comparison
equal deleted inserted replaced
26330:f19c214201db 26331:a5010188c01e
1 /**
2 * @file gtkdisco.c GTK+ Service Discovery UI
3 * @ingroup pidgin
4 */
5
6 /* pidgin
7 *
8 * Pidgin is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25 */
26
27 #include "internal.h"
28 #include "pidgin.h"
29 #include "gtkutils.h"
30 #include "debug.h"
31 #include "disco.h"
32
33 #include "gtkdisco.h"
34
35 typedef struct _PidginDiscoDialog {
36 GtkWidget *window;
37 GtkWidget *account_widget;
38
39 GtkWidget *sw;
40 GtkWidget *progress;
41 GtkTreeStore *model;
42 GtkWidget *tree;
43 GHashTable *cats; /** Meow. */
44
45 GtkWidget *stop_button;
46 GtkWidget *list_button;
47 GtkWidget *register_button;
48 GtkWidget *add_button;
49 GtkWidget *close_button;
50
51 PurpleAccount *account;
52 PurpleDiscoList *discolist;
53 } PidginDiscoDialog;
54
55 struct _menu_cb_info {
56 PurpleDiscoList *list;
57 PurpleDiscoService *service;
58 };
59
60 enum {
61 PIXBUF_COLUMN = 0,
62 NAME_COLUMN,
63 DESCRIPTION_COLUMN,
64 SERVICE_COLUMN,
65 NUM_OF_COLUMNS
66 };
67
68 static void dialog_select_account_cb(GObject *w, PurpleAccount *account,
69 PidginDiscoDialog *dialog)
70 {
71 dialog->account = account;
72 }
73
74 static void register_button_cb(GtkButton *button, PidginDiscoDialog *dialog)
75 {
76 struct _menu_cb_info *info = g_object_get_data(G_OBJECT(button), "disco-info");
77 PurpleConnection *gc = purple_account_get_connection(info->list->account);
78
79 purple_disco_service_register(gc, info->service);
80 }
81
82 static void list_button_cb(GtkButton *button, PidginDiscoDialog *dialog)
83 {
84 PurpleConnection *gc;
85
86 gc = purple_account_get_connection(dialog->account);
87 if (!gc)
88 return;
89
90 if (dialog->discolist != NULL)
91 purple_disco_list_unref(dialog->discolist);
92
93 dialog->discolist = purple_disco_list_new(dialog->account, (void*) dialog);
94
95 purple_disco_get_list(gc, dialog->discolist);
96 }
97
98 static void add_room_to_blist_cb(GtkButton *button, PidginDiscoDialog *dialog)
99 {
100 struct _menu_cb_info *info = g_object_get_data(G_OBJECT(button), "disco-info");
101
102 if (info) {
103 if (info->service->category == PURPLE_DISCO_SERVICE_CAT_MUC)
104 purple_blist_request_add_chat(info->list->account, NULL, NULL, info->service->name);
105 else
106 purple_blist_request_add_buddy(info->list->account, info->service->name, NULL, NULL);
107 }
108 }
109
110 static void
111 selection_changed_cb(GtkTreeSelection *selection, PidginDiscoDialog *dialog)
112 {
113 PurpleDiscoService *service;
114 GtkTreeIter iter;
115 GValue val;
116 static struct _menu_cb_info *info;
117
118 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
119 val.g_type = 0;
120 gtk_tree_model_get_value(GTK_TREE_MODEL(dialog-> model), &iter, SERVICE_COLUMN, &val);
121 service = g_value_get_pointer(&val);
122 if (!service) {
123 gtk_widget_set_sensitive(dialog->add_button, FALSE);
124 gtk_widget_set_sensitive(dialog->register_button, FALSE);
125 return;
126 }
127
128 info = g_new0(struct _menu_cb_info, 1);
129 info->list = dialog->discolist;
130 info->service = service;
131
132 g_object_set_data(G_OBJECT(dialog->add_button), "disco-info", info);
133 g_object_set_data(G_OBJECT(dialog->register_button), "disco-info", info);
134
135 gtk_widget_set_sensitive(dialog->add_button, service->flags & PURPLE_DISCO_FLAG_ADD);
136 gtk_widget_set_sensitive(dialog->register_button, service->flags & PURPLE_DISCO_FLAG_REGISTER);
137 } else {
138 gtk_widget_set_sensitive(dialog->add_button, FALSE);
139 gtk_widget_set_sensitive(dialog->register_button, FALSE);
140 }
141 }
142
143 static gint
144 delete_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d)
145 {
146 PidginDiscoDialog *dialog = d;
147
148 if (dialog->discolist)
149 purple_disco_list_unref(dialog->discolist);
150
151 g_free(dialog);
152
153 return FALSE;
154 }
155
156 static void stop_button_cb(GtkButton *button, PidginDiscoDialog *dialog)
157 {
158 purple_disco_cancel_get_list(dialog->discolist);
159
160 if (dialog->account_widget)
161 gtk_widget_set_sensitive(dialog->account_widget, TRUE);
162
163 gtk_widget_set_sensitive(dialog->stop_button, FALSE);
164 gtk_widget_set_sensitive(dialog->list_button, TRUE);
165 gtk_widget_set_sensitive(dialog->add_button, FALSE);
166 }
167
168 static void close_button_cb(GtkButton *button, PidginDiscoDialog *dialog)
169 {
170 GtkWidget *window = dialog->window;
171
172 delete_win_cb(NULL, NULL, dialog);
173 gtk_widget_destroy(window);
174 }
175
176 static gboolean account_filter_func(PurpleAccount *account)
177 {
178 PurpleConnection *conn = purple_account_get_connection(account);
179 PurplePluginProtocolInfo *prpl_info = NULL;
180
181 if (conn)
182 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(conn->prpl);
183
184 return (prpl_info && PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, disco_get_list));
185 }
186
187 gboolean
188 pidgin_disco_is_showable()
189 {
190 GList *c;
191 PurpleConnection *gc;
192
193 for (c = purple_connections_get_all(); c != NULL; c = c->next) {
194 gc = c->data;
195
196 if (account_filter_func(purple_connection_get_account(gc)))
197 return TRUE;
198 }
199
200 return FALSE;
201 }
202
203 static void pidgin_disco_create_tree(PidginDiscoDialog *dialog)
204 {
205 GtkCellRenderer *text_renderer, *pixbuf_renderer;
206 GtkTreeViewColumn *column;
207 GtkTreeSelection *selection;
208
209 dialog->model = gtk_tree_store_new(NUM_OF_COLUMNS,
210 GDK_TYPE_PIXBUF, /* PIXBUF_COLUMN */
211 G_TYPE_STRING, /* NAME_COLUMN */
212 G_TYPE_STRING, /* DESCRIPTION_COLUMN */
213 G_TYPE_POINTER /* SERVICE_COLUMN */
214 );
215
216 dialog->tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
217 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->tree), TRUE);
218
219 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->tree));
220 g_signal_connect(G_OBJECT(selection), "changed",
221 G_CALLBACK(selection_changed_cb), dialog);
222
223 g_object_unref(dialog->model);
224
225 gtk_container_add(GTK_CONTAINER(dialog->sw), dialog->tree);
226 gtk_widget_show(dialog->tree);
227
228 text_renderer = gtk_cell_renderer_text_new();
229 pixbuf_renderer = gtk_cell_renderer_pixbuf_new();
230
231 column = gtk_tree_view_column_new();
232 gtk_tree_view_column_set_title(column, _("Name"));
233
234 gtk_tree_view_column_pack_start(column, pixbuf_renderer, FALSE);
235 gtk_tree_view_column_set_attributes(column, pixbuf_renderer,
236 "pixbuf", PIXBUF_COLUMN, NULL);
237
238 gtk_tree_view_column_pack_start(column, text_renderer, TRUE);
239 gtk_tree_view_column_set_attributes(column, text_renderer,
240 "text", NAME_COLUMN, NULL);
241
242 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
243 GTK_TREE_VIEW_COLUMN_GROW_ONLY);
244 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
245 gtk_tree_view_column_set_sort_column_id(GTK_TREE_VIEW_COLUMN(column), NAME_COLUMN);
246 gtk_tree_view_column_set_reorderable(GTK_TREE_VIEW_COLUMN(column), TRUE);
247 gtk_tree_view_append_column(GTK_TREE_VIEW(dialog->tree), column);
248
249 column = gtk_tree_view_column_new_with_attributes(_("Description"), text_renderer,
250 "text", DESCRIPTION_COLUMN, NULL);
251 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
252 GTK_TREE_VIEW_COLUMN_GROW_ONLY);
253 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
254 gtk_tree_view_column_set_sort_column_id(GTK_TREE_VIEW_COLUMN(column), DESCRIPTION_COLUMN);
255 gtk_tree_view_column_set_reorderable(GTK_TREE_VIEW_COLUMN(column), TRUE);
256 gtk_tree_view_append_column(GTK_TREE_VIEW(dialog->tree), column);
257 }
258
259 static PidginDiscoDialog*
260 pidgin_disco_dialog_new_with_account(PurpleAccount *account)
261 {
262 PidginDiscoDialog *dialog;
263 GtkWidget *window, *vbox, *vbox2, *bbox;
264
265 dialog = g_new0(PidginDiscoDialog, 1);
266 dialog->account = account;
267
268 /* Create the window. */
269 dialog->window = window = pidgin_create_dialog(_("Service Discovery"), PIDGIN_HIG_BORDER, "service discovery", TRUE);
270
271 g_signal_connect(G_OBJECT(window), "delete_event",
272 G_CALLBACK(delete_win_cb), dialog);
273
274 /* Create the parent vbox for everything. */
275 vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(window), FALSE, PIDGIN_HIG_BORDER);
276
277 vbox2 = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
278 gtk_container_add(GTK_CONTAINER(vbox), vbox2);
279 gtk_widget_show(vbox2);
280
281 /* accounts dropdown list */
282 dialog->account_widget = pidgin_account_option_menu_new(dialog->account, FALSE,
283 G_CALLBACK(dialog_select_account_cb), account_filter_func, dialog);
284 if (!dialog->account) /* this is normally null, and we normally don't care what the first selected item is */
285 dialog->account = pidgin_account_option_menu_get_selected(dialog->account_widget);
286 pidgin_add_widget_to_vbox(GTK_BOX(vbox2), _("_Account:"), NULL, dialog->account_widget, TRUE, NULL);
287
288 /* scrolled window */
289 dialog->sw = gtk_scrolled_window_new(NULL, NULL);
290 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(dialog->sw),
291 GTK_SHADOW_IN);
292 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dialog->sw),
293 GTK_POLICY_AUTOMATIC,
294 GTK_POLICY_AUTOMATIC);
295 gtk_box_pack_start(GTK_BOX(vbox2), dialog->sw, TRUE, TRUE, 0);
296 gtk_widget_set_size_request(dialog->sw, -1, 250);
297 gtk_widget_show(dialog->sw);
298
299 /* progress bar */
300 dialog->progress = gtk_progress_bar_new();
301 gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(dialog->progress), 0.1);
302 gtk_box_pack_start(GTK_BOX(vbox2), dialog->progress, FALSE, FALSE, 0);
303 gtk_widget_show(dialog->progress);
304
305
306 /* button box */
307 bbox = pidgin_dialog_get_action_area(GTK_DIALOG(window));
308 gtk_box_set_spacing(GTK_BOX(bbox), PIDGIN_HIG_BOX_SPACE);
309 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
310
311 /* stop button */
312 dialog->stop_button = pidgin_dialog_add_button(GTK_DIALOG(window), GTK_STOCK_STOP,
313 G_CALLBACK(stop_button_cb), dialog);
314 gtk_widget_set_sensitive(dialog->stop_button, FALSE);
315
316 /* list button */
317 dialog->list_button = pidgin_pixbuf_button_from_stock(_("_Get List"), GTK_STOCK_REFRESH,
318 PIDGIN_BUTTON_HORIZONTAL);
319 gtk_box_pack_start(GTK_BOX(bbox), dialog->list_button, FALSE, FALSE, 0);
320 g_signal_connect(G_OBJECT(dialog->list_button), "clicked",
321 G_CALLBACK(list_button_cb), dialog);
322 gtk_widget_show(dialog->list_button);
323
324 /* register button */
325 dialog->register_button = pidgin_dialog_add_button(GTK_DIALOG(dialog->window), _("Register"),
326 G_CALLBACK(register_button_cb), dialog);
327 gtk_widget_set_sensitive(dialog->register_button, FALSE);
328
329 /* add button */
330 dialog->add_button = pidgin_pixbuf_button_from_stock(_("_Add"), GTK_STOCK_ADD,
331 PIDGIN_BUTTON_HORIZONTAL);
332 gtk_box_pack_start(GTK_BOX(bbox), dialog->add_button, FALSE, FALSE, 0);
333 g_signal_connect(G_OBJECT(dialog->add_button), "clicked",
334 G_CALLBACK(add_room_to_blist_cb), dialog);
335 gtk_widget_set_sensitive(dialog->add_button, FALSE);
336 gtk_widget_show(dialog->add_button);
337
338 /* close button */
339 dialog->close_button = pidgin_dialog_add_button(GTK_DIALOG(window), GTK_STOCK_CLOSE,
340 G_CALLBACK(close_button_cb), dialog);
341
342 pidgin_disco_create_tree(dialog);
343
344 /* show the dialog window and return the dialog */
345 gtk_widget_show(dialog->window);
346
347 return dialog;
348 }
349
350 void
351 pidgin_disco_dialog_show(void)
352 {
353 pidgin_disco_dialog_new_with_account(NULL);
354 }
355
356 void
357 pidgin_disco_dialog_show_with_account(PurpleAccount* account)
358 {
359 PidginDiscoDialog *dialog = pidgin_disco_dialog_new_with_account(account);
360
361 if (!dialog)
362 return;
363
364 list_button_cb(GTK_BUTTON(dialog->list_button), dialog);
365 }
366
367 static void
368 pidgin_disco_create(PurpleDiscoList *list)
369 {
370 PidginDiscoDialog *dialog = (PidginDiscoDialog *) list->ui_data;
371
372 dialog->cats = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)gtk_tree_row_reference_free);
373 }
374
375
376 static void
377 pidgin_disco_destroy(PurpleDiscoList *list)
378 {
379 PidginDiscoDialog *dialog = (PidginDiscoDialog *) list->ui_data;
380
381 g_hash_table_destroy(dialog->cats);
382 }
383
384 static void pidgin_disco_in_progress(PurpleDiscoList *list, gboolean in_progress)
385 {
386 PidginDiscoDialog *dialog = (PidginDiscoDialog *) list->ui_data;
387
388 if (!dialog)
389 return;
390
391 if (in_progress) {
392 gtk_tree_store_clear(dialog->model);
393 if (dialog->account_widget)
394 gtk_widget_set_sensitive(dialog->account_widget, FALSE);
395 gtk_widget_set_sensitive(dialog->stop_button, TRUE);
396 gtk_widget_set_sensitive(dialog->list_button, FALSE);
397 } else {
398 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dialog->progress), 0.0);
399 if (dialog->account_widget)
400 gtk_widget_set_sensitive(dialog->account_widget, TRUE);
401 gtk_widget_set_sensitive(dialog->stop_button, FALSE);
402 gtk_widget_set_sensitive(dialog->list_button, TRUE);
403 }
404 }
405
406 static void pidgin_disco_add_service(PurpleDiscoList *list, PurpleDiscoService *service, PurpleDiscoService *parent)
407 {
408 PidginDiscoDialog *dialog = (PidginDiscoDialog *) list->ui_data;
409 GtkTreeIter iter, parent_iter;
410 GtkTreeRowReference *rr;
411 GtkTreePath *path;
412 char *filename = NULL;
413 GdkPixbuf *pixbuf = NULL;
414
415 purple_debug_info("disco", "Add_service \"%s\"\n", service->name);
416
417 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(dialog->progress));
418
419 if (parent) {
420 rr = g_hash_table_lookup(dialog->cats, parent);
421 path = gtk_tree_row_reference_get_path(rr);
422 if (path) {
423 gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &parent_iter, path);
424 gtk_tree_path_free(path);
425 }
426 }
427
428 gtk_tree_store_append(dialog->model, &iter, (parent ? &parent_iter : NULL));
429
430 if (service->type == PURPLE_DISCO_SERVICE_TYPE_XMPP)
431 filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "22", "jabber.png", NULL);
432 else if (service->type == PURPLE_DISCO_SERVICE_TYPE_ICQ)
433 filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "22", "icq.png", NULL);
434 else if (service->type == PURPLE_DISCO_SERVICE_TYPE_YAHOO)
435 filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "22", "yahoo.png", NULL);
436 else if (service->type == PURPLE_DISCO_SERVICE_TYPE_GTALK)
437 filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "22", "google-talk.png", NULL);
438 else if (service->type == PURPLE_DISCO_SERVICE_TYPE_IRC)
439 filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "22", "irc.png", NULL);
440 else if (service->type == PURPLE_DISCO_SERVICE_TYPE_GG)
441 filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "22", "gadu-gadu.png", NULL);
442 else if (service->type == PURPLE_DISCO_SERVICE_TYPE_AIM)
443 filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "22", "aim.png", NULL);
444 else if (service->type == PURPLE_DISCO_SERVICE_TYPE_QQ)
445 filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "22", "qq.png", NULL);
446 else if (service->type == PURPLE_DISCO_SERVICE_TYPE_MSN)
447 filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "22", "msn.png", NULL);
448 else if (service->type == PURPLE_DISCO_SERVICE_TYPE_USER)
449 filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "status", "22", "person.png", NULL);
450 else if (service->category == PURPLE_DISCO_SERVICE_CAT_MUC)
451 filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "status", "22", "chat.png", NULL);
452
453 if (filename) {
454 pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
455 g_free(filename);
456 }
457
458 gtk_tree_store_set(dialog->model, &iter,
459 PIXBUF_COLUMN, pixbuf,
460 NAME_COLUMN, service->name,
461 DESCRIPTION_COLUMN, service->description,
462 SERVICE_COLUMN, service,
463 -1);
464
465 path = gtk_tree_model_get_path(GTK_TREE_MODEL(dialog->model), &iter);
466
467 rr = gtk_tree_row_reference_new(GTK_TREE_MODEL(dialog->model), path);
468 g_hash_table_insert(dialog->cats, service, rr);
469
470 gtk_tree_path_free(path);
471
472 if (pixbuf)
473 g_object_unref(pixbuf);
474 }
475
476 static PurpleDiscoUiOps ops = {
477 pidgin_disco_dialog_show_with_account,
478 pidgin_disco_create,
479 pidgin_disco_destroy,
480 pidgin_disco_add_service,
481 pidgin_disco_in_progress
482 };
483
484 void pidgin_disco_init() {
485 purple_disco_set_ui_ops(&ops);
486 }