Возможно переместить все окна (или все не минимизированные окна) формируют одну рабочую область другому?
Я знаю, что могу переместить одно окно в другую рабочую область с Shift+Ctrl+Alt+arrow, но это переместится только что одно сфокусированное окно.
Среды рабочего стола, не основанные на 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"
Переместить окно с идентификатором окна $ i
в рабочее пространство 2.
все это упаковано в простой while read ... do; done
цикл, который перебирает все окна на текущем рабочем столе.
Среды рабочего стола на основе Compiz (например, Unity)
Поиск решения для таких сред рабочего стола, как Unity, затруднен тем, что Compiz (оконный менеджер Unity) не использует рабочие столы в традиционном смысле .
Unity: Что такое вьюпорты?
Ubuntu Unity использует вьюпорты - по сути, систему координат (с координатами 0,0 - левый верхний угол), где один огромный рабочий стол разделен на части, соответствующие разрешению вашего экрана. Координаты увеличиваются по мере перемещения вправо и вниз.
Система координат относительна. Если моя текущая область просмотра находится слева вверху, то все, что находится относительно этой области просмотра, будет иметь положительные значения ширины и высоты. Например, если мой текущий видовой экран находится сверху слева, то окно firefox в верхней средней рабочей области, которое вы видите выше, позиционируется по x со значением 1366 и y со значением 0 относительно верхнего левого видового экрана. Если мой активный видовой экран - верхний средний, окно терминала в верхнем левом видовом экране позиционируется в значении x -1327 60. Это ключевой вопрос для xdotool
, потому что xdotool
не работает с отрицательными числами.
Заметим также, что верхний левый угол текущего видового экрана всегда будет приниматься xdotool за координаты 0 0 . Это означает, что мы можем перемещать материал только вправо и вниз.
Заставляем xdotool работать в Unity
Теперь мы знаем, что xdotool
может перемещать окна только относительно левого верхнего угла (т.е. вы всегда можете перемещать окно вниз и вправо, но никогда вверх и влево). Как мы можем заставить это работать для единства. Ну, основная идея заключается в следующем:
Сценарное решение
Приведенный ниже сценарий выполняет именно ту процедуру, которая описана выше. Он может быть вызван с флагом -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: 1047481448@qq.com
# 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
и снимите привязку окон в опциях диспетчера окон.
Я сделал что-то похожее на подход glutanimate
Вот 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
NOTE: Этот скрипт работает лучше, если вы используете статическое количество рабочих пространств (вы можете изменить это в Tweaks, если вы используете GNOME)