Window Configuration
Freya provides flexible window configuration options through WindowConfig and LaunchConfig. In this tutorial, we’ll explore how to customize your application’s windows.
[!NOTE] Window vs Launch Configuration
WindowConfigconfigures individual windows (title, size, decorations)LaunchConfigconfigures the entire application (fonts, plugins, multiple windows)
Basic Window
Create a simple window with default settings:
fn main() {
launch(WindowConfig::new_app(App));
}
#[derive(PartialEq)]
struct App;
impl Component for App {
fn render(&self) -> impl IntoElement {
rect().child(label().text("Hello, World!"))
}
}
WindowConfig
Configure individual window properties:
WindowConfig::new_app(MyApp)
.with_title("My Application")
.with_size(1024.0, 768.0)
.with_background(Color::WHITE)
.with_decorations(true)
.with_resizable(true)
Window Size
WindowConfig::new_app(App)
.with_size(800.0, 600.0) // Initial size
.with_min_size(400.0, 300.0) // Minimum size
.with_max_size(1920.0, 1080.0) // Maximum size
[!TIP] Always Set Minimum Size Setting a minimum size prevents your UI from breaking when users resize the window too small.
Window Appearance
WindowConfig::new_app(App)
.with_title("My App") // Window title
.with_decorations(true) // Title bar and borders
.with_transparency(false) // Transparent background
.with_background(Color::_rgb(240, 240, 240)) // Background color
Window Icon
let icon = LaunchConfig::window_icon(include_bytes!("../icon.png"));
WindowConfig::new_app(App)
.with_icon(icon)
Resizable Windows
WindowConfig::new_app(App)
.with_resizable(true) // Allow user to resize (default)
.with_resizable(false) // Fixed size window
Close Handling
Control what happens when the user tries to close the window:
WindowConfig::new_app(App)
.with_on_close(|ctx, window_id| {
if has_unsaved_changes() {
show_save_dialog();
CloseDecision::KeepOpen // Don't close yet
} else {
CloseDecision::Close // Allow close
}
})
Advanced Window Attributes
Access low-level winit window attributes for platform-specific options:
WindowConfig::new_app(App)
.with_window_attributes(|attrs, event_loop| {
attrs
.with_visible(false) // Start hidden
.with_always_on_top(true) // Stay on top
})
Window Handle Hook
Access the window handle after creation:
WindowConfig::new_app(App)
.with_window_handle(|window| {
// Access winit Window directly
window.set_ime_allowed(true);
})
LaunchConfig
Configure the overall application launch.
Multiple Windows
Create applications with multiple windows:
fn main() {
launch(
LaunchConfig::new()
.with_window(WindowConfig::new_app(MainWindow))
.with_window(
WindowConfig::new_app(SettingsWindow)
.with_title("Settings")
.with_size(400.0, 500.0)
)
);
}
Custom Fonts
Embedded Fonts
Embed fonts directly in your binary:
launch(
LaunchConfig::new()
.with_window(WindowConfig::new_app(App))
.with_font("Inter", include_bytes!("../fonts/Inter-Regular.ttf"))
.with_font("Inter-Bold", include_bytes!("../fonts/Inter-Bold.ttf"))
.with_font("Inter-Light", include_bytes!("../fonts/Inter-Light.ttf"))
);
Default Font
Set the default font for all text:
launch(
LaunchConfig::new()
.with_window(WindowConfig::new_app(App))
.with_default_font("Inter")
);
Fallback Fonts
Specify fallback fonts for missing characters:
launch(
LaunchConfig::new()
.with_window(WindowConfig::new_app(App))
.with_fallback_font("Arial")
.with_fallback_font("sans-serif")
);
Using embedded fonts:
label()
.text("Hello")
.font_family("Inter") // Uses Inter font
Window State at Runtime
Access window information while your app is running.
Window Size
fn component() -> impl IntoElement {
let size = use_window_size();
rect()
.child(label().text(format!("Window: {}x{}", size.width, size.height)))
}
Responsive Design
fn responsive_layout() -> impl IntoElement {
let size = use_window_size();
let is_mobile = size.width < 768.0;
rect()
.direction(if is_mobile {
Direction::Vertical
} else {
Direction::Horizontal
})
.child(sidebar(if !is_mobile))
.child(main_content())
}
Focus Events
rect()
.on_window_focus(|_| {
println!("Window focused");
})
.on_window_blur(|_| {
println!("Window lost focus");
})
Complete Configuration Example
fn main() {
let icon = LaunchConfig::window_icon(include_bytes!("../assets/icon.png"));
launch(
LaunchConfig::new()
.with_window(
WindowConfig::new_app(App)
.with_title("My Application")
.with_size(1024.0, 768.0)
.with_min_size(640.0, 480.0)
.with_max_size(1920.0, 1200.0)
.with_icon(icon)
.with_background(Color::from_rgb(248, 250, 252))
.with_decorations(true)
.with_resizable(true)
.with_on_close(|ctx, id| {
println!("Window close requested");
CloseDecision::Close
})
)
.with_font("Inter", include_bytes!("../assets/fonts/Inter-Regular.ttf"))
.with_font("Inter-Medium", include_bytes!("../assets/fonts/Inter-Medium.ttf"))
.with_font("Inter-Bold", include_bytes!("../assets/fonts/Inter-Bold.ttf"))
.with_default_font("Inter")
.with_fallback_font("Arial")
);
}
Platform Considerations
Windows
- Decorations include title bar and borders
- Transparent windows require DWM composition enabled
- Icons should be .ico format for best results
macOS
- Transparent windows require specific settings
- Fullscreen mode is available
- Title bar can be hidden
Linux
- Decorations depend on window manager
- Both X11 and Wayland are supported
- Some features may vary by desktop environment
Best Practices
1. Set Minimum Sizes
Prevent UI from breaking at small sizes:
.with_min_size(640.0, 480.0)
2. Handle Close Events
Prompt for unsaved changes:
.with_on_close(|ctx, id| {
if has_unsaved_changes() {
show_save_dialog();
CloseDecision::KeepOpen
} else {
CloseDecision::Close
}
})
3. Use Appropriate Backgrounds
Match your app’s theme:
// Light theme
.with_background(Color::from_rgb(248, 250, 252))
// Dark theme
.with_background(Color::from_rgb(17, 24, 39))
4. Embed Required Fonts
Ensure consistent appearance across platforms:
.with_font("Inter", include_bytes!("../fonts/Inter-Regular.ttf"))
5. Test on Multiple Platforms
Window behavior varies by OS - test on your target platforms.
Summary
In this tutorial, you learned:
- WindowConfig - Configuring individual windows
- Window size - Initial, minimum, maximum sizes
- Window appearance - Title, decorations, transparency, background
- Close handling - Custom close behavior
- LaunchConfig - Application-wide configuration
- Multiple windows - Creating multi-window apps
- Custom fonts - Embedding and using custom fonts
- Window state - Accessing size and focus at runtime
Previous: Part 12: Routing ←
Next: Part 14: Internationalization →
In the next tutorial, we’ll explore internationalization - making your app speak multiple languages with Fluent.