summaryrefslogtreecommitdiffhomepage
path: root/packages/kernel/src/server_impl.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'packages/kernel/src/server_impl.hpp')
-rw-r--r--packages/kernel/src/server_impl.hpp226
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