From 8fc032f2f64f4b7eb022adb0b1255a5a68df109f Mon Sep 17 00:00:00 2001 From: Patrick McDermott Date: Sun, 22 Oct 2017 19:09:22 -0400 Subject: Merge branch 'gobjectification' --- (limited to 'src/tab-chrome.c') 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 . - */ - -#include -#include - -#include -#include - -#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: 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); -} -- cgit v0.9.1