[openi18n-im:01530] convenient function for iml methods

Federic Zhang <[email protected]> Wed, 31 Aug 2005 13:09:58 +0800
Newsgroups gmane.comp.internationalization.input-methods
Message-ID <1125464996.7032.19.camel@hola>
Hi,

As first part of common language engine, today i will commit one patch
which will provide convenient functions for those low-level iml methods
for input method developer. those functions combine the iml creation and
execution, see SunIMSubr2.c for details. developer can use them via
s->If->m_wrapper, attached ime.c can demonstrate how they can be used.
Of course, the existing iml methods still work and developer still can
access via s->If->m.

The second step is to provide one imm service within iml, which would be
higher than those new convenient functions, it will take various aux
implementation into account, common aux, default aux and customized aux
etc and do encoding conversion, so it's unnecessary for developer to
care about code conversion between native encoding and UTF-16 in their
code, again, the service will be accessed directly be s->If->imm_service
to developer in future.

Based on those work, one real common language engine (adapter) would be
implemented later and high version of LEIF will be available in one or
two months eventually.

Please review, if it's ok i will commit today.

Almost forget to mention, most of code and idea comes from Ervin's cle,
i just copy directly.

-federic
IMUtil.c (text/x-csrc, 2.5 KB)
/*
  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.

*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>

#include "SunIM.h"
#include "SunIMLock.h"
#ifdef  sun
#include <unistd.h>
#endif

int
utfchar_length (UTFCHAR *p)
{
  int len = 0;

  while (*p) { ++len; ++p; }

  return len;
}

UTFCHAR *
utfchar_copy (UTFCHAR *dest,
              UTFCHAR *src)
{
  int len;

  if (!src || !dest) return NULL;

  len = utfchar_length (src);
  memcpy (dest, src, sizeof (UTFCHAR) * len);
  dest[len] = 0;

  return dest;
}

/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */
SunIMSubr2.c (text/x-csrc, 17 KB)
/*
  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.

*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>

#include "SunIM.h"
#include "SunIMLock.h"
#include "IMUtil.h"
#ifdef  sun
#include <unistd.h>
#endif

static void iml_commit (iml_session_t *, UTFCHAR *);
static void iml_forward_keypress (iml_session_t *, IMKeyEventStruct *);
static void iml_conversion_on (iml_session_t *);
static void iml_conversion_off (iml_session_t *);
static void iml_status_start (iml_session_t *);
static void iml_status_end (iml_session_t *);
static void iml_status_draw (iml_session_t *, UTFCHAR *);
static void iml_preedit_start (iml_session_t *);
static void iml_preedit_end (iml_session_t *);
static void iml_preedit_draw (iml_session_t *, UTFCHAR *, int);
static void iml_lookup_start (iml_session_t *, LayoutInfo *);
static void iml_lookup_end (iml_session_t *);
static void iml_lookup_draw (iml_session_t *, int, UTFCHAR **,
			     IMFeedbackList **, UTFCHAR **,
			     IMFeedbackList **, UTFCHAR *,
			     IMFeedbackList *, int, int);
static void iml_aux_start (iml_session_t *, char *);
static void iml_aux_done (iml_session_t *, char *);
static void iml_aux_draw (iml_session_t *, char *, int, int *, int, int *, UTFCHAR **);

iml_methods_wrapper_t _iml_methods_wrapper = {
  iml_commit,
  iml_forward_keypress,
  iml_conversion_on,
  iml_conversion_off,
  iml_status_start,
  iml_status_end,
  iml_status_draw,
  iml_preedit_start,
  iml_preedit_end,
  iml_preedit_draw,
  iml_lookup_start,
  iml_lookup_end,
  iml_lookup_draw,
  iml_aux_start,
  iml_aux_done,
  iml_aux_draw,
};

Public iml_methods_wrapper_t *
_iml_dup_iml_methods_wrapper ()
{
  iml_methods_wrapper_t *m_wrapper = (iml_methods_wrapper_t *) 
                                     malloc (sizeof (iml_methods_wrapper_t));
  memcpy (m_wrapper, &_iml_methods_wrapper, sizeof (iml_methods_wrapper_t));

  return m_wrapper;
}

static IMFeedbackList *
create_feedback_list (iml_session_t *s,
		      int size)
{
  IMFeedbackList *feedback;
  int i;

  if (s)
    feedback = (IMFeedbackList *) s->If->m->iml_new (s,
				    sizeof (IMFeedbackList) * size);
  else
    feedback = (IMFeedbackList *) malloc (sizeof (IMFeedbackList) * size);

  memset (feedback, 0, sizeof (IMFeedbackList) * size);

  for (i = 0; i < size; ++i)
    {
      IMFeedbackList *fbl = feedback + i;

      fbl->count_feedbacks = 1;

      // why 4 here?
      if (s)
	fbl->feedbacks = (IMFeedback *) s->If->m->iml_new (s,
					  sizeof (IMFeedback) * 4);
      else
	fbl->feedbacks = (IMFeedback *) malloc (sizeof (IMFeedback) * 4);

      memset (fbl->feedbacks, 0, sizeof (IMFeedback) * 4);
    }

  return feedback;
}

static void
free_feedback_list (iml_session_t *s,
		    IMFeedbackList *feedback,
		    int size)
{
  int i;

  if (!feedback) return;

  for (i = 0; i < size; ++i)
    {
      IMFeedbackList *fbl = feedback + i;

      if (fbl && !fbl->feedbacks) free (fbl->feedbacks);
    }

  free (feedback);
}

static int
get_nth_feedback (IMFeedbackList *feedback,
		  int n)
{
  IMFeedback *fb = feedback->feedbacks + n;

  return IM_FEEDBACK_VALUE(fb);
}

static void
set_nth_feedback (IMFeedbackList *feedback,
		  int n,
		  int type,
		  int value)
{
  IMFeedback *fb = feedback->feedbacks + n;

  IM_FEEDBACK_TYPE(fb) = type;
  IM_FEEDBACK_VALUE(fb) = value;
}

static void
set_feedback (IMFeedbackList *feedback,
	      int normal,
	      int fg,
	      int bg,
	      int underline)
{
  int count = 0;

  set_nth_feedback (feedback, count, IM_DECORATION_FEEDBACK, normal);
  ++count;

  if (fg != -1)
    {
      set_nth_feedback (feedback, count, IM_FOREGROUND_RGB_FEEDBACK, fg);
      ++count;
    }

  if (bg != -1)
    {
      set_nth_feedback (feedback, count, IM_BACKGROUND_RGB_FEEDBACK, bg);
      ++count;
    }
  
  if (underline != -1)
    {
      set_nth_feedback (feedback, count, IM_UNDERLINE_RGB_FEEDBACK, underline);
      ++count;
    }

  IM_FEEDBACK_COUNT(feedback) = count;
}

static IMText *
iml_make_imtext (iml_session_t *s,
		 UTFCHAR *p,
		 IMFeedbackList *feedback)
{
  IMText *text;
  int len = utfchar_length (p);

  if (s)
    text = (IMText *) s->If->m->iml_new (s, sizeof (IMText));
  else
    text = (IMText *) malloc (sizeof (IMText));

  memset (text, 0, sizeof (IMText));

  text->encoding = UTF16_CODESET;

  if (s)
    text->text.utf_chars = (UTFCHAR *) s->If->m->iml_new (s,
					      sizeof (UTFCHAR) * (len + 1));
  else
    text->text.utf_chars = (UTFCHAR *) malloc (sizeof (UTFCHAR) * (len + 1));

  utfchar_copy (text->text.utf_chars, p);
  text->char_length = len;

  if (feedback)
    text->feedback = feedback;
  else
    {
      int i;

      text->feedback = create_feedback_list (s, len);
      for (i = 0; i < len; i++)
	set_feedback (text->feedback + i, IMReverse, -1, -1, -1);
    }

  return text;
}

static void
iml_commit (iml_session_t *s, UTFCHAR *commit_str)
{
  int len = utfchar_length (commit_str);
  iml_inst *lp;
  IMText *text;

  if (len) return;

  text = iml_make_imtext (s, commit_str, NULL);
  lp = (iml_inst *) s->If->m->iml_make_commit_inst (s, text);
  s->If->m->iml_execute (s, &lp);
}

static void
iml_forward_keypress (iml_session_t *s,
		      IMKeyEventStruct *key)
{
  iml_inst *lp;

  lp = (iml_inst *) s->If->m->iml_make_keypress_inst (s, key);
  s->If->m->iml_execute (s, &lp);
}

static void
iml_conversion_on (iml_session_t *s)
{
  iml_inst *lp;

  lp = (iml_inst *) s->If->m->iml_make_start_conversion_inst (s);
  s->If->m->iml_execute (s, &lp);
}

static void
iml_conversion_off (iml_session_t *s)
{
  iml_inst *lp;

  lp = (iml_inst *) s->If->m->iml_make_end_conversion_inst (s);
  s->If->m->iml_execute (s, &lp);
}

static void
iml_status_start (iml_session_t *s)
{
  iml_inst *lp;
  iml_inst *rrv = NULL;

  lp = (iml_inst *) s->If->m->iml_make_status_start_inst (s);
  s->If->m->iml_link_inst_tail (&rrv, lp);
}

static void
iml_status_end (iml_session_t *s)
{
  iml_inst *lp;

  lp = (iml_inst *) s->If->m->iml_make_status_done_inst (s);
  s->If->m->iml_execute (s, &lp);
}

static void
iml_status_draw (iml_session_t *s,
		 UTFCHAR *status_str)
{
  IMText *text;
  iml_inst *lp, *rrv = NULL;

  iml_status_start (s);

  text = iml_make_imtext (s, status_str, NULL);
  lp = (iml_inst *) s->If->m->iml_make_status_draw_inst (s, text);
  s->If->m->iml_link_inst_tail (&rrv, lp);
  s->If->m->iml_execute (s, &rrv);
}

static void
iml_preedit_start (iml_session_t *s)
{
  iml_inst *lp, *rrv = NULL;

  lp = (iml_inst *) s->If->m->iml_make_preedit_start_inst (s);
  s->If->m->iml_link_inst_tail (&rrv, lp);
}

static void
iml_preedit_end (iml_session_t *s)
{
  iml_inst *lp, *rrv = NULL;

  lp = (iml_inst *) s->If->m->iml_make_preedit_erase_inst (s);
  s->If->m->iml_link_inst_tail (&rrv, lp);

  lp = (iml_inst *) s->If->m->iml_make_preedit_done_inst (s);
  s->If->m->iml_link_inst_tail (&rrv, lp);

  s->If->m->iml_execute (s, &rrv);
}

/*
 * Caret position is invalid if the `caret_pos` is -1.
 */
