¿Cómo puedo iniciar una aplicación con un tamaño de ventana y una posición predefinidos?

19

Me pregunto si hay alguna forma de lograr el efecto de los accesos directos de Ctrl-Alt-Teclado en Unity usando comandos de terminal en su lugar. Quiero un comando que configure una ventana de GUI a la mitad del tamaño de la pantalla, ya sea alineado a la izquierda o a la derecha.

A modo de trasfondo, estoy escribiendo un script que se ejecuta después de iniciar sesión. Utiliza Zenity para preguntar si quiero o no abrir mi entorno de desarrollo (GVim e IPython uno al lado del otro). He intentado lograr dos ventanas de igual tamaño para estos programas usando set lines= columns= en mi .gvimrc y c.IPythonWidget.width = y c.IPythonWidget.height = en mi ipython_qtconsole_config.py . Sin embargo, hay problemas asociados con este enfoque.

    
pregunta STim 25.04.2015 - 17:48

6 respuestas

15

Con lo que se encontrará

Si desea llamar primero a una aplicación y, posteriormente, colocar su ventana en una posición y tamaño específicos, el tiempo entre llamar a la aplicación y en el momento en que aparece realmente la ventana , es impredecible. Si su sistema está ocupado, puede ser significativamente más largo que si está inactivo.

Necesita una forma "inteligente" para asegurarse de que el posicionamiento / cambio de tamaño finalice (inmediatamente) después de que aparezca la ventana .

Script para llamar a una aplicación, esperar a que aparezca y colocarla en la pantalla

Con la secuencia de comandos a continuación, puede llamar a una aplicación y establecer la posición y el tamaño en el que debería aparecer con el comando:

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

Algunos ejemplos:

  • Para llamar a gnome-terminal y cambiar el tamaño de su ventana al 50% y colocarla en la mitad derecha:

    <script> gnome-terminal 840 0 50 100
    

  • Para llamar a gedit , colocar su ventana en la izquierda y invocar gnome-terminal , colocarlo a la derecha (estableciendo su v-size 46% para darle un pequeño espacio entre las ventanas ):

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

  • Para llamar a Inkscape, coloque su ventana en el cuarto izquierdo / superior de la pantalla:

    <script> inkscape 0 0 50 50
    

El script y cómo usarlo

  1. instala ambos xdotool y wmctrl . Usé ambos ya que el cambio de tamaño con wmctrl puede ocasionar algunas peculiaridades (específicamente) Unity .

    sudo apt-get install wmctrl
    sudo apt-get install xdotool
    
  2. Copie la secuencia de comandos siguiente en un archivo vacío, guárdelo como setwindow (sin extensión) en ~/bin ; cree el directorio si es necesario.
  3. Hacer el script ejecutable (!)
  4. Si acabas de crear ~bin , ejecuta: source ~/.profile
  5. Pruebe ejecutar el script con el comando (por ejemplo)

    setwindow gnome-terminal 0 0 50 100
    

    En otras palabras:

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

Si todo funciona bien, use el comando donde lo necesite.

El 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

Qué hace

Cuando se llama al script, este:

  1. inicia la aplicación
  2. vigila la lista de ventanas (usando wmctrl -lp )
  3. si aparece una nueva ventana, comprueba si la nueva ventana pertenece a la aplicación llamada (usando ps -ef ww , comparando el pid de la ventana con el pid de la aplicación)
  4. si es así, establece el tamaño y la posición, de acuerdo con sus argumentos. En caso de que una aplicación no se "muestre" dentro de aprox. 15 segundos, el script asume que la aplicación no se ejecutará debido a un error. La secuencia de comandos luego termina para evitar esperar la nueva ventana infinitamente.

Problema menor

En Unity, cuando (re) posiciona y (re) ajusta el tamaño de una ventana con wmctrl o xdotool , la ventana siempre mantendrá un margen pequeño en los bordes de la pantalla, a menos que lo configure al 100%. Puedes ver eso en la imagen (3) de arriba; mientras que la ventana inkscape se colocó en x posición 0, aún se puede ver un marge menor entre el Unity Launcher y la ventana inkscape .

    
respondido por el Jacob Vlijm 26.04.2015 - 09:20
4

Tengo una aplicación llamada Worksets (en github ) para Unity que te permite hacer esto fácilmente a través de una interfaz gráfica de usuario. Es gratis y de código abierto.

