Jak zadzwonić do gnome-session-quit z odliczaniem z Unity?

13

Aby móc zamknąć system za pomocą skrótu klawiaturowego , możemy przypisać gnome-session-quit ---power-offniestandardowy skrót.

W Unity spowoduje to wyświetlenie następującego okna dialogowego:

wprowadź opis zdjęcia tutaj

Następnie potrzebujemy kolejnych co najmniej dwóch naciśnięć klawiszy, aby w końcu wyłączyć nasz system. Jest to raczej niewygodne i wolałbym stare okno dialogowe zamykania, w którym można było wyłączyć, naciskając Returnlub pozwalając mu czekać domyślnym odliczaniem 60 sekund.

Podczas wywoływania gnome-session-quit --poweroffz sesji flashowania sesji GNOME w tym samym systemie (14.04 LTS) powraca stare okno dialogowe zawierające odliczanie:

wprowadź opis zdjęcia tutaj

Więc wiemy, że gdzieś mieszka.

Czy jest jakiś sposób na wywołanie tego starego okna dialogowego podczas uruchamiania sesji Unity?

Takkat
źródło
Czy jedność nie ma ukrytego timera, więc i tak wyłącza się po 60 sekundach?
Tim
Do obu: chodzi o to, że nowe okno dialogowe najwyraźniej czeka na wybór użytkownika, co ma zrobić ...: /
Takkat
2
@Serg Okno należy do Menedżera sesji (uruchomiłem skrypt w tle, aby zapisać właściwości nowego okna do pliku). Problem polega na tym, że zachowuje się inaczej, w zależności od menedżera okien.
Jacob Vlijm
1
@JacobVlijm: tak, też to widziałem ... najwyraźniej sonduje WM, a następnie nazywa tę lub inną rutynę, ale nie znalazłem sposobu, aby to wymusić.
Takkat,

Odpowiedzi:

10

Oto skrypt do naśladowania pożądanego zachowania. Musi być prowadzony jak z sudo. Można powiązać ze skrótem klawiaturowym (ze wstępnym dodaniem shutdownpolecenia do pliku sudoers, aby umożliwić uruchomienie bez hasła ). Prosty, zwięzły i spełnia swoje zadanie.

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

Aktualizacja: 14 czerwca

Jak sugeruje Takkat, oto skrypt, który wykorzystuje opcję - timera zenity i dbus, aby osiągnąć to samo zachowanie bez potrzeby dostępu do 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

Podstawową ideą jest to, że opcja limitu czasu zenity kończy działanie z kodem większym niż 0, co zwykle oznacza, że ​​polecenie nie powiodło się. Tak więc traktując opcję anulowania i limit czasu zenity jako warunek umożliwiający zamknięcie, używamy operatora OR ( ||), aby zamknąć tylko wtedy, gdy użytkownik kliknie przycisk anulowania (oznaczony jako „DOIT”) lub upłynie limit czasu okna dialogowego.

Można wprowadzić inną odmianę, aby poprawić wrażenia użytkownika yad(najpierw należy zainstalować za pomocą tych poleceń sudo apt-add-repository ppa:webupd8team/y-ppa-manager;sudo apt-get update; sudo apg-get install yad). Ta odmiana wykorzystuje pasek postępu, aby poinformować użytkownika, ile czasu pozostało

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

Inna możliwa wersja bierze pod uwagę, że jeśli zmienisz etykietę przycisku OK zenity, domyślnie podświetlony przycisk może być przyciskiem 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

Skrypt zamyka system przy każdym zwrocie, który nie jest równy 0. Jeśli skrypt przekroczy limit czasu, wartość 1 lub 5 zwraca skryptowi wykonanie elseczęści

