View Issue Details

IDProjectCategoryView StatusLast Update
0021119LazarusLCLpublic2020-03-21 13:45
ReporterMartin HoareAssigned ToZeljan Rikalo 
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionreopened 
PlatformLinuxOSUbuntuOS Version11.10
Product VersionProduct Build 
Target VersionFixed in Version 
Summary0021119: When a form is started as wsMaximized height and width report design time values
DescriptionWhen a form is started with property windowstate set to wsMaximized, the form starts maximised, but the values of Form.Width and Form.Height reflect the design time value.
Steps To ReproduceCreate an application with a form. Drop a panel on the form. Put its left hand side against the left of the form. Add this code to form event show:

procedure TForm1.FormShow(Sender: TObject);
begin
  Panel1.Width:=Form1.Width-15;
end;

Run the application and the panel will be almost the same width as the form.

Now change the form's WindowState to wsMaximized and run the application again. The form will appear as mazimised, but the panel will be the same size as before.
Additional InformationDoes the same on Windows.
TagsNo tags attached.
Fixed in Revision36106, r61997, r62113
LazTarget-
WidgetsetGTK, GTK 2, Win32/Win64, WinCE, Carbon, Cocoa, QT
Attached Files
  • wsMaximizeTest.zip (2,206 bytes)
  • bug21119.diff (13,545 bytes)
    Index: lcl/interfaces/qt/qtobject.inc
    ===================================================================
    --- lcl/interfaces/qt/qtobject.inc	(revision 46177)
    +++ lcl/interfaces/qt/qtobject.inc	(working copy)
    @@ -148,6 +148,8 @@
     
       if SavedHandlesList <> nil then
       begin
    +    if SavedHandlesList.Count > 0 then
    +      DebugLn('WARNING: SavedHandlesList > 0 ',dbgs(SavedHandlesList.Count),' possible memory leaks.');
         SavedHandlesList.Free;
         SavedHandlesList := nil;
       end;
    Index: lcl/interfaces/qt/qtwsforms.pp
    ===================================================================
    --- lcl/interfaces/qt/qtwsforms.pp	(revision 46177)
    +++ lcl/interfaces/qt/qtwsforms.pp	(working copy)
    @@ -183,6 +183,12 @@
     
       AForm := TCustomForm(AWinControl);
     
    +  if not (csDesigning in AWinControl.ComponentState) then
    +  begin
    +    QtMainWindow.RestoredWidth := AForm.RestoredWSWidth;
    +    QtMainWindow.RestoredHeight := AForm.RestoredWSHeight;
    +  end;
    +
       QtMainWindow.QtFormBorderStyle := Ord(AForm.BorderStyle);
       QtMainWindow.QtFormStyle := Ord(AForm.FormStyle);
     
    Index: lcl/interfaces/qt/qtwidgets.pas
    ===================================================================
    --- lcl/interfaces/qt/qtwidgets.pas	(revision 46177)
    +++ lcl/interfaces/qt/qtwidgets.pas	(working copy)
    @@ -612,6 +612,9 @@
       TQtMainWindow = class(TQtWidget)
       private
         FBlocked: Boolean;
    +    FRestoredHeight: integer;
    +    FRestoredWidth: integer;
    +    FStopResize: boolean;
         LayoutWidget: QBoxLayoutH;
         FCWEventHook: QObject_hookH;
         FShowOnTaskBar: Boolean;
    @@ -664,6 +667,8 @@
         procedure setShowInTaskBar(AValue: Boolean);
         procedure setPopupParent(APopupMode: TPopupMode; NewParent: QWidgetH);
         property Blocked: Boolean read FBlocked write FBlocked;
    +    property RestoredWidth: integer read FRestoredWidth write FRestoredWidth;
    +    property RestoredHeight: integer read FRestoredHeight write FRestoredHeight;
         property ShowOnTaskBar: Boolean read FShowOnTaskBar;
       public
         procedure AttachEvents; override;
    @@ -6358,14 +6363,21 @@
         begin
           if FOwner <> nil then
           begin
    -        {TQtMainWindow does not send resize event if ScrollArea is assigned,
    -         it is done here when viewport geometry is finally updated by Qt.}
    -        ASize := FOwner.getSize;
    -        AResizeEvent := QResizeEvent_create(@ASize, @ASize);
    -        try
    -          SlotResize(AResizeEvent);
    -        finally
    -          QEvent_destroy(AResizeEvent);
    +        if (FOwner is TQtMainWindow) and TQtMainWindow(FOwner).FStopResize then
    +        begin
    +          // issue 21119
    +          // DebugLn('TQtWindowArea.ScrollViewEventFilter: DO NOT UPDATE SIZE !!!! ',dbgs(QResizeEvent_size(QResizeEventH(Event))^));
    +        end else
    +        begin
    +          {TQtMainWindow does not send resize event if ScrollArea is assigned,
    +           it is done here when viewport geometry is finally updated by Qt.}
    +          ASize := FOwner.getSize;
    +          AResizeEvent := QResizeEvent_create(@ASize, @ASize);
    +          try
    +            SlotResize(AResizeEvent);
    +          finally
    +            QEvent_destroy(AResizeEvent);
    +          end;
             end;
           end else
             LCLObject.DoAdjustClientRectChange;
    @@ -6462,6 +6474,9 @@
       {$ifdef VerboseQt}
         WriteLn('TQtMainWindow.CreateWidget Name: ', LCLObject.Name);
       {$endif}
    +  FRestoredWidth := -1;
    +  FRestoredHeight := -1;
    +  FStopResize := False;
       FBlocked := False;
       FShowOnTaskBar := False;
       QtFormBorderStyle := Ord(bsSizeable);
    @@ -6818,6 +6833,7 @@
       AState: QtWindowStates;
       AOldState: QtWindowStates;
       CanSendEvent: Boolean;
    +  ASize: TSize;
       {$IFDEF MSWINDOWS}
       i: Integer;
       AForm: TCustomForm;
    @@ -6852,6 +6868,7 @@
       {$ENDIF}
     
       BeginEventProcessing;
    +  try
       case QEvent_type(Event) of
         QEventMouseButtonPress,
         QEventMouseButtonRelease,
    @@ -6878,7 +6895,7 @@
           begin
             //do not process QEventWindowStateChange for MDI children !
             //we are doing that job in MDIChildWindowStateChanged slot.
    -        EndEventProcessing;
    +        // EndEventProcessing;
             exit;
           end;
     
    @@ -6978,9 +6995,44 @@
               // do not trigger LCL
             else
             {$ENDIF}
    +
             SlotWindowStateChange;
    +
    +        // issue #21119
    +        if not (csDesigning in LCLObject.ComponentState) and
    +          ((AOldState and QtWindowMaximized <> 0) or
    +          (AOldState and QtWindowFullScreen <> 0)) and
    +          (AState and QtWindowMinimized = 0) and
    +          (AState and QtWindowMaximized = 0) and
    +          (AState and QtWindowFullScreen = 0) and
    +          not IsMdiChild and
    +          (RestoredWidth > 0) and (RestoredHeight > 0) and not FStopResize then
    +        begin
    +          // send resize via delayresize event !
    +          FStopResize := True;
    +          ASize.cx := RestoredWidth;
    +          ASize.cy := RestoredHeight;
    +          DelayResizeEvent(Widget, ASize);
    +        end;
           end;
         end;
    +
    +
    +    LCLQt_DelayResizeEvent:
    +    begin
    +      Result := True;
    +      if FStopResize then
    +      begin
    +        // issue #21119
    +        FStopResize := False;
    +        // writeln('STARTING RESIZING FROM QEventWindowStateChange ');
    +        Resize(RestoredWidth, RestoredHeight);
    +        FRestoredWidth := -1;
    +        FRestoredHeight := -1;
    +        // writeln('STOP RESIZING FROM QEventWindowStateChange ');
    +      end;
    +    end;
    +
         QEventDrop,
         QEventDragMove,
         QEventDragEnter:
    @@ -6991,6 +7043,8 @@
         end;
         QEventResize:
         begin
    +      if FStopResize then
    +        exit(False);
           {$IFDEF QTSCROLLABLEFORMS}
           if not Assigned(ScrollArea) then
           {$ENDIF}
    @@ -7007,7 +7061,9 @@
       else
         Result := inherited EventFilter(Sender, Event);
       end;
    +  finally
       EndEventProcessing;
    +  end;
     end;
     
     procedure TQtMainWindow.MDIChildWindowStateChanged(AOldState: QtWindowStates;
    Index: lcl/interfaces/gtk2/gtk2winapi.inc
    ===================================================================
    --- lcl/interfaces/gtk2/gtk2winapi.inc	(revision 46177)
    +++ lcl/interfaces/gtk2/gtk2winapi.inc	(working copy)
    @@ -9371,6 +9371,9 @@
       GtkWindow: PGtkWindow;
       B: Boolean;
       Widget: PGtkWidget;
    +  AState: TGdkEventWindowState;
    +  WInfo: PWidgetInfo;
    +  TheForm: TCustomForm;
     begin
       Result := False;
     
    @@ -9419,6 +9422,21 @@
             gtk_window_deiconify(GtkWindow);
             gtk_window_unmaximize(GtkWindow);
             gtk_window_unfullscreen(GtkWindow);
    +        FillChar(AState, SizeOf(AState), 0);
    +        AState.new_window_state := GDK_WINDOW_STATE_WITHDRAWN;
    +        AState.window := gtk_widget_get_parent_window(PGtkWidget(GtkWindow));
    +
    +        WInfo := GetWidgetInfo(GtkWindow);
    +        TheForm := TCustomForm(WInfo^.LCLObject);
    +        if (WInfo^.CurrentWindowState in [Ord(wsMaximized), Ord(wsFullScreen)]) and
    +          (WInfo^.RestoreFormWidth > 0) and (WInfo^.RestoreFormHeight > 0) then
    +        begin
    +          WInfo^.CurrentWindowState := Ord(wsNormal);
    +          TheForm.SetBounds(TheForm.Left,
    +            TheForm.Top, WInfo^.RestoreFormWidth, WInfo^.RestoreFormHeight);
    +          WInfo^.RestoreFormWidth := -1;
    +          WInfo^.RestoreFormHeight := -1;
    +        end;
           end;
         end;
     
    Index: lcl/interfaces/gtk2/gtk2callback.inc
    ===================================================================
    --- lcl/interfaces/gtk2/gtk2callback.inc	(revision 46177)
    +++ lcl/interfaces/gtk2/gtk2callback.inc	(working copy)
    @@ -1171,6 +1171,7 @@
       SizeMsg: TLMSize;
       GtkWidth: LongInt;
       GtkHeight: LongInt;
    +  WInfo: PWidgetInfo;
       {$IFDEF HasX}
       NetAtom: TGdkAtom;
       AtomType: TGdkAtom;
    @@ -1267,6 +1268,21 @@
               ]);
             {$ENDIF}
             DeliverMessage(TheForm, SizeMsg);
    +        WInfo := GetWidgetInfo(PGtkWidget(TheForm.Handle));
    +        // writeln('SIZETYPE = ',SizeMsg.SizeType xor Size_SourceIsInterface,' WinState=',WInfo^.CurrentWindowState,
    +        // ' RestoreW=',WInfo^.RestoreFormWidth,' RestoreH=',WInfo^.RestoreFormHeight);
    +        if (WInfo^.CurrentWindowState in [Ord(wsMaximized), Ord(wsFullScreen)]) and
    +          (SizeMsg.SizeType xor Size_SourceIsInterface = SIZE_RESTORED) and
    +          (WInfo^.RestoreFormWidth > 0) and (WInfo^.RestoreFormHeight > 0) then
    +        begin
    +          // writeln('SETTING BOUNDS TO RESTORED SIZES !');
    +          WInfo^.CurrentWindowState := Ord(wsNormal);
    +          TheForm.SetBounds(TheForm.Left,
    +            TheForm.Top, WInfo^.RestoreFormWidth, WInfo^.RestoreFormHeight);
    +          WInfo^.RestoreFormWidth := -1;
    +          WInfo^.RestoreFormHeight := -1;
    +        end;
    +
             if (gtk_major_version = 2) and (gtk_minor_version <= 8) and
               (TheForm.WindowState = wsMaximized) then
                 gtk_widget_queue_draw({%H-}PGtkWidget(TheForm.Handle));
    Index: lcl/interfaces/gtk2/gtk2wsforms.pp
    ===================================================================
    --- lcl/interfaces/gtk2/gtk2wsforms.pp	(revision 46177)
    +++ lcl/interfaces/gtk2/gtk2wsforms.pp	(working copy)
    @@ -418,7 +418,15 @@
     
       WidgetInfo := CreateWidgetInfo(P, AWinControl, AParams);
       WidgetInfo^.FormBorderStyle := Ord(ABorderStyle);
    +  WidgetInfo^.CurrentWindowState := Ord(TCustomForm(AWinControl).WindowState);
     
    +  if not (csDesigning in AWinControl.ComponentState) then
    +  begin
    +    WidgetInfo^.RestoreFormWidth := TCustomForm(AWinControl).RestoredWSWidth;
    +    WidgetInfo^.RestoreFormHeight := TCustomForm(AWinControl).RestoredWSHeight;
    +  end;
    +
    +
       FillChar(WidgetInfo^.FormWindowState, SizeOf(WidgetInfo^.FormWindowState), #0);
       WidgetInfo^.FormWindowState.new_window_state := GDK_WINDOW_STATE_WITHDRAWN;
     
    Index: lcl/interfaces/gtk2/gtk2def.pp
    ===================================================================
    --- lcl/interfaces/gtk2/gtk2def.pp	(revision 46177)
    +++ lcl/interfaces/gtk2/gtk2def.pp	(working copy)
    @@ -487,6 +487,9 @@
         UserData: Pointer;
         FormBorderStyle: Integer;         // used only by forms
         FormWindowState: TGdkEventWindowState; // used only by forms to stop infinite loops eg. issue #16505
    +    CurrentWindowState: byte; {TWindowState, issue 21119}
    +    RestoreFormWidth: Integer; // used only by forms, issue 21119
    +    RestoreFormHeight: Integer; // used only by forms, issue 21119
       end;
     
       //TODO: remove
    Index: lcl/forms.pp
    ===================================================================
    --- lcl/forms.pp	(revision 46177)
    +++ lcl/forms.pp	(working copy)
    @@ -421,6 +421,8 @@
         FOnShowModalFinished: TModalDialogFinished;
         FPopupMode: TPopupMode;
         FPopupParent: TCustomForm;
    +    FRestoredWSHeight: integer;
    +    FRestoredWSWidth: integer;
         FSmallIconHandle: HICON;
         FBigIconHandle: HICON;
         FKeyPreview: Boolean;
    @@ -689,6 +691,8 @@
         property RestoredTop: integer read GetRestoredTop;
         property RestoredWidth: integer read FRestoredWidth;
         property RestoredHeight: integer read FRestoredHeight;
    +    property RestoredWSWidth: integer read FRestoredWSWidth;
    +    property RestoredWSHeight: integer read FRestoredWSHeight;
         property ShowInTaskBar: TShowInTaskbar read FShowInTaskbar write SetShowInTaskBar
                                         default stDefault;
         property Visible stored VisibleIsStored default false;
    Index: lcl/include/customform.inc
    ===================================================================
    --- lcl/include/customform.inc	(revision 46177)
    +++ lcl/include/customform.inc	(working copy)
    @@ -121,10 +121,14 @@
           if NewHeight<=0 then
             NewHeight := Screen.WorkAreaHeight;
     
    -      if NewWidth>0 then
    -        Width := NewWidth;
    -      if NewHeight>0 then
    -        Height := NewHeight;
    +      if NewWidth <= 0 then
    +        NewWidth := Width;
    +      if NewHeight <= 0 then
    +        NewHeight := Height;
    +
    +      FRestoredWSWidth := Width;
    +      FRestoredWSHeight := Height;
    +      SetBounds(Left, Top, NewWidth, NewHeight);
         end;
     
         if (WindowState = wsFullScreen) and (FormStyle <> fsMDIChild) then
    @@ -135,27 +139,32 @@
             NewWidth := Min(Constraints.MaxWidth, NewWidth);
           if Constraints.MaxHeight > 0 then
             NewHeight := Min(Constraints.MaxHeight, NewHeight);
    -      Width := NewWidth;
    -      Height := NewHeight;
    +
    +      FRestoredWSWidth := Width;
    +      FRestoredWSHeight := Height;
    +      SetBounds(Left, Top, NewWidth, NewHeight);
         end;
       end;
     begin
    +  FRestoredWSWidth := -1;
    +  FRestoredWSHeight := -1;
    +
    +  DoCreate;
    +
       // issue #21119, prepare maximized or fullscreen form to accurate dimensions.
       // we avoid flickering also in this case.
    -  if not (csDesigning in ComponentState) then
    +  if not (csDesigning in ComponentState) and not HandleAllocated then
         ChangeFormDimensions(True);
    -
    -  OldWindowState := WindowState;
    -  DoCreate;
    -
    +  (*
       // if we change WindowState in constructor and handle isn't allocated
       // then change our dimensions to accurate one
    +
       if not (csDesigning in ComponentState) and not HandleAllocated and
         (OldWindowState <> WindowState) and
         not (OldWindowState in [wsMaximized, wsFullScreen]) and
         (WindowState in [wsMaximized, wsFullScreen]) then
           ChangeFormDimensions(False);
    -
    +  *)
       EndFormUpdate; // the BeginFormUpdate is in CreateNew
       inherited AfterConstruction;
     end;
    @@ -624,6 +633,7 @@
     
     procedure TCustomForm.CMShowingChanged(var Message: TLMessage);
     begin
    +  inherited CMShowingChanged(Message);
       try
         if Showing then
           DoShow
    @@ -633,7 +643,6 @@
         if not HandleShowHideException then
           raise;
       end;
    -  inherited CMShowingChanged(Message);
     end;
     
     procedure TCustomForm.DoShowWindow;
    
    bug21119.diff (13,545 bytes)

Relationships

related to 0022771 resolvedJuha Manninen When FormStyle = wsMaximized, after restore Widht/Height have wrong values 
related to 0008576 closedJuha Manninen After Mini/Maximizing window 'RestoredLeft/Top' values changes to "unreal" values 
related to 0021724 closedPaul Ishenin Minimizing and restoring maximized form changes size and position of aligned controls 
related to 0027375 resolvedJuha Manninen If a Form is started with wsMaximized (set in OI), it does not restore to designed Size 
related to 0036127 resolvedJuha Manninen [Patch] TForm's bounds and restored bounds are inconsistent 

Activities

Bart Broersma

2012-01-19 15:33

developer   ~0055848

Which widgetset?

Bart Broersma

2012-01-19 15:52

developer   ~0055852

Same happens on Win32 (Lazarus 0.9.31 r34638 FPC 2.6.0 i386-win32-win32/win64)

Reported width/heigth in
OnCreate: Width = 320 Heigth = 240
OnShow: Width = 320 Heigth = 240
OnActivate: Width = 320 Heigth = 240

Now after the form is shown on the desktop:
BtnClick: Width = 1280 Heigth = 1005


Compared to Delphi (3)
OnCreate: Width = 814 Heigth = 529
OnShow: Width = 1288 Heigth = 1032
OnActivate: Width = 1288 Heigth = 1032
BtnClick: Width = 1288 Heigth = 1032

Martin Hoare

2012-01-25 11:07

reporter   ~0056026

I have added a button to reproduce your test.

The initial call of FormShow on startup gives the wrong values.

When I click the button and call FormShow from OnClick I get the correct values.

When I added a timer which fired once one second in I got the wrong values. Something must be happening after the first call of FormShow and the later button click.

Zeljan Rikalo

2012-03-16 11:31

developer   ~0057708

Would be nice if you attach an example with all possibilites, so I can look into.

2012-03-16 22:33

 

wsMaximizeTest.zip (2,206 bytes)

Bart Broersma

2012-03-16 22:35

developer   ~0057743

Sample program attached.

Output on Windows 7 (64-bit OS, 32-bit Lazarus/Fpc)
Lazarus 0.9.31 r35332 FPC 2.6.0 i386-win32-win32/win64

OnCreate: Width = 320
OnCreate: Height = 240
OnShow: Width = 320
OnShow: Height = 240
OnActivate: Width = 320
OnActivate: Height = 240
AfterActivate: Width = 1366
AfterActivate: Height = 746

Zeljan Rikalo

2012-03-17 08:36

developer   ~0057748

this is Qt on X11:
OnCreate: Width = 320
OnCreate: Height = 240

OnShow: Width = 320
OnShow: Height = 240
OnActivate: Width = 320
OnActivate: Height = 240
AfterActivate: Width = 1280
AfterActivate: Height = 974

and this is Gtk2 on X11

OnCreate: Width = 320
OnCreate: Height = 240
OnShow: Width = 320
OnShow: Height = 240
OnActivate: Width = 320
OnActivate: Height = 240
AfterActivate: Width = 1280
AfterActivate: Height = 974

Zeljan Rikalo

2012-03-17 08:38

developer   ~0057749

Changed category to LCL ,also all widgetsets are affected.

Zeljan Rikalo

2012-03-17 11:49

developer   ~0057755

Please test and close if ok.
IMPORTANT NOTE: this is 100% accurate only under windows (and probably under carbon/cocoa).By that i mean when form is wsMaximized in lfm.
Under X11 it cannot be 100% accurate due to X11 decorations and the way how it works when main form is wsMaximized, since at that time there's no information from wm what size of title bar and frame border could be.
Now I see that MAYBE in OnCreate event one can set wsMaximized, so I'll extend patch for that part.

Zeljan Rikalo

2012-03-17 12:02

developer   ~0057756

Also added ability to change windowstate to wsMaximized or wsFullScreen in OnCreate, so after that in OnShow you'll get accurate size (r36107).
Note that such scenario will work only in case when handle isn't allocated in post OnCreate.

goldenfox

2012-04-03 06:19

reporter   ~0058270

I would like to point out that when you hit the restore button it will not restore to design time size but to a fullscreen size. It should return to design time size when you click restore button.

Bart Broersma

2012-04-04 18:37

developer   ~0058293

Results are inconsistent with Delphi:

OnCreate: Width = 1366
OnCreate: Height = 746
OnShow: Width = 1366
OnShow: Height = 746
OnActivate: Width = 1366
OnActivate: Height = 746
AfterActivate: Width = 1366
AfterActivate: Height = 746

In OnCreate the sizes should be design time values.
Possibly as a result of this, restore won't resize the window to design time value, but only move it to designtime left,top.

Zeljan Rikalo

2012-04-04 20:57

developer   ~0058299

It's easy to be consistent with Delphi, but if you set wsMaximized in lfm it shuold be maximized in all events IMO.
That code probably should be moved before WSShowHide is called , so then it will be maximized at correct point. In that case OnCreate will contain design time values....I'll see what to do.

Zeljan Rikalo

2012-04-05 07:38

developer   ~0058306

Yes, restore does not work under X11 as expected. Can anybody test win32 ?

Zeljan Rikalo

2012-04-05 09:11

developer   ~0058308

Targeted to 1.0 ... have solution for X11 widgetsets, must test others first.

Zeljan Rikalo

2012-04-05 09:12

developer   ~0058309

X11 is pretty tricky here but I've found solution which will be commited as soon as I test win32 and carbon.

goldenfox

2012-04-05 15:51

reporter   ~0058324

Windows 7 Ultimate
SVN 36568

Form size won't restore to the design time values after hitting restore button.

Bart Broersma

2012-08-30 21:47

developer   ~0061989

Last edited: 2012-09-01 23:07

It seems only Top/Lefts is restored to desintime values.
Lazarus 1.1 r38343 FPC 2.6.0 i386-win32-win32/win64 on Win7

[Edit] There is a seperate bugreport on this issue: 0022771

Zeljan Rikalo

2014-09-11 14:37

developer  

bug21119.diff (13,545 bytes)
Index: lcl/interfaces/qt/qtobject.inc
===================================================================
--- lcl/interfaces/qt/qtobject.inc	(revision 46177)
+++ lcl/interfaces/qt/qtobject.inc	(working copy)
@@ -148,6 +148,8 @@
 
   if SavedHandlesList <> nil then
   begin
+    if SavedHandlesList.Count > 0 then
+      DebugLn('WARNING: SavedHandlesList > 0 ',dbgs(SavedHandlesList.Count),' possible memory leaks.');
     SavedHandlesList.Free;
     SavedHandlesList := nil;
   end;
Index: lcl/interfaces/qt/qtwsforms.pp
===================================================================
--- lcl/interfaces/qt/qtwsforms.pp	(revision 46177)
+++ lcl/interfaces/qt/qtwsforms.pp	(working copy)
@@ -183,6 +183,12 @@
 
   AForm := TCustomForm(AWinControl);
 
+  if not (csDesigning in AWinControl.ComponentState) then
+  begin
+    QtMainWindow.RestoredWidth := AForm.RestoredWSWidth;
+    QtMainWindow.RestoredHeight := AForm.RestoredWSHeight;
+  end;
+
   QtMainWindow.QtFormBorderStyle := Ord(AForm.BorderStyle);
   QtMainWindow.QtFormStyle := Ord(AForm.FormStyle);
 
Index: lcl/interfaces/qt/qtwidgets.pas
===================================================================
--- lcl/interfaces/qt/qtwidgets.pas	(revision 46177)
+++ lcl/interfaces/qt/qtwidgets.pas	(working copy)
@@ -612,6 +612,9 @@
   TQtMainWindow = class(TQtWidget)
   private
     FBlocked: Boolean;
+    FRestoredHeight: integer;
+    FRestoredWidth: integer;
+    FStopResize: boolean;
     LayoutWidget: QBoxLayoutH;
     FCWEventHook: QObject_hookH;
     FShowOnTaskBar: Boolean;
@@ -664,6 +667,8 @@
     procedure setShowInTaskBar(AValue: Boolean);
     procedure setPopupParent(APopupMode: TPopupMode; NewParent: QWidgetH);
     property Blocked: Boolean read FBlocked write FBlocked;
+    property RestoredWidth: integer read FRestoredWidth write FRestoredWidth;
+    property RestoredHeight: integer read FRestoredHeight write FRestoredHeight;
     property ShowOnTaskBar: Boolean read FShowOnTaskBar;
   public
     procedure AttachEvents; override;
@@ -6358,14 +6363,21 @@
     begin
       if FOwner <> nil then
       begin
-        {TQtMainWindow does not send resize event if ScrollArea is assigned,
-         it is done here when viewport geometry is finally updated by Qt.}
-        ASize := FOwner.getSize;
-        AResizeEvent := QResizeEvent_create(@ASize, @ASize);
-        try
-          SlotResize(AResizeEvent);
-        finally
-          QEvent_destroy(AResizeEvent);
+        if (FOwner is TQtMainWindow) and TQtMainWindow(FOwner).FStopResize then
+        begin
+          // issue 21119
+          // DebugLn('TQtWindowArea.ScrollViewEventFilter: DO NOT UPDATE SIZE !!!! ',dbgs(QResizeEvent_size(QResizeEventH(Event))^));
+        end else
+        begin
+          {TQtMainWindow does not send resize event if ScrollArea is assigned,
+           it is done here when viewport geometry is finally updated by Qt.}
+          ASize := FOwner.getSize;
+          AResizeEvent := QResizeEvent_create(@ASize, @ASize);
+          try
+            SlotResize(AResizeEvent);
+          finally
+            QEvent_destroy(AResizeEvent);
+          end;
         end;
       end else
         LCLObject.DoAdjustClientRectChange;
@@ -6462,6 +6474,9 @@
   {$ifdef VerboseQt}
     WriteLn('TQtMainWindow.CreateWidget Name: ', LCLObject.Name);
   {$endif}
+  FRestoredWidth := -1;
+  FRestoredHeight := -1;
+  FStopResize := False;
   FBlocked := False;
   FShowOnTaskBar := False;
   QtFormBorderStyle := Ord(bsSizeable);
@@ -6818,6 +6833,7 @@
   AState: QtWindowStates;
   AOldState: QtWindowStates;
   CanSendEvent: Boolean;
+  ASize: TSize;
   {$IFDEF MSWINDOWS}
   i: Integer;
   AForm: TCustomForm;
@@ -6852,6 +6868,7 @@
   {$ENDIF}
 
   BeginEventProcessing;
+  try
   case QEvent_type(Event) of
     QEventMouseButtonPress,
     QEventMouseButtonRelease,
@@ -6878,7 +6895,7 @@
       begin
         //do not process QEventWindowStateChange for MDI children !
         //we are doing that job in MDIChildWindowStateChanged slot.
-        EndEventProcessing;
+        // EndEventProcessing;
         exit;
       end;
 
@@ -6978,9 +6995,44 @@
           // do not trigger LCL
         else
         {$ENDIF}
+
         SlotWindowStateChange;
+
+        // issue #21119
+        if not (csDesigning in LCLObject.ComponentState) and
+          ((AOldState and QtWindowMaximized <> 0) or
+          (AOldState and QtWindowFullScreen <> 0)) and
+          (AState and QtWindowMinimized = 0) and
+          (AState and QtWindowMaximized = 0) and
+          (AState and QtWindowFullScreen = 0) and
+          not IsMdiChild and
+          (RestoredWidth > 0) and (RestoredHeight > 0) and not FStopResize then
+        begin
+          // send resize via delayresize event !
+          FStopResize := True;
+          ASize.cx := RestoredWidth;
+          ASize.cy := RestoredHeight;
+          DelayResizeEvent(Widget, ASize);
+        end;
       end;
     end;
+
+
+    LCLQt_DelayResizeEvent:
+    begin
+      Result := True;
+      if FStopResize then
+      begin
+        // issue #21119
+        FStopResize := False;
+        // writeln('STARTING RESIZING FROM QEventWindowStateChange ');
+        Resize(RestoredWidth, RestoredHeight);
+        FRestoredWidth := -1;
+        FRestoredHeight := -1;
+        // writeln('STOP RESIZING FROM QEventWindowStateChange ');
+      end;
+    end;
+
     QEventDrop,
     QEventDragMove,
     QEventDragEnter:
@@ -6991,6 +7043,8 @@
     end;
     QEventResize:
     begin
+      if FStopResize then
+        exit(False);
       {$IFDEF QTSCROLLABLEFORMS}
       if not Assigned(ScrollArea) then
       {$ENDIF}
@@ -7007,7 +7061,9 @@
   else
     Result := inherited EventFilter(Sender, Event);
   end;
+  finally
   EndEventProcessing;
+  end;
 end;
 
 procedure TQtMainWindow.MDIChildWindowStateChanged(AOldState: QtWindowStates;
Index: lcl/interfaces/gtk2/gtk2winapi.inc
===================================================================
--- lcl/interfaces/gtk2/gtk2winapi.inc	(revision 46177)
+++ lcl/interfaces/gtk2/gtk2winapi.inc	(working copy)
@@ -9371,6 +9371,9 @@
   GtkWindow: PGtkWindow;
   B: Boolean;
   Widget: PGtkWidget;
+  AState: TGdkEventWindowState;
+  WInfo: PWidgetInfo;
+  TheForm: TCustomForm;
 begin
   Result := False;
 
@@ -9419,6 +9422,21 @@
         gtk_window_deiconify(GtkWindow);
         gtk_window_unmaximize(GtkWindow);
         gtk_window_unfullscreen(GtkWindow);
+        FillChar(AState, SizeOf(AState), 0);
+        AState.new_window_state := GDK_WINDOW_STATE_WITHDRAWN;
+        AState.window := gtk_widget_get_parent_window(PGtkWidget(GtkWindow));
+
+        WInfo := GetWidgetInfo(GtkWindow);
+        TheForm := TCustomForm(WInfo^.LCLObject);
+        if (WInfo^.CurrentWindowState in [Ord(wsMaximized), Ord(wsFullScreen)]) and
+          (WInfo^.RestoreFormWidth > 0) and (WInfo^.RestoreFormHeight > 0) then
+        begin
+          WInfo^.CurrentWindowState := Ord(wsNormal);
+          TheForm.SetBounds(TheForm.Left,
+            TheForm.Top, WInfo^.RestoreFormWidth, WInfo^.RestoreFormHeight);
+          WInfo^.RestoreFormWidth := -1;
+          WInfo^.RestoreFormHeight := -1;
+        end;
       end;
     end;
 
Index: lcl/interfaces/gtk2/gtk2callback.inc
===================================================================
--- lcl/interfaces/gtk2/gtk2callback.inc	(revision 46177)
+++ lcl/interfaces/gtk2/gtk2callback.inc	(working copy)
@@ -1171,6 +1171,7 @@
   SizeMsg: TLMSize;
   GtkWidth: LongInt;
   GtkHeight: LongInt;
+  WInfo: PWidgetInfo;
   {$IFDEF HasX}
   NetAtom: TGdkAtom;
   AtomType: TGdkAtom;
@@ -1267,6 +1268,21 @@
           ]);
         {$ENDIF}
         DeliverMessage(TheForm, SizeMsg);