static void
iml_preedit_draw (iml_session_t *s,
		  UTFCHAR *preedit_str,
		  int caret_pos)
{
  int len = utfchar_length (preedit_str);
  iml_inst *lp, *rrv = NULL;
  IMText *text;

  iml_preedit_start (s);

  if (!len)
    {
      lp = (iml_inst *) 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;
    }

  text = iml_make_imtext (s, preedit_str, NULL);
  lp = (iml_inst *) s->If->m->iml_make_preedit_draw_inst (s, text);
  s->If->m->iml_link_inst_tail (&rrv, lp);

  if (caret_pos != -1)
    {
      lp = (iml_inst *) s->If->m->iml_make_preedit_caret_inst (s,
							       caret_pos);
      s->If->m->iml_link_inst_tail (&rrv, lp);
    }

  s->If->m->iml_execute (s, &rrv);
}

static void
iml_lookup_start (iml_session_t *s,
		  LayoutInfo *layout)
{
  iml_inst *lp;
  IMLookupStartCallbackStruct *start_cb;
  LayoutInfo *tmp_layout;

  if (s)
    {
      start_cb = (IMLookupStartCallbackStruct *) s->If->m->iml_new (s,
					  sizeof (IMLookupStartCallbackStruct));
      tmp_layout = (LayoutInfo *) s->If->m->iml_new (s, sizeof (LayoutInfo));
    }
  else
    {
      start_cb = (IMLookupStartCallbackStruct *) malloc (sizeof (IMLookupStartCallbackStruct));
      tmp_layout = (LayoutInfo *) malloc (sizeof (LayoutInfo));
    }

  memset (start_cb, 0, sizeof (IMLookupStartCallbackStruct));
  memset (tmp_layout, 0, sizeof (LayoutInfo));

  start_cb->IMPreference = tmp_layout;

  memcpy (start_cb->IMPreference, layout, sizeof (LayoutInfo));
  start_cb->IMPreference->whoOwnsLabel = IMOwnsLabel;

  start_cb->CBPreference = NULL;
  start_cb->whoIsMaster = IMIsMaster;

  lp = (iml_inst *) s->If->m->iml_make_lookup_start_inst (s, start_cb);
  s->If->m->iml_execute (s, &lp);
}

