응용 프로그램 (및 모든 새 창)을 특정 작업 공간에 잠 그려면 어떻게해야합니까?


11

에서 Matlab스크립트를 실행 합니다 workspace 1. 여러 플롯이 생성됩니다. 그동안 나는 workspace 2그곳으로 가서 일했다. 내 문제는 줄거리가에 나타납니다 workspace 2. 소프트웨어를 작업 공간에 잠글 수 있습니까? Matlab에서의 플롯 을 생성하는 동안 팝업 플롯이 중단되지 않고 workspace 1작업 할 수 workspace 2있습니까?


유니티, 그놈 쉘 또는 다른 것?
AB

태그를 추가합니다. Unity와 Ubuntu 14.04
OHLÁLÁ

플롯 창은 어떤 클래스에 속합니까? (명령으로 확인한 xprop WM_CLASS다음 창을 클릭 할 수 있습니까?) Matlab의 WM_CLASS도 추가하십시오.
Jacob Vlijm

2
누군가가 그 동안 다른 훌륭한 솔루션을 게시하지 않는다면 오늘 나중에 게시 할 것입니다.
Jacob Vlijm 1

1
안녕하세요 OHLÁLÁ, 실제로 실제로 잘 작동했습니다. 응용 프로그램의 모든 추가 창은 즉시 응용 프로그램의 초기 작업 공간으로 이동하지만 ... 현재 작업 공간의 현재 창은 포커스를 잃습니다. 여전히 솔루션을 파악 중입니다. 여전히 해결책을 시도 하시겠습니까?
Jacob Vlijm

답변:


8

중요 편집

아래의 첫 번째 답변에서 다시 작성된 버전의 스크립트. 차이점들:

  • 스크립트는 이제 배경 스크립트와 같이 리소스가 매우 부족합니다. 이제 필요한 경우에만 조치가 수행되도록 조치가 정렬되었습니다. 루프는 실제로 새 창이 나타나지 않는지 확인합니다.
  • WM_CLASS및 대상 작업 공간은 이제 스크립트를 실행하기위한 인수 입니다. 의 첫 번째 또는 두 번째 (식별) 부분 만 사용하십시오 WM_CLASS(아래에서 추가 사용 방법 참조).
  • 이제 스크립트는 현재 활성화 된 창에 계속 초점을 유지합니다 (실제로 초에 다시 초점을 맞 춥니 다)
  • 스크립트가 시작되면 알림이 표시됩니다 (예 gedit:).

    여기에 이미지 설명을 입력하십시오

스크립트

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

app_class = sys.argv[1]
ws_lock = [int(n)-1 for n in sys.argv[2].split(",")]

def check_wlist():
    # get the current list of windows
    try:
        raw_list = [
            l.split() for l in subprocess.check_output(
                ["wmctrl", "-lG"]
                ).decode("utf-8").splitlines()
            ]
        ids = [l[0] for l in raw_list]
        return (raw_list, ids)
    except subprocess.CalledProcessError:
        pass

def get_wssize():
    # get workspace size
    resdata = subprocess.check_output(["xrandr"]).decode("utf-8").split()
    i = resdata.index("current")
    return [int(n) for n in [resdata[i+1], resdata[i+3].replace(",", "")]]

def get_current(ws_size):
    # vector of the current workspace to origin of the spanning desktop
    dt_data = subprocess.check_output(
        ["wmctrl", "-d"]
        ).decode("utf-8").split()
    curr = [int(n) for n in dt_data[5].split(",")]
    return (int(curr[0]/ws_size[0]), int(curr[1]/ws_size[1]))

def get_relativewinpos(ws_size, w_data):
    # vector to the application window, relative to the current workspace
    xpos = int(w_data[2]); ypos = int(w_data[3])
    xw = ws_size[0]; yw = ws_size[1]
    return (math.ceil((xpos-xw)/xw), math.ceil((ypos-yw)/yw))

def get_abswindowpos(ws_size, w_data):
    # vector from the origin to the current window's workspace (flipped y-axis)
    curr_pos = get_current(ws_size)
    w_pos = get_relativewinpos(ws_size, w_data)
    return (curr_pos[0]+w_pos[0], curr_pos[1]+w_pos[1])

def wm_class(w_id):
    # get the WM_CLASS of new windows
    return subprocess.check_output(
        ["xprop", "-id", w_id.strip(), "WM_CLASS"]
        ).decode("utf-8").split("=")[-1].strip()

ws_size = get_wssize()
wlist1 = []
subprocess.Popen(["notify-send", 'workspace lock is running for '+app_class])

