EventLoopImplementationQt.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. * Copyright (c) 2022-2023, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "EventLoopImplementationQt.h"
  7. #include "EventLoopImplementationQtEventTarget.h"
  8. #include <AK/IDAllocator.h>
  9. #include <LibCore/Event.h>
  10. #include <LibCore/EventReceiver.h>
  11. #include <LibCore/Notifier.h>
  12. #include <LibCore/ThreadEventQueue.h>
  13. #include <QCoreApplication>
  14. #include <QTimer>
  15. namespace Ladybird {
  16. struct ThreadData;
  17. static thread_local ThreadData* s_thread_data;
  18. struct ThreadData {
  19. static ThreadData& the()
  20. {
  21. if (!s_thread_data) {
  22. // FIXME: Don't leak this.
  23. s_thread_data = new ThreadData;
  24. }
  25. return *s_thread_data;
  26. }
  27. HashMap<Core::Notifier*, NonnullOwnPtr<QSocketNotifier>> notifiers;
  28. };
  29. EventLoopImplementationQt::EventLoopImplementationQt()
  30. {
  31. }
  32. EventLoopImplementationQt::~EventLoopImplementationQt() = default;
  33. int EventLoopImplementationQt::exec()
  34. {
  35. if (is_main_loop())
  36. return QCoreApplication::exec();
  37. return m_event_loop.exec();
  38. }
  39. size_t EventLoopImplementationQt::pump(PumpMode mode)
  40. {
  41. auto result = Core::ThreadEventQueue::current().process();
  42. auto qt_mode = mode == PumpMode::WaitForEvents ? QEventLoop::WaitForMoreEvents : QEventLoop::AllEvents;
  43. if (is_main_loop())
  44. QCoreApplication::processEvents(qt_mode);
  45. else
  46. m_event_loop.processEvents(qt_mode);
  47. result += Core::ThreadEventQueue::current().process();
  48. return result;
  49. }
  50. void EventLoopImplementationQt::quit(int code)
  51. {
  52. if (is_main_loop())
  53. QCoreApplication::exit(code);
  54. else
  55. m_event_loop.exit(code);
  56. }
  57. void EventLoopImplementationQt::wake()
  58. {
  59. if (!is_main_loop())
  60. m_event_loop.wakeUp();
  61. }
  62. void EventLoopImplementationQt::post_event(Core::EventReceiver& receiver, NonnullOwnPtr<Core::Event>&& event)
  63. {
  64. m_thread_event_queue.post_event(receiver, move(event));
  65. if (&m_thread_event_queue != &Core::ThreadEventQueue::current())
  66. wake();
  67. }
  68. static void qt_timer_fired(Core::TimerShouldFireWhenNotVisible should_fire_when_not_visible, Core::EventReceiver& object)
  69. {
  70. if (should_fire_when_not_visible == Core::TimerShouldFireWhenNotVisible::No) {
  71. if (!object.is_visible_for_timer_purposes())
  72. return;
  73. }
  74. Core::TimerEvent event;
  75. object.dispatch_event(event);
  76. }
  77. intptr_t EventLoopManagerQt::register_timer(Core::EventReceiver& object, int milliseconds, bool should_reload, Core::TimerShouldFireWhenNotVisible should_fire_when_not_visible)
  78. {
  79. auto timer = new QTimer;
  80. timer->setTimerType(Qt::PreciseTimer);
  81. timer->setInterval(milliseconds);
  82. timer->setSingleShot(!should_reload);
  83. auto weak_object = object.make_weak_ptr();
  84. QObject::connect(timer, &QTimer::timeout, [should_fire_when_not_visible, weak_object = move(weak_object)] {
  85. auto object = weak_object.strong_ref();
  86. if (!object)
  87. return;
  88. qt_timer_fired(should_fire_when_not_visible, *object);
  89. });
  90. timer->start();
  91. return bit_cast<intptr_t>(timer);
  92. }
  93. void EventLoopManagerQt::unregister_timer(intptr_t timer_id)
  94. {
  95. auto* timer = bit_cast<QTimer*>(timer_id);
  96. delete timer;
  97. }
  98. static void qt_notifier_activated(Core::Notifier& notifier)
  99. {
  100. Core::NotifierActivationEvent event(notifier.fd(), notifier.type());
  101. notifier.dispatch_event(event);
  102. }
  103. void EventLoopManagerQt::register_notifier(Core::Notifier& notifier)
  104. {
  105. QSocketNotifier::Type type;
  106. switch (notifier.type()) {
  107. case Core::Notifier::Type::Read:
  108. type = QSocketNotifier::Read;
  109. break;
  110. case Core::Notifier::Type::Write:
  111. type = QSocketNotifier::Write;
  112. break;
  113. default:
  114. TODO();
  115. }
  116. auto socket_notifier = make<QSocketNotifier>(notifier.fd(), type);
  117. QObject::connect(socket_notifier, &QSocketNotifier::activated, [&notifier] {
  118. qt_notifier_activated(notifier);
  119. });
  120. ThreadData::the().notifiers.set(&notifier, move(socket_notifier));
  121. }
  122. void EventLoopManagerQt::unregister_notifier(Core::Notifier& notifier)
  123. {
  124. ThreadData::the().notifiers.remove(&notifier);
  125. }
  126. void EventLoopManagerQt::did_post_event()
  127. {
  128. QCoreApplication::postEvent(m_main_thread_event_target.ptr(), new QtEventLoopManagerEvent(QtEventLoopManagerEvent::process_event_queue_event_type()));
  129. }
  130. bool EventLoopManagerQt::event_target_received_event(Badge<EventLoopImplementationQtEventTarget>, QEvent* event)
  131. {
  132. if (event->type() == QtEventLoopManagerEvent::process_event_queue_event_type()) {
  133. Core::ThreadEventQueue::current().process();
  134. return true;
  135. }
  136. return false;
  137. }
  138. EventLoopManagerQt::EventLoopManagerQt()
  139. : m_main_thread_event_target(make<EventLoopImplementationQtEventTarget>())
  140. {
  141. }
  142. EventLoopManagerQt::~EventLoopManagerQt() = default;
  143. NonnullOwnPtr<Core::EventLoopImplementation> EventLoopManagerQt::make_implementation()
  144. {
  145. return adopt_own(*new EventLoopImplementationQt);
  146. }
  147. }