使用命令行将窗口移动到特定屏幕

这类似于仅使用键盘快速将窗口放置到另一个屏幕 ,但我希望能够使用命令行(因此我需要做的就是从bash历史记录中调用命令行)。

例如,发送

  • 所有gnome终端窗口到eDP1
  • 所有Emacs窗口到VGA1 ,和
  • 所有Chrome窗口都支持HDMI1

(并在移动后最大化它们 – 但不是疯狂的F11方式,正常的窗口管理器式最大化)。

我想用可执行文件名指定windows。

通过(屏幕)名称将特定窗口类的所有窗口移动到特定屏幕

下面的脚本将通过屏幕名称将属于特定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%"]) 

如何使用

  1. 该脚本需要wmctrlxdotool

     sudo apt-get install xdotool wmctrl 
  2. 将下面的脚本复制到一个空文件中,将其另存为move_wclass.py

  3. 通过命令运行它:

     python3 /path/to/move_wclass.py   

    例如:

     python3 /path/to/move_wclass.py gnome-terminal VGA-1 

对于WM_CLASS ,您可以使用WM_CLASS 一部分 ,如示例中所示。 屏幕名称必须是完整且完整的名称。

怎么做(概念)

解释主要是关于概念,而不是编码。

在xrandr的输出中,对于每个连接的屏幕,都有一个字符串/行,如下所示:

 VGA-1 connected 1280x1024+1680+0 

这条线为我们提供了有关屏幕位置名称的信息 ,如此处所述。

该脚本列出了所有屏幕的信息。 当脚本以屏幕和窗口类作为参数运行时,它会查找屏幕的(x-)位置,查找某个类的所有窗口(-id)(在wmctrl -l的帮助下)输出xprop -id

随后,脚本将所有窗口逐个移动到目标屏幕上的某个位置(使用wmctrl -ir -e 0,,,, )并最大化它(使用xdotool windowsize 100% 100% )。

注意

该脚本在我运行它的测试中运行良好。 在Unity上使用wmctrl甚至xdotool可能会有一些顽固的特性,但有时需要通过实验而不是推理来解决。 如果您遇到exception,请提及。

为了记录,这里是我用来组合这个问题和恢复多个监视器设置 :

 # 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,ww,wh) 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或更高版本(因为我的拉取请求 )。

我已经将@jacobs python代码重写为简单的bash并使其工作(我在ubuntu 16肉桂上测试过这个)。

我不得不添加remove,maximized_vert, remove,maximized_horz而Windows没有移动。

 #!/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 
  1. sudo apt-get install xdotool wmctrl
  2. /path/to/script.sh "window-name" "monitor-name"