patch 8.0.1026: GTK on-the-spot input has problems

Problem:    GTK on-the-spot input has problems. (Gerd Wachsmuth)
Solution:   Support over-the-spot. (Yukihiro Nakadaira, Ketn Takata, closes
            #1215)
This commit is contained in:
Bram Moolenaar
2017-08-30 22:00:20 +02:00
parent 4e83961985
commit 5c6dbcb03f
12 changed files with 303 additions and 118 deletions

View File

@@ -832,6 +832,9 @@ Use the RPM or port for your system.
Currently, GUI Vim supports three styles, |OverTheSpot|, |OffTheSpot| and Currently, GUI Vim supports three styles, |OverTheSpot|, |OffTheSpot| and
|Root|. |Root|.
When compiled with |+GUI_GTK| feature, GUI Vim supports two styles,
|OnTheSpot| and |OverTheSpot|. You can select the style with the 'imstyle'
option.
*. on-the-spot *OnTheSpot* *. on-the-spot *OnTheSpot*
Preedit Area and Status Area are performed by the client application in Preedit Area and Status Area are performed by the client application in

View File

@@ -4356,6 +4356,23 @@ A jump table for the options with a short description can be found at |Q_op|.
< <
NOTE: This function is invoked very often. Keep it fast. NOTE: This function is invoked very often. Keep it fast.
*'imstyle'* *'imst'*
'imstyle' 'imst' number (default 1)
global
{not in Vi}
{only available when compiled with |+xim| and
|+GUI_GTK|}
This option specifies the input style of Input Method.
Set to zero if you want to use on-the-spot style.
Set to one if you want to use over-the-spot style.
See: |xim-input-style|
For a long time on-the-spot sytle had been used in GTK version of vim,
however, it is known that it causes troubles when using mappings,
|single-repeat|, etc. Therefore over-the-spot style becomes the
default now. This should work fine for most people, however if you
have any problem with it, try using on-the-spot style.
*'include'* *'inc'* *'include'* *'inc'*
'include' 'inc' string (default "^\s*#\s*include") 'include' 'inc' string (default "^\s*#\s*include")
global or local to buffer |global-local| global or local to buffer |global-local|

View File

@@ -9683,7 +9683,7 @@ ins_left(
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
/* Only call start_arrow() when not busy with preediting, it will /* Only call start_arrow() when not busy with preediting, it will
* break undo. K_LEFT is inserted in im_correct_cursor(). */ * break undo. K_LEFT is inserted in im_correct_cursor(). */
if (!im_is_preediting()) if (p_imst == IM_OVER_THE_SPOT || !im_is_preediting())
#endif #endif
{ {
start_arrow_with_change(&tpos, end_change); start_arrow_with_change(&tpos, end_change);

View File

@@ -3468,7 +3468,8 @@ cursorcmd(void)
windgoto(msg_row, msg_col); windgoto(msg_row, msg_col);
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
redrawcmd_preedit(); if (p_imst == IM_ON_THE_SPOT)
redrawcmd_preedit();
#endif #endif
#ifdef MCH_CURSOR_SHAPE #ifdef MCH_CURSOR_SHAPE
mch_update_cursor(); mch_update_cursor();

View File

@@ -4788,6 +4788,11 @@ static unsigned long im_commit_handler_id = 0;
static unsigned int im_activatekey_keyval = GDK_VoidSymbol; static unsigned int im_activatekey_keyval = GDK_VoidSymbol;
static unsigned int im_activatekey_state = 0; 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 void
im_set_active(int active) im_set_active(int active)
{ {
@@ -4825,6 +4830,9 @@ im_set_position(int row, int col)
area.height = gui.char_height; area.height = gui.char_height;
gtk_im_context_set_cursor_location(xic, &area); gtk_im_context_set_cursor_location(xic, &area);
if (p_imst == IM_OVER_THE_SPOT)
im_preedit_window_set_position();
} }
} }
@@ -4851,6 +4859,95 @@ im_add_to_input(char_u *str, int len)
if (input_conv.vc_type != CONV_NONE) if (input_conv.vc_type != CONV_NONE)
vim_free(str); 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, w, h, sw, sh;
if (preedit_window == NULL)
return;
sw = gdk_screen_get_width(gtk_widget_get_screen(preedit_window));
sh = gdk_screen_get_height(gtk_widget_get_screen(preedit_window));
#if GTK_CHECK_VERSION(3,0,0)
gdk_window_get_origin(gtk_widget_get_window(gui.drawarea), &x, &y);
#else
gdk_window_get_origin(gui.drawarea->window, &x, &y);
#endif
gtk_window_get_size(GTK_WINDOW(preedit_window), &w, &h);
x = x + FILL_X(gui.col);
y = y + FILL_Y(gui.row);
if (x + w > sw)
x = sw - w;
if (y + h > sh)
y = sh - h;
gtk_window_move(GTK_WINDOW(preedit_window), x, y);
}
static void
im_preedit_window_open()
{
char *preedit_string;
char buf[8];
PangoAttrList *attr_list;
PangoLayout *layout;
GdkColor color;
gint w, h;
if (preedit_window == NULL)
{
preedit_window = gtk_window_new(GTK_WINDOW_POPUP);
preedit_label = gtk_label_new("");
gtk_container_add(GTK_CONTAINER(preedit_window), preedit_label);
}
gtk_widget_modify_font(preedit_label, gui.norm_font);
vim_snprintf(buf, sizeof(buf), "#%06X", gui.norm_pixel);
gdk_color_parse(buf, &color);
gtk_widget_modify_fg(preedit_label, GTK_STATE_NORMAL, &color);
vim_snprintf(buf, sizeof(buf), "#%06X", gui.back_pixel);
gdk_color_parse(buf, &color);
gtk_widget_modify_bg(preedit_window, GTK_STATE_NORMAL, &color);
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 */ if (p_mh) /* blank out the pointer if necessary */
gui_mch_mousehide(TRUE); gui_mch_mousehide(TRUE);
} }
@@ -4861,6 +4958,12 @@ im_delete_preedit(void)
char_u bskey[] = {CSI, 'k', 'b'}; char_u bskey[] = {CSI, 'k', 'b'};
char_u delkey[] = {CSI, 'k', 'D'}; char_u delkey[] = {CSI, 'k', 'D'};
if (p_imst == IM_OVER_THE_SPOT)
{
im_preedit_window_close();
return;
}
if (State & NORMAL) if (State & NORMAL)
{ {
im_preedit_cursor = 0; im_preedit_cursor = 0;
@@ -4933,40 +5036,43 @@ im_commit_cb(GtkIMContext *context UNUSED,
xim_log("im_commit_cb(): %s\n", str); xim_log("im_commit_cb(): %s\n", str);
#endif #endif
/* The imhangul module doesn't reset the preedit string before if (p_imst == IM_ON_THE_SPOT)
* 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(); /* The imhangul module doesn't reset the preedit string before
commit_with_preedit = FALSE; * 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;
} }
/* 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 /* 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 * 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 * us carry on processing the raw keycode so that it may be used in
@@ -4990,14 +5096,17 @@ im_commit_cb(GtkIMContext *context UNUSED,
if (add_to_input) if (add_to_input)
im_add_to_input((char_u *)str, slen); im_add_to_input((char_u *)str, slen);
/* Inserting chars while "im_is_active" is set does not cause a change of if (p_imst == IM_ON_THE_SPOT)
* buffer. When the chars are committed the buffer must be marked as {
* changed. */ /* Inserting chars while "im_is_active" is set does not cause a
if (!commit_with_preedit) * change of buffer. When the chars are committed the buffer must be
preedit_start_col = MAXCOL; * marked as changed. */
if (!commit_with_preedit)
preedit_start_col = MAXCOL;
/* This flag is used in changed() at next call. */ /* This flag is used in changed() at next call. */
xim_changed_while_preediting = TRUE; xim_changed_while_preediting = TRUE;
}
if (gtk_main_level() > 0) if (gtk_main_level() > 0)
gtk_main_quit(); gtk_main_quit();
@@ -5031,7 +5140,8 @@ im_preedit_end_cb(GtkIMContext *context UNUSED, gpointer data UNUSED)
im_delete_preedit(); im_delete_preedit();
/* Indicate that preediting has finished */ /* Indicate that preediting has finished */
preedit_start_col = MAXCOL; if (p_imst == IM_ON_THE_SPOT)
preedit_start_col = MAXCOL;
xim_has_preediting = FALSE; xim_has_preediting = FALSE;
#if 0 #if 0
@@ -5092,9 +5202,14 @@ im_preedit_changed_cb(GtkIMContext *context, gpointer data UNUSED)
char_u *p; char_u *p;
int i; int i;
gtk_im_context_get_preedit_string(context, if (p_imst == IM_ON_THE_SPOT)
&preedit_string, NULL, gtk_im_context_get_preedit_string(context,
&cursor_index); &preedit_string, NULL,
&cursor_index);
else
gtk_im_context_get_preedit_string(context,
&preedit_string, NULL,
NULL);
#ifdef XIM_DEBUG #ifdef XIM_DEBUG
xim_log("im_preedit_changed_cb(): %s\n", preedit_string); xim_log("im_preedit_changed_cb(): %s\n", preedit_string);
@@ -5102,66 +5217,82 @@ im_preedit_changed_cb(GtkIMContext *context, gpointer data UNUSED)
g_return_if_fail(preedit_string != NULL); /* just in case */ g_return_if_fail(preedit_string != NULL); /* just in case */
/* If preedit_start_col is MAXCOL set it to the current cursor position. */ if (p_imst == IM_OVER_THE_SPOT)
if (preedit_start_col == MAXCOL && preedit_string[0] != '\0')
{ {
xim_has_preediting = TRUE; if (preedit_string[0] == NUL)
{
/* Urgh, this breaks if the input buffer isn't empty now */ xim_has_preediting = FALSE;
init_preedit_start_col(); im_delete_preedit();
}
else
{
xim_has_preediting = TRUE;
im_show_preedit();
}
} }
else if (cursor_index == 0 && preedit_string[0] == '\0') else
{ {
xim_has_preediting = FALSE; /* 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;
/* If at the start position (after typing backspace) /* Urgh, this breaks if the input buffer isn't empty now */
* preedit_start_col must be reset. */ init_preedit_start_col();
preedit_start_col = MAXCOL; }
} else if (cursor_index == 0 && preedit_string[0] == '\0')
{
xim_has_preediting = FALSE;
im_delete_preedit(); /* 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> * Compute the end of the preediting area: "preedit_end_col".
* to delete the preedit string. So don't count composing characters * According to the documentation of gtk_im_context_get_preedit_string(),
* unless 'delcombine' is enabled. * 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 (!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) if (preedit_start_col != MAXCOL)
preedit_end_col += utf_ptr2cells(p); 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;
if (p > str) is_composing = ((*p & 0x80) != 0 && utf_iscomposing(utf_ptr2char(p)));
{ /*
im_add_to_input(str, (int)(p - str)); * These offsets are used as counters when generating <BS> and <Del>
im_correct_cursor(num_move_back); * 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); g_free(preedit_string);
@@ -5310,7 +5441,8 @@ im_shutdown(void)
} }
im_is_active = FALSE; im_is_active = FALSE;
im_commit_handler_id = 0; im_commit_handler_id = 0;
preedit_start_col = MAXCOL; if (p_imst == IM_ON_THE_SPOT)
preedit_start_col = MAXCOL;
xim_has_preediting = FALSE; xim_has_preediting = FALSE;
} }
@@ -5465,7 +5597,8 @@ xim_reset(void)
} }
} }
preedit_start_col = MAXCOL; if (p_imst == IM_ON_THE_SPOT)
preedit_start_col = MAXCOL;
xim_has_preediting = FALSE; xim_has_preediting = FALSE;
} }
@@ -5570,19 +5703,22 @@ xim_queue_key_press_event(GdkEventKey *event, int down)
{ {
int imresult = gtk_im_context_filter_keypress(xic, event); int imresult = gtk_im_context_filter_keypress(xic, event);
/* Some XIM send following sequence: if (p_imst == IM_ON_THE_SPOT)
* 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); /* Some XIM send following sequence:
return FALSE; * 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., /* If XIM tried to commit a keypad key as a single char.,

View File

@@ -2730,12 +2730,15 @@ skip_to_option_part(char_u *p)
changed(void) changed(void)
{ {
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
/* The text of the preediting area is inserted, but this doesn't if (p_imst == IM_ON_THE_SPOT)
* mean a change of the buffer yet. That is delayed until the {
* text is committed. (this means preedit becomes empty) */ /* The text of the preediting area is inserted, but this doesn't
if (im_is_preediting() && !xim_changed_while_preediting) * mean a change of the buffer yet. That is delayed until the
return; * text is committed. (this means preedit becomes empty) */
xim_changed_while_preediting = FALSE; if (im_is_preediting() && !xim_changed_while_preediting)
return;
xim_changed_while_preediting = FALSE;
}
#endif #endif
if (!curbuf->b_changed) if (!curbuf->b_changed)

View File

@@ -1606,13 +1606,22 @@ static struct vimoption options[] =
#endif #endif
SCRIPTID_INIT}, SCRIPTID_INIT},
{"imstatusfunc","imsf",P_STRING|P_VI_DEF|P_SECURE, {"imstatusfunc","imsf",P_STRING|P_VI_DEF|P_SECURE,
# if defined(FEAT_EVAL) && defined(FEAT_XIM) && defined(FEAT_GUI_GTK) #if defined(FEAT_EVAL) && defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
(char_u *)&p_imsf, PV_NONE, (char_u *)&p_imsf, PV_NONE,
{(char_u *)"", (char_u *)NULL} {(char_u *)"", (char_u *)NULL}
# else #else
(char_u *)NULL, PV_NONE, (char_u *)NULL, PV_NONE,
{(char_u *)NULL, (char_u *)0L} {(char_u *)NULL, (char_u *)0L}
# endif #endif
SCRIPTID_INIT},
{"imstyle", "imst", P_NUM|P_VI_DEF|P_SECURE,
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
(char_u *)&p_imst, PV_NONE,
{(char_u *)IM_OVER_THE_SPOT, (char_u *)0L}
#else
(char_u *)NULL, PV_NONE,
{(char_u *)0L, (char_u *)0L}
#endif
SCRIPTID_INIT}, SCRIPTID_INIT},
{"include", "inc", P_STRING|P_ALLOCED|P_VI_DEF, {"include", "inc", P_STRING|P_ALLOCED|P_VI_DEF,
#ifdef FEAT_FIND_ID #ifdef FEAT_FIND_ID
@@ -8990,6 +8999,15 @@ set_num_option(
#endif #endif
} }
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
/* 'imstyle' */
else if (pp == &p_imst)
{
if (p_imst != IM_ON_THE_SPOT && p_imst != IM_OVER_THE_SPOT)
errmsg = e_invarg;
}
#endif
else if (pp == &p_window) else if (pp == &p_window)
{ {
if (p_window < 1) if (p_window < 1)

View File

@@ -581,6 +581,9 @@ EXTERN int p_ic; /* 'ignorecase' */
EXTERN char_u *p_imak; /* 'imactivatekey' */ EXTERN char_u *p_imak; /* 'imactivatekey' */
EXTERN char_u *p_imaf; /* 'imactivatefunc' */ EXTERN char_u *p_imaf; /* 'imactivatefunc' */
EXTERN char_u *p_imsf; /* 'imstatusfunc' */ EXTERN char_u *p_imsf; /* 'imstatusfunc' */
EXTERN long p_imst; /* 'imstyle' */
# define IM_ON_THE_SPOT 0L
# define IM_OVER_THE_SPOT 1L
#endif #endif
#ifdef USE_IM_CONTROL #ifdef USE_IM_CONTROL
EXTERN int p_imcmdline; /* 'imcmdline' */ EXTERN int p_imcmdline; /* 'imcmdline' */

View File

@@ -5197,7 +5197,8 @@ win_line(
/* XIM don't send preedit_start and preedit_end, but they send /* XIM don't send preedit_start and preedit_end, but they send
* preedit_changed and commit. Thus Vim can't set "im_is_active", use * preedit_changed and commit. Thus Vim can't set "im_is_active", use
* im_is_preediting() here. */ * im_is_preediting() here. */
if (xic != NULL if (p_imst == IM_ON_THE_SPOT
&& xic != NULL
&& lnum == wp->w_cursor.lnum && lnum == wp->w_cursor.lnum
&& (State & INSERT) && (State & INSERT)
&& !p_imdisable && !p_imdisable

View File

@@ -31,6 +31,7 @@ let test_values = {
\ 'history': [[0, 1, 100], [-1, 10001]], \ 'history': [[0, 1, 100], [-1, 10001]],
\ 'iminsert': [[0, 1], [-1, 3, 999]], \ 'iminsert': [[0, 1], [-1, 3, 999]],
\ 'imsearch': [[-1, 0, 1], [-2, 3, 999]], \ 'imsearch': [[-1, 0, 1], [-2, 3, 999]],
\ 'imstyle': [[0, 1], [-1, 2, 999]],
\ 'lines': [[2, 24], [-1, 0, 1]], \ 'lines': [[2, 24], [-1, 0, 1]],
\ 'linespace': [[0, 2, 4], ['']], \ 'linespace': [[0, 2, 4], ['']],
\ 'numberwidth': [[1, 4, 8, 10], [-1, 0, 11]], \ 'numberwidth': [[1, 4, 8, 10], [-1, 0, 11]],

View File

@@ -2984,7 +2984,7 @@ u_sync(
if (curbuf->b_u_synced || (!force && no_u_sync > 0)) if (curbuf->b_u_synced || (!force && no_u_sync > 0))
return; return;
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
if (im_is_preediting()) if (p_imst == IM_ON_THE_SPOT && im_is_preediting())
return; /* XIM is busy, don't break an undo sequence */ return; /* XIM is busy, don't break an undo sequence */
#endif #endif
if (get_undolevel() < 0) if (get_undolevel() < 0)

View File

@@ -769,6 +769,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1026,
/**/ /**/
1025, 1025,
/**/ /**/