+Search dialog: wrong maximized wnd placement

Bug reports will be moved here when the described bug has been fixed

Moderators: Hacker, petermad, Stefan2, white

User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

There is a WM_WINDOWPOSCHANGING message, it points to a record with new size and position for the window. They can be overwritten, so finally window will get modified size/position.
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 50541
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

I'm now using the same method as when creating: I do not restrict the window size, and resize it to the correct size after receiving WM_SIZE message. This is ugly with resizing window, but at least it works.
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

What about calling MonitorFromWindow + GetMonitorInfo - this gives rcWork rectangle. After overriding the height, this could be a maximized search window size.

TApplication.MessageBox method uses MonitorFromWindow + GetMonitorInfo internally (at least in Delphi 5 and up) - however not rcWork, but rcMonitor.
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 50541
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

The problem isn't when the window is fully maximized (after starting the search). It only happens when the height is restricted just to the tabbed notebook with the search settings.
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

Ok. But TC can obtain the work area by using GetMonitorInfo, so - as I suppose - TC could prevent search window from overlapping with the taskbar even when Windows tries to do this - for example TC could overwrite window position/size during WM_WINDOWPOSCHANGING message.
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 50541
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

I see - but this would also prevent users from dragging the window to other screens by dragging the title bar...
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

Mhmm, maybe not - MonitorFromWindow called before GetMonitorInfo should give an information about current monitor during dragging the window...
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 50541
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

Can you try with beta 5 now whether you still get a wrong search dialog size?
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

I can't check this this with Windows 7 or Windows 8 now. Maybe somebody else could check this...
gdpr deleted 6
Power Member
Power Member
Posts: 872
Joined: 2013-09-04, 14:07 UTC

Post by *gdpr deleted 6 »

I could not reproduce it with TC8.50b5 x64 in Windows 7 x64 Pro (Aero enabled).

My system has a non-standard dual monitor setup (one display landscape which is secondary output port of the gfx card but primary display in Windows, and one display in portrait mode, with one desktop spanning across both displays.)

Additionally to what was described in this thread, I tried moving/locking the taskbar around in different variations, tried "cheating" by manipulating the coordinates of the search window saved in TC's INI file, etc..., but i could never manage to get the maximized or maximized+docked search window outside the desktop area nor obstructed by a locked taskbar (unless i manually tore off the docked window with the mouse, of course).
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

I just made some tests with Windows 8.1 Preview 32-bit and TC 32-bit:

- I was able to reproduce the problem with TC 8.50 beta 1 (as described in the first post in this thread).
- I was able to reproduce the problem with TC 8.50 beta 4 (after restoring and maximizing search window again).
- I was unable to reproduce the problem with TC 8.50 beta 5.

So the problem seems to be fixed now, although I could see a fully maximized search window for a moment, even without search results.
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 50541
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

Yes, this full screen is unfortunately necessary to avoid the Windows 8 bug (failing to correctly resize to full width without full height).
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

I just made some tests with Windows 8.1 Preview. The code below seems to solve the problem completely, without that full screen hack (not tested with multimonitor system, however should work properly).

Declaration:

Code: Select all

procedure WMWindowPosChanging(var Message: TWMWindowPosChanging); message WM_WINDOWPOSCHANGING;
Implementation:

Code: Select all

procedure TForm1.WMWindowPosChanging(var Message: TWMWindowPosChanging);
var
  Placement: TWindowPlacement;
  MonInfo : TMonitorInfo;
  BorderX : Integer;
  BorderY : Integer;
begin
  BorderX:=-1; {Make compiler happy}
  BorderY:=-1; {Make compiler happy}

  if Win32Platform = VER_PLATFORM_WIN32_NT then
  if HandleAllocated then
  with Message do
  if WindowPos <> nil then
  with WindowPos^ do
  if flags and (SWP_NOMOVE or SWP_NOSIZE) = 0 then
  repeat {until True}
    Placement.length:=SizeOf(TWindowPlacement);
    if not GetWindowPlacement(Handle,@Placement) then
      Break;

    {Check if maximizing now}
    if not ((WindowState <> wsMaximized) and (Placement.showCmd = SW_MAXIMIZE)) then
      Break;

    {Maximized window is a bit larger than the screen size - get the difference}
    if BorderStyle = bsSingle then
    begin
      BorderX:=GetSystemMetrics(SM_CXDLGFRAME);
      BorderY:=GetSystemMetrics(SM_CYDLGFRAME);
    end else
    if BorderStyle = bsSizeable then
    begin
      BorderX:=GetSystemMetrics(SM_CXSIZEFRAME);
      BorderY:=GetSystemMetrics(SM_CYSIZEFRAME);
    end else
      Break;

    MonInfo.cbSize:=SizeOf(MonInfo);
    if not GetMonitorInfo(MonitorFromWindow(Handle,MONITOR_DEFAULTTONEAREST),@MonInfo) then
      Break;

    {Adjust window size to work area}
    with MonInfo.rcWork do
    begin
      if x < Left-BorderX then
      begin
        Dec(cx,Left-BorderX-x);
        Inc(x,Left-BorderX-x);
      end;

      if x+cx > Right+BorderX then
        Dec(cx,x+cx-Right-BorderX);

      if y < Top-BorderY then
      begin
        Dec(cy,Top-BorderY-y);
        Inc(y,Top-BorderY-y);
      end;

      if y+cy > Bottom+BorderY then
        Dec(cy,y+cy-Bottom-BorderY);
    end;
  until True;

  inherited;
