From 80edd3db9e081a97407f673e40ce81837c3fa7e1 Mon Sep 17 00:00:00 2001 From: rhzk Date: Sun, 27 Sep 2020 16:35:39 +0200 Subject: [PATCH] Reduce flashing on window creation --- CHANGELOG.md | 2 + druid-shell/src/platform/windows/window.rs | 80 ++++++++++++---------- druid-shell/src/window.rs | 8 +-- druid/src/app.rs | 4 +- 4 files changed, 52 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 681aaeaf79..7ee8570c23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ You can find its changes [documented below](#060---2020-06-01). ### Changed +- Windows: Reduced flashing when windows are created on high-dpi displays ([#1272] by [@rhzk]) - Windows: Improved DPI handling. Druid should now redraw correctly when dpi changes. ([#1037] by [@rhzk]) - windows: Window created with OS default size if not set. ([#1037] by [@rhzk]) - `Scale::from_scale` to `Scale::new`, and `Scale` methods `scale_x` / `scale_y` to `x` / `y`. ([#1042] by [@xStrom]) @@ -492,6 +493,7 @@ Last release without a changelog :( [#1251]: https://github.com/linebender/druid/pull/1251 [#1252]: https://github.com/linebender/druid/pull/1252 [#1255]: https://github.com/linebender/druid/pull/1255 +[#1272]: https://github.com/linebender/druid/pull/1272 [#1276]: https://github.com/linebender/druid/pull/1276 [#1278]: https://github.com/linebender/druid/pull/1278 [#1280]: https://github.com/linebender/druid/pull/1280 diff --git a/druid-shell/src/platform/windows/window.rs b/druid-shell/src/platform/windows/window.rs index bf45ed9366..6f3620821b 100644 --- a/druid-shell/src/platform/windows/window.rs +++ b/druid-shell/src/platform/windows/window.rs @@ -84,7 +84,7 @@ pub(crate) struct WindowBuilder { show_titlebar: bool, size: Option, min_size: Option, - position: Point, + position: Option, state: window::WindowState, } @@ -582,7 +582,6 @@ impl WndProc for MyWndProc { } else { 1.0 }; - let scale = Scale::new(scale_factor, scale_factor); self.set_scale(scale); @@ -689,25 +688,6 @@ impl WndProc for MyWndProc { (*rect).bottom - (*rect).top, SWP_NOZORDER | SWP_FRAMECHANGED | SWP_DRAWFRAME, ); - /* - if let Ok(mut s) = self.state.try_borrow_mut() { - let s = s.as_mut().unwrap(); - if s.dxgi_state.is_some() { - let scale = self.scale(); - let rt = paint::create_render_target(&self.d2d_factory, hwnd, scale); - s.render_target = rt.ok(); - { - let rect_dp = self.area().size_dp().to_rect(); - s.handler.rebuild_resources(); - s.render(&self.d2d_factory, &self.dwrite_factory, &rect_dp.into()); - self.clear_invalid(); - } - - } - } else { - self.log_dropped_msg(hwnd, msg, wparam, lparam); - } - */ Some(0) }, WM_NCCALCSIZE => unsafe { @@ -1180,7 +1160,7 @@ impl WindowBuilder { present_strategy: Default::default(), size: None, min_size: None, - position: Point::new(CW_USEDEFAULT as f64, CW_USEDEFAULT as f64), + position: None, state: window::WindowState::RESTORED, } } @@ -1215,7 +1195,7 @@ impl WindowBuilder { } pub fn set_position(&mut self, position: Point) { - self.position = position; + self.position = Some(position); } pub fn set_window_state(&mut self, state: window::WindowState) { @@ -1240,7 +1220,12 @@ impl WindowBuilder { present_strategy: self.present_strategy, }; + let (pos_x, pos_y) = match self.position { + Some(pos) => (pos.x as i32, pos.y as i32), + None => (CW_USEDEFAULT, CW_USEDEFAULT), + }; let scale = Scale::new(1.0, 1.0); + let mut area = ScaledArea::default(); let (width, height) = self .size @@ -1305,13 +1290,19 @@ impl WindowBuilder { dwExStyle |= WS_EX_NOREDIRECTIONBITMAP; } + match self.state { + window::WindowState::MAXIMIZED => dwStyle |= WS_MAXIMIZE, + window::WindowState::MINIMIZED => dwStyle |= WS_MINIMIZE, + _ => (), + }; + let hwnd = create_window( dwExStyle, class_name.as_ptr(), self.title.to_wide().as_ptr(), dwStyle, - self.position.x as i32, - self.position.y as i32, + pos_x, + pos_y, width, height, 0 as HWND, @@ -1322,20 +1313,32 @@ impl WindowBuilder { if hwnd.is_null() { return Err(Error::NullHwnd); } + + if let Some(size) = self.size { + if let Ok(scale) = handle.get_scale() { + if SetWindowPos( + hwnd, + HWND_TOPMOST, + 0, + 0, + (size.width * scale.x()) as i32, + (size.height * scale.y()) as i32, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE, + ) == 0 + { + warn!( + "failed to resize window: {}", + Error::Hr(HRESULT_FROM_WIN32(GetLastError())) + ); + }; + } + } + self.app.add_window(hwnd); if let Some(accels) = accels { register_accel(hwnd, &accels); } - - if let Some(size) = self.size { - // TODO: because this is deferred, it causes some flashing. - // Investigate a proper fix that gets the window created with - // the correct size. - handle.set_size(size); - } - handle.set_window_state(self.state); - Ok(handle) } } @@ -1520,7 +1523,12 @@ impl WindowHandle { if let Some(w) = self.state.upgrade() { let hwnd = w.hwnd.get(); unsafe { - ShowWindow(hwnd, SW_SHOWNORMAL); + let show = match self.get_window_state() { + window::WindowState::MAXIMIZED => SW_MAXIMIZE, + window::WindowState::MINIMIZED => SW_MINIMIZE, + _ => SW_SHOWNORMAL, + }; + ShowWindow(hwnd, show); UpdateWindow(hwnd); } } @@ -1673,7 +1681,7 @@ impl WindowHandle { } // Sets the window state. - pub fn set_window_state(&self, state: window::WindowState) { + pub fn set_window_state(&mut self, state: window::WindowState) { DeferredQueue::add(self.state.clone(), DeferredOp::SetWindowSizeState(state)); } diff --git a/druid-shell/src/window.rs b/druid-shell/src/window.rs index e83f02df31..cde4956944 100644 --- a/druid-shell/src/window.rs +++ b/druid-shell/src/window.rs @@ -178,8 +178,8 @@ impl WindowHandle { /// [`position`] The position in pixels. /// /// [`position`]: struct.Point.html - pub fn set_position(&self, position: Point) { - self.0.set_position(position) + pub fn set_position(&self, position: impl Into) { + self.0.set_position(position.into()) } /// Returns the position in virtual screen coordinates. @@ -200,8 +200,8 @@ impl WindowHandle { /// /// [`WinHandler::size`]: trait.WinHandler.html#method.size /// [display points]: struct.Scale.html - pub fn set_size(&self, size: Size) { - self.0.set_size(size) + pub fn set_size(&self, size: impl Into) { + self.0.set_size(size.into()) } /// Gets the window size. diff --git a/druid/src/app.rs b/druid/src/app.rs index 717c57041c..ad3bfbfcca 100644 --- a/druid/src/app.rs +++ b/druid/src/app.rs @@ -422,8 +422,8 @@ impl WindowDesc { /// [`position`] Position in pixels. /// /// [`position`]: struct.Point.html - pub fn set_position(mut self, position: Point) -> Self { - self.config = self.config.set_position(position); + pub fn set_position(mut self, position: impl Into) -> Self { + self.config = self.config.set_position(position.into()); self }