View Issue Details

IDProjectCategoryView StatusLast Update
0035622LazarusWidgetsetpublic2019-10-15 04:46
ReporterZoë Peterson Assigned ToDmitry Boyarintsev  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionreopened 
Product Version2.0.3 (SVN) 
Summary0035622: TCustomForm.WindowState is always wsNormal
DescriptionThis patch fixes an issue where TForm's WindowState property was always wsNormal regardless of the actual state of the window. There were two different bugs involved:

1) When resizing a form, TLCLCommonCallback's boundsDidChange called lclWindowState on the TCocoaWindowContent object, rather than TCocoaWindow. Adding an override to call the window's lclWindowState fixes that. It's possible this could be simplified by just moving the TCocoaWindow.lclWindowState code down to TCocoaWindowContent.

2) Minimizing/restoring the window does not change its bounds, so the boundsDidChange method never runs. Fixed by adding a call to LCLSendSizeMsg when the window receives the windowDidMiniaturize and windowDidDeminiaturize messages.This could instead be redirected through the existing TLCLWindowCallback.resize and TLCLCommonCallback.boundsDidChange functions, but TLCLCommonCallback.boundsDidChange would need a way to check whether the TCustomForm Target's WindowState had changed since neither Resized nor ClientResized are true in this case.
Steps To ReproduceExtract/compile the attached sample project and run it from the command line or put breakpoints in the FormResize and FormWindowStateChange events. It will write out when those functions are called and what the form's WindowState property is at that point. Prior to the patch, WindowState is always wsNormal, and neither FormResize nor FormWindowStateChange are called when minimize or de-minimizing a window.
TagsNo tags attached.
Fixed in Revision61287, 62060
LazTarget-
WidgetsetCocoa
Attached Files

Activities

Zoë Peterson

2019-05-22 22:22

reporter  

cocoa-windowstate.patch (3,307 bytes)   
diff --git a/lcl/interfaces/cocoa/cocoawindows.pas b/lcl/interfaces/cocoa/cocoawindows.pas
index 7e5a571faf..873c667f65 100644
--- a/lcl/interfaces/cocoa/cocoawindows.pas
+++ b/lcl/interfaces/cocoa/cocoawindows.pas
@@ -67,6 +67,7 @@ type
     procedure Close;
     procedure Resize;
     procedure Move;
+    procedure WindowStateChanged;
 
     function GetEnabled: Boolean;
     procedure SetEnabled(AValue: Boolean);
@@ -136,6 +137,8 @@ type
     procedure windowDidResignKey(notification: NSNotification); message 'windowDidResignKey:';
     procedure windowDidResize(notification: NSNotification); message 'windowDidResize:';
     procedure windowDidMove(notification: NSNotification); message 'windowDidMove:';
+    procedure windowDidMiniaturize(notification: NSNotification); message 'windowDidMiniaturize:';
+    procedure windowDidDeminiaturize(notification: NSNotification); message 'windowDidDeminiaturize:';
     // fullscreen notifications are only reported for 10.7 fullscreen
     procedure windowWillEnterFullScreen(notification: NSNotification); message 'windowWillEnterFullScreen:';
     procedure windowDidEnterFullScreen(notification: NSNotification); message 'windowDidEnterFullScreen:';
@@ -209,6 +212,7 @@ type
     function lclOwnWindow: NSWindow; message 'lclOwnWindow';
     procedure lclSetFrame(const r: TRect); override;
     function lclFrame: TRect; override;
+    function lclWindowState: Integer; override;
     procedure viewDidMoveToSuperview; override;
     procedure viewDidMoveToWindow; override;
     procedure viewWillMoveToWindow(newWindow: CocoaAll.NSWindow); override;
@@ -444,6 +448,14 @@ begin
   end;
 end;
 
+function TCocoaWindowContent.lclWindowState: Integer;
+begin
+  if isembedded then
+    Result := inherited lclWindowState
+  else
+    Result := window.lclWindowState;
+end;
+
 procedure TCocoaWindowContent.viewDidMoveToSuperview;
 begin
   inherited viewDidMoveToSuperview;