static void
iml_lookup_end (iml_session_t *s)
{
  iml_inst *lp;

  lp = (iml_inst *) s->If->m->iml_make_lookup_done_inst (s);
  s->If->m->iml_execute (s, &lp);
}

static void
iml_lookup_draw (iml_session_t *s,
		 int lookup_num,
		 UTFCHAR **lookup_strs,
		 IMFeedbackList **lookup_feedbacks,
		 UTFCHAR **label_strs,
		 IMFeedbackList **label_feedbacks,
		 UTFCHAR *title_str,
		 IMFeedbackList *title_feedbacks,
		 int cur_cand_id,
		 int vertical)
{
  int i, max_len = 0;
  IMLookupStartCallbackStruct *start_cb;
  IMLookupDrawCallbackStruct *draw_cb;
  IMFeedbackList *feedback;
  IMText **cand, **label;
  iml_inst *lp;
  LayoutInfo *layout;

  if (lookup_num <= 0 || !lookup_strs || !label_strs)
    return;

  if (s)
    {
      start_cb = (IMLookupStartCallbackStruct *) s->If->m->iml_new (s,
					    sizeof (IMLookupStartCallbackStruct));
      layout = (LayoutInfo *) s->If->m->iml_new (s, sizeof (LayoutInfo));
    }
  else
    {
      start_cb = (IMLookupStartCallbackStruct *) malloc (sizeof (IMLookupStartCallbackStruct));
      layout = (LayoutInfo *) malloc (sizeof (LayoutInfo));
    }

  layout->choice_per_window = lookup_num;
  layout->ncolumns = (vertical) ? 1 : lookup_num;
  layout->nrows = (vertical) ? lookup_num : 1;
  layout->drawUpDirection = vertical;
  layout->whoOwnsLabel = IMOwnsLabel;

  start_cb->IMPreference = layout;

  lp = s->If->m->iml_make_lookup_start_inst (s, start_cb);
  s->If->m->iml_execute (s, &lp);

  if (s)
    cand = (IMText **) s->If->m->iml_new (s, lookup_num * sizeof (IMText *));
  else
    cand = (IMText **) malloc (lookup_num * sizeof (IMText *));

  if (!cand) return;
  memset (cand, 0, lookup_num * sizeof (IMText *));

  for (i = 0; i < lookup_num; ++i)
    {
      if (lookup_feedbacks) 
	feedback = lookup_feedbacks[i];
      else
	feedback = NULL;

      if (lookup_strs[i])
	cand[i] = (IMText *)iml_make_imtext (s, lookup_strs[i], feedback);
    }

  if (s)
    label = (IMText **) s->If->m->iml_new (s, lookup_num * sizeof (IMText *));
  else
    label = (IMText **) malloc (lookup_num * sizeof (IMText *));

  if (!label) return;
  memset (label, 0, sizeof (lookup_num * sizeof (IMText *)));

  for (i = 0; i < lookup_num; ++i)
    {
      if (label_feedbacks)
	feedback = label_feedbacks[i];
      else
	feedback = NULL;

      if (label_strs[i])
	label[i] = (IMText *)iml_make_imtext (s, label_strs[i], feedback);
    }

  if (s)
    draw_cb = (IMLookupDrawCallbackStruct *) s->If->m->iml_new (s,
					sizeof (IMLookupDrawCallbackStruct));
  else
    draw_cb = (IMLookupDrawCallbackStruct *) malloc (sizeof (IMLookupDrawCallbackStruct));

  if (!draw_cb) return;

  memset (draw_cb, 0, sizeof (IMLookupDrawCallbackStruct));

  if (title_str)
    draw_cb->title = (IMText *) iml_make_imtext (s, title_str, title_feedbacks);

  draw_cb->n_choices = lookup_num;
  draw_cb->index_of_first_candidate = 0;
  draw_cb->index_of_last_candidate = lookup_num - 1;
  draw_cb->index_of_current_candidate = cur_cand_id;

  if (s)
    draw_cb->choices = (IMChoiceObject *) s->If->m->iml_new (s,
					     lookup_num * sizeof (IMChoiceObject));
  else
    draw_cb->choices = (IMChoiceObject *) malloc (lookup_num * sizeof (IMChoiceObject));

  if (!draw_cb->choices) return;

  memset (draw_cb->choices, 0, lookup_num * sizeof (IMChoiceObject));

  for (i = 0; i < lookup_num; ++i)
    {
      IMText *vt; /* for value */
      IMText *lt; /* for label */

      vt = draw_cb->choices[i].value = cand[i];
      lt = draw_cb->choices[i].label = label[i];

      if (vt && max_len < vt->char_length)
	max_len = vt->char_length;
    }

  draw_cb->max_len = max_len;

  lp = (iml_inst *) s->If->m->iml_make_lookup_draw_inst (s, draw_cb);
  s->If->m->iml_execute (s, &lp);
}

static void
iml_aux_start (iml_session_t *s,
	       char *auxname)
{
  iml_inst *lp;
  IMAuxStartCallbackStruct *start_cb;

  if (s)
    start_cb = (IMAuxStartCallbackStruct *) s->If->m->iml_new (s,
					  sizeof (IMAuxStartCallbackStruct));
  else
    start_cb = (IMAuxStartCallbackStruct *) malloc (sizeof (IMAuxStartCallbackStruct));

  if (!start_cb) return;

  memset (start_cb, 0, sizeof (IMAuxStartCallbackStruct));
  start_cb->aux_name = auxname;

  lp = (iml_inst *) s->If->m->iml_make_aux_start_inst (s, start_cb);
  s->If->m->iml_execute (s, &lp);
}

static void
iml_aux_done (iml_session_t *s,
	      char *auxname)
{
  iml_inst *lp;
  IMAuxDoneCallbackStruct *done_cb;

  if (s)
    done_cb = (IMAuxDoneCallbackStruct *) s->If->m->iml_new (s,
				     sizeof (IMAuxDoneCallbackStruct));
  else
    done_cb = (IMAuxDoneCallbackStruct *) malloc (sizeof (IMAuxDoneCallbackStruct));

  if (!done_cb) return;

  memset (done_cb, 0, sizeof (IMAuxDoneCallbackStruct));
  done_cb->aux_name = auxname;

  lp = (iml_inst *) s->If->m->iml_make_aux_done_inst (s, done_cb);
  s->If->m->iml_execute (s, &lp);
}

static void
iml_aux_draw (iml_session_t *s,
	      char *auxname,
	      int num_integers,
	      int *integers,
	      int num_strings,
	      int *string_char_lens,
	      UTFCHAR **strings)
{
  iml_inst *lp;
  IMText *text;
  IMAuxDrawCallbackStruct *draw_cb;
  int i, len;

  if (s)
    draw_cb = (IMAuxDrawCallbackStruct *) s->If->m->iml_new (s,
						     sizeof (IMAuxDrawCallbackStruct));
  else
    draw_cb = (IMAuxDrawCallbackStruct *) malloc (sizeof (IMAuxDrawCallbackStruct));

  if (!draw_cb) return;

  memset (draw_cb, 0, sizeof (IMAuxDrawCallbackStruct));
  draw_cb->aux_name = auxname;

  draw_cb->count_integer_values = num_integers;
  if (num_integers)
    {
      draw_cb->integer_values = (int *) s->If->m->iml_new (s,
					    sizeof (int) * num_integers);
      memset (draw_cb->integer_values, 0, sizeof (int) * num_integers);
      memset (draw_cb->integer_values, 0, sizeof (int) * num_integers);

      for (i = 0; i < num_integers; ++i)
	draw_cb->integer_values[i] = integers[i];
    }

  draw_cb->count_string_values = num_strings;
  if (num_strings)
    {
      draw_cb->string_values = (IMText *) s->If->m->iml_new (s,
					     sizeof (IMText) * num_strings);
      memset (draw_cb->string_values, 0, sizeof (IMText) * num_strings);

      draw_cb->string_values->encoding = UTF16_CODESET;
      for (i = 0, text = draw_cb->string_values; i < num_strings; ++i, ++text)
	{
	  len = strings[i] ? utfchar_length (strings[i]) : 0;
	  text->text.utf_chars = (UTFCHAR *) s->If->m->iml_new (s,
						sizeof (UTFCHAR) * (len + 1));
	  memset (text->text.utf_chars, 0, sizeof (UTFCHAR) * (len + 1));
	  text->char_length = len + 1;
	  if (strings[i])
	    memcpy (text->text.utf_chars, strings[i], len * sizeof (UTFCHAR));
	}
    }

  lp = (iml_inst *) s->If->m->iml_make_aux_draw_inst (s, draw_cb);
  s->If->m->iml_execute (s, &lp);
}

