diff options
Diffstat (limited to 'dsimple.c')
-rw-r--r-- | dsimple.c | 506 |
1 files changed, 317 insertions, 189 deletions
@@ -1,4 +1,26 @@ /* + * 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,19 +48,14 @@ from The Open Group. */ -#include <X11/Xos.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> +#include <xcb/xcb.h> +#include <xcb/xproto.h> +#include <xcb/xcb_icccm.h> #include <X11/cursorfont.h> #include <stdio.h> #include <stdlib.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" @@ -46,72 +63,33 @@ 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]; - - if (!strcmp (arg, "-display") || !strcmp (arg, "-d")) { - if (++i >= argc) usage (); + const char *name = display_name; - 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); -} - - - -/* - * Open_Display: Routine to open a display with correct error handling. - * Does not require dpy or screen defined on entry. - */ -Display *Open_Display (char *display_name) -{ - Display *d; - - d = XOpenDisplay (display_name); - if (d == NULL) { - fprintf (stderr, "%s: unable to open display '%s'\n", - program_name, XDisplayName (display_name)); - exit (1); - } - - return (d); + return (name); } @@ -120,154 +98,115 @@ Display *Open_Display (char *display_name) * 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. */ void Setup_Display_And_Screen ( - int *argc, /* MODIFIED */ - char **argv) /* MODIFIED */ + const char *display_name, + xcb_connection_t **dpy, /* MODIFIED */ + xcb_screen_t **screen) /* MODIFIED */ { - char *displayname = NULL; + int screen_number, i; - displayname = Get_Display_Name (argc, argv); - dpy = Open_Display (displayname); - screen = XDefaultScreen (dpy); -} + /* 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) ); + } -/* - * Close_Display: Close display - */ -void Close_Display (void) -{ - if (dpy == NULL) - return; + 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); - XCloseDisplay (dpy); - dpy = NULL; + for (i = 0; i < screen_number; i++) + xcb_screen_next(&screen_iter); + *screen = screen_iter.data; + } } - /* - * 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. + * xcb equivalent of XCreateFontCursor */ -Window Select_Window_Args ( - int *rargc, - char **argv) -#define ARGC (*rargc) +static xcb_cursor_t +Create_Font_Cursor (xcb_connection_t *dpy, uint16_t glyph) { - 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; - } - 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; - } - COPYOPT; - } - ARGC = nargc; + static xcb_font_t cursor_font; + xcb_cursor_t cursor; - return (w); -} + if (!cursor_font) { + cursor_font = xcb_generate_id (dpy); + xcb_open_font (dpy, cursor_font, strlen ("cursor"), "cursor"); + } -/* - * Other_stuff: A group of routines which do common X11 tasks. - * - * Written by Mark Lillibridge. Last updated 7/1/87 - */ + 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; +} /* * Routine to let user select a window using the mouse */ -Window Select_Window (Display *dpy, int descend) +xcb_window_t Select_Window(xcb_connection_t *dpy, + const xcb_screen_t *screen, + int descend) { - int status; - Cursor cursor; - XEvent event; - Window target_win = None, root = RootWindow (dpy,screen); + 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 = XCreateFontCursor (dpy, XC_crosshair); + cursor = Create_Font_Cursor (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."); + 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 == None) || (buttons != 0)) { + while ((target_win == XCB_WINDOW_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; + 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 ButtonRelease: + } + 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); } - XUngrabPointer (dpy, CurrentTime); /* Done with pointer */ + xcb_ungrab_pointer (dpy, XCB_TIME_CURRENT_TIME); /* Done with pointer */ if (!descend || (target_win == root)) return (target_win); @@ -285,36 +224,104 @@ Window Select_Window (Display *dpy, int descend) * one found will be returned. Only top and its subwindows * are looked at. Normally, top should be the RootWindow. */ -Window Window_With_Name ( - Display *dpy, - Window top, - char *name) + +struct wininfo_cookies { + xcb_get_property_cookie_t get_wm_name; + xcb_query_tree_cookie_t query_tree; +}; + +static xcb_window_t +recursive_Window_With_Name ( + xcb_connection_t *dpy, + xcb_window_t window, + struct wininfo_cookies *cookies, + const char *name) { - Window *children, dummy; + xcb_window_t *children; unsigned int nchildren; int i; - Window w=0; - char *window_name; + xcb_window_t w = 0; + xcb_generic_error_t *err; + xcb_get_text_property_reply_t prop; + xcb_query_tree_reply_t *tree; + struct wininfo_cookies *child_cookies; + + if (xcb_get_wm_name_reply (dpy, cookies->get_wm_name, &prop, &err)) { + /* can't use strcmp, since prop.name is not null terminated */ + if (strncmp (prop.name, name, prop.name_len) == 0) { + w = window; + } + + xcb_get_text_property_reply_wipe (&prop); - if (XFetchName (dpy, top, &window_name) && !strcmp (window_name, name)) - return (top); + if (w) + { + xcb_discard_reply (dpy, cookies->query_tree.sequence); + return w; + } + } else if (err) { + if (err->response_type == 0) + Print_X_Error (dpy, err); + return 0; + } - if (!XQueryTree (dpy, top, &dummy, &dummy, &children, &nchildren)) - return (0); + 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++) { + 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 = Window_With_Name (dpy, children[i], name); + w = recursive_Window_With_Name (dpy, children[i], + &child_cookies[i], name); if (w) break; } - if (children) XFree ((char *)children); + + if (w) + { + /* clean up remaining replies */ + for (/* keep previous i */; i < nchildren; i++) { + 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); } +xcb_window_t +Window_With_Name ( + xcb_connection_t *dpy, + xcb_window_t top, + const char *name) +{ + struct wininfo_cookies cookies; + + cookies.get_wm_name = xcb_get_wm_name (dpy, top); + cookies.query_tree = xcb_query_tree (dpy, top); + return recursive_Window_With_Name(dpy, top, &cookies, name); +} + /* * Standard fatal error routine - call like printf - * Does not require dpy or screen defined. */ void Fatal_Error (char *msg, ...) { @@ -326,6 +333,127 @@ void Fatal_Error (char *msg, ...) vfprintf (stderr, msg, args); va_end (args); fprintf (stderr, "\n"); - Close_Display (); exit (EXIT_FAILURE); } + +/* + * Print X error information like the default Xlib error handler + */ +void +Print_X_Error ( + xcb_connection_t *dpy, + xcb_generic_error_t *err + ) +{ + 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; + + 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; + + case XCB_LENGTH: + snprintf (buffer, sizeof(buffer), + ": Bad Request Length"); + break; + + case XCB_IMPLEMENTATION: + snprintf (buffer, sizeof(buffer), + ": Server Implementation Failure"); + break; + + 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); + } + + fprintf (stderr, " Request serial number: %d\n", err->full_sequence); +} |