/* This file is part of
* ======================================================
* 
*           LyX, the High Level Word Processor
* 	 
*	    Copyright (C) 1995 Matthias Ettrich
*
*======================================================*/

#include "xdefinitions.h"
#include "lyxfont.h"
#include "minibuffer.h"
#include <ctype.h>

extern int reverse_video;
extern int mono_video;
extern char math_color[];
extern char math_frame_color[];
extern char on_off_line_color[];
extern char fill_color[];
extern char latex_color[];
extern char foot_color[];
extern char inset_color[];
extern char lighted_color[];

/* table for all the fonts
 * family        series          shape       size                             bar
* 0 roman       0 medium        0 upshape   0 tiny <- used for scshape small  
* 1 sans (serif) 1 bold          1 italic    1 small                          0 nobar
* 2 typewriter                    /slanted  2 normal                          1 underbar
*                              (2 smallcaps)3 large 
*                                           4 larger 
*                                           5 largest
*                                           4 huge 
*                                           5 giant
*/

char* roman_font_name = "-*-utopia";
char* sans_font_name = "-*-helvetica";
char* typewriter_font_name = "-*-courier";
char* font_norm = "iso8859-1";
char font_sizes[8] =  {
  7, 9, 10, 12, 14, 17, 20, 25
};

extern Window WorkAreaWindow;

char zoom = font_sizes[LYX_SIZE_NORMAL];

Colormap color_map = 0;

static XFontStruct* fontstruct[3][2][2][8] =   {
   
     {
	  {
	       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
	       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
	  },
	  {
	       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
	       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
	  },
     },
     {
	  {
	       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
	       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
	  },
	  {
	       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
	       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
	  },
     },
     {
	  {
	       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
	       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
	  },
	  {
	       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
	       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
	  }
     }
   
};

static XFontStruct* symbol_fontstruct[8] = {NULL, NULL, NULL, NULL,
					    NULL, NULL, NULL, NULL};


static GC clear_gc = NULL;

static GC latex_gc = NULL;

static GC foot_gc = NULL;

static GC math_gc = NULL;

static GC math_frame_gc = NULL;

static GC fill_gc = NULL;

static GC copy_gc = NULL;

static GC select_gc = NULL;

static GC on_off_line_gc = NULL;

static GC thin_on_off_line_gc = NULL;

static GC thick_line_gc = NULL;

static GC lighted_gc = NULL;

static GC inset_gc = NULL;


void SetZoom(char new_zoom)
{
   int i1,i2,i3,i4;
   /* unload all fonts */ 
   for (i1=0; i1<3; i1++) {
      for (i2=0; i2<2; i2++) {
	 for (i3=0; i3<2; i3++) {
	    for (i4=0; i4<8; i4++) {
	       if (fontstruct[i1][i2][i3][i4]) {
		  XUnloadFont(fl_display, fontstruct[i1][i2][i3][i4]->fid);
		  fontstruct[i1][i2][i3][i4] = NULL;
	       }
	    }
	 }
      }
      // do not forget the symbol fonts:
      for (i4=0; i4<8; i4++) {
	if (symbol_fontstruct[i4]) {
	  XUnloadFont(fl_display, symbol_fontstruct[i4]->fid);
	  symbol_fontstruct[i4] = NULL;
	}
      }
      zoom = new_zoom; 
   }
}


char GetZoom()
{
   return zoom;
}


LyXFont GetLyXFont(char family, char series, char shape,
		   char size, char latex, char bar)
{
   static LyXFont tmp;
   tmp.family = family;
   tmp.series = series;
   tmp.shape = shape;
   tmp.size = size;
   tmp.latex = latex;
   tmp.bar = bar;
   return tmp;
}


static XFontStruct* GetXFontstruct(LyXFont font)
{
  // special code for symbols. 
  if (font.family == LYX_SYMBOL_FAMILY)
    return symbol_fontstruct[font.size];
  else
    return fontstruct[font.family][font.series][font.shape][font.size];
}


