解决方法

解决方法

关机时,会出现“您确定吗……”对话框。有时我想给自己发送一个提醒,例如运行一个通宵工作而不是关机。然后我需要显示另一个对话框 - 在“您确定吗”之前或旁边。(或者任何其他明显的提醒都可以,比如更改“您确定吗”框的颜色,但这可能涉及修改 Linux 模块的核心,而我并不想尝试。)我无法让新的 .service 文件按照其他地方描述的方式工作。由于在关机时我可能无法访问屏幕,因此我尝试将“touch /home/myuser/i_ran”添加到我的关机前脚本中。我还尝试将其添加到 atd 的 init.d 脚本的 stop 子句中。两者都不起作用。什么会起作用?理想情况下,它应该以我当前的用户身份运行,或者如果以 root 身份运行,我的脚本可以 su 到我当前的用户。我正在使用通知发送对话框,并运行 Ubuntu 20.04,经典 Gnome。

答案1

前言

这个答案并不是对您的问题的直接解决方案,而是一个重要的方法论讨论,它应该为您以及其他试图帮助您朝着正确方向发展的社区成员提供指导,并希望节省时间和精力。

讨论

你需要第一的保持/阻止关机可以通过多种方式完成...一种简单的方法是使用内置功能免费桌面systemd-inhibit可以从终端或脚本中轻松使用...并且然后您需要显示一个带有特定消息的对话窗口,这并不像上面那么简单(第一的要求),因为它需要正在运行的显示服务器和正在运行的用户图形 gnome 会话...但是,这无法通过外部方法实现(独立的) 到 gnome-shell,因为当系统收到有关“关闭”的通知时,用户的 gnome 会话将已经终止,并且已经带走了任何可能的用户 GUI 交互的机会...因此,据我所知,您的两个选择是:

  • 或者,用 C 或 Python 编写自己的应用程序来实现GTK 的抑制显然,一些 gnome 应用程序使用了它,例如gedit文本编辑器) 在链接源代码的第 1407 行,"There are unsaved documents"其中的消息将显示在 gnome 关机确认对话框中,而您自己的消息也将出现在您自己的应用程序中...但是,要使其正常工作,您的应用程序的进程需要在 gnome 用户会话中尝试关闭系统时运行...这是一个非常小的 Python 脚本示例(使用计算器Gnome 核心应用程序作为虚拟应用程序)只会做这个,而不会做其他事情:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

def on_activate(app):
  win = Gtk.ApplicationWindow.new(app)
  app.inhibit(win, Gtk.ApplicationInhibitFlags.LOGOUT | 
  Gtk.ApplicationInhibitFlags.SUSPEND, 
  'It\'s time to do some tasks:\n1) Task one ...\n2) Task two ...\n3) Task three ...')

app = Gtk.Application.new('org.gnome.Calculator', 0)
app.connect('activate', on_activate)
app.run()

解决方法

解决方法是采用替代的非原生解决方案,例如采用这样的关机脚本的形式:

#!/bin/bash

shut_down () {
zenity --question --default-cancel \
--text="You still have unfinished tasks:\n  \
1) Task one ...\n  \
2) Task two ...\n  \
3) Task three ...\n\n\
Are you sure you want to shutdown anyway?"
}

if shut_down
  then
    echo "Shutting down ..."
    # Your shutdown command(s) (either systemd or gnome-shell based) here
    fi

...然后,您需要使用该脚本而不是正常的关机 GUI 按钮...您可能希望禁用默认按钮或将其链接到此脚本(您可能需要查找/编写链接部分的扩展) 来实现某种本机功能的外观。

其他解决方法可能是:

  • 如果您能找到一个可用于此目的的 gnome-shell 扩展...
  • 或者,如果您知道如何做的话,您可以创建自己的 gnome-shell 扩展。
  • 一些用于管理关机的包/应用程序可能可通过 Ubuntu 的包管理器获得,例如 APT、SNAP 或 FLATPACK……等等……因此,请务必搜索这些。

