diff options
Diffstat (limited to 'apps/xwininfo/dsimple.c')
-rw-r--r-- | apps/xwininfo/dsimple.c | 762 |
1 files changed, 530 insertions, 232 deletions
diff --git a/apps/xwininfo/dsimple.c b/apps/xwininfo/dsimple.c index b70aa43f2..36ee5c29a 100644 --- a/apps/xwininfo/dsimple.c +++ b/apps/xwininfo/dsimple.c @@ -1,4 +1,25 @@ -/* $Xorg: dsimple.c,v 1.4 2001/02/09 02:05:54 xorgcvs Exp $ */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ /* Copyright 1993, 1998 The Open Group @@ -26,21 +47,20 @@ other dealings in this Software without prior written authorization from The Open Group. */ -/* $XFree86: xc/programs/xlsfonts/dsimple.c,v 3.6 2001/12/14 20:02:09 dawes Exp $ */ -#include <X11/Xos.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> +#include "config.h" + +#include <xcb/xcb.h> +#include <xcb/xproto.h> +#ifdef USE_XCB_ICCCM +# include <xcb/xcb_icccm.h> +#endif #include <X11/cursorfont.h> #include <stdio.h> #include <stdlib.h> +#include <unistd.h> #include <stdarg.h> -/* - * Other_stuff.h: Definitions of routines in other_stuff. - * - * Written by Mark Lillibridge. Last updated 7/1/87 - */ - +#include <string.h> #include "clientwin.h" #include "dsimple.h" @@ -48,287 +68,565 @@ from The Open Group. * Just_display: A group of routines designed to make the writing of simple * X11 applications which open a display but do not open * any windows much faster and easier. Unless a routine says - * otherwise, it may be assumed to require program_name, dpy, - * and screen already defined on entry. + * otherwise, it may be assumed to require program_name + * to be already defined on entry. * * Written by Mark Lillibridge. Last updated 7/1/87 */ -/* This stuff is defined in the calling program by just_display.h */ +/* This stuff is defined in the calling program by dsimple.h */ char *program_name = "unknown_program"; -Display *dpy = NULL; -int screen = 0; - /* - * Get_Display_Name (argc, argv) Look for -display, -d, or host:dpy (obselete) - * If found, remove it from command line. Don't go past a lone -. + * Get_Display_Name (argc, argv) - return string representing display name + * that would be used given the specified argument (i.e. if it's NULL, check + * getenv("DISPLAY") - always returns a non-NULL pointer, though it may be + * an unwritable constant, so is safe to printf() on platforms that crash + * on NULL printf arguments. */ -char *Get_Display_Name( - int *pargc, /* MODIFIED */ - char **argv) /* MODIFIED */ +const char *Get_Display_Name (const char *display_name) { - int argc = *pargc; - char **pargv = argv+1; - char *displayname = NULL; - int i; - - for (i = 1; i < argc; i++) { - char *arg = argv[i]; + const char *name = display_name; - if (!strcmp (arg, "-display") || !strcmp (arg, "-d")) { - if (++i >= argc) usage (); - - displayname = argv[i]; - *pargc -= 2; - continue; - } - if (!strcmp(arg,"-")) { - while (i<argc) - *pargv++ = argv[i++]; - break; - } - *pargv++ = arg; + if (!name) { + name = getenv ("DISPLAY"); + if (!name) + name = ""; } - - *pargv = NULL; - return (displayname); + return (name); } - /* - * Open_Display: Routine to open a display with correct error handling. - * Does not require dpy or screen defined on entry. + * Setup_Display_And_Screen: This routine opens up the correct display (i.e., + * it calls Get_Display_Name) and then stores a + * pointer to it in dpy. The default screen + * for this display is then stored in screen. */ -Display *Open_Display(char *display_name) +void Setup_Display_And_Screen ( + const char *display_name, + xcb_connection_t **dpy, /* MODIFIED */ + xcb_screen_t **screen) /* MODIFIED */ { - Display *d; + int screen_number, i; - d = XOpenDisplay(display_name); - if (d == NULL) { - fprintf (stderr, "%s: unable to open display '%s'\n", - program_name, XDisplayName (display_name)); - exit(1); - } + /* Open Display */ + *dpy = xcb_connect (display_name, &screen_number); + if (xcb_connection_has_error (*dpy)) { + Fatal_Error ("unable to open display \"%s\"", + Get_Display_Name(display_name) ); + } - return(d); -} + if (screen) { + /* find our screen */ + const xcb_setup_t *setup = xcb_get_setup(*dpy); + xcb_screen_iterator_t screen_iter = xcb_setup_roots_iterator(setup); + for (i = 0; i < screen_number; i++) + xcb_screen_next(&screen_iter); + *screen = screen_iter.data; + } +} /* - * Setup_Display_And_Screen: This routine opens up the correct display (i.e., - * it calls Get_Display_Name) and then stores a - * pointer to it in dpy. The default screen - * for this display is then stored in screen. - * Does not require dpy or screen defined. + * xcb equivalent of XCreateFontCursor */ -void Setup_Display_And_Screen( - int *argc, /* MODIFIED */ - char **argv) /* MODIFIED */ +static xcb_cursor_t +Create_Font_Cursor (xcb_connection_t *dpy, uint16_t glyph) { - char *displayname = NULL; - - displayname = Get_Display_Name(argc, argv); - dpy = Open_Display (displayname); - screen = XDefaultScreen(dpy); + static xcb_font_t cursor_font; + xcb_cursor_t cursor; + + if (!cursor_font) { + cursor_font = xcb_generate_id (dpy); + xcb_open_font (dpy, cursor_font, strlen ("cursor"), "cursor"); + } + + cursor = xcb_generate_id (dpy); + xcb_create_glyph_cursor (dpy, cursor, cursor_font, cursor_font, + glyph, glyph + 1, + 0, 0, 0, 0xffff, 0xffff, 0xffff); /* rgb, rgb */ + + return cursor; } /* - * Close_Display: Close display + * Routine to let user select a window using the mouse */ -void Close_Display(void) + +xcb_window_t Select_Window(xcb_connection_t *dpy, + const xcb_screen_t *screen, + int descend) { - if (dpy == NULL) - return; - - XCloseDisplay(dpy); - dpy = NULL; + xcb_cursor_t cursor; + xcb_generic_event_t *event; + xcb_window_t target_win = XCB_WINDOW_NONE; + xcb_window_t root = screen->root; + int buttons = 0; + xcb_generic_error_t *err; + xcb_grab_pointer_cookie_t grab_cookie; + xcb_grab_pointer_reply_t *grab_reply; + + /* Make the target cursor */ + cursor = Create_Font_Cursor (dpy, XC_crosshair); + + /* Grab the pointer using target cursor, letting it room all over */ + grab_cookie = xcb_grab_pointer + (dpy, False, root, + XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, + XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, + root, cursor, XCB_TIME_CURRENT_TIME); + grab_reply = xcb_grab_pointer_reply (dpy, grab_cookie, &err); + if (grab_reply->status != XCB_GRAB_STATUS_SUCCESS) + Fatal_Error ("Can't grab the mouse."); + + /* Let the user select a window... */ + while ((target_win == XCB_WINDOW_NONE) || (buttons != 0)) { + /* allow one more event */ + xcb_allow_events (dpy, XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME); + xcb_flush (dpy); + event = xcb_wait_for_event (dpy); + switch (event->response_type & 0x7f) { + case XCB_BUTTON_PRESS: + { + xcb_button_press_event_t *bp = (xcb_button_press_event_t *)event; + + if (target_win == XCB_WINDOW_NONE) { + target_win = bp->child; /* window selected */ + if (target_win == XCB_WINDOW_NONE) + target_win = root; + } + buttons++; + break; + } + case XCB_BUTTON_RELEASE: + if (buttons > 0) /* there may have been some down before we started */ + buttons--; + break; + default: + /* just discard all other events */ + break; + } + free (event); + } + + xcb_ungrab_pointer (dpy, XCB_TIME_CURRENT_TIME); /* Done with pointer */ + + if (!descend || (target_win == root)) + return (target_win); + + target_win = Find_Client (dpy, root, target_win); + + return (target_win); } /* - * Select_Window_Args: a rountine to provide a common interface for - * applications that need to allow the user to select one - * window on the screen for special consideration. - * This routine implements the following command line - * arguments: - * - * -root Selects the root window. - * -id <id> Selects window with id <id>. <id> may - * be either in decimal or hex. - * -name <name> Selects the window with name <name>. - * - * Call as Select_Window_Args(&argc, argv) in main before - * parsing any of your program's command line arguments. - * Select_Window_Args will remove its arguments so that - * your program does not have to worry about them. - * The window returned is the window selected or 0 if - * none of the above arguments was present. If 0 is - * returned, Select_Window should probably be called after - * all command line arguments, and other setup is done. - * For examples of usage, see xwininfo, xwd, or xprop. + * Window_With_Name: routine to locate a window with a given name on a display. + * If no window with the given name is found, 0 is returned. + * If more than one window has the given name, the first + * one found will be returned. Only top and its subwindows + * are looked at. Normally, top should be the RootWindow. */ -Window Select_Window_Args( - int *rargc, - char **argv) -#define ARGC (*rargc) + +struct wininfo_cookies { + xcb_get_property_cookie_t get_net_wm_name; + xcb_get_property_cookie_t get_wm_name; + xcb_query_tree_cookie_t query_tree; +}; + +#ifndef USE_XCB_ICCCM +# define xcb_get_wm_name(Dpy, Win) \ + xcb_get_property (Dpy, False, Win, XCB_ATOM_WM_NAME, \ + XCB_GET_PROPERTY_TYPE_ANY, 0, BUFSIZ) +#endif + +static xcb_atom_t atom_net_wm_name, atom_utf8_string; + +# define xcb_get_net_wm_name(Dpy, Win) \ + xcb_get_property (Dpy, False, Win, atom_net_wm_name, \ + atom_utf8_string, 0, BUFSIZ) + + +static xcb_window_t +recursive_Window_With_Name ( + xcb_connection_t *dpy, + xcb_window_t window, + struct wininfo_cookies *cookies, + const char *name) { - int nargc=1; - int argc; - char **nargv; - Window w=0; - - nargv = argv+1; argc = ARGC; -#define OPTION argv[0] -#define NXTOPTP ++argv, --argc>0 -#define NXTOPT if (++argv, --argc==0) usage() -#define COPYOPT nargv++[0]=OPTION, nargc++ - - while (NXTOPTP) { - if (!strcmp(OPTION, "-")) { - COPYOPT; - while (NXTOPTP) - COPYOPT; - break; - } - if (!strcmp(OPTION, "-root")) { - w=RootWindow(dpy, screen); - continue; - } - if (!strcmp(OPTION, "-name")) { - NXTOPT; - w = Window_With_Name(dpy, RootWindow(dpy, screen), - OPTION); - if (!w) - Fatal_Error("No window with name %s exists!",OPTION); - continue; + xcb_window_t *children; + unsigned int nchildren; + int i; + xcb_window_t w = 0; + xcb_generic_error_t *err; + xcb_query_tree_reply_t *tree; + struct wininfo_cookies *child_cookies; + xcb_get_property_reply_t *prop; + + if (cookies->get_net_wm_name.sequence) { + prop = xcb_get_property_reply (dpy, cookies->get_net_wm_name, &err); + + if (prop) { + if (prop->type == atom_utf8_string) { + const char *prop_name = xcb_get_property_value (prop); + int prop_name_len = xcb_get_property_value_length (prop); + + /* can't use strcmp, since prop.name is not null terminated */ + if (strncmp (prop_name, name, prop_name_len) == 0) { + w = window; } - if (!strcmp(OPTION, "-id")) { - NXTOPT; - w=0; - sscanf(OPTION, "0x%lx", &w); - if (!w) - sscanf(OPTION, "%lu", &w); - if (!w) - Fatal_Error("Invalid window id format: %s.", OPTION); - continue; + } + free (prop); + } else if (err) { + if (err->response_type == 0) + Print_X_Error (dpy, err); + return 0; + } + } + + if (w) { + xcb_discard_reply (dpy, cookies->get_wm_name.sequence); + } else { +#ifdef USE_XCB_ICCCM + xcb_get_text_property_reply_t nameprop; + + if (xcb_get_wm_name_reply (dpy, cookies->get_wm_name, + &nameprop, &err)) { + /* can't use strcmp, since nameprop.name is not null terminated */ + if (strncmp (nameprop.name, name, nameprop.name_len) == 0) { + w = window; + } + + xcb_get_text_property_reply_wipe (&nameprop); + } +#else + prop = xcb_get_property_reply (dpy, cookies->get_wm_name, &err); + + if (prop) { + if (prop->type == XCB_ATOM_STRING) { + const char *prop_name = xcb_get_property_value (prop); + int prop_name_len = xcb_get_property_value_length (prop); + + /* can't use strcmp, since prop.name is not null terminated */ + if (strncmp (prop_name, name, prop_name_len) == 0) { + w = window; } - COPYOPT; + } + free (prop); } - ARGC = nargc; - - return(w); +#endif + else if (err) { + if (err->response_type == 0) + Print_X_Error (dpy, err); + return 0; + } + } + + if (w) + { + xcb_discard_reply (dpy, cookies->query_tree.sequence); + return w; + } + + tree = xcb_query_tree_reply (dpy, cookies->query_tree, &err); + if (!tree) { + if (err->response_type == 0) + Print_X_Error (dpy, err); + return 0; + } + + nchildren = xcb_query_tree_children_length (tree); + children = xcb_query_tree_children (tree); + child_cookies = calloc(nchildren, sizeof(struct wininfo_cookies)); + + if (child_cookies == NULL) + Fatal_Error("Failed to allocate memory in recursive_Window_With_Name"); + + for (i = 0; i < nchildren; i++) { + if (atom_net_wm_name && atom_utf8_string) + child_cookies[i].get_net_wm_name = + xcb_get_net_wm_name (dpy, children[i]); + child_cookies[i].get_wm_name = xcb_get_wm_name (dpy, children[i]); + child_cookies[i].query_tree = xcb_query_tree (dpy, children[i]); + } + xcb_flush (dpy); + + for (i = 0; i < nchildren; i++) { + w = recursive_Window_With_Name (dpy, children[i], + &child_cookies[i], name); + if (w) + break; + } + + if (w) + { + /* clean up remaining replies */ + for (/* keep previous i */; i < nchildren; i++) { + if (child_cookies[i].get_net_wm_name.sequence) + xcb_discard_reply (dpy, + child_cookies[i].get_net_wm_name.sequence); + xcb_discard_reply (dpy, child_cookies[i].get_wm_name.sequence); + xcb_discard_reply (dpy, child_cookies[i].query_tree.sequence); + } + } + + free (child_cookies); + free (tree); /* includes storage for children[] */ + return (w); } -/* - * Other_stuff: A group of routines which do common X11 tasks. - * - * Written by Mark Lillibridge. Last updated 7/1/87 - */ +xcb_window_t +Window_With_Name ( + xcb_connection_t *dpy, + xcb_window_t top, + const char *name) +{ + struct wininfo_cookies cookies; + + atom_net_wm_name = Get_Atom (dpy, "_NET_WM_NAME"); + atom_utf8_string = Get_Atom (dpy, "UTF8_STRING"); + + if (atom_net_wm_name && atom_utf8_string) + cookies.get_net_wm_name = xcb_get_net_wm_name (dpy, top); + cookies.get_wm_name = xcb_get_wm_name (dpy, top); + cookies.query_tree = xcb_query_tree (dpy, top); + xcb_flush (dpy); + return recursive_Window_With_Name(dpy, top, &cookies, name); +} /* - * Routine to let user select a window using the mouse + * Standard fatal error routine - call like printf */ +void Fatal_Error (char *msg, ...) +{ + va_list args; + fflush (stdout); + fflush (stderr); + fprintf (stderr, "%s: error: ", program_name); + va_start (args, msg); + vfprintf (stderr, msg, args); + va_end (args); + fprintf (stderr, "\n"); + exit (EXIT_FAILURE); +} -Window Select_Window(Display *dpy, int descend) +/* + * Print X error information like the default Xlib error handler + */ +void +Print_X_Error ( + xcb_connection_t *dpy, + xcb_generic_error_t *err + ) { - int status; - Cursor cursor; - XEvent event; - Window target_win = None, root = RootWindow(dpy,screen); - int buttons = 0; - - /* Make the target cursor */ - cursor = XCreateFontCursor(dpy, XC_crosshair); - - /* Grab the pointer using target cursor, letting it room all over */ - status = XGrabPointer(dpy, root, False, - ButtonPressMask|ButtonReleaseMask, GrabModeSync, - GrabModeAsync, root, cursor, CurrentTime); - if (status != GrabSuccess) Fatal_Error("Can't grab the mouse."); - - /* Let the user select a window... */ - while ((target_win == None) || (buttons != 0)) { - /* allow one more event */ - XAllowEvents(dpy, SyncPointer, CurrentTime); - XWindowEvent(dpy, root, ButtonPressMask|ButtonReleaseMask, &event); - switch (event.type) { - case ButtonPress: - if (target_win == None) { - target_win = event.xbutton.subwindow; /* window selected */ - if (target_win == None) target_win = root; - } - buttons++; - break; - case ButtonRelease: - if (buttons > 0) /* there may have been some down before we started */ - buttons--; - break; + char buffer[256] = ""; + + if ((err == NULL) || (err->response_type != 0)) /* not an error */ + return; + + /* Todo: find a more user friendly way to show request/extension info */ + if (err->error_code >= 128) + { + fprintf (stderr, "X Extension Error: Error code %d\n", + err->error_code); } - } + else + { + switch (err->error_code) + { + case XCB_REQUEST: + snprintf (buffer, sizeof(buffer), ": Bad Request"); + break; + + case XCB_VALUE: + snprintf (buffer, sizeof(buffer), + ": Bad Value: 0x%x", err->resource_id); + break; + + case XCB_WINDOW: + snprintf (buffer, sizeof(buffer), + ": Bad Window: 0x%x", err->resource_id); + break; + + case XCB_PIXMAP: + snprintf (buffer, sizeof(buffer), + ": Bad Pixmap: 0x%x", err->resource_id); + break; + + case XCB_ATOM: + snprintf (buffer, sizeof(buffer), + ": Bad Atom: 0x%x", err->resource_id); + break; + + case XCB_CURSOR: + snprintf (buffer, sizeof(buffer), + ": Bad Cursor: 0x%x", err->resource_id); + break; + + case XCB_FONT: + snprintf (buffer, sizeof(buffer), + ": Bad Font: 0x%x", err->resource_id); + break; + + case XCB_MATCH: + snprintf (buffer, sizeof(buffer), ": Bad Match"); + break; + + case XCB_DRAWABLE: + snprintf (buffer, sizeof(buffer), + ": Bad Drawable: 0x%x", err->resource_id); + break; + + case XCB_ACCESS: + snprintf (buffer, sizeof(buffer), ": Access Denied"); + break; + + case XCB_ALLOC: + snprintf (buffer, sizeof(buffer), + ": Server Memory Allocation Failure"); + break; + + case XCB_COLORMAP: + snprintf (buffer, sizeof(buffer), + ": Bad Color: 0x%x", err->resource_id); + break; + + case XCB_G_CONTEXT: + snprintf (buffer, sizeof(buffer), + ": Bad GC: 0x%x", err->resource_id); + break; - XUngrabPointer(dpy, CurrentTime); /* Done with pointer */ + case XCB_ID_CHOICE: + snprintf (buffer, sizeof(buffer), + ": Bad XID: 0x%x", err->resource_id); + break; + + case XCB_NAME: + snprintf (buffer, sizeof(buffer), + ": Bad Name"); + break; - if (!descend || (target_win == root)) - return(target_win); + case XCB_LENGTH: + snprintf (buffer, sizeof(buffer), + ": Bad Request Length"); + break; + + case XCB_IMPLEMENTATION: + snprintf (buffer, sizeof(buffer), + ": Server Implementation Failure"); + break; - target_win = Find_Client(dpy, root, target_win); + default: + snprintf (buffer, sizeof(buffer), ": Unknown error"); + break; + } + fprintf (stderr, "X Error: %d%s\n", err->error_code, buffer); + } + + fprintf (stderr, " Request Major code: %d\n", err->major_code); + if (err->major_code >= 128) + { + fprintf (stderr, " Request Minor code: %d\n", err->minor_code); + } - return(target_win); + fprintf (stderr, " Request serial number: %d\n", err->full_sequence); } +/* + * Cache for atom lookups in either direction + */ +struct atom_cache_entry { + xcb_atom_t atom; + const char *name; + xcb_intern_atom_cookie_t intern_atom; + struct atom_cache_entry *next; +}; + +static struct atom_cache_entry *atom_cache; /* - * Window_With_Name: routine to locate a window with a given name on a display. - * If no window with the given name is found, 0 is returned. - * If more than one window has the given name, the first - * one found will be returned. Only top and its subwindows - * are looked at. Normally, top should be the RootWindow. + * Send a request to the server for an atom by name + * Does not create the atom if it is not already present */ -Window Window_With_Name( - Display *dpy, - Window top, - char *name) +struct atom_cache_entry *Intern_Atom (xcb_connection_t * dpy, const char *name) { - Window *children, dummy; - unsigned int nchildren; - int i; - Window w=0; - char *window_name; - - if (XFetchName(dpy, top, &window_name) && !strcmp(window_name, name)) - return(top); - - if (!XQueryTree(dpy, top, &dummy, &dummy, &children, &nchildren)) - return(0); - - for (i=0; i<nchildren; i++) { - w = Window_With_Name(dpy, children[i], name); - if (w) - break; - } - if (children) XFree ((char *)children); - return(w); + struct atom_cache_entry *a; + + for (a = atom_cache ; a != NULL ; a = a->next) { + if (strcmp (a->name, name) == 0) + return a; /* already requested or found */ + } + + a = calloc(1, sizeof(struct atom_cache_entry)); + if (a != NULL) { + a->name = name; + a->intern_atom = xcb_intern_atom (dpy, False, strlen (name), (name)); + a->next = atom_cache; + atom_cache = a; + } + return a; } +/* Get an atom by name when it is needed. */ +xcb_atom_t Get_Atom (xcb_connection_t * dpy, const char *name) +{ + struct atom_cache_entry *a = Intern_Atom (dpy, name); -/* - * Standard fatal error routine - call like printf - * Does not require dpy or screen defined. - */ -void Fatal_Error(char *msg, ...) + if (a == NULL) + return XCB_ATOM_NONE; + + if (a->atom == XCB_ATOM_NONE) { + xcb_intern_atom_reply_t *reply; + + reply = xcb_intern_atom_reply(dpy, a->intern_atom, NULL); + if (reply) { + a->atom = reply->atom; + free (reply); + } else { + a->atom = -1; + } + } + if (a->atom == -1) /* internal error */ + return XCB_ATOM_NONE; + + return a->atom; +} + +/* Get the name for an atom when it is needed. */ +const char *Get_Atom_Name (xcb_connection_t * dpy, xcb_atom_t atom) { - va_list args; - fflush(stdout); - fflush(stderr); - fprintf(stderr, "%s: error: ", program_name); - va_start(args, msg); - vfprintf(stderr, msg, args); - va_end(args); - fprintf(stderr, "\n"); - Close_Display(); - exit(EXIT_FAILURE); + struct atom_cache_entry *a; + + for (a = atom_cache ; a != NULL ; a = a->next) { + if (a->atom == atom) + return a->name; /* already requested or found */ + } + + a = calloc(1, sizeof(struct atom_cache_entry)); + if (a != NULL) { + xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name (dpy, atom); + xcb_get_atom_name_reply_t *reply + = xcb_get_atom_name_reply (dpy, cookie, NULL); + + a->atom = atom; + if (reply) { + int len = xcb_get_atom_name_name_length (reply); + char *name = malloc(len + 1); + if (name) { + memcpy (name, xcb_get_atom_name_name (reply), len); + name[len] = '\0'; + a->name = name; + } + free (reply); + } + + a->next = atom_cache; + atom_cache = a; + + return a->name; + } + return NULL; } |