wind: Remove special window attributes and add different window layers.
All checks were successful
Build and test / build (push) Successful in 1m38s

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.
This commit is contained in:
apio 2024-12-13 21:53:12 +01:00
parent ccef3e2069
commit fb3333a086
Signed by: apio
GPG Key ID: B8A7D06E42258954
12 changed files with 164 additions and 100 deletions

View File

@ -125,7 +125,7 @@ Result<int> 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);

View File

@ -65,7 +65,7 @@ namespace ui
void close();
void set_special_attributes(WindowAttributes attributes);
void set_layer(Layer layer);
Result<void> draw();
Result<ui::EventResult> handle_mouse_leave();

View File

@ -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;
};
}

View File

@ -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);
}

View File

@ -11,6 +11,8 @@ set(SOURCES
Keyboard.cpp
Keyboard.h
Client.h
Layer.cpp
Layer.h
)
add_executable(wind ${SOURCES})

View File

@ -1,4 +1,5 @@
#include "IPC.h"
#include "Layer.h"
#include "Mouse.h"
#include "Screen.h"
#include <luna/Alignment.h>
@ -47,7 +48,7 @@ static Result<void> 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<void> 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<void> handle_set_titlebar_height_message(Client& client)
return {};
}
static Result<void> handle_set_special_window_attributes_message(Client& client)
static Result<void> 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;
}
}

79
gui/wind/Layer.cpp Normal file
View File

@ -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;
}

20
gui/wind/Layer.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include "Window.h"
#include <luna/LinkedList.h>
#include <ui/Canvas.h>
struct Layer
{
LinkedList<Window> 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;

View File

@ -1,5 +1,6 @@
#include "Mouse.h"
#include "Client.h"
#include "Layer.h"
#include <os/File.h>
#include <os/IPC.h>
#include <ui/Image.h>
@ -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 (window->surface.contains(m_position))
{
if (!(window->attributes & ui::UNFOCUSEABLE)) window->focus();
if (window->surface.absolute(window->titlebar).contains(m_position))
if (auto* window = Layer::propagate_drag_event(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;
}
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)
{

View File

@ -1,12 +1,11 @@
#include "Window.h"
#include "Layer.h"
#include <luna/Utf8.h>
#include <os/File.h>
#include <sys/mman.h>
#include <ui/Font.h>
#include <ui/Image.h>
LinkedList<Window> 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()

View File

@ -7,6 +7,7 @@
#include <ui/ipc/Server.h>
struct Client;
struct Layer;
struct Window : public LinkedListNode<Window>
{
@ -17,8 +18,8 @@ struct Window : public LinkedListNode<Window>
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<Window>
void draw(ui::Canvas& screen);
};
extern LinkedList<Window> g_windows;

View File

@ -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<OwnedPtr<Client>>& 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<int> luna_main(int argc, char** argv)
{
srand((unsigned)time(NULL));
@ -133,7 +103,7 @@ Result<int> 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<int> 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<int> 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;
}