为什么XServer发送FocusOut两次通知

时间:2020-01-09 13:54:15

标签: c xlib

我为软件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?还是我的窗口管理器的错误/功能?

1 个答案:

答案 0 :(得分:1)

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

这种特殊行为可能是 last-focus-change 时间的结果。来自this man page

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