diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index 01253807..17b9d508 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -293,6 +293,9 @@ protected override void OnStartup(StartupEventArgs e) { Logger.WriteLine("[App::OnStartup] Bootstrapper task has finished"); + // notifyicon is blocking main thread, must be disposed here + NotifyIcon?.Dispose(); + if (t.IsFaulted) Logger.WriteLine("[App::OnStartup] An exception occurred when running the bootstrapper"); diff --git a/Bloxstrap/UI/Elements/NotifyIconMenu.xaml b/Bloxstrap/UI/Elements/NotifyIconMenu.xaml new file mode 100644 index 00000000..373a2b86 --- /dev/null +++ b/Bloxstrap/UI/Elements/NotifyIconMenu.xaml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + diff --git a/Bloxstrap/UI/Elements/NotifyIconMenu.xaml.cs b/Bloxstrap/UI/Elements/NotifyIconMenu.xaml.cs new file mode 100644 index 00000000..d8e14d03 --- /dev/null +++ b/Bloxstrap/UI/Elements/NotifyIconMenu.xaml.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Interop; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +using Bloxstrap.UI.ViewModels; + +namespace Bloxstrap.UI.Elements +{ + /// + /// Interaction logic for NotifyIconMenu.xaml + /// + public partial class NotifyIconMenu + { + public NotifyIconMenu() + { + InitializeComponent(); + } + + private void Window_Loaded(object? sender, RoutedEventArgs e) + { + // this is an awful hack lmao im so sorry to anyone who reads this + // https://stackoverflow.com/questions/357076/best-way-to-hide-a-window-from-the-alt-tab-program-switcher#:~:text=ShowInTaskbar%20%3D%20false%3B%20Owner%20%3D%20form1,form%27s%20ShowInTaskbar%20property%20to%20false. + var wndHelper = new WindowInteropHelper(this); + long exStyle = NativeMethods.GetWindowLongPtr(wndHelper.Handle, NativeMethods.GWL_EXSTYLE).ToInt64(); + exStyle |= NativeMethods.WS_EX_TOOLWINDOW; + NativeMethods.SetWindowLongPtr(wndHelper.Handle, NativeMethods.GWL_EXSTYLE, (IntPtr)exStyle); + } + + // i tried to use a viewmodel but uhhhhhhh it just didnt work idk + private void TestMenuItem_Click(object sender, RoutedEventArgs e) + { + Controls.ShowMessageBox($"hi how u doing i am {TestMenuItem.IsChecked}", MessageBoxImage.Warning); + } + } +} diff --git a/Bloxstrap/UI/NotifyIconWrapper.cs b/Bloxstrap/UI/NotifyIconWrapper.cs index ceda58e2..14fcbdcc 100644 --- a/Bloxstrap/UI/NotifyIconWrapper.cs +++ b/Bloxstrap/UI/NotifyIconWrapper.cs @@ -1,5 +1,7 @@ using System.Windows.Forms; +using Bloxstrap.UI.Elements; + namespace Bloxstrap.UI { public class NotifyIconWrapper : IDisposable @@ -7,9 +9,12 @@ public class NotifyIconWrapper : IDisposable bool _disposed = false; private readonly NotifyIcon _notifyIcon; + private readonly NotifyIconMenu _contextMenuWrapper = new(); + EventHandler? _alertClickHandler; - public NotifyIconWrapper() + + public NotifyIconWrapper() { App.Logger.WriteLine("[NotifyIconWrapper::NotifyIconWrapper] Initializing notification area icon"); @@ -19,6 +24,21 @@ public NotifyIconWrapper() Text = App.ProjectName, Visible = true }; + + _notifyIcon.MouseClick += MouseClickEventHandler; + + _contextMenuWrapper.Dispatcher.BeginInvoke(_contextMenuWrapper.ShowDialog); + + _contextMenuWrapper.Closing += (_, _) => App.Logger.WriteLine("[NotifyIconWrapper::NotifyIconWrapper] Context menu wrapper closing"); + } + + public void MouseClickEventHandler(object? sender, MouseEventArgs e) + { + if (e.Button != MouseButtons.Right) + return; + + _contextMenuWrapper.Activate(); + _contextMenuWrapper.ContextMenu.IsOpen = true; } public void ShowAlert(string caption, string message, int duration, EventHandler? clickHandler) @@ -62,8 +82,11 @@ public void Dispose() if (_disposed) return; + App.Logger.WriteLine($"[NotifyIconWrapper::Dispose] Disposing NotifyIcon"); + + _contextMenuWrapper.Dispatcher.Invoke(_contextMenuWrapper.Close); _notifyIcon.Dispose(); - + _disposed = true; GC.SuppressFinalize(this); diff --git a/Bloxstrap/Utility/NativeMethods.cs b/Bloxstrap/Utility/NativeMethods.cs index 321fbcfd..b869f071 100644 --- a/Bloxstrap/Utility/NativeMethods.cs +++ b/Bloxstrap/Utility/NativeMethods.cs @@ -9,5 +9,17 @@ static class NativeMethods [DllImport("user32.dll")] public static extern bool FlashWindow(IntPtr hWnd, bool bInvert); + + [DllImport("user32.dll")] + public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); + + [DllImport("user32.dll")] + public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong); + + // i only bothered to add the constants that im using lol + + public const int GWL_EXSTYLE = -20; + + public const int WS_EX_TOOLWINDOW = 0x00000080; } }