Compare commits

...

14 Commits

Author SHA1 Message Date
David Sparer
7305bc4441 Merge branch 'develop' into bug/ssh_focus
# Conflicts:
#	mRemoteV1/UI/Forms/frmMain.cs
2019-09-01 18:58:16 -05:00
David Sparer
2c47c857ec fixed array out of bounds exception when clicking in tab area 2019-09-01 17:16:07 -05:00
David Sparer
19f1770eda minor cleanup 2019-09-01 17:15:00 -05:00
David Sparer
40e878a517 resolved focus bug on first-connect 2019-09-01 16:38:11 -05:00
David Sparer
d09e9b10a0 fixed issue with mrng being in weird positions in the alt-tab lineup when extapp has focus 2019-09-01 16:07:58 -05:00
David Sparer
0d727338f0 moved a number of focus logic window events out of frmmain 2019-09-01 14:54:49 -05:00
David Sparer
e9838960fa improved ability to determine if external proc has focus 2019-09-01 12:30:11 -05:00
David Sparer
74611e9db6 refactored some alt-tab focus logic to a new class 2019-08-25 17:19:06 -05:00
David Sparer
f7dc0918eb fixed most focus issues when working with putty
still need to resolve refocusing putty in some cases
2019-08-25 15:59:51 -05:00
David Sparer
26d9e3c2ff debug putty focus issues 2019-08-25 10:42:13 -05:00
David Sparer
53c534aa93 use a single instance of IConnectionInitiator everywhere 2019-08-25 10:42:13 -05:00
David Sparer
dfd02e7b9a removed unused webhelper class 2019-08-25 10:42:13 -05:00
David Sparer
65eac21471 minor cleanup 2019-08-25 10:42:13 -05:00
David Sparer
5f776a3525 minor cleanup of the connection tab class 2019-08-25 10:42:13 -05:00
45 changed files with 2478 additions and 573 deletions

View File

@@ -12,7 +12,7 @@ namespace mRemoteNGTests.Connection.Protocol
{ {
public class IntegratedProgramTests public class IntegratedProgramTests
{ {
private readonly ExternalTool _extTool = new ExternalTool private readonly ExternalTool _extTool = new ExternalTool(new ConnectionInitiator(new ProtocolFactory()))
{ {
DisplayName = "notepad", DisplayName = "notepad",
FileName = @"%windir%\system32\notepad.exe", FileName = @"%windir%\system32\notepad.exe",
@@ -50,7 +50,7 @@ namespace mRemoteNGTests.Connection.Protocol
private InterfaceControl BuildInterfaceControl(string extAppName, ProtocolBase sut) private InterfaceControl BuildInterfaceControl(string extAppName, ProtocolBase sut)
{ {
var connectionWindow = new ConnectionWindow(new DockContent()); var connectionWindow = new ConnectionWindow(new DockContent(), new ConnectionInitiator(new ProtocolFactory()));
var connectionInfo = new ConnectionInfo {ExtApp = extAppName, Protocol = ProtocolType.IntApp}; var connectionInfo = new ConnectionInfo {ExtApp = extAppName, Protocol = ProtocolType.IntApp};
return new InterfaceControl(connectionWindow, sut, connectionInfo); return new InterfaceControl(connectionWindow, sut, connectionInfo);
} }

View File

@@ -1,4 +1,6 @@
using NUnit.Framework; using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using NUnit.Framework;
using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms;
namespace mRemoteNGTests.UI.Forms namespace mRemoteNGTests.UI.Forms
@@ -15,7 +17,7 @@ namespace mRemoteNGTests.UI.Forms
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_optionsForm = new FrmOptions(); _optionsForm = new FrmOptions(new ConnectionInitiator(new ProtocolFactory()));
_optionsForm.Show(); _optionsForm.Show();
} }

View File

@@ -1,4 +1,6 @@
using System.Threading; using System.Threading;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.UI.Window; using mRemoteNG.UI.Window;
using NUnit.Framework; using NUnit.Framework;
using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.Docking;
@@ -13,7 +15,7 @@ namespace mRemoteNGTests.UI.Window
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_connectionTreeWindow = new ConnectionTreeWindow(new DockContent()); _connectionTreeWindow = new ConnectionTreeWindow(new DockContent(), new ConnectionInitiator(new ProtocolFactory()));
} }
[TearDown] [TearDown]

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
using mRemoteNG.App.Info; using mRemoteNG.App.Info;
using mRemoteNG.Config.Putty; using mRemoteNG.Config.Putty;
using mRemoteNG.Connection; using mRemoteNG.Connection;
using mRemoteNG.Credential; using mRemoteNG.Credential;

View File

@@ -1,4 +1,5 @@
using System; using System;
using mRemoteNG.Connection;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.UI; using mRemoteNG.UI;
using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms;
@@ -20,7 +21,7 @@ namespace mRemoteNG.App
internal static ConnectionTreeWindow TreeForm internal static ConnectionTreeWindow TreeForm
{ {
get => _treeForm ?? (_treeForm = new ConnectionTreeWindow()); get => _treeForm ?? (_treeForm = new ConnectionTreeWindow(ConnectionInitiator));
set => _treeForm = value; set => _treeForm = value;
} }
@@ -29,6 +30,7 @@ namespace mRemoteNG.App
internal static ScreenshotManagerWindow ScreenshotForm { get; set; } = new ScreenshotManagerWindow(); internal static ScreenshotManagerWindow ScreenshotForm { get; set; } = new ScreenshotManagerWindow();
private static UpdateWindow UpdateForm { get; set; } = new UpdateWindow(); private static UpdateWindow UpdateForm { get; set; } = new UpdateWindow();
internal static SSHTransferWindow SshtransferForm { get; private set; } = new SSHTransferWindow(); internal static SSHTransferWindow SshtransferForm { get; private set; } = new SSHTransferWindow();
internal static IConnectionInitiator ConnectionInitiator { get; set; }
public static void Show(WindowType windowType) public static void Show(WindowType windowType)
@@ -50,7 +52,7 @@ namespace mRemoteNG.App
_adimportForm.Show(dockPanel); _adimportForm.Show(dockPanel);
break; break;
case WindowType.Options: case WindowType.Options:
using (var optionsForm = new FrmOptions()) using (var optionsForm = new FrmOptions(ConnectionInitiator))
{ {
optionsForm.ShowDialog(dockPanel); optionsForm.ShowDialog(dockPanel);
} }
@@ -73,7 +75,7 @@ namespace mRemoteNG.App
break; break;
case WindowType.ExternalApps: case WindowType.ExternalApps:
if (_externalappsForm == null || _externalappsForm.IsDisposed) if (_externalappsForm == null || _externalappsForm.IsDisposed)
_externalappsForm = new ExternalToolsWindow(); _externalappsForm = new ExternalToolsWindow(ConnectionInitiator);
_externalappsForm.Show(dockPanel); _externalappsForm.Show(dockPanel);
break; break;
case WindowType.PortScan: case WindowType.PortScan:

View File

@@ -4,6 +4,7 @@ using mRemoteNG.App.Info;
using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms;
using System.IO; using System.IO;
using System.Xml; using System.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.Tools; using mRemoteNG.Tools;
using mRemoteNG.UI.Controls; using mRemoteNG.UI.Controls;
@@ -13,12 +14,14 @@ namespace mRemoteNG.Config.Settings
public class ExternalAppsLoader public class ExternalAppsLoader
{ {
private readonly FrmMain _mainForm; private readonly FrmMain _mainForm;
private readonly IConnectionInitiator _connectionInitiator;
private readonly MessageCollector _messageCollector; private readonly MessageCollector _messageCollector;
private readonly ExternalToolsToolStrip _externalToolsToolStrip; private readonly ExternalToolsToolStrip _externalToolsToolStrip;
public ExternalAppsLoader(FrmMain mainForm, public ExternalAppsLoader(FrmMain mainForm,
MessageCollector messageCollector, MessageCollector messageCollector,
ExternalToolsToolStrip externalToolsToolStrip) ExternalToolsToolStrip externalToolsToolStrip,
IConnectionInitiator connectionInitiator)
{ {
if (mainForm == null) if (mainForm == null)
throw new ArgumentNullException(nameof(mainForm)); throw new ArgumentNullException(nameof(mainForm));
@@ -30,6 +33,7 @@ namespace mRemoteNG.Config.Settings
_mainForm = mainForm; _mainForm = mainForm;
_messageCollector = messageCollector; _messageCollector = messageCollector;
_externalToolsToolStrip = externalToolsToolStrip; _externalToolsToolStrip = externalToolsToolStrip;
_connectionInitiator = connectionInitiator;
} }
@@ -71,7 +75,7 @@ namespace mRemoteNG.Config.Settings
foreach (XmlElement xEl in xDom.DocumentElement.ChildNodes) foreach (XmlElement xEl in xDom.DocumentElement.ChildNodes)
{ {
var extA = new ExternalTool var extA = new ExternalTool(_connectionInitiator)
{ {
DisplayName = xEl.Attributes["DisplayName"].Value, DisplayName = xEl.Attributes["DisplayName"].Value,
FileName = xEl.Attributes["FileName"].Value, FileName = xEl.Attributes["FileName"].Value,

View File

@@ -1,4 +1,4 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.Docking;
@@ -7,6 +7,7 @@ using System.Threading;
using System.Globalization; using System.Globalization;
using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol;
using mRemoteNG.App.Info; using mRemoteNG.App.Info;
using mRemoteNG.Connection;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.Tools; using mRemoteNG.Tools;
using mRemoteNG.UI.Controls; using mRemoteNG.UI.Controls;
@@ -23,16 +24,19 @@ namespace mRemoteNG.Config.Settings
private readonly QuickConnectToolStrip _quickConnectToolStrip; private readonly QuickConnectToolStrip _quickConnectToolStrip;
private readonly ExternalToolsToolStrip _externalToolsToolStrip; private readonly ExternalToolsToolStrip _externalToolsToolStrip;
private readonly MultiSshToolStrip _multiSshToolStrip; private readonly MultiSshToolStrip _multiSshToolStrip;
private readonly IConnectionInitiator _connectionInitiator;
private FrmMain MainForm { get; } private FrmMain MainForm { get; }
public SettingsLoader(FrmMain mainForm, public SettingsLoader(
MessageCollector messageCollector, FrmMain mainForm,
QuickConnectToolStrip quickConnectToolStrip, IConnectionInitiator connectionInitiator,
ExternalToolsToolStrip externalToolsToolStrip, MessageCollector messageCollector,
MultiSshToolStrip multiSshToolStrip, QuickConnectToolStrip quickConnectToolStrip,
MenuStrip mainMenu) ExternalToolsToolStrip externalToolsToolStrip,
MultiSshToolStrip multiSshToolStrip,
MenuStrip mainMenu)
{ {
if (mainForm == null) if (mainForm == null)
throw new ArgumentNullException(nameof(mainForm)); throw new ArgumentNullException(nameof(mainForm));
@@ -53,7 +57,8 @@ namespace mRemoteNG.Config.Settings
_externalToolsToolStrip = externalToolsToolStrip; _externalToolsToolStrip = externalToolsToolStrip;
_multiSshToolStrip = multiSshToolStrip; _multiSshToolStrip = multiSshToolStrip;
_mainMenu = mainMenu; _mainMenu = mainMenu;
_externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip); _connectionInitiator = connectionInitiator;
_externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip, _connectionInitiator);
} }
#region Public Methods #region Public Methods
@@ -156,10 +161,10 @@ namespace mRemoteNG.Config.Settings
MainForm.Fullscreen.Value = true; MainForm.Fullscreen.Value = true;
} }
private static void SetShowSystemTrayIcon() private void SetShowSystemTrayIcon()
{ {
if (mRemoteNG.Settings.Default.ShowSystemTrayIcon) if (mRemoteNG.Settings.Default.ShowSystemTrayIcon)
Runtime.NotificationAreaIcon = new NotificationAreaIcon(); Runtime.NotificationAreaIcon = new NotificationAreaIcon(_connectionInitiator);
} }
private static void SetPuttyPath() private static void SetPuttyPath()

View File

@@ -5,7 +5,6 @@ using mRemoteNG.App;
using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container; using mRemoteNG.Container;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.Tools;
using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms;
using mRemoteNG.UI.Panels; using mRemoteNG.UI.Panels;
using mRemoteNG.UI.Tabs; using mRemoteNG.UI.Tabs;
@@ -17,10 +16,15 @@ namespace mRemoteNG.Connection
{ {
public class ConnectionInitiator : IConnectionInitiator public class ConnectionInitiator : IConnectionInitiator
{ {
private readonly PanelAdder _panelAdder = new PanelAdder(); private readonly ProtocolFactory _protocolFactory;
private readonly List<string> _activeConnections = new List<string>(); private readonly List<ProtocolBase> _activeConnections = new List<ProtocolBase>();
public IEnumerable<string> ActiveConnections => _activeConnections; public IEnumerable<ProtocolBase> ActiveConnections => _activeConnections;
public ConnectionInitiator(ProtocolFactory protocolFactory)
{
_protocolFactory = protocolFactory;
}
public bool SwitchToOpenConnection(ConnectionInfo connectionInfo) public bool SwitchToOpenConnection(ConnectionInfo connectionInfo)
{ {
@@ -33,6 +37,8 @@ namespace mRemoteNG.Connection
return true; return true;
} }
public void OpenConnection( public void OpenConnection(
ContainerInfo containerInfo, ContainerInfo containerInfo,
ConnectionInfo.Force force = ConnectionInfo.Force.None, ConnectionInfo.Force force = ConnectionInfo.Force.None,
@@ -75,8 +81,7 @@ namespace mRemoteNG.Connection
return; return;
} }
var protocolFactory = new ProtocolFactory(); var newProtocol = _protocolFactory.CreateProtocol(connectionInfo);
var newProtocol = protocolFactory.CreateProtocol(connectionInfo);
var connectionPanel = SetConnectionPanel(connectionInfo, force); var connectionPanel = SetConnectionPanel(connectionInfo, force);
if (string.IsNullOrEmpty(connectionPanel)) return; if (string.IsNullOrEmpty(connectionPanel)) return;
@@ -94,6 +99,7 @@ namespace mRemoteNG.Connection
return; return;
} }
OnConnectionStarting(newProtocol.InterfaceControl.Info, newProtocol);
if (newProtocol.Connect() == false) if (newProtocol.Connect() == false)
{ {
newProtocol.Close(); newProtocol.Close();
@@ -101,7 +107,7 @@ namespace mRemoteNG.Connection
} }
connectionInfo.OpenConnections.Add(newProtocol); connectionInfo.OpenConnections.Add(newProtocol);
_activeConnections.Add(connectionInfo.ConstantID); _activeConnections.Add(newProtocol);
FrmMain.Default.SelectedConnection = connectionInfo; FrmMain.Default.SelectedConnection = connectionInfo;
} }
catch (Exception ex) catch (Exception ex)
@@ -141,14 +147,14 @@ namespace mRemoteNG.Connection
return null; return null;
} }
private static string SetConnectionPanel(ConnectionInfo connectionInfo, ConnectionInfo.Force force) private string SetConnectionPanel(ConnectionInfo connectionInfo, ConnectionInfo.Force force)
{ {
if (connectionInfo.Panel != "" && if (connectionInfo.Panel != "" &&
!force.HasFlag(ConnectionInfo.Force.OverridePanel) && !force.HasFlag(ConnectionInfo.Force.OverridePanel) &&
!Settings.Default.AlwaysShowPanelSelectionDlg) !Settings.Default.AlwaysShowPanelSelectionDlg)
return connectionInfo.Panel; return connectionInfo.Panel;
var frmPnl = new FrmChoosePanel(); var frmPnl = new FrmChoosePanel(this);
return frmPnl.ShowDialog() == DialogResult.OK return frmPnl.ShowDialog() == DialogResult.OK
? frmPnl.Panel ? frmPnl.Panel
: null; : null;
@@ -159,7 +165,7 @@ namespace mRemoteNG.Connection
var connectionForm = conForm ?? Runtime.WindowList.FromString(connectionPanel) as ConnectionWindow; var connectionForm = conForm ?? Runtime.WindowList.FromString(connectionPanel) as ConnectionWindow;
if (connectionForm == null) if (connectionForm == null)
connectionForm = _panelAdder.AddPanel(connectionPanel); connectionForm = new PanelAdder(this).AddPanel(connectionPanel);
else else
connectionForm.Show(FrmMain.Default.pnlDock); connectionForm.Show(FrmMain.Default.pnlDock);
@@ -223,11 +229,11 @@ namespace mRemoteNG.Connection
} }
Runtime.MessageCollector.AddMessage(msgClass, Runtime.MessageCollector.AddMessage(msgClass,
string.Format( string.Format(
Language.strProtocolEventDisconnected, Language.strProtocolEventDisconnected,
disconnectedMessage, disconnectedMessage,
prot.InterfaceControl.Info.Hostname, prot.InterfaceControl.Info.Hostname,
prot.InterfaceControl.Info.Protocol.ToString())); prot.InterfaceControl.Info.Protocol.ToString()));
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -256,8 +262,8 @@ namespace mRemoteNG.Connection
prot.InterfaceControl.Info.Protocol, prot.InterfaceControl.Info.Protocol,
Environment.UserName)); Environment.UserName));
prot.InterfaceControl.Info.OpenConnections.Remove(prot); prot.InterfaceControl.Info.OpenConnections.Remove(prot);
if (_activeConnections.Contains(prot.InterfaceControl.Info.ConstantID)) if (_activeConnections.Contains(prot))
_activeConnections.Remove(prot.InterfaceControl.Info.ConstantID); _activeConnections.Remove(prot);
if (prot.InterfaceControl.Info.PostExtApp == "") return; if (prot.InterfaceControl.Info.PostExtApp == "") return;
var extA = Runtime.ExternalToolsService.GetExtAppByName(prot.InterfaceControl.Info.PostExtApp); var extA = Runtime.ExternalToolsService.GetExtAppByName(prot.InterfaceControl.Info.PostExtApp);
@@ -269,7 +275,7 @@ namespace mRemoteNG.Connection
} }
} }
private static void Prot_Event_Connected(object sender) private void Prot_Event_Connected(object sender)
{ {
var prot = (ProtocolBase)sender; var prot = (ProtocolBase)sender;
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strConnectionEventConnected, Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strConnectionEventConnected,
@@ -302,5 +308,11 @@ namespace mRemoteNG.Connection
} }
#endregion #endregion
public event EventHandler<ConnectionStartingEvent> ConnectionStarting;
protected virtual void OnConnectionStarting(ConnectionInfo connectionInfo, ProtocolBase protocolBase)
{
ConnectionStarting?.Invoke(this, new ConnectionStartingEvent(connectionInfo, protocolBase));
}
} }
} }

