AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / ubuntu / 问题 / 702071
Accepted
sds
sds
Asked: 2015-11-25 10:22:01 +0800 CST2015-11-25 10:22:01 +0800 CST 2015-11-25 10:22:01 +0800 CST

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

  • 772

这类似于Quickly place a window to another screen using only the keyboard,但我希望能够使用命令行(这样我需要做的就是从 bash 历史记录中调用命令行)。

例如,发送

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

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

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

command-line
  • 4 4 个回答
  • 11219 Views

4 个回答

  • Voted
  1. Best Answer
    Jacob Vlijm
    2015-11-26T02:18:46+08:002015-11-26T02:18:46+08:00

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

    下面的脚本将通过屏幕名称将属于特定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. 该脚本同时需要wmctrl和xdotool:

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

    3. 通过命令运行它:

      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
    

    此行向我们提供有关屏幕位置及其名称的信息,如此处所述。

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

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

    笔记

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

    • 11
  2. Andrzej Piszczek
    2018-10-22T23:20:41+08:002018-10-22T23:20:41+08:00

    我已经将 @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
    
    1. sudo apt-get install xdotool wmctrl
    2. /path/to/script.sh "window-name" "monitor-name"
    • 6
  3. sds
    2015-11-26T07:43:10+08:002015-11-26T07:43:10+08:00

    作为记录,这里是我用来组合这个问题和恢复多显示器设置的方法:

    # 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()
    

    您需要使用wmctrl 0.3 或更高版本(因为我的请求请求)。

    • 1
  4. wasp256
    2020-09-19T04:22:25+08:002020-09-19T04:22:25+08:00

    根据@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
    }
    
    • 1

相关问题

  • 如何从命令行仅安装安全更新?关于如何管理更新的一些提示

  • 如何从命令行刻录双层 dvd iso

  • 如何从命令行判断机器是否需要重新启动?

  • 文件权限如何工作?文件权限用户和组

  • 如何在 Vim 中启用全彩支持?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Martin Hope
    Flimm 如何在没有 sudo 的情况下使用 docker? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve