Repository navigation
refactor: split central state, engine-switch fixes, SpatialState (0.90.201–0.90.209) - #14
Merged
Merged
Conversation
Resolve the restored tiled size before with_pending_state holds Smithay's surface lock. BSP layout reads client minimum hints via with_states and otherwise tries to acquire that same mutex on the event-loop thread. Confirmed with all-thread GDB traces from the hung unstripped nested build. A two-client real-protocol regression fails on the previous code with a bounded watchdog; WM toggles and client fullscreen requests now restore the tiled size and remain responsive. Bump to 0.90.201. Validation: fmt, 709 all-feature/all-target tests, strict Clippy and release build; minimized GTK reproduction and two 61-observation nested runs. The repeated runs compare identically; the sole difference from the original baseline is successful Classic unfullscreen. Native activation is not run.
Move Smallvil::new and init_wayland_listener verbatim into the approved initialization domain. Rename state.rs to state/mod.rs; retain the struct, shared types, remaining methods, free helpers and tests there. Move initialization-only imports into the child module. No method or field visibility changes, forwarding methods, behavior changes or formatting of method bodies. Method source matches the previous file byte for byte. Validation: fmt, 709 locked all-feature/all-target tests and strict Clippy.
Move the approved emit_state_change_events, ipc_seen_state, emit_ipc_event, flush_ipc_subscribers, arm_ipc_flush_timer and remove_ipc_subscriber methods verbatim into a child impl Smallvil. Keep IPC fields, shared types and tests in state/mod.rs; has_lua_handler stays with configuration coordination. No visibility or import changes. Existing pub(crate) entry points retain their visibility; ipc_seen_state and remove_ipc_subscriber remain private. No behavior changes, forwarding methods or method-body formatting. Validation: source reconstruction is byte-identical, fmt, 709 locked all-feature/all-target tests and strict Clippy pass.
Move the nine approved methods verbatim to state/config_reload.rs and retain fields, shared types and tests in state/mod.rs. Remove the final method's separator when joining the remaining impl; no method-body formatting. Required visibility change: has_lua_handler becomes pub(super) because the IPC child module calls it. Other method and all field visibility stays as-is. No new accessors, ownership, behavior changes or dependencies. Validation: source identity checks, fmt, 709 locked all-feature/all-target tests and strict Clippy pass. Full batch runtime/release checks follow.
Move the 23 approved methods to state/workspace.rs without changing bodies, fields, shared types, tests or ownership. No forwarding methods or dependencies. Required private-to-pub(super) changes: resolve_window_rules_on_workspace, workspace_of_surface and apply_workspace_switch have callers in the remaining state impl or other approved child modules. All other visibility stays as-is. Validation: source identity/reconstruction, fmt, 709 locked all-feature/ all-target tests and strict Clippy pass. Batch runtime/release checks follow.
Move the 21 approved methods verbatim to state/render.rs; keep fields, shared types, free helpers and tests in state/mod.rs. Preserve method attributes and all existing call paths, without forwarding methods or dependencies. Required private-to-pub(super) changes: placement_visual_sample, rendered_rect_on_output, request_surface_redraws and placement_physical_rect. The remaining state impl still calls these helpers. No other visibility changes. Validation: source identity/reconstruction, fmt, 709 locked all-feature/ all-target tests and strict Clippy pass. Batch runtime/release checks follow.
Move all 57 approved methods with unchanged bodies/docs to state/focus.rs. Keep fields, shared types and tests in state/mod.rs. No new forwarding API, ownership changes, dependencies or behavior changes. Required private-to-pub(super) changes: release_popup_grab, refocus_after_hide and neighbor_in_direction, for existing state/workspace callers. All other method and field visibility stays unchanged. Validation: byte-identity/reconstruction, 709 locked all-feature/all-target tests and strict Clippy pass. The widened neighbor signature needs a line wrap; apply that formatting in its own following commit, not in this move.
Move the 19 approved methods with unchanged bodies/docs into state/scroll.rs. Keep fields, shared types, free helpers and tests in state/mod.rs. No accessors, forwarding API, ownership changes, dependencies or behavior changes. Required private-to-pub(super) changes: queue_scroll_pointer_refresh, scroll_axis_step, scroll_focus_target, anchor_scroll_floaters, rescue_scroll_floaters, floating_bounds and scroll_columns_changed, because remaining state or the focus child calls them. No other visibility changes. Validation: source identity/reconstruction, fmt, 709 locked all-feature/ all-target tests and strict Clippy pass. Batch runtime/release checks follow.
Move the 26 approved methods verbatim to state/session.rs, retaining existing accessibility feature guards and all bodies/docs. Fields, shared types, free helpers and tests remain in state/mod.rs. No new ownership or forwarding API. Required private-to-pub(super) changes: lock_focus_target, handle_client_disconnect and schedule_accessibility_sync, for existing calls from focus, init and render child modules. All other visibility stays as-is. Validation: source identity/reconstruction, fmt, 709 locked all-feature/ all-target tests and strict Clippy pass. Batch/default-feature checks follow.
Move the 40 approved methods to state/effects.rs with unchanged bodies, docs, attributes and feature guards. Keep fields, shared types, free helpers and tests in the parent. No forwarding API, dependency or behavior changes. Required private-to-pub(super) changes for existing callers: layer_dim_amount, queue_shader_failure, window_render_alpha_for, rounding_config_for_surface, rounding_applies, rounding_or_cascade_shader_possible, borders_possible, animated_borders_possible, surface_has_animated_border, window_border_element, shadows_possible, window_shadow_element. Validation: source identity/reconstruction, 709 locked all-feature/all-target tests and strict Clippy pass. Any needed formatting follows separately; full batch release/default-feature/runtime checks follow the remaining moves.
Move the 34 approved methods to state/physics.rs with unchanged bodies, docs, attributes and feature guards. Keep fields, shared types, free helpers and tests in the parent. No forwarding API, dependency or behavior changes. Required private-to-pub(super) changes for existing callers: interactive_motion_half_life, sway_enabled_for_surface, sync_float_physics_bodies, currents_enabled, cascade_liquid_applies, start_window_move_animation, focus_window_with_ripple, retile_with_viscosity. Validation: source identity/reconstruction, 709 locked all-feature/all-target tests and strict Clippy pass. Any needed formatting follows separately; full batch release/default-feature/runtime checks follow the remaining moves.
Move the 18 approved methods to state/ocean.rs with unchanged bodies, docs, attributes and feature guards. Keep fields, shared types, free helpers and tests in the parent. No forwarding API, dependency or behavior changes. Required private-to-pub(super) changes for existing callers: topmost_ocean_surface, caustics_active, retile_ocean, migrate_classic_to_ocean, migrate_ocean_to_classic, ocean_focus_target. Validation: source identity/reconstruction, 709 locked all-feature/all-target tests and strict Clippy pass. Any needed formatting follows separately; full batch release/default-feature/runtime checks follow the remaining moves.
Move the 36 approved methods to state/groups_depth.rs with unchanged bodies, docs, attributes and feature guards. Keep fields, shared types, free helpers and tests in the parent. No forwarding API, dependency or behavior changes. Required private-to-pub(super) changes for existing callers: depth_live_alpha, poll_depth_background, custom_shader_last_stage, group_activate_tab, toggle_column_tabbed, restore_all_depth_deck_windows. Validation: source identity/reconstruction, 709 locked all-feature/all-target tests and strict Clippy pass. Any needed formatting follows separately; full batch release/default-feature/runtime checks follow the remaining moves.
Move the 60 approved methods to state/spatial.rs with unchanged bodies, docs, attributes and feature guards. Keep fields, shared types, free helpers and tests in the parent. No forwarding API, dependency or behavior changes. Remove the emptied parent impl and relocate its spatial-migration section marker beside the unchanged migration methods. Required private-to-pub(super) changes for existing callers: enforce_floating_size_constraints_with_rule, is_floating, float_body_context, placement_input_rect, translate_floating_window, window_at_layout_position, window_surface_elements, retile_filtered, move_window_to_output, spatial_is_tiled, spatial_tiled_window, spatial_tiles_share_owner, allocate_ui_node_id. Validation: source identity/reconstruction, 709 locked all-feature/all-target tests and strict Clippy pass. Any needed formatting follows separately; full batch release/default-feature/runtime checks follow the remaining moves.
Replace `use super::*` in the 13 state child modules with explicit
imports: smithay/std/crate paths each module actually uses, plus
`use super::{...}` for the parent's fields' types and free helpers.
Two accessibility-only imports in session.rs are gated on that feature.
state/mod.rs drops the imports only its children used; the tests module
keeps `use super::*` and gains RenderElementStates, which only tests use.
Everything after the import blocks is byte-identical to ba8b06a. No
visibility, ownership or behavior changes.
Validation: fmt, 709 all-feature/all-target tests, strict Clippy with
all and default features, all-feature release build; clean checks with
screencast-only and accessibility-only features. Nested matrix with
subscribers: 61 observations, 0 differences vs .206 and the fixed
baseline.
New real-protocol test on two simulated outputs: tiled windows on two workspaces and both outputs, a floating window, a pinned window, a tab group and a fullscreen window go Classic -> Ocean -> Scroll -> Classic -> Scroll -> Ocean -> Classic. After every step each window has exactly one spatial owner, and focus, pin, fullscreen output, group membership and floating state are unchanged. Classic <-> Scroll leaves membership identical, and every return from Ocean restores the starting workspace membership and floating rectangle exactly. The child process runs with private XDG directories and a 10 s deadline, the same isolation as the fullscreen regression test; floating_placement fixture items become pub(super) so both tests share them. 710 tests, fmt and strict Clippy (all and default features) pass. No production code changes.
Switching to Ocean turned scratchpad workspace 0 into a reef exactly on top of workspace 1 and a named scratchpad into a reef at x = i32::MAX. Switching back renumbered the overlapping reefs in no fixed order (a normal tile could land on workspace 2), and the scratchpad windows came back as ordinary visible workspaces. Scratchpad trees and unpinned scratchpad floaters now stay in their workspace storage while Ocean runs. Ocean renders neither, so they stay hidden, and they come back exactly as they were. A shown scratchpad points the camera at the workspace it was opened from. Pinned floaters still migrate, since they show on every workspace. Every engine change also lost the stacking order of floating windows: both directions moved them in HashMap order, and Classic/Scroll remapped them that way too. The switch now records the order (Space bottom to top, or Ocean's front-to-back stack), drains Ocean floaters in stack order, and pushes and remaps them in that order. Layouts::drain_for_migration takes a keep predicate and unindexes only the trees it drains. New regression test (red on the old code, green three runs in a row): six stacked floaters, a scratchpad and a named scratchpad through Classic -> Ocean -> Classic -> Scroll -> Classic. 711 tests, fmt, strict Clippy with all and default features; nested matrix with subscribers: 61 observations, 0 differences.
SpatialEngine mixed two questions: who owns placement (numbered workspaces or the Ocean world) and how a workspace shows its tiles (Classic or Scroll). Add SpatialOwnership and WorkspaceProjection, with SpatialEngine::ownership() and projection(), and rewrite every runtime engine check to the axis it actually tests: - == / != Ocean -> ownership() == / != SpatialOwnership::Ocean - == / != Scroll|Classic -> projection() == / != Some(...) - uses_workspaces() -> ownership() == Workspaces (method removed) - Classic | Scroll => ..., Ocean => ... matches -> match ownership() - migration dispatch and tide_workspace_value -> ownership() Each rewrite is equivalent case by case; matches that need the whole engine (names, the engine list in tests) keep SpatialEngine. The public `engine = classic|scroll|ocean` config is unchanged. 711 tests, fmt, strict Clippy with all and default features pass.
config.spatial_engine was both the config file's request and the
running engine: migrate_spatial_engine wrote the live value back into
config, and reload patched new_config after a refused migration so the
two would not disagree.
New Smallvil::spatial: SpatialState { engine } holds the running engine,
and only migrate_spatial_engine changes it. Every runtime read (132
sites) goes through self.spatial.engine. config.spatial_engine now only
records what the file asks for: reload migrates whenever the request
differs from the running engine, and a refused migration leaves the
request in place instead of patching it. A later reload therefore still
retries, and after a live `engine:` action a reload still returns to
the file's engine, both as before.
Step 8 moves the workspace and Ocean ownership state into SpatialState.
New test: a migration refused for lack of an output keeps the request,
and the next reload of the same file performs it. 712 tests, fmt, strict
Clippy with all and default features; nested matrix with subscribers:
61 observations, 0 differences vs .208.
surface_under, window_under and fullscreen_surface_under did not split on ownership: Classic finds windows under the pointer through Space, while Scroll and Ocean go through render_placements, which carry their view offsets. Add SpatialState::hit_tests_through_space() and use it at those three checks. Same predicate, same behavior. Step 7's planned per-operation dispatch otherwise does not fit the code, and Fiw chose to shrink it: focus targeting already branches once at the top, map_toplevel's Ocean checks are interleaved with shared logic, and output removal is the same for every engine. 712 tests, fmt, strict Clippy with all and default features; nested matrix with subscribers: 61 observations, 0 differences vs .208.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Covers architecture-plan steps 5–7 plus two bug fixes. Source goes from
0.90.200to0.90.209. Every commit is signed, and each refactor commit is pure relocation or a mechanical rewrite, with the evidence noted per commit.Behavior changes
f929041,.201). Leaving fullscreen on a tiled window called the layout from insidewith_pending_state, so the same surface mutex was locked twice and the compositor hung. The tiled size is now worked out before the closure. The regression test fails before the fix and passes after.92b549f,.208). Switching to Ocean turned scratchpad workspace 0 into a reef exactly on top of workspace 1, and a named scratchpad into a reef atx = i32::MAX. The return then renumbered workspaces nondeterministically and turned scratchpads into ordinary visible workspaces. Scratchpad trees and their unpinned floaters now stay parked in workspace storage while Ocean runs, and come back as they were.92b549f). Migration used to move floaters inHashMaporder.Refactor, no behavior change
state.rs(about 16k lines) becomesstate/mod.rsplus 13 domain modules: init, ipc, config_reload, workspace, render, focus, scroll, session, effects, physics, ocean, groups_depth and spatial.Smallvilmethods and every field are byte-identical tof929041.pub(super), and the commits list each one.use super::*in every child module (d0ea005).407645c): Classic→Ocean→Scroll→Classic→Scroll→Ocean→Classic with tiled, floating, pinned, grouped and fullscreen windows.SpatialOwnership/WorkspaceProjectionaxes (0f96644).SpatialState { engine }as the single live engine value;config.spatial_engineis now only the file's request (c782b28).4b2bd74).Verification
.201fullscreen and.209both pass a startup probe and 12 WM + 4 client fullscreen round trips, with state restored..209, a live Ocean round trip kept the scratchpad parked and restored the desktop exactly.Known, not changed here: an Ocean round trip resets each Scroll strip's view offset, and Ocean→Classic pulls off-screen floaters on-screen. Both are tracked separately.