Bir uygulamayı (ve tüm yeni pencerelerini) belirli bir çalışma alanına nasıl kilitleyebilirim?


11

Bir Matlabkomut dosyası çalıştırıyorum workspace 1. Bu birkaç çizim oluşturur. Bu arada workspace 2oraya geçip orada çalışıyorum. Benim sorunum, parsellerin ortaya çıkması workspace 2. Yazılımı çalışma alanına kilitlemek mümkün mü? Peki Matlabparselleri oluştururken , pop-up parselleri aksatmadan workspace 1çalışabilir miyim workspace 2?


Birlik, GNOME Kabuğu veya başka bir şey?
AB

Etiketleri ekliyorum, Unity ile Ubuntu
14.04

Arsa pencereleri hangi sınıfa aittir? (komutla kontrol edebilir xprop WM_CLASSve ardından pencereye tıklayabilir misiniz?) Lütfen Matlab'ın WM_CLASS'sini de ekleyin.
Jacob Vlijm

2
Bugün daha sonra yayınlayacağım, eğer biri bu arada başka bir parlak çözüm yayınlamazsa.
Jacob Vlijm

1
Merhaba OHLÁLÁ, aslında oldukça iyi çalışma var, uygulamanın tüm ek pencereleri anında uygulamanın ilk çalışma alanına taşınır, ama .... gerçekten de mevcut çalışma alanındaki mevcut pencere yine de odak kaybeder. Hala bir çözüm buluyorum. Çözümü yine dener misiniz?
Jacob Vlijm

Yanıtlar:


8

ÖNEMLİ DÜZENLEME

Komut dosyasının ilk yanıtından yeniden yazılan bir versiyonunun altında (aşağıda). Farklılıklar:

  • Komut dosyası artık kaynaklarda son derece düşük (arka plan komut dosyalarında olması gerektiği gibi). Eylemler artık gerekliyse (ve sadece gerekiyorsa) hareket edecek şekilde düzenlenmiştir. Döngü, yeni pencerelerin görünmesini kontrol etmekten başka hiçbir şey yapmaz.
  • Bot WM_CLASSve hedeflenen çalışma alanı artık betiği çalıştırmak için bağımsız değişkenlerdir . Yalnızca birinci veya ikinci (tanımlayıcı) kısımlarını WM_CLASSkullanın (aşağıya bakınız: nasıl kullanılır)
  • Komut dosyası şimdi etkin durumda olan pencereye odaklanmaya devam ediyor (aslında bir saniyede yeniden odaklanıyor)
  • Komut dosyası başladığında bir bildirim gösterir (örnek gedit):

    resim açıklamasını buraya girin

Senaryo

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

Nasıl kullanılır

  1. Senaryo hem ihtiyacı wmctrlve xdotool:

    sudo apt-get install wmctrl xdotool
    
  2. Yukarıdaki komut dosyasını boş bir dosyaya kopyalayın, lock_towspace.py

  3. Özel uygulamanızın aşağıdakileri öğrenin WM_CLASS: Uygulamanızı açın, bir terminalde çalıştırın:

    xprop WM_CLASS and click on the window of the application
    

    Çıktı aşağıdaki gibi görünecektir (sizin durumunuzda):

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

    Komut dosyasını çalıştırmak için komuttaki ilk veya ikinci bölümü kullanın.

  4. Komut dosyasını çalıştırma komutu şöyledir:

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

    Komutta son bölüm; 2,2uygulamayı "insan" biçiminde (boşluk olmadan: (!) sütun, satır ) kilitlemek istediğiniz çalışma alanıdır ; ilk sütun / satır1,1

  5. Komut dosyasını çalıştırarak test edin. Çalıştırırken uygulamanızı açın ve her zamanki gibi pencere oluşturmasına izin verin. Tüm pencereler, komutta ayarlandığı şekilde, hedeflenen çalışma alanında görünmelidir.

ESKİ CEVAP:

(ikinci) TEST SÜRÜMÜ

Aşağıdaki komut dosyası , belirli bir uygulamayı ilk çalışma alanına kilitler . Komut dosyası başlatılırsa, uygulamanın hangi çalışma alanında olduğunu belirler. Uygulamanın ürettiği tüm ek pencereler bir saniyede aynı çalışma alanına taşınır.

