web-dev-qa-db-fra.com

Comment démarrer une application avec une taille et une position de fenêtre prédéfinies?

Je me demande s'il y a un moyen quelconque d'obtenir l'effet des raccourcis clavier Ctrl-Alt-Clavier dans Unity en utilisant plutôt les commandes de terminal. Je veux une commande qui définit une fenêtre graphique à la moitié de la taille de l’écran, alignée à gauche ou à droite.

En guise d'arrière-plan, j'écris un script qui s'exécute après la connexion. Il utilise Zenity pour demander si je veux ou non ouvrir mon environnement de développement (GVim et IPython côte à côte). J'ai essayé d'obtenir deux fenêtres de taille égale pour ces programmes en utilisant set lines= columns= dans mon .gvimrc et c.IPythonWidget.width = et c.IPythonWidget.height = dans mon ipython_qtconsole_config.py. Cependant, cette approche pose des problèmes.

20
STim

Ce que vous allez rencontrer

Si vous souhaitez d'abord appeler une application, puis placer sa fenêtre sur une position et une taille spécifiques, le temps entre appel de l'application et au moment où la fenêtre apparaît réellement, est imprévisible. Si votre système est occupé, il peut être considérablement plus long que s'il est inactif.

Vous avez besoin d'un moyen "intelligent" pour vous assurer que le positionnement/redimensionnement est fait (immédiatement) après la fenêtre apparaît.

Script pour appeler une application, attendez qu’elle apparaisse et positionnez-la à l’écran

Avec le script ci-dessous, vous pouvez appeler une application et définir la position et la taille sur lesquelles elle doit apparaître avec la commande:

<script> <application> <x-position> <y-position> <h-size> <v-size>

Quelques exemples:

  • Pour appeler gnome-terminal et redimensionner sa fenêtre à 50% et la placer dans la moitié droite:

    <script> gnome-terminal 840 0 50 100
    

    enter image description here

  • Pour appeler gedit, placez sa fenêtre à gauche et appelez gnome-terminal, placez-la à droite (définissez son v-size 46% pour lui laisser un peu d'espace entre les fenêtres):

    <script> gedit 0 0 46 100&&<script> gnome-terminal 860 0 46 100
    

    enter image description here

  • Pour appeler Inkscape, placez sa fenêtre dans le quart gauche/supérieur de l’écran:

    <script> inkscape 0 0 50 50
    

    enter image description here

Le script et comment l'utiliser

  1. installez à la fois xdotool et wmctrl. J'ai utilisé les deux car le redimensionnement avec wmctrl peut causer des particularités sur (plus précisément) Unity.

    Sudo apt-get install wmctrl
    Sudo apt-get install xdotool
    
  2. Copiez le script ci-dessous dans un fichier vide, enregistrez-le sous le nom setwindow (sans extension) dans ~/bin; créez le répertoire si nécessaire.
  3. Rendre le script exécutable (!)
  4. Si vous venez de créer ~bin, exécutez: source ~/.profile
  5. Exécuter le script avec la commande (par exemple)

    setwindow gnome-terminal 0 0 50 100
    

    En d'autres termes:

    setwindow <application> <horizontal-position> <vertical-position> <horizontal-size (%)> <vertical-size (%)>
    

Si tout fonctionne bien, utilisez la commande où vous en avez besoin.

Le scénario

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

app = sys.argv[1]

get = lambda x: subprocess.check_output(["/bin/bash", "-c", x]).decode("utf-8")
ws1 = get("wmctrl -lp"); t = 0
subprocess.Popen(["/bin/bash", "-c", app])

while t < 30:      
    ws2 = [w.split()[0:3] for w in get("wmctrl -lp").splitlines() if not w in ws1]
    procs = [[(p, w[0]) for p in get("ps -e ww").splitlines() \
              if app in p and w[2] in p] for w in ws2]
    if len(procs) > 0:
        w_id = procs[0][0][1]
        cmd1 = "wmctrl -ir "+w_id+" -b remove,maximized_horz"
        cmd2 = "wmctrl -ir "+w_id+" -b remove,maximized_vert"
        cmd3 = "xdotool windowsize --sync "+procs[0][0][1]+" "+sys.argv[4]+"% "+sys.argv[5]+"%"
        cmd4 = "xdotool windowmove "+procs[0][0][1]+" "+sys.argv[2]+" "+sys.argv[3]
        for cmd in [cmd1, cmd2, cmd3, cmd4]:   
            subprocess.call(["/bin/bash", "-c", cmd])
        break
    time.sleep(0.5)
    t = t+1

Ce qu'il fait

Lorsque le script est appelé, il:

  1. lance l'application
  2. garde un œil sur la liste de fenêtres (usingwmctrl -lp)
  3. si une nouvelle fenêtre apparaît, il vérifie si la nouvelle fenêtre appartient à l'application appelée (en utilisant ps -ef ww, en comparant le pid de la fenêtre au pid de l'application)
  4. si tel est le cas, il définit la taille et la position en fonction de vos arguments. Dans le cas où une application ne "apparaît pas" dans env. 15 secondes, le script suppose que l'application ne s'exécutera pas à cause d'une erreur. Le script se termine ensuite pour éviter d'attendre indéfiniment la nouvelle fenêtre.

