/*
Copyright 1990-2001 Sun Microsystems, Inc. All Rights Reserved.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions: The above copyright notice and this
permission notice shall be included in all copies or substantial
portions of the Software.


THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.


Except as contained in this notice, the names of The Open Group and/or
Sun Microsystems, Inc. shall not be used in advertising or otherwise to
promote the sale, use or other dealings in this Software without prior
written authorization from The Open Group and/or Sun Microsystems,
Inc., as applicable.


X Window System is a trademark of The Open Group

OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
logo, LBX, X Window System, and Xinerama are trademarks of the Open
Group. All other trademarks and registered trademarks mentioned herein
are the property of their respective owners. No right, title or
interest in or to any trademark, service mark, logo or trade name of
Sun Microsystems, Inc. or its licensors is granted.

*/
#ifdef	WIN32
#include <windows.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#include "SunIM.h"
#include "SunIMMMan.h"
#include "SunIMProt.h"
#include "SunIMMthd.h"
#include "SunIMPriv.h"
#include "SunIMCore.h"
#include "SunIMPub.h"
#include "UDEngine.h"

Bool if_udengine_OpenIF(iml_if_t *);
Bool if_udengine_CloseIF(iml_if_t *);
Bool if_udengine_GetIFValue(iml_if_t *, IMArgList, int);
Bool if_udengine_SetIFValue(iml_if_t *, IMArgList, int);
Bool if_udengine_OpenDesktop(iml_desktop_t *, IMArgList, int);
Bool if_udengine_CloseDesktop(iml_desktop_t *);
Bool if_udengine_CreateSC(iml_session_t *, IMArgList, int);
Bool if_udengine_DestroySC(iml_session_t *);
Bool if_udengine_GetSCValue(iml_session_t *, IMArgList, int);
Bool if_udengine_SetSCValue(iml_session_t *, IMArgList, int);
IMText *if_udengine_ResetSC(iml_session_t *);
void if_udengine_SetSCFocus(iml_session_t *);
void if_udengine_UnsetSCFocus(iml_session_t *);
void if_udengine_SendEvent(iml_session_t *, IMInputEvent * ev);

/* IF Method */
if_methods_t udengine_methods2 = {
    if_udengine_OpenIF,
    if_udengine_CloseIF,
    if_udengine_GetIFValue,
    if_udengine_SetIFValue,
    if_udengine_OpenDesktop,
    if_udengine_CloseDesktop,
    if_udengine_CreateSC,
    if_udengine_DestroySC,
    if_udengine_GetSCValue,
    if_udengine_SetSCValue,
    if_udengine_ResetSC,
    if_udengine_SetSCFocus,
    if_udengine_UnsetSCFocus,
    if_udengine_SendEvent
};

UTFCHAR lename_string[] = {0x7b80, 0x4f53, 0x4e2d, 0x872d, 0x65b0, 0x62fc, 0x97f3, 0x8f93, 0x8815, 0x6cd5, 0x0}; 
UTFCHAR zhhrn_string[] = {0x7b80, 0x4f53, 0x4e2d, 0x872d, 0x0};

static IMLEName lename = {
    "udengine", lename_string	/* LE id, HRN */
};

static IMLocale locales[] = {
    {"zh", zhhrn_string},	/* locale id, HRN */
    NULL
};

IMObjectDescriptorStruct *objects = NULL;

int max_codetable_number = 0;

void init_objects();
void free_objects();

#ifdef	WIN32
#define EXPORT extern __declspec(dllexport)

EXPORT

#endif

void 
if_GetIfInfo(
    IMArgList args,
    int num_args
)
{
    int i;

    init_objects(); 
    for (i = 0; i < num_args; i++, args++) {
        switch (args->id) {
            case IF_VERSION:
                args->value = (IMArgVal) "1.2";
                break;
            case IF_METHOD_TABLE:
                args->value = (IMArgVal) & udengine_methods2;
                break;
            case IF_LE_NAME:
                args->value = (IMArgVal) & lename;
                break;
            case IF_SUPPORTED_LOCALES:
                args->value = (IMArgVal) & locales;
                break;
            case IF_SUPPORTED_OBJECTS:
                args->value = (IMArgVal) NULL; 
                break;
            case IF_NEED_THREAD_LOCK:
                args->value = (IMArgVal) False;
                break;
            default:
                break;
            }
    }
}

char *class_names[] = {"com.sun.iiim.sample.udengine.NewPYPanel"};

void aux_start(iml_session_t *);
void aux_draw(iml_session_t *, int, int, int *, int, UTFCHAR **);
void aux_done(iml_session_t *);
void aux_set(iml_session_t *);
void receive_aux(iml_session_t *, IMAuxDrawCallbackStruct *);
Bool receive_keylist(iml_session_t *, IMKeyListEvent *);

void my_conversion_on(iml_session_t *);
void my_conversion_off(iml_session_t *);

void status_draw(iml_session_t *);
void preedit_draw(iml_session_t *);
void lookup_draw(iml_session_t *, UTFCHAR **, int);
void commit(iml_session_t *);
void eval_packet(iml_session_t *, im_data *);

IMText *make_preedit_imtext(iml_session_t *);
void preedit_buf_print(iml_session_t *);
IMText *make_imtext(iml_session_t *, UTFCHAR *);

int UTFCHARLen(UTFCHAR *);
int UTFCHARCpy(UTFCHAR *, UTFCHAR *);

IMFeedbackList *create_feedback(iml_session_t * s, int size);
IMFeedbackList *create_feedback2(iml_session_t * s, int size);
void set_feedback(IMFeedbackList *, int);
int get_feedback(IMFeedbackList *);

/* data per desktop */
typedef struct {
    iml_session_t *auxproxy_session;
    int aux_started;
    int engine_id;
    int punc;
    int skb;
    int gbk_support;
}   MyDataPerDesktop;

