fix up ns-extended-platform-support-mode
[bpt/emacs.git] / src / macselect.c
1 /* Selection processing for Emacs on Mac OS.
2 Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
3
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 3 of the License, or
9 (at your option) 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. If not, see <http://www.gnu.org/licenses/>. */
18
19 #include <config.h>
20
21 #include "lisp.h"
22 #include "macterm.h"
23 #include "blockinput.h"
24 #include "keymap.h"
25
26 #if !TARGET_API_MAC_CARBON
27 #include <Endian.h>
28 #endif
29
30 static void x_own_selection P_ ((Lisp_Object, Lisp_Object));
31 static Lisp_Object x_get_local_selection P_ ((Lisp_Object, Lisp_Object, int));
32 static Lisp_Object x_get_foreign_selection P_ ((Lisp_Object,
33 Lisp_Object,
34 Lisp_Object));
35
36 Lisp_Object QPRIMARY, QSECONDARY, QTIMESTAMP, QTARGETS;
37
38 static Lisp_Object Vx_lost_selection_functions;
39 /* Coding system for communicating with other programs via selections. */
40 static Lisp_Object Vselection_coding_system;
41
42 /* Coding system for the next communicating with other programs. */
43 static Lisp_Object Vnext_selection_coding_system;
44
45 static Lisp_Object Qforeign_selection;
46
47 /* The timestamp of the last input event Emacs received from the
48 window server. */
49 /* Defined in keyboard.c. */
50 extern unsigned long last_event_timestamp;
51
52 /* This is an association list whose elements are of the form
53 ( SELECTION-NAME SELECTION-VALUE SELECTION-TIMESTAMP FRAME OWNERSHIP-INFO)
54 SELECTION-NAME is a lisp symbol.
55 SELECTION-VALUE is the value that emacs owns for that selection.
56 It may be any kind of Lisp object.
57 SELECTION-TIMESTAMP is the time at which emacs began owning this selection,
58 as a cons of two 16-bit numbers (making a 32 bit time.)
59 FRAME is the frame for which we made the selection.
60 OWNERSHIP-INFO is a value saved when emacs owns for that selection.
61 If another application takes the ownership of that selection
62 later, then newly examined ownership info value should be
63 different from the saved one.
64 If there is an entry in this alist, the current ownership info for
65 the selection coincides with OWNERSHIP-INFO, then it can be
66 assumed that Emacs owns that selection.
67 The only (eq) parts of this list that are visible from Lisp are the
68 selection-values. */
69 static Lisp_Object Vselection_alist;
70
71 /* This is an alist whose CARs are selection-types and whose CDRs are
72 the names of Lisp functions to call to convert the given Emacs
73 selection value to a string representing the given selection type.
74 This is for Lisp-level extension of the emacs selection
75 handling. */
76 Lisp_Object Vselection_converter_alist;
77
78 /* A selection name (represented as a Lisp symbol) can be associated
79 with a named scrap via `mac-scrap-name' property. Likewise for a
80 selection type with a scrap flavor type via `mac-ostype'. */
81 Lisp_Object Qmac_scrap_name, Qmac_ostype;
82
83 \f
84 /* Do protocol to assert ourself as a selection owner.
85 Update the Vselection_alist so that we can reply to later requests for
86 our selection. */
87
88 static void
89 x_own_selection (selection_name, selection_value)
90 Lisp_Object selection_name, selection_value;
91 {
92 OSStatus err;
93 Selection sel;
94 struct gcpro gcpro1, gcpro2;
95 Lisp_Object rest, handler_fn, value, target_type;
96 int count;
97
98 CHECK_SYMBOL (selection_name);
99
100 GCPRO2 (selection_name, selection_value);
101
102 BLOCK_INPUT;
103
104 err = mac_get_selection_from_symbol (selection_name, 1, &sel);
105 if (err == noErr && sel)
106 {
107 /* Don't allow a quit within the converter.
108 When the user types C-g, he would be surprised
109 if by luck it came during a converter. */
110 count = SPECPDL_INDEX ();
111 specbind (Qinhibit_quit, Qt);
112
113 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
114 {
115 if (!(CONSP (XCAR (rest))
116 && (target_type = XCAR (XCAR (rest)),
117 SYMBOLP (target_type))
118 && mac_valid_selection_target_p (target_type)
119 && (handler_fn = XCDR (XCAR (rest)),
120 SYMBOLP (handler_fn))))
121 continue;
122
123 if (!NILP (handler_fn))
124 value = call3 (handler_fn, selection_name,
125 target_type, selection_value);
126
127 if (NILP (value))
128 continue;
129
130 if (mac_valid_selection_value_p (value, target_type))
131 err = mac_put_selection_value (sel, target_type, value);
132 else if (CONSP (value)
133 && EQ (XCAR (value), target_type)
134 && mac_valid_selection_value_p (XCDR (value), target_type))
135 err = mac_put_selection_value (sel, target_type, XCDR (value));
136 }
137
138 unbind_to (count, Qnil);
139 }
140
141 UNBLOCK_INPUT;
142
143 UNGCPRO;
144
145 if (sel && err != noErr)
146 error ("Can't set selection");
147
148 /* Now update the local cache */
149 {
150 Lisp_Object selection_time;
151 Lisp_Object selection_data;
152 Lisp_Object ownership_info;
153 Lisp_Object prev_value;
154
155 selection_time = long_to_cons (last_event_timestamp);
156 if (sel)
157 {
158 BLOCK_INPUT;
159 ownership_info = mac_get_selection_ownership_info (sel);
160 UNBLOCK_INPUT;
161 }
162 else
163 ownership_info = Qnil; /* dummy value for local-only selection */
164 selection_data = Fcons (selection_name,
165 Fcons (selection_value,
166 Fcons (selection_time,
167 Fcons (selected_frame,
168 Fcons (ownership_info,
169 Qnil)))));
170 prev_value = assq_no_quit (selection_name, Vselection_alist);
171
172 Vselection_alist = Fcons (selection_data, Vselection_alist);
173
174 /* If we already owned the selection, remove the old selection data.
175 Perhaps we should destructively modify it instead.
176 Don't use Fdelq as that may QUIT. */
177 if (!NILP (prev_value))
178 {
179 Lisp_Object rest; /* we know it's not the CAR, so it's easy. */
180 for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest))
181 if (EQ (prev_value, Fcar (XCDR (rest))))
182 {
183 XSETCDR (rest, Fcdr (XCDR (rest)));
184 break;
185 }
186 }
187 }
188 }
189 \f
190 /* Given a selection-name and desired type, look up our local copy of
191 the selection value and convert it to the type.
192 The value is nil or a string.
193 This function is used both for remote requests (LOCAL_REQUEST is zero)
194 and for local x-get-selection-internal (LOCAL_REQUEST is nonzero).
195
196 This calls random Lisp code, and may signal or gc. */
197
198 static Lisp_Object
199 x_get_local_selection (selection_symbol, target_type, local_request)
200 Lisp_Object selection_symbol, target_type;
201 int local_request;
202 {
203 Lisp_Object local_value;
204 Lisp_Object handler_fn, value, type, check;
205 int count;
206
207 if (NILP (Fx_selection_owner_p (selection_symbol)))
208 return Qnil;
209
210 local_value = assq_no_quit (selection_symbol, Vselection_alist);
211
212 /* TIMESTAMP is a special case 'cause that's easiest. */
213 if (EQ (target_type, QTIMESTAMP))
214 {
215 handler_fn = Qnil;
216 value = XCAR (XCDR (XCDR (local_value)));
217 }
218 #if 0
219 else if (EQ (target_type, QDELETE))
220 {
221 handler_fn = Qnil;
222 Fx_disown_selection_internal
223 (selection_symbol,
224 XCAR (XCDR (XCDR (local_value))));
225 value = QNULL;
226 }
227 #endif
228 else
229 {
230 /* Don't allow a quit within the converter.
231 When the user types C-g, he would be surprised
232 if by luck it came during a converter. */
233 count = SPECPDL_INDEX ();
234 specbind (Qinhibit_quit, Qt);
235
236 CHECK_SYMBOL (target_type);
237 handler_fn = Fcdr (Fassq (target_type, Vselection_converter_alist));
238 /* gcpro is not needed here since nothing but HANDLER_FN
239 is live, and that ought to be a symbol. */
240
241 if (!NILP (handler_fn))
242 value = call3 (handler_fn,
243 selection_symbol, (local_request ? Qnil : target_type),
244 XCAR (XCDR (local_value)));
245 else
246 value = Qnil;
247 unbind_to (count, Qnil);
248 }
249
250 if (local_request)
251 return value;
252
253 /* Make sure this value is of a type that we could transmit
254 to another application. */
255
256 type = target_type;
257 check = value;
258 if (CONSP (value)
259 && SYMBOLP (XCAR (value)))
260 type = XCAR (value),
261 check = XCDR (value);
262
263 if (NILP (value) || mac_valid_selection_value_p (check, type))
264 return value;
265
266 signal_error ("Invalid data returned by selection-conversion function",
267 list2 (handler_fn, value));
268 }
269
270 \f
271 /* Clear all selections that were made from frame F.
272 We do this when about to delete a frame. */
273
274 void
275 x_clear_frame_selections (f)
276 FRAME_PTR f;
277 {
278 Lisp_Object frame;
279 Lisp_Object rest;
280
281 XSETFRAME (frame, f);
282
283 /* Otherwise, we're really honest and truly being told to drop it.
284 Don't use Fdelq as that may QUIT;. */
285
286 /* Delete elements from the beginning of Vselection_alist. */
287 while (!NILP (Vselection_alist)
288 && EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (Vselection_alist)))))))
289 {
290 /* Let random Lisp code notice that the selection has been stolen. */
291 Lisp_Object hooks, selection_symbol;
292
293 hooks = Vx_lost_selection_functions;
294 selection_symbol = Fcar (Fcar (Vselection_alist));
295
296 if (!EQ (hooks, Qunbound)
297 && !NILP (Fx_selection_owner_p (selection_symbol)))
298 {
299 for (; CONSP (hooks); hooks = Fcdr (hooks))
300 call1 (Fcar (hooks), selection_symbol);
301 #if 0 /* This can crash when deleting a frame
302 from x_connection_closed. Anyway, it seems unnecessary;
303 something else should cause a redisplay. */
304 redisplay_preserve_echo_area (21);
305 #endif
306 }
307
308 Vselection_alist = Fcdr (Vselection_alist);
309 }
310
311 /* Delete elements after the beginning of Vselection_alist. */
312 for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest))
313 if (EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (XCDR (rest))))))))
314 {
315 /* Let random Lisp code notice that the selection has been stolen. */
316 Lisp_Object hooks, selection_symbol;
317
318 hooks = Vx_lost_selection_functions;
319 selection_symbol = Fcar (Fcar (XCDR (rest)));
320
321 if (!EQ (hooks, Qunbound)
322 && !NILP (Fx_selection_owner_p (selection_symbol)))
323 {
324 for (; CONSP (hooks); hooks = Fcdr (hooks))
325 call1 (Fcar (hooks), selection_symbol);
326 #if 0 /* See above */
327 redisplay_preserve_echo_area (22);
328 #endif
329 }
330 XSETCDR (rest, Fcdr (XCDR (rest)));
331 break;
332 }
333 }
334 \f
335 /* Do protocol to read selection-data from the server.
336 Converts this to Lisp data and returns it. */
337
338 static Lisp_Object
339 x_get_foreign_selection (selection_symbol, target_type, time_stamp)
340 Lisp_Object selection_symbol, target_type, time_stamp;
341 {
342 OSStatus err;
343 Selection sel;
344 Lisp_Object result = Qnil;
345
346 BLOCK_INPUT;
347
348 err = mac_get_selection_from_symbol (selection_symbol, 0, &sel);
349 if (err == noErr && sel)
350 {
351 if (EQ (target_type, QTARGETS))
352 {
353 result = mac_get_selection_target_list (sel);
354 result = Fvconcat (1, &result);
355 }
356 else
357 {
358 result = mac_get_selection_value (sel, target_type);
359 if (STRINGP (result))
360 Fput_text_property (make_number (0), make_number (SBYTES (result)),
361 Qforeign_selection, target_type, result);
362 }
363 }
364
365 UNBLOCK_INPUT;
366
367 return result;
368 }
369
370
371 DEFUN ("x-own-selection-internal", Fx_own_selection_internal,
372 Sx_own_selection_internal, 2, 2, 0,
373 doc: /* Assert a selection of the given TYPE with the given VALUE.
374 TYPE is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
375 VALUE is typically a string, or a cons of two markers, but may be
376 anything that the functions on `selection-converter-alist' know about. */)
377 (selection_name, selection_value)
378 Lisp_Object selection_name, selection_value;
379 {
380 check_mac ();
381 CHECK_SYMBOL (selection_name);
382 if (NILP (selection_value)) error ("SELECTION-VALUE may not be nil");
383 x_own_selection (selection_name, selection_value);
384 return selection_value;
385 }
386
387
388 /* Request the selection value from the owner. If we are the owner,
389 simply return our selection value. If we are not the owner, this
390 will block until all of the data has arrived. */
391
392 DEFUN ("x-get-selection-internal", Fx_get_selection_internal,
393 Sx_get_selection_internal, 2, 3, 0,
394 doc: /* Return text selected from some Mac application.
395 SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
396 TYPE is the type of data desired, typically `STRING'.
397 TIME_STAMP is ignored on Mac. */)
398 (selection_symbol, target_type, time_stamp)
399 Lisp_Object selection_symbol, target_type, time_stamp;
400 {
401 Lisp_Object val = Qnil;
402 struct gcpro gcpro1, gcpro2;
403 GCPRO2 (target_type, val); /* we store newly consed data into these */
404 check_mac ();
405 CHECK_SYMBOL (selection_symbol);
406 CHECK_SYMBOL (target_type);
407
408 val = x_get_local_selection (selection_symbol, target_type, 1);
409
410 if (NILP (val))
411 {
412 val = x_get_foreign_selection (selection_symbol, target_type, time_stamp);
413 goto DONE;
414 }
415
416 if (CONSP (val)
417 && SYMBOLP (XCAR (val)))
418 {
419 val = XCDR (val);
420 if (CONSP (val) && NILP (XCDR (val)))
421 val = XCAR (val);
422 }
423 DONE:
424 UNGCPRO;
425 return val;
426 }
427
428 DEFUN ("x-disown-selection-internal", Fx_disown_selection_internal,
429 Sx_disown_selection_internal, 1, 2, 0,
430 doc: /* If we own the selection SELECTION, disown it.
431 Disowning it means there is no such selection. */)
432 (selection, time)
433 Lisp_Object selection;
434 Lisp_Object time;
435 {
436 OSStatus err;
437 Selection sel;
438 Lisp_Object local_selection_data;
439
440 check_mac ();
441 CHECK_SYMBOL (selection);
442
443 if (NILP (Fx_selection_owner_p (selection)))
444 return Qnil; /* Don't disown the selection when we're not the owner. */
445
446 local_selection_data = assq_no_quit (selection, Vselection_alist);
447
448 /* Don't use Fdelq as that may QUIT;. */
449
450 if (EQ (local_selection_data, Fcar (Vselection_alist)))
451 Vselection_alist = Fcdr (Vselection_alist);
452 else
453 {
454 Lisp_Object rest;
455 for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest))
456 if (EQ (local_selection_data, Fcar (XCDR (rest))))
457 {
458 XSETCDR (rest, Fcdr (XCDR (rest)));
459 break;
460 }
461 }
462
463 /* Let random lisp code notice that the selection has been stolen. */
464
465 {
466 Lisp_Object rest;
467 rest = Vx_lost_selection_functions;
468 if (!EQ (rest, Qunbound))
469 {
470 for (; CONSP (rest); rest = Fcdr (rest))
471 call1 (Fcar (rest), selection);
472 prepare_menu_bars ();
473 redisplay_preserve_echo_area (20);
474 }
475 }
476
477 BLOCK_INPUT;
478
479 err = mac_get_selection_from_symbol (selection, 0, &sel);
480 if (err == noErr && sel)
481 mac_clear_selection (&sel);
482
483 UNBLOCK_INPUT;
484
485 return Qt;
486 }
487
488
489 DEFUN ("x-selection-owner-p", Fx_selection_owner_p, Sx_selection_owner_p,
490 0, 1, 0,
491 doc: /* Whether the current Emacs process owns the given SELECTION.
492 The arg should be the name of the selection in question, typically one of
493 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
494 For convenience, the symbol nil is the same as `PRIMARY',
495 and t is the same as `SECONDARY'. */)
496 (selection)
497 Lisp_Object selection;
498 {
499 OSStatus err;
500 Selection sel;
501 Lisp_Object result = Qnil, local_selection_data;
502
503 check_mac ();
504 CHECK_SYMBOL (selection);
505 if (EQ (selection, Qnil)) selection = QPRIMARY;
506 if (EQ (selection, Qt)) selection = QSECONDARY;
507
508 local_selection_data = assq_no_quit (selection, Vselection_alist);
509
510 if (NILP (local_selection_data))
511 return Qnil;
512
513 BLOCK_INPUT;
514
515 err = mac_get_selection_from_symbol (selection, 0, &sel);
516 if (err == noErr && sel)
517 {
518 Lisp_Object ownership_info;
519
520 ownership_info = XCAR (XCDR (XCDR (XCDR (XCDR (local_selection_data)))));
521 if (!NILP (Fequal (ownership_info,
522 mac_get_selection_ownership_info (sel))))
523 result = Qt;
524 }
525 else
526 result = Qt;
527
528 UNBLOCK_INPUT;
529
530 return result;
531 }
532
533 DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
534 0, 1, 0,
535 doc: /* Whether there is an owner for the given SELECTION.
536 The arg should be the name of the selection in question, typically one of
537 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
538 For convenience, the symbol nil is the same as `PRIMARY',
539 and t is the same as `SECONDARY'. */)
540 (selection)
541 Lisp_Object selection;
542 {
543 OSStatus err;
544 Selection sel;
545 Lisp_Object result = Qnil, rest;
546
547 /* It should be safe to call this before we have an Mac frame. */
548 if (! FRAME_MAC_P (SELECTED_FRAME ()))
549 return Qnil;
550
551 CHECK_SYMBOL (selection);
552 if (!NILP (Fx_selection_owner_p (selection)))
553 return Qt;
554 if (EQ (selection, Qnil)) selection = QPRIMARY;
555 if (EQ (selection, Qt)) selection = QSECONDARY;
556
557 BLOCK_INPUT;
558
559 err = mac_get_selection_from_symbol (selection, 0, &sel);
560 if (err == noErr && sel)
561 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
562 {
563 if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
564 && mac_selection_has_target_p (sel, XCAR (XCAR (rest))))
565 {
566 result = Qt;
567 break;
568 }
569 }
570
571 UNBLOCK_INPUT;
572
573 return result;
574 }
575
576 \f
577 /***********************************************************************
578 Apple event support
579 ***********************************************************************/
580 int mac_ready_for_apple_events = 0;
581 Lisp_Object Vmac_apple_event_map;
582 Lisp_Object Qmac_apple_event_class, Qmac_apple_event_id;
583 static Lisp_Object Qemacs_suspension_id;
584 extern Lisp_Object Qundefined;
585 extern void mac_store_apple_event P_ ((Lisp_Object, Lisp_Object,
586 const AEDesc *));
587
588 struct apple_event_binding
589 {
590 UInt32 code; /* Apple event class or ID. */
591 Lisp_Object key, binding;
592 };
593
594 struct suspended_ae_info
595 {
596 UInt32 expiration_tick, suspension_id;
597 AppleEvent apple_event, reply;
598 struct suspended_ae_info *next;
599 };
600
601 /* List of apple events deferred at the startup time. */
602 static struct suspended_ae_info *deferred_apple_events = NULL;
603
604 /* List of suspended apple events, in order of expiration_tick. */
605 static struct suspended_ae_info *suspended_apple_events = NULL;
606
607 static void
608 find_event_binding_fun (key, binding, args, data)
609 Lisp_Object key, binding, args;
610 void *data;
611 {
612 struct apple_event_binding *event_binding =
613 (struct apple_event_binding *)data;
614 Lisp_Object code_string;
615
616 if (!SYMBOLP (key))
617 return;
618 code_string = Fget (key, args);
619 if (STRINGP (code_string) && SBYTES (code_string) == 4
620 && (EndianU32_BtoN (*((UInt32 *) SDATA (code_string)))
621 == event_binding->code))
622 {
623 event_binding->key = key;
624 event_binding->binding = binding;
625 }
626 }
627
628 static void
629 find_event_binding (keymap, event_binding, class_p)
630 Lisp_Object keymap;
631 struct apple_event_binding *event_binding;
632 int class_p;
633 {
634 if (event_binding->code == 0)
635 event_binding->binding =
636 access_keymap (keymap, event_binding->key, 0, 1, 0);
637 else
638 {
639 event_binding->binding = Qnil;
640 map_keymap (keymap, find_event_binding_fun,
641 class_p ? Qmac_apple_event_class : Qmac_apple_event_id,
642 event_binding, 0);
643 }
644 }
645
646 void
647 mac_find_apple_event_spec (class, id, class_key, id_key, binding)
648 AEEventClass class;
649 AEEventID id;
650 Lisp_Object *class_key, *id_key, *binding;
651 {
652 struct apple_event_binding event_binding;
653 Lisp_Object keymap;
654
655 *binding = Qnil;
656
657 keymap = get_keymap (Vmac_apple_event_map, 0, 0);
658 if (NILP (keymap))
659 return;
660
661 event_binding.code = class;
662 event_binding.key = *class_key;
663 event_binding.binding = Qnil;
664 find_event_binding (keymap, &event_binding, 1);
665 *class_key = event_binding.key;
666 keymap = get_keymap (event_binding.binding, 0, 0);
667 if (NILP (keymap))
668 return;
669
670 event_binding.code = id;
671 event_binding.key = *id_key;
672 event_binding.binding = Qnil;
673 find_event_binding (keymap, &event_binding, 0);
674 *id_key = event_binding.key;
675 *binding = event_binding.binding;
676 }
677
678 static OSErr
679 defer_apple_events (apple_event, reply)
680 const AppleEvent *apple_event, *reply;
681 {
682 OSErr err;
683 struct suspended_ae_info *new;
684
685 new = xmalloc (sizeof (struct suspended_ae_info));
686 bzero (new, sizeof (struct suspended_ae_info));
687 new->apple_event.descriptorType = typeNull;
688 new->reply.descriptorType = typeNull;
689
690 err = AESuspendTheCurrentEvent (apple_event);
691
692 /* Mac OS 10.3 Xcode manual says AESuspendTheCurrentEvent makes
693 copies of the Apple event and the reply, but Mac OS 10.4 Xcode
694 manual says it doesn't. Anyway we create copies of them and save
695 them in `deferred_apple_events'. */
696 if (err == noErr)
697 err = AEDuplicateDesc (apple_event, &new->apple_event);
698 if (err == noErr)
699 err = AEDuplicateDesc (reply, &new->reply);
700 if (err == noErr)
701 {
702 new->next = deferred_apple_events;
703 deferred_apple_events = new;
704 }
705 else
706 {
707 AEDisposeDesc (&new->apple_event);
708 AEDisposeDesc (&new->reply);
709 xfree (new);
710 }
711
712 return err;
713 }
714
715 static OSErr
716 mac_handle_apple_event_1 (class, id, apple_event, reply)
717 Lisp_Object class, id;
718 const AppleEvent *apple_event;
719 AppleEvent *reply;
720 {
721 OSErr err;
722 static UInt32 suspension_id = 0;
723 struct suspended_ae_info *new;
724
725 new = xmalloc (sizeof (struct suspended_ae_info));
726 bzero (new, sizeof (struct suspended_ae_info));
727 new->apple_event.descriptorType = typeNull;
728 new->reply.descriptorType = typeNull;
729
730 err = AESuspendTheCurrentEvent (apple_event);
731 if (err == noErr)
732 err = AEDuplicateDesc (apple_event, &new->apple_event);
733 if (err == noErr)
734 err = AEDuplicateDesc (reply, &new->reply);
735 if (err == noErr)
736 err = AEPutAttributePtr (&new->apple_event, KEY_EMACS_SUSPENSION_ID_ATTR,
737 typeUInt32, &suspension_id, sizeof (UInt32));
738 if (err == noErr)
739 {
740 OSErr err1;
741 SInt32 reply_requested;
742
743 err1 = AEGetAttributePtr (&new->apple_event, keyReplyRequestedAttr,
744 typeSInt32, NULL, &reply_requested,
745 sizeof (SInt32), NULL);
746 if (err1 != noErr)
747 {
748 /* Emulate keyReplyRequestedAttr in older versions. */
749 reply_requested = reply->descriptorType != typeNull;
750 err = AEPutAttributePtr (&new->apple_event, keyReplyRequestedAttr,
751 typeSInt32, &reply_requested,
752 sizeof (SInt32));
753 }
754 }
755 if (err == noErr)
756 {
757 SInt32 timeout = 0;
758 struct suspended_ae_info **p;
759
760 new->suspension_id = suspension_id;
761 suspension_id++;
762 err = AEGetAttributePtr (apple_event, keyTimeoutAttr, typeSInt32,
763 NULL, &timeout, sizeof (SInt32), NULL);
764 new->expiration_tick = TickCount () + timeout;
765
766 for (p = &suspended_apple_events; *p; p = &(*p)->next)
767 if ((*p)->expiration_tick >= new->expiration_tick)
768 break;
769 new->next = *p;
770 *p = new;
771
772 mac_store_apple_event (class, id, &new->apple_event);
773 }
774 else
775 {
776 AEDisposeDesc (&new->reply);
777 AEDisposeDesc (&new->apple_event);
778 xfree (new);
779 }
780
781 return err;
782 }
783
784 pascal OSErr
785 mac_handle_apple_event (apple_event, reply, refcon)
786 const AppleEvent *apple_event;
787 AppleEvent *reply;
788 SInt32 refcon;
789 {
790 OSErr err;
791 UInt32 suspension_id;
792 AEEventClass event_class;
793 AEEventID event_id;
794 Lisp_Object class_key, id_key, binding;
795
796 if (!mac_ready_for_apple_events)
797 {
798 err = defer_apple_events (apple_event, reply);
799 if (err != noErr)
800 return errAEEventNotHandled;
801 return noErr;
802 }
803
804 err = AEGetAttributePtr (apple_event, KEY_EMACS_SUSPENSION_ID_ATTR,
805 typeUInt32, NULL,
806 &suspension_id, sizeof (UInt32), NULL);
807 if (err == noErr)
808 /* Previously suspended event. Pass it to the next handler. */
809 return errAEEventNotHandled;
810
811 err = AEGetAttributePtr (apple_event, keyEventClassAttr, typeType, NULL,
812 &event_class, sizeof (AEEventClass), NULL);
813 if (err == noErr)
814 err = AEGetAttributePtr (apple_event, keyEventIDAttr, typeType, NULL,
815 &event_id, sizeof (AEEventID), NULL);
816 if (err == noErr)
817 {
818 mac_find_apple_event_spec (event_class, event_id,
819 &class_key, &id_key, &binding);
820 if (!NILP (binding) && !EQ (binding, Qundefined))
821 {
822 if (INTEGERP (binding))
823 return XINT (binding);
824 err = mac_handle_apple_event_1 (class_key, id_key,
825 apple_event, reply);
826 }
827 else
828 err = errAEEventNotHandled;
829 }
830 if (err == noErr)
831 return noErr;
832 else
833 return errAEEventNotHandled;
834 }
835
836 static int
837 cleanup_suspended_apple_events (head, all_p)
838 struct suspended_ae_info **head;
839 int all_p;
840 {
841 UInt32 current_tick = TickCount (), nresumed = 0;
842 struct suspended_ae_info *p, *next;
843
844 for (p = *head; p; p = next)
845 {
846 if (!all_p && p->expiration_tick > current_tick)
847 break;
848 AESetTheCurrentEvent (&p->apple_event);
849 AEResumeTheCurrentEvent (&p->apple_event, &p->reply,
850 (AEEventHandlerUPP) kAENoDispatch, 0);
851 AEDisposeDesc (&p->reply);
852 AEDisposeDesc (&p->apple_event);
853 nresumed++;
854 next = p->next;
855 xfree (p);
856 }
857 *head = p;
858
859 return nresumed;
860 }
861
862 void
863 cleanup_all_suspended_apple_events ()
864 {
865 cleanup_suspended_apple_events (&deferred_apple_events, 1);
866 cleanup_suspended_apple_events (&suspended_apple_events, 1);
867 }
868
869 static UInt32
870 get_suspension_id (apple_event)
871 Lisp_Object apple_event;
872 {
873 Lisp_Object tem;
874
875 CHECK_CONS (apple_event);
876 CHECK_STRING_CAR (apple_event);
877 if (SBYTES (XCAR (apple_event)) != 4
878 || strcmp (SDATA (XCAR (apple_event)), "aevt") != 0)
879 error ("Not an apple event");
880
881 tem = assq_no_quit (Qemacs_suspension_id, XCDR (apple_event));
882 if (NILP (tem))
883 error ("Suspension ID not available");
884
885 tem = XCDR (tem);
886 if (!(CONSP (tem)
887 && STRINGP (XCAR (tem)) && SBYTES (XCAR (tem)) == 4
888 && strcmp (SDATA (XCAR (tem)), "magn") == 0
889 && STRINGP (XCDR (tem)) && SBYTES (XCDR (tem)) == 4))
890 error ("Bad suspension ID format");
891
892 return *((UInt32 *) SDATA (XCDR (tem)));
893 }
894
895
896 DEFUN ("mac-process-deferred-apple-events", Fmac_process_deferred_apple_events, Smac_process_deferred_apple_events, 0, 0, 0,
897 doc: /* Process Apple events that are deferred at the startup time. */)
898 ()
899 {
900 if (mac_ready_for_apple_events)
901 return Qnil;
902
903 BLOCK_INPUT;
904 mac_ready_for_apple_events = 1;
905 if (deferred_apple_events)
906 {
907 struct suspended_ae_info *prev, *tail, *next;
908
909 /* `nreverse' deferred_apple_events. */
910 prev = NULL;
911 for (tail = deferred_apple_events; tail; tail = next)
912 {
913 next = tail->next;
914 tail->next = prev;
915 prev = tail;
916 }
917
918 /* Now `prev' points to the first cell. */
919 for (tail = prev; tail; tail = next)
920 {
921 next = tail->next;
922 AEResumeTheCurrentEvent (&tail->apple_event, &tail->reply,
923 ((AEEventHandlerUPP)
924 kAEUseStandardDispatch), 0);
925 AEDisposeDesc (&tail->reply);
926 AEDisposeDesc (&tail->apple_event);
927 xfree (tail);
928 }
929
930 deferred_apple_events = NULL;
931 }
932 UNBLOCK_INPUT;
933
934 return Qt;
935 }
936
937 DEFUN ("mac-cleanup-expired-apple-events", Fmac_cleanup_expired_apple_events, Smac_cleanup_expired_apple_events, 0, 0, 0,
938 doc: /* Clean up expired Apple events.
939 Return the number of expired events. */)
940 ()
941 {
942 int nexpired;
943
944 BLOCK_INPUT;
945 nexpired = cleanup_suspended_apple_events (&suspended_apple_events, 0);
946 UNBLOCK_INPUT;
947
948 return make_number (nexpired);
949 }
950
951 DEFUN ("mac-ae-set-reply-parameter", Fmac_ae_set_reply_parameter, Smac_ae_set_reply_parameter, 3, 3, 0,
952 doc: /* Set parameter KEYWORD to DESCRIPTOR on reply of APPLE-EVENT.
953 KEYWORD is a 4-byte string. DESCRIPTOR is a Lisp representation of an
954 Apple event descriptor. It has the form of (TYPE . DATA), where TYPE
955 is a 4-byte string. Valid format of DATA is as follows:
956
957 * If TYPE is "null", then DATA is nil.
958 * If TYPE is "list", then DATA is a list (DESCRIPTOR1 ... DESCRIPTORn).
959 * If TYPE is "reco", then DATA is a list ((KEYWORD1 . DESCRIPTOR1)
960 ... (KEYWORDn . DESCRIPTORn)).
961 * If TYPE is "aevt", then DATA is ignored and the descriptor is
962 treated as null.
963 * Otherwise, DATA is a string.
964
965 If a (sub-)descriptor is in an invalid format, it is silently treated
966 as null.
967
968 Return t if the parameter is successfully set. Otherwise return nil. */)
969 (apple_event, keyword, descriptor)
970 Lisp_Object apple_event, keyword, descriptor;
971 {
972 Lisp_Object result = Qnil;
973 UInt32 suspension_id;
974 struct suspended_ae_info *p;
975
976 suspension_id = get_suspension_id (apple_event);
977
978 CHECK_STRING (keyword);
979 if (SBYTES (keyword) != 4)
980 error ("Apple event keyword must be a 4-byte string: %s",
981 SDATA (keyword));
982
983 BLOCK_INPUT;
984 for (p = suspended_apple_events; p; p = p->next)
985 if (p->suspension_id == suspension_id)
986 break;
987 if (p && p->reply.descriptorType != typeNull)
988 {
989 OSErr err;
990
991 err = mac_ae_put_lisp (&p->reply,
992 EndianU32_BtoN (*((UInt32 *) SDATA (keyword))),
993 descriptor);
994 if (err == noErr)
995 result = Qt;
996 }
997 UNBLOCK_INPUT;
998
999 return result;
1000 }
1001
1002 DEFUN ("mac-resume-apple-event", Fmac_resume_apple_event, Smac_resume_apple_event, 1, 2, 0,
1003 doc: /* Resume handling of APPLE-EVENT.
1004 Every Apple event handled by the Lisp interpreter is suspended first.
1005 This function resumes such a suspended event either to complete Apple
1006 event handling to give a reply, or to redispatch it to other handlers.
1007
1008 If optional ERROR-CODE is an integer, it specifies the error number
1009 that is set in the reply. If ERROR-CODE is t, the resumed event is
1010 handled with the standard dispatching mechanism, but it is not handled
1011 by Emacs again, thus it is redispatched to other handlers.
1012
1013 Return t if APPLE-EVENT is successfully resumed. Otherwise return
1014 nil, which means the event is already resumed or expired. */)
1015 (apple_event, error_code)
1016 Lisp_Object apple_event, error_code;
1017 {
1018 Lisp_Object result = Qnil;
1019 UInt32 suspension_id;
1020 struct suspended_ae_info **p, *ae;
1021
1022 suspension_id = get_suspension_id (apple_event);
1023
1024 BLOCK_INPUT;
1025 for (p = &suspended_apple_events; *p; p = &(*p)->next)
1026 if ((*p)->suspension_id == suspension_id)
1027 break;
1028 if (*p)
1029 {
1030 ae = *p;
1031 *p = (*p)->next;
1032 if (INTEGERP (error_code)
1033 && ae->reply.descriptorType != typeNull)
1034 {
1035 SInt32 errn = XINT (error_code);
1036
1037 AEPutParamPtr (&ae->reply, keyErrorNumber, typeSInt32,
1038 &errn, sizeof (SInt32));
1039 }
1040 AESetTheCurrentEvent (&ae->apple_event);
1041 AEResumeTheCurrentEvent (&ae->apple_event, &ae->reply,
1042 ((AEEventHandlerUPP)
1043 (EQ (error_code, Qt) ?
1044 kAEUseStandardDispatch : kAENoDispatch)),
1045 0);
1046 AEDisposeDesc (&ae->reply);
1047 AEDisposeDesc (&ae->apple_event);
1048 xfree (ae);
1049 result = Qt;
1050 }
1051 UNBLOCK_INPUT;
1052
1053 return result;
1054 }
1055
1056 \f
1057 /***********************************************************************
1058 Drag and drop support
1059 ***********************************************************************/
1060 #if TARGET_API_MAC_CARBON
1061 Lisp_Object Vmac_dnd_known_types;
1062 #endif /* TARGET_API_MAC_CARBON */
1063
1064 \f
1065 /***********************************************************************
1066 Services menu support
1067 ***********************************************************************/
1068 #ifdef MAC_OSX
1069 /* Selection name for communication via Services menu. */
1070 Lisp_Object Vmac_service_selection;
1071 #endif
1072
1073 void
1074 syms_of_macselect ()
1075 {
1076 defsubr (&Sx_get_selection_internal);
1077 defsubr (&Sx_own_selection_internal);
1078 defsubr (&Sx_disown_selection_internal);
1079 defsubr (&Sx_selection_owner_p);
1080 defsubr (&Sx_selection_exists_p);
1081 defsubr (&Smac_process_deferred_apple_events);
1082 defsubr (&Smac_cleanup_expired_apple_events);
1083 defsubr (&Smac_resume_apple_event);
1084 defsubr (&Smac_ae_set_reply_parameter);
1085
1086 Vselection_alist = Qnil;
1087 staticpro (&Vselection_alist);
1088
1089 DEFVAR_LISP ("selection-converter-alist", &Vselection_converter_alist,
1090 doc: /* An alist associating selection-types with functions.
1091 These functions are called to convert the selection, with three args:
1092 the name of the selection (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');
1093 a desired type to which the selection should be converted;
1094 and the local selection value (whatever was given to `x-own-selection').
1095
1096 The function should return the value to send to the Scrap Manager
1097 \(must be a string). A return value of nil
1098 means that the conversion could not be done. */);
1099 Vselection_converter_alist = Qnil;
1100
1101 DEFVAR_LISP ("x-lost-selection-functions", &Vx_lost_selection_functions,
1102 doc: /* A list of functions to be called when Emacs loses a selection.
1103 \(This happens when a Lisp program explicitly clears the selection.)
1104 The functions are called with one argument, the selection type
1105 \(a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'). */);
1106 Vx_lost_selection_functions = Qnil;
1107
1108 DEFVAR_LISP ("selection-coding-system", &Vselection_coding_system,
1109 doc: /* Coding system for communicating with other programs.
1110 When sending or receiving text via cut_buffer, selection, and clipboard,
1111 the text is encoded or decoded by this coding system.
1112 The default value is determined by the system script code. */);
1113 Vselection_coding_system = Qnil;
1114
1115 DEFVAR_LISP ("next-selection-coding-system", &Vnext_selection_coding_system,
1116 doc: /* Coding system for the next communication with other programs.
1117 Usually, `selection-coding-system' is used for communicating with
1118 other programs. But, if this variable is set, it is used for the
1119 next communication only. After the communication, this variable is
1120 set to nil. */);
1121 Vnext_selection_coding_system = Qnil;
1122
1123 DEFVAR_LISP ("mac-apple-event-map", &Vmac_apple_event_map,
1124 doc: /* Keymap for Apple events handled by Emacs. */);
1125 Vmac_apple_event_map = Qnil;
1126
1127 #if TARGET_API_MAC_CARBON
1128 DEFVAR_LISP ("mac-dnd-known-types", &Vmac_dnd_known_types,
1129 doc: /* The types accepted by default for dropped data.
1130 The types are chosen in the order they appear in the list. */);
1131 Vmac_dnd_known_types = mac_dnd_default_known_types ();
1132 #endif
1133
1134 #ifdef MAC_OSX
1135 DEFVAR_LISP ("mac-service-selection", &Vmac_service_selection,
1136 doc: /* Selection name for communication via Services menu. */);
1137 Vmac_service_selection = intern ("PRIMARY");
1138 #endif
1139
1140 QPRIMARY = intern ("PRIMARY"); staticpro (&QPRIMARY);
1141 QSECONDARY = intern ("SECONDARY"); staticpro (&QSECONDARY);
1142 QTIMESTAMP = intern ("TIMESTAMP"); staticpro (&QTIMESTAMP);
1143 QTARGETS = intern ("TARGETS"); staticpro (&QTARGETS);
1144
1145 Qforeign_selection = intern ("foreign-selection");
1146 staticpro (&Qforeign_selection);
1147
1148 Qmac_scrap_name = intern ("mac-scrap-name");
1149 staticpro (&Qmac_scrap_name);
1150
1151 Qmac_ostype = intern ("mac-ostype");
1152 staticpro (&Qmac_ostype);
1153
1154 Qmac_apple_event_class = intern ("mac-apple-event-class");
1155 staticpro (&Qmac_apple_event_class);
1156
1157 Qmac_apple_event_id = intern ("mac-apple-event-id");
1158 staticpro (&Qmac_apple_event_id);
1159
1160 Qemacs_suspension_id = intern ("emacs-suspension-id");
1161 staticpro (&Qemacs_suspension_id);
1162 }
1163
1164 /* arch-tag: f3c91ad8-99e0-4bd6-9eef-251b2f848732
1165 (do not change this comment) */