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 {