ฉันจะเริ่มแอปพลิเคชันด้วยขนาดและตำแหน่งของหน้าต่างที่กำหนดไว้ล่วงหน้าได้อย่างไร


22

ฉันสงสัยว่ามีวิธีใดบ้างที่จะบรรลุผลกระทบของปุ่มลัด Ctrl-Alt-Keypad ใน Unity โดยใช้คำสั่งเทอร์มินัลแทน? ฉันต้องการคำสั่งที่ตั้งค่าหน้าต่าง gui ให้มีขนาดครึ่งหนึ่งของหน้าจอไม่ว่าจะชิดซ้ายหรือขวา

โดยพื้นฐานแล้วฉันกำลังเขียนสคริปต์ที่ทำงานหลังจากเข้าสู่ระบบโดยใช้ Zenity เพื่อถามว่าฉันต้องการเปิดสภาพแวดล้อมการพัฒนาของฉันหรือไม่ (GVim และ IPython เคียงข้างกัน) ฉันได้รับการพยายามที่จะบรรลุสองหน้าต่างขนาดเท่ากันสำหรับโปรแกรมเหล่านี้โดยใช้set lines= columns=ในของฉัน.gvimrcและc.IPythonWidget.width =และในของฉันc.IPythonWidget.height = ipython_qtconsole_config.pyอย่างไรก็ตามมีปัญหาที่เกี่ยวข้องกับวิธีนี้


ฉันอัปเดตคำตอบของฉันเพราะมันไม่ได้อธิบายรายละเอียดของหัวข้อมากพอคุณอาจต้องการตรวจสอบการอัปเดต
kos

คำตอบ:


17

สิ่งที่คุณจะเจอ

หากคุณต้องการเรียกแอปพลิเคชั่นก่อนและหลังจากนั้นให้วางหน้าต่างของมันไว้ในตำแหน่งและขนาดที่เฉพาะเจาะจงเวลาระหว่างการเรียกใช้แอปพลิเคชันและช่วงเวลาที่หน้าต่างปรากฏขึ้นจริงไม่สามารถคาดเดาได้ หากระบบของคุณใช้งานได้อาจนานกว่าปกติหากไม่มีการใช้งาน

คุณต้องมีวิธี "สมาร์ท" เพื่อให้แน่ใจว่าการวางตำแหน่ง / ปรับขนาดจะทำ (ทันที) หลังจากที่หน้าต่างปรากฏขึ้น

สคริปต์เพื่อเรียกแอปพลิเคชันรอให้แอปพลิเคชันปรากฏและวางตำแหน่งบนหน้าจอ

ด้วยสคริปต์ด้านล่างคุณสามารถเรียกแอปพลิเคชันและกำหนดตำแหน่งและขนาดที่ควรปรากฏด้วยคำสั่ง:

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

ตัวอย่างบางส่วน:

  • หากต้องการโทรgnome-terminalและปรับขนาดหน้าต่างเป็น 50% และวางครึ่งขวา:

    <script> gnome-terminal 840 0 50 100

    ป้อนคำอธิบายรูปภาพที่นี่

  • หากต้องการโทรgeditให้วางหน้าต่างด้านซ้ายแล้วโทรgnome-terminalวางไว้ทางด้านขวา (ตั้งค่าv-size46% เพื่อให้มีช่องว่างเล็ก ๆ ระหว่างหน้าต่าง):

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

    ป้อนคำอธิบายรูปภาพที่นี่

  • หากต้องการโทร Inkscape ให้วางหน้าต่างไว้ที่ด้านซ้าย / บนของหน้าจอ:

    <script> inkscape 0 0 50 50

    ป้อนคำอธิบายรูปภาพที่นี่

สคริปต์และวิธีการใช้งาน

  1. ติดตั้งทั้งในและxdotool wmctrlผมใช้ทั้งสองตั้งแต่การปรับขนาดที่มีwmctrlสามารถทำให้เกิดลักษณะบางอย่างเกี่ยวกับ Unity(เฉพาะ)

    sudo apt-get install wmctrl
    sudo apt-get install xdotool
  2. คัดลอกสคริปต์ด้านล่างลงในไฟล์ว่างเปล่าบันทึกเป็นsetwindow(ไม่มีส่วนขยาย) ใน~/bin; สร้างไดเรกทอรีถ้าจำเป็น
  3. ทำให้สคริปต์ทำงานได้ (!)
  4. หากคุณเพิ่งสร้างขึ้น~binให้เรียกใช้:source ~/.profile
  5. ทดสอบสคริปต์ด้วยคำสั่ง (เช่น)

    setwindow gnome-terminal 0 0 50 100

    ในคำอื่น ๆ :

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

หากทำงานได้ดีให้ใช้คำสั่งทุกที่ที่คุณต้องการ

บท

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

มันทำอะไร

เมื่อสคริปต์ถูกเรียกมันจะ:

  1. เริ่มแอปพลิเคชัน
  2. คอยดูรายการหน้าต่าง (โดยใช้wmctrl -lp)
  3. หากหน้าต่างใหม่ปรากฏขึ้นจะตรวจสอบว่าหน้าต่างใหม่เป็นของแอปพลิเคชันที่เรียกใช้หรือไม่โดยใช้การps -ef wwเปรียบเทียบ pid ของหน้าต่างกับ pid ของแอปพลิเคชัน
  4. ถ้าเป็นเช่นนั้นมันจะกำหนดขนาดและตำแหน่งตามอาร์กิวเมนต์ของคุณ ในกรณีที่แอปพลิเคชันไม่ "แสดง" ภายใน appr 15 วินาทีสคริปต์จะถือว่าแอปพลิเคชันจะไม่ทำงานเนื่องจากข้อผิดพลาด สคริปต์จะสิ้นสุดลงเพื่อป้องกันการรอหน้าต่างใหม่อย่างไม่สิ้นสุด

ปัญหาเล็กน้อย

ใน Unity เมื่อคุณ (re-) วางตำแหน่งและ (re-) ขนาดของหน้าต่างด้วยwmctrlหรือxdotoolหน้าต่างจะเก็บ marge ขนาดเล็กไว้ที่ขอบของหน้าจอเสมอเว้นแต่คุณจะตั้งไว้ที่ 100% คุณจะเห็นว่าในภาพ (3) ด้านบน; ในขณะที่inkscapeหน้าต่างถูกวางไว้ที่xตำแหน่ง 0 คุณยังสามารถเห็นมาร์จตัวรองระหว่าง Unity Launcher กับinkscapeหน้าต่าง


เรียนเจคอบนี่เป็นสคริปต์ที่ยอดเยี่ยม! คำถามหนึ่ง: ฉันจะหามิติของหน้าต่างเปิดที่จะใช้ร่วมกับสคริปต์ในภายหลังได้อย่างไร
orschiro

สวัสดี @orschiro ฉันต้องใช้สำหรับการประชุม ... จะกลับมาในไม่กี่ชั่วโมง :)
จาค็อบ Vlijm

1
สวัสดี @orschiro สมมติว่าคุณได้wmctrlติดตั้งคำสั่ง: จะแสดงให้คุณส่งออกเช่น:wmctrl -lG | grep <windowname> 0x03600e4f 0 723 197 1114 563 jacob-System-Product-Name dimkeyboard.sh (~/Bureaublad) - geditในผลลัพธ์นี้คอลัมน์ที่ 3 ถึงคอลัมน์ที่ 6 แสดงขนาด, x, y, ความกว้าง, ความกว้าง, ความสูง
Jacob Vlijm

จาค็อบชื่นชมมาก! ฉันคิดว่าฉันตั้งค่าถูกต้องแล้ว แต่หน้าต่างที่เกี่ยวข้องเปิดในแบบเต็มหน้าจอทันที ความคิดใด ๆ
orschiro

1
ฉันรักสคริปต์นี้ แต่ฉันต้องทำการเปลี่ยนแปลงต่อไปนี้ในบล็อกแรกเพื่อให้มันทำงานได้สำหรับฉันเพราะฉันเพิ่มพารามิเตอร์ลงในแอปพลิเคชัน: 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> มันปฏิเสธที่จะจัดรูปแบบรหัสนั้น </edit>
Ron Thompson

3

คำสั่งจริงที่คุณต้องการนั้นเป็นอย่างไร

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

ซึ่งจะทำให้หน้าต่างปัจจุบันใช้เวลาครึ่งหน้าจอ (เปลี่ยน$HALFเป็นขนาดของหน้าจอของคุณ) และเลื่อนไปทางซ้ายมือ ในการจัดชิดขวาให้ใช้

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

นอกจากนี้คุณยังสามารถเล่นกับที่จะได้รับหมายเลขของหน้าต่างที่คุณกำลังสนใจในการแทนการใช้wmctrl :ACTIVE:ฉันไม่สามารถช่วยได้ตั้งแต่นั้นขึ้นอยู่กับหน้าต่างที่เป็นปัญหา ลองดูman wmctrlเพิ่มเติม


ฉันเขียนสคริปต์สำหรับสิ่งนั้น ฉันไม่ได้ใช้ Unity ดังนั้นฉันไม่สามารถรับประกันได้ว่ามันจะทำงานได้ แต่ฉันไม่เห็นเหตุผลว่าทำไม มันต้องwmctrl, xdpyinfoและdisperมีการติดตั้ง:

sudo apt-get install wmctrl x11-utils disper

จากนั้นให้บันทึกสคริปต์ด้านล่างเพื่อ~/bin/snap_windows.shให้chmod a+x ~/bin/snap_windows.shสามารถเรียกใช้และคุณสามารถเรียกใช้ได้

snap_windows.sh r

เพื่อสแน็ปไปทางด้านขวามือ ใช้lสำหรับด้านซ้ายและไม่มีข้อโต้แย้งเพื่อขยายหน้าต่างให้ใหญ่ที่สุด โปรดทราบว่ามันทำงานบนหน้าต่างปัจจุบันดังนั้นคุณจะต้องกำหนดทางลัดให้กับมันหากคุณต้องการให้มันทำงานบนอะไรก็ได้ยกเว้นเทอร์มินัล

สคริปต์ค่อนข้างซับซ้อนกว่าที่คุณขอเพราะฉันเขียนให้ทำงานทั้งในการตั้งค่าหน้าจอเดียวและหน้าจอคู่

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

xdotoolคุณสามารถทำได้โดยใช้

ในการติดตั้งxdotoolคุณสามารถเรียกใช้:

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

จากนั้นจะส่งCtrl+ Alt+ <keypad_key>การกดแป้นพิมพ์ไปยังสถานีXหน้าต่างคุณสามารถเรียกใช้:

xdotool key Ctrl+Alt+<keypad_key_value>

* <keypad_key_value> = ค่าของคีย์แพดในรายการด้านล่าง

ในการรันโปรแกรม GUI และส่งการกดแป้นไปที่Xหน้าต่างของมัน(ซึ่งในกรณีนี้คือหน้าต่างที่ใช้งานในเวลาที่มีxdotoolการเรียกใช้งานคำสั่ง) คุณสามารถเรียกใช้:

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

* คำสั่ง <command> = ที่เปิดหน้าต่างที่คุณต้องการส่งการกดแป้นไปที่; <delay> = เวลารอเป็นมิลลิวินาทีก่อนส่งการกดแป้น <keypad_key_value> = ค่าของคีย์แพดในรายการด้านล่าง

โปรดสังเกตว่าในกรณีส่วนใหญ่คุณจะต้องเรียกใช้คำสั่งที่คุณใช้เป็นกระบวนการแบบสแตนด์อโลน (เช่นโดยการเรียกใช้nohup <command> &แทนที่จะเป็น<command>ในตัวอย่างด้านบน) มิฉะนั้นxdotoolจะไม่ถูกเรียกใช้จนกว่า<command>การดำเนินการจะเสร็จสิ้น

นอกจากนี้คุณจะต้องตั้งค่าการหน่วงเวลาไม่เช่นนั้นการกดแป้นจะถูกส่งก่อนที่จะโหลดหน้าต่างเป้าหมายอย่างสมบูรณ์X(การหน่วงเวลา500msควรทำ)

ค่าที่เป็นไปได้สำหรับ<keypad_key_value>:

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

ตามกฎของหัวแม่มือเพื่อค้นหาค่าของคีย์ใด ๆ บนแป้นพิมพ์ภายในXสภาพแวดล้อมเราสามารถเรียกใช้xevและกดปุ่มเพื่อส่งออกค่าภายในเทอร์มินัล


มีสิ่งผิดปกติเกิดขึ้นกับการแก้ไขของเราหรือไม่
ทิม

@ Tim ไม่อย่างน้อยไม่ลบบรรทัดสุดท้ายซึ่งฉันเห็นว่ามันไม่ได้สวย แต่สิ่งที่สามารถแตกต่างกันภายในคำสั่งอยู่ในความคิดของฉันจัดรูปแบบดีกว่าถ้าล้อมรอบในวงเล็บเหลี่ยมซึ่งเป็นสัญลักษณ์มาตรฐานในทฤษฎีภาษาเพื่ออ้างถึง หมวดหมู่วากยสัมพันธ์ (หมายถึงการแก้ไขของคุณ) และฉันคิดว่าชื่อคำสั่งมันมีรูปแบบที่ดีกว่าถ้าอยู่ใน backticks เพื่อที่จะได้รับการยอมรับในทันทีเช่นนี้ (หมายถึงการแก้ไขของ AB); สังเกตว่าไม่ทั้งหมดนี้อยู่ด้านบนของหัวของฉันฉันมีข้อสงสัยมาก่อนและฉันถามสิ่งนี้ใน meta
kos

ใช่มันเป็นเรื่องปกติที่เป็นอยู่ในขณะนี้ :) <> เป็นมาตรฐานและฉันไปสำหรับ `` รอบคำสั่งใด ๆ :)
ทิม

3

ฉันได้สร้างแอพพลิเคชั่นชื่อ Worksets (บนgithub ) สำหรับ Unity ที่ให้คุณทำสิ่งนี้ได้อย่างง่ายดายผ่านทางส่วนต่อประสานกราฟิกผู้ใช้ - มันฟรีและโอเพ่นซอร์ส

เมนู tTray

โดยพื้นฐานแล้วมันเป็น wrapper สำหรับโซลูชัน wmctrl และ xdotool ที่ระบุว่าเป็นคำตอบที่นี่และเป็นวิธีที่ง่ายในการสร้างและบันทึกการตั้งค่าดังกล่าวได้อย่างรวดเร็ว


1

ฉันไม่มีตัวแทนที่จะแสดงความคิดเห็นโดยตรงกับโพสต์ที่ยอดเยี่ยมของ Jacob Vlijm แต่ฉันแก้ไขสคริปต์เพื่ออนุญาตให้เริ่มต้นแอปพลิเคชันที่มีข้อโต้แย้ง (จำเป็นต้องใช้setwindowกับgedit --new-window) เปลี่ยนแปลง:

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

ไปที่:

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

0

ฉันเล่นกับสคริปต์ของ Terdonจากด้านบนและเพิ่มสิ่งใหม่ ๆ (ความสามารถในการเลือกจอภาพและตั้งค่าความสูงสำหรับแต่ละจอภาพ) มันจะขยายได้เมื่อเพิ่มจอภาพที่ฉันคิด หวังว่าคนอื่นจะพบว่ามีประโยชน์

ไวยากรณ์พื้นฐาน:

prog_name monitor l/r/m window_name (optional)

ที่ prog_name เป็นสิ่งที่คุณบันทึกรหัสนี้เป็น; monitor คือหมายเลขมอนิเตอร์เช่น 1 หรือ 2; l / r / m ถูกซ้ายหรือขวาหรือสูงสุด; และ window_name คือชื่อ (หรือส่วนของชื่อ) ของหน้าต่างเป้าหมาย

เช่น:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.