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.
24 * Please see the following site for the detail of Windows IME API.
25 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/appendix/hh/appendix/imeimes2_35ph.asp
28 #include "gtkimcontextime.h"
30 #include "imm-extra.h"
32 #include "gdk/win32/gdkwin32.h"
33 #include "gdk/gdkkeysyms.h"
35 #include <pango/pango.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 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;
272 g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
273 context_ime = GTK_IM_CONTEXT_IME (context);
280 hwnd = GDK_WINDOW_HWND (client_window);
281 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;
305 gboolean retval = FALSE;
308 g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (context), FALSE);
309 g_return_val_if_fail (event, FALSE);
311 if (event->type == GDK_KEY_RELEASE)
314 if (event->state & GDK_CONTROL_MASK)
317 context_ime = GTK_IM_CONTEXT_IME (context);
319 if (!context_ime->focus)
322 if (!GDK_IS_WINDOW (context_ime->client_window))
325 c = gdk_keyval_to_unicode (event->keyval);
329 int len = g_unichar_to_utf8 (c, utf8);
332 g_signal_emit_by_name (context_ime, "commit", utf8);
341 gtk_im_context_ime_reset (GtkIMContext *context)
343 GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
347 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
348 himc = ImmGetContext (hwnd);
352 if (context_ime->preediting && ImmGetOpenStatus (himc))
353 ImmNotifyIME (himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
355 context_ime->preediting = FALSE;
356 g_signal_emit_by_name (context, "preedit-changed");
358 ImmReleaseContext (hwnd, himc);
363 get_utf8_preedit_string (GtkIMContextIME *context_ime, gint *pos_ret)
365 gchar *utf8str = NULL;
373 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
374 himc = ImmGetContext (hwnd);
376 return g_strdup ("");
378 if (context_ime->preediting)
382 len = ImmGetCompositionStringW (himc, GCS_COMPSTR, NULL, 0);
385 GError *error = NULL;
386 gpointer buf = g_alloca (len);
388 ImmGetCompositionStringW (himc, GCS_COMPSTR, buf, len);
390 utf8str = g_utf16_to_utf8 (buf, len, NULL, NULL, &error);
393 g_warning ("%s", error->message);
394 g_error_free (error);
399 pos = ImmGetCompositionStringW (himc, GCS_CURSORPOS, NULL, 0);
400 if (pos < 0 || len < pos)
402 g_warning ("ImmGetCompositionString: "
403 "Invalid cursor position!");
412 utf8str = g_strdup ("");
419 ImmReleaseContext (hwnd, himc);
425 static PangoAttrList *
426 get_pango_attr_list (GtkIMContextIME *context_ime, const gchar *utf8str)
428 PangoAttrList *attrs = pango_attr_list_new ();
432 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
433 himc = ImmGetContext (hwnd);
437 if (context_ime->preediting)
439 const gchar *schr = utf8str, *echr;
441 guint16 f_red, f_green, f_blue, b_red, b_green, b_blue;
442 glong len, spos = 0, epos, sidx = 0, eidx;
443 PangoAttribute *attr;
446 * get attributes list of IME.
448 len = ImmGetCompositionStringW (himc, GCS_COMPATTR, NULL, 0);
449 buf = g_alloca (len);
450 ImmGetCompositionStringW (himc, GCS_COMPATTR, buf, len);
453 * schr and echr are pointer in utf8str.
455 for (echr = g_utf8_next_char (utf8str); *schr != '\0';
456 echr = g_utf8_next_char (echr))
459 * spos and epos are buf(attributes list of IME) position by
461 * Using the wide-char API, this value is same with UTF-8 offset.
463 epos = g_utf8_pointer_to_offset (utf8str, echr);
466 * sidx and eidx are positions in utf8str by bytes.
468 eidx = echr - utf8str;
471 * convert attributes list to PangoAttriute.
473 if (*echr == '\0' || buf[spos] != buf[epos])
477 case ATTR_TARGET_CONVERTED:
478 attr = pango_attr_underline_new (PANGO_UNDERLINE_DOUBLE);
479 attr->start_index = sidx;
480 attr->end_index = eidx;
481 pango_attr_list_change (attrs, attr);
482 f_red = f_green = f_blue = 0;
483 b_red = b_green = b_blue = 0xffff;
485 case ATTR_TARGET_NOTCONVERTED:
486 f_red = f_green = f_blue = 0xffff;
487 b_red = b_green = b_blue = 0;
489 case ATTR_INPUT_ERROR:
490 f_red = f_green = f_blue = 0;
491 b_red = b_green = b_blue = 0x7fff;
493 default: /* ATTR_INPUT,ATTR_CONVERTED,ATTR_FIXEDCONVERTED */
494 attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
495 attr->start_index = sidx;
496 attr->end_index = eidx;
497 pango_attr_list_change (attrs, attr);
498 f_red = f_green = f_blue = 0;
499 b_red = b_green = b_blue = 0xffff;
501 attr = pango_attr_foreground_new (f_red, f_green, f_blue);
502 attr->start_index = sidx;
503 attr->end_index = eidx;
504 pango_attr_list_change (attrs, attr);
505 attr = pango_attr_background_new (b_red, b_green, b_blue);
506 attr->start_index = sidx;
507 attr->end_index = eidx;
508 pango_attr_list_change (attrs, attr);
517 ImmReleaseContext (hwnd, himc);
524 gtk_im_context_ime_get_preedit_string (GtkIMContext *context,
526 PangoAttrList **attrs,
529 gchar *utf8str = NULL;
531 GtkIMContextIME *context_ime;
533 context_ime = GTK_IM_CONTEXT_IME (context);
535 utf8str = get_utf8_preedit_string (context_ime, &pos);
538 *attrs = get_pango_attr_list (context_ime, utf8str);
556 gtk_im_context_ime_focus_in (GtkIMContext *context)
558 GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
560 GtkWidget *widget = NULL;
564 if (!GDK_IS_WINDOW (context_ime->client_window))
567 /* swtich current context */
568 context_ime->focus = TRUE;
570 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
571 himc = ImmGetContext (hwnd);
575 toplevel = gdk_window_get_toplevel (context_ime->client_window);
576 if (GDK_IS_WINDOW (toplevel))
578 gdk_window_add_filter (toplevel,
579 gtk_im_context_ime_message_filter, context_ime);
580 top_hwnd = GDK_WINDOW_HWND (toplevel);
582 context_ime->toplevel = toplevel;
586 g_warning ("gtk_im_context_ime_focus_in(): "
587 "cannot find toplevel window.");
591 /* trace reparenting (probably no need) */
592 gdk_window_get_user_data (context_ime->client_window, (gpointer) & widget);
593 if (GTK_IS_WIDGET (widget))
595 g_signal_connect (widget, "hierarchy-changed",
596 G_CALLBACK (cb_client_widget_hierarchy_changed),
604 /* restore preedit context */
605 ImmSetConversionStatus (himc,
606 context_ime->priv->conversion_mode,
607 context_ime->priv->sentence_mode);
609 if (context_ime->opened)
611 if (!ImmGetOpenStatus (himc))
612 ImmSetOpenStatus (himc, TRUE);
613 if (context_ime->preediting)
615 ImmSetCompositionStringW (himc,
617 context_ime->priv->comp_str,
618 context_ime->priv->comp_str_len, NULL, 0);
619 FREE_PREEDIT_BUFFER (context_ime);
624 ImmReleaseContext (hwnd, himc);
629 gtk_im_context_ime_focus_out (GtkIMContext *context)
631 GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
633 GtkWidget *widget = NULL;
637 if (!GDK_IS_WINDOW (context_ime->client_window))
640 /* swtich current context */
641 context_ime->focus = FALSE;
643 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
644 himc = ImmGetContext (hwnd);
648 /* save preedit context */
649 ImmGetConversionStatus (himc,
650 &context_ime->priv->conversion_mode,
651 &context_ime->priv->sentence_mode);
653 if (ImmGetOpenStatus (himc))
655 gboolean preediting = context_ime->preediting;
659 FREE_PREEDIT_BUFFER (context_ime);
661 context_ime->priv->comp_str_len
662 = ImmGetCompositionStringW (himc, GCS_COMPSTR, NULL, 0);
663 context_ime->priv->comp_str
664 = g_malloc (context_ime->priv->comp_str_len);
665 ImmGetCompositionStringW (himc, GCS_COMPSTR,
666 context_ime->priv->comp_str,
667 context_ime->priv->comp_str_len);
669 context_ime->priv->read_str_len
670 = ImmGetCompositionStringW (himc, GCS_COMPREADSTR, NULL, 0);
671 context_ime->priv->read_str
672 = g_malloc (context_ime->priv->read_str_len);
673 ImmGetCompositionStringW (himc, GCS_COMPREADSTR,
674 context_ime->priv->read_str,
675 context_ime->priv->read_str_len);
678 ImmSetOpenStatus (himc, FALSE);
680 context_ime->opened = TRUE;
681 context_ime->preediting = preediting;
685 context_ime->opened = FALSE;
686 context_ime->preediting = FALSE;
689 /* remove signal handler */
690 gdk_window_get_user_data (context_ime->client_window, (gpointer) & widget);
691 if (GTK_IS_WIDGET (widget))
693 g_signal_handlers_disconnect_by_func
695 G_CALLBACK (cb_client_widget_hierarchy_changed), context_ime);
698 /* remove event fileter */
699 toplevel = gdk_window_get_toplevel (context_ime->client_window);
700 if (GDK_IS_WINDOW (toplevel))
702 gdk_window_remove_filter (toplevel,
703 gtk_im_context_ime_message_filter,
705 top_hwnd = GDK_WINDOW_HWND (toplevel);
707 context_ime->toplevel = NULL;
711 g_warning ("gtk_im_context_ime_focus_out(): "
712 "cannot find toplevel window.");
716 ImmReleaseContext (hwnd, himc);
721 gtk_im_context_ime_set_cursor_location (GtkIMContext *context,
725 GtkIMContextIME *context_ime;
730 g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
732 context_ime = GTK_IM_CONTEXT_IME (context);
734 context_ime->cursor_location = *area;
736 if (!context_ime->client_window)
739 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
740 himc = ImmGetContext (hwnd);
744 get_window_position (context_ime->client_window, &wx, &wy);
745 cf.dwStyle = CFS_POINT;
746 cf.ptCurrentPos.x = wx + context_ime->cursor_location.x;
747 cf.ptCurrentPos.y = wy + context_ime->cursor_location.y;
748 ImmSetCompositionWindow (himc, &cf);
750 ImmReleaseContext (hwnd, himc);
755 gtk_im_context_ime_set_use_preedit (GtkIMContext *context,
756 gboolean use_preedit)
758 GtkIMContextIME *context_ime;
760 g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
761 context_ime = GTK_IM_CONTEXT_IME (context);
763 context_ime->use_preedit = use_preedit;
764 if (context_ime->preediting)
769 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
770 himc = ImmGetContext (hwnd);
774 /* FIXME: What to do? */
776 ImmReleaseContext (hwnd, himc);
782 gtk_im_context_ime_set_preedit_font (GtkIMContext *context)
784 GtkIMContextIME *context_ime;
785 GtkWidget *widget = NULL;
788 HKL ime = GetKeyboardLayout (0);
791 PangoContext *pango_context;
795 g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
797 context_ime = GTK_IM_CONTEXT_IME (context);
798 if (!context_ime->client_window)
801 gdk_window_get_user_data (context_ime->client_window, (gpointer) &widget);
802 if (!GTK_IS_WIDGET (widget))
805 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
806 himc = ImmGetContext (hwnd);
811 pango_context = gtk_widget_get_pango_context (widget);
815 /* Try to make sure we use a font that actually can show the
816 * language in question.
819 switch (PRIMARYLANGID (LOWORD (ime)))
826 switch (SUBLANGID (LOWORD (ime)))
828 case SUBLANG_CHINESE_TRADITIONAL:
829 lang = "zh_TW"; break;
830 case SUBLANG_CHINESE_SIMPLIFIED:
831 lang = "zh_CN"; break;
832 case SUBLANG_CHINESE_HONGKONG:
833 lang = "zh_HK"; break;
834 case SUBLANG_CHINESE_SINGAPORE:
835 lang = "zh_SG"; break;
836 case SUBLANG_CHINESE_MACAU:
837 lang = "zh_MO"; break;
848 /* We know what language it is. Look for a character, any
849 * character, that language needs.
851 PangoLanguage *pango_lang = pango_language_from_string (lang);
852 PangoFontset *fontset =
853 pango_context_load_fontset (pango_context,
854 widget->style->font_desc,
857 g_utf8_to_ucs4 (pango_language_get_sample_string (pango_lang),
858 -1, NULL, NULL, NULL);
859 wc = 0x4E00; /* In all CJK languages? */
864 for (i = 0; sample[i]; i++)
865 if (g_unichar_iswide (sample[i]))
872 font = pango_fontset_get_font (fontset, wc);
873 g_object_unref (fontset);
876 font = pango_context_load_font (pango_context, widget->style->font_desc);
881 logfont = pango_win32_font_logfont (font);
883 ImmSetCompositionFont (himc, logfont);
885 g_object_unref (font);
889 ImmReleaseContext (hwnd, himc);
893 static GdkFilterReturn
894 gtk_im_context_ime_message_filter (GdkXEvent *xevent,
898 GtkIMContext *context;
899 GtkIMContextIME *context_ime;
902 MSG *msg = (MSG *) xevent;
903 GdkFilterReturn retval = GDK_FILTER_CONTINUE;
905 g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (data), retval);
907 context = GTK_IM_CONTEXT (data);
908 context_ime = GTK_IM_CONTEXT_IME (data);
909 if (!context_ime->focus)
912 hwnd = GDK_WINDOW_HWND (context_ime->client_window);
913 himc = ImmGetContext (hwnd);
917 switch (msg->message)
919 case WM_IME_COMPOSITION:
924 get_window_position (context_ime->client_window, &wx, &wy);
932 GDK_WINDOW_HWND (gdk_window_get_toplevel
933 (context_ime->client_window));
934 GetWindowRect (hwnd_top, &rc);
937 ClientToScreen (hwnd_top, &pt);
942 cf.dwStyle = CFS_CANDIDATEPOS;
943 cf.ptCurrentPos.x = wx + context_ime->cursor_location.x;
944 cf.ptCurrentPos.y = wy + context_ime->cursor_location.y
945 + context_ime->cursor_location.height;
946 ImmSetCandidateWindow (himc, &cf);
948 if ((msg->lParam & GCS_COMPSTR))
949 g_signal_emit_by_name (context, "preedit-changed");
951 if (msg->lParam & GCS_RESULTSTR)
954 gchar *utf8str = NULL;
955 GError *error = NULL;
957 len = ImmGetCompositionStringW (himc, GCS_RESULTSTR, NULL, 0);
961 gpointer buf = g_alloca (len);
962 ImmGetCompositionStringW (himc, GCS_RESULTSTR, buf, len);
964 utf8str = g_utf16_to_utf8 (buf, len, NULL, NULL, &error);
967 g_warning ("%s", error->message);
968 g_error_free (error);
974 g_signal_emit_by_name (context, "commit", utf8str);
980 if (context_ime->use_preedit)
985 case WM_IME_STARTCOMPOSITION:
986 context_ime->preediting = TRUE;
987 gtk_im_context_ime_set_cursor_location (context, NULL);
988 g_signal_emit_by_name (context, "preedit-start");
989 if (context_ime->use_preedit)
993 case WM_IME_ENDCOMPOSITION:
994 context_ime->preediting = FALSE;
995 g_signal_emit_by_name (context, "preedit-changed");
996 g_signal_emit_by_name (context, "preedit-end");
997 if (context_ime->use_preedit)
1002 switch (msg->wParam)
1004 case IMN_SETOPENSTATUS:
1005 context_ime->opened = ImmGetOpenStatus (himc);
1006 gtk_im_context_ime_set_preedit_font (context);
1017 ImmReleaseContext (hwnd, himc);
1023 * x and y must be initialized to 0.
1026 get_window_position (GdkWindow *win, gint *x, gint *y)
1028 GdkWindow *parent, *toplevel;
1031 g_return_if_fail (GDK_IS_WINDOW (win));
1032 g_return_if_fail (x && y);
1034 gdk_window_get_position (win, &wx, &wy);
1037 parent = gdk_window_get_parent (win);
1038 toplevel = gdk_window_get_toplevel (win);
1040 if (parent && parent != toplevel)
1041 get_window_position (parent, x, y);
1046 * probably, this handler isn't needed.
1049 cb_client_widget_hierarchy_changed (GtkWidget *widget,
1051 GtkIMContextIME *context_ime)
1053 GdkWindow *new_toplevel;
1055 g_return_if_fail (GTK_IS_WIDGET (widget));
1056 g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime));
1058 if (!context_ime->client_window)
1060 if (!context_ime->focus)
1063 new_toplevel = gdk_window_get_toplevel (context_ime->client_window);
1064 if (context_ime->toplevel == new_toplevel)
1067 /* remove filter from old toplevel */
1068 if (GDK_IS_WINDOW (context_ime->toplevel))
1070 gdk_window_remove_filter (context_ime->toplevel,
1071 gtk_im_context_ime_message_filter,
1078 /* add filter to new toplevel */
1079 if (GDK_IS_WINDOW (new_toplevel))
1081 gdk_window_add_filter (new_toplevel,
1082 gtk_im_context_ime_message_filter, context_ime);
1088 context_ime->toplevel = new_toplevel;