diff --git a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs index 66700cd8..8aaf52f4 100644 --- a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs +++ b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs @@ -39,6 +39,7 @@ namespace SafeExamBrowser.Browser public IWindow Window { get { return window; } } public event DownloadRequestedEventHandler ConfigurationDownloadRequested; + public event IconChangedEventHandler IconChanged; public event InstanceTerminatedEventHandler Terminated; public event NameChangedEventHandler NameChanged; public event PopupRequestedEventHandler PopupRequested; @@ -66,17 +67,19 @@ namespace SafeExamBrowser.Browser internal void Initialize() { var contextMenuHandler = new ContextMenuHandler(settings, text); + var displayHandler = new DisplayHandler(); var downloadLogger = logger.CloneFor($"{nameof(DownloadHandler)} {Id}"); var downloadHandler = new DownloadHandler(appConfig, settings, downloadLogger); var keyboardHandler = new KeyboardHandler(); var lifeSpanHandler = new LifeSpanHandler(); var requestHandler = new RequestHandler(appConfig); + displayHandler.FaviconChanged += DisplayHandler_FaviconChanged; downloadHandler.ConfigurationDownloadRequested += DownloadHandler_ConfigurationDownloadRequested; keyboardHandler.ReloadRequested += KeyboardHandler_ReloadRequested; lifeSpanHandler.PopupRequested += LifeSpanHandler_PopupRequested; - control = new BrowserControl(contextMenuHandler, downloadHandler, keyboardHandler, lifeSpanHandler, requestHandler, settings.StartUrl); + control = new BrowserControl(contextMenuHandler, displayHandler, downloadHandler, keyboardHandler, lifeSpanHandler, requestHandler, settings.StartUrl); control.AddressChanged += Control_AddressChanged; control.LoadingStateChanged += Control_LoadingStateChanged; control.TitleChanged += Control_TitleChanged; @@ -139,6 +142,14 @@ namespace SafeExamBrowser.Browser NameChanged?.Invoke(title); } + private void DisplayHandler_FaviconChanged(string uri) + { + var icon = new BrowserIconResource(uri); + + IconChanged?.Invoke(icon); + window.UpdateIcon(icon); + } + private void DownloadHandler_ConfigurationDownloadRequested(string fileName, DownloadEventArgs args) { if (settings.AllowConfigurationDownloads) diff --git a/SafeExamBrowser.Browser/BrowserControl.cs b/SafeExamBrowser.Browser/BrowserControl.cs index 01f22a77..994ca66c 100644 --- a/SafeExamBrowser.Browser/BrowserControl.cs +++ b/SafeExamBrowser.Browser/BrowserControl.cs @@ -16,6 +16,7 @@ namespace SafeExamBrowser.Browser internal class BrowserControl : ChromiumWebBrowser, IBrowserControl { private IContextMenuHandler contextMenuHandler; + private IDisplayHandler displayHandler; private IDownloadHandler downloadHandler; private IKeyboardHandler keyboardHandler; private ILifeSpanHandler lifeSpanHandler; @@ -45,6 +46,7 @@ namespace SafeExamBrowser.Browser public BrowserControl( IContextMenuHandler contextMenuHandler, + IDisplayHandler displayHandler, IDownloadHandler downloadHandler, IKeyboardHandler keyboardHandler, ILifeSpanHandler lifeSpanHandler, @@ -52,6 +54,7 @@ namespace SafeExamBrowser.Browser string url) : base(url) { this.contextMenuHandler = contextMenuHandler; + this.displayHandler = displayHandler; this.downloadHandler = downloadHandler; this.keyboardHandler = keyboardHandler; this.lifeSpanHandler = lifeSpanHandler; @@ -64,6 +67,7 @@ namespace SafeExamBrowser.Browser LoadingStateChanged += (o, args) => loadingStateChanged?.Invoke(args.IsLoading); TitleChanged += (o, args) => titleChanged?.Invoke(args.Title); + DisplayHandler = displayHandler; DownloadHandler = downloadHandler; KeyboardHandler = keyboardHandler; LifeSpanHandler = lifeSpanHandler; diff --git a/SafeExamBrowser.Browser/BrowserIconResource.cs b/SafeExamBrowser.Browser/BrowserIconResource.cs index 651f057b..ebe15450 100644 --- a/SafeExamBrowser.Browser/BrowserIconResource.cs +++ b/SafeExamBrowser.Browser/BrowserIconResource.cs @@ -13,8 +13,13 @@ namespace SafeExamBrowser.Browser { public class BrowserIconResource : IIconResource { - public Uri Uri => new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/SafeExamBrowser.ico"); + public Uri Uri { get; private set; } public bool IsBitmapResource => true; public bool IsXamlResource => false; + + public BrowserIconResource(string uri = null) + { + Uri = new Uri(uri ?? "pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/SafeExamBrowser.ico"); + } } } diff --git a/SafeExamBrowser.Browser/Events/FaviconChangedEventHandler.cs b/SafeExamBrowser.Browser/Events/FaviconChangedEventHandler.cs new file mode 100644 index 00000000..f361a464 --- /dev/null +++ b/SafeExamBrowser.Browser/Events/FaviconChangedEventHandler.cs @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2019 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.Events +{ + internal delegate void FaviconChangedEventHandler(string uri); +} diff --git a/SafeExamBrowser.Browser/Handlers/DisplayHandler.cs b/SafeExamBrowser.Browser/Handlers/DisplayHandler.cs new file mode 100644 index 00000000..753f411f --- /dev/null +++ b/SafeExamBrowser.Browser/Handlers/DisplayHandler.cs @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 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.Linq; +using CefSharp; +using CefSharp.Structs; +using SafeExamBrowser.Browser.Events; + +namespace SafeExamBrowser.Browser.Handlers +{ + /// + /// See https://cefsharp.github.io/api/67.0.0/html/T_CefSharp_IDisplayHandler.htm. + /// + internal class DisplayHandler : IDisplayHandler + { + public event FaviconChangedEventHandler FaviconChanged; + + public void OnAddressChanged(IWebBrowser chromiumWebBrowser, AddressChangedEventArgs addressChangedArgs) + { + } + + public bool OnAutoResize(IWebBrowser chromiumWebBrowser, IBrowser browser, Size newSize) + { + return false; + } + + public bool OnConsoleMessage(IWebBrowser chromiumWebBrowser, ConsoleMessageEventArgs consoleMessageArgs) + { + return false; + } + + public void OnFaviconUrlChange(IWebBrowser chromiumWebBrowser, IBrowser browser, IList urls) + { + if (urls.Any()) + { + FaviconChanged?.Invoke(urls.First()); + } + } + + public void OnFullscreenModeChange(IWebBrowser chromiumWebBrowser, IBrowser browser, bool fullscreen) + { + } + + public void OnStatusMessage(IWebBrowser chromiumWebBrowser, StatusMessageEventArgs statusMessageArgs) + { + } + + public void OnTitleChanged(IWebBrowser chromiumWebBrowser, TitleChangedEventArgs titleChangedArgs) + { + } + + public bool OnTooltipChanged(IWebBrowser chromiumWebBrowser, ref string text) + { + return false; + } + } +} diff --git a/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj b/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj index 551b7436..8d509765 100644 --- a/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj +++ b/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj @@ -66,6 +66,7 @@ + @@ -74,6 +75,7 @@ Component + diff --git a/SafeExamBrowser.Contracts/Core/Events/IconChangedEventHandler.cs b/SafeExamBrowser.Contracts/Core/Events/IconChangedEventHandler.cs new file mode 100644 index 00000000..e4311c65 --- /dev/null +++ b/SafeExamBrowser.Contracts/Core/Events/IconChangedEventHandler.cs @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2019 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 SafeExamBrowser.Contracts.Configuration; + +namespace SafeExamBrowser.Contracts.Core.Events +{ + /// + /// Event handler used to indicate that the icon of an has changed. + /// + public delegate void IconChangedEventHandler(IIconResource icon); +} diff --git a/SafeExamBrowser.Contracts/Core/Events/InstanceTerminatedEventHandler.cs b/SafeExamBrowser.Contracts/Core/Events/InstanceTerminatedEventHandler.cs index 6899f664..71bd212a 100644 --- a/SafeExamBrowser.Contracts/Core/Events/InstanceTerminatedEventHandler.cs +++ b/SafeExamBrowser.Contracts/Core/Events/InstanceTerminatedEventHandler.cs @@ -6,7 +6,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - namespace SafeExamBrowser.Contracts.Core.Events { /// diff --git a/SafeExamBrowser.Contracts/Core/IApplicationInstance.cs b/SafeExamBrowser.Contracts/Core/IApplicationInstance.cs index 6ebbc4bb..3e1f676a 100644 --- a/SafeExamBrowser.Contracts/Core/IApplicationInstance.cs +++ b/SafeExamBrowser.Contracts/Core/IApplicationInstance.cs @@ -26,6 +26,11 @@ namespace SafeExamBrowser.Contracts.Core /// string Name { get; } + /// + /// Event fired when the icon of the application instance has changed. + /// + event IconChangedEventHandler IconChanged; + /// /// Event fired when the application instance has been terminated. /// diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj index a1c01d94..0e9831e3 100644 --- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj +++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj @@ -71,6 +71,7 @@ + diff --git a/SafeExamBrowser.Contracts/UserInterface/Browser/IBrowserWindow.cs b/SafeExamBrowser.Contracts/UserInterface/Browser/IBrowserWindow.cs index cea89a39..a155cc2b 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Browser/IBrowserWindow.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Browser/IBrowserWindow.cs @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.UserInterface.Browser.Events; using SafeExamBrowser.Contracts.UserInterface.Windows; @@ -46,6 +47,11 @@ namespace SafeExamBrowser.Contracts.UserInterface.Browser /// void UpdateAddress(string adress); + /// + /// Updates the icon of the browser window. + /// + void UpdateIcon(IIconResource icon); + /// /// Updates the loading state according to the given value. /// diff --git a/SafeExamBrowser.UserInterface.Desktop/BrowserWindow.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/BrowserWindow.xaml.cs index 14ed4800..4c3d211e 100644 --- a/SafeExamBrowser.UserInterface.Desktop/BrowserWindow.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/BrowserWindow.xaml.cs @@ -9,6 +9,8 @@ using System; using System.Windows; using System.Windows.Input; +using System.Windows.Media.Imaging; +using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Configuration.Settings; using SafeExamBrowser.Contracts.UserInterface.Browser; using SafeExamBrowser.Contracts.UserInterface.Browser.Events; @@ -89,6 +91,11 @@ namespace SafeExamBrowser.UserInterface.Desktop Dispatcher.Invoke(() => UrlTextBox.Text = url); } + public void UpdateIcon(IIconResource icon) + { + Dispatcher.BeginInvoke(new Action(() => Icon = new BitmapImage(icon.Uri))); + } + public void UpdateLoadingState(bool isLoading) { Dispatcher.Invoke(() => diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationInstanceButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationInstanceButton.xaml.cs index 125f5a5f..265adf14 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationInstanceButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationInstanceButton.xaml.cs @@ -6,10 +6,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System; using System.Windows; using System.Windows.Controls; -using SafeExamBrowser.Contracts.Core; using SafeExamBrowser.Contracts.Configuration; +using SafeExamBrowser.Contracts.Core; using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; using SafeExamBrowser.UserInterface.Desktop.Utilities; @@ -37,14 +38,22 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls Text.Text = instance.Name; Button.ToolTip = instance.Name; - instance.NameChanged += (name) => + instance.IconChanged += Instance_IconChanged; + instance.NameChanged += Instance_NameChanged; + } + + private void Instance_IconChanged(IIconResource icon) + { + Dispatcher.BeginInvoke(new Action(() => Icon.Content = IconResourceLoader.Load(icon))); + } + + private void Instance_NameChanged(string name) + { + Dispatcher.Invoke(() => { - Dispatcher.Invoke(() => - { - Text.Text = name; - Button.ToolTip = name; - }); - }; + Text.Text = name; + Button.ToolTip = name; + }); } private void Button_Click(object sender, RoutedEventArgs e)