750628620ca0c8ece265c54d0835fd63d3181fdd
[idea/community.git] / platform / platform-impl / src / com / intellij / ui / mac / foundation / Foundation.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.ui.mac.foundation;
17
18 import com.intellij.util.containers.HashMap;
19 import com.sun.jna.Callback;
20 import com.sun.jna.Native;
21 import com.sun.jna.Pointer;
22
23 import java.io.UnsupportedEncodingException;
24 import java.util.Map;
25
26 /**
27  * @author spleaner
28  */
29 public class Foundation {
30   private static final FoundationLibrary myFoundationLibrary;
31
32   static {
33     // Set JNA to convert java.lang.String to char* using UTF-8, and match that with
34     // the way we tell CF to interpret our char*
35     // May be removed if we use toStringViaUTF16
36     System.setProperty("jna.encoding", "UTF8");
37
38     Map<String, Object> foundationOptions = new HashMap<String, Object>();
39     //foundationOptions.put(Library.OPTION_TYPE_MAPPER, FoundationTypeMapper.INSTANCE);
40
41     myFoundationLibrary = (FoundationLibrary)Native.loadLibrary("Foundation", FoundationLibrary.class, foundationOptions);
42   }
43
44   public static void init() { /* fake method to init foundation */ }
45
46   private Foundation() {
47   }
48
49   /**
50    * Get the ID of the NSClass with className
51    */
52   public static ID getClass(String className) {
53     return myFoundationLibrary.objc_getClass(className);
54   }
55
56   public static Pointer createSelector(String s) {
57     return myFoundationLibrary.sel_registerName(s);
58   }
59
60   public static ID invoke(final ID id, final Pointer selector, Object... args) {
61     return myFoundationLibrary.objc_msgSend(id, selector, args);
62   }
63
64   public static ID registerObjcClass(ID superCls, String name) {
65     return myFoundationLibrary.objc_allocateClassPair(superCls, name, 0);
66   }
67
68   public static void registerObjcClassPair(ID cls) {
69     myFoundationLibrary.objc_registerClassPair(cls);
70   }
71
72   public static boolean isClassRespondsToSelector(ID cls, Pointer selectorName) {
73     return myFoundationLibrary.class_respondsToSelector(cls, selectorName);
74   }
75
76   public static boolean addMethod(ID cls, Pointer selectorName, Callback impl, String types) {
77     return myFoundationLibrary.class_addMethod(cls, selectorName, impl, types);
78   }
79
80   public static Pointer getClass(Pointer clazz) {
81     return myFoundationLibrary.objc_getClass(clazz);
82   }
83
84   /**
85    * Return a CFString as an ID, toll-free bridged to NSString.
86    * <p/>
87    * Note that the returned string must be freed with {@link #cfRelease(ID)}.
88    */
89   public static Pointer cfString(String s) {
90     // Use a byte[] rather than letting jna do the String -> char* marshalling itself.
91     // Turns out about 10% quicker for long strings.
92     try {
93       byte[] utf16Bytes = s.getBytes("UTF-16LE");
94       return myFoundationLibrary.CFStringCreateWithBytes(null, utf16Bytes, utf16Bytes.length, 0x14000100,
95                                                          (byte)0); /* kTextEncodingUnicodeDefault + kUnicodeUTF16LEFormat */
96     }
97     catch (UnsupportedEncodingException x) {
98       throw new RuntimeException(x);
99     }
100   }
101
102   public static String toStringViaUTF8(ID cfString) {
103     int lengthInChars = myFoundationLibrary.CFStringGetLength(cfString);
104     int potentialLengthInBytes = 3 * lengthInChars + 1; // UTF8 fully escaped 16 bit chars, plus nul
105
106     byte[] buffer = new byte[potentialLengthInBytes];
107     byte ok = myFoundationLibrary.CFStringGetCString(cfString, buffer, buffer.length, 0x08000100);
108     if (ok == 0) throw new RuntimeException("Could not convert string");
109     return Native.toString(buffer);
110   }
111
112   public static void cfRetain(ID id) {
113     myFoundationLibrary.CFRetain(id);
114   }
115 }