



#include "WINGsP.h"

#include <X11/keysym.h>
#include <X11/Xatom.h>

#include <ctype.h>

#define CURSOR_BLINK_ON_DELAY	600
#define CURSOR_BLINK_OFF_DELAY	300


char *WMTextDidChangeNotification = "WMTextDidChangeNotification";
char *WMTextDidBeginEditingNotification = "WMTextDidBeginEditingNotification";
char *WMTextDidEndEditingNotification = "WMTextDidEndEditingNotification";


typedef struct W_TextField {
    W_Class widgetClass;
    W_View *view;

    struct W_TextField *nextField;     /* next textfield in the chain */
    struct W_TextField *prevField;

    char *text;
    int textLen;		       /* size of text */
    int bufferSize;		       /* memory allocated for text */

    int viewPosition;		       /* position of text being shown */

    int cursorPosition;		       /* position of the insertion cursor */

    short usableWidth;
    short offsetWidth;		       /* offset of text from border */

    WMRange selection;

#if 0
    WMHandlerID	timerID;	       /* for cursor blinking */
#endif
    struct {
	WMAlignment alignment:2;

	unsigned int bordered:1;
	
	unsigned int enabled:1;
	
	unsigned int focused:1;

	unsigned int cursorOn:1;
	
	unsigned int secure:1;	       /* password entry style */

	/**/
	unsigned int notIllegalMovement:1;
    } flags;
} TextField;


#define MIN_TEXT_BUFFER		2
#define TEXT_BUFFER_INCR	8


#define WM_EMACSKEYMASK   ControlMask

#define WM_EMACSKEY_LEFT  XK_b
#define WM_EMACSKEY_RIGHT XK_f
#define WM_EMACSKEY_HOME  XK_a
#define WM_EMACSKEY_END   XK_e
#define WM_EMACSKEY_BS    XK_h
#define WM_EMACSKEY_DEL   XK_d



#define DEFAULT_WIDTH		60
#define DEFAULT_HEIGHT		20
#define DEFAULT_BORDERED	True
#define DEFAULT_ALIGNMENT	WALeft



static void destroyTextField(TextField *tPtr);
static void paintTextField(TextField *tPtr);

static void handleEvents(XEvent *event, void *data);
static void handleTextFieldActionEvents(XEvent *event, void *data);
static void resizeTextField();

struct W_ViewProcedureTable _TextFieldViewProcedures = {
    NULL,
	resizeTextField,
	NULL
};


#define TEXT_WIDTH(tPtr, start)	(WMWidthOfString((tPtr)->view->screen->normalFont, \
				   &((tPtr)->text[(start)]), (tPtr)->textLen - (start) + 1))

#define TEXT_WIDTH2(tPtr, start, end) (WMWidthOfString((tPtr)->view->screen->normalFont, \
				   &((tPtr)->text[(start)]), (end) - (start) + 1))


static void
memmv(char *dest, char *src, int size)
{
    int i;
    
    if (dest > src) {
	for (i=size-1; i>=0; i--) {
	    dest[i] = src[i];
	}
    } else if (dest < src) {
	for (i=0; i<size; i++) {
	    dest[i] = src[i];
	}
    }
}


static int
incrToFit(TextField *tPtr)
{
    int vp = tPtr->viewPosition;

    while (TEXT_WIDTH(tPtr, tPtr->viewPosition) > tPtr->usableWidth) {
	tPtr->viewPosition++;
    }
    return vp!=tPtr->viewPosition;
}

static int
incrToFit2(TextField *tPtr)
{
    int vp = tPtr->viewPosition;
    while (TEXT_WIDTH2(tPtr, tPtr->viewPosition, tPtr->cursorPosition) 
	   >= tPtr->usableWidth)
	tPtr->viewPosition++;

    
    return vp!=tPtr->viewPosition;
}


static void
decrToFit(TextField *tPtr)
{
    while (TEXT_WIDTH(tPtr, tPtr->viewPosition-1) < tPtr->usableWidth
	   && tPtr->viewPosition>0)
	tPtr->viewPosition--;
}

#undef TEXT_WIDTH
#undef TEXT_WIDTH2


