web-dev-qa-db-fra.com

Comment puis-je faire en sorte qu'une seconde fenêtre s'aligne sur le côté opposé de l'écran?

Je viens de Windows 10, bien que j’aie commencé (et accepté) le fonctionnement d’Ubuntu, c’est toujours une des choses que j’aime à propos de Windows 10, la fonctionnalité en question est la suivante: si je cale une fenêtre à la Tout à fait à droite de l’écran, il occupe la moitié droite de l’écran (ce qui est également similaire dans ubuntu), mais une autre application en arrière-plan prend la moitié gauche de l’écran et n’a pas besoin de le faire manuellement.

Screenshot

Dans cette image, si je décroche la fenêtre du navigateur vers la droite, la fenêtre Nautilus n’affectera pas l’action. Mais je veux qu’elle (fenêtre Nautilus) s’accroche à gauche.

Détails

  • Ubuntu 17.04
  • Saveur de gnome

Mettre à jour

résultat du script fillscreen.py

1st result

dans le premier essai fillscreen une notification est arrivée (je ne pouvais pas capturer cela) et elle a déplacé la 2e fenêtre (fenêtre à droite) dans une boîte, et la 1re fenêtre n'a pas été affectée à tout.

2nd result

au second essai, ce décalage était présent, mais cela a fonctionné (et cela a fonctionné principalement)

2
Sumeet Deshmukh

Note importante!

Le script ci-dessous fera exactement ce que vous décrivez sur les deux plus jeunes fenêtres , à savoir: les deux fenêtres qui ont été créées en dernier.

Le script, le comportement

  • Le script agit sur en faisant glisser l'une des deux "plus récentes" fenêtres vers l'une des deux zones de l'écran, comme indiqué dans l'image.

    enter image description here

    La zone est délibérément et non serrée dans le coin, afin de s’assurer qu’elle n’interfère pas avec la capture de fenêtre "normale".

  • Si la fenêtre est déplacée dans l'une des zones, le script attend 0,15 seconde pour voir si la souris est toujours dans la même position, pour s'assurer de ne pas agir si l'utilisateur était "en chemin" jusqu'au coin du coin. écran pour la capture de fenêtre normale.

  • Par la suite, la fenêtre glissée est accrochée dans la moitié de l’écran sur laquelle la zone est allumée, la deuxième fenêtre est accrochée au côté opposé de l’écran.

    1. faites glisser la fenêtre vers la zone

    enter image description here

    2. la fenêtre s’accroche, l’autre s’adapte au site opposé

    enter image description here

  • enfin, à titre de confirmation, une notification indique pendant trois secondes:

    enter image description here

    Voir le script en action

Le script et la configuration

