!7 sS background = #1101302; // #1009931; sS backgroundMode = 'fit; sS mainIconID = #1101272; static double minLoadScreenShowingTime = 3.0; static JDesktopPane desktop; // TODO: merge with systemQ static ReliableSingleThread rst = new(f updateModules); static volatile long updateCycles; static int systemErrorsToKeep = 10; static L systemErrors = synchroList(new CircularArrayList); static new Flag stopRequested; static SimpleLiveValue systemStatus = stringLiveValue("loading"); 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 Set onActiveModuleChange = synchroHashSet(); static JTextField tfTopInput; // the input field in the OS menu bar p { _handleException_addHandler(voidfunc(Throwable e) { pcall { addToListWithMaxSize(systemErrors, e, systemErrorsToKeep); } infoBox("Error: " + exceptionToStringShort(e)); LastErrors lastErrors = first(staticModulesOfType(LastErrors)); if (lastErrors != null) lastErrors.addError(e); }); print("Data dir: " + javaxDataDir()); globalACC = acc_current(); if (swic(activateFramesOf(programIDPlusHome()), "OK")) cleanKill(); framesBot(); //substance(); final SimpleLiveValue lvDetails = stringLiveValue(); lvDetails.onChange(r { print(lvDetails!) }); stefansOS_loadingAnimation_fullScreen = startInFullScreen() && !isWindows() /* bug */; final Component loadingAnim = stefansOS_loadingAnimation(r { stopRequested.raise() }, lvDetails); try { long start = sysNow(); systemQ = startQ("System Q"); useDBOf(#1015871); lvDetails.set("Loading database"); db(); lvDetails.set("Loading background"); background = or2(trim(loadTextFile(javaxDataDir("os-background.txt"))), background); if (eq(backgroundMode, 'fit)) desktop = jDesktopPaneWithFitPicture(background); else desktop = jDesktopPaneWithSkyPicture/*_autoUnload*/(background, Color.black); setMainDesktopPane(desktop); autoFixDesktopPane(desktop); long ms = toMS(minLoadScreenShowingTime); long remaining = start+ms-sysNow(); if (remaining <= 0) lvDetails.set("Done loading"); else { S seconds = formatDouble(toSeconds(remaining), 1); lvDetails.set("Done loading, just showing you the nice animation 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("Troubleshooting options will go here."), jcenteredbuttons( "Start Stefan's OS normally", r restart, "Delete session", disableButtonWhileCalcing(func -> bool { if (!fileExists(conceptsFile())) ret false with infoBox("Session already empty."); if (!confirmOKCancel("Really delete your current session?")) false; renameFileToSomeBackupName(conceptsFile()); infoBox("Session deleted. Starting again."); disableAllButtonsInWindow(heldInstance(JButton)); sleepSeconds(3); restart(); false; })))); //autoRestart(); serverAutoRestartMD5(); // just a short ping setLookAndFeel(); showDesktop(); } finally { disposeWindow(loadingAnim); } initAfterDBLoad(); hideConsole(); 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; if (showDesktop_first && startInFullScreen()) pcall { showFullScreen(desktop); done = true; } if (!done) { showMaximizedFrame(desktop); titlePopupMenu_top(desktop, voidfunc(JPopupMenu menu) { addMenuItems(menu, "Update One Cycle", rst, "New Session", rThreadPcallMessageBox(r deleteAllModules), "Restore Initial Modules", r initialModules, ); }); } 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 fillMenuBar { set jmenuItem_newThreads; S version = ai_versionFromName(programName()); final bool dev = neq(programID(), #1016005); S name = "Stefan's OS " + version; S home = userHomeIfNotActual(); S actual = actualUserHome(); S prefix = addFileSep(actualUserHome()); print("home: " + home + ", actual: " + actual); if (home != null) name += " [" + dropPrefix(prefix, home) + "]"; addMenu(desktop, trim(name), "Screenshot", r stefansOS_screenshot, "Full screen on/off", r fullScreenOnOff, "Switch to " + (dev ? "v5" : "v6"), r { innerCleanUp(); nohupJavax(dev ? #1016005 : #1016478); cleanKill(); }, "---", "Restart Stefan's OS", r { showConsole(); restart(); }, "Exit", r cleanKill ); addMenu(desktop, "Modules", "Other Module...", r stefansOS_addDynamicModuleDialog, "---", "Welcome Screen", r { makeOrShowModule("#1016067/WelcomeScreen") }, //"Hello (input field for everything)", r { makeOrShowModule("Hello") }, "Task Bar", r { makeOrShowModule("#1016123/TaskBar") }, "Module Classes", r { makeOrShowStaticModuleOfType(ModuleClasses) }, ); addMenu(desktop, "More", "Start External JavaX Program...", r stefansOS_startExternalJavaXProgram, "---", "Find memory leaks", r stefansOS_findMemoryLeaks); // Add the fancy stuff swing { JMenuBar menuBar = cast call(getFrame(desktop), 'getJMenuBar); if (!containsChildOfType(menuBar, JLabel.class)) { //menuBar.add(Box.createHorizontalGlue()); menuBar.add(Box.createHorizontalStrut(20)); tfTopInput = jcenteredtextfield(uniq(TopInput).text); onChange(tfTopInput, r { cset(uniq(TopInput), text := getText(tfTopInput)) }); //menuBar.add(jMinWidth(100, tfTopInput)); menuBar.add(tfTopInput); //menuBar.add(jhgrid(null, tfTopInput)); //menuBar.add(jhgrid(tfTopInput, null)); menuBar.add(Box.createHorizontalStrut(20)); menuBar.add(jLiveValueLabel(clockTimeLiveValue())); menuBar.add(Box.createHorizontalStrut(6)); } } } static AutoCloseable tempBusyAnimation(fS text) { if (headless()) null; final JComponent anim = jBackground(Color.white, jAnimation(#1101316, text)); swing { addInternalFrame_dontSelect.set(true); addInternalFrame_layer.set(JLayeredPane.POPUP_LAYER); addInternalFrame(desktop, text, null, anim); packInternalFrameInTopRightCorner(anim); JInternalFrame f = getInternalFrame(anim); print("Have busy animation: " + f + " in " + getParent(f)); } ret tempDisposeInternalFrame(anim); } svoid initAfterDBLoad { doEvery(30000, r { applyStandardSwingFixes(); cleanDefunctACCsInAllThreads(); }); doEvery(60000, r clearSnippetTitleCache); set cleanUp_interruptThreads; // for Java Chrome classForNameOpt("java.util.prefs.FileSystemPreferences"); temp tempBusyAnimation("Restoring Session"); initialModules(); UpdateCycles uc = conceptWhere(UpdateCycles); if (uc != null) updateCycles = uc.value; for (Module m : onModules()) startModule(m); addConceptIndex(simpleConceptIndex(rst)); rst.trigger(); systemStatus.set("running"); } svoid initialModules { if (empty(onModules())) showModule(new DynamicModule(#1016067, 'main$WelcomeScreen)); //makeOrShowStaticModuleOfType(ModuleClasses); //makeOrShowStaticModuleOfType(Hello); if (headless()) makeOrShowModule("#1016576/ConnectToServer"); } svoid triggerUpdate { rst.trigger(); } 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 cleanMeUp { systemStatus.set("shutting down"); temp tempBusyAnimation("Shutting Down"); for (Module m) if (m.vis != null) pcall { m.unvisualize(); } for (Module m) cleanUp(m); } static L onModules() { ret conceptsWhere(Module, on := true); } sbool hasModuleWithFields(Class c, O... params) { ret hasConcept(c, concatArrays(new O[] {on := true}, params)); } 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); } rst.trigger(); if (m.visible) showModule(m); }} static Module showModule(final Module m) { if (m == null) ret m; startModule(m); if (headless()) ret m; temp m.enter(); if (m.vis != null) { if (!isLoading()) activateInternalFrame(m.vis); ret m; } cset(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; { temp tempSetThreadLocal(addInternalFrame_dontSelect, isLoading()); f = showInternalFrame(desktop, frameTitle, r, m.vis); } if (r == null) centerPackInternalFrame(f); f.setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE); final WeakReference fRef = new(f); final WeakReference mRef = new(m); internalFrameTitlePopupMenuItem(f, "Module source", r-thread { pcall { S src = mRef->sourceCode(); if (src != null) showText(internalFrameTitle(fRef!) + " [Source]", src); else infoBox("No source code found"); }}); onInternalFrameIconified(f, r { hideModule(m) }); onInternalFrameClosing(f, r { deleteModule(m) }); onInternalFrameActivated(f, r { setActiveModule(m) }); onInternalFrameDeactivated(f, r { if (activeModule == m) setActiveModule(null) }); internalFrameIcon(f, m.iconID); m.enhanceFrame(f); } ret m; } svoid showModules(L l) { for (Module m : unnull(l)) showModule(m); } sbool deleteModule(Module m) { pcall { bool warn = isTrue(callOpt(resolveModule(m), 'warnOnDelete)); if (warn && !confirmOKCancel("Really delete module " + m + "?")) false; } onActiveModuleChange.remove(m); O m2 = unwrapDynamicModule(m); ghostModules.put(m == m2 ? m : m2.getClass(), nu(GhostModule, name := m.moduleName(), created := m.created, deleted := now(), instance := new WeakReference(m2)); pcall { m.unvisualize(); } pcall { logStructure(deletedModulesLogFile(), m); } removeConcept(m); triggerUpdate(); true; } svoid visualizeModule(Module m) { pcall { if (m.vis == null) m.vis = m.visualize(); if (m.vis == null) m.vis = defaultVisualize(m); } } svoid hideModule(final Module m) { if (m == null) ret; temp m.enter(); cset(m, visible := false); pcall { m.unvisualize(); } } 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(); bool on = true, visible; Rect frameRect; S iconID; PersistableThrowable error; //transient Set timers; JComponent visualize() { null; } void unvisualize() { pcall { unvisualize1(); } pcall { unvisualize2(); } } 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))); } void cleanMeUp_started() { started = false; } void delete() { unvisualize(); cleanUp(this); super.delete(); } S sourceCode() { ret javaxSourceOfMyClass1(shortClassName(this)); } // for all modules void triggerUpdate { rst.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)); } } // 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 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 ? 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 { S moduleID, _className; // "className" is taken by DynamicObject; _className == null for old-style dyn module S oStruct; // serialized dynamic object transient Class c; transient O o; *() {} *(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) { internalFrameTitlePopupMenuItem(f, "Reload", rThread(r reload)); { temp enter(); pcallOpt(o, 'enhanceFrame, f); } internalFrameTitle(f, moduleName()); } S moduleName() { S name = (S) callOpt(o, 'moduleName); if (nempty(name)) ret name; S title = snippetTitle_cached(moduleID); //ret dropSuffixICTrimOneOf(title, "[Dyn Module]", "[Dyn Module, OK]", "[Dyn Module, shortened]"); ret dropTrailingSquareBracketStuff(title); } void start() { if (moduleID == null) ret; if (c == null) c = hotwireModule(moduleID); if (oStruct != null) pcall { o = unstructureInRealm(oStruct, c); } if (o == null) if (_className == null) o = c; else o = nu(_getClass(c, _className)); setOptAll(o, _host := this, lock := lock); temp enter(); if (o instanceof Class) callMain(o); else callOpt(o, 'start); } void unvisualize2() { callOpt(o, 'unvisualize); } void update() { callOpt(o, 'update); } void cleanMeUp() { oStruct = null; pcall { if (o != null && !o instanceof Class) oStruct = struct(o); } cleanUpObjectAndItsMainClass(o); o = null; c = null; } void reload() { 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, jcenteredlabel("Reloading...")); visible = false; startModule(this); if (frame != null) { cset(this, visible := true); visualizeModule(this); //print("New content: " + vis); setInternalFrameContents(frame, vis); } rst.trigger(); } 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(Module m) { ret m == null ? null : m.resolve(); } 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); } static S makeOrShowModule(S moduleLibID, 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(snippetID); m = DynamicModule(snippetID, className, c); } if (orShow) showModule(m); else startModule(m); ret moduleID(m); } static S makeNewModule(S moduleLibID, bool show) { print("makeNewModule " + 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(snippetID); Module m = DynamicModule(snippetID, className, c); if (show) showModule(m); else startModule(m); ret moduleID(m); } 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 = nu(c); if (show) showModule(m); else startModule(m); ret m; } !include once #1016217 // Sticky Libs static Class hotwireModule(S snippetID) { hotwire_autoStickyLibs(); ret hotwire(snippetID); // give each their own local_log } sbool isLoading() { ret eq(systemStatus!, "loading"); } 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. !include once #1001372 // direct nohupJavaX // do it here, x30 has a bug on old Windows svoid restart { print("\nClean-restarting myself."); thread "Clean Restart" { call(javax(), 'preKill); nohupJavax(smartJoin((S[]) get(javax(), 'fullArgs)), fullVMArguments()); System.exit(0); } } svoid setLookAndFeel() { jtattoo_mcWin(); } please include function myTranspilationDate. // should happen in swing thread svoid setActiveModule(Module m) { if (activeModule != m) { activeModule = m; updateModules(onActiveModuleChange); } } static O unwrappedActiveModule() { ret unwrapDynamicModule(activeModule); } concept TopInput { S text; }