/*
###
### 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>
### WWW:         http://www.turbolinux.com.cn/ZWinPro/
### FTP:         ftp://ftp.turbolinux.com.cn/pub/ZWinPro/
###
*/

#include "all.h"
#include "config.h"

#ifdef IMLIB
#include "icons/chinput.xpm"
#include "icons/123.xpm"
#endif

static char *chinput_get_conf_value (char *line)
{
	char *ptr, *ptr2;
	line[strlen (line)-1] = '\0';       //change the last '\n' to '\0'

	ptr = strchr (line, '=') + 1;       //locate the ptr after the first '='

	// There should be some ' ' or '\t' between '=' and the value.
	while (*ptr == ' ' || *ptr == '\t')
		ptr++;							//skip ' ' and '\t'

	// We can just cut from the end of cut.
	// So that, we can remain the intened ' ' char within a value.
	ptr2 = ptr + strlen (ptr) - 1;
#if 0
	while ( ! ((*ptr2 >= 0x30 && *ptr2 <= 0x39)
			|| (*ptr2 >= 0x41 && *ptr2 <= 0x5A)
			|| (*ptr2 >= 0x61 && *ptr2 <= 0x7A)) )
#endif
	while ((*ptr2 == 0x20) || (*ptr2 == 0x09))
		ptr2--;
	*(ptr2+1) = '\0';

	return ptr;
}

static int chinput_match_conf_name (char *str1, char *str2)
{
	return strncmp (str1, str2, strlen (str2));
}

void chinput_check_pyinput (void)
{
	char fname[256];
	struct stat st;

	sprintf(fname, "%s/.pyinput", getenv("HOME"));
	if ( stat(fname, &st) == -1)
	{
		// create dir
		mkdir(fname, 0755);
	}
}

// Default setting of the program
void chinput_init_resource (void)
{
	char locale_buf[20];

	/* load definition from header file */
	strcpy (font_latin,		HZSERVER_FONT);
	strcpy (font_gb2312,	HZSERVER_GB2312_FONT);
	strcpy (font_gb18030,	HZSERVER_GB18030_FONT);
	strcpy (font_big5, 		HZSERVER_BIG5_FONT);
	strcpy (font_big5hkscs, HZSERVER_BIG5HKSCS_FONT);
	strcpy (gb2312locale,	HZSERVER_GB2312_LOCALE);
	strcpy (gb18030locale,	HZSERVER_GB18030_LOCALE);
	strcpy (big5locale,		HZSERVER_BIG5_LOCALE);
	strcpy (big5hkscslocale, HZSERVER_BIG5HKSCS_LOCALE);
	strcpy (color_dim, 		HZSERVER_DIM_COLOR);
	strcpy (color_light,	HZSERVER_LIGHT_COLOR);
	strcpy (color_panel,	HZSERVER_PANEL_COLOR);
	strcpy (color_hz,		HZSERVER_HZ_COLOR);
	strcpy (color_led,		HZSERVER_LED_COLOR);
	strcpy (color_bar,		HZSERVER_BAR_COLOR);

	flag_corner = False;	//half
	flag_punct = False;	//chinese punctuation
	flag_lock = LOCK_NONE;	//encoding not locked
	flag_ec  = True;	//chinese output
	flag_english = False;	//no english
	flag_single = 0;	//not single choice
	memset (input_buf, 0, 80);
	map_mode = 0;		//not mapped when started
	index_ime = 0;		//ime list index
	boxdrawn = False;
	dmode = HZSERVER_DMODE_OVERSPOT;
	hmode = HZSERVER_HMODE_NO;
	strcpy (input_method_gb2312, "ZNPY");
	strcpy (input_method_gb18030, "ZNPY");
	strcpy (input_method_big5, "PY");
	strcpy (input_method_big5hkscs, "CangJie");
	strcpy (dict_path, IMDIR);
	flag_showime = True;
	flag_automode = True;
	flag_client = HZSERVER_AREAMODE_CLIENT;	//client decide the area and position
	width_input_win = HZSERVER_INPUT_WIN16_WIDTH;
	width_inputbar = HZSERVER_COLS;
	flag_up = False;
	flag_down = False;
	prev_dmode = -1;
//	hwmode = False;
	// docking live is assumed to be started after chinput.
	docking_live = 0;

	/* enable more than one locales at the same time */
	strcpy (imlocale, IMLOCALE);

	setlocale (LC_ALL,"");
	strcpy (locale_buf, setlocale (LC_CTYPE,NULL));
	// Set system default locale
	if ( !strcmp (locale_buf, HZSERVER_BIG5_LOCALE))
	{
		strcpy (deflocale, big5locale);
		flag_encoding = HZSERVER_ENCODING_BIG5;
		HZServer.encoding = HZSERVER_ENCODING_BIG5;
	}
	else if ( !strcmp (locale_buf, HZSERVER_BIG5HKSCS_LOCALE ))
	{
		strcpy (deflocale, big5hkscslocale);
		flag_encoding = HZSERVER_ENCODING_BIG5HKSCS;
		HZServer.encoding = HZSERVER_ENCODING_BIG5HKSCS;
	} 
	else if ( !strcmp (locale_buf, HZSERVER_GB2312_LOCALE ))
	{
		strcpy (deflocale, gb2312locale);
		flag_encoding = HZSERVER_ENCODING_GB2312;
		HZServer.encoding = HZSERVER_ENCODING_GB2312;
	} 
	else if ( !strcmp (locale_buf, HZSERVER_GB18030_LOCALE ))
	{
		strcpy (deflocale, gb18030locale);
		flag_encoding = HZSERVER_ENCODING_GB18030;
		HZServer.encoding = HZSERVER_ENCODING_GB18030;
	}
	else
	{
		strcpy (deflocale, HZSERVER_DEFAULT_LOCALE);
		flag_encoding = HZSERVER_ENCODING_DEFAULT;
		HZServer.encoding = HZSERVER_ENCODING_DEFAULT;
	} 
	// As we still haven't initialize the IME data, we can't do anything on this
	// In other words, we have no need to start loading input modules or 
	// Set inputmethod ID, until our program have to.
}

