Wie rufe ich gnome-session-quit mit Countdown von Unity auf?

13

Um mit einer Tastenkombination herunterfahren zu können, können wir gnome-session-quit ---power-offeine benutzerdefinierte Tastenkombination zuweisen .

In Unity führt dies zum folgenden Dialog:

Bildbeschreibung hier eingeben

Dann brauchen wir mindestens zwei weitere Tastatureingaben, um unser System endgültig auszuschalten. Dies ist ziemlich unpraktisch und ich würde das alte Dialogfeld zum Herunterfahren vorziehen, wenn Sie es ausschalten könnten, indem Sie einfach drücken Returnoder den Standard-Countdown von 60 Sekunden abwarten lassen.

Beim Aufruf gnome-session-quit --poweroffvon einer GNOME-Session-Flashback- Session auf demselben System (14.04 LTS) wird der alte Dialog mit dem Countdown zurückgegeben:

Bildbeschreibung hier eingeben

Wir wissen also, dass es irgendwo wohnt.

Gibt es eine Möglichkeit, diesen alten Dialog aufzurufen, wenn eine Unity-Sitzung ausgeführt wird?

Takkat
quelle
Hat die Einheit keinen versteckten Timer, so dass sie sowieso nach 60 Sekunden abschaltet?
Tim
Für beide: Das Problem mit dem neuen Dialogfeld ist, dass es anscheinend auf eine Benutzerauswahl wartet, um zu sehen, was zu tun ist ...: /
Takkat
2
@Serg Das Fenster gehört zum Session Manager (ich habe ein Hintergrundskript ausgeführt, um die Eigenschaften des neuen Fensters in eine Datei zu schreiben). Das Problem ist, dass es sich je nach Fenstermanager unterschiedlich verhält.
Jacob Vlijm
1
@JacobVlijm: Ja, das ist es, was ich auch sehen konnte ... es fragt anscheinend die WM ab und ruft dann diese oder jene Routine auf, aber ich habe keine Möglichkeit gefunden, dies zu erzwingen.
Takkat,

Antworten:

10

Hier ist ein Skript, um das gewünschte Verhalten zu emulieren. Muss wie mit ran sudo. Kann an eine Tastenkombination gebunden werden (mit vorläufigem Hinzufügen des shutdownBefehls zur sudoers-Datei, um das Ausführen ohne Kennwort zu ermöglichen ). Einfach, präzise und macht den Job.

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

Update: 14. Juni

Wie von Takkat vorgeschlagen, ist hier ein Skript, das die --timer-Option und den dbus von zenity verwendet, um dasselbe Verhalten zu erzielen, ohne dass ein sudo-Zugriff erforderlich ist:

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

Die Grundidee dabei ist, dass die Timeout-Option von zenity mit einem Code größer als 0 beendet wird, was normalerweise bedeutet, dass der Befehl fehlgeschlagen ist. Indem wir die Abbruchoption und das Timeout von zenity als Bedingung behandeln, die das Herunterfahren ermöglichen, verwenden wir den Operator OR ( ||), um das Herunterfahren nur dann durchzuführen, wenn der Benutzer auf die Abbruchschaltfläche (mit der Bezeichnung "DOIT") klickt oder das Dialogfeld abläuft.

Eine weitere Variante zur Verbesserung der Benutzererfahrung kann verwendet werden yad(muss zuerst mit diesen Befehlen installiert werden sudo apt-add-repository ppa:webupd8team/y-ppa-manager;sudo apt-get update; sudo apg-get install yad). Bei dieser Variante wird der Fortschrittsbalken verwendet, um den Benutzer über die verbleibende Zeit zu informieren

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

Eine andere mögliche Version berücksichtigt, dass die standardmäßig hervorgehobene Schaltfläche die OK-Schaltfläche sein kann oder nicht, wenn Sie die Beschriftung der OK-Schaltfläche von zenity ändern.

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

Das Skript fährt das System herunter, wenn eine Rückgabe ungleich 0 erfolgt. Wenn das Skript eine Zeitüberschreitung aufweist, weist der Rückgabewert 1 oder 5 das Skript an, die auszuführen else Teil

