View Issue Details

IDProjectCategoryView StatusLast Update
0036127LazarusLCLpublic2021-06-14 07:56
ReporterJoeny Ang Assigned ToJuha Manninen  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Platformx86_64OSArch Linux 
Product Version2.0.4 
Summary0036127: [Patch] TForm's bounds and restored bounds are inconsistent
DescriptionThe attached patch tries to fix the following issues:

When form is designed with WindowState=wsMaximized:
1. Restored dimension is wrong (related to 0027894, 0022771, 0027375)
2. Width/Height in OnShow() and OnActivate() events are wrong (related to 0021119)
     Under Delphi 3:
          - OnCreate(): design time restored width/height
          - OnShow() and OnActivate(): maximized width/height

When form's WindowsState=not maximized
3. Restored bounds in OnResize() and OnChangeBounds() events are wrong or not updated (related to 0032631)

Note: Expanded on the idea of Yuichiro Takahashi from Issue 0008576 to use Application.QueueAsyncCall() to "queue" the procedure to update the restored values, to the main event loop, thus delaying it until the form is properly moved or resized. The first calls to OnShow() and OnActivate() are also moved to this procedure so that querying Width/Height during these events will return the correct values.

Tested on GTK2 and Win32.
TagsNo tags attached.
Fixed in Revisionr61997, r62113, r63218, r63577, r63842, r63888, r64986, r65213, r65228
LazTarget-
WidgetsetGTK 2, Win32/Win64
Attached Files

Relationships

related to 0027894 closedJuha Manninen Lazarus TForm RestoredWidth and RestoredHeight updated incorrectly if window maximized under Gtk2 
related to 0022771 resolvedJuha Manninen Lazarus When FormStyle = wsMaximized, after restore Widht/Height have wrong values 
related to 0027375 resolvedJuha Manninen Lazarus If a Form is started with wsMaximized (set in OI), it does not restore to designed Size 
related to 0021119 resolvedZeljan Rikalo Lazarus When a form is started as wsMaximized height and width report design time values 
related to 0032631 resolvedJuha Manninen Packages "restoredLeft, restoredTop, restoredWidth, restoredHeight" of TForm returned wrong value 
related to 0008576 closedJuha Manninen Lazarus After Mini/Maximizing window 'RestoredLeft/Top' values changes to "unreal" values 
related to 0037647 closedJuha Manninen Lazarus It does not raise an OnShow event if the form is maximized and ... - since rev 63577 (changed from 62892) 
related to 0036877 closedZeljan Rikalo Lazarus LCL: Regression TCustomForm.OnActivate 
related to 0037467 resolvedJuha Manninen Lazarus Form Resize Not Firing Correctly 
related to 0037732 resolvedJuha Manninen Lazarus Win32: bad window behavior after Restore from minimized state 
related to 0037688 resolvedJuha Manninen Lazarus Form Resize, Controls sizing very slow 
related to 0038004 resolvedBart Broersma Lazarus Not executing the "OnResize" method in an embedded TForm 
related to 0038261 closedMichl Lazarus After revision 63888 SpartaDockedFormEditor is not refreshed after bounds change 
related to 0038922 closedMichl Lazarus FormShow call at wrong time 

Activities

Joeny Ang

2019-10-02 07:55

reporter  

tform-wrong-bounds-and-restored-bounds.patch (9,834 bytes)   
--- lcl/forms.pp
+++ lcl/forms.pp
@@ -490,6 +490,8 @@
     FRestoredHeight: integer;
     FShowInTaskbar: TShowInTaskbar;
     FWindowState: TWindowState;
+    FMovedCtr: Integer;
+    FIsFirstOnShow, FIsFirstOnActivate: Boolean;
     function GetClientHandle: HWND;
     function GetEffectiveShowInTaskBar: TShowInTaskBar;
     function GetMonitor: TMonitor;
@@ -590,7 +592,6 @@
     procedure VisibleChanged; override;
     procedure WndProc(var TheMessage : TLMessage); override;
     function VisibleIsStored: boolean;
-    procedure DoSendBoundsToInterface; override;
     procedure DoAutoSize; override;
     procedure SetAutoSize(Value: Boolean); override;
     procedure SetAutoScroll(Value: Boolean); override;
@@ -649,7 +650,8 @@
     function CanFocus: Boolean; override;
     procedure SetFocus; override;
     function SetFocusedControl(Control: TWinControl): Boolean ; virtual;
-    procedure SetRestoredBounds(ALeft, ATop, AWidth, AHeight: integer);
+    procedure SetRestoredBounds(ALeft, ATop, AWidth, AHeight: integer; const
+                                ADefaultPosition: Boolean = False);
     procedure Show;
 
     function ShowModal: Integer; virtual;
--- lcl/include/customform.inc
+++ lcl/include/customform.inc
@@ -16,6 +16,8 @@
 
 const
   BorderStylesAllowAutoScroll = [bsSizeable, bsSizeToolWin];
+  ShowCommands: array[TWindowState] of Integer =
+    (SW_SHOWNORMAL, SW_MINIMIZE, SW_SHOWMAXIMIZED, SW_SHOWFULLSCREEN);
 
 { TCustomForm }
 
@@ -68,93 +70,10 @@
   Gets called after the construction of the object
  ------------------------------------------------------------------------------}
 procedure TCustomForm.AfterConstruction;
-var
-  NewWidth, NewHeight: Integer;
-  OldWindowState: TWindowState;
-
-  procedure ChangeFormDimensions(AIsBeforeOnCreate: Boolean);
-  begin
-    if (WindowState = wsMaximized) and (FormStyle <> fsMDIChild) then
-    begin
-      {$IFDEF DEBUG_SM_LCLMAXIMIZED}
-      DebugLn('TCustomForm.AfterConstruction: SM_CYCAPTION ',
-        dbgs(GetSystemMetrics(SM_CYCAPTION)),
-      ' SM_CYSIZEFRAME ',dbgs(GetSystemMetrics(SM_CYSIZEFRAME)),
-      ' SM_CXMAXIMIZED ',dbgs(GetSystemMetrics(SM_CXMAXIMIZED)),
-      ' SM_CYMAXIMIZED ',dbgs(GetSystemMetrics(SM_CYMAXIMIZED)),
-      ' SM_LCLMAXIMIZEDHEIGHT ',dbgs(GetSystemMetrics(SM_LCLMAXIMIZEDHEIGHT)),
-      ' SM_LCLMAXIMIZEDWIDTH ',dbgs(GetSystemMetrics(SM_LCLMAXIMIZEDWIDTH)),
-      ' AIsBeforeOnCreate ',dbgs(AIsBeforeOnCreate));
-      {$ENDIF}
-
-      if (BorderStyle <> bsNone) and (FormStyle <> fsSplash) then
-      begin
-        NewHeight := GetSystemMetrics(SM_LCLMAXIMIZEDHEIGHT);
-        NewWidth := GetSystemMetrics(SM_LCLMAXIMIZEDWIDTH);
-        // if some ws does not implement this then provide normal metrics.
-        if NewHeight <= 0 then
-          NewHeight := GetSystemMetrics(SM_CYMAXIMIZED);
-        if NewWidth <= 0 then
-          NewHeight := GetSystemMetrics(SM_CXMAXIMIZED);
-      end else
-      begin
-        NewHeight := GetSystemMetrics(SM_CYMAXIMIZED);
-        NewWidth := GetSystemMetrics(SM_CXMAXIMIZED);
-      end;
-
-      if Constraints.MaxWidth > 0 then
-        NewWidth := Min(Constraints.MaxWidth, NewWidth);
-      if Constraints.MaxHeight > 0 then
-        NewHeight := Min(Constraints.MaxHeight, NewHeight);
-
-      // for unknown reasons on some systems SM_*MAXIMIZED* system metrics
-      // (tested xubuntu,64bits) return 0 or negative values, in this case
-      // a maximized window is expected to have at least WorkArea width/height.
-      //
-      // Reproduced again under Debian Wheezy.
-      // mistery solved, it ocurrs under gtk2/64-bit, fixed at the place
-      // the checks doesn't hurt though
-      //
-      // see bug #21634
-      if NewWidth<=0 then
-        NewWidth := Screen.WorkAreaWidth;
-      if NewHeight<=0 then
-        NewHeight := Screen.WorkAreaHeight;
-
-      if NewWidth>0 then
-        Width := NewWidth;
-      if NewHeight>0 then
-        Height := NewHeight;
-    end;
-
-    if (WindowState = wsFullScreen) and (FormStyle <> fsMDIChild) then
-    begin
-      NewWidth := LCLIntf.GetSystemMetrics(SM_CXFULLSCREEN);
-      NewHeight := LCLIntf.GetSystemMetrics(SM_CYFULLSCREEN);
-      if Constraints.MaxWidth > 0 then
-        NewWidth := Min(Constraints.MaxWidth, NewWidth);
-      if Constraints.MaxHeight > 0 then
-        NewHeight := Min(Constraints.MaxHeight, NewHeight);
-      Width := NewWidth;
-      Height := NewHeight;
-    end;
-  end;
-begin
-  // issue #21119, prepare maximized or fullscreen form to accurate dimensions.
-  // we avoid flickering also in this case.
-  if not (csDesigning in ComponentState) then
-    ChangeFormDimensions(True);
-
-  OldWindowState := WindowState;
+begin
+  SetRestoredBounds(Left, Top, Width, Height, True);
+
   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;
@@ -677,6 +596,9 @@
  ------------------------------------------------------------------------------}
 procedure TCustomForm.Activate;
 begin
+  if FIsFirstOnActivate and (WindowState = wsMaximized) then
+    Exit;
+  FIsFirstOnActivate := False;
   if Assigned(FOnActivate) then FOnActivate(Self);
 end;
 
@@ -732,28 +654,47 @@
   end;
 
   inherited WMSize(Message);
-
-  if (Message.SizeType and not SIZE_SourceIsInterface) = SIZE_RESTORED then
-  begin
-    FRestoredWidth := Width;
-    FRestoredHeight := Height;
-    //DebugLn('[TCustomForm.WMSize] saving restored bounds ',DbgSName(Self),' ',dbgs(FRestoredWidth),'x',dbgs(FRestoredHeight));
-  end;
+  Inc(FMovedCtr);
+  Application.QueueAsyncCall(@Moved, 1);  // 1 = resized
 end;
 
 procedure TCustomForm.WMMove(var Message: TLMMove);
 begin
   inherited WMMove(Message);
-  Application.QueueAsyncCall(@Moved, 0);
+  Inc(FMovedCtr);
+  Application.QueueAsyncCall(@Moved, 0);  // 0 = moved
 end;
 
 procedure TCustomForm.Moved(Data: PtrInt);
 begin
+  Dec(FMovedCtr);
+  if FMovedCtr > 0 then
+    Exit;
   if WindowState = wsNormal then
   begin
-    FRestoredLeft := Left;
-    FRestoredTop := Top;
-  end;
+    if Data = 0 then
+      begin
+        FRestoredLeft := Left;
+        FRestoredTop := Top;
+      end
+    else
+      begin
+        FRestoredWidth := Width;
+        FRestoredHeight := Height;
+        DoOnResize;
+      end;
+    DoOnChangeBounds;
+  end;
+  if FIsFirstOnShow then
+    begin
+      FIsFirstOnShow := False;
+      DoShow;
+    end;
+  if FIsFirstOnActivate then
+    begin
+      FIsFirstOnActivate := False;
+      Activate;
+    end;
 end;
 
 procedure TCustomForm.WMWindowPosChanged(var Message: TLMWindowPosChanged);
@@ -1016,6 +957,9 @@
  ------------------------------------------------------------------------------}
 procedure TCustomForm.DoShow;
 begin
+  if FIsFirstOnShow and (WindowState = wsMaximized) then
+    Exit;
+  FIsFirstOnShow := False;
   if Assigned(FOnShow) then FOnShow(Self);
 end;
 
@@ -1338,7 +1282,7 @@
           AForm := TCustomForm(Owner)
         else
           AForm := Application.MainForm;
-        if (Self <> AForm) then
+        if (Self <> AForm) and Assigned(AForm) then
         begin
           if FormStyle = fsMDIChild then
           begin
@@ -1487,18 +1431,6 @@
   Result := (Color <> {$ifdef UseCLDefault}clDefault{$else}clBtnFace{$endif});
 end;
 
-procedure TCustomForm.DoSendBoundsToInterface;
-begin
-  inherited DoSendBoundsToInterface;
-  if WindowState = wsNormal then
-  begin
-    FRestoredLeft := Left;
-    FRestoredTop := Top;
-    FRestoredWidth := Width;
-    FRestoredHeight := Height;
-  end;
-end;
-
 procedure TCustomForm.GetPreferredSize(var PreferredWidth,
   PreferredHeight: integer; Raw: boolean; WithThemeSpace: boolean);
 begin
