diff options
Diffstat (limited to 'packages/kernel/src/server_impl.hpp')
| -rw-r--r-- | packages/kernel/src/server_impl.hpp | 226 |
1 files changed, 146 insertions, 80 deletions
diff --git a/packages/kernel/src/server_impl.hpp b/packages/kernel/src/server_impl.hpp index 2975537..c5615b2 100644 --- a/packages/kernel/src/server_impl.hpp +++ b/packages/kernel/src/server_impl.hpp @@ -1,28 +1,33 @@ #pragma once +#include <unbox/kernel/host.hpp> #include <unbox/kernel/server.hpp> #include <unbox/kernel/wlr.hpp> #include "listener.hpp" #include "ui_spike.hpp" +#include <array> #include <cstdint> #include <list> #include <memory> #include <string> +#include <typeindex> #include <unordered_map> - -// Private kernel state. Entity structs mirror tinywl's, with Listener -// members replacing manual wl_list_remove bookkeeping (RAII unsubscribes). -// Definitions are split: server.cpp (lifecycle + outputs), toplevel.cpp -// (xdg-shell + focus + grabs), input.cpp (devices, cursor, touch, seat). +#include <vector> + +// Private kernel state (slice 4). The kernel names no concrete feature: shell +// policy (xdg-shell toplevels/popups, focus, cycling, interactive move/resize, +// keybindings) was EXTRACTED to extensions. What remains is generic plumbing +// plus the extension host + typed bus. +// +// Definitions split: server.cpp (lifecycle, outputs, host/bus/activation), +// input.cpp (devices, cursor, touch, seat — now event-emitting, not routing). +// +// Everything runs on the single wl_event_loop thread. namespace unbox::kernel { -struct Toplevel; - -enum class CursorMode { Passthrough, Move, Resize }; - struct Output { Server::Impl* server = nullptr; wlr_output* output = nullptr; @@ -31,26 +36,6 @@ struct Output { Listener destroy; }; -struct Toplevel { - Server::Impl* server = nullptr; - wlr_xdg_toplevel* xdg_toplevel = nullptr; - wlr_scene_tree* scene_tree = nullptr; - Listener map; - Listener unmap; - Listener commit; - Listener destroy; - Listener request_move; - Listener request_resize; - Listener request_maximize; - Listener request_fullscreen; -}; - -struct Popup { - wlr_xdg_popup* xdg_popup = nullptr; - Listener commit; - Listener destroy; -}; - struct Keyboard { Server::Impl* server = nullptr; wlr_keyboard* keyboard = nullptr; @@ -65,7 +50,20 @@ struct TouchDevice { Listener destroy; }; -struct Server::Impl { +// ---- Extension host bookkeeping --------------------------------------------- + +class HostImpl; // per-extension Host facade (host.cpp) + +// One installed extension's kernel-side record. +struct ExtensionSlot { + std::unique_ptr<Extension> extension; + std::unique_ptr<HostImpl> host; + ExtensionId id{}; + bool activated = false; + bool disabled = false; // tripped when a callback threw (error isolation) +}; + +struct Server::Impl : detail::DisableSink { Options options; wl_display* display = nullptr; @@ -75,55 +73,60 @@ struct Server::Impl { wlr_scene* scene = nullptr; wlr_scene_output_layout* scene_layout = nullptr; wlr_output_layout* output_layout = nullptr; - wlr_xdg_shell* xdg_shell = nullptr; wlr_cursor* cursor = nullptr; wlr_xcursor_manager* cursor_mgr = nullptr; wlr_seat* seat = nullptr; std::string socket; - // Slice-3 spike: RMLUi -> wlr_scene bridge. Null unless options.ui_spike - // and the bridge started; a started-but-disabled bridge is non-null but - // reports Plan::Disabled. Owned here; torn down in shutdown() BEFORE the - // scene/renderer/allocator die. + // Ordered scene-tree z-bands (SceneLayer order). Created once over + // scene->tree in stacking order so background < … < overlay. Extensions + // attach nodes via Host::scene_layer(); the kernel owns them. + std::array<wlr_scene_tree*, 5> scene_layers{}; + + // Slice-3 spike (kernel-internal; not a contract). Torn down in shutdown() + // BEFORE scene/renderer/allocator. std::unique_ptr<UiSpike> ui_spike; - // Ownership (RAII teardown); drained naturally during shutdown by the - // destroy events wl_display_destroy_clients / backend destroy fire. std::list<std::unique_ptr<Output>> outputs; - std::unordered_map<wlr_xdg_toplevel*, std::unique_ptr<Toplevel>> toplevels; - std::unordered_map<wlr_xdg_popup*, std::unique_ptr<Popup>> popups; std::list<std::unique_ptr<Keyboard>> keyboards; std::list<std::unique_ptr<TouchDevice>> touch_devices; - // Focus order: front = focused. Contains MAPPED toplevels only. - std::list<Toplevel*> mapped_toplevels; - - // Interactive move/resize grab state (one grab at a time). - CursorMode cursor_mode = CursorMode::Passthrough; - Toplevel* grabbed_toplevel = nullptr; - double grab_x = 0.0; - double grab_y = 0.0; - wlr_box grab_geobox{}; - std::uint32_t resize_edges = 0; - - // Touch: Wayland implicitly grabs a touch point to the surface that - // received down; we record the surface's layout origin at down time to - // derive surface-local coords for motion. Assumes the surface doesn't - // move mid-touch (true except during interactive grabs; slice 5 will - // route input properly). - struct TouchPoint { - wlr_surface* surface = nullptr; - double origin_x = 0.0; - double origin_y = 0.0; - }; - std::unordered_map<std::int32_t, TouchPoint> touch_points; - - // Server-level listeners (disconnected explicitly in shutdown() BEFORE - // the wlr objects owning their signals are destroyed). + // ---- The typed bus: kernel-emitted hooks (host.hpp catalogue) ---- + Event<const OutputEvent&> ev_output_added{this}; + Event<const OutputEvent&> ev_output_removed{this}; + Event<const PointerMotionEvent&> ev_pointer_motion{this}; + Event<const PointerButtonEvent&> ev_pointer_button{this}; + Event<const PointerAxisEvent&> ev_pointer_axis{this}; + Event<> ev_pointer_frame{this}; + Event<const TouchDownEvent&> ev_touch_down{this}; + Event<const TouchMotionEvent&> ev_touch_motion{this}; + Event<const TouchUpEvent&> ev_touch_up{this}; + Event<const TouchCancelEvent&> ev_touch_cancel{this}; + Event<> ev_touch_frame{this}; + Filter<KeyEvent> key_filter{this}; + + // Every hook bound to the isolation registry (kernel hooks above + any + // extension-exported hooks adopted via Host::adopt). disable() purges an + // extension across ALL of them. Raw borrows; lifetimes are the hooks'. + std::vector<detail::HookBase*> all_hooks; + + // Typed service registry (one provider per interface type; no strings). + std::unordered_map<std::type_index, void*> services; + + // Kernel-owned surface -> scene-tree association (replaces the old untyped + // wlr_surface.data cross-extension convention). Shared by all extensions + // via Host::host_surface/scene_tree_for; the kernel just stores it. + detail::PointerAssoc surface_assoc; + + // Installed extensions, in install order; activation order is computed + // topologically in activate_extensions(). + std::vector<ExtensionSlot> extensions; + bool extensions_activated = false; + + // Server-level listeners (disconnected in shutdown() BEFORE the wlr objects + // owning their signals die). Listener new_output; Listener new_input; - Listener new_xdg_toplevel; - Listener new_xdg_popup; Listener cursor_motion; Listener cursor_motion_absolute; Listener cursor_button; @@ -138,33 +141,96 @@ struct Server::Impl { Listener seat_pointer_focus_change; Listener seat_request_set_selection; - // server.cpp + // detail::DisableSink + void disable(ExtensionId who) noexcept override; + + // server.cpp — lifecycle + outputs void init(); // throws std::runtime_error on any component failure void shutdown(); void handle_new_output(wlr_output* output); void start_ui_spike(); // slice-3 spike; never throws, may no-op + void register_hook(detail::HookBase& hook); // track for purge/disable - // toplevel.cpp - void handle_new_toplevel(wlr_xdg_toplevel* toplevel); - void handle_new_popup(wlr_xdg_popup* popup); - void focus_toplevel(Toplevel* toplevel); - auto toplevel_at(double lx, double ly, wlr_surface** surface, double* sx, double* sy) - -> Toplevel*; - void begin_interactive(Toplevel* toplevel, CursorMode mode, std::uint32_t edges); - void reset_cursor_mode(); + // server.cpp — extension host + void install(std::unique_ptr<Extension> extension); + void activate_extensions(); - // input.cpp + // input.cpp — devices, cursor, touch, seat (event-emitting glue) void handle_new_input(wlr_input_device* device); void new_keyboard(wlr_input_device* device); void new_pointer(wlr_input_device* device); void new_touch(wlr_input_device* device); void update_seat_capabilities(); - auto handle_keybinding(std::uint32_t keysym) -> bool; void attach_cursor_handlers(); void attach_seat_handlers(); - void process_cursor_motion(std::uint32_t time_msec); - void process_cursor_move(); - void process_cursor_resize(); + void emit_pointer_motion(std::uint32_t time_msec); +}; + +// ---- Per-extension Host facade ---------------------------------------------- + +class HostImpl final : public Host { +public: + HostImpl(Server::Impl* server, ExtensionId id) : server_(server), id_(id) {} + + auto display() -> wl_display* override { return server_->display; } + auto scene() -> wlr_scene* override { return server_->scene; } + auto seat() -> wlr_seat* override { return server_->seat; } + auto cursor() -> wlr_cursor* override { return server_->cursor; } + auto cursor_manager() -> wlr_xcursor_manager* override { return server_->cursor_mgr; } + auto output_layout() -> wlr_output_layout* override { return server_->output_layout; } + auto scene_layer(SceneLayer layer) -> wlr_scene_tree* override { + return server_->scene_layers[static_cast<std::size_t>(layer)]; + } + + auto on_output_added() -> Event<const OutputEvent&>& override { + return server_->ev_output_added; + } + auto on_output_removed() -> Event<const OutputEvent&>& override { + return server_->ev_output_removed; + } + auto on_pointer_motion() -> Event<const PointerMotionEvent&>& override { + return server_->ev_pointer_motion; + } + auto on_pointer_button() -> Event<const PointerButtonEvent&>& override { + return server_->ev_pointer_button; + } + auto on_pointer_axis() -> Event<const PointerAxisEvent&>& override { + return server_->ev_pointer_axis; + } + auto on_pointer_frame() -> Event<>& override { return server_->ev_pointer_frame; } + auto on_touch_down() -> Event<const TouchDownEvent&>& override { + return server_->ev_touch_down; + } + auto on_touch_motion() -> Event<const TouchMotionEvent&>& override { + return server_->ev_touch_motion; + } + auto on_touch_up() -> Event<const TouchUpEvent&>& override { return server_->ev_touch_up; } + auto on_touch_cancel() -> Event<const TouchCancelEvent&>& override { + return server_->ev_touch_cancel; + } + auto on_touch_frame() -> Event<>& override { return server_->ev_touch_frame; } + auto key_filter() -> Filter<KeyEvent>& override { return server_->key_filter; } + +protected: + auto extension_id() const -> ExtensionId override { return id_; } + + auto register_service(std::type_index type, void* impl) -> bool override { + const bool fresh = server_->services.emplace(type, impl).second; + if (!fresh) { + server_->services[type] = impl; // replace + } + return fresh; + } + auto lookup_service(std::type_index type) -> void* override { + auto it = server_->services.find(type); + return it == server_->services.end() ? nullptr : it->second; + } + void adopt_hook(detail::HookBase& hook) override { server_->register_hook(hook); } + auto surface_store() -> detail::PointerAssoc& override { return server_->surface_assoc; } + +private: + Server::Impl* server_; + ExtensionId id_; }; } // namespace unbox::kernel |
