Ladybird: Support multiple browser windows in Qt chrome

This also moves the ownership of the TaskManger to the Application.
This commit is contained in:
Andrew Kaster 2024-04-26 18:53:55 -06:00 committed by Tim Flynn
parent 2bb0f65309
commit 6b5deb2259
Notes: sideshowbarker 2024-07-17 00:49:59 +09:00
5 changed files with 93 additions and 42 deletions

View file

@ -6,6 +6,7 @@
#include "Application.h"
#include "StringUtils.h"
#include "TaskManagerWindow.h"
#include <LibWebView/URL.h>
#include <QFileOpenEvent>
@ -16,6 +17,11 @@ Application::Application(int& argc, char** argv)
{
}
Application::~Application()
{
close_task_manager_window();
}
bool Application::event(QEvent* event)
{
switch (event->type()) {
@ -37,4 +43,33 @@ bool Application::event(QEvent* event)
return QApplication::event(event);
}
void Application::show_task_manager_window()
{
if (!m_task_manager_window) {
m_task_manager_window = new TaskManagerWindow(nullptr);
}
m_task_manager_window->show();
m_task_manager_window->activateWindow();
m_task_manager_window->raise();
}
void Application::close_task_manager_window()
{
if (m_task_manager_window) {
m_task_manager_window->close();
delete m_task_manager_window;
m_task_manager_window = nullptr;
}
}
BrowserWindow& Application::new_window(Vector<URL::URL> const& initial_urls, WebView::CookieJar& cookie_jar, WebContentOptions const& web_content_options, StringView webdriver_content_ipc_path)
{
auto* window = new BrowserWindow(initial_urls, cookie_jar, web_content_options, webdriver_content_ipc_path);
set_active_window(*window);
window->show();
window->activateWindow();
window->raise();
return *window;
}
}

View file

@ -7,6 +7,8 @@
#pragma once
#include <AK/Function.h>
#include <AK/HashTable.h>
#include <Ladybird/Qt/BrowserWindow.h>
#include <LibProtocol/RequestClient.h>
#include <LibURL/URL.h>
#include <QApplication>
@ -18,11 +20,24 @@ class Application : public QApplication {
public:
Application(int& argc, char** argv);
virtual ~Application() override;
virtual bool event(QEvent* event) override;
Function<void(URL::URL)> on_open_file;
RefPtr<Protocol::RequestClient> request_server_client;
BrowserWindow& new_window(Vector<URL::URL> const& initial_urls, WebView::CookieJar&, WebContentOptions const&, StringView webdriver_content_ipc_path);
void show_task_manager_window();
void close_task_manager_window();
BrowserWindow& active_window() { return *m_active_window; }
void set_active_window(BrowserWindow& w) { m_active_window = &w; }
private:
TaskManagerWindow* m_task_manager_window { nullptr };
BrowserWindow* m_active_window { nullptr };
};
}

View file

@ -8,6 +8,7 @@
*/
#include "BrowserWindow.h"
#include "Application.h"
#include "Icon.h"
#include "Settings.h"
#include "SettingsDialog.h"
@ -82,6 +83,10 @@ BrowserWindow::BrowserWindow(Vector<URL::URL> const& initial_urls, WebView::Cook
m_new_tab_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::AddTab));
menu->addAction(m_new_tab_action);
m_new_window_action = new QAction("New &Window", this);
m_new_window_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::New));
menu->addAction(m_new_window_action);
auto* close_current_tab_action = new QAction("&Close Current Tab", this);
close_current_tab_action->setIcon(load_icon_from_uri("resource://icons/16x16/close-tab.png"sv));
close_current_tab_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::Close));
@ -213,8 +218,8 @@ BrowserWindow::BrowserWindow(Vector<URL::URL> const& initial_urls, WebView::Cook
task_manager_action->setIcon(load_icon_from_uri("resource://icons/16x16/app-system-monitor.png"sv));
task_manager_action->setShortcuts({ QKeySequence("Ctrl+Shift+M") });
inspect_menu->addAction(task_manager_action);
QObject::connect(task_manager_action, &QAction::triggered, this, [this] {
show_task_manager_window();
QObject::connect(task_manager_action, &QAction::triggered, this, [] {
static_cast<Ladybird::Application*>(QApplication::instance())->show_task_manager_window();
});
auto* debug_menu = menuBar()->addMenu("&Debug");
@ -391,6 +396,10 @@ BrowserWindow::BrowserWindow(Vector<URL::URL> const& initial_urls, WebView::Cook
QObject::connect(m_new_tab_action, &QAction::triggered, this, [this] {
new_tab_from_url(ak_url_from_qstring(Settings::the()->new_tab_page()), Web::HTML::ActivateTab::Yes);
});
QObject::connect(m_new_window_action, &QAction::triggered, this, [this] {
auto initial_urls = Vector<URL::URL> { ak_url_from_qstring(Settings::the()->new_tab_page()) };
(void)static_cast<Ladybird::Application*>(QApplication::instance())->new_window(initial_urls, m_cookie_jar, m_web_content_options, m_webdriver_content_ipc_path);
});
QObject::connect(open_file_action, &QAction::triggered, this, &BrowserWindow::open_file);
QObject::connect(settings_action, &QAction::triggered, this, [this] {
if (!m_settings_dialog) {
@ -864,6 +873,9 @@ bool BrowserWindow::event(QEvent* event)
}
#endif
if (event->type() == QEvent::WindowActivate)
static_cast<Ladybird::Application*>(QApplication::instance())->set_active_window(*this);
return QMainWindow::event(event);
}
@ -917,23 +929,9 @@ void BrowserWindow::closeEvent(QCloseEvent* event)
Settings::the()->set_last_size(size());
Settings::the()->set_is_maximized(isMaximized());
QObject::deleteLater();
QMainWindow::closeEvent(event);
}
void BrowserWindow::show_task_manager_window()
{
if (!m_task_manager_window) {
m_task_manager_window = new TaskManagerWindow(this);
}
m_task_manager_window->show();
m_task_manager_window->activateWindow();
m_task_manager_window->raise();
}
void BrowserWindow::close_task_manager_window()
{
if (m_task_manager_window)
m_task_manager_window->close();
}
}

View file

@ -57,6 +57,11 @@ public:
return *m_new_tab_action;
}
QAction& new_window_action()
{
return *m_new_window_action;
}
QAction& copy_selection_action()
{
return *m_copy_selection_action;
@ -141,9 +146,6 @@ private:
QString tool_tip_for_page_mute_state(Tab&) const;
QTabBar::ButtonPosition audio_button_position_for_tab(int tab_index) const;
void show_task_manager_window();
void close_task_manager_window();
QScreen* m_current_screen;
double m_device_pixel_ratio { 0 };
@ -155,6 +157,7 @@ private:
QAction* m_go_forward_action { nullptr };
QAction* m_reload_action { nullptr };
QAction* m_new_tab_action { nullptr };
QAction* m_new_window_action { nullptr };
QAction* m_copy_selection_action { nullptr };
QAction* m_paste_action { nullptr };
QAction* m_select_all_action { nullptr };
@ -163,9 +166,6 @@ private:
SettingsDialog* m_settings_dialog { nullptr };
// FIXME: This should be owned at a higher level in case we have multiple browser windows
TaskManagerWindow* m_task_manager_window { nullptr };
WebView::CookieJar& m_cookie_jar;
WebContentOptions m_web_content_options;

View file

@ -103,6 +103,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
bool debug_web_content = false;
bool log_all_js_exceptions = false;
bool enable_idl_tracing = false;
bool new_window = false;
Core::ArgsParser args_parser;
args_parser.set_general_help("The Ladybird web browser :^)");
@ -117,17 +118,29 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
args_parser.add_option(log_all_js_exceptions, "Log all JavaScript exceptions", "log-all-js-exceptions");
args_parser.add_option(enable_idl_tracing, "Enable IDL tracing", "enable-idl-tracing");
args_parser.add_option(expose_internals_object, "Expose internals object", "expose-internals-object");
args_parser.add_option(new_window, "Force opening in a new window", "new-window", 'n');
args_parser.parse(arguments);
WebView::ChromeProcess chrome_process;
auto new_window = false;
if (TRY(chrome_process.connect(raw_urls, new_window)) == WebView::ChromeProcess::ProcessDisposition::ExitProcess) {
outln("Opening in existing process");
return 0;
}
chrome_process.on_new_window = [](auto const& urls) {
dbgln("asked to open new window with urls: {}", urls);
chrome_process.on_new_tab = [&](auto const& raw_urls) {
auto& window = app.active_window();
auto urls = sanitize_urls(raw_urls);
for (size_t i = 0; i < urls.size(); ++i) {
window.new_tab_from_url(urls[i], (i == 0) ? Web::HTML::ActivateTab::Yes : Web::HTML::ActivateTab::No);
}
window.show();
window.activateWindow();
window.raise();
};
app.on_open_file = [&](auto file_url) {
auto& window = app.active_window();
window.view().load(file_url);
};
WebView::ProcessManager::initialize();
@ -171,23 +184,13 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
.expose_internals_object = expose_internals_object ? Ladybird::ExposeInternalsObject::Yes : Ladybird::ExposeInternalsObject::No,
};
Ladybird::BrowserWindow window(sanitize_urls(raw_urls), cookie_jar, web_content_options, webdriver_content_ipc_path);
chrome_process.on_new_window = [&](auto const& urls) {
app.new_window(sanitize_urls(urls), cookie_jar, web_content_options, webdriver_content_ipc_path);
};
auto& window = app.new_window(sanitize_urls(raw_urls), cookie_jar, web_content_options, webdriver_content_ipc_path);
window.setWindowTitle("Ladybird");
chrome_process.on_new_tab = [&](auto const& raw_urls) {
auto urls = sanitize_urls(raw_urls);
for (size_t i = 0; i < urls.size(); ++i) {
window.new_tab_from_url(urls[i], (i == 0) ? Web::HTML::ActivateTab::Yes : Web::HTML::ActivateTab::No);
}
window.show();
window.activateWindow();
window.raise();
};
app.on_open_file = [&](auto file_url) {
window.view().load(file_url);
};
if (Ladybird::Settings::the()->is_maximized()) {
window.showMaximized();
} else {