Commit Graph
303 Commits
Author SHA1 Message Date
aiongg ba00e9fd9e craft-ui: end drags and resizes on a focus loss, not while a window reports no focus
egui-winit starts RawInput::focused false and only a winit Focused event
sets it. A window that egui never heard was focused cancelled every tab,
group and window drag and every resize on its first frame. Gestures now
end on a focused-to-unfocused transition (or Escape); a window that
never reported focus still drags while the pointer is pressed in it.
2026-10-24 03:45:08 +00:00
aiongg 09e14347d3 Merge branch 'docking' into dock-windows 2026-10-24 03:44:56 +00:00
aiongg 2f90228e10 docking: a narrow group splits when its neighbours have room for both halves
A side split that leaves a half at its minimum is taken when the
dividers along that half can still travel, the groups beyond giving
way as they do for a dragged divider. An 80 pt group, whose halves
need 84, splits on all four sides and takes the rest from its
neighbour; only when the groups beyond are at their minimums too does
the drop join the group's tabs.
2026-10-24 03:41:27 +00:00
aiongg 308163bcb5 docking: macOS resizes native windows itself, bands elsewhere are 6 pt with 16 pt corners
On macOS the native window is resizable by AppKit again, with its own areas
and cursors. The bar's buttons sit 19 pt in from the trailing edge, clear of
AppKit's corner area (about 15 pt into the window, a 19 pt square measured on
macOS 26), and the window sets no cursor of its own over AppKit's areas.
Elsewhere the bands are 6 pt deep with 16 pt corner Ls, and hand the resize
to the window system; the manual resize path is gone.
2026-10-24 03:40:17 +00:00
aiongg 2cad4d2bec docking: clippy, a type for a split's children and one argument for a node and its rect 2026-10-24 03:13:34 +00:00
aiongg 1c24845a17 Merge branch 'docking' into dock-windows 2026-10-24 03:13:34 +00:00
aiongg 1ccdad9512 docking: Floating::with_id for layouts built in code; debug builds warn about rebuilt layouts
Floating::new, single and stack draw a fresh id on each call, so a layout
built anew each frame opened a new OS window each frame. with_id gives such
a layout the same windows every frame. Debug builds log a warning once when
three frames running replace every native window with new ones holding the
same panels.
2026-10-24 03:09:14 +00:00
aiongg cb352b39ff docking: all four drop zones of a group share one depth
Each side zone reaches zone_depth into the body, or a quarter of the
body's smaller side when that is less. A tall narrow group's top and
bottom zones are no deeper than its left and right ones.
2026-10-24 03:06:11 +00:00
aiongg 99d8fe537e docking: a dragged divider shrinks the groups beyond it in turn
A divider dragged past the minimum of the group it shrinks moves on to
the next group along the axis, and so on until every group on that side
is at its minimum. The line follows same-axis splits up the tree and
ends at a split across the axis or beside a dock. Groups touching the
divider on the other side grow, up to their maximums, as before.

