Compare commits

..

No commits in common. "master" and "0.10.1.1" have entirely different histories.

282 changed files with 12048 additions and 66459 deletions

View file

@ -1,79 +0,0 @@
[*.cs]
# WFAC010: Unsupported high DPI configuration
dotnet_diagnostic.WFAC010.severity = silent
csharp_indent_labels = one_less_than_current
csharp_using_directive_placement = outside_namespace:silent
csharp_prefer_simple_using_statement = true:suggestion
csharp_prefer_braces = true:silent
csharp_style_namespace_declarations = block_scoped:silent
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
dotnet_diagnostic.SX1101.severity = warning
dotnet_diagnostic.SA1101.severity = silent
[*.{cs,vb}]
#### Naming styles ####
# Naming rules
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
# Symbol specifications
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
# Naming styles
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_style_operator_placement_when_wrapping = beginning_of_line
tab_width = 4
indent_size = 4
end_of_line = crlf
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion

12
.github/FUNDING.yml vendored
View file

@ -1,12 +0,0 @@
# These are supported funding model platforms
github: Hofknecht # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View file

@ -7,10 +7,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Setup Nuget.exe
uses: nuget/setup-nuget@v1
uses: warrenbuckley/Setup-Nuget@v1
- name: Nuget Restore
run: nuget restore SystemTrayMenu.sln
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1
uses: warrenbuckley/Setup-MSBuild@v1
- name: Build with MSBuild
run: msbuild SystemTrayMenu.sln -p:Configuration=Release

View file

@ -1,114 +1,46 @@
// <copyright file="App.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using Microsoft.Win32;
using System;
using System.Windows.Forms;
using SystemTrayMenu.Business;
using SystemTrayMenu.DataClasses;
using SystemTrayMenu.Helper;
using SystemTrayMenu.UserInterface;
using SystemTrayMenu.Utilities;
namespace SystemTrayMenu
{
using System;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;
using SystemTrayMenu.Business;
using SystemTrayMenu.Helper.Updater;
using SystemTrayMenu.UserInterface;
using SystemTrayMenu.Utilities;
/// <summary>
/// App contains the notifyicon, the taskbarform and the menus.
/// </summary>
internal class App : IDisposable
{
private readonly AppNotifyIcon menuNotifyIcon = new();
private readonly Menus menus = new();
private readonly TaskbarForm taskbarForm = null;
private readonly MenuNotifyIcon menuNotifyIcon = new MenuNotifyIcon();
private readonly Menus menus = new Menus();
public App()
{
Screen screen = Screen.PrimaryScreen;
Statics.ScreenHeight = screen.Bounds.Height;
Statics.ScreenWidth = screen.Bounds.Width;
Statics.ScreenRight = screen.Bounds.Right;
Statics.TaskbarHeight = new WindowsTaskbar().Size.Height;
AppRestart.BeforeRestarting += Dispose;
SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
SystemEvents.DisplaySettingsChanged += AppRestart.ByDisplaySettings;
menus.LoadStarted += menuNotifyIcon.LoadingStart;
menus.LoadStopped += menuNotifyIcon.LoadingStop;
menuNotifyIcon.Exit += Application.Exit;
menuNotifyIcon.Restart += AppRestart.ByMenuNotifyIcon;
menuNotifyIcon.Click += MenuNotifyIcon_Click;
void MenuNotifyIcon_Click()
{
menus.SwitchOpenClose(true);
}
menuNotifyIcon.OpenLog += Log.OpenLogFile;
menus.MainPreload();
if (Properties.Settings.Default.ShowInTaskbar)
{
taskbarForm = new TaskbarForm();
taskbarForm.FormClosed += TaskbarForm_FormClosed;
taskbarForm.Deactivate += SetStateNormal;
taskbarForm.Resize += SetStateNormal;
taskbarForm.Activated += TasbkarItemActivated;
}
DllImports.NativeMethods.User32ShowInactiveTopmost(taskbarForm);
if (Properties.Settings.Default.CheckForUpdates)
{
new Thread((obj) => GitHubUpdate.ActivateNewVersionFormOrCheckForUpdates(
showWhenUpToDate: false))
.Start();
}
}
public void Dispose()
{
if (taskbarForm?.InvokeRequired == true)
{
taskbarForm.Invoke(Dispose);
}
else
{
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(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(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();
menus.Dispose();
menuNotifyIcon.Dispose();
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,269 +0,0 @@
// <copyright file="MenusHelpers.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Business
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using SystemTrayMenu.DataClasses;
using SystemTrayMenu.Helper;
using SystemTrayMenu.Utilities;
internal static class MenusHelpers
{
internal static void GetItemsForMainMenu(BackgroundWorker worker, string path, ref MenuData menuData)
{
menuData.IsNetworkRoot = FileLnk.IsNetworkRoot(path);
if (menuData.IsNetworkRoot)
{
GetNetworkRootDirectories(path, ref menuData);
}
else
{
GetDirectories(worker, path, ref menuData);
GetFiles(worker, path, ref menuData);
}
}
internal static void GetAddionalItemsForMainMenu(ref MenuData menuData)
{
if (menuData.Level != 0)
{
return;
}
foreach (var path in GetAddionalPathsForMainMenu())
{
GetDirectoriesAndFilesRecursive(ref menuData, path.Path, path.OnlyFiles, path.Recursive);
}
}
internal static IEnumerable<(string Path, bool Recursive, bool OnlyFiles)> GetAddionalPathsForMainMenu()
{
foreach (string pathAndRecursivString in Properties.Settings.Default.PathsAddToMainMenu.Split(@"|"))
{
if (string.IsNullOrEmpty(pathAndRecursivString))
{
continue;
}
string pathAddForMainMenu = pathAndRecursivString.Split("recursiv:")[0].Trim();
bool recursive = pathAndRecursivString.Split("recursiv:")[1].StartsWith("True");
bool onlyFiles = pathAndRecursivString.Split("onlyFiles:")[1].StartsWith("True");
yield return (Path: pathAddForMainMenu, Recursive: recursive, OnlyFiles: onlyFiles);
}
}
internal static void ReadHiddenAndReadIcons(BackgroundWorker worker, ref MenuData menuData)
{
List<RowData> rowDatasToRemove = new();
foreach (RowData rowData in menuData.RowDatas)
{
if (worker?.CancellationPending == true)
{
return;
}
if (!menuData.IsNetworkRoot && FolderOptions.IsHidden(rowData))
{
rowDatasToRemove.Add(rowData);
continue;
}
rowData.ReadIcon(true);
}
menuData.RowDatas = menuData.RowDatas.Except(rowDatasToRemove).ToList();
}
internal static void CheckIfValid(ref MenuData menuData)
{
if (menuData.Validity == MenuDataValidity.Undefined)
{
if (menuData.RowDatas.Count == 0)
{
menuData.Validity = MenuDataValidity.Empty;
}
else
{
menuData.Validity = MenuDataValidity.Valid;
}
}
}
internal static void SortItemsWhenValid(ref MenuData menuData)
{
if (menuData.Validity != MenuDataValidity.Valid)
{
return;
}
menuData.RowDatas = SortItems(menuData.RowDatas);
}
internal static List<RowData> SortItems(List<RowData> rowDatas)
{
if (Properties.Settings.Default.SortByTypeAndNameWindowsExplorerSort)
{
rowDatas = rowDatas.OrderByDescending(x => x.IsFolder)
.ThenBy(x => x.Text, new WindowsExplorerSort()).ToList();
}
else if (Properties.Settings.Default.SortByTypeAndDate)
{
rowDatas = rowDatas.OrderByDescending(x => x.IsFolder)
.ThenByDescending(x => x.FileInfo.LastWriteTime).ToList();
}
else if (Properties.Settings.Default.SortByFileExtensionAndName)
{
rowDatas = rowDatas.OrderBy(x => x.FileExtension).ThenBy(x => x.Text).ToList();
}
else if (Properties.Settings.Default.SortByName)
{
rowDatas = rowDatas.OrderBy(x => x.Text).ToList();
}
else if (Properties.Settings.Default.SortByDate)
{
rowDatas = rowDatas.OrderByDescending(x => x.FileInfo.LastWriteTime).ToList();
}
return rowDatas;
}
private static void GetNetworkRootDirectories(string path, ref MenuData menuData)
{
Process cmd = new();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
try
{
bool resolvedSomething = false;
cmd.Start();
cmd.StandardInput.WriteLine($"net view {path}");
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
string output = cmd.StandardOutput.ReadToEnd();
cmd.WaitForExit();
cmd.Close();
List<string> lines = output
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList();
if (lines.Count > 8)
{
foreach (string line in lines.Skip(6).SkipLast(2))
{
int indexOfFirstSpace = line.IndexOf(" ", StringComparison.InvariantCulture);
if (indexOfFirstSpace > 0)
{
string directory = Path.Combine(path, line[..indexOfFirstSpace]);
menuData.RowDatas.Add(new RowData(true, false, true, menuData.Level, directory));
resolvedSomething = true;
}
}
}
if (!resolvedSomething)
{
Log.Info($"Could not resolve network root folder: {path} , output:{output}");
}
}
catch (Exception ex)
{
Log.Warn($"path:'{path}'", ex);
if (ex is UnauthorizedAccessException)
{
menuData.Validity = MenuDataValidity.NoAccess;
}
}
}
private static void GetDirectories(BackgroundWorker worker, string path, ref MenuData menuData)
{
try
{
foreach (var directory in Directory.GetDirectories(path))
{
if (worker?.CancellationPending == true)
{
return;
}
menuData.RowDatas.Add(new RowData(true, false, false, menuData.Level, directory));
}
}
catch (Exception ex)
{
Log.Warn($"path:'{path}'", ex);
if (ex is UnauthorizedAccessException)
{
menuData.Validity = MenuDataValidity.NoAccess;
}
}
}
private static void GetFiles(BackgroundWorker worker, string path, ref MenuData menuData)
{
try
{
foreach (string file in DirectoryBySearchPattern.GetFiles(path, Config.SearchPattern))
{
if (worker?.CancellationPending == true)
{
return;
}
menuData.RowDatas.Add(new RowData(false, false, false, menuData.Level, file));
}
}
catch (Exception ex)
{
Log.Warn($"path:'{path}'", ex);
if (ex is UnauthorizedAccessException)
{
menuData.Validity = MenuDataValidity.NoAccess;
}
}
}
private static void GetDirectoriesAndFilesRecursive(
ref MenuData menuData,
string path,
bool onlyFiles,
bool recursiv)
{
try
{
foreach (string file in DirectoryBySearchPattern.GetFiles(path, Config.SearchPattern))
{
menuData.RowDatas.Add(new RowData(false, true, false, menuData.Level, file));
}
foreach (string directory in Directory.GetDirectories(path))
{
if (!onlyFiles)
{
menuData.RowDatas.Add(new RowData(true, true, false, menuData.Level, directory));
}
if (recursiv)
{
GetDirectoriesAndFilesRecursive(ref menuData, directory, onlyFiles, recursiv);
}
}
}
catch (Exception ex)
{
Log.Warn($"GetDirectoriesAndFilesRecursive path:'{path}'", ex);
}
}
}
}

View file

@ -1,50 +1,46 @@
// <copyright file="Program.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using SystemTrayMenu.Utilities;
namespace SystemTrayMenu
{
using System;
using System.Reflection;
using System.Windows.Forms;
using SystemTrayMenu.Utilities;
internal static class Program
{
private static bool isStartup = true;
[STAThread]
private static void Main(string[] args)
private static void Main()
{
try
{
Log.Initialize();
SingleAppInstance.Initialize();
Translator.Initialize();
Config.SetFolderByWindowsContextMenu(args);
Config.LoadOrSetByUser();
Config.Initialize();
PrivilegeChecker.Initialize();
if (SingleAppInstance.Initialize())
Config.UpgradeIfNotUpgraded();
if (Config.LoadOrSetByUser())
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += Application_ThreadException;
Application.ThreadException += ThreadException;
void ThreadException(object s, ThreadExceptionEventArgs t)
{
AskUserSendError(t.Exception);
}
Scaling.Initialize();
FolderOptions.Initialize();
using (new App())
{
isStartup = false;
Log.WriteApplicationRuns();
Application.Run();
}
}
Application.ThreadException -= Application_ThreadException;
Config.Dispose();
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception ex)
#pragma warning restore CA1031 // => Represents ThreadException during attached to process
{
AskUserSendError(ex);
}
@ -52,36 +48,22 @@ namespace SystemTrayMenu
{
Log.Close();
}
}
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)
void AskUserSendError(Exception ex)
{
Log.ProcessStart("mailto:" + "markus@hofknecht.eu" +
"?subject=SystemTrayMenu Bug reported " +
Assembly.GetEntryAssembly().GetName().Version +
"&body=" + ex.ToString());
}
Log.Error("Application Crashed", ex);
#warning [Feature] When Error ask user to send us #47, todo own dialog, lines here too long
if (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.",
"SystemTrayMenu BugSplat", MessageBoxButtons.YesNo) == 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();
}
}

View file

@ -1,16 +1,16 @@
// <copyright file="WaitLeave.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using SystemTrayMenu.Utilities;
using Timer = System.Windows.Forms.Timer;
namespace SystemTrayMenu.Handler
{
using System;
using SystemTrayMenu.Utilities;
using Timer = System.Windows.Forms.Timer;
internal class WaitLeave : IDisposable
{
private readonly Timer timerLeaveCheck = new();
public event EventHandlerEmpty LeaveTriggered;
private readonly Timer timerLeaveCheck = new Timer();
public bool IsRunning => timerLeaveCheck.Enabled;
public WaitLeave(int timeUntilTriggered)
{
@ -18,29 +18,26 @@ namespace SystemTrayMenu.Handler
timerLeaveCheck.Tick += TimerLeaveCheckTick;
}
public event Action LeaveTriggered;
public void Dispose()
{
timerLeaveCheck.Tick -= TimerLeaveCheckTick;
timerLeaveCheck.Dispose();
}
internal void Start()
public void Start()
{
timerLeaveCheck.Stop();
timerLeaveCheck.Start();
}
internal void Stop()
public void Stop()
{
timerLeaveCheck.Stop();
}
internal void TimerLeaveCheckTick(object sender, EventArgs e)
private void TimerLeaveCheckTick(object sender, EventArgs e)
{
timerLeaveCheck.Stop();
LeaveTriggered?.Invoke();
LeaveTriggered.Invoke();
}
public void Dispose()
{
timerLeaveCheck.Dispose();
}
}
}

76
Business/WaitMenuOpen.cs Normal file
View file

@ -0,0 +1,76 @@
using System;
using SystemTrayMenu.Utilities;
using Timer = System.Windows.Forms.Timer;
namespace SystemTrayMenu.Handler
{
internal class WaitMenuOpen : IDisposable
{
public event EventHandlerEmpty DoOpen;
private readonly Timer waitOpen = new Timer();
private bool waitedDone = false;
private bool clicked = false;
private bool menuLoaded = false;
public WaitMenuOpen()
{
waitOpen.Interval = MenuDefines.WaitMenuOpen;
waitOpen.Tick += WaitOpen_Tick;
}
private void WaitOpen_Tick(object sender, EventArgs e)
{
waitOpen.Stop();
waitedDone = true;
CheckConditionsToOpenMenu();
}
private void CheckConditionsToOpenMenu()
{
if ((waitedDone || clicked) &&
menuLoaded)
{
Stop();
DoOpen?.Invoke();
}
}
// When mouse on menu, wait x ms until open it
// meanwhile load content, click opens when loaded
// (to not interrupt user when he moves into a submenu)
public void Start()
{
if (!waitedDone)
{
waitOpen.Start();
}
}
public void Stop()
{
clicked = false;
waitedDone = false;
menuLoaded = false;
waitOpen.Stop();
}
public void Click()
{
clicked = true;
CheckConditionsToOpenMenu();
}
public void MenuLoaded()
{
menuLoaded = true;
CheckConditionsToOpenMenu();
}
public void Dispose()
{
Stop();
waitOpen.Dispose();
}
}
}

View file

@ -1,220 +0,0 @@
// <copyright file="WaitToLoadMenu.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Handler
{
using System;
using System.Windows.Forms;
using SystemTrayMenu.DataClasses;
using SystemTrayMenu.UserInterface;
using SystemTrayMenu.Utilities;
using Timer = System.Windows.Forms.Timer;
internal class WaitToLoadMenu : IDisposable
{
private readonly Timer timerStartLoad = new();
private DataGridView dgv;
private int rowIndex;
private DataGridView dgvTmp;
private int rowIndexTmp;
private int mouseMoveEvents;
private DateTime dateTimeLastMouseMoveEvent = DateTime.Now;
private bool checkForMouseActive = true;
internal WaitToLoadMenu()
{
timerStartLoad.Interval = Properties.Settings.Default.TimeUntilOpens;
timerStartLoad.Tick += WaitStartLoad_Tick;
}
internal event Action<RowData> StartLoadMenu;
internal event Action<int> CloseMenu;
internal event Action StopLoadMenu;
internal event Action<DataGridView, int> MouseEnterOk;
internal bool MouseActive { get; set; }
public void Dispose()
{
timerStartLoad.Tick -= WaitStartLoad_Tick;
timerStartLoad.Stop();
timerStartLoad.Dispose();
dgv?.Dispose();
dgvTmp?.Dispose();
}
internal void MouseEnter(object sender, DataGridViewCellEventArgs e)
{
if (MouseActive)
{
DataGridView dgv = (DataGridView)sender;
if (dgv.Rows.Count > e.RowIndex)
{
MouseEnterOk(dgv, e.RowIndex);
timerStartLoad.Stop();
StopLoadMenu?.Invoke();
checkForMouseActive = true;
SetData(dgv, e.RowIndex);
timerStartLoad.Start();
}
}
else
{
dgvTmp = (DataGridView)sender;
rowIndexTmp = e.RowIndex;
}
}
internal void RowSelected(DataGridView dgv, int rowIndex)
{
if (dgv.Rows.Count > rowIndex)
{
timerStartLoad.Stop();
StopLoadMenu?.Invoke();
SetData(dgv, rowIndex);
MouseActive = false;
checkForMouseActive = false;
timerStartLoad.Start();
}
}
internal void MouseLeave(object sender, DataGridViewCellEventArgs e)
{
if (MouseActive)
{
timerStartLoad.Stop();
StopLoadMenu?.Invoke();
ResetData((DataGridView)sender, e.RowIndex);
}
}
internal void RowDeselected(DataGridView dgv, int rowIndex)
{
timerStartLoad.Stop();
StopLoadMenu?.Invoke();
ResetData(dgv, rowIndex);
MouseActive = false;
}
internal void ClickOpensInstantly(DataGridView dgv, int rowIndex)
{
if (dgv.Rows.Count > rowIndex)
{
timerStartLoad.Stop();
SetData(dgv, rowIndex);
MouseActive = true;
checkForMouseActive = false;
CallOpenMenuNow();
}
}
internal void EnterOpensInstantly(DataGridView dgv, int rowIndex)
{
if (dgv.Rows.Count > rowIndex)
{
timerStartLoad.Stop();
StopLoadMenu?.Invoke();
SetData(dgv, rowIndex);
MouseActive = false;
checkForMouseActive = false;
CallOpenMenuNow();
}
}
internal void MouseMove(object sender, MouseEventArgs e)
{
if (!MouseActive)
{
if (mouseMoveEvents > 6)
{
MouseActive = true;
if (dgvTmp != null && !dgvTmp.IsDisposed)
{
MouseEnter(dgvTmp, new DataGridViewCellEventArgs(
0, rowIndexTmp));
}
mouseMoveEvents = 0;
}
else if (DateTime.Now - dateTimeLastMouseMoveEvent <
new TimeSpan(0, 0, 0, 0, 200))
{
mouseMoveEvents++;
}
else
{
dateTimeLastMouseMoveEvent = DateTime.Now;
mouseMoveEvents = 0;
}
}
}
private void WaitStartLoad_Tick(object sender, EventArgs e)
{
timerStartLoad.Stop();
if (!checkForMouseActive || MouseActive)
{
CallOpenMenuNow();
}
}
private void CallOpenMenuNow()
{
if (dgv.Rows.Count > rowIndex)
{
RowData rowData = (RowData)dgv.Rows[rowIndex].Cells[2].Value;
Menu menu = (Menu)dgv.FindForm();
rowData.Level = menu.Level;
if (rowData.ContainsMenu)
{
CloseMenu.Invoke(rowData.Level + 2);
}
CloseMenu.Invoke(rowData.Level + 1);
if (!rowData.IsContextMenuOpen &&
rowData.ContainsMenu &&
rowData.Level + 1 < MenuDefines.MenusMax)
{
StartLoadMenu.Invoke(rowData);
}
}
}
private void SetData(DataGridView dgv, int rowIndex)
{
dgvTmp = null;
this.dgv = dgv;
this.rowIndex = rowIndex;
RowData rowData = (RowData)dgv.Rows[rowIndex].Cells[2].Value;
if (rowData != null)
{
rowData.IsSelected = true;
}
dgv.Rows[rowIndex].Selected = false;
dgv.Rows[rowIndex].Selected = true;
}
private void ResetData(DataGridView dgv, int rowIndex)
{
if (dgv != null && dgv.Rows.Count > rowIndex)
{
RowData rowData = (RowData)dgv.Rows[rowIndex].Cells[2].Value;
if (rowData != null)
{
rowData.IsSelected = false;
rowData.IsClicking = false;
dgv.Rows[rowIndex].Selected = false;
this.dgv = null;
this.rowIndex = 0;
}
}
}
}
}

View file

@ -1,95 +0,0 @@
// <copyright file="AppColors.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu
{
using System.Drawing;
internal static class AppColors
{
public static Color Arrow { get; internal set; }
public static Color ArrowHoverBackground { get; internal set; }
public static Color ArrowHover { get; internal set; }
public static Color ArrowClick { get; internal set; }
public static Color ArrowClickBackground { get; internal set; }
public static Color SliderArrowsAndTrackHover { get; internal set; }
public static Color Slider { get; internal set; }
public static Color SliderHover { get; internal set; }
public static Color SliderDragging { get; internal set; }
public static Color ScrollbarBackground { get; internal set; }
public static Color ArrowDarkMode { get; internal set; }
public static Color ArrowHoverBackgroundDarkMode { get; internal set; }
public static Color ArrowHoverDarkMode { get; internal set; }
public static Color ArrowClickDarkMode { get; internal set; }
public static Color ArrowClickBackgroundDarkMode { get; internal set; }
public static Color SliderArrowsAndTrackHoverDarkMode { get; internal set; }
public static Color SliderDarkMode { get; internal set; }
public static Color SliderHoverDarkMode { get; internal set; }
public static Color SliderDraggingDarkMode { get; internal set; }
public static Color ScrollbarBackgroundDarkMode { get; internal set; }
public static Color SelectedItem { get; set; }
public static Color DarkModeSelecetedItem { get; set; }
public static Color SelectedItemBorder { get; set; }
public static Color DarkModeSelectedItemBorder { get; set; }
public static Color OpenFolder { get; set; }
public static Color DarkModeOpenFolder { get; set; }
public static Color OpenFolderBorder { get; set; }
public static Color DarkModeOpenFolderBorder { get; set; }
public static Color Background { get; set; }
public static Color DarkModeBackground { get; set; }
public static Color BackgroundBorder { get; set; }
public static Color DarkModeBackgroundBorder { get; set; }
public static Color SearchField { get; set; }
public static Color DarkModeSearchField { get; set; }
public static Bitmap BitmapOpenFolder { get; set; }
public static Bitmap BitmapPin { get; set; }
public static Bitmap BitmapSettings { get; set; }
public static Bitmap BitmapRestart { get; set; }
public static Bitmap BitmapPinActive { get; set; }
public static Bitmap BitmapSearch { get; set; }
public static Color Icons { get; set; }
public static Color DarkModeIcons { get; set; }
}
}

View file

@ -1,15 +0,0 @@
// <copyright file="ColorAndCode.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu
{
using System.Drawing;
internal struct ColorAndCode
{
public Color Color { get; set; }
public string HtmlColorCode { get; set; }
}
}

View file

@ -1,529 +1,90 @@
// <copyright file="Config.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using Microsoft.WindowsAPICodePack.Dialogs;
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using SystemTrayMenu.Utilities;
namespace SystemTrayMenu
{
using System;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;
using Svg;
using SystemTrayMenu.Properties;
using SystemTrayMenu.UserInterface.FolderBrowseDialog;
using SystemTrayMenu.Utilities;
using static SystemTrayMenu.Utilities.IconReader;
public static class Config
{
private static readonly Icon SystemTrayMenu = new Icon(Properties.Resources.SystemTrayMenu, SystemInformation.SmallIconSize);
private static readonly Icon IconRootFolder = GetIconSTA(Path, Path, false, IconSize.Small, true);
public const string Language = "en";
private static bool readDarkModeDone;
private static bool isDarkMode;
private static bool readHideFileExtdone;
private static bool isHideFileExtension;
public static string Path => Properties.Settings.Default.PathDirectory;
public static string Path => Settings.Default.PathDirectory;
public static string SearchPattern => Settings.Default.SearchPattern;
public static bool ShowDirectoryTitleAtTop => Settings.Default.ShowDirectoryTitleAtTop;
public static bool ShowSearchBar => Settings.Default.ShowSearchBar;
public static bool ShowCountOfElementsBelow => Settings.Default.ShowCountOfElementsBelow;
public static bool ShowFunctionKeyOpenFolder => Settings.Default.ShowFunctionKeyOpenFolder;
public static bool ShowFunctionKeyPinMenu => Settings.Default.ShowFunctionKeyPinMenu;
public static bool ShowFunctionKeySettings => Settings.Default.ShowFunctionKeySettings;
public static bool ShowFunctionKeyRestart => Settings.Default.ShowFunctionKeyRestart;
public static bool AlwaysOpenByPin { get; internal set; }
public static void Initialize()
public static void UpgradeIfNotUpgraded()
{
UpgradeIfNotUpgraded();
InitializeColors();
if (string.IsNullOrEmpty(Settings.Default.PathIcoDirectory))
if (!Properties.Settings.Default.IsUpgraded)
{
Settings.Default.PathIcoDirectory = System.IO.Path.Combine(
System.IO.Path.Combine(
Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData), $"SystemTrayMenu"), "ico");
if (!Directory.Exists(Settings.Default.PathIcoDirectory))
{
Directory.CreateDirectory(Settings.Default.PathIcoDirectory);
}
// configs located at "%localappdata%\<AssemblyCompany>\"
Properties.Settings.Default.Upgrade();
Properties.Settings.Default.IsUpgraded = true;
Properties.Settings.Default.Save();
FileVersionInfo versionInfo = FileVersionInfo.
GetVersionInfo(Assembly.GetEntryAssembly().Location);
Log.Info($"Settings upgraded from " +
$"%localappdata%\\{versionInfo.CompanyName}\\");
}
}
public static void Dispose()
public static bool LoadOrSetByUser()
{
AppColors.BitmapOpenFolder.Dispose();
AppColors.BitmapPin.Dispose();
AppColors.BitmapPinActive.Dispose();
AppColors.BitmapSettings.Dispose();
AppColors.BitmapRestart.Dispose();
AppColors.BitmapSearch.Dispose();
}
bool pathOK = Directory.Exists(
Properties.Settings.Default.PathDirectory);
public static Icon GetAppIcon()
{
if (Settings.Default.UseIconFromRootFolder)
if (!pathOK)
{
return IconRootFolder;
}
else
{
return SystemTrayMenu;
}
}
public static void SetFolderByWindowsContextMenu(string[] args)
{
if (args != null && args.Length > 0 && args[0] != "-r")
{
string path = args[0];
Log.Info($"SetFolderByWindowsContextMenu() path: {path}");
Settings.Default.PathDirectory = path;
Settings.Default.Save();
}
}
public static void LoadOrSetByUser()
{
if (string.IsNullOrEmpty(Path))
{
string textFirstStart = Translator.GetText(
"Read the FAQ and then choose a root directory for SystemTrayMenu.");
MessageBox.Show(
textFirstStart,
"SystemTrayMenu",
string textFirstStart = Translator.GetText("TextFirstStart");
MessageBox.Show(textFirstStart, Translator.GetText("SystemTrayMenu"),
MessageBoxButtons.OK);
ShowHelpFAQ();
SetFolderByUser();
pathOK = SetFolderByUser();
}
return pathOK;
}
public static void SetFolderByUser(bool save = true)
public static bool SetFolderByUser(bool save = true)
{
using FolderDialog dialog = new();
dialog.InitialFolder = Path;
if (dialog.ShowDialog() == DialogResult.OK)
bool pathOK = false;
bool userAborted = false;
using (CommonOpenFileDialog dialog = new CommonOpenFileDialog())
{
Settings.Default.PathDirectory = dialog.Folder;
if (save)
dialog.InitialDirectory = Path;
dialog.IsFolderPicker = true;
do
{
Settings.Default.Save();
if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
{
if (Directory.Exists(dialog.FileName))
{
pathOK = true;
Properties.Settings.Default.PathDirectory =
dialog.FileName;
if (save)
{
Properties.Settings.Default.Save();
}
}
}
else
{
userAborted = true;
}
}
}
}
while (!pathOK && !userAborted);
};
public static void SetFolderIcoByUser()
{
using FolderDialog dialog = new();
dialog.InitialFolder = Settings.Default.PathIcoDirectory;
if (dialog.ShowDialog() == DialogResult.OK)
{
Settings.Default.PathIcoDirectory = dialog.Folder;
}
return pathOK;
}
internal static void ShowHelpFAQ()
{
Log.ProcessStart("https://github.com/Hofknecht/SystemTrayMenu#FAQ");
}
internal static void ShowSupportSystemTrayMenu()
{
Log.ProcessStart("https://github.com/Hofknecht/SystemTrayMenu#donations");
}
/// <summary>
/// Read the OS setting whether dark mode is enabled.
/// </summary>
/// <returns>true = Dark mode; false = Light mode.</returns>
internal static bool IsDarkMode()
{
if (!readDarkModeDone)
{
// 0 = Dark mode, 1 = Light mode
if (Settings.Default.IsDarkModeAlwaysOn ||
IsRegistryValueThisValue(
@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize",
"AppsUseLightTheme",
"0"))
{
isDarkMode = true;
}
readDarkModeDone = true;
}
return isDarkMode;
}
internal static void ResetReadDarkModeDone()
{
isDarkMode = false;
readDarkModeDone = false;
}
/// <summary>
/// Read the OS setting whether HideFileExt enabled.
/// </summary>
/// <returns>isHideFileExtension.</returns>
internal static bool IsHideFileExtension()
{
if (!readHideFileExtdone)
{
// 0 = To show extensions, 1 = To hide extensions
if (IsRegistryValueThisValue(
@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced",
"HideFileExt",
"1"))
{
isHideFileExtension = true;
}
readHideFileExtdone = true;
}
return isHideFileExtension;
}
internal static void InitializeColors(bool save = true)
{
ColorConverter converter = new();
ColorAndCode colorAndCode = default;
bool changed = false;
colorAndCode.HtmlColorCode = Settings.Default.ColorSelectedItem;
colorAndCode.Color = Color.FromArgb(204, 232, 255);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorSelectedItem = colorAndCode.HtmlColorCode;
AppColors.SelectedItem = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorDarkModeSelecetedItem;
colorAndCode.Color = Color.FromArgb(51, 51, 51);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorDarkModeSelecetedItem = colorAndCode.HtmlColorCode;
AppColors.DarkModeSelecetedItem = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorSelectedItemBorder;
colorAndCode.Color = Color.FromArgb(153, 209, 255);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorSelectedItemBorder = colorAndCode.HtmlColorCode;
AppColors.SelectedItemBorder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorDarkModeSelectedItemBorder;
colorAndCode.Color = Color.FromArgb(20, 29, 75);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorDarkModeSelectedItemBorder = colorAndCode.HtmlColorCode;
AppColors.DarkModeSelectedItemBorder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorOpenFolder;
colorAndCode.Color = Color.FromArgb(194, 245, 222);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorOpenFolder = colorAndCode.HtmlColorCode;
AppColors.OpenFolder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorDarkModeOpenFolder;
colorAndCode.Color = Color.FromArgb(20, 65, 42);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorDarkModeOpenFolder = colorAndCode.HtmlColorCode;
AppColors.DarkModeOpenFolder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorOpenFolderBorder;
colorAndCode.Color = Color.FromArgb(153, 255, 165);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorOpenFolderBorder = colorAndCode.HtmlColorCode;
AppColors.OpenFolderBorder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorDarkModeOpenFolderBorder;
colorAndCode.Color = Color.FromArgb(20, 75, 85);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorDarkModeOpenFolderBorder = colorAndCode.HtmlColorCode;
AppColors.DarkModeOpenFolderBorder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorIcons;
colorAndCode.Color = Color.FromArgb(149, 160, 166);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorIcons = colorAndCode.HtmlColorCode;
AppColors.Icons = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorDarkModeIcons;
colorAndCode.Color = Color.FromArgb(149, 160, 166);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorDarkModeIcons = colorAndCode.HtmlColorCode;
AppColors.DarkModeIcons = colorAndCode.Color;
string htmlColorCodeIcons;
if (IsDarkMode())
{
htmlColorCodeIcons = Settings.Default.ColorDarkModeIcons;
}
else
{
htmlColorCodeIcons = Settings.Default.ColorIcons;
}
AppColors.BitmapOpenFolder =
ReadSvg(Properties.Resources.ic_fluent_folder_arrow_right_48_regular, htmlColorCodeIcons);
AppColors.BitmapPin =
ReadSvg(Properties.Resources.ic_fluent_pin_48_regular, htmlColorCodeIcons);
AppColors.BitmapSettings =
ReadSvg(Properties.Resources.ic_fluent_settings_28_regular, htmlColorCodeIcons);
AppColors.BitmapRestart =
ReadSvg(Properties.Resources.ic_fluent_arrow_sync_24_regular, htmlColorCodeIcons);
AppColors.BitmapPinActive =
ReadSvg(Properties.Resources.ic_fluent_pin_48_filled, htmlColorCodeIcons);
AppColors.BitmapSearch =
ReadSvg(Properties.Resources.ic_fluent_search_48_regular, htmlColorCodeIcons);
colorAndCode.HtmlColorCode = Settings.Default.ColorSearchField;
colorAndCode.Color = Color.FromArgb(255, 255, 255);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorSearchField = colorAndCode.HtmlColorCode;
AppColors.SearchField = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorDarkModeSearchField;
colorAndCode.Color = Color.FromArgb(25, 25, 25);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorDarkModeSearchField = colorAndCode.HtmlColorCode;
AppColors.DarkModeSearchField = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorBackground;
colorAndCode.Color = Color.FromArgb(255, 255, 255);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorBackground = colorAndCode.HtmlColorCode;
AppColors.Background = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorDarkModeBackground;
colorAndCode.Color = Color.FromArgb(32, 32, 32);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorDarkModeBackground = colorAndCode.HtmlColorCode;
AppColors.DarkModeBackground = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorBackgroundBorder;
colorAndCode.Color = Color.FromArgb(0, 0, 0);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorBackgroundBorder = colorAndCode.HtmlColorCode;
AppColors.BackgroundBorder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorDarkModeBackgroundBorder;
colorAndCode.Color = Color.FromArgb(0, 0, 0);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorDarkModeBackgroundBorder = colorAndCode.HtmlColorCode;
AppColors.DarkModeBackgroundBorder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorArrow;
colorAndCode.Color = Color.FromArgb(96, 96, 96);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorArrow = colorAndCode.HtmlColorCode;
AppColors.Arrow = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorArrowHoverBackground;
colorAndCode.Color = Color.FromArgb(218, 218, 218);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorArrowHoverBackground = colorAndCode.HtmlColorCode;
AppColors.ArrowHoverBackground = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorArrowHover;
colorAndCode.Color = Color.FromArgb(0, 0, 0);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorArrowHover = colorAndCode.HtmlColorCode;
AppColors.ArrowHover = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorArrowClick;
colorAndCode.Color = Color.FromArgb(255, 255, 255);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorArrowClick = colorAndCode.HtmlColorCode;
AppColors.ArrowClick = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorArrowClickBackground;
colorAndCode.Color = Color.FromArgb(96, 96, 96);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorArrowClickBackground = colorAndCode.HtmlColorCode;
AppColors.ArrowClickBackground = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorSliderArrowsAndTrackHover;
colorAndCode.Color = Color.FromArgb(192, 192, 192);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorSliderArrowsAndTrackHover = colorAndCode.HtmlColorCode;
AppColors.SliderArrowsAndTrackHover = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorSlider;
colorAndCode.Color = Color.FromArgb(205, 205, 205);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorSlider = colorAndCode.HtmlColorCode;
AppColors.Slider = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorSliderHover;
colorAndCode.Color = Color.FromArgb(166, 166, 166);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorSliderHover = colorAndCode.HtmlColorCode;
AppColors.SliderHover = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorSliderDragging;
colorAndCode.Color = Color.FromArgb(96, 96, 96);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorSliderDragging = colorAndCode.HtmlColorCode;
AppColors.SliderDragging = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorScrollbarBackground;
colorAndCode.Color = Color.FromArgb(240, 240, 240);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorScrollbarBackground = colorAndCode.HtmlColorCode;
AppColors.ScrollbarBackground = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorArrowDarkMode;
colorAndCode.Color = Color.FromArgb(103, 103, 103);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorArrowDarkMode = colorAndCode.HtmlColorCode;
AppColors.ArrowDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorArrowHoverBackgroundDarkMode;
colorAndCode.Color = Color.FromArgb(55, 55, 55);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorArrowHoverBackgroundDarkMode = colorAndCode.HtmlColorCode;
AppColors.ArrowHoverBackgroundDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorArrowHoverDarkMode;
colorAndCode.Color = Color.FromArgb(103, 103, 103);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorArrowHoverDarkMode = colorAndCode.HtmlColorCode;
AppColors.ArrowHoverDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorArrowClickDarkMode;
colorAndCode.Color = Color.FromArgb(23, 23, 23);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorArrowClickDarkMode = colorAndCode.HtmlColorCode;
AppColors.ArrowClickDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorArrowClickBackgroundDarkMode;
colorAndCode.Color = Color.FromArgb(166, 166, 166);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorArrowClickBackgroundDarkMode = colorAndCode.HtmlColorCode;
AppColors.ArrowClickBackgroundDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorSliderArrowsAndTrackHoverDarkMode;
colorAndCode.Color = Color.FromArgb(77, 77, 77);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorSliderArrowsAndTrackHoverDarkMode = colorAndCode.HtmlColorCode;
AppColors.SliderArrowsAndTrackHoverDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorSliderDarkMode;
colorAndCode.Color = Color.FromArgb(77, 77, 77);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorSliderDarkMode = colorAndCode.HtmlColorCode;
AppColors.SliderDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorSliderHoverDarkMode;
colorAndCode.Color = Color.FromArgb(122, 122, 122);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorSliderHoverDarkMode = colorAndCode.HtmlColorCode;
AppColors.SliderHoverDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorSliderDraggingDarkMode;
colorAndCode.Color = Color.FromArgb(166, 166, 166);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorSliderDraggingDarkMode = colorAndCode.HtmlColorCode;
AppColors.SliderDraggingDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Settings.Default.ColorScrollbarBackgroundDarkMode;
colorAndCode.Color = Color.FromArgb(23, 23, 23);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Settings.Default.ColorScrollbarBackgroundDarkMode = colorAndCode.HtmlColorCode;
AppColors.ScrollbarBackgroundDarkMode = colorAndCode.Color;
if (save && changed)
{
Settings.Default.Save();
}
}
private static Bitmap ReadSvg(byte[] byteArray, string htmlColorCode)
{
string str = Encoding.UTF8.GetString(byteArray);
str = str.Replace("#585858", htmlColorCode);
byteArray = Encoding.UTF8.GetBytes(str);
using MemoryStream stream = new(byteArray);
SvgDocument svgDocument = SvgDocument.Open<SvgDocument>(stream);
svgDocument.Color = new SvgColourServer(Color.Black);
return svgDocument.Draw();
}
private static bool IsRegistryValueThisValue(string keyName, string valueName, string value)
{
bool isRegistryValueThisValue = false;
try
{
object registryHideFileExt = Registry.GetValue(keyName, valueName, 1);
if (registryHideFileExt == null)
{
Log.Info($"Could not read registry keyName:{keyName} valueName:{valueName}");
}
else if (registryHideFileExt.ToString() == value)
{
isRegistryValueThisValue = true;
}
}
catch (Exception ex)
{
if (ex is System.Security.SecurityException ||
ex is IOException)
{
Log.Warn($"Could not read registry keyName:{keyName} valueName:{valueName}", ex);
}
else
{
throw;
}
}
return isRegistryValueThisValue;
}
private static void UpgradeIfNotUpgraded()
{
if (!Settings.Default.IsUpgraded)
{
Settings.Default.Upgrade();
Settings.Default.IsUpgraded = true;
Settings.Default.Save();
Log.Info($"Settings upgraded from {CustomSettingsProvider.UserConfigPath}");
}
}
private static ColorAndCode ProcessColorAndCode(
ColorConverter colorConverter,
ColorAndCode colorAndCode,
ref bool changedHtmlColorCode)
{
try
{
colorAndCode.Color = (Color)colorConverter.ConvertFromString(colorAndCode.HtmlColorCode);
}
catch (ArgumentException ex)
{
Log.Warn($"HtmlColorCode {colorAndCode.HtmlColorCode}", ex);
colorAndCode.HtmlColorCode = ColorTranslator.ToHtml(colorAndCode.Color);
changedHtmlColorCode = true;
}
return colorAndCode;
Process.Start("https://github.com/Hofknecht/SystemTrayMenu#FAQ");
}
}
}

View file

@ -1,90 +1,32 @@
// <copyright file="MenuDefines.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System.Drawing;
using System.Reflection;
namespace SystemTrayMenu
{
using System.Drawing;
internal static class MenuDefines
{
internal const int MenusMax = 50;
internal static string NotifyIconText = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyTitleAttribute>().Title;
internal static readonly Color File = Color.White;
internal static readonly Color Folder = Color.White;
internal static readonly Color ColorSelectedItem = AppColors.Blue;
internal static readonly Color ColorOpenFolder = AppColors.Green;
internal static readonly Color ColorTitleWarning = AppColors.Red;
internal static readonly Color ColorTitleSelected = AppColors.Yellow;
internal static readonly Color ColorTitleBackground = AppColors.Azure;
internal const int KeySearchInterval = 1000;
internal const int LengthMax = 37;
internal const int Scrollspeed = 3;
internal const int Scrollspeed = 4;
internal const int WaitMenuOpen = 200;
internal const int MenusMax = 50;
internal const int TimeUntilClose = 1000;
}
public static Color ColorSelectedItem
{
get
{
if (Config.IsDarkMode())
{
return AppColors.DarkModeSelecetedItem;
}
else
{
return AppColors.SelectedItem;
}
}
}
public static Color ColorSelectedItemBorder
{
get
{
if (Config.IsDarkMode())
{
return AppColors.DarkModeSelectedItemBorder;
}
else
{
return AppColors.SelectedItemBorder;
}
}
}
public static Color ColorOpenFolder
{
get
{
if (Config.IsDarkMode())
{
return AppColors.DarkModeOpenFolder;
}
else
{
return AppColors.OpenFolder;
}
}
}
public static Color ColorOpenFolderBorder
{
get
{
if (Config.IsDarkMode())
{
return AppColors.DarkModeOpenFolderBorder;
}
else
{
return AppColors.OpenFolderBorder;
}
}
}
public static Color ColorIcons
{
get
{
if (Config.IsDarkMode())
{
return AppColors.DarkModeIcons;
}
else
{
return AppColors.Icons;
}
}
}
internal static class AppColors
{
internal static readonly Color Blue = Color.FromArgb(204, 232, 255);
internal static readonly Color Green = Color.FromArgb(194, 245, 222);
internal static readonly Color Red = Color.FromArgb(255, 204, 232);
internal static readonly Color Yellow = Color.LightYellow;
internal static readonly Color Azure = Color.Azure;
}
}

View file

@ -1,38 +1,18 @@
// <copyright file="MenuData.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System.Collections.Generic;
namespace SystemTrayMenu.DataClasses
{
using System.Collections.Generic;
internal enum MenuDataValidity
{
Undefined,
Valid,
Empty,
NoAccess,
Invalid,
NoAccess
}
internal struct MenuData
{
public MenuData(int level)
{
RowDatas = new List<RowData>();
Validity = MenuDataValidity.Undefined;
Level = level;
RowDataParent = null;
IsNetworkRoot = false;
}
internal List<RowData> RowDatas { get; set; }
internal MenuDataValidity Validity { get; set; }
internal int Level { get; }
internal RowData RowDataParent { get; set; }
internal bool IsNetworkRoot { get; set; }
}
public List<RowData> RowDatas;
public MenuDataValidity Validity;
public int Level;
};
}

View file

@ -1,200 +1,308 @@
// <copyright file="RowData.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using IWshRuntimeLibrary;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security;
using System.Text;
using System.Windows.Forms;
using SystemTrayMenu.Handler;
using SystemTrayMenu.Utilities;
using TAFactory.IconPack;
using Menu = SystemTrayMenu.UserInterface.Menu;
namespace SystemTrayMenu.DataClasses
{
using System;
using System.Data;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using SystemTrayMenu.Utilities;
using static SystemTrayMenu.Utilities.IconReader;
using Menu = SystemTrayMenu.UserInterface.Menu;
internal class RowData
internal class RowData : IDisposable
{
private static DateTime contextMenuClosed;
private Icon icon;
internal event EventHandler<RowData> OpenMenu;
internal BackgroundWorker Reading = new BackgroundWorker();
internal FileInfo FileInfo;
internal Menu SubMenu;
internal bool IsSelected;
internal bool IsSelectedByKeyboard;
internal bool ContainsMenu;
internal bool IsContextMenuOpen;
private static DateTime ContextMenuClosed;
internal bool IsResolvedLnk;
internal bool IsLoading = false;
internal bool RestartLoading = false;
internal bool HiddenEntry;
internal string TargetFilePath;
internal string TargetFilePathOrig;
internal int RowIndex;
private string WorkingDirectory;
private string Arguments;
private string Text;
private readonly WaitMenuOpen waitMenuOpen = new WaitMenuOpen();
private Icon Icon = null;
private bool diposeIcon = true;
private bool isDisposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="RowData"/> class.
/// empty dummy.
/// </summary>
internal RowData()
{
Reading.WorkerSupportsCancellation = true;
waitMenuOpen.DoOpen += WaitMenuOpen_DoOpen;
}
/// <summary>
/// Initializes a new instance of the <see cref="RowData"/> class.
/// (Related replace "\x00" see #171.)
/// </summary>
/// <param name="isFolder">Flag if file or folder.</param>
/// <param name="isAddionalItem">Flag if addional 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 isAddionalItem, bool isNetworkRoot, int level, string path)
internal void SetText(string text)
{
IsFolder = isFolder;
IsAddionalItem = isAddionalItem;
IsNetworkRoot = isNetworkRoot;
Level = level;
try
if (text.Length > MenuDefines.LengthMax)
{
FileInfo = new FileInfo(path.Replace("\x00", string.Empty));
Path = IsFolder ? $@"{FileInfo.FullName}\" : FileInfo.FullName;
FileExtension = System.IO.Path.GetExtension(Path);
IsLink = FileExtension.Equals(".lnk", StringComparison.InvariantCultureIgnoreCase);
if (IsLink)
{
ResolvedPath = FileLnk.GetResolvedFileName(Path, out bool isLinkToFolder);
IsLinkToFolder = isLinkToFolder || FileLnk.IsNetworkRoot(ResolvedPath);
ShowOverlay = Properties.Settings.Default.ShowLinkOverlay;
Text = System.IO.Path.GetFileNameWithoutExtension(Path);
if (string.IsNullOrEmpty(ResolvedPath))
{
Log.Info($"Resolved path is empty: '{Path}'");
ResolvedPath = Path;
}
}
else
{
ResolvedPath = Path;
if (string.IsNullOrEmpty(FileInfo.Name))
{
int nameBegin = FileInfo.FullName.LastIndexOf(@"\", StringComparison.InvariantCulture) + 1;
Text = FileInfo.FullName[nameBegin..];
}
else if (FileExtension.Equals(".url", StringComparison.InvariantCultureIgnoreCase) ||
FileExtension.Equals(".appref-ms", StringComparison.InvariantCultureIgnoreCase))
{
ShowOverlay = Properties.Settings.Default.ShowLinkOverlay;
Text = System.IO.Path.GetFileNameWithoutExtension(FileInfo.Name);
}
else if (!IsFolder && Config.IsHideFileExtension())
{
Text = System.IO.Path.GetFileNameWithoutExtension(FileInfo.Name);
}
else
{
Text = FileInfo.Name;
}
}
ContainsMenu = IsFolder;
if (Properties.Settings.Default.ResolveLinksToFolders)
{
ContainsMenu |= IsLinkToFolder;
}
IsMainMenu = Level == 0;
}
catch (Exception ex)
{
Log.Warn($"path:'{path}'", ex);
text = $"{text.Substring(0, MenuDefines.LengthMax)}...";
}
Text = text;
}
internal FileInfo FileInfo { get; }
internal string Path { get; }
internal bool IsFolder { get; }
internal bool IsAddionalItem { get; }
internal bool IsNetworkRoot { get; }
internal int Level { get; set; }
internal string FileExtension { get; }
internal bool IsLink { get; }
internal string ResolvedPath { get; }
internal bool IsLinkToFolder { get; }
internal bool ShowOverlay { get; }
internal string Text { get; }
internal bool ContainsMenu { get; }
internal bool IsMainMenu { get; }
internal Menu SubMenu { get; set; }
internal bool IsMenuOpen { get; set; }
internal bool IsClicking { get; set; }
internal bool IsSelected { get; set; }
internal bool IsContextMenuOpen { get; set; }
internal bool HiddenEntry { get; set; }
internal int RowIndex { get; set; }
internal bool IconLoading { get; set; }
internal bool ProcessStarted { get; set; }
internal void SetData(RowData data, DataTable dataTable)
{
DataRow row = dataTable.Rows.Add();
data.RowIndex = dataTable.Rows.IndexOf(row);
if (Icon == null)
{
Icon = Properties.Resources.WhiteTransparency;
}
if (HiddenEntry)
{
row[0] = AddIconOverlay(data.icon, Properties.Resources.White50Percentage);
row[0] = IconReader.AddIconOverlay(data.Icon,
Properties.Resources.WhiteTransparency);
}
else
{
row[0] = data.icon;
row[0] = data.Icon;
}
row[1] = data.Text;
row[2] = data;
}
internal Icon ReadIcon(bool updateIconInBackground)
internal bool ReadIcon(bool isDirectory, ref string resolvedLnkPath)
{
if (IsFolder || IsLinkToFolder)
bool isLnkDirectory = false;
if (string.IsNullOrEmpty(TargetFilePath))
{
icon = GetFolderIconWithCache(Path, ShowOverlay, updateIconInBackground, IsMainMenu, out bool loading);
IconLoading = loading;
Log.Info($"TargetFilePath from {resolvedLnkPath} empty");
}
else if (isDirectory)
{
Icon = IconReader.GetFolderIcon(TargetFilePath,
IconReader.FolderType.Closed, false);
}
else
{
icon = GetFileIconWithCache(Path, ResolvedPath, ShowOverlay, updateIconInBackground, IsMainMenu, out bool loading);
IconLoading = loading;
bool handled = false;
string fileExtension = Path.GetExtension(TargetFilePath);
if (fileExtension == ".lnk")
{
handled = SetLnk(ref isLnkDirectory,
ref resolvedLnkPath);
}
else if (fileExtension == ".url")
{
handled = SetUrl();
}
else if (fileExtension == ".sln")
{
handled = SetSln();
}
if (!handled)
{
try
{
Icon = IconReader.GetFileIconWithCache(TargetFilePath, false);
diposeIcon = false;
// other project -> fails sometimes
//icon = IconHelper.ExtractIcon(TargetFilePath, 0);
// standard way -> fails sometimes
//icon = Icon.ExtractAssociatedIcon(filePath);
// API Code Pack -> fails sometimes
//ShellFile shellFile = ShellFile.FromFilePath(filePath);
//Bitmap shellThumb = shellFile.Thumbnail.ExtraLargeBitmap;
}
catch (Exception ex)
{
if (ex is SecurityException ||
ex is ArgumentException ||
ex is UnauthorizedAccessException ||
ex is PathTooLongException ||
ex is NotSupportedException)
{
Log.Warn($"path:'{TargetFilePath}'", ex);
}
else
{
throw;
}
}
}
}
if (!IconLoading)
return isLnkDirectory;
}
private bool SetLnk(ref bool isLnkDirectory,
ref string resolvedLnkPath)
{
bool handled = false;
resolvedLnkPath = LnkHelper.GetResolvedFileName(TargetFilePath);
if (LnkHelper.IsDirectory(resolvedLnkPath))
{
if (icon == null)
Icon = IconReader.GetFolderIcon(TargetFilePath,
IconReader.FolderType.Open, true);
handled = true;
isLnkDirectory = true;
}
else if (string.IsNullOrEmpty(resolvedLnkPath))
{
Log.Info($"Resolve *.LNK '{TargetFilePath}' has no icon");
#warning [Feature] Resolve network root #48, start here
}
else
{
IWshShell shell = new WshShell();
IWshShortcut lnk = shell.CreateShortcut(TargetFilePath)
as IWshShortcut;
Arguments = lnk.Arguments;
WorkingDirectory = lnk.WorkingDirectory;
string iconLocation = lnk.IconLocation;
if (iconLocation.Length > 2)
{
icon = Properties.Resources.NotFound;
iconLocation = iconLocation.Substring(0,
iconLocation.Length - 2);
if (System.IO.File.Exists(iconLocation))
{
try
{
Icon = Icon.ExtractAssociatedIcon(iconLocation);
handled = true;
}
catch (ArgumentException ex)
{
Log.Warn($"iconLocation:'{iconLocation}'", ex);
}
}
}
else if (HiddenEntry)
TargetFilePath = resolvedLnkPath;
}
SetText(Path.GetFileNameWithoutExtension(TargetFilePathOrig));
return handled;
}
private bool SetUrl()
{
bool handled = false;
string iconFile = string.Empty;
try
{
FileIni file = new FileIni(TargetFilePath);
iconFile = file.Value("IconFile", string.Empty);
if (string.IsNullOrEmpty(iconFile))
{
icon = AddIconOverlay(icon, Properties.Resources.White50Percentage);
string browserPath = FileUrl.GetDefaultBrowserPath();
if (string.IsNullOrEmpty(browserPath))
{
Log.Info($"Resolve *.URL '{TargetFilePath}'" +
$"No default browser found!");
}
else
{
Icon = IconReader.GetFileIconWithCache(browserPath, false);
diposeIcon = false;
handled = true;
}
}
else if (System.IO.File.Exists(iconFile))
{
Icon = Icon.ExtractAssociatedIcon(iconFile);
handled = true;
}
else
{
Log.Info($"Resolve *.URL '{TargetFilePath}' has no icon");
}
}
catch (Exception ex)
{
if (ex is SecurityException ||
ex is ArgumentException ||
ex is UnauthorizedAccessException ||
ex is PathTooLongException ||
ex is NotSupportedException)
{
Log.Warn($"path:'{TargetFilePath}', " +
$"iconFile:'{iconFile}'", ex);
}
else
{
throw;
}
}
return icon;
SetText($"{FileInfo.Name.Substring(0, FileInfo.Name.Length - 4)}");
return handled;
}
private bool SetSln()
{
bool handled = false;
StringBuilder executable = new StringBuilder(1024);
try
{
DllImports.NativeMethods.Shell32FindExecutable(TargetFilePath, string.Empty, executable);
// icon = IconReader.GetFileIcon(executable, false);
// e.g. VS 2019 icon, need another icom in imagelist
List<Icon> extractedIcons = IconHelper.ExtractAllIcons(
executable.ToString());
Icon = extractedIcons.Last();
handled = true;
}
catch (Exception ex)
{
if (ex is SecurityException ||
ex is ArgumentException ||
ex is UnauthorizedAccessException ||
ex is PathTooLongException ||
ex is NotSupportedException)
{
Log.Warn($"path:'{TargetFilePath}', " +
$"executable:'{executable}'", ex);
}
else
{
throw;
}
}
return handled;
}
internal void MouseDown(DataGridView dgv, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
if (ContainsMenu)
{
IsClicking = true;
TriggerMenuOpener(); // Touchscreen
}
if (IsLoading)
{
waitMenuOpen.Click();
}
if (e != null &&
@ -202,101 +310,131 @@ namespace SystemTrayMenu.DataClasses
FileInfo != null &&
dgv != null &&
dgv.Rows.Count > RowIndex &&
(DateTime.Now - contextMenuClosed).TotalMilliseconds > 200)
(DateTime.Now - ContextMenuClosed).TotalMilliseconds > 200)
{
IsContextMenuOpen = true;
Color colorbefore = dgv.Rows[RowIndex].DefaultCellStyle.SelectionBackColor;
dgv.Rows[RowIndex].DefaultCellStyle.SelectionBackColor =
MenuDefines.ColorSelectedItem;
ShellContextMenu ctxMnu = new();
ShellContextMenu ctxMnu = new ShellContextMenu();
Point location = dgv.FindForm().Location;
Point point = new(
Point point = new Point(
e.X + location.X + dgv.Location.X,
e.Y + location.Y + dgv.Location.Y);
if (ContainsMenu)
{
DirectoryInfo[] dir = new DirectoryInfo[1];
dir[0] = new DirectoryInfo(Path);
dir[0] = new DirectoryInfo(TargetFilePathOrig);
ctxMnu.ShowContextMenu(dir, point);
TriggerFileWatcherChangeWorkaround();
}
else
{
FileInfo[] arrFI = new FileInfo[1];
arrFI[0] = FileInfo;
arrFI[0] = new FileInfo(TargetFilePathOrig);
ctxMnu.ShowContextMenu(arrFI, point);
TriggerFileWatcherChangeWorkaround();
}
if (!dgv.IsDisposed)
{
dgv.Rows[RowIndex].DefaultCellStyle.SelectionBackColor = colorbefore;
}
IsContextMenuOpen = false;
contextMenuClosed = DateTime.Now;
ContextMenuClosed = DateTime.Now;
}
}
void TriggerFileWatcherChangeWorkaround()
internal void DoubleClick(MouseEventArgs e)
{
if (e == null ||
e.Button == MouseButtons.Left &&
!ContainsMenu)
{
try
{
string parentFolder = System.IO.Path.GetDirectoryName(Path);
Directory.GetFiles(parentFolder);
using (Process p = new Process())
{
p.StartInfo = new ProcessStartInfo(TargetFilePath)
{
FileName = TargetFilePathOrig,
Arguments = Arguments,
WorkingDirectory = WorkingDirectory,
CreateNoWindow = true
};
p.Start();
};
}
catch (Exception ex)
catch (Win32Exception ex)
{
Log.Warn($"{nameof(TriggerFileWatcherChangeWorkaround)} '{Path}'", ex);
Log.Warn($"path:'{TargetFilePath}'", ex);
MessageBox.Show(ex.Message);
}
}
if (e == null ||
e.Button == MouseButtons.Left &&
ContainsMenu)
{
Log.ProcessStart("explorer.exe", TargetFilePath);
}
}
internal void MouseClick(MouseEventArgs e, out bool toCloseByDoubleClick)
internal void MenuLoaded()
{
IsClicking = false;
toCloseByDoubleClick = false;
if (Properties.Settings.Default.OpenItemWithOneClick)
{
OpenItem(e, ref toCloseByDoubleClick);
}
waitMenuOpen.MenuLoaded();
}
if (Properties.Settings.Default.OpenDirectoryWithOneClick &&
ContainsMenu && (e == null || e.Button == MouseButtons.Left))
internal void StartMenuOpener()
{
if (ContainsMenu)
{
Log.ProcessStart(Path);
if (!Properties.Settings.Default.StaysOpenWhenItemClicked)
{
toCloseByDoubleClick = true;
}
IsLoading = true;
waitMenuOpen.Start();
}
}
internal void DoubleClick(MouseEventArgs e, out bool toCloseByDoubleClick)
private void TriggerMenuOpener()
{
IsClicking = false;
toCloseByDoubleClick = false;
if (!Properties.Settings.Default.OpenItemWithOneClick)
if (ContainsMenu && IsLoading)
{
OpenItem(e, ref toCloseByDoubleClick);
}
if (!Properties.Settings.Default.OpenDirectoryWithOneClick &&
ContainsMenu && (e == null || e.Button == MouseButtons.Left))
{
Log.ProcessStart(Path);
if (!Properties.Settings.Default.StaysOpenWhenItemClicked)
{
toCloseByDoubleClick = true;
}
waitMenuOpen.Start();
}
}
private void OpenItem(MouseEventArgs e, ref bool toCloseByOpenItem)
internal void StopLoadMenuAndStartWaitToOpenIt()
{
if (!ContainsMenu &&
(e == null || e.Button == MouseButtons.Left))
if (ContainsMenu)
{
ProcessStarted = true;
string workingDirectory = System.IO.Path.GetDirectoryName(ResolvedPath);
Log.ProcessStart(Path, string.Empty, false, workingDirectory, true, ResolvedPath);
if (!Properties.Settings.Default.StaysOpenWhenItemClicked)
waitMenuOpen.Stop();
//IsLoading = false;
}
}
private void WaitMenuOpen_DoOpen()
{
IsLoading = false;
OpenMenu?.Invoke(this, this);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!isDisposed)
{
waitMenuOpen.Dispose();
Reading.Dispose();
if (diposeIcon)
{
toCloseByOpenItem = true;
Icon?.Dispose();
}
}
isDisposed = true;
}
}
}

11
DataClasses/Statics.cs Normal file
View file

@ -0,0 +1,11 @@
namespace SystemTrayMenu.DataClasses
{
public static class Statics
{
public static int ScreenHeight = 0;
public static int ScreenWidth = 0;
public static int ScreenRight = 0;
public static int TaskbarHeight = 0;
}
}

View file

@ -1,16 +0,0 @@
// <copyright file="GlobalSuppressions.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA0001:XML comment analysis is disabled due to project configuration", Justification = "no idea what this is")]
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "we need to document")]
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1601:Partial elements should be documented", Justification = "we need to document")]
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1602:Enumeration items should be documented", Justification = "we need to document")]
[assembly: SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1000:Keywords should be spaced correctly", Justification = "new() should not be replaced by new() ")]
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:Prefix local calls with this", Justification = "Standard codecleanup removes the this")]
[assembly: SuppressMessage("Interoperability", "CA1416:Check platform compatibility", Justification = "this is a long way to get platform compatibility")]

View file

@ -1,106 +0,0 @@
// <copyright file="DgvMouseRow.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Helper
{
using System;
using System.Windows.Forms;
public class DgvMouseRow : IDisposable
{
private readonly Timer timerRaiseRowMouseLeave = new();
private DataGridView dgv;
private DataGridViewCellEventArgs eventArgs;
internal DgvMouseRow()
{
timerRaiseRowMouseLeave.Interval = 200;
timerRaiseRowMouseLeave.Tick += TimerRaiseRowMouseLeave_Tick;
}
~DgvMouseRow() // the finalizer
{
Dispose(false);
}
internal event Action<object, DataGridViewCellEventArgs> RowMouseEnter;
internal event Action<object, DataGridViewCellEventArgs> RowMouseLeave;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
internal void CellMouseEnter(object sender, DataGridViewCellEventArgs newEventArgs)
{
DataGridView newDgv = (DataGridView)sender;
if (dgv != newDgv || newEventArgs.RowIndex != eventArgs.RowIndex)
{
if (timerRaiseRowMouseLeave.Enabled)
{
timerRaiseRowMouseLeave.Stop();
TriggerRowMouseLeave();
}
TriggerRowMouseEnter(newDgv, newEventArgs);
}
else
{
timerRaiseRowMouseLeave.Stop();
}
dgv = newDgv;
eventArgs = newEventArgs;
}
internal void CellMouseLeave(object sender, DataGridViewCellEventArgs e)
{
timerRaiseRowMouseLeave.Start();
}
internal void MouseLeave(object sender, EventArgs e)
{
if (timerRaiseRowMouseLeave.Enabled)
{
timerRaiseRowMouseLeave.Stop();
TriggerRowMouseLeave();
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
timerRaiseRowMouseLeave.Tick -= TimerRaiseRowMouseLeave_Tick;
timerRaiseRowMouseLeave.Dispose();
dgv = null;
}
}
private void TimerRaiseRowMouseLeave_Tick(object sender, EventArgs e)
{
timerRaiseRowMouseLeave.Stop();
TriggerRowMouseLeave();
}
private void TriggerRowMouseLeave()
{
if (dgv != null)
{
RowMouseLeave?.Invoke(dgv, eventArgs);
}
dgv = null;
eventArgs = null;
}
private void TriggerRowMouseEnter(DataGridView dgv, DataGridViewCellEventArgs e)
{
RowMouseEnter?.Invoke(dgv, e);
}
}
}

View file

@ -1,190 +0,0 @@
// <copyright file="DragDropHelper.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Helper
{
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using SystemTrayMenu.DataClasses;
using SystemTrayMenu.UserInterface;
using SystemTrayMenu.Utilities;
public static class DragDropHelper
{
public static void DragEnter(object sender, DragEventArgs e)
{
object data = e.Data.GetData("UniformResourceLocator");
if (data is MemoryStream memoryStream)
{
byte[] bytes = memoryStream.ToArray();
Encoding encod = Encoding.ASCII;
string url = encod.GetString(bytes);
if (!string.IsNullOrEmpty(url))
{
e.Effect = DragDropEffects.Copy;
}
}
}
public static void DragDrop(object sender, DragEventArgs e)
{
Menu menu = (Menu)sender;
string path;
if (menu != null)
{
RowData rowData = (RowData)menu.Tag;
if (rowData != null)
{
path = rowData.ResolvedPath;
}
else
{
path = Config.Path;
}
}
else
{
path = Config.Path;
}
object data = e.Data.GetData("UniformResourceLocator");
MemoryStream ms = data as MemoryStream;
byte[] bytes = ms.ToArray();
Encoding encod = Encoding.ASCII;
string url = encod.GetString(bytes);
new Thread(CreateShortcutInBackground).Start();
void CreateShortcutInBackground()
{
CreateShortcut(url.Replace("\0", string.Empty), path);
}
}
private static void CreateShortcut(string url, string pathToStoreFile)
{
string title = GetUrlShortcutTitle(url);
string fileNamePathShortcut = pathToStoreFile + "\\" + title.Trim() + ".url";
WriteShortcut(url, null, fileNamePathShortcut);
string pathIcon = DownloadUrlIcon(url);
if (!string.IsNullOrEmpty(pathIcon))
{
WriteShortcut(url, pathIcon, fileNamePathShortcut);
}
}
private static string GetUrlShortcutTitle(string url)
{
string title = url
.Replace("/", " ")
.Replace("https", string.Empty)
.Replace("http", string.Empty);
string invalid =
new string(Path.GetInvalidFileNameChars()) +
new string(Path.GetInvalidPathChars());
foreach (char character in invalid)
{
title = title.Replace(character.ToString(), string.Empty);
}
title = Truncate(title, 128); // max 255
return title;
}
private static string Truncate(string value, int maxLength)
{
if (!string.IsNullOrEmpty(value) &&
value.Length > maxLength)
{
value = value[..maxLength];
}
return value;
}
private static void WriteShortcut(string url, string pathIcon, string fileNamePathShortcut)
{
try
{
if (File.Exists(fileNamePathShortcut))
{
File.Delete(fileNamePathShortcut);
}
StreamWriter writer = new(fileNamePathShortcut);
writer.WriteLine("[InternetShortcut]");
writer.WriteLine($"URL={url.TrimEnd('\0')}");
writer.WriteLine("IconIndex=0");
writer.WriteLine($"HotKey=0");
writer.WriteLine($"IDList=");
if (!string.IsNullOrEmpty(pathIcon))
{
writer.WriteLine($"IconFile={pathIcon}");
}
writer.Flush();
writer.Close();
}
catch (Exception ex)
{
Log.Warn($"{nameof(WriteShortcut)} failed", ex);
}
}
private static string DownloadUrlIcon(string url)
{
string pathIcon = string.Empty;
string pathToStoreIcons = Properties.Settings.Default.PathIcoDirectory;
Uri uri = new(url);
string hostname = uri.Host.ToString();
string pathIconPng = Path.Combine(pathToStoreIcons, $"{hostname}.png");
string urlGoogleIconDownload = @"http://www.google.com/s2/favicons?sz=32&domain=" + url;
HttpClient client = new();
try
{
if (!Directory.Exists(pathToStoreIcons))
{
Directory.CreateDirectory(pathToStoreIcons);
}
using HttpResponseMessage response = client.GetAsync(urlGoogleIconDownload).Result;
using HttpContent content = response.Content;
Stream stream = content.ReadAsStreamAsync().Result;
using var fileStream = File.Create(pathIconPng);
stream.Seek(0, SeekOrigin.Begin);
stream.CopyTo(fileStream);
fileStream.Close();
pathIcon = Path.Combine(pathToStoreIcons, $"{hostname}.ico");
if (!ImagingHelper.ConvertToIcon(pathIconPng, pathIcon, 32))
{
Log.Info("Failed to convert icon.");
}
}
catch (Exception ex)
{
Log.Warn($"{nameof(DownloadUrlIcon)} failed", ex);
}
try
{
if (File.Exists(pathIconPng))
{
File.Delete(pathIconPng);
}
}
catch (Exception ex)
{
Log.Warn($"{nameof(DownloadUrlIcon)} failed to delete {pathIconPng}", ex);
}
return pathIcon;
}
}
}

View file

@ -1,61 +1,41 @@
// <copyright file="Fading.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Windows.Forms;
using SystemTrayMenu.Utilities;
namespace SystemTrayMenu.Helper
namespace SystemTrayMenu.UserInterface
{
using System;
using System.Windows.Forms;
using SystemTrayMenu.Utilities;
public class Fading : IDisposable
{
private const int Interval100FPS = 10; // 100fps=>1s/100fps=~10ms
internal event EventHandlerEmpty Hide;
internal event EventHandlerEmpty Show;
internal event EventHandler<double> ChangeOpacity;
internal enum FadingState { Idle, Show, ShowTransparent, Hide };
internal bool IsHiding => state == FadingState.Hide;
private const int Interval60FPS = 16; //60fps=>1s/60fps=~16.6ms
private const double StepIn = 0.20;
private const double StepOut = 0.10;
private const double Transparent = 0.80;
private const double TransparentMinus = 0.60; // Transparent - StepIn
private const double TransparentPlus = 0.85; // Transparent + StepOut
private const double TransparentMinus = 0.60; //Transparent - StepIn
private const double TransparentPlus = 0.85; //Transparent + StepOut
private const double Shown = 1.00;
private const double ShownMinus = 0.80; // Shown - StepIn
private const double ShownMinus = 0.80; //Shown - StepIn
private readonly Timer timer = new();
private readonly Timer timer = new Timer();
private static readonly object lockTimerEnable = new object();
private FadingState state = FadingState.Idle;
private double opacity;
private bool visible;
private double opacity = 0.00;
private bool visible = false;
internal Fading()
{
timer.Interval = Interval100FPS;
timer.Tick += Timer_Tick;
}
~Fading() // the finalizer
{
Dispose(false);
}
internal event Action Hide;
internal event Action Show;
internal event Action<double> ChangeOpacity;
internal enum FadingState
{
Idle,
Show,
ShowTransparent,
Hide,
}
internal bool IsHiding => state == FadingState.Hide;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
timer.Interval = Interval60FPS;
timer.Tick += Tick;
void Tick(object sender, EventArgs e)
{
FadeStep();
}
}
internal void Fade(FadingState state)
@ -63,15 +43,6 @@ namespace SystemTrayMenu.Helper
StartStopTimer(state);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
timer.Tick -= Timer_Tick;
timer.Dispose();
}
}
private void StartStopTimer(FadingState newState)
{
if (newState == FadingState.Idle)
@ -83,14 +54,10 @@ namespace SystemTrayMenu.Helper
{
state = newState;
timer.Start();
FadeStep();
}
}
private void Timer_Tick(object sender, EventArgs e)
{
FadeStep();
}
private void FadeStep()
{
switch (state)
@ -101,28 +68,19 @@ namespace SystemTrayMenu.Helper
visible = true;
Show?.Invoke();
opacity = 0;
ChangeOpacity?.Invoke(opacity);
ChangeOpacity?.Invoke(this, opacity);
}
else if (Properties.Settings.Default.UseFading &&
opacity < ShownMinus)
else if (opacity < ShownMinus)
{
opacity += StepIn;
ChangeOpacity?.Invoke(opacity);
ChangeOpacity?.Invoke(this, opacity);
}
else
else if (opacity != Shown)
{
if (!Properties.Settings.Default.UseFading)
{
// #393 provoke a redraw for the CS_DROPSHADOW to work
opacity = ShownMinus;
ChangeOpacity?.Invoke(opacity);
}
opacity = Shown;
ChangeOpacity?.Invoke(opacity);
ChangeOpacity?.Invoke(this, Shown);
StartStopTimer(FadingState.Idle);
}
break;
case FadingState.ShowTransparent:
if (!visible)
@ -130,48 +88,38 @@ namespace SystemTrayMenu.Helper
visible = true;
Show?.Invoke();
opacity = 0;
ChangeOpacity?.Invoke(opacity);
ChangeOpacity?.Invoke(this, opacity);
}
else if (Properties.Settings.Default.UseFading &&
opacity < TransparentMinus)
else if (opacity < TransparentMinus)
{
opacity += StepIn;
ChangeOpacity?.Invoke(opacity);
ChangeOpacity?.Invoke(this, opacity);
}
else if (Properties.Settings.Default.UseFading &&
opacity > TransparentPlus)
else if (opacity > TransparentPlus)
{
opacity -= StepOut;
ChangeOpacity?.Invoke(opacity);
ChangeOpacity?.Invoke(this, opacity);
}
else
else if (opacity != Transparent)
{
opacity = Transparent;
ChangeOpacity?.Invoke(opacity);
ChangeOpacity?.Invoke(this, Transparent);
StartStopTimer(FadingState.Idle);
}
break;
case FadingState.Hide:
if (Properties.Settings.Default.UseFading &&
opacity > StepOut)
if (opacity > StepOut)
{
opacity -= StepOut;
ChangeOpacity?.Invoke(opacity);
ChangeOpacity?.Invoke(this, opacity);
}
else if (visible)
{
opacity = 0;
ChangeOpacity?.Invoke(opacity);
ChangeOpacity?.Invoke(this, opacity);
visible = false;
Hide?.Invoke();
StartStopTimer(FadingState.Idle);
}
else
{
StartStopTimer(FadingState.Idle);
}
break;
case FadingState.Idle:
default:
@ -179,5 +127,19 @@ namespace SystemTrayMenu.Helper
break;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
timer.Dispose();
}
}
}
}

