使用python-xlib禁用操作、移动、调整大小、最小化等

2 投票
2 回答
2061 浏览
提问于 2025-04-17 13:18

我正在做一个程序,需要把窗口的位置锁定在屏幕上。大家可能会觉得用 _NET_WM_ALLOWED_ACTIONS 来实现这个功能很简单,但显然我试了之后并没有成功,或者我根本不知道它是怎么工作的,哈哈……我尝试发送一个事件,像这样:

def getatom (atom):
    return self.display.intern_atom(atom)

data = [getatom("_NET_WM_ACTION_ABOVE"),getatom("_NET_WM_ACTION_CLOSE"),
        getatom("_NET_WM_ACTION_BELOW"),getatom("_NET_WM_ACTION_CHANGE_DESKTOP"),
        getatom("_NET_WM_ACTION_SHADE")]
state = getatom("_NET_WM_ALLOWED_ACTIONS")
event = Xlib.protocol.event.ClientMessage(window = window, client_type = state, data = (32, data))
root.send_event(event, X.SubstructureRedirectMask)
self.display.sync()

但是这样做没有任何效果。如果我用 xprop 查看,允许的操作有 _NET_WM_ACTION_ABOVE、_NET_WM_ACTION_CLOSE、_NET_WM_ACTION_BELOW、_NET_WM_ACTION_CHANGE_DESKTOP 和 _NET_WM_ACTION_SHADE,但我还是可以移动这个窗口。我真的不知道该怎么做或者它是怎么工作的。如果有人能给我解释一下,并给个例子,那就太感谢了。

2 个回答

2

_NET_WM_ALLOWED_ACTIONS 这个东西似乎和你想要的完全不搭边:

窗口管理器必须保持这个属性的更新,以反映当前窗口的“活动”或“敏感”操作 [...] 窗口管理器在最初管理一个窗口时,应该忽略 _NET_WM_ALLOWED_ACTIONS 的值。这个值可能是之前的窗口管理器留下来的,可能有不同的规则。

在freedesktop的扩展中,_NET_WM_WINDOW_TYPE 是最接近你想要的:它可以指定某种窗口类型,以推荐某种行为。不过,想要得到你想要的确切效果(比如一个不可移动的带装饰的窗口)几乎是不可能的,而且也不能保证窗口管理器会听从这个提示。

你可能想用 OverrideRedirect 属性:当在窗口被显示之前设置这个属性时,窗口管理器就不会干预窗口的显示过程。这意味着没有装饰,没有重新归属,也没有用户对这个窗口的操作:你承诺自己来管理它。这样的话,它变得不可移动(除非提供拖动的功能)。而且(可能不太好)它也会没有装饰。

3

这是一个老问题,但我遇到过类似的情况,所以我用的解决方案是:一种兼容Motif的、非官方的,但大多数窗口管理器都支持的设置 _MOTIF_WM_HINTS。这些定义来自旧的Motif代码(应该在 Xm/MwmUtil.h 文件里),不过大家都在模仿这些定义,所以:

struct MwmHints {
    unsigned long flags;
    unsigned long functions;
    unsigned long decorations;
    long input_mode;
    unsigned long status;
};
enum {
    MWM_HINTS_FUNCTIONS = (1L << 0),
    MWM_HINTS_DECORATIONS =  (1L << 1),

    MWM_FUNC_ALL = (1L << 0),
    MWM_FUNC_RESIZE = (1L << 1),
    MWM_FUNC_MOVE = (1L << 2),
    MWM_FUNC_MINIMIZE = (1L << 3),
    MWM_FUNC_MAXIMIZE = (1L << 4),
    MWM_FUNC_CLOSE = (1L << 5)
};

代码大概是这样的:

struct MwmHints hints;
Atom wm = XInternAtom(display, "_MOTIF_WM_HINTS", False);
hints.functions = MWM_FUNC_RESIZE | MWM_FUNC_MINIMIZE | MWM_FUNC_MAXIMIZE | MWM_FUNC_CLOSE;
hints.flags = MWM_HINTS_FUNCTIONS;
XChangeProperty(display, window, wm, XA_ATOM, 32, PropModeReplace, (unsigned char*)&hints, 5);

因为我们没有包含 MWM_FUNC_MOVE,所以这些窗口应该是不能移动的。

根据我有限的测试,这些大部分都能正常工作,除了 MWM_FUNC_RESIZE,这个大多数情况下不太好使。

把这些移植到Python里应该不难,但我在Python里不需要这个,我更喜欢分享能正常工作的代码。

撰写回答