end;
Regards
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 50541
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

Thanks for your code - looks good, but I will have to check it on various systems including Linux first to make sure that it doesn't cause any other side effects...
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

I discovered some other problem, where Beta 6 completely fails to place the window properly, and Beta 7 is still not ideal. This problem is somewhere inside Delphi 2 VCL library. The code from my previous post works properly when compiled with Delphi 5, but not properly when compiled with Delphi 2.

Steps to reproduce with Windows 8.1 (final version):
1) place taskbar on the TOP edge of the screen,
2) press Alt+F7 and maximize search window (if it was shown as maximized, restore it and maximize it again),
3) don't close search window - move taskbar to the RIGHT edge of the screen,
4) maximize search window again.

Now we can see that:
- search window in Beta 6 overlaps with the taskbar,
- search window in Beta 7 doesn't overlap anymore, but is placed not at the top of the screen, but rather a bit lower - the difference is equal to the height of the taskbar before moving it to the right.


So the general observation is: for some unknown reason, Delphi 2 remembers work area from the moment of creating a window and passes this remembered work area to the window (during WM_GETMINMAXINFO) for all the window lifetime.


So I modified the code - now it doesn't only trim coordinates, but it totally replaces these coordinates with the actual work area and only after this it trims the height to the maximum allowed value. This code works properly even with Delphi 2.

Note: there is a bug in Delphi 2 compiler - using "repeat .. until True" statement may raise an internal compiler error or even generate invalid code - i.e. invalid jumps in places of "Break" statements (as I checked with a disassembler, one of jumps was totally outside the procedure). So I replaced "until True" with "Break" + "until False".

Code: Select all

procedure TForm1.WMWindowPosChanging(var Message: TWMWindowPosChanging);
var
  Placement: TWindowPlacement;
  MonInfo : TMonitorInfo;
  BorderX : Integer;
  BorderY : Integer;
  Diff : Integer;
begin
  BorderX:=-1; {Make compiler happy}
  BorderY:=-1; {Make compiler happy}

  if Win32Platform = VER_PLATFORM_WIN32_NT then
  if HandleAllocated then
  with Message do
  if WindowPos <> nil then
  with WindowPos^ do
  if flags and (SWP_NOMOVE or SWP_NOSIZE) = 0 then
  repeat {until True}
    Placement.length:=SizeOf(Placement);
    if not GetWindowPlacement(Handle,@Placement) then
      Break;

    {Check if maximizing now}
    if not ((WindowState <> wsMaximized) and (Placement.showCmd = SW_MAXIMIZE)) then
      Break;

    {Maximized window is a bit larger than the screen size - get the difference}
    if BorderStyle = bsSingle then
    begin
      BorderX:=GetSystemMetrics(SM_CXDLGFRAME);
      BorderY:=GetSystemMetrics(SM_CYDLGFRAME);
    end else
    if BorderStyle = bsSizeable then
    begin
      BorderX:=GetSystemMetrics(SM_CXSIZEFRAME);
      BorderY:=GetSystemMetrics(SM_CYSIZEFRAME);
    end else
      Break;

    MonInfo.cbSize:=SizeOf(MonInfo);
    if not GetMonitorInfo(MonitorFromWindow(Handle,MONITOR_DEFAULTTONEAREST),@MonInfo) then
      Break;

    {Replace window size with work area}
    with MonInfo.rcWork do
    begin
      x:=Left-BorderX;
      cx:=Right-Left+2*BorderX;
      y:=Top-BorderY;
      cy:=Bottom-Top+2*BorderY;
    end;

    {Trim window width - center if trimmed}
    if Constraints.MaxWidth > 0 then
    begin
      Diff:=cx-Constraints.MaxWidth;
      if Diff > 0 then
      begin
        Dec(cx,Diff);
        Inc(X,Diff div 2);
      end;
    end;

    {Trim window height - move to top if trimmed}
    if Constraints.MaxHeight > 0 then
    begin
      Diff:=cy-Constraints.MaxHeight;
      if Diff > 0 then
        Dec(cy,Diff);
    end;

    {Warning: there is some problem with Delphi 2 compiler, and using
     "until True" statement may either raise an internal compiler error,
     or generate invalid assembler code. So this statement was replaced
     with "Break" and "until False" statements}
    Break;
  until False;

  inherited;
end;
Regards
Post Reply