From fb3333a0869871a7bcea58ffa8d834024fe5c179 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 13 Dec 2024 21:53:12 +0100 Subject: [PATCH] wind: Remove special window attributes and add different window layers. Two layers are accessible to all apps: global and global_top (for popups and similar windows). Three other layers are accessible to privileged clients (background, system and lock), for things that need to be on a different level than user apps, like the taskbar, system popups, menus and the lock screen. --- gui/apps/taskbar.cpp | 2 +- gui/libui/include/ui/Window.h | 2 +- gui/libui/include/ui/ipc/Server.h | 16 ++++--- gui/libui/src/Window.cpp | 6 +-- gui/wind/CMakeLists.txt | 2 + gui/wind/IPC.cpp | 39 +++++++++++---- gui/wind/Layer.cpp | 79 +++++++++++++++++++++++++++++++ gui/wind/Layer.h | 20 ++++++++ gui/wind/Mouse.cpp | 43 ++++------------- gui/wind/Window.cpp | 10 ++-- gui/wind/Window.h | 5 +- gui/wind/main.cpp | 40 ++-------------- 12 files changed, 164 insertions(+), 100 deletions(-) create mode 100644 gui/wind/Layer.cpp create mode 100644 gui/wind/Layer.h diff --git a/gui/apps/taskbar.cpp b/gui/apps/taskbar.cpp index 8084acc7..6665dd1b 100644 --- a/gui/apps/taskbar.cpp +++ b/gui/apps/taskbar.cpp @@ -125,7 +125,7 @@ Result luna_main(int, char**) app.set_main_window(window); window->set_background(TASKBAR_COLOR); - window->set_special_attributes(ui::UNFOCUSEABLE); + window->set_layer(ui::Layer::Background); ui::HorizontalLayout layout(ui::Margins { 0, 0, 0, 0 }, ui::AdjustHeight::Yes, ui::AdjustWidth::No); window->set_main_widget(layout); diff --git a/gui/libui/include/ui/Window.h b/gui/libui/include/ui/Window.h index a0a37bba..ca343873 100644 --- a/gui/libui/include/ui/Window.h +++ b/gui/libui/include/ui/Window.h @@ -65,7 +65,7 @@ namespace ui void close(); - void set_special_attributes(WindowAttributes attributes); + void set_layer(Layer layer); Result draw(); Result handle_mouse_leave(); diff --git a/gui/libui/include/ui/ipc/Server.h b/gui/libui/include/ui/ipc/Server.h index d054a07d..ae37d77c 100644 --- a/gui/libui/include/ui/ipc/Server.h +++ b/gui/libui/include/ui/ipc/Server.h @@ -25,7 +25,7 @@ namespace ui CLOSE_WINDOW_ID, GET_SCREEN_RECT_ID, SET_TITLEBAR_HEIGHT_ID, - SET_SPECIAL_WINDOW_ATTRIBUTES_ID, + SET_WINDOW_LAYER_ID, }; struct CreateWindowRequest @@ -81,16 +81,20 @@ namespace ui int height; }; - enum WindowAttributes : u8 + enum Layer : u8 { - UNFOCUSEABLE = 1, + Background, + Global, + GlobalTop, + System, + Lock }; - struct SetSpecialWindowAttributesRequest + struct SetWindowLayer { - static constexpr u8 ID = SET_SPECIAL_WINDOW_ATTRIBUTES_ID; + static constexpr u8 ID = SET_WINDOW_LAYER_ID; int window; - WindowAttributes attributes; + Layer layer; }; } diff --git a/gui/libui/src/Window.cpp b/gui/libui/src/Window.cpp index f52a50c2..dc8a0833 100644 --- a/gui/libui/src/Window.cpp +++ b/gui/libui/src/Window.cpp @@ -115,11 +115,11 @@ namespace ui app.unregister_window(this, {}); } - void Window::set_special_attributes(WindowAttributes attributes) + void Window::set_layer(Layer layer) { - ui::SetSpecialWindowAttributesRequest request; + ui::SetWindowLayer request; request.window = m_id; - request.attributes = attributes; + request.layer = layer; App::the().client().send_async(request); } diff --git a/gui/wind/CMakeLists.txt b/gui/wind/CMakeLists.txt index 2999afb8..85455a93 100644 --- a/gui/wind/CMakeLists.txt +++ b/gui/wind/CMakeLists.txt @@ -11,6 +11,8 @@ set(SOURCES Keyboard.cpp Keyboard.h Client.h + Layer.cpp + Layer.h ) add_executable(wind ${SOURCES}) diff --git a/gui/wind/IPC.cpp b/gui/wind/IPC.cpp index 99f739cb..f879e20c 100644 --- a/gui/wind/IPC.cpp +++ b/gui/wind/IPC.cpp @@ -1,4 +1,5 @@ #include "IPC.h" +#include "Layer.h" #include "Mouse.h" #include "Screen.h" #include @@ -47,7 +48,7 @@ static Result handle_create_window_message(Client& client) } auto guard = make_scope_guard([window] { - g_windows.remove(window); + window->layer->windows.remove(window); delete window; }); @@ -120,7 +121,7 @@ static Result handle_close_window_message(Client& client) auto* window = client.windows[request.window]; client.windows[request.window] = nullptr; - g_windows.remove(window); + window->layer->windows.remove(window); Mouse::the().window_did_close(window); delete window; @@ -160,22 +161,40 @@ static Result handle_set_titlebar_height_message(Client& client) return {}; } -static Result handle_set_special_window_attributes_message(Client& client) +static Result handle_set_window_layer_message(Client& client) { - ui::SetSpecialWindowAttributesRequest request; + ui::SetWindowLayer request; if (!TRY(client.conn->read_message(request))) return {}; - if (!client.privileged) + if (request.layer != ui::Layer::Global && request.layer != ui::Layer::GlobalTop && !client.privileged) { - os::eprintln( - "wind: Unprivileged client trying to call privileged request (SetSpecialWindowAttributes), disconnecting!"); + os::eprintln("wind: Unprivileged client trying to set window layer to a privileged layer, disconnecting!"); client.should_be_disconnected = true; return {}; } - CHECK_WINDOW_ID(request, "SetSpecialWindowAttributes"); + CHECK_WINDOW_ID(request, "SetWindowLayer"); - client.windows[request.window]->attributes = request.attributes; + auto* window = client.windows[request.window]; + + window->layer->windows.remove(window); + + switch (request.layer) + { + case ui::Layer::Background: window->layer = &l_background; break; + case ui::Layer::Global: window->layer = &l_global; break; + case ui::Layer::GlobalTop: window->layer = &l_global_top; break; + case ui::Layer::System: window->layer = &l_system; break; + case ui::Layer::Lock: window->layer = &l_lock; break; + default: { + window->layer->windows.append(window); + os::eprintln("wind: Client trying to set window layer to an invalid layer, disconnecting!"); + client.should_be_disconnected = true; + return {}; + } + } + + window->layer->windows.append(window); return {}; } @@ -194,7 +213,7 @@ namespace wind case ui::CLOSE_WINDOW_ID: handle_close_window_message(client); break; case ui::GET_SCREEN_RECT_ID: handle_get_screen_rect_message(client); break; case ui::SET_TITLEBAR_HEIGHT_ID: handle_set_titlebar_height_message(client); break; - case ui::SET_SPECIAL_WINDOW_ATTRIBUTES_ID: handle_set_special_window_attributes_message(client); break; + case ui::SET_WINDOW_LAYER_ID: handle_set_window_layer_message(client); break; default: os::eprintln("wind: Invalid IPC message from client!"); return; } } diff --git a/gui/wind/Layer.cpp b/gui/wind/Layer.cpp new file mode 100644 index 00000000..6b643984 --- /dev/null +++ b/gui/wind/Layer.cpp @@ -0,0 +1,79 @@ +#include "Layer.h" +#include "Client.h" +#include "Window.h" + +Layer l_background; +Layer l_global; +Layer l_global_top; +Layer l_system; +Layer l_lock; + +constexpr int NUM_LAYERS = 5; + +static Layer* const layers_front_to_back[NUM_LAYERS] = { &l_lock, &l_system, &l_global_top, &l_global, &l_background }; +static Layer* const layers_back_to_front[NUM_LAYERS] = { &l_background, &l_global, &l_global_top, &l_system, &l_lock }; + +Window* Layer::focused_window() +{ + for (int i = 0; i < NUM_LAYERS; i++) + { + Layer* l = layers_front_to_back[i]; + if (l->windows.last().has_value()) return l->windows.last().value(); + } + + return nullptr; +} + +void Layer::draw_all_windows(ui::Canvas& canvas) +{ + for (int i = 0; i < NUM_LAYERS; i++) + { + Layer* l = layers_back_to_front[i]; + for (Window* w : l->windows) { w->draw(canvas); } + } +} + +Window* Layer::propagate_mouse_event(ui::Point position, u8 buttons) +{ + for (int i = 0; i < NUM_LAYERS; i++) + { + Layer* l = layers_front_to_back[i]; + for (Window* window = l->windows.last().value_or(nullptr); window; + window = l->windows.previous(window).value_or(nullptr)) + { + if (window->surface.contains(position)) + { + ui::MouseEventRequest request; + request.window = window->id; + request.position = window->surface.relative(position); + request.buttons = buttons; + window->client->conn->send_async(request); + return window; + } + } + } + + return nullptr; +} + +Window* Layer::propagate_drag_event(ui::Point position) +{ + for (int i = 0; i < NUM_LAYERS; i++) + { + Layer* l = layers_front_to_back[i]; + for (Window* window = l->windows.last().value_or(nullptr); window; + window = l->windows.previous(window).value_or(nullptr)) + { + if (window->surface.contains(position)) + { + window->focus(); + + if (window->surface.absolute(window->titlebar).contains(position)) return window; + + return nullptr; + } + } + } + + return nullptr; +} diff --git a/gui/wind/Layer.h b/gui/wind/Layer.h new file mode 100644 index 00000000..55b82f29 --- /dev/null +++ b/gui/wind/Layer.h @@ -0,0 +1,20 @@ +#pragma once +#include "Window.h" +#include +#include + +struct Layer +{ + LinkedList windows; + + static Window* focused_window(); + static void draw_all_windows(ui::Canvas& canvas); + static Window* propagate_mouse_event(ui::Point position, u8 buttons); + static Window* propagate_drag_event(ui::Point position); +}; + +extern Layer l_background; +extern Layer l_global; +extern Layer l_global_top; +extern Layer l_system; +extern Layer l_lock; diff --git a/gui/wind/Mouse.cpp b/gui/wind/Mouse.cpp index 31526930..bad17cad 100644 --- a/gui/wind/Mouse.cpp +++ b/gui/wind/Mouse.cpp @@ -1,5 +1,6 @@ #include "Mouse.h" #include "Client.h" +#include "Layer.h" #include #include #include @@ -57,45 +58,17 @@ void Mouse::update(const moon::MousePacket& packet) else if ((packet.buttons & moon::MouseButton::Left) && !m_dragging_window) { - // Iterate from the end of the list, since windows at the beginning are stacked at the bottom and windows at the - // top are at the end. - for (Window* window = g_windows.last().value_or(nullptr); window; - window = g_windows.previous(window).value_or(nullptr)) + if (auto* window = Layer::propagate_drag_event(m_position)) { - if (window->surface.contains(m_position)) - { - if (!(window->attributes & ui::UNFOCUSEABLE)) window->focus(); - - if (window->surface.absolute(window->titlebar).contains(m_position)) - { - m_dragging_window = window; - m_initial_drag_position = window->surface.relative(m_position); - os::println("Started drag: window at (%d,%d,%d,%d) with offset (%d,%d)", window->surface.pos.x, - window->surface.pos.y, window->surface.width, window->surface.height, - m_initial_drag_position.x, m_initial_drag_position.y); - } - - break; - } + m_dragging_window = window; + m_initial_drag_position = window->surface.relative(m_position); + os::println("Started drag: window at (%d,%d,%d,%d) with offset (%d,%d)", window->surface.pos.x, + window->surface.pos.y, window->surface.width, window->surface.height, m_initial_drag_position.x, + m_initial_drag_position.y); } } - Window* new_active_window = nullptr; - - for (Window* window = g_windows.last().value_or(nullptr); window; - window = g_windows.previous(window).value_or(nullptr)) - { - if (window->surface.contains(m_position)) - { - ui::MouseEventRequest request; - request.window = window->id; - request.position = window->surface.relative(m_position); - request.buttons = packet.buttons; - window->client->conn->send_async(request); - new_active_window = window; - break; - } - } + Window* new_active_window = Layer::propagate_mouse_event(m_position, packet.buttons); if (m_active_window != new_active_window) { diff --git a/gui/wind/Window.cpp b/gui/wind/Window.cpp index ae5f6d57..c6ea2f77 100644 --- a/gui/wind/Window.cpp +++ b/gui/wind/Window.cpp @@ -1,12 +1,11 @@ #include "Window.h" +#include "Layer.h" #include #include #include #include #include -LinkedList g_windows; - void Window::draw(ui::Canvas& screen) { dirty = false; @@ -18,15 +17,16 @@ void Window::draw(ui::Canvas& screen) void Window::focus() { // Bring the window to the front of the list. - g_windows.remove(this); - g_windows.append(this); + layer->windows.remove(this); + layer->windows.append(this); } Window::Window(ui::Rect r, RefString&& n) : surface(r), name(move(n)) { auto font = ui::Font::default_font(); titlebar = ui::Rect { 0, 0, 0, 0 }; - g_windows.append(this); + l_global.windows.append(this); + layer = &l_global; } Window::~Window() diff --git a/gui/wind/Window.h b/gui/wind/Window.h index 67cd37ec..342f1616 100644 --- a/gui/wind/Window.h +++ b/gui/wind/Window.h @@ -7,6 +7,7 @@ #include struct Client; +struct Layer; struct Window : public LinkedListNode { @@ -17,8 +18,8 @@ struct Window : public LinkedListNode RefString shm_path; bool dirty { false }; Client* client; + Layer* layer; int id; - ui::WindowAttributes attributes { 0 }; Window(ui::Rect, RefString&&); ~Window(); @@ -27,5 +28,3 @@ struct Window : public LinkedListNode void draw(ui::Canvas& screen); }; - -extern LinkedList g_windows; diff --git a/gui/wind/main.cpp b/gui/wind/main.cpp index 8695b60d..bbebfc68 100644 --- a/gui/wind/main.cpp +++ b/gui/wind/main.cpp @@ -1,6 +1,7 @@ #define CLIENT_IMPLEMENTATION #include "Client.h" #include "Keyboard.h" +#include "Layer.h" #include "Mouse.h" #include "Screen.h" #include "Window.h" @@ -23,37 +24,6 @@ static constexpr uid_t WIND_USER_ID = 2; static constexpr gid_t WIND_GROUP_ID = 2; static constexpr gid_t WSYS_GROUP_ID = 3; -static void debug(const Vector>& clients) -{ - os::println("--- wind: DEBUG OUTPUT ---"); - - os::println("-- wind: Listing clients --"); - - for (const auto& client : clients) - { - os::println("Client with fd %d, owns %zu windows", client->conn->fd(), client->windows.size()); - } - - os::println("-- wind: Listing windows --"); - - for (const auto& window : g_windows) - { - os::println("Window of client (fd %d), id %d, %sdirty (\"%s\") (%d,%d,%d,%d)", window->client->conn->fd(), - window->id, window->dirty ? "" : "not ", window->name.chars(), window->surface.pos.x, - window->surface.pos.y, window->surface.width, window->surface.height); - } - - os::println("-- wind: Listing processes --"); - - system("ps"); - - os::println("-- wind: Listing memory usage --"); - - system("free -h"); - - os::println("--- wind: END DEBUG OUTPUT ---"); -} - Result luna_main(int argc, char** argv) { srand((unsigned)time(NULL)); @@ -133,7 +103,7 @@ Result luna_main(int argc, char** argv) while (1) { screen.canvas().fill(background); - for (auto* window : g_windows) window->draw(screen.canvas()); + Layer::draw_all_windows(screen.canvas()); mouse_pointer.draw(screen.canvas()); screen.sync(); @@ -153,11 +123,9 @@ Result luna_main(int argc, char** argv) { moon::KeyboardPacket packet; TRY(keyboard->read_typed(packet)); - if (!packet.released && packet.key == moon::K_Tab) debug(clients); auto request = wind::Keyboard::decode_keyboard_event((moon::KeyCode)packet.key, packet.released); - if (g_windows.last().has_value()) + if (auto* window = Layer::focused_window()) { - auto* window = g_windows.last().value(); request.window = window->id; window->client->conn->send_async(request); } @@ -198,7 +166,7 @@ Result luna_main(int argc, char** argv) { if (window) { - g_windows.remove(window); + window->layer->windows.remove(window); mouse_pointer.window_did_close(window); delete window; }