如何退出X11程序而不出错

发布于 2024-12-16 01:43:41 字数 3636 浏览 4 评论 0原文

我在问题末尾的 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.

因此,我尝试自己处理 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

听起来我正在尝试销毁一个已经销毁的窗口,但如果我取出 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;
}

更新

将行更改为:

   std::cout << "Shutting down now!!!" << std::endl;
        XDestroyWindow(display,w);

我不喜欢,因为我计划拥有的不仅仅是窗口,但现在我是 回到我收到的第一条错误消息:

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

更新

尝试更改许多内容,例如让循环运行 XPending()。 决定运行别人的 hello world ,我遇到了同样的问题与他们的代码。一定是我的设置有问题。

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

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

仍然会向能够解释原因以及是否可能将 return 语句(以及 XCloseDisplay)移动到循环之外的人提供正确的答案。


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

  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;

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

I have a fairly simple "Hello World" in X11 at end of question. But when it exits I get the run time error messages below:

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

So I tried handling the wmDeleteMessage myself, and I was able to stop the window from closing, so i know I am getting the event correctly. Than I added a XDestroyWindow() to the event handling and I get new errors.

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

It sounds like i am trying to destroy a already destroyed Window, but if I take out the XDestroyWindow() it stays alive on my screen.

Below is my code with an attempt at a destroy window handler. How do I exit without any errors?

#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;
}

Update

Changed line to :

   std::cout << "Shutting down now!!!" << std::endl;
        XDestroyWindow(display,w);

Which I don't like because I plan on having more than window, but for now I am
back to the first error message I had :

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

Update

Tried changing many things around like having the loop run off of XPending().
Decided to run someone else's hello world and I get the same problem with their code. Must be something wrong with my setup.

Update
Apparently alot of people have this problem. Google ftk had this problem and they fixed it in their change log. They call FTK_QUIT() which i am guessing is like Exit(). So i put my return right there inside the loop and that solved the problem. Not sure why but it did. fixed code:

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

Will still give correct answer to someone who can explain why and if is possible move the return statement (along with the XCloseDisplay) outside of the loop.


The Event loop should look like this to exit properly:

  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;

When running in a switch statement the code does not work. Even if it exits the loop without calling another X function. The if statement above placed before your switch statement fixes the issue without returning from the program inside the loop.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

鹤仙姿 2024-12-23 01:43:42

此问题的解决方案很简单:

您必须将正确的结构成员与 XDestroyWindow() 函数一起使用。

由于X11事件结构的实现标准,它们彼此非常相似。每个结构都以“type”成员开始,并且第一个成员实际上总是相同的。

现在假设:

int = 4 bytes
Bool = 4 bytes
unsigned long = 8 bytes
Display* = 8 bytes
Window = 4 bytes

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

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

如果您自己查看 Xlib.h 文件,您会发现这两个结构的 window 元素的位置不同。

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

最后你的代码唯一的错误是:

XDestroyWindow(display,e.xdestroywindow.window);

必须将其更改为:

XDestroyWindow(display,e.xclient.window);

相反, switch 的使用很好,并且是实现最多的,在 X11 代码上没有任何问题。

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

The solution to this problem is straightforward:

You must use the right structure member with the XDestroyWindow() function.

Due to the implementation standard of the X11 event structures, they're very similar each other. Every structure begins with the 'type' member, and the first members are practically always the same.

Now assume:

int = 4 bytes
Bool = 4 bytes
unsigned long = 8 bytes
Display* = 8 bytes
Window = 4 bytes

If you call XDestroyWindow() with e.xdestroywindow.window, you are going to be 28 bytes away from the beginning of the event structure, while if you use e.xclient.window, you would be 24 bytes away.

Since you're going to call XDestroyWindow() with a wrong Window argument, it will fail. Instead if you call it using e.xdestroywindow.event (which is 24 bytes away from the beginning of the event structure), the address would be right and the function would work gracefully.

If you take a look yourself at the Xlib.h file, you'll notice that the two structures have the window element positioned differently.

Stated this, remember that Xlib has been developed for years and many programmers every day work with it, so if there is a mysterious error, it's probably not within Xlib. As a last hint I want to tell you: if you want to get farther with Xlib programming, always take the header files as the primary reference, followed by the system manual, then all the rest.

The only error with your code in the end is:

XDestroyWindow(display,e.xdestroywindow.window);

Which must be changed to this:

XDestroyWindow(display,e.xclient.window);

Instead the usage of switch is good, and is the most implemented, with no issues on the X11 code.

NOTE: I've tested your code myself, by changing that line only, and then doing various tests, printing the result. The XDestroyWindow() line is for sure the only error.

南风起 2024-12-23 01:43:42

只需在 XCloseDisplay() 之前调用 XDestroyWindow() 即可。

编辑:

抱歉,我不明白 XSetWMProtocols 的事情。现在我已经阅读了它。我认为您访问了错误的事件联盟成员。

XDestroyWindow(display,e.xdestroywindow.window);

大概应该是:

XDestroyWindow(display,e.xclient.window);

Just call XDestroyWindow() right before XCloseDisplay().

