如何优雅地退出X11事件循环?

The*_*Saw 39 c linux x11 xlib

我找到的几乎每个教程都告诉我为我的事件循环执行此操作:

XEvent event;

while (true)
{
    XNextEvent(display, &event);

    switch (event.type)
    {
        case Expose:
            printf("Expose\n");
            break;

        default:
            break;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,单击X关闭程序将导致此消息.

XIO:  fatal IO error 11 (Resource temporarily unavailable) on X server ":0"
after 10 requests (10 known processed) with 0 events remaining.
Run Code Online (Sandbox Code Playgroud)

对我来说,这些例子建议使用无限循环确实很奇怪.这听起来并不自然,我的其他X11程序也不这样做.所以我四处搜寻.我发现了如何捕获窗口关闭事件.

Atom wmDeleteMessage = XInternAtom(mDisplay, "WM_DELETE_WINDOW", False);
XSetWMProtocols(display, window, &wmDeleteMessage, 1);

XEvent event;
bool running = true;

while (running)
{
    XNextEvent(display, &event);

    switch (event.type)
    {
        case Expose:
            printf("Expose\n");
            break;

        case ClientMessage:
            if (event.xclient.data.l[0] == wmDeleteMessage)
                running = false;
            break;

        default:
            break;
    }
}
Run Code Online (Sandbox Code Playgroud)

这样可行.它退出没有错误.......但我拒绝相信这是做事的正常方式.我的意思是,这是正确退出X11应用程序的唯一方法吗?为了捕捉近距离事件,似乎需要做很多工作.如何制作"正确"的事件循环?为什么近距离事件如此深深地被埋葬?我错过了什么?

Sas*_*asQ 53

问题在于X Server和Window Manager之间的通信.

当你打电话XCreateWindow或者XCreateSimpleWindow,X服务器创建你的窗口(直到你通过调用在屏幕上显式地映射它才显示它XMapWindow),然后窗口管理器负责在窗口周围附加所有的装饰和按钮以及系统菜单.

您可以XDestroyWindow自己调用以删除窗口,这通常意味着它只是从屏幕上消失,但您的程序仍在运行,并且与X服务器的连接仍然打开,因此您可以向其发送更多请求.

当用户单击X窗口管理器附加到窗口的小按钮时,问题就开始了,因为它不是由X服务器创建的,因此决定该做什么不是他的事.现在,它完全掌握在Window Manager中.

如果窗口管理器只是调用XDestroyWindow了你的窗口,如果你的应用程序想要在窗口被破坏之前捕获关闭事件以执行某些操作,则会导致问题.因此,已在X Server和Window Manager之间建立了约定来处理此过程.

大多数窗口管理器的默认行为是销毁窗口并关闭与X服务器的连接,因为这是窗口管理器的大多数用户所期望的:当它们关闭窗口时,程序将结束(以及与X服务器将关闭窗口关闭).然后,当您尝试调用时XCloseDisplay(display),它将导致您提到的IO错误,因为与服务器的连接已关闭且display结构无效.

以下是Xlib文档的摘录,解释了这一点:

如果用户要求删除其中一个客户端的顶级窗口,则选择不包含WM_DELETE_WINDOWWM_PROTOCOLS属性中的客户端可能会与服务器断开连接.

是的,如果他们没有在他们的文档中如此深入地隐藏它会很棒,但是:-P但是当你已经找到它时,幸运的是它也暗示了解决方案.

如果您想要一个不同的行为(即,从Window Manager捕获结束事件),您需要使用该WM_DESTROY_WINDOW协议.

文档的另一部分摘录:

客户端,通常是具有多个顶级窗口的客户端,其服务器连接必须在删除其某些顶级窗口后仍然存在,应该在每个此类窗口WM_DELETE_WINDOWWM_PROTOCOLS属性中包含atom .他们将收到ClientMessage如上所述的活动,其data[0]领域是WM_DELETE_WINDOW.

我有同样的错误,我想知道究竟是什么导致它和原因.我花了一些时间来弄明白并在文档中找到正确的解释,所以我在这里解释一下,以节省其他人不知情的时间.

  • 很好的答案.感谢您的时间! (2认同)

n. *_* m. 21

X11中没有"退出按钮"或"应用程序"或"关闭事件"之类的内容.这是设计的.

窗口装饰,退出按钮和我们依赖的许多其他东西都没有内置到X11中.它们是在核心X11之上实现的.负责的特定公约集的名称wmDeleteMessage是ICCCM,请查阅.

Xlib仅处理核心X11协议.那里没有内置的近距离活动.

有一些工具包可以处理ICCCM以及所有其他没有内置到X11中的东西(GTK,wxWindows,Qt,...)你可能想要使用其中一种.

  • 这就是关闭窗户这么模糊的原因.X不是为了关心这些事情而设计的 - 它是窗口管理员的工作.这就是大多数人使用GTK或Qt等工具包的原因. (2认同)