/*
* Tab body
*
* 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
#include
#include
#include "tab-body.h"
#include "tab.h"
#define WKCMA(ACTION) \
WEBKIT_CONTEXT_MENU_ACTION_##ACTION
static void
menu_open_link_activate_cb(GtkAction __attribute__((unused)) *action,
MqTabBody *body)
{
webkit_web_view_load_uri(body->web_view,
webkit_hit_test_result_get_link_uri(body->hit_test_result));
}
static void
menu_open_link_tab_activate_cb(GtkAction __attribute__((unused)) *action,
MqTabBody *body)
{
g_print("Open Link in New Tab\n");
}
static void
menu_open_link_win_activate_cb(GtkAction __attribute__((unused)) *action,
MqTabBody *body)
{
g_print("Open Link in New Window\n");
}
static void
menu_open_image_activate_cb(GtkAction __attribute__((unused)) *action,
MqTabBody *body)
{
webkit_web_view_load_uri(body->web_view,
webkit_hit_test_result_get_image_uri(body->hit_test_result));
}
static void
menu_open_image_tab_activate_cb(GtkAction __attribute__((unused)) *action,
MqTabBody *body)
{
g_print("Open Image in New Tab\n");
}
static void
menu_open_image_win_activate_cb(GtkAction __attribute__((unused)) *action,
MqTabBody *body)
{
g_print("Open Image in New Window\n");
}
#define ITEM_BEGIN_DECLS \
GtkAction *action; \
WebKitContextMenuItem *menu_item; \
/* Don't blame me; blame WebKitGTK+ for using GtkAction. */ \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
#define ITEM_BEGIN_DECLS_NO_CUSTOM \
WebKitContextMenuItem *menu_item; \
_Pragma("GCC diagnostic push")
#define ITEM_END_DECLS \
_Pragma("GCC diagnostic pop")
#define NEW_CUSTOM_ITEM(NAME, LABEL) \
do { \
action = gtk_action_new(#NAME, (LABEL), NULL, NULL); \
g_signal_connect(action, "activate", \
G_CALLBACK(menu_##NAME##_activate_cb), body); \
menu_item = webkit_context_menu_item_new(action); \
webkit_context_menu_append(context_menu, menu_item); \
} while (0)
#define NEW_STOCK_ITEM(STOCK) \
do { \
menu_item = webkit_context_menu_item_new_from_stock_action( \
WEBKIT_CONTEXT_MENU_ACTION_##STOCK); \
webkit_context_menu_append(context_menu, menu_item); \
} while (0)
static void
context_menu_link_cb(WebKitContextMenu *context_menu, MqTabBody *body)
{
ITEM_BEGIN_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_STOCK_ITEM(DOWNLOAD_LINK_TO_DISK); /* Download Linked File */
NEW_STOCK_ITEM(COPY_LINK_TO_CLIPBOARD); /* Copy Link Location */
ITEM_END_DECLS
}
static void
context_menu_image_cb(WebKitContextMenu *context_menu, MqTabBody *body)
{
ITEM_BEGIN_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_STOCK_ITEM(DOWNLOAD_IMAGE_TO_DISK); /* Save Image As */
NEW_STOCK_ITEM(COPY_IMAGE_TO_CLIPBOARD); /* Copy Image */
NEW_STOCK_ITEM(COPY_IMAGE_URL_TO_CLIPBOARD); /* Copy Image Address */
ITEM_END_DECLS
}
static void
context_menu_document_cb(WebKitContextMenu *context_menu, MqTabBody *body)
{
ITEM_BEGIN_DECLS_NO_CUSTOM
NEW_STOCK_ITEM(GO_BACK); /* Back */
NEW_STOCK_ITEM(GO_FORWARD); /* Forward */
NEW_STOCK_ITEM(STOP); /* Stop */
NEW_STOCK_ITEM(RELOAD); /* Reload */
NEW_STOCK_ITEM(NO_ACTION); /* --- */
NEW_STOCK_ITEM(SELECT_ALL); /* Select All */
NEW_STOCK_ITEM(NO_ACTION); /* --- */
/* View Page Source */
ITEM_END_DECLS
}
static gboolean
context_menu_cb(WebKitWebView __attribute__((unused)) *web_view,
WebKitContextMenu *context_menu,
GdkEvent __attribute__((unused)) *event,
WebKitHitTestResult *hit_test_result, MqTabBody *body)
{
GList *items;
GList *input_items;
GList *spell_items;
gboolean is_selection;
gboolean is_video;
WebKitContextMenuAction stock_action;
WebKitHitTestResultContext context;
gboolean context_handled;
/* 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);
input_items = NULL;
spell_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(COPY):
is_selection = TRUE;
break;
case WKCMA(INPUT_METHODS):
case WKCMA(UNICODE):
input_items = g_list_prepend(input_items,
items->data);
break;
case WKCMA(SPELLING_GUESS):
case WKCMA(NO_GUESSES_FOUND):
case WKCMA(IGNORE_SPELLING):
case WKCMA(LEARN_SPELLING):
case WKCMA(IGNORE_GRAMMAR):
spell_items = g_list_prepend(spell_items,
items->data);
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(MEDIA_PLAY):
case WKCMA(MEDIA_PAUSE):
break;
}
#pragma GCC diagnostic pop
}
webkit_context_menu_remove_all(context_menu);
context = webkit_hit_test_result_get_context(hit_test_result);
if (body->hit_test_result) {
g_object_unref(body->hit_test_result);
}
body->hit_test_result = hit_test_result;
g_object_ref(body->hit_test_result);
context_handled = FALSE;
g_print("Context menu, hit test:");
if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK) {
context_menu_link_cb(context_menu, body);
context_handled = TRUE;
}
if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) {
context_menu_image_cb(context_menu, body);
context_handled = TRUE;
}
if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA) {
if (is_video) {
/* Play / Pause (preserved)
* Mute (stock)
* Toggle Media Controls (stock?)
* Toggle Media Loop Playback (stock?)
* Switch Video to Fullscreen (stock)
* ---
* Copy Video Link Location (stock)
* Open Video
* Open Video in New Tab
* Open Video in New Window
* Download Video (stock) */
g_print(" video");
context_handled = TRUE;
} else {
/* Play / Pause (preserved)
* Mute (stock)
* Toggle Media Controls (stock?)
* Toggle Media Loop Playback (stock?)
* ---
* Copy Audio Link Location (stock)
* Open Audio
* Open Audio in New Tab
* Open Audio in New Window
* Download Audio (stock) */
g_print(" audio");
context_handled = TRUE;
}
}
if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE) {
/* Cut (stock)
* Copy (stock)
* Paste (stock)
* Delete (stock)
* ---
* Select All (stock)
* Insert Unicode Character (preserved) */
g_print(" editable");
context_handled = TRUE;
}
if (!context_handled &&
context & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT) {
if (is_selection) {
g_print(" selection");
} else {
context_menu_document_cb(context_menu, body);
}
}
g_print("\n");
if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT) {
/* ---
* Inspect Element (stock) */
}
return FALSE;
}
MqTabBody *
mq_tab_body_new(MqTab *tab, gchar *uri)
{
MqTabBody *body;
body = malloc(sizeof(*body));
body->tab = tab;
body->web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
if (uri) {
webkit_web_view_load_uri(body->web_view, uri);
}
body->container = GTK_WIDGET(body->web_view);
gtk_widget_set_vexpand(body->container, TRUE);
/* FIXME: This doesn't seem to be working. */
gtk_widget_grab_focus(body->container);
body->hit_test_result = NULL;
g_signal_connect(body->web_view, "context-menu",
G_CALLBACK(context_menu_cb), body);
return body;
}
GtkWidget *
mq_tab_body_get_container(MqTabBody *body)
{
return body->container;
}
WebKitWebView *
mq_tab_body_get_web_view(MqTabBody *body)
{
return body->web_view;
}