WSMessageLoop.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. #include <WindowServer/WSMessageLoop.h>
  2. #include <WindowServer/WSMessage.h>
  3. #include <WindowServer/WSMessageReceiver.h>
  4. #include <WindowServer/WSWindowManager.h>
  5. #include <WindowServer/WSScreen.h>
  6. #include <WindowServer/WSClientConnection.h>
  7. #include <WindowServer/WSAPITypes.h>
  8. #include <Kernel/KeyCode.h>
  9. #include <LibC/sys/socket.h>
  10. #include <LibC/sys/select.h>
  11. #include <LibC/unistd.h>
  12. #include <LibC/time.h>
  13. #include <LibC/fcntl.h>
  14. #include <LibC/stdio.h>
  15. #include <LibC/errno.h>
  16. //#define WSEVENTLOOP_DEBUG
  17. static WSMessageLoop* s_the;
  18. WSMessageLoop::WSMessageLoop()
  19. {
  20. if (!s_the)
  21. s_the = this;
  22. }
  23. WSMessageLoop::~WSMessageLoop()
  24. {
  25. }
  26. WSMessageLoop& WSMessageLoop::the()
  27. {
  28. ASSERT(s_the);
  29. return *s_the;
  30. }
  31. int WSMessageLoop::exec()
  32. {
  33. m_keyboard_fd = open("/dev/keyboard", O_RDONLY | O_NONBLOCK | O_CLOEXEC);
  34. m_mouse_fd = open("/dev/psaux", O_RDONLY | O_NONBLOCK | O_CLOEXEC);
  35. unlink("/tmp/wsportal");
  36. m_server_fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
  37. ASSERT(m_server_fd >= 0);
  38. sockaddr_un address;
  39. address.sun_family = AF_LOCAL;
  40. strcpy(address.sun_path, "/tmp/wsportal");
  41. int rc = bind(m_server_fd, (const sockaddr*)&address, sizeof(address));
  42. ASSERT(rc == 0);
  43. rc = listen(m_server_fd, 5);
  44. ASSERT(rc == 0);
  45. ASSERT(m_keyboard_fd >= 0);
  46. ASSERT(m_mouse_fd >= 0);
  47. m_running = true;
  48. for (;;) {
  49. wait_for_message();
  50. Vector<QueuedMessage> messages = move(m_queued_messages);
  51. for (auto& queued_message : messages) {
  52. auto* receiver = queued_message.receiver;
  53. auto& message = *queued_message.message;
  54. #ifdef WSEVENTLOOP_DEBUG
  55. dbgprintf("WSMessageLoop: receiver{%p} message %u\n", receiver, (unsigned)message.type());
  56. #endif
  57. if (!receiver) {
  58. dbgprintf("WSMessage type %u with no receiver :(\n", message.type());
  59. ASSERT_NOT_REACHED();
  60. return 1;
  61. } else {
  62. receiver->on_message(message);
  63. }
  64. }
  65. }
  66. }
  67. void WSMessageLoop::post_message(WSMessageReceiver* receiver, OwnPtr<WSMessage>&& message)
  68. {
  69. #ifdef WSEVENTLOOP_DEBUG
  70. dbgprintf("WSMessageLoop::post_message: {%u} << receiver=%p, message=%p (type=%u)\n", m_queued_messages.size(), receiver, message.ptr(), message->type());
  71. #endif
  72. m_queued_messages.append({ receiver, move(message) });
  73. }
  74. void WSMessageLoop::Timer::reload()
  75. {
  76. struct timeval now;
  77. gettimeofday(&now, nullptr);
  78. next_fire_time = {
  79. now.tv_sec + (interval / 1000),
  80. now.tv_usec + (interval % 1000)
  81. };
  82. }
  83. int WSMessageLoop::start_timer(int interval, Function<void()>&& callback)
  84. {
  85. auto timer = make<Timer>();
  86. int timer_id = m_next_timer_id++;
  87. timer->timer_id = timer_id;
  88. timer->callback = move(callback);
  89. timer->interval = interval;
  90. timer->reload();
  91. m_timers.set(timer_id, move(timer));
  92. return timer_id;
  93. }
  94. int WSMessageLoop::stop_timer(int timer_id)
  95. {
  96. auto it = m_timers.find(timer_id);
  97. if (it == m_timers.end())
  98. return -1;
  99. m_timers.remove(it);
  100. return 0;
  101. }
  102. void WSMessageLoop::wait_for_message()
  103. {
  104. fd_set rfds;
  105. FD_ZERO(&rfds);
  106. int max_fd = 0;
  107. auto add_fd_to_set = [&max_fd] (int fd, auto& set) {
  108. FD_SET(fd, &set);
  109. if (fd > max_fd)
  110. max_fd = fd;
  111. };
  112. add_fd_to_set(m_keyboard_fd, rfds);
  113. add_fd_to_set(m_mouse_fd, rfds);
  114. add_fd_to_set(m_server_fd, rfds);
  115. WSClientConnection::for_each_client([&] (WSClientConnection& client) {
  116. add_fd_to_set(client.fd(), rfds);
  117. });
  118. struct timeval timeout = { 0, 0 };
  119. bool had_any_timer = false;
  120. for (auto& it : m_timers) {
  121. auto& timer = *it.value;
  122. if (!had_any_timer) {
  123. timeout = timer.next_fire_time;
  124. had_any_timer = true;
  125. continue;
  126. }
  127. 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))
  128. timeout = timer.next_fire_time;
  129. }
  130. int rc = select(max_fd + 1, &rfds, nullptr, nullptr, m_timers.is_empty() && m_queued_messages.is_empty() ? nullptr : &timeout);
  131. if (rc < 0) {
  132. ASSERT_NOT_REACHED();
  133. }
  134. struct timeval now;
  135. gettimeofday(&now, nullptr);
  136. for (auto& it : m_timers) {
  137. auto& timer = *it.value;
  138. 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)) {
  139. timer.callback();
  140. timer.reload();
  141. }
  142. }
  143. if (FD_ISSET(m_keyboard_fd, &rfds))
  144. drain_keyboard();
  145. if (FD_ISSET(m_mouse_fd, &rfds))
  146. drain_mouse();
  147. if (FD_ISSET(m_server_fd, &rfds)) {
  148. sockaddr_un address;
  149. socklen_t address_size = sizeof(address);
  150. int client_fd = accept(m_server_fd, (sockaddr*)&address, &address_size);
  151. dbgprintf("accept() returned fd=%d, address=%s\n", client_fd, address.sun_path);
  152. ASSERT(client_fd >= 0);
  153. new WSClientConnection(client_fd);
  154. }
  155. WSClientConnection::for_each_client([&] (WSClientConnection& client) {
  156. if (!FD_ISSET(client.fd(), &rfds))
  157. return;
  158. unsigned messages_received = 0;
  159. for (;;) {
  160. WSAPI_ClientMessage message;
  161. // FIXME: Don't go one message at a time, that's so much context switching, oof.
  162. ssize_t nread = read(client.fd(), &message, sizeof(WSAPI_ClientMessage));
  163. if (nread == 0) {
  164. if (!messages_received)
  165. notify_client_disconnected(client.client_id());
  166. break;
  167. }
  168. if (nread < 0) {
  169. perror("read");
  170. ASSERT_NOT_REACHED();
  171. }
  172. on_receive_from_client(client.client_id(), message);
  173. ++messages_received;
  174. }
  175. });
  176. }
  177. void WSMessageLoop::drain_mouse()
  178. {
  179. auto& screen = WSScreen::the();
  180. bool prev_left_button = screen.left_mouse_button_pressed();
  181. bool prev_right_button = screen.right_mouse_button_pressed();
  182. int dx = 0;
  183. int dy = 0;
  184. bool left_button = prev_left_button;
  185. bool right_button = prev_right_button;
  186. for (;;) {
  187. byte data[3];
  188. ssize_t nread = read(m_mouse_fd, data, sizeof(data));
  189. if (nread == 0)
  190. break;
  191. ASSERT(nread == sizeof(data));
  192. bool left_button = data[0] & 1;
  193. bool right_button = data[0] & 2;
  194. bool x_overflow = data[0] & 0x40;
  195. bool y_overflow = data[0] & 0x80;
  196. bool x_sign = data[0] & 0x10;
  197. bool y_sign = data[0] & 0x20;
  198. if (x_overflow || y_overflow)
  199. continue;
  200. int x = data[1];
  201. int y = data[2];
  202. if (x && x_sign)
  203. x -= 0x100;
  204. if (y && y_sign)
  205. y -= 0x100;
  206. dx += x;
  207. dy += -y;
  208. if (left_button != prev_left_button || right_button != prev_right_button) {
  209. prev_left_button = left_button;
  210. prev_right_button = right_button;
  211. screen.on_receive_mouse_data(dx, dy, left_button, right_button);
  212. dx = 0;
  213. dy = 0;
  214. }
  215. }
  216. if (dx || dy) {
  217. screen.on_receive_mouse_data(dx, dy, left_button, right_button);
  218. }
  219. }
  220. void WSMessageLoop::drain_keyboard()
  221. {
  222. auto& screen = WSScreen::the();
  223. for (;;) {
  224. KeyEvent event;
  225. ssize_t nread = read(m_keyboard_fd, (byte*)&event, sizeof(KeyEvent));
  226. if (nread == 0)
  227. break;
  228. ASSERT(nread == sizeof(KeyEvent));
  229. screen.on_receive_keyboard_data(event);
  230. }
  231. }
  232. void WSMessageLoop::notify_client_disconnected(int client_id)
  233. {
  234. auto* client = WSClientConnection::from_client_id(client_id);
  235. if (!client)
  236. return;
  237. post_message(client, make<WSClientDisconnectedNotification>(client_id));
  238. }
  239. void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessage& message)
  240. {
  241. #if 0
  242. // FIXME: This should not be necessary.. why is this necessary?
  243. while (!running())
  244. sched_yield();
  245. #endif
  246. WSClientConnection* client = WSClientConnection::from_client_id(client_id);
  247. ASSERT(client);
  248. switch (message.type) {
  249. case WSAPI_ClientMessage::Type::CreateMenubar:
  250. post_message(client, make<WSAPICreateMenubarRequest>(client_id));
  251. break;
  252. case WSAPI_ClientMessage::Type::DestroyMenubar:
  253. post_message(client, make<WSAPIDestroyMenubarRequest>(client_id, message.menu.menubar_id));
  254. break;
  255. case WSAPI_ClientMessage::Type::SetApplicationMenubar:
  256. post_message(client, make<WSAPISetApplicationMenubarRequest>(client_id, message.menu.menubar_id));
  257. break;
  258. case WSAPI_ClientMessage::Type::AddMenuToMenubar:
  259. post_message(client, make<WSAPIAddMenuToMenubarRequest>(client_id, message.menu.menubar_id, message.menu.menu_id));
  260. break;
  261. case WSAPI_ClientMessage::Type::CreateMenu:
  262. ASSERT(message.text_length < sizeof(message.text));
  263. post_message(client, make<WSAPICreateMenuRequest>(client_id, String(message.text, message.text_length)));
  264. break;
  265. case WSAPI_ClientMessage::Type::DestroyMenu:
  266. post_message(client, make<WSAPIDestroyMenuRequest>(client_id, message.menu.menu_id));
  267. break;
  268. case WSAPI_ClientMessage::Type::AddMenuItem:
  269. ASSERT(message.text_length < sizeof(message.text));
  270. post_message(client, make<WSAPIAddMenuItemRequest>(client_id, message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length)));
  271. break;
  272. case WSAPI_ClientMessage::Type::CreateWindow:
  273. ASSERT(message.text_length < sizeof(message.text));
  274. post_message(client, make<WSAPICreateWindowRequest>(client_id, message.window.rect, String(message.text, message.text_length), message.window.has_alpha_channel, message.window.opacity, message.window.base_size, message.window.size_increment));
  275. break;
  276. case WSAPI_ClientMessage::Type::DestroyWindow:
  277. post_message(client, make<WSAPIDestroyWindowRequest>(client_id, message.window_id));
  278. break;
  279. case WSAPI_ClientMessage::Type::SetWindowTitle:
  280. ASSERT(message.text_length < sizeof(message.text));
  281. post_message(client, make<WSAPISetWindowTitleRequest>(client_id, message.window_id, String(message.text, message.text_length)));
  282. break;
  283. case WSAPI_ClientMessage::Type::GetWindowTitle:
  284. ASSERT(message.text_length < sizeof(message.text));
  285. post_message(client, make<WSAPIGetWindowTitleRequest>(client_id, message.window_id));
  286. break;
  287. case WSAPI_ClientMessage::Type::SetWindowRect:
  288. post_message(client, make<WSAPISetWindowRectRequest>(client_id, message.window_id, message.window.rect));
  289. break;
  290. case WSAPI_ClientMessage::Type::GetWindowRect:
  291. post_message(client, make<WSAPIGetWindowRectRequest>(client_id, message.window_id));
  292. break;
  293. case WSAPI_ClientMessage::Type::InvalidateRect:
  294. post_message(client, make<WSAPIInvalidateRectRequest>(client_id, message.window_id, message.window.rect));
  295. break;
  296. case WSAPI_ClientMessage::Type::DidFinishPainting:
  297. post_message(client, make<WSAPIDidFinishPaintingNotification>(client_id, message.window_id, message.window.rect));
  298. break;
  299. case WSAPI_ClientMessage::Type::GetWindowBackingStore:
  300. post_message(client, make<WSAPIGetWindowBackingStoreRequest>(client_id, message.window_id));
  301. break;
  302. case WSAPI_ClientMessage::Type::SetWindowBackingStore:
  303. post_message(client, make<WSAPISetWindowBackingStoreRequest>(client_id, message.window_id, message.backing.shared_buffer_id, message.backing.size, message.backing.bpp, message.backing.pitch, message.backing.has_alpha_channel));
  304. break;
  305. case WSAPI_ClientMessage::Type::SetGlobalCursorTracking:
  306. post_message(client, make<WSAPISetGlobalCursorTrackingRequest>(client_id, message.window_id, message.value));
  307. break;
  308. }
  309. }