Wie kann ich eine Anwendung mit einer vordefinierten Fenstergröße und -position starten?

22

Ich frage mich, ob es eine Möglichkeit gibt, die Auswirkungen der Tastenkombinationen für Strg-Alt-Tasten in Unity mithilfe von Terminalbefehlen zu erzielen. Ich möchte einen Befehl, der ein GUI-Fenster auf die Hälfte der Bildschirmgröße einstellt, entweder links oder rechts ausgerichtet.

Als Hintergrund schreibe ich ein Skript, das nach dem Anmelden ausgeführt wird. Mit Zenity wird gefragt, ob ich meine Entwicklungsumgebung (GVim und IPython nebeneinander) öffnen möchte oder nicht. Ich habe versucht, zwei gleich große Fenster für diese Programme zu erzielen, indem set lines= columns=ich in meinem .gvimrcund c.IPythonWidget.width =und c.IPythonWidget.height =in meinem ipython_qtconsole_config.py. Mit diesem Ansatz sind jedoch Probleme verbunden.

STim
quelle
Ich habe meine Antwort aktualisiert, weil das Thema nicht ausführlich genug erklärt wurde. Vielleicht möchten Sie das Update überprüfen
kos

Antworten:

17

Worauf du stoßen wirst

Wenn Sie eine Anwendung zum ersten Mal aufrufen und ihr Fenster anschließend an einer bestimmten Position und Größe platzieren möchten, ist die Zeit zwischen dem Aufrufen der Anwendung und dem tatsächlichen Erscheinen des Fensters nicht vorhersehbar. Wenn Ihr System belegt ist, kann es erheblich länger dauern als im Leerlauf.

Sie benötigen eine "intelligente" Methode, um sicherzustellen, dass die Positionierung / Größenänderung (unmittelbar) nach dem Erscheinen des Fensters erfolgt .

Skript zum Aufrufen einer Anwendung, warten Sie, bis sie angezeigt wird, und positionieren Sie sie auf dem Bildschirm

Mit dem folgenden Skript können Sie eine Anwendung aufrufen und die Position und Größe festlegen, auf der sie mit dem Befehl angezeigt werden soll:

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

Einige Beispiele:

  • So rufen Sie gnome-terminaldas Fenster auf, ändern die Größe auf 50% und platzieren es auf der rechten Hälfte:

    <script> gnome-terminal 840 0 50 100

    Bildbeschreibung hier eingeben

  • Um anzurufen gedit, platzieren Sie das Fenster auf der linken Seite und rufen gnome-terminalSie an, platzieren Sie es auf der rechten Seite (stellen Sie die v-size46% ein, um etwas Platz zwischen den Fenstern zu schaffen):

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

    Bildbeschreibung hier eingeben

  • Um Inkscape aufzurufen, platzieren Sie das zugehörige Fenster im linken / oberen Viertel des Bildschirms:

    <script> inkscape 0 0 50 50

    Bildbeschreibung hier eingeben

Das Skript und wie man es benutzt

  1. Installieren Sie beide xdotoolund wmctrl. Ich habe beides verwendet, da das Ändern der Größe mit wmctrl(speziell) einige Besonderheiten verursachen kann Unity.

    sudo apt-get install wmctrl
    sudo apt-get install xdotool
  2. Kopieren Sie das folgende Skript in eine leere Datei und speichern Sie es unter setwindow(ohne Erweiterung) in ~/bin. Erstellen Sie ggf. das Verzeichnis.
  3. Mach das Skript ausführbar (!)
  4. Wenn Sie gerade erstellt haben ~bin, führen Sie Folgendes aus:source ~/.profile
  5. Teste das Skript mit dem Befehl (zB)

    setwindow gnome-terminal 0 0 50 100

    Mit anderen Worten:

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

Wenn alles funktioniert, verwenden Sie den Befehl, wo immer Sie ihn benötigen.

Das Drehbuch

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

Was es macht

