aboutsummaryrefslogtreecommitdiffstats
path: root/src/mac.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mac.c')
-rw-r--r--src/mac.c1004
1 files changed, 973 insertions, 31 deletions
diff --git a/src/mac.c b/src/mac.c
index 44d763562b0..d57d6925c5d 100644
--- a/src/mac.c
+++ b/src/mac.c
@@ -26,31 +26,15 @@ Boston, MA 02111-1307, USA. */
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>
@@ -81,12 +65,6 @@ Boston, MA 02111-1307, USA. */
81#include <unistd.h> 65#include <unistd.h>
82#endif 66#endif
83 67
84#include "lisp.h"
85#include "process.h"
86#include "sysselect.h"
87#include "systime.h"
88#include "blockinput.h"
89
90Lisp_Object QCLIPBOARD; 68Lisp_Object QCLIPBOARD;
91 69
92/* An instance of the AppleScript component. */ 70/* An instance of the AppleScript component. */
@@ -272,7 +250,25 @@ posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen)
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
259static Lisp_Object Qstring, Qnumber, Qboolean, Qdate, Qdata;
260static Lisp_Object Qarray, Qdictionary;
261extern Lisp_Object Qutf_8;
262#define DECODE_UTF_8(str) code_convert_string_norecord (str, Qutf_8, 0)
263
264struct cfdict_context
265{
266 Lisp_Object *result;
267 int with_tag, hash_bound;
268};
269
270/* C string to CFString. */
271
276CFStringRef 272CFStringRef
277cfstring_create_with_utf8_cstring (c_str) 273cfstring_create_with_utf8_cstring (c_str)
278 const char *c_str; 274 const char *c_str;
@@ -286,8 +282,807 @@ cfstring_create_with_utf8_cstring (c_str)
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
289Lisp_Object
290cfdata_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
306Lisp_Object
307cfstring_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
342Lisp_Object
343cfnumber_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
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
369Lisp_Object
370cfdate_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
390Lisp_Object
391cfboolean_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
400Lisp_Object
401cfobject_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
419static void
420cfdictionary_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
434static void
435cfdictionary_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
461Lisp_Object
462cfproperty_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
568static void
569skip_while_space (p)
570 char **p;
571{
572 /* WhiteSpace = {<space> | <horizontal tab>} */
573 while (*P == ' ' || *P == '\t')
574 P++;
575}
576
577static int
578parse_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. */
595static int
596parse_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
612static char
613parse_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
630static Lisp_Object
631parse_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
655static Lisp_Object
656parse_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
689static Lisp_Object
690parse_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;
290 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
779static Lisp_Object
780parse_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_while_space (p);
791 quarks = parse_resource_name (p);
792 if (NILP (quarks))
793 goto cleanup;
794 skip_while_space (p);
795 if (*P != ':')
796 goto cleanup;
797 P++;
798 skip_while_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. Nodes of the trie are implemented as Lisp hash
816 tables, and a value associated with a resource name is recorded as
817 a value for HASHKEY_TERMINAL at the hash table whose path from the
818 root is the quarks of the resource name. */
819
820#define HASHKEY_TERMINAL Qt /* "T"erminal */
821
822static XrmDatabase
823xrm_create_database ()
824{
825 return make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
826 make_float (DEFAULT_REHASH_SIZE),
827 make_float (DEFAULT_REHASH_THRESHOLD),
828 Qnil, Qnil, Qnil);
829}
830
831static void
832xrm_q_put_resource (database, quarks, value)
833 XrmDatabase database;
834 Lisp_Object quarks, value;
835{
836 struct Lisp_Hash_Table *h;
837 unsigned hash_code;
838 int i;
839
840 for (; CONSP (quarks); quarks = XCDR (quarks))
841 {
842 h = XHASH_TABLE (database);
843 i = hash_lookup (h, XCAR (quarks), &hash_code);
844 if (i < 0)
845 {
846 database = xrm_create_database ();
847 hash_put (h, XCAR (quarks), database, hash_code);
848 }
849 else
850 database = HASH_VALUE (h, i);
851 }
852
853 Fputhash (HASHKEY_TERMINAL, value, database);
854}
855
856/* Merge multiple resource entries specified by DATA into a resource
857 database DATABASE. DATA points to the head of a null-terminated
858 string consisting of multiple resource lines. It's like a
859 combination of XrmGetStringDatabase and XrmMergeDatabases. */
860
861void
862xrm_merge_string_database (database, data)
863 XrmDatabase database;
864 char *data;
865{
866 Lisp_Object quarks_value;
867
868 while (*data)
869 {
870 quarks_value = parse_resource_line (&data);
871 if (!NILP (quarks_value))
872 xrm_q_put_resource (database,
873 XCAR (quarks_value), XCDR (quarks_value));
874 }
875}
876
877static Lisp_Object
878xrm_q_get_resource (database, quark_name, quark_class)
879 XrmDatabase database;
880 Lisp_Object quark_name, quark_class;
881{
882 struct Lisp_Hash_Table *h = XHASH_TABLE (database);
883 Lisp_Object keys[3], value;
884 int i, k;
885
886 if (!CONSP (quark_name))
887 return Fgethash (HASHKEY_TERMINAL, database, Qnil);
888
889 /* First, try tight bindings */
890 keys[0] = XCAR (quark_name);
891 keys[1] = XCAR (quark_class);
892 keys[2] = SINGLE_COMPONENT;
893
894 for (k = 0; k < sizeof (keys) / sizeof (*keys); k++)
895 {
896 i = hash_lookup (h, keys[k], NULL);
897 if (i >= 0)
898 {
899 value = xrm_q_get_resource (HASH_VALUE (h, i),
900 XCDR (quark_name), XCDR (quark_class));
901 if (!NILP (value))
902 return value;
903 }
904 }
905
906 /* Then, try loose bindings */
907 i = hash_lookup (h, LOOSE_BINDING, NULL);
908 if (i >= 0)
909 {
910 value = xrm_q_get_resource (HASH_VALUE (h, i), quark_name, quark_class);
911 if (!NILP (value))
912 return value;
913 else
914 return xrm_q_get_resource (database,
915 XCDR (quark_name), XCDR (quark_class));
916 }
917 else
918 return Qnil;
919}
920
921/* Retrieve a resource value for the specified NAME and CLASS from the
922 resource database DATABASE. It corresponds to XrmGetResource. */
923
924Lisp_Object
925xrm_get_resource (database, name, class)
926 XrmDatabase database;
927 char *name, *class;
928{
929 Lisp_Object quark_name, quark_class, tmp;
930 int nn, nc;
931
932 quark_name = parse_resource_name (&name);
933 if (*name != '\0')
934 return Qnil;
935 for (tmp = quark_name, nn = 0; CONSP (tmp); tmp = XCDR (tmp), nn++)
936 if (!STRINGP (XCAR (tmp)))
937 return Qnil;
938
939 quark_class = parse_resource_name (&class);
940 if (*class != '\0')
941 return Qnil;
942 for (tmp = quark_class, nc = 0; CONSP (tmp); tmp = XCDR (tmp), nc++)
943 if (!STRINGP (XCAR (tmp)))
944 return Qnil;
945
946 if (nn != nc)
947 return Qnil;
948 else
949 return xrm_q_get_resource (database, quark_name, quark_class);
950}
951
952#if TARGET_API_MAC_CARBON
953static Lisp_Object
954xrm_cfproperty_list_to_value (plist)
955 CFPropertyListRef plist;
956{
957 CFTypeID type_id = CFGetTypeID (plist);
958
959 if (type_id == CFStringGetTypeID ())
960 return cfstring_to_lisp (plist);
961 else if (type_id == CFNumberGetTypeID ())
962 {
963 CFStringRef string;
964 Lisp_Object result = Qnil;
965
966 string = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@"), plist);
967 if (string)
968 {
969 result = cfstring_to_lisp (string);
970 CFRelease (string);
971 }
972 return result;
973 }
974 else if (type_id == CFBooleanGetTypeID ())
975 {
976 static value_true = NULL, value_false = NULL;
977
978 if (value_true == NULL)
979 {
980 value_true = build_string ("true");
981 value_false = build_string ("false");
982 }
983 return CFBooleanGetValue (plist) ? value_true : value_false;
984 }
985 else if (type_id == CFDataGetTypeID ())
986 return cfdata_to_lisp (plist);
987 else
988 return Qnil;
989}
990#endif
991
992/* Create a new resource database from the preferences for the
993 application APPLICATION. APPLICATION is either a string that
994 specifies an application ID, or NULL that represents the current
995 application. */
996
997XrmDatabase
998xrm_get_preference_database (application)
999 char *application;
1000{
1001#if TARGET_API_MAC_CARBON
1002 CFStringRef app_id, *keys, user_doms[2], host_doms[2];
1003 CFMutableSetRef key_set = NULL;
1004 CFArrayRef key_array;
1005 CFIndex index, count;
1006 char *res_name;
1007 XrmDatabase database;
1008 Lisp_Object quarks = Qnil, value = Qnil;
1009 CFPropertyListRef plist;
1010 int iu, ih;
1011 struct gcpro gcpro1, gcpro2, gcpro3;
1012
1013 user_doms[0] = kCFPreferencesCurrentUser;
1014 user_doms[1] = kCFPreferencesAnyUser;
1015 host_doms[0] = kCFPreferencesCurrentHost;
1016 host_doms[1] = kCFPreferencesAnyHost;
1017
1018 database = xrm_create_database ();
1019
1020 GCPRO3 (database, quarks, value);
1021
1022 BLOCK_INPUT;
1023
1024 app_id = kCFPreferencesCurrentApplication;
1025 if (application)
1026 {
1027 app_id = cfstring_create_with_utf8_cstring (application);
1028 if (app_id == NULL)
1029 goto out;
1030 }
1031
1032 key_set = CFSetCreateMutable (NULL, 0, &kCFCopyStringSetCallBacks);
1033 if (key_set == NULL)
1034 goto out;
1035 for (iu = 0; iu < sizeof (user_doms) / sizeof (*user_doms) ; iu++)
1036 for (ih = 0; ih < sizeof (host_doms) / sizeof (*host_doms); ih++)
1037 {
1038 key_array = CFPreferencesCopyKeyList (app_id, user_doms[iu],
1039 host_doms[ih]);
1040 if (key_array)
1041 {
1042 count = CFArrayGetCount (key_array);
1043 for (index = 0; index < count; index++)
1044 CFSetAddValue (key_set,
1045 CFArrayGetValueAtIndex (key_array, index));
1046 CFRelease (key_array);
1047 }
1048 }
1049
1050 count = CFSetGetCount (key_set);
1051 keys = xmalloc (sizeof (CFStringRef) * count);
1052 if (keys == NULL)
1053 goto out;
1054 CFSetGetValues (key_set, (const void **)keys);
1055 for (index = 0; index < count; index++)
1056 {
1057 res_name = SDATA (cfstring_to_lisp (keys[index]));
1058 quarks = parse_resource_name (&res_name);
1059 if (!(NILP (quarks) || *res_name))
1060 {
1061 plist = CFPreferencesCopyAppValue (keys[index], app_id);
1062 value = xrm_cfproperty_list_to_value (plist);
1063 CFRelease (plist);
1064 if (!NILP (value))
1065 xrm_q_put_resource (database, quarks, value);
1066 }
1067 }
1068
1069 xfree (keys);
1070 out:
1071 if (key_set)
1072 CFRelease (key_set);
1073 CFRelease (app_id);
1074
1075 UNBLOCK_INPUT;
1076
1077 UNGCPRO;
1078
1079 return database;
1080#else
1081 return xrm_create_database ();
1082#endif
1083}
1084
1085
291#ifndef MAC_OSX 1086#ifndef MAC_OSX
292 1087
293/* The following functions with "sys_" prefix are stubs to Unix 1088/* The following functions with "sys_" prefix are stubs to Unix
@@ -2825,6 +3620,124 @@ and t is the same as `SECONDARY'. */)
2825 return Qnil; 3620 return Qnil;
2826} 3621}
2827 3622
3623#if TARGET_API_MAC_CARBON
3624static Lisp_Object Qxml;
3625
3626DEFUN ("mac-get-preference", Fmac_get_preference, Smac_get_preference, 1, 4, 0,
3627 doc: /* Return the application preference value for KEY.
3628KEY is either a string specifying a preference key, or a list of key
3629strings. If it is a list, the (i+1)-th element is used as a key for
3630the CFDictionary value obtained by the i-th element. If lookup is
3631failed at some stage, nil is returned.
3632
3633Optional arg APPLICATION is an application ID string. If omitted or
3634nil, that stands for the current application.
3635
3636Optional arg FORMAT specifies the data format of the return value. If
3637omitted or nil, each Core Foundation object is converted into a
3638corresponding Lisp object as follows:
3639
3640 Core Foundation Lisp Tag
3641 ------------------------------------------------------------
3642 CFString Multibyte string string
3643 CFNumber Integer or float number
3644 CFBoolean Symbol (t or nil) boolean
3645 CFDate List of three integers date
3646 (cf. `current-time')
3647 CFData Unibyte string data
3648 CFArray Array array
3649 CFDictionary Alist or hash table dictionary
3650 (depending on HASH-BOUND)
3651
3652If it is t, a symbol that represents the type of the original Core
3653Foundation object is prepended. If it is `xml', the value is returned
3654as an XML representation.
3655
3656Optional arg HASH-BOUND specifies which kinds of the list objects,
3657alists or hash tables, are used as the targets of the conversion from
3658CFDictionary. If HASH-BOUND is a negative integer or nil, always
3659generate alists. If HASH-BOUND >= 0, generate an alist if the number
3660of keys in the dictionary is smaller than HASH-BOUND, and a hash table
3661otherwise. */)
3662 (key, application, format, hash_bound)
3663 Lisp_Object key, application, format, hash_bound;
3664{
3665 CFStringRef app_id, key_str;
3666 CFPropertyListRef app_plist = NULL, plist;
3667 Lisp_Object result = Qnil, tmp;
3668
3669 if (STRINGP (key))
3670 key = Fcons (key, Qnil);
3671 else
3672 {
3673 CHECK_CONS (key);
3674 for (tmp = key; CONSP (tmp); tmp = XCDR (tmp))
3675 CHECK_STRING_CAR (tmp);
3676 if (!NILP (tmp))
3677 wrong_type_argument (Qlistp, key);
3678 }
3679 if (!NILP (application))
3680 CHECK_STRING (application);
3681 CHECK_SYMBOL (format);
3682 if (!NILP (hash_bound))
3683 CHECK_NUMBER (hash_bound);
3684
3685 BLOCK_INPUT;
3686
3687 app_id = kCFPreferencesCurrentApplication;
3688 if (!NILP (application))
3689 {
3690 app_id = cfstring_create_with_utf8_cstring (SDATA (application));
3691 if (app_id == NULL)
3692 goto out;
3693 }
3694 key_str = cfstring_create_with_utf8_cstring (SDATA (XCAR (key)));
3695 if (key_str == NULL)
3696 goto out;
3697 app_plist = CFPreferencesCopyAppValue (key_str, app_id);
3698 CFRelease (key_str);
3699 if (app_plist == NULL)
3700 goto out;
3701
3702 plist = app_plist;
3703 for (key = XCDR (key); CONSP (key); key = XCDR (key))
3704 {
3705 if (CFGetTypeID (plist) != CFDictionaryGetTypeID ())
3706 break;
3707 key_str = cfstring_create_with_utf8_cstring (SDATA (XCAR (key)));
3708 if (key_str == NULL)
3709 goto out;
3710 plist = CFDictionaryGetValue (plist, key_str);
3711 CFRelease (key_str);
3712 if (plist == NULL)
3713 goto out;
3714 }
3715
3716 if (NILP (key))
3717 if (EQ (format, Qxml))
3718 {
3719 CFDataRef data = CFPropertyListCreateXMLData (NULL, plist);
3720 if (data == NULL)
3721 goto out;
3722 result = cfdata_to_lisp (data);
3723 CFRelease (data);
3724 }
3725 else
3726 result =
3727 cfproperty_list_to_lisp (plist, EQ (format, Qt),
3728 NILP (hash_bound) ? -1 : XINT (hash_bound));
3729
3730 out:
3731 if (app_plist)
3732 CFRelease (app_plist);
3733 CFRelease (app_id);
3734
3735 UNBLOCK_INPUT;
3736
3737 return result;
3738}
3739#endif /* TARGET_API_MAC_CARBON */
3740
2828 3741
2829DEFUN ("mac-clear-font-name-table", Fmac_clear_font_name_table, Smac_clear_font_name_table, 0, 0, 0, 3742DEFUN ("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. */) 3743 doc: /* Clear the font name table. */)
@@ -3243,9 +4156,38 @@ syms_of_mac ()
3243 QCLIPBOARD = intern ("CLIPBOARD"); 4156 QCLIPBOARD = intern ("CLIPBOARD");
3244 staticpro (&QCLIPBOARD); 4157 staticpro (&QCLIPBOARD);
3245 4158
4159#if TARGET_API_MAC_CARBON
4160 Qstring = intern ("string");
4161 staticpro (&Qstring);
4162
4163 Qnumber = intern ("number");
4164 staticpro (&Qnumber);
4165
4166 Qboolean = intern ("boolean");
4167 staticpro (&Qboolean);
4168
4169 Qdate = intern ("date");
4170 staticpro (&Qdate);
4171
4172 Qdata = intern ("data");
4173 staticpro (&Qdata);
4174
4175 Qarray = intern ("array");
4176 staticpro (&Qarray);
4177
4178 Qdictionary = intern ("dictionary");
4179 staticpro (&Qdictionary);
4180
4181 Qxml = intern ("xml");
4182 staticpro (&Qxml);
4183#endif
4184
3246 defsubr (&Smac_paste_function); 4185 defsubr (&Smac_paste_function);
3247 defsubr (&Smac_cut_function); 4186 defsubr (&Smac_cut_function);
3248 defsubr (&Sx_selection_exists_p); 4187 defsubr (&Sx_selection_exists_p);
4188#if TARGET_API_MAC_CARBON
4189 defsubr (&Smac_get_preference);
4190#endif
3249 defsubr (&Smac_clear_font_name_table); 4191 defsubr (&Smac_clear_font_name_table);
3250 4192
3251 defsubr (&Sdo_applescript); 4193 defsubr (&Sdo_applescript);