Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you exit X11 program without Error

Tags:

c++

linux

x11

xlib

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.

like image 273
Joe McGrath Avatar asked Nov 18 '11 00:11

Joe McGrath


1 Answers

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.

like image 153
moongoal Avatar answered Sep 30 '22 07:09

moongoal