# HG changeset patch # User leonidr # Date 1373552595 -14400 # Node ID 438afe2fc852b4f2554807a140f992033e1b9496 # Parent 678de8e7eb93a316b7374b1170a611c7e2c763ba 8020038: [macosx] Incorrect usage of invokeLater() and likes in callbacks called via JNI from AppKit thread Reviewed-by: art, anthony diff -r 678de8e7eb93 -r 438afe2fc852 jdk/src/macosx/classes/com/apple/eawt/FullScreenHandler.java --- a/jdk/src/macosx/classes/com/apple/eawt/FullScreenHandler.java Thu Jul 11 16:42:13 2013 +0400 +++ b/jdk/src/macosx/classes/com/apple/eawt/FullScreenHandler.java Thu Jul 11 18:23:15 2013 +0400 @@ -32,6 +32,7 @@ import javax.swing.RootPaneContainer; import com.apple.eawt.AppEvent.FullScreenEvent; +import sun.awt.SunToolkit; import java.lang.annotation.Native; @@ -75,7 +76,7 @@ static void handleFullScreenEventFromNative(final Window window, final int type) { if (!(window instanceof RootPaneContainer)) return; // handles null - EventQueue.invokeLater(new Runnable() { + SunToolkit.executeOnEventHandlerThread(window, new Runnable() { public void run() { final FullScreenHandler handler = getHandlerFor((RootPaneContainer)window); if (handler != null) handler.notifyListener(new FullScreenEvent(window), type); diff -r 678de8e7eb93 -r 438afe2fc852 jdk/src/macosx/classes/com/apple/eawt/_AppEventHandler.java --- a/jdk/src/macosx/classes/com/apple/eawt/_AppEventHandler.java Thu Jul 11 16:42:13 2013 +0400 +++ b/jdk/src/macosx/classes/com/apple/eawt/_AppEventHandler.java Thu Jul 11 18:23:15 2013 +0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,8 @@ import java.net.*; import java.util.*; import java.util.List; +import sun.awt.AppContext; +import sun.awt.SunToolkit; import com.apple.eawt.AppEvent.*; @@ -269,11 +271,9 @@ } class _AppReOpenedDispatcher extends _AppEventMultiplexor { - void performOnListeners(final List listeners, final _NativeEvent event) { + void performOnListener(AppReOpenedListener listener, final _NativeEvent event) { final AppReOpenedEvent e = new AppReOpenedEvent(); - for (final AppReOpenedListener listener : listeners) { - listener.appReOpened(e); - } + listener.appReOpened(e); } } @@ -415,50 +415,67 @@ } abstract class _AppEventMultiplexor { - final List _listeners = new ArrayList(0); + private final Map listenerToAppContext = + new IdentityHashMap(); boolean nativeListenerRegistered; // called from AppKit Thread-0 void dispatch(final _NativeEvent event, final Object... args) { - // grab a local ref to the listeners - final List localListeners; + // grab a local ref to the listeners and its contexts as an array of the map's entries + final ArrayList> localEntries; synchronized (this) { - if (_listeners.size() == 0) return; - localListeners = new ArrayList(_listeners); + if (listenerToAppContext.size() == 0) { + return; + } + localEntries = new ArrayList>(listenerToAppContext.size()); + localEntries.addAll(listenerToAppContext.entrySet()); } - EventQueue.invokeLater(new Runnable() { - public void run() { - performOnListeners(localListeners, event); - } - }); + for (final Map.Entry e : localEntries) { + final L listener = e.getKey(); + final AppContext listenerContext = e.getValue(); + SunToolkit.invokeLaterOnAppContext(listenerContext, new Runnable() { + public void run() { + performOnListener(listener, event); + } + }); + } } synchronized void addListener(final L listener) { + setListenerContext(listener, AppContext.getAppContext()); + if (!nativeListenerRegistered) { registerNativeListener(); nativeListenerRegistered = true; } - _listeners.add(listener); } synchronized void removeListener(final L listener) { - _listeners.remove(listener); + listenerToAppContext.remove(listener); } - abstract void performOnListeners(final List listeners, final _NativeEvent event); + abstract void performOnListener(L listener, final _NativeEvent event); void registerNativeListener() { } + + private void setListenerContext(L listener, AppContext listenerContext) { + if (listenerContext == null) { + throw new RuntimeException( + "Attempting to add a listener from a thread group without AppContext"); + } + listenerToAppContext.put(listener, AppContext.getAppContext()); + } } abstract class _BooleanAppEventMultiplexor extends _AppEventMultiplexor { @Override - void performOnListeners(final List listeners, final _NativeEvent event) { + void performOnListener(L listener, final _NativeEvent event) { final boolean isTrue = Boolean.TRUE.equals(event.get(0)); final E e = createEvent(isTrue); if (isTrue) { - for (final L listener : listeners) performTrueEventOn(listener, e); + performTrueEventOn(listener, e); } else { - for (final L listener : listeners) performFalseEventOn(listener, e); + performFalseEventOn(listener, e); } } @@ -479,30 +496,34 @@ */ abstract class _AppEventDispatcher { H _handler; + AppContext handlerContext; // called from AppKit Thread-0 void dispatch(final _NativeEvent event) { - EventQueue.invokeLater(new Runnable() { - public void run() { - // grab a local ref to the handler - final H localHandler; - synchronized (_AppEventDispatcher.this) { - localHandler = _handler; - } + // grab a local ref to the handler + final H localHandler; + final AppContext localHandlerContext; + synchronized (_AppEventDispatcher.this) { + localHandler = _handler; + localHandlerContext = handlerContext; + } - // invoke the handler outside of the synchronized block - if (localHandler == null) { - performDefaultAction(event); - } else { + if (localHandler == null) { + performDefaultAction(event); + } else { + SunToolkit.invokeLaterOnAppContext(localHandlerContext, new Runnable() { + public void run() { performUsing(localHandler, event); } - } - }); + }); + } } synchronized void setHandler(final H handler) { this._handler = handler; + setHandlerContext(AppContext.getAppContext()); + // if a new handler is installed, block addition of legacy ApplicationListeners if (handler == legacyHandler) return; legacyHandler.blockLegacyAPI(); @@ -510,6 +531,15 @@ void performDefaultAction(final _NativeEvent event) { } // by default, do nothing abstract void performUsing(final H handler, final _NativeEvent event); + + protected void setHandlerContext(AppContext ctx) { + if (ctx == null) { + throw new RuntimeException( + "Attempting to set a handler from a thread group without AppContext"); + } + + handlerContext = ctx; + } } abstract class _QueuingAppEventDispatcher extends _AppEventDispatcher { @@ -531,6 +561,8 @@ synchronized void setHandler(final H handler) { this._handler = handler; + setHandlerContext(AppContext.getAppContext()); + // dispatch any events in the queue if (queuedEvents != null) { // grab a local ref to the queue, so the real one can be nulled out diff -r 678de8e7eb93 -r 438afe2fc852 jdk/src/macosx/classes/com/apple/eawt/event/GestureHandler.java --- a/jdk/src/macosx/classes/com/apple/eawt/event/GestureHandler.java Thu Jul 11 16:42:13 2013 +0400 +++ b/jdk/src/macosx/classes/com/apple/eawt/event/GestureHandler.java Thu Jul 11 18:23:15 2013 +0400 @@ -25,6 +25,8 @@ package com.apple.eawt.event; +import sun.awt.SunToolkit; + import java.awt.*; import java.util.*; import java.util.List; @@ -70,7 +72,7 @@ static void handleGestureFromNative(final Window window, final int type, final double x, final double y, final double a, final double b) { if (window == null) return; // should never happen... - EventQueue.invokeLater(new Runnable() { + SunToolkit.executeOnEventHandlerThread(window, new Runnable() { public void run() { final Component component = SwingUtilities.getDeepestComponentAt(window, (int)x, (int)y); diff -r 678de8e7eb93 -r 438afe2fc852 jdk/src/macosx/classes/com/apple/laf/ScreenMenu.java --- a/jdk/src/macosx/classes/com/apple/laf/ScreenMenu.java Thu Jul 11 16:42:13 2013 +0400 +++ b/jdk/src/macosx/classes/com/apple/laf/ScreenMenu.java Thu Jul 11 18:23:15 2013 +0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import javax.swing.*; +import sun.awt.SunToolkit; import sun.lwawt.LWToolkit; import sun.lwawt.macosx.*; @@ -144,7 +145,7 @@ updateItems(); fItemBounds = new Rectangle[invoker.getMenuComponentCount()]; } - }, null); + }, invoker); } catch (final Exception e) { System.err.println(e); e.printStackTrace(); @@ -172,7 +173,7 @@ fItemBounds = null; } - }, null); + }, invoker); } catch (final Exception e) { e.printStackTrace(); } @@ -200,7 +201,7 @@ if (kind == 0) return; if (fItemBounds == null) return; - SwingUtilities.invokeLater(new Runnable() { + SunToolkit.executeOnEventHandlerThread(fInvoker, new Runnable() { @Override public void run() { Component target = null; diff -r 678de8e7eb93 -r 438afe2fc852 jdk/src/macosx/classes/sun/lwawt/macosx/CCheckboxMenuItem.java --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CCheckboxMenuItem.java Thu Jul 11 16:42:13 2013 +0400 +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CCheckboxMenuItem.java Thu Jul 11 18:23:15 2013 +0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ public void handleAction(final boolean state) { final CheckboxMenuItem target = (CheckboxMenuItem)getTarget(); - EventQueue.invokeLater(new Runnable() { + SunToolkit.executeOnEventHandlerThread(target, new Runnable() { public void run() { target.setState(state); } diff -r 678de8e7eb93 -r 438afe2fc852 jdk/src/macosx/classes/sun/lwawt/macosx/CViewEmbeddedFrame.java --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CViewEmbeddedFrame.java Thu Jul 11 16:42:13 2013 +0400 +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CViewEmbeddedFrame.java Thu Jul 11 18:23:15 2013 +0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,7 +96,7 @@ validate(); setVisible(true); } - }, null); + }, this); } catch (InterruptedException | InvocationTargetException ex) {} } }