//This will overwrite the default value of program
void chinput_load_rcfile (void)
{
	FILE *fp = NULL;
	char line[255];

	// try ~/.chinput first
	if (getenv("HOME"))
	{
		sprintf(line, "%s/.chinput", (char *)getenv("HOME"));
		fp = fopen(line, "r");
	}
	// system ad file
	if(fp == NULL)
	{
		if((fp = fopen(RESOURCEFILE, "r")) == NULL)
		{
			chinput_util_print_sys_err ("chinput: Chinput.ad not found.\n");
			chinput_util_exit();
		}
	}

	while (fgets(line, 256, fp))
	{
		if (line[0] == '!')
			continue;
		if (line[0] == '\n')
			continue;
		if (!chinput_match_conf_name (line, "chinput.gb2312locale"))
		{
			char *ptr = chinput_get_conf_value(line);
			strcpy (gb2312locale, ptr);
		}
		if (!chinput_match_conf_name (line, "chinput.gb18030locale"))
		{
			char *ptr = chinput_get_conf_value(line);
			strcpy (gb18030locale, ptr);
		}
		else if (!chinput_match_conf_name (line, "chinput.big5locale"))
		{
			char *ptr = chinput_get_conf_value (line);
			strcpy (big5locale, ptr);
		}
		else if (!chinput_match_conf_name (line, "chinput.big5hkscslocale"))
		{
			char *ptr = chinput_get_conf_value (line);
			strcpy (big5hkscslocale, ptr);
		}
		else if (!chinput_match_conf_name (line, "chinput.dmode"))
		{
			char *ptr = chinput_get_conf_value (line);
			if (!strcmp (ptr, "AUTO"))
			{
				flag_automode = True;
				dmode = HZSERVER_DMODE_OVERSPOT;
			}
			else if (!strcmp (ptr, "ROOT"))
			{
				dmode = HZSERVER_DMODE_ROOT;
				flag_automode = False;
			}
			else if (!strcmp (ptr, "OVERSPOT") || !strcmp(ptr, "CARET"))
			{
				dmode = HZSERVER_DMODE_OVERSPOT;
				flag_automode = False;
			}
			else if (!strcmp (ptr, "ONSPOT"))
			{
				dmode = HZSERVER_DMODE_ONSPOT;
				flag_automode = False;
			}
			else if (!strcmp (ptr, "OFFSPOT"))
			{
				dmode = HZSERVER_DMODE_OFFSPOT;
				flag_automode = False;
			}
		}
		else if (!chinput_match_conf_name(line, "chinput.hmode"))
		{
			if (!strcmp (chinput_get_conf_value (line), "AUTO"))
			{
				hmode = HZSERVER_HMODE_AUTO;
			}
			else
			{
				hmode = HZSERVER_HMODE_NO;
			}
		}
		else if (!chinput_match_conf_name (line, "chinput.cmode"))
		{
			if (!strcmp (chinput_get_conf_value (line), "AUTO"))
				cmode = HZSERVER_CMODE_AUTO;
			else
				cmode = HZSERVER_CMODE_NO;
		}
		else if (!chinput_match_conf_name (line, "chinput.areamode"))
		{
			if (!strcmp (chinput_get_conf_value (line), "CLIENT"))
				flag_client = HZSERVER_AREAMODE_CLIENT;
			else
				flag_client = HZSERVER_AREAMODE_SERVER;
		}
		else if (!chinput_match_conf_name (line, "chinput.dictionary"))
		{
			strcpy (dict_path, chinput_get_conf_value (line));
		}
		else if (!chinput_match_conf_name (line, "chinput.showime"))
		{
			if (!strcmp (chinput_get_conf_value (line), "YES"))
				flag_showime = 1;
			else
				flag_showime = 0;
		}
		else if (!chinput_match_conf_name (line, "chinput.font"))
		{
			strcpy (font_latin, chinput_get_conf_value(line));
		}
		else if (!chinput_match_conf_name (line, "chinput.gb2312font"))
		{
			strcpy (font_gb2312, chinput_get_conf_value(line));
		}
		else if (!chinput_match_conf_name (line, "chinput.gb18030font"))
		{
			strcpy (font_gb18030, chinput_get_conf_value(line));
		}
		else if (!chinput_match_conf_name (line, "chinput.big5font"))
		{
//			printf ("before chinput_get_conf_value, string is : %s\n", line);
			strcpy (font_big5, chinput_get_conf_value(line));
		}
		else if (!chinput_match_conf_name (line, "chinput.big5hkscsfont"))
		{
			strcpy (font_big5hkscs, chinput_get_conf_value(line));
		}
		else if (!chinput_match_conf_name (line, "chinput.width"))
		{
			width_inputbar = atoi(chinput_get_conf_value (line));
		}
		else if (!chinput_match_conf_name (line, "chinput.dimcolor"))
		{
			strcpy (color_dim, chinput_get_conf_value (line));
		}
		else if (!chinput_match_conf_name (line, "chinput.lightcolor"))
		{
			strcpy (color_light, chinput_get_conf_value (line));
		}
		else if (!chinput_match_conf_name (line, "chinput.panelcolor"))
		{
			strcpy (color_panel, chinput_get_conf_value (line));
		}
		else if (!chinput_match_conf_name (line, "chinput.hzcolor"))
		{
			strcpy (color_hz, chinput_get_conf_value(line));
		}
		else if (!chinput_match_conf_name (line, "chinput.ledcolor"))
		{
			strcpy (color_led, chinput_get_conf_value (line));
		}
		else if (!chinput_match_conf_name (line, "chinput.barcolor"))
		{
			strcpy (color_bar, chinput_get_conf_value (line));
		}
//		else if (!chinput_match_conf_name (line, "chinput.hwtimeout"))
//		{
//			hw_timeout = atoi (chinput_get_conf_value(line));
//		}
		else if (!chinput_match_conf_name (line, "chinput.inputmethod.big5hkscs"))
		{
			strcpy (input_method_big5hkscs, chinput_get_conf_value (line));
		}
		else if (!chinput_match_conf_name (line, "chinput.inputmethod.big5"))
		{
			strcpy (input_method_big5, chinput_get_conf_value (line));
		}
		else if(!chinput_match_conf_name (line, "chinput.inputmethod.gb2312"))
		{
			strcpy (input_method_gb2312, chinput_get_conf_value (line));
		}
		else if(!chinput_match_conf_name (line, "chinput.inputmethod.gb18030"))
		{
			strcpy (input_method_gb18030, chinput_get_conf_value (line));
		}
	}
	fclose (fp);
}

// Loading Resource File
// Chinput will search for .chinput at your home directory first,
// if not found, it will load the system file /usr/lib/Chinput/Chinput.ad
// Each IME record in the config file will store as a record in 
// chinputime[index]. For those with "favourite=NO", we will ignore it.
void chinput_load_rcime (void)
{
	FILE *fp;
	char fname[256];
	char line[256];

	sprintf(fname, "%s/.chinput", getenv("HOME"));
	fp = fopen(fname, "r");
	if (!fp)
	{
		fp = fopen(RESOURCEFILE, "r");
		if(!fp)
		{
			chinput_util_print_sys_err ("Cannot open resource file Chinput.ad\n");
			chinput_util_exit();
		}
	} 
	while (fgets(line, 256, fp))
	{
		if(line[0] == '[')    //find an entry
		{
			char *ptr;
			ptr = strchr(line, ']');
			*ptr = '\0';

			strcpy(chinputime[index_ime].name, line+1);

			if (!fgets(line, 256, fp))
				return;
			strcpy(chinputime[index_ime].namegb, chinput_get_conf_value(line));

			if (!fgets(line, 256, fp))
				return;
			strcpy(chinputime[index_ime].namebig5, chinput_get_conf_value(line));

			if (!fgets(line, 256, fp))
				return;
			strcpy(chinputime[index_ime].encoding,chinput_get_conf_value(line));

			if (!fgets(line, 256, fp))
				return;
			strcpy(chinputime[index_ime].fname, chinput_get_conf_value(line));

			if (!fgets(line, 256, fp))
				return;
			strcpy(chinputime[index_ime].module, chinput_get_conf_value(line));

			// If favourite is YES, increment,
			// If favourite is NO, dont' increment the index.
			// So that in next loop, the we use same record set.
			index_ime ++;
			if (!fgets(line, 256, fp))
				return;
			if (!strcmp(chinput_get_conf_value(line), "NO"))
				index_ime --;
		}
	}
	fclose(fp);
}

