web-dev-qa-db-fra.com

Comment trouver les fenêtres d'une application spécifique et les placer dans une grille?

J'essaie d'écrire un script pour identifier toutes les fenêtres chrome ouvertes et les déplacer dans une disposition en grille sur un grand écran

Je ne sais pas comment trouver les meilleures résolutions, alors j'allais les ajouter manuellement à un tableau. Ainsi, si la fenêtre 1 chrome était disponible, maximisez-la si 2 chrome fenêtres disponibles puis aller à un tableau pour les tailles pour cela?

Pour le moment, je peux déplacer toutes les fenêtres de l'écran (mon écran est alors cassé) mais je peux voir comment déplacer uniquement les écrans chrome?

Le script ci-dessous contient quelques idées que j'ai eues, mais veuillez indiquer la direction correcte car pour le moment, le script ne fonctionne pas.

#!/bin/bash
#Chrome window crontroller 


# Monitor 1920 X 1800

# Choose array for number of screens available 

# Different screen positions 
G=0
win1_X=5;      win1_Y=24;    win1_W=639;   win1_H=499;
win2_X=642;    win2_Y=24;    win2_W=639;   win2_H=499;
win3_X=1280;   win3_Y=24;    win3_W=639;   win3_H=499;
win4_X=5;      win4_Y=552;   win4_W=639;   win4_H=499;

ChromesAvailable()
{
    CA=$(wmctrl -lx | grep Chromium | wc -l)
}


GetNumOfChrome()
{
  WID=$(wmctrl -l | grep n | awk '{print$1}')
  #echo "INFO: window id = $WID"
}


PlaceWindow()
{
  X=${n}_X; Y=${n}_Y; W=${n}_W; H=${n}_H; 
  wmctrl -i -r "$WID" -e $G,${!X},${!Y},${!W},${!H}
}

if [ "$#" -gt 0 ]; then
 case "$1" in

        *)
            echo "ERROR: invalid option $1"
            echo "see --help for usage"
            exit 1
            ;;
  esac
  exit 0
else
for n in win{1..4}; do
    GetNumOfChrome
    PlaceWindow
done

fi

Edité - Pour mieux expliquer les choses :-)

Utiliser grep n chargera toutes les fenêtres ouvertes du système. J'ai donc essayé d'utiliser grep Chromimum mais le script n'aime pas cela.

 GetNumOfChrome()
    {
      WID=$(wmctrl -l | grep n | awk '{print$1}')
      #echo "INFO: window id = $WID"
    }
3
Grimlockz

Une approche différente consiste à organiser les fenêtres sous forme de grille prédéfinie (personnalisable) (colonnes/lignes).

Un exemple:

enter image description here

réarrangé en (cols réglé sur 3, rows réglé sur 2):

enter image description here

réarrangé en (cols réglé sur 4, rows réglé sur 2):

enter image description here

Le script ci-dessous peut être utilisé pour cela. Comme indiqué, le nombre de colonnes et de lignes peut être défini, ainsi que le remplissage entre les fenêtres. Le script calcule ensuite les positions dans lesquelles les fenêtres doivent être disposées, ainsi que leurs tailles.

Utilisation de la commande wmctrl sur Unity

La commande wmctrl montre certaines particularités lorsqu’elle est utilisée pour déplacer des fenêtres vers ou très près du lanceur ou du panneau. Donc les marges:

left_margin = 70; top_margin = 30

ne peut pas être mis à zéro. Vous devez respecter une distance minimale de quelques px avec le panneau et le lanceur. Je suggérerais de laisser les deux marges - valeurs telles qu'elles sont. Toutes les autres valeurs, marges, colonnes et rangées avec lesquelles vous pouvez jouer et le définir à votre guise.

Le scénario

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

#--- set your preferences below: columns, rows, padding between windows, margin(s)
cols = 2; rows = 2; padding = 10; left_margin = 70; top_margin = 30
#---

