diff --git a/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index dc51373cc1b9fe24e76db5f6ad872f92cadf015c..3fb585bdb534f86b913d274528ec05f43954c007 100644 --- a/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -30,6 +30,7 @@ import java.awt.Dialog.ModalityType; import java.awt.event.*; import java.awt.peer.WindowPeer; import java.beans.*; +import java.lang.reflect.InvocationTargetException; import java.util.List; import javax.swing.*; @@ -861,7 +862,16 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo private void flushBuffers() { if (isVisible() && !nativeBounds.isEmpty()) { - LWCToolkit.getLWCToolkit().flushPendingEventsOnAppkit(target); + try { + LWCToolkit.invokeAndWait(new Runnable() { + @Override + public void run() { + //Posting an empty to flush the EventQueue without blocking the main thread + } + }, target); + } catch (InterruptedException | InvocationTargetException e) { + e.printStackTrace(); + } } } diff --git a/src/macosx/classes/sun/lwawt/macosx/CToolkitThreadBlockedHandler.java b/src/macosx/classes/sun/lwawt/macosx/CToolkitThreadBlockedHandler.java index 94a74e5174bf8f435d04ab6082e71a452e89fc68..6bc6cc7c41b0a71e3121b4e3668945b4e81902ce 100644 --- a/src/macosx/classes/sun/lwawt/macosx/CToolkitThreadBlockedHandler.java +++ b/src/macosx/classes/sun/lwawt/macosx/CToolkitThreadBlockedHandler.java @@ -25,27 +25,33 @@ package sun.lwawt.macosx; +import sun.awt.Mutex; import sun.awt.datatransfer.ToolkitThreadBlockedHandler; -final class CToolkitThreadBlockedHandler implements ToolkitThreadBlockedHandler { - private final LWCToolkit toolkit = (LWCToolkit)java.awt.Toolkit.getDefaultToolkit(); +final class CToolkitThreadBlockedHandler extends Mutex implements ToolkitThreadBlockedHandler { + private long awtRunLoopMediator = 0; + private final boolean processEvents; - public void lock() { - } - - public void unlock() { - } - - protected boolean isOwned() { - return false; + CToolkitThreadBlockedHandler() { + super(); + this.processEvents = true; } public void enter() { - // Execute the next AppKit event while we are waiting for system to - // finish our request - this will save us from biting our own tail - toolkit.executeNextAppKitEvent(); + if (!isOwned()) { + throw new IllegalMonitorStateException(); + } + awtRunLoopMediator = LWCToolkit.createAWTRunLoopMediator(); + unlock(); + LWCToolkit.doAWTRunLoop(awtRunLoopMediator, processEvents); + lock(); } public void exit() { + if (!isOwned()) { + throw new IllegalMonitorStateException(); + } + LWCToolkit.stopAWTRunLoop(awtRunLoopMediator); + awtRunLoopMediator = 0; } } diff --git a/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java index 801c3d41605061e2ab33935f56d67682ca44e634..83bc9f1f700ac53816dc1242b95346dfe66f101f 100644 --- a/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java +++ b/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java @@ -63,8 +63,6 @@ public final class LWCToolkit extends LWToolkit { private static native void initIDs(); - static native void executeNextAppKitEvent(); - private static CInputMethodDescriptor sInputMethodDescriptor; static { @@ -502,30 +500,6 @@ public final class LWCToolkit extends LWToolkit { synchronized(ret) { return ret[0]; } } - /** - * Just a wrapper for LWCToolkit.invokeAndWait. Posts an empty event to the - * appropriate event queue and waits for it to finish. - */ - public static void flushPendingEventsOnAppkit(final Component component) { - try { - invokeAndWait(new Runnable() { - @Override - public void run() { - } - }, component); - } catch (Exception e) { - e.printStackTrace(); - } - } - - // Kicks an event over to the appropriate eventqueue and waits for it to finish - // To avoid deadlocking, we manually run the NSRunLoop while waiting - // Any selector invoked using ThreadUtilities performOnMainThread will be processed in doAWTRunLoop - // The CInvocationEvent will call LWCToolkit.stopAWTRunLoop() when finished, which will stop our manual runloop - public static void invokeAndWait(Runnable event, Component component) throws InterruptedException, InvocationTargetException { - invokeAndWait(event, component, true); - } - public static T invokeAndWait(final Callable callable, Component component) throws Exception { final CallableWrapper wrapper = new CallableWrapper(callable); invokeAndWait(wrapper, component); @@ -555,10 +529,27 @@ public final class LWCToolkit extends LWToolkit { } } - public static void invokeAndWait(Runnable event, Component component, boolean detectDeadlocks) throws InterruptedException, InvocationTargetException { - long mediator = createAWTRunLoopMediator(); + // Kicks an event over to the appropriate eventqueue and waits for it to finish + // To avoid deadlocking, we manually run the NSRunLoop while waiting + // Any selector invoked using ThreadUtilities performOnMainThread will be processed in doAWTRunLoop + // The InvocationEvent will call LWCToolkit.stopAWTRunLoop() when finished, which will stop our manual runloop + // Does not dispatch native events while in the loop + public static void invokeAndWait(Runnable event, Component component) throws InterruptedException, InvocationTargetException { + final long mediator = createAWTRunLoopMediator(); - InvocationEvent invocationEvent = new CPeerEvent(event, mediator); + InvocationEvent invocationEvent = + new InvocationEvent(component != null ? component : Toolkit.getDefaultToolkit(), event) { + @Override + public void dispatch() { + try { + super.dispatch(); + } finally { + if (mediator != 0) { + stopAWTRunLoop(mediator); + } + } + } + }; if (component != null) { AppContext appContext = SunToolkit.targetToAppContext(component); @@ -571,7 +562,7 @@ public final class LWCToolkit extends LWToolkit { ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent); } - doAWTRunLoop(mediator, true, detectDeadlocks); + doAWTRunLoop(mediator, false); Throwable eventException = invocationEvent.getException(); if (eventException != null) { @@ -583,7 +574,8 @@ public final class LWCToolkit extends LWToolkit { } public static void invokeLater(Runnable event, Component component) throws InvocationTargetException { - final InvocationEvent invocationEvent = new CPeerEvent(event, 0); + final InvocationEvent invocationEvent = + new InvocationEvent(component != null ? component : Toolkit.getDefaultToolkit(), event); if (component != null) { final AppContext appContext = SunToolkit.targetToAppContext(component); @@ -688,31 +680,6 @@ public final class LWCToolkit extends LWToolkit { return false; } - // Extends PeerEvent because we want to pass long an ObjC mediator object and because we want these events to be posted early - // Typically, rather than relying on the notifier to call notifyAll(), we use the mediator to stop the runloop - public static class CPeerEvent extends PeerEvent { - private long _mediator = 0; - - public CPeerEvent(Runnable runnable, long mediator) { - super(Toolkit.getDefaultToolkit(), runnable, null, true, 0); - _mediator = mediator; - } - - public void dispatch() { - try { - super.dispatch(); - } finally { - if (_mediator != 0) { - LWCToolkit.stopAWTRunLoop(_mediator); - } - } - } - } - - // Call through to native methods - public static void doAWTRunLoop(long mediator, boolean awtMode) { doAWTRunLoop(mediator, awtMode, true); } - public static void doAWTRunLoop(long mediator) { doAWTRunLoop(mediator, true); } - private static Boolean sunAwtDisableCALayers = null; /** @@ -737,12 +704,20 @@ public final class LWCToolkit extends LWToolkit { * Native methods section ************************/ - // These are public because they are accessed from WebKitPluginObject in JavaDeploy - // Basic usage: - // createAWTRunLoopMediator. Start client code on another thread. doAWTRunLoop. When client code is finished, stopAWTRunLoop. - public static native long createAWTRunLoopMediator(); - public static native void doAWTRunLoop(long mediator, boolean awtMode, boolean detectDeadlocks); - public static native void stopAWTRunLoop(long mediator); + static native long createAWTRunLoopMediator(); + /** + * Method to run a nested run-loop. The nested loop is spinned in the javaRunLoop mode, so selectors sent + * by [JNFRunLoop performOnMainThreadWaiting] are processed. + * @param mediator a native pointer to the mediator object created by createAWTRunLoopMediator + * @param processEvents if true - dispatches event while in the nested loop. Used in DnD. + * Additional attention is needed when using this feature as we short-circuit normal event + * processing which could break Appkit. + * (One known example is when the window is resized with the mouse) + * + * if false - all events come after exit form the nested loop + */ + static native void doAWTRunLoop(long mediator, boolean processEvents); + static native void stopAWTRunLoop(long mediator); private native boolean nativeSyncQueue(long timeout); diff --git a/src/macosx/native/sun/awt/AWTView.m b/src/macosx/native/sun/awt/AWTView.m index cc16a2026ee233b53cb55859c06f3e47254c4d2c..7e1f248c7ed7e2258d6ffa65584188e2b1094710 100644 --- a/src/macosx/native/sun/awt/AWTView.m +++ b/src/macosx/native/sun/awt/AWTView.m @@ -227,7 +227,7 @@ AWT_ASSERT_APPKIT_THREAD; - (void) mouseMoved: (NSEvent *)event { // TODO: better way to redirect move events to the "under" view - + NSPoint eventLocation = [event locationInWindow]; NSPoint localPoint = [self convertPoint: eventLocation fromView: nil]; @@ -668,7 +668,7 @@ AWT_ASSERT_APPKIT_THREAD; - (void) setDropTarget:(CDropTarget *)target { self._dropTarget = target; - [ThreadUtilities performOnMainThread:@selector(controlModelControlValid) onObject:self._dropTarget withObject:nil waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(controlModelControlValid) on:self._dropTarget withObject:nil waitUntilDone:YES]; } /******************************** BEGIN NSDraggingSource Interface ********************************/ @@ -1215,7 +1215,7 @@ JNF_CLASS_CACHE(jc_CInputMethod, "sun/lwawt/macosx/CInputMethod"); fprintf(stderr, "AWTView InputMethod Selector Called : [abandonInput]\n"); #endif // IM_DEBUG - [ThreadUtilities performOnMainThread:@selector(markedTextAbandoned:) onObject:[NSInputManager currentInputManager] withObject:self waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(markedTextAbandoned:) on:[NSInputManager currentInputManager] withObject:self waitUntilDone:YES]; [self unmarkText]; } diff --git a/src/macosx/native/sun/awt/ApplicationDelegate.m b/src/macosx/native/sun/awt/ApplicationDelegate.m index 9a5aee94d44804e853fed1affa0c9a470e040170..6b584b21ca3c72754327f2a30a3648f42266ab44 100644 --- a/src/macosx/native/sun/awt/ApplicationDelegate.m +++ b/src/macosx/native/sun/awt/ApplicationDelegate.m @@ -567,10 +567,9 @@ JNIEXPORT void JNICALL Java_com_apple_eawt__1AppEventHandler_nativeRegisterForNo { JNF_COCOA_ENTER(env); [ThreadUtilities performOnMainThread:@selector(_registerForNotification:) - onObject:[ApplicationDelegate class] + on:[ApplicationDelegate class] withObject:[NSNumber numberWithInt:notificationType] - waitUntilDone:NO - awtMode:NO]; // AWT_THREADING Safe (non-blocking) + waitUntilDone:NO]; // AWT_THREADING Safe (non-blocking) JNF_COCOA_EXIT(env); } diff --git a/src/macosx/native/sun/awt/CClipboard.m b/src/macosx/native/sun/awt/CClipboard.m index fb300f729716754e6b6cbcf596e71c9680bd942d..bfba06b47d158bcac6fc2a46c54e6c6dc11c536f 100644 --- a/src/macosx/native/sun/awt/CClipboard.m +++ b/src/macosx/native/sun/awt/CClipboard.m @@ -120,7 +120,7 @@ static CClipboard *sClipboard = nil; fClipboardOwner = JNFNewGlobalRef(inEnv, inClipboard); } } - [ThreadUtilities performOnMainThread:@selector(_nativeDeclareTypes:) onObject:self withObject:inTypes waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(_nativeDeclareTypes:) on:self withObject:inTypes waitUntilDone:YES]; } - (void) _nativeDeclareTypes:(NSArray *)inTypes { @@ -135,7 +135,7 @@ static CClipboard *sClipboard = nil; - (NSArray *) javaGetTypes { NSMutableArray *args = [NSMutableArray arrayWithCapacity:1]; - [ThreadUtilities performOnMainThread:@selector(_nativeGetTypes:) onObject:self withObject:args waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(_nativeGetTypes:) on:self withObject:args waitUntilDone:YES]; //NSLog(@"CClipboard getTypes returns %@", [args lastObject]); return [args lastObject]; @@ -152,7 +152,7 @@ static CClipboard *sClipboard = nil; - (void) javaSetData:(NSData *)inData forType:(NSString *) inFormat { CClipboardUpdate *newUpdate = [[CClipboardUpdate alloc] initWithData:inData withFormat:inFormat]; - [ThreadUtilities performOnMainThread:@selector(_nativeSetData:) onObject:self withObject:newUpdate waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(_nativeSetData:) on:self withObject:newUpdate waitUntilDone:YES]; [newUpdate release]; //NSLog(@"CClipboard javaSetData forType %@", inFormat); @@ -170,7 +170,7 @@ static CClipboard *sClipboard = nil; - (NSData *) javaGetDataForType:(NSString *) inFormat { NSMutableArray *args = [NSMutableArray arrayWithObject:inFormat]; - [ThreadUtilities performOnMainThread:@selector(_nativeGetDataForType:) onObject:self withObject:args waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(_nativeGetDataForType:) on:self withObject:args waitUntilDone:YES]; //NSLog(@"CClipboard javaGetDataForType %@ returns an NSData", inFormat); return [args lastObject]; diff --git a/src/macosx/native/sun/awt/CDropTarget.m b/src/macosx/native/sun/awt/CDropTarget.m index 60cd7818254d4e8c17fa4e9fb2f1f5920c7a827a..9dda8ae3551c1a5b3fab8210ca3cc10894aabb2f 100644 --- a/src/macosx/native/sun/awt/CDropTarget.m +++ b/src/macosx/native/sun/awt/CDropTarget.m @@ -390,8 +390,7 @@ extern JNFClassInfo jc_CDropTargetContextPeer; // Release dragging data if any when Java's AWT event thread is all finished. // Make sure dragging data is released on the native event thread. - [ThreadUtilities performOnMainThread:@selector(safeReleaseDraggingData:) onObject:self - withObject:draggingSequenceNumberID waitUntilDone:NO awtMode:NO]; + [ThreadUtilities performOnMainThread:@selector(safeReleaseDraggingData:) on:self withObject:draggingSequenceNumberID waitUntilDone:NO]; } - (jint)currentJavaActions { diff --git a/src/macosx/native/sun/awt/CMenu.m b/src/macosx/native/sun/awt/CMenu.m index e6325c2c3db608607244c65ae6553cba83543968..8b643b3bca0dcc6c91299e2695ea7dc966a31a3a 100644 --- a/src/macosx/native/sun/awt/CMenu.m +++ b/src/macosx/native/sun/awt/CMenu.m @@ -55,11 +55,11 @@ AWT_ASSERT_APPKIT_THREAD; //- (void)finalize { [super finalize]; } - (void)addJavaSubmenu:(CMenu *)submenu { - [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) onObject:self withObject:submenu waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) on:self withObject:submenu waitUntilDone:YES]; } - (void)addJavaMenuItem:(CMenuItem *)theMenuItem { - [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) onObject:self withObject:theMenuItem waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) on:self withObject:theMenuItem waitUntilDone:YES]; } - (void)addNativeItem_OnAppKitThread:(CMenuItem *)itemModified { @@ -70,7 +70,7 @@ AWT_ASSERT_APPKIT_THREAD; - (void)setJavaMenuTitle:(NSString *)title { if (title) { - [ThreadUtilities performOnMainThread:@selector(setNativeMenuTitle_OnAppKitThread:) onObject:self withObject:title waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(setNativeMenuTitle_OnAppKitThread:) on:self withObject:title waitUntilDone:YES]; } } @@ -93,7 +93,7 @@ AWT_ASSERT_APPKIT_THREAD; - (void)deleteJavaItem:(jint)index { - [ThreadUtilities performOnMainThread:@selector(deleteNativeJavaItem_OnAppKitThread:) onObject:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(deleteNativeJavaItem_OnAppKitThread:) on:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES]; } - (void)deleteNativeJavaItem_OnAppKitThread:(NSNumber *)number { @@ -139,7 +139,7 @@ CMenu * createCMenu (jobject cPeerObjGlobal) { // We use an array here only to be able to get a return value NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], nil]; - [ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) onObject:[CMenu alloc] withObject:args waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) on:[CMenu alloc] withObject:args waitUntilDone:YES]; aCMenu = (CMenu *)[args objectAtIndex: 0]; diff --git a/src/macosx/native/sun/awt/CMenuBar.m b/src/macosx/native/sun/awt/CMenuBar.m index 23c794961894763e8e5bf0dffad660f4816f3f6d..b0d67f71a2a40c3adcc378ac72d2b60f89856533 100644 --- a/src/macosx/native/sun/awt/CMenuBar.m +++ b/src/macosx/native/sun/awt/CMenuBar.m @@ -197,7 +197,7 @@ static BOOL sSetupHelpMenu = NO; if (self == sActiveMenuBar) { NSArray *args = [[NSArray alloc] initWithObjects:theMenu, [NSNumber numberWithInt:-1], nil]; - [ThreadUtilities performOnMainThread:@selector(nativeAddMenuAtIndex_OnAppKitThread:) onObject:self withObject:args waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(nativeAddMenuAtIndex_OnAppKitThread:) on:self withObject:args waitUntilDone:YES]; [args release]; } } @@ -216,7 +216,7 @@ static BOOL sSetupHelpMenu = NO; if (self == sActiveMenuBar) { NSArray *args = [[NSArray alloc] initWithObjects:theMenu, [NSNumber numberWithInt:index], nil]; - [ThreadUtilities performOnMainThread:@selector(nativeAddMenuAtIndex_OnAppKitThread:) onObject:self withObject:args waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(nativeAddMenuAtIndex_OnAppKitThread:) on:self withObject:args waitUntilDone:YES]; [args release]; } } @@ -286,7 +286,7 @@ static BOOL sSetupHelpMenu = NO; - (void) javaDeleteMenu: (jint)index { if (self == sActiveMenuBar) { - [ThreadUtilities performOnMainThread:@selector(nativeDeleteMenu_OnAppKitThread:) onObject:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(nativeDeleteMenu_OnAppKitThread:) on:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES]; } @synchronized(self) { @@ -388,7 +388,7 @@ Java_sun_lwawt_macosx_CMenuBar_nativeCreateMenuBar // We use an array here only to be able to get a return value NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], nil]; - [ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) onObject:[CMenuBar alloc] withObject:args waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) on:[CMenuBar alloc] withObject:args waitUntilDone:YES]; aCMenuBar = (CMenuBar *)[args objectAtIndex: 0]; diff --git a/src/macosx/native/sun/awt/CMenuItem.m b/src/macosx/native/sun/awt/CMenuItem.m index 2281d8bcd959db244dbd60e4b92410f68e47d66b..b67c70658dd5259435ed1c9e4c28e499796401a5 100644 --- a/src/macosx/native/sun/awt/CMenuItem.m +++ b/src/macosx/native/sun/awt/CMenuItem.m @@ -386,7 +386,7 @@ JNF_COCOA_ENTER(env); args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], [NSNumber numberWithBool:NO], nil]; } - [ThreadUtilities performOnMainThread:@selector(_createMenuItem_OnAppKitThread:) onObject:[CMenuItem alloc] withObject:args waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(_createMenuItem_OnAppKitThread:) on:[CMenuItem alloc] withObject:args waitUntilDone:YES]; aCMenuItem = (CMenuItem *)[args objectAtIndex: 0]; diff --git a/src/macosx/native/sun/awt/JavaComponentAccessibility.m b/src/macosx/native/sun/awt/JavaComponentAccessibility.m index f886c4afbe17610ee0afbb0b7c59cfdc2441c548..a01bd781faaebad0aed32edaf21c5abc3ab39882 100644 --- a/src/macosx/native/sun/awt/JavaComponentAccessibility.m +++ b/src/macosx/native/sun/awt/JavaComponentAccessibility.m @@ -1113,18 +1113,10 @@ static NSObject *sAttributeNamesLOCK = nil; JNIEnv *env = [ThreadUtilities getJNIEnv]; id value = nil; - // This code frequently gets called indirectly by Java when VoiceOver is active. - // Basically, we just have to know when we going to be a bad state, and do something "special". - // Note that while NSApplication isn't technically correct, we post a focus changed notification - // (which will call this method, but with the correct codepath) shortly afterwards. See +postFocusChanged. - if (sInPerformFromJava) { - return [NSApplication sharedApplication]; - } else { - jobject focused = JNFCallStaticObjectMethod(env, jm_getFocusOwner, fComponent); // AWT_THREADING Safe (AWTRunLoop) - if (focused != NULL) { - if (JNFIsInstanceOf(env, focused, &sjc_Accessible)) { - value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView]; - } + jobject focused = JNFCallStaticObjectMethod(env, jm_getFocusOwner, fComponent); // AWT_THREADING Safe (AWTRunLoop) + if (focused != NULL) { + if (JNFIsInstanceOf(env, focused, &sjc_Accessible)) { + value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView]; } } @@ -1149,7 +1141,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessibility_focusChanged { JNF_COCOA_ENTER(env); - [ThreadUtilities performOnMainThread:@selector(postFocusChanged:) onObject:[JavaComponentAccessibility class] withObject:nil waitUntilDone:NO awtMode:NO]; + [ThreadUtilities performOnMainThread:@selector(postFocusChanged:) on:[JavaComponentAccessibility class] withObject:nil waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -1164,7 +1156,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_valueChanged (JNIEnv *env, jclass jklass, jlong element) { JNF_COCOA_ENTER(env); - [ThreadUtilities performOnMainThread:@selector(postValueChanged) onObject:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO awtMode:NO]; + [ThreadUtilities performOnMainThread:@selector(postValueChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -1177,7 +1169,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectionChanged (JNIEnv *env, jclass jklass, jlong element) { JNF_COCOA_ENTER(env); - [ThreadUtilities performOnMainThread:@selector(postSelectionChanged) onObject:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO awtMode:NO]; + [ThreadUtilities performOnMainThread:@selector(postSelectionChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -1191,7 +1183,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_unregisterFromCocoaAXSy (JNIEnv *env, jclass jklass, jlong element) { JNF_COCOA_ENTER(env); - [ThreadUtilities performOnMainThread:@selector(unregisterFromCocoaAXSystem) onObject:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO awtMode:NO]; + [ThreadUtilities performOnMainThread:@selector(unregisterFromCocoaAXSystem) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO]; JNF_COCOA_EXIT(env); } diff --git a/src/macosx/native/sun/awt/LWCToolkit.m b/src/macosx/native/sun/awt/LWCToolkit.m index 45c546181f0374698f4d06aa775662134d1c1fdc..ec4870eba6952c1f1d2c7aa66de90b46567324e9 100644 --- a/src/macosx/native/sun/awt/LWCToolkit.m +++ b/src/macosx/native/sun/awt/LWCToolkit.m @@ -332,7 +332,7 @@ AWT_ASSERT_APPKIT_THREAD; * Signature: (JZZ)V */ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_doAWTRunLoop -(JNIEnv *env, jclass clz, jlong mediator, jboolean awtMode, jboolean detectDeadlocks) +(JNIEnv *env, jclass clz, jlong mediator, jboolean processEvents) { AWT_ASSERT_APPKIT_THREAD; JNF_COCOA_ENTER(env); @@ -341,26 +341,25 @@ JNF_COCOA_ENTER(env); if (mediatorObject == nil) return; - if (!sInPerformFromJava || !detectDeadlocks) { - - NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; - NSDate *distantFuture = [NSDate distantFuture]; - NSString *mode = (awtMode) ? [JNFRunLoop javaRunLoopMode] : NSDefaultRunLoopMode; + // Don't use acceptInputForMode because that doesn't setup autorelease pools properly + BOOL isRunning = true; + while (![mediatorObject shouldEndRunLoop] && isRunning) { + isRunning = [[NSRunLoop currentRunLoop] runMode:[JNFRunLoop javaRunLoopMode] + beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.010]]; + if (processEvents) { + //We do not spin a runloop here as date is nil, so does not matter which mode to use + NSEvent *event; + if ((event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:nil + inMode:NSDefaultRunLoopMode + dequeue:YES]) != nil) { + [NSApp sendEvent:event]; + } - BOOL isRunning = YES; - while (isRunning && ![mediatorObject shouldEndRunLoop]) { - // Don't use acceptInputForMode because that doesn't setup autorelease pools properly - isRunning = [currentRunLoop runMode:mode beforeDate:distantFuture]; } - } -#ifndef PRODUCT_BUILD - if (sInPerformFromJava) { - NSLog(@"Apple AWT: Short-circuiting CToolkit.invokeAndWait trampoline deadlock!!!!!"); - NSLog(@"\tPlease file a bug report with this message and a reproducible test case."); - } -#endif + CFRelease(mediatorObject); JNF_COCOA_EXIT(env); @@ -379,7 +378,7 @@ JNF_COCOA_ENTER(env); AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator); - [ThreadUtilities performOnMainThread:@selector(endRunLoop) onObject:mediatorObject withObject:nil waitUntilDone:NO awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(endRunLoop) on:mediatorObject withObject:nil waitUntilDone:NO]; CFRelease(mediatorObject); @@ -463,20 +462,3 @@ Java_sun_font_FontManager_populateFontFileNameMap } -/* - * Class: sun_lwawt_macosx_LWCToolkit - * Method: executeNextAppKitEvent - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_executeNextAppKitEvent -(JNIEnv *env, jclass cls) -{ - // Simply get the next event in native loop and pass it to execution - // We'll be called repeatedly so there's no need to block here - NSRunLoop *theRL = [NSRunLoop currentRunLoop]; - NSApplication * app = [NSApplication sharedApplication]; - NSEvent * event = [app nextEventMatchingMask: 0xFFFFFFFF untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES]; - if (event != nil) { - [app sendEvent: event]; - } -} diff --git a/src/macosx/native/sun/osxapp/ThreadUtilities.h b/src/macosx/native/sun/osxapp/ThreadUtilities.h index c0d2054f6e30c4d001376b7a83409ba76ddc4fcc..2ee65e94c65c349db7e49353886d88310ec797f7 100644 --- a/src/macosx/native/sun/osxapp/ThreadUtilities.h +++ b/src/macosx/native/sun/osxapp/ThreadUtilities.h @@ -122,19 +122,12 @@ do { \ #endif /* AWT_THREAD_ASSERTS */ // -------------------------------------------------------------------------- -// This tracks if we are current inside of a performOnMainThread that is both waiting and in the AWTRunLoopMode -extern BOOL sInPerformFromJava; - -// This is an empty Obj-C object just so that -performSelectorOnMainThread -// can be used, and to use the Obj-C +initialize feature. __attribute__((visibility("default"))) -@interface ThreadUtilities : NSObject { } +@interface ThreadUtilities { } + (JNIEnv*)getJNIEnv; + (JNIEnv*)getJNIEnvUncached; -+ (void)performOnMainThread:(SEL)aSelector onObject:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait awtMode:(BOOL)inAWT; - //Wrappers for the corresponding JNFRunLoop methods with a check for main thread + (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block; + (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait; diff --git a/src/macosx/native/sun/osxapp/ThreadUtilities.m b/src/macosx/native/sun/osxapp/ThreadUtilities.m index 0b42f1b5896ee648b78bcb848ea9decdf22b4baf..d431386bbdbc4452597c2fbe610d20b245330367 100644 --- a/src/macosx/native/sun/osxapp/ThreadUtilities.m +++ b/src/macosx/native/sun/osxapp/ThreadUtilities.m @@ -34,85 +34,6 @@ JavaVM *jvm = NULL; static JNIEnv *appKitEnv = NULL; -static NSArray *sPerformModes = nil; -static NSArray *sAWTPerformModes = nil; - -static BOOL sLoggingEnabled = YES; - -#ifdef AWT_THREAD_ASSERTS_ENV_ASSERT -int sAWTThreadAsserts = 0; -#endif /* AWT_THREAD_ASSERTS_ENV_ASSERT */ - -BOOL sInPerformFromJava = NO; - -// This class is used so that performSelectorOnMainThread can be -// controlled a little more easily by us. It has 2 roles. -// The first is to set/unset a flag (sInPerformFromJava) that code can -// check to see if we are in a synchronous perform initiated by a java thread. -// The second is to implement the CocoaComponent backward compatibility mode. -@interface CPerformer : NSObject { - id fTarget; - SEL fSelector; - id fArg; - BOOL fWait; -} - -- (id) initWithTarget:(id)target selector:(SEL)selector arg:(id)arg wait:(BOOL)wait; -- (void) perform; -@end - - -@implementation CPerformer - -- (id) initWithTarget:(id)target selector:(SEL)selector arg:(id)arg { - return [self initWithTarget:target selector:selector arg:arg wait:YES]; -} - -- (id) initWithTarget:(id)target selector:(SEL)selector arg:(id)arg wait:(BOOL)wait { - self = [super init]; - if (self != nil) { - fTarget = [target retain]; - fSelector = selector; - fArg = [arg retain]; - // Only set sInPerformFromJava if this is a synchronous perform - fWait = wait; - } - return self; -} - -- (void) dealloc { - [fTarget release]; - [fArg release]; - [super dealloc]; -} -//- (void)finalize { [super finalize]; } - -- (void) perform { - AWT_ASSERT_APPKIT_THREAD; - - // If this is the first time we're going from java thread -> appkit thread, - // set sInPerformFromJava for the duration of the invocation - BOOL nestedPerform = sInPerformFromJava; - if (fWait) { - sInPerformFromJava = YES; - } - - // Actually do the work (cheat to avoid a method call) - @try { - objc_msgSend(fTarget, fSelector, fArg); - //[fTarget performSelector:fSelector withObject:fArg]; - } @catch (NSException *e) { - NSLog(@"*** CPerformer: ignoring exception '%@' raised during perform of selector '%@' on target '%@' with args '%@'", e, NSStringFromSelector(fSelector), fTarget, fArg); - } @finally { - // If we actually set sInPerformFromJava, unset it now - if (!nestedPerform && fWait) { - sInPerformFromJava = NO; - } - } -} -@end - - @implementation ThreadUtilities + (JNIEnv*)getJNIEnv { @@ -129,36 +50,6 @@ AWT_ASSERT_APPKIT_THREAD; return env; } -+ (void)initialize { - // Headless: BOTH - // Embedded: BOTH - // Multiple Calls: NO - // Caller: Obj-C class initialization - // Thread: ? - - if (sPerformModes == nil) { - // Create list of Run Loop modes to perform on - // The default performSelector, with no mode argument, runs in Default, - // ModalPanel, and EventTracking modes - sPerformModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode, NSModalPanelRunLoopMode, nil]; - sAWTPerformModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode, NSModalPanelRunLoopMode, NSEventTrackingRunLoopMode, [JNFRunLoop javaRunLoopMode], nil]; - -#ifdef AWT_THREAD_ASSERTS_ENV_ASSERT - sAWTThreadAsserts = (getenv("COCOA_AWT_DISABLE_THREAD_ASSERTS") == NULL); -#endif /* AWT_THREAD_ASSERTS_ENV_ASSERT */ - } -} - -// These methods can behave slightly differently than the normal -// performSelector... In particular, we define a special runloop mode -// (AWTRunLoopMode) so that we can "block" the main thread against the -// java event thread without deadlocking. See CToolkit.invokeAndWait. -+ (void)performOnMainThread:(SEL)aSelector onObject:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait awtMode:(BOOL)inAWT { - CPerformer *performer = [[CPerformer alloc] initWithTarget:target selector:aSelector arg:arg wait:wait]; - [performer performSelectorOnMainThread:@selector(perform) withObject:nil waitUntilDone:wait modes:((inAWT) ? sAWTPerformModes : sPerformModes)]; // AWT_THREADING Safe (cover method) - [performer release]; -} - + (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block { if ([NSThread isMainThread] && wait == YES) { block();