Я запускаю скрипт Matlab
в workspace 1
. Это создает несколько графиков. А пока я переключаюсь на workspace 2
и работаю там. Моя проблема в том, что сюжеты появляются в workspace 2
. Можно ли заблокировать программное обеспечение в рабочей области. Таким образом, хотя Matlab
генерирует графики в workspace 1
, я могу работать в workspace 2
без нарушения всплывающих графиков?
Ниже переписанной версии сценария из первого ответа (ниже). Различия:
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
Для сценария нужны оба wmctrl
и xdotool
:
sudo apt-get install wmctrl xdotool
Скопируйте сценарий выше в пустой файл, сохраните его как lock_towspace.py
Из Вашего определенного приложения узнайте 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"
Или используйте первое или вторую часть в команде для запущения скрипта.
Команда для запущения скрипта затем:
python3 /path/to/lock_towspace.py "sun-awt-X11-XFramePeer" 2,2
В команде, последнем разделе; 2,2
рабочая область, где Вы хотите заблокировать приложение к (без пробелов: (!) столбец, строка), в "человеческом" формате; первый столбец/строка 1,1
Сценарий ниже блокирует определенное приложение к своей начальной рабочей области. Если сценарий запускается, он определяет, на которой рабочей области находится приложение. Все дополнительные окна продукты приложения будут перемещены в ту же рабочую область в долю секунды.
Проблема фокуса решена автоматически пере - фокусирующийся на окне, которое было сфокусировано, прежде чем дополнительное окно было произведено.
#!/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
Для сценария нужны оба wmctrl
и xdotool
sudo apt-get install wmctrl xdotool
Скопируйте сценарий в пустой файл, сохраните его как keep_workspace.py
определите 'WM_CLASS' своего приложения путем открытия приложения, затем откройте терминал и выполните команду:
xprop WM_CLASS
Затем нажмите на окно своего приложения. Скопируйте вывод, будучи похож "sun-awt-X11-XFramePeer", "MATLAB R2015a - academic use"
в Вашем случае и месте это между одинарными кавычками в главном разделе сценария, как обозначено.
Запустите скрипт с командой:
python3 /path/to/keep_workspace.py
Если это будет работать как Вам угодно, то я добавлю функцию переключателя. Хотя это уже работает в течение нескольких часов в моей системе, bu это, возможно, нуждался бы в некоторой тонкой настройке сначала как бы то ни было.
Хотя Вы не должны замечать его, сценарий действительно добавляет, что некоторый процессор загружается к системе. В моей пожилой системе я заметил увеличение 3-10%. Если Вам нравится, как это работает, я, вероятно, далее настрою его для сокращения загрузки.
Сценарий, как это, предполагает, что secundary окна имеют тот же класс как главное окно, как Вы обозначены в комментарии. С (очень) простым изменением вторичные окна могут иметь другой класс как бы то ни было.
Хотя, вероятно, не очень интересный для среднего читателя, сценарий работает путем вычисления в векторах. На запуске вычисляет сценарий:
wmctrl -d
wmctrl -lG
С тех пор сценарий ищет новые окна того же приложения с выводом xprop WM_CLASS
, ищет их положение таким же образом как выше и перемещает их в "исходную" рабочую область.
Так как недавно созданное окно "украло" фокус из последнего используемого окна, пользователь продолжал работать, фокус впоследствии установлен на окно, которое сфокусировалось прежде.