Permanently have one or more applications run on specific viewport(s)
For the sport of it: to keep one or more applications running on one or more specified viewports, you can use the script below. It runs in the background and works as you describe, but you can add multiple applications to keep running on different viewports.
Although the script looks a bit extensive, most of it only runs one time, to collect data about your viewport(s) span, viewport columns & rows, screen resolution and such. It is not part of the loop.
If you close the application window you specified for the viewport, it opens a new window of the application on the targeted viewport.
How to use:
First: install wmctrl
:
sudo apt-get install wmctrl
Then just copy the script into an empty file, set the application(s) you need to run (in one or more tuples in a list, see example in the head section of the script) and the targeted viewport(s) you need it to run on (and keep available). Save it as keep_running.py
and make it executable.
run it by the command:
/path/to/keep_running.py
optionally, you can add it to your startup applications.
The script:
#!/usr/bin/env python3
import subprocess
import time
list applications and targeted viewports
applications = [("gnome-terminal", 4), ("gedit", 3)]
def get_value(command):
return subprocess.check_output(
["/bin/bash", "-c", command]).decode('utf-8').strip()
def screendata():
getres = get_value("xrandr").split(); idf = getres.index("current")
screen_res = (int(getres[idf+1]), int(getres[idf+3].replace(",", "")))
wsp_info = get_value("wmctrl -d").strip()
scr_data = [item.split("x") for item in wsp_info.split(" ") if "x" in item][0]
VP_hor = int(scr_data[0])/int(screen_res[0])
VP_vert = int(scr_data[1])/int(screen_res[1])
ranges_hor = [iscreen_res[0] for i in range(int(VP_hor))]
ranges_vert = [iscreen_res[1] for i in range(int(VP_hor))]
w_positions = [(int(ranges_hor[i]), int(ranges_vert[i2]))
for i2 in range(len(ranges_vert)) for i in range(len(ranges_hor))]
return {"resolution": screen_res, "horizontal": ranges_hor,
"vertical": ranges_vert, "columns": int(VP_hor),
"window_positions": w_positions}
def get_viewport(abs_h, abs_v): #calculates viewport from absolute coords
hor = screen_data["horizontal"]
vert = screen_data["vertical"]
hor_position = len([n for n in hor if int(abs_h) >= n])
vert_position = len([n for n in vert if int(abs_v) >= n])
return int(hor_position+(vert_position-1)*screen_data["columns"])
def window_position(rel_h, rel_v): #calculates viewport from coords, relative to current viewport
wsp_info = get_value("wmctrl -d").strip().split()
vp_coords = eval(wsp_info[wsp_info.index("VP:"):][1])
abs_h = rel_h+vp_coords[0]
abs_v = rel_v+vp_coords[1]
return get_viewport(abs_h, abs_v)
def pid_appinfo(pid):
get_app = "ps -p "+pid+" -o comm="
return get_value(get_app)
def check_windows():
try:
wlist = get_value("wmctrl -l -p -G")
except Exception:
# retry; when switching viewports while the command runs, it raises an error
wlist = get_value("wmctrl -l -p -G")
wdata = [l.split()[2:5] for l in wlist.split("\n")]
app_windows = []
for item in wdata:
if item[0] != "0":
try:
if pid_appinfo(item[0]) == application
and window_position(int(item[1]), int(item[2])) == target_viewport:
app_windows.append(item)
except Exception:
pass
if len(app_windows) == 0:
targeted_viewport = str(screen_data["window_positions"][target_viewport-1])
.replace("(","").replace(")","")
subprocess.call(["wmctrl", "-o", targeted_viewport])
subprocess.Popen([application])
screen_data = screendata()
while True:
for item in applications:
application = item[0]; target_viewport = item[1]
check_windows()
time.sleep(2)
This script is also on gist.gisthub