root/src/textconv.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. copy_buffer
  2. get_mark
  3. select_window
  4. textconv_query
  5. sync_overlay
  6. record_buffer_change
  7. reset_frame_state
  8. detect_conversion_events
  9. restore_selected_window
  10. really_commit_text
  11. really_finish_composing_text
  12. really_set_composing_text
  13. really_set_composing_region
  14. really_delete_surrounding_text
  15. really_request_point_update
  16. really_set_point_and_mark
  17. complete_edit
  18. complete_edit_check
  19. handle_pending_conversion_events_1
  20. decrement_inside
  21. handle_pending_conversion_events
  22. start_batch_edit
  23. end_batch_edit
  24. commit_text
  25. finish_composing_text
  26. set_composing_text
  27. set_composing_region
  28. textconv_set_point_and_mark
  29. delete_surrounding_text
  30. request_point_update
  31. textconv_barrier
  32. get_extracted_text
  33. get_surrounding_text
  34. conversion_disabled_p
  35. report_selected_window_change
  36. report_point_change
  37. disable_text_conversion
  38. resume_text_conversion
  39. register_textconv_interface
  40. check_postponed_buffers
  41. syms_of_textconv

     1 /* String conversion support for graphics terminals.
     2 
     3 Copyright (C) 2023 Free Software Foundation, Inc.
     4 
     5 This file is part of GNU Emacs.
     6 
     7 GNU Emacs is free software: you can redistribute it and/or modify
     8 it under the terms of the GNU General Public License as published by
     9 the Free Software Foundation, either version 3 of the License, or (at
    10 your option) any later version.
    11 
    12 GNU Emacs is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    19 
    20 /* String conversion support.
    21 
    22    Many input methods require access to text surrounding the cursor.
    23    They may then request that the text editor remove or substitute
    24    that text for something else, for example when providing the
    25    ability to ``undo'' or ``edit'' previously composed text.  This is
    26    most commonly seen in input methods for CJK laguages for X Windows,
    27    and is extensively used throughout Android by input methods for all
    28    kinds of scripts.
    29 
    30    In addition, these input methods may also need to make detailed
    31    edits to the content of a buffer.  That is also handled here.  */
    32 
    33 #include <config.h>
    34 
    35 #include "textconv.h"
    36 #include "buffer.h"
    37 #include "syntax.h"
    38 #include "blockinput.h"
    39 #include "keyboard.h"
    40 
    41 
    42 
    43 /* Define debugging macros.  */
    44 
    45 #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
    46 #if 0
    47 #include <android/log.h>
    48 
    49 #define TEXTCONV_DEBUG(fmt, ...)                                        \
    50   __android_log_print (ANDROID_LOG_VERBOSE, "EmacsInputConnection",     \
    51                        "%s: " fmt, __func__, ## __VA_ARGS__)
    52 #endif /* 0 */
    53 #endif /* defined HAVE_ANDROID && !defined ANDROID_STUBIFY */
    54 
    55 #ifndef TEXTCONV_DEBUG
    56 #define TEXTCONV_DEBUG(...) ((void) 0)
    57 #endif /* TEXTCONV_DEBUG */
    58 
    59 
    60 
    61 /* The window system's text conversion interface.  NULL when the
    62    window system has not set up text conversion.  */
    63 
    64 static struct textconv_interface *text_interface;
    65 
    66 /* How many times text conversion has been disabled.  */
    67 
    68 static int suppress_conversion_count;
    69 
    70 /* Flags used to determine what must be sent after a batch edit
    71    ends.  */
    72 
    73 enum textconv_batch_edit_flags
    74   {
    75     PENDING_POINT_CHANGE   = 1,
    76     PENDING_COMPOSE_CHANGE = 2,
    77   };
    78 
    79 
    80 
    81 /* Copy the portion of the current buffer described by BEG, BEG_BYTE,
    82    END, END_BYTE to the buffer BUFFER, which is END_BYTE - BEG_BYTEs
    83    long.  */
    84 
    85 static void
    86 copy_buffer (ptrdiff_t beg, ptrdiff_t beg_byte,
    87              ptrdiff_t end, ptrdiff_t end_byte,
    88              char *buffer)
    89 {
    90   ptrdiff_t beg0, end0, beg1, end1, size;
    91 
    92   if (beg_byte < GPT_BYTE && GPT_BYTE < end_byte)
    93     {
    94       /* Two regions, before and after the gap.  */
    95       beg0 = beg_byte;
    96       end0 = GPT_BYTE;
    97       beg1 = GPT_BYTE + GAP_SIZE - BEG_BYTE;
    98       end1 = end_byte + GAP_SIZE - BEG_BYTE;
    99     }
   100   else
   101     {
   102       /* The only region.  */
   103       beg0 = beg_byte;
   104       end0 = end_byte;
   105       beg1 = -1;
   106       end1 = -1;
   107     }
   108 
   109   size = end0 - beg0;
   110   memcpy (buffer, BYTE_POS_ADDR (beg0), size);
   111   if (beg1 != -1)
   112     memcpy (buffer + size, BEG_ADDR + beg1, end1 - beg1);
   113 }
   114 
   115 
   116 
   117 /* Conversion query.  */
   118 
   119 /* Return the position of the active mark, or -1 if there is no mark
   120    or it is not active.  */
   121 
   122 static ptrdiff_t
   123 get_mark (void)
   124 {
   125   if (!NILP (BVAR (current_buffer, mark_active))
   126       && XMARKER (BVAR (current_buffer, mark))->buffer)
   127     return marker_position (BVAR (current_buffer,
   128                                   mark));
   129 
   130   return -1;
   131 }
   132 
   133 /* Like Fselect_window.  However, if WINDOW is a mini buffer window
   134    but not the active minibuffer window, select its frame's selected
   135    window instead.  */
   136 
   137 static void
   138 select_window (Lisp_Object window, Lisp_Object norecord)
   139 {
   140   struct window *w;
   141 
   142   w = XWINDOW (window);
   143 
   144   if (MINI_WINDOW_P (w)
   145       && WINDOW_LIVE_P (window)
   146       && !EQ (window, Factive_minibuffer_window ()))
   147     window = WINDOW_XFRAME (w)->selected_window;
   148 
   149   Fselect_window (window, norecord);
   150 }
   151 
   152 /* Perform the text conversion operation specified in QUERY and return
   153    the results.
   154 
   155    Find the text between QUERY->position from point on F's selected
   156    window and QUERY->factor times QUERY->direction from that
   157    position.  Return it in QUERY->text.
   158 
   159    If QUERY->position is TYPE_MINIMUM (EMACS_INT) or EMACS_INT_MAX,
   160    start at the window's last point or mark, whichever is greater or
   161    smaller.
   162 
   163    Then, either delete that text from the buffer if QUERY->operation
   164    is TEXTCONV_SUBSTITUTION, or return 0.
   165 
   166    If FLAGS & TEXTCONV_SKIP_CONVERSION_REGION, then first move PT past
   167    the conversion region in the specified direction if it is inside.
   168 
   169    Value is 0 if QUERY->operation was not TEXTCONV_SUBSTITUTION
   170    or if deleting the text was successful, and 1 otherwise.  */
   171 
   172 int
   173 textconv_query (struct frame *f, struct textconv_callback_struct *query,
   174                 int flags)
   175 {
   176   specpdl_ref count;
   177   ptrdiff_t pos, pos_byte, end, end_byte, start;
   178   ptrdiff_t temp, temp1, mark;
   179   char *buffer;
   180   struct window *w;
   181 
   182   /* Save the excursion, as there will be extensive changes to the
   183      selected window.  */
   184   count = SPECPDL_INDEX ();
   185   record_unwind_protect_excursion ();
   186 
   187   /* Inhibit quitting.  */
   188   specbind (Qinhibit_quit, Qt);
   189 
   190   /* Temporarily switch to F's selected window at the time of the last
   191      redisplay.  */
   192   select_window ((WINDOW_LIVE_P (f->old_selected_window)
   193                   ? f->old_selected_window
   194                   : f->selected_window), Qt);
   195   w = XWINDOW (selected_window);
   196 
   197   /* Now find the appropriate text bounds for QUERY.  First, move
   198      point QUERY->position steps forward or backwards.  */
   199 
   200   pos = PT;
   201 
   202   /* If QUERY->position is EMACS_INT_MAX, use the last mark or the
   203      ephemeral last point, whichever is greater.
   204 
   205      The opposite applies for EMACS_INT_MIN.  */
   206 
   207   mark = get_mark ();
   208 
   209   if (query->position == EMACS_INT_MAX)
   210     {
   211       pos = (mark == -1
   212              ? w->ephemeral_last_point
   213              : max (w->ephemeral_last_point, mark));
   214       goto escape1;
   215     }
   216   else if (query->position == TYPE_MINIMUM (EMACS_INT))
   217     {
   218       pos = (mark == -1
   219              ? w->ephemeral_last_point
   220              : min (w->ephemeral_last_point, mark));
   221       goto escape1;
   222     }
   223 
   224   /* Next, if POS lies within the conversion region and the caller
   225      asked for it to be moved away, move it away from the conversion
   226      region.  */
   227 
   228   if (flags & TEXTCONV_SKIP_CONVERSION_REGION
   229       && MARKERP (f->conversion.compose_region_start))
   230     {
   231       start = marker_position (f->conversion.compose_region_start);
   232       end = marker_position (f->conversion.compose_region_end);
   233 
   234       if (pos >= start && pos < end)
   235         {
   236           switch (query->direction)
   237             {
   238             case TEXTCONV_FORWARD_CHAR:
   239             case TEXTCONV_FORWARD_WORD:
   240             case TEXTCONV_CARET_DOWN:
   241             case TEXTCONV_NEXT_LINE:
   242             case TEXTCONV_LINE_START:
   243               pos = end;
   244               break;
   245 
   246             default:
   247               pos = max (BEGV, start - 1);
   248               break;
   249             }
   250         }
   251     }
   252 
   253   /* If pos is outside the accessible part of the buffer or if it
   254      overflows, move back to point or to the extremes of the
   255      accessible region.  */
   256 
   257   if (ckd_add (&pos, pos, query->position))
   258     pos = PT;
   259 
   260  escape1:
   261 
   262   if (pos < BEGV)
   263     pos = BEGV;
   264 
   265   if (pos > ZV)
   266     pos = ZV;
   267 
   268   /* Move to pos.  */
   269   set_point (pos);
   270   pos = PT;
   271   pos_byte = PT_BYTE;
   272 
   273   /* Now scan forward or backwards according to what is in QUERY.  */
   274 
   275   switch (query->direction)
   276     {
   277     case TEXTCONV_FORWARD_CHAR:
   278       /* Move forward by query->factor characters.  */
   279       if (ckd_add (&end, pos, query->factor) || end > ZV)
   280         end = ZV;
   281 
   282       end_byte = CHAR_TO_BYTE (end);
   283       break;
   284 
   285     case TEXTCONV_BACKWARD_CHAR:
   286       /* Move backward by query->factor characters.  */
   287       if (ckd_sub (&end, pos, query->factor) || end < BEGV)
   288         end = BEGV;
   289 
   290       end_byte = CHAR_TO_BYTE (end);
   291       break;
   292 
   293     case TEXTCONV_FORWARD_WORD:
   294       /* Move forward by query->factor word.  */
   295       end = scan_words (pos, (EMACS_INT) query->factor);
   296 
   297       if (!end)
   298         {
   299           end = ZV;
   300           end_byte = ZV_BYTE;
   301         }
   302       else
   303         end_byte = CHAR_TO_BYTE (end);
   304 
   305       break;
   306 
   307     case TEXTCONV_BACKWARD_WORD:
   308       /* Move backwards by query->factor word.  */
   309       end = scan_words (pos, 0 - (EMACS_INT) query->factor);
   310 
   311       if (!end)
   312         {
   313           end = BEGV;
   314           end_byte = BEGV_BYTE;
   315         }
   316       else
   317         end_byte = CHAR_TO_BYTE (end);
   318 
   319       break;
   320 
   321     case TEXTCONV_CARET_UP:
   322       /* Move upwards one visual line, keeping the column intact.  */
   323       Fvertical_motion (Fcons (Fcurrent_column (), make_fixnum (-1)),
   324                         Qnil, Qnil);
   325       end = PT;
   326       end_byte = PT_BYTE;
   327       break;
   328 
   329     case TEXTCONV_CARET_DOWN:
   330       /* Move downwards one visual line, keeping the column
   331          intact.  */
   332       Fvertical_motion (Fcons (Fcurrent_column (), make_fixnum (1)),
   333                         Qnil, Qnil);
   334       end = PT;
   335       end_byte = PT_BYTE;
   336       break;
   337 
   338     case TEXTCONV_NEXT_LINE:
   339       /* Move one line forward.  */
   340       scan_newline (pos, pos_byte, ZV, ZV_BYTE,
   341                     query->factor, false);
   342       end = PT;
   343       end_byte = PT_BYTE;
   344       break;
   345 
   346     case TEXTCONV_PREVIOUS_LINE:
   347       /* Move one line backwards.  */
   348       scan_newline (pos, pos_byte, BEGV, BEGV_BYTE,
   349                     0 - (EMACS_INT) query->factor, false);
   350       end = PT;
   351       end_byte = PT_BYTE;
   352       break;
   353 
   354     case TEXTCONV_LINE_START:
   355       /* Move to the beginning of the line.  */
   356       Fbeginning_of_line (Qnil);
   357       end = PT;
   358       end_byte = PT_BYTE;
   359       break;
   360 
   361     case TEXTCONV_LINE_END:
   362       /* Move to the end of the line.  */
   363       Fend_of_line (Qnil);
   364       end = PT;
   365       end_byte = PT_BYTE;
   366       break;
   367 
   368     case TEXTCONV_ABSOLUTE_POSITION:
   369       /* How to implement this is unclear.  */
   370       SET_PT (query->factor);
   371       end = PT;
   372       end_byte = PT_BYTE;
   373       break;
   374 
   375     default:
   376       unbind_to (count, Qnil);
   377       return 1;
   378     }
   379 
   380   /* Sort end and pos.  */
   381 
   382   if (end < pos)
   383     {
   384       eassert (end_byte < pos_byte);
   385       temp = pos_byte;
   386       temp1 = pos;
   387       pos_byte = end_byte;
   388       pos = end;
   389       end = temp1;
   390       end_byte = temp;
   391     }
   392 
   393   /* Return the string first.  */
   394   buffer = xmalloc (end_byte - pos_byte);
   395   copy_buffer (pos, pos_byte, end, end_byte, buffer);
   396   query->text.text = buffer;
   397   query->text.length = end - pos;
   398   query->text.bytes = end_byte - pos_byte;
   399 
   400   /* Next, perform any operation specified.  */
   401 
   402   switch (query->operation)
   403     {
   404     case TEXTCONV_SUBSTITUTION:
   405       if (safe_del_range (pos, end))
   406         {
   407           /* Undo any changes to the excursion.  */
   408           unbind_to (count, Qnil);
   409           return 1;
   410         }
   411 
   412     default:
   413       break;
   414     }
   415 
   416   /* Undo any changes to the excursion.  */
   417   unbind_to (count, Qnil);
   418   return 0;
   419 }
   420 
   421 /* Update the overlay displaying the conversion area on F after a
   422    change to the conversion region.  */
   423 
   424 static void
   425 sync_overlay (struct frame *f)
   426 {
   427   if (MARKERP (f->conversion.compose_region_start)
   428       && !NILP (Vtext_conversion_face))
   429     {
   430       if (NILP (f->conversion.compose_region_overlay))
   431         {
   432           f->conversion.compose_region_overlay
   433             = Fmake_overlay (f->conversion.compose_region_start,
   434                              f->conversion.compose_region_end, Qnil,
   435                              Qt, Qnil);
   436           Foverlay_put (f->conversion.compose_region_overlay,
   437                         Qface, Vtext_conversion_face);
   438         }
   439 
   440       Fmove_overlay (f->conversion.compose_region_overlay,
   441                      f->conversion.compose_region_start,
   442                      f->conversion.compose_region_end, Qnil);
   443     }
   444   else if (!NILP (f->conversion.compose_region_overlay))
   445     {
   446       Fdelete_overlay (f->conversion.compose_region_overlay);
   447       f->conversion.compose_region_overlay = Qnil;
   448     }
   449 }
   450 
   451 /* Record a change to the current buffer as a result of an
   452    asynchronous text conversion operation on F.
   453 
   454    Consult the doc string of `text-conversion-edits' for the meaning
   455    of BEG, END, and EPHEMERAL.  */
   456 
   457 static void
   458 record_buffer_change (ptrdiff_t beg, ptrdiff_t end,
   459                       Lisp_Object ephemeral)
   460 {
   461   Lisp_Object buffer, beg_marker, end_marker;
   462 
   463   XSETBUFFER (buffer, current_buffer);
   464 
   465   /* Make markers for both BEG and END.  */
   466   beg_marker = build_marker (current_buffer, beg,
   467                              CHAR_TO_BYTE (beg));
   468 
   469   /* If BEG and END are identical, make sure to keep the markers
   470      eq.  */
   471 
   472   if (beg == end)
   473     end_marker = beg_marker;
   474   else
   475     {
   476       end_marker = build_marker (current_buffer, end,
   477                                  CHAR_TO_BYTE (end));
   478 
   479       /* Otherwise, make sure the marker extends past inserted
   480          text.  */
   481       Fset_marker_insertion_type (end_marker, Qt);
   482     }
   483 
   484   Vtext_conversion_edits
   485     = Fcons (list4 (buffer, beg_marker, end_marker,
   486                     ephemeral),
   487              Vtext_conversion_edits);
   488 }
   489 
   490 /* Reset F's text conversion state.  Delete any overlays or
   491    markers inside.  */
   492 
   493 void
   494 reset_frame_state (struct frame *f)
   495 {
   496   struct text_conversion_action *last, *next;
   497 
   498   /* Make the composition region markers point elsewhere.  */
   499 
   500   if (!NILP (f->conversion.compose_region_start))
   501     {
   502       Fset_marker (f->conversion.compose_region_start, Qnil, Qnil);
   503       Fset_marker (f->conversion.compose_region_end, Qnil, Qnil);
   504       f->conversion.compose_region_start = Qnil;
   505       f->conversion.compose_region_end = Qnil;
   506     }
   507 
   508   /* Delete the composition region overlay.  */
   509 
   510   if (!NILP (f->conversion.compose_region_overlay))
   511     Fdelete_overlay (f->conversion.compose_region_overlay);
   512 
   513   /* Delete each text conversion action queued up.  */
   514 
   515   next = f->conversion.actions;
   516   while (next)
   517     {
   518       last = next;
   519       next = next->next;
   520 
   521       /* Say that the conversion is finished.  */
   522       if (text_interface && text_interface->notify_conversion)
   523         text_interface->notify_conversion (last->counter);
   524 
   525       xfree (last);
   526     }
   527   f->conversion.actions = NULL;
   528 
   529   /* Clear batch edit state.  */
   530   f->conversion.batch_edit_count = 0;
   531   f->conversion.batch_edit_flags = 0;
   532 }
   533 
   534 /* Return whether or not there are pending edits from an input method
   535    on any frame.  */
   536 
   537 bool
   538 detect_conversion_events (void)
   539 {
   540   Lisp_Object tail, frame;
   541 
   542   FOR_EACH_FRAME (tail, frame)
   543     {
   544       /* See if there's a pending edit on this frame.  */
   545       if (XFRAME (frame)->conversion.actions
   546           && ((XFRAME (frame)->conversion.actions->operation
   547                != TEXTCONV_BARRIER)
   548               || (kbd_fetch_ptr == kbd_store_ptr)))
   549         return true;
   550     }
   551 
   552   return false;
   553 }
   554 
   555 /* Restore the selected window WINDOW.  */
   556 
   557 static void
   558 restore_selected_window (Lisp_Object window)
   559 {
   560   /* FIXME: not sure what to do if WINDOW has been deleted.  */
   561   select_window (window, Qt);
   562 }
   563 
   564 /* Commit the given text in the composing region.  If there is no
   565    composing region, then insert the text after F's selected window's
   566    last point instead, unless the mark is active.  Finally, remove the
   567    composing region.
   568 
   569    If the mark is active, delete the text between mark and point.
   570 
   571    Then, move point to POSITION relative to TEXT.  If POSITION is
   572    greater than zero, it is relative to the character at the end of
   573    TEXT; otherwise, it is relative to the start of TEXT.  */
   574 
   575 static void
   576 really_commit_text (struct frame *f, EMACS_INT position,
   577                     Lisp_Object text)
   578 {
   579   specpdl_ref count;
   580   ptrdiff_t wanted, start, end, mark;
   581   struct window *w;
   582 
   583   /* If F's old selected window is no longer live, fail.  */
   584 
   585   if (!WINDOW_LIVE_P (f->old_selected_window))
   586     return;
   587 
   588   count = SPECPDL_INDEX ();
   589   record_unwind_protect (restore_selected_window,
   590                          selected_window);
   591 
   592   /* Temporarily switch to F's selected window at the time of the last
   593      redisplay.  */
   594   select_window (f->old_selected_window, Qt);
   595 
   596   /* Now detect whether or not there is a composing or active region.
   597      If there is, then replace it with TEXT.  Don't do that
   598      otherwise.  */
   599 
   600   mark = get_mark ();
   601   if (MARKERP (f->conversion.compose_region_start) || mark != -1)
   602     {
   603       /* Replace its contents.  Set START and END to the start and end
   604          of the composing region if it exists.  */
   605 
   606       if (MARKERP (f->conversion.compose_region_start))
   607         {
   608           start = marker_position (f->conversion.compose_region_start);
   609           end = marker_position (f->conversion.compose_region_end);
   610         }
   611       else
   612         {
   613           /* Otherwise, set it to the start and end of the region.  */
   614           start = min (mark, PT);
   615           end = max (mark, PT);
   616         }
   617 
   618       /* Now delete whatever needs to go.  */
   619 
   620       del_range_1 (start, end, true, false);
   621       record_buffer_change (start, start, Qt);
   622 
   623       /* Don't record changes if TEXT is empty.  */
   624 
   625       if (SCHARS (text))
   626         {
   627           /* Insert the new text.  Make sure to inherit text
   628              properties from the surroundings: if this doesn't happen,
   629              CC Mode fontification can get thrown off and become very
   630              slow.  */
   631 
   632           insert_from_string (text, 0, 0, SCHARS (text),
   633                               SBYTES (text), true);
   634           record_buffer_change (start, PT, text);
   635         }
   636 
   637       /* Move to a the position specified in POSITION.  */
   638 
   639       if (position <= 0)
   640         {
   641           /* If POSITION is less than zero, it is relative to the
   642              start of the text that was inserted.  */
   643           wanted = start;
   644 
   645           if (INT_ADD_WRAPV (wanted, position, &wanted)
   646               || wanted < BEGV)
   647             wanted = BEGV;
   648 
   649           if (wanted > ZV)
   650             wanted = ZV;
   651 
   652           set_point (wanted);
   653         }
   654       else
   655         {
   656           /* Otherwise, it is relative to the last character in
   657              TEXT.  */
   658           wanted = PT;
   659 
   660           if (INT_ADD_WRAPV (wanted, position - 1, &wanted)
   661               || wanted > ZV)
   662             wanted = ZV;
   663 
   664           if (wanted < BEGV)
   665             wanted = BEGV;
   666 
   667           set_point (wanted);
   668         }
   669 
   670       /* Make the composition region markers point elsewhere.  */
   671 
   672       if (!NILP (f->conversion.compose_region_start))
   673         {
   674           Fset_marker (f->conversion.compose_region_start, Qnil, Qnil);
   675           Fset_marker (f->conversion.compose_region_end, Qnil, Qnil);
   676           f->conversion.compose_region_start = Qnil;
   677           f->conversion.compose_region_end = Qnil;
   678         }
   679 
   680       /* Delete the composition region overlay.  */
   681 
   682       if (!NILP (f->conversion.compose_region_overlay))
   683         Fdelete_overlay (f->conversion.compose_region_overlay);
   684     }
   685   else
   686     {
   687       /* Otherwise, move the text and point to an appropriate
   688          location.  */
   689       wanted = PT;
   690 
   691       /* Don't record changes if TEXT is empty.  */
   692 
   693       if (SCHARS (text))
   694         {
   695           /* Insert the new text.  Make sure to inherit text
   696              properties from the surroundings: if this doesn't happen,
   697              CC Mode fontification can get thrown off and become very
   698              slow.  */
   699 
   700           insert_from_string (text, 0, 0, SCHARS (text),
   701                               SBYTES (text), true);
   702 
   703           record_buffer_change (wanted, PT, text);
   704         }
   705 
   706       if (position <= 0)
   707         {
   708           if (INT_ADD_WRAPV (wanted, position, &wanted)
   709               || wanted < BEGV)
   710             wanted = BEGV;
   711 
   712           if (wanted > ZV)
   713             wanted = ZV;
   714 
   715           set_point (wanted);
   716         }
   717       else
   718         {
   719           wanted = PT;
   720 
   721           if (INT_ADD_WRAPV (wanted, position - 1, &wanted)
   722               || wanted > ZV)
   723             wanted = ZV;
   724 
   725           if (wanted < BEGV)
   726             wanted = BEGV;
   727 
   728           set_point (wanted);
   729         }
   730     }
   731 
   732   /* This should deactivate the mark.  */
   733   call0 (Qdeactivate_mark);
   734 
   735   /* Print some debugging information.  */
   736   TEXTCONV_DEBUG ("text inserted: %s, point now: %zd",
   737                   SSDATA (text), PT);
   738 
   739   /* Update the ephemeral last point.  */
   740   w = XWINDOW (selected_window);
   741   w->ephemeral_last_point = PT;
   742   unbind_to (count, Qnil);
   743 }
   744 
   745 /* Remove the composition region on the frame F, while leaving its
   746    contents intact.  If UPDATE, also notify the input method of the
   747    change.  */
   748 
   749 static void
   750 really_finish_composing_text (struct frame *f, bool update)
   751 {
   752   if (!NILP (f->conversion.compose_region_start))
   753     {
   754       Fset_marker (f->conversion.compose_region_start, Qnil, Qnil);
   755       Fset_marker (f->conversion.compose_region_end, Qnil, Qnil);
   756       f->conversion.compose_region_start = Qnil;
   757       f->conversion.compose_region_end = Qnil;
   758 
   759       if (update && text_interface
   760           && text_interface->compose_region_changed)
   761         (*text_interface->compose_region_changed) (f);
   762     }
   763 
   764   /* Delete the composition region overlay.  */
   765 
   766   if (!NILP (f->conversion.compose_region_overlay))
   767     Fdelete_overlay (f->conversion.compose_region_overlay);
   768 
   769   TEXTCONV_DEBUG ("conversion region removed");
   770 }
   771 
   772 /* Set the composing text on F to TEXT.  Then, move point to an
   773    appropriate position relative to POSITION, and call
   774    `compose_region_changed' in the text conversion interface should
   775    point not have been changed relative to F's old selected window's
   776    last point.  */
   777 
   778 static void
   779 really_set_composing_text (struct frame *f, ptrdiff_t position,
   780                            Lisp_Object text)
   781 {
   782   specpdl_ref count;
   783   ptrdiff_t start, wanted, end;
   784   struct window *w;
   785 
   786   /* If F's old selected window is no longer live, fail.  */
   787 
   788   if (!WINDOW_LIVE_P (f->old_selected_window))
   789     return;
   790 
   791   count = SPECPDL_INDEX ();
   792   record_unwind_protect (restore_selected_window,
   793                          selected_window);
   794 
   795   /* Temporarily switch to F's selected window at the time of the last
   796      redisplay.  */
   797   w = XWINDOW (f->old_selected_window);
   798   select_window (f->old_selected_window, Qt);
   799 
   800   /* Now set up the composition region if necessary.  */
   801 
   802   if (!MARKERP (f->conversion.compose_region_start))
   803     {
   804       /* Set START and END.  */
   805       start = PT;
   806       wanted = end = get_mark ();
   807 
   808       /* If END is -1, set it to start.  */
   809 
   810       if (end == -1)
   811         end = start;
   812       else
   813         {
   814           /* Now sort start and end.  */
   815           start = min (start, end);
   816           end  = max (PT, wanted);
   817         }
   818 
   819       /* If END is not the same as start, delete the text in
   820          between.  */
   821 
   822       if (end != start)
   823         {
   824           del_range_1 (start, end, true, false);
   825           set_point (start);
   826           record_buffer_change (start, start, Qt);
   827         }
   828 
   829       /* Now set the markers which denote the composition region.  */
   830       f->conversion.compose_region_start
   831         = build_marker (current_buffer, PT, PT_BYTE);
   832       f->conversion.compose_region_end
   833         = build_marker (current_buffer, PT, PT_BYTE);
   834 
   835       Fset_marker_insertion_type (f->conversion.compose_region_end,
   836                                   Qt);
   837     }
   838   else
   839     {
   840       /* Delete the text between the start of the composing region and
   841          its end.  */
   842       start = marker_position (f->conversion.compose_region_start);
   843       end = marker_position (f->conversion.compose_region_end);
   844       del_range_1 (start, end, true, false);
   845       set_point (start);
   846 
   847       if (start != end)
   848         record_buffer_change (start, start, Qt);
   849     }
   850 
   851   /* Insert the new text.  Make sure to inherit text properties from
   852      the surroundings: if this doesn't happen, CC Mode fontification
   853      can get thrown off and become very slow.  */
   854 
   855   insert_from_string (text, 0, 0, SCHARS (text),
   856                       SBYTES (text), true);
   857 
   858   if (start != PT)
   859     record_buffer_change (start, PT, Qt);
   860 
   861   /* Now move point to an appropriate location.  */
   862   if (position <= 0)
   863     {
   864       wanted = start;
   865 
   866       if (INT_SUBTRACT_WRAPV (wanted, position, &wanted)
   867           || wanted < BEGV)
   868         wanted = BEGV;
   869 
   870       if (wanted > ZV)
   871         wanted = ZV;
   872     }
   873   else
   874     {
   875       end = marker_position (f->conversion.compose_region_end);
   876       wanted = end;
   877 
   878       /* end should be PT after the edit.  */
   879       eassert (end == PT);
   880 
   881       if (INT_ADD_WRAPV (wanted, position - 1, &wanted)
   882           || wanted > ZV)
   883         wanted = ZV;
   884 
   885       if (wanted < BEGV)
   886         wanted = BEGV;
   887     }
   888 
   889   set_point (wanted);
   890 
   891   /* This should deactivate the mark.  */
   892   call0 (Qdeactivate_mark);
   893 
   894   /* Move the composition overlay.  */
   895   sync_overlay (f);
   896 
   897   /* If TEXT is empty, remove the composing region.  This goes against
   898      the documentation, but is ultimately what programs expect.  */
   899 
   900   if (!SCHARS (text))
   901     really_finish_composing_text (f, false);
   902 
   903   /* If PT hasn't changed, the conversion region definitely has.
   904      Otherwise, redisplay will update the input method instead.  */
   905 
   906   if (PT == w->ephemeral_last_point
   907       && text_interface
   908       && text_interface->compose_region_changed)
   909     {
   910       if (f->conversion.batch_edit_count > 0)
   911         f->conversion.batch_edit_flags |= PENDING_COMPOSE_CHANGE;
   912       else
   913         text_interface->compose_region_changed (f);
   914     }
   915 
   916   /* Update the ephemeral last point.  */
   917   w = XWINDOW (selected_window);
   918   w->ephemeral_last_point = PT;
   919 
   920   if (SCHARS (text))
   921     TEXTCONV_DEBUG ("conversion region set to: %td %td",
   922                     marker_position (f->conversion.compose_region_start),
   923                     marker_position (f->conversion.compose_region_end));
   924   else
   925     TEXTCONV_DEBUG ("conversion region removed; PT is now: %td", PT);
   926 
   927   unbind_to (count, Qnil);
   928 }
   929 
   930 /* Set the composing region to START by END.  Make it that it is not
   931    already set.  */
   932 
   933 static void
   934 really_set_composing_region (struct frame *f, ptrdiff_t start,
   935                              ptrdiff_t end)
   936 {
   937   specpdl_ref count;
   938   struct window *w;
   939 
   940   /* If F's old selected window is no longer live, fail.  */
   941 
   942   if (!WINDOW_LIVE_P (f->old_selected_window))
   943     return;
   944 
   945   /* If MAX (0, start) == end, then this should behave the same as
   946      really_finish_composing_text.  */
   947 
   948   if (max (0, start) == max (0, end))
   949     {
   950       really_finish_composing_text (f, false);
   951       return;
   952     }
   953 
   954   count = SPECPDL_INDEX ();
   955   record_unwind_protect (restore_selected_window,
   956                          selected_window);
   957 
   958   /* Temporarily switch to F's selected window at the time of the last
   959      redisplay.  */
   960   select_window (f->old_selected_window, Qt);
   961 
   962   /* Now set up the composition region if necessary.  */
   963 
   964   if (!MARKERP (f->conversion.compose_region_start))
   965     {
   966       f->conversion.compose_region_start = Fmake_marker ();
   967       f->conversion.compose_region_end = Fmake_marker ();
   968       Fset_marker_insertion_type (f->conversion.compose_region_end,
   969                                   Qt);
   970     }
   971 
   972   Fset_marker (f->conversion.compose_region_start,
   973                make_fixnum (start), Qnil);
   974   Fset_marker (f->conversion.compose_region_end,
   975                make_fixnum (end), Qnil);
   976   sync_overlay (f);
   977 
   978   TEXTCONV_DEBUG ("composing region set to: %td, %td; point is: %td",
   979                   start, end, PT);
   980 
   981   /* Update the ephemeral last point.  */
   982   w = XWINDOW (selected_window);
   983   w->ephemeral_last_point = PT;
   984 
   985   unbind_to (count, Qnil);
   986 }
   987 
   988 /* Delete LEFT and RIGHT chars around point or the active mark,
   989    whichever is larger, avoiding the composing region if
   990    necessary.  */
   991 
   992 static void
   993 really_delete_surrounding_text (struct frame *f, ptrdiff_t left,
   994                                 ptrdiff_t right)
   995 {
   996   specpdl_ref count;
   997   ptrdiff_t start, end, a, b, a1, b1, lstart, rstart;
   998   struct window *w;
   999   Lisp_Object text;
  1000 
  1001   /* If F's old selected window is no longer live, fail.  */
  1002 
  1003   if (!WINDOW_LIVE_P (f->old_selected_window))
  1004     return;
  1005 
  1006   count = SPECPDL_INDEX ();
  1007   record_unwind_protect (restore_selected_window,
  1008                          selected_window);
  1009 
  1010   /* Temporarily switch to F's selected window at the time of the last
  1011      redisplay.  */
  1012   select_window (f->old_selected_window, Qt);
  1013 
  1014   /* Figure out where to start deleting from.  */
  1015 
  1016   a = get_mark ();
  1017 
  1018   if (a != -1 && a != PT)
  1019     lstart = rstart = max (a, PT);
  1020   else
  1021     lstart = rstart = PT;
  1022 
  1023   /* Avoid the composing text.  This behavior is identical to how
  1024      Android's BaseInputConnection actually implements avoiding the
  1025      composing span.  */
  1026 
  1027   if (MARKERP (f->conversion.compose_region_start))
  1028     {
  1029       a = marker_position (f->conversion.compose_region_start);
  1030       b = marker_position (f->conversion.compose_region_end);
  1031 
  1032       a1 = min (a, b);
  1033       b1 = max (a, b);
  1034 
  1035       lstart = min (lstart, min (PT, a1));
  1036       rstart = max (rstart, max (PT, b1));
  1037     }
  1038 
  1039   if (lstart == rstart)
  1040     {
  1041       start = max (BEGV, lstart - left);
  1042       end = min (ZV, rstart + right);
  1043 
  1044       text = del_range_1 (start, end, true, true);
  1045       record_buffer_change (start, start, text);
  1046     }
  1047   else
  1048     {
  1049       /* Don't record a deletion if the text which was deleted lies
  1050          after point.  */
  1051 
  1052       start = rstart;
  1053       end = min (ZV, rstart + right);
  1054       text = del_range_1 (start, end, true, true);
  1055       record_buffer_change (start, start, Qnil);
  1056 
  1057       /* Now delete what must be deleted on the left.  */
  1058 
  1059       start = max (BEGV, lstart - left);
  1060       end = lstart;
  1061       text = del_range_1 (start, end, true, true);
  1062       record_buffer_change (start, start, text);
  1063     }
  1064 
  1065   TEXTCONV_DEBUG ("deleted surrounding text: %td, %td; PT is now %td",
  1066                   left, right, PT);
  1067 
  1068   /* if the mark is now equal to start, deactivate it.  */
  1069 
  1070   if (get_mark () == PT)
  1071     call0 (Qdeactivate_mark);
  1072 
  1073   /* Update the ephemeral last point.  */
  1074   w = XWINDOW (selected_window);
  1075   w->ephemeral_last_point = PT;
  1076 
  1077   unbind_to (count, Qnil);
  1078 }
  1079 
  1080 /* Update the interface with F's new point and mark.  If a batch edit
  1081    is in progress, schedule the update for when it finishes
  1082    instead.  */
  1083 
  1084 static void
  1085 really_request_point_update (struct frame *f)
  1086 {
  1087   /* If F's old selected window is no longer live, fail.  */
  1088 
  1089   if (!WINDOW_LIVE_P (f->old_selected_window))
  1090     return;
  1091 
  1092   if (f->conversion.batch_edit_count > 0)
  1093     f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE;
  1094   else if (text_interface && text_interface->point_changed)
  1095     text_interface->point_changed (f,
  1096                                    XWINDOW (f->old_selected_window),
  1097                                    current_buffer);
  1098 }
  1099 
  1100 /* Set point in F to POSITION.  If MARK is not POSITION, activate the
  1101    mark and set MARK to that as well.
  1102 
  1103    If it has not changed, signal an update through the text input
  1104    interface, which is necessary for the IME to acknowledge that the
  1105    change has completed.  */
  1106 
  1107 static void
  1108 really_set_point_and_mark (struct frame *f, ptrdiff_t point,
  1109                            ptrdiff_t mark)
  1110 {
  1111   specpdl_ref count;
  1112   struct window *w;
  1113 
  1114   /* If F's old selected window is no longer live, fail.  */
  1115 
  1116   if (!WINDOW_LIVE_P (f->old_selected_window))
  1117     return;
  1118 
  1119   count = SPECPDL_INDEX ();
  1120   record_unwind_protect (restore_selected_window,
  1121                          selected_window);
  1122 
  1123   /* Temporarily switch to F's selected window at the time of the last
  1124      redisplay.  */
  1125   select_window (f->old_selected_window, Qt);
  1126 
  1127   if (point == PT)
  1128     {
  1129       if (f->conversion.batch_edit_count > 0)
  1130         f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE;
  1131       else if (text_interface && text_interface->point_changed)
  1132         text_interface->point_changed (f,
  1133                                        XWINDOW (f->old_selected_window),
  1134                                        current_buffer);
  1135     }
  1136   else
  1137     /* Set the point.  */
  1138     Fgoto_char (make_fixnum (point));
  1139 
  1140   if (mark == point
  1141       && !NILP (BVAR (current_buffer, mark_active)))
  1142     call0 (Qdeactivate_mark);
  1143   else
  1144     call1 (Qpush_mark, make_fixnum (mark));
  1145 
  1146   /* Update the ephemeral last point.  */
  1147   w = XWINDOW (selected_window);
  1148   w->ephemeral_last_point = PT;
  1149 
  1150   TEXTCONV_DEBUG ("set point and mark: %td %td",
  1151                   PT, get_mark ());
  1152 
  1153   unbind_to (count, Qnil);
  1154 }
  1155 
  1156 /* Complete the edit specified by the counter value inside *TOKEN.  */
  1157 
  1158 static void
  1159 complete_edit (void *token)
  1160 {
  1161   if (text_interface && text_interface->notify_conversion)
  1162     text_interface->notify_conversion (*(unsigned long *) token);
  1163 }
  1164 
  1165 /* Context for complete_edit_check.  */
  1166 
  1167 struct complete_edit_check_context
  1168 {
  1169   /* The window.  */
  1170   struct window *w;
  1171 
  1172   /* Whether or not editing was successful.  */
  1173   bool check;
  1174 };
  1175 
  1176 /* If CONTEXT->check is false, then update W's ephemeral last point
  1177    and give it to the input method, the assumption being that an
  1178    editing operation signalled.  */
  1179 
  1180 static void
  1181 complete_edit_check (void *ptr)
  1182 {
  1183   struct complete_edit_check_context *context;
  1184   struct frame *f;
  1185 
  1186   context = ptr;
  1187 
  1188   if (!context->check)
  1189     {
  1190       /* Figure out the new position of point.  */
  1191       context->w->ephemeral_last_point
  1192         = window_point (context->w);
  1193 
  1194       /* See if the frame is still alive.  */
  1195 
  1196       f = WINDOW_XFRAME (context->w);
  1197 
  1198       if (!FRAME_LIVE_P (f))
  1199         return;
  1200 
  1201       if (text_interface && text_interface->point_changed)
  1202         {
  1203           if (f->conversion.batch_edit_count > 0)
  1204             f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE;
  1205           else
  1206             text_interface->point_changed (f, context->w, NULL);
  1207         }
  1208     }
  1209 }
  1210 
  1211 /* Process and free the text conversion ACTION.  F must be the frame
  1212    on which ACTION will be performed.
  1213 
  1214    Value is the window which was used, or NULL.  */
  1215 
  1216 static struct window *
  1217 handle_pending_conversion_events_1 (struct frame *f,
  1218                                     struct text_conversion_action *action)
  1219 {
  1220   Lisp_Object data;
  1221   enum text_conversion_operation operation;
  1222   struct buffer *buffer UNINIT;
  1223   struct window *w;
  1224   specpdl_ref count;
  1225   unsigned long token;
  1226   struct complete_edit_check_context context;
  1227 
  1228   /* Next, process this action and free it.  */
  1229 
  1230   data = action->data;
  1231   operation = action->operation;
  1232   token = action->counter;
  1233   xfree (action);
  1234 
  1235   /* Text conversion events can still arrive immediately after
  1236      `conversion_disabled_p' becomes true.  In that case, process all
  1237      events, but don't perform any associated actions.  */
  1238 
  1239   if (conversion_disabled_p ())
  1240     return NULL;
  1241 
  1242   /* check is a flag used by complete_edit_check to determine whether
  1243      or not the editing operation completed successfully.  */
  1244   context.check = false;
  1245 
  1246   /* Make sure completion is signalled.  */
  1247   count = SPECPDL_INDEX ();
  1248   record_unwind_protect_ptr (complete_edit, &token);
  1249   w = NULL;
  1250 
  1251   if (WINDOW_LIVE_P (f->old_selected_window))
  1252     {
  1253       w = XWINDOW (f->old_selected_window);
  1254       buffer = XBUFFER (WINDOW_BUFFER (w));
  1255       context.w = w;
  1256 
  1257       /* Notify the input method of any editing failures.  */
  1258       record_unwind_protect_ptr (complete_edit_check, &context);
  1259     }
  1260 
  1261   switch (operation)
  1262     {
  1263     case TEXTCONV_START_BATCH_EDIT:
  1264       f->conversion.batch_edit_count++;
  1265       break;
  1266 
  1267     case TEXTCONV_END_BATCH_EDIT:
  1268       if (f->conversion.batch_edit_count > 0)
  1269         f->conversion.batch_edit_count--;
  1270 
  1271       if (!WINDOW_LIVE_P (f->old_selected_window))
  1272         break;
  1273 
  1274       if (f->conversion.batch_edit_flags & PENDING_POINT_CHANGE)
  1275         text_interface->point_changed (f, w, buffer);
  1276 
  1277       if (f->conversion.batch_edit_flags & PENDING_COMPOSE_CHANGE)
  1278         text_interface->compose_region_changed (f);
  1279 
  1280       f->conversion.batch_edit_flags = 0;
  1281       break;
  1282 
  1283     case TEXTCONV_COMMIT_TEXT:
  1284       really_commit_text (f, XFIXNUM (XCAR (data)), XCDR (data));
  1285       break;
  1286 
  1287     case TEXTCONV_FINISH_COMPOSING_TEXT:
  1288       really_finish_composing_text (f, !NILP (data));
  1289       break;
  1290 
  1291     case TEXTCONV_SET_COMPOSING_TEXT:
  1292       really_set_composing_text (f, XFIXNUM (XCAR (data)),
  1293                                  XCDR (data));
  1294       break;
  1295 
  1296     case TEXTCONV_SET_COMPOSING_REGION:
  1297       really_set_composing_region (f, XFIXNUM (XCAR (data)),
  1298                                    XFIXNUM (XCDR (data)));
  1299       break;
  1300 
  1301     case TEXTCONV_SET_POINT_AND_MARK:
  1302       really_set_point_and_mark (f, XFIXNUM (XCAR (data)),
  1303                                  XFIXNUM (XCDR (data)));
  1304       break;
  1305 
  1306     case TEXTCONV_DELETE_SURROUNDING_TEXT:
  1307       really_delete_surrounding_text (f, XFIXNUM (XCAR (data)),
  1308                                       XFIXNUM (XCDR (data)));
  1309       break;
  1310 
  1311     case TEXTCONV_REQUEST_POINT_UPDATE:
  1312       really_request_point_update (f);
  1313       break;
  1314 
  1315     case TEXTCONV_BARRIER:
  1316       if (kbd_fetch_ptr != kbd_store_ptr)
  1317         emacs_abort ();
  1318 
  1319       /* Once a barrier is hit, synchronize F's selected window's
  1320          `ephemeral_last_point' with its current point.  The reason
  1321          for this is because otherwise a previous keyboard event may
  1322          have taken place without redisplay happening in between.  */
  1323 
  1324       if (w)
  1325         w->ephemeral_last_point = window_point (w);
  1326       break;
  1327     }
  1328 
  1329   /* Signal success.  */
  1330   context.check = true;
  1331   unbind_to (count, Qnil);
  1332 
  1333   return w;
  1334 }
  1335 
  1336 /* Decrement the variable pointed to by *PTR.  */
  1337 
  1338 static void
  1339 decrement_inside (void *ptr)
  1340 {
  1341   int *i;
  1342 
  1343   i = ptr;
  1344   (*i)--;
  1345 }
  1346 
  1347 /* Process any outstanding text conversion events.
  1348    This may run Lisp or signal.  */
  1349 
  1350 void
  1351 handle_pending_conversion_events (void)
  1352 {
  1353   struct frame *f;
  1354   Lisp_Object tail, frame;
  1355   struct text_conversion_action *action, *next;
  1356   bool handled;
  1357   static int inside;
  1358   specpdl_ref count;
  1359   ptrdiff_t last_point;
  1360   struct window *w;
  1361 
  1362   handled = false;
  1363 
  1364   /* Reset Vtext_conversion_edits.  Do not do this if called
  1365      reentrantly.  */
  1366 
  1367   if (!inside)
  1368     Vtext_conversion_edits = Qnil;
  1369 
  1370   inside++;
  1371 
  1372   count = SPECPDL_INDEX ();
  1373   record_unwind_protect_ptr (decrement_inside, &inside);
  1374 
  1375   FOR_EACH_FRAME (tail, frame)
  1376     {
  1377       f = XFRAME (frame);
  1378       last_point = -1;
  1379       w = NULL;
  1380 
  1381       /* Test if F has any outstanding conversion events.  Then
  1382          process them in bottom to up order.  */
  1383       while (true)
  1384         {
  1385           /* Update the input method if handled &&
  1386              w->ephemeral_last_point != last_point.  */
  1387           if (w && (last_point != w->ephemeral_last_point))
  1388             {
  1389               if (handled
  1390                   && last_point != -1
  1391                   && text_interface
  1392                   && text_interface->point_changed)
  1393                 {
  1394                   if (f->conversion.batch_edit_count > 0)
  1395                     f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE;
  1396                   else
  1397                     text_interface->point_changed (f, NULL, NULL);
  1398                 }
  1399 
  1400               last_point = w->ephemeral_last_point;
  1401             }
  1402 
  1403           /* Reload action.  This needs to be reentrant as buffer
  1404              modification functions can call `read-char'.  */
  1405           action = f->conversion.actions;
  1406 
  1407           /* If there are no more actions, break.  */
  1408 
  1409           if (!action)
  1410             break;
  1411 
  1412           /* If action is a barrier event and the keyboard buffer is
  1413              not yet empty, break out of the loop.  */
  1414 
  1415           if (action->operation == TEXTCONV_BARRIER
  1416               && kbd_store_ptr != kbd_fetch_ptr)
  1417             break;
  1418 
  1419           /* Unlink this action.  */
  1420           next = action->next;
  1421           f->conversion.actions = next;
  1422 
  1423           /* Handle and free the action.  */
  1424           w = handle_pending_conversion_events_1 (f, action);
  1425           handled = true;
  1426         }
  1427     }
  1428 
  1429   unbind_to (count, Qnil);
  1430 }
  1431 
  1432 /* Start a ``batch edit'' in F.  During a batch edit, point_changed
  1433    will not be called until the batch edit ends.
  1434 
  1435    Process the actual operation in the event loop in keyboard.c; then,
  1436    call `notify_conversion' in the text conversion interface with
  1437    COUNTER.  */
  1438 
  1439 void
  1440 start_batch_edit (struct frame *f, unsigned long counter)
  1441 {
  1442   struct text_conversion_action *action, **last;
  1443 
  1444   action = xmalloc (sizeof *action);
  1445   action->operation = TEXTCONV_START_BATCH_EDIT;
  1446   action->data = Qnil;
  1447   action->next = NULL;
  1448   action->counter = counter;
  1449   for (last = &f->conversion.actions; *last; last = &(*last)->next)
  1450     ;;
  1451   *last = action;
  1452   input_pending = true;
  1453 }
  1454 
  1455 /* End a ``batch edit''.  It is ok to call this function even if a
  1456    batch edit has not yet started, in which case it does nothing.
  1457 
  1458    COUNTER means the same as in `start_batch_edit'.  */
  1459 
  1460 void
  1461 end_batch_edit (struct frame *f, unsigned long counter)
  1462 {
  1463   struct text_conversion_action *action, **last;
  1464 
  1465   action = xmalloc (sizeof *action);
  1466   action->operation = TEXTCONV_END_BATCH_EDIT;
  1467   action->data = Qnil;
  1468   action->next = NULL;
  1469   action->counter = counter;
  1470   for (last = &f->conversion.actions; *last; last = &(*last)->next)
  1471     ;;
  1472   *last = action;
  1473   input_pending = true;
  1474 }
  1475 
  1476 /* Insert the specified STRING into F's current buffer's composition
  1477    region, and set point to POSITION relative to STRING.
  1478 
  1479    If there is no composition region, use the active region instead.
  1480    If that doesn't exist either, insert STRING after point.
  1481 
  1482    COUNTER means the same as in `start_batch_edit'.  */
  1483 
  1484 void
  1485 commit_text (struct frame *f, Lisp_Object string,
  1486              ptrdiff_t position, unsigned long counter)
  1487 {
  1488   struct text_conversion_action *action, **last;
  1489 
  1490   action = xmalloc (sizeof *action);
  1491   action->operation = TEXTCONV_COMMIT_TEXT;
  1492   action->data = Fcons (make_fixnum (position), string);
  1493   action->next = NULL;
  1494   action->counter = counter;
  1495   for (last = &f->conversion.actions; *last; last = &(*last)->next)
  1496     ;;
  1497   *last = action;
  1498   input_pending = true;
  1499 }
  1500 
  1501 /* Remove the composition region and its overlay from F's current
  1502    buffer.  Leave the text being composed intact.
  1503 
  1504    If UPDATE, call `compose_region_changed' after the region is
  1505    removed.
  1506 
  1507    COUNTER means the same as in `start_batch_edit'.  */
  1508 
  1509 void
  1510 finish_composing_text (struct frame *f, unsigned long counter,
  1511                        bool update)
  1512 {
  1513   struct text_conversion_action *action, **last;
  1514 
  1515   action = xmalloc (sizeof *action);
  1516   action->operation = TEXTCONV_FINISH_COMPOSING_TEXT;
  1517   action->data = update ? Qt : Qnil;
  1518   action->next = NULL;
  1519   action->counter = counter;
  1520   for (last = &f->conversion.actions; *last; last = &(*last)->next)
  1521     ;;
  1522   *last = action;
  1523   input_pending = true;
  1524 }
  1525 
  1526 /* Insert the given STRING and make it the currently active
  1527    composition.
  1528 
  1529    If there is currently no composing or active region, then the new
  1530    value of point is used as the composing region.
  1531 
  1532    Then, the composing or active region is replaced with the text in
  1533    the specified string.
  1534 
  1535    Finally, move point to new_point, which is relative to either the
  1536    start or the end of OBJECT depending on whether or not it is less
  1537    than zero.
  1538 
  1539    COUNTER means the same as in `start_batch_edit'.  */
  1540 
  1541 void
  1542 set_composing_text (struct frame *f, Lisp_Object object,
  1543                     ptrdiff_t new_point, unsigned long counter)
  1544 {
  1545   struct text_conversion_action *action, **last;
  1546 
  1547   action = xmalloc (sizeof *action);
  1548   action->operation = TEXTCONV_SET_COMPOSING_TEXT;
  1549   action->data = Fcons (make_fixnum (new_point),
  1550                         object);
  1551   action->next = NULL;
  1552   action->counter = counter;
  1553   for (last = &f->conversion.actions; *last; last = &(*last)->next)
  1554     ;;
  1555   *last = action;
  1556   input_pending = true;
  1557 }
  1558 
  1559 /* Make the region between START and END the currently active
  1560    ``composing region''.
  1561 
  1562    The ``composing region'' is a region of text in the buffer that is
  1563    about to undergo editing by the input method.  */
  1564 
  1565 void
  1566 set_composing_region (struct frame *f, ptrdiff_t start,
  1567                       ptrdiff_t end, unsigned long counter)
  1568 {
  1569   struct text_conversion_action *action, **last;
  1570 
  1571   if (start > MOST_POSITIVE_FIXNUM)
  1572     start = MOST_POSITIVE_FIXNUM;
  1573 
  1574   if (end > MOST_POSITIVE_FIXNUM)
  1575     end = MOST_POSITIVE_FIXNUM;
  1576 
  1577   action = xmalloc (sizeof *action);
  1578   action->operation = TEXTCONV_SET_COMPOSING_REGION;
  1579   action->data = Fcons (make_fixnum (start),
  1580                         make_fixnum (end));
  1581   action->next = NULL;
  1582   action->counter = counter;
  1583   for (last = &f->conversion.actions; *last; last = &(*last)->next)
  1584     ;;
  1585   *last = action;
  1586   input_pending = true;
  1587 }
  1588 
  1589 /* Move point in F's selected buffer to POINT and maybe push MARK.
  1590 
  1591    COUNTER means the same as in `start_batch_edit'.  */
  1592 
  1593 void
  1594 textconv_set_point_and_mark (struct frame *f, ptrdiff_t point,
  1595                              ptrdiff_t mark, unsigned long counter)
  1596 {
  1597   struct text_conversion_action *action, **last;
  1598 
  1599   if (point > MOST_POSITIVE_FIXNUM)
  1600     point = MOST_POSITIVE_FIXNUM;
  1601 
  1602   action = xmalloc (sizeof *action);
  1603   action->operation = TEXTCONV_SET_POINT_AND_MARK;
  1604   action->data = Fcons (make_fixnum (point),
  1605                         make_fixnum (mark));
  1606   action->next = NULL;
  1607   action->counter = counter;
  1608   for (last = &f->conversion.actions; *last; last = &(*last)->next)
  1609     ;;
  1610   *last = action;
  1611   input_pending = true;
  1612 }
  1613 
  1614 /* Delete LEFT and RIGHT characters around point in F's old selected
  1615    window.  */
  1616 
  1617 void
  1618 delete_surrounding_text (struct frame *f, ptrdiff_t left,
  1619                          ptrdiff_t right, unsigned long counter)
  1620 {
  1621   struct text_conversion_action *action, **last;
  1622 
  1623   action = xmalloc (sizeof *action);
  1624   action->operation = TEXTCONV_DELETE_SURROUNDING_TEXT;
  1625   action->data = Fcons (make_fixnum (left),
  1626                         make_fixnum (right));
  1627   action->next = NULL;
  1628   action->counter = counter;
  1629   for (last = &f->conversion.actions; *last; last = &(*last)->next)
  1630     ;;
  1631   *last = action;
  1632   input_pending = true;
  1633 }
  1634 
  1635 /* Request an immediate call to INTERFACE->point_changed with the new
  1636    details of F's region unless a batch edit is in progress.  */
  1637 
  1638 void
  1639 request_point_update (struct frame *f, unsigned long counter)
  1640 {
  1641   struct text_conversion_action *action, **last;
  1642 
  1643   action = xmalloc (sizeof *action);
  1644   action->operation = TEXTCONV_REQUEST_POINT_UPDATE;
  1645   action->data = Qnil;
  1646   action->next = NULL;
  1647   action->counter = counter;
  1648   for (last = &f->conversion.actions; *last; last = &(*last)->next)
  1649     ;;
  1650   *last = action;
  1651   input_pending = true;
  1652 }
  1653 
  1654 /* Request that text conversion on F pause until the keyboard buffer
  1655    becomes empty.
  1656 
  1657    Use this function to ensure that edits associated with a keyboard
  1658    event complete before the text conversion edits after the barrier
  1659    take place.  */
  1660 
  1661 void
  1662 textconv_barrier (struct frame *f, unsigned long counter)
  1663 {
  1664   struct text_conversion_action *action, **last;
  1665 
  1666   action = xmalloc (sizeof *action);
  1667   action->operation = TEXTCONV_BARRIER;
  1668   action->data = Qnil;
  1669   action->next = NULL;
  1670   action->counter = counter;
  1671   for (last = &f->conversion.actions; *last; last = &(*last)->next)
  1672     ;;
  1673   *last = action;
  1674   input_pending = true;
  1675 }
  1676 
  1677 /* Return N characters of text around point in F's old selected
  1678    window.
  1679 
  1680    If N is -1, return the text between point and mark instead, given
  1681    that the mark is active.
  1682 
  1683    Set *N to the actual number of characters returned, *START_RETURN
  1684    to the position of the first character returned, *START_OFFSET to
  1685    the offset of the lesser of mark and point within that text,
  1686    *END_OFFSET to the greater of mark and point within that text, and
  1687    *LENGTH to the actual number of characters returned, *BYTES to the
  1688    actual number of bytes returned, and *MARK_ACTIVE to whether or not
  1689    the mark is active.
  1690 
  1691    Value is NULL upon failure, and a malloced string upon success.  */
  1692 
  1693 char *
  1694 get_extracted_text (struct frame *f, ptrdiff_t n,
  1695                     ptrdiff_t *start_return,
  1696                     ptrdiff_t *start_offset,
  1697                     ptrdiff_t *end_offset, ptrdiff_t *length,
  1698                     ptrdiff_t *bytes, bool *mark_active)
  1699 {
  1700   specpdl_ref count;
  1701   ptrdiff_t start, end, start_byte, end_byte, mark;
  1702   char *buffer;
  1703 
  1704   if (!WINDOW_LIVE_P (f->old_selected_window))
  1705     return NULL;
  1706 
  1707   /* Save the excursion, as there will be extensive changes to the
  1708      selected window.  */
  1709   count = SPECPDL_INDEX ();
  1710   record_unwind_protect_excursion ();
  1711 
  1712   /* Inhibit quitting.  */
  1713   specbind (Qinhibit_quit, Qt);
  1714 
  1715   /* Temporarily switch to F's selected window at the time of the last
  1716      redisplay.  */
  1717   select_window (f->old_selected_window, Qt);
  1718   buffer = NULL;
  1719 
  1720   /* Figure out the bounds of the text to return.  */
  1721   if (n != -1)
  1722     {
  1723       /* Make sure n is at least 4, leaving two characters around
  1724          PT.  */
  1725       n = max (4, n);
  1726 
  1727       start = PT - n / 2;
  1728       end = PT + n - n / 2;
  1729     }
  1730   else
  1731     {
  1732       if (!NILP (BVAR (current_buffer, mark_active))
  1733           && XMARKER (BVAR (current_buffer, mark))->buffer)
  1734         {
  1735           start = marker_position (BVAR (current_buffer, mark));
  1736           end = PT;
  1737 
  1738           /* Sort start and end.  start_byte is used to hold a
  1739              temporary value.  */
  1740 
  1741           if (start > end)
  1742             {
  1743               start_byte = end;
  1744               end = start;
  1745               start = start_byte;
  1746             }
  1747         }
  1748       else
  1749         goto finish;
  1750     }
  1751 
  1752   start = max (start, BEGV);
  1753   end = min (end, ZV);
  1754 
  1755   /* Detect overflow.  */
  1756 
  1757   if (!(start <= PT && PT <= end))
  1758     goto finish;
  1759 
  1760   /* Convert the character positions to byte positions.  */
  1761   start_byte = CHAR_TO_BYTE (start);
  1762   end_byte = CHAR_TO_BYTE (end);
  1763 
  1764   /* Extract the text from the buffer.  */
  1765   buffer = xmalloc (end_byte - start_byte);
  1766   copy_buffer (start, start_byte, end, end_byte,
  1767                buffer);
  1768 
  1769   /* Get the mark.  If it's not active, use PT.  */
  1770 
  1771   mark = get_mark ();
  1772   *mark_active = true;
  1773 
  1774   if (mark == -1)
  1775     {
  1776       mark = PT;
  1777       *mark_active = false;
  1778     }
  1779 
  1780   /* Return the offsets.  */
  1781   *start_return = start;
  1782   *start_offset = min (mark - start, PT - start);
  1783   *end_offset = max (mark - start, PT - start);
  1784   *length = end - start;
  1785   *bytes = end_byte - start_byte;
  1786 
  1787   TEXTCONV_DEBUG ("get_extracted_text: PT, mark, start: %td, %td, %td",
  1788                   PT, mark, start);
  1789 
  1790  finish:
  1791   unbind_to (count, Qnil);
  1792   return buffer;
  1793 }
  1794 
  1795 /* Return the text between the positions PT - LEFT and PT + RIGHT.  If
  1796    the mark is active, return the range of text relative to the bounds
  1797    of the region instead.
  1798 
  1799    Set *LENGTH to the number of characters returned, *BYTES to the
  1800    number of bytes returned, *OFFSET to the character position of the
  1801    returned text, and *START_RETURN and *END_RETURN to the mark and
  1802    point relative to that position.  */
  1803 
  1804 char *
  1805 get_surrounding_text (struct frame *f, ptrdiff_t left,
  1806                       ptrdiff_t right, ptrdiff_t *length,
  1807                       ptrdiff_t *bytes, ptrdiff_t *offset,
  1808                       ptrdiff_t *start_return,
  1809                       ptrdiff_t *end_return)
  1810 {
  1811   specpdl_ref count;
  1812   ptrdiff_t start, end, start_byte, end_byte, mark, temp;
  1813   char *buffer;
  1814 
  1815   if (!WINDOW_LIVE_P (f->old_selected_window))
  1816     return NULL;
  1817 
  1818   /* Save the excursion, as there will be extensive changes to the
  1819      selected window.  */
  1820   count = SPECPDL_INDEX ();
  1821   record_unwind_protect_excursion ();
  1822 
  1823   /* Inhibit quitting.  */
  1824   specbind (Qinhibit_quit, Qt);
  1825 
  1826   /* Temporarily switch to F's selected window at the time of the last
  1827      redisplay.  */
  1828   select_window (f->old_selected_window, Qt);
  1829   buffer = NULL;
  1830 
  1831   /* Figure out the bounds of the text to return.  */
  1832 
  1833   /* First, obtain start and end.  */
  1834   end = get_mark ();
  1835   start = PT;
  1836 
  1837   /* If the mark is not active, make it start and end.  */
  1838 
  1839   if (end == -1)
  1840     end = start;
  1841 
  1842   /* Now sort start and end.  */
  1843 
  1844   if (end < start)
  1845     {
  1846       temp = start;
  1847       start = end;
  1848       end = temp;
  1849     }
  1850 
  1851   /* And subtract left and right.  */
  1852 
  1853   if (INT_SUBTRACT_WRAPV (start, left, &start)
  1854       || INT_ADD_WRAPV (end, right, &end))
  1855     goto finish;
  1856 
  1857   start = max (start, BEGV);
  1858   end = min (end, ZV);
  1859 
  1860   /* Detect overflow.  */
  1861 
  1862   if (!(start <= PT && PT <= end))
  1863     goto finish;
  1864 
  1865   /* Convert the character positions to byte positions.  */
  1866   start_byte = CHAR_TO_BYTE (start);
  1867   end_byte = CHAR_TO_BYTE (end);
  1868 
  1869   /* Extract the text from the buffer.  */
  1870   buffer = xmalloc (end_byte - start_byte);
  1871   copy_buffer (start, start_byte, end, end_byte,
  1872                buffer);
  1873 
  1874   /* Get the mark.  If it's not active, use PT.  */
  1875 
  1876   mark = get_mark ();
  1877 
  1878   if (mark == -1)
  1879     mark = PT;
  1880 
  1881   /* Return the offsets.  Unlike `get_extracted_text', this need not
  1882      sort mark and point.  */
  1883 
  1884   *offset = start;
  1885   *start_return = mark - start;
  1886   *end_return = PT - start;
  1887   *length = end - start;
  1888   *bytes = end_byte - start_byte;
  1889 
  1890  finish:
  1891   unbind_to (count, Qnil);
  1892   return buffer;
  1893 }
  1894 
  1895 /* Return whether or not text conversion is temporarily disabled.
  1896    `reset' should always call this to determine whether or not to
  1897    disable the input method.  */
  1898 
  1899 bool
  1900 conversion_disabled_p (void)
  1901 {
  1902   return suppress_conversion_count > 0;
  1903 }
  1904 
  1905 
  1906 
  1907 /* Window system interface.  These are called from the rest of
  1908    Emacs.  */
  1909 
  1910 /* Notice that F's selected window has been set from redisplay.
  1911    Reset F's input method state.  */
  1912 
  1913 void
  1914 report_selected_window_change (struct frame *f)
  1915 {
  1916   struct window *w;
  1917 
  1918   reset_frame_state (f);
  1919 
  1920   if (!text_interface)
  1921     return;
  1922 
  1923   /* When called from window.c, F's selected window has already been
  1924      redisplayed, but w->last_point has not yet been updated.  Update
  1925      it here to avoid race conditions when the IM asks for the initial
  1926      selection position immediately after.  */
  1927 
  1928   if (WINDOWP (f->selected_window))
  1929     {
  1930       w = XWINDOW (f->selected_window);
  1931       w->ephemeral_last_point = window_point (w);
  1932     }
  1933 
  1934   text_interface->reset (f);
  1935 }
  1936 
  1937 /* Notice that the point in F's selected window's current buffer has
  1938    changed.
  1939 
  1940    F is the frame whose selected window was changed, W is the window
  1941    in question, and BUFFER is that window's current buffer.
  1942 
  1943    Tell the text conversion interface about the change; it will likely
  1944    pass the information on to the system input method.  */
  1945 
  1946 void
  1947 report_point_change (struct frame *f, struct window *window,
  1948                      struct buffer *buffer)
  1949 {
  1950   if (!text_interface || !text_interface->point_changed)
  1951     return;
  1952 
  1953   if (f->conversion.batch_edit_count > 0)
  1954     f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE;
  1955   else
  1956     text_interface->point_changed (f, window, buffer);
  1957 }
  1958 
  1959 /* Temporarily disable text conversion.  Must be paired with a
  1960    corresponding call to resume_text_conversion.  */
  1961 
  1962 void
  1963 disable_text_conversion (void)
  1964 {
  1965   Lisp_Object tail, frame;
  1966   struct frame *f;
  1967 
  1968   suppress_conversion_count++;
  1969 
  1970   if (!text_interface || suppress_conversion_count > 1)
  1971     return;
  1972 
  1973   /* Loop through and reset the input method on each window system
  1974      frame.  It should call conversion_disabled_p and then DTRT.  */
  1975 
  1976   FOR_EACH_FRAME (tail, frame)
  1977     {
  1978       f = XFRAME (frame);
  1979       reset_frame_state (f);
  1980 
  1981       if (FRAME_WINDOW_P (f) && FRAME_VISIBLE_P (f))
  1982         text_interface->reset (f);
  1983     }
  1984 }
  1985 
  1986 /* Undo the effect of the last call to `disable_text_conversion'.  */
  1987 
  1988 void
  1989 resume_text_conversion (void)
  1990 {
  1991   Lisp_Object tail, frame;
  1992   struct frame *f;
  1993 
  1994   suppress_conversion_count--;
  1995   eassert (suppress_conversion_count >= 0);
  1996 
  1997   if (!text_interface || suppress_conversion_count)
  1998     return;
  1999 
  2000   /* Loop through and reset the input method on each window system
  2001      frame.  It should call conversion_disabled_p and then DTRT.  */
  2002 
  2003   FOR_EACH_FRAME (tail, frame)
  2004     {
  2005       f = XFRAME (frame);
  2006       reset_frame_state (f);
  2007 
  2008       if (FRAME_WINDOW_P (f) && FRAME_VISIBLE_P (f))
  2009         text_interface->reset (f);
  2010     }
  2011 }
  2012 
  2013 /* Register INTERFACE as the text conversion interface.  */
  2014 
  2015 void
  2016 register_textconv_interface (struct textconv_interface *interface)
  2017 {
  2018   text_interface = interface;
  2019 }
  2020 
  2021 
  2022 
  2023 /* List of buffers whose text conversion state will be reset after a
  2024    key sequence is read.  */
  2025 static Lisp_Object postponed_buffers;
  2026 
  2027 /* Reset the text conversion style of each frame whose selected buffer
  2028    is contained inside `postponed_buffers'.  Set `postponed_buffers'
  2029    to nil.  */
  2030 
  2031 void
  2032 check_postponed_buffers (void)
  2033 {
  2034   Lisp_Object buffer, tail, frame;
  2035   struct buffer *b;
  2036   struct frame *f;
  2037 
  2038   buffer = postponed_buffers;
  2039   postponed_buffers = Qnil;
  2040 
  2041   if (!text_interface->reset)
  2042     return;
  2043 
  2044   FOR_EACH_TAIL (buffer)
  2045     {
  2046       b = XBUFFER (XCAR (buffer));
  2047 
  2048       /* Continue if this is a dead buffer.  */
  2049 
  2050       if (!BUFFER_LIVE_P (b))
  2051         continue;
  2052 
  2053       /* If no windows are displaying B anymore, continue.  */
  2054 
  2055       if (!buffer_window_count (b))
  2056         continue;
  2057 
  2058       /* Look for frames which have B selected.  */
  2059 
  2060       FOR_EACH_FRAME (tail, frame)
  2061         {
  2062           f = XFRAME (frame);
  2063 
  2064           if (WINDOW_LIVE_P (f->old_selected_window)
  2065               && FRAME_WINDOW_P (f)
  2066               /* N.B. that the same frame can't be reset twice as long
  2067                  as the list of buffers remains unique.  */
  2068               && EQ (XWINDOW (f->old_selected_window)->contents,
  2069                      XCAR (buffer)))
  2070             {
  2071               block_input ();
  2072               reset_frame_state (f);
  2073               text_interface->reset (f);
  2074               unblock_input ();
  2075             }
  2076         }
  2077     }
  2078 }
  2079 
  2080 /* Lisp interface.  */
  2081 
  2082 DEFUN ("set-text-conversion-style", Fset_text_conversion_style,
  2083        Sset_text_conversion_style, 1, 2, 0,
  2084        doc: /* Set the text conversion style in the current buffer.
  2085 
  2086 Set `text-conversion-style' to VALUE, then force any input method
  2087 editing frame displaying this buffer to stop itself.
  2088 
  2089 This can lead to a significant amount of time being taken by the input
  2090 method resetting itself, so you should not use this function lightly;
  2091 instead, set `text-conversion-style' before your buffer is displayed,
  2092 and let redisplay manage the input method appropriately.
  2093 
  2094 If a key sequence is currently being read (either through the command
  2095 loop or by a call to `read-key-sequence') and AFTER-KEY-SEQUENCE is
  2096 non-nil, don't perform changes to the input method until the key
  2097 sequence is read.  This is useful within a function bound to
  2098 `input-decode-map' or `local-function-key-map', as it prevents the
  2099 input method from being redundantly enabled according to VALUE if the
  2100 replacement key sequence returned starts a new key sequence and makes
  2101 `read-key-sequence' disable text conversion again.  */)
  2102   (Lisp_Object value, Lisp_Object after_key_sequence)
  2103 {
  2104   Lisp_Object tail, frame;
  2105   struct frame *f;
  2106   Lisp_Object buffer;
  2107 
  2108   bset_text_conversion_style (current_buffer, value);
  2109 
  2110   if (!text_interface)
  2111     return Qnil;
  2112 
  2113   /* If there are any seleted windows displaying this buffer, reset
  2114      text conversion on their associated frames.  */
  2115 
  2116   if (buffer_window_count (current_buffer))
  2117     {
  2118       buffer = Fcurrent_buffer ();
  2119 
  2120       /* Postpone changes to the actual text conversion state if
  2121          AFTER_KEY_SEQUENCE is non-nil and a key sequence is being
  2122          read.  */
  2123 
  2124       if (reading_key_sequence && !NILP (after_key_sequence))
  2125         {
  2126           if (NILP (Fmemq (buffer, postponed_buffers)))
  2127             /* `check_postponed_buffers' will hopefully be called soon
  2128                enough to avoid postponed_buffers growing
  2129                indefinitely.  */
  2130             postponed_buffers = Fcons (buffer, postponed_buffers);
  2131           return Qnil;
  2132         }
  2133 
  2134       FOR_EACH_FRAME (tail, frame)
  2135         {
  2136           f = XFRAME (frame);
  2137 
  2138           if (WINDOW_LIVE_P (f->old_selected_window)
  2139               && FRAME_WINDOW_P (f)
  2140               && EQ (XWINDOW (f->old_selected_window)->contents,
  2141                      buffer))
  2142             {
  2143               block_input ();
  2144               reset_frame_state (f);
  2145               text_interface->reset (f);
  2146               unblock_input ();
  2147             }
  2148         }
  2149     }
  2150 
  2151   return Qnil;
  2152 }
  2153 
  2154 
  2155 
  2156 void
  2157 syms_of_textconv (void)
  2158 {
  2159   DEFSYM (Qaction, "action");
  2160   DEFSYM (Qtext_conversion, "text-conversion");
  2161   DEFSYM (Qpush_mark, "push-mark");
  2162   DEFSYM (Qunderline, "underline");
  2163   DEFSYM (Qoverriding_text_conversion_style,
  2164           "overriding-text-conversion-style");
  2165 
  2166   DEFVAR_LISP ("text-conversion-edits", Vtext_conversion_edits,
  2167     doc: /* List of buffers that were last edited as a result of text conversion.
  2168 
  2169 This list can be used while handling a `text-conversion' event to
  2170 determine which changes have taken place.
  2171 
  2172 Each element of the list describes a single edit in a buffer, of the
  2173 form:
  2174 
  2175     (BUFFER BEG END EPHEMERAL)
  2176 
  2177 If an insertion or an edit to the buffer text is described, then BEG
  2178 and END are markers which denote the bounds of the text that was
  2179 changed or inserted.  If a deletion is described, then BEG and END are
  2180 the same object.
  2181 
  2182 If EPHEMERAL is t, then the input method is preparing to make further
  2183 edits to the text, so any actions that would otherwise be taken, such
  2184 as indenting or automatically filling text, should not take place.
  2185 
  2186 Otherwise, it is either a string containing text that was inserted,
  2187 text deleted before point, or nil if text was deleted after point.
  2188 
  2189 The list contents are ordered later edits first, so you must iterate
  2190 through the list in reverse.  */);
  2191   Vtext_conversion_edits = Qnil;
  2192 
  2193   DEFVAR_LISP ("overriding-text-conversion-style",
  2194                Voverriding_text_conversion_style,
  2195     doc: /* Non-buffer local version of `text-conversion-style'.
  2196 
  2197 If this variable is the symbol `lambda', it means to consult the
  2198 buffer local variable `text-conversion-style' to determine whether or
  2199 not to activate the input method.  Otherwise, its value is used in
  2200 preference to any buffer local value of `text-conversion-style'.  */);
  2201   Voverriding_text_conversion_style = Qlambda;
  2202 
  2203   DEFVAR_LISP ("text-conversion-face", Vtext_conversion_face,
  2204     doc: /* Face in which to display temporary edits by an input method.
  2205 nil means to display no indication of a temporary edit.  */);
  2206   Vtext_conversion_face = Qunderline;
  2207 
  2208   defsubr (&Sset_text_conversion_style);
  2209 
  2210   postponed_buffers = Qnil;
  2211   staticpro (&postponed_buffers);
  2212 }

/* [<][>][^][v][top][bottom][index][help] */