/*
###
### This file is part of
###
###                        TurboLinux  ZWinPro
###
###                 Copyright (C) 1999-2000 TurboLinux, Inc.
###                        All Rights Reserved
### Distributed under the terms of the GNU General Public License (GPL)
###
###
### Authors:     TurboLinux Chinese Development Team:
###              Justin Yu   <justiny@turbolinux.com.cn>
###              Sean Chen   <seanc@turbolinux.com.cn>
###              Daniel Fang <danf@turbolinux.com.cn>
###
*/


// overthespot style is almost available by all XIM applications.
// it contains two parts: the preedit part and the candidate part.
// status area is optional for apps.
// +----------------+ +------------------+
// |preedit         | |[status][ime name]|
// +----------------+ +------------------+
//                    |1. xxx            |
//                    |2. xxx            |
//                    |.                 |
//                    |.                 |
//                    |.                 |
//                    |.                 |
//                    |.                 |
//                    |.                 |
//                    |0. xxx            |
//                    +------------------+
//                    | [arrows]         |
//                    +------------------+

// This is the a caret mode implementation for root-window preedit
//    style of XIM, it simulates the MS Windows' Chinese input method.
//    Now many applications support caret mode, such as gtk/gnome based
//    and qt/kde based applications. rxvt, a terminal simulator, also
//    support such mode by modify its source slightly.
//                                                --  Justin Yu

#include "all.h"
#include "tips.h"
#include <langinfo.h>
#define max(a, b) ((a) > (b) ? (a) : (b))

static int flag_noinput = 1;

#if 0
// Print STR as a caption of the output. And dump offset and hex value of BUF.
static void chinput_print_mbs_hex (const char *str, char *buf, int len)
{
	char *cur = buf;

	printf ("%s\n", str);
	while (*cur && (cur - buf) < len)
		printf ("... Offset: #%d, Value: #%x\n", cur - buf, (unsigned char) *cur++);
}

// ! Nothing else call this function.
// Hide all necessary window for overspot
static void chinput_overspot_hide_window (void)
{
	IC *ic = (IC *)chinput_find_ic  (last_icid);

	if (!ic)
		return;
	if (map_mode)
	{
		XUnmapWindow (display, window1);
		XUnmapWindow (display, window2);
		chinput_overspot_hide_status_window ();
		map_mode = 0;
	}
}

// ! Nothing else calls this function
static void chinput_overspot_draw_input_entry (int x, int y, int w, int h)
{
	Display *dpy = HZServer.display;
	Window  win  = HZServer.window1;
	GC dimgc = HZServer.dimGC;
	GC lightgc = HZServer.lightGC;

	XDrawLine(dpy, win, dimgc, x, y, x+w, y);
	XDrawLine(dpy, win, dimgc, x, y+1, x+w, y+1);
	XDrawLine(dpy, win, dimgc, x, y, x, y+h);
	XDrawLine(dpy, win, dimgc, x+1, y, x+1, y+h);
	XDrawLine(dpy, win, lightgc, x, y+h-2, x+w, y+h-2);
	XDrawLine(dpy, win, lightgc, x, y+h-1, x+w, y+h-1);
	XDrawLine(dpy, win, lightgc, x+w, y, x+w, y+h);
	XDrawLine(dpy, win, lightgc, x+w-1, y, x+w-1, y+h);
}
#endif

// Move and Resize Windows
static void chinput_overspot_resize_window (int len)
{
	int curx1, cury1, curx2, cury2;
	int dw = DisplayWidth(display, screen_num);
	int dh = DisplayHeight(display, screen_num);

	if (len < HZSERVER_INPUT_CHARS)
		len = HZSERVER_INPUT_CHARS;

	width_input_win = len * 8 + 8;
	
	// Get the position of window and move window2 first
	curx1 = HZServer.hzIwin.x;
	cury1 = HZServer.hzIwin.y;

	if (curx1 + width_input_win + 4 > dw)
		curx1 = dw - width_input_win - 4;

	if (cury1 + HZSERVER_INPUT_WIN16_HEIGHT + 4 > dh)
		cury1 = dh - HZSERVER_INPUT_WIN16_HEIGHT - 4;

	// Move candidate window first,
	// if we resize input window first, the input window
	// may obscure the candidate window, and cause remap
	curx2 = curx1 + width_input_win + 4;
	cury2 = cury1;

	if (curx2 < curx1 + width_input_win + 4)
		curx2 = curx1 + width_input_win + 4;

	if (curx2 + HZSERVER_CHOICE_WIN16_WIDTH + 4 > dw)
		curx2 = curx1 - HZSERVER_CHOICE_WIN16_WIDTH - 4;

	if (cury2 < 0)
		cury2 = 0;

	if (cury2 + HZSERVER_CHOICE_WIN16_HEIGHT + 4 > dh)
		cury2 = dh - HZSERVER_CHOICE_WIN16_HEIGHT - 4;

	XMoveWindow (display, window2, curx2, cury2);
	XMoveWindow (display, window1, curx1, cury1);
	XResizeWindow (display, window1, len*8 + 8, HZServer.hzCwin.h1);

	if (map_mode == 1)
		XMapRaised(display, window1);
}

