EventLoopImplementationQt.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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->setInterval(milliseconds);
  81. timer->setSingleShot(!should_reload);
  82. auto weak_object = object.make_weak_ptr();
  83. QObject::connect(timer, &QTimer::timeout, [should_fire_when_not_visible, weak_object = move(weak_object)] {
  84. auto object = weak_object.strong_ref();
  85. if (!object)
  86. return;
  87. qt_timer_fired(should_fire_when_not_visible, *object);
  88. });
  89. timer->start();
  90. return bit_cast<intptr_t>(timer);
  91. }
  92. void EventLoopManagerQt::unregister_timer(intptr_t timer_id)
  93. {
  94. auto* timer = bit_cast<QTimer*>(timer_id);
  95. delete timer;
  96. }
  97. static void qt_notifier_activated(Core::Notifier& notifier)
  98. {
  99. Core::NotifierActivationEvent event(notifier.fd(), notifier.type());
  100. notifier.dispatch_event(event);
  101. }
  102. void EventLoopManagerQt::register_notifier(Core::Notifier& notifier)
  103. {
  104. QSocketNotifier::Type type;
  105. switch (notifier.type()) {
  106. case Core::Notifier::Type::Read:
  107. type = QSocketNotifier::Read;
  108. break;
  109. case Core::Notifier::Type::Write:
  110. type = QSocketNotifier::Write;
  111. break;
  112. default:
  113. TODO();
  114. }
  115. auto socket_notifier = make<QSocketNotifier>(notifier.fd(), type);
  116. QObject::connect(socket_notifier, &QSocketNotifier::activated, [&notifier] {
  117. qt_notifier_activated(notifier);
  118. });
  119. ThreadData::the().notifiers.set(&notifier, move(socket_notifier));
  120. }
  121. void EventLoopManagerQt::unregister_notifier(Core::Notifier& notifier)
  122. {
  123. ThreadData::the().notifiers.remove(&notifier);
  124. }
  125. void EventLoopManagerQt::did_post_event()
  126. {
  127. QCoreApplication::postEvent(m_main_thread_event_target.ptr(), new QtEventLoopManagerEvent(QtEventLoopManagerEvent::process_event_queue_event_type()));
  128. }
  129. bool EventLoopManagerQt::event_target_received_event(Badge<EventLoopImplementationQtEventTarget>, QEvent* event)
  130. {
  131. if (event->type() == QtEventLoopManagerEvent::process_event_queue_event_type()) {
  132. Core::ThreadEventQueue::current().process();
  133. return true;
  134. }
  135. return false;
  136. }
  137. EventLoopManagerQt::EventLoopManagerQt()
  138. : m_main_thread_event_target(make<EventLoopImplementationQtEventTarget>())
  139. {
  140. }
  141. EventLoopManagerQt::~EventLoopManagerQt() = default;
  142. NonnullOwnPtr<Core::EventLoopImplementation> EventLoopManagerQt::make_implementation()
  143. {
  144. return adopt_own(*new EventLoopImplementationQt);
  145. }
  146. }