julho 29, 2019

Aprimorando a interface do Xfce com o Xdotool #1

O xdotool é uma das ferramentas mais tradicionais para trabalhar com ambientes gráficos com base no servidor X. Além de ser capaz de fornecer dezenas de informações úteis sobre janelas e espaços de trabalho, ele é capaz de emular ações de mouse e teclado como se fosse você digitando ou clicando. Neste artigo, nós vamos ver algumas ideias para deixar o ambiente de trabalho Xfce ainda mais interessante recorrendo aos recursos do xdotool.

Para demonstrar o potencial do xdotool (e, principalmente, aprender um pouco mais sobre programação no shell do Linux) nós vamos criar o script circula-desktop que, dependendo dos parâmetros de execução, irá mudar para a área de trabalho à esquerda ou à direita, poderá mostrar o número da área de trabalho atual no painel (com o plugin "Monitor Genérico") e ainda permitirá exibir ou ocultar todas as janelas da área de trabalho.

Nota: eu publiquei um vídeo sobre este exato procedimento no Youtube.

Conhecendo o xdotool

Geralmente o xdotool não vem instalado por padrão, mas certamente está presente no repositório da maioria das distribuições Linux. No Debian, basta executar este comando para instalá-lo:

sudo apt install xdotool

A lista de recursos do xdotool é enorme, mas você pode ter uma noção do que ele pode fazer digitando o seguinte comando no terminal:

xdotool help

Isso irá exibir uma lista com mais de 40 comandos disponíveis, cada um com as suas combinações, o que aumenta ainda mais a quantidade de opções.

Dessa lista, já pensando na nossa demonstração, nos interessam os seguintes comandos do xdotool:

  • get_desktop - retorna o número do desktop atual, onde "0" é o primeiro desktop;
  • get_num_desktops - retorna a quantidade de desktops;
  • set_desktop - muda para a área de trabalho "n";
  • key - executa a emulação de uma sequência de teclas.

Obtendo o número da área de trabalho atual

Em princípio, bastaria executar o comando...

xdotool get_desktop

Mas, como ele começa a contar do "0", nós precisamos somar "1" para obter uma numeração mais amigável. Portanto, nós temos que executar uma operação aritmética, o que pode ser feito assim no shell do Linux:

echo $(( $(xdotool get_desktop) + 1 ))

Nesse comando, os parênteses duplos com o cifrão na frente, $(( )), são o que nós chamamos de "expansão aritmética". O termo "expansão" se refere, em geral, à combinação de diversos comandos e caracteres especiais para gerar uma string (sequência de caracteres) contendo, por exemplo, o resultados de operações aritméticas e a substituição de comandos e varáveis pelos seus valores ou retornos.

É exatamente isso que esse comando faz. Ele substitui o comando xdotool get_desktop pela sua saída (que é o número da área de trabalho com base de contagem zero) e, em seguida, soma este valor a "1". O resultado expandido é a soma dos valores, e é isso que o comando echo irá exibir.

Mudando para a área de trabalho seguinte

Com o xdotool, o procedimento é bastante direto, sendo realizado apenas com o comando:

xdotool set_desktop --relative 1

Este método contempla, inclusive, o comportamento que nós queremos, que é voltar para a primeira área de trabalho depois de atingir a última.

Mudando para a área de trabalho anterior

Aqui a coisa fica um pouco mais complicada, mas não muito. Basicamente, a área de trabalho anterior é a área de trabalho atual menos "1". O único detalhe é descobrir o que fazer quando a área de trabalho atual for "0" e nós quisermos mudar para a última.

Para solucionar esse problema, nós podemos recorrer ao comando test ([ ... ]). Primeiro, vamos ver o código que eu estou sugerindo...

[ $(( $(xdotool get_desktop) - 1 )) -lt 0 ]

Este comando testa se o número da área de trabalho atual é ou não menor do que "0". Os colchetes são o comando test, cuja finalidade é comparar valores e retornar verdadeiro ou falso de acordo com a condição apresentada. No caso, a condição é expressa pelo operador -lt, que significa "menor que".

Portanto, se a área de trabalho atual menos "1" resultar num valor menor do que "0", o comando test irá retornar verdadeiro. Caso contrário, ele irá retornar falso. A partir daí, nós podemos utilizar os operadores lógicos && (and) e || (or) para criar uma pequena estrutura de controle...

[ $(( $(xdotool get_desktop) - 1 )) -lt 0 ] && ...executa isso... || ...ou isso...

Só que essa parte do procedimento é apenas para determinar quem será a área de trabalho anterior. Nós ainda precisamos de uma coisa antes de prosseguirmos, que é o número da última área de trabalho. Afinal, é para lá que nós queremos ir caso a subtração acima resulte num valor menor do que "0".

Felizmente, a última área de trabalho corresponde ao número total de áreas de trabalho menos "1" (lembre-se de que o xdotool começa a contar do "0"), e o comando para descobrirmos o total de áreas de trabalho é:

xdotool get_num_desktops

Como precisamos desse valor menos "1", ele ficaria...

echo $(( $(xdotool get_num_desktops) - 1 ))

Agora nós temos todos os elementos para montar uma série de comandos que nos leve à área de trabalho anterior. Dentro do script circula-desktop, ele ficaria assim...

IDESKTOP=$(xdotool get_desktop)      # número do desktop atual
NDESKTOP=$(xdotool get_num_desktops) # quantidade de áreas de trabalho

[ $(( IDESKTOP - 1 )) -lt 0 ] \
    && anterior=$(( $NDESKTOP - 1 )) \
    || anterior=$(( $IDESKTOP - 1 ))

