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

/*
 * $XConsortium: ProtoFlt.c,v 1.28 92/10/22 14:25:16 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
 */				

#define NEED_EVENTS
#define XK_MISCELLANY
#define XK_LATIN1
#include <X11/keysymdef.h>
#include "Xlibint.h"
#include "Xi18nint.h"
#include "XIMlibint.h"


static void
_call_preedit_draw(ic, cb)
    XipIC ic;
    XIMCallback *cb;
{
    XipIM	im = ipIMofIC(ic);
    XIMPreeditDrawCallbackStruct	call_data;
    XIMText		text;
    ximPreDrawReply	reply;
    XIMFeedback		fb;
    int		ret;
    int		wc_len;
    int		length;
    int		scanned_bytes;
#ifndef X_WCHAR
    int		mb_len;
    char	*mbuf;
#endif

    if (_XipReadFromIM(im, (char *)&reply, sz_ximPreDrawReply) < 0) {
	return;
    }
    length = (int)reply.length;
    if (length > 0) {
	if (reply.encoding_is_wchar != True) {
	    if (length > ic->max_of_ct) {
		if (ic->ct_buf == NULL) {
		    ic->ct_buf = (char *)Xmalloc((ic->max_of_ct = length + 1));
		} else {
		    ic->ct_buf = (char *)Xrealloc(ic->ct_buf,
						     (ic->max_of_ct = length + 1));
		}
	    }
	    if (_XipReadFromIM(im, ic->ct_buf, length) < 0) return;
	    ic->ct_buf[length] = 0;
	}
	if (length > ic->max_of_wc) {
	    if (ic->wc_buf == NULL) {
		ic->wc_buf = (wchar_t *)Xmalloc(
				(ic->max_of_wc = length + 1) * sizeof(wchar_t));
	    } else {
		ic->wc_buf = (wchar_t *)Xrealloc(ic->wc_buf,
				(ic->max_of_wc = length + 1) * sizeof(wchar_t));
	    }
	}
	if (reply.encoding_is_wchar != True) {
	    wc_len = ic->max_of_wc;
#ifdef X_WCHAR
	    ret = _XConvertCTToWC(ic->wc, (unsigned char *)ic->ct_buf, length,
				  (wchar *)ic->wc_buf, &wc_len, &scanned_bytes,
				  (_State *)NULL);
#else
	    mb_len = length * 2;
	    mbuf = _XAllocScratch(im->core.display, mb_len);
	    ret = _XConvertCTToMB(ic->mb, (unsigned char *)ic->ct_buf, length,
				  mbuf, &mb_len, &scanned_bytes,
				  (_State *)NULL);
	    if (ret >= 0) {
#ifdef macII
		wc_len = 0;
#else
		mbuf[mb_len] = '\0';
		wc_len = mbstowcs(ic->wc_buf, mbuf, ic->max_of_wc);
#endif
		if (wc_len == ic->max_of_wc)
		    return;
	    }
#endif
	    if (ret < 0) {
		return;
	    }
	} else {
	    if (_XipReadFromIM(im, (char *)ic->wc_buf,
			       (length * sizeof(wchar_t))) < 0) return;
	    ic->wc_buf[length] = 0;
	    wc_len = length;
	}
	text.length = wc_len;
	fb = (XIMFeedback)reply.feedback;
	text.feedback = &fb;
	text.encoding_is_wchar = True;
	text.string.wide_char = ic->wc_buf;
    } else {
	text.length = 0;
	text.feedback = 0;
	text.encoding_is_wchar = True;
	text.string.wide_char = NULL;
	text.string.multi_byte = NULL;
    }
    call_data.text = &text;
    call_data.caret = (int)reply.caret;
    call_data.chg_first = (int)reply.chg_first;
    call_data.chg_length = (int)reply.chg_length;

    (void)(cb->callback)(ic, cb->client_data, &call_data);
    return;
}

