예제 #1
0
main()
{
      Window w2;

      Display *dpy = XOpenDisplay(NIL);
      assert(dpy);
      Screen *scr = DefaultScreenOfDisplay(dpy);

      // CreateWindow

      Window w = XCreateWindow(dpy, RootWindowOfScreen(scr), 10, 100, 200, 300, 0, CopyFromParent,
			       CopyFromParent, CopyFromParent,
			       0, NIL);

      XDestroyWindow(dpy, w);

      // CreateWindow with arguments

      XSetWindowAttributes swa;
      swa.background_pixel = WhitePixelOfScreen(scr);
      swa.bit_gravity = NorthWestGravity;
      swa.border_pixel = BlackPixelOfScreen(scr);
      swa.colormap = DefaultColormapOfScreen(scr);
      swa.cursor = None;
      swa.win_gravity = NorthGravity;

      w = XCreateWindow(dpy, RootWindowOfScreen(scr), 10, 100, 200, 300, 0, CopyFromParent,
			CopyFromParent, CopyFromParent,
			CWBackPixel | CWBitGravity | CWBorderPixel | CWColormap | CWCursor | CWWinGravity, 
			&swa);
      
      // CreateWindow with other arguments

      XDestroyWindow(dpy, w);

      Pixmap pixmap = XCreatePixmap(dpy, RootWindowOfScreen(scr), 45, 25, DefaultDepthOfScreen(scr));
      assert(pixmap);

      swa.background_pixmap = pixmap;
      swa.border_pixmap = pixmap;

      w = XCreateWindow(dpy, RootWindowOfScreen(scr), 10, 100, 200, 300, 0, CopyFromParent,
			CopyFromParent, CopyFromParent,
			CWBackPixmap | CWBorderPixmap,
			&swa);
      
      // ChangeWindowAttributes

      swa.backing_planes = 0x1;
      swa.backing_pixel = WhitePixelOfScreen(scr);
      swa.save_under = True;
      swa.event_mask = KeyPressMask | KeyReleaseMask;
      swa.do_not_propagate_mask = ButtonPressMask | Button4MotionMask;
      swa.override_redirect = False;
      XChangeWindowAttributes(dpy, w, CWBackingPlanes | CWBackingPixel | CWSaveUnder | CWEventMask
			      | CWDontPropagate | CWOverrideRedirect, &swa);

      // GetWindowAttributes

      XWindowAttributes wa;
      Status success = XGetWindowAttributes(dpy, w, &wa);

      // DestroyWindow (done)

      // DestroySubwindows

      w2 = XCreateWindow(dpy, w, 20, 30, 40, 50, 3, CopyFromParent, CopyFromParent, CopyFromParent, 0, NIL);
      XDestroySubwindows(dpy, w);

      // ChangeSaveSet

//        Display *dpy2 = XOpenDisplay(NIL);
//        assert(dpy2);
//        XAddToSaveSet(dpy2, w);
//        XCloseDisplay(dpy2);

      // ReparentWindow

      w2 = XCreateWindow(dpy, RootWindowOfScreen(scr), 20, 30, 40, 50, 3, 
			 CopyFromParent, CopyFromParent, CopyFromParent, 0, NIL);
      XReparentWindow(dpy, w2, w, 10, 5);

      // MapWindow

      XMapWindow(dpy, w);

      // MapSubwindows
      
      XMapSubwindows(dpy, w);

      // UnmapWindow
      
      XUnmapWindow(dpy, w);

      // UnmapSubwindows

      XMapWindow(dpy, w);
      XUnmapSubwindows(dpy, w2);
      XMapSubwindows(dpy, w);

      // ConfigureWindow

      Window w3 = XCreateWindow(dpy, w, 10, 50, 100, 10, 2,
			 CopyFromParent, CopyFromParent, CopyFromParent, 0, NIL);

      XMapWindow(dpy, w3);

      XWindowChanges wc;
      wc.x = -5;
      wc.y = -10;
      wc.width = 50;
      wc.height = 40;
      wc.border_width = 7;
      wc.sibling = w2;
      wc.stack_mode = Opposite;
      XConfigureWindow(dpy, w3, 
		       CWX | CWY | CWWidth | CWHeight | CWBorderWidth | CWSibling | CWStackMode, 
		       &wc);

      // CirculateWindow

      XCirculateSubwindows(dpy, w, RaiseLowest);

      // GetGeometry

      Window root;
      int x, y;
      unsigned width, height, border_width, depth;
      XGetGeometry(dpy, w, &root, &x, &y, &width, &height, &border_width, &depth);

      // QueryTree

      Window parent;
      Window *children;
      unsigned nchildren;
      success = XQueryTree(dpy, w, &root, &parent, &children, &nchildren);
      XFree(children);

      // InternAtom

      Atom a = XInternAtom(dpy, "WM_PROTOCOLS", True);

      // GetAtomName

      char *string = XGetAtomName(dpy, XA_PRIMARY);
      XFree(string);

      // ChangeProperty

      XStoreName(dpy, w, "test window");

      // DeleteProperty

      XDeleteProperty(dpy, w, XA_WM_NAME);

      // GetProperty
      // TODO

      // ListProperties

      int num_prop;
      Atom *list = XListProperties(dpy, w, &num_prop);
      XFree(list);

      // SetSelectionOwner

      XSetSelectionOwner(dpy, XA_PRIMARY, w, 12000);
      XSetSelectionOwner(dpy, XA_SECONDARY, w, CurrentTime);

      // GetSelectionOwner

      Window wx = XGetSelectionOwner(dpy, XA_PRIMARY);

      // ConvertSelection

      XConvertSelection(dpy, XA_SECONDARY, XA_CURSOR, XA_POINT, w, CurrentTime);

      // SendEvent

      // GrabPointer

      std::cerr << "Grabbing" << std::endl;
      int res = XGrabPointer(dpy, w, False, Button5MotionMask | PointerMotionHintMask,
			     GrabModeSync, GrabModeAsync, w, None, CurrentTime);
      XSync(dpy, False);
//      sleep(5);

      // UngrabPointer

      std::cerr << "Ungrabbing" << std::endl;
      XUngrabPointer(dpy, CurrentTime);

      // GrabButton

      XGrabButton(dpy, 3, ShiftMask | ControlMask, w, False, PointerMotionHintMask | Button2MotionMask, 
		  GrabModeAsync, GrabModeSync, None, None);
		  
      XGrabButton(dpy, 2, AnyModifier, w, False, PointerMotionHintMask | Button2MotionMask, 
		  GrabModeAsync, GrabModeSync, None, None);
		  
      // UngrabButton

      XUngrabButton(dpy, 2, LockMask, w);

      // ChangeActivePointerGrab

      XChangeActivePointerGrab(dpy, ButtonPressMask, None, CurrentTime);

      // GrabKeyboard

      XGrabKeyboard(dpy, w, True, GrabModeSync, GrabModeSync, 12000);

      // UngrabKeyboard

      XUngrabKeyboard(dpy, 13000);

      // GrabKey

      XGrabKey(dpy, XKeysymToKeycode(dpy, XK_Tab), ShiftMask | Mod3Mask, w, True, GrabModeSync,
	       GrabModeSync);

      // UngrabKey

      XUngrabKey(dpy, AnyKey, AnyModifier, w);

      // AllowEvents

      XAllowEvents(dpy, AsyncPointer, 14000);

      // GrabServer

      XGrabServer(dpy);

      // UngrabServer

      XUngrabServer(dpy);

      // QueryPointer

      Window child;
      int root_x, root_y, win_x, win_y;
      unsigned mask;
      Bool bres = XQueryPointer(dpy, w, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask);

      // GetMotionEvents

      int nevents;
      XGetMotionEvents(dpy, w, 15000, 16000, &nevents);

      // TranslateCoordinates

      int dest_x, dest_y;

      XTranslateCoordinates(dpy, w, w2, 10, 20, &dest_x, &dest_y, &child);

      // WarpPointer

      XWarpPointer(dpy, w, w2, 0, 0, 100, 100, 20, 30);

      // SetInputFocus

      XSetInputFocus(dpy,w, RevertToPointerRoot, 17000);
      XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, 17000);

      // GetInputFocus

      Window focus;
      int revert_to;
      XGetInputFocus(dpy, &focus, &revert_to);

      // QueryKeymap

      char keys_return[32];
      XQueryKeymap(dpy, keys_return);

      // OpenFont

      Font fid = XLoadFont(dpy, "cursor");

      // CloseFont

      XUnloadFont(dpy, fid);

      // QueryFont

      XFontStruct *fs = XLoadQueryFont(dpy, "cursor");
      assert(fs);

      // QueryTextExtents

      int direction, font_ascent, font_descent;
      XCharStruct overall;
      XQueryTextExtents(dpy, fs -> fid, "toto", 4, &direction, &font_ascent, &font_descent, &overall);
      XQueryTextExtents(dpy, fs -> fid, "odd__length", 11, &direction, &font_ascent, &font_descent, &overall);

      XChar2b c2bs;
      c2bs.byte1 = '$';
      c2bs.byte2 = 'B';
      XQueryTextExtents16(dpy, fs -> fid, &c2bs, 1, &direction, &font_ascent, &font_descent, &overall);

      XQueryTextExtents(dpy, fs -> fid, longString, strlen(longString), &direction, &font_ascent, 
			&font_descent, &overall);

      // ListFonts

      int actual_count;
      char **fontList = XListFonts(dpy, "*", 100, &actual_count);
      XFree((char *)fontList);

      // ListFontsWithInfo

      int count;
      XFontStruct *info;
      char **names = XListFontsWithInfo(dpy, "*", 100, &count, &info);
      XFreeFontInfo(names, info, count);

      // SetFontPath
      // GetFontPath

      int npaths;
      char **charList = XGetFontPath(dpy, &npaths);

      char **charList2 = new char *[npaths + 1];
      memcpy(charList2, charList, npaths * sizeof(char *));
      charList2[npaths] = charList2[0];

      XSetFontPath(dpy, charList2, npaths + 1);
      XSetFontPath(dpy, charList, npaths); // Reset to some reasonnable value

      XFreeFontPath(charList);
      delete [] charList2;

      // CreatePixmap

      Pixmap pix2 = XCreatePixmap(dpy, w, 100, 200, DefaultDepthOfScreen(scr));

      // FreePixmap

      XFreePixmap(dpy, pix2);

      // CreateGC

      Pixmap bitmap = XCreateBitmapFromData(dpy, RootWindowOfScreen(scr), 
					    "\000\000\001\000\000\001\000\000\001\377\377\377", 3, 4);

      XGCValues gcv;
      gcv.function = GXand;
      gcv.plane_mask = 0x1;
      gcv.foreground = WhitePixelOfScreen(scr);
      gcv.background = BlackPixelOfScreen(scr);
      gcv.line_width = 2;
      gcv.line_style = LineDoubleDash;
      gcv.cap_style = CapProjecting;
      gcv.join_style = JoinRound;
      gcv.fill_style = FillStippled;
      gcv.fill_rule = EvenOddRule;
      gcv.arc_mode = ArcPieSlice;
      gcv.tile = pixmap;
      gcv.stipple = bitmap;
      gcv.ts_x_origin = 3;
      gcv.ts_y_origin = 4;
      gcv.font = fs -> fid;
      gcv.subwindow_mode = ClipByChildren;
      gcv.graphics_exposures = True;
      gcv.clip_x_origin = 5;
      gcv.clip_y_origin = 6;
      gcv.clip_mask = bitmap;
      gcv.dash_offset = 1;
      gcv.dashes = 0xc2;
      
      GC gc = XCreateGC(dpy, w, 
			  GCFunction | GCPlaneMask | GCForeground | GCBackground | GCLineWidth
			| GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle | GCFillRule | GCTile
			| GCStipple | GCTileStipXOrigin | GCTileStipYOrigin | GCFont | GCSubwindowMode
			| GCGraphicsExposures | GCClipXOrigin | GCClipYOrigin | GCClipMask | GCDashOffset
			| GCDashList | GCArcMode,
			&gcv);

      // ChangeGC

      gcv.function = GXandReverse;

      // Only a few of these should appear, since the values are cached on the client side by the Xlib.

      XChangeGC(dpy, gc, GCFunction | GCLineStyle | GCStipple | GCGraphicsExposures | GCDashList, &gcv);

      // CopyGC
      
      GC gc2 = XCreateGC(dpy, w, 0, NIL);
      XCopyGC(dpy, gc, GCFunction | GCLineStyle | GCStipple | GCGraphicsExposures | GCDashList, gc2);

      // SetDashes

      XSetDashes(dpy, gc, 3, "\001\377\001", 3);

      // SetClipRectangles

      XRectangle rectangles[] = { { 10, 20, 30, 40 }, { 100, 200, 5, 3 }, { -5, 1, 12, 24 } };
      XSetClipRectangles(dpy, gc, 12, 9, rectangles, SIZEOF(rectangles), Unsorted);

      // FreeGC

	    // done already

      // ClearArea

      XClearArea(dpy, w, 30, 10, 10, 100, False);

      // CopyArea

      XCopyArea(dpy, w, pixmap, gc, 0, 0, 100, 100, 10, 10);

      // CopyPlane

      // This won't work if the Screen doesn't have at least 3 planes
      XCopyPlane(dpy, pixmap, w, gc, 20, 10, 40, 30, 0, 0, 0x4);

      // PolyPoint

      XDrawPoint(dpy, w, gc, 1, 2);

      XPoint points[] = { { 3, 4 }, { 5, 6 } };
      XDrawPoints(dpy, w, gc, points, SIZEOF(points), CoordModeOrigin);

      // PolyLine

      XDrawLines(dpy, w, gc, points, SIZEOF(points), CoordModePrevious);

      // PolySegment

      XSegment segments[] = { { 7, 8, 9, 10 }, { 11, 12, 13, 14 }, { 15, 16, 17, 18 } };
      XDrawSegments(dpy, w, gc, segments, SIZEOF(segments));

      // PolyRectangle

      XDrawRectangles(dpy, w, gc, rectangles, SIZEOF(rectangles));

      // PolyArc

      XArc arcs[] = { { 10, 20, 30, 40, 50, 60 }, { -70, 80, 90, 100, 110, 120 }, 
		      { 10, 20, 30, 40, 50, -30 } };

      XDrawArcs(dpy, w, gc, arcs, SIZEOF(arcs));

      // FillPoly

      XFillPolygon(dpy, w, gc, points, SIZEOF(points), Convex, CoordModePrevious);

      // PolyFillRectangle
      
      XFillRectangles(dpy, w, gc, rectangles, SIZEOF(rectangles));

      // PolyFillArc
      
      XFillArcs(dpy, w, gc, arcs, SIZEOF(arcs));

      // PutImage
      // GetImage

      XImage *image = XGetImage(dpy, w, 10, 20, 40, 30, AllPlanes, ZPixmap);
      XPutImage(dpy, w, gc, image, 0, 0, 50, 60, 40, 30);
      XSync(dpy, False); // Make the next request starts at the beginning of a packet

      // PolyText8
      XTextItem textItems[3];
      textItems[0].chars = "toto";
      textItems[0].nchars = strlen(textItems[0].chars);
      textItems[0].delta = -3;
      textItems[0].font = fs->fid;
      textItems[1].chars = "titi";
      textItems[1].nchars = strlen(textItems[1].chars);
      textItems[1].delta = 3;
      textItems[1].font = None;
      textItems[2].chars = "tutu";
      textItems[2].nchars = strlen(textItems[2].chars);
      textItems[2].delta = 0;
      textItems[2].font = fs->fid;

      XDrawText(dpy, w, gc, 10, 10, textItems, 3);


      XTextItem textItems2[3];
      textItems2[0].chars = "totox";
      textItems2[0].nchars = strlen(textItems2[0].chars);
      textItems2[0].delta = -3;
      textItems2[0].font = fs->fid;
      textItems2[1].chars = "titi";
      textItems2[1].nchars = strlen(textItems2[1].chars);
      textItems2[1].delta = 3;
      textItems2[1].font = None;
      textItems2[2].chars = "tutu";
      textItems2[2].nchars = strlen(textItems2[2].chars);
      textItems2[2].delta = 0;
      textItems2[2].font = fs->fid;

      XDrawText(dpy, w, gc, 10, 10, textItems2, 3);

      // PolyText16

      XChar2b c2b2[] = { 0, 't', 0, 'x' };

      XTextItem16 items16[] = { { &c2bs, 1, -5, None }, { NULL, 0, 0, None }, { c2b2, 2, 0, fs -> fid } };
      XDrawText16(dpy, w, gc, 10, 0, items16, SIZEOF(items16));

      // ImageText8

      XDrawImageString(dpy, w, gc, 10, 10, "toto", 4);

      // ImageText16

      XDrawImageString16(dpy, w, gc, 10, 10, &c2bs, 1);
      XDrawImageString16(dpy, w, gc, 10, 20, c2b2, 2);

      // CreateColormap
      // Don't forget to tell the kids how it was when we had only 8 bits per pixel.

      Colormap colormap = XCreateColormap(dpy, w, DefaultVisualOfScreen(scr), None);

      // FreeColormap

      XFreeColormap(dpy, colormap);
      colormap = XCreateColormap(dpy, w, DefaultVisualOfScreen(scr), None);

      // CopyColormapAndFree

      Colormap colormap2 = XCopyColormapAndFree(dpy, colormap);

      // InstallColormap

      XInstallColormap(dpy, colormap2);

      // UninstallColormap

      XUninstallColormap(dpy, colormap2);

      // ListInstalledColormaps

      int num;
      Colormap *colormapList = XListInstalledColormaps(dpy, w, &num);

      // AllocColor

      XColor screen;
      screen.red = 0;
      screen.green = 32767;
      screen.blue = 65535;
      screen.flags = DoRed | DoGreen | DoBlue;
      success = XAllocColor(dpy, colormap, &screen);

      // AllocNamedColor

      XColor screen2, exact;
      success = XAllocNamedColor(dpy, colormap, "Wheat", &screen2, &exact);

      // AllocColorCells

      unsigned long plane_masks, pixels;
      success = XAllocColorCells(dpy, colormap, False, &plane_masks, 1, &pixels, 1);

      // AllocColorPlanes

      unsigned long rmask, gmask, bmask;
      success = XAllocColorPlanes(dpy, colormap, False, &pixels, 1, 0, 0, 0, &rmask, &gmask, &bmask);

      // FreeColors

      unsigned long pixels2[2] = { screen.pixel, screen2.pixel };
      XFreeColors(dpy, colormap, pixels2, 2, 0);

      // StoreColors

      success = XAllocColorCells(dpy, colormap, False, NIL, 0, pixels2, 2);

      // On many contemporary (that is, year 2000) video cards, you can't allocate read / write cells
      // I want my requests to be sent, however.
      if (!success) {
	    XSetErrorHandler(errorHandler);
      }

      XColor colors[2];
      colors[0] = screen;  colors[0].pixel = pixels2[0];
      colors[1] = screen2; colors[1].pixel = pixels2[1];
      XStoreColors(dpy, colormap, colors, 2);

      // StoreNamedColor

      XStoreNamedColor(dpy, colormap, "Wheat", colors[0].pixel, DoBlue);

      XSync(dpy, False);
      XSetErrorHandler(NIL); // Restore the default handler

      // QueryColors

      screen2.pixel = WhitePixelOfScreen(scr);
      XQueryColor(dpy, colormap, &screen2);

      // LookupColor

      success = XLookupColor(dpy, colormap, "DarkCyan", &exact, &screen);

      // CreateCursor

      Cursor cursor = XCreatePixmapCursor(dpy, pixmap, None, &exact, colors, 10, 10);

      // CreateGlyphCursor
      
      Cursor cursor2 = XCreateGlyphCursor(dpy, fs -> fid, fs -> fid, 'X', 0, &exact, colors);

      // FreeCursor
      
      XFreeCursor(dpy, cursor2);

      // RecolorCursor

      XRecolorCursor(dpy, cursor, colors, &exact);

      // QueryBestSize

      success = XQueryBestSize(dpy, CursorShape, RootWindowOfScreen(scr), 100, 20, &width, &height);

      // QueryExtension

      int major_opcode, first_event, first_error;
      XQueryExtension(dpy, "toto", &major_opcode, &first_event, &first_error);

      // ListExtensions

      int nextensions;
      char **extensionList = XListExtensions(dpy, &nextensions);
      for(char **p = extensionList; nextensions; nextensions--, p++) std::cout << *p << std::endl;
      XFree(extensionList);

      // ChangeKeyboardMapping
      // GetKeyboardMapping

      int min_keycodes, max_keycodes;
      XDisplayKeycodes(dpy, &min_keycodes, &max_keycodes);

      int keysyms_per_keycode;
      KeySym *keysyms = XGetKeyboardMapping(dpy, min_keycodes, max_keycodes - min_keycodes + 1,
					    &keysyms_per_keycode);
      XChangeKeyboardMapping(dpy, min_keycodes, keysyms_per_keycode, keysyms, 
			     max_keycodes - min_keycodes + 1);

      // ChangeKeyboardControl
      // GetKeyboardControl

      XKeyboardState keyboardState;
      XGetKeyboardControl(dpy, &keyboardState);

      XKeyboardControl keyboardValues;
      keyboardValues.key_click_percent = keyboardState.key_click_percent;
      keyboardValues.bell_percent = keyboardState.bell_percent;
      keyboardValues.bell_pitch = keyboardState.bell_pitch;
      keyboardValues.bell_duration = keyboardState.bell_duration;
      keyboardValues.led = 1;
      keyboardValues.led_mode = LedModeOn;
      keyboardValues.key = min_keycodes;
      keyboardValues.auto_repeat_mode = AutoRepeatModeDefault;
      XChangeKeyboardControl(dpy, 
			       KBKeyClickPercent | KBBellPercent | KBBellPitch | KBBellDuration
			     | KBLed | KBLedMode | KBKey | KBAutoRepeatMode,
			     &keyboardValues);

      // Bell

      XBell(dpy, 90);

      // ChangePointerControl
      // GetPointerControl

      int accel_numerator, accel_denominator, threshold;
      XGetPointerControl(dpy, &accel_numerator, &accel_denominator, &threshold);

      XChangePointerControl(dpy, True, True, accel_numerator, accel_denominator, threshold);

      // SetScreenSaver
      // GetScreenSaver

      int timeout, interval, prefer_blanking, allow_exposures;
      XGetScreenSaver(dpy, &timeout, &interval, &prefer_blanking, &allow_exposures);
      XSetScreenSaver(dpy, timeout, interval, prefer_blanking, allow_exposures);

      // ChangeHosts
      // ListHosts

      int nhosts;
      Bool state;
      XHostAddress *hostList = XListHosts(dpy, &nhosts, &state);

      XHostAddress host;
      host.family = FamilyInternet;
      host.length = 4;
      host.address = "\001\002\003\004";
      XAddHost(dpy, &host);

      // SetAccessControl

      XSetAccessControl(dpy, EnableAccess);

      // SetCloseDownMode

      XSetCloseDownMode(dpy, RetainTemporary);

      // KillClient

      XKillClient(dpy, AllTemporary);

      // RotateProperties

      Atom properties[] = { XInternAtom(dpy, "CUT_BUFFER0", False), 
			    XInternAtom(dpy, "CUT_BUFFER1", False),
			    XInternAtom(dpy, "CUT_BUFFER2", False) };
      XRotateWindowProperties(dpy, RootWindowOfScreen(scr), properties, SIZEOF(properties), -1);

      // ForceScreenSaver

      XForceScreenSaver(dpy, ScreenSaverReset);

      // SetPointerMapping
      // GetPointerMapping

      unsigned char map[64];
      int map_length = XGetPointerMapping(dpy, map, 64);
      XSetPointerMapping(dpy, map, map_length);

      // SetModifierMapping
      // GetModifierMapping

      XModifierKeymap *modmap = XGetModifierMapping(dpy);
      XSetModifierMapping(dpy, modmap);

      // NoOperation

      XNoOp(dpy);

      for(;;) {
	    XEvent e;
	    XNextEvent(dpy, &e);
	    std::cout << "Got an event of type " << e.type << std::endl;
      }
}
예제 #2
0
int main(int argc, char *argv[])
{
   /* default values for -f, -i, -r, -c, -b, -g */
   char *fontname = "*";
   char *filename = "font.pcx";
   int start_char = 32, end_char = 255;
   int ccolor = 000000000;
   int bcolor = 255255255;
   int gcolor = 255000255;
   /* X11 variables */
   Display *display;
   int screen_number;
   int default_depth;
   Window window;
   Font font;
   GC gc, gc2;
   Pixmap pixmap;
   XImage *image;
   XCharStruct overall;
   /* misc variables */
   int bitmap_width, bitmap_height;
   int max_ascent, max_descent;
   int max_width, max_height;
   int i, opt, x, y, cx, cy, sx, sy, lines;
   unsigned long black, white;
   BITMAP *bitmap;
   RGB palette[256];

   /* show usage if no options  */
   if (argc == 1) {
      usage(argv[0]);
      exit(EXIT_SUCCESS);
   }

   /* only to access bitmap operations */
   install_allegro(SYSTEM_NONE, &errno, atexit);

   /* parse options  */
   opterr = 0;
   while ((opt = getopt(argc, argv, "f:o:z:c:b:g:r:h")) != EOF) {
      switch (opt) {
	 case 'f':
	    fontname = optarg;
	    break;
	 case 'o':
	    filename = optarg;
	    break;
	 case 'c':
	    ccolor = atol(optarg);
	    break;
	 case 'b':
	    bcolor = atol(optarg);
	    break;
	 case 'g':
	    gcolor = atol(optarg);
	    break;
	 case 'r':
	    {
	       char *str;
	       start_char = strtol(optarg, &str, 0);
	       end_char = strtol(str + 1, NULL, 0);
	       break;
	    }
	 case 'h':
	    usage(argv[0]);
	    exit(EXIT_SUCCESS);
	 default:
	    fprintf(stderr, "%s: unrecognized option -- '%c'\n", argv[0],
		    optopt);
	    fprintf(stderr, "%s: try '%s -h' for more information\n",
		    argv[0], argv[0]);
	    exit(EXIT_FAILURE);
      }
   }

   /* open display */
   display = XOpenDisplay(0);
   if (display == 0) {
      fprintf(stderr, "%s: XOpenDisplay failed\n", argv[0]);
      exit(EXIT_FAILURE);
   }

   /* default screen number and window */
   screen_number = XDefaultScreen(display);
   default_depth = XDefaultDepth(display, screen_number);
   window = XDefaultRootWindow(display);

   /* load font */
   font = XLoadFont(display, fontname);

   /* create gcs */
   {
      unsigned long val_mask;
      XGCValues val_bits;
      val_mask = GCForeground | GCBackground | GCFont | GCFunction;
      val_bits.function = GXcopy;
      val_bits.foreground = white = WhitePixel(display, screen_number);
      val_bits.background = black = BlackPixel(display, screen_number);
      val_bits.font = font;
      gc = XCreateGC(display, window, val_mask, &val_bits);
      val_mask = GCForeground;
      val_bits.foreground = black;
      gc2 = XCreateGC(display, window, val_mask, &val_bits);
   }

   /* query font ascent and descent */
   {
      XFontStruct *xfs;
      int min, max;
      xfs = XQueryFont(display, font);
      max_ascent = xfs->ascent;
      max_descent = xfs->descent;

      if (xfs->min_byte1 == 0 && xfs->max_byte1 == 0) {
	 min = xfs->min_char_or_byte2;
	 max = xfs->max_char_or_byte2;
      }
      else {
	 min = (xfs->min_byte1 << 8) + xfs->min_char_or_byte2;
	 max = (xfs->max_byte1 << 8) + xfs->max_char_or_byte2;
      }

      if (start_char < min || end_char > max)
	 fprintf(stderr,
		 "You specified characters %04x-%04x, but this font "
		 "only has the range %04x-%04x\n", start_char, end_char,
		 min, max);

      XFreeFontInfo(NULL, xfs, 0);
   }

   /* calculate bitmap width and maximum ascent and descent of characters
    * (can exceed the font ascent/descent queried above!) */
   max_width = 0;
   lines = 1 + (end_char - start_char) / 16;
   for (cy = 0; cy < lines; cy++) {

      for (cx = 0; cx < 16 && start_char + cy * 16 + cx <= end_char; cx++) {
	 int dir, ascent, descent;
	 int width;
	 XChar2b string[2] = { {0, 0}, {0, 0} };

	 /* query character size */
	 string[0].byte1 = (start_char + cy * 16 + cx) >> 8;
	 string[0].byte2 = (start_char + cy * 16 + cx) & 255;
	 XQueryTextExtents16(display, font, string, 1, &dir, &ascent,
			     &descent, &overall);
	 width = overall.width;
	 if (width < 1)
	    width = 1;

	 if (width > max_width)
	    max_width = width;

	 if (max_ascent < overall.ascent)
	    max_ascent = overall.ascent;
	 if (max_descent < overall.descent)
	    max_descent = overall.descent;
      }

   }

   max_height = max_ascent + max_descent;

   bitmap_width = (max_width + 1) * 16 + 1;
   bitmap_height = (max_height + 1) * lines + 1;

   /* create bitmap */
   bitmap = create_bitmap(bitmap_width, bitmap_height);
   if (bitmap == 0) {
      fprintf(stderr, "%s: can not create bitmap\n", argv[0]);
      exit(EXIT_FAILURE);
   }

   /* fill with filler color */
   clear_to_color(bitmap, 255);

   /* process all characters */
   sy = 1;
   for (cy = 0; cy < lines; cy++) {

      sx = 1;
      for (cx = 0; cx < 16 && start_char + cy * 16 + cx <= end_char; cx++) {
	 int dir, ascent, descent;
	 XChar2b string[2] = { {0, 0}, {0, 0} };

	 /* query character size */
	 string[0].byte1 = (start_char + cy * 16 + cx) >> 8;
	 string[0].byte2 = (start_char + cy * 16 + cx) & 255;
	 XQueryTextExtents16(display, font, string, 1, &dir, &ascent,
			     &descent, &overall);

	 if (overall.width < 1)
	    overall.width = 1;

	 /* create pixmap and draw character there */
	 pixmap =
	     XCreatePixmap(display, window, overall.width, max_height,
			   default_depth);
	 /* some fonts draw outside their ascent/descent, so we need to clear
	  * the pixmap before drawing the glyph */
	 XFillRectangle(display, pixmap, gc2, 0, 0, overall.width,
			max_height);
	 XDrawImageString16(display, pixmap, gc, 0, max_ascent, string, 1);

	 /* create image with pixmap contents */
	 image =
	     XGetImage(display, pixmap, 0, 0, overall.width, max_height,
		       AllPlanes, ZPixmap);
	 if (image == 0) {
	    fprintf(stderr, "%s: can not get image\n", argv[0]);
	    exit(EXIT_FAILURE);
	 }

	 /* copy image to bitmap */
	 for (y = 0; y < max_height; y++)
	    for (x = 0; x < overall.width; x++) {
	       if (XGetPixel(image, x, y) == white)
		  putpixel(bitmap, sx + x, sy + y, 1);
	       else
		  putpixel(bitmap, sx + x, sy + y, 0);
	    }

	 XDestroyImage(image);
	 XFreePixmap(display, pixmap);

	 sx += max_width + 1;
      }
      sy += max_height + 1;
   }

   /* initialize palette */
   for (i = 0; i < 256; i++)
      palette[i].r = palette[i].g = palette[i].b = 0;

#define CLAMP_COL(v) (((v / 4) > 63) ? 63 : (v / 4))
   palette[0].r = CLAMP_COL(bcolor / 1000000);
   palette[0].g = CLAMP_COL((bcolor % 1000000) / 1000);
   palette[0].b = CLAMP_COL(bcolor % 1000);
   palette[1].r = CLAMP_COL(ccolor / 1000000);
   palette[1].g = CLAMP_COL((ccolor % 1000000) / 1000);
   palette[1].b = CLAMP_COL(ccolor % 1000);
   palette[255].r = CLAMP_COL(gcolor / 1000000);
   palette[255].g = CLAMP_COL((gcolor % 1000000) / 1000);
   palette[255].b = CLAMP_COL(gcolor % 1000);
#undef CLAMP_COL
   save_pcx(filename, bitmap, palette);

   /* clean up */
   destroy_bitmap(bitmap);
   XFreeGC(display, gc);
   XFreeGC(display, gc2);
   XUnloadFont(display, font);
   XCloseDisplay(display);

   exit(EXIT_SUCCESS);
}