microsoft/terminal
Three load-bearing flows were traced end-to-end. (1) Process startup: wWinMain -> WindowEmperor::HandleCommandlineArgs does mutex-or-WM_COPYDATA handoff, loads settings via AppLogic::ReloadSettings -> CascadiaSettings::LoadAll, restores persisted windows, dispatches the command line into AppHost windows, then pumps a single message loop. (2) New tab: an action (keybinding/menu/CLI) reaches ShortcutActionDispatch::DoAction -> TerminalPage handlers -> _MakePane -> _CreateConnectionFromSettings (ConptyConnection) -> TermControl::_InitializeTerminal -> connection.Start() -> ConPTY + CreateProcessW -> _OutputThread -> TerminalOutput -> Terminal::Write. (3) Settings persistence: a wil::FolderChangeReader on the settings directory triggers ReloadSettingsThrottled -> _TryLoadSettings -> SettingsChanged event, which WindowEmperor and TerminalPage subscribe to for hot-reload of hotkeys, themes, and profiles.
- Startup step 1 (pre-XAML): wWinMain registers TraceLogging, calls SetConsoleCtrlHandler(NULL,FALSE) to unbreak inherited ^C state, EnsureNativeArchitecture() to refuse wrong-arch binaries, EnableMouseInPointer(true), then winrt::init_apartment(single_threaded) — explicitly load-bearing for UIAutomation correctness per the comment.
- Startup step 2 (instance arbitration): WindowEmperor::HandleCommandlineArgs builds a branding+elevation+SID-scoped window class name, sets an AUMID for unpackaged runs (_setupAumid with deferred taskbar-pin stamping), then acquireMutexOrAttemptHandoff either wins the mutex or WM_COPYDATA's the serialized invocation to the running instance and TerminateProcess(0)s itself.
- Startup step 3 (app + settings): the emperor creates winrt::TerminalApp::App, calls App.Logic().ReloadSettings() (AppLogic::_TryLoadSettings -> CascadiaSettings::LoadAll -> SettingsLoader pipeline), pre-warms FOLDERID_LocalAppData to avoid an Nvidia loader-lock stall (GH#20348), creates the hidden message window, registers global hotkeys and notification icon, and subscribes to SettingsChanged.
- Startup step 4 (window materialization): persisted layouts are replayed as synthetic 'wt -w new -s <idx>' command lines; then the real argv is dispatched via _dispatchCommandlineCommon -> CreateNewWindow -> AppHost::Initialize; '-Embedding' mode instead arms a 5s handoff timeout; finally a single GetMessageW loop pumps all windows, then _finalizeSessionPersistence runs at exit.
- New-tab step 1 (invocation): keybindings go AppKeyBindings -> ActionMap lookup -> ShortcutActionDispatch::DoAction raising the NewTab event; the same dispatch is reused for command-line startup actions, the new-tab flyout items (which embed NewTabArgs with a profile index), and command palette entries.
- New-tab step 2 (pane + connection): the NewTab handler builds a pane via _MakePane -> _CreateConnectionFromSettings, which selects ConptyConnection or AzureConnection by profile.ConnectionType(), resolves StartingDirectory against the virtual CWD (for 'wt -w 0 -d .' correctness), packs a ValueSet (commandline, dirs, rows/cols, sessionId, textMeasurement, ambiguousIsWide, inheritCursor, environment) and calls connection.Initialize.
- New-tab step 3 (terminal bring-up): TermControl::_InitializeTerminal waits for a nonzero SwapChainPanel size, calls ControlCore::Initialize (creates Terminal + AtlasEngine), then _core.Connection().Start() — or _restoreInBackground for restored buffer contents — followed by EnablePainting, scrollbar setup, appearance application, and raising Initialized.
- New-tab step 4 (process + IO): ConptyConnection::Start transitions to Connecting, creates overlapped pipes, ConptyCreatePseudoConsole, _LaunchAttachedClient (CreateProcessW with PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, WSLENV-augmented env, WT_SESSION/WT_PROFILE_ID), ConptyReleasePseudoConsole, then spawns _OutputThread and transitions to Connected; failures emit localized ProcessFailedToLaunch/BadPathText/ElevationRequired text as TerminalOutput and transition to Failed.
- New-tab step 5 (steady state): _OutputThread pipe reads -> TerminalOutput event -> ControlCore::_connectionOutputHandler -> LockForWriting -> Terminal::Write -> StateMachine::ProcessString -> OutputStateMachineEngine Action* -> dispatch -> TextBuffer; scrollback/viewport changes invalidate the AtlasEngine for the next frame.
- Settings-reload trace: AppLogic::_RegisterSettingsChange creates a wil::FolderChangeReader on the settings directory watching FileName+LastWriteTime; when settings.json changes, ReloadSettingsThrottled debounces 100ms then _TryLoadSettings -> CascadiaSettings::LoadAll; success raises SettingsChanged (WindowEmperor re-registers global hotkeys/notification icon/persistence; TerminalPage re-binds keybindings), failure keeps the old settings and surfaces _settingsLoadExceptionText.
- First-run fixup trace: when settings.json is absent/empty, LoadAll resets ApplicationState, loads embedded IDR_USER_DEFAULTS, runs ApplyRuntimeInitialSettings + dynamic generators, and WriteSettingsToDisk persists the materialized file; Preview/Canary first try migrating the Release-channel settings.json instead.
- Teardown trace: ConptyConnection::Close sets state Closing, resets the HPCON (sends CTRL_CLOSE_EVENT to clients), then loops CancelIoEx + WaitForSingleObject(1000) until the output thread exits — required so TerminalOutput.raise can't hit a dead ControlCore (GH#13880); the code documents three termination 'EXIT POINT's that must not flap each other.