void chinput_parse_parameters (int argc, char **argv)
{
	int i;

	if(argc < 2)
		return;

	for (i=1; i<argc; i++)
	{
		if (!strcmp (argv[i], "-h"))
			chinput_usage ();

		if (!strcmp (argv[i], "-gb2312"))
		{
            strcpy (imlocale, HZSERVER_GB2312_LOCALE);
			strcpy (deflocale, HZSERVER_GB2312_LOCALE);
			HZServer.encoding = HZSERVER_ENCODING_GB2312;
			flag_encoding = HZSERVER_ENCODING_GB2312;
		}
		if (!strcmp (argv[i], "-gb18030"))
		{
			strcpy (imlocale, HZSERVER_GB18030_LOCALE);
			strcpy (deflocale, HZSERVER_GB18030_LOCALE);
			HZServer.encoding = HZSERVER_ENCODING_GB18030;
			flag_encoding = HZSERVER_ENCODING_GB18030;
		}
		if (!strcmp (argv[i], "-big5"))
		{
			strcpy (imlocale, HZSERVER_BIG5_LOCALE);
			strcpy (deflocale, HZSERVER_BIG5_LOCALE);
			HZServer.encoding = HZSERVER_ENCODING_BIG5;
			flag_encoding = HZSERVER_ENCODING_BIG5;
		}
		if (!strcmp (argv[i], "-big5hkscs"))
		{
			strcpy (imlocale, HZSERVER_BIG5HKSCS_LOCALE);
			HZServer.encoding = HZSERVER_ENCODING_BIG5HKSCS;
			flag_encoding = HZSERVER_ENCODING_BIG5HKSCS;
		}

		if (!strcmp (argv[i], "-root"))
		{
			dmode = HZSERVER_DMODE_ROOT;
			flag_automode = False;
		}
		if (!strcmp (argv[i], "-overspot"))
		{
			dmode = HZSERVER_DMODE_OVERSPOT;
			flag_automode = False;
		}
		if (!strcmp (argv[i], "-onspot"))
		{
			dmode = HZSERVER_DMODE_ONSPOT;
			flag_automode = False;
		}
		if (!strcmp (argv[i], "-offspot"))
		{
			dmode = HZSERVER_DMODE_OFFSPOT;
			flag_automode = False;
		}
	}
}

void chinput_init_display (void)
{
	if ( (display=XOpenDisplay(NULL)) == NULL )
	{
		fprintf(stderr, "\033[33;1m");
		fprintf(stderr, "Error: cannot connect to X server \n");
		fprintf(stderr, "\033[0m");
		chinput_util_exit();
	}
}

void chinput_init_server_atom (void)
{
	Window twin;

	hz_protocol_atom = XInternAtom (display, HZ_PROTOCOL_ATOM, False);
	hz_input_atom    = XInternAtom (display, HZ_INPUT_ATOM,    False);
	hz_output_atom   = XInternAtom (display, HZ_OUTPUT_ATOM,   False);
	hz_config_atom   = XInternAtom (display, HZ_CONFIG_ATOM,   False);
	hz_reply_atom    = XInternAtom (display, HZ_REPLY_ATOM,    False);
	hz_query_atom    = XInternAtom (display, HZ_QUERY_ATOM,    False);


	if ((twin = XGetSelectionOwner(display, hz_protocol_atom)) != None )
	{
		fprintf(stderr, "\033[33;1m");
		fprintf(stderr, "Chinese Input Server is already activated.\n");
		fprintf(stderr, "\033[0m");
		chinput_util_exit();
	}

	/* claim the owner of these selections */
	XSetSelectionOwner (display, hz_protocol_atom, window1, CurrentTime);
	XSetSelectionOwner (display, hz_input_atom,    window1, CurrentTime);
	XSetSelectionOwner (display, hz_output_atom,   window1, CurrentTime);
	XSetSelectionOwner (display, hz_reply_atom,    window1, CurrentTime);
	XSetSelectionOwner (display, hz_query_atom,    window1, CurrentTime);
	XSetSelectionOwner (display, hz_config_atom,   window1, CurrentTime);
}

