gpui: Fix window display on Windows (#18705)
- Closes #18610 This PR addresses the same issue as PR #18578. After a full day of research and testing, I believe I’ve found the best solution to resolve this issue. With this PR, the window creation behavior on Windows becomes more consistent with macOS: - When `params.show` is `true`: The window is created and immediately displayed. - When `params.show` is `false`: The window is created but remains hidden until the first call to `activate_window`. As I mentioned in #18578, `winit` creates hidden windows by setting the window's `exstyle` to `WS_EX_NOACTIVATE | WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOOLWINDOW`, which is different from the method used in this PR. Here, the window is created with normal parameters, but we do not call `ShowWindow` so the window is not shown. I'm not sure why `winit` doesn't use a smilliar approach like this PR to create hidden windows. My guess is that `winit` is creating this hidden window to function as a "DispatchWindow" — serving a purpose similar to `WindowsPlatform` in `zed`. To ensure the window stays hidden even if `ShowWindow` is called, they use the `exstyle` approach. With the method used in this PR, my initial tests haven't revealed any issues. Release Notes: - N/A
This commit is contained in:
parent
b75532fad7
commit
7c306a5a0e
1 changed files with 58 additions and 32 deletions
|
@ -52,6 +52,7 @@ pub struct WindowsWindowState {
|
||||||
|
|
||||||
pub display: WindowsDisplay,
|
pub display: WindowsDisplay,
|
||||||
fullscreen: Option<StyleAndBounds>,
|
fullscreen: Option<StyleAndBounds>,
|
||||||
|
initial_placement: Option<WINDOWPLACEMENT>,
|
||||||
hwnd: HWND,
|
hwnd: HWND,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +98,7 @@ impl WindowsWindowState {
|
||||||
let system_settings = WindowsSystemSettings::new(display);
|
let system_settings = WindowsSystemSettings::new(display);
|
||||||
let nc_button_pressed = None;
|
let nc_button_pressed = None;
|
||||||
let fullscreen = None;
|
let fullscreen = None;
|
||||||
|
let initial_placement = None;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
origin,
|
origin,
|
||||||
|
@ -114,6 +116,7 @@ impl WindowsWindowState {
|
||||||
nc_button_pressed,
|
nc_button_pressed,
|
||||||
display,
|
display,
|
||||||
fullscreen,
|
fullscreen,
|
||||||
|
initial_placement,
|
||||||
hwnd,
|
hwnd,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -231,6 +234,14 @@ impl WindowsWindowStatePtr {
|
||||||
main_receiver: context.main_receiver.clone(),
|
main_receiver: context.main_receiver.clone(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_window_placement(&self) -> Result<()> {
|
||||||
|
let Some(placement) = self.state.borrow_mut().initial_placement.take() else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
unsafe { SetWindowPlacement(self.hwnd, &placement)? };
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -295,9 +306,6 @@ impl WindowsWindow {
|
||||||
WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
|
WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
if !params.show {
|
|
||||||
dwstyle |= WS_MINIMIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
let hinstance = get_module_handle();
|
let hinstance = get_module_handle();
|
||||||
let display = if let Some(display_id) = params.display_id {
|
let display = if let Some(display_id) = params.display_id {
|
||||||
|
@ -336,36 +344,24 @@ impl WindowsWindow {
|
||||||
lpparam,
|
lpparam,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
// We should call `?` on state_ptr first, then call `?` on raw_hwnd.
|
// We should call `?` on state_ptr first, then call `?` on hwnd.
|
||||||
// Or, we will lose the error info reported by `WindowsWindowState::new`
|
// Or, we will lose the error info reported by `WindowsWindowState::new`
|
||||||
let state_ptr = context.inner.take().unwrap()?;
|
let state_ptr = context.inner.take().unwrap()?;
|
||||||
let raw_hwnd = creation_result?;
|
let hwnd = creation_result?;
|
||||||
register_drag_drop(state_ptr.clone())?;
|
register_drag_drop(state_ptr.clone())?;
|
||||||
|
|
||||||
unsafe {
|
state_ptr.state.borrow_mut().border_offset.update(hwnd)?;
|
||||||
let mut placement = WINDOWPLACEMENT {
|
let placement = retrieve_window_placement(
|
||||||
length: std::mem::size_of::<WINDOWPLACEMENT>() as u32,
|
hwnd,
|
||||||
..Default::default()
|
display,
|
||||||
};
|
params.bounds,
|
||||||
GetWindowPlacement(raw_hwnd, &mut placement)?;
|
state_ptr.state.borrow().scale_factor,
|
||||||
// the bounds may be not inside the display
|
state_ptr.state.borrow().border_offset,
|
||||||
let bounds = if display.check_given_bounds(params.bounds) {
|
)?;
|
||||||
params.bounds
|
|
||||||
} else {
|
|
||||||
display.default_bounds()
|
|
||||||
};
|
|
||||||
let mut lock = state_ptr.state.borrow_mut();
|
|
||||||
let bounds = bounds.to_device_pixels(lock.scale_factor);
|
|
||||||
lock.border_offset.update(raw_hwnd)?;
|
|
||||||
placement.rcNormalPosition = calculate_window_rect(bounds, lock.border_offset);
|
|
||||||
drop(lock);
|
|
||||||
SetWindowPlacement(raw_hwnd, &placement)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if params.show {
|
if params.show {
|
||||||
unsafe { ShowWindow(raw_hwnd, SW_SHOW).ok()? };
|
unsafe { SetWindowPlacement(hwnd, &placement)? };
|
||||||
} else {
|
} else {
|
||||||
unsafe { ShowWindow(raw_hwnd, SW_HIDE).ok()? };
|
state_ptr.state.borrow_mut().initial_placement = Some(placement);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self(state_ptr))
|
Ok(Self(state_ptr))
|
||||||
|
@ -541,11 +537,18 @@ impl PlatformWindow for WindowsWindow {
|
||||||
|
|
||||||
fn activate(&self) {
|
fn activate(&self) {
|
||||||
let hwnd = self.0.hwnd;
|
let hwnd = self.0.hwnd;
|
||||||
unsafe { SetActiveWindow(hwnd).log_err() };
|
let this = self.0.clone();
|
||||||
unsafe { SetFocus(hwnd).log_err() };
|
self.0
|
||||||
// todo(windows)
|
.executor
|
||||||
// crate `windows 0.56` reports true as Err
|
.spawn(async move {
|
||||||
unsafe { SetForegroundWindow(hwnd).as_bool() };
|
this.set_window_placement().log_err();
|
||||||
|
unsafe { SetActiveWindow(hwnd).log_err() };
|
||||||
|
unsafe { SetFocus(hwnd).log_err() };
|
||||||
|
// todo(windows)
|
||||||
|
// crate `windows 0.56` reports true as Err
|
||||||
|
unsafe { SetForegroundWindow(hwnd).as_bool() };
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_active(&self) -> bool {
|
fn is_active(&self) -> bool {
|
||||||
|
@ -1066,6 +1069,29 @@ fn calculate_client_rect(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn retrieve_window_placement(
|
||||||
|
hwnd: HWND,
|
||||||
|
display: WindowsDisplay,
|
||||||
|
initial_bounds: Bounds<Pixels>,
|
||||||
|
scale_factor: f32,
|
||||||
|
border_offset: WindowBorderOffset,
|
||||||
|
) -> Result<WINDOWPLACEMENT> {
|
||||||
|
let mut placement = WINDOWPLACEMENT {
|
||||||
|
length: std::mem::size_of::<WINDOWPLACEMENT>() as u32,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
unsafe { GetWindowPlacement(hwnd, &mut placement)? };
|
||||||
|
// the bounds may be not inside the display
|
||||||
|
let bounds = if display.check_given_bounds(initial_bounds) {
|
||||||
|
initial_bounds
|
||||||
|
} else {
|
||||||
|
display.default_bounds()
|
||||||
|
};
|
||||||
|
let bounds = bounds.to_device_pixels(scale_factor);
|
||||||
|
placement.rcNormalPosition = calculate_window_rect(bounds, border_offset);
|
||||||
|
Ok(placement)
|
||||||
|
}
|
||||||
|
|
||||||
mod windows_renderer {
|
mod windows_renderer {
|
||||||
use std::{num::NonZeroIsize, sync::Arc};
|
use std::{num::NonZeroIsize, sync::Arc};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue