home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk12 / mdi / mdidoc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-06  |  45.0 KB  |  1,468 lines

  1. /***************************************************************************\
  2. * mdidoc.c - MDI application
  3. *
  4. * Created by Microsoft Corporation, 1989
  5. \***************************************************************************/
  6.  
  7. #define INCL_WINSYS
  8. #define INCL_WINCOMMON
  9. #define INCL_WINMESSAGEMGR
  10. #define INCL_WINFRAMEMGR
  11. #define INCL_WINPOINTERS
  12. #define INCL_WINMENUS
  13. #define INCL_WINWINDOWMGR
  14. #define INCL_WINACCELERATORS
  15. #define INCL_WININPUT
  16. #define INCL_WINHEAP
  17. #define INCL_WINSCROLLBARS
  18. #define INCL_WINRECTANGLES
  19. #define INCL_WINCOUNTRY
  20. #define INCL_WINDIALOGS
  21. #define INCL_GPIPRIMITIVES
  22. #define INCL_GPILOGCOLORTABLE
  23.  
  24. #include <os2.h>
  25. #include <string.h>
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include "app.h"
  29. #include "appdata.h"
  30. #include "mdi.h"
  31. #include "mdidata.h"
  32.  
  33. BOOL fDestroying=FALSE;
  34.  
  35. /* Function Prototypes */
  36. VOID BuildWindowMenu(VOID);
  37. VOID TrackSplitbars(HWND, USHORT, SHORT, SHORT);
  38. MRESULT MDIFormatFrame(HWND hwnd, PSWP aswp, MPARAM mp2);
  39. MRESULT MDIMinMaxFrame(HWND hwnd, MPARAM mp1, MPARAM mp2);
  40.  
  41. VOID SetMainTitleText(HWND hwndDocFrame)
  42. {
  43.     char szDocTitle[80], szMainTitle[80];
  44.  
  45.     /*
  46.      * Get the titlebar text for the specified document window.
  47.      */
  48.     WinQueryWindowText(hwndDocFrame, 80, (PSZ)szDocTitle);
  49.  
  50.     /*
  51.      * Build up the correct text for the main window.
  52.      */
  53.     strcpy(szMainTitle, " - ");
  54.     strcat(szMainTitle, szDocTitle);
  55.  
  56.     /*
  57.      * Set the main window's titlebar to the new text.
  58.      */
  59.     WinSetWindowText(hwndMDIFrame, szMainTitle);
  60. }
  61.  
  62.  
  63. VOID ClearMainTitleText(VOID)
  64. {
  65.     WinSetWindowText(hwndMDIFrame, "");
  66. }
  67.  
  68.  
  69. /* *********************************************************************** *\
  70.  * AddToWindowMenu
  71.  *
  72.  * This routines adds a new document to the WINDOW submenu of each document's
  73.  * menu so that when any doc is active you can select the other documents
  74.  * by selecting it on the main menu bar
  75.  *
  76.  * History:
  77.  *
  78.  *      19-Oct-1989 Added multiple menu capabilities -johnba
  79.  *
  80. \* *********************************************************************** */
  81.  
  82. /* MULTIPLEMENU */
  83.  
  84. VOID AddToWindowMenu(NPDOC npdocNew)
  85. {
  86.     MENUITEM mi,miDoc;
  87.     char szItemText[1];
  88.     char szTitleNew[128], szTitleCompare[128];
  89.     register NPDOC npdoc, npdocPrev;
  90.     USHORT usRes;
  91.  
  92.     HWND hwndWindowMenu;
  93.     USHORT index;
  94.  
  95.  
  96.     /*
  97.      * Add the document to the DOCLIST.
  98.      */
  99.     if (npdocFirst == NULL) {
  100.         npdocFirst = npdocNew;
  101.  
  102.         /*
  103.          * Fill in the DOCLIST for this doc.
  104.          */
  105.         npdocNew->idMI = NULL;
  106.         npdocNew->npdocNext = NULL;
  107.         }
  108.  
  109.     else {
  110.  
  111.         /*
  112.          * Add the item in the correct
  113.          * sorted location.
  114.          */
  115.         npdoc = npdocFirst;
  116.         npdocPrev = NULL;
  117.  
  118.         while (npdoc != NULL) {
  119.             WinQueryWindowText(npdoc->hwndFrame, 128, szTitleCompare);
  120.             WinQueryWindowText(npdocNew->hwndFrame, 128, szTitleNew);
  121.             WinUpper(NULL, NULL, NULL, szTitleCompare);
  122.             WinUpper(NULL, NULL, NULL, szTitleNew);
  123.  
  124.             usRes = WinCompareStrings(NULL, NULL, NULL, szTitleNew,
  125.                     szTitleCompare, NULL);
  126.  
  127.             if (usRes == WCS_LT) {
  128.                 if (npdocPrev == NULL) {
  129.                     npdocFirst = npdocNew;
  130.                     npdocFirst->npdocNext = npdoc;
  131.                     }
  132.                 else {
  133.                     npdocPrev->npdocNext = npdocNew;
  134.                     npdocNew->npdocNext = npdoc;
  135.                     }
  136.  
  137.                 /*
  138.                  * Fill in the DOC for this document.
  139.                  */
  140.                 npdocNew->idMI = NULL;
  141.                 break;
  142.                 }
  143.             else {
  144.                 if (npdoc->npdocNext == NULL) {
  145.                     /*
  146.                      * If we've made it to the end,
  147.                      * just tack it on here.
  148.                      */
  149.                     npdoc->npdocNext =  npdocNew;
  150.  
  151.                     /*
  152.                      * Fill in the DOC for this document.
  153.                      */
  154.                     npdocNew->idMI = NULL;
  155.                     npdocNew->npdocNext = NULL;
  156.                     }
  157.                 }
  158.             npdocPrev = npdoc;
  159.             npdoc = npdoc->npdocNext;
  160.             }
  161.  
  162.         }
  163.  
  164.  
  165. /*  Add menu items to the new doc's menu to make all doc's window menus
  166.     have the same number of docs before this one was added */
  167.  
  168.     /* Get the hwnd to the IDM_WINDOW submenu for this npdoc's menu bar */
  169.     WinSendMsg(npdocNew->hwndMainMenu, MM_QUERYITEM,
  170.                 MPFROM2SHORT(IDM_WINDOW, FALSE), MPFROMP(&mi));
  171.     hwndWindowMenu = mi.hwndSubMenu;
  172.  
  173.     /* build blank menuitem structure for all documents */
  174.  
  175.     mi.iPosition = MIT_END;
  176.     mi.afStyle = MIS_TEXT;
  177.     mi.afAttribute = 0;
  178.     mi.hwndSubMenu = NULL;
  179.     mi.hItem = NULL;
  180.     szItemText[0] = '\0';
  181.  
  182.     for(index=1; index<=cDocs; index++) {
  183.  
  184.         mi.id = CMD_WINDOWITEMS + index;
  185.  
  186.         WinSendMsg(hwndWindowMenu, MM_INSERTITEM, MPFROMP(&mi),
  187.                 MPFROMP(szItemText));
  188.         }
  189.  
  190.     cDocs++;
  191.  
  192.     /* Now all the document window menus are similiar so we can now add the
  193.        new menu to each of them */
  194.  
  195.     /* build menuitem structure for this document */
  196.     miDoc.iPosition = MIT_END;
  197.     miDoc.afStyle = MIS_TEXT;
  198.     miDoc.afAttribute = 0;
  199.     miDoc.id = CMD_WINDOWITEMS + cDocs;
  200.     miDoc.hwndSubMenu = NULL;
  201.     miDoc.hItem = NULL;
  202.     szItemText[0] = '\0';
  203.  
  204.     npdoc=npdocFirst;
  205.  
  206.     /* insert a blank item into EVERY document's menu */
  207.     while (npdoc!=NULL) {
  208.  
  209.         /* This gets the hwnd to the IDM_WINDOW submenu for this npdoc's
  210.            menu bar. */
  211.  
  212.         WinSendMsg(npdoc->hwndMainMenu, MM_QUERYITEM,
  213.                     MPFROM2SHORT(IDM_WINDOW, FALSE), MPFROMP(&mi));
  214.         hwndWindowMenu = mi.hwndSubMenu;
  215.  
  216.         /*
  217.          * Insert a blank item into the menu.
  218.          */
  219.  
  220.         WinSendMsg(hwndWindowMenu, MM_INSERTITEM, MPFROMP(&miDoc),
  221.                 MPFROMP(szItemText));
  222.  
  223.         npdoc=npdoc->npdocNext;
  224.         }
  225.  
  226.     npdocNew->idMI=miDoc.id; /* Set the ID for the menu item of the new document */
  227.  
  228.     BuildWindowMenu();
  229. }
  230.  
  231.  
  232. VOID RemoveFromWindowMenu(NPDOC npdocRemove)
  233. {
  234.     register NPDOC npdoc, npdocPrev;
  235.  
  236.     MENUITEM mi;
  237.  
  238.     HWND hwndWindowMenu;
  239.  
  240.  
  241.     npdoc=npdocFirst;
  242.  
  243.     while (npdoc!=NULL) {
  244.  
  245.         /* This gets the hwnd to the IDM_WINDOW submenu for this npdoc's
  246.            menu bar. */
  247.  
  248.         /*
  249.          * If the window menu is gone no need to
  250.          * do any of this stuff.  This can happen
  251.          * when the MDI app is closing.
  252.          */
  253.  
  254.         if (WinIsWindow(hab, npdoc->hwndMainMenu)) {
  255.  
  256.  
  257.             WinSendMsg(npdoc->hwndMainMenu, MM_QUERYITEM,
  258.                         MPFROM2SHORT(IDM_WINDOW, FALSE), MPFROMP(&mi));
  259.             hwndWindowMenu = mi.hwndSubMenu;
  260.  
  261.             /* Delete item from menu */
  262.             WinSendMsg(hwndWindowMenu, MM_DELETEITEM,
  263.                     MPFROM2SHORT(npdocRemove->idMI, FALSE), NULL);
  264.  
  265.             }
  266.         npdoc=npdoc->npdocNext;
  267.         }
  268.  
  269.     /*
  270.      * Remove the DOC from the linked-list.
  271.      */
  272.     if (npdocFirst != NULL) {
  273.  
  274.         /*
  275.          * Initialize these for our while loop.
  276.          */
  277.         npdoc = npdocFirst;
  278.         npdocPrev = NULL;
  279.  
  280.         while (npdoc != NULL) {
  281.  
  282.             /*
  283.              * If we've found the element unlink
  284.              * it from the list.
  285.              */
  286.             if (npdoc == npdocRemove) {
  287.  
  288.                 /*
  289.                  * Unlink this document.
  290.                  */
  291.                 if (npdocPrev != NULL)
  292.                     npdocPrev->npdocNext = npdoc->npdocNext;
  293.                 else
  294.                     npdocFirst = npdoc->npdocNext;
  295.  
  296.                 /*
  297.                  * Break out of the while loop,
  298.                  * we're done here.
  299.                  */
  300.                 break;
  301.  
  302.            /*   cDocs--;  */  /* ?????????????????  this will help the menus
  303.                              sort of.  It will cause problems when we try
  304.                              to reuse the same ID again in a new document window
  305.                              ?????????????????????
  306.                           */
  307.  
  308.             }
  309.             npdocPrev = npdoc;
  310.             npdoc = npdoc->npdocNext;
  311.         }
  312.     }
  313.  
  314.     /* If we are terminating the app, don't try to build the menu since it
  315.         will make a mess */
  316.  
  317.     if (!fDestroying) {
  318.         BuildWindowMenu();
  319.         }
  320. }
  321.  
  322.  
  323. /* *********************************************************************** *\
  324.  * BuildWindowMenu
  325.  *
  326.  * This routine fills in the IDM_WINDOW submenu items with the titles of
  327.  * all the document windows.  It uses the first doc's submenu as a base to
  328.  * determine the ID's of the MENUITEMs and then changes the in the IDM_WINDOW
  329.  * submenu off ALL the document's menu bars.
  330.  *
  331.  * History:
  332.  *
  333.  *      19-Oct-1989 Added multiple menu capabilities -johnba
  334.  *
  335. \* *********************************************************************** */
  336.  
  337. /* MULTIPLEMENU */
  338.  
  339. VOID BuildWindowMenu(VOID)
  340. {
  341.     register NPDOC npdoc;
  342.     NPDOC npdocSetItem;
  343.     char szDocTitle[80];
  344.     char szItemText[80];
  345.     USHORT cWindows;
  346.  
  347.     /*
  348.      * Get the position of the first
  349.      * window in the Window menu.
  350.      */
  351.  
  352.     MENUITEM mi;
  353.     HWND hwndFirstWindowMenu;
  354.     HWND hwndMenu;
  355.  
  356.     if (npdocFirst==NULL) {
  357.         WinSetParent(hwndFirstMenu, hwndMDIFrame, FALSE);
  358.         WinSendMsg(hwndMDIFrame, WM_UPDATEFRAME, 0L, 0L);
  359.         return;
  360.         }
  361.  
  362.  
  363.     /* first query the hwnd of the IDM_WINDOW submenu which will be used
  364.        to determine the ID's of all the IDM_WINDOW subitems. */
  365.     hwndMenu = npdocFirst->hwndMainMenu;
  366.     WinSendMsg(hwndMenu, MM_QUERYITEM, MPFROM2SHORT(IDM_WINDOW, FALSE),
  367.                MPFROMP(&mi));
  368.     hwndFirstWindowMenu = mi.hwndSubMenu;
  369.  
  370.     npdoc = npdocFirst;
  371.     cWindows = 1;
  372.  
  373.     /* scan the documents to get the text of each of their title bars and
  374.        build the item text for each documents entry in the submenu */
  375.     while (npdoc != NULL) {
  376.  
  377.         /*
  378.          * Build the item string.
  379.          */
  380.         szItemText[0] = '~';
  381.         itoa(cWindows, szItemText + 1, 10);
  382.         strcat(szItemText, " ");
  383.         WinQueryWindowText(npdoc->hwndFrame, 80, (PSZ)szDocTitle);
  384.         strcat(szItemText, szDocTitle);
  385.  
  386.  
  387.         /* Now for each item loop through the documents, setting the text of
  388.            this menu item for each of their submenu's */
  389.         npdocSetItem=npdocFirst;
  390.  
  391.         while (npdocSetItem !=NULL) {
  392.  
  393.             HWND hwndWindowMenu;
  394.  
  395.             hwndMenu = npdocSetItem->hwndMainMenu;
  396.             WinSendMsg(hwndMenu, MM_QUERYITEM,
  397.                         MPFROM2SHORT(IDM_WINDOW, FALSE),
  398.                         MPFROMP(&mi));
  399.             hwndWindowMenu = mi.hwndSubMenu;
  400.  
  401.  
  402.             /*
  403.              * Set the item text for the menuitem.
  404.              */
  405.             WinSendMsg(hwndWindowMenu, MM_SETITEMTEXT,
  406.                     MPFROMSHORT(npdoc->idMI),
  407.                     MPFROMP(szItemText));
  408.  
  409.             /*
  410.              * Clear out the previous attributes.
  411.              */
  412.             WinSendMsg(hwndWindowMenu, MM_SETITEMATTR,
  413.                         MPFROM2SHORT(npdoc->idMI, FALSE),
  414.                         MPFROM2SHORT(MIA_CHECKED, 0));
  415.  
  416.             npdocSetItem=npdocSetItem->npdocNext;
  417.             }
  418.  
  419.         cWindows++;
  420.         npdoc = npdoc->npdocNext;
  421.     }
  422. }
  423.  
  424.  
  425. NPDOC MdiNewDocument(USHORT fsStyle, PSZ pszClassName)
  426. {
  427.     ULONG ctlData, flStyle;
  428.     HWND hwndNewFrame, hwndNewClient, hwndSysMenu;
  429.     HWND hwndMenu;          /* added to handle different menus for each doc
  430.                                    17-Oct-1989 */
  431.     register NPDOC npdocNew;
  432.     register NPVIEW npview;
  433.     char szDocTitle[80], szDocNumber[4];
  434.  
  435.     /*  make sure there's no current menu on the frame */
  436.     WinSetParent(WinWindowFromID(hwndMDIFrame, FID_MENU), HWND_OBJECT, FALSE);
  437.  
  438.     usDocNumber++;
  439.  
  440.     /*
  441.      * Setup the window's titlebar text.
  442.      */
  443.     itoa(usDocNumber, szDocNumber, 10);
  444.     strcpy(szDocTitle, "Untitled");
  445.     strcat(szDocTitle, szDocNumber);
  446.  
  447.     ctlData = FCF_TITLEBAR | FCF_MINMAX | FCF_SIZEBORDER |
  448.             FCF_VERTSCROLL | FCF_HORZSCROLL;
  449.  
  450.     hwndNewFrame = WinCreateStdWindow(hwndMDI,
  451.             FS_ICON | FS_ACCELTABLE,
  452.             (VOID FAR *)&ctlData,
  453.             pszClassName, szDocTitle,
  454.             WS_VISIBLE,
  455.             (HMODULE)NULL, IDR_MDIDOC,
  456.             (HWND FAR *)&hwndNewClient);
  457.  
  458. /* MULTIPLEMENU */
  459.  
  460.     switch (cDocs) {
  461.         case 0:  /* This is the first document */
  462.             hwndMenu=WinLoadMenu(hwndMDIFrame, NULL, IDR_DOC1MENU);
  463.             break;
  464.  
  465.         case 1:
  466.             hwndMenu=WinLoadMenu(hwndMDIFrame, NULL, IDR_DOC2MENU);
  467.             break;
  468.  
  469.         case 2:
  470.             hwndMenu=WinLoadMenu(hwndMDIFrame, NULL, IDR_DOC3MENU);
  471.             break;
  472.  
  473.         case 3:
  474.             hwndMenu=WinLoadMenu(hwndMDIFrame, NULL, IDR_DOC4MENU);
  475.             break;
  476.  
  477.         case 4:
  478.             hwndMenu=WinLoadMenu(hwndMDIFrame, NULL, IDR_DOC5MENU);
  479.             break;
  480.  
  481.         default:
  482.             hwndMenu=WinLoadMenu(hwndMDIFrame, NULL, IDR_DOCXMENU);
  483.             break;
  484.         }
  485.  
  486.     /* The menu needs to be owned by the frame so that its WM_COMMAND messages
  487.        will get sent to the frame to be processed.
  488.     */
  489.  
  490.     WinSetParent(hwndMenu, HWND_OBJECT, FALSE);
  491.  
  492.     npdocNew = (NPDOC)WinAllocMem(hHeap, sizeof(DOC));
  493.     if (npdocNew == NULL)
  494.         return (FALSE);
  495.  
  496.     npdocNew->hwndFrame = hwndNewFrame;
  497. /* MULTIPLEMENU */
  498.     npdocNew->hwndMainMenu = hwndMenu;              /* new for multiple menus */
  499.     npdocNew->fAabSysMenu=FALSE;
  500.  
  501.     npdocNew->cxVertSplitPos = 0;
  502.     npdocNew->cyHorzSplitPos = 0;
  503.     npdocNew->fs = 0;
  504.     npdocNew->fsStyle = fsStyle;
  505.  
  506.     npview = NPVIEWFROMCLIENT(hwndNewClient);
  507.     npview->npdoc = npdocNew;
  508.  
  509.     /*
  510.      * Link in the VIEW for FID_CLIENT since we
  511.      * know it exists.
  512.      */
  513.     npdocNew->npviewFirst = npview;
  514.  
  515.     /*
  516.      * Create the 'splitbar' controls for the frame.
  517.      * This includes the splitbar and the extra client
  518.      * and scrollbar windows.  This routine will also
  519.      * link the appropriate VIEWs into the DOC structure.
  520.      */
  521.     if (fsStyle & (DS_HORZSPLITBAR | DS_VERTSPLITBAR)) {
  522.         if (CreateSplitbarWindows(hwndNewFrame, npdocNew) == FALSE) {
  523.             WinDestroyWindow(hwndNewFrame);
  524.             return (FALSE);
  525.         }
  526.     }
  527.  
  528.     /*
  529.      * Load in the document window's system menu.
  530.      */
  531.     hwndSysMenu = WinLoadMenu(hwndNewFrame, (HMODULE)NULL, IDM_DOCSYSMENU);
  532.  
  533.     /*
  534.      * Make it look like a normal system menu to the frame manager so
  535.      * gets formatted correctly etc.
  536.      */
  537.     flStyle = WinQueryWindowULong(hwndSysMenu, QWL_STYLE);
  538.     WinSetWindowULong(hwndSysMenu, QWL_STYLE, flStyle | MS_TITLEBUTTON);
  539.     WinSetWindowUShort(hwndSysMenu, QWS_ID, FID_SYSMENU);
  540.  
  541.     /*
  542.      * Set the bitmap to the SBMP_CHILDSYSMENU bitmap.
  543.      */
  544.     WinSendMsg(hwndSysMenu, MM_SETITEMHANDLE, (MPARAM)SC_DOCSYSMENU,
  545.             (MPARAM)hbmChildSysMenu);
  546.  
  547.     /*
  548.      * Set the menu window handles in the DOC structure so these
  549.      * controls can be hidden/shown at the correct time.
  550.      */
  551.     npdocNew->hwndSysMenu = hwndSysMenu;
  552.     npdocNew->hwndMinmax = WinWindowFromID(hwndNewFrame, FID_MINMAX);
  553.  
  554.     /*
  555.      * Subclass the frame so we can handle the accelerators
  556.      * and other MDI stuff.
  557.      */
  558.  
  559.     pfnFrameWndProc = WinSubclassWindow(hwndNewFrame,
  560.             (PFNWP)DocFrameWndProc);
  561.     /*
  562.      * Add the window to the Window menu.
  563.      */
  564.  
  565.  /*    AddToWindowMenu(npdocNew);
  566.  */
  567.     return (npdocNew);
  568. }
  569.  
  570.  
  571. VOID MDISetInitialDocPos(HWND hwndNewFrame)
  572. {
  573.     WinSetWindowPos(hwndNewFrame, NULL, xNextNewDoc, yNextNewDoc,
  574.             cxNewDoc, cyNewDoc, SWP_MOVE | SWP_SIZE | SWP_SHOW);
  575.  
  576.     /*
  577.      * Insert logic to change xNextNewDoc/yNextNewDoc and cxNewDoc/cyNewDoc.
  578.      */
  579. }
  580.  
  581. /* ********************************************************************** *\
  582.  * AddAabSysMenu - adds the sys menu to the menu bar for the given        *
  583.                    document frame window.
  584.  
  585.    History:
  586.     20-Oct-1989 modified to pass an hwnd of the doc frame to add
  587.                 the menu to. -johnba
  588.  
  589. \* ********************************************************************** */
  590.  
  591. VOID AddAabSysMenu(HWND hwnd)
  592. {
  593.     HWND hwndMenu;
  594.     NPDOC npdoc;
  595.  
  596.     npdoc=NPDOCFROMCLIENT(WinWindowFromID(hwnd, FID_CLIENT));
  597.     hwndMenu=npdoc->hwndMainMenu;
  598.  
  599.     if (npdoc->fAabSysMenu == FALSE) {
  600.         WinSendMsg(hwndMenu, MM_INSERTITEM, MPFROMP(&miAabSysMenu),
  601.                 (MPARAM)NULL);
  602.         npdoc->fAabSysMenu = TRUE;
  603.     }
  604. }
  605.  
  606. /* ********************************************************************** *\
  607.  * RemoveAabSysMenu - removes the sys menu from the menu bar for the given        *
  608.                       document frame window.
  609.  
  610.    History:
  611.     20-Oct-1989 modified to pass an hwnd of the doc frame to remove
  612.                 the menu from. -johnba
  613.  
  614. \* ********************************************************************** */
  615.  
  616.  
  617.  
  618.  
  619. VOID RemoveAabSysMenu(HWND hwnd)
  620. {
  621.     HWND hwndMenu;
  622.     NPDOC npdoc;
  623.  
  624.     npdoc=NPDOCFROMCLIENT(WinWindowFromID(hwnd, FID_CLIENT));
  625.     hwndMenu=npdoc->hwndMainMenu;
  626.  
  627.     if (npdoc->fAabSysMenu == TRUE) {
  628.         WinSendMsg(hwndMenu, MM_REMOVEITEM,
  629.                 MPFROMSHORT(IDM_AABDOCSYSMENU), (MPARAM)FALSE);
  630.         npdoc->fAabSysMenu = FALSE;
  631.     }
  632. }
  633.  
  634.  
  635. BOOL MDICreate(HWND hwndClient)
  636. {
  637.     register NPVIEW npview;
  638.  
  639.     /*
  640.      * Allocate the DOC structure for this window and stick it in
  641.      * the window structure of the client.
  642.      */
  643.  
  644.     npview = (NPVIEW)WinAllocMem(hHeap, sizeof(VIEW));
  645.     if (npview == NULL)
  646.         return (FALSE);
  647.  
  648.     npview->xOrigin = 0;
  649.     npview->yOrigin = 0;
  650.     npview->fs = 0;
  651.     npview->npviewNext = NULL;
  652.     npview->hwndClient = hwndClient;
  653.  
  654.     WinSetWindowUShort(hwndClient, QWS_USER, (USHORT)npview);
  655.  
  656.     return (TRUE);
  657. }
  658.  
  659.  
  660. VOID MDIActivate(HWND hwndClient, BOOL fActivate)
  661. {
  662.     HWND hwndFrame;
  663.     register NPDOC npdoc;
  664.  
  665.  
  666.     MENUITEM mi;
  667.     HWND hwndWindowMenu;
  668.     HWND hwndNewMenu;
  669.     HWND hwndOldMenu;
  670.  
  671.  
  672.     /*
  673.      * If our active status is changing, show/hide the AAB Sysmenu, check
  674.      * the correct item on the Window menu, and show/hide the titlebar
  675.      * frame controls.  Also change the main menu bar  17-Oct-1989 johnba
  676.      */
  677.  
  678.     hwndFrame = WinQueryWindow(hwndClient, QW_PARENT, FALSE);
  679.  
  680.     npdoc = NPDOCFROMCLIENT(hwndClient);
  681.     if (fActivate != FALSE) {
  682.  
  683.         /* Receiving activation */
  684.  
  685.         hwndOldMenu = WinWindowFromID(hwndMDIFrame, FID_MENU);
  686.  
  687.         if (hwndOldMenu!=NULL) {
  688.  
  689.             WinSendMsg(hwndOldMenu, MM_QUERYITEM, MPFROM2SHORT(IDM_WINDOW, FALSE),
  690.                        MPFROMP(&mi));
  691.             hwndWindowMenu = mi.hwndSubMenu;
  692.             }
  693.  
  694.         hwndNewMenu=NPDOCFROMCLIENT(hwndClient)->hwndMainMenu;
  695.  
  696.         if (hwndOldMenu!=NULL) {
  697.             WinSendMsg(hwndOldMenu, MM_REMOVEITEM,
  698.                     MPFROMSHORT(IDM_AABDOCSYSMENU),
  699.                     (MPARAM)FALSE);
  700.  
  701.             /* hide current menu */
  702.             WinSetParent(hwndOldMenu, HWND_OBJECT, FALSE);
  703.  
  704.             /*
  705.              * Uncheck the appropriate item on the Window menu.
  706.              */
  707.             WinSendMsg(hwndWindowMenu, MM_SETITEMATTR,
  708.                     MPFROM2SHORT(npdoc->idMI, FALSE),
  709.                     MPFROM2SHORT(MIA_CHECKED, 0));
  710.             }
  711.  
  712.  
  713.         /* put new menu on main frame window */
  714.         WinSetParent(hwndNewMenu, hwndMDIFrame, FALSE);
  715.         WinSendMsg(hwndMDIFrame, WM_UPDATEFRAME, 0L, 0L);
  716.  
  717.         if (WinQueryWindowULong(hwndFrame, QWL_STYLE) & WS_MAXIMIZED) {
  718.             WinSendMsg(hwndNewMenu, MM_INSERTITEM,
  719.                     MPFROMP(&miAabSysMenu),
  720.                     (MPARAM)NULL);
  721.             }
  722.  
  723.  
  724.         WinSendMsg(hwndNewMenu, MM_QUERYITEM, MPFROM2SHORT(IDM_WINDOW, FALSE),
  725.                    MPFROMP(&mi));
  726.         hwndWindowMenu = mi.hwndSubMenu;
  727.  
  728.         hwndActiveDoc = hwndFrame; /* remember the active window in a global */
  729.  
  730.         /*
  731.          * Check the appropriate item on the Window menu.
  732.          */
  733.         WinSendMsg(hwndWindowMenu, MM_SETITEMATTR,
  734.                 MPFROM2SHORT(npdoc->idMI, FALSE),
  735.                 MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED));
  736.  
  737.         /*
  738.          * Show the titlebar frame controls.
  739.          */
  740.  
  741.         WinSetParent(npdoc->hwndSysMenu, hwndFrame, FALSE);
  742.         WinSetParent(npdoc->hwndMinmax, hwndFrame, FALSE);
  743.  
  744.         WinSendMsg(hwndFrame, WM_UPDATEFRAME, 0L, 0L);
  745.  
  746.     } else {
  747.         /* Losing activation */
  748.  
  749.  
  750.         /*
  751.          * Remove the titlebar frame controls.
  752.          */
  753.  
  754.         /* Need to hide them before setting the parent to HWND_OBJECT so
  755.            that they get painted right when they are restored. 02-Aug-1989 */
  756.  
  757.         WinShowWindow(npdoc->hwndSysMenu, FALSE);
  758.         WinShowWindow(npdoc->hwndMinmax, FALSE);
  759.  
  760.         WinSetParent(npdoc->hwndSysMenu, HWND_OBJECT, FALSE);
  761.         WinSetParent(npdoc->hwndMinmax, HWND_OBJECT, FALSE);
  762.  
  763.         WinSendMsg(hwndFrame, WM_UPDATEFRAME, 0L, 0L);
  764.     }
  765. }
  766.  
  767.  
  768. VOID MDIDestroy(HWND hwndClient)
  769. {
  770.  
  771.     WinFreeMem(hHeap, (NPBYTE)WinQueryWindowUShort(hwndClient, QWS_USER),
  772.             sizeof(VIEW));
  773. }
  774.  
  775.  
  776. VOID MDIClose(HWND hwndClient)
  777. {
  778.     WinDestroyWindow(WinQueryWindow(hwndClient, QW_PARENT, FALSE));
  779. }
  780.  
  781. struct ARECTL {
  782.     RECTL rclSrc;
  783.     RECTL rclDest;
  784.     };
  785.  
  786.  
  787.  
  788. MRESULT EXPENTRY DocFrameWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  789. {
  790.     MRESULT mres;
  791.     USHORT cFrameCtls;
  792.     HWND hwndParent, hwndClient;
  793.     register NPDOC npdoc;
  794.     RECTL rclClient;
  795.  
  796. struct ARECTL far *prcl;
  797.  
  798.     PSWP    pswp;
  799.  
  800.     switch (msg) {
  801.  
  802.     case WM_ADJUSTWINDOWPOS:
  803.         return (*pfnFrameWndProc)(hwnd, msg, mp1, mp2);
  804.         break;
  805.  
  806.     case WM_SYSCOMMAND:
  807.         if (SHORT1FROMMP(mp1) == SC_SPLIT) {
  808.             WinSetPointer(HWND_DESKTOP, hptrHVSplit);
  809.             TrackSplitbars(WinWindowFromID(hwnd, FID_CLIENT),
  810.                     SPS_HORZ | SPS_VERT, -1, -1);
  811.             WinSetPointer(HWND_DESKTOP, hptrArrow);
  812.         } else if (SHORT1FROMMP(mp2) == (SHORT) CMDSRC_ACCELERATOR) {
  813.  
  814.             /*
  815.              * If the command was sent because of an accelerator
  816.              * we need to see if it goes to the document or the main
  817.              * frame window.
  818.              */
  819.             if ((WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000)) {
  820.  
  821.                 /*
  822.                  * If the control key is down we'll send it
  823.                  * to the document's frame since that means
  824.                  * it's either ctl-esc or one of the document
  825.                  * window's accelerators.
  826.                  */
  827.                 return (*pfnFrameWndProc)(hwnd, msg, mp1, mp2);
  828.             } else if (SHORT1FROMMP(mp1) == SC_DOCSYSMENU) {
  829.  
  830.                 /*
  831.                  * If the window is maximized then we want
  832.                  * to pull down the system menu on the main
  833.                  * menu bar.
  834.                  */
  835.                 if ((WinQueryWindowULong(hwnd, QWL_STYLE) & WS_MAXIMIZED) &&
  836.                         (SHORT1FROMMP(mp1) == SC_DOCSYSMENU)) {
  837.                     WinPostMsg(miAabSysMenu.hwndSubMenu, MM_STARTMENUMODE,
  838.                             MPFROM2SHORT(TRUE, FALSE), 0L);
  839.                     return (0L);
  840.                 } else {
  841.                     WinPostMsg(WinWindowFromID(hwnd, FID_SYSMENU),
  842.                             MM_STARTMENUMODE, MPFROM2SHORT(TRUE, FALSE), 0L);
  843.                 }
  844.             } else {
  845.                 /*
  846.                  * Control isn't down so send it the main
  847.                  * frame window.
  848.                  */
  849.                 return WinSendMsg(hwndMDIFrame, msg, mp1, mp2);
  850.             }
  851.         } else {
  852.             /*
  853.              * WM_SYSCOMMAND not caused by an accelerator
  854.              * so hwnd is the window we want to send the
  855.              * message to.
  856.              */
  857.             return (*pfnFrameWndProc)(hwnd, msg, mp1, mp2);
  858.         }
  859.         break;
  860.  
  861.     case WM_NEXTMENU:
  862.         /*
  863.          * Connect child sysmenu with application menus for cursor motion.
  864.          * Only return a value if we're the System Menu.  We don't want the
  865.          * MinMax menu or any others that might be there to freak out.
  866.          */
  867.         if (WinQueryWindowUShort(HWNDFROMMP(mp1), QWS_ID) == FID_SYSMENU) {
  868.             if (SHORT1FROMMP(mp2)) {
  869.                 return (MRESULT)hwndSysMenu;
  870.                 }
  871.             else {
  872.                 /* return (MRESULT) hwndAppMenu; */
  873.                 return (MRESULT) (NPDOCFROMCLIENT(WinWindowFromID(hwnd, FID_CLIENT))
  874.                                         ->hwndMainMenu);
  875.                 }
  876.         } else {
  877.             return (0L);
  878.         }
  879.         break;
  880.  
  881.     case WM_MINMAXFRAME:
  882.         return (MDIMinMaxFrame(hwnd, mp1, mp2));
  883.         break;
  884.  
  885.     case WM_WINDOWPOSCHANGED: 
  886.  
  887. #define aswp    ((PSWP)mp1)
  888.  
  889.         npdoc = NPDOCFROMCLIENT(WinWindowFromID(hwnd, FID_CLIENT));
  890.         if (((PSWP)mp1)->fs & SWP_SIZE) {
  891.  
  892.             if (npdoc->fs & (DF_SPLITHORZ | DF_HSPLITOVERFLOW)) {
  893.                 /*
  894.                  * If we were sized then adjust the horizontal splitbar
  895.                  * to be top-aligned.
  896.                  */
  897.                 npdoc->cyHorzSplitPos += (aswp[0].cy - aswp[1].cy);
  898.  
  899.                 /*
  900.                  * Set or clear the DF_HSPLITOVERFLOW and DF_SPLITHORZ flags.
  901.                  */
  902.                 if (npdoc->cyHorzSplitPos < 0) {
  903.                     npdoc->fs |= DF_HSPLITOVERFLOW;
  904.                     npdoc->fs &= ~DF_SPLITHORZ;
  905.                 } else {
  906.                     npdoc->fs &= ~DF_HSPLITOVERFLOW;
  907.                     npdoc->fs |= DF_SPLITHORZ;
  908.                 }
  909.             }
  910.  
  911.             if (npdoc->fs & (DF_SPLITVERT | DF_VSPLITOVERFLOW)) {
  912.  
  913.                 WinQueryWindowRect(hwnd, &rclClient);
  914.                 WinCalcFrameRect(hwnd, &rclClient, TRUE);
  915.  
  916.                 /*
  917.                  * Set or clear the DF_VSPLITOVERFLOW and DF_SPLITVERT flags.
  918.                  */
  919.                 if (npdoc->cxVertSplitPos >
  920.                         (((SHORT)rclClient.xRight - (SHORT)rclClient.xLeft) -
  921.                         cxVertSplitbar)) {
  922.                     npdoc->fs |= DF_VSPLITOVERFLOW;
  923.                     npdoc->fs &= ~DF_SPLITVERT;
  924.                 } else {
  925.                     npdoc->fs &= ~DF_VSPLITOVERFLOW;
  926.                     npdoc->fs |= DF_SPLITVERT;
  927.                 }
  928.             }
  929.         }
  930.  
  931. #undef aswp
  932.  
  933.         return (*pfnFrameWndProc)(hwnd, msg, mp1, mp2);
  934.         break;
  935.  
  936.  
  937.     case WM_CALCVALIDRECTS:
  938.  
  939.         /*
  940.          * We do our own WM_CALCVALIDRECTS processing
  941.          * because the frame manager uses the window
  942.          * rectangle of FID_CLIENT, which in our case
  943.          * might be smaller than the 'client area' due
  944.          * to window splitting.
  945.          */
  946.  
  947. #define prclOld ((PRECTL)&(((PRECTL)mp1)[0]))
  948. #define prclNew ((PRECTL)&(((PRECTL)mp1)[1]))
  949.  
  950.         /*
  951.          * Calculate the client rectangle of hwnd in its
  952.          * parent's coordinates.
  953.          */
  954.         WinQueryWindowRect(hwnd, (PRECTL)prclOld);
  955.         hwndParent = WinQueryWindow(hwnd, QW_PARENT, FALSE);
  956.         WinMapWindowPoints(hwnd, hwndParent, (PPOINTL)prclOld, 2);
  957.         WinCalcFrameRect(hwnd, (PRECTL)prclOld, TRUE);
  958.  
  959.         /*
  960.          * Calculate the client rect for the
  961.          * destination of the frame window.
  962.          */
  963.         WinCalcFrameRect(hwnd, (PRECTL)prclNew, TRUE);
  964.  
  965.         /*
  966.          * Top align destination bits.
  967.          */
  968.         prclNew->yBottom += (prclNew->yTop - prclNew->yBottom) -
  969.                             (prclOld->yTop - prclOld->yBottom);
  970.  
  971.  
  972.  
  973.  
  974.  
  975. #undef prclOld
  976. #undef prclNew
  977.  
  978.     prcl = PVOIDFROMMP(mp1);     /* array of src and dest rectangles      */
  979.     pswp = PVOIDFROMMP(mp2);
  980.  
  981.  
  982.         /*
  983.          * Return 0 since we've already aligned the bits.
  984.          */
  985.         return(0);
  986.         break;
  987.  
  988.  
  989.  
  990.     case WM_QUERYFRAMECTLCOUNT:
  991.         cFrameCtls = (int)(ULONG)(*pfnFrameWndProc)(hwnd, WM_QUERYFRAMECTLCOUNT, mp1, mp2);
  992.  
  993.         /*
  994.          * Max number of additional frame controls is seven
  995.          * Two splitbars, two additional scrollbars, and three
  996.          * additional client windows.  Throw in 3 more just to
  997.          * be sure we don't trash memory
  998.          */
  999.         return (MRFROMSHORT(cFrameCtls + 7 + 3));
  1000.  
  1001.  
  1002.     case WM_FORMATFRAME:
  1003.         return (MDIFormatFrame(hwnd, ((PSWP)PVOIDFROMMP(mp1)), mp2));
  1004.         break;
  1005.  
  1006.     case WM_BUTTON1UP:
  1007.         mres =  (*pfnFrameWndProc)(hwnd, msg, mp1, mp2);
  1008.  
  1009.         /*
  1010.          * If we're minimized we need to do activation ourself
  1011.          * and bring up the system menu.
  1012.          */
  1013.         if (!(WinQueryWindowUShort(hwnd, QWS_FLAGS) & FF_ACTIVE)) {
  1014.  
  1015.             /*
  1016.              * Only do this if we're minimized.
  1017.              */
  1018.             if (WinQueryWindowULong(hwnd, QWL_STYLE) & WS_MINIMIZED) {
  1019.  
  1020.                 WinSetActiveWindow(HWND_DESKTOP, hwnd);
  1021.  
  1022.                 /*
  1023.                  * Bring up the system menu if there is one.
  1024.                  */
  1025.                 WinSendDlgItemMsg(hwnd, FID_SYSMENU, MM_STARTMENUMODE,
  1026.                         MPFROMSHORT(TRUE), 0L);
  1027.             }
  1028.         }
  1029.         break;
  1030.  
  1031.     case WM_DESTROY:
  1032.         /*
  1033.          * If this document is maximized, remove the AabSysMenu.
  1034.          */
  1035.  
  1036.         /* MULTIPLEMENU */
  1037.  
  1038. /* Not needed since we removed the system menu when it lost
  1039.         activation ???????????????????? */
  1040.  
  1041.    /*
  1042.         if (WinQueryWindowULong(hwnd, QWL_STYLE) & WS_MAXIMIZED)
  1043.             RemoveAabSysMenu();
  1044.    */
  1045.  
  1046.  
  1047.         hwndClient = WinWindowFromID(hwnd, FID_CLIENT);
  1048.         npdoc = NPDOCFROMCLIENT(hwndClient);
  1049.  
  1050.         /*
  1051.          * Make sure these windows are on the frame so they
  1052.          * get destroyed.
  1053.          */
  1054.         WinSetParent(npdoc->hwndSysMenu, hwnd, FALSE);
  1055.         WinSetParent(npdoc->hwndMinmax, hwnd, FALSE);
  1056.  
  1057.         WinSendMsg(npdoc->hwndSysMenu, MM_DELETEITEM,
  1058.                     MPFROM2SHORT(-127, TRUE),0L);
  1059.  
  1060.  
  1061.         fDestroying=TRUE;
  1062.  
  1063.         RemoveFromWindowMenu(npdoc);
  1064.  
  1065.         if (WinIsWindow(hab, npdoc->hwndMainMenu)) {
  1066.             WinDestroyWindow(npdoc->hwndMainMenu);
  1067.             }
  1068.  
  1069.         WinFreeMem(hHeap, (NPBYTE)npdoc, sizeof(DOC));
  1070.  
  1071.         if (npdocFirst==NULL) {
  1072.             /* No documents left, so put the first menu back on the main MDI
  1073.             window */
  1074.  
  1075.             /* need to make sure the hwndFirstMenu still exists, since it
  1076.                 is dead by now when the app is being closed down. */
  1077.  
  1078.             if (WinIsWindow(hab, hwndFirstMenu)) {
  1079.                 WinSetParent(hwndFirstMenu, hwndMDIFrame, FALSE);
  1080.                 WinSendMsg(hwndMDIFrame, WM_UPDATEFRAME, 0L, 0L);
  1081.                 }
  1082.             }
  1083.  
  1084.         return (*pfnFrameWndProc)(hwnd, msg, mp1, mp2);
  1085.  
  1086.     default:
  1087.         return (*pfnFrameWndProc)(hwnd, msg, mp1, mp2);
  1088.     }
  1089. }
  1090.  
  1091. MRESULT MDIMinMaxFrame(HWND hwnd, MPARAM mp1, MPARAM mp2)
  1092. {
  1093.     PSWP pswp;
  1094.  
  1095.     pswp = (PSWP)PVOIDFROMMP(mp1);
  1096.     if ((pswp->fs & SWP_MAXIMIZE) &&
  1097.             ((WinQueryWindowULong(hwnd, QWL_STYLE) & WS_MAXIMIZED) == 0L)) {
  1098.         pswp->cy += cyTitlebar;
  1099.         AddAabSysMenu(hwnd);
  1100.         SetMainTitleText(hwnd);
  1101.     } else if (((pswp->fs & SWP_RESTORE) || (pswp->fs & SWP_MINIMIZE)) &&
  1102.             (WinQueryWindowULong(hwnd, QWL_STYLE) & WS_MAXIMIZED)) {
  1103.         RemoveAabSysMenu(hwnd);
  1104.         ClearMainTitleText();
  1105.     }
  1106.     return (*pfnFrameWndProc)(hwnd, WM_MINMAXFRAME, mp1, mp2);
  1107. }
  1108.  
  1109. MRESULT MDIFormatFrame(HWND hwnd, PSWP aswp, MPARAM mp2)
  1110. {
  1111.     SWP swpClient;
  1112.     PSWP pswpHScroll, pswpVScroll;
  1113.     USHORT chwnd, iswpNext;
  1114.     register NPDOC npdoc;
  1115.     SHORT cyHorzSplitPos, cxVertSplitPos;
  1116.  
  1117.     iswpNext = chwnd = (USHORT) (ULONG)(*pfnFrameWndProc)(hwnd, WM_FORMATFRAME,
  1118.                             aswp, mp2);
  1119.  
  1120.     FindSwp(aswp, chwnd, FID_HORZSCROLL, (PSWP FAR *)&pswpHScroll);
  1121.     FindSwp(aswp, chwnd, FID_VERTSCROLL, (PSWP FAR *)&pswpVScroll);
  1122.  
  1123.     npdoc = NPDOCFROMCLIENT(aswp[chwnd - 1].hwnd);
  1124.  
  1125.     cyHorzSplitPos = npdoc->cyHorzSplitPos;
  1126.     cxVertSplitPos = npdoc->cxVertSplitPos;
  1127.  
  1128.     /*
  1129.      * Save the client rectangle away because we
  1130.      * want to do thing based on the original
  1131.      * client rectangle as well as move the
  1132.      * client's ordering in the SWP list behind
  1133.      * the other client windows.
  1134.      */
  1135.     swpClient = aswp[chwnd - 1];
  1136.  
  1137.     /*
  1138.      * Start from the client window's SWP
  1139.      * since we're going to move it to
  1140.      * the end.
  1141.      */
  1142.     iswpNext = (chwnd - 1);
  1143.  
  1144.     if (npdoc->fsStyle & DS_VERTSPLITBAR) {
  1145.  
  1146.         /*
  1147.          * If the horizontal scrollbar is being hidden
  1148.          * then we certainly don't need to be around...
  1149.          */
  1150.         if (pswpHScroll->fs & SWP_HIDE) {
  1151.  
  1152.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_CLIENT2),
  1153.                     &iswpNext);
  1154.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_HORZSCROLL2),
  1155.                     &iswpNext);
  1156.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_VERTSPLITBAR),
  1157.                     &iswpNext);
  1158.  
  1159.         } else if (npdoc->fs & DF_VSPLITOVERFLOW) {
  1160.  
  1161.             /*
  1162.              * First hide CLIENT3 and VERTSCROLL2
  1163.              * since we know they're going away.
  1164.              */
  1165.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_CLIENT2),
  1166.                     &iswpNext);
  1167.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_HORZSCROLL2),
  1168.                     &iswpNext);
  1169.  
  1170.             /*
  1171.              * Hide CLIENT4 since it won't be needed for now.
  1172.              */
  1173.             if (npdoc->fsStyle & DS_HORZSPLITBAR) {
  1174.                 HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_CLIENT4),
  1175.                         &iswpNext);
  1176.             }
  1177.  
  1178.             /*
  1179.              * If there isn't any room for even the hidden
  1180.              * representation then get rid of it...
  1181.              */
  1182.             if (pswpHScroll->cx < (SHORT) (cxVertSplitbar * 3)) {
  1183.                 HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_VERTSPLITBAR),
  1184.                         &iswpNext);
  1185.             } else {
  1186.                 SetSwpPos(&aswp[iswpNext++],
  1187.                         WinWindowFromID(hwnd, ID_VERTSPLITBAR), NULL,
  1188.                         pswpHScroll->x + pswpHScroll->cx - cxVertSplitbar,
  1189.                         pswpHScroll->y + cyBorder, cxVertSplitbar,
  1190.                         pswpHScroll->cy - cyBorder, pswpHScroll->fs);
  1191.  
  1192.                 pswpHScroll->cx -= cxVertSplitbar;
  1193.             }
  1194.  
  1195.         } else if (npdoc->fs & DF_SPLITVERT) {
  1196.  
  1197.             /*
  1198.              * Format the client windows.
  1199.              *
  1200.              * If we're split horzintally as well then we
  1201.              * need to show the fourth client.
  1202.              */
  1203.  
  1204.             /*
  1205.              * If we're split horizontally and there was
  1206.              * enough room to be split then format
  1207.              * the 'fourth' client window.
  1208.              */
  1209.             if ((npdoc->fs & DF_SPLITHORZ) &&
  1210.                     (pswpVScroll->cy > (SHORT) (cyHorzSplitbar * 3))) {
  1211.                 aswp[iswpNext].hwnd = WinWindowFromID(hwnd, ID_CLIENT4);
  1212.                 aswp[iswpNext].hwndInsertBehind = NULL;
  1213.                 aswp[iswpNext].x = swpClient.x +
  1214.                         (cxVertSplitPos + cxVertSplitbar);
  1215.                 aswp[iswpNext].cx = swpClient.cx -
  1216.                         (cxVertSplitPos + cxVertSplitbar);
  1217.                 aswp[iswpNext].y = swpClient.y;
  1218.                 aswp[iswpNext].cy = cyHorzSplitPos;
  1219.                 aswp[iswpNext].fs = swpClient.fs | SWP_SHOW;
  1220.  
  1221.                 iswpNext++;
  1222.             }
  1223.  
  1224.             aswp[iswpNext].hwnd = WinWindowFromID(hwnd, ID_CLIENT2);
  1225.             aswp[iswpNext].hwndInsertBehind = NULL;
  1226.             aswp[iswpNext].x = swpClient.x +
  1227.                     (cxVertSplitPos + cxVertSplitbar);
  1228.             aswp[iswpNext].cx = swpClient.cx -
  1229.                     (cxVertSplitPos + cxVertSplitbar);
  1230.             /*
  1231.              * If we're split horizontally and there was
  1232.              * enough room to be split then format
  1233.              * the 'second' client window against the
  1234.              * 'fourth' client window.
  1235.              */
  1236.             if ((npdoc->fs & DF_SPLITHORZ) &&
  1237.                     (pswpVScroll->cy > (SHORT) (cyHorzSplitbar * 3))) {
  1238.                 aswp[iswpNext].y = swpClient.y +
  1239.                         (cyHorzSplitPos + cyHorzSplitbar);
  1240.                 aswp[iswpNext].cy = swpClient.cy -
  1241.                         (cyHorzSplitPos + cyHorzSplitbar);
  1242.             } else {
  1243.                 aswp[iswpNext].y = swpClient.y;
  1244.                 aswp[iswpNext].cy = swpClient.cy;
  1245.             }
  1246.             aswp[iswpNext].fs = swpClient.fs | SWP_SHOW;
  1247.  
  1248.             iswpNext++;
  1249.  
  1250.         } else {
  1251.             /*
  1252.              * If we're not split then format the window with the
  1253.              * splitbar to the left of the horizontal scrollbar.
  1254.              */
  1255.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_HORZSCROLL2),
  1256.                     &iswpNext);
  1257.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_CLIENT2),
  1258.                     &iswpNext);
  1259.  
  1260.             /*
  1261.              * Hide ID_CLIENT4 since it won't be needed for now.
  1262.              */
  1263.             if (npdoc->fsStyle & DS_HORZSPLITBAR) {
  1264.                 HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_CLIENT4),
  1265.                         &iswpNext);
  1266.             }
  1267.  
  1268.             aswp[iswpNext].hwnd = WinWindowFromID(hwnd, ID_VERTSPLITBAR);
  1269.             aswp[iswpNext].hwndInsertBehind = NULL;
  1270.             aswp[iswpNext].x = pswpHScroll->x;
  1271.             aswp[iswpNext].y = pswpHScroll->y + cyBorder;
  1272.             aswp[iswpNext].cx = cxVertSplitbar;
  1273.             aswp[iswpNext].cy = pswpHScroll->cy - cyBorder;
  1274.             aswp[iswpNext].fs = pswpHScroll->fs;
  1275.             pswpHScroll->x += cxVertSplitbar;
  1276.             pswpHScroll->cx -= cxVertSplitbar;
  1277.  
  1278.             iswpNext++;
  1279.         }
  1280.     }
  1281.  
  1282.     if (npdoc->fsStyle & DS_HORZSPLITBAR) {
  1283.         /*
  1284.          * If the horizontal scrollbar is being hidden
  1285.          * then we certainly don't need to be around...
  1286.          */
  1287.         if (pswpVScroll->fs & SWP_HIDE) {
  1288.  
  1289.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_CLIENT3),
  1290.                     &iswpNext);
  1291.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_VERTSCROLL2),
  1292.                     &iswpNext);
  1293.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_HORZSPLITBAR),
  1294.                     &iswpNext);
  1295.  
  1296.         } else if (npdoc->fs & DF_HSPLITOVERFLOW) {
  1297.  
  1298.             /*
  1299.              * First hide CLIENT3 and VERTSCROLL2
  1300.              * since we know they're going away.
  1301.              */
  1302.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_CLIENT3),
  1303.                     &iswpNext);
  1304.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_VERTSCROLL2),
  1305.                     &iswpNext);
  1306.  
  1307.             /*
  1308.              * Hide CLIENT4 since it won't be needed for now.
  1309.              */
  1310.             if (npdoc->fsStyle & DS_VERTSPLITBAR) {
  1311.                 HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_CLIENT4),
  1312.                         &iswpNext);
  1313.             }
  1314.  
  1315.             /*
  1316.              * If there isn't any room for even the hidden
  1317.              * representation then get rid of it
  1318.              */
  1319.             if (pswpVScroll->cy < (SHORT)(cyHorzSplitbar * 3)) {
  1320.                 HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_HORZSPLITBAR),
  1321.                         &iswpNext);
  1322.             } else {
  1323.                 SetSwpPos(&aswp[iswpNext++],
  1324.                         WinWindowFromID(hwnd, ID_HORZSPLITBAR), NULL,
  1325.                         pswpVScroll->x, pswpVScroll->y, pswpVScroll->cx - cxBorder,
  1326.                         cyHorzSplitbar, pswpVScroll->fs);
  1327.  
  1328.                 pswpVScroll->y += cyHorzSplitbar;
  1329.                 pswpVScroll->cy -= cyHorzSplitbar;
  1330.             }
  1331.  
  1332.         } else if (npdoc->fs & DF_SPLITHORZ) {
  1333.  
  1334.             if (pswpVScroll->cy > (SHORT)(cyHorzSplitbar * 3)) {
  1335.                 /*
  1336.                  * Format the client windows.
  1337.                  */
  1338.                 SetSwpPos(&aswp[iswpNext++],
  1339.                         WinWindowFromID(hwnd, ID_CLIENT3), NULL,
  1340.                         swpClient.x, swpClient.y,
  1341.                         /*
  1342.                          * If we're split vertically then format
  1343.                          * the client against the vertical splitbar
  1344.                          * as well as the horzontal splitbar.
  1345.                          */
  1346.                         (npdoc->fs & DF_SPLITVERT) ? cxVertSplitPos : swpClient.cx,
  1347.                         cyHorzSplitPos, swpClient.fs | SWP_SHOW);
  1348.  
  1349.             } else {
  1350.                 HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_CLIENT3),
  1351.                         &iswpNext);
  1352.  
  1353.                 /*
  1354.                  * Hide CLIENT4 since it won't be needed for now.
  1355.                  */
  1356.                 if (npdoc->fsStyle & DS_VERTSPLITBAR) {
  1357.                     HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_CLIENT4),
  1358.                             &iswpNext);
  1359.                 }
  1360.             }
  1361.  
  1362.         } else {
  1363.             /*
  1364.              * If we're not split then format the window with the
  1365.              * splitbar at the top of the vertical scrollbar.
  1366.              */
  1367.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_VERTSCROLL2),
  1368.                     &iswpNext);
  1369.  
  1370.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_CLIENT3),
  1371.                     &iswpNext);
  1372.  
  1373.             if (npdoc->fsStyle & DS_VERTSPLITBAR) {
  1374.                 HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_CLIENT4),
  1375.                     &iswpNext);
  1376.             }
  1377.  
  1378.             if (pswpVScroll->cy > (SHORT)(cyHorzSplitbar * 3)) {
  1379.                 SetSwpPos(&aswp[iswpNext++],
  1380.                         WinWindowFromID(hwnd, ID_HORZSPLITBAR), NULL,
  1381.                         pswpVScroll->x, pswpVScroll->y + pswpVScroll->cy -
  1382.                             cyHorzSplitbar,
  1383.                         pswpVScroll->cx - cxBorder, cyHorzSplitbar, pswpVScroll->fs);
  1384.  
  1385.                 pswpVScroll->cy -= cyHorzSplitbar;
  1386.             } else {
  1387.                 HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_HORZSPLITBAR),
  1388.                         &iswpNext);
  1389.             }
  1390.         }
  1391.     }
  1392.  
  1393.     /*
  1394.      * Now format the original client window.
  1395.      */
  1396.     aswp[iswpNext] = swpClient;
  1397.  
  1398.     if (npdoc->fs & (DF_SPLITHORZ | DF_SPLITVERT)) {
  1399.  
  1400.         /*
  1401.          * Adjust the main client window for the splitbars.
  1402.          */
  1403.         if (npdoc->fs & DF_SPLITVERT) {
  1404.             aswp[iswpNext].cx = cxVertSplitPos;
  1405.         }
  1406.  
  1407.         if ((npdoc->fs & DF_SPLITHORZ) &&
  1408.                 (pswpVScroll->cy > (SHORT)(cyHorzSplitbar * 3))) {
  1409.             aswp[iswpNext].y += (cyHorzSplitPos + cyHorzSplitbar);
  1410.             aswp[iswpNext].cy -= (cyHorzSplitPos + cyHorzSplitbar);
  1411.         }
  1412.     }
  1413.  
  1414.     iswpNext++;
  1415.  
  1416.     if (npdoc->fs & DF_SPLITHORZ) {
  1417.         /*
  1418.          * Format the scrollbars and the splitbar.
  1419.          */
  1420.         if (pswpVScroll->cy > (SHORT)(cyHorzSplitbar * 3)) {
  1421.             SetSwpPos(&aswp[iswpNext++],
  1422.                     WinWindowFromID(hwnd, ID_HORZSPLITBAR), NULL,
  1423.                     swpClient.x, swpClient.y + cyHorzSplitPos,
  1424.                     swpClient.cx + pswpVScroll->cx - cxBorder, cyHorzSplitbar,
  1425.                     pswpVScroll->fs | SWP_SHOW);
  1426.  
  1427.             SetSwpPos(&aswp[iswpNext++],
  1428.                     WinWindowFromID(hwnd, ID_VERTSCROLL2), NULL,
  1429.                     pswpVScroll->x, pswpVScroll->y,
  1430.                     pswpVScroll->cx, cyHorzSplitPos + (cyBorder * 2),
  1431.                     pswpVScroll->fs | SWP_SHOW);
  1432.  
  1433.             pswpVScroll->y += (cyHorzSplitPos + cyHorzSplitbar);
  1434.             pswpVScroll->cy -= (cyHorzSplitPos + cyHorzSplitbar);
  1435.  
  1436.         } else {
  1437.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_VERTSCROLL2),
  1438.                     &iswpNext);
  1439.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_HORZSPLITBAR),
  1440.                     &iswpNext);
  1441.             HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_CLIENT3),
  1442.                     &iswpNext);
  1443.             if (npdoc->fsStyle & DS_VERTSPLITBAR)
  1444.                 HideSwp(&aswp[iswpNext], WinWindowFromID(hwnd, ID_CLIENT4),
  1445.                         &iswpNext);
  1446.         }
  1447.     }
  1448.  
  1449.     if (npdoc->fs & DF_SPLITVERT) {
  1450.  
  1451.         SetSwpPos(&aswp[iswpNext++],
  1452.                 WinWindowFromID(hwnd, ID_VERTSPLITBAR), NULL,
  1453.                 swpClient.x + cxVertSplitPos, pswpHScroll->y + cyBorder,
  1454.                 cxVertSplitbar, swpClient.cy + pswpHScroll->cy - cyBorder,
  1455.                 pswpHScroll->fs);
  1456.  
  1457.         SetSwpPos(&aswp[iswpNext++],
  1458.                 WinWindowFromID(hwnd, ID_HORZSCROLL2), NULL,
  1459.                 swpClient.x + cxVertSplitPos + cxVertSplitbar - cyBorder,
  1460.                 pswpHScroll->y, pswpHScroll->cx - (cxVertSplitPos + cxVertSplitbar),
  1461.                 pswpHScroll->cy, pswpVScroll->fs | SWP_SHOW);
  1462.  
  1463.         pswpHScroll->cx = cxVertSplitPos + (cxBorder * 2);
  1464.     }
  1465.  
  1466.     return ( (MRESULT) iswpNext);
  1467. }
  1468.