From 719168a1cdbb524da47f6fe67bfbda47a454edc5 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 17 May 2021 23:15:20 +0200 Subject: [PATCH] Browser: Move main browser window logic into a BrowserWindow class Having so much the logic and lambdas in main() was getting unwieldy. Moving it into a class simplifies this, and also opens up a path towards supporting "Open in New Window" :^) --- .../Applications/Browser/BrowserWindow.cpp | 166 ++++++++++++++++++ Userland/Applications/Browser/BrowserWindow.h | 38 ++++ Userland/Applications/Browser/CMakeLists.txt | 9 +- Userland/Applications/Browser/main.cpp | 166 ++---------------- 4 files changed, 228 insertions(+), 151 deletions(-) create mode 100644 Userland/Applications/Browser/BrowserWindow.cpp create mode 100644 Userland/Applications/Browser/BrowserWindow.h diff --git a/Userland/Applications/Browser/BrowserWindow.cpp b/Userland/Applications/Browser/BrowserWindow.cpp new file mode 100644 index 0000000000..bcb2498069 --- /dev/null +++ b/Userland/Applications/Browser/BrowserWindow.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2021, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "BrowserWindow.h" +#include "BookmarksBarWidget.h" +#include "CookieJar.h" +#include "Tab.h" +#include +#include +#include +#include +#include +#include +#include + +namespace Browser { + +extern bool g_single_process; +extern String g_home_url; + +static String bookmarks_file_path() +{ + StringBuilder builder; + builder.append(Core::StandardPaths::config_directory()); + builder.append("/bookmarks.json"); + return builder.to_string(); +} + +BrowserWindow::BrowserWindow(CookieJar& cookie_jar, URL url) + : m_cookie_jar(cookie_jar) + , m_window_actions(*this) +{ + auto app_icon = GUI::Icon::default_icon("app-browser"); + m_bookmarks_bar = Browser::BookmarksBarWidget::construct(Browser::bookmarks_file_path(), true); + + resize(640, 480); + set_icon(app_icon.bitmap_for_size(16)); + set_title("Browser"); + + auto& widget = set_main_widget(); + widget.load_from_gml(browser_window_gml); + + auto& top_line = *widget.find_descendant_of_type_named("top_line"); + + m_tab_widget = *widget.find_descendant_of_type_named("tab_widget"); + + m_tab_widget->on_tab_count_change = [&top_line](size_t tab_count) { + top_line.set_visible(tab_count > 1); + }; + + m_tab_widget->on_change = [this](auto& active_widget) { + auto& tab = static_cast(active_widget); + set_window_title_for_tab(tab); + tab.did_become_active(); + }; + + m_tab_widget->on_middle_click = [](auto& clicked_widget) { + auto& tab = static_cast(clicked_widget); + tab.on_tab_close_request(tab); + }; + + m_tab_widget->on_context_menu_request = [](auto& clicked_widget, const GUI::ContextMenuEvent& context_menu_event) { + auto& tab = static_cast(clicked_widget); + tab.context_menu_requested(context_menu_event.screen_position()); + }; + + m_window_actions.on_create_new_tab = [this] { + create_new_tab(Browser::g_home_url, true); + }; + + m_window_actions.on_next_tab = [this] { + m_tab_widget->activate_next_tab(); + }; + + m_window_actions.on_previous_tab = [this] { + m_tab_widget->activate_previous_tab(); + }; + + m_window_actions.on_about = [this] { + auto app_icon = GUI::Icon::default_icon("app-browser"); + GUI::AboutDialog::show("Browser", app_icon.bitmap_for_size(32), this); + }; + + m_window_actions.on_show_bookmarks_bar = [](auto& action) { + Browser::BookmarksBarWidget::the().set_visible(action.is_checked()); + }; + + m_window_actions.show_bookmarks_bar_action().set_checked(true); + + create_new_tab(move(url), true); +} + +BrowserWindow::~BrowserWindow() +{ +} + +GUI::TabWidget& BrowserWindow::tab_widget() +{ + return *m_tab_widget; +} + +void BrowserWindow::set_window_title_for_tab(Tab const& tab) +{ + auto& title = tab.title(); + auto url = tab.url(); + set_title(String::formatted("{} - Browser", title.is_empty() ? url.to_string() : title)); +} + +void BrowserWindow::create_new_tab(URL url, bool activate) +{ + auto type = Browser::g_single_process ? Browser::Tab::Type::InProcessWebView : Browser::Tab::Type::OutOfProcessWebView; + auto& new_tab = m_tab_widget->add_tab("New tab", type); + + m_tab_widget->set_bar_visible(!is_fullscreen() && m_tab_widget->children().size() > 1); + + auto default_favicon = Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-html.png"); + VERIFY(default_favicon); + m_tab_widget->set_tab_icon(new_tab, default_favicon); + + new_tab.on_title_change = [this, &new_tab](auto title) { + m_tab_widget->set_tab_title(new_tab, title); + if (m_tab_widget->active_widget() == &new_tab) + set_window_title_for_tab(new_tab); + }; + + new_tab.on_favicon_change = [this, &new_tab](auto& bitmap) { + m_tab_widget->set_tab_icon(new_tab, &bitmap); + }; + + new_tab.on_tab_open_request = [this](auto& url) { + create_new_tab(url, true); + }; + + new_tab.on_tab_close_request = [this](auto& tab) { + m_tab_widget->deferred_invoke([this, &tab](auto&) { + m_tab_widget->remove_tab(tab); + m_tab_widget->set_bar_visible(!is_fullscreen() && m_tab_widget->children().size() > 1); + if (m_tab_widget->children().is_empty()) + close(); + }); + }; + + new_tab.on_get_cookie = [this](auto& url, auto source) -> String { + return m_cookie_jar.get_cookie(url, source); + }; + + new_tab.on_set_cookie = [this](auto& url, auto& cookie, auto source) { + m_cookie_jar.set_cookie(url, cookie, source); + }; + + new_tab.on_dump_cookies = [this]() { + m_cookie_jar.dump_cookies(); + }; + + new_tab.load(url); + + dbgln("Added new tab {:p}, loading {}", &new_tab, url); + + if (activate) + m_tab_widget->set_active_widget(&new_tab); +} + +} diff --git a/Userland/Applications/Browser/BrowserWindow.h b/Userland/Applications/Browser/BrowserWindow.h new file mode 100644 index 0000000000..02d8e92318 --- /dev/null +++ b/Userland/Applications/Browser/BrowserWindow.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include "BookmarksBarWidget.h" +#include "WindowActions.h" +#include + +namespace Browser { + +class CookieJar; +class Tab; + +class BrowserWindow final : public GUI::Window { + C_OBJECT(BrowserWindow); + +public: + virtual ~BrowserWindow() override; + + GUI::TabWidget& tab_widget(); + void create_new_tab(URL, bool activate); + +private: + explicit BrowserWindow(CookieJar&, URL); + + void set_window_title_for_tab(Tab const&); + + CookieJar& m_cookie_jar; + WindowActions m_window_actions; + RefPtr m_tab_widget; + RefPtr m_bookmarks_bar; +}; + +} diff --git a/Userland/Applications/Browser/CMakeLists.txt b/Userland/Applications/Browser/CMakeLists.txt index bfec5c5b6a..9622e719b0 100644 --- a/Userland/Applications/Browser/CMakeLists.txt +++ b/Userland/Applications/Browser/CMakeLists.txt @@ -5,17 +5,18 @@ compile_gml(Tab.gml TabGML.h tab_gml) set(SOURCES BookmarksBarWidget.cpp BrowserConsoleClient.cpp + BrowserWindow.cpp + BrowserWindowGML.h ConsoleWidget.cpp CookieJar.cpp DownloadWidget.cpp + EditBookmarkGML.h History.cpp InspectorWidget.cpp - main.cpp Tab.cpp - WindowActions.cpp - BrowserWindowGML.h - EditBookmarkGML.h TabGML.h + WindowActions.cpp + main.cpp ) serenity_app(Browser ICON app-browser) diff --git a/Userland/Applications/Browser/main.cpp b/Userland/Applications/Browser/main.cpp index 50f1e785f3..331a9a75e1 100644 --- a/Userland/Applications/Browser/main.cpp +++ b/Userland/Applications/Browser/main.cpp @@ -4,45 +4,31 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include "BookmarksBarWidget.h" #include "Browser.h" +#include "BrowserWindow.h" #include "CookieJar.h" #include "Tab.h" #include "WindowActions.h" #include -#include #include #include #include #include #include -#include #include #include #include -#include #include -#include -#include #include #include #include #include -#include #include namespace Browser { String g_home_url; -static bool s_single_process = false; - -static String bookmarks_file_path() -{ - StringBuilder builder; - builder.append(Core::StandardPaths::config_directory()); - builder.append("/bookmarks.json"); - return builder.to_string(); -} +bool g_single_process = false; } @@ -61,13 +47,13 @@ int main(int argc, char** argv) const char* specified_url = nullptr; Core::ArgsParser args_parser; - args_parser.add_option(Browser::s_single_process, "Single-process mode", "single-process", 's'); + args_parser.add_option(Browser::g_single_process, "Single-process mode", "single-process", 's'); args_parser.add_positional_argument(specified_url, "URL to open", "url", Core::ArgsParser::Required::No); args_parser.parse(argc, argv); auto app = GUI::Application::construct(argc, argv); - if (Browser::s_single_process) { + if (Browser::g_single_process) { // Connect to the RequestServer and the WebSocket service immediately so we don't need to unveil their portals. Web::ResourceLoader::the(); Web::HTML::WebSocketClientManager::the(); @@ -126,105 +112,6 @@ int main(int argc, char** argv) } } - bool bookmarksbar_enabled = true; - auto bookmarks_bar = Browser::BookmarksBarWidget::construct(Browser::bookmarks_file_path(), bookmarksbar_enabled); - - Browser::CookieJar cookie_jar; - - auto window = GUI::Window::construct(); - window->resize(640, 480); - window->set_icon(app_icon.bitmap_for_size(16)); - window->set_title("Browser"); - - auto& widget = window->set_main_widget(); - widget.load_from_gml(browser_window_gml); - - auto& top_line = *widget.find_descendant_of_type_named("top_line"); - - auto& tab_widget = *widget.find_descendant_of_type_named("tab_widget"); - - tab_widget.on_tab_count_change = [&](size_t tab_count) { - top_line.set_visible(tab_count > 1); - }; - - auto default_favicon = Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-html.png"); - VERIFY(default_favicon); - - auto set_window_title_for_tab = [&window](auto& tab) { - auto& title = tab.title(); - auto url = tab.url(); - window->set_title(String::formatted("{} - Browser", title.is_empty() ? url.to_string() : title)); - }; - - tab_widget.on_change = [&](auto& active_widget) { - auto& tab = static_cast(active_widget); - set_window_title_for_tab(tab); - tab.did_become_active(); - }; - - tab_widget.on_middle_click = [&](auto& clicked_widget) { - auto& tab = static_cast(clicked_widget); - tab.on_tab_close_request(tab); - }; - - tab_widget.on_context_menu_request = [&](auto& clicked_widget, const GUI::ContextMenuEvent& context_menu_event) { - auto& tab = static_cast(clicked_widget); - tab.context_menu_requested(context_menu_event.screen_position()); - }; - - Browser::WindowActions window_actions(*window); - - Function create_new_tab; - create_new_tab = [&](auto url, auto activate) { - auto type = Browser::s_single_process ? Browser::Tab::Type::InProcessWebView : Browser::Tab::Type::OutOfProcessWebView; - auto& new_tab = tab_widget.add_tab("New tab", type); - - tab_widget.set_bar_visible(!window->is_fullscreen() && tab_widget.children().size() > 1); - tab_widget.set_tab_icon(new_tab, default_favicon); - - new_tab.on_title_change = [&](auto title) { - tab_widget.set_tab_title(new_tab, title); - if (tab_widget.active_widget() == &new_tab) - set_window_title_for_tab(new_tab); - }; - - new_tab.on_favicon_change = [&](auto& bitmap) { - tab_widget.set_tab_icon(new_tab, &bitmap); - }; - - new_tab.on_tab_open_request = [&](auto& url) { - create_new_tab(url, true); - }; - - new_tab.on_tab_close_request = [&](auto& tab) { - tab_widget.deferred_invoke([&](auto&) { - tab_widget.remove_tab(tab); - tab_widget.set_bar_visible(!window->is_fullscreen() && tab_widget.children().size() > 1); - if (tab_widget.children().is_empty()) - app->quit(); - }); - }; - - new_tab.on_get_cookie = [&](auto& url, auto source) -> String { - return cookie_jar.get_cookie(url, source); - }; - - new_tab.on_set_cookie = [&](auto& url, auto& cookie, auto source) { - cookie_jar.set_cookie(url, cookie, source); - }; - - new_tab.on_dump_cookies = [&]() { - cookie_jar.dump_cookies(); - }; - - new_tab.load(url); - - dbgln("Added new tab {:p}, loading {}", &new_tab, url); - - if (activate) - tab_widget.set_active_widget(&new_tab); - }; - URL first_url = Browser::g_home_url; if (specified_url) { if (Core::File::exists(specified_url)) { @@ -234,42 +121,27 @@ int main(int argc, char** argv) } } + Browser::CookieJar cookie_jar; + auto window = Browser::BrowserWindow::construct(cookie_jar, first_url); + app->on_action_enter = [&](GUI::Action& action) { - auto* tab = static_cast(tab_widget.active_widget()); - if (!tab) - return; - tab->action_entered(action); + if (auto* browser_window = dynamic_cast(app->active_window())) { + auto* tab = static_cast(browser_window->tab_widget().active_widget()); + if (!tab) + return; + tab->action_entered(action); + } }; app->on_action_leave = [&](auto& action) { - auto* tab = static_cast(tab_widget.active_widget()); - if (!tab) - return; - tab->action_left(action); + if (auto* browser_window = dynamic_cast(app->active_window())) { + auto* tab = static_cast(browser_window->tab_widget().active_widget()); + if (!tab) + return; + tab->action_left(action); + } }; - window_actions.on_create_new_tab = [&] { - create_new_tab(Browser::g_home_url, true); - }; - - window_actions.on_next_tab = [&] { - tab_widget.activate_next_tab(); - }; - - window_actions.on_previous_tab = [&] { - tab_widget.activate_previous_tab(); - }; - - window_actions.on_about = [&] { - GUI::AboutDialog::show("Browser", app_icon.bitmap_for_size(32), window); - }; - - window_actions.on_show_bookmarks_bar = [&](auto& action) { - Browser::BookmarksBarWidget::the().set_visible(action.is_checked()); - }; - window_actions.show_bookmarks_bar_action().set_checked(bookmarksbar_enabled); - - create_new_tab(first_url, true); window->show(); return app->exec();