From f268580a280a3237efa6942c0a3be6ac1e1d5654 Mon Sep 17 00:00:00 2001
From: Robert Di Pardo <59004801+rdipardo@users.noreply.github.com>
Date: Wed, 6 Mar 2024 19:38:16 -0500
Subject: [PATCH 1/2] Remove `WS_EX_CONTROLPARENT` when the panel undocks
Fixes #83
---
CSVLintNppPlugin/CsvLintNppPlugin.csproj | 3 +
CSVLintNppPlugin/Forms/CsvLintWindow.cs | 2 +-
CSVLintNppPlugin/Forms/DockingFormBase.cs | 67 +++++++++++++++++++
.../PluginInfrastructure/Win32.cs | 61 +++++++++++++++++
4 files changed, 132 insertions(+), 1 deletion(-)
create mode 100644 CSVLintNppPlugin/Forms/DockingFormBase.cs
diff --git a/CSVLintNppPlugin/CsvLintNppPlugin.csproj b/CSVLintNppPlugin/CsvLintNppPlugin.csproj
index 36bdf98..0b31e78 100644
--- a/CSVLintNppPlugin/CsvLintNppPlugin.csproj
+++ b/CSVLintNppPlugin/CsvLintNppPlugin.csproj
@@ -140,6 +140,9 @@
CsvLintWindow.cs
+
+ UserControl
+
diff --git a/CSVLintNppPlugin/Forms/CsvLintWindow.cs b/CSVLintNppPlugin/Forms/CsvLintWindow.cs
index 75e7afb..3771462 100644
--- a/CSVLintNppPlugin/Forms/CsvLintWindow.cs
+++ b/CSVLintNppPlugin/Forms/CsvLintWindow.cs
@@ -9,7 +9,7 @@
namespace Kbg.NppPluginNET
{
- public partial class CsvLintWindow : Form
+ public partial class CsvLintWindow : DockingFormBase
{
public CsvLintWindow()
{
diff --git a/CSVLintNppPlugin/Forms/DockingFormBase.cs b/CSVLintNppPlugin/Forms/DockingFormBase.cs
new file mode 100644
index 0000000..85ad606
--- /dev/null
+++ b/CSVLintNppPlugin/Forms/DockingFormBase.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+using Kbg.NppPluginNET.PluginInfrastructure;
+
+namespace CSVLintNppPlugin.Forms
+{
+ public partial class DockingFormBase : UserControl
+ {
+ private static Win32.WindowLongGetter _wndLongGetter;
+ private static Win32.WindowLongSetter _wndLongSetter;
+
+ public DockingFormBase()
+ {
+ if (Marshal.SizeOf(typeof(IntPtr)) == 8) // we are 64-bit
+ {
+ _wndLongGetter = Win32.GetWindowLongPtr;
+ _wndLongSetter = Win32.SetWindowLongPtr;
+ }
+ else // we are 32-bit
+ {
+ _wndLongGetter = Win32.GetWindowLong;
+ _wndLongSetter = Win32.SetWindowLong;
+ }
+ }
+
+ protected override void WndProc(ref Message m)
+ {
+ switch (m.Msg)
+ {
+ case Win32.WM_NOTIFY:
+ var nmdr = (Win32.TagNMHDR)Marshal.PtrToStructure(m.LParam, typeof(Win32.TagNMHDR));
+ if (nmdr.hwndFrom == PluginBase.nppData._nppHandle)
+ {
+ switch ((DockMgrMsg)(nmdr.code & 0xFFFFU))
+ {
+ case DockMgrMsg.DMN_DOCK: // we are being docked
+ break;
+ case DockMgrMsg.DMN_FLOAT: // we are being _un_docked
+ RemoveControlParent(this);
+ break;
+ case DockMgrMsg.DMN_CLOSE: // we are being closed
+ break;
+ }
+ }
+ break;
+ }
+ base.WndProc(ref m);
+ }
+
+ private void RemoveControlParent(Control parent)
+ {
+ if (parent.HasChildren)
+ {
+ long extAttrs = (long)_wndLongGetter(parent.Handle, Win32.GWL_EXSTYLE);
+ if (Win32.WS_EX_CONTROLPARENT == (extAttrs & Win32.WS_EX_CONTROLPARENT))
+ {
+ _wndLongSetter(parent.Handle, Win32.GWL_EXSTYLE, new IntPtr(extAttrs & ~Win32.WS_EX_CONTROLPARENT));
+ }
+ foreach (Control c in parent.Controls)
+ {
+ RemoveControlParent(c);
+ }
+ }
+ }
+ }
+}
diff --git a/CSVLintNppPlugin/PluginInfrastructure/Win32.cs b/CSVLintNppPlugin/PluginInfrastructure/Win32.cs
index 3933e00..53dd4ca 100644
--- a/CSVLintNppPlugin/PluginInfrastructure/Win32.cs
+++ b/CSVLintNppPlugin/PluginInfrastructure/Win32.cs
@@ -48,6 +48,17 @@ public struct ScrollInfo
public int nTrackPos;
}
+ ///
+ /// @see https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-nmhdr
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TagNMHDR
+ {
+ public IntPtr hwndFrom;
+ public UIntPtr idFrom;
+ public uint code;
+ }
+
///
/// Used for the ScrollInfo fMask
/// SIF_ALL => Combination of SIF_PAGE, SIF_POS, SIF_RANGE, and SIF_TRACKPOS.
@@ -302,6 +313,56 @@ public static IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, ref LangType
public static extern int CheckMenuItem(IntPtr hmenu, int uIDCheckItem, int uCheck);
public const int WM_CREATE = 1;
+ public const int WM_NOTIFY = 0x004e;
+ public const int GWL_EXSTYLE = -20;
+ public const int GWLP_HINSTANCE = -6;
+ public const int GWLP_HWNDPARENT = -8;
+ public const int GWLP_ID = -12;
+ public const int GWL_STYLE = -16;
+ public const int GWLP_USERDATA = -21;
+ public const int GWLP_WNDPROC = -4;
+ public const long WS_EX_ACCEPTFILES = 0x00000010L;
+ public const long WS_EX_APPWINDOW = 0x00040000L;
+ public const long WS_EX_CLIENTEDGE = 0x00000200L;
+ public const long WS_EX_COMPOSITED = 0x02000000L;
+ public const long WS_EX_CONTEXTHELP = 0x00000400L;
+ public const long WS_EX_CONTROLPARENT = 0x00010000L;
+ public const long WS_EX_DLGMODALFRAME = 0x00000001L;
+ public const long WS_EX_LAYERED = 0x00080000L;
+ public const long WS_EX_LAYOUTRTL = 0x00400000L;
+ public const long WS_EX_LEFT = 0x00000000L;
+ public const long WS_EX_LEFTSCROLLBAR = 0x00004000L;
+ public const long WS_EX_LTRREADING = 0x00000000L;
+ public const long WS_EX_MDICHILD = 0x00000040L;
+ public const long WS_EX_NOACTIVATE = 0x08000000L;
+ public const long WS_EX_NOINHERITLAYOUT = 0x00100000L;
+ public const long WS_EX_NOPARENTNOTIFY = 0x00000004L;
+ public const long WS_EX_NOREDIRECTIONBITMAP = 0x00200000L;
+ public const long WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
+ public const long WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST);
+ public const long WS_EX_RIGHT = 0x00001000L;
+ public const long WS_EX_RIGHTSCROLLBAR = 0x00000000L;
+ public const long WS_EX_RTLREADING = 0x00002000L;
+ public const long WS_EX_STATICEDGE = 0x00020000L;
+ public const long WS_EX_TOOLWINDOW = 0x00000080L;
+ public const long WS_EX_TOPMOST = 0x00000008L;
+ public const long WS_EX_TRANSPARENT = 0x00000020L;
+ public const long WS_EX_WINDOWEDGE = 0x00000100L;
+
+ public delegate IntPtr WindowLongGetter(IntPtr hWnd, int nIndex);
+ public delegate IntPtr WindowLongSetter(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
+
+ [DllImport("user32")]
+ public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ [DllImport("user32")]
+ public static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
+
+ [DllImport("user32")]
+ public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
+
+ [DllImport("user32")]
+ public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32")]
public static extern bool ClientToScreen(IntPtr hWnd, ref Point lpPoint);
From 175a187828edfeafc014baf09f4d08e6cd981fcb Mon Sep 17 00:00:00 2001
From: Robert Di Pardo <59004801+rdipardo@users.noreply.github.com>
Date: Wed, 6 Mar 2024 23:10:31 -0500
Subject: [PATCH 2/2] Derive from `Form` to keep dark mode theming consistent
---
CSVLintNppPlugin/CsvLintNppPlugin.csproj | 5 ++-
.../Forms/DockingFormBase.Designer.cs | 37 +++++++++++++++++++
CSVLintNppPlugin/Forms/DockingFormBase.cs | 3 +-
3 files changed, 43 insertions(+), 2 deletions(-)
create mode 100644 CSVLintNppPlugin/Forms/DockingFormBase.Designer.cs
diff --git a/CSVLintNppPlugin/CsvLintNppPlugin.csproj b/CSVLintNppPlugin/CsvLintNppPlugin.csproj
index 0b31e78..878ad45 100644
--- a/CSVLintNppPlugin/CsvLintNppPlugin.csproj
+++ b/CSVLintNppPlugin/CsvLintNppPlugin.csproj
@@ -141,7 +141,10 @@
CsvLintWindow.cs
- UserControl
+ Form
+
+
+ DockingFormBase.cs
diff --git a/CSVLintNppPlugin/Forms/DockingFormBase.Designer.cs b/CSVLintNppPlugin/Forms/DockingFormBase.Designer.cs
new file mode 100644
index 0000000..0a69c75
--- /dev/null
+++ b/CSVLintNppPlugin/Forms/DockingFormBase.Designer.cs
@@ -0,0 +1,37 @@
+namespace CSVLintNppPlugin.Forms
+{
+ partial class DockingFormBase
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ components = new System.ComponentModel.Container();
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ }
+
+ #endregion
+ }
+}
diff --git a/CSVLintNppPlugin/Forms/DockingFormBase.cs b/CSVLintNppPlugin/Forms/DockingFormBase.cs
index 85ad606..ee7c31b 100644
--- a/CSVLintNppPlugin/Forms/DockingFormBase.cs
+++ b/CSVLintNppPlugin/Forms/DockingFormBase.cs
@@ -5,13 +5,14 @@
namespace CSVLintNppPlugin.Forms
{
- public partial class DockingFormBase : UserControl
+ public partial class DockingFormBase : Form
{
private static Win32.WindowLongGetter _wndLongGetter;
private static Win32.WindowLongSetter _wndLongSetter;
public DockingFormBase()
{
+ InitializeComponent();
if (Marshal.SizeOf(typeof(IntPtr)) == 8) // we are 64-bit
{
_wndLongGetter = Win32.GetWindowLongPtr;