/* data per session */
typedef struct {
    int status_start;
    int preedit_start;
    int luc_start;
    int conv_on;
    
    IMText **luc_candidates;
    IMText **luc_labels;
    
    UTFCHAR *conversion_string;	/* reversed */
    UTFCHAR *preedit_string;	/* underlined */
    
    int luc_top;
    int luc_nchoices;
    int luc_current_candidate;	/* index of current candidate */
    int luc_type;		/* Clinet or IM Master */
    int max_candidates;
    
    UTFCHAR *preedit_buf;	/* preedit */
    IMFeedbackList *preedit_feedback;	/* feedback for preedit */
    int caret_pos;
    
    IMFeedbackList *luc_fbs_reverse;
    IMFeedbackList *luc_fbs_normal;

    UTFCHAR *commit_buf; /* commit */

    UTFCHAR *status_buf; /* status */

    int session_id;
    char *username;

}   MyDataPerSession;

#define MAX_SESSION 512
#define MAX_PHRASE_LEN 20
static int s_id[MAX_SESSION];

/*
#define	DEBUG
*/

#define	DEBUG1


void debugprint(iml_session_t *s) {
    printf("	s=[%x]\n", s);
    printf("	If=[%x]\n", s->desktop->If);
    printf("	desktop=[%x]\n", s->desktop);
    printf("	locale=[%s]\n", s->desktop->If->locale);
    printf("	if_name=[%s]\n", s->desktop->If->if_name);
    printf("	USER:%s\n", s->desktop->user_name);
    printf("	HOST:%s\n", s->desktop->host_name);
    printf("    DISPLAY:%s\n", s->desktop->display_id);
}

Bool
if_udengine_OpenIF(
    iml_if_t * If
)
{
    max_codetable_number = IM_open(If->ifpath_name);
    if(max_codetable_number) return True;
    else return False;
}

Bool
if_udengine_CloseIF(
    iml_if_t * If
)
{
#ifdef  notdef
    free_objects();
#endif

    IM_close(max_codetable_number);

    return True;
}

UTFCHAR aux_name_panel[] = {0x65b0, 0x62fc, 0x97f3, 0x8f85, 0x52a9, 0x7a97, 0x53e3, 0};
UTFCHAR aux_name_aux[] = {0x65b0, 0x62fc, 0x97f3, 0x8f85, 0x52a9, 0x7a97, 0x53e3, 0};

void
free_objects()
{
    IMObjectDescriptorStruct *l = objects;

    while (l->leid) {
        free(l->name);
        l++;
    };
    free(objects);
    objects = NULL;
}

void
init_objects()
{
    IMObjectDescriptorStruct *l;
    objects = (IMObjectDescriptorStruct *) calloc(2, sizeof(IMObjectDescriptorStruct));
    l = objects;

    l->leid = "udengine";       /* engine id */
    l->type = IM_DOWNLOADINGOBJECT_JARGUI_TYPE; /* object type */
    l->name = (UTFCHAR *) calloc(1, sizeof(UTFCHAR) * (UTFCHARLen(aux_name_panel) + 1));
    UTFCHARCpy(l->name, aux_name_panel);
    l->name_length = UTFCHARLen(aux_name_panel);
    l->domain = "com.sun.udengine";
    l->scope = "udengine";      
    l->path = "/usr/lib/im/locale/zh_CN/udengine/udengine_obj.jar";  /* path */
    l->signature = "";
    l->basepath = NULL;         /* only for CCDEF */
    l->encoding = NULL;         /* only for CCDEF */
    l->class_names = class_names;
    l->count_names = 1;
}

Bool
if_udengine_GetIFValue(
    iml_if_t * If,
    IMArgList args,
    int num_args
)
{

#ifdef	DEBUG
    printf("if_udengine_GetIFValue()\n");
    printf("	If=[%x]\n", If);
    printf("	locale=[%s]\n", If->locale);
    printf("	if_name=[%s]\n", If->if_name);
#endif

    return True;
}

Bool
if_udengine_SetIFValue(
    iml_if_t * If,
    IMArgList args,
    int num_args
)
{
    int i;
#ifdef	DEBUG
    printf("if_udengine_SetIFValue()\n");
    printf("	If=[%x]\n", If);
    printf("	locale=[%s]\n", If->locale);
    printf("	if_name=[%s]\n", If->if_name);
#endif
    for (i = 0; i < num_args; i++, args++) {
        switch (args->id) {
        }
    }
    return True;
}

Bool
if_udengine_OpenDesktop(
    iml_desktop_t * desktop,
    IMArgList args,
    int num_args
)
{
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) calloc(1, sizeof(MyDataPerDesktop));
    int i;

#ifdef	DEBUG
    printf("if_udengine_OpenDesktop()\n");
    printf("	If=[%x]\n", desktop->If);
    printf("	desktop=[%x]\n", desktop);
    printf("	locale=[%s]\n", desktop->If->locale);
    printf("	if_name=[%s]\n", desktop->If->if_name);
    printf("	USER:%s\n", desktop->user_name);
    printf("	HOST:%s\n", desktop->host_name);
    printf("	DISPLAY:%s\n", desktop->display_id);
#endif

    desktop_data->aux_started = False;
    desktop_data->engine_id = 0;
    desktop_data->punc = 0;
    desktop_data->skb = 0;
    desktop_data->gbk_support = 0;
    desktop_data->auxproxy_session = NULL;
    desktop->specific_data = (void *) desktop_data;
    return True;
}

Bool
if_udengine_CloseDesktop(
    iml_desktop_t * desktop
)
{
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) desktop->specific_data;

#ifdef	DEBUG
    printf("if_udengine_CloseDesktop()\n");
    printf("	If=[%x]\n", desktop->If);
    printf("	desktop=[%x]\n", desktop);
    printf("	locale=[%s]\n", desktop->If->locale);
    printf("	if_name=[%s]\n", desktop->If->if_name);
    printf("	USER:%s\n", desktop->user_name);
    printf("	HOST:%s\n", desktop->host_name);
    printf("	DISPLAY:%s\n", desktop->display_id);
#endif

    free(desktop_data);
    return True;
}

#define	BUFSIZE	256
#define	MAXCANDIDATES	40

