A small helper script for MangoWM that provides keyboard-driven application switching similar to pinned applications in GNOME Dash-to-Dock, KDE Plasma, Unity, and the Windows taskbar, where pressing Super+1, Super+2, etc. launches or focuses the corresponding application for fast, direct, and convenient access.
Bind the script to a single key to create an all-in-one application handler. Depending on the current state, it will:
- focus an existing application window
- cycle through multiple windows of the same application
- switch to the previously focused window when no other matching windows exist
- automatically switch between tags
- launch the application if it is not running
Update:
rs.shis now the current version and recommended default.
- MangoWM
- jq
rs [-t|--tag <tag>] [-a|--appid <appid>] [-T|--title <window_title>] [-i|--ignore <ignore_title_fragment>] [-c|--command <mmsg_dispatch_command>] [-n|--no-focuslast] [-- <launch_command...>]You can filter by:
- appid only
- window title only
- both appid and window title
- appid/title with an ignored title fragment
At least one of appid or window_title must be non-empty.
Use -- before the launch command.
| Argument | Description |
|---|---|
-t, --tag |
Tag where the application will be launched if it is not already running (1..9) |
-a, --appid |
Window app ID used by MangoWM |
-T, --title |
Window title or title fragment to match |
-i, --ignore |
Window title fragment to exclude from matches |
-c, --command |
Optional mmsg dispatch command executed after launching and detecting the new window |
-n, --no-focuslast |
Keep the current app focused when there is exactly one matching window, instead of switching back to the previously focused window |
-- <launch_command...> |
Command used to launch the application (variables, arguments and flags are supported). Use sh -c "launch_command" when the command requires shell parsing (pipes, redirects, &&, etc.). |
To inspect appids and titles, use:
mmsg get all-clients | jq -r '.clients[] | [.appid, .title] | @tsv'Focus/cycle/launch Konsole on first tag:
~/.local/bin/rs -t 1 -a org.kde.konsole -- konsoleFocus Nautilus or launch it on current tag:
~/.local/bin/rs -a org.gnome.Nautilus -- GSK_RENDERER=gl nautilus --new-windowLaunch Midnight Commander in Alacritty on current tag or focus matching window by title:
~/.local/bin/rs -T "mc [" -- alacritty -e mcRun Alacritty or focus it while excluding Midnight Commander title fragment:
~/.local/bin/rs -a Alacritty -i "mc [" -- alacrittyRun a complex shell command:
~/.local/bin/rs -a org.gnome.Nautilus -- sh -c "sleep 4 && GSK_RENDERER=gl nautilus --new-window"Launch app on tag 2 and then run an extra mmsg dispatch command:
~/.local/bin/rs -t 2 -a org.kde.konsole -c "set_proportion,0.5" -- konsolebind = SUPER, RETURN, spawn, ~/.local/bin/rs -t 1 -a org.kde.konsole -- konsole
bind = SUPER, e, spawn, ~/.local/bin/rs -a org.gnome.Nautilus -- GSK_RENDERER=gl nautilus
bind = SUPER, m, spawn, ~/.local/bin/rs -T "mc [" -- alacritty -e mc
bind = SUPER,1,spawn, ~/.local/bin/rs -a Alacritty -i "mc [" -- alacrittyIf the app is already focused:
- when another matching window exists, it cycles to the next one
- when only one matching window exists, it switches to the previously focused window unless
-n/--no-focuslastis used
If the app exists but is not focused:
- it focuses the matching window
If the app is not running:
- it switches to the specified tag (when
tagis numeric) - launches the application command
- waits briefly for the new window and optionally runs
mmsg dispatch <command>from-c/--command
Windows marked by MangoWM as is_swallowedby are ignored during matching, and is_swallowing windows are only used as a fallback when no regular matches exist. This keeps swallowed proxy clients out of the way while still allowing apps such as org.gnome.TextEditor opened from tools like Yazi to be focused correctly.
mkdir -p ~/.local/bin
wget -O ~/.local/bin/rs https://raw.githubusercontent.com/mtriam/runorfocus/main/rs.sh
chmod +x ~/.local/bin/rsrf <tag|c> <appid|""> <window_title|""> <ignore_title_fragment|""> <command...>| Argument | Description |
|---|---|
tag |
Tag where the application will be launched if it is not already running |
c |
Use the current tag |
appid |
Window app ID used by MangoWM (use "" to ignore appid matching) |
window_title |
Window title or title fragment to match (use "" to ignore title matching) |
ignore_title_fragment |
Window title fragment to exclude from matches (use "" to disable) |
command |
Command used to launch the application (arguments and flags are supported) |
~/.local/bin/rf 1 org.kde.konsole "" "" konsole
~/.local/bin/rf c org.gnome.Nautilus "" "" GSK_RENDERER=gl nautilus
~/.local/bin/rf c "" "mc [" "" alacritty -e mc
~/.local/bin/rf c Alacritty "" "mc [" alacrittybind = SUPER, RETURN, spawn, ~/.local/bin/rf 1 org.kde.konsole "" "" konsole
bind = SUPER, e, spawn, ~/.local/bin/rf c org.gnome.Nautilus "" "" GSK_RENDERER=gl nautilus
bind = SUPER, m, spawn, ~/.local/bin/rf c "" "mc [" "" alacritty -e mc
bind = SUPER,1,spawn, ~/.local/bin/rf c Alacritty "" "mc [" alacrittymkdir -p ~/.local/bin
wget -O ~/.local/bin/rf https://raw.githubusercontent.com/mtriam/runorfocus/main/rf.sh
wget -O ~/.local/bin/bind_generator_rf https://raw.githubusercontent.com/mtriam/runorfocus/main/bind_generator_rf.sh
chmod +x ~/.local/bin/rf
chmod +x ~/.local/bin/bind_generator_rfUse rfcm (new IPC mmsg) as the primary variant:
rfcm <tag|c> <appid> <command...>Use rfcmt to match by window title instead of appid:
rfcmt <tag|c> <window_title> <command...>Use rfe to run or focus by appid while ignoring a matching title fragment:
rfe <tag|c> <appid> <ignore_title_fragment> <command...>For older IPC-compatible workflows, you can still use:
rof <tag|c> <appid> <process_name> <command...>or
rofw <tag|c> <appid> <command...>| Argument | Description |
|---|---|
tag |
Tag where the application will be launched if it is not already running |
c |
Use the current tag |
appid |
Window app ID used by MangoWM * |
window_title |
Window title or title fragment used to match an existing window for rfcmt ** |
ignore_title_fragment |
Window title fragment to exclude from matching windows for rfe ** |
command |
Command used to launch the application (arguments and flags are supported) |
process_name |
Process name checked with pgrep -x and pgrep -f (legacy IPC variants only) |
* Use mmsg get all-clients | jq -r '.clients[].appid' (or mmsg -w -c and change the active window) to obtain application appids.
** Use mmsg get all-clients | jq -r '.clients[].title' to obtain window titles for rfcmt, or use rfe with a title fragment to exclude a matching window.
New mmsg IPC format:
Focus, cycle, or launch konsole on first tag:
~/.local/bin/rfcm 1 org.kde.konsole konsoleFocus Nautilus or launch it on current tag:
~/.local/bin/rfcm c org.gnome.Nautilus GSK_RENDERER=gl nautilusLaunch Midnight Commander in the Alacritty terminal emulator on current tag or focus it if already open using a window title fragment:
~/.local/bin/rfcmt c "mc [" alacritty -e mcRun Alacritty or focus it if already open, excluding Midnight Commander running in Alacritty:
~/.local/bin/rfe c Alacritty "mc [" alacrittyRun Alacritty or focus it if already open without excluding any title fragment:
~/.local/bin/rfe c Alacritty "" alacrittyOld mmsg IPC format:
Focus or launch konsole using rofw (wlrctl-based) on current tag:
~/.local/bin/rofw c org.kde.konsole konsoleFocus or launch code-oss on first tag:
~/.local/bin/rof 1 code-oss code.mjs code --password-store=gnome-libsecretFocus Nautilus or launch it on second tag:
~/.local/bin/rof 2 org.gnome.Nautilus nautilus GSK_RENDERER=gl nautilusbind = SUPER, RETURN, spawn, ~/.local/bin/rfcm 1 org.kde.konsole konsole
bind = SUPER, e, spawn, ~/.local/bin/rfcm c org.gnome.Nautilus GSK_RENDERER=gl nautilus
bind = SUPER, m, spawn, ~/.local/bin/rfcmt "mc [" alacritty -e mc
bind = SUPER,1,spawn, ~/.local/bin/rfe c Alacritty "mc [" alacrittyGenerate legacy rfcm keybinds:
bash bind_generator.shOlder IPC variants:
bind = SUPER, RETURN, spawn, ~/.local/bin/rof c org.kde.konsole konsole konsole
bind = SUPER, e, spawn, ~/.local/bin/rof 2 org.gnome.Nautilus nautilus GSK_RENDERER=gl nautilusor
bind = SUPER, RETURN, spawn, ~/.local/bin/rofw c org.kde.konsole konsole
bind = SUPER, e, spawn, ~/.local/bin/rofw 2 org.gnome.Nautilus GSK_RENDERER=gl nautilusIf the app is already focused:
The script searches for another matching window and focuses it. If only one matching window exists, it switches to the previously focused window.
This makes repeated key presses behave like a window cycler.
If the app exists but is not focused:
The script focuses the first matching window.
If the app is not running:
- switches to the specified tag
- launches the application
mkdir -p ~/.local/bin
wget -O ~/.local/bin/rfcm https://raw.githubusercontent.com/mtriam/runorfocus/main/rfcm.sh
wget -O ~/.local/bin/rfcmt https://raw.githubusercontent.com/mtriam/runorfocus/main/rfcmt.sh
wget -O ~/.local/bin/rfe https://raw.githubusercontent.com/mtriam/runorfocus/main/rfe.sh
chmod +x ~/.local/bin/rfcm
chmod +x ~/.local/bin/rfcmt
chmod +x ~/.local/bin/rfeor (older IPC variants)
mkdir -p ~/.local/bin
wget -O ~/.local/bin/rof https://raw.githubusercontent.com/mtriam/runorfocus/main/rof.sh
chmod +x ~/.local/bin/rofor
mkdir -p ~/.local/bin
wget -O ~/.local/bin/rofw https://raw.githubusercontent.com/mtriam/runorfocus/main/rofw.sh
chmod +x ~/.local/bin/rofwwlrctl installation examples (depending on your distribution):
- Arch Linux (AUR helper):
# using paru or yay
paru -S wlrctl
# or
yay -S wlrctl- Debian:
sudo apt install wlrctlGPL-3.0