home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1925 / rotate-text90.c
Encoding:
C/C++ Source or Header  |  1990-12-28  |  7.9 KB  |  232 lines

  1. /* Notes :
  2.  *    Text90() draws a text string rotated by 90 degrees on the given
  3.  *    drawable and given gc.  The gc is not modified.  Text90() respects
  4.  *    the Foreground, ClipMask, and ClipOrigin components of the
  5.  *    gc.  You must pass the Fontstruct separately because Text90()
  6.  *    needs to determine text extents from the gc alone.
  7.  *
  8.  *    The general scheme is as follows.  First make a 1 bit deep pixmap
  9.  *    and render the text using the usual XDrawString() function.
  10.  *    Then use XGetImage() to pull that back to the client, XCreateImage()
  11.  *      another XImage and put the rotated points from the gotten image
  12.  *    into it.  XPutImage() the rotated image back to another 1 bit
  13.  *    deep pixmap on the server.  Now, if there were not a ClipMask
  14.  *    set in the gc, we could use this pixmap with the rotated image
  15.  *    ('rot_pm') as a ClipMask in gc and use FillRectangle on the
  16.  *    given drawable.  But this would ignore and destroy the ClipMask
  17.  *    in the given gc.  So we make another pixmap ('deep_pm'), as deep
  18.  *    as the given drawable, XCopyArea() the relevant stuff in the
  19.  *    drawable into deep_pm, then using 'rot_pm' as a ClipMask
  20.  *    call XFillRectangle to bleed the rotated text onto 'deep_pm',
  21.  *    then XCopyArea 'deep_pm' back onto the given drawable, using
  22.  *    the given 'gc' so its ClipMask is respected.  Whew.
  23.  *
  24.  *    The XImage structure needs a Visual when you create it with
  25.  *    XCreateImage.  I am making an XImage which should be identical
  26.  *    except in shape to the that I got from XGetImage but the gotten
  27.  *    one contains no information about the Visual.  I punt and use
  28.  *    the default Visual of the default Screen  -- I am only making
  29.  *    a 1 bit deep pixmap so what difference can it make?.
  30.  *
  31.  *    I need to pass a drawable_depth to Text90 because there is no
  32.  *    way to ask a drawable how deep it is.
  33.  *
  34.  *    If we knew that there were no ClipMask in the given gc we could
  35.  *    skip the 2 CopyArea()s, but there is no way to determine this
  36.  *    without passing yet another argument to Text90 (an argument whose
  37.  *    value is probably not known by the caller).
  38.  *    
  39.  *    Text90 allocates and frees quite a few X objects.  If your server
  40.  *    has memory leaks you will find out about them using this.  Perhaps
  41.  *    one could cache these things as statics to Text90.
  42.  *
  43.  *    I have included a test main() program.  To use it :
  44.  *        cc -o xrot xrot.c -lX11 -lm
  45.  *        xrot xpos ypos
  46.  *    where xpos and ypos give the position of the string.
  47.  *
  48.  *    If any one has a better way of doing this, please tell me about it.
  49.  *
  50.  *    Bill Dunlap
  51.  *    Dept. of Statistics, GN-22
  52.  *    University of Washington
  53.  *    Seattle, WA 98195
  54.  *    bill@stat.washington.edu
  55.  */
  56. #include <stdio.h>
  57. #include <X11/Xlib.h>
  58. #include <X11/Xutil.h>
  59.  
  60. void Text90() ;
  61. static void BailOut() ;
  62. static Display *dpy ;
  63. static Window win ;
  64. static XFontStruct *fontstruct ;
  65. static GC win_gc ;
  66. static XGCValues xgcv ;
  67. extern char *malloc() ;
  68.  
  69. /* ARGSUSED */
  70. main(argc, argv)
  71. int argc ;
  72. char **argv ;
  73. {
  74.     unsigned long fg, bg ;
  75.     int x, y ;
  76.     if (!(--argc>0 && sscanf(*++argv, "%d", &x)==1))
  77.         x = 20 ;
  78.     if (!(--argc>0 && sscanf(*++argv, "%d", &y)==1))
  79.         y = 20 ;
  80.     dpy = XOpenDisplay((char *)NULL) ;
  81.     if (!dpy) BailOut("XOpenDisplay") ;
  82.     fg = BlackPixel(dpy, DefaultScreen(dpy)) ;
  83.     bg = WhitePixel(dpy, DefaultScreen(dpy)) ;
  84. #define WIN_WIDTH 500
  85. #define WIN_HEIGHT 100
  86.     win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
  87.         200, 200, /* position */
  88.         WIN_WIDTH, WIN_HEIGHT, /* size */
  89.         2, /* border width */
  90.         fg, /* border color */
  91.         bg) ; /* background color */
  92.     if (!win) BailOut("XCreateSimpleWindow") ;
  93. #define STRING "This is a test"
  94.     fontstruct = XLoadQueryFont(dpy, "fixed") ;
  95.     if (!fontstruct) BailOut("XLoadQueryFont") ;
  96.     xgcv.foreground = fg ;
  97.     xgcv.background = bg ;
  98.     xgcv.line_width = 4 ;
  99.     win_gc = XCreateGC(dpy, win,
  100.         GCForeground|GCBackground|GCLineWidth,
  101.         &xgcv) ;
  102.     if (!win_gc) BailOut("XCreateGC(win_gc)") ;
  103.     XSelectInput(dpy, win, ExposureMask) ;
  104.     XMapWindow(dpy, win) ;
  105.     while (1) {
  106.         XRectangle rect ;
  107.         XEvent event ;
  108.         XWindowAttributes xwa ;
  109.         XNextEvent(dpy, &event) ;
  110.         if (!(event.type == Expose && ((XExposeEvent *)&event)->count == 0))
  111.             continue ;
  112.         if (!XGetWindowAttributes(dpy, win, &xwa))
  113.             break ;
  114.         XClearWindow(dpy, win) ;
  115. #define MARGIN 5
  116.         rect.x = MARGIN ; rect.y = MARGIN ;
  117.         rect.width = xwa.width - 2 * MARGIN ;
  118.         rect.height = xwa.height -  2 * MARGIN ;
  119.         XSetClipRectangles(dpy, win_gc, 0, 0, &rect, 1, Unsorted) ;
  120.         XDrawLine(dpy, win, win_gc, 0, 0, xwa.width, xwa.height) ;
  121.         XDrawLine(dpy, win, win_gc, xwa.width, 0, 0, xwa.height) ;
  122.         Text90(dpy, win, xwa.depth, win_gc, x, y, STRING, strlen(STRING), fontstruct) ;
  123.     }
  124.     exit(0) ;
  125. }
  126.  
  127. static void
  128. BailOut(msg)
  129. char *msg ;
  130. {
  131.     fprintf(stderr, "Error in %s -- bailing out\n", msg) ;
  132.     exit(1) ;
  133. }
  134.  
  135. void
  136. Text90(dpy, drawable, drawable_depth, gc, x, y, string, length, fontstruct)
  137. Display *dpy ;
  138. Drawable drawable ;
  139. int drawable_depth ;
  140. GC gc ;
  141. int x, y ;
  142. char *string ;
  143. int length ;
  144. XFontStruct *fontstruct ;
  145. {
  146.     Pixmap pm, rot_pm, deep_pm ;
  147.     GC pm_gc, deep_gc ;
  148.     XImage *image, *rot_image ;
  149.     int row, col ;
  150.     char *d ;
  151.     int rot_bytes_per_line ;
  152.     XCharStruct xcs ;
  153.     int width, height ;
  154.     int direction, font_ascent, font_descent ;
  155.     XTextExtents(fontstruct, string, length,
  156.         &direction, &font_ascent, &font_descent,
  157.         &xcs) ;
  158.     width = xcs.width ;
  159.     height = font_ascent + font_descent ;
  160.     pm = XCreatePixmap(dpy, win, width, height, 1) ;
  161.     if (!pm) BailOut("XCreatePixmap") ;
  162.     rot_pm = XCreatePixmap(dpy, drawable, height, width, 1) ;
  163.     if (!rot_pm) BailOut("XCreatePixmap") ;
  164.     xgcv.foreground = 1 ; /* yes, 1, this will be a mask */
  165.     xgcv.background = 0 ;
  166.     xgcv.font = fontstruct->fid ;
  167.     pm_gc = XCreateGC(dpy, pm,
  168.         GCForeground|GCBackground|GCFont,
  169.         &xgcv) ;
  170.     if (!pm_gc) BailOut("XCreateGC(pm_gc)") ;
  171.     XDrawString(dpy, pm, pm_gc, 0, font_ascent, string, length) ;
  172.     image = XGetImage(dpy, pm, 0, 0, width, height, AllPlanes, XYPixmap) ;
  173.     if (!image) BailOut("XGetImage") ;
  174. #define roundup(n, mod) ( (n)%(mod) ? (1+(n)/(mod))*mod : n )
  175.     rot_bytes_per_line = roundup(image->height, image->bitmap_pad)/(image->bitmap_pad/8) ;
  176.     d = (char *)malloc(rot_bytes_per_line * image->width) ;
  177.     if (!d) BailOut("malloc") ;
  178.     rot_image = XCreateImage(dpy,
  179.         DefaultVisual(dpy, 0), /* I want the same as is in image */
  180.         image->depth,
  181.         image->format,
  182.         image->xoffset,
  183.         d,
  184.         image->height, image->width, /* yes, reverse these */
  185.         image->bitmap_pad, 
  186.         rot_bytes_per_line) ;
  187.     if (!rot_image) BailOut("XCreateImage") ;
  188.     /* rotate image 90 degrees clockwise */
  189.     for(row=0 ; row<image->height ; row++) {
  190.         for(col=0 ; col<image->width ; col++) {
  191.             (void)XPutPixel(rot_image, row, rot_image->height-1-col,
  192.                 XGetPixel(image, col, row)) ;
  193.         }
  194.     }
  195.     XPutImage(dpy, rot_pm, pm_gc, rot_image,
  196.         0, 0, /* source origin */
  197.         0, 0, /* dest origin */
  198.         rot_image->width, rot_image->height) ;
  199.     /* Now the pixmap rot_pm contains a mask of the rotated text */
  200.  
  201.     deep_pm = XCreatePixmap(dpy, drawable,
  202.         rot_image->width, rot_image->height, drawable_depth) ;
  203.     if (!deep_pm) BailOut("XCreatePixmap(deep_pm)") ;
  204.     deep_gc = XCreateGC(dpy, deep_pm, 0L, &xgcv) ;
  205.     if (!deep_gc) BailOut("XCreateGC(deep_gc)") ;
  206.     XCopyArea(dpy, drawable, deep_pm, deep_gc,
  207.         x, y, /* source origin */
  208.         rot_image->width, rot_image->height, /* size */
  209.         0, 0) ; /* destination origin */
  210.     XCopyGC(dpy, gc, GCForeground, deep_gc) ;
  211.     XSetClipMask(dpy, deep_gc, rot_pm) ;
  212.     XFillRectangle(dpy, deep_pm, deep_gc, 0, 0,
  213.         rot_image->width, rot_image->height) ;
  214.     XCopyArea(dpy, deep_pm, drawable, gc,
  215.         0, 0, /* source origin */
  216.         rot_image->width, rot_image->height, /* size */
  217.         x, y) ; /* destination origin */
  218.  
  219.     /* I set these things to NULL after freeing to prepare for
  220.      * caching them */
  221.     free(d) ; d = (char *)NULL ;
  222.     XFreeGC(dpy, pm_gc) ; pm_gc = (GC)NULL ;
  223.     XFreeGC(dpy, deep_gc) ; deep_gc = (GC)NULL ;
  224.     XFreePixmap(dpy, pm) ; pm = (Pixmap)NULL ;
  225.     XFreePixmap(dpy, deep_pm) ; deep_pm = (Pixmap)NULL ;
  226.     XFreePixmap(dpy, rot_pm) ; rot_pm = (Pixmap)NULL ;
  227.     XDestroyImage(image) ; image = (XImage *)NULL ;
  228.     XDestroyImage(rot_image) ; rot_image = (XImage *)NULL ;
  229.     /* did I free everything? */
  230.     return ;
  231. }
  232.