Housekeeping, refine IconReader and fix ShellContextMenu

This commit is contained in:
Peter Kirmeier 2023-04-28 18:48:39 +02:00
parent 175c93e511
commit ab9b0ea0b0
5 changed files with 68 additions and 109 deletions

View file

@ -209,7 +209,6 @@ namespace SystemTrayMenu.Business
timerShowProcessStartedAsLoadingIcon.Stop();
timerStillActiveCheck.Stop();
waitLeave.Stop();
IconReader.Dispose();
MainMenu?.Close();
foreach (FileSystemWatcher watcher in watchers)
@ -634,10 +633,7 @@ namespace SystemTrayMenu.Business
if (!AsEnumerable.Any(m => m.Visibility == Visibility.Visible))
{
if (IconReader.ClearIfCacheTooBig())
{
GC.Collect();
}
IconReader.ClearCacheWhenLimitReached();
openCloseState = OpenCloseState.Default;
}
@ -1088,7 +1084,7 @@ namespace SystemTrayMenu.Business
}
}
RowData rowDataRenamed = new(isFolder, rowData.IsAdditionalItem, false, 0, path);
RowData rowDataRenamed = new(isFolder, rowData.IsAdditionalItem, 0, path);
FolderOptions.ReadHiddenAttributes(rowDataRenamed.Path, out bool hasHiddenFlag, out bool isDirectoryToHide);
if (isDirectoryToHide)
{
@ -1160,7 +1156,7 @@ namespace SystemTrayMenu.Business
FileAttributes attr = File.GetAttributes(e.FullPath);
bool isFolder = (attr & FileAttributes.Directory) == FileAttributes.Directory;
bool isAddionalItem = Path.GetDirectoryName(e.FullPath) != Config.Path;
RowData rowData = new(isFolder, isAddionalItem, false, 0, e.FullPath);
RowData rowData = new(isFolder, isAddionalItem, 0, e.FullPath);
FolderOptions.ReadHiddenAttributes(rowData.Path, out bool hasHiddenFlag, out bool isDirectoryToHide);
if (isDirectoryToHide)
{

View file

@ -24,14 +24,12 @@ namespace SystemTrayMenu.DataClasses
/// </summary>
/// <param name="isFolder">Flag if file or folder.</param>
/// <param name="isAdditionalItem">Flag if additional item, from other folder than root folder.</param>
/// <param name="isNetworkRoot">Flag if resolved from network root folder.</param>
/// <param name="level">The number of the menu level.</param>
/// <param name="path">Path to item.</param>
internal RowData(bool isFolder, bool isAdditionalItem, bool isNetworkRoot, int level, string path)
internal RowData(bool isFolder, bool isAdditionalItem, int level, string path)
{
IsFolder = isFolder;
IsAdditionalItem = isAdditionalItem;
IsNetworkRoot = isNetworkRoot;
Level = level;
try
@ -81,8 +79,6 @@ namespace SystemTrayMenu.DataClasses
{
ContainsMenu |= IsLinkToFolder;
}
IsMainMenu = Level == 0;
}
catch (Exception ex)
{
@ -100,8 +96,6 @@ namespace SystemTrayMenu.DataClasses
internal bool IsAdditionalItem { get; }
internal bool IsNetworkRoot { get; }
internal int Level { get; set; }
internal string? FileExtension { get; }
@ -118,8 +112,6 @@ namespace SystemTrayMenu.DataClasses
internal bool ContainsMenu { get; }
internal bool IsMainMenu { get; }
internal Menu? SubMenu { get; set; }
internal bool IsMenuOpen { get; set; }
@ -140,12 +132,12 @@ namespace SystemTrayMenu.DataClasses
{
if (IsFolder || IsLinkToFolder)
{
Icon = GetFolderIconWithCache(Path, ShowOverlay, updateIconInBackground, IsMainMenu, out bool loading);
Icon = GetFolderIconWithCache(Path, ShowOverlay, updateIconInBackground, Level == 0, out bool loading);
IconLoading = loading;
}
else
{
Icon = GetFileIconWithCache(Path, ResolvedPath, ShowOverlay, updateIconInBackground, IsMainMenu, out bool loading);
Icon = GetFileIconWithCache(Path, ResolvedPath, ShowOverlay, updateIconInBackground, Level == 0, out bool loading);
IconLoading = loading;
}
@ -168,53 +160,52 @@ namespace SystemTrayMenu.DataClasses
{
IsClicking = true;
}
if (e != null &&
e.RightButton == MouseButtonState.Pressed &&
FileInfo != null &&
Path != null &&
dgv != null &&
dgv.Items.Count > RowIndex &&
else if (e.RightButton == MouseButtonState.Pressed &&
FileInfo != null && Path != null &&
dgv != null && dgv.Items.Count > RowIndex &&
(DateTime.Now - contextMenuClosed).TotalMilliseconds > 200)
{
IsContextMenuOpen = true;
ShellContextMenu ctxMnu = new();
Window window = dgv.GetParentWindow();
var position = Mouse.GetPosition(window);
position.Offset(window.Left, window.Top);
if (ContainsMenu)
CreateAndShowShellContextMenu();
void CreateAndShowShellContextMenu()
{
DirectoryInfo[] dir = new DirectoryInfo[1];
dir[0] = new DirectoryInfo(Path);
ctxMnu.ShowContextMenu(dir, position);
TriggerFileWatcherChangeWorkaround();
ShellContextMenu ctxMnu = new();
Window window = dgv.GetParentWindow();
var position = Mouse.GetPosition(window);
position.Offset(window.Left, window.Top);
if (ContainsMenu)
{
DirectoryInfo[] dir = new DirectoryInfo[1];
dir[0] = new DirectoryInfo(Path);
ctxMnu.ShowContextMenu(dir, position);
}
else
{
FileInfo[] arrFI = new FileInfo[1];
arrFI[0] = FileInfo;
ctxMnu.ShowContextMenu(arrFI, position);
}
}
else
TriggerFileWatcherChangeWorkaround();
void TriggerFileWatcherChangeWorkaround()
{
FileInfo[] arrFI = new FileInfo[1];
arrFI[0] = FileInfo;
ctxMnu.ShowContextMenu(arrFI, position);
TriggerFileWatcherChangeWorkaround();
try
{
string? parentFolder = System.IO.Path.GetDirectoryName(Path);
// Assume folder is not null as failure will be catched any ways
Directory.GetFiles(parentFolder!);
}
catch (Exception ex)
{
Log.Warn($"{nameof(TriggerFileWatcherChangeWorkaround)} '{Path}'", ex);
}
}
IsContextMenuOpen = false;
contextMenuClosed = DateTime.Now;
}
void TriggerFileWatcherChangeWorkaround()
{
try
{
string? parentFolder = System.IO.Path.GetDirectoryName(Path);
// Assume folder is not null as failure will be catched any ways
Directory.GetFiles(parentFolder!);
}
catch (Exception ex)
{
Log.Warn($"{nameof(TriggerFileWatcherChangeWorkaround)} '{Path}'", ex);
}
}
}
internal void OpenItem(out bool doCloseAfterOpen, int clickCount = -1)

View file

@ -173,7 +173,7 @@ namespace SystemTrayMenu.Helpers
if (indexOfFirstSpace > 0)
{
string directory = Path.Combine(path, line[..indexOfFirstSpace]);
menuData.RowDatas.Add(new RowData(true, false, true, menuData.Level, directory));
menuData.RowDatas.Add(new RowData(true, false, menuData.Level, directory));
resolvedSomething = true;
}
}
@ -201,7 +201,7 @@ namespace SystemTrayMenu.Helpers
return;
}
menuData.RowDatas.Add(new RowData(true, false, false, menuData.Level, directory));
menuData.RowDatas.Add(new RowData(true, false, menuData.Level, directory));
}
foreach (string file in DirectoryBySearchPattern.GetFiles(path, Config.SearchPattern))
@ -211,7 +211,7 @@ namespace SystemTrayMenu.Helpers
return;
}
menuData.RowDatas.Add(new RowData(false, false, false, menuData.Level, file));
menuData.RowDatas.Add(new RowData(false, false, menuData.Level, file));
}
}
@ -225,14 +225,14 @@ namespace SystemTrayMenu.Helpers
{
foreach (string file in DirectoryBySearchPattern.GetFiles(path, Config.SearchPattern))
{
menuData.RowDatas.Add(new RowData(false, true, false, menuData.Level, file));
menuData.RowDatas.Add(new RowData(false, true, menuData.Level, file));
}
foreach (string directory in Directory.GetDirectories(path))
{
if (!onlyFiles)
{
menuData.RowDatas.Add(new RowData(true, true, false, menuData.Level, directory));
menuData.RowDatas.Add(new RowData(true, true, menuData.Level, directory));
}
if (recursiv)

View file

@ -5,6 +5,7 @@
namespace SystemTrayMenu.Utilities
{
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
@ -735,7 +736,7 @@ namespace SystemTrayMenu.Utilities
try
{
if (arrPIDLs == null || oParentFolder == null || oContextMenu == null)
if (arrPIDLs == null || oParentFolder == null)
{
ReleaseAll();
return;
@ -972,6 +973,7 @@ namespace SystemTrayMenu.Utilities
/// <param name="oParentFolder">Parent folder.</param>
/// <param name="arrPIDLs">PIDLs.</param>
/// <returns>true if it got the interfaces, otherwise false.</returns>
[MemberNotNullWhen(true, nameof(oContextMenu))]
private bool GetContextMenuInterfaces(IShellFolder oParentFolder, IntPtr[] arrPIDLs, out IntPtr ctxMenuPtr)
{
int nResult = oParentFolder.GetUIObjectOf(

View file

@ -20,8 +20,8 @@ namespace SystemTrayMenu.Utilities
/// </summary>
public static class IconReader
{
private static readonly ConcurrentDictionary<string, Icon?> DictIconCacheMainMenu = new();
private static readonly ConcurrentDictionary<string, Icon?> DictIconCacheSubMenus = new();
private static readonly ConcurrentDictionary<string, Icon?> IconDictPersistent = new();
private static readonly ConcurrentDictionary<string, Icon?> IconDictCache = new();
public enum IconSize
{
@ -29,47 +29,26 @@ namespace SystemTrayMenu.Utilities
Small = 1, // 16x16 pixels
}
public enum FolderType
{
Open = 0,
Closed = 1,
}
// see https://github.com/Hofknecht/SystemTrayMenu/issues/209.
public static bool IsPreloading { get; set; } = true;
public static void Dispose(bool includingMainMenu = true)
public static void ClearCacheWhenLimitReached()
{
if (includingMainMenu)
if (IconDictCache.Count > Properties.Settings.Default.ClearCacheIfMoreThanThisNumberOfItems)
{
foreach (Icon? icon in DictIconCacheMainMenu.Values)
foreach (Icon? icon in IconDictCache.Values)
{
icon?.Dispose();
}
}
foreach (Icon? icon in DictIconCacheSubMenus.Values)
{
icon?.Dispose();
IconDictCache.Clear();
GC.Collect();
}
}
public static bool ClearIfCacheTooBig()
{
bool cleared = false;
if (DictIconCacheSubMenus.Count > Properties.Settings.Default.ClearCacheIfMoreThanThisNumberOfItems)
{
Dispose(false);
DictIconCacheSubMenus.Clear();
cleared = true;
}
return cleared;
}
public static void RemoveIconFromCache(string path)
{
if (DictIconCacheMainMenu.Remove(path, out Icon? iconToRemove))
if (IconDictPersistent.Remove(path, out Icon? iconToRemove))
{
iconToRemove?.Dispose();
}
@ -80,7 +59,7 @@ namespace SystemTrayMenu.Utilities
string? resolvedPath,
bool linkOverlay,
bool updateIconInBackground,
bool isMainMenu,
bool checkPersistentFirst,
out bool loading,
string keyPath = "")
{
@ -109,8 +88,8 @@ namespace SystemTrayMenu.Utilities
key = extension + linkOverlay;
}
if (!DictIconCache(isMainMenu).TryGetValue(key, out icon) &&
!DictIconCache(!isMainMenu).TryGetValue(key, out icon))
if (!DictIconCache(checkPersistentFirst).TryGetValue(key, out icon) &&
!DictIconCache(!checkPersistentFirst).TryGetValue(key, out icon))
{
icon = Resources.StaticResources.LoadingIcon;
loading = true;
@ -119,7 +98,7 @@ namespace SystemTrayMenu.Utilities
new Thread(UpdateIconInBackground).Start();
void UpdateIconInBackground()
{
DictIconCache(isMainMenu).GetOrAdd(key, GetIconSTA(path, resolvedPath, linkOverlay, size, false));
DictIconCache(checkPersistentFirst).GetOrAdd(key, GetIconSTA(path, resolvedPath, linkOverlay, size, false));
}
}
}
@ -132,7 +111,7 @@ namespace SystemTrayMenu.Utilities
string? path,
bool linkOverlay,
bool updateIconInBackground,
bool isMainMenu,
bool checkPersistentFirst,
out bool loading)
{
loading = false;
@ -150,8 +129,8 @@ namespace SystemTrayMenu.Utilities
}
string key = path;
if (!DictIconCache(isMainMenu).TryGetValue(key, out icon) &&
!DictIconCache(!isMainMenu).TryGetValue(key, out icon))
if (!DictIconCache(checkPersistentFirst).TryGetValue(key, out icon) &&
!DictIconCache(!checkPersistentFirst).TryGetValue(key, out icon))
{
icon = Resources.StaticResources.LoadingIcon;
loading = true;
@ -160,14 +139,14 @@ namespace SystemTrayMenu.Utilities
{
if (IsPreloading)
{
DictIconCache(isMainMenu).GetOrAdd(key, GetFolder);
DictIconCache(checkPersistentFirst).GetOrAdd(key, GetFolder);
}
else
{
new Thread(UpdateIconInBackground).Start();
void UpdateIconInBackground()
{
DictIconCache(isMainMenu).GetOrAdd(key, GetFolder);
DictIconCache(checkPersistentFirst).GetOrAdd(key, GetFolder);
}
}
@ -223,17 +202,8 @@ namespace SystemTrayMenu.Utilities
return icon;
}
private static ConcurrentDictionary<string, Icon?> DictIconCache(bool isMainMenu)
{
if (isMainMenu)
{
return DictIconCacheMainMenu;
}
else
{
return DictIconCacheSubMenus;
}
}
private static ConcurrentDictionary<string, Icon?> DictIconCache(bool checkPersistentFirst)
=> checkPersistentFirst ? IconDictPersistent : IconDictCache;
private static bool IsExtensionWithSameIcon(string fileExtension)
{