diff --git a/.changes/windows-rtl.md b/.changes/windows-rtl.md new file mode 100644 index 000000000..1157c3eb6 --- /dev/null +++ b/.changes/windows-rtl.md @@ -0,0 +1,5 @@ +--- +"tao": "patch" +--- + +Add `WindowExtWindows::set_rtl` and `WindowBuilderExtWindows::with_rtl` to set right-to-left layout on Windows. diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 5192ddb91..9cfcb4289 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -121,6 +121,11 @@ pub trait WindowExtWindows { /// /// Enabling the shadow causes a thin 1px line to appear on the top of the window. fn set_undecorated_shadow(&self, shadow: bool); + + /// Sets right-to-left layout. + /// + /// Enabling this mainly flips the orientation of menus and title bar buttons + fn set_rtl(&self, rtl: bool); } impl WindowExtWindows for Window { @@ -170,6 +175,11 @@ impl WindowExtWindows for Window { fn set_undecorated_shadow(&self, shadow: bool) { self.window.set_undecorated_shadow(shadow) } + + #[inline] + fn set_rtl(&self, rtl: bool) { + self.window.set_rtl(rtl) + } } /// Additional methods on `WindowBuilder` that are specific to Windows. @@ -226,6 +236,9 @@ pub trait WindowBuilderExtWindows { /// The shadow is hidden by default. /// Enabling the shadow causes a thin 1px line to appear on the top of the window. fn with_undecorated_shadow(self, shadow: bool) -> WindowBuilder; + + /// Sets right-to-left layout. + fn with_rtl(self, rtl: bool) -> WindowBuilder; } impl WindowBuilderExtWindows for WindowBuilder { @@ -276,6 +289,12 @@ impl WindowBuilderExtWindows for WindowBuilder { self.platform_specific.decoration_shadow = shadow; self } + + #[inline] + fn with_rtl(mut self, rtl: bool) -> WindowBuilder { + self.platform_specific.rtl = rtl; + self + } } /// Additional methods on `MonitorHandle` that are specific to Windows. diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 9f047b1f6..df9cafb92 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -51,6 +51,7 @@ pub struct PlatformSpecificWindowBuilderAttributes { pub drag_and_drop: bool, pub preferred_theme: Option, pub decoration_shadow: bool, + pub rtl: bool, } impl Default for PlatformSpecificWindowBuilderAttributes { @@ -64,6 +65,7 @@ impl Default for PlatformSpecificWindowBuilderAttributes { preferred_theme: None, skip_taskbar: false, decoration_shadow: true, + rtl: false, } } } diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index e39500374..0851b7cd2 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -756,6 +756,17 @@ impl Window { }); } + pub fn set_rtl(&self, rtl: bool) { + let window = self.window.clone(); + let window_state = Arc::clone(&self.window_state); + + self.thread_executor.execute_in_thread(move || { + WindowState::set_window_flags(window_state.lock(), window.0, |f| { + f.set(WindowFlags::RIGHT_TO_LEFT_LAYOUT, rtl) + }); + }); + } + #[inline] pub fn current_monitor(&self) -> Option { Some(RootMonitorHandle { @@ -1010,6 +1021,8 @@ unsafe fn init( window_flags.set(WindowFlags::MARKER_DONT_FOCUS, !attributes.focused); + window_flags.set(WindowFlags::RIGHT_TO_LEFT_LAYOUT, pl_attribs.rtl); + let parent = match pl_attribs.parent { Parent::ChildOf(parent) => { window_flags.set(WindowFlags::CHILD, true); diff --git a/src/platform_impl/windows/window_state.rs b/src/platform_impl/windows/window_state.rs index 579add95e..6fd20910b 100644 --- a/src/platform_impl/windows/window_state.rs +++ b/src/platform_impl/windows/window_state.rs @@ -107,6 +107,8 @@ bitflags! { /// Drop shadow for undecorated windows. const MARKER_UNDECORATED_SHADOW = 1 << 21; + const RIGHT_TO_LEFT_LAYOUT = 1 << 22; + const EXCLUSIVE_FULLSCREEN_OR_MASK = WindowFlags::ALWAYS_ON_TOP.bits; } } @@ -269,6 +271,9 @@ impl WindowFlags { ) { style &= !WS_OVERLAPPEDWINDOW; } + if self.contains(WindowFlags::RIGHT_TO_LEFT_LAYOUT) { + style_ex |= WS_EX_LAYOUTRTL | WS_EX_RTLREADING | WS_EX_RIGHT; + } (style, style_ex) }