WSMessageLoop.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. #include "WSMessageLoop.h"
  2. #include "WSMessage.h"
  3. #include "WSMessageReceiver.h"
  4. #include "WSWindowManager.h"
  5. #include "WSScreen.h"
  6. #include "PS2MouseDevice.h"
  7. #include <Kernel/Keyboard.h>
  8. #include <AK/Bitmap.h>
  9. #include "Process.h"
  10. //#define WSEVENTLOOP_DEBUG
  11. static WSMessageLoop* s_the;
  12. WSMessageLoop::WSMessageLoop()
  13. : m_lock("WSMessageLoop")
  14. {
  15. if (!s_the)
  16. s_the = this;
  17. }
  18. WSMessageLoop::~WSMessageLoop()
  19. {
  20. }
  21. WSMessageLoop& WSMessageLoop::the()
  22. {
  23. ASSERT(s_the);
  24. return *s_the;
  25. }
  26. int WSMessageLoop::exec()
  27. {
  28. ASSERT(m_server_process == current);
  29. m_keyboard_fd = m_server_process->sys$open("/dev/keyboard", O_RDONLY);
  30. m_mouse_fd = m_server_process->sys$open("/dev/psaux", O_RDONLY);
  31. ASSERT(m_keyboard_fd >= 0);
  32. ASSERT(m_mouse_fd >= 0);
  33. m_running = true;
  34. for (;;) {
  35. wait_for_message();
  36. Vector<QueuedMessage> messages;
  37. {
  38. ASSERT_INTERRUPTS_ENABLED();
  39. LOCKER(m_lock);
  40. messages = move(m_queued_messages);
  41. }
  42. for (auto& queued_message : messages) {
  43. auto* receiver = queued_message.receiver;
  44. auto& message = *queued_message.message;
  45. #ifdef WSEVENTLOOP_DEBUG
  46. dbgprintf("WSMessageLoop: receiver{%p} message %u\n", receiver, (unsigned)message.type());
  47. #endif
  48. if (!receiver) {
  49. dbgprintf("WSMessage type %u with no receiver :(\n", message.type());
  50. ASSERT_NOT_REACHED();
  51. return 1;
  52. } else {
  53. receiver->on_message(message);
  54. }
  55. }
  56. }
  57. }
  58. Process* WSMessageLoop::process_from_client_id(int client_id)
  59. {
  60. // FIXME: This shouldn't work this way lol.
  61. return (Process*)client_id;
  62. }
  63. void WSMessageLoop::post_message_to_client(int client_id, const GUI_ServerMessage& message)
  64. {
  65. auto* process = process_from_client_id(client_id);
  66. if (!process)
  67. return;
  68. LOCKER(process->gui_events_lock());
  69. process->gui_events().append(move(message));
  70. }
  71. void WSMessageLoop::post_message(WSMessageReceiver* receiver, OwnPtr<WSMessage>&& message)
  72. {
  73. LOCKER(m_lock);
  74. #ifdef WSEVENTLOOP_DEBUG
  75. dbgprintf("WSMessageLoop::post_message: {%u} << receiver=%p, message=%p (type=%u)\n", m_queued_messages.size(), receiver, message.ptr(), message->type());
  76. #endif
  77. if (message->type() == WSMessage::WM_ClientFinishedPaint) {
  78. auto& invalidation_message = static_cast<WSClientFinishedPaintMessage&>(*message);
  79. for (auto& queued_message : m_queued_messages) {
  80. if (receiver == queued_message.receiver && queued_message.message->type() == WSMessage::WM_ClientFinishedPaint) {
  81. auto& queued_invalidation_message = static_cast<WSClientFinishedPaintMessage&>(*queued_message.message);
  82. if (queued_invalidation_message.rect().is_empty() || queued_invalidation_message.rect().contains(invalidation_message.rect())) {
  83. #ifdef WSEVENTLOOP_DEBUG
  84. dbgprintf("Swallow WM_ClientFinishedPaint\n");
  85. #endif
  86. return;
  87. }
  88. }
  89. }
  90. }
  91. if (message->type() == WSMessage::WM_ClientWantsToPaint) {
  92. auto& invalidation_message = static_cast<WSClientWantsToPaintMessage&>(*message);
  93. for (auto& queued_message : m_queued_messages) {
  94. if (receiver == queued_message.receiver && queued_message.message->type() == WSMessage::WM_ClientWantsToPaint) {
  95. auto& queued_invalidation_message = static_cast<WSClientWantsToPaintMessage&>(*queued_message.message);
  96. if (queued_invalidation_message.rect().is_empty() || queued_invalidation_message.rect().contains(invalidation_message.rect())) {
  97. #ifdef WSEVENTLOOP_DEBUG
  98. dbgprintf("Swallow WM_ClientWantsToPaint\n");
  99. #endif
  100. return;
  101. }
  102. }
  103. }
  104. }
  105. m_queued_messages.append({ receiver, move(message) });
  106. if (current != m_server_process)
  107. m_server_process->request_wakeup();
  108. }
  109. void WSMessageLoop::Timer::reload()
  110. {
  111. struct timeval now;
  112. current->sys$gettimeofday(&now);
  113. next_fire_time = {
  114. now.tv_sec + (interval / 1000),
  115. now.tv_usec + (interval % 1000)
  116. };
  117. }
  118. int WSMessageLoop::start_timer(int interval, Function<void()>&& callback)
  119. {
  120. auto timer = make<Timer>();
  121. int timer_id = m_next_timer_id++;
  122. timer->timer_id = timer_id;
  123. timer->callback = move(callback);
  124. timer->interval = interval;
  125. timer->reload();
  126. m_timers.set(timer_id, move(timer));
  127. return timer_id;
  128. }
  129. int WSMessageLoop::stop_timer(int timer_id)
  130. {
  131. auto it = m_timers.find(timer_id);
  132. if (it == m_timers.end())
  133. return -1;
  134. m_timers.remove(it);
  135. return 0;
  136. }
  137. void WSMessageLoop::wait_for_message()
  138. {
  139. fd_set rfds;
  140. memset(&rfds, 0, sizeof(rfds));
  141. auto bitmap = Bitmap::wrap((byte*)&rfds, FD_SETSIZE);
  142. bitmap.set(m_keyboard_fd, true);
  143. bitmap.set(m_mouse_fd, true);
  144. Syscall::SC_select_params params;
  145. params.nfds = max(m_keyboard_fd, m_mouse_fd) + 1;
  146. params.readfds = &rfds;
  147. params.writefds = nullptr;
  148. params.exceptfds = nullptr;
  149. struct timeval timeout = { 0, 0 };
  150. bool had_any_timer = false;
  151. for (auto& it : m_timers) {
  152. auto& timer = *it.value;
  153. if (!had_any_timer) {
  154. timeout = timer.next_fire_time;
  155. had_any_timer = true;
  156. continue;
  157. }
  158. if (timer.next_fire_time.tv_sec > timeout.tv_sec || (timer.next_fire_time.tv_sec == timeout.tv_sec && timer.next_fire_time.tv_usec > timeout.tv_usec))
  159. timeout = timer.next_fire_time;
  160. }
  161. if (m_timers.is_empty() && m_queued_messages.is_empty())
  162. params.timeout = nullptr;
  163. else
  164. params.timeout = &timeout;
  165. int rc = m_server_process->sys$select(&params);
  166. memory_barrier();
  167. if (rc < 0) {
  168. ASSERT_NOT_REACHED();
  169. }
  170. struct timeval now;
  171. current->sys$gettimeofday(&now);
  172. for (auto& it : m_timers) {
  173. auto& timer = *it.value;
  174. if (now.tv_sec > timer.next_fire_time.tv_sec || (now.tv_sec == timer.next_fire_time.tv_sec && now.tv_usec > timer.next_fire_time.tv_usec)) {
  175. timer.callback();
  176. timer.reload();
  177. }
  178. }
  179. if (bitmap.get(m_keyboard_fd))
  180. drain_keyboard();
  181. if (bitmap.get(m_mouse_fd))
  182. drain_mouse();
  183. }
  184. void WSMessageLoop::drain_mouse()
  185. {
  186. auto& screen = WSScreen::the();
  187. auto& mouse = PS2MouseDevice::the();
  188. bool prev_left_button = screen.left_mouse_button_pressed();
  189. bool prev_right_button = screen.right_mouse_button_pressed();
  190. int dx = 0;
  191. int dy = 0;
  192. while (mouse.can_read(*m_server_process)) {
  193. byte data[3];
  194. ssize_t nread = mouse.read(*m_server_process, (byte*)data, sizeof(data));
  195. ASSERT(nread == sizeof(data));
  196. bool left_button = data[0] & 1;
  197. bool right_button = data[0] & 2;
  198. bool x_overflow = data[0] & 0x40;
  199. bool y_overflow = data[0] & 0x80;
  200. bool x_sign = data[0] & 0x10;
  201. bool y_sign = data[0] & 0x20;
  202. if (x_overflow || y_overflow)
  203. continue;
  204. int x = data[1];
  205. int y = data[2];
  206. if (x && x_sign)
  207. x -= 0x100;
  208. if (y && y_sign)
  209. y -= 0x100;
  210. dx += x;
  211. dy += -y;
  212. if (left_button != prev_left_button || right_button != prev_right_button || !mouse.can_read(*m_server_process)) {
  213. prev_left_button = left_button;
  214. prev_right_button = right_button;
  215. screen.on_receive_mouse_data(dx, dy, left_button, right_button);
  216. dx = 0;
  217. dy = 0;
  218. }
  219. }
  220. }
  221. void WSMessageLoop::drain_keyboard()
  222. {
  223. auto& screen = WSScreen::the();
  224. auto& keyboard = Keyboard::the();
  225. while (keyboard.can_read(*m_server_process)) {
  226. Keyboard::Event event;
  227. ssize_t nread = keyboard.read(*m_server_process, (byte*)&event, sizeof(Keyboard::Event));
  228. ASSERT(nread == sizeof(Keyboard::Event));
  229. screen.on_receive_keyboard_data(event);
  230. }
  231. }
  232. ssize_t WSMessageLoop::on_receive_from_client(int client_id, const byte* data, size_t size)
  233. {
  234. LOCKER(m_lock);
  235. ASSERT(size == sizeof(GUI_ClientMessage));
  236. auto& message = *reinterpret_cast<const GUI_ClientMessage*>(data);
  237. switch (message.type) {
  238. case GUI_ClientMessage::Type::CreateMenubar:
  239. post_message(&WSWindowManager::the(), make<WSAPICreateMenubarRequest>(client_id));
  240. break;
  241. case GUI_ClientMessage::Type::DestroyMenubar:
  242. post_message(&WSWindowManager::the(), make<WSAPIDestroyMenubarRequest>(client_id, message.menu.menubar_id));
  243. break;
  244. case GUI_ClientMessage::Type::SetApplicationMenubar:
  245. post_message(&WSWindowManager::the(), make<WSAPISetApplicationMenubarRequest>(client_id, message.menu.menubar_id));
  246. break;
  247. case GUI_ClientMessage::Type::AddMenuToMenubar:
  248. post_message(&WSWindowManager::the(), make<WSAPIAddMenuToMenubarRequest>(client_id, message.menu.menubar_id, message.menu.menu_id));
  249. break;
  250. case GUI_ClientMessage::Type::CreateMenu:
  251. ASSERT(message.menu.text_length < sizeof(message.menu.text));
  252. post_message(&WSWindowManager::the(), make<WSAPICreateMenuRequest>(client_id, String(message.menu.text, message.menu.text_length)));
  253. break;
  254. case GUI_ClientMessage::Type::DestroyMenu:
  255. post_message(&WSWindowManager::the(), make<WSAPIDestroyMenuRequest>(client_id, message.menu.menu_id));
  256. break;
  257. case GUI_ClientMessage::Type::AddMenuItem:
  258. ASSERT(message.menu.text_length < sizeof(message.menu.text));
  259. post_message(&WSWindowManager::the(), make<WSAPIAddMenuItemRequest>(client_id, message.menu.menu_id, message.menu.identifier, String(message.menu.text, message.menu.text_length)));
  260. }
  261. return size;
  262. }