Mercurial > pidgin.yaz
diff pidgin/gtkutils.c @ 29471:d83ee160ffb6
propagate from branch 'im.pidgin.pidgin' (head eb9385f349a20856b9d3f9911dbc8024caa44052)
to branch 'im.pidgin.pidgin.next.minor' (head 439fb2dd7a285d9ca645f65f36ef0f037abe7311)
author | Elliott Sales de Andrade <qulogic@pidgin.im> |
---|---|
date | Wed, 19 Aug 2009 00:46:04 +0000 |
parents | d4036e0f58d6 |
children | dfd8d82313be 07718e5eb8ce 2dcff225172e |
line wrap: on
line diff
--- a/pidgin/gtkutils.c Mon Mar 02 06:51:50 2009 +0000 +++ b/pidgin/gtkutils.c Wed Aug 19 00:46:04 2009 +0000 @@ -54,6 +54,7 @@ #include "prpl.h" #include "request.h" #include "signals.h" +#include "sound.h" #include "util.h" #include "gtkaccount.h" @@ -358,7 +359,7 @@ } GtkWidget *pidgin_new_check_item(GtkWidget *menu, const char *str, - GtkSignalFunc sf, gpointer data, gboolean checked) + GCallback cb, gpointer data, gboolean checked) { GtkWidget *menuitem; menuitem = gtk_check_menu_item_new_with_mnemonic(str); @@ -368,8 +369,8 @@ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), checked); - if (sf) - g_signal_connect(G_OBJECT(menuitem), "activate", sf, data); + if (cb) + g_signal_connect(G_OBJECT(menuitem), "activate", cb, data); gtk_widget_show_all(menuitem); @@ -439,7 +440,7 @@ } -GtkWidget *pidgin_new_item_from_stock(GtkWidget *menu, const char *str, const char *icon, GtkSignalFunc sf, gpointer data, guint accel_key, guint accel_mods, char *mod) +GtkWidget *pidgin_new_item_from_stock(GtkWidget *menu, const char *str, const char *icon, GCallback cb, gpointer data, guint accel_key, guint accel_mods, char *mod) { GtkWidget *menuitem; /* @@ -456,8 +457,8 @@ if (menu) gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - if (sf) - g_signal_connect(G_OBJECT(menuitem), "activate", sf, data); + if (cb) + g_signal_connect(G_OBJECT(menuitem), "activate", cb, data); if (icon != NULL) { image = gtk_image_new_from_stock(icon, gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL)); @@ -525,7 +526,7 @@ GtkWidget *item = gtk_menu_get_active(GTK_MENU(menu)); if (p_item) (*p_item) = item; - return g_object_get_data(G_OBJECT(item), "aop_per_item_data"); + return item ? g_object_get_data(G_OBJECT(item), "aop_per_item_data") : NULL; } static void @@ -950,7 +951,7 @@ "accel changed, scheduling save.\n"); if (!accels_save_timer) - accels_save_timer = g_timeout_add(5000, pidgin_save_accels, + accels_save_timer = purple_timeout_add_seconds(5, pidgin_save_accels, NULL); } @@ -1464,7 +1465,7 @@ str); g_free(str); - return; + break; } buddy = purple_find_buddy(data->account, data->who); @@ -1494,7 +1495,7 @@ g_error_free(err); g_free(str); - return; + break; } id = purple_imgstore_add_with_id(filedata, size, data->filename); @@ -1627,7 +1628,7 @@ _("Set as buddy icon"), DND_BUDDY_ICON, (ft ? _("Send image file") : _("Insert in message")), (ft ? DND_FILE_TRANSFER : DND_IM_IMAGE), NULL); - gdk_pixbuf_unref(pb); + g_object_unref(G_OBJECT(pb)); return; } @@ -1677,9 +1678,11 @@ * send. The only logical one is "Application," but do we really want to send a binary and nothing else? * Probably not. I'll just give an error and return. */ /* The original patch sent the icon used by the launcher. That's probably wrong */ - purple_notify_error(NULL, NULL, _("Cannot send launcher"), _("You dragged a desktop launcher. " - "Most likely you wanted to send whatever this launcher points to instead of this launcher" - " itself.")); + purple_notify_error(NULL, NULL, _("Cannot send launcher"), + _("You dragged a desktop launcher. Most " + "likely you wanted to send the target " + "of this launcher instead of this " + "launcher itself.")); break; } purple_desktop_item_unref(item); @@ -1715,29 +1718,67 @@ { GtkIconSize icon_size = gtk_icon_size_from_name(size); GdkPixbuf *pixbuf = NULL; - - if (prim == PURPLE_STATUS_UNAVAILABLE) - pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_BUSY, - icon_size, "GtkWidget"); - else if (prim == PURPLE_STATUS_AWAY) - pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_AWAY, - icon_size, "GtkWidget"); - else if (prim == PURPLE_STATUS_EXTENDED_AWAY) - pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_XA, - icon_size, "GtkWidget"); - else if (prim == PURPLE_STATUS_INVISIBLE) - pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_INVISIBLE, - icon_size, "GtkWidget"); - else if (prim == PURPLE_STATUS_OFFLINE) - pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_OFFLINE, - icon_size, "GtkWidget"); - else - pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_AVAILABLE, - icon_size, "GtkWidget"); + const char *stock = pidgin_stock_id_from_status_primitive(prim); + + pixbuf = gtk_widget_render_icon (w, stock ? stock : PIDGIN_STOCK_STATUS_AVAILABLE, + icon_size, "GtkWidget"); return pixbuf; - } +static const char * +stock_id_from_status_primitive_idle(PurpleStatusPrimitive prim, gboolean idle) +{ + const char *stock = NULL; + switch (prim) { + case PURPLE_STATUS_UNSET: + stock = NULL; + break; + case PURPLE_STATUS_UNAVAILABLE: + stock = idle ? PIDGIN_STOCK_STATUS_BUSY_I : PIDGIN_STOCK_STATUS_BUSY; + break; + case PURPLE_STATUS_AWAY: + stock = idle ? PIDGIN_STOCK_STATUS_AWAY_I : PIDGIN_STOCK_STATUS_AWAY; + break; + case PURPLE_STATUS_EXTENDED_AWAY: + stock = idle ? PIDGIN_STOCK_STATUS_XA_I : PIDGIN_STOCK_STATUS_XA; + break; + case PURPLE_STATUS_INVISIBLE: + stock = PIDGIN_STOCK_STATUS_INVISIBLE; + break; + case PURPLE_STATUS_OFFLINE: + stock = idle ? PIDGIN_STOCK_STATUS_OFFLINE_I : PIDGIN_STOCK_STATUS_OFFLINE; + break; + default: + stock = idle ? PIDGIN_STOCK_STATUS_AVAILABLE_I : PIDGIN_STOCK_STATUS_AVAILABLE; + break; + } + return stock; +} + +const char * +pidgin_stock_id_from_status_primitive(PurpleStatusPrimitive prim) +{ + return stock_id_from_status_primitive_idle(prim, FALSE); +} + +const char * +pidgin_stock_id_from_presence(PurplePresence *presence) +{ + PurpleStatus *status; + PurpleStatusType *type; + PurpleStatusPrimitive prim; + gboolean idle; + + g_return_val_if_fail(presence, NULL); + + status = purple_presence_get_active_status(presence); + type = purple_status_get_type(status); + prim = purple_status_type_get_primitive(type); + + idle = purple_presence_is_idle(presence); + + return stock_id_from_status_primitive_idle(prim, idle); +} GdkPixbuf * pidgin_create_prpl_icon(PurpleAccount *account, PidginPrplIconSize size) @@ -2451,11 +2492,6 @@ dialog->callback = callback; dialog->data = data; - if (dialog->icon_filesel != NULL) { - gtk_window_present(GTK_WINDOW(dialog->icon_filesel)); - return NULL; - } - current_folder = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder"); #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ @@ -2948,7 +2984,7 @@ #endif } -GSList *minidialogs = NULL; +static GSList *minidialogs = NULL; static void * pidgin_utils_get_handle(void) @@ -3543,6 +3579,219 @@ return TRUE; } +static void +file_open_uri(GtkIMHtml *imhtml, const char *uri) +{ + /* Copied from gtkft.c:open_button_cb */ +#ifdef _WIN32 + /* If using Win32... */ + int code; + if (G_WIN32_HAVE_WIDECHAR_API()) { + wchar_t *wc_filename = g_utf8_to_utf16( + uri, -1, NULL, NULL, NULL); + + code = (int)ShellExecuteW(NULL, NULL, wc_filename, NULL, NULL, + SW_SHOW); + + g_free(wc_filename); + } else { + char *l_filename = g_locale_from_utf8( + uri, -1, NULL, NULL, NULL); + + code = (int)ShellExecuteA(NULL, NULL, l_filename, NULL, NULL, + SW_SHOW); + + g_free(l_filename); + } + + if (code == SE_ERR_ASSOCINCOMPLETE || code == SE_ERR_NOASSOC) + { + purple_notify_error(imhtml, NULL, + _("There is no application configured to open this type of file."), NULL); + } + else if (code < 32) + { + purple_notify_error(imhtml, NULL, + _("An error occurred while opening the file."), NULL); + purple_debug_warning("gtkutils", "filename: %s; code: %d\n", uri, code); + } +#else + char *command = NULL; + char *tmp = NULL; + GError *error = NULL; + + if (purple_running_gnome()) + { + char *escaped = g_shell_quote(uri); + command = g_strdup_printf("gnome-open %s", escaped); + g_free(escaped); + } + else if (purple_running_kde()) + { + char *escaped = g_shell_quote(uri); + + if (purple_str_has_suffix(uri, ".desktop")) + command = g_strdup_printf("kfmclient openURL %s 'text/plain'", escaped); + else + command = g_strdup_printf("kfmclient openURL %s", escaped); + g_free(escaped); + } + else + { + purple_notify_uri(NULL, uri); + return; + } + + if (purple_program_is_valid(command)) + { + gint exit_status; + if (!g_spawn_command_line_sync(command, NULL, NULL, &exit_status, &error)) + { + tmp = g_strdup_printf(_("Error launching %s: %s"), + uri, error->message); + purple_notify_error(imhtml, NULL, _("Unable to open file."), tmp); + g_free(tmp); + g_error_free(error); + } + if (exit_status != 0) + { + char *primary = g_strdup_printf(_("Error running %s"), command); + char *secondary = g_strdup_printf(_("Process returned error code %d"), + exit_status); + purple_notify_error(imhtml, NULL, primary, secondary); + g_free(tmp); + } + } +#endif +} + +#define FILELINKSIZE (sizeof("file://") - 1) +static gboolean +file_clicked_cb(GtkIMHtml *imhtml, GtkIMHtmlLink *link) +{ + const char *uri = gtk_imhtml_link_get_url(link) + FILELINKSIZE; + file_open_uri(imhtml, uri); + return TRUE; +} + +static gboolean +open_containing_cb(GtkIMHtml *imhtml, const char *url) +{ + char *dir = g_path_get_dirname(url + FILELINKSIZE); + file_open_uri(imhtml, dir); + g_free(dir); + return TRUE; +} + +static gboolean +file_context_menu(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu) +{ + GtkWidget *img, *item; + const char *url; + + url = gtk_imhtml_link_get_url(link); + + /* Open File */ + img = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU); + item = gtk_image_menu_item_new_with_mnemonic(_("_Open File")); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); + g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_link_activate), link); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + + /* Open Containing Directory */ +#if GTK_CHECK_VERSION(2,6,0) + img = gtk_image_new_from_stock(GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU); + item = gtk_image_menu_item_new_with_mnemonic(_("Open _Containing Directory")); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); +#else + item = gtk_menu_item_new_with_mnemonic(_("Open _Containing Directory")); +#endif + g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(open_containing_cb), (gpointer)url); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + + return TRUE; +} + +#define AUDIOLINKSIZE (sizeof("audio://") - 1) +static gboolean +audio_clicked_cb(GtkIMHtml *imhtml, GtkIMHtmlLink *link) +{ + const char *uri; + PidginConversation *conv = g_object_get_data(G_OBJECT(imhtml), "gtkconv"); + if (!conv) /* no playback in debug window */ + return TRUE; + uri = gtk_imhtml_link_get_url(link) + AUDIOLINKSIZE; + purple_sound_play_file(uri, NULL); + return TRUE; +} + +static void +savefile_write_cb(gpointer user_data, char *file) +{ + char *temp_file = user_data; + gchar *contents; + gsize length; + GError *error; + + if (!g_file_get_contents(temp_file, &contents, &length, &error)) { + purple_debug_error("gtkutils", "Unable to read contents of %s: %s\n", + temp_file, error->message); + g_error_free(error); + return; + } + + if (!purple_util_write_data_to_file_absolute(file, contents, length)) { + purple_debug_error("gtkutils", "Unable to write contents to %s\n", + file); + } +} + +static gboolean +save_file_cb(GtkWidget *item, const char *url) +{ + PidginConversation *conv = g_object_get_data(G_OBJECT(item), "gtkconv"); + if (!conv) + return TRUE; + purple_request_file(conv->active_conv, _("Save File"), NULL, TRUE, + G_CALLBACK(savefile_write_cb), NULL, + conv->active_conv->account, NULL, conv->active_conv, + (void *)url); + return TRUE; +} + +static gboolean +audio_context_menu(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu) +{ + GtkWidget *img, *item; + const char *url; + PidginConversation *conv = g_object_get_data(G_OBJECT(imhtml), "gtkconv"); + if (!conv) /* No menu in debug window */ + return TRUE; + + url = gtk_imhtml_link_get_url(link); + + /* Play Sound */ +#if GTK_CHECK_VERSION(2,6,0) + img = gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_MENU); + item = gtk_image_menu_item_new_with_mnemonic(_("_Play Sound")); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); +#else + item = gtk_menu_item_new_with_mnemonic(_("_Play Sound")); +#endif + g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_link_activate), link); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + + /* Save File */ + img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); + item = gtk_image_menu_item_new_with_mnemonic(_("_Save File")); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); + g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(save_file_cb), (gpointer)(url+AUDIOLINKSIZE)); + g_object_set_data(G_OBJECT(item), "gtkconv", conv); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + + return TRUE; +} + /* XXX: The following two functions are for demonstration purposes only! */ static gboolean open_dialog(GtkIMHtml *imhtml, GtkIMHtmlLink *link) @@ -3583,7 +3832,9 @@ if (tmp == NULL) return FALSE; + g_free(tmp); tmp = NULL; + if (!g_spawn_command_line_sync("gconftool-2 --all-dirs /desktop/gnome/url-handlers", &tmp, &err, NULL, NULL)) { @@ -3647,6 +3898,9 @@ gtk_imhtml_class_register_protocol("gopher://", url_clicked_cb, link_context_menu); gtk_imhtml_class_register_protocol("mailto:", url_clicked_cb, copy_email_address); + gtk_imhtml_class_register_protocol("file://", file_clicked_cb, file_context_menu); + gtk_imhtml_class_register_protocol("audio://", audio_clicked_cb, audio_context_menu); + /* Example custom URL handler. */ gtk_imhtml_class_register_protocol("open://", open_dialog, dummy); @@ -3673,6 +3927,9 @@ return; } + gtk_imhtml_class_register_protocol("audio://", NULL, NULL); + gtk_imhtml_class_register_protocol("file://", NULL, NULL); + gtk_imhtml_class_register_protocol("http://", NULL, NULL); gtk_imhtml_class_register_protocol("https://", NULL, NULL); gtk_imhtml_class_register_protocol("ftp://", NULL, NULL);