Comment appeler gnome-session-quit avec compte à rebours depuis Unity?

13

Pour pouvoir arrêter avec un raccourci clavier, nous pouvons attribuer gnome-session-quit ---power-offà un raccourci personnalisé.

Dans Unity, cela conduira à la boîte de dialogue suivante:

entrez la description de l'image ici

Ensuite, nous avons besoin d'au moins deux frappes supplémentaires pour enfin éteindre notre système. C'est plutôt gênant et je préférerais l'ancienne boîte de dialogue d'arrêt lorsque vous pouvez éteindre en appuyant simplement Returnou en le laissant attendre le compte à rebours par défaut de 60 secondes.

Lors gnome-session-quit --poweroffd'un appel depuis une session flashback de session GNOME sur le même système (14.04 LTS), l'ancienne boîte de dialogue comprenant le compte à rebours revient:

entrez la description de l'image ici

Nous savons donc qu'il habite quelque part.

Existe-t-il un moyen d'appeler cette ancienne boîte de dialogue lors de l'exécution d'une session Unity?

Takkat
la source
L'unité n'a-t-elle pas de minuterie cachée, donc elle s'éteint après 60 secondes de toute façon ??
Tim
Aux deux: le truc avec la nouvelle boîte de dialogue, c'est qu'elle attend apparemment une sélection de l'utilisateur pour savoir quoi faire ...: /
Takkat
2
@Serg La fenêtre appartient à Session Manager (j'ai exécuté un script d'arrière-plan pour écrire les propriétés d'une nouvelle fenêtre dans un fichier). Le problème est qu'il se comporte différemment, selon le gestionnaire de fenêtres.
Jacob Vlijm
1
@JacobVlijm: oui c'est ce que j'ai pu voir aussi ... il interroge apparemment la WM et appelle ensuite telle ou telle routine mais je n'ai trouvé aucun moyen de forcer cela.
Takkat

Réponses:

10

Voici un script pour émuler le comportement souhaité. Doit être exécuté comme avec sudo. Peut être lié à un raccourci clavier (avec ajout préalable de la shutdowncommande au fichier sudoers pour permettre une exécution sans mot de passe ). Simpliste, concis et fait le travail.

#!/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

Mise à jour: 14 juin

Comme suggéré par Takkat, voici un script qui utilise l'option --timer de zenity et dbus pour obtenir le même comportement sans avoir besoin d'un accès 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

L'idée de base ici est que l'option de délai d'attente de zenity se termine avec un code supérieur à 0, ce qui signifie généralement que la commande a échoué. Ainsi, en traitant l'option d'annulation et le délai d'expiration de zenity comme la condition qui permettra l'arrêt, nous utilisons l'opérateur OR (|| ) pour arrêter uniquement si l'utilisateur clique sur le bouton d'annulation (étiqueté "DOIT") ou que la boîte de dialogue expire.

Une autre variante pour améliorer l'expérience utilisateur peut être effectuée yad(doit être installée en premier avec ces commandes sudo apt-add-repository ppa:webupd8team/y-ppa-manager;sudo apt-get update; sudo apg-get install yad). Cette variante utilise la barre de progression pour indiquer à l'utilisateur le temps restant

    #!/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

Une autre version possible, tient compte du fait que si vous modifiez le libellé du bouton ok de zenity, le bouton mis en surbrillance par défaut peut être ou non le bouton 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

Le script arrête le système lors de tout retour différent de 0. Si le script expire, la valeur de retour 1 ou 5 indique au script d'exécuter la elsepartie

Sergiy Kolodyazhnyy
la source
Fonctionne comme un charme lorsqu'il est exécuté avec sudo ou permet aux utilisateurs non root de s'arrêter. Je préfère ne pas faire ça. Permettez-moi de suggérer les modifications suivantes pour permettre à votre script d'être exécuté par un utilisateur mortel: 1. Utilisez dbus pour la mise hors tension comme cela a été suggéré dans cette réponse 2. Utilisez le zenity --timeoutminuteur intégré. Par cela, nous n'aurons pas à annuler / redémarrer l'arrêt plus tard.
Takkat
@Takkat a ajouté un autre script qui utilise vos suggestions. Veuillez commenter
Sergiy Kolodyazhnyy
Il s'arrête en effet sans mot de passe root mais le bouton OK / DOIT n'est pas sélectionné par défaut pour un arrêt immédiat avec la touche RETOUR. Nous utilisons un script similaire avec if [[ $? -eq 1 ]] ; then exit \else dbus...condition qui fait cela. De toute évidence, il ne semble pas possible d'appeler l'ancien aide à la déconnexion ...
Takkat
Ajoutez les commandes pour installer yad;)
AB
J'aimerais pouvoir partager la prime aux deux réponses. Il était très difficile de décider ici après avoir eu deux réponses aussi excellentes. Enfin, je l'ai donné à Jacob parce que sa réponse semble être un peu plus polyvalente. Mais votre script fait son travail à merveille, et c'est tellement simple. Je le marquerai comme accepté à la place pour le faire apparaître comme la meilleure réponse. J'espère qu'il obtiendra encore plus de votes au fil du temps d'ici là.
Takkat
6