Básicamente es un contenedor para las soluciones wmctrl y xdotool que se enumeran aquí como respuestas, y proporciona una manera fácil de realizar y guardar dichas configuraciones rápidamente.

    
respondido por el Tumult 10.07.2017 - 05:07
3

El comando real que desea es algo así como

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

Eso hará que la ventana actual ocupe la mitad de la pantalla (cambie $HALF a las dimensiones de su pantalla) y encaje en el lado izquierdo. Para ajustar a la derecha, use

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

También puedes jugar con wmctrl para obtener la ID de las ventanas que te interesan en lugar de usar :ACTIVE: . No puedo ayudar allí, ya que eso depende de las ventanas en cuestión. Eche un vistazo a man wmctrl para más.

He escrito un guión para eso. No uso Unity, así que no puedo garantizar que funcione, pero no veo ninguna razón para no hacerlo. Necesita wmctrl , xdpyinfo y disper para instalarse:

sudo apt-get install wmctrl x11-utils disper

Luego, guarde el script a continuación como ~/bin/snap_windows.sh , hágalo ejecutable con chmod a+x ~/bin/snap_windows.sh y puede ejecutar

snap_windows.sh r

Para ajustar al lado derecho. Use l para el lado izquierdo y sin argumentos para maximizar la ventana. Tenga en cuenta que se ejecuta en la ventana actual, por lo que tendrá que asignarle un acceso directo si desea que se ejecute en cualquier cosa que no sea el terminal.

La secuencia de comandos es un poco más complicada de lo que pides porque la escribí para que funcione en configuraciones de monitores simples y duales.

#!/usr/bin/env bash

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

## If a side has been given, continue
side=;
## 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
    
respondido por el terdon 25.04.2015 - 18:35
3

Puedes hacer esto usando xdotool .

Para instalar xdotool puede ejecutar:

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

Luego, para enviar una tecla Ctrl + Alt + & lt; keypad_key & gt; a la ventana del terminal X que puede ejecutar:

xdotool key Ctrl+Alt+<keypad_key_value>

* & lt; keypad_key_value & gt; = valor de la clave del teclado en la lista siguiente

Para ejecutar un programa GUI y enviar la pulsación de tecla a su ventana X (que en este caso es la ventana activa en el momento de la ejecución del comando xdotool ) puede ejecutar:

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

* & lt; comando & gt; = comando que abre la ventana a la que desea enviar la pulsación de tecla; & lt; retraso & gt; = tiempo de espera en milisegundos antes de enviar la pulsación de tecla; & lt; keypad_key_value & gt; = valor de la clave del teclado en la lista siguiente

Observe que en la mayoría de los casos necesitará ejecutar el comando que está emitiendo como un proceso independiente (por ejemplo, ejecutando nohup <command> & en lugar de <command> en el ejemplo anterior), de lo contrario xdotool won ' se ejecutará hasta que se complete la ejecución de <command> .

También tendrá que establecer un retraso, de lo contrario, la pulsación de tecla se enviará antes de que la ventana de destino esté completamente cargada en X (un retraso de 500ms debería hacerlo).

Los valores posibles para <keypad_key_value> son:

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

Como regla general, para conocer el valor de cualquier tecla en el teclado dentro del entorno X , se puede ejecutar xev y presionar la tecla para mostrar su valor dentro del terminal.

    
respondido por el kos 25.04.2015 - 17:55
1

No tengo el representante para comentar directamente la excelente publicación de Jacob Vlijm, pero modifiqué el script para permitir el inicio de una aplicación con argumentos (es necesario usar setwindow con gedit --new-window ). Cambio:

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

a:

if app.split()[0] in p and w[2] in p] for w in ws2]
    
respondido por el D. Hancock 13.05.2016 - 17:31
0

Jugué con el script de Terdon desde arriba y agregué algunas cosas nuevas (posibilidad de seleccionar el monitor y configurar la altura de cada monitor). Sería extensible agregar más monitores, creo. Con suerte, otros lo encontrarán útil.

Sintaxis básica:

prog_name monitor l/r/m window_name (optional)

Donde prog_name es lo que guardó este código como; monitor es el número de monitor, p. 1 o 2; l / r / m es izquierda o derecha o máxima; y window_name es el nombre (o una fracción de su nombre) de la ventana de destino.

P. ej .:

setwindow 1 m chrome

Script de 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 [ !  ]; then
    WIN=":ACTIVE:"
else
    WIN=
fi
case  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  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
    
respondido por el Philosopher Rex 02.07.2018 - 09:49

Lea otras preguntas en las etiquetas