-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix Firefox handling with custom window event logic (#957)
Previously, Whim would enqueue a `DoLayout` whenever a window moved. This was done to account for windows doing atypical things, like trying to restore their own position. This worked prior to Whim becoming multi-threaded. Now that it is, this is no longer a viable approach. The `WindowMovedTransform` is triggered many times by Whim. Accordingly, the enqueueing of `DoLayout` similarly is done many times, sometimes overloading the main thread (related issues: #941, #944). This PR allows custom logic for handling events for specific types of windows. `IWindowProcessor` s specify whether to ignore the current Windows event. A `FirefoxWindowProcessor` has been implemented to account for atypical behavior by Firefox during startup.
- Loading branch information
Showing
21 changed files
with
452 additions
and
115 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
112 changes: 112 additions & 0 deletions
112
src/Whim.Tests/Store/WindowSector/Processors/FirefoxWindowProcessorTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
using Windows.Win32; | ||
|
||
namespace Whim.Tests; | ||
|
||
public class FirefoxWindowProcessorTests | ||
{ | ||
[Theory, AutoSubstituteData] | ||
public void Create_Failure(IContext ctx, IWindow window) | ||
{ | ||
// Given a window which is not a Firefox window | ||
window.ProcessFileName.Returns("chrome.exe"); | ||
|
||
// When `Create` is called | ||
IWindowProcessor? processor = FirefoxWindowProcessor.Create(ctx, window); | ||
|
||
// Then the processor should be null | ||
Assert.Null(processor); | ||
} | ||
|
||
[Theory, AutoSubstituteData] | ||
public void Create_Success(IContext ctx, IWindow window) | ||
{ | ||
// Given a window which is a Firefox window | ||
window.ProcessFileName.Returns("firefox.exe"); | ||
|
||
// When `Create` is called | ||
IWindowProcessor? processor = FirefoxWindowProcessor.Create(ctx, window); | ||
|
||
// Then the processor should not be null | ||
Assert.NotNull(processor); | ||
} | ||
|
||
[Theory] | ||
[InlineAutoSubstituteData(PInvoke.EVENT_OBJECT_SHOW)] | ||
[InlineAutoSubstituteData(PInvoke.EVENT_SYSTEM_FOREGROUND)] | ||
[InlineAutoSubstituteData(PInvoke.EVENT_OBJECT_UNCLOAKED)] | ||
[InlineAutoSubstituteData(PInvoke.EVENT_OBJECT_HIDE)] | ||
[InlineAutoSubstituteData(PInvoke.EVENT_SYSTEM_MOVESIZESTART)] | ||
[InlineAutoSubstituteData(PInvoke.EVENT_SYSTEM_MOVESIZEEND)] | ||
[InlineAutoSubstituteData(PInvoke.EVENT_OBJECT_LOCATIONCHANGE)] | ||
[InlineAutoSubstituteData(PInvoke.EVENT_SYSTEM_MINIMIZESTART)] | ||
[InlineAutoSubstituteData(PInvoke.EVENT_SYSTEM_MINIMIZEEND)] | ||
public void ShouldBeIgnored_UntilCloaked(uint eventType, IContext ctx, IWindow window) | ||
{ | ||
// Given an event which isn't `EVENT_OBJECT_CLOAKED` or `EVENT_OBJECT_DESTROY` | ||
window.ProcessFileName.Returns("firefox.exe"); | ||
IWindowProcessor processor = FirefoxWindowProcessor.Create(ctx, window)!; | ||
|
||
// When the event is passed to `ShouldBeIgnored` | ||
WindowProcessorResult result = processor.ProcessEvent(eventType, 0, 0, 0, 0); | ||
|
||
// Then the event should be ignored | ||
Assert.Equal(WindowProcessorResult.Ignore, result); | ||
} | ||
|
||
[Theory, AutoSubstituteData] | ||
public void ShouldBeIgnored_FirstCloaked(IContext ctx, IWindow window) | ||
{ | ||
// Given the first `EVENT_OBJECT_CLOAKED` event | ||
window.ProcessFileName.Returns("firefox.exe"); | ||
IWindowProcessor processor = FirefoxWindowProcessor.Create(ctx, window)!; | ||
|
||
// When the event is passed to `ShouldBeIgnored` | ||
WindowProcessorResult result = processor.ProcessEvent(PInvoke.EVENT_OBJECT_CLOAKED, 0, 0, 0, 0); | ||
|
||
// Then the event should be ignored | ||
Assert.Equal(WindowProcessorResult.Ignore, result); | ||
} | ||
|
||
[Theory, AutoSubstituteData] | ||
public void ShouldNotBeIgnored_SecondCloaked(IContext ctx, IWindow window) | ||
{ | ||
// Given the second `EVENT_OBJECT_CLOAKED` event | ||
window.ProcessFileName.Returns("firefox.exe"); | ||
IWindowProcessor processor = FirefoxWindowProcessor.Create(ctx, window)!; | ||
processor.ProcessEvent(PInvoke.EVENT_OBJECT_CLOAKED, 0, 0, 0, 0); | ||
|
||
// When the event is passed to `ShouldBeIgnored` | ||
WindowProcessorResult result = processor.ProcessEvent(PInvoke.EVENT_OBJECT_CLOAKED, 0, 0, 0, 0); | ||
|
||
// Then the event should not be ignored | ||
Assert.Equal(WindowProcessorResult.Process, result); | ||
} | ||
|
||
[Theory, AutoSubstituteData] | ||
public void ShouldBeRemoved(IContext ctx, IWindow window) | ||
{ | ||
// Given an `EVENT_OBJECT_DESTROY` event | ||
window.ProcessFileName.Returns("firefox.exe"); | ||
IWindowProcessor processor = FirefoxWindowProcessor.Create(ctx, window)!; | ||
|
||
// When the event is passed to `ShouldBeIgnored` | ||
WindowProcessorResult result = processor.ProcessEvent(PInvoke.EVENT_OBJECT_DESTROY, 0, 0, 0, 0); | ||
|
||
// Then the processor should be removed | ||
Assert.Equal(WindowProcessorResult.RemoveProcessor, result); | ||
} | ||
|
||
[Theory, AutoSubstituteData] | ||
public void Window(IContext ctx, IWindow window) | ||
{ | ||
// Given a window which is a Firefox window | ||
window.ProcessFileName.Returns("firefox.exe"); | ||
IWindowProcessor processor = FirefoxWindowProcessor.Create(ctx, window)!; | ||
|
||
// When `Window` is called | ||
IWindow result = processor.Window; | ||
|
||
// Then the result should be the window | ||
Assert.Equal(window, result); | ||
} | ||
} |
66 changes: 66 additions & 0 deletions
66
src/Whim.Tests/Store/WindowSector/Processors/WindowProcessorManagerTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
using Windows.Win32; | ||
|
||
namespace Whim.Tests; | ||
|
||
public class WindowProcessorManagerTests | ||
{ | ||
[Theory, AutoSubstituteData] | ||
public void ShouldBeIgnored_CreateProcessor_Failure(IContext ctx, IWindow window) | ||
{ | ||
// Given a window which is not a Firefox window | ||
window.ProcessFileName.Returns("chrome.exe"); | ||
WindowProcessorManager sut = new(ctx); | ||
|
||
// When ShouldBeIgnored is called | ||
bool result = sut.ShouldBeIgnored(window, default, default, default, default, default, default); | ||
|
||
// Then the result should be false | ||
Assert.False(result); | ||
} | ||
|
||
[Theory, AutoSubstituteData] | ||
public void ShouldBeIgnored_CreateProcessor_Success(IContext ctx, IWindow window) | ||
{ | ||
// Given a window which is a Firefox window | ||
window.ProcessFileName.Returns("firefox.exe"); | ||
WindowProcessorManager sut = new(ctx); | ||
|
||
// When ShouldBeIgnored is called for the first time | ||
bool result = sut.ShouldBeIgnored(window, default, default, default, default, default, default); | ||
|
||
// Then the result should be true | ||
Assert.True(result); | ||
} | ||
|
||
[Theory, AutoSubstituteData] | ||
public void ShouldBeIgnored_ProcessorExists_Process(IContext ctx, IWindow window) | ||
{ | ||
// Given a window which is a Firefox window | ||
window.ProcessFileName.Returns("firefox.exe"); | ||
WindowProcessorManager sut = new(ctx); | ||
|
||
// When ShouldBeIgnored is called for the second time | ||
sut.ShouldBeIgnored(window, default, PInvoke.EVENT_OBJECT_CLOAKED, 0, 0, 0, 0); | ||
bool result = sut.ShouldBeIgnored(window, default, 0, 0, 0, 0, 0); | ||
|
||
// Then the processor should have been created by the second call, and the window should not be ignored | ||
Assert.False(result); | ||
} | ||
|
||
[Theory, AutoSubstituteData] | ||
public void ShouldBeIgnored_ProcessorExists_RemoveProcessor(IContext ctx, IWindow window) | ||
{ | ||
// Given a window which is a Firefox window | ||
window.ProcessFileName.Returns("firefox.exe"); | ||
WindowProcessorManager sut = new(ctx); | ||
|
||
// When ShouldBeIgnored is called for the second time | ||
sut.ShouldBeIgnored(window, default, PInvoke.EVENT_OBJECT_CLOAKED, 0, 0, 0, 0); | ||
bool firstProcessorResult = sut.ShouldBeIgnored(window, default, PInvoke.EVENT_OBJECT_DESTROY, 0, 0, 0, 0); | ||
bool secondProcessorResult = sut.ShouldBeIgnored(window, default, 0, 0, 0, 0, 0); | ||
|
||
// Then the processor should have been removed by the second call, and the window should be ignored in the next call | ||
Assert.False(firstProcessorResult); | ||
Assert.True(secondProcessorResult); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.