void chinput_init_server_font (void)
{
	if ( ! chinput_get_fontstruct (&font_info, font_latin) )
	{
		chinput_util_print_sys_err
				("Warning: Cannot load user defined fonts, %s\n", 
				font_latin);

		if ( ! chinput_get_fontstruct
						(&font_info, HZSERVER_FONT) )
		{
			chinput_util_print_sys_err
					("Error: Cannot load default fonts, %s\n", 
					HZSERVER_FONT);
			chinput_util_exit ();
		}
	}

	if ( ! chinput_get_fontstruct (&hzgb2312font_info, font_gb2312) )
	{
		chinput_util_print_sys_err
				("Warning: Cannot load user defined fonts, %s\n", 
				font_gb2312);

		if ( ! chinput_get_fontstruct
						(&hzgb2312font_info, HZSERVER_GB2312_FONT) )
		{
			chinput_util_print_sys_err
					("Error: Cannot load default fonts, %s\n", 
					HZSERVER_GB2312_FONT);
			chinput_util_exit ();
		}
	}

	if ( ! chinput_get_fontstruct (&hzgb18030font_info, font_gb18030) )
	{
		chinput_util_print_sys_err
				("Warning: Cannot load user defined fonts, %s\n", 
				font_gb18030);

		if ( ! chinput_get_fontstruct
						(&hzgb18030font_info, HZSERVER_GB18030_FONT) )
		{
			chinput_util_print_sys_err
					("Error: Cannot load default fonts, %s\n", 
					HZSERVER_GB18030_FONT);
			chinput_util_exit ();
		}
	}

	if ( ! chinput_get_fontstruct (&hzbig5font_info, font_big5) )
	{
		chinput_util_print_sys_err
				("Warning: Cannot load user defined fonts, %s\n",
				 font_big5);

		if ( ! chinput_get_fontstruct
						(&hzbig5font_info, HZSERVER_BIG5_FONT) )
		{
			chinput_util_print_sys_err
					("Error: Cannot load default fonts, %s\n", 
					HZSERVER_BIG5_FONT);
			chinput_util_exit ();
		}
	}

	if ( ! chinput_get_fontstruct (&hzbig5hkscsfont_info, font_big5hkscs) )
	{
		chinput_util_print_sys_err
				("Warning: Cannot load user defined fonts, %s\n",
				 font_big5hkscs);

		if ( ! chinput_get_fontstruct
						(&hzbig5hkscsfont_info, HZSERVER_BIG5HKSCS_FONT) )
		{
			chinput_util_print_sys_err
					("Error: Cannot load default fonts, %s\n", 
					HZSERVER_BIG5HKSCS_FONT);
			chinput_util_exit ();
		}
	}

	HZServer.f_width =
		hzgb2312font_info->max_bounds.rbearing
        + hzgb2312font_info->min_bounds.lbearing;
	HZServer.f_height =
		hzgb2312font_info->max_bounds.ascent
        + hzgb2312font_info->max_bounds.descent;
}

