How to detect if the game is unfocused in the browser [SOLVED]

Godot Version

Godot v4.3 (Official) (Stable)

Question

How can I detect if the game is not focused while it’s running in the browser? So far I’ve found out that I am able to detect when the game is running with this code:

func _notification(what):
	match what:
		MainLoop.NOTIFICATION_APPLICATION_FOCUS_OUT:
			get_tree().paused = true

However, this does not work in browsers. I switch tabs and the game does not pause. This makes it very annoying for the user if they need to switch tabs. It’s also a requirement to put my game on Yandex to make the audio switch off when the game is unfocused. Is there some method that I can use to detect easily when the game is unfocused?

1 Like

I’m surprised, this is not implemented in the engine - maybe for good reason, maybe it’s an opportunity for a code contribution.

Anyways, you can build it yourself by using the JavaScriptBridge and some custome JavaScript based on the Page Visibility API.

Hope, this serves as a starting point :slightly_smiling_face:

2 Likes

Hello,

Have you tried get_window().has_focus() ?
It’s works on web. Here is a basic example:

func _ready() -> void:
	get_window().focus_entered.connect(_on_window_focus_entered)
	get_window().focus_exited.connect(_on_window_focus_exited)


func _on_window_focus_entered() -> void:
	AudioServer.set_bus_mute(0, false)


func _on_window_focus_exited() -> void:
	AudioServer.set_bus_mute(0, true)

See Node.get_window() and Window.

3 Likes

You can have a live demo Here.Change tabs and the sound won’t play. Come back and it will.
The project was made in Godot v4.3 stable

1 Like

Thanks a lot for your help! This worked. It was a bit wanky and for some reason didn’t work directly in the sound manager node I had though, but I just made it detect if the tree was paused since the pause menu would pause it and this workaround worked.
My theory on why the detection didn’t work properly is that the soundmanager node was on autoload, so maybe it didn’t inherit everything properly.

2 Likes

I’m just wondering, could I have the code to that? After some testing the signals get_window() sends only get triggered if the game loses focus while it’s on screen, so the game realizes you tabbed off after you switch back to the tab.

Of course, the full script is:

extends Control


func _ready() -> void:
	get_window().focus_entered.connect(_on_window_focus_entered)
	get_window().focus_exited.connect(_on_window_focus_exited)


func _on_window_focus_entered() -> void:
	AudioServer.set_bus_mute(0, false)


func _on_window_focus_exited() -> void:
	AudioServer.set_bus_mute(0, true)


func _on_play_audio_pressed() -> void:
	AudioServer.set_bus_mute(0, false)
	$Music.play()

I’ve updated the itchio page so you can download the project.

1 Like

Thanks! I found out what the issue was. I was trying to use a mute variable and set it to false when you tab out and to true when you tab in, and putting this in process:

AudioServer.set_bus_mute(0, get_tree().paused or AdManager.ad_playing or mute)

I thought that this process line would run even while you’re focused out, but it seems like that doesn’t happen. So I just added the line after the signal is sent:

func _on_window_focus_entered() -> void:
	mute = false
	AudioServer.set_bus_mute(0, get_tree().paused or AdManager.ad_playing or mute)

And this fixed it! :tada: Thanks a lot for your help

2 Likes