Skip to content

Fix HTML5 keep-awake button double-toggle, silent wake lock errors, and cross-platform robustness#160

Open
Copilot wants to merge 5 commits intomasterfrom
copilot/fix-screen-dimming-issue
Open

Fix HTML5 keep-awake button double-toggle, silent wake lock errors, and cross-platform robustness#160
Copilot wants to merge 5 commits intomasterfrom
copilot/fix-screen-dimming-issue

Conversation

Copy link
Copy Markdown

Copilot AI commented Apr 1, 2026

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_script

  • Added if system_name ~= "HTML5" guard to the dirtylarry:button("toggle_keep_awake") handler in on_input.

    Without this, a single click fires the action twice in HTML5: once via defos.on_click (DOM event) and once via on_input (game loop), toggling self.keep_awake back to its original value. This is the same pattern already used by lock_cursor and toggle_fullscreen.

  • Gated the HTML5 on_click keep-awake toggle on defos.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.cpp

  • Refactored defos_set_keep_awake to track desired state via Module.__defosjs_keepAwakeDesired. Shared helpers are initialized once; subsequent calls only update the desired flag.

  • The release event listener and a visibilitychange listener both re-call requestWakeLock if 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 false while a navigator.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.cpp

  • defos_is_keep_awake_supported() now accurately reflects XScreenSaver extension availability by querying XScreenSaverQueryExtension and XScreenSaverQueryVersion at init time, instead of always returning true.

  • defos_set_keep_awake skips XScreenSaverSuspend when the extension is absent, avoiding X errors on systems without the XScreenSaver extension.

README.md

  • Fixed the API snippet to use a distinct variable name (local supported = defos.is_keep_awake_supported()) instead of reusing bool_value, eliminating ambiguity between the input to set_keep_awake and the output of is_keep_awake_supported.

Copilot AI changed the title [WIP] Fix screen dimming issue when using gamepad in Defold Add set_keep_awake API to prevent screen dimming/sleep during gamepad play Apr 1, 2026
Copilot AI requested a review from subsoap April 1, 2026 07:11
Agent-Logs-Url: https://github.com/subsoap/defos/sessions/6c3bcf85-1f02-48c1-9fcc-c825ab80100d

Co-authored-by: subsoap <409170+subsoap@users.noreply.github.com>
Copilot AI changed the title Add set_keep_awake API to prevent screen dimming/sleep during gamepad play Add screen sleep/dimming prevention for gamepad gameplay + demo button Apr 1, 2026
Copilot AI changed the title Add screen sleep/dimming prevention for gamepad gameplay + demo button Fix HTML5 keep-awake button double-toggle and silent wake lock errors Apr 1, 2026
@subsoap subsoap marked this pull request as ready for review April 1, 2026 07:49
Copilot AI review requested due to automatic review settings April 1, 2026 07:49
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) and defos.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.md and defos.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.

Comment on lines +417 to +425
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);
});
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +415 to +427
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 {
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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.

Copilot uses AI. Check for mistakes.
Comment on lines +99 to +101
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")
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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

Copilot uses AI. Check for mistakes.
README.md Outdated
Comment on lines +387 to +388
defos.set_keep_awake(bool_value)
bool_value = defos.is_keep_awake_supported()
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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

Copilot uses AI. Check for mistakes.
Comment on lines +932 to +943
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;
}
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 uses AI. Check for mistakes.
@subsoap
Copy link
Copy Markdown
Owner

subsoap commented Apr 1, 2026

@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>
Copy link
Copy Markdown
Author

Copilot AI commented Apr 1, 2026

@copilot apply changes based on the comments in this thread

Applied all changes from the review thread in commit 3d81629:

  • HTML5 defos_set_keep_awake: Refactored to track Module.__defosjs_keepAwakeDesired. The shared helpers are initialized once; the release event handler and a visibilitychange listener both re-call __defosjs_requestWakeLock if the desired state is still true. A in-flight promise race (desired state changed before .then() resolves) is also guarded.
  • HTML5 example: Wake lock toggle now checks defos.is_keep_awake_supported() first; prints a console message if unsupported so the UI stays accurate.
  • README: bool_value = defos.is_keep_awake_supported()local supported = defos.is_keep_awake_supported() to avoid variable-name confusion.
  • Linux: defos_is_keep_awake_supported() now returns the result of XScreenSaverQueryExtension + XScreenSaverQueryVersion probed at init time; defos_set_keep_awake skips XScreenSaverSuspend when the extension is absent.

Copilot AI changed the title Fix HTML5 keep-awake button double-toggle and silent wake lock errors Fix HTML5 keep-awake button double-toggle, silent wake lock errors, and cross-platform robustness Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants