Feature: frameless / custom-titlebar window support in blitz-shell (DOM-driven move, resize, window controls)
- Dominant language
- Rust
- Stars
- 4.1k
- Forks
- 203
- Avg merge
- 8h 58m
- Merged PRs (30d)
- 112
Description
Building a desktop app on `dioxus-native` with a borderless window (`with_decorations(false)`) to draw a custom titlebar, there is currently no way for the DOM to drive the window: dioxus-native never hands the winit `Window` to components, and `blitz-shell` (which owns the `Window`) has no built-in support for move/resize/min/max/fullscreen triggered from page content.
This is the equivalent of Electron's `-webkit-app-region: drag` / `no-drag` plus the usual window-control buttons. It seems like a natural fit for `blitz-shell` since it already owns the `Window` and the hit-testing.
## What's missing
For a frameless window, an app needs:
1. **Move-drag** from a titlebar region — start an OS window move when the user presses a draggable area.
2. **Resize-drag** from edge/corner bands — start an OS resize, with the correct resize cursor on hover.
3. **Window controls** — minimize / maximize-restore / fullscreen, triggered by in-DOM buttons (and ideally F11 for fullscreen).
All of these require calling winit methods (`drag_window`, `drag_resize_window`, `set_minimized`, `set_maximized`, `set_fullscreen`) that only the shell can reach.
## Approach that works (happy to upstream as a PR)
We carry these as a local patch on `blitz-shell` in our project; it has held up well and is small/self-contained. The mechanism mirrors `-webkit-app-region` using `data-*` attributes the shell hit-tests before forwarding the event to the DOM:
- **Move-drag:** on left mouse-press, walk up from the hit node; an element marked `data-drag` enables a window move, while a focusable element or one marked `data-nodrag` vetoes it (so buttons/inputs inside the titlebar still work). If enabled, call `window.drag_window()` and don't forward the press.
- **Resize-drag:** when the cursor is within a small band (e.g. 6 logical px) of an edge/corner of an *undecorated* window, map it to a `ResizeDirection`, set the matching resize cursor on `CursorMoved`, and on press call `window.drag_resize_window(dir)`.
- **Window controls:** walk up from the hit node for `data-minimize` / `data-maximize` / `data-fullscreen` markers (no focusable veto — the trigger is itself a ``) and call the corresponding winit method. F11 toggles `Fullscreen::Borderless`.
The frameless paths are gated on `!window.is_decorated()` so decorated windows are unaffected; the window-control markers work in both modes.
This is implemented entirely in `window.rs` (`handle_winit_event` + a few helpers) and needs no new public API surface beyond the attribute convention. I can open a PR if the maintainers are open to the `data-*` attribute approach — or adapt it to whatever convention you'd prefer (a dedicated CSS property, a config hook, etc.).
Would support for this be welcome in `blitz-shell`?
Contributor guide
Research direction
Read window.rs, especially handle_winit_event and its helpers, and trace the existing hit-testing and winit Window access first. Confirm the data-* convention and ensure undecorated move/resize behavior, window-control markers, and F11 fullscreen handling work without changing decorated-window behavior; the issue names no test file.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- desktop
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100