/*  MDI.c
    MDI Window Application
    Windows Toolkit Version 2.00
    Copyright (c) Microsoft 1986, 1987        */

#include "windows.h"
#include "mdi2.h"
#define OBM_CLOSE 32767

char szAppName[10];
char szTitle[15]; 
char *rgpszClass[] = {"Red", "Green", "Blue"};
char *rgpszCaption[] = {"Red Child n", "Green Child n", "Blue Child n"};
int  ChildCount[3]; /* one entry for each color */
HWND hwndActiveChild = NULL;
HWND hwndParent;
BOOL vfMaximize;
HANDLE hInst;
FARPROC lpprocHelp;
FARPROC lpprocNew;

HBITMAP ChildSysMenu ();
void ChangeChildSysMenu();
void DisplayChild();
void SetActiveChildWindow();
int  CchFromSz();
BOOL ParentInit();
void GetMaxChildSize();
void far lstrcpy();
void far lstrcat();
int  far lstrlen();

long FAR PASCAL ParentWndProc(HWND, unsigned, WORD, LONG);
long FAR PASCAL ChildWndProc(HWND, unsigned, WORD, LONG);
BOOL FAR PASCAL Help();
BOOL FAR PASCAL New();


/***************************************************************
*                    Main application function. 
****************************************************************/
int PASCAL WinMain(hInstance, hPrevInstance, lpszCmdLine, cmdShow)
HANDLE hInstance, hPrevInstance;
LPSTR  lpszCmdLine;
int    cmdShow;
{
  MSG   msg;
  HWND  hwnd, hChild;
  HMENU hMenu;
  HANDLE ParentAccel, ChildAccel;

  if (!hPrevInstance) 
      {
      /* Call initialization procedure if this is the first instance */
      if (!ParentInit(hInstance))
          return FALSE;
      }
  else 
      {
      /* Copy data from previous instance */
      GetInstanceData(hPrevInstance, (PSTR)szAppName, 10);
      GetInstanceData(hPrevInstance, (PSTR)szTitle, 15);
      }

  hwnd = CreateWindow((LPSTR)szAppName,
                      (LPSTR)szTitle,
                      WS_TILEDWINDOW | WS_CLIPCHILDREN,
                      0,
                      0,
                      400,
                      200,
                      (HWND)NULL,        /* no parent */
                      (HMENU)NULL,       /* use class menu */
                      (HANDLE)hInstance, /* handle to window instance */
                      (LPSTR)NULL        /* no params to pass on */
                      );

  hwndParent = hwnd;
 
  /* Save instance handle for DialogBox */
  hInst = hInstance;

  /* Bind callback function with module instance */
  lpprocHelp = MakeProcInstance((FARPROC)Help, hInstance);
  lpprocNew  = MakeProcInstance((FARPROC)New,  hInstance);

  /* Make window visible according to the way the app is activated */
  ShowWindow(hwnd, cmdShow);
  UpdateWindow(hwnd);

  DisplayChild(IDDRED);
  ChangeMenu(GetSubMenu(GetMenu(hwndParent), 1), 999, NULL, NULL, MF_DELETE);

  /* Load accelerators. */
  ParentAccel = LoadAccelerators(hInst, MAKEINTRESOURCE(ParentWindow));
  ChildAccel  = LoadAccelerators(hInst, MAKEINTRESOURCE(ChildWindow));

  /* Polling messages from event queue */
  while (GetMessage((LPMSG)&msg, NULL, 0, 0)) 
      {
      if (!TranslateAccelerator(hwndParent, ParentAccel, (LPMSG)&msg)) 
          {
          TranslateMessage((LPMSG)&msg);
          DispatchMessage((LPMSG)&msg);
          } 
      }
  return (int)msg.wParam;
}