while True:
    # check focussed window ('except' for errors during "wild" workspace change)
    try:
        focus = subprocess.check_output(
            ["xdotool", "getwindowfocus"]
            ).decode("utf-8")
    except subprocess.CalledProcessError:
        pass
    time.sleep(1)
    wdata = check_wlist() 
    if wdata !=  None:
        # compare existing window- ids, checking for new ones
        wlist2 = wdata[1]
        if wlist2 != wlist1:
            # if so, check the new window's class
            newlist = [[w, wm_class(w)] for w in wlist2 if not w in wlist1]
            valids = sum([[l for l in wdata[0] if l[0] == w[0]] \
                          for w in newlist if app_class in w[1]], [])
            # for matching windows, check if they need to be moved (check workspace)
            for w in valids:
                abspos = list(get_abswindowpos(ws_size, w))
                if not abspos == ws_lock:
                    current = get_current(ws_size)
                    move = (
                        (ws_lock[0]-current[0])*ws_size[0],
                            (ws_lock[1]-current[1])*ws_size[1]-56
                        )
                    new_w = "wmctrl -ir "+w[0]+" -e "+(",").join(
                        ["0", str(int(w[2])+move[0]),
                         str(int(w[2])+move[1]), w[4], w[5]]
                        )
                    subprocess.call(["/bin/bash", "-c", new_w])
                    # re- focus on the window that was focussed
                    if not app_class in wm_class(focus):
                        subprocess.Popen(["wmctrl", "-ia", focus])
        wlist1 = wlist2

사용하는 방법

  1. 스크립트는 모두 필요 wmctrl하고를 xdotool:

    sudo apt-get install wmctrl xdotool
    
  2. 위의 스크립트를 빈 파일로 복사하여 다른 이름으로 저장하십시오. lock_towspace.py

  3. 특정 응용 프로그램 중에서 다음을 찾으 WM_CLASS십시오. 응용 프로그램을 열고 터미널에서 실행하십시오.

    xprop WM_CLASS and click on the window of the application
    

    결과는 다음과 같습니다 (귀하의 경우).

    WM_CLASS: WM_CLASS(STRING) = "sun-awt-X11-XFramePeer", "MATLAB R2015a - academic use"
    

    명령의 첫 번째 또는 두 번째 부분을 사용하여 스크립트를 실행하십시오.

  4. 스크립트를 실행하는 명령은 다음과 같습니다.

    python3 /path/to/lock_towspace.py "sun-awt-X11-XFramePeer" 2,2
    

    명령에서 마지막 섹션; "인간"형식으로 2,2(공백없이 (!) 열, 행 ) 응용 프로그램을 잠 그려는 작업 공간 입니다. 첫 번째 열 / 행은1,1

  5. 스크립트를 실행하여 테스트하십시오. 실행하는 동안 응용 프로그램을 열고 평소처럼 창을 생성하십시오. 명령에 설정된대로 모든 창이 대상 작업 공간에 나타나야합니다.

오래된 답변 :

(초) 테스트 버전

아래 스크립트 는 특정 응용 프로그램 을 초기 작업 공간에 고정시킵니다. 스크립트가 시작되면 응용 프로그램이 상주하는 작업 공간을 판별합니다. 응용 프로그램이 생성하는 모든 추가 창은 순식간에 동일한 작업 공간으로 이동합니다.

추가 창을 만들기 전에 초점을 맞춘 창에 자동으로 초점을 다시 맞추면 초점 문제가 해결됩니다.

스크립트

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

app_class = '"gedit", "Gedit"'

def get_wssize():
    # get workspace size
    resdata = subprocess.check_output(["xrandr"]).decode("utf-8").split()
    i = resdata.index("current")
    return [int(n) for n in [resdata[i+1], resdata[i+3].replace(",", "")]]

def get_current(ws_size):
    # get vector of the current workspace to the origin of the spanning desktop (flipped y-axis)
    dt_data = subprocess.check_output(["wmctrl", "-d"]).decode("utf-8").split(); curr = [int(n) for n in dt_data[5].split(",")]
    return (int(curr[0]/ws_size[0]), int(curr[1]/ws_size[1]))

def get_relativewinpos(ws_size, w_data):
    # vector to the application window, relative to the current workspace
    xw = ws_size[0]; yw = ws_size[1]
    return (math.ceil((w_data[1]-xw)/xw), math.ceil((w_data[2]-yw)/yw))

def get_abswindowpos(ws_size, w_data):
    curr_pos = get_current(ws_size)
    w_pos = get_relativewinpos(ws_size, w_data)
    return (curr_pos[0]+w_pos[0], curr_pos[1]+w_pos[1])

def wm_class(w_id):
    return subprocess.check_output(["xprop", "-id", w_id, "WM_CLASS"]).decode("utf-8").split("=")[-1].strip()

def filter_windows(app_class):
    # find windows (id, x_pos, y_pos) of app_class
    try:
        raw_list = [l.split() for l in subprocess.check_output(["wmctrl", "-lG"]).decode("utf-8").splitlines()]
        return [(l[0], int(l[2]), int(l[3]), l[4], l[5]) for l in raw_list if wm_class(l[0]) == app_class]
    except subprocess.CalledProcessError:
        pass

ws_size = get_wssize()
init_window = get_abswindowpos(ws_size, filter_windows(app_class)[0])
valid_windows1 = filter_windows(app_class)

while True:
    focus = subprocess.check_output(["xdotool", "getwindowfocus"]).decode("utf-8")
    time.sleep(1)
    valid_windows2 = filter_windows(app_class)
    if all([valid_windows2 != None, valid_windows2 != valid_windows1]):
        for t in [t for t in valid_windows2 if not t[0] in [w[0] for w in valid_windows1]]:
            absolute = get_abswindowpos(ws_size, t)
            if not absolute == init_window:
                current = get_current(ws_size)
                move = ((init_window[0]-current[0])*ws_size[0], (init_window[1]-current[1])*ws_size[1]-56)
                new_w = "wmctrl -ir "+t[0]+" -e "+(",").join(["0", str(t[1]+move[0]), str(t[2]+move[1]), t[3], t[4]])
                subprocess.call(["/bin/bash", "-c", new_w])
            focus = str(hex(int(focus)))
            z = 10-len(focus); focus = focus[:2]+z*"0"+focus[2:]
            if not wm_class(focus) == app_class:
                subprocess.Popen(["wmctrl", "-ia", focus])
        valid_windows1 = valid_windows2

사용하는 방법

  1. 스크립트가 필요로 모두 wmctrlxdotool

    sudo apt-get install wmctrl xdotool
    
  2. 스크립트를 빈 파일로 복사하여 다른 이름으로 저장하십시오. keep_workspace.py

  3. 응용 프로그램을 열어 응용 프로그램의`WM_CLASS '를 확인한 다음 터미널을 열고 다음 명령을 실행하십시오.

    xprop WM_CLASS
    

    그런 다음 응용 프로그램 창을 클릭하십시오. "sun-awt-X11-XFramePeer", "MATLAB R2015a - academic use"귀하의 경우 처럼 출력을 복사하고 표시된대로 스크립트의 헤드 섹션에서 작은 따옴표 사이에 배치하십시오 .

  4. 다음 명령으로 스크립트를 실행하십시오.

    python3 /path/to/keep_workspace.py
    

원하는대로 작동하면 토글 기능을 추가하겠습니다. 내 시스템에서 이미 몇 시간 동안 작동하지만 bu를 먼저 조정해야 할 수도 있습니다.

노트

눈치 채지 않아도 스크립트 시스템에 프로세서로드를 추가합니다. 노인 시스템에서 3-10 % 증가한 것으로 나타났습니다. 작동 방식이 마음에 드시면 부하를 줄이기 위해 추가로 조정할 것입니다.

스크립트는 주석 창에 표시된 것처럼 보조 창이 기본 창과 동일한 클래스라고 가정합니다. (매우) 간단한 변경으로 보조 창 은 다른 클래스 있습니다.

설명

보통 독자에게는 그리 흥미롭지는 않지만 스크립트는 벡터로 계산하여 작동합니다. 시작시 스크립트는 다음을 계산합니다.

  • 출력이있는 원점에서 현재 작업 공간까지의 벡터 wmctrl -d
  • 현재 작업 공간을 기준으로 응용 프로그램 창에 대한 벡터 wmctrl -lG
  • 이 두 가지 스크립트를 통해 스크립트 는 스패닝 데스크탑 (한 매트릭스의 모든 작업 공간)에서 응용 프로그램 창의 절대 위치를 계산합니다.

그때부터 스크립트는 출력이 같은 동일한 응용 프로그램의 새 창을 xprop WM_CLASS찾고 위와 같은 방식으로 위치를 찾은 다음 "원본"작업 공간으로 옮깁니다.

새로 생성 된 창은 사용자가 마지막으로 사용한 창에서 포커스를 "저장"했으므로 이후에 포커스가 있던 창으로 포커스가 설정됩니다.


이것은 매우 끔찍합니다. 사용자가 다른 애플리케이션을 작업 공간에 잠글 수있는 표시기를 작성하는 것이 좋습니다. 지금은 Matlab에 문제가 있었지만 matplotlib와 동일한 문제가 발생합니다.
OHLÁLÁ

@ OHLÁLÁ 언급 한 바와 같이, 나는 질문이 매우 흥미롭고 계속 노력할 것입니다. 내가 생각하는 것은 사용자가 설정 application하고 설정할 수있는 파일입니다 workspace. 가능한 버그가 발생하면 언급하십시오!
Jacob Vlijm

별도의 작업 공간에서 두 개의 Matlab을 시작할 때의 동작은 무엇입니까?
OHLÁLÁ

@ OHLÁLÁ 그러면 둘 다 명령에서 설정 한 작업 공간에 고정됩니다. 그것들 WM_CLASS이 동일 하기 때문에 , 두 번째 것은 명령에서 설정 한 것으로 이동합니다.
Jacob Vlijm

WM_CLASS 이외의 응용 프로그램을 식별 할 수있는 다른 가능성이 있습니까?
OHLÁLÁ
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.