From 5cf5eddc818f1cfdcdb7f7c53c1022c639f52bf6 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Thu, 8 Nov 2018 16:19:25 -0600 Subject: [PATCH] Allow minimizing to the tray. This allows running GIF animations in the background. --- smx-config/App.xaml | 3 +- smx-config/App.xaml.cs | 111 ++++++++++++++++++++-- smx-config/MainWindow.xaml.cs | 45 +++++++++ smx-config/Resources/window icon grey.ico | Bin 0 -> 38078 bytes smx-config/Resources/window icon grey.png | Bin 0 -> 10810 bytes smx-config/SMXConfig.csproj | 7 ++ 6 files changed, 158 insertions(+), 8 deletions(-) create mode 100644 smx-config/Resources/window icon grey.ico create mode 100644 smx-config/Resources/window icon grey.png diff --git a/smx-config/App.xaml b/smx-config/App.xaml index aaa2d48..02fc130 100644 --- a/smx-config/App.xaml +++ b/smx-config/App.xaml @@ -1,8 +1,7 @@ + xmlns:local="clr-namespace:smx_config"> diff --git a/smx-config/App.xaml.cs b/smx-config/App.xaml.cs index da3de5d..6c3ad6d 100644 --- a/smx-config/App.xaml.cs +++ b/smx-config/App.xaml.cs @@ -1,6 +1,7 @@ using System; using System.Windows; using System.Runtime.InteropServices; +using System.IO; namespace smx_config { @@ -11,10 +12,18 @@ namespace smx_config [DllImport("SMX.dll", CallingConvention = CallingConvention.Cdecl)] private static extern void SMX_Internal_OpenConsole(); + private System.Windows.Forms.NotifyIcon trayIcon; + private MainWindow window; + App() { AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionEventHandler; - + } + + protected override void OnStartup(StartupEventArgs e) + { + base.OnStartup(e); + if(!SMX.SMX.DLLExists()) { MessageBox.Show("SMXConfig encountered an unexpected error.\n\nSMX.dll couldn't be found:\n\n" + Helpers.GetLastWin32ErrorString(), "SMXConfig"); @@ -38,6 +47,40 @@ namespace smx_config // we're running. Helpers.LoadSavedPanelAnimations(); SMX.SMX.LightsAnimation_SetAuto(true); + + CreateTrayIcon(); + + // Create the main window. + ToggleMainWindow(); + } + + // Open or close the main window. + // + // We don't create our UI until the first time it's opened, so we use + // less memory when we're launched on startup. However, when we're minimized + // back to the tray, we don't destroy the main window. WPF is just too + // leaky to recreate the main window each time it's called due to internal + // circular references. Instead, we just focus on minimizing CPU overhead. + void ToggleMainWindow() + { + if(window == null) + { + window = new MainWindow(); + window.Closed += MainWindowClosed; + window.Show(); + } + else if(window.WindowState == WindowState.Minimized) + { + window.WindowState = WindowState.Normal; + window.Activate(); + } + else + window.WindowState = WindowState.Minimized; + } + + private void MainWindowClosed(object sender, EventArgs e) + { + window = null; } private void UnhandledExceptionEventHandler(object sender, UnhandledExceptionEventArgs e) @@ -50,13 +93,69 @@ namespace smx_config { base.OnExit(e); - // Shut down cleanly, to make sure we don't run any threaded callbacks during shutdown. Console.WriteLine("Application exiting"); - if(CurrentSMXDevice.singleton == null) - return; - CurrentSMXDevice.singleton.Shutdown(); - CurrentSMXDevice.singleton = null; + + // Remove the tray icon. + if(trayIcon != null) + { + trayIcon.Visible = false; + trayIcon = null; + } + + // Shut down cleanly, to make sure we don't run any threaded callbacks during shutdown. + if(CurrentSMXDevice.singleton != null) + { + CurrentSMXDevice.singleton.Shutdown(); + CurrentSMXDevice.singleton = null; + } } + // Create a tray icon. For some reason there's no WPF interface for this, + // so we have to use Forms. + void CreateTrayIcon() + { + Stream iconStream = GetResourceStream(new Uri( "pack://application:,,,/Resources/window%20icon%20grey.ico")).Stream; + System.Drawing.Icon icon = new System.Drawing.Icon(iconStream); + + trayIcon = new System.Windows.Forms.NotifyIcon(); + trayIcon.Text = "StepManiaX"; + trayIcon.Visible = true; + + // Show or hide the application window on click. + trayIcon.Click += delegate (object sender, EventArgs e) { ToggleMainWindow(); }; + trayIcon.DoubleClick += delegate (object sender, EventArgs e) { ToggleMainWindow(); }; + + CurrentSMXDevice.singleton.ConfigurationChanged += delegate(LoadFromConfigDelegateArgs args) { + RefreshTrayIcon(args); + }; + + // Do the initial refresh. + RefreshTrayIcon(CurrentSMXDevice.singleton.GetState(), true); + } + + // Refresh the tray icon when we're connected or disconnected. + bool wasConnected; + void RefreshTrayIcon(LoadFromConfigDelegateArgs args, bool force=false) + { + if(trayIcon == null) + return; + + bool EitherControllerConnected = false; + for(int pad = 0; pad < 2; ++pad) + if(args.controller[pad].info.connected) + EitherControllerConnected = true; + + // Skip the refresh if the connected state didn't change. + if(wasConnected == EitherControllerConnected && !force) + return; + wasConnected = EitherControllerConnected; + + trayIcon.Text = EitherControllerConnected? "StepManiaX (connected)":"StepManiaX (disconnected)"; + + // Set the tray icon. + string filename = EitherControllerConnected? "window%20icon.ico":"window%20icon%20grey.ico"; + Stream iconStream = GetResourceStream(new Uri( "pack://application:,,,/Resources/" + filename)).Stream; + trayIcon.Icon = new System.Drawing.Icon(iconStream); + } } } diff --git a/smx-config/MainWindow.xaml.cs b/smx-config/MainWindow.xaml.cs index 0deb9f7..8eeb02a 100644 --- a/smx-config/MainWindow.xaml.cs +++ b/smx-config/MainWindow.xaml.cs @@ -18,6 +18,51 @@ namespace smx_config onConfigChange = new OnConfigChange(this, delegate(LoadFromConfigDelegateArgs args) { LoadUIFromConfig(args); }); + + // If we're controlling GIF animations, confirm exiting, since you can minimize + // to tray to keep playing animations. If we're not controlling animations, + // don't bug the user with a prompt. + Closing += delegate(object sender, System.ComponentModel.CancelEventArgs e) + { + LoadFromConfigDelegateArgs args = CurrentSMXDevice.singleton.GetState(); + + // Don't use ActivePads here. Even if P1 is selected for configuration, + // we can still be controlling animations for P2, so check both connected + // pads. + bool shouldConfirmExit = false; + for(int pad = 0; pad < 2; ++pad) + { + SMX.SMXConfig config; + if(!SMX.SMX.GetConfig(pad, out config)) + continue; + + // If AutoLightingUsePressedAnimations isn't set, the panel is using step + // coloring instead of pressed animations. All firmwares support this. + // Don't confirm exiting for this mode. + if((config.configFlags & SMX.SMXConfigFlags.SMXConfigFlags_AutoLightingUsePressedAnimations) == 0) + continue; + + shouldConfirmExit = true; + } + + if(!shouldConfirmExit) + return; + + MessageBoxResult result = MessageBox.Show( + "Close StepManiaX configuration?\n\n" + + "GIF animations will keep playing if the application is minimized.", + "StepManiaX", System.Windows.MessageBoxButton.YesNo); + if(result == MessageBoxResult.No) + e.Cancel = true; + }; + + StateChanged += delegate(object sender, EventArgs e) + { + // Closing the main window entirely when minimized to the tray would be + // nice, but with WPF we don't really save memory by doing that, so + // just hide the window. + ShowInTaskbar = WindowState != WindowState.Minimized; + }; } public override void OnApplyTemplate() diff --git a/smx-config/Resources/window icon grey.ico b/smx-config/Resources/window icon grey.ico new file mode 100644 index 0000000000000000000000000000000000000000..86c5cce6e2364ac57c83f5a95ee7beaf4c10a883 GIT binary patch literal 38078 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 literal 0 HcmV?d00001 diff --git a/smx-config/Resources/window icon grey.png b/smx-config/Resources/window icon grey.png new file mode 100644 index 0000000000000000000000000000000000000000..835e3f7ded14b5a27d4cf888d5e0e84804ee03f1 GIT binary patch literal 10810 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 literal 0 HcmV?d00001 diff --git a/smx-config/SMXConfig.csproj b/smx-config/SMXConfig.csproj index d5c23eb..9e628f8 100644 --- a/smx-config/SMXConfig.csproj +++ b/smx-config/SMXConfig.csproj @@ -81,6 +81,7 @@ + @@ -195,6 +196,12 @@ + + + + + +