unit wMDIChildWindow0;

{ 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.

  Its purpose is to handle Multiple Interface Document windows (MDI)
----------------------------------}

// 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 wMDIWindow0, wWindow0, wControl0, wGlobals2, windows;

type
  PMDIChildWindow0 = ^TMDIChildWindow0;
  TMDIChildWindow0 = object(TWindow)
  //""""""""""""""""""""""""""""""""
//  hWin     : HWND;  // Handle on the edit box, got from TWindowBase
//  hParent : HWND;  // Handle on the parent, got from TWindowBase
//  poParent: PWindowBase0;  // Pointer on the parent, got from TWindowBase

  lUserData : longint; // application-defined
  // can be used by a final application, not usefull, but has to be
  // send when creating the MDI child window.

  poGrParent : PMDIWindow0;
  // Pointer on the object which is parent to the
  // parent windo of this MDI child window
  // There are no object for the Client window, which is
  // son of the main window and parent of child window

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

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

  procedure WinMDICreate(poGrParentPrm:PMDIWindow0); virtual;
  // creation of an MDI child window
  // Can be overriden, but not overriden usually
  // poGrParentPrm is a pointer on the grand parent, which is normally
  // the main application MDI window

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

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

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

  function WindowProcFirst(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  // Handles MDI child window messages for the library, before calling  WindowProc
  // It is usually not overriden
  end; // TMDIChildWindow0 = object(TWindow)
  TMDIChildWindow =  TMDIChildWindow0;
  PMDIChildWindow = ^TMDIChildWindow;

// handles the messages send to the MDI child windows.
// must be in the interface part, to be registered by its parent
// in wMDUWindow0.pp
Function ChildWindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; stdcall; export;
//===================================================================================================
// This is the message handling function for the MDI child windows,

const
  // pointer on the active MDI child window
  gglpoMDIActiveWindow : PMDIChildWindow0 = NIL;

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

uses wWindowBase0, wDebug0;

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

//***************************************************
// TMDIChildWindow0 = object(TWindow0)
//***************************************************

Function ChildWindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; stdcall; export;
//==================================================================================================
// This is the message handling function for the MDI child windows,
var
  // corresponding object child window to the  hWindow  handle
  poWin       : PMDIChildWindow0;
  wL, wH      : word;

Begin
if (gglpoMDIActiveWindow <> NIL) then begin
   if (gglpoMDIActiveWindow^.hWin = hWindow) then begin
      // Call the event handler of the main application window.
      ChildWindowProc := gglpoMDIActiveWindow^.WindowProcFirst(hWindow, wMsg, wPar, lPar);
      exit;
      end;
   end;

// It is possible that the event handler of another MDI child 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.
      // Should be wType = GGLCTE_CHILD_MDIWINDOW
      // Pointer on the corresponding object window.
      wL:=GetWindowWord(hWindow, 12); //  LOWORD
      wH:=GetWindowWord(hWindow, 14); //  HIWORD
      poWin:=PMDIChildWindow0(MakeLong(wL, wH));
      // poWin = pointer on the object MDI child window

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

// Call the default event handler
// Default message handling for MDI child windows
// For the first messages, it can be that the pointer on the MDI Window is
// no initialised, and that we arrive here.
ChildWindowProc:=DefMDIChildProc(hWindow, wMsg, wPar, lPar);
End;  // ChildWindowProc

constructor TMDIChildWindow0.Init(strWinTitlePrm:ShortString);
//============================================================
begin
inherited Init(strWinTitlePrm);

wWindowType :=GGLCTE_CHILD_MDI_WINDOW;

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

// Default position and size of the MDI child window when created
nLeft   :=CW_USEDEFAULT;
nTop    :=CW_USEDEFAULT;
nWidth  :=150;
nHeight :=100;

// No extra style
dwStyle:=0;

lUserData:=0;

// Will be set to the parent window, when created.
hParent :=0;

// Grandparent, will be set when creating the window
poGrParent:=NIL;
end;  // TMDIChildWindow0.Init

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

inherited Done;
end;  // TMDIChildWindow0.Done

procedure TMDIChildWindow0.WinMDICreate(poGrParentPrm:PMDIWindow0);
//=================================================================
// Can be overriden, but it is not usual.
Begin
poGrParent:=poGrParentPrm;
//poParent:=NIL; // there are no object client window for the moment. Should come later.
hParent:=poGrParent^.hWinClient;

// Take the grand parent as the parent.
poParent:=poGrParentPrm;
if (poParent <> NIL) then
   // add the control to the parent's child list.
   poParent^.AddChildObjectWindow(@Self);

strWinTitle:=strWinTitle+#0;
hWin:=CreateMDIWindow( @gglstrClassWinMDIChildName[1], // is defined in wGlobals0.pp
                       @strWinTitle[1],
                       dwStyle, nLeft, nTop, nWidth, nHeight,
                       hParent, System.MainInstance, lUserData);

if (hWin = 0) then exit; // this is an error. The class may be incorrect.

// 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);
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_CHILD_MDI_WINDOW);
SetWindowWord(hWin,10, 0);
SetWindowWord(hWin,12, LOWORD(Longint(@Self)));
SetWindowWord(hWin,14, HIWORD(Longint(@Self)));

