From 926ee678fd39c7ee2c355579794c4b2e4ce7bfac Mon Sep 17 00:00:00 2001 From: Patrick McDermott Date: Mon, 30 Oct 2017 04:12:46 -0400 Subject: mq_web_view_normal_scheme_methods: Implement --- diff --git a/src/local.mk b/src/local.mk index 33cf992..2218f1a 100644 --- a/src/local.mk +++ b/src/local.mk @@ -17,3 +17,4 @@ marquee_SOURCES += \ include %reldir%/about/local.mk include %reldir%/toolbars/local.mk +include %reldir%/web-view-schemes/local.mk diff --git a/src/web-view-schemes/local.mk b/src/web-view-schemes/local.mk new file mode 100644 index 0000000..879ee6f --- /dev/null +++ b/src/web-view-schemes/local.mk @@ -0,0 +1,2 @@ +marquee_SOURCES += \ + %reldir%/normal.c diff --git a/src/web-view-schemes/normal.c b/src/web-view-schemes/normal.c new file mode 100644 index 0000000..3a0ccf2 --- /dev/null +++ b/src/web-view-schemes/normal.c @@ -0,0 +1,768 @@ +/* + * Web view members and methods for normal schemes (http, https, file, about) + * + * Copyright (C) 2017 Patrick McDermott + * + * This file is part of Marquee. + * + * Marquee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Marquee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Marquee. If not, see . + */ + +#include "schemes.h" + +#include + +#include +#include + +#include "../application.h" +#include "../config.h" +#include "../notebook.h" +#include "../tab-page.h" +#include "../web-view.h" + +static gchar * +rewrite_uri(MqWebViewScheme G_GNUC_UNUSED *scheme, const gchar *uri) +{ + if (g_str_has_prefix(uri, "about:")) { + return g_strconcat("mq-about:", uri + strlen("about:"), NULL); + } else { + return g_strdup(uri); + } +} + +static gchar * +display_uri(MqWebViewScheme G_GNUC_UNUSED *scheme, const gchar *uri) +{ + if (g_str_has_prefix(uri, "mq-about:")) { + return g_strconcat("about:", uri + strlen("mq-about:"), NULL); + } else { + return g_strdup(uri); + } +} + +#define WKCMA(ACTION) \ + WEBKIT_CONTEXT_MENU_ACTION_##ACTION + +static void +menu_open_link_activate_cb(GtkAction G_GNUC_UNUSED *action, MqWebView *web_view) +{ + MqWebViewNormalScheme *scheme; + + scheme = &mq_web_view_get_scheme(web_view)->normal; + + mq_web_view_load_uri(web_view, webkit_hit_test_result_get_link_uri( + scheme->hit_test_result)); +} + +static void +menu_open_link_tab_activate_cb(GtkAction G_GNUC_UNUSED *action, + MqWebView *web_view) +{ + MqWebViewNormalScheme *scheme; + + scheme = &mq_web_view_get_scheme(web_view)->normal; + + mq_notebook_insert_child( + MQ_NOTEBOOK(gtk_widget_get_parent(GTK_WIDGET( + mq_web_view_get_tab_page(web_view)))), + webkit_hit_test_result_get_link_uri(scheme->hit_test_result), + mq_web_view_get_tab_page(web_view), + !mq_config_get_boolean(mq_web_view_get_config(web_view), + "tabs.background")); +} + +static void +menu_open_link_win_activate_cb(GtkAction G_GNUC_UNUSED *action, + MqWebView *web_view) +{ + const gchar *uris[2] = { + webkit_hit_test_result_get_link_uri(mq_web_view_get_scheme( + web_view)->normal.hit_test_result), + NULL + }; + mq_application_add_window( + mq_tab_page_get_application(mq_web_view_get_tab_page(web_view)), + uris); +} + +static void +menu_open_image_activate_cb(GtkAction G_GNUC_UNUSED *action, + MqWebView *web_view) +{ + MqWebViewNormalScheme *scheme; + + scheme = &mq_web_view_get_scheme(web_view)->normal; + + mq_web_view_load_uri(web_view, webkit_hit_test_result_get_image_uri( + scheme->hit_test_result)); +} + +static void +menu_open_image_tab_activate_cb(GtkAction G_GNUC_UNUSED *action, + MqWebView *web_view) +{ + MqWebViewNormalScheme *scheme; + + scheme = &mq_web_view_get_scheme(web_view)->normal; + + mq_notebook_insert_child( + MQ_NOTEBOOK(gtk_widget_get_parent(GTK_WIDGET( + mq_web_view_get_tab_page(web_view)))), + webkit_hit_test_result_get_image_uri(scheme->hit_test_result), + mq_web_view_get_tab_page(web_view), + !mq_config_get_boolean(mq_web_view_get_config(web_view), + "tabs.background")); +} + +static void +menu_open_image_win_activate_cb(GtkAction G_GNUC_UNUSED *action, + MqWebView *web_view) +{ + const gchar *uris[2] = { + webkit_hit_test_result_get_image_uri(mq_web_view_get_scheme( + web_view)->normal.hit_test_result), + NULL + }; + mq_application_add_window( + mq_tab_page_get_application(mq_web_view_get_tab_page(web_view)), + uris); +} + +static void +menu_open_video_activate_cb(GtkAction G_GNUC_UNUSED *action, + MqWebView *web_view) +{ + MqWebViewNormalScheme *scheme; + + scheme = &mq_web_view_get_scheme(web_view)->normal; + + mq_web_view_load_uri(web_view, webkit_hit_test_result_get_media_uri( + scheme->hit_test_result)); +} + +static void +menu_open_video_tab_activate_cb(GtkAction G_GNUC_UNUSED *action, + MqWebView *web_view) +{ + MqWebViewNormalScheme *scheme; + + scheme = &mq_web_view_get_scheme(web_view)->normal; + + mq_notebook_insert_child( + MQ_NOTEBOOK(gtk_widget_get_parent(GTK_WIDGET( + mq_web_view_get_tab_page(web_view)))), + webkit_hit_test_result_get_media_uri(scheme->hit_test_result), + mq_web_view_get_tab_page(web_view), + !mq_config_get_boolean(mq_web_view_get_config(web_view), + "tabs.background")); +} + +static void +menu_open_video_win_activate_cb(GtkAction G_GNUC_UNUSED *action, + MqWebView *web_view) +{ + const gchar *uris[2] = { + webkit_hit_test_result_get_media_uri(mq_web_view_get_scheme( + web_view)->normal.hit_test_result), + NULL + }; + mq_application_add_window( + mq_tab_page_get_application(mq_web_view_get_tab_page(web_view)), + uris); +} + +static void +menu_open_audio_activate_cb(GtkAction G_GNUC_UNUSED *action, + MqWebView *web_view) +{ + MqWebViewNormalScheme *scheme; + + scheme = &mq_web_view_get_scheme(web_view)->normal; + + mq_web_view_load_uri(web_view, webkit_hit_test_result_get_media_uri( + scheme->hit_test_result)); +} + +static void +menu_open_audio_tab_activate_cb(GtkAction G_GNUC_UNUSED *action, + MqWebView *web_view) +{ + MqWebViewNormalScheme *scheme; + + scheme = &mq_web_view_get_scheme(web_view)->normal; + + mq_notebook_insert_child( + MQ_NOTEBOOK(gtk_widget_get_parent(GTK_WIDGET( + mq_web_view_get_tab_page(web_view)))), + webkit_hit_test_result_get_media_uri(scheme->hit_test_result), + mq_web_view_get_tab_page(web_view), + !mq_config_get_boolean(mq_web_view_get_config(web_view), + "tabs.background")); +} + +static void +menu_open_audio_win_activate_cb(GtkAction G_GNUC_UNUSED *action, + MqWebView *web_view) +{ + const gchar *uris[2] = { + webkit_hit_test_result_get_media_uri(mq_web_view_get_scheme( + web_view)->normal.hit_test_result), + NULL + }; + mq_application_add_window( + mq_tab_page_get_application(mq_web_view_get_tab_page(web_view)), + uris); +} + +#define ITEM_DECLS \ + GtkAction *action; \ + WebKitContextMenuItem *menu_item; +#define ITEM_DECLS_NO_CUSTOM \ + WebKitContextMenuItem *menu_item; +#define NEW_CUSTOM_ITEM(NAME, LABEL) \ + G_STMT_START { \ + /* Don't blame me; blame WebKitGTK+ for using GtkAction. */ \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + action = gtk_action_new(#NAME, (LABEL), NULL, NULL); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + g_signal_connect(action, "activate", \ + G_CALLBACK(menu_##NAME##_activate_cb), web_view); \ + menu_item = webkit_context_menu_item_new(action); \ + webkit_context_menu_append(context_menu, menu_item); \ + } G_STMT_END +#define NEW_STOCK_ITEM(STOCK) \ + G_STMT_START { \ + menu_item = webkit_context_menu_item_new_from_stock_action( \ + WEBKIT_CONTEXT_MENU_ACTION_##STOCK); \ + webkit_context_menu_append(context_menu, menu_item); \ + } G_STMT_END +#define NEW_SEPARATOR_ITEM() \ + G_STMT_START { \ + webkit_context_menu_append(context_menu, \ + webkit_context_menu_item_new_separator()); \ + } G_STMT_END +#define RESTORE_ITEMS(ITEMS) \ + G_STMT_START { \ + for (; ITEMS; ITEMS = ITEMS->next) { \ + webkit_context_menu_append(context_menu, ITEMS->data); \ + g_object_unref(ITEMS->data); \ + } \ + } G_STMT_END + +static void +context_menu_link_cb(WebKitContextMenu *context_menu, MqWebView *web_view) +{ + ITEM_DECLS + + NEW_CUSTOM_ITEM(open_link, "_Open Link"); + NEW_CUSTOM_ITEM(open_link_tab, "Open Link in New _Tab"); + NEW_CUSTOM_ITEM(open_link_win, "Open Link in New _Window"); + NEW_SEPARATOR_ITEM(); /* --- */ + NEW_STOCK_ITEM(DOWNLOAD_LINK_TO_DISK); /* _Download Linked File */ + NEW_STOCK_ITEM(COPY_LINK_TO_CLIPBOARD); /* Copy Link Loc_ation */ +} + +static void +context_menu_image_cb(WebKitContextMenu *context_menu, MqWebView *web_view) +{ + ITEM_DECLS + + NEW_CUSTOM_ITEM(open_image, "Open _Image"); + NEW_CUSTOM_ITEM(open_image_tab, "Open Image in New Tab"); + NEW_CUSTOM_ITEM(open_image_win, "Open Image in New Window"); + NEW_SEPARATOR_ITEM(); /* --- */ + NEW_STOCK_ITEM(DOWNLOAD_IMAGE_TO_DISK); /* Sa_ve Image As */ + NEW_STOCK_ITEM(COPY_IMAGE_TO_CLIPBOARD); /* Cop_y Image */ + NEW_STOCK_ITEM(COPY_IMAGE_URL_TO_CLIPBOARD); /* Copy Image _Address */ +} + +static void +context_menu_media_cb(WebKitContextMenu *context_menu, GList *media_ctrl_items, + GList *media_toggle_items, gboolean is_video, MqWebView *web_view) +{ + ITEM_DECLS + + /* _Play/_Pause, _Mute */ + RESTORE_ITEMS(media_ctrl_items); + /* _Toggle Media Controls, Toggle Media _Loop Playback, Switch Video to + * _Fullscreen */ + RESTORE_ITEMS(media_toggle_items); + NEW_SEPARATOR_ITEM(); /* --- */ + if (is_video) { + NEW_CUSTOM_ITEM(open_video, "_Open Video"); + NEW_CUSTOM_ITEM(open_video_tab, "Open Video in New Tab"); + NEW_CUSTOM_ITEM(open_video_win, "Open Video in New Window"); + NEW_SEPARATOR_ITEM(); /* --- */ + NEW_STOCK_ITEM(DOWNLOAD_VIDEO_TO_DISK); /* Download _Video */ + /* Cop_y Video Link Location */ + NEW_STOCK_ITEM(COPY_VIDEO_LINK_TO_CLIPBOARD); + } else { + NEW_CUSTOM_ITEM(open_audio, "_Open Audio"); + NEW_CUSTOM_ITEM(open_audio_tab, "Open Audio in New Tab"); + NEW_CUSTOM_ITEM(open_audio_win, "Open Audio in New Window"); + NEW_SEPARATOR_ITEM(); /* --- */ + NEW_STOCK_ITEM(DOWNLOAD_AUDIO_TO_DISK); /* Download _Audio */ + /* Cop_y Audio Link Location */ + NEW_STOCK_ITEM(COPY_AUDIO_LINK_TO_CLIPBOARD); + } +} + +static void +context_menu_editable_cb(WebKitContextMenu *context_menu, + GList *spell_repl_items, GList *spell_ctrl_items, GList *edit_items, + GList *input_items, MqWebView G_GNUC_UNUSED *web_view) +{ + ITEM_DECLS_NO_CUSTOM + + RESTORE_ITEMS(spell_repl_items); /* Spelling suggestions */ + NEW_SEPARATOR_ITEM(); /* --- */ + RESTORE_ITEMS(spell_ctrl_items); /* _Ignore Spelling, _Learn Spelling */ + NEW_SEPARATOR_ITEM(); /* --- */ + RESTORE_ITEMS(edit_items); /* Cu_t, _Copy, _Paste, _Delete */ + NEW_SEPARATOR_ITEM(); /* --- */ + NEW_STOCK_ITEM(SELECT_ALL); /* Select _All */ + NEW_SEPARATOR_ITEM(); /* --- */ + RESTORE_ITEMS(input_items); /* _Insert Unicode Character */ +} +static void +context_menu_document_cb(WebKitContextMenu *context_menu, GList *nav_items, + MqWebView G_GNUC_UNUSED *web_view) +{ + ITEM_DECLS_NO_CUSTOM + + RESTORE_ITEMS(nav_items); /* _Back, _Forward, _Stop, _Reload */ + NEW_SEPARATOR_ITEM(); /* --- */ + NEW_STOCK_ITEM(SELECT_ALL); /* Select _All */ + NEW_SEPARATOR_ITEM(); /* --- */ + /* View Page Source */ +} + +#define PRESERVE_ITEM(ITEMS) \ + G_STMT_START { \ + g_object_ref(items->data); \ + ITEMS = g_list_prepend(ITEMS, items->data); \ + } G_STMT_END + +static gboolean +context_menu(MqWebView *web_view, MqWebViewScheme G_GNUC_UNUSED *scheme, + WebKitContextMenu *context_menu, GdkEvent G_GNUC_UNUSED *event, + WebKitHitTestResult *hit_test_result) +{ + GList *items; + GList *nav_items; + GList *edit_items; + GList *input_items; + GList *spell_repl_items; + GList *spell_ctrl_items; + GList *media_ctrl_items; + GList *media_toggle_items; + gboolean is_selection; + gboolean is_video; + WebKitContextMenuAction stock_action; + WebKitHitTestResultContext context; + gboolean context_handled; + WebKitContextMenuItem *menu_item; + + /* Get more hints about the context, since WebKit doesn't describe + * context very well in hit test results. Also, preserve menu items + * that aren't easy to reproduce (e.g. the Unicode menu and spelling + * guesses). */ + items = webkit_context_menu_get_items(context_menu); + nav_items = NULL; + edit_items = NULL; + input_items = NULL; + spell_repl_items = NULL; + spell_ctrl_items = NULL; + media_ctrl_items = NULL; + media_toggle_items = NULL; + is_selection = FALSE; + is_video = FALSE; + for (; items; items = items->next) { + stock_action = webkit_context_menu_item_get_stock_action( + items->data); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" + switch (stock_action) { + case WKCMA(GO_BACK): + case WKCMA(GO_FORWARD): + case WKCMA(STOP): + case WKCMA(RELOAD): + PRESERVE_ITEM(nav_items); + break; + case WKCMA(COPY): + PRESERVE_ITEM(edit_items); + is_selection = TRUE; + break; + case WKCMA(CUT): + case WKCMA(PASTE): + case WKCMA(DELETE): + PRESERVE_ITEM(edit_items); + break; + case WKCMA(INPUT_METHODS): + case WKCMA(UNICODE): + PRESERVE_ITEM(input_items); + break; + case WKCMA(SPELLING_GUESS): + case WKCMA(NO_GUESSES_FOUND): + PRESERVE_ITEM(spell_repl_items); + break; + case WKCMA(IGNORE_SPELLING): + case WKCMA(LEARN_SPELLING): + case WKCMA(IGNORE_GRAMMAR): + PRESERVE_ITEM(spell_ctrl_items); + break; + case WKCMA(OPEN_VIDEO_IN_NEW_WINDOW): + case WKCMA(COPY_VIDEO_LINK_TO_CLIPBOARD): + case WKCMA(DOWNLOAD_VIDEO_TO_DISK): + is_video = TRUE; + break; + case WKCMA(OPEN_AUDIO_IN_NEW_WINDOW): + case WKCMA(COPY_AUDIO_LINK_TO_CLIPBOARD): + case WKCMA(DOWNLOAD_AUDIO_TO_DISK): + is_video = FALSE; + break; + case WKCMA(TOGGLE_MEDIA_CONTROLS): + case WKCMA(TOGGLE_MEDIA_LOOP): + case WKCMA(ENTER_VIDEO_FULLSCREEN): + PRESERVE_ITEM(media_toggle_items); + break; + case WKCMA(MEDIA_PLAY): + case WKCMA(MEDIA_PAUSE): + case WKCMA(MEDIA_MUTE): + PRESERVE_ITEM(media_ctrl_items); + break; + } +#pragma GCC diagnostic pop + } + nav_items = g_list_reverse(nav_items); + edit_items = g_list_reverse(edit_items); + input_items = g_list_reverse(input_items); + spell_repl_items = g_list_reverse(spell_repl_items); + spell_ctrl_items = g_list_reverse(spell_ctrl_items); + media_ctrl_items = g_list_reverse(media_ctrl_items); + media_toggle_items = g_list_reverse(media_toggle_items); + + /* Clear the menu. */ + webkit_context_menu_remove_all(context_menu); + + /* Get the reported context (which isn't very descriptive) and save the + * hit test result for use by action callbacks. */ + context = webkit_hit_test_result_get_context(hit_test_result); + if (scheme->normal.hit_test_result) { + g_object_unref(scheme->normal.hit_test_result); + } + scheme->normal.hit_test_result = hit_test_result; + g_object_ref(scheme->normal.hit_test_result); + context_handled = FALSE; + + /* Build the context menu. */ + if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK) { + context_menu_link_cb(context_menu, web_view); + context_handled = TRUE; + } + if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) { + if (context_handled) { + NEW_SEPARATOR_ITEM(); + } + context_menu_image_cb(context_menu, web_view); + context_handled = TRUE; + } + if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA) { + context_menu_media_cb(context_menu, media_ctrl_items, + media_toggle_items, is_video, web_view); + context_handled = TRUE; + } + if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE) { + context_menu_editable_cb(context_menu, spell_repl_items, + spell_ctrl_items, edit_items, input_items, web_view); + context_handled = TRUE; + } + if (!context_handled && + context & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT) { + if (is_selection) { + RESTORE_ITEMS(edit_items); /* _Copy */ + context_handled = TRUE; + } else { + context_menu_document_cb(context_menu, nav_items, + web_view); + context_handled = TRUE; + } + } + if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT) { + if (context_handled) { + NEW_SEPARATOR_ITEM(); + } + NEW_STOCK_ITEM(INSPECT_ELEMENT); /* Inspect Element */ + } + + /* Propagate the event further and show the context menu. */ + return FALSE; +} + +static void +save_html_replace_cb(GFile *file, GAsyncResult *result, guchar *data) +{ + g_file_replace_contents_finish(file, result, NULL, NULL); + /* TODO: Error handling? */ + g_free(data); +} + +static void +save_html_get_data_cb(WebKitWebResource *resource, GAsyncResult *result, + MqWebView *web_view) +{ + MqWebViewNormalScheme *scheme; + guchar *data; + gsize length; + + scheme = &mq_web_view_get_scheme(web_view)->normal; + + data = webkit_web_resource_get_data_finish(resource, result, &length, + NULL); /* TODO: Error handling? */ + g_file_replace_contents_async(scheme->save_file, + (gchar *) data, length, + NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL, + (GAsyncReadyCallback) save_html_replace_cb, data); +} + +static void +save_mhtml_cb(WebKitWebView *web_view, GAsyncResult *result) +{ + webkit_web_view_save_to_file_finish(web_view, result, NULL); +} + +static gchar * +get_extension(gchar *filename) +{ + gchar *extension; + + extension = strrchr(filename, '.'); + if (extension) { + return extension; + } else { + return filename + strlen(filename); + } +} + +static gboolean +extension_is_html(const gchar *extension) +{ + return + extension[0] == '.' && + extension[1] == 'h' && + extension[2] == 't' && + extension[3] == 'm' && + (extension[4] == '\0' || + (extension[4] == 'l' && + extension[5] == '\0')); +} + +static gboolean +extension_is_mhtml(const gchar *extension) +{ + return + extension[0] == '.' && + extension[1] == 'm' && + extension[2] == 'h' && + extension[3] == 't' && + (extension[4] == '\0' || + (extension[4] == 'm' && + (extension[5] == '\0' || + (extension[5] == 'l' && + extension[6] == '\0')))); +} + +static void +save_html(MqWebView *web_view, GFile *file) +{ + mq_web_view_get_scheme(web_view)->normal.save_file = file; + webkit_web_resource_get_data( + webkit_web_view_get_main_resource(WEBKIT_WEB_VIEW(web_view)), + NULL, (GAsyncReadyCallback) save_html_get_data_cb, web_view); +} + +static void +save_mhtml(MqWebView *web_view, GFile *file) +{ + webkit_web_view_save_to_file(WEBKIT_WEB_VIEW(web_view), file, + WEBKIT_SAVE_MODE_MHTML, NULL, + (GAsyncReadyCallback) save_mhtml_cb, NULL); +} + +static gchar * +get_clean_title(MqWebView *web_view) +{ + const gchar *title; + + title = webkit_web_view_get_title(WEBKIT_WEB_VIEW(web_view)); + if (!title || title[0] == '\0') { + title = mq_web_view_get_uri(web_view); + } + if (!title || title[0] == '\0') { + title = "page"; + } + return g_strdelimit(g_strdup(title), +#ifdef G_OS_WIN32 + "/\\:*\"?<>|", +#else + "/", +#endif + '_'); +} + +static void +save_type_changed_cb(GtkComboBox *combo_box, GtkFileChooser *chooser) +{ + gchar *name; + gchar *extension; + const gchar *active_id; + gchar *new_name; + + name = gtk_file_chooser_get_current_name(chooser); + extension = get_extension(name); + + active_id = gtk_combo_box_get_active_id(combo_box); + if (g_strcmp0(active_id, "html") == 0) { + if (!extension_is_html(extension)) { + /* Extension is not "htm" or "html". */ + extension[0] = '\0'; /* Remove extension. */ + new_name = g_strconcat(name, ".html", NULL); + gtk_file_chooser_set_current_name(chooser, new_name); + g_free(new_name); + } + } else if (g_strcmp0(active_id, "mhtml") == 0) { + if (!extension_is_mhtml(extension)) { + /* Extension is not "mht", "mhtm", or "mhtml". */ + extension[0] = '\0'; /* Remove extension. */ + new_name = g_strconcat(name, ".mhtml", NULL); + gtk_file_chooser_set_current_name(chooser, new_name); + g_free(new_name); + } + } + + g_free(name); +} + +static void +save_response_cb(GtkWidget *dialog, gint response_id, MqWebView *web_view) +{ + MqWebViewNormalScheme *scheme; + gchar *dir; + gchar *filename; + GFile *file; + gchar *extension; + const gchar *active_id; + + scheme = &mq_web_view_get_scheme(web_view)->normal; + + if (response_id == GTK_RESPONSE_ACCEPT) { + dir = gtk_file_chooser_get_current_folder( + GTK_FILE_CHOOSER(dialog)); + if (dir) { + mq_config_set_string(mq_web_view_get_config(web_view), + "directories.downloads", dir); + g_free(dir); + mq_config_save(mq_web_view_get_config(web_view)); + } + + filename = gtk_file_chooser_get_filename( + GTK_FILE_CHOOSER(dialog)); + file = g_file_new_for_path(filename); + + active_id = gtk_combo_box_get_active_id( + scheme->save_type_combo_box); + if (g_strcmp0(active_id, "detect") == 0) { + extension = get_extension(filename); + if (extension_is_html(extension)) { + save_html(web_view, file); + } else { + save_mhtml(web_view, file); + } + } else if (g_strcmp0(active_id, "html") == 0) { + save_html(web_view, file); + } else if (g_strcmp0(active_id, "mhtml") == 0) { + save_mhtml(web_view, file); + } + + g_free(filename); + } + + gtk_widget_destroy(dialog); +} + +static void +save_file(MqWebView *web_view, MqWebViewScheme *scheme) +{ + GtkWidget *dialog; + GtkFileChooser *chooser; + gchar *dir; + gchar *title; + gchar *filename; + GtkWidget *type_combo_box; + GtkWidget *type_box; + + dialog = gtk_file_chooser_dialog_new("Save File", + GTK_WINDOW(mq_tab_page_get_window( + mq_web_view_get_tab_page(web_view))), + GTK_FILE_CHOOSER_ACTION_SAVE, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Save", GTK_RESPONSE_ACCEPT, + NULL); + chooser = GTK_FILE_CHOOSER(dialog); + + gtk_file_chooser_set_do_overwrite_confirmation(chooser, TRUE); + + dir = mq_config_get_string(mq_web_view_get_config(web_view), + "directories.downloads"); + gtk_file_chooser_set_current_folder(chooser, dir); + g_free(dir); + + title = get_clean_title(web_view); + filename = g_strconcat(title, ".mhtml", NULL); + g_free(title); + gtk_file_chooser_set_current_name(chooser, filename); + g_free(filename); + + mq_web_view_add_html_mhtml_file_chooser_filters(chooser); + + type_combo_box = gtk_combo_box_text_new(); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(type_combo_box), + "detect", "By extension"); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(type_combo_box), + "html", "HTML document only"); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(type_combo_box), + "mhtml", "MHTML archive with associated resources"); + gtk_combo_box_set_active(GTK_COMBO_BOX(type_combo_box), 0); + g_signal_connect(type_combo_box, "changed", + G_CALLBACK(save_type_changed_cb), chooser); + scheme->normal.save_type_combo_box = GTK_COMBO_BOX(type_combo_box); + + type_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_pack_start(GTK_BOX(type_box), + gtk_label_new("Save as file type:"), FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(type_box), type_combo_box, FALSE, FALSE, 0); + gtk_file_chooser_set_extra_widget(chooser, type_box); + + g_signal_connect(dialog, "response", + G_CALLBACK(save_response_cb), web_view); + gtk_widget_show_all(dialog); +} + +MqWebViewSchemeMethods mq_web_view_normal_scheme_methods = { + .rewrite_uri = rewrite_uri, + .display_uri = display_uri, + .context_menu = context_menu, + .save_file = save_file, +}; -- cgit v0.9.1