mirror of
https://github.com/Hofknecht/SystemTrayMenu.git
synced 2024-09-30 09:06:32 +13:00
Simplified code
Fix potential issue of loading from wrong thread during startup
This commit is contained in:
parent
ddf91131cb
commit
cd5ab5aa5c
5 changed files with 88 additions and 173 deletions
|
@ -18,6 +18,7 @@ namespace SystemTrayMenu
|
|||
/// </summary>
|
||||
public partial class App : Application, IDisposable
|
||||
{
|
||||
private static TaskbarLogo? taskbarLogo;
|
||||
private readonly AppNotifyIcon menuNotifyIcon = new();
|
||||
private readonly Menus menus = new();
|
||||
private bool isDisposed;
|
||||
|
@ -29,26 +30,32 @@ namespace SystemTrayMenu
|
|||
menus.LoadStopped += menuNotifyIcon.LoadingStop;
|
||||
menuNotifyIcon.Click += () => menus.SwitchOpenClose(true, false);
|
||||
|
||||
if (Settings.Default.ShowInTaskbar)
|
||||
{
|
||||
TaskbarLogo = new ();
|
||||
TaskbarLogo.Activated += (_, _) => menus.SwitchOpenCloseByTaskbarItem();
|
||||
TaskbarLogo.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
menus.FirstStartInBackground();
|
||||
}
|
||||
Activated += (_, _) => IsActiveApp = true;
|
||||
Deactivated += (_, _) => IsActiveApp = false;
|
||||
|
||||
if (Settings.Default.CheckForUpdates)
|
||||
Startup += (_, _) =>
|
||||
{
|
||||
_ = Dispatcher.InvokeAsync(
|
||||
() => GitHubUpdate.ActivateNewVersionFormOrCheckForUpdates(showWhenUpToDate: false),
|
||||
DispatcherPriority.ApplicationIdle);
|
||||
}
|
||||
if (Settings.Default.ShowInTaskbar)
|
||||
{
|
||||
taskbarLogo = new();
|
||||
taskbarLogo.Activated += (_, _) => menus.SwitchOpenCloseByTaskbarItem();
|
||||
taskbarLogo.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
menus.SwitchOpenClose(false, true);
|
||||
}
|
||||
|
||||
if (Settings.Default.CheckForUpdates)
|
||||
{
|
||||
_ = Dispatcher.InvokeAsync(
|
||||
() => GitHubUpdate.ActivateNewVersionFormOrCheckForUpdates(showWhenUpToDate: false),
|
||||
DispatcherPriority.ApplicationIdle);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static TaskbarLogo? TaskbarLogo { get; private set; } = null;
|
||||
internal static bool IsActiveApp { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
@ -60,8 +67,8 @@ namespace SystemTrayMenu
|
|||
{
|
||||
if (!isDisposed)
|
||||
{
|
||||
TaskbarLogo?.Close();
|
||||
TaskbarLogo = null;
|
||||
taskbarLogo?.Close();
|
||||
taskbarLogo = null;
|
||||
|
||||
menus.Dispose();
|
||||
menuNotifyIcon.Dispose();
|
||||
|
|
|
@ -26,7 +26,6 @@ namespace SystemTrayMenu.Business
|
|||
|
||||
internal class Menus : IDisposable
|
||||
{
|
||||
private readonly Dispatcher dispatchter = Dispatcher.CurrentDispatcher;
|
||||
private readonly BackgroundWorker workerMainMenu = new();
|
||||
private readonly List<BackgroundWorker> workersSubMenu = new();
|
||||
private readonly WaitToLoadMenu waitToOpenMenu = new();
|
||||
|
@ -37,10 +36,10 @@ namespace SystemTrayMenu.Business
|
|||
private readonly DispatcherTimer timerShowProcessStartedAsLoadingIcon = new();
|
||||
private readonly DispatcherTimer timerStillActiveCheck = new();
|
||||
private readonly DispatcherTimer waitLeave = new();
|
||||
private DateTime deactivatedTime = DateTime.MinValue;
|
||||
private OpenCloseState openCloseState = OpenCloseState.Default;
|
||||
private TaskbarPosition taskbarPosition = new WindowsTaskbar().Position;
|
||||
private TaskbarPosition taskbarPosition = TaskbarPosition.Unknown;
|
||||
private bool showMenuAfterMainPreload;
|
||||
private bool wasDeactivated;
|
||||
private Menu? mainMenu;
|
||||
|
||||
public Menus()
|
||||
|
@ -115,7 +114,7 @@ namespace SystemTrayMenu.Business
|
|||
}
|
||||
}
|
||||
|
||||
waitToOpenMenu.MouseEnterOk += MouseEnterOk;
|
||||
waitToOpenMenu.MouseSelect += keyboardInput.SelectByMouse;
|
||||
waitToOpenMenu.CloseMenu += (menu) => HideOldMenu(menu);
|
||||
|
||||
if (Settings.Default.SupportGamepad)
|
||||
|
@ -125,7 +124,7 @@ namespace SystemTrayMenu.Business
|
|||
{
|
||||
if (IsMainUsable)
|
||||
{
|
||||
Menu? menu = GetActiveMenu(mainMenu) ?? mainMenu;
|
||||
Menu? menu = GetActiveMenu(mainMenu) ?? mainMenu; // TODO: Do we really need to provide the menu? doesn't keyboardInput already know this?
|
||||
menu?.Dispatcher.Invoke(keyboardInput.CmdKeyProcessed, new object[] { menu, key, modifiers });
|
||||
}
|
||||
};
|
||||
|
@ -137,10 +136,7 @@ namespace SystemTrayMenu.Business
|
|||
void StillActiveTick()
|
||||
{
|
||||
timerStillActiveCheck.Stop();
|
||||
if (!IsActiveApp())
|
||||
{
|
||||
FadeHalfOrOutIfNeeded();
|
||||
}
|
||||
FadeHalfOrOutIfNeeded();
|
||||
}
|
||||
|
||||
waitLeave.Interval = TimeSpan.FromMilliseconds(Settings.Default.TimeUntilCloses);
|
||||
|
@ -198,7 +194,7 @@ namespace SystemTrayMenu.Business
|
|||
}
|
||||
|
||||
[MemberNotNullWhen(true, nameof(mainMenu))]
|
||||
private bool IsMainUsable => mainMenu?.IsUsable ?? false;
|
||||
private bool IsMainUsable => mainMenu != null && mainMenu.Visibility == Visibility.Visible;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
@ -227,15 +223,7 @@ namespace SystemTrayMenu.Business
|
|||
mainMenu?.Close();
|
||||
}
|
||||
|
||||
internal static void OpenFolder(string? path = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
path = Config.Path;
|
||||
}
|
||||
|
||||
Log.ProcessStart(path);
|
||||
}
|
||||
internal static void OpenFolder(string path) => Log.ProcessStart(path);
|
||||
|
||||
internal void SwitchOpenCloseByTaskbarItem()
|
||||
{
|
||||
|
@ -245,11 +233,6 @@ namespace SystemTrayMenu.Business
|
|||
timerStillActiveCheck.Start();
|
||||
}
|
||||
|
||||
internal void FirstStartInBackground()
|
||||
{
|
||||
dispatchter.Invoke(() => SwitchOpenClose(false, true));
|
||||
}
|
||||
|
||||
internal void SwitchOpenClose(bool byClick, bool allowPreloading)
|
||||
{
|
||||
// Ignore open close events during main preload #248
|
||||
|
@ -261,9 +244,7 @@ namespace SystemTrayMenu.Business
|
|||
}
|
||||
|
||||
waitToOpenMenu.MouseActive = byClick;
|
||||
if (byClick &&
|
||||
!Config.AlwaysOpenByPin &&
|
||||
(DateTime.Now - deactivatedTime).TotalMilliseconds < 200)
|
||||
if (byClick && !Config.AlwaysOpenByPin && wasDeactivated)
|
||||
{
|
||||
// By click on notifyicon the menu gets deactivated and closed
|
||||
}
|
||||
|
@ -278,7 +259,12 @@ namespace SystemTrayMenu.Business
|
|||
{
|
||||
openCloseState = OpenCloseState.Closing;
|
||||
MenusFadeOut();
|
||||
StopWorker();
|
||||
|
||||
if (workerMainMenu.IsBusy)
|
||||
{
|
||||
workerMainMenu.CancelAsync();
|
||||
}
|
||||
|
||||
if (IsVisibleAnyMenu(mainMenu) == null)
|
||||
{
|
||||
openCloseState = OpenCloseState.Default;
|
||||
|
@ -287,33 +273,21 @@ namespace SystemTrayMenu.Business
|
|||
else
|
||||
{
|
||||
openCloseState = OpenCloseState.Opening;
|
||||
StartWorker();
|
||||
|
||||
if (Settings.Default.GenerateShortcutsToDrives)
|
||||
{
|
||||
GenerateDriveShortcuts.Start();
|
||||
}
|
||||
|
||||
if (!workerMainMenu.IsBusy)
|
||||
{
|
||||
LoadStarted?.Invoke();
|
||||
workerMainMenu.RunWorkerAsync(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deactivatedTime = DateTime.MinValue;
|
||||
}
|
||||
|
||||
internal void StartWorker()
|
||||
{
|
||||
if (Settings.Default.GenerateShortcutsToDrives)
|
||||
{
|
||||
GenerateDriveShortcuts.Start();
|
||||
}
|
||||
|
||||
if (!workerMainMenu.IsBusy)
|
||||
{
|
||||
LoadStarted?.Invoke();
|
||||
workerMainMenu.RunWorkerAsync(null);
|
||||
}
|
||||
}
|
||||
|
||||
internal void StopWorker()
|
||||
{
|
||||
if (workerMainMenu.IsBusy)
|
||||
{
|
||||
workerMainMenu.CancelAsync();
|
||||
}
|
||||
wasDeactivated = false;
|
||||
}
|
||||
|
||||
private static Menu? IsVisibleAnyMenu(Menu? menu)
|
||||
|
@ -432,13 +406,13 @@ namespace SystemTrayMenu.Business
|
|||
break;
|
||||
case MenuDataDirectoryState.Empty:
|
||||
MessageBox.Show(Translator.GetText("Your root directory for the app does not exist or is empty! Change the root directory or put some files, directories or shortcuts into the root directory."));
|
||||
OpenFolder();
|
||||
OpenFolder(Config.Path);
|
||||
Config.SetFolderByUser();
|
||||
AppRestart.ByConfigChange();
|
||||
break;
|
||||
case MenuDataDirectoryState.NoAccess:
|
||||
MessageBox.Show(Translator.GetText("You have no access to the root directory of the app. Grant access to the directory or change the root directory."));
|
||||
OpenFolder();
|
||||
OpenFolder(Config.Path);
|
||||
Config.SetFolderByUser();
|
||||
AppRestart.ByConfigChange();
|
||||
break;
|
||||
|
@ -493,8 +467,6 @@ namespace SystemTrayMenu.Business
|
|||
}
|
||||
}
|
||||
|
||||
private bool IsActiveApp() => GetActiveMenu(mainMenu) != null || (App.TaskbarLogo?.IsActive ?? false);
|
||||
|
||||
private Menu Create(MenuData menuData, string path)
|
||||
{
|
||||
Menu menu = new(menuData, path);
|
||||
|
@ -562,9 +534,9 @@ namespace SystemTrayMenu.Business
|
|||
else if (!Settings.Default.StaysOpenWhenFocusLostAfterEnterPressed)
|
||||
{
|
||||
FadeHalfOrOutIfNeeded();
|
||||
if (!IsActiveApp())
|
||||
if (!App.IsActiveApp)
|
||||
{
|
||||
deactivatedTime = DateTime.Now;
|
||||
wasDeactivated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -583,7 +555,7 @@ namespace SystemTrayMenu.Business
|
|||
menu.RowSelectionChanged += waitToOpenMenu.RowSelectionChanged;
|
||||
menu.CellMouseEnter += waitToOpenMenu.MouseEnter;
|
||||
menu.CellMouseLeave += waitToOpenMenu.MouseLeave;
|
||||
menu.CellMouseDown += (menu, itemData) => MouseEnterOk(menu, itemData);
|
||||
menu.CellMouseDown += keyboardInput.SelectByMouse;
|
||||
menu.CellOpenOnClick += waitToOpenMenu.ClickOpensInstantly;
|
||||
menu.ClosePressed += MenusFadeOut;
|
||||
|
||||
|
@ -596,11 +568,8 @@ namespace SystemTrayMenu.Business
|
|||
else
|
||||
{
|
||||
// Sub Menu (loading)
|
||||
if (IsMainUsable)
|
||||
{
|
||||
menu.ShowWithFade(!IsActiveApp(), false);
|
||||
menu.RefreshSelection();
|
||||
}
|
||||
menu.ShowWithFade(!App.IsActiveApp, false);
|
||||
menu.RefreshSelection();
|
||||
}
|
||||
|
||||
return menu;
|
||||
|
@ -608,7 +577,7 @@ namespace SystemTrayMenu.Business
|
|||
|
||||
private void MenuVisibleChanged(Menu menu)
|
||||
{
|
||||
if (menu.IsUsable)
|
||||
if (menu.Visibility == Visibility.Visible)
|
||||
{
|
||||
AdjustMenusSizeAndLocation(menu.Level);
|
||||
|
||||
|
@ -632,34 +601,14 @@ namespace SystemTrayMenu.Business
|
|||
}
|
||||
}
|
||||
|
||||
private void MouseEnterOk(Menu menu, ListViewItemData itemData)
|
||||
{
|
||||
if (IsMainUsable)
|
||||
{
|
||||
keyboardInput.SelectByMouse(menu, itemData);
|
||||
}
|
||||
}
|
||||
|
||||
private void SystemEvents_DisplaySettingsChanged(object? sender, EventArgs e)
|
||||
{
|
||||
dispatchter.Invoke(() =>
|
||||
{
|
||||
if (IsMainUsable)
|
||||
{
|
||||
Menu? menu = mainMenu;
|
||||
if (menu != null)
|
||||
{
|
||||
menu.RelocateOnNextShow = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
private void SystemEvents_DisplaySettingsChanged(object? sender, EventArgs e) =>
|
||||
mainMenu?.Dispatcher.Invoke(() => mainMenu.RelocateOnNextShow = true);
|
||||
|
||||
private void FadeHalfOrOutIfNeeded()
|
||||
{
|
||||
if (IsMainUsable)
|
||||
{
|
||||
if (!IsActiveApp())
|
||||
if (!App.IsActiveApp)
|
||||
{
|
||||
if (Settings.Default.StaysOpenWhenFocusLost && IsMouseOverAnyMenu(mainMenu) != null)
|
||||
{
|
||||
|
@ -711,14 +660,9 @@ namespace SystemTrayMenu.Business
|
|||
useCustomLocation = false;
|
||||
}
|
||||
|
||||
// Only apply taskbar position change when no menu is currently open
|
||||
WindowsTaskbar taskbar = new();
|
||||
if (IsMainUsable && mainMenu.SubMenu == null)
|
||||
{
|
||||
taskbarPosition = taskbar.Position;
|
||||
}
|
||||
|
||||
// Shrink the usable space depending on taskbar location
|
||||
WindowsTaskbar taskbar = new();
|
||||
taskbarPosition = taskbar.Position;
|
||||
switch (taskbarPosition)
|
||||
{
|
||||
case TaskbarPosition.Left:
|
||||
|
|
|
@ -16,7 +16,6 @@ namespace SystemTrayMenu.Handler
|
|||
private Menu? currentMenu;
|
||||
private ListViewItemData? currentItemData;
|
||||
private bool alreadyOpened;
|
||||
private bool checkForMouseActive = true;
|
||||
|
||||
internal WaitToLoadMenu()
|
||||
{
|
||||
|
@ -30,28 +29,34 @@ namespace SystemTrayMenu.Handler
|
|||
|
||||
internal event Action? StopLoadMenu;
|
||||
|
||||
internal event Action<Menu, ListViewItemData>? MouseEnterOk;
|
||||
internal event Action<Menu, ListViewItemData>? MouseSelect;
|
||||
|
||||
internal bool MouseActive { get; set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
timerStartLoad.Stop();
|
||||
}
|
||||
public void Dispose() => timerStartLoad.Stop();
|
||||
|
||||
internal void MouseEnter(Menu menu, ListViewItemData itemData)
|
||||
{
|
||||
if (MouseActive)
|
||||
{
|
||||
MouseEnterOk?.Invoke(menu, itemData);
|
||||
MouseSelect?.Invoke(menu, itemData);
|
||||
timerStartLoad.Stop();
|
||||
StopLoadMenu?.Invoke();
|
||||
checkForMouseActive = true;
|
||||
SetData(menu, itemData);
|
||||
timerStartLoad.Start();
|
||||
}
|
||||
}
|
||||
|
||||
internal void MouseLeave()
|
||||
{
|
||||
if (MouseActive)
|
||||
{
|
||||
timerStartLoad.Stop();
|
||||
StopLoadMenu?.Invoke();
|
||||
ResetData();
|
||||
}
|
||||
}
|
||||
|
||||
internal void RowSelectionChanged(Menu? menu)
|
||||
{
|
||||
// Deselect
|
||||
|
@ -64,28 +69,16 @@ namespace SystemTrayMenu.Handler
|
|||
if (menu?.SelectedItem != null)
|
||||
{
|
||||
SetData(menu, menu.SelectedItem);
|
||||
checkForMouseActive = false;
|
||||
timerStartLoad.Start();
|
||||
}
|
||||
}
|
||||
|
||||
internal void MouseLeave()
|
||||
{
|
||||
if (MouseActive)
|
||||
{
|
||||
timerStartLoad.Stop();
|
||||
StopLoadMenu?.Invoke();
|
||||
ResetData();
|
||||
}
|
||||
}
|
||||
|
||||
internal void ClickOpensInstantly(Menu menu, ListViewItemData itemData)
|
||||
{
|
||||
timerStartLoad.Stop();
|
||||
menu.SelectedItem = itemData;
|
||||
SetData(menu, itemData);
|
||||
MouseActive = true;
|
||||
checkForMouseActive = false;
|
||||
CallOpenMenuNow();
|
||||
}
|
||||
|
||||
|
@ -95,17 +88,13 @@ namespace SystemTrayMenu.Handler
|
|||
StopLoadMenu?.Invoke();
|
||||
SetData(menu, itemData);
|
||||
MouseActive = false;
|
||||
checkForMouseActive = false;
|
||||
CallOpenMenuNow();
|
||||
}
|
||||
|
||||
private void WaitStartLoad_Tick(object? sender, EventArgs e)
|
||||
{
|
||||
timerStartLoad.Stop();
|
||||
if (!checkForMouseActive || MouseActive)
|
||||
{
|
||||
CallOpenMenuNow();
|
||||
}
|
||||
CallOpenMenuNow();
|
||||
}
|
||||
|
||||
private void CallOpenMenuNow()
|
||||
|
|
|
@ -21,8 +21,7 @@
|
|||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
From="{Binding Opacity}" To="0.8" Duration="0:0:0.4"
|
||||
Completed="FadeIn_Completed"/>
|
||||
From="{Binding Opacity}" To="0.8" Duration="0:0:0.4"/>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
|
@ -31,8 +30,7 @@
|
|||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
From="{Binding Opacity}" To="1.0" Duration="0:0:0.5"
|
||||
Completed="FadeIn_Completed"/>
|
||||
From="{Binding Opacity}" To="1.0" Duration="0:0:0.5"/>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
|
|
|
@ -44,7 +44,6 @@ namespace SystemTrayMenu.UserInterface
|
|||
#if TODO // SEARCH
|
||||
public const string RowFilterShowAll = "[SortIndex] LIKE '%0%'";
|
||||
#endif
|
||||
private bool isFading;
|
||||
private bool directionToRight;
|
||||
private bool mouseDown;
|
||||
private Point lastLocation;
|
||||
|
@ -207,7 +206,6 @@ namespace SystemTrayMenu.UserInterface
|
|||
Closed += (_, _) =>
|
||||
{
|
||||
timerUpdateIcons.Stop();
|
||||
IsClosed = true; // TODO WPF Replace Forms wrapper
|
||||
|
||||
if (RowDataParent?.SubMenu == this)
|
||||
{
|
||||
|
@ -308,10 +306,6 @@ namespace SystemTrayMenu.UserInterface
|
|||
|
||||
internal bool RelocateOnNextShow { get; set; } = true;
|
||||
|
||||
internal bool IsClosed { get; private set; } = false;
|
||||
|
||||
internal bool IsUsable => Visibility == Visibility.Visible && !isFading && !IsClosed;
|
||||
|
||||
public override string ToString() => nameof(Menu) + " L" + Level.ToString() + ": " + Title;
|
||||
|
||||
internal void ResetSearchText()
|
||||
|
@ -485,13 +479,11 @@ namespace SystemTrayMenu.UserInterface
|
|||
{
|
||||
if (Settings.Default.UseFading)
|
||||
{
|
||||
isFading = true;
|
||||
RaiseEvent(new(routedEvent: FadeInEvent));
|
||||
}
|
||||
else
|
||||
{
|
||||
Opacity = 1D;
|
||||
FadeIn_Completed(this, new());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -513,22 +505,17 @@ namespace SystemTrayMenu.UserInterface
|
|||
Opacity = 0D;
|
||||
Show();
|
||||
|
||||
if (Settings.Default.UseFading)
|
||||
if (!Settings.Default.UseFading)
|
||||
{
|
||||
isFading = true;
|
||||
if (transparency)
|
||||
{
|
||||
RaiseEvent(new(routedEvent: FadeToTransparentEvent));
|
||||
}
|
||||
else
|
||||
{
|
||||
RaiseEvent(new(routedEvent: FadeInEvent));
|
||||
}
|
||||
Opacity = transparency ? 0.80D : 1D;
|
||||
}
|
||||
else if (transparency)
|
||||
{
|
||||
RaiseEvent(new(routedEvent: FadeToTransparentEvent));
|
||||
}
|
||||
else
|
||||
{
|
||||
Opacity = transparency ? 0.80D : 1D;
|
||||
FadeIn_Completed(this, new());
|
||||
RaiseEvent(new(routedEvent: FadeInEvent));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,7 +533,6 @@ namespace SystemTrayMenu.UserInterface
|
|||
|
||||
if (Settings.Default.UseFading)
|
||||
{
|
||||
isFading = true;
|
||||
RaiseEvent(new(routedEvent: FadeOutEvent));
|
||||
}
|
||||
else
|
||||
|
@ -867,16 +853,7 @@ namespace SystemTrayMenu.UserInterface
|
|||
labelStatus.Content = $"{filesAndFoldersCount} {Translator.GetText(elements)}";
|
||||
}
|
||||
|
||||
private void FadeIn_Completed(object sender, EventArgs e)
|
||||
{
|
||||
isFading = false;
|
||||
}
|
||||
|
||||
private void FadeOut_Completed(object sender, EventArgs e)
|
||||
{
|
||||
isFading = false;
|
||||
Hide();
|
||||
}
|
||||
private void FadeOut_Completed(object sender, EventArgs e) => Hide();
|
||||
|
||||
private void HandlePreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue