Je lance un script Matlab
dans le workspace 1
. Cela génère plusieurs parcelles. En attendant, je passe à workspace 2
et y travaille. Mon problème est que les parcelles apparaissent dans workspace 2
. Est-il possible de verrouiller un logiciel dans un espace de travail? Ainsi, alors que Matlab
génère les tracés dans workspace 1
, je peux travailler dans workspace 2
sans perturber les tracés qui s'affichent?
Ci-dessous une version réécrite du script de la première réponse (ci-dessous). Les différences:
WM_CLASS
et l'espace de travail ciblé sont désormais des arguments permettant d'exécuter le script. N'utilisez que la première ou la deuxième partie (identifiant) du WM_CLASS
(voir plus bas: comment utiliser)Lorsque le script démarre, il affiche une notification (exemple gedit
):
#!/usr/bin/env python3
import subprocess
import sys
import time
import math
app_class = sys.argv[1]
ws_lock = [int(n)-1 for n in sys.argv[2].split(",")]
def check_wlist():
# get the current list of windows
try:
raw_list = [
l.split() for l in subprocess.check_output(
["wmctrl", "-lG"]
).decode("utf-8").splitlines()
]
ids = [l[0] for l in raw_list]
return (raw_list, ids)
except subprocess.CalledProcessError:
pass
def get_wssize():
# get workspace size
resdata = subprocess.check_output(["xrandr"]).decode("utf-8").split()
i = resdata.index("current")
return [int(n) for n in [resdata[i+1], resdata[i+3].replace(",", "")]]
def get_current(ws_size):
# vector of the current workspace to Origin of the spanning desktop
dt_data = subprocess.check_output(
["wmctrl", "-d"]
).decode("utf-8").split()
curr = [int(n) for n in dt_data[5].split(",")]
return (int(curr[0]/ws_size[0]), int(curr[1]/ws_size[1]))
def get_relativewinpos(ws_size, w_data):
# vector to the application window, relative to the current workspace
xpos = int(w_data[2]); ypos = int(w_data[3])
xw = ws_size[0]; yw = ws_size[1]
return (math.ceil((xpos-xw)/xw), math.ceil((ypos-yw)/yw))
def get_abswindowpos(ws_size, w_data):
# vector from the Origin to the current window's workspace (flipped y-axis)
curr_pos = get_current(ws_size)
w_pos = get_relativewinpos(ws_size, w_data)
return (curr_pos[0]+w_pos[0], curr_pos[1]+w_pos[1])
def wm_class(w_id):
# get the WM_CLASS of new windows
return subprocess.check_output(
["xprop", "-id", w_id.strip(), "WM_CLASS"]
).decode("utf-8").split("=")[-1].strip()
ws_size = get_wssize()
wlist1 = []
subprocess.Popen(["notify-send", 'workspace lock is running for '+app_class])
while True:
# check focussed window ('except' for errors during "wild" workspace change)
try:
focus = subprocess.check_output(
["xdotool", "getwindowfocus"]
).decode("utf-8")
except subprocess.CalledProcessError:
pass
time.sleep(1)
wdata = check_wlist()
if wdata != None:
# compare existing window- ids, checking for new ones
wlist2 = wdata[1]
if wlist2 != wlist1:
# if so, check the new window's class
newlist = [[w, wm_class(w)] for w in wlist2 if not w in wlist1]
valids = sum([[l for l in wdata[0] if l[0] == w[0]] \
for w in newlist if app_class in w[1]], [])
# for matching windows, check if they need to be moved (check workspace)
for w in valids:
abspos = list(get_abswindowpos(ws_size, w))
if not abspos == ws_lock:
current = get_current(ws_size)
move = (
(ws_lock[0]-current[0])*ws_size[0],
(ws_lock[1]-current[1])*ws_size[1]-56
)
new_w = "wmctrl -ir "+w[0]+" -e "+(",").join(
["0", str(int(w[2])+move[0]),
str(int(w[2])+move[1]), w[4], w[5]]
)
subprocess.call(["/bin/bash", "-c", new_w])
# re- focus on the window that was focussed
if not app_class in wm_class(focus):
subprocess.Popen(["wmctrl", "-ia", focus])
wlist1 = wlist2
Le script nécessite à la fois wmctrl
et xdotool
:
Sudo apt-get install wmctrl xdotool
Copiez le script ci-dessus dans un fichier vide, enregistrez-le sous le nom lock_towspace.py
Dans votre application spécifique, trouvez le WM_CLASS
: ouvrez votre application, exécutez-le dans un terminal:
xprop WM_CLASS and click on the window of the application
La sortie ressemblera à (dans votre cas):
WM_CLASS: WM_CLASS(STRING) = "Sun-awt-X11-XFramePeer", "MATLAB R2015a - academic use"
Utilisez la première ou la deuxième partie de la commande pour exécuter le script.
La commande pour exécuter le script est alors:
python3 /path/to/lock_towspace.py "Sun-awt-X11-XFramePeer" 2,2
Dans la commande, la dernière section; 2,2
est l'espace de travail sur lequel vous souhaitez verrouiller l'application (sans espaces: (!) , colonne ), en "humain" format; la première colonne/ligne est 1,1
Le script ci-dessous verrouille une application spécifique sur son espace de travail initial. Si le script est démarré, il détermine sur quel espace de travail réside l'application. Toutes les fenêtres supplémentaires générées par l'application seront déplacées vers le même espace de travail en une fraction de seconde.
Le problème de focalisation est résolu en recentrant automatiquement sur la fenêtre qui était focalisée avant la production de la fenêtre supplémentaire.
#!/usr/bin/env python3
import subprocess
import time
import math
app_class = '"gedit", "Gedit"'
def get_wssize():
# get workspace size
resdata = subprocess.check_output(["xrandr"]).decode("utf-8").split()
i = resdata.index("current")
return [int(n) for n in [resdata[i+1], resdata[i+3].replace(",", "")]]
def get_current(ws_size):
# get vector of the current workspace to the Origin of the spanning desktop (flipped y-axis)
dt_data = subprocess.check_output(["wmctrl", "-d"]).decode("utf-8").split(); curr = [int(n) for n in dt_data[5].split(",")]
return (int(curr[0]/ws_size[0]), int(curr[1]/ws_size[1]))
def get_relativewinpos(ws_size, w_data):
# vector to the application window, relative to the current workspace
xw = ws_size[0]; yw = ws_size[1]
return (math.ceil((w_data[1]-xw)/xw), math.ceil((w_data[2]-yw)/yw))
def get_abswindowpos(ws_size, w_data):
curr_pos = get_current(ws_size)
w_pos = get_relativewinpos(ws_size, w_data)
return (curr_pos[0]+w_pos[0], curr_pos[1]+w_pos[1])
def wm_class(w_id):
return subprocess.check_output(["xprop", "-id", w_id, "WM_CLASS"]).decode("utf-8").split("=")[-1].strip()
def filter_windows(app_class):
# find windows (id, x_pos, y_pos) of app_class
try:
raw_list = [l.split() for l in subprocess.check_output(["wmctrl", "-lG"]).decode("utf-8").splitlines()]
return [(l[0], int(l[2]), int(l[3]), l[4], l[5]) for l in raw_list if wm_class(l[0]) == app_class]
except subprocess.CalledProcessError:
pass
ws_size = get_wssize()
init_window = get_abswindowpos(ws_size, filter_windows(app_class)[0])
valid_windows1 = filter_windows(app_class)
while True:
focus = subprocess.check_output(["xdotool", "getwindowfocus"]).decode("utf-8")
time.sleep(1)
valid_windows2 = filter_windows(app_class)
if all([valid_windows2 != None, valid_windows2 != valid_windows1]):
for t in [t for t in valid_windows2 if not t[0] in [w[0] for w in valid_windows1]]:
absolute = get_abswindowpos(ws_size, t)
if not absolute == init_window:
current = get_current(ws_size)
move = ((init_window[0]-current[0])*ws_size[0], (init_window[1]-current[1])*ws_size[1]-56)
new_w = "wmctrl -ir "+t[0]+" -e "+(",").join(["0", str(t[1]+move[0]), str(t[2]+move[1]), t[3], t[4]])
subprocess.call(["/bin/bash", "-c", new_w])
focus = str(hex(int(focus)))
z = 10-len(focus); focus = focus[:2]+z*"0"+focus[2:]
if not wm_class(focus) == app_class:
subprocess.Popen(["wmctrl", "-ia", focus])
valid_windows1 = valid_windows2
Le script nécessite à la fois wmctrl
et xdotool
Sudo apt-get install wmctrl xdotool
Copiez le script dans un fichier vide, enregistrez-le sous le nom keep_workspace.py
déterminez le `WM_CLASS 'de votre application en l'ouvrant, puis ouvrez un terminal et exécutez la commande suivante:
xprop WM_CLASS
Cliquez ensuite sur la fenêtre de votre application. Copiez la sortie sous la forme "Sun-awt-X11-XFramePeer", "MATLAB R2015a - academic use"
dans votre cas et placez-la entre guillemets simples dans la section d'en-tête du script, comme indiqué.
Exécutez le script avec la commande:
python3 /path/to/keep_workspace.py
Si cela fonctionne comme vous le souhaitez, je vais ajouter une fonction de basculement. Bien que cela fonctionne déjà depuis quelques heures sur mon système, il pourrait toutefois nécessiter quelques ajustements d’abord.
Bien que vous ne deviez pas le remarquer, le script ajoute une charge de processeur au système. Sur mon système de personnes âgées, j'ai constaté une augmentation de 3 à 10%. Si vous aimez la façon dont cela fonctionne, je vais probablement l'améliorer davantage pour réduire la charge.
Le script, dans son état actuel, suppose que les fenêtres secondaires appartiennent à la même classe que la fenêtre principale, comme vous l'avez indiqué dans un commentaire. Avec un changement (très) simple, les fenêtres secondaires peuvent appartenir à une autre classe.
Bien que probablement peu intéressant pour un lecteur moyen, le script fonctionne en calculant en vecteurs. Au démarrage, le script calcule:
wmctrl -d
wmctrl -lG
À partir de ce moment, le script recherche les nouvelles fenêtres de la même application, avec la sortie de xprop WM_CLASS
, recherche leur position de la même manière que ci-dessus et les déplace vers l'espace de travail "d'origine".
Étant donné que la fenêtre nouvellement créée "a volé" le focus de la dernière fenêtre utilisée par l'utilisateur, le focus est par la suite défini sur la fenêtre précédemment active.