Patch 8.2.0872
Problem:    XIM code is mixed with multi-byte code.
Solution:   Move the XIM code to a separate file. (Yegappan Lakshmanan,
            closes #6177)
Files:      Filelist, src/Make_cyg_ming.mak, src/Make_morph.mak,
            src/Make_mvc.mak, src/Make_vms.mms, src/Makefile, src/gui_xim.c,
            src/mbyte.c, src/proto.h, src/proto/gui_xim.pro,
            src/proto/mbyte.pro


*** ../vim-8.2.0871/Filelist    2020-05-31 14:24:39.592878605 +0200
--- Filelist    2020-06-01 14:18:57.754948914 +0200
***************
*** 419,424 ****
--- 419,425 ----
                src/gui_gtk_x11.c \
                src/gui_gtk_res.xml \
                src/gui_motif.c \
+               src/gui_xim.c \
                src/gui_xmdlg.c \
                src/gui_xmebw.c \
                src/gui_xmebw.h \
***************
*** 442,447 ****
--- 443,449 ----
                src/proto/gui_gtk_x11.pro \
                src/proto/gui_gtk_gresources.pro \
                src/proto/gui_motif.pro \
+               src/proto/gui_xim.pro \
                src/proto/gui_xmdlg.pro \
                src/proto/gui_x11.pro \
                src/proto/if_xcmdsrv.pro \
*** ../vim-8.2.0871/src/Make_cyg_ming.mak       2020-05-30 17:05:57.028692410 
+0200
--- src/Make_cyg_ming.mak       2020-06-01 14:18:57.754948914 +0200
***************
*** 741,746 ****
--- 741,747 ----
        $(OUTDIR)/findfile.o \
        $(OUTDIR)/fold.o \
        $(OUTDIR)/getchar.o \
+       $(OUTDIR)/gui_xim.o \
        $(OUTDIR)/hardcopy.o \
        $(OUTDIR)/hashtab.o \
        $(OUTDIR)/highlight.o \
*** ../vim-8.2.0871/src/Make_morph.mak  2020-05-30 17:05:57.028692410 +0200
--- src/Make_morph.mak  2020-06-01 14:18:57.754948914 +0200
***************
*** 61,66 ****
--- 61,67 ----
        findfile.c                                              \
        fold.c                                                  \
        getchar.c                                               \
+       gui_xim.c                                               \
        hardcopy.c                                              \
        hashtab.c                                               \
        highlight.c                                             \
*** ../vim-8.2.0871/src/Make_mvc.mak    2020-05-30 17:05:57.028692410 +0200
--- src/Make_mvc.mak    2020-06-01 14:18:57.754948914 +0200
***************
*** 761,766 ****
--- 761,767 ----
        $(OUTDIR)\findfile.obj \
        $(OUTDIR)\fold.obj \
        $(OUTDIR)\getchar.obj \
+       $(OUTDIR)\gui_xim.obj \
        $(OUTDIR)\hardcopy.obj \
        $(OUTDIR)\hashtab.obj \
        $(OUTDIR)\highlight.obj \
***************
*** 1591,1596 ****
--- 1592,1599 ----
  
  $(OUTDIR)/getchar.obj:        $(OUTDIR) getchar.c  $(INCL)
  
+ $(OUTDIR)/gui_xim.obj:        $(OUTDIR) gui_xim.c  $(INCL)
+ 
  $(OUTDIR)/hardcopy.obj:       $(OUTDIR) hardcopy.c  $(INCL) version.h
  
  $(OUTDIR)/hashtab.obj:        $(OUTDIR) hashtab.c  $(INCL)
***************
*** 1908,1913 ****
--- 1911,1917 ----
        proto/filepath.pro \
        proto/findfile.pro \
        proto/getchar.pro \
+       proto/gui_xim.pro \
        proto/hardcopy.pro \
        proto/hashtab.pro \
        proto/highlight.pro \
*** ../vim-8.2.0871/src/Make_vms.mms    2020-05-30 17:05:57.028692410 +0200
--- src/Make_vms.mms    2020-06-01 14:18:57.754948914 +0200
***************
*** 334,339 ****
--- 334,340 ----
        findfile.c \
        fold.c \
        getchar.c \
+       gui_xim.c \
        hardcopy.c \
        hashtab.c \
        highlight.c \
***************
*** 445,450 ****
--- 446,452 ----
        findfile.obj \
        fold.obj \
        getchar.obj \
+       gui_xim.obj \
        hardcopy.obj \
        hashtab.obj \
        highlight.obj \
***************
*** 818,823 ****
--- 820,829 ----
   ascii.h keymap.h term.h macros.h structs.h regexp.h \
   gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
   globals.h
+ gui_xim.obj : gui_xim.c vim.h [.auto]config.h feature.h os_unix.h \
+  ascii.h keymap.h term.h macros.h structs.h regexp.h \
+  gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+  globals.h
  hardcopy.obj : hardcopy.c vim.h [.auto]config.h feature.h os_unix.h \
   ascii.h keymap.h term.h macros.h structs.h regexp.h \
   gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
*** ../vim-8.2.0871/src/Makefile        2020-05-31 14:24:39.596878596 +0200
--- src/Makefile        2020-06-01 14:25:05.405585410 +0200
***************
*** 1636,1641 ****
--- 1636,1642 ----
        findfile.c \
        fold.c \
        getchar.c \
+       gui_xim.c \
        hardcopy.c \
        hashtab.c \
        highlight.c \
***************
*** 1785,1790 ****
--- 1786,1792 ----
        objects/findfile.o \
        objects/fold.o \
        objects/getchar.o \
+       objects/gui_xim.o \
        objects/hardcopy.o \
        objects/hashtab.o \
        objects/highlight.o \
***************
*** 1950,1955 ****
--- 1952,1958 ----
        findfile.pro \
        fold.pro \
        getchar.pro \
+       gui_xim.pro \
        gui_beval.pro \
        hardcopy.pro \
        hashtab.pro \
***************
*** 3301,3306 ****
--- 3304,3312 ----
  objects/gui_x11.o: gui_x11.c
        $(CCC) -o $@ gui_x11.c
  
+ objects/gui_xim.o: gui_xim.c
+       $(CCC) -o $@ gui_xim.c
+ 
  objects/gui_photon.o: gui_photon.c
        $(CCC) -o $@ gui_photon.c
  
***************
*** 4238,4243 ****
--- 4244,4254 ----
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
   proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
   proto.h globals.h ../runtime/vim32x32.xpm ../runtime/vim16x16.xpm \
+  ../runtime/vim48x48.xpm
+ objects/gui_xim.o: gui_xim.c vim.h protodef.h auto/config.h feature.h 
os_unix.h \
+  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+  proto.h globals.h ../runtime/vim32x32.xpm ../runtime/vim16x16.xpm \
   ../runtime/vim48x48.xpm
  objects/gui_at_sb.o: gui_at_sb.c vim.h protodef.h auto/config.h feature.h \
   os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
*** ../vim-8.2.0871/src/gui_xim.c       2020-06-01 14:33:33.391649376 +0200
--- src/gui_xim.c       2020-06-01 14:21:59.518280765 +0200
***************
*** 0 ****
--- 1,1777 ----
+ /* vi:set ts=8 sts=4 sw=4 noet:
+  *
+  * VIM - Vi IMproved  by Bram Moolenaar
+  *
+  * Do ":help uganda"  in Vim to read copying and usage conditions.
+  * Do ":help credits" in Vim to see a list of people who contributed.
+  * See README.txt for an overview of the Vim source code.
+  */
+ 
+ /*
+  * gui_xim.c: functions for the X Input Method
+  */
+ 
+ #include "vim.h"
+ 
+ #if defined(FEAT_GUI_GTK) && defined(FEAT_XIM)
+ # if GTK_CHECK_VERSION(3,0,0)
+ #  include <gdk/gdkkeysyms-compat.h>
+ # else
+ #  include <gdk/gdkkeysyms.h>
+ # endif
+ # ifdef MSWIN
+ #  include <gdk/gdkwin32.h>
+ # else
+ #  include <gdk/gdkx.h>
+ # endif
+ #endif
+ 
+ /*
+  * XIM often causes trouble.  Define XIM_DEBUG to get a log of XIM callbacks
+  * in the "xim.log" file.
+  */
+ // #define XIM_DEBUG
+ #ifdef XIM_DEBUG
+     static void
+ xim_log(char *s, ...)
+ {
+     va_list arglist;
+     static FILE *fd = NULL;
+ 
+     if (fd == (FILE *)-1)
+       return;
+     if (fd == NULL)
+     {
+       fd = mch_fopen("xim.log", "w");
+       if (fd == NULL)
+       {
+           emsg("Cannot open xim.log");
+           fd = (FILE *)-1;
+           return;
+       }
+     }
+ 
+     va_start(arglist, s);
+     vfprintf(fd, s, arglist);
+     va_end(arglist);
+ }
+ #endif
+ 
+ #ifdef FEAT_GUI
+ # define USE_IMACTIVATEFUNC (!gui.in_use && *p_imaf != NUL)
+ # define USE_IMSTATUSFUNC (!gui.in_use && *p_imsf != NUL)
+ #else
+ # define USE_IMACTIVATEFUNC (*p_imaf != NUL)
+ # define USE_IMSTATUSFUNC (*p_imsf != NUL)
+ #endif
+ 
+ #if defined(FEAT_EVAL) && \
+     (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL))
+     static void
+ call_imactivatefunc(int active)
+ {
+     typval_T argv[2];
+ 
+     argv[0].v_type = VAR_NUMBER;
+     argv[0].vval.v_number = active ? 1 : 0;
+     argv[1].v_type = VAR_UNKNOWN;
+     (void)call_func_retnr(p_imaf, 1, argv);
+ }
+ 
+     static int
+ call_imstatusfunc(void)
+ {
+     int is_active;
+ 
+     // FIXME: Don't execute user function in unsafe situation.
+     if (exiting || is_autocmd_blocked())
+       return FALSE;
+     // FIXME: :py print 'xxx' is shown duplicate result.
+     // Use silent to avoid it.
+     ++msg_silent;
+     is_active = call_func_retnr(p_imsf, 0, NULL);
+     --msg_silent;
+     return (is_active > 0);
+ }
+ #endif
+ 
+ #if defined(FEAT_XIM) || defined(PROTO)
+ 
+ # if defined(FEAT_GUI_GTK) || defined(PROTO)
+ static int xim_has_preediting INIT(= FALSE);  // IM current status
+ 
+ /*
+  * Set preedit_start_col to the current cursor position.
+  */
+     static void
+ init_preedit_start_col(void)
+ {
+     if (State & CMDLINE)
+       preedit_start_col = cmdline_getvcol_cursor();
+     else if (curwin != NULL && curwin->w_buffer != NULL)
+       getvcol(curwin, &curwin->w_cursor, &preedit_start_col, NULL, NULL);
+     // Prevent that preediting marks the buffer as changed.
+     xim_changed_while_preediting = curbuf->b_changed;
+ }
+ 
+ static int im_is_active              = FALSE; // IM is enabled for current 
mode
+ static int preedit_is_active   = FALSE;
+ static int im_preedit_cursor   = 0;   // cursor offset in characters
+ static int im_preedit_trailing = 0;   // number of characters after cursor
+ 
+ static unsigned long im_commit_handler_id  = 0;
+ static unsigned int  im_activatekey_keyval = GDK_VoidSymbol;
+ static unsigned int  im_activatekey_state  = 0;
+ 
+ static GtkWidget *preedit_window = NULL;
+ static GtkWidget *preedit_label = NULL;
+ 
+ static void im_preedit_window_set_position(void);
+ 
+     void
+ im_set_active(int active)
+ {
+     int was_active;
+ 
+     was_active = !!im_get_status();
+     im_is_active = (active && !p_imdisable);
+ 
+     if (im_is_active != was_active)
+       xim_reset();
+ }
+ 
+     void
+ xim_set_focus(int focus)
+ {
+     if (xic != NULL)
+     {
+       if (focus)
+           gtk_im_context_focus_in(xic);
+       else
+           gtk_im_context_focus_out(xic);
+     }
+ }
+ 
+     void
+ im_set_position(int row, int col)
+ {
+     if (xic != NULL)
+     {
+       GdkRectangle area;
+ 
+       area.x = FILL_X(col);
+       area.y = FILL_Y(row);
+       area.width  = gui.char_width * (mb_lefthalve(row, col) ? 2 : 1);
+       area.height = gui.char_height;
+ 
+       gtk_im_context_set_cursor_location(xic, &area);
+ 
+       if (p_imst == IM_OVER_THE_SPOT)
+           im_preedit_window_set_position();
+     }
+ }
+ 
+ #  if 0 || defined(PROTO) // apparently only used in gui_x11.c
+     void
+ xim_set_preedit(void)
+ {
+     im_set_position(gui.row, gui.col);
+ }
+ #  endif
+ 
+     static void
+ im_add_to_input(char_u *str, int len)
+ {
+     // Convert from 'termencoding' (always "utf-8") to 'encoding'
+     if (input_conv.vc_type != CONV_NONE)
+     {
+       str = string_convert(&input_conv, str, &len);
+       g_return_if_fail(str != NULL);
+     }
+ 
+     add_to_input_buf_csi(str, len);
+ 
+     if (input_conv.vc_type != CONV_NONE)
+       vim_free(str);
+ 
+     if (p_mh) // blank out the pointer if necessary
+       gui_mch_mousehide(TRUE);
+ }
+ 
+      static void
+ im_preedit_window_set_position(void)
+ {
+     int x, y, width, height;
+     int screen_x, screen_y, screen_width, screen_height;
+ 
+     if (preedit_window == NULL)
+       return;
+ 
+     gui_gtk_get_screen_geom_of_win(gui.drawarea,
+                         &screen_x, &screen_y, &screen_width, &screen_height);
+     gdk_window_get_origin(gtk_widget_get_window(gui.drawarea), &x, &y);
+     gtk_window_get_size(GTK_WINDOW(preedit_window), &width, &height);
+     x = x + FILL_X(gui.col);
+     y = y + FILL_Y(gui.row);
+     if (x + width > screen_x + screen_width)
+       x = screen_x + screen_width - width;
+     if (y + height > screen_y + screen_height)
+       y = screen_y + screen_height - height;
+     gtk_window_move(GTK_WINDOW(preedit_window), x, y);
+ }
+ 
+     static void
+ im_preedit_window_open()
+ {
+     char *preedit_string;
+ #if !GTK_CHECK_VERSION(3,16,0)
+     char buf[8];
+ #endif
+     PangoAttrList *attr_list;
+     PangoLayout *layout;
+ #if GTK_CHECK_VERSION(3,0,0)
+ # if !GTK_CHECK_VERSION(3,16,0)
+     GdkRGBA color;
+ # endif
+ #else
+     GdkColor color;
+ #endif
+     gint w, h;
+ 
+     if (preedit_window == NULL)
+     {
+       preedit_window = gtk_window_new(GTK_WINDOW_POPUP);
+       gtk_window_set_transient_for(GTK_WINDOW(preedit_window),
+                                                    GTK_WINDOW(gui.mainwin));
+       preedit_label = gtk_label_new("");
+       gtk_widget_set_name(preedit_label, "vim-gui-preedit-area");
+       gtk_container_add(GTK_CONTAINER(preedit_window), preedit_label);
+     }
+ 
+ #if GTK_CHECK_VERSION(3,16,0)
+     {
+       GtkStyleContext * const context
+                                 = gtk_widget_get_style_context(gui.drawarea);
+       GtkCssProvider * const provider = gtk_css_provider_new();
+       gchar              *css = NULL;
+       const char * const fontname
+                          = pango_font_description_get_family(gui.norm_font);
+       gint    fontsize
+               = pango_font_description_get_size(gui.norm_font) / PANGO_SCALE;
+       gchar   *fontsize_propval = NULL;
+ 
+       if (!pango_font_description_get_size_is_absolute(gui.norm_font))
+       {
+           // fontsize was given in points.  Convert it into that in pixels
+           // to use with CSS.
+           GdkScreen * const screen
+                 = gdk_window_get_screen(gtk_widget_get_window(gui.mainwin));
+           const gdouble dpi = gdk_screen_get_resolution(screen);
+           fontsize = dpi * fontsize / 72;
+       }
+       if (fontsize > 0)
+           fontsize_propval = g_strdup_printf("%dpx", fontsize);
+       else
+           fontsize_propval = g_strdup_printf("inherit");
+ 
+       css = g_strdup_printf(
+               "widget#vim-gui-preedit-area {\n"
+               "  font-family: %s,monospace;\n"
+               "  font-size: %s;\n"
+               "  color: #%.2lx%.2lx%.2lx;\n"
+               "  background-color: #%.2lx%.2lx%.2lx;\n"
+               "}\n",
+               fontname != NULL ? fontname : "inherit",
+               fontsize_propval,
+               (gui.norm_pixel >> 16) & 0xff,
+               (gui.norm_pixel >> 8) & 0xff,
+               gui.norm_pixel & 0xff,
+               (gui.back_pixel >> 16) & 0xff,
+               (gui.back_pixel >> 8) & 0xff,
+               gui.back_pixel & 0xff);
+ 
+       gtk_css_provider_load_from_data(provider, css, -1, NULL);
+       gtk_style_context_add_provider(context,
+                                    GTK_STYLE_PROVIDER(provider), G_MAXUINT);
+ 
+       g_free(css);
+       g_free(fontsize_propval);
+       g_object_unref(provider);
+     }
+ #elif GTK_CHECK_VERSION(3,0,0)
+     gtk_widget_override_font(preedit_label, gui.norm_font);
+ 
+     vim_snprintf(buf, sizeof(buf), "#%06X", gui.norm_pixel);
+     gdk_rgba_parse(&color, buf);
+     gtk_widget_override_color(preedit_label, GTK_STATE_FLAG_NORMAL, &color);
+ 
+     vim_snprintf(buf, sizeof(buf), "#%06X", gui.back_pixel);
+     gdk_rgba_parse(&color, buf);
+     gtk_widget_override_background_color(preedit_label, GTK_STATE_FLAG_NORMAL,
+                                                                     &color);
+ #else
+     gtk_widget_modify_font(preedit_label, gui.norm_font);
+ 
+     vim_snprintf(buf, sizeof(buf), "#%06X", (unsigned)gui.norm_pixel);
+     gdk_color_parse(buf, &color);
+     gtk_widget_modify_fg(preedit_label, GTK_STATE_NORMAL, &color);
+ 
+     vim_snprintf(buf, sizeof(buf), "#%06X", (unsigned)gui.back_pixel);
+     gdk_color_parse(buf, &color);
+     gtk_widget_modify_bg(preedit_window, GTK_STATE_NORMAL, &color);
+ #endif
+ 
+     gtk_im_context_get_preedit_string(xic, &preedit_string, &attr_list, NULL);
+ 
+     if (preedit_string[0] != NUL)
+     {
+       gtk_label_set_text(GTK_LABEL(preedit_label), preedit_string);
+       gtk_label_set_attributes(GTK_LABEL(preedit_label), attr_list);
+ 
+       layout = gtk_label_get_layout(GTK_LABEL(preedit_label));
+       pango_layout_get_pixel_size(layout, &w, &h);
+       h = MAX(h, gui.char_height);
+       gtk_window_resize(GTK_WINDOW(preedit_window), w, h);
+ 
+       gtk_widget_show_all(preedit_window);
+ 
+       im_preedit_window_set_position();
+     }
+ 
+     g_free(preedit_string);
+     pango_attr_list_unref(attr_list);
+ }
+ 
+     static void
+ im_preedit_window_close()
+ {
+     if (preedit_window != NULL)
+       gtk_widget_hide(preedit_window);
+ }
+ 
+     static void
+ im_show_preedit()
+ {
+     im_preedit_window_open();
+ 
+     if (p_mh) // blank out the pointer if necessary
+       gui_mch_mousehide(TRUE);
+ }
+ 
+     static void
+ im_delete_preedit(void)
+ {
+     char_u bskey[]  = {CSI, 'k', 'b'};
+     char_u delkey[] = {CSI, 'k', 'D'};
+ 
+     if (p_imst == IM_OVER_THE_SPOT)
+     {
+       im_preedit_window_close();
+       return;
+     }
+ 
+     if (State & NORMAL
+ #ifdef FEAT_TERMINAL
+           && !term_use_loop()
+ #endif
+        )
+     {
+       im_preedit_cursor = 0;
+       return;
+     }
+     for (; im_preedit_cursor > 0; --im_preedit_cursor)
+       add_to_input_buf(bskey, (int)sizeof(bskey));
+ 
+     for (; im_preedit_trailing > 0; --im_preedit_trailing)
+       add_to_input_buf(delkey, (int)sizeof(delkey));
+ }
+ 
+ /*
+  * Move the cursor left by "num_move_back" characters.
+  * Note that ins_left() checks im_is_preediting() to avoid breaking undo for
+  * these K_LEFT keys.
+  */
+     static void
+ im_correct_cursor(int num_move_back)
+ {
+     char_u backkey[] = {CSI, 'k', 'l'};
+ 
+     if (State & NORMAL)
+       return;
+ #  ifdef FEAT_RIGHTLEFT
+     if ((State & CMDLINE) == 0 && curwin != NULL && curwin->w_p_rl)
+       backkey[2] = 'r';
+ #  endif
+     for (; num_move_back > 0; --num_move_back)
+       add_to_input_buf(backkey, (int)sizeof(backkey));
+ }
+ 
+ static int xim_expected_char = NUL;
+ static int xim_ignored_char = FALSE;
+ 
+ /*
+  * Update the mode and cursor while in an IM callback.
+  */
+     static void
+ im_show_info(void)
+ {
+     int           old_vgetc_busy;
+ 
+     old_vgetc_busy = vgetc_busy;
+     vgetc_busy = TRUE;
+     showmode();
+     vgetc_busy = old_vgetc_busy;
+     if ((State & NORMAL) || (State & INSERT))
+       setcursor();
+     out_flush();
+ }
+ 
+ /*
+  * Callback invoked when the user finished preediting.
+  * Put the final string into the input buffer.
+  */
+     static void
+ im_commit_cb(GtkIMContext *context UNUSED,
+            const gchar *str,
+            gpointer data UNUSED)
+ {
+     int               slen = (int)STRLEN(str);
+     int               add_to_input = TRUE;
+     int               clen;
+     int               len = slen;
+     int               commit_with_preedit = TRUE;
+     char_u    *im_str;
+ 
+ #ifdef XIM_DEBUG
+     xim_log("im_commit_cb(): %s\n", str);
+ #endif
+ 
+     if (p_imst == IM_ON_THE_SPOT)
+     {
+       // The imhangul module doesn't reset the preedit string before
+       // committing.  Call im_delete_preedit() to work around that.
+       im_delete_preedit();
+ 
+       // Indicate that preediting has finished.
+       if (preedit_start_col == MAXCOL)
+       {
+           init_preedit_start_col();
+           commit_with_preedit = FALSE;
+       }
+ 
+       // The thing which setting "preedit_start_col" to MAXCOL means that
+       // "preedit_start_col" will be set forcedly when calling
+       // preedit_changed_cb() next time.
+       // "preedit_start_col" should not reset with MAXCOL on this part. Vim
+       // is simulating the preediting by using add_to_input_str(). when
+       // preedit begin immediately before committed, the typebuf is not
+       // flushed to screen, then it can't get correct "preedit_start_col".
+       // Thus, it should calculate the cells by adding cells of the committed
+       // string.
+       if (input_conv.vc_type != CONV_NONE)
+       {
+           im_str = string_convert(&input_conv, (char_u *)str, &len);
+           g_return_if_fail(im_str != NULL);
+       }
+       else
+           im_str = (char_u *)str;
+ 
+       clen = mb_string2cells(im_str, len);
+ 
+       if (input_conv.vc_type != CONV_NONE)
+           vim_free(im_str);
+       preedit_start_col += clen;
+     }
+ 
+     // Is this a single character that matches a keypad key that's just
+     // been pressed?  If so, we don't want it to be entered as such - let
+     // us carry on processing the raw keycode so that it may be used in
+     // mappings as <kSomething>.
+     if (xim_expected_char != NUL)
+     {
+       // We're currently processing a keypad or other special key
+       if (slen == 1 && str[0] == xim_expected_char)
+       {
+           // It's a match - don't do it here
+           xim_ignored_char = TRUE;
+           add_to_input = FALSE;
+       }
+       else
+       {
+           // Not a match
+           xim_ignored_char = FALSE;
+       }
+     }
+ 
+     if (add_to_input)
+       im_add_to_input((char_u *)str, slen);
+ 
+     if (p_imst == IM_ON_THE_SPOT)
+     {
+       // Inserting chars while "im_is_active" is set does not cause a
+       // change of buffer.  When the chars are committed the buffer must be
+       // marked as changed.
+       if (!commit_with_preedit)
+           preedit_start_col = MAXCOL;
+ 
+       // This flag is used in changed() at next call.
+       xim_changed_while_preediting = TRUE;
+     }
+ 
+     if (gtk_main_level() > 0)
+       gtk_main_quit();
+ }
+ 
+ /*
+  * Callback invoked after start to the preedit.
+  */
+     static void
+ im_preedit_start_cb(GtkIMContext *context UNUSED, gpointer data UNUSED)
+ {
+ #ifdef XIM_DEBUG
+     xim_log("im_preedit_start_cb()\n");
+ #endif
+ 
+     im_is_active = TRUE;
+     preedit_is_active = TRUE;
+     gui_update_cursor(TRUE, FALSE);
+     im_show_info();
+ }
+ 
+ /*
+  * Callback invoked after end to the preedit.
+  */
+     static void
+ im_preedit_end_cb(GtkIMContext *context UNUSED, gpointer data UNUSED)
+ {
+ #ifdef XIM_DEBUG
+     xim_log("im_preedit_end_cb()\n");
+ #endif
+     im_delete_preedit();
+ 
+     // Indicate that preediting has finished
+     if (p_imst == IM_ON_THE_SPOT)
+       preedit_start_col = MAXCOL;
+     xim_has_preediting = FALSE;
+ 
+ #if 0
+     // Removal of this line suggested by Takuhiro Nishioka.  Fixes that IM was
+     // switched off unintentionally.  We now use preedit_is_active (added by
+     // SungHyun Nam).
+     im_is_active = FALSE;
+ #endif
+     preedit_is_active = FALSE;
+     gui_update_cursor(TRUE, FALSE);
+     im_show_info();
+ }
+ 
+ /*
+  * Callback invoked after changes to the preedit string.  If the preedit
+  * string was empty before, remember the preedit start column so we know
+  * where to apply feedback attributes.  Delete the previous preedit string
+  * if there was one, save the new preedit cursor offset, and put the new
+  * string into the input buffer.
+  *
+  * TODO: The pragmatic "put into input buffer" approach used here has
+  *       several fundamental problems:
+  *
+  * - The characters in the preedit string are subject to remapping.
+  *   That's broken, only the finally committed string should be remapped.
+  *
+  * - There is a race condition involved:  The retrieved value for the
+  *   current cursor position will be wrong if any unprocessed characters
+  *   are still queued in the input buffer.
+  *
+  * - Due to the lack of synchronization between the file buffer in memory
+  *   and any typed characters, it's practically impossible to implement the
+  *   "retrieve_surrounding" and "delete_surrounding" signals reliably.  IM
+  *   modules for languages such as Thai are likely to rely on this feature
+  *   for proper operation.
+  *
+  * Conclusions:  I think support for preediting needs to be moved to the
+  * core parts of Vim.  Ideally, until it has been committed, the preediting
+  * string should only be displayed and not affect the buffer content at all.
+  * The question how to deal with the synchronization issue still remains.
+  * Circumventing the input buffer is probably not desirable.  Anyway, I think
+  * implementing "retrieve_surrounding" is the only hard problem.
+  *
+  * One way to solve all of this in a clean manner would be to queue all key
+  * press/release events "as is" in the input buffer, and apply the IM 
filtering
+  * at the receiving end of the queue.  This, however, would have a rather 
large
+  * impact on the code base.  If there is an easy way to force processing of 
all
+  * remaining input from within the "retrieve_surrounding" signal handler, this
+  * might not be necessary.  Gotta ask on vim-dev for opinions.
+  */
+     static void
+ im_preedit_changed_cb(GtkIMContext *context, gpointer data UNUSED)
+ {
+     char    *preedit_string = NULL;
+     int           cursor_index    = 0;
+     int           num_move_back   = 0;
+     char_u  *str;
+     char_u  *p;
+     int           i;
+ 
+     if (p_imst == IM_ON_THE_SPOT)
+       gtk_im_context_get_preedit_string(context,
+                                         &preedit_string, NULL,
+                                         &cursor_index);
+     else
+       gtk_im_context_get_preedit_string(context,
+                                         &preedit_string, NULL,
+                                         NULL);
+ 
+ #ifdef XIM_DEBUG
+     xim_log("im_preedit_changed_cb(): %s\n", preedit_string);
+ #endif
+ 
+     g_return_if_fail(preedit_string != NULL); // just in case
+ 
+     if (p_imst == IM_OVER_THE_SPOT)
+     {
+       if (preedit_string[0] == NUL)
+       {
+           xim_has_preediting = FALSE;
+           im_delete_preedit();
+       }
+       else
+       {
+           xim_has_preediting = TRUE;
+           im_show_preedit();
+       }
+     }
+     else
+     {
+       // If preedit_start_col is MAXCOL set it to the current cursor position.
+       if (preedit_start_col == MAXCOL && preedit_string[0] != '\0')
+       {
+           xim_has_preediting = TRUE;
+ 
+           // Urgh, this breaks if the input buffer isn't empty now
+           init_preedit_start_col();
+       }
+       else if (cursor_index == 0 && preedit_string[0] == '\0')
+       {
+           xim_has_preediting = FALSE;
+ 
+           // If at the start position (after typing backspace)
+           // preedit_start_col must be reset.
+           preedit_start_col = MAXCOL;
+       }
+ 
+       im_delete_preedit();
+ 
+       /*
+        * Compute the end of the preediting area: "preedit_end_col".
+        * According to the documentation of 
gtk_im_context_get_preedit_string(),
+        * the cursor_pos output argument returns the offset in bytes.  This is
+        * unfortunately not true -- real life shows the offset is in 
characters,
+        * and the GTK+ source code agrees with me.  Will file a bug later.
+        */
+       if (preedit_start_col != MAXCOL)
+           preedit_end_col = preedit_start_col;
+       str = (char_u *)preedit_string;
+       for (p = str, i = 0; *p != NUL; p += utf_byte2len(*p), ++i)
+       {
+           int is_composing;
+ 
+           is_composing = ((*p & 0x80) != 0 && 
utf_iscomposing(utf_ptr2char(p)));
+           /*
+            * These offsets are used as counters when generating <BS> and <Del>
+            * to delete the preedit string.  So don't count composing 
characters
+            * unless 'delcombine' is enabled.
+            */
+           if (!is_composing || p_deco)
+           {
+               if (i < cursor_index)
+                   ++im_preedit_cursor;
+               else
+                   ++im_preedit_trailing;
+           }
+           if (!is_composing && i >= cursor_index)
+           {
+               // This is essentially the same as im_preedit_trailing, except
+               // composing characters are not counted even if p_deco is set.
+               ++num_move_back;
+           }
+           if (preedit_start_col != MAXCOL)
+               preedit_end_col += utf_ptr2cells(p);
+       }
+ 
+       if (p > str)
+       {
+           im_add_to_input(str, (int)(p - str));
+           im_correct_cursor(num_move_back);
+       }
+     }
+ 
+     g_free(preedit_string);
+ 
+     if (gtk_main_level() > 0)
+       gtk_main_quit();
+ }
+ 
+ /*
+  * Translate the Pango attributes at iter to Vim highlighting attributes.
+  * Ignore attributes not supported by Vim highlighting.  This shouldn't have
+  * too much impact -- right now we handle even more attributes than necessary
+  * for the IM modules I tested with.
+  */
+     static int
+ translate_pango_attributes(PangoAttrIterator *iter)
+ {
+     PangoAttribute  *attr;
+     int                   char_attr = HL_NORMAL;
+ 
+     attr = pango_attr_iterator_get(iter, PANGO_ATTR_UNDERLINE);
+     if (attr != NULL && ((PangoAttrInt *)attr)->value
+                                                != (int)PANGO_UNDERLINE_NONE)
+       char_attr |= HL_UNDERLINE;
+ 
+     attr = pango_attr_iterator_get(iter, PANGO_ATTR_WEIGHT);
+     if (attr != NULL && ((PangoAttrInt *)attr)->value >= 
(int)PANGO_WEIGHT_BOLD)
+       char_attr |= HL_BOLD;
+ 
+     attr = pango_attr_iterator_get(iter, PANGO_ATTR_STYLE);
+     if (attr != NULL && ((PangoAttrInt *)attr)->value
+                                                  != (int)PANGO_STYLE_NORMAL)
+       char_attr |= HL_ITALIC;
+ 
+     attr = pango_attr_iterator_get(iter, PANGO_ATTR_BACKGROUND);
+     if (attr != NULL)
+     {
+       const PangoColor *color = &((PangoAttrColor *)attr)->color;
+ 
+       // Assume inverse if black background is requested
+       if ((color->red | color->green | color->blue) == 0)
+           char_attr |= HL_INVERSE;
+     }
+ 
+     return char_attr;
+ }
+ 
+ /*
+  * Retrieve the highlighting attributes at column col in the preedit string.
+  * Return -1 if not in preediting mode or if col is out of range.
+  */
+     int
+ im_get_feedback_attr(int col)
+ {
+     char          *preedit_string = NULL;
+     PangoAttrList   *attr_list            = NULL;
+     int                   char_attr       = -1;
+ 
+     if (xic == NULL)
+       return char_attr;
+ 
+     gtk_im_context_get_preedit_string(xic, &preedit_string, &attr_list, NULL);
+ 
+     if (preedit_string != NULL && attr_list != NULL)
+     {
+       int idx;
+ 
+       // Get the byte index as used by PangoAttrIterator
+       for (idx = 0; col > 0 && preedit_string[idx] != '\0'; --col)
+           idx += utfc_ptr2len((char_u *)preedit_string + idx);
+ 
+       if (preedit_string[idx] != '\0')
+       {
+           PangoAttrIterator   *iter;
+           int                 start, end;
+ 
+           char_attr = HL_NORMAL;
+           iter = pango_attr_list_get_iterator(attr_list);
+ 
+           // Extract all relevant attributes from the list.
+           do
+           {
+               pango_attr_iterator_range(iter, &start, &end);
+ 
+               if (idx >= start && idx < end)
+                   char_attr |= translate_pango_attributes(iter);
+           }
+           while (pango_attr_iterator_next(iter));
+ 
+           pango_attr_iterator_destroy(iter);
+       }
+     }
+ 
+     if (attr_list != NULL)
+       pango_attr_list_unref(attr_list);
+     g_free(preedit_string);
+ 
+     return char_attr;
+ }
+ 
+     void
+ xim_init(void)
+ {
+ #ifdef XIM_DEBUG
+     xim_log("xim_init()\n");
+ #endif
+ 
+     g_return_if_fail(gui.drawarea != NULL);
+     g_return_if_fail(gtk_widget_get_window(gui.drawarea) != NULL);
+ 
+     xic = gtk_im_multicontext_new();
+     g_object_ref(xic);
+ 
+     im_commit_handler_id = g_signal_connect(G_OBJECT(xic), "commit",
+                                           G_CALLBACK(&im_commit_cb), NULL);
+     g_signal_connect(G_OBJECT(xic), "preedit_changed",
+                    G_CALLBACK(&im_preedit_changed_cb), NULL);
+     g_signal_connect(G_OBJECT(xic), "preedit_start",
+                    G_CALLBACK(&im_preedit_start_cb), NULL);
+     g_signal_connect(G_OBJECT(xic), "preedit_end",
+                    G_CALLBACK(&im_preedit_end_cb), NULL);
+ 
+     gtk_im_context_set_client_window(xic, 
gtk_widget_get_window(gui.drawarea));
+ }
+ 
+     void
+ im_shutdown(void)
+ {
+ #ifdef XIM_DEBUG
+     xim_log("im_shutdown()\n");
+ #endif
+ 
+     if (xic != NULL)
+     {
+       gtk_im_context_focus_out(xic);
+       g_object_unref(xic);
+       xic = NULL;
+     }
+     im_is_active = FALSE;
+     im_commit_handler_id = 0;
+     if (p_imst == IM_ON_THE_SPOT)
+       preedit_start_col = MAXCOL;
+     xim_has_preediting = FALSE;
+ }
+ 
+ /*
+  * Convert the string argument to keyval and state for GdkEventKey.
+  * If str is valid return TRUE, otherwise FALSE.
+  *
+  * See 'imactivatekey' for documentation of the format.
+  */
+     static int
+ im_string_to_keyval(const char *str, unsigned int *keyval, unsigned int 
*state)
+ {
+     const char            *mods_end;
+     unsigned      tmp_keyval;
+     unsigned      tmp_state = 0;
+ 
+     mods_end = strrchr(str, '-');
+     mods_end = (mods_end != NULL) ? mods_end + 1 : str;
+ 
+     // Parse modifier keys
+     while (str < mods_end)
+       switch (*str++)
+       {
+           case '-':                                                   break;
+           case 'S': case 's': tmp_state |= (unsigned)GDK_SHIFT_MASK;  break;
+           case 'L': case 'l': tmp_state |= (unsigned)GDK_LOCK_MASK;   break;
+           case 'C': case 'c': tmp_state |= (unsigned)GDK_CONTROL_MASK;break;
+           case '1':           tmp_state |= (unsigned)GDK_MOD1_MASK;   break;
+           case '2':           tmp_state |= (unsigned)GDK_MOD2_MASK;   break;
+           case '3':           tmp_state |= (unsigned)GDK_MOD3_MASK;   break;
+           case '4':           tmp_state |= (unsigned)GDK_MOD4_MASK;   break;
+           case '5':           tmp_state |= (unsigned)GDK_MOD5_MASK;   break;
+           default:
+               return FALSE;
+       }
+ 
+     tmp_keyval = gdk_keyval_from_name(str);
+ 
+     if (tmp_keyval == 0 || tmp_keyval == GDK_VoidSymbol)
+       return FALSE;
+ 
+     if (keyval != NULL)
+       *keyval = tmp_keyval;
+     if (state != NULL)
+       *state = tmp_state;
+ 
+     return TRUE;
+ }
+ 
+ /*
+  * Return TRUE if p_imak is valid, otherwise FALSE.  As a special case, an
+  * empty string is also regarded as valid.
+  *
+  * Note: The numerical key value of p_imak is cached if it was valid; thus
+  * boldly assuming im_xim_isvalid_imactivate() will always be called whenever
+  * 'imak' changes.  This is currently the case but not obvious -- should
+  * probably rename the function for clarity.
+  */
+     int
+ im_xim_isvalid_imactivate(void)
+ {
+     if (p_imak[0] == NUL)
+     {
+       im_activatekey_keyval = GDK_VoidSymbol;
+       im_activatekey_state  = 0;
+       return TRUE;
+     }
+ 
+     return im_string_to_keyval((const char *)p_imak,
+                              &im_activatekey_keyval,
+                              &im_activatekey_state);
+ }
+ 
+     static void
+ im_synthesize_keypress(unsigned int keyval, unsigned int state)
+ {
+     GdkEventKey *event;
+ 
+     event = (GdkEventKey *)gdk_event_new(GDK_KEY_PRESS);
+     g_object_ref(gtk_widget_get_window(gui.drawarea));
+                                       // unreffed by gdk_event_free()
+     event->window = gtk_widget_get_window(gui.drawarea);
+     event->send_event = TRUE;
+     event->time = GDK_CURRENT_TIME;
+     event->state  = state;
+     event->keyval = keyval;
+     event->hardware_keycode = // needed for XIM
+       XKeysymToKeycode(GDK_WINDOW_XDISPLAY(event->window), (KeySym)keyval);
+     event->length = 0;
+     event->string = NULL;
+ 
+     gtk_im_context_filter_keypress(xic, event);
+ 
+     // For consistency, also send the corresponding release event.
+     event->type = GDK_KEY_RELEASE;
+     event->send_event = FALSE;
+     gtk_im_context_filter_keypress(xic, event);
+ 
+     gdk_event_free((GdkEvent *)event);
+ }
+ 
+     void
+ xim_reset(void)
+ {
+ # ifdef FEAT_EVAL
+     if (USE_IMACTIVATEFUNC)
+       call_imactivatefunc(im_is_active);
+     else
+ # endif
+     if (xic != NULL)
+     {
+       gtk_im_context_reset(xic);
+ 
+       if (p_imdisable)
+           im_shutdown();
+       else
+       {
+           xim_set_focus(gui.in_focus);
+ 
+           if (im_activatekey_keyval != GDK_VoidSymbol)
+           {
+               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);
+               }
+           }
+           else
+           {
+               im_shutdown();
+               xim_init();
+               xim_set_focus(gui.in_focus);
+           }
+       }
+     }
+ 
+     if (p_imst == IM_ON_THE_SPOT)
+       preedit_start_col = MAXCOL;
+     xim_has_preediting = FALSE;
+ }
+ 
+     int
+ xim_queue_key_press_event(GdkEventKey *event, int down)
+ {
+     if (down)
+     {
+       /*
+        * Workaround GTK2 XIM 'feature' that always converts keypad keys to
+        * chars., even when not part of an IM sequence (ref. feature of
+        * gdk/gdkkeyuni.c).
+        * Flag any keypad keys that might represent a single char.
+        * If this (on its own - i.e., not part of an IM sequence) is
+        * committed while we're processing one of these keys, we can ignore
+        * that commit and go ahead & process it ourselves.  That way we can
+        * still distinguish keypad keys for use in mappings.
+        * Also add GDK_space to make <S-Space> work.
+        */
+       switch (event->keyval)
+       {
+           case GDK_KP_Add:      xim_expected_char = '+';  break;
+           case GDK_KP_Subtract: xim_expected_char = '-';  break;
+           case GDK_KP_Divide:   xim_expected_char = '/';  break;
+           case GDK_KP_Multiply: xim_expected_char = '*';  break;
+           case GDK_KP_Decimal:  xim_expected_char = '.';  break;
+           case GDK_KP_Equal:    xim_expected_char = '=';  break;
+           case GDK_KP_0:        xim_expected_char = '0';  break;
+           case GDK_KP_1:        xim_expected_char = '1';  break;
+           case GDK_KP_2:        xim_expected_char = '2';  break;
+           case GDK_KP_3:        xim_expected_char = '3';  break;
+           case GDK_KP_4:        xim_expected_char = '4';  break;
+           case GDK_KP_5:        xim_expected_char = '5';  break;
+           case GDK_KP_6:        xim_expected_char = '6';  break;
+           case GDK_KP_7:        xim_expected_char = '7';  break;
+           case GDK_KP_8:        xim_expected_char = '8';  break;
+           case GDK_KP_9:        xim_expected_char = '9';  break;
+           case GDK_space:       xim_expected_char = ' ';  break;
+           default:              xim_expected_char = NUL;
+       }
+       xim_ignored_char = FALSE;
+     }
+ 
+     /*
+      * When typing fFtT, XIM may be activated. Thus it must pass
+      * gtk_im_context_filter_keypress() in Normal mode.
+      * And while doing :sh too.
+      */
+     if (xic != NULL && !p_imdisable
+                   && (State & (INSERT | CMDLINE | NORMAL | EXTERNCMD)) != 0)
+     {
+       /*
+        * Filter 'imactivatekey' and map it to CTRL-^.  This way, Vim is
+        * always aware of the current status of IM, and can even emulate
+        * the activation key for modules that don't support one.
+        */
+       if (event->keyval == im_activatekey_keyval
+            && (event->state & im_activatekey_state) == im_activatekey_state)
+       {
+           unsigned int state_mask;
+ 
+           // Require the state of the 3 most used modifiers to match exactly.
+           // Otherwise e.g. <S-C-space> would be unusable for other purposes
+           // if the IM activate key is <S-space>.
+           state_mask  = im_activatekey_state;
+           state_mask |= ((int)GDK_SHIFT_MASK | (int)GDK_CONTROL_MASK
+                                                       | (int)GDK_MOD1_MASK);
+ 
+           if ((event->state & state_mask) != im_activatekey_state)
+               return FALSE;
+ 
+           // Don't send it a second time on GDK_KEY_RELEASE.
+           if (event->type != GDK_KEY_PRESS)
+               return TRUE;
+ 
+           if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE))
+           {
+               im_set_active(FALSE);
+ 
+               // ":lmap" mappings exists, toggle use of mappings.
+               State ^= LANGMAP;
+               if (State & LANGMAP)
+               {
+                   curbuf->b_p_iminsert = B_IMODE_NONE;
+                   State &= ~LANGMAP;
+               }
+               else
+               {
+                   curbuf->b_p_iminsert = B_IMODE_LMAP;
+                   State |= LANGMAP;
+               }
+               return TRUE;
+           }
+ 
+           return gtk_im_context_filter_keypress(xic, event);
+       }
+ 
+       // Don't filter events through the IM context if IM isn't active
+       // right now.  Unlike with GTK+ 1.2 we cannot rely on the IM module
+       // not doing anything before the activation key was sent.
+       if (im_activatekey_keyval == GDK_VoidSymbol || im_is_active)
+       {
+           int imresult = gtk_im_context_filter_keypress(xic, event);
+ 
+           if (p_imst == IM_ON_THE_SPOT)
+           {
+               // Some XIM send following sequence:
+               // 1. preedited string.
+               // 2. committed string.
+               // 3. line changed key.
+               // 4. preedited string.
+               // 5. remove preedited string.
+               // if 3, Vim can't move back the above line for 5.
+               // thus, this part should not parse the key.
+               if (!imresult && preedit_start_col != MAXCOL
+                                           && event->keyval == GDK_Return)
+               {
+                   im_synthesize_keypress(GDK_Return, 0U);
+                   return FALSE;
+               }
+           }
+ 
+           // If XIM tried to commit a keypad key as a single char.,
+           // ignore it so we can use the keypad key 'raw', for mappings.
+           if (xim_expected_char != NUL && xim_ignored_char)
+               // We had a keypad key, and XIM tried to thieve it
+               return FALSE;
+ 
+           // This is supposed to fix a problem with iBus, that space
+           // characters don't work in input mode.
+           xim_expected_char = NUL;
+ 
+           // Normal processing
+           return imresult;
+       }
+     }
+ 
+     return FALSE;
+ }
+ 
+     int
+ im_get_status(void)
+ {
+ #  ifdef FEAT_EVAL
+     if (USE_IMSTATUSFUNC)
+       return call_imstatusfunc();
+ #  endif
+     return im_is_active;
+ }
+ 
+     int
+ preedit_get_status(void)
+ {
+     return preedit_is_active;
+ }
+ 
+     int
+ im_is_preediting(void)
+ {
+     return xim_has_preediting;
+ }
+ 
+ # else // !FEAT_GUI_GTK
+ 
+ static int    xim_is_active = FALSE;  // XIM should be active in the current
+                                       // mode
+ static int    xim_has_focus = FALSE;  // XIM is really being used for Vim
+ #  ifdef FEAT_GUI_X11
+ static XIMStyle       input_style;
+ static int    status_area_enabled = TRUE;
+ #  endif
+ 
+ /*
+  * Switch using XIM on/off.  This is used by the code that changes "State".
+  * When 'imactivatefunc' is defined use that function instead.
+  */
+     void
+ im_set_active(int active_arg)
+ {
+     int active = active_arg;
+ 
+     // If 'imdisable' is set, XIM is never active.
+     if (p_imdisable)
+       active = FALSE;
+     else if (input_style & XIMPreeditPosition)
+       // There is a problem in switching XIM off when preediting is used,
+       // and it is not clear how this can be solved.  For now, keep XIM on
+       // all the time, like it was done in Vim 5.8.
+       active = TRUE;
+ 
+ #  if defined(FEAT_EVAL)
+     if (USE_IMACTIVATEFUNC)
+     {
+       if (active != im_get_status())
+       {
+           call_imactivatefunc(active);
+           xim_has_focus = active;
+       }
+       return;
+     }
+ #  endif
+ 
+     if (xic == NULL)
+       return;
+ 
+     // Remember the active state, it is needed when Vim gets keyboard focus.
+     xim_is_active = active;
+     xim_set_preedit();
+ }
+ 
+ /*
+  * Adjust using XIM for gaining or losing keyboard focus.  Also called when
+  * "xim_is_active" changes.
+  */
+     void
+ xim_set_focus(int focus)
+ {
+     if (xic == NULL)
+       return;
+ 
+     /*
+      * XIM only gets focus when the Vim window has keyboard focus and XIM has
+      * been set active for the current mode.
+      */
+     if (focus && xim_is_active)
+     {
+       if (!xim_has_focus)
+       {
+           xim_has_focus = TRUE;
+           XSetICFocus(xic);
+       }
+     }
+     else
+     {
+       if (xim_has_focus)
+       {
+           xim_has_focus = FALSE;
+           XUnsetICFocus(xic);
+       }
+     }
+ }
+ 
+     void
+ im_set_position(int row UNUSED, int col UNUSED)
+ {
+     xim_set_preedit();
+ }
+ 
+ /*
+  * Set the XIM to the current cursor position.
+  */
+     void
+ xim_set_preedit(void)
+ {
+     XVaNestedList attr_list;
+     XRectangle spot_area;
+     XPoint over_spot;
+     int line_space;
+ 
+     if (xic == NULL)
+       return;
+ 
+     xim_set_focus(TRUE);
+ 
+     if (!xim_has_focus)
+     {
+       // hide XIM cursor
+       over_spot.x = 0;
+       over_spot.y = -100; // arbitrary invisible position
+       attr_list = (XVaNestedList) XVaCreateNestedList(0,
+                                                       XNSpotLocation,
+                                                       &over_spot,
+                                                       NULL);
+       XSetICValues(xic, XNPreeditAttributes, attr_list, NULL);
+       XFree(attr_list);
+       return;
+     }
+ 
+     if (input_style & XIMPreeditPosition)
+     {
+       if (xim_fg_color == INVALCOLOR)
+       {
+           xim_fg_color = gui.def_norm_pixel;
+           xim_bg_color = gui.def_back_pixel;
+       }
+       over_spot.x = TEXT_X(gui.col);
+       over_spot.y = TEXT_Y(gui.row);
+       spot_area.x = 0;
+       spot_area.y = 0;
+       spot_area.height = gui.char_height * Rows;
+       spot_area.width  = gui.char_width * Columns;
+       line_space = gui.char_height;
+       attr_list = (XVaNestedList) XVaCreateNestedList(0,
+                                       XNSpotLocation, &over_spot,
+                                       XNForeground, (Pixel) xim_fg_color,
+                                       XNBackground, (Pixel) xim_bg_color,
+                                       XNArea, &spot_area,
+                                       XNLineSpace, line_space,
+                                       NULL);
+       if (XSetICValues(xic, XNPreeditAttributes, attr_list, NULL))
+           emsg(_("E284: Cannot set IC values"));
+       XFree(attr_list);
+     }
+ }
+ 
+ #  if defined(FEAT_GUI_X11)
+ static char e_xim[] = N_("E285: Failed to create input context");
+ #  endif
+ 
+ #  if defined(FEAT_GUI_X11) || defined(PROTO)
+ #   if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && 
!defined(SUN_SYSTEM)
+ #    define USE_X11R6_XIM
+ #   endif
+ 
+ static int xim_real_init(Window x11_window, Display *x11_display);
+ 
+ 
+ #  ifdef USE_X11R6_XIM
+     static void
+ xim_instantiate_cb(
+     Display   *display,
+     XPointer  client_data UNUSED,
+     XPointer  call_data UNUSED)
+ {
+     Window    x11_window;
+     Display   *x11_display;
+ 
+ #   ifdef XIM_DEBUG
+     xim_log("xim_instantiate_cb()\n");
+ #   endif
+ 
+     gui_get_x11_windis(&x11_window, &x11_display);
+     if (display != x11_display)
+       return;
+ 
+     xim_real_init(x11_window, x11_display);
+     gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
+     if (xic != NULL)
+       XUnregisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
+                                        xim_instantiate_cb, NULL);
+ }
+ 
+     static void
+ xim_destroy_cb(
+     XIM               im UNUSED,
+     XPointer  client_data UNUSED,
+     XPointer  call_data UNUSED)
+ {
+     Window    x11_window;
+     Display   *x11_display;
+ 
+ #   ifdef XIM_DEBUG
+     xim_log("xim_destroy_cb()\n");
+    #endif
+     gui_get_x11_windis(&x11_window, &x11_display);
+ 
+     xic = NULL;
+     status_area_enabled = FALSE;
+ 
+     gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
+ 
+     XRegisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
+                                  xim_instantiate_cb, NULL);
+ }
+ #  endif
+ 
+     void
+ xim_init(void)
+ {
+     Window    x11_window;
+     Display   *x11_display;
+ 
+ #  ifdef XIM_DEBUG
+     xim_log("xim_init()\n");
+ #  endif
+ 
+     gui_get_x11_windis(&x11_window, &x11_display);
+ 
+     xic = NULL;
+ 
+     if (xim_real_init(x11_window, x11_display))
+       return;
+ 
+     gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
+ 
+ #  ifdef USE_X11R6_XIM
+     XRegisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
+                                  xim_instantiate_cb, NULL);
+ #  endif
+ }
+ 
+     static int
+ xim_real_init(Window x11_window, Display *x11_display)
+ {
+     int               i;
+     char      *p,
+               *s,
+               *ns,
+               *end,
+               tmp[1024];
+ #  define IMLEN_MAX 40
+     char      buf[IMLEN_MAX + 7];
+     XIM               xim = NULL;
+     XIMStyles *xim_styles;
+     XIMStyle  this_input_style = 0;
+     Boolean   found;
+     XPoint    over_spot;
+     XVaNestedList preedit_list, status_list;
+ 
+     input_style = 0;
+     status_area_enabled = FALSE;
+ 
+     if (xic != NULL)
+       return FALSE;
+ 
+     if (gui.rsrc_input_method != NULL && *gui.rsrc_input_method != NUL)
+     {
+       strcpy(tmp, gui.rsrc_input_method);
+       for (ns = s = tmp; ns != NULL && *s != NUL;)
+       {
+           s = (char *)skipwhite((char_u *)s);
+           if (*s == NUL)
+               break;
+           if ((ns = end = strchr(s, ',')) == NULL)
+               end = s + strlen(s);
+           while (isspace(((char_u *)end)[-1]))
+               end--;
+           *end = NUL;
+ 
+           if (strlen(s) <= IMLEN_MAX)
+           {
+               strcpy(buf, "@im=");
+               strcat(buf, s);
+               if ((p = XSetLocaleModifiers(buf)) != NULL && *p != NUL
+                       && (xim = XOpenIM(x11_display, NULL, NULL, NULL))
+                                                                     != NULL)
+                   break;
+           }
+ 
+           s = ns + 1;
+       }
+     }
+ 
+     if (xim == NULL && (p = XSetLocaleModifiers("")) != NULL && *p != NUL)
+       xim = XOpenIM(x11_display, NULL, NULL, NULL);
+ 
+     // This is supposed to be useful to obtain characters through
+     // XmbLookupString() without really using a XIM.
+     if (xim == NULL && (p = XSetLocaleModifiers("@im=none")) != NULL
+                                                                && *p != NUL)
+       xim = XOpenIM(x11_display, NULL, NULL, NULL);
+ 
+     if (xim == NULL)
+     {
+       // Only give this message when verbose is set, because too many people
+       // got this message when they didn't want to use a XIM.
+       if (p_verbose > 0)
+       {
+           verbose_enter();
+           emsg(_("E286: Failed to open input method"));
+           verbose_leave();
+       }
+       return FALSE;
+     }
+ 
+ #  ifdef USE_X11R6_XIM
+     {
+       XIMCallback destroy_cb;
+ 
+       destroy_cb.callback = xim_destroy_cb;
+       destroy_cb.client_data = NULL;
+       if (XSetIMValues(xim, XNDestroyCallback, &destroy_cb, NULL))
+           emsg(_("E287: Warning: Could not set destroy callback to IM"));
+     }
+ #  endif
+ 
+     if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL) || 
!xim_styles)
+     {
+       emsg(_("E288: input method doesn't support any style"));
+       XCloseIM(xim);
+       return FALSE;
+     }
+ 
+     found = False;
+     strcpy(tmp, gui.rsrc_preedit_type_name);
+     for (s = tmp; s && !found; )
+     {
+       while (*s && isspace((unsigned char)*s))
+           s++;
+       if (!*s)
+           break;
+       if ((ns = end = strchr(s, ',')) != 0)
+           ns++;
+       else
+           end = s + strlen(s);
+       while (isspace((unsigned char)*end))
+           end--;
+       *end = '\0';
+ 
+       if (!strcmp(s, "OverTheSpot"))
+           this_input_style = (XIMPreeditPosition | XIMStatusArea);
+       else if (!strcmp(s, "OffTheSpot"))
+           this_input_style = (XIMPreeditArea | XIMStatusArea);
+       else if (!strcmp(s, "Root"))
+           this_input_style = (XIMPreeditNothing | XIMStatusNothing);
+ 
+       for (i = 0; (unsigned short)i < xim_styles->count_styles; i++)
+       {
+           if (this_input_style == xim_styles->supported_styles[i])
+           {
+               found = True;
+               break;
+           }
+       }
+       if (!found)
+           for (i = 0; (unsigned short)i < xim_styles->count_styles; i++)
+           {
+               if ((xim_styles->supported_styles[i] & this_input_style)
+                       == (this_input_style & ~XIMStatusArea))
+               {
+                   this_input_style &= ~XIMStatusArea;
+                   found = True;
+                   break;
+               }
+           }
+ 
+       s = ns;
+     }
+     XFree(xim_styles);
+ 
+     if (!found)
+     {
+       // Only give this message when verbose is set, because too many people
+       // got this message when they didn't want to use a XIM.
+       if (p_verbose > 0)
+       {
+           verbose_enter();
+           emsg(_("E289: input method doesn't support my preedit type"));
+           verbose_leave();
+       }
+       XCloseIM(xim);
+       return FALSE;
+     }
+ 
+     over_spot.x = TEXT_X(gui.col);
+     over_spot.y = TEXT_Y(gui.row);
+     input_style = this_input_style;
+ 
+     // A crash was reported when trying to pass gui.norm_font as XNFontSet,
+     // thus that has been removed.  Hopefully the default works...
+ #  ifdef FEAT_XFONTSET
+     if (gui.fontset != NOFONTSET)
+     {
+       preedit_list = XVaCreateNestedList(0,
+                               XNSpotLocation, &over_spot,
+                               XNForeground, (Pixel)gui.def_norm_pixel,
+                               XNBackground, (Pixel)gui.def_back_pixel,
+                               XNFontSet, (XFontSet)gui.fontset,
+                               NULL);
+       status_list = XVaCreateNestedList(0,
+                               XNForeground, (Pixel)gui.def_norm_pixel,
+                               XNBackground, (Pixel)gui.def_back_pixel,
+                               XNFontSet, (XFontSet)gui.fontset,
+                               NULL);
+     }
+     else
+ #  endif
+     {
+       preedit_list = XVaCreateNestedList(0,
+                               XNSpotLocation, &over_spot,
+                               XNForeground, (Pixel)gui.def_norm_pixel,
+                               XNBackground, (Pixel)gui.def_back_pixel,
+                               NULL);
+       status_list = XVaCreateNestedList(0,
+                               XNForeground, (Pixel)gui.def_norm_pixel,
+                               XNBackground, (Pixel)gui.def_back_pixel,
+                               NULL);
+     }
+ 
+     xic = XCreateIC(xim,
+                   XNInputStyle, input_style,
+                   XNClientWindow, x11_window,
+                   XNFocusWindow, gui.wid,
+                   XNPreeditAttributes, preedit_list,
+                   XNStatusAttributes, status_list,
+                   NULL);
+     XFree(status_list);
+     XFree(preedit_list);
+     if (xic != NULL)
+     {
+       if (input_style & XIMStatusArea)
+       {
+           xim_set_status_area();
+           status_area_enabled = TRUE;
+       }
+       else
+           gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
+     }
+     else
+     {
+       if (!is_not_a_term())
+           emsg(_(e_xim));
+       XCloseIM(xim);
+       return FALSE;
+     }
+ 
+     return TRUE;
+ }
+ 
+ #  endif // FEAT_GUI_X11
+ 
+ /*
+  * Get IM status.  When IM is on, return TRUE.  Else return FALSE.
+  * FIXME: This doesn't work correctly: Having focus doesn't always mean XIM is
+  * active, when not having focus XIM may still be active (e.g., when using a
+  * tear-off menu item).
+  */
+     int
+ im_get_status(void)
+ {
+ #  ifdef FEAT_EVAL
+     if (USE_IMSTATUSFUNC)
+       return call_imstatusfunc();
+ #  endif
+     return xim_has_focus;
+ }
+ 
+ # endif // !FEAT_GUI_GTK
+ 
+ # if !defined(FEAT_GUI_GTK) || defined(PROTO)
+ /*
+  * Set up the status area.
+  *
+  * This should use a separate Widget, but that seems not possible, because
+  * preedit_area and status_area should be set to the same window as for the
+  * text input.  Unfortunately this means the status area pollutes the text
+  * window...
+  */
+     void
+ xim_set_status_area(void)
+ {
+     XVaNestedList preedit_list = 0, status_list = 0, list = 0;
+     XRectangle pre_area, status_area;
+ 
+     if (xic == NULL)
+       return;
+ 
+     if (input_style & XIMStatusArea)
+     {
+       if (input_style & XIMPreeditArea)
+       {
+           XRectangle *needed_rect;
+ 
+           // to get status_area width
+           status_list = XVaCreateNestedList(0, XNAreaNeeded,
+                                             &needed_rect, NULL);
+           XGetICValues(xic, XNStatusAttributes, status_list, NULL);
+           XFree(status_list);
+ 
+           status_area.width = needed_rect->width;
+       }
+       else
+           status_area.width = gui.char_width * Columns;
+ 
+       status_area.x = 0;
+       status_area.y = gui.char_height * Rows + gui.border_offset;
+       if (gui.which_scrollbars[SBAR_BOTTOM])
+           status_area.y += gui.scrollbar_height;
+ #ifdef FEAT_MENU
+       if (gui.menu_is_active)
+           status_area.y += gui.menu_height;
+ #endif
+       status_area.height = gui.char_height;
+       status_list = XVaCreateNestedList(0, XNArea, &status_area, NULL);
+     }
+     else
+     {
+       status_area.x = 0;
+       status_area.y = gui.char_height * Rows + gui.border_offset;
+       if (gui.which_scrollbars[SBAR_BOTTOM])
+           status_area.y += gui.scrollbar_height;
+ #ifdef FEAT_MENU
+       if (gui.menu_is_active)
+           status_area.y += gui.menu_height;
+ #endif
+       status_area.width = 0;
+       status_area.height = gui.char_height;
+     }
+ 
+     if (input_style & XIMPreeditArea)   // off-the-spot
+     {
+       pre_area.x = status_area.x + status_area.width;
+       pre_area.y = gui.char_height * Rows + gui.border_offset;
+       pre_area.width = gui.char_width * Columns - pre_area.x;
+       if (gui.which_scrollbars[SBAR_BOTTOM])
+           pre_area.y += gui.scrollbar_height;
+ #ifdef FEAT_MENU
+       if (gui.menu_is_active)
+           pre_area.y += gui.menu_height;
+ #endif
+       pre_area.height = gui.char_height;
+       preedit_list = XVaCreateNestedList(0, XNArea, &pre_area, NULL);
+     }
+     else if (input_style & XIMPreeditPosition)   // over-the-spot
+     {
+       pre_area.x = 0;
+       pre_area.y = 0;
+       pre_area.height = gui.char_height * Rows;
+       pre_area.width = gui.char_width * Columns;
+       preedit_list = XVaCreateNestedList(0, XNArea, &pre_area, NULL);
+     }
+ 
+     if (preedit_list && status_list)
+       list = XVaCreateNestedList(0, XNPreeditAttributes, preedit_list,
+                                  XNStatusAttributes, status_list, NULL);
+     else if (preedit_list)
+       list = XVaCreateNestedList(0, XNPreeditAttributes, preedit_list,
+                                  NULL);
+     else if (status_list)
+       list = XVaCreateNestedList(0, XNStatusAttributes, status_list,
+                                  NULL);
+     else
+       list = NULL;
+ 
+     if (list)
+     {
+       XSetICValues(xic, XNVaNestedList, list, NULL);
+       XFree(list);
+     }
+     if (status_list)
+       XFree(status_list);
+     if (preedit_list)
+       XFree(preedit_list);
+ }
+ 
+     int
+ xim_get_status_area_height(void)
+ {
+     if (status_area_enabled)
+       return gui.char_height;
+     return 0;
+ }
+ # endif
+ 
+ #else // !defined(FEAT_XIM)
+ 
+ # if defined(IME_WITHOUT_XIM) || defined(VIMDLL) || defined(PROTO)
+ static int im_was_set_active = FALSE;
+ 
+     int
+ #  ifdef VIMDLL
+ mbyte_im_get_status(void)
+ #  else
+ im_get_status(void)
+ #  endif
+ {
+ #  if defined(FEAT_EVAL)
+     if (USE_IMSTATUSFUNC)
+       return call_imstatusfunc();
+ #  endif
+     return im_was_set_active;
+ }
+ 
+     void
+ #  ifdef VIMDLL
+ mbyte_im_set_active(int active_arg)
+ #  else
+ im_set_active(int active_arg)
+ #  endif
+ {
+ #  if defined(FEAT_EVAL)
+     int           active = !p_imdisable && active_arg;
+ 
+     if (USE_IMACTIVATEFUNC && active != im_get_status())
+     {
+       call_imactivatefunc(active);
+       im_was_set_active = active;
+     }
+ #  endif
+ }
+ 
+ #  if defined(FEAT_GUI) && !defined(FEAT_GUI_HAIKU) && !defined(VIMDLL)
+     void
+ im_set_position(int row UNUSED, int col UNUSED)
+ {
+ }
+ #  endif
+ # endif
+ 
+ #endif // FEAT_XIM
*** ../vim-8.2.0871/src/mbyte.c 2020-02-26 16:15:31.072386953 +0100
--- src/mbyte.c 2020-06-01 14:18:57.758948897 +0200
***************
*** 111,129 ****
  # endif
  #endif
  
