/*******************************************************************
 FILE:		Lcd.c
 CONTENTS:	Definitions for structures, methods, and actions of the 
		Lcd widget.
 AUTHOR:	Paul D. Johnston
 HISTORY:
 Date		Action
 ---------	------------------------------------
 5/23/92	Changed the widget class name so that it is preceded
		by 'xc' with the first major word capitalized.
 5/19/91	Added range checking to the callback processing and the
		XcLcdUpdateValue function.
 4/04/92	Created.

********************************************************************/

#include <stdio.h>

/* Xlib includes */
#include <X11/Xlib.h>

/* Xt includes */
#include <X11/StringDefs.h>
#include <X11/IntrinsicP.h>


/* Widget includes */
#include <X11/Xc/Xc.h>
#include <X11/Xc/Control.h>
#include <X11/Xc/Value.h>
#include <X11/Xc/LcdP.h>	/* (includes Lcd.h also) */


/* Dimensions of the initial segment map */
#define SEG_MAP_WIDTH		10
#define SEG_MAP_HEIGHT		15


/* Quantity of character set supported by the LCD segment display. */
#define CHAR_TABLE_SIZE		19

/* Define T and F to simplify the character table entry */
#define T	True
#define F	False

/* Index into the segment map where the '.' period segment is. */
#define PERIOD_INDEX		8

/* Macro redefinition for offset. */
#define offset(field) XtOffset(LcdWidget, field)


/* Declare widget methods */
static void Initialize();
static void Redisplay();
static void Destroy();
static void Resize();
static XtGeometryResult QueryGeometry();
static Boolean SetValues();


/* Declare functions and variables private to this widget */
static void Draw_display();
static void Get_value();



/* Define the widget's resource list */
static XtResource resources[] =
{
  {
    XcNvalueLength,
    XcCValueLength,
    XtRInt,
    sizeof(int),
    offset(lcd.value_length),
    XtRImmediate,
    (XtPointer)12
  },
  {
    XcNinterval,
    XcCInterval,
    XtRInt,
    sizeof(int),
    offset(lcd.interval),
    XtRImmediate,
    (XtPointer)0
  },
  {
    XcNupdateCallback,
    XtCCallback,
    XtRCallback,
    sizeof(caddr_t),
    offset(lcd.update_callback),
    XtRCallback,
    NULL
  },
};



/* Widget Class Record initialization */
LcdClassRec lcdClassRec =
{
  {
  /* core_class part */
    (WidgetClass) &valueClassRec,		/* superclass */
    "Lcd",					/* class_name */
    sizeof(LcdRec),				/* widget_size */
    NULL,					/* class_initialize */
    NULL,					/* class_part_initialize */
    FALSE,					/* class_inited */
    Initialize,					/* initialize */
    NULL,					/* initialize_hook */
    XtInheritRealize,				/* realize */
    NULL,					/* actions */
    0,						/* num_actions */
    resources,					/* resources */
    XtNumber(resources),			/* num_resources */
    NULLQUARK,					/* xrm_class */
    TRUE,					/* compress_motion */
    TRUE,					/* compress_exposure */
    TRUE,					/* compress_enterleave */
    TRUE,					/* visible_interest */
    Destroy,					/* destroy */
    Resize,					/* resize */
    Redisplay,					/* expose */
    SetValues,					/* set_values */
    NULL,					/* set_values_hook */
    XtInheritSetValuesAlmost,			/* set_values_almost */
    NULL,					/* get_values_hook */
    NULL,					/* accept_focus */
    XtVersion,					/* version */
    NULL,					/* callback_private */
    NULL,					/* tm_table */
    QueryGeometry,				/* query_geometry */
    NULL,					/* display_accelerator */
    NULL,					/* extension */
  },
  {
  /* Control class part */
    0,						/* dummy_field */
  },
  {
  /* Value class part */
    0,						/* dummy_field */
  },
  {
  /* Lcd class part */
    0,						/* dummy_field */
  }
};

WidgetClass xcLcdWidgetClass = (WidgetClass)&lcdClassRec;



/* Points list for the LCD segment lines. */
static Seg_struct Seg_map[NUM_SEGS] =
{
   { TOP_SEG, { 2, 1, 9, 1 } },
   { RIGHT_SEG, { 9, 2, 9, 6 } },
   { RIGHT_SEG, { 9, 8, 9, 12 } },
   { BOTTOM_SEG, { 9, 13, 2, 13 } },
   { LEFT_SEG, { 2, 12, 2, 8 } },
   { LEFT_SEG, { 2, 6, 2, 2 } },
   { MIDDLE_SEG, { 2, 7, 9, 7 } },
   { PLUS_SEG, { 5, 3, 5, 11 } },
   { DOT_SEG, { 4, 11, 6, 13 } }
};


