1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-23 14:07:42 +00:00

WindowServer: Add WSClientConnection class to manage an individual client.

This makes both object lifetimes and object ID's a lot easier to understand.
This commit is contained in:
Andreas Kling 2019-02-14 08:22:47 +01:00
parent f529b845ec
commit aa7947c889
11 changed files with 452 additions and 383 deletions

View file

@ -66,6 +66,7 @@ WINDOWSERVER_OBJS = \
../WindowServer/WSMenuBar.o \ ../WindowServer/WSMenuBar.o \
../WindowServer/WSMenu.o \ ../WindowServer/WSMenu.o \
../WindowServer/WSMenuItem.o \ ../WindowServer/WSMenuItem.o \
../WindowServer/WSClientConnection.o \
../WindowServer/main.o ../WindowServer/main.o
AK_OBJS = \ AK_OBJS = \

View file

@ -20,6 +20,7 @@ void Process::destroy_all_windows()
{ {
if (!WSMessageLoop::the().running()) if (!WSMessageLoop::the().running())
return; return;
dbgprintf("Sending death notification for client_id %d\n", gui_client_id());
WSMessageLoop::the().notify_client_died(gui_client_id()); WSMessageLoop::the().notify_client_died(gui_client_id());
} }

View file

@ -0,0 +1,316 @@
#include <WindowServer/WSClientConnection.h>
#include <WindowServer/WSMessageLoop.h>
#include <WindowServer/WSMenuBar.h>
#include <WindowServer/WSMenu.h>
#include <WindowServer/WSMenuItem.h>
#include <WindowServer/WSWindow.h>
#include <WindowServer/WSWindowManager.h>
#include <Kernel/GUITypes.h>
#include <Kernel/MemoryManager.h>
Lockable<HashMap<int, WSClientConnection*>>* 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<HashMap<int, WSClientConnection*>>;
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<WSAPIClientRequest&>(message));
return;
}
if (message.type() == WSMessage::WM_ClientDisconnected) {
int client_id = static_cast<WSClientDisconnectedNotification&>(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<WSMenuBar>(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<WSAPIDestroyMenubarRequest&>(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<WSMenu>(*WSMessageLoop::process_from_client_id(request.client_id()), menu_id, static_cast<WSAPICreateMenuRequest&>(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<WSAPIDestroyMenuRequest&>(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<WSAPISetApplicationMenubarRequest&>(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<WSAPIAddMenuToMenubarRequest&>(request).menubar_id();
int menu_id = static_cast<WSAPIAddMenuToMenubarRequest&>(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<WSAPIAddMenuItemRequest&>(request).menu_id();
unsigned identifier = static_cast<WSAPIAddMenuItemRequest&>(request).identifier();
String text = static_cast<WSAPIAddMenuItemRequest&>(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<WSMenuItem>(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<WSAPIAddMenuSeparatorRequest&>(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>(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<WSAPISetWindowTitleRequest&>(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<WSAPISetWindowTitleRequest&>(request).title());
break;
}
case WSMessage::APIGetWindowTitleRequest: {
int window_id = static_cast<WSAPIGetWindowTitleRequest&>(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<WSAPISetWindowRectRequest&>(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<WSAPISetWindowRectRequest&>(request).rect());
break;
}
case WSMessage::APIGetWindowRectRequest: {
int window_id = static_cast<WSAPIGetWindowRectRequest&>(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<WSWindow>(request.client_id(), window_id);
window->set_title(static_cast<WSAPICreateWindowRequest&>(request).title());
window->set_rect(static_cast<WSAPICreateWindowRequest&>(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<WSAPIGetWindowRectRequest&>(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<WSAPIInvalidateRectRequest&>(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<WSAPIInvalidateRectRequest&>(request).rect();
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
break;
}
case WSMessage::APIDidFinishPaintingNotification: {
int window_id = static_cast<WSAPIDidFinishPaintingNotification&>(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<WSAPIDidFinishPaintingNotification&>(request).rect());
break;
}
case WSMessage::APIGetWindowBackingStoreRequest: {
int window_id = static_cast<WSAPIGetWindowBackingStoreRequest&>(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<RGBA32*>(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<WSAPIReleaseWindowBackingStoreRequest&>(request).backing_store_id();
// FIXME: It shouldn't work this way!
auto* backing_store = (GraphicsBitmap*)backing_store_id;
backing_store->release();
break;
}
default:
break;
}
}

View file

@ -0,0 +1,48 @@
#pragma once
#include <AK/HashMap.h>
#include <AK/OwnPtr.h>
#include <AK/WeakPtr.h>
#include <WindowServer/WSMessageReceiver.h>
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<int, OwnPtr<WSWindow>> m_windows;
HashMap<int, OwnPtr<WSMenuBar>> m_menubars;
HashMap<int, OwnPtr<WSMenu>> m_menus;
WeakPtr<WSMenuBar> m_app_menubar;
int m_next_menubar_id { 10000 };
int m_next_menu_id { 20000 };
int m_next_window_id { 1982 };
// FIXME: Remove.
WeakPtr<Process> m_process;
};

View file

@ -12,7 +12,7 @@ class WSWindow;
class Font; class Font;
class Process; class Process;
class WSMenu { class WSMenu : public Weakable<WSMenu> {
public: public:
WSMenu(Process&, int menu_id, String&& name); WSMenu(Process&, int menu_id, String&& name);
~WSMenu(); ~WSMenu();

View file

@ -2,11 +2,12 @@
#include "WSMenu.h" #include "WSMenu.h"
#include <AK/Vector.h> #include <AK/Vector.h>
#include <AK/Weakable.h>
#include <AK/WeakPtr.h> #include <AK/WeakPtr.h>
class Process; class Process;
class WSMenuBar { class WSMenuBar : public Weakable<WSMenuBar> {
public: public:
WSMenuBar(int menubar_id, Process&); WSMenuBar(int menubar_id, Process&);
~WSMenuBar(); ~WSMenuBar();

View file

@ -3,6 +3,7 @@
#include "WSMessageReceiver.h" #include "WSMessageReceiver.h"
#include "WSWindowManager.h" #include "WSWindowManager.h"
#include "WSScreen.h" #include "WSScreen.h"
#include <WindowServer/WSClientConnection.h>
#include "PS2MouseDevice.h" #include "PS2MouseDevice.h"
#include <Kernel/Keyboard.h> #include <Kernel/Keyboard.h>
#include <AK/Bitmap.h> #include <AK/Bitmap.h>
@ -267,7 +268,10 @@ void WSMessageLoop::drain_keyboard()
void WSMessageLoop::notify_client_died(int client_id) void WSMessageLoop::notify_client_died(int client_id)
{ {
LOCKER(m_lock); LOCKER(m_lock);
post_message(&WSWindowManager::the(), make<WSClientDisconnectedNotification>(client_id)); auto* client = WSClientConnection::from_client_id(client_id);
if (!client)
return;
post_message(client, make<WSClientDisconnectedNotification>(client_id));
} }
ssize_t WSMessageLoop::on_receive_from_client(int client_id, const byte* data, size_t size) 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(); Scheduler::yield();
LOCKER(m_lock); LOCKER(m_lock);
WSClientConnection* client = WSClientConnection::ensure_for_client_id(client_id);
ASSERT(size == sizeof(GUI_ClientMessage)); ASSERT(size == sizeof(GUI_ClientMessage));
auto& message = *reinterpret_cast<const GUI_ClientMessage*>(data); auto& message = *reinterpret_cast<const GUI_ClientMessage*>(data);
switch (message.type) { switch (message.type) {
case GUI_ClientMessage::Type::CreateMenubar: case GUI_ClientMessage::Type::CreateMenubar:
post_message(&WSWindowManager::the(), make<WSAPICreateMenubarRequest>(client_id)); post_message(client, make<WSAPICreateMenubarRequest>(client_id));
break; break;
case GUI_ClientMessage::Type::DestroyMenubar: case GUI_ClientMessage::Type::DestroyMenubar:
post_message(&WSWindowManager::the(), make<WSAPIDestroyMenubarRequest>(client_id, message.menu.menubar_id)); post_message(client, make<WSAPIDestroyMenubarRequest>(client_id, message.menu.menubar_id));
break; break;
case GUI_ClientMessage::Type::SetApplicationMenubar: case GUI_ClientMessage::Type::SetApplicationMenubar:
post_message(&WSWindowManager::the(), make<WSAPISetApplicationMenubarRequest>(client_id, message.menu.menubar_id)); post_message(client, make<WSAPISetApplicationMenubarRequest>(client_id, message.menu.menubar_id));
break; break;
case GUI_ClientMessage::Type::AddMenuToMenubar: case GUI_ClientMessage::Type::AddMenuToMenubar:
post_message(&WSWindowManager::the(), make<WSAPIAddMenuToMenubarRequest>(client_id, message.menu.menubar_id, message.menu.menu_id)); post_message(client, make<WSAPIAddMenuToMenubarRequest>(client_id, message.menu.menubar_id, message.menu.menu_id));
break; break;
case GUI_ClientMessage::Type::CreateMenu: case GUI_ClientMessage::Type::CreateMenu:
ASSERT(message.text_length < sizeof(message.text)); ASSERT(message.text_length < sizeof(message.text));
post_message(&WSWindowManager::the(), make<WSAPICreateMenuRequest>(client_id, String(message.text, message.text_length))); post_message(client, make<WSAPICreateMenuRequest>(client_id, String(message.text, message.text_length)));
break; break;
case GUI_ClientMessage::Type::DestroyMenu: case GUI_ClientMessage::Type::DestroyMenu:
post_message(&WSWindowManager::the(), make<WSAPIDestroyMenuRequest>(client_id, message.menu.menu_id)); post_message(client, make<WSAPIDestroyMenuRequest>(client_id, message.menu.menu_id));
break; break;
case GUI_ClientMessage::Type::AddMenuItem: case GUI_ClientMessage::Type::AddMenuItem:
ASSERT(message.text_length < sizeof(message.text)); ASSERT(message.text_length < sizeof(message.text));
post_message(&WSWindowManager::the(), make<WSAPIAddMenuItemRequest>(client_id, message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length))); post_message(client, make<WSAPIAddMenuItemRequest>(client_id, message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length)));
break; break;
case GUI_ClientMessage::Type::CreateWindow: case GUI_ClientMessage::Type::CreateWindow:
ASSERT(message.text_length < sizeof(message.text)); ASSERT(message.text_length < sizeof(message.text));
post_message(&WSWindowManager::the(), make<WSAPICreateWindowRequest>(client_id, message.window.rect, String(message.text, message.text_length))); post_message(client, make<WSAPICreateWindowRequest>(client_id, message.window.rect, String(message.text, message.text_length)));
break; break;
case GUI_ClientMessage::Type::DestroyWindow: case GUI_ClientMessage::Type::DestroyWindow:
post_message(&WSWindowManager::the(), make<WSAPIDestroyWindowRequest>(client_id, message.window_id)); post_message(client, make<WSAPIDestroyWindowRequest>(client_id, message.window_id));
break; break;
case GUI_ClientMessage::Type::SetWindowTitle: case GUI_ClientMessage::Type::SetWindowTitle:
ASSERT(message.text_length < sizeof(message.text)); ASSERT(message.text_length < sizeof(message.text));
post_message(&WSWindowManager::the(), make<WSAPISetWindowTitleRequest>(client_id, message.window_id, String(message.text, message.text_length))); post_message(client, make<WSAPISetWindowTitleRequest>(client_id, message.window_id, String(message.text, message.text_length)));
break; break;
case GUI_ClientMessage::Type::GetWindowTitle: case GUI_ClientMessage::Type::GetWindowTitle:
ASSERT(message.text_length < sizeof(message.text)); ASSERT(message.text_length < sizeof(message.text));
post_message(&WSWindowManager::the(), make<WSAPIGetWindowTitleRequest>(client_id, message.window_id)); post_message(client, make<WSAPIGetWindowTitleRequest>(client_id, message.window_id));
break; break;
case GUI_ClientMessage::Type::SetWindowRect: case GUI_ClientMessage::Type::SetWindowRect:
post_message(&WSWindowManager::the(), make<WSAPISetWindowRectRequest>(client_id, message.window_id, message.window.rect)); post_message(client, make<WSAPISetWindowRectRequest>(client_id, message.window_id, message.window.rect));
break; break;
case GUI_ClientMessage::Type::GetWindowRect: case GUI_ClientMessage::Type::GetWindowRect:
post_message(&WSWindowManager::the(), make<WSAPIGetWindowRectRequest>(client_id, message.window_id)); post_message(client, make<WSAPIGetWindowRectRequest>(client_id, message.window_id));
break; break;
case GUI_ClientMessage::Type::InvalidateRect: case GUI_ClientMessage::Type::InvalidateRect:
post_message(&WSWindowManager::the(), make<WSAPIInvalidateRectRequest>(client_id, message.window_id, message.window.rect)); post_message(client, make<WSAPIInvalidateRectRequest>(client_id, message.window_id, message.window.rect));
break; break;
case GUI_ClientMessage::Type::DidFinishPainting: case GUI_ClientMessage::Type::DidFinishPainting:
post_message(&WSWindowManager::the(), make<WSAPIDidFinishPaintingNotification>(client_id, message.window_id, message.window.rect)); post_message(client, make<WSAPIDidFinishPaintingNotification>(client_id, message.window_id, message.window.rect));
break; break;
case GUI_ClientMessage::Type::GetWindowBackingStore: case GUI_ClientMessage::Type::GetWindowBackingStore:
post_message(&WSWindowManager::the(), make<WSAPIGetWindowBackingStoreRequest>(client_id, message.window_id)); post_message(client, make<WSAPIGetWindowBackingStoreRequest>(client_id, message.window_id));
break; break;
case GUI_ClientMessage::Type::ReleaseWindowBackingStore: case GUI_ClientMessage::Type::ReleaseWindowBackingStore:
post_message(&WSWindowManager::the(), make<WSAPIReleaseWindowBackingStoreRequest>(client_id, (int)message.backing.backing_store_id)); post_message(client, make<WSAPIReleaseWindowBackingStoreRequest>(client_id, (int)message.backing.backing_store_id));
break; break;
case GUI_ClientMessage::Type::SetGlobalCursorTracking: case GUI_ClientMessage::Type::SetGlobalCursorTracking:
post_message(&WSWindowManager::the(), make<WSAPISetGlobalCursorTrackingRequest>(client_id, message.value)); post_message(client, make<WSAPISetGlobalCursorTrackingRequest>(client_id, message.value));
break; break;
} }
server_process().request_wakeup(); server_process().request_wakeup();

View file

@ -3,6 +3,7 @@
#include "WSMessage.h" #include "WSMessage.h"
#include "WSMessageLoop.h" #include "WSMessageLoop.h"
#include "Process.h" #include "Process.h"
#include <WindowServer/WSClientConnection.h>
WSWindow::WSWindow(WSMenu& menu) WSWindow::WSWindow(WSMenu& menu)
: m_lock("WSWindow (menu)") : m_lock("WSWindow (menu)")
@ -12,12 +13,11 @@ WSWindow::WSWindow(WSMenu& menu)
WSWindowManager::the().add_window(*this); 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_lock("WSWindow (normal)")
, m_client_id(client_id)
, m_type(WSWindowType::Normal) , m_type(WSWindowType::Normal)
, m_process(&process)
, m_window_id(window_id) , m_window_id(window_id)
, m_pid(process.pid())
{ {
WSWindowManager::the().add_window(*this); WSWindowManager::the().add_window(*this);
} }
@ -44,15 +44,21 @@ void WSWindow::set_rect(const Rect& rect)
Rect old_rect; Rect old_rect;
{ {
WSWindowLocker locker(*this); 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; return;
if (m_rect == rect) if (m_rect == rect)
return; return;
old_rect = m_rect; old_rect = m_rect;
m_rect = rect; m_rect = rect;
if (!m_backing || old_rect.size() != rect.size()) { if (!m_backing || old_rect.size() != rect.size()) {
if (m_process) if (process)
m_backing = GraphicsBitmap::create(*m_process, m_rect.size()); m_backing = GraphicsBitmap::create(*process, m_rect.size());
if (m_menu) if (m_menu)
m_backing = GraphicsBitmap::create_kernel_only(m_rect.size()); m_backing = GraphicsBitmap::create_kernel_only(m_rect.size());
} }
@ -135,19 +141,15 @@ void WSWindow::on_message(WSMessage& message)
{ {
WSWindowLocker window_locker(*this); WSWindowLocker window_locker(*this);
if (!m_process) if (auto* client = WSClientConnection::from_client_id(m_client_id)) {
return; if (auto* process = client->process()) {
LOCKER(m_process->gui_events_lock()); LOCKER(process->gui_events_lock());
m_process->gui_events().append(move(gui_event)); process->gui_events().append(move(gui_event));
}
}
} }
} }
void WSWindow::notify_process_died(Badge<Process>)
{
WSWindowLocker locker(*this);
m_process = nullptr;
}
void WSWindow::set_global_cursor_tracking_enabled(bool enabled) void WSWindow::set_global_cursor_tracking_enabled(bool enabled)
{ {
dbgprintf("WSWindow{%p} global_cursor_tracking <- %u\n", enabled); dbgprintf("WSWindow{%p} global_cursor_tracking <- %u\n", enabled);

View file

@ -6,21 +6,19 @@
#include <AK/InlineLinkedList.h> #include <AK/InlineLinkedList.h>
#include <AK/Lock.h> #include <AK/Lock.h>
#include <AK/Badge.h> #include <AK/Badge.h>
#include <Kernel/Process.h>
#include "WSMessageReceiver.h" #include "WSMessageReceiver.h"
#include <WindowServer/WSWindowType.h> #include <WindowServer/WSWindowType.h>
class Process;
class WSMenu; class WSMenu;
class WSWindow final : public WSMessageReceiver, public InlineLinkedListNode<WSWindow> { class WSWindow final : public WSMessageReceiver, public InlineLinkedListNode<WSWindow> {
friend class WSWindowLocker; friend class WSWindowLocker;
public: public:
WSWindow(Process&, int window_id); WSWindow(int client_id, int window_id);
explicit WSWindow(WSMenu&); explicit WSWindow(WSMenu&);
virtual ~WSWindow() override; virtual ~WSWindow() override;
const Process* process() const { return m_process; } int client_id() const { return m_client_id; }
WSWindowType type() const { return m_type; } WSWindowType type() const { return m_type; }
int window_id() const { return m_window_id; } int window_id() const { return m_window_id; }
@ -59,13 +57,9 @@ public:
GraphicsBitmap* backing() { return m_backing.ptr(); } GraphicsBitmap* backing() { return m_backing.ptr(); }
pid_t pid() const { return m_pid; }
void set_global_cursor_tracking_enabled(bool); void set_global_cursor_tracking_enabled(bool);
bool global_cursor_tracking() const { return m_global_cursor_tracking_enabled; } bool global_cursor_tracking() const { return m_global_cursor_tracking_enabled; }
void notify_process_died(Badge<Process>);
// For InlineLinkedList. // For InlineLinkedList.
// FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that. // FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that.
WSWindow* m_next { nullptr }; WSWindow* m_next { nullptr };
@ -73,6 +67,7 @@ public:
private: private:
Lock m_lock; Lock m_lock;
int m_client_id { 0 };
String m_title; String m_title;
Rect m_rect; Rect m_rect;
WSWindowType m_type { WSWindowType::Normal }; WSWindowType m_type { WSWindowType::Normal };
@ -83,9 +78,7 @@ private:
WSMenu* m_menu { nullptr }; WSMenu* m_menu { nullptr };
RetainPtr<GraphicsBitmap> m_backing; RetainPtr<GraphicsBitmap> m_backing;
Process* m_process { nullptr };
int m_window_id { -1 }; int m_window_id { -1 };
pid_t m_pid { -1 };
}; };
class WSWindowLocker { class WSWindowLocker {

View file

@ -14,6 +14,7 @@
#include "WSMenu.h" #include "WSMenu.h"
#include "WSMenuBar.h" #include "WSMenuBar.h"
#include "WSMenuItem.h" #include "WSMenuItem.h"
#include <WindowServer/WSClientConnection.h>
#include <Kernel/RTC.h> #include <Kernel/RTC.h>
//#define DEBUG_COUNTERS //#define DEBUG_COUNTERS
@ -239,7 +240,10 @@ int WSWindowManager::menubar_menu_margin() const
void WSWindowManager::set_current_menubar(WSMenuBar* menubar) void WSWindowManager::set_current_menubar(WSMenuBar* menubar)
{ {
LOCKER(m_lock); 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); dbgprintf("[WM] Current menubar is now %p\n", menubar);
Point next_menu_location { menubar_menu_margin() / 2, 3 }; Point next_menu_location { menubar_menu_margin() / 2, 3 };
for_each_active_menubar_menu([&] (WSMenu& menu) { 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_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 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 (should_open_menu) {
if (m_current_menu == &menu) if (current_menu() == &menu)
return; return;
close_current_menu(); close_current_menu();
if (!menu.is_empty()) { 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.move_to({ menu.rect_in_menubar().x(), menu.rect_in_menubar().bottom() });
menu_window.set_visible(true); menu_window.set_visible(true);
} }
m_current_menu = &menu; m_current_menu = menu.make_weak_ptr();
return; return;
} }
if (event.type() == WSMouseEvent::MouseDown && event.button() == MouseButton::Left) { if (event.type() == WSMouseEvent::MouseDown && event.button() == MouseButton::Left) {
@ -422,7 +426,7 @@ void WSWindowManager::close_current_menu()
m_current_menu = nullptr; 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) { for_each_active_menubar_menu([&] (WSMenu& menu) {
if (menu.rect_in_menubar().contains(event.position())) { 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())) { if (menubar_rect().contains(event.position())) {
handle_menubar_mouse_event(*m_current_menubar, event); handle_menubar_mouse_event(event);
return; 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); m_back_painter->draw_line({ 0, menubar_rect().bottom() }, { menubar_rect().right(), menubar_rect().bottom() }, Color::White);
for_each_active_menubar_menu([&] (WSMenu& menu) { for_each_active_menubar_menu([&] (WSMenu& menu) {
Color text_color = Color::Black; 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()); m_back_painter->fill_rect(menu.rect_in_menubar(), menu_selection_color());
text_color = Color::White; text_color = Color::White;
} }
@ -733,284 +737,6 @@ void WSWindowManager::on_message(WSMessage& message)
compose(); compose();
return; return;
} }
if (message.is_client_request()) {
handle_client_request(static_cast<WSAPIClientRequest&>(message));
return;
}
if (message.type() == WSMessage::WM_ClientDisconnected) {
int client_id = static_cast<WSClientDisconnectedNotification&>(message).client_id();
dbgprintf("[WM] Client disconnected: %d\n", client_id);
destroy_all_menus(*WSMessageLoop::process_from_client_id(client_id));
Vector<int> 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<WSMenuBar>(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<WSAPIDestroyMenubarRequest&>(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<WSMenu>(*WSMessageLoop::process_from_client_id(request.client_id()), menu_id, static_cast<WSAPICreateMenuRequest&>(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<WSAPIDestroyMenuRequest&>(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<WSAPISetApplicationMenubarRequest&>(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<WSAPIAddMenuToMenubarRequest&>(request).menubar_id();
int menu_id = static_cast<WSAPIAddMenuToMenubarRequest&>(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<WSAPIAddMenuItemRequest&>(request).menu_id();
unsigned identifier = static_cast<WSAPIAddMenuItemRequest&>(request).identifier();
String text = static_cast<WSAPIAddMenuItemRequest&>(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<WSMenuItem>(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<WSAPIAddMenuSeparatorRequest&>(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>(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<WSAPISetWindowTitleRequest&>(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<WSAPISetWindowTitleRequest&>(request).title());
break;
}
case WSMessage::APIGetWindowTitleRequest: {
int window_id = static_cast<WSAPIGetWindowTitleRequest&>(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<WSAPISetWindowRectRequest&>(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<WSAPISetWindowRectRequest&>(request).rect());
break;
}
case WSMessage::APIGetWindowRectRequest: {
int window_id = static_cast<WSAPIGetWindowRectRequest&>(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<WSWindow>(*WSMessageLoop::process_from_client_id(request.client_id()), window_id);
window->set_title(static_cast<WSAPICreateWindowRequest&>(request).title());
window->set_rect(static_cast<WSAPICreateWindowRequest&>(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<WSAPIGetWindowRectRequest&>(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<WSAPIInvalidateRectRequest&>(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<WSAPIInvalidateRectRequest&>(request).rect();
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
break;
}
case WSMessage::APIDidFinishPaintingNotification: {
int window_id = static_cast<WSAPIDidFinishPaintingNotification&>(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<WSAPIDidFinishPaintingNotification&>(request).rect());
break;
}
case WSMessage::APIGetWindowBackingStoreRequest: {
int window_id = static_cast<WSAPIGetWindowBackingStoreRequest&>(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<RGBA32*>(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<WSAPIReleaseWindowBackingStoreRequest&>(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) 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>(WSMessage::WindowActivated)); WSMessageLoop::the().post_message(m_active_window.ptr(), make<WSMessage>(WSMessage::WindowActivated));
invalidate(*m_active_window); invalidate(*m_active_window);
ASSERT(window->process()); int client_id = window->client_id();
auto it = m_app_menubars.find(window->process()->gui_client_id()); auto* client = WSClientConnection::from_client_id(client_id);
if (it != m_app_menubars.end()) { ASSERT(client);
auto* menubar = (*it).value; set_current_menubar(client->app_menubar());
if (menubar != m_current_menubar)
set_current_menubar(menubar);
} else {
set_current_menubar(nullptr);
}
} }
} }
@ -1119,44 +840,27 @@ void WSWindowManager::flush(const Rect& a_rect)
void WSWindowManager::close_menu(WSMenu& menu) void WSWindowManager::close_menu(WSMenu& menu)
{ {
LOCKER(m_lock); LOCKER(m_lock);
if (m_current_menu == &menu) if (current_menu() == &menu)
close_current_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 int WSWindowManager::active_client_id() const
{ {
if (m_active_window) if (m_active_window)
return m_active_window->process()->gui_client_id(); return m_active_window->client_id();
return 0; return 0;
} }
void WSWindowManager::destroy_all_menus(Process& process) void WSWindowManager::notify_client_changed_app_menubar(WSClientConnection& client)
{ {
LOCKER(m_lock); if (active_client_id() == client.client_id())
Vector<int> menu_ids; set_current_menubar(client.app_menubar());
bool should_close_current_menu = false; invalidate();
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<int> 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());
} }

View file

@ -18,6 +18,7 @@ class WSMenuBar;
class WSMouseEvent; class WSMouseEvent;
class WSClientWantsToPaintMessage; class WSClientWantsToPaintMessage;
class WSWindow; class WSWindow;
class WSClientConnection;
class CharacterBitmap; class CharacterBitmap;
class GraphicsBitmap; class GraphicsBitmap;
@ -31,6 +32,7 @@ public:
void notify_title_changed(WSWindow&); void notify_title_changed(WSWindow&);
void notify_rect_changed(WSWindow&, const Rect& oldRect, const Rect& newRect); 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(); } WSWindow* active_window() { return m_active_window.ptr(); }
int active_client_id() const; int active_client_id() const;
@ -42,9 +44,9 @@ public:
void draw_menubar(); void draw_menubar();
Rect menubar_rect() const; Rect menubar_rect() const;
WSMenuBar* current_menubar() { return m_current_menubar; } WSMenuBar* current_menubar() { return m_current_menubar.ptr(); }
void set_current_menubar(WSMenuBar*); 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 set_current_menu(WSMenu*);
void invalidate(const WSWindow&); void invalidate(const WSWindow&);
@ -57,6 +59,7 @@ public:
const Font& font() const { return *m_font; } const Font& font() const { return *m_font; }
void close_menu(WSMenu&); void close_menu(WSMenu&);
void close_menubar(WSMenuBar&);
Color menu_selection_color() const { return m_menu_selection_color; } Color menu_selection_color() const { return m_menu_selection_color; }
int menubar_menu_margin() const; int menubar_menu_margin() const;
@ -70,7 +73,7 @@ private:
void process_mouse_event(WSMouseEvent&); void process_mouse_event(WSMouseEvent&);
void handle_menu_mouse_event(WSMenu&, 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_titlebar_mouse_event(WSWindow&, WSMouseEvent&);
void handle_close_button_mouse_event(WSWindow&, WSMouseEvent&); void handle_close_button_mouse_event(WSWindow&, WSMouseEvent&);
void handle_client_request(WSAPIClientRequest&); void handle_client_request(WSAPIClientRequest&);
@ -145,15 +148,8 @@ private:
Lockable<bool> m_flash_flush; Lockable<bool> m_flash_flush;
bool m_buffers_are_flipped { false }; 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<WSMenu> m_system_menu; OwnPtr<WSMenu> m_system_menu;
Color m_menu_selection_color; Color m_menu_selection_color;
WSMenuBar* m_current_menubar { nullptr }; WeakPtr<WSMenuBar> m_current_menubar;
WSMenu* m_current_menu { nullptr }; WeakPtr<WSMenu> m_current_menu;
HashMap<int, OwnPtr<WSMenuBar>> m_menubars;
HashMap<int, OwnPtr<WSMenu>> m_menus;
HashMap<int, WSMenuBar*> m_app_menubars;
}; };