Sergiy Kolodyazhnyy
źródło
Działa jak urok podczas pracy z sudo lub pozwala użytkownikom innym niż root na zamknięcie. Wolałbym tego nie robić. Pozwól, że zasugeruję następujące zmiany, aby umożliwić skryptowi uruchamianie przez śmiertelnego użytkownika: 1. Użyj dbus do wyłączenia zasilania, jak zasugerowano w tej odpowiedzi 2. Użyj zenity --timeoutwbudowanego timera. Dzięki temu nie będziemy musieli anulować / ponownie uruchomić zamknięcia później.
Takkat
@Takkat dodał kolejny skrypt, który wykorzystuje twoje sugestie. Proszę przejrzeć
Sergiy Kolodyazhnyy
Rzeczywiście wyłącza się bez hasła roota, ale przycisk OK / DOIT nie jest domyślnie wybrany do natychmiastowego zamknięcia za pomocą klawisza RETURN. Używamy podobnego skryptu z if [[ $? -eq 1 ]] ; then exit \else dbus...warunkiem, który to robi. Oczywiście wydaje się, że nie ma sposobu, aby zadzwonić do starego pomocnika wylogowania ...
Takkat
Dodaj polecenia, aby zainstalować yad;)
AB
Chciałbym móc podzielić nagrodę na obie odpowiedzi. Trudno było tu podjąć decyzję po otrzymaniu dwóch tak równie wspaniałych odpowiedzi. Wreszcie dałem go Jakubowi, ponieważ jego odpowiedź wydaje się być bardziej wszechstronna. Ale twój skrypt wykonuje swoją pracę cudownie i jest tak prosty. Oznaczę to jako zaakceptowane, aby pokazać się jako najlepsza odpowiedź. Mam nadzieję, że z czasem zyska jeszcze więcej głosów.
Takkat
6

Nie dosłownie o co prosiłeś, ale przynajmniej (efektywnie) porównywalnym rozwiązaniem byłoby umieszczenie skryptu poniżej pod klawiszem skrótu.

Co to robi

Gdy używany jest klawisz skrótu:

  • gnome-session-quit --power-offpolecenie jest uruchamiane
  • mysz jest przesuwana do przycisku odpowiadającego „blisko”, skutecznie czyniąc wstępnie wybrany przycisk zamykania:

    wprowadź opis zdjęcia tutaj

Następnie:

  • Jeśli użytkownik naciśnie Enter, system wyłącza się
  • Jeśli użytkownik nic nie robi, system czeka 30 sekund (lub inny okres, który chcesz ustawić) i wyłącza się.
  • Jeśli użytkownik poruszy myszką w ciągu 30 sekund, procedura zostanie zatrzymana

Scenariusz

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

Jak używać

Jestem pewien, że wiesz, jak go używać, ale oto powód dla którego nawykliśmy:

  1. Używa skryptu xdotool

    sudo apt-get install xdotool
    
  2. Skopiuj skrypt do pustego pliku i zapisz go jako run_close.py

  3. W sekcji głowy ustaw lokalizację przycisku zamykania na ekranie w zamkniętym oknie (moje pierwsze przypuszczenie było słuszne):

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

    i czas oczekiwania na zamknięcie bez nadzoru:

    #--- set the time to wait before shutdown
    countdown = 30
    
  4. Uruchom go testowo za pomocą polecenia:

    python3 /path/to/run_close.py
    

    Przetestuj to z wszystkimi opcjami: naciskanie w Entercelu natychmiastowego wyłączenia, nienadzorowanego wyłączenia i przerwanie procedury za pomocą myszy

  5. Jeśli wszystko działa poprawnie, dodaj go do klawisza skrótu: wybierz: Ustawienia systemu> „Klawiatura”> „Skróty”> „Skróty niestandardowe”. Kliknij „+” i dodaj polecenie:

     python3 /path/to/run_close.py
    

EDYTOWAĆ

Poniżej wersja skryptu, która nie wymaga żadnych dodatkowych ustawień. Oblicza współrzędne przycisku wyjścia, bez względu na rozdzielczość ekranu.

Konfiguracja jest prawie taka sama, ale [3.]można ją pominąć.

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

Wyjaśnienie

Rozmiar okna Menedżera sesji do zamknięcia systemu jest zawsze wyśrodkowany i ma stały (absolutny) rozmiar, niezależny od rozdzielczości ekranu. Dlatego położenie względem środka ekranu jest stałym czynnikiem.

Wszystko, co musimy wtedy zrobić, to odczytać rozdzielczość ekranu i stamtąd obliczyć pozycję przycisku.

Zastosowana funkcja ( get_qloc()) oblicza rozdzielczość lewego ekranu , ponieważ to właśnie tam pojawi się dialog.

Uwaga

Czas ustawiony w wierszu time.sleep(0.4)jest ustawiony dla względnie wolnych systemów, aby upewnić się, że mysz zostanie poruszona po wyświetleniu okna zamykania. W szybszych systemach może być krótszy, w wolniejszych systemach (np. VM) może być konieczne ustawienie dłuższej.

Jacob Vlijm
źródło
@Takkat Naprawiono, ta wersja powinna działać na dowolnej rozdzielczości.
Jacob Vlijm,
Świetny! Działa również bezbłędnie na mojej maszynie wirtualnej.
Takkat