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 GV |
26 | #include "dispextern.h" /* frame.h seems to want this */ |
27 | #include "frame.h" /* Need this to get the X window of selected_frame */ | |
28 | #include "blockinput.h" | |
bbb059f3 AI |
29 | #include "buffer.h" |
30 | #include "charset.h" | |
31 | #include "coding.h" | |
ee78dc32 | 32 | |
9aa94bd5 KH |
33 | Lisp_Object QCLIPBOARD; |
34 | ||
bbb059f3 AI |
35 | /* Coding system for communicating with other Windows programs via the |
36 | clipboard. */ | |
37 | static Lisp_Object Vclipboard_coding_system; | |
38 | ||
ee78dc32 | 39 | #if 0 |
fbd6baed | 40 | DEFUN ("w32-open-clipboard", Fw32_open_clipboard, Sw32_open_clipboard, 0, 1, 0, |
ee78dc32 GV |
41 | "This opens the clipboard with the given frame pointer.") |
42 | (frame) | |
43 | Lisp_Object frame; | |
44 | { | |
45 | BOOL ok = FALSE; | |
46 | ||
47 | if (!NILP (frame)) | |
48 | CHECK_LIVE_FRAME (frame, 0); | |
49 | ||
50 | BLOCK_INPUT; | |
51 | ||
fbd6baed | 52 | ok = OpenClipboard ((!NILP (frame) && FRAME_W32_P (XFRAME (frame))) ? FRAME_W32_WINDOW (XFRAME (frame)) : NULL); |
ee78dc32 GV |
53 | |
54 | UNBLOCK_INPUT; | |
55 | ||
56 | return (ok ? frame : Qnil); | |
57 | } | |
58 | ||
fbd6baed | 59 | DEFUN ("w32-empty-clipboard", Fw32_empty_clipboard, Sw32_empty_clipboard, 0, 0, 0, |
ee78dc32 GV |
60 | "This empties the clipboard and assigns ownership to the window which opened the clipboard.") |
61 | () | |
62 | { | |
63 | BOOL ok = FALSE; | |
64 | ||
65 | BLOCK_INPUT; | |
66 | ||
67 | ok = EmptyClipboard (); | |
68 | ||
69 | UNBLOCK_INPUT; | |
70 | ||
71 | return (ok ? Qt : Qnil); | |
72 | } | |
73 | ||
fbd6baed | 74 | DEFUN ("w32-close-clipboard", Fw32_close_clipboard, Sw32_close_clipboard, 0, 0, 0, |
ee78dc32 GV |
75 | "This closes the clipboard.") |
76 | () | |
77 | { | |
78 | BOOL ok = FALSE; | |
79 | ||
80 | BLOCK_INPUT; | |
81 | ||
82 | ok = CloseClipboard (); | |
83 | ||
84 | UNBLOCK_INPUT; | |
85 | ||
86 | return (ok ? Qt : Qnil); | |
87 | } | |
88 | ||
89 | #endif | |
90 | ||
fbd6baed | 91 | DEFUN ("w32-set-clipboard-data", Fw32_set_clipboard_data, Sw32_set_clipboard_data, 1, 2, 0, |
ee78dc32 GV |
92 | "This sets the clipboard data to the given text.") |
93 | (string, frame) | |
94 | Lisp_Object string, frame; | |
95 | { | |
96 | BOOL ok = TRUE; | |
97 | HANDLE htext; | |
69cddef0 GV |
98 | int nbytes; |
99 | int truelen; | |
100 | unsigned char *src; | |
101 | unsigned char *dst; | |
ee78dc32 GV |
102 | |
103 | CHECK_STRING (string, 0); | |
104 | ||
105 | if (!NILP (frame)) | |
106 | CHECK_LIVE_FRAME (frame, 0); | |
107 | ||
108 | BLOCK_INPUT; | |
69cddef0 | 109 | |
bbb059f3 | 110 | nbytes = STRING_BYTES (XSTRING (string)) + 1; |
69cddef0 GV |
111 | src = XSTRING (string)->data; |
112 | ||
bbb059f3 AI |
113 | { |
114 | /* Since we are now handling multilingual text, we must consider | |
115 | encoding text for the clipboard. */ | |
116 | int charsets[MAX_CHARSET + 1]; | |
117 | int num; | |
118 | ||
119 | bzero (charsets, (MAX_CHARSET + 1) * sizeof (int)); | |
120 | num = ((nbytes <= 2 /* Check the possibility of short cut. */ | |
121 | || NILP (buffer_defaults.enable_multibyte_characters)) | |
122 | ? 0 | |
123 | : find_charset_in_str (src, nbytes, charsets, Qnil, 1)); | |
124 | ||
125 | if (!num || (num == 1 && charsets[CHARSET_ASCII])) | |
126 | { | |
127 | /* No multibyte character in OBJ. We need not encode it. */ | |
69cddef0 | 128 | |
bbb059f3 AI |
129 | /* need to know final size after '\r' chars are inserted (the |
130 | standard CF_TEXT clipboard format uses CRLF line endings, | |
131 | while Emacs uses just LF internally) */ | |
69cddef0 | 132 | |
bbb059f3 AI |
133 | truelen = nbytes; |
134 | dst = src; | |
135 | /* avoid using strchr because it recomputes the length everytime */ | |
136 | while ((dst = memchr (dst, '\n', nbytes - (dst - src))) != NULL) | |
137 | { | |
138 | truelen++; | |
139 | dst++; | |
140 | } | |
69cddef0 | 141 | |
bbb059f3 AI |
142 | if ((htext = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, truelen)) == NULL) |
143 | goto error; | |
144 | ||
145 | if ((dst = (unsigned char *) GlobalLock (htext)) == NULL) | |
146 | goto error; | |
ee78dc32 | 147 | |
bbb059f3 AI |
148 | /* convert to CRLF line endings expected by clipboard */ |
149 | while (1) | |
150 | { | |
151 | unsigned char *next; | |
152 | /* copy next line or remaining bytes including '\0' */ | |
153 | next = _memccpy (dst, src, '\n', nbytes); | |
154 | if (next) | |
155 | { | |
156 | /* copied one line ending with '\n' */ | |
157 | int copied = next - dst; | |
158 | nbytes -= copied; | |
159 | src += copied; | |
160 | /* insert '\r' before '\n' */ | |
161 | next[-1] = '\r'; | |
162 | next[0] = '\n'; | |
163 | dst = next + 1; | |
164 | } | |
165 | else | |
166 | /* copied remaining partial line -> now finished */ | |
167 | break; | |
168 | } | |
ee78dc32 | 169 | |
bbb059f3 | 170 | GlobalUnlock (htext); |
0108f679 AI |
171 | |
172 | Vlast_coding_system_used = Qraw_text; | |
bbb059f3 AI |
173 | } |
174 | else | |
175 | { | |
176 | /* We must encode contents of OBJ to compound text format. | |
177 | The format is compatible with what the target `STRING' | |
178 | expects if OBJ contains only ASCII and Latin-1 | |
179 | characters. */ | |
180 | int bufsize; | |
181 | struct coding_system coding; | |
182 | HANDLE htext2; | |
183 | ||
184 | setup_coding_system | |
185 | (Fcheck_coding_system (Vclipboard_coding_system), &coding); | |
186 | coding.mode |= CODING_MODE_LAST_BLOCK; | |
187 | bufsize = encoding_buffer_size (&coding, nbytes); | |
188 | if ((htext = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, bufsize)) == NULL) | |
189 | goto error; | |
190 | if ((dst = (unsigned char *) GlobalLock (htext)) == NULL) | |
191 | goto error; | |
192 | encode_coding (&coding, src, dst, nbytes, bufsize); | |
0108f679 | 193 | Vlast_coding_system_used = coding.symbol; |
bbb059f3 AI |
194 | GlobalUnlock (htext); |
195 | /* Shrink data block to actual size. */ | |
196 | htext2 = GlobalReAlloc (htext, coding.produced, GMEM_MOVEABLE | GMEM_DDESHARE); | |
197 | if (htext2 != NULL) htext = htext2; | |
198 | } | |
199 | } | |
ee78dc32 | 200 | |
fbd6baed | 201 | if (!OpenClipboard ((!NILP (frame) && FRAME_W32_P (XFRAME (frame))) ? FRAME_W32_WINDOW (XFRAME (frame)) : NULL)) |
ee78dc32 GV |
202 | goto error; |
203 | ||
204 | ok = EmptyClipboard () && SetClipboardData (CF_TEXT, htext); | |
205 | ||
206 | CloseClipboard (); | |
207 | ||
208 | if (ok) goto done; | |
209 | ||
210 | error: | |
211 | ||
212 | ok = FALSE; | |
213 | if (htext) GlobalFree (htext); | |
214 | ||
215 | done: | |
216 | UNBLOCK_INPUT; | |
217 | ||
218 | return (ok ? string : Qnil); | |
219 | } | |
220 | ||
fbd6baed | 221 | DEFUN ("w32-get-clipboard-data", Fw32_get_clipboard_data, Sw32_get_clipboard_data, 0, 1, 0, |
ee78dc32 GV |
222 | "This gets the clipboard data in text format.") |
223 | (frame) | |
224 | Lisp_Object frame; | |
225 | { | |
226 | HANDLE htext; | |
227 | Lisp_Object ret = Qnil; | |
228 | ||
229 | if (!NILP (frame)) | |
230 | CHECK_LIVE_FRAME (frame, 0); | |
231 | ||
232 | BLOCK_INPUT; | |
233 | ||
fbd6baed | 234 | if (!OpenClipboard ((!NILP (frame) && FRAME_W32_P (XFRAME (frame))) ? FRAME_W32_WINDOW (XFRAME (frame)) : NULL)) |
ee78dc32 GV |
235 | goto done; |
236 | ||
237 | if ((htext = GetClipboardData (CF_TEXT)) == NULL) | |
238 | goto closeclip; | |
239 | ||
ee78dc32 | 240 | { |
69cddef0 GV |
241 | unsigned char *src; |
242 | unsigned char *dst; | |
ee78dc32 | 243 | int nbytes; |
69cddef0 | 244 | int truelen; |
ee78dc32 | 245 | |
69cddef0 | 246 | if ((src = (unsigned char *) GlobalLock (htext)) == NULL) |
ee78dc32 GV |
247 | goto closeclip; |
248 | ||
69cddef0 GV |
249 | nbytes = strlen (src); |
250 | ||
bbb059f3 | 251 | if (! NILP (buffer_defaults.enable_multibyte_characters)) |
69cddef0 | 252 | { |
bbb059f3 AI |
253 | int bufsize; |
254 | unsigned char *buf; | |
255 | struct coding_system coding; | |
256 | ||
257 | setup_coding_system | |
258 | (Fcheck_coding_system(Vclipboard_coding_system), &coding); | |
259 | coding.mode |= CODING_MODE_LAST_BLOCK; | |
260 | bufsize = decoding_buffer_size (&coding, nbytes); | |
261 | buf = (unsigned char *) xmalloc (bufsize); | |
262 | decode_coding (&coding, src, buf, nbytes, bufsize); | |
0108f679 | 263 | Vlast_coding_system_used = coding.symbol; |
bbb059f3 AI |
264 | truelen = (coding.fake_multibyte |
265 | ? multibyte_chars_in_text (buf, coding.produced) | |
266 | : coding.produced_char); | |
267 | ret = make_string_from_bytes ((char *) buf, truelen, coding.produced); | |
268 | xfree (buf); | |
69cddef0 | 269 | } |
bbb059f3 AI |
270 | else |
271 | { | |
272 | /* need to know final size after '\r' chars are removed because | |
273 | we can't change the string size manually, and doing an extra | |
274 | copy is silly */ | |
275 | ||
276 | truelen = nbytes; | |
277 | dst = src; | |
278 | /* avoid using strchr because it recomputes the length everytime */ | |
279 | while ((dst = memchr (dst, '\r', nbytes - (dst - src))) != NULL) | |
280 | { | |
281 | truelen--; | |
282 | dst++; | |
283 | } | |
69cddef0 | 284 | |
bbb059f3 | 285 | ret = make_uninit_string (truelen); |
69cddef0 | 286 | |
bbb059f3 AI |
287 | /* convert CRLF line endings (the standard CF_TEXT clipboard |
288 | format) to LF endings as used internally by Emacs */ | |
69cddef0 | 289 | |
bbb059f3 AI |
290 | dst = XSTRING (ret)->data; |
291 | while (1) | |
69cddef0 | 292 | { |
bbb059f3 AI |
293 | unsigned char *next; |
294 | /* copy next line or remaining bytes excluding '\0' */ | |
295 | next = _memccpy (dst, src, '\r', nbytes); | |
296 | if (next) | |
297 | { | |
298 | /* copied one line ending with '\r' */ | |
299 | int copied = next - dst; | |
300 | nbytes -= copied; | |
301 | dst += copied - 1; /* overwrite '\r' */ | |
302 | src += copied; | |
303 | } | |
304 | else | |
305 | /* copied remaining partial line -> now finished */ | |
306 | break; | |
307 | } | |
0108f679 AI |
308 | |
309 | Vlast_coding_system_used = Qraw_text; | |
69cddef0 GV |
310 | } |
311 | ||
ee78dc32 GV |
312 | GlobalUnlock (htext); |
313 | } | |
314 | ||
315 | closeclip: | |
316 | CloseClipboard (); | |
317 | ||
318 | done: | |
319 | UNBLOCK_INPUT; | |
320 | ||
321 | return (ret); | |
322 | } | |
323 | ||
9aa94bd5 KH |
324 | /* Support checking for a clipboard selection. */ |
325 | ||
326 | DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p, | |
327 | 0, 1, 0, | |
328 | "Whether there is an owner for the given X Selection.\n\ | |
329 | The arg should be the name of the selection in question, typically one of\n\ | |
330 | the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\ | |
331 | \(Those are literal upper-case symbol names, since that's what X expects.)\n\ | |
332 | For convenience, the symbol nil is the same as `PRIMARY',\n\ | |
333 | and t is the same as `SECONDARY'.") | |
334 | (selection) | |
335 | Lisp_Object selection; | |
336 | { | |
337 | CHECK_SYMBOL (selection, 0); | |
338 | ||
339 | /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check | |
340 | if the clipboard currently has valid text format contents. */ | |
341 | ||
342 | if (EQ (selection, QCLIPBOARD)) | |
343 | { | |
344 | Lisp_Object val = Qnil; | |
345 | ||
346 | if (OpenClipboard (NULL)) | |
347 | { | |
348 | int format = 0; | |
349 | while (format = EnumClipboardFormats (format)) | |
350 | if (format == CF_TEXT) | |
351 | { | |
352 | val = Qt; | |
353 | break; | |
354 | } | |
355 | CloseClipboard (); | |
356 | } | |
357 | return val; | |
358 | } | |
359 | return Qnil; | |
360 | } | |
361 | ||
ee78dc32 | 362 | void |
fbd6baed | 363 | syms_of_w32select () |
ee78dc32 GV |
364 | { |
365 | #if 0 | |
fbd6baed GV |
366 | defsubr (&Sw32_open_clipboard); |
367 | defsubr (&Sw32_empty_clipboard); | |
368 | defsubr (&Sw32_close_clipboard); | |
ee78dc32 | 369 | #endif |
fbd6baed GV |
370 | defsubr (&Sw32_set_clipboard_data); |
371 | defsubr (&Sw32_get_clipboard_data); | |
9aa94bd5 KH |
372 | defsubr (&Sx_selection_exists_p); |
373 | ||
bbb059f3 AI |
374 | DEFVAR_LISP ("clipboard-coding-system", &Vclipboard_coding_system, |
375 | "Coding system for communicating with other X clients.\n\ | |
376 | When sending or receiving text via cut_buffer, selection, and clipboard,\n\ | |
377 | the text is encoded or decoded by this coding system.\n\ | |
378 | A default value is `compound-text'"); | |
379 | Vclipboard_coding_system=intern ("iso-latin-1-dos"); | |
380 | staticpro(&Vclipboard_coding_system); | |
381 | ||
9aa94bd5 | 382 | QCLIPBOARD = intern ("CLIPBOARD"); staticpro (&QCLIPBOARD); |
ee78dc32 | 383 | } |