8037840: [macosx] Rewrite CWarning window to eliminate the ExecutorService
authorpchelko
Thu, 20 Mar 2014 16:58:58 +0400
changeset 23681 2044c9d2b681
parent 23680 e05b2a687849
child 23682 ab1324996bc7
8037840: [macosx] Rewrite CWarning window to eliminate the ExecutorService Reviewed-by: anthony, serb
jdk/src/macosx/classes/sun/lwawt/macosx/CWarningWindow.java
jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java
jdk/src/macosx/native/sun/awt/LWCToolkit.m
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CWarningWindow.java	Thu Mar 20 12:10:53 2014 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CWarningWindow.java	Thu Mar 20 16:58:58 2014 +0400
@@ -27,7 +27,6 @@
 
 import sun.awt.AWTAccessor;
 import sun.awt.IconInfo;
-import sun.awt.SunToolkit;
 import sun.java2d.SunGraphics2D;
 import sun.java2d.SurfaceData;
 import sun.java2d.opengl.CGLLayer;
@@ -39,17 +38,11 @@
 import java.awt.event.MouseEvent;
 import java.awt.geom.Point2D;
 import java.lang.ref.WeakReference;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
 
 public final class CWarningWindow extends CPlatformWindow
         implements SecurityWarningWindow, PlatformEventNotifier {
 
-    private static class Lock {};
+    private static class Lock {}
     private final Lock lock = new Lock();
 
     private final static int SHOWING_DELAY = 300;
@@ -97,7 +90,7 @@
     public CWarningWindow(final Window _ownerWindow, final LWWindowPeer _ownerPeer) {
         super();
 
-        this.ownerPeer = new WeakReference<LWWindowPeer>(_ownerPeer);
+        this.ownerPeer = new WeakReference<>(_ownerPeer);
         this.ownerWindow = _ownerWindow;
 
         initialize(null, null, _ownerPeer.getPlatformWindow());
@@ -122,16 +115,8 @@
     }
 
     public void setVisible(boolean visible, boolean doSchedule) {
-        synchronized (scheduler) {
-            if (showingTaskHandle != null) {
-                showingTaskHandle.cancel(false);
-                showingTaskHandle = null;
-            }
-
-            if (hidingTaskHandle != null) {
-                hidingTaskHandle.cancel(false);
-                hidingTaskHandle = null;
-            }
+        synchronized (taskLock) {
+            cancelTasks();
 
             if (visible) {
                 if (isVisible()) {
@@ -140,20 +125,18 @@
                     currentIcon = 2;
                 }
 
-                showingTaskHandle = scheduler.schedule(showingTask, 50,
-                        TimeUnit.MILLISECONDS);
-
+                showHideTask = new ShowingTask();
+                LWCToolkit.performOnMainThreadAfterDelay(showHideTask, 50);
             } else {
                 if (!isVisible()) {
                     return;
                 }
 
+                showHideTask = new HidingTask();
                 if (doSchedule) {
-                    hidingTaskHandle = scheduler.schedule(hidingTask, HIDING_DELAY,
-                            TimeUnit.MILLISECONDS);
+                    LWCToolkit.performOnMainThreadAfterDelay(showHideTask, HIDING_DELAY);
                 } else {
-                    hidingTaskHandle = scheduler.schedule(hidingTask, 50,
-                            TimeUnit.MILLISECONDS);
+                    LWCToolkit.performOnMainThreadAfterDelay(showHideTask, 50);
                 }
             }
         }
@@ -325,13 +308,19 @@
 
     @Override
     public void dispose() {
-        AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
-            scheduler.shutdown();
-            return null;
-        });
+        cancelTasks();
         super.dispose();
     }
 
+    private void cancelTasks() {
+        synchronized (taskLock) {
+            if (showHideTask != null) {
+                showHideTask.cancel();
+                showHideTask = null;
+            }
+        }
+    }
+
     private void updateIconSize() {
         int newSize = -1;
 
@@ -364,7 +353,7 @@
         }
     }
 
