Como chamo gnome-session-quit com contagem regressiva do Unity?

13

Para podermos desligar com um atalho de teclado , podemos atribuir gnome-session-quit ---power-offum atalho personalizado.

No Unity, isso levará ao seguinte diálogo:

insira a descrição da imagem aqui

Depois, precisamos de mais pelo menos duas teclas pressionadas para finalmente desligar nosso sistema. Isso é bastante inconveniente e eu preferiria a caixa de diálogo de desligamento antiga quando você pudesse desligar apenas pressionando Returnou deixando aguardar a contagem regressiva padrão de 60 segundos.

Ao chamar gnome-session-quit --poweroffde uma sessão de flashback da sessão do GNOME no mesmo sistema (14.04 LTS), a caixa de diálogo antiga, incluindo a contagem regressiva, volta:

insira a descrição da imagem aqui

Então sabemos que ele mora em algum lugar.

Existe alguma maneira de chamar esse diálogo antigo ao executar uma sessão do Unity?

Takkat
fonte
Será que a unidade não possui um cronômetro oculto, de modo que se apaga após 60 segundos?
Tim
Para ambos: a coisa com a nova caixa de diálogo é que ela aparentemente espera uma seleção de usuários para o que fazer ...: /
Takkat 29/04/14/14:
2
@Serg A janela pertence ao Session Manager (executei um script em segundo plano para gravar as propriedades da nova janela em um arquivo). O problema é que ele se comporta de maneira diferente, dependendo do gerenciador de janelas.
26675 Jacob Vlijm
1
@JacobVlijm: Sim, é isso que eu também pude ver ... aparentemente ele pesquisa o WM e depois chama isso ou aquela rotina, mas não encontrei nenhuma maneira de forçar isso.
Takkat

Respostas:

10

Aqui está um script para emular o comportamento desejado. Deve ser executado como com sudo. Pode ser associado a um atalho de teclado (com a adição preliminar do shutdowncomando ao arquivo sudoers para permitir a execução sem senha ). Simplista, conciso e faz o trabalho.

#!/bin/bash
# Date: June 11,2015
# Author: Serg Kolo
# Description: a script to emulate
# behavior of GNOME session flashback
# shutdown dialog

# Tell ubuntu to shutdown in 1 min
shutdown -P +1 &
# Show the dialog
zenity --question --text="Shutdown now ? Automatic shutdown in 60 seconds" --ok-label="DOIT" 
# If user clicks DOIT, then cancel the old 
# shutdown call that has countdown,
# (because only one shutdown command can be run at a time), and
# tell ubuntu to shutdown immediately
# otherwise - cancel it
if [ $? -eq 0 ];then
        shutdown -c
        shutdown -P now
else
        shutdown -c
fi

Atualização: 14 de junho

Conforme sugerido por Takkat, aqui está um script que utiliza a opção --timer e o dbus do zenity para obter o mesmo comportamento sem a necessidade de acesso ao sudo:

#!/bin/bash
# Date: June 14,2015
# Author: Serg Kolo
# Description: a script to emulate
# behavior of GNOME session flashback
# shutdown dialog
# version #2

zenity --question --text="Shutdown now ? Autoshutdown in 60 seconds" \
    --cancel-label="DOIT" --ok-label="NOPE" --timeout=60 ||  
  dbus-send --system --print-reply --dest=org.freedesktop.login1 \
    /org/freedesktop/login1 "org.freedesktop.login1.Manager.PowerOff" boolean:true

A idéia básica aqui é que a opção de tempo limite do zenity é encerrada com código maior que 0, o que normalmente significa que o comando falhou. Portanto, tratando a opção de cancelamento e o tempo limite do zenity como a condição que permitirá o desligamento, usamos o operador OR ( ||) para encerrar apenas se o usuário clicar no botão Cancelar (rotulado como "DOIT") ou se o diálogo expirar.

