A Rust library that provides a native-feeling borderless window with a custom titlebar for Slint applications on Windows.
- Removes the default OS window frame (
no-frame: true) while preserving native behavior - Windows 11 DWM drop shadow and rounded corners via
DwmExtendFrameIntoClientAreaandDwmSetWindowAttribute - Edge and corner resize hit-testing via a WinAPI window subclass (
WM_NCHITTEST) - Ready-to-use
TitlebarSlint component with minimize, maximize/restore, and close buttons - Drag-to-move via winit's
drag_window() - Double-click titlebar to toggle maximize/restore
- Windows (the DWM and subclass APIs are Windows-only)
- Rust edition 2024
- Slint 1.16.1+
In your Cargo.toml:
[dependencies]
slint_borderless_windows = { git = "https://github.com/Drew-Chase/slint_borderless_windows.git" }
slint = { version = "1.16.1", features = ["backend-winit"] }import { Titlebar, WindowControls } from "path/to/titlebar.slint";
// Re-export WindowControls so it is accessible from Rust
export { WindowControls }
export component MainWindow inherits Window {
no-frame: true;
VerticalLayout {
padding: 0px;
spacing: 0px;
Titlebar {
title: "My App";
}
// Your content here
}
}Setting no-frame: true on the root Window removes the OS chrome. The Titlebar component replaces it.
use slint_borderless_windows::TitlebarSetup;
slint::include_modules!();
fn main() -> Result<(), slint::PlatformError> {
let app = MainWindow::new().expect("Failed to create main window");
let frame = app.as_weak().setup_borderless().expect("Failed to setup custom frame");
let frame_maximize = frame.clone();
let frame_close = frame.clone();
let frame_drag = frame.clone();
let frame_dblclick = frame.clone();
app.global::<WindowControls>().on_maximize(move || frame_maximize.toggle_maximized());
app.global::<WindowControls>().on_close(move || frame_close.close());
app.global::<WindowControls>().on_drag(move || frame_drag.drag());
app.global::<WindowControls>().on_double_click(move || frame_dblclick.toggle_maximized());
app.global::<WindowControls>().on_minimize(move || frame.minimize());
app.run()?;
Ok(())
}setup_borderless() applies the DWM styling and installs the resize subclass. It returns a WindowFrame handle that exposes the window control methods.
Implemented on slint::Weak<T>. Call setup_borderless() after creating your component to apply the custom frame.
fn setup_borderless(&self) -> Result<WindowFrame<T>, slint::PlatformError>A lightweight, cloneable handle (backed by slint::Weak<T>) for controlling the window.
| Method | Description |
|---|---|
minimize() |
Minimizes the window |
maximize(bool) |
Sets maximized state explicitly |
toggle_maximized() |
Toggles between maximized and restored |
close() |
Quits the Slint event loop |
drag() |
Initiates a native window drag-move |
A 32px tall titlebar strip. Drop it at the top of a VerticalLayout.
| Property | Type | Default | Description |
|---|---|---|---|
title |
string |
"Application" |
Text displayed in the titlebar |
icon |
image |
(none) | Optional icon shown left of the title |
Bridges the Slint UI to Rust. Wire up each callback from Rust as shown above.
| Callback | Triggered by |
|---|---|
minimize() |
Minimize button click |
maximize() |
Maximize/restore button click |
close() |
Close button click |
drag() |
Mouse-down on the titlebar drag area |
double-click() |
Double-click on the titlebar drag area |
| Property | Type | Description |
|---|---|---|
maximized |
bool |
Controls which icon the maximize button shows (square vs. restore). Set this from Rust when the window state changes. |
setup_borderless() performs three things on the underlying Win32 window handle:
- Rounded corners — calls
DwmSetWindowAttributewithDWMWCP_ROUND - Drop shadow — calls
DwmExtendFrameIntoClientAreawith a 1px bottom margin, which is enough for DWM to render a shadow without exposing any native frame - Resize hit-testing — installs a window subclass via
SetWindowSubclassthat interceptsWM_NCHITTESTand returns the correctHT*values for all eight resize edges and corners
WM_NCCALCSIZE is also intercepted and returns 0 when wParam != 0, which tells Windows the entire window rect is client area — removing all non-client chrome.
A full working example is in examples/basic_example/. Build and run it with:
cd examples/basic_example
cargo run