@@ -780,6 +792,18 @@ begin
     callback.Move;
 end;
 
+procedure TCocoaWindow.windowDidMiniaturize(notification: NSNotification);
+begin
+  if Assigned(callback) then
+    callback.WindowStateChanged;
+end;
+
+procedure TCocoaWindow.windowDidDeminiaturize(notification: NSNotification);
+begin
+  if Assigned(callback) then
+    callback.WindowStateChanged;
+end;
+
 procedure TCocoaWindow.windowWillEnterFullScreen(notification: NSNotification);
 begin
   if not isInFullScreen then isInFullScreen := true;
diff --git a/lcl/interfaces/cocoa/cocoawsforms.pas b/lcl/interfaces/cocoa/cocoawsforms.pas
index efc6804e19..4bcad61aea 100644
--- a/lcl/interfaces/cocoa/cocoawsforms.pas
+++ b/lcl/interfaces/cocoa/cocoawsforms.pas
@@ -51,6 +51,7 @@ type
     procedure Close; virtual;
     procedure Resize; virtual;
     procedure Move; virtual;
+    procedure WindowStateChanged; virtual;
 
     function GetEnabled: Boolean; virtual;
     procedure SetEnabled(AValue: Boolean); virtual;
@@ -428,6 +429,15 @@ begin
   boundsDidChange(Owner);
 end;
 
+procedure TLCLWindowCallback.WindowStateChanged;
+var
+  Bounds: TRect;
+begin
+  Bounds := HandleFrame.lclFrame;
+  LCLSendSizeMsg(Target, Bounds.Right - Bounds.Left, Bounds.Bottom - Bounds.Top,
+    Owner.lclWindowState, True);
+end;
+
 function TLCLWindowCallback.GetEnabled: Boolean;
 begin
   Result := Owner.lclIsEnabled;
cocoa-windowstate.patch (3,307 bytes)   
cocoa-windowstate.zip (131,042 bytes)

Dmitry Boyarintsev

2019-05-24 14:59

developer   ~0116393

the patch has been applied. Thank you.
please test and close if ok

Zoë Peterson

2019-08-29 20:56

reporter   ~0117868

The sample project is broken again. WindowStateChange is only called when minimizing/restoring, and not when maximizing or entering full screen, and when maximizing the WindowState is always wsNormal. I assume it was broken when the window content view was split in two, but haven't had a chance to look into it yet.

Zoë Peterson

2019-08-30 21:08

reporter   ~0117881

I was able to fix it by removing lclWindowState from TCocoaWindowContent and adding this version to TCocoaWindowContentDocument:

function TCocoaWindowContentDocument.lclWindowState: Integer;
begin
  if window.lclGetCallback = wincallback then // not embedded
    Result := window.lclWindowState
  else
    Result := inherited lclWindowState
end;


That doesn't seem very elegant, but the document doesn't currently have a reference to the content object outside "superview.superview", so it can't access that object's "isembedded" and adding a local field that duplicated it seemed like overkill.

Zoë Peterson

2019-08-30 21:13

reporter   ~0117882

Oops, removing the TCocoaWindowContent version breaks the minimize/restore loop. You also need to change TLCLWindowCallback.WindowStateChanged to access Owner.lclWindowState instead of HandleFrame.lclWindowState.

Zoë Peterson

2019-08-30 21:23

reporter  

cocoa-windowstate-2.patch (2,053 bytes)   
--- a/lcl/interfaces/cocoa/cocoawindows.pas
+++ b/lcl/interfaces/cocoa/cocoawindows.pas
@@ -195,6 +195,7 @@ type
   public
     overlay: NSView;
     wincallback: IWindowCallback;
+    function lclWindowState: Integer; override;
     procedure didAddSubview(aview: NSView); override;
     procedure setNeedsDisplay_(aflag: LCLObjCBoolean); override;
     procedure setNeedsDisplayInRect(arect: NSRect); override;
@@ -220,7 +221,6 @@ type
     function lclOwnWindow: NSWindow; message 'lclOwnWindow';
     procedure lclSetFrame(const r: TRect); override;
     function lclFrame: TRect; override;