static void
_call_preedit_caret(ic, cb)
    XipIC ic;
    XIMCallback *cb;
{
    XIMPreeditCaretCallbackStruct	call_data;
    ximPreCaretReply			reply;

    if (_XipReadFromIM(ipIMofIC(ic),
		       (char *)&reply, sz_ximPreCaretReply) < 0) {
	return;
    }
    call_data.position = (int)reply.position;
    switch((int)reply.direction) {
	case XIM_CB_FW_CHAR:
	    call_data.direction = XIMForwardChar;
	    break;
	case XIM_CB_BW_CHAR:
	    call_data.direction = XIMBackwardChar;
	    break;
	case XIM_CB_FW_WORD:
	    call_data.direction = XIMForwardWord;
	    break;
	case XIM_CB_BW_WORD:
	    call_data.direction = XIMBackwardWord;
	    break;
	case XIM_CB_CARET_UP:
	    call_data.direction = XIMCaretUp;
	    break;
	case XIM_CB_CARET_DOWN:
	    call_data.direction = XIMCaretDown;
	    break;
	case XIM_CB_NEXT_LINE:
	    call_data.direction = XIMNextLine;
	    break;
	case XIM_CB_PREV_LINE:
	    call_data.direction = XIMPreviousLine;
	    break;
	case XIM_CB_LINE_START:
	    call_data.direction = XIMLineStart;
	    break;
	case XIM_CB_LINE_END:
	    call_data.direction = XIMLineEnd;
	    break;
	case XIM_CB_ABS_POS:
	    call_data.direction = XIMAbsolutePosition;
	    break;
	case XIM_CB_DONT_CHANGE:
	    call_data.direction = XIMDontChange;
	    break;
	default:
	    return;
    }
    call_data.style = (XIMCaretStyle)reply.style;
    (void)(cb->callback)(ic, cb->client_data, &call_data);
    return;
}

static void
_call_status_draw(ic, cb)
    XipIC ic;
    XIMCallback *cb;
{
    XipIM		im = ipIMofIC(ic);
    XIMStatusDrawCallbackStruct		call_data;
    XIMText				text;
    ximStatusDrawReply			reply;
    XIMFeedback		fb;
    int			ret;
    int			wc_len = 0;
    int			length;
    int			scanned_bytes;
#ifndef X_WCHAR
    int		mb_len;
    char	*mbuf;
#endif

    if (_XipReadFromIM(im, (char *)&reply, sz_ximStatusDrawReply) < 0) {
	return;
    }
    if (reply.type == XIM_ST_BITMAP) {
	call_data.type = XIMBitmapType;
	call_data.data.bitmap = (Pixmap)reply.bitmap;
    } else {
	length = (int)reply.length;
	if (length > 0) {
	    if (reply.encoding_is_wchar != True) {
		if (length > ic->max_of_ct) {
		    if (ic->ct_buf == NULL) {
			ic->ct_buf = (char *)Xmalloc(
					    (ic->max_of_ct = length + 1));
		    } else {
			ic->ct_buf = (char *)Xrealloc(ic->ct_buf,
					      (ic->max_of_ct = length + 1));
		    }
		}
		if (_XipReadFromIM(im, ic->ct_buf, length) < 0) return;
		ic->ct_buf[length] = 0;
	    }
	    if (length > ic->max_of_wc) {
		if (ic->wc_buf == NULL) {
		    ic->wc_buf = (wchar_t *)Xmalloc(
			    (ic->max_of_wc = length + 1) * sizeof(wchar_t));
		} else {
		    ic->wc_buf = (wchar_t *)Xrealloc(ic->wc_buf,
			    (ic->max_of_wc = length + 1) * sizeof(wchar_t));
		}
	    }
	    if (reply.encoding_is_wchar != True) {
		wc_len = ic->max_of_wc;
#ifdef X_WCHAR
		ret = _XConvertCTToWC(ic->wc, (unsigned char *)ic->ct_buf,
				      length, (wchar *)ic->wc_buf, &wc_len,
				      &scanned_bytes, (_State *)NULL);
#else
		mb_len = length * 2;
		mbuf = _XAllocScratch(im->core.display, mb_len);
		ret = _XConvertCTToMB(ic->mb, (unsigned char *)ic->ct_buf,
				      length, mbuf, &mb_len, &scanned_bytes,
				      (_State *)NULL);
		if (ret >= 0) {
#ifdef macII
		    wc_len = 0;
#else
		    mbuf[mb_len] = '\0';
		    wc_len = mbstowcs(ic->wc_buf, mbuf, ic->max_of_wc);
#endif
		    if (wc_len == ic->max_of_wc)
			return;
		}
#endif
		if (ret < 0) {
		    return;
		}
	    } else {
		if (_XipReadFromIM(im, (char *)ic->wc_buf,
				   (length * sizeof(wchar_t))) < 0) return;
		ic->wc_buf[length] = 0;
		wc_len = length;
	    }
	}
	call_data.type = XIMTextType;
	call_data.data.text = &text;
	text.length = wc_len;
	fb = (XIMFeedback)reply.feedback;
	text.feedback = &fb;
	text.encoding_is_wchar = True;
	text.string.wide_char = ic->wc_buf;
    }

    (void)(cb->callback)(ic, cb->client_data, &call_data);
    return;
}

