Răsfoiți Sursa

fix(core): clear window surface for transparent windows (#8633)

* fix(core): clear window surface for transparent windows

closes #8632

this may conflict with `tauri-egui` rendering to the surface so we may need to add an option to disable internal rendering

* fix build
Amr Bashir 1 an în urmă
părinte
comite
9f8037c288

+ 6 - 0
.changes/tauri-decorated-transparent.md

@@ -0,0 +1,6 @@
+---
+'tauri': 'patch:bug'
+'tauri-runtime-wry': 'patch'
+---
+
+On Windows, fix decorated window not transparent initially until resized.

+ 2 - 1
core/tauri-runtime-wry/Cargo.toml

@@ -14,7 +14,7 @@ rust-version = { workspace = true }
 
 [dependencies]
 wry = { version = "0.35.2", default-features = false, features = [ "file-drop", "protocol", "os-webview" ] }
-tao = { version = "0.24", default-features = false, features = [ "rwh_05" ] }
+tao = { version = "0.24", default-features = false, features = [ "rwh_05", "rwh_06" ] }
 tauri-runtime = { version = "1.0.0-alpha.8", path = "../tauri-runtime" }
 tauri-utils = { version = "2.0.0-alpha.13", path = "../tauri-utils" }
 raw-window-handle = "0.5"
@@ -23,6 +23,7 @@ tracing = { version = "0.1", optional = true }
 
 [target."cfg(windows)".dependencies]
 webview2-com = "0.28"
+softbuffer = "0.4"
 
   [target."cfg(windows)".dependencies.windows]
   version = "0.52"

+ 83 - 5
core/tauri-runtime-wry/src/lib.rs

@@ -1678,6 +1678,9 @@ pub struct WindowWrapper {
   label: String,
   inner: Option<WindowHandle>,
   window_event_listeners: WindowEventListeners,
+  is_window_transparent: bool,
+  #[cfg(windows)]
+  surface: Option<softbuffer::Surface<Arc<Window>, Arc<Window>>>,
 }
 
 impl fmt::Debug for WindowWrapper {
@@ -1685,6 +1688,7 @@ impl fmt::Debug for WindowWrapper {
     f.debug_struct("WindowWrapper")
       .field("label", &self.label)
       .field("inner", &self.inner)
+      .field("is_window_transparent", &self.is_window_transparent)
       .finish()
   }
 }
@@ -2470,20 +2474,40 @@ fn handle_user_message<T: UserEvent>(
     },
     Message::CreateWindow(window_id, handler, sender) => {
       let (label, builder) = handler();
+      let is_window_transparent = builder.window.transparent;
       if let Ok(window) = builder.build(event_loop) {
         webview_id_map.insert(window.id(), window_id);
 
-        let w = Arc::new(window);
+        let window = Arc::new(window);
+
+        #[cfg(windows)]
+        let surface = if is_window_transparent {
+          if let Ok(context) = softbuffer::Context::new(window.clone()) {
+            if let Ok(mut surface) = softbuffer::Surface::new(&context, window.clone()) {
+              clear_window_surface(&window, &mut surface);
+              Some(surface)
+            } else {
+              None
+            }
+          } else {
+            None
+          }
+        } else {
+          None
+        };
 
         windows.borrow_mut().insert(
           window_id,
           WindowWrapper {
             label,
-            inner: Some(WindowHandle::Window(w.clone())),
+            inner: Some(WindowHandle::Window(window.clone())),
             window_event_listeners: Default::default(),
+            is_window_transparent,
+            #[cfg(windows)]
+            surface,
           },
         );
-        sender.send(Ok(Arc::downgrade(&w))).unwrap();
+        sender.send(Ok(Arc::downgrade(&window))).unwrap();
       } else {
         sender.send(Err(Error::CreateWindow)).unwrap();
       }
@@ -2533,8 +2557,23 @@ fn handle_event_loop<T: UserEvent>(
       callback(RunEvent::Exit);
     }
 
-    #[cfg(feature = "tracing")]
+    #[cfg(any(feature = "tracing", windows))]
     Event::RedrawRequested(id) => {
+      #[cfg(windows)]
+      if let Some(window_id) = webview_id_map.get(&id) {
+        let mut windows_ref = windows.borrow_mut();
+        if let Some(window) = windows_ref.get_mut(&window_id) {
+          if window.is_window_transparent {
+            if let Some(surface) = &mut window.surface {
+              if let Some(window) = &window.inner {
+                clear_window_surface(&window, surface)
+              }
+            }
+          }
+        }
+      }
+
+      #[cfg(feature = "tracing")]
       active_tracing_spans.remove_window_draw(id);
     }
 
@@ -2685,6 +2724,8 @@ fn on_close_requested<'a, T: UserEvent>(
 fn on_window_close(window_id: WebviewId, windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>) {
   if let Some(window_wrapper) = windows.borrow_mut().get_mut(&window_id) {
     window_wrapper.inner = None;
+    #[cfg(windows)]
+    window_wrapper.surface.take();
   }
 }
 
@@ -3021,10 +3062,27 @@ fn create_webview<T: UserEvent, F: Fn(RawWindow) + Send + 'static>(
     .unwrap();
   }
 
+  let window = Arc::new(window);
+  #[cfg(windows)]
+  let surface = if is_window_transparent {
+    if let Ok(context) = softbuffer::Context::new(window.clone()) {
+      if let Ok(mut surface) = softbuffer::Surface::new(&context, window.clone()) {
+        clear_window_surface(&window, &mut surface);
+        Some(surface)
+      } else {
+        None
+      }
+    } else {
+      None
+    }
+  } else {
+    None
+  };
+
   Ok(WindowWrapper {
     label,
     inner: Some(WindowHandle::Webview {
-      window: Arc::new(window),
+      window,
       inner: Rc::new(webview),
       context_store: web_context_store.clone(),
       context_key: if automation_enabled {
@@ -3034,6 +3092,9 @@ fn create_webview<T: UserEvent, F: Fn(RawWindow) + Send + 'static>(
       },
     }),
     window_event_listeners,
+    is_window_transparent,
+    #[cfg(windows)]
+    surface,
   })
 }
 
@@ -3057,3 +3118,20 @@ fn create_ipc_handler<T: UserEvent>(
     );
   })
 }
+
+#[cfg(windows)]
+fn clear_window_surface(
+  window: &Window,
+  surface: &mut softbuffer::Surface<Arc<Window>, Arc<Window>>,
+) {
+  let size = window.inner_size();
+  if let (Some(width), Some(height)) = (
+    std::num::NonZeroU32::new(size.width),
+    std::num::NonZeroU32::new(size.height),
+  ) {
+    surface.resize(width, height).unwrap();
+    let mut buffer = surface.buffer_mut().unwrap();
+    buffer.fill(0);
+    let _ = buffer.present();
+  }
+}