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

View file

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

View file

@ -173,7 +173,7 @@ namespace SystemTrayMenu.Helpers
if (indexOfFirstSpace > 0) if (indexOfFirstSpace > 0)
{ {
string directory = Path.Combine(path, line[..indexOfFirstSpace]); 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; resolvedSomething = true;
} }
} }
@ -201,7 +201,7 @@ namespace SystemTrayMenu.Helpers
return; 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)) foreach (string file in DirectoryBySearchPattern.GetFiles(path, Config.SearchPattern))
@ -211,7 +211,7 @@ namespace SystemTrayMenu.Helpers
return; 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)) 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)) foreach (string directory in Directory.GetDirectories(path))
{ {
if (!onlyFiles) 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) if (recursiv)

View file

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

View file

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