I have 3 monitors on my development machine, which runs Ubuntu + Unity. I usually посвяти тебе one монитор to Веб browsing and IM, and the other two to terminals where I run vim or enter commands. гm looking for в single-key-sequence to переключатель between them at-will.
I would like to know how I хан переключатель focus to (top-) windows on each монитор. The behavior гm looking or is sort-of like ALT+TAB, except instead of rotating between applications (which only makes the most-recently-used instance of application available in the rotation), I хан покрути тебя focus between monitors.
Схвати в compromise, I could стенд to использовал the ALT+TAB mechanism if I could have each and every window in the list. I still вообразил this getting annoying, though.
В установке ниже, включены два сценария: один фоновый сценарий для отслеживания историю сфокусированных окон (см. объяснение внизу для чтения, почему это необходимо), и один сценарий "действия", чтобы поместить под сочетанием клавиш, установить внимание на следующий экран. Если следующий экран в настоящее время не имеет никакого окна для установки внимания на, сообщение отображено:
Сценарий 1; фоновый сценарий, сохраните его (точно) как focus_track.py
#!/usr/bin/env python3
import subprocess
import time
import os
rootdata = os.environ["HOME"]+"/.focus_history"
def get_screendata():
return sorted([int(s.split("+")[-2]) for s in subprocess.check_output(["xrandr"]).decode("utf-8").split() if s.count("+") == 2])
def current_windows():
try:
return subprocess.check_output(["wmctrl", "-lG"]).decode("utf-8")
except subprocess.CalledProcessError:
pass
def convert_format(w_id):
return w_id[:2]+(10-len(w_id))*"0"+w_id[2:]
def read_data():
return open(rootdata).read().splitlines()
def get_top(wlist):
top = convert_format([l.split("#")[-1].strip() for l in \
subprocess.check_output(["xprop", "-root"]).decode("utf-8").splitlines() \
if "_NET_ACTIVE_WINDOW(WINDOW)" in l][0])
return [l for l in wlist if top in l][0]
if __name__ == "__main__":
open(rootdata, "wt").write("This is an empty line")
while True:
time.sleep(1)
wdata = current_windows()
if wdata != None:
wlist = wdata.splitlines()
# get frontmost window (as in wmctrl -lG)
top = get_top(wlist)
oldlist = read_data()
if not top == oldlist[0]:
# clean up closed windows
[oldlist.remove(l) for l in oldlist if not l.split()[0] in wdata]
# remove possible other mentions of the active window
[oldlist.remove(l) for l in oldlist if l.startswith(top.split()[0])]
open(rootdata, "wt").write(("\n").join([top]+oldlist))
Сценарий 2; сценарий действия, сохраните его как next_focus.py
В одном и том же каталоге как сценарий 1.
#!/usr/bin/env python3
import subprocess
import focus_track
# read existing windows and their order (x-wise) from file
windows = [w.split() for w in focus_track.read_data()]
w_data = [[w[0], int(w[2])] for w in windows]
# get position of currently focussed window
currfocus = focus_track.get_top(focus_track.current_windows().splitlines()).split()[2]
# get screendata
screens = focus_track.get_screendata()
def screen_pos(x):
return [(int(x) > n) for n in screens].count(True)
scr_position = screen_pos(currfocus)
next_screen = 1 if scr_position == len(screens) else scr_position+1
try:
next_focus = [w for w in w_data if screen_pos(w[1]) == next_screen][0]
subprocess.Popen(["wmctrl", "-ia", next_focus[0]])
except IndexError:
subprocess.Popen(["notify-send", "No window to focus on next screen"])
Потребности сценариев wmctrl
быть установленным
sudo apt-get install wmctrl
focus_track.py
. Имя важно, начиная с обеих функций доли сценариев; сценарий 1 импортируется в сценарий 2.next_focus.py
в одном и том же каталоге как сценарий 1.Тестовый прогон установка: N.B. Запустите фоновый сценарий прежде, чем открыться (и таким образом сфокусироваться) окна. Windows, открытый перед фоновыми запусками сценария, не "зарегистрирован", непока они не фокусируются
Запустите фоновый сценарий (с, например, терминал) с командой:
python3 /path/to/focus_track.py
На Ваших различных экранах откройте окна.
Выполненный сценарий 2 с командой:
python3 /path/to/next_focus.py
Фокус должен переключиться на следующий экран. Если текущий экран является последним в строке, фокус переключается на первый экран.
Если все хорошо работает, добавьте сценарий 1 для Запущения Приложений: Тире> Приложения Запуска> Добавляет команду:
python3 /path/to/focus_track.py
и добавьте сценарий 2 к сочетанию клавиш: выберите: Параметры настройки системы> "Клавиатура"> "Ярлыки"> "Пользовательские Ярлыки". Нажмите "+" и добавьте команду:
python3 /path/to/next_focus.py
к сочетанию клавиш Вашей симпатии.
Для переключения фокуса от одного экрана до другого необходимо определить, который является передней стороной большая часть окна на экран. Главная проблема однако, что окна, распространенные по нескольким экранам, на самом деле все в одном и тот же стек, и таким образом заказаны в одной и той же последовательности (z-wise). Инструменты мы имеем (wmctrl
, xdotool
, xprop
и т.д.) в лучшем случае может только определить в настоящее время активное окно. Они не дают нам информации вообще о порядке окна на другие экраны, так как окна ниже активного окна.
Поэтому на первый взгляд кажется довольно невозможным переключить фокус от одного экрана до другого.
Однако:
С обходным решением однако, существует Escape: если мы заставляем фоновый сценарий отслеживать в настоящее время фокусируемое окно и поддержать запись истории изменений (столько, сколько окно существует), мы на самом деле можем завершить то, что является z-порядком в настоящее время открываемых окон. Если мы также отслеживаем их геометрию и положение, у нас есть вся информация, в которой мы нуждаемся.
Пример:
У нас в настоящее время есть пять окон: A, B, C, D, E. Если их фокус изменяется через D, E, A, C, B, мы знаем, что z-порядок окон: B, C, A, E, D (по всей длине)
Вместе с их положениями (x-wise) и экранными данными (x-разрешение экранов) у нас есть вся информация, в которой мы нуждаемся. Для переключения фокуса на следующий экран мы затем просто должны искать первое окно, расположенное на следующем экране.