3 * Copyright (C) 2003 Takuro Ashie
4 * Copyright (C) 2003-2004 Kazuki IWAMOTO
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
25 * Please see the following site for the detail of Windows IME API.
26 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/appendix/hh/appendix/imeimes2_35ph.asp
29 #include "gtkimcontextime.h"
31 #include "imm-extra.h"
33 #include "gdk/win32/gdkwin32.h"
34 #include "gdk/gdkkeysyms.h"
35 #include "gtk/gtkwidget.h"
40 # include <pango/pangowin32.h>
45 # include <pango/pangowin32.h>
48 /* #define BUFSIZE 4096 */
50 #define FREE_PREEDIT_BUFFER(ctx) \
52 g_free((ctx)->priv->comp_str); \
53 g_free((ctx)->priv->read_str); \
54 (ctx)->priv->comp_str = NULL; \
55 (ctx)->priv->read_str = NULL; \
56 (ctx)->priv->comp_str_len = 0; \
57 (ctx)->priv->read_str_len = 0; \
61 struct _GtkIMContextIMEPrivate
63 /* save IME context when the client window is focused out */
64 DWORD conversion_mode;
74 /* GObject class methods */
75 static void gtk_im_context_ime_class_init (GtkIMContextIMEClass *class);
76 static void gtk_im_context_ime_init (GtkIMContextIME *context_ime);
77 static void gtk_im_context_ime_dispose (GObject *obj);
78 static void gtk_im_context_ime_finalize (GObject *obj);
80 static void gtk_im_context_ime_set_property (GObject *object,
84 static void gtk_im_context_ime_get_property (GObject *object,
89 /* GtkIMContext's virtual functions */
90 static void gtk_im_context_ime_set_client_window (GtkIMContext *context,
91 GdkWindow *client_window);
92 static gboolean gtk_im_context_ime_filter_keypress (GtkIMContext *context,
94 static void gtk_im_context_ime_reset (GtkIMContext *context);
95 static void gtk_im_context_ime_get_preedit_string (GtkIMContext *context,
97 PangoAttrList **attrs,
99 static void gtk_im_context_ime_focus_in (GtkIMContext *context);
100 static void gtk_im_context_ime_focus_out (GtkIMContext *context);
101 static void gtk_im_context_ime_set_cursor_location (GtkIMContext *context,
103 static void gtk_im_context_ime_set_use_preedit (GtkIMContext *context,
104 gboolean use_preedit);
106 /* GtkIMContextIME's private functions */
107 static void gtk_im_context_ime_set_preedit_font (GtkIMContext *context,
109 static GdkFilterReturn
110 gtk_im_context_ime_message_filter (GdkXEvent *xevent,
113 static void get_window_position (GdkWindow *win,
116 static void cb_client_widget_hierarchy_changed (GtkWidget *widget,
118 GtkIMContextIME *context_ime);
120 GType gtk_type_im_context_ime = 0;
121 static GObjectClass *parent_class;
125 gtk_im_context_ime_register_type (GTypeModule *type_module)
127 static const GTypeInfo im_context_ime_info = {
128 sizeof (GtkIMContextIMEClass),
129 (GBaseInitFunc) NULL,
130 (GBaseFinalizeFunc) NULL,
131 (GClassInitFunc) gtk_im_context_ime_class_init,
132 NULL, /* class_finalize */
133 NULL, /* class_data */
134 sizeof (GtkIMContextIME),
136 (GInstanceInitFunc) gtk_im_context_ime_init,
139 gtk_type_im_context_ime =
140 g_type_module_register_type (type_module,
142 "GtkIMContextIME", &im_context_ime_info, 0);
146 gtk_im_context_ime_class_init (GtkIMContextIMEClass *class)
148 GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class);
149 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
151 parent_class = g_type_class_peek_parent (class);
153 gobject_class->finalize = gtk_im_context_ime_finalize;
154 gobject_class->dispose = gtk_im_context_ime_dispose;
155 gobject_class->set_property = gtk_im_context_ime_set_property;
156 gobject_class->get_property = gtk_im_context_ime_get_property;
158 im_context_class->set_client_window = gtk_im_context_ime_set_client_window;
159 im_context_class->filter_keypress = gtk_im_context_ime_filter_keypress;
160 im_context_class->reset = gtk_im_context_ime_reset;
161 im_context_class->get_preedit_string = gtk_im_context_ime_get_preedit_string;
162 im_context_class->focus_in = gtk_im_context_ime_focus_in;
163 im_context_class->focus_out = gtk_im_context_ime_focus_out;
164 im_context_class->set_cursor_location = gtk_im_context_ime_set_cursor_location;
165 im_context_class->set_use_preedit = gtk_im_context_ime_set_use_preedit;
170 gtk_im_context_ime_init (GtkIMContextIME *context_ime)
172 context_ime->client_window = NULL;
173 context_ime->toplevel = NULL;
174 context_ime->use_preedit = TRUE;
175 context_ime->preediting = FALSE;
176 context_ime->opened = FALSE;
177 context_ime->focus = FALSE;
178 context_ime->cursor_location.x = 0;
179 context_ime->cursor_location.y = 0;
180 context_ime->cursor_location.width = 0;
181 context_ime->cursor_location.height = 0;
183 context_ime->priv = g_malloc0 (sizeof (GtkIMContextIMEPrivate));
184 context_ime->priv->conversion_mode = 0;
185 context_ime->priv->sentence_mode = 0;
186 context_ime->priv->comp_str = NULL;
187 context_ime->priv->comp_str_len = 0;
188 context_ime->priv->read_str = NULL;
189 context_ime->priv->read_str_len = 0;
194 gtk_im_context_ime_dispose (GObject *obj)
196 GtkIMContext *context = GTK_IM_CONTEXT (obj);
197 GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (obj);
199 if (context_ime->client_window)
200 gtk_im_context_ime_set_client_window (context, NULL);
202 FREE_PREEDIT_BUFFER (context_ime);
204 if (G_OBJECT_CLASS (parent_class)->dispose)
205 G_OBJECT_CLASS (parent_class)->dispose (obj);
210 gtk_im_context_ime_finalize (GObject *obj)
212 /* GtkIMContext *context = GTK_IM_CONTEXT (obj); */
213 GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (obj);
215 g_free (context_ime->priv);
216 context_ime->priv = NULL;
218 if (G_OBJECT_CLASS (parent_class)->finalize)
219 G_OBJECT_CLASS (parent_class)->finalize (obj);
224 gtk_im_context_ime_set_property (GObject *object,
229 GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (object);
231 g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime));
242 gtk_im_context_ime_get_property (GObject *object,
247 GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (object);
249 g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime));
260 gtk_im_context_ime_new (void)
262 return g_object_new (GTK_TYPE_IM_CONTEXT_IME, NULL);
267 gtk_im_context_ime_set_client_window (GtkIMContext *context,
268 GdkWindow *client_window)
270 GtkIMContextIME *context_ime;
273 g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
274 context_ime = GTK_IM_CONTEXT_IME (context);
280 hwnd = GDK_WINDOW_HWND (client_window);
282 /* get default ime context */
283 himc = ImmGetContext (hwnd);
284 context_ime->opened = ImmGetOpenStatus (himc);
285 ImmGetConversionStatus (himc,
286 &context_ime->priv->conversion_mode,
287 &context_ime->priv->sentence_mode);
288 ImmReleaseContext (hwnd, himc);
291 else if (context_ime->focus)
293 gtk_im_context_ime_focus_out (context);
296 context_ime->client_window = client_window;
301 gtk_im_context_ime_filter_keypress (GtkIMContext *context,
304 GtkIMContextIME *context_ime;
307 gboolean retval = FALSE;
309 g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (context), FALSE);
310 g_return_val_if_fail (event, FALSE);
312 if (event->type == GDK_KEY_RELEASE)
315 context_ime = GTK_IM_CONTEXT_IME (context);
316 if (!context_ime->focus)
318 if (!GDK_IS_WINDOW (context_ime->client_window))
321 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
322 himc = ImmGetContext (hwnd);
324 /* FIXME!! event->string is deprecated */
325 if (event->string && *event->string
326 && !g_unichar_iscntrl (g_utf8_get_char_validated (event->string,
327 strlen (event->string))))
329 g_signal_emit_by_name (G_OBJECT (context_ime), "commit", event->string);
333 ImmReleaseContext (hwnd, himc);
340 gtk_im_context_ime_reset (GtkIMContext *context)
342 GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
346 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
347 himc = ImmGetContext (hwnd);
351 if (context_ime->preediting && ImmGetOpenStatus (himc))
352 ImmNotifyIME (himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
354 context_ime->preediting = FALSE;
355 g_signal_emit_by_name (context, "preedit_changed");
357 ImmReleaseContext (hwnd, himc);
362 get_utf8_preedit_string (GtkIMContextIME *context_ime, gint *pos_ret)
364 gchar *utf8str = NULL;
373 g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime),
377 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
378 himc = ImmGetContext (hwnd);
380 /* shouldn't return NULL */
381 g_return_val_if_fail (himc, g_strdup (""));
383 if (context_ime->preediting)
387 GError *error = NULL;
390 len = ImmGetCompositionString (himc, GCS_COMPSTR, NULL, 0);
391 buf = g_malloc (len);
394 ImmGetCompositionString (himc, GCS_COMPSTR, buf, len);
395 len /= sizeof (gunichar2);
396 utf8str = g_utf16_to_utf8 (buf, len, NULL, NULL, &error);
399 g_warning ("%s", error->message);
400 g_error_free (error);
405 pos = ImmGetCompositionString (himc, GCS_CURSORPOS, NULL, 0);
406 if (pos < 0 || len < pos)
408 g_warning ("ImmGetCompositionString: "
409 "Invalid cursor position!");
415 #else /* not UNICODE */
416 len = ImmGetCompositionString (himc, GCS_COMPSTR, NULL, 0);
417 buf = g_malloc (len);
420 ImmGetCompositionString (himc, GCS_COMPSTR, buf, len);
421 utf8str = g_locale_to_utf8 (buf, len, NULL, NULL, &error);
424 g_warning ("%s", error->message);
425 g_error_free (error);
430 pos = ImmGetCompositionString (himc, GCS_CURSORPOS, NULL, 0);
431 /* get cursor position by offset */
432 if (pos < len && utf8str)
436 tmpstr = g_locale_to_utf8 (buf, pos, NULL, NULL, &error);
439 g_warning ("%s", error->message);
440 g_error_free (error);
444 pos = g_utf8_strlen (tmpstr, -1);
452 else if (pos == len && utf8str)
454 pos = g_utf8_strlen (utf8str, -1);
458 g_warning ("ImmGetCompositionString: "
459 "Invalid cursor position!");
465 #endif /* not UNICODE */
470 utf8str = g_strdup ("");
477 ImmReleaseContext (hwnd, himc);
483 static PangoAttrList *
484 get_pango_attr_list (GtkIMContextIME *context_ime, const gchar *utf8str)
486 PangoAttrList *attrs = pango_attr_list_new ();
490 /* g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime), attr); */
492 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
493 himc = ImmGetContext (hwnd);
495 g_return_val_if_fail (himc, attrs);
497 if (context_ime->preediting)
499 const gchar *schr = utf8str, *echr;
501 guint16 f_red, f_green, f_blue, b_red, b_green, b_blue;
502 glong len, spos = 0, epos, sidx = 0, eidx;
503 PangoAttribute *attr;
506 * get attributes list of IME.
508 len = ImmGetCompositionString (himc, GCS_COMPATTR, NULL, 0);
509 buf = g_malloc (len);
510 ImmGetCompositionString (himc, GCS_COMPATTR, buf, len);
513 * schr and echr are pointer in utf8str.
515 for (echr = g_utf8_next_char (utf8str); *schr != '\0';
516 echr = g_utf8_next_char (echr))
519 * spos and epos are buf(attributes list of IME) position by
521 * If UNICODE is defined, this value is same with UTF-8 offset.
522 * If it's not defined, this value is same with bytes position
523 * of locale encoded preedit string.
527 epos = g_utf8_pointer_to_offset (utf8str, echr);
528 #else /* not UNICODE */
530 GError *error = NULL;
533 tmpstr = g_locale_from_utf8 (schr, echr - schr, NULL, NULL, &error);
536 g_warning ("%s", error->message);
537 g_error_free (error);
541 epos += strlen (tmpstr);
544 #endif /* not UNICODE */
546 * sidx and eidx are positions in utf8str by bytes.
548 eidx = echr - utf8str;
551 * convert attributes list to PangoAttriute.
553 if (*echr == '\0' || buf[spos] != buf[epos])
557 case ATTR_TARGET_CONVERTED:
558 attr = pango_attr_underline_new (PANGO_UNDERLINE_DOUBLE);
559 attr->start_index = sidx;
560 attr->end_index = eidx;
561 pango_attr_list_change (attrs, attr);
562 f_red = f_green = f_blue = 0;
563 b_red = b_green = b_blue = 0xffff;
565 case ATTR_TARGET_NOTCONVERTED:
566 f_red = f_green = f_blue = 0xffff;
567 b_red = b_green = b_blue = 0;
569 case ATTR_INPUT_ERROR:
570 f_red = f_green = f_blue = 0;
571 b_red = b_green = b_blue = 0x7fff;
573 default: /* ATTR_INPUT,ATTR_CONVERTED,ATTR_FIXEDCONVERTED */
574 attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
575 attr->start_index = sidx;
576 attr->end_index = eidx;
577 pango_attr_list_change (attrs, attr);
578 f_red = f_green = f_blue = 0;
579 b_red = b_green = b_blue = 0xffff;
581 attr = pango_attr_foreground_new (f_red, f_green, f_blue);
582 attr->start_index = sidx;
583 attr->end_index = eidx;
584 pango_attr_list_change (attrs, attr);
585 attr = pango_attr_background_new (b_red, b_green, b_blue);
586 attr->start_index = sidx;
587 attr->end_index = eidx;
588 pango_attr_list_change (attrs, attr);
598 ImmReleaseContext (hwnd, himc);
605 gtk_im_context_ime_get_preedit_string (GtkIMContext *context,
607 PangoAttrList **attrs,
610 gchar *utf8str = NULL;
612 GtkIMContextIME *context_ime;
614 context_ime = GTK_IM_CONTEXT_IME (context);
616 utf8str = get_utf8_preedit_string (context_ime, &pos);
619 *attrs = get_pango_attr_list (context_ime, utf8str);
637 gtk_im_context_ime_focus_in (GtkIMContext *context)
639 GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
641 GtkWidget *widget = NULL;
645 if (!GDK_IS_WINDOW (context_ime->client_window))
648 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
649 himc = ImmGetContext (hwnd);
653 toplevel = gdk_window_get_toplevel (context_ime->client_window);
654 if (GDK_IS_WINDOW (toplevel))
656 gdk_window_add_filter (toplevel,
657 gtk_im_context_ime_message_filter, context_ime);
658 top_hwnd = GDK_WINDOW_HWND (toplevel);
660 context_ime->toplevel = toplevel;
664 g_warning ("gtk_im_context_ime_focus_in(): "
665 "cannot find toplevel window.");
669 /* trace reparenting (probably no need) */
670 gdk_window_get_user_data (context_ime->client_window, (gpointer) & widget);
671 if (GTK_IS_WIDGET (widget))
673 g_signal_connect (G_OBJECT (widget), "hierarchy-changed",
674 G_CALLBACK (cb_client_widget_hierarchy_changed),
682 /* swtich current context */
683 context_ime->focus = TRUE;
685 /* restore preedit context */
686 ImmSetConversionStatus (himc,
687 context_ime->priv->conversion_mode,
688 context_ime->priv->sentence_mode);
690 if (context_ime->opened)
692 if (!ImmGetOpenStatus (himc))
693 ImmSetOpenStatus (himc, TRUE);
694 if (context_ime->preediting)
696 ImmSetCompositionString (himc,
698 context_ime->priv->comp_str,
699 context_ime->priv->comp_str_len, NULL, 0);
700 FREE_PREEDIT_BUFFER (context_ime);
705 ImmReleaseContext (hwnd, himc);
710 gtk_im_context_ime_focus_out (GtkIMContext *context)
712 GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
714 GtkWidget *widget = NULL;
718 if (!GDK_IS_WINDOW (context_ime->client_window))
721 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
722 himc = ImmGetContext (hwnd);
726 /* save preedit context */
727 ImmGetConversionStatus (himc,
728 &context_ime->priv->conversion_mode,
729 &context_ime->priv->sentence_mode);
731 if (ImmGetOpenStatus (himc))
733 gboolean preediting = context_ime->preediting;
737 FREE_PREEDIT_BUFFER (context_ime);
739 context_ime->priv->comp_str_len
740 = ImmGetCompositionString (himc, GCS_COMPSTR, NULL, 0);
741 context_ime->priv->comp_str
742 = g_malloc (context_ime->priv->comp_str_len);
743 ImmGetCompositionString (himc, GCS_COMPSTR,
744 context_ime->priv->comp_str,
745 context_ime->priv->comp_str_len);
747 context_ime->priv->read_str_len
748 = ImmGetCompositionString (himc, GCS_COMPREADSTR, NULL, 0);
749 context_ime->priv->read_str
750 = g_malloc (context_ime->priv->read_str_len);
751 ImmGetCompositionString (himc, GCS_COMPREADSTR,
752 context_ime->priv->read_str,
753 context_ime->priv->read_str_len);
756 ImmSetOpenStatus (himc, FALSE);
758 context_ime->opened = TRUE;
759 context_ime->preediting = preediting;
763 context_ime->opened = FALSE;
764 context_ime->preediting = FALSE;
767 /* remove signal handler */
768 gdk_window_get_user_data (context_ime->client_window, (gpointer) & widget);
769 if (GTK_IS_WIDGET (widget))
771 g_signal_handlers_disconnect_by_func
773 G_CALLBACK (cb_client_widget_hierarchy_changed), context_ime);
776 /* remove event fileter */
777 toplevel = gdk_window_get_toplevel (context_ime->client_window);
778 if (GDK_IS_WINDOW (toplevel))
780 gdk_window_remove_filter (toplevel,
781 gtk_im_context_ime_message_filter,
783 top_hwnd = GDK_WINDOW_HWND (toplevel);
785 context_ime->toplevel = NULL;
789 g_warning ("gtk_im_context_ime_focus_out(): "
790 "cannot find toplevel window.");
793 /* swtich current context */
794 context_ime->focus = FALSE;
797 ImmReleaseContext (hwnd, himc);
802 gtk_im_context_ime_set_cursor_location (GtkIMContext *context,
806 GtkIMContextIME *context_ime;
811 g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
813 context_ime = GTK_IM_CONTEXT_IME (context);
815 context_ime->cursor_location = *area;
817 if (!context_ime->client_window)
820 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
821 himc = ImmGetContext (hwnd);
825 get_window_position (context_ime->client_window, &wx, &wy);
826 cf.dwStyle = CFS_POINT;
827 cf.ptCurrentPos.x = wx + context_ime->cursor_location.x;
828 cf.ptCurrentPos.y = wy + context_ime->cursor_location.y;
829 ImmSetCompositionWindow (himc, &cf);
831 ImmReleaseContext (hwnd, himc);
836 gtk_im_context_ime_set_use_preedit (GtkIMContext *context,
837 gboolean use_preedit)
839 GtkIMContextIME *context_ime;
841 g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
842 context_ime = GTK_IM_CONTEXT_IME (context);
844 context_ime->use_preedit = use_preedit;
845 if (context_ime->preediting)
851 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
852 himc = ImmGetContext (hwnd);
860 gtk_im_context_ime_set_preedit_font (GtkIMContext *context, PangoFont *font)
862 GtkIMContextIME *context_ime;
863 GtkWidget *widget = NULL;
866 PangoContext *pango_context;
869 g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
871 context_ime = GTK_IM_CONTEXT_IME (context);
872 if (!context_ime->client_window)
875 gdk_window_get_user_data (context_ime->client_window, (gpointer) &widget);
876 if (!GTK_IS_WIDGET (widget))
879 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
880 himc = ImmGetContext (hwnd);
885 pango_context = gtk_widget_get_pango_context (widget);
890 font = pango_context_load_font (pango_context, widget->style->font_desc);
894 logfont = pango_win32_font_logfont (font);
896 ImmSetCompositionFont (himc, logfont);
900 ImmReleaseContext (hwnd, himc);
904 static GdkFilterReturn
905 gtk_im_context_ime_message_filter (GdkXEvent *xevent,
909 GtkIMContext *context;
910 GtkIMContextIME *context_ime;
913 MSG *msg = (MSG *) xevent;
914 GdkFilterReturn retval = GDK_FILTER_CONTINUE;
916 g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (data), retval);
918 context = GTK_IM_CONTEXT (data);
919 context_ime = GTK_IM_CONTEXT_IME (data);
920 if (!context_ime->focus)
923 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
924 himc = ImmGetContext (hwnd);
928 switch (msg->message)
930 case WM_IME_COMPOSITION:
935 get_window_position (context_ime->client_window, &wx, &wy);
943 GDK_WINDOW_HWND (gdk_window_get_toplevel
944 (context_ime->client_window));
945 GetWindowRect (hwnd_top, &rc);
948 ClientToScreen (hwnd_top, &pt);
953 cf.dwStyle = CFS_CANDIDATEPOS;
954 cf.ptCurrentPos.x = wx + context_ime->cursor_location.x;
955 cf.ptCurrentPos.y = wy + context_ime->cursor_location.y
956 + context_ime->cursor_location.height;
957 ImmSetCandidateWindow (himc, &cf);
959 if ((msg->lParam & GCS_COMPSTR))
960 g_signal_emit_by_name (context, "preedit_changed");
962 if (msg->lParam & GCS_RESULTSTR)
966 gchar *utf8str = NULL;
967 GError *error = NULL;
969 len = ImmGetCompositionString (himc, GCS_RESULTSTR, NULL, 0);
970 buf = g_alloca (len);
973 ImmGetCompositionString (himc, GCS_RESULTSTR, buf, len);
975 len /= sizeof (gunichar2);
976 utf8str = g_utf16_to_utf8 (buf, len, NULL, NULL, &error);
977 #else /* not UNICODE */
978 utf8str = g_locale_to_utf8 (buf, len, NULL, NULL, &error);
979 #endif /* not UNICODE */
982 g_warning ("%s", error->message);
983 g_error_free (error);
989 g_signal_emit_by_name (G_OBJECT (context), "commit", utf8str);
994 if (context_ime->use_preedit)
999 case WM_IME_STARTCOMPOSITION:
1000 context_ime->preediting = TRUE;
1001 gtk_im_context_ime_set_cursor_location (context, NULL);
1002 g_signal_emit_by_name (context, "preedit_start");
1003 if (context_ime->use_preedit)
1007 case WM_IME_ENDCOMPOSITION:
1008 context_ime->preediting = FALSE;
1009 g_signal_emit_by_name (context, "preedit_changed");
1010 g_signal_emit_by_name (context, "preedit_end");
1011 if (context_ime->use_preedit)
1016 switch (msg->wParam)
1018 case IMN_SETOPENSTATUS:
1019 context_ime->opened = ImmGetOpenStatus (himc);
1020 gtk_im_context_ime_set_preedit_font (context, NULL);
1031 ImmReleaseContext (hwnd, himc);
1037 * x and y must be initialized to 0.
1040 get_window_position (GdkWindow *win, gint *x, gint *y)
1042 GdkWindow *parent, *toplevel;
1045 g_return_if_fail (GDK_IS_WINDOW (win));
1046 g_return_if_fail (x && y);
1048 gdk_window_get_position (win, &wx, &wy);
1051 parent = gdk_window_get_parent (win);
1052 toplevel = gdk_window_get_toplevel (win);
1054 if (parent && parent != toplevel)
1055 get_window_position (parent, x, y);
1060 * probably, this handler isn't needed.
1063 cb_client_widget_hierarchy_changed (GtkWidget *widget,
1065 GtkIMContextIME *context_ime)
1067 GdkWindow *new_toplevel;
1069 g_return_if_fail (GTK_IS_WIDGET (widget));
1070 g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime));
1072 if (!context_ime->client_window)
1074 if (!context_ime->focus)
1077 new_toplevel = gdk_window_get_toplevel (context_ime->client_window);
1078 if (context_ime->toplevel == new_toplevel)
1081 /* remove filter from old toplevel */
1082 if (GDK_IS_WINDOW (context_ime->toplevel))
1084 gdk_window_remove_filter (context_ime->toplevel,
1085 gtk_im_context_ime_message_filter,
1092 /* add filter to new toplevel */
1093 if (GDK_IS_WINDOW (new_toplevel))
1095 gdk_window_add_filter (new_toplevel,
1096 gtk_im_context_ime_message_filter, context_ime);
1102 context_ime->toplevel = new_toplevel;