/*
###
### 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/
###
*/

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

  XIM Implementation by Yu Mingjian(justiny@turbolinux.com.cn)

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


#include "all.h"

//InputModule *inmd=&HZServer.cxtermInput.InputMd;
Boolean xim_use_trigger = False;    /* Static Event Flow is default */
Boolean xim_use_offkey = False;    /* Register OFF Key for Dynamic Event Flow */
Boolean xim_use_tcp = False;       /* Using TCP/IP Transport or not */
Boolean xim_use_local = False;     /* Using Unix domain Tranport or not */
long filter_mask = KeyPressMask;
//static XIMS this_xims;

char *imname = DEFAULT_IMNAME;
XIMStyles *input_styles, *styles2;
XIMTriggerKeys *on_keys, *trigger2;
XIMEncodings *encodings, *encoding2;
char transport[80];

//all of the input styles Chinput supports
static XIMStyle Styles[] =
{
	XIMPreeditPosition | XIMStatusArea,			//OverTheSpot
	XIMPreeditPosition | XIMStatusNothing,		//OverTheSpot
	XIMPreeditPosition | XIMStatusNone,			//OverTheSpot
	XIMPreeditNothing | XIMStatusNothing,		//Root
	XIMPreeditNothing | XIMStatusNone,			//Root
	XIMPreeditCallbacks | XIMStatusCallbacks,	//OnTheSpot
	XIMPreeditCallbacks | XIMStatusArea,		//OnTheSpot
	XIMPreeditCallbacks | XIMStatusNothing,		//OnTheSpot
	XIMPreeditArea | XIMStatusArea,				//OffTheSpot
	XIMPreeditArea | XIMStatusNothing,			//OffTheSpot
	XIMPreeditArea | XIMStatusNone,				//OffTheSpot
	0
};

/* Trigger Keys List */
static XIMTriggerKey Trigger_Keys[] =
{
	{XK_space, ShiftMask, ShiftMask},
	{0L, 0L, 0L}
};

/* Supported Encodings */
static XIMEncoding chEncodings[] =
{
	"COMPOUND_TEXT",
	NULL
};

#define STRBUFLEN 64

static Boolean chinput_xim_is_forward_key (XIMS ims, IMForwardEventStruct *call_data)
{
	char strbuf[STRBUFLEN];
	KeySym keysym;
	XKeyEvent *kev;

	last_icid = call_data->icid;
	last_connectid = call_data->connect_id;

	memset (strbuf, 0, STRBUFLEN);
	kev = (XKeyEvent*)&call_data->event;
	XLookupString (kev, strbuf, STRBUFLEN, &keysym, NULL);

	//control-space/alt-space will NOT be forwarded
	if ( (kev->state & ControlMask) && (kev->state & Mod1Mask) &&
				(keysym == XK_space) )
		return False;
	if ( (kev->state & ControlMask) && (kev->state & Mod1Mask) &&
				(keysym == XK_s || keysym == XK_S) )
		return False;
	if ( (kev->state & ControlMask) && (keysym == XK_space) )
		return False;
	if ( (kev->state & Mod1Mask) && (keysym == XK_space) )
		return False;

	//if the input window not mapped, forward back
	if (map_mode == 0)
		return True;

	//switch input methods circularly
	if (keysym == XK_Shift_L && (kev->state & ControlMask))
		return False;
	if (keysym == XK_Control_L && (kev->state & ShiftMask))
		return False;

	//switch punctuation or corner mode
	if (keysym == XK_space && (kev->state & ShiftMask))
		return False;
	if (keysym == XK_period && (kev->state & ControlMask))
		return False;

	//all keys with modifier will be forwarded
	if ( (kev->state & ControlMask) || (kev->state & Mod1Mask) )
		return True;

	//backspace not forwarded
	if ( keysym == XK_BackSpace || keysym == XK_Linefeed ||
			keysym == XK_Return	|| keysym == XK_Delete )
		return False;
	
	//normal keys
	if( (keysym >= 0x20 && keysym <= 0xff) )
		return False;

	// Escape key, used to cancel inputted stroke
	if (keysym == XK_Escape)
		return False;
	
	//all others
	return True;
}

