Commit graph

2 commits

Author SHA1 Message Date
Breadway
6c4df8813c capsule: accept the open event breadbox can actually emit
An app may only publish inside its own bread.<app_id>.* namespace, so
breadbox (app id 'box') cannot emit bread.command.box.open — bread-client
refuses it and the redirect did nothing but log a warning. The capsule now
also subscribes to bread.box.open_requested, which is what breadbox emits.

bread.command.box.open is kept as well: that is the addressed-to-an-app
command form an external trigger (the bread CLI, a keybind, another app)
would legitimately send, so the capsule opens whether it was asked directly
or told by breadbox.
2026-08-31 15:45:25 +08:00
Breadway
e52c507f32 capsule: keyboard open, query modes, sections, and search-state geometry (phase 6c)
Completes the spotlight capsule (theme 04), THEME_SYSTEM_PLAN.md §7:

- Keyboard open (item A): a new launcher_command module subscribes to
  bread.command.box.open — only when the active theme's launcher is
  Embedded — and focuses launcher_entry on receipt, which the existing
  EventControllerFocus::connect_enter already turns into an open_fn()
  call, same path a mouse click into the entry takes. breadbox's own
  keybind-triggered launch now redirects to this same event under an
  embedded theme instead of stacking its overlay window on top (see the
  breadbox commit).

- Click-away scrim (item B): open_fn/close_fn now show/hide panel.rs's
  dismiss surface via the new show_capsule_dismiss/hide_dismiss, and
  panels.set_on_dismiss(close_fn) wires a click-away into the capsule's
  own close path. The scrim's clickable region starts at a fixed offset
  (capsule row height + the drawer's own maximum content height,
  DRAWER_MAX_HEIGHT_PX) rather than the drawer's live height, so it can
  never geometrically overlap a rendered result row regardless of
  breadbar-dismiss's overlay layer always rendering above the bar's own.

- Query modes (item C): connect_changed now runs bread_launcher::parse_query
  against the entry text and, when the parsed prefix is listed in
  [launcher].modes, swaps launcher_results.scroller for a new mode_list
  populated by populate_mode_list (calc result / filtered commands / an
  "open this URL" prompt). key_ctrl routes Up/Down/Return at whichever
  list is active; a `>`/`.` row's action runs through the new ModeAction
  enum (RunShell for a command's own fixed exec string, OpenUrl straight
  to xdg-open) so arbitrary typed text is never passed through a shell.

- Sections (item D): ResultsList::new's new `sections` bool is threaded
  from [launcher].sections.

- Search-state geometry (item E): root's own width now spring-animates
  between [launcher].width and .search_width (animate_capsule_width, same
  set_size_request-driven technique animate_drawer_height already uses),
  and a `.searching` class on root switches border-radius to
  .search_radius via a new CSS rule/transition in theme.rs.

Also fixes a real bug this surfaced: drawer_target_height was measuring
drawer_box itself, whose size_request is continuously overwritten by
animate_drawer_height's own tick callback — GTK clamps a widget's
measure() up to at least its own explicit size request, so switching from
the (tall) app list to a one-row calc result measured the PREVIOUS
frame's forced height instead of the new content's actual size. It now
sums each visible child's own natural height directly, which also fixes
the same latent issue for narrowing app-search results.

screenshot.rs gains two new views (capsule-sections, capsule-calc) to
exercise D and C's calc path.
2026-08-31 15:45:25 +08:00