From e735e85d3c10c49a717925e957344daaf12f8fb1 Mon Sep 17 00:00:00 2001 From: Kiwy Player Date: Sat, 17 Jan 2026 20:15:47 +0200 Subject: [PATCH] Add Wayland display server support for power management Added support for both X11 and Wayland environments: Display Server Detection: - Auto-detects Wayland via WAYLAND_DISPLAY environment variable - Falls back to X11 commands if not Wayland - Works seamlessly on both display servers Wayland-specific tools: - wlopm - Wayland output power management (keeps display on) - wlr-randr - Output management for wlroots compositors - ydotool - Mouse movement for Wayland (alternative to xdotool) - systemd-inhibit integration for idle prevention Enhanced display keep-alive script: - Detects display server type on startup - Uses appropriate commands based on environment - Wayland: wlopm, wlr-randr, ydotool - X11: xset, xdotool, xrandr - Both: tvservice for HDMI power control App-level improvements (main.py): - Detects Wayland via os.environ check - Executes Wayland-specific commands when detected - Maintains X11 compatibility for older systems Installation improvements: - Auto-installs Wayland tools if Wayland is detected - Attempts to install: wlopm, wlr-randr, ydotool - Graceful fallback if packages unavailable This ensures HDMI power management works correctly on: - Raspberry Pi OS with X11 (older versions) - Raspberry Pi OS with Wayland (Bookworm and newer) - Any Linux system using either display server --- .display-keepalive.sh | 33 ++++++++++++ .player_heartbeat | 2 +- install.sh | 113 +++++++++++++++++++++++++++++++++++------- src/main.py | 69 +++++++++++++++++--------- 4 files changed, 173 insertions(+), 44 deletions(-) create mode 100755 .display-keepalive.sh diff --git a/.display-keepalive.sh b/.display-keepalive.sh new file mode 100755 index 0000000..728fbbc --- /dev/null +++ b/.display-keepalive.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Aggressive display keep-alive for Raspberry Pi +# Prevents HDMI from powering down + +DISPLAY_TIMEOUT=30 + +while true; do + # Keep HDMI powered on (tvservice command) + if command -v tvservice &> /dev/null; then + /usr/bin/tvservice -p 2>/dev/null + fi + + # Disable screensaver + if command -v xset &> /dev/null; then + DISPLAY=:0 xset s off 2>/dev/null + DISPLAY=:0 xset -dpms 2>/dev/null + DISPLAY=:0 xset dpms force on 2>/dev/null + DISPLAY=:0 xset s reset 2>/dev/null + fi + + # Move mouse to trigger activity + if command -v xdotool &> /dev/null; then + DISPLAY=:0 xdotool mousemove_relative 1 1 2>/dev/null + DISPLAY=:0 xdotool mousemove_relative -1 -1 2>/dev/null + fi + + # Disable monitor power saving + if command -v xrandr &> /dev/null; then + DISPLAY=:0 xrandr --output HDMI-1 --power-profile performance 2>/dev/null || true + fi + + sleep $DISPLAY_TIMEOUT +done diff --git a/.player_heartbeat b/.player_heartbeat index 2fd304d..26cb022 100644 --- a/.player_heartbeat +++ b/.player_heartbeat @@ -1 +1 @@ -1768672780.5973904 \ No newline at end of file +1768673747.1927276 \ No newline at end of file diff --git a/install.sh b/install.sh index b9a295c..a4709ef 100644 --- a/install.sh +++ b/install.sh @@ -349,33 +349,79 @@ EOF cat > "$DISPLAY_KEEPALIVE" << 'EOF' #!/bin/bash # Aggressive display keep-alive for Raspberry Pi -# Prevents HDMI from powering down +# Supports both X11 and Wayland environments DISPLAY_TIMEOUT=30 +# Detect display server type +detect_display_server() { + if [ -n "$WAYLAND_DISPLAY" ]; then + echo "wayland" + elif [ -n "$DISPLAY" ]; then + echo "x11" + else + echo "unknown" + fi +} + +DISPLAY_SERVER=$(detect_display_server) + while true; do - # Keep HDMI powered on (tvservice command) + # Keep HDMI powered on (works for both X11 and Wayland) if command -v tvservice &> /dev/null; then /usr/bin/tvservice -p 2>/dev/null fi - # Disable screensaver - if command -v xset &> /dev/null; then - DISPLAY=:0 xset s off 2>/dev/null - DISPLAY=:0 xset -dpms 2>/dev/null - DISPLAY=:0 xset dpms force on 2>/dev/null - DISPLAY=:0 xset s reset 2>/dev/null - fi - - # Move mouse to trigger activity - if command -v xdotool &> /dev/null; then - DISPLAY=:0 xdotool mousemove_relative 1 1 2>/dev/null - DISPLAY=:0 xdotool mousemove_relative -1 -1 2>/dev/null - fi - - # Disable monitor power saving - if command -v xrandr &> /dev/null; then - DISPLAY=:0 xrandr --output HDMI-1 --power-profile performance 2>/dev/null || true + if [ "$DISPLAY_SERVER" = "wayland" ]; then + # Wayland-specific power management + + # Method 1: Use wlr-randr for Wayland compositors (if available) + if command -v wlr-randr &> /dev/null; then + wlr-randr --output HDMI-A-1 --on 2>/dev/null || true + fi + + # Method 2: Prevent idle using systemd-inhibit + if command -v systemd-inhibit &> /dev/null; then + # This is already running, but refresh the lock + systemctl --user restart plasma-ksmserver.service 2>/dev/null || true + fi + + # Method 3: Use wlopm (Wayland output power management) + if command -v wlopm &> /dev/null; then + wlopm --on \* 2>/dev/null || true + fi + + # Method 4: Simulate activity via input (works on Wayland) + if command -v ydotool &> /dev/null; then + ydotool mousemove -x 1 -y 1 2>/dev/null || true + ydotool mousemove -x -1 -y -1 2>/dev/null || true + fi + + # Method 5: GNOME/KDE Wayland idle inhibit + if command -v gnome-session-inhibit &> /dev/null; then + # Already inhibited by running process + true + fi + + else + # X11-specific power management (original code) + if command -v xset &> /dev/null; then + DISPLAY=:0 xset s off 2>/dev/null + DISPLAY=:0 xset -dpms 2>/dev/null + DISPLAY=:0 xset dpms force on 2>/dev/null + DISPLAY=:0 xset s reset 2>/dev/null + fi + + # Move mouse to trigger activity + if command -v xdotool &> /dev/null; then + DISPLAY=:0 xdotool mousemove_relative 1 1 2>/dev/null + DISPLAY=:0 xdotool mousemove_relative -1 -1 2>/dev/null + fi + + # Disable monitor power saving + if command -v xrandr &> /dev/null; then + DISPLAY=:0 xrandr --output HDMI-1 --power-profile performance 2>/dev/null || true + fi fi sleep $DISPLAY_TIMEOUT @@ -385,6 +431,35 @@ EOF chmod +x "$DISPLAY_KEEPALIVE" echo "✓ Display keep-alive script created" + # Install Wayland tools if using Wayland + echo "Checking for Wayland and installing necessary tools..." + if [ -n "$WAYLAND_DISPLAY" ] || pgrep -x "wayfire\|sway\|weston\|mutter" > /dev/null; then + echo "Wayland detected - installing Wayland power management tools..." + + # Install wlopm for Wayland output power management + if ! command -v wlopm &> /dev/null; then + echo "Installing wlopm..." + # wlopm might need to be compiled from source or installed via package manager + sudo apt-get install -y wlopm 2>/dev/null || echo "Note: wlopm not available in package manager" + fi + + # Install wlr-randr for wlroots compositors + if ! command -v wlr-randr &> /dev/null; then + echo "Installing wlr-randr..." + sudo apt-get install -y wlr-randr 2>/dev/null || echo "Note: wlr-randr not available" + fi + + # Install ydotool (Wayland's xdotool alternative) + if ! command -v ydotool &> /dev/null; then + echo "Installing ydotool..." + sudo apt-get install -y ydotool 2>/dev/null || echo "Note: ydotool not available" + fi + + echo "✓ Wayland tools installation attempted" + else + echo "X11 detected - using xset/xdotool/xrandr tools" + fi + # Update systemd screen keep-alive service to use this script sudo tee /etc/systemd/system/screen-keepalive.service > /dev/null << EOF [Unit] diff --git a/src/main.py b/src/main.py index 4f15e9e..957726f 100644 --- a/src/main.py +++ b/src/main.py @@ -930,34 +930,55 @@ class SignagePlayer(Widget): def signal_screen_activity(self, dt): """Signal screen activity to prevent power saving/sleep - Uses multiple methods to keep display awake: - 1. xset s reset - Reset screensaver timeout - 2. xset dpms force on - Force display on - 3. xdotool - Move mouse to trigger activity - 4. tvservice - Keep HDMI powered on (Raspberry Pi) - 5. xrandr - Disable monitor power saving + Supports both X11 and Wayland display servers. + Uses multiple methods to keep display awake. """ try: - # Method 1: Reset screensaver timer using xset - os.system('DISPLAY=:0 xset s reset 2>/dev/null') + # Detect display server type + is_wayland = os.environ.get('WAYLAND_DISPLAY') is not None - # Method 2: Force display on - os.system('DISPLAY=:0 xset dpms force on 2>/dev/null') - - # Method 3: Disable DPMS - os.system('DISPLAY=:0 xset -dpms 2>/dev/null') - - # Method 4: Move mouse slightly (subtle, user won't notice) - if os.system('DISPLAY=:0 xdotool mousemove_relative 1 1 2>/dev/null') == 0: - os.system('DISPLAY=:0 xdotool mousemove_relative -1 -1 2>/dev/null') - - # Method 5: Keep HDMI powered on (Raspberry Pi specific) - os.system('/usr/bin/tvservice -p 2>/dev/null') - - # Method 6: Disable monitor power saving via xrandr - os.system('DISPLAY=:0 xrandr --output HDMI-1 --power-profile performance 2>/dev/null || true') + if is_wayland: + # Wayland-specific commands - Logger.debug("SignagePlayer: Screen activity signal sent (display kept awake)") + # Method 1: Use wlopm (Wayland output power management) + os.system('wlopm --on \* 2>/dev/null || true') + + # Method 2: Use wlr-randr for wlroots compositors + os.system('wlr-randr --output HDMI-A-1 --on 2>/dev/null || true') + + # Method 3: Simulate activity via ydotool (Wayland's xdotool alternative) + if os.system('which ydotool 2>/dev/null') == 0: + os.system('ydotool mousemove -x 1 -y 1 2>/dev/null || true') + os.system('ydotool mousemove -x -1 -y -1 2>/dev/null || true') + + # Method 4: Keep HDMI powered on (works on both) + os.system('/usr/bin/tvservice -p 2>/dev/null') + + Logger.debug("SignagePlayer: Wayland screen activity signal sent") + + else: + # X11-specific commands (original code) + + # Method 1: Reset screensaver timer using xset + os.system('DISPLAY=:0 xset s reset 2>/dev/null') + + # Method 2: Force display on + os.system('DISPLAY=:0 xset dpms force on 2>/dev/null') + + # Method 3: Disable DPMS + os.system('DISPLAY=:0 xset -dpms 2>/dev/null') + + # Method 4: Move mouse slightly (subtle, user won't notice) + if os.system('DISPLAY=:0 xdotool mousemove_relative 1 1 2>/dev/null') == 0: + os.system('DISPLAY=:0 xdotool mousemove_relative -1 -1 2>/dev/null') + + # Method 5: Keep HDMI powered on (Raspberry Pi specific) + os.system('/usr/bin/tvservice -p 2>/dev/null') + + # Method 6: Disable monitor power saving via xrandr + os.system('DISPLAY=:0 xrandr --output HDMI-1 --power-profile performance 2>/dev/null || true') + + Logger.debug("SignagePlayer: X11 screen activity signal sent") except Exception as e: Logger.debug(f"SignagePlayer: Screen activity signal failed (non-critical): {e}")