# HG changeset patch # User Elliott Sales de Andrade # Date 1246947933 0 # Node ID 39c6f1d0cf26192b017b64ded89c62d33662147f # Parent 740760605cc1bee6350ee49a77a40897dfbc1ae2 Install a custom GtkIMHtml procol handler for the "file://" type which opens the file by default, and also has a menu for opening the file or the directory that contains it. Someone should figure out the correct handle to use for purple_notify_error because GtkIMHtml doesn't close them (that I can see). Fixes #8254. diff -r 740760605cc1 -r 39c6f1d0cf26 pidgin/gtkutils.c --- a/pidgin/gtkutils.c Tue Jul 07 06:18:24 2009 +0000 +++ b/pidgin/gtkutils.c Tue Jul 07 06:25:33 2009 +0000 @@ -3578,6 +3578,135 @@ 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 */ + img = gtk_image_new_from_stock(GTK_STOCK_COPY, 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); + 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; +} + /* XXX: The following two functions are for demonstration purposes only! */ static gboolean open_dialog(GtkIMHtml *imhtml, GtkIMHtmlLink *link) @@ -3684,6 +3813,8 @@ 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); + /* Example custom URL handler. */ gtk_imhtml_class_register_protocol("open://", open_dialog, dummy);