X11 - 如何使用 Python 升起另一个应用程序的窗口

问题描述 投票:0回答:4

我希望能够使用 Python 启动另一个应用程序的窗口。

我确实看到了这个,我想我可以尝试一下:

X11:通过命令行提升现有窗口?

但是,如果可能的话,我更愿意用 Python 来完成。

python x11
4个回答
9
投票

要激活另一个窗口,在 Xlib 协议层上正确的做法是发送 _NET_ACTIVE_WINDOW 消息,如 EWMH 规范中所述 http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html

这可以通过 python-xlib (大概)或通过 pygtk 使用 GDK 在外部 GdkWindow 上使用 gdk_window_focus() 来完成

_NET_ACTIVE_WINDOW 优于 XRaiseWindow(),并且多年来一直存在于所有重要的 WM 中。

您应该避免 XSetInputFocus() ,这会导致问题(特别是如果您的时间戳错误)。问题是 WM 无法拦截 SetInputFocus(),因此会导致奇怪的竞争条件和 UI 不一致。

实际上只有 _NET_ACTIVE_WINDOW 可以正常工作,这就是它被发明的原因,因为以前的 hack 很糟糕。

有一个名为 libwnck 的库,可以让您激活窗口(除其他外),但不幸的是,它增加了相当多的开销,因为它总是跟踪任何应用程序中所有打开的窗口,即使您不需要这样做。但是,如果您想从其他应用程序跟踪窗口无论如何,那么 libwnck 有一个函数可以激活那些执行正确操作的窗口,这将是一个不错的选择。

严格正确的方法是检查 EWMH _NET_ACTIVE_WINDOW 支持(EWMH 文档说明了如何执行此操作),如果 WM 没有 _NET_ACTIVE_WINDOW,则回退到 XRaiseWindow。然而,由于过去多年来积极开发的任何 WM 都具有 EWMH,因此很多人对遗留 WM 的回退感到懒惰。


7
投票

您可以查看python ewmh 包文档包含示例,但您可以通过以下方式实现您想要的:

from ewmh import EWMH
import random
ewmh = EWMH()

# get every displayed windows
wins = ewmh.getClientList()

# let's active one window randomly
ewmh.setActiveWindow(random.choice(wins))

# flush requests - that's actually do the real job
ewmh.display.flush()

6
投票

您需要使用 python-xlib 并在窗口对象上调用

.circulate(Xlib.X.RaiseLowest)
(可以通过很多很多不同的方式来识别它 - 无法从零信息量中猜测哪一个适合您)在你的问题中;-)。 对于使用
python-xlib
的一个很好的例子,请查看 tinywm 窗口管理器——在 C 版本之后,作者给出了一个 Python 版本,该版本需要大约 30 个非空白、非注释行(对于一个可用的,如果很小的话) , 窗口管理器...!-).


0
投票

使用python-xlib

# https://specifications.freedesktop.org/wm-spec/1.3/ar01s03.html#id-1.4.10
from Xlib.xobject.drawable import Window
from Xlib.display import Display
from Xlib.protocol.event import ClientMessage
from Xlib.X import AnyPropertyType
from Xlib import X

display:Display=Display()
root:Window|None=display.screen().root
if root is None:
    raise NotImplementedError()
hex_id="0x07c0000c" # your window hex id from wmctrl -l
xwin:Window = display.create_resource_object('window', int(hex_id, 16))

source:int=0 # It is set to 1 with lib pyewmh but not working on KDE 5.103.0. When set to 0 it works on my system
timestamp:int=X.CurrentTime
currently_active_window:int=0
ev = ClientMessage(window=xwin, client_type=display.get_atom("_NET_ACTIVE_WINDOW"), data=(32, [source, timestamp, currently_active_window, 0, 0]))
root.send_event(ev, event_mask=(X.SubstructureRedirectMask | X.SubstructureNotifyMask))
display.flush()
© www.soinside.com 2019 - 2024. All rights reserved.