如何在没有错误的情况下退出X11程序

Joe*_*ath 17 c++ linux x11 xlib

在问题结束时,我在X11中有一个相当简单的"Hello World".但是当它退出时,我得到下面的运行时错误消息:

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

所以我试着处理wmDeleteMessage自己,我能够阻止窗口关闭,所以我知道我正确地得到了这个事件.比我添加了一个XDestroyWindow()事件处理,我得到了新的错误.

X Error of failed request:  BadWindow (invalid Window parameter)
  Major opcode of failed request:  4 (X_DestroyWindow)
  Resource id in failed request:  0x130
  Serial number of failed request:  12
  Current serial number in output stream:  12
Run Code Online (Sandbox Code Playgroud)

听起来我正试图摧毁已经被摧毁的窗口,但是如果我把XDestroyWindow()它取出它在我的屏幕上保持活着.

下面是我的代码,试图破坏窗口处理程序.如何在没有任何错误的情况下退出?

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

int main()
{
  Display *display;
    if(!(display=XOpenDisplay(NULL))) 
    {
      std::cerr << "ERROR: could not open display\n";
      return 1;
    }

  int screen = DefaultScreen(display);
  Window rootwind = RootWindow(display, screen);
  Colormap cmap = DefaultColormap(display, screen);      
  Atom wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False);

  int blackColor = BlackPixel(display, screen);
  int whiteColor = WhitePixel(display, screen);

  Window w = XCreateSimpleWindow(display, rootwind, 0, 0, 200, 100, 0, blackColor, blackColor);
  XMapWindow(display, w);
  XSetWMProtocols(display, w, &wmDeleteMessage, 1);
  bool running = true;
  while(running) 
  {
    XEvent e;
    XNextEvent(display, &e);      
    switch  (e.type) 
    {
      case ClientMessage:
        if(e.xclient.data.l[0] == wmDeleteMessage) 
        {
          std::cout << "Shutting down now!!!" << std::endl;
          XDestroyWindow(display,e.xdestroywindow.window);
          running=false;
          break;
        }
        break;
    }
  }

    XCloseDisplay(display);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

更新

将行改为:

   std::cout << "Shutting down now!!!" << std::endl;
        XDestroyWindow(display,w);
Run Code Online (Sandbox Code Playgroud)

我不喜欢哪个,因为我计划拥有更多窗口,但是现在我回到了我的第一个错误消息:

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

更新

尝试改变很多东西,比如让循环运行XPending().决定运行别人的hello世界,我的代码也遇到了同样的问题.我的设置一定有问题.

更新 显然很多人都有这个问题.谷歌ftk遇到了这个问题,他们在更改日志中修复了它.他们调用FTK_QUIT(),我猜测它就像Exit().所以我把我的回归放在循环内部,这解决了问题.不知道为什么,但确实如此.固定代码:

  case ClientMessage:
    if(e.xclient.data.l[0] == wmDeleteMessage) 
    {
      XDestroyWindow(display,e.xclient.window);
      XCloseDisplay(display);
      return 0;
    }
Run Code Online (Sandbox Code Playgroud)

对于能够解释原因以及是否可能XCloseDisplay在循环之外移动return语句(以及)的人,仍会给出正确的答案.


事件循环应如下所示正确退出:

  XEvent e;
  do
  {
    XNextEvent(display, &e);      
    if(e.type == ClientMessage && e.xclient.data.l[0] == wmDeleteMessage) 
    {
      XDestroyWindow(display,e.xclient.window);
      break;    
    }
    //...
  }while (XPending(display) > 0)
  XCloseDisplay(display);
  return 0;
Run Code Online (Sandbox Code Playgroud)

switch语句中运行时,代码不起作用.即使它退出循环而不调用另一个X函数.在if语句之前放置的上述switch语句修复了问题,而没有从循环内的程序返回.

AlQ*_*fir 16

这个问题的解决方案很简单:

您必须在XDestroyWindow()函数中使用正确的结构成员.

由于X11事件结构的实现标准,它们彼此非常相似.每个结构都以'type'成员开头,第一个成员几乎总是相同.

现在假设:

int = 4 bytes
Bool = 4 bytes
unsigned long = 8 bytes
Display* = 8 bytes
Window = 4 bytes
Run Code Online (Sandbox Code Playgroud)

如果使用e.xdestroywindow.window调用XDestroyWindow(),则距离事件结构的开头28字节,而如果使用e.xclient.window,则距离为24字节.

由于您将使用错误的Window参数调用XDestroyWindow(),因此它将失败.相反,如果您使用e.xdestroywindow.event(距离事件结构的开头24个字节)调用它,则地址将是正确的,并且该函数将正常工作.

如果您自己查看Xlib.h文件,您会注意到这两个结构的窗口元素的位置不同.

说明这一点,请记住Xlib已经开发多年,并且每天都有许多程序员使用它,所以如果有一个神秘的错误,它可能不在Xlib中.作为最后一个提示,我想告诉您:如果您想进一步使用Xlib编程,请始终将头文件作为主要参考,然后是系统手册,然后是其他所有内容.

您的代码最终唯一的错误是:

XDestroyWindow(display,e.xdestroywindow.window);
Run Code Online (Sandbox Code Playgroud)

必须改为:

XDestroyWindow(display,e.xclient.window);
Run Code Online (Sandbox Code Playgroud)

相反,交换机的使用是好的,并且是最实现的,在X11代码上没有问题.

注意:我自己测试了您的代码,只更改了该行,然后进行各种测试,打印结果.该XDestroyWindow()线是肯定的唯一的错误.