View file

@ -1,147 +0,0 @@
// <copyright file="ImagingHelper.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Helper
{
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
/// <summary>
/// Provides helper methods for imaging.
/// </summary>
public static class ImagingHelper
{
/// <summary>
/// Converts a PNG image to a icon (ico).
/// </summary>
/// <param name="input">The input stream.</param>
/// <param name="output">The output stream.</param>
/// <param name="size">The size (16x16 px by default).</param>
/// <param name="preserveAspectRatio">Preserve the aspect ratio.</param>
/// <returns>Wether or not the icon was succesfully generated.</returns>
public static bool ConvertToIcon(Stream input, Stream output, int size = 16, bool preserveAspectRatio = false)
{
Bitmap inputBitmap = (Bitmap)Image.FromStream(input);
if (inputBitmap != null)
{
int width, height;
if (preserveAspectRatio)
{
width = size;
height = inputBitmap.Height / inputBitmap.Width * size;
}
else
{
width = height = size;
}
Bitmap newBitmap = new(inputBitmap, new Size(width, height));
if (newBitmap != null)
{
// save the resized png into a memory stream for future use
using MemoryStream memoryStream = new();
newBitmap.Save(memoryStream, ImageFormat.Png);
BinaryWriter iconWriter = new(output);
if (output != null && iconWriter != null)
{
// 0-1 reserved, 0
iconWriter.Write((byte)0);
iconWriter.Write((byte)0);
// 2-3 image type, 1 = icon, 2 = cursor
iconWriter.Write((short)1);
// 4-5 number of images
iconWriter.Write((short)1);
// image entry 1
// 0 image width
iconWriter.Write((byte)width);
// 1 image height
iconWriter.Write((byte)height);
// 2 number of colors
iconWriter.Write((byte)0);
// 3 reserved
iconWriter.Write((byte)0);
// 4-5 color planes
iconWriter.Write((short)0);
// 6-7 bits per pixel
iconWriter.Write((short)32);
// 8-11 size of image data
iconWriter.Write((int)memoryStream.Length);
// 12-15 offset of image data
iconWriter.Write(6 + 16);
// write image data
// png data must contain the whole png data file
iconWriter.Write(memoryStream.ToArray());
iconWriter.Flush();
return true;
}
}
return false;
}
return false;
}
/// <summary>
/// Converts a PNG image to a icon (ico).
/// </summary>
/// <param name="inputPath">The input path.</param>
/// <param name="outputPath">The output path.</param>
/// <param name="size">The size (16x16 px by default).</param>
/// <param name="preserveAspectRatio">Preserve the aspect ratio.</param>
/// <returns>Wether or not the icon was succesfully generated.</returns>
public static bool ConvertToIcon(string inputPath, string outputPath, int size = 16, bool preserveAspectRatio = false)
{
using FileStream inputStream = new(inputPath, FileMode.Open);
using FileStream outputStream = new(outputPath, FileMode.OpenOrCreate);
return ConvertToIcon(inputStream, outputStream, size, preserveAspectRatio);
}
public static Image RotateImage(Image img, float rotationAngle)
{
// create an empty Bitmap image
Bitmap bmp = new(img.Width, img.Height);
// turn the Bitmap into a Graphics object
Graphics gfx = Graphics.FromImage(bmp);
// now we set the rotation point to the center of our image
gfx.TranslateTransform(0.5f + ((float)bmp.Width / 2), 0.5f + ((float)bmp.Height / 2));
// now rotate the image
gfx.RotateTransform(rotationAngle);
gfx.TranslateTransform(0.5f - ((float)bmp.Width / 2), 0.5f - ((float)bmp.Height / 2));
// set the InterpolationMode to HighQualityBicubic so to ensure a high
// quality image once it is transformed to the specified size
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
// now draw our new image onto the graphics object
gfx.DrawImage(img, new Point(0, 0));
// dispose of our Graphics object
gfx.Dispose();
// return the image
return bmp;
}
}
}