@@ -1851,9 +1783,6 @@
        TCustomForm SetWindowState
 ------------------------------------------------------------------------------}
 procedure TCustomForm.SetWindowState(Value : TWindowState);
-const
-  ShowCommands: array[TWindowState] of Integer =
-    (SW_SHOWNORMAL, SW_MINIMIZE, SW_SHOWMAXIMIZED, SW_SHOWFULLSCREEN);
 begin
   if FWindowState <> Value then
   begin
@@ -1864,7 +1793,8 @@
   end;
 end;
 
-procedure TCustomForm.SetRestoredBounds(ALeft, ATop, AWidth, AHeight: integer);
+procedure TCustomForm.SetRestoredBounds(ALeft, ATop, AWidth, AHeight: integer;
+  const ADefaultPosition: Boolean);
 var
   prevWindowState: TWindowState;
 begin
@@ -1874,7 +1804,14 @@
   prevWindowState := WindowState;
   WindowState := wsNormal;
   SetBounds(ALeft, ATop, AWidth, AHeight);
+  // override
+  if ADefaultPosition then
+    MoveToDefaultPosition;
   WindowState := prevWindowState;
+  FRestoredLeft := Left;
+  FRestoredTop := Top;
+  FRestoredWidth := Width;
+  FRestoredHeight := Height;
 end;
 
 procedure TCustomForm.SetScaled(const AScaled: Boolean);
@@ -2047,6 +1984,9 @@
 ------------------------------------------------------------------------------}
 constructor TCustomForm.Create(AOwner: TComponent);
 begin
+  FMovedCtr := 0;
+  FIsFirstOnShow := True;
+  FIsFirstOnActivate := True;
   GlobalNameSpace.BeginWrite;
   try
     CreateNew(AOwner, 1); // this calls BeginFormUpdate, which is ended in AfterConstruction
@@ -2328,6 +2268,9 @@
       Width, MulDiv(Width, Monitor.PixelsPerInch, PixelsPerInch));
 
   Visible := True;
+  { wxMaximized secondary forms are not being shown maximized }
+  if (not (csDesigning in ComponentState)) and Showing then
+    ShowWindow(Handle, ShowCommands[WindowState]);
   BringToFront;
 end;
 

tform-restoredbounds.zip (133,630 bytes)

Joeny Ang

2019-10-03 01:52

reporter   ~0118263

Updated the patch (v2) with the following fixes:
- because the queued procedure is shared between WMMove and WMSize events, an event is sometimes missed because duplicate calls are discarded.
tform-wrong-bounds-and-restored-bounds-v2.patch (10,758 bytes)   
--- lcl/forms.pp
+++ lcl/forms.pp
@@ -490,6 +490,9 @@
     FRestoredHeight: integer;
     FShowInTaskbar: TShowInTaskbar;
     FWindowState: TWindowState;
+    FDelayedEventCtr: Integer;
+    FDelayedWMMove, FDelayedWMSize: Boolean;
+    FIsFirstOnShow, FIsFirstOnActivate: Boolean;
     function GetClientHandle: HWND;
     function GetEffectiveShowInTaskBar: TShowInTaskBar;
     function GetMonitor: TMonitor;
@@ -499,7 +502,7 @@
     procedure CloseModal;
     procedure FreeIconHandles;
     procedure IconChanged(Sender: TObject);
-    procedure Moved(Data: PtrInt);
+    procedure DelayedEvent(Data: PtrInt);
     procedure SetActive(AValue: Boolean);
     procedure SetActiveControl(AWinControl: TWinControl);
     procedure SetActiveDefaultControl(AControl: TControl);
@@ -590,7 +593,6 @@
     procedure VisibleChanged; override;
     procedure WndProc(var TheMessage : TLMessage); override;
     function VisibleIsStored: boolean;
-    procedure DoSendBoundsToInterface; override;
     procedure DoAutoSize; override;
     procedure SetAutoSize(Value: Boolean); override;
     procedure SetAutoScroll(Value: Boolean); override;
@@ -649,7 +651,8 @@
     function CanFocus: Boolean; override;
     procedure SetFocus; override;
     function SetFocusedControl(Control: TWinControl): Boolean ; virtual;
-    procedure SetRestoredBounds(ALeft, ATop, AWidth, AHeight: integer);
+    procedure SetRestoredBounds(ALeft, ATop, AWidth, AHeight: integer; const
+                                ADefaultPosition: Boolean = False);
     procedure Show;
 
     function ShowModal: Integer; virtual;
--- lcl/include/customform.inc
+++ lcl/include/customform.inc
@@ -16,6 +16,8 @@
 
 const
   BorderStylesAllowAutoScroll = [bsSizeable, bsSizeToolWin];
+  ShowCommands: array[TWindowState] of Integer =
+    (SW_SHOWNORMAL, SW_MINIMIZE, SW_SHOWMAXIMIZED, SW_SHOWFULLSCREEN);
 
 { TCustomForm }
 
@@ -68,93 +70,10 @@
   Gets called after the construction of the object
  ------------------------------------------------------------------------------}
 procedure TCustomForm.AfterConstruction;
-var
-  NewWidth, NewHeight: Integer;
-  OldWindowState: TWindowState;
-
-  procedure ChangeFormDimensions(AIsBeforeOnCreate: Boolean);
-  begin
-    if (WindowState = wsMaximized) and (FormStyle <> fsMDIChild) then
-    begin
-      {$IFDEF DEBUG_SM_LCLMAXIMIZED}
-      DebugLn('TCustomForm.AfterConstruction: SM_CYCAPTION ',
-        dbgs(GetSystemMetrics(SM_CYCAPTION)),
-      ' SM_CYSIZEFRAME ',dbgs(GetSystemMetrics(SM_CYSIZEFRAME)),
-      ' SM_CXMAXIMIZED ',dbgs(GetSystemMetrics(SM_CXMAXIMIZED)),
-      ' SM_CYMAXIMIZED ',dbgs(GetSystemMetrics(SM_CYMAXIMIZED)),
-      ' SM_LCLMAXIMIZEDHEIGHT ',dbgs(GetSystemMetrics(SM_LCLMAXIMIZEDHEIGHT)),
-      ' SM_LCLMAXIMIZEDWIDTH ',dbgs(GetSystemMetrics(SM_LCLMAXIMIZEDWIDTH)),
-      ' AIsBeforeOnCreate ',dbgs(AIsBeforeOnCreate));
-      {$ENDIF}
-
-      if (BorderStyle <> bsNone) and (FormStyle <> fsSplash) then
-      begin
-        NewHeight := GetSystemMetrics(SM_LCLMAXIMIZEDHEIGHT);
-        NewWidth := GetSystemMetrics(SM_LCLMAXIMIZEDWIDTH);
-        // if some ws does not implement this then provide normal metrics.
-        if NewHeight <= 0 then
-          NewHeight := GetSystemMetrics(SM_CYMAXIMIZED);
-        if NewWidth <= 0 then
-          NewHeight := GetSystemMetrics(SM_CXMAXIMIZED);
-      end else
-      begin
-        NewHeight := GetSystemMetrics(SM_CYMAXIMIZED);
-        NewWidth := GetSystemMetrics(SM_CXMAXIMIZED);
-      end;
-
-      if Constraints.MaxWidth > 0 then
-        NewWidth := Min(Constraints.MaxWidth, NewWidth);
-      if Constraints.MaxHeight > 0 then
-        NewHeight := Min(Constraints.MaxHeight, NewHeight);
-
-      // for unknown reasons on some systems SM_*MAXIMIZED* system metrics
-      // (tested xubuntu,64bits) return 0 or negative values, in this case
-      // a maximized window is expected to have at least WorkArea width/height.
-      //
-      // Reproduced again under Debian Wheezy.
-      // mistery solved, it ocurrs under gtk2/64-bit, fixed at the place
-      // the checks doesn't hurt though
-      //
-      // see bug #21634
-      if NewWidth<=0 then
-        NewWidth := Screen.WorkAreaWidth;
-      if NewHeight<=0 then
-        NewHeight := Screen.WorkAreaHeight;
-
-      if NewWidth>0 then
-        Width := NewWidth;
-      if NewHeight>0 then
-        Height := NewHeight;
-    end;
-
-    if (WindowState = wsFullScreen) and (FormStyle <> fsMDIChild) then
-    begin
-      NewWidth := LCLIntf.GetSystemMetrics(SM_CXFULLSCREEN);
-      NewHeight := LCLIntf.GetSystemMetrics(SM_CYFULLSCREEN);
-      if Constraints.MaxWidth > 0 then
-        NewWidth := Min(Constraints.MaxWidth, NewWidth);
-      if Constraints.MaxHeight > 0 then
-        NewHeight := Min(Constraints.MaxHeight, NewHeight);
-      Width := NewWidth;
-      Height := NewHeight;
-    end;
-  end;
-begin
-  // issue #21119, prepare maximized or fullscreen form to accurate dimensions.
-  // we avoid flickering also in this case.
-  if not (csDesigning in ComponentState) then
-    ChangeFormDimensions(True);
-
-  OldWindowState := WindowState;
+begin
+  SetRestoredBounds(Left, Top, Width, Height, True);
+
   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;
@@ -677,6 +596,9 @@
  ------------------------------------------------------------------------------}
 procedure TCustomForm.Activate;
 begin
+  if FIsFirstOnActivate and (WindowState = wsMaximized) then
+    Exit;
+  FIsFirstOnActivate := False;
   if Assigned(FOnActivate) then FOnActivate(Self);
 end;
 
@@ -733,27 +655,55 @@
 
   inherited WMSize(Message);
 
-  if (Message.SizeType and not SIZE_SourceIsInterface) = SIZE_RESTORED then
-  begin
-    FRestoredWidth := Width;
-    FRestoredHeight := Height;
-    //DebugLn('[TCustomForm.WMSize] saving restored bounds ',DbgSName(Self),' ',dbgs(FRestoredWidth),'x',dbgs(FRestoredHeight));
-  end;
+  FDelayedWMSize := True;
+  Inc(FDelayedEventCtr);
+  Application.QueueAsyncCall(@DelayedEvent, 0);
 end;
 
 procedure TCustomForm.WMMove(var Message: TLMMove);
 begin
   inherited WMMove(Message);
-  Application.QueueAsyncCall(@Moved, 0);
-end;
-
-procedure TCustomForm.Moved(Data: PtrInt);
-begin
+
+  FDelayedWMMove := True;
+  Inc(FDelayedEventCtr);
+  Application.QueueAsyncCall(@DelayedEvent, 0);
+end;
+
+procedure TCustomForm.DelayedEvent(Data: PtrInt);
+begin
+  { discard duplicate calls, accept last call only }
+  Dec(FDelayedEventCtr);
+  if FDelayedEventCtr > 0 then
+    Exit;
+  { update restored bounds }
   if WindowState = wsNormal then
-  begin
-    FRestoredLeft := Left;
-    FRestoredTop := Top;
-  end;
+    begin
+      if FDelayedWMMove then
+        begin
+          FRestoredLeft := Left;
+          FRestoredTop := Top;
+        end;
+      if FDelayedWMSize then
+        begin
+          FRestoredWidth := Width;
+          FRestoredHeight := Height;
+          DoOnResize;     // delayed onResize()
+        end;
+      DoOnChangeBounds;     // delayed onChangeBounds()
+    end;
+  FDelayedWMMove := False;
+  FDelayedWMSize := False;
+  { call onShow() or onActivate() for the first time }
+  if FIsFirstOnShow then
+    begin
+      FIsFirstOnShow := False;
+      DoShow;
+    end;
+  if FIsFirstOnActivate then
+    begin
+      FIsFirstOnActivate := False;
+      Activate;
+    end;
 end;
 
 procedure TCustomForm.WMWindowPosChanged(var Message: TLMWindowPosChanged);
@@ -1016,6 +966,9 @@
  ------------------------------------------------------------------------------}
 procedure TCustomForm.DoShow;
 begin
+  if FIsFirstOnShow and (WindowState = wsMaximized) then
+    Exit;
+  FIsFirstOnShow := False;
   if Assigned(FOnShow) then FOnShow(Self);
 end;
 
@@ -1338,7 +1291,7 @@
           AForm := TCustomForm(Owner)
         else
           AForm := Application.MainForm;
-        if (Self <> AForm) then
+        if (Self <> AForm) and Assigned(AForm) then
         begin
           if FormStyle = fsMDIChild then
           begin
