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

22

Me pregunto si hay alguna forma de lograr el efecto de los atajos de teclado Ctrl-Alt-Teclado en Unity utilizando comandos de terminal. Quiero un comando que establezca una ventana de interfaz gráfica de usuario a la mitad del tamaño de la pantalla, alineada a izquierda o derecha.

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

STim
fuente
Actualicé mi respuesta porque no explicaba el tema con suficiente detalle, es posible que desee verificar la actualización
kos

Respuestas:

17

En qué te encontrarás

Si primero desea llamar a una aplicación y, posteriormente, colocar su ventana en una posición y tamaño específicos, el tiempo entre la llamada a la aplicación y el momento en que aparece 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 se realice (inmediatamente) después de que aparezca la ventana .

Script para llamar a una aplicación, espere a que aparezca y colóquelo en la pantalla

Con el siguiente script, 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 gnome-terminaly redimensionar su ventana al 50% y colocarla en la mitad derecha:

    <script> gnome-terminal 840 0 50 100

    ingrese la descripción de la imagen aquí

  • Para llamar gedit, coloque su ventana a la izquierda y llame gnome-terminal, colóquela a la derecha (estableciendo su v-size46% para darle un poco de espacio entre las ventanas):

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

    ingrese la descripción de la imagen aquí

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

    <script> inkscape 0 0 50 50

    ingrese la descripción de la imagen aquí

El guión y cómo usarlo

  1. instalar ambos xdotooly wmctrl. Utilicé ambos, ya que cambiar el tamaño con wmctrlpuede causar algunas peculiaridades en (específicamente) Unity.

    sudo apt-get install wmctrl
    sudo apt-get install xdotool
  2. Copie el script a continuación 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 acaba de crear ~bin, ejecute:source ~/.profile
  5. Pruebe y ejecute 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.

La secuencia de comandos

#!/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

Que hace

Cuando se llama al script, se:

  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 "aparezca" dentro de appr. 15 segundos, el script asume que la aplicación no se ejecutará debido a un error. El script termina para evitar esperar la nueva ventana infinitamente.

Problema menor

En Unity, cuando (re) posiciona y (re) dimensiona una ventana con wmctrlo xdotool, la ventana siempre mantendrá un pequeño margen en los bordes de su pantalla, a menos que lo establezca al 100%. Puedes ver eso en la imagen (3) arriba; Si bien la inkscapeventana se colocó en la xposición 0, aún se puede ver una pequeña marca entre el Iniciador de Unity y la inkscapeventana.

Jacob Vlijm
fuente
Querido Jacob, este es un guión fantástico! Una pregunta: ¿cómo puedo encontrar la dimensión de una ventana abierta para usarla posteriormente junto con el script?
orschiro
Hola @orschiro, tengo que postularme para una reunión ... volveré dentro de unas horas :)
Jacob Vlijm
1
Hola @orschiro, suponiendo que haya wmctrlinstalado, el comando: wmctrl -lG | grep <windowname>le mostrará una salida como: 0x03600e4f 0 723 197 1114 563 jacob-System-Product-Name dimkeyboard.sh (~/Bureaublad) - gedit. En esta salida, la columna 3 a 6 muestra las dimensiones, x, y, ancho, ancho, alto.
Jacob Vlijm
Muy apreciado Jacob! Creo que hice la configuración correctamente, pero la ventana respectiva se abre en pantalla completa ahora. ¿Algunas ideas?
orschiro
1
Me encantó este script, pero tuve que hacer los siguientes cambios en el primer bloque para que funcione para mí, porque agregué parámetros a la aplicación: 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> se niega a formatear ese código. </edit>
Ron Thompson,
3

El comando real que quieres 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 $HALFa las dimensiones de su pantalla) y se ajuste al lado izquierdo. Para girar a la derecha, use

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

También puedes jugar wmctrlpara obtener la identificación de las ventanas que te interesan en lugar de usar :ACTIVE:. Sin embargo, no puedo ayudar ya que eso depende de las ventanas en cuestión. Echa un vistazo a man wmctrlmás.


He escrito un guión para eso. No uso Unity, así que no puedo garantizar que funcione con él, pero no veo ninguna razón por la que no. Necesita wmctrl, xdpyinfoy disperpara ser instalado:

sudo apt-get install wmctrl x11-utils disper

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

snap_windows.sh r

Para encajar a la derecha. Use lpara el lado izquierdo y sin argumentos para maximizar la ventana. Tenga en cuenta que se ejecuta en la ventana actual, por lo que deberá asignarle un acceso directo si desea que se ejecute en cualquier cosa que no sea el terminal.

El script es un poco más complicado de lo que pides porque lo he escrito para que funcione en configuraciones de monitor único y dual.

#!/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
fuente
3

Puedes hacer esto usando xdotool.

Para instalar xdotoolpuedes ejecutar:

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

Luego, para enviar una pulsación de tecla Ctrl+ Alt+ <keypad_key>a la Xventana de terminal , puede ejecutar:

xdotool key Ctrl+Alt+<keypad_key_value>

* <keypad_key_value> = valor de la tecla del teclado en la lista a continuación

Para ejecutar un programa GUI y enviar la combinación de teclas a su Xventana (que en este caso es la ventana activa en el momento de la xdotoolejecución del comando) puede ejecutar:

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

* <comando> = comando que abre la ventana a la que desea enviar la pulsación de tecla; <delay> = tiempo de espera en milisegundos antes de enviar la pulsación de tecla; <keypad_key_value> = valor de la tecla del teclado en la lista a continuación

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

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

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 averiguar el valor de cualquier tecla del teclado dentro del Xentorno, se puede ejecutar xevy presionar la tecla para generar su valor dentro del terminal.

kos
fuente
¿Hay algo mal con nuestras ediciones?
Tim
@Tim No, al menos no la eliminación de la última línea, que estoy de acuerdo es bastante inútil, pero lo que puede variar dentro de un comando está mejor formateado si está encerrado entre paréntesis angulares, que es la notación estándar en la teoría del lenguaje para referirse a una categoría sintáctica (refiriéndose a su edición) y creo que un nombre de comando está mejor formateado si está encerrado en backticks, para ser reconocido inmediatamente como tal (refiriéndose a la edición de AB); note que no todo esto está fuera de mi cabeza, tenía dudas antes y pregunté esto en meta
kos el
Sí, está bien como está ahora :) <> es el estándar, y voy por `` alrededor de cualquier comando :)
Tim
3

He creado 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 gratuita y de código abierto.

t Menú de bandeja

Básicamente es un envoltorio para las soluciones wmctrl y xdotool enumeradas como respuestas aquí, y proporciona una manera fácil de hacer y guardar rápidamente tales configuraciones.

Tumulto
fuente
1

No tengo el representante para comentar directamente sobre la excelente publicación de Jacob Vlijm, pero modifiqué el script para permitir iniciar una aplicación con argumentos (necesarios para usar setwindowcon 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]
D. Hancock
fuente
0

Jugué con el guión de Terdon desde arriba y agregué algunas cosas nuevas (capacidad de seleccionar el monitor y establecer la altura para cada monitor). Sería extensible agregar más monitores, creo. Esperemos que otros lo encuentren útil.

Sintaxis básica:

prog_name monitor l/r/m window_name (optional)

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

P.ej:

setwindow 1 m chrome

Guión 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
Filósofo Rex
fuente