diff --git a/Servers/WindowServer/WSClientConnection.cpp b/Servers/WindowServer/WSClientConnection.cpp index 510be0647c..a776caffea 100644 --- a/Servers/WindowServer/WSClientConnection.cpp +++ b/Servers/WindowServer/WSClientConnection.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -145,6 +146,267 @@ void WSClientConnection::did_misbehave() delete_later(); } +static Vector get_rects(const WSAPI_ClientMessage& message, const ByteBuffer& extra_data) +{ + Vector rects; + if (message.rect_count > (int)(WSAPI_ClientMessage::max_inline_rect_count + extra_data.size() / sizeof(WSAPI_Rect))) { + return {}; + } + for (int i = 0; i < min(WSAPI_ClientMessage::max_inline_rect_count, message.rect_count); ++i) + rects.append(message.rects[i]); + if (!extra_data.is_empty()) { + auto* extra_rects = reinterpret_cast(extra_data.data()); + for (int i = 0; i < (int)(extra_data.size() / sizeof(WSAPI_Rect)); ++i) + rects.append(extra_rects[i]); + } + return rects; +} + +void WSClientConnection::on_ready_read() +{ + unsigned messages_received = 0; + for (;;) { + WSAPI_ClientMessage message; + // FIXME: Don't go one message at a time, that's so much context switching, oof. + ssize_t nread = recv(fd(), &message, sizeof(WSAPI_ClientMessage), MSG_DONTWAIT); + if (nread == 0 || (nread == -1 && errno == EAGAIN)) { + if (!messages_received) + CEventLoop::current().post_event(*this, make(client_id())); + break; + } + if (nread < 0) { + perror("recv"); + ASSERT_NOT_REACHED(); + } + ByteBuffer extra_data; + if (message.extra_size) { + if (message.extra_size >= 32768) { + dbgprintf("message.extra_size is way too large\n"); + return did_misbehave(); + } + extra_data = ByteBuffer::create_uninitialized(message.extra_size); + // FIXME: We should allow this to time out. Maybe use a socket timeout? + int extra_nread = read(fd(), extra_data.data(), extra_data.size()); + if (extra_nread != (int)message.extra_size) { + dbgprintf("extra_nread(%d) != extra_size(%d)\n", extra_nread, extra_data.size()); + if (extra_nread < 0) + perror("read"); + return did_misbehave(); + } + } + if (!handle_message(message, move(extra_data))) + return; + ++messages_received; + } +} + +bool WSClientConnection::handle_message(const WSAPI_ClientMessage& message, ByteBuffer&& extra_data) +{ + switch (message.type) { + case WSAPI_ClientMessage::Type::Greeting: + set_client_pid(message.greeting.client_pid); + break; + case WSAPI_ClientMessage::Type::CreateMenubar: + CEventLoop::current().post_event(*this, make(m_client_id)); + break; + case WSAPI_ClientMessage::Type::DestroyMenubar: + CEventLoop::current().post_event(*this, make(m_client_id, message.menu.menubar_id)); + break; + case WSAPI_ClientMessage::Type::SetApplicationMenubar: + CEventLoop::current().post_event(*this, make(m_client_id, message.menu.menubar_id)); + break; + case WSAPI_ClientMessage::Type::AddMenuToMenubar: + CEventLoop::current().post_event(*this, make(m_client_id, message.menu.menubar_id, message.menu.menu_id)); + break; + case WSAPI_ClientMessage::Type::CreateMenu: + if (message.text_length > (int)sizeof(message.text)) { + did_misbehave(); + return false; + } + CEventLoop::current().post_event(*this, make(m_client_id, String(message.text, message.text_length))); + break; + case WSAPI_ClientMessage::Type::PopupMenu: + CEventLoop::current().post_event(*this, make(m_client_id, message.menu.menu_id, message.menu.position)); + break; + case WSAPI_ClientMessage::Type::DismissMenu: + CEventLoop::current().post_event(*this, make(m_client_id, message.menu.menu_id)); + break; + case WSAPI_ClientMessage::Type::SetWindowIcon: + if (message.text_length > (int)sizeof(message.text)) { + did_misbehave(); + return false; + } + CEventLoop::current().post_event(*this, make(m_client_id, message.window_id, String(message.text, message.text_length))); + break; + case WSAPI_ClientMessage::Type::DestroyMenu: + CEventLoop::current().post_event(*this, make(m_client_id, message.menu.menu_id)); + break; + case WSAPI_ClientMessage::Type::AddMenuItem: + if (message.text_length > (int)sizeof(message.text)) { + did_misbehave(); + return false; + } + if (message.menu.shortcut_text_length > (int)sizeof(message.menu.shortcut_text)) { + did_misbehave(); + return false; + } + CEventLoop::current().post_event(*this, make(m_client_id, message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length), String(message.menu.shortcut_text, message.menu.shortcut_text_length), message.menu.enabled, message.menu.checkable, message.menu.checked)); + break; + case WSAPI_ClientMessage::Type::UpdateMenuItem: + if (message.text_length > (int)sizeof(message.text)) { + did_misbehave(); + return false; + } + if (message.menu.shortcut_text_length > (int)sizeof(message.menu.shortcut_text)) { + did_misbehave(); + return false; + } + CEventLoop::current().post_event(*this, make(m_client_id, message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length), String(message.menu.shortcut_text, message.menu.shortcut_text_length), message.menu.enabled, message.menu.checkable, message.menu.checked)); + break; + case WSAPI_ClientMessage::Type::AddMenuSeparator: + CEventLoop::current().post_event(*this, make(m_client_id, message.menu.menu_id)); + break; + case WSAPI_ClientMessage::Type::CreateWindow: { + if (message.text_length > (int)sizeof(message.text)) { + did_misbehave(); + return false; + } + + auto ws_window_type = WSWindowType::Invalid; + switch (message.window.type) { + case WSAPI_WindowType::Normal: + ws_window_type = WSWindowType::Normal; + break; + case WSAPI_WindowType::Menu: + ws_window_type = WSWindowType::Menu; + break; + case WSAPI_WindowType::WindowSwitcher: + ws_window_type = WSWindowType::WindowSwitcher; + break; + case WSAPI_WindowType::Taskbar: + ws_window_type = WSWindowType::Taskbar; + break; + case WSAPI_WindowType::Tooltip: + ws_window_type = WSWindowType::Tooltip; + break; + case WSAPI_WindowType::Menubar: + ws_window_type = WSWindowType::Menubar; + break; + case WSAPI_WindowType::Launcher: + ws_window_type = WSWindowType::Launcher; + break; + case WSAPI_WindowType::Invalid: + default: + dbgprintf("Unknown WSAPI_WindowType: %d\n", message.window.type); + did_misbehave(); + return false; + } + + CEventLoop::current().post_event(*this, + make(m_client_id, + message.window.rect, + String(message.text, message.text_length), + message.window.has_alpha_channel, + message.window.modal, + message.window.resizable, + message.window.fullscreen, + message.window.show_titlebar, + message.window.opacity, + message.window.base_size, + message.window.size_increment, + ws_window_type, + Color::from_rgba(message.window.background_color))); + break; + } + case WSAPI_ClientMessage::Type::DestroyWindow: + CEventLoop::current().post_event(*this, make(m_client_id, message.window_id)); + break; + case WSAPI_ClientMessage::Type::SetWindowTitle: + if (message.text_length > (int)sizeof(message.text)) { + did_misbehave(); + return false; + } + CEventLoop::current().post_event(*this, make(m_client_id, message.window_id, String(message.text, message.text_length))); + break; + case WSAPI_ClientMessage::Type::GetWindowTitle: + CEventLoop::current().post_event(*this, make(m_client_id, message.window_id)); + break; + case WSAPI_ClientMessage::Type::SetWindowRect: + CEventLoop::current().post_event(*this, make(m_client_id, message.window_id, message.window.rect)); + break; + case WSAPI_ClientMessage::Type::GetWindowRect: + CEventLoop::current().post_event(*this, make(m_client_id, message.window_id)); + break; + case WSAPI_ClientMessage::Type::SetClipboardContents: + CEventLoop::current().post_event(*this, make(m_client_id, message.clipboard.shared_buffer_id, message.clipboard.contents_size)); + break; + case WSAPI_ClientMessage::Type::GetClipboardContents: + CEventLoop::current().post_event(*this, make(m_client_id)); + break; + case WSAPI_ClientMessage::Type::InvalidateRect: { + auto rects = get_rects(message, extra_data); + if (rects.is_empty()) { + did_misbehave(); + return false; + } + CEventLoop::current().post_event(*this, make(m_client_id, message.window_id, rects)); + break; + } + case WSAPI_ClientMessage::Type::DidFinishPainting: { + auto rects = get_rects(message, extra_data); + if (rects.is_empty()) { + did_misbehave(); + return false; + } + CEventLoop::current().post_event(*this, make(m_client_id, message.window_id, rects)); + break; + } + case WSAPI_ClientMessage::Type::GetWindowBackingStore: + CEventLoop::current().post_event(*this, make(m_client_id, message.window_id)); + break; + case WSAPI_ClientMessage::Type::SetWindowBackingStore: + CEventLoop::current().post_event(*this, make(m_client_id, message.window_id, message.backing.shared_buffer_id, message.backing.size, message.backing.bpp, message.backing.pitch, message.backing.has_alpha_channel, message.backing.flush_immediately)); + break; + case WSAPI_ClientMessage::Type::SetGlobalCursorTracking: + CEventLoop::current().post_event(*this, make(m_client_id, message.window_id, message.value)); + break; + case WSAPI_ClientMessage::Type::SetWallpaper: + if (message.text_length > (int)sizeof(message.text)) { + did_misbehave(); + return false; + } + CEventLoop::current().post_event(*this, make(m_client_id, String(message.text, message.text_length))); + break; + case WSAPI_ClientMessage::Type::GetWallpaper: + CEventLoop::current().post_event(*this, make(m_client_id)); + break; + case WSAPI_ClientMessage::Type::SetWindowOverrideCursor: + CEventLoop::current().post_event(*this, make(m_client_id, message.window_id, (WSStandardCursor)message.cursor.cursor)); + break; + case WSAPI_ClientMessage::SetWindowHasAlphaChannel: + CEventLoop::current().post_event(*this, make(m_client_id, message.window_id, message.value)); + break; + case WSAPI_ClientMessage::Type::WM_SetActiveWindow: + CEventLoop::current().post_event(*this, make(m_client_id, message.wm.client_id, message.wm.window_id)); + break; + case WSAPI_ClientMessage::Type::WM_SetWindowMinimized: + CEventLoop::current().post_event(*this, make(m_client_id, message.wm.client_id, message.wm.window_id, message.wm.minimized)); + break; + case WSAPI_ClientMessage::Type::WM_StartWindowResize: + CEventLoop::current().post_event(*this, make(m_client_id, message.wm.client_id, message.wm.window_id)); + break; + case WSAPI_ClientMessage::Type::WM_PopupWindowMenu: + CEventLoop::current().post_event(*this, make(m_client_id, message.wm.client_id, message.wm.window_id, message.wm.position)); + break; + case WSAPI_ClientMessage::Type::MoveWindowToFront: + CEventLoop::current().post_event(*this, make(m_client_id, message.window_id)); + break; + default: + break; + } + return true; +} + void WSClientConnection::handle_request(const WSAPICreateMenubarRequest&) { int menubar_id = m_next_menubar_id++; diff --git a/Servers/WindowServer/WSClientConnection.h b/Servers/WindowServer/WSClientConnection.h index 7032a5e186..747bebc2a0 100644 --- a/Servers/WindowServer/WSClientConnection.h +++ b/Servers/WindowServer/WSClientConnection.h @@ -43,9 +43,12 @@ public: void did_misbehave(); + void on_ready_read(); + private: virtual void event(CEvent&) override; + bool handle_message(const WSAPI_ClientMessage& message, ByteBuffer&& extra_data); void on_request(const WSAPIClientRequest&); void handle_request(const WSAPICreateMenubarRequest&); void handle_request(const WSAPIDestroyMenubarRequest&); diff --git a/Servers/WindowServer/WSEventLoop.cpp b/Servers/WindowServer/WSEventLoop.cpp index 7e46c6f311..8ae70f79d9 100644 --- a/Servers/WindowServer/WSEventLoop.cpp +++ b/Servers/WindowServer/WSEventLoop.cpp @@ -102,230 +102,6 @@ void WSEventLoop::drain_keyboard() } } -static Vector get_rects(const WSAPI_ClientMessage& message, const ByteBuffer& extra_data) -{ - Vector rects; - if (message.rect_count > (int)(WSAPI_ClientMessage::max_inline_rect_count + extra_data.size() / sizeof(WSAPI_Rect))) { - return {}; - } - for (int i = 0; i < min(WSAPI_ClientMessage::max_inline_rect_count, message.rect_count); ++i) - rects.append(message.rects[i]); - if (!extra_data.is_empty()) { - auto* extra_rects = reinterpret_cast(extra_data.data()); - for (int i = 0; i < (int)(extra_data.size() / sizeof(WSAPI_Rect)); ++i) - rects.append(extra_rects[i]); - } - return rects; -} - -bool WSEventLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessage& message, ByteBuffer&& extra_data) -{ - WSClientConnection& client = *WSClientConnection::from_client_id(client_id); - switch (message.type) { - case WSAPI_ClientMessage::Type::Greeting: - client.set_client_pid(message.greeting.client_pid); - break; - case WSAPI_ClientMessage::Type::CreateMenubar: - post_event(client, make(client_id)); - break; - case WSAPI_ClientMessage::Type::DestroyMenubar: - post_event(client, make(client_id, message.menu.menubar_id)); - break; - case WSAPI_ClientMessage::Type::SetApplicationMenubar: - post_event(client, make(client_id, message.menu.menubar_id)); - break; - case WSAPI_ClientMessage::Type::AddMenuToMenubar: - post_event(client, make(client_id, message.menu.menubar_id, message.menu.menu_id)); - break; - case WSAPI_ClientMessage::Type::CreateMenu: - if (message.text_length > (int)sizeof(message.text)) { - client.did_misbehave(); - return false; - } - post_event(client, make(client_id, String(message.text, message.text_length))); - break; - case WSAPI_ClientMessage::Type::PopupMenu: - post_event(client, make(client_id, message.menu.menu_id, message.menu.position)); - break; - case WSAPI_ClientMessage::Type::DismissMenu: - post_event(client, make(client_id, message.menu.menu_id)); - break; - case WSAPI_ClientMessage::Type::SetWindowIcon: - if (message.text_length > (int)sizeof(message.text)) { - client.did_misbehave(); - return false; - } - post_event(client, make(client_id, message.window_id, String(message.text, message.text_length))); - break; - case WSAPI_ClientMessage::Type::DestroyMenu: - post_event(client, make(client_id, message.menu.menu_id)); - break; - case WSAPI_ClientMessage::Type::AddMenuItem: - if (message.text_length > (int)sizeof(message.text)) { - client.did_misbehave(); - return false; - } - if (message.menu.shortcut_text_length > (int)sizeof(message.menu.shortcut_text)) { - client.did_misbehave(); - return false; - } - post_event(client, make(client_id, message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length), String(message.menu.shortcut_text, message.menu.shortcut_text_length), message.menu.enabled, message.menu.checkable, message.menu.checked)); - break; - case WSAPI_ClientMessage::Type::UpdateMenuItem: - if (message.text_length > (int)sizeof(message.text)) { - client.did_misbehave(); - return false; - } - if (message.menu.shortcut_text_length > (int)sizeof(message.menu.shortcut_text)) { - client.did_misbehave(); - return false; - } - post_event(client, make(client_id, message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length), String(message.menu.shortcut_text, message.menu.shortcut_text_length), message.menu.enabled, message.menu.checkable, message.menu.checked)); - break; - case WSAPI_ClientMessage::Type::AddMenuSeparator: - post_event(client, make(client_id, message.menu.menu_id)); - break; - case WSAPI_ClientMessage::Type::CreateWindow: { - if (message.text_length > (int)sizeof(message.text)) { - client.did_misbehave(); - return false; - } - - auto ws_window_type = WSWindowType::Invalid; - switch (message.window.type) { - case WSAPI_WindowType::Normal: - ws_window_type = WSWindowType::Normal; - break; - case WSAPI_WindowType::Menu: - ws_window_type = WSWindowType::Menu; - break; - case WSAPI_WindowType::WindowSwitcher: - ws_window_type = WSWindowType::WindowSwitcher; - break; - case WSAPI_WindowType::Taskbar: - ws_window_type = WSWindowType::Taskbar; - break; - case WSAPI_WindowType::Tooltip: - ws_window_type = WSWindowType::Tooltip; - break; - case WSAPI_WindowType::Menubar: - ws_window_type = WSWindowType::Menubar; - break; - case WSAPI_WindowType::Launcher: - ws_window_type = WSWindowType::Launcher; - break; - case WSAPI_WindowType::Invalid: - default: - dbgprintf("Unknown WSAPI_WindowType: %d\n", message.window.type); - client.did_misbehave(); - return false; - } - - post_event(client, - make(client_id, - message.window.rect, - String(message.text, message.text_length), - message.window.has_alpha_channel, - message.window.modal, - message.window.resizable, - message.window.fullscreen, - message.window.show_titlebar, - message.window.opacity, - message.window.base_size, - message.window.size_increment, - ws_window_type, - Color::from_rgba(message.window.background_color))); - break; - } - case WSAPI_ClientMessage::Type::DestroyWindow: - post_event(client, make(client_id, message.window_id)); - break; - case WSAPI_ClientMessage::Type::SetWindowTitle: - if (message.text_length > (int)sizeof(message.text)) { - client.did_misbehave(); - return false; - } - post_event(client, make(client_id, message.window_id, String(message.text, message.text_length))); - break; - case WSAPI_ClientMessage::Type::GetWindowTitle: - post_event(client, make(client_id, message.window_id)); - break; - case WSAPI_ClientMessage::Type::SetWindowRect: - post_event(client, make(client_id, message.window_id, message.window.rect)); - break; - case WSAPI_ClientMessage::Type::GetWindowRect: - post_event(client, make(client_id, message.window_id)); - break; - case WSAPI_ClientMessage::Type::SetClipboardContents: - post_event(client, make(client_id, message.clipboard.shared_buffer_id, message.clipboard.contents_size)); - break; - case WSAPI_ClientMessage::Type::GetClipboardContents: - post_event(client, make(client_id)); - break; - case WSAPI_ClientMessage::Type::InvalidateRect: { - auto rects = get_rects(message, extra_data); - if (rects.is_empty()) { - client.did_misbehave(); - return false; - } - post_event(client, make(client_id, message.window_id, rects)); - break; - } - case WSAPI_ClientMessage::Type::DidFinishPainting: { - auto rects = get_rects(message, extra_data); - if (rects.is_empty()) { - client.did_misbehave(); - return false; - } - post_event(client, make(client_id, message.window_id, rects)); - break; - } - case WSAPI_ClientMessage::Type::GetWindowBackingStore: - post_event(client, make(client_id, message.window_id)); - break; - case WSAPI_ClientMessage::Type::SetWindowBackingStore: - post_event(client, make(client_id, message.window_id, message.backing.shared_buffer_id, message.backing.size, message.backing.bpp, message.backing.pitch, message.backing.has_alpha_channel, message.backing.flush_immediately)); - break; - case WSAPI_ClientMessage::Type::SetGlobalCursorTracking: - post_event(client, make(client_id, message.window_id, message.value)); - break; - case WSAPI_ClientMessage::Type::SetWallpaper: - if (message.text_length > (int)sizeof(message.text)) { - client.did_misbehave(); - return false; - } - post_event(client, make(client_id, String(message.text, message.text_length))); - break; - case WSAPI_ClientMessage::Type::GetWallpaper: - post_event(client, make(client_id)); - break; - case WSAPI_ClientMessage::Type::SetWindowOverrideCursor: - post_event(client, make(client_id, message.window_id, (WSStandardCursor)message.cursor.cursor)); - break; - case WSAPI_ClientMessage::SetWindowHasAlphaChannel: - post_event(client, make(client_id, message.window_id, message.value)); - break; - case WSAPI_ClientMessage::Type::WM_SetActiveWindow: - post_event(client, make(client_id, message.wm.client_id, message.wm.window_id)); - break; - case WSAPI_ClientMessage::Type::WM_SetWindowMinimized: - post_event(client, make(client_id, message.wm.client_id, message.wm.window_id, message.wm.minimized)); - break; - case WSAPI_ClientMessage::Type::WM_StartWindowResize: - post_event(client, make(client_id, message.wm.client_id, message.wm.window_id)); - break; - case WSAPI_ClientMessage::Type::WM_PopupWindowMenu: - post_event(client, make(client_id, message.wm.client_id, message.wm.window_id, message.wm.position)); - break; - case WSAPI_ClientMessage::Type::MoveWindowToFront: - post_event(client, make(client_id, message.window_id)); - break; - default: - break; - } - return true; -} - void WSEventLoop::add_file_descriptors_for_select(fd_set& fds, int& max_fd_added) { auto add_fd_to_set = [&max_fd_added](int fd, auto& set) { @@ -348,44 +124,7 @@ void WSEventLoop::process_file_descriptors_after_select(const fd_set& fds) drain_mouse(); WSClientConnection::for_each_client([&](WSClientConnection& client) { if (FD_ISSET(client.fd(), &fds)) - drain_client(client); + client.on_ready_read(); }); } -void WSEventLoop::drain_client(WSClientConnection& client) -{ - unsigned messages_received = 0; - for (;;) { - WSAPI_ClientMessage message; - // FIXME: Don't go one message at a time, that's so much context switching, oof. - ssize_t nread = recv(client.fd(), &message, sizeof(WSAPI_ClientMessage), MSG_DONTWAIT); - if (nread == 0 || (nread == -1 && errno == EAGAIN)) { - if (!messages_received) - post_event(client, make(client.client_id())); - break; - } - if (nread < 0) { - perror("recv"); - ASSERT_NOT_REACHED(); - } - ByteBuffer extra_data; - if (message.extra_size) { - if (message.extra_size >= 32768) { - dbgprintf("message.extra_size is way too large\n"); - return client.did_misbehave(); - } - extra_data = ByteBuffer::create_uninitialized(message.extra_size); - // FIXME: We should allow this to time out. Maybe use a socket timeout? - int extra_nread = read(client.fd(), extra_data.data(), extra_data.size()); - if (extra_nread != (int)message.extra_size) { - dbgprintf("extra_nread(%d) != extra_size(%d)\n", extra_nread, extra_data.size()); - if (extra_nread < 0) - perror("read"); - return client.did_misbehave(); - } - } - if (!on_receive_from_client(client.client_id(), message, move(extra_data))) - return; - ++messages_received; - } -}