有能力去使用键盘快捷键关机我们可以分配gnome-session-quit ---power-off
给自定义快捷方式。
在 Unity 中这将导致以下对话框:
然后我们需要至少再按两次键才能最终关闭系统。这相当不方便,我更喜欢旧的关机对话框,因为您只需按下Return或等待默认的 60 秒倒计时即可关闭系统。
当gnome-session-quit --poweroff
从GNOME 会话闪回在同一系统 (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
如何使用
我确信你知道如何使用它,但出于习惯原因,我们还是先这样吧:
该脚本使用
xdotool
sudo apt-get install xdotool
将脚本复制到一个空文件中,另存为
run_close.py
在头部部分,设置关闭窗口中关机按钮的屏幕位置(我的第一个猜测是正确的):
#--- set the location of the close button x, y q_loc = [1050, 525]
以及无人值守关机前等待的时间:
#--- set the time to wait before shutdown countdown = 30
通过命令测试运行:
python3 /path/to/run_close.py
使用所有选项进行测试:按下Enter立即关机、无人值守关机并通过鼠标移动中断程序
如果一切正常,请将其添加到快捷键:选择:系统设置>“键盘”>“快捷键”>“自定义快捷键”。单击“+”并添加命令:
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),可能需要将该窗口设置得较长。