Làm cách nào tôi có thể khởi động một ứng dụng với kích thước và vị trí cửa sổ được xác định trước?


22

Tôi tự hỏi có cách nào để đạt được ảnh hưởng của các phím tắt Ctrl-Alt-Keypad trong Unity bằng cách sử dụng các lệnh đầu cuối không? Tôi muốn một lệnh đặt cửa sổ gui bằng một nửa kích thước của màn hình, được căn trái hoặc phải.

Nhân tiện, tôi đang viết một tập lệnh chạy sau khi đăng nhập. Nó sử dụng Zenity để hỏi liệu tôi có muốn mở môi trường phát triển của mình hay không (GVim và IPython cạnh nhau). Tôi đã cố gắng để đạt được hai cửa sổ có kích thước bằng nhau cho các chương trình này bằng cách sử dụng set lines= columns=trong .gvimrcc.IPythonWidget.width =c.IPythonWidget.height =của tôi ipython_qtconsole_config.py. Tuy nhiên, có những vấn đề liên quan đến phương pháp này.


Tôi đã cập nhật câu trả lời của mình vì nó không giải thích chi tiết về chủ đề này, bạn có thể muốn kiểm tra cập nhật
kos

Câu trả lời:


17

Những gì bạn sẽ chạy vào

Nếu trước tiên bạn muốn gọi một ứng dụng và sau đó, đặt cửa sổ của nó vào một vị trí và kích thước cụ thể, thời gian giữa khi gọi ứng dụngthời điểm cửa sổ thực sự xuất hiện , là không thể đoán trước. Nếu hệ thống của bạn bị chiếm đóng, nó có thể dài hơn đáng kể so với khi nó không hoạt động.

Bạn cần một cách "thông minh" để đảm bảo việc định vị / thay đổi kích thước được thực hiện (ngay lập tức) sau khi cửa sổ xuất hiện .

Script để gọi một ứng dụng, đợi cho nó xuất hiện và định vị nó trên màn hình

Với đoạn script bên dưới, bạn có thể gọi một ứng dụng và đặt vị trí và kích thước nó sẽ xuất hiện bằng lệnh:

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

Một vài ví dụ:

  • Để gọi gnome-terminalvà thay đổi kích thước cửa sổ của nó thành 50% và đặt nó ở nửa bên phải:

    <script> gnome-terminal 840 0 50 100

    nhập mô tả hình ảnh ở đây

  • Để gọi gedit, đặt cửa sổ bên trái gọi gnome-terminal, đặt bên phải (đặt v-size46% để tạo cho nó một khoảng trống nhỏ giữa các cửa sổ):

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

    nhập mô tả hình ảnh ở đây

  • Để gọi Inkscape, đặt cửa sổ của nó ở phần bên trái / trên của màn hình:

    <script> inkscape 0 0 50 50

    nhập mô tả hình ảnh ở đây

Kịch bản và cách sử dụng nó

  1. cài đặt cả hai xdotoolwmctrl. Tôi đã sử dụng cả hai kể từ khi thay đổi kích thước với wmctrlcó thể gây ra một số đặc thù trên (cụ thể) Unity.

    sudo apt-get install wmctrl
    sudo apt-get install xdotool
  2. Sao chép tập lệnh bên dưới vào một tệp trống, lưu nó dưới dạng setwindow(không có phần mở rộng) trong ~/bin; tạo thư mục nếu cần thiết
  3. Làm cho tập lệnh thực thi (!)
  4. Nếu bạn vừa tạo ~bin, hãy chạy:source ~/.profile
  5. Chạy thử tập lệnh bằng lệnh (vd)

    setwindow gnome-terminal 0 0 50 100

    Nói cách khác:

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

Nếu tất cả đều hoạt động tốt, sử dụng lệnh bất cứ nơi nào bạn cần.

Kịch bản

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

Những gì nó làm

Khi tập lệnh được gọi, nó:

  1. khởi động ứng dụng
  2. giữ một mắt trên danh sách cửa sổ (sử dụng wmctrl -lp)
  3. nếu một cửa sổ mới xuất hiện, nó sẽ kiểm tra xem cửa sổ mới có thuộc về ứng dụng được gọi hay không (sử dụng ps -ef ww, so sánh pid của cửa sổ với pid của ứng dụng)
  4. nếu vậy, nó đặt kích thước và vị trí, theo các đối số của bạn. Trong trường hợp một ứng dụng không "hiển thị" trong appr. 15 giây, tập lệnh giả định ứng dụng sẽ không chạy do lỗi. Tập lệnh sau đó chấm dứt để chờ đợi cửa sổ mới vô hạn.

