185: [Bug] Previews flicker when switching between clients with 'Hide previews when EVE client not active'

This commit is contained in:
Anton Kasyanov
2021-05-02 19:52:49 +03:00
parent d864bbb96d
commit 239026886c
5 changed files with 90 additions and 23 deletions

View File

@@ -32,9 +32,11 @@ namespace EveOPreview.Configuration.Implementation
this.HideActiveClientThumbnail = false;
this.MinimizeInactiveClients = false;
this.ShowThumbnailsAlwaysOnTop = true;
this.HideThumbnailsOnLostFocus = false;
this.EnablePerClientThumbnailLayouts = false;
this.HideThumbnailsOnLostFocus = false;
this.HideThumbnailsDelay = 2; // 2 thumbnails refresh cycles (1.0 sec)
this.ThumbnailSize = new Size(384, 216);
this.ThumbnailMinimumSize = new Size(192, 108);
this.ThumbnailMaximumSize = new Size(960, 540);
@@ -79,7 +81,6 @@ namespace EveOPreview.Configuration.Implementation
public bool HideActiveClientThumbnail { get; set; }
public bool MinimizeInactiveClients { get; set; }
public bool ShowThumbnailsAlwaysOnTop { get; set; }
public bool HideThumbnailsOnLostFocus { get; set; }
public bool EnablePerClientThumbnailLayouts
{
@@ -95,6 +96,9 @@ namespace EveOPreview.Configuration.Implementation
}
}
public bool HideThumbnailsOnLostFocus { get; set; }
public int HideThumbnailsDelay { get; set; }
public Size ThumbnailSize { get; set; }
public Size ThumbnailMaximumSize { get; set; }
public Size ThumbnailMinimumSize { get; set; }

View File

@@ -16,9 +16,11 @@ namespace EveOPreview.Configuration
bool HideActiveClientThumbnail { get; set; }
bool MinimizeInactiveClients { get; set; }
bool ShowThumbnailsAlwaysOnTop { get; set; }
bool HideThumbnailsOnLostFocus { get; set; }
bool EnablePerClientThumbnailLayouts { get; set; }
bool HideThumbnailsOnLostFocus { get; set; }
int HideThumbnailsDelay { get; set; }
Size ThumbnailSize { get; set; }
Size ThumbnailMinimumSize { get; set; }
Size ThumbnailMaximumSize { get; set; }

View File

@@ -8,15 +8,21 @@ namespace EveOPreview.Services.Implementation
{
#region Private constants
private const string DEFAULT_PROCESS_NAME = "ExeFile";
private const string CURRENT_PROCESS_NAME = "EVE-O Preview";
#endregion
#region Private fields
private readonly IDictionary<IntPtr, string> _processCache;
private IProcessInfo _currentProcessInfo;
#endregion
public ProcessMonitor()
{
this._processCache = new Dictionary<IntPtr, string>(512);
// This field cannot be initialized properly in constructor
// At the moment this code is executed the main application window is not yet initialized
this._currentProcessInfo = new ProcessInfo(IntPtr.Zero, "");
}
private bool IsMonitoredProcess(string processName)
@@ -25,6 +31,41 @@ namespace EveOPreview.Services.Implementation
return String.Equals(processName, ProcessMonitor.DEFAULT_PROCESS_NAME, StringComparison.OrdinalIgnoreCase);
}
private IProcessInfo GetCurrentProcessInfo()
{
var currentProcess = Process.GetCurrentProcess();
return new ProcessInfo(currentProcess.MainWindowHandle, currentProcess.MainWindowTitle);
}
public IProcessInfo GetMainProcess()
{
if (this._currentProcessInfo.Handle == IntPtr.Zero)
{
var processInfo = this.GetCurrentProcessInfo();
// Are we initialized yet?
if (processInfo.Title != "")
{
this._currentProcessInfo = processInfo;
}
}
return this._currentProcessInfo;
}
public ICollection<IProcessInfo> GetAllProcesses()
{
ICollection<IProcessInfo> result = new List<IProcessInfo>(this._processCache.Count);
// TODO Lock list here just in case
foreach (KeyValuePair<IntPtr, string> entry in this._processCache)
{
result.Add(new ProcessInfo(entry.Key, entry.Value));
}
return result;
}
public void GetUpdatedProcesses(out ICollection<IProcessInfo> addedProcesses, out ICollection<IProcessInfo> updatedProcesses, out ICollection<IProcessInfo> removedProcesses)
{
addedProcesses = new List<IProcessInfo>(16);
@@ -76,18 +117,5 @@ namespace EveOPreview.Services.Implementation
this._processCache.Remove(index);
}
}
public ICollection<IProcessInfo> GetAllProcesses()
{
ICollection<IProcessInfo> result = new List<IProcessInfo>(this._processCache.Count);
// TODO Lock list here just in case
foreach (KeyValuePair<IntPtr, string> entry in this._processCache)
{
result.Add(new ProcessInfo(entry.Key, entry.Value));
}
return result;
}
}
}