@@ -1487,18 +1440,6 @@
   Result := (Color <> {$ifdef UseCLDefault}clDefault{$else}clBtnFace{$endif});
 end;
 
-procedure TCustomForm.DoSendBoundsToInterface;
-begin
-  inherited DoSendBoundsToInterface;
-  if WindowState = wsNormal then
-  begin
-    FRestoredLeft := Left;
-    FRestoredTop := Top;
-    FRestoredWidth := Width;
-    FRestoredHeight := Height;
-  end;
-end;
-
 procedure TCustomForm.GetPreferredSize(var PreferredWidth,
   PreferredHeight: integer; Raw: boolean; WithThemeSpace: boolean);
 begin
@@ -1851,9 +1792,6 @@
        TCustomForm SetWindowState
 ------------------------------------------------------------------------------}
 procedure TCustomForm.SetWindowState(Value : TWindowState);
-const
-  ShowCommands: array[TWindowState] of Integer =
-    (SW_SHOWNORMAL, SW_MINIMIZE, SW_SHOWMAXIMIZED, SW_SHOWFULLSCREEN);
 begin
   if FWindowState <> Value then
   begin
@@ -1864,7 +1802,8 @@
   end;
 end;
 
-procedure TCustomForm.SetRestoredBounds(ALeft, ATop, AWidth, AHeight: integer);
+procedure TCustomForm.SetRestoredBounds(ALeft, ATop, AWidth, AHeight: integer;
+  const ADefaultPosition: Boolean);
 var
   prevWindowState: TWindowState;
 begin
@@ -1874,7 +1813,14 @@
   prevWindowState := WindowState;
   WindowState := wsNormal;
   SetBounds(ALeft, ATop, AWidth, AHeight);
+  // override
+  if ADefaultPosition then
+    MoveToDefaultPosition;
   WindowState := prevWindowState;
+  FRestoredLeft := Left;
+  FRestoredTop := Top;
+  FRestoredWidth := Width;
+  FRestoredHeight := Height;
 end;
 
 procedure TCustomForm.SetScaled(const AScaled: Boolean);
@@ -2047,6 +1993,11 @@
 ------------------------------------------------------------------------------}
 constructor TCustomForm.Create(AOwner: TComponent);
 begin
+  FDelayedEventCtr := 0;
+  FDelayedWMMove := False;
+  FDelayedWMSize := False;
+  FIsFirstOnShow := True;
+  FIsFirstOnActivate := True;
   GlobalNameSpace.BeginWrite;
   try
     CreateNew(AOwner, 1); // this calls BeginFormUpdate, which is ended in AfterConstruction
@@ -2328,6 +2279,9 @@
       Width, MulDiv(Width, Monitor.PixelsPerInch, PixelsPerInch));
 
   Visible := True;
+  { wxMaximized secondary forms are not being shown maximized }
+  if (not (csDesigning in ComponentState)) and Showing then
+    ShowWindow(Handle, ShowCommands[WindowState]);
   BringToFront;
 end;
 

Juha Manninen

2019-10-03 14:01

developer   ~0118278

Interesting! How many of the related issues this would fix?
I think this should be applied and tested in trunk.

Juha Manninen

2019-10-05 20:28

developer   ~0118358

I applied the patch in r61997 for everybody to test. Let's see if somebody finds bugs in it.

Joeny Ang

2019-10-07 06:00

reporter  

delayedevent-wait-for-wmsize-before-onshow-onactivate.patch (922 bytes)   
--- lcl/include/customform.inc
+++ lcl/include/customform.inc
@@ -691,19 +691,22 @@
         end;
       DoOnChangeBounds;     // delayed onChangeBounds()
     end;
+  { call onShow() or onActivate() for the first time, after first WMSize }
+  if FDelayedWMSize then
+    begin
+      if FIsFirstOnShow then
+        begin
+          FIsFirstOnShow := False;
+          DoShow;
+        end;
+      if FIsFirstOnActivate then
+        begin
+          FIsFirstOnActivate := False;
+          Activate;
+        end;
+    end;
   FDelayedWMMove := False;
   FDelayedWMSize := False;
-  { call onShow() or onActivate() for the first time }
-  if FIsFirstOnShow then
-    begin
-      FIsFirstOnShow := False;
-      DoShow;
-    end;
-  if FIsFirstOnActivate then
-    begin
-      FIsFirstOnActivate := False;
-      Activate;
-    end;
 end;
 
 procedure TCustomForm.WMWindowPosChanged(var Message: TLMWindowPosChanged);

Joeny Ang

2019-10-07 06:00

reporter   ~0118386

Another one :)

GTK2 only:
When a form is designed so as part of it is clipped off the screen, and WindowState=wsMaximized, width and height during onShow()/onActivate() is wrong.
Reason: After creation (?), the window manager automatically moves the form so that the whole form is visible. This will trigger WMMove() events, thus triggering the delayed onShow()/onActivate() even before the form is maxmimized.
Solution is to wait for the first WMSize() before triggering onShow()/onActivate().

Apply patch after the v2 patch.

Juha Manninen

2019-10-24 22:37

developer   ~0118793

I applied the new patch in r62113. Thanks. Please test everybody.

Juha Manninen

2020-03-16 18:29

developer   ~0121628

Resolving.
Thank you Joeny Ang for the patches.

Michl

2020-05-24 13:56

developer   ~0123037

Last edited: 2020-05-24 15:33

View 3 revisions

At least it breaks the usage of SpartaDockedFormEditor. After revision 61997 it isn't possible to change the bounds of a form anymore.

Too bad, just Windows seems to be affected. Just tried GTK2 and QT, both are working fine.

I'll try to look at it.

Michl

2020-05-25 13:17

developer   ~0123059

I fixed the problem with SpartaDockedFormEditor in revision 63218

Michl

2020-05-25 19:05

developer   ~0123062

Last edited: 2020-05-25 19:08

View 3 revisions

I have to reopen the issue. I could fix one problem with SpartaDockedFormEditor, but there is a other one, what can't be fixed there. If there are more than one form opened and resized, the frame got corrupted. Before I can search for the problem, one main problem has to be fixed:

After the revision 61997, OnChangeBounds of a form is called twice. See added project TestChangeBoundsEvent.zip. (tested on Windows 7)

Joeny Ang

2020-07-15 08:26

reporter   ~0124030

Last edited: 2020-07-15 08:27

View 2 revisions

Changes made by this patch:
  - fixed sequence of events (based on Delphi 3... create, show, activate, resize)
  - OnResize() and OnChangeBounds() are being called twice
      :: moved code queueing delayed events to overriden DoOnResize() and DoOnChangeBounds()
  - removed TCustomForm.WMMove()
  - added check for wsFullScreen in TCustomForm.Activate() and TCustomForm.DoShow()
  - renamed some variables
fix-duplicate-onresize-onchangebounds.patch (4,523 bytes)   
--- lcl/forms.pp
+++ lcl/forms.pp
@@ -491,7 +491,7 @@
     FShowInTaskbar: TShowInTaskbar;
     FWindowState: TWindowState;
     FDelayedEventCtr: Integer;
-    FDelayedWMMove, FDelayedWMSize: Boolean;
+    FDelayedOnChangeBounds, FDelayedOnResize: Boolean;
     FIsFirstOnShow, FIsFirstOnActivate: Boolean;
     function GetClientHandle: HWND;
     function GetEffectiveShowInTaskBar: TShowInTaskBar;
@@ -535,7 +535,6 @@
     procedure WMActivate(var Message : TLMActivate); message LM_ACTIVATE;
     procedure WMCloseQuery(var message: TLMessage); message LM_CLOSEQUERY;
     procedure WMHelp(var Message: TLMHelp); message LM_HELP;
-    procedure WMMove(var Message: TLMMove); message LM_MOVE;
     procedure WMShowWindow(var message: TLMShowWindow); message LM_SHOWWINDOW;
     procedure WMSize(var message: TLMSize); message LM_Size;
     procedure WMWindowPosChanged(var Message: TLMWindowPosChanged); message LM_WINDOWPOSCHANGED;
@@ -581,6 +580,8 @@
     procedure Resizing(State: TWindowState); override;
     procedure CalculatePreferredSize(var PreferredWidth,
            PreferredHeight: integer; WithThemeSpace: Boolean); override;
+    procedure DoOnResize; override;
+    procedure DoOnChangeBounds; override;
     procedure SetZOrder(Topmost: Boolean); override;
     procedure SetParent(NewParent: TWinControl); override;
     procedure MoveToDefaultPosition; virtual;
--- lcl/include/customform.inc
+++ lcl/include/customform.inc
@@ -604,7 +604,7 @@
  ------------------------------------------------------------------------------}
 procedure TCustomForm.Activate;
 begin
-  if FIsFirstOnActivate and (WindowState = wsMaximized) then
+  if FIsFirstOnActivate and (WindowState in [wsMaximized, wsFullScreen]) then
     Exit;
   FIsFirstOnActivate := False;
   if Assigned(FOnActivate) then FOnActivate(Self);
@@ -662,22 +662,23 @@
   end;
 
   inherited WMSize(Message);
-
+end;
+
+procedure TCustomForm.DoOnResize;
+begin
   if not (csDestroying in ComponentState) then
   begin
-    FDelayedWMSize := True;
+    FDelayedOnResize := True;
     Inc(FDelayedEventCtr);
     Application.QueueAsyncCall(@DelayedEvent, 0);
   end;
 end;
 
-procedure TCustomForm.WMMove(var Message: TLMMove);
-begin
-  inherited WMMove(Message);
-
+procedure TCustomForm.DoOnChangeBounds;
+begin
   if not (csDestroying in ComponentState) then
   begin
-    FDelayedWMMove := True;
+    FDelayedOnChangeBounds := True;
     Inc(FDelayedEventCtr);
     Application.QueueAsyncCall(@DelayedEvent, 0);
   end;
@@ -692,21 +693,20 @@
   { update restored bounds }
   if WindowState = wsNormal then
     begin
-      if FDelayedWMMove then
+      if FDelayedOnChangeBounds then
         begin
           FRestoredLeft := Left;
           FRestoredTop := Top;
         end;
-      if FDelayedWMSize then
+      if FDelayedOnResize then
         begin
           FRestoredWidth := Width;
           FRestoredHeight := Height;
-          DoOnResize;     // delayed onResize()
         end;
-      DoOnChangeBounds;     // delayed onChangeBounds()
-    end;
-  { call onShow() or onActivate() for the first time, after first WMSize }
-  if FDelayedWMSize then
+    end;
+  { call onShow() or onActivate() for the first time, after first OnResize()
+    and OnChangeBounds() }
+  if FDelayedOnResize and FDelayedOnChangeBounds then
     begin
       if FIsFirstOnShow then
         begin
@@ -720,8 +720,14 @@
             Activate;
         end;
     end;
-  FDelayedWMMove := False;
-  FDelayedWMSize := False;
+  { delayed onResize() }
+  if FDelayedOnResize then
+    inherited DoOnResize;
+  { delayed onChangeBounds() }
+  if FDelayedOnResize or FDelayedOnChangeBounds then
+    inherited DoOnChangeBounds;
+  FDelayedOnChangeBounds := False;
+  FDelayedOnResize := False;
 end;
 
 procedure TCustomForm.WMWindowPosChanged(var Message: TLMWindowPosChanged);
@@ -992,7 +998,7 @@
  ------------------------------------------------------------------------------}
 procedure TCustomForm.DoShow;
 begin
-  if FIsFirstOnShow and (WindowState = wsMaximized) then
+  if FIsFirstOnShow and (WindowState in [wsMaximized, wsFullScreen]) then
     Exit;
   FIsFirstOnShow := False;
   if Assigned(FOnShow) then FOnShow(Self);
@@ -2020,8 +2026,8 @@
 constructor TCustomForm.Create(AOwner: TComponent);
 begin
   FDelayedEventCtr := 0;
-  FDelayedWMMove := False;
-  FDelayedWMSize := False;
+  FDelayedOnChangeBounds := False;
+  FDelayedOnResize := False;
   FIsFirstOnShow := True;
   FIsFirstOnActivate := True;
   GlobalNameSpace.BeginWrite;

Juha Manninen

2020-07-16 23:01

developer   ~0124110

Thanks for the patch. I applied it in r63577.
Michl and others, please test.

Juha Manninen

2020-07-22 17:35

developer   ~0124233

No complaints. I guess this is fixed now. Resolving...

Juha Manninen

2020-08-26 09:12

developer   ~0125129

Last edited: 2020-08-26 09:13

View 2 revisions

r63577 caused a regression, see the related issue 0037467.
How to fix it?

