web-dev-qa-db-fra.com

Déplacer des fenêtres semi-maximisées sur plusieurs (2 ou plus) moniteurs

J'utilise fréquemment Ctrl+Super+Arrow -Clés pour déplacer les fenêtres. Cependant, avec la configuration de plusieurs moniteurs, les raccourcis ne déplacent que les fenêtres de l'écran actuel.

** Exemple de ma situation:

J'ai 3 moniteurs et une instance de Chrome ouverte dans mon moniteur central.

  1. Quand je frappe Ctrl+Super+Arrow (left)la fenêtre se sépare à la moitié gauche de mon moniteur central.
  2. Quand je répète, la fenêtre ne bouge pas.

Ce que j'aimerais voir à la place, c'est que dans [2.], la fenêtre se déplace vers la moitié droite du moniteur le plus à gauche, etc.

Comment puis-je obtenir ce comportement?

5
nivla12345

Déplacez vos fenêtres semi-maximisées sur plusieurs écrans ("aero-snap" de la même manière)

Le script ci-dessous fait exactement ce que vous décrivez. Il peut être utilisé sur n’importe quel nombre d’écrans. Le script est optimisé pour Unity, mais peut facilement être modifié pour s’adapter aux autres gestionnaires de fenêtres.

Cela s'est avéré être un peu plus compliqué que je ne le pensais, car le script doit prendre en compte le fait que l'utilisateur peut éventuellement configurer le lanceur pour qu'il n'apparaisse que sur l'écran le plus à gauche (ou non). Les positions ciblées (et les tailles de fenêtre ciblées) doivent être calculées en conséquence.


enter image description here

Remarques

  • Le script déplace les fenêtres à travers tous les écrans connectés, puis bascule dans les "moitiés" des écrans, de gauche à droite et inversement.
  • Le script lit les tailles des écrans et définit la taille de la fenêtre à la moitié de la taille de l'écran en conséquence.
  • Le script lit les paramètres sur le lanceur (si celui-ci apparaît uniquement sur le premier écran ou sur tous) et calcule les tailles de fenêtre ciblées en conséquence.
  • Le script ne prend pas en compte l'option de masquage automatique éventuellement définie pour le programme de lancement. La raison en est que la mise à jour de la taille de Windows une fois que le lanceur se cache ou s’affiche prendrait un script en arrière-plan et une toute autre histoire à coder.
  • Les fenêtres sont déplacées et redimensionnées par une combinaison de commandes xdotool et wmctrl -. Étant donné que ces commandes peuvent avoir un "comportement caractéristique" en combinaison avec Unity, il est possible que des modifications mineures puissent être utiles sur votre système. Je l'ai testé sur deux systèmes (assez différents) cependant, fonctionnant bien sur les deux.

Le scénario

#!/usr/bin/env python3
import subprocess
import sys

# --- set possibly wanted marge (on the right side of the window) below
marge = 0
# --- set set launcher width below (default = 65)
default_launcherwidth = 65
# ---

move = sys.argv[1]
get = lambda cmd: subprocess.check_output(
    ["/bin/bash", "-c", cmd]).decode("utf-8")

screendata = [l for l in get("xrandr").splitlines() if " connected" in l]
# get the primary screen's position
pr = [l.split() for l in screendata if "primary" in l][0]
i = pr.index("primary"); s = pr[i+1]
primary= [int(s.split("x")[0]), int(s.split("+")[-2])]
# general screen list
screendata = [
    [s for s in l.split() if s.count("+") == 2][0] for l in screendata
    ]
screendata = [
    [int(s.split("x")[0]),int(s.split("+")[-2])] for s in screendata
    ]
screendata.sort(key=lambda x: x[1]); primary = screendata.index(primary)

def launcher_size():
    launcherset = get(
        "dconf read /org/compiz/profiles/unity/plugins/unityshell/num-launchers"
        ).strip()
    l_size_0 = 65; l_size_1 = l_size_0 if launcherset == "0" else 0
    return [l_size_0, l_size_1]

