Skip to content

Commit 25a64d9

Browse files
Fixed the multiple window closing issue, where the two multiwindow examples weren't working. (#3499)
* fixed window when multiple windows not closing * fixed window when multiple windows not closing * fixed accidental includes * polished * fix last window closing hiding app and rc hardcount * find the suspect strong count holders and fix them * Use the proper type alias * fmt --------- Co-authored-by: Jonathan Kelley <[email protected]>
1 parent 36522cf commit 25a64d9

File tree

6 files changed

+45
-19
lines changed

6 files changed

+45
-19
lines changed

examples/multiwindow.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55
//! own context, root elements, etc.
66
77
use dioxus::prelude::*;
8+
use dioxus::{desktop::Config, desktop::WindowCloseBehaviour};
89

910
fn main() {
10-
dioxus::LaunchBuilder::desktop().launch(app);
11+
dioxus::LaunchBuilder::desktop()
12+
// We can choose the close behavior of the last window to hide. See WindowCloseBehaviour for more options.
13+
.with_cfg(Config::new().with_close_behaviour(WindowCloseBehaviour::LastWindowHides))
14+
.launch(app);
1115
}
1216

1317
fn app() -> Element {

packages/desktop/src/app.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use tao::{
2020
dpi::PhysicalSize,
2121
event::Event,
2222
event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopProxy, EventLoopWindowTarget},
23-
window::WindowId,
23+
window::{Window, WindowId},
2424
};
2525

2626
/// The single top-level object that manages all the running windows, assets, shortcuts, etc
@@ -198,11 +198,14 @@ impl App {
198198
}
199199
}
200200

201+
LastWindowHides if self.webviews.len() > 1 => {
202+
self.webviews.remove(&id);
203+
}
204+
201205
LastWindowHides => {
202-
let Some(webview) = self.webviews.get(&id) else {
203-
return;
204-
};
205-
hide_app_window(&webview.desktop_context.webview);
206+
if let Some(webview) = self.webviews.get(&id) {
207+
hide_last_window(&webview.desktop_context.window);
208+
}
206209
}
207210