Odaklanma sorunu, ek pencere üretilmeden önce odaklanan pencereye otomatik olarak yeniden odaklanarak çözülür.

Senaryo

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

Nasıl kullanılır

  1. Senaryo ihtiyacı hem wmctrlvexdotool

    sudo apt-get install wmctrl xdotool
    
  2. Komut dosyasını boş bir dosyaya kopyalayın, keep_workspace.py

  3. Uygulamayı açarak uygulamanızın WM_CLASS değerini belirleyin, ardından bir terminal açın ve komutu çalıştırın:

    xprop WM_CLASS
    

    Ardından uygulamanızın penceresini tıklayın. Çıkışı, "sun-awt-X11-XFramePeer", "MATLAB R2015a - academic use"durumunuzda olduğu gibi kopyalayın ve belirtildiği gibi komut dosyasının baş bölümünde tek tırnak işaretleri arasına yerleştirin .

  4. Komut dosyasını şu komutla çalıştırın:

    python3 /path/to/keep_workspace.py
    

İstediğiniz gibi çalışırsa, bir açma / kapatma işlevi ekleyeceğim. Sistemimde zaten birkaç saat çalışmasına rağmen, ilk önce biraz değişiklik yapması gerekebilir.

notlar

Bunu fark olmamalıdır rağmen, komut yapar sisteme bazı işlemci yükünü ekleyin. Yaşlı sistemimde% 3-10 oranında bir artış fark ettim. Nasıl çalıştığını seviyorsanız, muhtemelen yükü azaltmak için daha fazla ayarlayacağım.

Komut dosyası, olduğu gibi, güvenlik pencerelerinin bir yorumda belirttiğiniz gibi ana pencereyle aynı sınıfta olduğunu varsayar. Ancak (çok) basit bir değişiklikle ikincil pencereler başka bir sınıftan olabilir .

açıklama

Ortalama bir okuyucu için muhtemelen çok ilginç olmasa da, komut dosyası vektörlerde hesaplayarak çalışır. Başlangıçta komut dosyası şunları hesaplar:

  • çıkışından mevcut çalışma alanına başlangıç ​​noktasından vektör wmctrl -d
  • uygulamanın çalışma penceresine göre, geçerli çalışma alanına göre vektör wmctrl -lG
  • Bu ikisinden, komut dosyası , uygulama penceresinin yayılan masaüstündeki mutlak konumunu hesaplar (bir matristeki tüm çalışma alanları)

O andan itibaren, komut dosyası, aynı uygulamanın yeni pencerelerini arar, çıktısıyla, xprop WM_CLASSkonumlarını yukarıdaki ile aynı şekilde arar ve "orijinal" çalışma alanına taşır.

Yeni oluşturulan pencere, kullanıcının üzerinde çalıştığı son kullanılan pencereden odağı "çaldığı" için, odak daha sonra daha önce odaklanılan pencereye ayarlanır.


Bu çok şaşırtıcı. Kullanıcının farklı uygulamaları çalışma alanlarına kilitleyebileceği bir gösterge oluşturmak iyi bir fikir olabilir. Şu anda Matlab ile ilgili bir sorunum vardı, ancak aynı sorun matplotlib
OHLÁLÁ

@ OHLÁLÁ belirttiğim gibi, soruyu çok ilginç buluyorum ve üzerinde çalışmaya devam edeceğim. Aklımda ne var kullanıcı ayarlayabilir applicationve workspace-sets bir dosyadır . Olası hatalarla karşılaşırsanız, lütfen belirtin!
Jacob Vlijm

Ayrı çalışma alanlarında iki Matlab başlatıldığında davranış ne olacak?
OHLÁLÁ

@ OHLÁLÁ sonra her ikisi de komutta ayarladığınız çalışma alanına kilitlenir. Bunların WM_CLASSözdeş olması nedeniyle, ikincisi komutta ayarladığınıza taşınacaktır.
Jacob Vlijm

WM_CLASS dışında bir uygulamayı tanımlamak için başka olasılıklar var mı?
OHLÁLÁ
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.