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