home *** CD-ROM | disk | FTP | other *** search
- /* Notes :
- * Text90() draws a text string rotated by 90 degrees on the given
- * drawable and given gc. The gc is not modified. Text90() respects
- * the Foreground, ClipMask, and ClipOrigin components of the
- * gc. You must pass the Fontstruct separately because Text90()
- * needs to determine text extents from the gc alone.
- *
- * The general scheme is as follows. First make a 1 bit deep pixmap
- * and render the text using the usual XDrawString() function.
- * Then use XGetImage() to pull that back to the client, XCreateImage()
- * another XImage and put the rotated points from the gotten image
- * into it. XPutImage() the rotated image back to another 1 bit
- * deep pixmap on the server. Now, if there were not a ClipMask
- * set in the gc, we could use this pixmap with the rotated image
- * ('rot_pm') as a ClipMask in gc and use FillRectangle on the
- * given drawable. But this would ignore and destroy the ClipMask
- * in the given gc. So we make another pixmap ('deep_pm'), as deep
- * as the given drawable, XCopyArea() the relevant stuff in the
- * drawable into deep_pm, then using 'rot_pm' as a ClipMask
- * call XFillRectangle to bleed the rotated text onto 'deep_pm',
- * then XCopyArea 'deep_pm' back onto the given drawable, using
- * the given 'gc' so its ClipMask is respected. Whew.
- *
- * The XImage structure needs a Visual when you create it with
- * XCreateImage. I am making an XImage which should be identical
- * except in shape to the that I got from XGetImage but the gotten
- * one contains no information about the Visual. I punt and use
- * the default Visual of the default Screen -- I am only making
- * a 1 bit deep pixmap so what difference can it make?.
- *
- * I need to pass a drawable_depth to Text90 because there is no
- * way to ask a drawable how deep it is.
- *
- * If we knew that there were no ClipMask in the given gc we could
- * skip the 2 CopyArea()s, but there is no way to determine this
- * without passing yet another argument to Text90 (an argument whose
- * value is probably not known by the caller).
- *
- * Text90 allocates and frees quite a few X objects. If your server
- * has memory leaks you will find out about them using this. Perhaps
- * one could cache these things as statics to Text90.
- *
- * I have included a test main() program. To use it :
- * cc -o xrot xrot.c -lX11 -lm
- * xrot xpos ypos
- * where xpos and ypos give the position of the string.
- *
- * If any one has a better way of doing this, please tell me about it.
- *
- * Bill Dunlap
- * Dept. of Statistics, GN-22
- * University of Washington
- * Seattle, WA 98195
- * bill@stat.washington.edu
- */
- #include <stdio.h>
- #include <X11/Xlib.h>
- #include <X11/Xutil.h>
-
- void Text90() ;
- static void BailOut() ;
- static Display *dpy ;
- static Window win ;
- static XFontStruct *fontstruct ;
- static GC win_gc ;
- static XGCValues xgcv ;
- extern char *malloc() ;
-
- /* ARGSUSED */
- main(argc, argv)
- int argc ;
- char **argv ;
- {
- unsigned long fg, bg ;
- int x, y ;
- if (!(--argc>0 && sscanf(*++argv, "%d", &x)==1))
- x = 20 ;
- if (!(--argc>0 && sscanf(*++argv, "%d", &y)==1))
- y = 20 ;
- dpy = XOpenDisplay((char *)NULL) ;
- if (!dpy) BailOut("XOpenDisplay") ;
- fg = BlackPixel(dpy, DefaultScreen(dpy)) ;
- bg = WhitePixel(dpy, DefaultScreen(dpy)) ;
- #define WIN_WIDTH 500
- #define WIN_HEIGHT 100
- win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
- 200, 200, /* position */
- WIN_WIDTH, WIN_HEIGHT, /* size */
- 2, /* border width */
- fg, /* border color */
- bg) ; /* background color */
- if (!win) BailOut("XCreateSimpleWindow") ;
- #define STRING "This is a test"
- fontstruct = XLoadQueryFont(dpy, "fixed") ;
- if (!fontstruct) BailOut("XLoadQueryFont") ;
- xgcv.foreground = fg ;
- xgcv.background = bg ;
- xgcv.line_width = 4 ;
- win_gc = XCreateGC(dpy, win,
- GCForeground|GCBackground|GCLineWidth,
- &xgcv) ;
- if (!win_gc) BailOut("XCreateGC(win_gc)") ;
- XSelectInput(dpy, win, ExposureMask) ;
- XMapWindow(dpy, win) ;
- while (1) {
- XRectangle rect ;
- XEvent event ;
- XWindowAttributes xwa ;
- XNextEvent(dpy, &event) ;
- if (!(event.type == Expose && ((XExposeEvent *)&event)->count == 0))
- continue ;
- if (!XGetWindowAttributes(dpy, win, &xwa))
- break ;
- XClearWindow(dpy, win) ;
- #define MARGIN 5
- rect.x = MARGIN ; rect.y = MARGIN ;
- rect.width = xwa.width - 2 * MARGIN ;
- rect.height = xwa.height - 2 * MARGIN ;
- XSetClipRectangles(dpy, win_gc, 0, 0, &rect, 1, Unsorted) ;
- XDrawLine(dpy, win, win_gc, 0, 0, xwa.width, xwa.height) ;
- XDrawLine(dpy, win, win_gc, xwa.width, 0, 0, xwa.height) ;
- Text90(dpy, win, xwa.depth, win_gc, x, y, STRING, strlen(STRING), fontstruct) ;
- }
- exit(0) ;
- }
-
- static void
- BailOut(msg)
- char *msg ;
- {
- fprintf(stderr, "Error in %s -- bailing out\n", msg) ;
- exit(1) ;
- }
-
- void
- Text90(dpy, drawable, drawable_depth, gc, x, y, string, length, fontstruct)
- Display *dpy ;
- Drawable drawable ;
- int drawable_depth ;
- GC gc ;
- int x, y ;
- char *string ;
- int length ;
- XFontStruct *fontstruct ;
- {
- Pixmap pm, rot_pm, deep_pm ;
- GC pm_gc, deep_gc ;
- XImage *image, *rot_image ;
- int row, col ;
- char *d ;
- int rot_bytes_per_line ;
- XCharStruct xcs ;
- int width, height ;
- int direction, font_ascent, font_descent ;
- XTextExtents(fontstruct, string, length,
- &direction, &font_ascent, &font_descent,
- &xcs) ;
- width = xcs.width ;
- height = font_ascent + font_descent ;
- pm = XCreatePixmap(dpy, win, width, height, 1) ;
- if (!pm) BailOut("XCreatePixmap") ;
- rot_pm = XCreatePixmap(dpy, drawable, height, width, 1) ;
- if (!rot_pm) BailOut("XCreatePixmap") ;
- xgcv.foreground = 1 ; /* yes, 1, this will be a mask */
- xgcv.background = 0 ;
- xgcv.font = fontstruct->fid ;
- pm_gc = XCreateGC(dpy, pm,
- GCForeground|GCBackground|GCFont,
- &xgcv) ;
- if (!pm_gc) BailOut("XCreateGC(pm_gc)") ;
- XDrawString(dpy, pm, pm_gc, 0, font_ascent, string, length) ;
- image = XGetImage(dpy, pm, 0, 0, width, height, AllPlanes, XYPixmap) ;
- if (!image) BailOut("XGetImage") ;
- #define roundup(n, mod) ( (n)%(mod) ? (1+(n)/(mod))*mod : n )
- rot_bytes_per_line = roundup(image->height, image->bitmap_pad)/(image->bitmap_pad/8) ;
- d = (char *)malloc(rot_bytes_per_line * image->width) ;
- if (!d) BailOut("malloc") ;
- rot_image = XCreateImage(dpy,
- DefaultVisual(dpy, 0), /* I want the same as is in image */
- image->depth,
- image->format,
- image->xoffset,
- d,
- image->height, image->width, /* yes, reverse these */
- image->bitmap_pad,
- rot_bytes_per_line) ;
- if (!rot_image) BailOut("XCreateImage") ;
- /* rotate image 90 degrees clockwise */
- for(row=0 ; row<image->height ; row++) {
- for(col=0 ; col<image->width ; col++) {
- (void)XPutPixel(rot_image, row, rot_image->height-1-col,
- XGetPixel(image, col, row)) ;
- }
- }
- XPutImage(dpy, rot_pm, pm_gc, rot_image,
- 0, 0, /* source origin */
- 0, 0, /* dest origin */
- rot_image->width, rot_image->height) ;
- /* Now the pixmap rot_pm contains a mask of the rotated text */
-
- deep_pm = XCreatePixmap(dpy, drawable,
- rot_image->width, rot_image->height, drawable_depth) ;
- if (!deep_pm) BailOut("XCreatePixmap(deep_pm)") ;
- deep_gc = XCreateGC(dpy, deep_pm, 0L, &xgcv) ;
- if (!deep_gc) BailOut("XCreateGC(deep_gc)") ;
- XCopyArea(dpy, drawable, deep_pm, deep_gc,
- x, y, /* source origin */
- rot_image->width, rot_image->height, /* size */
- 0, 0) ; /* destination origin */
- XCopyGC(dpy, gc, GCForeground, deep_gc) ;
- XSetClipMask(dpy, deep_gc, rot_pm) ;
- XFillRectangle(dpy, deep_pm, deep_gc, 0, 0,
- rot_image->width, rot_image->height) ;
- XCopyArea(dpy, deep_pm, drawable, gc,
- 0, 0, /* source origin */
- rot_image->width, rot_image->height, /* size */
- x, y) ; /* destination origin */
-
- /* I set these things to NULL after freeing to prepare for
- * caching them */
- free(d) ; d = (char *)NULL ;
- XFreeGC(dpy, pm_gc) ; pm_gc = (GC)NULL ;
- XFreeGC(dpy, deep_gc) ; deep_gc = (GC)NULL ;
- XFreePixmap(dpy, pm) ; pm = (Pixmap)NULL ;
- XFreePixmap(dpy, deep_pm) ; deep_pm = (Pixmap)NULL ;
- XFreePixmap(dpy, rot_pm) ; rot_pm = (Pixmap)NULL ;
- XDestroyImage(image) ; image = (XImage *)NULL ;
- XDestroyImage(rot_image) ; rot_image = (XImage *)NULL ;
- /* did I free everything? */
- return ;
- }
-