1
1
package rprocessing ;
2
2
3
+ import java .awt .Component ;
4
+ import java .awt .Window ;
5
+ import java .awt .event .ComponentAdapter ;
6
+ import java .awt .event .ComponentEvent ;
7
+ import java .lang .reflect .Method ;
8
+ import java .util .Arrays ;
9
+ import java .util .concurrent .CountDownLatch ;
10
+
3
11
import javax .script .ScriptEngine ;
4
12
import javax .script .ScriptEngineManager ;
5
13
import javax .script .ScriptException ;
12
20
import org .renjin .sexp .SEXP ;
13
21
import org .renjin .sexp .Symbol ;
14
22
23
+ import processing .awt .PSurfaceAWT ;
24
+ import processing .core .PApplet ;
25
+ import processing .core .PConstants ;
26
+ import processing .core .PSurface ;
27
+ import processing .javafx .PSurfaceFX ;
28
+ import processing .opengl .PSurfaceJOGL ;
15
29
import rprocessing .applet .BuiltinApplet ;
16
30
import rprocessing .exception .NotFoundException ;
17
31
import rprocessing .util .Constant ;
18
32
import rprocessing .util .Printer ;
19
33
34
+ import com .jogamp .newt .opengl .GLWindow ;
35
+
20
36
/**
21
37
* RlangPApplet
22
38
* PApplet for R language, powered by Renjin.
25
41
*/
26
42
public class RLangPApplet extends BuiltinApplet {
27
43
28
- private static final boolean VERBOSE = Boolean
29
- . parseBoolean ( System .getenv ("VERBOSE_RLANG_MODE" ));
44
+ private static final boolean VERBOSE = Boolean . parseBoolean ( System
45
+ .getenv ("VERBOSE_RLANG_MODE" ));
30
46
31
47
// A static-mode sketch must be interpreted from within the setup() method.
32
48
// All others are interpreted during construction in order to harvest method
@@ -41,13 +57,15 @@ public class RLangPApplet extends BuiltinApplet {
41
57
42
58
private final Printer stdout ;
43
59
60
+ private final CountDownLatch finishedLatch = new CountDownLatch (1 );
61
+
44
62
/**
45
63
* Mode for Processing.
46
64
*
47
65
* @author github.com/gaocegege
48
66
*/
49
67
private enum Mode {
50
- STATIC , ACTIVE , MIXED
68
+ STATIC , ACTIVE , MIXED
51
69
}
52
70
53
71
private static void log (String msg ) {
@@ -89,8 +107,8 @@ public void prePassCode() {
89
107
*/
90
108
if (isSameClass (ev .get (i ), FunctionCall .class )
91
109
&& isSameClass (((FunctionCall ) ev .get (i )).getFunction (), Symbol .class )
92
- && ((Symbol ) ((FunctionCall ) ev .get (i )).getFunction ()).getPrintName ()
93
- . equals ( "<-" )) {
110
+ && ((Symbol ) ((FunctionCall ) ev .get (i )).getFunction ()).getPrintName (). equals (
111
+ "<-" )) {
94
112
this .renjinEngine .getTopLevelContext ().evaluate (ev .get (i ),
95
113
this .renjinEngine .getTopLevelContext ().getEnvironment ());
96
114
}
@@ -123,6 +141,105 @@ public void addPAppletToRContext() {
123
141
this .renjinEngine .put ("stdout" , stdout );
124
142
}
125
143
144
+ public void runBlock (final String [] arguments ) {
145
+ log ("runBlock" );
146
+ PApplet .runSketch (arguments , this );
147
+ try {
148
+ finishedLatch .await ();
149
+ log ("Down" );
150
+ } catch (final InterruptedException interrupted ) {
151
+ // Treat an interruption as a request to the applet to terminate.
152
+ exit ();
153
+ try {
154
+ finishedLatch .await ();
155
+ log ("Down" );
156
+ } catch (final InterruptedException e ) {
157
+ log (e .toString ());
158
+ }
159
+ } finally {
160
+ Thread .setDefaultUncaughtExceptionHandler (null );
161
+ if (PApplet .platform == PConstants .MACOSX
162
+ && Arrays .asList (arguments ).contains ("fullScreen" )) {
163
+ // Frame should be OS-X fullscreen, and it won't stop being that unless the jvm
164
+ // exits or we explicitly tell it to minimize.
165
+ // (If it's disposed, it'll leave a gray blank window behind it.)
166
+ log ("Disabling fullscreen." );
167
+ macosxFullScreenToggle (frame );
168
+ }
169
+ if (surface instanceof PSurfaceFX ) {
170
+ // Sadly, JavaFX is an abomination, and there's no way to run an FX sketch more than once,
171
+ // so we must actually exit.
172
+ log ("JavaFX requires SketchRunner to terminate. Farewell!" );
173
+ System .exit (0 );
174
+ }
175
+ final Object nativeWindow = surface .getNative ();
176
+ if (nativeWindow instanceof com .jogamp .newt .Window ) {
177
+ ((com .jogamp .newt .Window ) nativeWindow ).destroy ();
178
+ } else {
179
+ surface .setVisible (false );
180
+ }
181
+ }
182
+ // if (terminalException != null) {
183
+ // throw terminalException;
184
+ // }
185
+ }
186
+
187
+ static private void macosxFullScreenToggle (final Window window ) {
188
+ try {
189
+ final Class <?> appClass = Class .forName ("com.apple.eawt.Application" );
190
+ final Method getAppMethod = appClass .getMethod ("getApplication" );
191
+ final Object app = getAppMethod .invoke (null );
192
+ final Method requestMethod = appClass
193
+ .getMethod ("requestToggleFullScreen" , Window .class );
194
+ requestMethod .invoke (app , window );
195
+ } catch (final ClassNotFoundException cnfe ) {
196
+ // ignored
197
+ } catch (final Exception e ) {
198
+ e .printStackTrace ();
199
+ }
200
+ }
201
+
202
+ /**
203
+ *
204
+ * @see processing.core.PApplet#initSurface()
205
+ */
206
+ @ Override
207
+ protected PSurface initSurface () {
208
+ final PSurface s = super .initSurface ();
209
+ this .frame = null ; // eliminate a memory leak from 2.x compat hack
210
+ // s.setTitle(pySketchPath.getFileName().toString().replaceAll("\\..*$", ""));
211
+ if (s instanceof PSurfaceAWT ) {
212
+ final PSurfaceAWT surf = (PSurfaceAWT ) s ;
213
+ final Component c = (Component ) surf .getNative ();
214
+ c .addComponentListener (new ComponentAdapter () {
215
+ @ Override
216
+ public void componentHidden (final ComponentEvent e ) {
217
+ log ("initSurface" );
218
+ finishedLatch .countDown ();
219
+ }
220
+ });
221
+ } else if (s instanceof PSurfaceJOGL ) {
222
+ final PSurfaceJOGL surf = (PSurfaceJOGL ) s ;
223
+ final GLWindow win = (GLWindow ) surf .getNative ();
224
+ win .addWindowListener (new com .jogamp .newt .event .WindowAdapter () {
225
+ @ Override
226
+ public void windowDestroyed (final com .jogamp .newt .event .WindowEvent arg0 ) {
227
+ log ("initSurface" );
228
+ finishedLatch .countDown ();
229
+ }
230
+ });
231
+ } else if (s instanceof PSurfaceFX ) {
232
+ System .err .println ("I don't know how to watch FX2D windows for close." );
233
+ }
234
+ return s ;
235
+ }
236
+
237
+ @ Override
238
+ public void exitActual () {
239
+ log ("exitActual" );
240
+ finishedLatch .countDown ();
241
+ }
242
+
126
243
/**
127
244
* @see processing.core.PApplet#settings()
128
245
*/
0 commit comments