View file

@ -1,215 +0,0 @@
// <copyright file="JoystickHelper.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Helpers
{
using System;
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Reflection.Metadata;
using System.Threading;
using System.Windows.Forms;
using SharpDX.DirectInput;
public class JoystickHelper : IDisposable
{
private readonly System.Timers.Timer timerReadJoystick = new();
private readonly object lockRead = new();
private Joystick joystick;
private Keys pressingKey;
private int pressingKeyCounter;
private bool joystickHelperEnabled;
public JoystickHelper()
{
timerReadJoystick.Interval = 80;
timerReadJoystick.Elapsed += ReadJoystickLoop;
timerReadJoystick.Enabled = false;
if (Properties.Settings.Default.SupportGamepad)
{
timerReadJoystick.Start();
}
}
~JoystickHelper() // the finalizer
{
Dispose(false);
}
public event Action<Keys> KeyPressed;
public void Enable()
{
joystickHelperEnabled = true;
}
public void Disable()
{
joystickHelperEnabled = false;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
timerReadJoystick.Elapsed -= ReadJoystickLoop;
timerReadJoystick?.Dispose();
joystick?.Dispose();
}
}
private static Keys ReadKeyFromState(JoystickUpdate state)
{
Keys keys = Keys.None;
switch (state.Offset)
{
case JoystickOffset.PointOfViewControllers0:
switch (state.Value)
{
case 0:
keys = Keys.Up;
break;
case 9000:
keys = Keys.Right;
break;
case 18000:
keys = Keys.Down;
break;
case 27000:
keys = Keys.Left;
break;
default:
break;
}
break;
case JoystickOffset.Buttons0:
if (state.Value == 128)
{
keys = Keys.Enter;
}
break;
default:
break;
}
return keys;
}
private void ReadJoystickLoop(object sender, System.Timers.ElapsedEventArgs e)
{
if (joystickHelperEnabled)
{
lock (lockRead)
{
timerReadJoystick.Stop();
if (joystick == null)
{
Thread.Sleep(3000);
InitializeJoystick();
}
else
{
ReadJoystick();
}
timerReadJoystick.Start();
}
}
}
private void ReadJoystick()
{
try
{
joystick.Poll();
JoystickUpdate[] datas = joystick.GetBufferedData();
foreach (JoystickUpdate state in datas)
{
if (state.Value < 0)
{
pressingKey = Keys.None;
pressingKeyCounter = 0;
continue;
}
Keys key = ReadKeyFromState(state);
if (key != Keys.None)
{
KeyPressed?.Invoke(key);
if (state.Offset == JoystickOffset.PointOfViewControllers0)
{
pressingKeyCounter = 0;
pressingKey = key;
}
}
}
if (pressingKey != Keys.None)
{
pressingKeyCounter += 1;
if (pressingKeyCounter > 1)
{
KeyPressed?.Invoke(pressingKey);
}
}
}
catch
{
joystick?.Dispose();
joystick = null;
}
}
private void InitializeJoystick()
{
// Initialize DirectInput
DirectInput directInput = new();
// Find a Joystick Guid
Guid joystickGuid = Guid.Empty;
foreach (DeviceInstance deviceInstance in directInput.GetDevices(
DeviceType.Gamepad,
DeviceEnumerationFlags.AllDevices))
{
joystickGuid = deviceInstance.InstanceGuid;
}
// If Gamepad not found, look for a Joystick
if (joystickGuid == Guid.Empty)
{
foreach (DeviceInstance deviceInstance in directInput.GetDevices(
DeviceType.Joystick,
DeviceEnumerationFlags.AllDevices))
{
joystickGuid = deviceInstance.InstanceGuid;
}
}
// If Joystick found
if (joystickGuid != Guid.Empty)
{
// Instantiate the joystick
joystick = new Joystick(directInput, joystickGuid);
// Set BufferSize in order to use buffered data.
joystick.Properties.BufferSize = 128;
var handle = Process.GetCurrentProcess().MainWindowHandle;
joystick.SetCooperativeLevel(handle, CooperativeLevel.NonExclusive | CooperativeLevel.Background);
// Acquire the joystick
joystick.Acquire();
}
}
}
}

