summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McDermott <pj@pehjota.net>2017-10-11 17:16:38 (EDT)
committer Patrick McDermott <pj@pehjota.net>2017-10-11 17:21:46 (EDT)
commitf6c63159857a99d0871584c4e56832b5e5188058 (patch)
tree1b549fadbd55eabd6b71a1cc7f7ceb11836385e9
parent73b0e25d31adabfaeee3a69b84624595a32aabd8 (diff)
downloadmarquee-f6c63159857a99d0871584c4e56832b5e5188058.zip
marquee-f6c63159857a99d0871584c4e56832b5e5188058.tar.gz
marquee-f6c63159857a99d0871584c4e56832b5e5188058.tar.bz2
MqWebView: New class
-rw-r--r--src/local.mk1
-rw-r--r--src/web-view.c653
-rw-r--r--src/web-view.h66
3 files changed, 720 insertions, 0 deletions
diff --git a/src/local.mk b/src/local.mk
index b838bd8..2bb4584 100644
--- a/src/local.mk
+++ b/src/local.mk
@@ -7,6 +7,7 @@ marquee_SOURCES += \
%reldir%/tab.c \
%reldir%/tab-chrome.c \
%reldir%/tab-body.c \
+ %reldir%/web-view.c \
%reldir%/html.c \
%reldir%/gpl-3-0.c \
%reldir%/about.c
diff --git a/src/web-view.c b/src/web-view.c
new file mode 100644
index 0000000..0feaeb9
--- /dev/null
+++ b/src/web-view.c
@@ -0,0 +1,653 @@
+/*
+ * Web view
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <webkit2/webkit2.h>
+
+#include "web-view.h"
+#include "tab.h"
+
+struct _MqWebView {
+ WebKitWebView parent_instance;
+ MqTab *tab;
+ const gchar *uri;
+ WebKitHitTestResult *hit_test_result;
+ WebKitHitTestResult *mouse_target_hit_test_result;
+};
+
+enum {
+ PROP_TAB = 1,
+ PROP_URI,
+ N_PROPERTIES
+};
+
+static GParamSpec *obj_properties[N_PROPERTIES] = {NULL,};
+
+struct _MqWebViewClass {
+ WebKitWebViewClass parent_class;
+};
+
+G_DEFINE_TYPE(MqWebView, mq_web_view, WEBKIT_TYPE_WEB_VIEW)
+
+#define PARENT_CLASS WEBKIT_WEB_VIEW_CLASS(mq_web_view_parent_class)
+
+#define WKCMA(ACTION) \
+ WEBKIT_CONTEXT_MENU_ACTION_##ACTION
+
+static void
+get_property(GObject *object, guint property_id, GValue *value,
+ GParamSpec G_GNUC_UNUSED *pspec)
+{
+ MqWebView *web_view;
+
+ web_view = MQ_WEB_VIEW(object);
+
+ switch (property_id) {
+ case PROP_TAB:
+ g_value_set_pointer(value, web_view->tab);
+ break;
+ case PROP_URI:
+ g_value_set_string(value, web_view->uri); /* TODO */
+ break;
+ }
+}
+
+static void
+set_property(GObject *object, guint property_id, const GValue *value,
+ GParamSpec G_GNUC_UNUSED *pspec)
+{
+ MqWebView *web_view;
+
+ web_view = MQ_WEB_VIEW(object);
+
+ switch (property_id) {
+ case PROP_TAB:
+ web_view->tab = g_value_get_pointer(value);
+ break;
+ case PROP_URI:
+ web_view->uri = g_value_get_string(value);
+ break;
+ }
+}
+
+static void
+menu_open_link_activate_cb(GtkAction G_GNUC_UNUSED *action, MqWebView *web_view)
+{
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view),
+ webkit_hit_test_result_get_link_uri(
+ web_view->hit_test_result));
+}
+
+static void
+menu_open_link_tab_activate_cb(GtkAction G_GNUC_UNUSED *action,
+ MqWebView *web_view)
+{
+ mq_tab_new_relative(
+ webkit_hit_test_result_get_link_uri(web_view->hit_test_result),
+ web_view->tab);
+}
+
+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(web_view->hit_test_result),
+ NULL
+ };
+ mq_application_add_window(web_view->tab->application, uris);
+}
+
+static void
+menu_open_image_activate_cb(GtkAction G_GNUC_UNUSED *action,
+ MqWebView *web_view)
+{
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view),
+ webkit_hit_test_result_get_image_uri(
+ web_view->hit_test_result));
+}
+
+static void
+menu_open_image_tab_activate_cb(GtkAction G_GNUC_UNUSED *action,
+ MqWebView *web_view)
+{
+ mq_tab_new_relative(
+ webkit_hit_test_result_get_image_uri(web_view->hit_test_result),
+ web_view->tab);
+}
+
+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(web_view->hit_test_result),
+ NULL
+ };
+ mq_application_add_window(web_view->tab->application, uris);
+}
+
+static void
+menu_open_video_activate_cb(GtkAction G_GNUC_UNUSED *action,
+ MqWebView *web_view)
+{
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view),
+ webkit_hit_test_result_get_media_uri(
+ web_view->hit_test_result));
+}
+
+static void
+menu_open_video_tab_activate_cb(GtkAction G_GNUC_UNUSED *action,
+ MqWebView *web_view)
+{
+ mq_tab_new_relative(
+ webkit_hit_test_result_get_media_uri(web_view->hit_test_result),
+ web_view->tab);
+}
+
+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(web_view->hit_test_result),
+ NULL
+ };
+ mq_application_add_window(web_view->tab->application, uris);
+}
+
+static void
+menu_open_audio_activate_cb(GtkAction G_GNUC_UNUSED *action,
+ MqWebView *web_view)
+{
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view),
+ webkit_hit_test_result_get_media_uri(
+ web_view->hit_test_result));
+}
+
+static void
+menu_open_audio_tab_activate_cb(GtkAction G_GNUC_UNUSED *action,
+ MqWebView *web_view)
+{
+ mq_tab_new_relative(
+ webkit_hit_test_result_get_media_uri(web_view->hit_test_result),
+ web_view->tab);
+}
+
+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(web_view->hit_test_result),
+ NULL
+ };
+ mq_application_add_window(web_view->tab->application, uris);
+}
+
+#define ITEM_DECLS \
+ GtkAction *action; \
+ WebKitContextMenuItem *menu_item;
+#define ITEM_DECLS_NO_CUSTOM \
+ WebKitContextMenuItem *menu_item;
+#define NEW_CUSTOM_ITEM(NAME, LABEL) \
+ do { \
+ /* 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); \
+ } 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)
+#define NEW_SEPARATOR_ITEM() \
+ do { \
+ webkit_context_menu_append(context_menu, \
+ webkit_context_menu_item_new_separator()); \
+ } while (0)
+#define RESTORE_ITEMS(ITEMS) \
+ do { \
+ for (; ITEMS; ITEMS = ITEMS->next) { \
+ webkit_context_menu_append(context_menu, ITEMS->data); \
+ g_object_unref(ITEMS->data); \
+ } \
+ } while (0)
+
+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) \
+ do { \
+ g_object_ref(items->data); \
+ ITEMS = g_list_prepend(ITEMS, items->data); \
+ } while (0)
+
+static gboolean
+context_menu(WebKitWebView *wk_web_view, WebKitContextMenu *context_menu,
+ GdkEvent *event, WebKitHitTestResult *hit_test_result)
+{
+ MqWebView *web_view;
+ 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;
+
+ web_view = MQ_WEB_VIEW(wk_web_view);
+
+ /* 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 (web_view->hit_test_result) {
+ g_object_unref(web_view->hit_test_result);
+ }
+ web_view->hit_test_result = hit_test_result;
+ g_object_ref(web_view->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 PARENT_CLASS->context_menu(WEBKIT_WEB_VIEW(web_view),
+ context_menu, event, hit_test_result);
+}
+
+static void
+clipboard_text_recv_cb(GtkClipboard G_GNUC_UNUSED *clipboard,
+ const gchar *text, MqWebView *web_view)
+{
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view), text);
+}
+
+/* This callback is a hack to determine on middle mouse click whether to open a
+ * link in a new tab or to load a URI from the primary clipboard. The WebKit1
+ * API provided webkit_web_view_get_hit_test_result() which would have been
+ * easier. */
+static void
+mouse_target_changed(WebKitWebView *wk_web_view,
+ WebKitHitTestResult *hit_test_result, guint G_GNUC_UNUSED modifiers)
+{
+ MqWebView *web_view;
+
+ web_view = MQ_WEB_VIEW(wk_web_view);
+
+ web_view->mouse_target_hit_test_result = hit_test_result;
+ g_object_ref(web_view->mouse_target_hit_test_result);
+}
+
+static gboolean
+button_press_event(GtkWidget *widget, GdkEventButton *event)
+{
+ MqWebView *web_view;
+ WebKitHitTestResult *hit_test_result;
+ GtkClipboard *clipboard;
+
+ web_view = MQ_WEB_VIEW(widget);
+
+ /* Make sure this is a middle mouse button press event. */
+ if (event->button != 2) {
+ return GTK_WIDGET_CLASS(mq_web_view_parent_class)->
+ button_press_event(widget, event);
+ }
+
+ hit_test_result = web_view->mouse_target_hit_test_result;
+
+ if (webkit_hit_test_result_context_is_link(hit_test_result)) {
+ mq_tab_new_relative(
+ webkit_hit_test_result_get_link_uri(hit_test_result),
+ web_view->tab);
+ } else if (webkit_hit_test_result_context_is_editable(hit_test_result)){
+ /* Let WebKit handle pasting from the primary clipboard into an
+ * editable element. */
+ g_object_unref(hit_test_result);
+ return GTK_WIDGET_CLASS(mq_web_view_parent_class)->
+ button_press_event(widget, event);
+ } else {
+ clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
+ gtk_clipboard_request_text(clipboard,
+ (GtkClipboardTextReceivedFunc) clipboard_text_recv_cb,
+ web_view);
+ }
+
+ g_object_unref(hit_test_result);
+
+ return TRUE;
+}
+
+static void
+mq_web_view_class_init(MqWebViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+
+ object_class->get_property = get_property;
+ object_class->set_property = set_property;
+ widget_class->button_press_event = button_press_event;
+ PARENT_CLASS->context_menu = context_menu;
+ PARENT_CLASS->mouse_target_changed = mouse_target_changed;
+
+ obj_properties[PROP_TAB] = g_param_spec_pointer(
+ "tab", "MqTab", "Parent MqTab instance",
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
+ obj_properties[PROP_URI] = g_param_spec_string(
+ "uri", "URI", "URI to load",
+ "",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
+ g_object_class_install_properties(object_class, N_PROPERTIES,
+ obj_properties);
+}
+
+static void
+mq_web_view_init(MqWebView *web_view)
+{
+ gchar *rw_uri;
+ MqConfig *config;
+ gchar *new_tab_page;
+
+ webkit_web_view_set_settings(WEBKIT_WEB_VIEW(web_view),
+ mq_application_get_webkit_settings(
+ mq_tab_get_application(web_view->tab)));
+
+ if (web_view->uri) {
+ if (g_str_has_prefix(web_view->uri, "about:")) {
+ rw_uri = g_strconcat("mq-about:",
+ web_view->uri + strlen("about:"), NULL);
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view),
+ rw_uri);
+ g_free(rw_uri);
+ } else {
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view),
+ web_view->uri);
+ }
+ } else {
+ config = mq_application_get_config(
+ mq_tab_get_application(web_view->tab));
+ new_tab_page = mq_config_get_string(config, "tabs.new");
+ if (g_strcmp0(new_tab_page, "home") == 0) {
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view),
+ mq_config_get_string(config, "tabs.home"));
+ } else if (g_strcmp0(new_tab_page, "blank") == 0) {
+ /* Don't load any URI. */
+ } else {
+ g_assert_not_reached();
+ }
+ }
+
+ webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(web_view),
+ mq_config_get_double(
+ mq_application_get_config(
+ mq_tab_get_application(web_view->tab)),
+ "zoom.default"));
+
+ gtk_widget_set_vexpand(GTK_WIDGET(web_view), TRUE);
+ /* FIXME: This doesn't seem to be working. */
+ gtk_widget_grab_focus(GTK_WIDGET(web_view));
+
+ web_view->hit_test_result = NULL;
+}
+
+MqWebView *
+mq_web_view_new(MqTab *tab, const gchar *uri)
+{
+ return g_object_new(MQ_TYPE_WEB_VIEW,
+ "tab", tab, /* TODO: Use gtk_widget_get_parent() instead? */
+ "uri", uri,
+ NULL);
+}
+
+GtkWidget *
+mq_web_view_get_container(MqWebView *web_view)
+{
+ return GTK_WIDGET(web_view);
+}
+
+WebKitWebView *
+mq_web_view_get_web_view(MqWebView *web_view)
+{
+ return WEBKIT_WEB_VIEW(web_view);
+}
diff --git a/src/web-view.h b/src/web-view.h
new file mode 100644
index 0000000..b8c498d
--- /dev/null
+++ b/src/web-view.h
@@ -0,0 +1,66 @@
+/*
+ * Web view
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MQ_WEB_VIEW_H
+#define MQ_WEB_VIEW_H
+
+#include <gtk/gtk.h>
+#include <webkit2/webkit2.h>
+
+// #include "gtype.h"
+#include "tab.h"
+
+G_BEGIN_DECLS
+
+// #define MQ_TYPE_WEB_VIEW (mq_web_view_get_type())
+// G_DECLARE_FINAL_TYPE(MqWebView, mq_web_view, MQ, WEB_VIEW, WebKitWebView)
+
+#define MQ_TYPE_WEB_VIEW (mq_web_view_get_type())
+#define MQ_WEB_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ MQ_TYPE_WEB_VIEW, MqWebView))
+#define MQ_IS_WEB_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ MQ_TYPE_WEB_VIEW))
+#define MQ_WEB_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+ MQ_TYPE_WEB_VIEW, MqWebViewClass))
+#define MQ_IS_WEB_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \
+ MQ_TYPE_WEB_VIEW))
+#define MQ_WEB_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ MQ_TYPE_WEB_VIEW, MqWebViewClass))
+
+typedef struct _MqWebView MqWebView;
+typedef struct _MqWebViewClass MqWebViewClass;
+
+GType
+mq_web_view_get_type(void);
+
+MqWebView *
+mq_web_view_new(MqTab *tab, const gchar *uri);
+
+/* Temporary compatibility methods */
+
+GtkWidget *
+mq_web_view_get_container(MqWebView *body);
+WebKitWebView *
+mq_web_view_get_web_view(MqWebView *body);
+
+G_END_DECLS
+
+#endif /* MQ_WEB_VIEW_H */