Stacked panels and the groups of a dock column cascade the same way.
2026-10-24 03:05:32 +00:00
aiongg b892ec92e2 docking: native window bar buttons win over the resize bands, corners are 4 pt Ls
The bands along a native window's edges leave out the bar's buttons, which
sit 4 pt in from the window's edge. Each corner is an L, 4 pt deep and 12 pt
along both edges. macOS windows are not resizable by AppKit, whose resize
areas reach over the ×; the bands resize them by InnerSize and OuterPosition,
since winit has no BeginResize there.
2026-10-24 03:05:03 +00:00
aiongg 1546cef8d9 docking: Escape in a native window that doesn't own a drag cancels it, whichever window owns it 2026-10-24 00:33:17 +00:00
aiongg 0008f89212 Merge branch 'docking' into dock-windows
Native windows draw a frame's drop zones through the destination window's
painter, and the bar-docking test aims inside the 40 pt right band.
2026-10-24 00:00:43 +00:00
aiongg e6c76f5151 docking: drop zones are 40 pt bands below the tab strip, all outlined while dragging
A frame's side zones reach DockStyle::zone_depth (40 pt) into the body below
the tab strip, or a third of a smaller body, so a frame keeps its center.
drop_zone, zone_shape and resolve_drop take the depth. In the Frame style a
drag over a frame outlines every zone a drop there would change something in
and fills the one under the pointer, without the outline of the resulting rect.
2026-10-23 23:57:43 +00:00
aiongg 46a49971c7 docking: format 2026-10-23 18:06:20 +00:00
aiongg 909410258b docking: document native window placement, moves and mixed scale factors 2026-10-23 18:06:10 +00:00
aiongg e2b452482a docking: an example with native floating windows 2026-10-23 18:05:09 +00:00
aiongg 37b6a0dc25 docking: native windows move only on a pointer move of their frame
- A bar drag reads this frame's pointer moves only. egui keeps the last
  pointer position, measured against where the window was then; reused
  after the window moved, it crept the window on.
- Escape pressed in any of the application's windows cancels a drag a
  native window owns.
- DockContent::allow_native defaults to true: the feature is the opt-in.
- DockOutput::forwarded_modifiers tells Cmd/Ctrl+C, X and V, which
  egui-winit sends as Copy, Cut and Paste, from those keys.
2026-10-23 18:05:09 +00:00
aiongg 98e05997a0 docking: native windows place by their content and follow the layout
- A window made this session opens at its computed rect; only windows of a
  loaded layout are restored onto a connected monitor.
- The content (inner rect) is each native window's desktop origin; only
  OuterPosition converts to the outer position.
- A bar drag places the window from its reported position, so late moves
  do not overshoot. The layout follows once the drag ends, and a window
  left with its bar off every monitor goes back onto the nearest.
- A changed Floating::native (undo, reset, reload) moves the OS window
  instead of being overwritten by its next report.
- Dragging a native window's only tab or group docks it whatever
  title_bar_docks says.
- Escape that cancels a drag is consumed; nothing is forwarded while a
  widget of the window has focus.
- A bar drag whose window goes away ends.
- An embedded fallback keeps its drop targets; floating windows get no
  taskbar entry.
