/*
 * gmemusage.c
 * main file for gmemusage
 *
 * Copyright (C) 1997, 1998 by Raju Mathur (raju@sgi.com)
 * Some portions based on O'Reilly and Associates' Xlib Programming tutorial
 * examples.
 *
 * See file COPYING (included in this distribution) for copyright information.
 *
 * Xemacs configuration for this indentation:
 * (add-hook 'c-mode-common-hook
 *	  '(lambda ()
 *	     (c-set-style "ellemtel")
 *	     (c-set-offset 'topmost-intro-cont '+)
 *	     (c-set-offset 'topmost-intro '-)
 *	     (c-set-offset 'case-label '*)
 *	     (c-set-offset 'statement-case-intro '*)))
 *
 * Version 0.2, 980114
 */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>

#include "memusage.xbm"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <malloc.h>

#include "common.h"
#include "defaults.h"

#define BITMAPDEPTH 1

#define TOO_SMALL	0
#define	BIG_ENOUGH	1
/*
 * I hate these file-wide variables, but since draw_window is going to be
 * called from a signal, we can't pass it any args.
 */
static Display
   *display ;
static int
   screen_num ;
char
   progname [128] ,		/* other functions need to access this one */
   *version = "0.1" ;		/* and this one */
static Window
   win ;
#ifndef SAVE_XSERVER_MEMORY
static Pixmap
   pxm;
#endif
static int
   window_width ,
   window_height ;
static int
   nColors ;
static int
   Threshhold = -1 ;
static XColor
   Foreground ,
   Background ;
static XFontStruct
   *font_info ;
static int
   Exposed = 0 ;
/*
 * Is this the right way to have (e.g.) 16 colors? 16 different GC's with
 * a different foreground?
 */
static GC
   gc [MaxColors] ;
static GC
   blackGC;
/*
 * Protos.
 */
void getGCs ( Window win , Colormap cmap ) ;
#if 0
void place_text ( Window win , GC gc , XFontStruct *font_info ,
		  unsigned int win_width , unsigned int win_height ) ;
void place_graphics ( Window win , GC gc , unsigned int window_width ,
		 unsigned int window_height ) ;
#endif
void draw_window ( void ) ;
void TooSmall ( Window win , GC gc , XFontStruct *font_into ) ;