Vấn đề nhỏ

Trong Unity, khi bạn (tái) vị trí và (kích thước lại) một cửa sổ bằng một wmctrlhoặc xdotool, cửa sổ sẽ luôn giữ một sà lan nhỏ ở viền màn hình của bạn, trừ khi bạn đặt nó thành 100%. Bạn có thể thấy rằng trong hình (3) ở trên; trong khi inkscapecửa sổ được đặt ở xvị trí 0, bạn vẫn có thể thấy một sà lan nhỏ giữa Unity Launcher và inkscapecửa sổ.


Jacob thân mến, đây là một kịch bản tuyệt vời! Một câu hỏi: Làm thế nào tôi có thể tìm thấy kích thước của một cửa sổ mở để sau đó được sử dụng cùng với tập lệnh?
orschiro

Xin chào @orschiro Tôi phải chạy cho một cuộc họp ... sẽ trở lại sau vài giờ nữa :)
Jacob Vlijm

1
Xin chào @orschiro, giả sử bạn đã wmctrlcài đặt, lệnh: wmctrl -lG | grep <windowname>sẽ hiển thị cho bạn một đầu ra như : 0x03600e4f 0 723 197 1114 563 jacob-System-Product-Name dimkeyboard.sh (~/Bureaublad) - gedit. Trong đầu ra này, cột thứ 3 đến thứ 6 hiển thị kích thước, x, y, chiều rộng, chiều rộng, chiều cao.
Jacob Vlijm

Jacob rất cảm kích! Tôi nghĩ rằng tôi đã thiết lập đúng nhưng cửa sổ tương ứng hiện đang mở ở chế độ toàn màn hình. Có ý kiến ​​gì không?
orschiro

1
Tôi yêu thích tập lệnh này, nhưng tôi phải thực hiện các thay đổi sau cho khối đầu tiên để làm cho nó hoạt động, vì tôi đã thêm tham số cho ứng dụng: 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> nó từ chối định dạng mã đó. </ Edit>
Ron Thompson

3

Lệnh thực tế bạn muốn là một cái gì đó như

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

Điều đó sẽ làm cho cửa sổ hiện tại chiếm một nửa màn hình (thay đổi $HALFkích thước màn hình của bạn) và chụp sang phía bên trái. Để chụp sang phải, sử dụng

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

Bạn cũng có thể chơi với wmctrlđể lấy ID của các cửa sổ mà bạn quan tâm thay vì sử dụng :ACTIVE:. Tôi không thể giúp đỡ mặc dù điều đó phụ thuộc vào các cửa sổ được đề cập. Có một cái nhìn man wmctrlđể biết thêm.


Tôi đã viết một kịch bản cho điều đó. Tôi không sử dụng Unity vì vậy tôi không thể đảm bảo rằng nó sẽ hoạt động với nó, nhưng tôi thấy không có lý do tại sao không. Nó cần wmctrl, xdpyinfodisperphải được cài đặt:

sudo apt-get install wmctrl x11-utils disper

Sau đó, lưu tập lệnh bên dưới dưới dạng ~/bin/snap_windows.sh, làm cho nó có thể thực thi được chmod a+x ~/bin/snap_windows.shvà bạn có thể chạy

snap_windows.sh r

Để chụp sang phía bên tay phải. Sử dụng lcho phía bên trái và không có đối số để tối đa hóa cửa sổ. Lưu ý rằng nó chạy trên cửa sổ hiện tại, vì vậy bạn sẽ cần gán một phím tắt cho nó nếu bạn muốn nó chạy trên bất cứ thứ gì trừ thiết bị đầu cuối.

Kịch bản phức tạp hơn một chút so với những gì bạn yêu cầu vì tôi đã viết nó để hoạt động trên cả thiết lập màn hình đơn và màn hình kép.

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

Bạn có thể làm điều này bằng cách sử dụng xdotool.

Để cài đặt, xdotoolbạn có thể chạy:

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

Sau đó, để gửi một Ctrl+ Alt+ <keypad_key>tổ hợp phím cho thiết bị đầu cuối Xcửa sổ bạn có thể chạy:

xdotool key Ctrl+Alt+<keypad_key_value>

* <keyboard_key_value> = giá trị của bàn phím trong danh sách bên dưới

Để chạy chương trình GUI và gửi tổ hợp phím đến Xcửa sổ của nó (trong trường hợp này là cửa sổ hoạt động tại thời điểm xdotoolthực thi lệnh), bạn có thể chạy:

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

* <lệnh> = lệnh mở cửa sổ bạn muốn gửi tổ hợp phím đến; <delay> = thời gian chờ tính bằng mili giây trước khi gửi tổ hợp phím; <keyboard_key_value> = giá trị của bàn phím trong danh sách bên dưới

Lưu ý rằng trong hầu hết các trường hợp, bạn sẽ cần chạy lệnh bạn đang phát hành dưới dạng một quy trình độc lập (ví dụ: bằng cách chạy nohup <command> &thay vì <command>trong ví dụ trên), nếu không xdotoolsẽ không được chạy cho đến khi quá trình <command>thực thi hoàn tất.

Ngoài ra, bạn sẽ cần đặt một số độ trễ, nếu không, tổ hợp phím sẽ được gửi trước khi cửa sổ đích được tải đầy đủ X(nên trì hoãn xung quanh 500ms).

Các giá trị có thể <keypad_key_value>là:

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

Theo quy tắc ngón tay cái, để tìm ra giá trị của bất kỳ phím nào trên bàn phím trong Xmôi trường, người ta có thể chạy xevvà nhấn phím để xuất giá trị của nó bên trong thiết bị đầu cuối.


Có điều gì đó sai với chỉnh sửa của chúng tôi?
Tim

@Tim Không, ít nhất không phải là loại bỏ dòng cuối cùng, mà tôi đồng ý rằng nó khá khó tin, nhưng theo tôi, điều gì có thể thay đổi trong một lệnh được định dạng tốt hơn nếu được đặt trong dấu ngoặc nhọn, đó là ký hiệu chuẩn trong lý thuyết ngôn ngữ đến một danh mục cú pháp (tham khảo chỉnh sửa của bạn) và tôi nghĩ rằng một tên lệnh sẽ được định dạng tốt hơn nếu được đặt trong backticks, để được nhận ra ngay lập tức như vậy (tham khảo chỉnh sửa của AB); lưu ý rằng không phải tất cả những thứ này nằm ngoài đỉnh đầu của tôi, tôi đã nghi ngờ trước đây và tôi đã hỏi điều này trên meta
kos

Vâng, nó vẫn ổn như bây giờ :) <> là tiêu chuẩn, và tôi đi tìm `` xung quanh bất kỳ lệnh nào :)
Tim

3

Tôi đã xây dựng một ứng dụng có tên Worksets (trên github ) cho Unity cho phép bạn thực hiện điều này một cách dễ dàng thông qua giao diện người dùng đồ họa - Đó là nguồn mở và miễn phí.

menu tTray

Về cơ bản, nó là một trình bao bọc cho các giải pháp wmctrl và xdotool được liệt kê dưới dạng câu trả lời ở đây và cung cấp một cách dễ dàng để nhanh chóng thực hiện và lưu các thiết lập như vậy.


1

Tôi không có đại diện để bình luận trực tiếp về bài viết xuất sắc của Jacob Vlijm, nhưng tôi đã sửa đổi tập lệnh để cho phép bắt đầu một ứng dụng với các đối số (cần thiết để sử dụng setwindowvới gedit --new-window). Thay đổi:

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

đến:

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

0

Tôi đã chơi xung quanh với kịch bản của Terdon từ trên cao và thêm một số điều mới (khả năng chọn màn hình và đặt chiều cao cho mỗi màn hình). Tôi nghĩ nó có thể được mở rộng để thêm nhiều màn hình hơn. Hy vọng những người khác sẽ tìm thấy nó hữu ích.

Cú pháp cơ bản:

prog_name monitor l/r/m window_name (optional)

Trường hợp prog_name là bất cứ điều gì bạn đã lưu mã này như; màn hình là số màn hình, ví dụ 1 hoặc 2; l / r / m là trái hoặc phải hoặc tối đa; và window_name là tên (hoặc một phần tên của nó) của cửa sổ đích.

Ví dụ:

setwindow 1 m chrome

Kịch bả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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.