O Kommander permite criar interfaces gráficas para shell scripts, usando a biblioteca Qt do KDE. Ele é dividido em duas partes: o “kmdr-editor” é o editor que permite criar as interfaces, enquanto o “kmdr-executor” executa os arquivos gerados por ele.
Ao instalar o pacote do Kommander, você obtém os dois componentes. Nas distribuições derivadas do Debian você pode instalá-lo com um “apt-get install kommander“. Pacotes rpm para várias distribuições podem ser encontrados no https://www.rpmfind.net/.
Em último caso, você pode baixar uma versão genérica no:
https://kde-apps.org/content/show.php?content=12865
A interface do kmdr-editor lembra um pouco a do VB ou Delphi, mas é mais simples por conter muito menos funções. Lembre-se de que o objetivo do Kommander é desenvolver interfaces para scripts, ele provê relativamente poucas funções por si só.
Ao criar um novo projeto, no “Arquivo > Novo“, você tem a opção de criar um diálogo ou um assistente. Um diálogo cria uma interface simples, com botões e abas, do tipo onde você escolhe entre um conjunto de opções e clica no “Ok” para acionar o script. Já o assistente permite criar uma seqüência de telas interligadas, útil para criar programas de instalação, por exemplo.
Os arquivos gerados no kmdr-editor não são binários, mas sim arquivos em XML, que são interpretados e executados pelo kmdr-executor. Estes arquivos contém os “fontes” da interface. Não é possível criar diretamente um binário através do Kommander, é sempre necessário ter o kmdr-executor para executar os arquivos.
Você pode ver os fontes do Painel de Controle do Kurumin, junto com outros painéis que desenvolvi usando o Kommander, dentro da pasta “/etc/Painel” no Kurumin.
Vamos a um exemplo rápido. Que tal criar uma interface mais amigável para aquele script para gravar programas de TV que havíamos criado usando o kdialog? Usando o kommander poderíamos criar uma interface muito mais elaborada e profissional para ele.
Abra o kmdr-editor e crie um diálogo:
Vou criar um script simples, com um conjunto de opções para escolher o canal, tempo de gravação e o arquivo que será criado, que armazenarão as informações em um conjunto de variáveis e um botão que executa o script principal, montando o comando gigante do mencoder. Para dificultar um pouco, vou acrescentar mais uma opção, que permite escolher a qualidade da gravação.
Para as opções de escolha do canal e tempo de gravação, vou usar o widget “Line Edit“, que cria uma linha editável. Vou usar dois, um para cada opção, junto com dois “TextLabel“, duas legendas simples de texto.
Você pode escolher o texto padrão das opções dando um duplo clique sobre elas. Na janela de propriedades, você pode configurar opções como o tipo e tamanho das fontes, cores, alinhamento do texto, etc. Estas opções mudam de acordo com o widget usado.
Por enquanto não estou me preocupando com o visual, apenas em adicionar as opções. É mais fácil se preocupar primeiro com a parte técnica e deixar para cuidar da parte visual depois que o script estiver funcionando.
O texto dentro das duas caixas precisa ser armazenado em variáveis para que possamos utilizá-los mais tarde dentro do script principal. Para que isso aconteça, clique com o botão direito sobre cada uma das caixas e acesse a opção “Edit Text Associations“. No campo, digite “@widgetText“.
Isso faz com que o kommander crie uma variável contendo o texto digitado dentro da caixa. Esta variável tem o mesmo nome do widget, nome este que você escolhe nas propriedades. Para facilitar a minha vida depois, vou nomear as duas caixas como “canal” e tempo”, indicando exatamente o que ambas fazem:
É preciso incluir também um widget para salvar o arquivo. O Kommander oferece uma função bem similar ao “–getsavefilename” do kdialog, o widget “File Selector“. Adicione um ao programa, como fizemos com as duas caixas de texto.
O File Selector pode ser usado para abrir um arquivo, escolher uma pasta ou salvar um arquivo. Precisamos indicar a função do nosso nas propriedades. Para isso, configure a opção “selectionType” como “Save” (indicando que a janela servirá para salvar um arquivo).
Veja que aproveitei também para configurar a opção “selectionFilter” como “*.avi *.mpg *.wmf”, que faz com que a janela do gerenciador de arquivos mostre apenas arquivos de vídeo, com as três extensões especificadas e salve os arquivos com a extensão .avi, mesmo que o usuário não especifique a extensão. A opção “selectionCaption” permite escolher o título da janela para salvar.
Não se esqueça de configurar a opção “Edit Text Associations” do widget como “@widgetTex” como fizemos com as duas caixas de texto e escolher um nome nas propriedades. No meu caso deixei o nome como “arquivo”.
Você pode ver um preview da interface que está editando, clicando no “Visualização > Preview Form“. Isto é perfeito para ir testando cada opção conforme for adicionando, sem deixar que os erros se acumulem.
Falta incluir a opção para escolher a qualidade de gravação, neste caso dois parâmetros que podem ser especificados na linha de comando do mencoder. Vou criar dois botões separados, um para escolher a resolução do vídeo (640×480 ou 320×240) e outro para escolher o bitrate, que determina a qualidade e tamanho final do arquivo.
No caso da resolução, vou oferecer apenas duas opções, por isso uso o widget “RadioButton“, criando dois botões. Estes botões precisam ser exclusivos, ou seja, apenas um deles pode ser selecionado de cada vez. Para isso, vou precisar colocá-los dentro de um “ButtonGroup“, outro widget que é uma espécie de moldura, que permite agrupar vários botões de forma que eles se comportem da forma desejada.
Isto vai envolver um número maior de passos. Primeiro crie o ButtonGroup do tamanho desejado e coloque dois botões dentro dele. Nas propriedades, escolha nomes para os três. No meu caso, coloquei “resolucao” (para o ButtonGroup), “resolucao1” e “resolucao2” para os botões.
Nas propriedades do ButtonGroup, configure a opção “RadioButtonExclusive” como “Verdadeiro“. Isso faz com que apenas um dos botões dentro dele possa ser marcado de cada vez.
Dentro das propriedades do primeiro botão, deixe a opção “Checked” como “Verdadeiro“. Isso faz com que ele fique marcado por padrão.
Ao desenvolver uma interface, é importante fazer com que todas as opções sempre tenham algum valor padrão. Isso diminui a possibilidade de erros por parte do usuário, já que o script vai funcionar mesmo que ele não configure todas as opções.
Falta agora configurar o “Edit Text Associations” dos dois botões, para armazenar o conteúdo da variável que será criada caso cada um deles seja pressionado. Desta vez não vou usar o “@widgetText” pois os botões não contém texto algum. Vou indicar manualmente um valor padrão para cada um dos dois botões.
Um deles conterá o valor “width=640:height=480” e o outro o valor “width=320:height=240”, que são as opções que poderão ser incluídas na linha de comando do mencoder que será criada ao executar o programa. Lembre-se de que apenas um dos dois botões pode ser marcado de cada vez, por isso apenas uma das duas opções será usada.
Os dois botões estão dentro do ButtonGroup e apenas um deles pode ser marcado de cada vez. O valor da variável do ButtonGroup (“@resolucao” no meu caso) passa a ser o valor padrão do botão que for selecionado. Ou seja, se for marcado o primeiro botão, a variável “@resolucao” receberá o valor “width=640:height=480”.
Para que isso funcione, preciso configurar o “Edit Text Associations” do ButtonGroup como “@widgetTex“.
Na hora de usar a variável, uso a variável “@resolucao”, correspondente ao ButtonGroup e não as variáveis dos botões.
Esta é a moral da história de usar o ButtonGroup ao invés de botões isolados. Você pode colocar vários botões dentro dele, fazer com que apenas um botão possa ser clicado de cada vez, determinar um valor padrão para cada botão e fazer com que a variável do ButtonGroup contenha apenas o valor do botão que foi selecionado.
Para escolher o bitrate que será usado ao gerar o arquivo, vou usar um “SpinBoxInt“, um widget que cria uma caixa onde você pode escolher um valor numérico usando duas setas. Nas propriedades, você escolhe um valor máximo, um valor mínimo, um valor padrão e o “lineStep”, que determina quanto o número aumenta ou diminui cada vez que um dos botões é pressionado.
No “Edit Text Associations” do SpinBox, coloque “@widgetTex“, como sempre. Isso faz com que a variável contenha o número escolhido. Não se esqueça de escolher um nome para ele nas propriedades. No meu caso escolhi “bitrate”.
Para melhorar o visual, coloquei o SpinBox dentro de um “GroupBox“, que cria um quadrado, similar ao “ButtonGroup”, mas com função puramente estética.
Como disse acima, o bitrate determina a qualidade do vídeo gerado, especificando o número de kbits que serão reservados para cada segundo de vídeo. Um bitrate de 1500 kbits gera arquivos com cerca de 11 MB por minuto de vídeo, quase 700 MB por hora. O tamanho do arquivo aumenta ou diminui proporcionalmente de acordo com o bitrate. Um bitrate muito alto resultaria num arquivo gigantesco e um muito baixo resultaria num arquivo tosco, com uma qualidade muito ruim. Por isso usamos o SpinboxInt para determinar uma margem de valores razoáveis.
Você poderia adicionar mais um SpinBoxInt para oferecer também a opção de alterar o bitrate do som, mas no meu caso não vou incluir isto, pois o áudio comprimido em MP3 representa uma percentagem pequena do tamanho do arquivo.
Depois dessa trabalheira toda, temos as variáveis: @canal, @tempo, @arquivo, @resolucao e @bitrate, que usaremos para gerar a linha de comando do mencoder.
Precisamos agora de um gatilho, um botão que executa o comando final. Vamos usar um simples “ExecButton“.
Dentro do “Edit Text Associations” (do botão), vão as linhas:
verificador="@arquivo"
if [ -z "$verificador" ]; then
kdialog --msgbox "Você esqueceu de indicar o arquivo onde o vídeo será salvo ;-)"
exit 0
fi
kdialog --title "Gravando" --passivepopup "Gravando o canal $var1
por: @tempo horas
no arquivo: @arquivo
Feche a janela de terminal para abortar" 6 &
xterm -e "mencoder tv:// -tv driver=v4l2:input=0:normid=4:channel=@canal:chanlist=us-bcast:@resolucao:device=/dev/
video0:adevice=/dev/dsp0:audiorate=48000:forceaudio:forcechan=2:buffersize=64 -quiet -oac mp3lame -lameopts preset
=medium -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=@bitrate:keyint=132 -vop pp=lb -endpos @tempo -o @arquivo "
kdialog --title "Gravar-TV" --passivepopup "Ok!
A gravação terminou." 5 &
Veja que são os mesmos comandos que usamos no primeiro script, foi preciso apenas adaptar o uso das variáveis. Num script em shell normal as variáveis são identificadas por um dólar, “$“, enquanto as variáveis criadas através da interface no Kommander são identificadas por uma arroba, “@“.
A função que acrescentei no início do arquivo verifica se foi escolhido o arquivo onde salvar o arquivo, a variável “@arquivo” do Kommander. As funções condicionais do bash (if, case, etc.) em algumas situações não entendem as variáveis do Kommander diretamente, por isso, por segurança, criei primeiro a variável “verificador”, com o conteúdo da variável “@arquivo” do Kommander.
O “-z” é um comparador, significa “é nula”, ou seja, ela serve para verificar se a variável está vazia. Caso esteja, é exibida uma mensagem na tela e o script é fechado, graças ao “exit 0“. Como o script é executado pela janela principal do Kommander, o script fecha, mas a janela principal continua aberta, permitindo que o usuário corrija o erro e execute novamente.
Você pode usar funções do kdialog, funções lógicas e outros comandos que usaria num script tradicional. O Kommander apenas acrescenta algumas possibilidades novas.
Depois de revisar tudo, você pode finalmente testar o programa, executando-o no kmdr-executor:
$ kmdr-executor gravar-tv.kmdr
A segunda parte do trabalho envolve dar uma melhorada no aspecto visual. Você pode acrescentar imagens e ícones usando o widget “PixmapLabel“.
Os ícones do sistema vão por padrão dentro da pasta “/usr/share/icons“, e são um bom ponto de partida. Você pode usar também imagens e ícones personalizados, salvos em .png. Todas as imagens usadas são salvas como parte do arquivo, como se fosse um documento do OpenOffice. Você não precisa se preocupar em distribuir as imagens junto com o programa, a única dependência é o kmdr-executor, junto com os comandos usados dentro do script.
Uma dica é que o Kommander sempre degrada a qualidade das imagens com mais de 256 cores. Para melhor qualidade, prefira usar imagens com 256 cores, com paleta indexada (que podem ser tratadas usando o Gimp).
A maioria dos widgets, como as etiquetas de texto, caixas, etc., possuem várias opções de cores e fontes dentro das propriedades, que permitem fazer um bom trabalho. Esta é a versão inicial do script, que desenvolvi para uso no Kurumin:
Outro recurso interessante do Kommander e vem sendo melhorado rapidamente nas novas versões são as conexões. Elas permitem adicionar elementos dinâmicos na interface, um textLabel cujo conteúdo muda quando você clica num botão ou mostra informações sobre um arquivo escolhido num File Selector e assim por diante.
Para usar este recurso, certifique-se de ter instalada uma versão recente do Kommander, de preferência da 1.2 em diante, pois antes disso o suporte ainda era incipiente e mudanças eram feitas a cada nova versão.
Para seguir este exemplo, você precisa estar usando pelo menos o Kommander 1.0 final. Nas versões antigas o sistema de conexões ainda não estava terminado, muitas opções ainda não existiam.
Vamos usar algumas conexões para criar um editor de imagens primitivo. Comece criando um novo projeto e desenhe uma interface contendo um FileSelector, um textLabel, um PixmapLabel e quatro botões que usaremos para adicionar algumas funções de edição. Por enquanto não incluí código algum, apenas desenhei os widgets:
O objetivo é fazer com que o arquivo de imagem escolhido no FileSelector seja exibido no PixmapLabel, ao mesmo tempo em que a localização e nomes completos do arquivo são mostrados no textLabel. As duas coisas atualizadas automaticamente, sem que seja necessário pressionar nenhum botão.
Os botões vão conter mais algumas funções estáticas para deletar a imagem, girar e limpar os dois campos (novamente usando conexões).
Vamos começar fazendo com que a imagem seja exibida no PixmapLabel. Procure a “Ferramenta de conexão” na interface principal. Clique primeiro sobre o FileSelector e arraste até o PixmapLabel. Isso cria uma conexão entre eles, indicada pelos dois quadrados rosa que aparecem.
Na janela de propriedades que será aberta, você verá duas janelas, uma com os sinais disponíveis no FileSelector e do outro lado as propriedades do PixmapLabel que podem ser alteradas quando o sinal selecionado é emitido.
Marque a opção “widgetTextChanged(const QString)” do lado do FileSelector e a opção “setWidgetText(const QString)” do lado do PixmapLabel. Clique no “Conectar” para efetivar a conexão:
O que fizemos aqui foi especificar que quando o texto dentro do FileSelector for alterado (ou seja, quando for escolhido algum arquivo) o conteúdo do PixmapLabel muda, exibindo o conteúdo do arquivo. Se fosse uma caixa de texto, seria mostrado o conteúdo do arquivo na forma de texto; mas, como estamos usando uma caixa de imagem, será mostrado um preview da imagem.
Crie agora uma nova conexão, ligando o FileSelector e o textLabel. Na janela de propriedades, marque a opção “widgetTextChanged(const QString)” para o FileSelector (o mesmo do passo anterior) e a opção “Populate()” para o textLabel.
O textLabel está originalmente vazio, sem conteúdo algum. A função Populate vai “populá-lo” com o resultado de um comando que definiremos no passo a seguir. Isso é disparado sempre que o conteúdo do FileSelector muda. Sempre que é escolhido um arquivo diferente, o comando é executado novamente e o conteúdo do textLabel muda.
Para definir o comando, clique com o botão direito sobre o textLabel e acesse a opção “Editar texto do Kommander“. Dentro da janela, acesse a opção “Texto para: Population” que está no canto superior direito.
O comando começa com o “@exec“, com o comando propriamente dito entre parênteses. Dentro dos parênteses você pode separar uma seqüência de comandos por ponto-e-vírgula, usar o pipe e outros componentes de um shell script normal.
Neste exemplo, estou usando o comando:
@exec(identify "@arquivo.text" | cut -d " " -f 2-10)
O identify é um comando de texto que exibe as propriedades da imagem, como formato e resolução. Nas propriedades do meu FileSelector mudei o nome para “arquivo”, logo o “@arquivo.text” se refere ao conteúdo do FileSelector, ou seja, o nome do arquivo que foi escolhido. O “| cut -d ” ” -f 2-10″ é opcional, ele serve apenas para “limpar” a saída do identify, retirando o nome do arquivo e deixando apenas as propriedades da imagem.
Uma observação importante é que o Kommander não é muito bom em executar scripts complexos desta forma. Em muitos casos o Kommander entra em loop ao clicar no botão, ou retorna um valor inesperado, mesmo que que a função usada funcione perfeitamente se executada no terminal.
Embora este seja mais um fator que vem melhorando nas novas versões, é aconselhável que sempre que precisar incluir qualquer coisa mais elaborada, principalmente ao usar muitos pipes e redirecionamentos, prefira criar um script e chamá-lo dentro da função do Kommander, ao invés de tentar colocar todos os comandos diretamente dentro dos parênteses.
Por exemplo, num dos meus scripts uso uma função para popular um campo de texto com uma lista dos compartilhamentos NFS ativos. Isto é feito lendo e filtrando o conteúdo do arquivo “/etc/exports”, de forma que apenas as linhas referentes aos compartilhamentos sejam exibidas no campo. A atualização é feita ao clicar sobre um botão na interface.
Se coloco algo como: @exec(sed '/^$/d' /etc/exports | sed '/#/d') ou mesmo: @exec(cat /etc/exports | sed '/^$/d' | sed '/#/d') como função para o botão, o Kommander entra em loop ao clicar sobre ele e o campo com os compartilhamentos ativos nem chega a ser atualizado.
Para solucionar isso, criei um pequeno script com os comandos necessários e o executo dentro do botão. Embora os comandos executados sejam os mesmos, o botão passa a funcionar perfeitamente, pois o Kommander executa o script dentro de um shell separado e apenas “popula” o campo de texto com o resultado do comando. Ou seja, quem executa os comandos neste caso é o bash, não o Kommander.
O script (salvo como /etc/Painel/servidor-nfs.sh) fica:
#!/bin/sh sed '/^$/d' /etc/exports | sed '/#/d' > /tmp/kexports cat /tmp/kexports
E a função dentro das propriedades do botão, na interface do Kommander, fica:
@exec(/etc/Painel/servidor-nfs.sh)
Voltando ao exemplo original, salve o arquivo e clique no “Executar > Executar diálogo” para ver um preview dele funcionando. Veja que ao escolher um arquivo de imagem no FileSelector a imagem é realmente exibida no PixmapLabel, enquanto o textLabel mostra as informações fornecidas pelo identify:
Apesar disso, ainda existe um pequeno bug: está sendo exibido apenas um pedaço da imagem. Para que seja exibido um preview reduzido da imagem, acesse as propriedades do PixmapLabel e mude a opção “scaledContents” para verdadeiro (true). A partir daí a imagem passa a ser redimensionada corretamente.
Falta agora só dar funções aos botões de edição, que é a parte mais fácil.
Dentro do botão “Deletar a imagem” (botão direito > Editor texto do Kommander) inclua a função:
kdialog --yesno "Tem certeza?"
retval=$?
if [ "$retval" = "0" ]; then
rm -f @arquivo.text
fi
Lembre-se de que a variável “@arquivo.text” contém o caminho completo para o arquivo. Usando “rm -f @arquivo.text” no script, deletamos o arquivo, e não o conteúdo da variável.
Nos botões Girar no sentido horário e girar no sentido anti-horário, inclua (respectivamente) as funções:
jpegorient +90 @arquivo.text jpegorient +270 @arquivo.text
O jpegorient é mais um comando de edição de imagem em modo texto, que faz parte do pacote ImageMagik. Ele permite justamente girar a imagem no sentido desejado. Não é muito prático para usar no dia-a-dia, mas é muito usado em scripts.
O último botão, “Limpar”, vai servir apenas para limpar o conteúdo do PixmapLabel e do textLabel. Para isso, crie uma conexão entre o botão e o PixmapLabel. Marque de um lado a opção “Pressed” e do outro a opção “clear()“. Faça o mesmo entre ele e o textLabel.
Nosso programinha está quase pronto, existe apenas um último “bug”: ao clicar nos botões de girar, a imagem é alterada, mas não é automaticamente atualizada na janela do programa.
Se você for perfeccionista e quiser resolver isso, crie uma conexão entre cada um dos dois botões de girar e o PixmapLabel. Marque a opção “Pressed()” para o botão e “Populate()” para o PixmapLabel.
Acesse agora as propriedades do PixmapLabel e, dentro do “Texto para: Population“, coloque “@arquivo.text“. Isso fará com que cada vez que um dos dois botões for pressionado, a nova conexão dispare uma atualização da imagem:
Assim como no exemplo para gravar programas de TV, o Kommander pode ser usado para criar interfaces para diversos programas que originalmente são acessíveis apenas via linha de comando. Mais um exemplo é o “Kurumin-synergy”, a interface para o Synergy que comentei no segundo capítulo.
Antes de continuar lendo, eu recomendo que releia o tópico do Synergy e teste o programa, já que para escrever uma interface é necessário, antes de mais nada, conhecer bem o programa alvo.
Em primeiro lugar, o Synergy pode ser usado como servidor (o micro principal, que controla os demais) ou como cliente (o micro que é controlado). A idéia é que o script possa ser usado nas duas situações, por isso ele foi criado com duas abas independentes.
A aba do servidor é de longe a mais complexa. Ela possui 4 checkboxes, que podem ser acionadas de forma independente, nomeadas como “cima”, “baixo”, “esquerda” e “direita”. Para cada checkbox, existem dois Line Edits (oito no total), nomeados como “cima_ip”, “cima_nome”, “baixo_nome”, “nome_ip”, “esquerda_nome”, “esquerda_ip”, “direita_nome” e “direita_ip”. Existe ainda um ckeckbox extra, chamado “desk_icon”, que responde pela função “Criar atalho no desktop”.
Nas propriedades de cada um dos 4 checkboxes, certifique-se que a opção “Texto para: checked” está com o valor “1”, já que é nisso que o script vai se basear para decidir quais conexões devem ser ativadas. Por segurança, atribuí também o valor “0” para a opção “unchecked” de cada um.
Esta parte de criação da interface é relativamente simples, embora trabalhosa. O principal nesta fase é checar se todos os nomes e propriedades dos campos estão corretos, já que num painel com vários campos é fácil se esquecer de algum.
O principal vai dentro do botão “Ativar o Synergy”, que contém o script que verifica o status de cada um dos campos, gera a configuração (salva no arquivo “/home/$USER/.synergy.conf”) e ativa o servidor Synergy com as opções selecionadas. Baixe o script completo no https://www.hardware.com.br/kurumin/painel/kurumin-synergy.kmdr.
Este script é um pouco longo, então vamos por partes.
Na configuração do Synergy é preciso incluir o nome do servidor. Não coloquei isso como mais um campo na janela principal, pois esta é uma informação fácil de descobrir através do comando “hostname”. Na primeira linha do script, crio uma variável “server” contendo o resultado do comando, ou seja, o nome da máquina, como em “semprao”. As linhas seguintes fecham o Synergy caso aberto (ele não pode ser aberto duas vezes), deleta o arquivo de configuração, caso exista (já que o script cria um novo) e, só para garantir, cria um novo arquivo vazio usando o comando touch.
server=`hostname` killall synergys rm -f /home/$USER/.synergy.conf touch /home/$USER/.synergy.conf
Em seguida, começamos a escrever o arquivo, iniciando pela seção “screens”, que contém os nomes do servidor e de cada um dos clientes que poderão se conectar a ele. O nome do servidor está dentro da variável “$server” e os nomes de cada cliente foram escritos nos campos “cima_nome”, “baixo_nome”, “esquerda_nome” e “direita_nome”.
O arquivo deve conter apenas os campos que foram selecionados. Se foram marcados apenas os checkboxes “esquerda” e “direita”, ele deve incluir somente os campos “esquerda_nome” e “direita_nome”, ignorando os demais.
Uma forma simples de fazer isso é criar um if para cada um dos 4 checkboxes, incluindo cada um dos campos apenas caso ele esteja com o valor “1” (sintoma de que está selecionado). O script fica então:
echo 'section: screens' >> /home/$USER/.synergy.conf right="@direita" if [ "$right" = "1" ]; then right_nome="@direita_nome.text"; right_ip="@direita_ip.text" echo "$right_nome:" >> /home/$USER/.synergy.conf; fi left="@esquerda" if [ "$left" = "1" ]; then left_nome="@esquerda_nome.text"; left_ip="@esquerda_ip.text" echo "$left_nome:" >> /home/$USER/.synergy.conf; fi up="@cima" if [ "$up" = "1" ]; then up_nome="@cima_nome.text"; up_ip="@cima_ip.text" echo "$up_nome:" >> /home/$USER/.synergy.conf; fi down="@baixo" if [ "$down" = "1" ]; then down_nome="@baixo_nome.text"; down_ip="@baixo_ip.text" echo "$down_nome:" >> /home/$USER/.synergy.conf; fi echo "$server:" >> /home/$USER/.synergy.conf echo "end" >> /home/$USER/.synergy.conf echo "" >> /home/$USER/.synergy.conf
Veja que aproveitei para criar uma série de variáveis, armazenando os textos dos campos. Este passo não é realmente necessário, pois você pode continuar usando diretamente as variáveis do Kommander.
O resultado deste trecho do script será algo como:
section: screens toshiba: fedora: semprao: end
O próximo passo é acrescentar a seção “links” dentro do script, que contém a posição de cada um dos clientes em relação ao servidor e a posição do próprio servidor em relação a cada um.
Vamos começar com a seção referente ao servidor. Note que o script inclui apenas os clientes que estão realmente ativados, novamente checando se o valor de cada um dos 4 checkboxes é “1”:
echo "section: links" >> /home/$USER/.synergy.conf echo "$server:" >> /home/$USER/.synergy.conf if [ "$right" = "1" ]; then echo "right = $right_nome" >> /home/$USER/.synergy.conf; fi if [ "$left" = "1" ]; then echo "left = $left_nome" >> /home/$USER/.synergy.conf; fi if [ "$up" = "1" ]; then echo "up = $up_nome" >> /home/$USER/.synergy.conf; fi if [ "$down" = "1" ]; then echo "down = $down_nome" >> /home/$USER/.synergy.conf; fi
Em seguida, é necessário especificar a posição de cada cliente em relação ao servidor. Novamente, estou adotando a filosofia do “mais longo, porém mais fácil”, criando um if para cada um:
if [ "$right" = "1" ]; then
echo "$right_nome:" >> /home/$USER/.synergy.conf
echo "left = $server" >> /home/$USER/.synergy.conf; fi
if [ "$left" = "1" ]; then
echo "$left_nome:" >> /home/$USER/.synergy.conf
echo "right = $server" >> /home/$USER/.synergy.conf; fi
if [ "$up" = "1" ]; then
echo "$up_nome:" >> /home/$USER/.synergy.conf
echo "down = $server" >> /home/$USER/.synergy.conf; fi
if [ "$down" = "1" ]; then
echo "$down_nome:" >> /home/$USER/.synergy.conf
echo "up = $server" >> /home/$USER/.synergy.conf; fi
echo "end" >> /home/$USER/.synergy.conf
echo "" >> /home/$USER/.synergy.conf
Esta seção do script produz algo como:
section: links semprao: right = toshiba left = fedora toshiba: left = semprao fedora: right = semprao end
Finalmente, falta criar a seção “aliases” do arquivo, que relaciona o endereço IP de cada cliente a seu nome. Ela é mais simples que as anteriores, já que temos todas as variáveis em mãos:
echo "section: aliases" >> /home/$USER/.synergy.conf
if [ "$right" = "1" ]; then
echo "$right_nome:" >> /home/$USER/.synergy.conf
echo "$right_ip" >> /home/$USER/.synergy.conf; fi
if [ "$left" = "1" ]; then
echo "$left_nome:" >> /home/$USER/.synergy.conf
echo "$left_ip" >> /home/$USER/.synergy.conf; fi
if [ "$up" = "1" ]; then
echo "$up_nome:" >> /home/$USER/.synergy.conf
echo "$up_ip" >> /home/$USER/.synergy.conf; fi
if [ "$down" = "1" ]; then
echo "$down_nome:" >> /home/$USER/.synergy.conf
echo "$down_ip" >> /home/$USER/.synergy.conf; fi
echo "end" >> /home/$USER/.synergy.conf
echo "" >> /home/$USER/.synergy.conf
Com o arquivo criado, chegou a hora de criar o ícone no desktop, caso o checkbox “desk_icon” esteja marcado. O ícone contém o mesmo comando executado no final do script. Ao ser aberto, o synergys lê o arquivo de configuração e carrega com as opções adequadas. A partir daí, o Synergy pode ser ativado simplesmente clicando sobre o ícone no desktop. Só é necessário abrir o painel novamente quando for necessário alterar a configuração.
O trecho do script que cria o ícone fica:
icon=”@desk_icon”
if [ "$icon" = "1" ]; then
echo '[Desktop Entry]
Exec=xterm -e synergys -f
GenericName=Ativar o Synergy
Icon=krdc
Name=Ativar o Synergy
Type=Application
X-KDE-SubstituteUID=false' > /home/$USER/Desktop/Ativar\ o\ Synergy.desktop
fi
Como estou usando aspas simples, o echo escreve tudo literalmente, incluindo as quebras de linha. Em situações onde é preciso incluir variáveis dentro do comando ou nome do ícone, é necessário escrever linha a linha, usando aspas duplas, como em:
echo "GenericName=Conectar ao servidor $server" >> /home/$USER/Desktop/server.desktop
Finalmente, temos a última linha do script, o mesmo comando incluído no ícone, que abre o servidor. Note que estou usando o comando “xterm -e”, que roda o comando dentro de uma janela do terminal. A idéia aqui é que ele fique visível e possa ser encerrado ao fechar a janela.
xterm -e synergys -f
A segunda aba do script, referente ao cliente, é bem mais simples, contendo apenas um line edit onde vai o IP do servidor e um checkbox para o atalho no desktop.
Além das linhas que criam o ícone no desktop, o botão contém apenas a linha que ativa o cliente Synergy:
server=@ip_server.text
if [ -n "$server" ]; then
xterm -e synergyc -f $server
fi
Em muitas situações, é preciso criar scripts mais dinâmicos, que obtenham e exibam informações automaticamente ao serem abertos e não apenas depois de clicar num botão. É possível fazer com que o script execute comandos e exiba os resultados na forma de opções dentro de um ComboBox, ou um label de texto. Isso permite criar scripts mais inteligentes, que exibem apenas as opções que se aplicam à situação.
Vamos usar como exemplo um script que cria uma interface para o cpufreq-set, (um comando que faz parte do pacote “cpufrequtils”), que permite ajustar a freqüência do processador em notebooks ou desktops com processadores Intel que suportam speed-step.
Ele é ativado carregando os módulos “p4_clockmod”, “freq_table”, “speedstep_lib”, “cpufreq_powersave”, “cpufreq_ondemand” e “cpufreq_userspace”. A partir daí, você pode ver as freqüências suportadas pelo processador, junto com a freqüência atual usando o comando “cpufreq-info”, como em:
# cpufreq-infocpufrequtils 0.2: cpufreq-info (C) Dominik Brodowski 2004 Report errors and bugs to linux@brodo.de, please. analyzing CPU 0: driver: p4-clockmod CPUs which need to switch frequency at the same time: 0 hardware limits: 175 MHz - 1.40 Ghzavailable frequency steps: 175 MHz, 350 MHz, 525 MHz, 700 MHz, 875 MHz, 1.05 GHz, 1.23 GHz, 1.40 Ghzavailable cpufreq governors: ondemand, powersave, userspace current policy: frequency should be within 175 MHz and 1.40 Ghz. The governor "userspace" may decide which speed to use within this range.current CPU frequency is 1.40 GHz(asserted by call to hardware).
Pela saída do comando sei que o processador (um Celeron M, por isso o baixo clock) suporta várias freqüências entre 175 MHz e 1.4 GHz e que ele está atualmente operando na freqüência máxima.
Para ajustar a freqüência do processador, você usa o comando “cpufreq-set -f”, seguido pela freqüência desejada (em kHz), como em:
# cpufreq-set -f 1050
Existe ainda a opção “-g ondemand“, onde a freqüência é ajustada dinamicamente, de acordo com a utilização do processador.
Vamos a um exemplo de script que poderia apresentar estas opções de uma forma mais agradável. Aqui estou usando dois ComboBox (um deles está escondido atrás do texto, vamos ver o porquê em seguida), um TextLabel e dois botões. O restante são caixas de texto explicativas e outros elementos cosméticos que você poderia usar ou não, de acordo com o público ao qual o script se destina:
O TextLabel exibe a freqüência atual, detectada no momento em que o script é aberto, enquanto o primeiro ComboBox mostra uma lista das freqüências suportadas. Ambas as coisas são extraídas da saída do comando “cpufreq-info” usando o grep e o cut.
Tudo começa com um “script auxiliar”, que é executado primeiro. Ele carrega os módulos que ativam o cpufreq, filtra a saída do cpufreq-info e salva as informações que vamos precisar exibir dentro do script em dois arquivos de texto e no final carrega o script principal. Note que por causa da necessidade de carregar módulos, é preciso que o script seja executado com permissão de root, através do kdesu ou sudo:
modprobe p4_clockmod modprobe freq_table modprobe speed step_lib modprobe cpufreq_powersave modprobe cpufreq_ondemand modprobe cpufreq_userspace rm -f /tmp/myfreq; rm -f /tmp/freq availablefreq=`cpufreq-info | grep "frequency steps" | sed -r 's/ +/ /g' | cut -f 5-100 -d " "` myfreq=`echo $availablefreq | sed -e 's/\\.//g' | sed -e 's/ GHz/0000/g' | sed -e 's/ MHz/000/g' | sed -e 's/,//g'` echo $myfreq | sed -e 's/ /\n/g' | sed -e 's/ //g' >> /tmp/myfreq cpufreq-info | grep "current CPU frequency is" | sed -r 's/ +/ /g' | cut -f 6-7 -d " " >> /tmp/freq kmdr-executor k-cpufreqd.kmdr
No final, temos dois arquivos temporários, “/tmp/myfreq” e “/tmp/freq”. O primeiro contém as freqüências suportadas pelo processador, que serão exibidas dentro do ComboBox, já convertidas para kHz, como em “175000 350000 525000 700000 875000 1050000 1230000 1400000” (um número por linha), enquanto o segundo contém a freqüência atual, como em “1.40 GHz”.
Para fazer com que estas informações sejam incluídas no script principal durante sua abertura, clique com o botão direito sobre uma área vazia do painel principal e em “Editar Texto do Kommander”. Dentro da janela, acesse a opção “Texto para: initialization:“.
Aqui você pode acrescentar comandos que serão executados na abertura do painel.
procintel=`cat /proc/cpuinfo | grep Intel`
if [ -z "$procintel" ]; then
kdialog --msgbox "Desculpe, por enquanto este script funciona apenas em processadores Intel que
suportam o speed-step."
kill @pid
fi
@freq.insertItems(@exec('cat /tmp/myfreq'),0)
@ComboBox2.insertItems(@exec('cat /tmp/freq'),0)
@Label1.setText("@ComboBox2.text")
Acrescentei aqui uma verificação rápida para detectar se o PC possui um processador Intel e encerrar o script caso negativo. O “@pid” é uma variável interna do Kommander que armazena o número do processo da janela atual. Ele é útil quando você precisa fazer com que o script feche sozinho em determinado ponto, como neste caso. Outra observação importante é que, para usar os dois ComboBox desta maneira, é preciso ajustar a opção “Editable” como “Verdadeiro” nas propriedades de ambos.
Como vimos anteriormente, é possível fazer com um widget do Kommander exiba o resultado de um comando. Uma forma simples de colocar as freqüências suportadas pelo processador dentro do primeiro ComboBox (“freq” no meu script) é atribuir a ele o resultado do comando “cat /tmp/myfreq”. Veja que gerei o arquivo já formatando os dados de forma que fossem entendidos pelo Kommander, colocando um número por linha.
Cada widget suporta um conjunto próprio de funções. Você pode ver uma lista clicando sobre o botão “Função…” no canto da janela. No caso do ComboBox usamos a função “insertItems”, obtendo um menu de seleção com os valores.
Para mostrar a freqüência atual no textLabel, usamos a função “setText”. O problema é que (pelo menos no Kommander 1.2) não é possível atribuir o resultado de um comando, é preciso escrever diretamente o texto que será exibido ou usar uma variável do Kommander. É por isso que adicionei o segundo ComboBox escondido. Ele permite fazer uma escala. Primeiro atribuo o resultado do comando a ele e, em seguida, atribuo o valor dele ao textLabel.
Esta é a parte complicada do script. Fica faltando apenas definir os comandos dentro dos dois botões, ajustando a freqüência de acordo com o escolhido e fazendo com que a configuração seja restabelecida na hora do boot.
Para o botão “Ajustar a freqüência manualmente”, escrevi o seguinte:
cpufreq-set -f @freq.text kdialog --yesno "Gostaria que esta configuração seja restabelecida durante o boot? Isto criará o arquivo '/etc/rcS .d/S70cpufreq', que executará os comandos necessários durante o boot. Responder 'Não' desativa uma configuração sa lva anteriormente." if [ "$?" = "0" ]; then rm -f /tmp/S70cpufreq 2>/dev/null cat <<EOF >/tmp/S70cpufreq modprobe p4_clockmod modprobe freq_table modprobe speedstep_lib modprobe cpufreq_powersave modprobe cpufreq_ondemand modprobe cpufreq_userspace cpufreq-set -f @freq.text EOF rm -f /etc/rcS.d/S70cpufreq mv /tmp/S70cpufreq /etc/rcS.d/S70cpufreq chmod +x /etc/rcS.d/S70cpufreq else rm -f /etc/rcS.d/S70cpufreq fi
Para o botão “Ajustar Dinamicamente” a única coisa que muda é o comando “cpufreq-set -f @freq.text”, que passa a ser “cpufreq-set -g ondemand”.
Os exemplos que dei até aqui são de scripts relativamente complexos. Mas o Kommander também serve bem como interface para scripts simples. É incrível como um simples painel, com algumas instruções básicas sobre o uso do script e um botão “executar” podem valorizar seu trabalho.
Para finalizar, este é um exemplo de painel simples, que serve como interface para o script para baixar arquivos bittorrent que citei anteriormente. Ele tem apenas dois botões de funções e um botão para fechar. O restante é o trabalho visual e a organização dos botões, que dão um visual mais profissional a um script que originalmente passaria despercebido.




























