!7 set flag InOSCore. set flag NotifyingPrintLog. sS defaultBackground = #1101488; //#1101303; //#1101465; //#1101438; //#1101355; // #1009931; sS background = defaultBackground; sS backgroundMode = 'fit; sS mainIconID = #1102666, moduleDefaultIconID = #1101337; sS laf; static double minLoadScreenShowingTime = 2; sbool loadBackgroundLater = true; sbool showLoadingScreen = false; static JDesktopPane desktop; sbool useCodeSharing = true; // share code between identical modules static int autoSaveInterval = -10000; // 10 seconds plus slowdown logic static int persistenceDelayPerModule = 10000; // 10 seconds static int systemErrorsToKeep = 10; static ReliableSingleThread rstUpdateModules = new(r { systemQ.add(r updateModules) }); sS lastTopInput; static ReliableSingleThread rstTopInputChanged = rstWithDelay(250, r { S s = getText(tfTopInput); if (neq(lastTopInput, s)) vmBus_send('topInputChanged, lastTopInput = s); }); static volatile long updateCycles; static L systemErrors = synchroList(); static int systemErrors_pointer; static new Flag stopRequested; static SimpleLiveValue systemStatus = stringLiveValue("loading"); static bool firstModuleShown; static Map ghostModules = weakHashMap(); // key is main class (if dynamic module) or instance (if static module) static Q systemQ; static AccessControlContext globalACC; static volatile Module activeModule; static JTextField tfTopInput; // the input field in the OS menu bar static long tfTopInput_dontSelectAll; // sysNow timestamp static StefansOS_ConnectToServer connector; static Map generalMap = synchroMap(); static L trayAreaComponents = synchroList(); sbool printOnPersistContents, verboseCleanUp; static JMenuBar menuBar; sbool katze_send = true, katze_sendTyped; sO makeReloadingComponent; // F1 static long startTime; static NotTooOften backgroundGCFrequency = everyTenMinutes(); static Set hideFeatures; static LS standardModules; sS botName = "Stefan's OS."; sS osName; sbool showTopInput = true; static Runnable shutdownConsole; // instead of showConsole() sbool verboseModuleDeletes, cacheTranspilationsDuringBoot; // if you want other initial modules sO initialModules_override; // VF1 static Runnable restarter_override; static O onStart; p { startTime = sysNow(); vm_generalMap_put(stefansOS := mc()); callF(onStart, mc()); //set getServerTranspiled_printStackTrace; print(headless() ? "We are headless." : "Starting GUI."); if (!headless()) showControls(jbutton("TROUBLESHOOTING", r { stopRequested.raise() })); noRegularGC(); // not while we're loading if (onLocallyInferiorJavaX()) { print("Restarting to use standard JavaX"); restart(); } checkMaxWindowBoundsBug(); if (!eq("0", trim(loadTextFile(javaxDataDir("compile-on-server"))))) set hotwire_compileOnServer; /*if (isLinux() && isRoot()) addToDefaultVMArgs("-XX:ThreadPriorityPolicy");*/ if (java10OrHigher()) { addStandardAddOpensFlags(); addPermitIllegalAccessesFlag(); if (!hasPermitIllegalAccessesFlagInCurrentVM()) { print("RESTARTING with proper JDK 11 arguments"); restart(); } } if (java8OrHigher() && !contains(defaultVMArgs(), "UseZGC")) addToDefaultVMArgs(smallHeapArgs()); //laf = 'webLAF; // Let's not generally use it, is sluggish on my machine //laf = 'nimbus; laf = 'platform; //if (isMac()) laf = 'platform; // because https://github.com/michael-hagen/JTattoo/issues/1 if (isMac()) vmGeneralMap_set('iconifyBroken, true); if (isLinux()) laf = 'jtattoo; /*if (vmArgs().contains("-XX:+PrintAssembly")) pcall { teeSystemOutAndErrToFile(programFile("os.log")); }*/ if (!hasClass("x30_pkg.x30_util")) { if (!zipFileContains_falseOnError(pathToJavaxJar(), "x30_pkg/x30_util.class")) upgradeJavaXAndRestart(); else restart(); } _handleException_addHandler(voidfunc(Throwable e) { try { synchronized(systemErrors) { listSet(systemErrors, systemErrors_pointer, e); systemErrors_pointer = (systemErrors_pointer+1) % systemErrorsToKeep; } } catch e2 { printStackTrace(e2); } infoBox("Error: " + exceptionToStringShort(e)); LastErrors lastErrors = first(staticModulesOfType(LastErrors)); if (lastErrors != null) lastErrors.addError(e); }); timeJumpDetector(); vm_generalMap_put('consoleInUse, true); // bots made by modules should not handle console monitorThreadAllocatedMemory(); // Solve deadlocks every 10 to be sure doEvery(10000, r printDeadlocksAndSolve); print("Data dir: " + javaxDataDir()); vm_setGlobalACC(globalACC = acc_current()); if (swic(activateFramesOf(programIDPlusHome()), "OK")) { print("OS already running!"); cleanKill(); } framesBot(); if (nempty(botName)) makeBot(botName); S printLogSize = trim(loadTextFile(javaxDataDir("os-print-log-size.txt"))); if (isInteger(printLogSize)) printLogMaxChars(parseInt(printLogSize)); vm_generalMap_put('newSwingComponentRegistry, voidfunc(Component c) { allAWTComponents_extraList.add(c) }); connector = new StefansOS_ConnectToServer; connector.start(); //substance(); final SimpleLiveValue lvDetails = stringLiveValue(); lvDetails.onChange(r { print(lvDetails!) }); stefansOS_loadingAnimation_fullScreen = startInFullScreen() && !isWindows() /* bug */; final Component loadingAnim = showLoadingScreen ? stefansOS_loadingAnimation(r { stopRequested.raise() }, lvDetails) : null; try { long start = sysNow(); systemQ = startQ("System Q"); useDBOf(#1015871); lvDetails.set("Loading database"); db(autoSaveInterval); if (!headless()) { // if you use Processing JPopupMenu.setDefaultLightWeightPopupEnabled(false); lvDetails.set("Loading background"); background = or2(trim(loadTextFile(javaxDataDir("os-background.txt"))), background); if (!isSnippetID(background)) background = fileToURI(new File(background)); try { if (eq(backgroundMode, 'fit)) desktop = loadBackgroundLater ? jDesktopPaneWithFitPicture_smooth_cacheScaled_loadLater(background) : jDesktopPaneWithFitPicture_smooth_cacheScaled(background); else desktop = jDesktopPaneWithSkyPicture/*_autoUnload*/(background, Color.black); } catch print e { try { desktop = jDesktopPaneWithFitPicture_smooth(defaultBackground); } catch print e2 { desktop = jDesktopPane(); } } setMainDesktopPane(desktop); autoFixDesktopPane(desktop); // Allow frame switching from AI bar & similar components installInternalFrameSwitcher_v3(desktop).shouldSwitch = func -> bool { sameComponentOrDeepChildOf(getFocusOwner(), menuBar) }; } long ms = consoleShowing() ? toMS(minLoadScreenShowingTime) : 0; long remaining = start+ms-sysNow(); if (remaining <= 0) lvDetails.set("Done loading"); else { S seconds = formatDouble(toSeconds(remaining), 1); lvDetails.set("Done loading, but will wait if you hit the troubleshooting button for " + seconds + " more second" + (eq(seconds, "1") ? "" : "s")); } //if (loadingAnim != null) waitUntilSysTimeOrFlag(start+ms, stopRequested); } catch e { _handleException(e); stopRequested.raise(); } try { bool flag = stopRequested.isUp(); // get before closing animation if (flag) ret with showFrame("Stop screen", centerAndSouthWithMargins( jcenteredlabel("More troubleshooting options will go here."), jcenteredbuttons( "Start " + osName() + " normally", r restart, "Switch to " + otherVersionName(), r startOtherVersion, "Delete session", disableButtonWhileCalcing(func -> bool { if (!fileExists(conceptsFile())) ret false with infoBox("Session already empty."); if (!confirmOKCancel("Really delete your current session?")) false; cleanMeUp_concepts(); renameFileToSomeBackupName(conceptsFile()); infoBox("Session deleted. Starting again."); disableAllButtonsInWindow(heldInstance(JButton)); sleepSeconds(3); restart(); false; })))); //autoRestart(); thread { serverAutoRestartMD5(); } // just a short ping pcall { setLookAndFeel(); } showDesktop(); } finally { disposeWindow(loadingAnim); } initAfterDBLoad(); setOpt(javax(), regularGC_firstDelay := 60000); call(javax(), 'regularGC); if (!headless()) { setOpt(javax(), regularGC_condition := func -> bool { if (backgroundGCFrequency! || vmHasActiveFrame()) ret true /*with print("GC")*/; else ret false /* with print("Skipping GC (not in foreground)") */; }); } hideConsole(); manualConsole(); //clearConsole(); if (headless()) sleep(); } sbool startInFullScreen() { ret eq("1", trim(loadTextFile(javaxDataDir("start-os-in-full-screen.txt")))); } svoid setStartInFullScreen(bool b) { saveTextFile(javaxDataDir("start-os-in-full-screen.txt"), b ? "1" : "0"); } sbool showDesktop_first = true; svoid showDesktop { if (headless()) ret; bool done = false; S title; if (nempty(osName)) title = osName; else { title = programName(); S subDir = javaxVirtualSpaceName(); if (subDir != null) title = "[" + subDir + "] " + title; } if (showDesktop_first && startInFullScreen()) pcall { showFullScreen(title, desktop); done = true; } if (!done) { showMaximizedFrame(title, desktop); titlePopupMenu_top(desktop, voidfunc(JPopupMenu menu) { addMenuItems(menu, "New Session", rThreadPcallMessageBox(r deleteAllModules), "Restore Initial Modules", r initialModules, ); }); } if (showTopInput) registerFunctionKey(getFrame(desktop), 1, r { requestFocus(tfTopInput) }); fillMenuBar(); doNothingOnClose(getFrame(desktop)); frameIcon(mainIconID, desktop); showDesktop_first = false; cleanExitOnFrameClose_ifStillInSameFrame(desktop); } sbool inFullScreen() { ret isFullScreen(desktop); } svoid fullScreenOff() { if (inFullScreen()) fullScreenOnOff(); } svoid fullScreenOnOff { // Don't screw up window positions while adjusting from/to fullscreen autoFixDesktopPane_exclude.add(desktop); temp tempAfterwards(r { autoFixDesktopPane_exclude.remove(desktop) }); Window w = getWindow(desktop); if (!inFullScreen()) { showFullScreen(frameTitle(desktop), desktop); pcall { frameIcon(mainIconID, desktop); } cleanExitOnFrameClose_ifStillInSameFrame(desktop); fillMenuBar(); setStartInFullScreen(true); } else { removeFromParent(desktop); showDesktop(); setStartInFullScreen(false); } // Allow closing empty "zombie" windows (why do we have these?) final JFrame f = getFrame(desktop); onFrameClosing(f, r { if (isEmptyFrame(f)) { removeListener(); disposeWindow(f); }}); disposeWindow(w); fixDesktopPane(desktop); } svoid updateMenuBar() swing { //temp tempRememberFocusedComponent(); JMenuBar mb = getMenuBar(desktop); if (mb == null) { mb = addMenuBar(desktop); mb.setLayout(new javax.swing.plaf.basic.DefaultMenuLayout(menuBar, BoxLayout.X_AXIS)); } keepComponentsByPred(mb, func(Component c) -> bool { c instanceof JMenu || c == tfTopInput }); //clearMenuBar(); fillMenuBar(); } svoid fillMenuBar() swing { menuBar = addMenuBar(desktop); set jmenuItem_newThreads; S version = version(); S name = osName(); //S subDir = userHomeSubDirName(); //if (subDir != null) name += " [" + subDir + "]"; addMenuIfNempty(desktop, trim(name), featureMenuItem("Screenshot"), r stefansOS_screenshot, featureMenuItem("Full screen on/off"), r fullScreenOnOff, featureMenuItem("Switch OS version", "Switch to " + otherVersionName()), r { innerCleanUp(); startOtherVersion(); cleanKill(); }, "---", featureMenuItem("Restart OS", "Restart " + or2(osName, "Stefan's OS")), r { showConsole(); restart(); }, featureMenuItem("Exit"), r cleanKill ); addMenu(desktop, "Current Module", "Show Menu", r showCurrentModuleMenu); L moduleMenu = ll( featureMenuItem("Other Module..."), r stefansOS_addDynamicModuleDialog); for (int i = 0; i+1 < l(standardModules); i += 2) { moduleMenu.add(standardModules.get(i)); S id = standardModules.get(i+1); moduleMenu.add(r { makeOrShowModule(id) }); } moduleMenu.addAll(ll( featureMenuItem("Welcome Screen"), r { makeOrShowModule("#1016067/WelcomeScreen") }, featureMenuItem("Quick Module Search"), r addQuickModuleSearch, //"Hello (input field for everything)", r { makeOrShowModule("Hello") }, featureMenuItem("Task Bar"), r { makeOrShowModule("#1019954/TaskBar_dev") }, featureMenuItem("System Print Log"), r { makeOrShowModule("#1018866/SystemPrintLog") }, hideFeature("Internal Types") ? null : jmenu("Internal Types", map(myNonAbstractClassesImplementing(Module), func(final Class c) -> JMenuItem { jMenuItem(shortClassName(c), rThread { makeOrShowStaticModuleOfType(c) }) })), featureMenuItem("Module Classes"), r { makeOrShowStaticModuleOfType(ModuleClasses) }, "---", jDynamicScrollingMenu("Loaded Modules", voidfunc(JPopupMenu menu) { for (final Module m : sortedByMethodIC('moduleName, onModules())) addMenuItem(menu, m.moduleName(), rThread { showModule(m) }); }) )); addMenu(desktop, "Modules", asObjectArray(moduleMenu)); // TODO - need to generate menu items differently in enhanceFrame //addFullyDynamicMenu(desktop, "Current module", addMenu(desktop, "More", featureMenuItem("Start External JavaX Program..."), r stefansOS_startExternalJavaXProgram, "---", featureMenuItem("Run 10 Second Profiler"), r tenSecondProfileAndShowInFrame, featureMenuItem("Find memory leaks", "Find memory leaks (PID: " + getPID() + ")"), r stefansOS_findMemoryLeaks, "Computer ID: " + computerID(), r { copyTextToClipboard_infoBox(computerID()) }, featureMenuItem("Show console"), rThread showConsole, featureMenuItem("System Version"), r { makeOrShowModule("#1016442/SystemVersion") }, featureMenuItem("Remove moduleless frames"), rThread dm_closeModuleLessFrames, featureMenuItem("Clean disk caches"), rThread stefansOS_cleanDiskCaches, featureMenuItem("Hard exit"), rHardExit(), ); // Add the fancy stuff JMenuBar menuBar = cast call(getFrame(desktop), 'getJMenuBar); if (tfTopInput == null && showTopInput) { tfTopInput = jcenteredtextfield(uniq(TopInput).text); setFontSize(tfTopInput, 16); selectAllOnFocusIf(tfTopInput, func -> bool { elapsedTime(tfTopInput_dontSelectAll) >= 2000 }); onChange(tfTopInput, r { cset(uniq(TopInput), text := getText(tfTopInput)); rstTopInputChanged.trigger(); }); onEnter(tfTopInput, r { S info = cast generalMap.get('topInputInfo); temp dm_generalMap_tempPut(topInputInfo := or2(info, "typed")); S text = getText(tfTopInput); vmBus_send('topInput, text); if (katze_send) if (nempty(info)) katze_userSaid(info, text); else if (katze_sendTyped) katze_userTyped(text); }); } if (showTopInput && getParent(tfTopInput) == null) { menuBar.add(Box.createHorizontalStrut(20)); menuBar.add(tfTopInput); } if (!containsChildOfType(menuBar, JLabel.class)) { // look for clock label if (!showTopInput) menuBar.add(Box.createHorizontalGlue()); else { menuBar.add(Box.createHorizontalStrut(5)); menuBar.add(onClick(setToolTip([[Simulate pressing Enter key in input field to the left ("AI bar")]], jimage(#1101426)), r { simulateEnter(tfTopInput) })); } //menuBar.add(jhgrid(null, tfTopInput)); //menuBar.add(jhgrid(tfTopInput, null)); menuBar.add(Box.createHorizontalStrut(20)); for i over trayAreaComponents: { Component c = trayAreaComponents.get(i); continue if c == null; menuBar.add(c); menuBar.add(Box.createHorizontalStrut(i == l(trayAreaComponents)-1 ? 20 : 6)); } menuBar.add(jLiveValueLabel(clockTimeLiveValue())); menuBar.add(Box.createHorizontalStrut(6)); } } svoid addQuickModuleSearch { makeOrShowModule("#1016702/LoadedModuleSearch"); makeOrShowModule("#1016932/ServerModuleSearch"); } static tempDisposeInternalFrame_obj tempBusyAnimation(fS text) { ret vmExiting() ? null : tempBusyAnimation(stringLiveValue(text)); } static tempDisposeInternalFrame_obj tempBusyAnimation(LiveValue text) { if (headless()) null; final JLabel anim = jBackground(Color.white, jAnimation_liveValueText(#1101316, text)); swing { addInternalFrame_dontSelect.set(true); addInternalFrame_layer.set(JLayeredPane.POPUP_LAYER); addInternalFrame(desktop, "", null, anim); packInternalFrameInTopRightCorner(anim); JInternalFrame f = getInternalFrame(anim); //print("Have busy animation: " + f + " in " + getParent(f)); } ret tempDisposeInternalFrame(anim); } svoid allRegularFixes { applyStandardSwingFixes(); cleanDefunctACCsInAllThreads(); cleanDefunctACCsInAllSwingComponents(); } svoid gcWithFixes { allRegularFixes(); gc(); allRegularFixes(); } svoid initAfterDBLoad { doEvery(30000, r allRegularFixes); doEvery(600000, r clearSnippetTitleCacheIfOnline); set cleanUp_interruptThreads; // for Java Chrome classForNameOpt("java.util.prefs.FileSystemPreferences"); SimpleLiveValue lvText = stringLiveValue(jlabel_textAsHTML_center("Restoring Session")); temp final tempDisposeInternalFrame_obj anim = tempBusyAnimation(lvText); if (anim != null) { onResizeAndNow(anim.component, r { setVerticalAlignment( anim.component.getHeight() >= 150 ? JLabel.CENTER : JLabel.TOP, anim.component) }); growInternalFrameLeft(anim.component, 50); growInternalFrameSouth(anim.component, 50); } initialModules(); UpdateCycles uc = conceptWhere(UpdateCycles); if (uc != null) updateCycles = uc.value; stefansOS_installQuickSearchHelper(); // START MODULES L modules = startOrder(onModules()); temp tempSetTL(loadLibraryOrSrcLib_tempCache, new Map); temp cacheTranspilationsDuringBoot ? tempSetMCOpt(getServerTranspiled2_tempCache := syncMap()) : null; if (cacheTranspilationsDuringBoot) thread { for (Module m : modules) pcall { if (m cast DynamicModule) { print("Preloading " + m.moduleID); getServerTranspiled2(m.moduleID); } } print("Preloading done"); } int i = 0; for (Module m : modules) { if (isShuttingDown()) ret; ++i; lvText.set(jlabel_textAsHTML_center( "Starting module " + i + "/" + l(modules) + ":\n" + m.moduleName())); startModule(m); } /*addConceptIndex(simpleConceptIndex(rstUpdateModules)); rstUpdateModules.trigger();*/ if (isShuttingDown()) ret; systemStatus.set("running"); print("== STARTED IN " + iceil(elapsedSeconds(/*vmStartTime_sys()*/startTime)) + " SECONDS =="); } static L startOrder(L modules) { ret sortedByComparator( combineComparators( main. descFieldComparator('visible), main. fieldComparator('zOrder)), modules); } svoid initialModules { if (initialModules_override != null) ret with pcallF(initialModules_override, mc()); initialModules_base(); } svoid initialModules_base { if (headless()) { makeOrShowModule("#1016576/ConnectToServer"); ret; } if (empty(onModules())) { showModule(new DynamicModule(#1016081, 'main$WelcomeScreen)); showModule_noFocus(getModuleByID(makeModule("#1018866/SystemPrintLog"))); showModule_noFocus(getModuleByID(makeModule("#1019954/TaskBar_dev"))); //makeModule("#1016872/SnippetsDB"); makeModule("#1016932/ServerModuleSearch"); makeModule("#1016702/LoadedModuleSearch"); //makeModule("#1018602/QuickAudioRecord"); makeModule("#1019326/WitAILastRecording"); makeModule("#1019400/SpeechRecogConfirmation"); } } svoid triggerUpdate { rstUpdateModules.trigger(); } // not done anymore svoid updateModules { /*++updateCycles; for (Module m : onModules()) updateModule(m);*/ } svoid updateModule(Module m) { if (m == null) ret; temp m.enter(); pcall { m.update(); } } svoid updateModules(final Collection l) { systemQ.add(r { for (Module m : unnull(l)) updateModule(m); }); } svoid saveZOrder { for (Module m) cset(m, zOrder := getComponentZOrder(getInternalFrame(m.vis))); } svoid cleanMeUp { saveZOrder(); autoConsole(); if (shutdownConsole == null) showConsole(); else pcallF(shutdownConsole); killProgram(#1019683); // stop watch dog systemStatus.set("shutting down"); temp tempBusyAnimation("Shutting Down"); print("PRE-CLEAN UP"); preCleanUp(list(Module)); for (Module m) { if (m.vis != null) pcall { print("UNVISUALIZING " + moduleIDAndName(m)); m.unvisualize(); print("UNVISUALIZED " + moduleIDAndName(m)); } print("CLEANING UP " + moduleIDAndName(m)); cleanUp(m); print("CLEANED UP " + moduleIDAndName(m)); } print("CLEAN UP DONE"); cleanedUp = true; } static L onModules() { ret conceptsWhere(Module, on := true); } sbool hasModuleWithFields(Class c, O... params) { ret hasConcept(c, concatArrays(new O[] {on := true}, params)); } sbool startModule_reloading, startModule_doShare; sO startModule_beforeStart; svoid startModule(Module m) { ping(); pcall { //addIfNotThere(modules, m); temp m.enter(); if (m.started) ret; m.started = true; print("Starting module " + m.moduleName()); try { m.start(); } catch e { m.setError(e); _handleException(e); } vmBus_send('moduleStarted, m.moduleID()); rstUpdateModules.trigger(); if (m.visible) showModule(m); }} static Module showModule(final Module m) { ret showModule(m, true); } static Module showModule_noFocus(final Module m) { ret showModule(m, false); } svoid runInSystemQAndWait(Runnable r) { if (isAWTThread()) ret with callF(r); runInQAndWait(systemQ, r); } static A evalInSystemQ(F0 f) { if (isAWTThread()) ret callF(f); ret evalInQ(systemQ, f); } static Module showModule(final Module m, final bool focus) { if (m == null) ret m; runInSystemQAndWait(r { startModule(m); if (headless()) ret; temp m.enter(); if (m.vis != null) { if (focus && !isLoading()) activateInternalFrame(m.vis); ret; } csetAndStatusChange(m, visible := true); visualizeModule(m); if (m.vis != null) swing { Rect r = m.frameRect; /*if (r == null) r = randomRect(desktop.getWidth(), desktop.getHeight(), 10, 150, 100); if (r == null) r = Rect(10, 10, 200, 100); print("Showing frame at " + r);*/ S frameTitle = m.moduleName(); final JInternalFrame f; bool toBack = isLoading() && firstModuleShown; bool activate = focus && !toBack; { temp tempSetThreadLocal(addInternalFrame_toBack, toBack); temp tempSetThreadLocal(addInternalFrame_dontSelect, !activate); f = showInternalFrame(desktop, frameTitle, r, m.vis); set firstModuleShown; } if (r == null) centerPackInternalFrame(f); f.setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE); onInternalFrameIconified(f, r { hideModule(m) }); onInternalFrameClosing(f, rThread { deleteModule(m) }); onInternalFrameActivated(f, r { setActiveModule(m) }); onInternalFrameDeactivated(f, r { if (activeModule == m) setActiveModule(null) }); internalFrameIcon(f, or2(m.iconID, moduleDefaultIconID)); m.enhanceFrame(f); if (activate) setActiveModule(m); } }); ret m; } svoid showModules(L l) { for (Module m : unnull(l)) showModule(m); } sbool deleteModule(final Module m) { pcall { bool warn = isTrue(callOpt(resolveModule(m), 'warnOnDelete)); if (warn && !confirmOKCancel("Really delete module " + m + "?")) false; } runInSystemQAndWait(r { if (verboseModuleDeletes) print("delete phase 1"); O m2 = unwrapDynamicModule(m); vmBus_send('deletingModule, m2); ghostModules.put(m == m2 ? m : m2.getClass(), nu(GhostModule, name := m.moduleName(), created := m.created, deleted := now(), instance := new WeakReference(m2))); if (verboseModuleDeletes) print("delete phase 2"); pcall { m.unvisualize(); } if (verboseModuleDeletes) print("delete phase 3"); removeConcept(m); // generates oStruct vmBus_send('moduleDeleted, m); if (verboseModuleDeletes) print("delete phase 4"); pcall { S snippetID = m instanceof DynamicModule ? m/DynamicModule.moduleID : "internal_" + shortClassName(m); logStructure(deletedModulesLogFile(snippetID), litmap( globalID := aGlobalID(), deleted := now(), module := m)); } //triggerUpdate(); }); true; } svoid visualizeModule(Module m) { pcall { if (m.vis == null) m.vis = m.visualize(); } pcall { if (m.vis == null) m.vis = defaultVisualize(m); } vmBus_send('moduleVisualized, m); } svoid hideModule(final Module m) { if (m == null) ret; runInSystemQAndWait(r { temp m.enter(); csetAndStatusChange(m, visible := false); pcall { m.unvisualize(); } }); } svoid csetAndStatusChange(Module m, O... params) { if (cset(m, params) > 0) vmBus_send('moduleStatusChange, m, params); } svoid revisualizeModule(Module m) { pcall { if (m == null) ret; temp m.enter(); JInternalFrame frame = getInternalFrame(m.vis); if (frame == null) ret; m.unvisualize1b(); m.unvisualize2(); visualizeModule(m); setInternalFrameContents(frame, m.vis); } } abstract concept Module { transient JComponent vis; transient bool started; transient Lock lock = lock(); static int ALWAYSONTOPWHENPOPPEDOUT = 1; bool on = true, visible; int flags; Rect frameRect; int zOrder; S iconID; PersistableThrowable error; //transient Set timers; JComponent visualize() { null; } void unvisualize() { pcall { unvisualize1(); } pcall { unvisualize2(); } vmBus_send('moduleUnvisualized, this); } void enhanceFrame(JInternalFrame frame) {} void start() {} void unvisualize1() { disposeInternalFrame(getInternalFrame(vis)); unvisualize1b(); } void unvisualize1b() { grabFrameRect(); vis = null; } void unvisualize2() {} void update() {} void grabFrameRect() { JInternalFrame f = getInternalFrame(vis); if (f != null) cset(this, frameRect := toRect(getBounds(f))); } Rect getFrameRect() { grabFrameRect(); ret frameRect; } void cleanMeUp_started() { started = false; } void delete() { unvisualize(); cleanUp(this); super.delete(); } S sourceCode() { ret javaxSourceOfMyClass1(shortClassName(this)); } // for all modules void triggerUpdate { rstUpdateModules.trigger(); } void setModuleIcon(S iconID) { if (eq(iconID, this.iconID)) ret; this.iconID = iconID; internalFrameIcon(vis, iconID); } O resolve() { ret this; } O getError() { ret error; } S moduleID() { ret str(id); } void setError(Throwable e) { cset(this, error := persistableThrowable(e)); } AutoCloseable enter() { null; } JComponent vis() { ret vis; } static bool needsParameters() { false; } S moduleName() { ret humanizeFormLabel(shortClassName(this)); } bool hasFlag(int flag) { ret anyCommonBits(flags, flag); } void setFlag(int flag) { _setField(flags := flags | flag); } void clearFlag(int flag) { _setField(flags := flags & ~flag); } } // END CONCEPT MODULE static JComponent defaultVisualize(Module m) { ret jCenteredMultiLineLabel(renderConcept(m)); } static A findModule(Class c) { ret findConcept(c, on := true); } // returns module ID static S findDynModuleOfType(S type) { DynamicModule m = findConcept(DynamicModule, on := true, _className := "main$" + type); ret m == null ? null : m.moduleID(); } sbool moduleTypeIs(Module m, S type) { if (m == null) false; ret eq(moduleResolvedClassName(m), "main$" + type); } sS moduleResolvedClassName(Module m) { if (m == null) null; if (m instanceof DynamicModule) ret m/DynamicModule._className; ret className(m); } // returns module ID sS findClosestModuleTo(O searcher, S type) { JInternalFrame f = getInternalFrame(dm_getVisualization(searcher)); if (f == null) null; Pt p = centerOfRect(toRect(getBounds(f))); new Lowest best; for (Module m : onModules()) { JInternalFrame f2 = getInternalFrame(m.vis); if (f2 == null || f2 == f) continue; if (type != null && !moduleTypeIs(m, type)) continue; Rect r2 = toRect(getBounds(f2)); best.put(m.moduleID(), rectPointDistance(r2, p)); } ret best!; } static L staticModulesOfType(Class type) { ret conceptsWhere(type, on := true); } static L staticModulesOfExactType(Class type) { ret filterByExactType(type, staticModulesOfType(type)); } static L listModules() { ret map unwrapDynamicModule(onModules()); } static int moduleCount() { ret l(onModules()); } static L visibleModules() { ret map unwrapDynamicModule(objectsWhere(onModules(), visible := true)); } static O unwrapDynamicModule(Module m) { ret m instanceof DynamicModule ? or(m/DynamicModule.o, m) : m; } sbool moduleStillThere(O o) { Module m = o instanceof Module ? o/Module : (Module) get(o, '_host); ret isConceptRegistered(mainConcepts, m); } static O getDynModuleByID(S moduleID) { if (moduleID == null) null; ret resolveModule(getConcept(Module, parseLong(moduleID))); } static Module getModuleByID(S moduleID) { if (moduleID == null) null; ret getConcept(Module, parseLong(moduleID)); } sS getInterestingString { InterestingString m = findModule(InterestingString); ret m == null ? getText(tfTopInput) : m.theString; } sS modulesSessionGrab() { grabFrameRects(); ret struct(ll(programID(), localDateWithMilliseconds())) + "\n" + mainConcepts.xfullgrab(); } svoid autoSaveModulesSession() { infoBox("Auto-saving session."); S grab; logQuoted(javaxBackupDir(fsI(programID()) + "/auto-saved-sessions.txt"), grab = modulesSessionGrab()); infoBox("Auto-save done (" + l(grab) + " chars)"); } svoid deleteAllModules() { autoSaveModulesSession(); deleteConcepts(Module); initialModules(); } svoid restoreModulesSession(S text) { autoSaveModulesSession(); systemStatus.set("shutting down"); infoBox("Releasing session"); cleanMeUp(); cleanUp(mainConcepts); mainConcepts = null; //sleepSeconds(1); infoBox("Loading session"); systemStatus.set("loading"); mainConcepts = new Concepts().load(dropFirstLine(text)); initAfterDBLoad(); infoBox("Session restore done"); } svoid grabFrameRects { for (Module m : onModules()) m.grabFrameRect(); } sclass DynamicModule extends Module { // moduleID is the snippet ID // "className" is taken by DynamicObject; _className == null for old-style dyn module S moduleID, _className; S oStruct; // serialized dynamic object sbool reload_replaceFrame = true; transient Class c; transient O o; transient bool contentsDirty = true; transient ReliableSingleThread rstPersist = rstWithDelay(persistenceDelayPerModule, r persistContents); transient O reloadData; // data held for module during reload *() {} *(S *moduleID, S *_className) {} *(S *moduleID, S *_className, Class *c) {} static bool needsParameters() { true; } AutoCloseable enter() { ret castForTemp(callOpt(o, 'enter)); } JComponent visualize() { temp enter(); ret (JComponent) callOpt(o, 'visualize); } void enhanceFrame(final JInternalFrame f) { final WeakReference fRef = new(f); final WeakReference mRef = new(this); S idText = str(id); if (isTrue(vmGeneralMap_get('iconifyBroken))) internalFrameTitlePopupMenuItem(f, "Hide/Minimize", r { hideModule(mRef!) }); idText += "/" + moduleLibID(); if (!hideFeature("Show source code")) internalFrameTitlePopupMenuItem(f, "Source code [Module ID: " + idText + "]", r-thread { pcall { if (empty(mRef->moduleID)) ret with infoBox("No source code found"); dm_openSnippetInEditor(mRef->moduleID); }}); internalFrameTitlePopupMenuItem(f, "Reload", r reload); internalFrameTitlePopupMenuItem(f, "Duplicate", rThread { duplicateModule(DynamicModule.this) }); if (!hideFeature("Retranspile")) internalFrameTitlePopupMenuItem(f, "Medium Retranspile", rThread { transpileOnServerWithErrorWindow(moduleID, true, r reload) }); if (!hideFeature("Pop Out")) internalFrameTitlePopupMenuItem(f, "Pop Out", r { clearFlag(ALWAYSONTOPWHENPOPPEDOUT); stefansOS_popOutModule(DynamicModule.this); }); if (!hideFeature("Pop Out + Always On Top")) internalFrameTitlePopupMenuItem(f, "Pop Out + Always On Top", r { setFlag(ALWAYSONTOPWHENPOPPEDOUT); stefansOS_popOutModule(DynamicModule.this); }); { temp enter(); pcallOpt(o, 'enhanceFrame, f); } internalFrameTitle(f, moduleName()); } S moduleLibID() { ret moduleID + "/" + dropPrefix("main$", _className); } S moduleName() { S name = (S) callOpt(o, 'moduleName); if (nempty(name)) ret name; ret originalModuleName(); } S originalModuleName() { S title = snippetTitle_cached(moduleID); //ret dropSuffixICTrimOneOf(title, "[Dyn Module]", "[Dyn Module, OK]", "[Dyn Module, shortened]"); ret stefansOS_cleanModuleName(title); } void start() { try { start_impl(); } catch e { setError(e); _handleException(e); } } void start_impl { if (moduleID == null) ret; if (c == null) c = startModule_reloading && !startModule_doShare ? hotwireModule(moduleID) : hotwireModule_withSharing(moduleID); replaceACCInClassLoader(c, globalACC); if (oStruct != null) pcall { Map renames = cast getOpt(c, '_renameClasses); //print("Class renames: " + sfu(renames)); S renamed = migrateClassesInStructureText(oStruct, renames); //print("Renamed: " + renamed); o = unstructureInRealm(renamed, c); } if (o == null) if (_className == null) o = c; // old-style - just a class else { o = nu(_getClass(c, _className)); // new-style (module is an object) if (!stefansOS_checkModuleInstance(o)) { // TODO: doesn't seem to trigger for modules with wrong class name o = null; S msg = this + " failed to load - " + className(o) + " not an instance of DynModule"; infoBox(msg); error = persistableThrowable(new RuntimeException(msg)); ret; } } setOptAll(o, _host := this, lock := lock); temp enter(); callF(startModule_beforeStart, this); if (o instanceof Class) callMain(o); else callOpt(o, 'start); } void unvisualize2() { callOpt(o, 'unvisualize); } void update() { callOpt(o, 'update); } // TODO - only when called from DynModule // (works for now, but should be renamed) void _change() { super._change(); vmBus_send moduleChanged(this); contentsDirty = true; if (rstPersist != null) rstPersist.trigger(); } void persistContents() enter { if (_concepts != null && contentsDirty) { vmBus_send persistingModuleContents(this); contentsDirty = false; //oStruct = null; pcall { if (o != null && !o instanceof Class) { cset(this, oStruct := struct(o)); if (printOnPersistContents) print("Persisted contents: " + moduleID + " - " + l(oStruct) + " chars"); callOpt(o, 'onPersisted); } } } } void cleanMeUp() { persistContents(); if (verboseCleanUp) print("o: " + className(o) + ". Cleaning up main class: " + mainClass(o)); if (mainClass(o) == mc()) // anomalous object cleanUp(o); else { if (classLoadedInOtherModule(mainClass(o), this)) { print("KEEPING code (loaded in other module)"); cleanUp(o); } else cleanUpObjectAndItsMainClass(o); } o = null; c = null; } void reload() { reloadModuleInBackground(this); } // don't call directly - runs in system queue void reload_impl() { if (reloadData == null) reloadData = callOpt(o, '_getReloadData); bool poppedOut = stefansOS_moduleIsPoppedOut(this); if (poppedOut) stefansOS_popInModule(this); JInternalFrame frame = getInternalFrame(vis); unvisualize1b(); unvisualize2(); if (o != null) ghostModules.put(o.getClass(), nu(GhostModule, name := moduleName(), created := created, deleted := now(), instance := new WeakReference(o))); cleanUp(this); // also sets started to false if (frame != null) setInternalFrameContents(frame, makeReloadingComponent != null ? callF(makeReloadingComponent, this) : makeStandardReloadingComponent(this) ); visible = false; { temp tempSetMC(startModule_reloading := true); startModule(this); } if (reloadData != null) { callOpt(o, '_setReloadData, reloadData); reloadData = null; } if (frame != null) { if (reload_replaceFrame) { // avoids some bugs cset(this, frameRect := toRect(getBounds(frame))); disposeInternalFrame(frame); showModule(this); } else { csetAndStatusChange(this, visible := true); visualizeModule(this); //print("New content: " + vis); setInternalFrameContents(frame, vis); } } if (poppedOut) stefansOS_popOutModule(this); rstUpdateModules.trigger(); // I think this is obsolete } S sourceCode() { ret loadSnippet(moduleID); } O resolve() { ret o; } O getError() { if (o != null) { O error = callOpt(o, 'getError); if (error != null) ret error; } ret super.getError(); } toString { ret "DynModule " + moduleID + "/" + shortenClassName(_className); } void setError(Throwable e) { if (o != null && isTrue(callOpt(o, 'setError, e))) ret; super.setError(e); } } /*static L resolvedModules() { new L l; for (Module m : onModules()) l.add(m.resolve()); ret l; }*/ static S moduleID(Module m) { ret m == null ? null : m.moduleID(); } static O resolveModule(O m) { ret m instanceof Module ? m/Module.resolve() : m; } static S makeModule(Class moduleClass) { ret makeModule(shortClassName(moduleClass)); } static S makeModule(S moduleLibID) { ret makeOrShowModule(moduleLibID, false); } static S makeOrShowModule(S moduleLibID) { ret makeOrShowModule(moduleLibID, true); } sS makeOrShowModule(fS moduleLibID, final bool orShow) { ret evalInQ(systemQ, func -> S { // XXX - changed 2019/07/10 makeOrShowModule_impl(moduleLibID, orShow) }); } sS makeOrShowModule_impl(fS moduleLibID, final bool orShow) { // makes dynamic & static modules if (isIdentifier(moduleLibID)) ret moduleID(makeOrShowStaticModuleOfType(moduleLibID, orShow)); L l = splitAtSlash(moduleLibID); if (!isSnippetID(first(l))) fail("Unknown module lib ID: " + moduleLibID); S snippetID = first(l), className = second(l); className = className == null ? null : "main$" + className; DynamicModule m = findConcept(DynamicModule, on := true, moduleID := snippetID, _className := className); if (m == null) { Class c = hotwireModule_withSharing(snippetID); m = DynamicModule(snippetID, className, c); vmBus_send('moduleLoaded, m); } if (orShow) showModule(m); else startModule(m); ret moduleID(m); } // beforeStart: voidfunc(DynamicModule) sS makeNewModule(fS moduleLibID, final bool show, O... _) { temp tempSetMC(startModule_beforeStart := optPar beforeStart(_)); ret evalInSystemQ(func -> S { print("Loading module " + moduleLibID); if (isIdentifier(moduleLibID)) ret moduleID(makeNewStaticModuleOfType(moduleLibID, show)); L l = splitAtSlash(moduleLibID); if (!isSnippetID(first(l))) fail("Unknown module lib ID: " + moduleLibID); S snippetID = first(l), className = second(l); className = className == null ? null : "main$" + className; Class c = hotwireModule_withSharing(snippetID); Module m = DynamicModule(snippetID, className, c); startModule(m); if (show && !isTrue(getOpt(unwrapDynamicModule(m), '_startMinimized))) showModule(m); ret moduleID(m); }); } // dynamic only static S findModuleByLibID(S moduleLibID) { L l = splitAtSlash(moduleLibID); if (!isSnippetID(first(l))) fail("Unknown module lib ID: " + moduleLibID); S snippetID = first(l), className = second(l); className = className == null ? null : "main$" + className; L list = findConcepts(DynamicModule, on := true, moduleID := snippetID); DynamicModule m = firstWhere(list, _className := className); if (m != null) ret moduleID(m); if (className != null) null; ret moduleID(first(list)); } static Module makeOrShowStaticModuleOfType(S s) { ret makeOrShowStaticModuleOfType(s, true); } static Module makeOrShowStaticModuleOfType(S s, bool orShow) { ret makeOrShowStaticModuleOfType(classForName("main$" + s), orShow); } static Module makeOrShowStaticModuleOfType(Class c) { ret makeOrShowStaticModuleOfType(c, true); } static Module makeOrShowStaticModuleOfType(Class c, bool orShow) { final L l = staticModulesOfExactType(c); Module m = empty(l) ? nu(c) : first(l); if (orShow) showModule(m); else startModule(m); ret m; } static Module makeNewStaticModuleOfType(S type, bool show) { Class c = classForName("main$" + type); Module m = cast nu(c); if (show) showModule(m); else startModule(m); ret m; } //!include once #1016217 // Sticky Libs !include once #1020744 // Sticky Libs & Src Libs static Class hotwireModule(S snippetID) { hotwire_autoStickyLibs(); ret hotwire(snippetID); // give each their own local_log } static Class hotwireModule_withSharing(S snippetID) { Class c = null; if (useCodeSharing) { c = findLoadedCodeBySnippetID(snippetID); if (c != null) print("SHARING code for " + snippetID); } if (c == null) c = hotwireModule(snippetID); ret c; } // Make modules print with their module ID set flag hotwire_copyOver_extend. svoid hotwire_copyOver_extend(Class c) { S progID = getProgramID(c); if (nempty(progID) && fieldType(c, 'print_log) == Appendable.class) setOpt(c, 'print_log, _SubModulePrint("[" + progID + "] ")); } sbool isLoading() { ret eq(systemStatus!, "loading"); } sbool isShuttingDown() { ret eq(systemStatus!, "shutting down"); } svoid doInGlobalContext(final Runnable r) { final new Flag flag; systemQ.add(r { callF(r); flag.raise(); }); flag.waitUntilUp(); } !include once #1015842 // SavedSessions !include once #1015885 // Standard Modules !include once #1015959 // More Standard Modules please include function renderConcept. please include function restart. svoid setLookAndFeel() { if (eq(laf, 'webLAF)) installWebLAF(); else if (eq(laf, 'nimbus)) nimbus(); else if (eq(laf, 'jtattoo)) jtattoo_mcWin(); else if (eq(laf, 'platform)) systemLAF(); pcall { S scale = trim(loadTextFile(javaxDataDir("os-font-scale.txt"))); if (nempty(scale)) swingFontScale(parseDouble(scale)); } } please include function myTranspilationDate. // should happen in swing thread svoid setActiveModule(Module m) { if (activeModule != m) { activeModule = m; vmBus_send('newActiveModule, m); } } static O unwrappedActiveModule() { ret unwrapDynamicModule(activeModule); } concept TopInput { S text; } svoid nohupJavax(S javaxArgs) { nohupJavax(javaxArgs, javaxDefaultVMArgs()); } sbool cleanedUp; svoid nohupJavax(S javaxArgs, S vmArgs) { if (desktop != null && !cleanedUp) pcall { fullScreenOff(); } directNohupJavax(javaxArgs, vmArgs); } sbool isDevVersion() { ret neq(programID(), #1016478); } svoid startOtherVersion { nohupJavax(isDevVersion() ? #1016478 : #1024932); } sS otherVersionName() { ret isDevVersion() ? "v6" : "v7"; } sS restoreModule(S structure) { if (structure == null) null; O mod = safeUnstructure(structure); if (mod instanceof Map) mod = get((Map) mod, 'module); S shortName = dynShortName(mod); if (!eq(shortName, "DynamicModule")) fail("Can't restore static modules yet [" + shortName + "]"); S snippetID = getString(mod, "moduleID"); S className = getString(mod, "_className"); Class c = hotwireModule_withSharing(snippetID); DynamicModule m = new(snippetID, className, c); copyFields(mod, m, 'iconID); m.frameRect = (Rect) restruct(getOpt(m, 'frameRect)); m.oStruct = getString(mod, "oStruct"); showModule(m); ret moduleID(m); } sS moduleStructForDuplication(DynamicModule m) { if (m == null) null; m.persistContents(); S struct = struct(m); fO resolved = resolveModule(m); if (hasMethod(resolved, '_modifyStructForDuplication, struct)) struct = jreplace_first_dyn(struct, "oStruct=*", func(LS tok, int i) -> S { S s = unquote(tok.get(i+4)); s = callOpt(resolved, '_modifyStructForDuplication, s); if (s == null) fail("Module does not want to be duplicated"); ret "oStruct=" + quote(s); }); ret struct; } sS duplicateModule(DynamicModule m) { ret restoreModule(moduleStructForDuplication(m)); } static O dm_current_mandatory() { fail(); } // for modules please include function mechList_opt_raw. please include function mechList_clearCache. please include function mechLists_clearCache. // This is only answered from localhost answer { if "is stefan's os" ret "yes"; if "show module * with params *" { ret dm_showModuleWithParams(unstructString($1), unstructObjectArray($2)); } if (swic(s, "restore module:", m)) ret ok2(restoreModule(m.rest())); if "swing latency" { ret str(swingLatency()); } if "activate frames" { awt { activateMyFrames(); } ret "OK"; } if "program id" ret programID(); if "main program id" ret mainProgramID(); if "enable remote control from *" { O mod = getDynModuleByID(makeOrShowModule("#1017127/RemoteControlled")); call(mod, 'setFields, new O[] {new O[] {controllingComputers := $1, enabled := true}}); ret "OK"; } if "stack traces" ret renderAllThreadsWithStackTraces(); } srecord Service(O module, O worker) {} static new MultiMap registeredServices; static bool callService(S name, O... args) { for (Service service : cloneList(registeredServices.get(name))) if (isTrue(pcallF(service.worker, name, args))) true; false; } static void registerService(O module, S name, O service) { registeredServices.put(name, Service(module, service)); } static void unregisterService(O module, S name, O service) { registeredServices.remove(name, Service(module, service)); } static O dm_os() { ret main.class; } please include function robot_keyPress. please include function robot_keyRelease. please include function robot_safetyKeyReleaser. svoid showCurrentModuleMenu { swing { showInternalFramePopupMenu(desktop.getSelectedFrame()); } } svoid inSystemQ(Runnable r) { systemQ.add(r); } svoid reloadModuleInBackground(final DynamicModule m) { if (m == null) ret; inSystemQ(r { m.reload_impl() }); } svoid deleteModuleInBackground(final DynamicModule m) { if (m == null) ret; inSystemQ(r { deleteModule(m) }); } svoid restart { if (restarter_override != null) ret with callF(restarter_override); restartWithDefaultVMArgs(); sleep(); } static Component makeStandardReloadingComponent(Module m) { ret jcenteredlabel("Reloading..."); } sbool classLoadedInOtherModule(Class mainClass, Module mod) { for (DynamicModule m) if (m != mod && mainClass(m.o) == mainClass) true; false; } static Class findLoadedCodeBySnippetID(S snippetID) { for (Module m : onModules()) if (m cast DynamicModule) if (sameSnippetID(m.moduleID, snippetID) && m.c != null) ret m.c; null; } svoid cleanKill { setOpt(javax(), cleanKill_verbose := true); cleanKillVM(); } sS moduleIDAndName(Module m) { ret m == null ? "-" : m.id + " - " + rcall_pcall moduleName(m); } sbool hideFeature(S name) { ret contains(hideFeatures, name); } sS featureMenuItem(S name) { ret featureMenuItem(name, name); } sS featureMenuItem(S feature, S name) { ret hideFeature(feature) ? null : name; } sS osName() { ret or2(osName, "Stefan's OS " + version()); } sS version() { ret ai_versionFromName(programName()); }