Ubuntu GNOME环境下GTK应用通过Libnotify创建的通知在应用退出后无法触发启动问题
这其实不是你的操作问题,而是Libnotify配合GNOME通知系统的默认行为导致的,我来给你拆解原因和解决办法:
为什么会出现这个情况?
Libnotify创建的通知默认是和你的应用进程绑定在同一个DBus会话里的。当你退出应用后,对应的DBus连接会断开,通知中心里的历史条目就找不到原来处理动作的进程了,自然点击后没反应。而应用运行时,DBus连接还在,所以能触发你绑定的close信号动作。
解决办法:绑定桌面文件让系统负责启动应用
要让通知在应用退出后还能触发启动,你需要把通知和应用的.desktop桌面文件关联起来,让GNOME通知系统通过桌面文件来启动应用,而不是依赖应用内的回调函数。具体步骤如下:
确保你的应用有正确的桌面文件
- 把你的应用桌面文件(比如
myapp.desktop)放到~/.local/share/applications/(仅当前用户生效)或者/usr/share/applications/(全局生效)目录下。 - 桌面文件里至少要包含这些关键字段:
[Desktop Entry] Name=我的GTK应用 Exec=myapp %U # 这里填你的应用启动命令,%U可以传递参数(如果需要) Icon=myapp-icon # 应用图标名称 Type=Application DBusActivatable=true # 可选,如果你用DBus激活的话 Categories=Utility; # 应用分类,按需填写
注意:桌面文件的文件名(去掉
.desktop后缀)要和后面通知里设置的app-name一致。- 把你的应用桌面文件(比如
创建通知时关联桌面文件
不要直接绑定应用内的close信号,而是设置通知的app-name为桌面文件的名称,同时配置动作让系统启动应用。举个C语言Libnotify的例子:// 初始化Libnotify notify_init("myapp"); // 创建通知 NotifyNotification *notification = notify_notification_new( "新消息提醒", "你有一条未读消息", "mail-unread" ); // 设置app-name为桌面文件名(不带.desktop),让GNOME关联到你的应用 notify_notification_set_app_name(notification, "myapp"); // 添加默认动作,点击时系统会通过桌面文件启动你的应用 notify_notification_add_action( notification, "default", // 动作ID,用default表示默认点击动作 "打开应用", // 动作显示文本 NULL, // 这里不需要应用内回调,因为系统会处理 NULL, NULL ); // 显示通知 notify_notification_show(notification, NULL);如果用Python的
pynotify库,代码类似:import pynotify import subprocess pynotify.init("myapp") notification = pynotify.Notification( "新消息提醒", "你有一条未读消息", "mail-unread" ) notification.set_app_name("myapp") # 添加动作,这里可以直接指定启动命令,或者让系统通过桌面文件处理 notification.add_action( "default", "打开应用", lambda *args: subprocess.Popen(["myapp"]), None ) notification.show()可选:DBus激活方式
如果你的应用支持DBus激活,可以配置一个DBus服务文件(比如org.myapp.service),放到~/.local/share/dbus-1/services/或/usr/share/dbus-1/services/目录下,内容如下:[D-BUS Service] Name=org.myapp Exec=/path/to/your/myapp然后在桌面文件里加上
DBusActivatable=true,这样GNOME点击通知时会通过DBus自动启动你的应用,这种方式更适合复杂的应用场景。
总结
默认的Libnotify通知动作依赖应用进程的存在,所以退出后失效。通过绑定桌面文件让系统负责启动应用,就能解决点击历史通知无法启动应用的问题。
备注:内容来源于stack exchange,提问作者Vipul Gupta

