// The CMLeonOS Project (https://github.com/Leonmmcoset/CMLeonOS) // Copyright (C) 2025-present LeonOS 2 Developer Team // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . using CMLeonOS; using CMLeonOS.Logger; using CMLeonOS.Settings; using System; namespace CMLeonOS.Gui { internal static class Gui { private enum LowMemoryAction { Continue, ReturnBootMenu, Cancel } private static bool guiRunning = false; private static WindowManager windowManager; private static string FitText(string text, int width) { if (string.IsNullOrEmpty(text)) { return string.Empty.PadRight(width); } if (text.Length > width) { if (width <= 3) { return text.Substring(0, width); } return text.Substring(0, width - 3) + "..."; } return text.PadRight(width); } private static void WriteAt(int x, int y, string text, ConsoleColor fg, ConsoleColor bg) { if (y < 0 || y >= Console.WindowHeight) { return; } Console.SetCursorPosition(Math.Max(0, x), y); Console.ForegroundColor = fg; Console.BackgroundColor = bg; Console.Write(text); } private static void DrawBorderLine(int left, int y, int width, ConsoleColor fg, ConsoleColor bg) { string mid = new string('-', width - 2); WriteAt(left, y, "+" + mid + "+", fg, bg); } private static void DrawPanelLine(int left, int y, int width, string content, ConsoleColor contentFg, ConsoleColor contentBg) { int innerWidth = width - 2; WriteAt(left, y, "|", ConsoleColor.Cyan, ConsoleColor.Black); WriteAt(left + 1, y, FitText(content, innerWidth), contentFg, contentBg); WriteAt(left + width - 1, y, "|", ConsoleColor.Cyan, ConsoleColor.Black); } private static LowMemoryAction ShowLowMemoryWarning(uint ramMb) { int selected = 0; string[] options = new[] { "Continue Anyway", "Return to Boot Menu", "Cancel" }; bool needsRender = true; while (true) { if (needsRender) { Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.White; Console.Clear(); int width = Console.WindowWidth; int height = Console.WindowHeight; int panelWidth = Math.Min(86, Math.Max(58, width - 8)); int contentLineCount = 7 + options.Length; int panelHeight = contentLineCount + 2; int left = Math.Max(0, (width - panelWidth) / 2); int top = Math.Max(0, (height - panelHeight) / 2); DrawBorderLine(left, top, panelWidth, ConsoleColor.Cyan, ConsoleColor.Black); DrawPanelLine(left, top + 1, panelWidth, " CMLeonOS Boot Warning ", ConsoleColor.Black, ConsoleColor.Cyan); DrawPanelLine(left, top + 2, panelWidth, string.Empty, ConsoleColor.White, ConsoleColor.Black); DrawPanelLine(left, top + 3, panelWidth, " Not enough system memory is available for Desktop GUI.", ConsoleColor.Yellow, ConsoleColor.Black); DrawPanelLine(left, top + 4, panelWidth, $" Detected : {ramMb} MB", ConsoleColor.Gray, ConsoleColor.Black); DrawPanelLine(left, top + 5, panelWidth, " Required : at least 1024 MB", ConsoleColor.Gray, ConsoleColor.Black); DrawPanelLine(left, top + 6, panelWidth, string.Empty, ConsoleColor.White, ConsoleColor.Black); DrawPanelLine(left, top + 7, panelWidth, " Use Up/Down to select, Enter to confirm", ConsoleColor.DarkGray, ConsoleColor.Black); for (int i = 0; i < options.Length; i++) { bool isSelected = i == selected; DrawPanelLine( left, top + 8 + i, panelWidth, (isSelected ? " > " : " ") + options[i], isSelected ? ConsoleColor.Black : ConsoleColor.White, isSelected ? ConsoleColor.White : ConsoleColor.Black ); } DrawBorderLine(left, top + panelHeight - 1, panelWidth, ConsoleColor.Cyan, ConsoleColor.Black); needsRender = false; } if (Cosmos.System.KeyboardManager.TryReadKey(out var key)) { if (key.Key == Cosmos.System.ConsoleKeyEx.UpArrow) { selected--; if (selected < 0) { selected = options.Length - 1; } needsRender = true; } else if (key.Key == Cosmos.System.ConsoleKeyEx.DownArrow) { selected++; if (selected >= options.Length) { selected = 0; } needsRender = true; } else if (key.Key == Cosmos.System.ConsoleKeyEx.Enter) { if (selected == 0) { return LowMemoryAction.Continue; } if (selected == 1) { return LowMemoryAction.ReturnBootMenu; } return LowMemoryAction.Cancel; } else if (key.Key == Cosmos.System.ConsoleKeyEx.Escape) { return LowMemoryAction.ReturnBootMenu; } } else { System.Threading.Thread.Sleep(16); } } } internal static bool StartGui() { Console.Clear(); Console.CursorVisible = false; windowManager = new WindowManager(); Logger.Logger.Instance.Info("Gui", "GUI starting."); uint ramMb = Cosmos.Core.CPU.GetAmountOfRAM(); if (ramMb < 1000) { LowMemoryAction action = ShowLowMemoryWarning(ramMb); if (action != LowMemoryAction.Continue) { return false; } Console.Clear(); } Console.WriteLine("Loading apps..."); AppManager.LoadAllApps(); SettingsManager.LoadSettings(); UILib.UITheme.ApplyTheme(SettingsManager.GUI_Theme); ProcessManager.AddProcess(windowManager); ProcessManager.AddProcess(windowManager, new SettingsService()).Start(); windowManager.Start(); ProcessManager.AddProcess(windowManager, new Sound.SoundService()).Start(); ProcessManager.AddProcess(windowManager, new MemService()).Start(); Logger.Logger.Instance.Info("Gui", "Memory management service started"); Console.WriteLine("Starting lock screen..."); ProcessManager.AddProcess(windowManager, new ShellComponents.Lock()).Start(); guiRunning = true; // 进入 GUI 事件循环 RunGuiLoop(); return true; } private static void RunGuiLoop() { while (guiRunning) { ProcessManager.Yield(); } } internal static void StopGui() { guiRunning = false; if (windowManager != null) { windowManager.Stop(); } } } }