【问题标题】:Xlib: Closing window always causes fatal IO error?Xlib:关闭窗口总是导致致命的 IO 错误?
【发布时间】:2013-10-10 20:51:20
【问题描述】:

我不确定为什么会发生这种情况,但是当我尝试关闭使用 X 按钮时,我在 C++ 中使用 Xlib 创建的任何窗口都会向终端输出错误。我可以无错误地以编程方式关闭它,只需 X 按钮即可。

错误如下:

XIO:  fatal IO error 11 (Resource temporarily unavailable) on X server ":0"
after 483 requests (483 known processed) with 0 events remaining.

每次请求的数量都不一样,但总是剩下 0 个事件。为什么会这样?原因似乎不是我的代码,因为无论如何它都会这样做并且不会向队列发送关闭事件。我试过拦截 Atom WM_WINDOW_DELETE,当我关闭窗口时它没有运行在预期的代码上。

编辑:添加事件循环代码。

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

    pthread_mutex_unlock(&mutex);

    if(event.type == Expose) {
        XWindowAttributes getWindowAttributes;

        pthread_mutex_lock(&mutex);

        XGetWindowAttributes(display, window, &getWindowAttributes);

        if(state.currentState == STATE_NORMAL) {
            state.normX = getWindowAttributes.x;
            state.normY = getWindowAttributes.y;
            state.normWidth = getWindowAttributes.width;
            state.normHeight = getWindowAttributes.height;
        }

        pthread_mutex_unlock(&mutex);

        glViewport(0, 0, getWindowAttributes.width, getWindowAttributes.height);
    } else if(event.type == KeyPress) {
        return false;
    } else if(event.type == ClientMessage) {
        std::cout<<"X Button pressed"<<std::endl; //Never run when X-ing window
        if(event.xclient.message_type == XInternAtom(display, "WM_DELETE_WINDOW", True)) {
            return false;
        }
    } else if(event.type == ButtonPress) {
        if(state.currentState != STATE_FULLSCREEN) {
            fullscreen();
        } else {
            normalize();
        }
    } else if(!handleEvent(event)){
        return false;
    }

    pthread_mutex_lock(&mutex);
}

【问题讨论】:

  • 任何窗口,甚至是弹出窗口或瞬态窗口?
  • 除了WM_WINDOW_DELETE,你还需要监听和处理ClientMessage事件。显示您的代码。 WM_WINDOW_DELETE.
  • 添加了事件循环代码 - 我已经在寻找 ClientMessage。关闭错误是关闭窗口的行为,因此不会收到任何消息。
  • 到目前为止我只使用过普通的 XWindows,所以可能没有弹出窗口或瞬态。

标签: c++ c linux xlib


【解决方案1】:

除了WM_WINDOW_DELETE,您还需要监听和处理ClientMessage 事件。

修改Rosetta Code中的例子来说明:

#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    Display *d;
    Window w;
    XEvent e;
    const char *msg = "Hello, World!";
    int s;

    d = XOpenDisplay(NULL);
    if (d == NULL) {
        fprintf(stderr, "Cannot open display\n");
        exit(1);
    }

    s = DefaultScreen(d);
    w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1, BlackPixel(d, s), WhitePixel(d, s));
    XSelectInput(d, w, ExposureMask | KeyPressMask);
    XMapWindow(d, w);

    // I support the WM_DELETE_WINDOW protocol
    Atom WM_DELETE_WINDOW = XInternAtom(d, "WM_DELETE_WINDOW", False); 
    XSetWMProtocols(d, w, &WM_DELETE_WINDOW, 1);

    while (1) {
        XNextEvent(d, &e);
        if (e.type == Expose) {
            XFillRectangle(d, w, DefaultGC(d, s), 20, 20, 10, 10);
            XDrawString(d, w, DefaultGC(d, s), 10, 50, msg, strlen(msg));
        }
        else if (e.type == KeyPress)
            break;
        else if (e.type == ClientMessage)
            // TODO Should check here for other client message types - 
            // however as the only protocol registered above is WM_DELETE_WINDOW
            // it is safe for this small example.
            break;
    }

    XCloseDisplay(d);
    return 0;
}

【讨论】:

  • 我在我的代码中添加了 SetWMProtocols,看来这就是缺少的。为什么你必须默认这样做?奇怪...
  • 我还注意到 std::cout 的行为不像我预期的那样。有时它可以正常工作,有时它只是等到程序关闭以输出到终端或等待随机时间。这和Xlib有关系吗?
  • SetWMProtocols 是必需的,因为没有一些明确的通知,窗口管理器无法对任何特定客户端的功能做出假设。仅仅请求Atom 实际上并没有做任何事情。单独的原子只是资源的句柄。
  • std::cout 是一个缓冲流。 std::cerr 充当无缓冲流。当您想要刷新输出流时,您还可以继续使用std::cout 并调用std::flush
  • @mythagel:问个简单的问题:Atom 是什么?
猜你喜欢
  • 1970-01-01
  • 2019-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多