/* Truth table for possible characters to be displayed in LCD fashion. */
typedef struct chr_tbl_t
{
   char chr;			/* Character in set */
   Boolean sgmt[NUM_SEGS];	/* Table of which segments to draw */
} Char_tbl_struct;

static Char_tbl_struct Char_table[CHAR_TABLE_SIZE] =
{
/*   0  1  2  3  4  5  6  7  8    */
   { '+', { F, F, F, F, F, F, T, T, F } },	/* + */
   { '-', { F, F, F, F, F, F, T, F, F } },	/* - */
   { '0', { T, T, T, T, T, T, F, F, F } },	/* 0 */
   { '1', { F, T, T, F, F, F, F, F, F } },	/* 1 */
   { '2', { T, T, F, T, T, F, T, F, F } },	/* 2 */
   { '3', { T, T, T, T, F, F, T, F, F } },	/* 3 */
   { '4', { F, T, T, F, F, T, T, F, F } },	/* 4 */
   { '5', { T, F, T, T, F, T, T, F, F } },	/* 5 */
   { '6', { T, F, T, T, T, T, T, F, F } },	/* 6 */
   { '7', { T, T, T, F, F, F, F, F, F } },	/* 7 */
   { '8', { T, T, T, T, T, T, T, F, F } },	/* 8 */
   { '9', { T, T, T, F, F, T, T, F, F } },	/* 9 */
   { 'A', { T, T, T, F, T, T, T, F, F } },	/* A */
   { 'B', { F, F, T, T, T, T, T, F, F } },	/* B */
   { 'C', { T, F, F, T, T, T, F, F, F } },	/* C */
   { 'D', { F, T, T, T, T, F, T, F, F } },	/* D */
   { 'E', { T, F, F, T, T, T, T, F, F } },	/* E */
   { 'F', { T, F, F, F, T, T, T, F, F } },	/* F */
   { '.', { F, F, F, F, F, F, F, F, T } },	/* . */
};


/* Widget method function definitions */

/*******************************************************************
 NAME:		Initialize.		
 DESCRIPTION:
   This is the initialize method for the Lcd widget.  It 
validates user-modifiable instance resources and initializes private 
widget variables and structures.  This function also creates any server 
resources (i.e., GCs, fonts, Pixmaps, etc.) used by this widget.  This
method is called by Xt when the application calls XtCreateWidget().

*******************************************************************/

static void Initialize(request, new)
LcdWidget request, new;
{
/* Local variables */
int j;
Display *display = XtDisplay(new);


DPRINTF(("Lcd: executing Initialize...\n"));

/*
 * Validate public instance variable settings.
 */
/* Check valueLength resource setting. */
   if ((new->lcd.value_length > MAX_CHARS) || (new->lcd.value_length < 1))
   {
      XtWarning("Lcd: invalid valuelength setting");
      new->lcd.value_length = (MAX_CHARS / 2 + 0.5); 
   }

/* Check the interval resource setting. */
   if (new->lcd.interval > 0)
      new->lcd.interval_id =
	  XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)new),
					new->lcd.interval, Get_value, new);


/* Initialize the Lcd width and height. */
   if (new->core.width < MIN_LCD_WIDTH)
      new->core.width = MIN_LCD_WIDTH; 
   if (new->core.height < MIN_LCD_HEIGHT)
      new->core.height = MIN_LCD_HEIGHT; 
   
/* Initialize private instance variables.  */
   for (j = 0; j < NUM_SEGS; j++)
      new->lcd.segs[j].stype = Seg_map[j].stype;


/* Set the initial geometry of the Lcd elements. */
   Resize(new);


DPRINTF(("Lcd: done Initialize\n"));

}  /* end of Initialize */





/*******************************************************************
 NAME:		Redisplay.	
 DESCRIPTION:
   This function is the Lcd's Expose method.  It redraws the
Lcd's 3D rectangle border, Label, and the LCD characters corresponding
to the current value.  All drawing takes place within the widget's window 
(no need for an off-screen pixmap).

*******************************************************************/