+        WInfo := GetWidgetInfo(PGtkWidget(TheForm.Handle));
+        // writeln('SIZETYPE = ',SizeMsg.SizeType xor Size_SourceIsInterface,' WinState=',WInfo^.CurrentWindowState,
+        // ' RestoreW=',WInfo^.RestoreFormWidth,' RestoreH=',WInfo^.RestoreFormHeight);
+        if (WInfo^.CurrentWindowState in [Ord(wsMaximized), Ord(wsFullScreen)]) and
+          (SizeMsg.SizeType xor Size_SourceIsInterface = SIZE_RESTORED) and
+          (WInfo^.RestoreFormWidth > 0) and (WInfo^.RestoreFormHeight > 0) then
+        begin
+          // writeln('SETTING BOUNDS TO RESTORED SIZES !');
+          WInfo^.CurrentWindowState := Ord(wsNormal);
+          TheForm.SetBounds(TheForm.Left,
+            TheForm.Top, WInfo^.RestoreFormWidth, WInfo^.RestoreFormHeight);
+          WInfo^.RestoreFormWidth := -1;
+          WInfo^.RestoreFormHeight := -1;
+        end;
+
         if (gtk_major_version = 2) and (gtk_minor_version <= 8) and
           (TheForm.WindowState = wsMaximized) then
             gtk_widget_queue_draw({%H-}PGtkWidget(TheForm.Handle));