208211
CloseWindow => {
@@ -529,9 +532,13 @@ struct PreservedWindowState {
529532
monitor: String,
530533
}
531534

532-
/// Different hide implementations per platform
535+
/// Hide the last window when using LastWindowHides.
536+
///
537+
/// On macOS, if we use `set_visibility(false)` on the window, it will hide the window but not show
538+
/// it again when the user switches back to the app. `NSApplication::hide:` has the correct behaviour,
539+
/// so we need to special case it.
533540
#[allow(unused)]
534-
pub fn hide_app_window(window: &wry::WebView) {
541+
fn hide_last_window(window: &Window) {
535542
#[cfg(target_os = "windows")]
536543
{
537544
use tao::platform::windows::WindowExtWindows;

packages/desktop/src/desktop_context.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ pub fn window() -> DesktopContext {
3535
/// A handle to the [`DesktopService`] that can be passed around.
3636
pub type DesktopContext = Rc<DesktopService>;
3737

38+
/// A weak handle to the [`DesktopService`] to ensure safe passing.
39+
/// The problem without this is that the tao window is never dropped and therefore cannot be closed.
40+
/// This was due to the Rc that had still references because of multiple copies when creating a webview.
41+
pub type WeakDesktopContext = Weak<DesktopService>;
42+
3843
/// An imperative interface to the current window.
3944
///
4045
/// To get a handle to the current window, use the [`use_window`] hook.
@@ -101,7 +106,7 @@ impl DesktopService {
101106
/// You can use this to control other windows from the current window.
102107
///
103108
/// Be careful to not create a cycle of windows, or you might leak memory.
104-
pub fn new_window(&self, dom: VirtualDom, cfg: Config) -> Weak<DesktopService> {
109+
pub fn new_window(&self, dom: VirtualDom, cfg: Config) -> WeakDesktopContext {
105110
let window = WebviewInstance::new(cfg, dom, self.shared.clone());
106111

107112
let cx = window.dom.in_runtime(|| {

packages/desktop/src/document.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,42 @@
1+
use crate::{query::Query, DesktopContext, WeakDesktopContext};
12
use dioxus_core::prelude::queue_effect;
23
use dioxus_document::{
34
create_element_in_head, Document, Eval, EvalError, Evaluator, LinkProps, MetaProps,
45
ScriptProps, StyleProps,
56
};
6-
use generational_box::{AnyStorage, GenerationalBox, UnsyncStorage};
77

8-
use crate::{query::Query, DesktopContext};
8+
use generational_box::{AnyStorage, GenerationalBox, UnsyncStorage};
99

1010
/// Code for the Dioxus channel used to communicate between the dioxus and javascript code
1111
pub const NATIVE_EVAL_JS: &str = include_str!("./js/native_eval.js");
1212

1313
/// Represents the desktop-target's provider of evaluators.
1414
#[derive(Clone)]
1515
pub struct DesktopDocument {
16-
pub(crate) desktop_ctx: DesktopContext,
16+
pub(crate) desktop_ctx: WeakDesktopContext,
1717
}
1818

1919
impl DesktopDocument {
2020
pub fn new(desktop_ctx: DesktopContext) -> Self {
21+
let desktop_ctx = std::rc::Rc::downgrade(&desktop_ctx);
2122
Self { desktop_ctx }
2223
}
2324
}
2425

2526
impl Document for DesktopDocument {
2627
fn eval(&self, js: String) -> Eval {
27-
Eval::new(DesktopEvaluator::create(self.desktop_ctx.clone(), js))
28+
Eval::new(DesktopEvaluator::create(
29+
self.desktop_ctx
30+
.upgrade()
31+
.expect("Window to exist when document is alive"),
32+
js,
33+
))
2834
}
2935

3036
fn set_title(&self, title: String) {
31-
self.desktop_ctx.window.set_title(&title);
37+
if let Some(ctx) = self.desktop_ctx.upgrade() {
38+
ctx.set_title(&title);
39+
}
3240
}
3341

3442
/// Create a new meta tag in the head

packages/desktop/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub mod trayicon;
4848
// Public exports
4949
pub use assets::AssetRequest;
5050
pub use config::{Config, WindowCloseBehaviour};
51-
pub use desktop_context::{window, DesktopContext, DesktopService};
51+
pub use desktop_context::{window, DesktopContext, DesktopService, WeakDesktopContext};
5252
pub use event_handlers::WryEventHandler;
5353
pub use hooks::*;
5454
pub use shortcut::{ShortcutHandle, ShortcutRegistryError};

packages/desktop/src/webview.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::document::DesktopDocument;
21
use crate::element::DesktopElement;
32
use crate::file_upload::DesktopFileDragEvent;
43
use crate::menubar::DioxusMenu;
@@ -12,6 +11,7 @@ use crate::{
1211
waker::tao_waker,
1312
Config, DesktopContext, DesktopService,
1413
};
14+
use crate::{document::DesktopDocument, WeakDesktopContext};
1515
use base64::prelude::BASE64_STANDARD;
1616
use dioxus_core::{Runtime, ScopeId, VirtualDom};
1717
use dioxus_document::Document;
@@ -28,7 +28,7 @@ use wry::{DragDropEvent, RequestAsyncResponder, WebContext, WebViewBuilder};
2828
pub(crate) struct WebviewEdits {
2929
runtime: Rc<Runtime>,
3030
pub wry_queue: WryQueue,
31-
desktop_context: Rc<OnceCell<DesktopContext>>,
31+
desktop_context: Rc<OnceCell<WeakDesktopContext>>,
3232
}
3333

3434
impl WebviewEdits {
@@ -40,7 +40,7 @@ impl WebviewEdits {
4040
}
4141
}
4242

43-
fn set_desktop_context(&self, context: DesktopContext) {
43+
fn set_desktop_context(&self, context: WeakDesktopContext) {
4444
_ = self.desktop_context.set(context);
4545
}
4646

@@ -115,6 +115,8 @@ impl WebviewEdits {
115115
return Default::default();
116116
};
117117

118+
let desktop_context = desktop_context.upgrade().unwrap();
119+
118120
let query = desktop_context.query.clone();
119121
let recent_file = desktop_context.file_hover.clone();
120122

@@ -412,7 +414,7 @@ impl WebviewInstance {
412414
));
413415

414416
// Provide the desktop context to the virtual dom and edit handler
415-
edits.set_desktop_context(desktop_context.clone());
417+
edits.set_desktop_context(Rc::downgrade(&desktop_context));
416418
let provider: Rc<dyn Document> = Rc::new(DesktopDocument::new(desktop_context.clone()));
417419
let history_provider: Rc<dyn History> = Rc::new(MemoryHistory::default());
418420
dom.in_runtime(|| {

0 commit comments

Comments
 (0)