/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */
iiim-iml.diff (text/x-patch, 4.3 KB)
Index: iiimsf/lib/iml/SunIMConf.c
===================================================================
--- iiimsf/lib/iml/SunIMConf.c	(revision 2799)
+++ iiimsf/lib/iml/SunIMConf.c	(working copy)
@@ -65,6 +65,7 @@
 #endif
 
 Public iml_methods_t *_iml_dup_iml_methods();
+Public iml_methods_wrapper_t *_iml_dup_iml_methods_wrapper();
 
 #ifdef	sun
 int is_cm_available(char *locale);
@@ -328,6 +329,7 @@
   If->if_name = strdup(if_name);
   If->ifpath_name = strdup(iiimf_home);
   If->m = _iml_dup_iml_methods();
+  If->m_wrapper = _iml_dup_iml_methods_wrapper();
 #ifdef	DEBUG
   printf("try to call if_OpenIF() with locale=%s if_name=%s if_path=%s\n",
 	 If->locale, If->if_name, if_path);
Index: iiimsf/lib/iml/ChangeLog
===================================================================
--- iiimsf/lib/iml/ChangeLog	(revision 2799)
+++ iiimsf/lib/iml/ChangeLog	(working copy)
@@ -1,3 +1,13 @@
+2005-08-31  Federic Zhang <[email protected]>
+
+	Add convenient functions for low-level iml_methods.
+	
+	* Makefile.am: Add SunIMSubr2.c, IMUtil.c into libiml_la_SOURCES.
+	* SunIMSubr2.c: New
+	* IMUtil.c, IMUtil.h: New
+	* SunIM.c (if_CloseIF): free If->m_wrapper.
+	* SunIMConf.c (if_configure): new If->m_wrapper with _iml_dup_iml_methods_wrapper.
+	
 2005-08-30  AShiZaWa KaZuNoRi  <[email protected]>
 
 	* fop.c: fixes for errno
Index: iiimsf/lib/iml/Makefile.am
===================================================================
--- iiimsf/lib/iml/Makefile.am	(revision 2799)
+++ iiimsf/lib/iml/Makefile.am	(working copy)
@@ -1,2 +1,2 @@
-libiml_la_SOURCES = SunIM.c SunIMConf.c SunIMConf2.c SunIMMMan.c SunIMSubr.c IMLSubr.c fop.c fop_file.c
+libiml_la_SOURCES = SunIM.c SunIMConf.c SunIMConf2.c SunIMMMan.c SunIMSubr.c IMLSubr.c SunIMSubr2.c IMUtil.c fop.c fop_file.c
 noinst_LTLIBRARIES = libiml.la
Index: iiimsf/lib/iml/SunIM.c
===================================================================
--- iiimsf/lib/iml/SunIM.c	(revision 2799)
+++ iiimsf/lib/iml/SunIM.c	(working copy)
@@ -244,6 +244,9 @@
         If->ifm->if_CloseIF(If);
     }
 
+    if (If->m_wrapper) {
+        free (If->m_wrapper);
+    }
     if (If->m) {
         free(If->m);
     }
Index: include/iml/SunIMMthd.h
===================================================================
--- include/iml/SunIMMthd.h	(revision 2799)
+++ include/iml/SunIMMthd.h	(working copy)
@@ -264,6 +264,29 @@
 
 }   iml_methods_t;
 
