mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-26 12:08:37 +08:00
Compare commits
3 Commits
v1.78.2-de
...
copilot/ad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c421c9876b | ||
|
|
5db7fadefe | ||
|
|
4a1d75d189 |
2
.github/workflows/filter-links.yml
vendored
2
.github/workflows/filter-links.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
with:
|
||||
script: |
|
||||
const githubRepoRegex =
|
||||
/\[[^\]]*\]\((?!https?:\/\/github\.com\/user-attachments\/assets\/)[^\)]*https?:\/\/github\.com\/(?!user-attachments\/assets\/)[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+[^\s)]*\)|https?:\/\/github\.com\/(?!user-attachments\/assets\/)[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+[^\s)]*/gi;
|
||||
/\[[^\]]*\]\(https?:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+[^\s)]*\)|https?:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+[^\s)]*/gi;
|
||||
|
||||
// CASE 1: Comment
|
||||
if (context.payload.comment) {
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<NoWarn>$(NoWarn);NU1507;NU1701</NoWarn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="AWSSDK.Core" Version="4.0.3.15" />
|
||||
<PackageVersion Include="AWSSDK.EC2" Version="4.0.77" />
|
||||
<PackageVersion Include="AWSSDK.Core" Version="4.0.3.14" />
|
||||
<PackageVersion Include="AWSSDK.EC2" Version="4.0.76" />
|
||||
<PackageVersion Include="BouncyCastle.Cryptography" Version="2.6.2" />
|
||||
<PackageVersion Include="Castle.Core" Version="5.2.1" />
|
||||
<PackageVersion Include="ConsoleControl" Version="1.3.0" />
|
||||
@@ -25,7 +25,7 @@
|
||||
<PackageVersion Include="Microsoft.Data.SqlClient.SNI.runtime" Version="6.0.2" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyModel" Version="10.0.3" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.3" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
||||
<PackageVersion Include="Microsoft.NETCore.Platforms" Version="7.0.4" />
|
||||
<PackageVersion Include="Microsoft.NETCore.Targets" Version="5.0.0" />
|
||||
<PackageVersion Include="Microsoft.VisualStudio.TextTemplating.VSHost" Version="17.14.40265" />
|
||||
|
||||
@@ -56,6 +56,20 @@ namespace mRemoteNG.Connection
|
||||
[Browsable(false)]
|
||||
public bool PleaseConnect { get; set; }
|
||||
|
||||
private HostStatus _hostStatus = HostStatus.Unknown;
|
||||
|
||||
[Browsable(false)]
|
||||
public HostStatus HostStatus
|
||||
{
|
||||
get => _hostStatus;
|
||||
set
|
||||
{
|
||||
if (_hostStatus == value) return;
|
||||
_hostStatus = value;
|
||||
RaisePropertyChangedEvent(this, new PropertyChangedEventArgs(nameof(HostStatus)));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
9
mRemoteNG/Connection/HostStatus.cs
Normal file
9
mRemoteNG/Connection/HostStatus.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
public enum HostStatus
|
||||
{
|
||||
Unknown,
|
||||
Online,
|
||||
Offline
|
||||
}
|
||||
}
|
||||
9
mRemoteNG/Language/Language.Designer.cs
generated
9
mRemoteNG/Language/Language.Designer.cs
generated
@@ -6099,6 +6099,15 @@ namespace mRemoteNG.Resources.Language {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Show host status indicator in connection tree.
|
||||
/// </summary>
|
||||
internal static string ShowStatusIndicatorInTree {
|
||||
get {
|
||||
return ResourceManager.GetString("ShowStatusIndicatorInTree", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to &Show Help Text.
|
||||
/// </summary>
|
||||
|
||||
@@ -1606,6 +1606,9 @@ If you run into such an error, please create a new connection file!</value>
|
||||
<data name="ShowFullConsFilePath" xml:space="preserve">
|
||||
<value>Show full connections file path in window title</value>
|
||||
</data>
|
||||
<data name="ShowStatusIndicatorInTree" xml:space="preserve">
|
||||
<value>Show host status indicator in connection tree</value>
|
||||
</data>
|
||||
<data name="ShowLogonInfoOnTabs" xml:space="preserve">
|
||||
<value>Show logon information on tab names</value>
|
||||
</data>
|
||||
|
||||
@@ -94,5 +94,17 @@ namespace mRemoteNG.Properties {
|
||||
this["cbAppearancePageInOptionMenu"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool ShowStatusIndicatorInTree {
|
||||
get {
|
||||
return ((bool)(this["ShowStatusIndicatorInTree"]));
|
||||
}
|
||||
set {
|
||||
this["ShowStatusIndicatorInTree"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,5 +20,8 @@
|
||||
<Setting Name="cbAppearancePageInOptionMenu" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="ShowStatusIndicatorInTree" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
||||
133
mRemoteNG/Tools/ConnectionStatusChecker.cs
Normal file
133
mRemoteNG/Tools/ConnectionStatusChecker.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Tree;
|
||||
|
||||
namespace mRemoteNG.Tools
|
||||
{
|
||||
public class ConnectionStatusChecker : IDisposable
|
||||
{
|
||||
private Timer _timer;
|
||||
private ConnectionTreeModel _model;
|
||||
private bool _disposed;
|
||||
private const int CheckIntervalMs = 30000;
|
||||
private const int PingTimeoutMs = 5000;
|
||||
private const int MaxConcurrentChecks = 10;
|
||||
private readonly SemaphoreSlim _throttle = new(MaxConcurrentChecks, MaxConcurrentChecks);
|
||||
|
||||
public ConnectionStatusChecker(ConnectionTreeModel model)
|
||||
{
|
||||
_model = model;
|
||||
_timer = new Timer(CheckAllConnections, null, 0, CheckIntervalMs);
|
||||
}
|
||||
|
||||
public void UpdateModel(ConnectionTreeModel model)
|
||||
{
|
||||
_model = model;
|
||||
}
|
||||
|
||||
private void CheckAllConnections(object state)
|
||||
{
|
||||
if (!OptionsAppearancePage.Default.ShowStatusIndicatorInTree)
|
||||
return;
|
||||
|
||||
if (_model == null)
|
||||
return;
|
||||
|
||||
var connections = GetAllConnections(_model);
|
||||
foreach (var connection in connections)
|
||||
{
|
||||
Task.Run(() => CheckConnectionStatusThrottled(connection));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CheckConnectionStatusThrottled(ConnectionInfo connection)
|
||||
{
|
||||
await _throttle.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
CheckConnectionStatus(connection);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_throttle.Release();
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckConnectionStatus(ConnectionInfo connection)
|
||||
{
|
||||
if (string.IsNullOrEmpty(connection.Hostname))
|
||||
{
|
||||
connection.HostStatus = HostStatus.Unknown;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using var ping = new Ping();
|
||||
PingReply reply = ping.Send(connection.Hostname, PingTimeoutMs);
|
||||
connection.HostStatus = reply?.Status == IPStatus.Success
|
||||
? HostStatus.Online
|
||||
: HostStatus.Offline;
|
||||
}
|
||||
catch (PingException)
|
||||
{
|
||||
connection.HostStatus = HostStatus.Offline;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
connection.HostStatus = HostStatus.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ConnectionInfo> GetAllConnections(ConnectionTreeModel model)
|
||||
{
|
||||
var result = new List<ConnectionInfo>();
|
||||
foreach (var root in model.RootNodes)
|
||||
{
|
||||
CollectConnections(root, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void CollectConnections(ConnectionInfo node, List<ConnectionInfo> result)
|
||||
{
|
||||
if (node is ContainerInfo container)
|
||||
{
|
||||
foreach (var child in container.Children)
|
||||
{
|
||||
CollectConnections(child, result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(node);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed) return;
|
||||
if (disposing)
|
||||
{
|
||||
_timer?.Dispose();
|
||||
_timer = null;
|
||||
_throttle?.Dispose();
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Themes;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tools.Clipboard;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.ClickHandlers;
|
||||
@@ -29,6 +30,7 @@ namespace mRemoteNG.UI.Controls.ConnectionTree
|
||||
private readonly PuttySessionsManager _puttySessionsManager = PuttySessionsManager.Instance;
|
||||
private readonly StatusImageList _statusImageList = new();
|
||||
private ThemeManager _themeManager;
|
||||
private ConnectionStatusChecker _connectionStatusChecker;
|
||||
|
||||
private readonly ConnectionTreeSearchTextFilter _connectionTreeSearchTextFilter = new();
|
||||
|
||||
@@ -101,6 +103,7 @@ namespace mRemoteNG.UI.Controls.ConnectionTree
|
||||
{
|
||||
components?.Dispose();
|
||||
_statusImageList?.Dispose();
|
||||
_connectionStatusChecker?.Dispose();
|
||||
|
||||
_themeManager.ThemeChanged -= ThemeManagerOnThemeChanged;
|
||||
}
|
||||
@@ -202,6 +205,9 @@ namespace mRemoteNG.UI.Controls.ConnectionTree
|
||||
NodeSearcher = new NodeSearcher(newModel);
|
||||
ExecutePostSetupActions();
|
||||
AutoResizeColumn(Columns[0]);
|
||||
|
||||
_connectionStatusChecker?.Dispose();
|
||||
_connectionStatusChecker = new ConnectionStatusChecker(newModel);
|
||||
}
|
||||
|
||||
private void RegisterModelUpdateHandlers(ConnectionTreeModel newModel)
|
||||
@@ -234,7 +240,8 @@ namespace mRemoteNG.UI.Controls.ConnectionTree
|
||||
string property = propertyChangedEventArgs.PropertyName;
|
||||
if (property != nameof(ConnectionInfo.Name)
|
||||
&& property != nameof(ConnectionInfo.OpenConnections)
|
||||
&& property != nameof(ConnectionInfo.Icon))
|
||||
&& property != nameof(ConnectionInfo.Icon)
|
||||
&& property != nameof(ConnectionInfo.HostStatus))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
lblLanguage = new MrngLabel();
|
||||
chkShowFullConnectionsFilePathInTitle = new MrngCheckBox();
|
||||
chkShowDescriptionTooltipsInTree = new MrngCheckBox();
|
||||
chkShowStatusIndicatorInTree = new MrngCheckBox();
|
||||
chkShowSystemTrayIcon = new MrngCheckBox();
|
||||
chkMinimizeToSystemTray = new MrngCheckBox();
|
||||
chkCloseToSystemTray = new MrngCheckBox();
|
||||
@@ -76,18 +77,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
lblLanguage.TabIndex = 0;
|
||||
lblLanguage.Text = "Language";
|
||||
//
|
||||
// chkShowFullConnectionsFilePathInTitle
|
||||
//
|
||||
chkShowFullConnectionsFilePathInTitle._mice = MrngCheckBox.MouseState.OUT;
|
||||
chkShowFullConnectionsFilePathInTitle.AutoSize = true;
|
||||
chkShowFullConnectionsFilePathInTitle.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
chkShowFullConnectionsFilePathInTitle.Location = new System.Drawing.Point(3, 130);
|
||||
chkShowFullConnectionsFilePathInTitle.Name = "chkShowFullConnectionsFilePathInTitle";
|
||||
chkShowFullConnectionsFilePathInTitle.Size = new System.Drawing.Size(268, 17);
|
||||
chkShowFullConnectionsFilePathInTitle.TabIndex = 4;
|
||||
chkShowFullConnectionsFilePathInTitle.Text = "Show full connections file path in window title";
|
||||
chkShowFullConnectionsFilePathInTitle.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// chkShowDescriptionTooltipsInTree
|
||||
//
|
||||
chkShowDescriptionTooltipsInTree._mice = MrngCheckBox.MouseState.OUT;
|
||||
@@ -100,12 +89,36 @@ namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
chkShowDescriptionTooltipsInTree.Text = "Show description tooltips in connection tree";
|
||||
chkShowDescriptionTooltipsInTree.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// chkShowStatusIndicatorInTree
|
||||
//
|
||||
chkShowStatusIndicatorInTree._mice = MrngCheckBox.MouseState.OUT;
|
||||
chkShowStatusIndicatorInTree.AutoSize = true;
|
||||
chkShowStatusIndicatorInTree.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
chkShowStatusIndicatorInTree.Location = new System.Drawing.Point(3, 130);
|
||||
chkShowStatusIndicatorInTree.Name = "chkShowStatusIndicatorInTree";
|
||||
chkShowStatusIndicatorInTree.Size = new System.Drawing.Size(290, 17);
|
||||
chkShowStatusIndicatorInTree.TabIndex = 10;
|
||||
chkShowStatusIndicatorInTree.Text = "Show host status indicator in connection tree";
|
||||
chkShowStatusIndicatorInTree.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// chkShowFullConnectionsFilePathInTitle
|
||||
//
|
||||
chkShowFullConnectionsFilePathInTitle._mice = MrngCheckBox.MouseState.OUT;
|
||||
chkShowFullConnectionsFilePathInTitle.AutoSize = true;
|
||||
chkShowFullConnectionsFilePathInTitle.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
chkShowFullConnectionsFilePathInTitle.Location = new System.Drawing.Point(3, 153);
|
||||
chkShowFullConnectionsFilePathInTitle.Name = "chkShowFullConnectionsFilePathInTitle";
|
||||
chkShowFullConnectionsFilePathInTitle.Size = new System.Drawing.Size(268, 17);
|
||||
chkShowFullConnectionsFilePathInTitle.TabIndex = 4;
|
||||
chkShowFullConnectionsFilePathInTitle.Text = "Show full connections file path in window title";
|
||||
chkShowFullConnectionsFilePathInTitle.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// chkShowSystemTrayIcon
|
||||
//
|
||||
chkShowSystemTrayIcon._mice = MrngCheckBox.MouseState.OUT;
|
||||
chkShowSystemTrayIcon.AutoSize = true;
|
||||
chkShowSystemTrayIcon.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
chkShowSystemTrayIcon.Location = new System.Drawing.Point(3, 176);
|
||||
chkShowSystemTrayIcon.Location = new System.Drawing.Point(3, 199);
|
||||
chkShowSystemTrayIcon.Name = "chkShowSystemTrayIcon";
|
||||
chkShowSystemTrayIcon.Size = new System.Drawing.Size(178, 17);
|
||||
chkShowSystemTrayIcon.TabIndex = 5;
|
||||
@@ -117,7 +130,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
chkMinimizeToSystemTray._mice = MrngCheckBox.MouseState.OUT;
|
||||
chkMinimizeToSystemTray.AutoSize = true;
|
||||
chkMinimizeToSystemTray.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
chkMinimizeToSystemTray.Location = new System.Drawing.Point(3, 199);
|
||||
chkMinimizeToSystemTray.Location = new System.Drawing.Point(3, 222);
|
||||
chkMinimizeToSystemTray.Name = "chkMinimizeToSystemTray";
|
||||
chkMinimizeToSystemTray.Size = new System.Drawing.Size(147, 17);
|
||||
chkMinimizeToSystemTray.TabIndex = 6;
|
||||
@@ -129,7 +142,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
chkCloseToSystemTray._mice = MrngCheckBox.MouseState.OUT;
|
||||
chkCloseToSystemTray.AutoSize = true;
|
||||
chkCloseToSystemTray.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
chkCloseToSystemTray.Location = new System.Drawing.Point(3, 222);
|
||||
chkCloseToSystemTray.Location = new System.Drawing.Point(3, 245);
|
||||
chkCloseToSystemTray.Name = "chkCloseToSystemTray";
|
||||
chkCloseToSystemTray.Size = new System.Drawing.Size(129, 17);
|
||||
chkCloseToSystemTray.TabIndex = 7;
|
||||
@@ -143,13 +156,14 @@ namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
pnlOptions.Controls.Add(chkMinimizeToSystemTray);
|
||||
pnlOptions.Controls.Add(lblLanguageRestartRequired);
|
||||
pnlOptions.Controls.Add(chkShowSystemTrayIcon);
|
||||
pnlOptions.Controls.Add(chkShowStatusIndicatorInTree);
|
||||
pnlOptions.Controls.Add(chkShowDescriptionTooltipsInTree);
|
||||
pnlOptions.Controls.Add(lblLanguage);
|
||||
pnlOptions.Controls.Add(chkShowFullConnectionsFilePathInTitle);
|
||||
pnlOptions.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
pnlOptions.Location = new System.Drawing.Point(0, 30);
|
||||
pnlOptions.Name = "pnlOptions";
|
||||
pnlOptions.Size = new System.Drawing.Size(610, 267);
|
||||
pnlOptions.Size = new System.Drawing.Size(610, 290);
|
||||
pnlOptions.TabIndex = 8;
|
||||
//
|
||||
// lblRegistrySettingsUsedInfo
|
||||
@@ -183,6 +197,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
internal Controls.MrngLabel lblLanguage;
|
||||
internal MrngCheckBox chkShowFullConnectionsFilePathInTitle;
|
||||
internal MrngCheckBox chkShowDescriptionTooltipsInTree;
|
||||
internal MrngCheckBox chkShowStatusIndicatorInTree;
|
||||
internal MrngCheckBox chkShowSystemTrayIcon;
|
||||
internal MrngCheckBox chkMinimizeToSystemTray;
|
||||
internal MrngCheckBox chkCloseToSystemTray;
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
lblLanguageRestartRequired.Text =
|
||||
string.Format(Language.LanguageRestartRequired, Application.ProductName);
|
||||
chkShowDescriptionTooltipsInTree.Text = Language.ShowDescriptionTooltips;
|
||||
chkShowStatusIndicatorInTree.Text = Language.ShowStatusIndicatorInTree;
|
||||
chkShowFullConnectionsFilePathInTitle.Text = Language.ShowFullConsFilePath;
|
||||
chkShowSystemTrayIcon.Text = Language.AlwaysShowSysTrayIcon;
|
||||
chkMinimizeToSystemTray.Text = Language.MinimizeToSysTray;
|
||||
@@ -63,6 +64,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
}
|
||||
|
||||
chkShowDescriptionTooltipsInTree.Checked = Properties.OptionsAppearancePage.Default.ShowDescriptionTooltipsInTree;
|
||||
chkShowStatusIndicatorInTree.Checked = Properties.OptionsAppearancePage.Default.ShowStatusIndicatorInTree;
|
||||
chkShowFullConnectionsFilePathInTitle.Checked = Properties.OptionsAppearancePage.Default.ShowCompleteConsPathInTitle;
|
||||
chkShowSystemTrayIcon.Checked = Properties.OptionsAppearancePage.Default.ShowSystemTrayIcon;
|
||||
chkMinimizeToSystemTray.Checked = Properties.OptionsAppearancePage.Default.MinimizeToTray;
|
||||
@@ -82,6 +84,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
}
|
||||
|
||||
Properties.OptionsAppearancePage.Default.ShowDescriptionTooltipsInTree = chkShowDescriptionTooltipsInTree.Checked;
|
||||
Properties.OptionsAppearancePage.Default.ShowStatusIndicatorInTree = chkShowStatusIndicatorInTree.Checked;
|
||||
Properties.OptionsAppearancePage.Default.ShowCompleteConsPathInTitle = chkShowFullConnectionsFilePathInTitle.Checked;
|
||||
FrmMain.Default.ShowFullPathInTitle = chkShowFullConnectionsFilePathInTitle.Checked;
|
||||
|
||||
|
||||
@@ -127,10 +127,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
Properties.OptionsUpdatesPage.Default.UpdateProxyAuthUser = txtProxyUsername.Text;
|
||||
LegacyRijndaelCryptographyProvider cryptographyProvider = new();
|
||||
Properties.OptionsUpdatesPage.Default.UpdateProxyAuthPass = cryptographyProvider.Encrypt(txtProxyPassword.Text, Runtime.EncryptionKey);
|
||||
|
||||
// Mark that the user has explicitly configured their update preference so the
|
||||
// first-run preference prompt does not appear again.
|
||||
Properties.OptionsUpdatesPage.Default.CheckForUpdatesAsked = true;
|
||||
}
|
||||
|
||||
public override void LoadRegistrySettings()
|
||||
|
||||
@@ -416,15 +416,6 @@ namespace mRemoteNG.UI.Forms
|
||||
if (!CommonRegistrySettings.AllowCheckForUpdatesAutomatical) return;
|
||||
|
||||
if (Properties.OptionsUpdatesPage.Default.CheckForUpdatesAsked) return;
|
||||
|
||||
// If the user has already explicitly disabled automatic updates via settings, don't ask again
|
||||
if (!Properties.OptionsUpdatesPage.Default.CheckForUpdatesOnStartup)
|
||||
{
|
||||
Properties.OptionsUpdatesPage.Default.CheckForUpdatesAsked = true;
|
||||
Properties.OptionsUpdatesPage.Default.Save();
|
||||
return;
|
||||
}
|
||||
|
||||
string[] commandButtons =
|
||||
[
|
||||
Language.AskUpdatesCommandRecommended,
|
||||
@@ -434,25 +425,16 @@ namespace mRemoteNG.UI.Forms
|
||||
|
||||
CTaskDialog.ShowTaskDialogBox(this, GeneralAppInfo.ProductName, Language.AskUpdatesMainInstruction, string.Format(Language.AskUpdatesContent, GeneralAppInfo.ProductName), "", "", "", "", string.Join(" | ", commandButtons), ETaskDialogButtons.None, ESysIcons.Question, ESysIcons.Question);
|
||||
|
||||
if (CTaskDialog.CommandButtonResult == 0)
|
||||
if (CTaskDialog.CommandButtonResult == 0 | CTaskDialog.CommandButtonResult == 1)
|
||||
{
|
||||
// Use Recommended Settings: enable automatic updates with the default frequency
|
||||
Properties.OptionsUpdatesPage.Default.CheckForUpdatesOnStartup = true;
|
||||
if (Properties.OptionsUpdatesPage.Default.CheckForUpdatesFrequencyDays < 1)
|
||||
Properties.OptionsUpdatesPage.Default.CheckForUpdatesFrequencyDays = 14;
|
||||
Properties.OptionsUpdatesPage.Default.CheckForUpdatesAsked = true;
|
||||
Properties.OptionsUpdatesPage.Default.Save();
|
||||
}
|
||||
else if (CTaskDialog.CommandButtonResult == 1)
|
||||
{
|
||||
// Customize: let the user configure update settings manually, then open Options
|
||||
Properties.OptionsUpdatesPage.Default.CheckForUpdatesAsked = true;
|
||||
Properties.OptionsUpdatesPage.Default.Save();
|
||||
AppWindows.Show(WindowType.Options);
|
||||
if (AppWindows.OptionsFormWindow != null)
|
||||
AppWindows.OptionsFormWindow.SetActivatedPage(Language.Updates);
|
||||
}
|
||||
// For "Ask Later" (button 2), CheckForUpdatesAsked remains false so the dialog will show again next startup
|
||||
|
||||
if (CTaskDialog.CommandButtonResult != 1) return;
|
||||
|
||||
AppWindows.Show(WindowType.Options);
|
||||
if (AppWindows.OptionsFormWindow != null)
|
||||
AppWindows.OptionsFormWindow.SetActivatedPage(Language.Updates);
|
||||
}
|
||||
|
||||
private async Task CheckForUpdates()
|
||||
|
||||
@@ -57,6 +57,11 @@ namespace mRemoteNG.UI
|
||||
return $"Connection_{icon}_{status}";
|
||||
}
|
||||
|
||||
private static string BuildStatusIconName(string baseKey, HostStatus hostStatus)
|
||||
{
|
||||
return $"{baseKey}_{hostStatus}";
|
||||
}
|
||||
|
||||
private const string DefaultConnectionIcon = "";
|
||||
|
||||
private string GetConnectionIcon(ConnectionInfo connection)
|
||||
@@ -67,19 +72,80 @@ namespace mRemoteNG.UI
|
||||
}
|
||||
|
||||
bool connected = connection.OpenConnections.Count > 0;
|
||||
string name = BuildConnectionIconName(connection.Icon, connected);
|
||||
string baseKey = BuildConnectionIconName(connection.Icon, connected);
|
||||
|
||||
bool showStatusIndicator = Properties.OptionsAppearancePage.Default.ShowStatusIndicatorInTree;
|
||||
string name = showStatusIndicator
|
||||
? BuildStatusIconName(baseKey, connection.HostStatus)
|
||||
: baseKey;
|
||||
|
||||
if (ImageList.Images.ContainsKey(name)) return name;
|
||||
|
||||
Icon image = ConnectionIcon.FromString(connection.Icon);
|
||||
if (image == null)
|
||||
{
|
||||
return DefaultConnectionIcon;
|
||||
}
|
||||
|
||||
ImageList.Images.Add(BuildConnectionIconName(connection.Icon, false), image);
|
||||
ImageList.Images.Add(BuildConnectionIconName(connection.Icon, true), Overlay(image, Properties.Resources.ConnectedOverlay));
|
||||
Bitmap defaultBitmap = image.ToBitmap();
|
||||
Bitmap playBitmap = Overlay(image, Properties.Resources.ConnectedOverlay);
|
||||
|
||||
if (showStatusIndicator)
|
||||
{
|
||||
foreach (HostStatus status in Enum.GetValues<HostStatus>())
|
||||
{
|
||||
Color barColor = GetStatusColor(status);
|
||||
string defaultStatusKey = BuildStatusIconName(BuildConnectionIconName(connection.Icon, false), status);
|
||||
string playStatusKey = BuildStatusIconName(BuildConnectionIconName(connection.Icon, true), status);
|
||||
|
||||
if (!ImageList.Images.ContainsKey(defaultStatusKey))
|
||||
ImageList.Images.Add(defaultStatusKey, AddStatusBar(defaultBitmap, barColor));
|
||||
if (!ImageList.Images.ContainsKey(playStatusKey))
|
||||
ImageList.Images.Add(playStatusKey, AddStatusBar(playBitmap, barColor));
|
||||
}
|
||||
|
||||
defaultBitmap.Dispose();
|
||||
playBitmap.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ImageList.Images.ContainsKey(BuildConnectionIconName(connection.Icon, false)))
|
||||
ImageList.Images.Add(BuildConnectionIconName(connection.Icon, false), defaultBitmap);
|
||||
else
|
||||
defaultBitmap.Dispose();
|
||||
|
||||
if (!ImageList.Images.ContainsKey(BuildConnectionIconName(connection.Icon, true)))
|
||||
ImageList.Images.Add(BuildConnectionIconName(connection.Icon, true), playBitmap);
|
||||
else
|
||||
playBitmap.Dispose();
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
private static Color GetStatusColor(HostStatus status)
|
||||
{
|
||||
return status switch
|
||||
{
|
||||
HostStatus.Online => Color.FromArgb(0, 180, 0),
|
||||
HostStatus.Offline => Color.FromArgb(200, 0, 0),
|
||||
_ => Color.FromArgb(160, 160, 160)
|
||||
};
|
||||
}
|
||||
|
||||
private static Bitmap AddStatusBar(Bitmap source, Color barColor)
|
||||
{
|
||||
Bitmap result = new(source.Width, source.Height);
|
||||
using (Graphics gr = Graphics.FromImage(result))
|
||||
{
|
||||
gr.DrawImage(source, new Rectangle(0, 0, source.Width, source.Height));
|
||||
using SolidBrush brush = new(barColor);
|
||||
gr.FillRectangle(brush, 0, 0, 3, source.Height);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Bitmap Overlay(Icon background, Image foreground)
|
||||
{
|
||||
Bitmap result = new(background.ToBitmap(), new Size(16, 16));
|
||||
|
||||
@@ -553,10 +553,10 @@
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="chromiumembeddedframework.runtime.win-x64" Version="145.0.26" />
|
||||
<PackageReference Update="chromiumembeddedframework.runtime.win-x64" Version="144.0.12" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(Platform)'=='arm64'">
|
||||
<PackageReference Update="chromiumembeddedframework.runtime.win-arm64" Version="145.0.26" />
|
||||
<PackageReference Update="chromiumembeddedframework.runtime.win-arm64" Version="144.0.12" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
|
||||
|
||||
Reference in New Issue
Block a user