Responding to window deletion messages from the window manager
This program is very similar to A simple text window using Xlib, which creates an X window with some centred text. This program adds the ability to respond to being given a close message from the window manager. Without this, closing the window via the red cross at the top right of the screen, or equivalent, will result in an error message something like this:
XIO: fatal IO error 35 (Resource temporarily unavailable) on X server "localhost:10.0" after 18 requests (16 known processed) with 0 events remaining.
We can tell the window manager we are interested in these events by
calling XSetWMProtocols
and registering a
WM_DELETE_WINDOW
message with it. Then we'll get a client
message from the window manager when the user tries to close the
window.
#include <string.h> #include <stdlib.h> #include <stdio.h> #include <X11/Xlib.h> /* The window which contains the text. */ struct { int width; int height; char * text; int text_len; /* X Windows related variables. */ Display * display; int screen; Window root; Window window; GC gc; XFontStruct * font; unsigned long black_pixel; unsigned long white_pixel; } text_box; /* Connect to the display, set up the basic variables. */ static void x_connect () { text_box.display = XOpenDisplay (NULL); if (! text_box.display) { fprintf (stderr, "Could not open display.\n"); exit (1); } text_box.screen = DefaultScreen (text_box.display); text_box.root = RootWindow (text_box.display, text_box.screen); text_box.black_pixel = BlackPixel (text_box.display, text_box.screen); text_box.white_pixel = WhitePixel (text_box.display, text_box.screen); } /* Create the window. */ static void create_window () { text_box.width = 300; text_box.height = 300; text_box.window = XCreateSimpleWindow (text_box.display, text_box.root, 1, /* x */ 1, /* y */ text_box.width, text_box.height, 0, /* border width */ text_box.black_pixel, /* border pixel */ text_box.white_pixel /* background */); /* We don't need to select the events here. */ XSelectInput (text_box.display, text_box.window, ExposureMask); XMapWindow (text_box.display, text_box.window); } /* Set up the GC (Graphics Context). */ static void set_up_gc () { text_box.screen = DefaultScreen (text_box.display); text_box.gc = XCreateGC (text_box.display, text_box.window, 0, 0); XSetBackground (text_box.display, text_box.gc, text_box.white_pixel); XSetForeground (text_box.display, text_box.gc, text_box.black_pixel); } /* Set up the text font. */ static void set_up_font () { const char * fontname = "-*-helvetica-*-r-*-*-14-*-*-*-*-*-*-*"; text_box.font = XLoadQueryFont (text_box.display, fontname); /* If the font could not be loaded, revert to the "fixed" font. */ if (! text_box.font) { fprintf (stderr, "unable to load font %s: using fixed\n", fontname); text_box.font = XLoadQueryFont (text_box.display, "fixed"); } XSetFont (text_box.display, text_box.gc, text_box.font->fid); } /* Draw the window. */ static void draw_screen () { int x; int y; int direction; int ascent; int descent; XCharStruct overall; /* Centre the text in the middle of the box. */ XTextExtents (text_box.font, text_box.text, text_box.text_len, & direction, & ascent, & descent, & overall); x = (text_box.width - overall.width) / 2; y = text_box.height / 2 + (ascent - descent) / 2; XClearWindow (text_box.display, text_box.window); XDrawString (text_box.display, text_box.window, text_box.gc, x, y, text_box.text, text_box.text_len); } /* Loop over events. */ static void event_loop () { /* "wm_delete_window" is the Atom which corresponds to the delete window message sent by the window manager. */ Atom wm_delete_window; wm_delete_window = XInternAtom (text_box.display, "WM_DELETE_WINDOW", False); /* Set up the window manager protocols. The third argument here is meant to be an array, and the fourth argument is the size of the array. */ XSetWMProtocols (text_box.display, text_box.window, &wm_delete_window, 1); while (1) { XEvent e; XNextEvent (text_box.display, & e); if (e.type == Expose) { draw_screen (); } /* Deal with a client message from the window manager telling us to delete the window. */ else if (e.type == ClientMessage) { printf ("Closed by the window manager.\n"); if ((Atom)e.xclient.data.l[0] == wm_delete_window) { break; } } } /* Close the connection to the display. This also deletes any windows and other stuff which might have been created. */ XCloseDisplay (text_box.display); } int main (int argc, char ** argv) { text_box.text = "Hello World"; text_box.text_len = strlen (text_box.text); x_connect (); create_window (); set_up_gc (); set_up_font (); event_loop (); return 0; }
Web links
Copyright © Ben Bullock 2009-2024. All
rights reserved.
For comments, questions, and corrections, please email
Ben Bullock
(benkasminbullock@gmail.com).
/
Privacy /
Disclaimer