Add comprehensive documentation for Lenovo ThinkPad Gentoo Linux setup including: - Complete system configuration guides (power, Bluetooth, WiFi, audio) - Hardware setup documentation (touchpad, touchscreen, DisplayLink) - Management scripts with ZSH completions - Kernel configuration (6.12.41-gentoo-x86_64) - Lid automation and monitor management - Battery conservation system - User guides and troubleshooting Repository includes .gitignore to exclude logs, temporary files, and secrets. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
11 KiB
Lid Automation with Suspend/Resume
Overview
Automated lid handling system that intelligently manages displays and power states based on whether external monitors are connected. Provides seamless docking/undocking experience with proper suspend/resume support.
Requirements Met
Based on Lid-Functionality.md specifications:
- ✅ Lid closed + external monitors → Laptop screen turns off, external monitors stay active
- ✅ Lid closed + no external monitors → System suspends to sleep
- ✅ Lid opens from sleep → System resumes and restores monitors
- ✅ Lid opens + external monitors → Three-monitor mode (2 external + laptop)
- ✅ Dock disconnected → Automatically switches to mobile-only mode
- ✅ Dock connected → Auto-detects and enables external monitors
- ✅ Waybar restart → Automatically restarts on monitor configuration changes
- ✅ Multi-location support → Handles different monitor configurations
Architecture
The system consists of three components:
ACPI Event (lid open/close)
↓
/etc/acpi/lid.sh (ACPI handler)
↓
/usr/local/bin/lid-handler.sh (Decision logic)
↓
├→ External monitors present → Monitor reconfiguration
└→ No external monitors → System suspend
↓
/lib/elogind/system-sleep/hyprland-resume
↓
Monitor reconfiguration on wake
Components
1. ACPI Lid Event Handler
File: /etc/acpi/lid.sh
Purpose: Receives lid open/close events from ACPI daemon
Function: Minimal event handler that delegates to the comprehensive lid handler without blocking acpid
#!/bin/bash
# Simply delegate to comprehensive handler
/usr/local/bin/lid-handler.sh &
exit 0
Why this design:
- ACPI handlers should return quickly
- Running handler in background prevents blocking acpid
- Keeps ACPI config simple and maintainable
2. Comprehensive Lid Handler
File: /usr/local/bin/lid-handler.sh
Purpose: Intelligent decision-making for lid events
Logic Flow:
-
Detect lid state from
/proc/acpi/button/lid/*/state -
Check for Hyprland and set up environment
-
Count external monitors using
hyprctl monitors -
Make decision:
If lid is CLOSED:
- External monitors present → Disable laptop screen only
- No external monitors → Trigger suspend via
loginctl suspend
If lid is OPEN:
- Reconfigure all monitors (handled by monitor-setup.sh)
Key Features:
- Properly sets Hyprland environment variables for
hyprctlto work - Logs all actions to
/tmp/lid-handler.log - Uses
loginctl suspend(elogind) for proper suspend handling - Non-blocking execution
Environment Setup:
export HYPRLAND_INSTANCE_SIGNATURE=$(ls -t /tmp/hypr/ | head -n1)
export XDG_RUNTIME_DIR="/run/user/$(id -u)"
export WAYLAND_DISPLAY="wayland-0"
3. elogind Resume Hook
File: /lib/elogind/system-sleep/hyprland-resume
Purpose: Restores monitor configuration after waking from suspend
Execution: Automatically called by elogind with two arguments:
$1 = "pre"before suspend,"post"after resume$2 = "suspend","hibernate", or"hybrid-sleep"
On Resume (post):
- Wait 2 seconds for system to stabilize
- Find user running Hyprland
- Execute monitor-setup.sh as that user
- Log all actions
Why this is needed:
- Monitors may disconnect/reconnect during suspend
- DisplayLink dock needs re-initialization after resume
- Waybar needs restart to update status bar for new monitor layout
Logs: /tmp/elogind-sleep.log
4. Monitor Setup Script
File: /home/alexander/.config/hypr/scripts/monitor-setup.sh
Purpose: Central script for all monitor configuration
Called by:
- Lid handler (when lid state changes)
- Resume hook (when waking from suspend)
- DisplayLink hotplug (when dock connects/disconnects)
Already implemented and working correctly.
Installation
All scripts are prepared in /tmp/. To install:
su -
/tmp/install-lid-automation.sh
exit
What the installer does:
- Copies lid handler to
/usr/local/bin/ - Creates elogind sleep hook directory if needed
- Installs resume hook in
/lib/elogind/system-sleep/ - Replaces ACPI lid handler in
/etc/acpi/lid.sh - Restarts acpid service to activate changes
Testing
Test 1: Lid Close with External Monitors
Procedure:
- Connect USB-C dock with external monitors
- Verify external monitors are working
- Close laptop lid
Expected Result:
- Laptop screen turns off immediately
- External monitors continue working
- No system suspend
Verify:
tail -f /tmp/lid-handler.log
Should show: "External monitors detected" and "Disable laptop screen"
Test 2: Lid Close without External Monitors
Procedure:
- Disconnect USB-C dock
- Verify only laptop screen is active
- Close laptop lid
Expected Result:
- System suspends within 1 second
- Power LED should blink (suspend indicator)
Verify: After waking, check logs:
tail /tmp/lid-handler.log
Should show: "No external monitors" and "suspending system"
Test 3: Resume from Suspend
Procedure:
- With laptop suspended (from Test 2)
- Open laptop lid
Expected Result:
- System wakes immediately
- Laptop screen turns on
- Login prompt appears
- Monitors restore to correct configuration
Verify:
tail /tmp/elogind-sleep.log
Should show: "Waking from sleep" and "Monitor reconfiguration triggered"
Test 4: Three-Monitor Mode
Procedure:
- Connect USB-C dock with external monitors
- Open laptop lid (if closed)
Expected Result:
- Two external monitors: 2560x1440@60Hz side-by-side at top
- Laptop monitor: 2880x1800@120Hz centered below
- All three monitors active simultaneously
Verify:
hyprctl monitors
Should show 3 active monitors: eDP-1, DVI-I-1, DVI-I-2
Test 5: Dock Hotplug
Procedure:
- With laptop lid open, disconnect USB-C dock
- Wait 2-3 seconds
- Reconnect USB-C dock
Expected Result:
- On disconnect: Switches to laptop-only mode
- On reconnect: External monitors appear and configure automatically
- Waybar restarts on each change
Verify:
tail -f /tmp/displaylink-hotplug.log
Troubleshooting
Lid close doesn't suspend
Check:
cat /etc/elogind/logind.conf | grep HandleLidSwitch
Should show:
HandleLidSwitch=ignore
HandleLidSwitchExternalPower=ignore
HandleLidSwitchDocked=ignore
Our script handles lid logic, not elogind. This is correct.
Test suspend manually:
loginctl suspend
If this doesn't work, check:
cat /sys/power/state
Should include mem or s2idle.
Monitors don't restore after resume
Check logs:
tail -20 /tmp/elogind-sleep.log
tail -20 /tmp/hyprland-monitor-setup.log
Common issues:
- DisplayLink dock needs 2-3 seconds to re-initialize after resume
- Increase sleep time in resume hook if needed
Manual test: After resume, run:
~/.config/hypr/scripts/monitor-setup.sh
ACPI lid events not triggering
Check acpid is running:
rc-status | grep acpid
Test ACPI events:
# Clear log
> /tmp/lid-handler.log
# Close lid, wait, open lid
# Check log
cat /tmp/lid-handler.log
If no entries, check ACPI event:
acpi_listen
# Close and open lid - should see events
Logs
All components log their actions:
| Log File | What It Contains |
|---|---|
/tmp/lid-handler.log |
Lid event decisions and actions |
/tmp/elogind-sleep.log |
Suspend/resume events |
/tmp/hyprland-monitor-setup.log |
Monitor configuration details |
/tmp/displaylink-hotplug.log |
Dock connection/disconnection |
Monitor all logs simultaneously:
tail -f /tmp/lid-handler.log /tmp/elogind-sleep.log /tmp/hyprland-monitor-setup.log
Configuration
Single User System
The system is designed for single-user operation (alexander). The scripts automatically detect the user running Hyprland.
Different Monitor Configurations
The monitor setup script uses preferred resolution and auto-positioning. To support different locations (work/home) with different monitors:
Option 1: Let it auto-configure (current approach)
- Works for most setups
- Monitors use their preferred resolution
Option 2: Create location profiles (future enhancement)
- Detect location by monitor serial numbers
- Load specific configuration per location
- Requires extending monitor-setup.sh
Dependencies
- elogind: Session management and suspend/resume
- acpid: ACPI event handling
- hyprland: Window manager with hyprctl
- jq: JSON parsing for monitor queries
- loginctl: elogind control utility
All dependencies are already installed and working.
Files Modified/Created
| File | Action | Purpose |
|---|---|---|
/usr/local/bin/lid-handler.sh |
Created | Main lid event logic |
/lib/elogind/system-sleep/hyprland-resume |
Created | Resume hook |
/etc/acpi/lid.sh |
Replaced | ACPI event entry point |
/home/alexander/.config/hypr/scripts/monitor-setup.sh |
Already exists | Monitor configuration |
Design Decisions
Why not let elogind handle lid events?
Problem: elogind's lid handling is all-or-nothing:
HandleLidSwitch=suspend→ Always suspends (even with external monitors)HandleLidSwitch=ignore→ Never suspends (manual suspend only)
Solution: Custom logic that considers external monitor state.
Why use loginctl suspend instead of writing to /sys/power/state?
Reasons:
- elogind handles pre-suspend tasks (session locking, service notifications)
- Proper resume hook execution
- Better integration with session management
- Logs in journal/syslog
Why run handler in background from ACPI?
Reasons:
- ACPI handlers should return quickly (< 1 second)
- Suspend takes time, would block acpid
- Other ACPI events (power button, dock) need to be handled concurrently
Why wait 2 seconds on resume?
Reasons:
- DisplayLink USB devices need time to re-enumerate
- Kernel drivers need to re-initialize
- Too fast = monitors not detected yet
- Too slow = user sees blank screens longer
Tunable: Adjust sleep time in /lib/elogind/system-sleep/hyprland-resume if needed.
Future Enhancements
1. Monitor Configuration Profiles
- Detect location by monitor serial numbers
- Load specific layouts per location
- Store in
~/.config/hypr/monitor-profiles/
2. Lock Screen on Suspend
- Integrate with swaylock or gtklock
- Lock before suspend, unlock on resume
3. Notification on Dock Connect/Disconnect
- Use mako to show notifications
- "Dock connected: 2 monitors"
- "Switched to mobile mode"
4. Faster Resume
- Pre-load DisplayLink configuration
- Reduce sleep time by detecting device readiness
5. Hibernation Support
- Similar to suspend but saves to disk
- Requires swap configuration
- Useful for extended battery life
References
- elogind documentation:
/usr/share/doc/elogind-*/ - ACPI specification: https://www.kernel.org/doc/Documentation/acpi/
- Original requirements:
Lid-Functionality.md - Monitor configuration:
Monitor-Dock-via-DisplayLink.md