Sergiy Kolodyazhnyy
quelle
Funktioniert wie ein Zauber, wenn Sie mit sudo ausgeführt werden oder Benutzern ohne Rootberechtigung das Herunterfahren ermöglichen. Das mache ich lieber nicht. Lassen Sie mich die folgenden Änderungen vorschlagen, damit Ihr Skript von einem sterblichen Benutzer ausgeführt werden kann: 1. Verwenden Sie dbus zum Ausschalten, wie in dieser Antwort vorgeschlagen. 2. Verwenden Sie den zenity --timeouteingebauten Timer. Auf diese Weise müssen wir das Herunterfahren später nicht abbrechen / neu starten.
Takkat,
@Takkat hat ein weiteres Skript hinzugefügt, das Ihre Vorschläge verwendet. Bitte überprüfen Sie
Sergiy Kolodyazhnyy
Es wird zwar ohne root-Passwort heruntergefahren, aber die Schaltfläche OK / DOIT ist nicht standardmäßig für das sofortige Herunterfahren mit der Taste RETURN ausgewählt. Wir benutzen ein ähnliches Skript mit einer if [[ $? -eq 1 ]] ; then exit \else dbus...Bedingung, die das macht. Offensichtlich gibt es keine Möglichkeit, den alten Logout-Helfer
anzurufen
Fügen Sie die Befehle hinzu, um yad zu installieren;)
AB
Ich wünschte, ich könnte das Kopfgeld auf beide Antworten aufteilen. Es war sehr schwer, sich hier zu entscheiden, nachdem ich zwei gleich gute Antworten hatte. Schließlich gab ich es Jacob, weil seine Antwort ein bisschen vielseitiger zu sein scheint. Aber Ihr Skript macht seine Arbeit wunderbar und es ist so einfach. Ich werde es stattdessen als akzeptiert markieren, damit es als oberste Antwort angezeigt wird. Ich hoffe, dass es dadurch im Laufe der Zeit noch mehr Stimmen gibt.
Takkat,
6

Nicht wörtlich, wonach Sie gefragt haben, aber zumindest eine (effektiv) vergleichbare Lösung wäre, das folgende Skript unter eine Tastenkombination zu setzen.

Was es macht

Wenn die Tastenkombination verwendet wird:

  • Der gnome-session-quit --power-offBefehl wird ausgeführt
  • wird die Maus in die entsprechende Schaltfläche „Schließen“ bewegt wird , wirksam das Herunterfahren Schaltfläche ausgewählt prä- machen:

    Bildbeschreibung hier eingeben

Dann:

  • Wenn der Benutzer drückt Enter, wird das System heruntergefahren
  • Wenn der Benutzer nichts unternimmt, wartet das System 30 Sekunden (oder einen anderen Zeitraum, den Sie festlegen möchten) und fährt herunter.
  • Wenn der Benutzer die Maus während der 30 Sekunden bewegt, wird der Vorgang abgebrochen

Das Drehbuch

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

Wie benutzt man

Ich bin mir ziemlich sicher, dass Sie wissen, wie man es benutzt, aber hier kommen wir aus Gründen der Gewohnheit:

  1. Das Skript verwendet xdotool

    sudo apt-get install xdotool
    
  2. Kopieren Sie das Skript in eine leere Datei und speichern Sie es unter run_close.py

  3. Legen Sie im Kopfbereich die Position des Bildschirms für die Schaltfläche zum Herunterfahren im Schließfenster fest (meine erste Vermutung war richtig):

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

    und die Wartezeit vor dem unbeaufsichtigten Herunterfahren:

    #--- set the time to wait before shutdown
    countdown = 30
    
  4. Führen Sie es mit dem folgenden Befehl aus:

    python3 /path/to/run_close.py
    

    Testen Sie es mit allen Optionen: Drücken Sie, Enterum sofort herunterzufahren, und brechen Sie den Vorgang mit der Maus ab

  5. Wenn alles funktioniert, fügen Sie es einer Tastenkombination hinzu: Wählen Sie: Systemeinstellungen> "Tastatur"> "Tastenkombinationen"> "Benutzerdefinierte Tastenkombinationen". Klicken Sie auf das "+" und fügen Sie den Befehl hinzu:

     python3 /path/to/run_close.py
    

BEARBEITEN

Unten eine Version des Skripts, für die keine zusätzlichen Einstellungen erforderlich sind. Es berechnet die Koordinaten der Schaltfläche "Beenden", unabhängig von der Bildschirmauflösung.

Das Setup ist ziemlich gleich, [3.]kann aber übersprungen werden.

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

Erläuterung

Die Größe des Session Manager-Fensters zum Schließen des Systems ist immer zentriert und von fester (absoluter) Größe, unabhängig von der Bildschirmauflösung. Daher die Position relativ zur Bildschirmmitte ein konstanter Faktor.

Alles, was wir dann tun müssen, ist, die Bildschirmauflösung zu lesen und die Position der Schaltfläche von dort aus zu berechnen.

Die angewendete Funktion ( get_qloc()) berechnet die Auflösung des linken Bildschirms , da hier der Dialog angezeigt wird.

Hinweis

Die in der Zeile festgelegte Zeit time.sleep(0.4)ist für relativ langsame Systeme festgelegt, um sicherzustellen, dass die Maus bewegt wird, nachdem das Fenster zum Herunterfahren angezeigt wird. Auf schnelleren Systemen kann es kürzer sein, auf langsameren Systemen (wie möglicherweise einer VM) muss es möglicherweise länger eingestellt werden.

Jacob Vlijm
quelle
@Takkat Behoben, diese Version sollte auf jeder Auflösung funktionieren.
Jacob Vlijm
Groß! Es funktioniert auch auf meiner VM einwandfrei.
Takkat