| [ Return to Bugs & Features | Roadmap 1.3 | SVN ⇄ GIT ]
STR #3061
Application: | FLTK Library |
Status: | 1 - Closed w/Resolution |
Priority: | 3 - Moderate, e.g. unable to compile the software |
Scope: | 2 - Specific to an operating system |
Subsystem: | WIN32 |
Summary: | Non-resizable window border width is miscalculated in certain conditions on Windows Vista and up |
Version: | 1.3.2 |
Created By: | greentea101 |
Assigned To: | AlbrechtS |
Fix Version: | 1.3.3 (SVN: v10363) |
Update Notification: | |
Trouble Report Files:
Trouble Report Comments:
|
#1 | greentea101 15:33 Mar 02, 2014 |
| Problem symptom: ================
When an executable is built with MajorSubsystemVersion = 6 in the optional header of the image, the initial drawing of non-resizable FLTK windows (via Show()) omits a number of pixels from the client area that is proportional to the Border Padding setting in Windows. Specifically, the right and bottom borders are drawn over the client area, as shown in the image I attached. If the window is moved, the move operation causes the window to be drawn correctly.
In Visual C++ 2012, the subsystem version is controlled by the setting "Configuration Properties->General->Platform Toolset" from the project settings. Alternatively, it can also be changed from "Linker->System->Minimum Required Version". I wouldn't know about other IDEs and compilers.
The MajorSubsystemVersion and MinorSubsystemVersion data can also be modified "after the fact" by editing the PE header with a tool like CFF Explorer, to the same effect.
Problem cause: ==============
The cause of this behavior has to do with the way Windows uses the Border Padding setting, and the fact that FLTK doesn't take that setting into account altogether. Windows 7 uses padding to draw the border of resizable windows, and doesn't use it for non-resizable windows EXCEPT if MajorSubsystemVersion is 6 in the PE header. This is true if the Windows Classic or Windows Basic themes are being used. If the Aero theme is used, then all windows respect the Border Padding setting without exception, but the behavior I described still happens for whatever reason.
Inside the function Fl_X::fake_X_wm() from Fl_win32.cxx, the following code is found:
if (w->size_range_set && (w->maxw != w->minw || w->maxh != w->minh)) { ret = 2; bx = GetSystemMetrics(SM_CXSIZEFRAME); by = GetSystemMetrics(SM_CYSIZEFRAME); } else { ret = 1; bx = GetSystemMetrics(SM_CXFIXEDFRAME); by = GetSystemMetrics(SM_CYFIXEDFRAME); }
That code determines that the border width for non-resizable windows is GetSystemMetrics(SM_CXFIXEDFRAME), which is fine if MajorSubsystemVersion < 6, but is not fine if MajorSubsystemVersion = 6, because in that case the border padding is taken into account as well.
I have fixed it like this:
if (w->size_range_set && (w->maxw != w->minw || w->maxh != w->minh)) { ret = 2; bx = GetSystemMetrics(SM_CXSIZEFRAME); by = GetSystemMetrics(SM_CYSIZEFRAME); } else { ret = 1; int padding = GetSystemMetrics(92); // SM_CXPADDEDBORDER bx = GetSystemMetrics(SM_CXFIXEDFRAME) + (padding ? padding + GetSystemMetrics(SM_CXBORDER) : 0); by = GetSystemMetrics(SM_CYFIXEDFRAME) + (padding ? padding + GetSystemMetrics(SM_CYBORDER) : 0); }
I couldn't use SM_CXPADDEDBORDER because it was undefined (because _WIN32_WINNT was defined as 0x0500, and SM_CXPADDEDBORDER is not supported on WinXP), so I used its value (92). If MajorSubsystemVersion < 6, then GetSystemMetrics(92) returns 0, and if MajorSubsystemVersion = 6 then it returns 4 or whatever the "BorderPadding" setting is. | |
|
#2 | ianmacarthur 08:35 Mar 03, 2014 |
| Well, I guess this looks right - I've spent *some* time staring at MSDN, and all the bits make sense, but I still don't know what MS are doing here...
Why do we need to measure GetSystemMetrics(SM_CXBORDER) *and* the padding, for example? Why can't one parameter do the job?
And why doesn't the WM account for this itself? Why does it have to be done in user code? I'm sure that window borders always *used* to be handled by the WM without special handling by the user code...?
Anyway, if we do go with this, I'd suggest adding something like...
#ifndef SM_CXPADDEDBORDER # define SM_CXPADDEDBORDER 92 #endif /* SM_CXPADDEDBORDER set */
...somewhere near the top of Fl_win32.cxx to work around SM_CXPADDEDBORDER not existing on older Win32 variants. We already define a bunch of "missing" WM_whatever messages there anyway to help out older Windows compilers... | |
|
#3 | greentea101 19:28 Mar 03, 2014 |
| I've looked at a bunch of windows in an image editor, and the width of what looks like the padding is actually the sum of the values of the "Border Padding" and "Active Window Border" settings. Unless Aero is being used, in which case it's "Border Padding" + "Active Window Border" - 1. Why? I really couldn't tell you. | |
|
#4 | greentea101 20:16 Mar 03, 2014 |
| I've just made another unsettling discovery. GetSystemMetrics(SM_CXBORDER) always returns 1, and I have no idea how the get the actual value of "Active Window Border". Also, if I change the color of the "Active Window Border", the padding takes on that color as well, as if the two settings are the two halves of the same horrific entity, or something.
Most people don't bother to change "Active Window Border" from the default of 1, but still, this is not very nice. | |
|
#5 | greentea101 12:27 Mar 16, 2014 |
| I am currently using this code:
if (w->size_range_set && (w->maxw != w->minw || w->maxh != w->minh)) { ret = 2; bx = GetSystemMetrics(SM_CXSIZEFRAME); by = GetSystemMetrics(SM_CYSIZEFRAME); } else { ret = 1; int padding = GetSystemMetrics(92); // SM_CXPADDEDBORDER NONCLIENTMETRICS ncm; ncm.cbSize = sizeof(NONCLIENTMETRICS); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0); bx = GetSystemMetrics(SM_CXFIXEDFRAME) + (padding ? padding + ncm.iBorderWidth : 0); by = GetSystemMetrics(SM_CYFIXEDFRAME) + (padding ? padding + ncm.iBorderWidth : 0); }
This finally works for all possible cases. | |
|
#6 | cristiantm 05:51 May 21, 2014 |
| I just would like to add that 1) the fix works for me on Windows 8, Visual Studio 12 (2013) and my standard and custom dialogs; 2) This is becoming more and more important as more and more fltk based projects switch to VS120. Maybe should be added soon to the dev snapshots at least. | |
|
#7 | hectorhon 06:38 Aug 13, 2014 |
| Fix by greentea101 verified working (Visual Studio 2013, Windows 8.1.) (Thank you greentea101!) | |
|
#8 | roukaour 09:05 Aug 29, 2014 |
| I have also been using greentea101's fix on the 1.3.x weekly snapshots, with both VS 2012 + Windows 7 and VS 2013 + Windows 8.1. | |
|
#9 | AlbrechtS 12:47 Sep 18, 2014 |
| Raised priority to 3 (moderate). I would really like to have this in the next release (1.3.3).
To get this a little bit forward I uploaded border_padding.patch with the latest code changes found in this STR and Ian's suggestion to define the constant SM_CXPADDEDBORDER, if not defined.
Please review the patch, test, and confirm that this is what to do. It compiles w/o errors, but I didn't test anything.
Ian, you looked into this issue before, maybe you can tell if it's okay to commit (and if so, do it?). | |
|
#10 | ianmacarthur 13:35 Oct 05, 2014 |
| Albrecht,
I'm keen to get this one in for 1.3.3, and I *believe* the proposed fix is good.
However, I do not have access to a test environment I can really exercise this with (I have no Win7 or Win8 machine I can stick VS on at the moment.) | |
|
#11 | AlbrechtS 16:15 Oct 05, 2014 |
| I agree, and I have Windows 7 and 8 available, but I'm not keen on testing this (changing Windows setup, trying to get VS to do what is expected, and so on). That seems to be a lot of work, and I have many other things I need to do.
Maybe we can just commit the patch and test that it does no harm with a standard setup? I could do that...
And we have a few (4) independent confirmations that the patch works. | |
|
#12 | ianmacarthur 14:10 Oct 07, 2014 |
| For what it is worth, the patch has no discernible effect on my regular mingw builds on Win7, so is not causing any regression I can determine.
On that basis I think it is "harmless" and certainly reports suggest it has positive value for folks using recent MS compiler variants. | |
|
#13 | AlbrechtS 05:01 Oct 08, 2014 |
| Fixed in Subversion repository.
I can't find any visible regressions either. Committed patch with one small modification.
Thanks to greentea101 for the report and patch, and to others for testing and confirming the resolution. | |
[ Return to Bugs & Features ]
|
| |