From 4caf6946f201a29fffb40d57b9c65d69f29dac7c Mon Sep 17 00:00:00 2001 From: amrbashir Date: Thu, 30 May 2024 22:35:56 +0300 Subject: [PATCH 01/10] On Windows, fix undecorated shadow reported client size is bigger than what's visible --- examples/undecorated_window.rs | 64 +++++++++++++++++++++++++ examples/util/fill.rs | 45 +++++++++++++---- src/changelog/unreleased.md | 2 +- src/platform_impl/windows/event_loop.rs | 2 + src/platform_impl/windows/window.rs | 43 ++++++++++++----- 5 files changed, 136 insertions(+), 20 deletions(-) create mode 100644 examples/undecorated_window.rs diff --git a/examples/undecorated_window.rs b/examples/undecorated_window.rs new file mode 100644 index 0000000000..23c9f5c711 --- /dev/null +++ b/examples/undecorated_window.rs @@ -0,0 +1,64 @@ +#![allow(unused)] + +use winit::application::ApplicationHandler; +use winit::event::{ElementState, KeyEvent, WindowEvent}; +use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop}; +use winit::keyboard::Key; +#[cfg(windows)] +use winit::platform::windows::{WindowAttributesExtWindows, WindowExtWindows}; +use winit::window::{Window, WindowId}; + +#[path = "util/fill.rs"] +mod fill; + +struct App { + window: Option, + shadow: bool, +} + +impl Default for App { + fn default() -> Self { + Self { window: None, shadow: true } + } +} + +impl ApplicationHandler for App { + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + let mut attrs = Window::default_attributes().with_decorations(false); + #[cfg(windows)] + { + attrs = attrs.with_undecorated_shadow(false); + } + + self.window = Some(event_loop.create_window(attrs).unwrap()); + } + + fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { + match event { + #[cfg(windows)] + WindowEvent::KeyboardInput { + event: KeyEvent { logical_key: Key::Character(c), state: ElementState::Pressed, .. }, + .. + } if c.as_ref() == "x" => { + self.shadow = !self.shadow; + self.window.as_ref().unwrap().set_undecorated_shadow(self.shadow); + }, + WindowEvent::CloseRequested => { + event_loop.exit(); + }, + WindowEvent::RedrawRequested => { + let window = self.window.as_ref().unwrap(); + fill::fill_window_with_border(window); + window.request_redraw(); + }, + _ => (), + } + } +} + +fn main() { + let event_loop = EventLoop::new().unwrap(); + event_loop.set_control_flow(ControlFlow::Wait); + let mut app = App::default(); + event_loop.run_app(&mut app).unwrap() +} diff --git a/examples/util/fill.rs b/examples/util/fill.rs index 31540c0290..87006d48f6 100644 --- a/examples/util/fill.rs +++ b/examples/util/fill.rs @@ -7,9 +7,8 @@ //! The `softbuffer` crate is used, largely because of its ease of use. `glutin` or `wgpu` could //! also be used to fill the window buffer, but they are more complicated to use. -#[allow(unused_imports)] -pub use platform::cleanup_window; -pub use platform::fill_window; +#![allow(unused)] +pub use platform::{cleanup_window, fill_window, fill_window_with_border}; #[cfg(all(feature = "rwh_05", not(any(target_os = "android", target_os = "ios"))))] mod platform { @@ -19,7 +18,7 @@ mod platform { use std::mem::ManuallyDrop; use std::num::NonZeroU32; - use softbuffer::{Context, Surface}; + use softbuffer::{Buffer, Context, Surface}; use winit::window::{Window, WindowId}; thread_local! { @@ -68,7 +67,31 @@ mod platform { } } + const DARK_GRAY: u32 = 0xff181818; + const LEMON: u32 = 0xffd1ffbd; + pub fn fill_window(window: &Window) { + fill_window_ex(window, |_, _, buffer| buffer.fill(DARK_GRAY)) + } + + pub fn fill_window_with_border(window: &Window) { + fill_window_ex(window, |width, height, buffer| { + for y in 0..height { + for x in 0..width { + let color = if (x == 0 || y == 0 || x == width - 1 || y == height - 1) { + LEMON + } else { + DARK_GRAY + }; + buffer[y * width + x] = color; + } + } + }) + } + pub fn fill_window_ex)>( + window: &Window, + f: F, + ) { GC.with(|gc| { let size = window.inner_size(); let (Some(width), Some(height)) = @@ -82,13 +105,15 @@ mod platform { let surface = gc.get_or_insert_with(|| GraphicsContext::new(window)).create_surface(window); - // Fill a buffer with a solid color. - const DARK_GRAY: u32 = 0xff181818; - surface.resize(width, height).expect("Failed to resize the softbuffer surface"); let mut buffer = surface.buffer_mut().expect("Failed to get the softbuffer buffer"); - buffer.fill(DARK_GRAY); + + let width = width.get() as usize; + let height = height.get() as usize; + + f(width, height, &mut buffer); + buffer.present().expect("Failed to present the softbuffer buffer"); }) } @@ -110,6 +135,10 @@ mod platform { // No-op on mobile platforms. } + pub fn fill_window_with_border(window: &Window) { + // No-op on mobile platforms. + } + #[allow(dead_code)] pub fn cleanup_window(_window: &winit::window::Window) { // No-op on mobile platforms. diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 314d13ec4a..262c2603ee 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -33,7 +33,6 @@ with it, the migration guide should be added below the entry, like: To migrate it we should do X, Y, and then Z, for example: // Code snippet. - ``` The migration guide could reference other migration examples in the current @@ -55,3 +54,4 @@ changelog entry. - On macOS, fix panic on exit when dropping windows outside the event loop. - On macOS, fix window dragging glitches when dragging across a monitor boundary with different scale factor. +- On Windows, fix `Window::inner_size` of undecorated window with shadows, reporting a size bigger than what's visible. diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 4bc6499c80..af00dc355c 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -1136,6 +1136,8 @@ unsafe fn public_window_callback_inner( // with the Windows API. params.rgrc[0].top += 1; params.rgrc[0].bottom += 1; + params.rgrc[0].left += 1; + params.rgrc[0].right += 1; } result = ProcResult::Value(0); diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 23fec32b34..7b14280460 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -32,16 +32,16 @@ use windows_sys::Win32::UI::Input::KeyboardAndMouse::{ use windows_sys::Win32::UI::Input::Touch::{RegisterTouchWindow, TWF_WANTPALM}; use windows_sys::Win32::UI::WindowsAndMessaging::{ CreateWindowExW, EnableMenuItem, FlashWindowEx, GetClientRect, GetCursorPos, - GetForegroundWindow, GetSystemMenu, GetSystemMetrics, GetWindowPlacement, GetWindowTextLengthW, - GetWindowTextW, IsWindowVisible, LoadCursorW, PeekMessageW, PostMessageW, RegisterClassExW, - SetCursor, SetCursorPos, SetForegroundWindow, SetMenuDefaultItem, SetWindowDisplayAffinity, - SetWindowPlacement, SetWindowPos, SetWindowTextW, TrackPopupMenu, CS_HREDRAW, CS_VREDRAW, - CW_USEDEFAULT, FLASHWINFO, FLASHW_ALL, FLASHW_STOP, FLASHW_TIMERNOFG, FLASHW_TRAY, - GWLP_HINSTANCE, HTBOTTOM, HTBOTTOMLEFT, HTBOTTOMRIGHT, HTCAPTION, HTLEFT, HTRIGHT, HTTOP, - HTTOPLEFT, HTTOPRIGHT, MENU_ITEM_STATE, MFS_DISABLED, MFS_ENABLED, MF_BYCOMMAND, NID_READY, - PM_NOREMOVE, SC_CLOSE, SC_MAXIMIZE, SC_MINIMIZE, SC_MOVE, SC_RESTORE, SC_SIZE, SM_DIGITIZER, - SWP_ASYNCWINDOWPOS, SWP_NOACTIVATE, SWP_NOSIZE, SWP_NOZORDER, TPM_LEFTALIGN, TPM_RETURNCMD, - WDA_EXCLUDEFROMCAPTURE, WDA_NONE, WM_NCLBUTTONDOWN, WM_SYSCOMMAND, WNDCLASSEXW, + GetForegroundWindow, GetSystemMenu, GetSystemMetrics, GetWindowPlacement, GetWindowRect, + GetWindowTextLengthW, GetWindowTextW, IsWindowVisible, LoadCursorW, PeekMessageW, PostMessageW, + RegisterClassExW, SetCursor, SetCursorPos, SetForegroundWindow, SetMenuDefaultItem, + SetWindowDisplayAffinity, SetWindowPlacement, SetWindowPos, SetWindowTextW, TrackPopupMenu, + CS_HREDRAW, CS_VREDRAW, CW_USEDEFAULT, FLASHWINFO, FLASHW_ALL, FLASHW_STOP, FLASHW_TIMERNOFG, + FLASHW_TRAY, GWLP_HINSTANCE, HTBOTTOM, HTBOTTOMLEFT, HTBOTTOMRIGHT, HTCAPTION, HTLEFT, HTRIGHT, + HTTOP, HTTOPLEFT, HTTOPRIGHT, MENU_ITEM_STATE, MFS_DISABLED, MFS_ENABLED, MF_BYCOMMAND, + NID_READY, PM_NOREMOVE, SC_CLOSE, SC_MAXIMIZE, SC_MINIMIZE, SC_MOVE, SC_RESTORE, SC_SIZE, + SM_DIGITIZER, SWP_ASYNCWINDOWPOS, SWP_NOACTIVATE, SWP_NOSIZE, SWP_NOZORDER, TPM_LEFTALIGN, + TPM_RETURNCMD, WDA_EXCLUDEFROMCAPTURE, WDA_NONE, WM_NCLBUTTONDOWN, WM_SYSCOMMAND, WNDCLASSEXW, }; use tracing::warn; @@ -213,13 +213,34 @@ impl Window { #[inline] pub fn inner_size(&self) -> PhysicalSize { let mut rect: RECT = unsafe { mem::zeroed() }; + if unsafe { GetClientRect(self.hwnd(), &mut rect) } == false.into() { panic!( "Unexpected GetClientRect failure: please report this error to \ rust-windowing/winit" ) } - PhysicalSize::new((rect.right - rect.left) as u32, (rect.bottom - rect.top) as u32) + + let mut width = rect.right - rect.left; + let mut height = rect.bottom - rect.top; + + if self.window_state_lock().window_flags.contains(WindowFlags::MARKER_UNDECORATED_SHADOW) { + let mut pt: POINT = unsafe { mem::zeroed() }; + if unsafe { ClientToScreen(self.hwnd(), &mut pt) } == true.into() { + let mut window_rc: RECT = unsafe { mem::zeroed() }; + if unsafe { GetWindowRect(self.hwnd(), &mut window_rc) } == true.into() { + let left_b = pt.x - window_rc.left; + let right_b = pt.x + width - window_rc.right; + let top_b = pt.y - window_rc.top; + let bottom_b = pt.y + height - window_rc.bottom; + + width = width - left_b - right_b; + height = height - top_b - bottom_b; + } + } + } + + PhysicalSize::new(width as u32, height as u32) } #[inline] From c8fd8da3e0843efb522e808669cb68e870667cfc Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Thu, 30 May 2024 22:45:51 +0300 Subject: [PATCH 02/10] Update fill.rs --- examples/util/fill.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/util/fill.rs b/examples/util/fill.rs index 87006d48f6..31de8f28f2 100644 --- a/examples/util/fill.rs +++ b/examples/util/fill.rs @@ -135,7 +135,7 @@ mod platform { // No-op on mobile platforms. } - pub fn fill_window_with_border(window: &Window) { + pub fn fill_window_with_border(_window: &winit::window::Window) { // No-op on mobile platforms. } From 73e1d15e72f475c147c109a592254de8581b132e Mon Sep 17 00:00:00 2001 From: amrbashir Date: Mon, 24 Jun 2024 08:58:09 +0300 Subject: [PATCH 03/10] change shadow to be enabled by default --- examples/undecorated_window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/undecorated_window.rs b/examples/undecorated_window.rs index 23c9f5c711..e38918da22 100644 --- a/examples/undecorated_window.rs +++ b/examples/undecorated_window.rs @@ -27,7 +27,7 @@ impl ApplicationHandler for App { let mut attrs = Window::default_attributes().with_decorations(false); #[cfg(windows)] { - attrs = attrs.with_undecorated_shadow(false); + attrs = attrs.with_undecorated_shadow(true); } self.window = Some(event_loop.create_window(attrs).unwrap()); From ef857528285647b43513a5406cfeeb70a00a0ff7 Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Mon, 8 Jul 2024 13:23:49 +0300 Subject: [PATCH 04/10] Update undecorated_window.rs --- examples/undecorated_window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/undecorated_window.rs b/examples/undecorated_window.rs index e38918da22..6cc6fd114d 100644 --- a/examples/undecorated_window.rs +++ b/examples/undecorated_window.rs @@ -23,7 +23,7 @@ impl Default for App { } impl ApplicationHandler for App { - fn resumed(&mut self, event_loop: &ActiveEventLoop) { + fn can_create_surfaces(&mut self, event_loop: &ActiveEventLoop) { let mut attrs = Window::default_attributes().with_decorations(false); #[cfg(windows)] { From cae80ccc92bb67db6c98a27cb40cf74ae7361e5b Mon Sep 17 00:00:00 2001 From: amrbashir Date: Thu, 15 Aug 2024 16:40:08 +0300 Subject: [PATCH 05/10] fix example --- examples/undecorated_window.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/undecorated_window.rs b/examples/undecorated_window.rs index 6cc6fd114d..90cc069979 100644 --- a/examples/undecorated_window.rs +++ b/examples/undecorated_window.rs @@ -23,7 +23,7 @@ impl Default for App { } impl ApplicationHandler for App { - fn can_create_surfaces(&mut self, event_loop: &ActiveEventLoop) { + fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { let mut attrs = Window::default_attributes().with_decorations(false); #[cfg(windows)] { @@ -33,7 +33,12 @@ impl ApplicationHandler for App { self.window = Some(event_loop.create_window(attrs).unwrap()); } - fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { + fn window_event( + &mut self, + event_loop: &dyn ActiveEventLoop, + _id: WindowId, + event: WindowEvent, + ) { match event { #[cfg(windows)] WindowEvent::KeyboardInput { From 890be35086a4178d2d65a2dd807e049c71d87ac0 Mon Sep 17 00:00:00 2001 From: amrbashir Date: Tue, 22 Oct 2024 17:50:42 +0300 Subject: [PATCH 06/10] fix tests --- examples/util/fill.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/util/fill.rs b/examples/util/fill.rs index 186b76e2ac..9be609b665 100644 --- a/examples/util/fill.rs +++ b/examples/util/fill.rs @@ -137,7 +137,7 @@ mod platform { // No-op on mobile platforms. } - pub fn fill_window_with_border(_window: &winit::window::Window) { + pub fn fill_window_with_border(_window: &dynwinit::window::Window) { // No-op on mobile platforms. } From 39f2aecc64cf577190271884cccf5e8146d7743d Mon Sep 17 00:00:00 2001 From: amrbashir Date: Tue, 22 Oct 2024 17:58:09 +0300 Subject: [PATCH 07/10] fix --- examples/util/fill.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/util/fill.rs b/examples/util/fill.rs index 9be609b665..41fc8c37e4 100644 --- a/examples/util/fill.rs +++ b/examples/util/fill.rs @@ -137,7 +137,7 @@ mod platform { // No-op on mobile platforms. } - pub fn fill_window_with_border(_window: &dynwinit::window::Window) { + pub fn fill_window_with_border(_window: &dyn winit::window::Window) { // No-op on mobile platforms. } From 0969c1b85b8f690ae07eb050c1f6f8bd5c3f519b Mon Sep 17 00:00:00 2001 From: amrbashir Date: Mon, 11 Nov 2024 14:51:05 +0200 Subject: [PATCH 08/10] handle borders when requesting new surface size --- src/platform_impl/windows/window.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index e6ee04d53c..286f41dd71 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -470,7 +470,10 @@ impl CoreWindow for Window { let mut width = rect.right - rect.left; let mut height = rect.bottom - rect.top; - if self.window_state_lock().window_flags.contains(WindowFlags::MARKER_UNDECORATED_SHADOW) { + let window_flags = self.window_state_lock().window_flags; + if window_flags.contains(WindowFlags::MARKER_UNDECORATED_SHADOW) + && !window_flags.contains(WindowFlags::MARKER_DECORATIONS) + { let mut pt: POINT = unsafe { mem::zeroed() }; if unsafe { ClientToScreen(self.hwnd(), &mut pt) } == true.into() { let mut window_rc: RECT = unsafe { mem::zeroed() }; @@ -500,9 +503,28 @@ impl CoreWindow for Window { fn request_surface_size(&self, size: Size) -> Option> { let scale_factor = self.scale_factor(); - let physical_size = size.to_physical::(scale_factor); + let mut physical_size = size.to_physical::(scale_factor); let window_flags = self.window_state_lock().window_flags; + if window_flags.contains(WindowFlags::MARKER_UNDECORATED_SHADOW) + && !window_flags.contains(WindowFlags::MARKER_DECORATIONS) + { + let mut pt: POINT = unsafe { mem::zeroed() }; + if unsafe { ClientToScreen(self.hwnd(), &mut pt) } == true.into() { + let mut window_rc: RECT = unsafe { mem::zeroed() }; + if unsafe { GetWindowRect(self.hwnd(), &mut window_rc) } == true.into() { + let left_b = pt.x - window_rc.left; + let right_b = pt.x + physical_size.width as i32 - window_rc.right; + let top_b = pt.y - window_rc.top; + let bottom_b = pt.y + physical_size.height as i32 - window_rc.bottom; + + physical_size.width = (physical_size.width as i32 + (left_b - right_b)) as u32; + physical_size.height = + (physical_size.height as i32 + (top_b - bottom_b)) as u32; + } + } + } + window_flags.set_size(self.hwnd(), physical_size); if physical_size != self.surface_size() { From c3c01aa460c92f476b2d233f1cc6e9d7002a6b37 Mon Sep 17 00:00:00 2001 From: amrbashir Date: Mon, 6 Jan 2025 03:41:50 +0200 Subject: [PATCH 09/10] fix request_surface_size doing nothing --- src/platform_impl/windows/window.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 92b84fbc4a..bc2e8ee747 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -508,14 +508,21 @@ impl CoreWindow for Window { if unsafe { ClientToScreen(self.hwnd(), &mut pt) } == true.into() { let mut window_rc: RECT = unsafe { mem::zeroed() }; if unsafe { GetWindowRect(self.hwnd(), &mut window_rc) } == true.into() { - let left_b = pt.x - window_rc.left; - let right_b = pt.x + physical_size.width as i32 - window_rc.right; - let top_b = pt.y - window_rc.top; - let bottom_b = pt.y + physical_size.height as i32 - window_rc.bottom; - - physical_size.width = (physical_size.width as i32 + (left_b - right_b)) as u32; - physical_size.height = - (physical_size.height as i32 + (top_b - bottom_b)) as u32; + let mut client_rc: RECT = unsafe { mem::zeroed() }; + if unsafe { GetClientRect(self.hwnd(), &mut client_rc) } == true.into() { + let curr_width = client_rc.right - client_rc.left; + let curr_height = client_rc.bottom - client_rc.top; + + let left_b = pt.x - window_rc.left; + let right_b: i32 = (pt.x + curr_width) - window_rc.right; + let top_b = pt.y - window_rc.top; + let bottom_b: i32 = (pt.y + curr_height) - window_rc.bottom; + + physical_size.width = + (physical_size.width as i32 + (left_b - right_b)) as u32; + physical_size.height = + (physical_size.height as i32 + (top_b - bottom_b)) as u32; + } } } } From 81c879ad5035c7e126d31001ca1b3ea5d1c10da6 Mon Sep 17 00:00:00 2001 From: amrbashir Date: Mon, 6 Jan 2025 03:47:37 +0200 Subject: [PATCH 10/10] fix example --- examples/undecorated_window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/undecorated_window.rs b/examples/undecorated_window.rs index a6f14632a4..be667bff29 100644 --- a/examples/undecorated_window.rs +++ b/examples/undecorated_window.rs @@ -46,7 +46,7 @@ impl ApplicationHandler for App { WindowEvent::KeyboardInput { event: KeyEvent { logical_key: Key::Character(c), state: ElementState::Pressed, .. }, .. - } if c.as_ref() == "x" => { + } if c == "x" => { self.shadow = !self.shadow; self.window.as_ref().unwrap().set_undecorated_shadow(self.shadow); },