aboutsummaryrefslogtreecommitdiff
path: root/bin/gnome-window-switcher
diff options
context:
space:
mode:
Diffstat (limited to 'bin/gnome-window-switcher')
-rwxr-xr-xbin/gnome-window-switcher72
1 files changed, 72 insertions, 0 deletions
diff --git a/bin/gnome-window-switcher b/bin/gnome-window-switcher
new file mode 100755
index 0000000..87cbcdc
--- /dev/null
+++ b/bin/gnome-window-switcher
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+workspace_router_call() {
+ method="$1"
+ shift
+
+ command -v gdbus >/dev/null 2>&1 || return 1
+
+ gdbus call \
+ --session \
+ --dest name.rbenencia.WorkspaceRouter \
+ --object-path /name/rbenencia/WorkspaceRouter \
+ --method "name.rbenencia.WorkspaceRouter.$method" \
+ "$@"
+}
+
+list_windows_json() {
+ workspace_router_call ListWindows |
+ sed -n "s/^('\\(.*\\)',)\$/\\1/p"
+}
+
+activate_window() {
+ window_id="$1"
+ workspace_router_call ActivateWindow "uint32:$window_id" >/dev/null
+}
+
+command -v jq >/dev/null 2>&1 || {
+ echo "gnome-window-switcher: jq is required" >&2
+ exit 1
+}
+
+command -v rofi >/dev/null 2>&1 || {
+ echo "gnome-window-switcher: rofi is required" >&2
+ exit 1
+}
+
+windows_json=$(list_windows_json) || {
+ echo "gnome-window-switcher: Workspace Router is unavailable" >&2
+ exit 1
+}
+
+choices=$(
+ printf '%s\n' "$windows_json" |
+ jq -r '
+ sort_by(.workspace, .appName, .title)
+ | .[]
+ | [.id, ("[" + ((.workspace + 1) | tostring) + "]"), (.appName // .wmClass // "Unknown"), (.title // "")]
+ | @tsv
+ '
+)
+
+[ -n "$choices" ] || exit 0
+
+# GNOME invokes custom keybindings before the shortcut is fully released.
+# Give rofi a moment, then force the keyboard grab and focus takeover.
+sleep 0.1
+
+selection=$(
+ printf '%s\n' "$choices" |
+ cut -f2- |
+ rofi -dmenu -i -p "window" -format i -no-lazy-grab -steal-focus
+) || exit 0
+
+window_id=$(
+ printf '%s\n' "$choices" |
+ sed -n "$((selection + 1))p" |
+ cut -f1
+)
+
+[ -n "$window_id" ] || exit 1
+
+activate_window "$window_id"
nihil fit ex nihilo