4.4BSD/usr/src/contrib/X11R5-lib/lib/X/Xsi/XCrIC.c

/*
 * $XConsortium: XCrIC.c,v 1.34 92/07/29 13:54:58 rws Exp $
 */

/*
 * Copyright 1990, 1991 by OMRON Corporation
 * Copyright 1991 by the Massachusetts Institute of Technology
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the names of OMRON and MIT not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  OMRON and MIT make no representations
 * about the suitability of this software for any purpose.  It is provided
 * "as is" without express or implied warranty.
 *
 * OMRON AND MIT DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL OMRON OR MIT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE. 
 *
 *	Author:	Seiji Kuwari	OMRON Corporation
 *				kuwa@omron.co.jp
 *				kuwa%omron.co.jp@uunet.uu.net
 */				

#include <stdio.h>
#include "Xlibint.h"
#include "Xi18nint.h"
#include "XIMlibint.h"
#if NeedVarargsPrototypes
# include <stdarg.h>
# define Va_start(a,b) va_start(a,b)
#else
# include <varargs.h>
# define Va_start(a,b) va_start(a)
#endif

#if __STDC__ && !defined(NORCONST)
#define RConst const
#else
#define RConst /**/
#endif

/*
 * Free the input context.
 */
void
_XipDestroyIC(supic)
    XIC supic;
{
    XipIC ic = (XipIC)supic;
    XipIM im = (XipIM)ic->core.im;
    /* check xim and ic*/
    if (im->fd >= 0) {
	ximDestroyICReq	req;
	ximEventReply	reply;

	req.reqType = XIM_DestroyIC;
	req.length = sz_ximDestroyICReq;
	req.xic = ic->icid;
	if ((_XipWriteToIM(im, (char *)&req, sz_ximDestroyICReq) >= 0) &&
	    (_XipFlushToIM(im) >= 0)) {
	    for (;;) {
		if ((_XipReadFromIM(im, (char *)&reply, sz_ximEventReply) < 0)
		    || (reply.state == 0xffff)) {
		    return;
		}
		if (reply.detail == XIM_CALLBACK) {
		    /*
		     * Call the callback routines.
		     */
		    if (_XipCallCallbacks(ic) < 0) {
			return;
		    }
		} else {
		    break;
		}
	    }
	}
    }

    _XUnregisterFilter(im->core.display, ic->core.focus_window,
		       ic->prototype_filter, (XPointer)ic);

    if (ic->mb) _XlcFreeLocale(ic->mb);
    if (ic->wc) _XlcFreeLocale(ic->wc);
#ifdef	XML
    if (ic->xlc_num > 0) {
	int i;

	for (i = 0; i < ic->xlc_num; i++) {
	    _XlcFreeLocale(ic->mb_temp[i]);
	    _XlcFreeLocale(ic->wc_temp[i]);
	}
    }
    if (ic->mb_temp) Xfree(ic->mb_temp);
    if (ic->wc_temp) Xfree(ic->wc_temp);
    if (ic->values.using_language) Xfree(ic->values.using_language);
    if (ic->values.current_language) Xfree(ic->values.current_language);
#endif	/* XML */
    if (ic->ct_buf) Xfree(ic->ct_buf);
    if (ic->wc_buf) Xfree(ic->wc_buf);
    (void) _XipFreeAllICQueue(ic);
}

static RConst XICMethodsRec ic_methods = {
    _XipDestroyIC,
    _XipSetICFocus,
    _XipUnsetICFocus,
    _XipSetICValues,
    _XipGetICValues,
    _XipmbResetIC,
    _XipwcResetIC,
    _XipmbLookupString,
    _XipwcLookupString
};

static Status
_StringToPixel(display, colormap, name, pixel)
    Display *display;
    Colormap colormap;
    char *name;
    unsigned long *pixel;
{
    XColor c, e_c;
    Status status;

    if (name[0] == '#') {
	status = XParseColor(display, colormap, name, &c);
	if (status != 0) {
	    status = XAllocColor(display, colormap, &c);
	}
    } else {
	status = XAllocNamedColor(display, colormap, name, &c, &e_c);
    }
    if (status == 0) {
	return(-1);
    } else {
	*pixel = c.pixel;
	return(0);
    }
}