+/* Convenient functions, which are the wrapper of low level of iml methods */
+typedef struct _iml_methods_wrapper {
+  void (*iml_commit) (iml_session, UTFCHAR *);
+  void (*iml_forward_keypress) (iml_session, IMKeyEventStruct *);
+  void (*iml_conversion_on) (iml_session);
+  void (*iml_conversion_off) (iml_session);
+  void (*iml_status_start) (iml_session);
+  void (*iml_status_end) (iml_session);
+  void (*iml_status_draw) (iml_session, UTFCHAR *);
+  void (*iml_preedit_start) (iml_session);
+  void (*iml_preedit_end) (iml_session);
+  void (*iml_preedit_draw) (iml_session, UTFCHAR *, int);
+  void (*iml_lookup_start) (iml_session, LayoutInfo *);
+  void (*iml_lookup_end) (iml_session);
+  void (*iml_lookup_draw) (iml_session, int, UTFCHAR **,
+			   IMFeedbackList **, UTFCHAR **,
+			   IMFeedbackList **, UTFCHAR *,
+			   IMFeedbackList *, int, int);
+  void (*iml_aux_start) (iml_session, char *);
+  void (*iml_aux_done) (iml_session, char *);
+  void (*iml_aux_draw) (iml_session, char *, int, int *, int, int *, UTFCHAR **);
+} iml_methods_wrapper_t;
+
 typedef struct _if_methods {
     Bool(*if_OpenIF) (iml_if);
     Bool(*if_CloseIF) (iml_if);
@@ -387,6 +410,8 @@
 
     Bool need_keyrelease;
     IMEInfo *imeinfo_list;
+
+    iml_methods_wrapper_t *m_wrapper; /* convenient functions */
 }   iml_if_t;
 
 typedef enum {
Index: include/ChangeLog
===================================================================
--- include/ChangeLog	(revision 2799)
+++ include/ChangeLog	(working copy)
@@ -1,3 +1,12 @@
+2005-08-31  Federic Zhang <[email protected]>
+
+	New convenient functions for low-level iml_methods.
+	
+	* iml/SunIMMthd.h: new struct iml_methods_wrapper_t and
+	  add 'm_wrapper' to iml_if_t, then LE developer can use it
+	  with s->If->m_wrapper to obsolete those low level
+	  iml_methods.
+	  
 2005-08-24  AShiZaWa KaZuNoRi  <[email protected]>
 
 	* iml/iml_fop.h (iml_fop_utimes_t): fix argument types
ime.c (text/x-csrc, 15 KB)
/*
  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.

*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "SunIMSubr2.h"
#include "ime_session.h"
#include "aux_protocol.h"
#include "ime_util.h"
#include "ime.h"

#define IMM_SERVICE_VERSION 0x0101

static ImeInfo service_get_ime_info (ImeInputContext);
static ImeEncoding service_get_session_encoding (ImeInputContext);
static ImmResult service_show_preedit (ImeInputContext);
static ImmResult service_hide_preedit (ImeInputContext);
static ImmResult service_update_preedit (ImeInputContext, ImePreedit);
static ImmResult service_move_preedit_caret (ImeInputContext, int);
static ImmResult service_show_candidates (ImeInputContext);
static ImmResult service_hide_candidates (ImeInputContext);
static ImmResult service_update_candidates (ImeInputContext, ImeCandidates);
static ImmResult service_commit (ImeInputContext, unsigned char *);
static ImmResult service_show_aux (ImeInputContext, const char *);
static ImmResult service_hide_aux (ImeInputContext, ImHandle);
static ImmResult service_send_aux_data (ImeEvent);
static void *service_get_ime_data (ImeInputContext, ImeScopeType);
static ImmResult service_set_ime_data (ImeInputContext, ImeScopeType, void *);
static void *service_load_user_profile (ImeInputContext, const char *, int *);
static ImmResult service_free_user_profile (void *);
static ImmResult service_beep (ImeInputContext, ImeBeepType);

ImmServicesRec imm_services = {
  IMM_SERVICE_VERSION,          /* version              */
  service_get_ime_info,         /* ImmGetImeInfo        */
  service_get_session_encoding, /* ImmGetClientEncoding */
  service_show_preedit,         /* ImmShowPreedit       */
  service_hide_preedit,         /* ImmHidePreeit        */
  service_update_preedit,       /* ImmUpdatePredit      */
  service_move_preedit_caret,   /* ImmMovePreeditCaret  */
  service_show_candidates,      /* ImmShowCandidates    */
  service_hide_candidates,      /* ImmHideCandidates    */
  service_update_candidates,    /* ImmUpdateCandidates  */
  service_commit,               /* ImmCommit            */
  service_show_aux,             /* ImmStartAux          */
  service_hide_aux,             /* ImmCloseAux          */
  service_send_aux_data,        /* ImmSendUiMessage     */
  service_get_ime_data,         /* ImmGetData           */
  service_set_ime_data,         /* ImmSetData           */
  service_load_user_profile,    /* ImmLoadUserProfile   */
  service_free_user_profile,    /* ImmFreeUserProfile   */
  NULL,                         /* ImmSaveUserProfile   */
  service_beep,                 /* ImmBeep              */
  NULL,                         /* ImmPrefilterKey      */
  NULL                          /* ImmGetPropertyList   */
};

static ImeInfo
service_get_ime_info (ImeInputContext ic)
{
  SessionContext *sc = (SessionContext *) ic;
  ImeModule ime_module;

  if (!sc || !sc->s) return NULL;

  // FIXME why not use cur_ime_module here?
  ime_module = session_get_current_ime_module (sc->s);

  return ime_module ? ime_module->info : NULL;
}

static ImeEncoding
service_get_session_encoding (ImeInputContext ic)
{
  SessionContext *sc = (SessionContext *) ic;

  /* 
   * UTF-8 would be default encoding if encoding isn't specified
   */
  if (!sc || !sc->s) return ENCODE_UTF8;

  // FIXME why don't use client encoding directly here?
  return session_get_client_encoding (sc->s);
}

static ImmResult
service_show_preedit (ImeInputContext ic)
{
  SessionContext *sc = (SessionContext *) ic;

  if (!sc || !sc->s) return ImmFAIL;

  sc->preedit_show = True;

  /* FIXME need to support common aux win or aux object here */
  if (sc->auxtype == DEFAULT_AUX_TYPE)
    sc->s->If->m_wrapper->iml_preedit_start (sc->s);

  return ImmOK;
}

static ImmResult
service_hide_preedit (ImeInputContext ic)
{
  SessionContext *sc = (SessionContext *) ic;

  if (!sc || !sc->s) return ImmFAIL;

  sc->preedit_show = False;

  /* FIXME need to support common aux or aux object here */
  if (sc->auxtype == DEFAULT_AUX_TYPE)
    sc->s->If->m_wrapper->iml_preedit_end (sc->s);

  return ImmOK;
}

static void
dupIMText (ImeText dest, ImeText src)
{
  if (!dest) return;

  if (!src)
    memset (dest, 0, sizeof (ImeTextRec));

  dest->count_feedbacks = src->count_feedbacks;

  if (src->text)
    dest->text = strdup (src->text);

  if (src->feedbacks)
    {
      int i;

      dest->feedbacks = (ImeFeedbackRec *)malloc (src->count_feedbacks *
						  sizeof (ImeFeedbackRec));

      for (i = 0; i < src->count_feedbacks; ++i)
	dest->feedbacks[i] = src->feedbacks[i];
    }
}

static void
dupPreedit (ImePreedit dest, ImePreedit src)
{
  if (!dest) return;

  if (!src)
    memset (dest, 0, sizeof (ImePreeditRec));

  dest->caret = src->caret;
  dest->cand_list_start = src->cand_list_start;

  dupIMText (&dest->preedit, &src->preedit);
}

