EventLoopImplementationQt.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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 <QTimer>
  13. namespace Ladybird {
  14. struct ThreadData;
  15. static thread_local ThreadData* s_thread_data;
  16. struct ThreadData {
  17. static ThreadData& the()
  18. {
  19. if (!s_thread_data) {
  20. // FIXME: Don't leak this.
  21. s_thread_data = new ThreadData;
  22. }
  23. return *s_thread_data;
  24. }
  25. IDAllocator timer_id_allocator;
  26. HashMap<int, NonnullOwnPtr<QTimer>> timers;
  27. HashMap<Core::Notifier*, NonnullOwnPtr<QSocketNotifier>> notifiers;
  28. };
  29. EventLoopImplementationQt::EventLoopImplementationQt()
  30. {
  31. }
  32. EventLoopImplementationQt::~EventLoopImplementationQt() = default;
  33. int EventLoopImplementationQt::exec()
  34. {
  35. // NOTE: We don't use QEventLoop::exec() here since it wouldn't process the Core::ThreadEventQueue.
  36. while (!m_exit_code.has_value()) {
  37. pump(PumpMode::WaitForEvents);
  38. }
  39. return m_exit_code.value();
  40. }
  41. size_t EventLoopImplementationQt::pump(PumpMode mode)
  42. {
  43. bool result = Core::ThreadEventQueue::current().process() != 0;
  44. if (mode == PumpMode::WaitForEvents)
  45. result |= m_event_loop.processEvents(QEventLoop::WaitForMoreEvents);
  46. else
  47. result |= m_event_loop.processEvents();
  48. Core::ThreadEventQueue::current().process();
  49. return result;
  50. }
  51. void EventLoopImplementationQt::quit(int code)
  52. {
  53. m_exit_code = code;
  54. }
  55. void EventLoopImplementationQt::wake()
  56. {
  57. m_event_loop.wakeUp();
  58. }
  59. void EventLoopImplementationQt::deferred_invoke(Function<void()> function)
  60. {
  61. VERIFY(function);
  62. QTimer::singleShot(0, [function = move(function)] {
  63. function();
  64. });
  65. }
  66. int EventLoopImplementationQt::register_timer(Core::Object& object, int milliseconds, bool should_reload, Core::TimerShouldFireWhenNotVisible should_fire_when_not_visible)
  67. {
  68. auto& thread_data = ThreadData::the();
  69. auto timer = make<QTimer>();
  70. timer->setInterval(milliseconds);
  71. timer->setSingleShot(!should_reload);
  72. auto timer_id = thread_data.timer_id_allocator.allocate();
  73. auto weak_object = object.make_weak_ptr();
  74. QObject::connect(timer, &QTimer::timeout, [timer_id, should_fire_when_not_visible, weak_object = move(weak_object)] {
  75. auto object = weak_object.strong_ref();
  76. if (!object)
  77. return;
  78. if (should_fire_when_not_visible == Core::TimerShouldFireWhenNotVisible::No) {
  79. if (!object->is_visible_for_timer_purposes())
  80. return;
  81. }
  82. Core::ThreadEventQueue::current().post_event(*object, make<Core::TimerEvent>(timer_id));
  83. });
  84. timer->start();
  85. thread_data.timers.set(timer_id, move(timer));
  86. return timer_id;
  87. }
  88. bool EventLoopImplementationQt::unregister_timer(int timer_id)
  89. {
  90. auto& thread_data = ThreadData::the();
  91. thread_data.timer_id_allocator.deallocate(timer_id);
  92. return thread_data.timers.remove(timer_id);
  93. }
  94. void EventLoopImplementationQt::register_notifier(Core::Notifier& notifier)
  95. {
  96. QSocketNotifier::Type type;
  97. switch (notifier.type()) {
  98. case Core::Notifier::Type::Read:
  99. type = QSocketNotifier::Read;
  100. break;
  101. case Core::Notifier::Type::Write:
  102. type = QSocketNotifier::Write;
  103. break;
  104. default:
  105. TODO();
  106. }
  107. auto socket_notifier = make<QSocketNotifier>(notifier.fd(), type);
  108. QObject::connect(socket_notifier, &QSocketNotifier::activated, [fd = notifier.fd(), &notifier] {
  109. Core::ThreadEventQueue::current().post_event(notifier, make<Core::NotifierActivationEvent>(fd));
  110. });
  111. ThreadData::the().notifiers.set(&notifier, move(socket_notifier));
  112. }
  113. void EventLoopImplementationQt::unregister_notifier(Core::Notifier& notifier)
  114. {
  115. ThreadData::the().notifiers.remove(&notifier);
  116. }
  117. }