| 
									
										
										
										
											2019-04-10 17:01:54 +02:00
										 |  |  | #include <LibCore/CObject.h>
 | 
					
						
							| 
									
										
										
										
											2019-01-20 04:49:48 +01:00
										 |  |  | #include "GEventLoop.h"
 | 
					
						
							|  |  |  | #include "GEvent.h"
 | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  | #include "GWindow.h"
 | 
					
						
							| 
									
										
										
										
											2019-03-03 12:32:15 +01:00
										 |  |  | #include <LibGUI/GApplication.h>
 | 
					
						
							| 
									
										
										
										
											2019-02-12 14:09:48 +01:00
										 |  |  | #include <LibGUI/GAction.h>
 | 
					
						
							| 
									
										
										
										
											2019-04-10 17:35:43 +02:00
										 |  |  | #include <LibCore/CNotifier.h>
 | 
					
						
							| 
									
										
										
										
											2019-02-12 10:08:35 +01:00
										 |  |  | #include <LibGUI/GMenu.h>
 | 
					
						
							| 
									
										
										
										
											2019-04-03 17:22:14 +02:00
										 |  |  | #include <LibGUI/GDesktop.h>
 | 
					
						
							| 
									
										
										
										
											2019-04-20 21:56:56 +02:00
										 |  |  | #include <LibGUI/GWidget.h>
 | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  | #include <LibC/unistd.h>
 | 
					
						
							|  |  |  | #include <LibC/stdio.h>
 | 
					
						
							|  |  |  | #include <LibC/fcntl.h>
 | 
					
						
							|  |  |  | #include <LibC/string.h>
 | 
					
						
							| 
									
										
										
										
											2019-02-01 03:50:06 +01:00
										 |  |  | #include <LibC/time.h>
 | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  | #include <LibC/sys/select.h>
 | 
					
						
							| 
									
										
										
										
											2019-02-14 17:18:35 +01:00
										 |  |  | #include <LibC/sys/socket.h>
 | 
					
						
							| 
									
										
										
										
											2019-03-27 01:31:53 +01:00
										 |  |  | #include <LibC/sys/time.h>
 | 
					
						
							| 
									
										
										
										
											2019-02-14 17:18:35 +01:00
										 |  |  | #include <LibC/errno.h>
 | 
					
						
							|  |  |  | #include <LibC/string.h>
 | 
					
						
							|  |  |  | #include <LibC/stdlib.h>
 | 
					
						
							| 
									
										
										
										
											2018-10-10 15:12:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-20 07:03:38 +01:00
										 |  |  | //#define GEVENTLOOP_DEBUG
 | 
					
						
							| 
									
										
										
										
											2019-04-10 15:39:28 +02:00
										 |  |  | //#define COALESCING_DEBUG
 | 
					
						
							| 
									
										
										
										
											2019-01-20 07:03:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-09 17:34:09 +01:00
										 |  |  | int GEventLoop::s_event_fd = -1; | 
					
						
							|  |  |  | pid_t GEventLoop::s_server_pid = -1; | 
					
						
							| 
									
										
										
										
											2018-10-10 15:12:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-09 17:34:09 +01:00
										 |  |  | void GEventLoop::connect_to_server() | 
					
						
							| 
									
										
										
										
											2018-10-10 15:12:38 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-03-19 00:01:02 +01:00
										 |  |  |     ASSERT(s_event_fd == -1); | 
					
						
							| 
									
										
										
										
											2019-03-09 17:34:09 +01:00
										 |  |  |     s_event_fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); | 
					
						
							|  |  |  |     if (s_event_fd < 0) { | 
					
						
							| 
									
										
										
										
											2019-02-14 17:18:35 +01:00
										 |  |  |         perror("socket"); | 
					
						
							|  |  |  |         ASSERT_NOT_REACHED(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sockaddr_un address; | 
					
						
							|  |  |  |     address.sun_family = AF_LOCAL; | 
					
						
							| 
									
										
										
										
											2019-02-21 15:45:31 +01:00
										 |  |  |     strcpy(address.sun_path, "/tmp/wsportal"); | 
					
						
							| 
									
										
										
										
											2019-02-14 17:43:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-17 00:13:47 +01:00
										 |  |  |     int retries = 1000; | 
					
						
							| 
									
										
										
										
											2019-02-14 17:43:20 +01:00
										 |  |  |     int rc = 0; | 
					
						
							|  |  |  |     while (retries) { | 
					
						
							| 
									
										
										
										
											2019-03-09 17:34:09 +01:00
										 |  |  |         rc = connect(s_event_fd, (const sockaddr*)&address, sizeof(address)); | 
					
						
							| 
									
										
										
										
											2019-02-14 17:43:20 +01:00
										 |  |  |         if (rc == 0) | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2019-03-01 10:51:58 +01:00
										 |  |  | #ifdef GEVENTLOOP_DEBUG
 | 
					
						
							| 
									
										
										
										
											2019-02-14 17:18:35 +01:00
										 |  |  |         dbgprintf("connect failed: %d, %s\n", errno, strerror(errno)); | 
					
						
							| 
									
										
										
										
											2019-03-01 10:51:58 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-02-14 17:43:20 +01:00
										 |  |  |         sleep(1); | 
					
						
							|  |  |  |         --retries; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (rc < 0) { | 
					
						
							| 
									
										
										
										
											2019-02-14 17:18:35 +01:00
										 |  |  |         ASSERT_NOT_REACHED(); | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-03-19 00:01:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     WSAPI_ClientMessage request; | 
					
						
							|  |  |  |     request.type = WSAPI_ClientMessage::Type::Greeting; | 
					
						
							|  |  |  |     request.greeting.client_pid = getpid(); | 
					
						
							|  |  |  |     auto response = sync_request(request, WSAPI_ServerMessage::Type::Greeting); | 
					
						
							|  |  |  |     s_server_pid = response.greeting.server_pid; | 
					
						
							| 
									
										
										
										
											2019-04-03 19:38:44 +02:00
										 |  |  |     GDesktop::the().did_receive_screen_rect(Badge<GEventLoop>(), response.greeting.screen_rect); | 
					
						
							| 
									
										
										
										
											2019-03-09 17:34:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GEventLoop::GEventLoop() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-10 17:30:34 +02:00
										 |  |  |     static bool connected = false; | 
					
						
							|  |  |  |     if (!connected) { | 
					
						
							| 
									
										
										
										
											2019-03-09 17:34:09 +01:00
										 |  |  |         connect_to_server(); | 
					
						
							| 
									
										
										
										
											2019-04-10 17:30:34 +02:00
										 |  |  |         connected = true; | 
					
						
							| 
									
										
										
										
											2019-03-09 17:34:09 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-01 10:51:58 +01:00
										 |  |  | #ifdef GEVENTLOOP_DEBUG
 | 
					
						
							| 
									
										
										
										
											2019-02-17 00:13:47 +01:00
										 |  |  |     dbgprintf("(%u) GEventLoop constructed :)\n", getpid()); | 
					
						
							| 
									
										
										
										
											2019-03-01 10:51:58 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-10-10 15:12:38 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-20 04:49:48 +01:00
										 |  |  | GEventLoop::~GEventLoop() | 
					
						
							| 
									
										
										
										
											2018-10-10 15:12:38 +02:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  | void GEventLoop::handle_paint_event(const WSAPI_ServerMessage& event, GWindow& window) | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-01-26 21:44:13 +01:00
										 |  |  | #ifdef GEVENTLOOP_DEBUG
 | 
					
						
							|  |  |  |     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); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-04-20 17:37:28 +02:00
										 |  |  |     Vector<Rect, 32> rects; | 
					
						
							|  |  |  |     ASSERT(event.rect_count <= 32); | 
					
						
							| 
									
										
										
										
											2019-04-20 17:19:56 +02:00
										 |  |  |     for (int i = 0; i < event.rect_count; ++i) | 
					
						
							| 
									
										
										
										
											2019-04-20 17:37:28 +02:00
										 |  |  |         rects.append(event.rects[i]); | 
					
						
							|  |  |  |     post_event(window, make<GMultiPaintEvent>(rects, event.paint.window_size)); | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-20 15:34:55 +01:00
										 |  |  | void GEventLoop::handle_resize_event(const WSAPI_ServerMessage& event, GWindow& window) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-26 00:51:49 +01:00
										 |  |  |     post_event(window, make<GResizeEvent>(event.window.old_rect.size, event.window.rect.size)); | 
					
						
							| 
									
										
										
										
											2019-02-20 15:34:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  | void GEventLoop::handle_window_activation_event(const WSAPI_ServerMessage& event, GWindow& window) | 
					
						
							| 
									
										
										
										
											2019-01-26 21:58:43 +01:00
										 |  |  | { | 
					
						
							|  |  |  | #ifdef GEVENTLOOP_DEBUG
 | 
					
						
							|  |  |  |     dbgprintf("WID=%x WindowActivation\n", event.window_id); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-02-26 00:51:49 +01:00
										 |  |  |     post_event(window, make<GEvent>(event.type == WSAPI_ServerMessage::Type::WindowActivated ? GEvent::WindowBecameActive : GEvent::WindowBecameInactive)); | 
					
						
							| 
									
										
										
										
											2019-01-26 21:58:43 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  | void GEventLoop::handle_window_close_request_event(const WSAPI_ServerMessage&, GWindow& window) | 
					
						
							| 
									
										
										
										
											2019-02-05 10:31:37 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-26 00:51:49 +01:00
										 |  |  |     post_event(window, make<GEvent>(GEvent::WindowCloseRequest)); | 
					
						
							| 
									
										
										
										
											2019-02-05 10:31:37 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-20 10:12:19 +01:00
										 |  |  | void GEventLoop::handle_window_entered_or_left_event(const WSAPI_ServerMessage& message, GWindow& window) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-26 00:51:49 +01:00
										 |  |  |     post_event(window, make<GEvent>(message.type == WSAPI_ServerMessage::Type::WindowEntered ? GEvent::WindowEntered : GEvent::WindowLeft)); | 
					
						
							| 
									
										
										
										
											2019-02-20 10:12:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  | void GEventLoop::handle_key_event(const WSAPI_ServerMessage& event, GWindow& window) | 
					
						
							| 
									
										
										
										
											2019-01-26 06:39:13 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-01-26 21:44:13 +01:00
										 |  |  | #ifdef GEVENTLOOP_DEBUG
 | 
					
						
							|  |  |  |     dbgprintf("WID=%x KeyEvent character=0x%b\n", event.window_id, event.key.character); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-03-03 12:32:15 +01:00
										 |  |  |     auto key_event = make<GKeyEvent>(event.type == WSAPI_ServerMessage::Type::KeyDown ? GEvent::KeyDown : GEvent::KeyUp, event.key.key, event.key.modifiers); | 
					
						
							|  |  |  |     if (event.key.character != '\0') | 
					
						
							|  |  |  |         key_event->m_text = String(&event.key.character, 1); | 
					
						
							| 
									
										
										
										
											2019-03-02 10:04:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-08 01:59:07 +01:00
										 |  |  |     if (event.type == WSAPI_ServerMessage::Type::KeyDown) { | 
					
						
							| 
									
										
										
										
											2019-04-20 21:56:56 +02:00
										 |  |  |         if (auto* focused_widget = window.focused_widget()) { | 
					
						
							|  |  |  |             if (auto* action = focused_widget->action_for_key_event(*key_event)) { | 
					
						
							|  |  |  |                 if (action->is_enabled()) { | 
					
						
							|  |  |  |                     action->activate(); | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-08 01:59:07 +01:00
										 |  |  |         if (auto* action = GApplication::the().action_for_key_event(*key_event)) { | 
					
						
							| 
									
										
										
										
											2019-04-12 02:53:27 +02:00
										 |  |  |             if (action->is_enabled()) { | 
					
						
							|  |  |  |                 action->activate(); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-03-08 01:59:07 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-03-02 10:04:49 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-26 00:51:49 +01:00
										 |  |  |     post_event(window, move(key_event)); | 
					
						
							| 
									
										
										
										
											2019-01-26 06:39:13 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  | void GEventLoop::handle_mouse_event(const WSAPI_ServerMessage& event, GWindow& window) | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-01-26 21:44:13 +01:00
										 |  |  | #ifdef GEVENTLOOP_DEBUG
 | 
					
						
							|  |  |  |     dbgprintf("WID=%x MouseEvent %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  |     GMouseEvent::Type type; | 
					
						
							|  |  |  |     switch (event.type) { | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  |     case WSAPI_ServerMessage::Type::MouseMove: type = GEvent::MouseMove; break; | 
					
						
							|  |  |  |     case WSAPI_ServerMessage::Type::MouseUp: type = GEvent::MouseUp; break; | 
					
						
							|  |  |  |     case WSAPI_ServerMessage::Type::MouseDown: type = GEvent::MouseDown; break; | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  |     default: ASSERT_NOT_REACHED(); break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     GMouseButton button { GMouseButton::None }; | 
					
						
							|  |  |  |     switch (event.mouse.button) { | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  |     case WSAPI_MouseButton::NoButton: button = GMouseButton::None; break; | 
					
						
							|  |  |  |     case WSAPI_MouseButton::Left: button = GMouseButton::Left; break; | 
					
						
							|  |  |  |     case WSAPI_MouseButton::Right: button = GMouseButton::Right; break; | 
					
						
							|  |  |  |     case WSAPI_MouseButton::Middle: button = GMouseButton::Middle; break; | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  |     default: ASSERT_NOT_REACHED(); break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-03-08 17:53:02 +01:00
										 |  |  |     post_event(window, make<GMouseEvent>(type, event.mouse.position, event.mouse.buttons, button, event.mouse.modifiers)); | 
					
						
							| 
									
										
										
										
											2019-01-10 23:19:29 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  | void GEventLoop::handle_menu_event(const WSAPI_ServerMessage& event) | 
					
						
							| 
									
										
										
										
											2019-02-12 10:08:35 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  |     if (event.type == WSAPI_ServerMessage::Type::MenuItemActivated) { | 
					
						
							| 
									
										
										
										
											2019-02-12 10:08:35 +01:00
										 |  |  |         auto* menu = GMenu::from_menu_id(event.menu.menu_id); | 
					
						
							|  |  |  |         if (!menu) { | 
					
						
							|  |  |  |             dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-02-12 14:09:48 +01:00
										 |  |  |         if (auto* action = menu->action_at(event.menu.identifier)) | 
					
						
							|  |  |  |             action->activate(); | 
					
						
							| 
									
										
										
										
											2019-02-12 10:08:35 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ASSERT_NOT_REACHED(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-04 01:44:35 +02:00
										 |  |  | void GEventLoop::handle_wm_event(const WSAPI_ServerMessage& event, GWindow& window) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-04 16:23:23 +02:00
										 |  |  | #ifdef GEVENTLOOP_DEBUG
 | 
					
						
							|  |  |  |     dbgprintf("GEventLoop: handle_wm_event: %d\n", (int)event.type); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-04-04 01:44:35 +02:00
										 |  |  |     if (event.type == WSAPI_ServerMessage::WM_WindowStateChanged) | 
					
						
							| 
									
										
										
										
											2019-04-18 00:39:11 +02:00
										 |  |  |         return post_event(window, make<GWMWindowStateChangedEvent>(event.wm.client_id, event.wm.window_id, String(event.text, event.text_length), event.wm.rect, event.wm.is_active, (GWindowType)event.wm.window_type, event.wm.is_minimized)); | 
					
						
							| 
									
										
										
										
											2019-04-20 14:40:38 +02:00
										 |  |  |     if (event.type == WSAPI_ServerMessage::WM_WindowRectChanged) | 
					
						
							|  |  |  |         return post_event(window, make<GWMWindowRectChangedEvent>(event.wm.client_id, event.wm.window_id, event.wm.rect)); | 
					
						
							| 
									
										
										
										
											2019-04-18 00:39:11 +02:00
										 |  |  |     if (event.type == WSAPI_ServerMessage::WM_WindowIconChanged) | 
					
						
							|  |  |  |         return post_event(window, make<GWMWindowIconChangedEvent>(event.wm.client_id, event.wm.window_id, String(event.text, event.text_length))); | 
					
						
							| 
									
										
										
										
											2019-04-04 01:44:35 +02:00
										 |  |  |     if (event.type == WSAPI_ServerMessage::WM_WindowRemoved) | 
					
						
							|  |  |  |         return post_event(window, make<GWMWindowRemovedEvent>(event.wm.client_id, event.wm.window_id)); | 
					
						
							|  |  |  |     ASSERT_NOT_REACHED(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-20 21:59:13 +01:00
										 |  |  | void GEventLoop::process_unprocessed_messages() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-10 15:39:28 +02:00
										 |  |  |     int coalesced_paints = 0; | 
					
						
							|  |  |  |     int coalesced_resizes = 0; | 
					
						
							| 
									
										
										
										
											2019-02-13 17:59:38 +01:00
										 |  |  |     auto unprocessed_events = move(m_unprocessed_messages); | 
					
						
							| 
									
										
										
										
											2019-04-10 15:39:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     HashMap<int, Size> latest_size_for_window_id; | 
					
						
							|  |  |  |     for (auto& event : unprocessed_events) { | 
					
						
							|  |  |  |         if (event.type == WSAPI_ServerMessage::Type::WindowResized) { | 
					
						
							|  |  |  |             latest_size_for_window_id.set(event.window_id, event.window.rect.size); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int paint_count = 0; | 
					
						
							|  |  |  |     HashMap<int, Size> latest_paint_size_for_window_id; | 
					
						
							|  |  |  |     for (auto& event : unprocessed_events) { | 
					
						
							|  |  |  |         if (event.type == WSAPI_ServerMessage::Type::Paint) { | 
					
						
							|  |  |  |             ++paint_count; | 
					
						
							|  |  |  | #ifdef COALESCING_DEBUG
 | 
					
						
							|  |  |  |             dbgprintf("    %s (window: %s)\n", Rect(event.paint.rect).to_string().characters(), Size(event.paint.window_size).to_string().characters()); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |             latest_paint_size_for_window_id.set(event.window_id, event.paint.window_size); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #ifdef COALESCING_DEBUG
 | 
					
						
							|  |  |  |     dbgprintf("paint_count: %d\n", paint_count); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  |     for (auto& event : unprocessed_events) { | 
					
						
							| 
									
										
										
										
											2019-02-20 21:59:13 +01:00
										 |  |  |         if (event.type == WSAPI_ServerMessage::Type::Greeting) { | 
					
						
							| 
									
										
										
										
											2019-03-09 17:34:09 +01:00
										 |  |  |             s_server_pid = event.greeting.server_pid; | 
					
						
							| 
									
										
										
										
											2019-04-03 17:22:14 +02:00
										 |  |  |             GDesktop::the().did_receive_screen_rect(Badge<GEventLoop>(), event.greeting.screen_rect); | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (event.type == WSAPI_ServerMessage::Type::ScreenRectChanged) { | 
					
						
							|  |  |  |             GDesktop::the().did_receive_screen_rect(Badge<GEventLoop>(), event.screen.rect); | 
					
						
							| 
									
										
										
										
											2019-02-20 21:59:13 +01:00
										 |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-02-14 09:32:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  |         if (event.type == WSAPI_ServerMessage::Error) { | 
					
						
							| 
									
										
										
										
											2019-02-14 09:32:34 +01:00
										 |  |  |             dbgprintf("GEventLoop got error message from server\n"); | 
					
						
							|  |  |  |             dbgprintf("  - error message: %s\n", String(event.text, event.text_length).characters()); | 
					
						
							| 
									
										
										
										
											2019-02-17 09:58:35 +01:00
										 |  |  |             quit(1); | 
					
						
							| 
									
										
										
										
											2019-02-14 09:32:34 +01:00
										 |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-12 10:08:35 +01:00
										 |  |  |         switch (event.type) { | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  |         case WSAPI_ServerMessage::MenuItemActivated: | 
					
						
							| 
									
										
										
										
											2019-02-12 10:08:35 +01:00
										 |  |  |             handle_menu_event(event); | 
					
						
							|  |  |  |             continue; | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  |         default: | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2019-02-12 10:08:35 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  |         auto* window = GWindow::from_window_id(event.window_id); | 
					
						
							|  |  |  |         if (!window) { | 
					
						
							|  |  |  |             dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id); | 
					
						
							| 
									
										
										
										
											2019-01-20 07:03:38 +01:00
										 |  |  |             continue; | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         switch (event.type) { | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  |         case WSAPI_ServerMessage::Type::Paint: | 
					
						
							| 
									
										
										
										
											2019-04-10 15:39:28 +02:00
										 |  |  |             if (Size(event.paint.window_size) != latest_paint_size_for_window_id.get(event.window_id)) { | 
					
						
							|  |  |  |                 ++coalesced_paints; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  |             handle_paint_event(event, *window); | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  |         case WSAPI_ServerMessage::Type::MouseDown: | 
					
						
							|  |  |  |         case WSAPI_ServerMessage::Type::MouseUp: | 
					
						
							|  |  |  |         case WSAPI_ServerMessage::Type::MouseMove: | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  |             handle_mouse_event(event, *window); | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  |         case WSAPI_ServerMessage::Type::WindowActivated: | 
					
						
							|  |  |  |         case WSAPI_ServerMessage::Type::WindowDeactivated: | 
					
						
							| 
									
										
										
										
											2019-01-26 21:58:43 +01:00
										 |  |  |             handle_window_activation_event(event, *window); | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  |         case WSAPI_ServerMessage::Type::WindowCloseRequest: | 
					
						
							| 
									
										
										
										
											2019-02-05 10:31:37 +01:00
										 |  |  |             handle_window_close_request_event(event, *window); | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  |         case WSAPI_ServerMessage::Type::KeyDown: | 
					
						
							|  |  |  |         case WSAPI_ServerMessage::Type::KeyUp: | 
					
						
							| 
									
										
										
										
											2019-01-26 06:39:13 +01:00
										 |  |  |             handle_key_event(event, *window); | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2019-02-20 10:12:19 +01:00
										 |  |  |         case WSAPI_ServerMessage::Type::WindowEntered: | 
					
						
							|  |  |  |         case WSAPI_ServerMessage::Type::WindowLeft: | 
					
						
							|  |  |  |             handle_window_entered_or_left_event(event, *window); | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2019-02-20 15:34:55 +01:00
										 |  |  |         case WSAPI_ServerMessage::Type::WindowResized: | 
					
						
							| 
									
										
										
										
											2019-04-10 15:39:28 +02:00
										 |  |  |             if (Size(event.window.rect.size) != latest_size_for_window_id.get(event.window_id)) { | 
					
						
							|  |  |  |                 ++coalesced_resizes; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-02-20 15:34:55 +01:00
										 |  |  |             handle_resize_event(event, *window); | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2019-04-04 01:44:35 +02:00
										 |  |  |         case WSAPI_ServerMessage::Type::WM_WindowRemoved: | 
					
						
							|  |  |  |         case WSAPI_ServerMessage::Type::WM_WindowStateChanged: | 
					
						
							| 
									
										
										
										
											2019-04-18 00:39:11 +02:00
										 |  |  |         case WSAPI_ServerMessage::Type::WM_WindowIconChanged: | 
					
						
							| 
									
										
										
										
											2019-04-04 01:44:35 +02:00
										 |  |  |             handle_wm_event(event, *window); | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2019-02-12 10:08:35 +01:00
										 |  |  |         default: | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2019-01-20 05:48:43 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-20 21:59:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-10 15:39:28 +02:00
										 |  |  | #ifdef COALESCING_DEBUG
 | 
					
						
							|  |  |  |     if (coalesced_paints) | 
					
						
							|  |  |  |         dbgprintf("Coalesced %d paints\n", coalesced_paints); | 
					
						
							|  |  |  |     if (coalesced_resizes) | 
					
						
							|  |  |  |         dbgprintf("Coalesced %d resizes\n", coalesced_resizes); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-20 21:59:13 +01:00
										 |  |  |     if (!m_unprocessed_messages.is_empty()) | 
					
						
							|  |  |  |         process_unprocessed_messages(); | 
					
						
							| 
									
										
										
										
											2018-10-10 15:12:38 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-02-01 03:50:06 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-13 17:59:38 +01:00
										 |  |  | bool GEventLoop::drain_messages_from_server() | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-03-20 01:09:35 +01:00
										 |  |  |     bool is_first_pass = true; | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  |     for (;;) { | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  |         WSAPI_ServerMessage message; | 
					
						
							| 
									
										
										
										
											2019-03-09 17:34:09 +01:00
										 |  |  |         ssize_t nread = read(s_event_fd, &message, sizeof(WSAPI_ServerMessage)); | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  |         if (nread < 0) { | 
					
						
							|  |  |  |             perror("read"); | 
					
						
							| 
									
										
										
										
											2019-02-17 09:58:35 +01:00
										 |  |  |             quit(1); | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-03-20 01:09:35 +01:00
										 |  |  |         if (nread == 0) { | 
					
						
							|  |  |  |             if (is_first_pass) { | 
					
						
							|  |  |  |                 fprintf(stderr, "EOF on WindowServer fd\n"); | 
					
						
							|  |  |  |                 quit(1); | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  |             return true; | 
					
						
							| 
									
										
										
										
											2019-03-20 01:09:35 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-02-13 17:59:38 +01:00
										 |  |  |         assert(nread == sizeof(message)); | 
					
						
							|  |  |  |         m_unprocessed_messages.append(move(message)); | 
					
						
							| 
									
										
										
										
											2019-03-20 01:09:35 +01:00
										 |  |  |         is_first_pass = false; | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  | bool GEventLoop::post_message_to_server(const WSAPI_ClientMessage& message) | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-03-09 17:34:09 +01:00
										 |  |  |     int nwritten = write(s_event_fd, &message, sizeof(WSAPI_ClientMessage)); | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  |     return nwritten == sizeof(WSAPI_ClientMessage); | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  | bool GEventLoop::wait_for_specific_event(WSAPI_ServerMessage::Type type, WSAPI_ServerMessage& event) | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     for (;;) { | 
					
						
							| 
									
										
										
										
											2019-02-14 10:06:41 +01:00
										 |  |  |         fd_set rfds; | 
					
						
							|  |  |  |         FD_ZERO(&rfds); | 
					
						
							| 
									
										
										
										
											2019-03-09 17:34:09 +01:00
										 |  |  |         FD_SET(s_event_fd, &rfds); | 
					
						
							|  |  |  |         int rc = select(s_event_fd + 1, &rfds, nullptr, nullptr, nullptr); | 
					
						
							| 
									
										
										
										
											2019-02-14 10:06:41 +01:00
										 |  |  |         ASSERT(rc > 0); | 
					
						
							| 
									
										
										
										
											2019-03-09 17:34:09 +01:00
										 |  |  |         ASSERT(FD_ISSET(s_event_fd, &rfds)); | 
					
						
							| 
									
										
										
										
											2019-02-13 17:59:38 +01:00
										 |  |  |         bool success = drain_messages_from_server(); | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  |         if (!success) | 
					
						
							|  |  |  |             return false; | 
					
						
							| 
									
										
										
										
											2019-02-25 22:06:55 +01:00
										 |  |  |         for (ssize_t i = 0; i < m_unprocessed_messages.size(); ++i) { | 
					
						
							| 
									
										
										
										
											2019-02-13 17:59:38 +01:00
										 |  |  |             if (m_unprocessed_messages[i].type == type) { | 
					
						
							|  |  |  |                 event = move(m_unprocessed_messages[i]); | 
					
						
							|  |  |  |                 m_unprocessed_messages.remove(i); | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  |                 return true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  | WSAPI_ServerMessage GEventLoop::sync_request(const WSAPI_ClientMessage& request, WSAPI_ServerMessage::Type response_type) | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     bool success = post_message_to_server(request); | 
					
						
							|  |  |  |     ASSERT(success); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-15 09:17:18 +01:00
										 |  |  |     WSAPI_ServerMessage response; | 
					
						
							| 
									
										
										
										
											2019-03-19 00:01:02 +01:00
										 |  |  |     success = wait_for_specific_event(response_type, response); | 
					
						
							| 
									
										
										
										
											2019-02-13 17:54:30 +01:00
										 |  |  |     ASSERT(success); | 
					
						
							|  |  |  |     return response; | 
					
						
							|  |  |  | } |