/* * Tab * * 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 "tab.h" #include #include #include #include "tab-label.h" #include "toolbars/find-toolbar.h" #include "toolbars/navigation-toolbar.h" #include "web-view.h" static void update_tree_sizes(MqTab *node, guint step) { if (node) { node->tree_size += step; update_tree_sizes(node->parent, step); } } static void append_child(MqTab *new_node, MqTab *parent) { new_node->root = parent->root; new_node->parent = parent; new_node->next = NULL; new_node->prev = parent->last_child; /* May be NULL */ new_node->first_child = new_node->last_child = NULL; new_node->tree_size = 0; /* Will be updated */ if (parent->last_child) { new_node->position = parent->last_child->position; parent->last_child->next = new_node; } else { new_node->position = parent->position; parent->first_child = new_node; } parent->last_child = new_node; mq_tab_update_positions(new_node, 1); update_tree_sizes(new_node, 1); } static void append_sibling(MqTab *new_node, MqTab *prev_sibling) { new_node->root = prev_sibling->root; new_node->parent = prev_sibling->parent; new_node->prev = prev_sibling; new_node->next = prev_sibling->next; /* May be NULL */ new_node->first_child = new_node->last_child = NULL; new_node->position = prev_sibling->position; /* Will be updated */ new_node->tree_size = 0; /* Will be updated */ if (prev_sibling->next) { prev_sibling->next->prev = new_node; } prev_sibling->next = new_node; mq_tab_update_positions(new_node, 1); update_tree_sizes(new_node, 1); } static void title_cb(WebKitWebView *web_view, GParamSpec G_GNUC_UNUSED *param_spec, MqTab *tab) { tab->title = webkit_web_view_get_title(web_view); mq_window_update_tab_title(tab->window, tab->position, tab->title); } static MqTab * init_non_root(const gchar *uri, MqTab *source) { MqTab *tab; GtkWidget *navigation_toolbar; GtkWidget *find_toolbar; tab = malloc(sizeof(*tab)); tab->parent = NULL; tab->prev = NULL; 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); tab->web_view = WEBKIT_WEB_VIEW(mq_web_view_new(tab, uri)); 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 */ navigation_toolbar = mq_navigation_toolbar_new(tab->window->config, tab, MQ_FIND_TOOLBAR(find_toolbar), MQ_WEB_VIEW(tab->web_view), uri); tab->container = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(tab->container), navigation_toolbar, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(tab->container), find_toolbar, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(tab->container), GTK_WIDGET(tab->web_view), TRUE, TRUE, 0); return tab; } MqTab * mq_tab_new(const gchar *uri, MqTab *source) { MqTab *tab; tab = init_non_root(uri, source); if (mq_application_marquee_mode_on(tab->application)) { mq_tab_label_begin_scrolling(MQ_TAB_LABEL(tab->tab)); } append_sibling(tab, source); mq_window_insert_tab(tab->window, tab->container, tab->tab, tab->position); return tab; } MqTab * mq_tab_new_relative(const gchar *uri, MqTab *source) { MqTab *tab; tab = init_non_root(uri, source); if (mq_application_marquee_mode_on(tab->application)) { mq_tab_label_begin_scrolling(MQ_TAB_LABEL(tab->tab)); } append_child(tab, source); mq_window_insert_tab(tab->window, tab->container, tab->tab, tab->position); return tab; } MqTab * mq_tab_new_root(MqWindow *window) { MqTab *tab; tab = malloc(sizeof(*tab)); tab->root = tab; tab->parent = NULL; tab->prev = NULL; tab->next = NULL; tab->first_child = tab->last_child = NULL; tab->position = 0; tab->tree_size = 1; tab->window = window; return tab; } void mq_tab_quit(MqTab *tab) { mq_window_quit(tab->window); } MqApplication * mq_tab_get_application(MqTab *tab) { return tab->application; } MqWindow * mq_tab_get_window(MqTab *tab) { return tab->window; } void mq_tab_update_positions(MqTab *node, gint step) { if (node) { node->position += step; if (node->tab) { mq_tab_label_set_position(MQ_TAB_LABEL(node->tab), node->position); } if (node->next) { mq_tab_update_positions(node->next, step); } else if (node->parent && node->parent->next) { mq_tab_update_positions(node->parent->next, step); } } } void mq_tab_update_position(MqTab *tab, guint position) { tab->position = position; mq_tab_label_set_position(MQ_TAB_LABEL(tab->tab), position); } guint mq_tab_get_position(MqTab *tab) { return tab->position; } guint mq_tab_get_tree_size(MqTab *tab) { return tab->tree_size; } const gchar * mq_tab_get_title(MqTab *tab) { return tab->title; } MqTab * mq_tab_seek(MqTab *node, guint position) { /* Skip forward to the containing subtree. */ while (node && node->position + node->tree_size <= position) { node = node->next; } /* Check whether we've gone past the end of the tree. */ if (!node) { return NULL; } /* Check whether the sibling we've reached is the node we want. */ if (node->position == position) { return node; } /* Recurse down the subtree. */ return mq_tab_seek(node->first_child, position); } static void foreach_tab(MqTab *node, void (*cb)(MqTab *node, va_list ap), va_list ap) { va_list aq; for (; node; node = node->next) { va_copy(ap, aq); cb(node, aq); va_end(aq); va_copy(ap, aq); foreach_tab(node->first_child, cb, aq); va_end(aq); } } void mq_tab_foreach(MqTab *node, void (*cb)(MqTab *node, va_list ap), ...) { va_list ap; va_start(ap, cb); foreach_tab(node->root->first_child, cb, ap); va_end(ap); } MqTab * mq_tab_root(MqTab *node) { return node ? node->root : NULL; } MqTab * mq_tab_previous(MqTab *node) { return node ? node->prev : NULL; } MqTab * mq_tab_next(MqTab *node) { return node ? node->next : NULL; } MqTab * mq_tab_first_child(MqTab *node) { return node ? node->first_child : NULL; } void mq_tab_scroll_tab_labels(MqTab *node) { 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 *node) { 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 *node) { 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); } }