Чи є сценарій (або програмне забезпечення) для відкриття вікна програми на певному вікні перегляду та позиції?


8

Отже, у мене є 8 віртуальних Настільних комп’ютерів в Unity (з Compiz), оскільки у мене є багато проектів, над якими я працюю одночасно.

Проблема полягає в тому, що щоразу, коли мені потрібно перезавантажити або випадково закрити Chrome (який становить значну частину вікон, які мені потрібні для роботи), я повинен вручну знову відкрити ці вікна, а потім встановити їх (відкрити файли, перейти до правильного URL-адреси тощо).

Як би ти пішов писати сценарій, який зробить для мене все це? Тобто: 1) Відкрийте вікна 2) Поставте їх у правильні координати на правильних віртуальних екранах

(1) очевидно, що для Google Chrome ви просто запустите "google-chrome". Але як тоді ви поставите його в потрібне місце? (2)

Або є сценарій / програмне забезпечення, яке вже існує для мене?


Я можу спробувати створити сценарій для розміщення будь-яких вікон, які вам знадобляться на відповідних настільних комп’ютерах при запуску, це може зайняти мені кілька днів, хоча в наступному тижні я маю фінал. Він буде включати wmctrl, як програмне забезпечення для управління Windows через скрипт або термінал. А щодо перезапуску вікна, це може бути дещо більш складним завданням
Сергій Колодяжний

Хоча ви спеціально запитували про Unity, варто зазначити, що KDE має (в основному незадокументовану) програму під назвою kstart, яка робить це для вас. Він найкраще працює з програмами KDE, але також має певний успіх з іншими програмами.
Джо

Відповіді:


14

Це можна зробити дуже добре, але вам потрібно трохи зрозуміти Unity / viewports. Я сподіваюсь, що історія нижче зрозуміла, якщо ні, будь ласка, залиште коментар.

Сценарій нижче може бути використаний для відкриття вікна будь-якої програми на будь-якому з ваших вікон перегляду, у будь-якій позиції, якщо ви запускаєте його з правильними аргументами. Сценарій є відредагованою версією цієї , але тепер готова розмістити вікна на віртуальному робочому столі .

1. Розуміння вікон перегляду та координат вікон

Робочі простори в єдності

У Unity, на відміну від інших менеджерів вікон, у вас є лише одна робоча область, що охоплює, яка поділяється на вікна перегляду. У вашому випадку ваша робоча область розділена на вісім вікон перегляду.

Як визначається положення вікон

Положення вікна, як вихід команди:

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

описується як положення відносно верхнього лівого кута поточного огляду :


Отже, якщо ви перебуваєте у вікні перегляду 1:
вікно у вікні перегляду 2, яке може бути розміщене, наприклад, 1700 (x-мудрий) x 500 (y-мудрий)
(мій екран - 1680x1050)

введіть тут опис зображення


Однак якщо ви перебуваєте у вікні перегляду 6:
те саме вікно було б розміщене на 20 (x), -550 (y) введіть тут опис зображення


Використання цих координат важливо для запуску сценарію з правильними аргументами, як описано нижче:

2. Як користуватися сценарієм

Сценарій нижче може бути використаний для розміщення нового вікна програми на вашій віртуальній робочій області.

  1. Переконайтесь, що wmctrlвстановлено:

    sudo apt-get install wmctrl
    
  2. Скопіюйте сценарій нижче в порожній файл, збережіть його як setwindow(без розширення) в ~/bin. Створіть каталог, якщо він ще не існує. Зробіть сценарій виконуваним .

  3. Якщо ви тільки що створили ~/bin, виконайте команду source ~/.profileабо вийдіть / увійдіть, щоб зробити доступний каталог $PATH.
  4. Тестовий запуск команди:

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

    напр

    setwindow gedit 100 100 200 200
    

    У поточному вікні перегляду повинно з’являтися вікно gedit.