- #if defined(FEAT_GUI_GTK) && defined(FEAT_XIM)
- # if GTK_CHECK_VERSION(3,0,0)
- #  include <gdk/gdkkeysyms-compat.h>
- # else
- #  include <gdk/gdkkeysyms.h>
- # endif
- # ifdef MSWIN
- #  include <gdk/gdkwin32.h>
- # else
- #  include <gdk/gdkx.h>
- # endif
- #endif
- 
  #ifdef HAVE_WCHAR_H
  # include <wchar.h>
  #endif
--- 111,116 ----
***************
*** 179,215 ****
      3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0,
  };
  
- /*
-  * XIM often causes trouble.  Define XIM_DEBUG to get a log of XIM callbacks
-  * in the "xim.log" file.
-  */
- // #define XIM_DEBUG
- #ifdef XIM_DEBUG
-     static void
- xim_log(char *s, ...)
- {
-     va_list arglist;
-     static FILE *fd = NULL;
- 
-     if (fd == (FILE *)-1)
-       return;
-     if (fd == NULL)
-     {
-       fd = mch_fopen("xim.log", "w");
-       if (fd == NULL)
-       {
-           emsg("Cannot open xim.log");
-           fd = (FILE *)-1;
-           return;
-       }
-     }
- 
-     va_start(arglist, s);
-     vfprintf(fd, s, arglist);
-     va_end(arglist);
- }
- #endif
- 
  
  /*
   * Canonical encoding names and their properties.
--- 166,171 ----
***************
*** 4778,6503 ****
  #  endif // DYNAMIC_ICONV
  # endif // USE_ICONV
  
- 
- #ifdef FEAT_GUI
- # define USE_IMACTIVATEFUNC (!gui.in_use && *p_imaf != NUL)
- # define USE_IMSTATUSFUNC (!gui.in_use && *p_imsf != NUL)
- #else
- # define USE_IMACTIVATEFUNC (*p_imaf != NUL)
- # define USE_IMSTATUSFUNC (*p_imsf != NUL)
- #endif
- 
- #if defined(FEAT_EVAL) && \
-     (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL))
-     static void
- call_imactivatefunc(int active)
- {
-     typval_T argv[2];
- 
-     argv[0].v_type = VAR_NUMBER;
-     argv[0].vval.v_number = active ? 1 : 0;
-     argv[1].v_type = VAR_UNKNOWN;
-     (void)call_func_retnr(p_imaf, 1, argv);
- }
- 
-     static int
- call_imstatusfunc(void)
- {
-     int is_active;
- 
-     // FIXME: Don't execute user function in unsafe situation.
-     if (exiting || is_autocmd_blocked())
-       return FALSE;
-     // FIXME: :py print 'xxx' is shown duplicate result.
-     // Use silent to avoid it.
-     ++msg_silent;
-     is_active = call_func_retnr(p_imsf, 0, NULL);
-     --msg_silent;
-     return (is_active > 0);
- }
- #endif
- 
- #if defined(FEAT_XIM) || defined(PROTO)
- 
- # if defined(FEAT_GUI_GTK) || defined(PROTO)
- static int xim_has_preediting INIT(= FALSE);  // IM current status
- 
- /*
-  * Set preedit_start_col to the current cursor position.
-  */
-     static void
- init_preedit_start_col(void)
- {
-     if (State & CMDLINE)
-       preedit_start_col = cmdline_getvcol_cursor();
-     else if (curwin != NULL && curwin->w_buffer != NULL)
-       getvcol(curwin, &curwin->w_cursor, &preedit_start_col, NULL, NULL);
-     // Prevent that preediting marks the buffer as changed.
-     xim_changed_while_preediting = curbuf->b_changed;
- }
- 
- static int im_is_active              = FALSE; // IM is enabled for current 
mode
- static int preedit_is_active   = FALSE;
- static int im_preedit_cursor   = 0;   // cursor offset in characters
- static int im_preedit_trailing = 0;   // number of characters after cursor
- 
- static unsigned long im_commit_handler_id  = 0;
- static unsigned int  im_activatekey_keyval = GDK_VoidSymbol;
- static unsigned int  im_activatekey_state  = 0;
- 
- static GtkWidget *preedit_window = NULL;
- static GtkWidget *preedit_label = NULL;
- 
- static void im_preedit_window_set_position(void);
- 
-     void
- im_set_active(int active)
- {
-     int was_active;
- 
-     was_active = !!im_get_status();
-     im_is_active = (active && !p_imdisable);
- 
-     if (im_is_active != was_active)
-       xim_reset();
- }
- 
-     void
- xim_set_focus(int focus)
- {
-     if (xic != NULL)
-     {
-       if (focus)
-           gtk_im_context_focus_in(xic);
-       else
-           gtk_im_context_focus_out(xic);
-     }
- }
- 
-     void
- im_set_position(int row, int col)
- {
-     if (xic != NULL)
-     {
-       GdkRectangle area;
- 
-       area.x = FILL_X(col);
-       area.y = FILL_Y(row);
-       area.width  = gui.char_width * (mb_lefthalve(row, col) ? 2 : 1);
-       area.height = gui.char_height;
- 
-       gtk_im_context_set_cursor_location(xic, &area);
- 
-       if (p_imst == IM_OVER_THE_SPOT)
-           im_preedit_window_set_position();
-     }
- }
- 
- #  if 0 || defined(PROTO) // apparently only used in gui_x11.c
-     void
- xim_set_preedit(void)
- {
-     im_set_position(gui.row, gui.col);
- }
- #  endif
- 
-     static void
- im_add_to_input(char_u *str, int len)
- {
-     // Convert from 'termencoding' (always "utf-8") to 'encoding'
-     if (input_conv.vc_type != CONV_NONE)
-     {
-       str = string_convert(&input_conv, str, &len);
-       g_return_if_fail(str != NULL);
-     }
- 
-     add_to_input_buf_csi(str, len);
- 
-     if (input_conv.vc_type != CONV_NONE)
-       vim_free(str);
- 
-     if (p_mh) // blank out the pointer if necessary
-       gui_mch_mousehide(TRUE);
- }
- 
-      static void
- im_preedit_window_set_position(void)
- {
-     int x, y, width, height;
-     int screen_x, screen_y, screen_width, screen_height;
- 
-     if (preedit_window == NULL)
-       return;
- 
-     gui_gtk_get_screen_geom_of_win(gui.drawarea,
-                         &screen_x, &screen_y, &screen_width, &screen_height);
-     gdk_window_get_origin(gtk_widget_get_window(gui.drawarea), &x, &y);
-     gtk_window_get_size(GTK_WINDOW(preedit_window), &width, &height);
-     x = x + FILL_X(gui.col);
-     y = y + FILL_Y(gui.row);
-     if (x + width > screen_x + screen_width)
-       x = screen_x + screen_width - width;
-     if (y + height > screen_y + screen_height)
-       y = screen_y + screen_height - height;
-     gtk_window_move(GTK_WINDOW(preedit_window), x, y);
- }
- 
-     static void
- im_preedit_window_open()
- {
-     char *preedit_string;
- #if !GTK_CHECK_VERSION(3,16,0)
-     char buf[8];
- #endif
-     PangoAttrList *attr_list;
-     PangoLayout *layout;
- #if GTK_CHECK_VERSION(3,0,0)
- # if !GTK_CHECK_VERSION(3,16,0)
-     GdkRGBA color;
- # endif
- #else
-     GdkColor color;
- #endif
-     gint w, h;
- 
-     if (preedit_window == NULL)
-     {
-       preedit_window = gtk_window_new(GTK_WINDOW_POPUP);
-       gtk_window_set_transient_for(GTK_WINDOW(preedit_window),
-                                                    GTK_WINDOW(gui.mainwin));
-       preedit_label = gtk_label_new("");
-       gtk_widget_set_name(preedit_label, "vim-gui-preedit-area");
-       gtk_container_add(GTK_CONTAINER(preedit_window), preedit_label);
-     }
- 
- #if GTK_CHECK_VERSION(3,16,0)
-     {
-       GtkStyleContext * const context
-                                 = gtk_widget_get_style_context(gui.drawarea);
-       GtkCssProvider * const provider = gtk_css_provider_new();
-       gchar              *css = NULL;
-       const char * const fontname
-                          = pango_font_description_get_family(gui.norm_font);
-       gint    fontsize
-               = pango_font_description_get_size(gui.norm_font) / PANGO_SCALE;
-       gchar   *fontsize_propval = NULL;
- 
-       if (!pango_font_description_get_size_is_absolute(gui.norm_font))
-       {
-           // fontsize was given in points.  Convert it into that in pixels
-           // to use with CSS.
-           GdkScreen * const screen
-                 = gdk_window_get_screen(gtk_widget_get_window(gui.mainwin));
-           const gdouble dpi = gdk_screen_get_resolution(screen);
-           fontsize = dpi * fontsize / 72;
-       }
-       if (fontsize > 0)
-           fontsize_propval = g_strdup_printf("%dpx", fontsize);
-       else
-           fontsize_propval = g_strdup_printf("inherit");
- 
-       css = g_strdup_printf(
-               "widget#vim-gui-preedit-area {\n"
-               "  font-family: %s,monospace;\n"
-               "  font-size: %s;\n"
-               "  color: #%.2lx%.2lx%.2lx;\n"
-               "  background-color: #%.2lx%.2lx%.2lx;\n"
-               "}\n",
-               fontname != NULL ? fontname : "inherit",
-               fontsize_propval,
-               (gui.norm_pixel >> 16) & 0xff,
-               (gui.norm_pixel >> 8) & 0xff,
-               gui.norm_pixel & 0xff,
-               (gui.back_pixel >> 16) & 0xff,
-               (gui.back_pixel >> 8) & 0xff,
-               gui.back_pixel & 0xff);
- 
-       gtk_css_provider_load_from_data(provider, css, -1, NULL);
-       gtk_style_context_add_provider(context,
-                                    GTK_STYLE_PROVIDER(provider), G_MAXUINT);
- 
-       g_free(css);
-       g_free(fontsize_propval);
-       g_object_unref(provider);
-     }
- #elif GTK_CHECK_VERSION(3,0,0)
-     gtk_widget_override_font(preedit_label, gui.norm_font);
- 
-     vim_snprintf(buf, sizeof(buf), "#%06X", gui.norm_pixel);
-     gdk_rgba_parse(&color, buf);
-     gtk_widget_override_color(preedit_label, GTK_STATE_FLAG_NORMAL, &color);
- 
-     vim_snprintf(buf, sizeof(buf), "#%06X", gui.back_pixel);
-     gdk_rgba_parse(&color, buf);
-     gtk_widget_override_background_color(preedit_label, GTK_STATE_FLAG_NORMAL,
-                                                                     &color);
- #else
-     gtk_widget_modify_font(preedit_label, gui.norm_font);
- 
-     vim_snprintf(buf, sizeof(buf), "#%06X", (unsigned)gui.norm_pixel);
-     gdk_color_parse(buf, &color);
-     gtk_widget_modify_fg(preedit_label, GTK_STATE_NORMAL, &color);
- 
-     vim_snprintf(buf, sizeof(buf), "#%06X", (unsigned)gui.back_pixel);
-     gdk_color_parse(buf, &color);
-     gtk_widget_modify_bg(preedit_window, GTK_STATE_NORMAL, &color);
- #endif
- 
-     gtk_im_context_get_preedit_string(xic, &preedit_string, &attr_list, NULL);
- 
-     if (preedit_string[0] != NUL)
-     {
-       gtk_label_set_text(GTK_LABEL(preedit_label), preedit_string);
-       gtk_label_set_attributes(GTK_LABEL(preedit_label), attr_list);
- 
-       layout = gtk_label_get_layout(GTK_LABEL(preedit_label));
-       pango_layout_get_pixel_size(layout, &w, &h);
-       h = MAX(h, gui.char_height);
-       gtk_window_resize(GTK_WINDOW(preedit_window), w, h);
- 
-       gtk_widget_show_all(preedit_window);
- 
-       im_preedit_window_set_position();
-     }
- 
-     g_free(preedit_string);
-     pango_attr_list_unref(attr_list);
- }
- 
-     static void
- im_preedit_window_close()
- {
-     if (preedit_window != NULL)
-       gtk_widget_hide(preedit_window);
- }
- 
-     static void
- im_show_preedit()
- {
-     im_preedit_window_open();
- 
-     if (p_mh) // blank out the pointer if necessary
-       gui_mch_mousehide(TRUE);
- }
- 
-     static void
- im_delete_preedit(void)
- {
-     char_u bskey[]  = {CSI, 'k', 'b'};
-     char_u delkey[] = {CSI, 'k', 'D'};
- 
-     if (p_imst == IM_OVER_THE_SPOT)
-     {
-       im_preedit_window_close();
-       return;
-     }
- 
-     if (State & NORMAL
- #ifdef FEAT_TERMINAL
-           && !term_use_loop()
- #endif
-        )
-     {
-       im_preedit_cursor = 0;
-       return;
-     }
-     for (; im_preedit_cursor > 0; --im_preedit_cursor)
-       add_to_input_buf(bskey, (int)sizeof(bskey));
- 
-     for (; im_preedit_trailing > 0; --im_preedit_trailing)
-       add_to_input_buf(delkey, (int)sizeof(delkey));
- }
- 
- /*
-  * Move the cursor left by "num_move_back" characters.
-  * Note that ins_left() checks im_is_preediting() to avoid breaking undo for
-  * these K_LEFT keys.
-  */
-     static void
- im_correct_cursor(int num_move_back)
- {
-     char_u backkey[] = {CSI, 'k', 'l'};
- 
-     if (State & NORMAL)
-       return;
- #  ifdef FEAT_RIGHTLEFT
-     if ((State & CMDLINE) == 0 && curwin != NULL && curwin->w_p_rl)
-       backkey[2] = 'r';
- #  endif
-     for (; num_move_back > 0; --num_move_back)
-       add_to_input_buf(backkey, (int)sizeof(backkey));
- }
- 
- static int xim_expected_char = NUL;
- static int xim_ignored_char = FALSE;
- 
- /*
-  * Update the mode and cursor while in an IM callback.
-  */
-     static void
- im_show_info(void)
- {
-     int           old_vgetc_busy;
- 
-     old_vgetc_busy = vgetc_busy;
-     vgetc_busy = TRUE;
-     showmode();
-     vgetc_busy = old_vgetc_busy;
-     if ((State & NORMAL) || (State & INSERT))
-       setcursor();
-     out_flush();
- }
- 
- /*
-  * Callback invoked when the user finished preediting.
-  * Put the final string into the input buffer.
-  */
-     static void
- im_commit_cb(GtkIMContext *context UNUSED,
-            const gchar *str,
-            gpointer data UNUSED)
- {
-     int               slen = (int)STRLEN(str);
-     int               add_to_input = TRUE;
-     int               clen;
-     int               len = slen;
-     int               commit_with_preedit = TRUE;
-     char_u    *im_str;
- 
- #ifdef XIM_DEBUG
-     xim_log("im_commit_cb(): %s\n", str);
- #endif
- 
-     if (p_imst == IM_ON_THE_SPOT)
-     {
-       // The imhangul module doesn't reset the preedit string before
-       // committing.  Call im_delete_preedit() to work around that.
-       im_delete_preedit();
- 
-       // Indicate that preediting has finished.
-       if (preedit_start_col == MAXCOL)
-       {
-           init_preedit_start_col();
-           commit_with_preedit = FALSE;
-       }
- 
-       // The thing which setting "preedit_start_col" to MAXCOL means that
-       // "preedit_start_col" will be set forcedly when calling
-       // preedit_changed_cb() next time.
-       // "preedit_start_col" should not reset with MAXCOL on this part. Vim
-       // is simulating the preediting by using add_to_input_str(). when
-       // preedit begin immediately before committed, the typebuf is not
-       // flushed to screen, then it can't get correct "preedit_start_col".
-       // Thus, it should calculate the cells by adding cells of the committed
-       // string.
-       if (input_conv.vc_type != CONV_NONE)
-       {
-           im_str = string_convert(&input_conv, (char_u *)str, &len);
-           g_return_if_fail(im_str != NULL);
-       }
-       else
-           im_str = (char_u *)str;
- 
-       clen = mb_string2cells(im_str, len);
- 
-       if (input_conv.vc_type != CONV_NONE)
-           vim_free(im_str);
-       preedit_start_col += clen;
-     }
- 
-     // Is this a single character that matches a keypad key that's just
-     // been pressed?  If so, we don't want it to be entered as such - let
-     // us carry on processing the raw keycode so that it may be used in
-     // mappings as <kSomething>.
-     if (xim_expected_char != NUL)
-     {
-       // We're currently processing a keypad or other special key
-       if (slen == 1 && str[0] == xim_expected_char)
-       {
-           // It's a match - don't do it here
-           xim_ignored_char = TRUE;
-           add_to_input = FALSE;
-       }
-       else
-       {
-           // Not a match
-           xim_ignored_char = FALSE;
-       }
-     }
- 
-     if (add_to_input)
-       im_add_to_input((char_u *)str, slen);
- 
-     if (p_imst == IM_ON_THE_SPOT)
-     {
-       // Inserting chars while "im_is_active" is set does not cause a
-       // change of buffer.  When the chars are committed the buffer must be
-       // marked as changed.
-       if (!commit_with_preedit)
-           preedit_start_col = MAXCOL;
- 
-       // This flag is used in changed() at next call.
-       xim_changed_while_preediting = TRUE;
-     }
- 
-     if (gtk_main_level() > 0)
-       gtk_main_quit();
- }
- 
- /*
-  * Callback invoked after start to the preedit.
-  */
-     static void
- im_preedit_start_cb(GtkIMContext *context UNUSED, gpointer data UNUSED)
- {
- #ifdef XIM_DEBUG
-     xim_log("im_preedit_start_cb()\n");
- #endif
- 
-     im_is_active = TRUE;
-     preedit_is_active = TRUE;
-     gui_update_cursor(TRUE, FALSE);
-     im_show_info();
- }
- 
- /*
-  * Callback invoked after end to the preedit.
-  */
-     static void
- im_preedit_end_cb(GtkIMContext *context UNUSED, gpointer data UNUSED)
- {
- #ifdef XIM_DEBUG
-     xim_log("im_preedit_end_cb()\n");
- #endif
-     im_delete_preedit();
- 
-     // Indicate that preediting has finished
-     if (p_imst == IM_ON_THE_SPOT)
-       preedit_start_col = MAXCOL;
-     xim_has_preediting = FALSE;
- 
- #if 0
-     // Removal of this line suggested by Takuhiro Nishioka.  Fixes that IM was
-     // switched off unintentionally.  We now use preedit_is_active (added by
-     // SungHyun Nam).
-     im_is_active = FALSE;
- #endif
-     preedit_is_active = FALSE;
-     gui_update_cursor(TRUE, FALSE);
-     im_show_info();
- }
- 
- /*
-  * Callback invoked after changes to the preedit string.  If the preedit
-  * string was empty before, remember the preedit start column so we know
-  * where to apply feedback attributes.  Delete the previous preedit string
-  * if there was one, save the new preedit cursor offset, and put the new
-  * string into the input buffer.
-  *
-  * TODO: The pragmatic "put into input buffer" approach used here has
-  *       several fundamental problems:
-  *
-  * - The characters in the preedit string are subject to remapping.
-  *   That's broken, only the finally committed string should be remapped.
-  *
-  * - There is a race condition involved:  The retrieved value for the
-  *   current cursor position will be wrong if any unprocessed characters
-  *   are still queued in the input buffer.
-  *
-  * - Due to the lack of synchronization between the file buffer in memory
-  *   and any typed characters, it's practically impossible to implement the
-  *   "retrieve_surrounding" and "delete_surrounding" signals reliably.  IM
-  *   modules for languages such as Thai are likely to rely on this feature
-  *   for proper operation.
-  *
-  * Conclusions:  I think support for preediting needs to be moved to the
-  * core parts of Vim.  Ideally, until it has been committed, the preediting
-  * string should only be displayed and not affect the buffer content at all.
-  * The question how to deal with the synchronization issue still remains.
-  * Circumventing the input buffer is probably not desirable.  Anyway, I think
-  * implementing "retrieve_surrounding" is the only hard problem.
-  *
-  * One way to solve all of this in a clean manner would be to queue all key
-  * press/release events "as is" in the input buffer, and apply the IM 
filtering
-  * at the receiving end of the queue.  This, however, would have a rather 
large
-  * impact on the code base.  If there is an easy way to force processing of 
all
-  * remaining input from within the "retrieve_surrounding" signal handler, this
-  * might not be necessary.  Gotta ask on vim-dev for opinions.
-  */
-     static void
- im_preedit_changed_cb(GtkIMContext *context, gpointer data UNUSED)
- {
-     char    *preedit_string = NULL;
-     int           cursor_index    = 0;
-     int           num_move_back   = 0;
-     char_u  *str;
-     char_u  *p;
-     int           i;
- 
-     if (p_imst == IM_ON_THE_SPOT)
-       gtk_im_context_get_preedit_string(context,
-                                         &preedit_string, NULL,
-                                         &cursor_index);
-     else
-       gtk_im_context_get_preedit_string(context,
-                                         &preedit_string, NULL,
-                                         NULL);
- 
- #ifdef XIM_DEBUG
-     xim_log("im_preedit_changed_cb(): %s\n", preedit_string);
- #endif
- 
-     g_return_if_fail(preedit_string != NULL); // just in case
- 
-     if (p_imst == IM_OVER_THE_SPOT)
-     {
-       if (preedit_string[0] == NUL)
-       {
-           xim_has_preediting = FALSE;
-           im_delete_preedit();
-       }
-       else
-       {
-           xim_has_preediting = TRUE;
-           im_show_preedit();
-       }
-     }
-     else
-     {
-       // If preedit_start_col is MAXCOL set it to the current cursor position.
-       if (preedit_start_col == MAXCOL && preedit_string[0] != '\0')
-       {
-           xim_has_preediting = TRUE;
- 
-           // Urgh, this breaks if the input buffer isn't empty now
-           init_preedit_start_col();
-       }
-       else if (cursor_index == 0 && preedit_string[0] == '\0')
-       {
-           xim_has_preediting = FALSE;
- 
-           // If at the start position (after typing backspace)
-           // preedit_start_col must be reset.
-           preedit_start_col = MAXCOL;
-       }
- 
-       im_delete_preedit();
- 
-       /*
-        * Compute the end of the preediting area: "preedit_end_col".
-        * According to the documentation of 
gtk_im_context_get_preedit_string(),
-        * the cursor_pos output argument returns the offset in bytes.  This is
-        * unfortunately not true -- real life shows the offset is in 
characters,
-        * and the GTK+ source code agrees with me.  Will file a bug later.
-        */
-       if (preedit_start_col != MAXCOL)
-           preedit_end_col = preedit_start_col;
-       str = (char_u *)preedit_string;
-       for (p = str, i = 0; *p != NUL; p += utf_byte2len(*p), ++i)
-       {
-           int is_composing;
- 
-           is_composing = ((*p & 0x80) != 0 && 
utf_iscomposing(utf_ptr2char(p)));
-           /*
-            * These offsets are used as counters when generating <BS> and <Del>
-            * to delete the preedit string.  So don't count composing 
characters
-            * unless 'delcombine' is enabled.
-            */
-           if (!is_composing || p_deco)
-           {
-               if (i < cursor_index)
-                   ++im_preedit_cursor;
-               else
-                   ++im_preedit_trailing;
-           }
-           if (!is_composing && i >= cursor_index)
-           {
-               // This is essentially the same as im_preedit_trailing, except
-               // composing characters are not counted even if p_deco is set.
-               ++num_move_back;
-           }
-           if (preedit_start_col != MAXCOL)
-               preedit_end_col += utf_ptr2cells(p);
-       }
- 
-       if (p > str)
-       {
-           im_add_to_input(str, (int)(p - str));
-           im_correct_cursor(num_move_back);
-       }
-     }
- 
-     g_free(preedit_string);
- 
-     if (gtk_main_level() > 0)
-       gtk_main_quit();
- }
- 
- /*
-  * Translate the Pango attributes at iter to Vim highlighting attributes.
-  * Ignore attributes not supported by Vim highlighting.  This shouldn't have
-  * too much impact -- right now we handle even more attributes than necessary
-  * for the IM modules I tested with.
-  */
-     static int
- translate_pango_attributes(PangoAttrIterator *iter)
- {
-     PangoAttribute  *attr;
-     int                   char_attr = HL_NORMAL;
- 
-     attr = pango_attr_iterator_get(iter, PANGO_ATTR_UNDERLINE);
-     if (attr != NULL && ((PangoAttrInt *)attr)->value
-                                                != (int)PANGO_UNDERLINE_NONE)
-       char_attr |= HL_UNDERLINE;
- 
-     attr = pango_attr_iterator_get(iter, PANGO_ATTR_WEIGHT);
-     if (attr != NULL && ((PangoAttrInt *)attr)->value >= 
(int)PANGO_WEIGHT_BOLD)
-       char_attr |= HL_BOLD;
- 
-     attr = pango_attr_iterator_get(iter, PANGO_ATTR_STYLE);
-     if (attr != NULL && ((PangoAttrInt *)attr)->value
-                                                  != (int)PANGO_STYLE_NORMAL)
-       char_attr |= HL_ITALIC;
- 
-     attr = pango_attr_iterator_get(iter, PANGO_ATTR_BACKGROUND);
-     if (attr != NULL)
-     {
-       const PangoColor *color = &((PangoAttrColor *)attr)->color;
- 
-       // Assume inverse if black background is requested
-       if ((color->red | color->green | color->blue) == 0)
-           char_attr |= HL_INVERSE;
-     }
- 
-     return char_attr;
- }
- 
- /*
-  * Retrieve the highlighting attributes at column col in the preedit string.
-  * Return -1 if not in preediting mode or if col is out of range.
-  */
-     int
- im_get_feedback_attr(int col)
- {
-     char          *preedit_string = NULL;
-     PangoAttrList   *attr_list            = NULL;
-     int                   char_attr       = -1;
- 
-     if (xic == NULL)
-       return char_attr;
- 
-     gtk_im_context_get_preedit_string(xic, &preedit_string, &attr_list, NULL);
- 
-     if (preedit_string != NULL && attr_list != NULL)
-     {
-       int idx;
- 
-       // Get the byte index as used by PangoAttrIterator
-       for (idx = 0; col > 0 && preedit_string[idx] != '\0'; --col)
-           idx += utfc_ptr2len((char_u *)preedit_string + idx);
- 
-       if (preedit_string[idx] != '\0')
-       {
-           PangoAttrIterator   *iter;
-           int                 start, end;
- 
-           char_attr = HL_NORMAL;
-           iter = pango_attr_list_get_iterator(attr_list);
- 
-           // Extract all relevant attributes from the list.
-           do
-           {
-               pango_attr_iterator_range(iter, &start, &end);
- 
-               if (idx >= start && idx < end)
-                   char_attr |= translate_pango_attributes(iter);
-           }
-           while (pango_attr_iterator_next(iter));
- 
-           pango_attr_iterator_destroy(iter);
-       }
-     }
- 
-     if (attr_list != NULL)
-       pango_attr_list_unref(attr_list);
-     g_free(preedit_string);
- 
-     return char_attr;
- }
- 
-     void
- xim_init(void)
- {
- #ifdef XIM_DEBUG
-     xim_log("xim_init()\n");
- #endif
- 
-     g_return_if_fail(gui.drawarea != NULL);
-     g_return_if_fail(gtk_widget_get_window(gui.drawarea) != NULL);
- 
-     xic = gtk_im_multicontext_new();
-     g_object_ref(xic);
- 
-     im_commit_handler_id = g_signal_connect(G_OBJECT(xic), "commit",
-                                           G_CALLBACK(&im_commit_cb), NULL);
-     g_signal_connect(G_OBJECT(xic), "preedit_changed",
-                    G_CALLBACK(&im_preedit_changed_cb), NULL);
-     g_signal_connect(G_OBJECT(xic), "preedit_start",
-                    G_CALLBACK(&im_preedit_start_cb), NULL);
-     g_signal_connect(G_OBJECT(xic), "preedit_end",
-                    G_CALLBACK(&im_preedit_end_cb), NULL);
- 
-     gtk_im_context_set_client_window(xic, 
gtk_widget_get_window(gui.drawarea));
- }
- 
-     void
- im_shutdown(void)
- {
- #ifdef XIM_DEBUG
-     xim_log("im_shutdown()\n");
- #endif
- 
-     if (xic != NULL)
-     {
-       gtk_im_context_focus_out(xic);
-       g_object_unref(xic);
-       xic = NULL;
-     }
-     im_is_active = FALSE;
-     im_commit_handler_id = 0;
-     if (p_imst == IM_ON_THE_SPOT)
-       preedit_start_col = MAXCOL;
-     xim_has_preediting = FALSE;
- }
- 
- /*
-  * Convert the string argument to keyval and state for GdkEventKey.
-  * If str is valid return TRUE, otherwise FALSE.
-  *
-  * See 'imactivatekey' for documentation of the format.
-  */
-     static int
- im_string_to_keyval(const char *str, unsigned int *keyval, unsigned int 
*state)
- {
-     const char            *mods_end;
-     unsigned      tmp_keyval;
-     unsigned      tmp_state = 0;
- 
-     mods_end = strrchr(str, '-');
-     mods_end = (mods_end != NULL) ? mods_end + 1 : str;
- 
-     // Parse modifier keys
-     while (str < mods_end)
-       switch (*str++)
-       {
-           case '-':                                                   break;
-           case 'S': case 's': tmp_state |= (unsigned)GDK_SHIFT_MASK;  break;
-           case 'L': case 'l': tmp_state |= (unsigned)GDK_LOCK_MASK;   break;
-           case 'C': case 'c': tmp_state |= (unsigned)GDK_CONTROL_MASK;break;
-           case '1':           tmp_state |= (unsigned)GDK_MOD1_MASK;   break;
-           case '2':           tmp_state |= (unsigned)GDK_MOD2_MASK;   break;
-           case '3':           tmp_state |= (unsigned)GDK_MOD3_MASK;   break;
-           case '4':           tmp_state |= (unsigned)GDK_MOD4_MASK;   break;
-           case '5':           tmp_state |= (unsigned)GDK_MOD5_MASK;   break;
-           default:
-               return FALSE;
-       }
- 
-     tmp_keyval = gdk_keyval_from_name(str);
- 
-     if (tmp_keyval == 0 || tmp_keyval == GDK_VoidSymbol)
-       return FALSE;
- 
-     if (keyval != NULL)
-       *keyval = tmp_keyval;
-     if (state != NULL)
-       *state = tmp_state;
- 
-     return TRUE;
- }
- 
- /*
-  * Return TRUE if p_imak is valid, otherwise FALSE.  As a special case, an
-  * empty string is also regarded as valid.
-  *
-  * Note: The numerical key value of p_imak is cached if it was valid; thus
-  * boldly assuming im_xim_isvalid_imactivate() will always be called whenever
-  * 'imak' changes.  This is currently the case but not obvious -- should
-  * probably rename the function for clarity.
-  */
-     int
- im_xim_isvalid_imactivate(void)
- {
-     if (p_imak[0] == NUL)
-     {
-       im_activatekey_keyval = GDK_VoidSymbol;
-       im_activatekey_state  = 0;
-       return TRUE;
-     }
- 
-     return im_string_to_keyval((const char *)p_imak,
-                              &im_activatekey_keyval,
-                              &im_activatekey_state);
- }
- 
-     static void
- im_synthesize_keypress(unsigned int keyval, unsigned int state)
- {
-     GdkEventKey *event;
- 
-     event = (GdkEventKey *)gdk_event_new(GDK_KEY_PRESS);
-     g_object_ref(gtk_widget_get_window(gui.drawarea));
-                                       // unreffed by gdk_event_free()
-     event->window = gtk_widget_get_window(gui.drawarea);
-     event->send_event = TRUE;
-     event->time = GDK_CURRENT_TIME;
-     event->state  = state;
-     event->keyval = keyval;
-     event->hardware_keycode = // needed for XIM
-       XKeysymToKeycode(GDK_WINDOW_XDISPLAY(event->window), (KeySym)keyval);
-     event->length = 0;
-     event->string = NULL;
- 
-     gtk_im_context_filter_keypress(xic, event);
- 
-     // For consistency, also send the corresponding release event.
-     event->type = GDK_KEY_RELEASE;
-     event->send_event = FALSE;
-     gtk_im_context_filter_keypress(xic, event);
- 
-     gdk_event_free((GdkEvent *)event);
- }
- 
-     void
- xim_reset(void)
- {
- # ifdef FEAT_EVAL
-     if (USE_IMACTIVATEFUNC)
-       call_imactivatefunc(im_is_active);
-     else
- # endif
-     if (xic != NULL)
-     {
-       gtk_im_context_reset(xic);
- 
-       if (p_imdisable)
-           im_shutdown();
-       else
-       {
-           xim_set_focus(gui.in_focus);
- 
-           if (im_activatekey_keyval != GDK_VoidSymbol)
-           {
-               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);
-               }
-           }
-           else
-           {
-               im_shutdown();
-               xim_init();
-               xim_set_focus(gui.in_focus);
-           }
-       }
-     }
- 
-     if (p_imst == IM_ON_THE_SPOT)
-       preedit_start_col = MAXCOL;
-     xim_has_preediting = FALSE;
- }
- 
-     int
- xim_queue_key_press_event(GdkEventKey *event, int down)
- {
-     if (down)
-     {
-       /*
-        * Workaround GTK2 XIM 'feature' that always converts keypad keys to
-        * chars., even when not part of an IM sequence (ref. feature of
-        * gdk/gdkkeyuni.c).
-        * Flag any keypad keys that might represent a single char.
-        * If this (on its own - i.e., not part of an IM sequence) is
-        * committed while we're processing one of these keys, we can ignore
-        * that commit and go ahead & process it ourselves.  That way we can
-        * still distinguish keypad keys for use in mappings.
-        * Also add GDK_space to make <S-Space> work.
-        */
-       switch (event->keyval)
-       {
-           case GDK_KP_Add:      xim_expected_char = '+';  break;
-           case GDK_KP_Subtract: xim_expected_char = '-';  break;
-           case GDK_KP_Divide:   xim_expected_char = '/';  break;
-           case GDK_KP_Multiply: xim_expected_char = '*';  break;
-           case GDK_KP_Decimal:  xim_expected_char = '.';  break;
-           case GDK_KP_Equal:    xim_expected_char = '=';  break;
-           case GDK_KP_0:        xim_expected_char = '0';  break;
-           case GDK_KP_1:        xim_expected_char = '1';  break;
-           case GDK_KP_2:        xim_expected_char = '2';  break;
-           case GDK_KP_3:        xim_expected_char = '3';  break;
-           case GDK_KP_4:        xim_expected_char = '4';  break;
-           case GDK_KP_5:        xim_expected_char = '5';  break;
-           case GDK_KP_6:        xim_expected_char = '6';  break;
-           case GDK_KP_7:        xim_expected_char = '7';  break;
-           case GDK_KP_8:        xim_expected_char = '8';  break;
-           case GDK_KP_9:        xim_expected_char = '9';  break;
-           case GDK_space:       xim_expected_char = ' ';  break;
-           default:              xim_expected_char = NUL;
-       }
-       xim_ignored_char = FALSE;
-     }
- 
-     /*
-      * When typing fFtT, XIM may be activated. Thus it must pass
-      * gtk_im_context_filter_keypress() in Normal mode.
-      * And while doing :sh too.
-      */
-     if (xic != NULL && !p_imdisable
-                   && (State & (INSERT | CMDLINE | NORMAL | EXTERNCMD)) != 0)
-     {
-       /*
-        * Filter 'imactivatekey' and map it to CTRL-^.  This way, Vim is
-        * always aware of the current status of IM, and can even emulate
-        * the activation key for modules that don't support one.
-        */
-       if (event->keyval == im_activatekey_keyval
-            && (event->state & im_activatekey_state) == im_activatekey_state)
-       {
-           unsigned int state_mask;
- 
-           // Require the state of the 3 most used modifiers to match exactly.
-           // Otherwise e.g. <S-C-space> would be unusable for other purposes
-           // if the IM activate key is <S-space>.
-           state_mask  = im_activatekey_state;
-           state_mask |= ((int)GDK_SHIFT_MASK | (int)GDK_CONTROL_MASK
-                                                       | (int)GDK_MOD1_MASK);
- 
-           if ((event->state & state_mask) != im_activatekey_state)
-               return FALSE;
- 
-           // Don't send it a second time on GDK_KEY_RELEASE.
-           if (event->type != GDK_KEY_PRESS)
-               return TRUE;
- 
-           if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE))
-           {
-               im_set_active(FALSE);
- 
-               // ":lmap" mappings exists, toggle use of mappings.
-               State ^= LANGMAP;
-               if (State & LANGMAP)
-               {
-                   curbuf->b_p_iminsert = B_IMODE_NONE;
-                   State &= ~LANGMAP;
-               }
-               else
-               {
-                   curbuf->b_p_iminsert = B_IMODE_LMAP;
-                   State |= LANGMAP;
-               }
-               return TRUE;
-           }
- 
-           return gtk_im_context_filter_keypress(xic, event);
-       }
- 
-       // Don't filter events through the IM context if IM isn't active
-       // right now.  Unlike with GTK+ 1.2 we cannot rely on the IM module
-       // not doing anything before the activation key was sent.
-       if (im_activatekey_keyval == GDK_VoidSymbol || im_is_active)
-       {
-           int imresult = gtk_im_context_filter_keypress(xic, event);
- 
-           if (p_imst == IM_ON_THE_SPOT)
-           {
-               // Some XIM send following sequence:
-               // 1. preedited string.
-               // 2. committed string.
-               // 3. line changed key.
-               // 4. preedited string.
-               // 5. remove preedited string.
-               // if 3, Vim can't move back the above line for 5.
-               // thus, this part should not parse the key.
-               if (!imresult && preedit_start_col != MAXCOL
-                                           && event->keyval == GDK_Return)
-               {
-                   im_synthesize_keypress(GDK_Return, 0U);
-                   return FALSE;
-               }
-           }
- 
-           // If XIM tried to commit a keypad key as a single char.,
-           // ignore it so we can use the keypad key 'raw', for mappings.
-           if (xim_expected_char != NUL && xim_ignored_char)
-               // We had a keypad key, and XIM tried to thieve it
-               return FALSE;
- 
-           // This is supposed to fix a problem with iBus, that space
-           // characters don't work in input mode.
-           xim_expected_char = NUL;
- 
-           // Normal processing
-           return imresult;
-       }
-     }
- 
-     return FALSE;
- }
- 
-     int
- im_get_status(void)
- {
- #  ifdef FEAT_EVAL
-     if (USE_IMSTATUSFUNC)
-       return call_imstatusfunc();
- #  endif
-     return im_is_active;
- }
- 
-     int
- preedit_get_status(void)
- {
-     return preedit_is_active;
- }
- 
-     int
- im_is_preediting(void)
- {
-     return xim_has_preediting;
- }
- 
- # else // !FEAT_GUI_GTK
- 
- static int    xim_is_active = FALSE;  // XIM should be active in the current
-                                       // mode
- static int    xim_has_focus = FALSE;  // XIM is really being used for Vim
- #  ifdef FEAT_GUI_X11
- static XIMStyle       input_style;
- static int    status_area_enabled = TRUE;
- #  endif
- 
- /*
-  * Switch using XIM on/off.  This is used by the code that changes "State".
-  * When 'imactivatefunc' is defined use that function instead.
-  */
-     void
- im_set_active(int active_arg)
- {
-     int active = active_arg;
- 
-     // If 'imdisable' is set, XIM is never active.
-     if (p_imdisable)
-       active = FALSE;
-     else if (input_style & XIMPreeditPosition)
-       // There is a problem in switching XIM off when preediting is used,
-       // and it is not clear how this can be solved.  For now, keep XIM on
-       // all the time, like it was done in Vim 5.8.
-       active = TRUE;
- 
- #  if defined(FEAT_EVAL)
-     if (USE_IMACTIVATEFUNC)
-     {
-       if (active != im_get_status())
-       {
-           call_imactivatefunc(active);
-           xim_has_focus = active;
-       }
-       return;
-     }
- #  endif
- 
-     if (xic == NULL)
-       return;
- 
-     // Remember the active state, it is needed when Vim gets keyboard focus.
-     xim_is_active = active;
-     xim_set_preedit();
- }
- 
- /*
-  * Adjust using XIM for gaining or losing keyboard focus.  Also called when
-  * "xim_is_active" changes.
-  */
-     void
- xim_set_focus(int focus)
- {
-     if (xic == NULL)
-       return;
- 
-     /*
-      * XIM only gets focus when the Vim window has keyboard focus and XIM has
-      * been set active for the current mode.
-      */
-     if (focus && xim_is_active)
-     {
-       if (!xim_has_focus)
-       {
-           xim_has_focus = TRUE;
-           XSetICFocus(xic);
-       }
-     }
-     else
-     {
-       if (xim_has_focus)
-       {
-           xim_has_focus = FALSE;
-           XUnsetICFocus(xic);
-       }
-     }
- }
- 
-     void
- im_set_position(int row UNUSED, int col UNUSED)
- {
-     xim_set_preedit();
- }
- 
- /*
-  * Set the XIM to the current cursor position.
-  */
-     void
- xim_set_preedit(void)
- {
-     XVaNestedList attr_list;
-     XRectangle spot_area;
-     XPoint over_spot;
-     int line_space;
- 
-     if (xic == NULL)
-       return;
- 
-     xim_set_focus(TRUE);
- 
-     if (!xim_has_focus)
-     {
-       // hide XIM cursor
-       over_spot.x = 0;
-       over_spot.y = -100; // arbitrary invisible position
-       attr_list = (XVaNestedList) XVaCreateNestedList(0,
-                                                       XNSpotLocation,
-                                                       &over_spot,
-                                                       NULL);
-       XSetICValues(xic, XNPreeditAttributes, attr_list, NULL);
-       XFree(attr_list);
-       return;
-     }
- 
-     if (input_style & XIMPreeditPosition)
-     {
-       if (xim_fg_color == INVALCOLOR)
-       {
-           xim_fg_color = gui.def_norm_pixel;
-           xim_bg_color = gui.def_back_pixel;
-       }
-       over_spot.x = TEXT_X(gui.col);
-       over_spot.y = TEXT_Y(gui.row);
-       spot_area.x = 0;
-       spot_area.y = 0;
-       spot_area.height = gui.char_height * Rows;
-       spot_area.width  = gui.char_width * Columns;
-       line_space = gui.char_height;
-       attr_list = (XVaNestedList) XVaCreateNestedList(0,
-                                       XNSpotLocation, &over_spot,
-                                       XNForeground, (Pixel) xim_fg_color,
-                                       XNBackground, (Pixel) xim_bg_color,
-                                       XNArea, &spot_area,
-                                       XNLineSpace, line_space,
-                                       NULL);
-       if (XSetICValues(xic, XNPreeditAttributes, attr_list, NULL))
-           emsg(_("E284: Cannot set IC values"));
-       XFree(attr_list);
-     }
- }
- 
- #  if defined(FEAT_GUI_X11)
- static char e_xim[] = N_("E285: Failed to create input context");
- #  endif
- 
- #  if defined(FEAT_GUI_X11) || defined(PROTO)
- #   if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && 
!defined(SUN_SYSTEM)
- #    define USE_X11R6_XIM
- #   endif
- 
- static int xim_real_init(Window x11_window, Display *x11_display);
- 
- 
- #  ifdef USE_X11R6_XIM
-     static void
- xim_instantiate_cb(
-     Display   *display,
-     XPointer  client_data UNUSED,
-     XPointer  call_data UNUSED)
- {
-     Window    x11_window;
-     Display   *x11_display;
- 
- #   ifdef XIM_DEBUG
-     xim_log("xim_instantiate_cb()\n");
- #   endif
- 
-     gui_get_x11_windis(&x11_window, &x11_display);
-     if (display != x11_display)
-       return;
- 
-     xim_real_init(x11_window, x11_display);
-     gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
-     if (xic != NULL)
-       XUnregisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
-                                        xim_instantiate_cb, NULL);
- }
- 
-     static void
- xim_destroy_cb(
-     XIM               im UNUSED,
-     XPointer  client_data UNUSED,
-     XPointer  call_data UNUSED)
- {
-     Window    x11_window;
-     Display   *x11_display;
- 
- #   ifdef XIM_DEBUG
-     xim_log("xim_destroy_cb()\n");
-    #endif
-     gui_get_x11_windis(&x11_window, &x11_display);
- 
-     xic = NULL;
-     status_area_enabled = FALSE;
- 
-     gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
- 
-     XRegisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
-                                  xim_instantiate_cb, NULL);
- }
- #  endif
- 
-     void
- xim_init(void)
- {
-     Window    x11_window;
-     Display   *x11_display;
- 
- #  ifdef XIM_DEBUG
-     xim_log("xim_init()\n");
- #  endif
- 
-     gui_get_x11_windis(&x11_window, &x11_display);
- 
-     xic = NULL;
- 
-     if (xim_real_init(x11_window, x11_display))
-       return;
- 
-     gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
- 
- #  ifdef USE_X11R6_XIM
-     XRegisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
-                                  xim_instantiate_cb, NULL);
- #  endif
- }
- 
-     static int
- xim_real_init(Window x11_window, Display *x11_display)
- {
-     int               i;
-     char      *p,
-               *s,
-               *ns,
-               *end,
-               tmp[1024];
- #  define IMLEN_MAX 40
-     char      buf[IMLEN_MAX + 7];
-     XIM               xim = NULL;
-     XIMStyles *xim_styles;
-     XIMStyle  this_input_style = 0;
-     Boolean   found;
-     XPoint    over_spot;
-     XVaNestedList preedit_list, status_list;
- 
-     input_style = 0;
-     status_area_enabled = FALSE;
- 
-     if (xic != NULL)
-       return FALSE;
- 
-     if (gui.rsrc_input_method != NULL && *gui.rsrc_input_method != NUL)
-     {
-       strcpy(tmp, gui.rsrc_input_method);
-       for (ns = s = tmp; ns != NULL && *s != NUL;)
-       {
-           s = (char *)skipwhite((char_u *)s);
-           if (*s == NUL)
-               break;
-           if ((ns = end = strchr(s, ',')) == NULL)
-               end = s + strlen(s);
-           while (isspace(((char_u *)end)[-1]))
-               end--;
-           *end = NUL;
- 
-           if (strlen(s) <= IMLEN_MAX)
-           {
-               strcpy(buf, "@im=");
-               strcat(buf, s);
-               if ((p = XSetLocaleModifiers(buf)) != NULL && *p != NUL
-                       && (xim = XOpenIM(x11_display, NULL, NULL, NULL))
-                                                                     != NULL)
-                   break;
-           }
- 
-           s = ns + 1;
-       }
-     }
- 
-     if (xim == NULL && (p = XSetLocaleModifiers("")) != NULL && *p != NUL)
-       xim = XOpenIM(x11_display, NULL, NULL, NULL);
- 
-     // This is supposed to be useful to obtain characters through
-     // XmbLookupString() without really using a XIM.
-     if (xim == NULL && (p = XSetLocaleModifiers("@im=none")) != NULL
-                                                                && *p != NUL)
-       xim = XOpenIM(x11_display, NULL, NULL, NULL);
- 
-     if (xim == NULL)
-     {
-       // Only give this message when verbose is set, because too many people
-       // got this message when they didn't want to use a XIM.
-       if (p_verbose > 0)
-       {
-           verbose_enter();
-           emsg(_("E286: Failed to open input method"));
-           verbose_leave();
-       }
-       return FALSE;
-     }
- 
- #  ifdef USE_X11R6_XIM
-     {
-       XIMCallback destroy_cb;
- 
-       destroy_cb.callback = xim_destroy_cb;
-       destroy_cb.client_data = NULL;
-       if (XSetIMValues(xim, XNDestroyCallback, &destroy_cb, NULL))
-           emsg(_("E287: Warning: Could not set destroy callback to IM"));
-     }
- #  endif
- 
-     if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL) || 
!xim_styles)
-     {
-       emsg(_("E288: input method doesn't support any style"));
-       XCloseIM(xim);
-       return FALSE;
-     }
- 
-     found = False;
-     strcpy(tmp, gui.rsrc_preedit_type_name);
-     for (s = tmp; s && !found; )
-     {
-       while (*s && isspace((unsigned char)*s))
-           s++;
-       if (!*s)
-           break;
-       if ((ns = end = strchr(s, ',')) != 0)
-           ns++;
-       else
-           end = s + strlen(s);
-       while (isspace((unsigned char)*end))
-           end--;
-       *end = '\0';
- 
-       if (!strcmp(s, "OverTheSpot"))
-           this_input_style = (XIMPreeditPosition | XIMStatusArea);
-       else if (!strcmp(s, "OffTheSpot"))
-           this_input_style = (XIMPreeditArea | XIMStatusArea);
-       else if (!strcmp(s, "Root"))
-           this_input_style = (XIMPreeditNothing | XIMStatusNothing);
- 
-       for (i = 0; (unsigned short)i < xim_styles->count_styles; i++)
-       {
-           if (this_input_style == xim_styles->supported_styles[i])
-           {
-               found = True;
-               break;
-           }
-       }
-       if (!found)
-           for (i = 0; (unsigned short)i < xim_styles->count_styles; i++)
-           {
-               if ((xim_styles->supported_styles[i] & this_input_style)
-                       == (this_input_style & ~XIMStatusArea))
-               {
-                   this_input_style &= ~XIMStatusArea;
-                   found = True;
-                   break;
-               }
-           }
- 
-       s = ns;
-     }
-     XFree(xim_styles);
- 
-     if (!found)
-     {
-       // Only give this message when verbose is set, because too many people
-       // got this message when they didn't want to use a XIM.
-       if (p_verbose > 0)
-       {
-           verbose_enter();
-           emsg(_("E289: input method doesn't support my preedit type"));
-           verbose_leave();
-       }
-       XCloseIM(xim);
-       return FALSE;
-     }
- 
-     over_spot.x = TEXT_X(gui.col);
-     over_spot.y = TEXT_Y(gui.row);
-     input_style = this_input_style;
- 
-     // A crash was reported when trying to pass gui.norm_font as XNFontSet,
-     // thus that has been removed.  Hopefully the default works...
- #  ifdef FEAT_XFONTSET
-     if (gui.fontset != NOFONTSET)
-     {
-       preedit_list = XVaCreateNestedList(0,
-                               XNSpotLocation, &over_spot,
-                               XNForeground, (Pixel)gui.def_norm_pixel,
-                               XNBackground, (Pixel)gui.def_back_pixel,
-                               XNFontSet, (XFontSet)gui.fontset,
-                               NULL);
-       status_list = XVaCreateNestedList(0,
-                               XNForeground, (Pixel)gui.def_norm_pixel,
-                               XNBackground, (Pixel)gui.def_back_pixel,
-                               XNFontSet, (XFontSet)gui.fontset,
-                               NULL);
-     }
-     else
- #  endif
-     {
-       preedit_list = XVaCreateNestedList(0,
-                               XNSpotLocation, &over_spot,
-                               XNForeground, (Pixel)gui.def_norm_pixel,
-                               XNBackground, (Pixel)gui.def_back_pixel,
-                               NULL);
-       status_list = XVaCreateNestedList(0,
-                               XNForeground, (Pixel)gui.def_norm_pixel,
-                               XNBackground, (Pixel)gui.def_back_pixel,
-                               NULL);
-     }
- 
-     xic = XCreateIC(xim,
-                   XNInputStyle, input_style,
-                   XNClientWindow, x11_window,
-                   XNFocusWindow, gui.wid,
-                   XNPreeditAttributes, preedit_list,
-                   XNStatusAttributes, status_list,
-                   NULL);
-     XFree(status_list);
-     XFree(preedit_list);
-     if (xic != NULL)
-     {
-       if (input_style & XIMStatusArea)
-       {
-           xim_set_status_area();
-           status_area_enabled = TRUE;
-       }
-       else
-           gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
-     }
-     else
-     {
-       if (!is_not_a_term())
-           emsg(_(e_xim));
-       XCloseIM(xim);
-       return FALSE;
-     }
- 
-     return TRUE;
- }
- 
- #  endif // FEAT_GUI_X11
- 
- /*
-  * Get IM status.  When IM is on, return TRUE.  Else return FALSE.
-  * FIXME: This doesn't work correctly: Having focus doesn't always mean XIM is
-  * active, when not having focus XIM may still be active (e.g., when using a
-  * tear-off menu item).
-  */
-     int
- im_get_status(void)
- {
- #  ifdef FEAT_EVAL
-     if (USE_IMSTATUSFUNC)
-       return call_imstatusfunc();
- #  endif
-     return xim_has_focus;
- }
- 
- # endif // !FEAT_GUI_GTK
- 
- # if !defined(FEAT_GUI_GTK) || defined(PROTO)
- /*
-  * Set up the status area.
-  *
-  * This should use a separate Widget, but that seems not possible, because
-  * preedit_area and status_area should be set to the same window as for the
-  * text input.  Unfortunately this means the status area pollutes the text
-  * window...
-  */
-     void
- xim_set_status_area(void)
- {
-     XVaNestedList preedit_list = 0, status_list = 0, list = 0;
-     XRectangle pre_area, status_area;
- 
-     if (xic == NULL)
-       return;
- 
-     if (input_style & XIMStatusArea)
-     {
-       if (input_style & XIMPreeditArea)
-       {
-           XRectangle *needed_rect;
- 
-           // to get status_area width
-           status_list = XVaCreateNestedList(0, XNAreaNeeded,
-                                             &needed_rect, NULL);
-           XGetICValues(xic, XNStatusAttributes, status_list, NULL);
-           XFree(status_list);
- 
-           status_area.width = needed_rect->width;
-       }
-       else
-           status_area.width = gui.char_width * Columns;
- 
-       status_area.x = 0;
-       status_area.y = gui.char_height * Rows + gui.border_offset;
-       if (gui.which_scrollbars[SBAR_BOTTOM])
-           status_area.y += gui.scrollbar_height;
- #ifdef FEAT_MENU
-       if (gui.menu_is_active)
-           status_area.y += gui.menu_height;
- #endif
-       status_area.height = gui.char_height;
-       status_list = XVaCreateNestedList(0, XNArea, &status_area, NULL);
-     }
-     else
-     {
-       status_area.x = 0;
-       status_area.y = gui.char_height * Rows + gui.border_offset;
-       if (gui.which_scrollbars[SBAR_BOTTOM])
-           status_area.y += gui.scrollbar_height;
- #ifdef FEAT_MENU
-       if (gui.menu_is_active)
-           status_area.y += gui.menu_height;
- #endif
-       status_area.width = 0;
-       status_area.height = gui.char_height;
-     }
- 
-     if (input_style & XIMPreeditArea)   // off-the-spot
-     {
-       pre_area.x = status_area.x + status_area.width;
-       pre_area.y = gui.char_height * Rows + gui.border_offset;
-       pre_area.width = gui.char_width * Columns - pre_area.x;
-       if (gui.which_scrollbars[SBAR_BOTTOM])
-           pre_area.y += gui.scrollbar_height;
- #ifdef FEAT_MENU
-       if (gui.menu_is_active)
-           pre_area.y += gui.menu_height;
- #endif
-       pre_area.height = gui.char_height;
-       preedit_list = XVaCreateNestedList(0, XNArea, &pre_area, NULL);
-     }
-     else if (input_style & XIMPreeditPosition)   // over-the-spot
-     {
-       pre_area.x = 0;
-       pre_area.y = 0;
-       pre_area.height = gui.char_height * Rows;
-       pre_area.width = gui.char_width * Columns;
-       preedit_list = XVaCreateNestedList(0, XNArea, &pre_area, NULL);
-     }
- 
-     if (preedit_list && status_list)
-       list = XVaCreateNestedList(0, XNPreeditAttributes, preedit_list,
-                                  XNStatusAttributes, status_list, NULL);
-     else if (preedit_list)
-       list = XVaCreateNestedList(0, XNPreeditAttributes, preedit_list,
-                                  NULL);
-     else if (status_list)
-       list = XVaCreateNestedList(0, XNStatusAttributes, status_list,
-                                  NULL);
-     else
-       list = NULL;
- 
-     if (list)
-     {
-       XSetICValues(xic, XNVaNestedList, list, NULL);
-       XFree(list);
-     }
-     if (status_list)
-       XFree(status_list);
-     if (preedit_list)
-       XFree(preedit_list);
- }
- 
-     int
- xim_get_status_area_height(void)
- {
-     if (status_area_enabled)
-       return gui.char_height;
-     return 0;
- }
- # endif
- 
- #else // !defined(FEAT_XIM)
- 
- # if defined(IME_WITHOUT_XIM) || defined(VIMDLL)
- static int im_was_set_active = FALSE;
- 
-     int
- #  ifdef VIMDLL
- mbyte_im_get_status(void)
- #  else
- im_get_status(void)
- #  endif
- {
- #  if defined(FEAT_EVAL)
-     if (USE_IMSTATUSFUNC)
-       return call_imstatusfunc();
- #  endif
-     return im_was_set_active;
- }
- 
-     void
- #  ifdef VIMDLL
- mbyte_im_set_active(int active_arg)
- #  else
- im_set_active(int active_arg)
- #  endif
- {
- #  if defined(FEAT_EVAL)
-     int           active = !p_imdisable && active_arg;
- 
-     if (USE_IMACTIVATEFUNC && active != im_get_status())
-     {
-       call_imactivatefunc(active);
-       im_was_set_active = active;
-     }
- #  endif
- }
- 
- #  if defined(FEAT_GUI) && !defined(FEAT_GUI_HAIKU) && !defined(VIMDLL)
-     void
- im_set_position(int row UNUSED, int col UNUSED)
- {
- }
- #  endif
- # endif
- 
- #endif // FEAT_XIM
- 
  #if defined(FEAT_EVAL) || defined(PROTO)
  /*
   * "getimstatus()" function
--- 4734,4739 ----
*** ../vim-8.2.0871/src/proto.h 2020-05-30 18:14:37.828521058 +0200
--- src/proto.h 2020-06-01 14:18:57.758948897 +0200
***************
*** 92,97 ****
--- 92,98 ----
  # include "findfile.pro"
  # include "fold.pro"
  # include "getchar.pro"
+ # include "gui_xim.pro"
  # include "hardcopy.pro"
  # include "hashtab.pro"
  # include "highlight.pro"
*** ../vim-8.2.0871/src/proto/gui_xim.pro       2020-06-01 14:33:33.411649297 
+0200
--- src/proto/gui_xim.pro       2020-06-01 14:18:57.758948897 +0200
***************
*** 0 ****
--- 1,17 ----
+ /* gui_xim.c */
+ void im_set_active(int active);
+ void xim_set_focus(int focus);
+ void im_set_position(int row, int col);
+ void xim_set_preedit(void);
+ int im_get_feedback_attr(int col);
+ void xim_init(void);
+ void im_shutdown(void);
+ int im_xim_isvalid_imactivate(void);
+ void xim_reset(void);
+ int xim_queue_key_press_event(GdkEventKey *event, int down);
+ int im_get_status(void);
+ int preedit_get_status(void);
+ int im_is_preediting(void);
+ void xim_set_status_area(void);
+ int xim_get_status_area_height(void);
+ /* vim: set ft=c : */
*** ../vim-8.2.0871/src/proto/mbyte.pro 2019-12-12 12:55:26.000000000 +0100
--- src/proto/mbyte.pro 2020-06-01 14:18:57.758948897 +0200
***************
*** 74,94 ****
  void *my_iconv_open(char_u *to, char_u *from);
  int iconv_enabled(int verbose);
  void iconv_end(void);
