diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 112c96193..df06857e6 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -55,9 +55,9 @@ import processing.data.StringList; public class Base { // Added accessors for 0218 because the UpdateCheck class was not properly // updating the values, due to javac inlining the static final values. - static private final int REVISION = 246; + static private final int REVISION = 247; /** This might be replaced by main() if there's a lib/version.txt file. */ - static private String VERSION_NAME = "0246"; //$NON-NLS-1$ + static private String VERSION_NAME = "0247"; //$NON-NLS-1$ /** Set true if this a proper release rather than a numbered revision. */ /** True if heavy debugging error/log messages are enabled */ diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 8adcb7993..c3d6382f5 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -39,6 +39,7 @@ import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.*; +import java.util.ArrayList; import java.util.List; import javax.swing.*; @@ -143,44 +144,19 @@ public class Sketch { codeFolder = new File(folder, "code"); dataFolder = new File(folder, "data"); - // get list of files in the sketch folder - String list[] = folder.list(); + List filenames = new ArrayList<>(); + List extensions = new ArrayList<>(); - // reset these because load() may be called after an - // external editor event. (fix for 0099) - codeCount = 0; + getSketchCodeFiles(filenames, extensions); - code = new SketchCode[list.length]; + codeCount = filenames.size(); + code = new SketchCode[codeCount]; - String[] extensions = mode.getExtensions(); - - for (String filename : list) { - // Ignoring the dot prefix files is especially important to avoid files - // with the ._ prefix on Mac OS X. (You'll see this with Mac files on - // non-HFS drives, i.e. a thumb drive formatted FAT32.) - if (filename.startsWith(".")) continue; - - // Don't let some wacko name a directory blah.pde or bling.java. - if (new File(folder, filename).isDirectory()) continue; - - // figure out the name without any extension - String base = filename; - // now strip off the .pde and .java extensions - for (String extension : extensions) { - if (base.toLowerCase().endsWith("." + extension)) { - base = base.substring(0, base.length() - (extension.length() + 1)); - - // Don't allow people to use files with invalid names, since on load, - // it would be otherwise possible to sneak in nasty filenames. [0116] - if (isSanitaryName(base)) { - code[codeCount++] = - new SketchCode(new File(folder, filename), extension); - } - } - } + for (int i = 0; i < codeCount; i++) { + String filename = filenames.get(i); + String extension = extensions.get(i); + code[i] = new SketchCode(new File(folder, filename), extension); } - // Remove any code that wasn't proper - code = (SketchCode[]) PApplet.subset(code, 0, codeCount); // move the main class to the first tab // start at 1, if it's at zero, don't bother @@ -204,6 +180,39 @@ public class Sketch { } + public void getSketchCodeFiles(List outFilenames, + List outExtensions) { + // get list of files in the sketch folder + String list[] = folder.list(); + + for (String filename : list) { + // Ignoring the dot prefix files is especially important to avoid files + // with the ._ prefix on Mac OS X. (You'll see this with Mac files on + // non-HFS drives, i.e. a thumb drive formatted FAT32.) + if (filename.startsWith(".")) continue; + + // Don't let some wacko name a directory blah.pde or bling.java. + if (new File(folder, filename).isDirectory()) continue; + + // figure out the name without any extension + String base = filename; + // now strip off the .pde and .java extensions + for (String extension : mode.getExtensions()) { + if (base.toLowerCase().endsWith("." + extension)) { + base = base.substring(0, base.length() - (extension.length() + 1)); + + // Don't allow people to use files with invalid names, since on load, + // it would be otherwise possible to sneak in nasty filenames. [0116] + if (isSanitaryName(base)) { + if (outFilenames != null) outFilenames.add(filename); + if (outExtensions != null) outExtensions.add(extension); + } + } + } + } + } + + /** * Reload the current sketch. Used to update the text area when * an external editor is in use. diff --git a/app/src/processing/app/Util.java b/app/src/processing/app/Util.java index 8e51428a0..4dd579781 100644 --- a/app/src/processing/app/Util.java +++ b/app/src/processing/app/Util.java @@ -23,6 +23,7 @@ package processing.app; import java.io.*; +import java.nio.file.Files; import java.util.Enumeration; import java.util.Vector; import java.util.zip.*; @@ -301,7 +302,7 @@ public class Util { /** * Remove all files in a directory and the directory itself. - * Prints error messages with failed filenames. + * Prints error messages with failed filenames. Does not follow symlinks. */ static public boolean removeDir(File dir) { return removeDir(dir, true); @@ -310,22 +311,25 @@ public class Util { /** * Remove all files in a directory and the directory itself. * Optinally prints error messages with failed filenames. + * Does not follow symlinks. */ static public boolean removeDir(File dir, boolean printErrorMessages) { if (!dir.exists()) return true; boolean result = true; - File[] files = dir.listFiles(); - if (files != null) { - for (File child : files) { - if (child.isFile()) { - boolean deleted = child.delete(); - if (!deleted && printErrorMessages) { - System.err.println("Could not delete " + child.getAbsolutePath()); + if (!Files.isSymbolicLink(dir.toPath())) { + File[] files = dir.listFiles(); + if (files != null) { + for (File child : files) { + if (child.isFile()) { + boolean deleted = child.delete(); + if (!deleted && printErrorMessages) { + System.err.println("Could not delete " + child.getAbsolutePath()); + } + result &= deleted; + } else if (child.isDirectory()) { + result &= removeDir(child, printErrorMessages); } - result &= deleted; - } else if (child.isDirectory()) { - result &= removeDir(child, printErrorMessages); } } } diff --git a/app/src/processing/app/contrib/ContributionListing.java b/app/src/processing/app/contrib/ContributionListing.java index 8d94f8248..cf35ff628 100644 --- a/app/src/processing/app/contrib/ContributionListing.java +++ b/app/src/processing/app/contrib/ContributionListing.java @@ -585,6 +585,11 @@ public class ContributionListing { count++; } } + for (ExamplesContribution ec : base.getExampleContribs()) { + if (hasUpdates(ec)) { + count++; + } + } return count; } diff --git a/app/src/processing/app/ui/About.java b/app/src/processing/app/ui/About.java index 4eda1206f..a84a680c5 100644 --- a/app/src/processing/app/ui/About.java +++ b/app/src/processing/app/ui/About.java @@ -26,13 +26,18 @@ import java.awt.Color; import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; import java.awt.Window; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.ImageIcon; import processing.app.Base; +import processing.app.Platform; public class About extends Window { @@ -65,23 +70,42 @@ public class About extends Window { } }); + addKeyListener(new KeyAdapter() { + public void keyTyped(KeyEvent e) { + System.out.println(e); + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { + dispose(); + } + } + }); + // Dimension screen = Toolkit.getScreenSize(); // setBounds((screen.width-width)/2, (screen.height-height)/2, width, height); - setLocationRelativeTo(null); + setSize(width, height); +// setLocationRelativeTo(null); + setLocationRelativeTo(frame); setVisible(true); + requestFocus(); } public void paint(Graphics g) { +// Graphics2D g2 = Toolkit.prepareGraphics(g); +// g2.scale(0.5, 0.5); + + Graphics2D g2 = (Graphics2D) g; + // OS X looks better doing its own thing, Windows and Linux need AA + g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + Platform.isMacOS() ? + RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT : + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.drawImage(icon.getImage(), 0, 0, width, height, null); +// g.setColor(Color.ORANGE); +// g.fillRect(0, 0, width, height); -// Graphics2D g2 = (Graphics2D) g; -// g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, -// RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); - - g.setFont(Toolkit.getSansFont(Font.PLAIN, 10)); - //g.setFont(new Font("SansSerif", Font.PLAIN, 10)); //$NON-NLS-1$ - g.setColor(Color.white); + g.setFont(Toolkit.getSansFont(12, Font.PLAIN)); + g.setColor(Color.WHITE); g.drawString(Base.getVersionName(), 26, 29); } } \ No newline at end of file diff --git a/app/src/processing/app/ui/ChangeDetector.java b/app/src/processing/app/ui/ChangeDetector.java index 081f42334..866d2ffc4 100644 --- a/app/src/processing/app/ui/ChangeDetector.java +++ b/app/src/processing/app/ui/ChangeDetector.java @@ -5,7 +5,6 @@ import java.awt.Frame; import java.awt.event.WindowEvent; import java.awt.event.WindowFocusListener; import java.io.File; -import java.io.FilenameFilter; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; @@ -79,19 +78,12 @@ public class ChangeDetector implements WindowFocusListener { private boolean checkFileCount() { // check file count first - File sketchFolder = sketch.getFolder(); - File[] sketchFiles = sketchFolder.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String filename) { - for (String ext : editor.getMode().getExtensions()) { - if (filename.toLowerCase().endsWith(ext.toLowerCase())) { - return true; - } - } - return false; - } - }); - int fileCount = sketchFiles.length; + + List filenames = new ArrayList<>(); + + sketch.getSketchCodeFiles(filenames, null); + + int fileCount = filenames.size(); // Was considering keeping track of the last "known" number of files // (instead of using sketch.getCodeCount() here) in case the user diff --git a/app/src/processing/app/ui/EditorFooter.java b/app/src/processing/app/ui/EditorFooter.java index f81e41465..80c5c50dc 100644 --- a/app/src/processing/app/ui/EditorFooter.java +++ b/app/src/processing/app/ui/EditorFooter.java @@ -73,7 +73,7 @@ public class EditorFooter extends Box { Color[] tabColor = new Color[2]; Color updateColor; - int updateLeft, updateRight; + int updateLeft; Editor editor; @@ -87,6 +87,7 @@ public class EditorFooter extends Box { int imageW, imageH; Image gradient; + Color bgColor; JPanel cardPanel; CardLayout cardLayout; @@ -172,6 +173,11 @@ public class EditorFooter extends Box { updateColor = mode.getColor("footer.updates.color"); gradient = mode.makeGradient("footer", 400, HIGH); + // Set the default background color in case the window size reported + // incorrectly by the OS, or we miss an update event of some kind + // https://github.com/processing/processing/issues/3919 + bgColor = mode.getColor("footer.gradient.bottom"); + setBackground(bgColor); } @@ -191,7 +197,7 @@ public class EditorFooter extends Box { repaint(); } } - if (x > updateLeft) { + if (updateCount > 0 && x > updateLeft) { ContributionManager.openUpdates(); } } @@ -293,6 +299,9 @@ public class EditorFooter extends Box { final String updateLabel = "Updates"; String updatesStr = "" + updateCount; double countWidth = font.getStringBounds(updatesStr, frc).getWidth(); + if (fontAscent > countWidth) { + countWidth = fontAscent; + } float diameter = (float) (countWidth * 1.65f); float ex = getWidth() - Editor.RIGHT_GUTTER - diameter; float ey = (getHeight() - diameter) / 2; diff --git a/build/build.xml b/build/build.xml index 4ff38830e..0e145eb69 100644 --- a/build/build.xml +++ b/build/build.xml @@ -393,9 +393,9 @@ + (); - sketchChangedListener = new SketchChangedListener(); // for (final SketchCode sc : editor.getSketch().getCode()) { // sc.getDocument().addDocumentListener(sketchChangedListener); // } @@ -251,8 +249,7 @@ public class ErrorCheckerService { private Thread errorCheckerThread; private BlockingQueue requestQueue = new ArrayBlockingQueue<>(1); - private ScheduledExecutorService scheduler = - Executors.newSingleThreadScheduledExecutor(); + private ScheduledExecutorService scheduler; volatile ScheduledFuture scheduledUiUpdate = null; volatile long nextUiUpdate = 0; @@ -275,7 +272,6 @@ public class ErrorCheckerService { astGenerator.buildAST(lastCodeCheckResult.sourceCode, lastCodeCheckResult.compilationUnit); } - handleErrorCheckingToggle(); while (running) { try { @@ -288,16 +284,16 @@ public class ErrorCheckerService { try { Messages.log("Starting error check"); - lastCodeCheckResult = checkCode(); + CodeCheckResult result = checkCode(); if (!JavaMode.errorCheckEnabled) { lastCodeCheckResult.problems.clear(); Messages.log("Error Check disabled, so not updating UI."); } - checkForMissingImports(); + lastCodeCheckResult = result; - updateSketchCodeListeners(); + checkForMissingImports(lastCodeCheckResult); if (JavaMode.errorCheckEnabled) { if (scheduledUiUpdate != null) { @@ -320,7 +316,6 @@ public class ErrorCheckerService { editor.updateErrorBar(result.problems); editor.getTextArea().repaint(); editor.updateErrorToggle(result.containsErrors); - updateSketchCodeListeners(); } }); } @@ -350,6 +345,7 @@ public class ErrorCheckerService { public void start() { + scheduler = Executors.newSingleThreadScheduledExecutor(); errorCheckerThread = new Thread(mainLoop); errorCheckerThread.start(); } @@ -358,6 +354,9 @@ public class ErrorCheckerService { cancel(); running = false; errorCheckerThread.interrupt(); + if (scheduler != null) { + scheduler.shutdownNow(); + } } @@ -376,35 +375,15 @@ public class ErrorCheckerService { } - protected void updateSketchCodeListeners() { - for (SketchCode sc : editor.getSketch().getCode()) { - SyntaxDocument doc = (SyntaxDocument) sc.getDocument(); - if (!hasSketchChangedListener(doc)) { - doc.addDocumentListener(sketchChangedListener); - } - } + public void addListener(Document doc) { + doc.addDocumentListener(sketchChangedListener); } - boolean hasSketchChangedListener(SyntaxDocument doc) { - if (doc != null && doc.getDocumentListeners() != null) { - for (DocumentListener dl : doc.getDocumentListeners()) { - if (dl.equals(sketchChangedListener)) { - return true; - } - } - } - return false; - } - - - protected void checkForMissingImports() { - // Atomic access - CodeCheckResult lastCodeCheckResult = this.lastCodeCheckResult; - + protected void checkForMissingImports(CodeCheckResult result) { if (Preferences.getBoolean(JavaMode.SUGGEST_IMPORTS_PREF)) { - for (Problem p : lastCodeCheckResult.problems) { - if(p.getIProblem().getID() == IProblem.UndefinedType) { + for (Problem p : result.problems) { + if (p.getIProblem().getID() == IProblem.UndefinedType) { String args[] = p.getIProblem().getArguments(); if (args.length > 0) { String missingClass = args[0]; @@ -424,37 +403,22 @@ public class ErrorCheckerService { } - protected SketchChangedListener sketchChangedListener; - protected class SketchChangedListener implements DocumentListener{ - - private SketchChangedListener(){ - } - + protected final DocumentListener sketchChangedListener = new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { - if (JavaMode.errorCheckEnabled) { - request(); - //log("doc insert update, man error check.."); - } + if (JavaMode.errorCheckEnabled) request(); } @Override public void removeUpdate(DocumentEvent e) { - if (JavaMode.errorCheckEnabled){ - request(); - //log("doc remove update, man error check.."); - } + if (JavaMode.errorCheckEnabled) request(); } @Override public void changedUpdate(DocumentEvent e) { - if (JavaMode.errorCheckEnabled){ - request(); - //log("doc changed update, man error check.."); - } + if (JavaMode.errorCheckEnabled) request(); } - - } + }; public static class CodeCheckResult { @@ -1556,10 +1520,10 @@ public class ErrorCheckerService { return new String(p2, 0, index); } + public void handleErrorCheckingToggle() { if (!JavaMode.errorCheckEnabled) { - Messages.log(editor.getSketch().getName() + " Error Checker paused."); - //editor.clearErrorPoints(); + Messages.log(editor.getSketch().getName() + " Error Checker disabled."); editor.getErrorPoints().clear(); lastCodeCheckResult.problems.clear(); updateErrorTable(Collections.emptyList()); @@ -1567,7 +1531,7 @@ public class ErrorCheckerService { editor.getTextArea().repaint(); editor.repaintErrorBar(); } else { - Messages.log(editor.getSketch().getName() + " Error Checker resumed."); + Messages.log(editor.getSketch().getName() + " Error Checker enabled."); request(); } } diff --git a/java/theme/var-icons.gif b/java/theme/var-icons.gif deleted file mode 100644 index 1d0086a38..000000000 Binary files a/java/theme/var-icons.gif and /dev/null differ diff --git a/todo.txt b/todo.txt index fa32f37ca..111c3a11b 100644 --- a/todo.txt +++ b/todo.txt @@ -1,89 +1,8 @@ -0246 the holy land -X "Saving" messages never clear on "Save As" -X https://github.com/processing/processing/issues/3861 -X error checker/suggestions fixes -X https://github.com/processing/processing/pull/3871 -X https://github.com/processing/processing/pull/3879 -X contributions filter is ignored after clicking Install -X https://github.com/processing/processing/issues/3826 -X https://github.com/processing/processing/pull/3872 -X https://github.com/processing/processing/pull/3883 -X Exception in thread "Contribution List Downloader" -X https://github.com/processing/processing/issues/3882 -X https://github.com/processing/processing/pull/3884 -X Hide useless error in error checker -X https://github.com/processing/processing/pull/3887 -X grab bag of CM work from Jakub -X https://github.com/processing/processing/issues/3895 -X https://github.com/processing/processing/pull/3897 -X Clean up delete dir function -X https://github.com/processing/processing/pull/3910 -X show number of updates available in the footer -X https://github.com/processing/processing/issues/3518 -X https://github.com/processing/processing/pull/3896 -X https://github.com/processing/processing/pull/3901 -o total number of updates available is not correct? (may be fixed) -o ArrayIndexOutOfBoundsException freak out when clicking the header line -o think this was on name, with libraries, but not sure -X should be fixed with the updates from Jakub +0247 (3.0.1) -gui -X distinguish errors and warnings -X https://github.com/processing/processing/issues/3406 -X make breakpoints more prominent -X https://github.com/processing/processing/issues/3307 (comp is set) -X clean up statusMessage() inside JavaEditor -o do we want to bring back the delays? -X implement side gradient on the editor -X if fewer lines in sketch than can be shown in window, show ticks adjacent -X error/warning location is awkward when no scroll bar is in use -X when only one screen-full, show ticks at exact location -X simpler/less confusing to not show at all? -X MarkerColumn.recalculateMarkerPositions() -X https://github.com/processing/processing/pull/3903 -X Update status error/warning when changing the line -X https://github.com/processing/processing/pull/3907 -X Update status error/warning when changing the line -X when moving away from an error/warning line, de-select it below -X selecting a warning should also show the warning in the status area -X https://github.com/processing/processing/pull/3907 -X clicking an error or warning should give the focus back to the editor -X https://github.com/processing/processing/pull/3905 -X replace startup/about screen (1x and 2x versions) -X change 'alpha' to correct name -X also change the revision in the "about processing" dialog -X https://github.com/processing/processing/issues/3665 -X implement splash screen on OS X -X http://www.randelshofer.ch/oop/javasplash/javasplash.html -X also implement special retina version -X Fix placement and visual design when showing error on hover -X https://github.com/processing/processing/issues/3173 -X implement custom tooltip for error/warning hover -X applies to both MarkerColumn and JavaTextAreaPainter -X make gutter of console match error list -X https://github.com/processing/processing/issues/3904 -o bring back the # of updates on the update tab -o use this instead of the 'icon' stuff? -o or in addition, since only the 'updates' tab has it -X https://github.com/processing/processing/issues/3855 -X for updates available, have it be clickable to open the manager -X fix the design of the completions window -X remove extra border around the outside -X change font -X add 2x version of the icons -X change selection highlight color -o put some margin around it -X https://github.com/processing/processing/issues/3906 - -earlier/cleaning -X list with contrib types separated is really wonky -o do we keep the list? -o does it even work for different contrib types? -X cleaned this up in the last release -X remove the dated releases from download.processing.org -X new Android release (EditorButton constructor changed) -o JavaEditor has several null colors, remove color support -o once the design is complete and we for sure do not need color +jakub +X Include Example packs into update count +X https://github.com/processing/processing/pull/3932 known issues @@ -96,19 +15,30 @@ _ http://www.excelsiorjet.com/kb/35/howto-create-a-single-exe-from-your-java-a _ mouse events (i.e. toggle breakpoint) seem to be firing twice -3.0 final -_ https://github.com/processing/processing/milestones/3.0%20final -_ completion panel -X what should the background color be? -_ test fg/bg color on other operating systems -_ fix icon sizes/design +3.0.1 +_ https://github.com/processing/processing/milestones/3.0.1 +_ error checkers/suggestions not including the library path +_ https://github.com/processing/processing/issues/3924 _ import suggestions box needs design review _ https://github.com/processing/processing/issues/3407 +_ update CM entries when sketchbook location changes +_ https://github.com/processing/processing/issues/3927 + + +run/debug +_ debugger deadlocks when choosing "Step Into" on println() +_ https://github.com/processing/processing/issues/3923 +_ Tweak Mode sometimes freezes while running, require a force quit +_ https://github.com/processing/processing/issues/3928 + + +gui +_ fix background color for selected lines in VariableInspector +_ https://github.com/processing/processing/issues/3925 +_ implement 2x versions of the icons for the debugger window/variable inspector +_ https://github.com/processing/processing/issues/3921 _ different design of squiggly line _ easy to do inside JavaTextAreaPainter.paintSquiggle() - - -gui / post 3.0 _ build custom scroll bar since the OS versions are so ugly _ see notes in the 'dialogs' section below, implement our own option panes? _ tiny trail of dots when moving the selection bar up/down on retina @@ -149,9 +79,11 @@ _ https://github.com/processing/processing/issues/2886 pde/build +_ Editor objects are staying in memory +_ https://github.com/processing/processing/issues/3930 +_ unsupported java version when trying ant run with 7u65 +_ no helpful message about how to automatically download 8u51 _ ignore-tools in build.xml not being called for some reason -_ can't install processing-java into /usr/bin with El Capitan -_ https://github.com/processing/processing/issues/3497 _ when variables used in size(), getting exceptions instead of any warning _ https://github.com/processing/processing/issues/3311 _ crashed on startup w/ JavaScript mode as default b/c PdeKeyListener not found @@ -169,11 +101,11 @@ _ update license info to state gplv2 not v3 _ run through that online license checker _ save() and saveAs() need to be refactored _ https://github.com/processing/processing/issues/3843 - - -breakage -_ remove deprecated methods -_ do the right thing on passing around List vs ArrayList and others +_ clean out the repo +_ https://github.com/processing/processing/issues/1898 +_ search the source for 'applet' references (i.e. SVG docs) +_ update list of optional JRE files +_ https://github.com/processing/processing/issues/3288 _ PreferencesFrame is a misnomer (not a frame itself) _ change to PreferencesDialog, and make it a dialog? _ move Library to LibraryContribution and into contrib? @@ -183,23 +115,12 @@ from the todo list _ reas: comments go nasty when auto-formatted _ reas: code coloring sometimes disappears _ me: undo not in the correct location -_ implement the new gui _ drop XP support (but improve Windows 8 support? ouch) _ improve error message when creating a tab with the same name _ right now it's generic, based on "a file exists" _ don't allow users to create 'blah.java' when 'blah.pde' already in sketch -3.0 beta/final -_ wonder if "Save As" is causing the problems with auto-reload -_ look at the sound library https://github.com/wirsing/ProcessingSound -_ sound is not yet supported on Windows -_ clean out the repo -_ https://github.com/processing/processing/issues/1898 -_ search the source for 'applet' references (i.e. SVG docs) -_ update list of option JRE files -_ https://github.com/processing/processing/issues/3288 - sketchbook _ Mode.rebuildLibraryList() called too many times on startup?