-    function lclWindowState: Integer; override;
     procedure viewDidMoveToSuperview; override;
     procedure viewDidMoveToWindow; override;
     procedure viewWillMoveToWindow(newWindow: CocoaAll.NSWindow); override;
@@ -267,6 +267,14 @@ end;
 
 { TCocoaWindowContent }
 
+function TCocoaWindowContentDocument.lclWindowState: Integer;
+begin
+  if window.lclGetCallback = wincallback then // not embedded
+    Result := window.lclWindowState
+  else
+    Result := inherited lclWindowState
+end;
+
 procedure TCocoaWindowContentDocument.didAddSubview(aview: NSView);
 const
   mustHaveSizing = (NSViewWidthSizable or NSViewHeightSizable);
@@ -444,14 +452,6 @@ begin
   end;
 end;
 
-function TCocoaWindowContent.lclWindowState: Integer;
-begin
-  if isembedded then
-    Result := inherited lclWindowState
-  else
-    Result := window.lclWindowState;
-end;
-
 procedure TCocoaWindowContent.viewDidMoveToSuperview;
 begin
   inherited viewDidMoveToSuperview;
diff --git a/lcl/interfaces/cocoa/cocoawsforms.pas b/lcl/interfaces/cocoa/cocoawsforms.pas
index 1cee222dfb..c52a5b994e 100644
--- a/lcl/interfaces/cocoa/cocoawsforms.pas
+++ b/lcl/interfaces/cocoa/cocoawsforms.pas
@@ -457,7 +457,7 @@ var
 begin
   Bounds := HandleFrame.lclFrame;
   LCLSendSizeMsg(Target, Bounds.Right - Bounds.Left, Bounds.Bottom - Bounds.Top,
-    HandleFrame.lclWindowState, True);
+    Owner.lclWindowState, True);
 end;
 
 function TLCLWindowCallback.GetEnabled: Boolean;
cocoa-windowstate-2.patch (2,053 bytes)   

Zoë Peterson

2019-08-30 21:23

reporter   ~0117883

New patch

Dmitry Boyarintsev

2019-10-15 04:46

developer   ~0118608

thanks applied!

Issue History

Date Modified Username Field Change
2019-05-22 22:22 Zoë Peterson New Issue
2019-05-22 22:22 Zoë Peterson File Added: cocoa-windowstate.patch
2019-05-22 22:22 Zoë Peterson File Added: cocoa-windowstate.zip
2019-05-24 14:59 Dmitry Boyarintsev Assigned To => Dmitry Boyarintsev
2019-05-24 14:59 Dmitry Boyarintsev Status new => resolved
2019-05-24 14:59 Dmitry Boyarintsev Resolution open => fixed
2019-05-24 14:59 Dmitry Boyarintsev Fixed in Revision => 61287
2019-05-24 14:59 Dmitry Boyarintsev LazTarget => -
2019-05-24 14:59 Dmitry Boyarintsev Widgetset Cocoa => Cocoa
2019-05-24 14:59 Dmitry Boyarintsev Note Added: 0116393
2019-05-24 18:19 Zoë Peterson Status resolved => closed
2019-08-29 20:56 Zoë Peterson Status closed => assigned
2019-08-29 20:56 Zoë Peterson Resolution fixed => reopened
2019-08-29 20:56 Zoë Peterson Note Added: 0117868
2019-08-30 21:08 Zoë Peterson Note Added: 0117881
2019-08-30 21:13 Zoë Peterson Note Added: 0117882
2019-08-30 21:23 Zoë Peterson File Added: cocoa-windowstate-2.patch
2019-08-30 21:23 Zoë Peterson Note Added: 0117883
2019-10-15 04:46 Dmitry Boyarintsev Status assigned => resolved
2019-10-15 04:46 Dmitry Boyarintsev Fixed in Revision 61287 => 61287, 62060
2019-10-15 04:46 Dmitry Boyarintsev Widgetset Cocoa => Cocoa
2019-10-15 04:46 Dmitry Boyarintsev Note Added: 0118608