void main ( int argc , char **argv )
{
   int
      default_height ,
      default_width ,
      default_x ,
      default_y ;
   int
      x = 0 ,
      y = 0 ,
      width ,
      height ;
   unsigned int
      border_width = 4 ,
      display_width ,
      display_height ;
   char
      *window_name = "gmemusage" ,
      *icon_name = "gmemusage" ;
   Pixmap
      icon_pixmap ;
   XSizeHints
      *size_hints ;
   XEvent
      report ;
   int
      screen_num ;
   Screen
      *screen_ptr ;
   XWMHints
      *wm_hints ;
   XClassHint
      *class_hints ;
   XTextProperty
      windowName ,
      iconName ;
   Colormap
      cmap ;
/*
 * Remove leading dir.../ from argv[0] and store in progname
 */
   if ( strrchr ( argv [0] , '/' ) )
   {
      strcpy ( progname , strrchr ( argv [0] , '/' ) + 1 ) ;
   }
   else
   {
      strcpy ( progname , argv [0] ) ;
   }
/*
 * Allocate necessaru X structures for later use. Apparently this needs to
 * be done before any other X stuff.
 */
   if ( !( size_hints = XAllocSizeHints () ) )
   {
      fprintf ( stderr , "%s: failure allocating SizeHints\n" , progname ) ;
      exit ( 1 ) ;
   }
   if ( !( wm_hints = XAllocWMHints () ) )
   {
      fprintf ( stderr , "%s: failure allocating WMHints\n" , progname ) ;
      exit ( 1 ) ;
   }
   if ( !( class_hints = XAllocClassHint () ) )
   {
      fprintf ( stderr , "%s: failure allocating ClassHints\n" , progname ) ;
      exit ( 1 ) ;
   }
/*
 * Figure out resources from the command-line and screen resources.
 */
   GetInitialResources ( &argc , argv ) ;
   if ( ( display = XOpenDisplay ( dDisplay ) ) == NULL )
   {
      (void) fprintf ( stderr , "%s: cannot connect to X server %s\n" ,
		       progname , XDisplayName ( dDisplay ) ) ;
      exit ( 1 ) ;
   }
   GetResources ( display , argc , argv ) ;
   XParseGeometry ( dGeometry , &default_x , &default_y , &default_width ,
		    &default_height ) ;
   
   screen_num = DefaultScreen ( display ) ;
   screen_ptr = DefaultScreenOfDisplay ( display ) ;

   display_width = DisplayWidth ( display , screen_num ) ;
   display_height = DisplayHeight ( display , screen_num ) ;
/*
 * Get foreground and background colors for the window
 */
   cmap = DefaultColormap ( display , DefaultScreen ( display ) ) ;
   if (!XParseColor ( display , cmap , dForeground , &Foreground ) )
   {
      fprintf ( stderr , "%s: Cannot parse color %s\n" , progname ,
		dForeground ) ;
      Foreground . pixel = BlackPixel ( display , screen_num ) ;
   }
   else
   {
      XAllocColor ( display , cmap , &Foreground ) ;
   }
   if (!XParseColor ( display , cmap , dBackground , &Background ) )
   {
      fprintf ( stderr , "%s: Cannot parse color %s\n" , progname ,
		dBackground ) ;
      Background . pixel = WhitePixel ( display , screen_num ) ;
   }
   else
   {
      XAllocColor ( display , cmap , &Background ) ;
   }
   width = default_width ;
   height = default_height ;
   win = XCreateSimpleWindow (
      display ,
      RootWindow ( display , screen_num ) ,
      x ,
      y ,
      width ,
      height ,
      border_width ,
      Foreground . pixel ,
      Background . pixel ) ;
#ifndef SAVE_XSERVER_MEMORY
   pxm = XCreatePixmap (
      display ,
      win ,
      width ,
      height ,
      DefaultDepth ( display , screen_num ) );
#endif
   icon_pixmap = XCreateBitmapFromData ( display , win , memusage_bits ,
					 memusage_width , memusage_height ) ;
   size_hints -> flags = PPosition | PSize | PMinSize ;
   size_hints -> min_width = default_width ;
   size_hints -> min_height = default_height ;
   if ( XStringListToTextProperty (&window_name , 1 , &windowName ) == 0 )
   {
      fprintf ( stderr , "%s: struct allocation for windowName failed\n" ,
		progname ) ;
      exit ( 1 ) ;
   }
   if ( XStringListToTextProperty ( &icon_name , 1 , &iconName ) == 0 )
   {
      fprintf ( stderr , "%s: struct allocation for iconName failed\n" ,
		progname ) ;
      exit ( 1 ) ;
   }
   wm_hints -> initial_state = NormalState ;
   wm_hints -> input = True ;
   wm_hints -> icon_pixmap = icon_pixmap ;
   wm_hints -> flags = StateHint | IconPixmapHint | InputHint ;
   class_hints -> res_name = progname ;
   class_hints -> res_class = "BasicWin" ;
   XSetWMProperties ( display , win , &windowName , &iconName , argv , argc ,
		      size_hints , wm_hints , class_hints ) ;

   XSelectInput ( display , win , ExposureMask | KeyPressMask | ButtonPressMask
		  | StructureNotifyMask ) ;

   getGCs ( win , cmap ) ;

   XMapWindow ( display , win ) ;

   while ( 1 )
   {
      XNextEvent ( display , &report ) ;
      switch ( report . type )
      {
	 char
	    keybuf [10] ;
	 KeySym
	    keysym ;
	 int
	    count ;
	 XComposeStatus
	    composestatus ;

       case Expose:
	if ( report . xexpose . count != 0 )
	{
	   break ;
	}
#if 0
	printf("Expose %d %d %d %d\n",report.xexpose.x,report.xexpose.y,report.xexpose.width,report.xexpose.height);
#endif
#if 0
	if ( window_size == TOO_SMALL )
	{
	   TooSmall ( win , gc , font_info ) ;
	}
	else
#endif
	{
	   Exposed = 1 ;
	   draw_window () ;
	}
	break ;

       case ConfigureNotify:
	window_width = report . xconfigure . width ;
	window_height = report . xconfigure . height ;
#ifndef SAVE_XSERVER_MEMORY
        XFreePixmap ( display , pxm );
        pxm = XCreatePixmap (
           display ,
           win ,
           window_width ,
           window_height ,
           DefaultDepth ( display , screen_num ) );
#endif
#if 0
	if ( window_width < size_hints -> min_width
	     || window_height < size_hints -> min_height )
	{
	   window_size = TOO_SMALL ;
	}
	else
	{
	   window_size = BIG_ENOUGH ;
	}
#endif
	break ;

       case ButtonPress:	/* ignore buttons for now */
	XBell ( display , 10 ) ;
	break ;

       case KeyPress:
	count = XLookupString ( &report . xkey , keybuf ,
				sizeof ( keybuf ) ,
				&keysym , &composestatus ) ;
	if ( ( keysym >= XK_KP_Space && keysym <= XK_KP_9 )
	     || ( keysym >= XK_space && keysym <= XK_asciitilde ) )
	{
	   register int
	      i ;
	   for ( i = 0 ; keybuf [i] ; i++ )
	   {
	      switch ( keybuf [i] )
	      {
		 register int
		    j ;
	       case 'q':
	       case 'Q':
		XUnloadFont ( display , font_info -> fid ) ;
		for ( j = 0 ; j < nColors ; j++ )
		{
		   XFreeGC ( display , gc [j] ) ;
		}
		XCloseDisplay ( display ) ;
		exit ( 0 ) ;

	       default:
		XBell ( display , 10 ) ;
		break ;
	      }
	   }
	}
	else
	{
	   switch ( keysym )
	   {
	    case XK_Up:
	     Threshhold += ThreshholdDelta ;
	     break ;

	    case XK_Down:
	     Threshhold -= ThreshholdDelta ;
	     if ( Threshhold < ThreshholdDelta )
	     {
		XBell ( display , 0 ) ;
		Threshhold = ThreshholdDelta ;
	     }
	     break ;

	    default:
#ifdef BELL_ON_UNKNOWN_KEYPRESS
	     XBell ( display , 10 ) ;
#endif
	     break ;
	   }
	}
	break ;

       default:
#if 0
	fprintf ( stderr , "%s: Unknown event: %d\n" , progname ,
		  report . type ) ;
#endif
	break ;
      }
   }
   exit ( 0 ) ;
}
/*
 * Do all the drawing.
 */
