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