Improve minimizing to tray, and restore the existing instance if SMXConfig is launched when it's already minimized to the tray.
This commit is contained in:
parent
ded697cf4c
commit
cce566624a
@ -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…
x
Reference in New Issue
Block a user