J'ai donc 8 bureaux virtuels dans Unity (avec Compiz) car j'ai plusieurs projets sur lesquels je travaille simultanément.
Le problème, c’est que chaque fois que je dois redémarrer ou fermer accidentellement Chrome (qui constitue une grande partie des fenêtres dont j’ai besoin pour travailler), je dois manuellement ouvrir à nouveau ces fenêtres, puis les configurer (ouvrir fichiers, allez aux bonnes URL, etc.).
Comment feriez-vous pour écrire un script qui fera tout cela pour moi? C'est-à-dire que: 1) ouvrez les fenêtres 2) placez-les dans les bonnes coordonnées sur les écrans virtuels appropriés
(1) est évident, pour Google Chrome vous exécutez simplement "google-chrome". Mais alors comment le mettez-vous au bon endroit? (2)
Ou existe-t-il un script/logiciel existant qui le ferait pour moi?
Cela peut être très bien fait, mais vous avez besoin d’un peu de compréhension sur Unity/viewports. J'espère que l'histoire ci-dessous est compréhensible, sinon laissez un commentaire.
Le script ci-dessous peut être utilisé pour ouvrir une fenêtre de n'importe quelle application sur n'importe laquelle de vos fenêtres, sur n'importe quelle position, si vous l'exécutez avec les bons arguments. Le script est une version modifiée de celui-ci , mais il est maintenant prêt à placer des fenêtres sur le bureau virtuel .
Dans Unity, contrairement aux autres gestionnaires de fenêtres, vous n’avez en réalité qu’un seul espace de travail couvrant, divisé en fenêtres. Dans votre cas, votre espace de travail est divisé en huit fenêtres.
La position de la fenêtre, en tant que sortie de la commande:
wmctrl -lG
(you need to have wmctrl installed to run the command)
est décrit comme la position, relative par rapport au coin supérieur gauche de la fenêtre actuelle :
Donc, si vous êtes dans la fenêtre 1
:
une fenêtre sur la fenêtre 2 pourrait être positionnée par ex. 1700 (x-sage) x 500 (y-sage)
(mon écran est 1680x1050)
Cependant, si vous êtes dans la fenêtre 6:
la même fenêtre serait positionnée sur 20 (x), -550 (y)
Utiliser ces coordonnées correctement est important pour exécuter le script avec les bons arguments, comme décrit ci-dessous:
Le script ci-dessous peut être utilisé pour placer une nouvelle fenêtre d’une application sur votre espace de travail virtuel (étendu).
Assurez-vous que wmctrl
est installé:
Sudo apt-get install wmctrl
Copiez le script ci-dessous dans un fichier vide, enregistrez-le sous le nom setwindow
(sans extension) dans ~/bin
. Créez le répertoire s'il n'existe pas encore. Rend le script exécutable .
~/bin
, exécutez la commande source ~/.profile
ou déconnectez-vous/ouvrez pour rendre le répertoire disponible dans $PATH
.Test lance la commande:
setwindow <application> <x_position> <y_position> <horizontal_size> <vertical_size>
par exemple.
setwindow gedit 100 100 200 200
Une fenêtre gedit devrait apparaître dans la fenêtre courante.
Notes:
gedit
sur mon système est par exemple. env. 470 px.<x_position>
pour placer les fenêtres à gauche de la ou des fenêtres actuelles.<y_position>
pour placer les fenêtres au-dessus de la ou des fenêtres actuelles.Pour ouvrir simultanément de nouvelles fenêtres sur différentes fenêtres, vous pouvez simplement chaîner des commandes. En regardant la configuration de la fenêtre dans l'exemple "Longue histoire", si je suis dans la fenêtre 1, je peux ouvrir les fenêtres gedit dans les fenêtres 1, 2, 3 et 4 avec la commande:
setwindow gedit 100 100 200 200&&setwindow gedit 1780 100 200 200&&setwindow gedit 3460 100 200 200&&setwindow gedit 5140 100 200 200
#!/usr/bin/env python3
import subprocess
import time
import sys
app = sys.argv[1]
get = lambda x: subprocess.check_output(["/bin/bash", "-c", x]).decode("utf-8")
ws1 = get("wmctrl -lp"); t = 0
subprocess.Popen(["/bin/bash", "-c", app])
# fix exception for Chrome (command = google-chrome-stable, but processname = chrome)
app = "chrome" if "chrome" in app else app
while t < 30:
ws2 = [w.split()[0:3] for w in get("wmctrl -lp").splitlines() if not w in ws1]
procs = [[(p, w[0]) for p in get("ps -e ww").splitlines() \
if app in p and w[2] in p] for w in ws2]
if len(procs) > 0:
w_id = procs[0][0][1]
cmd1 = "wmctrl -ir "+w_id+" -b remove,maximized_horz"
cmd2 = "wmctrl -ir "+w_id+" -b remove,maximized_vert"
cmd3 = "wmctrl -ir "+procs[0][0][1]+" -e 0,"+sys.argv[2]+","+sys.argv[3]+","+sys.argv[4]+","+sys.argv[5]
for cmd in [cmd1, cmd2, cmd3]:
subprocess.call(["/bin/bash", "-c", cmd])
break
time.sleep(0.5)
t = t+1
Si vous préférez simplement entrer les coordonnées et la taille, comme si vous ouvriez une fenêtre sur la fenêtre d'affichage actuelle et donniez la fenêtre ciblée sous forme d'argument (sans rien calculer), utilisez la version ci-dessous ...
Si vous le configurez comme la première version du script, vous pouvez l'exécuter avec la commande suivante:
setwindow <application> <x_position> <y_position> <horizontal_size> <vertical_size> <targeted_viewport>
Exemple: pour ouvrir une fenêtre Google-Chrome
positionnée sur 20, 20
, taille 300x300
, dans la fenêtre 5
:
setwindow google-chrome 20 20 300 300 5
La configuration est à peu près la même que celle de la première version du script.
Notez également que ce script ne fonctionne correctement que si la fenêtre définie (position/taille) s’adapte parfaitement à la fenêtre de visualisation ciblée.
#!/usr/bin/env python3
import subprocess
import time
import sys
app = sys.argv[1]
target_vp = int(sys.argv[6])
def get_res():
# get resolution
xr = subprocess.check_output(["xrandr"]).decode("utf-8").split()
pos = xr.index("current")
return [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]
res = get_res()
def current(set_vp):
# get the current viewport
vp_data = subprocess.check_output(
["wmctrl", "-d"]
).decode("utf-8").split()
dt = [int(n) for n in vp_data[3].split("x")]
cols = int(dt[0]/res[0])
rows = int(dt[1]/res[1])
curr_vpdata = [int(n) for n in vp_data[5].split(",")]
curr_col = int(curr_vpdata[0]/res[0])
curr_row = int(curr_vpdata[1]/res[1])
curr_vp = curr_col+curr_row*cols+1
# calculate the vector to the Origin from the current viewport (in resolution units)
vec_curr = vector(curr_vp, cols)
# calculate the vector to the Origin from the targeted viewport
vec_set = vector(set_vp, cols)
# calculate the vector between current and targeted viewport
vec_relative = [vec_set[0] - vec_curr[0],
vec_set[1] - vec_curr[1]]
# calculate needed correction (absolute)
relative = [vec_relative[0]*res[0],
vec_relative[1]*res[1]]
return relative
def vector(vp, cols):
rem = vp%cols
vec_x = rem-1 if rem != 0 else cols-1
vec_y = int((vp-1)/cols)
return [vec_x, vec_y]
res = get_res() # nieuw
get = lambda x: subprocess.check_output(["/bin/bash", "-c", x]).decode("utf-8")
ws1 = get("wmctrl -lp"); t = 0
# check for additional arguments to run the application
try:
subprocess.Popen(["/bin/bash", "-c", app+" "+sys.argv[7]])
except IndexError:
subprocess.Popen(["/bin/bash", "-c", app])
# fix exception for Chrome (command = google-chrome-stable, but processname = chrome)
app = "chrome" if "chrome" in app else app
while t < 30:
ws2 = [w.split()[0:3] for w in get("wmctrl -lp").splitlines() if not w in ws1]
procs = [[(p, w[0]) for p in get("ps -e ww").splitlines() \
if app in p and w[2] in p] for w in ws2]
if len(procs) > 0:
w_id = procs[0][0][1]
cmd1 = "wmctrl -ir "+w_id+" -b remove,maximized_horz"
cmd2 = "wmctrl -ir "+w_id+" -b remove,maximized_vert"
# calculate the correction, related to the current workspace, marge for launcher and panel
pos_x = int(sys.argv[2]); pos_y = int(sys.argv[3]); x_marge = 65; y_marge = 35
pos_x = pos_x if pos_x > x_marge else x_marge; pos_y = pos_y if pos_y > y_marge else y_marge
x_relative = pos_x+current(target_vp)[0]
y_relative = pos_y+current(target_vp)[1]
# correct possible inaccurately set width / height
x_size = res[0]; y_size = res[1]
set_width = int(sys.argv[4]); set_height = int(sys.argv[5])
width = set_width if set_width+x_marge+pos_x < x_size else x_size - pos_x - x_marge
height = set_height if set_height+y_marge+pos_y < y_size else y_size - pos_y - y_marge
cmd3 = "wmctrl -ir "+w_id+" -e 0,"+str(x_relative)+","+str(y_relative)+","+str(width)+","+str(height)
for cmd in [cmd1, cmd2, cmd3]:
subprocess.call(["/bin/bash", "-c", cmd])
break
time.sleep(0.5)
t = t+1
Pour terminer le travail, répondez complètement à votre question:
Si vous exécutez le script comme par exemple:
setwindow google-chrome 20 20 300 300 5
il ouvrira une fenêtre par défaut sur le ou les bureaux ciblés.
Cependant, avec la dernière version du script, vous pouvez ajouter un additionnel argument pour ouvrir la fenêtre de l'application, par exemple un url
:
setwindow <application> <x_position> <y_position> <horizontal_size> <vertical_size> <targeted_viewport> <(optional)_argument>
par exemple.:
setwindow google-chrome 0 0 600 600 3 "--new-window http://askubuntu.com"
Si l'argument (extra) contient des espaces, utilisez des guillemets. L'exemple ci-dessus ouvrira une fenêtre google-chrome
sur la fenêtre d'affichage 3, ouvrant la url
http://askubuntu.com
.
Vous pouvez chaîner des commandes pour ouvrir plusieurs fenêtres/urls sur différents espaces de travail en une seule, par exemple:
setwindow google-chrome 0 0 600 600 8 "--new-window http://askubuntu.com"&&setwindow google-chrome 0 0 600 600 7 "--new-window www.google.com"
Ceci s’étend sur la réponse de @ @ @ @ Jacob Vlijim ci-dessus avec un script légèrement modifié setwindow
:
#!/usr/bin/env python
import time
import argparse
import subprocess
DEFAULT_WIDTH = '1920'
DEFAULT_HEIGHT = '1080'
def get_window_list():
window_list = subprocess.check_output(['/bin/bash', '-c', 'wmctrl -l'])
parsed_list = []
for line in window_list.splitlines():
window_info = line.split()
if window_info[1] != '-1':
parsed_list.append(window_info[0])
return parsed_list
def main(params):
old_list = get_window_list()
subprocess.Popen(['/bin/bash', '-c', params.command])
def get_diff(old):
new_list = get_window_list()
return list(set(new_list) - set(old))
diff = get_diff(old_list)
x = 0
while not diff:
if x == 10:
print 'window not found'
return
x += 1
diff = get_diff(old_list)
time.sleep(1)
if len(diff) > 1:
raise Exception(diff)
window_id = diff[0]
command_list = []
command_list.append('wmctrl -ir %s -t %s' % (window_id, params.desktop))
command_list.append('wmctrl -ir %s -b remove,maximized_horz,maximized_vert'
% window_id)
command_list.append('wmctrl -ir %s -e 0,%s,%s,%s,%s' %
(window_id, params.x_pos, params.y_pos, params.width, params.height))
for command in command_list:
subprocess.call(['/bin/bash', '-c', command])
if __== '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('command', type=str)
parser.add_argument('-d', '--desktop', default='0', type=str)
parser.add_argument('-x', '--x-pos', default='0', type=str)
parser.add_argument('-y', '--y-pos', default='0', type=str)
parser.add_argument('-w', '--width', default=DEFAULT_WIDTH, type=str)
parser.add_argument('-t', '--height', default=DEFAULT_HEIGHT, type=str)
args = parser.parse_args()
main(args)
Description des modifications:
python3
à python
(juste une préférence personnelle)sys.argv
à argparse
pour une meilleure interface en ligne de commandewhile
boucle de 0,5 seconde à 1 seconde de sommeil completxrandr
confianceNOTE: Ceci est une version légèrement améliorée que j'ai écrite pour un usage personnel sur Debian Jessie LXDE. Vos résultats peuvent varier.
Pour ceux que ça intéresse, j'ai implémenté Desktopen: github.com/snitko/desktopen
Il vous permet d'écrire un script pour ouvrir des fenêtres sur différentes fenêtres et de manière très conviviale.