void chinput_init_server_gc (void)
{
	char **missing_list;
	int  missing_count;
	char *def_string;
	char fontname[256];

	//
	// Create fontset for all supported locale
	setlocale (LC_CTYPE, HZSERVER_GB2312_LOCALE);
	sprintf(fontname, "%s,%s", font_latin, font_gb2312);
	if ((fontset_gb2312 = XCreateFontSet(display, fontname, &missing_list,
			&missing_count, &def_string)) == NULL)
	{
		chinput_util_print_sys_err ("Error : XCreateFontSet() with GB2312 font!\n");
		chinput_util_err_exit ();
	}
	else if (missing_list)
	{
		chinput_util_print_sys_msg ("Warning: XCreateFontSet () with GB2312 font!\n");
		while (missing_count)
		{
			chinput_util_print_sys_msg
				("         Missing font for %s.\n", missing_list[--missing_count]);
		}
		XFreeStringList (missing_list);
	}

	setlocale (LC_CTYPE, HZSERVER_GB18030_LOCALE);
	sprintf(fontname, "%s,%s,%s", font_latin, font_gb2312, font_gb18030);
	if ((fontset_gb18030= XCreateFontSet(display, fontname, &missing_list,
			&missing_count, &def_string)) == NULL)
	{
		chinput_util_print_sys_err ("Error : XCreateFontSet() with GB18030 font!\n");
		chinput_util_err_exit ();
	}
	else if (missing_list)
	{
		chinput_util_print_sys_msg ("Warning: XCreateFontSet () with GB2312 font!\n");
		while (missing_count)
		{
			chinput_util_print_sys_msg
				("         Missing font for %s.\n", missing_list[--missing_count]);
		}
		XFreeStringList (missing_list);
	}

	setlocale (LC_CTYPE, HZSERVER_BIG5_LOCALE);
	sprintf (fontname, "%s,%s", font_latin, font_big5);
	if ((fontset_big5 = XCreateFontSet(display, fontname, &missing_list,
			&missing_count, &def_string)) == NULL)
	{
		chinput_util_print_sys_err ("Error : XCreateFontSet() with Big5 font!\n");
		chinput_util_err_exit ();
	}
	else if (missing_list)
	{
		chinput_util_print_sys_msg ("Warning: XCreateFontSet () with GB2312 font!\n");
		while (missing_count)
		{
			chinput_util_print_sys_msg
				("         Missing font for %s.\n", missing_list[--missing_count]);
		}
		XFreeStringList (missing_list);
	}

	setlocale (LC_CTYPE, HZSERVER_BIG5HKSCS_LOCALE);
	sprintf (fontname, "%s,%s", font_latin, font_big5hkscs);
	if ((fontset_big5hkscs = XCreateFontSet(display, fontname, &missing_list,
			&missing_count, &def_string)) == NULL)
	{
		chinput_util_print_sys_err ("Error : XCreateFontSet() with Big5hkscs font!\n");
		chinput_util_err_exit ();
	}
	else if (missing_list)
	{
		chinput_util_print_sys_msg ("Warning: XCreateFontSet () with GB2312 font!\n");
		while (missing_count)
		{
			chinput_util_print_sys_msg
				("         Missing font for %s.\n", missing_list[--missing_count]);
		}
		XFreeStringList (missing_list);
	}
	setlocale (LC_CTYPE, "");

	chinput_get_color_gc (window1, &HZServer.dimGC, color_dim);
	chinput_get_color_gc (window1, &HZServer.lightGC, color_light);
	chinput_get_color_gc (window1, &HZServer.panelGC, color_panel);
	chinput_get_color_gc (window1, &HZServer.ledGC, color_led);
	chinput_get_color_gc (window1, &HZServer.barGC, color_bar);

	chinput_get_font_gc (window1,  &HZServer.normalGC, font_info, color_hz);
	chinput_get_font_gc (window1,  &offspot_gc, font_info, "#FFFF00");
	chinput_get_font_gc (window1,  &offspot_bggc, font_info, "#0000FF");
	
	HZServer.display = display;
	HZServer.window1 = window1;
	HZServer.window2 = window2;
	HZServer.window3 = window3;

	HZServer.lockw  = None;
	HZServer.focus  = False;
}

static void chinput_init_server_input_area (int x, int y, int w, int h)
{
	/* hanzi input area size */
	HZServer.hzIwin.rows = HZSERVER_ROWS;
	HZServer.hzIwin.cols = HZSERVER_COLS;
	HZServer.hzIwin.x = x;
	HZServer.hzIwin.y = y;
	HZServer.hzIwin.width = w;
	HZServer.hzIwin.height = h;
}

static void chinput_init_server_button_area (int bx, int by, int bw, int bh)
{
	/* button area size, which is on the right of input area */
	HZServer.hzBwin.flag = True;
	HZServer.hzBwin.x = bx;
	HZServer.hzBwin.y = by;
	HZServer.hzBwin.width = bw;
	HZServer.hzBwin.height = bh;
	HZServer.hzBwin.ledx1 = HZServer.hzIwin.width + bw - 25;
	HZServer.hzBwin.ledy1 = 5;
	HZServer.hzBwin.ledx2 = HZServer.hzIwin.width + bw - 5;
	HZServer.hzBwin.ledy2 = 11;
	HZServer.hzBwin.btnx1 = HZServer.hzIwin.width + bw - 23;
	HZServer.hzBwin.btny1 = HZServer.hzIwin.height - 10;
	HZServer.hzBwin.btnx2 = HZServer.hzIwin.width + bw - 7;
	HZServer.hzBwin.btny2 = HZServer.hzIwin.height - 10;
	HZServer.hzBwin.btnx3 = HZServer.hzIwin.width + bw - 15;
	HZServer.hzBwin.btny3 = HZServer.hzIwin.height - 3;

	// two buttons
	HZServer.hzBwin.q_x1 = HZServer.hzBwin.ledx1 - 26;
	HZServer.hzBwin.q_y1 = HZServer.hzBwin.ledy1;
	HZServer.hzBwin.q_x2 = HZServer.hzBwin.q_x1 + 19;
	HZServer.hzBwin.q_y2 = HZServer.hzBwin.q_y1 + 19;

	HZServer.hzBwin.p_x1 = HZServer.hzBwin.q_x1;
	HZServer.hzBwin.p_y1 = HZServer.hzBwin.q_y1 + 22;
	HZServer.hzBwin.p_x2 = HZServer.hzBwin.p_x1 + 19;
	HZServer.hzBwin.p_y2 = HZServer.hzBwin.p_y1 + 19;
	HZServer.hzBwin.offset = 16;
}

