Mercurial > pidgin.yaz
comparison console/gntblist.c @ 13958:6741419af7f7
[gaim-migrate @ 16510]
Add a context menu for the buddy-list. Most of the menus don't do
anything yet, because the request-ui is not done. But the others,
eg. 'Get Info', 'Join In Chat' etc.) work.
committer: Tailor Script <tailor@pidgin.im>
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Mon, 17 Jul 2006 21:23:38 +0000 |
parents | 841a5ffbfee4 |
children | 2ae35c0cf616 |
comparison
equal
deleted
inserted
replaced
13957:421259b9e06d | 13958:6741419af7f7 |
---|---|
1 #include <account.h> | 1 #include <account.h> |
2 #include <blist.h> | 2 #include <blist.h> |
3 #include <request.h> | |
3 #include <server.h> | 4 #include <server.h> |
4 #include <signal.h> | 5 #include <signal.h> |
5 #include <util.h> | 6 #include <util.h> |
6 | 7 |
7 #include "gntgaim.h" | 8 #include "gntgaim.h" |
17 GntWidget *window; | 18 GntWidget *window; |
18 GntWidget *tree; | 19 GntWidget *tree; |
19 | 20 |
20 GntWidget *tooltip; | 21 GntWidget *tooltip; |
21 GaimBlistNode *tnode; /* Who is the tooltip being displayed for? */ | 22 GaimBlistNode *tnode; /* Who is the tooltip being displayed for? */ |
23 | |
24 GntWidget *context; | |
25 GaimBlistNode *cnode; | |
22 } GGBlist; | 26 } GGBlist; |
23 | 27 |
24 GGBlist *ggblist; | 28 GGBlist *ggblist; |
25 | 29 |
26 static void add_buddy(GaimBuddy *buddy, GGBlist *ggblist); | 30 static void add_buddy(GaimBuddy *buddy, GGBlist *ggblist); |
27 static void add_group(GaimGroup *group, GGBlist *ggblist); | 31 static void add_group(GaimGroup *group, GGBlist *ggblist); |
28 static void add_chat(GaimChat *chat, GGBlist *ggblist); | 32 static void add_chat(GaimChat *chat, GGBlist *ggblist); |
29 static void add_node(GaimBlistNode *node, GGBlist *ggblist); | 33 static void add_node(GaimBlistNode *node, GGBlist *ggblist); |
30 static void draw_tooltip(GGBlist *ggblist); | 34 static void draw_tooltip(GGBlist *ggblist); |
35 static void remove_peripherals(GGBlist *ggblist); | |
31 | 36 |
32 static void | 37 static void |
33 new_node(GaimBlistNode *node) | 38 new_node(GaimBlistNode *node) |
34 { | 39 { |
35 } | 40 } |
250 serv_join_chat(chat->account->gc, chat->components); | 255 serv_join_chat(chat->account->gc, chat->components); |
251 } | 256 } |
252 } | 257 } |
253 | 258 |
254 static void | 259 static void |
260 remove_context_menu(GGBlist *ggblist) | |
261 { | |
262 if (ggblist->context) | |
263 gnt_widget_destroy(ggblist->context->parent); | |
264 ggblist->context = NULL; | |
265 ggblist->cnode = NULL; | |
266 } | |
267 | |
268 static void | |
269 gnt_append_menu_action(GntTree *tree, GaimMenuAction *action, gpointer parent) | |
270 { | |
271 GList *list; | |
272 | |
273 gnt_tree_add_row_after(tree, action, action->label, parent, NULL); | |
274 for (list = action->children; list; list = list->next) | |
275 gnt_append_menu_action(tree, list->data, action); | |
276 } | |
277 | |
278 static void | |
279 append_proto_menu(GntTree *tree, GaimConnection *gc, GaimBlistNode *node) | |
280 { | |
281 GList *list; | |
282 GaimPluginProtocolInfo *prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
283 | |
284 if(!prpl_info || !prpl_info->blist_node_menu) | |
285 return; | |
286 | |
287 for(list = prpl_info->blist_node_menu(node); list; | |
288 list = g_list_delete_link(list, list)) | |
289 { | |
290 GaimMenuAction *act = (GaimMenuAction *) list->data; | |
291 gnt_append_menu_action(tree, act, NULL); | |
292 } | |
293 } | |
294 | |
295 static void | |
296 add_custom_action(GntTree *tree, const char *label, GaimCallback callback, | |
297 gpointer data) | |
298 { | |
299 GaimMenuAction *action = gaim_menu_action_new(label, callback, data, NULL); | |
300 gnt_append_menu_action(tree, action, NULL); | |
301 g_signal_connect_swapped(G_OBJECT(tree), "destroy", | |
302 G_CALLBACK(gaim_menu_action_free), action); | |
303 } | |
304 | |
305 static void | |
306 create_chat_menu(GntTree *tree, GaimChat *chat) | |
307 { | |
308 } | |
309 | |
310 static void | |
311 create_group_menu(GntTree *tree, GaimGroup *group) | |
312 { | |
313 } | |
314 | |
315 static void | |
316 gg_blist_get_buddy_info_cb(GaimBuddy *buddy, GaimBlistNode *null) | |
317 { | |
318 serv_get_info(buddy->account->gc, gaim_buddy_get_name(buddy)); | |
319 } | |
320 | |
321 static void | |
322 create_buddy_menu(GntTree *tree, GaimBuddy *buddy) | |
323 { | |
324 GaimPluginProtocolInfo *prpl_info; | |
325 | |
326 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(buddy->account->gc->prpl); | |
327 if (prpl_info && prpl_info->get_info) | |
328 { | |
329 add_custom_action(tree, _("Get Info"), | |
330 GAIM_CALLBACK(gg_blist_get_buddy_info_cb), buddy); | |
331 } | |
332 | |
333 #if 0 | |
334 add_custom_action(tree, _("Add Buddy Pounce"), | |
335 GAIM_CALLBACK(gg_blist_add_buddy_pounce_cb)), buddy); | |
336 | |
337 if (prpl_info && prpl_info->send_file) | |
338 { | |
339 if (!prpl_info->can_receive_file || | |
340 prpl_info->can_receive_file(buddy->account->gc, buddy->name)) | |
341 add_custom_action(tree, _("Send File"), | |
342 GAIM_CALLBACK(gg_blist_show_file_cb)), buddy); | |
343 } | |
344 | |
345 add_custom_action(tree, _("View Log"), | |
346 GAIM_CALLBACK(gg_blist_view_log_cb)), buddy); | |
347 #endif | |
348 | |
349 /* Protocol actions */ | |
350 append_proto_menu(tree, | |
351 gaim_account_get_connection(gaim_buddy_get_account(buddy)), | |
352 (GaimBlistNode*)buddy); | |
353 } | |
354 | |
355 static void | |
356 append_extended_menu(GntTree *tree, GaimBlistNode *node) | |
357 { | |
358 GList *iter; | |
359 | |
360 for (iter = gaim_blist_node_get_extended_menu(node); | |
361 iter; iter = g_list_delete_link(iter, iter)) | |
362 { | |
363 gnt_append_menu_action(tree, iter->data, NULL); | |
364 } | |
365 } | |
366 | |
367 static void | |
368 context_menu_callback(GntTree *tree, GGBlist *ggblist) | |
369 { | |
370 GaimMenuAction *action = gnt_tree_get_selection_data(tree); | |
371 GaimBlistNode *node = ggblist->cnode; | |
372 | |
373 if (action) | |
374 { | |
375 void (*callback)(GaimBlistNode *, gpointer); | |
376 callback = (void (*)(GaimBlistNode *, gpointer))action->callback; | |
377 callback(node, action->data); | |
378 } | |
379 | |
380 remove_context_menu(ggblist); | |
381 } | |
382 | |
383 static void | |
384 gg_blist_rename_node_cb(GaimBlistNode *node, GaimBlistNode *null) | |
385 { | |
386 } | |
387 | |
388 /* XXX: This still doesn't do anything, because request doesn't have a ui yet */ | |
389 static void | |
390 gg_blist_remove_node_cb(GaimBlistNode *node, GaimBlistNode *null) | |
391 { | |
392 void (*callback)(gpointer); | |
393 | |
394 if (GAIM_BLIST_NODE_IS_BUDDY(node)) | |
395 callback = (void(*)(gpointer))gaim_blist_remove_buddy; | |
396 else if (GAIM_BLIST_NODE_IS_CHAT(node)) | |
397 callback = (void(*)(gpointer))gaim_blist_remove_chat; | |
398 else if (GAIM_BLIST_NODE_IS_GROUP(node)) | |
399 callback = (void(*)(gpointer))gaim_blist_remove_group; | |
400 | |
401 /* XXX: anything to do with the returned ui-handle? */ | |
402 gaim_request_action(node, _("Confirm Remove"), | |
403 _("Are you sure you want to remove ..."), NULL, /* XXX: tidy up */ | |
404 1, node, 2, | |
405 _("Remove"), callback, | |
406 _("No"), NULL); | |
407 | |
408 } | |
409 | |
410 static void | |
411 draw_context_menu(GGBlist *ggblist) | |
412 { | |
413 GaimBlistNode *node = NULL; | |
414 GntWidget *context = NULL, *window = NULL; | |
415 GntTree *tree = NULL; | |
416 int x, y, top, width; | |
417 char *title = NULL; | |
418 | |
419 tree = GNT_TREE(ggblist->tree); | |
420 | |
421 if (ggblist->context) | |
422 { | |
423 remove_context_menu(ggblist); | |
424 } | |
425 | |
426 node = gnt_tree_get_selection_data(tree); | |
427 | |
428 if (node == NULL) | |
429 return; | |
430 if (ggblist->tooltip) | |
431 remove_tooltip(ggblist); | |
432 | |
433 ggblist->cnode = node; | |
434 ggblist->context = context = gnt_tree_new(); | |
435 GNT_WIDGET_SET_FLAGS(context, GNT_WIDGET_NO_BORDER); | |
436 gnt_widget_set_name(context, "context menu"); | |
437 g_signal_connect(G_OBJECT(context), "activate", G_CALLBACK(context_menu_callback), ggblist); | |
438 | |
439 if (GAIM_BLIST_NODE_IS_BUDDY(node)) | |
440 { | |
441 GaimBuddy *buddy = (GaimBuddy *)node; | |
442 create_buddy_menu(GNT_TREE(context), buddy); | |
443 title = g_strdup(gaim_buddy_get_name(buddy)); | |
444 } | |
445 else if (GAIM_BLIST_NODE_IS_CHAT(node)) | |
446 { | |
447 GaimChat *chat = (GaimChat*)node; | |
448 create_chat_menu(GNT_TREE(context), chat); | |
449 title = g_strdup(gaim_chat_get_name(chat)); | |
450 } | |
451 else if (GAIM_BLIST_NODE_IS_GROUP(node)) | |
452 { | |
453 GaimGroup *group = (GaimGroup *)node; | |
454 create_group_menu(GNT_TREE(context), group); | |
455 title = g_strdup(group->name); | |
456 } | |
457 | |
458 append_extended_menu(GNT_TREE(context), node); | |
459 | |
460 /* These are common for everything */ | |
461 add_custom_action(GNT_TREE(context), _("Rename"), | |
462 GAIM_CALLBACK(gg_blist_rename_node_cb), node); | |
463 add_custom_action(GNT_TREE(context), _("Remove"), | |
464 GAIM_CALLBACK(gg_blist_remove_node_cb), node); | |
465 | |
466 window = gnt_vbox_new(FALSE); | |
467 gnt_box_set_toplevel(GNT_BOX(window), TRUE); | |
468 gnt_box_set_title(GNT_BOX(window), title); | |
469 | |
470 gnt_box_add_widget(GNT_BOX(window), context); | |
471 | |
472 /* Set the position for the popup */ | |
473 gnt_widget_get_position(GNT_WIDGET(tree), &x, &y); | |
474 gnt_widget_get_size(GNT_WIDGET(tree), &width, NULL); | |
475 top = gnt_tree_get_selection_visible_line(tree); | |
476 | |
477 x += width; | |
478 y += top - 1; | |
479 | |
480 gnt_widget_set_position(window, x, y); | |
481 gnt_widget_draw(window); | |
482 } | |
483 | |
484 static void | |
255 draw_tooltip(GGBlist *ggblist) | 485 draw_tooltip(GGBlist *ggblist) |
256 { | 486 { |
257 GaimBlistNode *node; | 487 GaimBlistNode *node; |
258 int x, y, top, width; | 488 int x, y, top, width; |
259 GString *str; | 489 GString *str; |
266 | 496 |
267 widget = ggblist->tree; | 497 widget = ggblist->tree; |
268 tree = GNT_TREE(widget); | 498 tree = GNT_TREE(widget); |
269 | 499 |
270 if (!gnt_widget_has_focus(ggblist->tree)) | 500 if (!gnt_widget_has_focus(ggblist->tree)) |
501 return; | |
502 | |
503 if (ggblist->context) | |
271 return; | 504 return; |
272 | 505 |
273 if (ggblist->tooltip) | 506 if (ggblist->tooltip) |
274 { | 507 { |
275 /* XXX: Once we can properly redraw on expose events, this can be removed at the end | 508 /* XXX: Once we can properly redraw on expose events, this can be removed at the end |
370 } | 603 } |
371 | 604 |
372 static gboolean | 605 static gboolean |
373 key_pressed(GntWidget *widget, const char *text, GGBlist *ggblist) | 606 key_pressed(GntWidget *widget, const char *text, GGBlist *ggblist) |
374 { | 607 { |
608 gboolean stop = FALSE, ret = FALSE; | |
375 if (text[0] == 27 && text[1] == 0) | 609 if (text[0] == 27 && text[1] == 0) |
376 { | 610 { |
377 /* Escape was pressed */ | 611 /* Escape was pressed */ |
378 if (ggblist->tooltip) | 612 remove_peripherals(ggblist); |
613 stop = TRUE; | |
614 ret = TRUE; | |
615 } | |
616 | |
617 if (ggblist->context) | |
618 { | |
619 ret = gnt_widget_key_pressed(ggblist->context, text); | |
620 stop = TRUE; | |
621 } | |
622 | |
623 if (text[0] == 27) | |
624 { | |
625 if (strcmp(text + 1, GNT_KEY_POPUP) == 0) | |
379 { | 626 { |
380 gnt_widget_destroy(ggblist->tooltip); | 627 draw_context_menu(ggblist); |
381 ggblist->tooltip = NULL; | 628 stop = TRUE; |
382 return TRUE; | 629 ret = TRUE; |
383 } | 630 } |
384 } | 631 } |
385 | 632 |
386 return FALSE; | 633 if (stop) |
634 g_signal_stop_emission_by_name(G_OBJECT(widget), "key_pressed"); | |
635 | |
636 return ret; | |
387 } | 637 } |
388 | 638 |
389 static void | 639 static void |
390 update_buddy_display(GaimBuddy *buddy, GGBlist *ggblist) | 640 update_buddy_display(GaimBuddy *buddy, GGBlist *ggblist) |
391 { | 641 { |
407 | 657 |
408 static void | 658 static void |
409 buddy_idle_changed(GaimBuddy *buddy, int old, int new, GGBlist *ggblist) | 659 buddy_idle_changed(GaimBuddy *buddy, int old, int new, GGBlist *ggblist) |
410 { | 660 { |
411 update_buddy_display(buddy, ggblist); | 661 update_buddy_display(buddy, ggblist); |
662 } | |
663 | |
664 static void | |
665 remove_peripherals(GGBlist *ggblist) | |
666 { | |
667 if (ggblist->tooltip) | |
668 remove_tooltip(ggblist); | |
669 else if (ggblist->context) | |
670 remove_context_menu(ggblist); | |
412 } | 671 } |
413 | 672 |
414 void gg_blist_init() | 673 void gg_blist_init() |
415 { | 674 { |
416 ggblist = g_new0(GGBlist, 1); | 675 ggblist = g_new0(GGBlist, 1); |
454 g_signal_connect(G_OBJECT(ggblist->tree), "selection_changed", G_CALLBACK(selection_changed), ggblist); | 713 g_signal_connect(G_OBJECT(ggblist->tree), "selection_changed", G_CALLBACK(selection_changed), ggblist); |
455 g_signal_connect(G_OBJECT(ggblist->tree), "key_pressed", G_CALLBACK(key_pressed), ggblist); | 714 g_signal_connect(G_OBJECT(ggblist->tree), "key_pressed", G_CALLBACK(key_pressed), ggblist); |
456 g_signal_connect(G_OBJECT(ggblist->tree), "activate", G_CALLBACK(selection_activate), ggblist); | 715 g_signal_connect(G_OBJECT(ggblist->tree), "activate", G_CALLBACK(selection_activate), ggblist); |
457 g_signal_connect_data(G_OBJECT(ggblist->tree), "gained-focus", G_CALLBACK(draw_tooltip), | 716 g_signal_connect_data(G_OBJECT(ggblist->tree), "gained-focus", G_CALLBACK(draw_tooltip), |
458 ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED); | 717 ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED); |
459 g_signal_connect_data(G_OBJECT(ggblist->tree), "lost-focus", G_CALLBACK(remove_tooltip), | 718 g_signal_connect_data(G_OBJECT(ggblist->tree), "lost-focus", G_CALLBACK(remove_peripherals), |
460 ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED); | 719 ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED); |
461 } | 720 } |
462 | 721 |
463 void gg_blist_uninit() | 722 void gg_blist_uninit() |
464 { | 723 { |