(font_find_for_lface): If registry is NULL, try iso8859-1 and ascii-0.
[bpt/emacs.git] / src / macselect.c
CommitLineData
944cda79 1/* Selection processing for Emacs on Mac OS.
8cabe764 2 Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
944cda79
YM
3
4This file is part of GNU Emacs.
5
9ec0b715 6GNU Emacs is free software: you can redistribute it and/or modify
944cda79 7it under the terms of the GNU General Public License as published by
9ec0b715
GM
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
944cda79
YM
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
9ec0b715 17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
944cda79
YM
18
19#include <config.h>
20
21#include "lisp.h"
22#include "macterm.h"
23#include "blockinput.h"
28714a27 24#include "keymap.h"
944cda79 25
5d6c5138 26#if !TARGET_API_MAC_CARBON
944cda79 27#include <Endian.h>
5d6c5138
YM
28#endif
29
944cda79
YM
30static void x_own_selection P_ ((Lisp_Object, Lisp_Object));
31static Lisp_Object x_get_local_selection P_ ((Lisp_Object, Lisp_Object, int));
32static Lisp_Object x_get_foreign_selection P_ ((Lisp_Object,
33 Lisp_Object,
34 Lisp_Object));
944cda79
YM
35
36Lisp_Object QPRIMARY, QSECONDARY, QTIMESTAMP, QTARGETS;
37
38static Lisp_Object Vx_lost_selection_functions;
a5b11587 39/* Coding system for communicating with other programs via selections. */
944cda79
YM
40static Lisp_Object Vselection_coding_system;
41
42/* Coding system for the next communicating with other programs. */
43static Lisp_Object Vnext_selection_coding_system;
44
45static 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. */
50extern unsigned long last_event_timestamp;
51
52/* This is an association list whose elements are of the form
a5b11587 53 ( SELECTION-NAME SELECTION-VALUE SELECTION-TIMESTAMP FRAME OWNERSHIP-INFO)
944cda79
YM
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.
a5b11587
YM
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.
944cda79
YM
67 The only (eq) parts of this list that are visible from Lisp are the
68 selection-values. */
69static Lisp_Object Vselection_alist;
70
944cda79
YM
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. */
5d6c5138 76Lisp_Object Vselection_converter_alist;
944cda79
YM
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'. */
5d6c5138 81Lisp_Object Qmac_scrap_name, Qmac_ostype;
944cda79 82
944cda79
YM
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
88static void
89x_own_selection (selection_name, selection_value)
90 Lisp_Object selection_name, selection_value;
91{
31f93085 92 OSStatus err;
a5b11587 93 Selection sel;
944cda79 94 struct gcpro gcpro1, gcpro2;
a5b11587 95 Lisp_Object rest, handler_fn, value, target_type;
944cda79
YM
96 int count;
97
98 CHECK_SYMBOL (selection_name);
99
100 GCPRO2 (selection_name, selection_value);
101
102 BLOCK_INPUT;
103
a5b11587
YM
104 err = mac_get_selection_from_symbol (selection_name, 1, &sel);
105 if (err == noErr && sel)
944cda79
YM
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))
a5b11587
YM
116 && (target_type = XCAR (XCAR (rest)),
117 SYMBOLP (target_type))
118 && mac_valid_selection_target_p (target_type)
d18bee72
YM
119 && (handler_fn = XCDR (XCAR (rest)),
120 SYMBOLP (handler_fn))))
944cda79
YM
121 continue;
122
123 if (!NILP (handler_fn))
124 value = call3 (handler_fn, selection_name,
a5b11587
YM
125 target_type, selection_value);
126
127 if (NILP (value))
128 continue;
944cda79 129
a5b11587
YM
130 if (mac_valid_selection_value_p (value, target_type))
131 err = mac_put_selection_value (sel, target_type, value);
956c0f10 132 else if (CONSP (value)
a5b11587
YM
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));
944cda79
YM
136 }
137
138 unbind_to (count, Qnil);
944cda79
YM
139 }
140
141 UNBLOCK_INPUT;
142
143 UNGCPRO;
144
a5b11587 145 if (sel && err != noErr)
944cda79
YM
146 error ("Can't set selection");
147
148 /* Now update the local cache */
149 {
150 Lisp_Object selection_time;
151 Lisp_Object selection_data;
a5b11587 152 Lisp_Object ownership_info;
944cda79
YM
153 Lisp_Object prev_value;
154
155 selection_time = long_to_cons (last_event_timestamp);
a5b11587 156 if (sel)
c04e33a6
YM
157 {
158 BLOCK_INPUT;
159 ownership_info = mac_get_selection_ownership_info (sel);
160 UNBLOCK_INPUT;
161 }
a5b11587
YM
162 else
163 ownership_info = Qnil; /* dummy value for local-only selection */
944cda79
YM
164 selection_data = Fcons (selection_name,
165 Fcons (selection_value,
166 Fcons (selection_time,
a5b11587
YM
167 Fcons (selected_frame,
168 Fcons (ownership_info,
169 Qnil)))));
944cda79
YM
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. */
99784d63 180 for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest))
944cda79
YM
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
198static Lisp_Object
199x_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
a5b11587
YM
250 if (local_request)
251 return value;
252
944cda79 253 /* Make sure this value is of a type that we could transmit
a5b11587 254 to another application. */
944cda79 255
a5b11587 256 type = target_type;
944cda79
YM
257 check = value;
258 if (CONSP (value)
259 && SYMBOLP (XCAR (value)))
260 type = XCAR (value),
261 check = XCDR (value);
262
a5b11587 263 if (NILP (value) || mac_valid_selection_value_p (check, type))
944cda79 264 return value;
4ae7943d
KS
265
266 signal_error ("Invalid data returned by selection-conversion function",
267 list2 (handler_fn, value));
944cda79
YM
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
274void
275x_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
956c0f10
YM
296 if (!EQ (hooks, Qunbound)
297 && !NILP (Fx_selection_owner_p (selection_symbol)))
944cda79
YM
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. */
99784d63 312 for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest))
944cda79
YM
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
956c0f10
YM
321 if (!EQ (hooks, Qunbound)
322 && !NILP (Fx_selection_owner_p (selection_symbol)))
944cda79
YM
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
338static Lisp_Object
339x_get_foreign_selection (selection_symbol, target_type, time_stamp)
340 Lisp_Object selection_symbol, target_type, time_stamp;
341{
31f93085 342 OSStatus err;
a5b11587 343 Selection sel;
944cda79
YM
344 Lisp_Object result = Qnil;
345
346 BLOCK_INPUT;
347
a5b11587
YM
348 err = mac_get_selection_from_symbol (selection_symbol, 0, &sel);
349 if (err == noErr && sel)
961bf590
YM
350 {
351 if (EQ (target_type, QTARGETS))
352 {
a5b11587 353 result = mac_get_selection_target_list (sel);
961bf590
YM
354 result = Fvconcat (1, &result);
355 }
356 else
357 {
a5b11587 358 result = mac_get_selection_value (sel, target_type);
961bf590
YM
359 if (STRINGP (result))
360 Fput_text_property (make_number (0), make_number (SBYTES (result)),
361 Qforeign_selection, target_type, result);
362 }
363 }
944cda79
YM
364
365 UNBLOCK_INPUT;
366
367 return result;
368}
369
370
371DEFUN ("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.
374TYPE is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
375VALUE is typically a string, or a cons of two markers, but may be
376anything 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);
99f963e4 382 if (NILP (selection_value)) error ("SELECTION-VALUE may not be nil");
944cda79
YM
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
392DEFUN ("x-get-selection-internal", Fx_get_selection_internal,
393 Sx_get_selection_internal, 2, 3, 0,
99f963e4 394 doc: /* Return text selected from some Mac application.
944cda79
YM
395SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
396TYPE is the type of data desired, typically `STRING'.
397TIME_STAMP is ignored on Mac. */)
99f963e4 398 (selection_symbol, target_type, time_stamp)
944cda79
YM
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
428DEFUN ("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.
431Disowning it means there is no such selection. */)
432 (selection, time)
433 Lisp_Object selection;
434 Lisp_Object time;
435{
31f93085 436 OSStatus err;
a5b11587 437 Selection sel;
944cda79
YM
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;
99784d63 455 for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest))
944cda79
YM
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
a5b11587
YM
479 err = mac_get_selection_from_symbol (selection, 0, &sel);
480 if (err == noErr && sel)
481 mac_clear_selection (&sel);
944cda79
YM
482
483 UNBLOCK_INPUT;
484
485 return Qt;
486}
487
488
489DEFUN ("x-selection-owner-p", Fx_selection_owner_p, Sx_selection_owner_p,
490 0, 1, 0,
99f963e4 491 doc: /* Whether the current Emacs process owns the given SELECTION.
944cda79
YM
492The arg should be the name of the selection in question, typically one of
493the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
494For convenience, the symbol nil is the same as `PRIMARY',
495and t is the same as `SECONDARY'. */)
496 (selection)
497 Lisp_Object selection;
498{
31f93085 499 OSStatus err;
a5b11587 500 Selection sel;
944cda79
YM
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
a5b11587
YM
515 err = mac_get_selection_from_symbol (selection, 0, &sel);
516 if (err == noErr && sel)
944cda79 517 {
a5b11587 518 Lisp_Object ownership_info;
944cda79 519
a5b11587
YM
520 ownership_info = XCAR (XCDR (XCDR (XCDR (XCDR (local_selection_data)))));
521 if (!NILP (Fequal (ownership_info,
522 mac_get_selection_ownership_info (sel))))
944cda79
YM
523 result = Qt;
524 }
525 else
526 result = Qt;
527
528 UNBLOCK_INPUT;
529
530 return result;
531}
532
533DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
534 0, 1, 0,
99f963e4 535 doc: /* Whether there is an owner for the given SELECTION.
944cda79
YM
536The arg should be the name of the selection in question, typically one of
537the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
538For convenience, the symbol nil is the same as `PRIMARY',
539and t is the same as `SECONDARY'. */)
540 (selection)
541 Lisp_Object selection;
542{
31f93085 543 OSStatus err;
a5b11587 544 Selection sel;
944cda79
YM
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
a5b11587
YM
559 err = mac_get_selection_from_symbol (selection, 0, &sel);
560 if (err == noErr && sel)
944cda79
YM
561 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
562 {
563 if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
a5b11587 564 && mac_selection_has_target_p (sel, XCAR (XCAR (rest))))
944cda79
YM
565 {
566 result = Qt;
567 break;
568 }
569 }
570
571 UNBLOCK_INPUT;
572
573 return result;
574}
575
576\f
0ffd2c76
YM
577/***********************************************************************
578 Apple event support
579***********************************************************************/
28714a27 580int mac_ready_for_apple_events = 0;
5d6c5138
YM
581Lisp_Object Vmac_apple_event_map;
582Lisp_Object Qmac_apple_event_class, Qmac_apple_event_id;
0ffd2c76 583static Lisp_Object Qemacs_suspension_id;
28714a27 584extern Lisp_Object Qundefined;
044f1b64
YM
585extern void mac_store_apple_event P_ ((Lisp_Object, Lisp_Object,
586 const AEDesc *));
28714a27
YM
587
588struct apple_event_binding
589{
590 UInt32 code; /* Apple event class or ID. */
591 Lisp_Object key, binding;
592};
593
0ffd2c76
YM
594struct suspended_ae_info
595{
596 UInt32 expiration_tick, suspension_id;
597 AppleEvent apple_event, reply;
598 struct suspended_ae_info *next;
599};
600
31f93085 601/* List of apple events deferred at the startup time. */
0ffd2c76
YM
602static struct suspended_ae_info *deferred_apple_events = NULL;
603
604/* List of suspended apple events, in order of expiration_tick. */
605static struct suspended_ae_info *suspended_apple_events = NULL;
606
28714a27
YM
607static void
608find_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
628static void
629find_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
646void
647mac_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
678static OSErr
679defer_apple_events (apple_event, reply)
680 const AppleEvent *apple_event, *reply;
681{
682 OSErr err;
0ffd2c76
YM
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;
28714a27
YM
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
961bf590 695 them in `deferred_apple_events'. */
0ffd2c76
YM
696 if (err == noErr)
697 err = AEDuplicateDesc (apple_event, &new->apple_event);
698 if (err == noErr)
699 err = AEDuplicateDesc (reply, &new->reply);
28714a27
YM
700 if (err == noErr)
701 {
0ffd2c76
YM
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
715static OSErr
716mac_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)
28714a27 747 {
0ffd2c76
YM
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));
28714a27
YM
753 }
754 }
28714a27
YM
755 if (err == noErr)
756 {
0ffd2c76
YM
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;
28714a27 771
0ffd2c76
YM
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);
28714a27
YM
779 }
780
781 return err;
782}
783
5d6c5138 784pascal OSErr
28714a27
YM
785mac_handle_apple_event (apple_event, reply, refcon)
786 const AppleEvent *apple_event;
787 AppleEvent *reply;
788 SInt32 refcon;
789{
790 OSErr err;
0ffd2c76 791 UInt32 suspension_id;
28714a27
YM
792 AEEventClass event_class;
793 AEEventID event_id;
794 Lisp_Object class_key, id_key, binding;
795
28714a27
YM
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
0ffd2c76
YM
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
28714a27
YM
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);
0ffd2c76
YM
824 err = mac_handle_apple_event_1 (class_key, id_key,
825 apple_event, reply);
28714a27 826 }
412f3f18
YM
827 else
828 err = errAEEventNotHandled;
28714a27 829 }
0ffd2c76
YM
830 if (err == noErr)
831 return noErr;
832 else
833 return errAEEventNotHandled;
834}
835
836static int
837cleanup_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
5d6c5138 862void
0ffd2c76
YM
863cleanup_all_suspended_apple_events ()
864{
865 cleanup_suspended_apple_events (&deferred_apple_events, 1);
866 cleanup_suspended_apple_events (&suspended_apple_events, 1);
28714a27
YM
867}
868
0ffd2c76
YM
869static UInt32
870get_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
28714a27
YM
896DEFUN ("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{
28714a27
YM
900 if (mac_ready_for_apple_events)
901 return Qnil;
902
903 BLOCK_INPUT;
904 mac_ready_for_apple_events = 1;
0ffd2c76 905 if (deferred_apple_events)
28714a27 906 {
0ffd2c76
YM
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)
28714a27 912 {
0ffd2c76
YM
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,
28714a27
YM
923 ((AEEventHandlerUPP)
924 kAEUseStandardDispatch), 0);
0ffd2c76
YM
925 AEDisposeDesc (&tail->reply);
926 AEDisposeDesc (&tail->apple_event);
927 xfree (tail);
28714a27 928 }
28714a27 929
0ffd2c76
YM
930 deferred_apple_events = NULL;
931 }
932 UNBLOCK_INPUT;
933
934 return Qt;
935}
936
937DEFUN ("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.
939Return 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
951DEFUN ("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.
953KEYWORD is a 4-byte string. DESCRIPTOR is a Lisp representation of an
954Apple event descriptor. It has the form of (TYPE . DATA), where TYPE
955is 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
965If a (sub-)descriptor is in an invalid format, it is silently treated
966as null.
967
968Return 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
1002DEFUN ("mac-resume-apple-event", Fmac_resume_apple_event, Smac_resume_apple_event, 1, 2, 0,
1003 doc: /* Resume handling of APPLE-EVENT.
1004Every Apple event handled by the Lisp interpreter is suspended first.
1005This function resumes such a suspended event either to complete Apple
1006event handling to give a reply, or to redispatch it to other handlers.
1007
1008If optional ERROR-CODE is an integer, it specifies the error number
1009that is set in the reply. If ERROR-CODE is t, the resumed event is
1010handled with the standard dispatching mechanism, but it is not handled
1011by Emacs again, thus it is redispatched to other handlers.
1012
1013Return t if APPLE-EVENT is successfully resumed. Otherwise return
1014nil, 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)
bd619af5 1033 && ae->reply.descriptorType != typeNull)
0ffd2c76
YM
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);
28714a27
YM
1049 result = Qt;
1050 }
1051 UNBLOCK_INPUT;
1052
1053 return result;
1054}
1055
1056\f
0ffd2c76
YM
1057/***********************************************************************
1058 Drag and drop support
1059***********************************************************************/
044f1b64 1060#if TARGET_API_MAC_CARBON
5d6c5138 1061Lisp_Object Vmac_dnd_known_types;
044f1b64
YM
1062#endif /* TARGET_API_MAC_CARBON */
1063
044f1b64 1064\f
0ffd2c76
YM
1065/***********************************************************************
1066 Services menu support
1067***********************************************************************/
944cda79 1068#ifdef MAC_OSX
5d6c5138
YM
1069/* Selection name for communication via Services menu. */
1070Lisp_Object Vmac_service_selection;
944cda79
YM
1071#endif
1072
944cda79
YM
1073void
1074syms_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);
28714a27 1081 defsubr (&Smac_process_deferred_apple_events);
0ffd2c76
YM
1082 defsubr (&Smac_cleanup_expired_apple_events);
1083 defsubr (&Smac_resume_apple_event);
1084 defsubr (&Smac_ae_set_reply_parameter);
944cda79
YM
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.
1091These functions are called to convert the selection, with three args:
1092the name of the selection (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');
1093a desired type to which the selection should be converted;
1094and the local selection value (whatever was given to `x-own-selection').
1095
1096The function should return the value to send to the Scrap Manager
99f963e4 1097\(must be a string). A return value of nil
d18bee72 1098means that the conversion could not be done. */);
944cda79
YM
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.)
1104The 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.
1110When sending or receiving text via cut_buffer, selection, and clipboard,
1111the text is encoded or decoded by this coding system.
1112The 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.
1117Usually, `selection-coding-system' is used for communicating with
1118other programs. But, if this variable is set, it is used for the
1119next communication only. After the communication, this variable is
1120set to nil. */);
1121 Vnext_selection_coding_system = Qnil;
1122
28714a27
YM
1123 DEFVAR_LISP ("mac-apple-event-map", &Vmac_apple_event_map,
1124 doc: /* Keymap for Apple events handled by Emacs. */);
4d4983fd 1125 Vmac_apple_event_map = Qnil;
28714a27 1126
044f1b64
YM
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.
1130The types are chosen in the order they appear in the list. */);
5d6c5138 1131 Vmac_dnd_known_types = mac_dnd_default_known_types ();
044f1b64
YM
1132#endif
1133
3f2bf04a 1134#ifdef MAC_OSX
c2e93c82 1135 DEFVAR_LISP ("mac-service-selection", &Vmac_service_selection,
944cda79 1136 doc: /* Selection name for communication via Services menu. */);
c2e93c82 1137 Vmac_service_selection = intern ("PRIMARY");
3f2bf04a 1138#endif
944cda79
YM
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);
28714a27
YM
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);
0ffd2c76
YM
1159
1160 Qemacs_suspension_id = intern ("emacs-suspension-id");
1161 staticpro (&Qemacs_suspension_id);
944cda79 1162}
0ed4adfc
MB
1163
1164/* arch-tag: f3c91ad8-99e0-4bd6-9eef-251b2f848732
1165 (do not change this comment) */