GEventLoop.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. #include "GEventLoop.h"
  2. #include "GEvent.h"
  3. #include "GObject.h"
  4. #include "GWindow.h"
  5. #include <LibGUI/GApplication.h>
  6. #include <LibGUI/GAction.h>
  7. #include <LibGUI/GNotifier.h>
  8. #include <LibGUI/GMenu.h>
  9. #include <LibC/unistd.h>
  10. #include <LibC/stdio.h>
  11. #include <LibC/fcntl.h>
  12. #include <LibC/string.h>
  13. #include <LibC/time.h>
  14. #include <LibC/sys/select.h>
  15. #include <LibC/sys/socket.h>
  16. #include <LibC/sys/time.h>
  17. #include <LibC/errno.h>
  18. #include <LibC/string.h>
  19. #include <LibC/stdlib.h>
  20. //#define GEVENTLOOP_DEBUG
  21. static HashMap<GShortcut, GAction*>* g_actions;
  22. static GEventLoop* s_main_event_loop;
  23. static Vector<GEventLoop*>* s_event_loop_stack;
  24. int GEventLoop::s_event_fd = -1;
  25. pid_t GEventLoop::s_server_pid = -1;
  26. HashMap<int, OwnPtr<GEventLoop::EventLoopTimer>>* GEventLoop::s_timers;
  27. HashTable<GNotifier*>* GEventLoop::s_notifiers;
  28. int GEventLoop::s_next_timer_id = 1;
  29. void GEventLoop::connect_to_server()
  30. {
  31. ASSERT(s_event_fd == -1);
  32. s_event_fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
  33. if (s_event_fd < 0) {
  34. perror("socket");
  35. ASSERT_NOT_REACHED();
  36. }
  37. sockaddr_un address;
  38. address.sun_family = AF_LOCAL;
  39. strcpy(address.sun_path, "/tmp/wsportal");
  40. int retries = 1000;
  41. int rc = 0;
  42. while (retries) {
  43. rc = connect(s_event_fd, (const sockaddr*)&address, sizeof(address));
  44. if (rc == 0)
  45. break;
  46. #ifdef GEVENTLOOP_DEBUG
  47. dbgprintf("connect failed: %d, %s\n", errno, strerror(errno));
  48. #endif
  49. sleep(1);
  50. --retries;
  51. }
  52. if (rc < 0) {
  53. ASSERT_NOT_REACHED();
  54. }
  55. WSAPI_ClientMessage request;
  56. request.type = WSAPI_ClientMessage::Type::Greeting;
  57. request.greeting.client_pid = getpid();
  58. auto response = sync_request(request, WSAPI_ServerMessage::Type::Greeting);
  59. s_server_pid = response.greeting.server_pid;
  60. }
  61. GEventLoop::GEventLoop()
  62. {
  63. if (!s_event_loop_stack) {
  64. s_event_loop_stack = new Vector<GEventLoop*>;
  65. s_timers = new HashMap<int, OwnPtr<GEventLoop::EventLoopTimer>>;
  66. s_notifiers = new HashTable<GNotifier*>;
  67. }
  68. if (!s_main_event_loop) {
  69. s_main_event_loop = this;
  70. s_event_loop_stack->append(this);
  71. connect_to_server();
  72. }
  73. if (!g_actions)
  74. g_actions = new HashMap<GShortcut, GAction*>;
  75. #ifdef GEVENTLOOP_DEBUG
  76. dbgprintf("(%u) GEventLoop constructed :)\n", getpid());
  77. #endif
  78. }
  79. GEventLoop::~GEventLoop()
  80. {
  81. }
  82. GEventLoop& GEventLoop::main()
  83. {
  84. ASSERT(s_main_event_loop);
  85. return *s_main_event_loop;
  86. }
  87. GEventLoop& GEventLoop::current()
  88. {
  89. return *s_event_loop_stack->last();
  90. }
  91. void GEventLoop::quit(int code)
  92. {
  93. m_exit_requested = true;
  94. m_exit_code = code;
  95. }
  96. struct GEventLoopPusher {
  97. public:
  98. GEventLoopPusher(GEventLoop& event_loop) : m_event_loop(event_loop)
  99. {
  100. if (&m_event_loop != s_main_event_loop) {
  101. m_event_loop.take_pending_events_from(GEventLoop::current());
  102. s_event_loop_stack->append(&event_loop);
  103. }
  104. }
  105. ~GEventLoopPusher()
  106. {
  107. if (&m_event_loop != s_main_event_loop) {
  108. s_event_loop_stack->take_last();
  109. GEventLoop::current().take_pending_events_from(m_event_loop);
  110. }
  111. }
  112. private:
  113. GEventLoop& m_event_loop;
  114. };
  115. int GEventLoop::exec()
  116. {
  117. GEventLoopPusher pusher(*this);
  118. m_running = true;
  119. for (;;) {
  120. if (m_exit_requested)
  121. return m_exit_code;
  122. process_unprocessed_messages();
  123. if (m_queued_events.is_empty()) {
  124. wait_for_event();
  125. process_unprocessed_messages();
  126. }
  127. Vector<QueuedEvent> events = move(m_queued_events);
  128. for (auto& queued_event : events) {
  129. auto* receiver = queued_event.receiver.ptr();
  130. auto& event = *queued_event.event;
  131. #ifdef GEVENTLOOP_DEBUG
  132. dbgprintf("GEventLoop: %s{%p} event %u\n", receiver->class_name(), receiver, (unsigned)event.type());
  133. #endif
  134. if (!receiver) {
  135. switch (event.type()) {
  136. case GEvent::Quit:
  137. ASSERT_NOT_REACHED();
  138. return 0;
  139. default:
  140. dbgprintf("Event type %u with no receiver :(\n", event.type());
  141. }
  142. } else {
  143. receiver->event(event);
  144. }
  145. if (m_exit_requested) {
  146. auto rejigged_event_queue = move(events);
  147. rejigged_event_queue.append(move(m_queued_events));
  148. m_queued_events = move(rejigged_event_queue);
  149. return m_exit_code;
  150. }
  151. }
  152. }
  153. ASSERT_NOT_REACHED();
  154. }
  155. void GEventLoop::post_event(GObject& receiver, OwnPtr<GEvent>&& event)
  156. {
  157. #ifdef GEVENTLOOP_DEBUG
  158. dbgprintf("GEventLoop::post_event: {%u} << receiver=%p, event=%p\n", m_queued_events.size(), &receiver, event.ptr());
  159. #endif
  160. m_queued_events.append({ receiver.make_weak_ptr(), move(event) });
  161. }
  162. void GEventLoop::handle_paint_event(const WSAPI_ServerMessage& event, GWindow& window)
  163. {
  164. #ifdef GEVENTLOOP_DEBUG
  165. 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);
  166. #endif
  167. post_event(window, make<GPaintEvent>(event.paint.rect, event.paint.window_size));
  168. }
  169. void GEventLoop::handle_resize_event(const WSAPI_ServerMessage& event, GWindow& window)
  170. {
  171. post_event(window, make<GResizeEvent>(event.window.old_rect.size, event.window.rect.size));
  172. }
  173. void GEventLoop::handle_window_activation_event(const WSAPI_ServerMessage& event, GWindow& window)
  174. {
  175. #ifdef GEVENTLOOP_DEBUG
  176. dbgprintf("WID=%x WindowActivation\n", event.window_id);
  177. #endif
  178. post_event(window, make<GEvent>(event.type == WSAPI_ServerMessage::Type::WindowActivated ? GEvent::WindowBecameActive : GEvent::WindowBecameInactive));
  179. }
  180. void GEventLoop::handle_window_close_request_event(const WSAPI_ServerMessage&, GWindow& window)
  181. {
  182. post_event(window, make<GEvent>(GEvent::WindowCloseRequest));
  183. }
  184. void GEventLoop::handle_window_entered_or_left_event(const WSAPI_ServerMessage& message, GWindow& window)
  185. {
  186. post_event(window, make<GEvent>(message.type == WSAPI_ServerMessage::Type::WindowEntered ? GEvent::WindowEntered : GEvent::WindowLeft));
  187. }
  188. void GEventLoop::handle_key_event(const WSAPI_ServerMessage& event, GWindow& window)
  189. {
  190. #ifdef GEVENTLOOP_DEBUG
  191. dbgprintf("WID=%x KeyEvent character=0x%b\n", event.window_id, event.key.character);
  192. #endif
  193. auto key_event = make<GKeyEvent>(event.type == WSAPI_ServerMessage::Type::KeyDown ? GEvent::KeyDown : GEvent::KeyUp, event.key.key, event.key.modifiers);
  194. if (event.key.character != '\0')
  195. key_event->m_text = String(&event.key.character, 1);
  196. if (event.type == WSAPI_ServerMessage::Type::KeyDown) {
  197. if (auto* action = GApplication::the().action_for_key_event(*key_event)) {
  198. action->activate();
  199. return;
  200. }
  201. }
  202. post_event(window, move(key_event));
  203. }
  204. void GEventLoop::handle_mouse_event(const WSAPI_ServerMessage& event, GWindow& window)
  205. {
  206. #ifdef GEVENTLOOP_DEBUG
  207. dbgprintf("WID=%x MouseEvent %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y);
  208. #endif
  209. GMouseEvent::Type type;
  210. switch (event.type) {
  211. case WSAPI_ServerMessage::Type::MouseMove: type = GEvent::MouseMove; break;
  212. case WSAPI_ServerMessage::Type::MouseUp: type = GEvent::MouseUp; break;
  213. case WSAPI_ServerMessage::Type::MouseDown: type = GEvent::MouseDown; break;
  214. default: ASSERT_NOT_REACHED(); break;
  215. }
  216. GMouseButton button { GMouseButton::None };
  217. switch (event.mouse.button) {
  218. case WSAPI_MouseButton::NoButton: button = GMouseButton::None; break;
  219. case WSAPI_MouseButton::Left: button = GMouseButton::Left; break;
  220. case WSAPI_MouseButton::Right: button = GMouseButton::Right; break;
  221. case WSAPI_MouseButton::Middle: button = GMouseButton::Middle; break;
  222. default: ASSERT_NOT_REACHED(); break;
  223. }
  224. post_event(window, make<GMouseEvent>(type, event.mouse.position, event.mouse.buttons, button, event.mouse.modifiers));
  225. }
  226. void GEventLoop::handle_menu_event(const WSAPI_ServerMessage& event)
  227. {
  228. if (event.type == WSAPI_ServerMessage::Type::MenuItemActivated) {
  229. auto* menu = GMenu::from_menu_id(event.menu.menu_id);
  230. if (!menu) {
  231. dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id);
  232. return;
  233. }
  234. if (auto* action = menu->action_at(event.menu.identifier))
  235. action->activate();
  236. return;
  237. }
  238. ASSERT_NOT_REACHED();
  239. }
  240. void GEventLoop::wait_for_event()
  241. {
  242. fd_set rfds;
  243. fd_set wfds;
  244. FD_ZERO(&rfds);
  245. FD_ZERO(&wfds);
  246. int max_fd = 0;
  247. auto add_fd_to_set = [&max_fd] (int fd, fd_set& set){
  248. FD_SET(fd, &set);
  249. if (fd > max_fd)
  250. max_fd = fd;
  251. };
  252. add_fd_to_set(s_event_fd, rfds);
  253. for (auto& notifier : *s_notifiers) {
  254. if (notifier->event_mask() & GNotifier::Read)
  255. add_fd_to_set(notifier->fd(), rfds);
  256. if (notifier->event_mask() & GNotifier::Write)
  257. add_fd_to_set(notifier->fd(), wfds);
  258. if (notifier->event_mask() & GNotifier::Exceptional)
  259. ASSERT_NOT_REACHED();
  260. }
  261. struct timeval timeout = { 0, 0 };
  262. if (!s_timers->is_empty() && m_queued_events.is_empty())
  263. get_next_timer_expiration(timeout);
  264. ASSERT(m_unprocessed_messages.is_empty());
  265. int rc = select(max_fd + 1, &rfds, &wfds, nullptr, (m_queued_events.is_empty() && s_timers->is_empty()) ? nullptr : &timeout);
  266. if (rc < 0) {
  267. ASSERT_NOT_REACHED();
  268. }
  269. for (auto& it : *s_timers) {
  270. auto& timer = *it.value;
  271. if (!timer.has_expired())
  272. continue;
  273. #ifdef GEVENTLOOP_DEBUG
  274. dbgprintf("GEventLoop: Timer %d has expired, sending GTimerEvent to %p\n", timer.timer_id, timer.owner);
  275. #endif
  276. post_event(*timer.owner, make<GTimerEvent>(timer.timer_id));
  277. if (timer.should_reload) {
  278. timer.reload();
  279. } else {
  280. // FIXME: Support removing expired timers that don't want to reload.
  281. ASSERT_NOT_REACHED();
  282. }
  283. }
  284. for (auto& notifier : *s_notifiers) {
  285. if (FD_ISSET(notifier->fd(), &rfds)) {
  286. if (notifier->on_ready_to_read)
  287. notifier->on_ready_to_read(*notifier);
  288. }
  289. if (FD_ISSET(notifier->fd(), &wfds)) {
  290. if (notifier->on_ready_to_write)
  291. notifier->on_ready_to_write(*notifier);
  292. }
  293. }
  294. if (!FD_ISSET(s_event_fd, &rfds))
  295. return;
  296. bool success = drain_messages_from_server();
  297. ASSERT(success);
  298. }
  299. void GEventLoop::process_unprocessed_messages()
  300. {
  301. auto unprocessed_events = move(m_unprocessed_messages);
  302. for (auto& event : unprocessed_events) {
  303. if (event.type == WSAPI_ServerMessage::Type::Greeting) {
  304. s_server_pid = event.greeting.server_pid;
  305. continue;
  306. }
  307. if (event.type == WSAPI_ServerMessage::Error) {
  308. dbgprintf("GEventLoop got error message from server\n");
  309. dbgprintf(" - error message: %s\n", String(event.text, event.text_length).characters());
  310. quit(1);
  311. return;
  312. }
  313. switch (event.type) {
  314. case WSAPI_ServerMessage::MenuItemActivated:
  315. handle_menu_event(event);
  316. continue;
  317. default:
  318. break;
  319. }
  320. auto* window = GWindow::from_window_id(event.window_id);
  321. if (!window) {
  322. dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id);
  323. continue;
  324. }
  325. switch (event.type) {
  326. case WSAPI_ServerMessage::Type::Paint:
  327. handle_paint_event(event, *window);
  328. break;
  329. case WSAPI_ServerMessage::Type::MouseDown:
  330. case WSAPI_ServerMessage::Type::MouseUp:
  331. case WSAPI_ServerMessage::Type::MouseMove:
  332. handle_mouse_event(event, *window);
  333. break;
  334. case WSAPI_ServerMessage::Type::WindowActivated:
  335. case WSAPI_ServerMessage::Type::WindowDeactivated:
  336. handle_window_activation_event(event, *window);
  337. break;
  338. case WSAPI_ServerMessage::Type::WindowCloseRequest:
  339. handle_window_close_request_event(event, *window);
  340. break;
  341. case WSAPI_ServerMessage::Type::KeyDown:
  342. case WSAPI_ServerMessage::Type::KeyUp:
  343. handle_key_event(event, *window);
  344. break;
  345. case WSAPI_ServerMessage::Type::WindowEntered:
  346. case WSAPI_ServerMessage::Type::WindowLeft:
  347. handle_window_entered_or_left_event(event, *window);
  348. break;
  349. case WSAPI_ServerMessage::Type::WindowResized:
  350. handle_resize_event(event, *window);
  351. break;
  352. default:
  353. break;
  354. }
  355. }
  356. if (!m_unprocessed_messages.is_empty())
  357. process_unprocessed_messages();
  358. }
  359. bool GEventLoop::drain_messages_from_server()
  360. {
  361. bool is_first_pass = true;
  362. for (;;) {
  363. WSAPI_ServerMessage message;
  364. ssize_t nread = read(s_event_fd, &message, sizeof(WSAPI_ServerMessage));
  365. if (nread < 0) {
  366. perror("read");
  367. quit(1);
  368. return false;
  369. }
  370. if (nread == 0) {
  371. if (is_first_pass) {
  372. fprintf(stderr, "EOF on WindowServer fd\n");
  373. quit(1);
  374. return false;
  375. }
  376. return true;
  377. }
  378. assert(nread == sizeof(message));
  379. m_unprocessed_messages.append(move(message));
  380. is_first_pass = false;
  381. }
  382. }
  383. bool GEventLoop::EventLoopTimer::has_expired() const
  384. {
  385. timeval now;
  386. gettimeofday(&now, nullptr);
  387. return now.tv_sec > fire_time.tv_sec || (now.tv_sec == fire_time.tv_sec && now.tv_usec >= fire_time.tv_usec);
  388. }
  389. void GEventLoop::EventLoopTimer::reload()
  390. {
  391. gettimeofday(&fire_time, nullptr);
  392. fire_time.tv_sec += interval / 1000;
  393. fire_time.tv_usec += (interval % 1000) * 1000;
  394. }
  395. void GEventLoop::get_next_timer_expiration(timeval& soonest)
  396. {
  397. ASSERT(!s_timers->is_empty());
  398. bool has_checked_any = false;
  399. for (auto& it : *s_timers) {
  400. auto& fire_time = it.value->fire_time;
  401. if (!has_checked_any || fire_time.tv_sec < soonest.tv_sec || (fire_time.tv_sec == soonest.tv_sec && fire_time.tv_usec < soonest.tv_usec))
  402. soonest = fire_time;
  403. has_checked_any = true;
  404. }
  405. }
  406. int GEventLoop::register_timer(GObject& object, int milliseconds, bool should_reload)
  407. {
  408. ASSERT(milliseconds >= 0);
  409. auto timer = make<EventLoopTimer>();
  410. timer->owner = object.make_weak_ptr();
  411. timer->interval = milliseconds;
  412. timer->reload();
  413. timer->should_reload = should_reload;
  414. int timer_id = ++s_next_timer_id; // FIXME: This will eventually wrap around.
  415. ASSERT(timer_id); // FIXME: Aforementioned wraparound.
  416. timer->timer_id = timer_id;
  417. s_timers->set(timer->timer_id, move(timer));
  418. return timer_id;
  419. }
  420. bool GEventLoop::unregister_timer(int timer_id)
  421. {
  422. auto it = s_timers->find(timer_id);
  423. if (it == s_timers->end())
  424. return false;
  425. s_timers->remove(it);
  426. return true;
  427. }
  428. void GEventLoop::register_notifier(Badge<GNotifier>, GNotifier& notifier)
  429. {
  430. s_notifiers->set(&notifier);
  431. }
  432. void GEventLoop::unregister_notifier(Badge<GNotifier>, GNotifier& notifier)
  433. {
  434. s_notifiers->remove(&notifier);
  435. }
  436. bool GEventLoop::post_message_to_server(const WSAPI_ClientMessage& message)
  437. {
  438. int nwritten = write(s_event_fd, &message, sizeof(WSAPI_ClientMessage));
  439. return nwritten == sizeof(WSAPI_ClientMessage);
  440. }
  441. bool GEventLoop::wait_for_specific_event(WSAPI_ServerMessage::Type type, WSAPI_ServerMessage& event)
  442. {
  443. for (;;) {
  444. fd_set rfds;
  445. FD_ZERO(&rfds);
  446. FD_SET(s_event_fd, &rfds);
  447. int rc = select(s_event_fd + 1, &rfds, nullptr, nullptr, nullptr);
  448. ASSERT(rc > 0);
  449. ASSERT(FD_ISSET(s_event_fd, &rfds));
  450. bool success = drain_messages_from_server();
  451. if (!success)
  452. return false;
  453. for (ssize_t i = 0; i < m_unprocessed_messages.size(); ++i) {
  454. if (m_unprocessed_messages[i].type == type) {
  455. event = move(m_unprocessed_messages[i]);
  456. m_unprocessed_messages.remove(i);
  457. return true;
  458. }
  459. }
  460. }
  461. }
  462. WSAPI_ServerMessage GEventLoop::sync_request(const WSAPI_ClientMessage& request, WSAPI_ServerMessage::Type response_type)
  463. {
  464. bool success = post_message_to_server(request);
  465. ASSERT(success);
  466. WSAPI_ServerMessage response;
  467. success = wait_for_specific_event(response_type, response);
  468. ASSERT(success);
  469. return response;
  470. }