unit wWindow0;

{ Feel free to use this unit as you want.
  First developped by Bernard Gisin
  This unit uses object programming to simplify the developpment
  of programs.
----------------------------------}

// To tell FreePascal that the application is a Graphical User Interface
// i.e. is running in windows, not in text mode.
{$APPTYPE GUI}

INTERFACE
//"""""""

uses wMenus0, wStatusLine0, wWindowBase0, wGlobals2, windows;

type
  PWindow0 = ^TWindow0;
  TWindow0 = object(TWindowBase)
  //""""""""""""""""""""""""""""
//  hWin    : HWND;  // Handle on the window, got from TWindowBase
//  hParent : HWND;  // Handle on the parent, got from TWindowBase
//  poParent: PWindowBase0;  // Pointer on the parent, got from TWindowBase

  hWinClient : HWND;
  // handle on the Client Window of the main MDI window
  // It will be the parent of any MDI child window
  // object client window will come later.
  // It is  0  for non main MDI windows.

  strWinTitle : string[200];
  // title of the window, when it is created
  // Memorise the strWinTitlePrm parameter of the init constructor.

  nLeft, nTop, nWidth, nHeight : longint;
  // Position and size of the window when created

  nClientWidth, nClientHeight : int32;
  // Width and Height of the client part

  wSizeState : word;
  // State of the window size. Can be :
  // SIZE_RESTORED (default value),  SIZE_MINIMIZED, SIZE_MAXIMIZED

  hMenuWin      : HMenu;
  // Handle on the menu

  poMenu        : PMenu;
  // If this window has a menu and this menu has the info in the
  // Status line, then this member (=property) can memorise the
  // information about the menu.

  poStatusLine  : PStatusLine0;
  // If this window has a status line,
  // This member can point to it.

  dwStyle : word32;
  // Style of the window. = ws_OverlappedWindow by default.

  dwExStyle : word32;
  // Extra Style of the window. = 0 by default.

  pDataCreation : Pointer;
  // = NIL usually for normal windows
  // = pointer on a  TCREATESTRUCT  record to create MDI main window

  constructor Init(strWinTitlePrm:ShortString);
  // Call Init; at the beggining of a new Init constructor.
  // strWinTitlePrm = title of the window

  destructor  Done; virtual;
  // Call Done; at the end of a new destructor.

  procedure MenuCreate; virtual;
  // By default, does nothing.
  // Is overriden to create a menu in the window

  procedure WinCreate(strWinClass:ShortString); virtual;
  // creation of the window
  // Can be overriden, but not overriden usually
  // For the main window, it is automatically called in TApplication.Run
  // strWinClass = class name defining the window.
  // Put strWinClass = '' to use the one defined in the  Application object.
  // This is what is usually done.

  function GetTextWidthPix(strS:ShortString):word; virtual;
  // return the width in pixel of a text.
  // This depends on the Device Context of the window, this is why
  // it is not a general utility, but is a function of TWindow

  function GetObjectMenu:pointer; virtual;
  // Overridden to return a pointer on the menu.
  // with this manner, a unit can get a pointer on the menu
  // of this window, without  "uses"  of this unit.
  // uses wWindowBase0  is enough.

  function WMNotify(wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  // Handles the notification messages send from the controls
  // It is usually overriden, if used.

  function WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  // Handles the menu messages
  // It is usually overriden

  function WMCTLCOLOR(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  // Special case where controls colors can be defines by their parent.
  // The controls can define the colors directly through this call.
  // lPar = handle on the control who wants to be redrawn
  // wPar = Device context used to draw the control.

  function WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  // Handles the window messages
  // It is usually overriden

  procedure WMSizeMoveFirst(wMsg:UINT; wPar:WPARAM; lPar:LPARAM); virtual;
  // The Window has been resized or moved, must take car of its child windows,
  // such as the tool bar, and a  RichText  control taking the whole
  // client area surface of its parent.

  procedure WMNotifyFirst(wPar:WPARAM; lPar:LPARAM); virtual;
  // Handles the notification messages send from the controls
  // It is usually overriden, if used.
  // It is send before the  WindowProc  receive the WM_NOTIFY

  procedure WMCommandFirst(wPar:WPARAM; lPar:LPARAM); virtual;
  // Handles the menu messages
  // It is usually overriden
  // It is send before the  WindowProc  receives the WM_COMMAND

  function WindowProcFirst(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  // Handles messages for the library, before calling  WindowProc
  // It is usually not overriden

  end; // TWindow0 = object(TWindowBase)
  TWindow =  TWindow0;
  PWindow = ^TWindow;

procedure gglGetPointerObject(hWinPrm:HWND; var wType:word; var poWin:PWindowBase0);
//==================================================================================
// call the same procedure from the wWindowBase0.pp unit,
// just to avoid having to include  wWindowBase0  in the uses of main applic.

// Used in wApplication.pp
Function MainWindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; stdcall; export;
//==================================================================================================
// This is the message handle function, which calls the
// Window's  'WindowProc' function

const
  // Pointer on the main application window
  // a copy named  gglpoMainWindowCopy  has been defined in  wWindowBase0.pp
  // Units should includ  wWindowBase0.pp  instead of  wWindow0.pp if possible
  gglpoMainWindow : PWindow0 = NIL;

IMPLEMENTATION
//""""""""""""

uses wToolBar0, {wRichText0,} wControl0, wMessages2, wObjectCreatorLOW2, wDebug0;

var glnNotUsed : integer; // To avoid an error in the DevPascal 1.9 environment

procedure gglGetPointerObject(hWinPrm:HWND; var wType:word; var poWin:PWindowBase0);
//==================================================================================
begin
wWindowBase0.gglGetPointerObject(hWinPrm, wType, poWin);
end;  // gglGetPointerObject

Function MainWindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; stdcall; export;
//==================================================================================================
// This is the message handle function, which calls the
// Window  'WindowProc' function
var
  // corresponding object child window to the  hWindow  handle
  poWin       : PWindow0;
  wL, wH      : word;

Begin
if (gglpoMainWindow = NIL) then begin
   // This is not normal, the main window should exist when entering this procedure
   // Calls the default event handler
   MainWindowProc := DefWindowProc(hWindow, wMsg, wPar, lPar);
   exit;
   end;

if (gglpoMainWindow^.hWin = hWindow) then begin
   // Call the event handler of the main application window.
   MainWindowProc := gglpoMainWindow^.WindowProcFirst(hWindow, wMsg, wPar, lPar);
   exit;
   end;

// It is possible that the event handler of another window is wanted.

// Test if the signature is correct.
// This is a security, probably useless
wL:=GetWindowWord(hWindow,  0); //  LOWORD
wH:=GetWindowWord(hWindow,  2); //  HIWORD
if (MakeLong(wL, wH) = GGLCTE_SIGNATURE_WND_EXTRA) then begin
   wL:=GetWindowWord(hWindow,  4); //  LOWORD
   wH:=GetWindowWord(hWindow,  6); //  HIWORD
   if (MakeLong(wL, wH) = GGLCTE_SIGNATURE_WND_EXTRA) then begin
      // Type of the window.
//      wType:=GetWindowWord(hWindow,  8); not used.

      // Pointer on the corresponding object window.
      wL:=GetWindowWord(hWindow, 12); //  LOWORD
      wH:=GetWindowWord(hWindow, 14); //  HIWORD
      poWin:=PWindow0(MakeLong(wL, wH));

      // call the event handler of the corresponding window
      MainWindowProc := poWin^.WindowProcFirst(hWindow, wMsg, wPar, lPar);
      exit;
      end;
   end;

// Normally we should never arrive here.
// Call the default event handler
MainWindowProc := DefWindowProc(hWindow, wMsg, wPar, lPar);
End;  // MainWindowProc

//***************************************************
// TWindow0 = object(TWindowBase)
//***************************************************

constructor TWindow0.Init(strWinTitlePrm:ShortString);
//====================================================
begin
inherited Init(NIL); // NIL => has no object parent

hWinClient:=0;

wWindowType :=GGLCTE_A_WINDOW;

// Memorise the strWinTitlePrm parameter.
strWinTitle:=strWinTitlePrm;

// Default position and size of the window when created
nLeft   :=5;
nTop    :=5;
nWidth  :=500;
nHeight :=300;
nClientWidth :=450;
nClientHeight:=250;

// State of the window size.
wSizeState:=SIZE_RESTORED;

// by default, no menu
hMenuWin:=0;

poMenu       :=NIL;
poStatusLine :=NIL;

// Style of the window. = ws_OverlappedWindow by default.
dwStyle   :=ws_OverlappedWindow;
dwExStyle :=0;

// points to a  CREATESTRUCT  for MDI main windows.
pDataCreation :=NIL;

// The first created window is supposed to be the main window.
// Keep a gloval variable pointer on the main window.
if (gglpoMainWindow = NIL) then begin
   gglpoMainWindow:=@Self;
   wWindowType :=GGLCTE_MAIN_WINDOW;
   end;
end;  // TWindow0.Init

destructor TWindow0.Done;
//=======================
var nDiff : int32;
begin
// remove it from the list of child Windows of its parent.
if (poParent <> NIL) then poParent^.RemoveChildObjectWindow(@Self);
poParent:=NIL;

// Test if the menu have been created with the  new(...)  procedure
// and thus must be disposed, or if it's a member of the descendent
// of the TWindow0 object, and thus only its destructor Done must be called.
if (poMenu <> NIL) and
   (not IsBadWritePtr(poMenu, sizeOf(TMenu))) and
   (poMenu^.poOwner = @Self) then begin
   nDiff:=int32(poMenu) - int32(@Self);

   if (nDiff > 0) and (nDiff < SizeOf(Self)) then begin
      // The Menu is a member of the parent, do not dispose, but
      // call the destructor  Done.
      poMenu^.Done;
      end
   else begin
      // The menu has probably been created with new(...).
      // If not, it is a programming error.
      // Menus should either be memeber of their parents, or
      // better, have been created with the 'new(...)' procedure.
      dispose(poMenu, Done);
      end;
   end;
poMenu:=NIL;

// poStatusLine is disposed in the inherited method.

inherited Done;
// gglpoMainWindow:=NIL;  done in wApplication.Done
end;  // TWindow0.Done

procedure TWindow0.MenuCreate;
//============================
// By default, does nothing.
// Is overriden to create a menu in the window
var
  strS        : ShortString;
begin
// Test if a menu is defined in the message file, at line 10000
// If the information there says to create the menu, then it is
// created automatically, the final application has nothing to do.
strS:=GetMsg(10000);
if (UpCase(strS) <> 'AUTOCREATE') then exit;

// here, the menu is automatically created.
if (poMenu = NIL) then poMenu:=PMenu(gglpoObjCreate^.CreateMenu(@Self));
hMenuWin:=poMenu^.MenuMsgCreate(10000);
end;  // TWindow0.MenuCreate

procedure TWindow0.WinCreate(strWinClass:ShortString);
//====================================================
// Creates a new window.
// strWinClass = class name defining the window.
// Put strWinClass = '' to use the one defined in the  Application object.
// This is what is usually done.
// Can be overriden, but it is not usual.
Begin
// if (gglpoApplication = NIL) then begin hWin:=0; exit; end; // Error

// Add a menu if wanted.
MenuCreate;

// Usually  strWinClass=''.
if (strWinClass = '') then strWinClass:=gglstrClassWinName;

strWinClass:=strWinClass+#0;
strWinTitle:=strWinTitle+#0;
hWin := CreateWindowEx ( dwExStyle, @strWinClass[1], @strWinTitle[1],
                         dwStyle, nLeft, nTop, nWidth, nHeight,
                         hParent, hMenuWin, System.MainInstance, pDataCreation);

if (hWin = 0) then exit; // error, window could not be created. Why?

// store in the window structure, a signature characteristique of the library,
// an indication on the type of window object
// and a pointer on the corresponding window object.
// Thus from the object one get the handle through .hWin
// From the handle one get the pointer on the object through
// gglGetPointerObject(hWin:HWND; var wType:word; var poWin:PWindowBase);
// See wWindowBase.pp
SetWindowWord(hWin, 0, LOWORD(GGLCTE_SIGNATURE_WND_EXTRA));
SetWindowWord(hWin, 2, HIWORD(GGLCTE_SIGNATURE_WND_EXTRA));
SetWindowWord(hWin, 4, LOWORD(GGLCTE_SIGNATURE_WND_EXTRA));
SetWindowWord(hWin, 6, HIWORD(GGLCTE_SIGNATURE_WND_EXTRA));
SetWindowWord(hWin, 8, GGLCTE_MAIN_WINDOW);
SetWindowWord(hWin,10, 0);
SetWindowWord(hWin,12, LOWORD(Longint(@Self)));
SetWindowWord(hWin,14, HIWORD(Longint(@Self)));

// If the status line object has been created, then
// creates the status line window and add it to the window.
if (poStatusLine <> NIL) and
   (poStatusLine^.poParent = @Self) and (poStatusLine^.hWin = 0) then begin
   // if a status line is wanted, create it automatically
   poStatusLine^.StatusCreate;
   end;

// show the window in its last size state.
if (wSizeState = SIZE_MAXIMIZED) then ShowWindow(hWin, SW_MAXIMIZE)
else if (wSizeState <> SIZE_MINIMIZED) then ShowWindow(hWin, SW_SHOWNORMAL);

// UpdateWindow(hWin); // to send a WM_paint to the window. Useless I think
End;  // TWindow0.WinCreate

function TWindow0.GetTextWidthPix(strS:ShortString):word;
//=======================================================
// return the width in pixel of a text.
// This depends on the Device Context of the window, this is why
// it is not a general utility, but is a function of TWindow
var
  hDCWin      : HDC;
  rSize       : SIZE;
begin
hDCWin:=GetDC(hWin);

strS[length(strS)+1]:=#0;
GetTextExtentPoint32( hDCWin, @strS[1], length(strS), @rSize);

ReleaseDC(hWin, hDCWin);

// This is the width in pixel of the text in strS.
GetTextWidthPix:=rSize.cx;
end;  // TWindow0.GetTextWidthPix

function TWindow0.GetObjectMenu:pointer;
//==========================================
// Overridden to return a pointer on the menu.
begin
GetObjectMenu:=poMenu;
end;  // TWindow0.GetObjectMenu

function TWindow0.WMNotify(wPar:WPARAM; lPar:LPARAM):LRESULT;
//===========================================================
// Handles the notification messages send from control
// It is usually overriden, if used.
var
  prNH        : ^NMHDR; // info associated with the notification message
  poCtrl      : PControl;

begin
// Notification message information. From whom and what.
prNH:=Pointer(lPar);

// The problem is that the handle doesn't identify always the control.
// only controls that has been defined in the library.
poCtrl:=Pointer(GetWindowLong(prNH^.hwndFrom, GWL_USERDATA));

// If the pointer is valid and represent the same handle, then
// it is a pointer on the object corresponding to the control.
if (not IsBadReadPtr(poCtrl, sizeOf(TControl0))) then begin
//   DBW0(2048, DBNotifToStr(prNH^.Code) + ITS(poCtrl^.hWin) + ' = ' + ITS(prNH^.hwndFrom));
   if (poCtrl^.hWin = prNH^.hwndFrom) then begin
      // the control has been identified to be the one having the right handle
      // Calls the notification message to the control's notification message handler
      // poCtrl^.Code = notification message, as NM_XXX and EN_XXX and ...
      poCtrl^.CtrlNotifMessageHandle(prNH^.Code, lPar);
      end;
   end;

WMNotify := DefWindowProc(hWin, WM_NOTIFY, wPar, lPar);
end;  //TWindow0.WMNotify

function TWindow0.WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT;
//============================================================
// Handles the menu messages
var
  poCtrl      : PControl;
  wNoticode   : word;

begin
if (lPar <> 0) then begin
   // It is a notification message send from the child control to its parent.
   // send it back to the object control
   wNotiCode := HiWord(wPar);

   // this message is a notification code from the control.
   // lPar = handle of the control, get the pointer on the object.
   poCtrl:=Pointer(GetWindowLong(lPar, GWL_USERDATA));

   // If the pointer is valid and represent the same handle, then
   // it is a pointer on the object corresponding to the control.
   if (not IsBadReadPtr(poCtrl, sizeOf(TControl0))) then begin
//      DBW0(4096, DBNotifToStr(wNotiCode) + ITS(poCtrl^.hWin) + ' = ' + ITS(lPar));
      if (poCtrl^.hWin = lPar) then begin
         // The control has been identified to be the one having the right handle
         // Calls the notification message to the control's notification
         // message handler
         // poCtrl^.Code = notification message, as NM_XXX and EN_XXX and ...
         poCtrl^.CtrlNotifMessageHandle(wNotiCode, lPar);
         end;
      end;
   end;

if (lPar = 0) then begin
   // Here comes the standard menu messages handling.
   // The library will handle many messages automatically.
   WMCommand :=0;  // default value if message is handeled

   case LoWord(wPar) of
      // standard menu message to close the window.
      // If it is the main window, this will also quit the application.
      65500 : PostMessage( hWin,WM_Close,0,0);

      65501 : DBW0(0, '');  // just open the debugging window, if it's not already done.

      // This is a special menu command, which ask the control which generated
      // the menu, to show a popup help window
      65530 : if (gglpoActiveControl <> NIL) then
                 gglpoControlOwnerMenu^.ShowPopupWindowHelp;

      // This is a special menu command, which ask the control which generated
      // the menu, to show a dialog help.
      65531 : if (gglpoActiveControl <> NIL) then
                 gglpoControlOwnerMenu^.ShowDialogHelp;

      else WMCommand := DefWindowProc(hWin, WM_COMMAND, wPar, lPar);
      end; // case LoWord(wPar) of

   exit;
   end;  // if (lPar = 0) then begin

WMCommand := DefWindowProc(hWin, WM_COMMAND, wPar, lPar);
end;  // TWindow0.WMCommand

function TWindow0.WMCTLCOLOR(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT;
//======================================================================================
// Special case where controls colors can be defines by their parent.
// The controls can define the colors directly through this call.
// lPar = handle on the control who wants to be redrawn
// wPar = Device context used to draw the control.
var
  poCtrl      : PControl;
begin
if (lPar <> 0) then begin
   // this message is sended to the control, so that he can decide
   // the colors he will use to draw itself.

   // lPar = handle of the control, get the pointer on the object.
   poCtrl:=Pointer(GetWindowLong(lPar, GWL_USERDATA));

   // If the pointer is valid and represent the same handle, then
   // it is a pointer on the object corresponding to the control.
   if (not IsBadReadPtr(poCtrl, sizeOf(TControl0))) then begin
//      DBW0(4096, DBMsgToStr(wMsg) + ITS(poCtrl^.hWin) + ' = ' + ITS(lPar));
      if (poCtrl^.hWin = lPar) then begin
         // The control has been identified to be the one having the right handle
         // Calls the notification message to the control's notification
         // message handler
         // poCtrl^.Code = notification message, as NM_XXX and EN_XXX and ...

         // Security test.
         if (poCtrl^.wWindowType >= 200) then
            WMCTLCOLOR:=poCtrl^.CtrlWMCTLCOLOR(hWindow, wMsg, wPar, lPar)
         else WMCTLCOLOR:=0; // not a control

         exit;
         end;
      end;
   end;

WMCTLCOLOR := 0; // => used default message handler in WindowProc
end;  // TWindow0.WMCTLCOLOR

function TWindow0.WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT;
//======================================================================================
const
  strMemStatusLine : ShortString = '';
  // when entering the menu, memorised what was in the status line.
  // Must be const to hold its value when we quit and re-enter the procedure.
  // Could be a globale variable too
var
  wRep        : LRESULT; // = word32;

  // Information stored in the Hash table created with the menu
  prML        : PRMenuLine;
  wInfoL      : word32;  // not used here, but must be passed as a parameter

begin
{ if (wMsg <> WM_MouseMove)   and (wMsg <> WM_NCMouseMove) and
//   (wMsg <> WM_MENUSELECT )   and (wMsg <> WM_ENTERIDLE ) and
   (wMsg <> WM_SetCursor)   and (wMsg <> WM_NCHittest) and
//   (wMsg <> WM_SetFocus) and (wMsg <> WM_KillFocus) and
//   (wMsg <> WM_KEYDOWN) and (wMsg <> WM_KEYUP) and
   (wMsg <> WM_Move)        and (wMsg <> WM_NCActivate) then
   DBW0(32, DBMsgToStr(wMsg) + ITS(LoWord(wPar))
                             + ITS(HiWord(wPar)) + ITS(lPar)); }

// Default treatment of a message. Does nearly nothing
WindowProc:=0;  // default value

Case wMsg Of
   WM_Destroy : Begin
      if (gglpoMainWindow = @Self) then PostQuitMessage (0)
      else WindowProc := DefWindowProc(hWindow, wMsg, wPar, lPar);
      End;
   WM_Notify  : WindowProc:=WMNotify(wPar, lPar);
   WM_Command : WindowProc:=WMCommand(wPar, lPar);

   WM_CTLCOLORMSGBOX,
   WM_CTLCOLOREDIT,
   WM_CTLCOLORLISTBOX,
   WM_CTLCOLORBTN,
//   WM_CTLCOLORDLG,
   WM_CTLCOLORSCROLLBAR,
   WM_CTLCOLORSTATIC : begin
      // Special case where controls colors can be defines by their parent.
      // The controls can define the colors directly through this call.
      // lPar = handle on the control who wants to be redrawn
      // wPar = Device context used to draw the control.
      wRep:=WMCTLCOLOR(hWindow, wMsg, wPar, lPar);
      if (wRep = 0) then WindowProc:=DefWindowProc(hWindow, wMsg, wPar, lPar)
      else               WindowProc:=wRep;
      end;

   WM_MENUSELECT : if (poStatusLine <> NIL) and (poMenu <> NIL) then begin
      // DBW0(32, DBMsgToStr(wMsg) + ITS(LoWord(wPar)) + ITS(HiWord(wPar)) + ITS(lPar));
      // display an info in the status line.
      if ((HiWord(wPar) and MF_POPUP) = MF_POPUP) then
           prML:=poMenu^.oHt.GetPointerW2(lPar, word32(65536)*LoWord(wPar), wInfoL)
      else prML:=poMenu^.oHt.GetPointerW2(lPar, LoWord(wPar), wInfoL);

      if (prML <> NIL) then poStatusLine^.SetStatusText(0, prML^.strInfo);
                            // display the info in the status line
      end; // WM_MENUSELECT : begin

   WM_ENTERMENULOOP : if (poStatusLine <> NIL) and (poMenu <> NIL) then
                         strMemStatusLine:=poStatusLine^.GetStatusText(0);
                         // Before changing the status line, memorise what was in it.
   WM_EXITMENULOOP  : if (poStatusLine <> NIL) and (poMenu <> NIL) then
                         poStatusLine^.SetStatusText(0, strMemStatusLine);
                         // set back what was in the status line.

   else begin // of case
      // default behaviour for normal windows.
      // for MDI main windows, use
      // DefFrameProc(hWindow, hWinClient, wMsg, wPar, lPar);  for the main window and
      // DefMDIChildProc(hWindow, wMsg, wPar, lPar);  for the child window
      WindowProc := DefWindowProc(hWindow, wMsg, wPar, lPar);
      end;
   End; // Case wMsg Of
end;  // TWindow0.WindowProc

procedure TWindow0.WMSizeMoveFirst(wMsg:UINT; wPar:WPARAM; lPar:LPARAM);
//======================================================================
// The Window has been resized, must take car of its child windows,
// such as the tool bar, and a  RichText  control taking the whole
// client area surface of its parent.
var
  rRec        : RECT;
  wChild      : word; // to loop over all its children
  poTBar      : PToolBar;

begin
if (wMsg = WM_Size) then WMToAllChildren(hWin, wMsg, wPar, lPar);
                         // send the message to all childrens

if not IsWindowVisible(hWin) then exit;

// Memorise its size state, position and size
if      (wPar = SIZE_MAXIMIZED) then wSizeState:=SIZE_MAXIMIZED
else if (wPar = SIZE_MINIMIZED) then wSizeState:=SIZE_MINIMIZED
else if (wPar = SIZE_RESTORED)  then begin
   wSizeState:=SIZE_RESTORED;

   if not (IsZoomed(hWin) or IsIconic(hWin)) then begin
      // Remember the position and size of the window
      GetWindowRect(hWin, @rRec);
      nLeft  :=rRec.Left;
      nTop   :=rRec.Top;
      nWidth :=rRec.Right  - rRec.Left;
      nHeight:=rRec.Bottom - rRec.Top;
      end;
   end; // else if (wPar = SIZE_RESTORED)  then begin

// Memorise the client size.
GetClientRect(hWin, @rRec);
nClientWidth  :=rRec.Right;
nClientHeight :=rRec.Bottom;

if (papoChild = NIL) then exit; // no child windows

// Loop over all its children, to see if they have to move or to be resized.
for wChild :=1 to nNumberOfChild do begin
   if (papoChild^[wChild]^.wWindowType = GGLCTE_ToolBar) then begin
      poTBar :=PToolBar(papoChild^[wChild]);

      if (poTBar^.wTBPosition = 16) then begin
         // Left vertical. Must shorten if a status line take place in the bottom
         if (poStatusLine <> NIL) then begin
            MoveWindow ( poTBar^.hWin,0, 0, poTBar^.nXSizePix,
                         nClientHeight - int32(poStatusLine^.wHeight), TRUE);
            end;
         end;
      // else other cases are not treated yet.
      end; // if (papoChild^[wChild]^.wWindowType = GGLCTE_ToolBar ...
   end; // for wChild :=1 to nNumberOfChild do begin
end;  // TWindow0.WMSizeMoveFirst

procedure TWindow0.WMNotifyFirst(wPar:WPARAM; lPar:LPARAM);
//=========================================================
// Handles the notification messages send from the control
// It is usually overriden, if used.
// It is send before the  WindowProc  receives it.
var
  prNH        : ^NMHDR; // info associated with the notification message
  poCtrl      : PControl;

begin
wPar:=wPar; // to avoid the Hint message
// Notification message information. From whom and what.
prNH:=Pointer(lPar);

// The problem is that the handle doesn't identify always the control.
// only controls that has been defined in the library.
if (IsBadReadPtr(prNH, sizeOf(NMHDR))) then exit; // not usable.
poCtrl:=Pointer(GetWindowLong(prNH^.hwndFrom, GWL_USERDATA));

// If the pointer is valid and represent the same handle, then
// it is a pointer on the object corresponding to the control.
if (not IsBadReadPtr(poCtrl, sizeOf(TControl0))) then begin
//   DBW0(2048, DBNotifToStr(prNH^.Code) + ITS(poCtrl^.hWin) + ' = ' + ITS(prNH^.hwndFrom));
   if (poCtrl^.hWin = prNH^.hwndFrom) then begin
      // the control has been identified to be the one having the right handle
      // Calls the notification message to the control's notification message handler
      // poCtrl^.Code = notification message, as NM_XXX and EN_XXX and ...
      poCtrl^.CtrlNotifMessageHandleFirst(prNH^.Code, lPar);
      end;
   end;

// else do nothing
end;  //TWindow0.WMNotifyFirst

procedure TWindow0.WMCommandFirst(wPar:WPARAM; lPar:LPARAM);
//==========================================================
// Handles the menu messages
// It is send before the  WindowProc  receives it.
var
  poCtrl      : PControl;
  wNoticode   : word;

begin
if (lPar <> 0) then begin
   // It is a notification message send from the child control to its parent.
   // send it back to the object control
   wNotiCode := HiWord(wPar);

   // this message is a notification code from the control.
   // lPar = handle of the control, get the pointer on the object.
   poCtrl:=Pointer(GetWindowLong(lPar, GWL_USERDATA));

   // If the pointer is valid and represent the same handle, then
   // it is a pointer on the object corresponding to the control.
   if (not IsBadReadPtr(poCtrl, sizeOf(TControl0))) then begin
//      DBW0(4096, DBNotifToStr(wNotiCode) + ITS(poCtrl^.hWin) + ' = ' + ITS(lPar));
      if (poCtrl^.hWin = lPar) then begin
         // The control has been identified to be the one having the right handle
         // Calls the notification message to the control's notification
         // message handler
         // poCtrl^.Code = notification message, as NM_XXX and EN_XXX and ...
         poCtrl^.CtrlNotifMessageHandleFirst(wNotiCode, lPar);
         end;
      end;
   end;

// else do nothing
end;  // TWindow0.WMCommandFirst

function TWindow0.WindowProcFirst(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT;
//===========================================================================================
// Handles messages for the library, before calling  WindowProc
Var poWin       : PWindow0;
begin
Case wMsg Of
   WM_Notify  : WMNotifyFirst(wPar, lPar);
   WM_Command : WMCommandFirst(wPar, lPar);
   WM_Move,
   WM_Size : WMSizeMoveFirst(wMsg, wPar, lPar);
   end; // Case wMsg Of

// Call the default window proc.
WindowProcFirst:=WindowProc(hWindow, wMsg, wPar, lPar);

// this is the very last message a window receives before destruction
if (wMsg = WM_NCDestroy) then begin
   // The window has been destroyed, do not destroy it again
   hWin:=0;

   // destroy all child windows, if not already done.
   WindowDestroyAllChild;

   if (wIsDone = 1) and (@Self <> gglpoMainWindow) then begin
      // dispose also the object
      // The main window will be disposed in the application's destructor
      poWin :=@Self;
      dispose(poWin, Done);
      end;
   // else it has already been disposed.
   end;

end;  // TWindow0.WindowProcFirst

end.  // unit wWindow0;