// Mark selection in Candidate Window
static void chinput_overspot_mark_selection (int item)
{
	int y;
	y = HZServer.f_height + 28 + (item-1) * (HZServer.f_height + 2) - 17;
	XDrawRectangle (display, window2, HZServer.dimGC,
			5, y, HZServer.hzCwin.w2 - 11, 17);
}

// Unmark selection in Candidate Window
static void chinput_overspot_unmark_selection (int item)
{
	int y;

	if (item == -1)
		return;

	y = HZServer.f_height + 28 + (item-1) * (HZServer.f_height + 2) - 17;
	XDrawRectangle (display, window2, HZServer.panelGC,
			5, y, HZServer.hzCwin.w2 - 11, 17);
}

//draw the up and down arrows, if needed
static void chinput_overspot_draw_caret_button (void)
{
	Display *dpy = HZServer.display;
	Window  win2 = HZServer.window2;

	GC dimgc2 = HZServer.dimGC;
	GC lightgc2 = HZServer.lightGC;
	//draw up/down buttons, if any
	if (flag_up)
		chinput_util_draw_tri_btn (dpy, win2, dimgc2, lightgc2,
			HZServer.hzCwin.b1_x1, HZServer.hzCwin.b1_y1,
			HZServer.hzCwin.b1_x2, HZServer.hzCwin.b1_y2,
			HZServer.hzCwin.b1_x3, HZServer.hzCwin.b1_y3,
			False);
	if (flag_down)
		chinput_util_draw_tri_btn (dpy, win2, dimgc2, lightgc2,
			HZServer.hzCwin.b2_x1, HZServer.hzCwin.b2_y1,
			HZServer.hzCwin.b2_x2, HZServer.hzCwin.b2_y2,
			HZServer.hzCwin.b2_x3, HZServer.hzCwin.b2_y3,
			False);
}

static void chinput_overspot_resize_status_window (IC *ic)
{
	Window win = (Window)0;
	XWindowAttributes xwa;

	win = ic->client_win;

	if(!win) return;
	XGetWindowAttributes (display, win, &xwa);

	ic->sts_attr.area.x = 0;
	ic->sts_attr.area.y = xwa.height - FONT_HEIGHT;
	ic->sts_attr.area.width = xwa.width;
	ic->sts_attr.area.height = FONT_HEIGHT;

	XMoveResizeWindow (display, ic->status_win, 
	ic->sts_attr.area.x, ic->sts_attr.area.y,
	ic->sts_attr.area.width, ic->sts_attr.area.height);
}

static void chinput_overspot_map_status_window (void)
{
	IC *ic = (IC *)chinput_find_ic  (last_icid);
	if (!ic)
		return;
	XMapRaised (display, ic->status_win);
}

static void chinput_overspot_reparent_status_window (IC *ic)
{
	Window win = (Window)0;
	XWindowAttributes xwa;

	win = ic->client_win;

	if (!win)
		return;
	XGetWindowAttributes (display, win, &xwa);

	ic->sts_attr.area.x = 0;
	ic->sts_attr.area.y = xwa.height - FONT_HEIGHT;
	ic->sts_attr.area.width = xwa.width;
	ic->sts_attr.area.height = FONT_HEIGHT;
	
	XReparentWindow(display, ic->status_win, win,
			ic->sts_attr.area.x, ic->sts_attr.area.y);
}

