有没有办法防止连接外接显示器时窗口移动?

有没有办法防止连接外接显示器时窗口移动?

因此,我在笔记本电脑上使用 Ubuntu 14.10,偶尔会将其插入电视作为第二个屏幕。我的电视在办公桌的左侧。当我将其作为笔记本电脑屏幕左侧的外接显示器启用时,笔记本电脑屏幕上的所有窗口都会移到电视屏幕上。我可以将它们移回,但每次都必须这样做真的很烦人,尤其是当打开了多个窗口时。

左边有电视

但是,如果我将电视屏幕(虚拟地)设置在笔记本电脑屏幕的右侧,窗口就不会移动。但这在使用上很容易让人困惑,因为它与物理设置相反。另外,我不想移动我的办公桌。

右边有电视

Ubuntu 或显示服务器似乎只是假设最左边的显示器是主显示器,所有窗口都应位于该显示器上。有没有办法禁用此行为?

我一直在查看这些论坛,但真的没看到有人发帖讨论这个问题。我找到的最接近的帖子是这个,虽然它不是完全相同的问题。

让 Ubuntu 在关闭多台显示器之一时不移动窗口

有人有什么想法吗?如果有的话请告诉我。谢谢!

答案1

我没有找到“秘密”设置来改变看起来设计的行为。看起来确实好像左侧屏幕被假定为“基本”屏幕。

但是,完全可以创建一个解决方法,结果基本相同。您可以创建一个脚本,在连接第二个屏幕时列出所有窗口。随后,最初移动到左侧屏幕的所有窗口将在一两秒内移回右侧屏幕。所有窗口的大小都将保留。
这就是下面的脚本所做的。

两个版本

您可以通过两种方式恢复排列好的窗口:

  • 偶尔用第二个屏幕连接后用快捷键运行。
  • 自动在后台运行脚本,等待您的屏幕连接。

如何使用

准备工作

  • 安装wmctrl

    sudo apt-get 安装 wmctrl

  • 借助 查找两个屏幕的名称xrandr,屏幕名称将位于“连接”一词之前。

  • 复制下面任一脚本,在头部部分,将这两行屏幕名称替换为正确的名称:

    screen_1 = "LVDS1"     # your main screen (laptop)
    screen_2 = "VGA1"      # secundary screen (on the left)
    

    另存脚本为move_windows.py

  • 确保在显示设置中您的辅助屏幕位于左侧。两个屏幕的顶行需要对齐(如问题的第一张图片所示)。

运行脚本
- 如果您偶尔使用其中一个运行,请在第二个屏幕连接后运行它。

    python3 /path/to/move_windows.py

如果您认为它可以完成应有的功能,则可能需要将其添加到键盘快捷键中,选择:系统设置 > “键盘” > “快捷键” > “自定义快捷键”。单击“+”并添加命令:

  • 如果使用后台运行,也可以通过以下命令运行它:

    python3 /path/to/move_windows.py
    

    如果它按照你的预期运行,请将其添加到你的启动应用程序中:Dash > 启动应用程序 > 添加

我使用我的笔记本电脑(右侧)和两个不同的屏幕(左侧)测试了该脚本。结果是一样的。

笔记本电脑屏幕

在此处输入图片描述

无需脚本即可连接

在此处输入图片描述

连接正在运行的脚本

在此处输入图片描述

脚本完成其工作后,窗口将“保持不变”(当然),您可以按照自己的方式排列窗口。

脚本

1.“手动”版本,连接屏幕后运行

#!/usr/bin/env python3
import subprocess
import time

#--
screen_2 = "LVDS1"       # replace with your internal screen (right)
screen_2 = "VGA1"        # replace with your external screen (left)
#--

def get(cmd):
    return subprocess.check_output(["/bin/bash", "-c",  cmd]).decode("utf-8")

def get_shift(xr_output):
    lines = [l for l in xr_output.splitlines() if " connected" in l][0].split()
    return int([it for it in lines if "x" in it][0].split("x")[0])

def shift_windows(shift):
    w_data = [l.split() for l in get("wmctrl -lG").splitlines()]
    relevant = []
    for w in w_data:
        props = get("xprop -id "+w[0])
        if (int(w[2]) < shift, "_TYPE_NORMAL" in props, "TYPE_DIALOG" in props).count(True) == 2:
            command = "wmctrl -ir "+w[0]+" -e 0,"+(",").join([str(int(w[2])+shift), w[3], w[4], w[5]])
            subprocess.Popen(["/bin/bash", "-c", command])

shift_windows(get_shift(get("xrandr")))

2. 自动化版本,在后台运行

#!/usr/bin/env python3
import subprocess
import time

#--
screen_2 = "LVDS1"       # replace with your internal screen (right)
screen_2 = "VGA1"        # replace with your external screen (left)
#--

def get(cmd):
    return subprocess.check_output(["/bin/bash", "-c",  cmd]).decode("utf-8")

def get_shift(xr_output):
    lines = [l for l in xr_output.splitlines() if " connected" in l][0].split()
    return int([it for it in lines if "x" in it][0].split("x")[0])

