summaryrefslogtreecommitdiff
path: root/dsimple.c
diff options
context:
space:
mode:
Diffstat (limited to 'dsimple.c')
-rw-r--r--dsimple.c506
1 files changed, 317 insertions, 189 deletions
diff --git a/dsimple.c b/dsimple.c
index 51df01f..d1accf7 100644
--- a/dsimple.c
+++ b/dsimple.c
@@ -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);
+}