SEBWIN-531, #240: Replaced custom life span handler implementation with new API of the browser engine in order to enable parent-child relationship / JavaScript functionality for popup windows.

This commit is contained in:
Damian Büchel 2022-02-23 13:59:36 +01:00
parent 83c387cffd
commit 71423803e5
65 changed files with 1433 additions and 464 deletions

View file

@ -5,10 +5,130 @@ root = true
[*]
end_of_line = crlf
dotnet_style_operator_placement_when_wrapping = beginning_of_line
tab_width = 4
indent_size = 4
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_object_initializer = false:none
dotnet_style_collection_initializer = true:suggestion
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_compound_assignment = true:suggestion
dotnet_style_prefer_simplified_interpolation = true:suggestion
dotnet_style_namespace_match_folder = true:suggestion
[*.cs]
dotnet_style_object_initializer = false:none
indent_style = tab
csharp_indent_labels = one_less_than_current
csharp_using_directive_placement = outside_namespace:silent
csharp_prefer_simple_using_statement = true:suggestion
csharp_prefer_braces = true:silent
csharp_style_namespace_declarations = block_scoped:silent
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
csharp_style_throw_expression = true:suggestion
csharp_style_prefer_null_check_over_type_check = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_prefer_local_over_anonymous_function = true:suggestion
csharp_style_prefer_index_operator = true:suggestion
csharp_style_prefer_range_operator = true:suggestion
csharp_style_prefer_tuple_swap = true:suggestion
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
csharp_style_unused_value_assignment_preference = discard_variable:silent
csharp_prefer_static_local_function = true:suggestion
csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
csharp_style_conditional_delegate_call = true:suggestion
csharp_style_prefer_switch_expression = true:suggestion
csharp_style_prefer_pattern_matching = true:silent
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_prefer_not_pattern = true:suggestion
csharp_style_prefer_extended_property_pattern = true:suggestion
csharp_style_var_for_built_in_types = false:silent
csharp_style_var_when_type_is_apparent = false:silent
csharp_style_var_elsewhere = false:silent
csharp_space_after_cast = true
[*.xml]
indent_style = space
indent_style = space
[*.{cs,vb}]
#### Naming styles ####
# Naming rules
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
# Symbol specifications
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
# Naming styles
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_style_readonly_field = true:suggestion
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
dotnet_style_allow_multiple_blank_lines_experimental = true:silent
dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
dotnet_code_quality_unused_parameters = all:suggestion
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent

View file

@ -31,7 +31,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
[TestMethod]
public void MustCorrectlyCancelDialog()
{
RequestDialog(default(CefFileDialogMode), false);
RequestDialog(default, false);
}
[TestMethod]
@ -80,7 +80,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
threadId = Thread.CurrentThread.ManagedThreadId;
};
var status = sut.OnFileDialog(default(IWebBrowser), default(IBrowser), mode, default(CefFileDialogFlags), title, initialPath, default(List<string>), default(int), callback.Object);
var status = sut.OnFileDialog(default, default, mode, default, title, initialPath, default, default, callback.Object);
sync.WaitOne();

View file

@ -6,11 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using System.Collections.Generic;
using CefSharp;
using CefSharp.Enums;
using CefSharp.Structs;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SafeExamBrowser.Browser.Handlers;
@ -32,10 +28,10 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
{
var text = default(string);
Assert.IsFalse(sut.OnAutoResize(default(IWebBrowser), default(IBrowser), default(Size)));
Assert.IsFalse(sut.OnConsoleMessage(default(IWebBrowser), default(ConsoleMessageEventArgs)));
Assert.IsFalse(sut.OnCursorChange(default(IWebBrowser), default(IBrowser), default(IntPtr), default(CursorType), default(CursorInfo)));
Assert.IsFalse(sut.OnTooltipChanged(default(IWebBrowser), ref text));
Assert.IsFalse(sut.OnAutoResize(default, default, default));
Assert.IsFalse(sut.OnConsoleMessage(default, default));
Assert.IsFalse(sut.OnCursorChange(default, default, default, default, default));
Assert.IsFalse(sut.OnTooltipChanged(default, ref text));
}
[TestMethod]
@ -50,12 +46,12 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
called = true;
url = u;
};
sut.OnFaviconUrlChange(default(IWebBrowser), default(IBrowser), new List<string>());
sut.OnFaviconUrlChange(default, default, new List<string>());
Assert.AreEqual(default(string), url);
Assert.AreEqual(default, url);
Assert.IsFalse(called);
sut.OnFaviconUrlChange(default(IWebBrowser), default(IBrowser), new List<string> { newUrl });
sut.OnFaviconUrlChange(default, default, new List<string> { newUrl });
Assert.AreEqual(newUrl, url);
Assert.IsTrue(called);
@ -68,7 +64,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
var actual = default(double);
sut.ProgressChanged += (p) => actual = p;
sut.OnLoadingProgressChange(default(IWebBrowser), default(IBrowser), expected);
sut.OnLoadingProgressChange(default, default, expected);
Assert.AreEqual(expected, actual);
}

View file

@ -1,49 +0,0 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SafeExamBrowser.Browser.Events;
using SafeExamBrowser.Browser.Handlers;
namespace SafeExamBrowser.Browser.UnitTests.Handlers
{
[TestClass]
public class LifeSpanHandlerTests
{
private LifeSpanHandler sut;
[TestInitialize]
public void Initialize()
{
sut = new LifeSpanHandler();
}
[TestMethod]
public void MustUseDefaultBehavior()
{
Assert.IsFalse(sut.DoClose(default(IWebBrowser), default(IBrowser)));
}
[TestMethod]
public void MustHandlePopup()
{
var args = default(PopupRequestedEventArgs);
var jsAccess = false;
var url = "https://www.host.org/some-url";
sut.PopupRequested += (a) => args = a;
var result = sut.OnBeforePopup(default(IWebBrowser), default(IBrowser), default(IFrame), url, default(string), default(WindowOpenDisposition), default(bool), default(IPopupFeatures), default(IWindowInfo), default(IBrowserSettings), ref jsAccess, out var newBrowser);
Assert.IsTrue(result);
Assert.AreEqual(default(IWebBrowser), newBrowser);
Assert.AreEqual(url, args.Url);
}
}
}

View file

@ -50,16 +50,16 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
text = new Mock<IText>();
resourceHandler = new ResourceHandler(appConfig, filter.Object, keyGenerator.Object, logger.Object, settings, windowSettings, text.Object);
sut = new TestableRequestHandler(appConfig, filter.Object, logger.Object, resourceHandler, settings, windowSettings, text.Object);
sut = new TestableRequestHandler(appConfig, filter.Object, logger.Object, resourceHandler, settings, windowSettings);
}
[TestMethod]
public void MustBlockSpecialWindowDispositions()
{
Assert.IsTrue(sut.OnOpenUrlFromTab(default(IWebBrowser), default(IBrowser), default(IFrame), default(string), WindowOpenDisposition.NewBackgroundTab, default(bool)));
Assert.IsTrue(sut.OnOpenUrlFromTab(default(IWebBrowser), default(IBrowser), default(IFrame), default(string), WindowOpenDisposition.NewPopup, default(bool)));
Assert.IsTrue(sut.OnOpenUrlFromTab(default(IWebBrowser), default(IBrowser), default(IFrame), default(string), WindowOpenDisposition.NewWindow, default(bool)));
Assert.IsTrue(sut.OnOpenUrlFromTab(default(IWebBrowser), default(IBrowser), default(IFrame), default(string), WindowOpenDisposition.SaveToDisk, default(bool)));
Assert.IsTrue(sut.OnOpenUrlFromTab(default, default, default, default, WindowOpenDisposition.NewBackgroundTab, default));
Assert.IsTrue(sut.OnOpenUrlFromTab(default, default, default, default, WindowOpenDisposition.NewPopup, default));
Assert.IsTrue(sut.OnOpenUrlFromTab(default, default, default, default, WindowOpenDisposition.NewWindow, default));
Assert.IsTrue(sut.OnOpenUrlFromTab(default, default, default, default, WindowOpenDisposition.SaveToDisk, default));
}
[TestMethod]
@ -214,7 +214,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
public void MustReturnResourceHandler()
{
var disableDefaultHandling = default(bool);
var handler = sut.GetResourceRequestHandler(default(IWebBrowser), default(IBrowser), default(IFrame), default(IRequest), default(bool), default(bool), default(string), ref disableDefaultHandling);
var handler = sut.GetResourceRequestHandler(default, default, default, default, default, default, default, ref disableDefaultHandling);
Assert.AreSame(resourceHandler, handler);
}
@ -229,7 +229,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
settings.Proxy.Proxies.Add(proxy1);
settings.Proxy.Proxies.Add(proxy2);
var result = sut.GetAuthCredentials(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), default(string), true, "WWW.tEst.Com", 10, default(string), default(string), callback.Object);
var result = sut.GetAuthCredentials(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), default, true, "WWW.tEst.Com", 10, default, default, callback.Object);
callback.Verify(c => c.Cancel(), Times.Never);
callback.Verify(c => c.Continue(It.Is<string>(u => u.Equals(proxy1.Username)), It.Is<string>(p => p.Equals(proxy1.Password))), Times.Once);
@ -243,7 +243,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
{
var callback = new Mock<IAuthCallback>();
sut.GetAuthCredentials(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), default(string), false, default(string), default(int), default(string), default(string), callback.Object);
sut.GetAuthCredentials(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), default, false, default, default, default, default, callback.Object);
callback.Verify(c => c.Cancel(), Times.Never);
callback.Verify(c => c.Continue(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
@ -251,14 +251,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
private class TestableRequestHandler : RequestHandler
{
internal TestableRequestHandler(
AppConfig appConfig,
IRequestFilter filter,
ILogger logger,
ResourceHandler resourceHandler,
BrowserSettings settings,
WindowSettings windowSettings,
IText text) : base(appConfig, filter, logger, resourceHandler, settings, windowSettings, text)
internal TestableRequestHandler(AppConfig appConfig, IRequestFilter filter, ILogger logger, ResourceHandler resourceHandler, BrowserSettings settings, WindowSettings windowSettings) : base(appConfig, filter, logger, resourceHandler, settings, windowSettings)
{
}

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props')" />
<Import Project="..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props" Condition="Exists('..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props')" />
<Import Project="..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props" Condition="Exists('..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props')" />
<Import Project="..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props')" />
<Import Project="..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props" Condition="Exists('..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props')" />
<Import Project="..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props" Condition="Exists('..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props')" />
<Import Project="..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
@ -64,11 +64,11 @@
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\packages\Castle.Core.4.4.1\lib\net45\Castle.Core.dll</HintPath>
</Reference>
<Reference Include="CefSharp, Version=97.1.11.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.Common.97.1.11\lib\net452\CefSharp.dll</HintPath>
<Reference Include="CefSharp, Version=98.1.210.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.Common.98.1.210\lib\net452\CefSharp.dll</HintPath>
</Reference>
<Reference Include="CefSharp.Core, Version=97.1.11.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.Common.97.1.11\lib\net452\CefSharp.Core.dll</HintPath>
<Reference Include="CefSharp.Core, Version=98.1.210.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.Common.98.1.210\lib\net452\CefSharp.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.2.8\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
@ -101,7 +101,6 @@
<Compile Include="Handlers\DisplayHandlerTests.cs" />
<Compile Include="Handlers\DownloadHandlerTests.cs" />
<Compile Include="Handlers\KeyboardHandlerTests.cs" />
<Compile Include="Handlers\LifeSpanHandlerTests.cs" />
<Compile Include="Handlers\RequestHandlerTests.cs" />
<Compile Include="Handlers\ResourceHandlerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@ -152,11 +151,11 @@
</PropertyGroup>
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.props'))" />
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.targets'))" />
<Error Condition="!Exists('..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props'))" />
<Error Condition="!Exists('..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets'))" />
<Error Condition="!Exists('..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props'))" />
<Error Condition="!Exists('..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets'))" />
</Target>
<Import Project="..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.targets')" />
<Import Project="..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets')" />
<Import Project="..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets')" />
</Project>

View file

@ -16,11 +16,11 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="CefSharp" publicKeyToken="40c4b6fc221f4138" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-97.1.11.0" newVersion="97.1.11.0" />
<bindingRedirect oldVersion="0.0.0.0-98.1.210.0" newVersion="98.1.210.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="CefSharp.Core" publicKeyToken="40c4b6fc221f4138" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-97.1.11.0" newVersion="97.1.11.0" />
<bindingRedirect oldVersion="0.0.0.0-98.1.210.0" newVersion="98.1.210.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Castle.Core" version="4.4.1" targetFramework="net472" />
<package id="cef.redist.x64" version="97.1.1" targetFramework="net472" />
<package id="cef.redist.x86" version="97.1.1" targetFramework="net472" />
<package id="CefSharp.Common" version="97.1.11" targetFramework="net472" />
<package id="cef.redist.x64" version="98.1.21" targetFramework="net472" />
<package id="cef.redist.x86" version="98.1.21" targetFramework="net472" />
<package id="CefSharp.Common" version="98.1.210" targetFramework="net472" />
<package id="Moq" version="4.16.1" targetFramework="net472" />
<package id="MSTest.TestAdapter" version="2.2.8" targetFramework="net472" />
<package id="MSTest.TestFramework" version="2.2.8" targetFramework="net472" />

View file

@ -24,7 +24,6 @@ using SafeExamBrowser.Configuration.Contracts.Cryptography;
using SafeExamBrowser.Core.Contracts.Resources.Icons;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Settings.Browser;
using SafeExamBrowser.Settings.Browser.Proxy;
using SafeExamBrowser.Settings.Logging;
using SafeExamBrowser.UserInterface.Contracts;
@ -170,36 +169,45 @@ namespace SafeExamBrowser.Browser
Thread.Sleep(500);
}
private void CreateNewWindow(string url = null)
private void CreateNewWindow(PopupRequestedEventArgs args = default)
{
var id = ++windowIdCounter;
var isMainWindow = windows.Count == 0;
var startUrl = url ?? GenerateStartUrl();
var startUrl = GenerateStartUrl();
var windowLogger = logger.CloneFor($"Browser Window #{id}");
var window = new BrowserWindow(
appConfig,
settings,
id,
isMainWindow,
fileSystemDialog,
hashAlgorithm,
id,
isMainWindow,
keyGenerator,
messageBox,
windowLogger,
messageBox,
settings,
startUrl,
text,
uiFactory,
startUrl);
uiFactory);
window.Closed += Window_Closed;
window.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args);
window.ConfigurationDownloadRequested += (f, a) => ConfigurationDownloadRequested?.Invoke(f, a);
window.PopupRequested += Window_PopupRequested;
window.ResetRequested += Window_ResetRequested;
window.SessionIdentifierDetected += (i) => SessionIdentifierDetected?.Invoke(i);
window.TerminationRequested += () => TerminationRequested?.Invoke();
window.Initialize();
window.InitializeControl();
windows.Add(window);
if (args != default(PopupRequestedEventArgs))
{
args.Window = window;
}
else
{
window.InitializeWindow();
}
logger.Info($"Created browser window #{window.Id}.");
WindowsChanged?.Invoke();
}
@ -421,8 +429,8 @@ namespace SafeExamBrowser.Browser
private void Window_PopupRequested(PopupRequestedEventArgs args)
{
logger.Info($"Received request to create new window{(settings.AdditionalWindow.UrlPolicy.CanLog() ? $" for '{args.Url}'" : "")}...");
CreateNewWindow(args.Url);
logger.Info($"Received request to create new window...");
CreateNewWindow(args);
}
private void Window_ResetRequested()

