aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-02-12 20:32:31 +0800
committerPo Lu2023-02-12 20:32:31 +0800
commit19eb27d47787bd8a519a37a8e6080ed5b56435dc (patch)
tree61669a450983bdaa356698b6f26958bebfa191ad /src
parent0198b8cffd82893412c738dae8e50c45a99286f1 (diff)
parent9510e8ad68271f58b4813478703a4b8eb1ba597b (diff)
downloademacs-19eb27d47787bd8a519a37a8e6080ed5b56435dc.tar.gz
emacs-19eb27d47787bd8a519a37a8e6080ed5b56435dc.zip
Merge remote-tracking branch 'origin/master' into feature/android
Diffstat (limited to 'src')
-rw-r--r--src/buffer.h2
-rw-r--r--src/emacs.c3
-rw-r--r--src/fns.c17
-rw-r--r--src/frame.c2
-rw-r--r--src/insdel.c38
-rw-r--r--src/lisp.h6
-rw-r--r--src/textconv.c312
-rw-r--r--src/textconv.h109
-rw-r--r--src/treesit.c46
-rw-r--r--src/window.c15
-rw-r--r--src/xfns.c303
-rw-r--r--src/xterm.c41
12 files changed, 856 insertions, 38 deletions
diff --git a/src/buffer.h b/src/buffer.h
index eb32d602ad6..e700297a264 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -690,7 +690,7 @@ struct buffer
690 display optimizations must be used. */ 690 display optimizations must be used. */
691 bool_bf long_line_optimizations_p : 1; 691 bool_bf long_line_optimizations_p : 1;
692 692
693 /* The inveral tree containing this buffer's overlays. */ 693 /* The interval tree containing this buffer's overlays. */
694 struct itree_tree *overlays; 694 struct itree_tree *overlays;
695 695
696 /* Changes in the buffer are recorded here for undo, and t means 696 /* Changes in the buffer are recorded here for undo, and t means
diff --git a/src/emacs.c b/src/emacs.c
index 79156c63017..d7de3c85bbe 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -2525,7 +2525,8 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
2525#ifdef HAVE_DBUS 2525#ifdef HAVE_DBUS
2526 init_dbusbind (); 2526 init_dbusbind ();
2527#endif 2527#endif
2528#if defined(USE_GTK) && !defined(HAVE_PGTK) 2528
2529#ifdef HAVE_X_WINDOWS
2529 init_xterm (); 2530 init_xterm ();
2530#endif 2531#endif
2531 2532
diff --git a/src/fns.c b/src/fns.c
index b356a069bda..bc4ec07421a 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -5813,8 +5813,9 @@ secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start,
5813DEFUN ("md5", Fmd5, Smd5, 1, 5, 0, 5813DEFUN ("md5", Fmd5, Smd5, 1, 5, 0,
5814 doc: /* Return MD5 message digest of OBJECT, a buffer or string. 5814 doc: /* Return MD5 message digest of OBJECT, a buffer or string.
5815 5815
5816A message digest is a cryptographic checksum of a document, and the 5816A message digest is the string representation of the cryptographic checksum
5817algorithm to calculate it is defined in RFC 1321. 5817of a document, and the algorithm to calculate it is defined in RFC 1321.
5818The MD5 digest is 32-character long.
5818 5819
5819The two optional arguments START and END are character positions 5820The two optional arguments START and END are character positions
5820specifying for which part of OBJECT the message digest should be 5821specifying for which part of OBJECT the message digest should be
@@ -5848,12 +5849,12 @@ anything security-related. See `secure-hash' for alternatives. */)
5848DEFUN ("secure-hash", Fsecure_hash, Ssecure_hash, 2, 5, 0, 5849DEFUN ("secure-hash", Fsecure_hash, Ssecure_hash, 2, 5, 0,
5849 doc: /* Return the secure hash of OBJECT, a buffer or string. 5850 doc: /* Return the secure hash of OBJECT, a buffer or string.
5850ALGORITHM is a symbol specifying the hash to use: 5851ALGORITHM is a symbol specifying the hash to use:
5851- md5 corresponds to MD5 5852- md5 corresponds to MD5, produces a 32-character signature
5852- sha1 corresponds to SHA-1 5853- sha1 corresponds to SHA-1, produces a 40-character signature
5853- sha224 corresponds to SHA-2 (SHA-224) 5854- sha224 corresponds to SHA-2 (SHA-224), produces a 56-character signature
5854- sha256 corresponds to SHA-2 (SHA-256) 5855- sha256 corresponds to SHA-2 (SHA-256), produces a 64-character signature
5855- sha384 corresponds to SHA-2 (SHA-384) 5856- sha384 corresponds to SHA-2 (SHA-384), produces a 96-character signature
5856- sha512 corresponds to SHA-2 (SHA-512) 5857- sha512 corresponds to SHA-2 (SHA-512), produces a 128-character signature
5857 5858
5858The two optional arguments START and END are positions specifying for 5859The two optional arguments START and END are positions specifying for
5859which part of OBJECT to compute the hash. If nil or omitted, uses the 5860which part of OBJECT to compute the hash. If nil or omitted, uses the
diff --git a/src/frame.c b/src/frame.c
index e98256fe9ed..a1d73d0799d 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -1538,7 +1538,7 @@ do_switch_frame (Lisp_Object frame, int for_deletion, Lisp_Object norecord)
1538 1538
1539 if (f->select_mini_window_flag 1539 if (f->select_mini_window_flag
1540 && !NILP (Fminibufferp (XWINDOW (f->minibuffer_window)->contents, Qt))) 1540 && !NILP (Fminibufferp (XWINDOW (f->minibuffer_window)->contents, Qt)))
1541 f->selected_window = f->minibuffer_window; 1541 fset_selected_window (f, f->minibuffer_window);
1542 f->select_mini_window_flag = false; 1542 f->select_mini_window_flag = false;
1543 1543
1544 if (! FRAME_MINIBUF_ONLY_P (XFRAME (selected_frame))) 1544 if (! FRAME_MINIBUF_ONLY_P (XFRAME (selected_frame)))
diff --git a/src/insdel.c b/src/insdel.c
index e459d0cfa17..b65a3fbd805 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -1715,6 +1715,44 @@ del_range (ptrdiff_t from, ptrdiff_t to)
1715 del_range_1 (from, to, 1, 0); 1715 del_range_1 (from, to, 1, 0);
1716} 1716}
1717 1717
1718struct safe_del_range_context
1719{
1720 /* From and to positions. */
1721 ptrdiff_t from, to;
1722};
1723
1724static Lisp_Object
1725safe_del_range_1 (void *ptr)
1726{
1727 struct safe_del_range_context *context;
1728
1729 context = ptr;
1730 del_range (context->from, context->to);
1731 return Qnil;
1732}
1733
1734static Lisp_Object
1735safe_del_range_2 (enum nonlocal_exit type, Lisp_Object value)
1736{
1737 return Qt;
1738}
1739
1740/* Like del_range; however, catch all non-local exits. Value is 0 if
1741 the buffer contents were really deleted. Otherwise, it is 1. */
1742
1743int
1744safe_del_range (ptrdiff_t from, ptrdiff_t to)
1745{
1746 struct safe_del_range_context context;
1747
1748 context.from = from;
1749 context.to = to;
1750
1751 return !NILP (internal_catch_all (safe_del_range_1,
1752 &context,
1753 safe_del_range_2));
1754}
1755
1718/* Like del_range; PREPARE says whether to call prepare_to_modify_buffer. 1756/* Like del_range; PREPARE says whether to call prepare_to_modify_buffer.
1719 RET_STRING says to return the deleted text. */ 1757 RET_STRING says to return the deleted text. */
1720 1758
diff --git a/src/lisp.h b/src/lisp.h
index 6abde4d545e..894b939b7b9 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4121,6 +4121,7 @@ extern void del_range_byte (ptrdiff_t, ptrdiff_t);
4121extern void del_range_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, bool); 4121extern void del_range_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, bool);
4122extern Lisp_Object del_range_2 (ptrdiff_t, ptrdiff_t, 4122extern Lisp_Object del_range_2 (ptrdiff_t, ptrdiff_t,
4123 ptrdiff_t, ptrdiff_t, bool); 4123 ptrdiff_t, ptrdiff_t, bool);
4124extern int safe_del_range (ptrdiff_t, ptrdiff_t);
4124extern void modify_text (ptrdiff_t, ptrdiff_t); 4125extern void modify_text (ptrdiff_t, ptrdiff_t);
4125extern void prepare_to_modify_buffer (ptrdiff_t, ptrdiff_t, ptrdiff_t *); 4126extern void prepare_to_modify_buffer (ptrdiff_t, ptrdiff_t, ptrdiff_t *);
4126extern void prepare_to_modify_buffer_1 (ptrdiff_t, ptrdiff_t, ptrdiff_t *); 4127extern void prepare_to_modify_buffer_1 (ptrdiff_t, ptrdiff_t, ptrdiff_t *);
@@ -5227,6 +5228,11 @@ extern void syms_of_profiler (void);
5227extern char *emacs_root_dir (void); 5228extern char *emacs_root_dir (void);
5228#endif /* DOS_NT */ 5229#endif /* DOS_NT */
5229 5230
5231#ifdef HAVE_TEXT_CONVERSION
5232/* Defined in textconv.c. */
5233extern void report_selected_window_change (struct frame *);
5234#endif
5235
5230#ifdef HAVE_NATIVE_COMP 5236#ifdef HAVE_NATIVE_COMP
5231INLINE bool 5237INLINE bool
5232SUBR_NATIVE_COMPILEDP (Lisp_Object a) 5238SUBR_NATIVE_COMPILEDP (Lisp_Object a)
diff --git a/src/textconv.c b/src/textconv.c
new file mode 100644
index 00000000000..e91e127b71c
--- /dev/null
+++ b/src/textconv.c
@@ -0,0 +1,312 @@
1/* String conversion support for graphics terminals.
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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#include <config.h>
31
32#include "textconv.h"
33#include "buffer.h"
34#include "syntax.h"
35
36
37
38/* The window system's text conversion interface.
39 NULL when the window system has not set up text conversion.
40
41 This interface will later be heavily extended on the
42 feature/android branch to deal with Android's much less
43 straightforward text conversion protocols. */
44
45static struct textconv_interface *text_interface;
46
47
48
49/* Copy the portion of the current buffer described by BEG, BEG_BYTE,
50 END, END_BYTE to the buffer BUFFER, which is END_BYTE - BEG_BYTEs
51 long. */
52
53static void
54copy_buffer (ptrdiff_t beg, ptrdiff_t beg_byte,
55 ptrdiff_t end, ptrdiff_t end_byte,
56 char *buffer)
57{
58 ptrdiff_t beg0, end0, beg1, end1, size;
59
60 if (beg_byte < GPT_BYTE && GPT_BYTE < end_byte)
61 {
62 /* Two regions, before and after the gap. */
63 beg0 = beg_byte;
64 end0 = GPT_BYTE;
65 beg1 = GPT_BYTE + GAP_SIZE - BEG_BYTE;
66 end1 = end_byte + GAP_SIZE - BEG_BYTE;
67 }
68 else
69 {
70 /* The only region. */
71 beg0 = beg_byte;
72 end0 = end_byte;
73 beg1 = -1;
74 end1 = -1;
75 }
76
77 size = end0 - beg0;
78 memcpy (buffer, BYTE_POS_ADDR (beg0), size);
79 if (beg1 != -1)
80 memcpy (buffer, BEG_ADDR + beg1, end1 - beg1);
81}
82
83
84
85/* Conversion query. */
86
87/* Perform the text conversion operation specified in QUERY and return
88 the results.
89
90 Find the text between QUERY->position from point on F's selected
91 window and QUERY->factor times QUERY->direction from that
92 position. Return it in QUERY->text.
93
94 Then, either delete that text from the buffer if QUERY->operation
95 is TEXTCONV_SUBSTITUTION, or return 0.
96
97 Value is 0 if QUERY->operation was not TEXTCONV_SUBSTITUTION
98 or if deleting the text was successful, and 1 otherwise. */
99
100int
101textconv_query (struct frame *f, struct textconv_callback_struct *query)
102{
103 specpdl_ref count;
104 ptrdiff_t pos, pos_byte, end, end_byte;
105 ptrdiff_t temp, temp1;
106 char *buffer;
107
108 /* Save the excursion, as there will be extensive changes to the
109 selected window. */
110 count = SPECPDL_INDEX ();
111 record_unwind_protect_excursion ();
112
113 /* Inhibit quitting. */
114 specbind (Qinhibit_quit, Qt);
115
116 /* Temporarily switch to F's selected window. */
117 Fselect_window (f->selected_window, Qt);
118
119 /* Now find the appropriate text bounds for QUERY. First, move
120 point QUERY->position steps forward or backwards. */
121
122 pos = PT;
123
124 /* If pos is outside the accessible part of the buffer or if it
125 overflows, move back to point or to the extremes of the
126 accessible region. */
127
128 if (INT_ADD_WRAPV (pos, query->position, &pos))
129 pos = PT;
130
131 if (pos < BEGV)
132 pos = BEGV;
133
134 if (pos > ZV)
135 pos = ZV;
136
137 /* Move to pos. */
138 set_point (pos);
139 pos = PT;
140 pos_byte = PT_BYTE;
141
142 /* Now scan forward or backwards according to what is in QUERY. */
143
144 switch (query->direction)
145 {
146 case TEXTCONV_FORWARD_CHAR:
147 /* Move forward by query->factor characters. */
148 if (INT_ADD_WRAPV (pos, query->factor, &end) || end > ZV)
149 end = ZV;
150
151 end_byte = CHAR_TO_BYTE (end);
152 break;
153
154 case TEXTCONV_BACKWARD_CHAR:
155 /* Move backward by query->factor characters. */
156 if (INT_SUBTRACT_WRAPV (pos, query->factor, &end) || end < BEGV)
157 end = BEGV;
158
159 end_byte = CHAR_TO_BYTE (end);
160 break;
161
162 case TEXTCONV_FORWARD_WORD:
163 /* Move forward by query->factor word. */
164 end = scan_words (pos, (EMACS_INT) query->factor);
165
166 if (!end)
167 {
168 end = ZV;
169 end_byte = ZV_BYTE;
170 }
171 else
172 end_byte = CHAR_TO_BYTE (end);
173
174 break;
175
176 case TEXTCONV_BACKWARD_WORD:
177 /* Move backwards by query->factor word. */
178 end = scan_words (pos, 0 - (EMACS_INT) query->factor);
179
180 if (!end)
181 {
182 end = BEGV;
183 end_byte = BEGV_BYTE;
184 }
185 else
186 end_byte = CHAR_TO_BYTE (end);
187
188 break;
189
190 case TEXTCONV_CARET_UP:
191 /* Move upwards one visual line, keeping the column intact. */
192 Fvertical_motion (Fcons (Fcurrent_column (), make_fixnum (-1)),
193 Qnil, Qnil);
194 end = PT;
195 end_byte = PT_BYTE;
196 break;
197
198 case TEXTCONV_CARET_DOWN:
199 /* Move downwards one visual line, keeping the column
200 intact. */
201 Fvertical_motion (Fcons (Fcurrent_column (), make_fixnum (1)),
202 Qnil, Qnil);
203 end = PT;
204 end_byte = PT_BYTE;
205 break;
206
207 case TEXTCONV_NEXT_LINE:
208 /* Move one line forward. */
209 scan_newline (pos, pos_byte, ZV, ZV_BYTE,
210 query->factor, false);
211 end = PT;
212 end_byte = PT_BYTE;
213 break;
214
215 case TEXTCONV_PREVIOUS_LINE:
216 /* Move one line backwards. */
217 scan_newline (pos, pos_byte, BEGV, BEGV_BYTE,
218 0 - (EMACS_INT) query->factor, false);
219 end = PT;
220 end_byte = PT_BYTE;
221 break;
222
223 case TEXTCONV_LINE_START:
224 /* Move to the beginning of the line. */
225 Fbeginning_of_line (Qnil);
226 end = PT;
227 end_byte = PT_BYTE;
228 break;
229
230 case TEXTCONV_LINE_END:
231 /* Move to the end of the line. */
232 Fend_of_line (Qnil);
233 end = PT;
234 end_byte = PT_BYTE;
235 break;
236
237 case TEXTCONV_ABSOLUTE_POSITION:
238 /* How to implement this is unclear. */
239 SET_PT (query->factor);
240 end = PT;
241 end_byte = PT_BYTE;
242 break;
243
244 default:
245 unbind_to (count, Qnil);
246 return 1;
247 }
248
249 /* Sort end and pos. */
250
251 if (end < pos)
252 {
253 eassert (end_byte < pos_byte);
254 temp = pos_byte;
255 temp1 = pos;
256 pos_byte = end_byte;
257 pos = end;
258 end = temp1;
259 end_byte = temp;
260 }
261
262 /* Return the string first. */
263 buffer = xmalloc (end_byte - pos_byte);
264 copy_buffer (pos, pos_byte, end, end_byte, buffer);
265 query->text.text = buffer;
266 query->text.length = end - pos;
267 query->text.bytes = end_byte - pos_byte;
268
269 /* Next, perform any operation specified. */
270
271 switch (query->operation)
272 {
273 case TEXTCONV_SUBSTITUTION:
274 if (safe_del_range (pos, end))
275 {
276 /* Undo any changes to the excursion. */
277 unbind_to (count, Qnil);
278 return 1;
279 }
280
281 default:
282 }
283
284 /* Undo any changes to the excursion. */
285 unbind_to (count, Qnil);
286 return 0;
287}
288
289
290
291/* Window system interface. These are called from the rest of
292 Emacs. */
293
294/* Notice that F's selected window has been set from redisplay.
295 Reset F's input method state. */
296
297void
298report_selected_window_change (struct frame *f)
299{
300 if (!text_interface)
301 return;
302
303 text_interface->reset (f);
304}
305
306/* Register INTERFACE as the text conversion interface. */
307
308void
309register_texconv_interface (struct textconv_interface *interface)
310{
311 text_interface = interface;
312}
diff --git a/src/textconv.h b/src/textconv.h
new file mode 100644
index 00000000000..f6e7eb7925f
--- /dev/null
+++ b/src/textconv.h
@@ -0,0 +1,109 @@
1/* String conversion support for graphics terminals.
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20#ifndef _TEXTCONV_H_
21
22#include "lisp.h"
23#include "frame.h"
24
25/* The function pointers in this structure should be filled out by
26 each GUI backend interested in supporting text conversion.
27
28 Finally, register_texconv_interface must be called at some point
29 during terminal initialization. */
30
31struct textconv_interface
32{
33 /* Notice that the text conversion context has changed (which can
34 happen if the window is deleted or switches buffers, or an
35 unexpected buffer change occurs.) */
36 void (*reset) (struct frame *);
37};
38
39
40
41enum textconv_caret_direction
42 {
43 TEXTCONV_FORWARD_CHAR,
44 TEXTCONV_BACKWARD_CHAR,
45 TEXTCONV_FORWARD_WORD,
46 TEXTCONV_BACKWARD_WORD,
47 TEXTCONV_CARET_UP,
48 TEXTCONV_CARET_DOWN,
49 TEXTCONV_NEXT_LINE,
50 TEXTCONV_PREVIOUS_LINE,
51 TEXTCONV_LINE_START,
52 TEXTCONV_LINE_END,
53 TEXTCONV_ABSOLUTE_POSITION,
54 };
55
56enum textconv_operation
57 {
58 TEXTCONV_SUBSTITUTION,
59 TEXTCONV_RETRIEVAL,
60 };
61
62/* Structure describing text in a buffer corresponding to a ``struct
63 textconv_callback_struct''. */
64
65struct textconv_conversion_text
66{
67 /* Length of the text in characters and bytes. */
68 size_t length, bytes;
69
70 /* Pointer to the text data. This must be deallocated by the
71 caller. */
72 char *text;
73};
74
75/* Structure describing a single query submitted by the input
76 method. */
77
78struct textconv_callback_struct
79{
80 /* Character position, relative to the current spot location, from
81 where on text should be returned. */
82 EMACS_INT position;
83
84 /* The type of scanning to perform to determine either the start or
85 the end of the conversion. */
86 enum textconv_caret_direction direction;
87
88 /* The the number of times for which to repeat the scanning in order
89 to determine the starting position of the text to return. */
90 unsigned short factor;
91
92 /* The operation to perform upon the current buffer contents.
93
94 If this is TEXTCONV_SUBSTITUTION, then the text that is returned
95 will be deleted from the buffer itself.
96
97 Otherwise, the text is simply returned without modifying the
98 buffer contents. */
99 enum textconv_operation operation;
100
101 /* Structure that will be filled with a description of the resulting
102 text. */
103 struct textconv_conversion_text text;
104};
105
106extern int textconv_query (struct frame *, struct textconv_callback_struct *);
107extern void register_texconv_interface (struct textconv_interface *);
108
109#endif /* _TEXTCONV_H_ */
diff --git a/src/treesit.c b/src/treesit.c
index cfa3721b5e7..cab2f0d5354 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -1475,6 +1475,15 @@ This symbol is the one used to create the parser. */)
1475 return XTS_PARSER (parser)->language_symbol; 1475 return XTS_PARSER (parser)->language_symbol;
1476} 1476}
1477 1477
1478/* Return true if PARSER is not deleted and its buffer is live. */
1479static bool
1480treesit_parser_live_p (Lisp_Object parser)
1481{
1482 CHECK_TS_PARSER (parser);
1483 return ((!XTS_PARSER (parser)->deleted) &&
1484 (!NILP (Fbuffer_live_p (XTS_PARSER (parser)->buffer))));
1485}
1486
1478/*** Parser API */ 1487/*** Parser API */
1479 1488
1480DEFUN ("treesit-parser-root-node", 1489DEFUN ("treesit-parser-root-node",
@@ -1908,7 +1917,8 @@ DEFUN ("treesit-node-check",
1908 Ftreesit_node_check, Streesit_node_check, 2, 2, 0, 1917 Ftreesit_node_check, Streesit_node_check, 2, 2, 0,
1909 doc: /* Return non-nil if NODE has PROPERTY, nil otherwise. 1918 doc: /* Return non-nil if NODE has PROPERTY, nil otherwise.
1910 1919
1911PROPERTY could be `named', `missing', `extra', `outdated', or `has-error'. 1920PROPERTY could be `named', `missing', `extra', `outdated',
1921`has-error', or `live'.
1912 1922
1913Named nodes correspond to named rules in the language definition, 1923Named nodes correspond to named rules in the language definition,
1914whereas "anonymous" nodes correspond to string literals in the 1924whereas "anonymous" nodes correspond to string literals in the
@@ -1924,7 +1934,10 @@ A node is "outdated" if the parser has reparsed at least once after
1924the node was created. 1934the node was created.
1925 1935
1926A node "has error" if itself is a syntax error or contains any syntax 1936A node "has error" if itself is a syntax error or contains any syntax
1927errors. */) 1937errors.
1938
1939A node is "live" if its parser is not deleted and its buffer is
1940live. */)
1928 (Lisp_Object node, Lisp_Object property) 1941 (Lisp_Object node, Lisp_Object property)
1929{ 1942{
1930 if (NILP (node)) return Qnil; 1943 if (NILP (node)) return Qnil;
@@ -1947,9 +1960,11 @@ errors. */)
1947 result = ts_node_is_extra (treesit_node); 1960 result = ts_node_is_extra (treesit_node);
1948 else if (EQ (property, Qhas_error)) 1961 else if (EQ (property, Qhas_error))
1949 result = ts_node_has_error (treesit_node); 1962 result = ts_node_has_error (treesit_node);
1963 else if (EQ (property, Qlive))
1964 result = treesit_parser_live_p (XTS_NODE (node)->parser);
1950 else 1965 else
1951 signal_error ("Expecting `named', `missing', `extra', " 1966 signal_error ("Expecting `named', `missing', `extra', "
1952 "`outdated', or `has-error', but got", 1967 "`outdated', `has-error', or `live', but got",
1953 property); 1968 property);
1954 return result ? Qt : Qnil; 1969 return result ? Qt : Qnil;
1955} 1970}
@@ -3135,13 +3150,13 @@ the way. PREDICATE is a regexp string that matches against each
3135node's type, or a function that takes a node and returns nil/non-nil. 3150node's type, or a function that takes a node and returns nil/non-nil.
3136 3151
3137By default, only traverse named nodes, but if ALL is non-nil, traverse 3152By default, only traverse named nodes, but if ALL is non-nil, traverse
3138all nodes. If BACKWARD is non-nil, traverse backwards. If LIMIT is 3153all nodes. If BACKWARD is non-nil, traverse backwards. If DEPTH is
3139non-nil, only traverse nodes up to that number of levels down in the 3154non-nil, only traverse nodes up to that number of levels down in the
3140tree. If LIMIT is nil, default to 1000. 3155tree. If DEPTH is nil, default to 1000.
3141 3156
3142Return the first matched node, or nil if none matches. */) 3157Return the first matched node, or nil if none matches. */)
3143 (Lisp_Object node, Lisp_Object predicate, Lisp_Object backward, 3158 (Lisp_Object node, Lisp_Object predicate, Lisp_Object backward,
3144 Lisp_Object all, Lisp_Object limit) 3159 Lisp_Object all, Lisp_Object depth)
3145{ 3160{
3146 CHECK_TS_NODE (node); 3161 CHECK_TS_NODE (node);
3147 CHECK_TYPE (STRINGP (predicate) || FUNCTIONP (predicate), 3162 CHECK_TYPE (STRINGP (predicate) || FUNCTIONP (predicate),
@@ -3152,10 +3167,10 @@ Return the first matched node, or nil if none matches. */)
3152 /* We use a default limit of 1000. See bug#59426 for the 3167 /* We use a default limit of 1000. See bug#59426 for the
3153 discussion. */ 3168 discussion. */
3154 ptrdiff_t the_limit = treesit_recursion_limit; 3169 ptrdiff_t the_limit = treesit_recursion_limit;
3155 if (!NILP (limit)) 3170 if (!NILP (depth))
3156 { 3171 {
3157 CHECK_FIXNUM (limit); 3172 CHECK_FIXNUM (depth);
3158 the_limit = XFIXNUM (limit); 3173 the_limit = XFIXNUM (depth);
3159 } 3174 }
3160 3175
3161 treesit_initialize (); 3176 treesit_initialize ();
@@ -3307,8 +3322,8 @@ If PROCESS-FN is non-nil, it should be a function of one argument. In
3307that case, instead of returning the matched nodes, pass each node to 3322that case, instead of returning the matched nodes, pass each node to
3308PROCESS-FN, and use its return value instead. 3323PROCESS-FN, and use its return value instead.
3309 3324
3310If non-nil, LIMIT is the number of levels to go down the tree from 3325If non-nil, DEPTH is the number of levels to go down the tree from
3311ROOT. If LIMIT is nil or omitted, it defaults to 1000. 3326ROOT. If DEPTH is nil or omitted, it defaults to 1000.
3312 3327
3313Each node in the returned tree looks like (NODE . (CHILD ...)). The 3328Each node in the returned tree looks like (NODE . (CHILD ...)). The
3314root of this tree might be nil, if ROOT doesn't match PREDICATE. 3329root of this tree might be nil, if ROOT doesn't match PREDICATE.
@@ -3319,7 +3334,7 @@ PREDICATE can also be a function that takes a node and returns
3319nil/non-nil, but it is slower and more memory consuming than using 3334nil/non-nil, but it is slower and more memory consuming than using
3320a regexp. */) 3335a regexp. */)
3321 (Lisp_Object root, Lisp_Object predicate, Lisp_Object process_fn, 3336 (Lisp_Object root, Lisp_Object predicate, Lisp_Object process_fn,
3322 Lisp_Object limit) 3337 Lisp_Object depth)
3323{ 3338{
3324 CHECK_TS_NODE (root); 3339 CHECK_TS_NODE (root);
3325 CHECK_TYPE (STRINGP (predicate) || FUNCTIONP (predicate), 3340 CHECK_TYPE (STRINGP (predicate) || FUNCTIONP (predicate),
@@ -3331,10 +3346,10 @@ a regexp. */)
3331 /* We use a default limit of 1000. See bug#59426 for the 3346 /* We use a default limit of 1000. See bug#59426 for the
3332 discussion. */ 3347 discussion. */
3333 ptrdiff_t the_limit = treesit_recursion_limit; 3348 ptrdiff_t the_limit = treesit_recursion_limit;
3334 if (!NILP (limit)) 3349 if (!NILP (depth))
3335 { 3350 {
3336 CHECK_FIXNUM (limit); 3351 CHECK_FIXNUM (depth);
3337 the_limit = XFIXNUM (limit); 3352 the_limit = XFIXNUM (depth);
3338 } 3353 }
3339 3354
3340 treesit_initialize (); 3355 treesit_initialize ();
@@ -3448,6 +3463,7 @@ syms_of_treesit (void)
3448 DEFSYM (Qextra, "extra"); 3463 DEFSYM (Qextra, "extra");
3449 DEFSYM (Qoutdated, "outdated"); 3464 DEFSYM (Qoutdated, "outdated");
3450 DEFSYM (Qhas_error, "has-error"); 3465 DEFSYM (Qhas_error, "has-error");
3466 DEFSYM (Qlive, "live");
3451 3467
3452 DEFSYM (QCanchor, ":anchor"); 3468 DEFSYM (QCanchor, ":anchor");
3453 DEFSYM (QCequal, ":equal"); 3469 DEFSYM (QCequal, ":equal");
diff --git a/src/window.c b/src/window.c
index 6201a6f4a36..9334f922f89 100644
--- a/src/window.c
+++ b/src/window.c
@@ -3856,6 +3856,9 @@ run_window_change_functions_1 (Lisp_Object symbol, Lisp_Object buffer,
3856 * 3856 *
3857 * This function does not save and restore match data. Any functions 3857 * This function does not save and restore match data. Any functions
3858 * it calls are responsible for doing that themselves. 3858 * it calls are responsible for doing that themselves.
3859 *
3860 * Additionally, report changes to each frame's selected window to the
3861 * input method in textconv.c.
3859 */ 3862 */
3860void 3863void
3861run_window_change_functions (void) 3864run_window_change_functions (void)
@@ -4015,6 +4018,18 @@ run_window_change_functions (void)
4015 run_window_change_functions_1 4018 run_window_change_functions_1
4016 (Qwindow_selection_change_functions, Qnil, frame); 4019 (Qwindow_selection_change_functions, Qnil, frame);
4017 4020
4021#if defined HAVE_TEXT_CONVERSION
4022
4023 /* If the buffer or selected window has changed, also reset the
4024 input method composition state. */
4025
4026 if ((frame_selected_window_change || frame_buffer_change)
4027 && FRAME_LIVE_P (f)
4028 && FRAME_WINDOW_P (f))
4029 report_selected_window_change (f);
4030
4031#endif
4032
4018 /* A frame has changed state when a size or buffer change 4033 /* A frame has changed state when a size or buffer change
4019 occurred, its selected window has changed, when it was 4034 occurred, its selected window has changed, when it was
4020 (de-)selected or its window state change flag was set. */ 4035 (de-)selected or its window state change flag was set. */
diff --git a/src/xfns.c b/src/xfns.c
index 3a129211463..9e004f6a678 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -37,6 +37,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
37#include "termhooks.h" 37#include "termhooks.h"
38#include "font.h" 38#include "font.h"
39 39
40#ifdef HAVE_X_I18N
41#include "textconv.h"
42#endif
43
40#include <sys/types.h> 44#include <sys/types.h>
41#include <sys/stat.h> 45#include <sys/stat.h>
42 46
@@ -2671,24 +2675,50 @@ append_wm_protocols (struct x_display_info *dpyinfo,
2671 2675
2672#ifdef HAVE_X_I18N 2676#ifdef HAVE_X_I18N
2673 2677
2674static void xic_preedit_draw_callback (XIC, XPointer, XIMPreeditDrawCallbackStruct *); 2678static void xic_preedit_draw_callback (XIC, XPointer,
2675static void xic_preedit_caret_callback (XIC, XPointer, XIMPreeditCaretCallbackStruct *); 2679 XIMPreeditDrawCallbackStruct *);
2680static void xic_preedit_caret_callback (XIC, XPointer,
2681 XIMPreeditCaretCallbackStruct *);
2676static void xic_preedit_done_callback (XIC, XPointer, XPointer); 2682static void xic_preedit_done_callback (XIC, XPointer, XPointer);
2677static int xic_preedit_start_callback (XIC, XPointer, XPointer); 2683static int xic_preedit_start_callback (XIC, XPointer, XPointer);
2684static void xic_string_conversion_callback (XIC, XPointer,
2685 XIMStringConversionCallbackStruct *);
2678 2686
2679#ifndef HAVE_XICCALLBACK_CALLBACK 2687#ifndef HAVE_XICCALLBACK_CALLBACK
2680#define XICCallback XIMCallback 2688#define XICCallback XIMCallback
2681#define XICProc XIMProc 2689#define XICProc XIMProc
2682#endif 2690#endif
2683 2691
2684static XIMCallback Xxic_preedit_draw_callback = { NULL, 2692static XIMCallback Xxic_preedit_draw_callback =
2685 (XIMProc) xic_preedit_draw_callback }; 2693 {
2686static XIMCallback Xxic_preedit_caret_callback = { NULL, 2694 NULL,
2687 (XIMProc) xic_preedit_caret_callback }; 2695 (XIMProc) xic_preedit_draw_callback,
2688static XIMCallback Xxic_preedit_done_callback = { NULL, 2696 };
2689 (XIMProc) xic_preedit_done_callback }; 2697
2690static XICCallback Xxic_preedit_start_callback = { NULL, 2698static XIMCallback Xxic_preedit_caret_callback =
2691 (XICProc) xic_preedit_start_callback }; 2699 {
2700 NULL,
2701 (XIMProc) xic_preedit_caret_callback,
2702 };
2703
2704static XIMCallback Xxic_preedit_done_callback =
2705 {
2706 NULL,
2707 (XIMProc) xic_preedit_done_callback,
2708 };
2709
2710static XICCallback Xxic_preedit_start_callback =
2711 {
2712 NULL,
2713 (XICProc) xic_preedit_start_callback,
2714 };
2715
2716static XIMCallback Xxic_string_conversion_callback =
2717 {
2718 /* This is actually an XICCallback! */
2719 NULL,
2720 (XIMProc) xic_string_conversion_callback,
2721 };
2692 2722
2693#if defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT 2723#if defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT
2694/* Create an X fontset on frame F with base font name BASE_FONTNAME. */ 2724/* Create an X fontset on frame F with base font name BASE_FONTNAME. */
@@ -3094,6 +3124,8 @@ create_frame_xic (struct frame *f)
3094 XNFocusWindow, FRAME_X_WINDOW (f), 3124 XNFocusWindow, FRAME_X_WINDOW (f),
3095 XNStatusAttributes, status_attr, 3125 XNStatusAttributes, status_attr,
3096 XNPreeditAttributes, preedit_attr, 3126 XNPreeditAttributes, preedit_attr,
3127 XNStringConversionCallback,
3128 &Xxic_string_conversion_callback,
3097 NULL); 3129 NULL);
3098 else if (preedit_attr) 3130 else if (preedit_attr)
3099 xic = XCreateIC (xim, 3131 xic = XCreateIC (xim,
@@ -3101,6 +3133,8 @@ create_frame_xic (struct frame *f)
3101 XNClientWindow, FRAME_X_WINDOW (f), 3133 XNClientWindow, FRAME_X_WINDOW (f),
3102 XNFocusWindow, FRAME_X_WINDOW (f), 3134 XNFocusWindow, FRAME_X_WINDOW (f),
3103 XNPreeditAttributes, preedit_attr, 3135 XNPreeditAttributes, preedit_attr,
3136 XNStringConversionCallback,
3137 &Xxic_string_conversion_callback,
3104 NULL); 3138 NULL);
3105 else if (status_attr) 3139 else if (status_attr)
3106 xic = XCreateIC (xim, 3140 xic = XCreateIC (xim,
@@ -3108,12 +3142,16 @@ create_frame_xic (struct frame *f)
3108 XNClientWindow, FRAME_X_WINDOW (f), 3142 XNClientWindow, FRAME_X_WINDOW (f),
3109 XNFocusWindow, FRAME_X_WINDOW (f), 3143 XNFocusWindow, FRAME_X_WINDOW (f),
3110 XNStatusAttributes, status_attr, 3144 XNStatusAttributes, status_attr,
3145 XNStringConversionCallback,
3146 &Xxic_string_conversion_callback,
3111 NULL); 3147 NULL);
3112 else 3148 else
3113 xic = XCreateIC (xim, 3149 xic = XCreateIC (xim,
3114 XNInputStyle, xic_style, 3150 XNInputStyle, xic_style,
3115 XNClientWindow, FRAME_X_WINDOW (f), 3151 XNClientWindow, FRAME_X_WINDOW (f),
3116 XNFocusWindow, FRAME_X_WINDOW (f), 3152 XNFocusWindow, FRAME_X_WINDOW (f),
3153 XNStringConversionCallback,
3154 &Xxic_string_conversion_callback,
3117 NULL); 3155 NULL);
3118 3156
3119 if (!xic) 3157 if (!xic)
@@ -3377,6 +3415,7 @@ struct x_xim_text_conversion_data
3377 struct coding_system *coding; 3415 struct coding_system *coding;
3378 char *source; 3416 char *source;
3379 struct x_display_info *dpyinfo; 3417 struct x_display_info *dpyinfo;
3418 size_t size;
3380}; 3419};
3381 3420
3382static Lisp_Object 3421static Lisp_Object
@@ -3412,6 +3451,38 @@ x_xim_text_to_utf8_unix_1 (ptrdiff_t nargs, Lisp_Object *args)
3412} 3451}
3413 3452
3414static Lisp_Object 3453static Lisp_Object
3454x_encode_xim_text_1 (ptrdiff_t nargs, Lisp_Object *args)
3455{
3456 struct x_xim_text_conversion_data *data;
3457 ptrdiff_t nbytes;
3458 Lisp_Object coding_system;
3459
3460 data = xmint_pointer (args[0]);
3461
3462 if (SYMBOLP (Vx_input_coding_system))
3463 coding_system = Vx_input_coding_system;
3464 else if (!NILP (data->dpyinfo->xim_coding))
3465 coding_system = data->dpyinfo->xim_coding;
3466 else
3467 coding_system = Vlocale_coding_system;
3468
3469 nbytes = data->size;
3470
3471 data->coding->destination = NULL;
3472
3473 setup_coding_system (coding_system, data->coding);
3474 data->coding->mode |= (CODING_MODE_LAST_BLOCK
3475 | CODING_MODE_SAFE_ENCODING);
3476 data->coding->source = (const unsigned char *) data->source;
3477 data->coding->dst_bytes = 2048;
3478 data->coding->destination = xmalloc (2048);
3479 encode_coding_object (data->coding, Qnil, 0, 0,
3480 nbytes, nbytes, Qnil);
3481
3482 return Qnil;
3483}
3484
3485static Lisp_Object
3415x_xim_text_to_utf8_unix_2 (Lisp_Object val, ptrdiff_t nargs, 3486x_xim_text_to_utf8_unix_2 (Lisp_Object val, ptrdiff_t nargs,
3416 Lisp_Object *args) 3487 Lisp_Object *args)
3417{ 3488{
@@ -3468,6 +3539,46 @@ x_xim_text_to_utf8_unix (struct x_display_info *dpyinfo,
3468 return (char *) coding.destination; 3539 return (char *) coding.destination;
3469} 3540}
3470 3541
3542/* Convert SIZE bytes of the specified text from Emacs's internal
3543 coding system to the input method coding system. Return the
3544 result, its byte length in *LENGTH, and its character length in
3545 *CHARS, or NULL.
3546
3547 The string returned is not NULL terminated. */
3548
3549static char *
3550x_encode_xim_text (struct x_display_info *dpyinfo, char *text,
3551 size_t size, ptrdiff_t *length,
3552 ptrdiff_t *chars)
3553{
3554 struct coding_system coding;
3555 struct x_xim_text_conversion_data data;
3556 Lisp_Object arg;
3557 bool was_waiting_for_input_p;
3558
3559 data.coding = &coding;
3560 data.source = text;
3561 data.dpyinfo = dpyinfo;
3562 data.size = size;
3563
3564 was_waiting_for_input_p = waiting_for_input;
3565 /* Otherwise Fsignal will crash. */
3566 waiting_for_input = false;
3567
3568 arg = make_mint_ptr (&data);
3569 internal_condition_case_n (x_encode_xim_text_1, 1, &arg,
3570 Qt, x_xim_text_to_utf8_unix_2);
3571 waiting_for_input = was_waiting_for_input_p;
3572
3573 if (length)
3574 *length = coding.produced;
3575
3576 if (chars)
3577 *chars = coding.produced_char;
3578
3579 return (char *) coding.destination;
3580}
3581
3471static void 3582static void
3472xic_preedit_draw_callback (XIC xic, XPointer client_data, 3583xic_preedit_draw_callback (XIC xic, XPointer client_data,
3473 XIMPreeditDrawCallbackStruct *call_data) 3584 XIMPreeditDrawCallbackStruct *call_data)
@@ -3664,6 +3775,128 @@ xic_set_xfontset (struct frame *f, const char *base_fontname)
3664 FRAME_XIC_FONTSET (f) = xfs; 3775 FRAME_XIC_FONTSET (f) = xfs;
3665} 3776}
3666 3777
3778
3779
3780/* String conversion support. See textconv.c for more details. */
3781
3782static void
3783xic_string_conversion_callback (XIC ic, XPointer client_data,
3784 XIMStringConversionCallbackStruct *call_data)
3785{
3786 struct textconv_callback_struct request;
3787 ptrdiff_t length;
3788 struct frame *f;
3789 int rc;
3790
3791 /* Find the frame associated with this IC. */
3792 f = x_xic_to_frame (ic);
3793
3794 if (!f)
3795 goto failure;
3796
3797 /* Fill in CALL_DATA as early as possible. */
3798 call_data->text->feedback = NULL;
3799 call_data->text->encoding_is_wchar = False;
3800
3801 /* Now translate the conversion request to the format understood by
3802 textconv.c. */
3803 request.position = call_data->position;
3804
3805 switch (call_data->direction)
3806 {
3807 case XIMForwardChar:
3808 request.direction = TEXTCONV_FORWARD_CHAR;
3809 break;
3810
3811 case XIMBackwardChar:
3812 request.direction = TEXTCONV_BACKWARD_CHAR;
3813 break;
3814
3815 case XIMForwardWord:
3816 request.direction = TEXTCONV_FORWARD_WORD;
3817 break;
3818
3819 case XIMBackwardWord:
3820 request.direction = TEXTCONV_BACKWARD_WORD;
3821 break;
3822
3823 case XIMCaretUp:
3824 request.direction = TEXTCONV_CARET_UP;
3825 break;
3826
3827 case XIMCaretDown:
3828 request.direction = TEXTCONV_CARET_DOWN;
3829 break;
3830
3831 case XIMNextLine:
3832 request.direction = TEXTCONV_NEXT_LINE;
3833 break;
3834
3835 case XIMPreviousLine:
3836 request.direction = TEXTCONV_PREVIOUS_LINE;
3837 break;
3838
3839 case XIMLineStart:
3840 request.direction = TEXTCONV_LINE_START;
3841 break;
3842
3843 case XIMLineEnd:
3844 request.direction = TEXTCONV_LINE_END;
3845 break;
3846
3847 case XIMAbsolutePosition:
3848 request.direction = TEXTCONV_ABSOLUTE_POSITION;
3849 break;
3850
3851 default:
3852 goto failure;
3853 }
3854
3855 /* factor is signed in call_data but is actually a CARD16. */
3856 request.factor = call_data->factor;
3857
3858 if (call_data->operation == XIMStringConversionSubstitution)
3859 request.operation = TEXTCONV_SUBSTITUTION;
3860 else
3861 request.operation = TEXTCONV_RETRIEVAL;
3862
3863 /* Now perform the string conversion. */
3864 rc = textconv_query (f, &request);
3865
3866 if (rc)
3867 {
3868 xfree (request.text.text);
3869 goto failure;
3870 }
3871
3872 /* Encode the text in the locale coding system and give it back to
3873 the input method. */
3874 request.text.text = NULL;
3875 call_data->text->string.mbs
3876 = x_encode_xim_text (FRAME_DISPLAY_INFO (f),
3877 request.text.text,
3878 request.text.bytes, NULL,
3879 &length);
3880 call_data->text->length = length;
3881
3882 /* Free the encoded text. This is always set to something
3883 valid. */
3884 xfree (request.text.text);
3885
3886 /* Detect failure. */
3887 if (!call_data->text->string.mbs)
3888 goto failure;
3889
3890 return;
3891
3892 failure:
3893 /* Return a string of length 0 using the C library malloc. This
3894 assumes XFree is able to free data allocated with our malloc
3895 wrapper. */
3896 call_data->text->length = 0;
3897 call_data->text->string.mbs = malloc (0);
3898}
3899
3667#endif /* HAVE_X_I18N */ 3900#endif /* HAVE_X_I18N */
3668 3901
3669 3902
@@ -9771,6 +10004,53 @@ This should be called from a variable watcher for `x-gtk-use-native-input'. */)
9771 10004
9772 return Qnil; 10005 return Qnil;
9773} 10006}
10007
10008#if 0
10009
10010DEFUN ("x-test-string-conversion", Fx_test_string_conversion,
10011 Sx_test_string_conversion, 5, 5, 0,
10012 doc: /* Perform tests on the XIM string conversion support. */)
10013 (Lisp_Object frame, Lisp_Object position,
10014 Lisp_Object direction, Lisp_Object operation, Lisp_Object factor)
10015{
10016 struct frame *f;
10017 XIMStringConversionCallbackStruct call_data;
10018 XIMStringConversionText text;
10019
10020 f = decode_window_system_frame (frame);
10021
10022 if (!FRAME_XIC (f))
10023 error ("No XIC on FRAME!");
10024
10025 CHECK_FIXNUM (position);
10026 CHECK_FIXNUM (direction);
10027 CHECK_FIXNUM (operation);
10028 CHECK_FIXNUM (factor);
10029
10030 /* xic_string_conversion_callback (XIC ic, XPointer client_data,
10031 XIMStringConversionCallbackStruct *call_data) */
10032
10033 call_data.position = XFIXNUM (position);
10034 call_data.direction = XFIXNUM (direction);
10035 call_data.operation = XFIXNUM (operation);
10036 call_data.factor = XFIXNUM (factor);
10037 call_data.text = &text;
10038
10039 block_input ();
10040 xic_string_conversion_callback (FRAME_XIC (f), NULL,
10041 &call_data);
10042 unblock_input ();
10043
10044 /* Place a breakpoint here to inspect TEXT! */
10045
10046 while (1)
10047 maybe_quit ();
10048
10049 return Qnil;
10050}
10051
10052#endif
10053
9774 10054
9775/*********************************************************************** 10055/***********************************************************************
9776 Initialization 10056 Initialization
@@ -10217,6 +10497,9 @@ eliminated in future versions of Emacs. */);
10217 defsubr (&Sx_display_set_last_user_time); 10497 defsubr (&Sx_display_set_last_user_time);
10218 defsubr (&Sx_translate_coordinates); 10498 defsubr (&Sx_translate_coordinates);
10219 defsubr (&Sx_get_modifier_masks); 10499 defsubr (&Sx_get_modifier_masks);
10500#if 0
10501 defsubr (&Sx_test_string_conversion);
10502#endif
10220 10503
10221 tip_timer = Qnil; 10504 tip_timer = Qnil;
10222 staticpro (&tip_timer); 10505 staticpro (&tip_timer);
diff --git a/src/xterm.c b/src/xterm.c
index eeefed34d4b..ccaacec2c57 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -636,6 +636,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
636#include "xterm.h" 636#include "xterm.h"
637#include <X11/cursorfont.h> 637#include <X11/cursorfont.h>
638 638
639#ifdef HAVE_X_I18N
640#include "textconv.h"
641#endif
642
639#ifdef USE_XCB 643#ifdef USE_XCB
640#include <xcb/xproto.h> 644#include <xcb/xproto.h>
641#include <xcb/xcb.h> 645#include <xcb/xcb.h>
@@ -31565,7 +31569,37 @@ x_initialize (void)
31565 XSetIOErrorHandler (x_io_error_quitter); 31569 XSetIOErrorHandler (x_io_error_quitter);
31566} 31570}
31567 31571
31568#ifdef USE_GTK 31572#ifdef HAVE_X_I18N
31573
31574/* Notice that a change has occured on F that requires its input
31575 method state to be reset. */
31576
31577static void
31578x_reset_conversion (struct frame *f)
31579{
31580 char *string;
31581
31582 if (FRAME_XIC (f))
31583 {
31584 string = XmbResetIC (FRAME_XIC (f));
31585
31586 /* string is actually any string that was being composed at the
31587 time of the reset. */
31588
31589 if (string)
31590 XFree (string);
31591 }
31592}
31593
31594/* Interface used to control input method ``text conversion''. */
31595
31596static struct textconv_interface text_conversion_interface =
31597 {
31598 x_reset_conversion,
31599 };
31600
31601#endif
31602
31569void 31603void
31570init_xterm (void) 31604init_xterm (void)
31571{ 31605{
@@ -31579,8 +31613,11 @@ init_xterm (void)
31579 gdk_disable_multidevice (); 31613 gdk_disable_multidevice ();
31580#endif 31614#endif
31581#endif 31615#endif
31582} 31616
31617#ifdef HAVE_X_I18N
31618 register_texconv_interface (&text_conversion_interface);
31583#endif 31619#endif
31620}
31584 31621
31585void 31622void
31586mark_xterm (void) 31623mark_xterm (void)