diff -r 580391c2f925 runtime/doc/options.txt
--- a/runtime/doc/options.txt	Thu Jul 19 18:05:44 2012 +0200
+++ b/runtime/doc/options.txt	Fri Jul 20 19:26:03 2012 +0900
@@ -3971,6 +3971,25 @@
 	Can be overruled by using "\c" or "\C" in the pattern, see
 	|/ignorecase|.
 
+						*'imactivatefunc'* *'imaf'*
+'imactivatefunc' 'imaf'	string (default "")
+			global
+			{not in Vi}
+			{only available when compiled with |+xim| and
+			|+GUI_GTK|}
+	This option specifies a function to be used to activate/inactivate
+	Input Method.
+
+	Prototype is: >
+		:function ImActivateFunc(active)
+		:  if a:active
+		:    ... do something
+		:  else
+		:    ... do something
+		:  endif
+		:  " return value is not used
+		:endfunction
+<
 						*'imactivatekey'* *'imak'*
 'imactivatekey' 'imak'	string (default "")
 			global
@@ -4003,6 +4022,23 @@
 <	"S-space" means shift+space.  This is the activation key for kinput2 +
 	canna (Japanese), and ami (Korean).
 
+						*'imstatusfunc'* *'imsf'*
+'imstatusfunc' 'imsf'	string (default "")
+			global
+			{not in Vi}
+			{only available when compiled with |+xim| and
+			|+GUI_GTK|}
+	This option specifies a function to be used to get status of Input
+	Method.
+
+	Prototype is: >
+		:function ImStatusFunc()
+		:  let is_active = ...do something
+		:  return is_active ? 1 : 0
+		:endfunction
+<
+	NOTE: This function is invoked too often.  Keep it fast.
+
 				*'imcmdline'* *'imc'* *'noimcmdline'* *'noimc'*
 'imcmdline' 'imc'	boolean (default off)
 			global
diff -r 580391c2f925 src/eval.c
--- a/src/eval.c	Thu Jul 19 18:05:44 2012 +0200
+++ b/src/eval.c	Fri Jul 20 19:26:03 2012 +0900
@@ -1655,7 +1655,7 @@
 }
 # endif
 
-# if defined(FEAT_COMPL_FUNC) || defined(PROTO)
+# if defined(FEAT_GTK) || defined(FEAT_COMPL_FUNC) || defined(PROTO)
 /*
  * Call vimL function "func" and return the result as a number.
  * Returns -1 when calling the function fails.
diff -r 580391c2f925 src/mbyte.c
--- a/src/mbyte.c	Thu Jul 19 18:05:44 2012 +0200
+++ b/src/mbyte.c	Fri Jul 20 19:26:03 2012 +0900
@@ -4390,7 +4390,7 @@
 {
     int was_active;
 
-    was_active = !!im_is_active;
+    was_active = !!im_get_status();
     im_is_active = (active && !p_imdisable);
 
     if (im_is_active != was_active)
@@ -5014,52 +5014,20 @@
 {
     if (xic != NULL)
     {
-	/*
-	 * The third-party imhangul module (and maybe others too) ignores
-	 * gtk_im_context_reset() or at least doesn't reset the active state.
-	 * Thus sending imactivatekey would turn it off if it was on before,
-	 * which is clearly not what we want.  Fortunately we can work around
-	 * that for imhangul by sending GDK_Escape, but I don't know if it
-	 * works with all IM modules that support an activation key :/
-	 *
-	 * An alternative approach would be to destroy the IM context and
-	 * recreate it.  But that means loading/unloading the IM module on
-	 * every mode switch, which causes a quite noticeable delay even on
-	 * my rather fast box...
-	 * *
-	 * Moreover, there are some XIM which cannot respond to
-	 * im_synthesize_keypress(). we hope that they reset by
-	 * xim_shutdown().
-	 */
-	if (im_activatekey_keyval != GDK_VoidSymbol && im_is_active)
-	    im_synthesize_keypress(GDK_Escape, 0U);
-
 	gtk_im_context_reset(xic);
 
