web-dev-qa-db-fra.com

Comment puis-je regrouper des fenêtres pour qu'elles ne soient plus qu'une?

J'ai deux fenêtres, A et B. Est-il possible de lier deux fenêtres ensemble, de sorte que le passage à A soulève également B, ou que le passage à B soulève également A?

Je comprends que l'utilisation de plusieurs espaces de travail est une option alternative, mais je me demandais si cela était également possible?

9
Simon Tong

Introduction

Le script suivant permet de sélectionner deux fenêtres. Lorsque les deux fenêtres sont ouvertes, il soulève les deux fenêtres lorsque l'utilisateur fait la mise au point. Par exemple, si l’on lie les veuves A et B, le fait de passer à A ou B fera augmenter les deux au-dessus des autres veuves.

Pour arrêter le script, vous pouvez utiliser killall link_windows.py dans un terminal, ou fermer et rouvrir une des fenêtres. Vous pouvez également annuler l'exécution en appuyant sur le bouton de fermeture X dans l’une des boîtes de dialogue contextuelles de sélection de fenêtre.

Réglages potentiels:

  • plusieurs instances du script peuvent être utilisées pour regrouper des paires de deux fenêtres. Par exemple, si nous avons les fenêtres A, B, C et D, nous pouvons relier A et B ensemble et relier C et D ensemble.
  • plusieurs fenêtres peuvent être regroupées sous une seule fenêtre. Par exemple, si je lie la fenêtre B à A, C à A et D à A, cela signifie que si je bascule toujours vers A, je peux lever toutes les 4 fenêtres en même temps.

Usage

Exécutez le script en tant que:

python link_windows.py

Le script est compatible avec Python 3, de sorte qu'il peut également s'exécuter en tant que

python3 link_windows.py

Il existe deux options de ligne de commande:

  • --quiet ou -q, permet de désactiver les fenêtres de l'interface graphique. Avec cette option, vous pouvez simplement cliquer avec la souris sur deux fenêtres et le script commencera à les lier.
  • --help ou -h imprime les informations d'utilisation et de description.

L'option -h fournit les informations suivantes:

$ python3 link_windows.py  -h                                                                                            
usage: link_windows.py [-h] [--quiet]

Linker for two X11 windows.Allows raising two user selected windows together

optional arguments:
  -h, --help  show this help message and exit
  -q, --quiet  Blocks GUI dialogs.

Des informations techniques supplémentaires peuvent être consultées via pydoc ./link_windows.py, où ./ signifie que vous devez vous trouver dans le même répertoire que le script.

