Skip to content

[Feature request] Keep app running after all windows are closed #2287

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
woubuc opened this issue Jul 23, 2021 · 11 comments
Closed

[Feature request] Keep app running after all windows are closed #2287

woubuc opened this issue Jul 23, 2021 · 11 comments

Comments

@woubuc
Copy link
Contributor

woubuc commented Jul 23, 2021

Is your feature request related to a problem? Please describe.
I am building an app that should "live" in the system tray. The app window can be closed and later reopened by clicking on the tray icon. However, when the last window of the app closes, Tauri exits.

Describe the solution you'd like
I would like an option to keep the app running after all windows are closed, so that I can create a new window when the user clicks on the tray icon.

Describe alternatives you've considered
Hiding the window instead of closing it will keep the app active, so this is a possible workaround. But this means that the window still exists in memory and still uses resources while that isn't necessary.

@woubuc
Copy link
Contributor Author

woubuc commented Jul 23, 2021

I'd be interested in figuring out how to implement this and creating a PR.

On first look, there seems to be an easy way to add a parameter to App.run() to prevent killing the app here in tauri/app.rs, but I think it's probably more appropriate to have this config passed down from a builder setter through the runtime to the event loop handler where the RunEvent::Exit is created here in tauri-runtime-wry/lib.rs. Is my understanding correct or would this logic go somewhere else?

@woubuc
Copy link
Contributor Author

woubuc commented Jul 23, 2021

I've gone ahead and hacked something together based on my (so far fairly limited) understanding of the codebase.

  1. A RunMode enum can be set on the builder
  2. This run mode is then passed through to the app and then to the runtime
  3. The Runtime.run() and Runtime.run_iteration() functions have a new parameter run_mode which adds the run mode to the EventLoopIterationContext.
  4. From there the event loop handler can use it where needed.

I don't want to create a PR just yet because there hasn't been enough discussion to determine if this is a desired approach, but you can check out the feat/run-mode branch in my fork, or the diff with the dev branch to see just what I changed to make it work.

If this approach sounds good then I'll go through it, clean it up where necessary, and create a proper PR for review. If y'all would prefer this feature to be approached in a different way, no problem, I'll just delete my branch and we can discuss how to do this properly. 😄

@lemarier
Copy link
Member

lemarier commented Jul 23, 2021

I've gone ahead and hacked something together based on my (so far fairly limited) understanding of the codebase.

  1. A RunMode enum can be set on the builder
  2. This run mode is then passed through to the app and then to the runtime
  3. The Runtime.run() and Runtime.run_iteration() functions have a new parameter run_mode which adds the run mode to the EventLoopIterationContext.
  4. From there the event loop handler can use it where needed.

I don't want to create a PR just yet because there hasn't been enough discussion to determine if this is a desired approach, but you can check out the feat/run-mode branch in my fork, or the diff with the dev branch to see just what I changed to make it work.

If this approach sounds good then I'll go through it, clean it up where necessary, and create a proper PR for review. If y'all would prefer this feature to be approached in a different way, no problem, I'll just delete my branch and we can discuss how to do this properly. 😄

Hey well done!

@lucasfernog what you think about this?
woubuc/tauri@dev...feat/run-mode

@amrbashir
Copy link
Member

we have something similar to stop Window from closing, check

.run(|app_handle, e| {
if let Event::CloseRequested { label, api, .. } = e {
api.prevent_close();
to see it in use, maybe something similar would be better ?

@woubuc
Copy link
Contributor Author

woubuc commented Jul 23, 2021

we have something similar to stop Window from closing
maybe something similar would be better ?

Personally I think my approach is easier on the developers who have to work with Tauri. It's directer ("set the mode of operation", instead of "check for an ExitRequested event and then callback to prevent the exit") and I think it more clearly communicates the intention of the code. Also, this is a personal preference but I always like to make "discoverable" APIs - if there's a function .run_mode() on the builder, devs will see it in their autocomplete list and check it out to see which run modes there are.

From a technical standpoint regarding the internal architecture I think my attempt also a little simpler because the data only flows one way (there's no need for a "prevent exit" callback).

But ultimately it's not my call, of course. It depends on how opinionated y'all want to be with this and what kind of architecture you prefer for the library.

@amrbashir
Copy link
Member

amrbashir commented Jul 23, 2021

Your approach is fine but I think we should do something similar to how we stop closing the window for two reasons:

  1. I don't see a way to close the app if the Run mode is set to Infinite but I am sure you can fix this.
  2. consistency in the codebase and similarity with javascript event.preventDefault() and this is my main reason.

@woubuc
Copy link
Contributor Author

woubuc commented Jul 24, 2021

  1. consistency in the codebase and similarity with javascript event.preventDefault() and this is my main reason.

That's a fair point. I had considered ease of use over consistency but both are indeed important. Which other APIs on the Rust side use cancelable events in this way? So I can check out how it's implemented for those cases and see if maybe I can implement something similar.

@amrbashir
Copy link
Member

Currently only Window close event

@woubuc
Copy link
Contributor Author

woubuc commented Jul 24, 2021

I've created a test on my fork of what the ExitRequested event would look like. I made it work in the exact same way as the existing CloseRequested event; A channel is created and sent to the user in the ExitRequested event, and the user can then use that to send a message back to prevent the app from exiting.

.run(|app, event| {
    if let Event::ExitRequested { api, .. } = event {
        api.prevent_exit();
    }
});

I also added an AppHandle.exit() function which cleans up the tray icon before exiting the process.

.on_system_tray_event(|app, event| {
    app.exit(0);
})

Let me know if this approach looks good enough to start a PR (where we can then discuss the actual underlying code & implementation).

@amrbashir
Copy link
Member

Looks good, would love to see a PR.

I also added an AppHandle.exit() function which cleans up the tray icon before exiting the process.

that won't be necessary, you can remove it. Tao will handle this automatically in the next release.

@woubuc
Copy link
Contributor Author

woubuc commented Jul 24, 2021

PR created #2293

lucasfernog added a commit that referenced this issue Aug 9, 2021
…exiting (#2293)

Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants