특정 뷰포트 및 위치에서 응용 프로그램 창을 여는 스크립트 (또는 소프트웨어)가 있습니까?


8

그래서 동시에 작업중 인 많은 프로젝트가 있기 때문에 Unity에 Compiz와 함께 8 개의 가상 데스크톱이 있습니다.

문제는 Chrome을 재부팅하거나 실수로 Chrome을 닫아야 할 때마다 (작업에 필요한 많은 부분을 차지합니다) 수동으로 해당 창을 다시 열어 설정해야합니다 (파일을 열고 올바른 파일로 이동하십시오) URL 등).

나를 위해 모든 것을 할 스크립트를 어떻게 작성하겠습니까? 즉 : 1) 열린 창 2) 올바른 가상 화면에서 올바른 좌표로 배치하십시오.

(1) 명백합니다. Chrome의 경우 'google-chrome'만 실행하면됩니다. 그러나 어떻게 올바른 장소에 배치합니까? (2)

아니면 이미 존재하는 스크립트 / 소프트웨어가 있습니까?


시작시 적절한 데스크톱에 필요한 창을 배치하기위한 스크립트를 작성하려고 시도 할 수 있습니다. 다음 주에 결승 진출이 있기 때문에 며칠이 걸릴 수 있습니다. wmctrl스크립트 나 터미널을 통해 창을 제어하는 ​​소프트웨어와 같은 을 포함 합니다. 그러나 창문을 다시 시작하는 것은 조금 더 어려운 문제 일 수 있습니다.
Sergiy Kolodyazhnyy

Unity에 대해 구체적으로 질문했지만 KDE에는 kstart라는 (주로 문서화되지 않은) 프로그램이 있습니다. KDE 프로그램과 가장 잘 작동하지만 다른 프로그램에서도 성공합니다.
Joe

답변:


14

잘 할 수 있지만 Unity / 뷰포트에 대한 이해가 필요합니다. 아래 이야기가 이해할 수 있기를 바랍니다. 그렇지 않으면 의견을 남겨주세요.

아래의 스크립트를 사용 하면 올바른 인수로 실행 하면 모든 위치에서 모든 뷰포트에서 응용 프로그램의 창을 열 수 있습니다 . 스크립트는 버전의 편집 된 버전 이지만 이제는 확장 가상 데스크톱 에 창을 배치 할 준비가되었습니다 .

1. 뷰포트 및 창 좌표 이해

Unity의 작업 공간

Unity에서는 다른 창 관리자와 달리 실제로는 하나의 스패닝 작업 영역 만 있으며 뷰포트로 나뉩니다. 귀하의 경우 작업 공간은 8 개의 뷰포트로 나뉩니다.

창의 위치를 ​​정의하는 방법

명령의 출력으로서의 창 위치 :

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

현재 뷰포트의 왼쪽 상단 기준 으로 한 위치로 설명됩니다 .


따라서 뷰포트에있는 경우 1:
뷰포트 2의 창을 1700 (x-wise) x 500 (y-wise)에 배치 할 수 있습니다
(내 화면은 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 Launcher와 패널은 창의 위치에 영향을 줄 수있는 공간 (!)을 사용합니다.
  • <x_position>현재 뷰포트 왼쪽에 창을 배치 하려면 음수 를 사용하십시오.
  • <y_position>현재 뷰포트 위에 창을 배치 하려면 음수 를 사용하십시오.
  • 한 번에 다른 뷰포트에서 새 창을 열려면 간단히 명령을 연결하면됩니다. "긴 스토리"예제에서 뷰포트 설정을 살펴보면, 뷰포트 1에있는 경우 다음 명령을 사용하여 뷰포트 1, 2, 3 및 4에서 gedit 창을 열 수 있습니다.

    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>

예 : viewport 에서 size Google-Chrome에 위치한 창 을 여는 방법 :20, 20300x3005

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 좋은 질문 주셔서 감사합니다, 그것을 달성하기 위해 좋은 도전이었다 :)
Jacob Vlijm

스크립트를 사용할 때 창에 약간의 오프셋이 있음을 알았습니다. 예를 들어 좌표 0 0에서 열면 실제로 오른쪽과 아래쪽으로 조금 더 열립니다 (~ 10px 오프셋). 괜찮습니다. 그러나 문제는 실제로 두 번째 스크립트의 문제입니다. 두 번째 스크립트의 오프셋이 가로 축에서 이상하게 커집니다. 왼쪽에 ~ 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. python3python(단지 개인적인 취향)
  2. sys.argvargparse더 나은 명령 행 인터페이스 를 위해
  3. 엄격한 창 ID (및 프로세스 ID 아님) 창 구문 분석
    • 일부 프로그램은 여러 창에 단일 프로세스 ID를 사용합니다.
  4. while 루프 0.5 초 ~ 1 초 전체 수면 시간
  5. 더 자세한 / 판독 가능한 변수 이름 및 pep8 준수
  6. xrandr의존 대신 화면 크기에 대한 전역 상수 변수

참고 : 이것은 데비안 Jessie LXDE에서 개인적으로 사용하기 위해 작성한 약간 개선 된 버전입니다. 결과는 다를 수 있습니다.


0

관심있는 사람들을 위해 Desktopen을 구현했습니다 : github.com/snitko/desktopen

다른 뷰포트와 디스플레이에서 창을 여는 스크립트를 매우 친숙한 방식으로 작성할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.