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