def shift_windows(shift):
    w_data = [l.split() for l in get("wmctrl -lG").splitlines()]
    relevant = []
    for w in w_data:
        props = get("xprop -id "+w[0])
        if (int(w[2]) < shift, "_TYPE_NORMAL" in props, "TYPE_DIALOG" in props).count(True) == 2:
            command = "wmctrl -ir "+w[0]+" -e 0,"+(",").join([str(int(w[2])+shift), w[3], w[4], w[5]])
            subprocess.Popen(["/bin/bash", "-c", command])

while True:
    try:
        screen_info1 = get("xrandr")
        time.sleep(5)
        screen_info2 = get("xrandr")
        check = screen_2+" connected"
        if (check in screen_info1, check in screen_info2) == (False, True):
            time.sleep(5)
            shift_windows(get_shift(screen_info2))
    except:
        pass

答案2

我有多个显示器连接到 HDMI 开关,每当我从一个设备切换到另一个设备时,前一个设备的行为就像显示器已关闭一样。所以我想在我的笔记本电脑上安装类似的功能(我在那里使用两个屏幕)

@JacobVlijm 不是我想要的,但基于沉重在此基础上我编写了一个 bash 脚本来将一些(或所有)窗口从一个屏幕移动到另一个屏幕。功能:

  • 它不关心“左和右”,只关心“从和到”。
  • 可以过滤要移动的应用程序
  • 是否能最好地保留窗口大小(最大化时完美运行,不最大化时效果一般)
  • 可以在 bash_aliases 中使用,这样你就不必记住脚本在哪里

要旨

代码

screen_from=${1:-'eDP-1'}
screen_to=${2:-'HDMI-1'}

echo "Moving windows from $screen_from to $screen_to"

apps_to_move=("Firefox" "Gnome-terminal" "Slack" "Sublime_text" "Terminator" "Thunderbird" "Mysql-workbench")

dimensions=`xrandr --listmonitors | grep $screen_to | cut -d ' ' -f4`
width=$(echo $dimensions | cut -f1 -d '/')
height=$(echo $dimensions | cut -f2 -d '/' |cut -f2 -d'x')
offset_x=$(echo $dimensions | cut -f2 -d '+')
offset_y=$(echo $dimensions | cut -f3 -d '+')

dimensions=`xrandr --listmonitors | grep $screen_from | cut -d ' ' -f4`
width_from=$(echo $dimensions | cut -f1 -d '/')
height_from=$(echo $dimensions | cut -f2 -d '/' |cut -f2 -d'x')
offset_x_from=$(echo $dimensions | cut -f2 -d '+')
offset_y_from=$(echo $dimensions | cut -f3 -d '+')

# Parameters: app_name (WM_CLASS or id)
move_window() {
    local app_name=$1

    # Looks for all windows of a given app (only need when WM_CLASS is provided)
    for app in `wmctrl -lGx | grep $app_name | tr -s ' ' | cut -d ' ' -f1`; do
        echo "Processing $app_name - ID: $app"

        cur_offset_x=`wmctrl -lGx | grep $app | tr -s ' ' | cut -d ' ' -f3`

        # Skip if window is already on dest screen
        if [[ $cur_offset_x -lt $offset_x_from ]]; then
            echo "$app is already on desired screen"
            continue
        fi

        echo "Moving $app"
        cur_width=`wmctrl -lGx | grep $app | tr -s ' ' | cut -d ' ' -f5`
        cur_height=`wmctrl -lGx | grep $app | tr -s ' ' | cut -d ' ' -f6`

        # echo "Cur width: $cur_width - Cur height: $cur_height"
        # echo "Width from: $width_from - Height from: $height_from"

        # Needed because otherwise wmctrl doesn't move the window
        wmctrl -ir $app -b remove,maximized_vert,maximized_horz

        # If app is maximized then it should be maximized in dest screen
        # 100 is the threshold to consider "maximized" because taskbars add offsets to windows
        if (( ($width_from - $cur_width < 100) && ($height_from - $cur_height < 100) )); then
            echo "App should be maximized"
            wmctrl -ir $app -e 0,$offset_x,$offset_y,-1,-1
            wmctrl -ir $app -b add,maximized_vert,maximized_horz
        else
            # Instead of keeping the original size I chose to preserve it's ratio in the source screen
            echo "App should preserve it's original size (ratio)"
            new_width=`bc <<< $width*$cur_width/$width_from`
            new_height=`bc <<< $height*$cur_height/$height_from`
            wmctrl -ir $app -e 0,$offset_x,$offset_y,$new_width,$new_height
        fi
    done
}

# If apps_to_move is not empty, use it
if (( ${#apps_to_move[@]} > 0 )); then
    echo "Using apps_to_move"
    for app in "${apps_to_move[@]}"; do
        move_window $app x
    done
# Else, move everything
else
    for app in `wmctrl -l | cut -d ' ' -f 1`; do
        move_window $app i
    done
fi

相关内容