long FAR PASCAL ParentWndProc(hwnd, message, wParam, lParam)
HWND hwnd;
unsigned message;
WORD wParam;
LONG lParam;
{
  PAINTSTRUCT ps;
  HWND hDlg;
  HMENU hmenu;

  switch (message)
      {
  case WM_COMMAND:
      switch (wParam)
          {
      case IDMEXIT:
           PostQuitMessage(0);
           break;

      case IDMNEW:
           DialogBox(hInst, MAKEINTRESOURCE(NEWBOX), hwnd, lpprocNew);
           break;

      case IDMUNDO:
           MessageBox(hwnd, (LPSTR)"UNDO",(LPSTR)"Key hit", MB_OK);
           break;

      case IDMGENERAL:
           hDlg = CreateDialog(hInst, MAKEINTRESOURCE(GENERALBOX),
                               hwnd, lpprocHelp);
           ShowWindow(hDlg, SHOW_OPENWINDOW); 
           break;

      case IDMABOUT:
           DialogBox(hInst, MAKEINTRESOURCE(ABOUTBOX), hwnd, lpprocHelp);
           break; 

      default:
          /* Must be call to bring a child window to the front. */
          SetActiveChildWindow(wParam);
          }
      break; 

  case WM_DESTROY:
      PostQuitMessage(0);
      break;

  case WM_ACTIVATE:
      if (hwndActiveChild != NULL)
          {
          /* make child's active state track parent's */
          SendMessage(hwndActiveChild, WM_NCACTIVATE, wParam, 0L);
          SendMessage(hwndActiveChild, WM_ACTIVATE, wParam, 0L);
          }

      /* intentional fall through */

  default:
      return DefWindowProc(hwnd, message, wParam, lParam);
      }

  return(0L);
}


long FAR PASCAL ChildWndProc(hwnd, message, wParam, lParam)
HWND hwnd;
unsigned message;
WORD wParam;
LONG lParam;
    {
    PAINTSTRUCT ps;
    HWND hDlg, hwndT;
    HMENU hmenu, hPopupMenu;
    RECT rc;
    char szT[30];
    HBITMAP hBitmap;
   
    switch (message)
        {
    case WM_DESTROY:
        hwndT = GetWindow(hwnd, GW_HWNDNEXT);
        ShowWindow(hwnd, HIDE_WINDOW);
        if (hwndT != hwnd)
            SetActiveChildWindow(hwndT);
        else
            hwndActiveChild = NULL;

        hmenu = GetSubMenu(GetMenu(hwndParent),1);
        ChangeMenu(hmenu, hwnd, NULL, NULL, MF_DELETE);
        return DefWindowProc(hwnd, message, wParam, lParam);

    case WM_SYSCOMMAND:
        switch (wParam) {
              case SC_MAXIMIZE:
                  if (!vfMaximize)
                  {
                     vfMaximize = TRUE;
                     lstrcpy((LPSTR)szT, (LPSTR)szTitle);
                     lstrcat((LPSTR)szT, (LPSTR)" - ");
                     GetWindowText(hwndActiveChild, 
                             (LPSTR)szT +lstrlen((LPSTR)szT), 20);
                     SetWindowText(hwndParent, (LPSTR)szT);
                
                     hmenu = GetMenu(hwndParent);
                     hPopupMenu = CreateMenu();
                     hBitmap = ChildSysMenu(hwnd);

                     if (hBitmap == NULL)
                        MessageBox (hwndParent, (LPSTR)"not found", (LPSTR)"bitmap",MB_OK);
                     else
                     {
                       ChangeMenu(hPopupMenu, NULL, "Restore\tCtrl+F5", SC_RESTORE,
                                  MF_APPEND ); 
                       ChangeMenu(hPopupMenu, NULL, "Move\tCtrl+F7", SC_MOVE,
                                  MF_APPEND | MF_GRAYED);
                       ChangeMenu(hPopupMenu, NULL, "Size\tCtrl+F8", SC_SIZE,
                                 MF_APPEND | MF_GRAYED);
                       ChangeMenu(hPopupMenu, NULL, "Maximize\tCtrl+F10", SC_MAXIMIZE,
                                  MF_APPEND | MF_GRAYED);
                       ChangeMenu(hPopupMenu, NULL, "Close\tCtrl+F4", SC_CLOSE,
                                  MF_APPEND );
                       ChangeMenu(hmenu, 0,(LPSTR)(DWORD)hBitmap,hPopupMenu,
                                  MF_INSERT | MF_BYPOSITION | MF_POPUP | MF_BITMAP);
                     }
                     DrawMenuBar(hwndParent);

                     return DefWindowProc(hwnd, message, wParam, lParam); 
                     break;
                  }
                  
                  /* else, want to restore it - intentional fall through */
              case SC_RESTORE:
                  SetWindowText(hwndParent, (LPSTR)szTitle);
                  vfMaximize = FALSE;
                  hmenu = GetMenu (hwndParent);
                  ChangeMenu (hmenu, 0, NULL, NULL, MF_BYPOSITION | MF_DELETE);
                  DrawMenuBar (hwndParent);
 
                  /* another intentional fall through */
              default:
                  return DefWindowProc(hwnd, message, wParam, lParam);
        }
   
    case WM_GETMINMAXINFO:
        GetMaxChildSize((LPPOINT)lParam);
        break;

    case WM_LBUTTONDOWN:
        if (hwndActiveChild != hwnd)
            SetActiveChildWindow(hwnd);
        break;

    case WM_NCLBUTTONDOWN:
        if (hwndActiveChild != hwnd)
            SetActiveChildWindow(hwnd);

        return DefWindowProc(hwnd, message, wParam, lParam);

#ifdef FOO
    case WM_ACTIVATE:
        if (wParam)
            {
            hwndActiveChild = hwnd;
            SetWindowLong(hwnd, GWL_STYLE, WS_CHILD | WS_CAPTION |
                  WS_SIZEBOX | WS_SYSMENU | WS_CLIPSIBLINGS |
                  WS_MAXIMIZEBOX);
            ShowWindow(hwnd, SHOW_OPENNOACTIVATE);
            }

        if (!wParam && IsWindowVisible(hwnd))
            {
            SetWindowLong(hwnd, GWL_STYLE, WS_CHILD | WS_CAPTION |
                           WS_SIZEBOX | WS_CLIPSIBLINGS);
            ShowWindow(hwnd, SHOW_OPENNOACTIVATE);
            }

        /* intentional fall through */
#endif

    default:
         return DefWindowProc(hwnd, message, wParam, lParam);
        }

    return(0L);
    }



