aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorYAMAMOTO Mitsuharu2005-04-24 05:58:47 +0000
committerYAMAMOTO Mitsuharu2005-04-24 05:58:47 +0000
commit944cda7903256c077bd928de330706951611b63d (patch)
tree982f0656a6bafaead779519200ffae8be91c8480 /src
parent2c97085e8479809f9005546fd4718a9dfbd284db (diff)
downloademacs-944cda7903256c077bd928de330706951611b63d.tar.gz
emacs-944cda7903256c077bd928de330706951611b63d.zip
New file for selection processing on Mac OS.
Diffstat (limited to 'src')
-rw-r--r--src/macselect.c1118
1 files changed, 1118 insertions, 0 deletions
diff --git a/src/macselect.c b/src/macselect.c
new file mode 100644
index 00000000000..aa2cfb55749
--- /dev/null
+++ b/src/macselect.c
@@ -0,0 +1,1118 @@
1/* Selection processing for Emacs on Mac OS.
2 Copyright (C) 2005 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
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
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21#include <config.h>
22
23#include "lisp.h"
24#include "macterm.h"
25#include "blockinput.h"
26
27#if !TARGET_API_MAC_CARBON
28#include <Endian.h>
29typedef int ScrapRef;
30typedef ResType ScrapFlavorType;
31#endif /* !TARGET_API_MAC_CARBON */
32
33static OSErr get_scrap_from_symbol P_ ((Lisp_Object, int, ScrapRef *));
34static ScrapFlavorType get_flavor_type_from_symbol P_ ((Lisp_Object));
35static int valid_scrap_target_type_p P_ ((Lisp_Object));
36static OSErr clear_scrap P_ ((ScrapRef *));
37static OSErr put_scrap_string P_ ((ScrapRef, Lisp_Object, Lisp_Object));
38static OSErr put_scrap_private_timestamp P_ ((ScrapRef, unsigned long));
39static ScrapFlavorType scrap_has_target_type P_ ((ScrapRef, Lisp_Object));
40static Lisp_Object get_scrap_string P_ ((ScrapRef, Lisp_Object));
41static OSErr get_scrap_private_timestamp P_ ((ScrapRef, unsigned long *));
42static Lisp_Object get_scrap_target_type_list P_ ((ScrapRef));
43static void x_own_selection P_ ((Lisp_Object, Lisp_Object));
44static Lisp_Object x_get_local_selection P_ ((Lisp_Object, Lisp_Object, int));
45static Lisp_Object x_get_foreign_selection P_ ((Lisp_Object,
46 Lisp_Object,
47 Lisp_Object));
48EXFUN (Fx_selection_owner_p, 1);
49#ifdef MAC_OSX
50static OSStatus mac_handle_service_event P_ ((EventHandlerCallRef,
51 EventRef, void *));
52void init_service_handler P_ ((void));
53#endif
54
55Lisp_Object QPRIMARY, QSECONDARY, QTIMESTAMP, QTARGETS;
56
57static Lisp_Object Vx_lost_selection_functions;
58/* Coding system for communicating with other programs via scrap. */
59static Lisp_Object Vselection_coding_system;
60
61/* Coding system for the next communicating with other programs. */
62static Lisp_Object Vnext_selection_coding_system;
63
64static Lisp_Object Qforeign_selection;
65
66/* The timestamp of the last input event Emacs received from the
67 window server. */
68/* Defined in keyboard.c. */
69extern unsigned long last_event_timestamp;
70
71/* This is an association list whose elements are of the form
72 ( SELECTION-NAME SELECTION-VALUE SELECTION-TIMESTAMP FRAME)
73 SELECTION-NAME is a lisp symbol.
74 SELECTION-VALUE is the value that emacs owns for that selection.
75 It may be any kind of Lisp object.
76 SELECTION-TIMESTAMP is the time at which emacs began owning this selection,
77 as a cons of two 16-bit numbers (making a 32 bit time.)
78 FRAME is the frame for which we made the selection.
79 If there is an entry in this alist, and the data for the flavor
80 type SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP in the corresponding scrap
81 (if exists) coincides with SELECTION-TIMESTAMP, then it can be
82 assumed that Emacs owns that selection.
83 The only (eq) parts of this list that are visible from Lisp are the
84 selection-values. */
85static Lisp_Object Vselection_alist;
86
87#define SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP 'Etsp'
88
89/* This is an alist whose CARs are selection-types and whose CDRs are
90 the names of Lisp functions to call to convert the given Emacs
91 selection value to a string representing the given selection type.
92 This is for Lisp-level extension of the emacs selection
93 handling. */
94static Lisp_Object Vselection_converter_alist;
95
96/* A selection name (represented as a Lisp symbol) can be associated
97 with a named scrap via `mac-scrap-name' property. Likewise for a
98 selection type with a scrap flavor type via `mac-ostype'. */
99static Lisp_Object Qmac_scrap_name, Qmac_ostype;
100
101/* Selection name for communication via Services menu. */
102static Lisp_Object Vmac_services_selection;
103
104/* Get a reference to the scrap corresponding to the symbol SYM. The
105 reference is set to *SCRAP, and it becomes NULL if there's no
106 corresponding scrap. Clear the scrap if CLEAR_P is non-zero. */
107
108static OSErr
109get_scrap_from_symbol (sym, clear_p, scrap)
110 Lisp_Object sym;
111 int clear_p;
112 ScrapRef *scrap;
113{
114 OSErr err = noErr;
115 Lisp_Object str = Fget (sym, Qmac_scrap_name);
116
117 if (!STRINGP (str))
118 *scrap = NULL;
119 else
120 {
121#if TARGET_API_MAC_CARBON
122#ifdef MAC_OSX
123 CFStringRef scrap_name = cfstring_create_with_string (str);
124 OptionBits options = (clear_p ? kScrapClearNamedScrap
125 : kScrapGetNamedScrap);
126
127 err = GetScrapByName (scrap_name, options, scrap);
128 CFRelease (scrap_name);
129#else /* !MAC_OSX */
130 if (clear_p)
131 err = ClearCurrentScrap ();
132 if (err == noErr)
133 err = GetCurrentScrap (scrap);
134#endif /* !MAC_OSX */
135#else /* !TARGET_API_MAC_CARBON */
136 if (clear_p)
137 err = ZeroScrap ();
138 if (err == noErr)
139 *scrap = 1;
140#endif /* !TARGET_API_MAC_CARBON */
141 }
142
143 return err;
144}
145
146/* Get a scrap flavor type from the symbol SYM. Return 0 if no
147 corresponding flavor type. */
148
149static ScrapFlavorType
150get_flavor_type_from_symbol (sym)
151 Lisp_Object sym;
152{
153 ScrapFlavorType val;
154 Lisp_Object str = Fget (sym, Qmac_ostype);
155
156 if (STRINGP (str) && SBYTES (str) == 4)
157 return EndianU32_BtoN (*((UInt32 *) SDATA (str)));
158
159 return 0;
160}
161
162/* Check if the symbol SYM has a corresponding scrap flavor type. */
163
164static int
165valid_scrap_target_type_p (sym)
166 Lisp_Object sym;
167{
168 return get_flavor_type_from_symbol (sym) != 0;
169}
170
171/* Clear the scrap whose reference is *SCRAP. */
172
173static INLINE OSErr
174clear_scrap (scrap)
175 ScrapRef *scrap;
176{
177#if TARGET_API_MAC_CARBON
178#ifdef MAC_OSX
179 return ClearScrap (scrap);
180#else
181 return ClearCurrentScrap ();
182#endif
183#else /* !TARGET_API_MAC_CARBON */
184 return ZeroScrap ();
185#endif /* !TARGET_API_MAC_CARBON */
186}
187
188/* Put Lisp String STR to the scrap SCRAP. The target type is
189 specified by TYPE. */
190
191static OSErr
192put_scrap_string (scrap, type, str)
193 ScrapRef scrap;
194 Lisp_Object type, str;
195{
196 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (type);
197
198 if (flavor_type == 0)
199 return noTypeErr;
200
201#if TARGET_API_MAC_CARBON
202 return PutScrapFlavor (scrap, flavor_type, kScrapFlavorMaskNone,
203 SBYTES (str), SDATA (str));
204#else /* !TARGET_API_MAC_CARBON */
205 return PutScrap (SBYTES (str), flavor_type, SDATA (str));
206#endif /* !TARGET_API_MAC_CARBON */
207}
208
209/* Put TIMESTAMP to the scrap SCRAP. The timestamp is used for
210 checking if the scrap is owned by the process. */
211
212static INLINE OSErr
213put_scrap_private_timestamp (scrap, timestamp)
214 ScrapRef scrap;
215 unsigned long timestamp;
216{
217#if TARGET_API_MAC_CARBON
218 return PutScrapFlavor (scrap, SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP,
219 kScrapFlavorMaskSenderOnly,
220 sizeof (timestamp), &timestamp);
221#else /* !TARGET_API_MAC_CARBON */
222 return PutScrap (sizeof (timestamp), SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP,
223 &timestamp);
224#endif /* !TARGET_API_MAC_CARBON */
225}
226
227/* Check if data for the target type TYPE is available in SCRAP. */
228
229static ScrapFlavorType
230scrap_has_target_type (scrap, type)
231 ScrapRef scrap;
232 Lisp_Object type;
233{
234 OSErr err;
235 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (type);
236
237 if (flavor_type)
238 {
239#if TARGET_API_MAC_CARBON
240 ScrapFlavorFlags flags;
241
242 err = GetScrapFlavorFlags (scrap, flavor_type, &flags);
243 if (err != noErr)
244 flavor_type = 0;
245#else /* !TARGET_API_MAC_CARBON */
246 SInt32 size, offset;
247
248 size = GetScrap (NULL, flavor_type, &offset);
249 if (size < 0)
250 flavor_type = 0;
251#endif /* !TARGET_API_MAC_CARBON */
252 }
253
254 return flavor_type;
255}
256
257/* Get data for the target type TYPE from SCRAP and create a Lisp
258 string. Return nil if failed to get data. */
259
260static Lisp_Object
261get_scrap_string (scrap, type)
262 ScrapRef scrap;
263 Lisp_Object type;
264{
265 OSErr err;
266 Lisp_Object result = Qnil;
267 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (type);
268#if TARGET_API_MAC_CARBON
269 Size size;
270
271 if (flavor_type)
272 {
273 err = GetScrapFlavorSize (scrap, flavor_type, &size);
274 if (err == noErr)
275 {
276 do
277 {
278 result = make_uninit_string (size);
279 err = GetScrapFlavorData (scrap, flavor_type,
280 &size, SDATA (result));
281 if (err != noErr)
282 result = Qnil;
283 else if (size < SBYTES (result))
284 result = make_unibyte_string (SDATA (result), size);
285 }
286 while (STRINGP (result) && size > SBYTES (result));
287 }
288 }
289#else
290 Handle handle;
291 SInt32 size, offset;
292
293 if (flavor_type)
294 size = GetScrap (NULL, flavor_type, &offset);
295 if (size >= 0)
296 {
297 handle = NewHandle (size);
298 HLock (handle);
299 size = GetScrap (handle, flavor_type, &offset);
300 if (size >= 0)
301 result = make_unibyte_string (*handle, size);
302 DisposeHandle (handle);
303 }
304#endif
305
306 return result;
307}
308
309/* Get timestamp from the scrap SCRAP and set to *TIMPSTAMP. */
310
311static OSErr
312get_scrap_private_timestamp (scrap, timestamp)
313 ScrapRef scrap;
314 unsigned long *timestamp;
315{
316 OSErr err = noErr;
317#if TARGET_API_MAC_CARBON
318 ScrapFlavorFlags flags;
319
320 err = GetScrapFlavorFlags (scrap, SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP, &flags);
321 if (err == noErr)
322 if (!(flags & kScrapFlavorMaskSenderOnly))
323 err = noTypeErr;
324 else
325 {
326 Size size = sizeof (*timestamp);
327
328 err = GetScrapFlavorData (scrap, SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP,
329 &size, timestamp);
330 if (err == noErr && size != sizeof (*timestamp))
331 err = noTypeErr;
332 }
333#else /* !TARGET_API_MAC_CARBON */
334 Handle handle;
335 SInt32 size, offset;
336
337 size = GetScrap (NULL, SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP, &offset);
338 if (size == sizeof (*timestamp))
339 {
340 handle = NewHandle (size);
341 HLock (handle);
342 size = GetScrap (handle, SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP, &offset);
343 if (size == sizeof (*timestamp))
344 *timestamp = *((unsigned long *) *handle);
345 DisposeHandle (handle);
346 }
347 if (size != sizeof (*timestamp))
348 err = noTypeErr;
349#endif /* !TARGET_API_MAC_CARBON */
350
351 return err;
352}
353
354/* Get the list of target types in SCRAP. The return value is a list
355 of target type symbols possibly followed by scrap flavor type
356 strings. */
357
358static Lisp_Object
359get_scrap_target_type_list (scrap)
360 ScrapRef scrap;
361{
362 Lisp_Object result = Qnil, rest, target_type;
363#if TARGET_API_MAC_CARBON
364 OSErr err;
365 UInt32 count, i, type;
366 ScrapFlavorInfo *flavor_info = NULL;
367 Lisp_Object strings = Qnil;
368
369 err = GetScrapFlavorCount (scrap, &count);
370 if (err == noErr)
371 flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
372 if (err == noErr && flavor_info)
373 {
374 err = GetScrapFlavorInfoList (scrap, &count, flavor_info);
375 if (err != noErr)
376 {
377 xfree (flavor_info);
378 flavor_info = NULL;
379 }
380 }
381#endif
382 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
383 {
384 ScrapFlavorType flavor_type = 0;
385
386 if (CONSP (XCAR (rest)) && SYMBOLP (target_type = XCAR (XCAR (rest)))
387 && (flavor_type = scrap_has_target_type (scrap, target_type)))
388 {
389 result = Fcons (target_type, result);
390#if TARGET_API_MAC_CARBON
391 for (i = 0; i < count; i++)
392 if (flavor_info[i].flavorType == flavor_type)
393 {
394 flavor_info[i].flavorType = 0;
395 break;
396 }
397#endif
398 }
399 }
400#if TARGET_API_MAC_CARBON
401 if (flavor_info)
402 {
403 for (i = 0; i < count; i++)
404 if (flavor_info[i].flavorType)
405 {
406 type = EndianU32_NtoB (flavor_info[i].flavorType);
407 strings = Fcons (make_unibyte_string ((char *) &type, 4), strings);
408 }
409 result = nconc2 (result, strings);
410 xfree (flavor_info);
411 }
412#endif
413
414 return result;
415}
416
417/* Do protocol to assert ourself as a selection owner.
418 Update the Vselection_alist so that we can reply to later requests for
419 our selection. */
420
421static void
422x_own_selection (selection_name, selection_value)
423 Lisp_Object selection_name, selection_value;
424{
425 OSErr err;
426 ScrapRef scrap;
427 struct gcpro gcpro1, gcpro2;
428 Lisp_Object rest, handler_fn, value, type;
429 int count;
430
431 CHECK_SYMBOL (selection_name);
432
433 GCPRO2 (selection_name, selection_value);
434
435 BLOCK_INPUT;
436
437 err = get_scrap_from_symbol (selection_name, 1, &scrap);
438 if (err == noErr && scrap)
439 {
440 /* Don't allow a quit within the converter.
441 When the user types C-g, he would be surprised
442 if by luck it came during a converter. */
443 count = SPECPDL_INDEX ();
444 specbind (Qinhibit_quit, Qt);
445
446 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
447 {
448 if (!(CONSP (XCAR (rest))
449 && SYMBOLP (type = XCAR (XCAR (rest)))
450 && valid_scrap_target_type_p (type)
451 && SYMBOLP (handler_fn = XCDR (XCAR (rest)))))
452 continue;
453
454 if (!NILP (handler_fn))
455 value = call3 (handler_fn, selection_name,
456 type, selection_value);
457
458 if (CONSP (value)
459 && EQ (XCAR (value), type)
460 && STRINGP (XCDR (value)))
461 err = put_scrap_string (scrap, type, XCDR (value));
462 }
463
464 unbind_to (count, Qnil);
465
466 if (err == noErr)
467 err = put_scrap_private_timestamp (scrap, last_event_timestamp);
468 }
469
470 UNBLOCK_INPUT;
471
472 UNGCPRO;
473
474 if (scrap && err != noErr)
475 error ("Can't set selection");
476
477 /* Now update the local cache */
478 {
479 Lisp_Object selection_time;
480 Lisp_Object selection_data;
481 Lisp_Object prev_value;
482
483 selection_time = long_to_cons (last_event_timestamp);
484 selection_data = Fcons (selection_name,
485 Fcons (selection_value,
486 Fcons (selection_time,
487 Fcons (selected_frame, Qnil))));
488 prev_value = assq_no_quit (selection_name, Vselection_alist);
489
490 Vselection_alist = Fcons (selection_data, Vselection_alist);
491
492 /* If we already owned the selection, remove the old selection data.
493 Perhaps we should destructively modify it instead.
494 Don't use Fdelq as that may QUIT. */
495 if (!NILP (prev_value))
496 {
497 Lisp_Object rest; /* we know it's not the CAR, so it's easy. */
498 for (rest = Vselection_alist; !NILP (rest); rest = Fcdr (rest))
499 if (EQ (prev_value, Fcar (XCDR (rest))))
500 {
501 XSETCDR (rest, Fcdr (XCDR (rest)));
502 break;
503 }
504 }
505 }
506}
507
508/* Given a selection-name and desired type, look up our local copy of
509 the selection value and convert it to the type.
510 The value is nil or a string.
511 This function is used both for remote requests (LOCAL_REQUEST is zero)
512 and for local x-get-selection-internal (LOCAL_REQUEST is nonzero).
513
514 This calls random Lisp code, and may signal or gc. */
515
516static Lisp_Object
517x_get_local_selection (selection_symbol, target_type, local_request)
518 Lisp_Object selection_symbol, target_type;
519 int local_request;
520{
521 Lisp_Object local_value;
522 Lisp_Object handler_fn, value, type, check;
523 int count;
524
525 if (NILP (Fx_selection_owner_p (selection_symbol)))
526 return Qnil;
527
528 local_value = assq_no_quit (selection_symbol, Vselection_alist);
529
530 /* TIMESTAMP is a special case 'cause that's easiest. */
531 if (EQ (target_type, QTIMESTAMP))
532 {
533 handler_fn = Qnil;
534 value = XCAR (XCDR (XCDR (local_value)));
535 }
536#if 0
537 else if (EQ (target_type, QDELETE))
538 {
539 handler_fn = Qnil;
540 Fx_disown_selection_internal
541 (selection_symbol,
542 XCAR (XCDR (XCDR (local_value))));
543 value = QNULL;
544 }
545#endif
546 else
547 {
548 /* Don't allow a quit within the converter.
549 When the user types C-g, he would be surprised
550 if by luck it came during a converter. */
551 count = SPECPDL_INDEX ();
552 specbind (Qinhibit_quit, Qt);
553
554 CHECK_SYMBOL (target_type);
555 handler_fn = Fcdr (Fassq (target_type, Vselection_converter_alist));
556 /* gcpro is not needed here since nothing but HANDLER_FN
557 is live, and that ought to be a symbol. */
558
559 if (!NILP (handler_fn))
560 value = call3 (handler_fn,
561 selection_symbol, (local_request ? Qnil : target_type),
562 XCAR (XCDR (local_value)));
563 else
564 value = Qnil;
565 unbind_to (count, Qnil);
566 }
567
568 /* Make sure this value is of a type that we could transmit
569 to another X client. */
570
571 check = value;
572 if (CONSP (value)
573 && SYMBOLP (XCAR (value)))
574 type = XCAR (value),
575 check = XCDR (value);
576
577 if (STRINGP (check)
578 || VECTORP (check)
579 || SYMBOLP (check)
580 || INTEGERP (check)
581 || NILP (value))
582 return value;
583 /* Check for a value that cons_to_long could handle. */
584 else if (CONSP (check)
585 && INTEGERP (XCAR (check))
586 && (INTEGERP (XCDR (check))
587 ||
588 (CONSP (XCDR (check))
589 && INTEGERP (XCAR (XCDR (check)))
590 && NILP (XCDR (XCDR (check))))))
591 return value;
592 else
593 return
594 Fsignal (Qerror,
595 Fcons (build_string ("invalid data returned by selection-conversion function"),
596 Fcons (handler_fn, Fcons (value, Qnil))));
597}
598
599
600/* Clear all selections that were made from frame F.
601 We do this when about to delete a frame. */
602
603void
604x_clear_frame_selections (f)
605 FRAME_PTR f;
606{
607 Lisp_Object frame;
608 Lisp_Object rest;
609
610 XSETFRAME (frame, f);
611
612 /* Otherwise, we're really honest and truly being told to drop it.
613 Don't use Fdelq as that may QUIT;. */
614
615 /* Delete elements from the beginning of Vselection_alist. */
616 while (!NILP (Vselection_alist)
617 && EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (Vselection_alist)))))))
618 {
619 /* Let random Lisp code notice that the selection has been stolen. */
620 Lisp_Object hooks, selection_symbol;
621
622 hooks = Vx_lost_selection_functions;
623 selection_symbol = Fcar (Fcar (Vselection_alist));
624
625 if (!EQ (hooks, Qunbound))
626 {
627 for (; CONSP (hooks); hooks = Fcdr (hooks))
628 call1 (Fcar (hooks), selection_symbol);
629#if 0 /* This can crash when deleting a frame
630 from x_connection_closed. Anyway, it seems unnecessary;
631 something else should cause a redisplay. */
632 redisplay_preserve_echo_area (21);
633#endif
634 }
635
636 Vselection_alist = Fcdr (Vselection_alist);
637 }
638
639 /* Delete elements after the beginning of Vselection_alist. */
640 for (rest = Vselection_alist; !NILP (rest); rest = Fcdr (rest))
641 if (EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (XCDR (rest))))))))
642 {
643 /* Let random Lisp code notice that the selection has been stolen. */
644 Lisp_Object hooks, selection_symbol;
645
646 hooks = Vx_lost_selection_functions;
647 selection_symbol = Fcar (Fcar (XCDR (rest)));
648
649 if (!EQ (hooks, Qunbound))
650 {
651 for (; CONSP (hooks); hooks = Fcdr (hooks))
652 call1 (Fcar (hooks), selection_symbol);
653#if 0 /* See above */
654 redisplay_preserve_echo_area (22);
655#endif
656 }
657 XSETCDR (rest, Fcdr (XCDR (rest)));
658 break;
659 }
660}
661
662/* Do protocol to read selection-data from the server.
663 Converts this to Lisp data and returns it. */
664
665static Lisp_Object
666x_get_foreign_selection (selection_symbol, target_type, time_stamp)
667 Lisp_Object selection_symbol, target_type, time_stamp;
668{
669 OSErr err;
670 ScrapRef scrap;
671 Lisp_Object result = Qnil;
672
673 BLOCK_INPUT;
674
675 err = get_scrap_from_symbol (selection_symbol, 0, &scrap);
676 if (err == noErr && scrap)
677 if (EQ (target_type, QTARGETS))
678 {
679 result = get_scrap_target_type_list (scrap);
680 result = Fvconcat (1, &result);
681 }
682 else
683 {
684 result = get_scrap_string (scrap, target_type);
685 if (STRINGP (result))
686 Fput_text_property (make_number (0), make_number (SBYTES (result)),
687 Qforeign_selection, target_type, result);
688 }
689
690 UNBLOCK_INPUT;
691
692 return result;
693}
694
695
696DEFUN ("x-own-selection-internal", Fx_own_selection_internal,
697 Sx_own_selection_internal, 2, 2, 0,
698 doc: /* Assert a selection of the given TYPE with the given VALUE.
699TYPE is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
700VALUE is typically a string, or a cons of two markers, but may be
701anything that the functions on `selection-converter-alist' know about. */)
702 (selection_name, selection_value)
703 Lisp_Object selection_name, selection_value;
704{
705 check_mac ();
706 CHECK_SYMBOL (selection_name);
707 if (NILP (selection_value)) error ("selection-value may not be nil");
708 x_own_selection (selection_name, selection_value);
709 return selection_value;
710}
711
712
713/* Request the selection value from the owner. If we are the owner,
714 simply return our selection value. If we are not the owner, this
715 will block until all of the data has arrived. */
716
717DEFUN ("x-get-selection-internal", Fx_get_selection_internal,
718 Sx_get_selection_internal, 2, 3, 0,
719 doc: /* Return text selected from some Mac window.
720SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
721TYPE is the type of data desired, typically `STRING'.
722TIME_STAMP is ignored on Mac. */)
723 (selection_symbol, target_type, time_stamp)
724 Lisp_Object selection_symbol, target_type, time_stamp;
725{
726 Lisp_Object val = Qnil;
727 struct gcpro gcpro1, gcpro2;
728 GCPRO2 (target_type, val); /* we store newly consed data into these */
729 check_mac ();
730 CHECK_SYMBOL (selection_symbol);
731 CHECK_SYMBOL (target_type);
732
733 val = x_get_local_selection (selection_symbol, target_type, 1);
734
735 if (NILP (val))
736 {
737 val = x_get_foreign_selection (selection_symbol, target_type, time_stamp);
738 goto DONE;
739 }
740
741 if (CONSP (val)
742 && SYMBOLP (XCAR (val)))
743 {
744 val = XCDR (val);
745 if (CONSP (val) && NILP (XCDR (val)))
746 val = XCAR (val);
747 }
748 DONE:
749 UNGCPRO;
750 return val;
751}
752
753DEFUN ("x-disown-selection-internal", Fx_disown_selection_internal,
754 Sx_disown_selection_internal, 1, 2, 0,
755 doc: /* If we own the selection SELECTION, disown it.
756Disowning it means there is no such selection. */)
757 (selection, time)
758 Lisp_Object selection;
759 Lisp_Object time;
760{
761 OSErr err;
762 ScrapRef scrap;
763 Lisp_Object local_selection_data;
764
765 check_mac ();
766 CHECK_SYMBOL (selection);
767
768 if (NILP (Fx_selection_owner_p (selection)))
769 return Qnil; /* Don't disown the selection when we're not the owner. */
770
771 local_selection_data = assq_no_quit (selection, Vselection_alist);
772
773 /* Don't use Fdelq as that may QUIT;. */
774
775 if (EQ (local_selection_data, Fcar (Vselection_alist)))
776 Vselection_alist = Fcdr (Vselection_alist);
777 else
778 {
779 Lisp_Object rest;
780 for (rest = Vselection_alist; !NILP (rest); rest = Fcdr (rest))
781 if (EQ (local_selection_data, Fcar (XCDR (rest))))
782 {
783 XSETCDR (rest, Fcdr (XCDR (rest)));
784 break;
785 }
786 }
787
788 /* Let random lisp code notice that the selection has been stolen. */
789
790 {
791 Lisp_Object rest;
792 rest = Vx_lost_selection_functions;
793 if (!EQ (rest, Qunbound))
794 {
795 for (; CONSP (rest); rest = Fcdr (rest))
796 call1 (Fcar (rest), selection);
797 prepare_menu_bars ();
798 redisplay_preserve_echo_area (20);
799 }
800 }
801
802 BLOCK_INPUT;
803
804 err = get_scrap_from_symbol (selection, 0, &scrap);
805 if (err == noErr && scrap)
806 clear_scrap (&scrap);
807
808 UNBLOCK_INPUT;
809
810 return Qt;
811}
812
813
814DEFUN ("x-selection-owner-p", Fx_selection_owner_p, Sx_selection_owner_p,
815 0, 1, 0,
816 doc: /* Whether the current Emacs process owns the given Selection.
817The arg should be the name of the selection in question, typically one of
818the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
819For convenience, the symbol nil is the same as `PRIMARY',
820and t is the same as `SECONDARY'. */)
821 (selection)
822 Lisp_Object selection;
823{
824 OSErr err;
825 ScrapRef scrap;
826 Lisp_Object result = Qnil, local_selection_data;
827
828 check_mac ();
829 CHECK_SYMBOL (selection);
830 if (EQ (selection, Qnil)) selection = QPRIMARY;
831 if (EQ (selection, Qt)) selection = QSECONDARY;
832
833 local_selection_data = assq_no_quit (selection, Vselection_alist);
834
835 if (NILP (local_selection_data))
836 return Qnil;
837
838 BLOCK_INPUT;
839
840 err = get_scrap_from_symbol (selection, 0, &scrap);
841 if (err == noErr && scrap)
842 {
843 unsigned long timestamp;
844
845 err = get_scrap_private_timestamp (scrap, &timestamp);
846 if (err == noErr
847 && (timestamp
848 == cons_to_long (XCAR (XCDR (XCDR (local_selection_data))))))
849 result = Qt;
850 }
851 else
852 result = Qt;
853
854 UNBLOCK_INPUT;
855
856 return result;
857}
858
859DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
860 0, 1, 0,
861 doc: /* Whether there is an owner for the given Selection.
862The arg should be the name of the selection in question, typically one of
863the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
864For convenience, the symbol nil is the same as `PRIMARY',
865and t is the same as `SECONDARY'. */)
866 (selection)
867 Lisp_Object selection;
868{
869 OSErr err;
870 ScrapRef scrap;
871 Lisp_Object result = Qnil, rest;
872
873 /* It should be safe to call this before we have an Mac frame. */
874 if (! FRAME_MAC_P (SELECTED_FRAME ()))
875 return Qnil;
876
877 CHECK_SYMBOL (selection);
878 if (!NILP (Fx_selection_owner_p (selection)))
879 return Qt;
880 if (EQ (selection, Qnil)) selection = QPRIMARY;
881 if (EQ (selection, Qt)) selection = QSECONDARY;
882
883 BLOCK_INPUT;
884
885 err = get_scrap_from_symbol (selection, 0, &scrap);
886 if (err == noErr && scrap)
887 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
888 {
889 if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
890 && scrap_has_target_type (scrap, XCAR (XCAR (rest))))
891 {
892 result = Qt;
893 break;
894 }
895 }
896
897 UNBLOCK_INPUT;
898
899 return result;
900}
901
902
903#ifdef MAC_OSX
904void
905init_service_handler ()
906{
907 EventTypeSpec specs[] = {{kEventClassService, kEventServiceGetTypes},
908 {kEventClassService, kEventServiceCopy},
909 {kEventClassService, kEventServicePaste},
910 {kEventClassService, kEventServicePerform}};
911 InstallApplicationEventHandler (NewEventHandlerUPP (mac_handle_service_event),
912 GetEventTypeCount (specs), specs, NULL, NULL);
913}
914
915extern void mac_store_services_event P_ ((EventRef));
916
917static OSStatus
918mac_handle_service_event (call_ref, event, data)
919 EventHandlerCallRef call_ref;
920 EventRef event;
921 void *data;
922{
923 OSStatus err = noErr;
924 ScrapRef cur_scrap;
925
926 /* Check if Vmac_services_selection is a valid selection that has a
927 corresponding scrap. */
928 if (!SYMBOLP (Vmac_services_selection))
929 err = eventNotHandledErr;
930 else
931 err = get_scrap_from_symbol (Vmac_services_selection, 0, &cur_scrap);
932 if (!(err == noErr && cur_scrap))
933 return eventNotHandledErr;
934
935 switch (GetEventKind (event))
936 {
937 case kEventServiceGetTypes:
938 {
939 CFMutableArrayRef copy_types, paste_types;
940 CFStringRef type;
941 Lisp_Object rest;
942 ScrapFlavorType flavor_type;
943
944 /* Set paste types. */
945 err = GetEventParameter (event, kEventParamServicePasteTypes,
946 typeCFMutableArrayRef, NULL,
947 sizeof (CFMutableArrayRef), NULL,
948 &paste_types);
949 if (err == noErr)
950 for (rest = Vselection_converter_alist; CONSP (rest);
951 rest = XCDR (rest))
952 if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
953 && (flavor_type =
954 get_flavor_type_from_symbol (XCAR (XCAR (rest)))))
955 {
956 type = CreateTypeStringWithOSType (flavor_type);
957 if (type)
958 {
959 CFArrayAppendValue (paste_types, type);
960 CFRelease (type);
961 }
962 }
963
964 /* Set copy types. */
965 err = GetEventParameter (event, kEventParamServiceCopyTypes,
966 typeCFMutableArrayRef, NULL,
967 sizeof (CFMutableArrayRef), NULL,
968 &copy_types);
969 if (err == noErr
970 && !NILP (Fx_selection_owner_p (Vmac_services_selection)))
971 for (rest = get_scrap_target_type_list (cur_scrap);
972 CONSP (rest) && SYMBOLP (XCAR (rest)); rest = XCDR (rest))
973 {
974 flavor_type = get_flavor_type_from_symbol (XCAR (rest));
975 if (flavor_type)
976 {
977 type = CreateTypeStringWithOSType (flavor_type);
978 if (type)
979 {
980 CFArrayAppendValue (copy_types, type);
981 CFRelease (type);
982 }
983 }
984 }
985 }
986 break;
987
988 case kEventServiceCopy:
989 {
990 ScrapRef specific_scrap;
991 Lisp_Object rest, data;
992
993 err = GetEventParameter (event, kEventParamScrapRef,
994 typeScrapRef, NULL,
995 sizeof (ScrapRef), NULL, &specific_scrap);
996 if (err == noErr
997 && !NILP (Fx_selection_owner_p (Vmac_services_selection)))
998 for (rest = get_scrap_target_type_list (cur_scrap);
999 CONSP (rest) && SYMBOLP (XCAR (rest)); rest = XCDR (rest))
1000 {
1001 data = get_scrap_string (cur_scrap, XCAR (rest));
1002 if (STRINGP (data))
1003 err = put_scrap_string (specific_scrap, XCAR (rest), data);
1004 }
1005 else
1006 err = eventNotHandledErr;
1007 }
1008 break;
1009
1010 case kEventServicePaste:
1011 case kEventServicePerform:
1012 {
1013 ScrapRef specific_scrap;
1014 Lisp_Object rest, data;
1015 int data_exists_p = 0;
1016
1017 err = GetEventParameter (event, kEventParamScrapRef, typeScrapRef,
1018 NULL, sizeof (ScrapRef), NULL,
1019 &specific_scrap);
1020 if (err == noErr)
1021 err = clear_scrap (&cur_scrap);
1022 if (err == noErr)
1023 for (rest = Vselection_converter_alist; CONSP (rest);
1024 rest = XCDR (rest))
1025 {
1026 if (! (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))))
1027 continue;
1028 data = get_scrap_string (specific_scrap, XCAR (XCAR (rest)));
1029 if (STRINGP (data))
1030 {
1031 err = put_scrap_string (cur_scrap, XCAR (XCAR (rest)),
1032 data);
1033 if (err != noErr)
1034 break;
1035 data_exists_p = 1;
1036 }
1037 }
1038 if (err == noErr)
1039 if (data_exists_p)
1040 mac_store_application_menu_event (event);
1041 else
1042 err = eventNotHandledErr;
1043 }
1044 break;
1045 }
1046
1047 return err;
1048}
1049#endif
1050
1051
1052void
1053syms_of_macselect ()
1054{
1055 defsubr (&Sx_get_selection_internal);
1056 defsubr (&Sx_own_selection_internal);
1057 defsubr (&Sx_disown_selection_internal);
1058 defsubr (&Sx_selection_owner_p);
1059 defsubr (&Sx_selection_exists_p);
1060
1061 Vselection_alist = Qnil;
1062 staticpro (&Vselection_alist);
1063
1064 DEFVAR_LISP ("selection-converter-alist", &Vselection_converter_alist,
1065 doc: /* An alist associating selection-types with functions.
1066These functions are called to convert the selection, with three args:
1067the name of the selection (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');
1068a desired type to which the selection should be converted;
1069and the local selection value (whatever was given to `x-own-selection').
1070
1071The function should return the value to send to the Scrap Manager
1072\(a string). A return value of nil
1073means that the conversion could not be done.
1074A return value which is the symbol `NULL'
1075means that a side-effect was executed,
1076and there is no meaningful selection value. */);
1077 Vselection_converter_alist = Qnil;
1078
1079 DEFVAR_LISP ("x-lost-selection-functions", &Vx_lost_selection_functions,
1080 doc: /* A list of functions to be called when Emacs loses a selection.
1081\(This happens when a Lisp program explicitly clears the selection.)
1082The functions are called with one argument, the selection type
1083\(a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'). */);
1084 Vx_lost_selection_functions = Qnil;
1085
1086 DEFVAR_LISP ("selection-coding-system", &Vselection_coding_system,
1087 doc: /* Coding system for communicating with other programs.
1088When sending or receiving text via cut_buffer, selection, and clipboard,
1089the text is encoded or decoded by this coding system.
1090The default value is determined by the system script code. */);
1091 Vselection_coding_system = Qnil;
1092
1093 DEFVAR_LISP ("next-selection-coding-system", &Vnext_selection_coding_system,
1094 doc: /* Coding system for the next communication with other programs.
1095Usually, `selection-coding-system' is used for communicating with
1096other programs. But, if this variable is set, it is used for the
1097next communication only. After the communication, this variable is
1098set to nil. */);
1099 Vnext_selection_coding_system = Qnil;
1100
1101 DEFVAR_LISP ("mac-services-selection", &Vmac_services_selection,
1102 doc: /* Selection name for communication via Services menu. */);
1103 Vmac_services_selection = intern ("CLIPBOARD");
1104
1105 QPRIMARY = intern ("PRIMARY"); staticpro (&QPRIMARY);
1106 QSECONDARY = intern ("SECONDARY"); staticpro (&QSECONDARY);
1107 QTIMESTAMP = intern ("TIMESTAMP"); staticpro (&QTIMESTAMP);
1108 QTARGETS = intern ("TARGETS"); staticpro (&QTARGETS);
1109
1110 Qforeign_selection = intern ("foreign-selection");
1111 staticpro (&Qforeign_selection);
1112
1113 Qmac_scrap_name = intern ("mac-scrap-name");
1114 staticpro (&Qmac_scrap_name);
1115
1116 Qmac_ostype = intern ("mac-ostype");
1117 staticpro (&Qmac_ostype);
1118}