BrunoK

2020-08-26 13:44

reporter   ~0125133

In my trunk I reverted to r62745.

Reason : Unit2.Form2 of example has Position = poMainFormCenter. I would expect that when restoring Form2 from initial wsMaximized to wsNomal the first time, it would place form2 at poMainFormCenter.
Afterwards, the new position of the modal form2 goes tracks the the last size/position.

Failing event FormResize beeing tracked is no good.

Also avoiding excessive messages in DelayedEvent seems reasonabéy neat in its currrent state.

Juha Manninen

2020-08-26 19:45

developer   ~0125143

How is r62745 related to this one? It says:
 "LCL: implement MDI for win32. Issue 36582, based on patch by Kostas Michalopoulos, attempt 2"

Paweł Dmitruk

2020-08-27 09:24

reporter   ~0125150

Juha: https://bugs.freepascal.org/view.php?id=37647

BrunoK

2020-08-27 09:54

reporter   ~0125151

Last edited: 2020-08-27 10:09

View 2 revisions

@Juha Manninen 2020-08-26 21:45

I picked up the lcl\forms.pp and lcl\include\customform.inc from r62745 and replaced the trunk r63577 version of these files in my installation.

At r62745 these two files seem to be OK . Issue 0037467 does not show with this version.

The logic of the various resizing events are a bit dispersed but still usable, I remember that in Delphi [ed. BDS 2007] BDS 2006 I had already difficulties figuring out how those things worked.

Here after a modified Unit2 from TestChangeBoundsEvent.zip that gives a bit more information about how the related sizing events works. Also if you change the Position = poMainFormCenter to Position = poDesigned, form2 will show at the designed position.

Joeny Ang

2020-08-28 01:17

reporter   ~0125163

Another patch :)
- if form is designed maximized or fullscreen, first restore will now honor Position property
- setting WindowState property will now trigger onWindowStateChange()
- win32: moving/resizing via mouse will now trigger onResize/onChangeBounds
  :: the async queue is not being processed while the mouse button is down
- gtk2: switching (via code) between wsFullscreen and other states now works properly

Tested:
  Widgetsets: Gtk2, Qt5, Win32 (WinXP)
  Window managers: Metacity, Mutter
tform-wrong-bounds-and-restored-bounds-part4.patch (5,701 bytes)   
--- lazarus/lcl/forms.pp.63838
+++ lazarus/lcl/forms.pp
@@ -492,7 +492,7 @@
     FWindowState: TWindowState;
     FDelayedEventCtr: Integer;
     FDelayedOnChangeBounds, FDelayedOnResize: Boolean;
-    FIsFirstOnShow, FIsFirstOnActivate: Boolean;
+    FIsFirstOnShow, FIsFirstOnActivate, FIsFirstRestore: Boolean;
     function GetClientHandle: HWND;
     function GetEffectiveShowInTaskBar: TShowInTaskBar;
     function GetMonitor: TMonitor;
--- lazarus/lcl/include/customform.inc.63838
+++ lazarus/lcl/include/customform.inc
@@ -692,42 +692,45 @@
     Exit;
   { update restored bounds }
   if WindowState = wsNormal then
-    begin
-      if FDelayedOnChangeBounds then
-        begin
-          FRestoredLeft := Left;
-          FRestoredTop := Top;
-        end;
-      if FDelayedOnResize then
-        begin
-          FRestoredWidth := Width;
-          FRestoredHeight := Height;
-        end;
-    end;
+  begin
+    if FDelayedOnChangeBounds then
+    begin
+      FRestoredLeft := Left;
+      FRestoredTop := Top;
+    end;
+    if FDelayedOnResize then
+    begin
+      FRestoredWidth := Width;
+      FRestoredHeight := Height;
+    end;
+  end;
   { call onShow() or onActivate() for the first time, after first OnResize()
     and OnChangeBounds() }
   if FDelayedOnResize and FDelayedOnChangeBounds then
-    begin
-      if FIsFirstOnShow then
-        begin
-          FIsFirstOnShow := False;
-          DoShow;
-        end;
-      if FIsFirstOnActivate then
-        begin
-          FIsFirstOnActivate := False;
-          if FActive then
-            Activate;
-        end;
-    end;
-  { delayed onResize() }
-  if FDelayedOnResize then
-    inherited DoOnResize;
-  { delayed onChangeBounds() }
-  if FDelayedOnResize or FDelayedOnChangeBounds then
-    inherited DoOnChangeBounds;
-  FDelayedOnChangeBounds := False;
-  FDelayedOnResize := False;
+  begin
+    if FIsFirstOnShow then
+    begin
+      FIsFirstOnShow := False;
+      DoShow;
+    end;
+    if FIsFirstOnActivate then
+    begin
+      FIsFirstOnActivate := False;
+      if FActive then
+        Activate;
+    end;
+  end;
+  if not (FIsFirstOnShow or FIsFirstOnActivate) then
+  begin
+    { delayed onResize() }
+    if FDelayedOnResize then
+      inherited DoOnResize;
+    { delayed onChangeBounds() }
+    if FDelayedOnResize or FDelayedOnChangeBounds then
+      inherited DoOnChangeBounds;
+    FDelayedOnChangeBounds := False;
+    FDelayedOnResize := False;
+  end;
 end;
 
 procedure TCustomForm.WMWindowPosChanged(var Message: TLMWindowPosChanged);
@@ -1001,6 +1004,7 @@
   if FIsFirstOnShow and (WindowState in [wsMaximized, wsFullScreen]) then
     Exit;
   FIsFirstOnShow := False;
+  FIsFirstRestore := WindowState in [wsMaximized, wsFullScreen];
   if Assigned(FOnShow) then FOnShow(Self);
 end;
 
@@ -1139,17 +1143,15 @@
   if Showing and not (csDesigning in ComponentState) then
   begin
     OldState := FWindowState;
-    FWindowState := State;
     if OldState <> State then
     begin
+      WindowState := State;
       if (State = wsMinimized) and (Application.MainForm = Self) and
          (WidgetSet.GetLCLCapability(lcNeedMininimizeAppWithMainForm) <> LCL_CAPABILITY_NO) then
         Application.Minimize;
       if (OldState = wsMinimized) and (Application.MainForm = Self) and
          (WidgetSet.GetLCLCapability(lcNeedMininimizeAppWithMainForm) <> LCL_CAPABILITY_NO) then
         Application.Restore;
-      if Assigned(OnWindowStateChange) then
-        OnWindowStateChange(Self);
     end;
   end;
 end;
@@ -1830,7 +1832,19 @@
     FWindowState := Value;
     //DebugLn(['TCustomForm.SetWindowState ',DbgSName(Self),' ',ord(FWindowState),' csDesigning=',csDesigning in ComponentState,' Showing=',Showing]);
     if (not (csDesigning in ComponentState)) and Showing then
+    begin
       ShowWindow(Handle, ShowCommands[Value]);
+      if not (FIsFirstOnShow or FIsFirstOnActivate) then
+      begin
+        if FIsFirstRestore then
+        begin
+          MoveToDefaultPosition;
+          FIsFirstRestore := False;
+        end;
+        if Assigned(OnWindowStateChange) then
+          OnWindowStateChange(Self);
+      end;
+    end;
   end;
 end;
 
@@ -2030,6 +2044,7 @@
   FDelayedOnResize := False;
   FIsFirstOnShow := True;
   FIsFirstOnActivate := True;
+  FIsFirstRestore := False;
   GlobalNameSpace.BeginWrite;
   try
     CreateNew(AOwner, 1); // this calls BeginFormUpdate, which is ended in AfterConstruction
--- lcl/interfaces/win32/win32callback.inc.63838
+++ lcl/interfaces/win32/win32callback.inc
@@ -15,6 +15,7 @@
 {$ENDIF}
 type
   TWinControlAccess = class(TWinControl);
+  TApplicationAccess = class(TApplication);
 {*************************************************************}
 {            callback routines                                }
 {*************************************************************}
@@ -2054,6 +2055,8 @@
       begin
         CheckSynchronize;
         TWin32Widgetset(Widgetset).CheckPipeEvents;
+        if Assigned(Application) then
+          TApplicationAccess(Application).ProcessAsyncCallQueue;
       end;
     WM_ENTERIDLE: Application.Idle(False);
     WM_ACTIVATE:  SetLMessageAndParams(LM_ACTIVATE);
--- lcl/interfaces/gtk2/gtk2callback.inc.63838
+++ lcl/interfaces/gtk2/gtk2callback.inc
@@ -1121,6 +1121,8 @@
           {$ENDIF}
           SizeMsg.SizeType := SIZE_MINIMIZED;
         end
+        else if (GDK_WINDOW_STATE_FULLSCREEN and state^.new_window_state)>0 then
+          SizeMsg.SizeType := SIZE_FULLSCREEN
         else if (GDK_WINDOW_STATE_MAXIMIZED and state^.new_window_state)>0 then
         begin
           // it can be both maximized + iconified and just loose iconified state

Joeny Ang

2020-08-28 09:16

reporter   ~0125170

Oooppss... updated the patch. :)
tform-wrong-bounds-and-restored-bounds-part4v2.patch (5,669 bytes)   
--- lcl/forms.pp.63838
+++ lcl/forms.pp
@@ -492,7 +492,7 @@
     FWindowState: TWindowState;
     FDelayedEventCtr: Integer;
     FDelayedOnChangeBounds, FDelayedOnResize: Boolean;
-    FIsFirstOnShow, FIsFirstOnActivate: Boolean;
+    FIsFirstOnShow, FIsFirstOnActivate, FIsFirstRestore: Boolean;
     function GetClientHandle: HWND;
     function GetEffectiveShowInTaskBar: TShowInTaskBar;
     function GetMonitor: TMonitor;
--- lcl/include/customform.inc.63838
+++ lcl/include/customform.inc
@@ -692,42 +692,45 @@
     Exit;
   { update restored bounds }
   if WindowState = wsNormal then
-    begin
-      if FDelayedOnChangeBounds then
-        begin
-          FRestoredLeft := Left;
-          FRestoredTop := Top;
-        end;
-      if FDelayedOnResize then
-        begin
-          FRestoredWidth := Width;
-          FRestoredHeight := Height;
-        end;
-    end;
+  begin
+    if FDelayedOnChangeBounds then
+    begin
+      FRestoredLeft := Left;
+      FRestoredTop := Top;
+    end;
+    if FDelayedOnResize then
+    begin
+      FRestoredWidth := Width;
+      FRestoredHeight := Height;
+    end;
+  end;
   { call onShow() or onActivate() for the first time, after first OnResize()
     and OnChangeBounds() }
   if FDelayedOnResize and FDelayedOnChangeBounds then
-    begin
-      if FIsFirstOnShow then
-        begin
-          FIsFirstOnShow := False;
-          DoShow;
-        end;
-      if FIsFirstOnActivate then
-        begin
-          FIsFirstOnActivate := False;
-          if FActive then
-            Activate;
-        end;
-    end;
-  { delayed onResize() }
-  if FDelayedOnResize then
-    inherited DoOnResize;
-  { delayed onChangeBounds() }
-  if FDelayedOnResize or FDelayedOnChangeBounds then
-    inherited DoOnChangeBounds;
-  FDelayedOnChangeBounds := False;
-  FDelayedOnResize := False;
+  begin
+    if FIsFirstOnShow then
+    begin
+      FIsFirstOnShow := False;
+      DoShow;
+    end;
+    if FIsFirstOnActivate then
+    begin
+      FIsFirstOnActivate := False;
+      if FActive then
+        Activate;
+    end;
+  end;
+  if not (FIsFirstOnShow or FIsFirstOnActivate) then
+  begin
+    { delayed onResize() }
+    if FDelayedOnResize then
+      inherited DoOnResize;
+    { delayed onChangeBounds() }
+    if FDelayedOnResize or FDelayedOnChangeBounds then
+      inherited DoOnChangeBounds;
+    FDelayedOnChangeBounds := False;
+    FDelayedOnResize := False;
+  end;
 end;
 
 procedure TCustomForm.WMWindowPosChanged(var Message: TLMWindowPosChanged);
@@ -1001,6 +1004,7 @@
   if FIsFirstOnShow and (WindowState in [wsMaximized, wsFullScreen]) then
     Exit;
   FIsFirstOnShow := False;
+  FIsFirstRestore := WindowState in [wsMaximized, wsFullScreen];
   if Assigned(FOnShow) then FOnShow(Self);
 end;
 
@@ -1139,17 +1143,15 @@
   if Showing and not (csDesigning in ComponentState) then
   begin
     OldState := FWindowState;