Outra variação para melhorar a experiência do usuário pode ser feita yad(precisa ser instalada primeiro com esses comandos sudo apt-add-repository ppa:webupd8team/y-ppa-manager;sudo apt-get update; sudo apg-get install yad). Essa variação usa a barra de progresso para informar ao usuário quanto tempo resta

    #!/bin/bash
    yad --auto-close --sticky --on-top --skip-taskbar --center \
  --text 'Shutdown now ? Autoshutdown in 60 seconds.' \
  --button="gtk-ok:1" --button="gtk-close:0" --image=dialog-question \ 
--title 'Shutdown' --timeout=60 --timeout-indicator=top || 
dbus-send --system --print-reply --dest=org.freedesktop.login1 \
/org/freedesktop/login1 "org.freedesktop.login1.Manager.PowerOff" boolean:true

Outra versão possível, leva em consideração que, se você alterar o rótulo do botão ok do zenity, o botão destacado por padrão pode ou não ser o botão ok.

zenity --question --timeout 10 --text="Automatic shutdown in 10 seconds"
if [[ $? -eq 1 ]] ; then
    # user clicked Cancel
    exit 
else
    dbus-send --system --print-reply --dest=org.freedesktop.login1 /org/freedesktop/login1 "org.freedesktop.login1.Manager.PowerOff" boolean:true
fi

O script encerra o sistema em qualquer retorno que não seja 0. Se o tempo limite do script expirar, o valor de retorno 1 ou 5 indica ao script para executar a elseparte

Sergiy Kolodyazhnyy
fonte
Funciona como um encanto quando executado com sudo ou permite que usuários não-root sejam desligados. Prefiro não fazer isso. Deixe-me sugerir as seguintes edições para permitir que seu script seja executado por um usuário mortal: 1. Use o dbus para desligar, como foi sugerido nesta resposta 2. Use o zenity --timeouttemporizador embutido. Por isso, não precisaremos cancelar / reiniciar o desligamento posteriormente.
Takkat
O @Takkat adicionou outro script que usa suas sugestões. Por favor, revise
Sergiy Kolodyazhnyy
Na verdade, ele é desligado sem a senha de root, mas o botão OK / DOIT não é selecionado por padrão para desligamento imediato com a tecla RETURN. Usamos um script semelhante com a if [[ $? -eq 1 ]] ; then exit \else dbus...condição que faz isso. Obviamente parece haver nenhuma maneira de chamar o velho de logout-helper ...
Takkat
Adicione os comandos para instalar o yad;)
AB
Gostaria de poder dividir a recompensa em ambas as respostas. Foi muito difícil decidir aqui depois de ter duas respostas igualmente ótimas. Finalmente, entreguei a Jacob porque sua resposta parece ser um pouco mais versátil. Mas seu script faz seu trabalho maravilhosamente, e é muito simples. Marcá-lo-ei como aceito para torná-lo a resposta principal. Espero que receba ainda mais votos com o passar do tempo.
Takkat
6

Não literalmente o que você pediu, mas pelo menos uma solução (efetivamente) comparável seria colocar o script abaixo em uma tecla de atalho.

O que faz

Quando a tecla de atalho é usada:

  • o gnome-session-quit --power-offcomando é executado
  • o mouse é movido para o botão "fechar" correspondente, efetivamente tornando o botão de desligamento pré-selecionado:

    insira a descrição da imagem aqui

Então:

  • Se o usuário pressionar Enter, o sistema será encerrado
  • Se o usuário não fizer nada, o sistema aguardará 30 segundos (ou qualquer outro período de tempo que você deseja definir) e será encerrado.
  • Se o usuário mover o mouse durante os 30 segundos, o procedimento será interrompido

O script

#!/usr/bin/env python3
import subprocess
import time

#--- set the location of the close button x, y
q_loc = [1050, 525]
#--- set the time to wait before shutdown
countdown = 30

subprocess.Popen(["gnome-session-quit", "--power-off"])
# for slower systems, set a longer break, on faster systems, can be shorter:
time.sleep(0.4)
subprocess.Popen(["xdotool", "mousemove", str(q_loc[0]), str(q_loc[1])])