static void LoadFont(LyXFont font)
{
   char* string = NULL;
   char* family = NULL;
   char* series = NULL;
   char* shape = NULL;
   char size;
   float tmpfloat1;
   float tmpfloat2;
   float tmpfloat3;

   // we are going to perform a number of blocking actions now so:
   XFlush(fl_get_display()); // to be on the safe side
   
   if (font.family == LYX_SYMBOL_FAMILY){
     // special code for the symbol family: only the size counts
     // Matthias 260496
     if (!symbol_fontstruct[font.size]){
       minibuffer.Store();
       minibuffer.Set("Loading fonts into X-Server..."); 
       // load the appropriate symbol font
       string = new char[100];
       tmpfloat1 = zoom;
       tmpfloat2 = font_sizes[LYX_SIZE_NORMAL];
       tmpfloat3 = font_sizes[font.size];
       size = (char) (tmpfloat3 * tmpfloat1 / tmpfloat2);
       sprintf(string, "-*-symbol-*-*-*-*-%d-*-*-*-*-*-*-*", size);
       symbol_fontstruct[font.size] =
	 XLoadQueryFont(fl_display, 
			string);
       if (!symbol_fontstruct[font.size]){
	 fprintf(stderr, "Couldn't load symbol font in size %d \n", size); 
	 fprintf(stderr, "Using fixed... \n");
	 symbol_fontstruct[font.size] =
	   XLoadQueryFont(fl_display, "fixed");
       }
       delete string;
     }
     minibuffer.Reset();
     return;
   }
   
   /* is the questioned font already loaded */
   if (!fontstruct[font.family][font.series][font.shape][font.size ]){
       minibuffer.Store();
       minibuffer.Set("Loading fonts into X-Server..."); 
      /* create the font name */ 
      string = new char[100];
      switch (font.family) {
       case LYX_SANS_FAMILY: family = sans_font_name; break;
       case LYX_TYPEWRITER_FAMILY: family = typewriter_font_name; break;
       default: family = roman_font_name; break;
      }
      switch (font.series) {
       case LYX_BOLD_SERIES: series = "bold"; break;
       default: series = "medium"; break;
      }
      switch (font.shape) {
       case LYX_ITALIC_SHAPE: shape = "i"; break;
       default: shape = "r"; break;
      }
      tmpfloat1 = zoom;
      tmpfloat2 = font_sizes[LYX_SIZE_NORMAL];
      tmpfloat3 = font_sizes[font.size];
      size = (char) (tmpfloat3 * tmpfloat1 / tmpfloat2);
      sprintf(string, "%s-%s-%s-normal-*-%d-*-*-*-*-*-%s",
	      family, series, shape, size, font_norm);
      fontstruct[font.family][font.series][font.shape][font.size] =
      XLoadQueryFont(fl_display, 
		     string);
      
      /* if we cannot get the roman font , we try times */ 
      if (!fontstruct[font.family][font.series][font.shape][font.size] 
	  && font.family == LYX_ROMAN_FAMILY) {
	fprintf(stderr, "Couldn't load font: %s \n", string); 
	fprintf(stderr, "Trying times... \n");
	sprintf(string, "-*-times-%s-%s-normal-*-%d-*-*-*-*-*-%s",
		series, shape, size, font_norm);
	fontstruct[font.family][font.series][font.shape][font.size] =
	  XLoadQueryFont(fl_display, 
			 string);
	/* if we cannot get italic, we use slanted */ 
	if (!fontstruct[font.family][font.series][font.shape][font.size] 
	    && font.shape == LYX_ITALIC_SHAPE) {
	  shape = "o";
	  sprintf(string, "%s-%s-%s-normal-*-%d-*-*-*-*-*-%s",
		  family, series, shape, size, font_norm);
	  fontstruct[font.family][font.series][font.shape][font.size] =
	    XLoadQueryFont(fl_display, 
			   string);
	}
      }
      /* if we cannot get italic, we use slanted */ 
      else if (!fontstruct[font.family][font.series][font.shape][font.size] 
	       && font.shape == LYX_ITALIC_SHAPE) {
	shape = "o";
	sprintf(string, "%s-%s-%s-normal-*-%d-*-*-*-*-*-%s",
		family, series, shape, size, font_norm);
	fontstruct[font.family][font.series][font.shape][font.size] =
	  XLoadQueryFont(fl_display, 
			 string);
      }
      
      /* did we get the font really? */ 
      if (!fontstruct[font.family][font.series][font.shape][font.size] ) {
	fprintf(stderr, "Couldn't load font: %s \n", string); 
	fprintf(stderr, "Using fixed... \n");
	fontstruct[font.family][font.series][font.shape][font.size] =
	  XLoadQueryFont(fl_display, "fixed");
      }
      delete string;
      minibuffer.Reset();
   }
}