static Boolean chinput_xim_is_control_key (XIMS ims, IMForwardEventStruct *call_data)
{
	char strbuf[STRBUFLEN];
	KeySym keysym;
	XKeyEvent *kev;

	memset (strbuf, 0, STRBUFLEN);
	kev = (XKeyEvent*)&call_data->event;
	XLookupString (kev, strbuf, STRBUFLEN, &keysym, NULL);

	//control-space will act as control key
	if ( (kev->state & ControlMask) && (kev->state & Mod1Mask) &&
			(keysym == XK_space) )
		return True;
	if ( (kev->state & ControlMask) && (kev->state & Mod1Mask) &&
			(keysym == XK_s || keysym == XK_S) )
		return True;
	if ( (kev->state & ControlMask) && (keysym == XK_space) )
		return True;
	if ( (kev->state & Mod1Mask) && (keysym == XK_space) )
		return True;

	//switch input methods circularly
	if (keysym == XK_Shift_L && (kev->state & ControlMask))
		return True;
	if (keysym == XK_Control_L && (kev->state & ShiftMask))
		return True;

	//switch corner or punctuation mode
	if (keysym == XK_space && (kev->state & ShiftMask))
		return True;
	if (keysym == XK_period && (kev->state & ControlMask))
		return True;

	//all others
	return False;
}

// Determine the incoming Key Process is a control key or not. Pls sync with HotKey.txt
static void chinput_xim_process_control_key (XIMS ims, IMForwardEventStruct *call_data)
{
	char strbuf[STRBUFLEN];
	KeySym keysym;
	XKeyEvent *kev;

	memset (strbuf, 0, STRBUFLEN);
	kev = (XKeyEvent*)&call_data->event;
	XLookupString (kev, strbuf, STRBUFLEN, &keysym, NULL);

	if ((kev->state & ControlMask) && (kev->state & Mod1Mask) 
				&& (keysym == XK_space) )
	{
		chinput_proc_auto_hide ();
	}
	else if ( (kev->state & ControlMask) && (keysym == XK_space) )
	{
		chinput_toggle_window_map ();
		chinput_dock_change_notify ();
	}
	else if ( (kev->state & Mod1Mask) && (keysym == XK_space) )
	{
		// Any problem, switch mode freely??
		// What happen's if the client doesn't some of the mode we offer?
		chinput_switch_style ();
	}
	else if ( (kev->state & ControlMask)
			&& ( (keysym == XK_Shift_L) || (keysym == XK_Shift_R) ) )
	{
		chinput_circulate_inputmethod (1);
		chinput_dock_change_notify ();
	}
	else if ( (kev->state & ShiftMask)
			&& ( (keysym == XK_Control_L) || (keysym == XK_Control_R) ) )
	{
		chinput_circulate_inputmethod (-1);
		chinput_dock_change_notify ();
	}
	else if ( (kev->state & ControlMask) && (kev->state & Mod1Mask) &&
				(keysym == XK_s || keysym == XK_S) )
	{
		// What else? It should be a function to save ZNPY user phrase file.
	}
	else if( (keysym == XK_space) && (kev->state & ShiftMask))
	{
		flag_corner = !flag_corner;
		chinput_set_2byte (flag_corner);
	}
	else if( (keysym == XK_period) && (kev->state & ControlMask))
	{
		flag_punct = !flag_punct;
		chinput_set_punct (flag_punct);
	}
}

static Boolean chinput_xim_open_hdlr (XIMS ims, IMOpenStruct *call_data)
{
	chinput_util_print_dbg_msg ("Debug: call_data->lang.name.%s\n",	call_data->lang.name);
	
	//
	// Please check the maxmium size of xim_connect array!!!
	if (call_data->connect_id > MAX_CONNECT - 1) //FIXME
	{
		chinput_util_print_sys_msg ("Warning: XIM Client connect limit exceed.\n");
		return True;
	}
	xim_connect[call_data->connect_id] = chinput_util_locale_to_enc (call_data->lang.name);

	// Set a server locale as client locale (for switch a default im)
#if 0
	HZServer.encoding = xim_connect[call_data->connect_id];
//	printf ("in open handler, HZServer.encoding is %d.\n", HZServer.encoding);
	switch (HZServer.encoding)
	{
		case HZSERVER_ENCODING_GB2312:
			chinput_switch_input (chinput_get_inputmethod (input_method_gb2312));
			break;
		case HZSERVER_ENCODING_GB18030:
			chinput_switch_input (chinput_get_inputmethod (input_method_gb18030));
			break;
		case HZSERVER_ENCODING_BIG5:
			chinput_switch_input (chinput_get_inputmethod (input_method_big5));
			break;
		case HZSERVER_ENCODING_BIG5HKSCS:
			chinput_switch_input (chinput_get_inputmethod (input_method_big5hkscs));
			break;
		default:
			break;
	}
#endif

	//should map window? Jacky: Not now.
	return True;
}

