我正在编写一个小守护进程,用于记录活动窗口的名称。相关部分如下:
import wnck
import gtk
from plugins import IReporter
class ActiveWindowNameReporter(IReporter):
export_as = 'active_window_name'
def report(self):
name = None
screen = wnck.screen_get_default()
screen.force_update()
while gtk.events_pending():
gtk.main_iteration()
if screen:
active_window = screen.get_active_window()
if active_window:
name = active_window.get_name()
return name
我为此编写了一个简单的 systemd 用户服务文件:
[Unit]
Description=Activity Monitor Service
[Service]
ExecStart=/usr/bin/python /home/me/Projects/monitor/monitor.py
[Install]
WantedBy=graphical.target
但是,运行服务失败。在 journalctl -r 中我可以看到:
Unit actor.service entered failed state.
actor.service: main process exited, code=exited, status=1/FAILURE
ImportError: could not import gtk
import wnck
File "/home/me/Projects/monitor/reporters/active_window_name.py", line 1, in <mod
from reporters import *
File "/home/me/Projects/monitor/monitor.py", line 16, in <module>
Traceback (most recent call last):
detected unhandled Python exception in '/home/tbabej/Projects/actor/actor.py'
Started Activity Monitor Service.
Starting Activity Monitor Service...
好像是因为会话不可用导致 gtk 模块导入失败?但是在脚本中设置 XDG_SESSION_ID 变量没有帮助。
答案1
系统服务不能也不应该与用户会话交互。Unix 上始终只有一个图形会话的假设从未成立(X11 从一开始就是多用户的),甚至在 Windows 上也不正确(NT 4.0 引入终端服务之后,XP 添加了快速用户切换)。
换句话说,系统服务不知道X11 显示它应该使用;没有权利证书即使你进行了硬编码:0
(只有会话的所有者知道正确的 $XAUTHORITY 值 - 成为 root 并不赋予任何魔法力量);并且通常会自动启动前会出现任何 X11 显示,即使你进行了硬编码/home/me/.Xauthority
。
这意味着必须启动像你这样的脚本里面图形会话——通过~/.config/autostart/*.desktop
(XDG 自动启动规范),或者通过~/.xprofile
(常规 shell 脚本)。
# ~/.config/autostart/monitor.desktop [桌面条目] 名称=活动监视器 类型=应用程序 执行=nm-applet