/*
* Web view members and methods for "view-source" scheme
*
* 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.h"
#include "../string-utils.h"
#include "../tab-page.h"
#include "../web-view.h"
static gboolean
match_uri(const gchar *uri)
{
return uri && g_str_has_prefix(uri, "view-source:");
}
static void
initialize(MqWebView *web_view, MqWebViewScheme *scheme, const gchar *uri)
{
MqTabPage *origin_tab;
/* TODO: Handle "view-source:URI" URIs. */
g_assert(g_str_has_prefix(uri, "view-source:origin-tab="));
/* Parse origin tab ID out of URI. */
uri += strlen("view-source:origin-tab=");
scheme->view_source.origin_tab_id = atoi64(uri);
/* Look up origin tab. */
origin_tab = mq_application_get_tab(mq_tab_page_get_application(
mq_web_view_get_tab_page(web_view)),
scheme->view_source.origin_tab_id);
/* Get origin tab's URI. */
scheme->view_source.uri = mq_web_view_get_uri(
mq_tab_page_get_web_view(origin_tab));
}
static void
finalize(MqWebViewScheme *scheme)
{
memset(&scheme->view_source, 0, sizeof(scheme->view_source));
}
static gchar *
rewrite_uri(MqWebView G_GNUC_UNUSED *web_view, MqWebViewScheme *scheme,
const gchar G_GNUC_UNUSED *uri)
{
/* TODO: Handle reloads and missing origin tab IDs (i.e. user loaded
* "view-source:URI"). */
return g_strdup_printf("view-source:origin-tab=%" PRId64,
scheme->view_source.origin_tab_id);
}
static gchar *
display_uri(MqWebView G_GNUC_UNUSED *web_view, MqWebViewScheme *scheme,
const gchar G_GNUC_UNUSED *uri)
{
return g_strdup_printf("view-source:%s", scheme->view_source.uri);
}
#define WKCMA(ACTION) \
WEBKIT_CONTEXT_MENU_ACTION_##ACTION
#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_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(); /* --- */
}
#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;
gboolean is_selection;
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;
is_selection = 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;
}
#pragma GCC diagnostic pop
}
nav_items = g_list_reverse(nav_items);
edit_items = g_list_reverse(edit_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_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_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_file(MqWebView *web_view, MqWebViewScheme *scheme)
{
/* TODO: Stub */
mq_web_view_get_scheme(web_view);
*scheme = *scheme;
}
MqWebViewSchemeMethods mq_web_view_view_source_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,
};