Blame modules/input/gtkimcontextime.c

Packit Service fb6fa5
/*
Packit Service fb6fa5
 * gtkimcontextime.c
Packit Service fb6fa5
 * Copyright (C) 2003 Takuro Ashie
Packit Service fb6fa5
 * Copyright (C) 2003-2004 Kazuki IWAMOTO
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * This library is free software; you can redistribute it and/or
Packit Service fb6fa5
 * modify it under the terms of the GNU Lesser General Public
Packit Service fb6fa5
 * License as published by the Free Software Foundation; either
Packit Service fb6fa5
 * version 2 of the License, or (at your option) any later version.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * This library is distributed in the hope that it will be useful,
Packit Service fb6fa5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service fb6fa5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service fb6fa5
 * Lesser General Public License for more details.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * You should have received a copy of the GNU Lesser General Public
Packit Service fb6fa5
 * License along with this library; if not, write to the
Packit Service fb6fa5
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit Service fb6fa5
 * Boston, MA 02111-1307, USA.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 *  Please see the following site for the detail of Windows IME API.
Packit Service fb6fa5
 *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/appendix/hh/appendix/imeimes2_35ph.asp
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
#include "gtkimcontextime.h"
Packit Service fb6fa5
Packit Service fb6fa5
#include "imm-extra.h"
Packit Service fb6fa5
Packit Service fb6fa5
#include <gdk/gdkkeysyms.h>
Packit Service fb6fa5
#include "gdk/win32/gdkwin32.h"
Packit Service fb6fa5
#include "gdk/gdkkeysyms.h"
Packit Service fb6fa5
Packit Service fb6fa5
#include <pango/pango.h>
Packit Service fb6fa5
Packit Service fb6fa5
/* avoid warning */
Packit Service fb6fa5
#ifdef STRICT
Packit Service fb6fa5
# undef STRICT
Packit Service fb6fa5
# include <pango/pangowin32.h>
Packit Service fb6fa5
# ifndef STRICT
Packit Service fb6fa5
#   define STRICT 1
Packit Service fb6fa5
# endif
Packit Service fb6fa5
#else /* STRICT */
Packit Service fb6fa5
#   include <pango/pangowin32.h>
Packit Service fb6fa5
#endif /* STRICT */
Packit Service fb6fa5
Packit Service fb6fa5
/* #define BUFSIZE 4096 */
Packit Service fb6fa5
Packit Service fb6fa5
#define IS_DEAD_KEY(k) \
Packit Service fb6fa5
    ((k) >= GDK_dead_grave && (k) <= (GDK_dead_dasia+1))
Packit Service fb6fa5
Packit Service fb6fa5
#define FREE_PREEDIT_BUFFER(ctx) \
Packit Service fb6fa5
{                                \
Packit Service fb6fa5
  g_free((ctx)->priv->comp_str); \
Packit Service fb6fa5
  g_free((ctx)->priv->read_str); \
Packit Service fb6fa5
  (ctx)->priv->comp_str = NULL;  \
Packit Service fb6fa5
  (ctx)->priv->read_str = NULL;  \
Packit Service fb6fa5
  (ctx)->priv->comp_str_len = 0; \
Packit Service fb6fa5
  (ctx)->priv->read_str_len = 0; \
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
struct _GtkIMContextIMEPrivate
Packit Service fb6fa5
{
Packit Service fb6fa5
  /* save IME context when the client window is focused out */
Packit Service fb6fa5
  DWORD conversion_mode;
Packit Service fb6fa5
  DWORD sentence_mode;
Packit Service fb6fa5
Packit Service fb6fa5
  LPVOID comp_str;
Packit Service fb6fa5
  DWORD comp_str_len;
Packit Service fb6fa5
  LPVOID read_str;
Packit Service fb6fa5
  DWORD read_str_len;
Packit Service fb6fa5
Packit Service fb6fa5
  guint32 dead_key_keyval;
Packit Service fb6fa5
};
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
/* GObject class methods */
Packit Service fb6fa5
static void gtk_im_context_ime_class_init (GtkIMContextIMEClass *class);
Packit Service fb6fa5
static void gtk_im_context_ime_init       (GtkIMContextIME      *context_ime);
Packit Service fb6fa5
static void gtk_im_context_ime_dispose    (GObject              *obj);
Packit Service fb6fa5
static void gtk_im_context_ime_finalize   (GObject              *obj);
Packit Service fb6fa5
Packit Service fb6fa5
static void gtk_im_context_ime_set_property (GObject      *object,
Packit Service fb6fa5
                                             guint         prop_id,
Packit Service fb6fa5
                                             const GValue *value,
Packit Service fb6fa5
                                             GParamSpec   *pspec);
Packit Service fb6fa5
static void gtk_im_context_ime_get_property (GObject      *object,
Packit Service fb6fa5
                                             guint         prop_id,
Packit Service fb6fa5
                                             GValue       *value,
Packit Service fb6fa5
                                             GParamSpec   *pspec);
Packit Service fb6fa5
Packit Service fb6fa5
/* GtkIMContext's virtual functions */
Packit Service fb6fa5
static void gtk_im_context_ime_set_client_window   (GtkIMContext *context,
Packit Service fb6fa5
                                                    GdkWindow    *client_window);
Packit Service fb6fa5
static gboolean gtk_im_context_ime_filter_keypress (GtkIMContext   *context,
Packit Service fb6fa5
                                                    GdkEventKey    *event);
Packit Service fb6fa5
static void gtk_im_context_ime_reset               (GtkIMContext   *context);
Packit Service fb6fa5
static void gtk_im_context_ime_get_preedit_string  (GtkIMContext   *context,
Packit Service fb6fa5
                                                    gchar         **str,
Packit Service fb6fa5
                                                    PangoAttrList **attrs,
Packit Service fb6fa5
                                                    gint           *cursor_pos);
Packit Service fb6fa5
static void gtk_im_context_ime_focus_in            (GtkIMContext   *context);
Packit Service fb6fa5
static void gtk_im_context_ime_focus_out           (GtkIMContext   *context);
Packit Service fb6fa5
static void gtk_im_context_ime_set_cursor_location (GtkIMContext   *context,
Packit Service fb6fa5
                                                    GdkRectangle   *area);
Packit Service fb6fa5
static void gtk_im_context_ime_set_use_preedit     (GtkIMContext   *context,
Packit Service fb6fa5
                                                    gboolean        use_preedit);
Packit Service fb6fa5
Packit Service fb6fa5
/* GtkIMContextIME's private functions */
Packit Service fb6fa5
static void gtk_im_context_ime_set_preedit_font (GtkIMContext    *context);
Packit Service fb6fa5
Packit Service fb6fa5
static GdkFilterReturn
Packit Service fb6fa5
gtk_im_context_ime_message_filter               (GdkXEvent       *xevent,
Packit Service fb6fa5
                                                 GdkEvent        *event,
Packit Service fb6fa5
                                                 gpointer         data);
Packit Service fb6fa5
static void get_window_position                 (GdkWindow       *win,
Packit Service fb6fa5
                                                 gint            *x,
Packit Service fb6fa5
                                                 gint            *y);
Packit Service fb6fa5
static void cb_client_widget_hierarchy_changed  (GtkWidget       *widget,
Packit Service fb6fa5
                                                 GtkWidget       *widget2,
Packit Service fb6fa5
                                                 GtkIMContextIME *context_ime);
Packit Service fb6fa5
Packit Service fb6fa5
GType gtk_type_im_context_ime = 0;
Packit Service fb6fa5
static GObjectClass *parent_class;
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
gtk_im_context_ime_register_type (GTypeModule *type_module)
Packit Service fb6fa5
{
Packit Service fb6fa5
  const GTypeInfo im_context_ime_info = {
Packit Service fb6fa5
    sizeof (GtkIMContextIMEClass),
Packit Service fb6fa5
    (GBaseInitFunc) NULL,
Packit Service fb6fa5
    (GBaseFinalizeFunc) NULL,
Packit Service fb6fa5
    (GClassInitFunc) gtk_im_context_ime_class_init,
Packit Service fb6fa5
    NULL,                       /* class_finalize */
Packit Service fb6fa5
    NULL,                       /* class_data */
Packit Service fb6fa5
    sizeof (GtkIMContextIME),
Packit Service fb6fa5
    0,
Packit Service fb6fa5
    (GInstanceInitFunc) gtk_im_context_ime_init,
Packit Service fb6fa5
  };
Packit Service fb6fa5
Packit Service fb6fa5
  gtk_type_im_context_ime =
Packit Service fb6fa5
    g_type_module_register_type (type_module,
Packit Service fb6fa5
                                 GTK_TYPE_IM_CONTEXT,
Packit Service fb6fa5
                                 "GtkIMContextIME", &im_context_ime_info, 0);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_context_ime_class_init (GtkIMContextIMEClass *class)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class);
Packit Service fb6fa5
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
Packit Service fb6fa5
Packit Service fb6fa5
  parent_class = g_type_class_peek_parent (class);
Packit Service fb6fa5
Packit Service fb6fa5
  gobject_class->finalize     = gtk_im_context_ime_finalize;
Packit Service fb6fa5
  gobject_class->dispose      = gtk_im_context_ime_dispose;
Packit Service fb6fa5
  gobject_class->set_property = gtk_im_context_ime_set_property;
Packit Service fb6fa5
  gobject_class->get_property = gtk_im_context_ime_get_property;
Packit Service fb6fa5
Packit Service fb6fa5
  im_context_class->set_client_window   = gtk_im_context_ime_set_client_window;
Packit Service fb6fa5
  im_context_class->filter_keypress     = gtk_im_context_ime_filter_keypress;
Packit Service fb6fa5
  im_context_class->reset               = gtk_im_context_ime_reset;
Packit Service fb6fa5
  im_context_class->get_preedit_string  = gtk_im_context_ime_get_preedit_string;
Packit Service fb6fa5
  im_context_class->focus_in            = gtk_im_context_ime_focus_in;
Packit Service fb6fa5
  im_context_class->focus_out           = gtk_im_context_ime_focus_out;
Packit Service fb6fa5
  im_context_class->set_cursor_location = gtk_im_context_ime_set_cursor_location;
Packit Service fb6fa5
  im_context_class->set_use_preedit     = gtk_im_context_ime_set_use_preedit;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_context_ime_init (GtkIMContextIME *context_ime)
Packit Service fb6fa5
{
Packit Service fb6fa5
  context_ime->client_window          = NULL;
Packit Service fb6fa5
  context_ime->toplevel               = NULL;
Packit Service fb6fa5
  context_ime->use_preedit            = TRUE;
Packit Service fb6fa5
  context_ime->preediting             = FALSE;
Packit Service fb6fa5
  context_ime->opened                 = FALSE;
Packit Service fb6fa5
  context_ime->focus                  = FALSE;
Packit Service fb6fa5
  context_ime->cursor_location.x      = 0;
Packit Service fb6fa5
  context_ime->cursor_location.y      = 0;
Packit Service fb6fa5
  context_ime->cursor_location.width  = 0;
Packit Service fb6fa5
  context_ime->cursor_location.height = 0;
Packit Service fb6fa5
Packit Service fb6fa5
  context_ime->priv = g_malloc0 (sizeof (GtkIMContextIMEPrivate));
Packit Service fb6fa5
  context_ime->priv->conversion_mode  = 0;
Packit Service fb6fa5
  context_ime->priv->sentence_mode    = 0;
Packit Service fb6fa5
  context_ime->priv->comp_str         = NULL;
Packit Service fb6fa5
  context_ime->priv->comp_str_len     = 0;
Packit Service fb6fa5
  context_ime->priv->read_str         = NULL;
Packit Service fb6fa5
  context_ime->priv->read_str_len     = 0;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_context_ime_dispose (GObject *obj)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMContext *context = GTK_IM_CONTEXT (obj);
Packit Service fb6fa5
  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (obj);
Packit Service fb6fa5
Packit Service fb6fa5
  if (context_ime->client_window)
Packit Service fb6fa5
    gtk_im_context_ime_set_client_window (context, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  FREE_PREEDIT_BUFFER (context_ime);
Packit Service fb6fa5
Packit Service fb6fa5
  if (G_OBJECT_CLASS (parent_class)->dispose)
Packit Service fb6fa5
    G_OBJECT_CLASS (parent_class)->dispose (obj);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_context_ime_finalize (GObject *obj)
Packit Service fb6fa5
{
Packit Service fb6fa5
  /* GtkIMContext *context = GTK_IM_CONTEXT (obj); */
Packit Service fb6fa5
  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (obj);
Packit Service fb6fa5
Packit Service fb6fa5
  g_free (context_ime->priv);
Packit Service fb6fa5
  context_ime->priv = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  if (G_OBJECT_CLASS (parent_class)->finalize)
Packit Service fb6fa5
    G_OBJECT_CLASS (parent_class)->finalize (obj);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_context_ime_set_property (GObject      *object,
Packit Service fb6fa5
                                 guint         prop_id,
Packit Service fb6fa5
                                 const GValue *value,
Packit Service fb6fa5
                                 GParamSpec   *pspec)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (object);
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime));
Packit Service fb6fa5
Packit Service fb6fa5
  switch (prop_id)
Packit Service fb6fa5
    {
Packit Service fb6fa5
    default:
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_context_ime_get_property (GObject    *object,
Packit Service fb6fa5
                                 guint       prop_id,
Packit Service fb6fa5
                                 GValue     *value,
Packit Service fb6fa5
                                 GParamSpec *pspec)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (object);
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime));
Packit Service fb6fa5
Packit Service fb6fa5
  switch (prop_id)
Packit Service fb6fa5
    {
Packit Service fb6fa5
    default:
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
GtkIMContext *
Packit Service fb6fa5
gtk_im_context_ime_new (void)
Packit Service fb6fa5
{
Packit Service fb6fa5
  return g_object_new (GTK_TYPE_IM_CONTEXT_IME, NULL);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_context_ime_set_client_window (GtkIMContext *context,
Packit Service fb6fa5
                                      GdkWindow    *client_window)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMContextIME *context_ime;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
Packit Service fb6fa5
  context_ime = GTK_IM_CONTEXT_IME (context);
Packit Service fb6fa5
Packit Service fb6fa5
  if (client_window)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      HIMC himc;
Packit Service fb6fa5
      HWND hwnd;
Packit Service fb6fa5
Packit Service fb6fa5
      hwnd = gdk_win32_window_get_impl_hwnd (client_window);
Packit Service fb6fa5
      himc = ImmGetContext (hwnd);
Packit Service fb6fa5
      if (himc)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  context_ime->opened = ImmGetOpenStatus (himc);
Packit Service fb6fa5
	  ImmGetConversionStatus (himc,
Packit Service fb6fa5
				  &context_ime->priv->conversion_mode,
Packit Service fb6fa5
				  &context_ime->priv->sentence_mode);
Packit Service fb6fa5
	  ImmReleaseContext (hwnd, himc);
Packit Service fb6fa5
	}
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (context_ime->focus)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gtk_im_context_ime_focus_out (context);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  context_ime->client_window = client_window;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gunichar
Packit Service fb6fa5
_gtk_im_context_ime_dead_key_unichar (guint    keyval,
Packit Service fb6fa5
                                      gboolean spacing)
Packit Service fb6fa5
{
Packit Service fb6fa5
  switch (keyval)
Packit Service fb6fa5
    {
Packit Service fb6fa5
#define CASE(keysym, unicode, spacing_unicode) \
Packit Service fb6fa5
      case GDK_dead_##keysym: return (spacing) ? spacing_unicode : unicode;
Packit Service fb6fa5
Packit Service fb6fa5
      CASE (grave, 0x0300, 0x0060);
Packit Service fb6fa5
      CASE (acute, 0x0301, 0x00b4);
Packit Service fb6fa5
      CASE (circumflex, 0x0302, 0x005e);
Packit Service fb6fa5
      CASE (tilde, 0x0303, 0x007e);	/* Also used with perispomeni, 0x342. */
Packit Service fb6fa5
      CASE (macron, 0x0304, 0x00af);
Packit Service fb6fa5
      CASE (breve, 0x0306, 0x02d8);
Packit Service fb6fa5
      CASE (abovedot, 0x0307, 0x02d9);
Packit Service fb6fa5
      CASE (diaeresis, 0x0308, 0x00a8);
Packit Service fb6fa5
      CASE (hook, 0x0309, 0);
Packit Service fb6fa5
      CASE (abovering, 0x030A, 0x02da);
Packit Service fb6fa5
      CASE (doubleacute, 0x030B, 0x2dd);
Packit Service fb6fa5
      CASE (caron, 0x030C, 0x02c7);
Packit Service fb6fa5
      CASE (abovecomma, 0x0313, 0);         /* Equivalent to psili */
Packit Service fb6fa5
      CASE (abovereversedcomma, 0x0314, 0); /* Equivalent to dasia */
Packit Service fb6fa5
      CASE (horn, 0x031B, 0);	/* Legacy use for psili, 0x313 (or 0x343). */
Packit Service fb6fa5
      CASE (belowdot, 0x0323, 0);
Packit Service fb6fa5
      CASE (cedilla, 0x0327, 0x00b8);
Packit Service fb6fa5
      CASE (ogonek, 0x0328, 0);	/* Legacy use for dasia, 0x314.*/
Packit Service fb6fa5
      CASE (iota, 0x0345, 0);
Packit Service fb6fa5
Packit Service fb6fa5
#undef CASE
Packit Service fb6fa5
    default:
Packit Service fb6fa5
      return 0;
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
_gtk_im_context_ime_commit_unichar (GtkIMContextIME *context_ime,
Packit Service fb6fa5
                                    gunichar         c)
Packit Service fb6fa5
{
Packit Service fb6fa5
  gchar utf8[10];
Packit Service fb6fa5
  int len;
Packit Service fb6fa5
Packit Service fb6fa5
  if (context_ime->priv->dead_key_keyval != 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gunichar combining;
Packit Service fb6fa5
Packit Service fb6fa5
      combining =
Packit Service fb6fa5
        _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval,
Packit Service fb6fa5
                                              FALSE);
Packit Service fb6fa5
      g_unichar_compose (c, combining, &c);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  len = g_unichar_to_utf8 (c, utf8);
Packit Service fb6fa5
  utf8[len] = 0;
Packit Service fb6fa5
Packit Service fb6fa5
  g_signal_emit_by_name (context_ime, "commit", utf8);
Packit Service fb6fa5
  context_ime->priv->dead_key_keyval = 0;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
gtk_im_context_ime_filter_keypress (GtkIMContext *context,
Packit Service fb6fa5
                                    GdkEventKey  *event)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMContextIME *context_ime;
Packit Service fb6fa5
  gboolean retval = FALSE;
Packit Service fb6fa5
  guint32 c;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (context), FALSE);
Packit Service fb6fa5
  g_return_val_if_fail (event, FALSE);
Packit Service fb6fa5
Packit Service fb6fa5
  if (event->type == GDK_KEY_RELEASE)
Packit Service fb6fa5
    return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
  if (event->state & GDK_CONTROL_MASK)
Packit Service fb6fa5
    return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
  context_ime = GTK_IM_CONTEXT_IME (context);
Packit Service fb6fa5
Packit Service fb6fa5
  if (!context_ime->focus)
Packit Service fb6fa5
    return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
  if (!GDK_IS_WINDOW (context_ime->client_window))
Packit Service fb6fa5
    return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
  if (event->keyval == GDK_space &&
Packit Service fb6fa5
      context_ime->priv->dead_key_keyval != 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      c = _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval, TRUE);
Packit Service fb6fa5
      context_ime->priv->dead_key_keyval = 0;
Packit Service fb6fa5
      _gtk_im_context_ime_commit_unichar (context_ime, c);
Packit Service fb6fa5
      return TRUE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  c = gdk_keyval_to_unicode (event->keyval);
Packit Service fb6fa5
Packit Service fb6fa5
  if (c)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      _gtk_im_context_ime_commit_unichar (context_ime, c);
Packit Service fb6fa5
      retval = TRUE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (IS_DEAD_KEY (event->keyval))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gunichar dead_key;
Packit Service fb6fa5
Packit Service fb6fa5
      dead_key = _gtk_im_context_ime_dead_key_unichar (event->keyval, FALSE);
Packit Service fb6fa5
Packit Service fb6fa5
      /* Emulate double input of dead keys */
Packit Service fb6fa5
      if (dead_key && event->keyval == context_ime->priv->dead_key_keyval)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          c = _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval, TRUE);
Packit Service fb6fa5
          context_ime->priv->dead_key_keyval = 0;
Packit Service fb6fa5
          _gtk_im_context_ime_commit_unichar (context_ime, c);
Packit Service fb6fa5
          _gtk_im_context_ime_commit_unichar (context_ime, c);
Packit Service fb6fa5
        }
Packit Service fb6fa5
      else
Packit Service fb6fa5
        context_ime->priv->dead_key_keyval = event->keyval;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return retval;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_context_ime_reset (GtkIMContext *context)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
Packit Service fb6fa5
  HWND hwnd;
Packit Service fb6fa5
  HIMC himc;
Packit Service fb6fa5
Packit Service fb6fa5
  if (!context_ime->client_window)
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
Packit Service fb6fa5
  himc = ImmGetContext (hwnd);
Packit Service fb6fa5
  if (!himc)
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  if (context_ime->preediting)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (ImmGetOpenStatus (himc))
Packit Service fb6fa5
        ImmNotifyIME (himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
Packit Service fb6fa5
Packit Service fb6fa5
      context_ime->preediting = FALSE;
Packit Service fb6fa5
      g_signal_emit_by_name (context, "preedit-changed");
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  ImmReleaseContext (hwnd, himc);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static gchar *
Packit Service fb6fa5
get_utf8_preedit_string (GtkIMContextIME *context_ime, gint *pos_ret)
Packit Service fb6fa5
{
Packit Service fb6fa5
  gchar *utf8str = NULL;
Packit Service fb6fa5
  HWND hwnd;
Packit Service fb6fa5
  HIMC himc;
Packit Service fb6fa5
  gint pos = 0;
Packit Service fb6fa5
Packit Service fb6fa5
  if (pos_ret)
Packit Service fb6fa5
    *pos_ret = 0;
Packit Service fb6fa5
Packit Service fb6fa5
  if (!context_ime->client_window)
Packit Service fb6fa5
    return g_strdup ("");
Packit Service fb6fa5
Packit Service fb6fa5
  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
Packit Service fb6fa5
  himc = ImmGetContext (hwnd);
Packit Service fb6fa5
  if (!himc)
Packit Service fb6fa5
    return g_strdup ("");
Packit Service fb6fa5
Packit Service fb6fa5
  if (context_ime->preediting)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      glong len;
Packit Service fb6fa5
Packit Service fb6fa5
      len = ImmGetCompositionStringW (himc, GCS_COMPSTR, NULL, 0);
Packit Service fb6fa5
      if (len > 0)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  GError *error = NULL;
Packit Service fb6fa5
	  gpointer buf = g_alloca (len);
Packit Service fb6fa5
Packit Service fb6fa5
	  ImmGetCompositionStringW (himc, GCS_COMPSTR, buf, len);
Packit Service fb6fa5
	  len /= 2;
Packit Service fb6fa5
	  utf8str = g_utf16_to_utf8 (buf, len, NULL, NULL, &error);
Packit Service fb6fa5
	  if (error)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      g_warning ("%s", error->message);
Packit Service fb6fa5
	      g_error_free (error);
Packit Service fb6fa5
	    }
Packit Service fb6fa5
Packit Service fb6fa5
	  if (pos_ret)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      pos = ImmGetCompositionStringW (himc, GCS_CURSORPOS, NULL, 0);
Packit Service fb6fa5
	      if (pos < 0 || len < pos)
Packit Service fb6fa5
		{
Packit Service fb6fa5
		  g_warning ("ImmGetCompositionString: "
Packit Service fb6fa5
			     "Invalid cursor position!");
Packit Service fb6fa5
		  pos = 0;
Packit Service fb6fa5
		}
Packit Service fb6fa5
	    }
Packit Service fb6fa5
	}
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (!utf8str)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      utf8str = g_strdup ("");
Packit Service fb6fa5
      pos = 0;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (pos_ret)
Packit Service fb6fa5
    *pos_ret = pos;
Packit Service fb6fa5
Packit Service fb6fa5
  ImmReleaseContext (hwnd, himc);
Packit Service fb6fa5
Packit Service fb6fa5
  return utf8str;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static PangoAttrList *
Packit Service fb6fa5
get_pango_attr_list (GtkIMContextIME *context_ime, const gchar *utf8str)
Packit Service fb6fa5
{
Packit Service fb6fa5
  PangoAttrList *attrs = pango_attr_list_new ();
Packit Service fb6fa5
  HWND hwnd;
Packit Service fb6fa5
  HIMC himc;
Packit Service fb6fa5
Packit Service fb6fa5
  if (!context_ime->client_window)
Packit Service fb6fa5
    return attrs;
Packit Service fb6fa5
Packit Service fb6fa5
  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
Packit Service fb6fa5
  himc = ImmGetContext (hwnd);
Packit Service fb6fa5
  if (!himc)
Packit Service fb6fa5
    return attrs;
Packit Service fb6fa5
Packit Service fb6fa5
  if (context_ime->preediting)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      const gchar *schr = utf8str, *echr;
Packit Service fb6fa5
      guint8 *buf;
Packit Service fb6fa5
      guint16 f_red, f_green, f_blue, b_red, b_green, b_blue;
Packit Service fb6fa5
      glong len, spos = 0, epos, sidx = 0, eidx;
Packit Service fb6fa5
      PangoAttribute *attr;
Packit Service fb6fa5
Packit Service fb6fa5
      /*
Packit Service fb6fa5
       *  get attributes list of IME.
Packit Service fb6fa5
       */
Packit Service fb6fa5
      len = ImmGetCompositionStringW (himc, GCS_COMPATTR, NULL, 0);
Packit Service fb6fa5
      buf = g_alloca (len);
Packit Service fb6fa5
      ImmGetCompositionStringW (himc, GCS_COMPATTR, buf, len);
Packit Service fb6fa5
Packit Service fb6fa5
      /*
Packit Service fb6fa5
       *  schr and echr are pointer in utf8str.
Packit Service fb6fa5
       */
Packit Service fb6fa5
      for (echr = g_utf8_next_char (utf8str); *schr != '\0';
Packit Service fb6fa5
           echr = g_utf8_next_char (echr))
Packit Service fb6fa5
        {
Packit Service fb6fa5
          /*
Packit Service fb6fa5
           *  spos and epos are buf(attributes list of IME) position by
Packit Service fb6fa5
           *  bytes.
Packit Service fb6fa5
           *  Using the wide-char API, this value is same with UTF-8 offset.
Packit Service fb6fa5
           */
Packit Service fb6fa5
	  epos = g_utf8_pointer_to_offset (utf8str, echr);
Packit Service fb6fa5
Packit Service fb6fa5
          /*
Packit Service fb6fa5
           *  sidx and eidx are positions in utf8str by bytes.
Packit Service fb6fa5
           */
Packit Service fb6fa5
          eidx = echr - utf8str;
Packit Service fb6fa5
Packit Service fb6fa5
          /*
Packit Service fb6fa5
           *  convert attributes list to PangoAttriute.
Packit Service fb6fa5
           */
Packit Service fb6fa5
          if (*echr == '\0' || buf[spos] != buf[epos])
Packit Service fb6fa5
            {
Packit Service fb6fa5
              switch (buf[spos])
Packit Service fb6fa5
                {
Packit Service fb6fa5
                case ATTR_TARGET_CONVERTED:
Packit Service fb6fa5
                  attr = pango_attr_underline_new (PANGO_UNDERLINE_DOUBLE);
Packit Service fb6fa5
                  attr->start_index = sidx;
Packit Service fb6fa5
                  attr->end_index = eidx;
Packit Service fb6fa5
                  pango_attr_list_change (attrs, attr);
Packit Service fb6fa5
                  f_red = f_green = f_blue = 0;
Packit Service fb6fa5
                  b_red = b_green = b_blue = 0xffff;
Packit Service fb6fa5
                  break;
Packit Service fb6fa5
                case ATTR_TARGET_NOTCONVERTED:
Packit Service fb6fa5
                  f_red = f_green = f_blue = 0xffff;
Packit Service fb6fa5
                  b_red = b_green = b_blue = 0;
Packit Service fb6fa5
                  break;
Packit Service fb6fa5
                case ATTR_INPUT_ERROR:
Packit Service fb6fa5
                  f_red = f_green = f_blue = 0;
Packit Service fb6fa5
                  b_red = b_green = b_blue = 0x7fff;
Packit Service fb6fa5
                  break;
Packit Service fb6fa5
                default:        /* ATTR_INPUT,ATTR_CONVERTED,ATTR_FIXEDCONVERTED */
Packit Service fb6fa5
                  attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
Packit Service fb6fa5
                  attr->start_index = sidx;
Packit Service fb6fa5
                  attr->end_index = eidx;
Packit Service fb6fa5
                  pango_attr_list_change (attrs, attr);
Packit Service fb6fa5
                  f_red = f_green = f_blue = 0;
Packit Service fb6fa5
                  b_red = b_green = b_blue = 0xffff;
Packit Service fb6fa5
                }
Packit Service fb6fa5
              attr = pango_attr_foreground_new (f_red, f_green, f_blue);
Packit Service fb6fa5
              attr->start_index = sidx;
Packit Service fb6fa5
              attr->end_index = eidx;
Packit Service fb6fa5
              pango_attr_list_change (attrs, attr);
Packit Service fb6fa5
              attr = pango_attr_background_new (b_red, b_green, b_blue);
Packit Service fb6fa5
              attr->start_index = sidx;
Packit Service fb6fa5
              attr->end_index = eidx;
Packit Service fb6fa5
              pango_attr_list_change (attrs, attr);
Packit Service fb6fa5
Packit Service fb6fa5
              schr = echr;
Packit Service fb6fa5
              spos = epos;
Packit Service fb6fa5
              sidx = eidx;
Packit Service fb6fa5
            }
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  ImmReleaseContext (hwnd, himc);
Packit Service fb6fa5
Packit Service fb6fa5
  return attrs;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_context_ime_get_preedit_string (GtkIMContext   *context,
Packit Service fb6fa5
                                       gchar         **str,
Packit Service fb6fa5
                                       PangoAttrList **attrs,
Packit Service fb6fa5
                                       gint           *cursor_pos)
Packit Service fb6fa5
{
Packit Service fb6fa5
  gchar *utf8str = NULL;
Packit Service fb6fa5
  gint pos = 0;
Packit Service fb6fa5
  GtkIMContextIME *context_ime;
Packit Service fb6fa5
Packit Service fb6fa5
  context_ime = GTK_IM_CONTEXT_IME (context);
Packit Service fb6fa5
Packit Service fb6fa5
  utf8str = get_utf8_preedit_string (context_ime, &pos;;
Packit Service fb6fa5
Packit Service fb6fa5
  if (attrs)
Packit Service fb6fa5
    *attrs = get_pango_attr_list (context_ime, utf8str);
Packit Service fb6fa5
Packit Service fb6fa5
  if (str)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      *str = utf8str;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_free (utf8str);
Packit Service fb6fa5
      utf8str = NULL;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (cursor_pos)
Packit Service fb6fa5
    *cursor_pos = pos;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_context_ime_focus_in (GtkIMContext *context)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
Packit Service fb6fa5
  GdkWindow *toplevel;
Packit Service fb6fa5
  GtkWidget *widget = NULL;
Packit Service fb6fa5
  HWND hwnd, top_hwnd;
Packit Service fb6fa5
  HIMC himc;
Packit Service fb6fa5
Packit Service fb6fa5
  if (!GDK_IS_WINDOW (context_ime->client_window))
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  /* swtich current context */
Packit Service fb6fa5
  context_ime->focus = TRUE;
Packit Service fb6fa5
Packit Service fb6fa5
  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
Packit Service fb6fa5
  himc = ImmGetContext (hwnd);
Packit Service fb6fa5
  if (!himc)
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  toplevel = gdk_window_get_toplevel (context_ime->client_window);
Packit Service fb6fa5
  if (GDK_IS_WINDOW (toplevel))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gdk_window_add_filter (toplevel,
Packit Service fb6fa5
                             gtk_im_context_ime_message_filter, context_ime);
Packit Service fb6fa5
      top_hwnd = gdk_win32_window_get_impl_hwnd (toplevel);
Packit Service fb6fa5
Packit Service fb6fa5
      context_ime->toplevel = toplevel;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_warning ("gtk_im_context_ime_focus_in(): "
Packit Service fb6fa5
                 "cannot find toplevel window.");
Packit Service fb6fa5
      return;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* trace reparenting (probably no need) */
Packit Service fb6fa5
  gdk_window_get_user_data (context_ime->client_window, (gpointer) & widget);
Packit Service fb6fa5
  if (GTK_IS_WIDGET (widget))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_signal_connect (widget, "hierarchy-changed",
Packit Service fb6fa5
                        G_CALLBACK (cb_client_widget_hierarchy_changed),
Packit Service fb6fa5
                        context_ime);
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      /* warning? */
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* restore preedit context */
Packit Service fb6fa5
  ImmSetConversionStatus (himc,
Packit Service fb6fa5
                          context_ime->priv->conversion_mode,
Packit Service fb6fa5
                          context_ime->priv->sentence_mode);
Packit Service fb6fa5
Packit Service fb6fa5
  if (context_ime->opened)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!ImmGetOpenStatus (himc))
Packit Service fb6fa5
        ImmSetOpenStatus (himc, TRUE);
Packit Service fb6fa5
      if (context_ime->preediting)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          ImmSetCompositionStringW (himc,
Packit Service fb6fa5
				    SCS_SETSTR,
Packit Service fb6fa5
				    context_ime->priv->comp_str,
Packit Service fb6fa5
				    context_ime->priv->comp_str_len, NULL, 0);
Packit Service fb6fa5
          FREE_PREEDIT_BUFFER (context_ime);
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* clean */
Packit Service fb6fa5
  ImmReleaseContext (hwnd, himc);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_context_ime_focus_out (GtkIMContext *context)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
Packit Service fb6fa5
  GdkWindow *toplevel;
Packit Service fb6fa5
  GtkWidget *widget = NULL;
Packit Service fb6fa5
  HWND hwnd, top_hwnd;
Packit Service fb6fa5
  HIMC himc;
Packit Service fb6fa5
Packit Service fb6fa5
  if (!GDK_IS_WINDOW (context_ime->client_window))
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  /* swtich current context */
Packit Service fb6fa5
  context_ime->focus = FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
Packit Service fb6fa5
  himc = ImmGetContext (hwnd);
Packit Service fb6fa5
  if (!himc)
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  /* save preedit context */
Packit Service fb6fa5
  ImmGetConversionStatus (himc,
Packit Service fb6fa5
                          &context_ime->priv->conversion_mode,
Packit Service fb6fa5
                          &context_ime->priv->sentence_mode);
Packit Service fb6fa5
Packit Service fb6fa5
  if (ImmGetOpenStatus (himc))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gboolean preediting = context_ime->preediting;
Packit Service fb6fa5
Packit Service fb6fa5
      if (preediting)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          FREE_PREEDIT_BUFFER (context_ime);
Packit Service fb6fa5
Packit Service fb6fa5
          context_ime->priv->comp_str_len
Packit Service fb6fa5
            = ImmGetCompositionStringW (himc, GCS_COMPSTR, NULL, 0);
Packit Service fb6fa5
          context_ime->priv->comp_str
Packit Service fb6fa5
            = g_malloc (context_ime->priv->comp_str_len);
Packit Service fb6fa5
          ImmGetCompositionStringW (himc, GCS_COMPSTR,
Packit Service fb6fa5
				    context_ime->priv->comp_str,
Packit Service fb6fa5
				    context_ime->priv->comp_str_len);
Packit Service fb6fa5
Packit Service fb6fa5
          context_ime->priv->read_str_len
Packit Service fb6fa5
            = ImmGetCompositionStringW (himc, GCS_COMPREADSTR, NULL, 0);
Packit Service fb6fa5
          context_ime->priv->read_str
Packit Service fb6fa5
            = g_malloc (context_ime->priv->read_str_len);
Packit Service fb6fa5
          ImmGetCompositionStringW (himc, GCS_COMPREADSTR,
Packit Service fb6fa5
				    context_ime->priv->read_str,
Packit Service fb6fa5
				    context_ime->priv->read_str_len);
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      ImmSetOpenStatus (himc, FALSE);
Packit Service fb6fa5
Packit Service fb6fa5
      context_ime->opened = TRUE;
Packit Service fb6fa5
      context_ime->preediting = preediting;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      context_ime->opened = FALSE;
Packit Service fb6fa5
      context_ime->preediting = FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* remove signal handler */
Packit Service fb6fa5
  gdk_window_get_user_data (context_ime->client_window, (gpointer) & widget);
Packit Service fb6fa5
  if (GTK_IS_WIDGET (widget))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_signal_handlers_disconnect_by_func
Packit Service fb6fa5
        (G_OBJECT (widget),
Packit Service fb6fa5
         G_CALLBACK (cb_client_widget_hierarchy_changed), context_ime);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* remove event fileter */
Packit Service fb6fa5
  toplevel = gdk_window_get_toplevel (context_ime->client_window);
Packit Service fb6fa5
  if (GDK_IS_WINDOW (toplevel))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gdk_window_remove_filter (toplevel,
Packit Service fb6fa5
                                gtk_im_context_ime_message_filter,
Packit Service fb6fa5
                                context_ime);
Packit Service fb6fa5
      top_hwnd = gdk_win32_window_get_impl_hwnd (toplevel);
Packit Service fb6fa5
Packit Service fb6fa5
      context_ime->toplevel = NULL;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_warning ("gtk_im_context_ime_focus_out(): "
Packit Service fb6fa5
                 "cannot find toplevel window.");
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* clean */
Packit Service fb6fa5
  ImmReleaseContext (hwnd, himc);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_context_ime_set_cursor_location (GtkIMContext *context,
Packit Service fb6fa5
                                        GdkRectangle *area)
Packit Service fb6fa5
{
Packit Service fb6fa5
  gint wx = 0, wy = 0;
Packit Service fb6fa5
  GtkIMContextIME *context_ime;
Packit Service fb6fa5
  COMPOSITIONFORM cf;
Packit Service fb6fa5
  HWND hwnd;
Packit Service fb6fa5
  HIMC himc;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
Packit Service fb6fa5
Packit Service fb6fa5
  context_ime = GTK_IM_CONTEXT_IME (context);
Packit Service fb6fa5
  if (area)
Packit Service fb6fa5
    context_ime->cursor_location = *area;
Packit Service fb6fa5
Packit Service fb6fa5
  if (!context_ime->client_window)
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
Packit Service fb6fa5
  himc = ImmGetContext (hwnd);
Packit Service fb6fa5
  if (!himc)
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  get_window_position (context_ime->client_window, &wx, &wy;;
Packit Service fb6fa5
  cf.dwStyle = CFS_POINT;
Packit Service fb6fa5
  cf.ptCurrentPos.x = wx + context_ime->cursor_location.x;
Packit Service fb6fa5
  cf.ptCurrentPos.y = wy + context_ime->cursor_location.y;
Packit Service fb6fa5
  ImmSetCompositionWindow (himc, &cf);
Packit Service fb6fa5
Packit Service fb6fa5
  ImmReleaseContext (hwnd, himc);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_context_ime_set_use_preedit (GtkIMContext *context,
Packit Service fb6fa5
                                    gboolean      use_preedit)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMContextIME *context_ime;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
Packit Service fb6fa5
  context_ime = GTK_IM_CONTEXT_IME (context);
Packit Service fb6fa5
Packit Service fb6fa5
  context_ime->use_preedit = use_preedit;
Packit Service fb6fa5
  if (context_ime->preediting)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      HWND hwnd;
Packit Service fb6fa5
      HIMC himc;
Packit Service fb6fa5
Packit Service fb6fa5
      hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
Packit Service fb6fa5
      himc = ImmGetContext (hwnd);
Packit Service fb6fa5
      if (!himc)
Packit Service fb6fa5
        return;
Packit Service fb6fa5
Packit Service fb6fa5
      /* FIXME: What to do? */
Packit Service fb6fa5
Packit Service fb6fa5
      ImmReleaseContext (hwnd, himc);
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_im_context_ime_set_preedit_font (GtkIMContext *context)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMContextIME *context_ime;
Packit Service fb6fa5
  GtkWidget *widget = NULL;
Packit Service fb6fa5
  HWND hwnd;
Packit Service fb6fa5
  HIMC himc;
Packit Service fb6fa5
  HKL ime = GetKeyboardLayout (0);
Packit Service fb6fa5
  const gchar *lang;
Packit Service fb6fa5
  gunichar wc;
Packit Service fb6fa5
  PangoContext *pango_context;
Packit Service fb6fa5
  PangoFont *font;
Packit Service fb6fa5
  LOGFONT *logfont;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
Packit Service fb6fa5
Packit Service fb6fa5
  context_ime = GTK_IM_CONTEXT_IME (context);
Packit Service fb6fa5
  if (!context_ime->client_window)
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  gdk_window_get_user_data (context_ime->client_window, (gpointer) &widget);
Packit Service fb6fa5
  if (!GTK_IS_WIDGET (widget))
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
Packit Service fb6fa5
  himc = ImmGetContext (hwnd);
Packit Service fb6fa5
  if (!himc)
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  /* set font */
Packit Service fb6fa5
  pango_context = gtk_widget_get_pango_context (widget);
Packit Service fb6fa5
  if (!pango_context)
Packit Service fb6fa5
    goto ERROR_OUT;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Try to make sure we use a font that actually can show the
Packit Service fb6fa5
   * language in question.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  switch (PRIMARYLANGID (LOWORD (ime)))
Packit Service fb6fa5
    {
Packit Service fb6fa5
    case LANG_JAPANESE:
Packit Service fb6fa5
      lang = "ja"; break;
Packit Service fb6fa5
    case LANG_KOREAN:
Packit Service fb6fa5
      lang = "ko"; break;
Packit Service fb6fa5
    case LANG_CHINESE:
Packit Service fb6fa5
      switch (SUBLANGID (LOWORD (ime)))
Packit Service fb6fa5
	{
Packit Service fb6fa5
	case SUBLANG_CHINESE_TRADITIONAL:
Packit Service fb6fa5
	  lang = "zh_TW"; break;
Packit Service fb6fa5
	case SUBLANG_CHINESE_SIMPLIFIED:
Packit Service fb6fa5
	  lang = "zh_CN"; break;
Packit Service fb6fa5
	case SUBLANG_CHINESE_HONGKONG:
Packit Service fb6fa5
	  lang = "zh_HK"; break;
Packit Service fb6fa5
	case SUBLANG_CHINESE_SINGAPORE:
Packit Service fb6fa5
	  lang = "zh_SG"; break;
Packit Service fb6fa5
	case SUBLANG_CHINESE_MACAU:
Packit Service fb6fa5
	  lang = "zh_MO"; break;
Packit Service fb6fa5
	default:
Packit Service fb6fa5
	  lang = "zh"; break;
Packit Service fb6fa5
	}
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    default:
Packit Service fb6fa5
      lang = ""; break;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (lang[0])
Packit Service fb6fa5
    {
Packit Service fb6fa5
      /* We know what language it is. Look for a character, any
Packit Service fb6fa5
       * character, that language needs.
Packit Service fb6fa5
       */
Packit Service fb6fa5
      PangoLanguage *pango_lang = pango_language_from_string (lang);
Packit Service fb6fa5
      PangoFontset *fontset =
Packit Service fb6fa5
	pango_context_load_fontset (pango_context,
Packit Service fb6fa5
				    widget->style->font_desc,
Packit Service fb6fa5
				    pango_lang);
Packit Service fb6fa5
      gunichar *sample =
Packit Service fb6fa5
	g_utf8_to_ucs4 (pango_language_get_sample_string (pango_lang),
Packit Service fb6fa5
			-1, NULL, NULL, NULL);
Packit Service fb6fa5
      wc = 0x4E00;		/* In all CJK languages? */
Packit Service fb6fa5
      if (sample != NULL)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  int i;
Packit Service fb6fa5
Packit Service fb6fa5
	  for (i = 0; sample[i]; i++)
Packit Service fb6fa5
	    if (g_unichar_iswide (sample[i]))
Packit Service fb6fa5
	      {
Packit Service fb6fa5
		wc = sample[i];
Packit Service fb6fa5
		break;
Packit Service fb6fa5
	      }
Packit Service fb6fa5
	  g_free (sample);
Packit Service fb6fa5
	}
Packit Service fb6fa5
      font = pango_fontset_get_font (fontset, wc);
Packit Service fb6fa5
      g_object_unref (fontset);
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    font = pango_context_load_font (pango_context, widget->style->font_desc);
Packit Service fb6fa5
Packit Service fb6fa5
  if (!font)
Packit Service fb6fa5
    goto ERROR_OUT;
Packit Service fb6fa5
Packit Service fb6fa5
  logfont = pango_win32_font_logfont (font);
Packit Service fb6fa5
  if (logfont)
Packit Service fb6fa5
    ImmSetCompositionFont (himc, logfont);
Packit Service fb6fa5
Packit Service fb6fa5
  g_object_unref (font);
Packit Service fb6fa5
Packit Service fb6fa5
ERROR_OUT:
Packit Service fb6fa5
  /* clean */
Packit Service fb6fa5
  ImmReleaseContext (hwnd, himc);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static GdkFilterReturn
Packit Service fb6fa5
gtk_im_context_ime_message_filter (GdkXEvent *xevent,
Packit Service fb6fa5
                                   GdkEvent  *event,
Packit Service fb6fa5
                                   gpointer   data)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkIMContext *context;
Packit Service fb6fa5
  GtkIMContextIME *context_ime;
Packit Service fb6fa5
  HWND hwnd;
Packit Service fb6fa5
  HIMC himc;
Packit Service fb6fa5
  MSG *msg = (MSG *) xevent;
Packit Service fb6fa5
  GdkFilterReturn retval = GDK_FILTER_CONTINUE;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (data), retval);
Packit Service fb6fa5
Packit Service fb6fa5
  context = GTK_IM_CONTEXT (data);
Packit Service fb6fa5
  context_ime = GTK_IM_CONTEXT_IME (data);
Packit Service fb6fa5
  if (!context_ime->focus)
Packit Service fb6fa5
    return retval;
Packit Service fb6fa5
Packit Service fb6fa5
  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
Packit Service fb6fa5
  himc = ImmGetContext (hwnd);
Packit Service fb6fa5
  if (!himc)
Packit Service fb6fa5
    return retval;
Packit Service fb6fa5
Packit Service fb6fa5
  switch (msg->message)
Packit Service fb6fa5
    {
Packit Service fb6fa5
    case WM_IME_COMPOSITION:
Packit Service fb6fa5
      {
Packit Service fb6fa5
        gint wx = 0, wy = 0;
Packit Service fb6fa5
        CANDIDATEFORM cf;
Packit Service fb6fa5
Packit Service fb6fa5
        get_window_position (context_ime->client_window, &wx, &wy;;
Packit Service fb6fa5
        /* FIXME! */
Packit Service fb6fa5
        {
Packit Service fb6fa5
          HWND hwnd_top;
Packit Service fb6fa5
          POINT pt;
Packit Service fb6fa5
          RECT rc;
Packit Service fb6fa5
Packit Service fb6fa5
          hwnd_top =
Packit Service fb6fa5
            gdk_win32_window_get_impl_hwnd (gdk_window_get_toplevel
Packit Service fb6fa5
                                            (context_ime->client_window));
Packit Service fb6fa5
          GetWindowRect (hwnd_top, &rc);
Packit Service fb6fa5
          pt.x = wx;
Packit Service fb6fa5
          pt.y = wy;
Packit Service fb6fa5
          ClientToScreen (hwnd_top, &pt;;
Packit Service fb6fa5
          wx = pt.x - rc.left;
Packit Service fb6fa5
          wy = pt.y - rc.top;
Packit Service fb6fa5
        }
Packit Service fb6fa5
        cf.dwIndex = 0;
Packit Service fb6fa5
        cf.dwStyle = CFS_CANDIDATEPOS;
Packit Service fb6fa5
        cf.ptCurrentPos.x = wx + context_ime->cursor_location.x;
Packit Service fb6fa5
        cf.ptCurrentPos.y = wy + context_ime->cursor_location.y
Packit Service fb6fa5
          + context_ime->cursor_location.height;
Packit Service fb6fa5
        ImmSetCandidateWindow (himc, &cf);
Packit Service fb6fa5
Packit Service fb6fa5
        if ((msg->lParam & GCS_COMPSTR))
Packit Service fb6fa5
          g_signal_emit_by_name (context, "preedit-changed");
Packit Service fb6fa5
Packit Service fb6fa5
        if (msg->lParam & GCS_RESULTSTR)
Packit Service fb6fa5
          {
Packit Service fb6fa5
            gsize len;
Packit Service fb6fa5
            gchar *utf8str = NULL;
Packit Service fb6fa5
            GError *error = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
	    len = ImmGetCompositionStringW (himc, GCS_RESULTSTR, NULL, 0);
Packit Service fb6fa5
Packit Service fb6fa5
            if (len > 0)
Packit Service fb6fa5
              {
Packit Service fb6fa5
		gpointer buf = g_alloca (len);
Packit Service fb6fa5
		ImmGetCompositionStringW (himc, GCS_RESULTSTR, buf, len);
Packit Service fb6fa5
		len /= 2;
Packit Service fb6fa5
		utf8str = g_utf16_to_utf8 (buf, len, NULL, NULL, &error);
Packit Service fb6fa5
                if (error)
Packit Service fb6fa5
                  {
Packit Service fb6fa5
                    g_warning ("%s", error->message);
Packit Service fb6fa5
                    g_error_free (error);
Packit Service fb6fa5
                  }
Packit Service fb6fa5
              }
Packit Service fb6fa5
Packit Service fb6fa5
            if (utf8str)
Packit Service fb6fa5
              {
Packit Service fb6fa5
                g_signal_emit_by_name (context, "commit", utf8str);
Packit Service fb6fa5
                g_free (utf8str);
Packit Service fb6fa5
		retval = TRUE;
Packit Service fb6fa5
              }
Packit Service fb6fa5
          }
Packit Service fb6fa5
Packit Service fb6fa5
        if (context_ime->use_preedit)
Packit Service fb6fa5
          retval = TRUE;
Packit Service fb6fa5
        break;
Packit Service fb6fa5
      }
Packit Service fb6fa5
Packit Service fb6fa5
    case WM_IME_STARTCOMPOSITION:
Packit Service fb6fa5
      context_ime->preediting = TRUE;
Packit Service fb6fa5
      gtk_im_context_ime_set_cursor_location (context, NULL);
Packit Service fb6fa5
      g_signal_emit_by_name (context, "preedit-start");
Packit Service fb6fa5
      if (context_ime->use_preedit)
Packit Service fb6fa5
        retval = TRUE;
Packit Service fb6fa5
      break;
Packit Service fb6fa5
Packit Service fb6fa5
    case WM_IME_ENDCOMPOSITION:
Packit Service fb6fa5
      context_ime->preediting = FALSE;
Packit Service fb6fa5
      g_signal_emit_by_name (context, "preedit-changed");
Packit Service fb6fa5
      g_signal_emit_by_name (context, "preedit-end");
Packit Service fb6fa5
      if (context_ime->use_preedit)
Packit Service fb6fa5
        retval = TRUE;
Packit Service fb6fa5
      break;
Packit Service fb6fa5
Packit Service fb6fa5
    case WM_IME_NOTIFY:
Packit Service fb6fa5
      switch (msg->wParam)
Packit Service fb6fa5
        {
Packit Service fb6fa5
        case IMN_SETOPENSTATUS:
Packit Service fb6fa5
          context_ime->opened = ImmGetOpenStatus (himc);
Packit Service fb6fa5
          gtk_im_context_ime_set_preedit_font (context);
Packit Service fb6fa5
          break;
Packit Service fb6fa5
Packit Service fb6fa5
        default:
Packit Service fb6fa5
          break;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
    default:
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  ImmReleaseContext (hwnd, himc);
Packit Service fb6fa5
  return retval;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * x and y must be initialized to 0.
Packit Service fb6fa5
 */
Packit Service fb6fa5
static void
Packit Service fb6fa5
get_window_position (GdkWindow *win, gint *x, gint *y)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GdkWindow *parent, *toplevel;
Packit Service fb6fa5
  gint wx, wy;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (GDK_IS_WINDOW (win));
Packit Service fb6fa5
  g_return_if_fail (x && y);
Packit Service fb6fa5
Packit Service fb6fa5
  gdk_window_get_position (win, &wx, &wy;;
Packit Service fb6fa5
  *x += wx;
Packit Service fb6fa5
  *y += wy;
Packit Service fb6fa5
  parent = gdk_window_get_parent (win);
Packit Service fb6fa5
  toplevel = gdk_window_get_toplevel (win);
Packit Service fb6fa5
Packit Service fb6fa5
  if (parent && parent != toplevel)
Packit Service fb6fa5
    get_window_position (parent, x, y);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 *  probably, this handler isn't needed.
Packit Service fb6fa5
 */
Packit Service fb6fa5
static void
Packit Service fb6fa5
cb_client_widget_hierarchy_changed (GtkWidget       *widget,
Packit Service fb6fa5
                                    GtkWidget       *widget2,
Packit Service fb6fa5
                                    GtkIMContextIME *context_ime)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GdkWindow *new_toplevel;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (GTK_IS_WIDGET (widget));
Packit Service fb6fa5
  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime));
Packit Service fb6fa5
Packit Service fb6fa5
  if (!context_ime->client_window)
Packit Service fb6fa5
    return;
Packit Service fb6fa5
  if (!context_ime->focus)
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  new_toplevel = gdk_window_get_toplevel (context_ime->client_window);
Packit Service fb6fa5
  if (context_ime->toplevel == new_toplevel)
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  /* remove filter from old toplevel */
Packit Service fb6fa5
  if (GDK_IS_WINDOW (context_ime->toplevel))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gdk_window_remove_filter (context_ime->toplevel,
Packit Service fb6fa5
                                gtk_im_context_ime_message_filter,
Packit Service fb6fa5
                                context_ime);
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* add filter to new toplevel */
Packit Service fb6fa5
  if (GDK_IS_WINDOW (new_toplevel))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gdk_window_add_filter (new_toplevel,
Packit Service fb6fa5
                             gtk_im_context_ime_message_filter, context_ime);
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  context_ime->toplevel = new_toplevel;
Packit Service fb6fa5
}