static void
dupCandidates (ImeCandidates dest, ImeCandidates src)
{
  if (!dest) return;

  if (!src)
    memset (dest, 0, sizeof (ImeCandidatesRec));

  dest->count = src->count;
  dest->focus = src->focus;
  dest->page_state = src->page_state;
  dest->horizontal = src->horizontal;

  if (src->title)
    dest->title = strdup (src->title);

  if (src->numbers)
    dest->numbers = strdup (src->numbers);

  if (src->count)
    {
      int i;

      dest->candidates = (ImeTextRec *)malloc (src->count * sizeof (ImeTextRec));

      for (i = 0; i < src->count; ++i)
	dupIMText (dest->candidates + i, src->candidates + i);
    }
}

void 
freePreeditInternal (ImePreedit pre)
{
  if (pre->preedit.text) free (pre->preedit.text);
  if (pre->preedit.feedbacks) free (pre->preedit.feedbacks);

  memset (pre, 0, sizeof (ImePreeditRec));
}

void
freeCandidatesInternal (ImeCandidates cand)
{
  if (cand->title) free (cand->title);
  if (cand->numbers) free (cand->numbers);
  if (cand->candidates)
    {
      int i;

      for (i = 0; i < cand->count; ++i)
	{	  
	  if (cand->candidates[i].text)
	    free (cand->candidates[i].text);
	  if (cand->candidates[i].feedbacks)
	    free (cand->candidates[i].feedbacks);
	}
    }

  memset (cand, 0, sizeof (ImeCandidatesRec));
}

static ImmResult
service_update_preedit (ImeInputContext ic,
			ImePreedit ime_preedit)
{
  SessionContext *sc = (SessionContext *) ic;

  if (!sc || !sc->s || !ime_preedit) return ImmFAIL;

  if (ime_preedit != (ImePreedit) &sc->preedit_backup)
    {
      freePreeditInternal ((ImePreedit) &sc->preedit_backup);
      dupPreedit ((ImePreedit)&sc->preedit_backup, ime_preedit);
    }

  /* FIMXE need to support common aux or aux object here */
  if (sc->auxtype == DEFAULT_AUX_TYPE)
    {
      ImeEncoding encoding;
      UTFCHAR tmp_buf[1024], *tmp_ptr;

      if ((encoding = session_get_current_ime_encoding (sc->s)) ==
	  ENCODE_INVALID)
	return ImmFAIL;

      tmp_ptr = tmp_buf;
      my_convert (encoding, ime_preedit->preedit.text, &tmp_ptr);

      sc->s->If->m_wrapper->iml_preedit_start (sc->s);
      sc->s->If->m_wrapper->iml_preedit_draw (sc->s, tmp_buf, ime_preedit->caret);
    }

  return ImmOK;
}

static ImmResult
service_move_preedit_caret (ImeInputContext ic,
			    int index)
{
  return ImmOK;
}

static ImmResult
service_show_candidates (ImeInputContext ic)
{
  SessionContext *sc = (SessionContext *) ic;

  if (!sc || !sc->s) return ImmFAIL;

  sc->cand_show = True;

  /* FIXME need to support common aux or aux object here */
  if (sc->auxtype == DEFAULT_AUX_TYPE)
    {
      LayoutInfo layout;
      Bool vertical_type = True; //FIXME
      int layout_capacity = 10; //FIXME

      layout.choice_per_window = layout_capacity;
      if (vertical_type)
	{
	  layout.ncolumns = 1;
	  layout.nrows = layout_capacity;
	  layout.drawUpDirection = DrawUpVertically;
	}
      else
	{
	  layout.ncolumns = layout_capacity;
	  layout.nrows = 1;

	  layout.drawUpDirection = DrawUpHorizontally;
	}

      sc->s->If->m_wrapper->iml_lookup_start (sc->s, &layout);
    }

  return ImmOK;
}

static ImmResult

service_hide_candidates (ImeInputContext ic)
{
  SessionContext *sc = (SessionContext *) ic;

  if (!sc || !sc->s) return ImmFAIL;

  sc->cand_show = False;
  
  /* FIXME need to support common aux or aux object here */
  if (sc->auxtype == DEFAULT_AUX_TYPE)
    sc->s->If->m_wrapper->iml_lookup_end (sc->s);

  return ImmOK;
}

