![如何将所有窗口移动到另一个工作区](https://linux22.com/image/1120817/%E5%A6%82%E4%BD%95%E5%B0%86%E6%89%80%E6%9C%89%E7%AA%97%E5%8F%A3%E7%A7%BB%E5%8A%A8%E5%88%B0%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%B7%A5%E4%BD%9C%E5%8C%BA.png)
是否可以将所有窗口(或所有未最小化的窗口)从一个工作区移动到另一个工作区?
Shift我知道我可以使用+ Ctrl+ Alt+把一个窗口移动到其他工作区arrow,但它只会移动那个焦点窗口。
答案1
Unity: 什么是视口?
Ubuntu Unity 使用视口 - 基本上是一个坐标系统(坐标 0,0 为左上角),其中一个巨大的桌面被细分为适合您的屏幕分辨率的块。当您向右和向下移动时,坐标值会增加。
坐标系是相对的。如果我当前的视口是左上角,则相对于该视口的所有内容都将是宽度和高度递增的正值。例如,如果我当前的视口是最左上角,则您在上面看到的中上工作区中的 Firefox 窗口相对于最左上角的视口位于 x 值 1366 和 y 值 0 处。如果我的活动视口是中上角的,则最左上角视口中的终端窗口位于 x 值 -1327 60 处。 这是关键问题xdotool
,因为xdotool
它不处理负数。
还要注意,xdotool 将始终假定当前视口的左上角为坐标 0 0 。这意味着我们只能向右和向下移动东西。
使 xdotool 适用于 Unity
现在我们知道xdotool
只能相对于左上角移动窗口(即,您始终可以向下和向右移动窗口,但不能向上和向左移动窗口)。我们如何才能使它适用于统一。嗯,基本的想法是
- 找出当前视口上的所有窗口
- 暂时移动到请求的视口,使左上角在该视口处假设坐标为 0 0
- 将所有窗口移动到用户定义的视口坐标
- 返回旧视口(可选,也可以跟随窗口)
脚本解决方案
下面的脚本执行的正是上面描述的过程。可以使用-v
标志来手动指定坐标,也可以使用-g
标志来调出 GUI 对话框。-f
标志也会告诉脚本切换视口;如果不使用该标志 - 您将停留在当前视口上,并且只有窗口会移动
获取脚本
可以直接从本文复制源代码,或者通过 github 按照以下步骤复制:
sudo apt-get install git
cd /opt ; sudo git clone https://github.com/SergKolo/sergrep.git
sudo chmod -R +x sergrep
脚本文件将是/opt/sergrep/move_viewport_windows.sh
要将脚本绑定到快捷方式,请参阅如何将 .sh 文件绑定到键盘组合?
请注意,此脚本需要wmctrl
和xdotool
才能正常工作。您可以通过 sudo apt-get install xdotool 和 wmctrl 安装它们
源代码
#!/usr/bin/env bash
#
###########################################################
# Author: Serg Kolo , contact: [email protected]
# Date: April 17 2016
# Purpose: Move all windows on the current viewport
# to a user-defined one
# Written for:
# Tested on: Ubuntu 14.04 LTS , Unity 7.2.6
###########################################################
# Copyright: Serg Kolo , 2016
#
# Permission to use, copy, modify, and distribute this software is hereby granted
# without fee, provided that the copyright notice above and this permission statement
# appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
get_active_viewport()
{
xprop -root -notype _NET_DESKTOP_VIEWPORT
}
get_screen_geometry()
{
xwininfo -root | awk '/-geometry/{gsub(/+|x/," ");print $2,$3}'
}
current_wins()
{
HEX="$(wmctrl -lG | \
awk -v xlim="$XMAX" -v ylim="$YMAX" \
'BEGIN{printf "ibase=16;"} $3>0 && $3<xlim && $4>0 && $4<ylim \
{ gsub(/0x/,""); printf "%s;",toupper($1) } ')"
echo $HEX | bc | tr '\n' ' '
}
gui_selection()
{
SCHEMA="org.compiz.core:/org/compiz/profiles/unity/plugins/core/"
read swidth sdepth <<< "$(get_screen_geometry)"
vwidth=$(gsettings get $SCHEMA hsize)
vheight=$(gsettings get $SCHEMA vsize)
width=0
for horizontal in $(seq 1 $vwidth); do
height=0
for vertical in $(seq 1 $vheight); do
array+=( FALSE )
array+=( $(echo "$width"x"$height") )
height=$(($height+$sdepth))
done
width=$(($width+$swidth))
done
zenity --list --radiolist --column="" --column "CHOICE" ${array[@]} --width 350 --height 350 2> /dev/null
}
print_usage()
{
cat << EOF
move_viewport_windows.sh [-v 'XPOS YPOS' ] [-g] [-f ] [-h]
Copyright Serg Kolo , 2016
The script gets list of all windows on the current Unity
viewport and moves them to user-specified viewport. If
ran without flags specified, script prints this text
-g flag brings up GUI dialog with list of viewports
-v allows manually specifying viewoport. Argument must be
quoted, X and Y position space separated
-f if set, the viewport will switch to the same one where
windows were sent
-h prints this text
** NOTE **
wmctrl and xdotool are required for this script to work
properly. You can install them via sudo apt-get install
xdotool and wmctrl
EOF
}
parse_args()
{
if [ $# -eq 0 ];then
print_usage
exit
fi
while getopts "v:ghf" opt
do
case ${opt} in
v) NEWVP=${OPTARG}
;;
g) NEWVP="$(gui_selection | tr 'x' ' ' )"
[ -z "$NEWVP" ] && exit 1
;;
f) FOLLOW=true
;;
h) print_usage
exit 0
;;
\?)
echo "Invalid option: -$OPTARG" >&2
;;
esac
done
shift $((OPTIND-1))
}
main()
{
# Basic idea:
#-------------------
# 1. get current viewport and list of windows
# 2. go to viewport 0 0 and move all windows from list
# to desired viewport
# 3. go back to original viewport or follow the windows,
# depending on user choice
# 4. Tell the user where they are currently
local FOLLOW
local NEWVP # coordinates of desired viewport
local XMAX YMAX # must be two vals for awk to work
local OLDVP=$(get_active_viewport | awk -F '=' '{sub(/,/," ");print $2}' )
parse_args "$@"
read XMAX YMAX <<< "$(get_screen_geometry)" # move to getopts
windows=( $(current_wins) )
xdotool set_desktop_viewport 0 0
for win in ${windows[@]} ; do
echo "$win"
xdotool windowmove $win $NEWVP
done
# sleep 0.25 # uncomment if necessary
if [ $FOLLOW ]; then
xdotool set_desktop_viewport $NEWVP
else
xdotool set_desktop_viewport $OLDVP
fi
sleep 0.25 # delay to allow catching active viewport
notify-send "current viewport is $(get_active_viewport | awk -F '=' '{sub(/,/," ");print $2}' )"
exit 0
}
main "$@"
演示
Webm 正在录制的脚本:
https://www.youtube.com/watch?v=cJMlC41CWWo
问题
由于 Unity 的grid
插件负责窗口捕捉,脚本无法移动最大化或右/左捕捉的窗口。将尝试添加该插件的瞬时取消设置和重置,以使脚本适用于所有窗口,但由于取消设置和重置有时间延迟,因此可能会放弃这个想法。如果您希望脚本适用于所有窗口,请unity-tweak-tool
在窗口管理器选项下安装和取消设置窗口捕捉。
答案2
非基于 Compiz 的桌面环境(XFCE、LXDE、GNOME、KDE……)
您可以结合使用wmctrl
和xdotool
。首先确保安装了这两个实用程序:
sudo apt-get install xdotool wmctrl
满足依赖关系后,您应该能够使用以下单行命令将当前桌面上的所有窗口移动到另一个桌面:
while read i; do wmctrl -i -t 2 -r "$i" ; done < <(wmctrl -l | awk -v var=$(xdotool get_desktop) '{if ($2 == var) print $0;}' | cut -d' ' -f1)
所用命令的快速分解:
wmctrl -l | awk -v var=$(xdotool get_desktop) '{if ($2 == var) print $0;}' | cut -d' ' -f1
列出所有窗口,过滤掉不在当前工作区中的窗口,并提取其窗口 ID
wmctrl -i -t 2 -r "$i"
将窗口 ID 为的窗口移动
$i
到工作区 2。所有这些都包含在一个简单的
while read ... do; done
循环中,该循环遍历当前桌面上的所有窗口
基于 Compiz 的桌面环境(例如 Unity)
由于 Compiz(Unity 的窗口管理器)的存在,为 Unity 等桌面环境寻找解决方案变得十分困难不以传统方式使用桌面。
答案3
我做了类似的事情谷氨酸的方法
下面是bash
执行该操作的脚本:
for window in `wmctrl -l | awk -v var=$(xdotool get_desktop) '{if ($2 == var) print $0;}' | cut -d' ' -f1`
do
target=$(($1-1))
wmctrl -i -t $target -r "$window"
done
wmctrl -s $target
只需运行它并传递目标窗口(基于 1 的索引)作为参数,如下所示:(bash move_ws.sh 3
将所有当前窗口移动到索引 3 中的工作区(从 1 开始计数))
然而,我认为,与其将所有窗口发送到某个工作区i
,不如交换相邻的工作区,这样更有用。
例如如果你当前在工作区2您的工作区如下(从左到右/从上到下):
1
2
3
4
您可以运行我的脚本bash swap_ws.sh down
(或者像我一样映射键盘快捷键)。并且2将与3:
1
3
2
4
理论上,工作区不会交换,但所有窗口都会交换。您也可以使用bash swap-ws.sh up
,它会按预期工作。
这是代码。只需记住使用以下命令运行它bash
:
cur_ws=$(xdotool get_desktop)
max_ws=$(xdotool get_num_desktops)
# determine destination workspace based on current workspace
if [ "$1" = "up" ] && [ $cur_ws -gt 0 ]; then
next_ws=$((cur_ws-1))
elif [ "$1" = "down" ] && [ $cur_ws -lt $max_ws ]; then
next_ws=$((cur_ws+1))
else
exit 0
fi
source_win=$(wmctrl -l | grep -oE "[0-9a-f]x[0-9a-f]+\s+$cur_ws" | cut -f1 -d" ")
target_win=$(wmctrl -l | grep -oE "[0-9a-f]x[0-9a-f]+\s+$next_ws" | cut -f1 -d" ")
# push each window from current to next ws
for win in $source_win; do
wmctrl -i -r "$win" -t "$next_ws"
done
# pull each window from next ws to current
for win in $target_win; do
wmctrl -i -r "$win" -t "$cur_ws"
done
# go to target workspace
wmctrl -s $next_ws
笔记:如果您使用静态数量的工作区,此脚本会运行得更好(如果您使用 GNOME,您可以在 Tweaks 中更改这一点)