1 /******************************************************************************* 2 * Copyright (c) 2000, 2008 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 * Port to the D programming language: 11 * Frank Benoit <benoit@tionex.de> 12 *******************************************************************************/ 13 module org.eclipse.swt.widgets.Synchronizer; 14 15 import org.eclipse.swt.widgets.Display; 16 import org.eclipse.swt.widgets.RunnableLock; 17 import org.eclipse.swt.internal.Compatibility; 18 import java.lang.all; 19 20 import org.eclipse.swt.SWT; 21 import java.lang.Thread; 22 import org.eclipse.swt.graphics.Device; 23 version(Tango){ 24 import tango.core.Exception; 25 } else { // Phobos 26 import java.nonstandard.sync.exception: SyncException; 27 } 28 29 /** 30 * Instances of this class provide synchronization support 31 * for displays. A default instance is created automatically 32 * for each display, and this instance is sufficient for almost 33 * all applications. 34 * <p> 35 * <b>IMPORTANT:</b> Typical application code <em>never</em> 36 * needs to deal with this class. It is provided only to 37 * allow applications which require non-standard 38 * synchronization behavior to plug in the support they 39 * require. <em>Subclasses which override the methods in 40 * this class must ensure that the superclass methods are 41 * invoked in their implementations</em> 42 * </p> 43 * 44 * @see Display#setSynchronizer 45 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> 46 */ 47 public class Synchronizer { 48 Display display; 49 int messageCount; 50 RunnableLock [] messages; 51 Object messageLock; 52 Thread syncThread; 53 static const int GROW_SIZE = 4; 54 static const int MESSAGE_LIMIT = 64; 55 56 /** 57 * Constructs a new instance of this class. 58 * 59 * @param display the display to create the synchronizer on 60 */ 61 public this (Display display) { 62 this.display = display; 63 messageLock = new Object (); 64 } 65 66 void addLast (RunnableLock lock) { 67 bool wake = false; 68 synchronized (messageLock) { 69 if (messages is null) messages = new RunnableLock [GROW_SIZE]; 70 if (messageCount is messages.length) { 71 RunnableLock[] newMessages = new RunnableLock [messageCount + GROW_SIZE]; 72 System.arraycopy (messages, 0, newMessages, 0, messageCount); 73 messages = newMessages; 74 } 75 messages [messageCount++] = lock; 76 wake = messageCount is 1; 77 } 78 if (wake) display.wakeThread (); 79 } 80 81 /** 82 * Causes the <code>run()</code> method of the runnable to 83 * be invoked by the user-interface thread at the next 84 * reasonable opportunity. The caller of this method continues 85 * to run in parallel, and is not notified when the 86 * runnable has completed. 87 * 88 * @param runnable code to run on the user-interface thread. 89 * 90 * @see #syncExec 91 */ 92 public void asyncExec (Runnable runnable) { 93 if (runnable is null) { 94 display.wake (); 95 return; 96 } 97 addLast (new RunnableLock (runnable)); 98 } 99 100 int getMessageCount () { 101 synchronized (messageLock) { 102 return messageCount; 103 } 104 } 105 106 void releaseSynchronizer () { 107 display = null; 108 messages = null; 109 messageLock = null; 110 syncThread = null; 111 } 112 113 RunnableLock removeFirst () { 114 synchronized (messageLock) { 115 if (messageCount is 0) return null; 116 RunnableLock lock = messages [0]; 117 System.arraycopy (messages, 1, messages, 0, --messageCount); 118 messages [messageCount] = null; 119 if (messageCount is 0) { 120 if (messages.length > MESSAGE_LIMIT) messages = null; 121 } 122 return lock; 123 } 124 } 125 126 bool runAsyncMessages () { 127 return runAsyncMessages (false); 128 } 129 130 bool runAsyncMessages (bool all) { 131 bool run = false; 132 do { 133 RunnableLock lock = removeFirst (); 134 if (lock is null) return run; 135 run = true; 136 synchronized (lock) { 137 syncThread = lock.thread; 138 try { 139 lock.run (); 140 } catch (Exception t) { 141 lock.throwable = t; 142 SWT.error (SWT.ERROR_FAILED_EXEC, t); 143 } finally { 144 syncThread = null; 145 lock.notifyAll (); 146 } 147 } 148 } while (all); 149 return run; 150 } 151 152 /** 153 * Causes the <code>run()</code> method of the runnable to 154 * be invoked by the user-interface thread at the next 155 * reasonable opportunity. The thread which calls this method 156 * is suspended until the runnable completes. 157 * 158 * @param runnable code to run on the user-interface thread. 159 * 160 * @exception SWTException <ul> 161 * <li>ERROR_FAILED_EXEC - if an exception occurred when executing the runnable</li> 162 * </ul> 163 * 164 * @see #asyncExec 165 */ 166 public void syncExec (Runnable runnable) { 167 RunnableLock lock = null; 168 synchronized (Device.classinfo) { 169 if (display is null || display.isDisposed ()) SWT.error (SWT.ERROR_DEVICE_DISPOSED); 170 if (!display.isValidThread ()) { 171 if (runnable is null) { 172 display.wake (); 173 return; 174 } 175 lock = new RunnableLock (runnable); 176 /* 177 * Only remember the syncThread for syncExec. 178 */ 179 lock.thread = Thread.currentThread(); 180 addLast (lock); 181 } 182 } 183 if (lock is null) { 184 if (runnable !is null) runnable.run (); 185 return; 186 } 187 synchronized (lock) { 188 bool interrupted = false; 189 while (!lock.done ()) { 190 try { 191 lock.wait (); 192 } catch (SyncException e) { 193 interrupted = true; 194 } 195 } 196 if (interrupted) { 197 Compatibility.interrupt(); 198 } 199 if (lock.throwable !is null) { 200 SWT.error (SWT.ERROR_FAILED_EXEC, lock.throwable); 201 } 202 } 203 } 204 205 }