Problème mineur

Dans Unity, lorsque vous (re) positionnez et (re) taillez une fenêtre avec wmctrl ou xdotool, la fenêtre conservera toujours une petite marge sur les bordures de votre écran, sauf si vous la définissez à 100%. Vous pouvez voir cela dans l'image (3) ci-dessus; alors que la fenêtre inkscape a été placée à x position 0, vous pouvez toujours voir une marge mineure entre Unity Launcher et la fenêtre inkscape.

17
Jacob Vlijm

J'ai construit une application nommée Worksets (sur github ) pour Unity qui vous permet de le faire facilement via une interface utilisateur graphique - C'est une source gratuite et ouverte.

tTray menu

Il s’agit en fait d’un wrapper pour les solutions wmctrl et xdotool répertoriées ici en tant que réponses, et offre un moyen simple de créer et d’enregistrer rapidement de telles configurations.

3
Tumult

Vous pouvez le faire en utilisant xdotoolname__.

Pour installer xdotoolvous pouvez exécuter:

Sudo apt-get update && Sudo apt-get install xdotool

Puis envoyer un Ctrl+Alt+<keypad_key> Une frappe sur la fenêtre du terminal Xque vous pouvez exécuter:

xdotool key Ctrl+Alt+<keypad_key_value>

* <keypad_key_value> = la valeur de la touche du clavier dans la liste ci-dessous

Pour exécuter un programme graphique et envoyer la frappe à sa fenêtre X(qui dans ce cas est la fenêtre active au moment de l'exécution de la commande xdotoolname__), vous pouvez exécuter:

<command> && window="$(xdotool getactivewindow)" xdotool key --delay <delay> --window "$window" <keypad_key_value>

* <commande> = commande qui ouvre la fenêtre à laquelle vous souhaitez envoyer la frappe; <délai> = temps d'attente en millisecondes avant l'envoi de la frappe; <keypad_key_value> = valeur de la touche du clavier dans la liste ci-dessous

Notez que dans la plupart des cas, vous devrez exécuter la commande émise en tant que processus autonome (par exemple, en exécutant Nohup <command> & au lieu de <command> dans l'exemple ci-dessus), sinon xdotoolne sera pas exécuté tant que l'exécution de <command> ne sera pas terminée.

Vous devrez également définir un délai, sinon la frappe sera envoyée avant le chargement complet de la fenêtre cible dans X(un délai autour de 500ms devrait suffire).

Les valeurs possibles pour <keypad_key_value> sont:

  • : 90
  • 1: 87
  • 2: 88
  • 3: 89
  • 4: 83
  • 5: 84
  • 6: 85
  • 7: 79
  • 8: 80
  • 9: 81

En règle générale, pour connaître la valeur de n'importe quelle touche du clavier dans l'environnement Xname__, vous pouvez exécuter xevet appuyer sur la touche pour afficher sa valeur à l'intérieur du terminal.

3
kos

La commande réelle que vous voulez est quelque chose comme

wmctrl -r :ACTIVE: -b add,maximized_vert && 
wmctrl -r :ACTIVE: -e 0,0,0,$HALF,-1

Cela fera que la fenêtre actuelle occupera la moitié de l’écran (changerez $HALF en fonction des dimensions de votre écran) et s’accrochant à gauche. Pour accrocher à droite, utilisez

wmctrl -r :ACTIVE: -b add,maximized_vert && 
wmctrl -r :ACTIVE: -e 0,$HALF,0,$HALF,-1 

Vous pouvez également jouer avec wmctrlpour obtenir l'ID des fenêtres qui vous intéressent au lieu d'utiliser :ACTIVE:. Je ne peux rien y faire car cela dépend des fenêtres en question. Regardez man wmctrl pour plus.


J'ai écrit un script pour ça. Je n'utilise pas Unity, je ne peux donc pas en garantir le fonctionnement, mais je ne vois pas pourquoi. Il faut que wmctrlname__, xdpyinfoet dispersoit installé:

Sudo apt-get install wmctrl x11-utils disper

Enregistrez ensuite le script ci-dessous sous le nom ~/bin/snap_windows.sh, rendez-le exécutable avec chmod a+x ~/bin/snap_windows.sh et vous pourrez exécuter

snap_windows.sh r

Pour accrocher sur le côté droit. Utilisez lpour le côté gauche et aucun argument pour agrandir la fenêtre. Notez qu’il s’exécute sur la fenêtre en cours, vous devrez donc lui attribuer un raccourci si vous souhaitez qu’elle s’exécute sur autre chose que le terminal.

Le script est un peu plus compliqué que ce que vous demandez, car je l’ai écrit pour fonctionner à la fois sur des configurations à simple et à double moniteur.

#!/usr/bin/env bash

## If no side has been given, maximize the current window and exit
if [ ! $1 ]
then
    wmctrl -r :ACTIVE: -b toggle,maximized_vert,maximized_horz
    exit
fi

## If a side has been given, continue
side=$1;
## How many screens are there?
screens=`disper -l | grep -c display`
## Get screen dimensions
WIDTH=`xdpyinfo | grep 'dimensions:' | cut -f 2 -d ':' | cut -f 1 -d 'x'`;
HALF=$(($WIDTH/2));

## If we are running on one screen, snap to Edge of screen
if [ $screens == '1' ]
then
    ## Snap to the left hand side
    if [ $side == 'l' ]
    then
        ## wmctrl format: gravity,posx,posy,width,height
    wmctrl -r :ACTIVE: -b add,maximized_vert && wmctrl -r :ACTIVE: -e 0,0,0,$HALF,-1
    ## Snap to the right hand side
    else
    wmctrl -r :ACTIVE: -b add,maximized_vert && wmctrl -r :ACTIVE: -e 0,$HALF,0,$HALF,-1 
    fi
## If we are running on two screens, snap to Edge of right hand screen
## I use 1600 because I know it is the size of my laptop display
## and that it is not the same as that of my 2nd monitor.
else
    LAPTOP=1600; ## Change this as approrpiate for your setup.
    let "WIDTH-=LAPTOP";
    SCREEN=$LAPTOP;
    HALF=$(($WIDTH/2));
    if [ $side == 'l' ]
    then
        wmctrl -r :ACTIVE: -b add,maximized_vert && wmctrl -r :ACTIVE: -e 0,$LAPTOP,0,$HALF,-1
    else
    let "SCREEN += HALF+2";
    wmctrl -r :ACTIVE: -b add,maximized_vert && wmctrl -r :ACTIVE: -e 0,$SCREEN,0,$HALF,-1;
    fi
fi
3
terdon

Je n'ai pas le représentant à commenter directement sur l'excellent post de Jacob Vlijm, mais j'ai modifié le script pour permettre de démarrer une application avec des arguments (nécessaire pour utiliser setwindow avec gedit --new-window). Changement:

if app in p and w[2] in p] for w in ws2]

à:

if app.split()[0] in p and w[2] in p] for w in ws2]
1
D. Hancock

J'ai joué avec le script de Terdon d'en haut et j'ai ajouté de nouvelles choses (possibilité de sélectionner le moniteur et de régler la hauteur pour chaque moniteur). Ce serait extensible à ajouter plus de moniteurs, je pense. J'espère que d'autres le trouveront utile.

syntaxe de base:

prog_name monitor l/r/m window_name (optional)

Où nom_prog est ce que vous avez enregistré sous ce code; moniteur est le numéro du moniteur, par exemple. 1 ou 2; l/r/m est à gauche ou à droite ou max; et window_name est le nom (ou une fraction de son nom) de la fenêtre cible.

Par exemple.:

setwindow 1 m chrome

Script Bash

#!/usr/bin/env bash
set -e
#######################-    Early Definitions    -#######################

snap () {
    wmctrl -r ${WIN} -b toggle,add,maximized_vert && wmctrl -r ${WIN} -e 0,${WINX},0,${WINWIDTH},${WINHEIGHT}
    }

DISPLAYWIDTH=`xdpyinfo | grep 'dimensions:' | cut -f 2 -d ':' | cut -f 1 -d 'x'`;       ## Get screen dimensions
LEFTSCREENWIDTH=1024    ## user set
LEFTSCREENHEIGHT=720    ## user set
RIGHTSCREENHEIGHT=960   ## user set
let "RIGHTSCREENWIDTH=(DISPLAYWIDTH-LEFTSCREENWIDTH)"

#############################-    Logic    -#############################

if [ ! ${3} ]; then
    WIN=":ACTIVE:"
else
    WIN=${3}
fi
case ${1} in
    1)  # monitor one
        LEFT=0
        WINHEIGHT=${LEFTSCREENHEIGHT}
        let "WINWIDTH=LEFTSCREENWIDTH/2"
    ;;
    2)  # monitor two
        let "LEFT=LEFTSCREENWIDTH"
        WINHEIGHT=${RIGHTSCREENHEIGHT}
        let "WINWIDTH=RIGHTSCREENWIDTH/2"
    ;;
    "") # error please select a monitor
        echo "please select a monitor (1 or 2)"
        exit 0
    ;;
esac
case ${2} in
    l|L)
        WINX=${LEFT}
        snap
    ;;
    r|R)
        let "WINX=LEFT+WINWIDTH"
        snap
    ;;
    ""|m|M)
        WINX=${LEFT}
        let "WINWIDTH=WINWIDTH*2"
        snap
    ;;
esac

exit 0
0
Philosopher Rex