Come posso avviare un'applicazione con dimensioni e posizione predefinite della finestra?


22

Mi chiedo c'è un modo per ottenere l'effetto delle scorciatoie da tastiera Ctrl-Alt-Tastiera in Unity usando invece i comandi del terminale? Voglio un comando che imposta una finestra della GUI a metà della dimensione dello schermo, a sinistra oa destra allineata.

A titolo di background, sto scrivendo uno script che viene eseguito dopo l'accesso. Usa Zenity per chiedermi se voglio aprire il mio ambiente di sviluppo (GVim e IPython fianco a fianco). Ho cercato di ottenere due finestre di uguali dimensioni per questi programmi usando set lines= columns=in my .gvimrce c.IPythonWidget.width =e c.IPythonWidget.height =in my ipython_qtconsole_config.py. Tuttavia, ci sono problemi associati a questo approccio.


Ho aggiornato la mia risposta perché non ha spiegato abbastanza l'argomento in dettaglio, potresti voler controllare l'aggiornamento
kos

Risposte:


17

In cosa ti imbatterai

Se si desidera prima chiamare un'applicazione e, successivamente, posizionare la sua finestra su una posizione e dimensione specifiche, il tempo che intercorre tra la chiamata dell'applicazione e il momento in cui appare effettivamente la finestra è imprevedibile. Se il sistema è occupato, può essere significativamente più lungo rispetto a quando è inattivo.

È necessario un modo "intelligente" per assicurarsi che il posizionamento / ridimensionamento venga eseguito (immediatamente) dopo la visualizzazione della finestra .

Script per chiamare un'applicazione, attendere che appaia e posizionarlo sullo schermo

Con lo script seguente, puoi chiamare un'applicazione e impostare la posizione e le dimensioni su cui dovrebbe apparire con il comando:

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

Alcuni esempi:

  • Per chiamare gnome-terminale ridimensionare la sua finestra al 50% e posizionarla sulla metà destra:

    <script> gnome-terminal 840 0 50 100

    inserisci qui la descrizione dell'immagine

  • Per chiamare gedit, posiziona la sua finestra a sinistra e chiama gnome-terminal, posizionalo a destra (impostando il v-size46% per dargli un piccolo spazio tra le finestre):

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

    inserisci qui la descrizione dell'immagine

  • Per chiamare Inkscape, posiziona la finestra nella parte sinistra / superiore dello schermo:

    <script> inkscape 0 0 50 50

    inserisci qui la descrizione dell'immagine

Lo script e come usarlo

  1. installa sia xdotoole wmctrl. Ho usato entrambi poiché il ridimensionamento con wmctrlpuò causare alcune peculiarità (in particolare) Unity.

    sudo apt-get install wmctrl
    sudo apt-get install xdotool
  2. Copia lo script seguente in un file vuoto, salvalo come setwindow(nessuna estensione) in ~/bin; creare la directory se necessario.
  3. Rendi eseguibile lo script (!)
  4. Se hai appena creato ~bin, esegui:source ~/.profile
  5. Esegui il test dello script con il comando (ad es.)

    setwindow gnome-terminal 0 0 50 100

    In altre parole:

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

Se tutto funziona bene, usa il comando ovunque ne hai bisogno.

Il copione

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

Cosa fa

Quando viene chiamato lo script, esso:

  1. avvia l'applicazione
  2. tiene d'occhio l'elenco delle finestre (usando wmctrl -lp)
  3. se appare una nuova finestra, controlla se la nuova finestra appartiene all'applicazione chiamata (usando ps -ef ww, confrontando il pid della finestra con il pid dell'applicazione)
  4. in tal caso, imposta le dimensioni e la posizione, in base ai tuoi argomenti. Nel caso in cui un'applicazione non "si presenti" all'interno di appr. 15 secondi, lo script presuppone che l'applicazione non verrà eseguita a causa di un errore. Lo script termina quindi per impedire l'attesa infinita della nuova finestra.

Problema minore

In Unity, quando si (ri) posiziona e (ri) ridimensiona una finestra con uno wmctrlo xdotool, la finestra manterrà sempre una piccola spaziatura ai bordi dello schermo, a meno che tu non lo imposti al 100%. Potete vederlo nell'immagine (3) sopra; mentre la inkscapefinestra è stata posizionata sulla xposizione 0, è ancora possibile vedere un lieve cambiamento tra l'Unity Launcher e la inkscapefinestra.


Caro Jacob, questa è una sceneggiatura fantastica! Una domanda: come posso trovare la dimensione di una finestra aperta da utilizzare successivamente con lo script?
Orschiro,

Ciao @orschiro, devo correre per un incontro ... tornerò tra poche ore :)
Jacob Vlijm,

1
Ciao @orschiro, sempre che abbiate wmctrlinstallato, il comando: wmctrl -lG | grep <windowname>vi mostrerà un output come: 0x03600e4f 0 723 197 1114 563 jacob-System-Product-Name dimkeyboard.sh (~/Bureaublad) - gedit. In questo output, la colonna dalla terza alla sesta mostra le dimensioni, x, y, larghezza, larghezza, altezza.
Jacob Vlijm,

Jacob molto apprezzato! Penso di aver eseguito correttamente l' installazione, ma ora la relativa finestra si apre a schermo intero. Qualche idea?
Orschiro,

