Skip to content
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

Support for activating already running app #3964

Open
Enyium opened this issue Oct 23, 2024 · 2 comments
Open

Support for activating already running app #3964

Enyium opened this issue Oct 23, 2024 · 2 comments
Labels
DS - windows S - enhancement Wouldn't this be the coolest?

Comments

@Enyium
Copy link

Enyium commented Oct 23, 2024

Description

To ensure only a single instance of your app can run, you can make use of a crate like single-instance. But an end user expects that, when trying to open the app by running its executable, the app is unconditionally brought into the foreground, no matter whether its relevant window is in the background, arranged, minimized, or hidden, because the app works with a tray icon.

I don't know whether Windows support for such functionality would fit into winit's existing ActivationToken API. In any case, an easy way to implement this functionality on Windows on a low level, is to retrieve a window message via RegisterWindowMessageW() in every app instance using the same app-specific string, and, if the app instance is a follow-up instance, use PostMessageW(HWND_BROADCAST, ...) to request the original app instance to activate its relevant window.

Note: You will know that Windows' SetForegroundWindow() is subject to certain restrictions. In my winit-using Slint app, though, I didn't have any trouble with activating the original app instance's window. The file manager will be the foreground process. Then this from the Microsoft docs will apply: "A process can set the foreground window...only if: ...The calling process was started by the foreground process..." Then, from my anecdotal evidence, Windows seems to allow this follow-up process of my app to transfer the right to successfully call SetForegroundWindow() to my original app instance (maybe because its the same executable path). (Alternatively, there would also be AllowSetForegroundWindow(), which requires retrieving the original app instance's process ID, though.)

However, as far as I can see, winit currently doesn't even support bringing a window into the foreground unconditionally. Window::focus_window() doesn't work for minimized and invisible windows, e.g., and Window::set_visible() probably also doesn't unminimize. Even though at least Windows 10 has a bug regarding arranged windows, there's a way to unconditionally bring a window into the foreground in its correct state: See this code (in another case, I only had success when calling SetForegroundWindow() before ShowWindowAsync(), in a branch where IsWindowVisible() returned true).

I think the functionality of unconditionally bringing a window to the foreground isn't only useful in the context of follow-up app instances, but also, e.g., when your app works with a tray icon, its window was minimized before hiding it in the tray, and the end user wants to show the app's window by clicking on the tray icon.

Somewhat similar issue regarding Wayland: #3633.

Relevant platforms

Windows

@Enyium Enyium added the S - enhancement Wouldn't this be the coolest? label Oct 23, 2024
@kchibisov
Copy link
Member

Wayland/X11 usually activate with dbus in case of IPC happening, so you pass some token to your main app, and then it acts based on the message you've passed, etc.

So no cross platform thing can not be done, really.

ActivationToken is just a string you pass via IPC to e.g. activate yourself and in some cases you can not really focus with it, like it should be passed to you via some sort of launcher for that to happen, etc.

What you describe sounds like you have IPC + some activation right in the windows API without a need for tokens, etc, since you basically do everything yourself, unlike like on Wayland where you get your token from somewhere else in cases of being activated.

@madsmtm
Copy link
Member

madsmtm commented Oct 25, 2024

In the case of macOS, this is handled automatically when the application is bundled (and if really necessary, the user can spawn a separate process with open -n). So there is nothing for Winit to do there.

So I've marked this with the DS - windows label, since it sounds like it's mostly an issue on Windows where this sort of behaviour isn't standardized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DS - windows S - enhancement Wouldn't this be the coolest?
Development

No branches or pull requests

3 participants