- The test host can give windows a frame inset and land moves a frame late.
2026-10-23 17:55:03 +00:00
aiongg 0ac8f80f64 docking: a loaded layout's monitor and monitor size are validated 2026-10-23 17:55:03 +00:00
aiongg e19b1b684d docking: a restored native window opens where its bar can be grabbed 2026-10-23 17:48:12 +00:00
aiongg 137845d6f4 docking: clamping a native window onto a fractional monitor origin cannot panic 2026-10-23 17:42:37 +00:00
aiongg 783793cbbc docking: document where a native window's bar docks it 2026-10-23 17:31:11 +00:00
aiongg b46b9dd5c1 docking: a native window's bar docks it at the main window's frame edges
The window docks as its groups at a frame's edge zones, as a group drag would; a body's
center still takes no whole window. Tests for Escape during a bar drag and for the
window focused last being in front.
2026-10-23 17:31:11 +00:00
aiongg 619c93ea29 docking: document drags between OS windows 2026-10-23 17:24:25 +00:00
aiongg 84b42eacc9 docking: tabs, groups and windows drag between OS windows
The window where a drag starts owns it and writes its pointer with its desktop origin.
The window under that point shows the preview with its own targets, and the release
docks there, or floats a new window over the desktop. Leaving a window is no release
with native viewports. Dragging the only tab or group of a window moves it, and its
bar docks the whole window.
2026-10-23 17:24:25 +00:00
aiongg 141ddc92f6 docking: which window lies under a desktop point 2026-10-23 17:24:19 +00:00
aiongg 48272d3932 docking: the host stand-in needs no expect, and the label count drops with New Window 2026-10-23 16:42:36 +00:00
aiongg 0ecc7d2d39 Merge remote-tracking branch 'ao/docking' into dock-windows 2026-10-23 16:42:21 +00:00
aiongg e350bfdb01 docking: the undock hint test uses contains, as clippy asks 2026-10-23 16:40:17 +00:00
aiongg e23e447f32 Merge remote-tracking branch 'ao/docking' into dock-windows 2026-10-23 16:35:58 +00:00
aiongg 53947dbfe8 docking: the undock hint test expects the platform's key 2026-10-23 16:35:35 +00:00
aiongg 99f4511e6d docking: document native windows 2026-10-23 08:27:19 +00:00
aiongg 06c1fc8825 docking: DockDriver stands in for OS windows, and native window tests
with_native_host draws native windows as their own egui frames with a
desktop rect, focus, close requests and the commands they receive. Tests
cover each way into a native window, closing, stable ids, place and
monitor, restore, the bar drag, hiding and forwarded keys.
2026-10-23 08:27:19 +00:00
aiongg 799ab4e691 docking: every float opens in its own OS window
With native-windows on a backend with viewports, each floating window
whose panels allow it is native: in-window floats open over their place
in the app window, and restored windows go back to their monitor or onto
the main window's. Windows stay on top and hide while the app is
inactive. A thin bar with title and close replaces the OS title bar and
moves the window; closing the window closes its panels. Keys a native
window leaves unused come back in DockOutput::forwarded_events, and
DockArea::monitors takes the monitor list. Move Panel to New Window goes,
since every float is native.
2026-10-23 08:27:13 +00:00
aiongg 9c869166e8 docking: floating windows keep a stable id and store their monitor
Floating::id names a window across panel moves: fresh from Floating::new
and on load, unique within a loaded layout, kept by a whole window that
moves and by the receiver of a merge. Floating::monitor and monitor_size
record where a native window is; Action::SetMonitor sets them. Equality
ignores the id.
2026-10-23 08:26:56 +00:00
aiongg 01ce7162a4 docking: Floating::stack is public, and four-way handles take the pointer only
Floating::stack builds a window from groups stacked top to bottom, so an
app's own stacked layouts migrate without building the split chain. The
four-way handle no longer takes keyboard focus: it has no label or key
action, and the two dividers it joins take arrow keys.
2026-10-23 06:11:03 +00:00
aiongg 50f9c06aa7 Merge remote-tracking branch 'upstream/main' into docking
# Conflicts:
#	crates/ui/src/docking/surface.rs
2026-10-23 05:06:13 +00:00
Dylan M. Taylor 4919088427 Merge pull request #238 from dylanmtaylor/security/media-allocation-bounds
security: bound craft-media metadata, sample reservation, header stripping and cue bookkeeping (CodeRabbit)
2026-10-22 22:42:59 -04:00
Dylan M. Taylor c67b1e16b8 Merge pull request #236 from dylanmtaylor/security/docking-group-move-permission
security: require every floating-group member to be movable for MoveFloating (CodeRabbit)
2026-10-22 22:42:36 -04:00
Dylan M. Taylor f0d9c32e67 Merge pull request #237 from dylanmtaylor/security/print-parsing-bounds
security: bound print dialog names, PPD labels, lpstat merge and inherited page geometry (CodeRabbit)
2026-10-22 22:26:23 -04:00
Dylan M. Taylor f721e1b969 Merge pull request #234 from dylanmtaylor/security/cms-eval-work
security: bound cms CLUT interpolation and inverse-curve table work (CodeRabbit)
2026-10-22 22:26:18 -04:00
Dylan M. Taylor c0a3d4c08c media: charge metadata at its converted length, before converting
Lossy UTF-8 conversion can triple invalid bytes, and a fallback key such as ©nam is five
bytes, not four. The budget now charges the length the text will be stored at, computed
without allocating, before the value is converted (CodeRabbit review).
2026-10-22 22:25:45 -04:00
Dylan M. Taylor fd9cf54c48 ui: test that a protected member blocks the floating group's resize grip
Drags the resize grip of sample()'s floating group: a movable group emits MoveFloating,
one with a protected member emits none. Fails without the surface.rs check (CodeRabbit
review nitpick).
2026-10-22 22:23:27 -04:00
Dylan M. Taylor bc8fe0eb53 cms: keep NaN propagation in multilinear interpolation
A NaN input gives a NaN fraction, which the active-dimension check dropped, returning a
finite node value. Keep any nonzero fraction, NaN included (CodeRabbit review).
2026-10-22 22:22:39 -04:00
Dylan M. Taylor 4d30617bcf Merge pull request #235 from dylanmtaylor/security/settings-section-merge
security: validate settings sections against the defaults alone (CodeRabbit)
2026-10-22 22:22:11 -04:00
Dylan M. Taylor b7d92278fe Merge pull request #233 from dylanmtaylor/security/ai-core-bounds
security: bound ai-core redaction and template rendering; consent for params-only requests (CodeRabbit)
2026-10-22 22:22:06 -04:00
Dylan M. Taylor ecf0ad47ad security: bound craft-media metadata, sample reservation, header stripping and cue bookkeeping
Follow-up to the hostile-input fixes in #196, covering findings that PR does not:

- ISO BMFF metadata: all udta/meta entries share a 4 MiB budget charged before a keys name
  is copied, so many ilst items naming one long key cannot multiply it (CodeRabbit CWE-400,
  isobmff/demux.rs:939)
- ISO BMFF stbl: reserve only the samples the chunk map can place, fallibly, instead of the
  declared stsz count (CodeRabbit CWE-789, isobmff/demux.rs:767)
- Matroska: a header-stripping prefix over 256 bytes is treated as unsupported compression
  rather than copied in front of every frame; Track::sample_size no longer allocates the
  prefix (CodeRabbit CWE-409, matroska/track.rs:257)
- Matroska muxer: per-track cue flags use a cluster number, so starting a cluster no longer
  clears every declared track (CodeRabbit CWE-407, matroska/mux.rs:402)
2026-10-22 21:53:10 -04:00
Dylan M. Taylor 4f85efb2b9 security: bound print dialog name resolution, PPD labels, lpstat merge and inherited geometry
- craft-ui shown_names resolves label collisions with hash-map counts and a worklist, so a
  crafted cascade is linear instead of cubic (CodeRabbit CWE-407, ui/src/printing.rs:32)
- parse_ppd caps group, option and choice labels at 256 characters before each option copies
  its group (CodeRabbit CWE-400, print/src/lib.rs:232)
- printers_parsed tracks seen destinations in a HashSet (CodeRabbit CWE-407, lib.rs:417)
- sheets::Reader::rect checks an inline array's length before reading it and borrows direct
  objects instead of deep-cloning the inherited MediaBox/CropBox/Rotate for every page
  (CodeRabbit CWE-400, print/src/sheets.rs:774)
2026-10-22 21:49:46 -04:00
Dylan M. Taylor d66e345cc7 security: require every floating-group member to be movable for MoveFloating
MoveFloating checked only the panel it named, but changes the rectangle shared by that
panel's whole floating group, so naming a movable sibling moved a panel whose policy forbids
it. The model now refuses the action unless every member is movable, and the floating
window's resize grip no longer emits it for such a group.

CodeRabbit CWE-863, crates/ui/src/docking/model.rs:392
2026-10-22 21:46:25 -04:00
Dylan M. Taylor 08109be362 security: validate settings sections against the defaults alone
deserialize_sections tried each top-level key against a document holding every key accepted
before it, cloning and deserializing the growing document per key. A config.toml with many
unknown keys took quadratic time (20k keys: >2 minutes, now <1 s). Each key is now checked
against the defaults plus that key, and accepted keys are merged once.

CodeRabbit CWE-407, crates/settings/src/document.rs:47
2026-10-22 21:42:13 -04:00