static Boolean chinput_xim_close_hdlr (XIMS ims, IMCloseStruct *call_data)
{
	//should unmap window?
	return True;
}

static Boolean chinput_xim_create_ic_hdlr (XIMS ims, IMChangeICStruct *call_data)
{
	chinput_create_ic (call_data);
	return True;
}

static Boolean chinput_xim_destroy_ic_hdlr (XIMS ims, IMChangeICStruct *call_data)
{
	chinput_destroy_ic (call_data);
	return True;
}

static Boolean chinput_xim_get_ic_values_hdlr (XIMS ims, IMChangeICStruct *call_data)
{
	chinput_get_ic (call_data);
	return True;
}

static Boolean chinput_xim_set_ic_values_hdlr (XIMS ims, IMChangeICStruct *call_data)
{
	chinput_set_ic (call_data);
	return True;
}

static Boolean chinput_xim_set_ic_focus_hdlr (XIMS ims, IMChangeFocusStruct *call_data)
{
//	printf ("Focus In\n");

	if(flag_encoding == HZSERVER_ENCODING_GB2312)
		setlocale(LC_CTYPE, gb2312locale);
	else if(flag_encoding == HZSERVER_ENCODING_GB18030)
		setlocale(LC_CTYPE, gb18030locale);
	else if(flag_encoding == HZSERVER_ENCODING_BIG5)
		setlocale(LC_CTYPE, big5locale);
	else if(flag_encoding == HZSERVER_ENCODING_BIG5HKSCS)
		setlocale(LC_CTYPE, big5hkscslocale);

	return chinput_proc_focus_in (call_data);
}

static Boolean chinput_xim_unset_ic_focus_hdlr (XIMS ims, IMChangeFocusStruct *call_data)
{
	return chinput_proc_focus_out (call_data);
}

static Boolean chinput_xim_reset_ic_hdlr (XIMS ims, IMResetICStruct *call_data)
{
//	printf ("Reset IC\n");
	return chinput_proc_reset_ic (call_data);
}

static Boolean
chinput_xim_forward_event_hdlr
(XIMS ims, IMForwardEventStruct *call_data)
{
//	printf ("chinput_xim_forward_event_hdlr () >> enc id is %d.\n",
//	xim_connect [call_data->connect_id]);

	if (call_data->event.type != KeyPress)					// Filter non-key press event
	{
//		printf ("... Is not keypress.\n");
		return True;
	}

//	HZServer.encoding = xim_connect [call_data->connect_id];

	if (flag_automode == True)								// Auto-mode
	{
//		printf ("... Automode.\n");
		chinput_proc_set_current_ic (call_data);
	}

	if (chinput_xim_is_forward_key (ims, call_data))		// Forward useless key
	{
		IMForwardEventStruct forward_ev = *((IMForwardEventStruct *)call_data);
		IMForwardEvent(ims, (XPointer)&forward_ev);
//		printf ("ChinputForwardEventHandler: ... Forward Key.\n");
	}
	else if (chinput_xim_is_control_key (ims, call_data))	// Control key do special thing!
	{
		// Testing only
/*		char	output[5] = {0xB3, 0xB5, 0xFA, 0xD3, 0};
		char	*clist[1];
		XTextProperty tp;
		Display *dpy = ims->core.display;

		printf ("... Control Key.\n");

		clist[0] = output;
		setlocale (LC_CTYPE, "zh_TW.Big5");
		XmbTextListToTextProperty (dpy, clist, 1, XCompoundTextStyle, &tp);

		((IMCommitStruct*) call_data)->flag |= XimLookupChars;
		((IMCommitStruct*) call_data)->commit_string = (char *) tp.value;

		IMCommitString (ims, (XPointer) call_data);
		XFree (tp.value);*/

		// End of Testing
		chinput_xim_process_control_key (ims, call_data);
	}
	else													// Use IM modules
	{
		int len;
		char *clist[1];
		char convtext[256];
		char tbuf[256];
		XTextProperty tp;
		Display *dpy = ims->core.display;

		// Real conversion
		chinput_server_proc_xim ((XKeyEvent *) &call_data -> event, convtext, &len);
		
		if (len == 0)
		{
			// The incoming character is control char for the input method.
			return False;
		}
		else if (len == 1)
		{
			IMForwardEventStruct forward_ev = *((IMForwardEventStruct *) call_data);
			IMForwardEvent (ims, (XPointer) &forward_ev);
			return False;
		}

		// flag_single means, input phrase, or input char
		// It is a explicit mode for ZNPY
		if (flag_single == 1)
		{
			convtext[2] = '\0';
			len = 2;
		}
		else if (flag_single == 2 && len > 2)
		{
			convtext[0] = convtext[2];
			convtext[1] = convtext[3];
			convtext[2] = '\0';
			len = 2;
		}

		flag_single = 0;

		flag_encoding = chinput_find_enc (call_data);

		if ( ( (HZServer.encoding == HZSERVER_ENCODING_GB2312)
						|| (HZServer.encoding == HZSERVER_ENCODING_GB18030) )
					&& ( (flag_encoding == HZSERVER_ENCODING_BIG5)
						|| (flag_encoding == HZSERVER_ENCODING_BIG5HKSCS)
						|| (flag_lock == LOCK_BIG5) ) )
		{
			// Convert to Big5 encoding "convtext => tbug"
			chinput_gbstring_to_big5string (convtext, tbuf, len);
			strncpy(convtext, tbuf, len);
		}
		if ( ( (HZServer.encoding == HZSERVER_ENCODING_BIG5)
						|| (HZServer.encoding == HZSERVER_ENCODING_BIG5HKSCS) )
					&& ( (flag_encoding == HZSERVER_ENCODING_GB2312)
						|| (flag_encoding == HZSERVER_ENCODING_GB18030)
						|| (flag_lock == LOCK_GB) ) )
		{
			// Convert to gb encoding
			chinput_big5string_to_gbstring (convtext, tbuf, len);
			strncpy(convtext, tbuf, len);
		}

//		printf ("first byte 0X%X\n", convtext[0]);
//		printf ("second byte 0X%X\n", convtext[1]);
		convtext[len] = 0;
		clist[0] = convtext;

		if (flag_encoding == HZSERVER_ENCODING_GB2312)
		{
			setlocale(LC_CTYPE, HZSERVER_GB2312_LOCALE);
		}
		else if (flag_encoding == HZSERVER_ENCODING_GB18030)
		{
			setlocale(LC_CTYPE, HZSERVER_GB18030_LOCALE);
		}
		else if (flag_encoding == HZSERVER_ENCODING_BIG5)
		{
			setlocale(LC_CTYPE, HZSERVER_BIG5_LOCALE);
		}
		else if (flag_encoding == HZSERVER_ENCODING_BIG5HKSCS )
		{
			setlocale(LC_CTYPE, HZSERVER_BIG5HKSCS_LOCALE);
		}

		XmbTextListToTextProperty(dpy, clist, 1,
                                  XCompoundTextStyle,
                                  &tp);

		((IMCommitStruct*)call_data)->flag |= XimLookupChars;
		((IMCommitStruct*)call_data)->commit_string = (char *)tp.value;
#if 0
		fprintf(stderr, "commiting string...(%s)\n", tp.value);
#endif
		IMCommitString(ims, (XPointer)call_data);

		//It is very important to flush the display of preedit area.
		//or else the display is incorrect.
		if(dmode == HZSERVER_DMODE_ONSPOT)
		{
			chinput_onspot_flush ();
			XUnmapWindow(display, window2);
		}

#if 0
		XmbTextPropertyToTextList(dpy, &tp, &list_return, &count_return);
		fprintf(stderr, "converted back: %s\n", *list_return);
#endif
		XFree(tp.value);
		//fprintf(stderr, "survived so far..\n");

		//hide window
		if(dmode == HZSERVER_DMODE_OVERSPOT)
		{
			if(hmode == HZSERVER_HMODE_AUTO)
			{
				XUnmapWindow(display, window1);
				XUnmapWindow(display, window2);
			}
			else
			{
				XUnmapWindow(display, window2);
			}
		}
		else if(dmode == HZSERVER_DMODE_ONSPOT)
		{
			chinput_onspot_clear ();
		}
		flag_found = 0;
	}
	//return IMPreeditEnd(ims, (XPointer)call_data);
	return True;
}

