]> code.delx.au - gnu-emacs/blob - src/macselect.c
Merge from emacs--devo--0
[gnu-emacs] / src / macselect.c
1 /* Selection processing for Emacs on Mac OS.
2 Copyright (C) 2005, 2006 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; 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. */
20
21 #include <config.h>
22
23 #include "lisp.h"
24 #include "macterm.h"
25 #include "blockinput.h"
26 #include "keymap.h"
27
28 #if !TARGET_API_MAC_CARBON
29 #include <Endian.h>
30 typedef int ScrapRef;
31 typedef ResType ScrapFlavorType;
32 #endif /* !TARGET_API_MAC_CARBON */
33
34 static OSErr get_scrap_from_symbol P_ ((Lisp_Object, int, ScrapRef *));
35 static ScrapFlavorType get_flavor_type_from_symbol P_ ((Lisp_Object));
36 static int valid_scrap_target_type_p P_ ((Lisp_Object));
37 static OSErr clear_scrap P_ ((ScrapRef *));
38 static OSErr put_scrap_string P_ ((ScrapRef, Lisp_Object, Lisp_Object));
39 static OSErr put_scrap_private_timestamp P_ ((ScrapRef, unsigned long));
40 static ScrapFlavorType scrap_has_target_type P_ ((ScrapRef, Lisp_Object));
41 static Lisp_Object get_scrap_string P_ ((ScrapRef, Lisp_Object));
42 static OSErr get_scrap_private_timestamp P_ ((ScrapRef, unsigned long *));
43 static Lisp_Object get_scrap_target_type_list P_ ((ScrapRef));
44 static void x_own_selection P_ ((Lisp_Object, Lisp_Object));
45 static Lisp_Object x_get_local_selection P_ ((Lisp_Object, Lisp_Object, int));
46 static Lisp_Object x_get_foreign_selection P_ ((Lisp_Object,
47 Lisp_Object,
48 Lisp_Object));
49 EXFUN (Fx_selection_owner_p, 1);
50 #ifdef MAC_OSX
51 static OSStatus mac_handle_service_event P_ ((EventHandlerCallRef,
52 EventRef, void *));
53 void init_service_handler P_ ((void));
54 #endif
55
56 Lisp_Object QPRIMARY, QSECONDARY, QTIMESTAMP, QTARGETS;
57
58 static Lisp_Object Vx_lost_selection_functions;
59 /* Coding system for communicating with other programs via scrap. */
60 static Lisp_Object Vselection_coding_system;
61
62 /* Coding system for the next communicating with other programs. */
63 static Lisp_Object Vnext_selection_coding_system;
64
65 static Lisp_Object Qforeign_selection;
66
67 /* The timestamp of the last input event Emacs received from the
68 window server. */
69 /* Defined in keyboard.c. */
70 extern unsigned long last_event_timestamp;
71
72 /* This is an association list whose elements are of the form
73 ( SELECTION-NAME SELECTION-VALUE SELECTION-TIMESTAMP FRAME)
74 SELECTION-NAME is a lisp symbol.
75 SELECTION-VALUE is the value that emacs owns for that selection.
76 It may be any kind of Lisp object.
77 SELECTION-TIMESTAMP is the time at which emacs began owning this selection,
78 as a cons of two 16-bit numbers (making a 32 bit time.)
79 FRAME is the frame for which we made the selection.
80 If there is an entry in this alist, and the data for the flavor
81 type SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP in the corresponding scrap
82 (if exists) coincides with SELECTION-TIMESTAMP, then it can be
83 assumed that Emacs owns that selection.
84 The only (eq) parts of this list that are visible from Lisp are the
85 selection-values. */
86 static Lisp_Object Vselection_alist;
87
88 #define SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP 'Etsp'
89
90 /* This is an alist whose CARs are selection-types and whose CDRs are
91 the names of Lisp functions to call to convert the given Emacs
92 selection value to a string representing the given selection type.
93 This is for Lisp-level extension of the emacs selection
94 handling. */
95 static Lisp_Object Vselection_converter_alist;
96
97 /* A selection name (represented as a Lisp symbol) can be associated
98 with a named scrap via `mac-scrap-name' property. Likewise for a
99 selection type with a scrap flavor type via `mac-ostype'. */
100 static Lisp_Object Qmac_scrap_name, Qmac_ostype;
101
102 #ifdef MAC_OSX
103 /* Selection name for communication via Services menu. */
104 static Lisp_Object Vmac_service_selection;
105 #endif
106 \f
107 /* Get a reference to the scrap corresponding to the symbol SYM. The
108 reference is set to *SCRAP, and it becomes NULL if there's no
109 corresponding scrap. Clear the scrap if CLEAR_P is non-zero. */
110
111 static OSErr
112 get_scrap_from_symbol (sym, clear_p, scrap)
113 Lisp_Object sym;
114 int clear_p;
115 ScrapRef *scrap;
116 {
117 OSErr err = noErr;
118 Lisp_Object str = Fget (sym, Qmac_scrap_name);
119
120 if (!STRINGP (str))
121 *scrap = NULL;
122 else
123 {
124 #if TARGET_API_MAC_CARBON
125 #ifdef MAC_OSX
126 CFStringRef scrap_name = cfstring_create_with_string (str);
127 OptionBits options = (clear_p ? kScrapClearNamedScrap
128 : kScrapGetNamedScrap);
129
130 err = GetScrapByName (scrap_name, options, scrap);
131 CFRelease (scrap_name);
132 #else /* !MAC_OSX */
133 if (clear_p)
134 err = ClearCurrentScrap ();
135 if (err == noErr)
136 err = GetCurrentScrap (scrap);
137 #endif /* !MAC_OSX */
138 #else /* !TARGET_API_MAC_CARBON */
139 if (clear_p)
140 err = ZeroScrap ();
141 if (err == noErr)
142 *scrap = 1;
143 #endif /* !TARGET_API_MAC_CARBON */
144 }
145
146 return err;
147 }
148
149 /* Get a scrap flavor type from the symbol SYM. Return 0 if no
150 corresponding flavor type. */
151
152 static ScrapFlavorType
153 get_flavor_type_from_symbol (sym)
154 Lisp_Object sym;
155 {
156 Lisp_Object str = Fget (sym, Qmac_ostype);
157
158 if (STRINGP (str) && SBYTES (str) == 4)
159 return EndianU32_BtoN (*((UInt32 *) SDATA (str)));
160
161 return 0;
162 }
163
164 /* Check if the symbol SYM has a corresponding scrap flavor type. */
165
166 static int
167 valid_scrap_target_type_p (sym)
168 Lisp_Object sym;
169 {
170 return get_flavor_type_from_symbol (sym) != 0;
171 }
172
173 /* Clear the scrap whose reference is *SCRAP. */
174
175 static INLINE OSErr
176 clear_scrap (scrap)
177 ScrapRef *scrap;
178 {
179 #if TARGET_API_MAC_CARBON
180 #ifdef MAC_OSX
181 return ClearScrap (scrap);
182 #else
183 return ClearCurrentScrap ();
184 #endif
185 #else /* !TARGET_API_MAC_CARBON */
186 return ZeroScrap ();
187 #endif /* !TARGET_API_MAC_CARBON */
188 }
189
190 /* Put Lisp String STR to the scrap SCRAP. The target type is
191 specified by TYPE. */
192
193 static OSErr
194 put_scrap_string (scrap, type, str)
195 ScrapRef scrap;
196 Lisp_Object type, str;
197 {
198 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (type);
199
200 if (flavor_type == 0)
201 return noTypeErr;
202
203 #if TARGET_API_MAC_CARBON
204 return PutScrapFlavor (scrap, flavor_type, kScrapFlavorMaskNone,
205 SBYTES (str), SDATA (str));
206 #else /* !TARGET_API_MAC_CARBON */
207 return PutScrap (SBYTES (str), flavor_type, SDATA (str));
208 #endif /* !TARGET_API_MAC_CARBON */
209 }
210
211 /* Put TIMESTAMP to the scrap SCRAP. The timestamp is used for
212 checking if the scrap is owned by the process. */
213
214 static INLINE OSErr
215 put_scrap_private_timestamp (scrap, timestamp)
216 ScrapRef scrap;
217 unsigned long timestamp;
218 {
219 #if TARGET_API_MAC_CARBON
220 return PutScrapFlavor (scrap, SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP,
221 kScrapFlavorMaskSenderOnly,
222 sizeof (timestamp), &timestamp);
223 #else /* !TARGET_API_MAC_CARBON */
224 return PutScrap (sizeof (timestamp), SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP,
225 &timestamp);
226 #endif /* !TARGET_API_MAC_CARBON */
227 }
228
229 /* Check if data for the target type TYPE is available in SCRAP. */
230
231 static ScrapFlavorType
232 scrap_has_target_type (scrap, type)
233 ScrapRef scrap;
234 Lisp_Object type;
235 {
236 OSErr err;
237 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (type);
238
239 if (flavor_type)
240 {
241 #if TARGET_API_MAC_CARBON
242 ScrapFlavorFlags flags;
243
244 err = GetScrapFlavorFlags (scrap, flavor_type, &flags);
245 if (err != noErr)
246 flavor_type = 0;
247 #else /* !TARGET_API_MAC_CARBON */
248 SInt32 size, offset;
249
250 size = GetScrap (NULL, flavor_type, &offset);
251 if (size < 0)
252 flavor_type = 0;
253 #endif /* !TARGET_API_MAC_CARBON */
254 }
255
256 return flavor_type;
257 }
258
259 /* Get data for the target type TYPE from SCRAP and create a Lisp
260 string. Return nil if failed to get data. */
261
262 static Lisp_Object
263 get_scrap_string (scrap, type)
264 ScrapRef scrap;
265 Lisp_Object type;
266 {
267 OSErr err;
268 Lisp_Object result = Qnil;
269 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (type);
270 #if TARGET_API_MAC_CARBON
271 Size size;
272
273 if (flavor_type)
274 {
275 err = GetScrapFlavorSize (scrap, flavor_type, &size);
276 if (err == noErr)
277 {
278 do
279 {
280 result = make_uninit_string (size);
281 err = GetScrapFlavorData (scrap, flavor_type,
282 &size, SDATA (result));
283 if (err != noErr)
284 result = Qnil;
285 else if (size < SBYTES (result))
286 result = make_unibyte_string (SDATA (result), size);
287 }
288 while (STRINGP (result) && size > SBYTES (result));
289 }
290 }
291 #else
292 Handle handle;
293 SInt32 size, offset;
294
295 if (flavor_type)
296 size = GetScrap (NULL, flavor_type, &offset);
297 if (size >= 0)
298 {
299 handle = NewHandle (size);
300 HLock (handle);
301 size = GetScrap (handle, flavor_type, &offset);
302 if (size >= 0)
303 result = make_unibyte_string (*handle, size);
304 DisposeHandle (handle);
305 }
306 #endif
307
308 return result;
309 }
310
311 /* Get timestamp from the scrap SCRAP and set to *TIMPSTAMP. */
312
313 static OSErr
314 get_scrap_private_timestamp (scrap, timestamp)
315 ScrapRef scrap;
316 unsigned long *timestamp;
317 {
318 OSErr err = noErr;
319 #if TARGET_API_MAC_CARBON
320 ScrapFlavorFlags flags;
321
322 err = GetScrapFlavorFlags (scrap, SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP, &flags);
323 if (err == noErr)
324 {
325 if (!(flags & kScrapFlavorMaskSenderOnly))
326 err = noTypeErr;
327 else
328 {
329 Size size = sizeof (*timestamp);
330
331 err = GetScrapFlavorData (scrap, SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP,
332 &size, timestamp);
333 if (err == noErr && size != sizeof (*timestamp))
334 err = noTypeErr;
335 }
336 }
337 #else /* !TARGET_API_MAC_CARBON */
338 Handle handle;
339 SInt32 size, offset;
340
341 size = GetScrap (NULL, SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP, &offset);
342 if (size == sizeof (*timestamp))
343 {
344 handle = NewHandle (size);
345 HLock (handle);
346 size = GetScrap (handle, SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP, &offset);
347 if (size == sizeof (*timestamp))
348 *timestamp = *((unsigned long *) *handle);
349 DisposeHandle (handle);
350 }
351 if (size != sizeof (*timestamp))
352 err = noTypeErr;
353 #endif /* !TARGET_API_MAC_CARBON */
354
355 return err;
356 }
357
358 /* Get the list of target types in SCRAP. The return value is a list
359 of target type symbols possibly followed by scrap flavor type
360 strings. */
361
362 static Lisp_Object
363 get_scrap_target_type_list (scrap)
364 ScrapRef scrap;
365 {
366 Lisp_Object result = Qnil, rest, target_type;
367 #if TARGET_API_MAC_CARBON
368 OSErr err;
369 UInt32 count, i, type;
370 ScrapFlavorInfo *flavor_info = NULL;
371 Lisp_Object strings = Qnil;
372
373 err = GetScrapFlavorCount (scrap, &count);
374 if (err == noErr)
375 flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
376 err = GetScrapFlavorInfoList (scrap, &count, flavor_info);
377 if (err != noErr)
378 {
379 xfree (flavor_info);
380 flavor_info = NULL;
381 }
382 if (flavor_info == NULL)
383 count = 0;
384 #endif
385 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
386 {
387 ScrapFlavorType flavor_type = 0;
388
389 if (CONSP (XCAR (rest)) && SYMBOLP (target_type = XCAR (XCAR (rest)))
390 && (flavor_type = scrap_has_target_type (scrap, target_type)))
391 {
392 result = Fcons (target_type, result);
393 #if TARGET_API_MAC_CARBON
394 for (i = 0; i < count; i++)
395 if (flavor_info[i].flavorType == flavor_type)
396 {
397 flavor_info[i].flavorType = 0;
398 break;
399 }
400 #endif
401 }
402 }
403 #if TARGET_API_MAC_CARBON
404 if (flavor_info)
405 {
406 for (i = 0; i < count; i++)
407 if (flavor_info[i].flavorType)
408 {
409 type = EndianU32_NtoB (flavor_info[i].flavorType);
410 strings = Fcons (make_unibyte_string ((char *) &type, 4), strings);
411 }
412 result = nconc2 (result, strings);
413 xfree (flavor_info);
414 }
415 #endif
416
417 return result;
418 }
419 \f
420 /* Do protocol to assert ourself as a selection owner.
421 Update the Vselection_alist so that we can reply to later requests for
422 our selection. */
423
424 static void
425 x_own_selection (selection_name, selection_value)
426 Lisp_Object selection_name, selection_value;
427 {
428 OSErr err;
429 ScrapRef scrap;
430 struct gcpro gcpro1, gcpro2;
431 Lisp_Object rest, handler_fn, value, type;
432 int count;
433
434 CHECK_SYMBOL (selection_name);
435
436 GCPRO2 (selection_name, selection_value);
437
438 BLOCK_INPUT;
439
440 err = get_scrap_from_symbol (selection_name, 1, &scrap);
441 if (err == noErr && scrap)
442 {
443 /* Don't allow a quit within the converter.
444 When the user types C-g, he would be surprised
445 if by luck it came during a converter. */
446 count = SPECPDL_INDEX ();
447 specbind (Qinhibit_quit, Qt);
448
449 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
450 {
451 if (!(CONSP (XCAR (rest))
452 && SYMBOLP (type = XCAR (XCAR (rest)))
453 && valid_scrap_target_type_p (type)
454 && SYMBOLP (handler_fn = XCDR (XCAR (rest)))))
455 continue;
456
457 if (!NILP (handler_fn))
458 value = call3 (handler_fn, selection_name,
459 type, selection_value);
460
461 if (STRINGP (value))
462 err = put_scrap_string (scrap, type, value);
463 else if (CONSP (value)
464 && EQ (XCAR (value), type)
465 && STRINGP (XCDR (value)))
466 err = put_scrap_string (scrap, type, XCDR (value));
467 }
468
469 unbind_to (count, Qnil);
470
471 if (err == noErr)
472 err = put_scrap_private_timestamp (scrap, last_event_timestamp);
473 }
474
475 UNBLOCK_INPUT;
476
477 UNGCPRO;
478
479 if (scrap && err != noErr)
480 error ("Can't set selection");
481
482 /* Now update the local cache */
483 {
484 Lisp_Object selection_time;
485 Lisp_Object selection_data;
486 Lisp_Object prev_value;
487
488 selection_time = long_to_cons (last_event_timestamp);
489 selection_data = Fcons (selection_name,
490 Fcons (selection_value,
491 Fcons (selection_time,
492 Fcons (selected_frame, Qnil))));
493 prev_value = assq_no_quit (selection_name, Vselection_alist);
494
495 Vselection_alist = Fcons (selection_data, Vselection_alist);
496
497 /* If we already owned the selection, remove the old selection data.
498 Perhaps we should destructively modify it instead.
499 Don't use Fdelq as that may QUIT. */
500 if (!NILP (prev_value))
501 {
502 Lisp_Object rest; /* we know it's not the CAR, so it's easy. */
503 for (rest = Vselection_alist; !NILP (rest); rest = Fcdr (rest))
504 if (EQ (prev_value, Fcar (XCDR (rest))))
505 {
506 XSETCDR (rest, Fcdr (XCDR (rest)));
507 break;
508 }
509 }
510 }
511 }
512 \f
513 /* Given a selection-name and desired type, look up our local copy of
514 the selection value and convert it to the type.
515 The value is nil or a string.
516 This function is used both for remote requests (LOCAL_REQUEST is zero)
517 and for local x-get-selection-internal (LOCAL_REQUEST is nonzero).
518
519 This calls random Lisp code, and may signal or gc. */
520
521 static Lisp_Object
522 x_get_local_selection (selection_symbol, target_type, local_request)
523 Lisp_Object selection_symbol, target_type;
524 int local_request;
525 {
526 Lisp_Object local_value;
527 Lisp_Object handler_fn, value, type, check;
528 int count;
529
530 if (NILP (Fx_selection_owner_p (selection_symbol)))
531 return Qnil;
532
533 local_value = assq_no_quit (selection_symbol, Vselection_alist);
534
535 /* TIMESTAMP is a special case 'cause that's easiest. */
536 if (EQ (target_type, QTIMESTAMP))
537 {
538 handler_fn = Qnil;
539 value = XCAR (XCDR (XCDR (local_value)));
540 }
541 #if 0
542 else if (EQ (target_type, QDELETE))
543 {
544 handler_fn = Qnil;
545 Fx_disown_selection_internal
546 (selection_symbol,
547 XCAR (XCDR (XCDR (local_value))));
548 value = QNULL;
549 }
550 #endif
551 else
552 {
553 /* Don't allow a quit within the converter.
554 When the user types C-g, he would be surprised
555 if by luck it came during a converter. */
556 count = SPECPDL_INDEX ();
557 specbind (Qinhibit_quit, Qt);
558
559 CHECK_SYMBOL (target_type);
560 handler_fn = Fcdr (Fassq (target_type, Vselection_converter_alist));
561 /* gcpro is not needed here since nothing but HANDLER_FN
562 is live, and that ought to be a symbol. */
563
564 if (!NILP (handler_fn))
565 value = call3 (handler_fn,
566 selection_symbol, (local_request ? Qnil : target_type),
567 XCAR (XCDR (local_value)));
568 else
569 value = Qnil;
570 unbind_to (count, Qnil);
571 }
572
573 /* Make sure this value is of a type that we could transmit
574 to another X client. */
575
576 check = value;
577 if (CONSP (value)
578 && SYMBOLP (XCAR (value)))
579 type = XCAR (value),
580 check = XCDR (value);
581
582 if (STRINGP (check)
583 || VECTORP (check)
584 || SYMBOLP (check)
585 || INTEGERP (check)
586 || NILP (value))
587 return value;
588 /* Check for a value that cons_to_long could handle. */
589 else if (CONSP (check)
590 && INTEGERP (XCAR (check))
591 && (INTEGERP (XCDR (check))
592 ||
593 (CONSP (XCDR (check))
594 && INTEGERP (XCAR (XCDR (check)))
595 && NILP (XCDR (XCDR (check))))))
596 return value;
597 else
598 return
599 Fsignal (Qerror,
600 Fcons (build_string ("invalid data returned by selection-conversion function"),
601 Fcons (handler_fn, Fcons (value, Qnil))));
602 }
603
604 \f
605 /* Clear all selections that were made from frame F.
606 We do this when about to delete a frame. */
607
608 void
609 x_clear_frame_selections (f)
610 FRAME_PTR f;
611 {
612 Lisp_Object frame;
613 Lisp_Object rest;
614
615 XSETFRAME (frame, f);
616
617 /* Otherwise, we're really honest and truly being told to drop it.
618 Don't use Fdelq as that may QUIT;. */
619
620 /* Delete elements from the beginning of Vselection_alist. */
621 while (!NILP (Vselection_alist)
622 && EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (Vselection_alist)))))))
623 {
624 /* Let random Lisp code notice that the selection has been stolen. */
625 Lisp_Object hooks, selection_symbol;
626
627 hooks = Vx_lost_selection_functions;
628 selection_symbol = Fcar (Fcar (Vselection_alist));
629
630 if (!EQ (hooks, Qunbound)
631 && !NILP (Fx_selection_owner_p (selection_symbol)))
632 {
633 for (; CONSP (hooks); hooks = Fcdr (hooks))
634 call1 (Fcar (hooks), selection_symbol);
635 #if 0 /* This can crash when deleting a frame
636 from x_connection_closed. Anyway, it seems unnecessary;
637 something else should cause a redisplay. */
638 redisplay_preserve_echo_area (21);
639 #endif
640 }
641
642 Vselection_alist = Fcdr (Vselection_alist);
643 }
644
645 /* Delete elements after the beginning of Vselection_alist. */
646 for (rest = Vselection_alist; !NILP (rest); rest = Fcdr (rest))
647 if (EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (XCDR (rest))))))))
648 {
649 /* Let random Lisp code notice that the selection has been stolen. */
650 Lisp_Object hooks, selection_symbol;
651
652 hooks = Vx_lost_selection_functions;
653 selection_symbol = Fcar (Fcar (XCDR (rest)));
654
655 if (!EQ (hooks, Qunbound)
656 && !NILP (Fx_selection_owner_p (selection_symbol)))
657 {
658 for (; CONSP (hooks); hooks = Fcdr (hooks))
659 call1 (Fcar (hooks), selection_symbol);
660 #if 0 /* See above */
661 redisplay_preserve_echo_area (22);
662 #endif
663 }
664 XSETCDR (rest, Fcdr (XCDR (rest)));
665 break;
666 }
667 }
668 \f
669 /* Do protocol to read selection-data from the server.
670 Converts this to Lisp data and returns it. */
671
672 static Lisp_Object
673 x_get_foreign_selection (selection_symbol, target_type, time_stamp)
674 Lisp_Object selection_symbol, target_type, time_stamp;
675 {
676 OSErr err;
677 ScrapRef scrap;
678 Lisp_Object result = Qnil;
679
680 BLOCK_INPUT;
681
682 err = get_scrap_from_symbol (selection_symbol, 0, &scrap);
683 if (err == noErr && scrap)
684 {
685 if (EQ (target_type, QTARGETS))
686 {
687 result = get_scrap_target_type_list (scrap);
688 result = Fvconcat (1, &result);
689 }
690 else
691 {
692 result = get_scrap_string (scrap, target_type);
693 if (STRINGP (result))
694 Fput_text_property (make_number (0), make_number (SBYTES (result)),
695 Qforeign_selection, target_type, result);
696 }
697 }
698
699 UNBLOCK_INPUT;
700
701 return result;
702 }
703
704
705 DEFUN ("x-own-selection-internal", Fx_own_selection_internal,
706 Sx_own_selection_internal, 2, 2, 0,
707 doc: /* Assert a selection of the given TYPE with the given VALUE.
708 TYPE is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
709 VALUE is typically a string, or a cons of two markers, but may be
710 anything that the functions on `selection-converter-alist' know about. */)
711 (selection_name, selection_value)
712 Lisp_Object selection_name, selection_value;
713 {
714 check_mac ();
715 CHECK_SYMBOL (selection_name);
716 if (NILP (selection_value)) error ("SELECTION-VALUE may not be nil");
717 x_own_selection (selection_name, selection_value);
718 return selection_value;
719 }
720
721
722 /* Request the selection value from the owner. If we are the owner,
723 simply return our selection value. If we are not the owner, this
724 will block until all of the data has arrived. */
725
726 DEFUN ("x-get-selection-internal", Fx_get_selection_internal,
727 Sx_get_selection_internal, 2, 3, 0,
728 doc: /* Return text selected from some Mac application.
729 SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
730 TYPE is the type of data desired, typically `STRING'.
731 TIME_STAMP is ignored on Mac. */)
732 (selection_symbol, target_type, time_stamp)
733 Lisp_Object selection_symbol, target_type, time_stamp;
734 {
735 Lisp_Object val = Qnil;
736 struct gcpro gcpro1, gcpro2;
737 GCPRO2 (target_type, val); /* we store newly consed data into these */
738 check_mac ();
739 CHECK_SYMBOL (selection_symbol);
740 CHECK_SYMBOL (target_type);
741
742 val = x_get_local_selection (selection_symbol, target_type, 1);
743
744 if (NILP (val))
745 {
746 val = x_get_foreign_selection (selection_symbol, target_type, time_stamp);
747 goto DONE;
748 }
749
750 if (CONSP (val)
751 && SYMBOLP (XCAR (val)))
752 {
753 val = XCDR (val);
754 if (CONSP (val) && NILP (XCDR (val)))
755 val = XCAR (val);
756 }
757 DONE:
758 UNGCPRO;
759 return val;
760 }
761
762 DEFUN ("x-disown-selection-internal", Fx_disown_selection_internal,
763 Sx_disown_selection_internal, 1, 2, 0,
764 doc: /* If we own the selection SELECTION, disown it.
765 Disowning it means there is no such selection. */)
766 (selection, time)
767 Lisp_Object selection;
768 Lisp_Object time;
769 {
770 OSErr err;
771 ScrapRef scrap;
772 Lisp_Object local_selection_data;
773
774 check_mac ();
775 CHECK_SYMBOL (selection);
776
777 if (NILP (Fx_selection_owner_p (selection)))
778 return Qnil; /* Don't disown the selection when we're not the owner. */
779
780 local_selection_data = assq_no_quit (selection, Vselection_alist);
781
782 /* Don't use Fdelq as that may QUIT;. */
783
784 if (EQ (local_selection_data, Fcar (Vselection_alist)))
785 Vselection_alist = Fcdr (Vselection_alist);
786 else
787 {
788 Lisp_Object rest;
789 for (rest = Vselection_alist; !NILP (rest); rest = Fcdr (rest))
790 if (EQ (local_selection_data, Fcar (XCDR (rest))))
791 {
792 XSETCDR (rest, Fcdr (XCDR (rest)));
793 break;
794 }
795 }
796
797 /* Let random lisp code notice that the selection has been stolen. */
798
799 {
800 Lisp_Object rest;
801 rest = Vx_lost_selection_functions;
802 if (!EQ (rest, Qunbound))
803 {
804 for (; CONSP (rest); rest = Fcdr (rest))
805 call1 (Fcar (rest), selection);
806 prepare_menu_bars ();
807 redisplay_preserve_echo_area (20);
808 }
809 }
810
811 BLOCK_INPUT;
812
813 err = get_scrap_from_symbol (selection, 0, &scrap);
814 if (err == noErr && scrap)
815 clear_scrap (&scrap);
816
817 UNBLOCK_INPUT;
818
819 return Qt;
820 }
821
822
823 DEFUN ("x-selection-owner-p", Fx_selection_owner_p, Sx_selection_owner_p,
824 0, 1, 0,
825 doc: /* Whether the current Emacs process owns the given SELECTION.
826 The arg should be the name of the selection in question, typically one of
827 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
828 For convenience, the symbol nil is the same as `PRIMARY',
829 and t is the same as `SECONDARY'. */)
830 (selection)
831 Lisp_Object selection;
832 {
833 OSErr err;
834 ScrapRef scrap;
835 Lisp_Object result = Qnil, local_selection_data;
836
837 check_mac ();
838 CHECK_SYMBOL (selection);
839 if (EQ (selection, Qnil)) selection = QPRIMARY;
840 if (EQ (selection, Qt)) selection = QSECONDARY;
841
842 local_selection_data = assq_no_quit (selection, Vselection_alist);
843
844 if (NILP (local_selection_data))
845 return Qnil;
846
847 BLOCK_INPUT;
848
849 err = get_scrap_from_symbol (selection, 0, &scrap);
850 if (err == noErr && scrap)
851 {
852 unsigned long timestamp;
853
854 err = get_scrap_private_timestamp (scrap, &timestamp);
855 if (err == noErr
856 && (timestamp
857 == cons_to_long (XCAR (XCDR (XCDR (local_selection_data))))))
858 result = Qt;
859 }
860 else
861 result = Qt;
862
863 UNBLOCK_INPUT;
864
865 return result;
866 }
867
868 DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
869 0, 1, 0,
870 doc: /* Whether there is an owner for the given SELECTION.
871 The arg should be the name of the selection in question, typically one of
872 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
873 For convenience, the symbol nil is the same as `PRIMARY',
874 and t is the same as `SECONDARY'. */)
875 (selection)
876 Lisp_Object selection;
877 {
878 OSErr err;
879 ScrapRef scrap;
880 Lisp_Object result = Qnil, rest;
881
882 /* It should be safe to call this before we have an Mac frame. */
883 if (! FRAME_MAC_P (SELECTED_FRAME ()))
884 return Qnil;
885
886 CHECK_SYMBOL (selection);
887 if (!NILP (Fx_selection_owner_p (selection)))
888 return Qt;
889 if (EQ (selection, Qnil)) selection = QPRIMARY;
890 if (EQ (selection, Qt)) selection = QSECONDARY;
891
892 BLOCK_INPUT;
893
894 err = get_scrap_from_symbol (selection, 0, &scrap);
895 if (err == noErr && scrap)
896 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
897 {
898 if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
899 && scrap_has_target_type (scrap, XCAR (XCAR (rest))))
900 {
901 result = Qt;
902 break;
903 }
904 }
905
906 UNBLOCK_INPUT;
907
908 return result;
909 }
910
911 \f
912 /***********************************************************************
913 Apple event support
914 ***********************************************************************/
915 int mac_ready_for_apple_events = 0;
916 static Lisp_Object Vmac_apple_event_map;
917 static Lisp_Object Qmac_apple_event_class, Qmac_apple_event_id;
918 static Lisp_Object Qemacs_suspension_id;
919 extern Lisp_Object Qundefined;
920 extern void mac_store_apple_event P_ ((Lisp_Object, Lisp_Object,
921 const AEDesc *));
922
923 struct apple_event_binding
924 {
925 UInt32 code; /* Apple event class or ID. */
926 Lisp_Object key, binding;
927 };
928
929 struct suspended_ae_info
930 {
931 UInt32 expiration_tick, suspension_id;
932 AppleEvent apple_event, reply;
933 struct suspended_ae_info *next;
934 };
935
936 /* List of deferred apple events at the startup time. */
937 static struct suspended_ae_info *deferred_apple_events = NULL;
938
939 /* List of suspended apple events, in order of expiration_tick. */
940 static struct suspended_ae_info *suspended_apple_events = NULL;
941
942 static void
943 find_event_binding_fun (key, binding, args, data)
944 Lisp_Object key, binding, args;
945 void *data;
946 {
947 struct apple_event_binding *event_binding =
948 (struct apple_event_binding *)data;
949 Lisp_Object code_string;
950
951 if (!SYMBOLP (key))
952 return;
953 code_string = Fget (key, args);
954 if (STRINGP (code_string) && SBYTES (code_string) == 4
955 && (EndianU32_BtoN (*((UInt32 *) SDATA (code_string)))
956 == event_binding->code))
957 {
958 event_binding->key = key;
959 event_binding->binding = binding;
960 }
961 }
962
963 static void
964 find_event_binding (keymap, event_binding, class_p)
965 Lisp_Object keymap;
966 struct apple_event_binding *event_binding;
967 int class_p;
968 {
969 if (event_binding->code == 0)
970 event_binding->binding =
971 access_keymap (keymap, event_binding->key, 0, 1, 0);
972 else
973 {
974 event_binding->binding = Qnil;
975 map_keymap (keymap, find_event_binding_fun,
976 class_p ? Qmac_apple_event_class : Qmac_apple_event_id,
977 event_binding, 0);
978 }
979 }
980
981 void
982 mac_find_apple_event_spec (class, id, class_key, id_key, binding)
983 AEEventClass class;
984 AEEventID id;
985 Lisp_Object *class_key, *id_key, *binding;
986 {
987 struct apple_event_binding event_binding;
988 Lisp_Object keymap;
989
990 *binding = Qnil;
991
992 keymap = get_keymap (Vmac_apple_event_map, 0, 0);
993 if (NILP (keymap))
994 return;
995
996 event_binding.code = class;
997 event_binding.key = *class_key;
998 event_binding.binding = Qnil;
999 find_event_binding (keymap, &event_binding, 1);
1000 *class_key = event_binding.key;
1001 keymap = get_keymap (event_binding.binding, 0, 0);
1002 if (NILP (keymap))
1003 return;
1004
1005 event_binding.code = id;
1006 event_binding.key = *id_key;
1007 event_binding.binding = Qnil;
1008 find_event_binding (keymap, &event_binding, 0);
1009 *id_key = event_binding.key;
1010 *binding = event_binding.binding;
1011 }
1012
1013 static OSErr
1014 defer_apple_events (apple_event, reply)
1015 const AppleEvent *apple_event, *reply;
1016 {
1017 OSErr err;
1018 struct suspended_ae_info *new;
1019
1020 new = xmalloc (sizeof (struct suspended_ae_info));
1021 bzero (new, sizeof (struct suspended_ae_info));
1022 new->apple_event.descriptorType = typeNull;
1023 new->reply.descriptorType = typeNull;
1024
1025 err = AESuspendTheCurrentEvent (apple_event);
1026
1027 /* Mac OS 10.3 Xcode manual says AESuspendTheCurrentEvent makes
1028 copies of the Apple event and the reply, but Mac OS 10.4 Xcode
1029 manual says it doesn't. Anyway we create copies of them and save
1030 them in `deferred_apple_events'. */
1031 if (err == noErr)
1032 err = AEDuplicateDesc (apple_event, &new->apple_event);
1033 if (err == noErr)
1034 err = AEDuplicateDesc (reply, &new->reply);
1035 if (err == noErr)
1036 {
1037 new->next = deferred_apple_events;
1038 deferred_apple_events = new;
1039 }
1040 else
1041 {
1042 AEDisposeDesc (&new->apple_event);
1043 AEDisposeDesc (&new->reply);
1044 xfree (new);
1045 }
1046
1047 return err;
1048 }
1049
1050 static OSErr
1051 mac_handle_apple_event_1 (class, id, apple_event, reply)
1052 Lisp_Object class, id;
1053 const AppleEvent *apple_event;
1054 AppleEvent *reply;
1055 {
1056 OSErr err;
1057 static UInt32 suspension_id = 0;
1058 struct suspended_ae_info *new;
1059
1060 new = xmalloc (sizeof (struct suspended_ae_info));
1061 bzero (new, sizeof (struct suspended_ae_info));
1062 new->apple_event.descriptorType = typeNull;
1063 new->reply.descriptorType = typeNull;
1064
1065 err = AESuspendTheCurrentEvent (apple_event);
1066 if (err == noErr)
1067 err = AEDuplicateDesc (apple_event, &new->apple_event);
1068 if (err == noErr)
1069 err = AEDuplicateDesc (reply, &new->reply);
1070 if (err == noErr)
1071 err = AEPutAttributePtr (&new->apple_event, KEY_EMACS_SUSPENSION_ID_ATTR,
1072 typeUInt32, &suspension_id, sizeof (UInt32));
1073 if (err == noErr)
1074 {
1075 OSErr err1;
1076 SInt32 reply_requested;
1077
1078 err1 = AEGetAttributePtr (&new->apple_event, keyReplyRequestedAttr,
1079 typeSInt32, NULL, &reply_requested,
1080 sizeof (SInt32), NULL);
1081 if (err1 != noErr)
1082 {
1083 /* Emulate keyReplyRequestedAttr in older versions. */
1084 reply_requested = reply->descriptorType != typeNull;
1085 err = AEPutAttributePtr (&new->apple_event, keyReplyRequestedAttr,
1086 typeSInt32, &reply_requested,
1087 sizeof (SInt32));
1088 }
1089 }
1090 if (err == noErr)
1091 {
1092 SInt32 timeout = 0;
1093 struct suspended_ae_info **p;
1094
1095 new->suspension_id = suspension_id;
1096 suspension_id++;
1097 err = AEGetAttributePtr (apple_event, keyTimeoutAttr, typeSInt32,
1098 NULL, &timeout, sizeof (SInt32), NULL);
1099 new->expiration_tick = TickCount () + timeout;
1100
1101 for (p = &suspended_apple_events; *p; p = &(*p)->next)
1102 if ((*p)->expiration_tick >= new->expiration_tick)
1103 break;
1104 new->next = *p;
1105 *p = new;
1106
1107 mac_store_apple_event (class, id, &new->apple_event);
1108 }
1109 else
1110 {
1111 AEDisposeDesc (&new->reply);
1112 AEDisposeDesc (&new->apple_event);
1113 xfree (new);
1114 }
1115
1116 return err;
1117 }
1118
1119 static pascal OSErr
1120 mac_handle_apple_event (apple_event, reply, refcon)
1121 const AppleEvent *apple_event;
1122 AppleEvent *reply;
1123 SInt32 refcon;
1124 {
1125 OSErr err;
1126 UInt32 suspension_id;
1127 AEEventClass event_class;
1128 AEEventID event_id;
1129 Lisp_Object class_key, id_key, binding;
1130
1131 if (!mac_ready_for_apple_events)
1132 {
1133 err = defer_apple_events (apple_event, reply);
1134 if (err != noErr)
1135 return errAEEventNotHandled;
1136 return noErr;
1137 }
1138
1139 err = AEGetAttributePtr (apple_event, KEY_EMACS_SUSPENSION_ID_ATTR,
1140 typeUInt32, NULL,
1141 &suspension_id, sizeof (UInt32), NULL);
1142 if (err == noErr)
1143 /* Previously suspended event. Pass it to the next handler. */
1144 return errAEEventNotHandled;
1145
1146 err = AEGetAttributePtr (apple_event, keyEventClassAttr, typeType, NULL,
1147 &event_class, sizeof (AEEventClass), NULL);
1148 if (err == noErr)
1149 err = AEGetAttributePtr (apple_event, keyEventIDAttr, typeType, NULL,
1150 &event_id, sizeof (AEEventID), NULL);
1151 if (err == noErr)
1152 {
1153 mac_find_apple_event_spec (event_class, event_id,
1154 &class_key, &id_key, &binding);
1155 if (!NILP (binding) && !EQ (binding, Qundefined))
1156 {
1157 if (INTEGERP (binding))
1158 return XINT (binding);
1159 err = mac_handle_apple_event_1 (class_key, id_key,
1160 apple_event, reply);
1161 }
1162 else
1163 err = errAEEventNotHandled;
1164 }
1165 if (err == noErr)
1166 return noErr;
1167 else
1168 return errAEEventNotHandled;
1169 }
1170
1171 static int
1172 cleanup_suspended_apple_events (head, all_p)
1173 struct suspended_ae_info **head;
1174 int all_p;
1175 {
1176 UInt32 current_tick = TickCount (), nresumed = 0;
1177 struct suspended_ae_info *p, *next;
1178
1179 for (p = *head; p; p = next)
1180 {
1181 if (!all_p && p->expiration_tick > current_tick)
1182 break;
1183 AESetTheCurrentEvent (&p->apple_event);
1184 AEResumeTheCurrentEvent (&p->apple_event, &p->reply,
1185 (AEEventHandlerUPP) kAENoDispatch, 0);
1186 AEDisposeDesc (&p->reply);
1187 AEDisposeDesc (&p->apple_event);
1188 nresumed++;
1189 next = p->next;
1190 xfree (p);
1191 }
1192 *head = p;
1193
1194 return nresumed;
1195 }
1196
1197 static void
1198 cleanup_all_suspended_apple_events ()
1199 {
1200 cleanup_suspended_apple_events (&deferred_apple_events, 1);
1201 cleanup_suspended_apple_events (&suspended_apple_events, 1);
1202 }
1203
1204 void
1205 init_apple_event_handler ()
1206 {
1207 OSErr err;
1208 long result;
1209
1210 /* Make sure we have Apple events before starting. */
1211 err = Gestalt (gestaltAppleEventsAttr, &result);
1212 if (err != noErr)
1213 abort ();
1214
1215 if (!(result & (1 << gestaltAppleEventsPresent)))
1216 abort ();
1217
1218 err = AEInstallEventHandler (typeWildCard, typeWildCard,
1219 #if TARGET_API_MAC_CARBON
1220 NewAEEventHandlerUPP (mac_handle_apple_event),
1221 #else
1222 NewAEEventHandlerProc (mac_handle_apple_event),
1223 #endif
1224 0L, false);
1225 if (err != noErr)
1226 abort ();
1227
1228 atexit (cleanup_all_suspended_apple_events);
1229 }
1230
1231 static UInt32
1232 get_suspension_id (apple_event)
1233 Lisp_Object apple_event;
1234 {
1235 Lisp_Object tem;
1236
1237 CHECK_CONS (apple_event);
1238 CHECK_STRING_CAR (apple_event);
1239 if (SBYTES (XCAR (apple_event)) != 4
1240 || strcmp (SDATA (XCAR (apple_event)), "aevt") != 0)
1241 error ("Not an apple event");
1242
1243 tem = assq_no_quit (Qemacs_suspension_id, XCDR (apple_event));
1244 if (NILP (tem))
1245 error ("Suspension ID not available");
1246
1247 tem = XCDR (tem);
1248 if (!(CONSP (tem)
1249 && STRINGP (XCAR (tem)) && SBYTES (XCAR (tem)) == 4
1250 && strcmp (SDATA (XCAR (tem)), "magn") == 0
1251 && STRINGP (XCDR (tem)) && SBYTES (XCDR (tem)) == 4))
1252 error ("Bad suspension ID format");
1253
1254 return *((UInt32 *) SDATA (XCDR (tem)));
1255 }
1256
1257
1258 DEFUN ("mac-process-deferred-apple-events", Fmac_process_deferred_apple_events, Smac_process_deferred_apple_events, 0, 0, 0,
1259 doc: /* Process Apple events that are deferred at the startup time. */)
1260 ()
1261 {
1262 if (mac_ready_for_apple_events)
1263 return Qnil;
1264
1265 BLOCK_INPUT;
1266 mac_ready_for_apple_events = 1;
1267 if (deferred_apple_events)
1268 {
1269 struct suspended_ae_info *prev, *tail, *next;
1270
1271 /* `nreverse' deferred_apple_events. */
1272 prev = NULL;
1273 for (tail = deferred_apple_events; tail; tail = next)
1274 {
1275 next = tail->next;
1276 tail->next = prev;
1277 prev = tail;
1278 }
1279
1280 /* Now `prev' points to the first cell. */
1281 for (tail = prev; tail; tail = next)
1282 {
1283 next = tail->next;
1284 AEResumeTheCurrentEvent (&tail->apple_event, &tail->reply,
1285 ((AEEventHandlerUPP)
1286 kAEUseStandardDispatch), 0);
1287 AEDisposeDesc (&tail->reply);
1288 AEDisposeDesc (&tail->apple_event);
1289 xfree (tail);
1290 }
1291
1292 deferred_apple_events = NULL;
1293 }
1294 UNBLOCK_INPUT;
1295
1296 return Qt;
1297 }
1298
1299 DEFUN ("mac-cleanup-expired-apple-events", Fmac_cleanup_expired_apple_events, Smac_cleanup_expired_apple_events, 0, 0, 0,
1300 doc: /* Clean up expired Apple events.
1301 Return the number of expired events. */)
1302 ()
1303 {
1304 int nexpired;
1305
1306 BLOCK_INPUT;
1307 nexpired = cleanup_suspended_apple_events (&suspended_apple_events, 0);
1308 UNBLOCK_INPUT;
1309
1310 return make_number (nexpired);
1311 }
1312
1313 DEFUN ("mac-ae-set-reply-parameter", Fmac_ae_set_reply_parameter, Smac_ae_set_reply_parameter, 3, 3, 0,
1314 doc: /* Set parameter KEYWORD to DESCRIPTOR on reply of APPLE-EVENT.
1315 KEYWORD is a 4-byte string. DESCRIPTOR is a Lisp representation of an
1316 Apple event descriptor. It has the form of (TYPE . DATA), where TYPE
1317 is a 4-byte string. Valid format of DATA is as follows:
1318
1319 * If TYPE is "null", then DATA is nil.
1320 * If TYPE is "list", then DATA is a list (DESCRIPTOR1 ... DESCRIPTORn).
1321 * If TYPE is "reco", then DATA is a list ((KEYWORD1 . DESCRIPTOR1)
1322 ... (KEYWORDn . DESCRIPTORn)).
1323 * If TYPE is "aevt", then DATA is ignored and the descriptor is
1324 treated as null.
1325 * Otherwise, DATA is a string.
1326
1327 If a (sub-)descriptor is in an invalid format, it is silently treated
1328 as null.
1329
1330 Return t if the parameter is successfully set. Otherwise return nil. */)
1331 (apple_event, keyword, descriptor)
1332 Lisp_Object apple_event, keyword, descriptor;
1333 {
1334 Lisp_Object result = Qnil;
1335 UInt32 suspension_id;
1336 struct suspended_ae_info *p;
1337
1338 suspension_id = get_suspension_id (apple_event);
1339
1340 CHECK_STRING (keyword);
1341 if (SBYTES (keyword) != 4)
1342 error ("Apple event keyword must be a 4-byte string: %s",
1343 SDATA (keyword));
1344
1345 BLOCK_INPUT;
1346 for (p = suspended_apple_events; p; p = p->next)
1347 if (p->suspension_id == suspension_id)
1348 break;
1349 if (p && p->reply.descriptorType != typeNull)
1350 {
1351 OSErr err;
1352
1353 err = mac_ae_put_lisp (&p->reply,
1354 EndianU32_BtoN (*((UInt32 *) SDATA (keyword))),
1355 descriptor);
1356 if (err == noErr)
1357 result = Qt;
1358 }
1359 UNBLOCK_INPUT;
1360
1361 return result;
1362 }
1363
1364 DEFUN ("mac-resume-apple-event", Fmac_resume_apple_event, Smac_resume_apple_event, 1, 2, 0,
1365 doc: /* Resume handling of APPLE-EVENT.
1366 Every Apple event handled by the Lisp interpreter is suspended first.
1367 This function resumes such a suspended event either to complete Apple
1368 event handling to give a reply, or to redispatch it to other handlers.
1369
1370 If optional ERROR-CODE is an integer, it specifies the error number
1371 that is set in the reply. If ERROR-CODE is t, the resumed event is
1372 handled with the standard dispatching mechanism, but it is not handled
1373 by Emacs again, thus it is redispatched to other handlers.
1374
1375 Return t if APPLE-EVENT is successfully resumed. Otherwise return
1376 nil, which means the event is already resumed or expired. */)
1377 (apple_event, error_code)
1378 Lisp_Object apple_event, error_code;
1379 {
1380 Lisp_Object result = Qnil;
1381 UInt32 suspension_id;
1382 struct suspended_ae_info **p, *ae;
1383
1384 suspension_id = get_suspension_id (apple_event);
1385
1386 BLOCK_INPUT;
1387 for (p = &suspended_apple_events; *p; p = &(*p)->next)
1388 if ((*p)->suspension_id == suspension_id)
1389 break;
1390 if (*p)
1391 {
1392 ae = *p;
1393 *p = (*p)->next;
1394 if (INTEGERP (error_code)
1395 && ae->apple_event.descriptorType != typeNull)
1396 {
1397 SInt32 errn = XINT (error_code);
1398
1399 AEPutParamPtr (&ae->reply, keyErrorNumber, typeSInt32,
1400 &errn, sizeof (SInt32));
1401 }
1402 AESetTheCurrentEvent (&ae->apple_event);
1403 AEResumeTheCurrentEvent (&ae->apple_event, &ae->reply,
1404 ((AEEventHandlerUPP)
1405 (EQ (error_code, Qt) ?
1406 kAEUseStandardDispatch : kAENoDispatch)),
1407 0);
1408 AEDisposeDesc (&ae->reply);
1409 AEDisposeDesc (&ae->apple_event);
1410 xfree (ae);
1411 result = Qt;
1412 }
1413 UNBLOCK_INPUT;
1414
1415 return result;
1416 }
1417
1418 \f
1419 /***********************************************************************
1420 Drag and drop support
1421 ***********************************************************************/
1422 #if TARGET_API_MAC_CARBON
1423 static Lisp_Object Vmac_dnd_known_types;
1424 static pascal OSErr mac_do_track_drag P_ ((DragTrackingMessage, WindowRef,
1425 void *, DragRef));
1426 static pascal OSErr mac_do_receive_drag P_ ((WindowRef, void *, DragRef));
1427 static DragTrackingHandlerUPP mac_do_track_dragUPP = NULL;
1428 static DragReceiveHandlerUPP mac_do_receive_dragUPP = NULL;
1429
1430 extern void mac_store_drag_event P_ ((WindowRef, Point, SInt16,
1431 const AEDesc *));
1432
1433 static pascal OSErr
1434 mac_do_track_drag (message, window, refcon, drag)
1435 DragTrackingMessage message;
1436 WindowRef window;
1437 void *refcon;
1438 DragRef drag;
1439 {
1440 OSErr err = noErr;
1441 static int can_accept;
1442 UInt16 num_items, index;
1443
1444 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
1445 return dragNotAcceptedErr;
1446
1447 switch (message)
1448 {
1449 case kDragTrackingEnterHandler:
1450 err = CountDragItems (drag, &num_items);
1451 if (err != noErr)
1452 break;
1453 can_accept = 0;
1454 for (index = 1; index <= num_items; index++)
1455 {
1456 ItemReference item;
1457 FlavorFlags flags;
1458 Lisp_Object rest;
1459
1460 err = GetDragItemReferenceNumber (drag, index, &item);
1461 if (err != noErr)
1462 continue;
1463 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
1464 {
1465 Lisp_Object str;
1466 FlavorType type;
1467
1468 str = XCAR (rest);
1469 if (!(STRINGP (str) && SBYTES (str) == 4))
1470 continue;
1471 type = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
1472
1473 err = GetFlavorFlags (drag, item, type, &flags);
1474 if (err == noErr)
1475 {
1476 can_accept = 1;
1477 break;
1478 }
1479 }
1480 }
1481 break;
1482
1483 case kDragTrackingEnterWindow:
1484 if (can_accept)
1485 {
1486 RgnHandle hilite_rgn = NewRgn ();
1487
1488 if (hilite_rgn)
1489 {
1490 Rect r;
1491
1492 GetWindowPortBounds (window, &r);
1493 OffsetRect (&r, -r.left, -r.top);
1494 RectRgn (hilite_rgn, &r);
1495 ShowDragHilite (drag, hilite_rgn, true);
1496 DisposeRgn (hilite_rgn);
1497 }
1498 SetThemeCursor (kThemeCopyArrowCursor);
1499 }
1500 break;
1501
1502 case kDragTrackingInWindow:
1503 break;
1504
1505 case kDragTrackingLeaveWindow:
1506 if (can_accept)
1507 {
1508 HideDragHilite (drag);
1509 SetThemeCursor (kThemeArrowCursor);
1510 }
1511 break;
1512
1513 case kDragTrackingLeaveHandler:
1514 break;
1515 }
1516
1517 if (err != noErr)
1518 return dragNotAcceptedErr;
1519 return noErr;
1520 }
1521
1522 static pascal OSErr
1523 mac_do_receive_drag (window, refcon, drag)
1524 WindowRef window;
1525 void *refcon;
1526 DragRef drag;
1527 {
1528 OSErr err;
1529 int num_types, i;
1530 Lisp_Object rest, str;
1531 FlavorType *types;
1532 AppleEvent apple_event;
1533 Point mouse_pos;
1534 SInt16 modifiers;
1535
1536 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
1537 return dragNotAcceptedErr;
1538
1539 num_types = 0;
1540 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
1541 {
1542 str = XCAR (rest);
1543 if (STRINGP (str) && SBYTES (str) == 4)
1544 num_types++;
1545 }
1546
1547 types = xmalloc (sizeof (FlavorType) * num_types);
1548 i = 0;
1549 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
1550 {
1551 str = XCAR (rest);
1552 if (STRINGP (str) && SBYTES (str) == 4)
1553 types[i++] = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
1554 }
1555
1556 err = create_apple_event_from_drag_ref (drag, num_types, types,
1557 &apple_event);
1558 xfree (types);
1559
1560 if (err == noErr)
1561 err = GetDragMouse (drag, &mouse_pos, NULL);
1562 if (err == noErr)
1563 {
1564 GlobalToLocal (&mouse_pos);
1565 err = GetDragModifiers (drag, NULL, NULL, &modifiers);
1566 }
1567
1568 if (err == noErr)
1569 {
1570 mac_store_drag_event (window, mouse_pos, modifiers, &apple_event);
1571 AEDisposeDesc (&apple_event);
1572 /* Post a harmless event so as to wake up from ReceiveNextEvent. */
1573 mac_post_mouse_moved_event ();
1574 return noErr;
1575 }
1576 else
1577 return dragNotAcceptedErr;
1578 }
1579 #endif /* TARGET_API_MAC_CARBON */
1580
1581 OSErr
1582 install_drag_handler (window)
1583 WindowRef window;
1584 {
1585 OSErr err = noErr;
1586
1587 #if TARGET_API_MAC_CARBON
1588 if (mac_do_track_dragUPP == NULL)
1589 mac_do_track_dragUPP = NewDragTrackingHandlerUPP (mac_do_track_drag);
1590 if (mac_do_receive_dragUPP == NULL)
1591 mac_do_receive_dragUPP = NewDragReceiveHandlerUPP (mac_do_receive_drag);
1592
1593 err = InstallTrackingHandler (mac_do_track_dragUPP, window, NULL);
1594 if (err == noErr)
1595 err = InstallReceiveHandler (mac_do_receive_dragUPP, window, NULL);
1596 #endif
1597
1598 return err;
1599 }
1600
1601 void
1602 remove_drag_handler (window)
1603 WindowRef window;
1604 {
1605 #if TARGET_API_MAC_CARBON
1606 if (mac_do_track_dragUPP)
1607 RemoveTrackingHandler (mac_do_track_dragUPP, window);
1608 if (mac_do_receive_dragUPP)
1609 RemoveReceiveHandler (mac_do_receive_dragUPP, window);
1610 #endif
1611 }
1612
1613 \f
1614 /***********************************************************************
1615 Services menu support
1616 ***********************************************************************/
1617 #ifdef MAC_OSX
1618 void
1619 init_service_handler ()
1620 {
1621 EventTypeSpec specs[] = {{kEventClassService, kEventServiceGetTypes},
1622 {kEventClassService, kEventServiceCopy},
1623 {kEventClassService, kEventServicePaste},
1624 {kEventClassService, kEventServicePerform}};
1625 InstallApplicationEventHandler (NewEventHandlerUPP (mac_handle_service_event),
1626 GetEventTypeCount (specs), specs, NULL, NULL);
1627 }
1628
1629 extern OSStatus mac_store_service_event P_ ((EventRef));
1630
1631 static OSStatus
1632 copy_scrap_flavor_data (from_scrap, to_scrap, flavor_type)
1633 ScrapRef from_scrap, to_scrap;
1634 ScrapFlavorType flavor_type;
1635 {
1636 OSStatus err;
1637 Size size, size_allocated;
1638 char *buf = NULL;
1639
1640 err = GetScrapFlavorSize (from_scrap, flavor_type, &size);
1641 if (err == noErr)
1642 buf = xmalloc (size);
1643 while (buf)
1644 {
1645 size_allocated = size;
1646 err = GetScrapFlavorData (from_scrap, flavor_type, &size, buf);
1647 if (err != noErr)
1648 {
1649 xfree (buf);
1650 buf = NULL;
1651 }
1652 else if (size_allocated < size)
1653 buf = xrealloc (buf, size);
1654 else
1655 break;
1656 }
1657 if (err == noErr)
1658 {
1659 if (buf == NULL)
1660 err = memFullErr;
1661 else
1662 {
1663 err = PutScrapFlavor (to_scrap, flavor_type, kScrapFlavorMaskNone,
1664 size, buf);
1665 xfree (buf);
1666 }
1667 }
1668
1669 return err;
1670 }
1671
1672 static OSStatus
1673 mac_handle_service_event (call_ref, event, data)
1674 EventHandlerCallRef call_ref;
1675 EventRef event;
1676 void *data;
1677 {
1678 OSStatus err = noErr;
1679 ScrapRef cur_scrap, specific_scrap;
1680 UInt32 event_kind = GetEventKind (event);
1681 CFMutableArrayRef copy_types, paste_types;
1682 CFStringRef type;
1683 Lisp_Object rest;
1684 ScrapFlavorType flavor_type;
1685
1686 /* Check if Vmac_service_selection is a valid selection that has a
1687 corresponding scrap. */
1688 if (!SYMBOLP (Vmac_service_selection))
1689 err = eventNotHandledErr;
1690 else
1691 err = get_scrap_from_symbol (Vmac_service_selection, 0, &cur_scrap);
1692 if (!(err == noErr && cur_scrap))
1693 return eventNotHandledErr;
1694
1695 switch (event_kind)
1696 {
1697 case kEventServiceGetTypes:
1698 /* Set paste types. */
1699 err = GetEventParameter (event, kEventParamServicePasteTypes,
1700 typeCFMutableArrayRef, NULL,
1701 sizeof (CFMutableArrayRef), NULL,
1702 &paste_types);
1703 if (err != noErr)
1704 break;
1705
1706 for (rest = Vselection_converter_alist; CONSP (rest);
1707 rest = XCDR (rest))
1708 if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
1709 && (flavor_type =
1710 get_flavor_type_from_symbol (XCAR (XCAR (rest)))))
1711 {
1712 type = CreateTypeStringWithOSType (flavor_type);
1713 if (type)
1714 {
1715 CFArrayAppendValue (paste_types, type);
1716 CFRelease (type);
1717 }
1718 }
1719
1720 /* Set copy types. */
1721 err = GetEventParameter (event, kEventParamServiceCopyTypes,
1722 typeCFMutableArrayRef, NULL,
1723 sizeof (CFMutableArrayRef), NULL,
1724 &copy_types);
1725 if (err != noErr)
1726 break;
1727
1728 if (NILP (Fx_selection_owner_p (Vmac_service_selection)))
1729 break;
1730 else
1731 goto copy_all_flavors;
1732
1733 case kEventServiceCopy:
1734 err = GetEventParameter (event, kEventParamScrapRef,
1735 typeScrapRef, NULL,
1736 sizeof (ScrapRef), NULL, &specific_scrap);
1737 if (err != noErr
1738 || NILP (Fx_selection_owner_p (Vmac_service_selection)))
1739 {
1740 err = eventNotHandledErr;
1741 break;
1742 }
1743
1744 copy_all_flavors:
1745 {
1746 UInt32 count, i;
1747 ScrapFlavorInfo *flavor_info = NULL;
1748 ScrapFlavorFlags flags;
1749
1750 err = GetScrapFlavorCount (cur_scrap, &count);
1751 if (err == noErr)
1752 flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
1753 err = GetScrapFlavorInfoList (cur_scrap, &count, flavor_info);
1754 if (err != noErr)
1755 {
1756 xfree (flavor_info);
1757 flavor_info = NULL;
1758 }
1759 if (flavor_info == NULL)
1760 break;
1761
1762 for (i = 0; i < count; i++)
1763 {
1764 flavor_type = flavor_info[i].flavorType;
1765 err = GetScrapFlavorFlags (cur_scrap, flavor_type, &flags);
1766 if (err == noErr && !(flags & kScrapFlavorMaskSenderOnly))
1767 {
1768 if (event_kind == kEventServiceCopy)
1769 err = copy_scrap_flavor_data (cur_scrap, specific_scrap,
1770 flavor_type);
1771 else /* event_kind == kEventServiceGetTypes */
1772 {
1773 type = CreateTypeStringWithOSType (flavor_type);
1774 if (type)
1775 {
1776 CFArrayAppendValue (copy_types, type);
1777 CFRelease (type);
1778 }
1779 }
1780 }
1781 }
1782 xfree (flavor_info);
1783 }
1784 break;
1785
1786 case kEventServicePaste:
1787 case kEventServicePerform:
1788 {
1789 int data_exists_p = 0;
1790
1791 err = GetEventParameter (event, kEventParamScrapRef, typeScrapRef,
1792 NULL, sizeof (ScrapRef), NULL,
1793 &specific_scrap);
1794 if (err == noErr)
1795 err = clear_scrap (&cur_scrap);
1796 if (err == noErr)
1797 for (rest = Vselection_converter_alist; CONSP (rest);
1798 rest = XCDR (rest))
1799 {
1800 if (! (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))))
1801 continue;
1802 flavor_type = get_flavor_type_from_symbol (XCAR (XCAR (rest)));
1803 if (flavor_type == 0)
1804 continue;
1805 err = copy_scrap_flavor_data (specific_scrap, cur_scrap,
1806 flavor_type);
1807 if (err == noErr)
1808 data_exists_p = 1;
1809 }
1810 if (!data_exists_p)
1811 err = eventNotHandledErr;
1812 else
1813 err = mac_store_service_event (event);
1814 }
1815 break;
1816 }
1817
1818 if (err != noErr)
1819 err = eventNotHandledErr;
1820 return err;
1821 }
1822 #endif
1823
1824
1825 void
1826 syms_of_macselect ()
1827 {
1828 defsubr (&Sx_get_selection_internal);
1829 defsubr (&Sx_own_selection_internal);
1830 defsubr (&Sx_disown_selection_internal);
1831 defsubr (&Sx_selection_owner_p);
1832 defsubr (&Sx_selection_exists_p);
1833 defsubr (&Smac_process_deferred_apple_events);
1834 defsubr (&Smac_cleanup_expired_apple_events);
1835 defsubr (&Smac_resume_apple_event);
1836 defsubr (&Smac_ae_set_reply_parameter);
1837
1838 Vselection_alist = Qnil;
1839 staticpro (&Vselection_alist);
1840
1841 DEFVAR_LISP ("selection-converter-alist", &Vselection_converter_alist,
1842 doc: /* An alist associating selection-types with functions.
1843 These functions are called to convert the selection, with three args:
1844 the name of the selection (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');
1845 a desired type to which the selection should be converted;
1846 and the local selection value (whatever was given to `x-own-selection').
1847
1848 The function should return the value to send to the Scrap Manager
1849 \(must be a string). A return value of nil
1850 means that the conversion could not be done.
1851 A return value which is the symbol `NULL'
1852 means that a side-effect was executed,
1853 and there is no meaningful selection value. */);
1854 Vselection_converter_alist = Qnil;
1855
1856 DEFVAR_LISP ("x-lost-selection-functions", &Vx_lost_selection_functions,
1857 doc: /* A list of functions to be called when Emacs loses a selection.
1858 \(This happens when a Lisp program explicitly clears the selection.)
1859 The functions are called with one argument, the selection type
1860 \(a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'). */);
1861 Vx_lost_selection_functions = Qnil;
1862
1863 DEFVAR_LISP ("selection-coding-system", &Vselection_coding_system,
1864 doc: /* Coding system for communicating with other programs.
1865 When sending or receiving text via cut_buffer, selection, and clipboard,
1866 the text is encoded or decoded by this coding system.
1867 The default value is determined by the system script code. */);
1868 Vselection_coding_system = Qnil;
1869
1870 DEFVAR_LISP ("next-selection-coding-system", &Vnext_selection_coding_system,
1871 doc: /* Coding system for the next communication with other programs.
1872 Usually, `selection-coding-system' is used for communicating with
1873 other programs. But, if this variable is set, it is used for the
1874 next communication only. After the communication, this variable is
1875 set to nil. */);
1876 Vnext_selection_coding_system = Qnil;
1877
1878 DEFVAR_LISP ("mac-apple-event-map", &Vmac_apple_event_map,
1879 doc: /* Keymap for Apple events handled by Emacs. */);
1880 Vmac_apple_event_map = Qnil;
1881
1882 #if TARGET_API_MAC_CARBON
1883 DEFVAR_LISP ("mac-dnd-known-types", &Vmac_dnd_known_types,
1884 doc: /* The types accepted by default for dropped data.
1885 The types are chosen in the order they appear in the list. */);
1886 Vmac_dnd_known_types = list4 (build_string ("hfs "), build_string ("utxt"),
1887 build_string ("TEXT"), build_string ("TIFF"));
1888 #ifdef MAC_OSX
1889 Vmac_dnd_known_types = Fcons (build_string ("furl"), Vmac_dnd_known_types);
1890 #endif
1891 #endif
1892
1893 #ifdef MAC_OSX
1894 DEFVAR_LISP ("mac-service-selection", &Vmac_service_selection,
1895 doc: /* Selection name for communication via Services menu. */);
1896 Vmac_service_selection = intern ("PRIMARY");
1897 #endif
1898
1899 QPRIMARY = intern ("PRIMARY"); staticpro (&QPRIMARY);
1900 QSECONDARY = intern ("SECONDARY"); staticpro (&QSECONDARY);
1901 QTIMESTAMP = intern ("TIMESTAMP"); staticpro (&QTIMESTAMP);
1902 QTARGETS = intern ("TARGETS"); staticpro (&QTARGETS);
1903
1904 Qforeign_selection = intern ("foreign-selection");
1905 staticpro (&Qforeign_selection);
1906
1907 Qmac_scrap_name = intern ("mac-scrap-name");
1908 staticpro (&Qmac_scrap_name);
1909
1910 Qmac_ostype = intern ("mac-ostype");
1911 staticpro (&Qmac_ostype);
1912
1913 Qmac_apple_event_class = intern ("mac-apple-event-class");
1914 staticpro (&Qmac_apple_event_class);
1915
1916 Qmac_apple_event_id = intern ("mac-apple-event-id");
1917 staticpro (&Qmac_apple_event_id);
1918
1919 Qemacs_suspension_id = intern ("emacs-suspension-id");
1920 staticpro (&Qemacs_suspension_id);
1921 }
1922
1923 /* arch-tag: f3c91ad8-99e0-4bd6-9eef-251b2f848732
1924 (do not change this comment) */