-    private final Graphics getGraphics() {
+    private Graphics getGraphics() {
         SurfaceData sd = contentView.getSurfaceData();
         if (ownerWindow == null || sd == null) {
             return null;
@@ -409,44 +398,59 @@
         return getSecurityIconInfo(currentSize, currentIcon);
     }
 
-    private final Runnable hidingTask = new Runnable() {
-        public void run() {
+    private final Lock taskLock = new Lock();
+    private CancelableRunnable showHideTask;
+
+    private static abstract class CancelableRunnable implements Runnable {
+        private volatile boolean perform = true;
+
+        public final void cancel() {
+            perform = false;
+        }
+
+        @Override
+        public final void run() {
+            if (perform) {
+                perform();
+            }
+        }
+
+        public abstract void perform();
+    }
+
+    private class HidingTask extends CancelableRunnable {
+        @Override
+        public void perform() {
             synchronized (lock) {
                 setVisible(false);
             }
 
-            synchronized (scheduler) {
-                hidingTaskHandle = null;
+            synchronized (taskLock) {
+                showHideTask = null;
             }
         }
-    };
+    }
 
-    private final Runnable showingTask = new Runnable() {
-        public void run() {
+    private class ShowingTask extends CancelableRunnable {
+        @Override
+        public void perform() {
             synchronized (lock) {
                 if (!isVisible()) {
                     setVisible(true);
                 }
-
                 repaint();
             }
 
-            synchronized (scheduler) {
+            synchronized (taskLock) {
                 if (currentIcon > 0) {
                     currentIcon--;
-                    showingTaskHandle = scheduler.schedule(showingTask, SHOWING_DELAY,
-                            TimeUnit.MILLISECONDS);
+                    showHideTask = new ShowingTask();
+                    LWCToolkit.performOnMainThreadAfterDelay(showHideTask, SHOWING_DELAY);
                 } else {
-                    showingTaskHandle = null;
+                    showHideTask = null;
                 }
             }
         }
-    };
-
-    private final ScheduledExecutorService scheduler =
-            Executors.newSingleThreadScheduledExecutor();
-
-    private ScheduledFuture hidingTaskHandle;
-    private ScheduledFuture showingTaskHandle;
+    }
 }
 
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java	Thu Mar 20 12:10:53 2014 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java	Thu Mar 20 16:58:58 2014 +0400
@@ -47,7 +47,6 @@
 import sun.lwawt.*;
 import sun.lwawt.LWWindowPeer.PeerType;
 import sun.security.action.GetBooleanAction;
-import sun.awt.image.MultiResolutionImage;
 
 import sun.util.CoreResourceBundleControl;
 
@@ -671,6 +670,13 @@
         throw new InvocationTargetException(eventException);
     }
 
+    /**
+     * Schedules a {@code Runnable} execution on the Appkit thread after a delay
+     * @param r a {@code Runnable} to execute
+     * @param delay a delay in milliseconds
+     */
+    native static void performOnMainThreadAfterDelay(Runnable r, long delay);
+
     // This exists purely to get around permissions issues with getSystemEventQueueImpl
     EventQueue getSystemEventQueueForInvokeAndWait() {
         return getSystemEventQueueImpl();
--- a/jdk/src/macosx/native/sun/awt/LWCToolkit.m	Thu Mar 20 12:10:53 2014 +0400
+++ b/jdk/src/macosx/native/sun/awt/LWCToolkit.m	Thu Mar 20 16:58:58 2014 +0400
@@ -82,6 +82,39 @@
 
 @end
 
+@interface JavaRunnable : NSObject { }
+@property jobject runnable;
+- (id)initWithRunnable:(jobject)gRunnable;
+- (void)perform;
+@end
+
+@implementation JavaRunnable
+@synthesize runnable = _runnable;
+
+- (id)initWithRunnable:(jobject)gRunnable {
+    if (self = [super init]) {
+        self.runnable = gRunnable;
+    }
+    return self;
+}
+
+- (void)dealloc {
+    JNIEnv *env = [ThreadUtilities getJNIEnv];
+    if (self.runnable) {
+        (*env)->DeleteGlobalRef(env, self.runnable);
+    }
+    [super dealloc];
+}
+
+- (void)perform {
+    JNIEnv* env = [ThreadUtilities getJNIEnv];
+    static JNF_CLASS_CACHE(sjc_Runnable, "java/lang/Runnable");
+    static JNF_MEMBER_CACHE(jm_Runnable_run, sjc_Runnable, "run", "()V");
+    JNFCallVoidMethod(env, self.runnable, jm_Runnable_run);
+    [self release];
+}
+@end
+
 /*
  * Class:     sun_lwawt_macosx_LWCToolkit
  * Method:    nativeSyncQueue
@@ -359,6 +392,25 @@
 
 /*
  * Class:     sun_lwawt_macosx_LWCToolkit
+ * Method:    performOnMainThreadAfterDelay
+ * Signature: (Ljava/lang/Runnable;J)V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_performOnMainThreadAfterDelay
+(JNIEnv *env, jclass clz, jobject runnable, jlong delay)
+{
+JNF_COCOA_ENTER(env);
+    jobject gRunnable = (*env)->NewGlobalRef(env, runnable);
+    CHECK_NULL(gRunnable);
+    [ThreadUtilities performOnMainThreadWaiting:NO block:^() {
+        JavaRunnable* performer = [[JavaRunnable alloc] initWithRunnable:gRunnable];
+        [performer performSelector:@selector(perform) withObject:nil afterDelay:(delay/1000.0)];
+    }];
+JNF_COCOA_EXIT(env);
+}
+
+
+/*
+ * Class:     sun_lwawt_macosx_LWCToolkit
  * Method:    isCapsLockOn
  * Signature: ()Z
  */
@@ -433,4 +485,3 @@
 {
 
 }
-