X Connection To Broken (Explicit Kill Or Server Shutdown)

So you've started writing a X Window application, everything is going well: it compiles and you're getting a top level window when you run it from the terminal. There is just one problem: when you press the X button on the top corner of your program, you get an error message in your terminal: X connection to broken (explicit kill or server shutdown). Everything seems to work, but you are just getting this bothersome error message instead of your destroy window handler. How do you fix it?

Screenshot of the X Window error message: X Connection To Broken (Explicit Kill Or Server Shutdown)

Well, after reading through the Xlib Programming Manual for Version 11, Rel. 5, Vol. 1, I have devised a solution that I will share with you.

The key is to create (declare) an Atom in your code (such as in main.c). For example this is the Atom window_delete:

Atom window_delete;

Then, where you give the window manager hints, you set the Atom and protocols:

window_delete = XInternAtom(my_display, "WM_DELETE_WINDOW", 1);
XSetWMProtocols(my_display, my_window, &window_delete, 1);

The function XInternAtom is described in the Xlib Programming Manual for Version 11, Rel. 5, Vol. 1 as so:

extern Atom XInternAtom(
#if NeedFunctionPrototypes
    /* display */
    Display*

    /* atom_name */
    _Xconst char*

    /* only if exists */
    Bool
#endif
);

I couldn't find any documentation on the XSetWMProtocols function (I only searched the document for XSetWMProtocols (Ctrl+f)), but I'm guessing it's similar. If you have the time (and patience!), maybe it's in /usr/include/X11?

And finally write a handler to check the ClientMessage in your event loop (it is probably good practice to check l[0], s[0] and b[0]...):

...
else if(my_event.type == ClientMessage)
{
    if(my_event.xclient.data.l[0] == window_delete || my_event.xclient.data.s[0] == window_delete || my_event.xclient.data.b[0] == window_delete)
    {
        if(document_is_dirty == 1)
        {
            // Ask if they want to quit
        }
        else if(document_is_dirty == 0)
        {
            // Just quit
            done = 1;
        }
    }
}
...

Here is the full code for a X Window program that launches a top level window and closes with the close button without the annoying error message:

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

int main(int argc, char *argv[])
{
    /***************
        X Window
    ***************/
    Display *my_display;
    XSetWindowAttributes my_at;
    Window my_window;
    XSizeHints wm_size;
    XWMHints wm_hints;
    XEvent my_event;
    XTextProperty p_window_name, p_icon_name;
    char *window_name = "X Window";
    char *icon_name = "X Window";

    uint32_t screen_num;
    unsigned long value_mask;

    GC my_gc_1;
    XGCValues my_gc_values;

    XFontStruct *font_1;

    Atom window_delete;

    // 1 if done
    uint8_t done = 0;

    // 1 if dirty
    uint8_t document_is_dirty = 0;

    /************************************
        Open connection to the server
    ************************************/
    if((my_display = XOpenDisplay("")) == NULL)
    {
        fprintf(stderr, "Cannot connect to X server\n");
        return -1;
    }

    /********************************
        Create a top level window
    ********************************/
    screen_num = DefaultScreen(my_display);
    my_at.background_pixel = WhitePixel(my_display, screen_num);
    my_at.border_pixel = BlackPixel(my_display, screen_num);
    my_at.event_mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask;
    value_mask = CWBackPixel | CWBorderPixel | CWEventMask;
    my_window = XCreateWindow(
        my_display,
        RootWindow(my_display, screen_num),
        0, 0, 800, 600, 0,
        DefaultDepth(my_display, screen_num),
        InputOutput,
        DefaultVisual(my_display, screen_num),
        value_mask,
        &my_at);

    /************************************
        Give the window manager hints
    ************************************/
    wm_size.flags = USPosition | USSize;
    XSetWMNormalHints(my_display, my_window, &wm_size);
    wm_hints.initial_state = NormalState;
    wm_hints.flags = StateHint;
    XSetWMHints(my_display, my_window, &wm_hints);

    if(XStringListToTextProperty(&window_name, 1, &p_window_name) == 0)
    {
        fprintf(stderr, "Structure allocation for window_name failed\n");
        return -1;
    }
    XSetWMName(my_display, my_window, &p_window_name);

    if(XStringListToTextProperty(&icon_name, 1, &p_icon_name) == 0)
    {
        fprintf(stderr, "Structure allocation for icon_name failed\n");
        return -1;
    }
    XSetWMIconName(my_display, my_window, &p_icon_name);

    window_delete = XInternAtom(my_display, "WM_DELETE_WINDOW", 1);
    XSetWMProtocols(my_display, my_window, &window_delete, 1);

    /*********************************
        Establish window resources
    *********************************/
    font_1 = XLoadQueryFont(my_display, "-misc-fixed-medium-r-semicondensed--13-100-100-100-c-60-iso8859-1");

    my_gc_values.font = font_1 -> fid;

    my_gc_values.background = WhitePixel(my_display, screen_num);
    my_gc_values.foreground = BlackPixel(my_display, screen_num);
    value_mask = GCForeground | GCBackground | GCFont;
    my_gc_1 = XCreateGC(my_display, my_window, value_mask, &my_gc_values);

    /***************************
        Create other windows
    ***************************/

    /**********************
        Map the windows
    **********************/
    XMapWindow(my_display, my_window);

    /*****************
        Event loop
    *****************/
    while(done == 0)
    {
        XNextEvent(my_display, &my_event);

        /*******************
            Expose Event
        *******************/
        if(my_event.type == Expose)
        {
        }
        /*********************
            Client Message
        *********************/
        else if(my_event.type == ClientMessage)
        {
            if(my_event.xclient.data.l[0] == window_delete || my_event.xclient.data.s[0] == window_delete || my_event.xclient.data.b[0] == window_delete)
            {
                if(document_is_dirty == 1)
                {
                    // Ask if they want to quit
                }
                else if(document_is_dirty == 0)
                {
                    // Just quit
                    done = 1;
                }
            }
        }
    }

    /******************************
        Clean up before exiting
    ******************************/
    XUnmapWindow(my_display, my_window);
    XDestroyWindow(my_display, my_window);
    XUnloadFont(my_display, font_1 -> fid);
    XFreeGC(my_display, my_gc_1);
    XCloseDisplay(my_display);

    return 0;
}

Screenshot of the X Window program top level window

This is how it's done in Project [KASUMI] and Project [SONICO]. Please check them out!