View file

@ -1,27 +0,0 @@
// <copyright file="KeyPressedEventArgs.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Helper
{
using System;
using System.Windows.Forms;
/// <summary>
/// Event Args for the event that is fired after the hot key has been pressed.
/// </summary>
internal class KeyPressedEventArgs : EventArgs
{
private readonly Keys key;
internal KeyPressedEventArgs(KeyboardHookModifierKeys modifier, Keys key)
{
Modifier = modifier;
this.key = key;
}
internal KeyboardHookModifierKeys Modifier { get; }
internal Keys Key => key;
}
}

View file

@ -1,54 +1,70 @@
// <copyright file="KeyboardHook.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Windows.Forms;
using SystemTrayMenu.UserInterface.Controls;
using SystemTrayMenu.Utilities;
namespace SystemTrayMenu.Helper
{
using System;
using System.Windows.Forms;
using SystemTrayMenu.UserInterface.HotkeyTextboxControl;
using SystemTrayMenu.Utilities;
/// <summary>
/// The enumeration of possible modifiers.
/// </summary>
[Flags]
public enum KeyboardHookModifierKeys : uint
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Win = 8,
}
public sealed class KeyboardHook : IDisposable
{
private readonly Window window = new();
private int currentId;
/// <summary>
/// Represents the window that is used internally to get the messages.
/// </summary>
private class Window : NativeWindow, IDisposable
{
private const int WM_HOTKEY = 0x0312;
public Window()
{
// create the handle for the window.
CreateHandle(new CreateParams());
}
/// <summary>
/// Overridden to get the notifications.
/// </summary>
/// <param name="m"></param>
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
// check if we got a hot key pressed.
if (m.Msg == WM_HOTKEY)
{
// get the keys.
Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);
KeyboardHookModifierKeys modifier = (KeyboardHookModifierKeys)((int)m.LParam & 0xFFFF);
// invoke the event to notify the parent.
if (KeyPressed != null)
{
KeyPressed(this, new KeyPressedEventArgs(modifier, key));
}
}
}
public event EventHandler<KeyPressedEventArgs> KeyPressed;
#region IDisposable Members
public void Dispose()
{
DestroyHandle();
}
#endregion
}
private readonly Window _window = new Window();
private int _currentId;
public KeyboardHook()
{
// register the event of the inner native window.
window.KeyPressed += Window_KeyPressed;
}
/// <summary>
/// A hot key has been pressed.
/// </summary>
internal event EventHandler<KeyPressedEventArgs> KeyPressed;
public void Dispose()
{
// unregister all the registered hot keys.
for (int i = currentId; i > 0; i--)
_window.KeyPressed += delegate (object sender, KeyPressedEventArgs args)
{
DllImports.NativeMethods.User32UnregisterHotKey(window.Handle, i);
}
// dispose the inner native window.
window.KeyPressed -= Window_KeyPressed;
window.Dispose();
KeyPressed?.Invoke(this, args);
};
}
/// <summary>
@ -61,36 +77,31 @@ namespace SystemTrayMenu.Helper
RegisterHotKey(keyModifiersNone, key);
}
internal void RegisterHotKey()
internal void RegisterHotKey(string hotKeyString)
{
KeyboardHookModifierKeys modifiers = KeyboardHookModifierKeys.None;
string modifiersString = Properties.Settings.Default.HotKey;
if (!string.IsNullOrEmpty(modifiersString))
{
if (modifiersString.ToUpperInvariant().Contains("ALT", StringComparison.InvariantCulture))
if (modifiersString.ToLower().Contains("alt"))
{
modifiers |= KeyboardHookModifierKeys.Alt;
}
if (modifiersString.ToUpperInvariant().Contains("CTRL", StringComparison.InvariantCulture) ||
modifiersString.ToUpperInvariant().Contains("STRG", StringComparison.InvariantCulture))
if (modifiersString.ToLower().Contains("ctrl"))
{
modifiers |= KeyboardHookModifierKeys.Control;
}
if (modifiersString.ToUpperInvariant().Contains("SHIFT", StringComparison.InvariantCulture))
if (modifiersString.ToLower().Contains("shift"))
{
modifiers |= KeyboardHookModifierKeys.Shift;
}
if (modifiersString.ToUpperInvariant().Contains("WIN", StringComparison.InvariantCulture))
if (modifiersString.ToLower().Contains("win"))
{
modifiers |= KeyboardHookModifierKeys.Win;
}
}
RegisterHotKey(
modifiers,
RegisterHotKey(modifiers,
HotkeyControl.HotkeyFromString(
Properties.Settings.Default.HotKey));
}
@ -100,22 +111,18 @@ namespace SystemTrayMenu.Helper
/// </summary>
/// <param name="modifier">The modifiers that are associated with the hot key.</param>
/// <param name="key">The key itself that is associated with the hot key.</param>
//internal void RegisterHotKey(KeyboardHookModifierKeys modifier, Keys key)
internal void RegisterHotKey(KeyboardHookModifierKeys modifier, Keys key)
{
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;
_currentId = _currentId + 1;
if (!DllImports.NativeMethods.User32RegisterHotKey(
window.Handle, currentId, modifier, (uint)key))
_window.Handle, _currentId, modifier, (uint)key))
{
throw new InvalidOperationException(
Translator.GetText("Could not register the hot key."));
@ -123,44 +130,56 @@ namespace SystemTrayMenu.Helper
}
/// <summary>
/// Represents the window that is used internally to get the messages.
/// A hot key has been pressed.
/// </summary>
private class Window : NativeWindow, IDisposable
internal event EventHandler<KeyPressedEventArgs> KeyPressed;
#region IDisposable Members
public void Dispose()
{
private const int WmHotkey = 0x0312;
public Window()
// unregister all the registered hot keys.
for (int i = _currentId; i > 0; i--)
{
// create the handle for the window.
CreateHandle(new CreateParams());
DllImports.NativeMethods.User32UnregisterHotKey(_window.Handle, i);
}
public event EventHandler<KeyPressedEventArgs> KeyPressed;
public void Dispose()
{
DestroyHandle();
}
/// <summary>
/// Overridden to get the notifications.
/// </summary>
/// <param name="m">m.</param>
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
// check if we got a hot key pressed.
if (m.Msg == WmHotkey)
{
// get the keys.
Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);
KeyboardHookModifierKeys modifier = (KeyboardHookModifierKeys)((int)m.LParam & 0xFFFF);
// invoke the event to notify the parent.
KeyPressed?.Invoke(this, new KeyPressedEventArgs(modifier, key));
}
}
// dispose the inner native window.
_window.Dispose();
}
#endregion
}
/// <summary>
/// Event Args for the event that is fired after the hot key has been pressed.
/// </summary>
internal class KeyPressedEventArgs : EventArgs
{
private readonly KeyboardHookModifierKeys _modifier;
private readonly Keys _key;
internal KeyPressedEventArgs(KeyboardHookModifierKeys modifier, Keys key)
{
_modifier = modifier;
_key = key;
}
internal KeyboardHookModifierKeys Modifier => _modifier;
internal Keys Key => _key;
}
/// <summary>
/// The enumeration of possible modifiers.
/// </summary>
[Flags]
internal enum KeyboardHookModifierKeys : uint
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Win = 8
}
}