static void Redisplay(w, event)
LcdWidget w;
XExposeEvent *event;
{

/*
 * Check to see whether or not the widget's window is mapped.  You can't
 * draw into a window that is not mapped.  Realizing a widget doesn't 
 * mean its mapped, but this call will work for most Window Managers.
 */
   if (!XtIsRealized((Widget)w))
      return;

DPRINTF(("Lcd: executing Redisplay\n"));

/* Draw the 3D rectangle background for the Lcd. */
   XSetClipMask(XtDisplay(w), w->control.gc, None);
   Rect3d(w, XtDisplay(w), XtWindow(w), w->control.gc,
		0, 0, w->core.width, w->core.height, RAISED);

/* Draw the Label string. */
   XSetClipRectangles(XtDisplay(w), w->control.gc, 0, 0, 
  			&(w->lcd.face), 1, Unsorted); 
   XSetForeground(XtDisplay(w), w->control.gc,
                        w->control.label_pixel);
   XDrawString(XtDisplay(w), XtWindow(w), w->control.gc,
	w->lcd.lbl.x, w->lcd.lbl.y, 
	w->control.label, strlen(w->control.label));

/* Draw the depressed border around the display. */
   Rect3d(w, XtDisplay(w), XtWindow(w), w->control.gc,
	w->lcd.display.x - w->control.shade_depth, 
	w->lcd.display.y - w->control.shade_depth,
	w->lcd.display.width + (2 * w->control.shade_depth),  
	w->lcd.display.height + (2 * w->control.shade_depth), DEPRESSED);


/* Draw the LCD display with the current value. */
   Draw_display(w, XtDisplay(w), XtWindow(w), w->control.gc);


DPRINTF(("Lcd: done Redisplay\n"));

}  /* end of Redisplay */





/*******************************************************************
 NAME:		SetValues.
 DESCRIPTION:
   This is the set_values method for this widget. It validates resource
settings set with XtSetValues. If a resource is changed that would
require re-drawing the widget, return True.

*******************************************************************/

static Boolean SetValues(cur, req, new)
LcdWidget cur, req, new;
{
/* Local variables */
Boolean do_redisplay = False;


DPRINTF(("Lcd: executing SetValues \n"));

/* Validate new resource settings. */
/* Check valueLength resource setting. */
   if (new->lcd.value_length != cur->lcd.value_length)
   {
      do_redisplay = True;
      if ((new->lcd.value_length > MAX_CHARS) || (new->lcd.value_length < 1))
      {
         XtWarning("Lcd: invalid valuelength setting");
         new->lcd.value_length = (MAX_CHARS / 2 + 0.5);
      }
   }

/* Check the interval resource setting. */
   if (new->lcd.interval != cur->lcd.interval) 
   {
      if (cur->lcd.interval > 0)
	    XtRemoveTimeOut (cur->lcd.interval_id);
      if (new->lcd.interval > 0)
         new->lcd.interval_id = 
		XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)new),
					new->lcd.interval, Get_value, new);
   }

DPRINTF(("Lcd: done SetValues\n"));
   return do_redisplay;


}  /* end of SetValues */




/*******************************************************************
 NAME:		Resize.
 DESCRIPTION:
   This is the resize method of the Lcd widget. It resizes the
Lcd's graphics based on the new width and height of the widget's
window.  

*******************************************************************/

