fix: idle detection errors and system freezes after hibernation

- Test idle detection methods only once during initialization to prevent repeated failures
- Add snap environment detection with automatic method filtering
- Add proper snap plugs for system-observe and login-session-observe interfaces
- Improve DBus handling by trying gdbus first (works better in snap environments)
- Add rate-limited error logging to prevent log spam
- Add snap install hook to guide users on connecting required interfaces
- Ensure graceful fallback to 0 (not idle) when detection fails

This prevents the system freezes that occurred after hibernation due to repeated
failing idle detection attempts, and improves snap compatibility for DBus access.
This commit is contained in:
Johannes Millan 2025-06-21 08:43:24 +02:00
parent c71a7d480f
commit fc343b801b
3 changed files with 51 additions and 15 deletions

View file

@ -61,6 +61,19 @@ snap:
autoStart: true
base: core22
confinement: strict
plugs:
- default
- desktop
- desktop-legacy
- wayland
- x11
- unity7
- home
- network
- browser-support
- password-manager-service
- system-observe
- login-session-observe
mac:
appId: com.super-productivity.app

View file

@ -72,15 +72,13 @@ export class IdleTimeHandler {
name: 'gnomeDBus',
test: async () => {
if (!this.isGnomeWayland) return false;
// Skip DBus in snap environment due to library version mismatches
if (this.isSnapEnvironment) {
log.info('Skipping GNOME DBus in snap environment');
return false;
}
try {
const idleTime = await this.getGnomeIdleTime();
return idleTime !== null;
} catch {
} catch (error) {
if (this.isSnapEnvironment) {
log.info('GNOME DBus test failed in snap environment:', error);
}
return false;
}
},
@ -189,16 +187,26 @@ export class IdleTimeHandler {
private async getGnomeIdleTime(): Promise<number | null> {
try {
const { stdout } = await execAsync(
'dbus-send --print-reply --dest=org.gnome.Mutter.IdleMonitor /org/gnome/Mutter/IdleMonitor/Core org.gnome.Mutter.IdleMonitor.GetIdletime',
{ timeout: 5000 }, // 5 second timeout
);
// Try gdbus first as it might work better in snap environments
let command =
'gdbus call --session --dest org.gnome.Mutter.IdleMonitor --object-path /org/gnome/Mutter/IdleMonitor/Core --method org.gnome.Mutter.IdleMonitor.GetIdletime';
// Parse the DBus response to extract the idle time
// Expected format: "uint64 1234567890"
const match = stdout.match(/uint64\s+(\d+)/);
if (match && match[1]) {
const idleMs = parseInt(match[1], 10);
// Check if gdbus is available
try {
await execAsync('which gdbus', { timeout: 1000 });
} catch {
// Fall back to dbus-send if gdbus is not available
command =
'dbus-send --print-reply --dest=org.gnome.Mutter.IdleMonitor /org/gnome/Mutter/IdleMonitor/Core org.gnome.Mutter.IdleMonitor.GetIdletime';
}
const { stdout } = await execAsync(command, { timeout: 5000 });
// Parse the response - gdbus format: (uint64 1234567890,)
// dbus-send format: uint64 1234567890
const match = stdout.match(/uint64\s+(\d+)|(?:\(uint64\s+)?(\d+)(?:,\))?/);
if (match) {
const idleMs = parseInt(match[1] || match[2], 10);
// Validate the result is reasonable (not negative, not extremely large)
if (idleMs >= 0 && idleMs < Number.MAX_SAFE_INTEGER) {
return idleMs;

15
snap/hooks/install Executable file
View file

@ -0,0 +1,15 @@
#!/bin/sh
# Connect interfaces for idle detection
if snapctl is-connected login-session-observe; then
echo "login-session-observe interface already connected"
else
echo "Please connect login-session-observe interface for idle detection:"
echo "sudo snap connect superproductivity:login-session-observe"
fi
if snapctl is-connected system-observe; then
echo "system-observe interface already connected"
else
echo "Please connect system-observe interface for better system integration:"
echo "sudo snap connect superproductivity:system-observe"
fi