Bool
if_udengine_CreateSC(
    iml_session_t *s,
    IMArgList args,
    int num_args
)
{
    iml_desktop_t *desktop = s->desktop;
    static int first_create = 1;
    int i;

    MyDataPerSession *p = (MyDataPerSession *) calloc(1, sizeof(MyDataPerSession));
    p->status_start = False;
    p->luc_start = False;
    p->preedit_start = False;
    p->preedit_buf = (UTFCHAR *) calloc(1, sizeof(UTFCHAR) * BUFSIZE);
    p->status_buf = (UTFCHAR *) calloc(1, sizeof(UTFCHAR) * BUFSIZE);
    p->commit_buf = (UTFCHAR *) calloc(1, sizeof(UTFCHAR) * BUFSIZE);
    
    p->conversion_string = (UTFCHAR *) calloc(1, sizeof(UTFCHAR) * BUFSIZE);
    p->preedit_string = (UTFCHAR *) calloc(1, sizeof(UTFCHAR) * BUFSIZE);
    p->luc_candidates = NULL;
    p->luc_labels = NULL;
    p->luc_nchoices = 36;
    p->caret_pos = -1;
    p->max_candidates = MAXCANDIDATES - 1;
    p->luc_current_candidate = 0;
    p->luc_fbs_reverse = create_feedback(0, BUFSIZE);
    p->luc_fbs_normal = create_feedback(0, BUFSIZE);
    p->preedit_feedback = create_feedback(0, BUFSIZE);
    for(i=0;i<BUFSIZE;i++) {
	set_feedback(&p->luc_fbs_reverse[i], IMUnderline);
	set_feedback(&p->luc_fbs_reverse[i], IMReverse);
	set_feedback(&p->luc_fbs_reverse[i], IMNormal);
    }

    if(first_create) {
        for (i = 0; i < MAX_SESSION; i ++) s_id[i] = 0;
        first_create = 0;
    }

    for (i = 0; i < MAX_SESSION; i ++)
        if (s_id[i] == 0) { p->session_id = i ; break; }

    if ( i == MAX_SESSION ) {
         perror(" Can't open so many subwindows");
         return False;
    }
    s_id[i] = 1;
    p->username = (char *)strdup(desktop->user_name);
    
#ifdef	DEBUG
    printf("if_udengine_CreateSC()\n");
    printf("    If=[%x]\n", desktop->If);
    printf("    desktop=[%x]\n", desktop);
    printf("    locale=[%s]\n", desktop->If->locale);
    printf("    if_name=[%s]\n", desktop->If->if_name);
    printf("    USER:%s\n", desktop->user_name);
    printf("    HOST:%s\n", desktop->host_name);
    printf("    DISPLAY:%s\n", desktop->display_id);

    for (i = 0; i < num_args; i++, args++) {
        switch (args->id) {
            case UI_USER_NAME:
                if (args->value) {
                    printf("    UI_USER_NAME=%s\n", args->value);
                }
                break;
            case UI_HOST_NAME:
                if (args->value) {
                    printf("    UI_HOST_NAME=%s\n", args->value);
                }
                break;
            case UI_DISPLAY_ID:
                if (args->value) {
                    printf("    UI_DISPLAY_ID=%s\n", args->value);
                }
                break;
            case UI_PROTOCOL_TYPE:
                if (args->value) {
                    printf("    UI_PROTOCOL_TYPE=%s\n", args->value);
                }
                break;
            case UI_XSERVER_VENDOR:
                if (args->value) {
                    printf("    UI_XSERVER_VENDOR=%s\n", args->value);
                }
                break;
            case UI_CLIENT_TYPE:
                if (args->value) {
                    printf("    UI_CLIENT_TYPE=%s\n", args->value);
                }
                break;
            case UI_OS_NAME:
                if (args->value) {
                    printf("    UI_OS_NAME=%s\n", args->value);
                }
                break;
            case UI_OS_ARCH:
                if (args->value) {
                    printf("    UI_OS_ARCH=%s\n", args->value);
                }
                break;
            case UI_OS_VERSION:
                if (args->value) {
                    printf("    UI_OS_VERSION=%s\n", args->value);
                }
                break;
            }
    }
#endif
    s->specific_data = (void*) p;
    
    return True;
}

Bool
if_udengine_DestroySC(
    iml_session_t * s
)
{
    MyDataPerSession *p = (MyDataPerSession *) s->specific_data;
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;

    IM_destroySession(p->session_id);
    s_id[p->session_id] = 0;

    if ( s == desktop_data->auxproxy_session) {
	aux_done(s);
	desktop_data->auxproxy_session = NULL;
	desktop_data->punc = 0;
	desktop_data->skb = 0;
	desktop_data->gbk_support = 0;
    }

    if (p->preedit_buf)
        free((char *) p->preedit_buf);
    if (p->status_buf)
        free((char *) p->status_buf);
    if (p->commit_buf)
        free((char *) p->commit_buf);
    if (p->conversion_string)
        free((char *) p->conversion_string);
    if (p->preedit_string)
        free((char *) p->preedit_string);
    if (p->preedit_feedback)
        free((char *) p->preedit_feedback);
    if (p->luc_fbs_reverse)
        free((char *) p->luc_fbs_reverse);
    if (p->luc_fbs_normal)
        free((char *) p->luc_fbs_normal);
    free((char *) p);
#ifdef	DEBUG
    printf("if_udengine_DestroySC(s=%x)\n", s);
    debugprint(s);
#endif
    return True;
}

Bool
if_udengine_GetSCValue(
    iml_session_t * s,
    IMArgList args,
    int num_args
)
{
    int i;
    IMArg *p = args;
    
    static int charsubset[] = {
        67,			/* LATIN */
        47,			/* HIRAGANA */
        48,			/* KATAKANA */
        71,			/* KANJI */
        0
    };
    
#ifdef	DEBUG
    printf("if_udengine_GetSCValue(s=%x)\n", s);
    debugprint(s);
#endif
    for (i = 0; i < num_args; i++, p++) {
        switch (p->id) {
            case SC_SUPPORTED_CHARACTER_SUBSETS:
                /* specify CHARACTER_SUBSETS */
                p->value = (IMArgVal) charsubset;
                break;
            default:
                break;
            }
    }
    return True;
}

UTFCHAR off_string[] = {0x897f, 0x6587, 0};
UTFCHAR title_string[] = {0x67e5, 0x627e, 0x8868, 0};

void
my_conversion_on(
    iml_session_t * s
)
{
    iml_inst *lp;
    iml_inst *rrv = NULL;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    session_data->conv_on = True;
    
    lp = s->If->m->iml_make_start_conversion_inst(s);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    
    if (session_data->preedit_start == False) {
        lp = s->If->m->iml_make_preedit_start_inst(s);
        s->If->m->iml_link_inst_tail(&rrv, lp);
        session_data->preedit_start = True;
    }
    lp = s->If->m->iml_execute(s, &rrv);
    status_draw(s);
}

void
my_conversion_off(
    iml_session_t * s
)
{
    iml_inst *lp;
    iml_inst *rrv = NULL;
    
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    session_data->conv_on = False;

    IM_resetSession(session_data->session_id);
    
    /* if preedit exists, commit the string */
    commit(s);
    
    if (session_data->luc_start == True) {
        lp = s->If->m->iml_make_lookup_done_inst(s);
        s->If->m->iml_link_inst_tail(&rrv, lp);
        session_data->luc_start = False;
    }
    if (session_data->preedit_start == True) {
        lp = s->If->m->iml_make_preedit_erase_inst(s);
        s->If->m->iml_link_inst_tail(&rrv, lp);
        lp = s->If->m->iml_make_preedit_done_inst(s);
        s->If->m->iml_link_inst_tail(&rrv, lp);
        session_data->preedit_start = False;
        session_data->caret_pos = -1;
    }
    lp = s->If->m->iml_make_end_conversion_inst(s);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    
    s->If->m->iml_execute(s, &rrv);
    
    status_draw(s);
}

Bool
if_udengine_SetSCValue(
    iml_session_t * s,
    IMArgList args,
    int num_args
)
{
    int i;
    IMArg *p = args;

#ifdef	DEBUG
    printf("if_udengine_SetSCValue()\n");
    debugprint(s);
#endif

    for (i = 0; i < num_args; i++, p++) {
        switch (p->id) {
            case SC_TRIGGER_ON_NOTIFY:
                my_conversion_on(s);
                break;
                
            case SC_TRIGGER_OFF_NOTIFY:
                my_conversion_off(s);
                break;
                
            case SC_REALIZE:
		{
		    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;
		    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
		    IM_createSession(session_data->session_id);
                    if(desktop_data->auxproxy_session == NULL) 
		        desktop_data->auxproxy_session = s;
                    /* aux_start(s); */
		    
		}
                break;

	    case SC_LOOKUP_LABELTYPE:
                break;

            default:
                break;
            }
    }
    return True;
}

IMText *
if_udengine_ResetSC(
    iml_session_t * s
)
{
    int i;
    iml_inst *lp;
    IMText *p = make_preedit_imtext(s);
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    
#ifdef	DEBUG
    printf("if_udengine_ResetSC(s=%x)\n", s);
    debugprint(s);
#endif
    
    /*
    * when you return IMText for commit string, you need to call
    * iml_make_preedit_erase_inst() here.
    */
    lp = s->If->m->iml_make_preedit_erase_inst(s);
    s->If->m->iml_execute(s, &lp);
    
    /*
    * reset buffer
    */
    for(i=0;i<BUFSIZE;i++){
	set_feedback(&session_data->preedit_feedback[i], IMUnderline);
    }
    memset(session_data->preedit_buf, 0, sizeof(UTFCHAR) * BUFSIZE);
    memset(session_data->status_buf, 0, sizeof(UTFCHAR) * BUFSIZE);
    memset(session_data->commit_buf, 0, sizeof(UTFCHAR) * BUFSIZE);
    memset(session_data->preedit_string, 0, sizeof(UTFCHAR) * BUFSIZE);
    memset(session_data->conversion_string, 0, sizeof(UTFCHAR) * BUFSIZE);
    session_data->caret_pos = -1;
    
    /*
    * return committed string
    */
    if (p->char_length) {
        return p;
    }
    return (IMText *) NULL;
}

void
if_udengine_SetSCFocus(
    iml_session_t * s
)
{
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;
#ifdef DEBUG
    printf("if_udengine_SetSCFocus()\n");
#endif
    aux_start(s);
    aux_set(s);
}

void
if_udengine_UnsetSCFocus(
    iml_session_t * s
)
{
#ifdef	DEBUG
    printf("if_udengine_UnsetSCFocus()\n");
    debugprint(s);
#endif
}

void
if_udengine_SendEvent(
    iml_session_t * s,
    IMInputEvent * ev
)
{
#ifdef	DEBUG
    printf("if_udengine_SendEvent s=%x ev=%x\n", s, ev);
#endif
    if (ev) {
        if (ev->type == IM_EventKeyList) {
            if (receive_keylist(s, (IMKeyListEvent *) ev) == False) {
                IMKeyListEvent *keylist = (IMKeyListEvent *) ev;
                iml_inst *lp = s->If->m->iml_make_keypress_inst(s, (IMKeyEventStruct *) keylist->keylist);
                s->If->m->iml_execute(s, &lp);
            }
        } else if (ev->type == IM_EventAux) {
            IMAuxEvent *aux = (IMAuxEvent *) ev;
            IMAuxDrawCallbackStruct *data = aux->aux;
            receive_aux(s, data);
        } else if (ev->type == IM_EventString) {
            /* String Event */
        } else if (ev->type == IM_EventText) {
            /* Text Event */
        }
    }
}

void im_send_aux_event(s,key,index)
iml_session_t *s;
int key;
int index;
{
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;

/*        XIMAuxDrawCallbackStruct *dcb;*/

    switch(key) {
        case '1':
            desktop_data->punc = (desktop_data->punc == 0) ? 1 : 0 ;
            break;

        case '2':
	    if(index != -1) desktop_data->skb = index;
	    else {
               	desktop_data->skb ++; 
		desktop_data->skb = desktop_data->skb % max_codetable_number;
 	    }
        default:
            break;
    }
    aux_set(s);

/*
        dcb = (XIMAuxDrawCallbackStruct *)create_aux_struct(s);
        im_draw_aux(s,dcb);
*/
        return;
}

