如何通过Unity倒计时调用gnome-session-quit?


13

为了能够使用键盘快捷键关闭,我们可以分配gnome-session-quit ---power-off一个自定义快捷键。

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

在此处输入图片说明

然后,我们还需要至少两次击键才能最终关闭系统电源。这非常不方便,如果您可以通过按Return或让其等待默认的60秒倒计时关闭电源,则我希望使用旧的关闭对话框。

gnome-session-quit --poweroff从同一系统(14.04 LTS)上的GNOME会话闪回会话进行调用时,包含倒数计时的旧对话框会返回:

在此处输入图片说明

因此,我们知道它驻留在某个地方。

运行Unity会话时,有什么方法可以调用此旧对话框?


团结者是否没有隐藏计时器,因此无论如何在60秒后会关闭电源?
蒂姆(Tim)


两者都存在:新对话框的作用是,它显然在等待用户选择要执行的操作...:/
Takkat 2014年

2
@Serg窗口属于会话管理器(我运行了一个后台脚本,将新窗口的属性写入文件)。问题在于它的行为不同,具体取决于窗口管理器。
Jacob Vlijm 2015年

1
@JacobVlijm:是的,我也可以看到它…显然轮询WM,然后调用此例程或该例程,但是我没有找到强制执行此方法的方法。
塔卡特2015年

Answers:


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

更新: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的cancel选项和超时视为允许关闭的条件,我们||仅在用户单击取消按钮(标记为“ DOIT”)或对话框超时时才使用OR运算符()关闭。

可以使用另一种改进用户体验的变体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内置计时器。这样,我们以后就不必取消/重新启动关机了。
塔卡特2015年

@Takkat添加了另一个使用您建议的脚本。请查看
Sergiy Kolodyazhnyy 2015年

它确实确实在没有root密码的情况下关闭,但是默认情况下未选择OK / DOIT按钮使用RETURN键立即关闭。我们使用if [[ $? -eq 1 ]] ; then exit \else dbus...条件类似的脚本来做到这一点。显然,似乎没有办法打电话给旧的注销助手...
Takkat 2015年

添加命令以安装yad;)
AB

希望我可以将赏金分配给两个答案。在得到两个同样出色的答案之后,很难在这里做出决定。最后,我把它交给了雅各布,因为他的回答似乎更加灵活。但是您的脚本可以出色地完成其工作,而且非常简单。我将其标记为已接受,以使其显示为最佳答案。我希望届时它将获得更多的选票。
塔卡特2015年

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)中设置的时间是为相对较慢的系统设置的,以确保在出现关闭窗口移动鼠标。在较快的系统上,它可能会更短,而在较慢的系统(可能是VM)上,可能需要将其设置为更长。


@Takkat已修复,此版本应可在任何分辨率下使用。
Jacob Vlijm 2015年

大!它也可以在我的VM上完美运行。
塔卡特2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.