Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent gaps-triggered shifting for FloatingLayoutEngine #1069

Merged
merged 3 commits into from
Nov 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 76 additions & 4 deletions src/Whim.Gaps.Tests/GapsLayoutEngineTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using FluentAssertions;
using NSubstitute;
using Whim.FloatingWindow;
using Whim.SliceLayout;
using Whim.TestUtils;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Gdi;
Expand Down Expand Up @@ -99,11 +100,18 @@ public static TheoryData<GapsConfig, IWindow[], int, IWindowState[]> DoLayout_Da
}

[Theory]
[MemberData(nameof(DoLayout_Data))]
public void DoLayout(GapsConfig gapsConfig, IWindow[] windows, int scale, IWindowState[] expectedWindowStates)
[MemberAutoSubstituteData(nameof(DoLayout_Data))]
public void DoLayout(
GapsConfig gapsConfig,
IWindow[] windows,
int scale,
IWindowState[] expectedWindowStates,
ISliceLayoutPlugin sliceLayoutPlugin,
IContext ctx
)
{
// Given
ILayoutEngine innerLayoutEngine = new ColumnLayoutEngine(_identity);
ILayoutEngine innerLayoutEngine = SliceLayouts.CreateRowLayout(ctx, sliceLayoutPlugin, _identity);

foreach (IWindow w in windows)
{
Expand Down Expand Up @@ -405,7 +413,7 @@ IWindowState[] expectedWindowStates

[Theory, AutoSubstituteData<StoreCustomization>]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")]
internal void DoLayout_WithFloatingLayoutEngine(IContext context, MutableRootSector root)
internal void DoLayout_WithProxyFloatingLayoutEngine(IContext context, MutableRootSector root)
{
// Input
GapsConfig gapsConfig = new();
Expand Down Expand Up @@ -506,6 +514,70 @@ internal void DoLayout_WithFloatingLayoutEngine(IContext context, MutableRootSec
);
}

[Theory, AutoSubstituteData<StoreCustomization>]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")]
internal void DoLayout_WithFloatingLayoutEngine(IContext context, MutableRootSector root)
{
// Input
GapsConfig gapsConfig = new();

Rectangle<int> rect1 = new(10, 10, 20, 20);
Rectangle<int> rect2 = new(30, 30, 40, 40);

IMonitor monitor = StoreTestUtils.CreateMonitor((HMONITOR)1);
monitor.WorkingArea.Returns(new Rectangle<int>(0, 0, 100, 100));

IWindow window1 = StoreTestUtils.CreateWindow((HWND)1);
IWindow window2 = StoreTestUtils.CreateWindow((HWND)2);

Workspace workspace = StoreTestUtils.CreateWorkspace(context);
StoreTestUtils.PopulateThreeWayMap(context, root, monitor, workspace, window1);
StoreTestUtils.PopulateWindowWorkspaceMap(context, root, window2, workspace);

context.NativeManager.DwmGetWindowRectangle(window1.Handle).Returns(rect1);
context.NativeManager.DwmGetWindowRectangle(window2.Handle).Returns(rect2);

FloatingLayoutEngine floatingLayoutEngine = new(context, _identity);

// Given
GapsLayoutEngine gapsLayoutEngine = new(gapsConfig, floatingLayoutEngine);

// When
GapsLayoutEngine gaps1 = (GapsLayoutEngine)gapsLayoutEngine.AddWindow(window1);
GapsLayoutEngine gaps2 = (GapsLayoutEngine)gaps1.AddWindow(window2);

IWindowState[] outputWindowStates = gaps2.DoLayout(monitor.WorkingArea, monitor).ToArray();

// Then
Assert.Equal(2, outputWindowStates.Length);

Assert.Contains(
outputWindowStates,
ws =>
ws.Equals(
new WindowState()
{
Window = window1,
Rectangle = rect1,
WindowSize = WindowSize.Normal,
}
)
);

Assert.Contains(
outputWindowStates,
ws =>
ws.Equals(
new WindowState()
{
Window = window2,
Rectangle = rect2,
WindowSize = WindowSize.Normal,
}
)
);
}

[Theory, AutoSubstituteData]
public void Count(ILayoutEngine innerLayoutEngine)
{
Expand Down
1 change: 1 addition & 0 deletions src/Whim.Gaps.Tests/Whim.Gaps.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Whim.Gaps\Whim.Gaps.csproj" />
<ProjectReference Include="..\Whim.SliceLayout\Whim.SliceLayout.csproj" />
<ProjectReference Include="..\Whim.TestUtils\Whim.TestUtils.csproj" />
</ItemGroup>
</Project>
15 changes: 13 additions & 2 deletions src/Whim.Gaps/GapsLayoutEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,27 @@ private GapsLayoutEngine UpdateInner(ILayoutEngine newInnerLayoutEngine) =>
/// <inheritdoc />
public override IEnumerable<IWindowState> DoLayout(IRectangle<int> rectangle, IMonitor monitor)
{
// If the inner layout engine is a floating layout engine, then we don't apply gaps.
if (InnerLayoutEngine.GetLayoutEngine<FloatingLayoutEngine>() is not null)
{
foreach (IWindowState windowState in InnerLayoutEngine.DoLayout(rectangle, monitor))
{
yield return windowState;
}
yield break;
}

// If the inner layout engine is a proxy floating layout engine, then we apply gaps for the non-floating windows.
int nonProxiedCount = 0;
if (InnerLayoutEngine is ProxyFloatingLayoutEngine proxy)
if (InnerLayoutEngine.GetLayoutEngine<ProxyFloatingLayoutEngine>() is ProxyFloatingLayoutEngine proxy)
{
nonProxiedCount = proxy.FloatingWindowRects.Count + proxy.MinimizedWindowRects.Count;

// The InnerLayoutEngine will use the default rectangle for nonProxiedCount.
// The InnerLayoutEngine will use the proxied rectangle for the remaining windows.
// This is brittle and relies on the order of the windows in the ProxyFloatingLayoutEngine.

IEnumerable<IWindowState> windows = InnerLayoutEngine.DoLayout(rectangle, monitor);
IEnumerable<IWindowState> windows = proxy.DoLayout(rectangle, monitor);
using IEnumerator<IWindowState> enumerator = windows.GetEnumerator();

for (int i = 0; i < nonProxiedCount; i++)
Expand Down