Mercurial > pidgin
changeset 19599:0a170af12723
merge of '0dbc6114de523821fc87cf7d1c44b30aa0e92713'
and 'a1d362572ca941722a9db19c6886f7796b6d8d81'
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Mon, 03 Sep 2007 06:51:15 +0000 |
parents | dd4b1dc8a0ce (current diff) c3259b161070 (diff) |
children | 8b887be774e2 |
files | |
diffstat | 14 files changed, 252 insertions(+), 160 deletions(-) [+] |
line wrap: on
line diff
--- a/COPYRIGHT Mon Sep 03 05:17:32 2007 +0000 +++ b/COPYRIGHT Mon Sep 03 06:51:15 2007 +0000 @@ -348,6 +348,7 @@ Sony Computer Entertainment America, Inc. Andy Spencer Mark Spencer +Peter Speybrouck Lex Spoon Chris Stafford Kevin Stange
--- a/ChangeLog.API Mon Sep 03 05:17:32 2007 +0000 +++ b/ChangeLog.API Mon Sep 03 06:51:15 2007 +0000 @@ -14,6 +14,10 @@ The UI no longer needs to call it. Pidgin: + Changed: + * pidgin_conversations_fill_menu now also adds a separator and a 'Show + All' item if there are more than one conversations in the list. + Added: * pidgin_set_accessible_relations, sets up label-for and labelled-by ATK relations (broken out from pidgin_set_accessible_label)
--- a/finch/plugins/gntclipboard.c Mon Sep 03 05:17:32 2007 +0000 +++ b/finch/plugins/gntclipboard.c Mon Sep 03 06:51:15 2007 +0000 @@ -38,10 +38,12 @@ #include <plugin.h> #include <version.h> #include <debug.h> +#include <notify.h> #include <gntwm.h> #include <gntplugin.h> +#ifdef HAVE_X11 static pid_t child = 0; static gulong sig_handle; @@ -49,7 +51,6 @@ static void set_clip(gchar *string) { -#ifdef HAVE_X11 Window w; XEvent e, respond; XSelectionRequestEvent *req; @@ -89,14 +90,12 @@ return; } } -#endif return; } static void clipboard_changed(GntWM *wm, gchar *string) { -#ifdef HAVE_X11 if (child) { kill(child, SIGTERM); } @@ -104,8 +103,8 @@ set_clip(string); _exit(0); } +} #endif -} static gboolean plugin_load(PurplePlugin *plugin) @@ -113,25 +112,35 @@ #ifdef HAVE_X11 if (!XOpenDisplay(NULL)) { purple_debug_warning("gntclipboard", "Couldn't find X display\n"); + purple_notify_error(NULL, _("Error"), _("Error loading the plugin."), + _("Couldn't find X display")); return FALSE; } -#endif if (!getenv("WINDOWID")) { purple_debug_warning("gntclipboard", "Couldn't find window\n"); + purple_notify_error(NULL, _("Error"), _("Error loading the plugin."), + _("Couldn't find window")); return FALSE; } sig_handle = g_signal_connect(G_OBJECT(gnt_get_clipboard()), "clipboard_changed", G_CALLBACK(clipboard_changed), NULL); return TRUE; +#else + purple_notify_error(NULL, _("Error"), _("Error loading the plugin."), + _("This plugin cannot be loaded because it was not built with X11 support.")); + return FALSE; +#endif } static gboolean plugin_unload(PurplePlugin *plugin) { +#ifdef HAVE_X11 if (child) { kill(child, SIGTERM); child = 0; } g_signal_handler_disconnect(G_OBJECT(gnt_get_clipboard()), sig_handle); +#endif return TRUE; }
--- a/libpurple/internal.h Mon Sep 03 05:17:32 2007 +0000 +++ b/libpurple/internal.h Mon Sep 03 06:51:15 2007 +0000 @@ -29,6 +29,10 @@ # include <config.h> #endif +/* for SIOCGIFCONF in SKYOS */ +#ifdef SKYOS +#include <net/sockios.h> +#endif /* * If we're using NLS, make sure gettext works. If not, then define * dummy macros in place of the normal gettext macros.
--- a/libpurple/protocols/bonjour/bonjour.c Mon Sep 03 05:17:32 2007 +0000 +++ b/libpurple/protocols/bonjour/bonjour.c Mon Sep 03 06:51:15 2007 +0000 @@ -235,6 +235,13 @@ g_free(stripped); } +static void bonjour_remove_buddy(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group) { + if (buddy->proto_data) { + bonjour_buddy_delete(buddy->proto_data); + buddy->proto_data = NULL; + } +} + static GList * bonjour_status_types(PurpleAccount *account) { @@ -395,7 +402,7 @@ NULL, /* change_passwd */ NULL, /* add_buddy */ NULL, /* add_buddies */ - NULL, /* remove_buddy */ + bonjour_remove_buddy, /* remove_buddy */ NULL, /* remove_buddies */ NULL, /* add_permit */ NULL, /* add_deny */
--- a/libpurple/protocols/bonjour/buddy.c Mon Sep 03 05:17:32 2007 +0000 +++ b/libpurple/protocols/bonjour/buddy.c Mon Sep 03 06:51:15 2007 +0000 @@ -121,9 +121,8 @@ * the buddy. */ void -bonjour_buddy_add_to_purple(BonjourBuddy *bonjour_buddy) +bonjour_buddy_add_to_purple(BonjourBuddy *bonjour_buddy, PurpleBuddy *buddy) { - PurpleBuddy *buddy; PurpleGroup *group; PurpleAccount *account = bonjour_buddy->account; const char *status_id, *old_hash, *new_hash; @@ -147,7 +146,8 @@ } /* Make sure the buddy exists in our buddy list */ - buddy = purple_find_buddy(account, bonjour_buddy->name); + if (buddy == NULL) + buddy = purple_find_buddy(account, bonjour_buddy->name); if (buddy == NULL) { buddy = purple_buddy_new(account, bonjour_buddy->name, NULL);
--- a/libpurple/protocols/bonjour/buddy.h Mon Sep 03 05:17:32 2007 +0000 +++ b/libpurple/protocols/bonjour/buddy.h Mon Sep 03 06:51:15 2007 +0000 @@ -92,8 +92,9 @@ /** * If the buddy doesn't previoulsy exists, it is created. Else, its data is changed (???) + * purple_buddy is optional; it saves an additional lookup if we already have it */ -void bonjour_buddy_add_to_purple(BonjourBuddy *buddy); +void bonjour_buddy_add_to_purple(BonjourBuddy *bonjour_buddy, PurpleBuddy *purple_buddy); /** * We got the buddy icon data; deal with it
--- a/libpurple/protocols/bonjour/jabber.c Mon Sep 03 05:17:32 2007 +0000 +++ b/libpurple/protocols/bonjour/jabber.c Mon Sep 03 06:51:15 2007 +0000 @@ -373,17 +373,19 @@ g_return_if_fail(bb != NULL); - /* Close the socket, clear the watcher and free memory */ - bonjour_jabber_close_conversation(bb->conversation); - bb->conversation = NULL; + /* Inform the user that the conversation has been closed */ + if (bb->conversation != NULL) { + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, pb->name, pb->account); + if (conv != NULL) { + char *tmp = g_strdup_printf(_("%s has closed the conversation."), pb->name); + purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL)); + g_free(tmp); + } + /* Close the socket, clear the watcher and free memory */ + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; + } - /* Inform the user that the conversation has been closed */ - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, pb->name, pb->account); - if (conv != NULL) { - char *tmp = g_strdup_printf(_("%s has closed the conversation."), pb->name); - purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL)); - g_free(tmp); - } } void bonjour_jabber_stream_started(PurpleBuddy *pb) {
--- a/libpurple/protocols/bonjour/mdns_avahi.c Mon Sep 03 05:17:32 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_avahi.c Mon Sep 03 06:51:15 2007 +0000 @@ -33,7 +33,7 @@ #include <avahi-glib/glib-malloc.h> #include <avahi-glib/glib-watch.h> -/* For some reason, this is missing from the Avahi type defines */ +/* Avahi only defines the types that it actually uses (which at this time doesn't include NULL) */ #ifndef AVAHI_DNS_TYPE_NULL #define AVAHI_DNS_TYPE_NULL 0x0A #endif @@ -58,7 +58,8 @@ const char *host_name, const AvahiAddress *a, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *userdata) { - BonjourBuddy *buddy; + PurpleBuddy *pb; + BonjourBuddy *bb; PurpleAccount *account = userdata; AvahiStringList *l; size_t size; @@ -67,44 +68,62 @@ g_return_if_fail(r != NULL); + pb = purple_find_buddy(account, name); + bb = (pb != NULL) ? pb->proto_data : NULL; + switch (event) { case AVAHI_RESOLVER_FAILURE: purple_debug_error("bonjour", "_resolve_callback - Failure: %s\n", avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r)))); + avahi_service_resolver_free(r); + if (bb != NULL) { + /* We've already freed the resolver */ + if (r == ((AvahiBuddyImplData *)bb->mdns_impl_data)->resolver) + ((AvahiBuddyImplData *)bb->mdns_impl_data)->resolver = NULL; + purple_blist_remove_buddy(pb); + } break; case AVAHI_RESOLVER_FOUND: /* create a buddy record */ - buddy = bonjour_buddy_new(name, account); + if (bb == NULL) + bb = bonjour_buddy_new(name, account); - ((AvahiBuddyImplData *)buddy->mdns_impl_data)->resolver = r; + /* If we're reusing an existing buddy, make sure if it is a different resolver to clean up the old one. + * I don't think this should ever happen, but I'm afraid we might get events out of sequence. */ + if (((AvahiBuddyImplData *)bb->mdns_impl_data)->resolver != NULL + && ((AvahiBuddyImplData *)bb->mdns_impl_data)->resolver != r) { + avahi_service_resolver_free(((AvahiBuddyImplData *)bb->mdns_impl_data)->resolver); + } + ((AvahiBuddyImplData *)bb->mdns_impl_data)->resolver = r; + g_free(bb->ip); /* Get the ip as a string */ - buddy->ip = g_malloc(AVAHI_ADDRESS_STR_MAX); - avahi_address_snprint(buddy->ip, AVAHI_ADDRESS_STR_MAX, a); + bb->ip = g_malloc(AVAHI_ADDRESS_STR_MAX); + avahi_address_snprint(bb->ip, AVAHI_ADDRESS_STR_MAX, a); - buddy->port_p2pj = port; + bb->port_p2pj = port; /* Obtain the parameters from the text_record */ - clear_bonjour_buddy_values(buddy); - l = txt; - while (l != NULL) { - ret = avahi_string_list_get_pair(l, &key, &value, &size); - l = l->next; - if (ret < 0) + clear_bonjour_buddy_values(bb); + for(l = txt; l != NULL; l = l->next) { + if ((ret = avahi_string_list_get_pair(l, &key, &value, &size)) < 0) continue; - set_bonjour_buddy_value(buddy, key, value, size); + set_bonjour_buddy_value(bb, key, value, size); /* TODO: Since we're using the glib allocator, I think we * can use the values instead of re-copying them */ avahi_free(key); avahi_free(value); } - if (!bonjour_buddy_check(buddy)) - bonjour_buddy_delete(buddy); - else + if (!bonjour_buddy_check(bb)) { + if (pb != NULL) + purple_blist_remove_buddy(pb); + else + bonjour_buddy_delete(bb); + } else /* Add or update the buddy in our buddy list */ - bonjour_buddy_add_to_purple(buddy); + bonjour_buddy_add_to_purple(bb, pb); break; default: @@ -120,7 +139,7 @@ AvahiLookupResultFlags flags, void *userdata) { PurpleAccount *account = userdata; - PurpleBuddy *gb = NULL; + PurpleBuddy *pb = NULL; switch (event) { case AVAHI_BROWSER_FAILURE: @@ -132,7 +151,7 @@ /* A new peer has joined the network and uses iChat bonjour */ purple_debug_info("bonjour", "_browser_callback - new service\n"); /* Make sure it isn't us */ - if (g_ascii_strcasecmp(name, account->username) != 0) { + if (purple_utf8_strcasecmp(name, account->username) != 0) { if (!avahi_service_resolver_new(avahi_service_browser_get_client(b), interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, _resolver_callback, account)) { @@ -143,16 +162,12 @@ break; case AVAHI_BROWSER_REMOVE: purple_debug_info("bonjour", "_browser_callback - Remove service\n"); - gb = purple_find_buddy(account, name); - if (gb != NULL) { - bonjour_buddy_delete(gb->proto_data); - purple_blist_remove_buddy(gb); - } + pb = purple_find_buddy(account, name); + if (pb != NULL) + purple_blist_remove_buddy(pb); break; case AVAHI_BROWSER_ALL_FOR_NOW: case AVAHI_BROWSER_CACHE_EXHAUSTED: - purple_debug_warning("bonjour", "(Browser) %s\n", - event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW"); break; default: purple_debug_info("bonjour", "Unrecognized Service browser event: %d.\n", event);
--- a/libpurple/protocols/bonjour/mdns_howl.c Mon Sep 03 05:17:32 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_howl.c Mon Sep 03 06:51:15 2007 +0000 @@ -71,6 +71,7 @@ char value[SW_TEXT_RECORD_MAX_LEN]; sw_uint32 value_length; + /* TODO: We want to keep listening for updates*/ sw_discovery_cancel(discovery, oid); /* create a buddy record */ @@ -100,7 +101,7 @@ } /* Add or update the buddy in our buddy list */ - bonjour_buddy_add_to_purple(buddy); + bonjour_buddy_add_to_purple(buddy, NULL); return SW_OKAY; } @@ -149,10 +150,7 @@ purple_debug_info("bonjour", "_browser_reply --> Remove service\n"); gb = purple_find_buddy(account, name); if (gb != NULL) - { - bonjour_buddy_delete(gb->proto_data); purple_blist_remove_buddy(gb); - } break; case SW_DISCOVERY_BROWSE_RESOLVED: purple_debug_info("bonjour", "_browse_reply --> Resolved\n");
--- a/libpurple/protocols/bonjour/mdns_win32.c Mon Sep 03 05:17:32 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_win32.c Mon Sep 03 06:51:15 2007 +0000 @@ -79,23 +79,23 @@ uint32_t ttl, void *context) { - if (kDNSServiceErr_NoError != errorCode) + if (kDNSServiceErr_NoError != errorCode) { purple_debug_error("bonjour", "record query - callback error.\n"); - else if (flags & kDNSServiceFlagsAdd) - { + /* TODO: Probably should remove the buddy when this happens */ + } else if (flags & kDNSServiceFlagsAdd) { if (rrtype == kDNSServiceType_TXT) { /* New Buddy */ - BonjourBuddy *buddy = (BonjourBuddy*) context; - _mdns_parse_text_record(buddy, rdata, rdlen); - bonjour_buddy_add_to_purple(buddy); + BonjourBuddy *bb = (BonjourBuddy*) context; + _mdns_parse_text_record(bb, rdata, rdlen); + bonjour_buddy_add_to_purple(bb, NULL); } else if (rrtype == kDNSServiceType_NULL) { /* Buddy Icon response */ - BonjourBuddy *buddy = (BonjourBuddy*) context; - Win32BuddyImplData *idata = buddy->mdns_impl_data; + BonjourBuddy *bb = (BonjourBuddy*) context; + Win32BuddyImplData *idata = bb->mdns_impl_data; g_return_if_fail(idata != NULL); - bonjour_buddy_got_buddy_icon(buddy, rdata, rdlen); + bonjour_buddy_got_buddy_icon(bb, rdata, rdlen); /* We've got what we need; stop listening */ purple_input_remove(idata->null_query_handler); @@ -110,32 +110,34 @@ _mdns_resolve_host_callback(GSList *hosts, gpointer data, const char *error_message) { ResolveCallbackArgs* args = (ResolveCallbackArgs*)data; + BonjourBuddy* bb = args->buddy; - if (!hosts || !hosts->data) + if (!hosts || !hosts->data) { purple_debug_error("bonjour", "host resolution - callback error.\n"); - else { + bonjour_buddy_delete(bb); + } else { struct sockaddr_in *addr = (struct sockaddr_in*)g_slist_nth_data(hosts, 1); - BonjourBuddy* buddy = args->buddy; - Win32BuddyImplData *idata = buddy->mdns_impl_data; + Win32BuddyImplData *idata = bb->mdns_impl_data; g_return_if_fail(idata != NULL); - buddy->ip = g_strdup(inet_ntoa(addr->sin_addr)); + g_free(bb->ip); + bb->ip = g_strdup(inet_ntoa(addr->sin_addr)); /* finally, set up the continuous txt record watcher, and add the buddy to purple */ if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&idata->txt_query, kDNSServiceFlagsLongLivedQuery, kDNSServiceInterfaceIndexAny, args->full_service_name, kDNSServiceType_TXT, - kDNSServiceClass_IN, _mdns_record_query_callback, buddy)) { + kDNSServiceClass_IN, _mdns_record_query_callback, bb)) { - purple_debug_info("bonjour", "Found buddy %s at %s:%d\n", buddy->name, buddy->ip, buddy->port_p2pj); + purple_debug_info("bonjour", "Found buddy %s at %s:%d\n", bb->name, bb->ip, bb->port_p2pj); idata->txt_query_handler = purple_input_add(DNSServiceRefSockFD(idata->txt_query), PURPLE_INPUT_READ, _mdns_handle_event, idata->txt_query); - bonjour_buddy_add_to_purple(buddy); + bonjour_buddy_add_to_purple(bb, NULL); } else - bonjour_buddy_delete(buddy); + bonjour_buddy_delete(bb); } @@ -202,18 +204,19 @@ DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) { PurpleAccount *account = (PurpleAccount*)context; - PurpleBuddy *gb = NULL; + PurpleBuddy *pb = NULL; if (kDNSServiceErr_NoError != errorCode) purple_debug_error("bonjour", "service browser - callback error"); else if (flags & kDNSServiceFlagsAdd) { /* A presence service instance has been discovered... check it isn't us! */ - if (g_ascii_strcasecmp(serviceName, account->username) != 0) { + if (purple_utf8_strcasecmp(serviceName, account->username) != 0) { /* OK, lets go ahead and resolve it to add to the buddy list */ ResolveCallbackArgs *args = g_new0(ResolveCallbackArgs, 1); args->buddy = bonjour_buddy_new(serviceName, account); - if (kDNSServiceErr_NoError != DNSServiceResolve(&args->resolver, 0, 0, serviceName, regtype, replyDomain, _mdns_service_resolve_callback, args)) { + if (kDNSServiceErr_NoError != DNSServiceResolve(&args->resolver, 0, 0, serviceName, regtype, + replyDomain, _mdns_service_resolve_callback, args)) { bonjour_buddy_delete(args->buddy); g_free(args); purple_debug_error("bonjour", "service browser - failed to resolve service.\n"); @@ -226,11 +229,9 @@ } else { /* A peer has sent a goodbye packet, remove them from the buddy list */ purple_debug_info("bonjour", "service browser - remove notification\n"); - gb = purple_find_buddy(account, serviceName); - if (gb != NULL) { - bonjour_buddy_delete(gb->proto_data); - purple_blist_remove_buddy(gb); - } + pb = purple_find_buddy(account, serviceName); + if (pb != NULL) + purple_blist_remove_buddy(pb); } }
--- a/libpurple/protocols/oscar/oscarcommon.h Mon Sep 03 05:17:32 2007 +0000 +++ b/libpurple/protocols/oscar/oscarcommon.h Mon Sep 03 06:51:15 2007 +0000 @@ -30,7 +30,7 @@ #include "version.h" #include "notify.h" -#define OSCAR_DEFAULT_LOGIN_SERVER "login.oscar.aol.com" +#define OSCAR_DEFAULT_LOGIN_SERVER "login.messaging.aol.com" #define OSCAR_DEFAULT_LOGIN_PORT 5190 #ifndef _WIN32 #define OSCAR_DEFAULT_CUSTOM_ENCODING "ISO-8859-1"
--- a/pidgin/gtkconv.c Mon Sep 03 05:17:32 2007 +0000 +++ b/pidgin/gtkconv.c Mon Sep 03 06:51:15 2007 +0000 @@ -2768,6 +2768,18 @@ pidgin_conv_present_conversation(conv); } +static void +unseen_all_conv_menu_cb(GtkMenuItem *item, GList *list) +{ + g_return_if_fail(list != NULL); + /* Do not free the list from here. It will be freed from the + * 'destroy' callback on the menuitem. */ + while (list) { + pidgin_conv_present_conversation(list->data); + list = list->next; + } +} + guint pidgin_conversations_fill_menu(GtkWidget *menu, GList *convs) { @@ -2799,6 +2811,19 @@ ret++; } + if (convs->next) { + /* There are more than one conversation. Add an option to show all conversations. */ + GtkWidget *item; + GList *list = g_list_copy(convs); + + pidgin_separator(menu); + + item = gtk_menu_item_new_with_label(_("Show All")); + g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(unseen_all_conv_menu_cb), list); + g_signal_connect_swapped(G_OBJECT(item), "destroy", G_CALLBACK(g_list_free), list); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + } + return ret; }
--- a/pidgin/gtkimhtmltoolbar.c Mon Sep 03 05:17:32 2007 +0000 +++ b/pidgin/gtkimhtmltoolbar.c Mon Sep 03 06:51:15 2007 +0000 @@ -28,6 +28,7 @@ #include "imgstore.h" #include "notify.h" +#include "prefs.h" #include "request.h" #include "pidginstock.h" #include "util.h" @@ -1021,9 +1022,41 @@ if (menu) gtk_widget_destroy(menu); + purple_prefs_disconnect_by_handle(object); + G_OBJECT_CLASS(parent_class)->finalize (object); } +static void +switch_toolbar_view(GtkWidget *item, GtkIMHtmlToolbar *toolbar) +{ + purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/toolbar/wide", + !purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/toolbar/wide")); +} + +static gboolean +gtk_imhtmltoolbar_popup_menu(GtkWidget *widget, GdkEventButton *event, GtkIMHtmlToolbar *toolbar) +{ + GtkWidget *menu; + GtkWidget *item; + gboolean wide; + + if (event->button != 3) + return FALSE; + + wide = GTK_WIDGET_VISIBLE(toolbar->bold); + + menu = gtk_menu_new(); + item = gtk_menu_item_new_with_mnemonic(wide ? _("Group Items") : _("Ungroup Items")); + g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(switch_toolbar_view), toolbar); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + gtk_widget_show(item); + + gtk_menu_popup(GTK_MENU(menu), NULL, NULL, pidgin_menu_position_func_helper, + widget, event->button, event->time); + return TRUE; +} + /* Boring GTK+ stuff */ static void gtk_imhtmltoolbar_class_init (GtkIMHtmlToolbarClass *class) { @@ -1033,90 +1066,58 @@ gobject_class = (GObjectClass*) class; parent_class = gtk_type_class(GTK_TYPE_HBOX); gobject_class->finalize = gtk_imhtmltoolbar_finalize; + + purple_prefs_add_none(PIDGIN_PREFS_ROOT "/conversations/toolbar"); + purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/toolbar/wide", FALSE); } static void gtk_imhtmltoolbar_create_old_buttons(GtkIMHtmlToolbar *toolbar) { + GtkWidget *hbox; GtkWidget *button; - /* Bold */ - button = pidgin_pixbuf_toolbar_button_from_stock(GTK_STOCK_BOLD); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(do_bold), toolbar); - toolbar->bold = button; - - - /* Italic */ - button = pidgin_pixbuf_toolbar_button_from_stock(GTK_STOCK_ITALIC); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(do_italic), toolbar); - toolbar->italic = button; - - /* Underline */ - button = pidgin_pixbuf_toolbar_button_from_stock(GTK_STOCK_UNDERLINE); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(do_underline), toolbar); - toolbar->underline = button; - - - /* Strikethrough */ - button = pidgin_pixbuf_toolbar_button_from_stock(GTK_STOCK_STRIKETHROUGH); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(do_strikethrough), toolbar); - toolbar->strikethrough = button; - - /* Increase font size */ - button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_TEXT_LARGER); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(do_big), toolbar); - toolbar->larger_size = button; - - /* Decrease font size */ - button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_TEXT_SMALLER); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(do_small), toolbar); - toolbar->smaller_size = button; + struct { + char *stock; + gpointer callback; + GtkWidget **button; + const char *tooltip; + } buttons[] = { + {GTK_STOCK_BOLD, G_CALLBACK(do_bold), &toolbar->bold, _("Bold")}, + {GTK_STOCK_ITALIC, do_italic, &toolbar->italic, _("Italic")}, + {GTK_STOCK_UNDERLINE, do_underline, &toolbar->underline, _("Underline")}, + {GTK_STOCK_STRIKETHROUGH, do_strikethrough, &toolbar->strikethrough, _("Strikethrough")}, + {"", NULL, NULL, NULL}, + {PIDGIN_STOCK_TOOLBAR_TEXT_LARGER, do_big, &toolbar->larger_size, _("Increase Font Size")}, + {PIDGIN_STOCK_TOOLBAR_TEXT_SMALLER, do_small, &toolbar->smaller_size, _("Decrease Font Size")}, + {"", NULL, NULL, NULL}, + {PIDGIN_STOCK_TOOLBAR_FONT_FACE, toggle_font, &toolbar->font, _("Font Face")}, + {PIDGIN_STOCK_TOOLBAR_FGCOLOR, toggle_bg_color, &toolbar->bgcolor, _("Background Color")}, + {PIDGIN_STOCK_TOOLBAR_BGCOLOR, toggle_fg_color, &toolbar->fgcolor, _("Foreground Color")}, + {"", NULL, NULL, NULL}, + {PIDGIN_STOCK_CLEAR, clear_formatting_cb, &toolbar->clear, _("Reset Formatting")}, + {"", NULL, NULL, NULL}, + {PIDGIN_STOCK_TOOLBAR_INSERT_LINK, insert_link_cb, &toolbar->link, _("Insert Link")}, + {PIDGIN_STOCK_TOOLBAR_INSERT_IMAGE, insert_image_cb, &toolbar->image, _("Insert IM Image")}, + {PIDGIN_STOCK_TOOLBAR_SMILEY, insert_smiley_cb, &toolbar->smiley, _("Insert Smiley")}, + {NULL, NULL, NULL, NULL} + }; + int iter; - /* Font Face */ - - button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_FONT_FACE); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(toggle_font), toolbar); - toolbar->font = button; - - /* Foreground Color */ - button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_FGCOLOR); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(toggle_fg_color), toolbar); - toolbar->fgcolor = button; - - /* Background Color */ - button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_BGCOLOR); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(toggle_bg_color), toolbar); - toolbar->bgcolor = button; + hbox = gtk_hbox_new(FALSE, 0); - button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_INSERT_LINK); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(insert_link_cb), toolbar); - toolbar->link = button; - - /* Insert IM Image */ - button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_INSERT_IMAGE); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(insert_image_cb), toolbar); - toolbar->image = button; + for (iter = 0; buttons[iter].stock; iter++) { + if (buttons[iter].stock[0]) { + button = pidgin_pixbuf_toolbar_button_from_stock(buttons[iter].stock); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(buttons[iter].callback), toolbar); + *(buttons[iter].button) = button; + gtk_tooltips_set_tip(toolbar->tooltips, button, buttons[iter].tooltip, NULL); + } else + button = gtk_vseparator_new(); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); + } - /* Insert Smiley */ - button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_SMILEY); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(insert_smiley_cb), toolbar); - toolbar->smiley = button; - - /* Reset formatting */ - button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_SMILEY); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(clear_formatting_cb), toolbar); - toolbar->clear = button; + gtk_box_pack_start(GTK_BOX(toolbar), hbox, FALSE, FALSE, 0); + g_object_set_data(G_OBJECT(toolbar), "wide-view", hbox); } static void @@ -1140,10 +1141,23 @@ g_object_set(G_OBJECT(widget), "use-markup", TRUE, NULL); } +static void +imhtmltoolbar_view_pref_changed(const char *name, PurplePrefType type, + gconstpointer value, gpointer toolbar) +{ + if (value) { + gtk_widget_hide_all(g_object_get_data(G_OBJECT(toolbar), "lean-view")); + gtk_widget_show_all(g_object_get_data(G_OBJECT(toolbar), "wide-view")); + } else { + gtk_widget_hide_all(g_object_get_data(G_OBJECT(toolbar), "wide-view")); + gtk_widget_show_all(g_object_get_data(G_OBJECT(toolbar), "lean-view")); + } +} + static void gtk_imhtmltoolbar_init (GtkIMHtmlToolbar *toolbar) { - GtkWidget *hbox = GTK_WIDGET(toolbar); - GtkWidget *bbox; + GtkWidget *hbox = GTK_WIDGET(toolbar), *event = gtk_event_box_new(); + GtkWidget *bbox, *box = gtk_hbox_new(FALSE, 0); GtkWidget *image; GtkWidget *label; GtkWidget *insert_button; @@ -1177,7 +1191,6 @@ {NULL, NULL, FALSE} }; - toolbar->imhtml = NULL; toolbar->font_dialog = NULL; toolbar->fgcolor_dialog = NULL; @@ -1203,7 +1216,7 @@ gtk_label_set_use_markup(GTK_LABEL(label), TRUE); g_object_set_data(G_OBJECT(hbox), "font_label", label); gtk_box_pack_start(GTK_BOX(bbox), label, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), font_button, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(box), font_button, FALSE, FALSE, 0); gtk_widget_show_all(font_button); font_menu = gtk_menu_new(); @@ -1232,7 +1245,7 @@ /* Sep */ sep = gtk_vseparator_new(); - gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(box), sep, FALSE, FALSE, 0); gtk_widget_show_all(sep); /* Insert */ @@ -1244,7 +1257,7 @@ gtk_box_pack_start(GTK_BOX(bbox), image, FALSE, FALSE, 0); label = gtk_label_new_with_mnemonic(_("_Insert")); gtk_box_pack_start(GTK_BOX(bbox), label, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), insert_button, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(box), insert_button, FALSE, FALSE, 0); gtk_widget_show_all(insert_button); insert_menu = gtk_menu_new(); @@ -1277,6 +1290,18 @@ g_signal_connect(G_OBJECT(insert_button), "activate", G_CALLBACK(pidgin_menu_clicked), insert_menu); g_signal_connect(G_OBJECT(insert_menu), "deactivate", G_CALLBACK(pidgin_menu_deactivate), insert_button); toolbar->sml = NULL; + + gtk_box_pack_start(GTK_BOX(hbox), box, FALSE, FALSE, 0); + g_object_set_data(G_OBJECT(hbox), "lean-view", box); + + purple_prefs_connect_callback(toolbar, PIDGIN_PREFS_ROOT "/conversations/toolbar/wide", + imhtmltoolbar_view_pref_changed, toolbar); + purple_prefs_trigger_callback(PIDGIN_PREFS_ROOT "/conversations/toolbar/wide"); + + gtk_widget_add_events(event, GDK_BUTTON_PRESS_MASK); + gtk_box_pack_start(GTK_BOX(hbox), event, TRUE, TRUE, 0); + g_signal_connect(G_OBJECT(event), "button-press-event", G_CALLBACK(gtk_imhtmltoolbar_popup_menu), toolbar); + gtk_widget_show(event); } GtkWidget *gtk_imhtmltoolbar_new()