我如何在 Gnome Wayland 上获得活跃的 window?

How do I get the active window on Gnome Wayland?

背景: 我正在开发一款名为 ActivityWatch 的软件,它可以记录您在计算机上的操作。基本上是尝试解决一些问题:RescueTime、selfspy、arbtt 等

我们做的一项核心工作是记录有关活动 window 的信息(class 和标题)。过去,这是在 Linux 上使用 xprop 完成的,现在 python-xlib 没有问题。

但现在我们遇到了一个问题: Wayland 正在崛起,据我所知,Wayland 没有活跃的概念 window。所以我担心我们将不得不为 Wayland 可用的每个桌面环境实现支持(假设他们将提供获取有关活动 window 的信息的能力)。

希望他们最终会融合并有一些共同的界面来完成这项工作,但我并没有屏住呼吸...

我曾被一位实际的 Wayland 用户anticipating this issue. But today we got our first user request for Wayland support。随着更大的发行版采用 Wayland 作为默认显示服务器协议(Fedora 25 已经在使用它,Ubuntu 将在即将推出的 17.10 中切换)随着时间的推移,情况会变得更加严峻。

ActivityWatch 的相关问题:

还有其他应用程序,如 ActivityWatch 需要相同的功能(RescueTime、arbtt、selfspy 等),它们现在似乎不支持 Wayland,我找不到有关它们计划的任何详细信息这样做。

我现在有兴趣实现对 Gnome 的支持,从 开始,随着路径变得更加清晰,跟进其他人。

这里有人问了一个关于韦斯顿的类似问题:get the list of active windows in wayland weston

编辑: 我在 Freenode 上的#wayland 中询问,得到以下回复:

15:20:44  ErikBjare    Hello everybody. I'm working on a piece of self-tracking software called ActivityWatch (https://github.com/ActivityWatch/activitywatch). I know this isn't exactly the right place to ask, but I was wondering if anyone knew anything about getting the active window in any Wayland-using DE.
15:20:57  ErikBjare    Created a question on SO: 
15:21:25  ErikBjare    Here's the issue in my repo for it: https://github.com/ActivityWatch/activitywatch/issues/92
15:22:54  ErikBjare    There are a bunch of other applications that depend on it (RescueTime, selfspy, arbtt, ulogme, etc.) so they'd need it as well
15:24:23  blocage      ErikBjare, in the core protocol you cannot know which windnow has the keyboard or cursor focus
15:24:39  blocage      ErikBjare, in the wayland core protocol *
15:25:10  blocage      ErikBjare, you can just know if your window has the focus or not, it a design choise
15:25:23  blocage      avoid client spying each other
15:25:25  ErikBjare    blocage: I'm aware, that's my reason for concern. I'm not saying it should be included or anything, but as it looks now every DE would need to implement it themselves if these kind of applications are to be supported
15:25:46  ErikBjare    So wondering if anyone knew the teams working with Wayland on Gnome for example
15:26:11  ErikBjare    But thanks for confirming
15:26:29  blocage      ErikBjare, DE should create a custom extension, or use D-bus or other IPC
15:27:31  blocage      ErikBjare, I guess some compositor are around here, but I do not know myself if there is such extension already
15:27:44  blocage      compositor developers *
15:28:36  ErikBjare    I don't think there is (I've done quite a bit of searching), so I guess I need to catch the attention of some DE developers
15:29:16  ErikBjare    Thanks a lot though
15:29:42  ErikBjare    blocage: Would you mind if I shared logs of our conversation in the issue?                                     
15:30:05  blocage      just use it :) it's public                                                                                               
15:30:19  ErikBjare    ty :)

编辑 2: 提交了 enhancement issue in the Gnome bugtracker

tl;dr: 使用 Wayland 时如何在 Gnome 上激活 window?

我有一个名为 preguiça.py 的脚本,它完全可以完成您正在做的事情,尽管它可能更简单,但我还没有发布它。

对于我的脚本,我使用 PyGObject 的 Window Navigator Construction Kit (Wnck) 获得了 window 标题。

这是它的简化版本,包含基本部分:

from gi.repository import Wnck
from gi.repository import GObject

def changed (screen, window, data):
    print ("Changed!")
#    window = screen.get_active_window()
    if window:
        print ("Title: %s" % window.get_name())

screen = Wnck.Screen.get_default ()
screen.connect ("active-window-changed", changed, None)

mainLoop = GObject.MainLoop ()

try:
    mainLoop.run ()
except KeyboardInterrupt:
    print ("Hey")

mainLoop.unref ()

你所要求的实际代码实际上在上面的例子中被注释掉了(我不需要捕获 window,因为回调已经收到它),但你可能需要它取决于您的实施。

我是为 X 写的,当我切换到 Wayland 时它没有抱怨,所以它应该适合你。

请注意,它没有从 Wayland 获取信息 ,如您所问,但它实际上可能更好,因为它将是 X/Wayland-agnostic。它的标题来自我打开的 xterm,因此它也应该是 toolkit-agnostic。

但是不要问我实施的细节。该代码至少已有四年历史:)

在我看来,您最好的选择不是 Wayland 或任何可用的库(没有)。其实在gnome-wayland中谁知道active windows是Mutter,所以你需要想办法去Mutter the active windows。 Gnome 可以开发一个 API 来在内部要求发出活动的 window 并恢复功能。但实际上,你没有地方要求它。 Mutter 不会开发一个 API 来访问他的内部表示,因为这将非常特定于 Mutter,而不是所有 Wayland windows 经理。所以这需要添加到一个外部库中,这个库可能会与当前的 window 经理交谈,它正在使用它以一般方式解决您的请求。

另一种可能性是添加一个 Wayland 插件,其中所有 windows 管理器都可以共享当前活动的 windows 并以某种方式直接与 Wayland 对话以恢复功能的库。

那么,你的应用有大问题了。大多数你能做的就是在 mutter 上请求这个(知道活动的地方windows),但在我看来它不能在 Mutter 中解决。

希望这对您有所帮助,您可以找到方法。祝你好运。

之前的两个答案已经过时了,这是在(Gnome)Wayland 中查询 windows 的应用名称和标题的当前状态。

  1. A Gnome-specific JavaScript API 可以通过 DBus
  2. 访问
  3. wlr-foreign-toplevel-management Wayland 协议(不幸的是 Gnome 没有实现)

Gnome-specific API 可能会在 Gnome 版本之间中断,但它可以工作。它严重依赖于 Gnome 内部 API 来工作,因此它不可能成为标准 API。有 a PR on aw-watcher-window to add this,但如果可能,它需要一些 clean-up 和 afk-support。

wlr-foreign-toplevel-management protocol is (at the time of writing this) implemented by the Sway, Mir, Phosh and Wayfire compositors. Together with the idle.xml protocol which is pretty widely implemented by wayland compositors there's a complete implementation with afk-detection for ActivityWatch in aw-watcher-window-wayland。我一直在与 sway/rootston 开发人员讨论 Wayland 应用程序名称和 X11 wm_class 是否可以互换,并且 Sway 和 Phosh 现在可以互换使用这些名称,因此 Wayland 和 XWayland 之间不应再有任何可区分的差异 windows 在 API 了。

我没有研究过 KWin 是否有一些 API 类似于 Gnome Shell 来获取应用程序名称和标题,但它至少没有实现 wlr-foreign-toplevel-management.