La configuration implique deux éléments:

  • le scénario:

    #!/usr/bin/env python3
    import sys
    import os
    import subprocess
    import time
    from operator import itemgetter
    from itertools import groupby
    import math
    
    #--- set your preferences below: padding between windows, margin(s)
    cols = 2; rows = 1; padding = 20; left_margin = 0; top_margin = 30
    #---
    
    fpath = os.path.dirname(os.path.abspath(__file__))
    n_wins = cols*rows
    
    
    def get_spot(pos):
        # get the resolution
        scrdata = get("xrandr").split(); resindex = scrdata.index("connected")+2
        res = [int(n) for n in scrdata[resindex].split("+")[0].split("x")]
        # list the corners, could be more elegant no doubt
        corners = [[0, res[1]], [res[0], res[1]]]
        diff = [int(math.sqrt(sum([(c[i]-pos[i])**2 for i, n in enumerate(res)])))\
                for c in corners]
        return diff
    
    def get(cmd):
        try:
            return subprocess.check_output(cmd).decode("utf-8")
        except subprocess.CalledProcessError:
            pass
    
    def get_res():
        xr = get("xrandr").split(); pos = xr.index("current")
        return [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]
    
    def get_pos():
        return [int(s.split(":")[1]) for s in get(["xdotool", "getmouselocation"]).split()[:2]]
    
    
    def check_window(w_id):
        w_type = get(["xprop", "-id", w_id])
        if " _NET_WM_WINDOW_TYPE_NORMAL" in w_type:
            return True
        else:
            return False
    
    def confirm():
        val = False
        mouseloc = get_spot(get_pos())
        match = [mouseloc.index(n) for n in mouseloc if 50 < n < 400]
        if match:
            time.sleep(0.15)
            val = True if get_spot(get_pos()) == mouseloc else False
        return val, match
    
    def arrange_wins(active, side):
        # get resolution
        res = get_res()
        # define (calculate) the area to divide
        area_h = res[0] - left_margin; area_v = res[1] - top_margin
        # create a list of calculated coordinates
        x_coords = [int(left_margin+area_h/cols*n) for n in range(cols)]
        y_coords = [int(top_margin+area_v/rows*n) for n in range(rows)]
        coords = sum([[(cx, cy) for cx in x_coords] for cy in y_coords], [])
        # calculate the corresponding window size, given the padding, margins, columns and rows
        w_size = [str(int(area_h/cols - padding)), str(int(area_v/rows - padding))]
        # find windows of the application, identified by their pid
        active = hex(int(get(["xdotool", "getactivewindow"])))
        active = active[:2]+(10-len(active))*"0"+active[2:]
        wlist = [w.split()[0] for w in get(["wmctrl", "-l"]).splitlines()]
        w_list = [w for w in wlist if check_window(w) == True][-n_wins:]
        try:
            w_list = w_list[::-1] if w_list.index(active) != side else w_list
        except ValueError:
            pass
        else: 
            print(w_list)
            # remove possibly maximization, move the windows
            for n, w in enumerate(w_list):
                data = (",").join([str(item) for item in coords[n]])+","+(",").join(w_size)
                cmd1 = "wmctrl -ir "+w+" -b remove,maximized_horz"
                cmd2 = "wmctrl -ir "+w+" -b remove,maximized_vert"
                cmd3 = "wmctrl -ir "+w+" -e 0,"+data
                for cmd in [cmd1, cmd2, cmd3]:
                    subprocess.Popen(["/bin/bash", "-c", cmd])
    
    wins1 = []
    
    while True:
        time.sleep(0.5)
        windata = get(["wmctrl", "-lG"])
        if windata:
            wins2 = [[l[0], l[2]] for l in [
                ln.split() for ln in windata.splitlines()]
                       ]
            # combined window locations old/new, grouped to see if moved
            winlocs = sorted(wins1 + wins2, key = itemgetter(0))
            test = [[item, [item[1] for item in list(occ)]] \
                    for item, occ in groupby(winlocs, itemgetter(0))]
            for item in test:
                # old loc, new loc of window
                locs = item[1]
                # window moves?
                if locs.count(locs[0]) != len(locs):
                    args = confirm()
                    if args[0]:
                        arrange_wins(item[0], args[1][0])
                        subprocess.Popen([
                            "notify-send", "-i", os.path.join(
                                fpath, "left.png"), "Fill screen"
                            ])
                        time.sleep(3)
                        subprocess.Popen(["pkill", "notify-osd"])
            wins1 = wins2
    
  • une icône à afficher dans la notification

    enter image description here

Configuration

  1. Installez à la fois xdotoolet wmctrl
  2. Copiez le script dans un fichier vide, enregistrez-le sous le nom fillscreen.py dans un dossier dédié quelque part.
  3. Cliquez avec le bouton droit sur l'icône ci-dessus, enregistrez-la sous (exactement) left.png dans un seul et même dossier que le script .
  4. Maintenant ouvrez un terminal, lancez la commande:

    python3 /path/to/fillscreen.py
    

    Notez que cette fenêtre de terminal est l'une des deux fenêtres que le script va capturer. Dessinez le terminal dans l'une des zones à gauche ou à droite. Les deux fenêtres les plus récentes devraient se casser.

  5. Si tout fonctionne correctement, ajoutez le script aux applications de démarrage: Dash> Applications de démarrage> Ajouter. Ajoutez la commande:

    /bin/bash -c "sleep 10 && python3 /path/to/fillscreen.py"
    

Remarque

Etant donné que le script n'agit que sur le mouvement de la fenêtre et que toutes les actions ultérieures dépendent par conséquent de la situation, le script n'a que très peu de ressources. Bien plus bas que ce à quoi je m'attendais quand j'ai commencé à travailler dessus.

1
Jacob Vlijm