/*  SetActiveChildWindow is used to activate the window whose handle is
    hwnd and deactivate the previously activated window. */

void SetActiveChildWindow(hwnd)
HWND hwnd;
{
  HWND hwndT;
  long l;

  if (hwnd == NULL)
      return;

  if (hwnd != hwndActiveChild)
      {
      hwndT = hwndActiveChild;
      if (hwndActiveChild != NULL)
          {
          /* deactivate old child */
          SendMessage(hwndT, WM_NCACTIVATE, FALSE, 0L);
          SendMessage(hwndT, WM_ACTIVATE, FALSE, 0L);
          }

      hwndActiveChild = hwnd;
      SendMessage(hwnd, WM_NCACTIVATE, TRUE, 0L);
      SendMessage(hwnd, WM_ACTIVATE, TRUE, 0L);
      if (vfMaximize)
          {
          SendMessage(hwndT, WM_SYSCOMMAND, SC_RESTORE, 0L);
          BringWindowToTop(hwnd);
          SendMessage(hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0L);
          }
      else
          BringWindowToTop(hwnd);

      SetFocus(hwndParent);
      }
}

 
/*  DisplayChild is called when a child window is first created. */

void DisplayChild(color)
int color;
{
  HMENU hmenu;
  HWND hChild;

  ChildCount[color] = (ChildCount[color] % 9) + 1;
  *(rgpszCaption[color] + CchFromSz(rgpszCaption[color]) - 1) = 
                                              (char)ChildCount[color] + '0';
  hChild = CreateWindow((LPSTR)rgpszClass[color],
                        (LPSTR)rgpszCaption[color],
                        WS_CHILD | WS_SIZEBOX | WS_SYSMENU |
                        WS_CAPTION | WS_CLIPSIBLINGS | WS_MAXIMIZEBOX, 
                        10, 10,
                        200, 100,
                        hwndParent,
                        (HMENU)NULL,
                        (HANDLE) hInst,
                        (LPSTR)NULL);

  ShowWindow(hChild, SHOW_OPENWINDOW);
  SetActiveChildWindow(hChild);
  ChangeChildSysMenu(hChild);
  hmenu = GetSubMenu(GetMenu(hwndParent), 1);
  ChangeMenu(hmenu, NULL, (LPSTR)rgpszCaption[color], hChild, MF_APPEND);    
}


/* Procedure called when the application is loaded for the first time */

BOOL ParentInit(hInstance)
HANDLE hInstance;
{
  PWNDCLASS pParentClass;
  int x;

  /* Load strings from resource */
  LoadString(hInstance, IDSNAME, (LPSTR)szAppName, 10);
  LoadString(hInstance, IDSTITLE, (LPSTR)szTitle, 15);

  pParentClass = (PWNDCLASS)LocalAlloc(LPTR, sizeof(WNDCLASS));

  pParentClass->hCursor        = LoadCursor(NULL, IDC_ARROW);
  pParentClass->hIcon          = LoadIcon(hInstance,
                                          MAKEINTRESOURCE(MDIICON));
  pParentClass->lpszMenuName   = (LPSTR)szAppName;
  pParentClass->lpszClassName  = (LPSTR)szAppName;
  pParentClass->hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH);
  pParentClass->hInstance      = hInstance;
  pParentClass->style          = CS_HREDRAW | CS_VREDRAW;
  pParentClass->lpfnWndProc    = ParentWndProc;

  /* Register parent class. */
  if (!RegisterClass((LPWNDCLASS)pParentClass))
      /* Initialization failed.
       * Windows will automatically deallocate all allocated memory.
       */
      return FALSE;
  
  /* Register child classes. */
  pParentClass->lpfnWndProc    = ChildWndProc;

  pParentClass->lpszClassName  = rgpszClass[IDDRED];
  pParentClass->hbrBackground  = CreateSolidBrush((long)0x0ff);
  if (!RegisterClass((LPWNDCLASS)pParentClass))
      return FALSE;

  pParentClass->lpszClassName  = rgpszClass[IDDGREEN];
  pParentClass->hbrBackground  = CreateSolidBrush((long)0x0ff00);
  if (!RegisterClass((LPWNDCLASS)pParentClass))
      return FALSE;

  pParentClass->lpszClassName  = rgpszClass[IDDBLUE];
  pParentClass->hbrBackground  = CreateSolidBrush((long)0x0ff0000);
  if (!RegisterClass((LPWNDCLASS)pParentClass))
      return FALSE;

  LocalFree((HANDLE)pParentClass);
  return TRUE;        /* Initialization succeeded */
}


/* Used to modify the system menu for the child windows to indicate the use
   of Ctrl+ to access system commands. */

HBITMAP ChildSysMenu( hWnd )
HWND hWnd;
{
  BOOL      bResult;
  HDC       hDC, hdc1, hdc2;
  BITMAP    bmp;
  HBITMAP   hbmpClose, hbmpSystem;
  int       dxMenu, dyMenu;
  char      buf[24];

  hbmpClose = LoadBitmap(NULL, MAKEINTRESOURCE (OBM_CLOSE));
  GetObject(hbmpClose, sizeof(BITMAP), (BYTE far *)&bmp);
  hDC    = GetDC(hWnd);
  hdc1   = CreateCompatibleDC(hDC);
  SelectObject(hdc1, hbmpClose);
  hdc2   = CreateCompatibleDC(hDC);
  dyMenu = GetSystemMetrics(SM_CYMENU);
  dxMenu = bmp.bmWidth / 2;
  hbmpSystem = CreateCompatibleBitmap(hdc2, dxMenu, dyMenu);
  SelectObject(hdc2, hbmpSystem);
  PatBlt(hdc2, 0, 0, dxMenu, dyMenu, WHITENESS);
  bResult = BitBlt(hdc2, 0, 0, dxMenu, dyMenu,
                   hdc1, dxMenu, 0,
                   SRCCOPY);
  DeleteDC(hdc1);
  DeleteDC(hdc2);
  ReleaseDC(hWnd, hDC);
  return (bResult == NULL ? NULL : hbmpSystem);

}


