Commit | Line | Data |
---|---|---|
e9e23e23 | 1 | /* Selection processing for Emacs on the Microsoft W32 API. |
ee78dc32 GV |
2 | Copyright (C) 1993, 1994 Free Software Foundation. |
3 | ||
3b7ad313 EN |
4 | This file is part of GNU Emacs. |
5 | ||
6 | GNU Emacs is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GNU Emacs is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GNU Emacs; see the file COPYING. If not, write to | |
18 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 | Boston, MA 02111-1307, USA. */ | |
ee78dc32 GV |
20 | |
21 | /* Written by Kevin Gallo */ | |
22 | ||
23 | #include <config.h> | |
24 | #include "lisp.h" | |
fbd6baed | 25 | #include "w32term.h" /* for all of the w32 includes */ |
ee78dc32 | 26 | #include "dispextern.h" /* frame.h seems to want this */ |
3e4731a3 | 27 | #include "keyboard.h" |
ee78dc32 GV |
28 | #include "frame.h" /* Need this to get the X window of selected_frame */ |
29 | #include "blockinput.h" | |
bbb059f3 AI |
30 | #include "buffer.h" |
31 | #include "charset.h" | |
32 | #include "coding.h" | |
ee78dc32 | 33 | |
9aa94bd5 KH |
34 | Lisp_Object QCLIPBOARD; |
35 | ||
bbb059f3 AI |
36 | /* Coding system for communicating with other Windows programs via the |
37 | clipboard. */ | |
72aca5fa | 38 | static Lisp_Object Vselection_coding_system; |
bbb059f3 | 39 | |
06466d9a | 40 | /* Coding system for the next communicating with other Windows programs. */ |
93cbf229 GV |
41 | static Lisp_Object Vnext_selection_coding_system; |
42 | ||
06466d9a JR |
43 | /* The last text we put into the clipboard. This is used to prevent |
44 | passing back our own text from the clipboard, instead of using the | |
45 | kill ring. The former is undesirable because the clipboard data | |
46 | could be MULEtilated by inappropriately chosen | |
47 | (next-)selection-coding-system. For this reason, we must store the | |
48 | text *after* it was encoded/Unix-to-DOS-converted. */ | |
49 | static unsigned char *last_clipboard_text = NULL; | |
50 | static size_t clipboard_storage_size = 0; | |
51 | ||
ee78dc32 | 52 | #if 0 |
fbd6baed | 53 | DEFUN ("w32-open-clipboard", Fw32_open_clipboard, Sw32_open_clipboard, 0, 1, 0, |
ee78dc32 GV |
54 | "This opens the clipboard with the given frame pointer.") |
55 | (frame) | |
56 | Lisp_Object frame; | |
57 | { | |
58 | BOOL ok = FALSE; | |
59 | ||
60 | if (!NILP (frame)) | |
61 | CHECK_LIVE_FRAME (frame, 0); | |
62 | ||
63 | BLOCK_INPUT; | |
64 | ||
fbd6baed | 65 | ok = OpenClipboard ((!NILP (frame) && FRAME_W32_P (XFRAME (frame))) ? FRAME_W32_WINDOW (XFRAME (frame)) : NULL); |
ee78dc32 GV |
66 | |
67 | UNBLOCK_INPUT; | |
68 | ||
69 | return (ok ? frame : Qnil); | |
70 | } | |
71 | ||
fbd6baed | 72 | DEFUN ("w32-empty-clipboard", Fw32_empty_clipboard, Sw32_empty_clipboard, 0, 0, 0, |
ee78dc32 GV |
73 | "This empties the clipboard and assigns ownership to the window which opened the clipboard.") |
74 | () | |
75 | { | |
76 | BOOL ok = FALSE; | |
77 | ||
78 | BLOCK_INPUT; | |
79 | ||
80 | ok = EmptyClipboard (); | |
81 | ||
82 | UNBLOCK_INPUT; | |
83 | ||
84 | return (ok ? Qt : Qnil); | |
85 | } | |
86 | ||
fbd6baed | 87 | DEFUN ("w32-close-clipboard", Fw32_close_clipboard, Sw32_close_clipboard, 0, 0, 0, |
ee78dc32 GV |
88 | "This closes the clipboard.") |
89 | () | |
90 | { | |
91 | BOOL ok = FALSE; | |
92 | ||
93 | BLOCK_INPUT; | |
94 | ||
95 | ok = CloseClipboard (); | |
96 | ||
97 | UNBLOCK_INPUT; | |
98 | ||
99 | return (ok ? Qt : Qnil); | |
100 | } | |
101 | ||
102 | #endif | |
103 | ||
fbd6baed | 104 | DEFUN ("w32-set-clipboard-data", Fw32_set_clipboard_data, Sw32_set_clipboard_data, 1, 2, 0, |
ee78dc32 GV |
105 | "This sets the clipboard data to the given text.") |
106 | (string, frame) | |
107 | Lisp_Object string, frame; | |
108 | { | |
109 | BOOL ok = TRUE; | |
110 | HANDLE htext; | |
69cddef0 | 111 | int nbytes; |
0ece9ef6 | 112 | int truelen, nlines = 0; |
69cddef0 GV |
113 | unsigned char *src; |
114 | unsigned char *dst; | |
0ece9ef6 | 115 | |
ee78dc32 GV |
116 | CHECK_STRING (string, 0); |
117 | ||
118 | if (!NILP (frame)) | |
119 | CHECK_LIVE_FRAME (frame, 0); | |
120 | ||
121 | BLOCK_INPUT; | |
69cddef0 | 122 | |
bbb059f3 | 123 | nbytes = STRING_BYTES (XSTRING (string)) + 1; |
69cddef0 | 124 | src = XSTRING (string)->data; |
0ece9ef6 AI |
125 | dst = src; |
126 | ||
127 | /* We need to know how many lines there are, since we need CRLF line | |
128 | termination for compatibility with other Windows Programs. | |
129 | avoid using strchr because it recomputes the length every time */ | |
130 | while ((dst = memchr (dst, '\n', nbytes - (dst - src))) != NULL) | |
131 | { | |
132 | nlines++; | |
133 | dst++; | |
134 | } | |
69cddef0 | 135 | |
bbb059f3 AI |
136 | { |
137 | /* Since we are now handling multilingual text, we must consider | |
138 | encoding text for the clipboard. */ | |
69ebbf81 | 139 | int charset_info = find_charset_in_text (src, XSTRING (string)->size, |
11f292ed | 140 | nbytes, NULL, Qnil); |
bbb059f3 | 141 | |
69ebbf81 | 142 | if (charset_info == 0) |
bbb059f3 AI |
143 | { |
144 | /* No multibyte character in OBJ. We need not encode it. */ | |
69cddef0 | 145 | |
c0ca703b | 146 | /* Need to know final size after CR chars are inserted (the |
bbb059f3 | 147 | standard CF_TEXT clipboard format uses CRLF line endings, |
c0ca703b | 148 | while Emacs uses just LF internally). */ |
69cddef0 | 149 | |
0ece9ef6 | 150 | truelen = nbytes + nlines; |
69cddef0 | 151 | |
bbb059f3 AI |
152 | if ((htext = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, truelen)) == NULL) |
153 | goto error; | |
154 | ||
155 | if ((dst = (unsigned char *) GlobalLock (htext)) == NULL) | |
156 | goto error; | |
ee78dc32 | 157 | |
bbb059f3 AI |
158 | /* convert to CRLF line endings expected by clipboard */ |
159 | while (1) | |
160 | { | |
161 | unsigned char *next; | |
162 | /* copy next line or remaining bytes including '\0' */ | |
163 | next = _memccpy (dst, src, '\n', nbytes); | |
164 | if (next) | |
165 | { | |
166 | /* copied one line ending with '\n' */ | |
167 | int copied = next - dst; | |
168 | nbytes -= copied; | |
169 | src += copied; | |
170 | /* insert '\r' before '\n' */ | |
171 | next[-1] = '\r'; | |
172 | next[0] = '\n'; | |
173 | dst = next + 1; | |
174 | } | |
175 | else | |
176 | /* copied remaining partial line -> now finished */ | |
177 | break; | |
178 | } | |
ee78dc32 | 179 | |
bbb059f3 | 180 | GlobalUnlock (htext); |
0108f679 AI |
181 | |
182 | Vlast_coding_system_used = Qraw_text; | |
bbb059f3 AI |
183 | } |
184 | else | |
185 | { | |
06466d9a JR |
186 | /* We must encode contents of OBJ to the selection coding |
187 | system. */ | |
bbb059f3 AI |
188 | int bufsize; |
189 | struct coding_system coding; | |
190 | HANDLE htext2; | |
191 | ||
93cbf229 GV |
192 | if (NILP (Vnext_selection_coding_system)) |
193 | Vnext_selection_coding_system = Vselection_coding_system; | |
bbb059f3 | 194 | setup_coding_system |
93cbf229 | 195 | (Fcheck_coding_system (Vnext_selection_coding_system), &coding); |
69ebbf81 KH |
196 | coding.src_multibyte = 1; |
197 | coding.dst_multibyte = 0; | |
93cbf229 | 198 | Vnext_selection_coding_system = Qnil; |
bbb059f3 | 199 | coding.mode |= CODING_MODE_LAST_BLOCK; |
43df7d0b | 200 | bufsize = encoding_buffer_size (&coding, nbytes); |
bbb059f3 AI |
201 | if ((htext = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, bufsize)) == NULL) |
202 | goto error; | |
203 | if ((dst = (unsigned char *) GlobalLock (htext)) == NULL) | |
204 | goto error; | |
205 | encode_coding (&coding, src, dst, nbytes, bufsize); | |
0108f679 | 206 | Vlast_coding_system_used = coding.symbol; |
06466d9a JR |
207 | |
208 | /* Stash away the data we are about to put into the clipboard, so we | |
209 | could later check inside Fw32_get_clipboard_data whether | |
210 | the clipboard still holds our data. */ | |
211 | if (clipboard_storage_size < coding.produced) | |
212 | { | |
213 | clipboard_storage_size = coding.produced + 100; | |
214 | last_clipboard_text = (char *) xrealloc (last_clipboard_text, | |
215 | clipboard_storage_size); | |
216 | } | |
217 | if (last_clipboard_text) | |
218 | memcpy (last_clipboard_text, dst, coding.produced); | |
219 | ||
bbb059f3 | 220 | GlobalUnlock (htext); |
06466d9a | 221 | |
bbb059f3 | 222 | /* Shrink data block to actual size. */ |
06466d9a JR |
223 | htext2 = GlobalReAlloc (htext, coding.produced, |
224 | GMEM_MOVEABLE | GMEM_DDESHARE); | |
bbb059f3 AI |
225 | if (htext2 != NULL) htext = htext2; |
226 | } | |
227 | } | |
ee78dc32 | 228 | |
fbd6baed | 229 | if (!OpenClipboard ((!NILP (frame) && FRAME_W32_P (XFRAME (frame))) ? FRAME_W32_WINDOW (XFRAME (frame)) : NULL)) |
ee78dc32 | 230 | goto error; |
06466d9a | 231 | |
ee78dc32 GV |
232 | ok = EmptyClipboard () && SetClipboardData (CF_TEXT, htext); |
233 | ||
234 | CloseClipboard (); | |
235 | ||
236 | if (ok) goto done; | |
237 | ||
238 | error: | |
239 | ||
240 | ok = FALSE; | |
241 | if (htext) GlobalFree (htext); | |
06466d9a JR |
242 | if (last_clipboard_text) |
243 | *last_clipboard_text = '\0'; | |
244 | ||
ee78dc32 GV |
245 | done: |
246 | UNBLOCK_INPUT; | |
247 | ||
248 | return (ok ? string : Qnil); | |
249 | } | |
250 | ||
fbd6baed | 251 | DEFUN ("w32-get-clipboard-data", Fw32_get_clipboard_data, Sw32_get_clipboard_data, 0, 1, 0, |
ee78dc32 GV |
252 | "This gets the clipboard data in text format.") |
253 | (frame) | |
254 | Lisp_Object frame; | |
255 | { | |
256 | HANDLE htext; | |
257 | Lisp_Object ret = Qnil; | |
258 | ||
259 | if (!NILP (frame)) | |
260 | CHECK_LIVE_FRAME (frame, 0); | |
261 | ||
262 | BLOCK_INPUT; | |
263 | ||
fbd6baed | 264 | if (!OpenClipboard ((!NILP (frame) && FRAME_W32_P (XFRAME (frame))) ? FRAME_W32_WINDOW (XFRAME (frame)) : NULL)) |
ee78dc32 GV |
265 | goto done; |
266 | ||
267 | if ((htext = GetClipboardData (CF_TEXT)) == NULL) | |
268 | goto closeclip; | |
269 | ||
ee78dc32 | 270 | { |
69cddef0 GV |
271 | unsigned char *src; |
272 | unsigned char *dst; | |
ee78dc32 | 273 | int nbytes; |
69cddef0 | 274 | int truelen; |
c0ca703b | 275 | int require_decoding = 0; |
ee78dc32 | 276 | |
69cddef0 | 277 | if ((src = (unsigned char *) GlobalLock (htext)) == NULL) |
ee78dc32 GV |
278 | goto closeclip; |
279 | ||
69cddef0 GV |
280 | nbytes = strlen (src); |
281 | ||
06466d9a JR |
282 | /* If the text in clipboard is identical to what we put there |
283 | last time w32_set_clipboard_data was called, pretend there's no | |
284 | data in the clipboard. This is so we don't pass our own text | |
285 | from the clipboard (which might be troublesome if the killed | |
286 | text includes null characters). */ | |
287 | if (last_clipboard_text | |
288 | && clipboard_storage_size >= nbytes | |
289 | && memcmp(last_clipboard_text, src, nbytes) == 0) | |
290 | goto closeclip; | |
291 | ||
93cbf229 GV |
292 | if ( |
293 | #if 1 | |
294 | 1 | |
295 | #else | |
296 | ! NILP (buffer_defaults.enable_multibyte_characters) | |
297 | #endif | |
298 | ) | |
299 | { | |
c0ca703b | 300 | /* If the clipboard data contains any non-ascii code, we |
93cbf229 GV |
301 | need to decode it. */ |
302 | int i; | |
303 | ||
304 | for (i = 0; i < nbytes; i++) | |
305 | { | |
306 | if (src[i] >= 0x80) | |
307 | { | |
c0ca703b | 308 | require_decoding = 1; |
93cbf229 GV |
309 | break; |
310 | } | |
311 | } | |
312 | } | |
313 | ||
c0ca703b | 314 | if (require_decoding) |
69cddef0 | 315 | { |
bbb059f3 AI |
316 | int bufsize; |
317 | unsigned char *buf; | |
318 | struct coding_system coding; | |
319 | ||
93cbf229 GV |
320 | if (NILP (Vnext_selection_coding_system)) |
321 | Vnext_selection_coding_system = Vselection_coding_system; | |
bbb059f3 | 322 | setup_coding_system |
93cbf229 | 323 | (Fcheck_coding_system (Vnext_selection_coding_system), &coding); |
69ebbf81 KH |
324 | coding.src_multibyte = 0; |
325 | coding.dst_multibyte = 1; | |
93cbf229 | 326 | Vnext_selection_coding_system = Qnil; |
bbb059f3 AI |
327 | coding.mode |= CODING_MODE_LAST_BLOCK; |
328 | bufsize = decoding_buffer_size (&coding, nbytes); | |
329 | buf = (unsigned char *) xmalloc (bufsize); | |
330 | decode_coding (&coding, src, buf, nbytes, bufsize); | |
0108f679 | 331 | Vlast_coding_system_used = coding.symbol; |
06466d9a JR |
332 | ret = make_string_from_bytes ((char *) buf, |
333 | coding.produced_char, coding.produced); | |
bbb059f3 | 334 | xfree (buf); |
69cddef0 | 335 | } |
bbb059f3 AI |
336 | else |
337 | { | |
c0ca703b GV |
338 | /* Need to know final size after CR chars are removed because we |
339 | can't change the string size manually, and doing an extra | |
340 | copy is silly. Note that we only remove CR when it appears | |
341 | as part of CRLF. */ | |
bbb059f3 AI |
342 | |
343 | truelen = nbytes; | |
344 | dst = src; | |
345 | /* avoid using strchr because it recomputes the length everytime */ | |
346 | while ((dst = memchr (dst, '\r', nbytes - (dst - src))) != NULL) | |
347 | { | |
c0ca703b GV |
348 | if (dst[1] == '\n') /* safe because of trailing '\0' */ |
349 | truelen--; | |
bbb059f3 AI |
350 | dst++; |
351 | } | |
69cddef0 | 352 | |
bbb059f3 | 353 | ret = make_uninit_string (truelen); |
69cddef0 | 354 | |
c0ca703b GV |
355 | /* Convert CRLF line endings (the standard CF_TEXT clipboard |
356 | format) to LF endings as used internally by Emacs. */ | |
69cddef0 | 357 | |
bbb059f3 AI |
358 | dst = XSTRING (ret)->data; |
359 | while (1) | |
69cddef0 | 360 | { |
bbb059f3 AI |
361 | unsigned char *next; |
362 | /* copy next line or remaining bytes excluding '\0' */ | |
363 | next = _memccpy (dst, src, '\r', nbytes); | |
364 | if (next) | |
365 | { | |
366 | /* copied one line ending with '\r' */ | |
367 | int copied = next - dst; | |
368 | nbytes -= copied; | |
c0ca703b | 369 | dst += copied; |
bbb059f3 | 370 | src += copied; |
c0ca703b GV |
371 | if (*src == '\n') |
372 | dst--; /* overwrite '\r' with '\n' */ | |
373 | } | |
bbb059f3 AI |
374 | else |
375 | /* copied remaining partial line -> now finished */ | |
376 | break; | |
377 | } | |
0108f679 AI |
378 | |
379 | Vlast_coding_system_used = Qraw_text; | |
69cddef0 GV |
380 | } |
381 | ||
ee78dc32 GV |
382 | GlobalUnlock (htext); |
383 | } | |
384 | ||
385 | closeclip: | |
386 | CloseClipboard (); | |
387 | ||
388 | done: | |
389 | UNBLOCK_INPUT; | |
390 | ||
391 | return (ret); | |
392 | } | |
393 | ||
9aa94bd5 KH |
394 | /* Support checking for a clipboard selection. */ |
395 | ||
396 | DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p, | |
397 | 0, 1, 0, | |
398 | "Whether there is an owner for the given X Selection.\n\ | |
399 | The arg should be the name of the selection in question, typically one of\n\ | |
400 | the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\ | |
401 | \(Those are literal upper-case symbol names, since that's what X expects.)\n\ | |
402 | For convenience, the symbol nil is the same as `PRIMARY',\n\ | |
403 | and t is the same as `SECONDARY'.") | |
404 | (selection) | |
405 | Lisp_Object selection; | |
406 | { | |
407 | CHECK_SYMBOL (selection, 0); | |
408 | ||
409 | /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check | |
410 | if the clipboard currently has valid text format contents. */ | |
411 | ||
412 | if (EQ (selection, QCLIPBOARD)) | |
413 | { | |
414 | Lisp_Object val = Qnil; | |
415 | ||
416 | if (OpenClipboard (NULL)) | |
417 | { | |
418 | int format = 0; | |
419 | while (format = EnumClipboardFormats (format)) | |
420 | if (format == CF_TEXT) | |
421 | { | |
422 | val = Qt; | |
423 | break; | |
424 | } | |
425 | CloseClipboard (); | |
426 | } | |
427 | return val; | |
428 | } | |
429 | return Qnil; | |
430 | } | |
431 | ||
ee78dc32 | 432 | void |
fbd6baed | 433 | syms_of_w32select () |
ee78dc32 GV |
434 | { |
435 | #if 0 | |
fbd6baed GV |
436 | defsubr (&Sw32_open_clipboard); |
437 | defsubr (&Sw32_empty_clipboard); | |
438 | defsubr (&Sw32_close_clipboard); | |
ee78dc32 | 439 | #endif |
fbd6baed GV |
440 | defsubr (&Sw32_set_clipboard_data); |
441 | defsubr (&Sw32_get_clipboard_data); | |
9aa94bd5 KH |
442 | defsubr (&Sx_selection_exists_p); |
443 | ||
72aca5fa | 444 | DEFVAR_LISP ("selection-coding-system", &Vselection_coding_system, |
bbb059f3 AI |
445 | "Coding system for communicating with other X clients.\n\ |
446 | When sending or receiving text via cut_buffer, selection, and clipboard,\n\ | |
447 | the text is encoded or decoded by this coding system.\n\ | |
448 | A default value is `compound-text'"); | |
72aca5fa | 449 | Vselection_coding_system=intern ("iso-latin-1-dos"); |
bbb059f3 | 450 | |
93cbf229 GV |
451 | DEFVAR_LISP ("next-selection-coding-system", &Vnext_selection_coding_system, |
452 | "Coding system for the next communication with other X clients.\n\ | |
453 | Usually, `selection-coding-system' is used for communicating with\n\ | |
454 | other X clients. But, if this variable is set, it is used for the\n\ | |
455 | next communication only. After the communication, this variable is\n\ | |
456 | set to nil."); | |
457 | Vnext_selection_coding_system = Qnil; | |
458 | ||
9aa94bd5 | 459 | QCLIPBOARD = intern ("CLIPBOARD"); staticpro (&QCLIPBOARD); |
ee78dc32 | 460 | } |