Skip to content

Commit 3d39804

Browse files
committed
Refactor initialization to use background threads
Moved several initialization tasks to background threads for improved startup performance and responsiveness, including tool, font, UI, and suggestion generator setup. Deferred some tool initialization until first use, added caching for SVG rendering, and simplified string loading in PApplet. Also made minor changes to library list and variable inspector initialization.
1 parent c1d6313 commit 3d39804

File tree

9 files changed

+109
-79
lines changed

9 files changed

+109
-79
lines changed

app/src/processing/app/Base.java

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ static private void createAndShowGUI(String[] args) {
302302
// t6 = System.currentTimeMillis();
303303

304304
// Prevent more than one copy of the PDE from running.
305-
SingleInstance.startServer(base);
305+
new Thread(() -> { SingleInstance.startServer(base); } ).start();
306306

307307
handleWelcomeScreen(base);
308308
handleCrustyDisplay();
@@ -485,20 +485,26 @@ static public boolean isCommandLine() {
485485

486486
public Base(String[] args) throws Exception {
487487
long t1 = System.currentTimeMillis();
488-
ContributionManager.init(this);
488+
new Thread(() -> {
489+
try {
490+
ContributionManager.init(this);
491+
} catch (Exception e) {
492+
throw new RuntimeException(e);
493+
}
494+
}).start();
489495

490496
long t2 = System.currentTimeMillis();
491497
buildCoreModes();
492498
long t2b = System.currentTimeMillis();
493-
rebuildContribModes();
499+
new Thread(this::rebuildContribModes).start();
494500
long t2c = System.currentTimeMillis();
495501
rebuildContribExamples();
496502

497503
long t3 = System.currentTimeMillis();
498504
// Needs to happen after the sketchbook folder has been located.
499505
// Also relies on the modes to be loaded, so it knows what can be
500506
// marked as an example.
501-
Recent.init(this);
507+
new Thread(() -> { Recent.init(this); }).start();
502508

503509
long t4 = System.currentTimeMillis();
504510
String lastModeIdentifier = Preferences.get("mode.last"); //$NON-NLS-1$
@@ -523,7 +529,7 @@ public Base(String[] args) throws Exception {
523529
long t5 = System.currentTimeMillis();
524530

525531
// Make sure ThinkDifferent has library examples too
526-
nextMode.rebuildLibraryList();
532+
// nextMode.rebuildLibraryList();
527533

528534
// Put this after loading the examples, so that building the default file
529535
// menu works on Mac OS X (since it needs examplesFolder to be set).
@@ -863,7 +869,7 @@ public List<ToolContribution> getContribTools() {
863869
return contribTools;
864870
}
865871

866-
872+
private List<Tool> toolsToInit = new ArrayList<>();
867873
public void rebuildToolList() {
868874
// Only do these once because the list of internal tools will never change
869875
if (internalTools == null) {
@@ -883,43 +889,12 @@ public void rebuildToolList() {
883889
// Only init() these the first time they're loaded
884890
if (coreTools == null) {
885891
coreTools = ToolContribution.loadAll(Base.getToolsFolder());
886-
for (Tool tool : coreTools) {
887-
tool.init(this);
888-
}
892+
toolsToInit.addAll(coreTools);
889893
}
890894

891895
// Reset the contributed tools and re-init() all of them.
892896
contribTools = ToolContribution.loadAll(Base.getSketchbookToolsFolder());
893-
for (Tool tool : contribTools) {
894-
try {
895-
tool.init(this);
896-
897-
// With the exceptions, we can't call statusError because the window
898-
// isn't completely set up yet. Also not gonna pop up a warning because
899-
// people may still be running different versions of Processing.
900-
901-
} catch (VerifyError | AbstractMethodError ve) {
902-
System.err.println("\"" + tool.getMenuTitle() + "\" is not " +
903-
"compatible with this version of Processing");
904-
Messages.err("Incompatible Tool found during tool.init()", ve);
905-
906-
} catch (NoSuchMethodError nsme) {
907-
System.err.println("\"" + tool.getMenuTitle() + "\" is not " +
908-
"compatible with this version of Processing");
909-
System.err.println("The " + nsme.getMessage() + " method no longer exists.");
910-
Messages.err("Incompatible Tool found during tool.init()", nsme);
911-
912-
} catch (NoClassDefFoundError ncdfe) {
913-
System.err.println("\"" + tool.getMenuTitle() + "\" is not " +
914-
"compatible with this version of Processing");
915-
System.err.println("The " + ncdfe.getMessage() + " class is no longer available.");
916-
Messages.err("Incompatible Tool found during tool.init()", ncdfe);
917-
918-
} catch (Error | Exception e) {
919-
System.err.println("An error occurred inside \"" + tool.getMenuTitle() + "\"");
920-
e.printStackTrace();
921-
}
922-
}
897+
toolsToInit.addAll(contribTools);
923898
}
924899

925900

@@ -928,7 +903,7 @@ protected void initInternalTool(Class<?> toolClass) {
928903
final Tool tool = (Tool)
929904
toolClass.getDeclaredConstructor().newInstance();
930905

931-
tool.init(this);
906+
toolsToInit.add(tool);
932907
internalTools.add(tool);
933908

934909
} catch (Exception e) {
@@ -976,12 +951,40 @@ public void populateToolsMenu(JMenu toolsMenu) {
976951
toolsMenu.add(manageTools);
977952
}
978953

954+
void initTool(Tool tool) {
955+
if(!toolsToInit.contains(tool)) {return;}
956+
try {
957+
tool.init(this);
958+
toolsToInit.remove(tool);
959+
} catch (VerifyError | AbstractMethodError ve) {
960+
System.err.println("\"" + tool.getMenuTitle() + "\" is not " +
961+
"compatible with this version of Processing");
962+
Messages.err("Incompatible Tool found during tool.init()", ve);
963+
964+
} catch (NoSuchMethodError nsme) {
965+
System.err.println("\"" + tool.getMenuTitle() + "\" is not " +
966+
"compatible with this version of Processing");
967+
System.err.println("The " + nsme.getMessage() + " method no longer exists.");
968+
Messages.err("Incompatible Tool found during tool.init()", nsme);
969+
970+
} catch (NoClassDefFoundError ncdfe) {
971+
System.err.println("\"" + tool.getMenuTitle() + "\" is not " +
972+
"compatible with this version of Processing");
973+
System.err.println("The " + ncdfe.getMessage() + " class is no longer available.");
974+
Messages.err("Incompatible Tool found during tool.init()", ncdfe);
975+
976+
} catch (Error | Exception e) {
977+
System.err.println("An error occurred inside \"" + tool.getMenuTitle() + "\"");
978+
e.printStackTrace();
979+
}
980+
}
979981

980982
JMenuItem createToolItem(final Tool tool) { //, Map<String, JMenuItem> toolItems) {
981983
String title = tool.getMenuTitle();
982984
final JMenuItem item = new JMenuItem(title);
983985
item.addActionListener(e -> {
984986
try {
987+
initTool(tool);
985988
tool.run();
986989

987990
} catch (NoSuchMethodError | NoClassDefFoundError ne) {

app/src/processing/app/Processing.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class Processing: SuspendingCliktCommand("processing"){
5656

5757
val subcommand = currentContext.invokedSubcommand
5858
if (subcommand == null) {
59-
Start.main(sketches.toTypedArray())
59+
Base.main(sketches.toTypedArray())
6060
}
6161
}
6262
}

app/src/processing/app/platform/DefaultPlatform.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import java.awt.Font;
2828
import java.io.File;
2929

30-
import javax.swing.UIManager;
30+
import javax.swing.*;
3131
import javax.swing.border.EmptyBorder;
3232

3333
import com.formdev.flatlaf.FlatLaf;
@@ -115,18 +115,29 @@ public void setLookAndFeel() throws Exception {
115115
// (i.e. Nimbus on Linux) with our custom components is badness.
116116

117117
// dummy font call so that it's registered for FlatLaf
118-
Font defaultFont = Toolkit.getSansFont(14, Font.PLAIN);
119-
UIManager.put("defaultFont", defaultFont);
118+
new Thread(() -> {
119+
Font defaultFont = Toolkit.getSansFont(14, Font.PLAIN);
120+
UIManager.put("defaultFont", defaultFont);
121+
}).start();
122+
120123

121124
// pull in FlatLaf.properties from the processing.app.laf folder
122125
FlatLaf.registerCustomDefaultsSource("processing.app.laf");
123126

124-
// start with Light, but updateTheme() will be called soon
125-
UIManager.setLookAndFeel(new FlatLightLaf());
127+
new Thread(() -> {
128+
// start with Light, but updateTheme() will be called soon
129+
try {
130+
UIManager.setLookAndFeel(new FlatLightLaf());
131+
} catch (UnsupportedLookAndFeelException e) {
132+
throw new RuntimeException(e);
133+
}
134+
}).start();
126135

127136
// Does not fully remove the gray hairline (probably from a parent
128137
// Window object), but is an improvement from the heavier default.
129-
UIManager.put("ToolTip.border", new EmptyBorder(0, 0, 0, 0));
138+
new Thread(() -> {
139+
UIManager.put("ToolTip.border", new EmptyBorder(0, 0, 0, 0));
140+
}).start();
130141

131142
/*
132143
javax.swing.UIDefaults defaults = UIManager.getDefaults();

app/src/processing/app/ui/Editor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ public void windowDeactivated(WindowEvent e) {
189189

190190
timer = new Timer();
191191

192-
buildMenuBar();
192+
new Thread(this::buildMenuBar).start();
193193

194194
JPanel contentPain = new JPanel();
195195
setContentPane(contentPain);

app/src/processing/app/ui/Toolkit.java

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,19 @@
4444
import java.awt.geom.AffineTransform;
4545
import java.awt.geom.GeneralPath;
4646
import java.awt.image.ImageObserver;
47+
import java.awt.image.RenderedImage;
4748
import java.io.BufferedInputStream;
4849
import java.io.File;
4950
import java.io.FileInputStream;
5051
import java.io.IOException;
52+
import java.nio.file.Files;
5153
import java.util.ArrayList;
5254
import java.util.Arrays;
5355
import java.util.Comparator;
5456
import java.util.List;
5557
import java.util.regex.Pattern;
5658

59+
import javax.imageio.ImageIO;
5760
import javax.swing.Action;
5861
import javax.swing.ImageIcon;
5962
import javax.swing.JButton;
@@ -68,14 +71,12 @@
6871
import javax.swing.text.html.HTMLEditorKit;
6972
import javax.swing.text.html.StyleSheet;
7073

71-
import processing.app.Language;
72-
import processing.app.Messages;
73-
import processing.app.Platform;
74-
import processing.app.Preferences;
75-
import processing.app.Util;
74+
import processing.app.*;
7675
import processing.awt.PGraphicsJava2D;
7776
import processing.awt.PShapeJava2D;
77+
import processing.awt.ShimAWT;
7878
import processing.core.PApplet;
79+
import processing.core.PImage;
7980
import processing.core.PShape;
8081
import processing.data.StringDict;
8182
import processing.data.StringList;
@@ -794,6 +795,7 @@ static private Image svgToImageMult(String xmlStr, int wide, int high) {
794795
*/
795796

796797

798+
797799
static public Image svgToImageMult(String xmlStr, int wide, int high, StringDict replacements) {
798800
/*
799801
for (StringDict.Entry entry : replacements.entries()) {
@@ -823,8 +825,25 @@ static private Image svgToImage(String xmlStr, int wide, int high) {
823825
pg.setSize(wide, high);
824826
pg.smooth();
825827

828+
829+
830+
831+
826832
pg.beginDraw();
827833

834+
var cacheKey = (xmlStr + "|" + wide + "x" + high).hashCode();
835+
var cachePath = Base.getSettingsFolder().toPath().resolve("svg_cache").resolve(String.valueOf(cacheKey) + ".png");
836+
if(!Base.DEBUG || true){
837+
if(Files.exists(cachePath)){
838+
byte[] bytes = PApplet.loadBytes(cachePath.toFile());
839+
if (bytes == null) {
840+
return null;
841+
} else {
842+
return new ImageIcon(bytes).getImage();
843+
}
844+
}
845+
}
846+
828847
try {
829848
XML xml = XML.parse(xmlStr);
830849
PShape shape = new PShapeJava2D(xml);
@@ -835,6 +854,12 @@ static private Image svgToImage(String xmlStr, int wide, int high) {
835854
}
836855

837856
pg.endDraw();
857+
try {
858+
Files.createDirectories(cachePath.getParent());
859+
pg.save(cachePath.toString());
860+
} catch (IOException e) {
861+
e.printStackTrace();
862+
}
838863
return pg.image;
839864
}
840865

@@ -1361,8 +1386,9 @@ static private Font initFont(String filename, int size) throws IOException, Font
13611386
Font font = Font.createFont(Font.TRUETYPE_FONT, input);
13621387
input.close();
13631388

1364-
// Register the font to be available for other function calls
1365-
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(font);
1389+
new Thread(() -> {
1390+
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(font);
1391+
}).start();
13661392

13671393
return font.deriveFont((float) size);
13681394
}

core/src/processing/core/PApplet.java

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6822,28 +6822,9 @@ static public String[] loadStrings(InputStream input) {
68226822

68236823
static public String[] loadStrings(BufferedReader reader) {
68246824
try {
6825-
String[] lines = new String[100];
6826-
int lineCount = 0;
6827-
String line;
6828-
while ((line = reader.readLine()) != null) {
6829-
if (lineCount == lines.length) {
6830-
String[] temp = new String[lineCount << 1];
6831-
System.arraycopy(lines, 0, temp, 0, lineCount);
6832-
lines = temp;
6833-
}
6834-
lines[lineCount++] = line;
6835-
}
6825+
var lines = reader.lines().toArray(String[]::new);
68366826
reader.close();
6837-
6838-
if (lineCount == lines.length) {
6839-
return lines;
6840-
}
6841-
6842-
// resize array to appropriate amount for these lines
6843-
String[] output = new String[lineCount];
6844-
System.arraycopy(lines, 0, output, 0, lineCount);
6845-
return output;
6846-
6827+
return lines;
68476828
} catch (IOException e) {
68486829
e.printStackTrace();
68496830
//throw new RuntimeException("Error inside loadStrings()");

java/src/processing/mode/java/JavaTextArea.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ public class JavaTextArea extends PdeTextArea {
5252
public JavaTextArea(TextAreaDefaults defaults, JavaEditor editor) {
5353
super(defaults, new JavaInputHandler(editor), editor);
5454

55-
suggestionGenerator = new CompletionGenerator((JavaMode) editor.getMode());
55+
new Thread(() -> {
56+
suggestionGenerator = new CompletionGenerator((JavaMode) editor.getMode());
57+
}).start();
5658
tweakMode = false;
5759
}
5860

java/src/processing/mode/java/PreprocService.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public class PreprocService {
8080
protected final JavaMode javaMode;
8181
protected final Sketch sketch;
8282

83-
protected final ASTParser parser = ASTParser.newParser(AST.JLS11);
83+
protected ASTParser parser;
8484

8585
private final Thread preprocessingThread;
8686
private final BlockingQueue<Boolean> requestQueue = new ArrayBlockingQueue<>(1);
@@ -116,6 +116,9 @@ public PreprocService(JavaMode javaMode, Sketch sketch) {
116116
* The "main loop" for the background thread that checks for code issues.
117117
*/
118118
private void mainLoop() {
119+
if(parser == null) {
120+
parser = ASTParser.newParser(AST.JLS11);
121+
}
119122
running = true;
120123
PreprocSketch prevResult = null;
121124
CompletableFuture<?> runningCallbacks = null;

java/src/processing/mode/java/debug/Debugger.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public class Debugger {
111111

112112
public Debugger(JavaEditor editor) {
113113
this.editor = editor;
114-
inspector = new VariableInspector(editor);
114+
// inspector = new VariableInspector(editor);
115115
}
116116

117117

@@ -206,6 +206,9 @@ public void toggleEnabled() {
206206
} else {
207207
debugItem.setText(Language.text("menu.debug.enable"));
208208
}
209+
if(inspector == null) {
210+
inspector = new VariableInspector(editor);
211+
}
209212
inspector.setVisible(enabled);
210213

211214
for (Component item : debugMenu.getMenuComponents()) {
@@ -297,6 +300,7 @@ public void removeClassLoadListener(ClassLoadListener listener) {
297300

298301

299302
public void dispose() {
303+
if(inspector == null) return;
300304
inspector.dispose();
301305
}
302306

0 commit comments

Comments
 (0)