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

sds*_*sds 9 command-line window-manager multiple-monitors window-management

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

例如,发送

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

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

我想通过可执行文件名称指定窗口。

Jac*_*ijm 10

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

下面的脚本将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%"])
Run Code Online (Sandbox Code Playgroud)

如何使用

  1. 该脚本需要wmctrlxdotool

    sudo apt-get install xdotool wmctrl
    
    Run Code Online (Sandbox Code Playgroud)
  2. 将下面的脚本复制到一个空文件中,另存为 move_wclass.py

  3. 通过以下命令运行它:

    python3 /path/to/move_wclass.py <WM_CLASS> <targeted_screen>
    
    Run Code Online (Sandbox Code Playgroud)

    例如:

    python3 /path/to/move_wclass.py gnome-terminal VGA-1
    
    Run Code Online (Sandbox Code Playgroud)

对于WM_CLASS,你可以使用部分WM_CLASS在本例中,等等。屏幕名称必须是准确且完整的名称。

如何完成(概念)

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

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

VGA-1 connected 1280x1024+1680+0
Run Code Online (Sandbox Code Playgroud)

此行让我们在屏幕上的信息位置和它的名字,如解释在这里

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

随后,脚本将所有窗口一个接一个地移动到目标屏幕上的某个位置(使用wmctrl -ir <window_id> -e 0,<x>,<y>,<width>,<height>)并将其最大化(使用xdotool windowsize 100% 100%)。

笔记

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


小智 5

我已将@jacobs python 代码重写为简单的 bash 并使其正常工作(我在 ubuntu 16 cinnamon 上对此进行了测试)。

我不得不补充说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
Run Code Online (Sandbox Code Playgroud)
  1. sudo apt-get install xdotool wmctrl
  2. /path/to/script.sh "window-name" "monitor-name"


归档时间:

查看次数:

8633 次

最近记录:

5 年,1 月 前