Как переместить все окна в другое рабочее пространство

Возможно ли переместить все окна (или все не свернутые окна) из одного рабочего пространства в другое?

Я знаю, что могу переместить одно окно в другое рабочее пространство с помощью Shift+Ctrl+Alt+стрелка, но оно будет перемещать только одно окно с фокусом.

3 ответа

Unity: что такое Viewports?

Ubuntu Unity использует окна просмотра - в основном систему координат (с координатой 0,0 в левом верхнем углу), где один гигантский рабочий стол разделен на куски, которые соответствуют вашему разрешению экрана. Координаты растут в цене при перемещении вправо и вниз.

https://ask-ubuntu.ru/images/513bbe9644a0a4aad42962f131f65f4303d001d2.png

Система координат является относительной. Если мой текущий видовой экран находится в верхнем левом углу, все относительно этого видового экрана будет иметь положительные значения в приращениях ширины и высоты. Например, если мой текущий видовой экран расположен в крайнем левом верхнем углу, окно Firefox в верхнем среднем рабочем пространстве, которое вы видите выше, расположено со значением x 1366 и значением y 0 относительно самого верхнего левого окна просмотра. Если мой активный видовой экран имеет верхний средний, окно терминала в верхнем левом видовом окне расположено со значением x -1327 60. Это ключевая проблема для xdotool, так как xdotool не имеет дело с отрицательными числами.

Также обратите внимание, что верхний левый угол вашего текущего окна просмотра всегда будет приниматься xdotool в качестве координат 0 0 . Это означает, что мы можем только двигать вещи вправо и вниз.

Заставить xdotool работать на Unity

Теперь мы знаем, что xdotool можно перемещать окна только относительно нашего верхнего левого угла (то есть вы всегда можете перемещать окно вниз и вправо, но никогда не вверх и влево). Как мы можем заставить это работать на единство. Ну, основная идея была бы

  1. Выяснить все окна в текущем окне просмотра
  2. На мгновение перейдите к запрашиваемому окну просмотра, чтобы верхний левый угол принял координаты 0 0 в этом окне просмотра.
  3. Переместить все окна в определенные пользователем координаты области просмотра
  4. Возврат к старому окну просмотра (необязательно, может также следовать за окнами)

Решение для сценариев

Сценарий ниже выполняет в точности процедуру, описанную выше. Это может быть вызвано либо -v флаг для указания координат вручную или вы можете использовать -g флаг, чтобы вызвать диалог GUI. -f флаг скажет сценарию также переключить область просмотра; если этот флаг не используется - вы останетесь в текущем окне просмотра, и только окна будут перемещаться

Получение сценария

С этого поста можно скопировать исходный код напрямую или через github, выполнив следующие действия:

  1. sudo apt-get install git
  2. cd /opt ; sudo git clone https://github.com/SergKolo/sergrep.git
  3. 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 "$@"

демонстрация

Веб-запись сценария в действии:

https://www.youtube.com/watch?v=cJMlC41CWWo

вопросы

Из-за единства grid плагин, который отвечает за привязку окна, скрипт не может перемещать развернутые окна или окна с привязкой вправо / влево. Будет предпринята попытка добавить моментальный сброс и сброс этого плагина, чтобы скрипт работал со всеми окнами, но поскольку сброс и сброс имеет задержку по времени, он может быть заброшен как идея. Если вы хотите, чтобы скрипт работал со всеми окнами, установите unity-tweak-tool и снимите привязку окна под опциями Window Manager.

Среды рабочего стола не на базе 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

    Вывести список всех окон, отфильтровать те, которые не находятся в текущей рабочей области, и извлечь их идентификатор окна

  • wmctrl -i -t 2 -r "$i"

    Переместить окно с идентификатором окна $i в рабочее пространство 2.

  • все это упаковано в простой while read ... do; done цикл, который перебирает все окна на текущем рабочем столе

Среды рабочего стола на базе Compiz (например, Unity)

Поиск решения для настольных сред, таких как Unity, затруднен тем, что Compiz (оконный менеджер Unity) не использует десктопы в традиционном смысле.

Я сделал что-то похожее на подход глутанимата

Вот скрипт, который это делает:

      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

ПРИМЕЧАНИЕ . Этот скрипт работает лучше, если вы использовали статическое количество рабочих областей (вы можете изменить это в Tweaks, если используете GNOME).

Другие вопросы по тегам