// The active MDI child window is this one.
gglpoMDIActiveWindow:=@Self;
End;  // TMDIChildWindow0.WinMDICreate

function TMDIChildWindow0.WMNotify(wPar:WPARAM; lPar:LPARAM):LRESULT;
//===================================================================
// Handles the notification messages send from the richedit 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 := DefMDIChildProc(hWin, WM_NOTIFY, wPar, lPar);
end;  //TMDIChildWindow0.WMNotify

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

begin
// if it is different from 0 and 1, it is a notification message send
// from the child control to its parent.
// send it back to the object control
wNotiCode := HiWord(wPar);

if (wNotiCode <> 0) and (wNotiCode <> 1) then begin
   // 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;

WMCommand := DefMDIChildProc(hWin, WM_COMMAND, wPar, lPar);
end;  // TMDIChildWindow0.WMCommand

function TMDIChildWindow0.WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT;
//==============================================================================================
// All window messages are send here.
Begin
WindowProc := 0; // Default return value when processing a message

{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, 'Child ' + DBMsgToStr(wMsg) + ITS(wPar) + ITS(lPar));  }

case wMsg of
   // processing of messages
      WM_Notify : WindowProc:=WMNotify(wPar, lPar);
      WM_Command : WindowProc:=WMCommand(wPar, lPar);
   else WindowProc := DefMDIChildProc(hWindow, wMsg, wPar, lPar);
        // Default message handling for MDI child windows
   end; // case
End;  // TMDIChildWindow0.WindowProc

function TMDIChildWindow0.WindowProcFirst(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT;
//===================================================================================================
// Handles MDI child window messages for the library, before calling  WindowProc
//Var  rRec        : rect;
var
  wType       : word;
  poWin       : PMDIChildWindow0;

begin
Case wMsg Of
   WM_Size : begin
      // send the message to all childrens
      WMToAllChildren(hWindow, wMsg, wPar, lPar);
      end;

   WM_MDIActivate : begin
      // sets the pointer on the active object MDI child window
      gglGetPointerObject(hWindow, wType, poWin);
      if (wType = GGLCTE_CHILD_MDI_WINDOW) then gglpoMDIActiveWindow:=poWin;
      end;
   end; // Case wMsg Of

WindowProcFirst:=WindowProc(hWindow, wMsg, wPar, lPar);

if (wMsg = WM_NCDestroy) then begin
   // this is the last message a window receive before beeing removed from memory
//   WindowDestroyAllChild; // destroy all childs, if not already done. Useless I think, Windows did it already.
   hWin:=0;  // do not destroy again.

   if (wIsDone = 1) 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;  // TMDIChildWindow0.WindowProcFirst

end.  // unit wMDIChildWindow0;

