Как мне вызвать gnome-session-quit с обратным отсчетом от Unity?

13

Чтобы иметь возможность выключения с помощью сочетания клавиш, мы можем назначить gnome-session-quit ---power-offнастраиваемое сочетание клавиш.

В Unity это приведет к следующему диалогу:

введите описание изображения здесь

Затем нам нужно еще как минимум два нажатия клавиш, чтобы наконец выключить нашу систему. Это довольно неудобно, и я бы предпочел старое диалоговое окно выключения, когда вы можете выключить питание, просто нажав Returnили оставив его ждать по умолчанию обратный отсчет 60 секунд.

При вызове gnome-session-quit --poweroffиз сеанса флэшбэка сеанса GNOME в той же системе (14.04 LTS) возвращается старое диалоговое окно, включая обратный отсчет:

введите описание изображения здесь

Итак, мы знаем, что это где-то обитает.

Есть ли способ вызвать этот старый диалог при запуске сеанса Unity?

Takkat
источник
У Unity One нет скрытого таймера, поэтому он отключается через 60 секунд?
Тим
askubuntu.com/questions/14794/… может помочь
Тим
Для обоих: в новом диалоговом окне есть то, что он, очевидно, ждет выбора пользователя для того, что делать ...: /
Таккат
2
@Serg Окно принадлежит Session Manager (я запустил фоновый скрипт для записи свойств нового окна в файл). Проблема в том, что он ведет себя по-разному, в зависимости от оконного менеджера.
Джейкоб Влейм
1
@JacobVlijm: да, это то, что я тоже мог видеть ... он, по-видимому, опрашивает WM, а затем вызывает ту или иную процедуру, но я не нашел способа форсировать это.
Таккат

Ответы:

10

Вот скрипт для эмуляции желаемого поведения. Должен быть запущен как с sudo. Может быть привязан к сочетанию клавиш (с предварительным добавлением shutdownкоманды в файл sudoers для запуска без пароля ). Упрощенно, лаконично и выполняет свою работу.

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

Обновление: 14 июня

Как предлагает Таккат, вот скрипт, который использует опцию --timer zenity и dbus для достижения того же поведения без необходимости доступа 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

Основная идея здесь заключается в том, что опция времени ожидания zenity завершается с кодом больше 0, что обычно означает, что команда не выполнена. Таким образом, рассматривая опцию отмены zenity и тайм-аут как условие, которое позволит отключить, мы используем оператор OR ( ||) для выключения, только если пользователь нажимает кнопку отмены (помеченную как «DOIT») или время ожидания диалога.

Можно сделать еще один вариант для улучшения взаимодействия с пользователем yad(сначала необходимо установить эти команды sudo apt-add-repository ppa:webupd8team/y-ppa-manager;sudo apt-get update; sudo apg-get install yad). Этот вариант использует индикатор выполнения, чтобы сообщить пользователю, сколько времени осталось

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

В другой возможной версии учитывается, что если вы измените метку кнопки ОК в zenity, кнопка, выделенная по умолчанию, может быть или не быть кнопкой ОК.

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

Сценарий завершает работу системы при любом возврате, который не равен 0. Если время выполнения сценария истекло, возвращаемое значение 1 или 5 указывает сценарию выполнить elseчасть

Сергей Колодяжный
источник
Работает как шарм, когда запускается с sudo или позволяет отключить не-root пользователям. Я бы предпочел не делать этого. Позвольте мне предложить следующие изменения, чтобы разрешить запуск сценария простым пользователем: 1. Используйте dbus для отключения питания, как было предложено в этом ответе 2. Используйте zenity --timeoutвстроенный таймер. При этом нам не придется отменять / перезапускать отключение позже.
Таккат
@Takkat добавил еще один скрипт, который использует ваши предложения. Пожалуйста, оставьте отзыв
Сергей Колодяжный
Он действительно выключается без пароля root, но кнопка OK / DOIT по умолчанию не выбрана для немедленного выключения клавишей RETURN. Мы используем аналогичный скрипт с if [[ $? -eq 1 ]] ; then exit \else dbus...условием, которое делает это. Очевидно, что нет никакого способа вызвать старого помощника выхода из системы ...
Таккат
Добавьте команды для установки yad;)
AB
Хотел бы я разделить награду за оба ответа. Здесь было очень трудно решить, получив два одинаково хороших ответа. В конце концов я передал его Джейкобу, потому что его ответ выглядит более универсальным. Но ваш скрипт прекрасно справляется со своей задачей, и это так просто. Вместо этого я отмечу его как принятый, чтобы он отображался в качестве основного ответа. Я надеюсь, что это получит еще больше голосов со временем.
Таккат
6

Не буквально то, что вы просили, но, по крайней мере, (эффективно) сопоставимое решение было бы поместить сценарий ниже под сочетанием клавиш.

Что оно делает

Когда используется сочетание клавиш:

  • gnome-session-quit --power-offкоманда запускается
  • мышь перемещается к соответствующей кнопке «закрыть», эффективно делая предварительно выбранную кнопку выключения:

    введите описание изображения здесь

Потом:

  • Если пользователь нажимает Enter, система выключается
  • Если пользователь ничего не делает, система ждет 30 секунд (или любой другой период времени, который вы хотите установить) и выключается.
  • Если пользователь перемещает мышь в течение 30 секунд, процедура останавливается

Сценарий

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

Как пользоваться

Я вполне уверен, что вы знаете, как его использовать, но здесь мы пойдем по причинам привычки:

  1. Скрипт использует xdotool

    sudo apt-get install xdotool
    
  2. Скопируйте скрипт в пустой файл, сохраните его как run_close.py

  3. В разделе заголовка установите расположение экрана кнопки выключения в окне закрытия (мое первое предположение было правильным):

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

    и время ожидания, прежде чем отключить без присмотра:

    #--- set the time to wait before shutdown
    countdown = 30
    
  4. Протестируйте его командой:

    python3 /path/to/run_close.py
    

    Протестируйте его всеми опциями: нажмите Enterдля немедленного выключения, автоматического выключения и прервите процедуру движением мыши

  5. Если все работает нормально, добавьте его к сочетанию клавиш: выберите: «Системные настройки»> «Клавиатура»> «Ярлыки»> «Пользовательские ярлыки». Нажмите «+» и добавьте команду:

     python3 /path/to/run_close.py
    

РЕДАКТИРОВАТЬ

Ниже приведена версия скрипта, которая не требует каких-либо дополнительных настроек. Он рассчитывает координаты кнопки выхода, независимо от разрешения экрана.

Настройка почти такая же, но [3.]ее можно пропустить.

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

объяснение

Размер окна диспетчера сеансов для закрытия системы всегда центрирован и имеет фиксированный (абсолютный) размер, не зависящий от разрешения экрана. Поэтому положение относительно центра экрана является постоянным фактором.

Все, что нам нужно сделать, это прочитать разрешение экрана и рассчитать положение кнопки оттуда.

Применяемая функция ( get_qloc()) вычисляет разрешение левого экрана , поскольку именно там появится диалог.

Заметка

Время, установленное в строке time.sleep(0.4), устанавливается для относительно медленных систем, чтобы убедиться, что мышь перемещается после появления окна выключения. В более быстрых системах это может быть короче, в более медленных системах (например, возможно, в ВМ) может потребоваться установить более продолжительное время.

Якоб Влейм
источник
@Takkat Исправлено, эта версия должна работать на любом разрешении.
Джейкоб Влейм
Большой! Это работает безупречно на моей виртуальной машине тоже.
Таккат