GC LyXGetMathGC()
{
   XGCValues val;
   XColor xcol;
   if (!math_gc) {
      if (reverse_video) {
         val.foreground=WhitePixel(fl_display, DefaultScreen(fl_display));
         val.background=BlackPixel(fl_display, DefaultScreen(fl_display));
      } else {
         val.foreground=BlackPixel(fl_display, DefaultScreen(fl_display));
         val.background=WhitePixel(fl_display, DefaultScreen(fl_display));
      }
      val.function=GXcopy;
      val.graphics_exposures = False;
      if (!color_map) {
	 color_map = DefaultColormap(fl_display,
				     DefaultScreen(fl_display));
      }
      if (!mono_video &&
	  XParseColor(fl_display, 
		      color_map, 
		      math_color,
		      &xcol)
	  && XAllocColor(fl_display, color_map, &xcol))
      {
	  val.foreground = xcol.pixel;
      }
      math_gc = XCreateGC(fl_display, RootWindow(fl_display, 0), GCBackground | GCForeground | GCFunction | GCGraphicsExposures, &val);
   
   }
   return math_gc;
}


GC LyXGetLatexGC()
{
   XGCValues val;
   XColor xcol;
   if (!latex_gc) {
      if (reverse_video ^ mono_video) {
         val.foreground=WhitePixel(fl_display, DefaultScreen(fl_display));
         val.background=BlackPixel(fl_display, DefaultScreen(fl_display));
      } else {
         val.foreground=BlackPixel(fl_display, DefaultScreen(fl_display));
         val.background=WhitePixel(fl_display, DefaultScreen(fl_display));
      }
      val.function=GXcopy;
      val.graphics_exposures = False;
      if (!color_map) {
	 color_map = DefaultColormap(fl_display,
				     DefaultScreen(fl_display));
      }
      if (!mono_video &&
	  XParseColor(fl_display, 
		      color_map, 
		      latex_color,
		      &xcol)
	  && XAllocColor(fl_display, color_map, &xcol))
      {
	  val.foreground = xcol.pixel;
      }
      latex_gc = XCreateGC(fl_display, RootWindow(fl_display, 0), GCBackground | GCForeground | GCFunction | GCGraphicsExposures, &val);
   
   }
   return latex_gc;
}


GC LyXGetFootGC()
{
   XGCValues val;
   XColor xcol;
   if (!foot_gc) {
      if (reverse_video) {
         val.foreground=WhitePixel(fl_display, DefaultScreen(fl_display));
         val.background=BlackPixel(fl_display, DefaultScreen(fl_display));
      } else {
         val.foreground=BlackPixel(fl_display, DefaultScreen(fl_display));
         val.background=WhitePixel(fl_display, DefaultScreen(fl_display));
      }
      val.function=GXcopy;
      val.graphics_exposures = False;
      if (!color_map) {
	 color_map = DefaultColormap(fl_display,
				     DefaultScreen(fl_display));
      }
      if (!mono_video &&
	  XParseColor(fl_display, 
		      color_map, 
		      foot_color,
		      &xcol)
	  && XAllocColor(fl_display, color_map, &xcol))
      {
	  val.foreground = xcol.pixel;
      }
      foot_gc = XCreateGC(fl_display, RootWindow(fl_display, 0), GCBackground | GCForeground | GCFunction | GCGraphicsExposures, &val);
   
   }
   return foot_gc;
}