Pas littéralement ce que vous avez demandé, mais au moins une solution (effectivement) comparable serait de mettre le script ci-dessous sous une touche de raccourci.

Ce qu'il fait

Lorsque la touche de raccourci est utilisée:

  • la gnome-session-quit --power-offcommande est exécutée
  • la souris est déplacée vers le bouton "fermer" correspondant, ce qui rend le bouton d'arrêt présélectionné:

    entrez la description de l'image ici

Alors:

  • Si l'utilisateur appuie sur Enter, le système s'arrête
  • Si l'utilisateur ne fait rien, le système attend 30 secondes (ou toute autre période que vous souhaitez définir) et s'arrête.
  • Si l'utilisateur déplace la souris pendant les 30 secondes, la procédure est arrêtée

Le 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

Comment utiliser

Je suis sûr que vous savez comment l'utiliser, mais c'est parti pour des raisons d'habbit:

  1. Le script utilise xdotool

    sudo apt-get install xdotool
    
  2. Copiez le script dans un fichier vide, enregistrez-le sous run_close.py

  3. Dans la section de tête, définissez l'emplacement de l'écran du bouton d'arrêt dans la fenêtre de fermeture (ma première supposition était juste):

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

    et le temps d'attendre avant l'arrêt sans surveillance:

    #--- set the time to wait before shutdown
    countdown = 30
    
  4. Testez-le par la commande:

    python3 /path/to/run_close.py
    

    Testez-le avec toutes les options: appuyez sur Enterpour un arrêt immédiat, un arrêt sans surveillance et interrompez la procédure par un mouvement de souris

  5. Si tout fonctionne bien, ajoutez-le à une touche de raccourci: choisissez: Paramètres système> "Clavier"> "Raccourcis"> "Raccourcis personnalisés". Cliquez sur le "+" et ajoutez la commande:

     python3 /path/to/run_close.py
    

ÉDITER

Ci-dessous une version du script qui ne nécessite aucun paramètre supplémentaire. Il calcule les coordonnées du bouton Quitter, quelle que soit la résolution de l'écran.

La configuration est à peu près la même, mais [3.]peut être ignorée.

#!/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

Explication

La taille de la fenêtre Session Manager pour fermer le système est toujours centrée et d'une taille fixe (absolue), indépendante de la résolution de l'écran. Par conséquent, la position par rapport au centre de l'écran est un facteur constant.

Il suffit alors de lire la résolution de l'écran et de calculer la position du bouton à partir de là.

La fonction appliquée ( get_qloc()) calcule la résolution de l' écran de gauche , puisque c'est celle où le dialogue apparaîtra.

Remarque

L'heure, définie dans la ligne, time.sleep(0.4)est définie pour les systèmes relativement lents, pour vous assurer que la souris est déplacée après l'apparition de la fenêtre d'arrêt. Sur les systèmes plus rapides, il peut être plus court, sur les systèmes plus lents (comme peut-être une machine virtuelle), il peut être nécessaire de définir une durée plus longue.

Jacob Vlijm
la source
@Takkat Fixed, cette version devrait fonctionner sur n'importe quelle résolution.
Jacob Vlijm
Génial! Cela fonctionne également parfaitement sur ma machine virtuelle.
Takkat