diff --git a/GlazeWM.App.IpcServer/Properties/launchSettings.json b/GlazeWM.App.IpcServer/Properties/launchSettings.json
new file mode 100644
index 000000000..9a7ce8b8c
--- /dev/null
+++ b/GlazeWM.App.IpcServer/Properties/launchSettings.json
@@ -0,0 +1,12 @@
+{
+ "profiles": {
+ "GlazeWM.App.IpcServer": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "applicationUrl": "https://localhost:61214;http://localhost:61215"
+ }
+ }
+}
\ No newline at end of file
diff --git a/GlazeWM.Domain/GlazeWM.Domain.csproj b/GlazeWM.Domain/GlazeWM.Domain.csproj
index dc36b139a..8c7e03ab1 100644
--- a/GlazeWM.Domain/GlazeWM.Domain.csproj
+++ b/GlazeWM.Domain/GlazeWM.Domain.csproj
@@ -12,4 +12,19 @@
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
diff --git a/GlazeWM.Domain/UserConfigs/CommandParsingService.cs b/GlazeWM.Domain/UserConfigs/CommandParsingService.cs
index 9fdd257bf..386879cb4 100644
--- a/GlazeWM.Domain/UserConfigs/CommandParsingService.cs
+++ b/GlazeWM.Domain/UserConfigs/CommandParsingService.cs
@@ -94,9 +94,7 @@ public Command ParseCommand(string commandString, Container subjectContainer)
? new IgnoreWindowCommand(subjectContainer as Window)
: new NoopCommand(),
"binding" => ParseBindingCommand(commandParts),
- "inspect" => subjectContainer is Window
- ? new InspectWindowCommand(subjectContainer as Window)
- : new NoopCommand(),
+ "inspect" => new InspectWindowCommand(subjectContainer as Window),
_ => throw new ArgumentException(null, nameof(commandString)),
};
}
diff --git a/GlazeWM.Domain/Windows/CommandHandlers/InspectWindowHandler.cs b/GlazeWM.Domain/Windows/CommandHandlers/InspectWindowHandler.cs
index 2ca09e7b9..c24e4b005 100644
--- a/GlazeWM.Domain/Windows/CommandHandlers/InspectWindowHandler.cs
+++ b/GlazeWM.Domain/Windows/CommandHandlers/InspectWindowHandler.cs
@@ -1,3 +1,5 @@
+using System.Threading;
+using System.Windows.Forms;
using GlazeWM.Domain.Windows.Commands;
using GlazeWM.Infrastructure.Bussing;
@@ -7,18 +9,30 @@ internal class InspectWindowHandler : ICommandHandler
{
public CommandResponse Handle(InspectWindowCommand command)
{
- var inspector = new Inspector();
- inspector.SetTitle(command.WindowToInspect.Title);
- inspector.SetClassName(command.WindowToInspect.ClassName);
- inspector.SetProcessName(command.WindowToInspect.ProcessName);
- inspector.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ // open inspector on a separate thread
+ var thread = new Thread(() =>
+ {
+ using var inspector = new Inspector();
+ inspector.ShowDialog(GetParentWindow(command.WindowToInspect));
+ });
- // show dialog as child of parent window
- var parentWindow = new System.Windows.Forms.NativeWindow();
- parentWindow.AssignHandle(command.WindowToInspect.Handle);
- inspector.ShowDialog(parentWindow);
+ thread.SetApartmentState(ApartmentState.STA);
+ thread.Start();
return CommandResponse.Ok;
}
+
+ private static NativeWindow GetParentWindow(Window windowToInspect)
+ {
+ if (windowToInspect == null)
+ {
+ return null;
+ }
+
+ var parentWindow = new NativeWindow();
+ parentWindow.AssignHandle(windowToInspect.Handle);
+
+ return parentWindow;
+ }
}
}
diff --git a/GlazeWM.Domain/Windows/Inspector.Designer.cs b/GlazeWM.Domain/Windows/Inspector.Designer.cs
index 588400248..2706696e0 100644
--- a/GlazeWM.Domain/Windows/Inspector.Designer.cs
+++ b/GlazeWM.Domain/Windows/Inspector.Designer.cs
@@ -1,3 +1,5 @@
+using System.Windows.Forms;
+
namespace GlazeWM.Domain.Windows
{
partial class Inspector
@@ -17,6 +19,9 @@ protected override void Dispose(bool disposing)
{
components.Dispose();
}
+
+ EventListener?.Dispose();
+
base.Dispose(disposing);
}
@@ -28,12 +33,12 @@ protected override void Dispose(bool disposing)
///
private void InitializeComponent()
{
- processNameLabel = new System.Windows.Forms.Label();
- classNameLabel = new System.Windows.Forms.Label();
- titleLabel = new System.Windows.Forms.Label();
- titleValue = new System.Windows.Forms.TextBox();
- classNameValue = new System.Windows.Forms.TextBox();
- processNameValue = new System.Windows.Forms.TextBox();
+ processNameLabel = new Label();
+ classNameLabel = new Label();
+ titleLabel = new Label();
+ titleValue = new TextBox();
+ classNameValue = new TextBox();
+ processNameValue = new TextBox();
SuspendLayout();
//
// processNameLabel
@@ -96,9 +101,9 @@ private void InitializeComponent()
// Inspector
//
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
- AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ AutoScaleMode = AutoScaleMode.Font;
BackColor = System.Drawing.SystemColors.Control;
- ClientSize = new System.Drawing.Size(412, 116);
+ ClientSize = new System.Drawing.Size(414, 116);
Controls.Add(processNameValue);
Controls.Add(classNameValue);
Controls.Add(titleValue);
@@ -119,20 +124,5 @@ private void InitializeComponent()
private System.Windows.Forms.TextBox titleValue;
private System.Windows.Forms.TextBox classNameValue;
private System.Windows.Forms.TextBox processNameValue;
-
- public void SetTitle(string title)
- {
- titleValue.Text = title;
- }
-
- public void SetClassName(string className)
- {
- classNameValue.Text = className;
- }
-
- public void SetProcessName(string processName)
- {
- processNameValue.Text = processName;
- }
}
}
diff --git a/GlazeWM.Domain/Windows/Inspector.cs b/GlazeWM.Domain/Windows/Inspector.cs
index 0bb75d9e5..5f92cc0c2 100644
--- a/GlazeWM.Domain/Windows/Inspector.cs
+++ b/GlazeWM.Domain/Windows/Inspector.cs
@@ -1,16 +1,52 @@
+using System;
+using System.Reactive.Linq;
using System.Windows.Forms;
+using GlazeWM.Infrastructure.WindowsApi;
+using static GlazeWM.Infrastructure.WindowsApi.WindowsApiService;
namespace GlazeWM.Domain.Windows
{
public partial class Inspector : Form
{
+ public IDisposable EventListener { get; }
+
public Inspector()
{
InitializeComponent();
-
MaximizeBox = false;
MinimizeBox = false;
FormBorderStyle = FormBorderStyle.FixedSingle;
+ StartPosition = FormStartPosition.CenterParent;
+
+ var point = new Point();
+ EventListener = MouseEvents.MouseMoves
+ .Sample(TimeSpan.FromMilliseconds(50))
+ .Subscribe((@event) =>
+ {
+ if (point.X == @event.Point.X && point.Y == @event.Point.Y)
+ {
+ return;
+ }
+
+ point.X = @event.Point.X;
+ point.Y = @event.Point.Y;
+ var handle = WindowFromPoint(point);
+
+ // get handle details
+ var processName = WindowService.GetProcessOfHandle(handle)?.ProcessName ?? string.Empty;
+ if (processName == "GlazeWM")
+ {
+ return;
+ }
+
+ var title = WindowService.GetTitleOfHandle(handle) ?? string.Empty;
+ var className = WindowService.GetClassNameOfHandle(handle) ?? string.Empty;
+
+ // update the inspector info
+ titleValue.Text = title;
+ classNameValue.Text = className;
+ processNameValue.Text = processName;
+ });
}
}
}
diff --git a/GlazeWM.Infrastructure/WindowsApi/Point.cs b/GlazeWM.Infrastructure/WindowsApi/Point.cs
index 93d8bd7fa..205cfaef3 100644
--- a/GlazeWM.Infrastructure/WindowsApi/Point.cs
+++ b/GlazeWM.Infrastructure/WindowsApi/Point.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
namespace GlazeWM.Infrastructure.WindowsApi
@@ -7,5 +8,20 @@ public struct Point
{
public int X;
public int Y;
+
+ public static bool operator ==(Point obj1, Point obj2)
+ {
+ return obj1.Equals(obj2);
+ }
+
+ public static bool operator !=(Point obj1, Point obj2)
+ {
+ return !(obj1 == obj2);
+ }
+
+ public override bool Equals([NotNullWhen(true)] object obj)
+ {
+ return obj is Point other && other.X == X && other.Y == Y;
+ }
}
}