Keep track of open windows


Related to this question: Launch other event-loop without blocking current

I have a GUI app containing both Gtk-rs and a bit of Tauri (Wry webview). The problem is that when a user clicks the button to open a specific window (e.g the settings) multiple times, the window also opens multiple times.

Is there a way to keep track of the state of the windows? I thought about using a global variable (lazy static + mutex) but that is not ideal in my multi-threaded app because it blocks my app. And using a singleton is also a bit too complex in this case.

Any ideas?

It's like managing any state, really. Tauri (and by extension winit) gives the caller a window handle that is freely cloneable and sendable. The existence of this handle is the state you are looking for... Kind of. The window itself that the handle references can go away for any reason, so it's like a weak reference.

Putting the handle into an Option<Window<Wry>> that your application can access just like, well, any of your other application data, should be enough. I know that Tauri gives you a place to put your application State, and I think Gtk4 has something similar, IIRC. That's where you would keep track of open windows.

1 Like

The problem is that I am launching the whole Wry-part in a function that gets called in a separate thread each time the window is opened. Won't executing the new event-loop reset the State?

pub fn dashboard_webview() -> wry::Result<()> {

    use wry::application::platform::windows::EventLoopBuilderExtWindows;
    use wry::application::event_loop::EventLoopBuilder;

    let event_loop: EventLoop<()> = EventLoopBuilder::default()
    let window = WindowBuilder::new()
        .with_title("Dashboard webview")
    let _webview = WebViewBuilder::new(window).unwrap()
        .with_url_and_headers(&*format!("https://{}/order-dashboard/panel?desktop_app=true", *config::URL), headers).unwrap()
 |event, _, control_flow| {
        *control_flow = ControlFlow::Wait;

    match event {
        Event::NewEvents(StartCause::Init) => {
            println!("Wry has started!");
            if !std::path::Path::new("webview_open.txt").exists() {
    Event::WindowEvent {
        event: WindowEvent::CloseRequested,
      } => {
            if std::path::Path::new("webview_open.txt").exists() {
      _ => (),


My understanding is that the "Gtk4 half" of your application is what opens the "Tauri half". In this situation, the latter should send its window handle to the former. The "Gtk4 half" maintains the state regarding whether the Tauri window is "potentially open" (it's the best we can do because the window can always close itself without informing the "Gtk4 half").

I don't think the event loop changes anything WRT resetting any state. But this is based on the assumption of which of the two halves represents the main thread.

1 Like

if the goal is to avoid opening multiple tauri window when the gtk button is clicked, I think it's enough to maintain a boolean "flag" in the gtk half, and let the tauri window send a notification to gtk when it is closed, probably in response to handle winit::Event::LoopDestroyed.

so the trick is to create a gtk channel and move the "sender" of the channel into the spawned tauri event loop thread so it can send the notification back to the "main" thread.

A bool is absolutely enough to "just check if a window is open". I also made an assumption that I failed to describe. And that is if they want to also interact with the other window, for instance check where its position is, or request it to close, then it's easy enough to do those kinds of interactions through the window handle.

And I agree they may also wish to have a channel for message passing between windows, and these actions could also be done indirectly that way.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.