Edit:

Sorry, I didn't understand the XSetWMProtocols thing. Now I've read up on it. I think you're accessing the wrong member of the event union.

XDestroyWindow(display,e.xdestroywindow.window);

Should probably be:

XDestroyWindow(display,e.xclient.window);
执着的年纪 2024-12-23 01:43:42

我遇到了同样的问题,在深入研究 Xlib 文档和大量实验后,我想我知道你问题的答案,我可以向你解释。

当您调用 XCreateWindowXCreateSimpleWindow,然后调用 XMapWindow 时,您指示 X Server 创建窗口并映射到屏幕上。将这些命令从本地缓冲区发送到服务器后(通过调用 XFlush 或任何从服务器请求某些数据的函数,因为它隐式刷新命令缓冲区),X 服务器将显示您的窗口。然后,窗口管理器的工作是将所有装饰附加到窗口,例如一些边框、标题栏、窗口菜单以及用于最小化/最大化/关闭窗口的按钮。

现在您的窗口正在显示,过了一会儿您可以决定使用 XDestroyWindow 销毁它,并通过调用 XCloseDisplay 关闭与 X Server 的连接,一切都会好起来的,没有错误。

问题是,当用户单击窗口标题栏上的 X 时,处理它的不是 X Server 的工作,而是 Window Manager 的工作(X Server 对这些信息一无所知)装饰品,它不在乎)。当用户关闭程序的顶级窗口时,窗口管理器的通常反应是销毁该窗口并关闭与 X Server 的连接,因为这就是大多数用户都会期望。您的程序可能仍然在屏幕外运行,但顶层窗口通常通过窗口管理器与 X Server 连接相关联。

因此,当窗口管理器销毁您的窗口时,您无法调用XDestroyWindow,因为窗口已经被销毁并且其Window句柄无效。您将收到有关 BadWindow 的错误。您也无法调用XCloseDisplay,因为与X Server的连接已经关闭,这将导致X服务器上出现XIO: fatal IO error 11 (Resource暂时不可用)许多用户在其作者不知道的应用程序中遇到的错误。这是一个常见的错误,因为一方面我们鼓励您自行清理,但另一方面文档对于如何正确完成此操作存在误导。

不过,关于 X Server 和窗口管理器应如何协作有一个约定,其中还包括响应用户命令来关闭顶级窗口。 X 协议有一个扩展可以处理它。 Xlib 文档对此的解释如下:

客户端(通常是具有多个顶级窗口的客户端,其服务器连接必须在删除某些顶级窗口后仍然存在)应在 WM_PROTOCOLS 中包含原子 WM_DELETE_WINDOW每个此类窗口上的 code> 属性。他们将收到如上所述的 ClientMessage 事件,其 data[0] 字段为 WM_DELETE_WINDOW
[...]
如果用户要求删除客户端的顶级窗口之一,则选择不在 WM_PROTOCOLS 属性中包含 WM_DELETE_WINDOW 的客户端可能会与服务器断开连接。

因此,这个问题有两种解决方案:当您的窗口被窗口管理器而不是您自己关闭时,避免调用 XDestroyWindowXCloseDisplay (您实际上没有来清理顶层窗口,因为当程序结束时 X Server 仍然会销毁它),或者您需要注册 WM_DESTROY_WINDOW 扩展并等待窗口管理器发出的通知用户关闭您的窗口(然后它会向您发送一个 ClientMessage 事件,其 data[0] 设置为 WM_DELETE_WINDOW)。收到它后,只需销毁窗口并自行关闭与 X Server 的连接,然后结束程序。或者,如果您愿意,请将与 X 服务器的连接保持打开状态以与其执行更多通信。当您处理 WM_DESTROY_WINDOW 时,窗口管理器不会尝试销毁您的窗口,也不会关闭与 X Server 的连接。

I had the same problem, and after digging through Xlib documentation and a lot of experimenting I think I know the answer to your question and I can explain it to you.

When you call XCreateWindow or XCreateSimpleWindow and then XMapWindow, you instruct the X Server to create your window and map in onto the screen. After sending these commands from the local buffer to the server (by calling XFlush or any function which requests some data from the server, since it implicitly flushes the command buffer), the X Server displays your window. Then it's a job of the Window Manager to attach all the decorations to your window, e.g. some borders, title bar, window menu and those buttons to minimize/maximize/close the window.

Now your window is being displayed, and after a while you can decide to destroy it with XDestroyWindow and close the connection to the X Server by calling XCloseDisplay, and everything will be fine, no errors.

The problem is that when the user clicks on that X on your window's title bar, it is not the job of the X Server to handle it, but the Window Manager's job (the X Server knows nothing about those decorations and it doesn't care). The usual reaction of the Window Manager when the user closes the top-level window of your program is to destroy the window and close the connection to the X Server, because that's what most users would expect. Your program may still run off-screen, but the top-level window is usually associated with the X Server connection by the Window Manager.

So when the Window Manager destroys your window, you cannot call XDestroyWindow, because the window is already destroyed and its Window handle is invalid. You will get an error about BadWindow. You also cannot call XCloseDisplay, because the connection to the X Server is already closed, and this will cause the XIO: fatal IO error 11 (Resource temporarily unavailable) on X server error many users experience from applications whose authors didn't knew that. It is a common mistake, because in one hand you are encouraged to clean up after yourself, but in the other hand the documentation is misleading about how this should be done properly.

There is a convention, though, about how X Server and Window Manager should cooperate, which also covers responding to user's commands to close the top-level window. There's an extension to the X protocol that handles it. Here's how the Xlib documentation explains it:

Clients, usually those with multiple top-level windows, whose server connection must survive the deletion of some of their top-level windows, should include the atom WM_DELETE_WINDOW in the WM_PROTOCOLS property on each such window. They will receive a ClientMessage event as described above whose data[0] field is WM_DELETE_WINDOW.
[...]
Clients that choose not to include WM_DELETE_WINDOW in the WM_PROTOCOLS property may be disconnected from the server if the user asks for one of the client's top-level windows to be deleted.

So there are two solutions to this problem: either avoid calling XDestroyWindow and XCloseDisplay when your window is being closed by the Window Manager and not by yourself (you actually don't have to clean up the top-level window since the X Server will destroy it nevertheless when your program ends), or you need to register the WM_DESTROY_WINDOW extension and wait for notification from the Window Manager when it is instructed by the user to close your window (it will send you a ClientMessage event then, with its data[0] set to WM_DELETE_WINDOW). And after receiving it just destroy the window and close the connection to the X Server yourself, and end your program. Or leave the connection to the X Server open to perform some more communication with it if you wish. When you handle WM_DESTROY_WINDOW, the Window Manager will not try to destroy your window nor close the connection to the X Server.

甜嗑 2024-12-23 01:43:42

// 此代码来自: https://en.wikibooks.org/wiki/X_Window_Programming/Xlib< /a> 不显示错误...

  /*
   Simple Xlib application drawing a box in a window.
   To Compile: gcc -o test test.c -lX11  */


 #include<X11/Xlib.h>
 #include<stdio.h>
 #include<stdlib.h> // prevents error for exit on line 18 when compiling with gcc
 int main() {
   Display *d;
   int s;
   Window w;
   XEvent e;


                        /* open connection with the server */
   d=XOpenDisplay(NULL);
   if(d==NULL) {
     printf("Cannot open display\n");
     exit(1);
   }
   s=DefaultScreen(d);


                        /* create window */
   w=XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1,
                         BlackPixel(d, s), WhitePixel(d, s));


   // Process Window Close Event through event handler so XNextEvent does Not fail
   Atom delWindow = XInternAtom( d, "WM_DELETE_WINDOW", 0 );
   XSetWMProtocols(d , w, &delWindow, 1);


                        /* select kind of events we are interested in */
   XSelectInput(d, w, ExposureMask | KeyPressMask);


                        /* map (show) the window */
   XMapWindow(d, w);


                        /* event loop */
   while(1) {
     XNextEvent(d, &e);
                        /* draw or redraw the window */
     if(e.type==Expose) {
       XFillRectangle(d, w, DefaultGC(d, s), 20, 20, 10, 10);
     }
                        /* exit on key press */
     if(e.type==KeyPress)
       break;
     // Handle Windows Close Event
     if(e.type==ClientMessage)
        break;
   }
                        /* destroy our window */
   XDestroyWindow(d, w);
                        /* close connection to server */
   XCloseDisplay(d);
   return 0;

}

// this code from : https://en.wikibooks.org/wiki/X_Window_Programming/Xlib don't show error...

  /*
   Simple Xlib application drawing a box in a window.
   To Compile: gcc -o test test.c -lX11  */


 #include<X11/Xlib.h>
 #include<stdio.h>
 #include<stdlib.h> // prevents error for exit on line 18 when compiling with gcc
 int main() {
   Display *d;
   int s;
   Window w;
   XEvent e;


                        /* open connection with the server */
   d=XOpenDisplay(NULL);
   if(d==NULL) {
     printf("Cannot open display\n");
     exit(1);
   }
   s=DefaultScreen(d);


                        /* create window */
   w=XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1,
                         BlackPixel(d, s), WhitePixel(d, s));


   // Process Window Close Event through event handler so XNextEvent does Not fail
   Atom delWindow = XInternAtom( d, "WM_DELETE_WINDOW", 0 );
   XSetWMProtocols(d , w, &delWindow, 1);


                        /* select kind of events we are interested in */
   XSelectInput(d, w, ExposureMask | KeyPressMask);


                        /* map (show) the window */
   XMapWindow(d, w);


                        /* event loop */
   while(1) {
     XNextEvent(d, &e);
                        /* draw or redraw the window */
     if(e.type==Expose) {
       XFillRectangle(d, w, DefaultGC(d, s), 20, 20, 10, 10);
     }
                        /* exit on key press */
     if(e.type==KeyPress)
       break;
     // Handle Windows Close Event
     if(e.type==ClientMessage)
        break;
   }
                        /* destroy our window */
   XDestroyWindow(d, w);
                        /* close connection to server */
   XCloseDisplay(d);
   return 0;

}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文