-    FWindowState := State;
     if OldState <> State then
     begin
+      WindowState := State;
       if (State = wsMinimized) and (Application.MainForm = Self) and
          (WidgetSet.GetLCLCapability(lcNeedMininimizeAppWithMainForm) <> LCL_CAPABILITY_NO) then
         Application.Minimize;
       if (OldState = wsMinimized) and (Application.MainForm = Self) and
          (WidgetSet.GetLCLCapability(lcNeedMininimizeAppWithMainForm) <> LCL_CAPABILITY_NO) then
         Application.Restore;
-      if Assigned(OnWindowStateChange) then
-        OnWindowStateChange(Self);
     end;
   end;
 end;
@@ -1830,7 +1832,19 @@
     FWindowState := Value;
     //DebugLn(['TCustomForm.SetWindowState ',DbgSName(Self),' ',ord(FWindowState),' csDesigning=',csDesigning in ComponentState,' Showing=',Showing]);
     if (not (csDesigning in ComponentState)) and Showing then
+    begin
       ShowWindow(Handle, ShowCommands[Value]);
+      if not (FIsFirstOnShow or FIsFirstOnActivate) then
+      begin
+        if FIsFirstRestore then
+        begin
+          MoveToDefaultPosition;
+          FIsFirstRestore := False;
+        end;
+        if Assigned(OnWindowStateChange) then
+          OnWindowStateChange(Self);
+      end;
+    end;
   end;
 end;
 
@@ -2030,6 +2044,7 @@
   FDelayedOnResize := False;
   FIsFirstOnShow := True;
   FIsFirstOnActivate := True;
+  FIsFirstRestore := False;
   GlobalNameSpace.BeginWrite;
   try
     CreateNew(AOwner, 1); // this calls BeginFormUpdate, which is ended in AfterConstruction
--- lcl/interfaces/win32/win32callback.inc.63838
+++ lcl/interfaces/win32/win32callback.inc
@@ -15,6 +15,7 @@
 {$ENDIF}
 type
   TWinControlAccess = class(TWinControl);
+  TApplicationAccess = class(TApplication);
 {*************************************************************}
 {            callback routines                                }
 {*************************************************************}
@@ -2054,6 +2055,8 @@
       begin
         CheckSynchronize;
         TWin32Widgetset(Widgetset).CheckPipeEvents;
+        if Assigned(Application) then
+          TApplicationAccess(Application).ProcessAsyncCallQueue;
       end;
     WM_ENTERIDLE: Application.Idle(False);
     WM_ACTIVATE:  SetLMessageAndParams(LM_ACTIVATE);
--- lcl/interfaces/gtk2/gtk2callback.inc.63838
+++ lcl/interfaces/gtk2/gtk2callback.inc
@@ -1121,6 +1121,8 @@
           {$ENDIF}
           SizeMsg.SizeType := SIZE_MINIMIZED;
         end
+        else if (GDK_WINDOW_STATE_FULLSCREEN and state^.new_window_state)>0 then
+          SizeMsg.SizeType := SIZE_FULLSCREEN
         else if (GDK_WINDOW_STATE_MAXIMIZED and state^.new_window_state)>0 then
         begin
           // it can be both maximized + iconified and just loose iconified state

Juha Manninen

2020-08-29 14:46

developer   ~0125202

Last edited: 2020-08-29 15:24

View 3 revisions

I applied the latest patch in r63842. Thanks.
Note: I split the unindent formatting part to another commit, r63843. Easier to figure out what happens.

@BrunoK, you mean r62745 did not change the behavior? It was just a random pick. Please write here only about revisions that are relevant for this issue. We already have many revisions and many reports to deal with. No need to complicate it more.
You can bisect guilty revisions. I recommend "git bisect" command for that.

BrunoK

2020-08-30 13:01

reporter   ~0125216

Juha Manninen 2020-08-29 16:46

I only meant : At r62745 these two files seem to be OK . Issue 0037467 does not show with this version. NOTHING MORE.

I will test with at r63842 and report how it looks.

jamie philbrook

2020-09-10 23:14

reporter   ~0125470

ITs strange because I just tested a variety of versions here, not the trunk and they all work correctly ?

So why all of this ? I too have Delphi 3 and they work exactly like D3 so like I said why ?

CudaText man_

2020-09-11 13:40

reporter   ~0125482

This patch broke the Restore action
https://bugs.freepascal.org/view.php?id=37732

Juha Manninen

2020-09-11 18:05

developer   ~0125488

r63842 caused a regression. I had to revert it.

BrunoK

2020-09-12 14:15

reporter   ~0125511

I reverted to
   \lcl\include\Forms.pp at r62745,
   \lcl\include\customform.inc at r62892.
Attached patch on 63882

Reason : r63882 makes 0037467 still broken : Form Resize Not Firing Correctly and its attached demos.

I have not critics about improving excessive messaging but think we should try, using Joeny Ang's ideas, to design a safer way to rework the code.
We should consider what is Widget set dependent and what is pure /lcl and /lcl/include stuff.

There has been recently quite a few issues in the bugtracker that I could not reproduce in Win10 2004 / 10.0.19041.508 (example > 0037706: [Regression] IDE extremely slow when adding a new control to a heavily populated form < ) so it is a bit difficult to understand what is going on.
revert_form_200912.patch (7,604 bytes)   
Index: lcl/forms.pp
===================================================================
--- lcl/forms.pp	(revision 63882)
+++ lcl/forms.pp	(working copy)
@@ -491,7 +491,7 @@
     FShowInTaskbar: TShowInTaskbar;
     FWindowState: TWindowState;
     FDelayedEventCtr: Integer;
-    FDelayedOnChangeBounds, FDelayedOnResize: Boolean;
+    FDelayedWMMove, FDelayedWMSize: Boolean;
     FIsFirstOnShow, FIsFirstOnActivate: Boolean;
     function GetClientHandle: HWND;
     function GetEffectiveShowInTaskBar: TShowInTaskBar;
@@ -535,6 +535,7 @@
     procedure WMActivate(var Message : TLMActivate); message LM_ACTIVATE;
     procedure WMCloseQuery(var message: TLMessage); message LM_CLOSEQUERY;
     procedure WMHelp(var Message: TLMHelp); message LM_HELP;
+    procedure WMMove(var Message: TLMMove); message LM_MOVE;
     procedure WMShowWindow(var message: TLMShowWindow); message LM_SHOWWINDOW;
     procedure WMSize(var message: TLMSize); message LM_Size;
     procedure WMWindowPosChanged(var Message: TLMWindowPosChanged); message LM_WINDOWPOSCHANGED;
@@ -580,8 +581,6 @@
     procedure Resizing(State: TWindowState); override;
     procedure CalculatePreferredSize(var PreferredWidth,
            PreferredHeight: integer; WithThemeSpace: Boolean); override;
-    procedure DoOnResize; override;
-    procedure DoOnChangeBounds; override;
     procedure SetZOrder(Topmost: Boolean); override;
     procedure SetParent(NewParent: TWinControl); override;
     procedure MoveToDefaultPosition; virtual;
@@ -1192,7 +1191,7 @@
     property Forms[Index: Integer]: TForm read GetForms;
     property DataModuleCount: Integer read GetDataModuleCount;
     property DataModules[Index: Integer]: TDataModule read GetDataModules;
-    
+
     property HintFont: TFont read GetHintFont write SetHintFont;
     property IconFont: TFont read GetIconFont write SetIconFont;
     property MenuFont: TFont read GetMenuFont write SetMenuFont;
Index: lcl/include/customform.inc
===================================================================
--- lcl/include/customform.inc	(revision 63882)
+++ lcl/include/customform.inc	(working copy)
@@ -240,7 +240,7 @@
     if Assigned(OldCancelControl) then
       OldCancelControl.UpdateRolesForForm;
     // notify new control
-    if Assigned(FCancelControl) then 
+    if Assigned(FCancelControl) then
     begin
       FreeNotification(FCancelControl);
       FCancelControl.UpdateRolesForForm;
@@ -604,7 +604,7 @@
  ------------------------------------------------------------------------------}
 procedure TCustomForm.Activate;
 begin
-  if FIsFirstOnActivate and (WindowState in [wsMaximized, wsFullScreen]) then
+  if FIsFirstOnActivate and (WindowState = wsMaximized) then
     Exit;
   FIsFirstOnActivate := False;
   if Assigned(FOnActivate) then FOnActivate(Self);
@@ -662,23 +662,22 @@
   end;
 
   inherited WMSize(Message);
-end;
 
-procedure TCustomForm.DoOnResize;
-begin
   if not (csDestroying in ComponentState) then
   begin
-    FDelayedOnResize := True;
+    FDelayedWMSize := True;
     Inc(FDelayedEventCtr);
     Application.QueueAsyncCall(@DelayedEvent, 0);
   end;
 end;
 
-procedure TCustomForm.DoOnChangeBounds;
+procedure TCustomForm.WMMove(var Message: TLMMove);
 begin
+  inherited WMMove(Message);
+
   if not (csDestroying in ComponentState) then
   begin
-    FDelayedOnChangeBounds := True;
+    FDelayedWMMove := True;
     Inc(FDelayedEventCtr);
     Application.QueueAsyncCall(@DelayedEvent, 0);
   end;
@@ -692,42 +691,37 @@
     Exit;
   { update restored bounds }
   if WindowState = wsNormal then
-  begin
-    if FDelayedOnChangeBounds then
     begin
-      FRestoredLeft := Left;
-      FRestoredTop := Top;
+      if FDelayedWMMove then
+        begin
+          FRestoredLeft := Left;
+          FRestoredTop := Top;
+        end;
+      if FDelayedWMSize then
+        begin
+          FRestoredWidth := Width;
+          FRestoredHeight := Height;
+          DoOnResize;     // delayed onResize()
+        end;
+      DoOnChangeBounds;     // delayed onChangeBounds()
     end;
-    if FDelayedOnResize then
+  { call onShow() or onActivate() for the first time, after first WMSize }
+  if FDelayedWMSize then
     begin
-      FRestoredWidth := Width;
-      FRestoredHeight := Height;
+      if FIsFirstOnShow then
+        begin
+          FIsFirstOnShow := False;
+          DoShow;
+        end;
+      if FIsFirstOnActivate then
+        begin
+          FIsFirstOnActivate := False;
+          if FActive then
+            Activate;
+        end;
     end;
-  end;
-  { call onShow() or onActivate() for the first time,
-    after first OnResize() and OnChangeBounds() }
-  if FDelayedOnResize or FDelayedOnChangeBounds then
-  begin
-    if FIsFirstOnShow then
-    begin
-      FIsFirstOnShow := False;
-      DoShow;
-    end;
-    if FIsFirstOnActivate then
-    begin
-      FIsFirstOnActivate := False;
-      if FActive then
-        Activate;
-    end;
-  end;
-  { delayed onResize() }
-  if FDelayedOnResize then
-    inherited DoOnResize;
-  { delayed onChangeBounds() }
-  if FDelayedOnResize or FDelayedOnChangeBounds then
-    inherited DoOnChangeBounds;
-  FDelayedOnChangeBounds := False;
-  FDelayedOnResize := False;
+  FDelayedWMMove := False;
+  FDelayedWMSize := False;
 end;
 
 procedure TCustomForm.WMWindowPosChanged(var Message: TLMWindowPosChanged);
@@ -998,7 +992,7 @@
  ------------------------------------------------------------------------------}
 procedure TCustomForm.DoShow;
 begin
-  if FIsFirstOnShow and (WindowState in [wsMaximized, wsFullScreen]) then
+  if FIsFirstOnShow and (WindowState = wsMaximized) then
     Exit;
   FIsFirstOnShow := False;
   if Assigned(FOnShow) then FOnShow(Self);
@@ -1625,7 +1619,7 @@
     end;
     Result := False;
   end;
-  
+
 begin
   // don't execute action while designing or when form is not visible
   if (csDesigning in ComponentState) or not Visible then
@@ -1634,9 +1628,9 @@
   // assume it gets handled somewhere
   Result := True;
   if Assigned(ActiveControl) and ActiveControl.ExecuteAction(ExeAction) then Exit;
-    
+
   if ExecuteAction(ExeAction) then Exit;
-    
+
   if DoExecuteActionInChildControls(Self, ExeAction) then Exit;
 
   // not handled anywhere, return false
@@ -1748,7 +1742,7 @@
     Value := nil;
 
   FMenu := Value;
-  if FMenu <> nil then 
+  if FMenu <> nil then
   begin
     FMenu.FreeNotification(Self);
     FMenu.Parent := Self;