static ImmResult
service_update_candidates (ImeInputContext ic,
			   ImeCandidates ime_candidates)
{
  SessionContext *sc = (SessionContext *) ic;

  if (!sc || !sc->s || !ime_candidates) return ImmFAIL;

  if (ime_candidates != (ImeCandidates) &sc->cand_backup)
    {
      freeCandidatesInternal ((ImeCandidates) &sc->cand_backup);
      dupCandidates ((ImeCandidates) &sc->cand_backup, ime_candidates);
    }

  /* FIXME need to support common aux or aux object here */
  if (sc->auxtype == DEFAULT_AUX_TYPE)
    {
      UTFCHAR **lookup_strs, **label_strs;
      UTFCHAR tmp_buf[1024], label_buf[64], *tmp_ptr;
      ImeEncoding encoding;
      int num_candidates = ime_candidates->count;
      int i;
      
      if ((encoding = session_get_current_ime_encoding (sc->s)) ==
	  ENCODE_INVALID)
	return ImmFAIL;

      lookup_strs = (UTFCHAR **) malloc (num_candidates * sizeof (UTFCHAR *));
      if (!lookup_strs) return ImmFAIL;
      memset (lookup_strs, 0, num_candidates * sizeof (UTFCHAR *));

      label_strs = (UTFCHAR **) malloc (num_candidates * sizeof (UTFCHAR *));
      if (!label_strs) return ImmFAIL;
      memset (label_strs, 0, num_candidates * sizeof (UTFCHAR *));
      
      if (ime_candidates->numbers)
	{
	  tmp_ptr = label_buf;
	  my_convert (encoding, ime_candidates->numbers, &tmp_ptr);
	}

      for (i = 0; i < num_candidates; ++i)
	{
	  if (!ime_candidates->candidates[i].text)
	    continue;

	  tmp_ptr = tmp_buf;
	  my_convert (encoding, ime_candidates->candidates[i].text,
		      &tmp_ptr);

	  lookup_strs[i] = (UTFCHAR *) malloc (sizeof (UTFCHAR) * 1024); //FIXME
	  if (!lookup_strs[i]) continue;
	  memset (lookup_strs[i], 0, sizeof (UTFCHAR) * 1024);
	  utfchar_copy (lookup_strs[i], tmp_buf);

	  label_strs[i] = (UTFCHAR *) malloc (sizeof (UTFCHAR) * 3); //FIXME
	  if (!label_strs[i]) continue;
	  memset (label_strs[i], 0, sizeof (UTFCHAR) * 3);

	  label_strs[i][0] = (ime_candidates->numbers) ? (label_buf[i]) : ('1' + i);
	  label_strs[i][1] = '.';
	  label_strs[i][2] = 0;
	}

      sc->s->If->m_wrapper->iml_lookup_draw (sc->s,
		       num_candidates,
		       lookup_strs,
		       NULL,
		       label_strs,
		       NULL,
		       NULL,
		       NULL,
		       0,
		       (ime_candidates->horizontal) ? 0 : 1);

      for (i = 0; i < num_candidates; ++i)
	{
	  if (lookup_strs[i]) free (lookup_strs[i]);
	  if (label_strs[i]) free (label_strs[i]);
	}

      free (lookup_strs);
      free (label_strs);
    }

  return ImmOK;
}			   

static ImmResult
service_commit (ImeInputContext ic,
		unsigned char *commit_str)
{
  SessionContext *sc = (SessionContext *) ic;

  if (!sc || !sc->s || commit_str) return ImmFAIL;

  if (sc->auxtype == DEFAULT_AUX_TYPE)
    {
      ImeEncoding encoding;
      UTFCHAR tmp_buf[1024], *tmp_ptr;

      if ((encoding = session_get_current_ime_encoding (sc->s))
	  == ENCODE_INVALID)
	return ImmFAIL;

      tmp_ptr = tmp_buf;
      my_convert (encoding, commit_str, &tmp_ptr);

      sc->s->If->m_wrapper->iml_commit (sc->s, tmp_buf);
    }

  return ImmOK;
}

static ImmResult
service_show_aux (ImeInputContext ic,
		  const char *auxname)
{
  SessionContext *sc = (SessionContext *) ic;
  int command = COMMONAUX_SHOW_NOTIFY; // FIXME

  if (!sc || !sc->s || !auxname) return ImmFAIL;

  sc->s->If->m_wrapper->iml_aux_start (sc->s, (char *) auxname);
  sc->s->If->m_wrapper->iml_aux_draw (sc->s, (char *) auxname, 1, &command, 0, NULL, NULL);

  return ImmOK;
}

static ImmResult
service_hide_aux (ImeInputContext ic,
		  ImHandle handle)
{
  SessionContext *sc = (SessionContext *) ic;
  int command = COMMONAUX_HIDE_NOTIFY; // FIXME
  unsigned char *auxname = (unsigned char *)handle;

  if (!sc || !sc->s || !auxname) return ImmFAIL;

  sc->s->If->m_wrapper->iml_aux_draw (sc->s, auxname, 1, &command, 0, NULL, NULL);

  return ImmOK;
}

static ImmResult
service_send_aux_data (ImeEvent event)
{
  return ImmOK;
}

static void *
service_get_ime_data (ImeInputContext ic,
		      ImeScopeType scope)
{
  SessionContext *sc = (SessionContext *) ic;
  void *ime_data = NULL;

  if (!sc) return NULL;

  switch (scope)
    {
    case IME_SCOPE_SESSION:
      ime_data = sc->ime_session_data;
      break;
    case IME_SCOPE_DESKTOP:
      ime_data = sc->ime_desktop_data;
      break;
    case IME_SCOPE_USER:
      ime_data = sc->ime_user_data;
      break;
    }

  return ime_data;     
}

static ImmResult
service_set_ime_data (ImeInputContext ic,
		      ImeScopeType scope,
		      void *data)
{
  SessionContext *sc = (SessionContext *) ic;

  if (!sc) return ImmFAIL;

  switch (scope)
    {
    case IME_SCOPE_SESSION:
      sc->ime_session_data = data;
      break;
    case IME_SCOPE_DESKTOP:
      sc->ime_desktop_data = data;
    case IME_SCOPE_USER:
      sc->ime_user_data = data;
    }

  return ImmOK;
}

static void *
service_load_user_profile (ImeInputContext ic,
			   const char *category,
			   int *profile)
{
  return NULL;
}

static ImmResult
service_free_user_profile (void *buf)
{
  return ImmOK;
}

static ImmResult
service_beep (ImeInputContext ic,
	      ImeBeepType beep_type)
{
  return ImmOK;
}

/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */