Lo he resuelto con un script en bash que utiliza las siguientes herramientas de XWindows:
- wmctrl
- xwininfo
- xdotool
Lo primero será por tanto instalar estas herramientas en tu sistema Elementary OS:
- sudo apt install wmctrl
- sudo apt install xwininfo
- sudo apt install xdotool
¿Qué hace cada una de ellas?
wmctrl -d: relación de escritorios virtuales
wmctrl -d nos muestra una línea por cada uno de los escritorios virtuales que tenemos. En mi caso tengo 4 escritorios virtuales. Fíjate que marca con un asterisco (*) el que está activo. En la imagen anterior se ve que el escritorio 0 es el que está activo ahora
wmctrl -l: ventanas activas en mi sistema
wmctrl -l nos muestra una línea por cada ventana activa en el sistema.
Veamos campo por campo el sentido de cada línea:
- El primer campo es el ID de la ventana
- El segundo campo es en qué escritorio virtual se encuentra la ventana. Fíjate que -1 es un escritorio no existente.
- El tercer campo es el nombre del PC
- El cuarto campo es el nombre de la ventana.
xwininfo: ¿Está la ventana x minimizada?
Esta herramienta me permite obtener información de detalle de una determinada ventana. Por ejemplo, ¿está minimizada?
Básicamente funciona así: xwininfo -id <idventana>
Donde, idventana es el ID que nos devuelve wmctrl.
xdotool: realizar acciones sobre una ventana
xdotool me permite realizar acciones sobre una ventana concreta:
- maximizar
- minimizar
- restaurar
- asignarle el foco, es decir, pornerla en primer plano y marcarla como activa
Básicamente, lo que hace mi script es:
- Contar el número de ventanas visibles del escritorio actual
- Si n_ventanas_visibles > 0 entonces, minimizar todas
- Si no, restaurar todas las ventanas del escritorio activo
Con un pequeño matiz, cuando minimizo todas, guardo en un fichero temporal cuál es la ventana activa en ese momento. Esto me permitirá que, si vuelvo a restaurar las ventanas, se vuelva a marcar como activa aquella en la que yo estaba trabajando.
A este script yo lo he llamada mDesktop.sh. Para asignarle un atajo de teclado, sencillamente configuro los atajos de teclado personalizados en Elementary OS:
A continuación te muestro el código completo del script:
#!/bin/bash mute=0 Program=$@ program_workingDir=`dirname $(readlink -f $0)` status_fname="$program_workingDir/.mdesktop_status" program_systemWindows="$program_workingDir/.mdesktop_systemWindows" n_visible=0 window_id=0 window_name="" window_hidden=0 window_isignorable=0 window_vd=0 #vd means virtual desktop vd_activeId=0 #----------------------------------------------------------------------------------------------- function debug() { if [[ $mute == 0 ]] then echo "DEBUG: $1" fi } #----------------------------------------------------------------------------------------------- function vd_getActiveId() { local vd_id=-1 local vd_status="-" while read vDesktop do vd_id=`echo "$vDesktop" | tr -s ' ' | cut -f 1 -d " "` vd_status=`echo "$vDesktop" | tr -s ' ' | cut -f 2 -d " "` if [ "$vd_status" == "*" ] then echo $vd_id break fi done < <(wmctrl -d) } #----------------------------------------------------------------------------------------------- #isSystemWindow: # All windows in mdestop_systemWindows and also the Desktop # How to detect the Desktop window? # Because if you ask xwininfo -id <window_id> -all and you grep Window type: Desktop # System Windows are marked to vDesktop -1 function isSystemWindow() { local window_isSystem=0 local window_name=$1 local window_id=$2 local window_isDesktop=0 window_isSystem=$(grep "$window_name" $program_systemWindows | wc -l) if [[ $window_isSystem == 1 ]] then echo $window_isSystem return fi window_isDesktop=$(xwininfo -id $window_id -all | grep "Desktop" | wc -l) if [[ $window_isDesktop == 1 ]] then echo "1" else echo "0" fi } #----------------------------------------------------------------------------------------------- # window_activeId # Window id which actually is focused, it is, the one which is active # This value will be saved in .desktop_status so it can be restored #----------------------------------------------------------------------------------------------- function windows_minimize_all() { local window_activeId=-1 debug "windows_minimize_all..." window_activeId=$(xdotool getactivewindow) echo "$window_activeId" > $status_fname while read Window do # window_name=`echo "$Window" | tr -s ' ' | cut -f 4 -d " "` window_id=`echo "$Window" | tr -s ' ' | cut -f 1 -d " "` window_vd=`echo "$Window" | tr -s ' ' | cut -f 2 -d " "` if [[ $(isSystemWindow $window_name $window_id) == 1 ]] then debug "NOT minimize $window_id: system window" continue fi if [[ $window_vd != $vd_activeId ]] then debug "NOT minimize $window_id: in another desktop" continue fi debug "MINIMIZE $window_id" xdotool windowminimize $window_id done < <(wmctrl -l) } #----------------------------------------------------------------------------------------------- function windows_restore_all() { while read Window do # window_name=`echo "$Window" | tr -s ' ' | cut -f 4 -d " "` window_id=`echo "$Window" | tr -s ' ' | cut -f 1 -d " "` window_vd=`echo "$Window" | tr -s ' ' | cut -f 2 -d " "` if [[ $(isSystemWindow $window_name $window_id) == 1 ]] then debug "NOT RESTORE $window_id: system window" continue fi if [[ $window_vd != $vd_activeId ]] then debug "NOT RESTORE $window_id: in another desktop" continue fi xdotool windowactivate $window_id done < <(wmctrl -l) # Set focus to the window was active before minimizing all window_activeId=$(cat $status_fname) debug "SETTING FOCUS TO: $window_activeId" xdotool windowactivate $window_activeId } #----------------------------------------------------------------------------------------------- debug "###############################################" debug "###############################################" debug "# MAIN ##########################################" debug "###############################################" debug "###############################################" vd_activeId=$(vd_getActiveId) debug "current virtual desktop=$vd_activeId" while read Window do debug "-----------------------------------------------------------------------" debug "### 1" debug "$Window" window_id=`echo "$Window" | tr -s ' ' | cut -f 1 -d " "` window_vd=`echo "$Window" | tr -s ' ' | cut -f 2 -d " "` window_name=`echo "$Window" | tr -s ' ' | cut -f 4 -d " "` window_hidden=`xwininfo -all -id $window_id | grep "Hidden" | wc -l` debug "Window Id: $window_id" debug "Window vd: $window_vd" debug "Window Hidden: $window_hidden" debug "Window Name: $window_name" if [[ $window_vd == "-1" ]] then debug "Window virtual desktip is -1, ignore actual window" continue fi window_isignorable=$(isSystemWindow $window_name $window_id) debug "Window is system: $window_isignorable" # is current window an ignore Window? if [[ $window_isignorable == 1 ]] then debug "Ignore actual Window" continue fi # is current active virtual desktop? if [[ $window_vd != $vd_activeId ]] then debug "Ignore actual Window: in another desktop" continue fi # Is there any visible window? if [[ $window_hidden == 0 ]] then debug "show_desktop" let n_visible++ fi debug "n_visible = $n_visible" debug "### 4" done < <(wmctrl -l) # We must exec every window and minimize or maximize, depending wether it was already minimized or not debug "###n_visible = $n_visible" # windows_restore_all if [[ $n_visible == 0 ]] then debug "restore all windows" windows_restore_all else debug "minimize all windows" windows_minimize_all fi |
Fuentes:
- https://unix.stackexchange.com/questions/23565/get-current-virtual-desktop-number-name-tag-id
- https://unix.stackexchange.com/questions/38867/is-it-possible-to-retrieve-the-active-window-process-title-in-gnome
- https://stackoverflow.com/questions/4057078/how-can-you-check-if-a-window-is-minimized-via-the-terminal-in-linux
- https://askubuntu.com/questions/553203/how-to-close-only-one-window-of-an-application
- http://linux.byexamples.com/archives/179/wmctrl-a-handy-tool-for-you-to-manipulate-windows/
- https://askubuntu.com/questions/4876/can-i-minimize-a-window-from-the-command-line
- https://askubuntu.com/questions/703628/how-to-close-minimize-and-maximize-a-specified-window-from-terminal