/******************************************************************************* * Copyright (c) 2016 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.browsersim.widgets; /** * RedDeer display provider. * * @author Jiri Peterka * @author Lucia Jelinkova */ public class RDDisplay { private static org.eclipse.swt.widgets.Display display; private RDDisplay(){ super(); } /** * Returns {@link org.eclipse.swt.widgets.Display} instance. * * @return current Display instance or throws CoreLayerException if there is no display */ public static org.eclipse.swt.widgets.Display getDisplay() { //return org.eclipse.swt.widgets.Display.getDefault(); if ((display == null) || display.isDisposed()) { display = null; Thread[] allThreads = allThreads(); for (Thread thread : allThreads) { org.eclipse.swt.widgets.Display d = org.eclipse.swt.widgets.Display.findDisplay(thread); if (d != null && !d.isDisposed()) display = d; } if (display == null) throw new IllegalArgumentException("Could not find a display"); } return display; } /** * Run sync in UI thread without returning any result. * * @param runnable runnable */ public static void syncExec(Runnable runnable) { syncExec(new VoidResultRunnable(runnable)); } /** * Run sync in UI thread with ability to return result. * * @param <T> the generic type * @param runnable runnable * @return result of runnable */ @SuppressWarnings("unchecked") public static <T> T syncExec(final ResultRunnable<T> runnable) { ErrorHandlingRunnable<T> errorHandlingRunnable = new ErrorHandlingRunnable<T>(runnable); if (!isUIThread()) { RDDisplay.getDisplay().syncExec(errorHandlingRunnable); } else { if (runnable instanceof ErrorHandlingRunnable){ errorHandlingRunnable = (ErrorHandlingRunnable<T>) runnable; } errorHandlingRunnable.run(); } if (errorHandlingRunnable.exceptionOccurred()){ throw new IllegalArgumentException("Exception during sync execution in UI thread", errorHandlingRunnable.getException()); } return errorHandlingRunnable.getResult(); } /** * Run async in UI thread without returning any result. * * @param runnable runnable */ public static void asyncExec(Runnable runnable) { ErrorHandlingRunnable<Void> errorHandlingRunnable = new ErrorHandlingRunnable<Void>(new VoidResultRunnable(runnable)); getDisplay().asyncExec(errorHandlingRunnable); if (errorHandlingRunnable.exceptionOccurred()){ throw new IllegalArgumentException("Exception during async execution in UI thread", errorHandlingRunnable.getException()); } } private static boolean isUIThread() { return getDisplay().getThread() == Thread.currentThread(); } private static Thread[] allThreads() { ThreadGroup threadGroup = primaryThreadGroup(); Thread[] threads = new Thread[64]; int enumerate = threadGroup.enumerate(threads, true); Thread[] result = new Thread[enumerate]; System.arraycopy(threads, 0, result, 0, enumerate); return result; } private static ThreadGroup primaryThreadGroup() { ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); while (threadGroup.getParent() != null) threadGroup = threadGroup.getParent(); return threadGroup; } /** * Decorator around the {@link ResultRunnable} classes. Its purpose is to catch any exception from UI thread and store * it so it will be thrown in non UI thread. * * @author Lucia Jelinkova * * @param <T> */ private static class ErrorHandlingRunnable<T> implements Runnable { private ResultRunnable<T> runnable; private T result; private Exception exception; private ErrorHandlingRunnable(ResultRunnable<T> runnable) { super(); this.runnable = runnable; } @Override public void run() { try { result = runnable.run(); } catch (Exception e) { exception = e; } } public boolean exceptionOccurred(){ return getException() != null; } public Exception getException() { return exception; } public T getResult() { return result; } } /** * Wrapper class that converts {@link Runnable} to {@link ResultRunnable} * @author Lucia Jelinkova * */ private static class VoidResultRunnable implements ResultRunnable<Void> { private Runnable runnable; public VoidResultRunnable(Runnable runnable) { this.runnable = runnable; } @Override public Void run() { runnable.run(); return null; } } }