Bagaimana saya bisa memulai aplikasi dengan ukuran dan posisi jendela yang telah ditentukan?

22

Saya bertanya-tanya apakah ada cara untuk mencapai pengaruh pintas Ctrl-Alt-Keypad di Unity menggunakan perintah terminal saja? Saya ingin perintah yang menetapkan jendela gui menjadi setengah ukuran layar, baik kiri atau kanan.

Sebagai latar belakang, saya sedang menulis skrip yang berjalan setelah login. Ia menggunakan Zenity untuk menanyakan apakah saya ingin membuka lingkungan pengembangan saya (GVim dan IPython berdampingan). Saya telah mencoba untuk mencapai dua jendela yang sama besar untuk program ini dengan menggunakan set lines= columns=di saya .gvimrcdan c.IPythonWidget.width =dan c.IPythonWidget.height =di saya ipython_qtconsole_config.py. Namun, ada masalah yang terkait dengan pendekatan ini.

STIM
sumber
Saya memperbarui jawaban saya karena itu tidak menjelaskan topik secara cukup detail, Anda mungkin ingin memeriksa pembaruan
kos

Jawaban:

17

Apa yang akan Anda temui

Jika Anda ingin memanggil aplikasi terlebih dahulu dan, kemudian, menempatkan jendelanya pada posisi dan ukuran tertentu, waktu antara memanggil aplikasi dan saat jendela itu benar-benar muncul , tidak dapat diprediksi. Jika sistem Anda terisi, ini bisa jauh lebih lama daripada jika tidak digunakan.

Anda memerlukan cara "pintar" untuk memastikan pemosisian / pengubahan ukuran dilakukan (segera) setelah jendela muncul .

Script untuk memanggil aplikasi, tunggu hingga muncul dan posisikan di layar

Dengan skrip di bawah ini, Anda dapat memanggil aplikasi dan mengatur posisi dan ukurannya akan muncul dengan perintah:

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

Beberapa contoh:

  • Untuk memanggil gnome-terminaldan mengubah ukuran jendelanya menjadi 50% dan menempatkannya di sebelah kanan:

    <script> gnome-terminal 840 0 50 100

    masukkan deskripsi gambar di sini

  • Untuk menelepon gedit, letakkan jendelanya di sebelah kiri dan panggil gnome-terminal, letakkan di sebelah kanan (atur v-size46% untuk memberi sedikit ruang di antara jendela):

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

    masukkan deskripsi gambar di sini

  • Untuk memanggil Inkscape, letakkan jendelanya di bagian kiri / atas layar:

    <script> inkscape 0 0 50 50

    masukkan deskripsi gambar di sini

Script dan cara menggunakannya

  1. instal keduanya xdotooldan wmctrl. Saya menggunakan keduanya karena mengubah ukuran dengan wmctrldapat menyebabkan beberapa kekhasan pada (khusus) Unity.

    sudo apt-get install wmctrl
    sudo apt-get install xdotool
  2. Salin skrip di bawah ini ke file kosong, simpan sebagai setwindow(tanpa ekstensi) di ~/bin; buat direktori jika perlu.
  3. Jadikan skrip dapat dieksekusi (!)
  4. Jika Anda baru saja dibuat ~bin, jalankan:source ~/.profile
  5. Uji-coba skrip dengan perintah (misalnya)

    setwindow gnome-terminal 0 0 50 100

    Dengan kata lain:

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

Jika semua berfungsi dengan baik, gunakan perintah di mana pun Anda membutuhkannya.

Naskah

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

Apa yang dilakukannya

Ketika skrip dipanggil, itu:

  1. memulai aplikasi
  2. mengawasi daftar jendela (menggunakan wmctrl -lp)
  3. jika jendela baru muncul, ia memeriksa apakah jendela baru itu milik aplikasi yang dipanggil (menggunakan ps -ef ww, membandingkan pid jendela dengan pid aplikasi)
  4. jika demikian, itu menentukan ukuran dan posisi, sesuai dengan argumen Anda. Dalam hal aplikasi tidak "muncul" di appr. 15 detik, skrip menganggap aplikasi tidak akan berjalan karena kesalahan. Script kemudian berakhir untuk mencegah menunggu jendela baru tanpa batas.

Masalah kecil

Di Unity, ketika Anda (kembali) memposisikan dan (kembali) ukuran jendela dengan salah satu wmctrlatau xdotool, jendela akan selalu menjaga muatan kecil ke batas layar Anda, kecuali jika Anda mengaturnya ke 100%. Anda dapat melihatnya pada gambar (3) di atas; sementara inkscapejendela ditempatkan pada xposisi 0, Anda masih dapat melihat muatan kecil antara Unity Launcher dan inkscapejendela.

Yakub Vlijm
sumber
Ya Yakub, ini naskah yang fantastis! Satu pertanyaan: Bagaimana saya bisa menemukan dimensi jendela yang terbuka untuk selanjutnya digunakan bersama dengan skrip?
orschiro
Hai @orschiro Saya harus mencalonkan diri untuk rapat ... akan kembali dalam beberapa jam :)
Jacob Vlijm
1
Hi @orschiro, dengan asumsi Anda telah wmctrlterinstal, perintah: wmctrl -lG | grep <windowname>akan menunjukkan output seperti: 0x03600e4f 0 723 197 1114 563 jacob-System-Product-Name dimkeyboard.sh (~/Bureaublad) - gedit. Dalam output ini, kolom ke-3 sampai ke-6 menunjukkan dimensi, x, y, lebar, lebar, tinggi.
Jacob Vlijm
Yakub sangat dihargai! Saya pikir saya melakukan pengaturan dengan benar tetapi jendela masing-masing tidak terbuka di layar penuh sekarang. Ada ide?
orschiro
1
Saya menyukai skrip ini, tetapi saya harus membuat perubahan berikut pada blok pertama untuk membuatnya berfungsi untuk saya, karena saya menambahkan parameter ke aplikasi: 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> menolak untuk memformat kode itu. </edit>
Ron Thompson
3

Perintah aktual yang Anda inginkan adalah sesuatu seperti

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

Itu akan membuat jendela saat ini mengambil setengah layar (ubah $HALFke dimensi layar Anda) dan jepret ke sisi kiri. Untuk mengambil ke kanan, gunakan

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

Anda juga dapat bermain dengan wmctrluntuk mendapatkan ID dari jendela yang Anda sukai daripada menggunakan :ACTIVE:. Saya tidak dapat membantu di sana karena itu tergantung pada windows yang bersangkutan. Lihat man wmctrllebih lanjut.


Saya sudah menulis naskah untuk itu. Saya tidak menggunakan Unity jadi saya tidak bisa menjamin itu akan berhasil, tetapi saya tidak melihat alasan mengapa tidak. Perlu wmctrl, xdpyinfodan disperharus diinstal:

sudo apt-get install wmctrl x11-utils disper

Kemudian, simpan skrip di bawah ini sebagai ~/bin/snap_windows.sh, buat agar dapat dieksekusi chmod a+x ~/bin/snap_windows.shdan Anda dapat menjalankannya

snap_windows.sh r

Untuk mengambil ke sisi kanan. Gunakan luntuk sisi kiri dan tidak ada argumen untuk memaksimalkan jendela. Perhatikan bahwa ini berjalan pada jendela saat ini sehingga Anda harus menetapkan cara pintas untuk itu jika Anda ingin itu berjalan pada apa pun selain terminal.

Script ini sedikit lebih rumit daripada yang Anda minta karena saya telah menulisnya untuk bekerja pada setup tunggal dan dual-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
terdon
sumber
3

Anda dapat melakukan ini dengan menggunakan xdotool.

Untuk menginstal xdotoolAnda dapat menjalankan:

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

Kemudian untuk mengirim Ctrl+ Alt+ <keypad_key>keystroke ke Xjendela terminal Anda dapat menjalankan:

xdotool key Ctrl+Alt+<keypad_key_value>

* <keypad_key_value> = nilai tombol keypad dalam daftar di bawah ini

Untuk menjalankan program GUI dan mengirim keystroke ke Xjendelanya (yang dalam hal ini adalah jendela aktif pada saat xdotoolpelaksanaan perintah) Anda dapat menjalankan:

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

* <command> = perintah yang membuka jendela tempat Anda ingin mengirim keystroke; <delay> = waktu untuk menunggu dalam milidetik sebelum mengirim keystroke; <keypad_key_value> = nilai tombol keypad dalam daftar di bawah ini

Perhatikan bahwa dalam kebanyakan kasus Anda harus menjalankan perintah yang Anda keluarkan sebagai proses yang berdiri sendiri (misalnya dengan menjalankan nohup <command> &alih-alih <command>dalam contoh di atas), jika xdotooltidak, tidak akan dijalankan sampai <command>eksekusi selesai.

Anda juga harus mengatur beberapa penundaan, jika tidak, tombol akan dikirim sebelum jendela target dimuat penuh X(penundaan 500msseharusnya dilakukan).

Nilai yang mungkin untuk <keypad_key_value>adalah:

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

Sebagai aturan praktis, untuk mengetahui nilai tombol apa saja pada keyboard di Xlingkungan, seseorang dapat menjalankan xevdan menekan tombol untuk menampilkan nilainya di dalam terminal.

kos
sumber
Apakah ada yang salah dengan suntingan kami?
Tim
@Tim Tidak, setidaknya bukan penghapusan baris terakhir, yang saya setuju itu cukup tidak berguna, tetapi apa yang dapat bervariasi dalam suatu perintah menurut saya lebih baik diformat jika tertutup dalam kurung sudut, yang merupakan notasi standar dalam teori bahasa untuk merujuk ke kategori sintaksis (merujuk pada hasil edit Anda) dan saya pikir nama perintah itu lebih baik diformat jika disertakan dalam backticks, agar segera dikenali seperti itu (merujuk pada edit AB); perhatikan bahwa tidak semua ini lepas dari kepala saya, saya ragu sebelumnya dan saya menanyakan ini pada meta
kos
Ya, tidak apa-apa seperti sekarang :) <> adalah standar, dan saya mencari `` di sekitar perintah apa pun :)
Tim
3

Saya telah membangun sebuah aplikasi bernama Worksets (on github ) untuk Unity yang memungkinkan Anda melakukan ini dengan mudah melalui antarmuka pengguna grafis - Ini gratis dan open source.

Menu tray

Ini pada dasarnya adalah pembungkus untuk solusi wmctrl dan xdotool yang terdaftar sebagai jawaban di sini, dan menyediakan cara mudah untuk membuat dan menyimpan pengaturan seperti itu dengan cepat.

Keributan
sumber
1

Saya tidak memiliki perwakilan untuk mengomentari secara langsung posting bagus Jacob Vlijm, tetapi saya memodifikasi skrip untuk mengizinkan memulai aplikasi dengan argumen (perlu digunakan setwindowdengan gedit --new-window). Perubahan:

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

untuk:

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

Saya bermain-main dengan skrip Terdon dari atas dan menambahkan beberapa hal baru (kemampuan untuk memilih monitor dan mengatur ketinggian untuk setiap monitor). Saya akan memperpanjang untuk menambahkan lebih banyak monitor. Semoga orang lain akan merasakan manfaatnya.

Sintaks dasar:

prog_name monitor l/r/m window_name (optional)

Di mana prog_name adalah apa pun yang Anda simpan kode ini sebagai; monitor adalah nomor monitor mis. 1 atau 2; l / r / m adalah kiri atau kanan atau maks; dan window_name adalah nama (atau sebagian dari nama itu) dari jendela target.

Misalnya:

setwindow 1 m chrome

Skrip 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
Filsuf Rex
sumber