static void chinput_overspot_move_status_window (IC *ic)
{
	Window win;
	XWindowAttributes xwa;

	win = chinput_util_find_top_win (ic->client_win);
	if (!win)
		return;

	XGetWindowAttributes (display, win, &xwa);

	ic->sts_attr.area.x = 0;
	ic->sts_attr.area.y = xwa.height - 16;
	//ic->sts_attr.area.width = ic->sts_attr.area_needed.width;
	//ic->sts_attr.area.height = 16;

	XMoveWindow (display, ic->status_win, 
			ic->sts_attr.area.x, ic->sts_attr.area.y);
}

static void chinput_overspot_draw_input_panel (void)
{
	int w1 = width_input_win;
	int h1 = HZServer.hzCwin.h1;			// Why not use the h1 from hzIwin??

	GC dimgc = HZServer.dimGC;
	GC lightgc = HZServer.lightGC;
	GC panelgc = HZServer.panelGC;

	/* fill background of two windows */
	XFillRectangle (display, window1, panelgc,  0, 0, w1, h1);
	chinput_util_draw_sunken_border (display, window1, lightgc, dimgc, 0, 0, w1, h1);

#ifdef IMLIB
	// The four geometry parameter is (X0, Y0, X1, Y1), we can scale the image
	if (flag_noinput == 1)
		Imlib_paste_image (icon_id, im_chinput, window1, 6, 6, 16, 16);
#endif
}

static void chinput_overspot_draw_input (char *buf, int len)
{
	int backupEnc;

	// Check space for input area
	chinput_overspot_resize_window (len);
	
	chinput_overspot_draw_input_panel ();

	// Draw input code
    if (flag_noinput == 0)
		flag_tip=0;

	backupEnc = HZServer.encoding;
	if (HZServer.encoding == HZSERVER_ENCODING_GB2312)
	{
		HZServer.encoding = HZSERVER_ENCODING_GB2312;
		setlocale (LC_CTYPE, gb2312locale);
	}
	if (HZServer.encoding == HZSERVER_ENCODING_GB18030)
	{
		HZServer.encoding = HZSERVER_ENCODING_GB2312;
		setlocale (LC_CTYPE, gb2312locale);
	}
	else if (HZServer.encoding == HZSERVER_ENCODING_BIG5 )
	{
		HZServer.encoding = HZSERVER_ENCODING_BIG5;
		setlocale (LC_CTYPE, big5locale);
	}
	else if (HZServer.encoding == HZSERVER_ENCODING_BIG5HKSCS)
	{
		HZServer.encoding = HZSERVER_ENCODING_BIG5;
		setlocale (LC_CTYPE, big5locale);
	}

#ifdef IMLIB
	if(flag_noinput == 1)
		chinput_util_draw_str (window1, HZServer.normalGC, 24, HZServer.f_height + 7, buf, len);
	else
		chinput_util_draw_str (window1, HZServer.normalGC, 8, HZServer.f_height + 7, buf, len);
#else
	chinput_util_draw_str (window1, HZServer.normalGC, 4, HZServer.f_height+7, buf, len);
#endif

	HZServer.encoding = backupEnc;
	if (HZServer.encoding == HZSERVER_ENCODING_GB2312)
		setlocale (LC_CTYPE, gb2312locale);
	if (HZServer.encoding == HZSERVER_ENCODING_GB18030)
		setlocale (LC_CTYPE, gb18030locale);
	else if (HZServer.encoding == HZSERVER_ENCODING_BIG5 )
		setlocale (LC_CTYPE, big5locale);
	else if (HZServer.encoding == HZSERVER_ENCODING_BIG5HKSCS)
		setlocale (LC_CTYPE, big5hkscslocale);
}

static void chinput_overspot_draw_caret_panel (void)
{
	Display *dpy = HZServer.display;
	Window  win2 = HZServer.window2;
	int w2 = HZServer.hzCwin.w2;
	int h2 = HZServer.hzCwin.h2;

	GC dimgc2 = HZServer.dimGC;
	GC lightgc2 = HZServer.lightGC;
	GC panelgc2 = HZServer.panelGC;

	// Fill Background
	XFillRectangle (dpy, win2, panelgc2, 0, 0, w2, h2);

	// Draw Upper Separator w/Shadow
	XDrawLine (dpy, win2, dimgc2, 1, 23, w2-1, 23);
	XDrawLine (dpy, win2, lightgc2, 1, 24, w2-1, 24);

	// Draw Lower Separator w/Shadow
	XDrawLine (dpy, win2, dimgc2, 1, h2-20, w2-1, h2-20);
	XDrawLine (dpy, win2, lightgc2, 1, h2-19, w2-1, h2-19);

	// Draw Border
	chinput_util_draw_sunken_border (dpy, win2, lightgc2, dimgc2, 0, 0, w2, h2);
}

