comparison src/mac.c @ 90127:30ad2795fdab

Revision: miles@gnu.org--gnu-2005/emacs--unicode--0--patch-28 Merge from emacs--cvs-trunk--0 Patches applied: * emacs--cvs-trunk--0 (patch 180-191) - Update from CVS - Merge from gnus--rel--5.10 * gnus--rel--5.10 (patch 39-44) - Merge from emacs--cvs-trunk--0 - Update from CVS
author Miles Bader <miles@gnu.org>
date Sat, 19 Mar 2005 02:42:17 +0000
parents 29e773288013 40fe172d199c
children 02f1dbc4a199
comparison
equal deleted inserted replaced
90126:8ee106ee2dc8 90127:30ad2795fdab
24 24
25 #include <stdio.h> 25 #include <stdio.h>
26 #include <errno.h> 26 #include <errno.h>
27 #include <time.h> 27 #include <time.h>
28 28
29 #ifdef HAVE_CARBON 29 #include "lisp.h"
30 #ifdef MAC_OSX 30 #include "process.h"
31 #undef mktime 31 #include "sysselect.h"
32 #undef DEBUG 32 #include "systime.h"
33 #undef free 33 #include "blockinput.h"
34 #undef malloc 34
35 #undef realloc 35 #include "macterm.h"
36 #undef init_process 36
37 #include <Carbon/Carbon.h> 37 #ifndef HAVE_CARBON
38 #undef mktime
39 #define mktime emacs_mktime
40 #undef free
41 #define free unexec_free
42 #undef malloc
43 #define malloc unexec_malloc
44 #undef realloc
45 #define realloc unexec_realloc
46 #undef init_process
47 #define init_process emacs_init_process
48 #else /* not MAC_OSX */
49 #undef SIGHUP
50 #define OLDP2C 1
51 #include <Carbon.h>
52 #endif /* not MAC_OSX */
53 #else /* not HAVE_CARBON */
54 #include <Files.h> 38 #include <Files.h>
55 #include <MacTypes.h> 39 #include <MacTypes.h>
56 #include <TextUtils.h> 40 #include <TextUtils.h>
57 #include <Folders.h> 41 #include <Folders.h>
58 #include <Resources.h> 42 #include <Resources.h>
78 #include <stdlib.h> 62 #include <stdlib.h>
79 #include <fcntl.h> 63 #include <fcntl.h>
80 #if __MWERKS__ 64 #if __MWERKS__
81 #include <unistd.h> 65 #include <unistd.h>
82 #endif 66 #endif
83
84 #include "lisp.h"
85 #include "process.h"
86 #include "sysselect.h"
87 #include "systime.h"
88 #include "blockinput.h"
89 67
90 Lisp_Object QCLIPBOARD; 68 Lisp_Object QCLIPBOARD;
91 69
92 /* An instance of the AppleScript component. */ 70 /* An instance of the AppleScript component. */
93 static ComponentInstance as_scripting_component; 71 static ComponentInstance as_scripting_component;
270 } 248 }
271 249
272 return 1; 250 return 1;
273 } 251 }
274 252
253
254 /***********************************************************************
255 Conversion between Lisp and Core Foundation objects
256 ***********************************************************************/
257
275 #if TARGET_API_MAC_CARBON 258 #if TARGET_API_MAC_CARBON
259 static Lisp_Object Qstring, Qnumber, Qboolean, Qdate, Qdata;
260 static Lisp_Object Qarray, Qdictionary;
261 extern Lisp_Object Qutf_8;
262 #define DECODE_UTF_8(str) code_convert_string_norecord (str, Qutf_8, 0)
263
264 struct cfdict_context
265 {
266 Lisp_Object *result;
267 int with_tag, hash_bound;
268 };
269
270 /* C string to CFString. */
271
276 CFStringRef 272 CFStringRef
277 cfstring_create_with_utf8_cstring (c_str) 273 cfstring_create_with_utf8_cstring (c_str)
278 const char *c_str; 274 const char *c_str;
279 { 275 {
280 CFStringRef str; 276 CFStringRef str;
284 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */ 280 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
285 str = CFStringCreateWithCString (NULL, c_str, kCFStringEncodingMacRoman); 281 str = CFStringCreateWithCString (NULL, c_str, kCFStringEncodingMacRoman);
286 282
287 return str; 283 return str;
288 } 284 }
285
286
287 /* From CFData to a lisp string. Always returns a unibyte string. */
288
289 Lisp_Object
290 cfdata_to_lisp (data)
291 CFDataRef data;
292 {
293 CFIndex len = CFDataGetLength (data);
294 Lisp_Object result = make_uninit_string (len);
295
296 CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result));
297
298 return result;
299 }
300
301
302 /* From CFString to a lisp string. Never returns a unibyte string
303 (even if it only contains ASCII characters).
304 This may cause GC during code conversion. */
305
306 Lisp_Object
307 cfstring_to_lisp (string)
308 CFStringRef string;
309 {
310 Lisp_Object result = Qnil;
311 const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8);
312
313 if (s)
314 result = make_unibyte_string (s, strlen (s));
315 else
316 {
317 CFDataRef data =
318 CFStringCreateExternalRepresentation (NULL, string,
319 kCFStringEncodingUTF8, '?');
320
321 if (data)
322 {
323 result = cfdata_to_lisp (data);
324 CFRelease (data);
325 }
326 }
327
328 if (!NILP (result))
329 {
330 result = DECODE_UTF_8 (result);
331 /* This may be superfluous. Just to make sure that the result
332 is a multibyte string. */
333 result = string_to_multibyte (result);
334 }
335
336 return result;
337 }
338
339
340 /* CFNumber to a lisp integer or a lisp float. */
341
342 Lisp_Object
343 cfnumber_to_lisp (number)
344 CFNumberRef number;
345 {
346 Lisp_Object result = Qnil;
347 #if BITS_PER_EMACS_INT > 32
348 SInt64 int_val;
349 CFNumberType emacs_int_type = kCFNumberSInt64Type;
350 #else
351 SInt32 int_val;
352 CFNumberType emacs_int_type = kCFNumberSInt32Type;
289 #endif 353 #endif
290 354 double float_val;
355
356 if (CFNumberGetValue (number, emacs_int_type, &int_val)
357 && !FIXNUM_OVERFLOW_P (int_val))
358 result = make_number (int_val);
359 else
360 if (CFNumberGetValue (number, kCFNumberDoubleType, &float_val))
361 result = make_float (float_val);
362 return result;
363 }
364
365
366 /* CFDate to a list of three integers as in a return value of
367 `current-time'xo. */
368
369 Lisp_Object
370 cfdate_to_lisp (date)
371 CFDateRef date;
372 {
373 static CFGregorianDate epoch_gdate = {1970, 1, 1, 0, 0, 0.0};
374 static CFAbsoluteTime epoch = 0.0, sec;
375 int high, low;
376
377 if (epoch == 0.0)
378 epoch = CFGregorianDateGetAbsoluteTime (epoch_gdate, NULL);
379
380 sec = CFDateGetAbsoluteTime (date) - epoch;
381 high = sec / 65536.0;
382 low = sec - high * 65536.0;
383
384 return list3 (make_number (high), make_number (low), make_number (0));
385 }
386
387
388 /* CFBoolean to a lisp symbol, `t' or `nil'. */
389
390 Lisp_Object
391 cfboolean_to_lisp (boolean)
392 CFBooleanRef boolean;
393 {
394 return CFBooleanGetValue (boolean) ? Qt : Qnil;
395 }
396
397
398 /* Any Core Foundation object to a (lengthy) lisp string. */
399
400 Lisp_Object
401 cfobject_desc_to_lisp (object)
402 CFTypeRef object;
403 {
404 Lisp_Object result = Qnil;
405 CFStringRef desc = CFCopyDescription (object);
406
407 if (desc)
408 {
409 result = cfstring_to_lisp (desc);
410 CFRelease (desc);
411 }
412
413 return result;
414 }
415
416
417 /* Callback functions for cfproperty_list_to_lisp. */
418
419 static void
420 cfdictionary_add_to_list (key, value, context)
421 const void *key;
422 const void *value;
423 void *context;
424 {
425 struct cfdict_context *cxt = (struct cfdict_context *)context;
426
427 *cxt->result =
428 Fcons (Fcons (cfstring_to_lisp (key),
429 cfproperty_list_to_lisp (value, cxt->with_tag,
430 cxt->hash_bound)),
431 *cxt->result);
432 }
433
434 static void
435 cfdictionary_puthash (key, value, context)
436 const void *key;
437 const void *value;
438 void *context;
439 {
440 Lisp_Object lisp_key = cfstring_to_lisp (key);
441 struct cfdict_context *cxt = (struct cfdict_context *)context;
442 struct Lisp_Hash_Table *h = XHASH_TABLE (*(cxt->result));
443 unsigned hash_code;
444
445 hash_lookup (h, lisp_key, &hash_code);
446 hash_put (h, lisp_key,
447 cfproperty_list_to_lisp (value, cxt->with_tag, cxt->hash_bound),
448 hash_code);
449 }
450
451
452 /* Convert CFPropertyList PLIST to a lisp object. If WITH_TAG is
453 non-zero, a symbol that represents the type of the original Core
454 Foundation object is prepended. HASH_BOUND specifies which kinds
455 of the lisp objects, alists or hash tables, are used as the targets
456 of the conversion from CFDictionary. If HASH_BOUND is negative,
457 always generate alists. If HASH_BOUND >= 0, generate an alist if
458 the number of keys in the dictionary is smaller than HASH_BOUND,
459 and a hash table otherwise. */
460
461 Lisp_Object
462 cfproperty_list_to_lisp (plist, with_tag, hash_bound)
463 CFPropertyListRef plist;
464 int with_tag, hash_bound;
465 {
466 CFTypeID type_id = CFGetTypeID (plist);
467 Lisp_Object tag = Qnil, result = Qnil;
468 struct gcpro gcpro1, gcpro2;
469
470 GCPRO2 (tag, result);
471
472 if (type_id == CFStringGetTypeID ())
473 {
474 tag = Qstring;
475 result = cfstring_to_lisp (plist);
476 }
477 else if (type_id == CFNumberGetTypeID ())
478 {
479 tag = Qnumber;
480 result = cfnumber_to_lisp (plist);
481 }
482 else if (type_id == CFBooleanGetTypeID ())
483 {
484 tag = Qboolean;
485 result = cfboolean_to_lisp (plist);
486 }
487 else if (type_id == CFDateGetTypeID ())
488 {
489 tag = Qdate;
490 result = cfdate_to_lisp (plist);
491 }
492 else if (type_id == CFDataGetTypeID ())
493 {
494 tag = Qdata;
495 result = cfdata_to_lisp (plist);
496 }
497 else if (type_id == CFArrayGetTypeID ())
498 {
499 CFIndex index, count = CFArrayGetCount (plist);
500
501 tag = Qarray;
502 result = Fmake_vector (make_number (count), Qnil);
503 for (index = 0; index < count; index++)
504 XVECTOR (result)->contents[index] =
505 cfproperty_list_to_lisp (CFArrayGetValueAtIndex (plist, index),
506 with_tag, hash_bound);
507 }
508 else if (type_id == CFDictionaryGetTypeID ())
509 {
510 struct cfdict_context context;
511 CFIndex count = CFDictionaryGetCount (plist);
512
513 tag = Qdictionary;
514 context.result = &result;
515 context.with_tag = with_tag;
516 context.hash_bound = hash_bound;
517 if (hash_bound < 0 || count < hash_bound)
518 {
519 result = Qnil;
520 CFDictionaryApplyFunction (plist, cfdictionary_add_to_list,
521 &context);
522 }
523 else
524 {
525 result = make_hash_table (Qequal,
526 make_number (count),
527 make_float (DEFAULT_REHASH_SIZE),
528 make_float (DEFAULT_REHASH_THRESHOLD),
529 Qnil, Qnil, Qnil);
530 CFDictionaryApplyFunction (plist, cfdictionary_puthash,
531 &context);
532 }
533 }
534 else
535 abort ();
536
537 UNGCPRO;
538
539 if (with_tag)
540 result = Fcons (tag, result);
541
542 return result;
543 }
544 #endif
545
546
547 /***********************************************************************
548 Emulation of the X Resource Manager
549 ***********************************************************************/
550
551 /* Parser functions for resource lines. Each function takes an
552 address of a variable whose value points to the head of a string.
553 The value will be advanced so that it points to the next character
554 of the parsed part when the function returns.
555
556 A resource name such as "Emacs*font" is parsed into a non-empty
557 list called `quarks'. Each element is either a Lisp string that
558 represents a concrete component, a Lisp symbol LOOSE_BINDING
559 (actually Qlambda) that represents any number (>=0) of intervening
560 components, or a Lisp symbol SINGLE_COMPONENT (actually Qquote)
561 that represents as any single component. */
562
563 #define P (*p)
564
565 #define LOOSE_BINDING Qlambda /* '*' ("L"oose) */
566 #define SINGLE_COMPONENT Qquote /* '?' ("Q"uestion) */
567
568 static void
569 skip_white_space (p)
570 char **p;
571 {
572 /* WhiteSpace = {<space> | <horizontal tab>} */
573 while (*P == ' ' || *P == '\t')
574 P++;
575 }
576
577 static int
578 parse_comment (p)
579 char **p;
580 {
581 /* Comment = "!" {<any character except null or newline>} */
582 if (*P == '!')
583 {
584 P++;
585 while (*P)
586 if (*P++ == '\n')
587 break;
588 return 1;
589 }
590 else
591 return 0;
592 }
593
594 /* Don't interpret filename. Just skip until the newline. */
595 static int
596 parse_include_file (p)
597 char **p;
598 {
599 /* IncludeFile = "#" WhiteSpace "include" WhiteSpace FileName WhiteSpace */
600 if (*P == '#')
601 {
602 P++;
603 while (*P)
604 if (*P++ == '\n')
605 break;
606 return 1;
607 }
608 else
609 return 0;
610 }
611
612 static char
613 parse_binding (p)
614 char **p;
615 {
616 /* Binding = "." | "*" */
617 if (*P == '.' || *P == '*')
618 {
619 char binding = *P++;
620
621 while (*P == '.' || *P == '*')
622 if (*P++ == '*')
623 binding = '*';
624 return binding;
625 }
626 else
627 return '\0';
628 }
629
630 static Lisp_Object
631 parse_component (p)
632 char **p;
633 {
634 /* Component = "?" | ComponentName
635 ComponentName = NameChar {NameChar}
636 NameChar = "a"-"z" | "A"-"Z" | "0"-"9" | "_" | "-" */
637 if (*P == '?')
638 {
639 P++;
640 return SINGLE_COMPONENT;
641 }
642 else if (isalnum (*P) || *P == '_' || *P == '-')
643 {
644 char *start = P++;
645
646 while (isalnum (*P) || *P == '_' || *P == '-')
647 P++;
648
649 return make_unibyte_string (start, P - start);
650 }
651 else
652 return Qnil;
653 }
654
655 static Lisp_Object
656 parse_resource_name (p)
657 char **p;
658 {
659 Lisp_Object result = Qnil, component;
660 char binding;
661
662 /* ResourceName = [Binding] {Component Binding} ComponentName */
663 if (parse_binding (p) == '*')
664 result = Fcons (LOOSE_BINDING, result);
665
666 component = parse_component (p);
667 if (NILP (component))
668 return Qnil;
669
670 result = Fcons (component, result);
671 while (binding = parse_binding (p))
672 {
673 if (binding == '*')
674 result = Fcons (LOOSE_BINDING, result);
675 component = parse_component (p);
676 if (NILP (component))
677 return Qnil;
678 else
679 result = Fcons (component, result);
680 }
681
682 /* The final component should not be '?'. */
683 if (EQ (component, SINGLE_COMPONENT))
684 return Qnil;
685
686 return Fnreverse (result);
687 }
688
689 static Lisp_Object
690 parse_value (p)
691 char **p;
692 {
693 char *q, *buf;
694 Lisp_Object seq = Qnil, result;
695 int buf_len, total_len = 0, len, continue_p;
696
697 q = strchr (P, '\n');
698 buf_len = q ? q - P : strlen (P);
699 buf = xmalloc (buf_len);
700
701 while (1)
702 {
703 q = buf;
704 continue_p = 0;
705 while (*P)
706 {
707 if (*P == '\n')
708 {
709 P++;
710 break;
711 }
712 else if (*P == '\\')
713 {
714 P++;
715 if (*P == '\0')
716 break;
717 else if (*P == '\n')
718 {
719 P++;
720 continue_p = 1;
721 break;
722 }
723 else if (*P == 'n')
724 {
725 *q++ = '\n';
726 P++;
727 }
728 else if ('0' <= P[0] && P[0] <= '7'
729 && '0' <= P[1] && P[1] <= '7'
730 && '0' <= P[2] && P[2] <= '7')
731 {
732 *q++ = (P[0] - '0' << 6) + (P[1] - '0' << 3) + (P[2] - '0');
733 P += 3;
734 }
735 else
736 *q++ = *P++;
737 }
738 else
739 *q++ = *P++;
740 }
741 len = q - buf;
742 seq = Fcons (make_unibyte_string (buf, len), seq);
743 total_len += len;
744
745 if (continue_p)
746 {
747 q = strchr (P, '\n');
748 len = q ? q - P : strlen (P);
749 if (len > buf_len)
750 {
751 xfree (buf);
752 buf_len = len;
753 buf = xmalloc (buf_len);
754 }
755 }
756 else
757 break;
758 }
759 xfree (buf);
760
761 if (SBYTES (XCAR (seq)) == total_len)
762 return make_string (SDATA (XCAR (seq)), total_len);
763 else
764 {
765 buf = xmalloc (total_len);
766 q = buf + total_len;
767 for (; CONSP (seq); seq = XCDR (seq))
768 {
769 len = SBYTES (XCAR (seq));
770 q -= len;
771 memcpy (q, SDATA (XCAR (seq)), len);
772 }
773 result = make_string (buf, total_len);
774 xfree (buf);
775 return result;
776 }
777 }
778
779 static Lisp_Object
780 parse_resource_line (p)
781 char **p;
782 {
783 Lisp_Object quarks, value;
784
785 /* ResourceLine = Comment | IncludeFile | ResourceSpec | <empty line> */
786 if (parse_comment (p) || parse_include_file (p))
787 return Qnil;
788
789 /* ResourceSpec = WhiteSpace ResourceName WhiteSpace ":" WhiteSpace Value */
790 skip_white_space (p);
791 quarks = parse_resource_name (p);
792 if (NILP (quarks))
793 goto cleanup;
794 skip_white_space (p);
795 if (*P != ':')
796 goto cleanup;
797 P++;
798 skip_white_space (p);
799 value = parse_value (p);
800 return Fcons (quarks, value);
801
802 cleanup:
803 /* Skip the remaining data as a dummy value. */
804 parse_value (p);
805 return Qnil;
806 }
807
808 #undef P
809
810 /* Equivalents of X Resource Manager functions.
811
812 An X Resource Database acts as a collection of resource names and
813 associated values. It is implemented as a trie on quarks. Namely,
814 each edge is labeled by either a string, LOOSE_BINDING, or
815 SINGLE_COMPONENT. Each node has a node id, which is a unique
816 nonnegative integer, and the root node id is 0. A database is
817 implemented as a hash table that maps a pair (SRC-NODE-ID .
818 EDGE-LABEL) to DEST-NODE-ID. It also holds a maximum node id used
819 in the table as a value for HASHKEY_MAX_NID. A value associated to
820 a node is recorded as a value for the node id. */
821
822 #define HASHKEY_MAX_NID (make_number (0))
823
824 static XrmDatabase
825 xrm_create_database ()
826 {
827 XrmDatabase database;
828
829 database = make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
830 make_float (DEFAULT_REHASH_SIZE),
831 make_float (DEFAULT_REHASH_THRESHOLD),
832 Qnil, Qnil, Qnil);
833 Fputhash (HASHKEY_MAX_NID, make_number (0), database);
834
835 return database;
836 }
837
838 static void
839 xrm_q_put_resource (database, quarks, value)
840 XrmDatabase database;
841 Lisp_Object quarks, value;
842 {
843 struct Lisp_Hash_Table *h = XHASH_TABLE (database);
844 unsigned hash_code;
845 int max_nid, i;
846 Lisp_Object node_id, key;
847
848 max_nid = XINT (Fgethash (HASHKEY_MAX_NID, database, Qnil));
849
850 XSETINT (node_id, 0);
851 for (; CONSP (quarks); quarks = XCDR (quarks))
852 {
853 key = Fcons (node_id, XCAR (quarks));
854 i = hash_lookup (h, key, &hash_code);
855 if (i < 0)
856 {
857 max_nid++;
858 XSETINT (node_id, max_nid);
859 hash_put (h, key, node_id, hash_code);
860 }
861 else
862 node_id = HASH_VALUE (h, i);
863 }
864 Fputhash (node_id, value, database);
865
866 Fputhash (HASHKEY_MAX_NID, make_number (max_nid), database);
867 }
868
869 /* Merge multiple resource entries specified by DATA into a resource
870 database DATABASE. DATA points to the head of a null-terminated
871 string consisting of multiple resource lines. It's like a
872 combination of XrmGetStringDatabase and XrmMergeDatabases. */
873
874 void
875 xrm_merge_string_database (database, data)
876 XrmDatabase database;
877 char *data;
878 {
879 Lisp_Object quarks_value;
880
881 while (*data)
882 {
883 quarks_value = parse_resource_line (&data);
884 if (!NILP (quarks_value))
885 xrm_q_put_resource (database,
886 XCAR (quarks_value), XCDR (quarks_value));
887 }
888 }
889
890 static Lisp_Object
891 xrm_q_get_resource_1 (database, node_id, quark_name, quark_class)
892 XrmDatabase database;
893 Lisp_Object node_id, quark_name, quark_class;
894 {
895 struct Lisp_Hash_Table *h = XHASH_TABLE (database);
896 Lisp_Object key, labels[3], value;
897 int i, k;
898
899 if (!CONSP (quark_name))
900 return Fgethash (node_id, database, Qnil);
901
902 /* First, try tight bindings */
903 labels[0] = XCAR (quark_name);
904 labels[1] = XCAR (quark_class);
905 labels[2] = SINGLE_COMPONENT;
906
907 key = Fcons (node_id, Qnil);
908 for (k = 0; k < sizeof (labels) / sizeof (*labels); k++)
909 {
910 XSETCDR (key, labels[k]);
911 i = hash_lookup (h, key, NULL);
912 if (i >= 0)
913 {
914 value = xrm_q_get_resource_1 (database, HASH_VALUE (h, i),
915 XCDR (quark_name), XCDR (quark_class));
916 if (!NILP (value))
917 return value;
918 }
919 }
920
921 /* Then, try loose bindings */
922 XSETCDR (key, LOOSE_BINDING);
923 i = hash_lookup (h, key, NULL);
924 if (i >= 0)
925 {
926 value = xrm_q_get_resource_1 (database, HASH_VALUE (h, i),
927 quark_name, quark_class);
928 if (!NILP (value))
929 return value;
930 else
931 return xrm_q_get_resource_1 (database, node_id,
932 XCDR (quark_name), XCDR (quark_class));
933 }
934 else
935 return Qnil;
936 }
937
938 static Lisp_Object
939 xrm_q_get_resource (database, quark_name, quark_class)
940 XrmDatabase database;
941 Lisp_Object quark_name, quark_class;
942 {
943 return xrm_q_get_resource_1 (database, make_number (0),
944 quark_name, quark_class);
945 }
946
947 /* Retrieve a resource value for the specified NAME and CLASS from the
948 resource database DATABASE. It corresponds to XrmGetResource. */
949
950 Lisp_Object
951 xrm_get_resource (database, name, class)
952 XrmDatabase database;
953 char *name, *class;
954 {
955 Lisp_Object quark_name, quark_class, tmp;
956 int nn, nc;
957
958 quark_name = parse_resource_name (&name);
959 if (*name != '\0')
960 return Qnil;
961 for (tmp = quark_name, nn = 0; CONSP (tmp); tmp = XCDR (tmp), nn++)
962 if (!STRINGP (XCAR (tmp)))
963 return Qnil;
964
965 quark_class = parse_resource_name (&class);
966 if (*class != '\0')
967 return Qnil;
968 for (tmp = quark_class, nc = 0; CONSP (tmp); tmp = XCDR (tmp), nc++)
969 if (!STRINGP (XCAR (tmp)))
970 return Qnil;
971
972 if (nn != nc)
973 return Qnil;
974 else
975 return xrm_q_get_resource (database, quark_name, quark_class);
976 }
977
978 #if TARGET_API_MAC_CARBON
979 static Lisp_Object
980 xrm_cfproperty_list_to_value (plist)
981 CFPropertyListRef plist;
982 {
983 CFTypeID type_id = CFGetTypeID (plist);
984
985 if (type_id == CFStringGetTypeID ())
986 return cfstring_to_lisp (plist);
987 else if (type_id == CFNumberGetTypeID ())
988 {
989 CFStringRef string;
990 Lisp_Object result = Qnil;
991
992 string = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@"), plist);
993 if (string)
994 {
995 result = cfstring_to_lisp (string);
996 CFRelease (string);
997 }
998 return result;
999 }
1000 else if (type_id == CFBooleanGetTypeID ())
1001 return build_string (CFBooleanGetValue (plist) ? "true" : "false");
1002 else if (type_id == CFDataGetTypeID ())
1003 return cfdata_to_lisp (plist);
1004 else
1005 return Qnil;
1006 }
1007 #endif
1008
1009 /* Create a new resource database from the preferences for the
1010 application APPLICATION. APPLICATION is either a string that
1011 specifies an application ID, or NULL that represents the current
1012 application. */
1013
1014 XrmDatabase
1015 xrm_get_preference_database (application)
1016 char *application;
1017 {
1018 #if TARGET_API_MAC_CARBON
1019 CFStringRef app_id, *keys, user_doms[2], host_doms[2];
1020 CFMutableSetRef key_set = NULL;
1021 CFArrayRef key_array;
1022 CFIndex index, count;
1023 char *res_name;
1024 XrmDatabase database;
1025 Lisp_Object quarks = Qnil, value = Qnil;
1026 CFPropertyListRef plist;
1027 int iu, ih;
1028 struct gcpro gcpro1, gcpro2, gcpro3;
1029
1030 user_doms[0] = kCFPreferencesCurrentUser;
1031 user_doms[1] = kCFPreferencesAnyUser;
1032 host_doms[0] = kCFPreferencesCurrentHost;
1033 host_doms[1] = kCFPreferencesAnyHost;
1034
1035 database = xrm_create_database ();
1036
1037 GCPRO3 (database, quarks, value);
1038
1039 BLOCK_INPUT;
1040
1041 app_id = kCFPreferencesCurrentApplication;
1042 if (application)
1043 {
1044 app_id = cfstring_create_with_utf8_cstring (application);
1045 if (app_id == NULL)
1046 goto out;
1047 }
1048
1049 key_set = CFSetCreateMutable (NULL, 0, &kCFCopyStringSetCallBacks);
1050 if (key_set == NULL)
1051 goto out;
1052 for (iu = 0; iu < sizeof (user_doms) / sizeof (*user_doms) ; iu++)
1053 for (ih = 0; ih < sizeof (host_doms) / sizeof (*host_doms); ih++)
1054 {
1055 key_array = CFPreferencesCopyKeyList (app_id, user_doms[iu],
1056 host_doms[ih]);
1057 if (key_array)
1058 {
1059 count = CFArrayGetCount (key_array);
1060 for (index = 0; index < count; index++)
1061 CFSetAddValue (key_set,
1062 CFArrayGetValueAtIndex (key_array, index));
1063 CFRelease (key_array);
1064 }
1065 }
1066
1067 count = CFSetGetCount (key_set);
1068 keys = xmalloc (sizeof (CFStringRef) * count);
1069 if (keys == NULL)
1070 goto out;
1071 CFSetGetValues (key_set, (const void **)keys);
1072 for (index = 0; index < count; index++)
1073 {
1074 res_name = SDATA (cfstring_to_lisp (keys[index]));
1075 quarks = parse_resource_name (&res_name);
1076 if (!(NILP (quarks) || *res_name))
1077 {
1078 plist = CFPreferencesCopyAppValue (keys[index], app_id);
1079 value = xrm_cfproperty_list_to_value (plist);
1080 CFRelease (plist);
1081 if (!NILP (value))
1082 xrm_q_put_resource (database, quarks, value);
1083 }
1084 }
1085
1086 xfree (keys);
1087 out:
1088 if (key_set)
1089 CFRelease (key_set);
1090 CFRelease (app_id);
1091
1092 UNBLOCK_INPUT;
1093
1094 UNGCPRO;
1095
1096 return database;
1097 #else
1098 return xrm_create_database ();
1099 #endif
1100 }
1101
1102
291 #ifndef MAC_OSX 1103 #ifndef MAC_OSX
292 1104
293 /* The following functions with "sys_" prefix are stubs to Unix 1105 /* The following functions with "sys_" prefix are stubs to Unix
294 functions that have already been implemented by CW or MPW. The 1106 functions that have already been implemented by CW or MPW. The
295 calls to them in Emacs source course are #define'd to call the sys_ 1107 calls to them in Emacs source course are #define'd to call the sys_
2823 return val; 3635 return val;
2824 } 3636 }
2825 return Qnil; 3637 return Qnil;
2826 } 3638 }
2827 3639
3640 #if TARGET_API_MAC_CARBON
3641 static Lisp_Object Qxml;
3642
3643 DEFUN ("mac-get-preference", Fmac_get_preference, Smac_get_preference, 1, 4, 0,
3644 doc: /* Return the application preference value for KEY.
3645 KEY is either a string specifying a preference key, or a list of key
3646 strings. If it is a list, the (i+1)-th element is used as a key for
3647 the CFDictionary value obtained by the i-th element. If lookup is
3648 failed at some stage, nil is returned.
3649
3650 Optional arg APPLICATION is an application ID string. If omitted or
3651 nil, that stands for the current application.
3652
3653 Optional arg FORMAT specifies the data format of the return value. If
3654 omitted or nil, each Core Foundation object is converted into a
3655 corresponding Lisp object as follows:
3656
3657 Core Foundation Lisp Tag
3658 ------------------------------------------------------------
3659 CFString Multibyte string string
3660 CFNumber Integer or float number
3661 CFBoolean Symbol (t or nil) boolean
3662 CFDate List of three integers date
3663 (cf. `current-time')
3664 CFData Unibyte string data
3665 CFArray Array array
3666 CFDictionary Alist or hash table dictionary
3667 (depending on HASH-BOUND)
3668
3669 If it is t, a symbol that represents the type of the original Core
3670 Foundation object is prepended. If it is `xml', the value is returned
3671 as an XML representation.
3672
3673 Optional arg HASH-BOUND specifies which kinds of the list objects,
3674 alists or hash tables, are used as the targets of the conversion from
3675 CFDictionary. If HASH-BOUND is a negative integer or nil, always
3676 generate alists. If HASH-BOUND >= 0, generate an alist if the number
3677 of keys in the dictionary is smaller than HASH-BOUND, and a hash table
3678 otherwise. */)
3679 (key, application, format, hash_bound)
3680 Lisp_Object key, application, format, hash_bound;
3681 {
3682 CFStringRef app_id, key_str;
3683 CFPropertyListRef app_plist = NULL, plist;
3684 Lisp_Object result = Qnil, tmp;
3685
3686 if (STRINGP (key))
3687 key = Fcons (key, Qnil);
3688 else
3689 {
3690 CHECK_CONS (key);
3691 for (tmp = key; CONSP (tmp); tmp = XCDR (tmp))
3692 CHECK_STRING_CAR (tmp);
3693 if (!NILP (tmp))
3694 wrong_type_argument (Qlistp, key);
3695 }
3696 if (!NILP (application))
3697 CHECK_STRING (application);
3698 CHECK_SYMBOL (format);
3699 if (!NILP (hash_bound))
3700 CHECK_NUMBER (hash_bound);
3701
3702 BLOCK_INPUT;
3703
3704 app_id = kCFPreferencesCurrentApplication;
3705 if (!NILP (application))
3706 {
3707 app_id = cfstring_create_with_utf8_cstring (SDATA (application));
3708 if (app_id == NULL)
3709 goto out;
3710 }
3711 key_str = cfstring_create_with_utf8_cstring (SDATA (XCAR (key)));
3712 if (key_str == NULL)
3713 goto out;
3714 app_plist = CFPreferencesCopyAppValue (key_str, app_id);
3715 CFRelease (key_str);
3716 if (app_plist == NULL)
3717 goto out;
3718
3719 plist = app_plist;
3720 for (key = XCDR (key); CONSP (key); key = XCDR (key))
3721 {
3722 if (CFGetTypeID (plist) != CFDictionaryGetTypeID ())
3723 break;
3724 key_str = cfstring_create_with_utf8_cstring (SDATA (XCAR (key)));
3725 if (key_str == NULL)
3726 goto out;
3727 plist = CFDictionaryGetValue (plist, key_str);
3728 CFRelease (key_str);
3729 if (plist == NULL)
3730 goto out;
3731 }
3732
3733 if (NILP (key))
3734 if (EQ (format, Qxml))
3735 {
3736 CFDataRef data = CFPropertyListCreateXMLData (NULL, plist);
3737 if (data == NULL)
3738 goto out;
3739 result = cfdata_to_lisp (data);
3740 CFRelease (data);
3741 }
3742 else
3743 result =
3744 cfproperty_list_to_lisp (plist, EQ (format, Qt),
3745 NILP (hash_bound) ? -1 : XINT (hash_bound));
3746
3747 out:
3748 if (app_plist)
3749 CFRelease (app_plist);
3750 CFRelease (app_id);
3751
3752 UNBLOCK_INPUT;
3753
3754 return result;
3755 }
3756 #endif /* TARGET_API_MAC_CARBON */
3757
2828 3758
2829 DEFUN ("mac-clear-font-name-table", Fmac_clear_font_name_table, Smac_clear_font_name_table, 0, 0, 0, 3759 DEFUN ("mac-clear-font-name-table", Fmac_clear_font_name_table, Smac_clear_font_name_table, 0, 0, 0,
2830 doc: /* Clear the font name table. */) 3760 doc: /* Clear the font name table. */)
2831 () 3761 ()
2832 { 3762 {
3241 syms_of_mac () 4171 syms_of_mac ()
3242 { 4172 {
3243 QCLIPBOARD = intern ("CLIPBOARD"); 4173 QCLIPBOARD = intern ("CLIPBOARD");
3244 staticpro (&QCLIPBOARD); 4174 staticpro (&QCLIPBOARD);
3245 4175
4176 #if TARGET_API_MAC_CARBON
4177 Qstring = intern ("string");
4178 staticpro (&Qstring);
4179
4180 Qnumber = intern ("number");
4181 staticpro (&Qnumber);
4182
4183 Qboolean = intern ("boolean");
4184 staticpro (&Qboolean);
4185
4186 Qdate = intern ("date");
4187 staticpro (&Qdate);
4188
4189 Qdata = intern ("data");
4190 staticpro (&Qdata);
4191
4192 Qarray = intern ("array");
4193 staticpro (&Qarray);
4194
4195 Qdictionary = intern ("dictionary");
4196 staticpro (&Qdictionary);
4197
4198 Qxml = intern ("xml");
4199 staticpro (&Qxml);
4200 #endif
4201
3246 defsubr (&Smac_paste_function); 4202 defsubr (&Smac_paste_function);
3247 defsubr (&Smac_cut_function); 4203 defsubr (&Smac_cut_function);
3248 defsubr (&Sx_selection_exists_p); 4204 defsubr (&Sx_selection_exists_p);
4205 #if TARGET_API_MAC_CARBON
4206 defsubr (&Smac_get_preference);
4207 #endif
3249 defsubr (&Smac_clear_font_name_table); 4208 defsubr (&Smac_clear_font_name_table);
3250 4209
3251 defsubr (&Sdo_applescript); 4210 defsubr (&Sdo_applescript);
3252 defsubr (&Smac_file_name_to_posix); 4211 defsubr (&Smac_file_name_to_posix);
3253 defsubr (&Sposix_file_name_to_mac); 4212 defsubr (&Sposix_file_name_to_mac);