Fix HTML5 keep-awake button double-toggle, silent wake lock errors, and cross-platform robustness#160
Fix HTML5 keep-awake button double-toggle, silent wake lock errors, and cross-platform robustness#160
Conversation
…nput Agent-Logs-Url: https://github.com/subsoap/defos/sessions/df5acc75-529a-4503-a815-05247ebd9deb Co-authored-by: subsoap <409170+subsoap@users.noreply.github.com>
set_keep_awake API to prevent screen dimming/sleep during gamepad play
Agent-Logs-Url: https://github.com/subsoap/defos/sessions/6c3bcf85-1f02-48c1-9fcc-c825ab80100d Co-authored-by: subsoap <409170+subsoap@users.noreply.github.com>
set_keep_awake API to prevent screen dimming/sleep during gamepad play…rror logging Agent-Logs-Url: https://github.com/subsoap/defos/sessions/fd598dad-c808-4199-9013-3a1d3a5df658 Co-authored-by: subsoap <409170+subsoap@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a cross-platform “keep screen awake” feature to defos and updates the HTML5 example/docs to avoid double-toggling in HTML5 input handling while improving diagnostics on wake lock failures.
Changes:
- Introduces
defos.set_keep_awake(bool)anddefos.is_keep_awake_supported()in the Lua API and platform backends (Win/macOS/Linux/HTML5). - Updates the HTML5 example UI handling to prevent a single click from toggling keep-awake twice.
- Documents the new API in both
README.mdanddefos.script_api, and updates platform linking requirements (IOKit, Xss).
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Documents keep-awake API and provides an example snippet. |
| example/example.gui_script | Adds keep-awake state, UI label updates, and HTML5 double-toggle guard in input handling. |
| example/example.gui | Adds a new GUI button/label node for keep-awake toggling. |
| defos/src/defos.cpp | Exposes keep-awake functions to Lua and resets keep-awake on extension finalize. |
| defos/src/defos_win.cpp | Implements keep-awake using SetThreadExecutionState. |
| defos/src/defos_private.h | Declares keep-awake backend functions. |
| defos/src/defos_mac.mm | Implements keep-awake via IOPM assertions. |
| defos/src/defos_linux.cpp | Implements keep-awake via XScreenSaverSuspend. |
| defos/src/defos_html5.cpp | Implements keep-awake via the Screen Wake Lock API and logs request/release failures. |
| defos/ext.manifest | Adds platform link dependencies for IOKit (macOS) and Xss (Linux). |
| defos/api/defos.script_api | Adds script API documentation for the new functions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
defos/src/defos_html5.cpp
Outdated
| if (!Module.__defosjs_wakeLock && 'wakeLock' in navigator) { | ||
| navigator.wakeLock.request('screen').then(function(lock) { | ||
| Module.__defosjs_wakeLock = lock; | ||
| lock.addEventListener('release', function() { | ||
| Module.__defosjs_wakeLock = null; | ||
| }); | ||
| }).catch(function(err) { | ||
| console.error('defos: wake lock request failed:', err); | ||
| }); |
There was a problem hiding this comment.
In the HTML5 implementation, the wake lock request promise can resolve after a subsequent call to defos_set_keep_awake(false) (or after the lock was released), which would re-populate Module.__defosjs_wakeLock and leave the wake lock active even though keep-awake is no longer desired. Track the desired keep-awake state (e.g. Module.__defosjs_keepAwakeDesired) and in the .then(...) handler either keep the lock only if still desired, or immediately release it if the desired state has changed.
defos/src/defos_html5.cpp
Outdated
| var keep = $0; | ||
| if (keep) { | ||
| if (!Module.__defosjs_wakeLock && 'wakeLock' in navigator) { | ||
| navigator.wakeLock.request('screen').then(function(lock) { | ||
| Module.__defosjs_wakeLock = lock; | ||
| lock.addEventListener('release', function() { | ||
| Module.__defosjs_wakeLock = null; | ||
| }); | ||
| }).catch(function(err) { | ||
| console.error('defos: wake lock request failed:', err); | ||
| }); | ||
| } | ||
| } else { |
There was a problem hiding this comment.
When the document/tab visibility changes, the Screen Wake Lock is typically released by the browser; this code clears Module.__defosjs_wakeLock on the release event but does not attempt to re-acquire the lock while keep-awake is still enabled. Consider re-requesting on visibilitychange (when visible again) or in the release handler when Module.__defosjs_keepAwakeDesired is still true, so defos.set_keep_awake(true) continues to have effect across focus/visibility transitions.
| var keep = $0; | |
| if (keep) { | |
| if (!Module.__defosjs_wakeLock && 'wakeLock' in navigator) { | |
| navigator.wakeLock.request('screen').then(function(lock) { | |
| Module.__defosjs_wakeLock = lock; | |
| lock.addEventListener('release', function() { | |
| Module.__defosjs_wakeLock = null; | |
| }); | |
| }).catch(function(err) { | |
| console.error('defos: wake lock request failed:', err); | |
| }); | |
| } | |
| } else { | |
| var keep = $0 !== 0; | |
| // Initialize state and helpers once. | |
| if (!Module.__defosjs_keepAwakeInitialized) { | |
| Module.__defosjs_keepAwakeInitialized = true; | |
| Module.__defosjs_keepAwakeDesired = false; | |
| Module.__defosjs_wakeLock = Module.__defosjs_wakeLock || null; | |
| // Shared helper to request a wake lock. | |
| Module.__defosjs_requestWakeLock = Module.__defosjs_requestWakeLock || function() { | |
| // Only attempt if desired, supported, and not already locked. | |
| if (!Module.__defosjs_keepAwakeDesired) { | |
| return; | |
| } | |
| if (!('wakeLock' in navigator)) { | |
| return; | |
| } | |
| if (Module.__defosjs_wakeLock) { | |
| return; | |
| } | |
| navigator.wakeLock.request('screen').then(function(lock) { | |
| Module.__defosjs_wakeLock = lock; | |
| lock.addEventListener('release', function() { | |
| // Browser released the lock (e.g., tab hidden, system policy, etc.) | |
| Module.__defosjs_wakeLock = null; | |
| // If keep-awake is still desired, try to reacquire. | |
| if (Module.__defosjs_keepAwakeDesired) { | |
| Module.__defosjs_requestWakeLock(); | |
| } | |
| }); | |
| }).catch(function(err) { | |
| console.error('defos: wake lock request failed:', err); | |
| }); | |
| }; | |
| // Re-try when the document becomes visible again. | |
| if (typeof document !== 'undefined' && document.addEventListener) { | |
| document.addEventListener('visibilitychange', function() { | |
| if (document.visibilityState === 'visible' && | |
| Module.__defosjs_keepAwakeDesired && | |
| !Module.__defosjs_wakeLock) { | |
| Module.__defosjs_requestWakeLock(); | |
| } | |
| }); | |
| } | |
| } | |
| // Update desired state based on the argument. | |
| Module.__defosjs_keepAwakeDesired = keep; | |
| if (keep) { | |
| // Ensure a wake lock is held (or requested) while desired. | |
| Module.__defosjs_requestWakeLock(); | |
| } else { | |
| // Release any existing wake lock and clear state. |
example/example.gui_script
Outdated
| self.keep_awake = not self.keep_awake | ||
| defos.set_keep_awake(self.keep_awake) | ||
| gui.set_text(gui.get_node("toggle_keep_awake/larrylabel"), self.keep_awake and "Allow screen sleep" or "Keep screen awake") |
There was a problem hiding this comment.
On HTML5, the example toggles self.keep_awake and updates the label even if the browser does not support the Wake Lock API (in which case defos.set_keep_awake() is effectively a no-op). This can leave the UI indicating an active wake lock when none exists. Consider gating the toggle on defos.is_keep_awake_supported() (and/or disabling the button / showing a message) so the example state stays accurate on unsupported browsers.
| self.keep_awake = not self.keep_awake | |
| defos.set_keep_awake(self.keep_awake) | |
| gui.set_text(gui.get_node("toggle_keep_awake/larrylabel"), self.keep_awake and "Allow screen sleep" or "Keep screen awake") | |
| if defos.is_keep_awake_supported() then | |
| self.keep_awake = not self.keep_awake | |
| defos.set_keep_awake(self.keep_awake) | |
| gui.set_text(gui.get_node("toggle_keep_awake/larrylabel"), self.keep_awake and "Allow screen sleep" or "Keep screen awake") | |
| else | |
| print("Keep-awake / Wake Lock is not supported on this platform.") | |
| end |
README.md
Outdated
| defos.set_keep_awake(bool_value) | ||
| bool_value = defos.is_keep_awake_supported() |
There was a problem hiding this comment.
The README signature snippet reuses bool_value for both set_keep_awake() and is_keep_awake_supported(), which reads as if the supported-flag is the same value passed to set_keep_awake() and can be confusing. Consider using a distinct variable name (e.g. supported = defos.is_keep_awake_supported()) and/or ordering the snippet to show checking support before calling defos.set_keep_awake(true) on HTML5.
| defos.set_keep_awake(bool_value) | |
| bool_value = defos.is_keep_awake_supported() | |
| local keep_awake = true -- or false to allow screen dimming/sleep | |
| local supported = defos.is_keep_awake_supported() | |
| if supported then | |
| defos.set_keep_awake(keep_awake) | |
| end |
| void defos_set_keep_awake(bool keep_awake) | ||
| { | ||
| if (keep_awake == g_keep_awake) { return; } | ||
| g_keep_awake = keep_awake; | ||
| XScreenSaverSuspend(disp, keep_awake ? True : False); | ||
| XFlush(disp); | ||
| } | ||
|
|
||
| bool defos_is_keep_awake_supported() | ||
| { | ||
| return true; | ||
| } |
There was a problem hiding this comment.
On Linux, defos_is_keep_awake_supported() currently always returns true, but XScreenSaverSuspend() requires the XScreenSaver extension to be present on the connected X11 display. Consider querying extension availability (e.g. XScreenSaverQueryExtension / XScreenSaverQueryVersion) during init and returning an accurate supported flag; additionally, skip calling XScreenSaverSuspend when unsupported to avoid X errors on systems without the extension.
|
@copilot apply changes based on the comments in this thread |
… re-acquire, Linux XSS check, README fix Agent-Logs-Url: https://github.com/subsoap/defos/sessions/e1c7b7ee-6953-4abf-9d79-0387fc4c10c0 Co-authored-by: subsoap <409170+subsoap@users.noreply.github.com>
Applied all changes from the review thread in commit
|
In HTML5 builds, clicking "Keep screen awake" appeared to do nothing — the label never changed and the wake lock was never acquired. Additionally, wake lock failures were silently swallowed with no diagnostic output.
Changes
example/example.gui_scriptAdded
if system_name ~= "HTML5"guard to thedirtylarry:button("toggle_keep_awake")handler inon_input.Without this, a single click fires the action twice in HTML5: once via
defos.on_click(DOM event) and once viaon_input(game loop), togglingself.keep_awakeback to its original value. This is the same pattern already used bylock_cursorandtoggle_fullscreen.Gated the HTML5
on_clickkeep-awake toggle ondefos.is_keep_awake_supported(). If the browser does not support the Wake Lock API, a diagnostic message is printed to the console instead of updating the UI to show an active wake lock that doesn't exist.defos/src/defos_html5.cppRefactored
defos_set_keep_awaketo track desired state viaModule.__defosjs_keepAwakeDesired. Shared helpers are initialized once; subsequent calls only update the desired flag.The
releaseevent listener and avisibilitychangelistener both re-callrequestWakeLockif keep-awake is still desired, so the lock is automatically re-acquired when the tab regains visibility after a browser-initiated release.Guarded against a promise race condition: if the desired state changes to
falsewhile anavigator.wakeLock.request()is in flight, the newly acquired lock is immediately released in the.then()handler.Wake lock failures now surface the full error object via
console.error('defos: wake lock ...:', err)in both the request and release paths, replacing silent empty.catch()callbacks.defos/src/defos_linux.cppdefos_is_keep_awake_supported()now accurately reflects XScreenSaver extension availability by queryingXScreenSaverQueryExtensionandXScreenSaverQueryVersionat init time, instead of always returningtrue.defos_set_keep_awakeskipsXScreenSaverSuspendwhen the extension is absent, avoiding X errors on systems without the XScreenSaver extension.README.mdlocal supported = defos.is_keep_awake_supported()) instead of reusingbool_value, eliminating ambiguity between the input toset_keep_awakeand the output ofis_keep_awake_supported.