GC LyXGetMathFrameGC()
{
   XGCValues val;
   XColor xcol;
   if (!math_frame_gc) {
      if (reverse_video) {
         val.foreground=WhitePixel(fl_display, DefaultScreen(fl_display));
         val.background=BlackPixel(fl_display, DefaultScreen(fl_display));
      } else {
	 val.foreground=BlackPixel(fl_display, DefaultScreen(fl_display));
	 val.background=WhitePixel(fl_display, DefaultScreen(fl_display));
      }
      val.function=GXcopy;
      val.graphics_exposures = False;
      if (!color_map) {
	 color_map = DefaultColormap(fl_display,
				     DefaultScreen(fl_display));
      }
      if (!mono_video &&
	  XParseColor(fl_display, 
		      color_map, 
		      math_frame_color,
		      &xcol)
	  && XAllocColor(fl_display, color_map, &xcol))
	{
	   val.foreground = xcol.pixel;
	}
      math_frame_gc = XCreateGC(fl_display, RootWindow(fl_display, 0), GCBackground | GCForeground | GCFunction | GCGraphicsExposures, &val);
   
   }
   return math_frame_gc;
}

 
GC LyXGetFillGC()
{
   XGCValues val;
   XColor xcol;
   if (!fill_gc) {
      if (reverse_video) {
         val.foreground=WhitePixel(fl_display, DefaultScreen(fl_display));
         val.background=BlackPixel(fl_display, DefaultScreen(fl_display));
      } else {
	 val.foreground=BlackPixel(fl_display, DefaultScreen(fl_display));
	 val.background=WhitePixel(fl_display, DefaultScreen(fl_display));
      }
      val.function=GXcopy;
      val.graphics_exposures = False;
      if (!color_map) {
	 color_map = DefaultColormap(fl_display,
				     DefaultScreen(fl_display));
      }
      if (!mono_video &&
	  XParseColor(fl_display, 
		      color_map, 
		      fill_color,
		      &xcol)
	  && XAllocColor(fl_display, color_map, &xcol))
	{
	   val.foreground = xcol.pixel;
	}
      fill_gc = XCreateGC(fl_display, RootWindow(fl_display, 0), GCBackground | GCForeground | GCFunction | GCGraphicsExposures, &val);
   
   }
   return fill_gc;
}

 
GC LyXGetClearGC()
{
   XGCValues val;
   if (!clear_gc) {
      if (reverse_video) {
         val.foreground=BlackPixel(fl_display, DefaultScreen(fl_display));
         val.background=WhitePixel(fl_display, DefaultScreen(fl_display));
      } else {
	 val.background=BlackPixel(fl_display, DefaultScreen(fl_display));
	 val.foreground=WhitePixel(fl_display, DefaultScreen(fl_display));
      }
      val.function=GXcopy;
      val.graphics_exposures = False;
      clear_gc = XCreateGC(fl_display, RootWindow(fl_display, 0), GCBackground | GCForeground | GCFunction | GCGraphicsExposures, &val);
   }
   return clear_gc;
}


GC LyXGetOnOffLineGC()
{
   XGCValues val;
   XColor xcol;
   if (!on_off_line_gc) {
      if (reverse_video) {
         val.foreground=WhitePixel(fl_display, DefaultScreen(fl_display));
         val.background=BlackPixel(fl_display, DefaultScreen(fl_display));
      } else {
	 val.foreground=BlackPixel(fl_display, DefaultScreen(fl_display));
	 val.background=WhitePixel(fl_display, DefaultScreen(fl_display));
      }
      val.function=GXcopy;
      val.graphics_exposures = False;
      if (!color_map) {
	 color_map = DefaultColormap(fl_display,
				     DefaultScreen(fl_display));
      }
      if (XParseColor(fl_display, 
		      color_map, 
		      on_off_line_color,
		      &xcol)
	  && XAllocColor(fl_display, color_map, &xcol))
	{
	   val.foreground = xcol.pixel;
	}
      val.line_width = 0;
      val.line_style = LineOnOffDash;
      on_off_line_gc = XCreateGC(fl_display, RootWindow(fl_display, 0),GCBackground 
				 | GCForeground | GCFunction | GCGraphicsExposures
				 | GCLineWidth | GCLineStyle , &val);
      
   }
   return on_off_line_gc;
}


GC LyXGetThickLineGC()
{
   XGCValues val;
   if (!thick_line_gc) {
      if (reverse_video) {
         val.foreground=WhitePixel(fl_display, DefaultScreen(fl_display));
         val.background=BlackPixel(fl_display, DefaultScreen(fl_display));
      } else {
	 val.foreground=BlackPixel(fl_display, DefaultScreen(fl_display));
	 val.background=WhitePixel(fl_display, DefaultScreen(fl_display));
      }
      val.function=GXcopy;
      val.graphics_exposures = False;
      val.line_width = 2;
      val.line_style = LineSolid;
      thick_line_gc = XCreateGC(fl_display, RootWindow(fl_display, 0),GCBackground 
			      | GCForeground | GCFunction | GCGraphicsExposures
			      | GCLineWidth | GCLineStyle , &val);
      
   }
   return thick_line_gc;
}