@@ -1790,7 +1784,7 @@
   AdaptBorderIcons := not (csLoading in ComponentState) and
                       (BorderIcons = DefaultBorderIcons[FFormBorderStyle]);
   FFormBorderStyle := NewStyle;
-  
+
   if not (csDesigning in ComponentState) then
   begin
     // if Form had default border icons before change, it should keep the default
@@ -1939,7 +1933,7 @@
 begin
   if AValue = FAllowDropFiles then Exit;
   FAllowDropFiles := AValue;
-  
+
   if HandleAllocated and not (csDesigning in ComponentState) then
     TWSCustomFormClass(WidgetSetClass).SetAllowDropFiles(Self, AValue);
 end;
@@ -2026,8 +2020,8 @@
 constructor TCustomForm.Create(AOwner: TComponent);
 begin
   FDelayedEventCtr := 0;
-  FDelayedOnChangeBounds := False;
-  FDelayedOnResize := False;
+  FDelayedWMMove := False;
+  FDelayedWMSize := False;
   FIsFirstOnShow := True;
   FIsFirstOnActivate := True;
   GlobalNameSpace.BeginWrite;
@@ -2661,7 +2655,7 @@
 procedure TCustomForm.IntfHelp(AComponent: TComponent);
 begin
   if csDesigning in ComponentState then exit;
-  
+
   if AComponent is TControl then begin
     TControl(AComponent).ShowHelp;
   end else begin
revert_form_200912.patch (7,604 bytes)   

Juha Manninen

2020-09-13 10:12

developer   ~0125523

@BrunoK, did you test issue 0037732 with your patch?
I will look at it later.

BrunoK

2020-09-13 11:03

reporter   ~0125525

@Juha Manninen
> did you test issue 0037732 with your patch?

Tested 0037732 on Win 10 64 / PFC 3.0.4 i386/win32. Works for me.
My patch is a revert to a reasonable stable state so we can reassert what and where something should be done.

Note that 0037467 does show (in debug mode) some duplicates OnResize but the problem demo is maybe not optimally written.

Joeny Ang

2020-09-14 10:02

reporter   ~0125536

Hi all :)

Updated the last patch:
- Issue 0037732 was caused by the attempt to fix onWindowStateChange() not triggering when setting WindowState via code. This is now fixed.
- Fixed code to honor Position property on first restore when form was designed maximized.
- Tweaked DelayedEvent() for QT5 sometimes triggering onChangeBounds() twice on first show.

Patched against r63882
tform-wrong-bounds-and-restored-bounds-part4-fix.patch (5,616 bytes)   
--- lcl/forms.pp.63882
+++ lcl/forms.pp
@@ -493,6 +493,7 @@
     FDelayedEventCtr: Integer;
     FDelayedOnChangeBounds, FDelayedOnResize: Boolean;
     FIsFirstOnShow, FIsFirstOnActivate: Boolean;
+    FIsFirstRestore, FWindowStateChanged: Boolean;
     function GetClientHandle: HWND;
     function GetEffectiveShowInTaskBar: TShowInTaskBar;
     function GetMonitor: TMonitor;
--- lcl/include/customform.inc.63882
+++ lcl/include/customform.inc
@@ -706,7 +706,7 @@
   end;
   { call onShow() or onActivate() for the first time,
     after first OnResize() and OnChangeBounds() }
-  if FDelayedOnResize or FDelayedOnChangeBounds then
+  if FDelayedOnResize and FDelayedOnChangeBounds and FActive then
   begin
     if FIsFirstOnShow then
     begin
@@ -716,18 +716,20 @@
     if FIsFirstOnActivate then
     begin
       FIsFirstOnActivate := False;
-      if FActive then
-        Activate;
-    end;
-  end;
-  { delayed onResize() }
-  if FDelayedOnResize then
-    inherited DoOnResize;
-  { delayed onChangeBounds() }
-  if FDelayedOnResize or FDelayedOnChangeBounds then
-    inherited DoOnChangeBounds;
-  FDelayedOnChangeBounds := False;
-  FDelayedOnResize := False;
+      Activate;
+    end;
+  end;
+  if not (FIsFirstOnShow or FIsFirstOnActivate) then
+  begin
+    { delayed onResize() }
+    if FDelayedOnResize then
+      inherited DoOnResize;
+    { delayed onChangeBounds() }
+    if FDelayedOnResize or FDelayedOnChangeBounds then
+      inherited DoOnChangeBounds;
+    FDelayedOnChangeBounds := False;
+    FDelayedOnResize := False;
+  end;
 end;
 
 procedure TCustomForm.WMWindowPosChanged(var Message: TLMWindowPosChanged);
@@ -1001,6 +1003,7 @@
   if FIsFirstOnShow and (WindowState in [wsMaximized, wsFullScreen]) then
     Exit;
   FIsFirstOnShow := False;
+  FIsFirstRestore := WindowState in [wsMaximized, wsFullScreen];
   if Assigned(FOnShow) then FOnShow(Self);
 end;
 
@@ -1148,8 +1151,28 @@
       if (OldState = wsMinimized) and (Application.MainForm = Self) and
          (WidgetSet.GetLCLCapability(lcNeedMininimizeAppWithMainForm) <> LCL_CAPABILITY_NO) then
         Application.Restore;
-      if Assigned(OnWindowStateChange) then
-        OnWindowStateChange(Self);
+    end;
+
+    if (OldState <> State) or FWindowStateChanged then
+    begin
+      { honor Position property on first restore when form was designed maximized }
+      if not (FIsFirstOnShow or FIsFirstOnActivate) then
+      begin
+        if FIsFirstRestore and (State = wsNormal) then
+        begin
+          { Need to check width/height before calling MoveToDefaultPosition.
+            QT5 triggers Resizing() twice: one for position change, and
+            another for size change. This check should not affect other
+            widgetsets. }
+          if (Width <> RestoredWidth) or (Height <> RestoredHeight) then
+            Exit;
+          MoveToDefaultPosition;
+          FIsFirstRestore := False;
+        end;
+        if Assigned(OnWindowStateChange) then
+          OnWindowStateChange(Self);
+      end;
+      FWindowStateChanged := False;
     end;
   end;
 end;
@@ -1830,7 +1853,10 @@
     FWindowState := Value;
     //DebugLn(['TCustomForm.SetWindowState ',DbgSName(Self),' ',ord(FWindowState),' csDesigning=',csDesigning in ComponentState,' Showing=',Showing]);
     if (not (csDesigning in ComponentState)) and Showing then
+    begin
+      FWindowStateChanged := True;
       ShowWindow(Handle, ShowCommands[Value]);
+    end;
   end;
 end;
 
@@ -2030,6 +2056,8 @@
   FDelayedOnResize := False;
   FIsFirstOnShow := True;
   FIsFirstOnActivate := True;
+  FIsFirstRestore := False;
+  FWindowStateChanged := False;
   GlobalNameSpace.BeginWrite;
   try
     CreateNew(AOwner, 1); // this calls BeginFormUpdate, which is ended in AfterConstruction
--- lcl/interfaces/gtk2/gtk2callback.inc.63882
+++ lcl/interfaces/gtk2/gtk2callback.inc
@@ -1121,6 +1121,8 @@
           {$ENDIF}
           SizeMsg.SizeType := SIZE_MINIMIZED;
         end
+        else if (GDK_WINDOW_STATE_FULLSCREEN and state^.new_window_state)>0 then
+          SizeMsg.SizeType := SIZE_FULLSCREEN
         else if (GDK_WINDOW_STATE_MAXIMIZED and state^.new_window_state)>0 then
         begin
           // it can be both maximized + iconified and just loose iconified state
@@ -1133,7 +1135,8 @@
         // don't bother the LCL if nothing changed
         case SizeMsg.SizeType of
           SIZE_RESTORED: if TheForm.WindowState=wsNormal then exit;
-          SIZE_MINIMIZED: if TheForm.WindowState=wsMinimized then exit;
+          // Need to send LM_SIZE message to LCL if wsMinimized to trigger onWindowStateChange()
+          //SIZE_MINIMIZED: if TheForm.WindowState=wsMinimized then exit;
           SIZE_MAXIMIZED: if TheForm.WindowState=wsMaximized then exit;
           SIZE_FULLSCREEN: if TheForm.WindowState=wsFullScreen then exit;
         end;
--- lcl/interfaces/win32/win32callback.inc.63882
+++ lcl/interfaces/win32/win32callback.inc
@@ -15,6 +15,7 @@
 {$ENDIF}
 type
   TWinControlAccess = class(TWinControl);
+  TApplicationAccess = class(TApplication);
 {*************************************************************}
 {            callback routines                                }
 {*************************************************************}
@@ -2054,6 +2055,8 @@
       begin
         CheckSynchronize;
         TWin32Widgetset(Widgetset).CheckPipeEvents;
+        if Assigned(Application) then
+          TApplicationAccess(Application).ProcessAsyncCallQueue;
       end;
     WM_ENTERIDLE: Application.Idle(False);
     WM_ACTIVATE:  SetLMessageAndParams(LM_ACTIVATE);

Juha Manninen

2020-09-18 09:49

developer   ~0125609

Sorry for the delay. I had other stuff going on.
In r63888 I applied the latest patch from Joeny Ang with one important change.
In customform.inc the patch has :
+ if FDelayedOnResize and FDelayedOnChangeBounds and FActive then
which reverts my fix for issue 0037647 (after lots of debugging :) .
I changed it to :
+ if (FDelayedOnResize or FDelayedOnChangeBounds) and FActive then
Everybody please test and verify it works.
If it works then I would like to resolve this issue ASAP. It is getting long and difficult to follow with all the revisions involved. New related issues can have their own reports.

CudaText man_

2020-09-18 11:14

reporter   ~0125613

Thanks for the fix

josh

2020-09-18 19:49

reporter   ~0125631

Hi
Just tested Rev 63888.
it has fixed that the form.resize is being fired.

form.OnResize appears now not to be re-entrent, if you run the attached test with rev 63888, and compare against rev 63556, you will see some big differneces in the time my re-size take to complete.

The attached project; now keeps track of how many time the on-reize is called when it is allready in the re-size code.


rev 63556 (resizing the form via the corner tab, slowly upto full screen and back again)
Use processmessages re-entrant called 48 times, max time in code 94ms average time in resize code 20ms
use ProcessMessages and Begin/End Update Re-entrent 88, max 94 avg 13
Use Begin/Endupdate Re-entrant 0, Max 16, Avg 3.
use None Re-Entrant 0, Max 31, AVg 5

rev 63888
Use processmessages re-entrant called 0, max time in code 344ms average time in resize code 141ms
use ProcessMessages and Begin/End Update Re-entrent 0, max 234 avg 37
Use Begin/Endupdate Re-entrant 0, Max 62, Avg 12.
use None Re-Entrant 0, Max 281, Avg 38

I get similar figures when testing on WIn/32/64 and linux Mint. Not yet tried on MacOS yet

Can anyone else confirm similar impacts?

You may think that its a strange test; but a few of my applications use the resize event to calculate what is displayed on the screen and in what location; based on the size of active form etc. These forms do not use anchor docking because visual components can be moved, made visible etc based on screen size and user preferences. Also they keeps a track if it in a re-entrant state so that any cpu/gpu intensive scaling etc can be ignored; until its not in a re-entrent state; it might complicated; but it does keep the application extrememly responsive and smooth. THought I would explain the issue.
Also the current way it works is not very compatible with Delphi
Form_events_3.zip (102,037 bytes)

Juha Manninen

2020-09-18 21:21

developer   ~0125632

@josh, please open a new report for your speed issue. It can have this issue, 0037467 and maybe 0037706 as related issues.
Resolving this one.

josh

2020-09-18 21:35

reporter   ~0125634

@Juha Manninen
I will add this to my previous report. 0037688

I still make the issue of the form.onresize not be re-entrant? was this introduced in this report?

Andrey Zubarev

2020-09-30 19:47

reporter   ~0126009