get = lambda cmd: subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
def get_res():
    xr = get("xrandr").split(); pos = xr.index("current")
    return [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]

# 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
pids = [p.split()[0] for p in get("ps -e").splitlines() if sys.argv[1] in p]
w_list = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if p in w] for p in pids], [])
print(pids, w_list, coords)
# 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])

Comment utiliser

  1. Assurez-vous que wmctrl est installé :)
  2. Copiez ce script dans un fichier vide, enregistrez-le sous le nom rearrange_windows.py
  3. Dans la section head du script, définissez vos préférences.
  4. Exécutez-le à l'aide de la commande:

    python3 /path/to/rearrange_windows.py <application>
    

    exemple: pour réorganiser chromium fenêtres:

    python3 /path/to/rearrange_windows.py chromium
    

    réorganiser chrome fenêtres

    python3 /path/to/rearrange_windows.py chrome
    

Remarque

Le script peut être utilisé pour placer les fenêtres de n'importe quelle application dans une grille, car le nom du processus de l'application est utilisé comme argument.


MODIFIER

Version dynamique

ci-dessous une version dynamique du script, comme demandé dans un commentaire. Cette version du script calcule le nombre de colonnes et de lignes en fonction du nombre de fenêtres. Les proportions de la ou des fenêtres réarrangées sont similaires à celles de l’écran.

La configuration et l'utilisation sont à peu près les mêmes que celles de la version ci-dessus, seul le nombre de colonnes et de lignes est maintenant défini automatiquement.

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

#--- set your preferences below: padding between windows, margin(s)
padding = 10; left_margin = 70; top_margin = 30
#---

get = lambda cmd: subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
def get_res():
    xr = get("xrandr").split(); pos = xr.index("current")
    return [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]

# find windows of the application, identified by their pid
pids = [p.split()[0] for p in get("ps -e").splitlines() if sys.argv[1] in p]
w_list = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if p in w] for p in pids], [])
# calculate the columns/rows, depending on the number of windows
cols = math.ceil(math.sqrt(len(w_list))); rows = cols
# define (calculate) the area to divide
res = get_res()
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
if cols != 0:
    w_size = [str(int(area_h/cols - padding)), str(int(area_v/rows - padding))]
# 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.call(["/bin/bash", "-c", cmd])

Voir ci-dessous les exemples avec un nombre variable de fenêtres ouvertes:

enter image description hereenter image description here

enter image description hereenter image description here

Explication (deuxième script)

Recherche des fenêtres spécifiques

  1. La commande:

    wmctrl -lp
    

    liste toutes les fenêtres, dans le format:

    0x19c00085  0 14838  jacob-System-Product-Name *Niet-opgeslagen document 1 - gedit
    

    où la première colonne est l'identifiant unique de la fenêtre et la troisième colonne le pid de l'application propriétaire de la fenêtre.

  2. La commande:

    ps -e
    

    liste tous les processus, dans le format:

    14838 ?        00:00:02 gedit
    

    où la première colonne est le pid de l'application, la dernière est le nom du processus.

  3. En comparant ces deux listes, on peut trouver toutes les fenêtres (id of-) appartenant à une application spécifique (appelée w_list dans le script, à la suite de la ligne 17/18 du script):

    pids = [p.split()[0] for p in get("ps -e").splitlines() if sys.argv[1] in p]
    w_list = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if p in w] for p in pids], [])
    

Calcul du nombre de lignes/colonnes

  1. Si nous faisons les fenêtres dans les mêmes proportions que l'écran, cela signifie que le nombre de colonnes est égal au nombre de lignes.
  2. Cela implique que le nombre de colonnes et de rangées est égal à la racine carrée arrondie du nombre de fenêtres à réorganiser. Cela se fait à la ligne 20:

    cols = math.ceil(math.sqrt(len(w_list))); rows = cols
    

