dockpanelsuite
dockpanelsuite copied to clipboard
Minimize Button Click Not Detected
https://github.com/dockpanelsuite/dockpanelsuite/blob/bb1246b6950b9a0c8ac24c3c22a1bc77af4a49e8/WinFormsUI/Docking/FloatWindow.cs#L197
On some setups, clicking the in lower left corner of the minimize button on the title bar will not be detected correctly. The result from the hit test will come back with a 2 indicating the title bar rather than an 8 for the minimize button. For the WM_NCLBUTTONDOWN message, the WParam included in the Message passed to WndProc should be used to determine where the click occurred. https://msdn.microsoft.com/en-us/library/windows/desktop/ms645620(v=vs.85).aspx
This line should be removed and the relevant part of the if statement on the next line should be changed to
(uint)m.WParam == 2
We cannot make the changes you described so far. Though there are tons of related articles from Microsoft, this library itself proves that many tricks are still necessary.
We are also cautious on patches. You can review our recent releases and see how patch controller was invented to enable experimental patches.
My guess on the cause is also different. Maybe the minimize button area calculation code has some issues under that setup so indeed the hit test returns 2. This happened once in the past (like #510). Thus, before drawing a conclusion, we need to identify exactly the setup and steps to reproduce it reliably. That can give us a solid foundation to troubleshoot and locate the culprit.
My specific setup is using Dock Panel Suite on Windows 10 with 3 monitors. From left to right, monitor one has a screen resolution of 1920x1080 scaled to 125%, monitor three is 1680x1050 scaled to 100% and monitor two is 1920x1080 scaled to 100%.
When using a float window, the red section in the image below does not work while the green section does. When I make the suggested change, everything works as expected. But like you mentioned that was only under the limited testing of my system. My coworkers have similar setups except on Windows 7. They can reproduce the issue to a lesser extent in that the red region is not as pronounced.

If you are willing to impart some of your knowledge and experience on me, out of my own intellectual curiosity, what issues are there with using the WParam that is provided with the Message?
Just noticed that you are using a customized FloatWindow. Then you can override WndProc to resolve the issue.
I will be reluctant to include the changes in master, as
- For the default
FloatWindowwith no such buttons, the existing code seems to work. - Current maintainers including me try to avoid changes to existing code base whenever possible, as honestly speaking we are not the original developers, and we don't know what harm any change can lead to.
I put your changes on a new branch, and might put the patch under patch controller for future releases, but that's just an idea, not a promise.
In case anyone is still interested in this issue, I added a custom MinimizingFloatWindow using instructions found here: [http://docs.dockpanelsuite.com/tutorials/customizing-floatwindow.html]
It had the same issue which I have seen in other free software (Click Minimize only works on one side). I set up a MinButton variable and captured the mouse move message to set it to true when you mouse over the minimize button. Then the click message check the variable and minimizes or restores the form depending on its window state. Its kludgy but it works.
bool MinButton = false;
int SC_MINIMIZE = 0xF020;
int SC_RESTORE = 0xF120;
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
[System.Diagnostics.DebuggerStepThrough]
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)Win32.Msgs.WM_NCMOUSEMOVE)
{
if ((int)m.WParam == 0x8)
MinButton = true;
else
MinButton = false;
}
else if (m.Msg == (int)Win32.Msgs.WM_MOUSEMOVE)
{
MinButton = false;
}
switch (m.Msg)
{
case (int)Win32.Msgs.WM_NCLBUTTONDOWN:
{
if (IsDisposed)
return;
if (MinButton)
{
if (this.WindowState == FormWindowState.Minimized)
NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_SYSCOMMAND, (uint)SC_RESTORE, 0);
else
NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_SYSCOMMAND, (uint)SC_MINIMIZE, 0);
return;
}
The rest of the WndProc procedure is the same as the standard FloatWindow.
The suggested solution by @mapper55 will minimize the window as soon as the left mouse button is pressed down. This is not how Windows usually works; normally it's only on mouseup that the action is taken.
That said, if you change it to look at WM_NCLBUTTONUP instead, then clicking in the red region initiates a drag operation, whereas minimizing on mousedown doesn't give time for that. The proper fix would be to use the correct hit test value for the drag operation too.
I think the better fix would be the one suggested by @TheBobman03. This would mean the dragging code works as it should too.
In case anyone is "still still" interested in this issue I'll post a complete implementation of a customized FloatWindow. It will address the minimize issue with the solution suggested by @mapper55 and also address another annoying issue where you dock two FloatWindows together and a new instance is created automatically that does not preserve any Icon set (will force null / default icon).
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;
namespace MyNamespace
{
public class CustomFloatWindow : FloatWindow
{
Icon mIcon;
public CustomFloatWindow(DockPanel dockPanel, DockPane pane)
: base(dockPanel, pane)
{
setDefaultProperties();
}
public CustomFloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds)
: base(dockPanel, pane, bounds)
{
setDefaultProperties();
}
private void setDefaultProperties()
{
FormBorderStyle = FormBorderStyle.Sizable;
// To enable Alt+Tab between your undocked forms and your main form
ShowInTaskbar = true;
Owner = null;
// Allow the Windows default behavior of maximizing/restoring the window
DoubleClickTitleBarToDock = false;
var resources = new System.ComponentModel.ComponentResourceManager(typeof(MyChosenForm));
mIcon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
Icon = mIcon;
}
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern uint SendMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m)
{
int WM_NCLBUTTONDOWN = 0x00A1;
int WM_SYSCOMMAND = 0x0112;
int WM_GETICON = 0x007F;
int SC_MINIMIZE = 0xF020;
int SC_RESTORE = 0xF120;
if (m.Msg == WM_NCLBUTTONDOWN)
{
if (IsDisposed)
return;
if ((uint)m.WParam == 8) // Check if button down occured in minimize box
{
if (WindowState == FormWindowState.Minimized)
CustomFloatWindow.SendMessage(Handle, (int)WM_SYSCOMMAND, (uint)SC_RESTORE, 0);
else
CustomFloatWindow.SendMessage(Handle, (int)WM_SYSCOMMAND, (uint)SC_MINIMIZE, 0);
return;
}
}
else if (m.Msg == WM_GETICON)
{
// A combined new FloatWindow will use default SetText() method which sets Text to space and Icon to null,
// hammering an override here until both are properly set, C-
if (Text == " ")
{
Text = "MyText"; // Anything but spacy really
Icon = mIcon;
}
}
base.WndProc(ref m);
}
}
public class CustomFloatWindowFactory : DockPanelExtender.IFloatWindowFactory
{
public FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds)
{
return new CustomFloatWindow(dockPanel, pane, bounds);
}
public FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane)
{
return new CustomFloatWindow(dockPanel, pane);
}
}
}