Это подобно для быстрого размещения окна в другой экран с помощью только клавиатуру, но я хочу смочь использовать командную строку (так, чтобы все, что я должен сделать, вспомнило командную строку из истории удара).
Например, отправить
eDP1
, VGA1
, и HDMI1
(и максимизируйте их после перемещения - но не сумасшедший путь F11, нормальная максимизация стиля менеджера окон).
Я хотел бы указать окна исполняемым именем.
Сценарий ниже отправит окна, принадлежа определенному WM_CLASS
(приложение), на определенный экран, именем экрана. То, как это сделано, объяснено в сценарии и также далее ниже.
Сценарий предполагает, что экраны расположены горизонтально и более или менее главные - выровненный (с различием <100 ПКС).
#!/usr/bin/env python3
import subprocess
import sys
# just a helper function, to reduce the amount of code
get = lambda cmd: subprocess.check_output(cmd).decode("utf-8")
# get the data on all currently connected screens, their x-resolution
screendata = [l.split() for l in get(["xrandr"]).splitlines() if " connected" in l]
screendata = sum([[(w[0], s.split("+")[-2]) for s in w if s.count("+") == 2] for w in screendata], [])
def get_class(classname):
# function to get all windows that belong to a specific window class (application)
w_list = [l.split()[0] for l in get(["wmctrl", "-l"]).splitlines()]
return [w for w in w_list if classname in get(["xprop", "-id", w])]
scr = sys.argv[2]
try:
# determine the left position of the targeted screen (x)
pos = [sc for sc in screendata if sc[0] == scr][0]
except IndexError:
# warning if the screen's name is incorrect (does not exist)
print(scr, "does not exist. Check the screen name")
else:
for w in get_class(sys.argv[1]):
# first move and resize the window, to make sure it fits completely inside the targeted screen
# else the next command will fail...
subprocess.Popen(["wmctrl", "-ir", w, "-e", "0,"+str(int(pos[1])+100)+",100,300,300"])
# maximize the window on its new screen
subprocess.Popen(["xdotool", "windowsize", "-sync", w, "100%", "100%"])
Для сценария нужны оба wmctrl
и xdotool
:
sudo apt-get install xdotool wmctrl
Скопируйте сценарий ниже в пустой файл, сохраните его как move_wclass.py
Выполните его командой:
python3 /path/to/move_wclass.py <WM_CLASS> <targeted_screen>
например:
python3 /path/to/move_wclass.py gnome-terminal VGA-1
Для WM_CLASS
, можно использовать часть WM_CLASS
, как в примере. Имя экрана должно быть точным и полным именем.
Объяснение находится главным образом на понятии, не так на кодировании.
В выводе xrandr, для каждого связанного экрана, существует строка/строка, будучи похож:
VGA-1 connected 1280x1024+1680+0
Эта строка дает нам информацию о положении экрана и его имени, как объяснено здесь.
Сценарий перечисляет информацию для всех экранов. То, когда скрипт запущен с экраном и классом окна как аргументы, он ищет (x-) положение экрана, ищет все окна (-идентификатор) определенного класса (с помощью wmctrl -l
и вывод xprop -id <window_id>
.
Впоследствии, сценарий перемещает все окна, один за другим, к позиции по целенаправленному экрану (использование wmctrl -ir <window_id> -e 0,<x>,<y>,<width>,<height>
) и максимизирует его (с xdotool windowsize 100% 100%
).
Сценарий хорошо работал на тестах, с которыми я запустил его. Используя wmctrl
, и даже xdotool
, на Единице может иметь некоторые упрямые особенности однако, которые иногда должны решаться экспериментом вместо обоснования. Если Вы могли бы столкнуться с исключениями, упомяните.
Я имею rewrited @jacobs код Python к простому удару и делаю его работами (я протестировал это на корице человечности 16).
я должен был добавить remove,maximized_vert, remove,maximized_horz
, без которого не перемещались окна.
#!/bin/bash
if [ ! -z "$1" ] || [ -z "$2" ]; then
command=$(wmctrl -l | grep $1 | cut -d" " -f1)
if [ ! -z "$command" ]; then
position=$(xrandr | grep "^$2" | cut -d"+" -f2)
if [ ! -z "$position" ]; then
for window in $command; do
wmctrl -ir $window -b remove,maximized_vert
wmctrl -ir $window -b remove,maximized_horz
wmctrl -ir $window -e 0,$position,0,1920,1080
wmctrl -ir $window -b add,maximized_vert
wmctrl -ir $window -b add,maximized_horz
done
else
echo -e "not found monitor with given name"
fi
else
echo -e "not found windows with given name"
fi
else
echo -e "specify window and monitor name;\nmove.sh window-name monitor-name"
fi
sudo apt-get install xdotool wmctrl
/path/to/script.sh "window-name" "monitor-name"
Для записи вот то, что я использую для комбинации этого вопроса и Восстановления несколько настроек монитора:
# configure multiplr displays and
# move the windows to their appropriate displays
import subprocess
import os
import wmctrl
import re
mydisplays = [("VGA1",0,"left"),
("eDP1",1080,"normal"),
("HDMI1",3000,"left")]
# https://askubuntu.com/questions/702002/restore-multiple-monitor-settings
def set_displays ():
subprocess.check_call(" && ".join([
"xrandr --output %s --pos %dx0 --rotate %s" % d for d in mydisplays]),
shell=True)
# https://askubuntu.com/questions/702071/move-windows-to-specific-screens-using-the-command-line
mywindows = [("/emacs$","VGA1"),
("/chrome$","HDMI1"),
("gnome-terminal","eDP1")]
def max_windows ():
didi = dict([(d,x) for d,x,_ in mydisplays])
for w in wmctrl.Window.list():
try:
exe = os.readlink("/proc/%d/exe" % (w.pid))
for (r,d) in mywindows:
if re.search(r,exe):
x = didi[d]
print "%s(%s) --> %s (%d)" % (r,exe,d,x)
w.set_properties(("remove","maximized_vert","maximized_horz"))
w.resize_and_move(x,0,w.w,w.h)
w.set_properties(("add","maximized_vert","maximized_horz"))
break
except OSError:
continue
def cmdlines (cmd):
return subprocess.check_output(cmd).splitlines()
def show_displays ():
for l in cmdlines(["xrandr"]):
if " connected " in l:
print l
if __name__ == '__main__':
show_displays()
set_displays()
show_displays()
max_windows()
необходимо было бы использовать wmctrl версию 0.3 или позже (из-за моего запроса получения по запросу).
Основываясь на ответе @AndrzejPiszczek, вот способ переместить все окна на определенный экран:
function move_win {
if [ -z "$1" ]; then
echo -e "Specify a screen, possible options: "
echo -e $(xrandr | grep " connected " | cut -d'-' -f1)
return
fi
MONITOR=$1
# get all relevant windows on all screens
windows=$(wmctrl -l | egrep -v " -1 " | cut -d" " -f1)
if [ ! -z "$windows" ]; then
# get the necessary metrics from the screen the windows should be moved to
# will contain: width, height, offsetX, offsetY
screen_values=($(xrandr | grep "^$MONITOR-.* connected" | grep -Eo '[0-9]+x[0-9]+\+[0-9]+\+[0-9]+' | sed 's/x/ /g; s/+/ /g'))
if (( ${#screen_values[@]} )); then
# get the start/end position of the screen so we can later determine
# if the window is already on the screen or not
screen_start_pos=$(( ${screen_values[2]} ))
screen_end_pos=$(( ${screen_values[2]} + ${screen_values[0]} ))
for window in $windows; do
# get the window name
window_name=$(wmctrl -lG | grep "$window" | awk -F "$HOSTNAME " '{print $2}')
# extract relevant window geometry values such as x, y, width, height
window_values=($(wmctrl -lG | grep "$window" | awk -F " " '{print $3, $5, $6}'))
# if the window's X origin position is already inside the screen's
# total width then don't move it (this won't work exactly for windows only partially on the screen)
if (( ${window_values[0]} >= $screen_end_pos || ${window_values[0]} < $screen_start_pos )); then
echo -e "Moving to screen $MONITOR: $window_name"
wmctrl -ir $window -b remove,maximized_vert
wmctrl -ir $window -b remove,maximized_horz
# the -e parameters are gradient,x,y,width,height
# move window to (X,Y) -> (0,0) of new screen and the same window dimensions
wmctrl -ir $window -e 0,$screen_start_pos,0,${window_values[1]},${window_values[2]}
else
echo -e "Already on screen $MONITOR: $window_name"
fi
done
else
echo -e "No screen found"
fi
else
echo -e "No windows found"
fi
}