static void chinput_init_server_browse_area (int kx, int ky, int kw, int kh,
	int offx1, int offy1, int offx2, int offy2)
{
	// keyboard area... popup when press the lower-right button
	// Not the Virtual Keyboard, but the character browse window
	HZServer.hzKwin.onflag = False;
	HZServer.hzKwin.offx1 = offx1;
	HZServer.hzKwin.offy1 = offy1;
	HZServer.hzKwin.offx2 = offx2;
	HZServer.hzKwin.offy2 = offy2;
	HZServer.hzKwin.x = kx;
	HZServer.hzKwin.y = ky;
	HZServer.hzKwin.width = kw;
	HZServer.hzKwin.height = kh;
	HZServer.hzKwin.rows = 10;
	HZServer.hzKwin.cols = 10;
	HZServer.hzKwin.prevx2 = kw - 50;
	HZServer.hzKwin.prevy2 = HZServer.hzIwin.height + kh - 20;
	HZServer.hzKwin.prevx3 = kw - 40;
	HZServer.hzKwin.prevy3 = HZServer.hzIwin.height + kh - 30;
	HZServer.hzKwin.prevx1 = kw - 40;
	HZServer.hzKwin.prevy1 = HZServer.hzIwin.height + kh - 10;
	HZServer.hzKwin.nextx1 = kw - 10;
	HZServer.hzKwin.nexty1 = HZServer.hzIwin.height + kh - 20;
	HZServer.hzKwin.nextx3 = kw - 20;
	HZServer.hzKwin.nexty3 = HZServer.hzIwin.height + kh - 30;
	HZServer.hzKwin.nextx2 = kw - 20;
	HZServer.hzKwin.nexty2 = HZServer.hzIwin.height + kh - 10;

	switch(HZServer.encoding)
	{
		case HZSERVER_ENCODING_GB2312:
		case HZSERVER_ENCODING_GB18030:
			HZServer.hzKwin.cur           = 0x81;
			HZServer.hzKwin.first_start   = 0x81;
			HZServer.hzKwin.first_end     = 0xfe;
			HZServer.hzKwin.second_start  = 0x40;
			HZServer.hzKwin.second_end    = 0x7e;
			HZServer.hzKwin.second_start2 = 0x80;
			HZServer.hzKwin.second_end2   = 0xfe;
			break;

		case HZSERVER_ENCODING_BIG5:
		case HZSERVER_ENCODING_BIG5HKSCS:
			HZServer.hzKwin.cur = 0xa1;
			HZServer.hzKwin.first_start   = 0xa1;
			HZServer.hzKwin.first_end     = 0xf9;
			HZServer.hzKwin.second_start  = 0x40;
			HZServer.hzKwin.second_end    = 0x7e;
			HZServer.hzKwin.second_start2 = 0xa1;
			HZServer.hzKwin.second_end2   = 0xfe;
			break;

		default:
			break;
	}
}

void chinput_init_icon (void)
{
#ifdef  IMLIB
	int w,h;
	icon_id = Imlib_init(display);
	//icon chinput
	im_chinput = Imlib_create_image_from_xpm_data (icon_id,icon_chinput);
	w = im_chinput->rgb_width;
	h = im_chinput->rgb_height;
	Imlib_render(icon_id, im_chinput, w, h);
	//icon 123
	im_123 = Imlib_create_image_from_xpm_data (icon_id,icon_123);
	w = im_123->rgb_width;
	h = im_123->rgb_height;
	Imlib_render(icon_id, im_123, w, h);
#endif
}

void chinput_init_daemon (void)
{
	pid_t id;

	id = fork();
	if (id == -1)
		return;			//error in fork
	else if (id > 0)
		exit(0);		//parent
	else
		return;			//child
}

