From 36db1cd4beb8bb005b2a849b8d29867926f221d7 Mon Sep 17 00:00:00 2001 From: Alexey Pegov Date: Tue, 23 Aug 2011 18:30:56 +0400 Subject: [PATCH] [mac] MacNativeMethodInterceptor utility --- .../ui/mac/MacNativeMethodInterceptor.java | 73 +++++++++++++++++++ .../ui/mac/foundation/Foundation.java | 27 +++++++ .../ui/mac/foundation/FoundationLibrary.java | 10 +++ 3 files changed, 110 insertions(+) create mode 100644 platform/platform-impl/src/com/intellij/ui/mac/MacNativeMethodInterceptor.java diff --git a/platform/platform-impl/src/com/intellij/ui/mac/MacNativeMethodInterceptor.java b/platform/platform-impl/src/com/intellij/ui/mac/MacNativeMethodInterceptor.java new file mode 100644 index 000000000000..45a293769083 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ui/mac/MacNativeMethodInterceptor.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ui.mac; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.ui.mac.foundation.Foundation; +import com.intellij.ui.mac.foundation.ID; +import com.sun.jna.Callback; +import com.sun.jna.Pointer; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Utility class to debug native method calls + * + * @author pegov + */ +public class MacNativeMethodInterceptor { + public static AtomicBoolean FIX_ENABLED = new AtomicBoolean(false); + + private static final Logger LOG = Logger.getInstance("#com.intellij.ui.mac.FindHeavyweightUnderCursorFix"); + + private static final Callback CB = new Callback() { + public void callback(ID self, + Pointer originalSelector, + Pointer selToPerform, + ID anObject, + ID withObject, + boolean waitUntilDone, + ID awtMode) { + String selectorName = Foundation.stringFromSelector(selToPerform); + //LOG.info("selectorName = " + selectorName); + if (FIX_ENABLED.get() && "findHeavyweightUnderCursor:".equals(selectorName)) { + return; + } + + Foundation.invoke(self, "oldPerformOnMainThread:onObject:withObject:waitUntilDone:awtMode:", selToPerform, anObject, withObject, waitUntilDone, awtMode); + } + }; + + static { + if (SystemInfo.isMac) { + ID threadUtilities = Foundation.getMetaClass("ThreadUtilities"); + ID originalMethod = Foundation.class_replaceMethod(threadUtilities, + Foundation + .createSelector("performOnMainThread:onObject:withObject:waitUntilDone:awtMode:"), + CB, "v@::@@B*"); + + if (!Foundation.addMethodByID(threadUtilities, + Foundation.createSelector("oldPerformOnMainThread:onObject:withObject:waitUntilDone:awtMode:"), originalMethod, + "v@::@@B*")) { + LOG.error("Unable to restore original behavior :("); + } + } + } + + private MacNativeMethodInterceptor() { + } +} 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 71f3be7c8683..d43059ccc2e3 100644 --- a/platform/util/src/com/intellij/ui/mac/foundation/Foundation.java +++ b/platform/util/src/com/intellij/ui/mac/foundation/Foundation.java @@ -20,6 +20,7 @@ import com.sun.jna.Callback; import com.sun.jna.Native; import com.sun.jna.Pointer; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.UnsupportedEncodingException; @@ -90,6 +91,24 @@ public class Foundation { return myFoundationLibrary.class_addMethod(cls, selectorName, impl, types); } + public static boolean addMethodByID(ID cls, Pointer selectorName, ID impl, String types) { + return myFoundationLibrary.class_addMethod(cls, selectorName, impl, types); + } + + public static boolean isMetaClass(ID cls) { + return myFoundationLibrary.class_isMetaClass(cls); + } + + @Nullable + public static String stringFromSelector(Pointer selector) { + ID id = myFoundationLibrary.NSStringFromSelector(selector); + if (id.intValue() > 0) { + return toStringViaUTF8(id); + } + + return null; + } + public static Pointer getClass(Pointer clazz) { return myFoundationLibrary.objc_getClass(clazz); } @@ -97,6 +116,14 @@ public class Foundation { public static String fullUserName() { return toStringViaUTF8(myFoundationLibrary.NSFullUserName()); } + + public static ID class_replaceMethod(ID cls, Pointer selector, Callback impl, String types) { + return myFoundationLibrary.class_replaceMethod(cls, selector, impl, types); + } + + public static ID getMetaClass(String className) { + return myFoundationLibrary.objc_getMetaClass(className); + } public static boolean isPackageAtPath(@NotNull final String path) { final ID workspace = invoke("NSWorkspace", "sharedWorkspace"); 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 4b1bcaff5786..1a7c540a902c 100644 --- a/platform/util/src/com/intellij/ui/mac/foundation/FoundationLibrary.java +++ b/platform/util/src/com/intellij/ui/mac/foundation/FoundationLibrary.java @@ -42,10 +42,20 @@ public interface FoundationLibrary extends Library { ID class_createInstance(ID pClass, int extraBytes); Pointer sel_registerName(String selectorName); + ID class_replaceMethod(ID cls, Pointer selName, Callback impl, String types); + + ID objc_getMetaClass(String name); + ID objc_msgSend(ID receiver, Pointer selector, Object... args); boolean class_respondsToSelector(ID cls, Pointer selName); boolean class_addMethod(ID cls, Pointer selName, Callback imp, String types); + + boolean class_addMethod(ID cls, Pointer selName, ID imp, String types); + + boolean class_isMetaClass(ID cls); + + ID NSStringFromSelector(Pointer selector); Pointer objc_getClass(Pointer clazz); }