Je me demandais simplement, est-il possible de "grouper" les fenêtres? Je veux dire, existe-t-il un moyen de joindre les bords de deux ou plusieurs fenêtres de sorte que lorsque l'une est déplacée, l'autre se déplace avec elle, agissant comme une grande fenêtre? Ou au moins quelque chose de similaire où le déplacement d'une fenêtre déplace l'autre de la même manière? J'utilise Ubuntu GNOME 15.10 avec GNOME 3.18.
Bien qu'à première vue cela semble très bien faisable, en utilisant wmctrl
, comme toujours, la réalité est (beaucoup) plus compliquée que la théorie.
J'hésite à poster ceci comme une réponse, car ce n'est qu'une réponse expérimentale, conceptuelle, pas (encore) une solution prête à l'emploi à cause de quelques bugs. Je le poste néanmoins dans l'espoir d'obtenir des informations sur la résolution des problèmes dans la version actuelle. La question est suffisamment intéressante pour un développement ultérieur (OMI) pour voir si une solution fluide peut être créée.
Bien que j'aie écrit le script dans Python
, la langue n'est pas pertinente pour les problèmes que je rencontre; principalement lié aux particularités de l'utilisation de wmctrl
.
I pourrait utiliser xdotool
pour positionner les fenêtres, mais comme OP mentionne le déplacement d'un ensemble de fenêtres vers un autre espace de travail, wmctrl
présente certains avantages, en particulier en utilisant Gnome , où les espaces de travail sont organisés différemment de Unity.
déplacer des fenêtres en groupe
L'exemple de l'écran ci-dessus a été réalisé sur Unity. Il devrait cependant fonctionner de la même manière sur Gnome
(à part l'écart, voir plus loin à propos du script).
a
. Dans la distribution d'écran, j'ai ajouté la commande à un lanceur (Unity), sur Gnome
, cela pourrait être fait avec une touche de raccourci.r
après le déplacement de l'une des fenêtres groupées, le script déplace toutes les fenêtres du groupe de la même manière, en restaurant les fenêtres les unes par rapport aux autres:a
, le script ci-dessous ajoute la fenêtre actuellement active, sa position et sa taille (comme dans la ligne correspondante dans la sortie de wmctrl -lG
), dans un fichier, wgroup_data.txt
(dans ~
).r
, le script lit le fichier, recherche la fenêtre qui a changé de position, calcule le vecteur entre l'ancienne et la nouvelle position et déplace les autres fenêtres en conséquence.Jusqu'à présent aucun problème.
Cependant, si l'une des fenêtres ne correspond pas complètement à l'intérieur des bordures de l'espace de travail actuel, le script échoue. En fait, la commande wmctrl
échoue, car elle échoue également "en dehors" du script, exécuté comme une seule commande.
#!/usr/bin/env python3
import subprocess
import os
import sys
arg = sys.argv[1]
# vertical deviation for Unity (use 0 for Gnome)
deviation = 28
fdata = os.environ["HOME"]+"/wgroup_data.txt"
def get_wmctrl():
# try because of buggy wmctrl...
try:
return subprocess.check_output(["wmctrl", "-lG"]).decode("utf-8")
except subprocess.CalledProcessError:
pass
def remove_window(window):
data = open(fdata).readlines()
[data.remove(l) for l in data if l.startswith(window)]
open(fdata, "wt").write(("").join(data))
def addwindow():
relevant = get_wmctrl()
frontmost = hex(int((subprocess.check_output(["xdotool", "getactivewindow"]).decode("utf-8").strip())))
frontmost = frontmost[:2]+str((10-len(frontmost))*"0")+frontmost[2:]
open(fdata, "+a").write([l+("\n") for l in get_wmctrl().splitlines() if frontmost in l][0])
print(frontmost)
def rearrange():
wlist = get_wmctrl()
if wlist != None:
group = [(l.strip(), l.split()) for l in open(fdata).read().splitlines() if not l in ("", "\n")]
try:
changed = [w for w in group if (w[0] in wlist, w[1][0] in wlist) == (False, True)][0] #
# only proceed if one of the grouped windows moved (give priority to a light loop if not):
follow = []
for w in group:
if not w == changed:
test = (w[0] in wlist, w[1][0] in wlist)
if test == (True, True):
follow.append(w)
Elif test == (False, False):
# remove closed window from list
remove_window(w[1][0])
# only proceed if there are windows to move:
if follow:
# find match of the moved window (new coords)
wlines = wlist.splitlines()
match = [l.split() for l in wlines if changed[1][0] in l][0]
# calculate the move vector
x_move = int(match[2])-(int(changed[1][2])); y_move = int(match[3])-(int(changed[1][3]))
for w in follow:
# should be changed to try?
w[1][2] = str(int(w[1][2]) + x_move); w[1][3] = str(int(w[1][3]) + y_move - deviation)
subprocess.Popen([
"wmctrl", "-ir", w[1][0], "-e",
(",").join([w[1][1], w[1][2], w[1][3], w[1][4], w[1][5]])
])
# update grouplist
while True:
try:
newlines = sum([[l for l in get_wmctrl().splitlines() if w in l] for w in [match[0]]+[item[1][0] for item in follow]], [])
open(fdata, "wt").write(("\n").join(newlines))
break
except AttributeError:
pass
except IndexError:
print("nothing changed")
if arg == "a":
addwindow()
Elif arg == "r":
rearrange()
Le script nécessite à la fois wmctrl
et xdotool
Sudo apt-get install xdotool wmctrl
Copiez le script dans un fichier vide, enregistrez-le sous group_windows.py
Si vous êtes sur Gnome:
Dans la section d'en-tête du script, changez la ligne:
deviation = 28
dans
deviation = 0
Ajoutez deux commandes à différents raccourcis:
python3 /path/to/group_windows.py a
pour ajouter des fenêtres à un groupe, et
python3 /path/to/group_windows.py r
pour réorganiser les fenêtres, comme indiqué dans la distribution d'écran
Testez le script en ajoutant des fenêtres à un groupe, déplacez-les et restaurez leur position relative, comme indiqué dans la distribution d'écran.
Le problème pourrait être résolu, au niveau du code, en refusant simplement de déplacer les fenêtres au cas où l'une des fenêtres devrait sortir de l'espace de travail actuel. Dans ce cas, même la fenêtre qui vient d'être déplacée doit être remise à sa position initiale pour conserver les positions relatives.
Cela nécessiterait cependant un calcul approfondi (rien pour l'ordinateur, mais compliqué à coder), et il serait plus élégant de rendre possible un positionnement partiel en dehors de l'espace de travail actuel; ce n'est pas un problème lorsqu'une fenêtre est positionnée "sur ou sur le bord" manuellement.
Toute suggestion sur la résolution du problème est plus que bienvenue.