void draw_window ( void )
{
   int
      pcWidth ,
      pcHeight ,
      pixelWidth ,
      pixelHeight ;
#ifdef SAVE_XSERVER_MEMORY
   Pixmap
      pxm;
#endif
   struct XProcInfo
   {
      struct ProcInfo
	 *pi ;
      int
	 pixelHeight ,
	 base ,
	 midpoint ;
   } ;
   register int
      i ;
   static int
      nprocs ;
   static int
      oldThreshhold ;
   int
      oldnprocs ;
   register struct XProcInfo
      *this ;
   static struct ProcInfo
      *pi ;
   static struct XProcInfo
      *xpi ,
      *oldxpi ;
   int
      alarmsecs ;
   static int
      done = 0 ;
   int
      basex ,
      basey ;
#if 0
   int
      temp1 ;
#endif
   GC
      *thisGC ;
   int
      thxpi = -1 ;
   struct ProcInfo
      thProc ;
   int
      labelNumber = 0 ,
      nLabels = 0 ;
   int
      longestLabel = 0 ;
/*
 * No alarms while we're here.
 */
   (void) signal ( SIGALRM , SIG_IGN ) ;
/*
 * See if we're being called due to an alarm, and schedule the next alarm.
 * If the alarm is pending, we can reuse the old data rather than calling
 * AllProcs again.
 */
   if ( alarmsecs = alarm ( dUpdate ) && done )
   {
/*
 * if the alarm didn't go off, we don't need to recalc everything.
 */
#if 0
      printf("called from expose\n");
#endif
      alarm ( alarmsecs ) ;
   }
   else
   {
/*
 * Get the process info
 */
#if 0
      printf("called from alarm\n");
#endif
      oldxpi = xpi ;
      oldnprocs = nprocs ;
      makeProcs () ;
      pi = AllProcs ( &nprocs ) ;
      done = 1 ;
   }
/*
 * Calculate width of memory bars as percentage and in pixels.
 */
   pcWidth = 40 ;
   pixelWidth = window_width * pcWidth / 100.0 ;
   pcHeight = 90 ;
   pixelHeight = window_height * pcHeight / 100.0 ;
   basex = DefaultBorder ;
   basey = window_height - ( window_height - pixelHeight ) / 2 - 1 ;
   if ( Threshhold < 0 )
   {
      Threshhold = dThreshhold ;
   }
#if 0
   printf("pcw %d, pw %d, pch %d, ph %d, base %d\n",pcWidth,pixelWidth,pcHeight,pixelHeight,basey);
#endif
/*
 * Go through the array: allocate the ProcInfo pointer, calculate height,
 * base, midpoint for each rectangle.
 */
   if ( ( xpi = calloc ( nprocs , sizeof ( struct XProcInfo ) ) ) == NULL )
   {
      fprintf ( stderr , "%s: calloc struct XProcInfo failed" , progname ) ;
      perror ( "" ) ;
      exit ( 1 ) ;
   }
   this = xpi ;
/*
 * First get the sum of processes less than the threshhold size
 */
   for ( i = 0 ; i < nprocs ; i++ )
   {
      if ( pi [i] . totRSS < Threshhold
	   && strcmp ( pi [i] . procname , kernelname )
	   && strcmp ( pi [i] . procname , freename ) )
      {
	 if ( thxpi < 0 )
	 {
	    thxpi = i ;
	    sprintf ( thProc . procname , "< %d" , Threshhold ) ;
	    thProc . totRSS = pi [i] . totRSS ;
	    thProc . totMem = 0 ;
	    thProc . nProcs = pi [i] . nProcs ;
	    this [i] . pi = &thProc ;
	 }
	 else
	 {
	    this [thxpi] . pi -> nProcs += pi [i] . nProcs ;
	    this [thxpi] . pi -> totRSS += pi [i] . totRSS ;
	 }
      }
   }
#if 0
   temp1=0;
   printf("%d %s %d\n",thxpi,this[thxpi].pi->procname,this[thxpi].pi->totRSS);
#endif
/*
 * Now calculate percentages and sizes for the remaining (large-enough)
 * processes.
 */
   for ( i = 0 ; i < nprocs ; i++ )
   {
      if ( i != thxpi )
      {
	 if ( pi [i] . totRSS < Threshhold )
	 {
	    this [i] . pi = NULL ;
	    continue ;
	 }
	 else
	 {
	    this [i] . pi = &pi [i] ;
	 }
      }
      nLabels++ ;
#if 0
      temp1+=pi[i].totRSS;
      printf("%s %d %d %d\n",this[i].pi->procname,this[i].pi->totMem,this[i].pi->totRSS,temp1);
#endif
      this [i] . pixelHeight = this [i] . pi -> totRSS * pixelHeight / sysmem ;
      basey -= this [i] . pixelHeight ;
      this [i] . base = basey ;
      this [i] . midpoint = basey + this [i] . pixelHeight / 2 ;
      if ( strlen ( this [i] . pi -> procname ) > longestLabel )
      {
	 longestLabel = strlen ( this [i] . pi -> procname ) ;
      }
   }
#if 0				/* Needs much more work */
/*
 * Check if the new values have changed at all from the previous values.
 * If not, just deallocate and return without redrawing.
 */
   if ( oldThreshhold == Threshhold
	&& oldnprocs == nprocs
	&& !memcmp ( xpi , oldxpi , sizeof ( struct XProcInfo ) * nprocs )
	&& !Exposed )
   {
      free ( oldxpi ) ;
      return ;
   }
#endif
/*
 * Make the boxes.
 */
#if 0
   XClearArea ( display , win , 0 , 0 , 0 , 0 , False ) ;
#else
#ifdef SAVE_XSERVER_MEMORY
   pxm = XCreatePixmap (
      display ,
      win ,
      window_width ,
      window_height ,
      DefaultDepth ( display , screen_num ) );
#endif
      XFillRectangle ( display , pxm , blackGC , 0 , 0 ,
		       window_width , window_height ) ;
#endif
#if 0
   printf("%d %d\n",window_height,window_width);
#endif
   labelNumber = 0 ;
   for ( i = 0 ; i < nprocs ; i++ )
   {
      if ( !this [i] . pi )
      {
	 continue ;
      }
      thisGC = &gc [labelNumber % nColors] ;
#if 0
      printf("%d %d %d %d\n",basex,this[i].base,pixelWidth,this[i].pixelHeight);
#endif
      XFillRectangle ( display , pxm , *thisGC , basex , this [i] . base ,
		       pixelWidth , this [i] . pixelHeight ) ;
      labelNumber++ ;
   }
/*
 * Make the lines and the text.
 */
   {
      int
	 lineSpace = window_height / nLabels ,
	 longestLabelWidth ,
	 textXoffset ,
	 fontHeight ;
      char
	 buf [128] ,
	 nprocbuf [10] ;
				/* procname (nnn) : nnnnnK */
      memset ( buf , 'W' , longestLabel + 6 + 2 + 7 ) ;
      longestLabelWidth = XTextWidth ( font_info , buf ,
				       longestLabel + 6 + 2 + 7 ) ;
      textXoffset = window_width - DefaultBorder
	 - longestLabelWidth ;
      fontHeight = font_info -> ascent + font_info -> descent ;
      labelNumber = 0 ;
      for ( i = 0 ; i < nprocs ; i++ )
      {
	 if ( !this [i] . pi )
	 {
	    continue ;
	 }
	 thisGC = &gc [labelNumber % nColors] ;
	 XDrawLine ( display , pxm , *thisGC ,
		     DefaultBorder + pixelWidth ,
		     this [i] . midpoint ,
		     textXoffset - 2 ,
		     window_height
		     - (labelNumber * lineSpace ) - lineSpace / 2 ) ;
	 if ( this [i] . pi -> nProcs > 1 )
	 {
	    sprintf ( nprocbuf , "(%d)" , this [i] . pi -> nProcs ) ;
	 }
	 else
	 {
	    nprocbuf [0] = '\0' ;
	 }
	 sprintf ( buf , "%-*s %6s : %5dK" , longestLabel ,
		   this [i] . pi -> procname , nprocbuf ,
		   this [i] . pi -> totRSS ) ;
#if 0
	 if ( strcmp ( this [i] . pi -> procname , kernelname )
	      && strcmp ( this [i] . pi -> procname , freename ) )
	 {
	    sprintf ( buf , "%s (%d)" , this [i] . pi -> procname ,
		      this [i] . pi -> nProcs ) ;
	 }
	 else
	 {
	    strcpy ( buf , this [i] . pi -> procname ) ;
	 }
#endif
	 XDrawString ( display , pxm , *thisGC ,
		       textXoffset ,
		       window_height - ( labelNumber * lineSpace )
		       - ( lineSpace - fontHeight ) / 2 - 2 ,
		       buf , strlen ( buf ) ) ;
	 labelNumber++ ;
      }
   }
   XCopyArea ( display , pxm , win , blackGC, 0 , 0 , window_width,
      window_height, 0 , 0 );
#ifdef SAVE_XSERVER_MEMORY
   XFreePixmap ( display , pxm );
#endif
   XFlush ( display ) ;
/*
 * Save and clear some of the values.
 */
   oldThreshhold = Threshhold ;
   Exposed = 0 ;
   if ( oldxpi )
   {
      free ( oldxpi ) ;
      oldxpi = NULL ;
   }
/*
 * We can accept alarms again
 */
   (void) signal ( SIGALRM , draw_window ) ;
   return ;
}
   
