comparison src/select-msw.c @ 412:697ef44129c6 r21-2-14

Import from CVS: tag r21-2-14
author cvs
date Mon, 13 Aug 2007 11:20:41 +0200
parents de805c49cfc1
children da8ed4261e83
comparison
equal deleted inserted replaced
411:12e008d41344 412:697ef44129c6
22 22
23 /* Authorship: 23 /* Authorship:
24 24
25 Written by Kevin Gallo for FSF Emacs. 25 Written by Kevin Gallo for FSF Emacs.
26 Rewritten for mswindows by Jonathan Harris, December 1997 for 21.0. 26 Rewritten for mswindows by Jonathan Harris, December 1997 for 21.0.
27 Hacked by Alastair Houghton, July 2000 for enhanced clipboard support. 27 */
28 */ 28
29 29
30 #include <config.h> 30 #include <config.h>
31 #include "lisp.h" 31 #include "lisp.h"
32 #include "frame.h"
33 #include "select.h"
34 #include "opaque.h"
35 #include "file-coding.h"
36 #include "buffer.h"
37 32
38 #include "console-msw.h" 33 #include "console-msw.h"
39 34
40 /* A list of handles that we must release. Not accessible from Lisp. */ 35 DEFUN ("mswindows-set-clipboard", Fmswindows_set_clipboard, 1, 1, 0, /*
41 static Lisp_Object Vhandle_alist; 36 Copy STRING to the mswindows clipboard.
37 */
38 (string))
39 {
40 int rawsize, size, i;
41 unsigned char *src, *dst, *next;
42 HGLOBAL h = NULL;
42 43
43 /* Test if this is an X symbol that we understand */ 44 CHECK_STRING (string);
44 static int
45 x_sym_p (Lisp_Object value)
46 {
47 if (NILP (value) || INTP (value))
48 return 0;
49 45
50 /* Check for some of the X symbols */ 46 /* Calculate size with LFs converted to CRLFs because
51 if (EQ (value, QSTRING)) return 1; 47 * CF_TEXT format uses CRLF delimited ASCIIZ */
52 if (EQ (value, QTEXT)) return 1; 48 src = XSTRING_DATA (string);
53 if (EQ (value, QCOMPOUND_TEXT)) return 1; 49 size = rawsize = XSTRING_LENGTH (string) + 1;
50 for (i=0; i<rawsize; i++)
51 if (src[i] == '\n')
52 size++;
54 53
55 return 0; 54 if (!OpenClipboard (NULL))
55 return Qnil;
56
57 if (!EmptyClipboard () ||
58 (h = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, size)) == NULL ||
59 (dst = (unsigned char *) GlobalLock (h)) == NULL)
60 {
61 if (h != NULL) GlobalFree (h);
62 CloseClipboard ();
63 return Qnil;
64 }
65
66 /* Convert LFs to CRLFs */
67 do
68 {
69 /* copy next line or remaining bytes including '\0' */
70 next = memccpy (dst, src, '\n', rawsize);
71 if (next)
72 {
73 /* copied one line ending with '\n' */
74 int copied = next - dst;
75 rawsize -= copied;
76 src += copied;
77 /* insert '\r' before '\n' */
78 next[-1] = '\r';
79 next[0] = '\n';
80 dst = next+1;
81 }
82 }
83 while (next);
84
85 GlobalUnlock (h);
86
87 i = (SetClipboardData (CF_TEXT, h) != NULL);
88
89 CloseClipboard ();
90 GlobalFree (h);
91
92 return i ? Qt : Qnil;
56 } 93 }
57 94
58 /* This converts a Lisp symbol to an MS-Windows clipboard format. 95 DEFUN ("mswindows-get-clipboard", Fmswindows_get_clipboard, 0, 0, 0, /*
59 We have symbols for all predefined clipboard formats, but that 96 Return the contents of the mswindows clipboard.
60 doesn't mean we support them all ;-) 97 */
61 The name of this function is actually a lie - it also knows about 98 ())
62 integers and strings... */
63 static UINT
64 symbol_to_ms_cf (Lisp_Object value)
65 { 99 {
66 /* If it's NIL, we're in trouble. */ 100 HANDLE h;
67 if (NILP (value)) return 0; 101 unsigned char *src, *dst, *next;
68 102 Lisp_Object ret = Qnil;
69 /* If it's an integer, assume it's a format ID */
70 if (INTP (value)) return (UINT) (XINT (value));
71 103
72 /* If it's a string, register the format(!) */ 104 if (!OpenClipboard (NULL))
73 if (STRINGP (value)) 105 return Qnil;
74 return RegisterClipboardFormat (XSTRING_DATA (value));
75
76 /* Check for Windows clipboard format symbols */
77 if (EQ (value, QCF_TEXT)) return CF_TEXT;
78 if (EQ (value, QCF_BITMAP)) return CF_BITMAP;
79 if (EQ (value, QCF_METAFILEPICT)) return CF_METAFILEPICT;
80 if (EQ (value, QCF_SYLK)) return CF_SYLK;
81 if (EQ (value, QCF_DIF)) return CF_DIF;
82 if (EQ (value, QCF_TIFF)) return CF_TIFF;
83 if (EQ (value, QCF_OEMTEXT)) return CF_OEMTEXT;
84 if (EQ (value, QCF_DIB)) return CF_DIB;
85 if (EQ (value, QCF_PALETTE)) return CF_PALETTE;
86 if (EQ (value, QCF_PENDATA)) return CF_PENDATA;
87 if (EQ (value, QCF_RIFF)) return CF_RIFF;
88 if (EQ (value, QCF_WAVE)) return CF_WAVE;
89 if (EQ (value, QCF_UNICODETEXT)) return CF_UNICODETEXT;
90 if (EQ (value, QCF_ENHMETAFILE)) return CF_ENHMETAFILE;
91 if (EQ (value, QCF_HDROP)) return CF_HDROP;
92 if (EQ (value, QCF_LOCALE)) return CF_LOCALE;
93 if (EQ (value, QCF_OWNERDISPLAY)) return CF_OWNERDISPLAY;
94 if (EQ (value, QCF_DSPTEXT)) return CF_DSPTEXT;
95 if (EQ (value, QCF_DSPBITMAP)) return CF_DSPBITMAP;
96 if (EQ (value, QCF_DSPMETAFILEPICT)) return CF_DSPMETAFILEPICT;
97 if (EQ (value, QCF_DSPENHMETAFILE)) return CF_DSPENHMETAFILE;
98 106
99 return 0; 107 if ((h = GetClipboardData (CF_TEXT)) != NULL &&
108 (src = (unsigned char *) GlobalLock (h)) != NULL)
109 {
110 int i;
111 int size, rawsize;
112 size = rawsize = strlen (src);
113
114 for (i=0; i<rawsize; i++)
115 if (src[i] == '\r' && src[i+1] == '\n')
116 size--;
117
118 /* Convert CRLFs to LFs */
119 ret = make_uninit_string (size);
120 dst = XSTRING_DATA (ret);
121 do
122 {
123 /* copy next line or remaining bytes excluding '\0' */
124 next = memccpy (dst, src, '\r', rawsize);
125 if (next)
126 {
127 /* copied one line ending with '\r' */
128 int copied = next - dst;
129 rawsize -= copied;
130 src += copied;
131 if (*src == '\n')
132 dst += copied - 1; /* overwrite '\r' */
133 else
134 dst += copied;
135 }
136 }
137 while (next);
138
139 GlobalUnlock (h);
140 }
141
142 CloseClipboard ();
143
144 return ret;
100 } 145 }
101 146
102 /* This converts an MS-Windows clipboard format to its corresponding 147 DEFUN ("mswindows-selection-exists-p", Fmswindows_selection_exists_p, 0, 0, 0, /*
103 Lisp symbol, or a Lisp integer otherwise. */ 148 Whether there is an MS-Windows selection.
104 static Lisp_Object 149 */
105 ms_cf_to_symbol (UINT format) 150 ())
106 { 151 {
107 switch (format) 152 return IsClipboardFormatAvailable (CF_TEXT) ? Qt : Qnil;
108 {
109 case CF_TEXT: return QCF_TEXT;
110 case CF_BITMAP: return QCF_BITMAP;
111 case CF_METAFILEPICT: return QCF_METAFILEPICT;
112 case CF_SYLK: return QCF_SYLK;
113 case CF_DIF: return QCF_DIF;
114 case CF_TIFF: return QCF_TIFF;
115 case CF_OEMTEXT: return QCF_OEMTEXT;
116 case CF_DIB: return QCF_DIB;
117 case CF_PALETTE: return QCF_PALETTE;
118 case CF_PENDATA: return QCF_PENDATA;
119 case CF_RIFF: return QCF_RIFF;
120 case CF_WAVE: return QCF_WAVE;
121 case CF_UNICODETEXT: return QCF_UNICODETEXT;
122 case CF_ENHMETAFILE: return QCF_ENHMETAFILE;
123 case CF_HDROP: return QCF_HDROP;
124 case CF_LOCALE: return QCF_LOCALE;
125 case CF_OWNERDISPLAY: return QCF_OWNERDISPLAY;
126 case CF_DSPTEXT: return QCF_DSPTEXT;
127 case CF_DSPBITMAP: return QCF_DSPBITMAP;
128 case CF_DSPMETAFILEPICT: return QCF_DSPMETAFILEPICT;
129 case CF_DSPENHMETAFILE: return QCF_DSPENHMETAFILE;
130 default: return make_int ((int) format);
131 }
132 } 153 }
133 154
134 /* Test if the specified clipboard format is auto-released by the OS. If 155 DEFUN ("mswindows-delete-selection", Fmswindows_delete_selection, 0, 0, 0, /*
135 not, we must remember the handle on Vhandle_alist, and free it if 156 Remove the current MS-Windows selection from the clipboard.
136 the clipboard is emptied or if we set data with the same format. */ 157 */
137 static int 158 ())
138 cf_is_autofreed (UINT format)
139 { 159 {
140 switch (format) 160 return EmptyClipboard () ? Qt : Qnil;
141 {
142 /* This list comes from the SDK documentation */
143 case CF_DSPENHMETAFILE:
144 case CF_DSPMETAFILEPICT:
145 case CF_ENHMETAFILE:
146 case CF_BITMAP:
147 case CF_DSPBITMAP:
148 case CF_PALETTE:
149 case CF_DIB:
150 case CF_DSPTEXT:
151 case CF_OEMTEXT:
152 case CF_TEXT:
153 case CF_UNICODETEXT:
154 return TRUE;
155
156 default:
157 return FALSE;
158 }
159 }
160
161 /* Do protocol to assert ourself as a selection owner.
162
163 Under mswindows, we:
164
165 * Only set the clipboard if (eq selection-name 'CLIPBOARD)
166
167 * Check if an X atom name has been passed. If so, convert to CF_TEXT
168 (or CF_UNICODETEXT) remembering to perform LF -> CR-LF conversion.
169
170 * Otherwise assume the data is formatted appropriately for the data type
171 that was passed.
172
173 Then set the clipboard as necessary.
174 */
175 static Lisp_Object
176 mswindows_own_selection (Lisp_Object selection_name,
177 Lisp_Object selection_value,
178 Lisp_Object how_to_add,
179 Lisp_Object selection_type)
180 {
181 HGLOBAL hValue = NULL;
182 UINT cfType;
183 int is_X_type = FALSE;
184 Lisp_Object cfObject;
185 Lisp_Object data = Qnil;
186 int size;
187 void *src, *dst;
188 struct frame *f = NULL;
189
190 /* Only continue if we're trying to set the clipboard - mswindows doesn't
191 use the same selection model as X */
192 if (!EQ (selection_name, QCLIPBOARD))
193 return Qnil;
194
195 /* If this is one of the X-style atom name symbols, or NIL, convert it
196 as appropriate */
197 if (NILP (selection_type) || x_sym_p (selection_type))
198 {
199 /* Should COMPOUND_TEXT map to CF_UNICODETEXT? */
200 cfType = CF_TEXT;
201 cfObject = QCF_TEXT;
202 is_X_type = TRUE;
203 }
204 else
205 {
206 cfType = symbol_to_ms_cf (selection_type);
207
208 /* Only continue if we can figure out a clipboard type */
209 if (!cfType)
210 return Qnil;
211
212 cfObject = selection_type;
213 }
214
215 /* Convert things appropriately */
216 data = select_convert_out (selection_name,
217 cfObject,
218 selection_value);
219
220 if (NILP (data))
221 return Qnil;
222
223 if (CONSP (data))
224 {
225 if (!EQ (XCAR (data), cfObject))
226 cfType = symbol_to_ms_cf (XCAR (data));
227
228 if (!cfType)
229 return Qnil;
230
231 data = XCDR (data);
232 }
233
234 /* We support opaque or string values, but we only mention string
235 values for now... */
236 if (!OPAQUEP (data)
237 && !STRINGP (data))
238 return Qnil;
239
240 /* Compute the data length */
241 if (OPAQUEP (data))
242 size = XOPAQUE_SIZE (data);
243 else
244 size = XSTRING_LENGTH (data) + 1;
245
246 /* Find the frame */
247 f = selected_frame ();
248
249 /* Open the clipboard */
250 if (!OpenClipboard (FRAME_MSWINDOWS_HANDLE (f)))
251 return Qnil;
252
253 /* Allocate memory */
254 hValue = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, size);
255
256 if (!hValue)
257 {
258 CloseClipboard ();
259
260 return Qnil;
261 }
262
263 /* Copy the data */
264 if (OPAQUEP (data))
265 src = XOPAQUE_DATA (data);
266 else
267 src = XSTRING_DATA (data);
268
269 dst = GlobalLock (hValue);
270
271 if (!dst)
272 {
273 GlobalFree (hValue);
274 CloseClipboard ();
275
276 return Qnil;
277 }
278
279 memcpy (dst, src, size);
280
281 GlobalUnlock (hValue);
282
283 /* Empty the clipboard if we're replacing everything */
284 if (NILP (how_to_add) || EQ (how_to_add, Qreplace_all))
285 {
286 if (!EmptyClipboard ())
287 {
288 CloseClipboard ();
289 GlobalFree (hValue);
290
291 return Qnil;
292 }
293 }
294
295 /* Append is currently handled in select.el; perhaps this should change,
296 but it only really makes sense for ordinary text in any case... */
297
298 SetClipboardData (cfType, hValue);
299
300 if (!cf_is_autofreed (cfType))
301 {
302 Lisp_Object alist_elt = Qnil, rest;
303 Lisp_Object cfType_int = make_int (cfType);
304
305 /* First check if there's an element in the alist for this type
306 already. */
307 alist_elt = assq_no_quit (cfType_int, Vhandle_alist);
308
309 /* Add an element to the alist */
310 Vhandle_alist = Fcons (Fcons (cfType_int, make_opaque_ptr (hValue)),
311 Vhandle_alist);
312
313 if (!NILP (alist_elt))
314 {
315 /* Free the original handle */
316 GlobalFree ((HGLOBAL) get_opaque_ptr (XCDR (alist_elt)));
317
318 /* Remove the original one (adding first makes life easier, because
319 we don't have to special case this being the first element) */
320 for (rest = Vhandle_alist; !NILP (rest); rest = Fcdr (rest))
321 if (EQ (cfType_int, Fcar (XCDR (rest))))
322 {
323 XCDR (rest) = Fcdr (XCDR (rest));
324 break;
325 }
326 }
327 }
328
329 CloseClipboard ();
330
331 /* #### Should really return a time, though this is because of the
332 X model (by the looks of things) */
333 return Qnil;
334 }
335
336 static Lisp_Object
337 mswindows_available_selection_types (Lisp_Object selection_name)
338 {
339 Lisp_Object types = Qnil;
340 UINT format = 0;
341 struct frame *f = NULL;
342
343 if (!EQ (selection_name, QCLIPBOARD))
344 return Qnil;
345
346 /* Find the frame */
347 f = selected_frame ();
348
349 /* Open the clipboard */
350 if (!OpenClipboard (FRAME_MSWINDOWS_HANDLE (f)))
351 return Qnil;
352
353 /* #### ajh - Should there be an unwind-protect handler around this?
354 It could (well it probably won't, but it's always better to
355 be safe) run out of memory and leave the clipboard open... */
356
357 while ((format = EnumClipboardFormats (format)))
358 types = Fcons (ms_cf_to_symbol (format), types);
359
360 /* Close it */
361 CloseClipboard ();
362
363 return types;
364 }
365
366 static Lisp_Object
367 mswindows_register_selection_data_type (Lisp_Object type_name)
368 {
369 /* Type already checked in select.c */
370 const char *name = XSTRING_DATA (type_name);
371 UINT format;
372
373 format = RegisterClipboardFormat (name);
374
375 if (format)
376 return make_int ((int) format);
377 else
378 return Qnil;
379 }
380
381 static Lisp_Object
382 mswindows_selection_data_type_name (Lisp_Object type_id)
383 {
384 UINT format;
385 int numchars;
386 char name_buf[128];
387
388 /* If it's an integer, convert to a symbol if appropriate */
389 if (INTP (type_id))
390 type_id = ms_cf_to_symbol (XINT (type_id));
391
392 /* If this is a symbol, return it */
393 if (SYMBOLP (type_id))
394 return type_id;
395
396 /* Find the format code */
397 format = symbol_to_ms_cf (type_id);
398
399 if (!format)
400 return Qnil;
401
402 /* Microsoft, stupid Microsoft */
403 numchars = GetClipboardFormatName (format, name_buf, 128);
404
405 if (numchars)
406 {
407 Lisp_Object name;
408
409 /* Do this properly - though we could support UNICODE (UCS-2) if
410 MULE could hack it. */
411 name = make_ext_string (name_buf, numchars,
412 Fget_coding_system (Qraw_text));
413
414 return name;
415 }
416
417 return Qnil;
418 }
419
420 static Lisp_Object
421 mswindows_get_foreign_selection (Lisp_Object selection_symbol,
422 Lisp_Object target_type)
423 {
424 HGLOBAL hValue = NULL;
425 UINT cfType;
426 Lisp_Object cfObject = Qnil, ret = Qnil, value = Qnil;
427 int is_X_type = FALSE;
428 int size;
429 void *data;
430 struct frame *f = NULL;
431 struct gcpro gcpro1;
432
433 /* Only continue if we're trying to read the clipboard - mswindows doesn't
434 use the same selection model as X */
435 if (!EQ (selection_symbol, QCLIPBOARD))
436 return Qnil;
437
438 /* If this is one fo the X-style atom name symbols, or NIL, convert it
439 as appropriate */
440 if (NILP (target_type) || x_sym_p (target_type))
441 {
442 /* Should COMPOUND_TEXT map to CF_UNICODETEXT? */
443 cfType = CF_TEXT;
444 cfObject = QCF_TEXT;
445 is_X_type = TRUE;
446 }
447 else
448 {
449 cfType = symbol_to_ms_cf (target_type);
450
451 /* Only continue if we can figure out a clipboard type */
452 if (!cfType)
453 return Qnil;
454
455 cfObject = ms_cf_to_symbol (cfType);
456 }
457
458 /* Find the frame */
459 f = selected_frame ();
460
461 /* Open the clipboard */
462 if (!OpenClipboard (FRAME_MSWINDOWS_HANDLE (f)))
463 return Qnil;
464
465 /* Read the clipboard */
466 hValue = GetClipboardData (cfType);
467
468 if (!hValue)
469 {
470 CloseClipboard ();
471
472 return Qnil;
473 }
474
475 /* Find the data */
476 size = GlobalSize (hValue);
477 data = GlobalLock (hValue);
478
479 if (!data)
480 {
481 CloseClipboard ();
482
483 return Qnil;
484 }
485
486 /* Place it in a Lisp string */
487 TO_INTERNAL_FORMAT (DATA, (data, size),
488 LISP_STRING, ret,
489 Qbinary);
490
491 GlobalUnlock (data);
492 CloseClipboard ();
493
494 GCPRO1 (ret);
495
496 /* Convert this to the appropriate type. If we can't find anything,
497 then we return a cons of the form (DATA-TYPE . STRING), where the
498 string contains the raw binary data. */
499 value = select_convert_in (selection_symbol,
500 cfObject,
501 ret);
502
503 UNGCPRO;
504
505 if (NILP (value))
506 return Fcons (cfObject, ret);
507 else
508 return value;
509 }
510
511 static void
512 mswindows_disown_selection (Lisp_Object selection, Lisp_Object timeval)
513 {
514 if (EQ (selection, QCLIPBOARD))
515 {
516 BOOL success = OpenClipboard (NULL);
517 if (success)
518 {
519 success = EmptyClipboard ();
520 /* Close it regardless of whether empty worked. */
521 if (!CloseClipboard ())
522 success = FALSE;
523 }
524
525 /* #### return success ? Qt : Qnil; */
526 }
527 }
528
529 void
530 mswindows_destroy_selection (Lisp_Object selection)
531 {
532 Lisp_Object alist_elt;
533
534 /* Do nothing if this isn't for the clipboard. */
535 if (!EQ (selection, QCLIPBOARD))
536 return;
537
538 /* Right. We need to delete everything in Vhandle_alist. */
539 alist_elt = Vhandle_alist;
540
541 for (alist_elt; !NILP (alist_elt); alist_elt = Fcdr (alist_elt))
542 GlobalFree ((HGLOBAL) get_opaque_ptr (XCDR (alist_elt)));
543
544 Vhandle_alist = Qnil;
545 }
546
547 static Lisp_Object
548 mswindows_selection_exists_p (Lisp_Object selection,
549 Lisp_Object selection_type)
550 {
551 /* We used to be picky about the format, but now we support anything. */
552 if (EQ (selection, QCLIPBOARD))
553 {
554 if (NILP (selection_type))
555 return CountClipboardFormats () ? Qt : Qnil;
556 else
557 return IsClipboardFormatAvailable (symbol_to_ms_cf (selection_type))
558 ? Qt : Qnil;
559 }
560 else
561 return Qnil;
562 } 161 }
563 162
564 163
565 /************************************************************************/ 164 /************************************************************************/
566 /* initialization */ 165 /* initialization */
567 /************************************************************************/ 166 /************************************************************************/
568 167
569 void 168 void
570 console_type_create_select_mswindows (void)
571 {
572 CONSOLE_HAS_METHOD (mswindows, own_selection);
573 CONSOLE_HAS_METHOD (mswindows, disown_selection);
574 CONSOLE_HAS_METHOD (mswindows, selection_exists_p);
575 CONSOLE_HAS_METHOD (mswindows, get_foreign_selection);
576 CONSOLE_HAS_METHOD (mswindows, available_selection_types);
577 CONSOLE_HAS_METHOD (mswindows, register_selection_data_type);
578 CONSOLE_HAS_METHOD (mswindows, selection_data_type_name);
579 }
580
581 void
582 syms_of_select_mswindows (void) 169 syms_of_select_mswindows (void)
583 { 170 {
171 DEFSUBR (Fmswindows_set_clipboard);
172 DEFSUBR (Fmswindows_get_clipboard);
173 DEFSUBR (Fmswindows_selection_exists_p);
174 DEFSUBR (Fmswindows_delete_selection);
584 } 175 }
585 176
586 void 177 void
587 vars_of_select_mswindows (void) 178 vars_of_select_mswindows (void)
588 { 179 {
589 /* Initialise Vhandle_alist */
590 Vhandle_alist = Qnil;
591 staticpro (&Vhandle_alist);
592 } 180 }