(apropos-function, apropos-macro, apropos-command)
[emacs.git] / src / macselect.c
blobb505698fab05cde663696ace22ad7fbcfd641add
1 /* Selection processing for Emacs on Mac OS.
2 Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
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.
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.
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/>. */
19 #include <config.h>
21 #include "lisp.h"
22 #include "macterm.h"
23 #include "blockinput.h"
24 #include "keymap.h"
26 #if !TARGET_API_MAC_CARBON
27 #include <Endian.h>
28 #endif
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));
36 Lisp_Object QPRIMARY, QSECONDARY, QTIMESTAMP, QTARGETS;
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;
42 /* Coding system for the next communicating with other programs. */
43 static Lisp_Object Vnext_selection_coding_system;
45 static Lisp_Object Qforeign_selection;
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;
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;
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;
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;
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. */
88 static void
89 x_own_selection (selection_name, selection_value)
90 Lisp_Object selection_name, selection_value;
92 OSStatus err;
93 Selection sel;
94 struct gcpro gcpro1, gcpro2;
95 Lisp_Object rest, handler_fn, value, target_type;
96 int count;
98 CHECK_SYMBOL (selection_name);
100 GCPRO2 (selection_name, selection_value);
102 BLOCK_INPUT;
104 err = mac_get_selection_from_symbol (selection_name, 1, &sel);
105 if (err == noErr && sel)
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);
113 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
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;
123 if (!NILP (handler_fn))
124 value = call3 (handler_fn, selection_name,
125 target_type, selection_value);
127 if (NILP (value))
128 continue;
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));
138 unbind_to (count, Qnil);
141 UNBLOCK_INPUT;
143 UNGCPRO;
145 if (sel && err != noErr)
146 error ("Can't set selection");
148 /* Now update the local cache */
150 Lisp_Object selection_time;
151 Lisp_Object selection_data;
152 Lisp_Object ownership_info;
153 Lisp_Object prev_value;
155 selection_time = long_to_cons (last_event_timestamp);
156 if (sel)
158 BLOCK_INPUT;
159 ownership_info = mac_get_selection_ownership_info (sel);
160 UNBLOCK_INPUT;
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);
172 Vselection_alist = Fcons (selection_data, Vselection_alist);
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))
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))))
183 XSETCDR (rest, Fcdr (XCDR (rest)));
184 break;
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).
196 This calls random Lisp code, and may signal or gc. */
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;
203 Lisp_Object local_value;
204 Lisp_Object handler_fn, value, type, check;
205 int count;
207 if (NILP (Fx_selection_owner_p (selection_symbol)))
208 return Qnil;
210 local_value = assq_no_quit (selection_symbol, Vselection_alist);
212 /* TIMESTAMP is a special case 'cause that's easiest. */
213 if (EQ (target_type, QTIMESTAMP))
215 handler_fn = Qnil;
216 value = XCAR (XCDR (XCDR (local_value)));
218 #if 0
219 else if (EQ (target_type, QDELETE))
221 handler_fn = Qnil;
222 Fx_disown_selection_internal
223 (selection_symbol,
224 XCAR (XCDR (XCDR (local_value))));
225 value = QNULL;
227 #endif
228 else
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);
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. */
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);
250 if (local_request)
251 return value;
253 /* Make sure this value is of a type that we could transmit
254 to another application. */
256 type = target_type;
257 check = value;
258 if (CONSP (value)
259 && SYMBOLP (XCAR (value)))
260 type = XCAR (value),
261 check = XCDR (value);
263 if (NILP (value) || mac_valid_selection_value_p (check, type))
264 return value;
266 signal_error ("Invalid data returned by selection-conversion function",
267 list2 (handler_fn, value));
271 /* Clear all selections that were made from frame F.
272 We do this when about to delete a frame. */
274 void
275 x_clear_frame_selections (f)
276 FRAME_PTR f;
278 Lisp_Object frame;
279 Lisp_Object rest;
281 XSETFRAME (frame, f);
283 /* Otherwise, we're really honest and truly being told to drop it.
284 Don't use Fdelq as that may QUIT;. */
286 /* Delete elements from the beginning of Vselection_alist. */
287 while (!NILP (Vselection_alist)
288 && EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (Vselection_alist)))))))
290 /* Let random Lisp code notice that the selection has been stolen. */
291 Lisp_Object hooks, selection_symbol;
293 hooks = Vx_lost_selection_functions;
294 selection_symbol = Fcar (Fcar (Vselection_alist));
296 if (!EQ (hooks, Qunbound)
297 && !NILP (Fx_selection_owner_p (selection_symbol)))
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
308 Vselection_alist = Fcdr (Vselection_alist);
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))))))))
315 /* Let random Lisp code notice that the selection has been stolen. */
316 Lisp_Object hooks, selection_symbol;
318 hooks = Vx_lost_selection_functions;
319 selection_symbol = Fcar (Fcar (XCDR (rest)));
321 if (!EQ (hooks, Qunbound)
322 && !NILP (Fx_selection_owner_p (selection_symbol)))
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
330 XSETCDR (rest, Fcdr (XCDR (rest)));
331 break;
335 /* Do protocol to read selection-data from the server.
336 Converts this to Lisp data and returns it. */
338 static Lisp_Object
339 x_get_foreign_selection (selection_symbol, target_type, time_stamp)
340 Lisp_Object selection_symbol, target_type, time_stamp;
342 OSStatus err;
343 Selection sel;
344 Lisp_Object result = Qnil;
346 BLOCK_INPUT;
348 err = mac_get_selection_from_symbol (selection_symbol, 0, &sel);
349 if (err == noErr && sel)
351 if (EQ (target_type, QTARGETS))
353 result = mac_get_selection_target_list (sel);
354 result = Fvconcat (1, &result);
356 else
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);
365 UNBLOCK_INPUT;
367 return result;
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;
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;
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. */
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;
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);
408 val = x_get_local_selection (selection_symbol, target_type, 1);
410 if (NILP (val))
412 val = x_get_foreign_selection (selection_symbol, target_type, time_stamp);
413 goto DONE;
416 if (CONSP (val)
417 && SYMBOLP (XCAR (val)))
419 val = XCDR (val);
420 if (CONSP (val) && NILP (XCDR (val)))
421 val = XCAR (val);
423 DONE:
424 UNGCPRO;
425 return val;
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;
436 OSStatus err;
437 Selection sel;
438 Lisp_Object local_selection_data;
440 check_mac ();
441 CHECK_SYMBOL (selection);
443 if (NILP (Fx_selection_owner_p (selection)))
444 return Qnil; /* Don't disown the selection when we're not the owner. */
446 local_selection_data = assq_no_quit (selection, Vselection_alist);
448 /* Don't use Fdelq as that may QUIT;. */
450 if (EQ (local_selection_data, Fcar (Vselection_alist)))
451 Vselection_alist = Fcdr (Vselection_alist);
452 else
454 Lisp_Object rest;
455 for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest))
456 if (EQ (local_selection_data, Fcar (XCDR (rest))))
458 XSETCDR (rest, Fcdr (XCDR (rest)));
459 break;
463 /* Let random lisp code notice that the selection has been stolen. */
466 Lisp_Object rest;
467 rest = Vx_lost_selection_functions;
468 if (!EQ (rest, Qunbound))
470 for (; CONSP (rest); rest = Fcdr (rest))
471 call1 (Fcar (rest), selection);
472 prepare_menu_bars ();
473 redisplay_preserve_echo_area (20);
477 BLOCK_INPUT;
479 err = mac_get_selection_from_symbol (selection, 0, &sel);
480 if (err == noErr && sel)
481 mac_clear_selection (&sel);
483 UNBLOCK_INPUT;
485 return Qt;
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;
499 OSStatus err;
500 Selection sel;
501 Lisp_Object result = Qnil, local_selection_data;
503 check_mac ();
504 CHECK_SYMBOL (selection);
505 if (EQ (selection, Qnil)) selection = QPRIMARY;
506 if (EQ (selection, Qt)) selection = QSECONDARY;
508 local_selection_data = assq_no_quit (selection, Vselection_alist);
510 if (NILP (local_selection_data))
511 return Qnil;
513 BLOCK_INPUT;
515 err = mac_get_selection_from_symbol (selection, 0, &sel);
516 if (err == noErr && sel)
518 Lisp_Object ownership_info;
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;
525 else
526 result = Qt;
528 UNBLOCK_INPUT;
530 return result;
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;
543 OSStatus err;
544 Selection sel;
545 Lisp_Object result = Qnil, rest;
547 /* It should be safe to call this before we have an Mac frame. */
548 if (! FRAME_MAC_P (SELECTED_FRAME ()))
549 return Qnil;
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;
557 BLOCK_INPUT;
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))
563 if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
564 && mac_selection_has_target_p (sel, XCAR (XCAR (rest))))
566 result = Qt;
567 break;
571 UNBLOCK_INPUT;
573 return result;
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 *));
588 struct apple_event_binding
590 UInt32 code; /* Apple event class or ID. */
591 Lisp_Object key, binding;
594 struct suspended_ae_info
596 UInt32 expiration_tick, suspension_id;
597 AppleEvent apple_event, reply;
598 struct suspended_ae_info *next;
601 /* List of apple events deferred at the startup time. */
602 static struct suspended_ae_info *deferred_apple_events = NULL;
604 /* List of suspended apple events, in order of expiration_tick. */
605 static struct suspended_ae_info *suspended_apple_events = NULL;
607 static void
608 find_event_binding_fun (key, binding, args, data)
609 Lisp_Object key, binding, args;
610 void *data;
612 struct apple_event_binding *event_binding =
613 (struct apple_event_binding *)data;
614 Lisp_Object code_string;
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))
623 event_binding->key = key;
624 event_binding->binding = binding;
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;
634 if (event_binding->code == 0)
635 event_binding->binding =
636 access_keymap (keymap, event_binding->key, 0, 1, 0);
637 else
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);
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;
652 struct apple_event_binding event_binding;
653 Lisp_Object keymap;
655 *binding = Qnil;
657 keymap = get_keymap (Vmac_apple_event_map, 0, 0);
658 if (NILP (keymap))
659 return;
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;
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;
678 static OSErr
679 defer_apple_events (apple_event, reply)
680 const AppleEvent *apple_event, *reply;
682 OSErr err;
683 struct suspended_ae_info *new;
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;
690 err = AESuspendTheCurrentEvent (apple_event);
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)
702 new->next = deferred_apple_events;
703 deferred_apple_events = new;
705 else
707 AEDisposeDesc (&new->apple_event);
708 AEDisposeDesc (&new->reply);
709 xfree (new);
712 return err;
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;
721 OSErr err;
722 static UInt32 suspension_id = 0;
723 struct suspended_ae_info *new;
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;
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)
740 OSErr err1;
741 SInt32 reply_requested;
743 err1 = AEGetAttributePtr (&new->apple_event, keyReplyRequestedAttr,
744 typeSInt32, NULL, &reply_requested,
745 sizeof (SInt32), NULL);
746 if (err1 != noErr)
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));
755 if (err == noErr)
757 SInt32 timeout = 0;
758 struct suspended_ae_info **p;
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;
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;
772 mac_store_apple_event (class, id, &new->apple_event);
774 else
776 AEDisposeDesc (&new->reply);
777 AEDisposeDesc (&new->apple_event);
778 xfree (new);
781 return err;
784 pascal OSErr
785 mac_handle_apple_event (apple_event, reply, refcon)
786 const AppleEvent *apple_event;
787 AppleEvent *reply;
788 SInt32 refcon;
790 OSErr err;
791 UInt32 suspension_id;
792 AEEventClass event_class;
793 AEEventID event_id;
794 Lisp_Object class_key, id_key, binding;
796 if (!mac_ready_for_apple_events)
798 err = defer_apple_events (apple_event, reply);
799 if (err != noErr)
800 return errAEEventNotHandled;
801 return noErr;
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;
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)
818 mac_find_apple_event_spec (event_class, event_id,
819 &class_key, &id_key, &binding);
820 if (!NILP (binding) && !EQ (binding, Qundefined))
822 if (INTEGERP (binding))
823 return XINT (binding);
824 err = mac_handle_apple_event_1 (class_key, id_key,
825 apple_event, reply);
827 else
828 err = errAEEventNotHandled;
830 if (err == noErr)
831 return noErr;
832 else
833 return errAEEventNotHandled;
836 static int
837 cleanup_suspended_apple_events (head, all_p)
838 struct suspended_ae_info **head;
839 int all_p;
841 UInt32 current_tick = TickCount (), nresumed = 0;
842 struct suspended_ae_info *p, *next;
844 for (p = *head; p; p = next)
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);
857 *head = p;
859 return nresumed;
862 void
863 cleanup_all_suspended_apple_events ()
865 cleanup_suspended_apple_events (&deferred_apple_events, 1);
866 cleanup_suspended_apple_events (&suspended_apple_events, 1);
869 static UInt32
870 get_suspension_id (apple_event)
871 Lisp_Object apple_event;
873 Lisp_Object tem;
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");
881 tem = assq_no_quit (Qemacs_suspension_id, XCDR (apple_event));
882 if (NILP (tem))
883 error ("Suspension ID not available");
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");
892 return *((UInt32 *) SDATA (XCDR (tem)));
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. */)
900 if (mac_ready_for_apple_events)
901 return Qnil;
903 BLOCK_INPUT;
904 mac_ready_for_apple_events = 1;
905 if (deferred_apple_events)
907 struct suspended_ae_info *prev, *tail, *next;
909 /* `nreverse' deferred_apple_events. */
910 prev = NULL;
911 for (tail = deferred_apple_events; tail; tail = next)
913 next = tail->next;
914 tail->next = prev;
915 prev = tail;
918 /* Now `prev' points to the first cell. */
919 for (tail = prev; tail; tail = next)
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);
930 deferred_apple_events = NULL;
932 UNBLOCK_INPUT;
934 return Qt;
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. */)
942 int nexpired;
944 BLOCK_INPUT;
945 nexpired = cleanup_suspended_apple_events (&suspended_apple_events, 0);
946 UNBLOCK_INPUT;
948 return make_number (nexpired);
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:
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.
965 If a (sub-)descriptor is in an invalid format, it is silently treated
966 as null.
968 Return t if the parameter is successfully set. Otherwise return nil. */)
969 (apple_event, keyword, descriptor)
970 Lisp_Object apple_event, keyword, descriptor;
972 Lisp_Object result = Qnil;
973 UInt32 suspension_id;
974 struct suspended_ae_info *p;
976 suspension_id = get_suspension_id (apple_event);
978 CHECK_STRING (keyword);
979 if (SBYTES (keyword) != 4)
980 error ("Apple event keyword must be a 4-byte string: %s",
981 SDATA (keyword));
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)
989 OSErr err;
991 err = mac_ae_put_lisp (&p->reply,
992 EndianU32_BtoN (*((UInt32 *) SDATA (keyword))),
993 descriptor);
994 if (err == noErr)
995 result = Qt;
997 UNBLOCK_INPUT;
999 return result;
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.
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.
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;
1018 Lisp_Object result = Qnil;
1019 UInt32 suspension_id;
1020 struct suspended_ae_info **p, *ae;
1022 suspension_id = get_suspension_id (apple_event);
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)
1030 ae = *p;
1031 *p = (*p)->next;
1032 if (INTEGERP (error_code)
1033 && ae->reply.descriptorType != typeNull)
1035 SInt32 errn = XINT (error_code);
1037 AEPutParamPtr (&ae->reply, keyErrorNumber, typeSInt32,
1038 &errn, sizeof (SInt32));
1040 AESetTheCurrentEvent (&ae->apple_event);
1041 AEResumeTheCurrentEvent (&ae->apple_event, &ae->reply,
1042 ((AEEventHandlerUPP)
1043 (EQ (error_code, Qt) ?
1044 kAEUseStandardDispatch : kAENoDispatch)),
1046 AEDisposeDesc (&ae->reply);
1047 AEDisposeDesc (&ae->apple_event);
1048 xfree (ae);
1049 result = Qt;
1051 UNBLOCK_INPUT;
1053 return result;
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 */
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
1073 void
1074 syms_of_macselect ()
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);
1086 Vselection_alist = Qnil;
1087 staticpro (&Vselection_alist);
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').
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;
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;
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;
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;
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;
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
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
1140 QPRIMARY = intern ("PRIMARY"); staticpro (&QPRIMARY);
1141 QSECONDARY = intern ("SECONDARY"); staticpro (&QSECONDARY);
1142 QTIMESTAMP = intern ("TIMESTAMP"); staticpro (&QTIMESTAMP);
1143 QTARGETS = intern ("TARGETS"); staticpro (&QTARGETS);
1145 Qforeign_selection = intern ("foreign-selection");
1146 staticpro (&Qforeign_selection);
1148 Qmac_scrap_name = intern ("mac-scrap-name");
1149 staticpro (&Qmac_scrap_name);
1151 Qmac_ostype = intern ("mac-ostype");
1152 staticpro (&Qmac_ostype);
1154 Qmac_apple_event_class = intern ("mac-apple-event-class");
1155 staticpro (&Qmac_apple_event_class);
1157 Qmac_apple_event_id = intern ("mac-apple-event-id");
1158 staticpro (&Qmac_apple_event_id);
1160 Qemacs_suspension_id = intern ("emacs-suspension-id");
1161 staticpro (&Qemacs_suspension_id);
1164 /* arch-tag: f3c91ad8-99e0-4bd6-9eef-251b2f848732
1165 (do not change this comment) */