View File

@@ -41,6 +41,7 @@ namespace EveOPreview.Services
private bool _isHoverEffectActive;
private int _refreshCycleCount;
private int _hideThumbnailsDelay;
#endregion
public ThumbnailManager(IMediator mediator, IThumbnailConfiguration configuration, IProcessMonitor processMonitor, IWindowManager windowManager, IThumbnailViewFactory factory)
@@ -66,6 +67,8 @@ namespace EveOPreview.Services
this._thumbnailUpdateTimer = new DispatcherTimer();
this._thumbnailUpdateTimer.Tick += ThumbnailUpdateTimerTick;
this._thumbnailUpdateTimer.Interval = new TimeSpan(0, 0, 0, 0, configuration.ThumbnailRefreshPeriod);
this._hideThumbnailsDelay = this._configuration.HideThumbnailsDelay;
}
public void Start()
@@ -180,10 +183,19 @@ namespace EveOPreview.Services
{
// TODO Split this method
IntPtr foregroundWindowHandle = this._windowManager.GetForegroundWindowHandle();
// The foreground window can be NULL in certain circumstances, such as when a window is losing activation.
// It is safer to just skip this refresh round than to do something while the system state is undefined
if (foregroundWindowHandle == IntPtr.Zero)
{
return;
}
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);
bool isMainWindowActive = this.IsMainWindowActive(foregroundWindowHandle);
if (foregroundWindowHandle == this._activeClient.Handle)
{
@@ -195,14 +207,9 @@ namespace EveOPreview.Services
foregroundWindowTitle = foregroundView.Title;
}
else if (!isClientWindow)
{
// 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)
if (!string.IsNullOrEmpty(foregroundWindowTitle))
@@ -210,7 +217,25 @@ namespace EveOPreview.Services
this.SwitchActiveClient(foregroundWindowHandle, foregroundWindowTitle);
}
bool hideAllThumbnails = this._configuration.HideThumbnailsOnLostFocus && !isClientWindow;
bool hideAllThumbnails = this._configuration.HideThumbnailsOnLostFocus && !(isClientWindow || isMainWindowActive);
// Wait for some time before hiding all previews
if (hideAllThumbnails)
{
this._hideThumbnailsDelay--;
if (this._hideThumbnailsDelay > 0)
{
hideAllThumbnails = false; // Postpone the 'hide all' operation
}
else
{
this._hideThumbnailsDelay = 0; // Stop the counter
}
}
else
{
this._hideThumbnailsDelay = this._configuration.HideThumbnailsDelay; // Reset the counter
}
this._refreshCycleCount++;
@@ -456,6 +481,7 @@ namespace EveOPreview.Services
this.EnqueueLocationChange(view);
}
// Checks whether currently active window belongs to an EVE client or its thumbnail
private bool IsClientWindowActive(IntPtr windowHandle)
{
if (windowHandle == IntPtr.Zero)
@@ -476,6 +502,12 @@ namespace EveOPreview.Services
return false;
}
// Check whether the currently active window belongs to EVE-O Preview itself
private bool IsMainWindowActive(IntPtr windowHandle)
{
return (this._processMonitor.GetMainProcess().Handle == windowHandle);
}
private void ThumbnailZoomIn(IThumbnailView view)
{
this.DisableViewEvents();

View File

@@ -4,6 +4,7 @@ namespace EveOPreview.Services
{
public interface IProcessMonitor
{
IProcessInfo GetMainProcess();
ICollection<IProcessInfo> GetAllProcesses();
void GetUpdatedProcesses(out ICollection<IProcessInfo> addedProcesses, out ICollection<IProcessInfo> updatedProcesses, out ICollection<IProcessInfo> removedProcesses);
}