mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-04 05:19:58 +03:00
Ladybird: Allow posting events to the Qt event loop from other threads
Previously, a QTimer was used to start processing of our event queue in the main Qt event loop. Unfortunately, QTimers are not thread-safe, and disallow starting of a timer from a different thread than it was created in. Instead, use a dummy QObject to post a custom QEvent to the main loop from whatever thread we like, and process our event queue when it is received by our dummy object.
This commit is contained in:
parent
6131d879f7
commit
78e1defbfe
Notes:
sideshowbarker
2024-07-17 03:14:39 +09:00
Author: https://github.com/Zaggy1024 Commit: https://github.com/SerenityOS/serenity/commit/78e1defbfe Pull-request: https://github.com/SerenityOS/serenity/pull/19849 Reviewed-by: https://github.com/ADKaster ✅ Reviewed-by: https://github.com/AtkinsSJ Reviewed-by: https://github.com/kleinesfilmroellchen Reviewed-by: https://github.com/trflynn89
@ -84,6 +84,7 @@ set(SOURCES
|
||||
BrowserWindow.cpp
|
||||
ConsoleWidget.cpp
|
||||
EventLoopImplementationQt.cpp
|
||||
EventLoopImplementationQtEventTarget.cpp
|
||||
HelperProcess.cpp
|
||||
InspectorWidget.cpp
|
||||
LocationEdit.cpp
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "EventLoopImplementationQt.h"
|
||||
#include "EventLoopImplementationQtEventTarget.h"
|
||||
#include <AK/IDAllocator.h>
|
||||
#include <LibCore/Event.h>
|
||||
#include <LibCore/Notifier.h>
|
||||
@ -149,16 +150,21 @@ void EventLoopManagerQt::unregister_notifier(Core::Notifier& notifier)
|
||||
|
||||
void EventLoopManagerQt::did_post_event()
|
||||
{
|
||||
m_process_core_events_timer.start();
|
||||
QCoreApplication::postEvent(m_main_thread_event_target.ptr(), new QtEventLoopManagerEvent(QtEventLoopManagerEvent::process_event_queue_event_type()));
|
||||
}
|
||||
|
||||
bool EventLoopManagerQt::event_target_received_event(Badge<EventLoopImplementationQtEventTarget>, QEvent* event)
|
||||
{
|
||||
if (event->type() == QtEventLoopManagerEvent::process_event_queue_event_type()) {
|
||||
Core::ThreadEventQueue::current().process();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EventLoopManagerQt::EventLoopManagerQt()
|
||||
: m_main_thread_event_target(make<EventLoopImplementationQtEventTarget>())
|
||||
{
|
||||
m_process_core_events_timer.setSingleShot(true);
|
||||
m_process_core_events_timer.setInterval(0);
|
||||
QObject::connect(&m_process_core_events_timer, &QTimer::timeout, [] {
|
||||
Core::ThreadEventQueue::current().process();
|
||||
});
|
||||
}
|
||||
|
||||
EventLoopManagerQt::~EventLoopManagerQt() = default;
|
||||
|
@ -6,16 +6,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Badge.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <LibCore/EventLoopImplementation.h>
|
||||
#include <QEvent>
|
||||
#include <QEventLoop>
|
||||
#include <QSocketNotifier>
|
||||
#include <QTimer>
|
||||
|
||||
namespace Ladybird {
|
||||
|
||||
class EventLoopImplementationQtEventTarget;
|
||||
|
||||
class EventLoopManagerQt final : public Core::EventLoopManager {
|
||||
public:
|
||||
EventLoopManagerQt();
|
||||
@ -29,13 +33,28 @@ public:
|
||||
virtual void unregister_notifier(Core::Notifier&) override;
|
||||
|
||||
virtual void did_post_event() override;
|
||||
static bool event_target_received_event(Badge<EventLoopImplementationQtEventTarget>, QEvent* event);
|
||||
|
||||
// FIXME: These APIs only exist for obscure use-cases inside SerenityOS. Try to get rid of them.
|
||||
virtual int register_signal(int, Function<void(int)>) override { return 0; }
|
||||
virtual void unregister_signal(int) override { }
|
||||
|
||||
private:
|
||||
QTimer m_process_core_events_timer;
|
||||
NonnullOwnPtr<EventLoopImplementationQtEventTarget> m_main_thread_event_target;
|
||||
};
|
||||
|
||||
class QtEventLoopManagerEvent final : public QEvent {
|
||||
public:
|
||||
static QEvent::Type process_event_queue_event_type()
|
||||
{
|
||||
static auto const type = static_cast<QEvent::Type>(QEvent::registerEventType());
|
||||
return type;
|
||||
}
|
||||
|
||||
QtEventLoopManagerEvent(QEvent::Type type)
|
||||
: QEvent(type)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class EventLoopImplementationQt final : public Core::EventLoopImplementation {
|
||||
|
16
Ladybird/EventLoopImplementationQtEventTarget.cpp
Normal file
16
Ladybird/EventLoopImplementationQtEventTarget.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Gregory Bertilson <zaggy1024@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "EventLoopImplementationQtEventTarget.h"
|
||||
|
||||
namespace Ladybird {
|
||||
|
||||
bool EventLoopImplementationQtEventTarget::event(QEvent* event)
|
||||
{
|
||||
return EventLoopManagerQt::event_target_received_event({}, event);
|
||||
}
|
||||
|
||||
}
|
22
Ladybird/EventLoopImplementationQtEventTarget.h
Normal file
22
Ladybird/EventLoopImplementationQtEventTarget.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Gregory Bertilson <zaggy1024@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QEvent>
|
||||
|
||||
#include "EventLoopImplementationQt.h"
|
||||
|
||||
namespace Ladybird {
|
||||
|
||||
class EventLoopImplementationQtEventTarget final : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
virtual bool event(QEvent* event) override;
|
||||
};
|
||||
|
||||
}
|
@ -9,6 +9,7 @@ set(WEBCONTENT_SOURCES
|
||||
../AudioCodecPluginQt.cpp
|
||||
../AudioThread.cpp
|
||||
../EventLoopImplementationQt.cpp
|
||||
../EventLoopImplementationQtEventTarget.cpp
|
||||
../FontPlugin.cpp
|
||||
../HelperProcess.cpp
|
||||
../ImageCodecPlugin.cpp
|
||||
|
Loading…
Reference in New Issue
Block a user