//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1991, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of TMDIChild. This defines the basic behavior of all MDI
/// child windows
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/mdichild.h>
#include <owl/mdi.h>
#include <owl/applicat.h>
 
#if defined(__BORLANDC__)
# pragma option -w-ccc // Disable "Condition is always true/false"
#endif
 
namespace owl {
 
OWL_DIAGINFO;
DIAG_DECLARE_GROUP(OwlWin);  // diagnostic group for windows
 
#if !defined(WS_EX_MDICHILD)
# define WS_EX_MDICHILD          0x00000040L
#endif
 
 
DEFINE_RESPONSE_TABLE1(TMDIChild, TFrameWindow)
  EV_WM_ENTERIDLE,
  EV_WM_MDIACTIVATE,
  EV_WM_MENUSELECT,
  EV_WM_NCACTIVATE,
END_RESPONSE_TABLE;
 
namespace
{
 
  // Initializes attributes (helper used by the constructors).
  //
  void InitAttributes(TWindowAttr& a)
  {
    a.Y = a.H = CW_USEDEFAULT;
    a.Style = WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
      WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
    a.ExStyle |= WS_EX_MDICHILD;
  }
 
} // namespace
 
//
/// Constructor for a TMDIChild
///
/// Creates an MDI child window of the MDI client window specified by
/// parent, using the specified title, client window (clientWnd) and instance
/// (inst). Invokes the TFrameWindow base class constructor, supplying parent,
/// title, clientWnd, inst, and indicating that the child window is not to be
/// resized to fit. Invokes the TWindow base class constructor, specifying parent,
/// title, and inst. The window attributes are then adjusted to include WS_VISIBLE,
/// WS_CHILD, WS_CLIPSIBLINGS, WS_CLIPCHILDREN, WS_SYSMENU, WS_CAPTION,
/// WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX. The dimensions of the window
/// are set to the system default values.
//
TMDIChild::TMDIChild(TMDIClient&     parent,
                     LPCTSTR         title,
                     TWindow*        clientWnd,
                     bool            shrinkToClient,
                     TModule*        module)
{
  TWindow::Init(&parent, title, module);
  TFrameWindow::Init(clientWnd, shrinkToClient);
  InitAttributes(Attr);
}
 
//
/// String-aware overload
//
TMDIChild::TMDIChild(
  TMDIClient& parent,
  const tstring& title,
  TWindow* clientWnd,
  bool shrinkToClient,
  TModule* module)
{
  TWindow::Init(&parent, title, module);
  TFrameWindow::Init(clientWnd, shrinkToClient);
  InitAttributes(Attr);
}
 
//
/// Constructor for a TMDIChild which is being used in a DLL as an alias for a non-OWL window
///
/// Creates an MDI child window object from a preexisting window, specified
/// by hWnd. The base class TFrameWindow constructor is invoked, specifying this
/// hWnd, as well as the specified inst. The base class TWindow constructor is
/// invoked, supplying the hWnd and inst parameters.
//
TMDIChild::TMDIChild(THandle handle, TModule* module)
:
  TWindow(handle, module),
  TFrameWindow(handle, module)
{
  Attr.Style = WS_CLIPSIBLINGS;
  Attr.ExStyle |= WS_EX_MDICHILD;
}
 
//
// Destructor for a MDI child
//
TMDIChild::~TMDIChild()
{
}
 
//
/// Responds to a request to change a title bar or icon.
///
/// Don't allow NC Activation if we are only temporarily unhidden for window
/// menu maintainance
//
bool
TMDIChild::EvNCActivate(bool active)
{
  return IsFlagSet(wfUnHidden) ? false : TFrameWindow::EvNCActivate(active);
}
 
//
/// Overrides TWindow's virtual function. Displays a child window according to the
/// value of cmdShow.
///
/// Perform special processing for showing MDI children to make sure that
/// the MDI client maintains the window list correctly
//
bool
TMDIChild::ShowWindow(int cmdShow)
{
  int  retVal = TFrameWindow::ShowWindow(cmdShow);     // 0 if had been hidden
 
  // Process only if visible state has changed
  //
  if ((retVal != 0) != (cmdShow != SW_HIDE)) {
    if ((THandle)GetParentO()->HandleMessage(WM_MDIGETACTIVE) == *this) {
      if (cmdShow == SW_HIDE)
        GetParentO()->HandleMessage(WM_MDINEXT, TParam1(GetHandle()));
      else
        HandleMessage(WM_NCACTIVATE, true); // resend suppressed message
    }
    GetParentO()->HandleMessage(WM_MDIREFRESHMENU);
  }
  return retVal;
}
 
//
/// Overrides TWindow's virtual function. Enables a child window.
///
/// Perform special processing for enabling MDI children to make sure that
/// the MDI client maintains the window list correctly
//
bool
TMDIChild::EnableWindow(bool enable)
{
  int retVal = TFrameWindow::EnableWindow(enable);  // 0 if previously enabled
 
  // Process only if disabled state has actually changed
  //
  if ((retVal!=0) != (enable==0)) {
    if (!enable && (THandle)GetParentO()->HandleMessage(WM_MDIGETACTIVE) == *this)
      GetParentO()->HandleMessage(WM_MDINEXT, TParam1(GetHandle()));
    GetParentO()->HandleMessage(WM_MDIREFRESHMENU);
  }
  return retVal;
}
 
//
/// Performs preprocessing of window messages for the MDI child window. If keyboard
/// handling is enabled the parent client window's TMDIClient_PreProcessMsg member
/// function is called to preprocess messages. In this case, the return value is
/// true. Otherwise, TFrameWindow::PreProcessMsg is called and its return value
/// becomes the return value of this member function.
///
/// If the MDI child has requested keyboard navigation then TFrameWindow's
/// PreProcessMsg() member function will call ::&IsDialogMessage() which will
/// eat the event and the MDI client window won't get a chance to do MDI
/// accelerator processing
///
/// So, we will do it here to make sure it gets done
//
bool
TMDIChild::PreProcessMsg(MSG& msg)
{
  if (KeyboardHandling && GetParentO()->PreProcessMsg(msg))
    return true;
  //????????????????????????????????????????????????????????????????????????????
  // Parent->Parent-> - this is MDIFrame ???
  if (HAccel && ::TranslateAccelerator(GetParentO()->GetParentO()->GetHandle(), HAccel, &msg))
    return true;
 
  return TFrameWindow::PreProcessMsg(msg);
}
 
void
TMDIChild::EvMenuSelect(uint menuItemId, uint flags, HMENU hMenu)
{
  TFrameWindow::EvMenuSelect(menuItemId, flags, hMenu);
  // if system message forward it to MainWindows() to display help message
  if ((flags & MF_SYSMENU)>0){
    TFrameWindow* frameWnd = TYPESAFE_DOWNCAST (GetApplication()->GetMainWindow(), TFrameWindow);
    if(frameWnd)
      frameWnd->ForwardMessage(true);
  }
}
 
//
// Handle WM_ENTERIDLE in order to display help hints on the messsage bar if
// there is a hint pending & this frame has a message bar.
//
void
TMDIChild::EvEnterIdle(uint source, HWND hDlg)
{
  if (source == MSGF_MENU){
    TFrameWindow* frameWnd = TYPESAFE_DOWNCAST (GetApplication()->GetMainWindow(), TFrameWindow);
    if(frameWnd)
      frameWnd->ForwardMessage(true);
  }
  TFrameWindow::EvEnterIdle(source, hDlg);
}
 
//
/// Destroys the interface element associated with the TMDIChild. Calls
/// EnableAutoCreate for each window in the child list so that the children are also
/// re-created when the parent window is re-created.
//
void
TMDIChild::Destroy(int)
{
  if (GetHandle())
  {
    for (auto& w : GetChildren())
      if (w.GetHandle())
        w.EnableAutoCreate();
    if (GetParentO()) {
      // Send destroy message to MDI client window to have it destroy this THandle
      //
      GetParentO()->HandleMessage(WM_MDIDESTROY, TParam1(GetHandle()));
      SetHandle(0);  // Assume success
    }
    else {
      if (::DestroyWindow(GetHandle()))
        SetHandle(0);
      GetApplication()->ResumeThrow();
      WARNX(OwlWin, GetHandle(), 0, "::DestroyWindow(" << static_cast<void*>(GetHandle()) << ") failed");
    }
  }
}
 
//
/// Creates the interface element associated with the MDI child window. Otherwise,
/// it notifies the parent MDI client window to create the child window's interface
/// element. The supplied menuOrId parameter is ignored because MDI child windows
/// cannot have menus.
///
/// An MDI Child creates its GetHandle() by sending an MDI Create packet to the MDI
/// client.
//
TWindow::THandle
TMDIChild::PerformCreate()
{
  PRECONDITION(Parent);
 
  MDICREATESTRUCT  createStruct;
  createStruct.szClass = GetWindowClassName().GetPointerRepresentation();
  createStruct.szTitle = GetCaption();
  createStruct.hOwner = *GetModule();
  createStruct.x = Attr.X;
  createStruct.y = Attr.Y;
  createStruct.cx = Attr.W;
  createStruct.cy = Attr.H;
  createStruct.style = Attr.Style;
  createStruct.lParam = TParam2(Attr.Param);
 
  // Work around a Windows MDI bug w/ bad menus if MDI child is created
  // maximized, by hiding child now & maximizing later
  //
  uint32 origStyle = Attr.Style;
  if (createStruct.style & WS_MAXIMIZE)
    createStruct.style &= ~(WS_MAXIMIZE | WS_VISIBLE);
 
  TResult r = GetParentO()->HandleMessage(WM_MDICREATE, 0, TParam2(&createStruct));
  THandle h = reinterpret_cast<THandle>(r);
 
  // Finish up maximized MDI child workaround
  //
  if (h && (origStyle & WS_MAXIMIZE)) {
    GetParentO()->HandleMessage(WM_MDIMAXIMIZE, TParam1(GetHandle()));
    GetParentO()->HandleMessage(WM_MDIREFRESHMENU);
  }
  return h;
}
 
//
/// Instructs a client window to activate or deactivate an MDI child window and then
/// sends a message to the child window being activated and the child window being
/// deactivated.
//
void
TMDIChild::EvMDIActivate(HWND hActivated, HWND hDeactivated)
{
  if (GetHandle() == hActivated) {
 
    // A bug in Windows MDI causes the first MDI child to not get a
    // WM_SETFOCUS. Simulate it now
    //
    if(!GetWindow(GW_HWNDNEXT) &&  GetFocus() != GetHandle())
      HandleMessage(WM_SETFOCUS, TParam1(GetHandle()));
 
    // Merge this windows menubar with the MDI frame's if there is a
    // MenuDescr assigned
    //
    TFrameWindow* frame = TYPESAFE_DOWNCAST(GetParentO()->GetParentO(),TFrameWindow);
    if (GetMenuDescr()){
      if (frame)
        frame->MergeMenu(*GetMenuDescr());
    }
    if (frame){
      if(GetBarDescr())
        frame->MergeBar(*GetBarDescr());
      else
         frame->RestoreBar();
    }
  }
  else {
    // Restore the MDI frame's menubar if there is no other MDI child being
    // activated
    //
    if(!hActivated){
      TFrameWindow* frame = TYPESAFE_DOWNCAST(GetParentO()->GetParentO(),TFrameWindow);
      if (GetMenuDescr()) {
        if (frame)
          frame->RestoreMenu();
      }
      if (GetBarDescr()){
        if (frame)
          frame->RestoreBar();
      }
    }
  }
 
  // Forward MDI child activation to our client (if we have one) so that it can
  // perform any type of activate/deactivate processing that it needs
  //
  TWindow* w = GetClientWindow();
  if (w && w->IsWindow())
    w->HandleMessage(WM_MDIACTIVATE, TParam1(hDeactivated), TParam2(hActivated));
 
  DefaultProcessing();
}
 
//
/// Overrides TWindow::DefWindowProc to provide default processing for any incoming
/// message the MDI child window does not process. In addition, DefWindowProc
/// handles the following messages: WM_CHILDACTIVATE, WM_GETMINMAXINFO, WM_MENUCHAR,
/// WM_MOVE, WM_SETFOCUS, WM_SIZE, and WM_SYSCOMMAND.
//
TResult
TMDIChild::DefWindowProc(TMsgId msg, TParam1 param1, TParam2 param2)
{
  if (IsFlagSet(wfAlias))
    return TWindow::DefWindowProc(msg, param1, param2);
 
  return ::DefMDIChildProc(GetHandle(), msg, param1, param2);
}
 
 
 
IMPLEMENT_STREAMABLE2(TMDIChild, TFrameWindow, TWindow);
 
#if OWL_PERSISTENT_STREAMS
 
//
// Reads data of the TMDIChild from the passed opstream
//
void*
TMDIChild::Streamer::Read(ipstream& is, uint32 /*version*/) const
{
  ReadVirtualBase((TFrameWindow*)GetObject(), is);
  return GetObject();
}
 
//
// Writes data of the TMDIChild to the passed opstream
//
void
TMDIChild::Streamer::Write(opstream& os) const
{
  WriteVirtualBase((TFrameWindow*)GetObject(), os);
}
 
#endif
 
} // OWL namespace
/* ========================================================================== */
 

V601 The 'true' value is implicitly cast to the integer type. Inspect the second argument.