Yet more syncing of xselect docs and argument specs
[bpt/emacs.git] / src / nsselect.m
CommitLineData
edfda783 1/* NeXT/Open/GNUstep / MacOSX Cocoa selection processing for emacs.
acaf905b 2 Copyright (C) 1993-1994, 2005-2006, 2008-2012
32d235f8 3 Free Software Foundation, Inc.
edfda783
AR
4
5This file is part of GNU Emacs.
6
32d235f8 7GNU Emacs is free software: you can redistribute it and/or modify
edfda783 8it under the terms of the GNU General Public License as published by
32d235f8
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
edfda783
AR
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
32d235f8 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
edfda783 19
32d235f8 20/*
edfda783
AR
21Originally by Carl Edman
22Updated by Christian Limpach (chris@nice.ch)
23OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
24MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
25GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
edfda783
AR
26*/
27
5a06864f
AR
28/* This should be the first include, as it may set up #defines affecting
29 interpretation of even the system includes. */
08a494a3 30#include <config.h>
b024548b 31#include <setjmp.h>
5a06864f 32
edfda783
AR
33#include "lisp.h"
34#include "nsterm.h"
35#include "termhooks.h"
921242c6 36#include "keyboard.h"
edfda783 37
64cb6c78 38Lisp_Object QCLIPBOARD, QSECONDARY, QTEXT, QFILE_NAME;
edfda783 39
00b3c7ac
TT
40static Lisp_Object Vselection_alist;
41
edfda783
AR
42static Lisp_Object Qforeign_selection;
43
64cb6c78
J
44/* NSGeneralPboard is pretty much analogous to X11 CLIPBOARD */
45NSString *NXPrimaryPboard;
edfda783
AR
46NSString *NXSecondaryPboard;
47
48
49
50/* ==========================================================================
51
52 Internal utility functions
53
54 ========================================================================== */
55
56
57static NSString *
58symbol_to_nsstring (Lisp_Object sym)
59{
60 CHECK_SYMBOL (sym);
c803b2b7 61 if (EQ (sym, QCLIPBOARD)) return NSGeneralPboard;
64cb6c78 62 if (EQ (sym, QPRIMARY)) return NXPrimaryPboard;
edfda783
AR
63 if (EQ (sym, QSECONDARY)) return NXSecondaryPboard;
64 if (EQ (sym, QTEXT)) return NSStringPboardType;
86fa089e 65 return [NSString stringWithUTF8String: SDATA (XSYMBOL (sym)->xname)];
edfda783
AR
66}
67
c803b2b7
JD
68static NSPasteboard *
69ns_symbol_to_pb (Lisp_Object symbol)
70{
71 return [NSPasteboard pasteboardWithName: symbol_to_nsstring (symbol)];
72}
edfda783
AR
73
74static Lisp_Object
75ns_string_to_symbol (NSString *t)
76{
77 if ([t isEqualToString: NSGeneralPboard])
64cb6c78
J
78 return QCLIPBOARD;
79 if ([t isEqualToString: NXPrimaryPboard])
edfda783
AR
80 return QPRIMARY;
81 if ([t isEqualToString: NXSecondaryPboard])
82 return QSECONDARY;
83 if ([t isEqualToString: NSStringPboardType])
84 return QTEXT;
85 if ([t isEqualToString: NSFilenamesPboardType])
86 return QFILE_NAME;
87 if ([t isEqualToString: NSTabularTextPboardType])
88 return QTEXT;
89 return intern ([t UTF8String]);
90}
91
92
93static Lisp_Object
94clean_local_selection_data (Lisp_Object obj)
95{
96 if (CONSP (obj)
97 && INTEGERP (XCAR (obj))
98 && CONSP (XCDR (obj))
99 && INTEGERP (XCAR (XCDR (obj)))
100 && NILP (XCDR (XCDR (obj))))
101 obj = Fcons (XCAR (obj), XCDR (obj));
102
103 if (CONSP (obj)
104 && INTEGERP (XCAR (obj))
105 && INTEGERP (XCDR (obj)))
106 {
107 if (XINT (XCAR (obj)) == 0)
108 return XCDR (obj);
109 if (XINT (XCAR (obj)) == -1)
110 return make_number (- XINT (XCDR (obj)));
111 }
112
113 if (VECTORP (obj))
114 {
115 int i;
facfbbbd 116 int size = ASIZE (obj);
edfda783
AR
117 Lisp_Object copy;
118
119 if (size == 1)
facfbbbd
SM
120 return clean_local_selection_data (AREF (obj, 0));
121 copy = Fmake_vector (make_number (size), Qnil);
edfda783 122 for (i = 0; i < size; i++)
86fa089e 123 ASET (copy, i, clean_local_selection_data (AREF (obj, i)));
edfda783
AR
124 return copy;
125 }
126
127 return obj;
128}
129
130
131static void
132ns_declare_pasteboard (id pb)
133{
134 [pb declareTypes: ns_send_types owner: NSApp];
135}
136
137
138static void
139ns_undeclare_pasteboard (id pb)
140{
141 [pb declareTypes: [NSArray array] owner: nil];
142}
143
144
145static void
146ns_string_to_pasteboard_internal (id pb, Lisp_Object str, NSString *gtype)
147{
148 if (EQ (str, Qnil))
149 {
150 [pb declareTypes: [NSArray array] owner: nil];
151 }
152 else
153 {
154 char *utfStr;
155 NSString *type, *nsStr;
156 NSEnumerator *tenum;
157
158 CHECK_STRING (str);
159
86fa089e 160 utfStr = SDATA (str);
497a1925
JD
161 nsStr = [[NSString alloc] initWithBytesNoCopy: utfStr
162 length: SBYTES (str)
163 encoding: NSUTF8StringEncoding
164 freeWhenDone: NO];
edfda783
AR
165 if (gtype == nil)
166 {
167 [pb declareTypes: ns_send_types owner: nil];
168 tenum = [ns_send_types objectEnumerator];
169 while ( (type = [tenum nextObject]) )
170 [pb setString: nsStr forType: type];
171 }
172 else
173 {
174 [pb setString: nsStr forType: gtype];
175 }
497a1925 176 [nsStr release];
edfda783
AR
177 }
178}
179
180
699c10bd 181Lisp_Object
edfda783
AR
182ns_get_local_selection (Lisp_Object selection_name,
183 Lisp_Object target_type)
184{
185 Lisp_Object local_value;
186 Lisp_Object handler_fn, value, type, check;
187 int count;
188
189 local_value = assq_no_quit (selection_name, Vselection_alist);
190
191 if (NILP (local_value)) return Qnil;
192
193 count = specpdl_ptr - specpdl;
194 specbind (Qinhibit_quit, Qt);
195 CHECK_SYMBOL (target_type);
196 handler_fn = Fcdr (Fassq (target_type, Vselection_converter_alist));
197 if (!NILP (handler_fn))
facfbbbd 198 value = call3 (handler_fn, selection_name, target_type,
edfda783
AR
199 XCAR (XCDR (local_value)));
200 else
facfbbbd 201 value = Qnil;
edfda783
AR
202 unbind_to (count, Qnil);
203
facfbbbd 204 check = value;
edfda783
AR
205 if (CONSP (value) && SYMBOLP (XCAR (value)))
206 {
207 type = XCAR (value);
208 check = XCDR (value);
209 }
210
211 if (STRINGP (check) || VECTORP (check) || SYMBOLP (check)
212 || INTEGERP (check) || NILP (value))
213 return value;
214
215 if (CONSP (check)
216 && INTEGERP (XCAR (check))
217 && (INTEGERP (XCDR (check))||
218 (CONSP (XCDR (check))
219 && INTEGERP (XCAR (XCDR (check)))
220 && NILP (XCDR (XCDR (check))))))
221 return value;
222
facfbbbd 223 // FIXME: Why `quit' rather than `error'?
edfda783
AR
224 Fsignal (Qquit, Fcons (build_string (
225 "invalid data returned by selection-conversion function"),
226 Fcons (handler_fn, Fcons (value, Qnil))));
facfbbbd
SM
227 // FIXME: Beware, `quit' can return!!
228 return Qnil;
edfda783
AR
229}
230
231
232static Lisp_Object
233ns_get_foreign_selection (Lisp_Object symbol, Lisp_Object target)
234{
235 id pb;
c803b2b7
JD
236 pb = ns_symbol_to_pb (symbol);
237 return pb != nil ? ns_string_from_pasteboard (pb) : Qnil;
edfda783
AR
238}
239
240
edfda783
AR
241
242
243/* ==========================================================================
244
245 Functions used externally
246
247 ========================================================================== */
248
249
250Lisp_Object
251ns_string_from_pasteboard (id pb)
252{
253 NSString *type, *str;
254 const char *utfStr;
497a1925 255 int length;
edfda783
AR
256
257 type = [pb availableTypeFromArray: ns_return_types];
258 if (type == nil)
259 {
260 Fsignal (Qquit,
261 Fcons (build_string ("empty or unsupported pasteboard type"),
262 Qnil));
263 return Qnil;
264 }
265
266 /* get the string */
267 if (! (str = [pb stringForType: type]))
268 {
269 NSData *data = [pb dataForType: type];
270 if (data != nil)
271 str = [[NSString alloc] initWithData: data
272 encoding: NSUTF8StringEncoding];
273 if (str != nil)
274 {
275 [str autorelease];
276 }
277 else
278 {
279 Fsignal (Qquit,
280 Fcons (build_string ("pasteboard doesn't contain valid data"),
281 Qnil));
282 return Qnil;
283 }
284 }
285
286 /* assume UTF8 */
287 NS_DURING
288 {
289 /* EOL conversion: PENDING- is this too simple? */
290 NSMutableString *mstr = [[str mutableCopy] autorelease];
291 [mstr replaceOccurrencesOfString: @"\r\n" withString: @"\n"
292 options: NSLiteralSearch range: NSMakeRange (0, [mstr length])];
293 [mstr replaceOccurrencesOfString: @"\r" withString: @"\n"
294 options: NSLiteralSearch range: NSMakeRange (0, [mstr length])];
295
296 utfStr = [mstr UTF8String];
497a1925
JD
297 length = [mstr lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
298
4393663b 299#if ! defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4
497a1925
JD
300 if (!utfStr)
301 {
302 utfStr = [mstr cString];
303 length = strlen (utfStr);
304 }
4393663b 305#endif
edfda783
AR
306 }
307 NS_HANDLER
308 {
309 message1 ("ns_string_from_pasteboard: UTF8String failed\n");
4393663b
JD
310#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
311 utfStr = "Conversion failed";
312#else
edfda783 313 utfStr = [str lossyCString];
4393663b 314#endif
497a1925 315 length = strlen (utfStr);
edfda783
AR
316 }
317 NS_ENDHANDLER
318
497a1925 319 return make_string (utfStr, length);
edfda783
AR
320}
321
322
323void
324ns_string_to_pasteboard (id pb, Lisp_Object str)
325{
326 ns_string_to_pasteboard_internal (pb, str, nil);
327}
328
329
330
331/* ==========================================================================
332
333 Lisp Defuns
334
335 ========================================================================== */
336
337
28bf482a 338DEFUN ("x-own-selection-internal", Fx_own_selection_internal,
bd7da63e
GM
339 Sx_own_selection_internal, 2, 3, 0,
340 doc: /* Assert an X selection of type SELECTION and value VALUE.
341SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
342\(Those are literal upper-case symbol names, since that's what X expects.)
a5c55c69 343VALUE is typically a string, or a cons of two markers, but may be
bd7da63e
GM
344anything that the functions on `selection-converter-alist' know about.
345
346FRAME should be a frame that should own the selection. If omitted or
347nil, it defaults to the selected frame.
348
349On Nextstep, FRAME is unused. */)
350 (Lisp_Object selection, Lisp_Object value, Lisp_Object frame)
edfda783
AR
351{
352 id pb;
353 Lisp_Object old_value, new_value;
c803b2b7
JD
354 NSString *type;
355 Lisp_Object successful_p = Qnil, rest;
356 Lisp_Object target_symbol, data;
357
edfda783
AR
358
359 check_ns ();
bd7da63e
GM
360 CHECK_SYMBOL (selection);
361 if (NILP (value))
362 error ("selection value may not be nil.");
363 pb = ns_symbol_to_pb (selection);
c803b2b7
JD
364 if (pb == nil) return Qnil;
365
edfda783 366 ns_declare_pasteboard (pb);
bd7da63e
GM
367 old_value = assq_no_quit (selection, Vselection_alist);
368 new_value = Fcons (selection, Fcons (value, Qnil));
c803b2b7 369
edfda783 370 if (NILP (old_value))
facfbbbd 371 Vselection_alist = Fcons (new_value, Vselection_alist);
edfda783
AR
372 else
373 Fsetcdr (old_value, Fcdr (new_value));
c803b2b7
JD
374
375 /* We only support copy of text. */
376 type = NSStringPboardType;
377 target_symbol = ns_string_to_symbol (type);
bd7da63e 378 data = ns_get_local_selection (selection, target_symbol);
c803b2b7
JD
379 if (!NILP (data))
380 {
381 if (STRINGP (data))
382 ns_string_to_pasteboard_internal (pb, data, type);
383 successful_p = Qt;
384 }
385
386 if (!EQ (Vns_sent_selection_hooks, Qunbound))
387 {
388 for (rest = Vns_sent_selection_hooks; CONSP (rest); rest = Fcdr (rest))
bd7da63e 389 call3 (Fcar (rest), selection, target_symbol, successful_p);
c803b2b7
JD
390 }
391
bd7da63e 392 return value;
edfda783
AR
393}
394
395
9e50ff0c 396DEFUN ("x-disown-selection-internal", Fx_disown_selection_internal,
bd7da63e
GM
397 Sx_disown_selection_internal, 1, 3, 0,
398 doc: /* If we own the selection SELECTION, disown it.
399Disowning it means there is no such selection.
400
401Sets the last-change time for the selection to TIME-OBJECT (by default
402the time of the last event).
403
404TERMINAL should be a terminal object or a frame specifying the X
405server to query. If omitted or nil, that stands for the selected
406frame's display, or the first available X display.
407
408On Nextstep, the TIME-OBJECT and TERMINAL arguments are unused.
409On MS-DOS, all this does is return non-nil if we own the selection. */)
410 (Lisp_Object selection, Lisp_Object time_object, Lisp_Object terminal)
edfda783
AR
411{
412 id pb;
413 check_ns ();
bd7da63e
GM
414 CHECK_SYMBOL (selection);
415 if (NILP (assq_no_quit (selection, Vselection_alist))) return Qnil;
edfda783 416
bd7da63e 417 pb = ns_symbol_to_pb (selection);
c803b2b7 418 if (pb != nil) ns_undeclare_pasteboard (pb);
edfda783
AR
419 return Qt;
420}
421
422
28bf482a 423DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
bd7da63e
GM
424 0, 2, 0, doc: /* Whether there is an owner for the given X selection.
425SELECTION should be the name of the selection in question, typically
426one of the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'. (X expects
427these literal upper-case names.) The symbol nil is the same as
428`PRIMARY', and t is the same as `SECONDARY'.
429
430TERMINAL should be a terminal object or a frame specifying the X
431server to query. If omitted or nil, that stands for the selected
432frame's display, or the first available X display.
433
434On Nextstep, TERMINAL is unused. */)
435 (Lisp_Object selection, Lisp_Object terminal)
edfda783
AR
436{
437 id pb;
438 NSArray *types;
439
440 check_ns ();
441 CHECK_SYMBOL (selection);
442 if (EQ (selection, Qnil)) selection = QPRIMARY;
443 if (EQ (selection, Qt)) selection = QSECONDARY;
c803b2b7
JD
444 pb = ns_symbol_to_pb (selection);
445 if (pb == nil) return Qnil;
446
447 types = [pb types];
edfda783
AR
448 return ([types count] == 0) ? Qnil : Qt;
449}
450
451
28bf482a 452DEFUN ("x-selection-owner-p", Fx_selection_owner_p, Sx_selection_owner_p,
bd7da63e
GM
453 0, 2, 0,
454 doc: /* Whether the current Emacs process owns the given X Selection.
a5c55c69
CY
455The arg should be the name of the selection in question, typically one of
456the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
bd7da63e 457\(Those are literal upper-case symbol names, since that's what X expects.)
a5c55c69 458For convenience, the symbol nil is the same as `PRIMARY',
bd7da63e
GM
459and t is the same as `SECONDARY'.
460
461TERMINAL should be a terminal object or a frame specifying the X
462server to query. If omitted or nil, that stands for the selected
463frame's display, or the first available X display.
464
465On Nextstep, TERMINAL is unused. */)
466 (Lisp_Object selection, Lisp_Object terminal)
edfda783
AR
467{
468 check_ns ();
469 CHECK_SYMBOL (selection);
470 if (EQ (selection, Qnil)) selection = QPRIMARY;
471 if (EQ (selection, Qt)) selection = QSECONDARY;
472 return (NILP (Fassq (selection, Vselection_alist))) ? Qnil : Qt;
473}
474
475
9e50ff0c 476DEFUN ("x-get-selection-internal", Fx_get_selection_internal,
bd7da63e
GM
477 Sx_get_selection_internal, 2, 4, 0,
478 doc: /* Return text selected from some X window.
479SELECTION-SYMBOL is typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
480\(Those are literal upper-case symbol names, since that's what X expects.)
481TARGET-TYPE is the type of data desired, typically `STRING'.
482
483TIME-STAMP is the time to use in the XConvertSelection call for foreign
484selections. If omitted, defaults to the time for the last event.
485
486TERMINAL should be a terminal object or a frame specifying the X
487server to query. If omitted or nil, that stands for the selected
488frame's display, or the first available X display.
489
490On Nextstep, TIME-STAMP and TERMINAL are unused. */)
491 (Lisp_Object selection_name, Lisp_Object target_type,
492 Lisp_Object time_stamp, Lisp_Object terminal)
edfda783
AR
493{
494 Lisp_Object val;
495
496 check_ns ();
497 CHECK_SYMBOL (selection_name);
498 CHECK_SYMBOL (target_type);
499 val = ns_get_local_selection (selection_name, target_type);
500 if (NILP (val))
501 val = ns_get_foreign_selection (selection_name, target_type);
502 if (CONSP (val) && SYMBOLP (Fcar (val)))
503 {
504 val = Fcdr (val);
505 if (CONSP (val) && NILP (Fcdr (val)))
506 val = Fcar (val);
507 }
508 val = clean_local_selection_data (val);
509 return val;
510}
511
512
c803b2b7
JD
513DEFUN ("ns-get-selection-internal", Fns_get_selection_internal,
514 Sns_get_selection_internal, 1, 1, 0,
515 doc: /* Returns the value of SELECTION as a string.
516SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'. */)
517 (Lisp_Object selection)
edfda783
AR
518{
519 id pb;
520 check_ns ();
c803b2b7
JD
521 pb = ns_symbol_to_pb (selection);
522 return pb != nil ? ns_string_from_pasteboard (pb) : Qnil;
edfda783
AR
523}
524
525
c803b2b7
JD
526DEFUN ("ns-store-selection-internal", Fns_store_selection_internal,
527 Sns_store_selection_internal, 2, 2, 0,
528 doc: /* Sets the string value of SELECTION.
529SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'. */)
530 (Lisp_Object selection, Lisp_Object string)
edfda783
AR
531{
532 id pb;
533 check_ns ();
c803b2b7
JD
534 pb = ns_symbol_to_pb (selection);
535 if (pb != nil) ns_string_to_pasteboard (pb, string);
edfda783
AR
536 return Qnil;
537}
edfda783
AR
538
539
540void
541nxatoms_of_nsselect (void)
542{
2c0ac867
J
543 NXPrimaryPboard = @"Selection";
544 NXSecondaryPboard = @"Secondary";
edfda783
AR
545}
546
547void
548syms_of_nsselect (void)
549{
088dcc3e
DN
550 QCLIPBOARD = intern_c_string ("CLIPBOARD"); staticpro (&QCLIPBOARD);
551 QSECONDARY = intern_c_string ("SECONDARY"); staticpro (&QSECONDARY);
552 QTEXT = intern_c_string ("TEXT"); staticpro (&QTEXT);
553 QFILE_NAME = intern_c_string ("FILE_NAME"); staticpro (&QFILE_NAME);
edfda783 554
9e50ff0c
DN
555 defsubr (&Sx_disown_selection_internal);
556 defsubr (&Sx_get_selection_internal);
28bf482a
DR
557 defsubr (&Sx_own_selection_internal);
558 defsubr (&Sx_selection_exists_p);
559 defsubr (&Sx_selection_owner_p);
c803b2b7
JD
560 defsubr (&Sns_get_selection_internal);
561 defsubr (&Sns_store_selection_internal);
edfda783
AR
562
563 Vselection_alist = Qnil;
564 staticpro (&Vselection_alist);
565
fb9d0f5a 566 DEFVAR_LISP ("ns-sent-selection-hooks", Vns_sent_selection_hooks,
edfda783
AR
567 "A list of functions to be called when Emacs answers a selection request.\n\
568The functions are called with four arguments:\n\
569 - the selection name (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');\n\
570 - the selection-type which Emacs was asked to convert the\n\
571 selection into before sending (for example, `STRING' or `LENGTH');\n\
572 - a flag indicating success or failure for responding to the request.\n\
573We might have failed (and declined the request) for any number of reasons,\n\
574including being asked for a selection that we no longer own, or being asked\n\
575to convert into a type that we don't know about or that is inappropriate.\n\
576This hook doesn't let you change the behavior of Emacs's selection replies,\n\
577it merely informs you that they have happened.");
578 Vns_sent_selection_hooks = Qnil;
579
fb9d0f5a 580 DEFVAR_LISP ("selection-converter-alist", Vselection_converter_alist,
edfda783
AR
581 "An alist associating X Windows selection-types with functions.\n\
582These functions are called to convert the selection, with three args:\n\
583the name of the selection (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');\n\
584a desired type to which the selection should be converted;\n\
585and the local selection value (whatever was given to `x-own-selection').\n\
586\n\
587The function should return the value to send to the X server\n\
588\(typically a string). A return value of nil\n\
589means that the conversion could not be done.\n\
590A return value which is the symbol `NULL'\n\
591means that a side-effect was executed,\n\
592and there is no meaningful selection value.");
593 Vselection_converter_alist = Qnil;
594
fb9d0f5a 595 DEFVAR_LISP ("ns-lost-selection-hooks", Vns_lost_selection_hooks,
edfda783
AR
596 "A list of functions to be called when Emacs loses an X selection.\n\
597\(This happens when some other X client makes its own selection\n\
598or when a Lisp program explicitly clears the selection.)\n\
599The functions are called with one argument, the selection type\n\
600\(a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD').");
601 Vns_lost_selection_hooks = Qnil;
602
088dcc3e 603 Qforeign_selection = intern_c_string ("foreign-selection");
edfda783 604 staticpro (&Qforeign_selection);
edfda783 605}
0ae1e5e5 606