View File

@@ -0,0 +1,18 @@
using System;
using mRemoteNG.Connection.Protocol;
namespace mRemoteNG.Connection
{
[Serializable]
public class ConnectionStartingEvent : EventArgs
{
public ConnectionInfo ConnectionInfo { get; }
public ProtocolBase Protocol { get; }
public ConnectionStartingEvent(ConnectionInfo connectionInfo, ProtocolBase protocol)
{
ConnectionInfo = connectionInfo;
Protocol = protocol;
}
}
}

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container; using mRemoteNG.Container;
using mRemoteNG.UI.Window; using mRemoteNG.UI.Window;
@@ -6,7 +8,7 @@ namespace mRemoteNG.Connection
{ {
public interface IConnectionInitiator public interface IConnectionInitiator
{ {
IEnumerable<string> ActiveConnections { get; } IEnumerable<ProtocolBase> ActiveConnections { get; }
void OpenConnection( void OpenConnection(
ContainerInfo containerInfo, ContainerInfo containerInfo,
@@ -19,5 +21,7 @@ namespace mRemoteNG.Connection
ConnectionWindow conForm = null); ConnectionWindow conForm = null);
bool SwitchToOpenConnection(ConnectionInfo connectionInfo); bool SwitchToOpenConnection(ConnectionInfo connectionInfo);
event EventHandler<ConnectionStartingEvent> ConnectionStarting;
} }
} }

View File

@@ -1,4 +1,4 @@
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol;
using System; using System;
using System.Drawing; using System.Drawing;
@@ -25,6 +25,8 @@ namespace mRemoteNG.Connection
Location = new Point(0, 0); Location = new Point(0, 0);
Size = Parent.Size; Size = Parent.Size;
Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
GotFocus += OnGotFocus;
LostFocus += OnLostFocus;
InitializeComponent(); InitializeComponent();
} }
catch (Exception ex) catch (Exception ex)
@@ -35,6 +37,16 @@ namespace mRemoteNG.Connection
} }
} }
private void OnLostFocus(object sender, EventArgs e)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, $"InterfaceControl lost focus '{Info.Name}'");
}
private void OnGotFocus(object sender, EventArgs e)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, $"InterfaceControl gained focus '{Info.Name}'");
}
public static InterfaceControl FindInterfaceControl(DockPanel DockPnl) public static InterfaceControl FindInterfaceControl(DockPanel DockPnl)
{ {
if (!(DockPnl.ActiveDocument is ConnectionTab ct)) return null; if (!(DockPnl.ActiveDocument is ConnectionTab ct)) return null;

View File

@@ -0,0 +1,120 @@
using System;
using System.Diagnostics;
using mRemoteNG.App;
using mRemoteNG.Messages;
namespace mRemoteNG.Connection.Protocol
{
public abstract class ExternalProcessProtocolBase : ProtocolBase, IFocusable
{
private IntPtr _winEventHook;
private NativeMethods.WinEventDelegate _setForegroundDelegate;
private bool _hasFocus;
public override bool IsExternalProcess { get; } = true;
protected Process ProtocolProcess { get; set; }
protected IntPtr ProcessHandle { get; set; }
public bool HasFocus
{
get => _hasFocus;
private set
{
if (_hasFocus == value)
return;
_hasFocus = value;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg,
string.Format("External protocol window set to {0}. name:'{1}', protocol:'{2}', pid:{3}, hwnd:{4}",
_hasFocus ? "foreground" : "background",
InterfaceControl.Info.Name,
InterfaceControl.Info.Protocol,
ProtocolProcess.Id,
ProcessHandle));
OnFocusChanged();
}
}
public int ThreadId => (int)NativeMethods.GetWindowThreadProcessId(ProcessHandle, IntPtr.Zero);
public override bool Connect()
{
_setForegroundDelegate = OnWinEventSetForeground;
_winEventHook = NativeMethods.SetWinEventHook(
NativeMethods.EVENT_SYSTEM_FOREGROUND,
NativeMethods.EVENT_SYSTEM_FOREGROUND,
IntPtr.Zero,
_setForegroundDelegate,
/*Convert.ToUInt32(ProtocolProcess.Id)*/0,
0,
NativeMethods.WINEVENT_OUTOFCONTEXT);
return base.Connect();
}
public override void Close()
{
if (NativeMethods.UnhookWinEvent(_winEventHook))
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Successfully unhooked WinEvent listener from '{InterfaceControl.Info.Name}'");
}
else
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Failed to unhook WinEvent listener from '{InterfaceControl.Info.Name}'");
}
base.Close();
}
public override void Focus()
{
FocusChildProcessWindow();
}
private void FocusChildProcessWindow()
{
if (NativeMethods.GetForegroundWindow() == ProcessHandle)
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Process already focused - do nothing");
return;
}
var setForegroundSuccessful = NativeMethods.SetForegroundWindow(ProcessHandle);
if (!setForegroundSuccessful)
{
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg,
"Failed to set external protocol window to foreground. " +
$"name:'{InterfaceControl.Info.Name}', " +
$"protocol:'{InterfaceControl.Info.Protocol}', " +
$"pid:{ProtocolProcess.Id}, " +
$"hwnd:{ProcessHandle}");
}
}
/// <summary>
/// This callback will be called when the external process window managed by
/// this protocol is brought to the foreground.
/// </summary>
/// <param name="hWinEventHook"></param>
/// <param name="eventType"></param>
/// <param name="hwnd"></param>
/// <param name="idObject"></param>
/// <param name="idChild"></param>
/// <param name="dwEventThread"></param>
/// <param name="dwmsEventTime"></param>
void OnWinEventSetForeground(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
HasFocus = hwnd == ProcessHandle;
}
public event EventHandler FocusChanged;
protected virtual void OnFocusChanged()
{
FocusChanged?.Invoke(this, EventArgs.Empty);
}
}
}

View File

@@ -0,0 +1,11 @@
using System;
namespace mRemoteNG.Connection.Protocol
{
public interface IFocusable
{
bool HasFocus { get; }
void Focus();
event EventHandler FocusChanged;
}
}

View File

@@ -1,4 +1,4 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Threading; using System.Threading;
@@ -9,7 +9,7 @@ using mRemoteNG.Tools;
namespace mRemoteNG.Connection.Protocol namespace mRemoteNG.Connection.Protocol
{ {
public class IntegratedProgram : ProtocolBase public class IntegratedProgram : ExternalProcessProtocolBase
{ {
#region Private Fields #region Private Fields

View File

@@ -63,6 +63,12 @@ namespace mRemoteNG.Connection.Protocol
public readonly System.Timers.Timer tmrReconnect = new System.Timers.Timer(2000); public readonly System.Timers.Timer tmrReconnect = new System.Timers.Timer(2000);
protected ReconnectGroup ReconnectGroup; protected ReconnectGroup ReconnectGroup;
/// <summary>
/// Whether this protocol runs as a thread within the main process or if
/// it is an external process that is running as a child process.
/// </summary>
public virtual bool IsExternalProcess { get; } = false;
protected ProtocolBase(string name) protected ProtocolBase(string name)
{ {
Name = name; Name = name;
@@ -335,8 +341,7 @@ namespace mRemoteNG.Connection.Protocol
{ {
if (!disposing) return; if (!disposing) return;
if(tmrReconnect != null) tmrReconnect?.Dispose();
tmrReconnect.Dispose();
} }
public void Dispose() public void Dispose()

View File

@@ -1,4 +1,4 @@
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.Security.SymmetricEncryption; using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools; using mRemoteNG.Tools;
@@ -14,27 +14,22 @@ using System.Windows.Forms;
namespace mRemoteNG.Connection.Protocol namespace mRemoteNG.Connection.Protocol
{ {
public class PuttyBase : ProtocolBase public class PuttyBase : ExternalProcessProtocolBase
{ {
private const int IDM_RECONF = 0x50; // PuTTY Settings Menu ID private const int IDM_RECONF = 0x50; // PuTTY Settings Menu ID
private bool _isPuttyNg; private bool _isPuttyNg;
private readonly DisplayProperties _display = new DisplayProperties(); private readonly DisplayProperties _display = new DisplayProperties();
#region Public Properties #region Public Properties
protected Putty_Protocol PuttyProtocol { private get; set; } protected Putty_Protocol PuttyProtocol { private get; set; }
protected Putty_SSHVersion PuttySSHVersion { private get; set; } protected Putty_SSHVersion PuttySSHVersion { private get; set; }
public IntPtr PuttyHandle { get; set; }
private Process PuttyProcess { get; set; }
public static string PuttyPath { get; set; } public static string PuttyPath { get; set; }
public bool Focused public bool Focused
{ {
get { return NativeMethods.GetForegroundWindow() == PuttyHandle; } get { return NativeMethods.GetForegroundWindow() == ProcessHandle; }
} }
#endregion #endregion
@@ -54,111 +49,40 @@ namespace mRemoteNG.Connection.Protocol
{ {
try try
{ {
_isPuttyNg = PuttyTypeDetector.GetPuttyType() == PuttyTypeDetector.PuttyType.PuttyNg; base.Connect();
var arguments = BuildPuttyCommandLineArguments(InterfaceControl.Info);
PuttyProcess = new Process ProtocolProcess = new Process
{ {
StartInfo = StartInfo =
{ {
UseShellExecute = false, UseShellExecute = false,
FileName = PuttyPath FileName = PuttyPath,
} Arguments = arguments.ToString()
},
EnableRaisingEvents = true
}; };
var arguments = new CommandLineArguments {EscapeForShell = false}; ProtocolProcess.Exited += ProcessExited;
arguments.Add("-load", InterfaceControl.Info.PuttySession); ProtocolProcess.Start();
ProtocolProcess.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000);
if (!(InterfaceControl.Info is PuttySessionInfo))
{
arguments.Add("-" + PuttyProtocol);
if (PuttyProtocol == Putty_Protocol.ssh)
{
var username = "";
var password = "";
if (!string.IsNullOrEmpty(InterfaceControl.Info?.Username))
{
username = InterfaceControl.Info.Username;
}
else
{
// ReSharper disable once SwitchStatementMissingSomeCases
switch (Settings.Default.EmptyCredentials)
{
case "windows":
username = Environment.UserName;
break;
case "custom":
username = Settings.Default.DefaultUsername;
break;
}
}
if (!string.IsNullOrEmpty(InterfaceControl.Info?.Password))
{
password = InterfaceControl.Info.Password;
}
else
{
if (Settings.Default.EmptyCredentials == "custom")
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword,
Runtime.EncryptionKey);
}
}
arguments.Add("-" + (int)PuttySSHVersion);
if (!Force.HasFlag(ConnectionInfo.Force.NoCredentials))
{
if (!string.IsNullOrEmpty(username))
{
arguments.Add("-l", username);
}
if (!string.IsNullOrEmpty(password))
{
arguments.Add("-pw", password);
}
}
}
arguments.Add("-P", InterfaceControl.Info.Port.ToString());
arguments.Add(InterfaceControl.Info.Hostname);
}
if (_isPuttyNg)
{
arguments.Add("-hwndparent", InterfaceControl.Handle.ToString());
}
PuttyProcess.StartInfo.Arguments = arguments.ToString();
PuttyProcess.EnableRaisingEvents = true;
PuttyProcess.Exited += ProcessExited;
PuttyProcess.Start();
PuttyProcess.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000);
var startTicks = Environment.TickCount; var startTicks = Environment.TickCount;
while (PuttyHandle.ToInt32() == 0 & while (ProcessHandle.ToInt32() == 0 &
Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000) Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000)
{ {
if (_isPuttyNg) if (_isPuttyNg)
{ {
PuttyHandle = NativeMethods.FindWindowEx( ProcessHandle = NativeMethods.FindWindowEx(InterfaceControl.Handle, new IntPtr(0), null, null);
InterfaceControl.Handle, new IntPtr(0), null, null);
} }
else else
{ {
PuttyProcess.Refresh(); ProtocolProcess.Refresh();
PuttyHandle = PuttyProcess.MainWindowHandle; ProcessHandle = ProtocolProcess.MainWindowHandle;
} }
if (PuttyHandle.ToInt32() == 0) if (ProcessHandle.ToInt32() == 0)
{ {
Thread.Sleep(0); Thread.Sleep(0);
} }
@@ -166,21 +90,20 @@ namespace mRemoteNG.Connection.Protocol
if (!_isPuttyNg) if (!_isPuttyNg)
{ {
NativeMethods.SetParent(PuttyHandle, InterfaceControl.Handle); NativeMethods.SetParent(ProcessHandle, InterfaceControl.Handle);
} }
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strPuttyStuff, true); Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strPuttyStuff, true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg,
string.Format(Language.strPuttyHandle, PuttyHandle), true); string.Format(Language.strPuttyHandle, ProcessHandle), true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg,
string.Format(Language.strPuttyTitle, PuttyProcess.MainWindowTitle), string.Format(Language.strPuttyTitle, ProtocolProcess.MainWindowTitle),
true); true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg,
string.Format(Language.strPuttyParentHandle, string.Format(Language.strPuttyParentHandle,
InterfaceControl.Parent.Handle), true); InterfaceControl.Parent.Handle), true);
Resize(this, new EventArgs()); Resize(this, new EventArgs());
base.Connect();
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
@@ -192,18 +115,102 @@ namespace mRemoteNG.Connection.Protocol
} }
} }
private CommandLineArguments BuildPuttyCommandLineArguments(AbstractConnectionRecord connectionInfo)
{
var arguments = new CommandLineArguments { EscapeForShell = false };
arguments.Add("-load", connectionInfo.PuttySession);
if (!(connectionInfo is PuttySessionInfo))
{
arguments.Add("-" + PuttyProtocol);
if (PuttyProtocol == Putty_Protocol.ssh)
{
var username = "";
var password = "";
if (!string.IsNullOrEmpty(connectionInfo.Username))
{
username = connectionInfo.Username;
}
else
{
// ReSharper disable once SwitchStatementMissingSomeCases
switch (Settings.Default.EmptyCredentials)
{
case "windows":
username = Environment.UserName;
break;
case "custom":
username = Settings.Default.DefaultUsername;
break;
}
}
if (!string.IsNullOrEmpty(connectionInfo.Password))
{
password = connectionInfo.Password;
}
else
{
if (Settings.Default.EmptyCredentials == "custom")
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword,
Runtime.EncryptionKey);
}
}
arguments.Add("-" + (int)PuttySSHVersion);
if (!Force.HasFlag(ConnectionInfo.Force.NoCredentials))
{
if (!string.IsNullOrEmpty(username))
{
arguments.Add("-l", username);
}
if (!string.IsNullOrEmpty(password))
{
arguments.Add("-pw", password);
}
}
}
arguments.Add("-P", connectionInfo.Port.ToString());
arguments.Add(connectionInfo.Hostname);
}
_isPuttyNg = PuttyTypeDetector.GetPuttyType() == PuttyTypeDetector.PuttyType.PuttyNg;
if (_isPuttyNg)
{
arguments.Add("-hwndparent", InterfaceControl.Handle.ToString());
}
return arguments;
}
public override void Focus() public override void Focus()
{ {
try //try
{ //{
NativeMethods.SetForegroundWindow(PuttyHandle); // if (NativeMethods.GetForegroundWindow() == PuttyHandle)
} // {
catch (Exception ex) // Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Putty window already focused, ignoring focus request '{InterfaceControl.Info.Name}' (pid:{PuttyProcess.Id})");
{ // return;
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, // }
Language.strPuttyFocusFailed + Environment.NewLine + ex.Message,
true); // NativeMethods.SetForegroundWindow(PuttyHandle);
} // Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Putty window focused '{InterfaceControl.Info.Name}' (pid:{PuttyProcess.Id})");
//}
//catch (Exception ex)
//{
// Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg,
// Language.strPuttyFocusFailed + Environment.NewLine + ex.Message,
// true);
//}
base.Focus();
} }
public override void Resize(object sender, EventArgs e) public override void Resize(object sender, EventArgs e)
@@ -216,14 +223,14 @@ namespace mRemoteNG.Connection.Protocol
if (_isPuttyNg) if (_isPuttyNg)
{ {
// PuTTYNG 0.70.0.1 and later doesn't have any window borders // PuTTYNG 0.70.0.1 and later doesn't have any window borders
NativeMethods.MoveWindow(PuttyHandle, 0, 0, InterfaceControl.Width, InterfaceControl.Height, true); NativeMethods.MoveWindow(ProcessHandle, 0, 0, InterfaceControl.Width, InterfaceControl.Height, true);
} }
else else
{ {
var scaledFrameBorderHeight = _display.ScaleHeight(SystemInformation.FrameBorderSize.Height); var scaledFrameBorderHeight = _display.ScaleHeight(SystemInformation.FrameBorderSize.Height);
var scaledFrameBorderWidth = _display.ScaleWidth(SystemInformation.FrameBorderSize.Width); var scaledFrameBorderWidth = _display.ScaleWidth(SystemInformation.FrameBorderSize.Width);
NativeMethods.MoveWindow(PuttyHandle, -scaledFrameBorderWidth, NativeMethods.MoveWindow(ProcessHandle, -scaledFrameBorderWidth,
-(SystemInformation.CaptionHeight + scaledFrameBorderHeight), -(SystemInformation.CaptionHeight + scaledFrameBorderHeight),
InterfaceControl.Width + scaledFrameBorderWidth * 2, InterfaceControl.Width + scaledFrameBorderWidth * 2,
InterfaceControl.Height + SystemInformation.CaptionHeight + InterfaceControl.Height + SystemInformation.CaptionHeight +
@@ -243,9 +250,9 @@ namespace mRemoteNG.Connection.Protocol
{ {
try try
{ {
if (PuttyProcess.HasExited == false) if (ProtocolProcess.HasExited == false)
{ {
PuttyProcess.Kill(); ProtocolProcess.Kill();
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -257,7 +264,7 @@ namespace mRemoteNG.Connection.Protocol
try try
{ {
PuttyProcess.Dispose(); ProtocolProcess.Dispose();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -273,8 +280,8 @@ namespace mRemoteNG.Connection.Protocol
{ {
try try
{ {
NativeMethods.PostMessage(PuttyHandle, NativeMethods.WM_SYSCOMMAND, (IntPtr)IDM_RECONF, (IntPtr)0); NativeMethods.PostMessage(ProcessHandle, NativeMethods.WM_SYSCOMMAND, (IntPtr)IDM_RECONF, IntPtr.Zero);
NativeMethods.SetForegroundWindow(PuttyHandle); Focus();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -284,6 +291,14 @@ namespace mRemoteNG.Connection.Protocol
} }
} }
/// <summary>
/// Sends an individual key stroke to this PuTTY session.
/// </summary>
public void SendKeyStroke(int keyType, int keyData)
{
NativeMethods.PostMessage(ProcessHandle, keyType, new IntPtr(keyData), new IntPtr(0));
}
#endregion #endregion
#region Enums #region Enums

View File

@@ -1,6 +1,9 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading; using System.Threading;
using System.Timers; using System.Timers;
using System.Windows.Forms; using System.Windows.Forms;
@@ -35,6 +38,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
private readonly FrmMain _frmMain = FrmMain.Default; private readonly FrmMain _frmMain = FrmMain.Default;
protected virtual RdpVersion RdpProtocolVersion => RdpVersion.Rdc6; protected virtual RdpVersion RdpProtocolVersion => RdpVersion.Rdc6;
private AxHost AxHost => (AxHost)Control; private AxHost AxHost => (AxHost)Control;
private readonly NativeMethods.EnumWindowsProc _enumWindowsProc;
#region Properties #region Properties
@@ -101,6 +105,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
{ {
_displayProperties = new DisplayProperties(); _displayProperties = new DisplayProperties();
tmrReconnect.Elapsed += tmrReconnect_Elapsed; tmrReconnect.Elapsed += tmrReconnect_Elapsed;
_enumWindowsProc = LpEnumFunc;
} }
#endregion #endregion
@@ -243,17 +248,54 @@ namespace mRemoteNG.Connection.Protocol.RDP
public override void Focus() public override void Focus()
{ {
var result = new List<IntPtr>();
var listHandle = GCHandle.Alloc(result);
try try
{ {
if (Control.ContainsFocus == false) if (Control.ContainsFocus == false)
{ {
Control.Focus(); //AxHost.Focus();
//AxHost.Select();
//AxHost.DoVerb(-1);
//AxHost.DoVerb(-4);
//AxHost.DoVerb(-5);
NativeMethods.EnumChildWindows(AxHost.Handle, _enumWindowsProc, GCHandle.ToIntPtr(listHandle));
if (result.Any())
{
NativeMethods.SetFocus(result[0]);
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"RDP connection focused '{connectionInfo.Name}'");
}
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpFocusFailed, ex); Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpFocusFailed, ex);
} }
finally
{
if (listHandle.IsAllocated)
listHandle.Free();
}
}
private bool LpEnumFunc(IntPtr hwnd, IntPtr lparam)
{
var gch = GCHandle.FromIntPtr(lparam);
var list = gch.Target as List<IntPtr>;
if (list == null)
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
var sb = new StringBuilder();
NativeMethods.GetClassName(hwnd, sb, 64);
if (sb.ToString().Equals("IHWindowClass"))
{
list.Add(hwnd);
return false;
}
return true;
} }
/// <summary> /// <summary>
@@ -672,6 +714,9 @@ namespace mRemoteNG.Connection.Protocol.RDP
_rdpClient.OnDisconnected += RDPEvent_OnDisconnected; _rdpClient.OnDisconnected += RDPEvent_OnDisconnected;
_rdpClient.OnLeaveFullScreenMode += RDPEvent_OnLeaveFullscreenMode; _rdpClient.OnLeaveFullScreenMode += RDPEvent_OnLeaveFullscreenMode;
_rdpClient.OnIdleTimeoutNotification += RDPEvent_OnIdleTimeoutNotification; _rdpClient.OnIdleTimeoutNotification += RDPEvent_OnIdleTimeoutNotification;
//_rdpClient.OnFocusReleased += direction => Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"RDP control '{connectionInfo.Name}' released focus.");
//AxHost.GotFocus += (sender, args) => Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"RDP control '{connectionInfo.Name}' received focus.");
//AxHost.LostFocus += (sender, args) => Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"RDP control '{connectionInfo.Name}' lost focus.");
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -748,7 +793,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
private void RdpClient_GotFocus(object sender, EventArgs e) private void RdpClient_GotFocus(object sender, EventArgs e)
{ {
((ConnectionTab)Control.Parent.Parent).Focus(); //((ConnectionTab)Control.Parent.Parent).Focus();
} }
#endregion #endregion

View File

@@ -1,23 +0,0 @@
using mRemoteNG.Connection.Protocol;
namespace mRemoteNG.Connection
{
public class WebHelper
{
public static void GoToUrl(string url)
{
var connectionInfo = new ConnectionInfo();
connectionInfo.CopyFrom(DefaultConnectionInfo.Instance);
connectionInfo.Name = "";
connectionInfo.Hostname = url;
connectionInfo.Protocol = url.StartsWith("https:") ? ProtocolType.HTTPS : ProtocolType.HTTP;
connectionInfo.SetDefaultPort();
if (string.IsNullOrEmpty(connectionInfo.Panel))
connectionInfo.Panel = Language.strGeneral;
connectionInfo.IsQuickConnect = true;
var connectionInitiator = new ConnectionInitiator();
connectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump);
}
}
}

View File

@@ -6,7 +6,7 @@ namespace mRemoteNG.Messages.MessageWriters
{ {
public void Write(IMessage message) public void Write(IMessage message)
{ {
var textToPrint = $"{message.Class}: {message.Text}"; var textToPrint = $"[{message.Date.ToString("O")}] {message.Class}: {message.Text}";
Debug.Print(textToPrint); Debug.Print(textToPrint);
} }
} }

View File

@@ -1,4 +1,4 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.Docking;

View File

@@ -16,7 +16,7 @@ namespace mRemoteNG.Tools
{ {
public class ExternalTool : INotifyPropertyChanged public class ExternalTool : INotifyPropertyChanged
{ {
private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); private readonly IConnectionInitiator _connectionInitiator;
private string _displayName; private string _displayName;
private string _fileName; private string _fileName;
private bool _waitForExit; private bool _waitForExit;
@@ -102,12 +102,15 @@ namespace mRemoteNG.Tools
#endregion #endregion
public ExternalTool(string displayName = "", public ExternalTool(
string fileName = "", IConnectionInitiator connectionInitiator,
string arguments = "", string displayName = "",
string workingDir = "", string fileName = "",
bool runElevated = false) string arguments = "",
string workingDir = "",
bool runElevated = false)
{ {
_connectionInitiator = connectionInitiator;
DisplayName = displayName; DisplayName = displayName;
FileName = fileName; FileName = fileName;
Arguments = arguments; Arguments = arguments;

View File

@@ -63,7 +63,7 @@ namespace mRemoteNG.Tools
foreach (PuttyBase proc in processHandlers) foreach (PuttyBase proc in processHandlers)
{ {
NativeMethods.PostMessage(proc.PuttyHandle, keyType, new IntPtr(keyData), new IntPtr(0)); proc.SendKeyStroke(keyType, keyData);
} }
} }

View File

@@ -14,13 +14,14 @@ namespace mRemoteNG.Tools
private readonly NotifyIcon _nI; private readonly NotifyIcon _nI;
private readonly ContextMenuStrip _cMen; private readonly ContextMenuStrip _cMen;
private readonly ToolStripMenuItem _cMenCons; private readonly ToolStripMenuItem _cMenCons;
private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); private readonly IConnectionInitiator _connectionInitiator;
private static readonly FrmMain FrmMain = FrmMain.Default; private static readonly FrmMain FrmMain = FrmMain.Default;
public bool Disposed { get; private set; } public bool Disposed { get; private set; }
public NotificationAreaIcon() public NotificationAreaIcon(IConnectionInitiator connectionInitiator)
{ {
_connectionInitiator = connectionInitiator;
try try
{ {
_cMenCons = new ToolStripMenuItem _cMenCons = new ToolStripMenuItem

View File

@@ -26,7 +26,7 @@ namespace mRemoteNG.Tree
.Where(item => .Where(item =>
item.PleaseConnect && item.PleaseConnect &&
//ignore items that have already connected //ignore items that have already connected
!_connectionInitiator.ActiveConnections.Contains(item.ConstantID)); _connectionInitiator.ActiveConnections.All(protocol => protocol.InterfaceControl.Info.ConstantID != item.ConstantID));
foreach (var connectionInfo in previouslyOpenedConnections) foreach (var connectionInfo in previouslyOpenedConnections)
{ {

View File

@@ -54,10 +54,10 @@ namespace mRemoteNG.UI.Controls
private readonly IConnectionInitiator _connectionInitiator; private readonly IConnectionInitiator _connectionInitiator;
public ConnectionContextMenu(ConnectionTree connectionTree) public ConnectionContextMenu(ConnectionTree connectionTree, IConnectionInitiator connectionInitiator)
{ {
_connectionTree = connectionTree; _connectionTree = connectionTree;
_connectionInitiator = new ConnectionInitiator(); _connectionInitiator = connectionInitiator;
InitializeComponent(); InitializeComponent();
ApplyLanguage(); ApplyLanguage();
EnableShortcutKeys(); EnableShortcutKeys();

View File

@@ -23,7 +23,8 @@ namespace mRemoteNG.UI.Controls
private readonly ConnectionTreeDragAndDropHandler _dragAndDropHandler = new ConnectionTreeDragAndDropHandler(); private readonly ConnectionTreeDragAndDropHandler _dragAndDropHandler = new ConnectionTreeDragAndDropHandler();
private readonly PuttySessionsManager _puttySessionsManager = PuttySessionsManager.Instance; private readonly PuttySessionsManager _puttySessionsManager = PuttySessionsManager.Instance;
private readonly StatusImageList _statusImageList = new StatusImageList(); private readonly StatusImageList _statusImageList = new StatusImageList();
private ThemeManager _themeManager; private readonly IConnectionInitiator _connectionInitiator;
private readonly ThemeManager _themeManager;
private readonly ConnectionTreeSearchTextFilter _connectionTreeSearchTextFilter = private readonly ConnectionTreeSearchTextFilter _connectionTreeSearchTextFilter =
new ConnectionTreeSearchTextFilter(); new ConnectionTreeSearchTextFilter();
@@ -63,6 +64,7 @@ namespace mRemoteNG.UI.Controls
public ConnectionTree() public ConnectionTree()
{ {
_connectionInitiator = Windows.ConnectionInitiator;
InitializeComponent(); InitializeComponent();
SetupConnectionTreeView(); SetupConnectionTreeView();
UseOverlays = false; UseOverlays = false;
@@ -114,7 +116,7 @@ namespace mRemoteNG.UI.Controls
SmallImageList = _statusImageList.ImageList; SmallImageList = _statusImageList.ImageList;
AddColumns(_statusImageList.ImageGetter); AddColumns(_statusImageList.ImageGetter);
LinkModelToView(); LinkModelToView();
_contextMenu = new ConnectionContextMenu(this); _contextMenu = new ConnectionContextMenu(this, _connectionInitiator);
ContextMenuStrip = _contextMenu; ContextMenuStrip = _contextMenu;
SetupDropSink(); SetupDropSink();
SetEventHandlers(); SetEventHandlers();

View File

@@ -22,21 +22,11 @@ namespace mRemoteNG.UI.Controls
private ContextMenuStrip _mnuQuickConnectProtocol; private ContextMenuStrip _mnuQuickConnectProtocol;
private QuickConnectComboBox _cmbQuickConnect; private QuickConnectComboBox _cmbQuickConnect;
private ContextMenuStrip _mnuConnections; private ContextMenuStrip _mnuConnections;
private IConnectionInitiator _connectionInitiator = new ConnectionInitiator();
private readonly ThemeManager _themeManager; private readonly ThemeManager _themeManager;
private WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender vsToolStripExtender; private WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender vsToolStripExtender;
private readonly DisplayProperties _display; private readonly DisplayProperties _display;
public IConnectionInitiator ConnectionInitiator public IConnectionInitiator ConnectionInitiator { get; set; }
{
get => _connectionInitiator;
set
{
if (value == null)
return;
_connectionInitiator = value;
}
}
public QuickConnectToolStrip() public QuickConnectToolStrip()
{ {

View File

@@ -0,0 +1,327 @@
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Messages;
using mRemoteNG.UI.Tabs;
using Message = System.Windows.Forms.Message;
namespace mRemoteNG.UI.FocusHelpers
{
public class ExternalProcessFocusHelper : IDisposable
{
private readonly IntPtr _mainWindowHandle;
private int _extFocusCount;
private readonly SystemKeyboardHook _keyboardHook;
private bool _currentlyFixingAltTab;
private bool _childProcessHeldLastFocus;
private bool _inSizeMove;
private bool _fixingMainWindowFocus;
/// <summary>
/// TRUE if any part of mrng has focus - the main window or child processes
/// </summary>
public bool MrngFocused => MainWindowFocused || ChildProcessFocused;
/// <summary>
/// TRUE when the main mRemoteNG window has focus.
/// </summary>
public bool MainWindowFocused { get; private set; }
/// <summary>
/// TRUE when a child process (not the mRemoteNG main window) has focus.
/// </summary>
public bool ChildProcessFocused => _extFocusCount > 0;
/// <summary>
/// TRUE when a child process was the last window within mRemoteNG
/// to have focus.
/// </summary>
public bool ChildProcessHeldLastFocus
{
get => _childProcessHeldLastFocus;
private set
{
_childProcessHeldLastFocus = value;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"_childProcessHeldLastFocus={_childProcessHeldLastFocus}");
}
}
public ExternalProcessFocusHelper(
IConnectionInitiator connectionInitiator,
IntPtr mainWindowHandle)
{
connectionInitiator.ConnectionStarting += ConnectionInitiatorOnConnectionStarting;
_mainWindowHandle = mainWindowHandle;
_keyboardHook = new SystemKeyboardHook(KeyboardHookCallback);
}
private void ConnectionInitiatorOnConnectionStarting(object sender, ConnectionStartingEvent e)
{
if (!(e.Protocol is ExternalProcessProtocolBase extProc))
return;
extProc.FocusChanged += ExtProcOnFocusChanged;
extProc.Disconnected += ProtocolOnDisconnected;
}
private void ExtProcOnFocusChanged(object sender, EventArgs e)
{
if (!(sender is IFocusable extProc))
return;
if (extProc.HasFocus)
ExternalWindowFocused();
else
ExternalWindowDefocused();
}
private void ProtocolOnDisconnected(object sender, string disconnectedMessage, int? reasonCode)
{
if (!(sender is ExternalProcessProtocolBase prot))
return;
prot.FocusChanged -= ExtProcOnFocusChanged;
prot.Disconnected -= ProtocolOnDisconnected;
}
public void ActivateConnection()
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Performing special connection focus logic");
//var cw = pnlDock.ActiveDocument as ConnectionWindow;
//var dp = cw?.ActiveControl as DockPane;
//if (!(dp?.ActiveContent is ConnectionTab tab))
//{
// Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Active content is not a tab. We won't focus a specific connection.");
// return;
//}
//var ifc = InterfaceControl.FindInterfaceControl(tab);
var tab = TabHelper.Instance.CurrentTab;
if (tab == null)
return;
var ifc = tab.InterfaceControl;
if (ifc == null)
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg,
$"InterfaceControl for tab '{tab.Name}' was not found. We won't focus that connection.");
return;
}
ifc.Protocol.Focus();
var conFormWindow = ifc.FindForm();
((ConnectionTab)conFormWindow)?.RefreshInterfaceController();
}
/// <summary>
/// Toggle focus between the main window and the last active external app.
/// </summary>
public void ToggleFocus()
{
if (ChildProcessFocused)
{
ForceExtAppToGiveUpFocus();
var focused = NativeMethods.SetForegroundWindow(_mainWindowHandle);
}
else if (MainWindowFocused)
{
ActivateConnection();
}
}
/// <summary>
/// A hook into system keyboard events.
/// </summary>
/// <param name="msg"></param>
/// <param name="kbd"></param>
/// <remarks>
/// This is the only way we can detect ALT-TAB events on Win10, since the EVENT_SYSTEM_SWITCHSTART and
/// EVENT_SYSTEM_SWITCHEND events do not seem to fire. If there is another way to detect that a user
/// is switching between apps using ALT-TAB, then we should try to use that. Hooking into keyboard
/// events like this feels dirty, as it is often used by malicious programs.
/// </remarks>
/// <returns></returns>
private int KeyboardHookCallback(int msg, NativeMethods.KBDLLHOOKSTRUCT kbd)
{
var key = (Keys)kbd.vkCode;
// Alt + Tab
if (key.HasFlag(Keys.Tab) && kbd.flags.HasFlag(NativeMethods.KBDLLHOOKSTRUCTFlags.LLKHF_ALTDOWN))
{
if (msg == NativeMethods.WM_SYSKEYDOWN || msg == NativeMethods.WM_KEYDOWN)
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"ALT-TAB PRESSED (CHILDPROC_FOCUSED={ChildProcessFocused}, CHILDPROC_LAST_FOCUSED={ChildProcessHeldLastFocus}, MRNG_FOCUSED={MrngFocused}, CURR_FIXING={_currentlyFixingAltTab})");
if (ChildProcessHeldLastFocus && MrngFocused && !_currentlyFixingAltTab)
{
FixExternalAppAltTab();
}
}
}
return 0;
}
/// <summary>
/// Ensure that focus events on the main window are allowed to complete
/// without the external app stealing focus away.
/// </summary>
private void ForceExtAppToGiveUpFocus()
{
if (!ChildProcessHeldLastFocus)
return;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Forcing extpp to give up focus.");
ChildProcessHeldLastFocus = false;
}
/// <summary>
/// When we alt-tab and an external app has focus,
/// </summary>
private void FixExternalAppAltTab()
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "FIXING ALT-TAB FOR EXTAPP");
_currentlyFixingAltTab = true;
// simulate an extra TAB key press. This skips focus of the mrng main window.
// end the current alt-tab key press
NativeMethods.keybd_event((byte) Keys.Tab, 0, (uint) NativeMethods.KEYEVENTF.KEYUP, 0);
// start a new alt-tab key press
NativeMethods.keybd_event((byte) Keys.Tab, 0, 0, 0);
// WndProc will never get an event when we switch from a child proc to a completely different program since the main mrng window never had focus to begin with.
// Assume mrng as a whole will lose focus, even though the user could choose to retain focus on us. When Alt-tab completes, the mrng main window will
// receive the focus event and we will handle the child process focusing as necessary.
MainWindowFocused = false;
_currentlyFixingAltTab = false;
}
private void ExternalWindowFocused()
{
_extFocusCount++;
ChildProcessHeldLastFocus = true;
}
private void ExternalWindowDefocused()
{
_extFocusCount--;
ChildProcessHeldLastFocus = !MainWindowFocused && !ChildProcessFocused;
}
/// <summary>
/// Give the <see cref="ExternalProcessFocusHelper"/> a chance to
/// hook into a system window's WndProc message handler. Returns
/// true if an action has been taken which should override the
/// base windows own WndProc handling.
/// </summary>
/// <param name="m"></param>
/// <param name="baseWindowProcessMessage">
/// Call this with the current message to allow the default window handler
/// to process the message. Useful if you want to perform some work after
/// the default processing is complete.
/// </param>
/// <returns>
/// Returns true if an action has been taken which should override the
/// base windows own WndProc handling.
/// </returns>
public bool HandleWndProc(ref Message m, Action<Message> baseWindowProcessMessage)
{
// ReSharper disable once SwitchStatementMissingSomeCases
switch (m.Msg)
{
case NativeMethods.WM_PARENTNOTIFY:
var notifyType = m.WParam.ToInt32();
// ignore non-click notify events
if (notifyType == NativeMethods.WM_CREATE || notifyType == NativeMethods.WM_DESTROY)
break;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Main window clicked");
// when the main window is clicked, assume the user wants the main window focused
ForceExtAppToGiveUpFocus();
break;
case NativeMethods.WM_ACTIVATEAPP:
if (_fixingMainWindowFocus)
break;
// main window is being deactivated
if (m.WParam.ToInt32() == 0)
{
MainWindowFocused = false;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"mRemoteNG main window lost focus (_childProcessHeldLastFocus={ChildProcessHeldLastFocus})");
break;
}
MainWindowFocused = true;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"mRemoteNG main window received focus (_childProcessHeldLastFocus={ChildProcessHeldLastFocus})");
break;
case NativeMethods.WM_SETFOCUS:
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "WM_SETFOCUS");
_fixingMainWindowFocus = true;
baseWindowProcessMessage(m);
_fixingMainWindowFocus = false;
if (ChildProcessHeldLastFocus && MainWindowFocused)
ActivateConnection();
return true;
case NativeMethods.WM_ACTIVATE:
if (m.WParam.ToInt32() == NativeMethods.WA_INACTIVE)
break;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "WM_ACTIVATE");
break;
case NativeMethods.WM_NCACTIVATE:
// Never allow the mRemoteNG window to display itself as inactive. By doing this,
// we ensure focus events can propagate to child connection windows
NativeMethods.DefWindowProc(_mainWindowHandle, Convert.ToUInt32(m.Msg), (IntPtr)1, m.LParam);
m.Result = (IntPtr)1;
return true;
// handle re-focusing connection when the main window moves or resizes
case NativeMethods.WM_ENTERSIZEMOVE:
_inSizeMove = true;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Begin app window move/resize");
break;
case NativeMethods.WM_EXITSIZEMOVE:
_inSizeMove = false;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "End app window move/resize");
// This handles activations from clicks that started a size/move operation
ActivateConnection();
break;
case NativeMethods.WM_WINDOWPOSCHANGED:
// Ignore this message if the window wasn't activated
if (!MainWindowFocused)
break;
var windowPos = (NativeMethods.WINDOWPOS)Marshal.PtrToStructure(m.LParam, typeof(NativeMethods.WINDOWPOS));
if ((windowPos.flags & NativeMethods.SWP_NOACTIVATE) == 0)
{
if (!MainWindowFocused && !_inSizeMove)
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "WM_WINDOWPOSCHANGED DONE");
ActivateConnection();
}
}
break;
}
return false;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposing)
return;
_keyboardHook?.Dispose();
}
}
}

View File

@@ -1,14 +1,18 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Tools; using mRemoteNG.Tools;
namespace mRemoteNG.UI.Forms.OptionsPages namespace mRemoteNG.UI.Forms.OptionsPages
{ {
public sealed partial class AppearancePage public sealed partial class AppearancePage
{ {
public AppearancePage() private readonly IConnectionInitiator _connectionInitiator;
public AppearancePage(IConnectionInitiator connectionInitiator)
{ {
_connectionInitiator = connectionInitiator;
InitializeComponent(); InitializeComponent();
ApplyTheme(); ApplyTheme();
PageIcon = Resources.Panels_Icon; PageIcon = Resources.Panels_Icon;
@@ -82,7 +86,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
{ {
if (Runtime.NotificationAreaIcon == null) if (Runtime.NotificationAreaIcon == null)
{ {
Runtime.NotificationAreaIcon = new NotificationAreaIcon(); Runtime.NotificationAreaIcon = new NotificationAreaIcon(_connectionInitiator);
} }
} }
else else

View File

@@ -1,5 +1,6 @@
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Themes; using mRemoteNG.Themes;
using mRemoteNG.UI.Forms.Input; using mRemoteNG.UI.Forms.Input;
using mRemoteNG.UI.Panels; using mRemoteNG.UI.Panels;
@@ -10,10 +11,10 @@ namespace mRemoteNG.UI.Forms
{ {
private readonly PanelAdder _panelAdder; private readonly PanelAdder _panelAdder;
public FrmChoosePanel() public FrmChoosePanel(IConnectionInitiator connectionInitiator)
{ {
InitializeComponent(); InitializeComponent();
_panelAdder = new PanelAdder(); _panelAdder = new PanelAdder(connectionInitiator);
} }
public string Panel public string Panel

View File

@@ -31,193 +31,189 @@
[System.Diagnostics.DebuggerStepThrough()] [System.Diagnostics.DebuggerStepThrough()]
private void InitializeComponent() private void InitializeComponent()
{ {
this.components = new System.ComponentModel.Container(); this.components = new System.ComponentModel.Container();
mRemoteNG.Connection.ConnectionInitiator connectionInitiator1 = new mRemoteNG.Connection.ConnectionInitiator(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmMain));
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmMain)); this.pnlDock = new WeifenLuo.WinFormsUI.Docking.DockPanel();
this.pnlDock = new WeifenLuo.WinFormsUI.Docking.DockPanel(); this.msMain = new System.Windows.Forms.MenuStrip();
this.msMain = new System.Windows.Forms.MenuStrip(); this.fileMenu = new mRemoteNG.UI.Menu.MainFileMenu();
this.fileMenu = new mRemoteNG.UI.Menu.MainFileMenu(); this.viewMenu = new mRemoteNG.UI.Menu.ViewMenu();
this.viewMenu = new mRemoteNG.UI.Menu.ViewMenu(); this.toolsMenu = new mRemoteNG.UI.Menu.ToolsMenu();
this.toolsMenu = new mRemoteNG.UI.Menu.ToolsMenu(); this.helpMenu = new mRemoteNG.UI.Menu.HelpMenu();
this.helpMenu = new mRemoteNG.UI.Menu.HelpMenu(); this.mMenSep3 = new System.Windows.Forms.ToolStripSeparator();
this.mMenSep3 = new System.Windows.Forms.ToolStripSeparator(); this.tsContainer = new System.Windows.Forms.ToolStripContainer();
this.tsContainer = new System.Windows.Forms.ToolStripContainer(); this._quickConnectToolStrip = new mRemoteNG.UI.Controls.QuickConnectToolStrip();
this._quickConnectToolStrip = new mRemoteNG.UI.Controls.QuickConnectToolStrip(); this._multiSshToolStrip = new mRemoteNG.UI.Controls.MultiSshToolStrip();
this._multiSshToolStrip = new mRemoteNG.UI.Controls.MultiSshToolStrip(); this._externalToolsToolStrip = new mRemoteNG.UI.Controls.ExternalToolsToolStrip();
this._externalToolsToolStrip = new mRemoteNG.UI.Controls.ExternalToolsToolStrip(); this.tmrAutoSave = new System.Windows.Forms.Timer(this.components);
this.tmrAutoSave = new System.Windows.Forms.Timer(this.components); this.vsToolStripExtender = new WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender(this.components);
this.vsToolStripExtender = new WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender(this.components); this.msMain.SuspendLayout();
this.msMain.SuspendLayout(); this.tsContainer.ContentPanel.SuspendLayout();
this.tsContainer.ContentPanel.SuspendLayout(); this.tsContainer.TopToolStripPanel.SuspendLayout();
this.tsContainer.TopToolStripPanel.SuspendLayout(); this.tsContainer.SuspendLayout();
this.tsContainer.SuspendLayout(); this.SuspendLayout();
this.SuspendLayout(); //
// // pnlDock
// pnlDock //
// this.pnlDock.Dock = System.Windows.Forms.DockStyle.Fill;
this.pnlDock.Dock = System.Windows.Forms.DockStyle.Fill; this.pnlDock.DockBackColor = System.Drawing.SystemColors.Control;
this.pnlDock.DockBackColor = System.Drawing.SystemColors.Control; this.pnlDock.DockLeftPortion = 230D;
this.pnlDock.DockLeftPortion = 230D; this.pnlDock.DockRightPortion = 230D;
this.pnlDock.DockRightPortion = 230D; this.pnlDock.DocumentStyle = WeifenLuo.WinFormsUI.Docking.DocumentStyle.DockingSdi;
this.pnlDock.DocumentStyle = WeifenLuo.WinFormsUI.Docking.DocumentStyle.DockingSdi; this.pnlDock.Location = new System.Drawing.Point(0, 0);
this.pnlDock.Location = new System.Drawing.Point(0, 0); this.pnlDock.Name = "pnlDock";
this.pnlDock.Name = "pnlDock"; this.pnlDock.Size = new System.Drawing.Size(1129, 471);
this.pnlDock.Size = new System.Drawing.Size(1129, 471); this.pnlDock.TabIndex = 13;
this.pnlDock.TabIndex = 13; this.pnlDock.ActiveDocumentChanged += new System.EventHandler(this.pnlDock_ActiveDocumentChanged);
this.pnlDock.ActiveDocumentChanged += new System.EventHandler(this.pnlDock_ActiveDocumentChanged); //
// // msMain
// msMain //
// this.msMain.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.msMain.Anchor = System.Windows.Forms.AnchorStyles.Left; this.msMain.Dock = System.Windows.Forms.DockStyle.None;
this.msMain.Dock = System.Windows.Forms.DockStyle.None; this.msMain.GripMargin = new System.Windows.Forms.Padding(2);
this.msMain.GripMargin = new System.Windows.Forms.Padding(2); this.msMain.GripStyle = System.Windows.Forms.ToolStripGripStyle.Visible;
this.msMain.GripStyle = System.Windows.Forms.ToolStripGripStyle.Visible; this.msMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.msMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.fileMenu, this.fileMenu,
this.viewMenu, this.viewMenu,
this.toolsMenu, this.toolsMenu,
this.helpMenu}); this.helpMenu});
this.msMain.Location = new System.Drawing.Point(3, 50); this.msMain.Location = new System.Drawing.Point(3, 50);
this.msMain.Name = "msMain"; this.msMain.Name = "msMain";
this.msMain.Padding = new System.Windows.Forms.Padding(0, 0, 1, 0); this.msMain.Padding = new System.Windows.Forms.Padding(0, 0, 1, 0);
this.msMain.Size = new System.Drawing.Size(184, 25); this.msMain.Size = new System.Drawing.Size(184, 25);
this.msMain.Stretch = false; this.msMain.Stretch = false;
this.msMain.TabIndex = 0; this.msMain.TabIndex = 0;
this.msMain.Text = "Main Toolbar"; this.msMain.Text = "Main Toolbar";
// //
// fileMenu // fileMenu
// //
this.fileMenu.ConnectionInitiator = null; this.fileMenu.ConnectionInitiator = null;
this.fileMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3); this.fileMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
this.fileMenu.Name = "mMenFile"; this.fileMenu.Name = "mMenFile";
this.fileMenu.Size = new System.Drawing.Size(37, 19); this.fileMenu.Size = new System.Drawing.Size(37, 19);
this.fileMenu.Text = "&File"; this.fileMenu.Text = "&File";
this.fileMenu.TreeWindow = null; this.fileMenu.TreeWindow = null;
this.fileMenu.DropDownOpening += new System.EventHandler(this.mainFileMenu1_DropDownOpening); this.fileMenu.DropDownOpening += new System.EventHandler(this.mainFileMenu1_DropDownOpening);
// //
// viewMenu // viewMenu
// //
this.viewMenu.FullscreenHandler = null; this.viewMenu.FullscreenHandler = null;
this.viewMenu.MainForm = null; this.viewMenu.MainForm = null;
this.viewMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3); this.viewMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
this.viewMenu.Name = "mMenView"; this.viewMenu.Name = "mMenView";
this.viewMenu.Size = new System.Drawing.Size(44, 19); this.viewMenu.Size = new System.Drawing.Size(44, 19);
this.viewMenu.Text = "&View"; this.viewMenu.Text = "&View";
this.viewMenu.TsExternalTools = null; this.viewMenu.TsExternalTools = null;
this.viewMenu.TsMultiSsh = null; this.viewMenu.TsMultiSsh = null;
this.viewMenu.TsQuickConnect = null; this.viewMenu.TsQuickConnect = null;
this.viewMenu.DropDownOpening += new System.EventHandler(this.ViewMenu_Opening); this.viewMenu.DropDownOpening += new System.EventHandler(this.ViewMenu_Opening);
// //
// toolsMenu // toolsMenu
// //
this.toolsMenu.CredentialProviderCatalog = null; this.toolsMenu.CredentialProviderCatalog = null;
this.toolsMenu.MainForm = null; this.toolsMenu.MainForm = null;
this.toolsMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3); this.toolsMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
this.toolsMenu.Name = "mMenTools"; this.toolsMenu.Name = "mMenTools";
this.toolsMenu.Size = new System.Drawing.Size(47, 19); this.toolsMenu.Size = new System.Drawing.Size(47, 19);
this.toolsMenu.Text = "&Tools"; this.toolsMenu.Text = "&Tools";
// //
// helpMenu // helpMenu
// //
this.helpMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3); this.helpMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
this.helpMenu.Name = "mMenInfo"; this.helpMenu.Name = "mMenInfo";
this.helpMenu.Size = new System.Drawing.Size(44, 19); this.helpMenu.Size = new System.Drawing.Size(44, 19);
this.helpMenu.Text = "&Help"; this.helpMenu.Text = "&Help";
this.helpMenu.TextDirection = System.Windows.Forms.ToolStripTextDirection.Horizontal; this.helpMenu.TextDirection = System.Windows.Forms.ToolStripTextDirection.Horizontal;
// //
// mMenSep3 // mMenSep3
// //
this.mMenSep3.Name = "mMenSep3"; this.mMenSep3.Name = "mMenSep3";
this.mMenSep3.Size = new System.Drawing.Size(211, 6); this.mMenSep3.Size = new System.Drawing.Size(211, 6);
// //
// tsContainer // tsContainer
// //
// //
// tsContainer.ContentPanel // tsContainer.ContentPanel
// //
this.tsContainer.ContentPanel.Controls.Add(this.pnlDock); this.tsContainer.ContentPanel.Controls.Add(this.pnlDock);
this.tsContainer.ContentPanel.Size = new System.Drawing.Size(1129, 471); this.tsContainer.ContentPanel.Size = new System.Drawing.Size(1129, 471);
this.tsContainer.Dock = System.Windows.Forms.DockStyle.Fill; this.tsContainer.Dock = System.Windows.Forms.DockStyle.Fill;
this.tsContainer.Location = new System.Drawing.Point(0, 0); this.tsContainer.Location = new System.Drawing.Point(0, 0);
this.tsContainer.Name = "tsContainer"; this.tsContainer.Name = "tsContainer";
this.tsContainer.Size = new System.Drawing.Size(1129, 571); this.tsContainer.Size = new System.Drawing.Size(1129, 571);
this.tsContainer.TabIndex = 17; this.tsContainer.TabIndex = 17;
this.tsContainer.Text = "ToolStripContainer1"; this.tsContainer.Text = "ToolStripContainer1";
// //
// tsContainer.TopToolStripPanel // tsContainer.TopToolStripPanel
// //
this.tsContainer.TopToolStripPanel.Controls.Add(this._quickConnectToolStrip); this.tsContainer.TopToolStripPanel.Controls.Add(this._quickConnectToolStrip);
this.tsContainer.TopToolStripPanel.Controls.Add(this._multiSshToolStrip); this.tsContainer.TopToolStripPanel.Controls.Add(this._multiSshToolStrip);
this.tsContainer.TopToolStripPanel.Controls.Add(this.msMain); this.tsContainer.TopToolStripPanel.Controls.Add(this.msMain);
this.tsContainer.TopToolStripPanel.Controls.Add(this._externalToolsToolStrip); this.tsContainer.TopToolStripPanel.Controls.Add(this._externalToolsToolStrip);
this.tsContainer.TopToolStripPanel.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional; this.tsContainer.TopToolStripPanel.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional;
// //
// _quickConnectToolStrip // _quickConnectToolStrip
// //
this._quickConnectToolStrip.BackColor = System.Drawing.SystemColors.Control; this._quickConnectToolStrip.BackColor = System.Drawing.SystemColors.Control;
this._quickConnectToolStrip.ConnectionInitiator = connectionInitiator1; this._quickConnectToolStrip.Dock = System.Windows.Forms.DockStyle.None;
this._quickConnectToolStrip.Dock = System.Windows.Forms.DockStyle.None; this._quickConnectToolStrip.ForeColor = System.Drawing.SystemColors.ControlText;
this._quickConnectToolStrip.ForeColor = System.Drawing.SystemColors.ControlText; this._quickConnectToolStrip.Location = new System.Drawing.Point(3, 0);
this._quickConnectToolStrip.Location = new System.Drawing.Point(3, 0); this._quickConnectToolStrip.Name = "_quickConnectToolStrip";
this._quickConnectToolStrip.Name = "_quickConnectToolStrip"; this._quickConnectToolStrip.Size = new System.Drawing.Size(364, 25);
this._quickConnectToolStrip.Size = new System.Drawing.Size(364, 25); this._quickConnectToolStrip.TabIndex = 18;
this._quickConnectToolStrip.TabIndex = 18; //
// // _multiSshToolStrip
// _multiSshToolStrip //
// this._multiSshToolStrip.Dock = System.Windows.Forms.DockStyle.None;
this._multiSshToolStrip.Dock = System.Windows.Forms.DockStyle.None; this._multiSshToolStrip.Location = new System.Drawing.Point(3, 25);
this._multiSshToolStrip.Location = new System.Drawing.Point(3, 25); this._multiSshToolStrip.MinimumSize = new System.Drawing.Size(300, 0);
this._multiSshToolStrip.MinimumSize = new System.Drawing.Size(300, 0); this._multiSshToolStrip.Name = "_multiSshToolStrip";
this._multiSshToolStrip.Name = "_multiSshToolStrip"; this._multiSshToolStrip.Size = new System.Drawing.Size(376, 25);
this._multiSshToolStrip.Size = new System.Drawing.Size(376, 25); this._multiSshToolStrip.TabIndex = 1;
this._multiSshToolStrip.TabIndex = 1; //
// // _externalToolsToolStrip
// _externalToolsToolStrip //
// this._externalToolsToolStrip.BackColor = System.Drawing.SystemColors.Control;
this._externalToolsToolStrip.BackColor = System.Drawing.SystemColors.Control; this._externalToolsToolStrip.Dock = System.Windows.Forms.DockStyle.None;
this._externalToolsToolStrip.Dock = System.Windows.Forms.DockStyle.None; this._externalToolsToolStrip.ForeColor = System.Drawing.SystemColors.ControlText;
this._externalToolsToolStrip.ForeColor = System.Drawing.SystemColors.ControlText; this._externalToolsToolStrip.Location = new System.Drawing.Point(3, 75);
this._externalToolsToolStrip.Location = new System.Drawing.Point(3, 75); this._externalToolsToolStrip.Name = "_externalToolsToolStrip";
this._externalToolsToolStrip.Name = "_externalToolsToolStrip"; this._externalToolsToolStrip.Size = new System.Drawing.Size(111, 25);
this._externalToolsToolStrip.Size = new System.Drawing.Size(111, 25); this._externalToolsToolStrip.TabIndex = 17;
this._externalToolsToolStrip.TabIndex = 17; //
// // tmrAutoSave
// tmrAutoSave //
// this.tmrAutoSave.Interval = 10000;
this.tmrAutoSave.Interval = 10000; this.tmrAutoSave.Tick += new System.EventHandler(this.tmrAutoSave_Tick);
this.tmrAutoSave.Tick += new System.EventHandler(this.tmrAutoSave_Tick); //
// // vsToolStripExtender
// vsToolStripExtender //
// this.vsToolStripExtender.DefaultRenderer = null;
this.vsToolStripExtender.DefaultRenderer = null; //
// // FrmMain
// FrmMain //
// this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.ClientSize = new System.Drawing.Size(1129, 571);
this.ClientSize = new System.Drawing.Size(1129, 571); this.Controls.Add(this.tsContainer);
this.Controls.Add(this.tsContainer); this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MainMenuStrip = this.msMain;
this.MainMenuStrip = this.msMain; this.MinimumSize = new System.Drawing.Size(400, 400);
this.MinimumSize = new System.Drawing.Size(400, 400); this.Name = "FrmMain";
this.Name = "FrmMain"; this.Opacity = 0D;
this.Opacity = 0D; this.Text = " ";
this.Text = " "; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmMain_FormClosing);
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmMain_FormClosing); this.Load += new System.EventHandler(this.frmMain_Load);
this.Load += new System.EventHandler(this.frmMain_Load); this.Shown += new System.EventHandler(this.frmMain_Shown);
this.Shown += new System.EventHandler(this.frmMain_Shown); this.Resize += new System.EventHandler(this.frmMain_Resize);
this.ResizeBegin += new System.EventHandler(this.frmMain_ResizeBegin); this.msMain.ResumeLayout(false);
this.ResizeEnd += new System.EventHandler(this.frmMain_ResizeEnd); this.msMain.PerformLayout();
this.Resize += new System.EventHandler(this.frmMain_Resize); this.tsContainer.ContentPanel.ResumeLayout(false);
this.msMain.ResumeLayout(false); this.tsContainer.TopToolStripPanel.ResumeLayout(false);
this.msMain.PerformLayout(); this.tsContainer.TopToolStripPanel.PerformLayout();
this.tsContainer.ContentPanel.ResumeLayout(false); this.tsContainer.ResumeLayout(false);
this.tsContainer.TopToolStripPanel.ResumeLayout(false); this.tsContainer.PerformLayout();
this.tsContainer.TopToolStripPanel.PerformLayout(); this.ResumeLayout(false);
this.tsContainer.ResumeLayout(false);
this.tsContainer.PerformLayout();
this.ResumeLayout(false);
} }
internal WeifenLuo.WinFormsUI.Docking.DockPanel pnlDock; internal WeifenLuo.WinFormsUI.Docking.DockPanel pnlDock;

View File

@@ -8,11 +8,14 @@ using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Putty; using mRemoteNG.Config.Putty;
using mRemoteNG.Config.Settings; using mRemoteNG.Config.Settings;
using mRemoteNG.Connection; using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.Messages.MessageWriters; using mRemoteNG.Messages.MessageWriters;
using mRemoteNG.Themes; using mRemoteNG.Themes;
using mRemoteNG.Tools; using mRemoteNG.Tools;
using mRemoteNG.UI.FocusHelpers;
using mRemoteNG.UI.Menu; using mRemoteNG.UI.Menu;
using mRemoteNG.UI.Panels;
using mRemoteNG.UI.Tabs; using mRemoteNG.UI.Tabs;
using mRemoteNG.UI.TaskDialog; using mRemoteNG.UI.TaskDialog;
using mRemoteNG.UI.Window; using mRemoteNG.UI.Window;
@@ -23,11 +26,10 @@ using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.UI.Panels;
using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.Docking;
using Message = System.Windows.Forms.Message;
// ReSharper disable MemberCanBePrivate.Global // ReSharper disable MemberCanBePrivate.Global
@@ -38,8 +40,6 @@ namespace mRemoteNG.UI.Forms
public static FrmMain Default { get; } = new FrmMain(); public static FrmMain Default { get; } = new FrmMain();
private static ClipboardchangeEventHandler _clipboardChangedEvent; private static ClipboardchangeEventHandler _clipboardChangedEvent;
private bool _inSizeMove;
private bool _inMouseActivate;
private IntPtr _fpChainedWindowHandle; private IntPtr _fpChainedWindowHandle;
private bool _usingSqlServer; private bool _usingSqlServer;
private string _connectionsFileName; private string _connectionsFileName;
@@ -49,6 +49,8 @@ namespace mRemoteNG.UI.Forms
private readonly IList<IMessageWriter> _messageWriters = new List<IMessageWriter>(); private readonly IList<IMessageWriter> _messageWriters = new List<IMessageWriter>();
private readonly ThemeManager _themeManager; private readonly ThemeManager _themeManager;
private readonly FileBackupPruner _backupPruner = new FileBackupPruner(); private readonly FileBackupPruner _backupPruner = new FileBackupPruner();
private readonly IConnectionInitiator _connectionInitiator;
private readonly ExternalProcessFocusHelper _focusHelper;
internal FullscreenHandler Fullscreen { get; set; } internal FullscreenHandler Fullscreen { get; set; }
@@ -67,6 +69,11 @@ namespace mRemoteNG.UI.Forms
ApplyTheme(); ApplyTheme();
_screenSystemMenu = new ScreenSelectionSystemMenu(this); _screenSystemMenu = new ScreenSelectionSystemMenu(this);
var protocolFactory = new ProtocolFactory();
_connectionInitiator = new ConnectionInitiator(protocolFactory);
Debug.Assert(IsHandleCreated, "Expected main window handle to be created by now");
_focusHelper = new ExternalProcessFocusHelper(_connectionInitiator, Handle);
} }
#region Properties #region Properties
@@ -145,10 +152,11 @@ namespace mRemoteNG.UI.Forms
MessageCollectorSetup.SetupMessageCollector(messageCollector, _messageWriters); MessageCollectorSetup.SetupMessageCollector(messageCollector, _messageWriters);
MessageCollectorSetup.BuildMessageWritersFromSettings(_messageWriters); MessageCollectorSetup.BuildMessageWritersFromSettings(_messageWriters);
Windows.ConnectionInitiator = _connectionInitiator;
Startup.Instance.InitializeProgram(messageCollector); Startup.Instance.InitializeProgram(messageCollector);
msMain.Location = Point.Empty; msMain.Location = Point.Empty;
var settingsLoader = new SettingsLoader(this, messageCollector, _quickConnectToolStrip, var settingsLoader = new SettingsLoader(this, _connectionInitiator, messageCollector, _quickConnectToolStrip,
_externalToolsToolStrip, _multiSshToolStrip, msMain); _externalToolsToolStrip, _multiSshToolStrip, msMain);
settingsLoader.LoadSettings(); settingsLoader.LoadSettings();
@@ -200,14 +208,29 @@ namespace mRemoteNG.UI.Forms
ShowInTaskbar = false; ShowInTaskbar = false;
} }
if (!Settings.Default.CreateEmptyPanelOnStartUp) return; if (Settings.Default.CreateEmptyPanelOnStartUp)
var panelName = !string.IsNullOrEmpty(Settings.Default.StartUpPanelName) {
? Settings.Default.StartUpPanelName var panelName = !string.IsNullOrEmpty(Settings.Default.StartUpPanelName)
: Language.strNewPanel; ? Settings.Default.StartUpPanelName
: Language.strNewPanel;
var panelAdder = new PanelAdder(); var panelAdder = new PanelAdder(_connectionInitiator);
if (!panelAdder.DoesPanelExist(panelName)) if (!panelAdder.DoesPanelExist(panelName))
panelAdder.AddPanel(panelName); panelAdder.AddPanel(panelName);
}
TabHelper.Instance.ActiveConnectionTabChanged += OnActiveConnectionTabChanged;
TabHelper.Instance.TabClicked += OnTabClicked;
}
private void OnTabClicked(object sender, EventArgs e)
{
_focusHelper.ActivateConnection();
}
private void OnActiveConnectionTabChanged(object sender, EventArgs e)
{
_focusHelper.ActivateConnection();
} }
private void ApplyLanguage() private void ApplyLanguage()
@@ -256,20 +279,20 @@ namespace mRemoteNG.UI.Forms
private void SetMenuDependencies() private void SetMenuDependencies()
{ {
var connectionInitiator = new ConnectionInitiator();
fileMenu.TreeWindow = Windows.TreeForm; fileMenu.TreeWindow = Windows.TreeForm;
fileMenu.ConnectionInitiator = connectionInitiator; fileMenu.ConnectionInitiator = _connectionInitiator;
viewMenu.TsExternalTools = _externalToolsToolStrip; viewMenu.TsExternalTools = _externalToolsToolStrip;
viewMenu.TsQuickConnect = _quickConnectToolStrip; viewMenu.TsQuickConnect = _quickConnectToolStrip;
viewMenu.TsMultiSsh = _multiSshToolStrip; viewMenu.TsMultiSsh = _multiSshToolStrip;
viewMenu.FullscreenHandler = Fullscreen; viewMenu.FullscreenHandler = Fullscreen;
viewMenu.MainForm = this; viewMenu.MainForm = this;
viewMenu.ConnectionInitiator = _connectionInitiator;
toolsMenu.MainForm = this; toolsMenu.MainForm = this;
toolsMenu.CredentialProviderCatalog = Runtime.CredentialProviderCatalog; toolsMenu.CredentialProviderCatalog = Runtime.CredentialProviderCatalog;
_quickConnectToolStrip.ConnectionInitiator = connectionInitiator; _quickConnectToolStrip.ConnectionInitiator = _connectionInitiator;
} }
//Theming support //Theming support
@@ -345,7 +368,7 @@ namespace mRemoteNG.UI.Forms
if (CTaskDialog.CommandButtonResult != 1) return; if (CTaskDialog.CommandButtonResult != 1) return;
using (var optionsForm = new FrmOptions(Language.strTabUpdates)) using (var optionsForm = new FrmOptions(Language.strTabUpdates, _connectionInitiator))
{ {
optionsForm.ShowDialog(this); optionsForm.ShowDialog(this);
} }
@@ -355,13 +378,8 @@ namespace mRemoteNG.UI.Forms
{ {
if (!Settings.Default.CheckForUpdatesOnStartup) return; if (!Settings.Default.CheckForUpdatesOnStartup) return;
var nextUpdateCheck = Convert.ToDateTime( var updateFrequencyInDays = Convert.ToDouble(Settings.Default.CheckForUpdatesFrequencyDays);
Settings.Default.CheckForUpdatesLastCheck.Add( var nextUpdateCheck = Settings.Default.CheckForUpdatesLastCheck.AddDays(updateFrequencyInDays);
TimeSpan
.FromDays(Convert
.ToDouble(Settings
.Default
.CheckForUpdatesFrequencyDays))));
if (!Settings.Default.UpdatePending && DateTime.UtcNow <= nextUpdateCheck) return; if (!Settings.Default.UpdatePending && DateTime.UtcNow <= nextUpdateCheck) return;
if (!IsHandleCreated) if (!IsHandleCreated)
@@ -372,6 +390,8 @@ namespace mRemoteNG.UI.Forms
private void frmMain_FormClosing(object sender, FormClosingEventArgs e) private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{ {
_focusHelper?.Dispose();
if (!(Runtime.WindowList == null || Runtime.WindowList.Count == 0)) if (!(Runtime.WindowList == null || Runtime.WindowList.Count == 0))
{ {
var openConnections = 0; var openConnections = 0;
@@ -440,12 +460,6 @@ namespace mRemoteNG.UI.Forms
#endregion #endregion
#region Window Overrides and DockPanel Stuff #region Window Overrides and DockPanel Stuff
private void frmMain_ResizeBegin(object sender, EventArgs e)
{
_inSizeMove = true;
}
private void frmMain_Resize(object sender, EventArgs e) private void frmMain_Resize(object sender, EventArgs e)
{ {
if (WindowState == FormWindowState.Minimized) if (WindowState == FormWindowState.Minimized)
@@ -453,7 +467,7 @@ namespace mRemoteNG.UI.Forms
if (!Settings.Default.MinimizeToTray) return; if (!Settings.Default.MinimizeToTray) return;
if (Runtime.NotificationAreaIcon == null) if (Runtime.NotificationAreaIcon == null)
{ {
Runtime.NotificationAreaIcon = new NotificationAreaIcon(); Runtime.NotificationAreaIcon = new NotificationAreaIcon(_connectionInitiator);
} }
Hide(); Hide();
@@ -464,81 +478,62 @@ namespace mRemoteNG.UI.Forms
} }
} }
private void frmMain_ResizeEnd(object sender, EventArgs e) // Maybe after starting putty, remove its ability to show up in alt-tab?
{ // SetWindowLong(this.Handle, GWL_EXSTYLE, (GetWindowLong(this.Handle,GWL_EXSTYLE) | WS_EX_TOOLWINDOW) & ~WS_EX_APPWINDOW);
_inSizeMove = false; protected override void WndProc(ref Message m)
// This handles activations from clicks that started a size/move operation
ActivateConnection();
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{ {
// Listen for and handle operating system messages // Listen for and handle operating system messages
try try
{ {
if (_focusHelper?.HandleWndProc(ref m, wm => base.WndProc(ref wm)) == true)
return;
// ReSharper disable once SwitchStatementMissingSomeCases // ReSharper disable once SwitchStatementMissingSomeCases
switch (m.Msg) switch (m.Msg)
{ {
case NativeMethods.WM_MOUSEACTIVATE: case NativeMethods.WM_MOUSEACTIVATE:
_inMouseActivate = true; var controlThatWasClicked2 = FromChildHandle(NativeMethods.WindowFromPoint(MousePosition))
break; ?? GetChildAtPoint(MousePosition);
case NativeMethods.WM_ACTIVATEAPP:
var candidateTabToFocus = FromChildHandle(NativeMethods.WindowFromPoint(MousePosition))
?? GetChildAtPoint(MousePosition);
if (candidateTabToFocus is InterfaceControl) if (controlThatWasClicked2 == null)
{ break;
candidateTabToFocus.Parent.Focus();
}
_inMouseActivate = false; Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Clicked control: {controlThatWasClicked2}");
break; break;
case NativeMethods.WM_ACTIVATE: case NativeMethods.WM_ACTIVATE:
// Only handle this msg if it was triggered by a click // Only handle this msg if it was triggered by a click
if (NativeMethods.LOWORD(m.WParam) == NativeMethods.WA_CLICKACTIVE) if (NativeMethods.LOWORD(m.WParam) != NativeMethods.WA_CLICKACTIVE)
{ return;
var controlThatWasClicked = FromChildHandle(NativeMethods.WindowFromPoint(MousePosition))
?? GetChildAtPoint(MousePosition);
if (controlThatWasClicked != null)
{
if (controlThatWasClicked is TreeView ||
controlThatWasClicked is ComboBox ||
controlThatWasClicked is TextBox ||
controlThatWasClicked is FrmMain)
{
controlThatWasClicked.Focus();
}
else if (controlThatWasClicked.CanSelect ||
controlThatWasClicked is MenuStrip ||
controlThatWasClicked is ToolStrip)
{
// Simulate a mouse event since one wasn't generated by Windows
SimulateClick(controlThatWasClicked);
controlThatWasClicked.Focus();
}
else if (controlThatWasClicked is AutoHideStripBase)
{
// only focus the autohide toolstrip
controlThatWasClicked.Focus();
}
else
{
// This handles activations from clicks that did not start a size/move operation
ActivateConnection();
}
}
}
break; var controlThatWasClicked = FromChildHandle(NativeMethods.WindowFromPoint(MousePosition))
case NativeMethods.WM_WINDOWPOSCHANGED: ?? GetChildAtPoint(MousePosition);
// Ignore this message if the window wasn't activated
var windowPos = if (controlThatWasClicked == null)
(NativeMethods.WINDOWPOS)Marshal.PtrToStructure(m.LParam, typeof(NativeMethods.WINDOWPOS)); break;
if ((windowPos.flags & NativeMethods.SWP_NOACTIVATE) == 0)
{ Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Click activate: {controlThatWasClicked}");
if (!_inMouseActivate && !_inSizeMove)
ActivateConnection(); //if (controlThatWasClicked is TreeView ||
} // controlThatWasClicked is ComboBox ||
// controlThatWasClicked is TextBox ||
// controlThatWasClicked is FrmMain ||
// controlThatWasClicked is AutoHideStripBase)
//{
// controlThatWasClicked.Focus();
//}
//else if (controlThatWasClicked.CanSelect ||
// controlThatWasClicked is MenuStrip ||
// controlThatWasClicked is ToolStrip)
//{
// // Simulate a mouse event since one wasn't generated by Windows
// SimulateClick(controlThatWasClicked);
// controlThatWasClicked.Focus();
//}
//else
//{
// // This handles activations from clicks that did not start a size/move operation
// ActivateConnection();
//}
break; break;
case NativeMethods.WM_SYSCOMMAND: case NativeMethods.WM_SYSCOMMAND:
@@ -576,23 +571,9 @@ namespace mRemoteNG.UI.Forms
clientMousePosition.Y = temp_wHigh; clientMousePosition.Y = temp_wHigh;
} }
private void ActivateConnection()
{
var cw = pnlDock.ActiveDocument as ConnectionWindow;
var dp = cw?.ActiveControl as DockPane;
if (!(dp?.ActiveContent is ConnectionTab tab)) return;
var ifc = InterfaceControl.FindInterfaceControl(tab);
if (ifc == null) return;
ifc.Protocol.Focus();
var conFormWindow = ifc.FindForm();
((ConnectionTab)conFormWindow)?.RefreshInterfaceController();
}
private void pnlDock_ActiveDocumentChanged(object sender, EventArgs e) private void pnlDock_ActiveDocumentChanged(object sender, EventArgs e)
{ {
ActivateConnection(); //_focusHelper.ActivateConnection();
} }
internal void UpdateWindowTitle() internal void UpdateWindowTitle()

View File

@@ -4,26 +4,30 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.Connection;
using mRemoteNG.Themes; using mRemoteNG.Themes;
namespace mRemoteNG.UI.Forms namespace mRemoteNG.UI.Forms
{ {
public partial class FrmOptions : Form public partial class FrmOptions : Form
{ {
private readonly IConnectionInitiator _connectionInitiator;
private Dictionary<string, OptionsPage> _pages; private Dictionary<string, OptionsPage> _pages;
private readonly string _pageName; private readonly string _pageName;
private readonly DisplayProperties _display = new DisplayProperties(); private readonly DisplayProperties _display = new DisplayProperties();
public FrmOptions() : this(Language.strStartupExit) public FrmOptions(IConnectionInitiator connectionInitiator)
: this(Language.strStartupExit, connectionInitiator)
{ {
} }
public FrmOptions(string pn) public FrmOptions(string pn, IConnectionInitiator connectionInitiator)
{ {
Cursor.Current = Cursors.WaitCursor; Cursor.Current = Cursors.WaitCursor;
Application.DoEvents(); Application.DoEvents();
InitializeComponent(); InitializeComponent();
_pageName = pn; _pageName = pn;
_connectionInitiator = connectionInitiator;
Cursor.Current = Cursors.Default; Cursor.Current = Cursors.Default;
} }
@@ -68,7 +72,7 @@ namespace mRemoteNG.UI.Forms
_pages = new Dictionary<string, OptionsPage> _pages = new Dictionary<string, OptionsPage>
{ {
{typeof(StartupExitPage).Name, new StartupExitPage {Dock = DockStyle.Fill}}, {typeof(StartupExitPage).Name, new StartupExitPage {Dock = DockStyle.Fill}},
{typeof(AppearancePage).Name, new AppearancePage {Dock = DockStyle.Fill}}, {typeof(AppearancePage).Name, new AppearancePage(_connectionInitiator) {Dock = DockStyle.Fill}},
{typeof(TabsPanelsPage).Name, new TabsPanelsPage {Dock = DockStyle.Fill}}, {typeof(TabsPanelsPage).Name, new TabsPanelsPage {Dock = DockStyle.Fill}},
{typeof(NotificationsPage).Name, new NotificationsPage {Dock = DockStyle.Fill}}, {typeof(NotificationsPage).Name, new NotificationsPage {Dock = DockStyle.Fill}},
{typeof(ConnectionsPage).Name, new ConnectionsPage {Dock = DockStyle.Fill}}, {typeof(ConnectionsPage).Name, new ConnectionsPage {Dock = DockStyle.Fill}},

View File

@@ -453,7 +453,7 @@ namespace mRemoteNG.UI.Menu
if (!(window is ConnectionWindow connectionWindow)) if (!(window is ConnectionWindow connectionWindow))
return; return;
connectionWindow.reconnectAll(ConnectionInitiator); connectionWindow.ReconnectAll(ConnectionInitiator);
} }
} }

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms;
using mRemoteNG.UI.Panels; using mRemoteNG.UI.Panels;
using mRemoteNG.UI.Window; using mRemoteNG.UI.Window;
@@ -27,7 +28,6 @@ namespace mRemoteNG.UI.Menu
private ToolStripMenuItem _mMenViewResetLayout; private ToolStripMenuItem _mMenViewResetLayout;
private ToolStripMenuItem _mMenViewLockToolbars; private ToolStripMenuItem _mMenViewLockToolbars;
private ToolStripSeparator _toolStripSeparator1; private ToolStripSeparator _toolStripSeparator1;
private readonly PanelAdder _panelAdder;
public ToolStrip TsExternalTools { get; set; } public ToolStrip TsExternalTools { get; set; }
@@ -35,12 +35,12 @@ namespace mRemoteNG.UI.Menu
public ToolStrip TsMultiSsh { get; set; } public ToolStrip TsMultiSsh { get; set; }
public FullscreenHandler FullscreenHandler { get; set; } public FullscreenHandler FullscreenHandler { get; set; }
public FrmMain MainForm { get; set; } public FrmMain MainForm { get; set; }
public IConnectionInitiator ConnectionInitiator { get; set; }
public ViewMenu() public ViewMenu()
{ {
Initialize(); Initialize();
_panelAdder = new PanelAdder();
} }
private void Initialize() private void Initialize()
@@ -374,7 +374,7 @@ namespace mRemoteNG.UI.Menu
private void mMenViewAddConnectionPanel_Click(object sender, EventArgs e) private void mMenViewAddConnectionPanel_Click(object sender, EventArgs e)
{ {
_panelAdder.AddPanel(); new PanelAdder(ConnectionInitiator).AddPanel();
} }
private void mMenViewExtAppsToolbar_Click(object sender, EventArgs e) private void mMenViewExtAppsToolbar_Click(object sender, EventArgs e)

View File

@@ -7,17 +7,25 @@ using System;
using System.Collections; using System.Collections;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.Connection;
using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNG.UI.Panels namespace mRemoteNG.UI.Panels
{ {
public class PanelAdder public class PanelAdder
{ {
private readonly IConnectionInitiator _connectionInitiator;
public PanelAdder(IConnectionInitiator connectionInitiator)
{
_connectionInitiator = connectionInitiator;
}
public ConnectionWindow AddPanel(string title = "") public ConnectionWindow AddPanel(string title = "")
{ {
try try
{ {
var connectionForm = new ConnectionWindow(new DockContent()); var connectionForm = new ConnectionWindow(new DockContent(), _connectionInitiator);
BuildConnectionWindowContextMenu(connectionForm); BuildConnectionWindowContextMenu(connectionForm);
SetConnectionWindowTitle(title, connectionForm); SetConnectionWindowTitle(title, connectionForm);
ShowConnectionWindow(connectionForm); ShowConnectionWindow(connectionForm);

View File

@@ -0,0 +1,60 @@
using mRemoteNG.App;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace mRemoteNG.UI
{
public class SystemKeyboardHook : IDisposable
{
private readonly IntPtr _hookId;
private readonly Func<int, NativeMethods.KBDLLHOOKSTRUCT, int> _userCallback;
private readonly NativeMethods.LowLevelKeyboardProc _sysCallback;
private bool _disposed;
public SystemKeyboardHook(Func<int, NativeMethods.KBDLLHOOKSTRUCT, int> proc)
{
_userCallback = proc;
_sysCallback = SystemCallback;
using (var curProcess = Process.GetCurrentProcess())
using (var curModule = curProcess.MainModule)
{
_hookId = NativeMethods.SetWindowsHookEx(
NativeMethods.WH_KEYBOARD_LL,
_sysCallback,
NativeMethods.GetModuleHandle(curModule.ModuleName),
0);
}
}
private IntPtr SystemCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
var kdb = Marshal.PtrToStructure<NativeMethods.KBDLLHOOKSTRUCT>(lParam);
return new IntPtr(_userCallback(wParam.ToInt32(), kdb));
}
return NativeMethods.CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
NativeMethods.UnhookWindowsHookEx(_hookId);
}
_disposed = true;
}
}
}

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.App.Info; using mRemoteNG.App.Info;
@@ -6,6 +7,7 @@ using mRemoteNG.Config;
using mRemoteNG.Connection; using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.VNC; using mRemoteNG.Connection.Protocol.VNC;
using mRemoteNG.Messages;
using mRemoteNG.UI.TaskDialog; using mRemoteNG.UI.TaskDialog;
using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.Docking;
@@ -13,81 +15,73 @@ namespace mRemoteNG.UI.Tabs
{ {
public partial class ConnectionTab : DockContent public partial class ConnectionTab : DockContent
{ {
public InterfaceControl InterfaceControl => Tag as InterfaceControl;
/// <summary> /// <summary>
///Silent close ignores the popup asking for confirmation ///Silent close ignores the popup asking for confirmation
/// </summary> /// </summary>
public bool silentClose { get; set; } public bool SilentClose { get; set; }
/// <summary> /// <summary>
/// Protocol close ignores the interface controller cleanup and the user confirmation dialog /// Protocol close ignores the interface controller cleanup and the user confirmation dialog
/// </summary> /// </summary>
public bool protocolClose { get; set; } public bool ProtocolClose { get; set; }
public ConnectionTab() public ConnectionTab()
{ {
InitializeComponent(); InitializeComponent();
GotFocus += ConnectionTab_GotFocus; GotFocus += ConnectionTab_GotFocus;
Activated += OnActivated;
Click += OnClick;
}
private void OnClick(object sender, EventArgs e)
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Tab clicked: '{TabText}'");
}
private void OnActivated(object sender, EventArgs e)
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Tab activated: '{TabText}'");
} }
private void ConnectionTab_GotFocus(object sender, EventArgs e) private void ConnectionTab_GotFocus(object sender, EventArgs e)
{ {
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Tab received focused: '{TabText}'");
TabHelper.Instance.CurrentTab = this; TabHelper.Instance.CurrentTab = this;
} }
protected override void OnFormClosing(FormClosingEventArgs e) protected override void OnFormClosing(FormClosingEventArgs e)
{ {
if (!protocolClose) if (!ProtocolClose)
{ {
if (!silentClose) if (!SilentClose)
{ {
if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All)
{ {
var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, ShowCloseConnectionTabPrompt(e);
string
.Format(Language.strConfirmCloseConnectionPanelMainInstruction,
TabText), "", "", "",
Language.strCheckboxDoNotShowThisMessageAgain,
ETaskDialogButtons.YesNo, ESysIcons.Question,
ESysIcons.Question);
if (CTaskDialog.VerificationChecked)
{
Settings.Default.ConfirmCloseConnection--;
}
if (result == DialogResult.No)
{
e.Cancel = true;
}
else
{
((InterfaceControl)Tag)?.Protocol.Close();
}
} }
else else
{ {
// close without the confirmation prompt... // close without the confirmation prompt...
((InterfaceControl)Tag)?.Protocol.Close(); InterfaceControl?.Protocol.Close();
} }
} }
else else
{ {
((InterfaceControl)Tag)?.Protocol.Close(); InterfaceControl?.Protocol.Close();
} }
} }
base.OnFormClosing(e); base.OnFormClosing(e);
} }
#region HelperFunctions
public void RefreshInterfaceController() public void RefreshInterfaceController()
{ {
try try
{ {
var interfaceControl = Tag as InterfaceControl; if (InterfaceControl?.Info.Protocol == ProtocolType.VNC)
if (interfaceControl?.Info.Protocol == ProtocolType.VNC) ((ProtocolVNC)InterfaceControl.Protocol).RefreshScreen();
((ProtocolVNC)interfaceControl.Protocol).RefreshScreen();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -95,6 +89,28 @@ namespace mRemoteNG.UI.Tabs
} }
} }
#endregion private void ShowCloseConnectionTabPrompt(FormClosingEventArgs e)
{
var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName,
string.Format(Language.strConfirmCloseConnectionPanelMainInstruction, TabText),
"", "", "",
Language.strCheckboxDoNotShowThisMessageAgain,
ETaskDialogButtons.YesNo, ESysIcons.Question,
ESysIcons.Question);
if (CTaskDialog.VerificationChecked)
{
Settings.Default.ConfirmCloseConnection--;
}
if (result == DialogResult.No)
{
e.Cancel = true;
}
else
{
InterfaceControl?.Protocol.Close();
}
}
} }
} }

View File

@@ -1088,11 +1088,22 @@ namespace mRemoteNG.UI.Tabs
protected override void OnMouseDown(MouseEventArgs e) protected override void OnMouseDown(MouseEventArgs e)
{ {
App.Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, "Mouse down");
base.OnMouseDown(e); base.OnMouseDown(e);
// suspend drag if mouse is down on active close button. // suspend drag if mouse is down on active close button.
m_suspendDrag = ActiveCloseHitTest(e.Location); m_suspendDrag = ActiveCloseHitTest(e.Location);
if (!IsMouseDown) if (!IsMouseDown)
IsMouseDown = true; IsMouseDown = true;
var tabIndex = HitTest(e.Location);
if (tabIndex < 0 || tabIndex >= Tabs.Count)
return;
var tab = Tabs[tabIndex].Content as ConnectionTab;
if (tab == null)
return;
TabHelper.Instance.CurrentTab = tab;
TabHelper.Instance.RaiseTabClickedEvent();
} }
protected override void OnMouseMove(MouseEventArgs e) protected override void OnMouseMove(MouseEventArgs e)
@@ -1149,6 +1160,7 @@ namespace mRemoteNG.UI.Tabs
protected override void OnMouseClick(MouseEventArgs e) protected override void OnMouseClick(MouseEventArgs e)
{ {
App.Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, "Mouse click");
base.OnMouseClick(e); base.OnMouseClick(e);
if (e.Button != MouseButtons.Left || Appearance != DockPane.AppearanceStyle.Document) if (e.Button != MouseButtons.Left || Appearance != DockPane.AppearanceStyle.Document)
return; return;

View File

@@ -4,12 +4,18 @@ using System;
namespace mRemoteNG.UI.Tabs namespace mRemoteNG.UI.Tabs
{ {
class TabHelper public class TabHelper
{ {
private static readonly Lazy<TabHelper> lazyHelper = new Lazy<TabHelper>(() => new TabHelper()); private static readonly Lazy<TabHelper> lazyHelper = new Lazy<TabHelper>(() => new TabHelper());
public static TabHelper Instance => lazyHelper.Value; public static TabHelper Instance => lazyHelper.Value;
/// <summary>
/// Should focus events on a connection tab automatically focus
/// its child connection?
/// </summary>
public bool FocusConnection { get; set; } = true;
private TabHelper() private TabHelper()
{ {
} }
@@ -21,10 +27,16 @@ namespace mRemoteNG.UI.Tabs
get => currentTab; get => currentTab;
set set
{ {
if (currentTab == value)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, $"Tab already current: '{currentTab.TabText}'");
return;
}
currentTab = value; currentTab = value;
findCurrentPanel(); findCurrentPanel();
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, $"Current tab changed: '{currentTab.TabText}'");
"Tab got focused: " + currentTab.TabText); RaiseActiveConnectionTabChangedEvent();
} }
} }
@@ -36,7 +48,7 @@ namespace mRemoteNG.UI.Tabs
currentForm = currentForm.Parent; currentForm = currentForm.Parent;
} }
if (currentForm != null) if (currentForm != null && CurrentPanel != currentForm)
CurrentPanel = (ConnectionWindow)currentForm; CurrentPanel = (ConnectionWindow)currentForm;
} }
@@ -47,10 +59,31 @@ namespace mRemoteNG.UI.Tabs
get => currentPanel; get => currentPanel;
set set
{ {
if (currentPanel == value)
return;
currentPanel = value; currentPanel = value;
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, $"Current panel changed: '{currentPanel.TabText}'");
"Panel got focused: " + currentPanel.TabText); RaiseActivePanelChangedEvent();
} }
} }
public event EventHandler ActivePanelChanged;
protected virtual void RaiseActivePanelChangedEvent()
{
ActivePanelChanged?.Invoke(this, EventArgs.Empty);
}
public event EventHandler ActiveConnectionTabChanged;
protected virtual void RaiseActiveConnectionTabChangedEvent()
{
ActiveConnectionTabChanged?.Invoke(this, EventArgs.Empty);
}
public event EventHandler TabClicked;
public void RaiseTabClickedEvent()
{
TabClicked?.Invoke(this, EventArgs.Empty);
}
} }
} }

