-
Notifications
You must be signed in to change notification settings - Fork 942
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(windows): fix aero-snap of borderless window #1891
fix(windows): fix aero-snap of borderless window #1891
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't had the chance to test this, as I'm currently in Linux-land, implementing #753.
As discussed on Discord yesterday, some messages can be delivered to the window procedure during the call to CreateWindow
, and WM_NCCREATE
is presumably among them. I'm going to look into fixing this, but that's going to have to sit on the back-burner while I work on #753.
It is ok for this PR to wait until the subclass handler issue is fixed, In fact you can mark the PR as draft until then. |
e6ba7e9
to
3204e65
Compare
I found a workaround, we can resize the window with one pixel then revert it back after attaching the subclass. After this line: winit/src/platform_impl/windows/window.rs Line 122 in e8cdf8b
we can do something like this event_loop::subclass_window(win.window.0, subclass_input);
let win_flags = win.window_state.lock().window_flags();
if !win_flags.contains(WindowFlags::DECORATIONS) {
let original = win.inner_size();
win.set_inner_size(
PhysicalSize::new(original.width + 1, original.height).into(),
);
win.set_inner_size(original.into());
} let me know if this works for you and I will commit it. |
I don't particularly like the hack you've proposed, but @msiglreith is the Windows maintainer in the end. I'd prefer to move from using a subclass to using Unfortunately, I can't give you a precise estimate of when I'll get on with fixing this, but I hope to look into this during the next 2-4 weeks. |
This workaround isn't enough unfortunately because the transparency seems to be broken too because of the subclass issue. To confirm that transparency works well with a normal window procedure I cloned this repo https://github.com/melak47/BorderlessWindow/ and added the same transparency code that winit uses, and it works as expected along with the aero-snap and resizing |
I will mark this PR as ready for review, since #1933 got merged and fixed the issues I had. |
I believe I've found a workable solution to the "window spill-over "by using parts of this SO answer (thanks, @MrGibus, for linking me this). It doesn't quite get rid of all of it, but I think this is about as correct as other applications seem to get it. One quirk of this solution is that the window shadow appears to still be around, and users can as such resize the window on the left, right, and bottom sides of the window. It is unclear to me what the best way to handle this would be, although my first reaction would be to get rid of the shadow somehow. The slight vertical size error still persists, but I believe this is an error in some internal win32 function. The error goes away when I use a stub handler for I did try to see if I could link to an internal function I found ( It might be possible to make borderless applications correct in this regard by using this There's unfortunately a problem where changing from "borderless" to "bordered" when the window is maximized makes Windows think the window suddenly isn't maximized any more. There's also apparently a bug with the Bonus fact: If you use a winuser::WM_NCPAINT => {
if userdata
.window_state
.lock()
.window_flags()
.contains(WindowFlags::DECORATIONS)
{
winuser::DefWindowProcW(window, msg, wparam, lparam)
} else {
0
}
} |
Hey. I ran into the following issue with snapping while trying to implement egui. Is this a manifestation of the issue this pull request solves, or is there something else at play? cant_snap.mp4Edit: Maroider confirmed that this is likely related in the gitter channel. Thank you. |
I guess there is nothing but BUGS in this PR and I am tempted to close it tbh. // bug: each call adds an extra 16px to width and around 40px to height
// expected: nothing changes as we are just sitting the window size to the same current size
window.set_inner_size(window.inner_size());
window.set_inner_size(window.inner_size());
window.set_inner_size(window.inner_size()); It doesn't happen on master btw and it happens in this PR even before @maroider spill-over fix. |
I guess that's what we get for abusing Windows in this way 😅. However, I think we can turn this PR into something usable, it just might take some more months before we get there (largely due to how sporadically I work on things). |
Edit: it doesn't work without the spillover fix (4618897) and it doesn't make sense anyway. // src/plaform_impl/windows/util.rs
// in `set_inner_size_physical()`
let dpi = hwnd_dpi(window);
let titlebar_height = winuser::GetSystemMetricsForDpi(winuser::SM_CYSIZE, dpi)
+ winuser::GetSystemMetricsForDpi(winuser::SM_CXPADDEDBORDER, dpi) * 2
+ winuser::GetSystemMetricsForDpi(winuser::SM_CYBORDER, dpi);
let rect = adjust_window_rect(
window,
RECT {
top: 0,
left: 0,
bottom: (y - titlebar_height as u32) as LONG,
right: x as LONG,
},
)
.expect("adjust_window_rect failed"); This ONLY works when decorations is disabled. If the decorations are enabled, The window will shrink.
|
I'd like to make some progress in this PR if possible and last time I checked, there was two major issues with this PR:
Here is the example I use test this size overflow behavior: use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("A fantastic window!")
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
.with_decorations(false)
.build(&event_loop)
.unwrap();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
// println!("{:?}", event);
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
println!("{:?}", window.inner_size());
window.set_inner_size(window.inner_size());
}
Event::MainEventsCleared => {
window.request_redraw();
}
_ => (),
}
});
} |
Forgive my ignorance. Is it possible for your work in this PR to be configurable? Fixing the issue addressed in this PR would effectively unblock using winit for custom decorated windows, and making this bugfix opt-in (or auto disabled) for users of transparent windows could be a way of preventing a regression. |
Unfortunately this PR is not done yet and there is currently no way to manage whether the shadow is present or not. It is not the goal of this PR. |
I made another attempt at fixing the size overflow in For now, I commented out the spillover fix. I don't know if it is worth to keep it anyways. What do you think @maroider ? |
superseded by #2419 |
cargo fmt
has been run on this branchcargo doc
builds successfullyCHANGELOG.md
if knowledge of this change could be valuable to usersFixes #1548.
Note: This PR is merely a port of the cpp code in this repo
Note: The window isn't borderless when first created and needs to be maximized at least once or resized or anything that redraws the window before it can work properly. This however not a bug in my implementation, it is a bug in the subclass handler, you can reproduce it by adding
println!("ANYTHING")
insideWM_NCCREATE
. It will never be called which means there is a gap before the subclass handler gets attached.