void eval_packet(s, imdata)
iml_session_t *s ;
im_data *imdata;
{
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    iml_inst *lp;
    UTFCHAR **luc_tmp;
    int k;
    int caret;

    if(imdata->operation == CIM_STATUS) status_draw(s); 
	
    session_data->caret_pos = imdata->caret_pos;
    zh_str_to_utf16(imdata->pre_str, session_data->preedit_buf, &session_data->caret_pos);
    preedit_draw(s);
	
    if( (imdata->operation == CIM_COMMIT) || (imdata->operation == CIM_COMMITSYMBOL) ) {
	zh_str_to_utf16(imdata->commit_str, session_data->commit_buf, &caret);
	commit(s);
    }

    if (imdata->luc_num > 0) {
	session_data->luc_nchoices = imdata->luc_num;
	luc_tmp = (UTFCHAR**) s->If->m->iml_new(s, session_data->luc_nchoices * sizeof(UTFCHAR*));
	for(k = 0; k < session_data->luc_nchoices; k ++) {
	    luc_tmp[k] = (UTFCHAR*) s->If->m->iml_new(s, MAX_PHRASE_LEN * sizeof(UTFCHAR));
	    luc_tmp[k][0] = 0;
	    zh_str_to_utf16(imdata->luc_str[k], luc_tmp[k], &caret);
	}
	lookup_draw(s, luc_tmp, imdata->luc_num);
    }
    else if(session_data->luc_start == True){
        lp = (iml_inst*)s->If->m->iml_make_lookup_done_inst(s);
        s->If->m->iml_execute(s, &lp);
	session_data->luc_start = False;
    }
}

Bool
receive_keylist(
    iml_session_t * s,
    IMKeyListEvent * keylist
)
{
    int i;
    im_data *imdata;
    IMKeyEventStruct *k = (IMKeyEventStruct *) keylist->keylist;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    long kcode, modifier;
    unsigned short kchar;
    i = UTFCHARLen(session_data->preedit_buf);

    #ifdef DEBUG
	printf("keycode %x, keychar %x state %x\n",k->keyCode, k->keyChar, k->modifier);
    #endif

    kcode = k->keyCode;
    kchar = k->keyChar;
    modifier = k->modifier; 

    modifyEvent(&kcode, &kchar, &modifier);
    if((modifier & 0x0008 ) == 0x0008) {  /*aux operation*/ 
	im_send_aux_event(s, kcode, -1);
	return True;
    }

    if((modifier == 4) && (kchar == 0x20)) { /* conversion off */
	my_conversion_off(s);
	return True;
    }
    imdata = (im_data *)IM_sendEvent(session_data->session_id, kcode, kchar, modifier);
    if(imdata == NULL) return False;

    #ifdef DEBUG
    if(imdata != NULL) {
        printf("imdata->operation=%d\n",imdata->operation);
        printf("imdata->pre_str=%s\n",imdata->pre_str);
        printf("imdata->caret_pos=%d\n",imdata->caret_pos);
        printf("imdata->luc_str=%s\n",imdata->luc_str[0]);
        printf("imdata->luc_num=%d\n",imdata->luc_num);
        printf("imdata->commit_str=%s\n",imdata->commit_str);
        printf("imdata->status_str=%s\n",imdata->status_str);
        printf("imdata->error_num=%d\n",imdata->error_num);
    }
    #endif

    if(imdata->operation == CIM_BOUNCEKEY) return False;
    else {
        eval_packet(s, imdata);
	return True;
    }
}

UTFCHARCat(
    UTFCHAR * dest,
    UTFCHAR * str1,
    UTFCHAR * str2
)
{
    int i;
    for (i = 0; *str1; i++) {
        *dest++ = *str1++;
    }
    for (i = 0; *str2; i++) {
        *dest++ = *str2++;
    }
    *dest = 0;
    return i;
}

int
UTFCHARCpy(
    UTFCHAR * dest,
    UTFCHAR * original
)
{
    int i;
    for (i = 0; *original; i++) {
        *dest++ = *original++;
    }
    *dest = 0;
    return i;
}

int
UTFCHARLen(
    UTFCHAR * p
)
{
    int i;
    for (i = 0; *p; i++)
    p++;
    return i;
}

void
commit(
    iml_session_t * s
)
{
    int len, i;
    iml_inst *lp;
    iml_inst *rrv = NULL;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    IMText *p = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
    memset(p, 0, sizeof(IMText));
    p->encoding = UTF16_CODESET;
    
    len = UTFCHARLen(session_data->commit_buf);
    if (len != 0) {
	p->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * (len + 1));
	UTFCHARCpy(p->text.utf_chars, session_data->commit_buf);
	p->char_length = len;
	p->feedback = create_feedback(s, p->char_length);
	lp = s->If->m->iml_make_commit_inst(s, p);
	s->If->m->iml_link_inst_tail(&rrv, lp);
	s->If->m->iml_execute(s, &rrv);
    }
    for(i=0;i<BUFSIZE;i++){
	set_feedback(&session_data->preedit_feedback[i], IMUnderline);
    }
    memset(session_data->preedit_buf, 0, sizeof(UTFCHAR) * BUFSIZE);
    memset(session_data->commit_buf, 0, sizeof(UTFCHAR) * BUFSIZE);
    memset(session_data->preedit_string, 0, sizeof(UTFCHAR) * BUFSIZE);
    memset(session_data->conversion_string, 0, sizeof(UTFCHAR) * BUFSIZE);
    
    session_data->caret_pos = -1;
}

void 
aux_set(
    iml_session_t *s
)
{
    int caret;
    char mode[40];
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;
    im_data* imdata;
    extern im_data *IM_setAuxValue();

    IM_setAuxValue(session_data->session_id, PUNCTUATION_STATUS, desktop_data->punc);

    imdata = (im_data *)IM_setAuxValue(session_data->session_id, SOFTKEYBOARD_LAYOUT, desktop_data->skb);
    if(imdata) {
        zh_str_to_utf16(imdata->status_str, session_data->status_buf, &caret);
        eval_packet(s,imdata);
    }
    else {
	IM_getValue(session_data->session_id, IM_STATUS, mode);
	zh_str_to_utf16(mode, session_data->status_buf, &caret);
	status_draw(s);
    }
}