//simulate keyboard input
//Warning: this maybe dangerous
//If you closed the application, Chinput may exit with core
void chinput_xim_forward_string (char *text, int len)
{
	IMCommitStruct cms;
	XTextProperty tp;
	char *clist[1];
	char tbuf[20];
	char *convtext = text;
	Display *display = this_xims->core.display;

	if(!last_icid) return;

	flag_encoding = chinput_find_enc_by_ic (last_icid);
	text[len] = '\0';

	if ( ( (HZServer.encoding == HZSERVER_ENCODING_GB2312)
					|| (HZServer.encoding == HZSERVER_ENCODING_GB18030) )
				&& ( (flag_encoding == HZSERVER_ENCODING_BIG5)
					|| (flag_encoding == HZSERVER_ENCODING_BIG5HKSCS)
					|| (flag_lock == LOCK_BIG5) ) )
	{
		// Convert to Big5 encoding
		chinput_gbstring_to_big5string (convtext, tbuf, len);
		strncpy(convtext, tbuf, len);
	}
	if ( ( (HZServer.encoding == HZSERVER_ENCODING_BIG5)
					|| (HZServer.encoding == HZSERVER_ENCODING_BIG5HKSCS) )
				&& ( (flag_encoding == HZSERVER_ENCODING_GB2312)
					|| (flag_encoding == HZSERVER_ENCODING_GB18030)
					|| (flag_lock == LOCK_GB) ) )
	{
		// Convert to gb encoding
		chinput_big5string_to_gbstring (convtext, tbuf, len);
		strncpy(convtext, tbuf, len);
	}

	convtext[len] = 0;
	clist[0] = convtext;

	if(flag_encoding == HZSERVER_ENCODING_GB2312)
		setlocale(LC_CTYPE, gb2312locale);
	else if(flag_encoding == HZSERVER_ENCODING_GB18030)
		setlocale(LC_CTYPE, gb18030locale);
	else if(flag_encoding == HZSERVER_ENCODING_BIG5)
		setlocale(LC_CTYPE, big5locale);
	else if(flag_encoding == HZSERVER_ENCODING_BIG5HKSCS)
		setlocale(LC_CTYPE, big5hkscslocale);

	XmbTextListToTextProperty(display, clist, 1,
		XCompoundTextStyle, &tp);

	memset(&cms, 0, sizeof(cms));
	cms.major_code = XIM_COMMIT;
	cms.icid = last_icid;
	cms.connect_id = last_connectid;
	cms.flag = XimLookupChars;
	cms.commit_string = (char *)tp.value;
	IMCommitString(this_xims, (XPointer)&cms);
	XFree(tp.value);
}

int chinput_xim_forward_event (unsigned long keysym, Boolean f_shift,
	Boolean f_control, Boolean f_alt)
{
	IMForwardEventStruct fe;
	XEvent xkp;
	
	if (!last_icid)
	    return 0;
	
	// Create event
	xkp.type                = KeyPress;
	xkp.xkey.type           = KeyPress;
	xkp.xkey.display        = display;
	xkp.xkey.serial         = 0L;
	xkp.xkey.send_event     = True;
	xkp.xkey.display        = display;
	xkp.xkey.x = xkp.xkey.y = xkp.xkey.x_root = xkp.xkey.y_root = 0;
	xkp.xkey.time           = chinput_util_get_time();
	xkp.xkey.same_screen    = True;
	xkp.xkey.subwindow      = None;
	xkp.xkey.window         = window3;
	xkp.xkey.root           = DefaultRootWindow(display);
	xkp.xkey.keycode        = XKeysymToKeycode(display, keysym);
	printf ("Keycode is %d\n", xkp.xkey.keycode);
	xkp.xkey.state          = (f_shift ? ShiftMask : 0) |
			  (f_control ? ControlMask : 0) |
			  (f_alt ? Mod1Mask : 0);

	memset(&fe, 0, sizeof(fe));
	fe.major_code 		= XIM_FORWARD_EVENT;
	fe.icid 		= last_icid;
	fe.connect_id 		= last_connectid;
	fe.sync_bit 		= 1;
	fe.serial_number 	= 0L;
	memcpy(&(fe.event), &xkp, sizeof(fe.event));
	IMForwardEvent(this_xims, (XPointer)&fe);
	printf ("After keypress\n");

	fe.serial_number 	= 1L;
	xkp.xkey.type           = KeyRelease;
	xkp.xkey.time           = chinput_util_get_time();
	memcpy(&(fe.event), &xkp, sizeof(fe.event));
	IMForwardEvent(this_xims, (XPointer)&fe);
	printf ("After keyrelease\n");

	// Where is black and US dollar.
	return 1;
}