Processus d'utilisation simple pour deux fenêtres:

  1. Une fenêtre contextuelle vous demandant de sélectionner une fenêtre n ° 1 apparaît. Appuyez sur OK ou frapper Enter. Le pointeur de la souris se transformera en croix. Cliquez sur l'une des fenêtres que vous souhaitez lier.

  2. Une seconde fenêtre apparaît vous demandant de sélectionner la fenêtre 2, appuyez sur OK ou frapper Enter. Encore une fois, le pointeur de la souris se transformera en croix.Cliquez sur l’autre fenêtre à lier. Après cette exécution va commencer.

  3. Chaque fois que vous focalisez l'une ou l'autre fenêtre, le script soulève l'autre fenêtre, mais rétablit le focus sur celle sélectionnée à l'origine (remarque - avec un délai d'un quart de seconde pour des performances optimales), ce qui donne l'impression que les fenêtres sont liées.

Si vous sélectionnez la même fenêtre à deux reprises, le script se ferme. Si, à tout moment, vous cliquez sur le bouton de fermeture de la boîte de dialogue contextuelle, le script se ferme.

Source du script

Egalement disponible en tant que GitHub Gist

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Author: Sergiy Kolodyazhnyy
Date:  August 2nd, 2016
Written for: https://askubuntu.com/q/805515/295286
Tested on Ubuntu 16.04 LTS
"""
import gi
gi.require_version('Gdk', '3.0')
gi.require_version('Gtk', '3.0')
from gi.repository import Gdk, Gtk
import time
import subprocess
import sys
import argparse


def run_cmd(cmdlist):
    """ Reusable function for running Shell commands"""
    try:
        stdout = subprocess.check_output(cmdlist)
    except subprocess.CalledProcessError:
        sys.exit(1)
    else:
        if stdout:
            return stdout


def focus_windows_in_order(first, second, scr):
    """Raise two user-defined windows above others.
       Takes two XID integers and screen object.
       Window with first XID will have the focus"""

    first_obj = None
    second_obj = None

    for window in scr.get_window_stack():
        if window.get_xid() == first:
            first_obj = window
        if window.get_xid() == second:
            second_obj = window

    # When this  function is called first_obj is alread
    # raised. Therefore we must raise second one, and switch
    # back to first
    second_obj.focus(int(time.time()))
    second_obj.get_update_area()
    # time.sleep(0.25)
    first_obj.focus(int(time.time()))
    first_obj.get_update_area()


def get_user_window():
    """Select two windows via mouse. Returns integer value of window's id"""
    window_id = None
    while not window_id:
        for line in run_cmd(['xwininfo', '-int']).decode().split('\n'):
            if 'Window id:' in line:
                window_id = line.split()[3]
    return int(window_id)


def main():
    """ Main function. This is where polling for window stack is done"""

    # Parse command line arguments
    arg_parser = argparse.ArgumentParser(
        description="""Linker for two X11 windows.Allows raising """ +
                    """two user selected windows together""")
    arg_parser.add_argument(
                '-q','--quiet', action='store_true',
                help='Blocks GUI dialogs.',
                required=False)
    args = arg_parser.parse_args()

    # Obtain list of two user windows
    user_windows = [None, None]
    if not args.quiet:
        run_cmd(['zenity', '--info', '--text="select first window"'])
    user_windows[0] = get_user_window()
    if not args.quiet:
        run_cmd(['zenity', '--info', '--text="select second window"'])
    user_windows[1] = get_user_window()

    if user_windows[0] == user_windows[1]:
        run_cmd(
            ['zenity', '--error', '--text="Same window selected. Exiting"'])
        sys.exit(1)

    screen = Gdk.Screen.get_default()
    flag = False

    # begin watching for changes in window stack
    while True:

        window_stack = [window.get_xid()
                        for window in screen.get_window_stack()]

        if user_windows[0] in window_stack and user_windows[1] in window_stack:

            active_xid = screen.get_active_window().get_xid()
            if active_xid not in user_windows:
                flag = True

            if flag and active_xid == user_windows[0]:
                focus_windows_in_order(
                    user_windows[0], user_windows[1], screen)
                flag = False

            Elif flag and active_xid == user_windows[1]:
                focus_windows_in_order(
                    user_windows[1], user_windows[0], screen)
                flag = False

        else:
            break

        time.sleep(0.15)


if __== "__main__":
    main()

Remarques:

9

Augmenter un nombre arbitraire de fenêtres comme une

La solution ci-dessous vous permettra de choisir toute combinaison de deux, trois fenêtres ou plus à combiner et à afficher en une avec un raccourci clavier.

Le script fonctionne avec trois arguments:

add

ajouter la fenêtre active au groupe

raise

élever le groupe

clear

pour effacer le groupe, prêt à définir un nouveau groupe

Le scénario

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

wlist = os.path.join(os.environ["HOME"], ".windowlist")

arg = sys.argv[1]

if arg == "add":
    active = subprocess.check_output([
        "xdotool", "getactivewindow"
        ]).decode("utf-8").strip()
    try:
        currlist = open(wlist).read()
    except FileNotFoundError:
        currlist = []
    if not active in currlist:
        open(wlist, "a").write(active + "\n")
Elif arg == "raise":
    group = [w.strip() for w in open(wlist).readlines()]
    [subprocess.call(["wmctrl", "-ia", w]) for w in group]
Elif arg == "clear":
    os.remove(wlist)

Comment utiliser

  1. Le script a besoin de wmctrl et xdotool:

    Sudo apt-get install wmctrl xdotool
    
  2. Copiez le script ci-dessus dans un fichier vide, enregistrez-le sous le nom groupwindows.py
  3. Testez le script: ouvrez deux fenêtres de terminal, lancez la commande:

    python3 /absolute/path/to/groupwindows.py add
    

    dans les deux. Couvrez-les avec d'autres fenêtres (ou minimisez-les). Ouvrez une troisième fenêtre de terminal, lancez la commande:

    python3 /absolute/path/to/groupwindows.py raise
    

    Les deux premières fenêtres seront levées comme une seule.

  4. Si tout fonctionne correctement, créez trois touches de raccourci personnalisées: Choisissez: Paramètres système> "Clavier"> "Raccourcis"> "Raccourcis personnalisés". Cliquez sur le "+" et ajoutez les commandes ci-dessous à trois raccourcis distincts:

    sur mon système, j'ai utilisé:

    Alt+A, en exécutant la commande:

    python3 /absolute/path/to/groupwindows.py add
    

    ... pour ajouter une fenêtre au groupe.

    Alt+R, en exécutant la commande:

    python3 /absolute/path/to/groupwindows.py raise
    

    ... pour élever le groupe.

    Alt+C, en exécutant la commande:

    python3 /absolute/path/to/groupwindows.py clear
    

    ... pour effacer le groupe

Explication

Le script fonctionne tout simplement:

  • Lorsqu'il est exécuté avec l'argument add, le script enregistre/ajoute l'identifiant de fenêtre de la fenêtre active dans un fichier caché ~/.windowlist
  • Lorsqu'il est exécuté avec l'argument raise, le script lit le fichier, soulève les fenêtres de la liste à l'aide de la commande suivante:

    wmctrl -ia <window_id>
    
  • Lorsqu'il est exécuté avec l'argument clear, le script supprime le fichier caché ~/.windowlist.

Remarques

  • Le script fonctionnera également sur les fenêtres réduites, il minimisera la possibilité de réduire les fenêtres éventuellement réduites.
  • Si l'ensemble de fenêtres se trouve sur une autre fenêtre, le script bascule sur la fenêtre correspondante.
  • L'ensemble est flexibel, vous pouvez toujours ajouter d'autres fenêtres à l'ensemble actuel.

Plus de flexibilité?

Comme mentionné, le script ci-dessus permet d'ajouter des fenêtres à tout moment aux fenêtres groupées. La version ci-dessous autorise également supprimer n'importe laquelle des fenêtres (à tout moment) de la liste groupée:

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

wlist = os.path.join(os.environ["HOME"], ".windowlist")
arg = sys.argv[1]
# add windows to the group
if arg == "add":
    active = subprocess.check_output([
        "xdotool", "getactivewindow"
        ]).decode("utf-8").strip()
    try:
        currlist = open(wlist).read()
    except FileNotFoundError:
        currlist = []
    if not active in currlist:
        open(wlist, "a").write(active + "\n")
# delete window from the group
if arg == "delete":
    try:
        currlist = [w.strip() for w in open(wlist).readlines()]
    except FileNotFoundError:
        pass
    else:
        currlist.remove(subprocess.check_output([
            "xdotool", "getactivewindow"]).decode("utf-8").strip())      
        open(wlist, "w").write("\n".join(currlist)+"\n")
# raise the grouped windows
Elif arg == "raise":
    group = [w.strip() for w in open(wlist).readlines()]
    [subprocess.call(["wmctrl", "-ia", w]) for w in group]
# clear the grouped window list
Elif arg == "clear":
    os.remove(wlist)

L'argument supplémentaire pour exécuter le script est delete, donc:

python3 /absolute/path/to/groupwindows.py delete

supprime la fenêtre active des fenêtres groupées. Pour exécuter cette commande, sur mon système, je mets Alt+D comme raccourci.

6
Jacob Vlijm