WMTextField*
WMCreateTextField(WMWidget *parent)
{
    TextField *tPtr;

    
    tPtr = wmalloc(sizeof(TextField));
    memset(tPtr, 0, sizeof(TextField));

    tPtr->widgetClass = WC_TextField;
    
    tPtr->view = W_CreateView(W_VIEW(parent));
    if (!tPtr->view) {
	free(tPtr);
	return NULL;
    }
    tPtr->view->self = tPtr;
    
    tPtr->view->attribFlags |= CWCursor;
    tPtr->view->attribs.cursor = tPtr->view->screen->textCursor;
    
    W_SetViewBackgroundColor(tPtr->view, tPtr->view->screen->white);
    
    tPtr->text = wmalloc(MIN_TEXT_BUFFER);
    tPtr->text[0] = 0;
    tPtr->textLen = 0;
    tPtr->bufferSize = MIN_TEXT_BUFFER;
    
    tPtr->flags.enabled = 1;
    
    WMCreateEventHandler(tPtr->view, ExposureMask|StructureNotifyMask
			 |FocusChangeMask, handleEvents, tPtr);

    W_ResizeView(tPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
    WMSetTextFieldBordered(tPtr, DEFAULT_BORDERED);
    tPtr->flags.alignment = DEFAULT_ALIGNMENT;
    tPtr->offsetWidth = (tPtr->view->size.height
			 - WMFontHeight(tPtr->view->screen->normalFont))/2;

    WMCreateEventHandler(tPtr->view, EnterWindowMask|LeaveWindowMask
			 |ButtonPressMask|KeyPressMask|Button1MotionMask,
			 handleTextFieldActionEvents, tPtr);

    tPtr->flags.cursorOn = 1;
    
    return tPtr;
}


void
WMInsertTextFieldText(WMTextField *tPtr, char *text, int position)
{
    int len;
 
    CHECK_CLASS(tPtr, WC_TextField);
    
    if (!text)
	return;
    
    len = strlen(text);

    /* check if buffer will hold the text */
    if (len + tPtr->textLen >= tPtr->bufferSize) {
	tPtr->bufferSize = tPtr->textLen + len + TEXT_BUFFER_INCR;
	tPtr->text = realloc(tPtr->text, tPtr->bufferSize);
    }
    
    if (position < 0 || position >= tPtr->textLen) {
	/* append the text at the end */
	strcat(tPtr->text, text);
	
	incrToFit(tPtr);

	tPtr->textLen += len;
	tPtr->cursorPosition += len;
    } else {
	/* insert text at position */ 
	memmv(&(tPtr->text[position+len]), &(tPtr->text[position]),
                tPtr->textLen-position+1);
	
	memcpy(&(tPtr->text[position]), text, len);
	
	tPtr->textLen += len;
	if (position >= tPtr->cursorPosition) {
	    tPtr->cursorPosition += len;
	    incrToFit2(tPtr);
	} else {
	    incrToFit(tPtr);
	}
    }
    
    paintTextField(tPtr);
}


void
WMDeleteTextFieldRange(WMTextField *tPtr, WMRange range)
{    
    CHECK_CLASS(tPtr, WC_TextField);

    if (range.position >= tPtr->textLen)
	return;
    
    if (range.count < 1) {
	if (range.position < 0)
	    range.position = 0;
	tPtr->text[range.position] = 0;
	tPtr->textLen = range.position;
	
	tPtr->cursorPosition = 0;
	tPtr->viewPosition = 0;
    } else {
	if (range.position + range.count > tPtr->textLen)
	    range.count = tPtr->textLen - range.position;
	memmv(&(tPtr->text[range.position]), &(tPtr->text[range.position+range.count]),
                tPtr->textLen - (range.position+range.count) + 1);
	tPtr->textLen -= range.count;
	
	if (tPtr->cursorPosition > range.position)
	    tPtr->cursorPosition -= range.count;

	decrToFit(tPtr);
    }
        
    paintTextField(tPtr);
}



char*
WMGetTextFieldText(WMTextField *tPtr)
{
    CHECK_CLASS(tPtr, WC_TextField);
        
    return wstrdup(tPtr->text);
}


void
WMSetTextFieldText(WMTextField *tPtr, char *text)
{
    if (text==NULL) {
	tPtr->text[0] = 0;
	tPtr->textLen = 0;
    } else {
	tPtr->textLen = strlen(text);
	
	if (tPtr->textLen >= tPtr->bufferSize) {
	    tPtr->bufferSize = tPtr->textLen + TEXT_BUFFER_INCR;
	    tPtr->text = realloc(tPtr->text, tPtr->bufferSize);
	}
	strcpy(tPtr->text, text);
    }
    /*
    if (tPtr->textLen < tPtr->cursorPosition)
	tPtr->cursorPosition = tPtr->textLen;
     */
    tPtr->cursorPosition = 0;
    tPtr->viewPosition = 0;
    
    if (tPtr->view->flags.realized)
	paintTextField(tPtr);
}


void
WMSetTextFieldAlignment(WMTextField *tPtr, WMAlignment alignment)
{
    tPtr->flags.alignment = alignment;
    if (alignment!=WALeft) {
	wwarning("only left alignment is supported in textfields");
	return;
    }
	
    if (tPtr->view->flags.realized) {
	paintTextField(tPtr);
    }
}


void
WMSetTextFieldBordered(WMTextField *tPtr, Bool bordered)
{
    tPtr->flags.bordered = bordered;

    if (tPtr->view->flags.realized) {
	paintTextField(tPtr);
    }
}



void
WMSetTextFieldSecure(WMTextField *tPtr, Bool flag)
{
    tPtr->flags.secure = flag;
    
    if (tPtr->view->flags.realized) {
	paintTextField(tPtr);
    }    
}


void
WMSetTextFieldEnabled(WMTextField *tPtr, Bool flag)
{
    tPtr->flags.enabled = flag;
    
    if (tPtr->view->flags.realized) {
	paintTextField(tPtr);
    }
}


static void 
resizeTextField(WMTextField *tPtr, unsigned int width, unsigned int height)
{
    W_ResizeView(tPtr->view, width, height);
    
    tPtr->offsetWidth = (tPtr->view->size.height
			 - WMFontHeight(tPtr->view->screen->normalFont))/2;
    
    tPtr->usableWidth = tPtr->view->size.width - 2*tPtr->offsetWidth;
}


static void
paintCursor(TextField *tPtr)
{
    int cx;
    WMScreen *screen = tPtr->view->screen;
    int textWidth;

    cx = WMWidthOfString(screen->normalFont,
			 &(tPtr->text[tPtr->viewPosition]),
			 tPtr->cursorPosition-tPtr->viewPosition);

    switch (tPtr->flags.alignment) {
     case WARight:
	textWidth = WMWidthOfString(screen->normalFont, tPtr->text, 
				    tPtr->textLen);
	if (textWidth < tPtr->usableWidth)
	    cx += tPtr->offsetWidth + tPtr->usableWidth - textWidth;
	else
	    cx += tPtr->offsetWidth;
	break;
     case WALeft:
	cx += tPtr->offsetWidth;
	break;
     case WACenter:
	textWidth = WMWidthOfString(screen->normalFont, tPtr->text, 
				    tPtr->textLen);
	if (textWidth < tPtr->usableWidth)
	    cx += tPtr->offsetWidth + (tPtr->usableWidth-textWidth)/2;
	else
	    cx += tPtr->offsetWidth;
	break;
    }
    /*
    XDrawRectangle(screen->display, tPtr->view->window, screen->xorGC,
		   cx, tPtr->offsetWidth, 1,
		   tPtr->view->size.height - 2*tPtr->offsetWidth - 1);
     */
    XDrawLine(screen->display, tPtr->view->window, screen->xorGC,
	      cx, tPtr->offsetWidth, cx,
	      tPtr->view->size.height - tPtr->offsetWidth - 1);
}



static void
drawRelief(WMView *view)
{
    WMScreen *scr = view->screen;
    Display *dpy = scr->display;
    GC wgc;
    GC lgc;
    GC dgc;
    int width = view->size.width;
    int height = view->size.height;
    
    wgc = W_GC(scr->white);
    dgc = W_GC(scr->darkGray);
    lgc = W_GC(scr->gray);

    /* top left */
    XDrawLine(dpy, view->window, dgc, 0, 0, width-1, 0);
    XDrawLine(dpy, view->window, dgc, 0, 1, width-2, 1);
    
    XDrawLine(dpy, view->window, dgc, 0, 0, 0, height-2);
    XDrawLine(dpy, view->window, dgc, 1, 0, 1, height-3);
    
    /* bottom right */
    XDrawLine(dpy, view->window, wgc, 0, height-1, width-1, height-1);
    XDrawLine(dpy, view->window, lgc, 1, height-2, width-2, height-2);

    XDrawLine(dpy, view->window, wgc, width-1, 0, width-1, height-1);
    XDrawLine(dpy, view->window, lgc, width-2, 1, width-2, height-3);
}


static void
paintTextField(TextField *tPtr)
{
    W_Screen *screen = tPtr->view->screen;
    W_View *view = tPtr->view;
    int tx, ty, tw, th;
    int bd;
    int totalWidth;

    
    if (!view->flags.realized || !view->flags.mapped)
	return;

    if (!tPtr->flags.bordered) {
	bd = 0;
    } else {
	bd = 2;
    }

    totalWidth = tPtr->view->size.width - 2*bd;

    if (tPtr->textLen > 0) {
    	tw = WMWidthOfString(screen->normalFont, 
			     &(tPtr->text[tPtr->viewPosition]),
			     tPtr->textLen - tPtr->viewPosition);
    
	th = WMFontHeight(screen->normalFont);

	ty = tPtr->offsetWidth;
	switch (tPtr->flags.alignment) {
	 case WALeft:
	    tx = tPtr->offsetWidth;
	    if (tw < tPtr->usableWidth)
		XClearArea(screen->display, view->window, bd+tw, bd,
			   totalWidth-tw, view->size.height-2*bd, 
			   False);
	    break;
	
	 case WACenter:	    
	    tx = tPtr->offsetWidth + (tPtr->usableWidth - tw) / 2;
	    if (tw < tPtr->usableWidth)
		XClearArea(screen->display, view->window, bd, bd,
			   totalWidth, view->size.height-2*bd, False);
	    break;

	 default:
	 case WARight:
	    tx = tPtr->offsetWidth + tPtr->usableWidth - tw;
	    if (tw < tPtr->usableWidth)
		XClearArea(screen->display, view->window, bd, bd,
			   totalWidth-tw, view->size.height-2*bd, False);
	    break;
	}

	if (!tPtr->flags.secure) {
	    if (!tPtr->flags.enabled)
		WMSetColorInGC(screen->darkGray, screen->textFieldGC);

	    WMDrawImageString(screen, view->window, screen->textFieldGC, 
			      screen->normalFont, tx, ty,
			      &(tPtr->text[tPtr->viewPosition]), 
			      tPtr->textLen - tPtr->viewPosition);
	
	    if (!tPtr->flags.enabled)
		WMSetColorInGC(screen->black, screen->textFieldGC);
	}
    } else {
	XClearArea(screen->display, view->window, bd, bd, totalWidth,
		   view->size.height - 2*bd, False);
    }

    /* draw cursor */
    if (tPtr->flags.focused && tPtr->flags.enabled && tPtr->flags.cursorOn
	&& !tPtr->flags.secure) {
	paintCursor(tPtr);
    }
    
    /* draw relief */
    if (tPtr->flags.bordered) {
	drawRelief(view);
    }
}


#if 0
static void
blinkCursor(void *data)
{
    TextField *tPtr = (TextField*)data;
    
    if (tPtr->flags.cursorOn) {
	tPtr->timerID = WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY, blinkCursor,
					  data);
    } else {
	tPtr->timerID = WMAddTimerHandler(CURSOR_BLINK_ON_DELAY, blinkCursor,
					  data);	
    }
    paintCursor(tPtr);
    tPtr->flags.cursorOn = !tPtr->flags.cursorOn;
}
#endif

static void
handleEvents(XEvent *event, void *data)
{
    TextField *tPtr = (TextField*)data;

    CHECK_CLASS(data, WC_TextField);


    switch (event->type) {
     case FocusIn:
	if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr->view))!=tPtr->view)
	    return;
	tPtr->flags.focused = 1;
#if 0
	if (!tPtr->timerID) {
	    tPtr->timerID = WMAddTimerHandler(CURSOR_BLINK_ON_DELAY, 
					      blinkCursor, tPtr);
	}
#endif
	paintTextField(tPtr);

	WMPostNotificationName(WMTextDidBeginEditingNotification, tPtr, NULL);

	tPtr->flags.notIllegalMovement = 0;
	break;
	
     case FocusOut:
	tPtr->flags.focused = 0;
#if 0
	if (tPtr->timerID)
	    WMDeleteTimerHandler(tPtr->timerID);
	tPtr->timerID = NULL;
#endif

	paintTextField(tPtr);
	if (!tPtr->flags.notIllegalMovement) {
	    WMPostNotificationName(WMTextDidEndEditingNotification, tPtr,
				   (void*)WMIllegalTextMovement);
	}
	break;
	
     case Expose:
	if (event->xexpose.count!=0)
	    break;
	paintTextField(tPtr);
	break;
	
     case DestroyNotify:
	destroyTextField(tPtr);
	break;
    }
}


static void
handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
{
    char buffer[64];
    KeySym ksym;
    int count, refresh = 0;
    int control_pressed = 0;
    int changed;
    WMScreen *scr = tPtr->view->screen;

    changed = 0;

    if (((XKeyEvent *) event)->state & WM_EMACSKEYMASK) {
	control_pressed = 1;
    }

    count = XLookupString(&event->xkey, buffer, 63, &ksym, NULL);
    buffer[count] = '\0';

    switch (ksym) {
     case XK_Tab:
	if (event->xkey.state & ShiftMask) {
	    if (tPtr->view->prevFocusChain) {
		W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr->view),
				     tPtr->view->prevFocusChain);
		tPtr->flags.notIllegalMovement = 1;
	    }
	    WMPostNotificationName(WMTextDidEndEditingNotification, tPtr,
				   (void*)WMBacktabTextMovement);
	} else {
	    if (tPtr->view->nextFocusChain) {
		W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr->view),
				 tPtr->view->nextFocusChain);
		tPtr->flags.notIllegalMovement = 1;
	    }
	    WMPostNotificationName(WMTextDidEndEditingNotification,
				   tPtr, (void*)WMTabTextMovement);
	}
	break;
	
     case XK_Return:
	WMPostNotificationName(WMTextDidEndEditingNotification, tPtr, 
			       (void*)WMReturnTextMovement);
	break;

     case WM_EMACSKEY_LEFT:
	if (!control_pressed) {
	    goto normal_key;
	}
     case XK_KP_Left:
     case XK_Left:
	if (tPtr->cursorPosition > 0) {
	    paintCursor(tPtr);
	    tPtr->cursorPosition--;
	    if (tPtr->cursorPosition < tPtr->viewPosition) {
		tPtr->viewPosition = tPtr->cursorPosition;
		refresh = 1;
	    } else {
		paintCursor(tPtr);
	    }
	}
	break;

    case WM_EMACSKEY_RIGHT:
      if (!control_pressed) {
	goto normal_key;
      }
    case XK_KP_Right:
     case XK_Right:
	if (tPtr->cursorPosition < tPtr->textLen) {
	    paintCursor(tPtr);
	    tPtr->cursorPosition++;
	    while (WMWidthOfString(scr->normalFont,
				&(tPtr->text[tPtr->viewPosition]),
				tPtr->cursorPosition-tPtr->viewPosition)
		   > tPtr->usableWidth) {
		tPtr->viewPosition++;
		refresh = 1;
	    }
	    if (!refresh)
		paintCursor(tPtr);
	}
	break;
	
    case WM_EMACSKEY_HOME:
      if (!control_pressed) {
	goto normal_key;
      }
    case XK_KP_Home:
     case XK_Home:
	if (tPtr->cursorPosition > 0) {
	    paintCursor(tPtr);
	    tPtr->cursorPosition = 0;
	    if (tPtr->viewPosition > 0) {
		tPtr->viewPosition = 0;
		refresh = 1;
	    } else {
		paintCursor(tPtr);
	    }
	}
	break;
	
    case WM_EMACSKEY_END:
      if (!control_pressed) {
	goto normal_key;
      }
     case XK_KP_End:
     case XK_End:
	if (tPtr->cursorPosition < tPtr->textLen) {
	    paintCursor(tPtr);
	    tPtr->cursorPosition = tPtr->textLen;
	    tPtr->viewPosition = 0;
	    while (WMWidthOfString(scr->normalFont,
				   &(tPtr->text[tPtr->viewPosition]),
				   tPtr->textLen-tPtr->viewPosition)
		   >= tPtr->usableWidth) {
		tPtr->viewPosition++;
		refresh = 1;
	    }
	    if (!refresh)
		paintCursor(tPtr);
	}
	break;
	
     case WM_EMACSKEY_BS:
      if (!control_pressed) {
	goto normal_key;
      }
     case XK_BackSpace:
	if (tPtr->cursorPosition > 0) {
	    WMRange range;
	    changed = 1;
	    range.position = tPtr->cursorPosition-1;
	    range.count = 1;
	    WMDeleteTextFieldRange(tPtr, range);
	}
	break;
	
    case WM_EMACSKEY_DEL:
      if (!control_pressed) {
	goto normal_key;
      }
    case XK_KP_Delete:
     case XK_Delete:
	if (tPtr->cursorPosition < tPtr->textLen) {
	    WMRange range;
	    changed = 1;
	    range.position = tPtr->cursorPosition;
	    range.count = 1;
	    WMDeleteTextFieldRange(tPtr, range);
	}
	break;

    normal_key:
     default:
	if (count > 0 && !iscntrl(buffer[0])) {
	    changed = 1;
	    WMInsertTextFieldText(tPtr, buffer, tPtr->cursorPosition);
	}
    }
    if (refresh) {
	paintTextField(tPtr);
    }
    
    if (changed) {
	WMPostNotificationName(WMTextDidChangeNotification, tPtr, NULL);
    }
}


static int
pointToCursorPosition(TextField *tPtr, int x)
{
    WMFont *font = tPtr->view->screen->normalFont;
    int a, b, mid;
    int tw;

    if (tPtr->flags.bordered)
	x -= 2;

    a = tPtr->viewPosition;
    b = tPtr->viewPosition + tPtr->textLen;
    if (WMWidthOfString(font, &(tPtr->text[tPtr->viewPosition]), 
			tPtr->textLen-tPtr->viewPosition) < x)
	return tPtr->textLen;

    while (a < b && b-a>1) {
	mid = (a+b)/2;
	tw = WMWidthOfString(font, &(tPtr->text[tPtr->viewPosition]), 
			     mid - tPtr->viewPosition);
	if (tw > x)
	    b = mid;
	else if (tw < x)
	    a = mid;
	else
	    return mid;
    }
    return (a+b)/2;
}


static void
handleTextFieldActionEvents(XEvent *event, void *data)
{
    TextField *tPtr = (TextField*)data;
    
    CHECK_CLASS(data, WC_TextField);

    switch (event->type) {
     case KeyPress:
	if (tPtr->flags.enabled)
	    handleTextFieldKeyPress(tPtr, event);
	break;
	
     case MotionNotify:
	if (tPtr->flags.enabled && (event->xmotion.state & Button1Mask)) {
	    tPtr->cursorPosition = pointToCursorPosition(tPtr,
							 event->xmotion.x);
	    paintTextField(tPtr);
	}
	break;
	
     case ButtonPress:
	if (tPtr->flags.enabled && !tPtr->flags.focused) {
	    WMSetFocusToWidget(tPtr);
	    tPtr->cursorPosition = pointToCursorPosition(tPtr, 
							 event->xbutton.x);
	    paintTextField(tPtr);
	} else if (tPtr->flags.focused) {
	    tPtr->cursorPosition = pointToCursorPosition(tPtr, 
							 event->xbutton.x);
	    paintTextField(tPtr);
	}
	if (event->xbutton.button == Button2 && tPtr->flags.enabled) {
	    char *text;
	    
	    text = W_GetTextSelection(tPtr->view->screen, XA_PRIMARY);
	    if (!text) {
		text = W_GetTextSelection(tPtr->view->screen, XA_CUT_BUFFER0);
	    }
	    if (text) {
		WMInsertTextFieldText(tPtr, text, tPtr->cursorPosition);
		XFree(text);
		WMPostNotificationName(WMTextDidChangeNotification, tPtr, 
				       NULL);
	    }
	}
	break;
	
     case ButtonRelease:
	
	break;
    }
}


static void
destroyTextField(TextField *tPtr)
{
#if 0
    if (tPtr->timerID)
	WMDeleteTimerHandler(tPtr->timerID);
#endif
    
    if (tPtr->text)
	free(tPtr->text);

    free(tPtr);
}