unsigned long
_XipReadRdb(display, ic, mask, rdb, res_name, res_class)
    Display *display;
    XipIC ic;
    unsigned long mask;
    XrmDatabase rdb;
    char *res_name;
    char *res_class;
{
    XipIM im = ipIMofIC(ic);
    unsigned long ret_mask = 0;
    char name_prefix[256], class_prefix[256];
    char res_name_buf[256], res_class_buf[256];
    /*
    char def_fontset[256];
    */
#ifdef	XML
    char def_language[256];
#endif	/* XML */
    char def_fg_name[256], def_bg_name[256];
    unsigned long def_fg, def_bg;
    char *str_type[20];
    XrmValue value;
    XIMArg args[8], pre_args[4], st_args[4];
    int count = 0, pre_count = 0, st_count = 0;
    Colormap colormap, def_colormap;
    XWindowAttributes win_info;

    if (rdb == NULL) {
	return(0);
    }
    if (ic->core.client_window) {
	XGetWindowAttributes(display, ic->core.client_window, &win_info);
    } else {
	XGetWindowAttributes(display,
			     RootWindow(display, DefaultScreen(display)),
			     &win_info);
    }
    def_colormap = win_info.colormap;
    if (res_name == NULL || *res_name == '\0'
	|| res_class == NULL || *res_class == '\0') {
	strcpy(name_prefix, "*.");
	strcpy(class_prefix, "*.");
    } else {
	strcpy(name_prefix, res_name);
	strcpy(class_prefix, res_class);
	strcat(name_prefix, ".");
	strcat(class_prefix, ".");
    }
    if (!(mask & ((1 << ICForeground) | (1 << (ICForeground + StatusOffset))))){
	strcpy(res_name_buf, name_prefix);
	strcpy(res_class_buf, class_prefix);
	strcat(res_name_buf, "foreground");
	strcat(res_class_buf, "Foreground");
	if (XrmGetResource(rdb, res_name_buf, res_class_buf,
			   str_type, &value) == True) {
	    strncpy(def_fg_name, value.addr, (int)value.size);
	    if (ic->core.preedit_attr.colormap) {
		colormap = ic->core.preedit_attr.colormap;
	    } else {
		colormap = def_colormap;
	    }
	    if (_StringToPixel(display, colormap, def_fg_name, &def_fg) == 0) {
		if (!(mask & (1 << ICForeground))) {
		    pre_args[pre_count].name = (char *)XNForeground;
		    pre_args[pre_count].value = (XPointer)def_fg;
		    pre_count++;
		}
		if (!(mask & (1 << (ICForeground + StatusOffset)))) {
		    st_args[st_count].name = (char *)XNForeground;
		    st_args[st_count].value = (XPointer)def_fg;
		    st_count++;
		}
	    } else {
		fprintf(stderr, "XIM: Could not Alloc color \"%s\".",
			def_fg_name);
	    }
	}
    }
    if (!(mask & ((1 << ICBackground) | (1 << (ICBackground + StatusOffset))))){
	strcpy(res_name_buf, name_prefix);
	strcpy(res_class_buf, class_prefix);
	strcat(res_name_buf, "background");
	strcat(res_class_buf, "Background");
	if (XrmGetResource(rdb, res_name_buf, res_class_buf,
			   str_type, &value) == True) {	
	    strncpy(def_bg_name, value.addr, (int)value.size);	
	    if (ic->core.preedit_attr.colormap) {
		colormap = ic->core.preedit_attr.colormap;
	    } else {
		colormap = def_colormap;
	    }
	    if (_StringToPixel(display, colormap, def_bg_name, &def_bg) == 0) {
		if (!(mask & (1 << ICBackground))) {
		    pre_args[pre_count].name = (char *)XNBackground;
		    pre_args[pre_count].value = (XPointer)def_bg;
		    pre_count++;
		}
		if (!(mask & (1 << (ICBackground + StatusOffset)))) {
		    st_args[st_count].name = (char *)XNBackground;
		    st_args[st_count].value = (XPointer)def_bg;
		    st_count++;
		}
	    } else {
		fprintf(stderr, "XIM: Could not Alloc color \"%s\".",
			def_bg_name);
	    }	
	}	
    }
    /*
    if (!(mask & ((1 << ICFontSet) | (1 << (ICFontSet + StatusOffset))))) {
	strcpy(res_name_buf, name_prefix);	
	strcpy(res_class_buf, class_prefix);
	strcat(res_name_buf, "fontSet");
	strcat(res_class_buf, "FontSet");
	if (XrmGetResource(rdb, res_name_buf, res_class_buf,
			   str_type, &value) == True) {
	    strncpy(def_fontset, value.addr, value.size);
	    if (!(mask & (1 << ICFontSet))) {
		pre_args[pre_count].name = (char *)XNFontSet;
		pre_args[pre_count].value = (XPointer)def_fontset;
		pre_count++;
	    }
	    if (!(mask & (1 << (ICFontSet + StatusOffset)))) {
		st_args[st_count].name = (char *)XNForeground;
		st_args[st_count].value = (XPointer)def_fg;
		st_count++;
	    }
	}
    }
    */
#ifdef	XML
    if (!(mask & (1 << ICUsingLanguage))) {
	strcpy(res_name_buf, name_prefix);	
	strcpy(res_class_buf, class_prefix);
	strcat(res_name_buf, "usingLanguage");
	strcat(res_class_buf, "usingLanguage");
	if (XrmGetResource(rdb, res_name_buf, res_class_buf,
			   str_type, &value) == True) {
	    strncpy(def_language, value.addr, (int)value.size);
	    args[count].name = (char *)XNUsingLanguage;
	    args[count].value = (XPointer)def_language;
	    count++;
	}
    }
#endif	/* XML */
    if(pre_count) {
	pre_args[pre_count].name = (char *)NULL;
	(void)_XipICSetAttrValues(im, pre_args, &ic->core.preedit_attr,
				  &ret_mask, 0);
    }
    if(st_count) {
	st_args[st_count].name = (char *)NULL;
	(void)_XipICSetAttrValues(im, st_args, &ic->core.status_attr,
				  &ret_mask, StatusOffset);
    }
    if (count) {
	args[count].name = (char *)NULL;
	(void)_XipICSetValues(ic, args, &ret_mask);
    }
    return(ret_mask);
}

Bool
_XipCreateDefIC(im)
    XipIM im;
{
    im->default_ic = (XipIC)Xcalloc(1, sizeof(XipICRec));
    if (im->default_ic == NULL) {
	return False;
    }
    im->default_ic->core.im = (XIM)im;

    im->default_mask = _XipReadRdb(im->core.display, im->default_ic,
				(unsigned long)0,
				im->core.rdb, im->core.res_name,
				im->core.res_class);
    return True;
}


/*
 * Create an input context within the input method, 
 * and return a pointer the input context ti the caller.
 */
XIC
_XipCreateIC(supim, args)
    XIM supim;
    XIMArg *args;
{
    XipIM		im = (XipIM)supim;
    XipIC		ic;
    ximCreateICReq	req;
    ximCreateICReply	reply;
    ximEventReply	reply1;
    unsigned long	mask;
    extern Bool		_XipBackEndFilter();
#ifdef	XML
    char		*p, **nls_list, **l;
    unsigned int	i, n = 0;
    XLocale		xlc;
#endif	/* XML */

    /*
     * If im is not specified or the file descripter is not available,
     * return NULL.
     */
    if (im->fd < 0) {
	return(NULL);
    }

    if ((ic = (XipIC)Xcalloc(1, sizeof(XipICRec))) == NULL) {
	return(NULL);
    }

    mask = im->default_mask;
    if (mask)
	bcopy((char *)&im->default_ic->values, (char *)&ic->values,
	      sizeof(struct _ICValues));

    ic->methods = (XICMethods) &ic_methods;
    ic->prototype_filter = _XipBackEndFilter;
    ic->core.im = supim;
    (void)_XipICSetValues(ic, args, &mask);

    req.reqType = XIM_CreateIC;
    req.length = sz_ximCreateICReq + strlen(im->client_data);

    if ((_XipWriteToIM(im, (char *)&req, sz_ximCreateICReq) < 0) ||
	(_XipWriteToIM(im, im->client_data, strlen(im->client_data)) < 0) ||
	(_XipFlushToIM(im) < 0)) {
	return(NULL);
    }

    if (im->core.rdb && ic->values.res_name && ic->values.res_class) {
	mask |= _XipReadRdb(im->core.display, ic, mask, im->core.rdb,
			 ic->values.res_name, ic->values.res_class);
    }
	
#ifdef	XML
    if (im->xlc != NULL) {
#endif	/* XML */
	ic->mb = _XlcDupLocale(im->xlc);
	ic->wc = _XlcDupLocale(im->xlc);
#ifdef	XML
	ic->xlc_num = 0;
	ic->mb_temp = NULL;
	ic->wc_temp = NULL;
	n = strlen(im->xlc->xlc_db->lc_name) + 1;
	if ((p = Xmalloc(n)) == NULL) return(NULL);
	strcpy(p, im->xlc->xlc_db->lc_name);
	p[n - 1] = 0;
	ic->values.using_language = p;
	mask |= (1 << ICUsingLanguage);
    } else {
	ic->mb = NULL;
	ic->wc = NULL;
	ic->xlc_num = 0;
	if ((ic->mb_temp = (XLocale*)Xmalloc(sizeof(XLocale) * 32)) == NULL) {
	    return(NULL);
	}
	if ((ic->wc_temp = (XLocale*)Xmalloc(sizeof(XLocale) * 32)) == NULL) {
	    return(NULL);
	}
	_XlcListLocale(&nls_list);
	for (l = nls_list; *l; l++) {
	    xlc = _XlcMakeLocale(*l);
	    if (!xlc)
		continue;
	    ic->mb_temp[ic->xlc_num] = xlc;
	    ic->wc_temp[ic->xlc_num] = _XlcDupLocale(xlc);
	    n += strlen(ic->mb_temp[ic->xlc_num]->xlc_db->lc_name) + 1;
	    ic->xlc_num++;
	}
	Xfree((char *)nls_list);
	if ((p = Xmalloc(n)) == NULL) return(NULL);
	p[0] = '\0';
	for (i = 0; i < ic->xlc_num; i++) {
	    strcat(p, ic->mb_temp[i]->xlc_db->lc_name);
	    strcat(p, ";");
	}
	p[n - 1] = '\0';
	ic->values.using_language = p;
	mask |= (1 << ICUsingLanguage);
    }
#endif /* XML */


    /*
     * Attempt to send IC data to the input manager. If sending failed,
     * free IC structure and return NULL.
     */
    _XipSendICValues(ic, mask);
    ic->max_of_ct = ic->max_of_wc = 0;
    ic->ct_buf = NULL;
    ic->wc_buf = NULL;
    for (;;) {
	if ((_XipReadFromIM(im, (char *)&reply1, sz_ximEventReply) < 0) ||
	    (reply1.state == 0xffff)) {
	    goto _err_ret;
	}
	if (reply1.detail == XIM_CALLBACK) {
	    /*
	     * Call the callback routines.
	     */
	    if (_XipCallCallbacks(ic) < 0) {
		goto _err_ret;
	    }
	} else if (reply1.detail == XIM_IC) {
	    if (_XipReadFromIM(im, (char *)&reply, sz_ximCreateICReply) < 0) {
		goto _err_ret;
	    }
	    if (reply.state != 0) {
		goto _err_ret;
	    }
	    ic->icid = reply.xic;
	    break;
	} else {
	    break;
	}
    }

    /*
     * Attempt to get current IC data from the input manager.
     */
    _XipReceiveICValues(ic, (unsigned long)ICAllMask);

#ifdef	XML
    if (ic->xlc_num > 0) {
	for (i = 0; i < ic->xlc_num; i++) {
	    if (!strcmp(ic->values.current_language,
			ic->mb_temp[i]->xlc_db->lc_name)) {
		ic->mb = ic->mb_temp[i];
		ic->wc = ic->wc_temp[i];
		break;
	    }
	}
	if (ic->mb == NULL) {
	    ic->mb = ic->mb_temp[0];
	    ic->wc = ic->wc_temp[0];
	}
    }
#endif	/* XML */
    return((XIC)ic);

_err_ret:
    if (ic->mb) _XlcFreeLocale(ic->mb);
    if (ic->wc) _XlcFreeLocale(ic->wc);
#ifdef  XML
    if (ic->xlc_num > 0) {
	for (i = 0; i < ic->xlc_num; i++) {
	    _XlcFreeLocale(ic->mb_temp[i]);
	    _XlcFreeLocale(ic->wc_temp[i]);
	}
    }
    if (ic->mb_temp) Xfree(ic->mb_temp);
    if (ic->wc_temp) Xfree(ic->wc_temp);
    if (ic->values.using_language) Xfree(ic->values.using_language);
#endif  /* XML */
    Xfree((char *)ic);
    return(NULL);
}