def magnets(index):
    l_size = l_sizes[0] if index == primary else l_sizes[1]
    screen = screendata[index]
    screenwidth = screen[0]; shift = screen[1]
    parts = (screenwidth - l_size)/2; virtual_mid = screenwidth - parts + shift
    left_trigger = shift + l_size
    return [left_trigger, int(virtual_mid), int(parts)]

def find_screen(x_loc):
    scr_index = len([scr for scr in screendata if x_loc >= scr[1]])-1
    scr_index = scr_index if scr_index >= 0 else 0
    screen = screendata[scr_index]
    return [scr_index, screen]

def get_active():
    active = hex(int(get("xdotool getactivewindow").strip()))
    active = active[:2]+(10-len(active))*"0"+active[2:] 
    x_pos = int([l.split()[2] for l in get("wmctrl -lG").splitlines() \
                 if l.startswith(active)][0])
    return [active, x_pos]

def decide(x_loc, active):
    current_scr = find_screen(x_loc)
    triggers = magnets(current_scr[0])
    width = triggers[2]
    index = current_scr[0]
    if move == "left":
        if x_loc <= triggers[1]:
            if x_loc == triggers[0]:
                if index != 0:
                    alter = magnets(index-1) 
                    width = alter[-1]
                    target = alter[1]
                else:
                    target = triggers[0]
            else:
                target = triggers[0]
        Elif x_loc > triggers[1]:
            target = triggers[1]        
    Elif move == "right":
        if x_loc >= triggers[1]:
            if index != len(screendata)-1:
                alter = magnets(index+1)
                width = alter[-1]
                target = alter[0]
            else:
                target = triggers[1]
        Elif x_loc < triggers[1]:
            target = triggers[1]
    subprocess.call([
        "wmctrl", "-r", ":ACTIVE:","-b", "remove,maximized_vert,maximized_horz"
        ])
    subprocess.call(["wmctrl", "-ir", active, "-e", "0,"+str(target)+",400,"+\
                      str(int(width)-marge)+",200"])
    subprocess.call([
        "wmctrl", "-ir", active, "-b", "toggle,maximized_vert"
        ])

l_sizes = launcher_size()
w_data = get_active()
active = w_data[0]
x_loc = w_data[1]

decide(x_loc, active)

Comment utiliser

  • Le scrpt a besoin de wmctrl et de xdotool:

    Sudo apt-get instal xdotool wmctrl
    
  • Copiez le script dans un fichier vide, enregistrez-le sous le nom move_window.py

  • Tester le script depuis une fenêtre de terminal en exécutant (à plusieurs reprises) la commande suivante:

    python3 /path/to/move_window.py right
    

    qui devrait déplacer la fenêtre à travers vos écrans vers la droite, et:

    python3 /path/to/move_window.py left
    

    qui devrait déplacer la fenêtre à travers vos écrans vers la gauche.

  • Si tout fonctionne correctement, ajoutez les deux commandes aux touches de raccourci: sélectionnez: Paramètres système> "Clavier"> "Raccourcis"> "Raccourcis personnalisés". Cliquez sur le "+" et ajoutez les commandes à deux touches de raccourci de votre choix.

Notes IMPORTANTES

  1. Le lanceur width est réglé sur 65px (correspondant à la taille de l'icône 48px + 17px défaut). Si la largeur définie est différente, il convient de la définir correctement dans l'en-tête du script, comme indiqué dans la section:

    # --- set set launcher width below (default = 65)
    default_launcherwidth = 65
    # ---
    
  2. Dans la section de tête du script, il y a en outre une ligne:

    marge = 0
    

    qui définit la marge vide sur le côté droit de l’écran déplacé. Changez-le si vous aimez une autre valeur.

3
Jacob Vlijm