////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001-2023 Alexey Kuryakin daqgroup@mail.ru under MIT license //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// This file is part of the CRW-DAQ project by DaqGroup - component CRWLIB.   //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Purpose:                                                                   //
// Application Form related routines.                                         //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// History:                                                                   //
// 20230810 - Created by A.K. from _stdapp                                    //
////////////////////////////////////////////////////////////////////////////////

unit _crw_appforms; //  Application Form routines.

{$I _crw_sysdef}

{$IFDEF FPC}{$mode Delphi}{$ENDIF}{$H+}

interface

uses
_crw_sharemem, // NB: THIS UNIT MUST BE FIRST !!!
{$IFDEF UNIX} cthreads, dl, {$ENDIF}
{$IFDEF WINDOWS} windows, {$ENDIF}
sysutils, classes, forms, controls, lmessages,
_crw_alloc;

 {
 *******************************************
 Basic class for Forms with Master property.
 *******************************************
 Master property is pointer to static variable, wich points to object.
 TMasterForm clears this variable to nil in destructor, so we may be sure
 that this variable always have correct value.
 Example:
  x:=TMasterObject.Create;
  x.Master:=x;
  ...
  x.Free;          // automatically set variable x to nil
  ...
  if x.Ok then ... // check object valid
 }
type
 PMasterForm = ^TMasterForm;
 TMasterForm = class(TForm)
 private
  myRef     : Integer;
  myMaster  : PMasterForm;
  function    GetOk:Boolean;
  function    GetRef:Integer;
 protected
  function    CheckOk:Boolean; virtual;
  function    GetMaster:PMasterForm;
  procedure   SetMaster(aMaster:PMasterForm);
  procedure   ClearMaster;
  procedure   WndProc(var Message: TLMessage); override;
 public
  constructor Create(AOwner: TComponent); override;
  procedure   AfterConstruction; override;
  procedure   BeforeDestruction; override;
 public
  property    Ok     : Boolean      read GetOk;
  property    Ref    : Integer      read GetRef;
  property    Master : PMasterForm  read GetMaster write SetMaster;
 end;

procedure Kill(var TheObject:TMasterForm); overload;

const
 TMasterFormWndProcCallCount : Int64 = 0;

implementation

 {
 **************************
 TMasterForm implementation
 **************************
 }
const
 BornKillBalance : SizeInt = 0;

constructor TMasterForm.Create(AOwner: TComponent);
begin
 inherited Create(AOwner);
 myMaster:=nil;
end;

procedure TMasterForm.AfterConstruction;
begin
 inherited AfterConstruction;
 if UsesBornKillLog
 then BornKillLog(Format('BORN %-25s %8.8x %8.8x %d',
                  [ClassName, Integer(Self), GetCurrentThreadID, BornKillBalance]));
 LockedInc(BornKillBalance);
 myRef:=ObjectRegistry.InitRef(Self);
end;

procedure TMasterForm.BeforeDestruction;
begin
 ObjectRegistry.FreeRef(myRef);
 LockedDec(BornKillBalance);
 if UsesBornKillLog
 then BornKillLog(Format('KILL %-25s %8.8x %8.8x %d',
                  [ClassName, Integer(Self), GetCurrentThreadID, BornKillBalance]));
 if (FormStyle=fsMDIChild) and (WindowState=wsMaximized) then WindowState:=wsMinimized;
 ClearMaster;
 inherited BeforeDestruction;
end;

function TMasterForm.GetOk:Boolean;
begin
 if Assigned(Self) then Result:=CheckOk else Result:=false;
end;

function TMasterForm.GetRef:Integer;
begin
 if Assigned(Self) then Result:=myRef else Result:=0;
end;

function TMasterForm.CheckOk:Boolean;
begin
 Result:=true;
end;

function TMasterForm.GetMaster:PMasterForm;
begin
 if Assigned(Self) then Result:=myMaster else Result:=nil;
end;

procedure TMasterForm.SetMaster(aMaster:PMasterForm);
begin
 if Assigned(Self) then
 try
  if (aMaster<>nil) and (aMaster^=Self) then myMaster:=aMaster else myMaster:=nil;
 except
  on E:Exception do BugReport(E,Self,'SetMaster');
 end;
end;

procedure TMasterForm.ClearMaster;
begin
 if Assigned(Self) then
 try
  if Assigned(myMaster) then if myMaster^=Self then myMaster^:=nil;
  myMaster:=nil;
 except
  on E:Exception do BugReport(E,Self,'ClearMaster');
 end;
end;

procedure TMasterForm.WndProc(var Message: TLMessage);
begin
 inherited WndProc(Message);
 inc(TMasterFormWndProcCallCount);
end;

procedure Kill(var TheObject:TMasterForm); overload;
begin
 try
  FreeAndNil(TheObject);
 except
  on E:Exception do BugReport(E,nil,'Kill');
 end;
end;

///////////////////////////////////////
// Unit initialization and finalization
///////////////////////////////////////

procedure Init_crw_appforms;
begin
end;

procedure Free_crw_appforms;
begin
 ResourceLeakageLog(Format('%-60s = %d',['Balance of TMasterForm.Born/Kill', BornKillBalance]));
end;

initialization

 Init_crw_appforms;

finalization

 Free_crw_appforms;

end.

//////////////
// END OF FILE
//////////////

