GEventLoop.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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. static GEventLoop* s_mainGEventLoop;
  12. void GEventLoop::initialize()
  13. {
  14. s_mainGEventLoop = nullptr;
  15. }
  16. GEventLoop::GEventLoop()
  17. {
  18. if (!s_mainGEventLoop)
  19. s_mainGEventLoop = this;
  20. }
  21. GEventLoop::~GEventLoop()
  22. {
  23. }
  24. GEventLoop& GEventLoop::main()
  25. {
  26. ASSERT(s_mainGEventLoop);
  27. return *s_mainGEventLoop;
  28. }
  29. int GEventLoop::exec()
  30. {
  31. m_event_fd = open("/dev/gui_events", O_RDONLY);
  32. if (m_event_fd < 0) {
  33. perror("GEventLoop::exec(): open");
  34. exit(1);
  35. }
  36. m_running = true;
  37. for (;;) {
  38. if (m_queued_events.is_empty())
  39. wait_for_event();
  40. Vector<QueuedEvent> events;
  41. {
  42. events = move(m_queued_events);
  43. }
  44. for (auto& queuedEvent : events) {
  45. auto* receiver = queuedEvent.receiver;
  46. auto& event = *queuedEvent.event;
  47. //printf("GEventLoop: GObject{%p} event %u (%s)\n", receiver, (unsigned)event.type(), event.name());
  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. //printf("GEventLoop::postGEvent: {%u} << receiver=%p, event=%p\n", m_queuedEvents.size(), receiver, event.ptr());
  67. m_queued_events.append({ receiver, move(event) });
  68. }
  69. void GEventLoop::handle_paint_event(const GUI_Event& event, GWindow& window)
  70. {
  71. post_event(&window, make<GPaintEvent>(event.paint.rect));
  72. }
  73. void GEventLoop::handle_mouse_event(const GUI_Event& event, GWindow& window)
  74. {
  75. GMouseEvent::Type type;
  76. switch (event.type) {
  77. case GUI_Event::Type::MouseMove: type = GEvent::MouseMove; break;
  78. case GUI_Event::Type::MouseUp: type = GEvent::MouseUp; break;
  79. case GUI_Event::Type::MouseDown: type = GEvent::MouseDown; break;
  80. default: ASSERT_NOT_REACHED(); break;
  81. }
  82. GMouseButton button { GMouseButton::None };
  83. switch (event.mouse.button) {
  84. case GUI_MouseButton::NoButton: button = GMouseButton::None; break;
  85. case GUI_MouseButton::Left: button = GMouseButton::Left; break;
  86. case GUI_MouseButton::Right: button = GMouseButton::Right; break;
  87. case GUI_MouseButton::Middle: button = GMouseButton::Middle; break;
  88. default: ASSERT_NOT_REACHED(); break;
  89. }
  90. auto mouse_event = make<GMouseEvent>(type, event.mouse.position, button);
  91. }
  92. void GEventLoop::wait_for_event()
  93. {
  94. fd_set rfds;
  95. FD_ZERO(&rfds);
  96. FD_SET(m_event_fd, &rfds);
  97. int rc = select(m_event_fd + 1, &rfds, nullptr, nullptr, nullptr);
  98. if (rc < 0) {
  99. ASSERT_NOT_REACHED();
  100. }
  101. if (!FD_ISSET(m_event_fd, &rfds))
  102. return;
  103. for (;;) {
  104. GUI_Event event;
  105. ssize_t nread = read(m_event_fd, &event, sizeof(GUI_Event));
  106. if (nread < 0) {
  107. perror("read");
  108. exit(1); // FIXME: This should cause EventLoop::exec() to return 1.
  109. }
  110. if (nread == 0)
  111. break;
  112. assert(nread == sizeof(event));
  113. auto* window = GWindow::from_window_id(event.window_id);
  114. if (!window) {
  115. dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id);
  116. }
  117. switch (event.type) {
  118. case GUI_Event::Type::Paint:
  119. 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;
  120. handle_paint_event(event, *window);
  121. break;
  122. case GUI_Event::Type::MouseDown:
  123. case GUI_Event::Type::MouseUp:
  124. case GUI_Event::Type::MouseMove:
  125. dbgprintf("WID=%x MouseEvent %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y);
  126. handle_mouse_event(event, *window);
  127. break;
  128. case GUI_Event::Type::WindowActivated:
  129. dbgprintf("WID=%x WindowActivated\n", event.window_id);
  130. break;
  131. case GUI_Event::Type::WindowDeactivated:
  132. dbgprintf("WID=%x WindowDeactivated\n", event.window_id);
  133. break;
  134. }
  135. }
  136. }