int
_XipCallCallbacks(ic)
    XipIC ic;
{
    ICCallbacks		*pre_cbs = &ic->core.preedit_attr.callbacks;
    ICCallbacks		*st_cbs = &ic->core.status_attr.callbacks;
    ximNormalReply	reply;
    int		type;

    for (;;) {
	if (_XipReadFromIM(ipIMofIC(ic),
			   (char *)&reply, sz_ximNormalReply) < 0) {
	    return(-1);
	}
	type = (int)reply.detail;
	if (type == XIM_CB_PRE_START) {
	    if (pre_cbs->start.callback) {
		(*pre_cbs->start.callback)(ic, pre_cbs->start.client_data,
					   NULL);
	    }
	} else if (type == XIM_CB_PRE_DONE) {
	    if (pre_cbs->done.callback) {
		(*pre_cbs->done.callback)(ic, pre_cbs->done.client_data, NULL);
	    }
	} else if (type == XIM_CB_PRE_DRAW) {
	    (void)_call_preedit_draw(ic, &(pre_cbs->draw));
	} else if (type == XIM_CB_PRE_CARET) {
	    (void)_call_preedit_caret(ic, &(pre_cbs->caret));
	} else if (type == XIM_CB_ST_START) {
	    if (st_cbs->start.callback) {
		(*st_cbs->start.callback)(ic, st_cbs->start.client_data, NULL);
	    }
	} else if (type == XIM_CB_ST_DONE) {
	    if (st_cbs->done.callback) {
		(*st_cbs->done.callback)(ic, st_cbs->done.client_data, NULL);
	    }
	} else if (type == XIM_CB_ST_DRAW) {
	    (void)_call_status_draw(ic, &(st_cbs->draw));
	} else {
	    return(0);
	}
    }
}

