From c4f93571a9d3e724b3971b9a2758598ef002e623 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 28 Dec 2025 16:41:36 +0000 Subject: [PATCH 1/2] Add power button, fix EPIPE errors, fix display schedule - Add red power icon button in top-right corner of UI - Click power button triggers showPowerMenu via IPC - Add EPIPE error suppression for stdout/stderr (no more error dialogs) - Fix display on/off scripts: add XAUTHORITY, hardcode kiosk user - Add logging to display scripts for debugging --- install_kiosk_v0.9.9.1.sh | 61 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/install_kiosk_v0.9.9.1.sh b/install_kiosk_v0.9.9.1.sh index 1933455..cbce7f6 100644 --- a/install_kiosk_v0.9.9.1.sh +++ b/install_kiosk_v0.9.9.1.sh @@ -2646,9 +2646,13 @@ configure_display_schedule() { sudo tee /usr/local/bin/kiosk-display-off.sh > /dev/null </dev/null && echo "✓ xset dpms off" || echo "✗ xset failed" +sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority xset dpms force off 2>/dev/null && logger "KIOSK: xset dpms off success" || logger "KIOSK: xset dpms off failed" # Method 2: vbetool (if available) if command -v vbetool &>/dev/null; then @@ -2672,9 +2676,13 @@ EOF sudo tee /usr/local/bin/kiosk-display-on.sh > /dev/null </dev/null && echo "✓ xset dpms on" || echo "✗ xset failed" +sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority xset dpms force on 2>/dev/null && logger "KIOSK: xset dpms on success" || logger "KIOSK: xset dpms on failed" # Method 2: vbetool (if available) if command -v vbetool &>/dev/null; then @@ -2691,10 +2699,10 @@ if [[ -d /sys/class/backlight ]]; then fi # Method 4: Wake up input (move mouse) -sudo -u $KIOSK_USER DISPLAY=:0 xdotool mousemove 1 1 2>/dev/null && echo "✓ mouse wiggle" || echo "✗ mouse wiggle failed" +sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority xdotool mousemove 1 1 2>/dev/null && logger "KIOSK: mouse wiggle success" || logger "KIOSK: mouse wiggle failed" # Method 5: Signal Electron app to require password if enabled -sudo -u $KIOSK_USER touch /home/$KIOSK_USER/kiosk-app/.display-wake 2>/dev/null && echo "✓ password flag set" || echo "✗ password flag failed" +sudo -u kiosk touch /home/kiosk/kiosk-app/.display-wake 2>/dev/null && logger "KIOSK: password flag set" || logger "KIOSK: password flag failed" logger "KIOSK: Display turned ON (scheduled)" EOF @@ -4017,6 +4025,14 @@ const fs=require('fs'); const path=require('path'); const os=require('os'); +// Suppress EPIPE errors (happen when no terminal attached) +process.stdout.on('error',(e)=>{if(e.code!=='EPIPE')throw e;}); +process.stderr.on('error',(e)=>{if(e.code!=='EPIPE')throw e;}); +process.on('uncaughtException',(e)=>{ + if(e.code==='EPIPE')return; + console.error('Uncaught:',e); +}); + const CONFIG_FILE=path.join(__dirname,'config.json'); const VERSION='0.9.9.1'; @@ -6503,6 +6519,43 @@ window.addEventListener('DOMContentLoaded',()=>{ document.body.appendChild(navButton); } + // Power button in top-right corner + let powerButton=null; + function createPowerButton(){ + if(powerButton)return; + powerButton=document.createElement('div'); + powerButton.id='electron-power-button'; + // Power icon SVG + powerButton.innerHTML=''; + powerButton.title='Power Menu'; + powerButton.style.cssText=` + position:fixed;top:20px;right:20px;width:50px;height:50px; + background:rgba(231,76,60,0.9);border:2px solid rgba(255,255,255,0.8); + border-radius:50%;display:flex;align-items:center;justify-content:center; + cursor:pointer;z-index:999999; + box-shadow:0 4px 12px rgba(0,0,0,0.4);user-select:none; + transition:transform 0.2s,background 0.2s; + `; + powerButton.addEventListener('mouseenter',()=>{ + powerButton.style.transform='scale(1.1)'; + powerButton.style.background='rgba(192,57,43,0.95)'; + }); + powerButton.addEventListener('mouseleave',()=>{ + powerButton.style.transform='scale(1)'; + powerButton.style.background='rgba(231,76,60,0.9)'; + }); + powerButton.addEventListener('click',(e)=>{ + e.preventDefault(); + e.stopPropagation(); + console.log('[POWER] Button clicked'); + ipcRenderer.send('show-power-menu'); + }); + document.body.appendChild(powerButton); + } + + // Create power button on page load + setTimeout(createPowerButton,1000); + function showNavButton(){ if(!navButtonEnabled)return; if(!navButton)createNavButton(); From 4ac9676ef59899988b9f4f39e0ca514e91841be1 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 28 Dec 2025 17:29:27 +0000 Subject: [PATCH 2/2] Power button follows same show/hide logic as nav button - Power button now starts hidden and appears on user interaction - Auto-hides after 5 seconds of inactivity (matching nav button) - Increased size to 60px with 3px border for consistency - Removed hover transitions for simpler, consistent behavior --- install_kiosk_v0.9.9.1.sh | 52 ++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/install_kiosk_v0.9.9.1.sh b/install_kiosk_v0.9.9.1.sh index cbce7f6..10680f6 100644 --- a/install_kiosk_v0.9.9.1.sh +++ b/install_kiosk_v0.9.9.1.sh @@ -6519,8 +6519,10 @@ window.addEventListener('DOMContentLoaded',()=>{ document.body.appendChild(navButton); } - // Power button in top-right corner + // Power button in top-right corner (follows same show/hide logic as nav button) let powerButton=null; + let powerButtonHideTimer=null; + const POWER_BUTTON_HIDE_DELAY=5000; // Same as nav button function createPowerButton(){ if(powerButton)return; powerButton=document.createElement('div'); @@ -6529,21 +6531,12 @@ window.addEventListener('DOMContentLoaded',()=>{ powerButton.innerHTML=''; powerButton.title='Power Menu'; powerButton.style.cssText=` - position:fixed;top:20px;right:20px;width:50px;height:50px; - background:rgba(231,76,60,0.9);border:2px solid rgba(255,255,255,0.8); - border-radius:50%;display:flex;align-items:center;justify-content:center; + position:fixed;top:20px;right:20px;width:60px;height:60px; + background:rgba(231,76,60,0.95);border:3px solid rgba(255,255,255,0.9); + border-radius:50%;display:none;align-items:center;justify-content:center; cursor:pointer;z-index:999999; box-shadow:0 4px 12px rgba(0,0,0,0.4);user-select:none; - transition:transform 0.2s,background 0.2s; `; - powerButton.addEventListener('mouseenter',()=>{ - powerButton.style.transform='scale(1.1)'; - powerButton.style.background='rgba(192,57,43,0.95)'; - }); - powerButton.addEventListener('mouseleave',()=>{ - powerButton.style.transform='scale(1)'; - powerButton.style.background='rgba(231,76,60,0.9)'; - }); powerButton.addEventListener('click',(e)=>{ e.preventDefault(); e.stopPropagation(); @@ -6553,8 +6546,34 @@ window.addEventListener('DOMContentLoaded',()=>{ document.body.appendChild(powerButton); } - // Create power button on page load - setTimeout(createPowerButton,1000); + function showPowerButton(){ + if(!powerButton)createPowerButton(); + if(powerButton){ + powerButton.style.display='flex'; + } + + // Clear existing hide timer + if(powerButtonHideTimer){ + clearTimeout(powerButtonHideTimer); + powerButtonHideTimer=null; + } + + // Set new hide timer - button will auto-hide after inactivity + powerButtonHideTimer=setTimeout(()=>{ + console.log('[POWER-BTN] Auto-hiding after '+POWER_BUTTON_HIDE_DELAY+'ms inactivity'); + hidePowerButton(); + },POWER_BUTTON_HIDE_DELAY); + } + + function hidePowerButton(){ + if(powerButtonHideTimer){ + clearTimeout(powerButtonHideTimer); + powerButtonHideTimer=null; + } + if(powerButton){ + powerButton.style.display='none'; + } + } function showNavButton(){ if(!navButtonEnabled)return; @@ -6956,6 +6975,9 @@ window.addEventListener('DOMContentLoaded',()=>{ if(navButtonEnabled){ showNavButton(); } + + // Always show power button on user interaction + showPowerButton(); } // Show pause button on any user interaction