Improve minimizing to tray, and restore the existing instance if SMXConfig is launched when it's already minimized to the tray.

master
Glenn Maynard 6 years ago
parent ded697cf4c
commit cce566624a
  1. 66
      smx-config/App.xaml.cs
  2. 3
      smx-config/Helpers.cs
  3. 29
      smx-config/MainWindow.xaml.cs

@ -2,6 +2,7 @@ using System;
using System.Windows;
using System.Runtime.InteropServices;
using System.IO;
using System.Threading;
namespace smx_config
{
@ -24,6 +25,13 @@ namespace smx_config
{
base.OnStartup(e);
// If an instance is already running, foreground it and exit.
if(ForegroundExistingInstance())
{
Shutdown();
return;
}
// If we're being launched on startup, but the LaunchOnStartup setting is false,
// then the user turned off auto-launching but we're still being launched for some
// reason (eg. a renamed launch shortcut that we couldn't find to remove). As
@ -82,13 +90,38 @@ namespace smx_config
window.Closed += MainWindowClosed;
window.Show();
}
else if(window.WindowState == WindowState.Minimized)
else if(IsMinimizedToTray())
{
window.WindowState = WindowState.Normal;
window.Visibility = Visibility.Visible;
window.Activate();
}
else
window.WindowState = WindowState.Minimized;
{
MinimizeToTray();
}
}
public bool IsMinimizedToTray()
{
return window.Visibility == Visibility.Collapsed;
}
public void MinimizeToTray()
{
// Just hide the window. Don't actually set the window to minimized, since it
// won't do anything and it causes problems when restoring the window.
window.Visibility = Visibility.Collapsed;
}
public void BringToForeground()
{
// Restore or create the window. Don't minimize if we're already restored.
if(window == null || IsMinimizedToTray())
ToggleMainWindow();
// Focus the window.
window.WindowState = WindowState.Normal;
window.Activate();
}
private void MainWindowClosed(object sender, EventArgs e)
@ -123,6 +156,33 @@ namespace smx_config
}
}
// If another instance other than this one is running, send it WM_USER to tell it to
// foreground itself. Return true if another instance was found.
private bool ForegroundExistingInstance()
{
bool createdNew = false;
EventWaitHandle SMXConfigEvent = new EventWaitHandle(false, EventResetMode.AutoReset, "SMXConfigEvent", out createdNew);
if(!createdNew)
{
// Signal the event to foreground the existing instance.
SMXConfigEvent.Set();
return true;
}
ThreadPool.RegisterWaitForSingleObject(SMXConfigEvent, ForegroundApplicationCallback, this, Timeout.Infinite, false);
return false;
}
private static void ForegroundApplicationCallback(Object self, Boolean timedOut)
{
// This is called when another instance sends us a message over SMXConfigEvent.
Application.Current.Dispatcher.Invoke(new Action(() => {
App application = (App) Application.Current;
application.BringToForeground();
}));
}
// Create a tray icon. For some reason there's no WPF interface for this,
// so we have to use Forms.
void CreateTrayIcon()

@ -357,6 +357,9 @@ namespace smx_config
shortcut.WindowStyle = 0;
shortcut.Save();
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
}
// This class just makes it easier to assemble binary command packets.

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Interop;
namespace smx_config
{
@ -65,20 +66,16 @@ namespace smx_config
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()
{
base.OnApplyTemplate();
// Add our WndProc hook.
HwndSource source = (HwndSource) PresentationSource.FromVisual(this);
source.AddHook(new HwndSourceHook(WndProcHook));
Version1.Content = "SMXConfig version " + SMX.SMX.Version();
Version2.Content = "SMXConfig version " + SMX.SMX.Version();
@ -516,5 +513,21 @@ namespace smx_config
// until we call dialog.Close above.
dialog.ShowDialog();
}
const int WM_SYSCOMMAND = 0x0112;
const int SC_MINIMIZE = 0xF020;
private IntPtr WndProcHook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
App application = (App) Application.Current;
if(msg == WM_SYSCOMMAND && ((int)wparam & 0xFFF0) == SC_MINIMIZE)
{
// Cancel minimize, and call MinimizeToTray instead.
handled = true;
application.MinimizeToTray();
}
return IntPtr.Zero;
}
}
}

Loading…
Cancel
Save