Parcourir la source

feat: emit `CloseRequested` event for egui windows (#3222)

Lucas Fernandes Nogueira il y a 3 ans
Parent
commit
ab7d3b51eb
1 fichiers modifiés avec 218 ajouts et 111 suppressions
  1. 218 111
      core/tauri-runtime-wry/src/lib.rs

+ 218 - 111
core/tauri-runtime-wry/src/lib.rs

@@ -1908,24 +1908,29 @@ impl Runtime for Wry {
         }
 
         #[cfg(feature = "egui")]
-        handle_gl_loop(
-          &event,
-          event_loop,
-          control_flow,
-          EventLoopIterationContext {
-            callback: &mut callback,
-            windows: windows.clone(),
-            window_event_listeners: &window_event_listeners,
-            global_shortcut_manager: global_shortcut_manager.clone(),
-            global_shortcut_manager_handle: &global_shortcut_manager_handle,
-            clipboard_manager: clipboard_manager.clone(),
-            menu_event_listeners: &menu_event_listeners,
-            #[cfg(feature = "system-tray")]
-            tray_context: &tray_context,
-          },
-          &web_context,
-          &mut is_focused,
-        );
+        {
+          let prevent_default = handle_gl_loop(
+            &event,
+            event_loop,
+            control_flow,
+            EventLoopIterationContext {
+              callback: &mut callback,
+              windows: windows.clone(),
+              window_event_listeners: &window_event_listeners,
+              global_shortcut_manager: global_shortcut_manager.clone(),
+              global_shortcut_manager_handle: &global_shortcut_manager_handle,
+              clipboard_manager: clipboard_manager.clone(),
+              menu_event_listeners: &menu_event_listeners,
+              #[cfg(feature = "system-tray")]
+              tray_context: &tray_context,
+            },
+            &web_context,
+            &mut is_focused,
+          );
+          if prevent_default {
+            return;
+          }
+        }
         iteration = handle_event_loop(
           event,
           event_loop,
@@ -1964,24 +1969,29 @@ impl Runtime for Wry {
 
     self.event_loop.run(move |event, event_loop, control_flow| {
       #[cfg(feature = "egui")]
-      handle_gl_loop(
-        &event,
-        event_loop,
-        control_flow,
-        EventLoopIterationContext {
-          callback: &mut callback,
-          windows: windows.clone(),
-          window_event_listeners: &window_event_listeners,
-          global_shortcut_manager: global_shortcut_manager.clone(),
-          global_shortcut_manager_handle: &global_shortcut_manager_handle,
-          clipboard_manager: clipboard_manager.clone(),
-          menu_event_listeners: &menu_event_listeners,
-          #[cfg(feature = "system-tray")]
-          tray_context: &tray_context,
-        },
-        &web_context,
-        &mut is_focused,
-      );
+      {
+        let prevent_default = handle_gl_loop(
+          &event,
+          event_loop,
+          control_flow,
+          EventLoopIterationContext {
+            callback: &mut callback,
+            windows: windows.clone(),
+            window_event_listeners: &window_event_listeners,
+            global_shortcut_manager: global_shortcut_manager.clone(),
+            global_shortcut_manager_handle: &global_shortcut_manager_handle,
+            clipboard_manager: clipboard_manager.clone(),
+            menu_event_listeners: &menu_event_listeners,
+            #[cfg(feature = "system-tray")]
+            tray_context: &tray_context,
+          },
+          &web_context,
+          &mut is_focused,
+        );
+        if prevent_default {
+          return;
+        }
+      }
       handle_event_loop(
         event,
         event_loop,
@@ -2641,42 +2651,14 @@ fn handle_event_loop(
 
       match event {
         WryWindowEvent::CloseRequested => {
-          let (tx, rx) = channel();
-          let windows_guard = windows.lock().expect("poisoned webview collection");
-          if let Some(w) = windows_guard.get(&window_id) {
-            let label = w.label.clone();
-            drop(windows_guard);
-            for handler in window_event_listeners
-              .lock()
-              .unwrap()
-              .get(&window_id)
-              .unwrap()
-              .lock()
-              .unwrap()
-              .values()
-            {
-              handler(&WindowEvent::CloseRequested {
-                label: label.clone(),
-                signal_tx: tx.clone(),
-              });
-            }
-            callback(RunEvent::CloseRequested {
-              label,
-              signal_tx: tx,
-            });
-            if let Ok(true) = rx.try_recv() {
-            } else {
-              on_window_close(
-                callback,
-                window_id,
-                windows.lock().expect("poisoned webview collection"),
-                control_flow,
-                #[cfg(target_os = "linux")]
-                window_event_listeners,
-                menu_event_listeners.clone(),
-              );
-            }
-          }
+          on_close_requested(
+            callback,
+            window_id,
+            windows.clone(),
+            control_flow,
+            window_event_listeners,
+            menu_event_listeners.clone(),
+          );
         }
         WryWindowEvent::Resized(_) => {
           if let Some(WindowHandle::Webview(webview)) = windows
@@ -2740,10 +2722,12 @@ fn handle_gl_loop(
   context: EventLoopIterationContext<'_>,
   _web_context: &WebContextStore,
   is_focused: &mut bool,
-) {
+) -> bool {
+  let mut prevent_default = false;
   let EventLoopIterationContext {
     callback,
     windows,
+    window_event_listeners,
     menu_event_listeners,
     #[cfg(feature = "system-tray")]
     tray_context,
@@ -2751,9 +2735,9 @@ fn handle_gl_loop(
   } = context;
   let egui_id = EGUI_ID.lock().unwrap();
   if let Some(id) = *egui_id {
-    let mut windows = windows.lock().unwrap();
+    let mut windows_lock = windows.lock().unwrap();
     let mut should_quit = false;
-    if let Some(win) = windows.get_mut(&id) {
+    if let Some(win) = windows_lock.get_mut(&id) {
       if let WindowHandle::GLWindow(gl_window, gl, painter, integration) = &mut win.inner {
         let mut redraw = || {
           if !*is_focused {
@@ -2820,21 +2804,49 @@ fn handle_gl_loop(
             event, window_id, ..
           } => {
             if window_id == &id {
-              if let glutin::event::WindowEvent::Focused(new_focused) = event {
-                *is_focused = *new_focused;
-              }
-
-              if let glutin::event::WindowEvent::Resized(physical_size) = event {
-                gl_window.resize(*physical_size);
+              match event {
+                glutin::event::WindowEvent::Focused(new_focused) => {
+                  *is_focused = *new_focused;
+                }
+                glutin::event::WindowEvent::Resized(physical_size) => {
+                  gl_window.resize(*physical_size);
+                }
+                _ => (),
               }
 
-              integration.on_event(&event);
-              if integration.should_quit() {
-                should_quit = true;
-                *control_flow = glutin::event_loop::ControlFlow::Wait;
+              if let glutin::event::WindowEvent::CloseRequested = event {
+                drop(windows_lock);
+                let w = on_close_requested(
+                  callback,
+                  *window_id,
+                  windows.clone(),
+                  control_flow,
+                  window_event_listeners,
+                  menu_event_listeners.clone(),
+                );
+                if let Some(mut win) = w {
+                  if let WindowHandle::GLWindow(gl_window, _gl, _painter, integration) =
+                    &mut win.inner
+                  {
+                    // marker
+                    integration.on_event(&event);
+                    if integration.should_quit() {
+                      should_quit = true;
+                      *control_flow = glutin::event_loop::ControlFlow::Wait;
+                    }
+                    gl_window.window().request_redraw();
+                  }
+                }
+                prevent_default = true;
+              } else {
+                // same as the `marker` above
+                integration.on_event(&event);
+                if integration.should_quit() {
+                  should_quit = true;
+                  *control_flow = glutin::event_loop::ControlFlow::Wait;
+                }
+                gl_window.window().request_redraw();
               }
-
-              gl_window.window().request_redraw();
             }
           }
           _ => (),
@@ -2847,12 +2859,14 @@ fn handle_gl_loop(
       on_window_close(
         callback,
         id,
-        windows,
+        windows.lock().unwrap(),
         control_flow,
         menu_event_listeners.clone(),
       );
     }
   }
+
+  prevent_default
 }
 
 #[allow(dead_code)]
@@ -2865,7 +2879,8 @@ fn handle_gl_loop(
   context: EventLoopIterationContext<'_>,
   _web_context: &WebContextStore,
   is_focused: &mut bool,
-) {
+) -> bool {
+  let mut prevent_default = false;
   let EventLoopIterationContext {
     callback,
     windows,
@@ -2875,13 +2890,12 @@ fn handle_gl_loop(
   } = context;
   let egui_id = EGUI_ID.lock().unwrap();
   if let Some(id) = *egui_id {
-    let mut windows = windows.lock().unwrap();
+    let mut windows_lock = windows.lock().unwrap();
     let mut should_quit = false;
-    if let Some(win) = windows.get_mut(&id) {
+    if let Some(win) = windows_lock.get_mut(&id) {
       if let WindowHandle::GLWindow(gl_window, _gl, _painter, integration, render_flow) =
         &mut win.inner
       {
-        let mut integration = integration.borrow_mut();
         let area = unsafe { gl_window.raw_handle() };
         match event {
           glutin::event::Event::MainEventsCleared => {
@@ -2897,21 +2911,57 @@ fn handle_gl_loop(
             event, window_id, ..
           } => {
             if window_id == &id {
-              if let glutin::event::WindowEvent::Focused(new_focused) = event {
-                *is_focused = *new_focused;
+              match event {
+                glutin::event::WindowEvent::Focused(new_focused) => {
+                  *is_focused = *new_focused;
+                }
+                glutin::event::WindowEvent::Resized(physical_size) => {
+                  gl_window.resize(*physical_size);
+                }
+                _ => (),
               }
 
-              if let glutin::event::WindowEvent::Resized(physical_size) = event {
-                gl_window.resize(*physical_size);
-              }
+              if let glutin::event::WindowEvent::CloseRequested = event {
+                drop(windows_lock);
+                let w = on_close_requested(
+                  callback,
+                  *window_id,
+                  windows.clone(),
+                  control_flow,
+                  window_event_listeners,
+                  menu_event_listeners.clone(),
+                );
+                if let Some(mut win) = w {
+                  if let WindowHandle::GLWindow(
+                    gl_window,
+                    _gl,
+                    _painter,
+                    integration,
+                    _render_flow,
+                  ) = &mut win.inner
+                  {
+                    // marker
+                    let mut integration = integration.borrow_mut();
+                    integration.on_event(&event);
+                    if integration.should_quit() {
+                      should_quit = true;
+                      *control_flow = glutin::event_loop::ControlFlow::Wait;
+                    }
+                    gl_window.window().request_redraw();
+                  }
+                }
+                prevent_default = true;
+              } else {
+                // same as the `marker` above
+                let mut integration = integration.borrow_mut();
 
-              integration.on_event(event);
-              if integration.should_quit() {
-                should_quit = true;
-                *control_flow = glutin::event_loop::ControlFlow::Wait;
+                integration.on_event(&event);
+                if integration.should_quit() {
+                  should_quit = true;
+                  *control_flow = glutin::event_loop::ControlFlow::Wait;
+                }
+                gl_window.window().request_redraw();
               }
-
-              gl_window.window().request_redraw();
             }
           }
           _ => (),
@@ -2924,13 +2974,63 @@ fn handle_gl_loop(
       on_window_close(
         callback,
         id,
-        windows,
+        windows.lock().unwrap(),
         control_flow,
         window_event_listeners,
         menu_event_listeners.clone(),
       );
     }
   }
+  prevent_default
+}
+
+fn on_close_requested<'a>(
+  callback: &'a mut (dyn FnMut(RunEvent) + 'static),
+  window_id: WindowId,
+  windows: Arc<Mutex<HashMap<WindowId, WindowWrapper>>>,
+  control_flow: &mut ControlFlow,
+  window_event_listeners: &WindowEventListeners,
+  menu_event_listeners: MenuEventListeners,
+) -> Option<WindowWrapper> {
+  let (tx, rx) = channel();
+  let windows_guard = windows.lock().expect("poisoned webview collection");
+  if let Some(w) = windows_guard.get(&window_id) {
+    let label = w.label.clone();
+    drop(windows_guard);
+    for handler in window_event_listeners
+      .lock()
+      .unwrap()
+      .get(&window_id)
+      .unwrap()
+      .lock()
+      .unwrap()
+      .values()
+    {
+      handler(&WindowEvent::CloseRequested {
+        label: label.clone(),
+        signal_tx: tx.clone(),
+      });
+    }
+    callback(RunEvent::CloseRequested {
+      label,
+      signal_tx: tx,
+    });
+    if let Ok(true) = rx.try_recv() {
+      None
+    } else {
+      on_window_close(
+        callback,
+        window_id,
+        windows.lock().expect("poisoned webview collection"),
+        control_flow,
+        #[cfg(target_os = "linux")]
+        window_event_listeners,
+        menu_event_listeners,
+      )
+    }
+  } else {
+    None
+  }
 }
 
 fn on_window_close<'a>(
@@ -2940,8 +3040,9 @@ fn on_window_close<'a>(
   control_flow: &mut ControlFlow,
   #[cfg(target_os = "linux")] window_event_listeners: &WindowEventListeners,
   menu_event_listeners: MenuEventListeners,
-) {
-  if let Some(webview) = windows.remove(&window_id) {
+) -> Option<WindowWrapper> {
+  #[allow(unused_mut)]
+  let w = if let Some(mut webview) = windows.remove(&window_id) {
     #[cfg(feature = "egui")]
     {
       // Destrooy GL context if its a GLWindow
@@ -2949,15 +3050,17 @@ fn on_window_close<'a>(
       if let Some(id) = *egui_id {
         if id == window_id {
           #[cfg(not(target_os = "linux"))]
-          if let WindowHandle::GLWindow(gl_window, gl, mut painter, mut integration, ..) =
-            webview.inner
+          if let WindowHandle::GLWindow(gl_window, gl, ref mut painter, ref mut integration, ..) =
+            &mut webview.inner
           {
             integration.on_exit(gl_window.window());
             painter.destroy(&gl);
             *egui_id = None;
           }
           #[cfg(target_os = "linux")]
-          if let WindowHandle::GLWindow(gl_window, gl, painter, integration, ..) = webview.inner {
+          if let WindowHandle::GLWindow(gl_window, gl, painter, integration, ..) =
+            &mut webview.inner
+          {
             let mut integration = integration.borrow_mut();
             let mut painter = painter.borrow_mut();
             integration.on_exit(gl_window.window());
@@ -2976,7 +3079,7 @@ fn on_window_close<'a>(
     if is_empty {
       let (tx, rx) = channel();
       callback(RunEvent::ExitRequested {
-        window_label: webview.label,
+        window_label: webview.label.clone(),
         tx,
       });
 
@@ -2988,7 +3091,10 @@ fn on_window_close<'a>(
         callback(RunEvent::Exit);
       }
     }
-  }
+    Some(webview)
+  } else {
+    None
+  };
   // TODO: tao does not fire the destroyed event properly
   #[cfg(target_os = "linux")]
   {
@@ -3004,6 +3110,7 @@ fn on_window_close<'a>(
       handler(&WindowEvent::Destroyed);
     }
   }
+  w
 }
 
 fn center_window(window: &Window, window_size: WryPhysicalSize<u32>) -> Result<()> {