View file

@ -1,251 +0,0 @@
// <copyright file="GitHubUpdate.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Helper.Updater
{
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Net.Http;
using System.Reflection;
using System.Windows.Forms;
using SystemTrayMenu.Utilities;
public class GitHubUpdate
{
private static List<Dictionary<string, object>> releases;
private static Form newVersionForm;
public static void ActivateNewVersionFormOrCheckForUpdates(bool showWhenUpToDate)
{
if (newVersionForm != null)
{
newVersionForm.HandleInvoke(newVersionForm.Activate);
}
else
{
CheckForUpdates(showWhenUpToDate);
}
}
private static void CheckForUpdates(bool showWhenUpToDate)
{
string urlGithubReleases = @"http://api.github.com/repos/Hofknecht/SystemTrayMenu/releases";
HttpClient client = new();
// https://developer.github.com/v3/#user-agent-required
client.DefaultRequestHeaders.Add("User-Agent", "SystemTrayMenu/" + Application.ProductVersion.ToString());
// https://developer.github.com/v3/media/#request-specific-version
client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3.text+json");
try
{
using HttpResponseMessage response = client.GetAsync(urlGithubReleases).Result;
using HttpContent content = response.Content;
string responseString = content.ReadAsStringAsync().Result;
releases = responseString.FromJson<List<Dictionary<string, object>>>();
}
catch (Exception ex)
{
Log.Warn($"{nameof(CheckForUpdates)} failed", ex);
}
if (releases == null)
{
Log.Info($"{nameof(CheckForUpdates)} failed.");
}
else
{
RemoveCurrentAndOlderVersions();
ShowNewVersionOrUpToDateDialog(showWhenUpToDate);
}
newVersionForm?.Dispose();
newVersionForm = null;
}
private static void RemoveCurrentAndOlderVersions()
{
int releasesCount = releases.Count;
Version versionCurrent = Assembly.GetExecutingAssembly().GetName().Version;
for (int i = 0; i < releasesCount; i++)
{
string tagName = releases[i]["tag_name"].ToString();
Version versionGitHub = new(tagName.Replace("v", string.Empty));
if (versionGitHub.CompareTo(versionCurrent) < 1)
{
releases.RemoveRange(i, releasesCount - i);
break;
}
}
}
private static void ShowNewVersionOrUpToDateDialog(bool showWhenUpToDate)
{
if (releases.Count > 0)
{
if (NewVersionDialog() == DialogResult.Yes)
{
Log.ProcessStart("https://github.com/Hofknecht/SystemTrayMenu/releases");
}
}
else if (showWhenUpToDate)
{
MessageBox.Show(Translator.GetText("You have the latest version of SystemTrayMenu!"));
}
}
/// <summary>
/// Creates a window to show changelog of new available versions.
/// </summary>
/// <param name="LatestVersionTitle">Name of latest release.</param>
/// <param name="Changelog">Pathnotes.</param>
/// <returns>OK = OK, Yes = Website, else = Cancel.</returns>
private static DialogResult NewVersionDialog()
{
const int ClientPad = 15;
newVersionForm = new()
{
StartPosition = FormStartPosition.CenterScreen,
FormBorderStyle = FormBorderStyle.FixedDialog,
Icon = Config.GetAppIcon(),
ShowInTaskbar = false,
};
newVersionForm.FormBorderStyle = FormBorderStyle.Sizable;
newVersionForm.MaximizeBox = true;
newVersionForm.MinimizeBox = false;
newVersionForm.ClientSize = new Size(600, 400);
newVersionForm.MinimumSize = newVersionForm.ClientSize;
newVersionForm.Text = Translator.GetText("New version available!");
Label label = new()
{
Size = new Size(newVersionForm.ClientSize.Width - ClientPad, 20),
Location = new Point(ClientPad, ClientPad),
Text = $"{Translator.GetText("Latest available version:")} {GetLatestVersionName()}",
};
newVersionForm.Controls.Add(label);
Button buttonOK = new()
{
DialogResult = DialogResult.OK,
Name = "buttonOK",
};
buttonOK.Location = new Point(
newVersionForm.ClientSize.Width - buttonOK.Size.Width - ClientPad,
newVersionForm.ClientSize.Height - buttonOK.Size.Height - ClientPad);
buttonOK.MinimumSize = new Size(75, 23);
buttonOK.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
buttonOK.Text = Translator.GetText("OK");
buttonOK.AutoSizeMode = AutoSizeMode.GrowAndShrink;
buttonOK.AutoSize = true;
newVersionForm.Controls.Add(buttonOK);
Button buttonGoToDownloadPage = new()
{
DialogResult = DialogResult.Yes,
Name = "buttonGoToDownloadPage",
};
buttonGoToDownloadPage.Location = new Point(
newVersionForm.ClientSize.Width - buttonGoToDownloadPage.Size.Width - ClientPad - buttonOK.Size.Width - ClientPad,
newVersionForm.ClientSize.Height - buttonGoToDownloadPage.Size.Height - ClientPad);
buttonGoToDownloadPage.MinimumSize = new Size(75, 23);
buttonGoToDownloadPage.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
buttonGoToDownloadPage.Text = Translator.GetText("Go to download page");
buttonGoToDownloadPage.AutoSizeMode = AutoSizeMode.GrowAndShrink;
buttonGoToDownloadPage.AutoSize = true;
newVersionForm.Controls.Add(buttonGoToDownloadPage);
TextBox textBox = new()
{
Location = new Point(ClientPad, label.Location.Y + label.Size.Height + 5),
};
textBox.Size = new Size(
newVersionForm.ClientSize.Width - (ClientPad * 2),
buttonOK.Location.Y - ClientPad - textBox.Location.Y);
textBox.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
textBox.Multiline = true;
textBox.Text = GetChangelog();
textBox.ReadOnly = true;
textBox.ScrollBars = ScrollBars.Both;
textBox.BackColor = Color.FromKnownColor(KnownColor.Window);
textBox.ForeColor = Color.FromKnownColor(KnownColor.ControlText);
newVersionForm.Controls.Add(textBox);
newVersionForm.AcceptButton = buttonOK;
return newVersionForm.ShowDialog();
}
/// <summary>
/// Returns the latest release version name.
/// </summary>
/// <returns>Version name.</returns>
private static string GetLatestVersionName()
{
string result = "Unknown";
if (releases == null)
{
return result;
}
try
{
result = releases[0]["tag_name"].ToString().Replace("v", string.Empty);
}
catch (Exception ex)
{
Log.Warn($"{nameof(GetLatestVersionName)} failed", ex);
}
return result;
}
/// <summary>
/// Returns the change log from current version up to the latest release version.
/// </summary>
/// <returns>Change log summary or error text.</returns>
private static string GetChangelog()
{
string result = string.Empty;
string errorstr = "An error occurred during update check!" + Environment.NewLine;
if (releases == null)
{
return errorstr + "Could not receive changelog!";
}
try
{
for (int i = 0; i < releases.Count; i++)
{
Dictionary<string, object> release = releases[i];
result += release["name"].ToString()
+ Environment.NewLine
+ release["body_text"].ToString()
.Replace("\n\n", Environment.NewLine)
.Replace("\n \n", Environment.NewLine)
+ Environment.NewLine + Environment.NewLine;
if (i < releases.Count)
{
result += "--------------------------------------------------" +
"-------------------------------------------------------"
+ Environment.NewLine;
}
}
result = result.Replace("\n", Environment.NewLine);
}
catch (Exception ex)
{
Log.Warn($"{nameof(GetChangelog)}", ex);
result = errorstr + ex.Message.ToString();
}
return result;
}
}
}

View file