1
Ho adorato questo script, ma ho dovuto apportare le seguenti modifiche al primo blocco per farlo funzionare per me, perché ho aggiunto parametri all'applicazione: 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> si rifiuta di formattare quel codice. </edit>
Ron Thompson,

3

Il vero comando che vuoi è qualcosa di simile

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

Ciò farà in modo che la finestra corrente occupi metà dello schermo (modificando $HALFle dimensioni dello schermo) e scattando sul lato sinistro. Per scattare a destra, utilizzare

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

Puoi anche giocare con wmctrlper ottenere l'ID delle finestre che ti interessano invece di utilizzare :ACTIVE:. Non posso fare a meno però, poiché dipende dalle finestre in questione. Dai un'occhiata man wmctrlper di più.


Ho scritto una sceneggiatura per questo. Non utilizzo Unity quindi non posso garantire che funzionerà con esso, ma non vedo alcun motivo per cui no. Ha bisogno wmctrl, xdpyinfoe disperda installare:

sudo apt-get install wmctrl x11-utils disper

Quindi, salva lo script qui sotto come ~/bin/snap_windows.sh, rendilo eseguibile con chmod a+x ~/bin/snap_windows.she puoi eseguirlo

snap_windows.sh r

Per scattare a destra. Utilizzare lper il lato sinistro e senza argomenti per ingrandire la finestra. Si noti che viene eseguito sulla finestra corrente, quindi è necessario assegnare un collegamento ad esso se si desidera che venga eseguito su qualsiasi cosa tranne il terminale.

Lo script è un po 'più complicato di quello che chiedi perché l'ho scritto per funzionare su configurazioni sia a singolo monitor che a doppio monitor.

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

Puoi farlo usando xdotool.

Per installare xdotoolè possibile eseguire:

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

Quindi per inviare un tasto Ctrl+ Alt+ <keypad_key>alla Xfinestra del terminale è possibile eseguire:

xdotool key Ctrl+Alt+<keypad_key_value>

* <key_key_valore> = valore della chiave della tastiera nell'elenco seguente

Per eseguire un programma GUI e inviare la sequenza di tasti alla sua Xfinestra (che in questo caso è la finestra attiva al momento dell'esecuzione del xdotoolcomando) è possibile eseguire:

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

* <comando> = comando che apre la finestra a cui si desidera inviare la sequenza di tasti; <ritardo> = tempo di attesa in millisecondi prima di inviare la sequenza di tasti; <key_key_valore> = valore della chiave della tastiera nell'elenco seguente

Si noti che nella maggior parte dei casi è necessario eseguire il comando che si sta eseguendo come processo autonomo (ad esempio eseguendo nohup <command> &anziché <command>nell'esempio sopra), altrimenti xdotoolnon verrà eseguito fino al <command>completamento dell'esecuzione.

Inoltre, è necessario impostare un certo ritardo, altrimenti la sequenza di tasti verrà inviata prima che la finestra di destinazione sia completamente caricata X(un ritardo intorno 500msdovrebbe fare).

I valori possibili per <keypad_key_value>sono:

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

Come regola empirica, per scoprire il valore di qualsiasi tasto sulla tastiera all'interno Xdell'ambiente, è possibile eseguire xeve premere il tasto per emettere il suo valore all'interno del terminale.


C'è qualcosa che non va nelle nostre modifiche?
Tim

@Tim No, almeno non la rimozione dell'ultima riga, che concordo sul fatto che è piuttosto inutile, ma ciò che può variare all'interno di un comando è secondo me meglio formattato se racchiuso tra parentesi angolari, che è la notazione standard nella teoria del linguaggio a cui fare riferimento a una categoria sintattica (riferendosi alla tua modifica) e penso che un nome di comando sia meglio formattato se racchiuso in backtick, al fine di essere immediatamente riconosciuto come tale (facendo riferimento alla modifica di AB); notare che non tutto questo è fuori della parte superiore della mia testa, ho avuto dubbi prima e ho chiesto questo su meta
kos

Sì, va bene come lo è ora :) <> è lo standard, e cerco `` intorno a qualsiasi comando :)
Tim

3

Ho creato un'applicazione denominata Worksets (su github ) per Unity che ti consente di farlo facilmente attraverso un'interfaccia utente grafica: è gratuita e open source.

Menu tray

Fondamentalmente è un wrapper per le soluzioni wmctrl e xdotool elencate come risposte qui e fornisce un modo semplice per effettuare e salvare rapidamente tali configurazioni.


1

Non ho il rappresentante per commentare direttamente l'eccellente post di Jacob Vlijm, ma ho modificato lo script per consentire l'avvio di un'applicazione con argomenti (necessario da utilizzare setwindowcon gedit --new-window). Modificare:

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]

0

Ho giocato con la sceneggiatura di Terdon dall'alto e ho aggiunto alcune cose nuove (possibilità di selezionare il monitor e impostare l'altezza per ciascun monitor). Penso che sarebbe estendibile all'aggiunta di più monitor. Speriamo che altri lo trovino utile.

Sintassi di base:

prog_name monitor l/r/m window_name (optional)

Dove prog_name è qualunque cosa tu abbia salvato questo codice; monitor è il numero del monitor, ad es. 1 o 2; l / r / m è sinistra o destra o max; e nome_finestra è il nome (o una frazione del suo nome) della finestra di destinazione.

Per esempio:

setwindow 1 m chrome

Bash script

#!/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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.