diff options
| author | Adam Malczewski <[email protected]> | 2026-06-15 18:43:12 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-15 18:43:12 +0900 |
| commit | e73dfd27ba95d42b80c90d622250ad1f3be9bf33 (patch) | |
| tree | 309ecf439e66726598847f5d06b767fa47586c9a /packages/kernel/src/ui_substrate.cpp | |
| parent | 38f0091c64523cbda8c080c0525c74e725f40c87 (diff) | |
| download | unbox-e73dfd27ba95d42b80c90d622250ad1f3be9bf33.tar.gz unbox-e73dfd27ba95d42b80c90d622250ad1f3be9bf33.zip | |
kernel(rml-compositing): surface-element box readback, per-row drag, xdg-decoration
- SurfaceElement::rendered_width()/height(): read back the RCSS-resolved root
<img> content box (the substrate already computes it for popup placement) so a
window manager can size a client to its on-screen tile. Reading geometry, not
computing it -- RCSS still owns layout.
- UiSurface::bind_list_drag(list, name, cb(row, phase, x, y)): the per-row drag
binding (list analogue of bind_drag + bind_list_event), for per-window move and
resize in a data-for list.
- Expose wlr_xdg_decoration_v1 through the wlr wrapper (for ext-xdg-shell's
server-side-decoration negotiation).
Diffstat (limited to 'packages/kernel/src/ui_substrate.cpp')
| -rw-r--r-- | packages/kernel/src/ui_substrate.cpp | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/packages/kernel/src/ui_substrate.cpp b/packages/kernel/src/ui_substrate.cpp index 5971c56..a6a5bfa 100644 --- a/packages/kernel/src/ui_substrate.cpp +++ b/packages/kernel/src/ui_substrate.cpp @@ -42,6 +42,7 @@ #include <list> #include <string> #include <unordered_map> +#include <utility> #include <vector> // The installed asset root, resolved against for a RELATIVE UiSurfaceSpec:: @@ -447,6 +448,15 @@ struct Surface { Substrate::Impl* owner; }; std::list<ListEventBinding> list_event_bindings; + // Per-row drag callbacks (bind_list_drag): combine the drag phase + surface- + // local x/y (like DragBinding) with the row index from the data expression's + // first argument (like ListEventBinding). Same error-isolation boundary. + struct ListDragBinding { + std::function<void(std::size_t, UiSurface::DragPhase, double, double)> cb; + ExtensionId who; + Substrate::Impl* owner; + }; + std::list<ListDragBinding> list_drag_bindings; // touch-mode-changed notification (one per surface; see ui.hpp). Fired on a // transition, error-isolated to `who`. touch-mode does NO visual scaling @@ -865,6 +875,13 @@ struct Substrate::Impl { // after the tree was re-walked. Idempotent per frame. void layout_surface_element_children(SurfaceElementState& el); + // The resolved on-screen content box (px) of this element's ROOT <img> in the + // FIRST ui surface document that hosts it (ui.hpp SurfaceElement:: + // rendered_width/height — the kernel reading back RCSS's computed rectangle). + // {0,0} when no laid-out document hosts the element yet. + [[nodiscard]] auto surface_element_rendered_size(const SurfaceElementState& el) const + -> std::pair<int, int>; + // ---- surface-element input-back ---- // Resolve a hovered RmlUi element to the surface-element NODE it samples (its // <img src> is a node URI), walking up parents. Returns null if the pick is @@ -1942,6 +1959,25 @@ void Substrate::Impl::layout_surface_element_children(SurfaceElementState& el) { } } +auto Substrate::Impl::surface_element_rendered_size(const SurfaceElementState& el) const + -> std::pair<int, int> { + // Read back the rectangle RCSS laid the root <img> out to (the same resolved + // content box used for child placement above). First hosting document wins; + // {0,0} before any document has laid it out. GetClientWidth/Height are the + // element's content-box dimensions in document px — exactly the texture's + // drawn box. Rounded to whole px (a client buffer size is integral). + for (const Surface& surf : surfaces) { + Rml::Element* root_img = find_img_by_src(surf.document, el.root.uri); + if (root_img == nullptr) { + continue; + } + const int w = static_cast<int>(root_img->GetClientWidth() + 0.5F); + const int h = static_cast<int>(root_img->GetClientHeight() + 0.5F); + return {w, h}; + } + return {0, 0}; +} + // ---- Surface-element input-back (pick -> surface-local -> wl_seat) ----------- // // Port of the spike's route_point: the substrate already feeds pointer/touch @@ -3061,6 +3097,44 @@ void SurfaceHandle::bind_list_event(std::string_view /*list*/, std::string_view }); } +void SurfaceHandle::bind_list_drag( + std::string_view /*list*/, std::string_view name, + std::function<void(std::size_t, UiSurface::DragPhase, double, double)> callback) { + // The per-row drag binding = bind_drag (phase from the event id, x/y from the + // event's surface-local mouse_x/mouse_y) + bind_list_event (row index from the + // data expression's first argument, it_index). The event name is model-global + // (like bind_list_event) so `list` is documentary; keep names unique. Survives + // dev hot-reload like every binding (registered once on the open ctor). + Surface& s = *surface_; + if (!s.ctor) { + return; + } + s.list_drag_bindings.push_back({std::move(callback), s.who, s.owner}); + Surface::ListDragBinding* binding = &s.list_drag_bindings.back(); + s.ctor.BindEventCallback( + std::string(name), + [binding](Rml::DataModelHandle, Rml::Event& ev, const Rml::VariantList& args) { + try { + if (!binding->cb) { + return; + } + UiSurface::DragPhase phase = UiSurface::DragPhase::move; + drag_phase_for(ev.GetId(), phase); + std::size_t row = 0; + if (!args.empty()) { + row = static_cast<std::size_t>(args[0].Get<int>()); + } + const double x = static_cast<double>(ev.GetParameter<float>("mouse_x", 0.0F)); + const double y = static_cast<double>(ev.GetParameter<float>("mouse_y", 0.0F)); + binding->cb(row, phase, x, y); + } catch (...) { + if (binding->owner->disable) { + binding->owner->disable(binding->who); + } + } + }); +} + void SurfaceHandle::on_touch_mode_changed(std::function<void(bool)> callback) { surface_->touch_mode_cb = std::move(callback); } @@ -3169,6 +3243,12 @@ SurfaceElementHandle::~SurfaceElementHandle() { auto SurfaceElementHandle::source_uri() const -> std::string { return state_->root.uri; } auto SurfaceElementHandle::width() const -> int { return state_->root.width; } auto SurfaceElementHandle::height() const -> int { return state_->root.height; } +auto SurfaceElementHandle::rendered_width() const -> int { + return substrate_->impl_->surface_element_rendered_size(*state_).first; +} +auto SurfaceElementHandle::rendered_height() const -> int { + return substrate_->impl_->surface_element_rendered_size(*state_).second; +} void SurfaceElementHandle::focus_keyboard() { substrate_->impl_->focus_keyboard(*state_); } |
