EventLoopImplementationQt.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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 <AK/IDAllocator.h>
  8. #include <LibCore/Event.h>
  9. #include <LibCore/Notifier.h>
  10. #include <LibCore/Object.h>
  11. #include <LibCore/ThreadEventQueue.h>
  12. #include <QCoreApplication>
  13. #include <QTimer>
  14. namespace Ladybird {
  15. struct ThreadData;
  16. static thread_local ThreadData* s_thread_data;
  17. struct ThreadData {
  18. static ThreadData& the()
  19. {
  20. if (!s_thread_data) {
  21. // FIXME: Don't leak this.
  22. s_thread_data = new ThreadData;
  23. }
  24. return *s_thread_data;
  25. }
  26. IDAllocator timer_id_allocator;
  27. HashMap<int, NonnullOwnPtr<QTimer>> timers;
  28. HashMap<Core::Notifier*, NonnullOwnPtr<QSocketNotifier>> notifiers;
  29. };
  30. EventLoopImplementationQt::EventLoopImplementationQt()
  31. {
  32. m_process_core_events_timer.setSingleShot(true);
  33. m_process_core_events_timer.setInterval(0);
  34. QObject::connect(&m_process_core_events_timer, &QTimer::timeout, [] {
  35. Core::ThreadEventQueue::current().process();
  36. });
  37. }
  38. EventLoopImplementationQt::~EventLoopImplementationQt() = default;
  39. int EventLoopImplementationQt::exec()
  40. {
  41. if (is_main_loop())
  42. return QCoreApplication::exec();
  43. return m_event_loop.exec();
  44. }
  45. size_t EventLoopImplementationQt::pump(PumpMode mode)
  46. {
  47. auto result = Core::ThreadEventQueue::current().process();
  48. if (mode == PumpMode::WaitForEvents) {
  49. if (is_main_loop())
  50. QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
  51. else
  52. m_event_loop.processEvents(QEventLoop::WaitForMoreEvents);
  53. } else {
  54. }
  55. result += Core::ThreadEventQueue::current().process();
  56. return result;
  57. }
  58. void EventLoopImplementationQt::quit(int code)
  59. {
  60. if (is_main_loop())
  61. QCoreApplication::exit(code);
  62. else
  63. m_event_loop.exit(code);
  64. }
  65. void EventLoopImplementationQt::wake()
  66. {
  67. if (!is_main_loop())
  68. m_event_loop.wakeUp();
  69. }
  70. void EventLoopImplementationQt::deferred_invoke(Function<void()> function)
  71. {
  72. VERIFY(function);
  73. QTimer::singleShot(0, [function = move(function)] {
  74. function();
  75. });
  76. }
  77. static void qt_timer_fired(int timer_id, Core::TimerShouldFireWhenNotVisible should_fire_when_not_visible, Core::Object& object)
  78. {
  79. if (should_fire_when_not_visible == Core::TimerShouldFireWhenNotVisible::No) {
  80. if (!object.is_visible_for_timer_purposes())
  81. return;
  82. }
  83. Core::TimerEvent event(timer_id);
  84. object.dispatch_event(event);
  85. }
  86. int EventLoopImplementationQt::register_timer(Core::Object& object, int milliseconds, bool should_reload, Core::TimerShouldFireWhenNotVisible should_fire_when_not_visible)
  87. {
  88. auto& thread_data = ThreadData::the();
  89. auto timer = make<QTimer>();
  90. timer->setInterval(milliseconds);
  91. timer->setSingleShot(!should_reload);
  92. auto timer_id = thread_data.timer_id_allocator.allocate();
  93. auto weak_object = object.make_weak_ptr();
  94. QObject::connect(timer, &QTimer::timeout, [timer_id, should_fire_when_not_visible, weak_object = move(weak_object)] {
  95. auto object = weak_object.strong_ref();
  96. if (!object)
  97. return;
  98. qt_timer_fired(timer_id, should_fire_when_not_visible, *object);
  99. });
  100. timer->start();
  101. thread_data.timers.set(timer_id, move(timer));
  102. return timer_id;
  103. }
  104. bool EventLoopImplementationQt::unregister_timer(int timer_id)
  105. {
  106. auto& thread_data = ThreadData::the();
  107. thread_data.timer_id_allocator.deallocate(timer_id);
  108. return thread_data.timers.remove(timer_id);
  109. }
  110. static void qt_notifier_activated(Core::Notifier& notifier)
  111. {
  112. Core::NotifierActivationEvent event(notifier.fd());
  113. notifier.dispatch_event(event);
  114. }
  115. void EventLoopImplementationQt::register_notifier(Core::Notifier& notifier)
  116. {
  117. QSocketNotifier::Type type;
  118. switch (notifier.type()) {
  119. case Core::Notifier::Type::Read:
  120. type = QSocketNotifier::Read;
  121. break;
  122. case Core::Notifier::Type::Write:
  123. type = QSocketNotifier::Write;
  124. break;
  125. default:
  126. TODO();
  127. }
  128. auto socket_notifier = make<QSocketNotifier>(notifier.fd(), type);
  129. QObject::connect(socket_notifier, &QSocketNotifier::activated, [&notifier] {
  130. qt_notifier_activated(notifier);
  131. });
  132. ThreadData::the().notifiers.set(&notifier, move(socket_notifier));
  133. }
  134. void EventLoopImplementationQt::unregister_notifier(Core::Notifier& notifier)
  135. {
  136. ThreadData::the().notifiers.remove(&notifier);
  137. }
  138. void EventLoopImplementationQt::did_post_event()
  139. {
  140. m_process_core_events_timer.start();
  141. }
  142. }