如何使用 Unity 中的倒计时功能调用 gnome-session-quit?

如何使用 Unity 中的倒计时功能调用 gnome-session-quit?

有能力去使用键盘快捷键关机我们可以分配gnome-session-quit ---power-off给自定义快捷方式。

在 Unity 中这将导致以下对话框:

在此处输入图片描述

然后我们需要至少再按两次键才能最终关闭系统。这相当不方便,我更喜欢旧的关机对话框,因为您只需按下Return或等待默认的 60 秒倒计时即可关闭系统。

gnome-session-quit --poweroffGNOME 会话闪回在同一系统 (14.04 LTS) 上的会话中,包含倒计时的旧对话框再次出现:

在此处输入图片描述

因此我们知道它栖息在某个地方。

有没有办法在运行 Unity 会话时调用这个旧对话框?

答案1

这是模拟所需行为的脚本。必须使用 运行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

更新:6 月 14 日

根据 Takkat 的建议,这里有一个脚本,它利用 zenity 的 --timer 选项和 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 apt-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部分

答案2

不是字面上地您所要求的,但至少一个(有效的)可比较的解决方案是将下面的脚本放在快捷键下。

它能做什么

使用快捷键时:

  • 命令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)是针对相对较慢的系统设置的,以确保鼠标移动出现关机窗口。在较快的系统上,该窗口可以设置得较短;在较慢的系统上(例如可能是 VM),可能需要将该窗口设置得较长。

相关内容