Calcul de la taille et de la position de la fenêtre

  1. Une fois que nous avons le nombre de colonnes, tout ce que nous avons à faire est de diviser la zone disponible (résolution d'écran - marge gauche/marge supérieure) dans les colonnes/lignes et nous obtenons le taille de la fenêtre ciblée, qui est puis diminué de la padding, comme indiqué dans la tête du script:

    w_size = [str(int(area_h/cols - padding)), str(int(area_v/rows - padding))]
    
  2. Les positions horizontales (x) sont le résultat du ou des produits du type taille de la fenêtre horizontale (remplissage compris) multiplié par le numéro de colonne, dans une plage du nombre de Colonnes. par exemple: si j'ai 3 colonnes de 300 px, les positions x résultantes sont:

    [0, 300, 600]
    
  3. Les positions verticales (y) sont calculés de la même manière. Les deux listes sont ensuite combinées dans une liste de coordonnées dans laquelle les fenêtres seront réorganisées.

    Ceci est fait dans les lignes 26-28 du script:

    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], [])
    
  4. La réorganisation réelle enfin (après optimisation des fenêtres éventuellement maximisées) est effectuée à partir de la ligne 33 et plus.

2
Jacob Vlijm

Le script ci-dessous met en mosaïque un nombre arbitraire de fenêtres chrome ou chromées dans une grille Nx2 (N lignes, 2 colonnes), où N dépend du nombre de fenêtres ouvertes. S'il n'y a qu'une seule fenêtre, cette fenêtre sera maximisée (ou non maximisée si elle est déjà maximisée).

#!/usr/bin/env bash

#################################################
# Exit if there are no running chrome processes #
#################################################
pgrep "chrom[e|ium]" &>/dev/null || 
    echo "No Chrom[e|ium] processes are running" 1>&2 && exit
#########################
# Get screen dimensions #
#########################
read width x height < <(xrandr | grep -Po 'current\s*\K.*?(?=,)' )

###################################################################
# Get the names of all Chrome windows. I am using PIDs because    #
# searching by name will match anything with chrome/chromium in   #
# the title, not only chromium windows. It also matches a firefox #
# window open on this AU question, for example.                   #
###################################################################
mapfile -t windows < 
    <(wmctrl -pl | grep -f <(pgrep "chrom[e|ium]") | 
                   cut -d' ' -f1)

####################################
# Get the number of Chrome windows #
####################################
numofwins=${#windows[@]}

#########################################
# Initialize the x and y positions to 0 #
#########################################
x=0
y=0

#############################################
# Get 1/2 the number of windows, rounded up #
#############################################
halfwins=$(printf "%.f" "$(echo $numofwins/2 | bc -l | 
                           awk '{print int($1+0.5)}')")

######################################################
# If there's only one window, maximize/unmaximize it #
######################################################
[[ $numofwins -eq 1 ]] && 
    wmctrl -i -r "${windows[@]}" -b toggle,maximized_vert,maximized_horz &&  
    exit;

##########################################################################
# The height of each window will be the height of the display divided by #
# half the number of windows                                             #
##########################################################################
winheight=$(printf "%.f" "$(echo $height/$halfwins | bc -l)")

##################################################################
# The width of each window will be half the width of the display #
##################################################################
winwidth=$(($width/2))

##################################
# Iterate over each window found #
##################################
for winID in "${windows[@]}"
do
    ########################################
    # Increment a counter. This is used to #
    # know when we should change rows.     #
    ########################################
    let c++
    ###############################
    # Position the current window #
    ###############################
    wmctrl -i -r "$winID" -e 0,$x,$y,$winwidth,$winheight
    ##################################################
    # If the counter is a multiple of 2, change rows #
    ##################################################
    if [[ $((c % 2)) -eq 0 ]]
    then
        y=$((y+$winheight+2))
        x=0
    #######################################
    # If it isn't, move to the right only #
    #######################################
    else
        x=$((x+$winwidth+2))
    fi
done                                
3
terdon