Gnome 会话讨论

尽管如此,Gnome 中发生的事情仍留在 Gnome 中,即它有自己的方法,与其他进程分开(我的意思是 Gnome 内部),但您可以使用正确的工具来观察它是如何工作的并尝试与它交互......如果您dbus-monitor在终端中运行,保持它运行并尝试关闭/注销,然后只需单击关闭对话框上的取消按钮,然后您会注意到在不同的地址上调用的方法和发出的信号,特别是其中一个正在CanShutdown检查用户是否被允许实际关闭机器,您可以使用类似以下方法进行拦截:

if dbus-monitor | grep -q 'CanShutdown'
  then
    zenity --info --extra-button "Logout" --extra-button "Suspend" \
    --extra-button "Restart" --extra-button "PowerOff" --text="What to do?"
    fi

...运行它并保持其运行然后尝试例如注销...但是这还为时过早。

您会注意到的另一个调用是对话框打开调用,它应该包含类似于EndSessionDialog和的Open 内容,其中Canceled第一个是方法,第二个是信号...您可以观察对话框,关闭它并发送信号,如下所示(请注意,无论你采取什么措施阻止,你的系统都将注销/关闭):

if dbus-monitor | grep -q 'EndSessionDialog'
  then
    sleep 3
    gdbus call --session --dest org.gnome.Shell \
    --object-path /org/gnome/SessionManager/EndSessionDialog \
    --method org.gnome.SessionManager.EndSessionDialog.Close
    gdbus emit --session --object-path /org/gnome/SessionManager/EndSessionDialog \
    --signal org.gnome.SessionManager.EndSessionDialog.Canceled
    fi

... 如果您尝试这样做,您会注意到它会在 3 秒后关闭对话框,甚至会发送信号Canceled,但您的会话会在 60 秒后注销。这是因为 Gnome 在后台设置了一个计数器,您需要找到它并找到禁用它的方法... 是的,我知道您是怎么想的 :-) ... 无论如何,您明白我的意思了。

答案2

Raffa 写了一个很长的答案,其中包含了大量的技术细节,对于任何想要创建一个与 Gnome 保持一致的优雅解决方案的人来说,这应该是无价之宝。我没有 Linux 和 Gnome 系统知识,但我创建了一个类似于 Raffa 答案中的实用解决方法。我将这个解决方法放在下面作为可接受的答案,但带有强烈推荐阅读 Raffa 的回答以了解技术背景,看看您是否可以使用它来找到更好的解决方案。

解决方法

适用于:Ubuntu 20.04/Gnome flashback metacity 和许多其他/旧版本。

目的

能够在关机启动前运行脚本或可执行文件,允许您运行或取消它。例如,您可能希望显示运行夜间作业的提醒。

问题

系统菜单可通过屏幕右上角的开启/齿轮图标访问,其中包含“关机...”菜单选项。它不使用 .desktop 文件,因此可以轻松更改要运行的命令。并且它忽略了GTK 抑制,哪些应用程序设置为对未保存的更改或正在进行的操作发出警告。

解决方法

  • 从系统菜单中删除现有的关机选项。
  • 创建一个新的关机图标并将其添加到顶部菜单栏。

新的关机有一个 .desktop 文件,该文件调用一个 shell 脚本。它可以执行任何您想要的操作,例如显示信息框或运行快速命令。此后,脚本将运行关机命令(与系统菜单命令不同),该命令会观察 GTK 是否禁止并提供关机或取消选项。

显示的解决方法适用于关机,但可以适用于重启、暂停和注销操作。

测试特定关机选项或命令是否忽略 GTK 禁止

运行 Gnome 文本编辑器 gedit 并在新文件中输入一些文本而不保存。这将引发 GTK 禁止。确保您没有任何未保存的实际更改或不应中断的进程,然后运行关机。如果它观察到 GTK 禁止,关机将显示“某些进程仍在运行”对话框,列出已引发禁止的任何应用程序,并附上文本原因,允许您继续或取消。如果没有,它将运行而不发出任何警告。

