Not enough memory resources are available to process this command. (#442), version 1.3.1.9

This commit is contained in:
Markus Hofknecht 2022-10-20 17:55:54 +02:00
parent 87dbd64c73
commit 1d4820c946
19 changed files with 735 additions and 569 deletions

View file

@ -24,27 +24,20 @@ namespace SystemTrayMenu
public App()
{
AppRestart.BeforeRestarting += Dispose;
SystemEvents.DisplaySettingsChanged += (s, e) => SystemEvents_DisplaySettingsChanged();
SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
menus.LoadStarted += menuNotifyIcon.LoadingStart;
menus.LoadStopped += menuNotifyIcon.LoadingStop;
menuNotifyIcon.Click += () => menus.SwitchOpenClose(true);
menuNotifyIcon.Click += MenuNotifyIcon_Click;
menuNotifyIcon.OpenLog += Log.OpenLogFile;
menus.MainPreload();
if (Properties.Settings.Default.ShowInTaskbar)
{
taskbarForm = new TaskbarForm();
taskbarForm.FormClosed += (s, e) => Application.Exit();
taskbarForm.Deactivate += (s, e) => SetStateNormal();
taskbarForm.Resize += (s, e) => SetStateNormal();
taskbarForm.FormClosed += TaskbarForm_FormClosed;
taskbarForm.Deactivate += SetStateNormal;
taskbarForm.Resize += SetStateNormal;
taskbarForm.Activated += TasbkarItemActivated;
void TasbkarItemActivated(object sender, EventArgs e)
{
SetStateNormal();
taskbarForm.Activate();
taskbarForm.Focus();
menus.SwitchOpenCloseByTaskbarItem();
}
}
DllImports.NativeMethods.User32ShowInactiveTopmost(taskbarForm);
@ -65,27 +58,57 @@ namespace SystemTrayMenu
}
else
{
taskbarForm?.Dispose();
SystemEvents.DisplaySettingsChanged -= (s, e) => SystemEvents_DisplaySettingsChanged();
AppRestart.BeforeRestarting -= Dispose;
SystemEvents.DisplaySettingsChanged -= SystemEvents_DisplaySettingsChanged;
menus.LoadStarted -= menuNotifyIcon.LoadingStart;
menus.LoadStopped -= menuNotifyIcon.LoadingStop;
menus.Dispose();
menuNotifyIcon.Click -= MenuNotifyIcon_Click;
menuNotifyIcon.OpenLog -= Log.OpenLogFile;
menuNotifyIcon.Dispose();
if (taskbarForm != null)
{
taskbarForm.FormClosed -= TaskbarForm_FormClosed;
taskbarForm.Deactivate -= SetStateNormal;
taskbarForm.Resize -= SetStateNormal;
taskbarForm.Activated -= TasbkarItemActivated;
taskbarForm.Dispose();
}
}
}
private void SystemEvents_DisplaySettingsChanged()
private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
{
menus.ReAdjustSizeAndLocation();
}
private void MenuNotifyIcon_Click()
{
menus.SwitchOpenClose(true);
}
private void TaskbarForm_FormClosed(object sender, FormClosedEventArgs e)
{
Application.Exit();
}
/// <summary>
/// This ensures that next click on taskbaritem works as activate event/click event.
/// </summary>
private void SetStateNormal()
private void SetStateNormal(object sender, EventArgs e)
{
if (Form.ActiveForm == taskbarForm)
{
taskbarForm.WindowState = FormWindowState.Normal;
}
}
private void TasbkarItemActivated(object sender, EventArgs e)
{
SetStateNormal(sender, e);
taskbarForm.Activate();
taskbarForm.Focus();
menus.SwitchOpenCloseByTaskbarItem();
}
}
}

View file

