/* * 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 void finalize(MqWebViewScheme *scheme) { memset(&scheme->view_source, 0, sizeof(scheme->view_source)); } static gboolean match_uri(const gchar *uri) { return uri && g_str_has_prefix(uri, "view-source:"); } static gchar * rewrite_uri(MqWebView *web_view, MqWebViewScheme *scheme, const gchar *uri) { MqTabPage *origin_tab; 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 and data. */ scheme->view_source.uri = mq_web_view_get_uri( mq_tab_page_get_web_view(origin_tab)); /* TODO: Get data. */ /* Rewrite URI. */ return g_strdup_printf("view-source:view-tab=%" PRId64, mq_tab_page_get_id(mq_web_view_get_tab_page(web_view))); } 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, .finalize = finalize, .rewrite_uri = rewrite_uri, .display_uri = display_uri, .context_menu = context_menu, .save_file = save_file, };