summaryrefslogtreecommitdiffstats
path: root/src/tab-chrome.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tab-chrome.c')
-rw-r--r--src/tab-chrome.c1017
1 files changed, 0 insertions, 1017 deletions
diff --git a/src/tab-chrome.c b/src/tab-chrome.c
deleted file mode 100644
index 3a57f4b..0000000
--- a/src/tab-chrome.c
+++ /dev/null
@@ -1,1017 +0,0 @@
-/*
- * Tab chrome
- *
- * 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 <gtk/gtk.h>
-#include <webkit2/webkit2.h>
-
-#include "tab-chrome.h"
-#include "tab.h"
-
-static void
-back_clicked_cb(GtkButton G_GNUC_UNUSED *toolbutton, MqTabChrome *chrome)
-{
- webkit_web_view_go_back(chrome->web_view);
-}
-
-static void
-forward_clicked_cb(GtkButton G_GNUC_UNUSED *toolbutton, MqTabChrome *chrome)
-{
- webkit_web_view_go_forward(chrome->web_view);
-}
-
-static GtkWidget *
-back_forward_list_item_new(WebKitBackForwardListItem *list_item,
- gint type)
-{
- GtkWidget *label;
- GtkWidget *icon_stack;
- GtkWidget *icon;
- GtkWidget *box;
-
- label = gtk_label_new(webkit_back_forward_list_item_get_title(
- list_item));
- gtk_widget_set_halign(label, GTK_ALIGN_START);
-
- icon_stack = gtk_stack_new();
- switch (type) {
- case 0:
- icon = gtk_radio_button_new(NULL);
- gtk_stack_add_named(GTK_STACK(icon_stack), icon,
- "current");
- gtk_widget_set_can_focus(icon, FALSE);
- gtk_stack_add_named(GTK_STACK(icon_stack),
- gtk_image_new_from_icon_name("go-previous",
- GTK_ICON_SIZE_BUTTON), "back");
- break;
- case -1:
- gtk_stack_add_named(GTK_STACK(icon_stack),
- gtk_image_new_from_icon_name("go-previous",
- GTK_ICON_SIZE_BUTTON), "back");
- gtk_stack_add_named(GTK_STACK(icon_stack),
- gtk_radio_button_new(NULL), "current");
- break;
- case 1:
- gtk_stack_add_named(GTK_STACK(icon_stack),
- gtk_image_new_from_icon_name("go-next",
- GTK_ICON_SIZE_BUTTON), "forward");
- gtk_stack_add_named(GTK_STACK(icon_stack),
- gtk_radio_button_new(NULL), "current");
- break;
- }
-
- box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
- gtk_box_pack_start(GTK_BOX(box), icon_stack, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
- gtk_widget_set_tooltip_text(box,
- webkit_back_forward_list_item_get_uri(list_item));
-
- return box;
-}
-
-static void
-back_forward_list_box_row_activated_cb(GtkListBox G_GNUC_UNUSED *box,
- GtkListBoxRow *row, MqTabChrome *chrome)
-{
- webkit_web_view_go_to_back_forward_list_item(chrome->web_view,
- webkit_back_forward_list_get_nth_item(
- webkit_web_view_get_back_forward_list(chrome->web_view),
- gtk_list_box_row_get_index(row) - chrome->back_items));
-
- gtk_widget_hide(chrome->back_forward_popover);
-}
-
-static void
-back_forward_toggle_button_toggled_cb(GtkToggleButton *toggle_button,
- GtkStack *stack)
-{
- /* Use gtk_widget_show() and gtk_widget_hide() instead of
- * gtk_stack_set_visible_child() so that the stack fits the size of only
- * the visible child. */
- gtk_widget_show_all(gtk_stack_get_child_by_name(stack,
- gtk_toggle_button_get_active(toggle_button) ?
- "text" : "list"));
- gtk_widget_hide(gtk_stack_get_child_by_name(stack,
- gtk_toggle_button_get_active(toggle_button) ?
- "list" : "text"));
-}
-
-static gboolean
-back_forward_box_button_press_cb(GtkWidget *widget, GdkEvent *event,
- MqTabChrome *chrome)
-{
- WebKitBackForwardList *back_forward_list;
- GtkWidget *list_box;
- GtkWidget *text_view;
- GtkTextBuffer *text_buffer;
- GList *list_item;
- GtkTextIter text_iter;
- gchar *str;
- GtkTextTag *text_tag;
- GtkWidget *list_scrolled_window;
- GtkWidget *text_scrolled_window;
- GtkWidget *stack;
- GtkWidget *toggle_button;
- GtkWidget *box;
-
- /* Make sure this is a mouse button press event. Either the middle or
- * right button is OK. */
- if (event->type != GDK_BUTTON_PRESS) {
- return FALSE;
- }
-
- /* Get the back/forward list for the Web view. */
- back_forward_list = webkit_web_view_get_back_forward_list(
- chrome->web_view);
-
- /* Set up the list box. */
- list_box = gtk_list_box_new();
- gtk_list_box_set_selection_mode(GTK_LIST_BOX(list_box),
- GTK_SELECTION_BROWSE);
- gtk_list_box_set_activate_on_single_click(GTK_LIST_BOX(list_box), TRUE);
- g_signal_connect(list_box, "row-activated",
- G_CALLBACK(back_forward_list_box_row_activated_cb), chrome);
-
- /* Set up the text view. */
- text_view = gtk_text_view_new();
- text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
- gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view), FALSE);
-
- /* Insert forward list items. */
- /* The forward list is backwards, so we need to prepend each item to our
- * list box and text buffer. */
- list_item = webkit_back_forward_list_get_forward_list(
- back_forward_list);
- for (; list_item; list_item = list_item->next) {
- gtk_list_box_prepend(GTK_LIST_BOX(list_box),
- back_forward_list_item_new(list_item->data, 1));
- gtk_text_buffer_get_start_iter(text_buffer, &text_iter);
- str = g_strdup_printf("\n%s",
- webkit_back_forward_list_item_get_uri(list_item->data));
- gtk_text_buffer_insert(text_buffer, &text_iter, str, -1);
- g_free(str);
- }
-
- /* Insert the current item. */
- gtk_list_box_prepend(GTK_LIST_BOX(list_box), back_forward_list_item_new(
- webkit_back_forward_list_get_current_item(
- back_forward_list), 0));
- gtk_list_box_select_row(GTK_LIST_BOX(list_box),
- gtk_list_box_get_row_at_index(GTK_LIST_BOX(list_box), 0));
- gtk_text_buffer_get_start_iter(text_buffer, &text_iter);
- text_tag = gtk_text_buffer_create_tag(text_buffer, NULL, "weight",
- PANGO_WEIGHT_BOLD, NULL);
- gtk_text_buffer_insert_with_tags(text_buffer, &text_iter,
- webkit_back_forward_list_item_get_uri(
- webkit_back_forward_list_get_current_item(
- back_forward_list)), -1, text_tag, NULL);
-
- /* Insert back list items. */
- list_item = webkit_back_forward_list_get_back_list(
- back_forward_list);
- chrome->back_items = 0;
- for (; list_item; list_item = list_item->next) {
- gtk_list_box_prepend(GTK_LIST_BOX(list_box),
- back_forward_list_item_new(list_item->data, -1));
- gtk_text_buffer_get_start_iter(text_buffer, &text_iter);
- str = g_strdup_printf("%s\n",
- webkit_back_forward_list_item_get_uri(list_item->data));
- gtk_text_buffer_insert(text_buffer, &text_iter, str, -1);
- g_free(str);
- ++chrome->back_items;
- }
-
- /*
- * The following GtkScrolledWindow widgets have hardcoded minimum sizes,
- * because there seems to be (in GTK+ versions before 3.22) no way to
- * set the natural size of GtkScrolledWindow and its GtkViewport.
- *
- * I tried:
- *
- * - Setting size requests of the sizes of child widgets plus
- * scrollbars (commit 2205669)
- * - Putting GtkScrolledWindow widgets in stacks with non-scrolled
- * versions of children, to allocate more area for the
- * GtkScrolledWindow widgets to fill (commits 922cdef and 90686fa)
- * - Setting policies to disable scrollbars upon GtkScrolledWindow
- * instantiation, then enabling scrollbars on the GtkScrolledWindow
- * "size-allocate" signal (commits c534c7e and 42ca783)
- *
- * Attempts to match the size of a GtkScrolledWindow's GtkViewport to
- * its child's size don't allow the GtkScrolledWindow and GtkViewport to
- * shrink when necessary to fit within the window. Therefore, such
- * methods are equivalent to simply not using GtkScrolledWindow at all.
- * And there appears to be no easy way to calculate the available size
- * (the size of the GtkWindow minus all of the surrounding widgets) to
- * manually manage a GtkViewport's size.
- *
- * GtkScrolledWindow or GtkViewport ignores the child's preferred
- * (minimum and natural) sizes and apparently just sets a hardcoded size
- * of about 64x64 px. I considered subclassing GtkScrolledWindow or
- * GtkViewport, but I'm not sure where the hardcoded size is set.
- *
- * The functions gtk_scrolled_window_set_propagate_natural_width() and
- * gtk_scrolled_window_set_propagate_natural_height() were introduced in
- * GTK+ 3.22 and probably do what I want. However, I want to maintain
- * compatibility with at least GTK+ 3.12 or 3.14.
- */
-
- /* Set up the list scrolled window. */
- list_scrolled_window = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_min_content_width(
- GTK_SCROLLED_WINDOW(list_scrolled_window), 400);
- gtk_scrolled_window_set_min_content_height(
- GTK_SCROLLED_WINDOW(list_scrolled_window), 200);
- gtk_container_add(GTK_CONTAINER(list_scrolled_window), list_box);
-
- /* Set up the text scrolled window. */
- text_scrolled_window = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_min_content_width(
- GTK_SCROLLED_WINDOW(text_scrolled_window), 400);
- gtk_scrolled_window_set_min_content_height(
- GTK_SCROLLED_WINDOW(text_scrolled_window), 200);
- gtk_container_add(GTK_CONTAINER(text_scrolled_window), text_view);
-
- /* Set up the stack. */
- stack = gtk_stack_new();
- gtk_stack_add_named(GTK_STACK(stack), list_scrolled_window, "list");
- gtk_stack_add_named(GTK_STACK(stack), text_scrolled_window, "text");
-
- /* Set up the toggle button. */
- toggle_button = gtk_toggle_button_new();
- gtk_button_set_image(GTK_BUTTON(toggle_button),
- gtk_image_new_from_icon_name("edit-select-all",
- GTK_ICON_SIZE_SMALL_TOOLBAR));
- gtk_widget_set_halign(toggle_button, GTK_ALIGN_START);
- g_signal_connect(toggle_button, "toggled",
- G_CALLBACK(back_forward_toggle_button_toggled_cb),
- GTK_STACK(stack));
-
- /* Set up the containing box. */
- box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
- gtk_box_pack_start(GTK_BOX(box), toggle_button, TRUE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(box), stack, TRUE, FALSE, 0);
-
- /* Set up the popover. */
- chrome->back_forward_popover = gtk_popover_new(widget);
- gtk_container_add(GTK_CONTAINER(chrome->back_forward_popover), box);
-
- /* NB: gtk_popover_popup() is new in GTK+ 3.22. */
- gtk_widget_show_all(chrome->back_forward_popover);
- gtk_widget_hide(text_view);
-
- return FALSE;
-}
-
-static void
-stop_reload_clicked_cb(GtkToolButton G_GNUC_UNUSED *toolbutton,
- MqTabChrome *chrome)
-{
- if (webkit_web_view_is_loading(chrome->web_view)) {
- webkit_web_view_stop_loading(chrome->web_view);
- } else {
- webkit_web_view_reload(chrome->web_view);
- }
-}
-
-static void
-uri_activate_cb(GtkEntry *entry, MqTabChrome *chrome)
-{
- const gchar *uri;
- gchar *rw_uri;
-
- uri = gtk_entry_get_text(GTK_ENTRY(entry));
-
- if (g_str_has_prefix(uri, "about:")) {
- rw_uri = g_strconcat("mq-about:", uri + strlen("about:"), NULL);
- webkit_web_view_load_uri(chrome->web_view, rw_uri);
- g_free(rw_uri);
- } else {
- webkit_web_view_load_uri(chrome->web_view, uri);
- }
-}
-
-static void
-home_clicked_cb(GtkToolButton G_GNUC_UNUSED *toolbutton,
- MqTabChrome *chrome)
-{
- const gchar *uri;
- gchar *rw_uri;
-
- uri = mq_config_get_string(chrome->config, "tabs.home");
-
- if (g_str_has_prefix(uri, "about:")) {
- rw_uri = g_strconcat("mq-about:", uri + strlen("about:"), NULL);
- webkit_web_view_load_uri(chrome->web_view, rw_uri);
- g_free(rw_uri);
- } else {
- webkit_web_view_load_uri(chrome->web_view, uri);
- }
-}
-
-static void
-zoom_out_clicked_cb(GtkButton G_GNUC_UNUSED *button, MqTabChrome *chrome)
-{
- webkit_web_view_set_zoom_level(chrome->web_view,
- webkit_web_view_get_zoom_level(chrome->web_view) - 0.1);
-}
-
-static void
-zoom_reset_clicked_cb(GtkButton G_GNUC_UNUSED *button, MqTabChrome *chrome)
-{
- webkit_web_view_set_zoom_level(chrome->web_view,
- mq_config_get_double(chrome->config, "zoom.default"));
-}
-
-static void
-zoom_in_clicked_cb(GtkButton G_GNUC_UNUSED *button, MqTabChrome *chrome)
-{
- webkit_web_view_set_zoom_level(chrome->web_view,
- webkit_web_view_get_zoom_level(chrome->web_view) + 0.1);
-}
-
-static void
-find_clicked_cb(GtkButton G_GNUC_UNUSED *button, MqTabChrome *chrome)
-{
- gtk_revealer_set_reveal_child(GTK_REVEALER(chrome->find_revealer),
- TRUE);
- gtk_widget_grab_focus(chrome->find_search_entry);
- gtk_widget_hide(chrome->menu_popover);
-}
-
-static void
-fullscreen_clicked_cb(GtkButton G_GNUC_UNUSED *button, MqTabChrome *chrome)
-{
- mq_window_toggle_fullscreen(mq_tab_get_window(chrome->tab));
- gtk_widget_hide(chrome->menu_popover);
-}
-
-static void
-developer_tools_clicked_cb(GtkButton G_GNUC_UNUSED *button, MqTabChrome *chrome)
-{
- webkit_web_inspector_show(webkit_web_view_get_inspector(
- chrome->web_view));
- gtk_widget_hide(chrome->menu_popover);
-}
-
-static void
-preferences_clicked_cb(GtkButton G_GNUC_UNUSED *button, MqTabChrome *chrome)
-{
- mq_tab_new("about:preferences", chrome->tab);
- gtk_widget_hide(chrome->menu_popover);
- /* TODO: Hack: */
- gtk_notebook_next_page(GTK_NOTEBOOK(chrome->tab->window->notebook));
-}
-
-static void
-about_clicked_cb(GtkButton G_GNUC_UNUSED *button, MqTabChrome *chrome)
-{
- mq_tab_new("about:", chrome->tab);
- gtk_widget_hide(chrome->menu_popover);
- /* TODO: Hack: */
- gtk_notebook_next_page(GTK_NOTEBOOK(chrome->tab->window->notebook));
-}
-
-static void
-quit_clicked_cb(GtkButton G_GNUC_UNUSED *button, MqTabChrome *chrome)
-{
- mq_tab_quit(chrome->tab);
- /* mq_tab_quit() just calls mq_window_quit(), which just calls
- * mq_application_quit(), which is asynchronous. So close the menu. */
- gtk_widget_hide(chrome->menu_popover);
-}
-
-#define BUTTON_ROWS 6
-#define BUTTON_COLS 3
-#define NEW_BUTTON(Y, X, ICON, TOOLTIP) \
- do { \
- buttons[Y * BUTTON_COLS + X] = gtk_button_new_from_icon_name(\
- ICON, GTK_ICON_SIZE_BUTTON); \
- gtk_widget_set_tooltip_text(buttons[Y * BUTTON_COLS + X], \
- TOOLTIP); \
- gtk_grid_attach(GTK_GRID(grid), buttons[Y * BUTTON_COLS + X], \
- X, Y, 1, 1); \
- } while (0)
-#define CLICKED_CB(Y, X, CB) \
- g_signal_connect(buttons[Y * BUTTON_COLS + X], "clicked", \
- G_CALLBACK(CB), chrome)
-
-static void
-menu_button_clicked_cb(GtkToolButton *tool_button,
- MqTabChrome G_GNUC_UNUSED *chrome)
-{
- GtkWidget *grid;
- GtkWidget *buttons[BUTTON_ROWS * BUTTON_COLS];
-
- /* Set up the grid. */
- grid = gtk_grid_new();
-
- NEW_BUTTON(0, 0, "zoom-out", "Zoom out");
- NEW_BUTTON(0, 1, "zoom-original", "Reset zoom");
- NEW_BUTTON(0, 2, "zoom-in", "Zoom in");
- NEW_BUTTON(1, 0, "document-open", "Open file");
- NEW_BUTTON(1, 1, "document-save-as", "Save page");
- NEW_BUTTON(1, 2, "mail-message-new", "E-mail link");
- NEW_BUTTON(2, 0, "edit-find", "Find");
- NEW_BUTTON(2, 1, "document-print-preview", "Print preview");
- NEW_BUTTON(2, 2, "document-print", "Print");
- NEW_BUTTON(3, 0, "bookmark-new", "Bookmarks");
- NEW_BUTTON(3, 1, "document-open-recent", "History");
- NEW_BUTTON(3, 2, "document-save", "Downloads");
- NEW_BUTTON(4, 0, "view-fullscreen", "Full screen");
- NEW_BUTTON(4, 1, "document-properties", "Developer tools");
- NEW_BUTTON(4, 2, "system-run", "Preferences");
- NEW_BUTTON(5, 0, "help-about", "About Marquee");
- NEW_BUTTON(5, 2, "application-exit", "Quit");
-
- CLICKED_CB(0, 0, zoom_out_clicked_cb);
- CLICKED_CB(0, 1, zoom_reset_clicked_cb);
- CLICKED_CB(0, 2, zoom_in_clicked_cb);
- /* TODO: 1, 0: Open file */
- /* TODO: 1, 1: Save page */
- /* TODO: 1, 2: E-mail link */
- CLICKED_CB(2, 0, find_clicked_cb);
- /* TODO: 2, 1: Print preview */
- /* TODO: 2, 2: Print */
- /* TODO: 3, 0: Bookmarks */
- /* TODO: 3, 1: History */
- /* TODO: 3, 2: Downloads */
- CLICKED_CB(4, 0, fullscreen_clicked_cb);
- CLICKED_CB(4, 1, developer_tools_clicked_cb);
- CLICKED_CB(4, 2, preferences_clicked_cb);
- CLICKED_CB(5, 0, about_clicked_cb);
- CLICKED_CB(5, 2, quit_clicked_cb);
-
- /* Set up the popover. */
- chrome->menu_popover = gtk_popover_new(GTK_WIDGET(tool_button));
- gtk_container_add(GTK_CONTAINER(chrome->menu_popover), grid);
-
- /* NB: gtk_popover_popup() is new in GTK+ 3.22. */
- gtk_widget_show_all(chrome->menu_popover);
-}
-
-#undef BUTTON_ROWS
-#undef BUTTON_COLS
-#undef NEW_BUTTON
-
-static GtkWidget *
-navigation_toolbar_new(MqTabChrome *chrome, const gchar *uri)
-{
- GtkToolbar *navigation_toolbar;
- GtkToolItem *back_forward_tool_item;
- GtkWidget *back_forward_event_box;
- GtkToolItem *uri_tool_item;
- GtkToolItem *home_button;
-
- navigation_toolbar = GTK_TOOLBAR(gtk_toolbar_new());
-
- back_forward_tool_item = gtk_tool_item_new();
- chrome->back_forward_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
-
- /* Back button */
- chrome->back_button = gtk_button_new_from_icon_name("go-previous",
- GTK_ICON_SIZE_SMALL_TOOLBAR);
- gtk_widget_set_tooltip_text(GTK_WIDGET(chrome->back_button),
- "Go back one page");
- g_signal_connect(chrome->back_button, "clicked",
- G_CALLBACK(back_clicked_cb), chrome);
- gtk_box_pack_start(GTK_BOX(chrome->back_forward_box),
- chrome->back_button, FALSE, FALSE, 0);
-
- /* Forward button */
- chrome->forward_button = gtk_button_new_from_icon_name("go-next",
- GTK_ICON_SIZE_SMALL_TOOLBAR);
- gtk_widget_set_tooltip_text(GTK_WIDGET(chrome->forward_button),
- "Go forward one page");
- g_signal_connect(chrome->forward_button, "clicked",
- G_CALLBACK(forward_clicked_cb), chrome);
- gtk_box_pack_start(GTK_BOX(chrome->back_forward_box),
- chrome->forward_button, FALSE, FALSE, 0);
-
- gtk_style_context_add_class(
- gtk_widget_get_style_context(chrome->back_forward_box),
- "linked");
- back_forward_event_box = gtk_event_box_new();
- g_signal_connect(back_forward_event_box, "button-press-event",
- G_CALLBACK(back_forward_box_button_press_cb), chrome);
- gtk_container_add(GTK_CONTAINER(back_forward_event_box),
- chrome->back_forward_box);
- gtk_container_add(GTK_CONTAINER(back_forward_tool_item),
- back_forward_event_box);
- gtk_toolbar_insert(navigation_toolbar, back_forward_tool_item, -1);
-
- /* Stop/reload button */
- chrome->stop_icon = gtk_image_new_from_icon_name("process-stop",
- GTK_ICON_SIZE_SMALL_TOOLBAR);
- g_object_ref_sink(chrome->stop_icon);
- chrome->reload_icon = gtk_image_new_from_icon_name("view-refresh",
- GTK_ICON_SIZE_SMALL_TOOLBAR);
- g_object_ref_sink(chrome->reload_icon);
- chrome->stop_reload_button = gtk_tool_button_new(chrome->stop_icon,
- "Stop");
- gtk_widget_set_tooltip_text(GTK_WIDGET(chrome->stop_reload_button),
- "Stop loading the current page");
- g_signal_connect(chrome->stop_reload_button, "clicked",
- G_CALLBACK(stop_reload_clicked_cb), chrome);
- gtk_toolbar_insert(navigation_toolbar, chrome->stop_reload_button, -1);
-
- /* URI bar */
- uri_tool_item = gtk_tool_item_new();
- chrome->uri_entry = gtk_entry_new();
- if (uri) {
- gtk_entry_set_text(GTK_ENTRY(chrome->uri_entry), uri);
- }
- gtk_entry_set_placeholder_text(GTK_ENTRY(chrome->uri_entry),
- "URI...");
- gtk_entry_set_icon_from_icon_name(GTK_ENTRY(chrome->uri_entry),
- GTK_ENTRY_ICON_PRIMARY, "text-x-generic");
- gtk_entry_set_progress_fraction(GTK_ENTRY(chrome->uri_entry), 0.0);
- g_signal_connect(chrome->uri_entry, "activate",
- G_CALLBACK(uri_activate_cb), chrome);
- gtk_container_add(GTK_CONTAINER(uri_tool_item),
- chrome->uri_entry);
- gtk_tool_item_set_expand(uri_tool_item, TRUE);
- gtk_toolbar_insert(navigation_toolbar, uri_tool_item, -1);
-
- /* URI bar hovered link style */
- chrome->hovered_link_style = pango_attr_list_new();
- pango_attr_list_insert(chrome->hovered_link_style,
- pango_attr_style_new(PANGO_STYLE_ITALIC));
-
- /* Home button */
- home_button = gtk_tool_button_new(gtk_image_new_from_icon_name(
- "go-home", GTK_ICON_SIZE_SMALL_TOOLBAR), "Home");
- gtk_widget_set_tooltip_text(GTK_WIDGET(home_button),
- "Load the home page");
- g_signal_connect(home_button, "clicked",
- G_CALLBACK(home_clicked_cb), chrome);
- gtk_toolbar_insert(navigation_toolbar, home_button, -1);
-
- /* Menu button */
- chrome->menu_button = gtk_tool_button_new(
- gtk_image_new_from_icon_name("open-menu-symbolic",
- GTK_ICON_SIZE_SMALL_TOOLBAR), "Menu");
- gtk_widget_set_tooltip_text(GTK_WIDGET(chrome->menu_button),
- "Open menu");
- g_signal_connect(chrome->menu_button, "clicked",
- G_CALLBACK(menu_button_clicked_cb), chrome);
- gtk_toolbar_insert(navigation_toolbar, chrome->menu_button, -1);
-
- gtk_widget_set_hexpand(GTK_WIDGET(navigation_toolbar), TRUE);
-
- chrome->load_failed = FALSE;
-
- return GTK_WIDGET(navigation_toolbar);
-}
-
-static void
-find_search(MqTabChrome *chrome, gboolean forward)
-{
- guint32 find_options;
-
- find_options = WEBKIT_FIND_OPTIONS_WRAP_AROUND;
- if (!chrome->find_match_case) {
- find_options |= WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE;
- }
- if (!forward) {
- find_options |= WEBKIT_FIND_OPTIONS_BACKWARDS;
- }
- webkit_find_controller_search(chrome->find_controller,
- gtk_entry_get_text(GTK_ENTRY(chrome->find_search_entry)),
- find_options, G_MAXUINT);
- chrome->find_searching = TRUE;
-}
-
-static void
-find_search_finished(MqTabChrome *chrome)
-{
- chrome->find_searching = FALSE;
- webkit_find_controller_search_finish(chrome->find_controller);
-}
-
-static void
-find_close(MqTabChrome *chrome)
-{
- gtk_revealer_set_reveal_child(GTK_REVEALER(chrome->find_revealer),
- FALSE);
- gtk_label_set_text(GTK_LABEL(chrome->find_matches_label), NULL);
- find_search_finished(chrome);
-}
-
-static void
-find_search_changed_cb(GtkSearchEntry G_GNUC_UNUSED *entry, MqTabChrome *chrome)
-{
- find_search(chrome, TRUE);
-}
-
-static gboolean
-find_search_key_press_event_cb(GtkSearchEntry G_GNUC_UNUSED *entry,
- GdkEventKey *event, MqTabChrome *chrome)
-{
- switch (event->keyval) {
- case GDK_KEY_Escape:
- find_close(chrome);
- return TRUE;
- case GDK_KEY_Return:
- case GDK_KEY_KP_Enter:
- case GDK_KEY_ISO_Enter:
- find_search(chrome, !(event->state & GDK_SHIFT_MASK));
- return TRUE;
- default:
- return FALSE;
- }
-}
-
-static void
-find_prev_clicked_cb(GtkButton G_GNUC_UNUSED *button, MqTabChrome *chrome)
-{
- /* Calling this method before webkit_find_controller_search() or
- * webkit_find_controller_count_matches() is a programming error. */
- if (chrome->find_searching) {
- webkit_find_controller_search_previous(chrome->find_controller);
- } else {
- find_search(chrome, FALSE);
- }
-}
-
-static void
-find_next_clicked_cb(GtkButton G_GNUC_UNUSED *button, MqTabChrome *chrome)
-{
- /* Calling this method before webkit_find_controller_search() or
- * webkit_find_controller_count_matches() is a programming error. */
- if (chrome->find_searching) {
- webkit_find_controller_search_next(chrome->find_controller);
- } else {
- find_search(chrome, TRUE);
- }
-}
-
-static void
-find_match_case_toggled_cb(GtkToggleButton *toggle_button, MqTabChrome *chrome)
-{
- chrome->find_match_case = gtk_toggle_button_get_active(toggle_button);
- find_search(chrome, TRUE);
-}
-
-static void
-find_close_clicked_cb(GtkButton G_GNUC_UNUSED *button, MqTabChrome *chrome)
-{
- find_close(chrome);
-}
-
-static GtkWidget *
-find_toolbar_new(MqTabChrome *chrome)
-{
- GtkWidget *close_button;
- GtkWidget *prev_button;
- GtkWidget *next_button;
- GtkWidget *match_case_button;
- GtkWidget *box;
-
- /* Search entry */
- chrome->find_search_entry = gtk_search_entry_new();
- g_signal_connect(chrome->find_search_entry, "search-changed",
- G_CALLBACK(find_search_changed_cb), chrome);
- g_signal_connect(chrome->find_search_entry, "key-press-event",
- G_CALLBACK(find_search_key_press_event_cb), chrome);
-
- /* Previous button */
- prev_button = gtk_button_new_from_icon_name("go-up",
- GTK_ICON_SIZE_BUTTON);
- gtk_widget_set_tooltip_text(prev_button, "Find previous occurrence");
- gtk_widget_set_can_focus(prev_button, FALSE);
- g_signal_connect(prev_button, "clicked",
- G_CALLBACK(find_prev_clicked_cb), chrome);
-
- /* Next button */
- next_button = gtk_button_new_from_icon_name("go-down",
- GTK_ICON_SIZE_BUTTON);
- gtk_widget_set_tooltip_text(next_button, "Find next occurrence");
- gtk_widget_set_can_focus(next_button, FALSE);
- g_signal_connect(next_button, "clicked",
- G_CALLBACK(find_next_clicked_cb), chrome);
-
- /* Case sensitivity button */
- match_case_button = gtk_toggle_button_new_with_label("Match case");
- gtk_widget_set_tooltip_text(match_case_button,
- "Search with case sensitivity");
- gtk_widget_set_can_focus(match_case_button, FALSE);
- g_signal_connect(match_case_button, "toggled",
- G_CALLBACK(find_match_case_toggled_cb), chrome);
-
- /* Matches label */
- chrome->find_matches_label = gtk_label_new(NULL);
-
- /* Close button */
- close_button = gtk_button_new_from_icon_name("window-close",
- GTK_ICON_SIZE_BUTTON);
- gtk_button_set_relief(GTK_BUTTON(close_button), GTK_RELIEF_NONE);
- gtk_widget_set_tooltip_text(close_button, "Close find bar");
- gtk_widget_set_can_focus(close_button, FALSE);
- g_signal_connect(close_button, "clicked",
- G_CALLBACK(find_close_clicked_cb), chrome);
-
- /* Box */
- box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
- gtk_box_pack_start(GTK_BOX(box), chrome->find_search_entry,
- FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(box), prev_button, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(box), next_button, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(box), match_case_button, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(box), chrome->find_matches_label,
- FALSE, FALSE, 0);
- gtk_box_pack_end(GTK_BOX(box), close_button, FALSE, FALSE, 0);
-
- /* Revealer */
- chrome->find_revealer = gtk_revealer_new();
- gtk_revealer_set_transition_type(GTK_REVEALER(chrome->find_revealer),
- GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN);
- gtk_container_add(GTK_CONTAINER(chrome->find_revealer), box);
-
- chrome->find_match_case = FALSE;
- chrome->find_searching = FALSE;
-
- return chrome->find_revealer;
-}
-
-MqTabChrome *
-mq_tab_chrome_new(MqTab *tab, const gchar *uri)
-{
- MqTabChrome *chrome;
-
- chrome = malloc(sizeof(*chrome));
- chrome->config = mq_application_get_config(mq_tab_get_application(tab));
- chrome->tab = tab;
-
- chrome->container = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
- gtk_box_pack_start(GTK_BOX(chrome->container),
- navigation_toolbar_new(chrome, uri), FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(chrome->container),
- find_toolbar_new(chrome), FALSE, FALSE, 0);
-
- return chrome;
-}
-
-GtkWidget *
-mq_tab_chrome_get_container(MqTabChrome *chrome)
-{
- return chrome->container;
-}
-
-static gchar *
-web_view_get_uri(WebKitWebView *web_view)
-{
- const gchar *uri;
- gchar *rw_uri;
-
- uri = webkit_web_view_get_uri(web_view);
-
- if (g_str_has_prefix(uri, "mq-about:")) {
- rw_uri = g_strconcat("about:", uri + strlen("mq-about:"), NULL);
- } else {
- rw_uri = g_strdup(uri);
- }
-
- return rw_uri;
-}
-
-static void
-load_changed_cb(WebKitWebView *web_view, WebKitLoadEvent load_event,
- MqTabChrome *chrome)
-{
- gchar *uri;
-
- switch (load_event) {
- case WEBKIT_LOAD_STARTED:
- case WEBKIT_LOAD_REDIRECTED:
- case WEBKIT_LOAD_COMMITTED:
- uri = web_view_get_uri(web_view);
- gtk_entry_set_text(GTK_ENTRY(chrome->uri_entry), uri);
- g_free(uri);
- gtk_entry_set_attributes(GTK_ENTRY(chrome->uri_entry),
- NULL);
- break;
- case WEBKIT_LOAD_FINISHED:
- gtk_entry_set_progress_fraction(
- GTK_ENTRY(chrome->uri_entry), 0.0);
- break;
- }
-}
-
-static gboolean
-load_failed_cb(WebKitWebView G_GNUC_UNUSED *web_view,
- WebKitLoadEvent G_GNUC_UNUSED load_event,
- gchar G_GNUC_UNUSED *failing_uri, GError G_GNUC_UNUSED *error,
- MqTabChrome *chrome)
-{
- chrome->load_failed = TRUE;
- return FALSE;
-}
-
-/* TODO: <Esc> key in URI bar should reset to URI of current hovered link, if
- * any, even if different from chrome->hovered_link_uri. */
-static void
-mouse_target_changed_cb(WebKitWebView G_GNUC_UNUSED *web_view,
- WebKitHitTestResult *hit_test_result, guint G_GNUC_UNUSED modifiers,
- MqTabChrome *chrome)
-{
- gchar *uri;
-
- uri = web_view_get_uri(web_view);
- if (webkit_hit_test_result_context_is_link(hit_test_result)) {
- if (gtk_widget_has_focus(chrome->uri_entry)) {
- } else if (chrome->hovered_link_uri &&
- g_strcmp0(gtk_entry_get_text(
- GTK_ENTRY(chrome->uri_entry)),
- chrome->hovered_link_uri) != 0) {
- /* The user has edited the hovered link URI in the URI
- * bar. */
- } else if (g_strcmp0(gtk_entry_get_text(
- GTK_ENTRY(chrome->uri_entry)), uri) ==
- 0) {
- g_free(chrome->hovered_link_uri);
- chrome->hovered_link_uri = g_strdup(
- webkit_hit_test_result_get_link_uri(
- hit_test_result));
- gtk_entry_set_text(GTK_ENTRY(chrome->uri_entry),
- chrome->hovered_link_uri);
- gtk_entry_set_attributes(GTK_ENTRY(chrome->uri_entry),
- chrome->hovered_link_style);
- } else if (gtk_entry_get_attributes(
- GTK_ENTRY(chrome->uri_entry)) ==
- chrome->hovered_link_style) {
- /* The URI bar's text differs from the Web view's URI
- * because the mouse was already targeting a different
- * link. */
- g_free(chrome->hovered_link_uri);
- chrome->hovered_link_uri = g_strdup(
- webkit_hit_test_result_get_link_uri(
- hit_test_result));
- gtk_entry_set_text(GTK_ENTRY(chrome->uri_entry),
- chrome->hovered_link_uri);
- }
- } else if (gtk_entry_get_attributes(GTK_ENTRY(chrome->uri_entry)) ==
- chrome->hovered_link_style) {
- if (gtk_widget_has_focus(chrome->uri_entry)) {
- } else if (g_strcmp0(gtk_entry_get_text(
- GTK_ENTRY(chrome->uri_entry)),
- chrome->hovered_link_uri) == 0) {
- /* The user hasn't edited the hovered link URI in the
- * URI bar. */
- g_free(chrome->hovered_link_uri);
- chrome->hovered_link_uri = NULL;
- gtk_entry_set_text(GTK_ENTRY(chrome->uri_entry), uri);
- gtk_entry_set_attributes(GTK_ENTRY(chrome->uri_entry),
- NULL);
- }
- }
-
- g_free(uri);
-}
-
-static void
-load_progress_cb(WebKitWebView *web_view, GParamSpec G_GNUC_UNUSED *paramspec,
- MqTabChrome *chrome)
-{
- /*
- * If loading fails, the WebKitWebView's "estimated-load-progress" is
- * set to 1.0 after signals like "load-changed" and "load-failed" are
- * emitted. So the only way to avoid leaving behind a full progress bar
- * after, for example, canceling a page load is to save a flag on a
- * failed load and only update the progress bar if the flag is unset.
- */
- if (chrome->load_failed) {
- chrome->load_failed = FALSE;
- return;
- }
- gtk_entry_set_progress_fraction(GTK_ENTRY(chrome->uri_entry),
- webkit_web_view_get_estimated_load_progress(web_view));
-}
-
-static void
-uri_cb(WebKitWebView *web_view, GParamSpec G_GNUC_UNUSED *paramspec,
- MqTabChrome *chrome)
-{
- gchar *uri;
-
- uri = web_view_get_uri(web_view);
- gtk_entry_set_text(GTK_ENTRY(chrome->uri_entry), uri);
- g_free(uri);
- gtk_entry_set_attributes(GTK_ENTRY(chrome->uri_entry), NULL);
-}
-
-static void
-loading_cb(WebKitWebView *web_view, GParamSpec G_GNUC_UNUSED *paramspec,
- MqTabChrome *chrome)
-{
- if (webkit_web_view_is_loading(web_view)) {
- gtk_tool_button_set_icon_widget(
- GTK_TOOL_BUTTON(chrome->stop_reload_button),
- chrome->stop_icon);
- gtk_tool_button_set_label(
- GTK_TOOL_BUTTON(chrome->stop_reload_button), "Stop");
- gtk_widget_set_tooltip_text(
- GTK_WIDGET(chrome->stop_reload_button),
- "Stop loading the current page");
- } else {
- gtk_tool_button_set_icon_widget(
- GTK_TOOL_BUTTON(chrome->stop_reload_button),
- chrome->reload_icon);
- gtk_tool_button_set_label(
- GTK_TOOL_BUTTON(chrome->stop_reload_button), "Reload");
- gtk_widget_set_tooltip_text(
- GTK_WIDGET(chrome->stop_reload_button),
- "Reload the current page");
- }
- gtk_widget_show_all(GTK_WIDGET(chrome->stop_reload_button));
-}
-
-static void
-back_forward_list_changed_cb(
- WebKitBackForwardList G_GNUC_UNUSED *back_forward_list,
- WebKitBackForwardListItem G_GNUC_UNUSED *item_added,
- gpointer G_GNUC_UNUSED items_removed, MqTabChrome *chrome)
-{
- gtk_widget_set_sensitive(GTK_WIDGET(chrome->back_button),
- webkit_web_view_can_go_back(chrome->web_view));
- gtk_widget_set_sensitive(GTK_WIDGET(chrome->forward_button),
- webkit_web_view_can_go_forward(chrome->web_view));
-}
-
-static void
-find_found_text_cb(WebKitFindController G_GNUC_UNUSED *find_controller,
- guint match_count, MqTabChrome *chrome)
-{
- gchar *text;
-
- if (match_count == 1) {
- text = g_strdup("1 match");
- } else {
- text = g_strdup_printf("%u matches", match_count);
- }
- gtk_label_set_text(GTK_LABEL(chrome->find_matches_label), text);
- g_free(text);
-
-}
-
-static void
-find_failed_to_find_text_cb(WebKitFindController G_GNUC_UNUSED *find_controller,
- MqTabChrome *chrome)
-{
- gtk_label_set_text(GTK_LABEL(chrome->find_matches_label), "No matches");
-}
-
-static void
-connect_web_view(MqTabChrome *chrome)
-{
- chrome->hovered_link_uri = NULL;
-
- g_signal_connect(chrome->web_view, "load-changed",
- G_CALLBACK(load_changed_cb), chrome);
- g_signal_connect(chrome->web_view, "load-failed",
- G_CALLBACK(load_failed_cb), chrome);
- g_signal_connect(chrome->web_view, "mouse-target-changed",
- G_CALLBACK(mouse_target_changed_cb), chrome);
- g_signal_connect(chrome->web_view, "notify::estimated-load-progress",
- G_CALLBACK(load_progress_cb), chrome);
- g_signal_connect(chrome->web_view, "notify::uri",
- G_CALLBACK(uri_cb), chrome);
- g_signal_connect(chrome->web_view, "notify::is-loading",
- G_CALLBACK(loading_cb), chrome);
- g_signal_connect(
- webkit_web_view_get_back_forward_list(chrome->web_view),
- "changed", G_CALLBACK(back_forward_list_changed_cb), chrome);
-
- g_signal_connect(chrome->find_controller, "found-text",
- G_CALLBACK(find_found_text_cb), chrome);
- g_signal_connect(chrome->find_controller, "failed-to-find-text",
- G_CALLBACK(find_failed_to_find_text_cb), chrome);
-}
-
-void
-mq_tab_chrome_set_web_view(MqTabChrome *chrome, WebKitWebView *web_view)
-{
- chrome->web_view = web_view;
- chrome->find_controller = webkit_web_view_get_find_controller(web_view);
- connect_web_view(chrome);
-}