Allow minimizing to the tray.
This allows running GIF animations in the background.
This commit is contained in:
parent
4691ce5ecf
commit
5cf5eddc81
@ -1,8 +1,7 @@
|
|||||||
<Application x:Class="smx_config.App"
|
<Application x:Class="smx_config.App"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:local="clr-namespace:smx_config"
|
xmlns:local="clr-namespace:smx_config">
|
||||||
StartupUri="MainWindow.xaml">
|
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
|
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace smx_config
|
namespace smx_config
|
||||||
{
|
{
|
||||||
@ -11,9 +12,17 @@ namespace smx_config
|
|||||||
[DllImport("SMX.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("SMX.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern void SMX_Internal_OpenConsole();
|
private static extern void SMX_Internal_OpenConsole();
|
||||||
|
|
||||||
|
private System.Windows.Forms.NotifyIcon trayIcon;
|
||||||
|
private MainWindow window;
|
||||||
|
|
||||||
App()
|
App()
|
||||||
{
|
{
|
||||||
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionEventHandler;
|
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionEventHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStartup(StartupEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnStartup(e);
|
||||||
|
|
||||||
if(!SMX.SMX.DLLExists())
|
if(!SMX.SMX.DLLExists())
|
||||||
{
|
{
|
||||||
@ -38,6 +47,40 @@ namespace smx_config
|
|||||||
// we're running.
|
// we're running.
|
||||||
Helpers.LoadSavedPanelAnimations();
|
Helpers.LoadSavedPanelAnimations();
|
||||||
SMX.SMX.LightsAnimation_SetAuto(true);
|
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)
|
private void UnhandledExceptionEventHandler(object sender, UnhandledExceptionEventArgs e)
|
||||||
@ -50,13 +93,69 @@ namespace smx_config
|
|||||||
{
|
{
|
||||||
base.OnExit(e);
|
base.OnExit(e);
|
||||||
|
|
||||||
// Shut down cleanly, to make sure we don't run any threaded callbacks during shutdown.
|
|
||||||
Console.WriteLine("Application exiting");
|
Console.WriteLine("Application exiting");
|
||||||
if(CurrentSMXDevice.singleton == null)
|
|
||||||
return;
|
// Remove the tray icon.
|
||||||
CurrentSMXDevice.singleton.Shutdown();
|
if(trayIcon != null)
|
||||||
CurrentSMXDevice.singleton = 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,51 @@ namespace smx_config
|
|||||||
onConfigChange = new OnConfigChange(this, delegate(LoadFromConfigDelegateArgs args) {
|
onConfigChange = new OnConfigChange(this, delegate(LoadFromConfigDelegateArgs args) {
|
||||||
LoadUIFromConfig(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()
|
public override void OnApplyTemplate()
|
||||||
|
BIN
smx-config/Resources/window icon grey.ico
Normal file
BIN
smx-config/Resources/window icon grey.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
BIN
smx-config/Resources/window icon grey.png
Normal file
BIN
smx-config/Resources/window icon grey.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
@ -81,6 +81,7 @@
|
|||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
@ -195,6 +196,12 @@
|
|||||||
<Resource Include="Resources\pressed.gif" />
|
<Resource Include="Resources\pressed.gif" />
|
||||||
<Resource Include="Resources\released.gif" />
|
<Resource Include="Resources\released.gif" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Resource Include="Resources\window icon grey.ico" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Resource Include="Resources\window icon.ico" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user