static void chinput_overspot_draw_caret_label (void)
{
	char buf[80];

//	printf ("chinput_overspot_draw_caret_label (), encoding is %d\n", HZServer.encoding);

	strcpy (buf, "");
	if (HZServer.encoding == HZSERVER_ENCODING_GB2312)
	{
		if (flag_corner)
			strcat (buf, "¡¾È«");
		else
			strcat (buf, "¡¾°ë");
		if (flag_punct)
			strcat (buf, "£ï¡¿");
		else
			strcat (buf, " .¡¿");
		strcat (buf, chinputime[cur_inputmethod].namegb);
	}
	if (HZServer.encoding == HZSERVER_ENCODING_GB18030)
	{
		if (flag_corner)
			strcat (buf, "¡¾È«");
		else
			strcat (buf, "¡¾°ë");
		if (flag_punct)
			strcat (buf, "£ï¡¿");
		else
			strcat (buf, " .¡¿");
		strcat (buf, chinputime[cur_inputmethod].namegb);
	}
	else if (HZServer.encoding == HZSERVER_ENCODING_BIG5 )
	{
		if (flag_corner)
			strcat(buf, "¡i¥þ");
		else
			strcat(buf, "¡i¥b");
		if (flag_punct)
			strcat(buf, "¢÷¡j");
		else
			strcat(buf, "¡O¡j");
		strcat(buf, chinputime[cur_inputmethod].namebig5);
	}
	else if (HZServer.encoding == HZSERVER_ENCODING_BIG5HKSCS )
	{
		if (flag_corner)
			strcat(buf, "¡i¥þ");
		else
			strcat(buf, "¡i¥b");
		if (flag_punct)
			strcat(buf, "¢÷¡j");
		else
			strcat(buf, "¡O¡j");
		strcat(buf, chinputime[cur_inputmethod].namebig5);
	}
	chinput_util_draw_str (window2, HZServer.normalGC, 2, 20, buf, strlen (buf)); 

#ifdef IMLIB
//	Imlib_paste_image (icon_id, im_123, window2, 4, 4, 16, 16);
#endif
}

static void chinput_overspot_input_flush (void)
{
	char mbuf[256];

	bzero (mbuf, 256);

	if (flag_english == True)
		strcpy (mbuf, input_buf);
	else
	{
		// Return 0 indicate emtpy buffer returned
		if (IMM_GetInputDisplay (chinput_imm, mbuf, sizeof (mbuf)))
			; // chinput_print_mbs_hex ("chinput_overspot_input_flush () ...", mbuf, strlen (mbuf));
	}

	flag_noinput = 0;
	if (strlen (mbuf) == 0 && flag_showime == 1)
	{
		flag_noinput = 1;
		if (HZServer.encoding == HZSERVER_ENCODING_GB2312)
		    sprintf (mbuf, "%s", chinputime[cur_inputmethod].namegb);
		if (HZServer.encoding == HZSERVER_ENCODING_GB18030)
		    sprintf (mbuf, "%s", chinputime[cur_inputmethod].namegb);
		else if (HZServer.encoding == HZSERVER_ENCODING_BIG5 )
		    sprintf (mbuf, "%s", chinputime[cur_inputmethod].namebig5);
		else if (HZServer.encoding == HZSERVER_ENCODING_BIG5HKSCS)
		    sprintf (mbuf, "%s", chinputime[cur_inputmethod].namebig5);
	}
	chinput_overspot_draw_input (mbuf, strlen (mbuf));
}

static void chinput_overspot_status_flush (void)
{
	// In overthespot style, I set the status area at the lower
	// part of the root window;

	char buf[128];
	IC *ic = (IC *) chinput_find_ic  (last_icid);

	if (!ic)
		return;

	//only status area style supported
	if (!(ic->input_style & XIMStatusArea))
		return;

	if (ic->reparented)
	{
		// If already reparented check the new position of status window
		chinput_overspot_move_status_window (ic);
		// Map the window and raise it to top window stack
		chinput_overspot_map_status_window ();
	}
	else
	{
		// If not reparented, init all first resize the window to fit the status area
		chinput_overspot_resize_status_window (ic);
		// Reparent it to the status area
		chinput_overspot_reparent_status_window (ic);
		// Map the status window and raise it to top window stack
		chinput_overspot_map_status_window ();
		ic->reparented = 1;
	}
	// Clear status area
	XFillRectangle(display, ic->status_win, offspot_bggc, 0, 0,
			ic->sts_attr.area.width, ic->sts_attr.area.height);

	// Draw preedit string and candidate string
	// in preedit window
	if (HZServer.encoding == HZSERVER_ENCODING_GB2312)
	{
		strcpy (buf, "");
		if (flag_corner)
			strcat (buf, "¡¾È«");
		else
			strcat (buf, "¡¾°ë");
		if (flag_punct)
			strcat (buf, "£ï¡¿");
		else
			strcat (buf, " .¡¿");
		strcat (buf, chinputime[cur_inputmethod].namegb);
	}
	if (HZServer.encoding == HZSERVER_ENCODING_GB18030)
	{
		strcpy (buf, "");
		if (flag_corner)
			strcat (buf, "¡¾È«");
		else
			strcat (buf, "¡¾°ë");
		if (flag_punct)
			strcat (buf, "£ï¡¿");
		else
			strcat (buf, " .¡¿");
		strcat (buf, chinputime[cur_inputmethod].namegb);
	}
	else if (HZServer.encoding == HZSERVER_ENCODING_BIG5)
	{
		strcpy (buf, "");
		if (flag_corner)
			strcat (buf, "¡i¥þ");
		else
			strcat (buf, "¡i¥b");
		if (flag_punct)
			strcat (buf, "¡³¡j");
		else
			strcat (buf, "¡E¡j");
		strcat (buf, chinputime[cur_inputmethod].namebig5);
	}
	else if (HZServer.encoding == HZSERVER_ENCODING_BIG5HKSCS)
	{
		strcpy (buf, "");
		if (flag_corner)
			strcat (buf, "¡i¥þ");
		else
			strcat (buf, "¡i¥b");
		if (flag_punct)
			strcat (buf, "¡³¡j");
		else
			strcat (buf, "¡E¡j");
		strcat (buf, chinputime[cur_inputmethod].namebig5);
	}

#ifdef IMLIB
	Imlib_paste_image (icon_id, im_chinput, ic->status_win, 0, 0, 16, 16);
#endif
	chinput_util_draw_str (ic->status_win, offspot_gc, 16, FONT_ASCENT, buf, strlen (buf));
}

static void chinput_overspot_caret_flush (void)
{
	char mbuf[256];

	if (flag_refresh)
		return;

	// Candidate area
	bzero (mbuf, 256);
	IMM_GetSelectDisplay (chinput_imm, mbuf, sizeof (mbuf));

//	chinput_print_mbs_hex ("chinput_overspot_caret_flush ()...", mbuf, strlen (mbuf));

	chinput_overspot_draw_caret (mbuf, strlen (mbuf));
}

static void chinput_overspot_draw_tip (void)
{
	char tmpbuf[80];
    char buf[80];
    int i, j, y, tipnum;
        
	XMapRaised (display, window2);
	chinput_overspot_draw_caret_panel ();

	strcpy (tmpbuf, TIP_HEADER);
	chinput_util_draw_str (window2, HZServer.normalGC, 10, 20, tmpbuf, strlen(tmpbuf)); 

    tipnum = rand() % NUM_TIPS;
    j = 0;
	y = HZServer.f_height + 26;

    for (i = 0; i < strlen (tip[tipnum]); i++)
    {
        buf[j] = tip[tipnum][i];
        if (j > 21 || tip[tipnum][i] == '\n')
		{ 
            buf[j] = '\0';
            chinput_util_draw_str (window2, HZServer.normalGC, 6, y, buf, strlen (buf)); 
            y += HZServer.f_height + 2;
            if (tip[tipnum][i] == '\n')
				j = 0;
            else 
            {
                buf[0] = tip[tipnum][i];
                j = 1;
            }
        }
        else j++;
    }
	strcpy (tmpbuf, TIP_FOOTER);
	chinput_util_draw_str (window2, HZServer.normalGC, 6, 
			HZServer.hzCwin.h2-5, tmpbuf, strlen (tmpbuf)); 
}

// Set the location of input bar
void chinput_overspot_set_location (IC *ic)
{
	int x0, y0;
	Window child;
	// curx1 for status window, curx2 for candidate window
	int curx1, cury1, curx2, cury2;
	int dw = DisplayWidth (display, screen_num);
	int dh = DisplayHeight (display, screen_num);

	// Focus window is usually the same as client window
	// but in some cases, focus win is none

	// Note:
	//   If the area is a scrolled area, then the location
	// maybe not correct. e.g., kedit with a long line being
	// edited. In such case, there should have a checking
	// for the border of window, but now for simplicity...
	if (ic->focus_win)
	{
//		printf ("chinput_overspot_set_location () : focus_win\n");
//		printf ("... spot_location.x is %d\n", ic->pre_attr.spot_location.x);
//		printf ("... spot_location.y is %d\n", ic->pre_attr.spot_location.y);

		// Try focus win first
		XTranslateCoordinates(display, ic->focus_win, 
				DefaultRootWindow(display),
				ic->pre_attr.spot_location.x + HZSERVER_POS_XOFFSET,
				ic->pre_attr.spot_location.y + HZSERVER_POS_YOFFSET,
				&x0, &y0, &child);
	}
	else if (ic->client_win)
	{
//		printf ("chinput_overspot_set_location () : client_win\n");
//		printf ("... spot_location.x is %d\n", ic->pre_attr.spot_location.x);
//		printf ("... spot_location.y is %d\n", ic->pre_attr.spot_location.y);

		XTranslateCoordinates(display, ic->client_win, 
				DefaultRootWindow(display),
				ic->pre_attr.spot_location.x + HZSERVER_POS_XOFFSET,
				ic->pre_attr.spot_location.y + HZSERVER_POS_YOFFSET,
				&x0, &y0, &child);
	}
	else
	{
//		printf ("chinput_overspot_set_location () : return soon...\n");
//		printf ("... spot_location.x is %d\n", ic->pre_attr.spot_location.x);
//		printf ("... spot_location.y is %d\n", ic->pre_attr.spot_location.y);

		return;
	}

	// Take consider the candidate window also.
	// set the location of Input Window
	curx1 = x0;
	cury1 = y0;

	if (curx1 < 0)
		curx1 = 0;
	if (cury1 < 0)
		cury1 = 0;

	if (curx1 + width_input_win + 4 > dw)
		curx1 = dw - width_input_win - 4;
	if(cury1 + HZSERVER_INPUT_WIN16_HEIGHT + 4 > dh)
		cury1 = dh - HZSERVER_INPUT_WIN16_HEIGHT - 4;

	// Set location of Candidate Window
	curx2 = curx1 + width_input_win + 4;
	cury2 = cury1;

	if (curx2 + HZSERVER_CHOICE_WIN16_WIDTH + 4 > dw)
		curx2 = curx1 - HZSERVER_CHOICE_WIN16_WIDTH - 4;
	if (cury2 + HZSERVER_CHOICE_WIN16_HEIGHT + 4 > dh)
		cury2 = dh - HZSERVER_CHOICE_WIN16_HEIGHT - 4;

	XMoveWindow (display, HZServer.window1, curx1, cury1);
	XMoveWindow (display, HZServer.window2, curx2, cury2);
	if (map_mode == 1)
	{
		XRaiseWindow (display, HZServer.window1);
		XRaiseWindow (display, HZServer.window2);

		if (HZServer.hzVKwin.onflag)
			XRaiseWindow (display, HZServer.window3);
	}

	// Save the position
	HZServer.hzIwin.x = curx1; 
	HZServer.hzIwin.y = cury1;
	HZServer.hzCwin.x2 = curx2;
	HZServer.hzCwin.y2 = cury2;
}

// Draw Selection List
void chinput_overspot_draw_caret (char *buf, int len)
{
	int n; // Line no.
	int flag_first;
	char *ptr, *ptr1, *p; // Draw text in candidate window
	char s[80];
	int y = HZServer.f_height + 26;

//	printf ("chinput_overspot_draw_caret () >> encoding : %d\n", HZServer.encoding);

	// Draw candidate list
	n = 1;
	ptr = buf;

	if (len == 0)
	{
		flag_found = 0;
		XUnmapWindow (display, window2);
		return;
	}
	if (map_mode == 0)
		return;

	selection_count = 0;
	flag_first = 0;
	flag_found = 0;
	flag_up = (strchr (buf, '<')) ? True : False;
	flag_down = (strrchr (buf, '>')) ? True : False;
	
//	chinput_print_mbs_hex ("chinput_overspot_draw_caret...", buf, len);

	while (*ptr++)
	{
		if (*ptr & 0x80)
		{
			flag_found = 1;
			if (flag_first == 0)
			{
				XMapRaised (display, window2);
				chinput_overspot_draw_caret_panel ();
				chinput_overspot_draw_caret_label ();
				flag_first = 1;
			}
			ptr1 = ptr+2;
			while (*ptr1 & 0x80)
				ptr1 += 2;
			if (n == 10)
				n = 0;
			sprintf (s, "%d. %s", n, ptr);
			p = selection_list[selection_count++];
			strncpy (p, ptr, ptr1-ptr);
			p[ptr1-ptr] = '\0';

			chinput_util_draw_str (window2, HZServer.normalGC, 6, y, s, ptr1-ptr+3);
			y += HZServer.f_height + 2;
			n++;
			ptr = ptr1;
			if (!*ptr)
				break;
		}
	}
	if (!flag_found)
		XUnmapWindow (display, window2);

	if (flag_found)
		chinput_overspot_draw_caret_button ();
}

// Unmap the Status Window
void chinput_overspot_hide_status_window (void)
{
	IC *ic = (IC *)chinput_find_ic (last_icid);

//	if(dmode == HZSERVER_DMODE_OVERSPOT)
//		XUnmapWindow(display, window2);

	if (!ic)
		return;
	if (!(ic->input_style & XIMStatusArea))
		return;
	if (ic->status_win)
		XUnmapWindow (display, ic->status_win);
}

void chinput_overspot_flush (void)
{
	// Clear and draw the panel of two windows
	chinput_overspot_input_flush ();

    XUnmapWindow (display, window2);
    chinput_overspot_caret_flush ();
#if 0
	// Auxiliary window flush
    if (flag_tip && map_mode == 1
			&& (HZServer.encoding == HZSERVER_ENCODING_BIG5
			 || HZServer.encoding == HZSERVER_ENCODING_BIG5HKSCS) )
	{
		flag_tip = 0;
		XMapWindow (display, window2);
		chinput_overspot_draw_tip ();
	}
	else
	{
		XUnmapWindow (display, window2);
		chinput_overspot_caret_flush ();
	}
#endif

	// Status window flush, this function only happens if
	// the client use XIMPreeditPosition|XIMStatusArea style
	chinput_overspot_status_flush ();
	XFlush (display);
}

// By the given coordinate (x0, y0), determine if we should mark up a box in 
// selection window; Or, if we should clear all markup
void chinput_overspot_proc_caret_window (int x0, int y0)
{
	int item;
	static int pre_item = -1;

	// Only work for OverSpot and OnSpot Style
	if (dmode != HZSERVER_DMODE_OVERSPOT
			&& dmode != HZSERVER_DMODE_ONSPOT)
		return;

	if (x0 < 6 || x0 > HZServer.hzCwin.s_x2 - 5 ||
			y0 < 27 || y0 > HZServer.hzCwin.h2 - 22)
	{
		chinput_overspot_unmark_selection (pre_item);
		pre_item = -1;
		return;
	}

	// Item from 1 to 10 if within the area
	item = (y0 - HZServer.hzCwin.s_y1) / (HZServer.f_height + 2) + 1;

	//if(item >10 || item < 1) return;
	if (item == pre_item)
		return;
	chinput_overspot_unmark_selection (pre_item);
	pre_item = item;
	chinput_overspot_mark_selection (item);
}

// If user select a Char by pointer (rather than by keyboard)
// We make decision of which char is selected. Then pass to chinput_xim_forward_string  ()
void chinput_overspot_proc_pointer_select (int x0, int y0)
{
	char buf[80];
	int len;
	int item = -1;

	// Decide which key selected
	item = (y0 - HZServer.hzCwin.s_y1) / (HZServer.f_height + 2) + 1;
	if (item == 10)
		item = 0;

	len = chinput_server_set_reply ('0' + item, buf);

	if (len > 1)
		chinput_xim_forward_string (buf, len);
}

// Simulate a page up
void chinput_overspot_proc_pointer_pageup (int x0, int y0)
{
	char buf[80];
	Display *dpy = HZServer.display;
	Window  win2 = HZServer.window2;

	GC dimgc2 = HZServer.dimGC;
	GC lightgc2 = HZServer.lightGC;

	chinput_util_draw_tri_btn (dpy, win2, dimgc2, lightgc2,
			HZServer.hzCwin.b1_x1, HZServer.hzCwin.b1_y1,
			HZServer.hzCwin.b1_x2, HZServer.hzCwin.b1_y2,
			HZServer.hzCwin.b1_x3, HZServer.hzCwin.b1_y3,
			True);
	chinput_util_wait_btn_release();
	chinput_util_draw_tri_btn (dpy, win2, dimgc2, lightgc2,
			HZServer.hzCwin.b1_x1, HZServer.hzCwin.b1_y1,
			HZServer.hzCwin.b1_x2, HZServer.hzCwin.b1_y2,
			HZServer.hzCwin.b1_x3, HZServer.hzCwin.b1_y3,
			False);
	if(!chinput_util_in_box(x0, y0,
			HZServer.hzCwin.b1_x2, HZServer.hzCwin.b1_y1,
			HZServer.hzCwin.b1_x3, HZServer.hzCwin.b1_y3))
		return;
	chinput_server_set_reply ('<', buf);
}

//simulate a page down key
void chinput_overspot_proc_pointer_pagedown (int x0, int y0)
{
	char buf[80];
	Display *dpy = HZServer.display;
	Window  win2 = HZServer.window2;

	GC dimgc2 = HZServer.dimGC;
	GC lightgc2 = HZServer.lightGC;

	chinput_util_draw_tri_btn (dpy, win2, dimgc2, lightgc2,
			HZServer.hzCwin.b2_x1, HZServer.hzCwin.b2_y1,
			HZServer.hzCwin.b2_x2, HZServer.hzCwin.b2_y2,
			HZServer.hzCwin.b2_x3, HZServer.hzCwin.b2_y3,
			True);
	chinput_util_wait_btn_release();
	chinput_util_draw_tri_btn (dpy, win2, dimgc2, lightgc2,
			HZServer.hzCwin.b2_x1, HZServer.hzCwin.b2_y1,
			HZServer.hzCwin.b2_x2, HZServer.hzCwin.b2_y2,
			HZServer.hzCwin.b2_x3, HZServer.hzCwin.b2_y3,
			False);

	if(!chinput_util_in_box(x0, y0,
			HZServer.hzCwin.b2_x1, HZServer.hzCwin.b2_y1,
			HZServer.hzCwin.b2_x3, HZServer.hzCwin.b2_y2))
		return;

	chinput_server_set_reply ('>', buf);
}

// Initialize coordinate and size related variable for OverSpot Style
void chinput_init_server_caret_mode (int x1, int y1, int w1, int h1,
        int x2, int y2, int w2, int h2)
{
	// Geometry of windows of input area and candidate area
	HZServer.hzCwin.x1 = x1;		// Input Area
	HZServer.hzCwin.y1 = y1;
	HZServer.hzCwin.w1 = w1;
	HZServer.hzCwin.h1 = h1;
	HZServer.hzCwin.x2 = x2;		// Candidate area
	HZServer.hzCwin.y2 = y2;
	HZServer.hzCwin.w2 = w2;
	HZServer.hzCwin.h2 = h2;

	// Geometry of "Page Up / Down" button
	HZServer.hzCwin.b1_x1 = 16;		// Page Up
	HZServer.hzCwin.b1_y1 = h2 - 16;
	HZServer.hzCwin.b1_x2 = 8;
	HZServer.hzCwin.b1_y2 = h2 - 6;
	HZServer.hzCwin.b1_x3 = 24;
	HZServer.hzCwin.b1_y3 = h2 - 6;

	HZServer.hzCwin.b2_x1 = 36;		// Page Down
	HZServer.hzCwin.b2_y1 = h2 - 16;
	HZServer.hzCwin.b2_x2 = 44;
	HZServer.hzCwin.b2_y2 = h2 - 6;
	HZServer.hzCwin.b2_x3 = 52;
	HZServer.hzCwin.b2_y3 = h2 - 16;

	HZServer.hzCwin.s_x1 = 2;
	HZServer.hzCwin.s_y1 = 26;
	HZServer.hzCwin.s_x2 = w2 - 2;
	HZServer.hzCwin.s_y2 = h2 - 22;
}