GC LyXGetThinOnOffLineGC()
{
   XGCValues val;
   if (!thin_on_off_line_gc) {
      if (reverse_video) {
         val.foreground=WhitePixel(fl_display, DefaultScreen(fl_display));
         val.background=BlackPixel(fl_display, DefaultScreen(fl_display));
      } else {
	 val.background=WhitePixel(fl_display, DefaultScreen(fl_display));
	 val.foreground=BlackPixel(fl_display, DefaultScreen(fl_display));
      }
     val.function=GXcopy;
     val.graphics_exposures = False;
     val.line_style = LineOnOffDash;
     val.line_width = 0;
     thin_on_off_line_gc =
	     XCreateGC(fl_display, RootWindow(fl_display, 0), GCBackground
		       | GCForeground | GCFunction | GCGraphicsExposures
		       | GCLineWidth | GCLineStyle , &val);
   }
   return thin_on_off_line_gc;
}


GC LyXGetCopyGC()
{
   XGCValues val;
   if (!copy_gc) {
      if (reverse_video) {
         val.foreground=WhitePixel(fl_display, DefaultScreen(fl_display));
         val.background=BlackPixel(fl_display, DefaultScreen(fl_display));
      } else {
	 val.background=WhitePixel(fl_display, DefaultScreen(fl_display));
	 val.foreground=BlackPixel(fl_display, DefaultScreen(fl_display));
      }
      val.function=GXcopy;
      val.graphics_exposures = False;
      val.line_style = LineSolid;
      val.line_width = 0;
      copy_gc = XCreateGC(fl_display, RootWindow(fl_display, 0), GCBackground
			| GCForeground | GCFunction | GCGraphicsExposures
			| GCLineWidth | GCLineStyle , &val);
   }
   return copy_gc;
}


GC LyXGetSelectGC()
{
   XGCValues val;
   if (!select_gc) {
      unsigned int a = BlackPixel(fl_display, DefaultScreen(fl_display));
      unsigned int b = WhitePixel(fl_display, DefaultScreen(fl_display)); 
      val.plane_mask = a^b;
      val.line_style = LineSolid;
      val.line_width = 2;
      val.graphics_exposures = False;
      val.function=GXinvert;
      select_gc = XCreateGC(fl_display, RootWindow(fl_display, 0),
			  GCFunction | GCGraphicsExposures | GCPlaneMask
			  | GCLineWidth | GCLineStyle , &val);

   }
   return select_gc; 
}


GC LyXGetLightedGC()
{
	XGCValues val;
	XColor xcol;
   if (!lighted_gc) {
      if (reverse_video ^ mono_video) {
         val.background=BlackPixel(fl_display, DefaultScreen(fl_display));
      } else {
	 val.background=WhitePixel(fl_display, DefaultScreen(fl_display));
      }
      val.foreground=val.background;
      val.function=GXcopy;
      val.graphics_exposures = False;
      val.line_style = LineSolid;
      val.line_width = 0;

      if (!color_map) color_map = DefaultColormap(fl_display,
						  DefaultScreen(fl_display));
      
      if (!mono_video &&
	  XParseColor(fl_display, 
		      color_map, 
		      lighted_color,
		      &xcol)
	  && XAllocColor(fl_display, color_map, &xcol))
	{
	  val.foreground = xcol.pixel;
	} 
      
      
      lighted_gc = XCreateGC(fl_display, RootWindow(fl_display, 0), GCBackground
			   | GCForeground | GCFunction | GCGraphicsExposures
			   | GCLineWidth | GCLineStyle , &val);
   }
   return lighted_gc;
}


GC LyXGetInsetGC()
{
 XGCValues val;
 XColor xcol;
   if (!inset_gc) {
      if (reverse_video) {
         val.background=BlackPixel(fl_display, DefaultScreen(fl_display));
      } else {
	 val.background=WhitePixel(fl_display, DefaultScreen(fl_display));
      }
      val.foreground=val.background;
      val.graphics_exposures = False;
      val.function=GXcopy;
      val.line_style = LineSolid;
      val.line_width = 0;

      if (!color_map) color_map = DefaultColormap(fl_display,
						  DefaultScreen(fl_display));
      
      if (XParseColor(fl_display, 
		      color_map, 
		      inset_color,
		      &xcol)
	  
	  && XAllocColor(fl_display, color_map, &xcol))
	{
	  val.foreground = xcol.pixel;
	} 
      
      inset_gc = XCreateGC(fl_display, RootWindow(fl_display, 0), GCBackground
			   | GCForeground | GCFunction | GCGraphicsExposures
			   | GCLineWidth | GCLineStyle , &val);
   }
   return inset_gc;
}