- void im_set_active(int active);
- void xim_set_focus(int focus);
- void im_set_position(int row, int col);
- void xim_set_preedit(void);
- int im_get_feedback_attr(int col);
- void xim_init(void);
- void im_shutdown(void);
- int im_xim_isvalid_imactivate(void);
- void xim_reset(void);
- int xim_queue_key_press_event(GdkEventKey *event, int down);
- int im_get_status(void);
- int preedit_get_status(void);
- int im_is_preediting(void);
- void xim_set_status_area(void);
- int xim_get_status_area_height(void);
  void f_getimstatus(typval_T *argvars, typval_T *rettv);
  int convert_setup(vimconv_T *vcp, char_u *from, char_u *to);
  int convert_setup_ext(vimconv_T *vcp, char_u *from, int from_unicode_is_utf8, 
char_u *to, int to_unicode_is_utf8);
--- 74,79 ----
*** ../vim-8.2.0871/src/version.c       2020-06-01 14:14:40.691899742 +0200
--- src/version.c       2020-06-01 14:20:12.406676209 +0200
***************
*** 748,749 ****
--- 748,751 ----
  {   /* Add new patch number below this line */
+ /**/
+     872,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
242. You turn down a better-paying job because it doesn't come with
     a free e-mail account.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202006011235.051CZ7td905772%40masaka.moolenaar.net.

Raspunde prin e-mail lui