View file

@ -8,8 +8,9 @@
using System;
using CefSharp;
using CefSharp.WinForms;
using SafeExamBrowser.Browser.Content;
using SafeExamBrowser.Browser.Wrapper;
using SafeExamBrowser.Browser.Wrapper.Events;
using SafeExamBrowser.Configuration.Contracts;
using SafeExamBrowser.Configuration.Contracts.Cryptography;
using SafeExamBrowser.I18n.Contracts;
@ -18,105 +19,80 @@ using SafeExamBrowser.UserInterface.Contracts.Browser.Events;
namespace SafeExamBrowser.Browser
{
internal class BrowserControl : ChromiumWebBrowser, IBrowserControl
internal class BrowserControl : IBrowserControl
{
private readonly AppConfig appConfig;
private readonly ContentLoader contentLoader;
private readonly IContextMenuHandler contextMenuHandler;
private readonly ICefSharpControl control;
private readonly IDialogHandler dialogHandler;
private readonly IDisplayHandler displayHandler;
private readonly IDownloadHandler downloadHandler;
private readonly IKeyGenerator generator;
private readonly IKeyboardHandler keyboardHandler;
private readonly ILifeSpanHandler lifeSpanHandler;
private readonly IKeyGenerator generator;
private readonly IRequestHandler requestHandler;
private readonly IText text;
private AddressChangedEventHandler addressChanged;
private LoadFailedEventHandler loadFailed;
private LoadingStateChangedEventHandler loadingStateChanged;
private TitleChangedEventHandler titleChanged;
public string Address => control.Address;
public bool CanNavigateBackwards => control.BrowserCore.CanGoBack;
public bool CanNavigateForwards => control.BrowserCore.CanGoForward;
public object EmbeddableControl => control;
public bool CanNavigateBackwards => GetBrowser().CanGoBack;
public bool CanNavigateForwards => GetBrowser().CanGoForward;
event AddressChangedEventHandler IBrowserControl.AddressChanged
{
add { addressChanged += value; }
remove { addressChanged -= value; }
}
event LoadFailedEventHandler IBrowserControl.LoadFailed
{
add { loadFailed += value; }
remove { loadFailed -= value; }
}
event LoadingStateChangedEventHandler IBrowserControl.LoadingStateChanged
{
add { loadingStateChanged += value; }
remove { loadingStateChanged -= value; }
}
event TitleChangedEventHandler IBrowserControl.TitleChanged
{
add { titleChanged += value; }
remove { titleChanged -= value; }
}
public event AddressChangedEventHandler AddressChanged;
public event LoadFailedEventHandler LoadFailed;
public event LoadingStateChangedEventHandler LoadingStateChanged;
public event TitleChangedEventHandler TitleChanged;
public BrowserControl(
AppConfig appConfig,
IContextMenuHandler contextMenuHandler,
ICefSharpControl control,
IDialogHandler dialogHandler,
IDisplayHandler displayHandler,
IDownloadHandler downloadHandler,
IKeyGenerator generator,
IKeyboardHandler keyboardHandler,
ILifeSpanHandler lifeSpanHandler,
IKeyGenerator generator,
IRequestHandler requestHandler,
IText text,
string url) : base(url)
IText text)
{
this.appConfig = appConfig;
this.contentLoader = new ContentLoader(text);
this.contextMenuHandler = contextMenuHandler;
this.control = control;
this.dialogHandler = dialogHandler;
this.displayHandler = displayHandler;
this.downloadHandler = downloadHandler;
this.generator = generator;
this.keyboardHandler = keyboardHandler;
this.lifeSpanHandler = lifeSpanHandler;
this.generator = generator;
this.requestHandler = requestHandler;
this.text = text;
}
public void Destroy()
{
if (!IsDisposed)
if (!control.IsDisposed)
{
Dispose(true);
control.Dispose(true);
}
}
public void Initialize()
{
AddressChanged += (o, args) => addressChanged?.Invoke(args.Address);
FrameLoadStart += BrowserControl_FrameLoadStart;
IsBrowserInitializedChanged += BrowserControl_IsBrowserInitializedChanged;
LoadError += BrowserControl_LoadError;
LoadingStateChanged += (o, args) => loadingStateChanged?.Invoke(args.IsLoading);
TitleChanged += (o, args) => titleChanged?.Invoke(args.Title);
DialogHandler = dialogHandler;
DisplayHandler = displayHandler;
DownloadHandler = downloadHandler;
KeyboardHandler = keyboardHandler;
LifeSpanHandler = lifeSpanHandler;
MenuHandler = contextMenuHandler;
RequestHandler = requestHandler;
control.AddressChanged += (o, e) => AddressChanged?.Invoke(e.Address);
control.AuthCredentialsRequired += (w, b, o, i, h, p, r, s, c, a) => a.Value = requestHandler.GetAuthCredentials(w, b, o, i, h, p, r, s, c);
control.BeforeBrowse += (w, b, f, r, u, i, a) => a.Value = requestHandler.OnBeforeBrowse(w, b, f, r, u, i);
control.BeforeDownload += (w, b, d, c) => downloadHandler.OnBeforeDownload(w, b, d, c);
control.DownloadUpdated += (w, b, d, c) => downloadHandler.OnDownloadUpdated(w, b, d, c);
control.FaviconUrlChanged += (w, b, u) => displayHandler.OnFaviconUrlChange(w, b, u);
control.FileDialogRequested += (w, b, m, f, t, d, a, s, c) => dialogHandler.OnFileDialog(w, b, m, f, t, d, a, s, c);
control.FrameLoadStart += Control_FrameLoadStart;
control.IsBrowserInitializedChanged += Control_IsBrowserInitializedChanged;
control.KeyEvent += (w, b, t, k, n, m, s) => keyboardHandler.OnKeyEvent(w, b, t, k, n, m, s);
control.LoadError += (o, e) => LoadFailed?.Invoke((int) e.ErrorCode, e.ErrorText, e.FailedUrl);
control.LoadingProgressChanged += (w, b, p) => displayHandler.OnLoadingProgressChange(w, b, p);
control.LoadingStateChanged += (o, e) => LoadingStateChanged?.Invoke(e.IsLoading);
control.OpenUrlFromTab += (w, b, f, u, t, g, a) => a.Value = requestHandler.OnOpenUrlFromTab(w, b, f, u, t, g);
control.PreKeyEvent += (IWebBrowser w, IBrowser b, KeyType t, int k, int n, CefEventFlags m, bool i, ref bool s, GenericEventArgs a) => a.Value = keyboardHandler.OnPreKeyEvent(w, b, t, k, n, m, i, ref s);
control.ResourceRequestHandlerRequired += (IWebBrowser w, IBrowser b, IFrame f, IRequest r, bool n, bool d, string i, ref bool h, ResourceRequestEventArgs a) => a.Handler = requestHandler.GetResourceRequestHandler(w, b, f, r, n, d, i, ref h);
control.TitleChanged += (o, e) => TitleChanged?.Invoke(e.Title);
}
private void BrowserControl_FrameLoadStart(object sender, FrameLoadStartEventArgs e)
private void Control_FrameLoadStart(object sender, FrameLoadStartEventArgs e)
{
var browserExamKey = generator.CalculateBrowserExamKeyHash(e.Url);
var configurationKey = generator.CalculateConfigurationKeyHash(e.Url);
@ -125,52 +101,47 @@ namespace SafeExamBrowser.Browser
e.Frame.ExecuteJavaScriptAsync(api);
}
private void Control_IsBrowserInitializedChanged(object sender, EventArgs e)
{
if (control.IsBrowserInitialized)
{
control.BrowserCore.GetHost().SetFocus(true);
}
}
public void Find(string term, bool isInitial, bool caseSensitive, bool forward = true)
{
this.Find(0, term, forward, caseSensitive, !isInitial);
control.Find(0, term, forward, caseSensitive, !isInitial);
}
public void NavigateBackwards()
{
GetBrowser().GoBack();
control.BrowserCore.GoBack();
}
public void NavigateForwards()
{
GetBrowser().GoForward();
control.BrowserCore.GoForward();
}
public void NavigateTo(string address)
{
Load(address);
control.Load(address);
}
public void ShowDeveloperConsole()
{
GetBrowser().ShowDevTools();
control.BrowserCore.ShowDevTools();
}
public void Reload()
{
GetBrowser().Reload();
control.BrowserCore.Reload();
}
public void Zoom(double level)
{
GetBrowser().SetZoomLevel(level);
}
private void BrowserControl_IsBrowserInitializedChanged(object sender, EventArgs e)
{
if (IsBrowserInitialized)
{
GetBrowser().GetHost().SetFocus(true);
}
}
private void BrowserControl_LoadError(object sender, LoadErrorEventArgs e)
{
loadFailed?.Invoke((int) e.ErrorCode, e.ErrorText, e.FailedUrl);
control.BrowserCore.SetZoomLevel(level);
}
}
}