r63888 break my app((
Unfortunately, I can't give a minimal example. I use the progress bar to display the progress of long actions. To update it when the program is busy, I use application.ProcessMessages. After r63888 my app began hang, if at time of application.ProcessMessages execution there are controls created but not yet shown

Michl

2021-04-12 21:13

developer   ~0130330

Last edited: 2021-04-12 21:20

View 2 revisions

The revision 63888 breaks the event handling of form with parent. I add a minimal example.

Windows 7, Lazarus 2.1.0 r63888 FPC 3.0.4 i386-win32-win32/win64
TestEmbeddedForm.zip (2,468 bytes)

Juha Manninen

2021-04-13 16:36

developer   ~0130357

I reverted r63888 in r64986. Does it cause problems elsewhere? How to fix them?

Joeny Ang

2021-04-14 03:01

reporter   ~0130364

onchangebounds-not-called-if-form-has-a-parent-fix.patch (432 bytes)   
--- lcl/include/customform.inc
+++ lcl/include/customform.inc
@@ -1003,6 +1003,9 @@
   if FIsFirstOnShow and (WindowState in [wsMaximized, wsFullScreen]) then
     Exit;
   FIsFirstOnShow := False;
+  // WMActivate is not being called if form has a parent
+  if Parent <> nil then
+    FIsFirstOnActivate := False;
   FIsFirstRestore := WindowState in [wsMaximized, wsFullScreen];
   if Assigned(FOnShow) then FOnShow(Self);
 end;

Joeny Ang

2021-04-14 03:14

reporter   ~0130365

The patch will fix the onChangeBounds() not triggered issue for the meantime.

As reported by Josh, I have tested that the fixes for this bug report has indeed affected various event handlers' re-entrancy.
And there is this report by Andre involving hangs when using Application.ProcessMessages. I'll add this to my todo list.

Juha Manninen

2021-04-14 18:22

developer   ~0130379

Last edited: 2021-04-14 18:30

View 2 revisions

$ patch -p0 < ~/patch/onchangebounds-not-called-if-form-has-a-parent-fix.patch
patching file lcl/include/customform.inc
Hunk 0000001 FAILED at 1003.

> And there is this report by Andre involving hangs when using Application.ProcessMessages. I'll add this to my todo list.
Which one is that?

Joeny Ang

2021-04-15 01:12

reporter   ~0130385

Hi Juha, the patch was made against revisions before r64986, before you reverted r63888.

Re Andrey's report, see 5-6 posts prior to this one.

Mattias Gaertner

2021-04-17 09:20

manager   ~0130423

Last edited: 2021-04-17 09:38

View 2 revisions

I fixed the IDE crash of r64986:

TApplication.HandleException: EInvalidOperation
[TCustomForm.SetFocus] AnchorDockSite4:TAnchorDockHostSite Can not focus
  Stack trace:
  $000000000048773C RAISECANNOTFOCUS, line 381 of include/customform.inc
  $0000000000487618 SETFOCUS, line 396 of include/customform.inc
  $0000000000486999 FOCUSCONTROL, line 160 of include/customform.inc
  $00000000005C3C54 SETFOCUS, line 5681 of include/wincontrol.inc
  $0000000000F758C3 SETFOCUS, line 859 of groupededit.pp
  $0000000000B3945F FORMSHOW, line 234 of componentlist.pas
  $0000000000489458 DOSHOW, line 1004 of include/customform.inc
  $000000000048847F DELAYEDEVENT, line 714 of include/customform.inc
  $000000000049A572 PROCESSASYNCCALLQUEUE, line 1069 of include/application.inc
  $000000000049830B PROCESSMESSAGES, line 422 of include/application.inc
  $0000000000D960FC UPDATECLOSEBUTTONS, line 924 of searchresultview.pp
  $0000000000D93A39 FORM1CREATE, line 363 of searchresultview.pp
  $000000000048907D DOCREATE, line 921 of include/customform.inc
  $0000000000486559 AFTERCONSTRUCTION, line 77 of include/customform.inc
  $00000000004912A0 CREATE, line 3170 of include/customform.inc
  $0000000000A6810B CREATEFORM, line 2255 of idewindowintf.pas
  $00000000004E2E20 DOSHOWSEARCHRESULTSVIEW, line 9239 of main.pp

Juha Manninen

2021-05-11 06:54

developer   ~0130819

I resolve this one. Please create a new report for remaining issues if there is any.

Joeny Ang

2021-05-28 03:06

reporter   ~0131058

Hi, combined the last 2 patches. Fixes event handling of form with parent problem (as reported by Michl) and issue 0038922 (David).
last-2-patches-combined.patch (5,710 bytes)   
--- lcl/forms.pp
+++ lcl/forms.pp
@@ -501,6 +501,7 @@
     FDelayedEventCtr: Integer;
     FDelayedOnChangeBounds, FDelayedOnResize: Boolean;
     FIsFirstOnShow, FIsFirstOnActivate: Boolean;
+    FIsFirstRestore, FWindowStateChanged: Boolean;
     function GetClientHandle: HWND;
     function GetEffectiveShowInTaskBar: TShowInTaskBar;
     function GetMonitor: TMonitor;
--- lcl/include/customform.inc
+++ lcl/include/customform.inc
@@ -706,7 +706,7 @@
   end;
   { call onShow() or onActivate() for the first time,
     after first OnResize() and OnChangeBounds() }
-  if FDelayedOnResize or FDelayedOnChangeBounds then
+  if FDelayedOnResize and FDelayedOnChangeBounds and FActive then
   begin
     if FIsFirstOnShow then
     begin
@@ -716,18 +716,20 @@
     if FIsFirstOnActivate then
     begin
       FIsFirstOnActivate := False;
-      if FActive then
-        Activate;
-    end;
-  end;
-  { delayed onResize() }
-  if FDelayedOnResize then
-    inherited DoOnResize;
-  { delayed onChangeBounds() }
-  if FDelayedOnResize or FDelayedOnChangeBounds then
-    inherited DoOnChangeBounds;
-  FDelayedOnChangeBounds := False;
-  FDelayedOnResize := False;
+      Activate;
+    end;
+  end;
+  if not (FIsFirstOnShow or FIsFirstOnActivate) then
+  begin
+    { delayed onResize() }
+    if FDelayedOnResize then
+      inherited DoOnResize;
+    { delayed onChangeBounds() }
+    if FDelayedOnResize or FDelayedOnChangeBounds then
+      inherited DoOnChangeBounds;
+    FDelayedOnChangeBounds := False;
+    FDelayedOnResize := False;
+  end;
 end;
 
 procedure TCustomForm.WMWindowPosChanged(var Message: TLMWindowPosChanged);
@@ -1001,6 +1003,10 @@
   if FIsFirstOnShow and (WindowState in [wsMaximized, wsFullScreen]) then
     Exit;
   FIsFirstOnShow := False;
+  // WMActivate is not being called if form has a parent
+  if Parent <> nil then
+    FIsFirstOnActivate := False;
+  FIsFirstRestore := WindowState in [wsMaximized, wsFullScreen];
   if Assigned(FOnShow) then FOnShow(Self);
 end;
 
@@ -1148,8 +1154,28 @@
       if (OldState = wsMinimized) and (Application.MainForm = Self) and
          (WidgetSet.GetLCLCapability(lcNeedMininimizeAppWithMainForm) <> LCL_CAPABILITY_NO) then
         Application.Restore;
-      if Assigned(OnWindowStateChange) then
-        OnWindowStateChange(Self);
+    end;
+
+    if (OldState <> State) or FWindowStateChanged then
+    begin
+      { honor Position property on first restore when form was designed maximized }
+      if not (FIsFirstOnShow or FIsFirstOnActivate) then
+      begin
+        if FIsFirstRestore and (State = wsNormal) then
+        begin
+          { Need to check width/height before calling MoveToDefaultPosition.
+            QT5 triggers Resizing() twice: one for position change, and
+            another for size change. This check should not affect other
+            widgetsets. }
+          if (Width <> RestoredWidth) or (Height <> RestoredHeight) then
+            Exit;
+          MoveToDefaultPosition;
+          FIsFirstRestore := False;
+        end;
+        if Assigned(OnWindowStateChange) then
+          OnWindowStateChange(Self);
+      end;
+      FWindowStateChanged := False;
     end;
   end;
 end;
@@ -1830,7 +1856,10 @@
     FWindowState := Value;
     //DebugLn(['TCustomForm.SetWindowState ',DbgSName(Self),' ',ord(FWindowState),' csDesigning=',csDesigning in ComponentState,' Showing=',Showing]);
     if (not (csDesigning in ComponentState)) and Showing then
+    begin
+      FWindowStateChanged := True;
       ShowWindow(Handle, ShowCommands[Value]);
+    end;
   end;
 end;
 
@@ -2030,6 +2059,8 @@
   FDelayedOnResize := False;
   FIsFirstOnShow := True;
   FIsFirstOnActivate := True;
+  FIsFirstRestore := False;
+  FWindowStateChanged := False;
   GlobalNameSpace.BeginWrite;
   try
     CreateNew(AOwner, 1); // this calls BeginFormUpdate, which is ended in AfterConstruction
--- lcl/interfaces/gtk2/gtk2callback.inc
+++ lcl/interfaces/gtk2/gtk2callback.inc
@@ -1162,6 +1162,8 @@
           {$ENDIF}
           SizeMsg.SizeType := SIZE_MINIMIZED;
         end
+        else if (GDK_WINDOW_STATE_FULLSCREEN and state^.new_window_state)>0 then
+          SizeMsg.SizeType := SIZE_FULLSCREEN
         else if (GDK_WINDOW_STATE_MAXIMIZED and state^.new_window_state)>0 then
         begin
           // it can be both maximized + iconified and just loose iconified state
@@ -1174,7 +1176,8 @@
         // don't bother the LCL if nothing changed
         case SizeMsg.SizeType of
           SIZE_RESTORED: if TheForm.WindowState=wsNormal then exit;
-          SIZE_MINIMIZED: if TheForm.WindowState=wsMinimized then exit;
+          // Need to send LM_SIZE message to LCL if wsMinimized to trigger onWindowStateChange()
+          //SIZE_MINIMIZED: if TheForm.WindowState=wsMinimized then exit;
           SIZE_MAXIMIZED: if TheForm.WindowState=wsMaximized then exit;
           SIZE_FULLSCREEN: if TheForm.WindowState=wsFullScreen then exit;
         end;
--- lcl/interfaces/win32/win32callback.inc
+++ lcl/interfaces/win32/win32callback.inc
@@ -15,6 +15,7 @@
 {$ENDIF}
 type
   TWinControlAccess = class(TWinControl);
+  TApplicationAccess = class(TApplication);
 {*************************************************************}
 {            callback routines                                }
 {*************************************************************}
@@ -2055,6 +2056,8 @@
       begin
         CheckSynchronize;
         TWin32Widgetset(Widgetset).CheckPipeEvents;
+        if Assigned(Application) then
+          TApplicationAccess(Application).ProcessAsyncCallQueue;
       end;
     WM_ENTERIDLE: Application.Idle(False);
     WM_ACTIVATE:  SetLMessageAndParams(LM_ACTIVATE);

last-2-patches-combined.patch (5,710 bytes)   

David

2021-05-28 06:50

reporter   ~0131062

OK, nice work Joeny !

I confirm it fixes the problem in 0038922. I have further tested it it in Win10 Hi DPI, Windows 10 normal DPI, Windows Vista (yep, I still have a Vister box to test on).

I have also superficially tested on Linux, GTK2 and Qt5

Please consider !

Michl

2021-06-13 19:04

developer   ~0131293

Last edited: 2021-06-13 19:22

View 2 revisions

The revision 65213 breaks the DragNDrop of TChromium in a bigger app of mine. Not sure, if I can create a minimal example.

The showstopper is (and IMHO it is generally a bad idea to call Application.ProcessAsyncCallQueue anywhere in message handling):

--- lcl/interfaces/win32/win32callback.inc (revision 65212)
+++ lcl/interfaces/win32/win32callback.inc (revision 65213)
@@ -2054,6 +2055,8 @@
       begin
         CheckSynchronize;
         TWin32Widgetset(Widgetset).CheckPipeEvents;
+ if Assigned(Application) then
+ TApplicationAccess(Application).ProcessAsyncCallQueue;
       end;
     WM_ENTERIDLE: Application.Idle(False);
     WM_ACTIVATE: SetLMessageAndParams(LM_ACTIVATE);

If I comment this two lines, the app is running fine.

jamie philbrook

2021-06-14 01:08

reporter   ~0131296

IT has always been a BAD idea to process any messages before returning back from one..

A lot of things can go wrong and do, as many are seeing here.
 
case and point, drag & drop: The process involves SetCapture to lock the mouse input to the starting window and as the drag is being performed the system is sending
a WM_SETCURSOR msg as the mouse drags over other windows and those windows must perform in proper order..

 When the drop is complete the starting window must then call the ReleaseCapture because it is expected to receive the WM_MOUSEUP message.

 The point is, performing hack tricks because you just can't figure out how to do it correctly with events is a very bad idea and giving the example I just laid out is a perfect example of how calling a message que to process a message can cause messages to get out of order and thus even cause some controls to seem like they are not receiving any mouse input from that point on, because the ReleaseCapture process was interrupted.

 My opinion is this, keep that kind of hack code in the user's side application and leave it out of the libs/LCL so that everyone else needs not to suffer with hackery weekend slop
. This is why custom messages were invented to post to the que so that users code could have a chance to clean up something where it left off.

Thank you for allowing me to express my opinion, as little as it matters.

Juha Manninen

2021-06-14 07:55

developer   ~0131301

Ok, reverted. I resolve this issue again. Joeny Ang, please don't reopen. Attach possible patches in related 0038922 instead.

Issue History

Date Modified Username Field Change
2019-10-02 07:55 Joeny Ang New Issue
2019-10-02 07:55 Joeny Ang File Added: tform-wrong-bounds-and-restored-bounds.patch
2019-10-02 07:55 Joeny Ang File Added: tform-restoredbounds.zip
2019-10-03 01:52 Joeny Ang File Added: tform-wrong-bounds-and-restored-bounds-v2.patch
2019-10-03 01:52 Joeny Ang Note Added: 0118263
2019-10-03 12:33 Juha Manninen Relationship added related to 0027894
2019-10-03 12:33 Juha Manninen Relationship added related to 0022771
2019-10-03 12:33 Juha Manninen Relationship added related to 0027375
2019-10-03 12:34 Juha Manninen Relationship added related to 0021119
2019-10-03 12:42 Juha Manninen Relationship added related to 0032631
2019-10-03 12:44 Juha Manninen Relationship added related to 0008576
2019-10-03 12:45 Juha Manninen Description Updated View Revisions
2019-10-03 12:45 Juha Manninen LazTarget => -
2019-10-03 12:45 Juha Manninen Widgetset GTK 2, Win32/Win64 => GTK 2, Win32/Win64
2019-10-03 14:01 Juha Manninen Note Added: 0118278
2019-10-05 20:26 Juha Manninen Assigned To => Juha Manninen
2019-10-05 20:26 Juha Manninen Status new => assigned
2019-10-05 20:28 Juha Manninen Note Added: 0118358
2019-10-07 06:00 Joeny Ang File Added: delayedevent-wait-for-wmsize-before-onshow-onactivate.patch
2019-10-07 06:00 Joeny Ang Note Added: 0118386
2019-10-24 22:37 Juha Manninen Note Added: 0118793
2019-10-24 22:38 Juha Manninen Fixed in Revision => r61997, r62113
2019-10-24 22:38 Juha Manninen Widgetset GTK 2, Win32/Win64 => GTK 2, Win32/Win64
2020-03-16 18:29 Juha Manninen Status assigned => resolved
2020-03-16 18:29 Juha Manninen Resolution open => fixed
2020-03-16 18:29 Juha Manninen Widgetset GTK 2, Win32/Win64 => GTK 2, Win32/Win64
2020-03-16 18:29 Juha Manninen Note Added: 0121628
2020-04-05 16:44 Juha Manninen Relationship added related to 0036877
2020-05-24 13:56 Michl Note Added: 0123037
2020-05-24 13:59 Michl Note Edited: 0123037 View Revisions
2020-05-24 15:33 Michl Note Edited: 0123037 View Revisions
2020-05-25 13:16 Michl Fixed in Revision r61997, r62113 => r61997, r62113, r63218
2020-05-25 13:16 Michl Widgetset GTK 2, Win32/Win64 => GTK 2, Win32/Win64
2020-05-25 13:17 Michl Note Added: 0123059
2020-05-25 19:04 Michl Status resolved => assigned
2020-05-25 19:04 Michl Resolution fixed => reopened
2020-05-25 19:05 Michl Note Added: 0123062
2020-05-25 19:05 Michl File Added: TestChangeBoundsEvent.zip
2020-05-25 19:07 Michl Note Edited: 0123062 View Revisions
2020-05-25 19:08 Michl Note Edited: 0123062 View Revisions
2020-07-15 08:26 Joeny Ang Note Added: 0124030
2020-07-15 08:26 Joeny Ang File Added: fix-duplicate-onresize-onchangebounds.patch
2020-07-15 08:27 Joeny Ang Note Edited: 0124030 View Revisions
2020-07-16 23:01 Juha Manninen Note Added: 0124110
2020-07-16 23:02 Juha Manninen Fixed in Revision r61997, r62113, r63218 => r61997, r62113, r63218, r63577
2020-07-16 23:02 Juha Manninen Widgetset GTK 2, Win32/Win64 => GTK 2, Win32/Win64
2020-07-22 17:35 Juha Manninen Status assigned => resolved
2020-07-22 17:35 Juha Manninen Widgetset GTK 2, Win32/Win64 => GTK 2, Win32/Win64
2020-07-22 17:35 Juha Manninen Note Added: 0124233
2020-08-26 09:10 Juha Manninen Relationship added related to 0037467
2020-08-26 09:12 Juha Manninen Status resolved => assigned
2020-08-26 09:12 Juha Manninen Resolution reopened => open
2020-08-26 09:12 Juha Manninen Note Added: 0125129
2020-08-26 09:13 Juha Manninen Note Edited: 0125129 View Revisions
2020-08-26 13:44 BrunoK Note Added: 0125133
2020-08-26 19:45 Juha Manninen Note Added: 0125143
2020-08-27 09:24 Paweł Dmitruk Note Added: 0125150
2020-08-27 09:54 BrunoK Note Added: 0125151
2020-08-27 09:54 BrunoK File Added: tform-restoredbounds-unit2.zip
2020-08-27 10:09 BrunoK Note Edited: 0125151 View Revisions
2020-08-28 01:17 Joeny Ang Note Added: 0125163
2020-08-28 01:17 Joeny Ang File Added: tform-wrong-bounds-and-restored-bounds-part4.patch
2020-08-28 01:17 Joeny Ang File Added: tform-restoredbounds2-2020.08.28.zip
2020-08-28 09:16 Joeny Ang Note Added: 0125170
2020-08-28 09:16 Joeny Ang File Added: tform-wrong-bounds-and-restored-bounds-part4v2.patch
2020-08-29 13:46 Juha Manninen Relationship added related to 0037647
2020-08-29 14:46 Juha Manninen Note Added: 0125202
2020-08-29 14:47 Juha Manninen Fixed in Revision r61997, r62113, r63218, r63577 => r61997, r62113, r63218, r63577, r63842
2020-08-29 14:47 Juha Manninen Widgetset GTK 2, Win32/Win64 => GTK 2, Win32/Win64
2020-08-29 14:51 Juha Manninen Note Edited: 0125202 View Revisions
2020-08-29 15:24 Juha Manninen Note Edited: 0125202 View Revisions
2020-08-30 13:01 BrunoK Note Added: 0125216
2020-09-02 15:39 Juha Manninen Status assigned => resolved
2020-09-02 15:39 Juha Manninen Resolution open => fixed
2020-09-02 15:39 Juha Manninen Widgetset GTK 2, Win32/Win64 => GTK 2, Win32/Win64
2020-09-10 21:49 wp Relationship added related to 0037732
2020-09-10 23:14 jamie philbrook Note Added: 0125470
2020-09-11 13:40 CudaText man_ Note Added: 0125482
2020-09-11 18:05 Juha Manninen Status resolved => assigned
2020-09-11 18:05 Juha Manninen Resolution fixed => open
2020-09-11 18:05 Juha Manninen Note Added: 0125488
2020-09-12 14:15 BrunoK Note Added: 0125511
2020-09-12 14:15 BrunoK File Added: revert_form_200912.patch
2020-09-13 10:12 Juha Manninen Note Added: 0125523
2020-09-13 11:03 BrunoK Note Added: 0125525
2020-09-14 10:02 Joeny Ang Note Added: 0125536
2020-09-14 10:02 Joeny Ang File Added: tform-wrong-bounds-and-restored-bounds-part4-fix.patch
2020-09-18 09:49 Juha Manninen Note Added: 0125609
2020-09-18 09:50 Juha Manninen Status assigned => feedback
2020-09-18 11:14 CudaText man_ Note Added: 0125613
2020-09-18 19:49 josh Note Added: 0125631
2020-09-18 19:49 josh File Added: Form_events_3.zip
2020-09-18 21:21 Juha Manninen Status feedback => resolved
2020-09-18 21:21 Juha Manninen Resolution open => fixed
2020-09-18 21:21 Juha Manninen Fixed in Revision r61997, r62113, r63218, r63577, r63842 => r61997, r62113, r63218, r63577, r63842, r63888
2020-09-18 21:21 Juha Manninen Widgetset GTK 2, Win32/Win64 => GTK 2, Win32/Win64
2020-09-18 21:21 Juha Manninen Note Added: 0125632
2020-09-18 21:35 josh Note Added: 0125634
2020-09-19 08:56 Juha Manninen Relationship added related to 0037688
2020-09-30 19:47 Andrey Zubarev Note Added: 0126009
2020-10-29 10:53 Juha Manninen Relationship added related to 0038004
2020-12-26 15:52 Michl Relationship added related to 0038261
2021-04-12 21:13 Michl Status resolved => assigned
2021-04-12 21:13 Michl Resolution fixed => open
2021-04-12 21:13 Michl Note Added: 0130330
2021-04-12 21:13 Michl File Added: TestEmbeddedForm.zip
2021-04-12 21:20 Michl Note Edited: 0130330 View Revisions
2021-04-13 16:36 Juha Manninen Status assigned => feedback
2021-04-13 16:36 Juha Manninen Note Added: 0130357
2021-04-13 16:37 Juha Manninen Fixed in Revision r61997, r62113, r63218, r63577, r63842, r63888 => r61997, r62113, r63218, r63577, r63842, r63888, r64986
2021-04-13 16:37 Juha Manninen Widgetset GTK 2, Win32/Win64 => GTK 2, Win32/Win64
2021-04-14 03:01 Joeny Ang Note Added: 0130364
2021-04-14 03:01 Joeny Ang File Added: onchangebounds-not-called-if-form-has-a-parent-fix.patch
2021-04-14 03:01 Joeny Ang Status feedback => assigned
2021-04-14 03:14 Joeny Ang Note Added: 0130365
2021-04-14 18:22 Juha Manninen Note Added: 0130379
2021-04-14 18:30 Juha Manninen Note Edited: 0130379 View Revisions
2021-04-15 01:12 Joeny Ang Note Added: 0130385
2021-04-17 09:20 Mattias Gaertner Note Added: 0130423
2021-04-17 09:38 Mattias Gaertner Note Edited: 0130423 View Revisions
2021-05-11 06:54 Juha Manninen Status assigned => resolved
2021-05-11 06:54 Juha Manninen Resolution open => fixed
2021-05-11 06:54 Juha Manninen Widgetset GTK 2, Win32/Win64 => GTK 2, Win32/Win64
2021-05-11 06:54 Juha Manninen Note Added: 0130819
2021-05-22 11:49 Juha Manninen Relationship added related to 0038922
2021-05-28 03:06 Joeny Ang Note Added: 0131058
2021-05-28 03:06 Joeny Ang File Added: last-2-patches-combined.patch
2021-05-28 06:50 David Note Added: 0131062
2021-05-28 13:03 Maxim Ganetsky Status resolved => assigned
2021-05-28 13:03 Maxim Ganetsky Resolution fixed => open
2021-06-11 06:19 Juha Manninen Status assigned => resolved
2021-06-11 06:19 Juha Manninen Resolution open => fixed
2021-06-11 06:19 Juha Manninen Fixed in Revision r61997, r62113, r63218, r63577, r63842, r63888, r64986 => r61997, r62113, r63218, r63577, r63842, r63888, r64986, r65213
2021-06-11 06:19 Juha Manninen Widgetset GTK 2, Win32/Win64 => GTK 2, Win32/Win64
2021-06-13 19:04 Michl Status resolved => assigned
2021-06-13 19:04 Michl Resolution fixed => open
2021-06-13 19:04 Michl Note Added: 0131293
2021-06-13 19:22 Michl Note Edited: 0131293 View Revisions
2021-06-14 01:08 jamie philbrook Note Added: 0131296
2021-06-14 07:55 Juha Manninen Note Added: 0131301
2021-06-14 07:56 Juha Manninen Fixed in Revision r61997, r62113, r63218, r63577, r63842, r63888, r64986, r65213 => r61997, r62113, r63218, r63577, r63842, r63888, r64986, r65213, r65228
2021-06-14 07:56 Juha Manninen Widgetset GTK 2, Win32/Win64 => GTK 2, Win32/Win64
2021-06-14 07:56 Juha Manninen Status assigned => resolved
2021-06-14 07:56 Juha Manninen Resolution open => fixed
2021-06-14 07:56 Juha Manninen Widgetset GTK 2, Win32/Win64 => GTK 2, Win32/Win64