static void Resize(w)
LcdWidget w;
{
int i, j, border_width;
float sx, sy;

DPRINTF(("Lcd: executing Resize\n"));

/* Set the widgets new width and height. */
   w->lcd.face.x = w->lcd.face.y = w->control.shade_depth;
   w->lcd.face.width = w->core.width - (2*w->control.shade_depth);
   w->lcd.face.height = w->core.height - (2*w->control.shade_depth);

/* Set the geometry of the border of the LCD display */
   border_width = ((w->lcd.face.width + w->lcd.face.height) / 2) / 10 + 0.5; 
   w->lcd.display.x = w->lcd.face.x + border_width + w->control.shade_depth;
   w->lcd.display.y = w->lcd.display.x;
   w->lcd.display.width = w->lcd.face.width - 
		(2 * (w->lcd.display.x - w->lcd.face.x)); 
   w->lcd.display.height = w->lcd.face.height - 
		(2 * (w->lcd.display.y - w->lcd.face.y)); 

/* Set the new label location. */
   w->lcd.lbl.x = (w->core.width / 2 + 0.5) -
		(XTextWidth(w->control.font, w->control.label, 
			strlen(w->control.label)) / 2 + 0.5); 
   w->lcd.lbl.y = w->lcd.face.y + w->control.font->ascent + 
			(short)(w->lcd.face.height / 32 + 0.5);

/* Now establish the geometry of the LCD display elements. */
/* Width of each character. */
   w->lcd.char_width = (w->lcd.display.width / w->lcd.value_length + 0.5);

/* Width of each segment line. */
   w->lcd.seg_width = (((w->lcd.char_width < w->lcd.display.height) ?
		w->lcd.char_width : w->lcd.display.height) / 10 + 0.5);
   if (w->lcd.seg_width < MIN_SEG_WIDTH)
      w->lcd.seg_width = MIN_SEG_WIDTH;
   if (w->lcd.seg_width > MAX_SEG_WIDTH)
      w->lcd.seg_width = MAX_SEG_WIDTH;

/* Rectangle that encloses each character in the display.*/
   for (j = 0, i = 0; j < w->lcd.display.x + w->lcd.display.width, 
		i < w->lcd.value_length; j += w->lcd.char_width, i++)
   {
      w->lcd.chars[i].x = w->lcd.display.x + j;
      w->lcd.chars[i].y = w->lcd.display.y;
      w->lcd.chars[i].width = w->lcd.char_width;
      w->lcd.chars[i].height = w->lcd.display.height;
   }

/*
 * Now, scale the segments to fit into the character rectangles in
 * the LCD display.
 */
   sx = (w->lcd.char_width / SEG_MAP_WIDTH);
   sy = (w->lcd.display.height / SEG_MAP_HEIGHT);
   for (j = 0; j < NUM_SEGS; j++)
   {
      w->lcd.segs[j].points.x1 = (int)((float)Seg_map[j].points.x1 * sx);
      w->lcd.segs[j].points.y1 = (int)((float)Seg_map[j].points.y1 * sy);
      w->lcd.segs[j].points.x2 = (int)((float)Seg_map[j].points.x2 * sx);
      w->lcd.segs[j].points.y2 = (int)((float)Seg_map[j].points.y2 * sy);
   }

DPRINTF(("Lcd: done Resize\n"));

}  /* end of Resize */




/*******************************************************************
 NAME:		QueryGeometry.		
 DESCRIPTION:
   This function is the widget's query_geometry method.  It simply
checks the proposed size and returns the appropriate value based on
the proposed size.  If the proposed size is greater than the maximum
appropriate size for this widget, QueryGeometry returns the recommended
size.

*******************************************************************/

static XtGeometryResult QueryGeometry(w, proposed, answer)
LcdWidget w;
XtWidgetGeometry *proposed, *answer;
{
/* Set the request mode mask for the returned answer. */
   answer->request_mode = CWWidth | CWHeight;

/* Set the recommended size. */
   answer->width = (w->core.width > MAX_LCD_WIDTH)
	? MAX_LCD_WIDTH : w->core.width;
   answer->height = (w->core.height > MAX_LCD_HEIGHT)
	? MAX_LCD_HEIGHT : w->core.height;

/* 
 * Check the proposed dimensions. If the proposed size is larger than
 * appropriate, return the recommended size.
 */
   if (((proposed->request_mode & (CWWidth | CWHeight)) == (CWWidth | CWHeight))
	&& proposed->width == answer->width 
	&& proposed->height == answer->height)
      return XtGeometryYes;
   else if (answer->width == w->core.width && answer->height == w->core.height)
      return XtGeometryNo;
   else
      return XtGeometryAlmost;

}  /* end of QueryGeometry */




/*******************************************************************
 NAME:		Destroy.
 DESCRIPTION:
   This function is the widget's destroy method.  It simply releases
any server resources acquired during the life of the widget.

*******************************************************************/

static void Destroy(w)
LcdWidget w;
{

   if (w->lcd.interval > 0)
      XtRemoveTimeOut (w->lcd.interval_id);

}  /* end of Destroy */





/* Widget action functions. */

/*******************************************************************
 NAME:		Get_value.		
 DESCRIPTION:
   This function is the time out procecure called at XcNinterval 
intervals.  It calls the application registered callback function to
get the latest value and updates the LCD display accordingly.

*******************************************************************/

static void Get_value(client_data, id)
caddr_t client_data;
XtIntervalId *id;		/* unused */
{
/* Local variables */
static XcCallData call_data;
LcdWidget w = (LcdWidget)client_data;
   
/* Re-register this TimeOut procedure for the next interval. */
   if (w->lcd.interval > 0)
      w->lcd.interval_id = 
	XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)w),
		       w->lcd.interval, Get_value, client_data);


/* Get the new value by calling the application's callback if it exists. */
   if (w->lcd.update_callback == NULL)
       return;

/* Set the widget's current value and datatype before calling the callback. */
   call_data.dtype = w->value.datatype;
   call_data.decimals = w->value.decimals;
   if ((w->value.datatype == XcLval) || (w->value.datatype == XcHval))  
      call_data.value.lval = w->value.val.lval;
   else if (w->value.datatype == XcFval)
      call_data.value.fval = w->value.val.fval;
   XtCallCallbacks((Widget)w, XcNupdateCallback, &call_data);


/* Update the new value, update the LCD display. */
   if ((w->value.datatype == XcLval) || (w->value.datatype == XcHval))  
   {
      if ((call_data.value.lval <= w->value.upper_bound.lval) &&
                        (call_data.value.lval >= w->value.lower_bound.lval))
         w->value.val.lval = call_data.value.lval;
   }
   else if (w->value.datatype == XcFval)
   {
      if ((call_data.value.fval <= w->value.upper_bound.fval) &&
                        (call_data.value.fval >= w->value.lower_bound.fval))
         w->value.val.fval = call_data.value.fval;
   }

   if (XtIsRealized((Widget)w))
      Draw_display(w, XtDisplay(w), XtWindow(w), w->control.gc);
   

}  /* end of Get_value */




/*******************************************************************
 NAME:		XcLcdUpdateValue.		
 DESCRIPTION:
   This convenience function is called by the application in order to
update the value (a little quicker than using XtSetArg/XtSetValue).
The application passes the new value to be updated with.

*******************************************************************/

void XcLcdUpdateValue(w, value)
LcdWidget w;
XcVType *value;
{
/* Local variables */
   
/* Update the new value, then update the LCD display. */
   if (value != NULL)
   {
      if ((w->value.datatype == XcLval) || (w->value.datatype == XcHval))  
      {
         if ((value->lval <= w->value.upper_bound.lval) &&
                        (value->lval >= w->value.lower_bound.lval))
            w->value.val.lval = value->lval;
      }
      else if (w->value.datatype == XcFval)
      {
         if ((value->fval <= w->value.upper_bound.fval) &&
                        (value->fval >= w->value.lower_bound.fval))
            w->value.val.fval = value->fval;
      }

      if (XtIsRealized((Widget)w))
         Draw_display(w, XtDisplay(w), XtWindow(w), w->control.gc);

   }
   
}  /* end of XcLcdUpdateValue */





/*******************************************************************
 NAME:		Draw_display.		
 DESCRIPTION:
   This function redraws the characters in the LCD display.

*******************************************************************/

static void Draw_display(w, display, drawable, gc)
LcdWidget w;
Display *display;
Drawable drawable;
GC gc;
{
/* Local variables */
int i, j, k, l, chr_index, tbl_index;
int origin_x, origin_y, half;
char temp[MAX_CHARS+1];

/* Clear the display by re-filling it with its background color. */
   XSetForeground(display, gc, w->value.value_bg_pixel); 
   XFillRectangle(display, drawable, gc,
  	w->lcd.display.x, w->lcd.display.y, 
  	w->lcd.display.width, w->lcd.display.height); 

/*
 * Now draw each character in the foreground color, clipped by each
 * character's rectangle.  Convert the current value into a string,
 * step through the string and draw each valid character in LCD segment
 * format.
 */

   if (w->value.datatype == XcLval)  
   {
      sprintf(temp, "%ld", w->value.val.lval); 
   } 
   else if (w->value.datatype == XcHval)  
   {
      sprintf(temp, "%lX", w->value.val.lval); 
   } 
   else if (w->value.datatype == XcFval)  
   {
      sprintf(temp, "%.*f", w->value.decimals, w->value.val.fval); 
   } 

/*
 * Step through each character in the value string, starting from the end
 * of the string, and lookup the required segments in the Character Table
 * if the character is valid.  Draw the corresponding segments in the
 * corresponding character rectangle in the LCD display.
 */
/* Set GC attributes used in drawing the LCD character segments. */
   XSetForeground(display, gc, w->value.value_fg_pixel); 

   chr_index = strlen(temp) - 1;
   if (chr_index > (w->lcd.value_length - 1)) 
      chr_index = w->lcd.value_length - 1;

   for (j = chr_index, k = w->lcd.value_length-1;  j >= 0; j--, k--)
   {
   /* Set the origin and clip rectangle for drawing each character. */
      origin_x = w->lcd.chars[k].x;
      origin_y = w->lcd.chars[k].y;
      XSetClipRectangles(display, gc, 0, 0, &(w->lcd.chars[k]), 1, Unsorted); 

   /* Lookup up the segment list for the given character. */
      tbl_index = CHAR_TABLE_SIZE;
      for (i = 0; i < CHAR_TABLE_SIZE; i++)
      {
	 if (temp[j] == Char_table[i].chr)
	 {
	    tbl_index = i;
	    break;
	 }
      }

   /* If the character is found, draw the required segments. */
      if (tbl_index < CHAR_TABLE_SIZE)
      {
	 for (i = 0; i < NUM_SEGS; i++)
	 {
	    if (Char_table[tbl_index].sgmt[i] == T)
	    {
		for (l = 0; l < w->lcd.seg_width; l++)
		{
		   switch((int)w->lcd.segs[i].stype)
		   {
		      case TOP_SEG:
		        XDrawLine(display, drawable, gc,
				origin_x + w->lcd.segs[i].points.x1 + l, 
				origin_y + w->lcd.segs[i].points.y1 + l, 
				origin_x + w->lcd.segs[i].points.x2 - l, 
				origin_y + w->lcd.segs[i].points.y2 + l); 
		 	break;

		      case BOTTOM_SEG:
		        XDrawLine(display, drawable, gc,
				origin_x + w->lcd.segs[i].points.x1 - l, 
				origin_y + w->lcd.segs[i].points.y1 - l, 
				origin_x + w->lcd.segs[i].points.x2 + l, 
				origin_y + w->lcd.segs[i].points.y2 - l); 
		 	break;

		      case LEFT_SEG:
		        XDrawLine(display, drawable, gc,
				origin_x + w->lcd.segs[i].points.x1 + l, 
				origin_y + w->lcd.segs[i].points.y1 - l, 
				origin_x + w->lcd.segs[i].points.x2 + l, 
				origin_y + w->lcd.segs[i].points.y2 + l); 
		 	break;

		      case RIGHT_SEG:
		        XDrawLine(display, drawable, gc,
				origin_x + w->lcd.segs[i].points.x1 - l, 
				origin_y + w->lcd.segs[i].points.y1 + l, 
				origin_x + w->lcd.segs[i].points.x2 - l, 
				origin_y + w->lcd.segs[i].points.y2 - l); 
		 	break;

		      case MIDDLE_SEG:
			half = l / 2 + 0.5;
		        XDrawLine(display, drawable, gc,
				origin_x + w->lcd.segs[i].points.x1 + half, 
				origin_y + w->lcd.segs[i].points.y1 - half, 
				origin_x + w->lcd.segs[i].points.x2 - half, 
				origin_y + w->lcd.segs[i].points.y2 - half); 
		        XDrawLine(display, drawable, gc,
				origin_x + w->lcd.segs[i].points.x1 + half, 
				origin_y + w->lcd.segs[i].points.y1 + half, 
				origin_x + w->lcd.segs[i].points.x2 - half, 
				origin_y + w->lcd.segs[i].points.y2 + half); 
		 	break;

		      case PLUS_SEG:
		        XDrawLine(display, drawable, gc,
				origin_x + w->lcd.segs[i].points.x1 - l, 
				origin_y + w->lcd.segs[i].points.y1 + l, 
				origin_x + w->lcd.segs[i].points.x2 - l, 
				origin_y + w->lcd.segs[i].points.y2 - l); 
		        XDrawLine(display, drawable, gc,
				origin_x + w->lcd.segs[i].points.x1 + l, 
				origin_y + w->lcd.segs[i].points.y1 + l, 
				origin_x + w->lcd.segs[i].points.x2 + l, 
				origin_y + w->lcd.segs[i].points.y2 - l); 
		 	break;

		      case DOT_SEG:
			XFillRectangle(display, drawable, gc,
		    	   origin_x + w->lcd.segs[i].points.x1, 
		    	   origin_y + w->lcd.segs[i].points.y1,
		    	   w->lcd.segs[i].points.x2 - w->lcd.segs[i].points.x1,
		    	   w->lcd.segs[i].points.y2 - w->lcd.segs[i].points.y1);
		 	break;
		  }
	       }
	    }
	 }
      }
   }


/* Reset the clip_mask to no clipping. */
   XSetClipMask(display, gc, None);

}  /* end of Draw_display */



/* end of Lcd.c */