View file

@ -7,9 +7,12 @@
*/
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using CefSharp;
using CefSharp.WinForms.Handler;
using CefSharp.WinForms.Host;
using SafeExamBrowser.Applications.Contracts;
using SafeExamBrowser.Applications.Contracts.Events;
using SafeExamBrowser.Browser.Contracts.Events;
@ -17,6 +20,7 @@ using SafeExamBrowser.Browser.Contracts.Filters;
using SafeExamBrowser.Browser.Events;
using SafeExamBrowser.Browser.Filters;
using SafeExamBrowser.Browser.Handlers;
using SafeExamBrowser.Browser.Wrapper;
using SafeExamBrowser.Configuration.Contracts;
using SafeExamBrowser.Configuration.Contracts.Cryptography;
using SafeExamBrowser.Core.Contracts.Resources.Icons;
@ -31,6 +35,7 @@ using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
using Syroot.Windows.IO;
using BrowserSettings = SafeExamBrowser.Settings.Browser.BrowserSettings;
using DisplayHandler = SafeExamBrowser.Browser.Handlers.DisplayHandler;
using Request = SafeExamBrowser.Browser.Contracts.Filters.Request;
using ResourceHandler = SafeExamBrowser.Browser.Handlers.ResourceHandler;
using TitleChangedEventHandler = SafeExamBrowser.Applications.Contracts.Events.TitleChangedEventHandler;
@ -49,12 +54,12 @@ namespace SafeExamBrowser.Browser
private readonly IKeyGenerator keyGenerator;
private readonly IModuleLogger logger;
private readonly IMessageBox messageBox;
private readonly Dictionary<int, BrowserWindow> popups;
private readonly BrowserSettings settings;
private readonly string startUrl;
private readonly IText text;
private readonly IUserInterfaceFactory uiFactory;
private IBrowserControl control;
private IBrowserWindow window;
private double zoomLevel;
@ -63,6 +68,7 @@ namespace SafeExamBrowser.Browser
get { return isMainWindow ? settings.MainWindow : settings.AdditionalWindow; }
}
internal IBrowserControl Control { get; private set; }
internal int Id { get; }
public IntPtr Handle { get; private set; }
@ -81,31 +87,32 @@ namespace SafeExamBrowser.Browser
public BrowserWindow(
AppConfig appConfig,
BrowserSettings settings,
int id,
bool isMainWindow,
IFileSystemDialog fileSystemDialog,
IHashAlgorithm hashAlgorithm,
int id,
bool isMainWindow,
IKeyGenerator keyGenerator,
IMessageBox messageBox,
IModuleLogger logger,
IMessageBox messageBox,
BrowserSettings settings,
string startUrl,
IText text,
IUserInterfaceFactory uiFactory,
string startUrl)
IUserInterfaceFactory uiFactory)
{
this.appConfig = appConfig;
this.Id = id;
this.httpClient = new HttpClient();
this.isMainWindow = isMainWindow;
this.fileSystemDialog = fileSystemDialog;
this.hashAlgorithm = hashAlgorithm;
this.httpClient = new HttpClient();
this.Id = id;
this.isMainWindow = isMainWindow;
this.keyGenerator = keyGenerator;
this.messageBox = messageBox;
this.logger = logger;
this.messageBox = messageBox;
this.popups = new Dictionary<int, BrowserWindow>();
this.settings = settings;
this.startUrl = startUrl;
this.text = text;
this.uiFactory = uiFactory;
this.startUrl = startUrl;
}
public void Activate()
@ -116,31 +123,34 @@ namespace SafeExamBrowser.Browser
internal void Close()
{
window.Close();
control.Destroy();
Control.Destroy();
}
internal void Initialize()
{
InitializeControl();
InitializeWindow();
}
private void InitializeControl()
internal void InitializeControl()
{
var cefSharpControl = default(ICefSharpControl);
var contextMenuHandler = new ContextMenuHandler();
var dialogHandler = new DialogHandler();
var displayHandler = new DisplayHandler();
var downloadLogger = logger.CloneFor($"{nameof(DownloadHandler)} #{Id}");
var downloadHandler = new DownloadHandler(appConfig, downloadLogger, settings, WindowSettings);
var keyboardHandler = new KeyboardHandler();
var lifeSpanHandler = new LifeSpanHandler();
var requestFilter = new RequestFilter();
var requestLogger = logger.CloneFor($"{nameof(RequestHandler)} #{Id}");
var resourceHandler = new ResourceHandler(appConfig, requestFilter, keyGenerator, logger, settings, WindowSettings, text);
var requestHandler = new RequestHandler(appConfig, requestFilter, requestLogger, resourceHandler, settings, WindowSettings, text);
var requestHandler = new RequestHandler(appConfig, requestFilter, requestLogger, resourceHandler, settings, WindowSettings);
Icon = new BrowserIconResource();
if (isMainWindow)
{
cefSharpControl = new CefSharpBrowserControl(CreateLifeSpanHandlerForMainWindow(), startUrl);
}
else
{
cefSharpControl = new CefSharpPopupControl();
}
dialogHandler.DialogRequested += DialogHandler_DialogRequested;
displayHandler.FaviconChanged += DisplayHandler_FaviconChanged;
displayHandler.ProgressChanged += DisplayHandler_ProgressChanged;
@ -152,34 +162,65 @@ namespace SafeExamBrowser.Browser
keyboardHandler.ZoomInRequested += ZoomInRequested;
keyboardHandler.ZoomOutRequested += ZoomOutRequested;
keyboardHandler.ZoomResetRequested += ZoomResetRequested;
lifeSpanHandler.PopupRequested += LifeSpanHandler_PopupRequested;
resourceHandler.SessionIdentifierDetected += (id) => SessionIdentifierDetected?.Invoke(id);
requestHandler.QuitUrlVisited += RequestHandler_QuitUrlVisited;
requestHandler.RequestBlocked += RequestHandler_RequestBlocked;
InitializeRequestFilter(requestFilter);
control = new BrowserControl(
Control = new BrowserControl(
appConfig,
contextMenuHandler,
cefSharpControl,
dialogHandler,
displayHandler,
downloadHandler,
keyGenerator,
keyboardHandler,
lifeSpanHandler,
keyGenerator,
requestHandler,
text,
startUrl);
control.AddressChanged += Control_AddressChanged;
control.LoadFailed += Control_LoadFailed;
control.LoadingStateChanged += Control_LoadingStateChanged;
control.TitleChanged += Control_TitleChanged;
text);
Control.AddressChanged += Control_AddressChanged;
Control.LoadFailed += Control_LoadFailed;
Control.LoadingStateChanged += Control_LoadingStateChanged;
Control.TitleChanged += Control_TitleChanged;
control.Initialize();
Control.Initialize();
logger.Debug("Initialized browser control.");
}
internal void InitializeWindow()
{
window = uiFactory.CreateBrowserWindow(Control, settings, isMainWindow);
window.AddressChanged += Window_AddressChanged;
window.BackwardNavigationRequested += Window_BackwardNavigationRequested;
window.Closed += Window_Closed;
window.Closing += Window_Closing;
window.DeveloperConsoleRequested += Window_DeveloperConsoleRequested;
window.FindRequested += Window_FindRequested;
window.ForwardNavigationRequested += Window_ForwardNavigationRequested;
window.HomeNavigationRequested += HomeNavigationRequested;
window.ReloadRequested += ReloadRequested;
window.ZoomInRequested += ZoomInRequested;
window.ZoomOutRequested += ZoomOutRequested;
window.ZoomResetRequested += ZoomResetRequested;
window.UpdateZoomLevel(CalculateZoomPercentage());
window.Show();
window.BringToForeground();
Handle = window.Handle;
logger.Debug("Initialized browser window.");
}
private ILifeSpanHandler CreateLifeSpanHandlerForMainWindow()
{
return LifeSpanHandler
.Create(() => LifeSpanHandler_CreatePopup())
.OnBeforePopupCreated((wb, b, f, u, t, d, g, s) => LifeSpanHandler_PopupRequested(u))
.OnPopupCreated((c, u) => LifeSpanHandler_PopupCreated(c))
.OnPopupDestroyed((c, b) => LifeSpanHandler_PopupDestroyed(c))
.Build();
}
private void InitializeRequestFilter(IRequestFilter requestFilter)
{
if (settings.Filter.ProcessContentRequests || settings.Filter.ProcessMainRequests)
@ -208,32 +249,9 @@ namespace SafeExamBrowser.Browser
}
}
private void InitializeWindow()
{
window = uiFactory.CreateBrowserWindow(control, settings, isMainWindow);
window.AddressChanged += Window_AddressChanged;
window.BackwardNavigationRequested += Window_BackwardNavigationRequested;
window.Closing += Window_Closing;
window.DeveloperConsoleRequested += Window_DeveloperConsoleRequested;
window.FindRequested += Window_FindRequested;
window.ForwardNavigationRequested += Window_ForwardNavigationRequested;
window.HomeNavigationRequested += HomeNavigationRequested;
window.ReloadRequested += ReloadRequested;
window.ZoomInRequested += ZoomInRequested;
window.ZoomOutRequested += ZoomOutRequested;
window.ZoomResetRequested += ZoomResetRequested;
window.UpdateZoomLevel(CalculateZoomPercentage());
window.Show();
window.BringToForeground();
Handle = window.Handle;
logger.Debug("Initialized browser window.");
}
private void Control_AddressChanged(string address)
{
logger.Debug($"Navigated{(WindowSettings.UrlPolicy.CanLog() ? $" to '{address}'" : "")}.");
logger.Info($"Navigated{(WindowSettings.UrlPolicy.CanLog() ? $" to '{address}'" : "")}.");
window.UpdateAddress(address);
if (WindowSettings.UrlPolicy == UrlPolicy.Always || WindowSettings.UrlPolicy == UrlPolicy.BeforeTitle)
@ -265,14 +283,14 @@ namespace SafeExamBrowser.Browser
logger.Warn($"Request{(WindowSettings.UrlPolicy.CanLogError() ? $" for '{url}'" : "")} failed: {errorText} ({errorCode}).");
Task.Run(() => messageBox.Show(message, title, icon: MessageBoxIcon.Error, parent: window)).ContinueWith(_ => control.NavigateBackwards());
Task.Run(() => messageBox.Show(message, title, icon: MessageBoxIcon.Error, parent: window)).ContinueWith(_ => Control.NavigateBackwards());
}
}
private void Control_LoadingStateChanged(bool isLoading)
{
window.CanNavigateBackwards = WindowSettings.AllowBackwardNavigation && control.CanNavigateBackwards;
window.CanNavigateForwards = WindowSettings.AllowForwardNavigation && control.CanNavigateForwards;
window.CanNavigateBackwards = WindowSettings.AllowBackwardNavigation && Control.CanNavigateBackwards;
window.CanNavigateForwards = WindowSettings.AllowForwardNavigation && Control.CanNavigateForwards;
window.UpdateLoadingState(isLoading);
}
@ -423,7 +441,7 @@ namespace SafeExamBrowser.Browser
if (navigate)
{
control.NavigateTo(url);
Control.NavigateTo(url);
}
}
}
@ -436,32 +454,67 @@ namespace SafeExamBrowser.Browser
}
}
private void LifeSpanHandler_PopupRequested(PopupRequestedEventArgs args)
private ChromiumHostControl LifeSpanHandler_CreatePopup()
{
var validCurrentUri = Uri.TryCreate(control.Address, UriKind.Absolute, out var currentUri);
var validNewUri = Uri.TryCreate(args.Url, UriKind.Absolute, out var newUri);
var args = new PopupRequestedEventArgs();
PopupRequested?.Invoke(args);
var control = args.Window.Control.EmbeddableControl as ChromiumHostControl;
var id = control.GetHashCode();
var window = args.Window;
popups[id] = window;
window.Closed += (_) => popups.Remove(id);
return control;
}
private void LifeSpanHandler_PopupCreated(ChromiumHostControl control)
{
var id = control.GetHashCode();
var window = popups[id];
window.InitializeWindow();
}
private void LifeSpanHandler_PopupDestroyed(ChromiumHostControl control)
{
var id = control.GetHashCode();
var window = popups[id];
window.Close();
}
private PopupCreation LifeSpanHandler_PopupRequested(string targetUrl)
{
var creation = PopupCreation.Cancel;
var validCurrentUri = Uri.TryCreate(Control.Address, UriKind.Absolute, out var currentUri);
var validNewUri = Uri.TryCreate(targetUrl, UriKind.Absolute, out var newUri);
var sameHost = validCurrentUri && validNewUri && string.Equals(currentUri.Host, newUri.Host, StringComparison.OrdinalIgnoreCase);
switch (settings.PopupPolicy)
{
case PopupPolicy.Allow:
case PopupPolicy.AllowSameHost when sameHost:
logger.Debug($"Forwarding request to open new window{(WindowSettings.UrlPolicy.CanLog() ? $" for '{args.Url}'" : "")}...");
PopupRequested?.Invoke(args);
logger.Debug($"Forwarding request to open new window{(WindowSettings.UrlPolicy.CanLog() ? $" for '{targetUrl}'" : "")}...");
creation = PopupCreation.Continue;
break;
case PopupPolicy.AllowSameWindow:
case PopupPolicy.AllowSameHostAndWindow when sameHost:
logger.Info($"Discarding request to open new window and loading{(WindowSettings.UrlPolicy.CanLog() ? $" '{args.Url}'" : "")} directly...");
control.NavigateTo(args.Url);
logger.Info($"Discarding request to open new window and loading{(WindowSettings.UrlPolicy.CanLog() ? $" '{targetUrl}'" : "")} directly...");
Control.NavigateTo(targetUrl);
break;
case PopupPolicy.AllowSameHost when !sameHost:
case PopupPolicy.AllowSameHostAndWindow when !sameHost:
logger.Info($"Blocked request to open new window{(WindowSettings.UrlPolicy.CanLog() ? $" for '{args.Url}'" : "")} as it targets a different host.");
logger.Info($"Blocked request to open new window{(WindowSettings.UrlPolicy.CanLog() ? $" for '{targetUrl}'" : "")} as it targets a different host.");
break;
default:
logger.Info($"Blocked request to open new window{(WindowSettings.UrlPolicy.CanLog() ? $" for '{args.Url}'" : "")}.");
logger.Info($"Blocked request to open new window{(WindowSettings.UrlPolicy.CanLog() ? $" for '{targetUrl}'" : "")}.");
break;
}
return creation;
}
private void RequestHandler_QuitUrlVisited(string url)
@ -508,7 +561,7 @@ namespace SafeExamBrowser.Browser
var message = text.Get(TextKey.MessageBox_BrowserNavigationBlocked).Replace("%%URL%%", WindowSettings.UrlPolicy.CanLogError() ? url : "");
var title = text.Get(TextKey.MessageBox_BrowserNavigationBlockedTitle);
control.TitleChanged -= Control_TitleChanged;
Control.TitleChanged -= Control_TitleChanged;
if (url.Equals(startUrl, StringComparison.OrdinalIgnoreCase))
{
@ -517,7 +570,7 @@ namespace SafeExamBrowser.Browser
}
messageBox.Show(message, title, parent: window);
control.TitleChanged += Control_TitleChanged;
Control.TitleChanged += Control_TitleChanged;
});
}
@ -530,7 +583,7 @@ namespace SafeExamBrowser.Browser
if (result == MessageBoxResult.Yes)
{
logger.Debug("The user confirmed reloading the current page...");
control.Reload();
Control.Reload();
}
else
{
@ -540,7 +593,7 @@ namespace SafeExamBrowser.Browser
else if (WindowSettings.AllowReloading)
{
logger.Debug("Reloading current page...");
control.Reload();
Control.Reload();
}
else
{
@ -555,7 +608,7 @@ namespace SafeExamBrowser.Browser
if (isValid)
{
logger.Debug($"The user requested to navigate to '{address}', the URI is valid.");
control.NavigateTo(address);
Control.NavigateTo(address);
}
else
{
@ -567,34 +620,39 @@ namespace SafeExamBrowser.Browser
private void Window_BackwardNavigationRequested()
{
logger.Debug("Navigating backwards...");
control.NavigateBackwards();
Control.NavigateBackwards();
}
private void Window_Closing()
{
logger.Info($"Window is closing...");
control.Destroy();
logger.Debug($"Window is closing...");
}
private void Window_Closed()
{
logger.Debug($"Window has been closed.");
Control.Destroy();
Closed?.Invoke(Id);
}
private void Window_DeveloperConsoleRequested()
{
logger.Debug("Showing developer console...");
control.ShowDeveloperConsole();
Control.ShowDeveloperConsole();
}
private void Window_FindRequested(string term, bool isInitial, bool caseSensitive, bool forward = true)
{
if (settings.AllowFind)
{
control.Find(term, isInitial, caseSensitive, forward);
Control.Find(term, isInitial, caseSensitive, forward);
}
}
private void Window_ForwardNavigationRequested()
{
logger.Debug("Navigating forwards...");
control.NavigateForwards();
Control.NavigateForwards();
}
private void ZoomInRequested()
@ -602,7 +660,7 @@ namespace SafeExamBrowser.Browser
if (settings.AllowPageZoom && CalculateZoomPercentage() < 300)
{
zoomLevel += ZOOM_FACTOR;
control.Zoom(zoomLevel);
Control.Zoom(zoomLevel);
window.UpdateZoomLevel(CalculateZoomPercentage());
logger.Debug($"Increased page zoom to {CalculateZoomPercentage()}%.");
}
@ -613,7 +671,7 @@ namespace SafeExamBrowser.Browser
if (settings.AllowPageZoom && CalculateZoomPercentage() > 25)
{
zoomLevel -= ZOOM_FACTOR;
control.Zoom(zoomLevel);
Control.Zoom(zoomLevel);
window.UpdateZoomLevel(CalculateZoomPercentage());
logger.Debug($"Decreased page zoom to {CalculateZoomPercentage()}%.");
}
@ -624,7 +682,7 @@ namespace SafeExamBrowser.Browser
if (settings.AllowPageZoom)
{
zoomLevel = 0;
control.Zoom(0);
Control.Zoom(0);
window.UpdateZoomLevel(CalculateZoomPercentage());
logger.Debug($"Reset page zoom to {CalculateZoomPercentage()}%.");
}

View file

@ -10,6 +10,6 @@ namespace SafeExamBrowser.Browser.Events
{
internal class PopupRequestedEventArgs
{
public string Url { get; set; }
public BrowserWindow Window { get; set; }
}
}

View file

@ -10,7 +10,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using CefSharp;
using SafeExamBrowser.Browser.Events;
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
using SafeExamBrowser.Browser.Wrapper;
namespace SafeExamBrowser.Browser.Handlers
{
@ -22,9 +22,9 @@ namespace SafeExamBrowser.Browser.Handlers
{
var args = new DialogRequestedEventArgs
{
Element = ToElement(mode),
Element = mode.ToElement(),
InitialPath = defaultFilePath,
Operation = ToOperation(mode),
Operation = mode.ToOperation(),
Title = title
};
@ -47,27 +47,5 @@ namespace SafeExamBrowser.Browser.Handlers
return true;
}
private FileSystemElement ToElement(CefFileDialogMode mode)
{
switch (mode)
{
case CefFileDialogMode.OpenFolder:
return FileSystemElement.Folder;
default:
return FileSystemElement.File;
}
}
private FileSystemOperation ToOperation(CefFileDialogMode mode)
{
switch (mode)
{
case CefFileDialogMode.Save:
return FileSystemOperation.Save;
default:
return FileSystemOperation.Open;
}
}
}
}

View file

@ -24,12 +24,12 @@ namespace SafeExamBrowser.Browser.Handlers
{
internal class DownloadHandler : IDownloadHandler
{
private AppConfig appConfig;
private BrowserSettings settings;
private WindowSettings windowSettings;
private ConcurrentDictionary<int, DownloadFinishedCallback> callbacks;
private ConcurrentDictionary<int, Guid> downloads;
private ILogger logger;
private readonly AppConfig appConfig;
private readonly ConcurrentDictionary<int, DownloadFinishedCallback> callbacks;
private readonly ConcurrentDictionary<int, Guid> downloads;
private readonly ILogger logger;
private readonly BrowserSettings settings;
private readonly WindowSettings windowSettings;
internal event DownloadRequestedEventHandler ConfigurationDownloadRequested;
internal event DownloadUpdatedEventHandler DownloadUpdated;
@ -85,7 +85,7 @@ namespace SafeExamBrowser.Browser.Handlers
IsComplete = downloadItem.IsComplete,
Url = downloadItem.Url
};
Task.Run(() => DownloadUpdated?.Invoke(state));
}

View file

@ -1,41 +0,0 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
using SafeExamBrowser.Browser.Events;
namespace SafeExamBrowser.Browser.Handlers
{
internal class LifeSpanHandler : ILifeSpanHandler
{
public event PopupRequestedEventHandler PopupRequested;
public bool DoClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
{
return false;
}
public void OnAfterCreated(IWebBrowser chromiumWebBrowser, IBrowser browser)
{
}
public void OnBeforeClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
{
}
public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
{
var args = new PopupRequestedEventArgs { Url = targetUrl };
newBrowser = default(IWebBrowser);
PopupRequested?.Invoke(args);
return true;
}
}
}

View file

@ -14,7 +14,6 @@ using CefSharp;
using SafeExamBrowser.Browser.Contracts.Filters;
using SafeExamBrowser.Browser.Events;
using SafeExamBrowser.Configuration.Contracts;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Settings.Browser;
using SafeExamBrowser.Settings.Browser.Filter;
@ -25,13 +24,14 @@ namespace SafeExamBrowser.Browser.Handlers
{
internal class RequestHandler : CefSharp.Handler.RequestHandler
{
private AppConfig appConfig;
private IRequestFilter filter;
private ILogger logger;
private readonly AppConfig appConfig;
private readonly IRequestFilter filter;
private readonly ILogger logger;
private readonly ResourceHandler resourceHandler;
private readonly WindowSettings windowSettings;
private readonly BrowserSettings settings;
private string quitUrlPattern;
private ResourceHandler resourceHandler;
private WindowSettings windowSettings;
private BrowserSettings settings;
internal event UrlEventHandler QuitUrlVisited;
internal event UrlEventHandler RequestBlocked;
@ -42,8 +42,7 @@ namespace SafeExamBrowser.Browser.Handlers
ILogger logger,
ResourceHandler resourceHandler,
BrowserSettings settings,
WindowSettings windowSettings,
IText text)
WindowSettings windowSettings)
{
this.appConfig = appConfig;
this.filter = filter;
@ -53,16 +52,7 @@ namespace SafeExamBrowser.Browser.Handlers
this.windowSettings = windowSettings;
}
protected override bool GetAuthCredentials(
IWebBrowser webBrowser,
IBrowser browser,
string originUrl,
bool isProxy,
string host,
int port,
string realm,
string scheme,
IAuthCallback callback)
protected override bool GetAuthCredentials(IWebBrowser webBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)
{
if (isProxy)
{
@ -80,15 +70,7 @@ namespace SafeExamBrowser.Browser.Handlers
return base.GetAuthCredentials(webBrowser, browser, originUrl, isProxy, host, port, realm, scheme, callback);
}
protected override IResourceRequestHandler GetResourceRequestHandler(
IWebBrowser webBrowser,
IBrowser browser,
IFrame frame,
IRequest request,
bool isNavigation,
bool isDownload,
string requestInitiator,
ref bool disableDefaultHandling)
protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
{
return resourceHandler;
}
@ -122,13 +104,7 @@ namespace SafeExamBrowser.Browser.Handlers
return base.OnBeforeBrowse(webBrowser, browser, frame, request, userGesture, isRedirect);
}
protected override bool OnOpenUrlFromTab(
IWebBrowser webBrowser,
IBrowser browser,
IFrame frame,
string targetUrl,
WindowOpenDisposition targetDisposition,
bool userGesture)
protected override bool OnOpenUrlFromTab(IWebBrowser webBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)
{
switch (targetDisposition)
{
@ -172,7 +148,7 @@ namespace SafeExamBrowser.Browser.Handlers
if (!string.IsNullOrWhiteSpace(settings.QuitUrl))
{
if (quitUrlPattern == default(string))
if (quitUrlPattern == default)
{
quitUrlPattern = Regex.Escape(settings.QuitUrl.TrimEnd('/')) + @"\/?";
}

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props')" />
<Import Project="..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props" Condition="Exists('..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props')" />
<Import Project="..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props" Condition="Exists('..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props')" />
<Import Project="..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props')" />
<Import Project="..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props" Condition="Exists('..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props')" />
<Import Project="..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props" Condition="Exists('..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -53,14 +53,14 @@
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="CefSharp, Version=97.1.11.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.Common.97.1.11\lib\net452\CefSharp.dll</HintPath>
<Reference Include="CefSharp, Version=98.1.210.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.Common.98.1.210\lib\net452\CefSharp.dll</HintPath>
</Reference>
<Reference Include="CefSharp.Core, Version=97.1.11.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.Common.97.1.11\lib\net452\CefSharp.Core.dll</HintPath>
<Reference Include="CefSharp.Core, Version=98.1.210.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.Common.98.1.210\lib\net452\CefSharp.Core.dll</HintPath>
</Reference>
<Reference Include="CefSharp.WinForms, Version=97.1.11.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.WinForms.97.1.11\lib\net462\CefSharp.WinForms.dll</HintPath>
<Reference Include="CefSharp.WinForms, Version=98.1.210.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.WinForms.98.1.210\lib\net462\CefSharp.WinForms.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
@ -95,19 +95,42 @@
<Compile Include="Filters\RuleFactory.cs" />
<Compile Include="Filters\Rules\SimplifiedRule.cs" />
<Compile Include="Handlers\ContextMenuHandler.cs" />
<Compile Include="BrowserControl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="BrowserControl.cs" />
<Compile Include="BrowserIconResource.cs" />
<Compile Include="Handlers\DialogHandler.cs" />
<Compile Include="Handlers\DisplayHandler.cs" />
<Compile Include="Handlers\DownloadHandler.cs" />
<Compile Include="Handlers\KeyboardHandler.cs" />
<Compile Include="Handlers\LifeSpanHandler.cs" />
<Compile Include="Handlers\RequestHandler.cs" />
<Compile Include="Handlers\ResourceHandler.cs" />
<Compile Include="Content\ContentLoader.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Wrapper\CefSharpBrowserControl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Wrapper\CefSharpPopupControl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Wrapper\Events\AuthCredentialsEventHandler.cs" />
<Compile Include="Wrapper\Events\BeforeBrowseEventHandler.cs" />
<Compile Include="Wrapper\Events\BeforeDownloadEventHandler.cs" />
<Compile Include="Wrapper\Events\DownloadUpdatedEventHandler.cs" />
<Compile Include="Wrapper\Events\FaviconUrlChangedEventHandler.cs" />
<Compile Include="Wrapper\Events\FileDialogRequestedEventHandler.cs" />
<Compile Include="Wrapper\Events\KeyEventHandler.cs" />
<Compile Include="Wrapper\Events\LoadingProgressChangedEventHandler.cs" />
<Compile Include="Wrapper\Events\GenericEventArgs.cs" />
<Compile Include="Wrapper\Events\OpenUrlFromTabEventHandler.cs" />
<Compile Include="Wrapper\Events\PreKeyEventHandler.cs" />
<Compile Include="Wrapper\Events\ResourceRequestEventArgs.cs" />
<Compile Include="Wrapper\Events\ResourceRequestEventHandler.cs" />
<Compile Include="Wrapper\Extensions.cs" />
<Compile Include="Wrapper\Handlers\DialogHandlerSwitch.cs" />
<Compile Include="Wrapper\Handlers\DisplayHandlerSwitch.cs" />
<Compile Include="Wrapper\Handlers\DownloadHandlerSwitch.cs" />
<Compile Include="Wrapper\Handlers\KeyboardHandlerSwitch.cs" />
<Compile Include="Wrapper\Handlers\RequestHandlerSwitch.cs" />
<Compile Include="Wrapper\ICefSharpControl.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SafeExamBrowser.Applications.Contracts\SafeExamBrowser.Applications.Contracts.csproj">
@ -153,9 +176,7 @@
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Content\Api.js" />
@ -172,10 +193,10 @@
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props'))" />
<Error Condition="!Exists('..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets'))" />
<Error Condition="!Exists('..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props'))" />
<Error Condition="!Exists('..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets'))" />
</Target>
<Import Project="..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets')" />
<Import Project="..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets')" />
</Project>

View file

@ -0,0 +1,103 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.Collections.Generic;
using CefSharp;
using CefSharp.WinForms;
using SafeExamBrowser.Browser.Handlers;
using SafeExamBrowser.Browser.Wrapper.Events;
using SafeExamBrowser.Browser.Wrapper.Handlers;
namespace SafeExamBrowser.Browser.Wrapper
{
internal class CefSharpBrowserControl : ChromiumWebBrowser, ICefSharpControl
{
public event AuthCredentialsEventHandler AuthCredentialsRequired;
public event BeforeBrowseEventHandler BeforeBrowse;
public event BeforeDownloadEventHandler BeforeDownload;
public event DownloadUpdatedEventHandler DownloadUpdated;
public event FaviconUrlChangedEventHandler FaviconUrlChanged;
public event FileDialogRequestedEventHandler FileDialogRequested;
public event KeyEventHandler KeyEvent;
public event LoadingProgressChangedEventHandler LoadingProgressChanged;
public event OpenUrlFromTabEventHandler OpenUrlFromTab;
public event PreKeyEventHandler PreKeyEvent;
public event ResourceRequestEventHandler ResourceRequestHandlerRequired;
public CefSharpBrowserControl(ILifeSpanHandler lifeSpanHandler, string url) : base(url)
{
DialogHandler = new DialogHandlerSwitch();
DisplayHandler = new DisplayHandlerSwitch();
DownloadHandler = new DownloadHandlerSwitch();
KeyboardHandler = new KeyboardHandlerSwitch();
LifeSpanHandler = lifeSpanHandler;
MenuHandler = new ContextMenuHandler();
RequestHandler = new RequestHandlerSwitch();
}
void ICefSharpControl.Dispose(bool disposing)
{
base.Dispose(disposing);
}
public void GetAuthCredentials(IWebBrowser webBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback, GenericEventArgs args)
{
AuthCredentialsRequired?.Invoke(webBrowser, browser, originUrl, isProxy, host, port, realm, scheme, callback, args);
}
public void GetResourceRequestHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling, ResourceRequestEventArgs args)
{
ResourceRequestHandlerRequired?.Invoke(webBrowser, browser, frame, request, isNavigation, isDownload, requestInitiator, ref disableDefaultHandling, args);
}
public void OnBeforeBrowse(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect, GenericEventArgs args)
{
BeforeBrowse?.Invoke(webBrowser, browser, frame, request, userGesture, isRedirect, args);
}
public void OnBeforeDownload(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
{
BeforeDownload?.Invoke(webBrowser, browser, downloadItem, callback);
}
public void OnDownloadUpdated(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
{
DownloadUpdated?.Invoke(webBrowser, browser, downloadItem, callback);
}
public void OnFaviconUrlChange(IWebBrowser webBrowser, IBrowser browser, IList<string> urls)
{
FaviconUrlChanged?.Invoke(webBrowser, browser, urls);
}
public void OnFileDialog(IWebBrowser webBrowser, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback)
{
FileDialogRequested?.Invoke(webBrowser, browser, mode, flags, title, defaultFilePath, acceptFilters, selectedAcceptFilter, callback);
}
public void OnKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
{
KeyEvent?.Invoke(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey);
}
public void OnLoadingProgressChange(IWebBrowser webBrowser, IBrowser browser, double progress)
{
LoadingProgressChanged?.Invoke(webBrowser, browser, progress);
}
public void OnOpenUrlFromTab(IWebBrowser webBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture, GenericEventArgs args)
{
OpenUrlFromTab?.Invoke(webBrowser, browser, frame, targetUrl, targetDisposition, userGesture, args);
}
public void OnPreKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut, GenericEventArgs args)
{
PreKeyEvent?.Invoke(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey, ref isKeyboardShortcut, args);
}
}
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.Collections.Generic;
using CefSharp;
using CefSharp.WinForms.Host;
using SafeExamBrowser.Browser.Wrapper.Events;
namespace SafeExamBrowser.Browser.Wrapper
{
internal class CefSharpPopupControl : ChromiumHostControl, ICefSharpControl
{
public event AuthCredentialsEventHandler AuthCredentialsRequired;
public event BeforeBrowseEventHandler BeforeBrowse;
public event BeforeDownloadEventHandler BeforeDownload;
public event DownloadUpdatedEventHandler DownloadUpdated;
public event FaviconUrlChangedEventHandler FaviconUrlChanged;
public event FileDialogRequestedEventHandler FileDialogRequested;
public event KeyEventHandler KeyEvent;
public event LoadingProgressChangedEventHandler LoadingProgressChanged;
public event OpenUrlFromTabEventHandler OpenUrlFromTab;
public event PreKeyEventHandler PreKeyEvent;
public event ResourceRequestEventHandler ResourceRequestHandlerRequired;
void ICefSharpControl.Dispose(bool disposing)
{
if (!IsDisposed && IsHandleCreated)
{
base.Dispose(disposing);
}
}
public void GetAuthCredentials(IWebBrowser webBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback, GenericEventArgs args)
{
AuthCredentialsRequired?.Invoke(webBrowser, browser, originUrl, isProxy, host, port, realm, scheme, callback, args);
}
public void GetResourceRequestHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling, ResourceRequestEventArgs args)
{
ResourceRequestHandlerRequired?.Invoke(webBrowser, browser, frame, request, isNavigation, isDownload, requestInitiator, ref disableDefaultHandling, args);
}
public void Load(string address)
{
LoadUrl(address);
}
public void OnBeforeBrowse(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect, GenericEventArgs args)
{
BeforeBrowse?.Invoke(webBrowser, browser, frame, request, userGesture, isRedirect, args);
}
public void OnBeforeDownload(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
{
BeforeDownload?.Invoke(webBrowser, browser, downloadItem, callback);
}
public void OnDownloadUpdated(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
{
DownloadUpdated?.Invoke(webBrowser, browser, downloadItem, callback);
}
public void OnFaviconUrlChange(IWebBrowser webBrowser, IBrowser browser, IList<string> urls)
{
FaviconUrlChanged?.Invoke(webBrowser, browser, urls);
}
public void OnFileDialog(IWebBrowser webBrowser, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback)
{
FileDialogRequested?.Invoke(webBrowser, browser, mode, flags, title, defaultFilePath, acceptFilters, selectedAcceptFilter, callback);
}
public void OnKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
{
KeyEvent?.Invoke(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey);
}
public void OnLoadingProgressChange(IWebBrowser webBrowser, IBrowser browser, double progress)
{
LoadingProgressChanged?.Invoke(webBrowser, browser, progress);
}
public void OnOpenUrlFromTab(IWebBrowser webBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture, GenericEventArgs args)
{
OpenUrlFromTab?.Invoke(webBrowser, browser, frame, targetUrl, targetDisposition, userGesture, args);
}
public void OnPreKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut, GenericEventArgs args)
{
PreKeyEvent?.Invoke(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey, ref isKeyboardShortcut, args);
}
}
}

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
namespace SafeExamBrowser.Browser.Wrapper.Events
{
internal delegate void AuthCredentialsEventHandler(IWebBrowser webBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback, GenericEventArgs args);
}

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
namespace SafeExamBrowser.Browser.Wrapper.Events
{
internal delegate void BeforeBrowseEventHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect, GenericEventArgs args);
}

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
namespace SafeExamBrowser.Browser.Wrapper.Events
{
internal delegate void BeforeDownloadEventHandler(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback);
}

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
namespace SafeExamBrowser.Browser.Wrapper.Events
{
internal delegate void DownloadUpdatedEventHandler(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback);
}

View file

@ -0,0 +1,15 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.Collections.Generic;
using CefSharp;
namespace SafeExamBrowser.Browser.Wrapper.Events
{
internal delegate void FaviconUrlChangedEventHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IList<string> urls);
}

View file

@ -0,0 +1,15 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.Collections.Generic;
using CefSharp;
namespace SafeExamBrowser.Browser.Wrapper.Events
{
internal delegate void FileDialogRequestedEventHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback);
}

View file

@ -0,0 +1,15 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
namespace SafeExamBrowser.Browser.Wrapper.Events
{
internal class GenericEventArgs
{
public bool Value { get; set; }
}
}

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
namespace SafeExamBrowser.Browser.Wrapper.Events
{
internal delegate void KeyEventHandler(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey);
}

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
namespace SafeExamBrowser.Browser.Wrapper.Events
{
internal delegate void LoadingProgressChangedEventHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, double progress);
}

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
namespace SafeExamBrowser.Browser.Wrapper.Events
{
internal delegate void OpenUrlFromTabEventHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture, GenericEventArgs args);
}

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
namespace SafeExamBrowser.Browser.Wrapper.Events
{
internal delegate void PreKeyEventHandler(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut, GenericEventArgs args);
}

View file

@ -0,0 +1,17 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
namespace SafeExamBrowser.Browser.Wrapper.Events
{
internal class ResourceRequestEventArgs
{
public IResourceRequestHandler Handler { get; set; }
}
}

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
namespace SafeExamBrowser.Browser.Wrapper.Events
{
internal delegate void ResourceRequestEventHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling, ResourceRequestEventArgs args);
}

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
namespace SafeExamBrowser.Browser.Wrapper
{
internal static class Extensions
{
internal static FileSystemElement ToElement(this CefFileDialogMode mode)
{
switch (mode)
{
case CefFileDialogMode.OpenFolder:
return FileSystemElement.Folder;
default:
return FileSystemElement.File;
}
}
internal static FileSystemOperation ToOperation(this CefFileDialogMode mode)
{
switch (mode)
{
case CefFileDialogMode.Save:
return FileSystemOperation.Save;
default:
return FileSystemOperation.Open;
}
}
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.Collections.Generic;
using CefSharp;
using CefSharp.WinForms;
using CefSharp.WinForms.Host;
namespace SafeExamBrowser.Browser.Wrapper.Handlers
{
internal class DialogHandlerSwitch : IDialogHandler
{
public bool OnFileDialog(IWebBrowser webBrowser, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback)
{
if (browser.IsPopup)
{
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
control?.OnFileDialog(webBrowser, browser, mode, flags, title, defaultFilePath, acceptFilters, selectedAcceptFilter, callback);
}
else
{
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
control?.OnFileDialog(webBrowser, browser, mode, flags, title, defaultFilePath, acceptFilters, selectedAcceptFilter, callback);
}
return true;
}
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.Collections.Generic;
using CefSharp;
using CefSharp.WinForms;
using CefSharp.WinForms.Handler;
using CefSharp.WinForms.Host;
namespace SafeExamBrowser.Browser.Wrapper.Handlers
{
internal class DisplayHandlerSwitch : DisplayHandler
{
protected override void OnFaviconUrlChange(IWebBrowser chromiumWebBrowser, IBrowser browser, IList<string> urls)
{
if (browser.IsPopup)
{
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
control?.OnFaviconUrlChange(chromiumWebBrowser, browser, urls);
}
else
{
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
control?.OnFaviconUrlChange(chromiumWebBrowser, browser, urls);
}
base.OnFaviconUrlChange(chromiumWebBrowser, browser, urls);
}
protected override void OnLoadingProgressChange(IWebBrowser chromiumWebBrowser, IBrowser browser, double progress)
{
if (browser.IsPopup)
{
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
control?.OnLoadingProgressChange(chromiumWebBrowser, browser, progress);
}
else
{
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
control?.OnLoadingProgressChange(chromiumWebBrowser, browser, progress);
}
base.OnLoadingProgressChange(chromiumWebBrowser, browser, progress);
}
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
using CefSharp.WinForms;
using CefSharp.WinForms.Host;
namespace SafeExamBrowser.Browser.Wrapper.Handlers
{
internal class DownloadHandlerSwitch : IDownloadHandler
{
public void OnBeforeDownload(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
{
if (browser.IsPopup)
{
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
control?.OnBeforeDownload(webBrowser, browser, downloadItem, callback);
}
else
{
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
control?.OnBeforeDownload(webBrowser, browser, downloadItem, callback);
}
}
public void OnDownloadUpdated(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
{
if (browser.IsPopup)
{
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
control?.OnDownloadUpdated(webBrowser, browser, downloadItem, callback);
}
else
{
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
control?.OnDownloadUpdated(webBrowser, browser, downloadItem, callback);
}
}
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
using CefSharp.WinForms;
using CefSharp.WinForms.Host;
using SafeExamBrowser.Browser.Wrapper.Events;
namespace SafeExamBrowser.Browser.Wrapper.Handlers
{
internal class KeyboardHandlerSwitch : IKeyboardHandler
{
public bool OnKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
{
if (browser.IsPopup)
{
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
control?.OnKeyEvent(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey);
}
else
{
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
control?.OnKeyEvent(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey);
}
return false;
}
public bool OnPreKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut)
{
var args = new GenericEventArgs { Value = false };
if (browser.IsPopup)
{
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
control?.OnPreKeyEvent(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey, ref isKeyboardShortcut, args);
}
else
{
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
control?.OnPreKeyEvent(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey, ref isKeyboardShortcut, args);
}
return args.Value;
}
}
}

View file

@ -0,0 +1,99 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using CefSharp;
using CefSharp.Handler;
using CefSharp.WinForms;
using CefSharp.WinForms.Host;
using SafeExamBrowser.Browser.Wrapper.Events;
namespace SafeExamBrowser.Browser.Wrapper.Handlers
{
internal class RequestHandlerSwitch : RequestHandler
{
protected override bool GetAuthCredentials(IWebBrowser webBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)
{
var args = new GenericEventArgs { Value = false };
if (browser.IsPopup)
{
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
control?.GetAuthCredentials(webBrowser, browser, originUrl, isProxy, host, port, realm, scheme, callback, args);
}
else
{
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
control?.GetAuthCredentials(webBrowser, browser, originUrl, isProxy, host, port, realm, scheme, callback, args);
}
return args.Value;
}
protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
{
var args = new ResourceRequestEventArgs();
if (browser.IsPopup)
{
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
control?.GetResourceRequestHandler(chromiumWebBrowser, browser, frame, request, isNavigation, isDownload, requestInitiator, ref disableDefaultHandling, args);
}
else
{
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
control?.GetResourceRequestHandler(chromiumWebBrowser, browser, frame, request, isNavigation, isDownload, requestInitiator, ref disableDefaultHandling, args);
}
return args.Handler;
}
protected override bool OnBeforeBrowse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect)
{
var args = new GenericEventArgs { Value = false };
if (browser.IsPopup)
{
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
control?.OnBeforeBrowse(chromiumWebBrowser, browser, frame, request, userGesture, isRedirect, args);
}
else
{
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
control?.OnBeforeBrowse(chromiumWebBrowser, browser, frame, request, userGesture, isRedirect, args);
}
return args.Value;
}
protected override bool OnOpenUrlFromTab(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)
{
var args = new GenericEventArgs { Value = false };
if (browser.IsPopup)
{
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
control?.OnOpenUrlFromTab(chromiumWebBrowser, browser, frame, targetUrl, targetDisposition, userGesture, args);
}
else
{
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
control?.OnOpenUrlFromTab(chromiumWebBrowser, browser, frame, targetUrl, targetDisposition, userGesture, args);
}
return args.Value;
}
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;
using SafeExamBrowser.Browser.Wrapper.Events;
using KeyEventHandler = SafeExamBrowser.Browser.Wrapper.Events.KeyEventHandler;
namespace SafeExamBrowser.Browser.Wrapper
{
internal interface ICefSharpControl : IChromiumWebBrowserBase, IWinFormsChromiumWebBrowser, IWin32Window, IComponent, ISynchronizeInvoke
{
event AuthCredentialsEventHandler AuthCredentialsRequired;
event BeforeBrowseEventHandler BeforeBrowse;
event BeforeDownloadEventHandler BeforeDownload;
event DownloadUpdatedEventHandler DownloadUpdated;
event FaviconUrlChangedEventHandler FaviconUrlChanged;
event FileDialogRequestedEventHandler FileDialogRequested;
event KeyEventHandler KeyEvent;
event LoadingProgressChangedEventHandler LoadingProgressChanged;
event OpenUrlFromTabEventHandler OpenUrlFromTab;
event PreKeyEventHandler PreKeyEvent;
event ResourceRequestEventHandler ResourceRequestHandlerRequired;
void Dispose(bool disposing);
void GetAuthCredentials(IWebBrowser webBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback, GenericEventArgs args);
void GetResourceRequestHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling, ResourceRequestEventArgs args);
void Load(string address);
void OnBeforeBrowse(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect, GenericEventArgs args);
void OnBeforeDownload(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback);
void OnDownloadUpdated(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback);
void OnFaviconUrlChange(IWebBrowser webBrowser, IBrowser browser, IList<string> urls);
void OnFileDialog(IWebBrowser webBrowser, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback);
void OnKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey);
void OnLoadingProgressChange(IWebBrowser webBrowser, IBrowser browser, double progress);
void OnOpenUrlFromTab(IWebBrowser webBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture, GenericEventArgs args);
void OnPreKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut, GenericEventArgs args);
}
}

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="cef.redist.x64" version="97.1.1" targetFramework="net472" />
<package id="cef.redist.x86" version="97.1.1" targetFramework="net472" />
<package id="CefSharp.Common" version="97.1.11" targetFramework="net472" />
<package id="CefSharp.WinForms" version="97.1.11" targetFramework="net472" />
<package id="cef.redist.x64" version="98.1.21" targetFramework="net472" />
<package id="cef.redist.x86" version="98.1.21" targetFramework="net472" />
<package id="CefSharp.Common" version="98.1.210" targetFramework="net472" />
<package id="CefSharp.WinForms" version="98.1.210" targetFramework="net472" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net472" />
<package id="Syroot.Windows.IO.KnownFolders" version="1.2.3" targetFramework="net472" />
<package id="System.Security.Principal.Windows" version="5.0.0" targetFramework="net472" />

View file

@ -20,7 +20,6 @@ namespace SafeExamBrowser.Client.Notifications
internal class AboutNotification : INotification
{
private readonly AppConfig appConfig;
private readonly IText text;
private readonly IUserInterfaceFactory uiFactory;
private IWindow window;
@ -33,7 +32,6 @@ namespace SafeExamBrowser.Client.Notifications
public AboutNotification(AppConfig appConfig, IText text, IUserInterfaceFactory uiFactory)
{
this.appConfig = appConfig;
this.text = text;
this.uiFactory = uiFactory;
IconResource = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/AboutNotification.xaml") };
@ -42,11 +40,11 @@ namespace SafeExamBrowser.Client.Notifications
public void Activate()
{
if (window == default(IWindow))
if (window == default)
{
window = uiFactory.CreateAboutWindow(appConfig);
window.Closing += () => window = default(IWindow);
window.Closed += () => window = default;
window.Show();
}
else

View file

@ -20,7 +20,6 @@ namespace SafeExamBrowser.Client.Notifications
internal class LogNotification : INotification
{
private readonly ILogger logger;
private readonly IText text;
private readonly IUserInterfaceFactory uiFactory;
private IWindow window;
@ -33,7 +32,6 @@ namespace SafeExamBrowser.Client.Notifications
public LogNotification(ILogger logger, IText text, IUserInterfaceFactory uiFactory)
{
this.logger = logger;
this.text = text;
this.uiFactory = uiFactory;
IconResource = new BitmapIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/LogNotification.ico") };
@ -42,11 +40,11 @@ namespace SafeExamBrowser.Client.Notifications
public void Activate()
{
if (window == default(IWindow))
if (window == default)
{
window = uiFactory.CreateLogWindow(logger);
window.Closing += () => window = null;
window.Closed += () => window = default;
window.Show();
}
else

View file

@ -52,14 +52,14 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Web.WebView2.Core, Version=1.0.1072.54, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.1072.54\lib\net45\Microsoft.Web.WebView2.Core.dll</HintPath>
<Reference Include="Microsoft.Web.WebView2.Core, Version=1.0.1108.44, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.1108.44\lib\net45\Microsoft.Web.WebView2.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.WebView2.WinForms, Version=1.0.1072.54, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.1072.54\lib\net45\Microsoft.Web.WebView2.WinForms.dll</HintPath>
<Reference Include="Microsoft.Web.WebView2.WinForms, Version=1.0.1108.44, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.1108.44\lib\net45\Microsoft.Web.WebView2.WinForms.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.WebView2.Wpf, Version=1.0.1072.54, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.1072.54\lib\net45\Microsoft.Web.WebView2.Wpf.dll</HintPath>
<Reference Include="Microsoft.Web.WebView2.Wpf, Version=1.0.1108.44, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.1108.44\lib\net45\Microsoft.Web.WebView2.Wpf.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
@ -124,11 +124,11 @@
</None>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Microsoft.Web.WebView2.1.0.1072.54\build\Microsoft.Web.WebView2.targets" Condition="Exists('..\packages\Microsoft.Web.WebView2.1.0.1072.54\build\Microsoft.Web.WebView2.targets')" />
<Import Project="..\packages\Microsoft.Web.WebView2.1.0.1108.44\build\Microsoft.Web.WebView2.targets" Condition="Exists('..\packages\Microsoft.Web.WebView2.1.0.1108.44\build\Microsoft.Web.WebView2.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Web.WebView2.1.0.1072.54\build\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Web.WebView2.1.0.1072.54\build\Microsoft.Web.WebView2.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.Web.WebView2.1.0.1108.44\build\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Web.WebView2.1.0.1108.44\build\Microsoft.Web.WebView2.targets'))" />
</Target>
</Project>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Web.WebView2" version="1.0.1072.54" targetFramework="net472" />
<package id="Microsoft.Web.WebView2" version="1.0.1108.44" targetFramework="net472" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net472" />
</packages>

View file

@ -120,13 +120,13 @@ namespace SafeExamBrowser.Runtime
}
internal void LogStartupInformation()
{
{
logger.Log($"/* {appConfig.ProgramTitle}, Version {appConfig.ProgramInformationalVersion}, Build {appConfig.ProgramBuildVersion}");
logger.Log($"/* {appConfig.ProgramCopyright}");
logger.Log($"/* ");
logger.Log($"/* Please visit https://www.github.com/SafeExamBrowser for more information.");
logger.Log(string.Empty);
logger.Log($"# Application started at {appConfig.ApplicationStartTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
logger.Log($"# Application started at {appConfig.ApplicationStartTime:yyyy-MM-dd HH:mm:ss.fff}");
logger.Log($"# Running on {systemInfo.OperatingSystemInfo}");
logger.Log($"# Computer '{systemInfo.Name}' is a {systemInfo.Model} manufactured by {systemInfo.Manufacturer}");
logger.Log($"# Runtime-ID: {appConfig.RuntimeId}");
@ -135,7 +135,7 @@ namespace SafeExamBrowser.Runtime
internal void LogShutdownInformation()
{
logger?.Log($"# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
logger?.Log($"# Application terminated at {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
}
private void InitializeConfiguration()

View file

@ -31,6 +31,11 @@ namespace SafeExamBrowser.UserInterface.Contracts.Browser
/// </summary>
bool CanNavigateForwards { get; }
/// <summary>
/// The user interface control to be embedded in an <see cref="IBrowserWindow"/>.
/// </summary>
object EmbeddableControl { get; }
/// <summary>
/// Event fired when the address of the browser control changes.
/// </summary>

View file

@ -94,6 +94,7 @@
<Compile Include="Windows\Data\LockScreenOption.cs" />
<Compile Include="Windows\Data\LockScreenResult.cs" />
<Compile Include="Windows\Data\ServerFailureDialogResult.cs" />
<Compile Include="Windows\Events\WindowClosedEventHandler.cs" />
<Compile Include="Windows\Events\WindowClosingEventHandler.cs" />
<Compile Include="Windows\IExamSelectionDialog.cs" />
<Compile Include="Windows\ILockScreen.cs" />

View file

@ -0,0 +1,15 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
namespace SafeExamBrowser.UserInterface.Contracts.Windows.Events
{
/// <summary>
/// Indicates that a window has been closed.
/// </summary>
public delegate void WindowClosedEventHandler();
}

View file

@ -15,6 +15,11 @@ namespace SafeExamBrowser.UserInterface.Contracts.Windows
/// </summary>
public interface IWindow
{
/// <summary>
/// Event fired when the window has been closed;
/// </summary>
event WindowClosedEventHandler Closed;
/// <summary>
/// Event fired when the window is closing.
/// </summary>

View file

@ -18,10 +18,18 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
{
internal partial class AboutWindow : Window, IWindow
{
private AppConfig appConfig;
private IText text;
private readonly AppConfig appConfig;
private readonly IText text;
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
@ -44,6 +52,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
private void InitializeAboutWindow()
{
Closed += (o, args) => closed?.Invoke();
Closing += (o, args) => closing?.Invoke();
MainText.Inlines.InsertBefore(MainText.Inlines.FirstInline, new Run(text.Get(TextKey.AboutWindow_LicenseInfo)));
Title = text.Get(TextKey.AboutWindow_Title);

View file

@ -30,9 +30,11 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
{
internal partial class BrowserWindow : Window, IBrowserWindow
{
private bool isMainWindow;
private BrowserSettings settings;
private IText text;
private readonly bool isMainWindow;
private readonly BrowserSettings settings;
private readonly IText text;
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
private WindowSettings WindowSettings
@ -55,6 +57,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
public event ActionRequestedEventHandler ZoomOutRequested;
public event ActionRequestedEventHandler ZoomResetRequested;
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
@ -282,7 +290,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
private void InitializeBrowserWindow(IBrowserControl browserControl)
{
if (browserControl is System.Windows.Forms.Control control)
if (browserControl.EmbeddableControl is System.Windows.Forms.Control control)
{
BrowserControlHost.Child = control;
}
@ -297,6 +305,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
private void RegisterEvents()
{
BackwardButton.Click += (o, args) => BackwardNavigationRequested?.Invoke();
Closed += (o, args) => closed?.Invoke();
Closing += BrowserWindow_Closing;
DeveloperConsoleButton.Click += (o, args) => DeveloperConsoleRequested?.Invoke();
DownloadsButton.Click += (o, args) => DownloadsPopup.IsOpen = !DownloadsPopup.IsOpen;

View file

@ -25,9 +25,16 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
{
internal partial class LockScreen : Window, ILockScreen
{
private AutoResetEvent autoResetEvent;
private readonly AutoResetEvent autoResetEvent;
private readonly IText text;
private IList<Window> windows;
private IText text;
event WindowClosedEventHandler IWindow.Closed
{
add { throw new NotImplementedException(); }
remove { throw new NotImplementedException(); }
}
event WindowClosingEventHandler IWindow.Closing
{

View file

@ -19,10 +19,18 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
{
internal partial class LogWindow : Window, IWindow
{
private ILogger logger;
private LogViewModel model;
private readonly ILogger logger;
private readonly LogViewModel model;
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
@ -70,6 +78,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
private void InitializeLogWindow()
{
DataContext = model;
Closed += (o, args) => closed?.Invoke();
Closing += LogWindow_Closing;
Loaded += LogWindow_Loaded;
}

View file

@ -17,9 +17,17 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
{
internal partial class PasswordDialog : Window, IPasswordDialog
{
private IText text;
private readonly IText text;
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
@ -73,6 +81,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
ConfirmButton.Content = text.Get(TextKey.PasswordDialog_Confirm);
ConfirmButton.Click += ConfirmButton_Click;
Closed += (o, args) => closed?.Invoke();
Closing += (o, args) => closing?.Invoke();
Loaded += (o, args) => Activate();
Password.KeyUp += Password_KeyUp;

View file

@ -18,8 +18,15 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
{
public partial class ProctoringWindow : Window, IProctoringWindow
{
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
@ -99,6 +106,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
control.FullScreenChanged += Control_FullScreenChanged;
}
Closed += (o, args) => closed?.Invoke();
Closing += ProctoringWindow_Closing;
Loaded += ProctoringWindow_Loaded;
Top = SystemParameters.WorkArea.Height - Height - 15;

View file

@ -20,10 +20,13 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
{
internal partial class RuntimeWindow : Window, IRuntimeWindow
{
private readonly AppConfig appConfig;
private readonly IText text;
private bool allowClose;
private AppConfig appConfig;
private IText text;
private RuntimeWindowViewModel model;
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
public bool ShowLog
@ -48,6 +51,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
set => Dispatcher.Invoke(() => Topmost = value);
}
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
@ -74,6 +83,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
{
allowClose = true;
model.BusyIndication = false;
closing?.Invoke();
base.Close();
});
@ -145,6 +155,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
ProgressBar.DataContext = model;
StatusTextBlock.DataContext = model;
Closed += (o, args) => closed?.Invoke();
Closing += (o, args) => args.Cancel = !allowClose;
#if DEBUG

View file

@ -19,10 +19,13 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
{
internal partial class SplashScreen : Window, ISplashScreen
{
private bool allowClose;
private ProgressIndicatorViewModel model = new ProgressIndicatorViewModel();
private readonly ProgressIndicatorViewModel model;
private readonly IText text;
private AppConfig appConfig;
private IText text;
private bool allowClose;
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
public AppConfig AppConfig
@ -37,6 +40,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
}
}
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
@ -46,6 +55,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
internal SplashScreen(IText text, AppConfig appConfig = null)
{
this.appConfig = appConfig;
this.model = new ProgressIndicatorViewModel();
this.text = text;
InitializeComponent();
@ -63,6 +73,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
{
allowClose = true;
model.BusyIndication = false;
closing?.Invoke();
base.Close();
});
@ -116,6 +127,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
StatusTextBlock.DataContext = model;
ProgressBar.DataContext = model;
Closed += (o, args) => closed?.Invoke();
Closing += (o, args) => args.Cancel = !allowClose;
}

View file

@ -18,10 +18,18 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
{
internal partial class AboutWindow : Window, IWindow
{
private AppConfig appConfig;
private IText text;
private readonly AppConfig appConfig;
private readonly IText text;
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
@ -44,6 +52,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
private void InitializeAboutWindow()
{
Closed += (o, args) => closed?.Invoke();
Closing += (o, args) => closing?.Invoke();
MainText.Inlines.InsertBefore(MainText.Inlines.FirstInline, new Run(text.Get(TextKey.AboutWindow_LicenseInfo)));
Title = text.Get(TextKey.AboutWindow_Title);

View file

@ -30,9 +30,11 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
{
internal partial class BrowserWindow : Window, IBrowserWindow
{
private bool isMainWindow;
private BrowserSettings settings;
private IText text;
private readonly bool isMainWindow;
private readonly BrowserSettings settings;
private readonly IText text;
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
private WindowSettings WindowSettings
@ -55,6 +57,12 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
public event ActionRequestedEventHandler ZoomOutRequested;
public event ActionRequestedEventHandler ZoomResetRequested;
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
@ -282,7 +290,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
private void InitializeBrowserWindow(IBrowserControl browserControl)
{
if (browserControl is System.Windows.Forms.Control control)
if (browserControl.EmbeddableControl is System.Windows.Forms.Control control)
{
BrowserControlHost.Child = control;
}
@ -297,6 +305,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
private void RegisterEvents()
{
BackwardButton.Click += (o, args) => BackwardNavigationRequested?.Invoke();
Closed += (o, args) => closed?.Invoke();
Closing += BrowserWindow_Closing;
DeveloperConsoleButton.Click += (o, args) => DeveloperConsoleRequested?.Invoke();
DownloadsButton.Click += (o, args) => DownloadsPopup.IsOpen = !DownloadsPopup.IsOpen;

View file

@ -25,9 +25,16 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
{
internal partial class LockScreen : Window, ILockScreen
{
private AutoResetEvent autoResetEvent;
private readonly AutoResetEvent autoResetEvent;
private readonly IText text;
private IList<Window> windows;
private IText text;
event WindowClosedEventHandler IWindow.Closed
{
add { throw new NotImplementedException(); }
remove { throw new NotImplementedException(); }
}
event WindowClosingEventHandler IWindow.Closing
{

View file

@ -19,10 +19,18 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
{
internal partial class LogWindow : Window, IWindow
{
private ILogger logger;
private LogViewModel model;
private readonly ILogger logger;
private readonly LogViewModel model;
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
@ -70,6 +78,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
private void InitializeLogWindow()
{
DataContext = model;
Closed += (o, args) => closed?.Invoke();
Closing += LogWindow_Closing;
Loaded += LogWindow_Loaded;
}

View file

@ -17,9 +17,17 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
{
internal partial class PasswordDialog : Window, IPasswordDialog
{
private IText text;
private readonly IText text;
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
@ -83,6 +91,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
ConfirmButton.Content = text.Get(TextKey.PasswordDialog_Confirm);
ConfirmButton.Click += ConfirmButton_Click;
Closed += (o, args) => closed?.Invoke();
Closing += (o, args) => closing?.Invoke();
Loaded += (o, args) => Activate();
Password.KeyUp += Password_KeyUp;

View file

@ -18,8 +18,15 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
{
public partial class ProctoringWindow : Window, IProctoringWindow
{
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
@ -99,6 +106,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
control.FullScreenChanged += Control_FullScreenChanged;
}
Closed += (o, args) => closed?.Invoke();
Closing += ProctoringWindow_Closing;
Loaded += ProctoringWindow_Loaded;
Top = SystemParameters.WorkArea.Height - Height - 15;

View file

@ -20,10 +20,13 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
{
internal partial class RuntimeWindow : Window, IRuntimeWindow
{
private readonly AppConfig appConfig;
private readonly IText text;
private bool allowClose;
private AppConfig appConfig;
private IText text;
private RuntimeWindowViewModel model;
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
public bool ShowLog
@ -48,6 +51,12 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
set => Dispatcher.Invoke(() => Topmost = value);
}
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
@ -74,6 +83,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
{
allowClose = true;
model.BusyIndication = false;
closing?.Invoke();
base.Close();
});
@ -145,6 +155,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
ProgressBar.DataContext = model;
StatusTextBlock.DataContext = model;
Closed += (o, args) => closed?.Invoke();
Closing += (o, args) => args.Cancel = !allowClose;
#if DEBUG

View file

@ -19,10 +19,13 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
{
internal partial class SplashScreen : Window, ISplashScreen
{
private readonly ProgressIndicatorViewModel model;
private readonly IText text;
private bool allowClose;
private ProgressIndicatorViewModel model = new ProgressIndicatorViewModel();
private AppConfig appConfig;
private IText text;
private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing;
public AppConfig AppConfig
@ -37,6 +40,12 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
}
}
event WindowClosedEventHandler IWindow.Closed
{
add { closed += value; }
remove { closed -= value; }
}
event WindowClosingEventHandler IWindow.Closing
{
add { closing += value; }
@ -46,6 +55,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
internal SplashScreen(IText text, AppConfig appConfig = null)
{
this.appConfig = appConfig;
this.model = new ProgressIndicatorViewModel();
this.text = text;
InitializeComponent();
@ -63,6 +73,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
{
allowClose = true;
model.BusyIndication = false;
closing?.Invoke();
base.Close();
});
@ -116,6 +127,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
StatusTextBlock.DataContext = model;
ProgressBar.DataContext = model;
Closed += (o, args) => closed?.Invoke();
Closing += (o, args) => args.Cancel = !allowClose;
}