Wenn das Skript aufgerufen wird, geschieht Folgendes:

  1. Startet die Anwendung
  2. behält die Fensterliste im Auge (mit wmctrl -lp)
  3. Wenn ein neues Fenster angezeigt wird, wird überprüft, ob das neue Fenster zur aufgerufenen Anwendung gehört ( ps -ef wwindem die PID des Fensters mit der PID der Anwendung verglichen wird).
  4. In diesem Fall werden Größe und Position entsprechend Ihren Argumenten festgelegt. Falls eine Anwendung nicht innerhalb von ca. Nach 15 Sekunden geht das Skript davon aus, dass die Anwendung aufgrund eines Fehlers nicht ausgeführt wird. Das Skript wird dann beendet, um ein unbegrenztes Warten auf das neue Fenster zu verhindern.

Geringes Problem

Wenn Sie in Unity ein Fenster mit wmctrloder (neu) positionieren und (in der Größe neu) xdotoolanpassen, bleibt der Rand des Fensters immer klein, es sei denn, Sie setzen ihn auf 100%. Sie können das im Bild (3) oben sehen; Während das inkscapeFenster auf xPosition 0 gestellt wurde, sehen Sie immer noch einen kleinen Abstand zwischen dem Unity Launcher und dem inkscapeFenster.

Jacob Vlijm
quelle
Lieber Jacob, das ist ein fantastisches Drehbuch! Eine Frage: Wie finde ich die Dimension eines geöffneten Fensters, das später zusammen mit dem Skript verwendet werden soll?
Orschiro
Hallo @orschiro Ich muss für ein Treffen laufen ... werde in ein paar Stunden zurück sein :)
Jacob Vlijm
1
Hallo @orschiro, vorausgesetzt , Sie haben wmctrlinstalliert, wird der Befehl: wmctrl -lG | grep <windowname>wird Ihnen eine Ausgabe wie: 0x03600e4f 0 723 197 1114 563 jacob-System-Product-Name dimkeyboard.sh (~/Bureaublad) - gedit. In dieser Ausgabe werden in der 3. bis 6. Spalte die Abmessungen x, y, Breite, Breite und Höhe angezeigt.
Jacob Vlijm
Sehr geschätzter Jacob! Ich glaube, ich habe das Setup richtig gemacht, aber das entsprechende Fenster wird jetzt im Vollbildmodus geöffnet. Irgendwelche Ideen?
Orschiro
1
Ich mochte dieses Skript, musste aber die folgenden Änderungen am ersten Block vornehmen, damit es für mich funktioniert, da ich der Anwendung Parameter hinzugefügt habe: 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> Es lehnt ab , diesen Code zu formatieren. </ Edit>
Ron Thompson
3

Der eigentliche Befehl, den Sie wollen, ist so etwas wie

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

Dadurch nimmt das aktuelle Fenster die Hälfte des Bildschirms ein (ändern Sie $HALFdie Abmessungen Ihres Bildschirms) und rastet auf der linken Seite ein. Zum Einrasten nach rechts verwenden Sie

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

Sie können auch damit spielen wmctrl, um die ID der Fenster zu ermitteln, an denen Sie interessiert sind, anstatt sie zu verwenden :ACTIVE:. Ich kann da allerdings nicht helfen, da das von den jeweiligen Fenstern abhängt. Schauen Sie sich man wmctrlnach mehr um.


Ich habe ein Skript dafür geschrieben. Ich verwende Unity nicht und kann daher nicht garantieren, dass es damit funktioniert, aber ich sehe keinen Grund, warum nicht. Es muss wmctrl, xdpyinfound disperinstalliert werden:

sudo apt-get install wmctrl x11-utils disper

Speichern Sie dann das unten stehende Skript als ~/bin/snap_windows.sh, machen Sie es mit ausführbar chmod a+x ~/bin/snap_windows.shund Sie können es ausführen

snap_windows.sh r

Rechts einrasten. Verwendenl für die linke Seite keine Argumente, um das Fenster zu maximieren. Beachten Sie, dass es im aktuellen Fenster ausgeführt wird, sodass Sie ihm eine Verknüpfung zuweisen müssen, wenn es auf einem anderen Computer als dem Terminal ausgeführt werden soll.

Das Skript ist etwas komplizierter als gewünscht, da ich es sowohl für Einzel- als auch für Doppelmonitor-Setups geschrieben habe.

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

Sie können dies mit tun xdotool.

Zum Installieren können xdotoolSie Folgendes ausführen:

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