void
status_draw(
    iml_session_t * s
)
{
    int len;
    iml_inst *lp;
    iml_inst *rrv = NULL;
    UTFCHAR status_str[20];
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;

    IMText *p = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
    memset(p, 0, sizeof(IMText));

    p->encoding = UTF16_CODESET;
    
    if (session_data->conv_on) {
	UTFCHARCpy(status_str, session_data->status_buf);
    } else {
         UTFCHARCpy(status_str,off_string);
    }
    
    len = UTFCHARLen(status_str);
    p->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * (len + 1));
    
    UTFCHARCpy(p->text.utf_chars, status_str);
    
    p->char_length = len;
    p->feedback = create_feedback(s, p->char_length);

    if (session_data->status_start == False) {
        lp = s->If->m->iml_make_status_start_inst(s);
        s->If->m->iml_link_inst_tail(&rrv, lp);
        session_data->status_start = True;
    }
    lp = s->If->m->iml_make_status_draw_inst(s, p);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    
    s->If->m->iml_execute(s, &rrv);
}

void
preedit_buf_print(iml_session_t * s)
{
    int i;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    int len = UTFCHARLen(session_data->preedit_buf);
    for (i = 0; i <= len; i++) {
        printf("Preedit[%d]=%x	%x\n",
            i,
            session_data->preedit_buf[i],
	    get_feedback(&session_data->preedit_feedback[i]));
    }
}

IMText *
make_imtext(iml_session_t * s, UTFCHAR * u)
{
    int len;
    IMText *p = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
    memset(p, 0, sizeof(IMText));
    p->encoding = UTF16_CODESET;
    len = UTFCHARLen(u);
    p->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * (len + 1));
    UTFCHARCpy(p->text.utf_chars, u);
    p->char_length = len;
    p->feedback = create_feedback(s, p->char_length);
    return p;
}

IMText *
make_preedit_imtext(iml_session_t * s)
{
    int len, i;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    IMText *p = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
    memset(p, 0, sizeof(IMText));

    p->encoding = UTF16_CODESET;
    len = UTFCHARLen(session_data->preedit_buf);
    p->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * (len + 1));
    UTFCHARCpy(p->text.utf_chars, session_data->preedit_buf);
    p->char_length = len;
    p->feedback = create_feedback(s, p->char_length);
    for(i = 0; i < session_data->caret_pos; i ++) {
	set_feedback(&session_data->preedit_feedback[i], IMReverse);
    }
    for(i = session_data->caret_pos; i < p->char_length; i ++) {
	set_feedback(&session_data->preedit_feedback[i], IMUnderline);
    }
    for (i = 0; i < p->char_length; i++) {
        set_feedback(&p->feedback[i], get_feedback(&session_data->preedit_feedback[i]));
    }
    return p;
}

void
preedit_draw(
    iml_session_t * s
)
{
    iml_inst *lp;
    iml_inst *rrv = NULL;
    
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    IMText *p = make_preedit_imtext(s);
    
    if (session_data->preedit_start == False) {
        lp = s->If->m->iml_make_preedit_start_inst(s);
        s->If->m->iml_link_inst_tail(&rrv, lp);
        session_data->preedit_start = True;
    }
    if(p->char_length == 0) {
	lp = s->If->m->iml_make_preedit_erase_inst(s);
	s->If->m->iml_link_inst_tail(&rrv, lp);
	s->If->m->iml_execute(s, &rrv);
	return;
    }
    lp = s->If->m->iml_make_preedit_draw_inst(s, p);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    
    if(session_data->caret_pos != -1) {
	lp = s->If->m->iml_make_preedit_caret_inst(s, session_data->caret_pos); 
	s->If->m->iml_link_inst_tail(&rrv, lp);
    }
    s->If->m->iml_execute(s, &rrv);
}

