diff --git a/frontends/rioterm/src/router/window.rs b/frontends/rioterm/src/router/window.rs index 5a2f701384..5c38b5ab2e 100644 --- a/frontends/rioterm/src/router/window.rs +++ b/frontends/rioterm/src/router/window.rs @@ -1,7 +1,7 @@ -use rio_backend::config::window::{Decorations, WindowMode}; +use rio_backend::config::window::{Decorations, DecorationsThemeVariant, WindowMode}; use rio_backend::config::Config; use rio_window::window::{ - CursorIcon, Fullscreen, Icon, ImePurpose, Window, WindowAttributes, + CursorIcon, Fullscreen, Icon, ImePurpose, Theme, Window, WindowAttributes, }; pub const LOGO_ICON: &[u8; 410598] = include_bytes!("./resources/images/rio-logo.ico"); @@ -123,6 +123,19 @@ pub fn create_window_builder( // On windows cloak (hide) the window initially, we later reveal it after the first draw. // This is a workaround to hide the "white flash" that occurs during application startup. window_builder = window_builder.with_cloaked(true); + // Apply decorations theme variant if specified + match config.window.decorations_theme_variant { + DecorationsThemeVariant::Dark => { + window_builder = window_builder.with_theme(Some(Theme::Dark)); + } + DecorationsThemeVariant::Light => { + window_builder = window_builder.with_theme(Some(Theme::Light)); + } + DecorationsThemeVariant::None => { + // Let the system decide (default behavior) + window_builder = window_builder.with_theme(None); + } + } } match config.window.mode { @@ -218,6 +231,19 @@ pub fn configure_window(winit_window: &Window, config: &Config) { winit_window.set_corner_preference(preference); } + // Apply decorations theme variant if specified + match config.window.decorations_theme_variant { + DecorationsThemeVariant::Dark => { + winit_window.set_theme(Some(Theme::Dark)); + } + DecorationsThemeVariant::Light => { + winit_window.set_theme(Some(Theme::Light)); + } + DecorationsThemeVariant::None => { + // Let the system decide (default behavior) + winit_window.set_theme(None); + } + } } if let Some(title) = &config.title.placeholder { winit_window.set_title(title); diff --git a/rio-backend/src/config/defaults.rs b/rio-backend/src/config/defaults.rs index d2a3f4ec51..57f9c140d3 100644 --- a/rio-backend/src/config/defaults.rs +++ b/rio-backend/src/config/defaults.rs @@ -268,6 +268,10 @@ pub fn default_config_file_content() -> String { # # • decorations - Set window decorations, options: "Enabled", "Disabled", "Transparent", "Buttonless" # +# • decorations-theme-variant - Set window decorations theme variant, options: "Dark", "Light", "None" +# - "Dark" - Force dark mode for window decorations +# - "Light" - Force light mode for window decorations +# - "None" - Follow system theme (default) # • colorspace - Set the color space for the window # - "srgb" (default on non-macOS) # - "display-p3" (default on macOS) @@ -281,6 +285,7 @@ pub fn default_config_file_content() -> String { # opacity = 1.0 # blur = false # decorations = "enabled" +# decorations-theme-variant = "none" # colorspace = "display-p3" # Renderer diff --git a/rio-backend/src/config/window.rs b/rio-backend/src/config/window.rs index bd214e3947..37f6f42727 100644 --- a/rio-backend/src/config/window.rs +++ b/rio-backend/src/config/window.rs @@ -59,6 +59,20 @@ impl Default for Decorations { } } +#[derive(Clone, Serialize, Deserialize, Copy, Debug, PartialEq)] +pub enum DecorationsThemeVariant { + #[serde(alias = "dark")] + Dark, + #[serde(alias = "light")] + Light, + #[serde(alias = "none")] + None, +} + +impl Default for DecorationsThemeVariant { + fn default() -> DecorationsThemeVariant { DecorationsThemeVariant::None } +} + #[derive(PartialEq, Serialize, Deserialize, Clone, Debug)] pub enum WindowsCornerPreference { #[serde(alias = "default")] @@ -87,6 +101,8 @@ pub struct Window { pub background_image: Option, #[serde(default = "Decorations::default")] pub decorations: Decorations, + #[serde(default = "DecorationsThemeVariant::default", rename = "decorations-theme-variant")] + pub decorations_theme_variant: DecorationsThemeVariant, #[serde(default = "bool::default", rename = "macos-use-unified-titlebar")] pub macos_use_unified_titlebar: bool, #[serde(rename = "macos-use-shadow", default = "default_bool_true")] @@ -115,6 +131,7 @@ impl Default for Window { opacity: default_opacity(), background_image: None, decorations: Decorations::default(), + decorations_theme_variant: DecorationsThemeVariant::default(), blur: false, macos_use_unified_titlebar: false, macos_use_shadow: true, diff --git a/rio-window/src/platform_impl/windows/event_loop.rs b/rio-window/src/platform_impl/windows/event_loop.rs index c830a31651..ae879158f5 100644 --- a/rio-window/src/platform_impl/windows/event_loop.rs +++ b/rio-window/src/platform_impl/windows/event_loop.rs @@ -2574,8 +2574,9 @@ unsafe fn public_window_callback_inner( WM_SETTINGCHANGE => { use crate::event::WindowEvent::ThemeChanged; + let decorations_theme_variant = userdata.window_state_lock().decorations_theme_variant; - let preferred_theme = userdata.window_state_lock().preferred_theme; + let preferred_theme = decorations_theme_variant.or(userdata.window_state_lock().preferred_theme); if preferred_theme.is_none() { let new_theme = try_theme(window, preferred_theme); diff --git a/rio-window/src/platform_impl/windows/window.rs b/rio-window/src/platform_impl/windows/window.rs index dba3f1d2cd..be8c25cafe 100644 --- a/rio-window/src/platform_impl/windows/window.rs +++ b/rio-window/src/platform_impl/windows/window.rs @@ -1247,13 +1247,15 @@ impl InitData<'_> { // If the system theme is dark, we need to set the window theme now // before we update the window flags (and possibly show the // window for the first time). - let current_theme = try_theme(window, self.attributes.preferred_theme); + let preferred_theme = self.attributes.decorations_theme_variant.or(self.attributes.preferred_theme); + let current_theme = try_theme(window, preferred_theme); let window_state = { let window_state = WindowState::new( &self.attributes, scale_factor, current_theme, + self.attributes.decorations_theme_variant, self.attributes.preferred_theme, ); let window_state = Arc::new(Mutex::new(window_state)); diff --git a/rio-window/src/platform_impl/windows/window_state.rs b/rio-window/src/platform_impl/windows/window_state.rs index b15232e121..3c32ec9049 100644 --- a/rio-window/src/platform_impl/windows/window_state.rs +++ b/rio-window/src/platform_impl/windows/window_state.rs @@ -41,6 +41,7 @@ pub(crate) struct WindowState { pub modifiers_state: ModifiersState, pub fullscreen: Option, pub current_theme: Theme, + pub decorations_theme_variant: Option, pub preferred_theme: Option, pub window_flags: WindowFlags, @@ -141,6 +142,7 @@ impl WindowState { attributes: &WindowAttributes, scale_factor: f64, current_theme: Theme, + decorations_theme_variant: Option, preferred_theme: Option, ) -> WindowState { WindowState { @@ -165,7 +167,8 @@ impl WindowState { modifiers_state: ModifiersState::default(), fullscreen: None, current_theme, - preferred_theme, + decorations_theme_variant: decorations_theme_variant, + preferred_theme: decorations_theme_variant.or(preferred_theme), window_flags: WindowFlags::empty(), ime_state: ImeState::Disabled, diff --git a/rio-window/src/window.rs b/rio-window/src/window.rs index 456de8f85e..4080e6d8d8 100644 --- a/rio-window/src/window.rs +++ b/rio-window/src/window.rs @@ -117,6 +117,7 @@ pub struct WindowAttributes { pub transparent: bool, pub blur: bool, pub decorations: bool, + pub decorations_theme_variant: Option, pub window_icon: Option, pub preferred_theme: Option, pub resize_increments: Option, @@ -148,6 +149,7 @@ impl Default for WindowAttributes { transparent: false, blur: false, decorations: true, + decorations_theme_variant: None, window_level: Default::default(), window_icon: None, preferred_theme: None, @@ -392,9 +394,10 @@ impl WindowAttributes { /// system preference. When explicit theme is used, this will avoid dbus all together. /// - **x11:** Build window with `_GTK_THEME_VARIANT` hint set to `dark` or `light`. /// - **iOS / Android / Web / x11 / Orbital:** Ignored. + //// if decorations_theme_variant set use it #[inline] pub fn with_theme(mut self, theme: Option) -> Self { - self.preferred_theme = theme; + self.preferred_theme = self.decorations_theme_variant.or(theme); self }