GEventLoop.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. #include "GEventLoop.h"
  2. #include "GEvent.h"
  3. #include "GObject.h"
  4. #include "GWindow.h"
  5. #include <LibC/unistd.h>
  6. #include <LibC/stdio.h>
  7. #include <LibC/fcntl.h>
  8. #include <LibC/string.h>
  9. #include <LibC/sys/select.h>
  10. #include <LibC/gui.h>
  11. //#define GEVENTLOOP_DEBUG
  12. static GEventLoop* s_mainGEventLoop;
  13. void GEventLoop::initialize()
  14. {
  15. s_mainGEventLoop = nullptr;
  16. }
  17. GEventLoop::GEventLoop()
  18. {
  19. if (!s_mainGEventLoop)
  20. s_mainGEventLoop = this;
  21. }
  22. GEventLoop::~GEventLoop()
  23. {
  24. }
  25. GEventLoop& GEventLoop::main()
  26. {
  27. ASSERT(s_mainGEventLoop);
  28. return *s_mainGEventLoop;
  29. }
  30. int GEventLoop::exec()
  31. {
  32. m_event_fd = open("/dev/gui_events", O_RDONLY | O_NONBLOCK);
  33. if (m_event_fd < 0) {
  34. perror("GEventLoop::exec(): open");
  35. exit(1);
  36. }
  37. m_running = true;
  38. for (;;) {
  39. if (m_queued_events.is_empty())
  40. wait_for_event();
  41. Vector<QueuedEvent> events = move(m_queued_events);
  42. for (auto& queued_event : events) {
  43. auto* receiver = queued_event.receiver;
  44. auto& event = *queued_event.event;
  45. #ifdef GEVENTLOOP_DEBUG
  46. dbgprintf("GEventLoop: GObject{%p} event %u (%s)\n", receiver, (unsigned)event.type(), event.name());
  47. #endif
  48. if (!receiver) {
  49. switch (event.type()) {
  50. case GEvent::Quit:
  51. ASSERT_NOT_REACHED();
  52. return 0;
  53. default:
  54. dbgprintf("event type %u with no receiver :(\n", event.type());
  55. ASSERT_NOT_REACHED();
  56. return 1;
  57. }
  58. } else {
  59. receiver->event(event);
  60. }
  61. }
  62. }
  63. }
  64. void GEventLoop::post_event(GObject* receiver, OwnPtr<GEvent>&& event)
  65. {
  66. #ifdef GEVENTLOOP_DEBUG
  67. dbgprintf("GEventLoop::post_event: {%u} << receiver=%p, event=%p\n", m_queued_events.size(), receiver, event.ptr());
  68. #endif
  69. m_queued_events.append({ receiver, move(event) });
  70. }
  71. void GEventLoop::handle_paint_event(const GUI_Event& event, GWindow& window)
  72. {
  73. post_event(&window, make<GPaintEvent>(event.paint.rect));
  74. }
  75. void GEventLoop::handle_mouse_event(const GUI_Event& event, GWindow& window)
  76. {
  77. GMouseEvent::Type type;
  78. switch (event.type) {
  79. case GUI_Event::Type::MouseMove: type = GEvent::MouseMove; break;
  80. case GUI_Event::Type::MouseUp: type = GEvent::MouseUp; break;
  81. case GUI_Event::Type::MouseDown: type = GEvent::MouseDown; break;
  82. default: ASSERT_NOT_REACHED(); break;
  83. }
  84. GMouseButton button { GMouseButton::None };
  85. switch (event.mouse.button) {
  86. case GUI_MouseButton::NoButton: button = GMouseButton::None; break;
  87. case GUI_MouseButton::Left: button = GMouseButton::Left; break;
  88. case GUI_MouseButton::Right: button = GMouseButton::Right; break;
  89. case GUI_MouseButton::Middle: button = GMouseButton::Middle; break;
  90. default: ASSERT_NOT_REACHED(); break;
  91. }
  92. post_event(&window, make<GMouseEvent>(type, event.mouse.position, event.mouse.buttons, button));
  93. }
  94. void GEventLoop::wait_for_event()
  95. {
  96. fd_set rfds;
  97. FD_ZERO(&rfds);
  98. FD_SET(m_event_fd, &rfds);
  99. struct timeval timeout = { 0, 0 };
  100. int rc = select(m_event_fd + 1, &rfds, nullptr, nullptr, m_queued_events.is_empty() ? nullptr : &timeout);
  101. if (rc < 0) {
  102. ASSERT_NOT_REACHED();
  103. }
  104. if (!FD_ISSET(m_event_fd, &rfds))
  105. return;
  106. for (;;) {
  107. GUI_Event event;
  108. ssize_t nread = read(m_event_fd, &event, sizeof(GUI_Event));
  109. if (nread < 0) {
  110. perror("read");
  111. exit(1); // FIXME: This should cause EventLoop::exec() to return 1.
  112. }
  113. if (nread == 0)
  114. break;
  115. assert(nread == sizeof(event));
  116. auto* window = GWindow::from_window_id(event.window_id);
  117. if (!window) {
  118. dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id);
  119. continue;
  120. }
  121. switch (event.type) {
  122. case GUI_Event::Type::Paint:
  123. dbgprintf("WID=%x Paint [%d,%d %dx%d]\n", event.window_id, event.paint.rect.location.x, event.paint.rect.location.y, event.paint.rect.size.width, event.paint.rect.size.height); break;
  124. handle_paint_event(event, *window);
  125. break;
  126. case GUI_Event::Type::MouseDown:
  127. case GUI_Event::Type::MouseUp:
  128. case GUI_Event::Type::MouseMove:
  129. dbgprintf("WID=%x MouseEvent %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y);
  130. handle_mouse_event(event, *window);
  131. break;
  132. case GUI_Event::Type::WindowActivated:
  133. dbgprintf("WID=%x WindowActivated\n", event.window_id);
  134. break;
  135. case GUI_Event::Type::WindowDeactivated:
  136. dbgprintf("WID=%x WindowDeactivated\n", event.window_id);
  137. break;
  138. }
  139. }
  140. }