void
lookup_draw(iml_session_t * s, UTFCHAR ** luc_tmp, int luc_num)
{
    int i;
    int j = 0;
    iml_inst *lp;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    IMLookupDrawCallbackStruct *draw;
    IMLookupStartCallbackStruct *start;
    int max_len = 0;
    IMText **candidates;
    IMText **labels;
    int len;
    UTFCHAR buf[BUFSIZE];
    
    if (session_data->luc_candidates == NULL) {
        session_data->luc_candidates = (IMText **) calloc(MAXCANDIDATES, sizeof(IMText *));
    }
    candidates = session_data->luc_candidates;
    
    for (i = 0; i < luc_num; i++) {
        if (candidates[i]) {
            free(candidates[i]->text.utf_chars);
            free(candidates[i]->feedback);
            free(candidates[i]);
        }
        candidates[i] = (IMText *) calloc(1, sizeof(IMText));
        candidates[i]->encoding = UTF16_CODESET;
        candidates[i]->char_length = UTFCHARLen(luc_tmp[i]);
        candidates[i]->text.utf_chars = (UTFCHAR *) calloc(1,
            sizeof(IMText) * (candidates[i]->char_length + 1));
        UTFCHARCpy(candidates[i]->text.utf_chars, luc_tmp[i]);

        candidates[i]->feedback = create_feedback(0, candidates[i]->char_length);
    }
    
    if (session_data->luc_labels == NULL) {
        session_data->luc_labels = (IMText **) calloc(MAXCANDIDATES, sizeof(IMText));
        labels = session_data->luc_labels;
        for (i = '1'; i <= '9'; i++, j++) {
            labels[j] = (IMText *) calloc(1, sizeof(IMText));
	    labels[j]->encoding = UTF16_CODESET;
            labels[j]->char_length = 1;
            labels[j]->text.utf_chars = (UTFCHAR *) calloc(1,
                sizeof(IMText) * (labels[j]->char_length + 1));
            labels[j]->text.utf_chars[0] = (UTFCHAR) i;
            labels[j]->feedback = create_feedback(0, labels[j]->char_length);
        }
/*
        for (i = 'A'; i <= 'Z'; i++, j++) {
            labels[j] = (IMText *) calloc(1, sizeof(IMText));
	    labels[j]->encoding = UTF16_CODESET;
            labels[j]->char_length = 1;
            labels[j]->text.utf_chars = (UTFCHAR *) calloc(1,
                sizeof(IMText) * (labels[j]->char_length + 1));
            labels[j]->text.utf_chars[0] = (UTFCHAR) i;
            labels[j]->feedback = (IMFeedback *) calloc(1,
                sizeof(IMText) * (labels[j]->char_length + 1));
            memset(labels[j]->feedback, 0, sizeof(IMFeedback) * (labels[j]->char_length + 1));
        }
        for (i = 'a'; i <= 'z'; i++, j++) {
            labels[j] = (IMText *) calloc(1, sizeof(IMText));
	    labels[j]->encoding = UTF16_CODESET;
            labels[j]->char_length = 1;
            labels[j]->text.utf_chars = (UTFCHAR *) calloc(1,
                sizeof(IMText) * (labels[j]->char_length + 1));
            labels[j]->text.utf_chars[0] = (UTFCHAR) i;
            labels[j]->feedback = (IMFeedback *) calloc(1,
                sizeof(IMText) * (labels[j]->char_length + 1));
            memset(labels[j]->feedback, 0, sizeof(IMFeedback) * (labels[j]->char_length + 1));
        }
*/
    }
    labels = session_data->luc_labels;
    
    if (session_data->luc_start == False) {
        session_data->luc_top = 0;
        start = (IMLookupStartCallbackStruct *) s->If->m->iml_new(s, sizeof(IMLookupStartCallbackStruct));
        memset(start, 0, sizeof(IMLookupStartCallbackStruct));
        start->whoIsMaster = IMIsMaster;
        session_data->luc_type = IMIsMaster;
        start->IMPreference = (LayoutInfo *) s->If->m->iml_new(s, sizeof(LayoutInfo));
        memset(start->IMPreference, 0, sizeof(LayoutInfo));
        start->IMPreference->choice_per_window = 7;
        start->IMPreference->ncolumns = 7;
        start->IMPreference->nrows = 1;
        start->IMPreference->drawUpDirection = DrawUpHorizontally;
        start->IMPreference->whoOwnsLabel = IMOwnsLabel;
        start->CBPreference = NULL;
        lp = s->If->m->iml_make_lookup_start_inst(s, start);
        s->If->m->iml_execute(s, &lp);
        session_data->luc_start = True;
    }
    draw = (IMLookupDrawCallbackStruct *) s->If->m->iml_new(s, sizeof(IMLookupDrawCallbackStruct));
    memset(draw, 0, sizeof(IMLookupDrawCallbackStruct));
    draw->index_of_first_candidate = 0;
    draw->index_of_last_candidate = luc_num - 1;
    draw->n_choices = draw->index_of_last_candidate - draw->index_of_first_candidate + 1;
    
    draw->title = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
    memset(draw->title, 0, sizeof(IMText));
    draw->title->encoding = UTF16_CODESET;
    draw->title->char_length = UTFCHARLen(title_string);
    draw->title->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s,
        sizeof(IMText) * (draw->title->char_length + 1));
    UTFCHARCpy(draw->title->text.utf_chars, title_string);
    draw->title->feedback = create_feedback(s, draw->title->char_length);
    
    draw->choices = (IMChoiceObject *) s->If->m->iml_new(s, draw->n_choices * sizeof(IMChoiceObject));
    memset(draw->choices, 0, draw->n_choices * sizeof(IMChoiceObject));
    
    for (i = 0; i < draw->n_choices; i++) {
        IMText *vt;		/* for value */
        IMText *lt;		/* for label */
        vt = draw->choices[i].value = candidates[i + session_data->luc_top];
        lt = draw->choices[i].label = labels[i];
#ifdef DEBUG        
        printf("candidates[%d]=%x\n", i + session_data->luc_top,
            candidates[i + session_data->luc_top]);
#endif
        
        if (max_len < vt->char_length)
            max_len = vt->char_length;
        
        if (i + session_data->luc_top == session_data->max_candidates) {
            draw->index_of_first_candidate = 0;
            draw->index_of_last_candidate = i;
            draw->n_choices = i + 1;
            break;
        }
    }
    draw->max_len = max_len;
    draw->max_len = 20;
    draw->index_of_current_candidate = session_data->luc_current_candidate;
    
#ifdef DEBUG        
    printf("session_data->luc_top=%x\n", session_data->luc_top);
    
    printf("draw->index_of_first_candidate=%x\n", draw->index_of_first_candidate);
    printf("draw->index_of_last_candidate=%x\n", draw->index_of_last_candidate);
    printf("draw->n_choices=%x\n", draw->n_choices);
    printf("draw->max_len=%x\n", max_len);
    printf("draw->index_of_current_candidate=%x\n", session_data->luc_current_candidate);
#endif    

    lp = s->If->m->iml_make_lookup_draw_inst(s, draw);
    s->If->m->iml_execute(s, &lp);
}

void
receive_aux(
    iml_session_t * s,
    IMAuxDrawCallbackStruct * aux
)
{
    IMText *lts, *lt;
    int i, j, index;
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;

#ifdef DEBUG
    printf("AUX\n");
    
    printf("\taux_name=[%s]\n", aux->aux_name);
    printf("\tcount_integer_values=[%d]\n", aux->count_integer_values);
    printf("\tcount_string_values=[%d]\n", aux->count_string_values);
    
    printf("\t** INT[] **\n");
#endif

    if(aux->count_integer_values == 3) {
	desktop_data->punc = aux->integer_values[0];
	desktop_data->skb = aux->integer_values[1];
	desktop_data->gbk_support = aux->integer_values[2];	
    }
}

