Comment puis-je regrouper les fenêtres à soulever comme une seule?

10

J'ai deux fenêtres, A et B. Est-il possible de lier en quelque sorte deux fenêtres ensemble, de sorte que le passage à A déclenche également B, ou 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?

Simon Tong
la source
z-order n'est pas super important mais si possible ce serait génial
Simon Tong
Je pense que plusieurs lieux de travail est de loin la solution la plus simple. Vous connaissez les combinaisons de touches pour basculer entre elles?
thomasrutter
1
Vous êtes un accepteur rapide :) Néanmoins, je vous serais reconnaissant de bien vouloir donner un commentaire sur ma réponse.
Jacob Vlijm
5
Copie possible du «regroupement»

Réponses:

9

introduction

Le script suivant permet de sélectionner deux fenêtres, et bien que les deux fenêtres soient ouvertes, il soulèvera les deux fenêtres lorsque l'utilisateur se concentrera sur l'une d'entre elles. Par exemple, si l'on relie les veuves A et B, le fait de passer à A ou B les fera s'élever au-dessus des autres veuves.

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

Ajustements potentiels:

  • plusieurs instances du script peuvent être utilisées pour regrouper des paires de deux fenêtres. Par exemple, si nous avons des fenêtres A, B, C et D, nous pouvons lier A et B ensemble, et lier C et D ensemble.
  • plusieurs fenêtres peuvent être regroupées sous une seule fenêtre. Par exemple, si je relie la fenêtre B à A, C à A et D à A, cela signifie que si je passe toujours à A, je peux ouvrir 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, il peut donc également s'exécuter en tant que

python3 link_windows.py

Il existe deux options de ligne de commande:

  • --quietou -q, permet de faire taire 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.
  • --helpou -himprime les informations d'utilisation et de description.

L' -hoption produit 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 être dans le même répertoire que le script.

Processus d'utilisation simple pour deux fenêtres:

  1. Une fenêtre apparaîtra vous demandant de sélectionner une fenêtre # 1, appuyez OKou appuyez sur Enter. Le pointeur de la souris se transforme en croix. Cliquez sur l'une des fenêtres que vous souhaitez lier.

  2. Une deuxième fenêtre apparaîtra vous demandant de sélectionner la fenêtre # 2, appuyez OKou appuyez sur Enter. Encore une fois, le pointeur de la souris se transforme en croix. Cliquez sur l'autre fenêtre que vous souhaitez lier. Après cette exécution commencera.

  3. Chaque fois que vous concentrez l'une des fenêtres, le script fait monter l'autre fenêtre, mais ramène le focus à celle initialement sélectionnée (note - avec un quart de seconde de retard pour de meilleures performances), créant ainsi l'impression que les fenêtres sont liées entre elles.

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

Source de script

Également disponible en GitHub Gist

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Author: Sergiy Kolodyazhnyy
Date:  August 2nd, 2016
Written for: /ubuntu//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 __name__ == "__main__":
    main()

Remarques:

Sergiy Kolodyazhnyy
la source
Vive, je suis vraiment impressionné. Le time.sleeppeu entre la commutation, est-ce que je peux mettre ça à zéro? y a-t-il une raison au retard?
Simon Tong
1
@simontong vous pouvez essayer de commenter cette ligne comme # time.sleep(0.25)et elle ne s'exécutera pas. La raison en est que chaque fenêtre est correctement relevée. D'après mon expérience dans le passé, j'avais besoin d'avoir des retards pour fonctionner sur Windows. Je pense que le retard d'un quart de seconde n'est pas tant que ça. En fait, permettez-moi d'ajouter une seule ligne de plus au script, ce qui pourrait l'accélérer. D'ACCORD ?
Sergiy Kolodyazhnyy
@simontong OK, j'ai mis à jour le script. Essayez-le maintenant. Devrait avoir un changement plus rapide
Sergiy Kolodyazhnyy
@simontong Je mettrai à jour le script avec quelques ajouts mineurs pour ajouter quelques fonctionnalités supplémentaires. Je vous ferai savoir une fois qu'il sera prêt, faites-moi savoir ce que vous en pensez
Sergiy Kolodyazhnyy
@simontong a ajouté des options supplémentaires au script, veuillez vérifier
Sergiy Kolodyazhnyy
6

Augmenter un nombre arbitraire de fenêtres comme une seule

La solution ci-dessous vous permettra de choisir n'importe quelle combinaison de deux, trois ou plusieurs fenêtres à combiner et à soulever comme une seule avec un raccourci clavier.

Le script fait son travail avec trois arguments:

add

pour ajouter la fenêtre active au groupe

raise

pour élever le groupe défini

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 wmctrlet xdotool:

    sudo apt-get install wmctrl xdotool
  2. Copiez le script ci-dessus dans un fichier vide, enregistrez-le sous groupwindows.py
  3. Testez-exécutez le script: ouvrez deux fenêtres de terminal, exécutez 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, exécutez 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 stocke / 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, ouvre les fenêtres de la liste avec la commande:

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

Remarques

  • Le script fonctionnera également sur les fenêtres minimisées, il minimisera les fenêtres éventuellement réduites
  • Si l'ensemble de fenêtres se trouve sur une autre fenêtre, le script passera à la fenêtre correspondante
  • L'ensemble est flexible, 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 permet également de supprimer n'importe quelle fenêtre (à 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 deletele suivant:

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, j'ai défini Alt+ Dcomme raccourci.

Jacob Vlijm
la source