void ChangeChildSysMenu (hwnd)
HWND hwnd;
{
  HMENU hChildMenu;

  hChildMenu = GetSystemMenu(hwnd, FALSE);
  ChangeMenu(hChildMenu, 0, "Restore\tCtrl+F5", SC_RESTORE,
               MF_CHANGE | MF_BYPOSITION | MF_GRAYED); 
  ChangeMenu(hChildMenu, 1, "Move\tCtrl+F7", SC_MOVE,
               MF_CHANGE | MF_BYPOSITION);
  ChangeMenu(hChildMenu, 2, "Size\tCtrl+F8", SC_SIZE,
               MF_CHANGE | MF_BYPOSITION);
  ChangeMenu(hChildMenu, 3, NULL, NULL, 
               MF_DELETE | MF_BYPOSITION);
  ChangeMenu(hChildMenu, 3, "Maximize\tCtrl+F10", SC_MAXIMIZE,
               MF_CHANGE | MF_BYPOSITION);
  ChangeMenu(hChildMenu, 5, "Close\tCtrl+F4", SC_CLOSE,
               MF_CHANGE | MF_BYPOSITION);
}


/*  Help is the dialog box function used to process messages for both the
    'About' and 'General' dialog boxes called from the 'Help' menu. */ 

BOOL FAR PASCAL Help(hDlg, message, wParam, lParam)
HWND     hDlg;
unsigned message;
WORD     wParam;
LONG     lParam;
{
  if (message == WM_COMMAND) {
    EndDialog(hDlg, TRUE);
    return TRUE;
  }
  else
    if (message == WM_INITDIALOG)
         return TRUE;
    else return FALSE;
}



/*  New is the dialog box function used to process messages for the 'New'
    dialog box called from the 'File' menu. */

BOOL FAR PASCAL New(hDlg, message, wParam, lParam)
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{
  static int ChildType;

  switch (message)
      {
  case WM_INITDIALOG:
      ChildType = IDDRED;
      CheckRadioButton(hDlg, IDDRED, IDDBLUE, ChildType);
      return TRUE;

  case WM_COMMAND:
      switch (wParam) {
        case IDDRED:
        case IDDGREEN:
        case IDDBLUE:
            ChildType = wParam;
            CheckRadioButton(hDlg, IDDRED, IDDBLUE, wParam);
            return TRUE;

        case IDDOK:
            EndDialog(hDlg, TRUE);
            DisplayChild(ChildType);
            break;

        case IDDCANCEL:
            EndDialog(hDlg, TRUE);
            break;

        default:
            return FALSE;
      } /* end switch */
      break;

  default:
      return FALSE;
      }
}



int CchFromSz(psz)
char *psz;
{
  register char *pszTmp;

  for (pszTmp = psz; *pszTmp; pszTmp++)
      ;
  return(pszTmp - psz);
}


/* rgpoint[1] will be size, rgpoint[2] will be position */

void GetMaxChildSize(rgpoint)
LPPOINT rgpoint;
{
  RECT rc;

  GetClientRect(hwndParent, (LPRECT)&rc);
  rgpoint[1].x = rc.right - rc.left + 2 * GetSystemMetrics(SM_CXFRAME);
  rgpoint[1].y = rc.bottom - rc.top + 2 * GetSystemMetrics(SM_CYFRAME) +
                  GetSystemMetrics(SM_CYCAPTION);
  rgpoint[2].y -= GetSystemMetrics(SM_CYCAPTION); 
}