xdotool set_desktop $anterior

Com tudo que nós vimos até aqui, eu acho que você é capaz de entender esse trecho de código. Mas, se tiver alguma dificuldade, deixe a sua dúvida nos comentários.

Criando as funções para circular as áreas de trabalho

Até aqui, tudo bem, mas o nosso objetivo é criar um script, e não executar comandos no terminal. Sendo assim, nós podemos transformar os comandos que já vimos em funções (trechos de código que podem ser chamados pelo nome dentro de um script). A coisa é bem mais simples do que parece, veja como fica:

IDESKTOP=$(xdotool get_desktop)      # número do desktop atual
NDESKTOP=$(xdotool get_num_desktops) # quantidade de áreas de trabalho

desktop_seguinte() {
    xdotool set_desktop --relative 1
}

desktop_anterior() {
    [ $(( IDESKTOP - 1 )) -lt 0 ] \
        && anterior=$(( $NDESKTOP - 1 )) \
        || anterior=$(( $IDESKTOP - 1 ))

    xdotool set_desktop $anterior
}

As funções criadas foram desktop_seguinte e desktop_anterior, e tudo que eu fiz foi colocar os comandos dentro da seguinte estrutura:

nome_da_função() {

  comandos...

}

Tudo que estiver dentro dessa estrutura só será executado se, em algum outro ponto do código, a função for chamada pelo nome.

Mas, ainda não terminamos!

Exibindo o número da área de trabalho no plugin "Monitor Genérico"

O script circula-desktop ainda precisa ser capaz de exibir o número da área de trabalho atual de forma amigável e, ao clicarmos no plugin, as janelas da área de trabalho terão que ser ocultadas ou exibidas.

O Xfce não possui um comando para alternar a exibição da área de trabalho, mas possui um atalho de teclado (CTRL+ALT+D). Portanto, vamos deixar que o comando key do xdotool "tecle" essa combinação por nós...

xdotool key ctrl+alt+d

Simples assim!

Para tornar o plugin "Monitor Genárico" clicável, nós precisamos seguir a sintaxe que está descrita na página do plugin e consiste basicamente num conjunto de tags, o que nós podemos gerar assim (já dentro de uma função)...

desktop_show() {
    echo "<txt>$(( $IDESKTOP + 1 ))</txt>"
    echo "<txtclick>xdotool key ctrl+alt+d</txtclick>"
    echo "<tool>Alternar desktop...</tool>"
}

Aqui está o que cada tag faz:

<txt>      É o texto a ser exibido no plugin
<txtclick> A ação realizada ao clicar no plugin
<tool>     "Tooltip", a dica que aparece ao parar o mouse sobre o plugin

Criando um seletor

Agora nós só precisamos de uma estrutura de controle que selecione a função correta de acordo com o argumento passado junto com o script quando ele for executado. Por exemplo:

circula-desktop next - chamaria a função "desktop_seguinte"

circula-desktop prev - chamaria a função "desktop_anterior"

circula-desktop show - chamaria a função "desktop_show"

Nós podemos fazer isso com a declaração case do shell:

case $1 in
  "next")  desktop_seguinte
           ;;
  "prev")  desktop_anterior
           ;;
  "show"   desktop_show
           ;;
esac

Neste trecho, o $1 corresponde ao primeiro argumento passado junto com o script. Nos nossos exemplos, ele corresponderia aos valores "next", "prev" ou "show". Caso o script seja executado assim, por exemplo...

circula-desktop next

O case irá desviar o fluxo de execução apenas para a linha que corresponda ao parâmetro next. No caso, como está no código, é a função desktop_seguinte.

Juntando tudo

O nosso script está pronto. Agora é só juntar todas as peças:

#!/usr/bin/env bash

IDESKTOP=$(xdotool get_desktop)      # número do desktop atual
NDESKTOP=$(xdotool get_num_desktops) # quantidade de áreas de trabalho


# Muda para o desktop seguinte...

desktop_seguinte() {
    xdotool set_desktop --relative 1
}

# Muda para o desktop anterior...

desktop_anterior() {
    [ $(( IDESKTOP - 1 )) -lt 0 ] \
        && anterior=$(( $NDESKTOP - 1 )) \
        || anterior=$(( $IDESKTOP - 1 ))

    xdotool set_desktop $anterior
}

# Exibe o número do desktop atual e alterna a exibição...

desktop_show() {
    echo "<txt>$(( $IDESKTOP + 1 ))</txt>"
    echo "<txtclick>xdotool key ctrl+alt+d</txtclick>"
    echo "<tool>Alternar desktop...</tool>"
}

# Seleciona a função a ser executada de acordo
# com o argumento passado com o script...

case $1 in
  "next")  desktop_seguinte
           ;;
  "prev")  desktop_anterior
           ;;
  "show")   desktop_show
           ;;
esac

Não se esqueça de salvar o seu script e torná-lo executável.

chmod +x /caminho/nome_do_script

Configurando os lançadores e o plugin

Por fim, com seu script salvo, basta adicionar dois lançadores e um plugin Monitor Genérico no painel do Xfce e configurá-los da forma que aparece na imagem abaixo (os ícones ficam ao seu critério).

 

Nenhum comentário:

Postar um comentário

O sistema de comentários do Blogspot é um lixo e praticamente me obriga a liberar ou moderar todos os comentários. Portanto, eu peço perdão antecipadamente caso o seu comentário demore para aparecer.

Mas não se acanhe por causa disso! :-)