/* * AwtRunnableQueue.java - Queue for task to run in the Event Dispatch Thread * :tabSize=4:indentSize=4:noTabs=false: * :folding=explicit:collapseFolds=1: * * Copyright (C) 2012 Thomas Meyer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.gjt.sp.util; import java.awt.EventQueue; import java.util.LinkedList; import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.ThreadSafe; /** * A queue for runnables that should run in the EDT after all pending * IO tasks are finished * @author Thomas Meyer * @since jEdit 5.1pre1 */ @ThreadSafe public enum AwtRunnableQueue { INSTANCE; @GuardedBy("this") private boolean awtQueueStarted; @GuardedBy("this") private boolean awtRunnerQueued; @GuardedBy("this") private final LinkedList<Runnable> awtQueue; //{{{ Constructor method private AwtRunnableQueue() { awtQueue = new LinkedList<Runnable>(); } //}}} //{{{ start() method /** * Queue the AWT runner for the first time. */ public void start() { synchronized (this) { awtQueueStarted = true; } queueAWTRunner(false); } //}}} //{{{ runAfterIoTasks() method /** * Adds a runnable to the AWT queue to run in the EDT * after all pending IO tasks are finished * @param run The runnable to queue for execution in the EDT after all IO tasks */ public void runAfterIoTasks(Runnable run) { boolean runDirectly = false; //{{{ if there are no requests, execute AWT requests immediately synchronized (this) { if(awtQueueStarted && TaskManager.instance.countIoTasks() == 0 && awtQueue.isEmpty()) runDirectly = true; } if(runDirectly) { // Log.log(Log.DEBUG,this,"AWT immediate: " + run); ThreadUtilities.runInDispatchThread(run); return; } //}}} synchronized (this) { awtQueue.offer(run); } // queue AWT request queueAWTRunner(false); } //}}} //{{{ queueAWTRunner() method public void queueAWTRunner(boolean wait) { if(wait) ThreadUtilities.runInDispatchThreadAndWait(new RunRequestsInAWTThread()); else { synchronized (this) { if(awtQueue.isEmpty()) return; if(!awtQueueStarted || awtRunnerQueued) return; awtRunnerQueued = true; } EventQueue.invokeLater(new RunRequestsInAWTThread()); // Log.log(Log.DEBUG,this,"AWT runner queued"); } } //}}} //{{{ RunRequestsInAWTThread class private class RunRequestsInAWTThread implements Runnable { public void run() { Runnable nextRunnable; // enable queuing of AWT runner again synchronized (AwtRunnableQueue.this) { awtRunnerQueued = false; nextRunnable = awtQueue.peek(); } while(TaskManager.instance.countIoTasks() == 0 && nextRunnable != null) { doAWTRequest(nextRunnable); synchronized (AwtRunnableQueue.this) { // consume current entry awtQueue.poll(); nextRunnable = awtQueue.peek(); } } } //{{{ doAWTRequest() method /** * Actually run the Runnable * @param request the request to run */ private void doAWTRequest(Runnable request) { // Log.log(Log.DEBUG,this,"Running in AWT thread: " + request); try { request.run(); } catch(Throwable t) { Log.log(Log.ERROR,this,"Exception " + "in AWT thread:"); Log.log(Log.ERROR,this,t); } } //}}} } //}}} }