static void chinput_exit_sig_hdlr (int sig_num, siginfo_t *sig_info, void *misc)
{
	if (sig_info->si_signo == SIGTERM)
	{
		chinput_util_free_all ();
		exit (0);
	}
}

void chinput_init_signal_handler (void)
{
	struct sigaction sig_act;

	memset (&sig_act, 0, sizeof (struct sigaction));
	sig_act.sa_sigaction = chinput_exit_sig_hdlr;
	sig_act.sa_flags = 0 | SA_SIGINFO;

	if (sigaction (SIGTERM, &sig_act, NULL) < 0)
	{
		perror ("Cannot Initialize Signal Handler");
		chinput_util_exit ();
	}
}

void chinput_init_windows (void)
{
	// Normal input window
	int winx=0, winy=0, winw=0, winh=0;
	int bwinx=0, bwiny=0, bwinw=0, bwinh=0;
	int kwinx=0, kwiny=0, kwinw=0, kwinh=0;
	int offx1=0, offx2=0, offy1=0, offy2=0;

	// Winmode input window
	int win1x, win1y, win1w, win1h;
	int win2x, win2y, win2w, win2h;
	int win3x, win3y, win3w, win3h;

	winx = HZSERVER_STARTX;
	winy = HZSERVER_STARTY;
	winw = HZSERVER_16_WIDTH2;
	winh = HZSERVER_16_HEIGHT2;
	bwinx = HZSERVER_16_WIDTH2;
	bwiny = 0;
	bwinw = HZSERVER_BWIN16_WIDTH;
	bwinh = HZSERVER_BWIN16_HEIGHT;
	kwinx = 0;
	kwiny = HZSERVER_16_HEIGHT2;
	kwinw = HZSERVER_16_WIDTH2 + HZSERVER_BWIN16_WIDTH;
	kwinh = HZSERVER_KWIN16_HEIGHT;
	offx1 = HZSERVER_KWIN16_XOFFSET1;
	offy1 = HZSERVER_KWIN16_YOFFSET1;
	offx2 = HZSERVER_KWIN16_XOFFSET2;
	offy2 = HZSERVER_KWIN16_YOFFSET2;

	win1x = winx;
	win1y = winy;
	win1w = HZSERVER_INPUT_WIN16_WIDTH;
    // we should calculate this...  "HZServer.f_height"
	win1h = HZServer.f_height + 14;

	win2x = win1x + HZSERVER_WIN16_XOFFSET;
	win2y = win1y;
	win2w = HZSERVER_CHOICE_CHARS * HZServer.f_width + HZServer.f_width / 2 + 4;
    // we should calculate this...  "HZServer.f_height"
	win2h = 26 + 22 + (HZServer.f_height + 2) * 10;

	win3x = winx;
	win3y = winy;
	win3w = HZSERVER_VK_WIDTH;
	win3h = HZSERVER_VK_HEIGHT;

	// Create the window  with input area and button area
	if (dmode == HZSERVER_DMODE_ROOT)
		window1 = chinput_util_create_win (winx, winy, winw + bwinw, winh);
	else
		window1 = chinput_util_create_win (win1x, win1y, win1w, win1h);
	
	// Window for  Candidate Selection (aka caret)
	window2 = chinput_util_create_win (win2x, win2y, win2w, win2h);
	// Virtual Keyboard
	window3 = chinput_util_create_win (win3x, win3y, win3w, win3h);

	chinput_init_server_input_area (winx, winy, winw, winh);
	chinput_init_server_button_area (bwinx, bwiny, bwinw, bwinh);
	chinput_init_server_browse_area (kwinx, kwiny, kwinw, kwinh,
			offx1, offy1, offx2, offy2);
	// Initialize for Overspot Input and Candidate Window
	chinput_init_server_caret_mode (win1x, win1y, win1w, win1h,
			win2x, win2y, win2w, win2h);
	chinput_init_server_virtual_keyboard (win3x, win3y, win3w, win3h);
}

void chinput_init_ime (void)
{
	flag_refresh = 1;		//need not get display/input buffer

	//open ime server (:unicon:TLS_LibMain.cpp)
	LibOpen ();
	chinput_imserver = IMM_OpenClient("127.0.0.1", 9010);

	// -1 == nothing; Don't open any IM at the first stat. Save memory!
	// Becoz many people start IM Server from xinitrc script.
	// But it may not the case, that, everytime, he'll use the IM Server
	cur_inputmethod = -1;
//	chinput_load_inputmethod (cur_inputmethod);

	XSetErrorHandler (chinput_util_err_hdlr);

	//XFlush(display);
}