coords1 = q_loc
t = 0

while True:
    time.sleep(1)
    cmd = "xdotool", "getmouselocation"
    currloc = subprocess.check_output(cmd).decode("utf-8").split()[:2]
    coords2 = [int(n.split(":")[1]) for n in currloc]
    if coords2 != coords1:
        break
    else:
        if t >= countdown:
            subprocess.Popen(["xdotool", "key", "KP_Enter"])
            break
    t += 1

Como usar

Tenho certeza que você sabe como usá-lo, mas aqui vamos por razões de habbit:

  1. O script usa xdotool

    sudo apt-get install xdotool
    
  2. Copie o script em um arquivo vazio, salve-o como run_close.py

  3. Na seção principal, defina a localização da tela do botão desligar na janela próxima (minha primeira hipótese foi correta):

    #--- set the location of the close button x, y
    q_loc = [1050, 525]
    

    e o tempo de espera antes do desligamento automático:

    #--- set the time to wait before shutdown
    countdown = 30
    
  4. Execute-o de teste pelo comando:

    python3 /path/to/run_close.py
    

    Teste-o com todas as opções: pressionando Enterpara desligar imediatamente, desligar sem supervisão e interromper o procedimento movendo o mouse

  5. Se tudo funcionar bem, adicione-o a uma tecla de atalho: escolha: Configurações do sistema> "Teclado"> "Atalhos"> "Atalhos personalizados". Clique no "+" e adicione o comando:

     python3 /path/to/run_close.py
    

EDITAR

Abaixo de uma versão do script que não precisa de nenhuma configuração adicional. Ele calcula as coordenadas do botão sair, independentemente da resolução da tela.

A configuração é praticamente a mesma, mas [3.]pode ser ignorada.

#!/usr/bin/env python3
import subprocess
import time

#--- set the time to wait before shutdown
countdown = 30

def get_qloc():
    xr = subprocess.check_output(["xrandr"]).decode("utf-8").split()
    scrs = [s.split("+") for s in xr if all([s.count("x") == 1, s.count("+") == 2])]
    center = [int(int(s)/2) for s in [scr[0] for scr in scrs if scr[1] == "0"][0].split("x")]
    return [center[0] + 250, center[1]]

q_loc = get_qloc()

subprocess.Popen(["gnome-session-quit", "--power-off"])
# for slower systems, set a longer break, on faster systems, can be shorter:
time.sleep(0.4)
subprocess.Popen(["xdotool", "mousemove", str(q_loc[0]), str(q_loc[1])])

coords1 = q_loc
t = 0

while True:
    time.sleep(1)
    cmd = "xdotool", "getmouselocation"
    currloc = subprocess.check_output(cmd).decode("utf-8").split()[:2]
    coords2 = [int(n.split(":")[1]) for n in currloc]
    if coords2 != coords1:
        break
    else:
        if t >= countdown:
            subprocess.Popen(["xdotool", "key", "KP_Enter"])
            break
    t += 1

Explicação

O tamanho da janela do Session Manager para fechar o sistema sempre está centralizado e tem um tamanho fixo (absoluto), independente da resolução da tela. Portanto, a posição relativa ao centro da tela é um fator constante.

Tudo o que precisamos fazer é ler a resolução da tela e calcular a posição do botão a partir daí.

A função aplicada ( get_qloc()) calcula a resolução da tela esquerda , pois é nesse local que o diálogo aparecerá.

Nota

O tempo definido na linha time.sleep(0.4)é definido para sistemas relativamente lentos, para garantir que o mouse seja movido após a janela de desligamento aparecer. Em sistemas mais rápidos, pode ser mais curto; em sistemas mais lentos (como possivelmente uma VM), pode ser necessário definir mais.

Jacob Vlijm
fonte
@ Takkat Corrigida, esta versão deve funcionar em qualquer resolução.
Jacob Vlijm
Ótimo! Também funciona perfeitamente na minha VM.
Takkat