Существует ли сценарий (или программное обеспечение) для открытия окна приложения в определенной области просмотра и позиции?

Итак, у меня есть 8 виртуальных рабочих столов в Unity (с Compiz), потому что у меня много проектов, над которыми я работаю одновременно.

Проблема в том, что каждый раз, когда мне нужно перезагрузить или случайно закрыть Chrome (который составляет большую часть окон, необходимых для работы), я должен вручную открыть эти окна и затем настроить их (открыть файлы, перейти на правильные URL и т. д.).

Как бы ты написал сценарий, который сделает все это для меня? То есть: 1) Откройте окна 2) Поместите их в правильные координаты на правильных виртуальных экранах

(1) очевидно, для Google Chrome вы просто запускаете «google-chrome». Но тогда как вы положите его в нужном месте? (2)

Или уже существует сценарий / программное обеспечение, которое сделало бы это для меня?

8
задан 1 June 2016 в 11:47

3 ответа

Это может быть сделано очень хорошо, но Вам нужно некоторое понимание Единицы/областей просмотра. Я надеюсь, что история ниже понятна, в противном случае оставьте комментарий.

Сценарий ниже может использоваться для открытия окна любого приложения на любой из областей просмотра, на любом положении при выполнении его с правильными аргументами. Сценарий является отредактированной версией этого, но теперь готовый поместить окна в виртуальный рабочий стол охвата.

1. Понимание областей просмотра и координат окна

Рабочие области в единице

В Единице, в отличие от других менеджеров окон, у Вас на самом деле только есть одна рабочая область охвата, которая разделена на области просмотра. В Вашем случае Ваша рабочая область разделена на восемь областей просмотра.

Как положение окон определяется

Положение окна, как вывод команды:

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

описан как положение, относительно левого верхнего угла текущей области просмотра:


Таким образом, если Вы находитесь на области просмотра 1:
окно на области просмотра 2 к могло быть расположено на, например, 1700 (x-wise) x 500 (y-wise)
(мой экран 1680x1050),

enter image description here


Однако, если Вы находитесь на области просмотра 6:
то же окно было бы расположено на 20 (x),-550 (y) enter image description here


Используя эти координаты правильно важно для запущения скрипта с правильными аргументами, как описано ниже:

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 окно должно обнаружиться на текущей области просмотра.

Примечания:

  • Следует иметь в виду, что не все приложения позволяют размеры окна ниже определенной ширины или высоты. Минимальная ширина a gedit окно в моей системе, например, appr. 470 пкс.
  • Сценарий только хорошо работает, если целые соответствия окна на целенаправленной области просмотра, выберите свои координаты/размеры соответственно. Также ум, что Средство запуска Единицы и панель используют некоторое пространство (!), которое может влиять на положение окна.
  • Используйте отрицательный <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



Править: ленивая версия

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

При установке его как первая версия сценария можно выполнить его с командой:

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

Пример: открыть a 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

это откроет окно по умолчанию на целенаправленном рабочем столе (столах).
С последней версией сценария однако, можно добавить дополнительный аргумент для открытия окна приложения, например, a 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"

Если (дополнительный) аргумент содержит пробелы, используйте кавычки. Вышеупомянутый пример откроет agoogle-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"
14
ответ дан 1 June 2016 в 21:47
  • 1
    cat первоначально коротко для " concatenate" поскольку это было его намеченной целью (связывающий файлы вместе). – user13161 10 August 2016 в 08:40

Для заинтересованных, я реализовал Desktopen: github.com/snitko/desktopen

Это позволяет Вам писать сценарий для вводных окон на различных областях просмотра и дисплеях очень дружественным способом.

0
ответ дан 1 June 2016 в 21:47
  • 1
    Here' s альтернативная идея, попытайтесь установить 14.04 на VM или где-то в другом месте и попробуйте свой метод снова, если он работает тогда, Вы знаете, что это - ошибка на 16,04 – patrick 9 August 2016 в 20:16

Это подробно останавливается на большом ответе @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. Ваши результаты могут варьироваться.

1
ответ дан 1 June 2016 в 21:47
  • 1
    That' s очень любезно с вашей стороны, но как я сказал первоначально, файл загружается автоматически composer сценарий и я на самом деле don' t знают, если и где я могу вручную изменить URL выборки. Также я предполагаю, что будут другие файлы, которые должны быть загружены в процессе который you' d также должны предоставить вручную один за другим. Если я действительно don' t не находят никакое другое решение, я мог разместить файлы сам (как Вы, сделал в GitHub repo), и загрузка силы путем создания руководства размещает маршрут, но I' m на самом деле заинтересованный действительным решением причина (URL, не достижимый), не некоторое обходное решение для него. – suamikim 9 August 2016 в 20:14

Другие вопросы по тегам:

Похожие вопросы: