diff --git a/mRemoteNG/Connection/ConnectionInitiator.cs b/mRemoteNG/Connection/ConnectionInitiator.cs
index c0ab7604c..c18bf5ec4 100644
--- a/mRemoteNG/Connection/ConnectionInitiator.cs
+++ b/mRemoteNG/Connection/ConnectionInitiator.cs
@@ -348,6 +348,7 @@ namespace mRemoteNG.Connection
private static void SetConnectionFormEventHandlers(ProtocolBase newProtocol, Form connectionForm)
{
newProtocol.Closed += ((ConnectionWindow)connectionForm).Prot_Event_Closed;
+ newProtocol.TitleChanged += ((ConnectionWindow)connectionForm).Prot_Event_TitleChanged;
}
private void SetConnectionEventHandlers(ProtocolBase newProtocol)
diff --git a/mRemoteNG/Connection/Protocol/ProtocolBase.cs b/mRemoteNG/Connection/Protocol/ProtocolBase.cs
index 6664274a1..3835a85e3 100644
--- a/mRemoteNG/Connection/Protocol/ProtocolBase.cs
+++ b/mRemoteNG/Connection/Protocol/ProtocolBase.cs
@@ -305,6 +305,15 @@ namespace mRemoteNG.Connection.Protocol
remove => ClosedEvent = (ClosedEventHandler)Delegate.Remove(ClosedEvent, value);
}
+ public delegate void TitleChangedEventHandler(object sender, string newTitle);
+
+ private TitleChangedEventHandler TitleChangedEvent;
+
+ public event TitleChangedEventHandler TitleChanged
+ {
+ add => TitleChangedEvent = (TitleChangedEventHandler)Delegate.Combine(TitleChangedEvent, value);
+ remove => TitleChangedEvent = (TitleChangedEventHandler)Delegate.Remove(TitleChangedEvent, value);
+ }
public void Event_Closing(object sender)
{
@@ -336,6 +345,11 @@ namespace mRemoteNG.Connection.Protocol
ErrorOccuredEvent?.Invoke(sender, errorMsg, errorCode);
}
+ protected void Event_TitleChanged(object sender, string newTitle)
+ {
+ TitleChangedEvent?.Invoke(sender, newTitle);
+ }
+
protected void Event_ReconnectGroupCloseClicked()
{
Close();
diff --git a/mRemoteNG/Connection/Protocol/PuttyBase.cs b/mRemoteNG/Connection/Protocol/PuttyBase.cs
index 0ac453446..fe71f7bda 100644
--- a/mRemoteNG/Connection/Protocol/PuttyBase.cs
+++ b/mRemoteNG/Connection/Protocol/PuttyBase.cs
@@ -28,8 +28,11 @@ namespace mRemoteNG.Connection.Protocol
public class PuttyBase : ProtocolBase
{
private const int IDM_RECONF = 0x50; // PuTTY Settings Menu ID
+ private const int TitleMonitorIntervalMs = 500;
private bool _isPuttyNg;
private readonly DisplayProperties _display = new();
+ private System.Threading.Timer _titleMonitorTimer;
+ private string _lastWindowTitle;
#region Public Properties
@@ -333,6 +336,11 @@ namespace mRemoteNG.Connection.Protocol
Resize(this, new EventArgs());
base.Connect();
+
+ // Start monitoring PuTTY window title for dynamic tab naming
+ _lastWindowTitle = PuttyProcess.MainWindowTitle;
+ _titleMonitorTimer = new System.Threading.Timer(MonitorPuttyTitle, null, TitleMonitorIntervalMs, TitleMonitorIntervalMs);
+
return true;
}
catch (Exception ex)
@@ -363,6 +371,32 @@ namespace mRemoteNG.Connection.Protocol
}
}
+ private void MonitorPuttyTitle(object state)
+ {
+ try
+ {
+ if (PuttyProcess == null || PuttyProcess.HasExited)
+ {
+ _titleMonitorTimer?.Dispose();
+ return;
+ }
+
+ PuttyProcess.Refresh();
+ string currentTitle = PuttyProcess.MainWindowTitle;
+ if (currentTitle != _lastWindowTitle)
+ {
+ _lastWindowTitle = currentTitle;
+ Event_TitleChanged(this, currentTitle);
+ }
+ }
+ catch (Exception ex)
+ {
+ _titleMonitorTimer?.Dispose();
+ Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg,
+ "PuTTY title monitoring stopped: " + ex.Message, true);
+ }
+ }
+
protected override void Resize(object sender, EventArgs e)
{
try
@@ -403,6 +437,9 @@ namespace mRemoteNG.Connection.Protocol
public override void Close()
{
+ _titleMonitorTimer?.Dispose();
+ _titleMonitorTimer = null;
+
try
{
if (PuttyProcess.HasExited == false)
diff --git a/mRemoteNG/Language/Language.Designer.cs b/mRemoteNG/Language/Language.Designer.cs
index 92979144c..eb1abbe35 100644
--- a/mRemoteNG/Language/Language.Designer.cs
+++ b/mRemoteNG/Language/Language.Designer.cs
@@ -6117,6 +6117,15 @@ namespace mRemoteNG.Resources.Language {
}
}
+ ///
+ /// Looks up a localized string similar to Use terminal title for tab names (SSH/Telnet).
+ ///
+ internal static string UseTerminalTitleForTabs {
+ get {
+ return ResourceManager.GetString("UseTerminalTitleForTabs", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Show Text.
///
diff --git a/mRemoteNG/Language/Language.resx b/mRemoteNG/Language/Language.resx
index 8b08a641f..acdd83bec 100644
--- a/mRemoteNG/Language/Language.resx
+++ b/mRemoteNG/Language/Language.resx
@@ -1600,6 +1600,9 @@ If you run into such an error, please create a new connection file!
Show protocols on tab names
+
+ Use terminal title for tab names (SSH/Telnet)
+
Single click on connection opens it
diff --git a/mRemoteNG/Properties/OptionsTabsPanelsPage.Designer.cs b/mRemoteNG/Properties/OptionsTabsPanelsPage.Designer.cs
index b14cd22c3..89da0bff8 100644
--- a/mRemoteNG/Properties/OptionsTabsPanelsPage.Designer.cs
+++ b/mRemoteNG/Properties/OptionsTabsPanelsPage.Designer.cs
@@ -166,5 +166,17 @@ namespace mRemoteNG.Properties {
this["BindConnectionsAndConfigPanels"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("False")]
+ public bool UseTerminalTitleForTabs {
+ get {
+ return ((bool)(this["UseTerminalTitleForTabs"]));
+ }
+ set {
+ this["UseTerminalTitleForTabs"] = value;
+ }
+ }
}
}
diff --git a/mRemoteNG/Properties/OptionsTabsPanelsPage.settings b/mRemoteNG/Properties/OptionsTabsPanelsPage.settings
index 2f7159637..32d9f2316 100644
--- a/mRemoteNG/Properties/OptionsTabsPanelsPage.settings
+++ b/mRemoteNG/Properties/OptionsTabsPanelsPage.settings
@@ -38,5 +38,8 @@
False
+
+ False
+
\ No newline at end of file
diff --git a/mRemoteNG/UI/Forms/OptionsPages/TabsPanelsPage.Designer.cs b/mRemoteNG/UI/Forms/OptionsPages/TabsPanelsPage.Designer.cs
index d20ca2325..ccbbd31fd 100644
--- a/mRemoteNG/UI/Forms/OptionsPages/TabsPanelsPage.Designer.cs
+++ b/mRemoteNG/UI/Forms/OptionsPages/TabsPanelsPage.Designer.cs
@@ -41,6 +41,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
chkShowLogonInfoOnTabs = new MrngCheckBox();
chkDoubleClickClosesTab = new MrngCheckBox();
chkShowProtocolOnTabs = new MrngCheckBox();
+ chkUseTerminalTitleForTabs = new MrngCheckBox();
chkCreateEmptyPanelOnStart = new MrngCheckBox();
chkBindConnectionsAndConfigPanels = new MrngCheckBox();
txtBoxPanelName = new MrngTextBox();
@@ -80,7 +81,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
chkIdentifyQuickConnectTabs._mice = MrngCheckBox.MouseState.OUT;
chkIdentifyQuickConnectTabs.AutoSize = true;
chkIdentifyQuickConnectTabs.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
- chkIdentifyQuickConnectTabs.Location = new System.Drawing.Point(3, 72);
+ chkIdentifyQuickConnectTabs.Location = new System.Drawing.Point(3, 95);
chkIdentifyQuickConnectTabs.Name = "chkIdentifyQuickConnectTabs";
chkIdentifyQuickConnectTabs.Size = new System.Drawing.Size(315, 17);
chkIdentifyQuickConnectTabs.TabIndex = 4;
@@ -104,7 +105,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
chkAlwaysShowPanelSelectionDlg._mice = MrngCheckBox.MouseState.OUT;
chkAlwaysShowPanelSelectionDlg.AutoSize = true;
chkAlwaysShowPanelSelectionDlg.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
- chkAlwaysShowPanelSelectionDlg.Location = new System.Drawing.Point(3, 118);
+ chkAlwaysShowPanelSelectionDlg.Location = new System.Drawing.Point(3, 141);
chkAlwaysShowPanelSelectionDlg.Name = "chkAlwaysShowPanelSelectionDlg";
chkAlwaysShowPanelSelectionDlg.Size = new System.Drawing.Size(347, 17);
chkAlwaysShowPanelSelectionDlg.TabIndex = 6;
@@ -128,7 +129,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
chkDoubleClickClosesTab._mice = MrngCheckBox.MouseState.OUT;
chkDoubleClickClosesTab.AutoSize = true;
chkDoubleClickClosesTab.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
- chkDoubleClickClosesTab.Location = new System.Drawing.Point(3, 95);
+ chkDoubleClickClosesTab.Location = new System.Drawing.Point(3, 118);
chkDoubleClickClosesTab.Name = "chkDoubleClickClosesTab";
chkDoubleClickClosesTab.Size = new System.Drawing.Size(170, 17);
chkDoubleClickClosesTab.TabIndex = 5;
@@ -147,12 +148,24 @@ namespace mRemoteNG.UI.Forms.OptionsPages
chkShowProtocolOnTabs.Text = "Show protocols on tab names";
chkShowProtocolOnTabs.UseVisualStyleBackColor = true;
//
+ // chkUseTerminalTitleForTabs
+ //
+ chkUseTerminalTitleForTabs._mice = MrngCheckBox.MouseState.OUT;
+ chkUseTerminalTitleForTabs.AutoSize = true;
+ chkUseTerminalTitleForTabs.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
+ chkUseTerminalTitleForTabs.Location = new System.Drawing.Point(3, 72);
+ chkUseTerminalTitleForTabs.Name = "chkUseTerminalTitleForTabs";
+ chkUseTerminalTitleForTabs.Size = new System.Drawing.Size(270, 17);
+ chkUseTerminalTitleForTabs.TabIndex = 10;
+ chkUseTerminalTitleForTabs.Text = "Use terminal title for tab names (SSH/Telnet)";
+ chkUseTerminalTitleForTabs.UseVisualStyleBackColor = true;
+ //
// chkCreateEmptyPanelOnStart
//
chkCreateEmptyPanelOnStart._mice = MrngCheckBox.MouseState.OUT;
chkCreateEmptyPanelOnStart.AutoSize = true;
chkCreateEmptyPanelOnStart.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
- chkCreateEmptyPanelOnStart.Location = new System.Drawing.Point(3, 141);
+ chkCreateEmptyPanelOnStart.Location = new System.Drawing.Point(3, 164);
chkCreateEmptyPanelOnStart.Name = "chkCreateEmptyPanelOnStart";
chkCreateEmptyPanelOnStart.Size = new System.Drawing.Size(271, 17);
chkCreateEmptyPanelOnStart.TabIndex = 7;
@@ -165,7 +178,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
chkBindConnectionsAndConfigPanels._mice = MrngCheckBox.MouseState.OUT;
chkBindConnectionsAndConfigPanels.AutoSize = true;
chkBindConnectionsAndConfigPanels.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
- chkBindConnectionsAndConfigPanels.Location = new System.Drawing.Point(3, 210);
+ chkBindConnectionsAndConfigPanels.Location = new System.Drawing.Point(3, 233);
chkBindConnectionsAndConfigPanels.Name = "chkBindConnectionsAndConfigPanels";
chkBindConnectionsAndConfigPanels.Size = new System.Drawing.Size(350, 17);
chkBindConnectionsAndConfigPanels.TabIndex = 9;
@@ -175,7 +188,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
// txtBoxPanelName
//
txtBoxPanelName.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
- txtBoxPanelName.Location = new System.Drawing.Point(35, 177);
+ txtBoxPanelName.Location = new System.Drawing.Point(35, 200);
txtBoxPanelName.Name = "txtBoxPanelName";
txtBoxPanelName.Size = new System.Drawing.Size(213, 22);
txtBoxPanelName.TabIndex = 8;
@@ -183,7 +196,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
// lblPanelName
//
lblPanelName.AutoSize = true;
- lblPanelName.Location = new System.Drawing.Point(32, 161);
+ lblPanelName.Location = new System.Drawing.Point(32, 184);
lblPanelName.Name = "lblPanelName";
lblPanelName.Size = new System.Drawing.Size(69, 13);
lblPanelName.TabIndex = 9;
@@ -194,6 +207,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
pnlOptions.Controls.Add(chkAlwaysShowPanelTabs);
pnlOptions.Controls.Add(lblPanelName);
pnlOptions.Controls.Add(chkShowProtocolOnTabs);
+ pnlOptions.Controls.Add(chkUseTerminalTitleForTabs);
pnlOptions.Controls.Add(txtBoxPanelName);
pnlOptions.Controls.Add(chkDoubleClickClosesTab);
pnlOptions.Controls.Add(chkCreateEmptyPanelOnStart);
@@ -206,7 +220,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
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, 240);
+ pnlOptions.Size = new System.Drawing.Size(610, 263);
pnlOptions.TabIndex = 10;
//
// lblRegistrySettingsUsedInfo
@@ -243,6 +257,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
internal MrngCheckBox chkShowLogonInfoOnTabs;
internal MrngCheckBox chkDoubleClickClosesTab;
internal MrngCheckBox chkShowProtocolOnTabs;
+ internal MrngCheckBox chkUseTerminalTitleForTabs;
private MrngCheckBox chkCreateEmptyPanelOnStart;
private MrngCheckBox chkBindConnectionsAndConfigPanels;
private Controls.MrngTextBox txtBoxPanelName;
diff --git a/mRemoteNG/UI/Forms/OptionsPages/TabsPanelsPage.cs b/mRemoteNG/UI/Forms/OptionsPages/TabsPanelsPage.cs
index c7f52e365..142f4b40f 100644
--- a/mRemoteNG/UI/Forms/OptionsPages/TabsPanelsPage.cs
+++ b/mRemoteNG/UI/Forms/OptionsPages/TabsPanelsPage.cs
@@ -42,6 +42,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
chkOpenNewTabRightOfSelected.Text = Language.OpenNewTabRight;
chkShowLogonInfoOnTabs.Text = Language.ShowLogonInfoOnTabs;
chkShowProtocolOnTabs.Text = Language.ShowProtocolOnTabs;
+ chkUseTerminalTitleForTabs.Text = Language.UseTerminalTitleForTabs;
chkIdentifyQuickConnectTabs.Text = Language.IdentifyQuickConnectTabs;
chkDoubleClickClosesTab.Text = Language.DoubleClickTabClosesIt;
chkAlwaysShowPanelSelectionDlg.Text = Language.AlwaysShowPanelSelection;
@@ -73,6 +74,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
chkShowLogonInfoOnTabs.Checked = Properties.OptionsTabsPanelsPage.Default.ShowLogonInfoOnTabs;
chkShowProtocolOnTabs.Checked = Properties.OptionsTabsPanelsPage.Default.ShowProtocolOnTabs;
+ chkUseTerminalTitleForTabs.Checked = Properties.OptionsTabsPanelsPage.Default.UseTerminalTitleForTabs;
chkIdentifyQuickConnectTabs.Checked = Properties.OptionsTabsPanelsPage.Default.IdentifyQuickConnectTabs;
chkDoubleClickClosesTab.Checked = Properties.OptionsTabsPanelsPage.Default.DoubleClickOnTabClosesIt;
chkAlwaysShowPanelSelectionDlg.Checked = Properties.OptionsTabsPanelsPage.Default.AlwaysShowPanelSelectionDlg;
@@ -105,6 +107,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
Properties.OptionsTabsPanelsPage.Default.ShowLogonInfoOnTabs = chkShowLogonInfoOnTabs.Checked;
Properties.OptionsTabsPanelsPage.Default.ShowProtocolOnTabs = chkShowProtocolOnTabs.Checked;
+ Properties.OptionsTabsPanelsPage.Default.UseTerminalTitleForTabs = chkUseTerminalTitleForTabs.Checked;
Properties.OptionsTabsPanelsPage.Default.IdentifyQuickConnectTabs = chkIdentifyQuickConnectTabs.Checked;
Properties.OptionsTabsPanelsPage.Default.DoubleClickOnTabClosesIt = chkDoubleClickClosesTab.Checked;
Properties.OptionsTabsPanelsPage.Default.AlwaysShowPanelSelectionDlg = chkAlwaysShowPanelSelectionDlg.Checked;
diff --git a/mRemoteNG/UI/Window/ConnectionWindow.cs b/mRemoteNG/UI/Window/ConnectionWindow.cs
index 4fc122e3d..63332e69d 100644
--- a/mRemoteNG/UI/Window/ConnectionWindow.cs
+++ b/mRemoteNG/UI/Window/ConnectionWindow.cs
@@ -832,6 +832,26 @@ namespace mRemoteNG.UI.Window
Invoke(new Action(() => tabPage.Close()));
}
+ public void Prot_Event_TitleChanged(object sender, string newTitle)
+ {
+ if (!Properties.OptionsTabsPanelsPage.Default.UseTerminalTitleForTabs) return;
+ ProtocolBase protocolBase = sender as ProtocolBase;
+ if (!(protocolBase?.InterfaceControl?.Parent is ConnectionTab tabPage)) return;
+ if (tabPage.Disposing || tabPage.IsDisposed) return;
+ if (IsDisposed || Disposing) return;
+
+ string connectionName = protocolBase.InterfaceControl.Info?.Name ?? "";
+ string tabText = string.IsNullOrEmpty(newTitle)
+ ? connectionName
+ : $"{newTitle} ({connectionName})";
+ tabText = tabText.Replace("&", "&&");
+
+ if (tabPage.InvokeRequired)
+ tabPage.Invoke(new Action(() => tabPage.TabText = tabText));
+ else
+ tabPage.TabText = tabText;
+ }
+
#endregion
}
}