@ -27,33 +27,34 @@ namespace SystemTrayMenu.Handler
this.menus = menus;
}
internal event EventHandlerEmpty HotKeyPressed;
public event Action HotKeyPressed;
internal event EventHandlerEmpty ClosePressed;
public event Action ClosePressed;
internal event Action<DataGridView, int> RowSelected;
public event Action<DataGridView, int> RowSelected;
internal event Action<int, DataGridView> RowDeselected;
public event Action<DataGridView, int> RowDeselected;
internal event Action<DataGridView, int> EnterPressed;
public event Action<DataGridView, int> EnterPressed;
internal event EventHandlerEmpty Cleared;
public event Action Cleared;
internal bool InUse { get; set; }
public bool InUse { get; set; }
public void Dispose()
{
hook.KeyPressed -= Hook_KeyPressed;
hook.Dispose();
}
internal void RegisterHotKey()
public void RegisterHotKey()
{
if (!string.IsNullOrEmpty(Properties.Settings.Default.HotKey))
{
try
{
hook.RegisterHotKey();
hook.KeyPressed += (sender, e) => HotKeyPressed?.Invoke();
hook.KeyPressed += Hook_KeyPressed;
}
catch (InvalidOperationException ex)
{
@ -64,13 +65,13 @@ namespace SystemTrayMenu.Handler
}
}
internal void ResetSelectedByKey()
public void ResetSelectedByKey()
{
iRowKey = -1;
iMenuKey = 0;
}
internal void CmdKeyProcessed(object sender, Keys keys)
public void CmdKeyProcessed(object sender, Keys keys)
{
sender ??= menus[iMenuKey];
@ -171,12 +172,12 @@ namespace SystemTrayMenu.Handler
}
}
internal void SearchTextChanging()
public void SearchTextChanging()
{
ClearIsSelectedByKey();
}
internal void SearchTextChanged(Menu menu, bool isSearchStringEmpty)
public void SearchTextChanged(Menu menu, bool isSearchStringEmpty)
{
DataGridView dgv = menu.GetDataGridView();
if (isSearchStringEmpty)
@ -189,12 +190,12 @@ namespace SystemTrayMenu.Handler
}
}
internal void ClearIsSelectedByKey()
public void ClearIsSelectedByKey()
{
ClearIsSelectedByKey(iMenuKey, iRowKey);
}
internal void Select(DataGridView dgv, int i, bool refreshview)
public void Select(DataGridView dgv, int i, bool refreshview)
{
int newiMenuKey = ((Menu)dgv.TopLevelControl).Level;
if (i != iRowKey || newiMenuKey != iMenuKey)
@ -222,6 +223,11 @@ namespace SystemTrayMenu.Handler
}
}
private void Hook_KeyPressed(object sender, KeyPressedEventArgs e)
{
HotKeyPressed?.Invoke();
}
private bool IsAnyMenuSelectedByKey(
ref DataGridView dgv,
ref Menu menuFromSelected,
@ -307,7 +313,7 @@ namespace SystemTrayMenu.Handler
}
else
{
RowDeselected(iRowBefore, dgvBefore);
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
EnterPressed.Invoke(dgv, iRowKey);
}
@ -318,7 +324,7 @@ namespace SystemTrayMenu.Handler
if (SelectMatchedReverse(dgv, iRowKey) ||
SelectMatchedReverse(dgv, dgv.Rows.Count - 1))
{
RowDeselected(iRowBefore, dgvBefore);
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
@ -328,7 +334,7 @@ namespace SystemTrayMenu.Handler
if (SelectMatched(dgv, iRowKey) ||
SelectMatched(dgv, 0))
{
RowDeselected(iRowBefore, dgvBefore);
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
@ -337,7 +343,7 @@ namespace SystemTrayMenu.Handler
case Keys.Home:
if (SelectMatched(dgv, 0))
{
RowDeselected(iRowBefore, dgvBefore);
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
@ -346,7 +352,7 @@ namespace SystemTrayMenu.Handler
case Keys.End:
if (SelectMatchedReverse(dgv, dgv.Rows.Count - 1))
{
RowDeselected(iRowBefore, dgvBefore);
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
@ -380,7 +386,7 @@ namespace SystemTrayMenu.Handler
break;
case Keys.Escape:
case Keys.Alt | Keys.F4:
RowDeselected(iRowBefore, dgvBefore);
RowDeselected(dgvBefore, iRowBefore);
iMenuKey = 0;
iRowKey = -1;
toClear = true;
@ -392,7 +398,7 @@ namespace SystemTrayMenu.Handler
if (SelectMatched(dgv, iRowKey, keyInput) ||
SelectMatched(dgv, 0, keyInput))
{
RowDeselected(iRowBefore, null);
RowDeselected(null, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
@ -402,7 +408,7 @@ namespace SystemTrayMenu.Handler
if (SelectMatched(dgv, iRowKey, keyInput) ||
SelectMatched(dgv, 0, keyInput))
{
RowDeselected(iRowBefore, null);
RowDeselected(null, iRowBefore);
SelectRow(dgv, iRowKey);
}
else
@ -434,7 +440,7 @@ namespace SystemTrayMenu.Handler
if (SelectMatched(dgv, dgv.SelectedRows[0].Index) ||
SelectMatched(dgv, 0))
{
RowDeselected(iRowBefore, dgvBefore);
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
@ -442,7 +448,7 @@ namespace SystemTrayMenu.Handler
}
else
{
RowDeselected(iRowBefore, dgvBefore);
RowDeselected(dgvBefore, iRowBefore);
iMenuKey = 0;
iRowKey = -1;
toClear = true;
@ -466,7 +472,7 @@ namespace SystemTrayMenu.Handler
if (SelectMatched(dgv, iRowKey) ||
SelectMatched(dgv, 0))
{
RowDeselected(iRowBefore, dgvBefore);
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
@ -483,7 +489,7 @@ namespace SystemTrayMenu.Handler
if (SelectMatched(dgv, iRowKey) ||
SelectMatched(dgv, 0))
{
RowDeselected(iRowBefore, dgvBefore);
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}

View file

@ -12,6 +12,7 @@ namespace SystemTrayMenu.Business
using System.IO;
using System.Linq;
using System.Windows.Forms;
using SharpDX.DirectInput;
using SystemTrayMenu.DataClasses;
using SystemTrayMenu.DllImports;
using SystemTrayMenu.Handler;
@ -19,6 +20,7 @@ namespace SystemTrayMenu.Business
using SystemTrayMenu.Helpers;
using SystemTrayMenu.UserInterface;
using SystemTrayMenu.Utilities;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using Menu = SystemTrayMenu.UserInterface.Menu;
using Timer = System.Windows.Forms.Timer;
@ -53,275 +55,33 @@ namespace SystemTrayMenu.Business
workerMainMenu.WorkerSupportsCancellation = true;
workerMainMenu.DoWork += LoadMenu;
workerMainMenu.RunWorkerCompleted += LoadMainMenuCompleted;
void LoadMainMenuCompleted(object sender, RunWorkerCompletedEventArgs e)
{
keyboardInput.ResetSelectedByKey();
LoadStopped();
if (e.Result == null)
{
// Clean up menu status IsMenuOpen for previous one
DataGridView dgvMainMenu = menus[0].GetDataGridView();
foreach (DataRow row in ((DataTable)dgvMainMenu.DataSource).Rows)
{
RowData rowDataToClear = (RowData)row[2];
rowDataToClear.IsMenuOpen = false;
rowDataToClear.IsClicking = false;
rowDataToClear.IsSelected = false;
rowDataToClear.IsContextMenuOpen = false;
}
RefreshSelection(dgvMainMenu);
if (Properties.Settings.Default.AppearAtMouseLocation)
{
menus[0].Tag = null;
}
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
else
{
MenuData menuData = (MenuData)e.Result;
switch (menuData.Validity)
{
case MenuDataValidity.Valid:
if (IconReader.MainPreload)
{
workerMainMenu.DoWork -= LoadMenu;
menus[0] = Create(menuData, new DirectoryInfo(Config.Path).Name);
menus[0].HandleCreated += (s, e) => ExecuteWatcherHistory();
Scaling.CalculateFactorByDpi(menus[0].GetDataGridView().CreateGraphics());
IconReader.MainPreload = false;
if (showMenuAfterMainPreload)
{
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
}
else
{
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
break;
case MenuDataValidity.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();
Config.SetFolderByUser();
AppRestart.ByConfigChange();
break;
case MenuDataValidity.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();
Config.SetFolderByUser();
AppRestart.ByConfigChange();
break;
case MenuDataValidity.Undefined:
Log.Info($"{nameof(MenuDataValidity)}.{nameof(MenuDataValidity.Undefined)}");
break;
default:
break;
}
}
openCloseState = OpenCloseState.Default;
}
waitToOpenMenu.StopLoadMenu += WaitToOpenMenu_StopLoadMenu;
void WaitToOpenMenu_StopLoadMenu()
{
foreach (BackgroundWorker workerSubMenu in workersSubMenu.
Where(w => w.IsBusy))
{
workerSubMenu.CancelAsync();
}
LoadStopped();
}
waitToOpenMenu.StartLoadMenu += StartLoadMenu;
void StartLoadMenu(RowData rowData)
{
if (menus[0].IsUsable &&
(menus[rowData.Level + 1] == null ||
menus[rowData.Level + 1].Tag as RowData != rowData))
{
CreateAndShowLoadingMenu(rowData);
void CreateAndShowLoadingMenu(RowData rowData)
{
MenuData menuDataLoading = new(rowData.Level + 1)
{
Validity = MenuDataValidity.Valid,
};
Menu menuLoading = Create(menuDataLoading, new DirectoryInfo(rowData.Path).Name);
menuLoading.IsLoadingMenu = true;
AdjustMenusSizeAndLocation();
menus[rowData.Level + 1] = menuLoading;
menuLoading.Tag = menuDataLoading.RowDataParent = rowData;
menuDataLoading.RowDataParent.SubMenu = menuLoading;
menuLoading.SetTypeLoading();
ShowSubMenu(menuLoading);
}
BackgroundWorker workerSubMenu = workersSubMenu.
Where(w => !w.IsBusy).FirstOrDefault();
if (workerSubMenu == null)
{
workerSubMenu = new BackgroundWorker
{
WorkerSupportsCancellation = true,
};
workerSubMenu.DoWork += LoadMenu;
workerSubMenu.RunWorkerCompleted += LoadSubMenuCompleted;
workersSubMenu.Add(workerSubMenu);
}
workerSubMenu.RunWorkerAsync(rowData);
}
void LoadSubMenuCompleted(object senderCompleted, RunWorkerCompletedEventArgs e)
{
MenuData menuData = (MenuData)e.Result;
Menu menuLoading = menus[menuData.Level];
string userSearchText = string.Empty;
bool closedLoadingMenu = false;
if (menuLoading != null && menuLoading.IsLoadingMenu)
{
menuLoading.HideWithFade();
userSearchText = menuLoading.GetSearchText();
menus[menuLoading.Level] = null;
closedLoadingMenu = true;
}
if (menuData.Validity != MenuDataValidity.Undefined &&
menus[0].IsUsable)
{
Menu menu = Create(menuData);
switch (menuData.Validity)
{
case MenuDataValidity.Valid:
menu.SetTypeSub();
break;
case MenuDataValidity.Empty:
menu.SetTypeEmpty();
break;
case MenuDataValidity.NoAccess:
menu.SetTypeNoAccess();
break;
}
menu.Tag = menuData.RowDataParent;
menuData.RowDataParent.SubMenu = menu;
if (menus[0].IsUsable)
{
ShowSubMenu(menu);
menu.SetSearchText(userSearchText);
}
}
else if (closedLoadingMenu && menus[0].IsUsable)
{
menuData.RowDataParent.IsMenuOpen = false;
menuData.RowDataParent.IsClicking = false;
menuData.RowDataParent.IsSelected = false;
Menu menuPrevious = menus[menuData.Level - 1];
if (menuPrevious != null)
{
RefreshSelection(menuPrevious.GetDataGridView());
}
}
}
}
waitToOpenMenu.CloseMenu += CloseMenu;
void CloseMenu(int level)
{
if (level < menus.Length && menus[level] != null)
{
HideOldMenu(menus[level]);
}
if (level - 1 < menus.Length && menus[level - 1] != null)
{
menus[level - 1].FocusTextBox();
}
}
waitToOpenMenu.MouseEnterOk += MouseEnterOk;
dgvMouseRow.RowMouseEnter += waitToOpenMenu.MouseEnter;
dgvMouseRow.RowMouseLeave += waitToOpenMenu.MouseLeave;
dgvMouseRow.RowMouseLeave += Dgv_RowMouseLeave;
keyboardInput = new(menus);
keyboardInput.RegisterHotKey();
keyboardInput.HotKeyPressed += () => SwitchOpenClose(false);
keyboardInput.HotKeyPressed += KeyboardInput_HotKeyPressed;
keyboardInput.ClosePressed += MenusFadeOut;
keyboardInput.RowDeselected += waitToOpenMenu.RowDeselected;
keyboardInput.EnterPressed += waitToOpenMenu.EnterOpensInstantly;
keyboardInput.RowSelected += waitToOpenMenu.RowSelected;
keyboardInput.RowSelected += AdjustScrollbarToDisplayedRow;
void AdjustScrollbarToDisplayedRow(DataGridView dgv, int index)
{
Menu menu = (Menu)dgv.FindForm();
menu.AdjustScrollbar();
}
joystickHelper = new();
joystickHelper.KeyPressed += (key) => menus[0].Invoke(keyboardInput.CmdKeyProcessed, null, key);
joystickHelper.KeyPressed += JoystickHelper_KeyPressed;
timerShowProcessStartedAsLoadingIcon.Interval = Properties.Settings.Default.TimeUntilClosesAfterEnterPressed;
timerStillActiveCheck.Interval = Properties.Settings.Default.TimeUntilClosesAfterEnterPressed + 20;
timerStillActiveCheck.Tick += (sender, e) => StillActiveTick();
void StillActiveTick()
{
if (!IsActive())
{
FadeHalfOrOutIfNeeded();
}
timerStillActiveCheck.Stop();
}
timerStillActiveCheck.Tick += TimerStillActiveCheck_Tick;
waitLeave.LeaveTriggered += FadeHalfOrOutIfNeeded;
CreateWatcher(Config.Path, false);
foreach (var pathAndFlags in MenusHelpers.GetAddionalPathsForMainMenu())
{
CreateWatcher(pathAndFlags.Path, pathAndFlags.Recursive);
}
void CreateWatcher(string path, bool recursiv)
{
try
{
FileSystemWatcher watcher = new()
{
Path = path,
NotifyFilter = NotifyFilters.Attributes |
NotifyFilters.DirectoryName |
NotifyFilters.FileName |
NotifyFilters.LastWrite,
Filter = "*.*",
};
watcher.Created += WatcherProcessItem;
watcher.Deleted += WatcherProcessItem;
watcher.Renamed += WatcherProcessItem;
watcher.Changed += WatcherProcessItem;
watcher.IncludeSubdirectories = recursiv;
watcher.EnableRaisingEvents = true;
watchers.Add(watcher);
}
catch (Exception ex)
{
Log.Warn($"Failed to {nameof(CreateWatcher)}: {path}", ex);
}
}
CreateWatchers();
}
internal event EventHandlerEmpty LoadStarted;
public event Action LoadStarted;
internal event EventHandlerEmpty LoadStopped;
public event Action LoadStopped;
private enum OpenCloseState
{
@ -334,34 +94,7 @@ namespace SystemTrayMenu.Business
private List<Menu> AsList => AsEnumerable.ToList();
public void Dispose()
{
workerMainMenu.Dispose();
foreach (BackgroundWorker worker in workersSubMenu)
{
worker.Dispose();
}
waitToOpenMenu.Dispose();
keyboardInput.Dispose();
joystickHelper.Dispose();
timerShowProcessStartedAsLoadingIcon.Dispose();
timerStillActiveCheck.Dispose();
waitLeave.Dispose();
IconReader.Dispose();
DisposeMenu(menus[0]);
dgvMouseRow.Dispose();
foreach (FileSystemWatcher watcher in watchers)
{
watcher.Created -= WatcherProcessItem;
watcher.Deleted -= WatcherProcessItem;
watcher.Renamed -= WatcherProcessItem;
watcher.Changed -= WatcherProcessItem;
watcher.Dispose();
}
}
internal static MenuData GetData(BackgroundWorker worker, string path, int level)
public static MenuData GetData(BackgroundWorker worker, string path, int level)
{
MenuData menuData = new(level);
if (worker?.CancellationPending == true || string.IsNullOrEmpty(path))
@ -392,18 +125,65 @@ namespace SystemTrayMenu.Business
return menuData;
}
internal void SwitchOpenCloseByTaskbarItem()
public void Dispose()
{
workerMainMenu.DoWork -= LoadMenu;
workerMainMenu.RunWorkerCompleted -= LoadMainMenuCompleted;
workerMainMenu.Dispose();
dgvMouseRow.RowMouseEnter -= waitToOpenMenu.MouseEnter;
dgvMouseRow.RowMouseLeave -= waitToOpenMenu.MouseLeave;
dgvMouseRow.RowMouseLeave -= Dgv_RowMouseLeave;
keyboardInput.HotKeyPressed -= KeyboardInput_HotKeyPressed;
keyboardInput.ClosePressed -= MenusFadeOut;
keyboardInput.RowDeselected -= waitToOpenMenu.RowDeselected;
keyboardInput.EnterPressed -= waitToOpenMenu.EnterOpensInstantly;
keyboardInput.RowSelected -= waitToOpenMenu.RowSelected;
keyboardInput.RowSelected -= AdjustScrollbarToDisplayedRow;
keyboardInput.Dispose();
waitToOpenMenu.StopLoadMenu -= WaitToOpenMenu_StopLoadMenu;
waitToOpenMenu.StartLoadMenu -= StartLoadMenu;
waitToOpenMenu.CloseMenu -= CloseMenu;
waitToOpenMenu.MouseEnterOk -= MouseEnterOk;
waitToOpenMenu.Dispose();
joystickHelper.KeyPressed -= JoystickHelper_KeyPressed;
joystickHelper.Dispose();
timerShowProcessStartedAsLoadingIcon.Dispose();
timerStillActiveCheck.Tick -= TimerStillActiveCheck_Tick;
timerStillActiveCheck.Dispose();
waitLeave.LeaveTriggered -= FadeHalfOrOutIfNeeded;
waitLeave.Dispose();
foreach (BackgroundWorker workerSubMenu in workersSubMenu)
{
workerSubMenu.DoWork -= LoadMenu;
workerSubMenu.RunWorkerCompleted -= LoadSubMenuCompleted;
workerSubMenu.Dispose();
}
IconReader.Dispose();
dgvMouseRow.Dispose();
DisposeMenu(menus[0]);
foreach (FileSystemWatcher watcher in watchers)
{
watcher.Created -= WatcherProcessItem;
watcher.Deleted -= WatcherProcessItem;
watcher.Renamed -= WatcherProcessItem;
watcher.Changed -= WatcherProcessItem;
watcher.Dispose();
}
}
public void SwitchOpenCloseByTaskbarItem()
{
SwitchOpenClose(true);
timerStillActiveCheck.Start();
}
internal bool IsOpenCloseStateOpening()
public bool IsOpenCloseStateOpening()
{
return openCloseState == OpenCloseState.Opening;
}
internal void SwitchOpenClose(bool byClick, bool isMainPreload = false)
public void SwitchOpenClose(bool byClick, bool isMainPreload = false)
{
// Ignore open close events during main preload #248
if (IconReader.MainPreload && !isMainPreload)
@ -448,13 +228,18 @@ namespace SystemTrayMenu.Business
{
if (menuToDispose != null)
{
menuToDispose.UserClickedOpenFolder -= OpenFolder;
menuToDispose.MouseWheel -= AdjustMenusSizeAndLocation;
menuToDispose.MouseLeave -= waitLeave.Start;
menuToDispose.MouseEnter -= waitLeave.Stop;
menuToDispose.CmdKeyProcessed -= keyboardInput.CmdKeyProcessed;
menuToDispose.SearchTextChanging -= keyboardInput.SearchTextChanging;
menuToDispose.KeyPressCheck -= Menu_KeyPressCheck;
menuToDispose.SearchTextChanging -= Menu_SearchTextChanging;
menuToDispose.SearchTextChanged -= Menu_SearchTextChanged;
menuToDispose.UserDragsMenu -= Menu_UserDragsMenu;
menuToDispose.Activated -= Menu_Activated;
menuToDispose.Deactivate -= Menu_Deactivate;
menuToDispose.VisibleChanged -= MenuVisibleChanged;
DataGridView dgv = menuToDispose.GetDataGridView();
if (dgv != null)
{
@ -470,6 +255,7 @@ namespace SystemTrayMenu.Business
dgv.MouseDoubleClick -= Dgv_MouseDoubleClick;
dgv.SelectionChanged -= Dgv_SelectionChanged;
dgv.RowPostPaint -= Dgv_RowPostPaint;
dgv.DataError -= Dgv_DataError;
dgv.ClearSelection();
foreach (DataGridViewRow row in dgv.Rows)
@ -477,6 +263,9 @@ namespace SystemTrayMenu.Business
RowData rowData = (RowData)row.Cells[2].Value;
DisposeMenu(rowData.SubMenu);
}
DataTable dataTable = (DataTable)dgv.DataSource;
dataTable.Dispose();
}
menuToDispose.Dispose();
@ -620,6 +409,197 @@ namespace SystemTrayMenu.Business
}
}
private void LoadMainMenuCompleted(object sender, RunWorkerCompletedEventArgs e)
{
keyboardInput.ResetSelectedByKey();
LoadStopped();
if (e.Result == null)
{
// Clean up menu status IsMenuOpen for previous one
DataGridView dgvMainMenu = menus[0].GetDataGridView();
foreach (DataRow row in ((DataTable)dgvMainMenu.DataSource).Rows)
{
RowData rowDataToClear = (RowData)row[2];
rowDataToClear.IsMenuOpen = false;
rowDataToClear.IsClicking = false;
rowDataToClear.IsSelected = false;
rowDataToClear.IsContextMenuOpen = false;
}
RefreshSelection(dgvMainMenu);
if (Properties.Settings.Default.AppearAtMouseLocation)
{
menus[0].Tag = null;
}
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
else
{
MenuData menuData = (MenuData)e.Result;
switch (menuData.Validity)
{
case MenuDataValidity.Valid:
if (IconReader.MainPreload)
{
workerMainMenu.DoWork -= LoadMenu;
menus[0] = Create(menuData, new DirectoryInfo(Config.Path).Name);
menus[0].HandleCreated += (s, e) => ExecuteWatcherHistory();
Scaling.CalculateFactorByDpi(menus[0].GetDataGridView().CreateGraphics());
IconReader.MainPreload = false;
if (showMenuAfterMainPreload)
{
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
}
else
{
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
break;
case MenuDataValidity.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();
Config.SetFolderByUser();
AppRestart.ByConfigChange();
break;
case MenuDataValidity.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();
Config.SetFolderByUser();
AppRestart.ByConfigChange();
break;
case MenuDataValidity.Undefined:
Log.Info($"{nameof(MenuDataValidity)}.{nameof(MenuDataValidity.Undefined)}");
break;
default:
break;
}
}
openCloseState = OpenCloseState.Default;
}
private void WaitToOpenMenu_StopLoadMenu()
{
foreach (BackgroundWorker workerSubMenu in workersSubMenu.Where(w => w.IsBusy))
{
workerSubMenu.CancelAsync();
}
LoadStopped();
}
private void StartLoadMenu(RowData rowData)
{
if (menus[0].IsUsable &&
(menus[rowData.Level + 1] == null ||
menus[rowData.Level + 1].Tag as RowData != rowData))
{
CreateAndShowLoadingMenu(rowData);
void CreateAndShowLoadingMenu(RowData rowData)
{
MenuData menuDataLoading = new(rowData.Level + 1)
{
Validity = MenuDataValidity.Valid,
};
Menu menuLoading = Create(menuDataLoading, new DirectoryInfo(rowData.Path).Name);
menuLoading.IsLoadingMenu = true;
AdjustMenusSizeAndLocation();
menus[rowData.Level + 1] = menuLoading;
menuLoading.Tag = menuDataLoading.RowDataParent = rowData;
menuDataLoading.RowDataParent.SubMenu = menuLoading;
menuLoading.SetTypeLoading();
ShowSubMenu(menuLoading);
}
BackgroundWorker workerSubMenu = workersSubMenu.
Where(w => !w.IsBusy).FirstOrDefault();
if (workerSubMenu == null)
{
workerSubMenu = new BackgroundWorker()
{
WorkerSupportsCancellation = true,
};
workerSubMenu.DoWork += LoadMenu;
workerSubMenu.RunWorkerCompleted += LoadSubMenuCompleted;
workersSubMenu.Add(workerSubMenu);
}
workerSubMenu.RunWorkerAsync(rowData);
}
}
private void CloseMenu(int level)
{
if (level < menus.Length && menus[level] != null)
{
HideOldMenu(menus[level]);
}
if (level - 1 < menus.Length && menus[level - 1] != null)
{
menus[level - 1].FocusTextBox();
}
}
private void LoadSubMenuCompleted(object senderCompleted, RunWorkerCompletedEventArgs e)
{
MenuData menuData = (MenuData)e.Result;
Menu menuLoading = menus[menuData.Level];
string userSearchText = string.Empty;
bool closedLoadingMenu = false;
if (menuLoading != null && menuLoading.IsLoadingMenu)
{
menuLoading.HideWithFade();
userSearchText = menuLoading.GetSearchText();
menus[menuLoading.Level] = null;
closedLoadingMenu = true;
}
if (menuData.Validity != MenuDataValidity.Undefined &&
menus[0].IsUsable)
{
Menu menu = Create(menuData);
switch (menuData.Validity)
{
case MenuDataValidity.Valid:
menu.SetTypeSub();
break;
case MenuDataValidity.Empty:
menu.SetTypeEmpty();
break;
case MenuDataValidity.NoAccess:
menu.SetTypeNoAccess();
break;
}
menu.Tag = menuData.RowDataParent;
menuData.RowDataParent.SubMenu = menu;
if (menus[0].IsUsable)
{
ShowSubMenu(menu);
menu.SetSearchText(userSearchText);
}
}
else if (closedLoadingMenu && menus[0].IsUsable)
{
menuData.RowDataParent.IsMenuOpen = false;
menuData.RowDataParent.IsClicking = false;
menuData.RowDataParent.IsSelected = false;
Menu menuPrevious = menus[menuData.Level - 1];
if (menuPrevious != null)
{
RefreshSelection(menuPrevious.GetDataGridView());
}
}
}
private bool IsActive()
{
bool IsShellContextMenuOpen()
@ -653,22 +633,21 @@ namespace SystemTrayMenu.Business
private Menu Create(MenuData menuData, string title = null)
{
Menu menu = new();
string path = Config.Path;
menu.Level = menuData.Level;
menu.Path = Config.Path;
if (title == null)
{
title = new DirectoryInfo(menuData.RowDataParent.ResolvedPath).Name;
path = menuData.RowDataParent.ResolvedPath;
menu.Path = menuData.RowDataParent.ResolvedPath;
}
if (string.IsNullOrEmpty(title))
{
title = Path.GetPathRoot(path);
title = Path.GetPathRoot(menu.Path);
}
menu.AdjustControls(title, menuData.Validity);
menu.UserClickedOpenFolder += () => OpenFolder(path);
menu.Level = menuData.Level;
menu.UserClickedOpenFolder += OpenFolder;
menu.MouseWheel += AdjustMenusSizeAndLocation;
menu.MouseLeave += waitLeave.Start;
menu.MouseEnter += waitLeave.Stop;
@ -677,43 +656,8 @@ namespace SystemTrayMenu.Business
menu.SearchTextChanging += Menu_SearchTextChanging;
menu.SearchTextChanged += Menu_SearchTextChanged;
menu.UserDragsMenu += Menu_UserDragsMenu;
void Menu_UserDragsMenu()
{
if (menus[1] != null)
{
HideOldMenu(menus[1]);
}
}
menu.Deactivate += Deactivate;
void Deactivate(object sender, EventArgs e)
{
if (IsOpenCloseStateOpening())
{
Log.Info("Ignored Deactivate, because openCloseState == OpenCloseState.Opening");
}
else if (!Properties.Settings.Default.StaysOpenWhenFocusLostAfterEnterPressed ||
!waitingForReactivate)
{
FadeHalfOrOutIfNeeded();
if (!IsActive())
{
deactivatedTime = DateTime.Now;
}
}
}
menu.Activated += (sender, e) => Activated();
void Activated()
{
if (IsActive() && menus[0].IsUsable)
{
AsList.ForEach(m => m.ShowWithFade());
timerStillActiveCheck.Stop();
timerStillActiveCheck.Start();
}
}
menu.Activated += Menu_Activated;
menu.Deactivate += Menu_Deactivate;
menu.VisibleChanged += MenuVisibleChanged;
AddItemsToMenu(menuData.RowDatas, menu, out int foldersCount, out int filesCount);
@ -731,18 +675,47 @@ namespace SystemTrayMenu.Business
dgv.SelectionChanged += Dgv_SelectionChanged;
dgv.RowPostPaint += Dgv_RowPostPaint;
dgv.DataError += Dgv_DataError;
void Dgv_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
// WARN Dgv_DataError occured System.ObjectDisposedException: Cannot access a disposed object. Object name: 'Icon'
// => Rare times occured (e.g. when focused an close other application => closed and activated at same time)
Log.Warn("Dgv_DataError occured", e.Exception);
}
menu.SetCounts(foldersCount, filesCount);
return menu;
}
private void Menu_UserDragsMenu()
{
if (menus[1] != null)
{
HideOldMenu(menus[1]);
}
}
private void Menu_Activated(object sender, EventArgs e)
{
if (IsActive() && menus[0].IsUsable)
{
AsList.ForEach(m => m.ShowWithFade());
timerStillActiveCheck.Stop();
timerStillActiveCheck.Start();
}
}
private void Menu_Deactivate(object sender, EventArgs e)
{
if (IsOpenCloseStateOpening())
{
Log.Info("Ignored Deactivate, because openCloseState == OpenCloseState.Opening");
}
else if (!Properties.Settings.Default.StaysOpenWhenFocusLostAfterEnterPressed ||
!waitingForReactivate)
{
FadeHalfOrOutIfNeeded();
if (!IsActive())
{
deactivatedTime = DateTime.Now;
}
}
}
private void MenuVisibleChanged(object sender, EventArgs e)
{
Menu menu = (Menu)sender;
@ -1058,6 +1031,13 @@ namespace SystemTrayMenu.Business
}
}
private void Dgv_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
// WARN Dgv_DataError occured System.ObjectDisposedException: Cannot access a disposed object. Object name: 'Icon'
// => Rare times occured (e.g. when focused an close other application => closed and activated at same time)
Log.Warn("Dgv_DataError occured", e.Exception);
}
private void ShowSubMenu(Menu menuToShow)
{
HideOldMenu(menuToShow, true);
@ -1142,6 +1122,68 @@ namespace SystemTrayMenu.Business
joystickHelper.Disable();
}
private void CreateWatchers()
{
CreateWatcher(Config.Path, false);
foreach (var pathAndFlags in MenusHelpers.GetAddionalPathsForMainMenu())
{
CreateWatcher(pathAndFlags.Path, pathAndFlags.Recursive);
}
void CreateWatcher(string path, bool recursiv)
{
try
{
FileSystemWatcher watcher = new()
{
Path = path,
NotifyFilter = NotifyFilters.Attributes |
NotifyFilters.DirectoryName |
NotifyFilters.FileName |
NotifyFilters.LastWrite,
Filter = "*.*",
};
watcher.Created += WatcherProcessItem;
watcher.Deleted += WatcherProcessItem;
watcher.Renamed += WatcherProcessItem;
watcher.Changed += WatcherProcessItem;
watcher.IncludeSubdirectories = recursiv;
watcher.EnableRaisingEvents = true;
watchers.Add(watcher);
}
catch (Exception ex)
{
Log.Warn($"Failed to {nameof(CreateWatcher)}: {path}", ex);
}
}
}
private void AdjustScrollbarToDisplayedRow(DataGridView dgv, int index)
{
Menu menu = (Menu)dgv.FindForm();
menu.AdjustScrollbar();
}
private void JoystickHelper_KeyPressed(Keys keys)
{
menus[0].Invoke(keyboardInput.CmdKeyProcessed, null, keys);
}
private void TimerStillActiveCheck_Tick(object sender, EventArgs e)
{
if (!IsActive())
{
FadeHalfOrOutIfNeeded();
}
timerStillActiveCheck.Stop();
}
private void KeyboardInput_HotKeyPressed()
{
SwitchOpenClose(false);
}
private void AdjustMenusSizeAndLocation()
{
Rectangle screenBounds;

View file

@ -28,7 +28,7 @@ namespace SystemTrayMenu
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += (sender, e) => AskUserSendError(e.Exception);
Application.ThreadException += Application_ThreadException;
Scaling.Initialize();
FolderOptions.Initialize();
@ -40,6 +40,7 @@ namespace SystemTrayMenu
}
}
Application.ThreadException -= Application_ThreadException;
Config.Dispose();
}
catch (Exception ex)
@ -50,32 +51,37 @@ namespace SystemTrayMenu
{
Log.Close();
}
}
static void AskUserSendError(Exception ex)
private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
AskUserSendError(e.Exception);
}
private static void AskUserSendError(Exception ex)
{
Log.Error("Application Crashed", ex);
DialogResult dialogResult = MessageBox.Show(
"A problem has been encountered and the application needs to restart. " +
"Reporting this error will help us make our product better. " +
"Press 'Yes' to open your standard email app (emailto: Markus@Hofknecht.eu). " + Environment.NewLine +
@"You can also create an issue manually here https://github.com/Hofknecht/SystemTrayMenu/issues" + Environment.NewLine +
"Press 'Cancel' to quit SystemTrayMenu.",
"SystemTrayMenu Crashed",
MessageBoxButtons.YesNoCancel);
if (dialogResult == DialogResult.Yes)
{
Log.Error("Application Crashed", ex);
Log.ProcessStart("mailto:" + "markus@hofknecht.eu" +
"?subject=SystemTrayMenu Bug reported " +
Assembly.GetEntryAssembly().GetName().Version +
"&body=" + ex.ToString());
}
DialogResult dialogResult = MessageBox.Show(
"A problem has been encountered and the application needs to restart. " +
"Reporting this error will help us make our product better. " +
"Press 'Yes' to open your standard email app (emailto: Markus@Hofknecht.eu). " + Environment.NewLine +
@"You can also create an issue manually here https://github.com/Hofknecht/SystemTrayMenu/issues" + Environment.NewLine +
"Press 'Cancel' to quit SystemTrayMenu.",
"SystemTrayMenu Crashed",
MessageBoxButtons.YesNoCancel);
if (dialogResult == DialogResult.Yes)
{
Log.ProcessStart("mailto:" + "markus@hofknecht.eu" +
"?subject=SystemTrayMenu Bug reported " +
Assembly.GetEntryAssembly().GetName().Version +
"&body=" + ex.ToString());
}
if (!isStartup && dialogResult != DialogResult.Cancel)
{
AppRestart.ByThreadException();
}
if (!isStartup && dialogResult != DialogResult.Cancel)
{
AppRestart.ByThreadException();
}
}
}

View file

@ -18,10 +18,11 @@ namespace SystemTrayMenu.Handler
timerLeaveCheck.Tick += TimerLeaveCheckTick;
}
public event EventHandlerEmpty LeaveTriggered;
public event Action LeaveTriggered;
public void Dispose()
{
timerLeaveCheck.Tick -= TimerLeaveCheckTick;
timerLeaveCheck.Dispose();
}

View file

@ -33,7 +33,7 @@ namespace SystemTrayMenu.Handler
internal event Action<int> CloseMenu;
internal event EventHandlerEmpty StopLoadMenu;
internal event Action StopLoadMenu;
internal event Action<DataGridView, int> MouseEnterOk;
@ -41,6 +41,7 @@ namespace SystemTrayMenu.Handler
public void Dispose()
{
timerStartLoad.Tick -= WaitStartLoad_Tick;
timerStartLoad.Stop();
timerStartLoad.Dispose();
dgv?.Dispose();
@ -92,7 +93,7 @@ namespace SystemTrayMenu.Handler
}
}
internal void RowDeselected(int rowIndex, DataGridView dgv)
internal void RowDeselected(DataGridView dgv, int rowIndex)
{
timerStartLoad.Stop();
StopLoadMenu?.Invoke();

View file

@ -16,12 +16,12 @@ namespace SystemTrayMenu.Helper
internal DgvMouseRow()
{
timerRaiseRowMouseLeave.Interval = 200;
timerRaiseRowMouseLeave.Tick += Elapsed;
void Elapsed(object sender, EventArgs e)
{
timerRaiseRowMouseLeave.Stop();
TriggerRowMouseLeave();
}
timerRaiseRowMouseLeave.Tick += TimerRaiseRowMouseLeave_Tick;
}
~DgvMouseRow() // the finalizer
{
Dispose(false);
}
internal event Action<object, DataGridViewCellEventArgs> RowMouseEnter;
@ -75,11 +75,18 @@ namespace SystemTrayMenu.Helper
{
if (disposing)
{
timerRaiseRowMouseLeave.Tick -= TimerRaiseRowMouseLeave_Tick;
timerRaiseRowMouseLeave.Dispose();
dgv?.Dispose();
dgv = null;
}
}
private void TimerRaiseRowMouseLeave_Tick(object sender, EventArgs e)
{
timerRaiseRowMouseLeave.Stop();
TriggerRowMouseLeave();
}
private void TriggerRowMouseLeave()
{
if (dgv != null)

View file

@ -28,14 +28,19 @@ namespace SystemTrayMenu.Helper
internal Fading()
{
timer.Interval = Interval100FPS;
timer.Tick += (sender, e) => FadeStep();
timer.Tick += Timer_Tick;
}
internal event EventHandlerEmpty Hide;
~Fading() // the finalizer
{
Dispose(false);
}
internal event EventHandlerEmpty Show;
internal event Action Hide;
internal event EventHandler<double> ChangeOpacity;
internal event Action Show;
internal event Action<double> ChangeOpacity;
internal enum FadingState
{
@ -62,6 +67,7 @@ namespace SystemTrayMenu.Helper
{
if (disposing)
{
timer.Tick -= Timer_Tick;
timer.Dispose();
}
}
@ -80,6 +86,11 @@ namespace SystemTrayMenu.Helper
}
}
private void Timer_Tick(object sender, EventArgs e)
{
FadeStep();
}
private void FadeStep()
{
switch (state)
@ -90,13 +101,13 @@ namespace SystemTrayMenu.Helper
visible = true;
Show?.Invoke();
opacity = 0;
ChangeOpacity?.Invoke(this, opacity);
ChangeOpacity?.Invoke(opacity);
}
else if (Properties.Settings.Default.UseFading &&
opacity < ShownMinus)
{
opacity += StepIn;
ChangeOpacity?.Invoke(this, opacity);
ChangeOpacity?.Invoke(opacity);
}
else
{
@ -104,11 +115,11 @@ namespace SystemTrayMenu.Helper
{
// #393 provoke a redraw for the CS_DROPSHADOW to work
opacity = ShownMinus;
ChangeOpacity?.Invoke(this, opacity);
ChangeOpacity?.Invoke(opacity);
}
opacity = Shown;
ChangeOpacity?.Invoke(this, opacity);
ChangeOpacity?.Invoke(opacity);
StartStopTimer(FadingState.Idle);
}
@ -119,24 +130,24 @@ namespace SystemTrayMenu.Helper
visible = true;
Show?.Invoke();
opacity = 0;
ChangeOpacity?.Invoke(this, opacity);
ChangeOpacity?.Invoke(opacity);
}
else if (Properties.Settings.Default.UseFading &&
opacity < TransparentMinus)
{
opacity += StepIn;
ChangeOpacity?.Invoke(this, opacity);
ChangeOpacity?.Invoke(opacity);
}
else if (Properties.Settings.Default.UseFading &&
opacity > TransparentPlus)
{
opacity -= StepOut;
ChangeOpacity?.Invoke(this, opacity);
ChangeOpacity?.Invoke(opacity);
}
else
{
opacity = Transparent;
ChangeOpacity?.Invoke(this, opacity);
ChangeOpacity?.Invoke(opacity);
StartStopTimer(FadingState.Idle);
}
@ -146,12 +157,12 @@ namespace SystemTrayMenu.Helper
opacity > StepOut)
{
opacity -= StepOut;
ChangeOpacity?.Invoke(this, opacity);
ChangeOpacity?.Invoke(opacity);
}
else if (visible)
{
opacity = 0;
ChangeOpacity?.Invoke(this, opacity);
ChangeOpacity?.Invoke(opacity);
visible = false;
Hide?.Invoke();
StartStopTimer(FadingState.Idle);

View file

@ -32,6 +32,11 @@ namespace SystemTrayMenu.Helpers
}
}
~JoystickHelper() // the finalizer
{
Dispose(false);
}
public event Action<Keys> KeyPressed;
public void Enable()
@ -54,6 +59,7 @@ namespace SystemTrayMenu.Helpers
{
if (disposing)
{
timerReadJoystick.Elapsed -= ReadJoystickLoop;
timerReadJoystick?.Dispose();
joystick?.Dispose();
}

View file

@ -13,7 +13,7 @@ namespace SystemTrayMenu.Helper
/// The enumeration of possible modifiers.
/// </summary>
[Flags]
internal enum KeyboardHookModifierKeys : uint
public enum KeyboardHookModifierKeys : uint
{
None = 0,
Alt = 1,
@ -30,7 +30,7 @@ namespace SystemTrayMenu.Helper
public KeyboardHook()
{
// register the event of the inner native window.
window.KeyPressed += (sender, e) => KeyPressed?.Invoke(this, e);
window.KeyPressed += Window_KeyPressed;
}
/// <summary>
@ -47,6 +47,7 @@ namespace SystemTrayMenu.Helper
}
// dispose the inner native window.
window.KeyPressed -= Window_KeyPressed;
window.Dispose();
}
@ -104,6 +105,11 @@ namespace SystemTrayMenu.Helper
RegisterHotKey((uint)modifier, key);
}
private void Window_KeyPressed(object sender, KeyPressedEventArgs e)
{
KeyPressed?.Invoke(this, e);
}
private void RegisterHotKey(uint modifier, Keys key)
{
currentId += 1;

View file

@ -39,5 +39,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.3.1.7")]
[assembly: AssemblyFileVersion("1.3.1.7")]
[assembly: AssemblyVersion("1.3.1.9")]
[assembly: AssemblyFileVersion("1.3.1.9")]

View file

@ -15,7 +15,7 @@ namespace SystemTrayMenu.Helper
internal class AppContextMenu
{
public event EventHandlerEmpty ClickedOpenLog;
public event Action ClickedOpenLog;
public ContextMenuStrip Create()
{

View file

@ -41,9 +41,9 @@ namespace SystemTrayMenu.UserInterface
}
}
public event EventHandlerEmpty Click;
public event Action Click;
public event EventHandlerEmpty OpenLog;
public event Action OpenLog;
public void Dispose()
{

View file

@ -204,6 +204,11 @@ namespace SystemTrayMenu.UserInterface
protected override void Dispose(bool disposing)
{
MouseDown -= CustomScrollbar_MouseDown;
MouseMove -= CustomScrollbar_MouseMove;
MouseUp -= CustomScrollbar_MouseUp;
MouseLeave -= CustomScrollbar_MouseLeave;
timerMouseStillClicked.Tick -= TimerMouseStillClicked_Tick;
timerMouseStillClicked.Dispose();
base.Dispose(disposing);
}

View file

@ -14,6 +14,11 @@ namespace SystemTrayMenu.UserInterface.FolderBrowseDialog
{
private bool isDisposed;
~FolderDialog() // the finalizer
{
Dispose(false);
}
/// <summary>
/// Gets or sets /sets folder in which dialog will be open.
/// </summary>

View file

@ -1,4 +1,7 @@
namespace SystemTrayMenu.UserInterface
using System.Windows.Forms;
using SystemTrayMenu.Helper;
namespace SystemTrayMenu.UserInterface
{
partial class Menu
{
@ -19,9 +22,45 @@
}
timerUpdateIcons.Stop();
timerUpdateIcons.Tick -= TimerUpdateIcons_Tick;
timerUpdateIcons.Tick += TimerUpdateIcons_Tick_Loading;
timerUpdateIcons.Dispose();
fading.ChangeOpacity -= Fading_ChangeOpacity;
fading.Show -= Fading_Show;
fading.Hide -= Hide;
fading.Dispose();
dgv.GotFocus -= Dgv_GotFocus;
dgv.MouseEnter -= ControlsMouseEnter;
dgv.MouseLeave -= ControlsMouseLeave;
customScrollbar.GotFocus -= CustomScrollbar_GotFocus;
customScrollbar.Scroll -= CustomScrollbar_Scroll;
customScrollbar.MouseEnter -= ControlsMouseEnter;
customScrollbar.MouseLeave -= ControlsMouseLeave;
customScrollbar.Dispose();
labelTitle.MouseEnter -= ControlsMouseEnter;
labelTitle.MouseLeave -= ControlsMouseLeave;
textBoxSearch.MouseEnter -= ControlsMouseEnter;
textBoxSearch.MouseLeave -= ControlsMouseLeave;
pictureBoxOpenFolder.MouseEnter -= ControlsMouseEnter;
pictureBoxOpenFolder.MouseLeave -= ControlsMouseLeave;
pictureBoxMenuAlwaysOpen.MouseEnter -= ControlsMouseEnter;
pictureBoxMenuAlwaysOpen.MouseLeave -= ControlsMouseLeave;
pictureBoxMenuAlwaysOpen.Paint -= PictureBoxMenuAlwaysOpen_Paint;
pictureBoxMenuAlwaysOpen.Paint -= LoadingMenu_Paint;
pictureBoxSettings.MouseEnter -= ControlsMouseEnter;
pictureBoxSettings.MouseLeave -= ControlsMouseLeave;
pictureBoxRestart.MouseEnter -= ControlsMouseEnter;
pictureBoxRestart.MouseLeave -= ControlsMouseLeave;
pictureBoxSearch.MouseEnter -= ControlsMouseEnter;
pictureBoxSearch.MouseLeave -= ControlsMouseLeave;
tableLayoutPanelMenu.MouseEnter -= ControlsMouseEnter;
tableLayoutPanelMenu.MouseLeave -= ControlsMouseLeave;
tableLayoutPanelDgvAndScrollbar.MouseEnter -= ControlsMouseEnter;
tableLayoutPanelDgvAndScrollbar.MouseLeave -= ControlsMouseLeave;
tableLayoutPanelBottom.MouseEnter -= ControlsMouseEnter;
tableLayoutPanelBottom.MouseLeave -= ControlsMouseLeave;
labelItems.MouseEnter -= ControlsMouseEnter;
labelItems.MouseLeave -= ControlsMouseLeave;
base.Dispose(disposing);
}

View file

@ -32,144 +32,41 @@ namespace SystemTrayMenu.UserInterface
internal Menu()
{
fading.ChangeOpacity += Fading_ChangeOpacity;
void Fading_ChangeOpacity(object sender, double newOpacity)
{
if (newOpacity != Opacity && !IsDisposed && !Disposing)
{
Opacity = newOpacity;
}
}
fading.Show += Fading_Show;
void Fading_Show()
{
try
{
isShowing = true;
Visible = true;
isShowing = false;
timerUpdateIcons.Start();
}
catch (ObjectDisposedException)
{
Visible = false;
isShowing = false;
Log.Info($"Could not open menu, old menu was disposing," +
$" IsDisposed={IsDisposed}");
}
if (Visible)
{
if (Level == 0)
{
Activate();
NativeMethods.User32ShowInactiveTopmost(this);
NativeMethods.ForceForegroundWindow(Handle);
}
else
{
NativeMethods.User32ShowInactiveTopmost(this);
}
}
}
fading.Hide += Hide;
InitializeComponent();
SetDoubleBuffer(dgv, true);
Color foreColor = Color.Black;
Color backColor = AppColors.Background;
Color backColorSearch = AppColors.SearchField;
Color backgroundBorder = AppColors.BackgroundBorder;
if (Config.IsDarkMode())
{
foreColor = Color.White;
labelTitle.ForeColor = foreColor;
textBoxSearch.ForeColor = foreColor;
backColor = AppColors.DarkModeBackground;
backColorSearch = AppColors.DarkModeSearchField;
backgroundBorder = AppColors.DarkModeBackgroundBorder;
}
ColorConverter colorConverter = new();
labelItems.ForeColor = MenuDefines.ColorIcons;
if (backColor.R == 0)
{
backColor = Color.White;
}
BackColor = backgroundBorder;
labelTitle.BackColor = backColor;
tableLayoutPanelDgvAndScrollbar.BackColor = backColor;
tableLayoutPanelBottom.BackColor = backColor;
tableLayoutPanelMenu.BackColor = backColor;
dgv.BackgroundColor = backColor;
textBoxSearch.BackColor = backColorSearch;
panelLine.BackColor = AppColors.Icons;
pictureBoxSearch.BackColor = backColorSearch;
tableLayoutPanelSearch.BackColor = backColorSearch;
dgv.DefaultCellStyle = new DataGridViewCellStyle
{
SelectionForeColor = foreColor,
ForeColor = foreColor,
BackColor = backColor,
};
dgv.GotFocus += (sender, e) => FocusTextBox();
customScrollbar.GotFocus += (sender, e) => FocusTextBox();
customScrollbar.Margin = new Padding(0);
customScrollbar.Scroll += CustomScrollbar_Scroll;
void CustomScrollbar_Scroll(object sender, EventArgs e)
{
decimal firstIndex = customScrollbar.Value * dgv.Rows.Count / (decimal)customScrollbar.Maximum;
int firstIndexRounded = (int)Math.Ceiling(firstIndex);
if (firstIndexRounded > -1 && firstIndexRounded < dgv.RowCount)
{
dgv.FirstDisplayedScrollingRowIndex = firstIndexRounded;
}
}
customScrollbar.MouseEnter += ControlsMouseEnter;
AdjustColors();
dgv.GotFocus += Dgv_GotFocus;
dgv.MouseEnter += ControlsMouseEnter;
labelTitle.MouseEnter += ControlsMouseEnter;
textBoxSearch.MouseEnter += ControlsMouseEnter;
pictureBoxOpenFolder.MouseEnter += ControlsMouseEnter;
pictureBoxMenuAlwaysOpen.MouseEnter += ControlsMouseEnter;
pictureBoxSettings.MouseEnter += ControlsMouseEnter;
pictureBoxRestart.MouseEnter += ControlsMouseEnter;
pictureBoxSearch.MouseEnter += ControlsMouseEnter;
tableLayoutPanelMenu.MouseEnter += ControlsMouseEnter;
tableLayoutPanelDgvAndScrollbar.MouseEnter += ControlsMouseEnter;
tableLayoutPanelBottom.MouseEnter += ControlsMouseEnter;
labelItems.MouseEnter += ControlsMouseEnter;
void ControlsMouseEnter(object sender, EventArgs e)
{
MouseEnter?.Invoke();
}
customScrollbar.MouseLeave += ControlsMouseLeave;
dgv.MouseLeave += ControlsMouseLeave;
customScrollbar.Margin = new Padding(0);
customScrollbar.GotFocus += CustomScrollbar_GotFocus;
customScrollbar.Scroll += CustomScrollbar_Scroll;
customScrollbar.MouseEnter += ControlsMouseEnter;
customScrollbar.MouseLeave += ControlsMouseLeave;
labelTitle.MouseEnter += ControlsMouseEnter;
labelTitle.MouseLeave += ControlsMouseLeave;
textBoxSearch.MouseEnter += ControlsMouseEnter;
textBoxSearch.MouseLeave += ControlsMouseLeave;
pictureBoxMenuAlwaysOpen.MouseLeave += ControlsMouseLeave;
pictureBoxOpenFolder.MouseEnter += ControlsMouseEnter;
pictureBoxOpenFolder.MouseLeave += ControlsMouseLeave;
pictureBoxMenuAlwaysOpen.MouseEnter += ControlsMouseEnter;
pictureBoxMenuAlwaysOpen.MouseLeave += ControlsMouseLeave;
pictureBoxSettings.MouseEnter += ControlsMouseEnter;
pictureBoxSettings.MouseLeave += ControlsMouseLeave;
pictureBoxRestart.MouseEnter += ControlsMouseEnter;
pictureBoxRestart.MouseLeave += ControlsMouseLeave;
pictureBoxSearch.MouseEnter += ControlsMouseEnter;
pictureBoxSearch.MouseLeave += ControlsMouseLeave;
tableLayoutPanelMenu.MouseEnter += ControlsMouseEnter;
tableLayoutPanelMenu.MouseLeave += ControlsMouseLeave;
tableLayoutPanelDgvAndScrollbar.MouseEnter += ControlsMouseEnter;
tableLayoutPanelDgvAndScrollbar.MouseLeave += ControlsMouseLeave;
tableLayoutPanelBottom.MouseEnter += ControlsMouseEnter;
tableLayoutPanelBottom.MouseLeave += ControlsMouseLeave;
labelItems.MouseEnter += ControlsMouseEnter;
labelItems.MouseLeave += ControlsMouseLeave;
void ControlsMouseLeave(object sender, EventArgs e)
{
MouseLeave?.Invoke();
}
bool isTouchEnabled = NativeMethods.IsTouchEnabled();
if ((isTouchEnabled && Properties.Settings.Default.DragDropItemsEnabledTouch) ||
(!isTouchEnabled && Properties.Settings.Default.DragDropItemsEnabled))
@ -180,23 +77,23 @@ namespace SystemTrayMenu.UserInterface
}
}
internal new event EventHandlerEmpty MouseWheel;
internal new event Action MouseWheel;
internal new event EventHandlerEmpty MouseEnter;
internal new event Action MouseEnter;
internal new event EventHandlerEmpty MouseLeave;
internal new event Action MouseLeave;
internal event EventHandlerEmpty UserClickedOpenFolder;
internal event Action<string> UserClickedOpenFolder;
internal event EventHandler<Keys> CmdKeyProcessed;
internal event EventHandler<KeyPressEventArgs> KeyPressCheck;
internal event EventHandlerEmpty SearchTextChanging;
internal event Action SearchTextChanging;
internal event EventHandler<bool> SearchTextChanged;
internal event EventHandlerEmpty UserDragsMenu;
internal event Action UserDragsMenu;
internal enum MenuType
{
@ -218,6 +115,8 @@ namespace SystemTrayMenu.UserInterface
internal int Level { get; set; }
internal string Path { get; set; }
internal bool IsUsable => Visible && !fading.IsHiding && !IsDisposed && !Disposing;
internal bool ScrollbarVisible { get; private set; }
@ -324,7 +223,7 @@ namespace SystemTrayMenu.UserInterface
pictureBoxMenuAlwaysOpen.Paint -= PictureBoxMenuAlwaysOpen_Paint;
pictureBoxMenuAlwaysOpen.Paint += LoadingMenu_Paint;
timerUpdateIcons.Tick -= TimerUpdateIcons_Tick;
timerUpdateIcons.Tick += (sender, e) => pictureBoxMenuAlwaysOpen.Invalidate();
timerUpdateIcons.Tick += TimerUpdateIcons_Tick_Loading;
timerUpdateIcons.Interval = 15;
break;
default:
@ -718,6 +617,117 @@ namespace SystemTrayMenu.UserInterface
CultureInfo.InvariantCulture);
}
private void Fading_ChangeOpacity(double newOpacity)
{
if (newOpacity != Opacity && !IsDisposed && !Disposing)
{
Opacity = newOpacity;
}
}
private void Fading_Show()
{
try
{
isShowing = true;
Visible = true;
isShowing = false;
timerUpdateIcons.Start();
}
catch (ObjectDisposedException)
{
Visible = false;
isShowing = false;
Log.Info($"Could not open menu, old menu was disposing," +
$" IsDisposed={IsDisposed}");
}
if (Visible)
{
if (Level == 0)
{
Activate();
NativeMethods.User32ShowInactiveTopmost(this);
NativeMethods.ForceForegroundWindow(Handle);
}
else
{
NativeMethods.User32ShowInactiveTopmost(this);
}
}
}
private void AdjustColors()
{
Color foreColor = Color.Black;
Color backColor = AppColors.Background;
Color backColorSearch = AppColors.SearchField;
Color backgroundBorder = AppColors.BackgroundBorder;
if (Config.IsDarkMode())
{
foreColor = Color.White;
labelTitle.ForeColor = foreColor;
textBoxSearch.ForeColor = foreColor;
backColor = AppColors.DarkModeBackground;
backColorSearch = AppColors.DarkModeSearchField;
backgroundBorder = AppColors.DarkModeBackgroundBorder;
}
ColorConverter colorConverter = new();
labelItems.ForeColor = MenuDefines.ColorIcons;
if (backColor.R == 0)
{
backColor = Color.White;
}
BackColor = backgroundBorder;
labelTitle.BackColor = backColor;
tableLayoutPanelDgvAndScrollbar.BackColor = backColor;
tableLayoutPanelBottom.BackColor = backColor;
tableLayoutPanelMenu.BackColor = backColor;
dgv.BackgroundColor = backColor;
textBoxSearch.BackColor = backColorSearch;
panelLine.BackColor = AppColors.Icons;
pictureBoxSearch.BackColor = backColorSearch;
tableLayoutPanelSearch.BackColor = backColorSearch;
dgv.DefaultCellStyle = new DataGridViewCellStyle
{
SelectionForeColor = foreColor,
ForeColor = foreColor,
BackColor = backColor,
};
}
private void Dgv_GotFocus(object sender, EventArgs e)
{
FocusTextBox();
}
private void CustomScrollbar_GotFocus(object sender, EventArgs e)
{
FocusTextBox();
}
private void CustomScrollbar_Scroll(object sender, EventArgs e)
{
decimal firstIndex = customScrollbar.Value * dgv.Rows.Count / (decimal)customScrollbar.Maximum;
int firstIndexRounded = (int)Math.Ceiling(firstIndex);
if (firstIndexRounded > -1 && firstIndexRounded < dgv.RowCount)
{
dgv.FirstDisplayedScrollingRowIndex = firstIndexRounded;
}
}
private void ControlsMouseEnter(object sender, EventArgs e)
{
MouseEnter?.Invoke();
}
private void ControlsMouseLeave(object sender, EventArgs e)
{
MouseLeave?.Invoke();
}
private void AdjustDataGridViewHeight(Menu menuPredecessor, int screenHeightMax)
{
double factor = Properties.Settings.Default.RowHeighteInPercentage / 100f;
@ -753,12 +763,12 @@ namespace SystemTrayMenu.UserInterface
row.Height = dgv.RowTemplate.Height;
}
int dgvHeightByItems = dgv.Rows.GetRowsHeight(DataGridViewElementStates.None);
int dgvHeightByItems = Math.Max(dgv.Rows.GetRowsHeight(DataGridViewElementStates.None), 1);
int dgvHeightMaxByScreen = screenHeightMax - (Height - dgv.Height);
int dgvHeightMaxByOptions = (int)(Scaling.Factor * Scaling.FactorByDpi *
450f * (Properties.Settings.Default.HeightMaxInPercent / 100f));
int dgvHeightMax = Math.Min(dgvHeightMaxByScreen, dgvHeightMaxByOptions);
if (!dgvHeightSet && dgvHeightByItems > 0 && dgvHeightMax > 0)
if (!dgvHeightSet)
{
dgv.Height = Math.Min(dgvHeightByItems, dgvHeightMax);
dgvHeightSet = true;
@ -1035,7 +1045,7 @@ namespace SystemTrayMenu.UserInterface
{
if (e.Button == MouseButtons.Left)
{
UserClickedOpenFolder?.Invoke();
UserClickedOpenFolder?.Invoke(Path);
}
}
@ -1145,6 +1155,11 @@ namespace SystemTrayMenu.UserInterface
}
}
private void TimerUpdateIcons_Tick_Loading(object sender, EventArgs e)
{
pictureBoxMenuAlwaysOpen.Invalidate();
}
private void Menu_MouseDown(object sender, MouseEventArgs e)
{
if (Level == 0)

View file

@ -4,6 +4,7 @@
namespace SystemTrayMenu.Utilities
{
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
@ -11,7 +12,7 @@ namespace SystemTrayMenu.Utilities
internal class AppRestart
{
public static event EventHandlerEmpty BeforeRestarting;
public static event Action BeforeRestarting;
internal static void ByThreadException()
{

View file

@ -1,8 +0,0 @@
// <copyright file="EventHandlerEmpty.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Utilities
{
public delegate void EventHandlerEmpty();
}