Bool
_XipBackEndFilter(display, window, ev, client_data)
    Display *display;
    Window window;
    XEvent *ev;
    XPointer client_data;
{
    register int	count;
    register XipIC	ic = (XipIC)client_data;
    XipIM		im = ipIMofIC(ic);
    ximEventReq		req;
    ximEventReply	reply;
    ximReturnReply	reply1;
    KeySym		keysym;
    int			keycode;
    int			mode;
    register int	i;
    XEvent		dummy_ev;
    int			ret;
    int			first = 0;
#ifdef	XML
    char		tmp_lc_name[32];
#endif	/* XML */

    if (!im || (im->fd < 0)) return(False);
    /*
     * If key_code is 0, this key event be regarded
     * as the event pushed back by this filter.
     */
    if (ev->xkey.keycode == 0) {
	if (_XipTypeOfNextICQueue(ic) == XIM_KEYSYM &&
	    (keysym = _XipKeySymOfNextICQueue(ic)) > XK_BackSpace){
	    if ((keycode = XKeysymToKeycode(display, keysym)) != 0) {
		ev->xkey.keycode = keycode;
		ev->xkey.state = _XipStateOfNextICQueue(ic);
		_XipFreeNextICQueue(ic);
	    }
	}
	return(False);
    }
    if (ic->out) ic->out = NULL;

    if (ev->xany.window != window) {
	ev->xany.window = window;
    }
    req.reqType = XIM_Event;
    req.length = sz_ximEventReq + sizeof(XEvent);
    req.xic = ic->icid;
    if ((_XipWriteToIM(im, (char *)&req, sz_ximEventReq) < 0)
	|| (_XipWriteToIM(im, (char *)ev, sizeof(XEvent)) < 0)
	|| (_XipFlushToIM(im) < 0)) {
	return(-1);
    }
    
    ret = True;
    for (;;) {
	if (_XipReadFromIM(im, (char *)&reply, sz_ximEventReply) < 0) {
	    return(-1);
	}
	if (reply.state != 0) {
	    return(-1);
	}
	mode = (int)reply.detail;
	if (mode == XIM_NOTHING) {
	    /*
	     * The input manager filtered a event.
	     */
	    ret = True;
	} else if (mode == XIM_NOFILTER) {
	    /*
	     * The input manager didn't filter a event.
	     */
	    ret = False;
	} else if (mode == XIM_RETURN) {
	    /*
	     * The input manager returns some strings and events.
	     */
	    count = 0;
	    for (;;) {
		if (_XipReadFromIM(im, (char *)&reply1,
				   sz_ximReturnReply) < 0) {
		    return(-1);
		}
		if (reply1.type == XIM_KEYSYM || reply1.type == XIM_STRING) {
		    if (_XipPutICQueue(ic, (short)reply1.type,
				       (int)reply1.length,
				       (KeySym)reply1.keysym, 0, 0, NULL) < 0) {
			return(-1);
		    }
		    count++;
		} else {
		    break;
		}
	    }
	    bcopy((char *)ev, (char *)&dummy_ev, sizeof(XEvent));
	    dummy_ev.type = KeyPress;
	    dummy_ev.xkey.state = 0;
	    dummy_ev.xkey.keycode = 0;
	    if (first == 0) count--;
	    for (i = 0; i < count; i++) {
		XPutBackEvent(display, &dummy_ev);
	    }
	    ret = False;
	    if (first > 0) continue;
	    first++;
	    ev->xkey.state = 0;
	    ev->xkey.keycode = 0;
	    if (_XipTypeOfNextICQueue(ic) == XIM_KEYSYM &&
		(keysym = _XipKeySymOfNextICQueue(ic)) > XK_BackSpace){
		if ((keycode = XKeysymToKeycode(display, keysym)) != 0) {
		    ev->xkey.keycode = keycode;
		    ev->xkey.state = _XipStateOfNextICQueue(ic);
		    _XipFreeNextICQueue(ic);
		}
	    }
	} else if (mode == XIM_CALLBACK) {
	    /*
	     * Calling callback routines.
	     */
	    if (_XipCallCallbacks(ic) < 0) {
		return(True);
	    }
#ifdef	XML
	} else if (mode == XIM_CH_LOCALE) {
	    if (_XipReadFromIM(im, tmp_lc_name, reply.number) < 0) {
		return(-1);
	    }
	    tmp_lc_name[reply.number] = '\0';
	    _XipChangeLocale(ic, tmp_lc_name);
	    (*ic->values.ch_locale_cb)(tmp_lc_name);
	    ret = True;
#endif	/* XML */
	} else {
	    return(ret);
	}
    }
}