Index: binaries/data/config/default.cfg =================================================================== --- binaries/data/config/default.cfg +++ binaries/data/config/default.cfg @@ -506,6 +506,10 @@ echelon = "echelon27" ; Name of the server-side XMPP-account that manages ratings buddies = "," ; Comma separated list of playernames that the current user has marked as buddies rememberpassword = true ; Whether to store the encrypted password in the user config +awayinbackground = true ; Whether the user's presence will be set to "away" when the window is unfocussed +awayinbackgroundtime = 1 ; Time in which the user's presence status will be set to "away" when the window is unfocussed in minutes +awaytimeout = true ; Whether the user's presence status will be set to "away" on inactivity +awaytimeouttime = 5 ; Time in which the user's presence status will be set to "away" on inactivity in minutes [lobby.columns] gamerating = false ; Show the average rating of the participating players in a column of the gamelist Index: binaries/data/mods/public/gui/lobby/LobbyHandler.js =================================================================== --- binaries/data/mods/public/gui/lobby/LobbyHandler.js +++ binaries/data/mods/public/gui/lobby/LobbyHandler.js @@ -11,15 +11,38 @@ this.leaderboardPage = new LeaderboardPage(this.xmppMessages); this.lobbyPage = new LobbyPage(dialog, this.xmppMessages, this.leaderboardPage, this.profilePage); - this.xmppMessages.processHistoricMessages(); + this.inputBeforeGuiHandlers = new Set(); + this.presenceHandler = new PresenceHandler(this); - if (Engine.LobbyGetPlayerPresence(g_Nickname) != "available") - Engine.LobbySetPlayerPresence("available"); + this.xmppMessages.processHistoricMessages(); if (!dialog) { initMusic(); global.music.setState(global.music.states.MENU); } + + Engine.GetGUIObjectByName("lobbyWindow").onTick = this.onTick; + } + + onTick() + { + updateTimers(); + } + + registerInputBeforeGuiHandler(handler) + { + this.inputBeforeGuiHandlers.add(handler); + } + + unregisterInputBeforeGuiHandler(handler) + { + this.inputBeforeGuiHandlers.delete(handler); + } + + handleInputBeforeGui(ev) + { + for (let handler of this.inputBeforeGuiHandlers) + handler(ev); } } Index: binaries/data/mods/public/gui/lobby/LobbyPage/Buttons/QuitButton.js =================================================================== --- binaries/data/mods/public/gui/lobby/LobbyPage/Buttons/QuitButton.js +++ binaries/data/mods/public/gui/lobby/LobbyPage/Buttons/QuitButton.js @@ -28,7 +28,7 @@ closeDialog() { - Engine.LobbySetPlayerPresence("playing"); + g_LobbyHandler.presenceHandler.fixPresence("playing"); Engine.PopGuiPage(); } Index: binaries/data/mods/public/gui/lobby/LobbyPage/Chat/ChatCommandHandler.js =================================================================== --- binaries/data/mods/public/gui/lobby/LobbyPage/Chat/ChatCommandHandler.js +++ binaries/data/mods/public/gui/lobby/LobbyPage/Chat/ChatCommandHandler.js @@ -87,14 +87,14 @@ "away": { "description": translate("Set your state to 'Away'."), "handler": function(args) { - Engine.LobbySetPlayerPresence("away"); + g_LobbyHandler.presenceHandler.fixPresence("away"); return true; } }, "back": { "description": translate("Set your state to 'Online'."), "handler": function(args) { - Engine.LobbySetPlayerPresence("available"); + g_LobbyHandler.presenceHandler.unfixPresence(); return true; } }, Index: binaries/data/mods/public/gui/lobby/LobbyPage/PresenceHandler.js =================================================================== --- /dev/null +++ binaries/data/mods/public/gui/lobby/LobbyPage/PresenceHandler.js @@ -0,0 +1,103 @@ +/** + * This class handling the presence status of the user. + */ +class PresenceHandler +{ + constructor(lobbyHandler) + { + if (Engine.LobbyGetPlayerPresence(g_Nickname) != "available") + Engine.LobbySetPlayerPresence("available"); + + this.presenceFixed = false; + + this.activityPresent = new Observable(); + this.activityPresent.value = true; + this.lastActive = Date.now(); + if (Engine.ConfigDB_GetValue("user", "lobby.awaytimeout") == "true") + setTimeout(this.checkActivity.bind(this), 1000 * 60 * +Engine.ConfigDB_GetValue("user", "lobby.awaytimeouttime")); + + this.backgroundPresent = new Observable(); + this.backgroundPresent.value = true; + this.windowFocus = true; + this.backgroundTimer = undefined; + let lobbyWindow = Engine.GetGUIObjectByName("lobbyWindow"); + lobbyWindow.onWindowFocusGained = this.onWindowFocusGained.bind(this); + lobbyWindow.onWindowFocusLost = this.onWindowFocusLost.bind(this); + + lobbyHandler.registerInputBeforeGuiHandler(this.handleInputBeforeGui.bind(this)); + + this.activityPresent.watch(this.setPresence.bind(this), ["value"]); + this.backgroundPresent.watch(this.setPresence.bind(this), ["value"]); + } + + checkActivity() + { + let timeLeft = this.lastActive + 1000 * 60 * +Engine.ConfigDB_GetValue("user", "lobby.awaytimeouttime") - Date.now(); + if (timeLeft <= 0) + { + this.activityPresent.value = false; + // Make sure we keep a timer running, so that we can set away again after a brief burst of activity. + setTimeout(this.checkActivity.bind(this), 1000 * 60 * +Engine.ConfigDB_GetValue("user", "lobby.awaytimeouttime")); + } + else + setTimeout(this.checkActivity.bind(this), timeLeft); + } + + fixPresence(status) + { + this.presenceFixed = true; + if (Engine.LobbyGetPlayerPresence(g_Nickname) != status) + Engine.LobbySetPlayerPresence(status); + } + + unfixPresence() + { + this.presenceFixed = false; + this.setPresence(); + } + + setPresence() + { + if (this.presenceFixed) + return; + + if (this.activityPresent.value && this.backgroundPresent.value && Engine.LobbyGetPlayerPresence(g_Nickname) != "available") + Engine.LobbySetPlayerPresence("available"); + else if (Engine.LobbyGetPlayerPresence(g_Nickname) != "away") + Engine.LobbySetPlayerPresence("away"); + } + + onWindowFocusGained() + { + this.windowFocus = true; + this.backgroundPresent.value = true; + + if (!this.backgroundTimer) + return; + + clearTimeout(this.backgroundTimer); + this.backgroundTimer = undefined; + } + + onWindowFocusLost() + { + this.windowFocus = false; + if (Engine.ConfigDB_GetValue("user", "lobby.awayinbackground") == "true") + this.backgroundTimer = setTimeout( + (() => { + this.backgroundPresent.value = false; + this.setPresence(); + }).bind(this), + 1000 * 60 * +Engine.ConfigDB_GetValue("user", "lobby.awayinbackgroundtime")); + } + + handleInputBeforeGui(ev, obj) + { + // Ignore mousemotion when not focussed. + if (ev.type == "mousemotion" && !this.windowFocus) + return; + + this.lastActive = Date.now(); + this.activityPresent.value = true; + } +} Index: binaries/data/mods/public/gui/lobby/lobby.js =================================================================== --- binaries/data/mods/public/gui/lobby/lobby.js +++ binaries/data/mods/public/gui/lobby/lobby.js @@ -38,3 +38,9 @@ else error("Could not load settings"); } + +function handleInputBeforeGui(ev, obj) +{ + g_LobbyHandler?.handleInputBeforeGui(ev, obj); + return false; +} Index: binaries/data/mods/public/gui/lobby/lobby.xml =================================================================== --- binaries/data/mods/public/gui/lobby/lobby.xml +++ binaries/data/mods/public/gui/lobby/lobby.xml @@ -6,7 +6,7 @@