diff --git a/platform/platform-impl/src/com/intellij/ide/MacOSApplicationProvider.java b/platform/platform-impl/src/com/intellij/ide/MacOSApplicationProvider.java index 7b1c6dd05963..2520e4d57be5 100644 --- a/platform/platform-impl/src/com/intellij/ide/MacOSApplicationProvider.java +++ b/platform/platform-impl/src/com/intellij/ide/MacOSApplicationProvider.java @@ -149,8 +149,9 @@ public class MacOSApplicationProvider implements ApplicationComponent { Foundation.registerObjcClassPair(checkForUpdatesClass); ID checkForUpdates = Foundation.invoke("NSCheckForUpdates", "alloc"); - Foundation.invoke(checkForUpdates, Foundation.createSelector("initWithTitle:action:keyEquivalent:"), Foundation.cfString("Check for Updates..."), - Foundation.createSelector("checkForUpdates"), Foundation.cfString("")); + Foundation.invoke(checkForUpdates, Foundation.createSelector("initWithTitle:action:keyEquivalent:"), + Foundation.nsString("Check for Updates..."), + Foundation.createSelector("checkForUpdates"), Foundation.nsString("")); Foundation.invoke(checkForUpdates, Foundation.createSelector("setTarget:"), checkForUpdates); Foundation.invoke(appMenu, Foundation.createSelector("insertItem:atIndex:"), checkForUpdates, 1); diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/MacRestarter.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/MacRestarter.java index 10bf5ffa82a4..73b76980be65 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/MacRestarter.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/MacRestarter.java @@ -53,10 +53,10 @@ public class MacRestarter { final long processId = Foundation.invoke(app, Foundation.createSelector("processIdentifier")).longValue(); final ID args = Foundation.invoke(Foundation.getClass("NSArray"), Foundation.createSelector("arrayWithObjects:"), - new Object[]{Foundation.cfString(appPath), Foundation.cfString(String.valueOf(processId))}); + new Object[]{Foundation.nsString(appPath), Foundation.nsString(String.valueOf(processId))}); Foundation.invoke(Foundation.getClass("NSTask"), Foundation.createSelector("launchedTaskWithLaunchPath:arguments:"), - Foundation.cfString(relaunchPath), args); + Foundation.nsString(relaunchPath), args); } } } diff --git a/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java b/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java index 3cf8d86702f4..c0c8e983517a 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java @@ -26,7 +26,6 @@ import com.intellij.ui.mac.foundation.Foundation; import com.intellij.ui.mac.foundation.ID; import com.intellij.ui.mac.foundation.MacUtil; import com.sun.jna.Callback; -import com.sun.jna.Pointer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -130,7 +129,7 @@ public class MacFileChooserDialogImpl implements MacFileChooserDialog { public void callback(ID self, String selector, ID toSelect) { final ID chooser = invoke("NSOpenPanel", "openPanel"); - invoke(chooser, "setPrompt:", Foundation.cfString("Choose")); + invoke(chooser, "setPrompt:", Foundation.nsString("Choose")); invoke(chooser, "setCanChooseFiles:", myChooserDescriptor.isChooseFiles()); invoke(chooser, "setCanChooseDirectories:", myChooserDescriptor.isChooseFolders()); invoke(chooser, "setAllowsMultipleSelection:", myChooserDescriptor.isChooseMultiple()); @@ -152,8 +151,8 @@ public class MacFileChooserDialogImpl implements MacFileChooserDialog { invoke(chooser, "setDelegate:", self); - Object directory = null; - Object file = null; + ID directory = null; + ID file = null; final String toSelectPath = toSelect == null || toSelect.intValue() == 0 ? null : Foundation.toStringViaUTF8(toSelect); final VirtualFile toSelectFile = toSelectPath == null ? null : LocalFileSystem.getInstance().findFileByPath(toSelectPath); if (toSelectFile != null) { @@ -161,8 +160,8 @@ public class MacFileChooserDialogImpl implements MacFileChooserDialog { directory = toSelect; } else { - directory = Foundation.cfString(toSelectFile.getParent().getPath()); - file = Foundation.cfString(toSelectFile.getName()); + directory = Foundation.nsString(toSelectFile.getParent().getPath()); + file = Foundation.nsString(toSelectFile.getName()); } } @@ -181,6 +180,14 @@ public class MacFileChooserDialogImpl implements MacFileChooserDialog { if (focusedWindow != null) { invoke(chooser, "beginSheetForDirectory:file:types:modalForWindow:modalDelegate:didEndSelector:contextInfo:", directory, file, null, focusedWindow, self, Foundation.createSelector("openPanelDidEnd:returnCode:contextInfo:"), null); + + if (directory != null) { + Foundation.cfRelease(directory); + } + + if (file != null) { + Foundation.cfRelease(file); + } } } } @@ -265,7 +272,7 @@ public class MacFileChooserDialogImpl implements MacFileChooserDialog { try { final ID delegate = invoke(Foundation.getClass("NSOpenPanelDelegate_"), "new"); - final Pointer select = toSelect == null ? null : Foundation.cfString(toSelect.getPath()); + final ID select = toSelect == null ? null : Foundation.nsString(toSelect.getPath()); Foundation.cfRetain(delegate); invoke(delegate, "performSelectorOnMainThread:withObject:waitUntilDone:", Foundation.createSelector("showOpenPanel:"), select, false); @@ -281,7 +288,7 @@ public class MacFileChooserDialogImpl implements MacFileChooserDialog { try { final ID delegate = invoke(Foundation.getClass("NSOpenPanelDelegate_"), "new"); - final Pointer select = toSelect == null ? null : Foundation.cfString(toSelect.getPath()); + final ID select = toSelect == null ? null : Foundation.nsString(toSelect.getPath()); Foundation.cfRetain(delegate); invoke(delegate, "performSelectorOnMainThread:withObject:waitUntilDone:", Foundation.createSelector("showOpenPanel:"), select, false); diff --git a/platform/platform-impl/src/com/intellij/ui/mac/MacMainFrameDecorator.java b/platform/platform-impl/src/com/intellij/ui/mac/MacMainFrameDecorator.java index 489d108879dd..9f582883ea73 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/MacMainFrameDecorator.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/MacMainFrameDecorator.java @@ -177,18 +177,18 @@ public class MacMainFrameDecorator implements UISettingsListener, Disposable { ID delegate = invoke(invoke("IdeaNSWindowDelegate" + v, "alloc"), "init"); invoke(notificationCenter, "addObserver:selector:name:object:", delegate, Foundation.createSelector("windowDidEnterFullScreen:"), - Foundation.cfString("NSWindowDidEnterFullScreenNotification"), window); + Foundation.nsString("NSWindowDidEnterFullScreenNotification"), window); //invoke(notificationCenter, "addObserver:selector:name:object:", delegate, // Foundation.createSelector("windowDidExitFullScreen:"), - // Foundation.cfString("NSWindowDidExitFullScreenNotification"), window); + // Foundation.nsString("NSWindowDidExitFullScreenNotification"), window); } else { // toggle toolbar String className = "IdeaToolbar" + v; final ID ownToolbar = Foundation.registerObjcClass(Foundation.getClass("NSToolbar"), className); Foundation.registerObjcClassPair(ownToolbar); - ID toolbar = invoke(invoke(className, "alloc"), "initWithIdentifier:", Foundation.cfString(className)); + ID toolbar = invoke(invoke(className, "alloc"), "initWithIdentifier:", Foundation.nsString(className)); Foundation.cfRetain(toolbar); invoke(toolbar, "setVisible:", 0); // hide native toolbar by default diff --git a/platform/platform-impl/src/com/intellij/ui/mac/MacMessagesImpl.java b/platform/platform-impl/src/com/intellij/ui/mac/MacMessagesImpl.java index eb20198fdf0c..641f7a1dc76a 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/MacMessagesImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/MacMessagesImpl.java @@ -158,7 +158,7 @@ public class MacMessagesImpl extends MacMessages { // it is impossible to override ESCAPE key behavior -> key should be named "Cancel" to be bound to ESC //if (!alternateExist) { - //invoke(invoke(invoke(alert, "buttons"), "objectAtIndex:", 1), "setKeyEquivalent:", cfString("\\e")); + //invoke(invoke(invoke(alert, "buttons"), "objectAtIndex:", 1), "setKeyEquivalent:", nsString("\\e")); //} String doNotAsk = toStringViaUTF8(doNotAskText); @@ -263,19 +263,21 @@ public class MacMessagesImpl extends MacMessages { final ID buttonsArray = invoke("NSMutableArray", "array"); for (String s : buttons) { - invoke(buttonsArray, "addObject:", cfString(UIUtil.removeMnemonic(s))); + ID s1 = nsString(UIUtil.removeMnemonic(s)); + invoke(buttonsArray, "addObject:", s); + cfRelease(s1); } - ID paramsArray = invoke("NSArray", "arrayWithObjects:", cfString(title), + ID paramsArray = invoke("NSArray", "arrayWithObjects:", nsString(title), // replace % -> %% to avoid formatted parameters (causes SIGTERM) - cfString(StringUtil.stripHtml(message, true).replace("%", "%%")), - focusedWindow, cfString(fakeTitle), cfString(errorStyle ? "error" : "-1"), - cfString(doNotAskDialogOption == null || !doNotAskDialogOption.canBeHidden() + nsString(StringUtil.stripHtml(message, true).replace("%", "%%")), + focusedWindow, nsString(fakeTitle), nsString(errorStyle ? "error" : "-1"), + nsString(doNotAskDialogOption == null || !doNotAskDialogOption.canBeHidden() // TODO: state=!doNotAsk.shouldBeShown() ? "-1" : doNotAskDialogOption.getDoNotShowMessage()), - cfString(Integer.toString(defaultOptionIndex)), - cfString(Integer.toString(focusedOptionIndex)), buttonsArray, null); + nsString(Integer.toString(defaultOptionIndex)), + nsString(Integer.toString(focusedOptionIndex)), buttonsArray, null); IdeFocusManager.getGlobalInstance().setTypeaheadEnabled(false); @@ -427,13 +429,13 @@ public class MacMessagesImpl extends MacMessages { fakeTitle = String.format("MacSheetDialog-%d", delegate.intValue()); - ID paramsArray = invoke("NSArray", "arrayWithObjects:", cfString(title), cfString(UIUtil.removeMnemonic(defaultText)), - cfString(otherText == null ? "-1" : UIUtil.removeMnemonic(otherText)), - cfString(alternateText == null ? "-1" : UIUtil.removeMnemonic(alternateText)), + ID paramsArray = invoke("NSArray", "arrayWithObjects:", nsString(title), nsString(UIUtil.removeMnemonic(defaultText)), + nsString(otherText == null ? "-1" : UIUtil.removeMnemonic(otherText)), + nsString(alternateText == null ? "-1" : UIUtil.removeMnemonic(alternateText)), // replace % -> %% to avoid formatted parameters (causes SIGTERM) - cfString(StringUtil.stripHtml(message, true).replace("%", "%%")), - focusedWindow, cfString(fakeTitle), cfString(errorStyle ? "error" : "-1"), - cfString(doNotAskDialogOption == null || !doNotAskDialogOption.canBeHidden() + nsString(StringUtil.stripHtml(message, true).replace("%", "%%")), + focusedWindow, nsString(fakeTitle), nsString(errorStyle ? "error" : "-1"), + nsString(doNotAskDialogOption == null || !doNotAskDialogOption.canBeHidden() // TODO: state=!doNotAsk.shouldBeShown() ? "-1" : doNotAskDialogOption.getDoNotShowMessage()), null); diff --git a/platform/platform-impl/src/com/intellij/ui/mac/growl/Growl.java b/platform/platform-impl/src/com/intellij/ui/mac/growl/Growl.java index 8198247e6c02..df4a5d97bf20 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/growl/Growl.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/growl/Growl.java @@ -55,7 +55,7 @@ public class Growl { new Object[]{myProductName, applicationIcon, defaultNotifications, allNotifications}); final ID center = invoke("NSDistributedNotificationCenter", "defaultCenter"); - final Object notificationName = Foundation.cfString(GROWL_APPLICATION_REGISTRATION_NOTIFICATION); + final Object notificationName = Foundation.nsString(GROWL_APPLICATION_REGISTRATION_NOTIFICATION); invoke(center, "postNotificationName:object:userInfo:deliverImmediately:", notificationName, null, userDict, true); invoke(autoReleasePool, "release"); } @@ -66,7 +66,7 @@ public class Growl { GROWL_NOTIFICATION_NAME, GROWL_NOTIFICATION_TITLE, GROWL_NOTIFICATION_DESCRIPTION, GROWL_APP_NAME}, new Object[]{notification, title, description, myProductName}); final ID center = invoke("NSDistributedNotificationCenter", "defaultCenter"); - final Object notificationName = Foundation.cfString(GROWL_NOTIFICATION); + final Object notificationName = Foundation.nsString(GROWL_NOTIFICATION); invoke(center, "postNotificationName:object:userInfo:deliverImmediately:", notificationName, null, dict, true); invoke(autoReleasePool, "release"); @@ -104,7 +104,7 @@ public class Growl { if (o instanceof Pointer || o instanceof ID) { return o; } else if (o instanceof String) { - return Foundation.cfString((String) o); + return Foundation.nsString((String)o); } else { throw new IllegalArgumentException("Unsupported type! " + o.getClass()); } diff --git a/platform/util/src/com/intellij/ui/mac/foundation/Foundation.java b/platform/util/src/com/intellij/ui/mac/foundation/Foundation.java index ea7063f0a24d..4ead26f95b10 100644 --- a/platform/util/src/com/intellij/ui/mac/foundation/Foundation.java +++ b/platform/util/src/com/intellij/ui/mac/foundation/Foundation.java @@ -128,7 +128,7 @@ public class Foundation { public static boolean isPackageAtPath(@NotNull final String path) { final ID workspace = invoke("NSWorkspace", "sharedWorkspace"); - final ID result = invoke(workspace, createSelector("isFilePackageAtPath:"), cfString(path)); + final ID result = invoke(workspace, createSelector("isFilePackageAtPath:"), nsString(path)); return result.intValue() == 1; } @@ -138,18 +138,17 @@ public class Foundation { return isPackageAtPath(file.getPath()); } - /** - * Return a CFString as an ID, toll-free bridged to NSString. - *
- * Note that the returned string must be freed with {@link #cfRelease(ID)}. - */ - public static Pointer cfString(String s) { + public static ID nsString(String s) { // Use a byte[] rather than letting jna do the String -> char* marshalling itself. // Turns out about 10% quicker for long strings. try { + if (s.length() == 0) { + return invoke("NSString", "string"); + } + byte[] utf16Bytes = s.getBytes("UTF-16LE"); - return myFoundationLibrary.CFStringCreateWithBytes(null, utf16Bytes, utf16Bytes.length, FoundationLibrary.kCFStringEncodingUTF16LE, - (byte)0); /* kTextEncodingUnicodeDefault + kUnicodeUTF16LEFormat */ + return invoke(invoke("NSString", "alloc"), "initWithBytes:length:encoding:", utf16Bytes, utf16Bytes.length, + myFoundationLibrary.CFStringConvertEncodingToNSStringEncoding(FoundationLibrary.kCFStringEncodingUTF16LE)); } catch (UnsupportedEncodingException x) { throw new RuntimeException(x); @@ -179,7 +178,7 @@ public class Foundation { public static long getEncodingCode(@Nullable String encodingName) { if (StringUtil.isEmptyOrSpaces(encodingName)) return -1; - Pointer converted = cfString(encodingName); + ID converted = nsString(encodingName); int cfEncoding = myFoundationLibrary.CFStringConvertIANACharSetNameToEncoding(converted); if (cfEncoding == FoundationLibrary.kCFStringEncodingInvalidId) return -1; @@ -190,8 +189,10 @@ public class Foundation { myFoundationLibrary.CFRetain(id); } - public static void cfRelease(ID id) { - myFoundationLibrary.CFRelease(id); + public static void cfRelease(ID... id) { + for (ID id1 : id) { + myFoundationLibrary.CFRelease(id1); + } } public static boolean isMainThread() { @@ -223,7 +224,7 @@ public class Foundation { final ID ideaRunnable = getClass("IdeaRunnable"); final ID runnableObject = invoke(invoke(ideaRunnable, "alloc"), "init"); invoke(runnableObject, "performSelectorOnMainThread:withObject:waitUntilDone:", createSelector("run:"), - cfString(String.valueOf(ourCurrentRunnableCount)), Boolean.valueOf(waitUntilDone)); + nsString(String.valueOf(ourCurrentRunnableCount)), Boolean.valueOf(waitUntilDone)); invoke(runnableObject, "release"); } diff --git a/platform/util/src/com/intellij/ui/mac/foundation/FoundationLibrary.java b/platform/util/src/com/intellij/ui/mac/foundation/FoundationLibrary.java index 6e82289fb5c5..1d2665fe94b8 100644 --- a/platform/util/src/com/intellij/ui/mac/foundation/FoundationLibrary.java +++ b/platform/util/src/com/intellij/ui/mac/foundation/FoundationLibrary.java @@ -30,14 +30,14 @@ public interface FoundationLibrary extends Library { ID objc_allocateClassPair(ID supercls, String name, int extraBytes); void objc_registerClassPair(ID cls); - Pointer CFStringCreateWithBytes(Pointer allocator, byte[] bytes, int byteCount, int encoding, byte isExternalRepresentation); + ID CFStringCreateWithBytes(Pointer allocator, byte[] bytes, int byteCount, int encoding, byte isExternalRepresentation); byte CFStringGetCString(ID theString, byte[] buffer, int bufferSize, int encoding); int CFStringGetLength(ID theString); int CFStringConvertNSStringEncodingToEncoding(long nsEncoding); ID CFStringConvertEncodingToIANACharSetName(int cfEncoding); - int CFStringConvertIANACharSetNameToEncoding(Pointer encodingName); + int CFStringConvertIANACharSetNameToEncoding(ID encodingName); long CFStringConvertEncodingToNSStringEncoding(int cfEncoding); void CFRetain(ID cfTypeRef);