diff --git a/Kernel/Makefile b/Kernel/Makefile index db6f6e5217..3f3f73d036 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -66,6 +66,7 @@ WINDOWSERVER_OBJS = \ ../WindowServer/WSMenuBar.o \ ../WindowServer/WSMenu.o \ ../WindowServer/WSMenuItem.o \ + ../WindowServer/WSClientConnection.o \ ../WindowServer/main.o AK_OBJS = \ diff --git a/Kernel/ProcessGUI.cpp b/Kernel/ProcessGUI.cpp index cfdfff3269..4c87cd7146 100644 --- a/Kernel/ProcessGUI.cpp +++ b/Kernel/ProcessGUI.cpp @@ -20,6 +20,7 @@ void Process::destroy_all_windows() { if (!WSMessageLoop::the().running()) return; + dbgprintf("Sending death notification for client_id %d\n", gui_client_id()); WSMessageLoop::the().notify_client_died(gui_client_id()); } diff --git a/WindowServer/WSClientConnection.cpp b/WindowServer/WSClientConnection.cpp new file mode 100644 index 0000000000..ff780e73e3 --- /dev/null +++ b/WindowServer/WSClientConnection.cpp @@ -0,0 +1,316 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Lockable>* s_connections; + + +WSClientConnection* WSClientConnection::from_client_id(int client_id) +{ + if (!s_connections) + return nullptr; + LOCKER(s_connections->lock()); + auto it = s_connections->resource().find(client_id); + if (it == s_connections->resource().end()) + return nullptr; + return (*it).value; +} + +WSClientConnection* WSClientConnection::ensure_for_client_id(int client_id) +{ + if (auto* client = from_client_id(client_id)) + return client; + return new WSClientConnection(client_id); +} + +WSClientConnection::WSClientConnection(int client_id) + : m_client_id(client_id) +{ + if (!s_connections) + s_connections = new Lockable>; + LOCKER(s_connections->lock()); + s_connections->resource().set(client_id, this); + + m_process = ((Process*)m_client_id)->make_weak_ptr(); +} + +WSClientConnection::~WSClientConnection() +{ + LOCKER(s_connections->lock()); + s_connections->resource().remove(m_client_id); +} + +void WSClientConnection::on_message(WSMessage& message) +{ + if (message.is_client_request()) { + handle_client_request(static_cast(message)); + return; + } + + if (message.type() == WSMessage::WM_ClientDisconnected) { + int client_id = static_cast(message).client_id(); + dbgprintf("WSClientConnection: Client disconnected: %d\n", client_id); + delete this; + return; + } +} + +void WSClientConnection::handle_client_request(WSAPIClientRequest& request) +{ + switch (request.type()) { + case WSMessage::APICreateMenubarRequest: { + int menubar_id = m_next_menubar_id++; + auto menubar = make(menubar_id, *WSMessageLoop::process_from_client_id(request.client_id())); + m_menubars.set(menubar_id, move(menubar)); + GUI_ServerMessage response; + response.type = GUI_ServerMessage::Type::DidCreateMenubar; + response.menu.menubar_id = menubar_id; + WSMessageLoop::the().post_message_to_client(request.client_id(), response); + break; + } + case WSMessage::APIDestroyMenubarRequest: { + int menubar_id = static_cast(request).menubar_id(); + auto it = m_menubars.find(menubar_id); + if (it == m_menubars.end()) { + ASSERT_NOT_REACHED(); + // FIXME: Send an error. + return; + } + auto& menubar = *(*it).value; + WSWindowManager::the().close_menubar(menubar); + m_menubars.remove(it); + GUI_ServerMessage response; + response.type = GUI_ServerMessage::Type::DidDestroyMenubar; + response.menu.menubar_id = menubar_id; + WSMessageLoop::the().post_message_to_client(request.client_id(), response); + break; + } + case WSMessage::APICreateMenuRequest: { + int menu_id = m_next_menu_id++; + auto menu = make(*WSMessageLoop::process_from_client_id(request.client_id()), menu_id, static_cast(request).text()); + m_menus.set(menu_id, move(menu)); + GUI_ServerMessage response; + response.type = GUI_ServerMessage::Type::DidCreateMenu; + response.menu.menu_id = menu_id; + WSMessageLoop::the().post_message_to_client(request.client_id(), response); + break; + } + case WSMessage::APIDestroyMenuRequest: { + int menu_id = static_cast(request).menu_id(); + auto it = m_menus.find(menu_id); + if (it == m_menus.end()) { + ASSERT_NOT_REACHED(); + // FIXME: Send an error. + return; + } + auto& menu = *(*it).value; + WSWindowManager::the().close_menu(menu); + m_menus.remove(it); + GUI_ServerMessage response; + response.type = GUI_ServerMessage::Type::DidDestroyMenu; + response.menu.menu_id = menu_id; + WSMessageLoop::the().post_message_to_client(request.client_id(), response); + break; + } + case WSMessage::APISetApplicationMenubarRequest: { + int menubar_id = static_cast(request).menubar_id(); + auto it = m_menubars.find(menubar_id); + if (it == m_menubars.end()) { + ASSERT_NOT_REACHED(); + // FIXME: Send an error. + return; + } + auto& menubar = *(*it).value; + m_app_menubar = menubar.make_weak_ptr(); + WSWindowManager::the().notify_client_changed_app_menubar(*this); + GUI_ServerMessage response; + response.type = GUI_ServerMessage::Type::DidSetApplicationMenubar; + response.menu.menubar_id = menubar_id; + WSMessageLoop::the().post_message_to_client(request.client_id(), response); + break; + } + case WSMessage::APIAddMenuToMenubarRequest: { + int menubar_id = static_cast(request).menubar_id(); + int menu_id = static_cast(request).menu_id(); + auto it = m_menubars.find(menubar_id); + auto jt = m_menus.find(menu_id); + if (it == m_menubars.end() || jt == m_menus.end()) { + ASSERT_NOT_REACHED(); + } + auto& menubar = *(*it).value; + auto& menu = *(*jt).value; + menubar.add_menu(&menu); + GUI_ServerMessage response; + response.type = GUI_ServerMessage::Type::DidAddMenuToMenubar; + response.menu.menubar_id = menubar_id; + response.menu.menu_id = menu_id; + WSMessageLoop::the().post_message_to_client(request.client_id(), response); + break; + } + case WSMessage::APIAddMenuItemRequest: { + int menu_id = static_cast(request).menu_id(); + unsigned identifier = static_cast(request).identifier(); + String text = static_cast(request).text(); + auto it = m_menus.find(menu_id); + if (it == m_menus.end()) { + ASSERT_NOT_REACHED(); + } + auto& menu = *(*it).value; + menu.add_item(make(identifier, move(text))); + GUI_ServerMessage response; + response.type = GUI_ServerMessage::Type::DidAddMenuItem; + response.menu.menu_id = menu_id; + response.menu.identifier = identifier; + WSMessageLoop::the().post_message_to_client(request.client_id(), response); + break; + } + case WSMessage::APIAddMenuSeparatorRequest: { + int menu_id = static_cast(request).menu_id(); + auto it = m_menus.find(menu_id); + if (it == m_menus.end()) { + ASSERT_NOT_REACHED(); + } + auto& menu = *(*it).value; + menu.add_item(make(WSMenuItem::Separator)); + GUI_ServerMessage response; + response.type = GUI_ServerMessage::Type::DidAddMenuSeparator; + response.menu.menu_id = menu_id; + WSMessageLoop::the().post_message_to_client(request.client_id(), response); + break; + } + case WSMessage::APISetWindowTitleRequest: { + int window_id = static_cast(request).window_id(); + auto it = m_windows.find(window_id); + if (it == m_windows.end()) { + ASSERT_NOT_REACHED(); + } + auto& window = *(*it).value; + window.set_title(static_cast(request).title()); + break; + } + case WSMessage::APIGetWindowTitleRequest: { + int window_id = static_cast(request).window_id(); + auto it = m_windows.find(window_id); + if (it == m_windows.end()) { + ASSERT_NOT_REACHED(); + } + auto& window = *(*it).value; + GUI_ServerMessage response; + response.type = GUI_ServerMessage::Type::DidGetWindowTitle; + response.window_id = window.window_id(); + ASSERT(window.title().length() < sizeof(response.text)); + strcpy(response.text, window.title().characters()); + response.text_length = window.title().length(); + WSMessageLoop::the().post_message_to_client(request.client_id(), response); + break; + } + case WSMessage::APISetWindowRectRequest: { + int window_id = static_cast(request).window_id(); + auto it = m_windows.find(window_id); + if (it == m_windows.end()) { + ASSERT_NOT_REACHED(); + } + auto& window = *(*it).value; + window.set_rect(static_cast(request).rect()); + break; + } + case WSMessage::APIGetWindowRectRequest: { + int window_id = static_cast(request).window_id(); + auto it = m_windows.find(window_id); + if (it == m_windows.end()) { + ASSERT_NOT_REACHED(); + } + auto& window = *(*it).value; + GUI_ServerMessage response; + response.type = GUI_ServerMessage::Type::DidGetWindowRect; + response.window_id = window.window_id(); + response.window.rect = window.rect(); + WSMessageLoop::the().post_message_to_client(request.client_id(), response); + break; + } + case WSMessage::APICreateWindowRequest: { + int window_id = m_next_window_id++; + auto window = make(request.client_id(), window_id); + window->set_title(static_cast(request).title()); + window->set_rect(static_cast(request).rect()); + m_windows.set(window_id, move(window)); + GUI_ServerMessage response; + response.type = GUI_ServerMessage::Type::DidCreateWindow; + response.window_id = window_id; + WSMessageLoop::the().post_message_to_client(request.client_id(), response); + break; + } + case WSMessage::APIDestroyWindowRequest: { + int window_id = static_cast(request).window_id(); + auto it = m_windows.find(window_id); + if (it == m_windows.end()) { + ASSERT_NOT_REACHED(); + } + auto& window = *(*it).value; + WSWindowManager::the().invalidate(window); + m_windows.remove(it); + break; + } + case WSMessage::APIInvalidateRectRequest: { + int window_id = static_cast(request).window_id(); + auto it = m_windows.find(window_id); + if (it == m_windows.end()) { + ASSERT_NOT_REACHED(); + } + GUI_ServerMessage response; + response.type = GUI_ServerMessage::Type::Paint; + response.window_id = window_id; + response.paint.rect = static_cast(request).rect(); + WSMessageLoop::the().post_message_to_client(request.client_id(), response); + break; + } + case WSMessage::APIDidFinishPaintingNotification: { + int window_id = static_cast(request).window_id(); + auto it = m_windows.find(window_id); + if (it == m_windows.end()) { + ASSERT_NOT_REACHED(); + } + auto& window = *(*it).value; + WSWindowManager::the().invalidate(window, static_cast(request).rect()); + break; + } + case WSMessage::APIGetWindowBackingStoreRequest: { + int window_id = static_cast(request).window_id(); + auto it = m_windows.find(window_id); + if (it == m_windows.end()) { + ASSERT_NOT_REACHED(); + } + auto& window = *(*it).value; + auto* backing_store = window.backing(); + + // FIXME: It shouldn't work this way! + backing_store->retain(); + + GUI_ServerMessage response; + response.type = GUI_ServerMessage::Type::DidGetWindowBackingStore; + response.window_id = window_id; + response.backing.backing_store_id = backing_store; + response.backing.bpp = sizeof(RGBA32); + response.backing.pitch = backing_store->pitch(); + response.backing.size = backing_store->size(); + response.backing.pixels = reinterpret_cast(backing_store->client_region()->laddr().as_ptr()); + WSMessageLoop::the().post_message_to_client(request.client_id(), response); + break; + } + case WSMessage::APIReleaseWindowBackingStoreRequest: { + int backing_store_id = static_cast(request).backing_store_id(); + // FIXME: It shouldn't work this way! + auto* backing_store = (GraphicsBitmap*)backing_store_id; + backing_store->release(); + break; + } + default: + break; + } +} diff --git a/WindowServer/WSClientConnection.h b/WindowServer/WSClientConnection.h new file mode 100644 index 0000000000..529447c469 --- /dev/null +++ b/WindowServer/WSClientConnection.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include + +class WSWindow; +class WSMenu; +class WSMenuBar; +class WSAPIClientRequest; + +// FIXME: Remove. +class Process; + +class WSClientConnection final : public WSMessageReceiver { +public: + explicit WSClientConnection(int client_id); + virtual ~WSClientConnection() override; + + static WSClientConnection* from_client_id(int client_id); + static WSClientConnection* ensure_for_client_id(int client_id); + + // FIXME: Remove. + Process* process() { return m_process.ptr(); } + + int client_id() const { return m_client_id; } + WSMenuBar* app_menubar() { return m_app_menubar.ptr(); } + +private: + virtual void on_message(WSMessage&) override; + + void handle_client_request(WSAPIClientRequest&); + + int m_client_id { 0 }; + + HashMap> m_windows; + HashMap> m_menubars; + HashMap> m_menus; + WeakPtr m_app_menubar; + + int m_next_menubar_id { 10000 }; + int m_next_menu_id { 20000 }; + int m_next_window_id { 1982 }; + + // FIXME: Remove. + WeakPtr m_process; +}; diff --git a/WindowServer/WSMenu.h b/WindowServer/WSMenu.h index bd15d02e59..363f92b52c 100644 --- a/WindowServer/WSMenu.h +++ b/WindowServer/WSMenu.h @@ -12,7 +12,7 @@ class WSWindow; class Font; class Process; -class WSMenu { +class WSMenu : public Weakable { public: WSMenu(Process&, int menu_id, String&& name); ~WSMenu(); diff --git a/WindowServer/WSMenuBar.h b/WindowServer/WSMenuBar.h index 2aec358889..285aa8d067 100644 --- a/WindowServer/WSMenuBar.h +++ b/WindowServer/WSMenuBar.h @@ -2,11 +2,12 @@ #include "WSMenu.h" #include +#include #include class Process; -class WSMenuBar { +class WSMenuBar : public Weakable { public: WSMenuBar(int menubar_id, Process&); ~WSMenuBar(); diff --git a/WindowServer/WSMessageLoop.cpp b/WindowServer/WSMessageLoop.cpp index 4493e8e382..40b3cb1a16 100644 --- a/WindowServer/WSMessageLoop.cpp +++ b/WindowServer/WSMessageLoop.cpp @@ -3,6 +3,7 @@ #include "WSMessageReceiver.h" #include "WSWindowManager.h" #include "WSScreen.h" +#include #include "PS2MouseDevice.h" #include #include @@ -267,7 +268,10 @@ void WSMessageLoop::drain_keyboard() void WSMessageLoop::notify_client_died(int client_id) { LOCKER(m_lock); - post_message(&WSWindowManager::the(), make(client_id)); + auto* client = WSClientConnection::from_client_id(client_id); + if (!client) + return; + post_message(client, make(client_id)); } ssize_t WSMessageLoop::on_receive_from_client(int client_id, const byte* data, size_t size) @@ -277,67 +281,70 @@ ssize_t WSMessageLoop::on_receive_from_client(int client_id, const byte* data, s Scheduler::yield(); LOCKER(m_lock); + + WSClientConnection* client = WSClientConnection::ensure_for_client_id(client_id); + ASSERT(size == sizeof(GUI_ClientMessage)); auto& message = *reinterpret_cast(data); switch (message.type) { case GUI_ClientMessage::Type::CreateMenubar: - post_message(&WSWindowManager::the(), make(client_id)); + post_message(client, make(client_id)); break; case GUI_ClientMessage::Type::DestroyMenubar: - post_message(&WSWindowManager::the(), make(client_id, message.menu.menubar_id)); + post_message(client, make(client_id, message.menu.menubar_id)); break; case GUI_ClientMessage::Type::SetApplicationMenubar: - post_message(&WSWindowManager::the(), make(client_id, message.menu.menubar_id)); + post_message(client, make(client_id, message.menu.menubar_id)); break; case GUI_ClientMessage::Type::AddMenuToMenubar: - post_message(&WSWindowManager::the(), make(client_id, message.menu.menubar_id, message.menu.menu_id)); + post_message(client, make(client_id, message.menu.menubar_id, message.menu.menu_id)); break; case GUI_ClientMessage::Type::CreateMenu: ASSERT(message.text_length < sizeof(message.text)); - post_message(&WSWindowManager::the(), make(client_id, String(message.text, message.text_length))); + post_message(client, make(client_id, String(message.text, message.text_length))); break; case GUI_ClientMessage::Type::DestroyMenu: - post_message(&WSWindowManager::the(), make(client_id, message.menu.menu_id)); + post_message(client, make(client_id, message.menu.menu_id)); break; case GUI_ClientMessage::Type::AddMenuItem: ASSERT(message.text_length < sizeof(message.text)); - post_message(&WSWindowManager::the(), make(client_id, message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length))); + post_message(client, make(client_id, message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length))); break; case GUI_ClientMessage::Type::CreateWindow: ASSERT(message.text_length < sizeof(message.text)); - post_message(&WSWindowManager::the(), make(client_id, message.window.rect, String(message.text, message.text_length))); + post_message(client, make(client_id, message.window.rect, String(message.text, message.text_length))); break; case GUI_ClientMessage::Type::DestroyWindow: - post_message(&WSWindowManager::the(), make(client_id, message.window_id)); + post_message(client, make(client_id, message.window_id)); break; case GUI_ClientMessage::Type::SetWindowTitle: ASSERT(message.text_length < sizeof(message.text)); - post_message(&WSWindowManager::the(), make(client_id, message.window_id, String(message.text, message.text_length))); + post_message(client, make(client_id, message.window_id, String(message.text, message.text_length))); break; case GUI_ClientMessage::Type::GetWindowTitle: ASSERT(message.text_length < sizeof(message.text)); - post_message(&WSWindowManager::the(), make(client_id, message.window_id)); + post_message(client, make(client_id, message.window_id)); break; case GUI_ClientMessage::Type::SetWindowRect: - post_message(&WSWindowManager::the(), make(client_id, message.window_id, message.window.rect)); + post_message(client, make(client_id, message.window_id, message.window.rect)); break; case GUI_ClientMessage::Type::GetWindowRect: - post_message(&WSWindowManager::the(), make(client_id, message.window_id)); + post_message(client, make(client_id, message.window_id)); break; case GUI_ClientMessage::Type::InvalidateRect: - post_message(&WSWindowManager::the(), make(client_id, message.window_id, message.window.rect)); + post_message(client, make(client_id, message.window_id, message.window.rect)); break; case GUI_ClientMessage::Type::DidFinishPainting: - post_message(&WSWindowManager::the(), make(client_id, message.window_id, message.window.rect)); + post_message(client, make(client_id, message.window_id, message.window.rect)); break; case GUI_ClientMessage::Type::GetWindowBackingStore: - post_message(&WSWindowManager::the(), make(client_id, message.window_id)); + post_message(client, make(client_id, message.window_id)); break; case GUI_ClientMessage::Type::ReleaseWindowBackingStore: - post_message(&WSWindowManager::the(), make(client_id, (int)message.backing.backing_store_id)); + post_message(client, make(client_id, (int)message.backing.backing_store_id)); break; case GUI_ClientMessage::Type::SetGlobalCursorTracking: - post_message(&WSWindowManager::the(), make(client_id, message.value)); + post_message(client, make(client_id, message.value)); break; } server_process().request_wakeup(); diff --git a/WindowServer/WSWindow.cpp b/WindowServer/WSWindow.cpp index 07c933c522..bea91954dd 100644 --- a/WindowServer/WSWindow.cpp +++ b/WindowServer/WSWindow.cpp @@ -3,6 +3,7 @@ #include "WSMessage.h" #include "WSMessageLoop.h" #include "Process.h" +#include WSWindow::WSWindow(WSMenu& menu) : m_lock("WSWindow (menu)") @@ -12,12 +13,11 @@ WSWindow::WSWindow(WSMenu& menu) WSWindowManager::the().add_window(*this); } -WSWindow::WSWindow(Process& process, int window_id) +WSWindow::WSWindow(int client_id, int window_id) : m_lock("WSWindow (normal)") + , m_client_id(client_id) , m_type(WSWindowType::Normal) - , m_process(&process) , m_window_id(window_id) - , m_pid(process.pid()) { WSWindowManager::the().add_window(*this); } @@ -44,15 +44,21 @@ void WSWindow::set_rect(const Rect& rect) Rect old_rect; { WSWindowLocker locker(*this); - if (!m_process && !m_menu) + + Process* process = nullptr; + auto* client = WSClientConnection::from_client_id(m_client_id); + if (client) + process = client->process(); + + if (!process && !m_menu) return; if (m_rect == rect) return; old_rect = m_rect; m_rect = rect; if (!m_backing || old_rect.size() != rect.size()) { - if (m_process) - m_backing = GraphicsBitmap::create(*m_process, m_rect.size()); + if (process) + m_backing = GraphicsBitmap::create(*process, m_rect.size()); if (m_menu) m_backing = GraphicsBitmap::create_kernel_only(m_rect.size()); } @@ -135,19 +141,15 @@ void WSWindow::on_message(WSMessage& message) { WSWindowLocker window_locker(*this); - if (!m_process) - return; - LOCKER(m_process->gui_events_lock()); - m_process->gui_events().append(move(gui_event)); + if (auto* client = WSClientConnection::from_client_id(m_client_id)) { + if (auto* process = client->process()) { + LOCKER(process->gui_events_lock()); + process->gui_events().append(move(gui_event)); + } + } } } -void WSWindow::notify_process_died(Badge) -{ - WSWindowLocker locker(*this); - m_process = nullptr; -} - void WSWindow::set_global_cursor_tracking_enabled(bool enabled) { dbgprintf("WSWindow{%p} global_cursor_tracking <- %u\n", enabled); diff --git a/WindowServer/WSWindow.h b/WindowServer/WSWindow.h index db5e148a77..ff8c7de012 100644 --- a/WindowServer/WSWindow.h +++ b/WindowServer/WSWindow.h @@ -6,21 +6,19 @@ #include #include #include -#include #include "WSMessageReceiver.h" #include -class Process; class WSMenu; class WSWindow final : public WSMessageReceiver, public InlineLinkedListNode { friend class WSWindowLocker; public: - WSWindow(Process&, int window_id); + WSWindow(int client_id, int window_id); explicit WSWindow(WSMenu&); virtual ~WSWindow() override; - const Process* process() const { return m_process; } + int client_id() const { return m_client_id; } WSWindowType type() const { return m_type; } int window_id() const { return m_window_id; } @@ -59,13 +57,9 @@ public: GraphicsBitmap* backing() { return m_backing.ptr(); } - pid_t pid() const { return m_pid; } - void set_global_cursor_tracking_enabled(bool); bool global_cursor_tracking() const { return m_global_cursor_tracking_enabled; } - void notify_process_died(Badge); - // For InlineLinkedList. // FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that. WSWindow* m_next { nullptr }; @@ -73,6 +67,7 @@ public: private: Lock m_lock; + int m_client_id { 0 }; String m_title; Rect m_rect; WSWindowType m_type { WSWindowType::Normal }; @@ -83,9 +78,7 @@ private: WSMenu* m_menu { nullptr }; RetainPtr m_backing; - Process* m_process { nullptr }; int m_window_id { -1 }; - pid_t m_pid { -1 }; }; class WSWindowLocker { diff --git a/WindowServer/WSWindowManager.cpp b/WindowServer/WSWindowManager.cpp index eb2196f7f9..ca46ed2323 100644 --- a/WindowServer/WSWindowManager.cpp +++ b/WindowServer/WSWindowManager.cpp @@ -14,6 +14,7 @@ #include "WSMenu.h" #include "WSMenuBar.h" #include "WSMenuItem.h" +#include #include //#define DEBUG_COUNTERS @@ -239,7 +240,10 @@ int WSWindowManager::menubar_menu_margin() const void WSWindowManager::set_current_menubar(WSMenuBar* menubar) { LOCKER(m_lock); - m_current_menubar = menubar; + if (menubar) + m_current_menubar = menubar->make_weak_ptr(); + else + m_current_menubar = nullptr; dbgprintf("[WM] Current menubar is now %p\n", menubar); Point next_menu_location { menubar_menu_margin() / 2, 3 }; for_each_active_menubar_menu([&] (WSMenu& menu) { @@ -395,10 +399,10 @@ void WSWindowManager::handle_menu_mouse_event(WSMenu& menu, WSMouseEvent& event) { bool is_hover_with_any_menu_open = event.type() == WSMouseEvent::MouseMove && m_current_menu; bool is_mousedown_with_left_button = event.type() == WSMouseEvent::MouseDown && event.button() == MouseButton::Left; - bool should_open_menu = &menu != m_current_menu && (is_hover_with_any_menu_open || is_mousedown_with_left_button); + bool should_open_menu = &menu != current_menu() && (is_hover_with_any_menu_open || is_mousedown_with_left_button); if (should_open_menu) { - if (m_current_menu == &menu) + if (current_menu() == &menu) return; close_current_menu(); if (!menu.is_empty()) { @@ -406,7 +410,7 @@ void WSWindowManager::handle_menu_mouse_event(WSMenu& menu, WSMouseEvent& event) menu_window.move_to({ menu.rect_in_menubar().x(), menu.rect_in_menubar().bottom() }); menu_window.set_visible(true); } - m_current_menu = &menu; + m_current_menu = menu.make_weak_ptr(); return; } if (event.type() == WSMouseEvent::MouseDown && event.button() == MouseButton::Left) { @@ -422,7 +426,7 @@ void WSWindowManager::close_current_menu() m_current_menu = nullptr; } -void WSWindowManager::handle_menubar_mouse_event(WSMenuBar&, WSMouseEvent& event) +void WSWindowManager::handle_menubar_mouse_event(WSMouseEvent& event) { for_each_active_menubar_menu([&] (WSMenu& menu) { if (menu.rect_in_menubar().contains(event.position())) { @@ -499,7 +503,7 @@ void WSWindowManager::process_mouse_event(WSMouseEvent& event) } if (menubar_rect().contains(event.position())) { - handle_menubar_mouse_event(*m_current_menubar, event); + handle_menubar_mouse_event(event); return; } @@ -684,7 +688,7 @@ void WSWindowManager::draw_menubar() m_back_painter->draw_line({ 0, menubar_rect().bottom() }, { menubar_rect().right(), menubar_rect().bottom() }, Color::White); for_each_active_menubar_menu([&] (WSMenu& menu) { Color text_color = Color::Black; - if (&menu == m_current_menu) { + if (&menu == current_menu()) { m_back_painter->fill_rect(menu.rect_in_menubar(), menu_selection_color()); text_color = Color::White; } @@ -733,284 +737,6 @@ void WSWindowManager::on_message(WSMessage& message) compose(); return; } - - if (message.is_client_request()) { - handle_client_request(static_cast(message)); - return; - } - - if (message.type() == WSMessage::WM_ClientDisconnected) { - int client_id = static_cast(message).client_id(); - dbgprintf("[WM] Client disconnected: %d\n", client_id); - - destroy_all_menus(*WSMessageLoop::process_from_client_id(client_id)); - Vector windows_belonging_to_client; - for (auto& it : m_windows_by_id) { - if (it.value->process()->gui_client_id() == client_id) - windows_belonging_to_client.append(it.value->window_id()); - } - for (int window_id : windows_belonging_to_client) { - m_windows_by_id.remove(window_id); - } - return; - } -} - -void WSWindowManager::handle_client_request(WSAPIClientRequest& request) -{ - switch (request.type()) { - case WSMessage::APICreateMenubarRequest: { - int menubar_id = m_next_menubar_id++; - auto menubar = make(menubar_id, *WSMessageLoop::process_from_client_id(request.client_id())); - m_menubars.set(menubar_id, move(menubar)); - GUI_ServerMessage response; - response.type = GUI_ServerMessage::Type::DidCreateMenubar; - response.menu.menubar_id = menubar_id; - WSMessageLoop::the().post_message_to_client(request.client_id(), response); - break; - } - case WSMessage::APIDestroyMenubarRequest: { - int menubar_id = static_cast(request).menubar_id(); - auto it = m_menubars.find(menubar_id); - if (it == m_menubars.end()) { - ASSERT_NOT_REACHED(); - // FIXME: Send an error. - return; - } - auto& menubar = *(*it).value; - if (&menubar == m_current_menubar) - set_current_menubar(nullptr); - m_menubars.remove(it); - GUI_ServerMessage response; - response.type = GUI_ServerMessage::Type::DidDestroyMenubar; - response.menu.menubar_id = menubar_id; - WSMessageLoop::the().post_message_to_client(request.client_id(), response); - break; - } - case WSMessage::APICreateMenuRequest: { - int menu_id = m_next_menu_id++; - auto menu = make(*WSMessageLoop::process_from_client_id(request.client_id()), menu_id, static_cast(request).text()); - m_menus.set(menu_id, move(menu)); - GUI_ServerMessage response; - response.type = GUI_ServerMessage::Type::DidCreateMenu; - response.menu.menu_id = menu_id; - WSMessageLoop::the().post_message_to_client(request.client_id(), response); - break; - } - case WSMessage::APIDestroyMenuRequest: { - int menu_id = static_cast(request).menu_id(); - auto it = m_menus.find(menu_id); - if (it == m_menus.end()) { - ASSERT_NOT_REACHED(); - // FIXME: Send an error. - return; - } - auto& menu = *(*it).value; - close_menu(menu); - m_menus.remove(it); - GUI_ServerMessage response; - response.type = GUI_ServerMessage::Type::DidDestroyMenu; - response.menu.menu_id = menu_id; - WSMessageLoop::the().post_message_to_client(request.client_id(), response); - break; - } - case WSMessage::APISetApplicationMenubarRequest: { - int menubar_id = static_cast(request).menubar_id(); - auto it = m_menubars.find(menubar_id); - if (it == m_menubars.end()) { - ASSERT_NOT_REACHED(); - // FIXME: Send an error. - return; - } - auto& menubar = *(*it).value; - m_app_menubars.set(request.client_id(), &menubar); - if (active_client_id() == request.client_id()) - set_current_menubar(&menubar); - invalidate(); - GUI_ServerMessage response; - response.type = GUI_ServerMessage::Type::DidSetApplicationMenubar; - response.menu.menubar_id = menubar_id; - WSMessageLoop::the().post_message_to_client(request.client_id(), response); - break; - } - case WSMessage::APIAddMenuToMenubarRequest: { - int menubar_id = static_cast(request).menubar_id(); - int menu_id = static_cast(request).menu_id(); - auto it = m_menubars.find(menubar_id); - auto jt = m_menus.find(menu_id); - if (it == m_menubars.end() || jt == m_menus.end()) { - ASSERT_NOT_REACHED(); - } - auto& menubar = *(*it).value; - auto& menu = *(*jt).value; - menubar.add_menu(&menu); - GUI_ServerMessage response; - response.type = GUI_ServerMessage::Type::DidAddMenuToMenubar; - response.menu.menubar_id = menubar_id; - response.menu.menu_id = menu_id; - WSMessageLoop::the().post_message_to_client(request.client_id(), response); - break; - } - case WSMessage::APIAddMenuItemRequest: { - int menu_id = static_cast(request).menu_id(); - unsigned identifier = static_cast(request).identifier(); - String text = static_cast(request).text(); - auto it = m_menus.find(menu_id); - if (it == m_menus.end()) { - ASSERT_NOT_REACHED(); - } - auto& menu = *(*it).value; - menu.add_item(make(identifier, move(text))); - GUI_ServerMessage response; - response.type = GUI_ServerMessage::Type::DidAddMenuItem; - response.menu.menu_id = menu_id; - response.menu.identifier = identifier; - WSMessageLoop::the().post_message_to_client(request.client_id(), response); - break; - } - case WSMessage::APIAddMenuSeparatorRequest: { - int menu_id = static_cast(request).menu_id(); - auto it = m_menus.find(menu_id); - if (it == m_menus.end()) { - ASSERT_NOT_REACHED(); - } - auto& menu = *(*it).value; - menu.add_item(make(WSMenuItem::Separator)); - GUI_ServerMessage response; - response.type = GUI_ServerMessage::Type::DidAddMenuSeparator; - response.menu.menu_id = menu_id; - WSMessageLoop::the().post_message_to_client(request.client_id(), response); - break; - } - case WSMessage::APISetWindowTitleRequest: { - int window_id = static_cast(request).window_id(); - auto it = m_windows_by_id.find(window_id); - if (it == m_windows_by_id.end()) { - ASSERT_NOT_REACHED(); - } - auto& window = *(*it).value; - window.set_title(static_cast(request).title()); - break; - } - case WSMessage::APIGetWindowTitleRequest: { - int window_id = static_cast(request).window_id(); - auto it = m_windows_by_id.find(window_id); - if (it == m_windows_by_id.end()) { - ASSERT_NOT_REACHED(); - } - auto& window = *(*it).value; - GUI_ServerMessage response; - response.type = GUI_ServerMessage::Type::DidGetWindowTitle; - response.window_id = window.window_id(); - ASSERT(window.title().length() < sizeof(response.text)); - strcpy(response.text, window.title().characters()); - response.text_length = window.title().length(); - WSMessageLoop::the().post_message_to_client(request.client_id(), response); - break; - } - case WSMessage::APISetWindowRectRequest: { - int window_id = static_cast(request).window_id(); - auto it = m_windows_by_id.find(window_id); - if (it == m_windows_by_id.end()) { - ASSERT_NOT_REACHED(); - } - auto& window = *(*it).value; - window.set_rect(static_cast(request).rect()); - break; - } - case WSMessage::APIGetWindowRectRequest: { - int window_id = static_cast(request).window_id(); - auto it = m_windows_by_id.find(window_id); - if (it == m_windows_by_id.end()) { - ASSERT_NOT_REACHED(); - } - auto& window = *(*it).value; - GUI_ServerMessage response; - response.type = GUI_ServerMessage::Type::DidGetWindowRect; - response.window_id = window.window_id(); - response.window.rect = window.rect(); - WSMessageLoop::the().post_message_to_client(request.client_id(), response); - break; - } - case WSMessage::APICreateWindowRequest: { - int window_id = m_next_window_id++; - auto window = make(*WSMessageLoop::process_from_client_id(request.client_id()), window_id); - window->set_title(static_cast(request).title()); - window->set_rect(static_cast(request).rect()); - m_windows_by_id.set(window_id, move(window)); - GUI_ServerMessage response; - response.type = GUI_ServerMessage::Type::DidCreateWindow; - response.window_id = window_id; - WSMessageLoop::the().post_message_to_client(request.client_id(), response); - break; - } - case WSMessage::APIDestroyWindowRequest: { - int window_id = static_cast(request).window_id(); - auto it = m_windows_by_id.find(window_id); - if (it == m_windows_by_id.end()) { - ASSERT_NOT_REACHED(); - } - auto& window = *(*it).value; - invalidate(window); - m_windows_by_id.remove(it); - break; - } - case WSMessage::APIInvalidateRectRequest: { - int window_id = static_cast(request).window_id(); - auto it = m_windows_by_id.find(window_id); - if (it == m_windows_by_id.end()) { - ASSERT_NOT_REACHED(); - } - GUI_ServerMessage response; - response.type = GUI_ServerMessage::Type::Paint; - response.window_id = window_id; - response.paint.rect = static_cast(request).rect(); - WSMessageLoop::the().post_message_to_client(request.client_id(), response); - break; - } - case WSMessage::APIDidFinishPaintingNotification: { - int window_id = static_cast(request).window_id(); - auto it = m_windows_by_id.find(window_id); - if (it == m_windows_by_id.end()) { - ASSERT_NOT_REACHED(); - } - auto& window = *(*it).value; - invalidate(window, static_cast(request).rect()); - break; - } - case WSMessage::APIGetWindowBackingStoreRequest: { - int window_id = static_cast(request).window_id(); - auto it = m_windows_by_id.find(window_id); - if (it == m_windows_by_id.end()) { - ASSERT_NOT_REACHED(); - } - auto& window = *(*it).value; - auto* backing_store = window.backing(); - - // FIXME: It shouldn't work this way! - backing_store->retain(); - - GUI_ServerMessage response; - response.type = GUI_ServerMessage::Type::DidGetWindowBackingStore; - response.window_id = window_id; - response.backing.backing_store_id = backing_store; - response.backing.bpp = sizeof(RGBA32); - response.backing.pitch = backing_store->pitch(); - response.backing.size = backing_store->size(); - response.backing.pixels = reinterpret_cast(backing_store->client_region()->laddr().as_ptr()); - WSMessageLoop::the().post_message_to_client(request.client_id(), response); - break; - } - case WSMessage::APIReleaseWindowBackingStoreRequest: { - int backing_store_id = static_cast(request).backing_store_id(); - // FIXME: It shouldn't work this way! - auto* backing_store = (GraphicsBitmap*)backing_store_id; - backing_store->release(); - break; - } - default: - break; - } } void WSWindowManager::set_active_window(WSWindow* window) @@ -1028,15 +754,10 @@ void WSWindowManager::set_active_window(WSWindow* window) WSMessageLoop::the().post_message(m_active_window.ptr(), make(WSMessage::WindowActivated)); invalidate(*m_active_window); - ASSERT(window->process()); - auto it = m_app_menubars.find(window->process()->gui_client_id()); - if (it != m_app_menubars.end()) { - auto* menubar = (*it).value; - if (menubar != m_current_menubar) - set_current_menubar(menubar); - } else { - set_current_menubar(nullptr); - } + int client_id = window->client_id(); + auto* client = WSClientConnection::from_client_id(client_id); + ASSERT(client); + set_current_menubar(client->app_menubar()); } } @@ -1119,44 +840,27 @@ void WSWindowManager::flush(const Rect& a_rect) void WSWindowManager::close_menu(WSMenu& menu) { LOCKER(m_lock); - if (m_current_menu == &menu) + if (current_menu() == &menu) close_current_menu(); } +void WSWindowManager::close_menubar(WSMenuBar& menubar) +{ + LOCKER(m_lock); + if (current_menubar() == &menubar) + set_current_menubar(nullptr); +} + int WSWindowManager::active_client_id() const { if (m_active_window) - return m_active_window->process()->gui_client_id(); + return m_active_window->client_id(); return 0; } -void WSWindowManager::destroy_all_menus(Process& process) +void WSWindowManager::notify_client_changed_app_menubar(WSClientConnection& client) { - LOCKER(m_lock); - Vector menu_ids; - bool should_close_current_menu = false; - for (auto& it : m_menus) { - if (it.value->process() == &process) - menu_ids.append(it.value->menu_id()); - if (m_current_menu == it.value.ptr()) - should_close_current_menu = true; - } - if (should_close_current_menu) - close_current_menu(); - for (int menu_id : menu_ids) - m_menus.remove(menu_id); - - Vector menubar_ids; - bool should_close_current_menubar = false; - for (auto& it : m_menubars) { - if (it.value->process() == &process) - menubar_ids.append(it.value->menubar_id()); - if (m_current_menubar == it.value.ptr()) - should_close_current_menubar = true; - } - if (should_close_current_menubar) - set_current_menubar(nullptr); - for (int menubar_id : menubar_ids) - m_menubars.remove(menubar_id); - m_app_menubars.remove(process.gui_client_id()); + if (active_client_id() == client.client_id()) + set_current_menubar(client.app_menubar()); + invalidate(); } diff --git a/WindowServer/WSWindowManager.h b/WindowServer/WSWindowManager.h index 707f82dc85..d27a98b18e 100644 --- a/WindowServer/WSWindowManager.h +++ b/WindowServer/WSWindowManager.h @@ -18,6 +18,7 @@ class WSMenuBar; class WSMouseEvent; class WSClientWantsToPaintMessage; class WSWindow; +class WSClientConnection; class CharacterBitmap; class GraphicsBitmap; @@ -31,6 +32,7 @@ public: void notify_title_changed(WSWindow&); void notify_rect_changed(WSWindow&, const Rect& oldRect, const Rect& newRect); + void notify_client_changed_app_menubar(WSClientConnection&); WSWindow* active_window() { return m_active_window.ptr(); } int active_client_id() const; @@ -42,9 +44,9 @@ public: void draw_menubar(); Rect menubar_rect() const; - WSMenuBar* current_menubar() { return m_current_menubar; } + WSMenuBar* current_menubar() { return m_current_menubar.ptr(); } void set_current_menubar(WSMenuBar*); - WSMenu* current_menu() { return m_current_menu; } + WSMenu* current_menu() { return m_current_menu.ptr(); } void set_current_menu(WSMenu*); void invalidate(const WSWindow&); @@ -57,6 +59,7 @@ public: const Font& font() const { return *m_font; } void close_menu(WSMenu&); + void close_menubar(WSMenuBar&); Color menu_selection_color() const { return m_menu_selection_color; } int menubar_menu_margin() const; @@ -70,7 +73,7 @@ private: void process_mouse_event(WSMouseEvent&); void handle_menu_mouse_event(WSMenu&, WSMouseEvent&); - void handle_menubar_mouse_event(WSMenuBar&, WSMouseEvent&); + void handle_menubar_mouse_event(WSMouseEvent&); void handle_titlebar_mouse_event(WSWindow&, WSMouseEvent&); void handle_close_button_mouse_event(WSWindow&, WSMouseEvent&); void handle_client_request(WSAPIClientRequest&); @@ -145,15 +148,8 @@ private: Lockable m_flash_flush; bool m_buffers_are_flipped { false }; - int m_next_menubar_id { 100 }; - int m_next_menu_id { 100 }; - int m_next_window_id { 1982 }; - OwnPtr m_system_menu; Color m_menu_selection_color; - WSMenuBar* m_current_menubar { nullptr }; - WSMenu* m_current_menu { nullptr }; - HashMap> m_menubars; - HashMap> m_menus; - HashMap m_app_menubars; + WeakPtr m_current_menubar; + WeakPtr m_current_menu; };