void
getGCs ( Window win , Colormap cmap )
{
   unsigned long
      valuemask = 0 ;
   XGCValues
      values ;
   unsigned int
      line_width = 0 ;		/* fastest server-dependent line */
   int
      line_style = LineSolid ,
      cap_style = CapRound ,
      join_style = JoinRound ;
   XColor
      rgb ;
   register int
      i ;

   if ( ( font_info =
	  XLoadQueryFont ( display , dFont ) )
	== NULL )
   {
      fprintf ( stderr , "%s: cannot load font %s\n" , progname , dFont ) ;
      exit ( 1 ) ;
   }
   nColors = dnColors ;
   for ( i = 0 ; i < nColors ; i++ )
   {
      if ( dColor [i] [0]
	   && !XParseColor ( display , cmap , dColor [i] , &rgb ) )
      {
	 fprintf ( stderr , "%s: Cannot parse color %s\n" , progname ,
		   dColor [i] ) ;
	 rgb . pixel = BlackPixel ( display , screen_num ) ;
      }
      else
      {
	 XAllocColor ( display , cmap , &rgb ) ;
      }
      gc [i] = XCreateGC ( display , win , valuemask , &values ) ;
      XSetForeground ( display , gc [i] , rgb . pixel ) ;
      XSetFont ( display , gc [i] , font_info -> fid ) ;
      XSetLineAttributes ( display , gc [i] , line_width , line_style ,
			   cap_style , join_style ) ;
   }
   valuemask |= GCPlaneMask;
   values.plane_mask = AllPlanes;
   blackGC = XCreateGC ( display , win , valuemask , &values ) ;
   XSetForeground ( display , blackGC , BlackPixel ( display , screen_num ) ) ;
   return ;
}
#if 0
void
place_text ( Window win , GC gc , XFontStruct *font_info ,
	     unsigned int win_width , unsigned int win_height )
{
   char
      *string1 = "Hi! I'm a window, who are you?" ,
      *string2 = "To terminate program: press any key" ,
      *string3 = "or button while in this window." ,
      *string4 = "Screen Dimensions" ;
   int
      len1 ,
      len2 ,
      len3 ,
      len4 ,
      width1 ,
      width2 ,
      width3 ;
   char
      cd_height[50] ,
      cd_width [50] ,
      cd_depth [50] ;
   int
      font_height ,
      initial_y_offset ,
      x_offset ;

   len1 = strlen ( string1 ) ;
   len2 = strlen ( string2 ) ;
   len3 = strlen ( string3 ) ;
   width1 = XTextWidth ( font_info , string1 , len1 ) ;
   width2 = XTextWidth ( font_info , string2 , len2 ) ;
   width3 = XTextWidth ( font_info , string3 , len3 ) ;
   font_height = font_info -> ascent + font_info -> descent ;

   XDrawString ( display , win , gc , ( win_width - width1 ) / 2 , font_height ,
		 string1 , len1 ) ;
   XDrawString ( display , win , gc , ( win_width - width2 ) / 2 ,
		 win_height - 2 * font_height , string2 , len2 ) ;
   XDrawString ( display , win , gc , ( win_width - width3 ) / 2 ,
		 win_height - 3 * font_height , string3 , len3 ) ;
   sprintf ( cd_height , " Height - %d pixels" ,
	     DisplayHeight ( display , screen_num ) ) ;
   sprintf ( cd_width , " Width  - %d pixels" ,
	     DisplayWidth ( display , screen_num ) ) ;
   sprintf ( cd_depth , " Depth  - %d planes" ,
	     DefaultDepth ( display , screen_num ) ) ;
   len4 = strlen ( string4 ) ;
   len1 = strlen ( cd_height ) ;
   len2 = strlen ( cd_width ) ;
   len3 = strlen ( cd_depth ) ;
   initial_y_offset = win_height / 2 - font_height - font_info -> descent ;
   x_offset = win_width / 4 ;
   XDrawString ( display , win , gc , x_offset , initial_y_offset , string4 ,
		 len4 ) ;
   XDrawString ( display , win , gc , x_offset ,
		 initial_y_offset + font_height , cd_height , len1 ) ;
   XDrawString ( display , win , gc , x_offset ,
		 initial_y_offset + 2 * font_height , cd_width , len2 ) ;
   XDrawString ( display , win , gc , x_offset ,
		 initial_y_offset + 3 * font_height , cd_depth , len3 ) ;
}

void
place_graphics ( Window win , GC gc , unsigned int window_width ,
		 unsigned int window_height )
{
   int
      x ,
      y ,
      width ,
      height ;

   height = window_height / 2 ;
   width = 3 * window_width / 4 ;
   x = window_width / 2 - width / 2 ;
   y = window_height / 2 - height / 2 ;
   XDrawRectangle ( display , win , gc , x , y , width , height ) ;
}

void
TooSmall ( Window win , GC gc , XFontStruct *font_info )
{
   char
      *string1 = "Too Small" ;
   int
      x_offset ,
      y_offset ;

   y_offset = font_info -> ascent + 2 ;
   x_offset = 2 ;
   XDrawString ( display , win , gc , x_offset , y_offset , string1 ,
		 strlen ( string1 ) ) ;
}
#endif
