/* * Copyright (c) 2014, Michael Grossmann * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the jo-widgets.org nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL jo-widgets.org BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ package org.jowidgets.tools.osx; import java.lang.reflect.Method; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import org.jowidgets.util.Assert; /** * A workaround to deal with the problem that swt applications started with webstart * won't work on mac os x under some circumstances even if -XstartOnFirstThread was set * in the jnlp (for me java 7_51, swt-mac-osx-64-4.3). * * Remark: This workaround only works for os x on a mac and it depends on * non public api that may be changed. But for now it works and may be the * problem described may be fixed in future releases :-) */ public final class OsxMainThreadExecutor { private OsxMainThreadExecutor() {} /** * Runs a given application in the mac os x main thread and makes the vm argument * -XstartOnFirstThread obsolete. * * Remark: This is a workaround that depends on non public api * * @param runnable The runnable that runs the application and the swt event loop. * This runnable has to block until the application was finished */ public static void runAppInOsxMainThread(final Runnable runnable) { Assert.paramNotNull(runnable, "runnable"); try { //maybe the thread is already correct, so first try to start normally runnable.run(); } catch (final Exception e) { //CHECKSTYLE:OFF System.out.println("*** Ignore warning about wrong thread by now and try it in the main thread"); //CHECKSTYLE:ON final CountDownLatch latch = new CountDownLatch(1); getOsxNonBlockingMainExecutor().execute(new Runnable() { @Override public void run() { try { //this starts the swt event loop and blocks until main shell will closed runnable.run(); } finally { //ensure that the execution thread not blocks on exceptions latch.countDown(); } } }); try { //wait until the application has been finished latch.await(); } catch (final InterruptedException e2) { throw new RuntimeException(e2); } } } /** * Gets the NonBlockingMainExecutor of os x. * * This will be done by reflection do make it possible to compile this code on all platforms. * * @return The executor or null, if no executor can be created (e.g. not a mac jvm or api changed) */ private static Executor getOsxNonBlockingMainExecutor() { try { final Class<?> dispatchClass = Class.forName("com.apple.concurrent.Dispatch"); final Method getInstanceMethod = dispatchClass.getMethod("getInstance"); final Object dispatchInstance = getInstanceMethod.invoke(null); final Method getExecutorMethod = dispatchClass.getMethod("getNonBlockingMainQueueExecutor"); return (Executor) getExecutorMethod.invoke(dispatchInstance); } catch (final Exception e) { throw new RuntimeException("*** Cannot get os x main thread executor", e); } } }