How to cause the game window to jump to the foreground when an event occurs

Godot Version

4.3

Question

I want the user to be able to do other things while my game runs in the background behind other windows or possibly minimized and then I want to snap the game window to the foreground when an event occurs.

For some reason I’ve been unable to find any solution for this. The closest looking method I can find is the Window.grab_focus() method, but all this does is cause the taskbar icon to flash to try to get the user’s attention, but the window won’t actually come to the foreground. The grab_focus() method is documented as being a replacement for Window.move_to_foreground() - which is deprecated. Despite being deprecated, I tested out the aforementioned method and even if behaves the same, not actually bringing my window to the foreground.

I could see this being something that might be prevented on some Operating Systems, but I’m developing on Windows 10 and am quite sure that I have had other apps do this, so it seems that either Godot doesn’t support this or, more likely, I’ve been failing to find the answer. I’ve searched at length here, on reddit, on google, asked in the Discord, but still so far no light at the end of this tunnel.

Until a better solution presents itself, I’ve come up with this reusable hack, but it really seems like it isn’t the right way to solve the problem. It does, however, yield exactly the experience I was looking for.

class_name FocusWindow

func focus(window_id: int) -> void:
	DisplayServer.window_set_mode(
		DisplayServer.WindowMode.WINDOW_MODE_WINDOWED,
		window_id
	)
	DisplayServer.window_set_flag(
		DisplayServer.WindowFlags.WINDOW_FLAG_ALWAYS_ON_TOP,
		true,
		window_id
	)
	DisplayServer.window_set_flag(
		DisplayServer.WindowFlags.WINDOW_FLAG_ALWAYS_ON_TOP,
		false,
		window_id
	)
	DisplayServer.window_request_attention(window_id)

The behavior you are seeing is the expected one. It uses SetForegroundWindow() internally godot/platform/windows/display_server_windows.cpp at 906a4e9db91c2c6b17a0cb1cddf2a96f64114646 · godotengine/godot · GitHub where in the Remarks, says the following:

An application cannot force a window to the foreground while the user is working with another window. Instead, Windows flashes the taskbar button of the window to notify the user.

Later it says:

A process that can set the foreground window can enable another process to set the foreground window by calling the AllowSetForegroundWindow function.

Which you can set with DisplayServer.enable_for_stealing_focus() like:

DisplayServer.enable_for_stealing_focus(OS.get_process_id())

I’m not able to test it because this only works on Windows.

The same behavior happens on Linux X11 as far as I can tell. Haven’t tested Wayland or macOS but I bet it’s the same behavior.

I tried your solution and it does not work on Linux X11.