static Boolean chinput_xim_trigger_notify_hdlr (XIMS ims, IMTriggerNotifyStruct *call_data)
{
	if (call_data->flag == 0) /* on key */
	{
	/* Here, the start of preediting is notified from IMlibrary, which
	   is the only way to start preediting in case of Dynamic Event
	   Flow, because ON key is mandatary for Dynamic Event Flow. */
		return True;
	}
	else if (xim_use_offkey && call_data->flag == 1)    /* off key */
	{
	/* Here, the end of preediting is notified from the IMlibrary, which
	   happens only if OFF key, which is optional for Dynamic Event Flow,
	   has been registered by IMOpenIM or IMSetIMValues, otherwise,
	   the end of preediting must be notified from the IMserver to the
	   IMlibrary. */
		return True;
	}
	else
	{
		/* never happens */
		return False;
	}
}

static Boolean chinput_xim_preedit_start_reply_hdlr (XIMS ims, IMPreeditCBStruct *call_data)
{
	return True;
}

static Boolean chinput_xim_preedit_caret_reply_hdlr (XIMS ims, IMPreeditCBStruct *call_data)
{
	return True;
}

static Boolean chinput_xim_str_conversion_reply_hdlr (XIMS ims, IMStrConvCBStruct *call_data)
{
	return True;
}

Boolean chinput_xim_proto_hdlr (XIMS ims, IMProtocol *call_data)
{
	static long long logNum = 0;
	logNum ++;
	switch (call_data->major_code)
	{
		case XIM_OPEN: 	
//			fprintf (stderr, "%lld >> XIM_OPEN event caught\n", logNum);
			return chinput_xim_open_hdlr (ims, 
					(IMOpenStruct *)call_data);

		case XIM_CLOSE:	
//			fprintf (stderr, "%lld >> XIM_CLOSE event caught\n", logNum);
			return chinput_xim_close_hdlr (ims, 
					(IMCloseStruct *)call_data);

		case XIM_CREATE_IC:
//			fprintf (stderr, "%lld >> XIM_CREATE_IC event caught\n", logNum);
			return chinput_xim_create_ic_hdlr (ims, 
					(IMChangeICStruct *)call_data);

		case XIM_DESTROY_IC:
//			fprintf (stderr, "%lld >> XIM_DESTROY_IC event caught\n", logNum);
			return chinput_xim_destroy_ic_hdlr (ims, 
					(IMChangeICStruct *)call_data);

		case XIM_SET_IC_VALUES: 
//			fprintf (stderr, "%lld >> XIM_SET_IC_VALUES event caught\n", logNum);
			return chinput_xim_set_ic_values_hdlr (ims, 
					(IMChangeICStruct *)call_data);

		case XIM_GET_IC_VALUES: 
//			fprintf (stderr, "%lld >> XIM_GET_IC_VALUES event caught\n", logNum);
			return chinput_xim_get_ic_values_hdlr (ims, 
					(IMChangeICStruct *)call_data);

		case XIM_FORWARD_EVENT: 
//			fprintf (stderr, "%lld >> XIM_FORWARD_EVENT event caught\n", logNum);
			return chinput_xim_forward_event_hdlr (ims, 
					(IMForwardEventStruct *)call_data);

		case XIM_SET_IC_FOCUS:
//			fprintf (stderr, "%lld >> XIM_SET_IC_FOCUS event caught\n", logNum);
			return chinput_xim_set_ic_focus_hdlr (ims, 
					(IMChangeFocusStruct *)call_data);

		case XIM_UNSET_IC_FOCUS:
//			fprintf (stderr, "%lld >> XIM_UNSET_IC_FOCUS event caught\n", logNum);
			return chinput_xim_unset_ic_focus_hdlr (ims, 
					(IMChangeFocusStruct *)call_data);

		case XIM_RESET_IC: 	
//			fprintf (stderr, "%lld >> XIM_RESET_IC event caught\n", logNum);
			return chinput_xim_reset_ic_hdlr (ims, 
					(IMResetICStruct *)call_data);

		case XIM_TRIGGER_NOTIFY:
//			fprintf (stderr, "%lld >> XIM_TRIGGER_NOTIFY event caught\n", logNum);
			return chinput_xim_trigger_notify_hdlr (ims, 
					(IMTriggerNotifyStruct *)call_data);

		case XIM_PREEDIT_START_REPLY: 
//			fprintf (stderr, "%lld >> XIM_PREEDIT_START_REPLY event caught\n", logNum);
			return chinput_xim_preedit_start_reply_hdlr (ims, 
					(IMPreeditCBStruct *)call_data);

		case XIM_PREEDIT_CARET_REPLY:
//			fprintf (stderr, "%lld >> XIM_PREEDIT_CARET_REPLY event caught\n", logNum);
			return chinput_xim_preedit_caret_reply_hdlr (ims, 
					(IMPreeditCBStruct *)call_data);

		case XIM_STR_CONVERSION_REPLY:
//			fprintf (stderr, "%lld >> XIM_STR_CONVERSION_REPLY event caught\n", logNum);
			return chinput_xim_str_conversion_reply_hdlr (ims, 
					(IMStrConvCBStruct *)call_data);

		default: 
//			fprintf (stderr, "%lld >> UNKNOWN event caught\n", logNum);
			chinput_util_print_sys_err ( "chinput_xim_proto_hdlr: Unknown major code.\n" );
			break;
	}
	return True;
}

