#include #include #include #include #include #include /* Xwinwrap - wrapper for unfriendly X applications to allow some user control over creation of top-level windows. Copyright (c) 1999 Nathan Meyers $Id: xwinwrap.c,v 1.15 2000/02/04 03:52:20 nathanm Exp $ 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 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. */ /* Xwinwrap - wrapper for unfriendly X applications to allow some user control over creation of top-level windows. Author: Nathan Meyers, nmeyers@javalinux.net This wrapper intercepts calls to XOpenDisplay and XCreateWindow. It installs its own colormap and, if preference is expressed for a Visual ID, sets up the Display to use that visual. Its behavior is constrained by what visuals are available from the X server. The following environment variable controls our behavior: XWINWRAP_VISUALID= Example: XWINWRAP_VISUALID=0x22 To see a list of available visual IDs, run xdpyinfo. Known defects: Because we replace the default GC for all screens, we end up with a GC that may be incompatible (depth and/or visual) with use on the root window. In the unlikely event the app tries to use the default GC on the root window, it could be in for a rude surprise. */ #define deffunc(X) typeof(X) static *p_ ## X = 0; #define findfunc(X) p_ ## X = dlsym(handle, #X); #define callfunc(X) (*p_ ## X) deffunc(XAllocColor) deffunc(XCreateColormap) deffunc(XCreateGC) deffunc(XCreateWindow) deffunc(XFree) deffunc(XGetVisualInfo) deffunc(XGetWindowAttributes) deffunc(XOpenDisplay) static void *handle = 0; /* Initialization: Load the X11R6 library and find the XCreateWindow() entry point. */ void _init() { handle = dlopen("libX11.so.6", RTLD_GLOBAL | RTLD_LAZY); if (handle) { /* Find the entry points we'll be needing */ findfunc(XAllocColor) findfunc(XCreateColormap) findfunc(XCreateGC) findfunc(XCreateWindow) findfunc(XFree) findfunc(XGetVisualInfo) findfunc(XGetWindowAttributes) findfunc(XOpenDisplay) } else abort(); } Display *XOpenDisplay(const char* displayName) { int screenNo; VisualID user_visual_id = 0; char *env_value; char *use_one_colormap; /* Open the display */ Display *display = callfunc(XOpenDisplay)(displayName); /* Get our environment data */ if (env_value = getenv("XWINWRAP_VISUALID")) user_visual_id = strtoul(env_value, 0, 0); use_one_colormap = getenv("XWINWRAP_SINGLEMAP"); /* Step through the display's screens */ for (screenNo = 0; screenNo < ScreenCount(display); screenNo++) { Screen *screen = ScreenOfDisplay(display, screenNo); XVisualInfo *info, template; Visual *visual = 0; Window bogusWin; Colormap colormap = 0; XColor color; XSetWindowAttributes attributes; unsigned long white_pixel, black_pixel; GC gc; int count = 0; int new_depth; /* Are we passing colormap IDs through environment variables? */ if (use_one_colormap) { /* We should be. Look for an environment var with a relevant name */ char colormap_name[128], *colormap_val; sprintf(colormap_name, "XWINWRAP_SINGLEMAP_%d", screenNo); colormap_val = getenv(colormap_name); /* If one is found, read its value */ if (colormap_val) colormap = (Colormap)strtoul(colormap_val, 0, 0); } /* Look for desired visual */ if (!user_visual_id) user_visual_id = DefaultVisualOfScreen(screen)->visualid; template.screen = screenNo; info = callfunc(XGetVisualInfo)(display, VisualScreenMask, &template, &count); if (info) { int visNo; for (visNo = 0; visNo < count; visNo++) { if (info[visNo].visualid == user_visual_id) { visual = info[visNo].visual; new_depth = info[visNo].depth; break; } } } if (!visual) { fprintf(stderr, "XWINWRAP: Requested visual ID 0x%lx is " "not available on screen #%d\n", (long)user_visual_id, screenNo); if (info) { static char *visual_classes[] = { "StaticGray", "GrayScale", "StaticColor", "PseudoColor", "TrueColor", "DirectColor", }; int visNo; fprintf(stderr, "Available visuals:\n"); for (visNo = 0; visNo < count; visNo++) fprintf(stderr, " 0x%lx: depth %d %s\n", info[visNo].visualid, info[visNo].depth, visual_classes[info[visNo].class]); } continue; } /* Create a colormap for the screen */ if (!colormap) { colormap = callfunc(XCreateColormap)(display, RootWindowOfScreen(screen), visual, AllocNone); /* Do we need to pass this data on to children? */ if (use_one_colormap) { /* Yes. Set the environment */ char colormap_name[128], colormap_val[128]; sprintf(colormap_name, "XWINWRAP_SINGLEMAP_%d", screenNo); sprintf(colormap_val, "0x%lx", (unsigned long)colormap); setenv(colormap_name, colormap_val, 1); } } /* Create a bogus window */ attributes.colormap = colormap; bogusWin = callfunc(XCreateWindow)(display, RootWindowOfScreen(screen), 0, 0, 1, 1, 0, new_depth, InputOutput, visual, CWColormap, &attributes); /* Create a GC for the bogus window */ gc = callfunc(XCreateGC)(display, bogusWin, 0, 0); /* Get the two basic pixels */ color.red = color.green = color.blue = 0x0; callfunc(XAllocColor)(display, colormap, &color); black_pixel = color.pixel; color.red = color.green = color.blue = 0xffff; callfunc(XAllocColor)(display, colormap, &color); white_pixel = color.pixel; /* Here's where most of the magic happens. We've created a colormap, visual, and default GC that conform to the user's requests. Now we violate the opacity of the Screen structure and drop these in as defaults. Do not try this at home! */ /* Replace the depth... */ screen->root_depth = new_depth; /* Replace the root visual... */ screen->root_visual = visual; /* Replace the default GC... */ screen->default_gc = gc; /* Replace the default colormap... */ screen->cmap = colormap; /* And replace the two standard pixels */ screen->white_pixel = white_pixel; screen->black_pixel = black_pixel; /* We're done violating the screen structure. */ } return display; } /* XCreateWindow: This is the hijacked version executed by the application. We look for creation of top-level windows, and apply the user preferences to the arguments we're passing through. */ Window XCreateWindow(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, int depth, unsigned int class, Visual *visual, unsigned long valuemask, XSetWindowAttributes* attributes) { Screen *screen; XWindowAttributes win_attributes; XSetWindowAttributes tempbuf; callfunc(XGetWindowAttributes)(display, parent, &win_attributes); /* We now have a Screen* */ screen = win_attributes.screen; /* Is parent the root window */ if (parent == RootWindowOfScreen(screen)) { /* We need one other piece of magic. In case the application has its own ideas about depth, visual, and colormap, we enforce the user's preferences here. */ depth = DefaultDepthOfScreen(screen); visual = DefaultVisualOfScreen(screen); valuemask |= CWColormap; if (!attributes) attributes = &tempbuf; attributes->colormap = DefaultColormapOfScreen(screen); } return callfunc(XCreateWindow)(display, parent, x, y, width, height, border_width, depth, class, visual, valuemask, attributes); }