Index: lcl/interfaces/gtk2/gtk2wsforms.pp
===================================================================
--- lcl/interfaces/gtk2/gtk2wsforms.pp	(revision 46177)
+++ lcl/interfaces/gtk2/gtk2wsforms.pp	(working copy)
@@ -418,7 +418,15 @@
 
   WidgetInfo := CreateWidgetInfo(P, AWinControl, AParams);
   WidgetInfo^.FormBorderStyle := Ord(ABorderStyle);
+  WidgetInfo^.CurrentWindowState := Ord(TCustomForm(AWinControl).WindowState);
 
+  if not (csDesigning in AWinControl.ComponentState) then
+  begin
+    WidgetInfo^.RestoreFormWidth := TCustomForm(AWinControl).RestoredWSWidth;
+    WidgetInfo^.RestoreFormHeight := TCustomForm(AWinControl).RestoredWSHeight;
+  end;
+
+
   FillChar(WidgetInfo^.FormWindowState, SizeOf(WidgetInfo^.FormWindowState), #0);
   WidgetInfo^.FormWindowState.new_window_state := GDK_WINDOW_STATE_WITHDRAWN;
 
Index: lcl/interfaces/gtk2/gtk2def.pp
===================================================================
--- lcl/interfaces/gtk2/gtk2def.pp	(revision 46177)
+++ lcl/interfaces/gtk2/gtk2def.pp	(working copy)
@@ -487,6 +487,9 @@
     UserData: Pointer;
     FormBorderStyle: Integer;         // used only by forms
     FormWindowState: TGdkEventWindowState; // used only by forms to stop infinite loops eg. issue #16505
+    CurrentWindowState: byte; {TWindowState, issue 21119}
+    RestoreFormWidth: Integer; // used only by forms, issue 21119
+    RestoreFormHeight: Integer; // used only by forms, issue 21119
   end;
 
   //TODO: remove
Index: lcl/forms.pp
===================================================================
--- lcl/forms.pp	(revision 46177)
+++ lcl/forms.pp	(working copy)
@@ -421,6 +421,8 @@
     FOnShowModalFinished: TModalDialogFinished;
     FPopupMode: TPopupMode;
     FPopupParent: TCustomForm;
+    FRestoredWSHeight: integer;
+    FRestoredWSWidth: integer;
     FSmallIconHandle: HICON;
     FBigIconHandle: HICON;
     FKeyPreview: Boolean;
@@ -689,6 +691,8 @@
     property RestoredTop: integer read GetRestoredTop;
     property RestoredWidth: integer read FRestoredWidth;
     property RestoredHeight: integer read FRestoredHeight;
+    property RestoredWSWidth: integer read FRestoredWSWidth;
+    property RestoredWSHeight: integer read FRestoredWSHeight;
     property ShowInTaskBar: TShowInTaskbar read FShowInTaskbar write SetShowInTaskBar
                                     default stDefault;
     property Visible stored VisibleIsStored default false;
Index: lcl/include/customform.inc
===================================================================
--- lcl/include/customform.inc	(revision 46177)
+++ lcl/include/customform.inc	(working copy)
@@ -121,10 +121,14 @@
       if NewHeight<=0 then
         NewHeight := Screen.WorkAreaHeight;
 
-      if NewWidth>0 then
-        Width := NewWidth;
-      if NewHeight>0 then
-        Height := NewHeight;
+      if NewWidth <= 0 then
+        NewWidth := Width;
+      if NewHeight <= 0 then
+        NewHeight := Height;
+
+      FRestoredWSWidth := Width;
+      FRestoredWSHeight := Height;
+      SetBounds(Left, Top, NewWidth, NewHeight);
     end;
 
     if (WindowState = wsFullScreen) and (FormStyle <> fsMDIChild) then
@@ -135,27 +139,32 @@
         NewWidth := Min(Constraints.MaxWidth, NewWidth);
       if Constraints.MaxHeight > 0 then
         NewHeight := Min(Constraints.MaxHeight, NewHeight);
-      Width := NewWidth;
-      Height := NewHeight;
+
+      FRestoredWSWidth := Width;
+      FRestoredWSHeight := Height;
+      SetBounds(Left, Top, NewWidth, NewHeight);
     end;
   end;
 begin
+  FRestoredWSWidth := -1;
+  FRestoredWSHeight := -1;
+
+  DoCreate;
+
   // issue #21119, prepare maximized or fullscreen form to accurate dimensions.
   // we avoid flickering also in this case.
-  if not (csDesigning in ComponentState) then
+  if not (csDesigning in ComponentState) and not HandleAllocated then
     ChangeFormDimensions(True);
-
-  OldWindowState := WindowState;
-  DoCreate;
-
+  (*
   // if we change WindowState in constructor and handle isn't allocated
   // then change our dimensions to accurate one
+
   if not (csDesigning in ComponentState) and not HandleAllocated and
     (OldWindowState <> WindowState) and
     not (OldWindowState in [wsMaximized, wsFullScreen]) and
     (WindowState in [wsMaximized, wsFullScreen]) then
       ChangeFormDimensions(False);
-
+  *)
   EndFormUpdate; // the BeginFormUpdate is in CreateNew
   inherited AfterConstruction;
 end;
@@ -624,6 +633,7 @@
 
 procedure TCustomForm.CMShowingChanged(var Message: TLMessage);
 begin
+  inherited CMShowingChanged(Message);
   try
     if Showing then
       DoShow
@@ -633,7 +643,6 @@
     if not HandleShowHideException then
       raise;
   end;
-  inherited CMShowingChanged(Message);
 end;
 
 procedure TCustomForm.DoShowWindow;
bug21119.diff (13,545 bytes)

Zeljan Rikalo

2014-09-11 14:39

developer   ~0077084

I've attached possible way of fixing this bug and 0022771.
Works ok with Qt, but with Gtk2 it sends few resize events (gtk2 fix isn't finished yet). Now, if someone have enough spare time to try to implement it in same way in win32 and give feedback would be a huge step in fixing this.

Mike Thompson

2014-09-16 12:27

developer   ~0077302

Last edited: 2014-09-16 12:28

View 2 revisions

I suspect this issue could be related to 8576 (http://bugs.freepascal.org/view.php?id=8576 - or rather the other way around 8576 is related to this)

Edson Lidorio

2015-12-22 03:09

reporter   ~0088158

This problem still persists.

Juha Manninen

2020-03-16 19:24

developer   ~0121625

Fixed together with related issue 0036127.

Issue History

Date Modified Username Field Change
2012-01-19 15:03 Martin Hoare New Issue
2012-01-19 15:05 Marco van de Voort Project FPC => Lazarus
2012-01-19 15:33 Bart Broersma LazTarget => -
2012-01-19 15:33 Bart Broersma Note Added: 0055848
2012-01-19 15:33 Bart Broersma Status new => feedback
2012-01-19 15:52 Bart Broersma Note Added: 0055852
2012-01-25 11:07 Martin Hoare Note Added: 0056026
2012-03-15 19:55 Vincent Snijders Status feedback => acknowledged
2012-03-16 11:31 Zeljan Rikalo Note Added: 0057708
2012-03-16 11:31 Zeljan Rikalo Status acknowledged => feedback
2012-03-16 22:33 Bart Broersma File Added: wsMaximizeTest.zip
2012-03-16 22:35 Bart Broersma Note Added: 0057743
2012-03-17 08:36 Zeljan Rikalo Note Added: 0057748
2012-03-17 08:38 Zeljan Rikalo Widgetset => GTK, GTK 2, Win32/Win64, WinCE, Carbon, Cocoa, QT
2012-03-17 08:38 Zeljan Rikalo Note Added: 0057749
2012-03-17 08:38 Zeljan Rikalo Category Packages => LCL
2012-03-17 08:38 Zeljan Rikalo Product Version 2.7.1 =>
2012-03-17 11:49 Zeljan Rikalo Fixed in Revision => 36106
2012-03-17 11:49 Zeljan Rikalo Status feedback => resolved
2012-03-17 11:49 Zeljan Rikalo Resolution open => fixed
2012-03-17 11:49 Zeljan Rikalo Assigned To => Zeljan Rikalo
2012-03-17 11:49 Zeljan Rikalo Note Added: 0057755
2012-03-17 12:02 Zeljan Rikalo Note Added: 0057756
2012-04-03 06:19 goldenfox Note Added: 0058270
2012-04-04 18:37 Bart Broersma Status resolved => assigned
2012-04-04 18:37 Bart Broersma Resolution fixed => reopened
2012-04-04 18:37 Bart Broersma Note Added: 0058293
2012-04-04 20:57 Zeljan Rikalo Note Added: 0058299
2012-04-05 07:38 Zeljan Rikalo Note Added: 0058306
2012-04-05 09:11 Zeljan Rikalo LazTarget - => 1.0
2012-04-05 09:11 Zeljan Rikalo Note Added: 0058308
2012-04-05 09:12 Zeljan Rikalo Note Added: 0058309
2012-04-05 09:12 Zeljan Rikalo Status assigned => confirmed
2012-04-05 09:12 Zeljan Rikalo Target Version => 1.0.0
2012-04-05 15:51 goldenfox Note Added: 0058324
2012-04-12 13:21 Zeljan Rikalo Relationship added related to 0021724
2012-08-30 12:22 Vincent Snijders Target Version 1.0.0 => 1.0.2
2012-08-30 12:22 Vincent Snijders LazTarget 1.0 => 1.0.2
2012-08-30 21:47 Bart Broersma Note Added: 0061989
2012-09-01 23:07 Bart Broersma Note Edited: 0061989
2012-09-01 23:07 Bart Broersma Relationship added related to 0022771
2012-10-09 13:42 Martin Friebe LazTarget 1.0.2 => 1.0.4
2012-10-09 13:46 Martin Friebe Target Version 1.0.2 => 1.0.4
2013-09-14 00:41 Martin Friebe LazTarget 1.0.4 => 1.2
2013-09-14 00:42 Martin Friebe Target Version 1.0.4 => 1.2.0
2014-02-15 20:51 Martin Friebe LazTarget 1.2 => 1.4
2014-02-15 20:52 Martin Friebe Target Version 1.2.0 => 1.4
2014-09-11 14:37 Zeljan Rikalo File Added: bug21119.diff
2014-09-11 14:39 Zeljan Rikalo Note Added: 0077084
2014-09-16 12:27 Mike Thompson Note Added: 0077302
2014-09-16 12:28 Mike Thompson Note Edited: 0077302 View Revisions
2014-09-16 20:28 Juha Manninen Relationship added related to 0008576
2015-02-06 16:00 Martin Friebe Relationship added related to 0027375
2015-04-27 21:59 Juha Manninen LazTarget 1.4 => -
2015-04-27 22:02 Juha Manninen Target Version 1.4 =>
2015-12-22 03:09 Edson Lidorio Note Added: 0088158
2019-10-03 14:34 Juha Manninen Relationship added related to 0036127
2020-03-16 19:24 Juha Manninen Status confirmed => resolved
2020-03-16 19:24 Juha Manninen Fixed in Revision 36106 => 36106, r61997, r62113
2020-03-16 19:24 Juha Manninen Widgetset GTK, GTK 2, Win32/Win64, WinCE, Carbon, Cocoa, QT => GTK, GTK 2, Win32/Win64, WinCE, Carbon, Cocoa, QT
2020-03-16 19:24 Juha Manninen Note Added: 0121625