void
aux_start(
    iml_session_t * s
)
{
    int i;
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;
    iml_session_t *s_ = desktop_data->auxproxy_session;

    if(s_ == NULL) {
	s_ = desktop_data->auxproxy_session = s;
	printf("aux_start: auxproxy_session is NULL, take the responsibility for auxproxy\n");
    }

    if (desktop_data->aux_started == False) {
        iml_inst *lp;
        IMAuxStartCallbackStruct *aux = (IMAuxStartCallbackStruct *) s_->If->m->iml_new(s_, sizeof(IMAuxStartCallbackStruct));
        memset(aux, 0, sizeof(IMAuxStartCallbackStruct));
        aux->aux_name = class_names[0];
        lp = s_->If->m->iml_make_aux_start_inst(s_, aux);
        s_->If->m->iml_execute(s_, &lp);
#ifdef DEBUG
        printf("Starting AUX [%s]\n", class_names[0]);
#endif
        desktop_data->aux_started = True;
    } else {
#ifdef DEBUG
        printf("AUX[%s] is already started.\n", class_names[0]);
#endif
    }
}

void
aux_done(
    iml_session_t * s
)
{
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;
    iml_session_t *s_ = desktop_data->auxproxy_session;

    if (desktop_data->aux_started == True) {
        iml_inst *lp;
        IMAuxDoneCallbackStruct *aux = (IMAuxDoneCallbackStruct *) 
		s_->If->m->iml_new(s_, sizeof(IMAuxDoneCallbackStruct));
        memset(aux, 0, sizeof(IMAuxDoneCallbackStruct));
        aux->aux_name = class_names[0];
        lp = s_->If->m->iml_make_aux_done_inst(s_, aux);
        s_->If->m->iml_execute(s_, &lp);
#ifdef DEBUG
        printf("Closing AUX\n");
#endif
        desktop_data->aux_started = False;
    } else {
#ifdef DEBUG
        printf("AUX is already done.\n");
#endif
    }
}

void
aux_draw(
    iml_session_t * s,
    int class_name_id,
    int count_integers,
    int *integers,
    int count_strings,
    UTFCHAR ** strings
)
{
    iml_inst *lp;
    int i, j;
    int len = 7;
    IMText *lts, *lt;
    IMAuxDrawCallbackStruct *aux;
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;
    iml_session_t *s_ = desktop_data->auxproxy_session;

    if(s_ == NULL) {
	s_ = desktop_data->auxproxy_session = s;
#ifdef DEBUG
	printf("aux_draw: auxproxy_session is NULL, take the responsibility for auxproxy\n");
#endif
    }

    if (desktop_data->aux_started == False) {
#ifdef DEBUG
        printf("AUX is not started.\n");
#endif
        return;
    }
    aux = (IMAuxDrawCallbackStruct *) s_->If->m->iml_new(s_, sizeof(IMAuxDrawCallbackStruct));
    memset(aux, 0, sizeof(IMAuxDrawCallbackStruct));

    aux->aux_name = class_names[0];

    aux->count_integer_values = count_integers;
    if (aux->count_integer_values) {
        aux->integer_values = (int *) s_->If->m->iml_new(s_, sizeof(int) * aux->count_integer_values);
        memset(aux->integer_values, 0, sizeof(int) * aux->count_integer_values);

        for (i = 0; i < aux->count_integer_values; i++) {
            aux->integer_values[i] = integers[i];
        }
    }
    aux->count_string_values = count_strings;
    if (aux->count_string_values) {
        aux->string_values = lts = (IMText *)
        s_->If->m->iml_new(s_, sizeof(IMText) * aux->count_string_values);
        memset(aux->string_values, 0, sizeof(IMText) * aux->count_string_values);
        aux->string_values->encoding = UTF16_CODESET;

        for (i = 0, lt = lts; i < aux->count_string_values; i++, lt++) {
            len = UTFCHARLen(strings[i]);
            lt->text.utf_chars = (UTFCHAR *) s_->If->m->iml_new(s_, sizeof(UTFCHAR) * (len + 1));
            lt->char_length = len + 1;
            UTFCHARCpy(lt->text.utf_chars, strings[i]);
        }
    }
    lp = s_->If->m->iml_make_aux_draw_inst(s_, aux);
    s_->If->m->iml_execute(s_, &lp);
}

IMFeedbackList *
create_feedback2(
    iml_session_t * s,
    int size
)
{
    int i;
    IMFeedbackList *feedback, *fbl;
    IMFeedback *fb;
    feedback = (IMFeedbackList *) s->If->m->iml_new2(s, sizeof(IMFeedbackList) * size);
    memset(feedback, 0, sizeof(IMFeedbackList) * size);
    for (i = 0; i < size; i++) {
        IMFeedbackList *fbl = &feedback[i];
        fbl->count_feedbacks = 1;
        fb = fbl->feedbacks = (IMFeedback *) s->If->m->iml_new2(s, sizeof(IMFeedback));
        memset(fbl->feedbacks, 0, sizeof(IMFeedback));
    }
    return feedback;
}

IMFeedbackList *
create_feedback(
    iml_session_t * s,
    int size
)
{
    int i;
    IMFeedbackList *feedback, *fbl;
    IMFeedback *fb;
    
    if (s) {
        feedback = (IMFeedbackList *) s->If->m->iml_new(s, sizeof(IMFeedbackList) * size);
        memset(feedback, 0, sizeof(IMFeedbackList) * size);
    } else {
        feedback = (IMFeedbackList *) calloc(1, sizeof(IMFeedbackList) * size);
    }
    for (i = 0; i < size; i++) {
        IMFeedbackList *fbl = &feedback[i];
        fbl->count_feedbacks = 1;
        if (s) {
            fb = fbl->feedbacks = (IMFeedback *) s->If->m->iml_new(s, sizeof(IMFeedback));
            memset(fbl->feedbacks, 0, sizeof(IMFeedback));
        } else {
            fb = fbl->feedbacks = (IMFeedback *) calloc(1, sizeof(IMFeedback));
        }
    }
    return feedback;
}

int
get_feedback(
    IMFeedbackList * fbl
)
{
    IMFeedback *fb = &fbl->feedbacks[0];
    return IM_FEEDBACK_VALUE(fb);
}

void
set_feedback(
    IMFeedbackList * fbl,
    int value
)
{
    IMFeedback *fb = &fbl->feedbacks[0];
    IM_FEEDBACK_TYPE(fb)=IM_DECORATION_FEEDBACK;
    IM_FEEDBACK_VALUE(fb)=value;
}
