Windows Super+P style display mode switcher for Hyprland
A fast, minimal TUI tool for switching display modes on Hyprland. Switch between laptop-only, external-only, extend, and mirror modes with a single keypress—just like Windows Super+P.
Get HyprMode running in 5 minutes. Follow these steps in order:
yay -S hyprmodeAUR helpers like yay cache package builds locally. If a new version was just released and you see an old version:
Clear cache and reinstall:
yay -Sc
yay -S hyprmodeOr force rebuild:
yay -S hyprmode --rebuild --cleanafter# Clone the repository
git clone https://github.com/Zeus-Deus/hyprmode.git
cd hyprmode
# Run the installer
chmod +x install.sh
./install.shThe installer will set up both the main tool and the emergency recovery daemon (prevents black screens when unplugging monitors).
Dependencies (Arch Linux):
sudo pacman -S python-textualAdd this keybinding to launch HyprMode with SUPER+SHIFT+P:
For Omarchy users (< 3.2 with Alacritty):
echo 'bindd = SUPER SHIFT, P, Display switcher, exec, alacritty --class hyprmode -e hyprmode' >> ~/.config/hypr/bindings.confFor Omarchy users (>= 3.2 with Ghostty):
echo 'bindd = SUPER SHIFT, P, Display switcher, exec, ghostty --title=hyprmode -e hyprmode' >> ~/.config/hypr/bindings.confFor standard Hyprland users (Kitty):
echo 'bind = SUPER SHIFT, P, exec, kitty --class hyprmode -e hyprmode' >> ~/.config/hypr/hyprland.confFor Foot users:
echo 'bind = SUPER SHIFT, P, exec, foot --app-id=hyprmode hyprmode' >> ~/.config/hypr/hyprland.confNote: The
--class,--title, or--app-idflag is required so Hyprland can identify the HyprMode window and apply the floating/centering rules. Choose the command that matches your terminal. Ghostty requires--titleinstead of--class.
HyprMode needs to float and center on your screen. Choose the rules that match your terminal:
For Ghostty users:
cat >> ~/.config/hypr/windows.conf << 'EOF'
# HyprMode - Float and center (for Ghostty terminal)
windowrule = float on, center on, size 600 530, opacity 0.95, match:title ^(hyprmode)$
EOFFor Alacritty/Kitty users:
cat >> ~/.config/hypr/windows.conf << 'EOF'
# HyprMode - Float and center (for Alacritty/Kitty)
windowrule = float on, center on, size 600 530, opacity 0.95, match:class ^(hyprmode)$
EOFFor Foot users:
cat >> ~/.config/hypr/windows.conf << 'EOF'
# HyprMode - Float and center (for Foot terminal)
windowrule = float on, center on, size 600 530, opacity 0.95, match:class ^(hyprmode)$
EOFNote: Ghostty uses
title:matching, Alacritty/Kitty useclass:matching, and Foot usesapp-id:matching. Make sure to use the correct window rules for your terminal.
For Omarchy users only - ensure windows.conf is sourced in your main config:
# Check if already sourced
if ! grep -q "windows.conf" ~/.config/hypr/hyprland.conf; then
echo "source = ~/.config/hypr/windows.conf" >> ~/.config/hypr/hyprland.conf
fiThe emergency recovery daemon prevents black screens when you unplug monitors. Enable it to start automatically:
systemctl --user enable hyprmode-daemon.service
systemctl --user start hyprmode-daemon.serviceApply all the changes:
hyprctl reloadTest that HyprMode launches correctly:
Press SUPER+SHIFT+P to confirm the keybinding works.
You should see a centered floating window with display mode options. Use j/k or arrow keys to navigate, Enter to select, and q to quit.
If it doesn't work: See the Troubleshooting section below.
✅ Setup Complete! Press SUPER+SHIFT+P anytime to switch display modes.
For advanced configuration, technical details, and troubleshooting, see the sections below.
HyprMode gives you four display modes, just like Windows Super+P:
- 💻 Laptop Only - Only your laptop screen is active (external displays disabled)
- 🖥️ External Only - Only external monitor is active (laptop screen disabled)
↔️ Extend - Both displays active, external positioned to the right- 🔄 Mirror - Both displays show identical content
- Fast switching - Change display modes in under a second
- Emergency recovery - Daemon automatically restores your laptop screen if all monitors disconnect
- Lid-aware - Automatically handles laptop lid open/close events
- Beautiful TUI - Clean interface with vim keybindings
- Theme support - Auto-detects Omarchy themes
Run hyprmode from terminal or press SUPER+SHIFT+P:
hyprmodeNavigation:
j/Down- Move downk/Up- Move upEnter- Apply selected modeq- Quit
The daemon runs in the background and monitors for monitor disconnections. If you're in "External Only" mode and unplug your HDMI cable, the daemon automatically restores your laptop screen within 1 second.
Check daemon status:
systemctl --user status hyprmode-daemonView live logs:
journalctl --user -u hyprmode-daemon -fYou should see HEARTBEAT messages every second, confirming the daemon is monitoring.
The default HyprMode window is 600x530 pixels. To change it:
nano ~/.config/hypr/windows.conf # or hyprland.confChange the size line (use the matching type for your terminal):
# For Alacritty/Kitty
# HyprMode - Float and center
windowrule = size 600 530, match:class ^(hyprmode)$ # Default
windowrule = size 550 400, match:class ^(hyprmode)$ # Smaller
windowrule = size 700 600, match:class ^(hyprmode)$ # Larger
# For Ghostty
windowrule = size 600 530, match:title ^(hyprmode)$ # Default
windowrule = size 550 400, match:title ^(hyprmode)$ # Smaller
windowrule = size 700 600, match:title ^(hyprmode)$ # Larger
# For Foot
windowrule = size 600 530, match:class ^(hyprmode)$ # Default
windowrule = size 550 400, match:class ^(hyprmode)$ # Smaller
windowrule = size 700 600, match:class ^(hyprmode)$ # Larger
Then reload: hyprctl reload
Don't like SUPER+SHIFT+P? You can use any key combination. Just edit your binding:
Example with SUPER+P (no shift) - Alacritty:
bind = SUPER, P, exec, alacritty --class hyprmode -e hyprmode
Example with SUPER+P (no shift) - Ghostty:
bind = SUPER, P, exec, ghostty --title=hyprmode -e hyprmode
Example with SUPER+D - Alacritty:
bind = SUPER, D, exec, alacritty --class hyprmode -e hyprmode
Example with SUPER+D - Ghostty:
bind = SUPER, D, exec, ghostty --title=hyprmode -e hyprmode
The installer auto-detects your laptop monitor and creates ~/.config/hypr/lid-switch.conf with lid event bindings:
# When lid closes - disable laptop display
bindl = , switch:on:Lid Switch, exec, hyprctl keyword monitor "eDP-2,disable"
# When lid opens - restore laptop display
bindl = , switch:off:Lid Switch, exec, hyprctl keyword monitor "eDP-2,1920x1200@165,auto,1.25"
This uses Hyprland's native bindl (bind lid switch) feature for instant, zero-CPU-overhead detection. The installer automatically detects your laptop monitor name (eDP-1, eDP-2, etc.) and resolution.
After installation, reload Hyprland: hyprctl reload
If you're creating wrapper scripts or want to auto-detect the terminal, use this helper function:
def build_terminal_command():
import os
terminal = os.environ.get("TERMINAL", "alacritty").lower()
flags = {
"alacritty": "--class hyprmode -e",
"ghostty": "--title=hyprmode -e",
"kitty": "--class hyprmode -e",
"foot": "--app-id=hyprmode",
}
flag = flags.get(terminal, "-e")
return f"{terminal} {flag} hyprmode"This automatically selects the correct --class, --title, or --app-id flag based on your $TERMINAL environment variable.
Problem: The window opens but isn't floating/centered.
Solution: Make sure you added the window rules and reloaded Hyprland:
hyprctl reloadVerify the rules are loaded:
hyprctl getoption windowrulev2 | grep hyprmodeProblem: HyprMode can't find hyprctl.
Solution: Make sure you're running Hyprland (not X11/other Wayland compositors). HyprMode only works on Hyprland.
Problem: HyprMode can't detect your displays.
Solution: Check that Hyprland sees your monitors:
hyprctl monitors -jIf this command fails, Hyprland isn't running or has an issue.
Problem: Pressing SUPER+SHIFT+P does nothing.
Solution:
- Verify the binding was added:
grep -i "hyprmode" ~/.config/hypr/bindings.conf ~/.config/hypr/hyprland.conf- Make sure you reloaded Hyprland after adding the binding:
hyprctl reload- Test if HyprMode works from terminal:
hyprmodeIf it works from terminal but not from the keybind, check your terminal's executable name matches the command.
Problem: Emergency recovery daemon isn't running.
Solution:
- Check daemon status:
systemctl --user status hyprmode-daemon- If it shows "failed", check logs:
journalctl --user -u hyprmode-daemon -n 50- Verify daemon is enabled:
systemctl --user is-enabled hyprmode-daemon- If disabled, enable it:
systemctl --user enable hyprmode-daemon
systemctl --user start hyprmode-daemonProblem: Unplugging HDMI in "External Only" mode doesn't restore laptop screen.
Solution:
- Verify daemon is running and monitoring:
journalctl --user -u hyprmode-daemon -fYou should see HEARTBEAT messages every second.
- If no heartbeat, restart the daemon:
systemctl --user restart hyprmode-daemon-
Test emergency recovery:
- Plug in external monitor
- Run
hyprmodeand switch to "External Only" - Unplug HDMI cable
- Laptop screen should restore within 1 second
-
Check logs for emergency event:
journalctl --user -u hyprmode-daemon | grep "EMERGENCY"Expected output:
⚠️ EMERGENCY: No active monitors detected!
✓ Emergency recovery executed
Problem: Laptop screen is "disabled" but still shows some display output.
Solution: This is a display driver issue, not a HyprMode issue. The monitor is properly disabled in Hyprland. Some laptop displays show residual artifacts when disabled—this is normal hardware behavior.
Problem: I have 2+ external monitors and HyprMode only uses one.
Solution: HyprMode currently uses the first detected external monitor. Multi-monitor support may be added in the future. For now, you can manually configure additional monitors using hyprctl.
Problem: Daemon shows wrong version or old code is running.
Solution: Force a clean reinstall:
cd ~/Documents/hyprmode # or wherever you cloned it
# Complete uninstall
./uninstall.sh
# Clean Python bytecode cache
sudo find /usr/local/bin -name "*.pyc" -delete
find ~/.cache -name "*hyprmode*.pyc" -delete
# Reinstall
./install.sh
# Verify correct version
journalctl --user -u hyprmode-daemon | grep "VERSION"HyprMode consists of two tools:
- hyprmode - Interactive TUI for switching display modes
- hyprmode-daemon - Emergency recovery daemon that monitors for monitor disconnections
Both are installed together and work seamlessly.
- Uses
hyprctl monitors all -jto detect all monitors (including disabled ones) - Falls back to
hyprctl monitors -jfor older Hyprland versions - Identifies laptop display by "eDP" in monitor name
- Handles multiple external monitors (uses first detected)
HyprMode uses these hyprctl commands internally:
# Disable monitor
hyprctl keyword monitor "MONITOR_NAME,disable"
# Enable with auto-detection
hyprctl keyword monitor "MONITOR_NAME,preferred,auto,1"
# Extend mode
hyprctl keyword monitor "LAPTOP,preferred,0x0,1"
hyprctl keyword monitor "EXTERNAL,preferred,auto-right,1"
# Mirror mode
hyprctl keyword monitor "EXTERNAL,WIDTHxHEIGHT@REFRESH,0x0,1,mirror,LAPTOP"Monitor Detection Method:
- Uses
hyprctl monitors -jwithdpmsStatusfield - Checks if display is actually powered on (
dpmsStatus == True) - More reliable than the
disabledfield
Startup Behavior:
- Waits up to 30 seconds for Hyprland to be ready
- Auto-retries via systemd if first attempt fails
- Typical success on 2nd attempt (6 seconds after boot)
Performance:
- Polls every 1 second (negligible CPU usage)
- Memory footprint: ~6-7MB
- Response time: < 1 second for emergency recovery
Safety Features:
- Python bytecode caching bypass (prevents stale code)
- Version tracking (verify correct code is running)
- Comprehensive error logging
- Automatic systemd restart on failure
/usr/local/bin/hyprmode- Main TUI tool/usr/local/bin/hyprmode-daemon- Emergency recovery daemon/usr/local/bin/hyprmode-daemon-wrapper- Python wrapper script~/.config/systemd/user/hyprmode-daemon.service- Systemd service~/.config/hypr/lid-switch.conf- Automatic lid handling config (created by installer)
# Manual mode
python hyprmode.py
# Daemon mode
python hyprmode-daemon.pyhyprmode/
├── hyprmode.py # Main TUI application
├── hyprmode-daemon.py # Emergency recovery daemon
├── hyprmode-daemon-wrapper # Daemon wrapper script
├── hyprmode-daemon.service # Systemd service unit
├── install.sh # Installation script
├── uninstall.sh # Uninstallation script
├── README.md # This file
└── LICENSE # MIT License
Check Hyprland monitor state:
# View all monitors (including disabled)
hyprctl monitors all -j | jq
# View only active monitors
hyprctl monitors -j | jq
# Check specific monitor's dpmsStatus
hyprctl monitors -j | jq '.[] | {name, dpmsStatus, disabled}'Monitor daemon in real-time:
# Follow daemon logs live
journalctl --user -u hyprmode-daemon -f
# Show last 100 lines
journalctl --user -u hyprmode-daemon -n 100
# Show logs from specific time
journalctl --user -u hyprmode-daemon --since "5 minutes ago"
# Show only emergency events
journalctl --user -u hyprmode-daemon | grep "EMERGENCY"Verify installation:
# Check all installed files exist
ls -la /usr/local/bin/hyprmode*
ls -la ~/.config/systemd/user/hyprmode-daemon.service
# Verify service is enabled
systemctl --user is-enabled hyprmode-daemon
# Check what systemd is actually executing
systemctl --user show hyprmode-daemon | grep ExecStartNormal operation (healthy daemon):
✓ Hyprland is ready
HyprMode Daemon VERSION: 2025-10-19-PRODUCTION-v1
hyprmode emergency recovery daemon started
Monitoring for external display disconnect...
HEARTBEAT
Detected: 2 monitors, has_laptop=True
First boot attempt (normal behavior):
Waiting for Hyprland to start...
ERROR: Hyprland failed to start after 30 seconds
hyprmode-daemon.service: Failed with result 'exit-code'.
Scheduled restart job, restart counter is at 1.
This is expected on boot - systemd automatically retries and succeeds.
Emergency recovery in action:
Detected: 1 monitors, has_laptop=False # External Only mode
Detected: 0 monitors, has_laptop=False # HDMI unplugged!
⚠️ EMERGENCY: No active monitors detected!
✓ Emergency recovery executed
Detected: 1 monitors, has_laptop=True # Laptop restored
To remove HyprMode completely:
cd ~/Documents/hyprmode # or wherever you cloned it
chmod +x uninstall.sh
./uninstall.shThis removes all installed files and disables the daemon service.
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
MIT License - see LICENSE file for details
- Built with Textual TUI framework
- Inspired by Windows Super+P functionality
- Made for Hyprland Wayland compositor
- Repository: https://github.com/Zeus-Deus/hyprmode
- Issues: https://github.com/Zeus-Deus/hyprmode/issues
- Hyprland: https://hyprland.org/
- Textual: https://textual.textualize.io/
