From 5c1e667413dc0e4cbdc06ea77b66933a49f4886b Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Fri, 5 Jul 2024 09:05:10 -0700 Subject: [PATCH] Windowattributes::delay_visible Refs khonsulabs/cushy#152 --- CHANGELOG.md | 9 +++++++++ src/window.rs | 19 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8544c19..b65b33e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- `WindowAttributes::delay_visible` is a new setting initializes the window + `visible: false` before showing it after the first successful redraw. The goal + is to avoid the OS drawing an empty window before the window behavior has + initialized. This new attribute defaults to true. + ## v0.3.0 (2024-05-12) ### Breaking Changes diff --git a/src/window.rs b/src/window.rs index 89ce8ae..c5c7d53 100644 --- a/src/window.rs +++ b/src/window.rs @@ -149,6 +149,8 @@ pub struct WindowAttributes { pub window_level: WindowLevel, /// Whether the window is active or not. pub active: bool, + /// When true, this window will delay honoring the `visible` attribute until after the window behavior has been initialized and redrawn a single time. + pub delay_visible: bool, /// Name of the application /// /// - `WM_CLASS` on X11 @@ -182,6 +184,7 @@ impl Default for WindowAttributes { window_level: defaults.window_level, active: defaults.active, app_name: None, + delay_visible: true, } } } @@ -210,7 +213,7 @@ where /// /// The only errors this funciton can return arise from /// [`winit::window::WindowBuilder::build`]. - pub fn open(self) -> Result>, winit::error::OsError> { + pub fn open(mut self) -> Result>, winit::error::OsError> { // The window's thread shouldn't ever block for long periods of time. To // avoid a "frozen" window causing massive memory allocations, we'll use // a fixed-size channel and be cautious to not block the main event loop @@ -218,6 +221,7 @@ where let (sender, receiver) = mpsc::sync_channel(65536); let sender = Arc::new(sender); let app = self.owner.as_application().app(); + let show_after_init = self.attributes.delay_visible && std::mem::replace(&mut self.attributes.visible, false); let Some(winit) = self.owner.as_application_mut().open( self.attributes, sender.clone(), @@ -243,6 +247,7 @@ where cursor_position: None, mouse_buttons: HashSet::default(), keys: HashSet::default(), + show_after_init, }; thread::spawn(move || running_window.run_with::(self.context)); @@ -292,6 +297,7 @@ where focused: bool, theme: Theme, modifiers: Modifiers, + show_after_init: bool, } impl RunningWindow @@ -448,6 +454,17 @@ where // the entire app panics or not. let possible_panic = std::panic::catch_unwind(AssertUnwindSafe(move || { let mut behavior = Behavior::initialize(&mut self, context); + + // When it takes a while for a graphics stack to initialize, we can + // avoid showing a blank window due to our multi-threaded event + // handling by not showing the window until the graphics stack has + // been initialized. + if self.show_after_init { + self.next_redraw_target = None; + behavior.redraw(&mut self); + self.window.set_visible(true); + } + while !self.close { match self.process_messages_until_redraw(&mut behavior) { Ok(guard) => {