23

On a multi-monitor system, a "blank" VCL application maximizes fine, but the same application with styles enabled (and one chosen as default) maximizes incorrectly. What I'm seeing is the right-hand edge of the window extend onto the 2nd monitor (my main is on the left). When I started comparing to other Windows apps, I noticed that under Windows 7 (at least), maximized windows do not even have non-client borders on the left, right or bottom sides. And indeed, the standard VCL (non-styled) app behaves this same way, without non-client borders.

How do I fix this? I notice that TFormStyleHook has a handler for WMNCCalcSize, which I haven't dissected yet, but makes me wonder if VCL might be incorrectly handling this message for a maximized window.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
DaveS_Lifeway
  • 375
  • 3
  • 9
  • 5
    Yet more VCL styles bugs. Please QC this. – David Heffernan Jun 07 '12 at 19:38
  • 1
    QC web address: http://qc.embarcadero.com/wc/qcmain.aspx – Warren P Jun 07 '12 at 19:43
  • Can you reproduce this behavior in a single monitor? I ask because on my current location I don't have another monitor to test this issue. – RRUZ Jun 07 '12 at 20:52
  • Visually, single monitor behavior of styled apps matches non-styled apps, so no problem there. – DaveS_Lifeway Jun 07 '12 at 21:41
  • It's even worse with irregular placed monitors. Have a secondary monitor with a positive top (+16 etc..) and on the right of the primary monitor. Then maximize the form in the primary monitor. You'll lose caption buttons.. – Sertac Akyuz Jun 07 '12 at 22:16
  • 7
    Obligatory "The Old New Thing" link: "Why does a maximized window have the wrong window rectangle?" (http://blogs.msdn.com/b/oldnewthing/archive/2012/03/26/10287385.aspx) describes in its last section why in recent Windows versions there are no borders for maximized apps visible on other monitors. Code doing its own NC area drawing evidently doesn't get this special treatment. – mghie Jun 08 '12 at 03:53
  • Can I check that I understand correctly. You are running ms-windows7, you are writing an application in delphi using vlc. The application is not decorating it self properly in the case of maximized on duel monitor system, decoration is ever spilling to other screen. (should use a different decoration policy for maximized windows). – ctrl-alt-delor Jun 11 '12 at 09:59
  • @mghie There's good info in that article. As someone in those comments mentioned, Photoshop does indeed exhibit this same behavior. What I'm not sure of, is how to address it. I suppose I could take over all drawing of the main app window, but that seems like more headache than I really want. Anyone have any suggestions for possible workarounds? – DaveS_Lifeway Jun 11 '12 at 18:07
  • @DaveS_Lifeway: Have you tried toggling the border style between single and sizeable when the window is maximized / restored? – mghie Jun 11 '12 at 18:44
  • @mghie: I tried this two ways, one in the FormResize event, and the other by intercepting the WM_SYSCOMMAND message. Neither worked perfectly, but both worked "better" (i.e. showed less of the window edge) than nothing at all. Intercepting WM_SYSCOMMAND and setting BorderStyle := bsSingle on SC_MAXIMIZE and BorderStyle := bsSizeable on SC_RESTORE, resulted in the smallest "sliver" on the 2nd monitor, but it was definitely still there. – DaveS_Lifeway Jun 12 '12 at 19:19
  • I've seen this issue too. I tried constraining the MaxWidth of the form based on the active monitor's `WorkareaRect`, but that created other problems worse than the original border problem. If you do find a workaround, please post it. Thanks! – James L. Jun 29 '12 at 00:10

2 Answers2

5

After fiddling some time on this, my take is, this is not a vcl-styles bug at all. This indeed is related with the behavior in the article mentioned in a comment to the question by mghie.

The specific behavior is that, the size of a maximized window is larger than the work area of the monitor that the window is maximized on. Supposedly, the window manager hides the overhang borders. Apparently, it doesn't quite do so with customized frames. Note that MSDN's own custom window frame example seems to suffer from the same problem (refer to the post titled "Bug when window is Maximized " in community content). VCL's application is different than the MSDN example in that it's not based on DWM, but I still think it is the same issue.

The overhang borders have the size of the system sizing border (SM_C[X|Y]SIZEFRAME), but this is irrelevant to the workaround below as it disregards the OS suggested size/position and uses the work area.

Unfortunately I don't think this workaround is usable at all. For one, the mentioned behavior is not documented, for two, the workaround is not perfect; there's still an odd pixel out. If you snap the window exactly on the work area, the window manager decides to offset the window to where it thinks the window (with hidden frames) should be placed. (The VCL could probably be modified to do what the window manager does, and take into account overhang and do not draw them or something similar, but it would be more work and it still would be to workaround undocumented behavior..)

Anyway;

type
  TForm1 = class(TForm)
    ..
  protected
    // overriding styles is not necessary since TFormStyleHook.WMGetMinMaxInfo
    // first calls the default window procedure 
    procedure WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo);
      message WM_GETMINMAXINFO;

..

procedure TForm1.WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo);
var
  R: TRect;
begin
  // always arrives with MinMaxInfo.ptMaxPosition = (-SM_CXFRAME, -SM_CYFRAME)
  // and MinMaxInfo.ptMaxSize = (PrimaryMonitor.Width (?) + 2 * SM_CXFRAME, ... )
  inherited;

  // should test for OS, styles etc. before running the below 
  R := Monitor.WorkareaRect;
  InflateRect(R, -1, -1);             // odd pixel
  OffsetRect(R, -Monitor.Left, -Monitor.Top);
  Message.MinMaxInfo.ptMaxPosition := R.TopLeft;
  Message.MinMaxInfo.ptMaxSize := Point(R.Width, R.Height);
end;
Community
  • 1
  • 1
Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • Raymond specifically says "visual trick" so I suppose we don't resize the window rect, but just clip the overhanging borders? – whosrdaddy Aug 02 '12 at 09:52
  • @whos - Sure, it would be much better (would also get rid of internal frames). I thought we'd need VCLs cooperation for that, but maybe not. – Sertac Akyuz Aug 02 '12 at 09:59
1

The only way i found is to handle WM_SIZE event and modify the window region to chop the extra border.

Dominique
  • 11
  • 2