/*
* Web view members and methods for normal schemes (http, https, file)
*
* 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
#include "../application.h"
#include "../config/config.h"
#include "../config/settings.h"
#include "../i18n.h"
#include "../notebook.h"
#include "../tab-page.h"
#include "../web-view.h"
static MqSettings *settings = NULL;
static gboolean
match_uri(const gchar *uri)
{
/* This is a catch-all scheme handler, so match any schemes not handled
* by another handler. */
return !uri || (!g_str_has_prefix(uri, "view-source:") &&
!g_str_has_prefix(uri, "about:") &&
!g_str_has_prefix(uri, "mq-about:"));
}
static void
init_settings(MqConfig *config)
{
if (settings) {
return;
}
settings = mq_settings_new();
mq_settings_set_web_context(settings, webkit_web_context_get_default());
mq_settings_connect_config(settings, config);
}
static void
initialize(MqWebView *web_view, MqWebViewScheme G_GNUC_UNUSED *scheme,
const gchar G_GNUC_UNUSED *uri)
{
init_settings(mq_web_view_get_config(web_view));
webkit_web_view_set_settings(WEBKIT_WEB_VIEW(web_view),
WEBKIT_SETTINGS(settings));
}
static void
finalize(MqWebViewScheme *scheme)
{
memset(&scheme->normal, 0, sizeof(scheme->normal));
}
static gchar *
rewrite_uri(MqWebView G_GNUC_UNUSED *web_view,
MqWebViewScheme G_GNUC_UNUSED *scheme, const gchar *uri)
{
return g_strdup(uri);
}
static gchar *
display_uri(MqWebView G_GNUC_UNUSED *web_view,
MqWebViewScheme G_GNUC_UNUSED *scheme, const gchar *uri)
{
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);
}
static void
menu_view_source_activate_cb(GtkAction G_GNUC_UNUSED *action,
MqWebView *web_view)
{
mq_notebook_insert_child(
MQ_NOTEBOOK(gtk_widget_get_parent(GTK_WIDGET(
mq_web_view_get_tab_page(web_view)))),
g_strdup_printf("view-source:origin-tab=%" PRId64 "&uri=%s",
mq_tab_page_get_id(mq_web_view_get_tab_page(web_view)),
mq_web_view_get_uri(web_view)),
mq_web_view_get_tab_page(web_view),
!mq_config_get_boolean(mq_web_view_get_config(web_view),
"tabs.background"));
}
#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
RESTORE_ITEMS(nav_items); /* _Back, _Forward, _Stop, _Reload */
NEW_SEPARATOR_ITEM(); /* --- */
NEW_STOCK_ITEM(SELECT_ALL); /* Select _All */
NEW_SEPARATOR_ITEM(); /* --- */
NEW_CUSTOM_ITEM(view_source, _("View Page So_urce"));
}
#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;
default:
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 = {
.match_uri = match_uri,
.initialize = initialize,
.finalize = finalize,
.rewrite_uri = rewrite_uri,
.display_uri = display_uri,
.context_menu = context_menu,
.save_file = save_file,
};