/*
 * Reset the input context. 
 */
wchar_t *
_XipwcResetIC(ic)
    XIC ic;		/* specified the input context to reset*/
{
    XipIM im = ipIMofIC((XipIC)ic);
    ximResetICReq	req;
    ximEventReply	reply;

    /*
     * If im is not specified or the file descripter is not available,
     * return NULL.
     */
    if (im->fd < 0) {
	return((wchar_t *)NULL);
    }
    req.reqType = XIM_ResetIC;
    req.length = sz_ximResetICReq;
    req.xic = ((XipIC)ic)->icid;
    if ((_XipWriteToIM(im, (char *)&req, sz_ximResetICReq) >= 0) &&
	(_XipFlushToIM(im) >= 0)) {
	for (;;) {
	    if ((_XipReadFromIM(im, (char *)&reply, sz_ximEventReply) < 0) ||
		(reply.state == 0xffff)) {
		return((wchar_t *)NULL);
	    }
	    if (reply.detail == XIM_CALLBACK) {
		/*
		 * Call the callback routines.
		 */
		if (_XipCallCallbacks(ic) < 0) {
		    return((wchar_t *)NULL);
		}
	    } else {
		break;
	    }
	}
    }
    return((wchar_t *)NULL);
}

char *
_XipmbResetIC(ic)
    XIC ic;		/* specified the input context to reset*/
{
    XipIM im = ipIMofIC((XipIC)ic);
    ximResetICReq	req;
    ximEventReply	reply;

    /*
     * If im is not specified or the file descripter is not available,
     * return NULL.
     */
    if (im->fd < 0) {
	return(NULL);
    }
    req.reqType = XIM_ResetIC;
    req.length = sz_ximResetICReq;
    req.xic = ((XipIC)ic)->icid;
    if ((_XipWriteToIM(im, (char *)&req, sz_ximResetICReq) >= 0) &&
	(_XipFlushToIM(im) >= 0)) {
	for (;;) {
	    if ((_XipReadFromIM(im, (char *)&reply, sz_ximEventReply) < 0) ||
		(reply.state == 0xffff)) {
		return(NULL);
	    }
	    if (reply.detail == XIM_CALLBACK) {
		/*
		 * Call the callback routines.
		 */
		if (_XipCallCallbacks(ic) < 0) {
		    return(NULL);
		}
	    } else {
		break;
	    }
	}
    }
    return(NULL);
}

#ifdef	XML
void
_XipChangeLocale(ic, lc_name)
    XipIC ic;
    char *lc_name;
{
    XLocale xlc;
    int i;

    for (i = 0; i < ic->xlc_num; i++) {
	if ((!strcmp(lc_name, ic->mb_temp[i]->lc_lang)) ||
	    (!strcmp(lc_name, ic->mb_temp[i]->xlc_db->lc_name))) {
	    ic->mb = ic->mb_temp[i];
	    ic->wc = ic->wc_temp[i];
	    return;
	}
    }
    xlc = _XlcMakeLocale(lc_name);
    if (xlc) {
	ic->mb = ic->mb_temp[ic->xlc_num] = xlc;
	ic->wc = ic->wc_temp[ic->xlc_num] = _XlcDupLocale(xlc);
	ic->xlc_num++;
    }
}
#endif	/* XML */