Skip to content

Commit

Permalink
Extract UpdateWindowRectangle from Floating and ProxyFloating layout (#…
Browse files Browse the repository at this point in the history
…967)

Extract shared `UpdateWindowRectangle` logic into a `FloatingUtils` static class, for the ``FloatingLayoutEngine` and `ProxyFloatingLayoutEngine`.
  • Loading branch information
Lukinoh authored Aug 6, 2024
1 parent ea8719b commit 0480abf
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 57 deletions.
26 changes: 7 additions & 19 deletions src/Whim.FloatingWindow/FloatingLayoutEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Whim.FloatingWindow;
/// <summary>
/// Layout engine that lays out all windows as free-floating.
/// </summary>
public class FloatingLayoutEngine : ILayoutEngine
public record FloatingLayoutEngine : ILayoutEngine
{
private readonly IContext _context;
private readonly ImmutableDictionary<IWindow, IRectangle<double>> _dict;
Expand Down Expand Up @@ -122,29 +122,17 @@ public ILayoutEngine MoveWindowEdgesInDirection(Direction edges, IPoint<double>

private FloatingLayoutEngine UpdateWindowRectangle(IWindow window)
{
// Try get the old rectangle.
IRectangle<double>? oldRectangle = _dict.TryGetValue(window, out IRectangle<double>? rectangle)
? rectangle
: null;

// Since the window is floating, we update the rectangle, and return.
IRectangle<int>? newActualRectangle = _context.NativeManager.DwmGetWindowRectangle(window.Handle);
if (newActualRectangle == null)
{
Logger.Error($"Could not obtain rectangle for floating window {window}");
return this;
}
ImmutableDictionary<IWindow, IRectangle<double>>? newDict = FloatingUtils.UpdateWindowRectangle(
_context,
_dict,
window
);

IMonitor newMonitor = _context.MonitorManager.GetMonitorAtPoint(newActualRectangle);
IRectangle<double> newUnitSquareRectangle = newMonitor.WorkingArea.NormalizeRectangle(newActualRectangle);
if (newUnitSquareRectangle.Equals(oldRectangle))
if (newDict == null || newDict == _dict)
{
Logger.Debug($"Rectangle for window {window} has not changed");
return this;
}

ImmutableDictionary<IWindow, IRectangle<double>> newDict = _dict.SetItem(window, newUnitSquareRectangle);

return new FloatingLayoutEngine(this, newDict);
}
}
48 changes: 48 additions & 0 deletions src/Whim.FloatingWindow/FloatingUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Collections.Immutable;

namespace Whim.FloatingWindow;

/// <summary>
/// Provide methods for the floating engines
/// </summary>
internal static class FloatingUtils
{
/// <summary>
/// Update the position of a <paramref name="window"/> from the <paramref name="dict"/>.
/// </summary>
/// <param name="context"></param>
/// <param name="dict"></param>
/// <param name="window"></param>
/// <returns></returns>
public static ImmutableDictionary<IWindow, IRectangle<double>>? UpdateWindowRectangle(
IContext context,
ImmutableDictionary<IWindow, IRectangle<double>> dict,
IWindow window
)
{
// Try get the old rectangle.
IRectangle<double>? oldRectangle = dict.TryGetValue(window, out IRectangle<double>? rectangle)
? rectangle
: null;

// Since the window is floating, we update the rectangle, and return.
IRectangle<int>? newActualRectangle = context.NativeManager.DwmGetWindowRectangle(window.Handle);
if (newActualRectangle == null)
{
Logger.Error($"Could not obtain rectangle for floating window {window}");
return null;
}

IMonitor newMonitor = context.MonitorManager.GetMonitorAtPoint(newActualRectangle);
IRectangle<double> newUnitSquareRectangle = newMonitor.WorkingArea.NormalizeRectangle(newActualRectangle);
if (newUnitSquareRectangle.Equals(oldRectangle))
{
Logger.Debug($"Rectangle for window {window} has not changed");
return dict;
}

ImmutableDictionary<IWindow, IRectangle<double>> newDict = dict.SetItem(window, newUnitSquareRectangle);

return newDict;
}
}
53 changes: 15 additions & 38 deletions src/Whim.FloatingWindow/ProxyFloatingLayoutEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,42 +143,31 @@ public override ILayoutEngine MoveWindowEdgesInDirection(Direction edge, IPoint<
return UpdateInner(InnerLayoutEngine.MoveWindowEdgesInDirection(edge, deltas, window), window);
}

private bool IsWindowFloating(IWindow window) =>
_plugin.FloatingWindows.TryGetValue(window, out ISet<LayoutEngineIdentity>? layoutEngines)
private bool IsWindowFloating(IWindow? window) =>
window != null
&& _plugin.FloatingWindows.TryGetValue(window, out ISet<LayoutEngineIdentity>? layoutEngines)
&& layoutEngines.Contains(InnerLayoutEngine.Identity);

private (ProxyFloatingLayoutEngine, bool error) UpdateWindowRectangle(IWindow window)
{
// Try get the old rectangle.
IRectangle<double>? oldRectangle = _floatingWindowRects.TryGetValue(window, out IRectangle<double>? rectangle)
? rectangle
: null;

// Since the window is floating, we update the rectangle, and return.
IRectangle<int>? newActualRectangle = _context.NativeManager.DwmGetWindowRectangle(window.Handle);
if (newActualRectangle == null)
ImmutableDictionary<IWindow, IRectangle<double>>? newDict = FloatingUtils.UpdateWindowRectangle(
_context,
_floatingWindowRects,
window
);

if (newDict == null)
{
Logger.Error($"Could not obtain rectangle for floating window {window}");
return (this, true);
}

IMonitor newMonitor = _context.MonitorManager.GetMonitorAtPoint(newActualRectangle);
IRectangle<double> newUnitSquareRectangle = newMonitor.WorkingArea.NormalizeRectangle(newActualRectangle);
if (newUnitSquareRectangle.Equals(oldRectangle))
if (newDict == _floatingWindowRects)
{
Logger.Debug($"Rectangle for window {window} has not changed");
return (this, false);
}

ILayoutEngine innerLayoutEngine = InnerLayoutEngine.RemoveWindow(window);
return (
new ProxyFloatingLayoutEngine(
this,
innerLayoutEngine,
_floatingWindowRects.SetItem(window, newUnitSquareRectangle)
),
false
);
return (new ProxyFloatingLayoutEngine(this, innerLayoutEngine, newDict), false);
}

/// <inheritdoc />
Expand All @@ -203,20 +192,8 @@ public override IEnumerable<IWindowState> DoLayout(IRectangle<int> rectangle, IM
}

/// <inheritdoc />
public override IWindow? GetFirstWindow()
{
if (InnerLayoutEngine.GetFirstWindow() is IWindow window)
{
return window;
}

if (_floatingWindowRects.Count > 0)
{
return _floatingWindowRects.Keys.First();
}

return null;
}
public override IWindow? GetFirstWindow() =>
InnerLayoutEngine.GetFirstWindow() ?? _floatingWindowRects.Keys.FirstOrDefault();

/// <inheritdoc />
public override ILayoutEngine FocusWindowInDirection(Direction direction, IWindow window)
Expand Down Expand Up @@ -262,7 +239,7 @@ public override ILayoutEngine MinimizeWindowEnd(IWindow window) =>
/// <inheritdoc />
public override ILayoutEngine PerformCustomAction<T>(LayoutEngineCustomAction<T> action)
{
if (action.Window != null && IsWindowFloating(action.Window))
if (IsWindowFloating(action.Window))
{
// At this stage, we don't have a way to get the window in a child layout engine at
// a given point.
Expand Down

0 comments on commit 0480abf

Please sign in to comment.