home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / sources / misc / 4162 / xvertext.2.0 / rotated.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-12  |  21.2 KB  |  806 lines

  1. /* ********************************************************************** */
  2.  
  3. /* xvertext, Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma)
  4.  *
  5.  * Permission to use, copy, modify, and distribute this software and its
  6.  * documentation for any purpose and without fee is hereby granted, provided
  7.  * that the above copyright notice appear in all copies and that both the
  8.  * copyright notice and this permission notice appear in supporting
  9.  * documentation.  All work developed as a consequence of the use of
  10.  * this program should duly acknowledge such use. No representations are
  11.  * made about the suitability of this software for any purpose.  It is
  12.  * provided "as is" without express or implied warranty.
  13.  */
  14.  
  15. /* ********************************************************************** */
  16.  
  17.  
  18. #include <X11/Xlib.h>
  19. #include <X11/Xutil.h>
  20. #include <stdio.h>
  21. #include "rotated.h"
  22.  
  23.  
  24. /* ---------------------------------------------------------------------- */
  25.  
  26.  
  27. static char        *my_strdup();
  28. static char        *my_strtok();
  29.  
  30. float             XRotVersion();
  31. XRotFontStruct         *XRotLoadFont();
  32. void              XRotUnloadFont();
  33. int               XRotTextWidth();
  34. void             XRotDrawString();
  35. void               XRotDrawImageString();
  36. void                     XRotPaintString();
  37. void               XRotDrawAlignedString();
  38. void                     XRotDrawAlignedImageString();
  39. void                     XRotPaintAlignedString();
  40.  
  41.  
  42. /* ---------------------------------------------------------------------- */  
  43.  
  44.  
  45. /* *** Routine to mimic `strdup()' (some machines don't have it) *** */
  46.  
  47. static char *my_strdup(str)
  48.  char *str;
  49. {
  50.  char *s;
  51.  
  52.  if(str==NULL)
  53.      return NULL;
  54.  
  55.  s=(char *)malloc((unsigned)(strlen(str)+1));
  56.  /* this error is highly unlikely ... */
  57.  if(s==NULL) {
  58.      fprintf(stderr, "Fatal error: my_strdup(): Couldn't do malloc (gulp!)\n");
  59.      exit(1); 
  60.  }
  61.  
  62.  strcpy(s, str);
  63.  return s;
  64. }
  65.  
  66.  
  67. /* ---------------------------------------------------------------------- */
  68.  
  69.  
  70. /* *** Routine to replace `strtok' : this one returns a zero
  71.        length string if it encounters two consecutive delimiters *** */
  72.  
  73. static char *my_strtok(str1, str2)
  74.  char *str1, *str2;
  75. {
  76.  char *ret;
  77.  int i, j, stop;
  78.  static int start, len;
  79.  static char *stext;
  80.  
  81.  /* this error should never occur ... */
  82.  if(str2==NULL) {
  83.      fprintf(stderr,
  84.              "Fatal error: my_strdup(): recieved null delimiter string\n");
  85.      exit(1);
  86.  }
  87.  
  88.  /* initialise if str1 not NULL ... */
  89.  if(str1!=NULL) {
  90.      start=0;
  91.      stext=str1;
  92.      len=strlen(str1);
  93.  }
  94.  
  95.  /* run out of tokens ? ... */
  96.  if(start>=len)
  97.      return NULL;
  98.  
  99.  /* loop through characters ... */
  100.  for(i=start; i<len; i++) {
  101.      /* loop through delimiters ... */
  102.      stop=0;
  103.      for(j=0; j<strlen(str2); j++)
  104.          if(stext[i]==str2[j]) 
  105.               stop=1;
  106.  
  107.      if(stop)
  108.          break;
  109.  }
  110.  
  111.  stext[i]='\0';
  112.  
  113.  ret=stext+start;
  114.  
  115.  start=i+1;
  116.  
  117.  return ret;
  118. }
  119.  
  120.  
  121. /* ---------------------------------------------------------------------- */
  122.   
  123.  
  124. /* *** Routine to return version/copyright information *** */
  125.  
  126. float XRotVersion(str, n)
  127.  char *str;
  128.  int n;
  129. {
  130.  if(str!=NULL)
  131.      strncpy(str, XV_COPYRIGHT, n);
  132.  return XV_VERSION;
  133. }
  134.  
  135.  
  136. /* ---------------------------------------------------------------------- */
  137.  
  138.  
  139. /* *** Load the rotated version of a given font *** */
  140.  
  141. XRotFontStruct *XRotLoadFont(dpy, fontname, angle)
  142.  Display *dpy;
  143.  char *fontname;
  144.  float angle;
  145. {
  146.  char val;
  147.  XImage    *I1, *I2;
  148.  Pixmap canvas;
  149.  Window root;
  150.  int screen;
  151.  GC font_gc;
  152.  char text[3], errstr[300];
  153.  XFontStruct *fontstruct;
  154.  XRotFontStruct    *rotfont;
  155.  int ichar, i, j, index, boxlen=60, dir;
  156.  int vert_w, vert_h, vert_len, bit_w, bit_h, bit_len;
  157.  int min_char, max_char;
  158.  unsigned char *vertdata, *bitdata;
  159.  int ascent, descent, lbearing, rbearing;
  160.  int on=1, off=0;
  161.  
  162.  /* make angle positive ... */
  163.  if(angle<0)
  164.      do angle+=360; while(angle<0);
  165.  
  166.  /* get nearest vertical or horizontal direction ... */
  167.  dir=(int)((angle+45.)/90.)%4;
  168.  
  169.  /* useful macros ... */
  170.  screen=DefaultScreen(dpy);
  171.  root=DefaultRootWindow(dpy);
  172.  
  173.  /* create the depth 1 canvas bitmap ... */
  174.  canvas=XCreatePixmap(dpy, root, boxlen, boxlen, 1);
  175.  
  176.  /* create a GC ... */
  177.  font_gc=XCreateGC(dpy, canvas, NULL, 0);
  178.  XSetBackground(dpy, font_gc, off);
  179.  
  180.  /* load the font ... */
  181.  fontstruct=XLoadQueryFont(dpy, fontname);
  182.  if(fontstruct==NULL) {
  183.      xv_errno=XV_NOFONT;
  184.      return NULL;
  185.  }
  186.  
  187.  XSetFont(dpy, font_gc, fontstruct->fid);
  188.  
  189.  /* allocate space for rotated font ... */
  190.  rotfont=(XRotFontStruct *)malloc((unsigned)sizeof(XRotFontStruct));
  191.  if(rotfont==NULL) {
  192.      xv_errno=XV_NOMEM;
  193.      return NULL;
  194.  }
  195.    
  196.  /* determine which characters are defined in font ... */
  197.  min_char=fontstruct->min_char_or_byte2; 
  198.  max_char=fontstruct->max_char_or_byte2;
  199.  
  200.  /* we only want printing characters ... */
  201.  if(min_char<32)  min_char=32;
  202.  if(max_char>126) max_char=126;
  203.      
  204.  /* some overall font data ... */
  205.  rotfont->name=my_strdup(fontname);
  206.  rotfont->dir=dir;
  207.  rotfont->min_char=min_char;
  208.  rotfont->max_char=max_char;
  209.  rotfont->max_ascent=fontstruct->max_bounds.ascent;
  210.  rotfont->max_descent=fontstruct->max_bounds.descent;   
  211.  rotfont->height=rotfont->max_ascent+rotfont->max_descent;
  212.  
  213.  /* remember xfontstruct for `normal' text ... */
  214.  if(dir==0) 
  215.      rotfont->xfontstruct=fontstruct;
  216.  
  217.  else {
  218.      /* font needs rotation ... */
  219.      /* loop through each character ... */
  220.      for(ichar=min_char; ichar<=max_char; ichar++) {
  221.  
  222.          index=ichar-fontstruct->min_char_or_byte2;
  223.  
  224.          /* per char dimensions ... */
  225.          ascent=  rotfont->per_char[ichar-32].ascent=
  226.                           fontstruct->per_char[index].ascent;
  227.          descent= rotfont->per_char[ichar-32].descent=
  228.                           fontstruct->per_char[index].descent;
  229.          lbearing=rotfont->per_char[ichar-32].lbearing=
  230.                           fontstruct->per_char[index].lbearing;
  231.          rbearing=rotfont->per_char[ichar-32].rbearing=
  232.                           fontstruct->per_char[index].rbearing;
  233.                   rotfont->per_char[ichar-32].width=
  234.                           fontstruct->per_char[index].width;
  235.  
  236.          /* some space chars have zero body, but a bitmap can't have ... */
  237.          if(!ascent && !descent)   
  238.              ascent=  rotfont->per_char[ichar-32].ascent=  1;
  239.          if(!lbearing && !rbearing) 
  240.              rbearing=rotfont->per_char[ichar-32].rbearing=1;
  241.  
  242.          /* glyph width and height when vertical ... */
  243.          vert_w=rbearing-lbearing;
  244.          vert_h=ascent+descent;
  245.  
  246.          /* width in bytes ... */
  247.          vert_len=(vert_w-1)/8+1;   
  248.  
  249.          XSetForeground(dpy, font_gc, off);
  250.          XFillRectangle(dpy, canvas, font_gc, 0, 0, boxlen, boxlen);
  251.  
  252.          /* draw the character centre top right on canvas ... */
  253.          sprintf(text, "%c", ichar);
  254.          XSetForeground(dpy, font_gc, on);
  255.          XDrawImageString(dpy, canvas, font_gc, boxlen/2-lbearing,
  256.                           boxlen/2-descent, text, 1);
  257.  
  258.          /* reserve memory for first XImage ... */
  259.          vertdata=(unsigned char *) malloc((unsigned)(vert_len*vert_h));
  260.          if(vertdata==NULL) {
  261.              xv_errno=XV_NOMEM;
  262.              return NULL;
  263.          }
  264.   
  265.          /* create the XImage ... */
  266.          I1=XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap,
  267.                          0, vertdata, vert_w, vert_h, 8, 0);
  268.  
  269.          if(I1==NULL) {
  270.              xv_errno=XV_NOXIMAGE;
  271.              return NULL;
  272.           }
  273.   
  274.          I1->byte_order=I1->bitmap_bit_order=MSBFirst;
  275.    
  276.          /* extract character from canvas ... */
  277.          XGetSubImage(dpy, canvas, boxlen/2, boxlen/2-vert_h,
  278.                       vert_w, vert_h, 1, XYPixmap, I1, 0, 0);
  279.          I1->format=XYBitmap; 
  280.  
  281.          /* width, height of rotated character ... */
  282.          if(dir==2) { 
  283.              bit_w=vert_w;
  284.              bit_h=vert_h; 
  285.          }
  286.          else {
  287.              bit_w=vert_h;
  288.              bit_h=vert_w; 
  289.          }
  290.  
  291.          /* width in bytes ... */
  292.          bit_len=(bit_w-1)/8+1;
  293.    
  294.          rotfont->per_char[ichar-32].glyph.bit_w=bit_w;
  295.          rotfont->per_char[ichar-32].glyph.bit_h=bit_h;
  296.  
  297.          /* reserve memory for the rotated image ... */
  298.          bitdata=(unsigned char *)calloc((unsigned)(bit_h*bit_len), 1);
  299.          if(bitdata==NULL) {
  300.              xv_errno=XV_NOMEM;
  301.              return NULL;
  302.          }
  303.  
  304.          /* create the image ... */
  305.          I2=XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0,
  306.                          bitdata, bit_w, bit_h, 8, 0); 
  307.  
  308.          if(I2==NULL) {
  309.              xv_errno=XV_NOXIMAGE;
  310.              return NULL;
  311.          }
  312.  
  313.          I2->byte_order=I2->bitmap_bit_order=MSBFirst;
  314.  
  315.          /* map vertical data to rotated character ... */
  316.          for(j=0; j<bit_h; j++) {
  317.              for(i=0; i<bit_w; i++) {
  318.                  /* map bits ... */
  319.                  if(dir==1)
  320.                      val=vertdata[i*vert_len + (vert_w-j-1)/8] &
  321.                          (128>>((vert_w-j-1)%8));
  322.    
  323.                  else if(dir==2)
  324.                      val=vertdata[(vert_h-j-1)*vert_len + (vert_w-i-1)/8] &
  325.                          (128>>((vert_w-i-1)%8));
  326.                     
  327.                  else 
  328.                      val=vertdata[(vert_h-i-1)*vert_len + j/8] & 
  329.                          (128>>(j%8));
  330.         
  331.                  if(val) 
  332.                      bitdata[j*bit_len + i/8] = bitdata[j*bit_len + i/8] |
  333.                                                 (128>>(i%8));
  334.              }
  335.          }
  336.    
  337.          /* create this character's bitmap ... */
  338.          rotfont->per_char[ichar-32].glyph.bm=
  339.            XCreatePixmap(dpy, root, bit_w, bit_h, 1);
  340.      
  341.          /* put the image into the bitmap ... */
  342.          XPutImage(dpy, rotfont->per_char[ichar-32].glyph.bm, 
  343.                    font_gc, I2, 0, 0, 0, 0, bit_w, bit_h);
  344.   
  345.          /* free the image and data ... */
  346.          XDestroyImage(I1);
  347.          XDestroyImage(I2);
  348.          free((char *)bitdata);
  349.          free((char *)vertdata);
  350.      }
  351.  
  352.      XFreeFont(dpy, fontstruct);
  353.  }
  354.  
  355.  /* free pixmap and GC ... */
  356.  XFreePixmap(dpy, canvas);
  357.  XFreeGC(dpy, font_gc);
  358.  
  359.  return rotfont;
  360. }
  361.  
  362.  
  363. /* ---------------------------------------------------------------------- */
  364.  
  365.  
  366. /* *** Free the resources associated with a rotated font *** */
  367.  
  368. void XRotUnloadFont(dpy, rotfont)
  369.  Display *dpy;
  370.  XRotFontStruct *rotfont;
  371. {
  372.  int ichar;
  373.  
  374.  if(rotfont->dir==0)
  375.      XFreeFont(dpy, rotfont->xfontstruct);
  376.  
  377.  else
  378.      /* loop through each character, freeing its pixmap ... */
  379.      for(ichar=rotfont->min_char-32; ichar<=rotfont->max_char-32; ichar++)
  380.          XFreePixmap(dpy, rotfont->per_char[ichar].glyph.bm);
  381.  
  382.  /* rotfont should never be referenced again ... */
  383.  free((char *)rotfont);
  384. }
  385.  
  386.  
  387. /* ---------------------------------------------------------------------- */
  388.    
  389.  
  390. /* *** Return the width of a string *** */
  391.  
  392. int XRotTextWidth(rotfont, str, len)
  393.  XRotFontStruct *rotfont;
  394.  char *str;
  395.  int len;
  396. {
  397.  int i, width=0, ichar;
  398.  
  399.  if(str==NULL) 
  400.      return 0;
  401.  
  402.  if(rotfont->dir==0)
  403.      width=XTextWidth(rotfont->xfontstruct, str, strlen(str));
  404.  
  405.  else
  406.      for(i=0; i<len; i++) {
  407.          ichar=str[i]-32;
  408.   
  409.          /* make sure it's a printing character ... */
  410.          if(ichar>=0 && ichar<95) 
  411.              width+=rotfont->per_char[ichar].width;
  412.      }
  413.  
  414.  return width;
  415. }
  416.  
  417.  
  418. /* ---------------------------------------------------------------------- */
  419.  
  420.  
  421. /* *** A front end to XRotPaintString : mimics XDrawString *** */
  422.  
  423. void XRotDrawString(dpy, rotfont, drawable, gc, x, y, str, len)
  424.  Display *dpy;
  425.  XRotFontStruct *rotfont;
  426.  Drawable drawable;
  427.  GC gc;
  428.  int x, y;
  429.  char *str;
  430.  int len;
  431. {
  432.  XRotPaintString(dpy, rotfont, drawable, gc, x, y, str, len, False);
  433. }
  434.  
  435.  
  436. /* ---------------------------------------------------------------------- */
  437.  
  438.  
  439. /* *** A front end to XRotPaintString : mimics XDrawImageString *** */
  440.  
  441. void XRotDrawImageString(dpy, rotfont, drawable, gc, x, y, str, len)
  442.  Display *dpy;
  443.  XRotFontStruct *rotfont;
  444.  Drawable drawable;
  445.  GC gc;
  446.  int x, y;
  447.  char *str;
  448.  int len;
  449. {
  450.  XRotPaintString(dpy, rotfont, drawable, gc, x, y, str, len, True);
  451. }
  452.  
  453.  
  454. /* ---------------------------------------------------------------------- */
  455.               
  456.               
  457. /* *** Paint a simple string with a rotated font *** */
  458.  
  459. /* *** The user should use one of the two front ends above *** */
  460.  
  461. void XRotPaintString(dpy, rotfont, drawable, gc, x, y, str, len, paintbg)
  462.  Display *dpy;
  463.  XRotFontStruct *rotfont;
  464.  Drawable drawable;
  465.  GC gc;
  466.  int x, y;
  467.  char *str;
  468.  int len;
  469.  Bool paintbg;
  470. {            
  471.  static GC my_gc=0;
  472.  XGCValues values;
  473.  int i, xp, yp, dir, ichar, width;
  474. #ifdef X11R3
  475.  static Pixmap empty_stipple=0;
  476. #endif 
  477.  
  478.  if(str==NULL || len<1)
  479.      return;
  480.  
  481.  dir=rotfont->dir;
  482.  
  483.  if(my_gc==0)
  484.      my_gc=XCreateGC(dpy, drawable, NULL, 0);
  485.  
  486.  XCopyGC(dpy, gc, GCForeground|GCBackground, my_gc);
  487.  
  488.  /* a horizontal string is easy ... */
  489.  if(dir==0) {
  490.      XSetFillStyle(dpy, my_gc, FillSolid);
  491.      XSetFont(dpy, my_gc, rotfont->xfontstruct->fid);
  492.      if(!paintbg)
  493.          XDrawString(dpy, drawable, my_gc, x, y, str, len);
  494.      else
  495.          XDrawImageString(dpy, drawable, my_gc, x, y, str, len);
  496.  
  497.      return;
  498.  }
  499.  
  500.  /* vertical or upside down ... */
  501.  
  502.  /* to draw an `image string' we need to fill the background ... */
  503.  if(paintbg) {
  504.  
  505. #ifdef X11R3
  506.      /* Release 3 doesn't have XGetGCValues(), so this is a
  507.         slightly slower fudge ... */
  508.      {
  509.       GC stipple_gc;
  510.       int bestw, besth;
  511.  
  512.       if(empty_stipple==0) {
  513.           XQueryBestStipple(dpy, drawable, 1, 1, &bestw, &besth);
  514.           empty_stipple=XCreatePixmap(dpy, drawable, bestw, besth, 1);
  515.  
  516.           stipple_gc=XCreateGC(dpy, empty_stipple, NULL, 0);
  517.           XSetForeground(dpy, stipple_gc, 0);
  518.  
  519.           XFillRectangle(dpy, empty_stipple, stipple_gc, 0, 0,
  520.                          bestw+1, besth+1);
  521.           XFreeGC(dpy, stipple_gc);
  522.       }
  523.  
  524.       XSetStipple(dpy, my_gc, empty_stipple);
  525.       XSetFillStyle(dpy, my_gc, FillOpaqueStippled);
  526.      }    
  527. #else
  528.      /* get the foreground and background colors
  529.         ( note that this is not a round trip -> little speed penalty ) */
  530.      XGetGCValues(dpy, my_gc, GCForeground|GCBackground, &values);
  531.  
  532.      XSetForeground(dpy, my_gc, values.background);
  533.      XSetFillStyle(dpy, my_gc, FillSolid);
  534. #endif 
  535.  
  536.      width=XRotTextWidth(rotfont, str, strlen(str));
  537.  
  538.      if(dir==1)
  539.          XFillRectangle(dpy, drawable, my_gc, x-rotfont->max_ascent+1, y-width,
  540.                         rotfont->height-1, width);
  541.      else if(dir==2)
  542.          XFillRectangle(dpy, drawable, my_gc, x-width, y-rotfont->max_descent+1,
  543.                         width, rotfont->height-1);
  544.      else
  545.          XFillRectangle(dpy, drawable, my_gc, x-rotfont->max_descent+1,
  546.                         y, rotfont->height-1, width);
  547.  
  548. #ifndef X11R3
  549.    XSetForeground(dpy, my_gc, values.foreground);
  550. #endif 
  551.  }
  552.  
  553.  XSetFillStyle(dpy, my_gc, FillStippled);
  554.  
  555.  /* loop through each character in string ... */
  556.  for(i=0; i<len; i++) {
  557.      ichar=str[i]-32;
  558.  
  559.      /* make sure it's a printing character ... */
  560.      if(ichar>=0 && ichar<95) {
  561.          /* suitable offset ... */
  562.          if(dir==1) {
  563.              xp=x-rotfont->per_char[ichar].ascent;
  564.              yp=y-rotfont->per_char[ichar].rbearing; 
  565.          }
  566.          else if(dir==2) {
  567.              xp=x-rotfont->per_char[ichar].rbearing;
  568.              yp=y-rotfont->per_char[ichar].descent+1; 
  569.          }
  570.          else {
  571.              xp=x-rotfont->per_char[ichar].descent+1;  
  572.              yp=y+rotfont->per_char[ichar].lbearing; 
  573.          }
  574.                    
  575.          /* draw the glyph ... */
  576.          XSetStipple(dpy, my_gc, rotfont->per_char[ichar].glyph.bm);
  577.     
  578.          XSetTSOrigin(dpy, my_gc, xp, yp);
  579.       
  580.          XFillRectangle(dpy, drawable, my_gc, xp, yp,
  581.                         rotfont->per_char[ichar].glyph.bit_w,
  582.                         rotfont->per_char[ichar].glyph.bit_h);
  583.     
  584.          /* advance position ... */
  585.          if(dir==1)
  586.              y-=rotfont->per_char[ichar].width;
  587.          else if(dir==2)
  588.              x-=rotfont->per_char[ichar].width;
  589.          else 
  590.              y+=rotfont->per_char[ichar].width;
  591.          }
  592.      }
  593. }
  594.   
  595.     
  596. /* ---------------------------------------------------------------------- */
  597.  
  598.  
  599. /* *** A front end to XRotPaintAlignedString : uses XRotDrawString *** */
  600.  
  601. void XRotDrawAlignedString(dpy, rotfont, drawable, gc, x, y,
  602.                                   text, align)
  603.  Display *dpy;                    
  604.  XRotFontStruct *rotfont;
  605.  Drawable drawable;
  606.  GC gc;
  607.  int x, y;
  608.  char *text;
  609.  int align;
  610. {
  611.  XRotPaintAlignedString(dpy, rotfont, drawable, gc, x, y, text, align, False);
  612. }
  613.  
  614.  
  615. /* ---------------------------------------------------------------------- */
  616.  
  617.  
  618. /* *** A front end to XRotPaintAlignedString : uses XRotDrawImageString *** */
  619.  
  620. void XRotDrawAlignedImageString(dpy, rotfont, drawable, gc, x, y,
  621.                                   text, align)
  622.  Display *dpy;
  623.  XRotFontStruct *rotfont;
  624.  Drawable drawable;  
  625.  GC gc;
  626.  int x, y;
  627.  char *text;
  628.  int align;
  629. {
  630.  XRotPaintAlignedString(dpy, rotfont, drawable, gc, x, y, text, align, True);
  631. }
  632.  
  633.  
  634. /* ---------------------------------------------------------------------- */
  635.                    
  636.                    
  637. /* *** Routine to paint a string, possibly containing newline characters,
  638.                                                        with alignment *** */
  639.  
  640. /* *** The user should use one of the front ends above *** */
  641.  
  642. void XRotPaintAlignedString(dpy, rotfont, drawable, gc, x, y, text,
  643.                             align, paintbg)
  644.  Display *dpy;
  645.  XRotFontStruct *rotfont;
  646.  Drawable drawable;
  647.  GC gc;
  648.  int x, y;
  649.  char *text;
  650.  int align;
  651.  Bool paintbg;
  652. {  
  653.  int xp, yp, dir;
  654.  int i, nl=1, max_width=0, this_width;
  655.  char *str1, *str2="\n\0", *str3;
  656.  
  657.  if(text==NULL) 
  658.      return;
  659.   
  660.  dir=rotfont->dir;
  661.  
  662.  /* count number of sections in string ... */
  663.  for(i=0; i<strlen(text); i++) 
  664.      if(text[i]=='\n') 
  665.          nl++;
  666.  
  667.  /* find width of longest section ... */
  668.  str1=my_strdup(text);
  669.  str3=my_strtok(str1, str2);
  670.  max_width=XRotTextWidth(rotfont, str3, strlen(str3));
  671.  
  672.  do {
  673.      str3=my_strtok((char *)NULL, str2);
  674.      if(str3!=NULL)
  675.          if(XRotTextWidth(rotfont, str3, strlen(str3))>max_width)
  676.              max_width=XRotTextWidth(rotfont, str3, strlen(str3));
  677.  }
  678.  while(str3!=NULL);
  679.  
  680.  /* calculate vertical starting point according to alignment policy and
  681.       rotation angle ... */
  682.  if(dir==0) {
  683.      if(align==TLEFT || align==TCENTRE || align==TRIGHT)
  684.          yp=y+rotfont->max_ascent;
  685.  
  686.      else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
  687.          yp=y-(nl-1)*rotfont->height - rotfont->max_descent;
  688.  
  689.      else 
  690.          yp=y-(nl-1)/2*rotfont->height + rotfont->max_ascent -
  691.             rotfont->height/2 - ( (nl%2==0)?rotfont->height/2:0 ); 
  692.  }
  693.  
  694.  else if(dir==1) {
  695.      if(align==TLEFT || align==TCENTRE || align==TRIGHT)
  696.          xp=x+rotfont->max_ascent;
  697.  
  698.      else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
  699.          xp=x-(nl-1)*rotfont->height - rotfont->max_descent;
  700.  
  701.      else 
  702.          xp=x-(nl-1)/2*rotfont->height + rotfont->max_ascent -
  703.             rotfont->height/2 - ( (nl%2==0)?rotfont->height/2:0 ); 
  704.  }
  705.  
  706.  else if(dir==2) {
  707.      if(align==TLEFT || align==TCENTRE || align==TRIGHT)
  708.          yp=y-rotfont->max_ascent;
  709.      
  710.      else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
  711.          yp=y+(nl-1)*rotfont->height + rotfont->max_descent;
  712.      
  713.      else 
  714.          yp=y+(nl-1)/2*rotfont->height - rotfont->max_ascent +
  715.             rotfont->height/2 + ( (nl%2==0)?rotfont->height/2:0 ); 
  716.  }
  717.  
  718.  else {
  719.      if(align==TLEFT || align==TCENTRE || align==TRIGHT)
  720.          xp=x-rotfont->max_ascent;
  721.     
  722.      else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
  723.          xp=x+(nl-1)*rotfont->height + rotfont->max_descent;
  724.   
  725.      else 
  726.          xp=x+(nl-1)/2*rotfont->height - rotfont->max_ascent +
  727.             rotfont->height/2 + ( (nl%2==0)?rotfont->height/2:0 ); 
  728.  }
  729.  
  730.  str1=my_strdup(text);
  731.  str3=my_strtok(str1, str2);
  732.   
  733.  /* loop through each section in the string ... */
  734.  do {
  735.      /* width of this section ... */
  736.      this_width=XRotTextWidth(rotfont, str3, strlen(str3));
  737.  
  738.      /* horizontal alignment ... */
  739.      if(dir==0) {
  740.          if(align==TLEFT || align==MLEFT || align==BLEFT)
  741.              xp=x;
  742.   
  743.          else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
  744.              xp=x-this_width/2;
  745.  
  746.          else 
  747.              xp=x-max_width; 
  748.      }   
  749.  
  750.      else if(dir==1) {
  751.          if(align==TLEFT || align==MLEFT || align==BLEFT)
  752.              yp=y;
  753.  
  754.          else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
  755.              yp=y+this_width/2;
  756.  
  757.          else 
  758.              yp=y+max_width; 
  759.      }
  760.  
  761.      else if(dir==2) {
  762.          if(align==TLEFT || align==MLEFT || align==BLEFT)
  763.              xp=x;
  764.   
  765.          else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
  766.              xp=x+this_width/2;
  767.  
  768.          else 
  769.              xp=x+max_width; 
  770.      }
  771.  
  772.      else {
  773.          if(align==TLEFT || align==MLEFT || align==BLEFT)  
  774.              yp=y;
  775.      
  776.          else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
  777.              yp=y-this_width/2;
  778.      
  779.          else 
  780.              yp=y-max_width; 
  781.      }
  782.  
  783.      /* draw the section ... */
  784.      if(!paintbg)
  785.          XRotDrawString(dpy, rotfont, drawable, gc, xp, yp,
  786.                         str3, strlen(str3));
  787.      else
  788.          XRotDrawImageString(dpy, rotfont, drawable, gc, xp, yp, 
  789.                              str3, strlen(str3));  
  790.  
  791.      str3=my_strtok((char *)NULL, str2);
  792.  
  793.      /* advance position ... */
  794.      if(dir==0)
  795.          yp+=rotfont->height;
  796.      else if(dir==1)
  797.          xp+=rotfont->height;
  798.      else if(dir==2)
  799.          yp-=rotfont->height;
  800.      else 
  801.          xp-=rotfont->height;
  802.  }
  803.  while(str3!=NULL);
  804. }
  805.  
  806.