Примітки:

  • Майте на увазі, що не всі програми допускають розміри вікон нижче певної ширини чи висоти. Мінімальна ширина geditвікна в моїй системі, наприклад, appr. 470 пікс.
  • Сценарій чудово працює лише у тому випадку, якщо все вікно вміщається на цільовому вікні перегляду, відповідно вибирайте координати / розміри. Також майте на увазі, що панель запуску Unity та панель використовують деякий простір (!), Який може впливати на положення вікна.
  • Використовуйте мінус, <x_position>щоб розмістити вікна зліва від поточних вікон перегляду
  • Використовуйте мінус, <y_position>щоб розмістити вікна над поточними вікнами перегляду
  • Щоб відкрити нові вікна в різних областях перегляду одразу, можна просто ланцюжок команд. Переглядаючи налаштування вікна перегляду в прикладі "Довга історія", якщо я перебуваю у вікні перегляду 1, я можу відкрити вікна gedit у вікнах перегляду 1, 2, 3 та 4 за допомогою команди:

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

Сценарій

#!/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: лінива версія

У випадку, якщо ви хочете просто ввести координати та розмір, просто так, як якщо б ви відкрили вікно в поточному вікні перегляду та надали цільовий огляд перегляду як аргумент (без необхідності нічого обчислювати), то використовуйте наведену нижче версію ...

Якщо встановити його як першу версію сценарію, ви можете запустити його командою:

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

Приклад: відкрити Google-Chromeвікно, розміщене на 20, 20, розмірі 300x300, у вікні перегляду 5:

setwindow google-chrome 20 20 300 300 5

Установка майже однакова як у першій версії сценарію.
Зверніть увагу, що також цей скрипт працює правильно, лише якщо визначене вікно (положення / розмір) повністю вписується в цільовий вікно перегляду.

Сценарій:

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


Відкриття вікна програми з аргументами

Щоб закінчити роботу, повністю відповівши на ваше запитання:

Якщо ви запускаєте сценарій, наприклад:

setwindow google-chrome 20 20 300 300 5

це відкриє вікно за замовчуванням на цільовому робочому столі.
З останньою версією сценарію, однак, ви можете додати додатковий аргумент для відкриття вікна програми, наприклад url:

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

наприклад:

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

Якщо (додатковий) аргумент містить пробіли, використовуйте лапки. Наведений вище приклад відкриє google-chromeвікно на вікні перегляду 3, відкривши вікно url http://askubuntu.com.

Ви можете зв'язати команди, щоб відкрити кілька вікон / URL-адрес на різних робочих просторах однією командою, наприклад:

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 Дякую за приємне запитання, це було приємним викликом, щоб його виконати :)
Якоб Влійм

Я помітив, що для вікна, коли я використовую сценарій, є невелике зміщення. Так, наприклад, якщо я відкриваю за координатами 0 0, це фактично відкриває його трохи більше праворуч і внизу (зміщення ~ 10 пікселів). Це гаразд, але проблема полягає насправді у другому сценарії: зміщення у другому сценарії дивно більше на горизонтальній осі. Я думаю, що це приблизно ~ 50px зліва. Ви можете зрозуміти, чому це? Встановлення негативних координат у цьому випадку не допомагає.
snitko

Ще одне питання: як відкрити повноекранний екран вікна?
snitko

Оновлення: зсув у випадку другого сценарію здається таким же, як і ширина док-одиниці зліва (хоча він прихований).
snitko

Для тих, хто цікавиться, я реалізував Desktopen: github.com/snitko/desktopen
snitko

1

Це додається до чудової відповіді @Jacob Vlijim вище, дещо зміненим setwindowсценарієм:

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

Опис змін:

  1. python3до python(лише особисті переваги)
  2. sys.argvщоб argparseдля інтерфейсу командного рядка краще
  3. суворий ідентифікатор вікна (а не ідентифікатор процесу) розбору вікон
    • деякі програми використовують єдиний ідентифікатор процесу для декількох вікон
  4. while цикл 0,5 секунди до 1 повного другого часу сну
  5. більш докладно / читабельні назви змінних та прихильність pep8
  6. глобальні постійні змінні для розміру екрана замість xrandrопори

ПРИМІТКА. Це лише трохи вдосконалена версія, яку я написав для особистого використання на Debian Jessie LXDE. Ваші результати можуть відрізнятися.


0

Для тих, хто цікавиться, я реалізував Desktopen: github.com/snitko/desktopen

Це дозволяє написати сценарій для відкриття вікон на різних вікнах перегляду та відображення дуже дружньо.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.