From 4503cbe778c995e24033ef83789764a95af98d9e Mon Sep 17 00:00:00 2001 From: dbuechel Date: Thu, 28 Nov 2019 17:22:04 +0100 Subject: [PATCH] SEBWIN-312: Removed IApplicationInstance from API as it is irrelevant to the shell (which cares only about applications and their windows). --- .../Events/IconChangedEventHandler.cs | 2 +- ...Handler.cs => TitleChangedEventHandler.cs} | 4 +- ...ndler.cs => WindowsChangedEventHandler.cs} | 4 +- .../IApplication.cs | 10 ++- .../IApplicationInstance.cs | 64 ---------------- .../IApplicationWindow.cs | 44 +++++++++++ ...eExamBrowser.Applications.Contracts.csproj | 7 +- .../ExternalApplication.cs | 14 ++-- .../ExternalApplicationInstance.cs | 75 +++---------------- SafeExamBrowser.Browser/BrowserApplication.cs | 10 ++- .../BrowserApplicationInstance.cs | 36 ++++----- .../Events/InstanceTerminatedEventHandler.cs | 9 +-- .../SafeExamBrowser.Browser.csproj | 1 + .../ActionCenterApplicationButton.xaml.cs | 24 +++--- .../ActionCenterApplicationControl.xaml | 2 +- .../ActionCenterApplicationControl.xaml.cs | 48 ++++++------ ...ontrol.xaml => TaskViewWindowControl.xaml} | 2 +- ....xaml.cs => TaskViewWindowControl.xaml.cs} | 26 +++---- .../Controls/TaskbarApplicationControl.xaml | 6 +- .../TaskbarApplicationControl.xaml.cs | 68 ++++++++--------- ...ml => TaskbarApplicationWindowButton.xaml} | 2 +- ...=> TaskbarApplicationWindowButton.xaml.cs} | 30 ++++---- ...feExamBrowser.UserInterface.Desktop.csproj | 12 +-- .../TaskView.xaml.cs | 65 +++++++--------- .../ActionCenterApplicationButton.xaml.cs | 24 +++--- .../ActionCenterApplicationControl.xaml | 2 +- .../ActionCenterApplicationControl.xaml.cs | 48 ++++++------ ...ontrol.xaml => TaskViewWindowControl.xaml} | 2 +- ....xaml.cs => TaskViewWindowControl.xaml.cs} | 26 +++---- .../Controls/TaskbarApplicationControl.xaml | 6 +- .../TaskbarApplicationControl.xaml.cs | 68 ++++++++--------- ...ml => TaskbarApplicationWindowButton.xaml} | 2 +- ...=> TaskbarApplicationWindowButton.xaml.cs} | 30 ++++---- ...afeExamBrowser.UserInterface.Mobile.csproj | 12 +-- .../TaskView.xaml.cs | 65 +++++++--------- .../IProcess.cs | 12 --- 36 files changed, 374 insertions(+), 488 deletions(-) rename SafeExamBrowser.Applications.Contracts/Events/{InstanceStartedEventHandler.cs => TitleChangedEventHandler.cs} (68%) rename SafeExamBrowser.Applications.Contracts/Events/{NameChangedEventHandler.cs => WindowsChangedEventHandler.cs} (73%) delete mode 100644 SafeExamBrowser.Applications.Contracts/IApplicationInstance.cs create mode 100644 SafeExamBrowser.Applications.Contracts/IApplicationWindow.cs rename {SafeExamBrowser.Applications.Contracts => SafeExamBrowser.Browser}/Events/InstanceTerminatedEventHandler.cs (50%) rename SafeExamBrowser.UserInterface.Desktop/Controls/{TaskViewInstanceControl.xaml => TaskViewWindowControl.xaml} (97%) rename SafeExamBrowser.UserInterface.Desktop/Controls/{TaskViewInstanceControl.xaml.cs => TaskViewWindowControl.xaml.cs} (66%) rename SafeExamBrowser.UserInterface.Desktop/Controls/{TaskbarApplicationInstanceButton.xaml => TaskbarApplicationWindowButton.xaml} (97%) rename SafeExamBrowser.UserInterface.Desktop/Controls/{TaskbarApplicationInstanceButton.xaml.cs => TaskbarApplicationWindowButton.xaml.cs} (59%) rename SafeExamBrowser.UserInterface.Mobile/Controls/{TaskViewInstanceControl.xaml => TaskViewWindowControl.xaml} (97%) rename SafeExamBrowser.UserInterface.Mobile/Controls/{TaskViewInstanceControl.xaml.cs => TaskViewWindowControl.xaml.cs} (66%) rename SafeExamBrowser.UserInterface.Mobile/Controls/{TaskbarApplicationInstanceButton.xaml => TaskbarApplicationWindowButton.xaml} (97%) rename SafeExamBrowser.UserInterface.Mobile/Controls/{TaskbarApplicationInstanceButton.xaml.cs => TaskbarApplicationWindowButton.xaml.cs} (59%) diff --git a/SafeExamBrowser.Applications.Contracts/Events/IconChangedEventHandler.cs b/SafeExamBrowser.Applications.Contracts/Events/IconChangedEventHandler.cs index 93c764bc..71adaf49 100644 --- a/SafeExamBrowser.Applications.Contracts/Events/IconChangedEventHandler.cs +++ b/SafeExamBrowser.Applications.Contracts/Events/IconChangedEventHandler.cs @@ -11,7 +11,7 @@ using SafeExamBrowser.Core.Contracts; namespace SafeExamBrowser.Applications.Contracts.Events { /// - /// Event handler used to indicate that the icon of an has changed. + /// Event handler used to indicate that an icon has changed. /// public delegate void IconChangedEventHandler(IconResource icon); } diff --git a/SafeExamBrowser.Applications.Contracts/Events/InstanceStartedEventHandler.cs b/SafeExamBrowser.Applications.Contracts/Events/TitleChangedEventHandler.cs similarity index 68% rename from SafeExamBrowser.Applications.Contracts/Events/InstanceStartedEventHandler.cs rename to SafeExamBrowser.Applications.Contracts/Events/TitleChangedEventHandler.cs index c9e65009..4c2e162e 100644 --- a/SafeExamBrowser.Applications.Contracts/Events/InstanceStartedEventHandler.cs +++ b/SafeExamBrowser.Applications.Contracts/Events/TitleChangedEventHandler.cs @@ -9,7 +9,7 @@ namespace SafeExamBrowser.Applications.Contracts.Events { /// - /// Event handler used to inform about the existence of a new . + /// Event handler used to indicate that a title has changed to a new value. /// - public delegate void InstanceStartedEventHandler(IApplicationInstance instance); + public delegate void TitleChangedEventHandler(string title); } diff --git a/SafeExamBrowser.Applications.Contracts/Events/NameChangedEventHandler.cs b/SafeExamBrowser.Applications.Contracts/Events/WindowsChangedEventHandler.cs similarity index 73% rename from SafeExamBrowser.Applications.Contracts/Events/NameChangedEventHandler.cs rename to SafeExamBrowser.Applications.Contracts/Events/WindowsChangedEventHandler.cs index 3d51804b..ac1e6ad9 100644 --- a/SafeExamBrowser.Applications.Contracts/Events/NameChangedEventHandler.cs +++ b/SafeExamBrowser.Applications.Contracts/Events/WindowsChangedEventHandler.cs @@ -9,7 +9,7 @@ namespace SafeExamBrowser.Applications.Contracts.Events { /// - /// Event handler used to indicate that a name has changed to a new value. + /// Event handler used to indicate that the windows of an application have changed. /// - public delegate void NameChangedEventHandler(string name); + public delegate void WindowsChangedEventHandler(); } diff --git a/SafeExamBrowser.Applications.Contracts/IApplication.cs b/SafeExamBrowser.Applications.Contracts/IApplication.cs index c75b4908..28f8def2 100644 --- a/SafeExamBrowser.Applications.Contracts/IApplication.cs +++ b/SafeExamBrowser.Applications.Contracts/IApplication.cs @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System.Collections.Generic; using SafeExamBrowser.Applications.Contracts.Events; namespace SafeExamBrowser.Applications.Contracts @@ -21,9 +22,14 @@ namespace SafeExamBrowser.Applications.Contracts ApplicationInfo Info { get; } /// - /// Fired when a new has started. + /// Event fired when the windows of the application have changed. /// - event InstanceStartedEventHandler InstanceStarted; + event WindowsChangedEventHandler WindowsChanged; + + /// + /// Returns all windows of the application. + /// + IEnumerable GetWindows(); /// /// Performs any initialization work, if necessary. diff --git a/SafeExamBrowser.Applications.Contracts/IApplicationInstance.cs b/SafeExamBrowser.Applications.Contracts/IApplicationInstance.cs deleted file mode 100644 index c92fcab0..00000000 --- a/SafeExamBrowser.Applications.Contracts/IApplicationInstance.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.Applications.Contracts.Events; -using SafeExamBrowser.Core.Contracts; - -namespace SafeExamBrowser.Applications.Contracts -{ - /// - /// Defines an instance of an application which can be accessed via the shell. - /// - public interface IApplicationInstance - { - /// - /// The icon resource for this instance. - /// - IconResource Icon { get; } - - /// - /// The unique identifier for the application instance. - /// - InstanceIdentifier Id { get; } - - /// - /// The name or document title of the application instance. - /// - string Name { get; } - - /// - /// Event fired when the icon of the application instance has changed. - /// - event IconChangedEventHandler IconChanged; - - /// - /// Event fired when the name or (document) title of the application instance has changed. - /// - event NameChangedEventHandler NameChanged; - - /// - /// Event fired when the application instance has been terminated. - /// - event InstanceTerminatedEventHandler Terminated; - - /// - /// Makes this instance the currently active one and brings it to the foreground. - /// - void Activate(); - - /// - /// Initializes the application instance. - /// - void Initialize(); - - /// - /// Terminates the application instance. - /// - void Terminate(); - } -} diff --git a/SafeExamBrowser.Applications.Contracts/IApplicationWindow.cs b/SafeExamBrowser.Applications.Contracts/IApplicationWindow.cs new file mode 100644 index 00000000..24a8e7ca --- /dev/null +++ b/SafeExamBrowser.Applications.Contracts/IApplicationWindow.cs @@ -0,0 +1,44 @@ +/* + * 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.Applications.Contracts.Events; +using SafeExamBrowser.Core.Contracts; + +namespace SafeExamBrowser.Applications.Contracts +{ + /// + /// Defines a window of an . + /// + public interface IApplicationWindow + { + /// + /// The icon of the window. + /// + IconResource Icon { get; } + + /// + /// The title of the window. + /// + string Title { get; } + + /// + /// Event fired when the icon of the window has changed. + /// + event IconChangedEventHandler IconChanged; + + /// + /// Event fired when the title of the window has changed. + /// + event TitleChangedEventHandler TitleChanged; + + /// + /// Brings the window to the foreground and activates it. + /// + void Activate(); + } +} diff --git a/SafeExamBrowser.Applications.Contracts/SafeExamBrowser.Applications.Contracts.csproj b/SafeExamBrowser.Applications.Contracts/SafeExamBrowser.Applications.Contracts.csproj index 69812b8b..add43a26 100644 --- a/SafeExamBrowser.Applications.Contracts/SafeExamBrowser.Applications.Contracts.csproj +++ b/SafeExamBrowser.Applications.Contracts/SafeExamBrowser.Applications.Contracts.csproj @@ -55,14 +55,13 @@ - - - + + - + diff --git a/SafeExamBrowser.Applications/ExternalApplication.cs b/SafeExamBrowser.Applications/ExternalApplication.cs index b9f845b1..df8985a0 100644 --- a/SafeExamBrowser.Applications/ExternalApplication.cs +++ b/SafeExamBrowser.Applications/ExternalApplication.cs @@ -20,22 +20,27 @@ namespace SafeExamBrowser.Applications { private string executablePath; private IModuleLogger logger; - private IList instances; + private IList instances; private IProcessFactory processFactory; - public ApplicationInfo Info { get; } + public event WindowsChangedEventHandler WindowsChanged; - public event InstanceStartedEventHandler InstanceStarted; + public ApplicationInfo Info { get; } internal ExternalApplication(string executablePath, ApplicationInfo info, IModuleLogger logger, IProcessFactory processFactory) { this.executablePath = executablePath; this.Info = info; this.logger = logger; - this.instances = new List(); + this.instances = new List(); this.processFactory = processFactory; } + public IEnumerable GetWindows() + { + return Enumerable.Empty(); + } + public void Initialize() { // Nothing to do here for now. @@ -53,7 +58,6 @@ namespace SafeExamBrowser.Applications instance.Initialize(); instances.Add(instance); - InstanceStarted?.Invoke(instance); } catch (Exception e) { diff --git a/SafeExamBrowser.Applications/ExternalApplicationInstance.cs b/SafeExamBrowser.Applications/ExternalApplicationInstance.cs index 0ab3724f..90241a86 100644 --- a/SafeExamBrowser.Applications/ExternalApplicationInstance.cs +++ b/SafeExamBrowser.Applications/ExternalApplicationInstance.cs @@ -6,57 +6,34 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System; -using System.Timers; using SafeExamBrowser.Applications.Contracts; -using SafeExamBrowser.Applications.Contracts.Events; using SafeExamBrowser.Core.Contracts; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.WindowsApi.Contracts; namespace SafeExamBrowser.Applications { - internal class ExternalApplicationInstance : IApplicationInstance + internal class ExternalApplicationInstance { - private const int ONE_SECOND = 1000; - + private IconResource icon; + private InstanceIdentifier id; private ILogger logger; private IProcess process; - private Timer timer; - public IconResource Icon { get; } - public InstanceIdentifier Id { get; } - public string Name { get; private set; } - - public event IconChangedEventHandler IconChanged { add { } remove { } } - public event NameChangedEventHandler NameChanged; - public event InstanceTerminatedEventHandler Terminated; - - public ExternalApplicationInstance(IconResource icon, InstanceIdentifier id, ILogger logger, IProcess process) + internal ExternalApplicationInstance(IconResource icon, InstanceIdentifier id, ILogger logger, IProcess process) { - this.Icon = icon; - this.Id = id; + this.icon = icon; + this.id = id; this.logger = logger; this.process = process; } - public void Activate() + internal void Initialize() { - var success = process.TryActivate(); - - if (!success) - { - logger.Warn("Failed to activate instance!"); - } + process.Terminated += Process_Terminated; } - public void Initialize() - { - InitializeEvents(); - logger.Info("Initialized application instance."); - } - - public void Terminate() + internal void Terminate() { const int MAX_ATTEMPTS = 5; const int TIMEOUT_MS = 500; @@ -65,7 +42,7 @@ namespace SafeExamBrowser.Applications if (!terminated) { - FinalizeEvents(); + process.Terminated -= Process_Terminated; for (var attempt = 0; attempt < MAX_ATTEMPTS && !terminated; attempt++) { @@ -91,37 +68,7 @@ namespace SafeExamBrowser.Applications private void Process_Terminated(int exitCode) { logger.Info($"Application instance has terminated with exit code {exitCode}."); - FinalizeEvents(); - Terminated?.Invoke(Id); - } - - private void InitializeEvents() - { - timer = new Timer(ONE_SECOND); - timer.Elapsed += Timer_Elapsed; - timer.Start(); - process.Terminated += Process_Terminated; - } - - private void FinalizeEvents() - { - timer.Elapsed -= Timer_Elapsed; - timer.Stop(); - process.Terminated -= Process_Terminated; - } - - private void Timer_Elapsed(object sender, ElapsedEventArgs e) - { - var success = process.TryGetWindowTitle(out var title); - var hasChanged = Name?.Equals(title, StringComparison.Ordinal) != true; - - if (success && hasChanged) - { - Name = title; - NameChanged?.Invoke(Name); - } - - timer.Start(); + // TODO: Terminated?.Invoke(Id); -> Remove from application! } } } diff --git a/SafeExamBrowser.Browser/BrowserApplication.cs b/SafeExamBrowser.Browser/BrowserApplication.cs index 0ccd5098..d2c57e2b 100644 --- a/SafeExamBrowser.Browser/BrowserApplication.cs +++ b/SafeExamBrowser.Browser/BrowserApplication.cs @@ -41,7 +41,7 @@ namespace SafeExamBrowser.Browser public ApplicationInfo Info { get; private set; } public event DownloadRequestedEventHandler ConfigurationDownloadRequested; - public event InstanceStartedEventHandler InstanceStarted; + public event WindowsChangedEventHandler WindowsChanged; public BrowserApplication( AppConfig appConfig, @@ -60,6 +60,11 @@ namespace SafeExamBrowser.Browser this.uiFactory = uiFactory; } + public IEnumerable GetWindows() + { + return new List(instances); + } + public void Initialize() { var cefSettings = InitializeCefSettings(); @@ -119,9 +124,9 @@ namespace SafeExamBrowser.Browser instance.Initialize(); instances.Add(instance); - InstanceStarted?.Invoke(instance); logger.Info($"Created browser instance {instance.Id}."); + WindowsChanged?.Invoke(); } private CefSettings InitializeCefSettings() @@ -156,6 +161,7 @@ namespace SafeExamBrowser.Browser { instances.Remove(instances.FirstOrDefault(i => i.Id == id)); logger.Info($"Browser instance {id} was terminated."); + WindowsChanged?.Invoke(); } /// diff --git a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs index b88f544f..9a01d5b7 100644 --- a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs +++ b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs @@ -27,7 +27,7 @@ using SafeExamBrowser.UserInterface.Contracts.MessageBox; namespace SafeExamBrowser.Browser { - internal class BrowserApplicationInstance : IApplicationInstance + internal class BrowserApplicationInstance : IApplicationWindow { private const double ZOOM_FACTOR = 0.2; @@ -49,20 +49,22 @@ namespace SafeExamBrowser.Browser get { return isMainInstance ? settings.MainWindow : settings.AdditionalWindow; } } - public IconResource Icon { get; private set; } - public InstanceIdentifier Id { get; private set; } - public string Name { get; private set; } + internal BrowserInstanceIdentifier Id { get; private set; } + + public IconResource Icon { get; private set; } + public string Title { get; private set; } + + internal event DownloadRequestedEventHandler ConfigurationDownloadRequested; + internal event PopupRequestedEventHandler PopupRequested; + internal event InstanceTerminatedEventHandler Terminated; - public event DownloadRequestedEventHandler ConfigurationDownloadRequested; public event IconChangedEventHandler IconChanged; - public event NameChangedEventHandler NameChanged; - public event PopupRequestedEventHandler PopupRequested; - public event InstanceTerminatedEventHandler Terminated; + public event TitleChangedEventHandler TitleChanged; public BrowserApplicationInstance( AppConfig appConfig, BrowserSettings settings, - InstanceIdentifier id, + BrowserInstanceIdentifier id, bool isMainInstance, IMessageBox messageBox, IModuleLogger logger, @@ -84,18 +86,18 @@ namespace SafeExamBrowser.Browser public void Activate() { - window?.BringToForeground(); + window.BringToForeground(); } - public void Initialize() + internal void Initialize() { InitializeControl(); InitializeWindow(); } - public void Terminate() + internal void Terminate() { - window?.Close(); + window.Close(); } private void InitializeControl() @@ -194,9 +196,9 @@ namespace SafeExamBrowser.Browser private void Control_TitleChanged(string title) { - Name = title; - window.UpdateTitle(Name); - NameChanged?.Invoke(Name); + Title = title; + window.UpdateTitle(Title); + TitleChanged?.Invoke(Title); } private void DisplayHandler_FaviconChanged(string uri) @@ -267,7 +269,7 @@ namespace SafeExamBrowser.Browser if (url == this.url) { window.UpdateTitle($"*** {title} ***"); - NameChanged?.Invoke($"*** {title} ***"); + TitleChanged?.Invoke($"*** {title} ***"); } messageBox.Show(message, title, parent: window); diff --git a/SafeExamBrowser.Applications.Contracts/Events/InstanceTerminatedEventHandler.cs b/SafeExamBrowser.Browser/Events/InstanceTerminatedEventHandler.cs similarity index 50% rename from SafeExamBrowser.Applications.Contracts/Events/InstanceTerminatedEventHandler.cs rename to SafeExamBrowser.Browser/Events/InstanceTerminatedEventHandler.cs index c108238c..afbc35e6 100644 --- a/SafeExamBrowser.Applications.Contracts/Events/InstanceTerminatedEventHandler.cs +++ b/SafeExamBrowser.Browser/Events/InstanceTerminatedEventHandler.cs @@ -6,12 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Core.Contracts; - -namespace SafeExamBrowser.Applications.Contracts.Events +namespace SafeExamBrowser.Browser.Events { - /// - /// Event handler used to indicate that an has terminated. - /// - public delegate void InstanceTerminatedEventHandler(InstanceIdentifier id); + internal delegate void InstanceTerminatedEventHandler(BrowserInstanceIdentifier id); } diff --git a/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj b/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj index 10a93b10..943d6f1d 100644 --- a/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj +++ b/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj @@ -65,6 +65,7 @@ + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationButton.xaml.cs index 1ae6d8a3..04a03b32 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationButton.xaml.cs @@ -17,14 +17,14 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls public partial class ActionCenterApplicationButton : UserControl { private ApplicationInfo info; - private IApplicationInstance instance; + private IApplicationWindow window; internal event EventHandler Clicked; - public ActionCenterApplicationButton(ApplicationInfo info, IApplicationInstance instance = null) + public ActionCenterApplicationButton(ApplicationInfo info, IApplicationWindow window = null) { this.info = info; - this.instance = instance; + this.window = window; InitializeComponent(); InitializeApplicationInstanceButton(); @@ -33,28 +33,28 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls private void InitializeApplicationInstanceButton() { Icon.Content = IconResourceLoader.Load(info.Icon); - Text.Text = instance?.Name ?? info.Name; + Text.Text = window?.Title ?? info.Name; Button.Click += (o, args) => Clicked?.Invoke(this, EventArgs.Empty); - Button.ToolTip = instance?.Name ?? info.Tooltip; + Button.ToolTip = window?.Title ?? info.Tooltip; - if (instance != null) + if (window != null) { - instance.IconChanged += Instance_IconChanged; - instance.NameChanged += Instance_NameChanged; + window.IconChanged += Window_IconChanged; + window.TitleChanged += Window_TitleChanged; } } - private void Instance_IconChanged(IconResource icon) + private void Window_IconChanged(IconResource icon) { Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(icon)); } - private void Instance_NameChanged(string name) + private void Window_TitleChanged(string title) { Dispatcher.InvokeAsync(() => { - Text.Text = name; - Button.ToolTip = name; + Text.Text = title; + Button.ToolTip = title; }); } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml index c0fefed6..a6d057f6 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml @@ -22,6 +22,6 @@ - + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml.cs index 327e0c7c..d289ef42 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml.cs @@ -29,40 +29,42 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls { var button = new ActionCenterApplicationButton(application.Info); - application.InstanceStarted += Application_InstanceStarted; + application.WindowsChanged += Application_WindowsChanged; button.Clicked += (o, args) => application.Start(); ApplicationName.Text = application.Info.Name; ApplicationName.Visibility = Visibility.Collapsed; ApplicationButton.Content = button; } - private void Application_InstanceStarted(IApplicationInstance instance) + private void Application_WindowsChanged() { - Dispatcher.InvokeAsync(() => - { - var button = new ActionCenterApplicationButton(application.Info, instance); - - button.Clicked += (o, args) => instance.Activate(); - instance.Terminated += (_) => RemoveInstance(button); - InstancePanel.Children.Add(button); - - ApplicationName.Visibility = Visibility.Visible; - ApplicationButton.Visibility = Visibility.Collapsed; - }); + Dispatcher.InvokeAsync(Update); } - private void RemoveInstance(ActionCenterApplicationButton button) + private void Update() { - Dispatcher.InvokeAsync(() => - { - InstancePanel.Children.Remove(button); + var windows = application.GetWindows(); - if (InstancePanel.Children.Count == 0) - { - ApplicationName.Visibility = Visibility.Collapsed; - ApplicationButton.Visibility = Visibility.Visible; - } - }); + WindowPanel.Children.Clear(); + + foreach (var window in windows) + { + var button = new ActionCenterApplicationButton(application.Info, window); + + button.Clicked += (o, args) => window.Activate(); + WindowPanel.Children.Add(button); + } + + if (WindowPanel.Children.Count == 0) + { + ApplicationName.Visibility = Visibility.Collapsed; + ApplicationButton.Visibility = Visibility.Visible; + } + else + { + ApplicationName.Visibility = Visibility.Visible; + ApplicationButton.Visibility = Visibility.Collapsed; + } } } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewWindowControl.xaml similarity index 97% rename from SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml rename to SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewWindowControl.xaml index ebccd149..1c5353f3 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewWindowControl.xaml @@ -1,4 +1,4 @@ - instance.Id; - - public TaskViewInstanceControl(IApplicationInstance instance) + public TaskViewWindowControl(IApplicationWindow window) { - this.instance = instance; + this.window = window; InitializeComponent(); InitializeControl(); @@ -30,7 +28,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls internal void Activate() { - instance.Activate(); + window.Activate(); } internal void Deselect() @@ -49,21 +47,21 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls private void InitializeControl() { - Icon.Content = IconResourceLoader.Load(instance.Icon); - Title.Text = instance.Name; + Icon.Content = IconResourceLoader.Load(window.Icon); + Title.Text = window.Title; - instance.IconChanged += Instance_IconChanged; - instance.NameChanged += Instance_NameChanged; + window.IconChanged += Instance_IconChanged; + window.TitleChanged += Instance_TitleChanged; } - private void Instance_NameChanged(string name) + private void Instance_TitleChanged(string title) { - Dispatcher.InvokeAsync(() => Title.Text = name); + Dispatcher.InvokeAsync(() => Title.Text = title); } private void Instance_IconChanged(IconResource icon) { - Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(instance.Icon)); + Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(window.Icon)); } } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationControl.xaml index d7148826..25999907 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationControl.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationControl.xaml @@ -16,10 +16,10 @@ - + - - + + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationControl.xaml.cs index 9eb37158..18434b5c 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationControl.xaml.cs @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; @@ -20,7 +21,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls public partial class TaskbarApplicationControl : UserControl, IApplicationControl { private IApplication application; - private IApplicationInstance single; + private IApplicationWindow single; public TaskbarApplicationControl(IApplication application) { @@ -34,71 +35,64 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls { var originalBrush = Button.Background; - application.InstanceStarted += Application_InstanceStarted; + application.WindowsChanged += Application_WindowsChanged; Button.Click += Button_Click; Button.Content = IconResourceLoader.Load(application.Info.Icon); - Button.MouseEnter += (o, args) => InstancePopup.IsOpen = InstanceStackPanel.Children.Count > 1; - Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => InstancePopup.IsOpen = InstancePopup.IsMouseOver)); + Button.MouseEnter += (o, args) => WindowPopup.IsOpen = WindowStackPanel.Children.Count > 0; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => WindowPopup.IsOpen = WindowPopup.IsMouseOver)); Button.ToolTip = application.Info.Tooltip; - InstancePopup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => InstancePopup.IsOpen = IsMouseOver)); + WindowPopup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => WindowPopup.IsOpen = IsMouseOver)); - InstancePopup.Opened += (o, args) => + WindowPopup.Opened += (o, args) => { Background = Brushes.LightGray; Button.Background = Brushes.LightGray; }; - InstancePopup.Closed += (o, args) => + WindowPopup.Closed += (o, args) => { Background = originalBrush; Button.Background = originalBrush; }; } - private void Application_InstanceStarted(IApplicationInstance instance) + private void Application_WindowsChanged() { - Dispatcher.Invoke(() => - { - var button = new TaskbarApplicationInstanceButton(instance, application.Info); - - instance.Terminated += (_) => RemoveInstance(button); - InstanceStackPanel.Children.Add(button); - - if (single == default(IApplicationInstance)) - { - single = instance; - } - }); + Dispatcher.InvokeAsync(Update); } private void Button_Click(object sender, RoutedEventArgs e) { - if (InstanceStackPanel.Children.Count == 0) + if (WindowStackPanel.Children.Count == 0) { application.Start(); } - else if (InstanceStackPanel.Children.Count == 1) + else if (WindowStackPanel.Children.Count == 1) { - single.Activate(); + single?.Activate(); + } + } + + private void Update() + { + var windows = application.GetWindows(); + + WindowStackPanel.Children.Clear(); + + foreach (var window in windows) + { + WindowStackPanel.Children.Add(new TaskbarApplicationWindowButton(window)); + } + + if (WindowStackPanel.Children.Count == 1) + { + single = windows.First(); } else { - InstancePopup.IsOpen = true; + single = default(IApplicationWindow); } } - - private void RemoveInstance(TaskbarApplicationInstanceButton button) - { - Dispatcher.InvokeAsync(() => - { - InstanceStackPanel.Children.Remove(button); - - if (InstanceStackPanel.Children.Count == 0) - { - single = default(IApplicationInstance); - } - }); - } } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationInstanceButton.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationWindowButton.xaml similarity index 97% rename from SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationInstanceButton.xaml rename to SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationWindowButton.xaml index 9a2a8090..666ebaa7 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationInstanceButton.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationWindowButton.xaml @@ -1,4 +1,4 @@ - Icon.Content = IconResourceLoader.Load(icon)); } - private void Instance_NameChanged(string name) + private void Window_TitleChanged(string title) { - Dispatcher.Invoke(() => + Dispatcher.InvokeAsync(() => { - Text.Text = name; - Button.ToolTip = name; + Text.Text = title; + Button.ToolTip = title; }); } } diff --git a/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj b/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj index 3675db98..e8a13618 100644 --- a/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj +++ b/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj @@ -112,8 +112,8 @@ TaskbarApplicationControl.xaml - - TaskbarApplicationInstanceButton.xaml + + TaskbarApplicationWindowButton.xaml TaskbarAudioControl.xaml @@ -142,8 +142,8 @@ TaskbarWirelessNetworkControl.xaml - - TaskViewInstanceControl.xaml + + TaskViewWindowControl.xaml LockScreen.xaml @@ -229,7 +229,7 @@ Designer MSBuild:Compile - + Designer MSBuild:Compile @@ -317,7 +317,7 @@ MSBuild:Compile Designer - + Designer MSBuild:Compile diff --git a/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml.cs index 807cf362..1e3ad581 100644 --- a/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml.cs @@ -19,21 +19,22 @@ namespace SafeExamBrowser.UserInterface.Desktop { public partial class TaskView : Window, ITaskView { - private LinkedListNode current; - private LinkedList controls; - private List instances; + private IList applications; + private LinkedListNode current; + private LinkedList controls; public TaskView() { - controls = new LinkedList(); - instances = new List(); + applications = new List(); + controls = new LinkedList(); InitializeComponent(); } public void Add(IApplication application) { - application.InstanceStarted += Application_InstanceStarted; + application.WindowsChanged += Application_WindowsChanged; + applications.Add(application); } public void Register(ITaskViewActivator activator) @@ -43,9 +44,9 @@ namespace SafeExamBrowser.UserInterface.Desktop activator.PreviousActivated += Activator_Previous; } - private void Application_InstanceStarted(IApplicationInstance instance) + private void Application_WindowsChanged() { - Dispatcher.InvokeAsync(() => Add(instance)); + Dispatcher.InvokeAsync(Update); } private void Activator_Deactivated() @@ -63,11 +64,6 @@ namespace SafeExamBrowser.UserInterface.Desktop Dispatcher.InvokeAsync(SelectPrevious); } - private void Instance_Terminated(InstanceIdentifier id) - { - Dispatcher.InvokeAsync(() => Remove(id)); - } - private void ActivateAndHide() { Activate(); @@ -75,24 +71,6 @@ namespace SafeExamBrowser.UserInterface.Desktop Hide(); } - private void Add(IApplicationInstance instance) - { - instance.Terminated += Instance_Terminated; - instances.Add(instance); - Update(); - } - - private void Remove(InstanceIdentifier id) - { - var instance = instances.FirstOrDefault(i => i.Id == id); - - if (instance != default(IApplicationInstance)) - { - instances.Remove(instance); - Update(); - } - } - private void SelectNext() { ShowConditional(); @@ -119,7 +97,7 @@ namespace SafeExamBrowser.UserInterface.Desktop private void ShowConditional() { - if (instances.Any() && Visibility != Visibility.Visible) + if (controls.Any() && Visibility != Visibility.Visible) { Show(); Activate(); @@ -128,22 +106,31 @@ namespace SafeExamBrowser.UserInterface.Desktop private void Update() { - var max = Math.Ceiling(Math.Sqrt(instances.Count)); - var stack = new Stack(instances); + var windows = new Stack(); + + foreach (var application in applications) + { + foreach (var window in application.GetWindows()) + { + windows.Push(window); + } + } + + var max = Math.Ceiling(Math.Sqrt(windows.Count)); controls.Clear(); Rows.Children.Clear(); - for (var rowCount = 0; rowCount < max && stack.Any(); rowCount++) + for (var rowCount = 0; rowCount < max && windows.Any(); rowCount++) { var row = new StackPanel { Orientation = Orientation.Horizontal, HorizontalAlignment = HorizontalAlignment.Center }; Rows.Children.Add(row); - for (var columnIndex = 0; columnIndex < max && stack.Any(); columnIndex++) + for (var columnIndex = 0; columnIndex < max && windows.Any(); columnIndex++) { - var instance = stack.Pop(); - var control = new TaskViewInstanceControl(instance); + var window = windows.Pop(); + var control = new TaskViewWindowControl(window); controls.AddLast(control); row.Children.Add(control); @@ -158,7 +145,7 @@ namespace SafeExamBrowser.UserInterface.Desktop Left = (SystemParameters.WorkArea.Width - Width) / 2 + SystemParameters.WorkArea.Left; Top = (SystemParameters.WorkArea.Height - Height) / 2 + SystemParameters.WorkArea.Top; - if (!instances.Any()) + if (!windows.Any()) { Hide(); } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationButton.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationButton.xaml.cs index ec29ac3c..b60c51f8 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationButton.xaml.cs @@ -17,14 +17,14 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls public partial class ActionCenterApplicationButton : UserControl { private ApplicationInfo info; - private IApplicationInstance instance; + private IApplicationWindow window; internal event EventHandler Clicked; - public ActionCenterApplicationButton(ApplicationInfo info, IApplicationInstance instance = null) + public ActionCenterApplicationButton(ApplicationInfo info, IApplicationWindow window = null) { this.info = info; - this.instance = instance; + this.window = window; InitializeComponent(); InitializeApplicationInstanceButton(); @@ -33,28 +33,28 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls private void InitializeApplicationInstanceButton() { Icon.Content = IconResourceLoader.Load(info.Icon); - Text.Text = instance?.Name ?? info.Name; + Text.Text = window?.Title ?? info.Name; Button.Click += (o, args) => Clicked?.Invoke(this, EventArgs.Empty); - Button.ToolTip = instance?.Name ?? info.Tooltip; + Button.ToolTip = window?.Title ?? info.Tooltip; - if (instance != null) + if (window != null) { - instance.IconChanged += Instance_IconChanged; - instance.NameChanged += Instance_NameChanged; + window.IconChanged += Window_IconChanged; + window.TitleChanged += Window_TitleChanged; } } - private void Instance_IconChanged(IconResource icon) + private void Window_IconChanged(IconResource icon) { Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(icon)); } - private void Instance_NameChanged(string name) + private void Window_TitleChanged(string title) { Dispatcher.InvokeAsync(() => { - Text.Text = name; - Button.ToolTip = name; + Text.Text = title; + Button.ToolTip = title; }); } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationControl.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationControl.xaml index 1172d550..3e574918 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationControl.xaml +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationControl.xaml @@ -22,6 +22,6 @@ - + diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationControl.xaml.cs index 00f4e823..3f8ad7aa 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationControl.xaml.cs @@ -29,40 +29,42 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls { var button = new ActionCenterApplicationButton(application.Info); - application.InstanceStarted += Application_InstanceStarted; + application.WindowsChanged += Application_WindowsChanged; button.Clicked += (o, args) => application.Start(); ApplicationName.Text = application.Info.Name; ApplicationName.Visibility = Visibility.Collapsed; ApplicationButton.Content = button; } - private void Application_InstanceStarted(IApplicationInstance instance) + private void Application_WindowsChanged() { - Dispatcher.InvokeAsync(() => - { - var button = new ActionCenterApplicationButton(application.Info, instance); - - button.Clicked += (o, args) => instance.Activate(); - instance.Terminated += (_) => RemoveInstance(button); - InstancePanel.Children.Add(button); - - ApplicationName.Visibility = Visibility.Visible; - ApplicationButton.Visibility = Visibility.Collapsed; - }); + Dispatcher.InvokeAsync(Update); } - private void RemoveInstance(ActionCenterApplicationButton button) + private void Update() { - Dispatcher.InvokeAsync(() => - { - InstancePanel.Children.Remove(button); + var windows = application.GetWindows(); - if (InstancePanel.Children.Count == 0) - { - ApplicationName.Visibility = Visibility.Collapsed; - ApplicationButton.Visibility = Visibility.Visible; - } - }); + WindowPanel.Children.Clear(); + + foreach (var window in windows) + { + var button = new ActionCenterApplicationButton(application.Info, window); + + button.Clicked += (o, args) => window.Activate(); + WindowPanel.Children.Add(button); + } + + if (WindowPanel.Children.Count == 0) + { + ApplicationName.Visibility = Visibility.Collapsed; + ApplicationButton.Visibility = Visibility.Visible; + } + else + { + ApplicationName.Visibility = Visibility.Visible; + ApplicationButton.Visibility = Visibility.Collapsed; + } } } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskViewInstanceControl.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskViewWindowControl.xaml similarity index 97% rename from SafeExamBrowser.UserInterface.Mobile/Controls/TaskViewInstanceControl.xaml rename to SafeExamBrowser.UserInterface.Mobile/Controls/TaskViewWindowControl.xaml index d0f8a794..48f6912f 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskViewInstanceControl.xaml +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskViewWindowControl.xaml @@ -1,4 +1,4 @@ - instance.Id; - - public TaskViewInstanceControl(IApplicationInstance instance) + public TaskViewWindowControl(IApplicationWindow window) { - this.instance = instance; + this.window = window; InitializeComponent(); InitializeControl(); @@ -30,7 +28,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls internal void Activate() { - instance.Activate(); + window.Activate(); } internal void Deselect() @@ -49,21 +47,21 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls private void InitializeControl() { - Icon.Content = IconResourceLoader.Load(instance.Icon); - Title.Text = instance.Name; + Icon.Content = IconResourceLoader.Load(window.Icon); + Title.Text = window.Title; - instance.IconChanged += Instance_IconChanged; - instance.NameChanged += Instance_NameChanged; + window.IconChanged += Instance_IconChanged; + window.TitleChanged += Instance_TitleChanged; } - private void Instance_NameChanged(string name) + private void Instance_TitleChanged(string title) { - Dispatcher.InvokeAsync(() => Title.Text = name); + Dispatcher.InvokeAsync(() => Title.Text = title); } private void Instance_IconChanged(IconResource icon) { - Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(instance.Icon)); + Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(window.Icon)); } } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarApplicationControl.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarApplicationControl.xaml index dfc889b5..af5d3b89 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarApplicationControl.xaml +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarApplicationControl.xaml @@ -16,10 +16,10 @@ - + - - + + diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarApplicationControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarApplicationControl.xaml.cs index 1e8db711..fc98dcf0 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarApplicationControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarApplicationControl.xaml.cs @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; @@ -20,7 +21,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls public partial class TaskbarApplicationControl : UserControl, IApplicationControl { private IApplication application; - private IApplicationInstance single; + private IApplicationWindow single; public TaskbarApplicationControl(IApplication application) { @@ -34,71 +35,64 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls { var originalBrush = Button.Background; - application.InstanceStarted += Application_InstanceStarted; + application.WindowsChanged += Application_WindowsChanged; Button.Click += Button_Click; Button.Content = IconResourceLoader.Load(application.Info.Icon); - Button.MouseEnter += (o, args) => InstancePopup.IsOpen = InstanceStackPanel.Children.Count > 1; - Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => InstancePopup.IsOpen = InstancePopup.IsMouseOver)); + Button.MouseEnter += (o, args) => WindowPopup.IsOpen = WindowStackPanel.Children.Count > 0; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => WindowPopup.IsOpen = WindowPopup.IsMouseOver)); Button.ToolTip = application.Info.Tooltip; - InstancePopup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => InstancePopup.IsOpen = IsMouseOver)); + WindowPopup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => WindowPopup.IsOpen = IsMouseOver)); - InstancePopup.Opened += (o, args) => + WindowPopup.Opened += (o, args) => { Background = Brushes.LightGray; Button.Background = Brushes.LightGray; }; - InstancePopup.Closed += (o, args) => + WindowPopup.Closed += (o, args) => { Background = originalBrush; Button.Background = originalBrush; }; } - private void Application_InstanceStarted(IApplicationInstance instance) + private void Application_WindowsChanged() { - Dispatcher.Invoke(() => - { - var button = new TaskbarApplicationInstanceButton(instance, application.Info); - - instance.Terminated += (_) => RemoveInstance(button); - InstanceStackPanel.Children.Add(button); - - if (single == default(IApplicationInstance)) - { - single = instance; - } - }); + Dispatcher.InvokeAsync(Update); } private void Button_Click(object sender, RoutedEventArgs e) { - if (InstanceStackPanel.Children.Count == 0) + if (WindowStackPanel.Children.Count == 0) { application.Start(); } - else if (InstanceStackPanel.Children.Count == 1) + else if (WindowStackPanel.Children.Count == 1) { - single.Activate(); + single?.Activate(); + } + } + + private void Update() + { + var windows = application.GetWindows(); + + WindowStackPanel.Children.Clear(); + + foreach (var window in windows) + { + WindowStackPanel.Children.Add(new TaskbarApplicationWindowButton(window)); + } + + if (WindowStackPanel.Children.Count == 1) + { + single = windows.First(); } else { - InstancePopup.IsOpen = true; + single = default(IApplicationWindow); } } - - private void RemoveInstance(TaskbarApplicationInstanceButton button) - { - Dispatcher.InvokeAsync(() => - { - InstanceStackPanel.Children.Remove(button); - - if (InstanceStackPanel.Children.Count == 0) - { - single = default(IApplicationInstance); - } - }); - } } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarApplicationInstanceButton.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarApplicationWindowButton.xaml similarity index 97% rename from SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarApplicationInstanceButton.xaml rename to SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarApplicationWindowButton.xaml index bd0b5870..e151bda3 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarApplicationInstanceButton.xaml +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarApplicationWindowButton.xaml @@ -1,4 +1,4 @@ - Icon.Content = IconResourceLoader.Load(icon)); } - private void Instance_NameChanged(string name) + private void Window_TitleChanged(string title) { - Dispatcher.Invoke(() => + Dispatcher.InvokeAsync(() => { - Text.Text = name; - Button.ToolTip = name; + Text.Text = title; + Button.ToolTip = title; }); } } diff --git a/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj b/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj index 75a7d088..8e7cee3f 100644 --- a/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj +++ b/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj @@ -113,8 +113,8 @@ TaskbarApplicationControl.xaml - - TaskbarApplicationInstanceButton.xaml + + TaskbarApplicationWindowButton.xaml TaskbarAudioControl.xaml @@ -143,8 +143,8 @@ TaskbarWirelessNetworkControl.xaml - - TaskViewInstanceControl.xaml + + TaskViewWindowControl.xaml LockScreen.xaml @@ -283,7 +283,7 @@ MSBuild:Compile Designer - + MSBuild:Compile Designer @@ -359,7 +359,7 @@ MSBuild:Compile Designer - + MSBuild:Compile Designer diff --git a/SafeExamBrowser.UserInterface.Mobile/TaskView.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/TaskView.xaml.cs index d577e7ea..123447f9 100644 --- a/SafeExamBrowser.UserInterface.Mobile/TaskView.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/TaskView.xaml.cs @@ -19,21 +19,22 @@ namespace SafeExamBrowser.UserInterface.Mobile { public partial class TaskView : Window, ITaskView { - private LinkedListNode current; - private LinkedList controls; - private List instances; + private IList applications; + private LinkedListNode current; + private LinkedList controls; public TaskView() { - controls = new LinkedList(); - instances = new List(); + applications = new List(); + controls = new LinkedList(); InitializeComponent(); } public void Add(IApplication application) { - application.InstanceStarted += Application_InstanceStarted; + application.WindowsChanged += Application_WindowsChanged; + applications.Add(application); } public void Register(ITaskViewActivator activator) @@ -43,9 +44,9 @@ namespace SafeExamBrowser.UserInterface.Mobile activator.PreviousActivated += Activator_Previous; } - private void Application_InstanceStarted(IApplicationInstance instance) + private void Application_WindowsChanged() { - Dispatcher.InvokeAsync(() => Add(instance)); + Dispatcher.InvokeAsync(Update); } private void Activator_Deactivated() @@ -63,11 +64,6 @@ namespace SafeExamBrowser.UserInterface.Mobile Dispatcher.InvokeAsync(SelectPrevious); } - private void Instance_Terminated(InstanceIdentifier id) - { - Dispatcher.InvokeAsync(() => Remove(id)); - } - private void ActivateAndHide() { Activate(); @@ -75,24 +71,6 @@ namespace SafeExamBrowser.UserInterface.Mobile Hide(); } - private void Add(IApplicationInstance instance) - { - instance.Terminated += Instance_Terminated; - instances.Add(instance); - Update(); - } - - private void Remove(InstanceIdentifier id) - { - var instance = instances.FirstOrDefault(i => i.Id == id); - - if (instance != default(IApplicationInstance)) - { - instances.Remove(instance); - Update(); - } - } - private void SelectNext() { ShowConditional(); @@ -119,7 +97,7 @@ namespace SafeExamBrowser.UserInterface.Mobile private void ShowConditional() { - if (instances.Any() && Visibility != Visibility.Visible) + if (controls.Any() && Visibility != Visibility.Visible) { Show(); Activate(); @@ -128,22 +106,31 @@ namespace SafeExamBrowser.UserInterface.Mobile private void Update() { - var max = Math.Ceiling(Math.Sqrt(instances.Count)); - var stack = new Stack(instances); + var windows = new Stack(); + + foreach (var application in applications) + { + foreach (var window in application.GetWindows()) + { + windows.Push(window); + } + } + + var max = Math.Ceiling(Math.Sqrt(windows.Count)); controls.Clear(); Rows.Children.Clear(); - for (var rowCount = 0; rowCount < max && stack.Any(); rowCount++) + for (var rowCount = 0; rowCount < max && windows.Any(); rowCount++) { var row = new StackPanel { Orientation = Orientation.Horizontal, HorizontalAlignment = HorizontalAlignment.Center }; Rows.Children.Add(row); - for (var columnIndex = 0; columnIndex < max && stack.Any(); columnIndex++) + for (var columnIndex = 0; columnIndex < max && windows.Any(); columnIndex++) { - var instance = stack.Pop(); - var control = new TaskViewInstanceControl(instance); + var window = windows.Pop(); + var control = new TaskViewWindowControl(window); controls.AddLast(control); row.Children.Add(control); @@ -158,7 +145,7 @@ namespace SafeExamBrowser.UserInterface.Mobile Left = (SystemParameters.WorkArea.Width - Width) / 2 + SystemParameters.WorkArea.Left; Top = (SystemParameters.WorkArea.Height - Height) / 2 + SystemParameters.WorkArea.Top; - if (!instances.Any()) + if (!windows.Any()) { Hide(); } diff --git a/SafeExamBrowser.WindowsApi.Contracts/IProcess.cs b/SafeExamBrowser.WindowsApi.Contracts/IProcess.cs index 95fb6308..5e5e6b30 100644 --- a/SafeExamBrowser.WindowsApi.Contracts/IProcess.cs +++ b/SafeExamBrowser.WindowsApi.Contracts/IProcess.cs @@ -40,12 +40,6 @@ namespace SafeExamBrowser.WindowsApi.Contracts /// event ProcessTerminatedEventHandler Terminated; - /// - /// Attempts to activate the process (i.e. bring its main window to the foreground). This may only work for interactive processes which have - /// a main window. Returns true if the process was successfully activated, otherwise false. - /// - bool TryActivate(); - /// /// Attempts to gracefully terminate the process by closing its main window. This will only work for interactive processes which have a main /// window. Optionally waits the specified amount of time for the process to terminate. Returns true if the process has terminated, @@ -53,12 +47,6 @@ namespace SafeExamBrowser.WindowsApi.Contracts /// bool TryClose(int timeout_ms = 0); - /// - /// Attempts to retrieve the title of the main window of the process. This will only work if for interactive processes which have a main - /// window. Returns true if the title was successfully retrieved, otherwise false. - /// - bool TryGetWindowTitle(out string title); - /// /// Attempts to immediately kill the process. Optionally waits the specified amount of time for the process to terminate. Returns true /// if the process has terminated, otherwise false.