有一些与此类似的老问题;但是,我还没有找到一种方法来列出并选择性地关闭应用程序,最小化到系统托盘。
在 Windows 中会话注销期间,Windows 会优雅地要求所有正在运行的 GUI 应用程序优雅地终止,并且只有当所有应用程序正常终止并确认此请求时,Windows 才会继续注销过程。
相反,在 Ubuntu 中,GNOME 不会要求所有应用程序正常终止,而只是kill
在注销时退出。可能有些情况下,您只是没有注意到打开了带有未保存数据的编辑器,在这种情况下,您可能会丢失所有更新。或者可能有一些其他 GUI 应用程序需要正常关闭或必须继续运行,直到某些操作完成。
为此,我创建了一个脚本来找出所有打开的 GUI 窗口,然后“优雅地”逐个关闭它们。这个脚本的关键是wmctrl -lp
列出应用程序并向wmctrl -ic <win_id>
窗口 ID 已知的应用程序发送关闭消息的命令。但是,wmctrl -lp
无法列出正在运行的任何应用程序最小化到系统托盘因此目前没有窗口(和窗口 ID)。我使用的一些可以最小化到系统托盘的示例应用程序是:Viber(.deb 软件包),电报(也是 .deb 包)或者一些葡萄酒(Windows)应用程序。请注意,我使用的是 snap 版本的火狐并wmctrl
成功检测到它的窗口 id,尽管 Firefox 的父级似乎是systemd
。
我目前正在使用 Xorg,并且更愿意继续使用 Xorg。但是,我也测试过 Wayland,结果更糟:Waylandwmctrl -lp
无法列出 Xorg 中可轻松检测到的大多数“正常”应用程序。
注意:我测试过,发现最小化到托盘的应用程序会丢失其窗口 ID。恢复时(通过在系统托盘上的图标上用鼠标交互),它将获得一个新的窗口 ID。
我如何才能获得所有最小化到托盘应用程序的列表并恢复它们的窗口,以便我可以对它们进行操作wmctrl
?
答案1
以下脚本guir
在手册列表的帮助下运行manlist
,其中包含未显示的应用程序wmctrl -lp
。
#!/bin/bash
manlist=\
'Viber
Telegram
onboard
skype
xeyes'
mizer=$(wmctrl -lp|grep -v '@!0,0;BDHF'|tr -s ' ' '\t'|cut -f3|grep -v '^0$')
guip="$mizer
$manlist"
runners=$(ps -e |grep "^$guip$"|sed -e 's/^ *//' -e 's/ .*$//')
guir="$(ps $runners)"
echo "$guir"
if [ $(echo "$runners"|wc -l) -gt 1 ]
then
echo "-------------------------------------------------------------------"
echo "Please close some programs gracefully before logout/reboot/shutdown"
exit 1
fi
测试运行:
$ ./guir
PID TTY STAT TIME COMMAND
3006 ? Ssl 0:59 /usr/libexec/gnome-terminal-server
3042 pts/0 S+ 0:58 xeyes -geometry +1775-0
3043 pts/0 S+ 0:58 xeyes -geometry +800+0
3954 pts/0 Sl 10:02 /snap/firefox/2605/usr/lib/firefox/firefox
5790 ? Sl 3:39 /usr/lib/thunderbird/thunderbird
6707 pts/0 Sl 1:18 geany
9929 ? Sl 0:07 /usr/bin/python3 /usr/bin/onboard
-------------------------------------------------------------------
Please close some programs gracefully before logout/reboot/shutdown
如果您想使用此方法,您可能会修改这个脚本,例如向中添加一些程序
manlist
。假设脚本在终端窗口中运行,则允许一个程序运行而无需关闭其他程序。您可能也想更改这一点。
您可以关闭
xeyes
而不保存任何内容,它manlist
仅作为演示,因为wmctrl
没有找到它的进程号(列表0
),并且可能还有其他程序受到类似影响。最后,我认为您打算在注销/重启/关机过程中自动使用脚本/程序,因此我修改了程序应正常关闭时的退出状态。
答案2
由于所有 GUI 进程都是窗口管理器的子进程(孙进程,...),因此您可以使用pgrep
来查找窗口管理器的 PID,ps
或pstree
列出该 PID 的子进程。阅读man pgrep ps pstree
。