Blame modules/input/gtkimcontextime.c

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