From f229681f545d898ed7063c5a7fce3ca053d111d7 Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 25 Feb 2019 21:32:46 +0200 Subject: [PATCH 01/27] Version update (4.1.0.1) --- Eve-O-Preview/Properties/AssemblyInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eve-O-Preview/Properties/AssemblyInfo.cs b/Eve-O-Preview/Properties/AssemblyInfo.cs index 363b1d9..9b2adf4 100644 --- a/Eve-O-Preview/Properties/AssemblyInfo.cs +++ b/Eve-O-Preview/Properties/AssemblyInfo.cs @@ -12,7 +12,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("04f08f8d-9e98-423b-acdb-4effb31c0d35")] -[assembly: AssemblyVersion("4.0.1.0")] -[assembly: AssemblyFileVersion("4.0.1.0")] +[assembly: AssemblyVersion("4.1.0.1")] +[assembly: AssemblyFileVersion("4.1.0.1")] [assembly: CLSCompliant(false)] \ No newline at end of file From ff36d15b7571b79a93ecc4d7fa5c92a1244e50c7 Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 25 Feb 2019 21:33:49 +0200 Subject: [PATCH 02/27] 138: Simplify Hotkey management code --- Eve-O-Preview/Hotkeys/HotkeyHandler.cs | 50 +++++-------------- .../View/Implementation/ThumbnailView.cs | 10 +--- 2 files changed, 14 insertions(+), 46 deletions(-) diff --git a/Eve-O-Preview/Hotkeys/HotkeyHandler.cs b/Eve-O-Preview/Hotkeys/HotkeyHandler.cs index 86c705a..4b95cf2 100644 --- a/Eve-O-Preview/Hotkeys/HotkeyHandler.cs +++ b/Eve-O-Preview/Hotkeys/HotkeyHandler.cs @@ -29,28 +29,14 @@ namespace EveOPreview.UI.Hotkeys public void Dispose() { - if (this.IsRegistered) - { - this.Unregister(); - } - + this.Unregister(); GC.SuppressFinalize(this); } ~HotkeyHandler() { // Unregister the hotkey if necessary - if (this.IsRegistered) - { - try - { - this.Unregister(); - } - catch (Exception) - { - // Please no exceptions in the finalizer thread - } - } + this.Unregister(); } public bool IsRegistered { get; private set; } @@ -61,22 +47,12 @@ namespace EveOPreview.UI.Hotkeys public bool CanRegister() { - // Any exception means "no, you can't register" - try - { - // Attempt to register - if (this.Register()) - { - // Unregister and say we managed it - this.Unregister(); - return true; - } - } - catch (Win32Exception) - { - } - catch (NotSupportedException) + // Attempt to register + if (this.Register()) { + // Unregister and say we managed it + this.Unregister(); + return true; } return false; @@ -87,12 +63,12 @@ namespace EveOPreview.UI.Hotkeys // Check that we have not registered if (this.IsRegistered) { - throw new NotSupportedException("This hotkey is already registered"); + return false; } if (this.KeyCode == Keys.None) { - throw new NotSupportedException("Cannot register an empty hotkey"); + return false; } // Remove all modifiers from the 'main' hotkey @@ -122,18 +98,18 @@ namespace EveOPreview.UI.Hotkeys // Check that we have registered if (!this.IsRegistered) { - throw new NotSupportedException("This hotkey was not registered"); + return; } + this.IsRegistered = false; + Application.RemoveMessageFilter(this); // Clean up after ourselves if (!HotkeyHandlerNativeMethods.UnregisterHotKey(this._hotkeyTarget, this._hotkeyId)) { - throw new Win32Exception(); + return; } - - this.IsRegistered = false; } #region IMessageFilter diff --git a/Eve-O-Preview/View/Implementation/ThumbnailView.cs b/Eve-O-Preview/View/Implementation/ThumbnailView.cs index 7199707..7c386ca 100644 --- a/Eve-O-Preview/View/Implementation/ThumbnailView.cs +++ b/Eve-O-Preview/View/Implementation/ThumbnailView.cs @@ -287,15 +287,7 @@ namespace EveOPreview.View this._hotkeyHandler = new HotkeyHandler(this.Handle, hotkey); this._hotkeyHandler.Pressed += HotkeyPressed_Handler; - try - { - this._hotkeyHandler.Register(); - } - catch (Exception) - { - // There can be a lot of possible exception reasons here - // In case of any of them the hotkey setting is silently ignored - } + this._hotkeyHandler.Register(); } public void UnregisterHotkey() From 9d54613170ad114e7a3937e5d9734a59e412b90f Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 25 Feb 2019 21:38:52 +0200 Subject: [PATCH 03/27] 139: Application crashes on Windows User switch --- .../Services/Implementation/DwmThumbnail.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Eve-O-Preview/Services/Implementation/DwmThumbnail.cs b/Eve-O-Preview/Services/Implementation/DwmThumbnail.cs index e1b8fa6..76b9388 100644 --- a/Eve-O-Preview/Services/Implementation/DwmThumbnail.cs +++ b/Eve-O-Preview/Services/Implementation/DwmThumbnail.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.InteropServices; using EveOPreview.Services.Interop; namespace EveOPreview.Services.Implementation @@ -45,6 +46,12 @@ namespace EveOPreview.Services.Implementation // a thumbnail source this._handle = IntPtr.Zero; } + catch (COMException) + { + // This exception is raised if DWM is suddenly not available + // (f.e. when switching between Windows user accounts) + this._handle = IntPtr.Zero; + } } public void Unregister() @@ -61,6 +68,10 @@ namespace EveOPreview.Services.Implementation catch (ArgumentException) { } + catch (COMException) + { + // This exception is raised when DWM is not available for some reason + } } public void Move(int left, int top, int right, int bottom) @@ -81,7 +92,11 @@ namespace EveOPreview.Services.Implementation } catch (ArgumentException) { - //This exception will be thrown if the EVE client disappears while this method is running + // This exception will be thrown if the EVE client disappears while this method is running + } + catch (COMException) + { + // This exception is raised when DWM is not available for some reason } } } From a4e46c27bd6622b9ec9704ac05d5351bc3b6db0f Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 25 Feb 2019 21:52:03 +0200 Subject: [PATCH 04/27] 140: Saved client location is applied even if the corresponding option is disabled --- Eve-O-Preview/Services/Implementation/ThumbnailManager.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs b/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs index 693e12d..e4c2a99 100644 --- a/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs +++ b/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs @@ -397,8 +397,6 @@ namespace EveOPreview.Services this.UpdateClientLayouts(); this.RefreshThumbnails(); }); - - this.UpdateClientLayouts(); } private void ThumbnailDeactivated(IntPtr id) @@ -562,6 +560,11 @@ namespace EveOPreview.Services private void ApplyClientLayout(IntPtr clientHandle, string clientTitle) { + if (!this._configuration.EnableClientLayoutTracking) + { + return; + } + ClientLayout clientLayout = this._configuration.GetClientLayout(clientTitle); if (clientLayout == null) From 7bc2775fb79669c2cc9865a0ce32d17ccf118f91 Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 25 Feb 2019 22:03:11 +0200 Subject: [PATCH 05/27] Internal code cleanup --- .../ApplicationBase/ExceptionHandler.cs | 8 ++-- .../Implementation/ConfigurationStorage.cs | 4 +- Eve-O-Preview/Eve-O-Preview.csproj | 1 - Eve-O-Preview/Hotkeys/HotkeyHandler.cs | 9 ++-- .../Implementation/MainFormPresenter.cs | 6 +-- .../Services/Implementation/ProcessMonitor.cs | 6 +-- .../Implementation/ThumbnailManager.cs | 45 +++++++++---------- .../View/Implementation/ThumbnailView.cs | 4 +- Eve-O-Preview/View/Interface/IMainFormView.cs | 1 - 9 files changed, 39 insertions(+), 45 deletions(-) diff --git a/Eve-O-Preview/ApplicationBase/ExceptionHandler.cs b/Eve-O-Preview/ApplicationBase/ExceptionHandler.cs index 461370e..f1669b6 100644 --- a/Eve-O-Preview/ApplicationBase/ExceptionHandler.cs +++ b/Eve-O-Preview/ApplicationBase/ExceptionHandler.cs @@ -12,8 +12,8 @@ namespace EveOPreview // So this dumb and non elegant approach is used sealed class ExceptionHandler { - private const string ExceptionDumpFileName = "EVE-O Preview.log"; - private const string ExceptionMessage = "EVE-O Preview has encountered a problem and needs to close. Additional information has been saved in the crash log file."; + private const string EXCEPTION_DUMP_FILE_NAME = "EVE-O Preview.log"; + private const string EXCEPTION_MESSAGE = "EVE-O Preview has encountered a problem and needs to close. Additional information has been saved in the crash log file."; public void SetupExceptionHandlers() { @@ -39,9 +39,9 @@ namespace EveOPreview try { String exceptionMessage = exception.ToString(); - File.WriteAllText(ExceptionHandler.ExceptionDumpFileName, exceptionMessage); + File.WriteAllText(ExceptionHandler.EXCEPTION_DUMP_FILE_NAME, exceptionMessage); - MessageBox.Show(ExceptionHandler.ExceptionMessage, @"EVE-O Preview", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(ExceptionHandler.EXCEPTION_MESSAGE, @"EVE-O Preview", MessageBoxButtons.OK, MessageBoxIcon.Error); } catch { diff --git a/Eve-O-Preview/Configuration/Implementation/ConfigurationStorage.cs b/Eve-O-Preview/Configuration/Implementation/ConfigurationStorage.cs index e07ec8f..3419b74 100644 --- a/Eve-O-Preview/Configuration/Implementation/ConfigurationStorage.cs +++ b/Eve-O-Preview/Configuration/Implementation/ConfigurationStorage.cs @@ -5,7 +5,7 @@ namespace EveOPreview.Configuration.Implementation { class ConfigurationStorage : IConfigurationStorage { - private const string ConfigurationFileName = "EVE-O Preview.json"; + private const string CONFIGURATION_FILE_NAME = "EVE-O Preview.json"; private readonly IAppConfig _appConfig; private readonly IThumbnailConfiguration _thumbnailConfiguration; @@ -50,7 +50,7 @@ namespace EveOPreview.Configuration.Implementation private string GetConfigFileName() { - return string.IsNullOrEmpty(this._appConfig.ConfigFileName) ? ConfigurationStorage.ConfigurationFileName : this._appConfig.ConfigFileName; + return string.IsNullOrEmpty(this._appConfig.ConfigFileName) ? ConfigurationStorage.CONFIGURATION_FILE_NAME : this._appConfig.ConfigFileName; } } } \ No newline at end of file diff --git a/Eve-O-Preview/Eve-O-Preview.csproj b/Eve-O-Preview/Eve-O-Preview.csproj index abdecee..30d8b89 100644 --- a/Eve-O-Preview/Eve-O-Preview.csproj +++ b/Eve-O-Preview/Eve-O-Preview.csproj @@ -214,7 +214,6 @@ Designer - diff --git a/Eve-O-Preview/Hotkeys/HotkeyHandler.cs b/Eve-O-Preview/Hotkeys/HotkeyHandler.cs index 4b95cf2..bb95186 100644 --- a/Eve-O-Preview/Hotkeys/HotkeyHandler.cs +++ b/Eve-O-Preview/Hotkeys/HotkeyHandler.cs @@ -7,7 +7,7 @@ namespace EveOPreview.UI.Hotkeys class HotkeyHandler : IMessageFilter, IDisposable { private static int _currentId; - private const int MaxId = 0xBFFF; + private const int MAX_ID = 0xBFFF; #region Private fields private readonly int _hotkeyId; @@ -17,7 +17,7 @@ namespace EveOPreview.UI.Hotkeys public HotkeyHandler(IntPtr target, Keys hotkey) { this._hotkeyId = HotkeyHandler._currentId; - HotkeyHandler._currentId = (HotkeyHandler._currentId + 1) & HotkeyHandler.MaxId; + HotkeyHandler._currentId = (HotkeyHandler._currentId + 1) & HotkeyHandler.MAX_ID; this._hotkeyTarget = target; @@ -106,10 +106,7 @@ namespace EveOPreview.UI.Hotkeys Application.RemoveMessageFilter(this); // Clean up after ourselves - if (!HotkeyHandlerNativeMethods.UnregisterHotKey(this._hotkeyTarget, this._hotkeyId)) - { - return; - } + HotkeyHandlerNativeMethods.UnregisterHotKey(this._hotkeyTarget, this._hotkeyId); } #region IMessageFilter diff --git a/Eve-O-Preview/Presenters/Implementation/MainFormPresenter.cs b/Eve-O-Preview/Presenters/Implementation/MainFormPresenter.cs index 8d35104..57b82ea 100644 --- a/Eve-O-Preview/Presenters/Implementation/MainFormPresenter.cs +++ b/Eve-O-Preview/Presenters/Implementation/MainFormPresenter.cs @@ -12,7 +12,7 @@ namespace EveOPreview.Presenters public class MainFormPresenter : Presenter, IMainFormPresenter { #region Private constants - private const string ForumUrl = @"https://forum.eveonline.com/t/4202"; + private const string FORUM_URL = @"https://forum.eveonline.com/t/4202"; #endregion #region Private fields @@ -50,7 +50,7 @@ namespace EveOPreview.Presenters private void Activate() { this.LoadApplicationSettings(); - this.View.SetDocumentationUrl(MainFormPresenter.ForumUrl); + this.View.SetDocumentationUrl(MainFormPresenter.FORUM_URL); this.View.SetVersionInfo(this.GetApplicationVersion()); if (this._configuration.MinimizeToTray) { @@ -225,7 +225,7 @@ namespace EveOPreview.Presenters private void OpenDocumentationLink() { // TODO Move out to a separate service / presenter / message handler - ProcessStartInfo processStartInfo = new ProcessStartInfo(new Uri(MainFormPresenter.ForumUrl).AbsoluteUri); + ProcessStartInfo processStartInfo = new ProcessStartInfo(new Uri(MainFormPresenter.FORUM_URL).AbsoluteUri); Process.Start(processStartInfo); } diff --git a/Eve-O-Preview/Services/Implementation/ProcessMonitor.cs b/Eve-O-Preview/Services/Implementation/ProcessMonitor.cs index 3f53e87..5c5e057 100644 --- a/Eve-O-Preview/Services/Implementation/ProcessMonitor.cs +++ b/Eve-O-Preview/Services/Implementation/ProcessMonitor.cs @@ -7,7 +7,7 @@ namespace EveOPreview.Services.Implementation sealed class ProcessMonitor : IProcessMonitor { #region Private constants - private const string DefaultProcessName = "ExeFile"; + private const string DEFAULT_PROCESS_NAME = "ExeFile"; #endregion #region Private fields @@ -22,7 +22,7 @@ namespace EveOPreview.Services.Implementation private bool IsMonitoredProcess(string processName) { // This is a possible extension point - return String.Equals(processName, ProcessMonitor.DefaultProcessName, StringComparison.OrdinalIgnoreCase); + return String.Equals(processName, ProcessMonitor.DEFAULT_PROCESS_NAME, StringComparison.OrdinalIgnoreCase); } public void GetUpdatedProcesses(out ICollection addedProcesses, out ICollection updatedProcesses, out ICollection removedProcesses) @@ -62,7 +62,7 @@ namespace EveOPreview.Services.Implementation if (cachedTitle != mainWindowTitle) { this._processCache[mainWindowHandle] = mainWindowTitle; - updatedProcesses.Add((IProcessInfo)new ProcessInfo(mainWindowHandle, mainWindowTitle)); + updatedProcesses.Add(new ProcessInfo(mainWindowHandle, mainWindowTitle)); } knownProcesses.Remove(mainWindowHandle); diff --git a/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs b/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs index e4c2a99..58a562f 100644 --- a/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs +++ b/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Windows.Threading; using EveOPreview.Configuration; @@ -14,13 +13,13 @@ namespace EveOPreview.Services class ThumbnailManager : IThumbnailManager { #region Private constants - private const int WindowPositionThresholdLow = -10_000; - private const int WindowPositionThresholdHigh = 31_000; - private const int WindowSizeThreshold = 10; - private const int ForcedRefreshCycleThreshold = 2; - private const int DefaultLocationChangeNotificationDelay = 2; + private const int WINDOW_POSITION_THRESHOLD_LOW = -10_000; + private const int WINDOW_POSITION_THRESHOLD_HIGH = 31_000; + private const int WINDOW_SIZE_THRESHOLD = 10; + private const int FORCED_REFRESH_CYCLE_THRESHOLD = 2; + private const int DEFAULT_LOCATION_CHANGE_NOTIFICATION_DELAY = 2; - private const string DefaultClientTitle = "EVE"; + private const string DEFAULT_CLIENT_TITLE = "EVE"; #endregion #region Private fields @@ -51,7 +50,7 @@ namespace EveOPreview.Services this._configuration = configuration; this._thumbnailViewFactory = factory; - this._activeClient = (IntPtr.Zero, ThumbnailManager.DefaultClientTitle); + this._activeClient = (IntPtr.Zero, ThumbnailManager.DEFAULT_CLIENT_TITLE); this.EnableViewEvents(); this._isHoverEffectActive = false; @@ -121,7 +120,7 @@ namespace EveOPreview.Services this.ApplyClientLayout(view.Id, view.Title); // TODO Add extension filter here later - if (view.Title != ThumbnailManager.DefaultClientTitle) + if (view.Title != ThumbnailManager.DEFAULT_CLIENT_TITLE) { viewsAdded.Add(view.Title); } @@ -154,7 +153,7 @@ namespace EveOPreview.Services IThumbnailView view = this._thumbnailViews[process.Handle]; this._thumbnailViews.Remove(view.Id); - if (view.Title != ThumbnailManager.DefaultClientTitle) + if (view.Title != ThumbnailManager.DEFAULT_CLIENT_TITLE) { viewsRemoved.Add(view.Title); } @@ -203,7 +202,7 @@ namespace EveOPreview.Services this._refreshCycleCount++; bool forceRefresh; - if (this._refreshCycleCount >= ThumbnailManager.ForcedRefreshCycleThreshold) + if (this._refreshCycleCount >= ThumbnailManager.FORCED_REFRESH_CYCLE_THRESHOLD) { this._refreshCycleCount = 0; forceRefresh = true; @@ -223,11 +222,11 @@ namespace EveOPreview.Services { this.SnapThumbnailView(view); - this.RaiseThumbnailLocationUpdatedNotification(view.Title, this._activeClient.Title, view.ThumbnailLocation); + this.RaiseThumbnailLocationUpdatedNotification(view.Title); } else { - this.RaiseThumbnailLocationUpdatedNotification(locationChange.Title, locationChange.ActiveClient, locationChange.Location); + this.RaiseThumbnailLocationUpdatedNotification(locationChange.Title); } } @@ -609,7 +608,7 @@ namespace EveOPreview.Services { if (this._enqueuedLocationChangeNotification.Handle == IntPtr.Zero) { - this._enqueuedLocationChangeNotification = (view.Id, view.Title, activeClientTitle, view.ThumbnailLocation, ThumbnailManager.DefaultLocationChangeNotificationDelay); + this._enqueuedLocationChangeNotification = (view.Id, view.Title, activeClientTitle, view.ThumbnailLocation, ThumbnailManager.DEFAULT_LOCATION_CHANGE_NOTIFICATION_DELAY); return; } @@ -617,12 +616,12 @@ namespace EveOPreview.Services if ((this._enqueuedLocationChangeNotification.Handle == view.Id) && (this._enqueuedLocationChangeNotification.ActiveClient == activeClientTitle)) { - this._enqueuedLocationChangeNotification.Delay = ThumbnailManager.DefaultLocationChangeNotificationDelay; + this._enqueuedLocationChangeNotification.Delay = ThumbnailManager.DEFAULT_LOCATION_CHANGE_NOTIFICATION_DELAY; return; } - this.RaiseThumbnailLocationUpdatedNotification(this._enqueuedLocationChangeNotification.Title, activeClientTitle, this._enqueuedLocationChangeNotification.Location); - this._enqueuedLocationChangeNotification = (view.Id, view.Title, activeClientTitle, view.ThumbnailLocation, ThumbnailManager.DefaultLocationChangeNotificationDelay); + this.RaiseThumbnailLocationUpdatedNotification(this._enqueuedLocationChangeNotification.Title); + this._enqueuedLocationChangeNotification = (view.Id, view.Title, activeClientTitle, view.ThumbnailLocation, ThumbnailManager.DEFAULT_LOCATION_CHANGE_NOTIFICATION_DELAY); } } @@ -651,9 +650,9 @@ namespace EveOPreview.Services } } - private async void RaiseThumbnailLocationUpdatedNotification(string title, string activeClient, Point location) + private async void RaiseThumbnailLocationUpdatedNotification(string title) { - if (string.IsNullOrEmpty(title) || (title == ThumbnailManager.DefaultClientTitle)) + if (string.IsNullOrEmpty(title) || (title == ThumbnailManager.DEFAULT_CLIENT_TITLE)) { return; } @@ -665,15 +664,15 @@ namespace EveOPreview.Services // TODO Move to a service (?) private bool IsManageableThumbnail(IThumbnailView view) { - return view.Title != ThumbnailManager.DefaultClientTitle; + return view.Title != ThumbnailManager.DEFAULT_CLIENT_TITLE; } // Quick sanity check that the window is not minimized private bool IsValidWindowPosition(int letf, int top, int width, int height) { - return (letf > ThumbnailManager.WindowPositionThresholdLow) && (letf < ThumbnailManager.WindowPositionThresholdHigh) - && (top > ThumbnailManager.WindowPositionThresholdLow) && (top < ThumbnailManager.WindowPositionThresholdHigh) - && (width > ThumbnailManager.WindowSizeThreshold) && (height > ThumbnailManager.WindowSizeThreshold); + return (letf > ThumbnailManager.WINDOW_POSITION_THRESHOLD_LOW) && (letf < ThumbnailManager.WINDOW_POSITION_THRESHOLD_HIGH) + && (top > ThumbnailManager.WINDOW_POSITION_THRESHOLD_LOW) && (top < ThumbnailManager.WINDOW_POSITION_THRESHOLD_HIGH) + && (width > ThumbnailManager.WINDOW_SIZE_THRESHOLD) && (height > ThumbnailManager.WINDOW_SIZE_THRESHOLD); } } } \ No newline at end of file diff --git a/Eve-O-Preview/View/Implementation/ThumbnailView.cs b/Eve-O-Preview/View/Implementation/ThumbnailView.cs index 7c386ca..94b1f72 100644 --- a/Eve-O-Preview/View/Implementation/ThumbnailView.cs +++ b/Eve-O-Preview/View/Implementation/ThumbnailView.cs @@ -10,7 +10,7 @@ namespace EveOPreview.View public partial class ThumbnailView : Form, IThumbnailView { #region Private constants - private const int ResizeEventTimeout = 500; + private const int RESIZE_EVENT_TIMEOUT = 500; #endregion #region Private fields @@ -388,7 +388,7 @@ namespace EveOPreview.View { // Workaround for WinForms issue with the Resize event being fired with inconsistent ClientSize value // Any Resize events fired before this timestamp will be ignored - this._suppressResizeEventsTimestamp = DateTime.UtcNow.AddMilliseconds(ThumbnailView.ResizeEventTimeout); + this._suppressResizeEventsTimestamp = DateTime.UtcNow.AddMilliseconds(ThumbnailView.RESIZE_EVENT_TIMEOUT); } #region GUI events diff --git a/Eve-O-Preview/View/Interface/IMainFormView.cs b/Eve-O-Preview/View/Interface/IMainFormView.cs index 1c4ad32..cc727ef 100644 --- a/Eve-O-Preview/View/Interface/IMainFormView.cs +++ b/Eve-O-Preview/View/Interface/IMainFormView.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Drawing; -using EveOPreview.UI; namespace EveOPreview.View { From cd74a3d29fac9d0501c6c7197ddbaa25e9765a5e Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 4 Mar 2019 21:17:03 +0200 Subject: [PATCH 06/27] NuGet packages update --- Eve-O-Preview/Eve-O-Preview.csproj | 33 +++--- Eve-O-Preview/FodyWeavers.xml | 2 +- Eve-O-Preview/FodyWeavers.xsd | 111 ++++++++++++++++++ .../Configuration/SaveConfigurationHandler.cs | 4 +- .../Services/StartStopServiceHandler.cs | 8 +- Eve-O-Preview/Program.cs | 4 +- Eve-O-Preview/packages.config | 11 +- 7 files changed, 144 insertions(+), 29 deletions(-) create mode 100644 Eve-O-Preview/FodyWeavers.xsd diff --git a/Eve-O-Preview/Eve-O-Preview.csproj b/Eve-O-Preview/Eve-O-Preview.csproj index 30d8b89..c469a1f 100644 --- a/Eve-O-Preview/Eve-O-Preview.csproj +++ b/Eve-O-Preview/Eve-O-Preview.csproj @@ -1,5 +1,6 @@  + Debug AnyCPU @@ -75,24 +76,29 @@ app.manifest - - ..\packages\Costura.Fody.1.6.2\lib\dotnet\Costura.dll - False + + ..\packages\Costura.Fody.3.3.2\lib\net40\Costura.dll - - ..\packages\LightInject.5.1.2\lib\net452\LightInject.dll - True + + ..\packages\LightInject.5.4.0\lib\net46\LightInject.dll - - ..\packages\MediatR.4.0.1\lib\net45\MediatR.dll + + ..\packages\MediatR.6.0.0\lib\net461\MediatR.dll - - ..\packages\Newtonsoft.Json.11.0.1\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll + + + + + + ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll + @@ -221,15 +227,14 @@ + 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}. - - + + - - + + + + + + + + + A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks + + + + + A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. + + + + + A list of unmanaged 32 bit assembly names to include, delimited with line breaks. + + + + + A list of unmanaged 64 bit assembly names to include, delimited with line breaks. + + + + + The order of preloaded assemblies, delimited with line breaks. + + + + + + This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file. + + + + + Controls if .pdbs for reference assemblies are also embedded. + + + + + Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option. + + + + + As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off. + + + + + Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code. + + + + + Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior. + + + + + A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with | + + + + + A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |. + + + + + A list of unmanaged 32 bit assembly names to include, delimited with |. + + + + + A list of unmanaged 64 bit assembly names to include, delimited with |. + + + + + The order of preloaded assemblies, delimited with |. + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/Eve-O-Preview/Mediator/Handlers/Configuration/SaveConfigurationHandler.cs b/Eve-O-Preview/Mediator/Handlers/Configuration/SaveConfigurationHandler.cs index c870f7a..f1b2db2 100644 --- a/Eve-O-Preview/Mediator/Handlers/Configuration/SaveConfigurationHandler.cs +++ b/Eve-O-Preview/Mediator/Handlers/Configuration/SaveConfigurationHandler.cs @@ -15,11 +15,11 @@ namespace EveOPreview.Mediator.Handlers.Configuration this._storage = storage; } - public Task Handle(SaveConfiguration message, CancellationToken cancellationToken) + public Task Handle(SaveConfiguration message, CancellationToken cancellationToken) { this._storage.Save(); - return Task.CompletedTask; + return Unit.Task; } } } \ No newline at end of file diff --git a/Eve-O-Preview/Mediator/Handlers/Services/StartStopServiceHandler.cs b/Eve-O-Preview/Mediator/Handlers/Services/StartStopServiceHandler.cs index 2b34cdb..896ba68 100644 --- a/Eve-O-Preview/Mediator/Handlers/Services/StartStopServiceHandler.cs +++ b/Eve-O-Preview/Mediator/Handlers/Services/StartStopServiceHandler.cs @@ -15,18 +15,18 @@ namespace EveOPreview.Mediator.Handlers.Services this._manager = manager; } - public Task Handle(StartService message, CancellationToken cancellationToken) + public Task Handle(StartService message, CancellationToken cancellationToken) { this._manager.Start(); - return Task.CompletedTask; + return Unit.Task; } - public Task Handle(StopService message, CancellationToken cancellationToken) + public Task Handle(StopService message, CancellationToken cancellationToken) { this._manager.Stop(); - return Task.CompletedTask; + return Unit.Task; } } } \ No newline at end of file diff --git a/Eve-O-Preview/Program.cs b/Eve-O-Preview/Program.cs index eb723f5..f681020 100644 --- a/Eve-O-Preview/Program.cs +++ b/Eve-O-Preview/Program.cs @@ -4,7 +4,6 @@ using System.Windows.Forms; using EveOPreview.Configuration; using EveOPreview.Presenters; using EveOPreview.Services; -using EveOPreview.UI; using EveOPreview.View; using MediatR; @@ -80,8 +79,7 @@ namespace EveOPreview // MediatR container.Register(); - container.RegisterInstance(t => container.Resolve(t)); - container.RegisterInstance(t => container.ResolveAll(t)); + container.RegisterInstance(t => container.Resolve(t)); container.Register(typeof(INotificationHandler<>), typeof(Program).Assembly); container.Register(typeof(IRequestHandler<>), typeof(Program).Assembly); container.Register(typeof(IRequestHandler<,>), typeof(Program).Assembly); diff --git a/Eve-O-Preview/packages.config b/Eve-O-Preview/packages.config index b04a818..7b4d3e0 100644 --- a/Eve-O-Preview/packages.config +++ b/Eve-O-Preview/packages.config @@ -1,8 +1,9 @@  - - - - - + + + + + + \ No newline at end of file From ea2445eeb25f519d77dd0101478a3866ffae9151 Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 4 Mar 2019 21:37:03 +0200 Subject: [PATCH 07/27] 142: Add a mouse action to switch out to the last used external app --- .../Implementation/ThumbnailManager.cs | 33 ++++++++++++++----- .../View/Implementation/ThumbnailView.cs | 15 ++++++--- .../View/Interface/IThumbnailView.cs | 2 +- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs b/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs index 58a562f..241e91b 100644 --- a/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs +++ b/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs @@ -32,6 +32,7 @@ namespace EveOPreview.Services private readonly Dictionary _thumbnailViews; private (IntPtr Handle, string Title) _activeClient; + private IntPtr _externalApplication; private readonly object _locationChangeNotificationSyncRoot; private (IntPtr Handle, string Title, string ActiveClient, Point Location, int Delay) _enqueuedLocationChangeNotification; @@ -181,6 +182,9 @@ namespace EveOPreview.Services IntPtr foregroundWindowHandle = this._windowManager.GetForegroundWindowHandle(); string foregroundWindowTitle = null; + // Check if the foreground window handle is one of the known handles for client windows or their thumbnails + bool isClientWindow = this.IsClientWindowActive(foregroundWindowHandle); + if (foregroundWindowHandle == this._activeClient.Handle) { foregroundWindowTitle = this._activeClient.Title; @@ -190,6 +194,10 @@ namespace EveOPreview.Services // This code will work only on Alt+Tab switch between clients foregroundWindowTitle = foregroundView.Title; } + else if (!isClientWindow) + { + this._externalApplication = foregroundWindowHandle; + } // No need to minimize EVE clients when switching out to non-EVE window (like thumbnail) if (!string.IsNullOrEmpty(foregroundWindowTitle)) @@ -197,7 +205,7 @@ namespace EveOPreview.Services this.SwitchActiveClient(foregroundWindowHandle, foregroundWindowTitle); } - bool hideAllThumbnails = this._configuration.HideThumbnailsOnLostFocus && !this.IsClientWindowActive(foregroundWindowHandle); + bool hideAllThumbnails = this._configuration.HideThumbnailsOnLostFocus && !isClientWindow; this._refreshCycleCount++; @@ -324,10 +332,10 @@ namespace EveOPreview.Services this._ignoreViewEvents = true; } - private void SwitchActiveClient(IntPtr foregroungClientHandle, string foregroundClientTitle) + private void SwitchActiveClient(IntPtr foregroundClientHandle, string foregroundClientTitle) { // Check if any actions are needed - if (this._activeClient.Handle == foregroungClientHandle) + if (this._activeClient.Handle == foregroundClientHandle) { return; } @@ -338,7 +346,7 @@ namespace EveOPreview.Services this._windowManager.MinimizeWindow(this._activeClient.Handle, false); } - this._activeClient = (foregroungClientHandle, foregroundClientTitle); + this._activeClient = (foregroundClientHandle, foregroundClientTitle); } private void ThumbnailViewFocused(IntPtr id) @@ -398,15 +406,22 @@ namespace EveOPreview.Services }); } - private void ThumbnailDeactivated(IntPtr id) + private void ThumbnailDeactivated(IntPtr id, bool switchOut) { - if (!this._thumbnailViews.TryGetValue(id, out IThumbnailView view)) + if (switchOut) { - return; + this._windowManager.ActivateWindow(this._externalApplication); } + else + { + if (!this._thumbnailViews.TryGetValue(id, out IThumbnailView view)) + { + return; + } - this._windowManager.MinimizeWindow(view.Id, true); - this.RefreshThumbnails(); + this._windowManager.MinimizeWindow(view.Id, true); + this.RefreshThumbnails(); + } } private async void ThumbnailViewResized(IntPtr id) diff --git a/Eve-O-Preview/View/Implementation/ThumbnailView.cs b/Eve-O-Preview/View/Implementation/ThumbnailView.cs index 94b1f72..bc5cf0f 100644 --- a/Eve-O-Preview/View/Implementation/ThumbnailView.cs +++ b/Eve-O-Preview/View/Implementation/ThumbnailView.cs @@ -104,7 +104,7 @@ namespace EveOPreview.View public Action ThumbnailActivated { get; set; } - public Action ThumbnailDeactivated { get; set; } + public Action ThumbnailDeactivated { get; set; } public new void Show() { @@ -159,7 +159,7 @@ namespace EveOPreview.View // Overlay opacity settings // Of the thumbnail's opacity is almost full then set the overlay's one to - // full. Otherwise set it to half of the thumnail opacity + // full. Otherwise set it to half of the thumbnail opacity // Opacity value is stored even if the overlay is not displayed atm this._overlay.Opacity = this.Opacity > 0.9 ? 1.0 : 1.0 - (1.0 - this.Opacity) / 2; } @@ -231,7 +231,7 @@ namespace EveOPreview.View // First change size, THEN move the window // Otherwise there is a chance to fail in a loop - // Zoom requied -> Moved the windows 1st -> Focus is lost -> Window is moved back -> Focus is back on -> Zoom required -> ... + // Zoom required -> Moved the windows 1st -> Focus is lost -> Window is moved back -> Focus is back on -> Zoom required -> ... this.MaximumSize = new Size(0, 0); this.Size = new Size(newWidth, newHeight); @@ -439,7 +439,12 @@ namespace EveOPreview.View { if (Control.ModifierKeys == Keys.Control) { - this.ThumbnailDeactivated?.Invoke(this.Id); + this.ThumbnailDeactivated?.Invoke(this.Id, false); + } + else + if (Control.ModifierKeys == (Keys.Control | Keys.Shift)) + { + this.ThumbnailDeactivated?.Invoke(this.Id, true); } else { @@ -490,7 +495,7 @@ namespace EveOPreview.View #endregion #region Custom Mouse mode - // This pair of methods saves/restores certain window propeties + // This pair of methods saves/restores certain window properties // Methods are used to remove the 'Zoom' effect (if any) when the // custom resize/move mode is activated // Methods are kept on this level because moving to the presenter diff --git a/Eve-O-Preview/View/Interface/IThumbnailView.cs b/Eve-O-Preview/View/Interface/IThumbnailView.cs index 3d7e593..00cac7d 100644 --- a/Eve-O-Preview/View/Interface/IThumbnailView.cs +++ b/Eve-O-Preview/View/Interface/IThumbnailView.cs @@ -36,6 +36,6 @@ namespace EveOPreview.View Action ThumbnailLostFocus { get; set; } Action ThumbnailActivated { get; set; } - Action ThumbnailDeactivated { get; set; } + Action ThumbnailDeactivated { get; set; } } } \ No newline at end of file From cec2d3d90120fa838f1681b33facc8a069a49c1a Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 4 Mar 2019 21:39:11 +0200 Subject: [PATCH 08/27] Simplify thumbnail activation code (more efficient Task call) --- .../Services/Implementation/ThumbnailManager.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs b/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs index 241e91b..a7bb0c9 100644 --- a/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs +++ b/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs @@ -396,14 +396,13 @@ namespace EveOPreview.Services { this._windowManager.ActivateWindow(view.Id); }) - .ConfigureAwait(true) - .GetAwaiter() - .OnCompleted(() => + .ContinueWith((task) => { + // This code should be executed on UI thread this.SwitchActiveClient(view.Id, view.Title); this.UpdateClientLayouts(); this.RefreshThumbnails(); - }); + }, TaskScheduler.FromCurrentSynchronizationContext()); } private void ThumbnailDeactivated(IntPtr id, bool switchOut) @@ -683,9 +682,9 @@ namespace EveOPreview.Services } // Quick sanity check that the window is not minimized - private bool IsValidWindowPosition(int letf, int top, int width, int height) + private bool IsValidWindowPosition(int left, int top, int width, int height) { - return (letf > ThumbnailManager.WINDOW_POSITION_THRESHOLD_LOW) && (letf < ThumbnailManager.WINDOW_POSITION_THRESHOLD_HIGH) + return (left > ThumbnailManager.WINDOW_POSITION_THRESHOLD_LOW) && (left < ThumbnailManager.WINDOW_POSITION_THRESHOLD_HIGH) && (top > ThumbnailManager.WINDOW_POSITION_THRESHOLD_LOW) && (top < ThumbnailManager.WINDOW_POSITION_THRESHOLD_HIGH) && (width > ThumbnailManager.WINDOW_SIZE_THRESHOLD) && (height > ThumbnailManager.WINDOW_SIZE_THRESHOLD); } From 9e5738b74a308a1ca996e0491adaf15d48bfa6dd Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 4 Mar 2019 21:50:25 +0200 Subject: [PATCH 09/27] 143: Add a simple nag message box for Beta builds --- Eve-O-Preview/Program.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Eve-O-Preview/Program.cs b/Eve-O-Preview/Program.cs index f681020..430e490 100644 --- a/Eve-O-Preview/Program.cs +++ b/Eve-O-Preview/Program.cs @@ -17,12 +17,20 @@ namespace EveOPreview [STAThread] static void Main() { +#if DEBUG + var expirationDate = new DateTime(2019, 5, 1); + if (DateTime.Today >= expirationDate) + { + MessageBox.Show(@"This Beta version is expired. Please download a new build at https://github.com/Phrynohyas/eve-o-preview/releases", @"EVE-O Preview", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } +#endif + // The very usual Mutex-based single-instance screening // 'token' variable is used to store reference to the instance Mutex // during the app lifetime object token = Program.GetInstanceToken(); - // If it was not possible to aquire the app token then another app instance is already running + // If it was not possible to acquire the app token then another app instance is already running // Nothing to do here if (token == null) { From 013cd9ba04857b360a552f216170833794ad51d3 Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 4 Mar 2019 22:09:58 +0200 Subject: [PATCH 10/27] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 84fbf39..03ac55d 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ Mouse gestures are applied to the thumbnail window currently being hovered over. | --- | --- | | Activate the EVE Online client and bring it to front | Click the thumbnail | | Minimize the EVE Online client | Hold Control key and click the thumbnail | +| Switch to the last used application that is not an EVE Online client | Hold Control + Shift keys and click any thumbnail | | Move thumbnail to a new position | Press right mouse button and move the mouse | | Adjust thumbnail height | Press both left and right mouse buttons and move the mouse up or down | | Adjust thumbnail width | Press both left and right mouse buttons and move the mouse left or right | From cfcc5d085c465c0a13419dbd73ca91e47ef8bb74 Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 4 Mar 2019 22:37:10 +0200 Subject: [PATCH 11/27] Fix for the detection of the currently active non-EVE app --- Eve-O-Preview/Services/Implementation/ThumbnailManager.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs b/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs index a7bb0c9..005927c 100644 --- a/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs +++ b/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs @@ -196,7 +196,12 @@ namespace EveOPreview.Services } else if (!isClientWindow) { - this._externalApplication = foregroundWindowHandle; + // Under some circumstances Foreground WindowHandle can be zero + // (f.e. when Thumbnail is silently stealing focus from the currently open app) + if (foregroundWindowHandle != IntPtr.Zero) + { + this._externalApplication = foregroundWindowHandle; + } } // No need to minimize EVE clients when switching out to non-EVE window (like thumbnail) From 687520d2eb84a74476b8c33301d15eb4c0438cab Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 29 Apr 2019 19:51:47 +0300 Subject: [PATCH 12/27] Display thumbnails even when Aero is disabled --- .../Implementation/ThumbnailConfiguration.cs | 5 + .../Interface/IThumbnailConfiguration.cs | 2 + Eve-O-Preview/Eve-O-Preview.csproj | 12 +- Eve-O-Preview/Program.cs | 10 +- .../Services/Implementation/DwmThumbnail.cs | 6 +- .../Implementation/ThumbnailManager.cs | 2 +- .../Services/Implementation/WindowManager.cs | 41 +++- .../Services/Interface/IWindowManager.cs | 4 +- ...piNativeMethods.cs => DwmNativeMethods.cs} | 2 +- .../Services/Interop/Gdi32NativeMethods.cs | 28 +++ .../Services/Interop/User32NativeMethods.cs | 14 +- .../View/Implementation/LiveThumbnailView.cs | 48 ++++ .../View/Implementation/MainForm.resx | 213 ++++++++++++++++++ .../Implementation/StaticThumbnailImage.cs | 23 ++ .../Implementation/StaticThumbnailView.cs | 49 ++++ .../Implementation/ThumbnailView.Designer.cs | 3 +- .../View/Implementation/ThumbnailView.cs | 153 ++++++------- .../Implementation/ThumbnailViewFactory.cs | 9 +- 18 files changed, 519 insertions(+), 105 deletions(-) rename Eve-O-Preview/Services/Interop/{DwmApiNativeMethods.cs => DwmNativeMethods.cs} (95%) create mode 100644 Eve-O-Preview/Services/Interop/Gdi32NativeMethods.cs create mode 100644 Eve-O-Preview/View/Implementation/LiveThumbnailView.cs create mode 100644 Eve-O-Preview/View/Implementation/StaticThumbnailImage.cs create mode 100644 Eve-O-Preview/View/Implementation/StaticThumbnailView.cs diff --git a/Eve-O-Preview/Configuration/Implementation/ThumbnailConfiguration.cs b/Eve-O-Preview/Configuration/Implementation/ThumbnailConfiguration.cs index eac17e9..79fd030 100644 --- a/Eve-O-Preview/Configuration/Implementation/ThumbnailConfiguration.cs +++ b/Eve-O-Preview/Configuration/Implementation/ThumbnailConfiguration.cs @@ -24,6 +24,8 @@ namespace EveOPreview.Configuration.Implementation this.MinimizeToTray = false; this.ThumbnailRefreshPeriod = 500; + this.EnableCompatibilityMode = false; + this.ThumbnailOpacity = 0.5; this.EnableClientLayoutTracking = false; @@ -54,6 +56,9 @@ namespace EveOPreview.Configuration.Implementation public bool MinimizeToTray { get; set; } public int ThumbnailRefreshPeriod { get; set; } + [JsonProperty("PotatoMode")] + public bool EnableCompatibilityMode { get; set; } + [JsonProperty("ThumbnailsOpacity")] public double ThumbnailOpacity { get; set; } diff --git a/Eve-O-Preview/Configuration/Interface/IThumbnailConfiguration.cs b/Eve-O-Preview/Configuration/Interface/IThumbnailConfiguration.cs index 565e395..3cb1158 100644 --- a/Eve-O-Preview/Configuration/Interface/IThumbnailConfiguration.cs +++ b/Eve-O-Preview/Configuration/Interface/IThumbnailConfiguration.cs @@ -8,6 +8,8 @@ namespace EveOPreview.Configuration bool MinimizeToTray { get; set; } int ThumbnailRefreshPeriod { get; set; } + bool EnableCompatibilityMode { get; set; } + double ThumbnailOpacity { get; set; } bool EnableClientLayoutTracking { get; set; } diff --git a/Eve-O-Preview/Eve-O-Preview.csproj b/Eve-O-Preview/Eve-O-Preview.csproj index c469a1f..5e9d4aa 100644 --- a/Eve-O-Preview/Eve-O-Preview.csproj +++ b/Eve-O-Preview/Eve-O-Preview.csproj @@ -147,6 +147,7 @@ + @@ -157,6 +158,15 @@ + + Form + + + Component + + + Form + @@ -212,7 +222,7 @@ ThumbnailView.cs - + diff --git a/Eve-O-Preview/Program.cs b/Eve-O-Preview/Program.cs index 430e490..16fc709 100644 --- a/Eve-O-Preview/Program.cs +++ b/Eve-O-Preview/Program.cs @@ -18,7 +18,7 @@ namespace EveOPreview static void Main() { #if DEBUG - var expirationDate = new DateTime(2019, 5, 1); + var expirationDate = new DateTime(2019, 5, 15); if (DateTime.Today >= expirationDate) { MessageBox.Show(@"This Beta version is expired. Please download a new build at https://github.com/Phrynohyas/eve-o-preview/releases", @"EVE-O Preview", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); @@ -105,9 +105,11 @@ namespace EveOPreview IApplicationController controller = new ApplicationController(container); // UI classes - controller.RegisterView() - .RegisterView() - .RegisterInstance(new ApplicationContext()); + controller.RegisterView(); + controller.RegisterView(); + + controller.RegisterView(); + controller.RegisterInstance(new ApplicationContext()); return controller; } diff --git a/Eve-O-Preview/Services/Implementation/DwmThumbnail.cs b/Eve-O-Preview/Services/Implementation/DwmThumbnail.cs index 76b9388..873ded8 100644 --- a/Eve-O-Preview/Services/Implementation/DwmThumbnail.cs +++ b/Eve-O-Preview/Services/Implementation/DwmThumbnail.cs @@ -36,7 +36,7 @@ namespace EveOPreview.Services.Implementation try { - this._handle = DwmApiNativeMethods.DwmRegisterThumbnail(destination, source); + this._handle = DwmNativeMethods.DwmRegisterThumbnail(destination, source); } catch (ArgumentException) { @@ -63,7 +63,7 @@ namespace EveOPreview.Services.Implementation try { - DwmApiNativeMethods.DwmUnregisterThumbnail(this._handle); + DwmNativeMethods.DwmUnregisterThumbnail(this._handle); } catch (ArgumentException) { @@ -88,7 +88,7 @@ namespace EveOPreview.Services.Implementation try { - DwmApiNativeMethods.DwmUpdateThumbnailProperties(this._handle, this._properties); + DwmNativeMethods.DwmUpdateThumbnailProperties(this._handle, this._properties); } catch (ArgumentException) { diff --git a/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs b/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs index 005927c..9f55ac2 100644 --- a/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs +++ b/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs @@ -10,7 +10,7 @@ using MediatR; namespace EveOPreview.Services { - class ThumbnailManager : IThumbnailManager + sealed class ThumbnailManager : IThumbnailManager { #region Private constants private const int WINDOW_POSITION_THRESHOLD_LOW = -10_000; diff --git a/Eve-O-Preview/Services/Implementation/WindowManager.cs b/Eve-O-Preview/Services/Implementation/WindowManager.cs index a2096f1..b7e7135 100644 --- a/Eve-O-Preview/Services/Implementation/WindowManager.cs +++ b/Eve-O-Preview/Services/Implementation/WindowManager.cs @@ -1,14 +1,19 @@ using System; +using System.Drawing; using System.Runtime.InteropServices; using EveOPreview.Services.Interop; namespace EveOPreview.Services.Implementation { - class WindowManager : IWindowManager + sealed class WindowManager : IWindowManager { + #region Private constants + private const int WINDOW_SIZE_THRESHOLD = 300; + #endregion + public WindowManager() { - this.IsCompositionEnabled = DwmApiNativeMethods.DwmIsCompositionEnabled(); + this.IsCompositionEnabled = DwmNativeMethods.DwmIsCompositionEnabled(); } public bool IsCompositionEnabled { get; } @@ -63,12 +68,42 @@ namespace EveOPreview.Services.Implementation return User32NativeMethods.IsIconic(handle); } - public IDwmThumbnail RegisterThumbnail(IntPtr destination, IntPtr source) + public IDwmThumbnail GetLiveThumbnail(IntPtr destination, IntPtr source) { IDwmThumbnail thumbnail = new DwmThumbnail(this); thumbnail.Register(destination, source); return thumbnail; } + + public Image GetStaticThumbnail(IntPtr source) + { + var sourceContext = User32NativeMethods.GetDC(source); + + User32NativeMethods.GetClientRect(source, out RECT windowRect); + + var width = windowRect.Right - windowRect.Left; + var height = windowRect.Bottom - windowRect.Top; + + // Check if there is anything to make thumbnail of + if ((width < WINDOW_SIZE_THRESHOLD) || (height < WINDOW_SIZE_THRESHOLD)) + { + return null; + } + + var destContext = Gdi32NativeMethods.CreateCompatibleDC(sourceContext); + var bitmap = Gdi32NativeMethods.CreateCompatibleBitmap(sourceContext, width, height); + + var oldBitmap = Gdi32NativeMethods.SelectObject(destContext, bitmap); + Gdi32NativeMethods.BitBlt(destContext, 0, 0, width, height, sourceContext, 0, 0, Gdi32NativeMethods.SRCCOPY); + Gdi32NativeMethods.SelectObject(destContext, oldBitmap); + Gdi32NativeMethods.DeleteDC(destContext); + User32NativeMethods.ReleaseDC(source, sourceContext); + + Image image = Image.FromHbitmap(bitmap); + Gdi32NativeMethods.DeleteObject(bitmap); + + return image; + } } } \ No newline at end of file diff --git a/Eve-O-Preview/Services/Interface/IWindowManager.cs b/Eve-O-Preview/Services/Interface/IWindowManager.cs index e482a16..50a01b6 100644 --- a/Eve-O-Preview/Services/Interface/IWindowManager.cs +++ b/Eve-O-Preview/Services/Interface/IWindowManager.cs @@ -1,4 +1,5 @@ using System; +using System.Drawing; namespace EveOPreview.Services { @@ -15,6 +16,7 @@ namespace EveOPreview.Services (int Left, int Top, int Right, int Bottom) GetWindowPosition(IntPtr handle); bool IsWindowMinimized(IntPtr handle); - IDwmThumbnail RegisterThumbnail(IntPtr destination, IntPtr source); + IDwmThumbnail GetLiveThumbnail(IntPtr destination, IntPtr source); + Image GetStaticThumbnail(IntPtr source); } } \ No newline at end of file diff --git a/Eve-O-Preview/Services/Interop/DwmApiNativeMethods.cs b/Eve-O-Preview/Services/Interop/DwmNativeMethods.cs similarity index 95% rename from Eve-O-Preview/Services/Interop/DwmApiNativeMethods.cs rename to Eve-O-Preview/Services/Interop/DwmNativeMethods.cs index 90794e0..5cb7325 100644 --- a/Eve-O-Preview/Services/Interop/DwmApiNativeMethods.cs +++ b/Eve-O-Preview/Services/Interop/DwmNativeMethods.cs @@ -4,7 +4,7 @@ using System.Drawing; namespace EveOPreview.Services.Interop { - static class DwmApiNativeMethods + static class DwmNativeMethods { [DllImport("dwmapi.dll", PreserveSig = false)] public static extern void DwmEnableBlurBehindWindow(IntPtr hWnd, DWM_BLURBEHIND pBlurBehind); diff --git a/Eve-O-Preview/Services/Interop/Gdi32NativeMethods.cs b/Eve-O-Preview/Services/Interop/Gdi32NativeMethods.cs new file mode 100644 index 0000000..f966511 --- /dev/null +++ b/Eve-O-Preview/Services/Interop/Gdi32NativeMethods.cs @@ -0,0 +1,28 @@ +using System; +using System.Runtime.InteropServices; + +namespace EveOPreview.Services.Interop +{ + static class Gdi32NativeMethods + { + public const int SRCCOPY = 13369376; + + [DllImport("gdi32.dll")] + public static extern IntPtr CreateCompatibleDC(IntPtr hdc); + + [DllImport("gdi32.dll")] + public static extern bool DeleteDC(IntPtr hdc); + + [DllImport("gdi32.dll")] + public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int width, int height); + + [DllImport("gdi32.dll")] + public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hObject); + + [DllImport("gdi32.dll")] + public static extern bool DeleteObject(IntPtr hObject); + + [DllImport("gdi32.dll")] + public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hObjectSource, int nXSrc, int nYSrc, int dwRop); + } +} diff --git a/Eve-O-Preview/Services/Interop/User32NativeMethods.cs b/Eve-O-Preview/Services/Interop/User32NativeMethods.cs index fbde187..6adc97a 100644 --- a/Eve-O-Preview/Services/Interop/User32NativeMethods.cs +++ b/Eve-O-Preview/Services/Interop/User32NativeMethods.cs @@ -24,7 +24,10 @@ namespace EveOPreview.Services.Interop public static extern int GetWindowLong(IntPtr hWnd, int nIndex); [DllImport("user32.dll")] - public static extern int GetWindowRect(IntPtr hwnd, out RECT rect); + public static extern int GetWindowRect(IntPtr hWnd, out RECT rect); + + [DllImport("user32.dll")] + public static extern bool GetClientRect(IntPtr hWnd, out RECT rect); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] @@ -42,5 +45,14 @@ namespace EveOPreview.Services.Interop [DllImport("user32.dll")] public static extern bool IsZoomed(IntPtr hWnd); + + [DllImport("user32.dll")] + public static extern IntPtr GetWindowDC(IntPtr hWnd); + + [DllImport("user32.dll")] + public static extern IntPtr GetDC(IntPtr hWnd); + + [DllImport("user32.dll")] + public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hdc); } } \ No newline at end of file diff --git a/Eve-O-Preview/View/Implementation/LiveThumbnailView.cs b/Eve-O-Preview/View/Implementation/LiveThumbnailView.cs new file mode 100644 index 0000000..543c94d --- /dev/null +++ b/Eve-O-Preview/View/Implementation/LiveThumbnailView.cs @@ -0,0 +1,48 @@ +using System; +using EveOPreview.Services; + +namespace EveOPreview.View +{ + sealed class LiveThumbnailView : ThumbnailView + { + #region Private fields + private IDwmThumbnail _thumbnail; + #endregion + + public LiveThumbnailView(IWindowManager windowManager) + : base(windowManager) + { + } + + public override void Close() + { + this._thumbnail?.Unregister(); + base.Close(); + } + + protected override void RefreshThumbnail(bool forceRefresh) + { + // To prevent flickering the old broken thumbnail is removed AFTER the new shiny one is created + IDwmThumbnail obsoleteThumbnail = forceRefresh ? this._thumbnail : null; + + if ((this._thumbnail == null) || forceRefresh) + { + this.RegisterThumbnail(); + } + + obsoleteThumbnail?.Unregister(); + } + + protected override void ResizeThumbnail(int baseWidth, int baseHeight, int highlightWidthTop, int highlightWidthRight, int highlightWidthBottom, int highlightWidthLeft) + { + this._thumbnail.Move(0 + highlightWidthLeft, 0 + highlightWidthTop, baseWidth - highlightWidthRight, baseHeight - highlightWidthBottom); + this._thumbnail.Update(); + } + + private void RegisterThumbnail() + { + this._thumbnail = this.WindowManager.GetLiveThumbnail(this.Handle, this.Id); + this._thumbnail.Update(); + } + } +} diff --git a/Eve-O-Preview/View/Implementation/MainForm.resx b/Eve-O-Preview/View/Implementation/MainForm.resx index 426d527..0537524 100644 --- a/Eve-O-Preview/View/Implementation/MainForm.resx +++ b/Eve-O-Preview/View/Implementation/MainForm.resx @@ -141,12 +141,72 @@ True + + False + + + True + + + True + + + False + + + True + + + False + + + True + + + False + + + True + + + False + + + True + False True + + False + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + True @@ -180,6 +240,39 @@ True + + False + + + True + + + False + + + True + + + False + + + True + + + True + + + True + + + True + + + False + + + True + False @@ -216,6 +309,12 @@ True + + False + + + True + False @@ -225,6 +324,54 @@ True + + False + + + True + + + True + + + True + + + False + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + True @@ -276,6 +423,27 @@ True + + False + + + True + + + True + + + True + + + True + + + True + + + True + True @@ -303,6 +471,21 @@ True + + False + + + True + + + True + + + False + + + True + True @@ -324,6 +507,36 @@ True + + False + + + True + + + False + + + True + + + False + + + True + + + True + + + False + + + True + + + True + False diff --git a/Eve-O-Preview/View/Implementation/StaticThumbnailImage.cs b/Eve-O-Preview/View/Implementation/StaticThumbnailImage.cs new file mode 100644 index 0000000..f5ec500 --- /dev/null +++ b/Eve-O-Preview/View/Implementation/StaticThumbnailImage.cs @@ -0,0 +1,23 @@ +using System; +using System.Windows.Forms; + +namespace EveOPreview.View +{ + sealed class StaticThumbnailImage : PictureBox + { + protected override void WndProc(ref Message m) + { + const int WM_NCHITTEST = 0x0084; + const int HTTRANSPARENT = (-1); + + if (m.Msg == WM_NCHITTEST) + { + m.Result = (IntPtr)HTTRANSPARENT; + } + else + { + base.WndProc(ref m); + } + } + } +} diff --git a/Eve-O-Preview/View/Implementation/StaticThumbnailView.cs b/Eve-O-Preview/View/Implementation/StaticThumbnailView.cs new file mode 100644 index 0000000..cabe743 --- /dev/null +++ b/Eve-O-Preview/View/Implementation/StaticThumbnailView.cs @@ -0,0 +1,49 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using EveOPreview.Services; + +namespace EveOPreview.View +{ + sealed class StaticThumbnailView : ThumbnailView + { + #region Private fields + private readonly PictureBox _thumbnail; + #endregion + + public StaticThumbnailView(IWindowManager windowManager) + : base(windowManager) + { + this._thumbnail = new StaticThumbnailImage + { + TabStop = false, + SizeMode = PictureBoxSizeMode.StretchImage, + Location = new Point(0, 0), + Size = new Size(this.ClientSize.Width, this.ClientSize.Height) + }; + this.Controls.Add(this._thumbnail); + } + + protected override void RefreshThumbnail(bool forceRefresh) + { + if (!forceRefresh) + { + return; + } + + var thumbnail = this.WindowManager.GetStaticThumbnail(this.Id); + if (thumbnail != null) + { + var oldImage = this._thumbnail.Image; + this._thumbnail.Image = thumbnail; + oldImage?.Dispose(); + } + } + + protected override void ResizeThumbnail(int baseWidth, int baseHeight, int highlightWidthTop, int highlightWidthRight, int highlightWidthBottom, int highlightWidthLeft) + { + this._thumbnail.Location = new Point(0 + highlightWidthLeft, 0 + highlightWidthTop); + this._thumbnail.Size = new Size(baseWidth - highlightWidthLeft - highlightWidthRight, baseHeight - highlightWidthTop - highlightWidthBottom); + } + } +} \ No newline at end of file diff --git a/Eve-O-Preview/View/Implementation/ThumbnailView.Designer.cs b/Eve-O-Preview/View/Implementation/ThumbnailView.Designer.cs index c0540fd..697d424 100644 --- a/Eve-O-Preview/View/Implementation/ThumbnailView.Designer.cs +++ b/Eve-O-Preview/View/Implementation/ThumbnailView.Designer.cs @@ -19,11 +19,12 @@ namespace EveOPreview.View // ThumbnailView // this.AccessibleRole = System.Windows.Forms.AccessibleRole.None; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; this.BackColor = System.Drawing.Color.Black; + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; this.ClientSize = new System.Drawing.Size(153, 89); this.ControlBox = false; + this.DoubleBuffered = true; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow; this.MaximizeBox = false; this.MinimizeBox = false; diff --git a/Eve-O-Preview/View/Implementation/ThumbnailView.cs b/Eve-O-Preview/View/Implementation/ThumbnailView.cs index bc5cf0f..7755687 100644 --- a/Eve-O-Preview/View/Implementation/ThumbnailView.cs +++ b/Eve-O-Preview/View/Implementation/ThumbnailView.cs @@ -7,26 +7,25 @@ using EveOPreview.UI.Hotkeys; namespace EveOPreview.View { - public partial class ThumbnailView : Form, IThumbnailView + public abstract partial class ThumbnailView : Form, IThumbnailView { #region Private constants private const int RESIZE_EVENT_TIMEOUT = 500; #endregion #region Private fields - private readonly IWindowManager _windowManager; private readonly ThumbnailOverlay _overlay; - private IDwmThumbnail _thumbnail; // Part of the logic (namely current size / position management) // was moved to the view due to the performance reasons private bool _isOverlayVisible; private bool _isTopMost; + private bool _isHighlightEnabled; + private bool _isHighlightRequested; + private int _highlightWidth; private bool _isLocationChanged; private bool _isSizeChanged; private bool _isCustomMouseModeActive; - private bool _isHighlightEnabled; - private int _highlightWidth; private DateTime _suppressResizeEventsTimestamp; private Size _baseZoomSize; private Point _baseZoomLocation; @@ -36,29 +35,32 @@ namespace EveOPreview.View private HotkeyHandler _hotkeyHandler; #endregion - public ThumbnailView(IWindowManager windowManager) + protected ThumbnailView(IWindowManager windowManager) { this.SuppressResizeEvent(); - this._windowManager = windowManager; + this.WindowManager = windowManager; this.IsActive = false; this.IsOverlayEnabled = false; this._isOverlayVisible = false; this._isTopMost = false; + this._isHighlightEnabled = false; this._isLocationChanged = true; this._isSizeChanged = true; this._isCustomMouseModeActive = false; - this._isHighlightEnabled = false; + this._isHighlightRequested = false; InitializeComponent(); this._overlay = new ThumbnailOverlay(this, this.MouseDown_Handler); } + protected IWindowManager WindowManager { get; } + public IntPtr Id { get; set; } public string Title @@ -131,12 +133,11 @@ namespace EveOPreview.View base.Hide(); } - public new void Close() + public new virtual void Close() { this.SuppressResizeEvent(); this.IsActive = false; - this._thumbnail?.Unregister(); this._overlay.Close(); base.Close(); } @@ -177,9 +178,6 @@ namespace EveOPreview.View this.SuppressResizeEvent(); this.FormBorderStyle = style; - - // Notify about possible contents position change - this._isSizeChanged = true; } public void SetTopMost(bool enableTopmost) @@ -198,20 +196,20 @@ namespace EveOPreview.View public void SetHighlight(bool enabled, Color color, int width) { - if (this._isHighlightEnabled == enabled) + if (this._isHighlightRequested == enabled) { return; } if (enabled) { - this._isHighlightEnabled = true; + this._isHighlightRequested = true; this._highlightWidth = width; this.BackColor = color; } else { - this._isHighlightEnabled = false; + this._isHighlightRequested = false; this.BackColor = SystemColors.Control; } @@ -305,69 +303,31 @@ namespace EveOPreview.View public void Refresh(bool forceRefresh) { - // To prevent flickering the old broken thumbnail is removed AFTER the new shiny one is created - IDwmThumbnail obsoleteThumbnail = forceRefresh ? this._thumbnail : null; + this.RefreshThumbnail(forceRefresh); + this.HighlightThumbnail(forceRefresh || this._isSizeChanged); + this.RefreshOverlay(forceRefresh || this._isSizeChanged || this._isLocationChanged); - if ((this._thumbnail == null) || forceRefresh) - { - this.RegisterThumbnail(); - } - - bool sizeChanged = this._isSizeChanged || forceRefresh; - bool locationChanged = this._isLocationChanged || forceRefresh; - - if (sizeChanged) - { - this.RecalculateThumbnailSize(); - - this.UpdateThumbnail(); - - this._isSizeChanged = false; - } - - obsoleteThumbnail?.Unregister(); - - this._overlay.EnableOverlayLabel(this.IsOverlayEnabled); - - if (!this._isOverlayVisible) - { - // One-time action to show the Overlay before it is set up - // Otherwise its position won't be set - this._overlay.Show(); - this._isOverlayVisible = true; - } - else - { - if (!(sizeChanged || locationChanged)) - { - // No need to adjust in the overlay location if it is already visible and properly set - return; - } - } - - Size overlaySize = this.ClientSize; - Point overlayLocation = this.Location; - - int borderWidth = (this.Size.Width - this.ClientSize.Width) / 2; - overlayLocation.X += borderWidth; - overlayLocation.Y += (this.Size.Height - this.ClientSize.Height) - borderWidth; - - this._isLocationChanged = false; - this._overlay.Size = overlaySize; - this._overlay.Location = overlayLocation; - this._overlay.Refresh(); + this._isSizeChanged = false; } - private void RecalculateThumbnailSize() + protected abstract void RefreshThumbnail(bool forceRefresh); + + protected abstract void ResizeThumbnail(int baseWidth, int baseHeight, int highlightWidthTop, int highlightWidthRight, int highlightWidthBottom, int highlightWidthLeft); + + private void HighlightThumbnail(bool forceRefresh) { - // This approach would work only for square-shaped thumbnail window - // To get PROPER results we have to do some crazy math - //int delta = this._isHighlightEnabled ? this._highlightWidth : 0; - //this._thumbnail.rcDestination = new RECT(0 + delta, 0 + delta, this.ClientSize.Width - delta, this.ClientSize.Height - delta); - if (!this._isHighlightEnabled) + if (!forceRefresh && (this._isHighlightRequested == this._isHighlightEnabled)) { - //No highlighting enabled, so no odd math required - this._thumbnail.Move(0, 0, this.ClientSize.Width, this.ClientSize.Height); + // Nothing to do here + return; + } + + this._isHighlightEnabled = this._isHighlightRequested; + + if (!this._isHighlightRequested) + { + //No highlighting enabled, so no math required + this.ResizeThumbnail(this.ClientSize.Width, this.ClientSize.Height, 0, 0, 0, 0); return; } @@ -381,7 +341,38 @@ namespace EveOPreview.View int highlightWidthLeft = (baseWidth - actualWidth) / 2; int highlightWidthRight = baseWidth - actualWidth - highlightWidthLeft; - this._thumbnail.Move(0 + highlightWidthLeft, 0 + this._highlightWidth, baseWidth - highlightWidthRight, baseHeight - this._highlightWidth); + this.ResizeThumbnail(this.ClientSize.Width, this.ClientSize.Height, this._highlightWidth, highlightWidthRight, this._highlightWidth, highlightWidthLeft); + } + + private void RefreshOverlay(bool forceRefresh) + { + if (this._isOverlayVisible && !forceRefresh) + { + // No need to update anything. Everything is already set up + return; + } + + this._overlay.EnableOverlayLabel(this.IsOverlayEnabled); + + if (!this._isOverlayVisible) + { + // One-time action to show the Overlay before it is set up + // Otherwise its position won't be set + this._overlay.Show(); + this._isOverlayVisible = true; + } + + Size overlaySize = this.ClientSize; + Point overlayLocation = this.Location; + + int borderWidth = (this.Size.Width - this.ClientSize.Width) / 2; + overlayLocation.X += borderWidth; + overlayLocation.Y += (this.Size.Height - this.ClientSize.Height) - borderWidth; + + this._isLocationChanged = false; + this._overlay.Size = overlaySize; + this._overlay.Location = overlayLocation; + this._overlay.Refresh(); } private void SuppressResizeEvent() @@ -482,18 +473,6 @@ namespace EveOPreview.View } #endregion - #region Thumbnail management - private void RegisterThumbnail() - { - this._thumbnail = this._windowManager.RegisterThumbnail(this.Handle, this.Id); - } - - private void UpdateThumbnail() - { - this._thumbnail.Update(); - } - #endregion - #region Custom Mouse mode // This pair of methods saves/restores certain window properties // Methods are used to remove the 'Zoom' effect (if any) when the diff --git a/Eve-O-Preview/View/Implementation/ThumbnailViewFactory.cs b/Eve-O-Preview/View/Implementation/ThumbnailViewFactory.cs index 22c8715..83d271e 100644 --- a/Eve-O-Preview/View/Implementation/ThumbnailViewFactory.cs +++ b/Eve-O-Preview/View/Implementation/ThumbnailViewFactory.cs @@ -1,20 +1,25 @@ using System; using System.Drawing; +using EveOPreview.Configuration; namespace EveOPreview.View { sealed class ThumbnailViewFactory : IThumbnailViewFactory { private readonly IApplicationController _controller; + private readonly bool _isCompatibilityModeEnabled; - public ThumbnailViewFactory(IApplicationController controller) + public ThumbnailViewFactory(IApplicationController controller, IThumbnailConfiguration configuration) { this._controller = controller; + this._isCompatibilityModeEnabled = configuration.EnableCompatibilityMode; } public IThumbnailView Create(IntPtr id, string title, Size size) { - IThumbnailView view = this._controller.Create(); + IThumbnailView view = this._isCompatibilityModeEnabled + ? (IThumbnailView)this._controller.Create() + : (IThumbnailView)this._controller.Create(); view.Id = id; view.Title = title; From 3c3ee9f702482d7d35c89b4d8df6307249c1ca80 Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Thu, 2 May 2019 17:01:05 +0300 Subject: [PATCH 13/27] Support multiple displays with different DPI set --- Eve-O-Preview/app.manifest | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eve-O-Preview/app.manifest b/Eve-O-Preview/app.manifest index 5fc7044..cc914b0 100644 --- a/Eve-O-Preview/app.manifest +++ b/Eve-O-Preview/app.manifest @@ -74,8 +74,8 @@ --> - True/PM - PerMonitorV2 + True + PerMonitor From 315c5044c7628018cd126f4c68cc9802fad33ed5 Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Thu, 2 May 2019 17:02:16 +0300 Subject: [PATCH 14/27] Config file property name changed from `PotatoMode` to `CompatibilityMode` --- .../Configuration/Implementation/ThumbnailConfiguration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eve-O-Preview/Configuration/Implementation/ThumbnailConfiguration.cs b/Eve-O-Preview/Configuration/Implementation/ThumbnailConfiguration.cs index 79fd030..779f509 100644 --- a/Eve-O-Preview/Configuration/Implementation/ThumbnailConfiguration.cs +++ b/Eve-O-Preview/Configuration/Implementation/ThumbnailConfiguration.cs @@ -56,7 +56,7 @@ namespace EveOPreview.Configuration.Implementation public bool MinimizeToTray { get; set; } public int ThumbnailRefreshPeriod { get; set; } - [JsonProperty("PotatoMode")] + [JsonProperty("CompatibilityMode")] public bool EnableCompatibilityMode { get; set; } [JsonProperty("ThumbnailsOpacity")] From ef9924b1649b8ce660cb3dbf6f5247c7d485a7f3 Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Thu, 2 May 2019 18:06:16 +0300 Subject: [PATCH 15/27] Documentation update --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 03ac55d..5d5997b 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ Some of the application options are not exposed in the GUI. They can be adjusted | Option | Description | | --- | --- | | **ActiveClientHighlightThickness** | Thickness of the border used to highlight the active client's thumbnail.
Allowed values are **1**...**6**.
The default value is **3**
For example: **"ActiveClientHighlightThickness": 3** | +| **CompatibilityMode** | Enables the alternative render mode (see below)
The default value is **false**
For example: **"CompatibilityMode": true** | | **EnableThumbnailSnap** | Allows to disable thumbnails snap feature by setting its value to **false**
The default value is **true**
For example: **"EnableThumbnailSnap": true** | | **PriorityClients** | Allows to set a list of clients that are not auto-minimized on inactivity even if the **Minimize inactive EVE clients** option is enabled. Listed clients still can be minimized using Windows hotkeys or via _Ctrl+Click_ on the corresponding thumbnail
The default value is empty list **[]**
For example: **"PriorityClients": [ "EVE - Phrynohyas Tig-Rah", "EVE - Ondatra Patrouette" ]** | | **ThumbnailMinimumSize** | Minimum thumbnail size that can be set either via GUI or by resizing a thumbnail window. Value is written in the form "width, height"
The default value is **"100, 80"**.
For example: **"ThumbnailMinimumSize": "100, 80"** | @@ -124,6 +125,14 @@ The following hotkey is described as `modifier+key` where `modifier` can be **Co **Note:** Do not set hotkeys to use the key combinations already used by EVE. It won't work as "_I set hotkey for my DPS char to F1 and when I'll press F1 it will automatically open the DPS char's window and activate guns_". Key combination will be swallowed by EVE-O Preview and NOT retranslated to EVE window. So it will be only "_it will automatically open the DPS char's window_". +## Compatibility Mode + +This setting allows to enable an alternate thumbnail render. This render doesn't use advanced DWM API to create live previews. Instead it is a screenshot-based render with the following pros and cons: +* `+` Doesn't require Aero to work +* `+` Should work even in remote desktop environments +* `-` Consumes significantly more memory. In the testing environment EVE-O Preview did consume around 180 MB to manage 3 thumbnails using this render. At the same time the primary render did consume around 50 MB when run in the same environment. +* `-` Thumbnail images are refreshed at 1 FPS rate +* `-` Possible short mouse cursor freezes --- From 00339bc34cc2293040c6cfebb01a0001fe407a0a Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Sun, 5 May 2019 02:25:26 +0300 Subject: [PATCH 16/27] Single-instance check sometimes doesn't detect another running instance --- Eve-O-Preview/Program.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Eve-O-Preview/Program.cs b/Eve-O-Preview/Program.cs index 16fc709..9ab309b 100644 --- a/Eve-O-Preview/Program.cs +++ b/Eve-O-Preview/Program.cs @@ -11,7 +11,9 @@ namespace EveOPreview { static class Program { - private static string MutexName = "EVE-O Preview Single Instance Mutex"; + private static string MUTEX_NAME = "EVE-O Preview Single Instance Mutex"; + + private static Mutex _singleInstanceMutex; /// The main entry point for the application. [STAThread] @@ -28,11 +30,11 @@ namespace EveOPreview // The very usual Mutex-based single-instance screening // 'token' variable is used to store reference to the instance Mutex // during the app lifetime - object token = Program.GetInstanceToken(); + Program._singleInstanceMutex = Program.GetInstanceToken(); // If it was not possible to acquire the app token then another app instance is already running // Nothing to do here - if (token == null) + if (Program._singleInstanceMutex == null) { return; } @@ -46,7 +48,7 @@ namespace EveOPreview controller.Run(); } - private static object GetInstanceToken() + private static Mutex GetInstanceToken() { // The code might look overcomplicated here for a single Mutex operation // Yet we had already experienced a Windows-level issue @@ -55,7 +57,7 @@ namespace EveOPreview // exceptions later try { - Mutex.OpenExisting(Program.MutexName); + Mutex.OpenExisting(Program.MUTEX_NAME); // if that didn't fail then another instance is already running return null; } @@ -65,7 +67,7 @@ namespace EveOPreview } catch (Exception) { - Mutex token = new Mutex(true, Program.MutexName, out var result); + Mutex token = new Mutex(true, Program.MUTEX_NAME, out var result); return result ? token : null; } } From dd24494e620ffcf7c1be45928fec7ca1b2dd15a3 Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Sun, 5 May 2019 02:28:02 +0300 Subject: [PATCH 17/27] Thumbnail opacity management might cause performance issues and/or app crashes --- .../View/Implementation/ThumbnailView.cs | 43 ++++++++++++++++--- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/Eve-O-Preview/View/Implementation/ThumbnailView.cs b/Eve-O-Preview/View/Implementation/ThumbnailView.cs index 7755687..65e1e7d 100644 --- a/Eve-O-Preview/View/Implementation/ThumbnailView.cs +++ b/Eve-O-Preview/View/Implementation/ThumbnailView.cs @@ -11,6 +11,8 @@ namespace EveOPreview.View { #region Private constants private const int RESIZE_EVENT_TIMEOUT = 500; +f private const double OPACITY_THRESHOLD = 0.9; + private const double OPACITY_EPSILON = 0.1; #endregion #region Private fields @@ -23,9 +25,14 @@ namespace EveOPreview.View private bool _isHighlightEnabled; private bool _isHighlightRequested; private int _highlightWidth; + private bool _isLocationChanged; private bool _isSizeChanged; + private bool _isCustomMouseModeActive; + + private double _opacity; + private DateTime _suppressResizeEventsTimestamp; private Size _baseZoomSize; private Point _baseZoomLocation; @@ -47,12 +54,14 @@ namespace EveOPreview.View this._isOverlayVisible = false; this._isTopMost = false; this._isHighlightEnabled = false; + this._isHighlightRequested = false; this._isLocationChanged = true; this._isSizeChanged = true; + this._isCustomMouseModeActive = false; - this._isHighlightRequested = false; + this._opacity = 1.0; InitializeComponent(); @@ -156,13 +165,33 @@ namespace EveOPreview.View public void SetOpacity(double opacity) { - this.Opacity = opacity; + if (opacity >= OPACITY_THRESHOLD) + { + opacity = 1.0; + } - // Overlay opacity settings - // Of the thumbnail's opacity is almost full then set the overlay's one to - // full. Otherwise set it to half of the thumbnail opacity - // Opacity value is stored even if the overlay is not displayed atm - this._overlay.Opacity = this.Opacity > 0.9 ? 1.0 : 1.0 - (1.0 - this.Opacity) / 2; + if (Math.Abs(opacity - this._opacity) < OPACITY_EPSILON) + { + return; + } + + try + { + this.Opacity = opacity; + + // Overlay opacity settings + // Of the thumbnail's opacity is almost full then set the overlay's one to + // full. Otherwise set it to half of the thumbnail opacity + // Opacity value is stored even if the overlay is not displayed atm + this._overlay.Opacity = opacity > 0.8 ? 1.0 : 1.0 - (1.0 - opacity) / 2; + + this._opacity = opacity; + } + catch (Win32Exception) + { + // Something went wrong in WinForms internals + // Opacity will be updated in the next cycle + } } public void SetFrames(bool enable) From 634a5fe038fc48c652c091bddbff83c467455087 Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 6 May 2019 22:36:22 +0300 Subject: [PATCH 18/27] Opacity cache fix --- Eve-O-Preview/View/Implementation/ThumbnailView.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eve-O-Preview/View/Implementation/ThumbnailView.cs b/Eve-O-Preview/View/Implementation/ThumbnailView.cs index 65e1e7d..da26bd8 100644 --- a/Eve-O-Preview/View/Implementation/ThumbnailView.cs +++ b/Eve-O-Preview/View/Implementation/ThumbnailView.cs @@ -11,7 +11,7 @@ namespace EveOPreview.View { #region Private constants private const int RESIZE_EVENT_TIMEOUT = 500; -f private const double OPACITY_THRESHOLD = 0.9; + private const double OPACITY_THRESHOLD = 0.9; private const double OPACITY_EPSILON = 0.1; #endregion @@ -61,7 +61,7 @@ f private const double OPACITY_THRESHOLD = 0.9; this._isCustomMouseModeActive = false; - this._opacity = 1.0; + this._opacity = 0.1; InitializeComponent(); From cb73a165c263c5a821b3085c57dd1ae2273c0743 Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Sun, 12 May 2019 22:34:33 +0300 Subject: [PATCH 19/27] Typo in comment --- Eve-O-Preview/Services/Implementation/DwmThumbnail.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eve-O-Preview/Services/Implementation/DwmThumbnail.cs b/Eve-O-Preview/Services/Implementation/DwmThumbnail.cs index 873ded8..7562929 100644 --- a/Eve-O-Preview/Services/Implementation/DwmThumbnail.cs +++ b/Eve-O-Preview/Services/Implementation/DwmThumbnail.cs @@ -42,7 +42,7 @@ namespace EveOPreview.Services.Implementation { // This exception is raised if the source client is already closed // Can happen on a really slow CPU's that the window is still being - // lised in the process list yet it already cannot be used as + // listed in the process list yet it already cannot be used as // a thumbnail source this._handle = IntPtr.Zero; } From 63fa0e9ff5feb5ed78e7ec7e2ef7cebd55f7daaa Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Sun, 12 May 2019 22:38:22 +0300 Subject: [PATCH 20/27] 148: Flickering of live thumbnails --- .../View/Implementation/LiveThumbnailView.cs | 26 ++++++++++++++----- .../Implementation/StaticThumbnailView.cs | 25 ++++++++++++++++-- .../View/Implementation/ThumbnailView.cs | 13 ++++++---- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/Eve-O-Preview/View/Implementation/LiveThumbnailView.cs b/Eve-O-Preview/View/Implementation/LiveThumbnailView.cs index 543c94d..487d9c1 100644 --- a/Eve-O-Preview/View/Implementation/LiveThumbnailView.cs +++ b/Eve-O-Preview/View/Implementation/LiveThumbnailView.cs @@ -1,4 +1,5 @@ using System; +using System.Drawing; using EveOPreview.Services; namespace EveOPreview.View @@ -7,17 +8,15 @@ namespace EveOPreview.View { #region Private fields private IDwmThumbnail _thumbnail; + private Point _startLocation; + private Point _endLocation; #endregion public LiveThumbnailView(IWindowManager windowManager) : base(windowManager) { - } - - public override void Close() - { - this._thumbnail?.Unregister(); - base.Close(); + this._startLocation = new Point(0, 0); + this._endLocation = new Point(this.ClientSize); } protected override void RefreshThumbnail(bool forceRefresh) @@ -35,13 +34,26 @@ namespace EveOPreview.View protected override void ResizeThumbnail(int baseWidth, int baseHeight, int highlightWidthTop, int highlightWidthRight, int highlightWidthBottom, int highlightWidthLeft) { - this._thumbnail.Move(0 + highlightWidthLeft, 0 + highlightWidthTop, baseWidth - highlightWidthRight, baseHeight - highlightWidthBottom); + var left = 0 + highlightWidthLeft; + var top = 0 + highlightWidthTop; + var right = baseWidth - highlightWidthRight; + var bottom = baseHeight - highlightWidthBottom; + + if ((this._startLocation.X == left) && (this._startLocation.Y == top) && (this._endLocation.X == right) && (this._endLocation.Y == bottom)) + { + return; // No update required + } + this._startLocation = new Point(left, top); + this._endLocation = new Point(right, bottom); + + this._thumbnail.Move(left, top, right, bottom); this._thumbnail.Update(); } private void RegisterThumbnail() { this._thumbnail = this.WindowManager.GetLiveThumbnail(this.Handle, this.Id); + this._thumbnail.Move(this._startLocation.X, this._startLocation.Y, this._endLocation.X, this._endLocation.Y); this._thumbnail.Update(); } } diff --git a/Eve-O-Preview/View/Implementation/StaticThumbnailView.cs b/Eve-O-Preview/View/Implementation/StaticThumbnailView.cs index cabe743..c01ebc3 100644 --- a/Eve-O-Preview/View/Implementation/StaticThumbnailView.cs +++ b/Eve-O-Preview/View/Implementation/StaticThumbnailView.cs @@ -42,8 +42,29 @@ namespace EveOPreview.View protected override void ResizeThumbnail(int baseWidth, int baseHeight, int highlightWidthTop, int highlightWidthRight, int highlightWidthBottom, int highlightWidthLeft) { - this._thumbnail.Location = new Point(0 + highlightWidthLeft, 0 + highlightWidthTop); - this._thumbnail.Size = new Size(baseWidth - highlightWidthLeft - highlightWidthRight, baseHeight - highlightWidthTop - highlightWidthBottom); + var left = 0 + highlightWidthLeft; + var top = 0 + highlightWidthTop; + if (this.IsLocationUpdateRequired(this._thumbnail.Location, left, top)) + { + this._thumbnail.Location = new Point(left, top); + } + + var width = baseWidth - highlightWidthLeft - highlightWidthRight; + var height = baseHeight - highlightWidthTop - highlightWidthBottom; + if (this.IsSizeUpdateRequired(this._thumbnail.Size, width, height)) + { + this._thumbnail.Size = new Size(width, height); + } + } + + private bool IsLocationUpdateRequired(Point currentLocation, int left, int top) + { + return (currentLocation.X != left) || (currentLocation.Y != top); + } + + private bool IsSizeUpdateRequired(Size currentSize, int width, int height) + { + return (currentSize.Width != width) || (currentSize.Height != height); } } } \ No newline at end of file diff --git a/Eve-O-Preview/View/Implementation/ThumbnailView.cs b/Eve-O-Preview/View/Implementation/ThumbnailView.cs index da26bd8..167b673 100644 --- a/Eve-O-Preview/View/Implementation/ThumbnailView.cs +++ b/Eve-O-Preview/View/Implementation/ThumbnailView.cs @@ -253,8 +253,10 @@ namespace EveOPreview.View int locationX = this.Location.X; int locationY = this.Location.Y; - int newWidth = (zoomFactor * this.ClientSize.Width) + (this.Size.Width - this.ClientSize.Width); - int newHeight = (zoomFactor * this.ClientSize.Height) + (this.Size.Height - this.ClientSize.Height); + int clientSizeWidth = this.ClientSize.Width; + int clientSizeHeight = this.ClientSize.Height; + int newWidth = (zoomFactor * clientSizeWidth) + (this.Size.Width - clientSizeWidth); + int newHeight = (zoomFactor * clientSizeHeight) + (this.Size.Height - clientSizeHeight); // First change size, THEN move the window // Otherwise there is a chance to fail in a loop @@ -353,15 +355,16 @@ namespace EveOPreview.View this._isHighlightEnabled = this._isHighlightRequested; + int baseWidth = this.ClientSize.Width; + int baseHeight = this.ClientSize.Height; + if (!this._isHighlightRequested) { //No highlighting enabled, so no math required - this.ResizeThumbnail(this.ClientSize.Width, this.ClientSize.Height, 0, 0, 0, 0); + this.ResizeThumbnail(baseWidth, baseHeight, 0, 0, 0, 0); return; } - int baseWidth = this.ClientSize.Width; - int baseHeight = this.ClientSize.Height; double baseAspectRatio = ((double)baseWidth) / baseHeight; int actualHeight = baseHeight - 2 * this._highlightWidth; From 4b0b0c465d87a11397df6c7fe428c3e1fc5d61f7 Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 10 Jun 2019 21:14:52 +0300 Subject: [PATCH 21/27] Build version update --- Eve-O-Preview/Properties/AssemblyInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eve-O-Preview/Properties/AssemblyInfo.cs b/Eve-O-Preview/Properties/AssemblyInfo.cs index 9b2adf4..2908b70 100644 --- a/Eve-O-Preview/Properties/AssemblyInfo.cs +++ b/Eve-O-Preview/Properties/AssemblyInfo.cs @@ -12,7 +12,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("04f08f8d-9e98-423b-acdb-4effb31c0d35")] -[assembly: AssemblyVersion("4.1.0.1")] -[assembly: AssemblyFileVersion("4.1.0.1")] +[assembly: AssemblyVersion("4.1.0.6")] +[assembly: AssemblyFileVersion("4.1.0.6")] [assembly: CLSCompliant(false)] \ No newline at end of file From 0199f9f4a669141bb578885122983c305b25b0da Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 10 Jun 2019 21:15:36 +0300 Subject: [PATCH 22/27] Remove Beta nag message --- Eve-O-Preview/Program.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Eve-O-Preview/Program.cs b/Eve-O-Preview/Program.cs index 9ab309b..dd29e98 100644 --- a/Eve-O-Preview/Program.cs +++ b/Eve-O-Preview/Program.cs @@ -19,14 +19,6 @@ namespace EveOPreview [STAThread] static void Main() { -#if DEBUG - var expirationDate = new DateTime(2019, 5, 15); - if (DateTime.Today >= expirationDate) - { - MessageBox.Show(@"This Beta version is expired. Please download a new build at https://github.com/Phrynohyas/eve-o-preview/releases", @"EVE-O Preview", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); - } -#endif - // The very usual Mutex-based single-instance screening // 'token' variable is used to store reference to the instance Mutex // during the app lifetime From 4740b9185f04cabe0c2f34f0455a4bc455e039ae Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Mon, 10 Jun 2019 21:29:07 +0300 Subject: [PATCH 23/27] 149: Stored Client Layout doesn't persist information about maximized EVE client windows --- .../Configuration/Interface/ClientLayout.cs | 7 ++++++- Eve-O-Preview/Eve-O-Preview.csproj | 2 +- .../Services/Implementation/ThumbnailManager.cs | 16 ++++++++++++---- .../Services/Implementation/WindowManager.cs | 12 +++++++++++- .../Services/Interface/IWindowManager.cs | 5 ++--- .../Services/Interface/InteropConstants.cs | 3 ++- 6 files changed, 34 insertions(+), 11 deletions(-) diff --git a/Eve-O-Preview/Configuration/Interface/ClientLayout.cs b/Eve-O-Preview/Configuration/Interface/ClientLayout.cs index 02266c4..c158401 100644 --- a/Eve-O-Preview/Configuration/Interface/ClientLayout.cs +++ b/Eve-O-Preview/Configuration/Interface/ClientLayout.cs @@ -6,18 +6,23 @@ namespace EveOPreview.Configuration { } - public ClientLayout(int x, int y, int width, int height) + public ClientLayout(int x, int y, int width, int height, bool maximized) { this.X = x; this.Y = y; this.Width = width; this.Height = height; + this.IsMaximized = maximized; } public int X { get; set; } + public int Y { get; set; } public int Width { get; set; } + public int Height { get; set; } + + public bool IsMaximized { get; set; } } } \ No newline at end of file diff --git a/Eve-O-Preview/Eve-O-Preview.csproj b/Eve-O-Preview/Eve-O-Preview.csproj index 5e9d4aa..375b7a6 100644 --- a/Eve-O-Preview/Eve-O-Preview.csproj +++ b/Eve-O-Preview/Eve-O-Preview.csproj @@ -10,7 +10,7 @@ WinExe Properties EveOPreview - Eve-O Preview + EVE-O Preview v4.7 diff --git a/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs b/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs index 9f55ac2..ea0904f 100644 --- a/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs +++ b/Eve-O-Preview/Services/Implementation/ThumbnailManager.cs @@ -590,7 +590,14 @@ namespace EveOPreview.Services return; } - this._windowManager.MoveWindow(clientHandle, clientLayout.X, clientLayout.Y, clientLayout.Width, clientLayout.Height); + if (clientLayout.IsMaximized) + { + this._windowManager.MaximizeWindow(clientHandle); + } + else + { + this._windowManager.MoveWindow(clientHandle, clientLayout.X, clientLayout.Y, clientLayout.Width, clientLayout.Height); + } } private void UpdateClientLayouts() @@ -604,16 +611,17 @@ namespace EveOPreview.Services { IThumbnailView view = entry.Value; (int Left, int Top, int Right, int Bottom) position = this._windowManager.GetWindowPosition(view.Id); - int width = Math.Abs(position.Right - position.Left); int height = Math.Abs(position.Bottom - position.Top); - if (!this.IsValidWindowPosition(position.Left, position.Top, width, height)) + var isMaximized = this._windowManager.IsWindowMaximized(view.Id); + + if (!(isMaximized || this.IsValidWindowPosition(position.Left, position.Top, width, height))) { continue; } - this._configuration.SetClientLayout(view.Title, new ClientLayout(position.Left, position.Top, width, height)); + this._configuration.SetClientLayout(view.Title, new ClientLayout(position.Left, position.Top, width, height, isMaximized)); } } diff --git a/Eve-O-Preview/Services/Implementation/WindowManager.cs b/Eve-O-Preview/Services/Implementation/WindowManager.cs index b7e7135..c1b8d88 100644 --- a/Eve-O-Preview/Services/Implementation/WindowManager.cs +++ b/Eve-O-Preview/Services/Implementation/WindowManager.cs @@ -31,7 +31,7 @@ namespace EveOPreview.Services.Implementation if ((style & InteropConstants.WS_MINIMIZE) == InteropConstants.WS_MINIMIZE) { - User32NativeMethods.ShowWindowAsync(handle, InteropConstants.SW_SHOWNORMAL); + User32NativeMethods.ShowWindowAsync(handle, InteropConstants.SW_RESTORE); } } @@ -56,6 +56,11 @@ namespace EveOPreview.Services.Implementation User32NativeMethods.MoveWindow(handle, left, top, width, height, true); } + public void MaximizeWindow(IntPtr handle) + { + User32NativeMethods.ShowWindowAsync(handle, InteropConstants.SW_SHOWMAXIMIZED); + } + public (int Left, int Top, int Right, int Bottom) GetWindowPosition(IntPtr handle) { User32NativeMethods.GetWindowRect(handle, out RECT windowRectangle); @@ -63,6 +68,11 @@ namespace EveOPreview.Services.Implementation return (windowRectangle.Left, windowRectangle.Top, windowRectangle.Right, windowRectangle.Bottom); } + public bool IsWindowMaximized(IntPtr handle) + { + return User32NativeMethods.IsZoomed(handle); + } + public bool IsWindowMinimized(IntPtr handle) { return User32NativeMethods.IsIconic(handle); diff --git a/Eve-O-Preview/Services/Interface/IWindowManager.cs b/Eve-O-Preview/Services/Interface/IWindowManager.cs index 50a01b6..c1ce08d 100644 --- a/Eve-O-Preview/Services/Interface/IWindowManager.cs +++ b/Eve-O-Preview/Services/Interface/IWindowManager.cs @@ -8,14 +8,13 @@ namespace EveOPreview.Services bool IsCompositionEnabled { get; } IntPtr GetForegroundWindowHandle(); - void ActivateWindow(IntPtr handle); void MinimizeWindow(IntPtr handle, bool enableAnimation); - void MoveWindow(IntPtr handle, int left, int top, int width, int height); + void MaximizeWindow(IntPtr handle); (int Left, int Top, int Right, int Bottom) GetWindowPosition(IntPtr handle); + bool IsWindowMaximized(IntPtr handle); bool IsWindowMinimized(IntPtr handle); - IDwmThumbnail GetLiveThumbnail(IntPtr destination, IntPtr source); Image GetStaticThumbnail(IntPtr source); } diff --git a/Eve-O-Preview/Services/Interface/InteropConstants.cs b/Eve-O-Preview/Services/Interface/InteropConstants.cs index e6df312..5fdd320 100644 --- a/Eve-O-Preview/Services/Interface/InteropConstants.cs +++ b/Eve-O-Preview/Services/Interface/InteropConstants.cs @@ -56,7 +56,7 @@ namespace EveOPreview.Services public const UInt32 WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE); public const UInt32 WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST); public const UInt32 WS_EX_LAYERED = 0x00080000; - public const UInt32 WS_EX_NOINHERITLAYOUT = 0x00100000; // Disable inheritence of mirroring by children + public const UInt32 WS_EX_NOINHERITLAYOUT = 0x00100000; // Disable inheritance of mirroring by children public const UInt32 WS_EX_LAYOUTRTL = 0x00400000; // Right to left mirroring public const UInt32 WS_EX_COMPOSITED = 0x02000000; public const UInt32 WS_EX_NOACTIVATE = 0x08000000; @@ -78,5 +78,6 @@ namespace EveOPreview.Services public const int SW_SHOWNORMAL = 1; public const int SW_SHOWMINIMIZED = 2; public const int SW_SHOWMAXIMIZED = 3; + public const int SW_RESTORE = 9; } } \ No newline at end of file From c9593d485a11e9d0d1e4b5db284ddfdb8da6938a Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Fri, 12 Jul 2019 11:05:12 +0300 Subject: [PATCH 24/27] Update version to 5.0.0 --- Eve-O-Preview/Properties/AssemblyInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eve-O-Preview/Properties/AssemblyInfo.cs b/Eve-O-Preview/Properties/AssemblyInfo.cs index 2908b70..701f66a 100644 --- a/Eve-O-Preview/Properties/AssemblyInfo.cs +++ b/Eve-O-Preview/Properties/AssemblyInfo.cs @@ -12,7 +12,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("04f08f8d-9e98-423b-acdb-4effb31c0d35")] -[assembly: AssemblyVersion("4.1.0.6")] -[assembly: AssemblyFileVersion("4.1.0.6")] +[assembly: AssemblyVersion("5.0.0.0")] +[assembly: AssemblyFileVersion("5.0.0.0")] [assembly: CLSCompliant(false)] \ No newline at end of file From 6fda268678b1c1cb354763c8ac82aa9240ba30bd Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Fri, 12 Jul 2019 11:06:42 +0300 Subject: [PATCH 25/27] Documentation update --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 5d5997b..b7d166a 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,6 @@ The following hotkey is described as `modifier+key` where `modifier` can be **Co ## Compatibility Mode This setting allows to enable an alternate thumbnail render. This render doesn't use advanced DWM API to create live previews. Instead it is a screenshot-based render with the following pros and cons: -* `+` Doesn't require Aero to work * `+` Should work even in remote desktop environments * `-` Consumes significantly more memory. In the testing environment EVE-O Preview did consume around 180 MB to manage 3 thumbnails using this render. At the same time the primary render did consume around 50 MB when run in the same environment. * `-` Thumbnail images are refreshed at 1 FPS rate From 7bc0ffd076bb71f64eb9d8b79f7236aa7a3f4e3e Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Fri, 12 Jul 2019 11:11:49 +0300 Subject: [PATCH 26/27] Typo in the 'About' box --- Eve-O-Preview/View/Implementation/MainForm.Designer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eve-O-Preview/View/Implementation/MainForm.Designer.cs b/Eve-O-Preview/View/Implementation/MainForm.Designer.cs index e185e73..084354f 100644 --- a/Eve-O-Preview/View/Implementation/MainForm.Designer.cs +++ b/Eve-O-Preview/View/Implementation/MainForm.Designer.cs @@ -820,7 +820,7 @@ namespace EveOPreview.View DocumentationLinkLabel.Padding = new System.Windows.Forms.Padding(12, 5, 12, 5); DocumentationLinkLabel.Size = new System.Drawing.Size(336, 30); DocumentationLinkLabel.TabIndex = 6; - DocumentationLinkLabel.Text = "For more information visit our forum thread:"; + DocumentationLinkLabel.Text = "For more information visit the forum thread:"; // // DescriptionLabel // From cbe82704b6423f08355093dc0ca461994825ceef Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Fri, 12 Jul 2019 11:16:44 +0300 Subject: [PATCH 27/27] 151: Aero is detected as disabled in Windows 10 'High Contrast' mode --- Eve-O-Preview/Services/Implementation/WindowManager.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Eve-O-Preview/Services/Implementation/WindowManager.cs b/Eve-O-Preview/Services/Implementation/WindowManager.cs index c1b8d88..80ff23c 100644 --- a/Eve-O-Preview/Services/Implementation/WindowManager.cs +++ b/Eve-O-Preview/Services/Implementation/WindowManager.cs @@ -13,7 +13,11 @@ namespace EveOPreview.Services.Implementation public WindowManager() { - this.IsCompositionEnabled = DwmNativeMethods.DwmIsCompositionEnabled(); + // Composition is always enabled for Windows 8+ + this.IsCompositionEnabled = + ((Environment.OSVersion.Version.Major == 6) && (Environment.OSVersion.Version.Minor >= 2)) // Win 8 and Win 8.1 + || (Environment.OSVersion.Version.Major >= 10) // Win 10 + || DwmNativeMethods.DwmIsCompositionEnabled(); // In case of Win 7 an API call is requiredWin 7 } public bool IsCompositionEnabled { get; }