/* * Created by SharpDevelop. * User: EVXIO * Date: 4/3/2025 * Time: 10:01 PM * * To change this template use Tools | Options | Coding | Edit Standard Headers. */ using System; using System.Diagnostics; using System.Drawing; using System.Threading; using System.Windows.Forms; using System.Text; namespace UPSNet { public sealed class NotificationIcon { private NotifyIcon notifyIcon; private ContextMenu notificationMenu; private readonly BackgroundTimer _monitoringTimer; //UPSApp upsApp = new UPSApp(); private static NotificationIcon _instance; private static int lastState = -1; //for save cpu by checking state // Changed to .NET 4.0 compatible property public static NotifyIcon NotifyIconInstance { get { return _instance != null ? _instance.notifyIcon : null; } } #region Initialize icon and menu public NotificationIcon() { _instance = this; notifyIcon = new NotifyIcon(); notificationMenu = new ContextMenu(InitializeMenu()); notifyIcon.BalloonTipText = "Application is running in the background"; notifyIcon.BalloonTipTitle = "UPS Net v1.0"; notifyIcon.BalloonTipIcon = ToolTipIcon.Info; notifyIcon.Text = "UPS Net \nBattery: - "; // This is the regular tooltip notifyIcon.DoubleClick += IconDoubleClick; System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(NotificationIcon)); notifyIcon.Icon = (Icon)resources.GetObject("$this.Icon"); notifyIcon.ContextMenu = notificationMenu; _monitoringTimer = new BackgroundTimer(CheckUPSStatus, 1000); } private MenuItem[] InitializeMenu() { MenuItem[] menu = new MenuItem[] { new MenuItem("Show", menuShowClick), new MenuItem("-"), // Separator new MenuItem("About", menuAboutClick), new MenuItem("Exit", menuExitClick) }; // Enable OwnerDraw for each MenuItem (except separators) foreach (MenuItem item in menu) { if (item.Text != "-") { item.OwnerDraw = true; // Attach events to EACH MenuItem (not ContextMenu) item.DrawItem += MenuItem_DrawItem; item.MeasureItem += MenuItem_MeasureItem; } } return menu; } // Handle drawing for EACH MenuItem private void MenuItem_DrawItem(object sender, DrawItemEventArgs e){ MenuItem menuItem = (MenuItem)sender; // Draw background e.DrawBackground(); // Draw icon (if available) System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(NotificationIcon)); Image icon = null; switch (menuItem.Text) { case "Show": icon = (Image) resources.GetObject("dashboard16"); break; case "About": icon = (Image) resources.GetObject("info16"); break; case "Exit": icon = (Image) resources.GetObject("close16"); break; //case "About": icon = Properties.Resources.AboutIcon; break; //case "Exit": icon = Properties.Resources.ExitIcon; break; } if (icon != null){ e.Graphics.DrawImage( icon, new Rectangle( e.Bounds.X + 2, e.Bounds.Y + (e.Bounds.Height - 16) / 2, 16, 16 ) ); } // Draw text TextRenderer.DrawText( e.Graphics, menuItem.Text, SystemFonts.MenuFont, new Rectangle(e.Bounds.X + 20, e.Bounds.Y, e.Bounds.Width - 20, e.Bounds.Height), e.ForeColor, TextFormatFlags.VerticalCenter | TextFormatFlags.Left ); } // Measure each MenuItem private void MenuItem_MeasureItem(object sender, MeasureItemEventArgs e){ MenuItem menuItem = (MenuItem)sender; SizeF textSize = e.Graphics.MeasureString(menuItem.Text, SystemFonts.MenuFont); e.ItemHeight = Math.Max(16, (int)textSize.Height) + 4; e.ItemWidth = (int)textSize.Width + 20; // 16 (icon) + 4 (padding) } #endregion #region Main - Program entry point /// Program entry point. /// Command Line Arguments [STAThread] public static void Main(string[] args) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); bool isFirstInstance; // Please use a unique name for the mutex to prevent conflicts with other programs using (Mutex mtx = new Mutex(true, "UPSNet", out isFirstInstance)) { if (isFirstInstance) { UPSApp.Init(); NotificationIcon notificationIcon = new NotificationIcon(); notificationIcon.notifyIcon.Visible = true; if (SynchronizationContext.Current == null) { SynchronizationContext.SetSynchronizationContext(new System.Windows.Forms.WindowsFormsSynchronizationContext()); } UPSApp.uiContext = SynchronizationContext.Current; Application.Run(); notificationIcon.notifyIcon.Dispose(); } else { // The application is already running // TODO: Display message box or change focus to existing application instance } } // releases the Mutex } #endregion #region Event Handlers private void menuAboutClick(object sender, EventArgs e) { MessageBox.Show( "EVXIO UPS Net \nVersion 1.0.0 - Portable Edition \n\nCopyright ©2025 Victor Phoa. All Rights Reserved.", "About - EVXIO UPS Net", MessageBoxButtons.OK, MessageBoxIcon.Information ); } private void menuExitClick(object sender, EventArgs e) { Application.Exit(); } private void IconDoubleClick(object sender, EventArgs e) { UPSApp.ShowOrHideForm(); //MessageBox.Show("The icon was double clicked"); } private void menuShowClick(object sender, EventArgs e) { UPSApp.ShowForm(); //MessageBox.Show("The icon was double clicked"); } #endregion public static string RepeatString(string str, int count){ if (count <= 0) return "";//string.Empty; if (count == 1) return str; var sb = new StringBuilder(str.Length * count); for (int i = 0; i < count; i++) { sb.Append(str); } return sb.ToString(); } private static void CheckUPSStatus() { //string s = ""; if (UPSApp.fetcher.IsReachable) { //s += "OnShut=" + UPSApp.fetcher.OnTimedShutdown + " Remaining=" + UPSApp.fetcher.TimedShutdownRemaining; if (NotifyIconInstance != null) { // Explicit null check if (UPSApp.fetcher.OnState){ int maxBars = 4; int barCount = 0; if (UPSApp.fetcher.BattMaxLevel > 0) { barCount = (int)Math.Round((double)UPSApp.fetcher.ChargeLevel * maxBars / UPSApp.fetcher.BattMaxLevel); } else { barCount = UPSApp.fetcher.ChargeLevel > 4 ? (int)Math.Round(UPSApp.fetcher.ChargeLevel / 25.0) : UPSApp.fetcher.ChargeLevel; } barCount = Math.Max(0, Math.Min(maxBars, barCount)); if (lastState != (100 + barCount)){ lastState = 100 + barCount; NotifyIconInstance.Text = "UPS Net \nBattery: " + RepeatString("■", barCount) + RepeatString(" ", maxBars - barCount); } }else{ if (lastState!=200){ lastState = 200; NotifyIconInstance.Text = "UPS Net \nUPS OFF"; } } } }else{ //s = "Unreachable"; if (NotifyIconInstance != null){ if (lastState!=300){ lastState = 300; NotifyIconInstance.Text = "UPS Net \nNot Connected"; } } } //Debug.WriteLine("CheckUPSStatus: " + s); //UPSApp.ManageShutdownRoutine(); //this now managed from OnStatusChanged ata UPSApp } } }