
Das ist ähnlich wiePlatzieren Sie ein Fenster schnell auf einem anderen Bildschirm, indem Sie nur die Tastatur verwenden, aber ich möchte die Befehlszeile verwenden können (so dass ich nur die Befehlszeile aus dem Bash-Verlauf abrufen muss).
Senden Sie beispielsweise
- alle Gnome-Terminalfenster zu
eDP1
, - alle Emacs-Fenster zu
VGA1
, und - alle Chrome-Fenster auf
HDMI1
(und maximieren Sie sie nach dem Verschieben – aber nicht auf die verrückte F11Art, sondern die normale Maximierung im Fenstermanager-Stil).
Ich möchte Windows anhand des ausführbaren Namens angeben.
Antwort1
Verschieben aller Fenster einer bestimmten Fensterklasse auf einen bestimmten Bildschirm anhand des (Bildschirm-)Namens
Das folgende Skript sendet Fenster, die zu einer bestimmten WM_CLASS
(Anwendung) gehören, an einen bestimmten Bildschirm, und zwar über denName. Wie das geht, wird im Skript und auch weiter unten erklärt.
Das Skript geht davon aus, dass die Bildschirme horizontal angeordnet und mehr oder weniger oben ausgerichtet sind (mit einem Unterschied von < 100 PX).
Das Drehbuch
#!/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%"])
Wie benutzt man
Das Skript benötigt beides
wmctrl
undxdotool
:sudo apt-get install xdotool wmctrl
Kopieren Sie das folgende Skript in eine leere Datei und speichern Sie es unter
move_wclass.py
Führen Sie es mit dem folgenden Befehl aus:
python3 /path/to/move_wclass.py <WM_CLASS> <targeted_screen>
Zum Beispiel:
python3 /path/to/move_wclass.py gnome-terminal VGA-1
Für WM_CLASS
können Sie verwenden:Teildes WM_CLASS
, wie im Beispiel. Der Name des Bildschirms muss dergenauund vollständiger Name.
Wie es gemacht wird (das Konzept)
Die Erklärung bezieht sich hauptsächlich auf das Konzept und nicht so sehr auf die Codierung.
In der Ausgabe von xrandr gibt es für jeden verbundenen Bildschirm eine Zeichenfolge/Zeile, die wie folgt aussieht:
VGA-1 connected 1280x1024+1680+0
Diese Zeile gibt uns Informationen über den BildschirmPositionund seinName, wie erklärtHier.
Das Skript listet die Informationen für alle Bildschirme auf. Wenn das Skript mit dem Bildschirm und der Fensterklasse als Argumente ausgeführt wird, sucht es die (x-)Position des Bildschirms, sucht alle Fenster (-id's) einer bestimmten Klasse (mithilfe von wmctrl -l
und der Ausgabe von xprop -id <window_id>
).
Anschließend verschiebt das Skript alle Fenster nacheinander an eine Position auf dem Zielbildschirm (mit wmctrl -ir <window_id> -e 0,<x>,<y>,<width>,<height>
) und maximiert diese (mit xdotool windowsize 100% 100%
).
Notiz
Das Skript funktionierte bei den Tests, mit denen ich es ausgeführt habe, einwandfrei. Die Verwendung von wmctrl
und sogar xdotool
mit Unity kann jedoch einige hartnäckige Eigenheiten aufweisen, die manchmal eher durch Experimente als durch Argumentation gelöst werden müssen. Wenn Sie auf Ausnahmen stoßen, geben Sie dies bitte an.
Antwort2
Ich habe den Python-Code von @jacobs in einfaches Bash umgeschrieben und zum Laufen gebracht (ich habe dies auf Ubuntu 16 Cinnamon getestet).
Ich musste hinzufügen, remove,maximized_vert, remove,maximized_horz
dass sich die Fenster ohne dieses nicht bewegten.
#!/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"
Antwort3
Fürs Protokoll: Hier ist, was ich für die Kombination dieser Frage verwende undWiederherstellen mehrerer Monitoreinstellungen:
# 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()
Sie müssten verwendenwmctrlVersion 0.3 oder höher (aufgrund meinerPull-Anfrage).
Antwort4
Basierend auf der Antwort von @AndrzejPiszczek gibt es folgende Möglichkeit, alle Fenster auf einen bestimmten Bildschirm zu verschieben:
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
}