Instantly share code, notes, and snippets.
Last active
November 16, 2021 03:07
-
Star
2
(2)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save promovicz/e0c194151670446ee671af047b0bead5 to your computer and use it in GitHub Desktop.
Enhanced dmenu for use with qubes and i3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Example use: | |
# qubes control | |
bindsym $mod+u exec --no-startup-id "qubes-i3-dmenu-shell --start" | |
bindsym $mod+Shift+u exec --no-startup-id "qubes-i3-dmenu-shell --pause" | |
bindsym $mod+i exec --no-startup-id "qubes-i3-dmenu-shell --shutdown" | |
bindsym $mod+Shift+i exec --no-startup-id "qubes-i3-dmenu-shell --unpause" | |
# qubes launching | |
bindsym $mod+o exec --no-startup-id "qubes-i3-dmenu-shell --global" | |
bindsym $mod+Shift+o exec --no-startup-id "qubes-i3-dmenu-shell --global" | |
bindsym $mod+p exec --no-startup-id "qubes-i3-dmenu-shell --select --running" | |
bindsym $mod+Shift+p exec --no-startup-id "qubes-i3-dmenu-shell --select" | |
bindsym $mod+w exec --no-startup-id "qubes-i3-dmenu-shell --window-domain" | |
bindsym $mod+Shift+w exec --no-startup-id "qubes-i3-dmenu-shell --window-template" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
set -e | |
PROGRAM="$0" | |
NAME="$(basename "${PROGRAM}")" | |
say() { | |
echo "${NAME}: $*" 1>&2 | |
} | |
quote() { | |
for s in "$@"; do | |
printf %q "${s}" | |
done | |
} | |
main() { | |
local nb="#d2d2d2" | |
local nf="#000000" | |
local sb="#63a0ff" | |
local sf="#ffffff" | |
local rest="" | |
local idx=0 | |
while [ $# -gt 0 ]; do | |
case $1 in | |
-nb) | |
nb="$2" | |
shift 2 | |
;; | |
-nf) | |
nf="$2" | |
shift 2 | |
;; | |
-sb) | |
sb="$2" | |
shift 2 | |
;; | |
-sf) | |
sf="$2" | |
shift 2 | |
;; | |
*) | |
rest="${rest} $(quote "$1")" | |
shift 1 | |
;; | |
esac | |
idx=$(( ${idx} + 1 )) | |
done | |
eval "dmenu -nb '${nb}' -nf '${nf}' -sb '${sb}' -sf '${sf}' ${rest}" | |
} | |
main "$@" || say "The program has failed" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -e | |
PROGRAM="$0" | |
NAME="$(basename "${PROGRAM}")" | |
run_terminal=' | |
for t in "$TERMINAL" x-terminal-emulator urxvt rxvt termit terminator Eterm aterm gnome-terminal konsole roxterm xfce4-terminal termite lxterminal mate-terminal terminology st xterm; do | |
command -v "$t" > /dev/null 2>&1 && exec "$t"; | |
done | |
' | |
# default color | |
#sb_default='#63a0ff' | |
sb_default='#2004A0' | |
#sb_default='#204080' | |
#sb_default='#080808' | |
# i3 focused | |
sb_dom0='#522702' | |
sb_red='#e53b27' | |
sb_orange='#d05f03' | |
sb_yellow='#999b00' | |
sb_green='#04af5b' | |
sb_gray='#8c959f' | |
sb_blue='#3384d6' | |
sb_purple='#8f5cbe' | |
sb_black='#595959' | |
# i3 unfocused | |
#sb_dom0='#361a01' | |
#sb_red='#902519' | |
#sb_orange='#7b3702' | |
#sb_yellow='#666700' | |
#sb_green='#02713b' | |
#sb_gray='#676d75' | |
#sb_blue='#1f5082' | |
#sb_purple='#5c3e78' | |
#sb_black='#3a3a3a' | |
# say <message>... | |
# | |
# Log a message to stderr. | |
# | |
say() { | |
echo "${NAME}: $*" 1>&2 | |
} | |
# get_active_window | |
# | |
# Get the window id of the active window. | |
# | |
get_active_window() { | |
local id=$(xprop -root _NET_ACTIVE_WINDOW) | |
local rid=${id##* } # extract raw id | |
if [ "${rid}" != "0x0" ]; then | |
echo "${rid}" | |
fi | |
} | |
# get_window_vm <wid> | |
# | |
# Get the VM of the given window. | |
# | |
get_window_vm() { | |
local id="$1" | |
local vm=$(xprop -id "${id}" | grep '_QUBES_VMNAME(STRING)') | |
local vm=${vm#*\"} # extract vmname | |
echo ${vm%\"*} # extract vmname | |
} | |
# get_active_vm | |
# | |
# Get the active VM based on the active window. | |
# | |
#get_active_vm() { | |
# local win="$(get_active_window)" | |
# if [ -n "${win}" ]; then | |
# get_window_vm "${win}" | |
# fi | |
#} | |
# get_vm_label <vm> | |
# | |
# Get label color of VM. | |
# | |
get_vm_label() { | |
local vms="$@" | |
for vm in "${vms}"; do | |
qvm-ls --raw-data -O label "${vm}" | |
done | |
} | |
# get_vm_color <vm> | |
# | |
# Get background color for VM. | |
# | |
get_vm_color() { | |
local vm="$1" | |
local label="$(get_vm_label "${vm}")" | |
local color="$(eval "echo \${sb_${label}}")" | |
if [ -z "${color}" ]; then | |
color="${sb_default}" | |
fi | |
echo -n "${color}" | |
} | |
# get_vm_template <vm> | |
# | |
# Get template for VM. | |
# | |
get_vm_template() { | |
local vm="$1" | |
qvm-prefs "${vm}" template 2> /dev/null | |
} | |
# run_dmenu <options>... | |
# | |
# Run an instance of dmenu with our settings. | |
# | |
run_dmenu() { | |
qubes-i3-dmenu -sb "${sb_default}" "$@" | |
} | |
# run_dmenu_message <options>... | |
# | |
# Use dmenu to show a message with confirm. | |
# | |
run_dmenu_message() { | |
echo dismiss | run_dmenu "$@" > /dev/null | |
} | |
# run_dmenu_error <options>... | |
# | |
# Use dmenu to show an error with confirm. | |
# | |
run_dmenu_error() { | |
echo dismiss | run_dmenu "$@" > /dev/null | |
} | |
# run_dmenu_confirm <message> <token>... | |
# | |
# Use dmenu for a confirmation message. | |
# | |
# The given tokens will be presented as dmenu items | |
# to be skipped with the cursor as intent confirmation. | |
# | |
run_dmenu_confirm() { | |
local message="$1" | |
shift 1 | |
echo "$@" "-->" "[confirm]" | tr ' ' '\n' \ | |
| run_dmenu -p "${message}" \ | |
| grep -q '^\[confirm\]$' > /dev/null | |
} | |
# run_dmenu_select_vm <prompt> <filter>... | |
# | |
# Run dmenu to select a VM. | |
# | |
run_dmenu_select_vm() { | |
local prompt="$1" | |
shift 1 | |
local rules="class=*" | |
if [ $# -ge 1 ]; then | |
rules="${rules} $(echo "$*" | sed -e 's/[ ]*\-\-all \-\-exclude dom0[ ]*//' -e 's/--//g')" | |
fi | |
say "Running dmenu to select VMs $*" | |
qvm-ls --raw-list "$@" | run_dmenu -p "${prompt} (${rules})" | |
} | |
# run_dmenu_select_vm_class <prompt> <class> <filter>... | |
# | |
# Run dmenu to select a VM, select on class. | |
# | |
# Needed because qvm-ls can't filter on class. | |
# | |
run_dmenu_select_vm_class() { | |
local prompt="$1" | |
local class="$2" | |
shift 2 | |
local rules="class=${class}" | |
if [ $# -ge 1 ]; then | |
rules="${rules} $(echo "$*" | sed -e 's/[ ]*\-\-all \-\-exclude dom0[ ]*//' -e 's/--//g')" | |
fi | |
say "Running dmenu to select VMs with ${rules}" | |
qvm-ls --raw-data -O NAME,CLASS "$@" \ | |
| awk -F \| "{ if ( \$2 == \"${class}\" ) { print \$1 } }" \ | |
| run_dmenu -p "${prompt} (${rules})" | |
} | |
# run_dmenu_desktop_global | |
# | |
# Run dmenu to select desktop files on dom0. | |
# | |
run_dmenu_desktop_global() { | |
say "Running dmenu for desktop files of dom0" | |
i3-dmenu-desktop --dmenu "qubes-i3-dmenu -p 'launch (dom0)' -sb '${sb_default}'" | |
} | |
# run_dmenu_desktop_global <vm> | |
# | |
# Run dmenu to select desktop files for a VM. | |
# | |
run_dmenu_desktop_vm() { | |
local vm="$1" | |
if [ "${vm}" = "dom0" ]; then | |
run_dmenu_desktop_global | |
return $? | |
fi | |
local color="$(get_vm_color "${vm}")" | |
say "Running dmenu for desktop files of ${vm}" | |
local label="$(get_vm_label "${vm}")" | |
local cmd="grep '^${vm}: ' | sed 's/^${vm}: //' | qubes-i3-dmenu -p '${vm}' -sb '${color}' | sed 's/.*/${vm}: \0/'" | |
i3-dmenu-desktop --dmenu "${cmd}" | |
} | |
# kill_previous | |
# | |
# Kill other instances of this tool. | |
# | |
kill_previous() { | |
killall -qe -o '1s' -u "${USER}" qubes-i3-dmenu-shell qubes-i3-dmenu dmenu || true | |
} | |
# main <arg>... | |
# | |
# Main program. | |
# | |
main() { | |
local mode="" | |
local modeparm="" | |
local rest="" | |
say "Started with parameters: $*" | |
while [ $# -gt 0 ]; do | |
#say "A: $1" | |
case "$1" in | |
--global|--select|--start|--shutdown|--pause|--unpause|--window-domain|--window-template) | |
mode="$1" | |
shift 1 | |
;; | |
--domain|--template) | |
mode="$1" | |
modeparm="$2" | |
if [ -z "${modeparm}" ]; then | |
say "Usage: ${NAME} ${mode} <domain>" | |
return 1 | |
fi | |
shift 2 | |
;; | |
--message|--error) | |
mode="$1" | |
modeparm="$2" | |
if [ -u "${modeparm}" ]; then | |
say "Usage: ${NAME} ${mode} <message>" | |
fi | |
shift 2 | |
;; | |
--system-poweroff|--system-reboot|--session-quit) | |
mode="$1" | |
shift 1 | |
;; | |
*) | |
rest="${rest} $1" | |
shift 1 | |
;; | |
esac | |
done | |
local exclude_dom0="--all --exclude dom0" | |
case "${mode}" in | |
--global) | |
run_dmenu_desktop_global | |
;; | |
--select) | |
run_dmenu_select_vm launch ${rest} ${exclude_dom0} | xargs -n1 ${PROGRAM} --domain | |
;; | |
--start) | |
run_dmenu_select_vm start --halted ${exclude_dom0} | xargs qvm-start | |
;; | |
--shutdown) | |
run_dmenu_select_vm shutdown --running --paused ${exclude_dom0} | xargs qvm-shutdown | |
;; | |
--pause) | |
run_dmenu_select_vm pause --running ${exclude_dom0} | xargs qvm-pause | |
;; | |
--unpause) | |
run_dmenu_select_vm unpause --paused ${exclude_dom0} | xargs qvm-unpause | |
;; | |
--domain|--template) | |
local vm="${modeparm}" | |
run_dmenu_desktop_vm "${vm}" | |
;; | |
--template) | |
local vm="${modeparm}" | |
local tm="$(get_vm_template "${vm}")" | |
if [ -z "${tm}" ]; then | |
run_dmenu_error -p "${vm} has no template" | |
return 1 | |
fi | |
run_dmenu_desktop_vm "${tm}" | |
;; | |
--message) | |
run_dmenu_message -p "${modeparm}" ${rest} | |
;; | |
--error) | |
run_dmenu_error -p "${modeparm}" ${rest} | |
;; | |
--system-poweroff) | |
if run_dmenu_confirm "SYSTEM SHUTDOWN" "yes" "please" "halt" "immediately"; then | |
poweroff | |
fi | |
;; | |
--system-reboot) | |
if run_dmenu_confirm "SYSTEM REBOOT" "yes" "please" "reboot" "immediately"; then | |
reboot | |
fi | |
;; | |
--session-quit) | |
if run_dmenu_confirm "SESSION QUIT" "yes" "please" "terminate" "session"; then | |
i3-msg exit | |
fi | |
;; | |
--window-domain) | |
local win="" | |
local vm="" | |
local tm="" | |
win="$(get_active_window)" | |
if [ -n "${win}" ]; then | |
vm="$(get_window_vm "${win}")" | |
fi | |
if [ -n "${vm}" ]; then | |
run_dmenu_desktop_vm "${vm}" | |
else | |
run_dmenu_select_vm launch --running ${exclude_dom0} | xargs -n1 ${PROGRAM} --domain | |
fi | |
;; | |
--window-template) | |
local win="" | |
local vm="" | |
local tm="" | |
win="$(get_active_window)" | |
if [ -n "${win}" ]; then | |
vm="$(get_window_vm "${win}")" | |
if [ -n "${vm}" ]; then | |
tm="$(get_vm_template "${vm}")" | |
if [ -z "${tm}" ]; then | |
run_dmenu_error -p "${vm} has no template" | |
return 1 | |
fi | |
fi | |
fi | |
if [ -n "${tm}" ]; then | |
run_dmenu_desktop_vm "${tm}" | |
else | |
run_dmenu_select_vm_class launch TemplateVM | xargs -n1 ${PROGRAM} --domain | |
fi | |
;; | |
*) | |
say "Unknown mode ${mode}" | |
return 1 | |
;; | |
esac | |
} | |
# kill previous instances | |
kill_previous | |
# run main program, report errors | |
main "$@" || (say "The program has failed."; exit 1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment