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

22

Je me demande s'il existe un moyen d'obtenir l'effet des raccourcis Ctrl-Alt-Clavier dans Unity en utilisant des commandes de terminal à la place? 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 me demander si je souhaite ouvrir mon environnement de développement (GVim et IPython côte à côte). Je suis en train de réaliser deux fenêtres de taille égale pour ces programmes en utilisant set lines= columns=dans mon .gvimrcet c.IPythonWidget.width =et c.IPythonWidget.height =dans mon ipython_qtconsole_config.py. Cependant, cette approche pose des problèmes.

STim
la source
J'ai mis à jour ma réponse car elle n'expliquait pas suffisamment le sujet en détails, vous voudrez peut-être vérifier la mise à jour
kos

Réponses:

17

Dans quoi vous rencontrerez

Si vous souhaitez d'abord appeler une application et, par la suite, placer sa fenêtre sur une position et une taille spécifiques, le temps entre l' appel de l'application et le 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 effectué (immédiatement) après l' apparition de la fenêtre .

Script pour appeler une application, attendez qu'elle apparaisse et positionnez-la sur 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-terminalet redimensionner sa fenêtre à 50% et la placer sur la moitié droite:

    <script> gnome-terminal 840 0 50 100

    entrez la description de l'image ici

  • Pour appeler gedit, placez sa fenêtre à gauche et appelez gnome-terminal, placez-la à droite (en réglant ses v-size46% pour lui donner un peu d'espace entre les fenêtres):

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

    entrez la description de l'image ici

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

    <script> inkscape 0 0 50 50

    entrez la description de l'image ici

Le script et comment l'utiliser

  1. installez les deux xdotoolet wmctrl. J'ai utilisé les deux, car le redimensionnement avec wmctrlpeut entraîner certaines particularités (en particulier) Unity.

    sudo apt-get install wmctrl
    sudo apt-get install xdotool
  2. Copiez le script ci-dessous dans un fichier vide, enregistrez-le sous 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. Testez 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 partout où vous en avez besoin.

Le script

#!/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. démarre l'application
  2. garde un œil sur la liste des fenêtres (en utilisant wmctrl -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 c'est le cas, il définit la taille et la position, selon vos arguments. Dans le cas où une demande ne "se présente" pas dans env. 15 secondes, le script suppose que l'application ne s'exécutera pas en raison d'une erreur. Le script se termine alors pour éviter d'attendre indéfiniment la nouvelle fenêtre.

Problème mineur

Dans Unity, lorsque vous (re) positionnez et (re) dimensionnez une fenêtre avec wmctrlou xdotool, la fenêtre gardera toujours une petite marge aux bords de votre écran, sauf si vous la définissez à 100%. Vous pouvez le voir dans l'image (3) ci-dessus; tandis que la inkscapefenêtre était placée en xposition 0, vous pouvez toujours voir une marge mineure entre le lanceur Unity et la inkscapefenêtre.

Jacob Vlijm
la source
Cher Jacob, c'est un script fantastique! Une question: comment puis-je trouver la dimension d'une fenêtre ouverte à utiliser ultérieurement avec le script?
orschiro
Salut @orschiro, je dois me présenter à une réunion ... sera de retour dans quelques heures :)
Jacob Vlijm
1
Salut @orschiro, en supposant que vous avez wmctrlinstallé, la commande: wmctrl -lG | grep <windowname>vous montrer comme une sortie: 0x03600e4f 0 723 197 1114 563 jacob-System-Product-Name dimkeyboard.sh (~/Bureaublad) - gedit. Dans cette sortie, la 3ème à la 6ème colonne affiche les dimensions, x, y, largeur, largeur, hauteur.
Jacob Vlijm
Très apprécié Jacob! Je pense que j'ai fait la bonne configuration, mais la fenêtre respective s'ouvre maintenant en plein écran. Des idées?
orschiro
1
J'ai adoré ce script, mais j'ai dû apporter les modifications suivantes au premier bloc pour qu'il fonctionne pour moi, car j'ai ajouté des paramètres à l'application: appAndParams = sys.argv[1] app = appAndParams[0].split(' ', 1)[0] get = lambda x: subprocess.check_output(["/bin/bash", "-c",x]).decode("utf-8") ws1 = get("wmctrl -lp"); t = 0 subprocess.Popen(["/bin/bash", "-c", appAndParams])</pre> <edit> il refuse de formater ce code. </edit>
Ron Thompson
3

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 occupe la moitié de l'écran (changez $HALFles dimensions de votre écran) et s'accroche sur le côté gauche. Pour accrocher vers la 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 pas vous aider, car cela dépend des fenêtres en question. Jetez un oeil à man wmctrlplus.


J'ai écrit un script pour ça. Je n'utilise pas Unity, je ne peux donc pas garantir qu'il fonctionnera avec, mais je ne vois aucune raison de ne pas le faire. Il a besoin wmctrl, xdpyinfoet disperà installer:

sudo apt-get install wmctrl x11-utils disper

Ensuite, enregistrez le script ci-dessous sous ~/bin/snap_windows.sh, rendez-le exécutable avec chmod a+x ~/bin/snap_windows.shet vous pouvez exécuter

snap_windows.sh r

Pour accrocher sur le côté droit. Utilisationl pour le côté gauche et aucun argument pour maximiser la fenêtre. Notez qu'il s'exécute sur la fenêtre actuelle, vous devrez donc lui attribuer un raccourci si vous souhaitez qu'il 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 sur des configurations à un ou deux moniteurs.

#!/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
terdon
la source
3

Vous pouvez le faire en utilisant xdotool.

Pour installer, xdotoolvous pouvez exécuter:

sudo apt-get update && sudo apt-get install xdotool

Ensuite, pour envoyer une touche Ctrl+ Alt+ <keypad_key>à la Xfenêtre du terminal , vous pouvez exécuter:

xdotool key Ctrl+Alt+<keypad_key_value>

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

Pour exécuter un programme GUI et envoyer la séquence de touches à sa Xfenêtre (qui dans ce cas est la fenêtre active au moment de l' xdotoolexécution de la commande), vous pouvez exécuter:

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

* <command> = commande qui ouvre la fenêtre à laquelle vous souhaitez envoyer la frappe; <delay> = temps d'attente en millisecondes avant d'envoyer la séquence de touches; <keypad_key_value> = valeur de la clé du clavier dans la liste ci-dessous

Notez que dans la plupart des cas, vous devrez exécuter la commande que vous émettez en tant que processus autonome (par exemple en exécutant à la nohup <command> &place de <command>dans l'exemple ci-dessus), sinon xdotoolne sera pas exécutée avant<command> l'exécution n'est pas terminée.

Vous devrez également définir un délai, sinon la frappe sera envoyée avant que la fenêtre cible ne soit complètement chargée X(un délai 500msdevrait suffire).

Les valeurs possibles pour <keypad_key_value>sont:

  • 0: 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' Xenvironnement, on peut exécuter xevet appuyer sur la touche pour afficher sa valeur à l'intérieur du terminal.

kos
la source
Y a-t-il un problème avec nos modifications?
Tim
@Tim Non, du moins pas la suppression de la dernière ligne, ce qui, je suis d'accord, est assez inutile, mais ce qui peut varier au sein d'une commande est à mon avis mieux formaté s'il est placé entre crochets, qui est la notation standard en théorie du langage à laquelle se référer à une catégorie syntaxique (se référant à votre édition) et je pense qu'un nom de commande est mieux formaté s'il est entouré de crochets, afin d'être immédiatement reconnu comme tel (se référant à l'édition d'AB); avis que tous cela est du haut de ma tête, j'avais des doutes avant et j'ai demandé ce sur une méta
kos
Ouais, ça va comme ça maintenant :) <> est la norme, et je vais pour `` autour de toute commande :)
Tim
3

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 gratuit et open source.

Menu tTray

Il s'agit essentiellement d'un wrapper pour les solutions wmctrl et xdotool répertoriées comme réponses ici, et fournit un moyen facile de créer et d'enregistrer rapidement de telles configurations.

Tumulte
la source
1

Je n'ai pas le représentant pour commenter directement 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 l'utiliser setwindowavec 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]
D. Hancock
la source
0

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). Il serait extensible d'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ù prog_name est tout ce que vous avez enregistré ce code sous; 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
Philosophe Rex
la source