实施解决方法的步骤

从右上角的系统菜单中删除关机条目
gsettings set com.canonical.indicator.session suppress-shutdown-menuitem true

用新应用程序替换它这将是一个 shell 脚本,它可以执行您想要的任何操作。它应该在操作完成或用户关闭信息框时返回,然后脚本运行关机命令。

如果文本文件存在且包含提醒文本,则这是显示提醒的基本方法。将其保存为例如 ~/.local/bin/shutdown-notify.sh 并运行chmod +x ~/.local/bin/shutdown-notify.sh以使其可执行。

#!/bin/bash

shut_down () {
# call a shutdown command that observes application inhibit.
# If the reminder is something you need to do in the current session,
# you can click the Cancel button it displays.
gnome-session-quit --power-off
}

if [ -s "$HOME/shutdown-note.txt" ]; then
  readarray -t lines < "$HOME/shutdown-note.txt"
  printf -v text '%s\n' "${lines[@]}"
  # Display an info box. Control does not return to the script until the user dismisses the box.  
  zenity --question --width=400 --ok-label="Shutdown anyway" --cancel-label="Cancel" --title="Shutdown reminder" --text="$text"
  status="$?"
  if [ "$status" = 0 ]; then
    # truncate the text file so it won't display next time
    : > "$HOME/shutdown-note.txt"
    # Do shutdown
    shut_down
  fi
else
  shut_down   
fi

为新关机创建桌面文件

将以下代码保存为(例如)~/.local/share/applications/shutdown.desktop

#!/usr/bin/env xdg-open
[Desktop Entry]
Name=Shutdown
GenericName=Shutdown with reminder
Comment=Display reminder before shutdown if set
Exec=/home/MYUSER/.local/bin/shutdown-notify.sh
Terminal=false
Type=Application
Icon=/home/MYUSER/.local/share/icons/shut-down-icon-32.png
Categories=
StartupNotify=false

找到一个合适的图标,或者创建一个 32x32px 的 PNG 格式的图标,然后保存到上面 Icon= 行中给出的路径 - 这里是 ~/.local/share/icons/shut-down-icon-32.png

打开包含桌面文件的文件夹,然后将文件拖到屏幕顶部的菜单栏。光标将变为手和加号,您可以将其放在左侧或右侧。

此后,系统菜单中将不再显示关机选项,但菜单栏上将显示一个更好的选项图标。

其他可能的增强功能

更换注销、重启或暂停

要替换 Log Out(可能没有必要,因为它遵守 GTK 禁止),请运行gsettings set suppress-logout-menuitem true 要替换 Log Out、Restart 和关机,请运行gsettings suppress-logout-restart-shutdown true 在 shell 脚本底部运行的命令是,gnome-session-quit --reboot或者gnome-session-quit --logout 我还没有研究如何替换 Suspend 或使用哪个命令。

将新的关机功能添加为系统菜单选项,就像旧的一样

我还没有尝试过。有些 Gnome 扩展可以更改系统菜单中的选项,但我找不到可以执行此操作或可以配置的扩展。可能存在,或者熟悉它们的人可以编写或改编一个。

使用 GTK inhibit 显示警告

如果您只想显示警告,则桌面文件可以 gnome-session-quit --power-off直接调用,无需用户提供的 shell 脚本。这将使关机本身显示“某些进程仍在运行”对话框,并带有文本原因。在这种情况下,您必须创建一个虚拟GTK 应用程序,在 C 或 Python 中,它会提升抑制,然后在后台不可见地运行。在 C 中,您可以包含以下行,例如

inh = gtk_application_inhibit (app,
NULL, GTK_APPLICATION_INHIBIT_LOGOUT |
GTK_APPLICATION_INHIBIT_SUSPEND,
"run the overnight jobs");

相关内容