web-dev-qa-db-fra.com

Existe-t-il un sélecteur de fenêtre basé sur du texte pour Unity?

Le sélecteur visuel est très pauvre pour fournir le contexte. Par exemple. les miniatures de la fenêtre du navigateur sont trop petites pour les distinguer, et souvent la plupart d'entre elles sont vides (voir capture d'écran). Unity switcher with useless thumbnails

Y a-t-il un sélecteur qui affiche une liste de titres de fenêtres? De préférence avec la saisie semi-automatique intelligente (comme https://github.com/ctrlpvim/ctrlp.vim ou https://github.com/junegunn/fzf ) :-)

3
Jean Jordaan

La partie amusante des "produits faits maison" est toujours que vous pouvez les faire à peu près exactement comme vous le souhaitez. L'inconvénient possible est que vous vous laissez facilement emporter par un projet s'il est agréable de travailler ...

Cela pourrait être le cas avec le script ci-dessous :). Bien que j'aurais préféré ajouter une explication détaillée sur la façon dont cela fonctionne "sous le capot", il s'agit d'une solution "prête à l'emploi". Bien que j'aie ajouté quelques lignes de commentaires, il est difficile de donner une explication interne simple sur le code. Il semble cependant proche de ce que vous recherchez.

Ce que c'est

Le script est une solution purement textuelle pour répertorier toutes les fenêtres d'application "normales" ouvertes (et en augmenter une choisie), mais il a un certain nombre d'options:

  1. liste les fenêtres, triées par nom de la fenêtre:

    Exécutez avec la commande:

    python3 <script> -win
    

    enter image description here

    tapez le (s) premier (s) caractère (s) de la fenêtre recherchée et appuyez sur Entrée pour amener la fenêtre en avant.

  2. lister les fenêtres, triées par application:

    Exécutez avec la commande:

    python3 <script> -app
    

    enter image description here

  3. lister les fenêtres, triées par espace de travail:

    Exécutez avec la commande:

    python3 <script> -ws
    

    enter image description here

Comme vous pouvez le voir, les colonnes affichées sont: Nom de la fenêtre, Application, Workspace. La colonne triée prédéfinie est toujours la première.

Flou?

Pour sélectionner un élément dans la liste, tapez simplement le premier caractère. S'il y a plus d'éléments qui correspondent aux caractères saisis, les touches fléchées parcourent uniquement les éléments qui correspondent aux caractères saisis:

enter image description here

En outre:

indication de l'espace de travail
L'espace de travail actuel est marqué d'un *: par exemple. si tu vois 2*, cela signifie que la fenêtre est sur l'espace de travail 2et espace de travail 2 est l'espace de travail actuel. Cela fonctionne quel que soit le nombre d'espaces de travail dont vous disposez.

La taille de la fenêtre
de la fenêtre de sélection est automatiquement réglé sur le nom de la fenêtre (le plus long) et le nombre de fenêtres à afficher, par exemple:

enter image description here

ou:

enter image description here

Comment utiliser

La configuration est assez simple:

  1. Le script a (définitivement) besoin de wmctrl:

    Sudo apt-get install wmctrl
    
  2. Copiez ensuite le script ci-dessous dans un fichier vide, enregistrez-le sous list_windows.py

  3. Ensuite, testez-le avec les commandes:

    python3 /path/to/list_windows.py -app
    python3 /path/to/list_windows.py -win
    python3 /path/to/list_windows.py -ws
    
  4. Si tout fonctionne correctement, ajoutez une ou plusieurs des commandes préférées à une ou plusieurs touches de raccourci: choisissez: Paramètres système> "Clavier"> "Raccourcis"> "Raccourcis personnalisés". Cliquez sur le "+" et ajoutez la commande

Le script

(code encore "non poli")

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

arg = sys.argv[1]
# list (column) header titles and their (data) position in the produced window data list
cols = [["Workspace", -1], ["Application name", -2] , ["Window name", -3]]
# rearrange columns, depending on the chosen option
if arg == "-app":
    cols = [cols[1], cols[2], cols[0]]
Elif arg == "-ws":
    cols = [cols[0], cols[2], cols[1]]
Elif arg == "-win":
    cols = [cols[2], cols[1], cols[0]]
# extract headers, list positions, to be used in the zenity list
col1 = cols[0][0]; i1 = cols[0][1]
col2 = cols[1][0]; i2 = cols[1][1]
col3 = cols[2][0]; i3 = cols[2][1]
# just a helper function
get = lambda cmd: subprocess.check_output([
    "/bin/bash", "-c", cmd
    ]).decode("utf-8")
# analyse viewport data, to be able to calculate relative/absolute position of windows
# and current viewport
def get_spandata():
    xr = get("xrandr").split(); pos = xr.index("current")
    res = [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]
    spandata = get("wmctrl -d").split()
    span = [int(n) for n in spandata[3].split("x")]
    cols = int(span[0]/res[0]); rows = int(span[1]/res[1])
    curr_vector = [int(n) for n in spandata[5].split(",")]
    curr_viewport = int((curr_vector[1]/res[1])*cols + (curr_vector[0]/res[0])+1)
    return {"resolution": res, "n_columns": cols, "vector": curr_vector, "current_viewport": curr_viewport}

posdata = get_spandata()
vector = posdata["vector"]; cols = posdata["n_columns"]
res = posdata["resolution"]; currvp = posdata["current_viewport"]
# function to distinguish "normal" windows from other types (like the desktop etc)
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
# split windowdata by machine name
mach_name = socket.gethostname()
wlist = [[l.strip() for l in w.split(mach_name)] for w in get("wmctrl -lpG").splitlines()]
# split first section of window data
for i, w in enumerate(wlist):
    wlist[i][0] = wlist[i][0].split()
# filter only "real" windows
real_wlist = [w for w in wlist if check_window(w[0][0]) == True]
# adding the viewport to the window's data
for w in real_wlist:
    w.append(get("ps -p "+w[0][2]+" -o comm=").strip())
    loc_rel = [int(n) for n in w[0][3:5]]
    loc_abs = [loc_rel[0]+vector[0], loc_rel[1]+vector[1]]
    abs_viewport = int((loc_abs[1]/res[1])*cols + (loc_abs[0]/res[0])+1)
    abs_viewport = str(abs_viewport)+"*" if abs_viewport == currvp else str(abs_viewport)
    w.append(abs_viewport)
# set sorting rules
if arg == "-app":
    real_wlist.sort(key=lambda x: x[-2])
Elif arg == "-ws":
    real_wlist.sort(key=lambda x: x[-1])
Elif arg == "-win":
    real_wlist.sort(key=lambda x: x[-3])
# calculate width and height of the zenity window:
# height = 140px + 23px per line
h = str(140+(len(real_wlist)*23))
# width = 250px + 8px per character (of the longest window title)
w = str(250+(max([len(w[-3]) for w in real_wlist])*8))
# define the zenity window's content
cmd = "zenity --list --hide-column=4 --print-column=4 --title='Window list' "\
      "--width="+w+" --height="+h+" --column='"+col1+"' --column='"+col2+"' --column='"+col3+\
      "' --column='w_id' "+(" ").join([(" ").join([
          '"'+w[i1]+'"','"'+w[i2]+'"','"'+w[i3]+'"','"'+w[0][0]+'"'
          ]) for w in real_wlist])
# finally, call the window list
try:
    w_id = subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8").split("|")[0]
    subprocess.Popen(["wmctrl", "-ia", w_id])
except subprocess.CalledProcessError:
    pass
4
Jacob Vlijm

Réponses provisoires:

2
Jean Jordaan