-	/*
-	 * HACK for Ami: This sequence of function calls makes Ami handle
-	 * the IM reset graciously, without breaking loads of other stuff.
-	 * It seems to force English mode as well, which is exactly what we
-	 * want because it makes the Ami status display work reliably.
-	 */
-	gtk_im_context_set_use_preedit(xic, FALSE);
-
 	if (p_imdisable)
 	    im_shutdown();
 	else
 	{
-	    gtk_im_context_set_use_preedit(xic, TRUE);
-	    xim_set_focus(gui.in_focus);
-
-	    if (im_activatekey_keyval != GDK_VoidSymbol)
+	    if (p_imaf[0] != NUL)
 	    {
+		char_u *argv[1];
 		if (im_is_active)
-		{
-		    g_signal_handler_block(xic, im_commit_handler_id);
-		    im_synthesize_keypress(im_activatekey_keyval,
-						    im_activatekey_state);
-		    g_signal_handler_unblock(xic, im_commit_handler_id);
-		}
+		    argv[0] = "1";
+		else
+		    argv[0] = "0";
+		(void)call_func_retnr(p_imaf, 1, argv, FALSE);
 	    }
 	    else
 	    {
@@ -5211,6 +5179,15 @@
     int
 im_get_status(void)
 {
+    if (p_imsf[0] != NUL)
+    {
+	/* FIXME: If !gui.in_focus, it may cause user function to get IM
+	 * status of other process. */
+	int is_active = call_func_retnr(p_imsf, 0, NULL, FALSE);
+	if (is_active == -1 || is_active == 0)
+	    return FALSE;
+	return TRUE;
+    }
     return im_is_active;
 }
 
diff -r 580391c2f925 src/option.c
--- a/src/option.c	Thu Jul 19 18:05:44 2012 +0200
+++ b/src/option.c	Fri Jul 20 19:26:03 2012 +0900
@@ -1416,6 +1416,15 @@
     {"ignorecase",  "ic",   P_BOOL|P_VI_DEF,
 			    (char_u *)&p_ic, PV_NONE,
 			    {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
+    {"imactivatefunc","imaf",P_STRING|P_VI_DEF|P_SECURE,
+# if defined(FEAT_EVAL) && defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+			    (char_u *)&p_imaf, PV_NONE,
+			    {(char_u *)"", (char_u *)NULL}
+# else
+			    (char_u *)NULL, PV_NONE,
+			    {(char_u *)NULL, (char_u *)0L}
+# endif
+			    SCRIPTID_INIT},
     {"imactivatekey","imak",P_STRING|P_VI_DEF,
 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
 			    (char_u *)&p_imak, PV_NONE,
@@ -1423,6 +1432,15 @@
 			    (char_u *)NULL, PV_NONE,
 #endif
 			    {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
+    {"imstatusfunc","imse",P_STRING|P_VI_DEF|P_SECURE,
+# if defined(FEAT_EVAL) && defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+			    (char_u *)&p_imsf, PV_NONE,
+			    {(char_u *)"", (char_u *)NULL}
+# else
+			    (char_u *)NULL, PV_NONE,
+			    {(char_u *)NULL, (char_u *)0L}
+# endif
+			    SCRIPTID_INIT},
     {"imcmdline",   "imc",  P_BOOL|P_VI_DEF,
 #ifdef USE_IM_CONTROL
 			    (char_u *)&p_imcmdline, PV_NONE,
diff -r 580391c2f925 src/option.h
--- a/src/option.h	Thu Jul 19 18:05:44 2012 +0200
+++ b/src/option.h	Fri Jul 20 19:26:03 2012 +0900
@@ -557,6 +557,8 @@
 EXTERN int	p_ic;		/* 'ignorecase' */
 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
 EXTERN char_u	*p_imak;	/* 'imactivatekey' */
+EXTERN char_u	*p_imaf;	/* 'imactivatefunc' */
+EXTERN char_u	*p_imsf;	/* 'imstatusfunc' */
 #endif
 #ifdef USE_IM_CONTROL
 EXTERN int	p_imcmdline;	/* 'imcmdline' */
