From 37d844fd664d7d22ac9626ff3d566a4ec52d857c Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 7 Sep 2022 20:33:15 +0200 Subject: [PATCH] Ladybird: Use only the Qt event loop to speed everything up :^) This patch removes the dual-event-loop setup, leaving only the Qt event loop. We teach LibWeb how to drive Qt by installing an EventLoopPlugin. This removes the 50ms latency on all UI interactions (and network requests, etc.) --- Ladybird/BrowserWindow.cpp | 14 +---- Ladybird/BrowserWindow.h | 6 +-- Ladybird/CMakeLists.txt | 2 + Ladybird/EventLoopPluginQt.cpp | 40 +++++++++++++++ Ladybird/EventLoopPluginQt.h | 23 +++++++++ Ladybird/TimerQt.cpp | 94 ++++++++++++++++++++++++++++++++++ Ladybird/TimerQt.h | 42 +++++++++++++++ Ladybird/WebView.cpp | 4 ++ Ladybird/main.cpp | 12 +---- 9 files changed, 209 insertions(+), 28 deletions(-) create mode 100644 Ladybird/EventLoopPluginQt.cpp create mode 100644 Ladybird/EventLoopPluginQt.h create mode 100644 Ladybird/TimerQt.cpp create mode 100644 Ladybird/TimerQt.h diff --git a/Ladybird/BrowserWindow.cpp b/Ladybird/BrowserWindow.cpp index aabdc6cbff..1932ef623d 100644 --- a/Ladybird/BrowserWindow.cpp +++ b/Ladybird/BrowserWindow.cpp @@ -10,7 +10,6 @@ #include "Settings.h" #include "SettingsDialog.h" #include "WebView.h" -#include #include #include #include @@ -18,8 +17,7 @@ extern String s_serenity_resource_root; extern Browser::Settings* s_settings; -BrowserWindow::BrowserWindow(Core::EventLoop& event_loop) - : m_event_loop(event_loop) +BrowserWindow::BrowserWindow() { m_tabs_container = new QTabWidget; m_tabs_container->setElideMode(Qt::TextElideMode::ElideRight); @@ -257,13 +255,3 @@ void BrowserWindow::tab_favicon_changed(int index, QIcon icon) m_tabs_container->setTabIcon(index, icon); setWindowIcon(icon); } - -void BrowserWindow::closeEvent(QCloseEvent* event) -{ - QWidget::closeEvent(event); - - // FIXME: Ladybird only supports one window at the moment. When we support - // multiple windows, we'll only want to fire off the quit event when - // all of the browser windows have closed. - m_event_loop.quit(0); -} diff --git a/Ladybird/BrowserWindow.h b/Ladybird/BrowserWindow.h index b97a76f119..a184dd91c1 100644 --- a/Ladybird/BrowserWindow.h +++ b/Ladybird/BrowserWindow.h @@ -22,14 +22,12 @@ class WebView; class BrowserWindow : public QMainWindow { Q_OBJECT public: - explicit BrowserWindow(Core::EventLoop&); + explicit BrowserWindow(); WebView& view() const { return m_current_tab->view(); } int tab_index(Tab*); - virtual void closeEvent(QCloseEvent*) override; - public slots: void tab_title_changed(int index, QString const&); void tab_favicon_changed(int index, QIcon icon); @@ -44,6 +42,4 @@ private: QTabBar* m_tabs_bar { nullptr }; NonnullOwnPtrVector m_tabs; Tab* m_current_tab { nullptr }; - - Core::EventLoop& m_event_loop; }; diff --git a/Ladybird/CMakeLists.txt b/Ladybird/CMakeLists.txt index e907626c57..4af4585e26 100644 --- a/Ladybird/CMakeLists.txt +++ b/Ladybird/CMakeLists.txt @@ -49,6 +49,7 @@ set(SOURCES ConsoleClient.cpp ConsoleGlobalObject.cpp CookieJar.cpp + EventLoopPluginQt.cpp RequestManagerQt.cpp main.cpp WebView.cpp @@ -56,6 +57,7 @@ set(SOURCES Settings.cpp SettingsDialog.cpp Tab.cpp + TimerQt.cpp ) qt_add_executable(ladybird ${SOURCES} diff --git a/Ladybird/EventLoopPluginQt.cpp b/Ladybird/EventLoopPluginQt.cpp new file mode 100644 index 0000000000..266778430b --- /dev/null +++ b/Ladybird/EventLoopPluginQt.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#define AK_DONT_REPLACE_STD + +#include "EventLoopPluginQt.h" +#include "TimerQt.h" +#include +#include +#include +#include + +namespace Ladybird { + +EventLoopPluginQt::EventLoopPluginQt() = default; +EventLoopPluginQt::~EventLoopPluginQt() = default; + +void EventLoopPluginQt::spin_until(Function goal_condition) +{ + while (!goal_condition()) + QCoreApplication::processEvents(); +} + +void EventLoopPluginQt::deferred_invoke(Function function) +{ + VERIFY(function); + QTimer::singleShot(0, [function = move(function)] { + function(); + }); +} + +NonnullRefPtr EventLoopPluginQt::create_timer() +{ + return TimerQt::create(); +} + +} diff --git a/Ladybird/EventLoopPluginQt.h b/Ladybird/EventLoopPluginQt.h new file mode 100644 index 0000000000..f094ffcb6b --- /dev/null +++ b/Ladybird/EventLoopPluginQt.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Ladybird { + +class EventLoopPluginQt final : public Web::Platform::EventLoopPlugin { +public: + EventLoopPluginQt(); + virtual ~EventLoopPluginQt() override; + + virtual void spin_until(Function goal_condition) override; + virtual void deferred_invoke(Function) override; + virtual NonnullRefPtr create_timer() override; +}; + +} diff --git a/Ladybird/TimerQt.cpp b/Ladybird/TimerQt.cpp new file mode 100644 index 0000000000..3692a635e2 --- /dev/null +++ b/Ladybird/TimerQt.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#define AK_DONT_REPLACE_STD + +#include "TimerQt.h" +#include +#include + +namespace Ladybird { + +NonnullRefPtr TimerQt::create() +{ + return adopt_ref(*new TimerQt); +} + +TimerQt::TimerQt() +{ + m_timer = new QTimer; + QObject::connect(m_timer, &QTimer::timeout, [this] { + if (on_timeout) + on_timeout(); + }); +} + +TimerQt::~TimerQt() +{ + delete m_timer; +} + +void TimerQt::start() +{ + m_timer->start(); +} + +void TimerQt::start(int interval_ms) +{ + m_timer->start(interval_ms); +} + +void TimerQt::restart() +{ + restart(interval()); +} + +void TimerQt::restart(int interval_ms) +{ + if (is_active()) + stop(); + start(interval_ms); +} + +void TimerQt::stop() +{ + m_timer->stop(); +} + +void TimerQt::set_active(bool active) +{ + if (active) + m_timer->start(); + else + m_timer->stop(); +} + +bool TimerQt::is_active() const +{ + return m_timer->isActive(); +} + +int TimerQt::interval() const +{ + return m_timer->interval(); +} + +void TimerQt::set_interval(int interval_ms) +{ + m_timer->setInterval(interval_ms); +} + +bool TimerQt::is_single_shot() const +{ + return m_timer->isSingleShot(); +} + +void TimerQt::set_single_shot(bool single_shot) +{ + m_timer->setSingleShot(single_shot); +} + +} diff --git a/Ladybird/TimerQt.h b/Ladybird/TimerQt.h new file mode 100644 index 0000000000..2057cf38b4 --- /dev/null +++ b/Ladybird/TimerQt.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +class QTimer; + +namespace Ladybird { + +class TimerQt final : public Web::Platform::Timer { +public: + static NonnullRefPtr create(); + + virtual ~TimerQt(); + + virtual void start() override; + virtual void start(int interval_ms) override; + virtual void restart() override; + virtual void restart(int interval_ms) override; + virtual void stop() override; + + virtual void set_active(bool) override; + + virtual bool is_active() const override; + virtual int interval() const override; + virtual void set_interval(int interval_ms) override; + + virtual bool is_single_shot() const override; + virtual void set_single_shot(bool) override; + +private: + TimerQt(); + + QTimer* m_timer { nullptr }; +}; + +} diff --git a/Ladybird/WebView.cpp b/Ladybird/WebView.cpp index 61b1c90392..e304f2cd40 100644 --- a/Ladybird/WebView.cpp +++ b/Ladybird/WebView.cpp @@ -10,6 +10,7 @@ #include "WebView.h" #include "ConsoleClient.h" #include "CookieJar.h" +#include "EventLoopPluginQt.h" #include "RequestManagerQt.h" #include #include @@ -47,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -819,6 +821,8 @@ static void platform_init() void initialize_web_engine() { + Web::Platform::EventLoopPlugin::install(*new Ladybird::EventLoopPluginQt); + Web::ImageDecoding::Decoder::initialize(HeadlessImageDecoderClient::create()); Web::ResourceLoader::initialize(RequestManagerQt::create()); Web::WebSockets::WebSocketClientManager::initialize(HeadlessWebSocketClientManager::create()); diff --git a/Ladybird/main.cpp b/Ladybird/main.cpp index 940f77fefe..c6af32fd3f 100644 --- a/Ladybird/main.cpp +++ b/Ladybird/main.cpp @@ -8,7 +8,6 @@ #include "Settings.h" #include "WebView.h" #include -#include #include #include #include @@ -29,22 +28,15 @@ ErrorOr serenity_main(Main::Arguments arguments) s_settings = new Browser::Settings(); - Core::EventLoop event_loop; - QApplication app(arguments.argc, arguments.argv); - BrowserWindow window(event_loop); + BrowserWindow window; window.setWindowTitle("Ladybird"); window.resize(800, 600); window.show(); - auto qt_event_loop_driver = Core::Timer::create_repeating(50, [&] { - app.processEvents(); - }); - qt_event_loop_driver->start(); - if (!url.is_empty()) { window.view().load(url); } - return event_loop.exec(); + return app.exec(); }