EDIT PENTING
Di bawah versi naskah yang ditulis ulang dari jawaban pertama (di bawah). Perbedaan:
Naskah
#!/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
Cara Penggunaan
Script membutuhkan keduanya wmctrl
dan xdotool
:
sudo apt-get install wmctrl xdotool
Salin skrip di atas ke dalam file kosong, simpan sebagai lock_towspace.py
Dari aplikasi spesifik Anda, cari tahu WM_CLASS
: buka aplikasi Anda, jalankan di terminal:
xprop WM_CLASS and click on the window of the application
Outputnya akan terlihat seperti (dalam kasus Anda):
WM_CLASS: WM_CLASS(STRING) = "sun-awt-X11-XFramePeer", "MATLAB R2015a - academic use"
Gunakan bagian pertama atau kedua dalam perintah untuk menjalankan skrip.
Perintah untuk menjalankan skrip adalah:
python3 /path/to/lock_towspace.py "sun-awt-X11-XFramePeer" 2,2
Dalam perintah, bagian terakhir; 2,2
adalah ruang kerja tempat Anda ingin mengunci aplikasi ke (tanpa spasi: (!) kolom, baris ), dalam format "manusia"; kolom / baris pertama adalah1,1
- Uji skrip dengan menjalankannya. Saat berjalan, buka aplikasi Anda dan biarkan menghasilkan windows seperti biasa. Semua jendela akan muncul di ruang kerja yang ditargetkan, sebagaimana diatur dalam perintah.
JAWABAN KAKI:
(kedua) UJI VERSI
Skrip di bawah ini mengunci aplikasi tertentu ke ruang kerja awalnya. Jika skrip dimulai, ia menentukan ruang kerja tempat aplikasi berada. Semua jendela tambahan yang dihasilkan aplikasi akan dipindahkan ke ruang kerja yang sama dalam sepersekian detik.
Masalah fokus diselesaikan dengan secara otomatis memfokuskan kembali pada jendela yang difokuskan sebelum jendela tambahan diproduksi.
Naskah
#!/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
Cara Penggunaan
Script membutuhkan keduanya wmctrl
danxdotool
sudo apt-get install wmctrl xdotool
Salin skrip ke file kosong, simpan sebagai keep_workspace.py
tentukan `WM_CLASS 'aplikasi Anda dengan membuka aplikasi, lalu buka terminal dan jalankan perintah:
xprop WM_CLASS
Kemudian klik pada jendela aplikasi Anda. Salin hasilnya, terlihat seperti "sun-awt-X11-XFramePeer", "MATLAB R2015a - academic use"
dalam kasus Anda, dan letakkan di antara tanda kutip tunggal di bagian kepala skrip, seperti yang ditunjukkan.
Jalankan skrip dengan perintah:
python3 /path/to/keep_workspace.py
Jika berfungsi sesuka Anda, saya akan menambahkan fungsi sakelar. Meskipun sudah berfungsi selama beberapa jam di sistem saya, tetapi mungkin perlu beberapa penyesuaian terlebih dahulu.
Catatan
Meskipun Anda tidak akan melihat itu, script tidak menambahkan beberapa beban prosesor ke sistem. Pada sistem lanjut usia saya, saya perhatikan peningkatan 3-10%. Jika Anda suka cara kerjanya, saya mungkin akan men-tweak lebih lanjut untuk mengurangi beban.
Script, seperti itu, mengasumsikan jendela sekunder dari kelas yang sama dengan jendela utama, seperti yang Anda tunjukkan dalam komentar. Dengan perubahan (sangat) sederhana, jendela sekunder dapat dari kelas lain.
Penjelasan
Meskipun mungkin tidak terlalu menarik untuk pembaca rata-rata, skrip bekerja dengan menghitung dalam vektor. Saat memulai, skrip menghitung:
- vektor dari asal ke ruang kerja saat ini dengan output dari
wmctrl -d
- vektor ke jendela aplikasi, relatif ke ruang kerja saat ini, oleh output dari
wmctrl -lG
- Dari keduanya, skrip menghitung posisi absolut dari jendela aplikasi pada desktop spanning (semua ruang kerja dalam satu matriks)
Sejak saat itu, skrip mencari jendela baru dari aplikasi yang sama, dengan output dari xprop WM_CLASS
, mencari posisi mereka dengan cara yang sama seperti di atas dan memindahkannya ke ruang kerja "asli".
Karena jendela yang baru dibuat "mencuri" fokus dari jendela yang terakhir digunakan pengguna, fokus kemudian diatur ke jendela yang sebelumnya fokus.