SEBWIN-531, #240: Refactored browser application instance to browser window.

This commit is contained in:
Damian Büchel 2022-02-04 13:41:11 +01:00
parent fa3763a32a
commit 83c387cffd
4 changed files with 70 additions and 65 deletions

View file

@ -37,12 +37,11 @@ namespace SafeExamBrowser.Browser
{ {
public class BrowserApplication : IBrowserApplication public class BrowserApplication : IBrowserApplication
{ {
private int instanceIdCounter = default(int); private int windowIdCounter = default;
private readonly AppConfig appConfig; private readonly AppConfig appConfig;
private readonly IFileSystemDialog fileSystemDialog; private readonly IFileSystemDialog fileSystemDialog;
private readonly IHashAlgorithm hashAlgorithm; private readonly IHashAlgorithm hashAlgorithm;
private readonly List<BrowserApplicationInstance> instances;
private readonly IKeyGenerator keyGenerator; private readonly IKeyGenerator keyGenerator;
private readonly IModuleLogger logger; private readonly IModuleLogger logger;
private readonly IMessageBox messageBox; private readonly IMessageBox messageBox;
@ -50,6 +49,7 @@ namespace SafeExamBrowser.Browser
private readonly BrowserSettings settings; private readonly BrowserSettings settings;
private readonly IText text; private readonly IText text;
private readonly IUserInterfaceFactory uiFactory; private readonly IUserInterfaceFactory uiFactory;
private readonly List<BrowserWindow> windows;
public bool AutoStart { get; private set; } public bool AutoStart { get; private set; }
public IconResource Icon { get; private set; } public IconResource Icon { get; private set; }
@ -77,7 +77,6 @@ namespace SafeExamBrowser.Browser
this.appConfig = appConfig; this.appConfig = appConfig;
this.fileSystemDialog = fileSystemDialog; this.fileSystemDialog = fileSystemDialog;
this.hashAlgorithm = hashAlgorithm; this.hashAlgorithm = hashAlgorithm;
this.instances = new List<BrowserApplicationInstance>();
this.keyGenerator = keyGenerator; this.keyGenerator = keyGenerator;
this.logger = logger; this.logger = logger;
this.messageBox = messageBox; this.messageBox = messageBox;
@ -85,11 +84,12 @@ namespace SafeExamBrowser.Browser
this.settings = settings; this.settings = settings;
this.text = text; this.text = text;
this.uiFactory = uiFactory; this.uiFactory = uiFactory;
this.windows = new List<BrowserWindow>();
} }
public IEnumerable<IApplicationWindow> GetWindows() public IEnumerable<IApplicationWindow> GetWindows()
{ {
return new List<IApplicationWindow>(instances); return new List<IApplicationWindow>(windows);
} }
public void Initialize() public void Initialize()
@ -123,7 +123,7 @@ namespace SafeExamBrowser.Browser
public void Start() public void Start()
{ {
CreateNewInstance(); CreateNewWindow();
} }
public void Terminate() public void Terminate()
@ -131,11 +131,11 @@ namespace SafeExamBrowser.Browser
logger.Info("Initiating termination..."); logger.Info("Initiating termination...");
AwaitReady(); AwaitReady();
foreach (var instance in instances) foreach (var window in windows)
{ {
instance.Terminated -= Instance_Terminated; window.Closed -= Window_Closed;
instance.Terminate(); window.Close();
logger.Info($"Terminated browser instance {instance.Id}."); logger.Info($"Closed browser window #{window.Id}.");
} }
if (settings.UseTemporaryDownAndUploadDirectory) if (settings.UseTemporaryDownAndUploadDirectory)
@ -170,37 +170,37 @@ namespace SafeExamBrowser.Browser
Thread.Sleep(500); Thread.Sleep(500);
} }
private void CreateNewInstance(string url = null) private void CreateNewWindow(string url = null)
{ {
var id = ++instanceIdCounter; var id = ++windowIdCounter;
var isMainInstance = instances.Count == 0; var isMainWindow = windows.Count == 0;
var instanceLogger = logger.CloneFor($"Browser Instance #{id}");
var startUrl = url ?? GenerateStartUrl(); var startUrl = url ?? GenerateStartUrl();
var instance = new BrowserApplicationInstance( var windowLogger = logger.CloneFor($"Browser Window #{id}");
var window = new BrowserWindow(
appConfig, appConfig,
settings, settings,
id, id,
isMainInstance, isMainWindow,
fileSystemDialog, fileSystemDialog,
hashAlgorithm, hashAlgorithm,
keyGenerator, keyGenerator,
messageBox, messageBox,
instanceLogger, windowLogger,
text, text,
uiFactory, uiFactory,
startUrl); startUrl);
instance.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args); window.Closed += Window_Closed;
instance.PopupRequested += Instance_PopupRequested; window.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args);
instance.ResetRequested += Instance_ResetRequested; window.PopupRequested += Window_PopupRequested;
instance.SessionIdentifierDetected += (i) => SessionIdentifierDetected?.Invoke(i); window.ResetRequested += Window_ResetRequested;
instance.Terminated += Instance_Terminated; window.SessionIdentifierDetected += (i) => SessionIdentifierDetected?.Invoke(i);
instance.TerminationRequested += () => TerminationRequested?.Invoke(); window.TerminationRequested += () => TerminationRequested?.Invoke();
instance.Initialize(); window.Initialize();
instances.Add(instance); windows.Add(window);
logger.Info($"Created browser instance {instance.Id}."); logger.Info($"Created browser window #{window.Id}.");
WindowsChanged?.Invoke(); WindowsChanged?.Invoke();
} }
@ -412,25 +412,32 @@ namespace SafeExamBrowser.Browser
throw new NotImplementedException($"Mapping for proxy protocol '{protocol}' is not yet implemented!"); throw new NotImplementedException($"Mapping for proxy protocol '{protocol}' is not yet implemented!");
} }
private void Instance_PopupRequested(PopupRequestedEventArgs args) private void Window_Closed(int id)
{ {
logger.Info($"Received request to create new instance{(settings.AdditionalWindow.UrlPolicy.CanLog() ? $" for '{args.Url}'" : "")}..."); windows.Remove(windows.First(i => i.Id == id));
CreateNewInstance(args.Url); WindowsChanged?.Invoke();
logger.Info($"Window #{id} has been closed.");
} }
private void Instance_ResetRequested() private void Window_PopupRequested(PopupRequestedEventArgs args)
{
logger.Info($"Received request to create new window{(settings.AdditionalWindow.UrlPolicy.CanLog() ? $" for '{args.Url}'" : "")}...");
CreateNewWindow(args.Url);
}
private void Window_ResetRequested()
{ {
logger.Info("Attempting to reset browser..."); logger.Info("Attempting to reset browser...");
AwaitReady(); AwaitReady();
foreach (var instance in instances) foreach (var window in windows)
{ {
instance.Terminated -= Instance_Terminated; window.Closed -= Window_Closed;
instance.Terminate(); window.Close();
logger.Info($"Terminated browser instance {instance.Id}."); logger.Info($"Closed browser window #{window.Id}.");
} }
instances.Clear(); windows.Clear();
WindowsChanged?.Invoke(); WindowsChanged?.Invoke();
if (settings.DeleteCookiesOnStartup && settings.DeleteCookiesOnShutdown) if (settings.DeleteCookiesOnStartup && settings.DeleteCookiesOnShutdown)
@ -439,14 +446,8 @@ namespace SafeExamBrowser.Browser
} }
nativeMethods.EmptyClipboard(); nativeMethods.EmptyClipboard();
CreateNewInstance(); CreateNewWindow();
logger.Info("Successfully reset browser."); logger.Info("Successfully reset browser.");
} }
private void Instance_Terminated(int id)
{
instances.Remove(instances.First(i => i.Id == id));
WindowsChanged?.Invoke();
}
} }
} }

View file

@ -37,7 +37,7 @@ using TitleChangedEventHandler = SafeExamBrowser.Applications.Contracts.Events.T
namespace SafeExamBrowser.Browser namespace SafeExamBrowser.Browser
{ {
internal class BrowserApplicationInstance : IApplicationWindow internal class BrowserWindow : IApplicationWindow
{ {
private const double ZOOM_FACTOR = 0.2; private const double ZOOM_FACTOR = 0.2;
@ -45,22 +45,22 @@ namespace SafeExamBrowser.Browser
private readonly IFileSystemDialog fileSystemDialog; private readonly IFileSystemDialog fileSystemDialog;
private readonly IHashAlgorithm hashAlgorithm; private readonly IHashAlgorithm hashAlgorithm;
private readonly HttpClient httpClient; private readonly HttpClient httpClient;
private readonly bool isMainWindow;
private readonly IKeyGenerator keyGenerator; private readonly IKeyGenerator keyGenerator;
private readonly IModuleLogger logger; private readonly IModuleLogger logger;
private readonly IMessageBox messageBox; private readonly IMessageBox messageBox;
private readonly BrowserSettings settings;
private readonly string startUrl;
private readonly IText text; private readonly IText text;
private readonly IUserInterfaceFactory uiFactory; private readonly IUserInterfaceFactory uiFactory;
private IBrowserControl control; private IBrowserControl control;
private IBrowserWindow window; private IBrowserWindow window;
private bool isMainInstance;
private BrowserSettings settings;
private string startUrl;
private double zoomLevel; private double zoomLevel;
private WindowSettings WindowSettings private WindowSettings WindowSettings
{ {
get { return isMainInstance ? settings.MainWindow : settings.AdditionalWindow; } get { return isMainWindow ? settings.MainWindow : settings.AdditionalWindow; }
} }
internal int Id { get; } internal int Id { get; }
@ -69,21 +69,21 @@ namespace SafeExamBrowser.Browser
public IconResource Icon { get; private set; } public IconResource Icon { get; private set; }
public string Title { get; private set; } public string Title { get; private set; }
internal event WindowClosedEventHandler Closed;
internal event DownloadRequestedEventHandler ConfigurationDownloadRequested; internal event DownloadRequestedEventHandler ConfigurationDownloadRequested;
internal event PopupRequestedEventHandler PopupRequested; internal event PopupRequestedEventHandler PopupRequested;
internal event ResetRequestedEventHandler ResetRequested; internal event ResetRequestedEventHandler ResetRequested;
internal event SessionIdentifierDetectedEventHandler SessionIdentifierDetected; internal event SessionIdentifierDetectedEventHandler SessionIdentifierDetected;
internal event InstanceTerminatedEventHandler Terminated;
internal event TerminationRequestedEventHandler TerminationRequested; internal event TerminationRequestedEventHandler TerminationRequested;
public event IconChangedEventHandler IconChanged; public event IconChangedEventHandler IconChanged;
public event TitleChangedEventHandler TitleChanged; public event TitleChangedEventHandler TitleChanged;
public BrowserApplicationInstance( public BrowserWindow(
AppConfig appConfig, AppConfig appConfig,
BrowserSettings settings, BrowserSettings settings,
int id, int id,
bool isMainInstance, bool isMainWindow,
IFileSystemDialog fileSystemDialog, IFileSystemDialog fileSystemDialog,
IHashAlgorithm hashAlgorithm, IHashAlgorithm hashAlgorithm,
IKeyGenerator keyGenerator, IKeyGenerator keyGenerator,
@ -96,7 +96,7 @@ namespace SafeExamBrowser.Browser
this.appConfig = appConfig; this.appConfig = appConfig;
this.Id = id; this.Id = id;
this.httpClient = new HttpClient(); this.httpClient = new HttpClient();
this.isMainInstance = isMainInstance; this.isMainWindow = isMainWindow;
this.fileSystemDialog = fileSystemDialog; this.fileSystemDialog = fileSystemDialog;
this.hashAlgorithm = hashAlgorithm; this.hashAlgorithm = hashAlgorithm;
this.keyGenerator = keyGenerator; this.keyGenerator = keyGenerator;
@ -113,18 +113,18 @@ namespace SafeExamBrowser.Browser
window.BringToForeground(); window.BringToForeground();
} }
internal void Close()
{
window.Close();
control.Destroy();
}
internal void Initialize() internal void Initialize()
{ {
InitializeControl(); InitializeControl();
InitializeWindow(); InitializeWindow();
} }
internal void Terminate()
{
window.Close();
control.Destroy();
}
private void InitializeControl() private void InitializeControl()
{ {
var contextMenuHandler = new ContextMenuHandler(); var contextMenuHandler = new ContextMenuHandler();
@ -210,10 +210,10 @@ namespace SafeExamBrowser.Browser
private void InitializeWindow() private void InitializeWindow()
{ {
window = uiFactory.CreateBrowserWindow(control, settings, isMainInstance); window = uiFactory.CreateBrowserWindow(control, settings, isMainWindow);
window.Closing += Window_Closing;
window.AddressChanged += Window_AddressChanged; window.AddressChanged += Window_AddressChanged;
window.BackwardNavigationRequested += Window_BackwardNavigationRequested; window.BackwardNavigationRequested += Window_BackwardNavigationRequested;
window.Closing += Window_Closing;
window.DeveloperConsoleRequested += Window_DeveloperConsoleRequested; window.DeveloperConsoleRequested += Window_DeveloperConsoleRequested;
window.FindRequested += Window_FindRequested; window.FindRequested += Window_FindRequested;
window.ForwardNavigationRequested += Window_ForwardNavigationRequested; window.ForwardNavigationRequested += Window_ForwardNavigationRequested;
@ -297,9 +297,13 @@ namespace SafeExamBrowser.Browser
{ {
initialPath = args.InitialPath; initialPath = args.InitialPath;
} }
else if (string.IsNullOrEmpty(settings.DownAndUploadDirectory))
{
initialPath = KnownFolders.Downloads.ExpandedPath;
}
else else
{ {
initialPath = string.IsNullOrEmpty(settings.DownAndUploadDirectory) ? KnownFolders.Downloads.ExpandedPath : Environment.ExpandEnvironmentVariables(settings.DownAndUploadDirectory); initialPath = Environment.ExpandEnvironmentVariables(settings.DownAndUploadDirectory);
} }
if (isAllowed) if (isAllowed)
@ -382,7 +386,7 @@ namespace SafeExamBrowser.Browser
private void HomeNavigationRequested() private void HomeNavigationRequested()
{ {
if (isMainInstance && (settings.UseStartUrlAsHomeUrl || !string.IsNullOrWhiteSpace(settings.HomeUrl))) if (isMainWindow && (settings.UseStartUrlAsHomeUrl || !string.IsNullOrWhiteSpace(settings.HomeUrl)))
{ {
var navigate = false; var navigate = false;
var url = settings.UseStartUrlAsHomeUrl ? settings.StartUrl : settings.HomeUrl; var url = settings.UseStartUrlAsHomeUrl ? settings.StartUrl : settings.HomeUrl;
@ -568,9 +572,9 @@ namespace SafeExamBrowser.Browser
private void Window_Closing() private void Window_Closing()
{ {
logger.Info($"Instance has terminated."); logger.Info($"Window is closing...");
control.Destroy(); control.Destroy();
Terminated?.Invoke(Id); Closed?.Invoke(Id);
} }
private void Window_DeveloperConsoleRequested() private void Window_DeveloperConsoleRequested()

View file

@ -8,5 +8,5 @@
namespace SafeExamBrowser.Browser.Events namespace SafeExamBrowser.Browser.Events
{ {
internal delegate void InstanceTerminatedEventHandler(int id); internal delegate void WindowClosedEventHandler(int id);
} }

View file

@ -79,12 +79,12 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="BrowserApplication.cs" /> <Compile Include="BrowserApplication.cs" />
<Compile Include="BrowserApplicationInstance.cs" /> <Compile Include="BrowserWindow.cs" />
<Compile Include="Events\DialogRequestedEventArgs.cs" /> <Compile Include="Events\DialogRequestedEventArgs.cs" />
<Compile Include="Events\DialogRequestedEventHandler.cs" /> <Compile Include="Events\DialogRequestedEventHandler.cs" />
<Compile Include="Events\DownloadUpdatedEventHandler.cs" /> <Compile Include="Events\DownloadUpdatedEventHandler.cs" />
<Compile Include="Events\FaviconChangedEventHandler.cs" /> <Compile Include="Events\FaviconChangedEventHandler.cs" />
<Compile Include="Events\InstanceTerminatedEventHandler.cs" /> <Compile Include="Events\WindowClosedEventHandler.cs" />
<Compile Include="Events\PopupRequestedEventArgs.cs" /> <Compile Include="Events\PopupRequestedEventArgs.cs" />
<Compile Include="Events\PopupRequestedEventHandler.cs" /> <Compile Include="Events\PopupRequestedEventHandler.cs" />
<Compile Include="Events\ProgressChangedEventHandler.cs" /> <Compile Include="Events\ProgressChangedEventHandler.cs" />