
이는 다음과 유사합니다.키보드만 사용하여 창을 다른 화면에 빠르게 배치, 그러나 나는 명령줄을 사용할 수 있기를 원합니다(그래서 내가 해야 할 일은 bash 기록에서 명령줄을 불러오는 것뿐입니다).
예를 들어, 보내다
- 모든 그놈 터미널 창을
eDP1
, - 모든 Emacs 창을
VGA1
, 및 - 모든 Chrome 창
HDMI1
(그리고 이동한 후에 최대화합니다. 그러나 F11일반적인 창 관리자 스타일 최대화와 같은 이상한 방법은 아닙니다.)
실행 파일 이름으로 창을 지정하고 싶습니다.
답변1
특정 창 클래스의 모든 창을 (화면-) 이름별로 특정 화면으로 이동
WM_CLASS
아래 스크립트는 특정 (응용 프로그램)에 속한 창을 특정 화면으로 보냅니다 .이름. 그 방법은 스크립트와 아래에 자세히 설명되어 있습니다.
스크립트는 화면이 수평으로 배열되어 있고 어느 정도 위쪽에 정렬되어 있다고 가정합니다(차이 < 100 PX).
스크립트
#!/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-) 위치를 조회하고 특정 클래스의 모든 창(-id's)을 조회합니다( wmctrl -l
및 의 출력을 사용하여 xprop -id <window_id>
.
그런 다음 스크립트는 모든 창을 대상 화면의 위치로 하나씩 이동하고( 사용 wmctrl -ir <window_id> -e 0,<x>,<y>,<width>,<height>
) 이를 최대화합니다( 사용 xdotool windowsize 100% 100%
).
메모
스크립트는 제가 실행한 테스트에서 잘 작동했습니다. Unity에서 wmctrl
, 심지어 를 사용하면 xdotool
몇 가지 완고한 특성이 있을 수 있지만 때로는 추론보다는 실험을 통해 해결해야 합니다. 예외가 발생할 수 있는 경우 언급해 주세요.
답변2
@jacobs Python 코드를 간단한 bash로 다시 작성하여 작동하도록 했습니다(우분투 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"
답변3
기록을 위해 이 질문과다중 모니터 설정 복원:
# configure multiple 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()
답변4
@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
}