GC LyXGetGC(LyXFont font)
{
   LoadFont(font);
   GC gc;
   if (font.latex == LYX_NO_LATEX)
      gc = LyXGetCopyGC();
   else if (font.latex == LYX_FORMULA_LATEX)
      gc = LyXGetMathGC();
   else
      gc = LyXGetLatexGC();
   
     XSetFont(fl_display, gc, GetXFontstruct(font)->fid);
   return gc;
}


int LyXMaxAscent(LyXFont font)
{
   return LyXAscent(font, 'f');
}


int LyXMaxDescent(LyXFont font)
{
   return LyXDescent(font, 'g');
}


int LyXAscent(LyXFont font, char c)
{
   unsigned int index;
   XFontStruct *finfo;
   LoadFont(font);
   finfo = GetXFontstruct(font);
   if (finfo->per_char
       && (unsigned int) c >= finfo->min_char_or_byte2
       && (unsigned int) c <= finfo->max_char_or_byte2) {
	  index = (unsigned int) c - finfo->min_char_or_byte2;
	  return finfo->per_char[index].ascent;
       }
   else
     return LyXMaxAscent(font);
}


int LyXDescent(LyXFont font, char c)
{
   unsigned int index;
   XFontStruct *finfo;
   LoadFont(font);
   finfo = GetXFontstruct(font);
   if (finfo->per_char
       && (unsigned int) c >= finfo->min_char_or_byte2
       && (unsigned int) c <= finfo->max_char_or_byte2) {
	  index = (unsigned int) c - finfo->min_char_or_byte2;
	  return finfo->per_char[index].descent;
       }
   else
     return LyXMaxDescent(font);
}


int LyXWidth(LyXFont font, char c)
{
   return LyXTextWidth(font, &c, 1);
}


int LyXTextWidth(LyXFont font, char*s, int n)
{
  LoadFont(font);
  if (font.shape != LYX_SMALLCAPS_SHAPE){
    return XTextWidth(GetXFontstruct(font), s, n);
  }
  else
    {
      // emulate xmallcaps since X doesn't support this
      int i;
      int result = 0;
      char c;
      LyXFont smallfont = font;
      if (smallfont.size > LYX_SIZE_TINY)
	smallfont.size--;
      smallfont.shape = LYX_UP_SHAPE;
      LoadFont(smallfont);
      for (i=0; i < n; i++){
	c = s[i];
	if (islower(c)){
	  c = toupper(c);
	  result += XTextWidth(GetXFontstruct(smallfont), &c, 1);
	}
	else
	  result += XTextWidth(GetXFontstruct(font), &c, 1);
      }
      return result;
    }
}


int LyXStringWidth(LyXFont font, char *s)
{
   int n = 0;
   while (s[n])			       /* get the length of the string  */
     n++;
   return LyXTextWidth((font), s, n);
}


void LyXDrawText(LyXFont font, char* s, int n, Pixmap pm, int baseline, int x) {
  LoadFont(font);
  if (font.shape != LYX_SMALLCAPS_SHAPE){
    XDrawString(fl_display,
		pm,
		LyXGetGC(font),
		x, baseline,
		s, n);
  }
  else
    {
      // emulate xmallcaps since X doesn't support this
      int i;
      char c;
      LyXFont smallfont = font;
      if (smallfont.size > LYX_SIZE_TINY)
	smallfont.size--;
      smallfont.shape = LYX_UP_SHAPE;
      LoadFont(smallfont);
      for (i=0; i < n; i++){
	c = s[i];
	if (islower(c)){
	  c = toupper(c);
	  XDrawString(fl_display,
		      pm,
		      LyXGetGC(smallfont),
		      x, baseline,
		      &c, 1);
	  x += XTextWidth(GetXFontstruct(smallfont), &c, 1);
    	}
	else {
	  XDrawString(fl_display,
		      pm,
		      LyXGetGC(font),
		      x, baseline,
		      &c, 1);
	  x += XTextWidth(GetXFontstruct(font), &c, 1);
	}
      }
    }
}


void LyXDrawString(LyXFont font, char* s, Pixmap pm, int baseline, int x) {
   int n = 0;
   while (s[n])			       /* get the length of the string  */
     n++;
   LyXDrawText(font, s, n, pm, baseline, x);
}

