XServer为什么发送两次FocusOut通知

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

我为软件KVM编写了虚拟窗口。想法是,当用户切换到另一台计算机时,先前的计算机会在屏幕范围之外打开虚拟窗口,因此会模拟失去的焦点。没有焦点的Windows在我的系统上是透明的(wm很棒)。如果仅使用XSetInputFocus(dpy, None, RevertToNone, CurrentTime),则当前窗口会失去焦点,但不会变得透明。这就是为什么我使用虚拟窗口。

到这一点。我的程序在打开虚拟窗口之前先保存焦点窗口。当虚拟窗口失去焦点时,程序恢复将保存。因此它需要捕获FocusOut事件,然后调用XSetInputFocus函数以恢复焦点。问题是xserver发送FocusOut通知两次。如果我仅在程序无法正常工作时处理它。

下面是代码。

#include <X11/Xlib.h>
#include <X11/Xatom.h>

int x = 100, y = 100, height = 200, width = 200;

typedef struct {
    Window win;
    int notify;
} wait_arg;

Bool xevent_handler(Display *dpy, XEvent *ev, XPointer arg) {
    wait_arg *a = (wait_arg *) arg;
    return (ev->type == a->notify) && (ev->xvisibility.window == a->win);
}

int main(int argc, char *argv[]) {
    Display *dpy;
    Window focused;
    int revert_to;
    Window win;
    wait_arg arg;
    XEvent ev;

    dpy = XOpenDisplay(NULL);

    // Save window which has focus now
    XGetInputFocus(dpy, &focused, &revert_to);

    int s = DefaultScreen(dpy);
    win = XCreateSimpleWindow(dpy, RootWindow(dpy, s), 0, 0, height, width, 0,
            CopyFromParent, CopyFromParent);

    // Set DIALOG type for window
    Atom type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
    long value = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
    XChangeProperty(dpy, win, type, XA_ATOM, 32, PropModeReplace,
            (unsigned char *) &value, 1);

    // Set events to handle
    XSelectInput(dpy, win, VisibilityChangeMask | FocusChangeMask);

    // Draw window
    XMapWindow(dpy, win);

    // Wait until window stands visible, otherwise will get
    // "Error of failed request: BadMatch"
    arg.win = win;
    arg.notify = VisibilityNotify;
    XIfEvent(dpy, &ev, &xevent_handler, (XPointer) &arg);

    XSetInputFocus(dpy, win, RevertToNone, CurrentTime);
    XSync(dpy, False);

    XMoveWindow(dpy, win, x, y);

    // Wait until focus lost
    arg.win = win;
    arg.notify = FocusOut;
    XIfEvent(dpy, &ev, &xevent_handler, (XPointer) &arg);
    // Why I should handle this event twice?
    XIfEvent(dpy, &ev, &xevent_handler, (XPointer) &arg);

    // Restore focus
    XSetInputFocus(dpy, focused, revert_to, CurrentTime);
    XSync(dpy, False);
}

如何检查不正确的行为:

我评论第二次FocusOut处理。我使用两个监视器:左和右。我在右监视器的终端中启动程序。程序在左侧监视器上打开虚拟窗口。当虚拟窗口失去焦点时,左监视器上的另一个窗口将获得它。右监视器上没有终端窗口!

为什么xserver两次发送FocusOut?还是我的窗口管理器的错误/功能?

c xlib
1个回答
1
投票

没有您的实现,实际上不可能确切知道所看到行为的驱动程序是什么,但是手册页的确提供了对可能发生的情况的一些了解。

此特定行为可能是last-focus-change-时间的结果。从this man page

... XSetInputFocus()函数更改输入焦点和最后更改焦点的时间。如果指定时间早于当前时间,则无效上次焦点更改时间或晚于当前X服务器时间。

© www.soinside.com 2019 - 2024. All rights reserved.