因此,我在笔记本电脑上使用 Ubuntu 14.10,偶尔会将其插入电视作为第二个屏幕。我的电视在办公桌的左侧。当我将其作为笔记本电脑屏幕左侧的外接显示器启用时,笔记本电脑屏幕上的所有窗口都会移到电视屏幕上。我可以将它们移回,但每次都必须这样做真的很烦人,尤其是当打开了多个窗口时。
但是,如果我将电视屏幕(虚拟地)设置在笔记本电脑屏幕的右侧,窗口就不会移动。但这在使用上很容易让人困惑,因为它与物理设置相反。另外,我不想移动我的办公桌。
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