2023-04-24 15:51:19 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2022-2023, Andreas Kling <kling@serenityos.org>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "EventLoopImplementationQt.h"
|
|
|
|
#include <AK/IDAllocator.h>
|
|
|
|
#include <LibCore/Event.h>
|
|
|
|
#include <LibCore/Notifier.h>
|
|
|
|
#include <LibCore/Object.h>
|
|
|
|
#include <LibCore/ThreadEventQueue.h>
|
2023-04-25 17:53:07 +03:00
|
|
|
#include <QCoreApplication>
|
2023-04-24 15:51:19 +03:00
|
|
|
#include <QTimer>
|
|
|
|
|
|
|
|
namespace Ladybird {
|
|
|
|
|
|
|
|
struct ThreadData;
|
|
|
|
static thread_local ThreadData* s_thread_data;
|
|
|
|
|
|
|
|
struct ThreadData {
|
|
|
|
static ThreadData& the()
|
|
|
|
{
|
|
|
|
if (!s_thread_data) {
|
|
|
|
// FIXME: Don't leak this.
|
|
|
|
s_thread_data = new ThreadData;
|
|
|
|
}
|
|
|
|
return *s_thread_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
IDAllocator timer_id_allocator;
|
|
|
|
HashMap<int, NonnullOwnPtr<QTimer>> timers;
|
|
|
|
HashMap<Core::Notifier*, NonnullOwnPtr<QSocketNotifier>> notifiers;
|
|
|
|
};
|
|
|
|
|
|
|
|
EventLoopImplementationQt::EventLoopImplementationQt()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
EventLoopImplementationQt::~EventLoopImplementationQt() = default;
|
|
|
|
|
|
|
|
int EventLoopImplementationQt::exec()
|
|
|
|
{
|
2023-04-25 17:53:07 +03:00
|
|
|
if (is_main_loop())
|
|
|
|
return QCoreApplication::exec();
|
|
|
|
return m_event_loop.exec();
|
2023-04-24 15:51:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t EventLoopImplementationQt::pump(PumpMode mode)
|
|
|
|
{
|
2023-04-25 17:53:07 +03:00
|
|
|
auto result = Core::ThreadEventQueue::current().process();
|
|
|
|
if (mode == PumpMode::WaitForEvents) {
|
|
|
|
if (is_main_loop())
|
|
|
|
QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
|
|
|
|
else
|
|
|
|
m_event_loop.processEvents(QEventLoop::WaitForMoreEvents);
|
|
|
|
} else {
|
|
|
|
}
|
|
|
|
result += Core::ThreadEventQueue::current().process();
|
2023-04-24 15:51:19 +03:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EventLoopImplementationQt::quit(int code)
|
|
|
|
{
|
2023-04-25 17:53:07 +03:00
|
|
|
if (is_main_loop())
|
|
|
|
QCoreApplication::exit(code);
|
|
|
|
else
|
|
|
|
m_event_loop.exit(code);
|
2023-04-24 15:51:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void EventLoopImplementationQt::wake()
|
|
|
|
{
|
2023-04-25 17:53:07 +03:00
|
|
|
if (!is_main_loop())
|
|
|
|
m_event_loop.wakeUp();
|
2023-04-24 15:51:19 +03:00
|
|
|
}
|
|
|
|
|
2023-04-26 19:51:07 +03:00
|
|
|
void EventLoopImplementationQt::post_event(Core::Object& receiver, NonnullOwnPtr<Core::Event>&& event)
|
2023-04-24 15:51:19 +03:00
|
|
|
{
|
2023-04-26 19:51:07 +03:00
|
|
|
m_thread_event_queue.post_event(receiver, move(event));
|
|
|
|
if (&m_thread_event_queue != &Core::ThreadEventQueue::current())
|
|
|
|
wake();
|
2023-04-24 15:51:19 +03:00
|
|
|
}
|
|
|
|
|
2023-04-25 17:53:07 +03:00
|
|
|
static void qt_timer_fired(int timer_id, Core::TimerShouldFireWhenNotVisible should_fire_when_not_visible, Core::Object& object)
|
|
|
|
{
|
|
|
|
if (should_fire_when_not_visible == Core::TimerShouldFireWhenNotVisible::No) {
|
|
|
|
if (!object.is_visible_for_timer_purposes())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Core::TimerEvent event(timer_id);
|
|
|
|
object.dispatch_event(event);
|
|
|
|
}
|
|
|
|
|
2023-04-25 18:38:48 +03:00
|
|
|
int EventLoopManagerQt::register_timer(Core::Object& object, int milliseconds, bool should_reload, Core::TimerShouldFireWhenNotVisible should_fire_when_not_visible)
|
2023-04-24 15:51:19 +03:00
|
|
|
{
|
|
|
|
auto& thread_data = ThreadData::the();
|
|
|
|
auto timer = make<QTimer>();
|
|
|
|
timer->setInterval(milliseconds);
|
|
|
|
timer->setSingleShot(!should_reload);
|
|
|
|
auto timer_id = thread_data.timer_id_allocator.allocate();
|
|
|
|
auto weak_object = object.make_weak_ptr();
|
|
|
|
QObject::connect(timer, &QTimer::timeout, [timer_id, should_fire_when_not_visible, weak_object = move(weak_object)] {
|
|
|
|
auto object = weak_object.strong_ref();
|
|
|
|
if (!object)
|
|
|
|
return;
|
2023-04-25 17:53:07 +03:00
|
|
|
qt_timer_fired(timer_id, should_fire_when_not_visible, *object);
|
2023-04-24 15:51:19 +03:00
|
|
|
});
|
|
|
|
timer->start();
|
|
|
|
thread_data.timers.set(timer_id, move(timer));
|
|
|
|
return timer_id;
|
|
|
|
}
|
|
|
|
|
2023-04-25 18:38:48 +03:00
|
|
|
bool EventLoopManagerQt::unregister_timer(int timer_id)
|
2023-04-24 15:51:19 +03:00
|
|
|
{
|
|
|
|
auto& thread_data = ThreadData::the();
|
|
|
|
thread_data.timer_id_allocator.deallocate(timer_id);
|
|
|
|
return thread_data.timers.remove(timer_id);
|
|
|
|
}
|
|
|
|
|
2023-04-25 17:53:07 +03:00
|
|
|
static void qt_notifier_activated(Core::Notifier& notifier)
|
|
|
|
{
|
|
|
|
Core::NotifierActivationEvent event(notifier.fd());
|
|
|
|
notifier.dispatch_event(event);
|
|
|
|
}
|
|
|
|
|
2023-04-25 18:38:48 +03:00
|
|
|
void EventLoopManagerQt::register_notifier(Core::Notifier& notifier)
|
2023-04-24 15:51:19 +03:00
|
|
|
{
|
|
|
|
QSocketNotifier::Type type;
|
|
|
|
switch (notifier.type()) {
|
|
|
|
case Core::Notifier::Type::Read:
|
|
|
|
type = QSocketNotifier::Read;
|
|
|
|
break;
|
|
|
|
case Core::Notifier::Type::Write:
|
|
|
|
type = QSocketNotifier::Write;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
auto socket_notifier = make<QSocketNotifier>(notifier.fd(), type);
|
2023-04-25 17:53:07 +03:00
|
|
|
QObject::connect(socket_notifier, &QSocketNotifier::activated, [¬ifier] {
|
|
|
|
qt_notifier_activated(notifier);
|
2023-04-24 15:51:19 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
ThreadData::the().notifiers.set(¬ifier, move(socket_notifier));
|
|
|
|
}
|
|
|
|
|
2023-04-25 18:38:48 +03:00
|
|
|
void EventLoopManagerQt::unregister_notifier(Core::Notifier& notifier)
|
2023-04-24 15:51:19 +03:00
|
|
|
{
|
|
|
|
ThreadData::the().notifiers.remove(¬ifier);
|
|
|
|
}
|
|
|
|
|
2023-04-25 18:38:48 +03:00
|
|
|
void EventLoopManagerQt::did_post_event()
|
2023-04-25 17:53:07 +03:00
|
|
|
{
|
|
|
|
m_process_core_events_timer.start();
|
|
|
|
}
|
|
|
|
|
2023-04-25 18:38:48 +03:00
|
|
|
EventLoopManagerQt::EventLoopManagerQt()
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
NonnullOwnPtr<Core::EventLoopImplementation> EventLoopManagerQt::make_implementation()
|
|
|
|
{
|
|
|
|
return adopt_own(*new EventLoopImplementationQt);
|
|
|
|
}
|
|
|
|
|
2023-04-24 15:51:19 +03:00
|
|
|
}
|