Teoria básica
Como você pode ou não saber, muitas ações do Unity são implementadas usando o dbus . A grande conveniência do dbus é que você pode realizar muitas ações requeridas pela raiz, chamando os métodos apropriados na linha de comando, sem precisar de conta de administrador, por exemplo desligando o seu sistema .
Especificamente em nosso caso, estamos interessados em com.canonical.Unity
service, /com/canonical/Unity/Session
path. Você pode listar informações sobre ele com o comando qdbus
. Particularmente, estamos interessados em sinais que possuem Requested
neles.
$ qdbus com.canonical.Unity /com/canonical/Unity/Session | grep 'signal.*Requested.*'
signal void com.canonical.Unity.Session.LockRequested()
signal void com.canonical.Unity.Session.LogoutRequested(bool have_inhibitors)
signal void com.canonical.Unity.Session.RebootRequested(bool have_inhibitors)
signal void com.canonical.Unity.Session.ShutdownRequested(bool have_inhibitors)
signal void com.canonical.Unity.Session.UnlockRequested()
Esses sinais aparecem no barramento quando o usuário clica em qualquer um dos itens de desligamento, bloqueio, logout ou reinicialização no menu da sessão suspensa, no lado direito da barra superior do Unity. Então, o que precisamos fazer é isto:
- monitore o barramento para esses sinais aparecerem.
- depois de aparecerem, execute uma determinada ação.
É claro que o grande divulgador é que, se um usuário usar sudo shutdown -P now
ou gnome-session-quit
, isso não será informado para o dbus
, portanto, qualquer ação desejada não será ser feito.
Monitorando o dbus
Convenientemente, há um comando para isso, dbus-monitor
, e podemos filtrar sua saída usando um conjunto de opções e executar uma ação usando while read do … done
structure
Abaixo está um exemplo de um script de monitoramento simples.
dbus-monitor --profile "interface='com.canonical.Unity.Session',type=signal" | \
while read -r line;
do
echo "$line"
sleep 0.25
done
O que ele faz é meramente monitorar o barramento em busca de sinais, e fazer com que eles voltem ao stdout se eles aparecerem; Claro que o eco pode ser qualquer comando. Execute-o e tente clicar em cada item no menu da sessão que deve gerar sinais, e você verá algo como isto:
$ ./logout_monitor.sh
sig 1458319246 172587 2 /org/freedesktop/DBus org.freedesktop.DBus NameAcquired
sig 1458319251 213766 5496 /com/canonical/Unity/Session com.canonical.Unity.Session RebootRequested
sig 1458319265 62555 5525 /com/canonical/Unity/Session com.canonical.Unity.Session LogoutRequested
sig 1458319271 856770 5555 /com/canonical/Unity/Session com.canonical.Unity.Session LockRequested
sig 1458319273 223940 5564 /com/canonical/Unity/Session com.canonical.Unity.Session Locked
sig 1458319276 991413 5604 /com/canonical/Unity/Session com.canonical.Unity.Session UnlockRequested
sig 1458319278 3443 5606 /com/canonical/Unity/Session com.canonical.Unity.Session Unlocked
Portanto, agora temos uma função de monitoramento que pode executar uma ação quando ocorre uma interrupção. Agora, para resolver a questão específica que você estava tentando resolver, seu script está tirando instantâneos dos ícones na área de trabalho. Não há nenhum dano se fizermos um snapshot a cada vez que um sinal ocorrer - ele não precisa ser reinicializado ou desligado especificamente. Portanto, se monitorarmos essa interface Unity específica para sinais e tirarmos instantâneos após a chegada de cada sinal, poderemos simplificar o script.
Script orientado a interrupções
Abaixo, você pode ver um script baseado em interrupções que irá monitorar o barramento por sinais (ignorando o primeiro) e se tivermos um sinal entrando, então chame uma função de interrupção (que no seu caso será o script de instantâneo do ícone que você escreveu).
#!/bin/bash
main()
{
ARG="cow"
dbus-monitor --profile "interface='com.canonical.Unity.Session',type=signal" |
while read -r line;
do
grep -q '.*NameAcquired.*' <<< "$line" && continue # Ignore that first line
if [ -n "$line" ];then
interrupt $ARG # call your python snapshot script here
fi
done
}
interrupt()
{
echo 'Old McDonald had a ' $ARG ' e-i-e-i-o '
}
main
OBSERVAÇÃO : O Dbus conta com uma sessão GUI, já que (até onde eu sei) começa com o login do Unity / Gnome. Ambientes mais antigos, como blackbox e openbox, assim como ambientes TTY não iniciam a sessão dbus, por isso o script vai vomitar se você tentar iniciá-lo em ~/.profile
(eu tive um usuário que tentou fazer algo assim e ele entrou em apuros). Inicie o script usando o programa Unity ou Gnome's Startup Applications .
Indo além deste script
- O Dbus tem muitas APIs, incluindo python
- Eu prefiro usar
qdbus
porque é simples, mas sempre é possível usardbus-send
. Exemplos - A função de interrupção pode ser qualquer coisa, até mesmo outros métodos
dbus
. Há muito para se olhar.
Curiosidades : Eu usei esse mesmo método para prevenir o desligamento se o apt estiver em execução