View File

@@ -21,7 +21,7 @@ namespace mRemoteNG.UI.Window
{ {
public partial class ConnectionTreeWindow public partial class ConnectionTreeWindow
{ {
private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); private readonly IConnectionInitiator _connectionInitiator;
private ThemeManager _themeManager; private ThemeManager _themeManager;
private bool sortedAz = true; private bool sortedAz = true;
@@ -33,12 +33,14 @@ namespace mRemoteNG.UI.Window
set { olvConnections = value; } set { olvConnections = value; }
} }
public ConnectionTreeWindow() : this(new DockContent()) public ConnectionTreeWindow(IConnectionInitiator connectionInitiator)
: this(new DockContent(), connectionInitiator)
{ {
} }
public ConnectionTreeWindow(DockContent panel) public ConnectionTreeWindow(DockContent panel, IConnectionInitiator connectionInitiator)
{ {
_connectionInitiator = connectionInitiator;
WindowType = WindowType.Tree; WindowType = WindowType.Tree;
DockPnl = panel; DockPnl = panel;
InitializeComponent(); InitializeComponent();

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.App; using mRemoteNG.App;
@@ -23,14 +24,15 @@ namespace mRemoteNG.UI.Window
{ {
public partial class ConnectionWindow : BaseWindow public partial class ConnectionWindow : BaseWindow
{ {
private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); private readonly IConnectionInitiator _connectionInitiator;
private VisualStudioToolStripExtender vsToolStripExtender; private VisualStudioToolStripExtender vsToolStripExtender;
private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer(); private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer();
#region Public Methods #region Public Methods
public ConnectionWindow(DockContent panel, string formText = "") public ConnectionWindow(DockContent panel, IConnectionInitiator connectionInitiator, string formText = "")
{ {
_connectionInitiator = connectionInitiator;
if (formText == "") if (formText == "")
{ {
formText = Language.strNewPanel; formText = Language.strNewPanel;
@@ -96,6 +98,7 @@ namespace mRemoteNG.UI.Window
private void ConnectionWindow_GotFocus(object sender, EventArgs e) private void ConnectionWindow_GotFocus(object sender, EventArgs e)
{ {
TabHelper.Instance.CurrentPanel = this; TabHelper.Instance.CurrentPanel = this;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Connection window focused: '{TabText}'");
} }
public ConnectionTab AddConnectionTab(ConnectionInfo connectionInfo) public ConnectionTab AddConnectionTab(ConnectionInfo connectionInfo)
@@ -131,7 +134,7 @@ namespace mRemoteNG.UI.Window
var conTab = new ConnectionTab var conTab = new ConnectionTab
{ {
Tag = connectionInfo, Tag = connectionInfo, // BUG: the Tag gets set to an InterfaceControl later on. Is this right?
DockAreas = DockAreas.Document | DockAreas.Float, DockAreas = DockAreas.Document | DockAreas.Float,
Icon = ConnectionIcon.FromString(connectionInfo.Icon), Icon = ConnectionIcon.FromString(connectionInfo.Icon),
TabText = titleText, TabText = titleText,
@@ -159,7 +162,7 @@ namespace mRemoteNG.UI.Window
#endregion #endregion
public void reconnectAll(IConnectionInitiator initiator) public void ReconnectAll(IConnectionInitiator initiator)
{ {
var controlList = new List<InterfaceControl>(); var controlList = new List<InterfaceControl>();
try try
@@ -316,7 +319,7 @@ namespace mRemoteNG.UI.Window
{ {
var tabP = (ConnectionTab)dockContent; var tabP = (ConnectionTab)dockContent;
if (tabP.Tag == null) continue; if (tabP.Tag == null) continue;
tabP.silentClose = true; tabP.SilentClose = true;
tabP.Close(); tabP.Close();
} }
} }
@@ -798,7 +801,7 @@ namespace mRemoteNG.UI.Window
var protocolBase = sender as ProtocolBase; var protocolBase = sender as ProtocolBase;
if (!(protocolBase?.InterfaceControl.Parent is ConnectionTab tabPage)) return; if (!(protocolBase?.InterfaceControl.Parent is ConnectionTab tabPage)) return;
if (tabPage.Disposing) return; if (tabPage.Disposing) return;
tabPage.protocolClose = true; tabPage.ProtocolClose = true;
Invoke(new Action(() => tabPage.Close())); Invoke(new Action(() => tabPage.Close()));
} }

View File

@@ -1,9 +1,10 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using BrightIdeasSoftware; using BrightIdeasSoftware;
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.Config.Settings; using mRemoteNG.Config.Settings;
using mRemoteNG.Connection;
using mRemoteNG.Tools; using mRemoteNG.Tools;
using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.Docking;
using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms;
@@ -14,12 +15,15 @@ namespace mRemoteNG.UI.Window
{ {
public partial class ExternalToolsWindow public partial class ExternalToolsWindow
{ {
private readonly IConnectionInitiator _connectionInitiator;
private readonly ExternalAppsSaver _externalAppsSaver; private readonly ExternalAppsSaver _externalAppsSaver;
private readonly ThemeManager _themeManager; private readonly ThemeManager _themeManager;
private readonly FullyObservableCollection<ExternalTool> _currentlySelectedExternalTools; private readonly FullyObservableCollection<ExternalTool> _currentlySelectedExternalTools;
public ExternalToolsWindow()
public ExternalToolsWindow(IConnectionInitiator connectionInitiator)
{ {
_connectionInitiator = connectionInitiator;
InitializeComponent(); InitializeComponent();
WindowType = WindowType.ExternalApps; WindowType = WindowType.ExternalApps;
DockPnl = new DockContent(); DockPnl = new DockContent();
@@ -177,7 +181,10 @@ namespace mRemoteNG.UI.Window
{ {
try try
{ {
var externalTool = new ExternalTool(Language.strExternalToolDefaultName); var externalTool = new ExternalTool(_connectionInitiator)
{
DisplayName = Language.strExternalToolDefaultName
};
Runtime.ExternalToolsService.ExternalTools.Add(externalTool); Runtime.ExternalToolsService.ExternalTools.Add(externalTool);
UpdateToolsListObjView(); UpdateToolsListObjView();
ToolsListObjView.SelectedObject = externalTool; ToolsListObjView.SelectedObject = externalTool;

View File

@@ -96,6 +96,9 @@
<Reference Include="System.Windows.Forms" /> <Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="Utf8Json">
<HintPath>..\packages\Utf8Json.1.3.7\lib\net45\Utf8Json.dll</HintPath>
</Reference>
<Reference Include="VncSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=61974755c7bfea7c, processorArchitecture=MSIL"> <Reference Include="VncSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=61974755c7bfea7c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>References\VncSharp.dll</HintPath> <HintPath>References\VncSharp.dll</HintPath>
@@ -249,13 +252,16 @@
<Compile Include="App\ProgramRoot.cs" /> <Compile Include="App\ProgramRoot.cs" />
<Compile Include="Connection\ConnectionInitiator.cs" /> <Compile Include="Connection\ConnectionInitiator.cs" />
<Compile Include="Connection\ConnectionsService.cs" /> <Compile Include="Connection\ConnectionsService.cs" />
<Compile Include="Connection\ConnectionStartingEvent.cs" />
<Compile Include="Connection\Converter.cs" /> <Compile Include="Connection\Converter.cs" />
<Compile Include="Connection\DefaultConnectionInfo.cs" /> <Compile Include="Connection\DefaultConnectionInfo.cs" />
<Compile Include="Connection\DefaultConnectionInheritance.cs" /> <Compile Include="Connection\DefaultConnectionInheritance.cs" />
<Compile Include="Connection\IConnectionInitiator.cs" /> <Compile Include="Connection\IConnectionInitiator.cs" />
<Compile Include="Connection\IInheritable.cs" /> <Compile Include="Connection\IInheritable.cs" />
<Compile Include="Connection\IHasParent.cs" /> <Compile Include="Connection\IHasParent.cs" />
<Compile Include="Connection\Protocol\ExternalProcessProtocolBase.cs" />
<Compile Include="Connection\Protocol\Http\Connection.Protocol.HTTPS.CertEvent.cs" /> <Compile Include="Connection\Protocol\Http\Connection.Protocol.HTTPS.CertEvent.cs" />
<Compile Include="Connection\Protocol\IFocusable.cs" />
<Compile Include="Connection\Protocol\ProtocolFactory.cs" /> <Compile Include="Connection\Protocol\ProtocolFactory.cs" />
<Compile Include="Connection\Protocol\RDP\AuthenticationLevel.cs" /> <Compile Include="Connection\Protocol\RDP\AuthenticationLevel.cs" />
<Compile Include="Connection\Protocol\RDP\AzureLoadBalanceInfoEncoder.cs" /> <Compile Include="Connection\Protocol\RDP\AzureLoadBalanceInfoEncoder.cs" />
@@ -276,7 +282,6 @@
<Compile Include="Connection\Protocol\RDP\RDPSounds.cs" /> <Compile Include="Connection\Protocol\RDP\RDPSounds.cs" />
<Compile Include="Connection\Protocol\RDP\RdpVersion.cs" /> <Compile Include="Connection\Protocol\RDP\RdpVersion.cs" />
<Compile Include="Connection\Protocol\VNC\VNCEnum.cs" /> <Compile Include="Connection\Protocol\VNC\VNCEnum.cs" />
<Compile Include="Connection\WebHelper.cs" />
<Compile Include="Credential\PlaceholderCredentialRecord.cs" /> <Compile Include="Credential\PlaceholderCredentialRecord.cs" />
<Compile Include="Credential\Repositories\CompositeRepositoryUnlocker.cs" /> <Compile Include="Credential\Repositories\CompositeRepositoryUnlocker.cs" />
<Compile Include="Credential\CredentialChangedEventArgs.cs" /> <Compile Include="Credential\CredentialChangedEventArgs.cs" />
@@ -535,6 +540,7 @@
</Compile> </Compile>
<Compile Include="UI\DialogFactory.cs" /> <Compile Include="UI\DialogFactory.cs" />
<Compile Include="UI\DisplayProperties.cs" /> <Compile Include="UI\DisplayProperties.cs" />
<Compile Include="UI\FocusHelpers\ExternalProcessFocusHelper.cs" />
<Compile Include="UI\FontOverrider.cs" /> <Compile Include="UI\FontOverrider.cs" />
<Compile Include="UI\FormExtensions.cs" /> <Compile Include="UI\FormExtensions.cs" />
<Compile Include="UI\Forms\FrmOptions.cs"> <Compile Include="UI\Forms\FrmOptions.cs">
@@ -733,6 +739,7 @@
<SubType>Component</SubType> <SubType>Component</SubType>
</Compile> </Compile>
<Compile Include="UI\Panels\PanelAdder.cs" /> <Compile Include="UI\Panels\PanelAdder.cs" />
<Compile Include="UI\SystemKeyboardHook.cs" />
<Compile Include="UI\Tabs\Enums.cs" /> <Compile Include="UI\Tabs\Enums.cs" />
<Compile Include="UI\Tabs\ConnectionTab.cs"> <Compile Include="UI\Tabs\ConnectionTab.cs">
<SubType>Form</SubType> <SubType>Form</SubType>