void chinput_xim_init (void)
{
	if ((input_styles = (XIMStyles *)malloc(sizeof(XIMStyles))) == NULL)
	{
		fprintf(stderr, "Can't allocate\n");
		return;
	}
	input_styles->count_styles = sizeof(Styles)/sizeof(XIMStyle) - 1;
	input_styles->supported_styles = Styles;

	if ((on_keys=(XIMTriggerKeys *)malloc(sizeof(XIMTriggerKeys)))==NULL)
	{
		fprintf(stderr, "Can't allocate\n");
        	return;
	}
	on_keys->count_keys = sizeof(Trigger_Keys)/sizeof(XIMTriggerKey) - 1;
	on_keys->keylist = Trigger_Keys;

	if ((encodings = (XIMEncodings *)malloc(sizeof(XIMEncodings)))==NULL)
	{
		fprintf(stderr, "Can't allocate\n");
		return;
	}
	encodings->count_encodings = sizeof(chEncodings)/sizeof(XIMEncoding)-1;
	encodings->supported_encodings = chEncodings;

	if (xim_use_local)
	{
		char hostname[64];
		char *address = "/tmp/.ximsock";
		gethostname(hostname, 64);
		sprintf(transport, "local/%s:%s", hostname, address);
	}
	else if (xim_use_tcp)
	{
		char hostname[64];
		int port_number = 9010;
		gethostname(hostname, 64);
		sprintf(transport, "tcp/%s:%d", hostname, port_number);
	}
	else
	{
		strcpy(transport, "X/");
	}

//	printf ("IMOpenIM, imlocale is %s.\n", imlocale);
	this_xims = IMOpenIM(display,
		IMServerWindow, 	window1,	//input window
		IMModifiers, 		"Xi18n",	//X11R6 protocol
		IMServerName, 		imname,		//XIM server name
		IMLocale, 			imlocale,	//XIM server locale
		IMServerTransport, 	transport,	//Comm. protocol
		IMInputStyles, 		input_styles,	//faked styles
		IMEncodingList, 	encodings,
		IMProtocolHandler, 	chinput_xim_proto_hdlr,
		IMFilterEventMask, 	filter_mask,
		NULL);
	if (this_xims == (XIMS)NULL)
	{
        	fprintf(stderr, "Can't Open Input Method Service:\n");
        	fprintf(stderr, "\tInput Method Name :%s\n", imname);
        	fprintf(stderr, "\tTranport Address:%s\n", transport);
        	return;
	}
#if 0
	if(xim_use_trigger)
	{
		if (xim_use_offkey)
			IMSetIMValues(this_xims,
				IMOnKeysList, 	on_keys,
				IMOffKeysList, 	on_keys,
				NULL);
		else
			IMSetIMValues(this_xims,
				IMOnKeysList, 	on_keys,
				NULL);
	}
#endif
	free (input_styles);
	free (on_keys);
	free (encodings);
}

