Skip to content

Instantly share code, notes, and snippets.

@iynaix
Created November 6, 2017 05:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iynaix/8a32bfb599be717c752431ef3d11ba3a to your computer and use it in GitHub Desktop.
Save iynaix/8a32bfb599be717c752431ef3d11ba3a to your computer and use it in GitHub Desktop.
Application Switching and Launch Utility
#! /usr/bin/env python3
"""
USAGE:
1. Put this script somewhere on yout path
2. Assign a keyboard shortcut for opening this script with for your target
application, e.g.
Ctrl-Alt-Shift-1 to launch "wintool chrome"
3. Defaults are provided in the APP_PATHS, modify as necessary
Operation:
3 possible behaviors are possible with this script, depending on what
application windows are currently open on the user's desktop.
Using chrome for example:
a. no chrome windows currently open: launches chrome
b. chrome windows open, user not focused on a chrome window: focuses on a
chrome window
c. user focused on a chrome window: focuses on next chrome window
"""
import os
import re
import subprocess
import sys
from collections import namedtuple
# dictionary of app string: command line invocation of executable
# the app string is provided as the first argument to the command line, e.g.
# wintool chrome
# NOTE: the app string should be a case insensitive substring of the target
# application's WM_CLASS
APP_PATHS = {
# terminal
"tilix": "tilix",
"vim": "gvim",
"emacs": "emacs",
# chrome, replace with desired chrome executable
"chrome": "google-chrome-unstable",
# music player
"deadbeef": "deadbeef",
# file manager
"nemo": "nemo",
}
Window = namedtuple("Window", ["wid", "wm_class", "title"])
def cmd_output(s):
# returns the output of the given cmd in lines
return subprocess.check_output(s.split()).decode("utf-8").splitlines()
def get_app_windows(app=None):
if app:
app = app.lower()
for line in cmd_output("wmctrl -lx"):
[wid, _, wm_class, _, title] = re.split(r"\s+", line, 4)
# not interested in desktop
if title == "Desktop":
continue
# perform further filtering by app if necessary
if app and app not in wm_class.lower():
continue
# wids are in hexadecimal
yield Window(int(wid, 16), wm_class, title)
def get_active_wid():
# wid for xdotool is in decimal
return int(cmd_output("xdotool getwindowfocus")[0])
if __name__ == "__main__":
# not enough args
if len(sys.argv) == 1:
exit()
app = sys.argv[1].lower()
# get the wid of the current window
active_wid = get_active_wid()
app_windows = list(get_app_windows(app))
if not app_windows:
# unknown app, exit
if app not in APP_PATHS:
exit()
# launch the program
os.system(APP_PATHS[app])
# is current window of the requested type
focused_idx = None
for i, w in enumerate(app_windows):
if w.wid == active_wid:
focused_idx = i
break
if focused_idx is None:
# focus on first window of requested type
target_idx = 0
else:
# only window open, noop
if len(app_windows) == 1:
exit()
# focus on next window of requested type (with wraparound)
target_idx = (i + 1) % len(app_windows)
# do the actual window switching
subprocess.Popen(["wmctrl", "-ia", str(app_windows[target_idx].wid)])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment