Có tập lệnh (hoặc phần mềm) để mở cửa sổ ứng dụng trên chế độ xem và vị trí cụ thể không?


8

Vì vậy, tôi có 8 Máy tính để bàn ảo trong Unity (với Compiz) vì tôi có nhiều dự án tôi đang làm cùng một lúc.

Vấn đề là, mỗi khi tôi cần khởi động lại hoặc vô tình đóng Chrome (tạo thành một phần lớn các cửa sổ tôi cần cho công việc) Tôi phải tự mở lại các cửa sổ đó và sau đó thiết lập chúng (mở tệp, đi đến đúng url, v.v.).

Làm thế nào bạn sẽ đi về việc viết một kịch bản sẽ làm tất cả điều đó cho tôi? Đó là: 1) Mở các cửa sổ 2) Đặt chúng vào tọa độ chính xác tại các màn hình ảo chính xác

(1) là hiển nhiên, đối với Google Chrome, bạn chỉ cần chạy 'google-chrome'. Nhưng sau đó, làm thế nào để bạn đặt nó ở đúng nơi? (2)

Hoặc có một kịch bản / phần mềm đã tồn tại sẽ làm điều đó cho tôi?


Tôi có thể cố gắng tạo ra một kịch bản để đặt bất kỳ cửa sổ nào bạn có thể cần trên máy tính để bàn phù hợp khi khởi động, có thể tôi sẽ mất vài ngày, vì tôi sẽ có trận chung kết vào tuần tới. Nó sẽ liên quan wmctrl, giống như một phần mềm để điều khiển các cửa sổ thông qua tập lệnh hoặc thiết bị đầu cuối. Nhưng đối với việc khởi động lại một cửa sổ, đó có thể là một thử thách lớn hơn một chút
Sergiy Kolodyazhnyy

Mặc dù bạn đã hỏi cụ thể về Unity, nhưng đáng chú ý là KDE có một chương trình (hầu hết không có giấy tờ) được gọi là kstart thực hiện điều này cho bạn. Nó hoạt động tốt nhất với các chương trình KDE, nhưng cũng có một số thành công với các chương trình khác.
Joe

Câu trả lời:


14

Nó có thể được thực hiện rất tốt, nhưng bạn cần một số hiểu biết về Unity / viewports. Tôi hy vọng câu chuyện dưới đây là dễ hiểu, nếu không, xin vui lòng để lại nhận xét.

Các kịch bản dưới đây có thể được sử dụng để mở một cửa sổ của bất kỳ ứng dụng trên bất kỳ khung nhìn của bạn, vào vị trí bất kỳ, nếu bạn chạy nó với các đối số đúng. Kịch bản là một phiên bản chỉnh sửa của cái này , nhưng bây giờ đã chuẩn bị để đặt các cửa sổ trên màn hình ảo kéo dài .

1. Hiểu về khung nhìn và tọa độ cửa sổ

Không gian làm việc trong Unity

Trong Unity, không giống như các trình quản lý cửa sổ khác, bạn thực sự chỉ có một không gian làm việc kéo dài, được chia thành các khung nhìn. Trong trường hợp của bạn, không gian làm việc của bạn được chia thành tám khung nhìn.

Vị trí của các cửa sổ được xác định như thế nào

Vị trí cửa sổ, là đầu ra của lệnh:

wmctrl -lG
(you need to have wmctrl installed to run the command)

được mô tả là vị trí, liên quan đến góc trên bên trái của chế độ xem hiện tại :


Vì vậy, nếu bạn đang ở chế độ xem 1:
một cửa sổ trên chế độ xem 2 có thể được định vị trên ví dụ: 1700 (x-khôn) x 500 (y-khôn)
(màn hình của tôi là 1680x1050)

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


Tuy nhiên, nếu bạn ở chế độ xem 6:
cùng một cửa sổ sẽ được định vị trên 20 (x), -550 (y) nhập mô tả hình ảnh ở đây


Sử dụng các tọa độ này một cách chính xác là rất quan trọng để chạy tập lệnh với các đối số phù hợp, như được mô tả dưới đây:

2. Cách sử dụng tập lệnh

Kịch bản dưới đây có thể được sử dụng để đặt một cửa sổ mới của ứng dụng trên không gian làm việc (kéo dài) ảo của bạn.

  1. Đảm bảo đã wmctrlđược cài đặt:

    sudo apt-get install wmctrl
    
  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 nó chưa tồn tại. Làm cho kịch bản thực thi .

  3. Nếu bạn vừa tạo ~/bin, hãy chạy lệnh source ~/.profilehoặc đăng xuất / đăng nhập để làm cho thư mục có sẵn $PATH.
  4. Chạy thử lệnh:

    setwindow <application> <x_position> <y_position> <horizontal_size> <vertical_size>
    

    ví dụ

    setwindow gedit 100 100 200 200
    

    Một cửa sổ gedit sẽ hiển thị trên khung nhìn hiện tại.

Ghi chú:

  • Hãy nhớ rằng không phải tất cả các ứng dụng đều cho phép kích thước cửa sổ dưới một chiều rộng hoặc chiều cao nhất định. Chiều rộng tối thiểu của một geditcửa sổ trên hệ thống của tôi là ví dụ như appr. 470 px.
  • Kịch bản chỉ hoạt động tốt nếu toàn bộ cửa sổ vừa với khung nhìn được nhắm mục tiêu, chọn tọa độ / kích thước của bạn cho phù hợp. Cũng lưu ý rằng Unity Launcher và bảng điều khiển sử dụng một số khoảng trắng (!) Có thể ảnh hưởng đến vị trí của cửa sổ.
  • Sử dụng phủ định <x_position>để đặt các cửa sổ ở bên trái của (các) chế độ xem hiện tại
  • Sử dụng phủ định <y_position>để đặt các cửa sổ phía trên (các) chế độ xem hiện tại
  • Để mở các cửa sổ mới trên các chế độ xem khác nhau cùng một lúc, bạn có thể chỉ cần xâu chuỗi các lệnh. Nhìn vào thiết lập chế độ xem trong ví dụ "Câu chuyện dài", Nếu tôi ở chế độ xem 1, tôi có thể mở các cửa sổ gedit trên chế độ xem 1, 2, 3 và 4 bằng lệnh:

    setwindow gedit 100 100 200 200&&setwindow gedit 1780 100 200 200&&setwindow gedit 3460 100 200 200&&setwindow gedit 5140 100 200 200
    

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])
# fix exception for Chrome (command = google-chrome-stable, but processname = chrome)
app = "chrome" if "chrome" in app else 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 = "wmctrl -ir "+procs[0][0][1]+" -e 0,"+sys.argv[2]+","+sys.argv[3]+","+sys.argv[4]+","+sys.argv[5]
        for cmd in [cmd1, cmd2, cmd3]:   
            subprocess.call(["/bin/bash", "-c", cmd])
        break
    time.sleep(0.5)
    t = t+1



EDIT: phiên bản lười biếng

Trong trường hợp bạn chỉ muốn nhập tọa độ và kích thước, đơn giản như thể bạn sẽ mở một cửa sổ trên chế độ xem hiện tại và đưa ra chế độ xem được nhắm mục tiêu làm đối số (không phải tính toán bất cứ điều gì), sau đó sử dụng phiên bản bên dưới ...

Nếu bạn thiết lập nó giống như phiên bản đầu tiên của tập lệnh, bạn có thể chạy nó bằng lệnh:

setwindow <application> <x_position> <y_position> <horizontal_size> <vertical_size> <targeted_viewport>

Một ví dụ: để mở một Google-Chromecửa sổ được định vị 20, 20, kích thước 300x300, trên khung nhìn 5:

setwindow google-chrome 20 20 300 300 5

Thiết lập khá giống với phiên bản đầu tiên của tập lệnh.
Lưu ý rằng tập lệnh này chỉ hoạt động chính xác nếu cửa sổ được xác định (vị trí / kích thước) hoàn toàn phù hợp với chế độ xem được nhắm mục tiêu.

Kịch bản:

#!/usr/bin/env python3
import subprocess
import time
import sys

app = sys.argv[1]
target_vp = int(sys.argv[6])

def get_res():
    # get resolution
    xr = subprocess.check_output(["xrandr"]).decode("utf-8").split()
    pos = xr.index("current")
    return [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]

res = get_res()

def current(set_vp):
    # get the current viewport
    vp_data = subprocess.check_output(
        ["wmctrl", "-d"]
        ).decode("utf-8").split()
    dt = [int(n) for n in vp_data[3].split("x")]
    cols = int(dt[0]/res[0])
    rows = int(dt[1]/res[1])    
    curr_vpdata = [int(n) for n in vp_data[5].split(",")]
    curr_col = int(curr_vpdata[0]/res[0])
    curr_row = int(curr_vpdata[1]/res[1])
    curr_vp = curr_col+curr_row*cols+1
    # calculate the vector to the origin from the current viewport (in resolution units)
    vec_curr = vector(curr_vp, cols)
    # calculate the vector to the origin from the targeted viewport
    vec_set = vector(set_vp, cols)
    # calculate the vector between current and targeted viewport
    vec_relative = [vec_set[0] - vec_curr[0],
                    vec_set[1] - vec_curr[1]]
    # calculate needed correction (absolute)
    relative = [vec_relative[0]*res[0],
                vec_relative[1]*res[1]]
    return relative

def vector(vp, cols):
    rem = vp%cols
    vec_x = rem-1 if rem != 0 else cols-1
    vec_y = int((vp-1)/cols)
    return [vec_x, vec_y]

res = get_res() # nieuw
get = lambda x: subprocess.check_output(["/bin/bash", "-c", x]).decode("utf-8")
ws1 = get("wmctrl -lp"); t = 0
# check for additional arguments to run the application
try:
    subprocess.Popen(["/bin/bash", "-c", app+" "+sys.argv[7]])  
except IndexError:
    subprocess.Popen(["/bin/bash", "-c", app])

# fix exception for Chrome (command = google-chrome-stable, but processname = chrome)
app = "chrome" if "chrome" in app else 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"
        # calculate the correction, related to the current workspace, marge for launcher and panel
        pos_x = int(sys.argv[2]); pos_y = int(sys.argv[3]); x_marge = 65; y_marge = 35
        pos_x = pos_x if pos_x > x_marge else x_marge; pos_y = pos_y if pos_y > y_marge else y_marge
        x_relative = pos_x+current(target_vp)[0]
        y_relative = pos_y+current(target_vp)[1]
        # correct possible inaccurately set width / height
        x_size = res[0]; y_size = res[1]
        set_width = int(sys.argv[4]); set_height = int(sys.argv[5])
        width = set_width if set_width+x_marge+pos_x < x_size else x_size - pos_x - x_marge
        height = set_height if set_height+y_marge+pos_y < y_size else y_size - pos_y - y_marge
        cmd3 = "wmctrl -ir "+w_id+" -e 0,"+str(x_relative)+","+str(y_relative)+","+str(width)+","+str(height)
        for cmd in [cmd1, cmd2, cmd3]:   
            subprocess.call(["/bin/bash", "-c", cmd])
        break
    time.sleep(0.5)
    t = t+1


Mở cửa sổ ứng dụng bằng các đối số

Để hoàn thành công việc, trả lời hoàn toàn câu hỏi của bạn:

Nếu bạn chạy tập lệnh như:

setwindow google-chrome 20 20 300 300 5

nó sẽ mở một cửa sổ mặc định trên (các) máy tính để bàn được nhắm mục tiêu.
Tuy nhiên, với phiên bản mới nhất của tập lệnh, bạn có thể thêm một đối số bổ sung để mở cửa sổ ứng dụng, ví dụ url:

setwindow <application> <x_position> <y_position> <horizontal_size> <vertical_size> <targeted_viewport> <(optional)_argument>

ví dụ:

setwindow google-chrome 0 0 600 600 3 "--new-window http://askubuntu.com"

Nếu đối số (thêm) chứa khoảng trắng, hãy sử dụng dấu ngoặc kép. Ví dụ trên sẽ mở một google-chromecửa sổ trên khung nhìn 3, mở url http://askubuntu.com.

Bạn có thể xâu chuỗi các lệnh để mở nhiều cửa sổ / url trên các không gian làm việc khác nhau trong một lệnh, ví dụ:

setwindow google-chrome 0 0 600 600 8 "--new-window http://askubuntu.com"&&setwindow google-chrome 0 0 600 600 7 "--new-window www.google.com"

@snitko Cảm ơn câu hỏi hay, đó là một thử thách thú vị để hoàn thành nó :)
Jacob Vlijm

Tôi nhận thấy có một chút bù cho cửa sổ khi tôi đang sử dụng tập lệnh. Vì vậy, ví dụ, nếu tôi mở ở tọa độ 0 0, nó thực sự mở ra một chút ở bên phải và phía dưới (độ lệch ~ 10px). Điều đó không sao, nhưng vấn đề thực sự nằm ở tập lệnh thứ hai: phần bù trong tập lệnh thứ hai lớn hơn một cách kỳ lạ trên trục hoành. Tôi nghĩ rằng nó khoảng ~ 50px ở bên trái. Bạn có thể thấy tại sao vậy không? Đặt tọa độ âm không giúp ích trong trường hợp đó.
snitko

Một câu hỏi khác: làm thế nào để tôi mở một cửa sổ toàn màn hình?
snitko

Một bản cập nhật: phần bù trong trường hợp của tập lệnh thứ hai dường như giống với chiều rộng của dock thống nhất ở bên trái (mặc dù nó bị ẩn).
snitko

Đối với những người quan tâm, tôi đã triển khai Desktopen: github.com/snitko/desktopen
snitko

1

Điều này mở rộng trên câu trả lời tuyệt vời của @Jacob Vlijim ở trên với một setwindowtập lệnh được sửa đổi một chút :

#!/usr/bin/env python

import time
import argparse
import subprocess

DEFAULT_WIDTH = '1920'
DEFAULT_HEIGHT = '1080'


def get_window_list():
    window_list = subprocess.check_output(['/bin/bash', '-c', 'wmctrl -l'])
    parsed_list = []
    for line in window_list.splitlines():
        window_info = line.split()
        if window_info[1] != '-1':
            parsed_list.append(window_info[0])
    return parsed_list


def main(params):
    old_list = get_window_list()
    subprocess.Popen(['/bin/bash', '-c', params.command])

    def get_diff(old):
        new_list = get_window_list()
        return list(set(new_list) - set(old))

    diff = get_diff(old_list)
    x = 0
    while not diff:
        if x == 10:
            print 'window not found'
            return
        x += 1
        diff = get_diff(old_list)
        time.sleep(1)
    if len(diff) > 1:
        raise Exception(diff)
    window_id = diff[0]
    command_list = []
    command_list.append('wmctrl -ir %s -t %s' % (window_id, params.desktop))
    command_list.append('wmctrl -ir %s -b remove,maximized_horz,maximized_vert'
        % window_id)
    command_list.append('wmctrl -ir %s -e 0,%s,%s,%s,%s' %
        (window_id, params.x_pos, params.y_pos, params.width, params.height))
    for command in command_list:
        subprocess.call(['/bin/bash', '-c', command])

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('command', type=str)
    parser.add_argument('-d', '--desktop', default='0', type=str)
    parser.add_argument('-x', '--x-pos', default='0', type=str)
    parser.add_argument('-y', '--y-pos', default='0', type=str)
    parser.add_argument('-w', '--width', default=DEFAULT_WIDTH, type=str)
    parser.add_argument('-t', '--height', default=DEFAULT_HEIGHT, type=str)
    args = parser.parse_args()
    main(args)

Mô tả về các thay đổi:

  1. python3đến python(chỉ là một sở thích cá nhân)
  2. sys.argvđể argparsecó giao diện dòng lệnh tốt hơn
  3. phân tích cú pháp cửa sổ id (và không xử lý id)
    • một số chương trình sử dụng một id process process cho nhiều windows
  4. while vòng lặp 0,5 giây đến 1 giây đầy đủ thời gian ngủ
  5. nhiều tên biến / dài dễ đọc hơn và tuân thủ pep8
  6. biến hằng toàn cầu cho kích thước màn hình thay vì xrandrphụ thuộc

LƯU Ý: Đây chỉ là phiên bản cải tiến một chút mà tôi đã viết để sử dụng cá nhân trên Debian Jessie LXDE. Kết quả của bạn có thể thay đổi.


0

Đối với những người quan tâm, tôi đã triển khai Desktopen: github.com/snitko/desktopen

Nó cho phép bạn viết một kịch bản để mở các cửa sổ trên các khung nhìn khác nhau và hiển thị một cách rất thân thiện.

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.