监视在带有Python和xorg服务器的计算机上花费的时间

监视在带有Python和xorg服务器的计算机上花费的时间,python,linux,monitoring,xorg,Python,Linux,Monitoring,Xorg,我正在尝试制作一个脚本,它将帮助我跟踪我花在电脑上的时间。这个脚本应该跟踪我何时开始、停止以及我在每个“任务”上花费的时间。经过一番搜索,我找到了一个名为xdool的终端实用程序,它将返回当前的聚焦窗口及其标题,运行方式如下:xdool getwindowfocus getwindowna me。例如当聚焦此窗口时,它返回: linux - Monitering time spent on computer w/ Python and xorg-server - Stack Overflow —

我正在尝试制作一个脚本,它将帮助我跟踪我花在电脑上的时间。这个脚本应该跟踪我何时开始、停止以及我在每个“任务”上花费的时间。经过一番搜索,我找到了一个名为
xdool
的终端实用程序,它将返回当前的聚焦窗口及其标题,运行方式如下:
xdool getwindowfocus getwindowna me
。例如当聚焦此窗口时,它返回:

linux - Monitering time spent on computer w/ Python and xorg-server - Stack Overflow — Firefox Developer Edition
这正是我想要的。我的第一个想法是检测聚焦窗口何时改变,然后获取发生这种情况的时间,但是我找不到任何结果,所以我求助于while循环,每5秒运行一次该命令,但这非常困难,而且已经证明很麻烦,我更喜欢聚焦改变方法,但这是我目前的代码:

#/usr/bin/env蟒蛇3
从子流程导入运行
从时间导入时间,睡眠
日志=[]
prevwindow=“”
尽管如此:
currentwindow=run(['xdotool','getwindowfocus','getwindowname'],
捕获输出=True,文本=True).stdout
如果当前窗口!=前置窗口:
对于日志中的条目:
如果当前窗口在条目中:
通过#计算花费的时间
打印(f“{time()}:\t{currentwindow}”)
追加((time(),currentwindow))
prevwindow=currentwindow
睡眠(5)
我使用的是Arch linux和dwm,这很重要,请参见。只要将日志机制放在
handle\u change
函数中,它就应该可以工作了,在Arch Linux-dwm系统上进行了测试

出于存档目的,我在这里包括代码。所有的功劳都归于GitHub上的Stephan Sokolow()

从contextlib导入contextmanager
输入import Any、Dict、Optional、Tuple、Union#noqa
从Xlib导入X
从Xlib.display导入显示
从Xlib.error导入XError
从Xlib.xobject.drawable导入窗口
从Xlib.protocol.rq导入事件
#连接到X服务器并获取根窗口
disp=Display()
root=disp.screen().root
#准备我们使用的属性名称,以便将它们输入到X11 API中
网络活动窗口=显示内部原子(“网络活动窗口”)
NET\u WM\u NAME=disp.intern\u atom(“NET\u WM\u NAME”)#UTF-8
WM_NAME=disp.intern_atom('WM_NAME')#传统编码
上次看到={xid':无,'title':无}类型:Dict[str,Any]
@上下文管理器
def窗口对象(win\U id:可选[int])->窗口:
“”“简化处理BadWindow(使其有效或无)”
窗口对象=无
如果赢了(id):
尝试:
window\u obj=disp.create\u resource\u object('window',win\u id)
除Xeror外:
通过
屈服窗口
def get_active_window()->Tuple[可选[int],bool]:
“”“返回活动窗口的(窗口对象,焦点已更改)元组。”“”
response=root.get\u full\u属性(NET\u ACTIVE\u窗口,
X.AnyPropertyType)
如果没有答复:
返回None,False
win_id=响应。值[0]
焦点更改=(win\u id!=最后一次看到['xid'])
如果焦点改变:
窗口对象(最后一次看到['xid'])作为旧窗口:
如果你赢了:
旧赢。更改属性(事件掩码=X.NoEventMask)
上次看到['xid']=win\u id
将窗口对象(win\U id)作为新win:
如果新团队获胜:
新建\u win.change\u属性(事件\u掩码=X.PropertyChangeMask)
返回win\u id,焦点已更改
def\u get\u window\u name\u internal(win\u obj:window)->str:
“”“简化处理\u NET\u WM\u NAME(UTF-8)与WM\u NAME(遗留)”的比较”
对于atom in(网络名称,工作名称):
尝试:
window\u name=win\u obj.get\u full\u属性(atom,0)
除了UnicodeDecodeError:#显然是Debian发行版包错误
title=“”
其他:
如果窗口名称:
win_name=window_name.value#类型:Union[str,bytes]
如果isinstance(win_名称,字节):
#显然,复合文本是如此神秘,这是如何
#像xprop这样的工具现在处理接收它的问题
win_name=win_name.decode('latin1','replace')
返回win_名称
其他:
title=“”
返回“{}(XID:{})”格式(title,win_obj.id)
def get_window_name(win_id:Optional[int])->Tuple[Optional[str],bool]:
“”“查找给定X11窗口ID的窗口名称”“”
如果没有赢取id:
最后一次看到['title']=无
返回上次看到的[title],True
title\u changed=False
窗口对象(win_id)作为wobj:
如果wobj:
尝试:
win\u title=\u get\u window\u name\u inner(wobj)
除Xeror外:
通过
其他:
title\u changed=(win\u title!=最后一次看到['title'])
最后一次见面['title']=赢得冠军
返回上次看到的['title',title\u已更改
def句柄事件(事件:事件):
“”“忽略焦点/标题更改以外任何内容的X事件处理程序”“”
如果event.type!=X.财产通知:
返回
更改=错误
如果event.atom==NET\u ACTIVE\u窗口:
如果获取活动窗口()[1]:
获取窗口名称(最后一次看到['xid'))#依赖副作用
更改=真
elif event.atom in(NET\u WM\u NAME,WM\u NAME):
更改=更改或获取窗口名称(最后一次看到['xid'])[1]
如有更改:
处理更改(上次看到)
def句柄更改(新状态:dict):
“”“用您真正想做的事情替换此内容”“”
打印(新州)
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
#侦听\u网络\u活动\u窗口更改
root.change\u属性(事件\u掩码=X.PropertyChangeMask)
#当我们开始这项工作时,上次看到的Prime窗口是活动的
获取窗口名称(获取活动窗口()[0])
处理更改(上次看到)
而True:#next_event()会一直休眠,直到我们得到一个事件
句柄\u xevent(disp.next\u事件())