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;