From 7f2e1dee888cb4c70e39bcb36e51604ea84be526 Mon Sep 17 00:00:00 2001 From: blam <61704528+notblam@users.noreply.github.com> Date: Tue, 5 Sep 2023 16:55:23 -0400 Subject: [PATCH] feat: add `FocusedContainerMovedEvent` and `NativeFocusReassignedEvent` (#378) --- GlazeWM.App.IpcServer/IpcMessageHandler.cs | 1 + GlazeWM.App.WindowManager/WmStartup.cs | 29 +++++++++++++++++-- GlazeWM.Domain/Common/DomainEvent.cs | 2 ++ .../MoveContainerWithinTreeHandler.cs | 15 ++++++---- .../CommandHandlers/SetNativeFocusHandler.cs | 5 ++-- .../Events/FocusedContainerMovedEvent.cs | 8 +++++ .../Events/NativeFocusReassignedEvent.cs | 8 +++++ 7 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 GlazeWM.Domain/Containers/Events/FocusedContainerMovedEvent.cs create mode 100644 GlazeWM.Domain/Containers/Events/NativeFocusReassignedEvent.cs diff --git a/GlazeWM.App.IpcServer/IpcMessageHandler.cs b/GlazeWM.App.IpcServer/IpcMessageHandler.cs index 2fdbbdc63..10bc009c9 100644 --- a/GlazeWM.App.IpcServer/IpcMessageHandler.cs +++ b/GlazeWM.App.IpcServer/IpcMessageHandler.cs @@ -60,6 +60,7 @@ public sealed class IpcMessageHandler { DomainEvent.BindingModeChanged, DomainEvent.FocusChanged, + DomainEvent.FocusedContainerMoved, DomainEvent.MonitorAdded, DomainEvent.MonitorRemoved, DomainEvent.TilingDirectionChanged, diff --git a/GlazeWM.App.WindowManager/WmStartup.cs b/GlazeWM.App.WindowManager/WmStartup.cs index 373fcf55e..94291d37f 100644 --- a/GlazeWM.App.WindowManager/WmStartup.cs +++ b/GlazeWM.App.WindowManager/WmStartup.cs @@ -74,10 +74,23 @@ public ExitCode Run() _systemTrayIcon = new SystemTrayIcon(systemTrayIconConfig); _systemTrayIcon.Show(); + var nativeFocusReassigned = _bus.Events + .OfType() + .Select((@event) => @event.FocusedContainer); + if (_userConfigService.FocusBorderConfig.Active.Enabled || _userConfigService.FocusBorderConfig.Inactive.Enabled) - _bus.Events.OfType().Subscribe((@event) => - _bus.InvokeAsync(new SetActiveWindowBorderCommand(@event.FocusedContainer as Window))); + { + var focusChanged = _bus.Events + .OfType() + .Select(@event => @event.FocusedContainer); + + focusChanged + .Merge(nativeFocusReassigned) + .Subscribe((container) => + _bus.InvokeAsync(new SetActiveWindowBorderCommand(container as Window)) + ); + } // Hook mouse event for focus follows cursor. if (_userConfigService.GeneralConfig.FocusFollowsCursor) @@ -87,6 +100,18 @@ public ExitCode Run() _bus.InvokeAsync(new FocusContainerUnderCursorCommand(@event.Point)); }); + // Setup cursor follows focus + if (_userConfigService.GeneralConfig.CursorFollowsFocus) + { + var focusedContainerMoved = _bus.Events + .OfType() + .Select(@event => @event.FocusedContainer); + + focusedContainerMoved.Merge(nativeFocusReassigned) + .Where(container => container is Window) + .Subscribe((window) => _bus.InvokeAsync(new CenterCursorOnContainerCommand(window))); + } + System.Windows.Forms.Application.Run(); return ExitCode.Success; } diff --git a/GlazeWM.Domain/Common/DomainEvent.cs b/GlazeWM.Domain/Common/DomainEvent.cs index 0bc986cee..a5291668d 100644 --- a/GlazeWM.Domain/Common/DomainEvent.cs +++ b/GlazeWM.Domain/Common/DomainEvent.cs @@ -4,8 +4,10 @@ public static class DomainEvent { public const string BindingModeChanged = "binding_mode_changed"; public const string FocusChanged = "focus_changed"; + public const string FocusedContainerMoved = "focused_container_moved"; public const string MonitorAdded = "monitor_added"; public const string MonitorRemoved = "monitor_removed"; + public const string NativeFocusReassigned = "native_focus_reassigned"; public const string TilingDirectionChanged = "tiling_direction_changed"; public const string UserConfigReloaded = "user_config_reloaded"; public const string WindowManaged = "window_managed"; diff --git a/GlazeWM.Domain/Containers/CommandHandlers/MoveContainerWithinTreeHandler.cs b/GlazeWM.Domain/Containers/CommandHandlers/MoveContainerWithinTreeHandler.cs index 661ceb73a..882b12733 100644 --- a/GlazeWM.Domain/Containers/CommandHandlers/MoveContainerWithinTreeHandler.cs +++ b/GlazeWM.Domain/Containers/CommandHandlers/MoveContainerWithinTreeHandler.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using GlazeWM.Domain.Containers.Commands; +using GlazeWM.Domain.Containers.Events; using GlazeWM.Infrastructure.Bussing; using GlazeWM.Infrastructure.Utils; @@ -9,10 +10,12 @@ namespace GlazeWM.Domain.Containers.CommandHandlers internal sealed class MoveContainerWithinTreeHandler : ICommandHandler { private readonly Bus _bus; + private readonly ContainerService _containerService; - public MoveContainerWithinTreeHandler(Bus bus) + public MoveContainerWithinTreeHandler(Bus bus, ContainerService containerService) { _bus = bus; + _containerService = containerService; } public CommandResponse Handle(MoveContainerWithinTreeCommand command) @@ -32,6 +35,8 @@ public CommandResponse Handle(MoveContainerWithinTreeCommand command) targetParent ); + var focusedContainer = _containerService.FocusedContainer; + // Handle case where target parent is the LCA (eg. in the case of swapping sibling containers // or moving a container to a direct ancestor). if (targetParent == lowestCommonAncestor) @@ -43,8 +48,8 @@ public CommandResponse Handle(MoveContainerWithinTreeCommand command) shouldAdjustSize ); - // Center cursor in focused window's new location - _bus.InvokeAsync(new CenterCursorOnContainerCommand(containerToMove)); + if (containerToMove == focusedContainer) + _bus.Emit(new FocusedContainerMovedEvent(containerToMove)); return CommandResponse.Ok; } @@ -90,8 +95,8 @@ public CommandResponse Handle(MoveContainerWithinTreeCommand command) targetParentAncestor ); - // Center cursor in focused window's new location - _bus.InvokeAsync(new CenterCursorOnContainerCommand(containerToMove)); + if (containerToMove == focusedContainer) + _bus.Emit(new FocusedContainerMovedEvent(containerToMove)); return CommandResponse.Ok; } diff --git a/GlazeWM.Domain/Containers/CommandHandlers/SetNativeFocusHandler.cs b/GlazeWM.Domain/Containers/CommandHandlers/SetNativeFocusHandler.cs index 1909bd25c..e8dbf9b8d 100644 --- a/GlazeWM.Domain/Containers/CommandHandlers/SetNativeFocusHandler.cs +++ b/GlazeWM.Domain/Containers/CommandHandlers/SetNativeFocusHandler.cs @@ -36,6 +36,8 @@ public CommandResponse Handle(SetNativeFocusCommand command) KeybdEvent(0, 0, 0, 0); SetForegroundWindow(handleToFocus); + _bus.Emit(new NativeFocusReassignedEvent(containerToFocus)); + // Setting focus to the desktop window does not emit `EVENT_SYSTEM_FOREGROUND` window event, // so `SetFocusedDescendantCommand` has to be manually called. // TODO: This is called twice unnecessarily when setting workspace focus on unmanage. @@ -45,9 +47,6 @@ public CommandResponse Handle(SetNativeFocusCommand command) _bus.Emit(new FocusChangedEvent(containerToFocus)); } - // Center cursor in focused window's new location - _bus.InvokeAsync(new CenterCursorOnContainerCommand(containerToFocus)); - return CommandResponse.Ok; } } diff --git a/GlazeWM.Domain/Containers/Events/FocusedContainerMovedEvent.cs b/GlazeWM.Domain/Containers/Events/FocusedContainerMovedEvent.cs new file mode 100644 index 000000000..a781a9049 --- /dev/null +++ b/GlazeWM.Domain/Containers/Events/FocusedContainerMovedEvent.cs @@ -0,0 +1,8 @@ +using GlazeWM.Domain.Common; +using GlazeWM.Infrastructure.Bussing; + +namespace GlazeWM.Domain.Containers.Events +{ + public record FocusedContainerMovedEvent(Container FocusedContainer) + : Event(DomainEvent.FocusedContainerMoved); +} diff --git a/GlazeWM.Domain/Containers/Events/NativeFocusReassignedEvent.cs b/GlazeWM.Domain/Containers/Events/NativeFocusReassignedEvent.cs new file mode 100644 index 000000000..7c1795d07 --- /dev/null +++ b/GlazeWM.Domain/Containers/Events/NativeFocusReassignedEvent.cs @@ -0,0 +1,8 @@ +using GlazeWM.Domain.Common; +using GlazeWM.Infrastructure.Bussing; + +namespace GlazeWM.Domain.Containers.Events +{ + public record NativeFocusReassignedEvent(Container FocusedContainer) + : Event(DomainEvent.NativeFocusReassigned); +}