Um dann einen Ctrl+ Alt+ <keypad_key>Tastendruck an das Terminalfenster zu senden X, können Sie Folgendes ausführen:

xdotool key Ctrl+Alt+<keypad_key_value>

* <Tastatur_Tastenwert> = Wert der Tastaturtaste in der folgenden Liste

Um ein GUI-Programm auszuführen und den Tastendruck an sein XFenster zu senden (das in diesem Fall zum Zeitpunkt der xdotoolBefehlsausführung das aktive Fenster ist ), können Sie Folgendes ausführen:

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

* <Befehl> = Befehl, der das Fenster öffnet, an das Sie den Tastendruck senden möchten; <delay> = Wartezeit in Millisekunden vor dem Senden des Tastenanschlags; <keypad_key_value> = Wert der Tastaturtaste in der Liste unten

Beachten Sie, dass Sie den Befehl, den Sie ausgeben, in den meisten Fällen als eigenständigen Prozess ausführen müssen (z. B. indem Sie ihn nohup <command> &anstelle des <command>obigen Beispiels xdotoolausführen ). Anderenfalls wird er erst ausgeführt, wenn <command>die Ausführung abgeschlossen ist.

Außerdem müssen Sie eine Verzögerung einstellen, da andernfalls der Tastenanschlag gesendet wird, bevor das Zielfenster vollständig geladen ist X(eine Verzögerung 500mssollte dies tun).

Mögliche Werte für <keypad_key_value>sind:

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

Um den Wert einer beliebigen Taste auf der Tastatur innerhalb der XUmgebung herauszufinden, kann man als Faustregel xevdie Taste ausführen und drücken, um ihren Wert im Terminal auszugeben.

kos
quelle
Stimmt etwas mit unseren Änderungen nicht?
Tim
@Tim Nein, zumindest nicht das Entfernen der letzten Zeile, was meiner Meinung nach ziemlich unnütz ist, aber was innerhalb eines Befehls variieren kann, ist meiner Meinung nach besser formatiert, wenn es in spitze Klammern eingeschlossen ist, was die Standardnotation in der Sprachtheorie ist auf eine syntaktische Kategorie (in Bezug auf Ihre Bearbeitung) und ich denke, dass ein Befehlsname besser formatiert ist, wenn er in Backticks eingeschlossen ist, um sofort als solcher erkannt zu werden (in Bezug auf die Bearbeitung von AB); bemerken Sie, dass nicht alles von der Spitze meines Kopfes ist, ich hatte vorher Zweifel und ich fragte dies auf meta
kos
Ja, es ist in Ordnung, so wie es jetzt ist :) <> ist der Standard, und ich gehe um jeden Befehl herum :)
Tim
3

Ich habe eine Anwendung namens Worksets (auf Github ) für Unity erstellt, mit der Sie dies auf einfache Weise über eine grafische Benutzeroberfläche tun können - Es ist kostenlos und Open Source.

tTablettmenü

Es ist im Grunde ein Wrapper für die hier als Antworten aufgeführten Lösungen wmctrl und xdotool und bietet eine einfache Möglichkeit, solche Einstellungen schnell vorzunehmen und zu speichern.

Tumult
quelle
1

Ich habe nicht die rep kommentieren direkt auf Jacob Vlijm ausgezeichneten Beitrag, aber ich modifizierte , um das Skript eine Anwendung mit Argumenten zu ermöglichen , beginnen (erforderlich verwenden setwindowmit gedit --new-window). Veränderung:

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

zu:

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

Ich habe mit Terdons Skript von oben herumgespielt und einige neue Dinge hinzugefügt (die Möglichkeit, den Monitor auszuwählen und die Höhe für jeden Monitor festzulegen ). Es wäre erweiterbar, um mehr Monitore hinzuzufügen, denke ich. Hoffentlich finden es andere nützlich.

Grundlegende Syntax:

prog_name monitor l/r/m window_name (optional)

Wo prog_name ist, als was auch immer Sie diesen Code gespeichert haben; monitor ist die Monitornummer, z. B. 1 oder 2; l / r / m ist links oder rechts oder max; und Fenstername ist der Name (oder ein Bruchteil seines Namens) des Zielfensters.

Z.B:

setwindow 1 m chrome

Bash-Skript

#!/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
Philosoph Rex
quelle