diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/tab.c | 407 | ||||
-rw-r--r-- | src/tab.h | 11 |
2 files changed, 34 insertions, 384 deletions
@@ -25,6 +25,7 @@ #include <gtk/gtk.h> +#include "tab-label.h" #include "toolbars/find-toolbar.h" #include "toolbars/navigation-toolbar.h" #include "web-view.h" @@ -39,35 +40,13 @@ foreach_tab(MqTab *node, void (*cb)(MqTab *node)) } static void -update_tab_image(MqTab *tab, GdkPixbuf *favicon) -{ - if (favicon) { - gtk_image_set_from_pixbuf(GTK_IMAGE(tab->tab_image), favicon); - } else { - gtk_image_set_from_icon_name(GTK_IMAGE(tab->tab_image), - "text-x-generic", GTK_ICON_SIZE_BUTTON); - } -} - -static void -update_tab_label(MqTab *tab) -{ - const gchar *title; - gchar *label; - - title = tab->scrolling ? tab->scrolled_title : tab->title; - label = g_strdup_printf("%d. %s", tab->position, title); - gtk_label_set_text(GTK_LABEL(tab->tab_label), label); - gtk_widget_set_tooltip_text(tab->tab, label); - g_free(label); -} - -static void update_positions(MqTab *node, gint step) { if (node) { node->position += step; - update_tab_label(node); + if (node->tab) { + mq_tab_label_set_position(node->tab, node->position); + } if (node->next) { update_positions(node->next, step); } else if (node->parent && node->parent->next) { @@ -125,294 +104,10 @@ append_sibling(MqTab *new_node, MqTab *prev_sibling) } static void -reload_tab_clicked_cb(GtkWidget G_GNUC_UNUSED *button, MqTab *tab) -{ - webkit_web_view_reload(tab->web_view); - gtk_widget_hide(tab->popover); -} - -static void -new_tab_clicked_cb(GtkWidget G_GNUC_UNUSED *button, MqTab *tab) -{ - mq_tab_new(NULL, tab); - gtk_widget_hide(tab->popover); -} - -static void -new_window_clicked_cb(GtkWidget G_GNUC_UNUSED *button, MqTab *tab) -{ - mq_application_add_window(tab->application, NULL); - gtk_widget_hide(tab->popover); -} - -static void -tab_list_button_toggled_cb(GtkToggleButton *toggle_button, GtkWidget *tab_list) -{ - if (gtk_toggle_button_get_active(toggle_button)) { - gtk_widget_show(tab_list); - } else { - gtk_widget_hide(tab_list); - } -} - -static void -create_tree_model_recurse(MqTab *node, GtkTreeStore *tree_store, - GtkTreeIter *parent_tree_iter) -{ - GtkTreeIter tree_iter; - - for (; node; node = node->next) { - gtk_tree_store_append(tree_store, &tree_iter, parent_tree_iter); - gtk_tree_store_set(tree_store, &tree_iter, 0, node->title, -1); - create_tree_model_recurse(node->first_child, tree_store, - &tree_iter); - } -} - -static GtkTreeModel * -create_tree_model(MqTab *tab) -{ - GtkTreeStore *tree_store; - - tree_store = gtk_tree_store_new(1, G_TYPE_STRING); - - create_tree_model_recurse(tab->root->first_child, tree_store, NULL); - - return GTK_TREE_MODEL(tree_store); -} - -static void -row_activated_cb(GtkTreeView G_GNUC_UNUSED *tree_view, GtkTreePath *tree_path, - GtkTreeViewColumn G_GNUC_UNUSED *tree_view_column, MqTab *tab) -{ - gint *indices; - gint depth; - - indices = gtk_tree_path_get_indices_with_depth(tree_path, &depth); - g_assert(depth == 1); - mq_window_set_current_tab(tab->window, indices[0] + 1); - gtk_widget_hide(tab->popover); -} - -static GtkWidget * -create_tab_list(MqTab *tab) -{ - GtkWidget *tree_view; - GtkTreeSelection *tree_selection; - GtkCellRenderer *cell_renderer; - GtkWidget *scrolled_window; - - tree_view = gtk_tree_view_new_with_model(create_tree_model(tab)); - tree_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); - gtk_tree_selection_set_mode(tree_selection, GTK_SELECTION_BROWSE); - gtk_tree_selection_select_path(tree_selection, - gtk_tree_path_new_from_indices( - mq_window_get_current_tab(tab->window) - 1, -1)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), FALSE); - gtk_tree_view_set_activate_on_single_click(GTK_TREE_VIEW(tree_view), - TRUE); - gtk_tree_view_expand_all(GTK_TREE_VIEW(tree_view)); - gtk_tree_view_set_reorderable(GTK_TREE_VIEW(tree_view), TRUE); - gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(tree_view), TRUE); - g_signal_connect(tree_view, "row-activated", - G_CALLBACK(row_activated_cb), tab); - - cell_renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(tree_view), - -1, NULL, cell_renderer, "text", 0, NULL); - - scrolled_window = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_min_content_width( - GTK_SCROLLED_WINDOW(scrolled_window), 400); - gtk_scrolled_window_set_min_content_height( - GTK_SCROLLED_WINDOW(scrolled_window), 200); - gtk_container_add(GTK_CONTAINER(scrolled_window), tree_view); - - return scrolled_window; -} - -#define BUTTON_ROWS 2 -#define BUTTON_COLS 4 -#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_widget_set_can_focus(buttons[Y * BUTTON_COLS + X], FALSE); \ - gtk_grid_attach(GTK_GRID(button_grid), \ - buttons[Y * BUTTON_COLS + X], X, Y, 1, 1); \ - } while (0) -#define NEW_TOGGLE(Y, X, ICON, TOOLTIP) \ - do { \ - buttons[Y * BUTTON_COLS + X] = gtk_toggle_button_new(); \ - gtk_button_set_image(GTK_BUTTON(buttons[Y * BUTTON_COLS + X]), \ - gtk_image_new_from_icon_name(ICON, \ - GTK_ICON_SIZE_BUTTON)); \ - gtk_widget_set_tooltip_text(buttons[Y * BUTTON_COLS + X], \ - TOOLTIP); \ - gtk_widget_set_can_focus(buttons[Y * BUTTON_COLS + X], FALSE); \ - gtk_grid_attach(GTK_GRID(button_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", CB, tab) - -static void -create_tab_popover(GtkWidget *widget, MqTab *tab) -{ - GtkWidget *button_grid; - GtkWidget *buttons[BUTTON_ROWS * BUTTON_COLS]; - GtkWidget *tab_list; - GtkWidget *tab_list_scrolled_window; - GtkWidget *box; - - /* Set up button grid. */ - button_grid = gtk_grid_new(); - gtk_widget_set_halign(button_grid, GTK_ALIGN_CENTER); - - /* Set up buttons. */ - NEW_BUTTON(0, 0, "view-refresh", "Reload tab"); - NEW_BUTTON(0, 1, "edit-copy", "Duplicate tab"); - NEW_BUTTON(0, 2, "window-new", "Move tab to new window"); - NEW_BUTTON(0, 3, "window-close", "Close tab"); - NEW_BUTTON(1, 0, "tab-new-symbolic", "New tab"); - NEW_BUTTON(1, 1, "window-new", "New window"); - NEW_BUTTON(1, 2, "edit-undo", "Undo close tab"); - NEW_TOGGLE(1, 3, "view-list-symbolic", "Tab list..."); - - CLICKED_CB(0, 0, G_CALLBACK(reload_tab_clicked_cb)); - CLICKED_CB(1, 0, G_CALLBACK(new_tab_clicked_cb)); - CLICKED_CB(1, 1, G_CALLBACK(new_window_clicked_cb)); - - /* Set up the tab list. */ - tab_list = create_tab_list(tab); - - /* Set up the tab list scrolled window. - * - * The following GtkScrolledWindow widget has a hardcoded minimum size, - * because there seems to be (in GTK+ versions before 3.22) no way to - * set the natural size of GtkScrolledWindow and its GtkViewport. - * - * See tab-chrome.c for more information. */ - tab_list_scrolled_window = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_min_content_width( - GTK_SCROLLED_WINDOW(tab_list_scrolled_window), 400); - gtk_scrolled_window_set_min_content_height( - GTK_SCROLLED_WINDOW(tab_list_scrolled_window), 200); - gtk_container_add(GTK_CONTAINER(tab_list_scrolled_window), tab_list); - - /* Add tab list toggle button handler. */ - g_signal_connect(buttons[1 * BUTTON_COLS + 3], "toggled", - G_CALLBACK(tab_list_button_toggled_cb), - tab_list_scrolled_window); - - /* Set up the button rows box. */ - box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_box_pack_start(GTK_BOX(box), button_grid, - TRUE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box), tab_list_scrolled_window, - TRUE, FALSE, 0); - - /* Set up the popover. */ - tab->popover = gtk_popover_new(widget); - gtk_container_add(GTK_CONTAINER(tab->popover), box); - - /* NB: gtk_popover_popup() is new in GTK+ 3.22. */ - gtk_widget_show_all(tab->popover); - gtk_widget_hide(tab_list_scrolled_window); -} - -#undef BUTTON_ROWS -#undef BUTTON_COLS -#undef NEW_BUTTON -#undef NEW_TOGGLE -#undef CLICKED_CB - -static gboolean -tab_label_button_press_cb(GtkWidget *widget, GdkEventButton *event, MqTab *tab) -{ - /* Create a popover menu on right click. */ - if (event->button == 3) { - create_tab_popover(widget, tab); - } - - return FALSE; -} - -static void -mq_tab_populate_tab(MqTab *tab) -{ - GtkWidget *close_button; - GtkWidget *box; - - tab->title = "New tab"; - - /* Set up tab image. */ - tab->tab_image = gtk_image_new_from_icon_name("text-x-generic", - GTK_ICON_SIZE_BUTTON); - - /* Set up tab label. */ - tab->tab_label = gtk_label_new(NULL); - gtk_label_set_ellipsize(GTK_LABEL(tab->tab_label), - PANGO_ELLIPSIZE_END); - gtk_widget_set_hexpand(tab->tab_label, TRUE); - gtk_widget_set_size_request(tab->tab_label, 50, 1); - - /* Set up close button. */ - close_button = gtk_button_new_from_icon_name("window-close", - GTK_ICON_SIZE_BUTTON); - gtk_widget_set_tooltip_text(close_button, "Close tab"); - - /* Pack tab box. */ - box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_box_pack_start(GTK_BOX(box), tab->tab_image, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box), tab->tab_label, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(box), close_button, FALSE, FALSE, 0); - gtk_widget_show_all(box); - - /* Set up event box. */ - tab->tab = gtk_event_box_new(); - g_signal_connect(tab->tab, "button-press-event", - G_CALLBACK(tab_label_button_press_cb), tab); - gtk_event_box_set_visible_window(GTK_EVENT_BOX(tab->tab), - FALSE); - gtk_container_add(GTK_CONTAINER(tab->tab), box); -} - -static void -favicon_cb(WebKitWebView G_GNUC_UNUSED *web_view, - GParamSpec G_GNUC_UNUSED *param_spec, MqTab *tab) -{ - cairo_surface_t *surface; - GdkPixbuf *pixbuf; - GdkPixbuf *scaled_pixbuf; - - surface = webkit_web_view_get_favicon(tab->web_view); - scaled_pixbuf = NULL; - if (surface) { - pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, - cairo_image_surface_get_width(surface), - cairo_image_surface_get_height(surface)); - if (pixbuf) { - scaled_pixbuf = gdk_pixbuf_scale_simple(pixbuf, 16, 16, - GDK_INTERP_BILINEAR); - g_object_unref(pixbuf); - } - } - - update_tab_image(tab, scaled_pixbuf); -} - -static void title_cb(WebKitWebView G_GNUC_UNUSED *web_view, GParamSpec G_GNUC_UNUSED *param_spec, MqTab *tab) { tab->title = webkit_web_view_get_title(tab->web_view); - if (tab->scrolling) { - tab->scrolled_title = g_strdup_printf("%s ", tab->title); - } - update_tab_label(tab); mq_window_update_tab_title(tab->window, tab->position, tab->title); } @@ -429,18 +124,17 @@ init_non_root(const gchar *uri, MqTab *source) tab->next = NULL; tab->first_child = tab->last_child = NULL; tab->tree_size = 1; + tab->title = "New tab"; tab->window = source->window; tab->application = mq_window_get_application(tab->window); - mq_tab_populate_tab(tab); - tab->web_view = WEBKIT_WEB_VIEW(mq_web_view_new(tab, uri)); - g_signal_connect(tab->web_view, "notify::favicon", - G_CALLBACK(favicon_cb), tab); g_signal_connect(tab->web_view, "notify::title", G_CALLBACK(title_cb), tab); + tab->tab = mq_tab_label_new(tab, MQ_WEB_VIEW(tab->web_view)); + find_toolbar = mq_find_toolbar_new(MQ_WEB_VIEW(tab->web_view)); /* FIXME: Replace tab->window->config */ @@ -458,56 +152,6 @@ init_non_root(const gchar *uri, MqTab *source) return tab; } -static void -scroll_tab_label(MqTab *tab) -{ - gchar c[5]; /* Up to 4 bytes for a UTF-8 character, plus NUL */ - guint i; - guint j; - - /* Save the first (possibly multibyte) character. */ - c[0] = tab->scrolled_title[0]; - for (i = 1; tab->scrolled_title[i] & 0x80; ++i) { - c[i] = tab->scrolled_title[i]; - } - c[i] = '\0'; - - /* Shift all characters. */ - for (j = 0; tab->scrolled_title[i]; ++i, ++j) { - tab->scrolled_title[j] = tab->scrolled_title[i]; - } - - /* Set the last (possibly multibyte) character. */ - for (--j, i = 0; c[i]; ++i, ++j) { - tab->scrolled_title[j] = c[i]; - } - - update_tab_label(tab); -} - -static void -begin_scrolling_tab_label(MqTab *tab) -{ - PangoFontDescription *font_desc; - - tab->scrolling = TRUE; - tab->scrolled_title = g_strdup_printf("%s ", tab->title); - - font_desc = pango_font_description_new(); - pango_font_description_set_family_static(font_desc, "monospace"); - gtk_widget_override_font(tab->tab_label, font_desc); -} - -static void -end_scrolling_tab_label(MqTab *tab) -{ - tab->scrolling = FALSE; - - gtk_widget_override_font(tab->tab_label, NULL); - - update_tab_label(tab); -} - MqTab * mq_tab_new(const gchar *uri, MqTab *source) { @@ -516,9 +160,7 @@ mq_tab_new(const gchar *uri, MqTab *source) tab = init_non_root(uri, source); if (mq_application_marquee_mode_on(tab->application)) { - begin_scrolling_tab_label(tab); - } else { - tab->scrolling = FALSE; + mq_tab_label_begin_scrolling(MQ_TAB_LABEL(tab->tab)); } append_sibling(tab, source); @@ -537,9 +179,7 @@ mq_tab_new_relative(const gchar *uri, MqTab *source) tab = init_non_root(uri, source); if (mq_application_marquee_mode_on(tab->application)) { - begin_scrolling_tab_label(tab); - } else { - tab->scrolling = FALSE; + mq_tab_label_begin_scrolling(MQ_TAB_LABEL(tab->tab)); } append_child(tab, source); @@ -590,7 +230,7 @@ void mq_tab_update_position(MqTab *tab, guint position) { tab->position = position; - update_tab_label(tab); + mq_tab_label_set_position(tab->tab, position); } guint @@ -634,19 +274,34 @@ mq_tab_seek(MqTab *node, guint position) } void -mq_tab_scroll_tab_labels(MqTab *root) +mq_tab_scroll_tab_labels(MqTab *node) { - foreach_tab(root->first_child, scroll_tab_label); + for (; node; node = node->next) { + if (node->tab) { + mq_tab_label_scroll(MQ_TAB_LABEL(node->tab)); + } + mq_tab_scroll_tab_labels(node->first_child); + } } void -mq_tab_begin_scrolling_tab_labels(MqTab *root) +mq_tab_begin_scrolling_tab_labels(MqTab *node) { - foreach_tab(root->first_child, begin_scrolling_tab_label); + for (; node; node = node->next) { + if (node->tab) { + mq_tab_label_begin_scrolling(MQ_TAB_LABEL(node->tab)); + } + mq_tab_begin_scrolling_tab_labels(node->first_child); + } } void -mq_tab_end_scrolling_tab_labels(MqTab *root) +mq_tab_end_scrolling_tab_labels(MqTab *node) { - foreach_tab(root->first_child, end_scrolling_tab_label); + for (; node; node = node->next) { + if (node->tab) { + mq_tab_label_end_scrolling(MQ_TAB_LABEL(node->tab)); + } + mq_tab_end_scrolling_tab_labels(node->first_child); + } } @@ -44,13 +44,8 @@ struct MqTab { MqWindow *window; GtkWidget *container; GtkWidget *tab; - GtkWidget *tab_image; - GtkWidget *tab_label; const gchar *title; WebKitWebView *web_view; - GtkWidget *popover; - gboolean scrolling; - gchar *scrolled_title; }; MqTab * @@ -87,12 +82,12 @@ MqTab * mq_tab_seek(MqTab *node, guint position); void -mq_tab_scroll_tab_labels(MqTab *root); +mq_tab_scroll_tab_labels(MqTab *node); void -mq_tab_begin_scrolling_tab_labels(MqTab *root); +mq_tab_begin_scrolling_tab_labels(MqTab *node); void -mq_tab_end_scrolling_tab_labels(MqTab *root); +mq_tab_end_scrolling_tab_labels(MqTab *node); #endif |