@ -1,480 +0,0 @@
// <copyright file="JsonParser.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Helper.Updater
{
// Copyright (c) 2018 Alex Parker
// Copyright (c) 2018-2019 Peter Kirmeier
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
// Really simple JSON parser in ~300 lines
// - Attempts to parse JSON files with minimal GC allocation
// - Nice and simple "[1,2,3]".FromJson<List<int>>() API
// - Classes and structs can be parsed too!
// class Foo { public int Value; }
// "{\"Value\":10}".FromJson<Foo>()
// - Can parse JSON without type information into Dictionary<string,object> and List<object> e.g.
// "[1,2,3]".FromJson<object>().GetType() == typeof(List<object>)
// "{\"Value\":10}".FromJson<object>().GetType() == typeof(Dictionary<string,object>)
// - No JIT Emit support to support AOT compilation on iOS
// - Attempts are made to NOT throw an exception if the JSON is corrupted or invalid: returns null instead.
// - Only public fields and property setters on classes/structs will be written to
//
// Limitations:
// - No JIT Emit support to parse structures quickly
// - Limited to parsing <2GB JSON files (due to int.MaxValue)
// - Parsing of abstract classes or interfaces is NOT supported and will throw an exception.
public static class JSONParser
{
[ThreadStatic]
private static Stack<List<string>> splitArrayPool;
[ThreadStatic]
private static StringBuilder stringBuilder;
[ThreadStatic]
private static Dictionary<Type, Dictionary<string, FieldInfo>> fieldInfoCache;
[ThreadStatic]
private static Dictionary<Type, Dictionary<string, PropertyInfo>> propertyInfoCache;
public static T FromJson<T>(this string json)
{
// Initialize, if needed, the ThreadStatic variables
propertyInfoCache ??= new Dictionary<Type, Dictionary<string, PropertyInfo>>();
fieldInfoCache ??= new Dictionary<Type, Dictionary<string, FieldInfo>>();
stringBuilder ??= new StringBuilder();
splitArrayPool ??= new Stack<List<string>>();
// Remove all whitespace not within strings to make parsing simpler
stringBuilder.Length = 0;
for (int i = 0; i < json.Length; i++)
{
char c = json[i];
if (c == '"')
{
i = AppendUntilStringEnd(true, i, json);
continue;
}
if (char.IsWhiteSpace(c))
{
continue;
}
stringBuilder.Append(c);
}
// Parse the thing!
return (T)ParseValue(typeof(T), stringBuilder.ToString());
}
internal static object ParseValue(Type type, string json)
{
if (type == typeof(string))
{
if (json.Length <= 2)
{
return string.Empty;
}
StringBuilder parseStringBuilder = new(json.Length);
for (int i = 1; i < json.Length - 1; ++i)
{
if (json[i] == '\\' && i + 1 < json.Length - 1)
{
int j = "\"\\nrtbf/".IndexOf(json[i + 1]);
if (j >= 0)
{
parseStringBuilder.Append("\"\\\n\r\t\b\f/"[j]);
++i;
continue;
}
if (json[i + 1] == 'u' && i + 5 < json.Length - 1)
{
if (uint.TryParse(json.AsSpan(i + 2, 4), System.Globalization.NumberStyles.AllowHexSpecifier, null, out uint c))
{
parseStringBuilder.Append((char)c);
i += 5;
continue;
}
}
}
parseStringBuilder.Append(json[i]);
}
return parseStringBuilder.ToString();
}
if (type.IsPrimitive)
{
var result = Convert.ChangeType(json, type, System.Globalization.CultureInfo.InvariantCulture);
return result;
}
if (type == typeof(decimal))
{
decimal.TryParse(json, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out decimal result);
return result;
}
if (json == "null")
{
return null;
}
if (type.IsEnum)
{
if (json[0] == '"')
{
json = json[1..^1];
}
try
{
return Enum.Parse(type, json, false);
}
catch
{
return 0;
}
}
if (type.IsArray)
{
Type arrayType = type.GetElementType();
if (json[0] != '[' || json[^1] != ']')
{
return null;
}
List<string> elems = Split(json);
Array newArray = Array.CreateInstance(arrayType, elems.Count);
for (int i = 0; i < elems.Count; i++)
{
newArray.SetValue(ParseValue(arrayType, elems[i]), i);
}
splitArrayPool.Push(elems);
return newArray;
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
{
Type listType = type.GetGenericArguments()[0];
if (json[0] != '[' || json[^1] != ']')
{
return null;
}
List<string> elems = Split(json);
var list = (IList)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count });
for (int i = 0; i < elems.Count; i++)
{
list.Add(ParseValue(listType, elems[i]));
}
splitArrayPool.Push(elems);
return list;
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
Type keyType, valueType;
{
Type[] args = type.GetGenericArguments();
keyType = args[0];
valueType = args[1];
}
// Refuse to parse dictionary keys that aren't of type string
if (keyType != typeof(string))
{
return null;
}
// Must be a valid dictionary element
if (json[0] != '{' || json[^1] != '}')
{
return null;
}
// The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
{
return null;
}
var dictionary = (IDictionary)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count / 2 });
for (int i = 0; i < elems.Count; i += 2)
{
if (elems[i].Length <= 2)
{
continue;
}
string keyValue = elems[i][1..^1];
object val = ParseValue(valueType, elems[i + 1]);
dictionary.Add(keyValue, val);
}
return dictionary;
}
if (type == typeof(object))
{
return ParseAnonymousValue(json);
}
if (json[0] == '{' && json[^1] == '}')
{
return ParseObject(type, json);
}
return null;
}
private static int AppendUntilStringEnd(bool appendEscapeCharacter, int startIdx, string json)
{
stringBuilder.Append(json[startIdx]);
for (int i = startIdx + 1; i < json.Length; i++)
{
if (json[i] == '\\')
{
if (appendEscapeCharacter)
{
stringBuilder.Append(json[i]);
}
stringBuilder.Append(json[i + 1]);
i++; // Skip next character as it is escaped
}
else if (json[i] == '"')
{
stringBuilder.Append(json[i]);
return i;
}
else
{
stringBuilder.Append(json[i]);
}
}
return json.Length - 1;
}
// Splits { <value>:<value>, <value>:<value> } and [ <value>, <value> ] into a list of <value> strings
private static List<string> Split(string json)
{
List<string> splitArray = splitArrayPool.Count > 0 ? splitArrayPool.Pop() : new List<string>();
splitArray.Clear();
if (json.Length == 2)
{
return splitArray;
}
int parseDepth = 0;
stringBuilder.Length = 0;
for (int i = 1; i < json.Length - 1; i++)
{
switch (json[i])
{
case '[':
case '{':
parseDepth++;
break;
case ']':
case '}':
parseDepth--;
break;
case '"':
i = AppendUntilStringEnd(true, i, json);
continue;
case ',':
case ':':
if (parseDepth == 0)
{
splitArray.Add(stringBuilder.ToString());
stringBuilder.Length = 0;
continue;
}
break;
}
stringBuilder.Append(json[i]);
}
splitArray.Add(stringBuilder.ToString());
return splitArray;
}
private static object ParseAnonymousValue(string json)
{
if (json.Length == 0)
{
return null;
}
if (json[0] == '{' && json[^1] == '}')
{
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
{
return null;
}
var dict = new Dictionary<string, object>(elems.Count / 2);
for (int i = 0; i < elems.Count; i += 2)
{
dict.Add(elems[i][1..^1], ParseAnonymousValue(elems[i + 1]));
}
return dict;
}
if (json[0] == '[' && json[^1] == ']')
{
List<string> items = Split(json);
var finalList = new List<object>(items.Count);
for (int i = 0; i < items.Count; i++)
{
finalList.Add(ParseAnonymousValue(items[i]));
}
return finalList;
}
if (json[0] == '"' && json[^1] == '"')
{
return ParseValue(typeof(string), json); // fix https://github.com/zanders3/json/issues/29
}
if (char.IsDigit(json[0]) || json[0] == '-')
{
if (json.Contains('.'))
{
double.TryParse(json, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out double result);
return result;
}
else
{
_ = int.TryParse(json, out int result);
return result;
}
}
if (json == "true")
{
return true;
}
if (json == "false")
{
return false;
}
// handles json == "null" as well as invalid JSON
return null;
}
private static Dictionary<string, T> CreateMemberNameDictionary<T>(T[] members)
where T : MemberInfo
{
Dictionary<string, T> nameToMember = new(StringComparer.OrdinalIgnoreCase);
for (int i = 0; i < members.Length; i++)
{
/*T member = members[i];
if (member.IsDefined(typeof(IgnoreDataMemberAttribute), true))
continue;
string name = member.Name;
if (member.IsDefined(typeof(DataMemberAttribute), true))
{
DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)Attribute.GetCustomAttribute(member, typeof(DataMemberAttribute), true);
if (!string.IsNullOrEmpty(dataMemberAttribute.Name))
name = dataMemberAttribute.Name;
}
nameToMember.Add(name, member);*/
// The above code is not working with .Net framework 2.0, so we ignore these attributes for compatibility reasons:
nameToMember.Add(members[i].Name, members[i]);
}
return nameToMember;
}
private static object ParseObject(Type type, string json)
{
object instance = FormatterServices.GetUninitializedObject(type);
// The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
{
return instance;
}
if (!fieldInfoCache.TryGetValue(type, out Dictionary<string, FieldInfo> nameToField))
{
nameToField = CreateMemberNameDictionary(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy));
fieldInfoCache.Add(type, nameToField);
}
if (!propertyInfoCache.TryGetValue(type, out Dictionary<string, PropertyInfo> nameToProperty))
{
nameToProperty = CreateMemberNameDictionary(type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy));
propertyInfoCache.Add(type, nameToProperty);
}
for (int i = 0; i < elems.Count; i += 2)
{
if (elems[i].Length <= 2)
{
continue;
}
string key = elems[i][1..^1];
string value = elems[i + 1];
if (nameToField.TryGetValue(key, out FieldInfo fieldInfo))
{
fieldInfo.SetValue(instance, ParseValue(fieldInfo.FieldType, value));
}
else if (nameToProperty.TryGetValue(key, out PropertyInfo propertyInfo))
{
propertyInfo.SetValue(instance, ParseValue(propertyInfo.PropertyType, value), null);
}
}
return instance;
}
}
}

View file

@ -1,11 +1,7 @@
// <copyright file="WindowsExplorerSort.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System.Collections.Generic;
namespace SystemTrayMenu.Helper
{
using System.Collections.Generic;
internal class WindowsExplorerSort : IComparer<string>
{
public int Compare(string x, string y)

View file

@ -1,14 +1,11 @@
// <copyright file="WindowsTaskbar.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using static SystemTrayMenu.DllImports.NativeMethods;
//Microsoft.WindowsAPICodePack.Taskbar.TaskbarManager do not have the bounds implemented?
namespace SystemTrayMenu.Helper
{
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using static SystemTrayMenu.DllImports.NativeMethods;
public enum TaskbarPosition
{
Unknown = -1,
@ -22,18 +19,43 @@ namespace SystemTrayMenu.Helper
{
private const string ClassName = "Shell_TrayWnd";
public Rectangle Bounds
{
get;
private set;
}
public TaskbarPosition Position
{
get;
private set;
}
public Point Location => Bounds.Location;
public Size Size => Bounds.Size;
//Always returns false under Windows 7
public bool AlwaysOnTop
{
get;
private set;
}
public bool AutoHide
{
get;
private set;
}
public WindowsTaskbar()
{
IntPtr taskbarHandle = User32FindWindow(ClassName, null);
APPBARDATA data = new()
APPBARDATA data = new APPBARDATA
{
cbSize = (uint)Marshal.SizeOf(typeof(APPBARDATA)),
hWnd = taskbarHandle,
hWnd = taskbarHandle
};
IntPtr result = Shell32SHAppBarMessage(ABM.GetTaskbarPos, ref data);
if (result == IntPtr.Zero)
{
//throw new InvalidOperationException();
Bounds = new Rectangle(20, 20, 20, 20);
}
else
@ -48,33 +70,5 @@ namespace SystemTrayMenu.Helper
AutoHide = (state & ABS.Autohide) == ABS.Autohide;
}
}
public Rectangle Bounds
{
get;
private set;
}
public TaskbarPosition Position
{
get;
private set;
}
public Point Location => Bounds.Location;
public Size Size => Bounds.Size;
public bool AlwaysOnTop
{
get;
private set;
}
public bool AutoHide
{
get;
private set;
}
}
}

View file

@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
TAMAHO SystemTrayMenu - browse and open your files easily
Copyright (C) 2022 Markus Hofknecht
TAMAHO SystemTrayMenu - an improved Windows toolbar
Copyright (C) 2020 Markus Hofknecht
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -652,7 +652,7 @@ You can contact me by mail Markus@Hofknecht.eu
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
TAMAHO SystemTrayMenu Copyright (C) 2022 Markus Hofknecht
TAMAHO SystemTrayMenu Copyright (C) 2020 Markus Hofknecht
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.

View file

@ -1,18 +1,29 @@
// <copyright file="BringWindowToTop.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
private const int SwRestore = 9;
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("kernel32.dll")]
private static extern uint GetCurrentThreadId();
[DllImport("user32.dll")]
private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool BringWindowToTop(IntPtr hWnd);
private const int SW_RESTORE = 9;
public static void ForceForegroundWindow(IntPtr hWnd)
{
@ -24,7 +35,7 @@ namespace SystemTrayMenu.DllImports
if (IsIconic(hWnd))
{
cmdShow = SwRestore;
cmdShow = SW_RESTORE;
}
if (foreThread != appThread)
@ -40,29 +51,5 @@ namespace SystemTrayMenu.DllImports
ShowWindow(hWnd, cmdShow);
}
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern uint GetCurrentThreadId();
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern bool BringWindowToTop(IntPtr hWnd);
}
}

View file

@ -1,25 +1,17 @@
// <copyright file="CreatePopupMenu.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
// The CreatePopupMenu function creates a drop-down menu, submenu, or shortcut menu. The menu is initially empty. You can insert or append menu items by using the InsertMenuItem function. You can also use the InsertMenu function to insert menu items and the AppendMenu function to append menu items.
[DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr CreatePopupMenu();
public static IntPtr User32CreatePopupMenu()
{
return CreatePopupMenu();
}
// The CreatePopupMenu function creates a drop-down menu, submenu, or shortcut menu. The menu is initially empty. You can insert or append menu items by using the InsertMenuItem function. You can also use the InsertMenu function to insert menu items and the AppendMenu function to append menu items.
[DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern IntPtr CreatePopupMenu();
}
}

View file

@ -1,40 +0,0 @@
// <copyright file="CreateRoundRectRgn.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
public static bool GetRegionRoundCorners(int width, int height, int widthEllipse, int heightEllipse, out System.Drawing.Region region)
{
bool success = false;
region = null;
IntPtr handle = CreateRoundRectRgn(0, 0, width, height, widthEllipse, heightEllipse);
if (handle != IntPtr.Zero)
{
region = System.Drawing.Region.FromHrgn(handle);
_ = DeleteObject(handle);
success = true;
}
return success;
}
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr CreateRoundRectRgn(
int nLeftRect, // x-coordinate of upper-left corner
int nTopRect, // y-coordinate of upper-left corner
int nRightRect, // x-coordinate of lower-right corner
int nBottomRect, // y-coordinate of lower-right corner
int nWidthEllipse, // width of ellipse
int nHeightEllipse); // height of ellipse
}
}

View file

@ -1,19 +0,0 @@
// <copyright file="DeleteObject.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
[DllImport("gdi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern int DeleteObject(IntPtr hIcon);
}
}

View file

@ -1,24 +1,16 @@
// <copyright file="DestroyIcon.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
[DllImport("User32.dll")]
private static extern int DestroyIcon(IntPtr hIcon);
public static void User32DestroyIcon(IntPtr hIcon)
{
_ = DestroyIcon(hIcon);
}
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern int DestroyIcon(IntPtr hIcon);
}
}

View file

@ -1,25 +1,17 @@
// <copyright file="DestroyMenu.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
// The DestroyMenu function destroys the specified menu and frees any memory that the menu occupies.
[DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool DestroyMenu(IntPtr hMenu);
public static bool User32DestroyMenu(IntPtr hMenu)
{
return DestroyMenu(hMenu);
}
// The DestroyMenu function destroys the specified menu and frees any memory that the menu occupies.
[DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern bool DestroyMenu(IntPtr hMenu);
}
}

View file

@ -1,24 +1,16 @@
// <copyright file="FindExecuteable.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System.Runtime.InteropServices;
using System.Text;
namespace SystemTrayMenu.DllImports
{
using System.Runtime.InteropServices;
using System.Text;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
private static extern int FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult);
public static void Shell32FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult)
{
_ = FindExecutable(lpFile, lpDirectory, lpResult);
}
[DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern int FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult);
}
}

View file

@ -1,24 +1,16 @@
// <copyright file="FindWindow.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public static IntPtr User32FindWindow(string lpClassName, string lpWindowName)
{
return FindWindow(lpClassName, lpWindowName);
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
}
}

View file

@ -0,0 +1,16 @@
using System;
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
public static partial class NativeMethods
{
[DllImport("gdi32.dll")]
private static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
public static int Gdi32GetDeviceCaps(IntPtr hdc, int nIndex)
{
return GetDeviceCaps(hdc, nIndex);
}
}
}

View file

@ -1,39 +1,89 @@
// <copyright file="GetIcon.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
//[StructLayout(LayoutKind.Sequential)]
//[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1815:Override equals and operator equals on value types", Justification = "<Pending>")]
//internal struct SHITEMID
//{
// public ushort cb;
// [MarshalAs(UnmanagedType.LPArray)]
// public byte[] abID;
//}
//[StructLayout(LayoutKind.Sequential)]
//[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1815:Override equals and operator equals on value types", Justification = "<Pending>")]
//internal struct ITEMIDLIST
//{
// public SHITEMID mkid;
//}
//[StructLayout(LayoutKind.Sequential)]
//[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1815:Override equals and operator equals on value types", Justification = "<Pending>")]
//internal struct BROWSEINFO
//{
// public IntPtr hwndOwner;
// public IntPtr pidlRoot;
// public IntPtr pszDisplayName;
// [MarshalAs(UnmanagedType.LPTStr)]
// public string lpszTitle;
// public uint ulFlags;
// public IntPtr lpfn;
// public int lParam;
// public IntPtr iImage;
//}
// Browsing for directory.
//public const uint BIF_RETURNONLYFSDIRS = 0x0001;
//public const uint BIF_DONTGOBELOWDOMAIN = 0x0002;
//public const uint BIF_STATUSTEXT = 0x0004;
//public const uint BIF_RETURNFSANCESTORS = 0x0008;
//public const uint BIF_EDITBOX = 0x0010;
//public const uint BIF_VALIDATE = 0x0020;
//public const uint BIF_NEWDIALOGSTYLE = 0x0040;
//public const uint BIF_USENEWUI = (BIF_NEWDIALOGSTYLE | BIF_EDITBOX);
//public const uint BIF_BROWSEINCLUDEURLS = 0x0080;
//public const uint BIF_BROWSEFORCOMPUTER = 0x1000;
//public const uint BIF_BROWSEFORPRINTER = 0x2000;
//public const uint BIF_BROWSEINCLUDEFILES = 0x4000;
//public const uint BIF_SHAREABLE = 0x8000;
public const uint ShgfiIcon = 0x000000100; // get icon
//public const uint SHGFI_DISPLAYNAME = 0x000000200; // get display name
//public const uint SHGFI_TYPENAME = 0x000000400; // get type name
//public const uint SHGFI_ATTRIBUTES = 0x000000800; // get attributes
//public const uint SHGFI_ICONLOCATION = 0x000001000; // get icon location
//public const uint SHGFI_EXETYPE = 0x000002000; // return exe type
public const uint ShgfiSYSICONINDEX = 0x000004000; // get system icon index
public const uint ShgfiLINKOVERLAY = 0x000008000; // put a link overlay on icon
//public const uint SHGFI_SELECTED = 0x000010000; // show icon in selected state
//public const uint SHGFI_ATTR_SPECIFIED = 0x000020000; // get only specified attributes
public const uint ShgfiLARGEICON = 0x000000000; // get large icon
public const uint ShgfiSMALLICON = 0x000000001; // get small icon
public const uint ShgfiOPENICON = 0x000000002; // get open icon
//public const uint SHGFI_SHELLICONSIZE = 0x000000004; // get shell size icon
//public const uint SHGFI_PIDL = 0x000000008; // pszPath is a pidl
//public const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute
//public const uint SHGFI_ADDOVERLAYS = 0x000000020; // apply the appropriate overlays
//public const uint SHGFI_OVERLAYINDEX = 0x000000040; // Get the index of the overlay
public const uint FileAttributeDirectory = 0x00000010;
public const uint FileAttributeNormal = 0x00000080;
public const int IldTransparent = 0x00000001;
/// <summary>
/// comctl32 ImageList_GetIcon(IntPtr himl, int i, int flags).
/// </summary>
/// <param name="himl">himl.</param>
/// <param name="i">i.</param>
/// <param name="flags">flags.</param>
/// <returns>IntPtr.</returns>
[DllImport("comctl32", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
[DllImport("comctl32")]
internal static extern IntPtr ImageList_GetIcon(
IntPtr himl,
int i,
int flags);
public static void Comctl32ImageListGetIcon(IntPtr hIcon)
{
_ = DestroyIcon(hIcon);
}
}
}

View file

@ -0,0 +1,17 @@
using System;
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
public static partial class NativeMethods
{
// Determines the default menu item on the specified menu
[DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern int GetMenuDefaultItem(IntPtr hMenu, bool fByPos, uint gmdiFlags);
public static int User32GetMenuDefaultItem(IntPtr hMenu, bool fByPos, uint gmdiFlags)
{
return GetMenuDefaultItem(hMenu, fByPos, gmdiFlags);
}
}
}

View file

@ -1,26 +0,0 @@
// <copyright file="IsTouchEnabled.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.DllImports
{
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
public static bool IsTouchEnabled()
{
const int MAXTOUCHES_INDEX = 95;
int maxTouches = GetSystemMetrics(MAXTOUCHES_INDEX);
return maxTouches > 0;
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern int GetSystemMetrics(int nIndex);
}
}

View file

@ -1,18 +1,16 @@
// <copyright file="RegisterHotKey.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
using System.Text;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
public static bool User32RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk)
{
return RegisterHotKey(hWnd, id, fsModifiers, vk);
@ -22,33 +20,5 @@ namespace SystemTrayMenu.DllImports
{
return UnregisterHotKey(hWnd, id);
}
public static uint User32MapVirtualKey(uint uCode, uint uMapType)
{
return MapVirtualKey(uCode, uMapType);
}
public static int User32GetKeyNameText(uint lParam, [Out] StringBuilder lpString, int nSize)
{
return GetKeyNameText(lParam, lpString, nSize);
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint virtualKeyCode);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern uint MapVirtualKey(uint uCode, uint uMapType);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern int GetKeyNameText(uint lParam, [Out] StringBuilder lpString, int nSize);
}
}

View file

@ -1,17 +1,18 @@
// <copyright file="SHAppBarMessage.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
[DllImport("shell32.dll", SetLastError = true)]
private static extern IntPtr SHAppBarMessage(ABM dwMessage, [In] ref APPBARDATA pData);
internal static IntPtr Shell32SHAppBarMessage(ABM dwMessage, [In] ref APPBARDATA pData)
{
return SHAppBarMessage(dwMessage, ref pData);
}
internal enum ABM : uint
{
New = 0x00000000,
@ -32,19 +33,16 @@ namespace SystemTrayMenu.DllImports
Left = 0,
Top = 1,
Right = 2,
Bottom = 3,
Bottom = 3
}
internal static IntPtr Shell32SHAppBarMessage(ABM dwMessage, [In] ref APPBARDATA pData)
internal static class ABS
{
return SHAppBarMessage(dwMessage, ref pData);
public const int Autohide = 0x0000001;
public const int AlwaysOnTop = 0x0000002;
}
[DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern IntPtr SHAppBarMessage(ABM dwMessage, [In] ref APPBARDATA pData);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
[StructLayout(LayoutKind.Sequential)]
internal struct APPBARDATA
{
public uint cbSize;
@ -55,7 +53,7 @@ namespace SystemTrayMenu.DllImports
public int lParam;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
[StructLayout(LayoutKind.Sequential)]
internal struct RECT
{
public int left;
@ -63,11 +61,5 @@ namespace SystemTrayMenu.DllImports
public int right;
public int bottom;
}
internal static class ABS
{
public const int Autohide = 0x0000001;
public const int AlwaysOnTop = 0x0000002;
}
}
}

View file

@ -1,25 +1,17 @@
// <copyright file="SHGetDesktopFolder.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
// Retrieves the IShellFolder interface for the desktop folder, which is the root of the Shell's namespace.
[DllImport("shell32.dll")]
private static extern int SHGetDesktopFolder(out IntPtr ppshf);
public static int Shell32SHGetDesktopFolder(out IntPtr ppshf)
{
return SHGetDesktopFolder(out ppshf);
}
// Retrieves the IShellFolder interface for the desktop folder, which is the root of the Shell's namespace.
[DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern int SHGetDesktopFolder(out IntPtr ppshf);
}
}

View file

@ -1,45 +1,37 @@
// <copyright file="SHGetFileInfo.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
private const int maxPath = 256;
[DllImport("Shell32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr SHGetFileInfo(
string pszPath,
uint dwFileAttributes,
ref SHFILEINFO psfi,
uint cbFileInfo,
uint uFlags
);
internal static IntPtr Shell32SHGetFileInfo(
string pszPath,
uint dwFileAttributes,
ref SHFILEINFO psfi,
uint cbFileInfo,
uint uFlags)
uint uFlags
)
{
return SHGetFileInfo(
pszPath,
return SHGetFileInfo(pszPath,
dwFileAttributes,
ref psfi,
cbFileInfo,
uFlags);
}
[DllImport("Shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern IntPtr SHGetFileInfo(
string pszPath,
uint dwFileAttributes,
ref SHFILEINFO psfi,
uint cbFileInfo,
uint uFlags);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
[StructLayout(LayoutKind.Sequential)]
internal struct SHFILEINFO
{
public const int NAMESIZE = 80;
@ -53,3 +45,5 @@ namespace SystemTrayMenu.DllImports
}
}
}

View file

@ -1,25 +1,16 @@
// <copyright file="SHGetFolderPath.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
using System.Text;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
[DllImport("shfolder.dll", CharSet = CharSet.Unicode)]
private static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder, IntPtr hToken, int dwFlags, StringBuilder lpszPath);
public static int ShfolderSHGetFolderPath(IntPtr hwndOwner, int nFolder, IntPtr hToken, int dwFlags, StringBuilder lpszPath)
{
return SHGetFolderPath(hwndOwner, nFolder, hToken, dwFlags, lpszPath);
}
[DllImport("shfolder.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder, IntPtr hToken, int dwFlags, StringBuilder lpszPath);
}
}

View file

@ -0,0 +1,14 @@
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
public static partial class NativeMethods
{
[DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();
public static void User32SetProcessDPIAware()
{
_ = SetProcessDPIAware();
}
}
}

View file

@ -1,39 +1,15 @@
// <copyright file="ShowInactiveTopmost.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace SystemTrayMenu.DllImports
{
using System.Runtime.InteropServices;
using System.Windows.Forms;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = -1;
private const uint SWP_NOACTIVATE = 0x0010;
public static void User32ShowInactiveTopmost(Form form)
{
if (form != null)
{
_ = ShowWindow(form.Handle, SW_SHOWNOACTIVATE);
SetWindowPos(
form.Handle.ToInt32(),
HWND_TOPMOST,
form.Left,
form.Top,
form.Width,
form.Height,
SWP_NOACTIVATE);
}
}
[DllImport("user32.dll", EntryPoint = "SetWindowPos", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
private static extern bool SetWindowPos(
int hWnd, // Window handle
int hWndInsertAfter, // Placement-order handle
@ -42,5 +18,16 @@ namespace SystemTrayMenu.DllImports
int cx, // Width
int cy, // Height
uint uFlags); // Window positioning flags
public static void User32ShowInactiveTopmost(Form form)
{
if (form != null)
{
_ = ShowWindow(form.Handle, SW_SHOWNOACTIVATE);
SetWindowPos(form.Handle.ToInt32(), HWND_TOPMOST,
form.Left, form.Top, form.Width, form.Height,
SWP_NOACTIVATE);
}
}
}
}

View file

@ -1,19 +1,11 @@
// <copyright file="ShowWindow.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
}

View file

@ -1,23 +1,15 @@
// <copyright file="StrCmpLogicalW.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern int StrCmpLogicalW(string x, string y);
public static int ShlwapiStrCmpLogicalW(string x, string y)
{
return StrCmpLogicalW(x, y);
}
[DllImport("shlwapi.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern int StrCmpLogicalW(string x, string y);
}
}

View file

@ -1,26 +1,18 @@
// <copyright file="StrRetToBuf.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
using System.Text;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
// Takes a STRRET structure returned by IShellFolder::GetDisplayNameOf, converts it to a string, and places the result in a buffer.
[DllImport("shlwapi.dll", EntryPoint = "StrRetToBuf", ExactSpelling = false, CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int StrRetToBuf(IntPtr pstr, IntPtr pidl, StringBuilder pszBuf, int cchBuf);
public static int ShlwapiStrRetToBuf(IntPtr pstr, IntPtr pidl, StringBuilder pszBuf, int cchBuf)
{
return StrRetToBuf(pstr, pidl, pszBuf, cchBuf);
}
// Takes a STRRET structure returned by IShellFolder::GetDisplayNameOf, converts it to a string, and places the result in a buffer.
[DllImport("shlwapi.dll", EntryPoint = "StrRetToBuf", ExactSpelling = false, SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern int StrRetToBuf(IntPtr pstr, IntPtr pidl, StringBuilder pszBuf, int cchBuf);
}
}

View file

@ -1,29 +1,32 @@
// <copyright file="TrackPopupMenuEx.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System;
using System.Runtime.InteropServices;
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
/// <summary>
/// Specifies how TrackPopupMenuEx positions the shortcut menu horizontally.
/// </summary>
// The TrackPopupMenuEx function displays a shortcut menu at the specified location and tracks the selection of items on the shortcut menu. The shortcut menu can appear anywhere on the screen.
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Unicode)]
private static extern uint TrackPopupMenuEx(IntPtr hmenu, TPM flags, int x, int y, IntPtr hwnd, IntPtr lptpm);
internal static uint User32TrackPopupMenuEx(IntPtr hmenu, TPM flags, int x, int y, IntPtr hwnd, IntPtr lptpm)
{
return TrackPopupMenuEx(hmenu, flags, x, y, hwnd, lptpm);
}
// Specifies how TrackPopupMenuEx positions the shortcut menu horizontally
[Flags]
internal enum TPM : uint
{
LEFTBUTTON = 0x0000, // LEFTALIGN = 0x0000, // TOPALIGN = 0x0000, // HORIZONTAL = 0x0000,
LEFTBUTTON = 0x0000,
RIGHTBUTTON = 0x0002,
LEFTALIGN = 0x0000,
CENTERALIGN = 0x0004,
RIGHTALIGN = 0x0008,
TOPALIGN = 0x0000,
VCENTERALIGN = 0x0010,
BOTTOMALIGN = 0x0020,
HORIZONTAL = 0x0000,
VERTICAL = 0x0040,
NONOTIFY = 0x0080,
RETURNCMD = 0x0100,
@ -33,27 +36,7 @@ namespace SystemTrayMenu.DllImports
VERPOSANIMATION = 0x1000,
VERNEGANIMATION = 0x2000,
NOANIMATION = 0x4000,
LAYOUTRTL = 0x8000,
LAYOUTRTL = 0x8000
}
/// <summary>
/// user32 TrackPopupMenuEx.
/// </summary>
/// <param name="hmenu">hmenu.</param>
/// <param name="flags">flags.</param>
/// <param name="x">x.</param>
/// <param name="y">y.</param>
/// <param name="hwnd">hwnd.</param>
/// <param name="lptpm">lptpm.</param>
/// <returns>uint.</returns>
internal static uint User32TrackPopupMenuEx(IntPtr hmenu, TPM flags, int x, int y, IntPtr hwnd, IntPtr lptpm)
{
return TrackPopupMenuEx(hmenu, flags, x, y, hwnd, lptpm);
}
// The TrackPopupMenuEx function displays a shortcut menu at the specified location and tracks the selection of items on the shortcut menu. The shortcut menu can appear anywhere on the screen.
[DllImport("user32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern uint TrackPopupMenuEx(IntPtr hmenu, TPM flags, int x, int y, IntPtr hwnd, IntPtr lptpm);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 860 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 732 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 732 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 517 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 883 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Some files were not shown because too many files have changed in this diff Show more