home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / MDI-15.ZIP / MDI.C < prev    next >
Text File  |  1990-08-30  |  118KB  |  2,909 lines

  1. // Includes
  2. // --------
  3.    #define  INCL_WIN
  4.    #define  INCL_DOS
  5.  
  6.    #include <stdio.h>
  7.    #include <stdlib.h>
  8.    #include <string.h>
  9.    #include <os2.h>
  10.  
  11.    #include "MDI.H"
  12.    #include "MDI.RH"
  13.  
  14.    #include "AllocMem.H"
  15.    #include "TellUser.H"
  16.  
  17.  
  18. // Constants
  19. // ---------
  20.    #define MAX_STRING    256           // Maximum string size
  21.    #define MAX_MENUDELTA  32           // Maximum menu delta ids
  22.    #define INSERT_TITLE    1           // Insert title command code
  23.    #define REMOVE_TITLE    2           // Remove title command code
  24.    #define UPDATE_TITLE    3           // Update title command code
  25.    #define HIDE_TITLE      4           // Hide or unhide title command code
  26.    #define AWP_TILED       1           // Arrange tiled flag
  27.    #define AWP_CASCADED    2           // Arrange cascaded flag
  28.    #define CASC_EDGE_NUM   2           // Cascaded arrange edge
  29.    #define CASC_EDGE_DENOM 3           // Cascaded arrange edge
  30.    #define ICON_PARK_NUM   5           // Icon park
  31.    #define ICON_PARK_DENOM 3           // Icon park
  32.  
  33.    const USHORT cbExtraData            // Extra window storage
  34.               = (2 * sizeof (PVOID));
  35.  
  36.  
  37. // Desktop Creation Parameters
  38. // ---------------------------
  39.    typedef struct _DESKTOPCREATEPARMS
  40.      {USHORT cbDeskData;               // Size of user desktop data
  41.       PCHAR pszDelta;                  // Menu item before which deltas go
  42.       PCHAR pszExit;                   // Menu item before which "window" goes
  43.       PCHAR pszWindow;                 // Window menu item text
  44.      } DESKTOPCREATEPARMS;
  45.  
  46.    typedef DESKTOPCREATEPARMS *PDESKTOPCREATEPARMS;
  47.  
  48.  
  49. // Document Creation Parameters
  50. // ----------------------------
  51.    typedef struct _DOCUMENTCREATEPARMS
  52.      {USHORT cbDocData;                // Size of user document data
  53.       USHORT cbInstData;               // Size of user instance data
  54.       ULONG flCreateFlags;             // Copy of frame creation flags
  55.       HMODULE hmodResources;           // Copy of frame resources
  56.       USHORT idResources;              // Copy of frame resources id
  57.       PFNWP pfnUser;                   // User window procedure
  58.      } DOCUMENTCREATEPARMS;
  59.  
  60.    typedef DOCUMENTCREATEPARMS *PDOCUMENTCREATEPARMS;
  61.  
  62.  
  63. // Desktop Intra-instance Data
  64. // ---------------------------
  65.    typedef struct _INSTDESKTOP
  66.      {HWND hwndDocument;               // Active document window
  67.       HWND hwndDesktop;                // Desktop window
  68.       HWND hwndParent;                 // Its frame's parent
  69.       HWND hwndFrame;                  // Its frame
  70.       HWND hwndMenu;                   // Its menu
  71.       HWND hwndMenuDelta;              // Its menu delta
  72.       HACCEL haccel;                   // Its accelerator table
  73.       CHAR szName[MAX_STRING];         // Its name
  74.       CHAR szTitleText[MAX_STRING];    // Its titlebar text
  75.       SWP swp;                         // Its position
  76.       MENUITEM miSysMenu;              // Maximized child system menu
  77.       PVOID pvDeskData;                // -->user desktop data
  78.       BOOL fTileAlways;                // TRUE == Tile always
  79.       BOOL fCascadeAlways;             // TRUE == Cascade always
  80.       BOOL fAlwaysOnResize;            // TRUE == Tile, cascade always on resize
  81.       BOOL fKeepWindowsMenu;           // TRUE == Keep windows menu
  82.       BOOL fKeepScrollBars;            // TRUE == Keep scroll bars
  83.       BOOL fDisableDesktopPosition;    // TRUE == Disable desktop position retention
  84.       BOOL fDisableDocumentPosition;   // TRUE == Disable document position retention
  85.       BOOL fDisableNewDocument;        // TRUE == Disable "new document" menu item
  86.       PCHAR pszDelta;                  // Menu item before which deltas go
  87.       MENUITEM miDelta;                // Delta menu
  88.       PCHAR pszExit;                   // Menu item before which "window" goes
  89.       PCHAR pszWindow;                 // Window menu item text
  90.       MENUITEM miWindow;               // Window menu
  91.       USHORT idDesktop;                // Desktop id
  92.       USHORT cidDelta;                 // Count of menu delta ids
  93.       USHORT idDelta[MAX_MENUDELTA];   // Menu delta ids
  94.      } INSTDESKTOP;
  95.  
  96.    typedef INSTDESKTOP *PINSTDESKTOP;
  97.  
  98.  
  99. // Document Intra-instance Data
  100. // ----------------------------
  101.    typedef struct _INSTDOCUMENT
  102.      {HWND hwndDocument;               // Document window
  103.       HWND hwndDesktop;                // Desktop window
  104.       HWND hwndFrame;                  // Its frame
  105.       HWND hwndMenu;                   // Its menu
  106.       HWND hwndSysMenu;                // Its system menu
  107.       HWND hwndTitleBar;               // Its title bar
  108.       HWND hwndMinMax;                 // Its min/max buttons
  109.       HWND hwndVScroll;                // Its vertical scroll bar
  110.       HWND hwndHScroll;                // Its horizontal scroll bar
  111.       USHORT idInternal;               // Its internal id
  112.       HACCEL haccel;                   // Its accelerator table
  113.       CHAR szName[MAX_STRING];         // Its name
  114.       SHORT iName;                     // Its name index
  115.       CHAR szTitleText[MAX_STRING];    // Its titlebar text
  116.       SWP swp;                         // Its position
  117.       USHORT usState;                  // Its state
  118.       USHORT cbDocData;                // Size of user document data
  119.       USHORT cbInstData;               // Size of user instance data
  120.       PFNWP pfnUser;                   // User window procedure
  121.       ULONG flCreateFlags;             // Frame creation flags
  122.       HMODULE hmodResources;           // Frame resources
  123.       USHORT idResources;              // Frame resources id
  124.       USHORT idDesktop;                // Desktop id
  125.       PVOID pvDocData;                 // -->user document data
  126.       PVOID pvInstData;                // -->user instance data
  127.      } INSTDOCUMENT;
  128.  
  129.    typedef INSTDOCUMENT *PINSTDOCUMENT;
  130.  
  131.  
  132. // Function Declarations (see also MDI.H)
  133. // --------------------------------------
  134.    MRESULT       FAR      MDIDesktopClose            (PINSTDESKTOP);
  135.    MRESULT       FAR      MDIDesktopCommand          (PINSTDESKTOP, USHORT);
  136.    MRESULT       FAR      MDIDesktopCreate           (HWND, PDESKTOPCREATEPARMS);
  137.    MRESULT       FAR      MDIDesktopDestroy          (PINSTDESKTOP);
  138.    MRESULT       FAR      MDIDesktopMinMax           (PINSTDESKTOP, PSWP);
  139.    MRESULT       FAR      MDIDesktopPaint            (PINSTDESKTOP);
  140.    MRESULT       FAR      MDIDesktopSizeAndMove      (PINSTDESKTOP);
  141.    MRESULT       FAR      MDIDocumentActivate        (PINSTDOCUMENT, BOOL);
  142.    VOID          FAR      MDIDocumentArrange         (HWND, USHORT);
  143.    VOID          FAR      MDIDocumentArrangeCascaded (PRECTL, SHORT, PSWP);
  144.    VOID          FAR      MDIDocumentArrangeTiled    (PRECTL, SHORT, PSWP);
  145.    VOID          FAR      MDIDocumentClone           (PINSTDOCUMENT);
  146.    MRESULT       FAR      MDIDocumentClose           (PINSTDOCUMENT);
  147.    MRESULT       FAR      MDIDocumentCommand         (PINSTDOCUMENT, USHORT);
  148.    MRESULT       FAR      MDIDocumentCreate          (HWND, PDOCUMENTCREATEPARMS);
  149.    MRESULT       FAR      MDIDocumentDestroy         (PINSTDOCUMENT);
  150.    HWND          FAR      MDIDocumentFrameFromID     (HWND, USHORT);
  151.    VOID          FAR      MDIDocumentHide            (PINSTDOCUMENT);
  152.    MRESULT       FAR      MDIDocumentMinMax          (PINSTDOCUMENT, PSWP);
  153.    MRESULT       EXPENTRY MDIDocumentMoreDlgProc     (HWND, USHORT, MPARAM, MPARAM);
  154.    MRESULT       FAR      MDIDocumentPaint           (PINSTDOCUMENT);
  155.    VOID          FAR      MDIDocumentShowFrameCtls   (PINSTDOCUMENT, BOOL, BOOL, BOOL);
  156.    PINSTDOCUMENT FAR      MDIDocumentTitlesRebuild   (PINSTDOCUMENT, USHORT);
  157.    MRESULT       EXPENTRY MDIDocumentUnhideDlgProc   (HWND, USHORT, MPARAM, MPARAM);
  158.    HACCEL        FAR      MDILoadAccelTable          (USHORT);
  159.    HWND          FAR      MDILoadDialog              (HWND, PFNWP, USHORT, PVOID);
  160.    HWND          FAR      MDILoadMenu                (HWND, USHORT);
  161.    VOID          FAR      MDILoadString              (USHORT, USHORT, PCHAR);
  162.  
  163.  
  164. // Function: MDICreateDesktop - Create MDI Desktop
  165. // -----------------------------------------------
  166.    HWND EXPENTRY MDICreateDesktop (pfnUser, flFrameFlags, pszName, hmodResources, idResources,
  167.      phwndClient, cbDeskData, idDesktop, pszDelta, pszExit, pszWindow, flOptions)
  168.  
  169.       PFNWP pfnUser;                   // User window procedure
  170.       ULONG flFrameFlags;              // Frame creation flags
  171.       PCHAR pszName;                   // Desktop name
  172.       HMODULE hmodResources;           // Module that contains resources
  173.       USHORT idResources;              // Resources identifier
  174.       PHWND phwndClient;               // -->area to receive desktop handle
  175.       USHORT cbDeskData;               // Size of user desktop data
  176.       USHORT idDesktop;                // ID of desktop
  177.       PCHAR pszDelta;                  // Text of menu entry before which menu deltas are inserted
  178.       PCHAR pszExit;                   // Text of menu entry before which the "window" menu is inserted
  179.       PCHAR pszWindow;                 // Desired "Window" menu text
  180.       ULONG flOptions;                 // Options
  181.  
  182.    // Define function data
  183.  
  184.      {HWND hwndFrame;                  // Frame window
  185.       FRAMECDATA fcdata;               // Frame creation parameters
  186.       DESKTOPCREATEPARMS deskcp;       // Desktop creation parameters
  187.       PINSTDESKTOP pinst;              // -->desktop instance data
  188.  
  189.    // Initialize frame creation parameters
  190.  
  191.       fcdata.cb = sizeof (fcdata);
  192.       fcdata.flCreateFlags = flFrameFlags;
  193.       fcdata.hmodResources = hmodResources;
  194.       fcdata.idResources = idResources;
  195.  
  196.    // Initialize desktop creation parameters
  197.  
  198.       deskcp.cbDeskData = cbDeskData;
  199.       deskcp.pszDelta = pszDelta;
  200.       deskcp.pszExit = pszExit;
  201.       deskcp.pszWindow = pszWindow;
  202.  
  203.    // Create desktop frame and client windows
  204.  
  205.       hwndFrame = WinCreateWindow (HWND_DESKTOP, WC_FRAME, pszName,
  206.         WS_VISIBLE, 0, 0, 0, 0, (PVOID) NULL, HWND_TOP, idDesktop, &fcdata, (PVOID) NULL);
  207.       if (hwndFrame == (PVOID) NULL) return (HWND) NULL;
  208.       *phwndClient = WinCreateWindow (hwndFrame, MDI_DESKTOPCLASS, (PSZ) NULL,
  209.         WS_VISIBLE, 0, 0, 0, 0, hwndFrame, HWND_BOTTOM, FID_CLIENT, &deskcp, (PVOID) NULL);
  210.       if (*phwndClient == (HWND) NULL) return (HWND) NULL;
  211.  
  212.    // Subclass desktop window procedure
  213.  
  214.       if (pfnUser != (PFNWP) NULL)
  215.          WinSubclassWindow (*phwndClient, pfnUser);
  216.  
  217.    // Locate desktop instance data
  218.  
  219.       pinst = (PINSTDESKTOP) WinQueryWindowULong (*phwndClient, QWL_USER + sizeof (PVOID));
  220.  
  221.    // Tell user that desktop has been created
  222.  
  223.       WinSendMsg (*phwndClient, WM_CONTROL,
  224.         MPFROM2SHORT (pinst->idDesktop, MDI_NOTIFY_CREATE_DESKTOP),
  225.         (MPARAM) pinst->pvDeskData);
  226.  
  227.    // Handle option flags
  228.  
  229.       // Handle "keep windows menu"
  230.  
  231.          if (flOptions & MDI_KEEP_WINDOWS_MENU)
  232.            {pinst->fKeepWindowsMenu = TRUE;
  233.             WinSendMsg (pinst->hwndMenu, MM_INSERTITEM,
  234.               (MPARAM) &(pinst->miWindow), (MPARAM) pinst->pszWindow);
  235.            }
  236.  
  237.       // Handle "keep scroll bars"
  238.  
  239.          if (flOptions & MDI_KEEP_SCROLLBARS)
  240.             pinst->fKeepScrollBars = TRUE;
  241.  
  242.       // Handle "disable new document"
  243.  
  244.          if (flOptions & MDI_DISABLE_NEW_DOCUMENT)
  245.            {pinst->fDisableNewDocument = TRUE;
  246.             WinSendMsg (pinst->miWindow.hwndSubMenu, MM_DELETEITEM,
  247.               MPFROM2SHORT (CMD_NEW_DOCUMENT, TRUE), (MPARAM) NULL);
  248.            }
  249.  
  250.       // Handle "disable desktop position"
  251.  
  252.          if (flOptions & MDI_DISABLE_DESKTOP_POSITION)
  253.             pinst->fDisableDesktopPosition = TRUE;
  254.  
  255.       // Handle "disable document position"
  256.  
  257.          if (flOptions & MDI_DISABLE_DOCUMENT_POSITION)
  258.             pinst->fDisableDocumentPosition = TRUE;
  259.  
  260.       // Handle "always on resize"
  261.  
  262.          if (flOptions & MDI_ALWAYS_ON_RESIZE)
  263.             pinst->fAlwaysOnResize = TRUE;
  264.  
  265.       // Handle "initial tile always"
  266.  
  267.          if (flOptions & MDI_INITIAL_TILE_ALWAYS)
  268.            {pinst->fTileAlways = TRUE;
  269.             pinst->fCascadeAlways = FALSE;
  270.             WinSendMsg (pinst->miWindow.hwndSubMenu, MM_SETITEMATTR,
  271.               MPFROM2SHORT (CMD_TILE_ALWAYS, FALSE),
  272.               MPFROM2SHORT (MIA_CHECKED, MIA_CHECKED));
  273.            }
  274.  
  275.       // Handle "initial cascade always"
  276.  
  277.          if (flOptions & MDI_INITIAL_CASCADE_ALWAYS)
  278.            {pinst->fTileAlways = FALSE;
  279.             pinst->fCascadeAlways = TRUE;
  280.             WinSendMsg (pinst->miWindow.hwndSubMenu, MM_SETITEMATTR,
  281.               MPFROM2SHORT (CMD_CASCADE_ALWAYS, FALSE),
  282.               MPFROM2SHORT (MIA_CHECKED, MIA_CHECKED));
  283.            }
  284.  
  285.       // Handle "initial maximized desktop"
  286.  
  287.          if (flOptions & MDI_INITIAL_MAX_DESKTOP)
  288.             WinSendMsg (hwndFrame, WM_SYSCOMMAND,
  289.               MPFROMSHORT ((CMD_DESKTOP_MAXIMIZE - CMD_DESKTOP_BASE) | SC_SIZE),
  290.               MPFROM2SHORT (CMDSRC_ACCELERATOR, FALSE));
  291.  
  292.    // Return
  293.  
  294.       return hwndFrame;
  295.  
  296.      }
  297.  
  298.  
  299. // Function: MDICreateDocument - Create MDI Document
  300. // -------------------------------------------------
  301.    HWND EXPENTRY MDICreateDocument (pfnUser, hwndParent, flFrameFlags, pszName,
  302.                                hmodResources, idResources, phwndClient, cbDocData, cbInstData, idDocument)
  303.  
  304.       PFNWP pfnUser;                   // User window procedure
  305.       HWND hwndParent;                 // Document parent
  306.       ULONG flFrameFlags;              // Frame creation flags
  307.       PCHAR pszName;                   // Document name
  308.       HMODULE hmodResources;           // Module that contains resources
  309.       USHORT idResources;              // Resources identifier
  310.       PHWND phwndClient;               // -->area to receive document handle
  311.       USHORT cbDocData;                // Size of user document data
  312.       USHORT cbInstData;               // Size of user document data
  313.       USHORT idDocument;               // Document frame id
  314.  
  315.    // Define function data
  316.  
  317.      {HWND hwndFrame;                  // Frame window
  318.       FRAMECDATA fcdata;               // Frame creation parameters
  319.       DOCUMENTCREATEPARMS doccp;       // Document creation parameters
  320.       PINSTDOCUMENT pinst;             // -->document instance data
  321.  
  322.    // Initialize frame creation parameters
  323.  
  324.       fcdata.cb = sizeof (fcdata);
  325.       fcdata.flCreateFlags = flFrameFlags;
  326.       fcdata.hmodResources = hmodResources;
  327.       fcdata.idResources = idResources;
  328.  
  329.    // Initialize document creation parameters
  330.  
  331.       doccp.cbDocData = cbDocData;
  332.       doccp.cbInstData = cbInstData;
  333.       doccp.pfnUser = pfnUser;
  334.       doccp.flCreateFlags = flFrameFlags;
  335.       doccp.hmodResources = hmodResources;
  336.       doccp.idResources = idResources;
  337.  
  338.    // Create document frame and client windows
  339.  
  340.       hwndFrame = WinCreateWindow (hwndParent, WC_FRAME, pszName,
  341.         WS_VISIBLE, 0, 0, 0, 0, (PVOID) NULL, HWND_TOP, idDocument, &fcdata, (PVOID) NULL);
  342.       if (hwndFrame == (HWND) NULL) return (HWND) NULL;
  343.       *phwndClient = WinCreateWindow (hwndFrame, MDI_DOCUMENTCLASS, (PSZ) NULL,
  344.         WS_VISIBLE, 0, 0, 0, 0, hwndFrame, HWND_BOTTOM, FID_CLIENT, &doccp, (PVOID) NULL);
  345.       if (*phwndClient == (HWND) NULL) return (HWND) NULL;
  346.  
  347.    // Subclass document window procedure
  348.  
  349.       if (pfnUser != (PFNWP) NULL)
  350.          WinSubclassWindow (*phwndClient, pfnUser);
  351.  
  352.    // Tell user that document and instance has been created
  353.  
  354.       pinst = (PINSTDOCUMENT) WinQueryWindowULong (*phwndClient, QWL_USER + sizeof (PVOID));
  355.       if (pinst->iName <= 1)
  356.          WinSendMsg (*phwndClient, WM_CONTROL,
  357.            MPFROM2SHORT (pinst->idDesktop, MDI_NOTIFY_CREATE_DOCUMENT),
  358.            (MPARAM) pinst->pvDocData);
  359.       WinSendMsg (*phwndClient, WM_CONTROL,
  360.         MPFROM2SHORT (pinst->idDesktop, MDI_NOTIFY_CREATE_INSTANCE),
  361.         (MPARAM) pinst->pvInstData);
  362.  
  363.    // Return
  364.  
  365.       return hwndFrame;
  366.  
  367.      }
  368.  
  369.  
  370. // Function: MDIDesktopClose - Close MDI Desktop
  371. // ---------------------------------------------
  372.    MRESULT FAR MDIDesktopClose (pinst)
  373.  
  374.       PINSTDESKTOP pinst;              // -->desktop instance data
  375.  
  376.    // Define function data
  377.  
  378.      {PINSTDOCUMENT pinstDocument;     // -->document instance data
  379.       HWND hwnd, hwndNext;             // Document window
  380.       BOOL fNoQuit = FALSE;            // TRUE == don't quit
  381.  
  382.    // Ask if the desktop can be closed; if it can't nothing else changes
  383.  
  384.       if ((BOOL) SHORT1FROMMR (WinSendMsg (pinst->hwndDesktop, WM_CONTROL,
  385.        MPFROM2SHORT (pinst->idDesktop, MDI_INHIBIT_CLOSE_DESKTOP), (MPARAM) pinst->pvDeskData)) == TRUE)
  386.          return (MRESULT) NULL;
  387.  
  388.    // Close all open documents if the user lets us
  389.  
  390.       for (hwnd = WinQueryWindow (pinst->hwndDesktop, QW_TOP, FALSE);
  391.        hwnd; hwnd = WinQueryWindow (hwnd, QW_NEXT, FALSE))
  392.         {retryClose: if ((WinQueryWindow (hwnd, QW_OWNER, FALSE) == (HWND) NULL)
  393.           && (WinQueryWindowUShort (hwnd, QWS_ID) != 0))
  394.            {pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong
  395.              (WinWindowFromID (hwnd, FID_CLIENT), QWL_USER + sizeof (PVOID));
  396.             if ((BOOL) SHORT1FROMMR (WinSendMsg (pinstDocument->hwndDocument, WM_CONTROL,
  397.              MPFROM2SHORT (pinstDocument->idDesktop, MDI_INHIBIT_CLOSE_DESKTOP), (MPARAM) pinstDocument->pvInstData)) == FALSE)
  398.               {hwndNext = WinQueryWindow (hwnd, QW_NEXT, FALSE);
  399.                WinDestroyWindow (hwnd);
  400.                if ((hwnd = hwndNext) == NULL) break;
  401.                goto retryClose;
  402.               }
  403.             else fNoQuit = TRUE;
  404.            }
  405.         }
  406.  
  407.    // Quit if the user lets us
  408.  
  409.       if (!fNoQuit)
  410.         {WinDestroyWindow (pinst->hwndFrame);
  411.          WinPostMsg ((HWND) NULL, WM_QUIT, NULL, NULL);
  412.         }
  413.  
  414.    // Indicate close handled
  415.  
  416.       return (MRESULT) NULL;
  417.  
  418.      }
  419.  
  420.  
  421. // Function: MDIDesktopCommand - Handle MDI Desktop Command
  422. // --------------------------------------------------------
  423.    MRESULT FAR MDIDesktopCommand (pinst, usCommand)
  424.  
  425.       PINSTDESKTOP pinst;              // -->desktop instance data
  426.       USHORT usCommand;                // WM_COMMAND code
  427.  
  428.    // Define function data
  429.  
  430.      {PINSTDOCUMENT pinstDocument;     // -->document instance data
  431.       HWND hdlg;                       // Unhide dialog box
  432.  
  433.    // Act upon command code
  434.  
  435.       switch (usCommand)
  436.  
  437.    // Handle Desktop system menu command by passing the system equivalent
  438.    // to the desktop frame
  439.  
  440.         {case CMD_DESKTOP_SIZE:
  441.          case CMD_DESKTOP_MOVE:
  442.          case CMD_DESKTOP_MINIMIZE:
  443.          case CMD_DESKTOP_MAXIMIZE:
  444.          case CMD_DESKTOP_CLOSE:
  445.          case CMD_DESKTOP_NEXT:
  446.          case CMD_DESKTOP_APPMENU:
  447.          case CMD_DESKTOP_SYSMENU:
  448.          case CMD_DESKTOP_RESTORE:
  449.             WinSendMsg (pinst->hwndFrame, WM_SYSCOMMAND,
  450.               MPFROMSHORT ((usCommand - CMD_DESKTOP_BASE) | SC_SIZE),
  451.               MPFROM2SHORT (CMDSRC_ACCELERATOR, FALSE));
  452.             break;
  453.  
  454.    // Handle Maximized Document system menu command by applying
  455.    // the command to the active document
  456.  
  457.          case CMD_DOCUMENT_SIZE:
  458.          case CMD_DOCUMENT_MOVE:
  459.          case CMD_DOCUMENT_MINIMIZE:
  460.          case CMD_DOCUMENT_MAXIMIZE:
  461.          case CMD_DOCUMENT_CLOSE:
  462.          case CMD_DOCUMENT_NEXT:
  463.          case CMD_DOCUMENT_APPMENU:
  464.          case CMD_DOCUMENT_SYSMENU:
  465.          case CMD_DOCUMENT_RESTORE:
  466.             if (pinst->hwndDocument != (HWND) NULL)
  467.               {pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (pinst->hwndDocument,
  468.                  QWL_USER + sizeof (PVOID));
  469.                if (pinstDocument->usState == SWP_MAXIMIZE)
  470.                  {if (usCommand == CMD_DOCUMENT_RESTORE)
  471.                     {WinSetParent (pinstDocument->hwndMinMax, pinstDocument->hwndFrame, FALSE);
  472.                      WinSetWindowPos (pinstDocument->hwndFrame, (HWND) NULL, 0, 0, 0, 0, SWP_RESTORE);
  473.                     }
  474.                   else if (usCommand == CMD_DOCUMENT_NEXT)
  475.                      WinSendMsg (pinstDocument->hwndFrame, WM_SYSCOMMAND,
  476.                        MPFROMSHORT (SC_NEXT), MPFROM2SHORT (CMDSRC_MENU, FALSE));
  477.                   else if (usCommand == CMD_DOCUMENT_CLOSE)
  478.                      WinDestroyWindow (pinstDocument->hwndFrame);
  479.                  }
  480.               }
  481.             else WinAlarm (HWND_DESKTOP, WA_WARNING);
  482.             break;
  483.  
  484.    // Handle arrange tiled request
  485.  
  486.          case CMD_ARRANGE_TILED:
  487.             MDIDocumentArrange (pinst->hwndDesktop, AWP_TILED);
  488.             break;
  489.  
  490.    // Handle arrange cascaded request
  491.  
  492.          case CMD_ARRANGE_CASCADED:
  493.             MDIDocumentArrange (pinst->hwndDesktop, AWP_CASCADED);
  494.             break;
  495.  
  496.    // Handle tile always request by reseting flags and checking menu items;
  497.    // then we perform actual tile
  498.  
  499.          case CMD_TILE_ALWAYS:
  500.             pinst->fTileAlways = ! pinst->fTileAlways;
  501.             pinst->fCascadeAlways = FALSE;
  502.             WinSendMsg (pinst->miWindow.hwndSubMenu, MM_SETITEMATTR,
  503.               MPFROM2SHORT (CMD_TILE_ALWAYS, FALSE),
  504.               MPFROM2SHORT (MIA_CHECKED, (pinst->fTileAlways)? MIA_CHECKED : FALSE));
  505.             WinSendMsg (pinst->miWindow.hwndSubMenu, MM_SETITEMATTR,
  506.               MPFROM2SHORT (CMD_CASCADE_ALWAYS, FALSE), MPFROM2SHORT (MIA_CHECKED, FALSE));
  507.             if (pinst->fTileAlways)
  508.                MDIDocumentArrange (pinst->hwndDesktop, AWP_TILED);
  509.             break;
  510.  
  511.    // Handle cascade always request by reseting flags and checking menu items;
  512.    // then we perform actual cascade
  513.  
  514.          case CMD_CASCADE_ALWAYS:
  515.             pinst->fCascadeAlways = ! pinst->fCascadeAlways;
  516.             pinst->fTileAlways = FALSE;
  517.             WinSendMsg (pinst->miWindow.hwndSubMenu, MM_SETITEMATTR,
  518.               MPFROM2SHORT (CMD_CASCADE_ALWAYS, FALSE),
  519.               MPFROM2SHORT (MIA_CHECKED, (pinst->fCascadeAlways)? MIA_CHECKED : FALSE));
  520.             WinSendMsg (pinst->miWindow.hwndSubMenu, MM_SETITEMATTR,
  521.               MPFROM2SHORT (CMD_TILE_ALWAYS, FALSE), MPFROM2SHORT (MIA_CHECKED, FALSE));
  522.             if (pinst->fCascadeAlways)
  523.                MDIDocumentArrange (pinst->hwndDesktop, AWP_CASCADED);
  524.             break;
  525.  
  526.    // Handle request to hide document by removing its entry from the
  527.    // window submenu, activating the next entry in the submenu (if any)
  528.    // and hiding the document
  529.  
  530.          case CMD_HIDE:
  531.             if (pinst->hwndDocument != (HWND) NULL)
  532.               {pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (pinst->hwndDocument,
  533.                  QWL_USER + sizeof (PVOID));
  534.                MDIDocumentHide (pinstDocument);
  535.               }
  536.             break;
  537.  
  538.    // Handle request to unhide document using the unhide dialog procedure
  539.  
  540.          case CMD_UNHIDE:
  541.             hdlg = MDILoadDialog (pinst->hwndDesktop, MDIDocumentUnhideDlgProc,
  542.                DIALOG_UNHIDE, (PVOID) pinst);
  543.             WinProcessDlg (hdlg);
  544.             WinDestroyWindow (hdlg);
  545.             break;
  546.  
  547.    // Handle request for a new document by creating the document
  548.    // based on the currently active document
  549.  
  550.          case CMD_NEW_DOCUMENT:
  551.             if (pinst->hwndDocument != (HWND) NULL)
  552.               {pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (pinst->hwndDocument,
  553.                  QWL_USER + sizeof (PVOID));
  554.                MDIDocumentClone (pinstDocument);
  555.               }
  556.             break;
  557.  
  558.    // Handle request to display the "More Documents" dialog
  559.  
  560.          case CMD_MORE_DOCUMENTS:
  561.             hdlg = MDILoadDialog (pinst->hwndDesktop, MDIDocumentMoreDlgProc,
  562.                DIALOG_MORE, (PVOID) pinst);
  563.             WinProcessDlg (hdlg);
  564.             WinDestroyWindow (hdlg);
  565.             break;
  566.  
  567.    // Handle request to activate document
  568.  
  569.          default:
  570.             if (usCommand >= CMD_SELECT_DOCUMENT)
  571.                WinSetWindowPos (MDIDocumentFrameFromID (pinst->hwndDesktop, usCommand),
  572.                  HWND_TOP, 0, 0, 0, 0, SWP_ACTIVATE | SWP_ZORDER);
  573.             else if ((usCommand < CMD_DESKTOP_BASE) && (pinst->hwndDocument != (HWND) NULL))
  574.                WinSendMsg (pinst->hwndDocument, WM_COMMAND,
  575.                  MPFROMSHORT (usCommand), MPFROM2SHORT (CMDSRC_ACCELERATOR, FALSE));
  576.             break;
  577.  
  578.    // Complete handling of command code
  579.  
  580.         }
  581.  
  582.    // Indicate command handled
  583.  
  584.       return (MRESULT) NULL;
  585.  
  586.      }
  587.  
  588.  
  589. // Function: MDIDesktopCreate - Create MDI Desktop
  590. // -----------------------------------------------
  591.    MRESULT FAR MDIDesktopCreate (hwndDesktop, pdeskcp)
  592.  
  593.       HWND hwndDesktop;                // Desktop window
  594.       PDESKTOPCREATEPARMS pdeskcp;     // -->desktop creation parameters
  595.  
  596.    // Define function data
  597.  
  598.      {PINSTDESKTOP pinst;              // -->instance data
  599.       BOOL fIniDatFound;               // TRUE == OS2.INI data found
  600.       USHORT cbBuf;                    // Length of OS2.INI data
  601.       SHORT xLeft, xRight;             // X indentation factors
  602.       SHORT yBottom, yTop;             // Y indentation factors
  603.       CHAR szText[MAX_STRING];         // Menu item text
  604.  
  605.    // Acquire instance data and save in MDI desktop window
  606.  
  607.       pinst = AllocMemAlloc ((LONG) (sizeof (*pinst)));
  608.       WinSetWindowULong (hwndDesktop, QWL_USER + sizeof (PVOID), (ULONG) pinst);
  609.  
  610.    // Copy desktop creation parameters if available
  611.  
  612.       if (pdeskcp != (PDESKTOPCREATEPARMS) NULL)
  613.         {pinst->pszDelta = pdeskcp->pszDelta;
  614.          pinst->pszExit = pdeskcp->pszExit;
  615.          pinst->pszWindow = pdeskcp->pszWindow;
  616.         }
  617.  
  618.    // Initialize inter-window relationships
  619.  
  620.       pinst->hwndDesktop = hwndDesktop;
  621.       pinst->hwndFrame = WinQueryWindow (pinst->hwndDesktop, QW_PARENT, FALSE);
  622.       pinst->hwndParent = WinQueryWindow (pinst->hwndFrame, QW_PARENT, FALSE);
  623.       pinst->hwndMenu = WinWindowFromID (pinst->hwndFrame, FID_MENU);
  624.       pinst->idDesktop = WinQueryWindowUShort (pinst->hwndFrame, QWS_ID);
  625.  
  626.    // Verify inter-window relationships
  627.  
  628.       while (pinst->hwndMenu == (HWND) NULL)
  629.          TellUser (ERROR_DESKTOP_NO_MENU, MDI_MODNAME, MB_ABORTRETRYIGNORE | MB_ICONHAND);
  630.  
  631.    // Find location in desktop menu at which to insert the document menu deltas
  632.  
  633.       pinst->miDelta.iPosition = 0;
  634.       while ((pinst->miDelta.id = SHORT1FROMMR (WinSendMsg (pinst->hwndMenu, MM_ITEMIDFROMPOSITION,
  635.        MPFROMSHORT (pinst->miDelta.iPosition), (MPARAM) NULL))) != MID_ERROR)
  636.         {WinSendMsg (pinst->hwndMenu, MM_QUERYITEMTEXT, MPFROM2SHORT (pinst->miDelta.id,
  637.            sizeof (szText)), (MPARAM) szText);
  638.          if (strcmpi (szText, pinst->pszDelta) == 0) break;
  639.          pinst->miDelta.iPosition++;
  640.         }
  641.  
  642.    // Verify that a location for the window sub-menu was found
  643.  
  644.       while (pinst->miDelta.id == MID_ERROR)
  645.          TellUser (ERROR_DESKTOP_NO_DELTA, MDI_MODNAME, MB_ABORTRETRYIGNORE | MB_ICONHAND, pinst->pszDelta);
  646.  
  647.    // Find location in desktop menu at which to insert the window sub-menu
  648.  
  649.       pinst->miWindow.iPosition = 0;
  650.       while ((pinst->miWindow.id = SHORT1FROMMR (WinSendMsg (pinst->hwndMenu, MM_ITEMIDFROMPOSITION,
  651.        MPFROMSHORT (pinst->miWindow.iPosition), (MPARAM) NULL))) != MID_ERROR)
  652.         {WinSendMsg (pinst->hwndMenu, MM_QUERYITEMTEXT, MPFROM2SHORT (pinst->miWindow.id,
  653.            sizeof (szText)), (MPARAM) szText);
  654.          if (strcmpi (szText, pinst->pszExit) == 0) break;
  655.          pinst->miWindow.iPosition++;
  656.         }
  657.  
  658.    // Verify that a location for the window sub-menu was found
  659.  
  660.       while (pinst->miWindow.id == MID_ERROR)
  661.          TellUser (ERROR_DESKTOP_NO_EXIT, MDI_MODNAME, MB_ABORTRETRYIGNORE | MB_ICONHAND, pinst->pszExit);
  662.  
  663.    // Initialize the window menu
  664.  
  665.       pinst->miWindow.afStyle = MIS_TEXT | MIS_SUBMENU;
  666.       pinst->miWindow.afAttribute = 0;
  667.       pinst->miWindow.id = MENU_WINDOW;
  668.       pinst->miWindow.hwndSubMenu = MDILoadMenu (pinst->hwndMenu, MENU_WINDOW);
  669.       pinst->miWindow.hItem = (ULONG) NULL;
  670.  
  671.    // Initialize the maximized child system menu
  672.  
  673.       pinst->miSysMenu.iPosition = 0;
  674.       pinst->miSysMenu.afStyle = MIS_BITMAP | MIS_SUBMENU;
  675.       pinst->miSysMenu.afAttribute = 0;
  676.       pinst->miSysMenu.id = MENU_MAXCHILD_SYSMENU;
  677.       pinst->miSysMenu.hwndSubMenu = MDILoadMenu (pinst->hwndMenu, MENU_MAXCHILD_SYSMENU);
  678.       pinst->miSysMenu.hItem = (ULONG) WinGetSysBitmap (HWND_DESKTOP, SBMP_CHILDSYSMENU);
  679.  
  680.    // Load accelerator table
  681.  
  682.       pinst->haccel = MDILoadAccelTable (ACCEL_DESKTOP);
  683.       WinSetAccelTable ((HAB) NULL, pinst->haccel, pinst->hwndFrame);
  684.  
  685.    // Determine initial name
  686.  
  687.       WinQueryWindowText (pinst->hwndFrame, sizeof (pinst->szName), pinst->szName);
  688.  
  689.    // Create user desktop data if applicable
  690.  
  691.       if (pdeskcp && (pdeskcp->cbDeskData > 0))
  692.          pinst->pvDeskData = AllocMemAlloc ((LONG) (pdeskcp->cbDeskData));
  693.  
  694.    // Recall window position from OS2.INI file, if available
  695.  
  696.       cbBuf = sizeof (pinst->swp);
  697.       pinst->swp.fs = 0;
  698.       if (! pinst->fDisableDesktopPosition)
  699.         fIniDatFound = WinQueryProfileData ((HAB) NULL, MDI_DESKTOPCLASS,
  700.           pinst->szName, &(pinst->swp), &cbBuf);
  701.       else fIniDatFound = FALSE;
  702.  
  703.    // If no prior position was stored, or if the window was maximized,
  704.    // minimized or hidden, find a default position
  705.  
  706.       if (! fIniDatFound || (pinst->swp.fs & (SWP_MINIMIZE | SWP_MAXIMIZE /* | SWP_HIDE */)))
  707.         {xLeft = (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CXSIZEBORDER);
  708.          xRight = (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CXSIZEBORDER);
  709.          yTop = (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CYSIZEBORDER);
  710.          yBottom = 2 * (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CYICON);
  711.          pinst->swp.x = xLeft;
  712.          pinst->swp.y = yBottom;
  713.          pinst->swp.cx = (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN) - xLeft - xRight;
  714.          pinst->swp.cy = (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN) - yBottom - yTop;
  715.          pinst->swp.fs &= ~SWP_HIDE;
  716.         }
  717.  
  718.    // Display and position the desktop window
  719.  
  720.       pinst->swp.fs |= SWP_ACTIVATE | SWP_MOVE | SWP_SIZE | SWP_SHOW | SWP_ZORDER;
  721.       pinst->swp.hwndInsertBehind = HWND_TOP;
  722.       pinst->swp.hwnd = pinst->hwndFrame;
  723.       WinSetMultWindowPos ((HAB) NULL, &(pinst->swp), 1);
  724.  
  725.    // Indicate create handled
  726.  
  727.       return (MRESULT) NULL;
  728.  
  729.      }
  730.  
  731.  
  732. // Function: MDIDesktopDestroy - Destroy MDI Desktop
  733. // -------------------------------------------------
  734.    MRESULT FAR MDIDesktopDestroy (pinst)
  735.  
  736.       PINSTDESKTOP pinst;              // -->desktop instance data
  737.  
  738.    // Save window position onto OS2.INI file
  739.  
  740.      {pinst->swp.fs &= ~SWP_HIDE;
  741.       if (! pinst->fDisableDesktopPosition)
  742.         WinWriteProfileData ((HAB) NULL, MDI_DESKTOPCLASS, pinst->szName,
  743.           &(pinst->swp), sizeof (pinst->swp));
  744.  
  745.    // Free accelerator table
  746.  
  747.       WinDestroyAccelTable (pinst->haccel);
  748.  
  749.    // Tell user desktop will be destroyed
  750.  
  751.       WinSendMsg (pinst->hwndDesktop, WM_CONTROL,
  752.         MPFROM2SHORT (pinst->idDesktop, MDI_NOTIFY_DESTROY_DESKTOP),
  753.         (MPARAM) pinst->pvDeskData);
  754.  
  755.    // Free user desktop data if applicable
  756.  
  757.       if (pinst->pvDeskData)
  758.          AllocMemFree (pinst->pvDeskData);
  759.  
  760.    // Free instance data
  761.  
  762.       AllocMemFree (pinst);
  763.  
  764.    // Indicate destroy handled
  765.  
  766.       return (MRESULT) NULL;
  767.  
  768.      }
  769.  
  770.  
  771. // Function: MDIDesktopMinMax - Minimize/Maximize MDI Desktop
  772. // ----------------------------------------------------------
  773.    MRESULT FAR MDIDesktopMinMax (pinst, pswp)
  774.  
  775.       PINSTDESKTOP pinst;              // -->desktop instance data
  776.       PSWP pswp;                       // -->desktop position information
  777.  
  778.    // Define function data
  779.  
  780.      {PINSTDOCUMENT pinstDocument;     // -->document instance data
  781.       HWND hwndDocument;               // Document window
  782.       HWND hwnd;                       // Document window handle
  783.       ULONG ulStyle;                   // Document window style
  784.  
  785.    // Fool the compiler
  786.  
  787.       pswp = pswp;
  788.  
  789.    // We restore all maximized documents
  790.  
  791.       for (hwnd = WinQueryWindow (pinst->hwndDesktop, QW_TOP, FALSE);
  792.        hwnd; hwnd = WinQueryWindow (hwnd, QW_NEXT, FALSE))
  793.  
  794.          // Determine document style
  795.  
  796.         {ulStyle = WinQueryWindowULong (hwnd, QWL_STYLE);
  797.  
  798.          // Ignore documents that are invisible or that do not
  799.          // belong to the desktop
  800.  
  801.          if (WinQueryWindow (hwnd, QW_OWNER, FALSE)
  802.           || (WinQueryWindowUShort (hwnd, QWS_ID) == 0)
  803.           || !(ulStyle & WS_VISIBLE)) continue;
  804.  
  805.          // If the document is maximized, restore it
  806.  
  807.          if (ulStyle & WS_MAXIMIZED)
  808.            {hwndDocument = WinWindowFromID (hwnd, FID_CLIENT);
  809.             pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong
  810.               (hwndDocument, QWL_USER + sizeof (PVOID));
  811.             WinSetParent (pinstDocument->hwndMinMax, pinstDocument->hwndFrame, FALSE);
  812.             WinSetWindowPos (hwnd, (HWND) NULL, 0, 0, 0, 0, SWP_RESTORE);
  813.             if (pinst->hwndDocument != hwndDocument)
  814.                MDIDocumentShowFrameCtls (pinstDocument, FALSE, FALSE, TRUE);
  815.            }
  816.  
  817.          // Loop until all documents processed
  818.  
  819.         }
  820.  
  821.    // Indicate min/max handled
  822.  
  823.       return (MRESULT) NULL;
  824.  
  825.      }
  826.  
  827.  
  828. // Function: MDIDesktopPaint - Paint MDI Desktop
  829. // ---------------------------------------------
  830.    MRESULT FAR MDIDesktopPaint (pinst)
  831.  
  832.       PINSTDESKTOP pinst;              // -->desktop instance data
  833.  
  834.    // Define function data
  835.  
  836.      {HPS hps;                         // Presentation space
  837.       RECTL rcl;                       // Update rectangle
  838.  
  839.    // Paint a SYSCLR_WINDOW background
  840.  
  841.       hps = WinBeginPaint (pinst->hwndDesktop, (HPS) NULL, &rcl);
  842.       WinFillRect (hps, &rcl, SYSCLR_APPWORKSPACE);
  843.       WinEndPaint (hps);
  844.  
  845.    // Indicate paint handled
  846.  
  847.       return (MRESULT) NULL;
  848.  
  849.      }
  850.  
  851.  
  852. // Function: MDIDesktopSizeAndMove - Size and Move Documents in MDI Desktop
  853. // ---------------------------------------------------------------------
  854.    MRESULT FAR MDIDesktopSizeAndMove (pinst)
  855.  
  856.       PINSTDESKTOP pinst;              // -->desktop instance data
  857.  
  858.    // Define function data
  859.  
  860.      {PINSTDOCUMENT pinstDocument;     // -->document instance data
  861.       HWND hwnd;                       // Document window handle
  862.       ULONG ulStyle;                   // Window style
  863.       SWP swpDesktop;                  // Current desktop position
  864.       SWP swpDocument;                 // Current document position
  865.  
  866.    // Capture new desktop position, saving the current position
  867.  
  868.       swpDesktop = pinst->swp;
  869.       WinQueryWindowPos (pinst->hwndFrame, &(pinst->swp));
  870.  
  871.    // Don't do anything if the size hasn't changed
  872.  
  873.       if ((swpDesktop.cx == pinst->swp.cx) && (swpDesktop.cy == pinst->swp.cy))
  874.          return (MRESULT) NULL;
  875.  
  876.    // Don't do anything if the desktop is (or was) minimized
  877.  
  878.       ulStyle = WinQueryWindowULong (pinst->hwndFrame, QWL_STYLE);
  879.       if ((ulStyle & WS_MINIMIZED) || (swpDesktop.fs & SWP_MINIMIZE))
  880.          return (MRESULT) NULL;
  881.  
  882.    // If tile, cascade always on resize is in effect, perform operation
  883.  
  884.       if (pinst->fAlwaysOnResize && (pinst->fCascadeAlways || pinst->fTileAlways))
  885.         {if (pinst->fTileAlways)
  886.             WinPostMsg (pinst->hwndDesktop, WM_COMMAND, MPFROMSHORT (CMD_ARRANGE_TILED), (MPARAM) NULL);
  887.          else if (pinst->fCascadeAlways)
  888.             WinPostMsg (pinst->hwndDesktop, WM_COMMAND, MPFROMSHORT (CMD_ARRANGE_CASCADED), (MPARAM) NULL);
  889.         }
  890.  
  891.    // Otherwise, we move all documents that are themselves not minimized
  892.  
  893.       else
  894.         {for (hwnd = WinQueryWindow (pinst->hwndDesktop, QW_TOP, FALSE);
  895.           hwnd; hwnd = WinQueryWindow (hwnd, QW_NEXT, FALSE))
  896.  
  897.             // Determine document style
  898.  
  899.            {ulStyle = WinQueryWindowULong (hwnd, QWL_STYLE);
  900.  
  901.             // Ignore documents that are invisible or that do not
  902.             // belong to the desktop
  903.  
  904.             if (WinQueryWindow (hwnd, QW_OWNER, FALSE)
  905.              || (WinQueryWindowUShort (hwnd, QWS_ID) == 0)
  906.              || !(ulStyle & WS_VISIBLE)) continue;
  907.  
  908.             // If the document is not minimized move relative to its top left corner
  909.  
  910.             if (!(ulStyle & WS_MINIMIZED))
  911.               {pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong
  912.                  (WinWindowFromID (hwnd, FID_CLIENT), QWL_USER + sizeof (PVOID));
  913.                WinQueryWindowPos (pinstDocument->hwndFrame, &swpDocument);
  914.                WinSetWindowPos (pinstDocument->hwndFrame, (HWND) NULL,
  915.                  swpDocument.x, swpDocument.y + (swpDesktop.y - pinst->swp.y), 0, 0, SWP_MOVE);
  916.               }
  917.  
  918.             // Loop until all documents processed
  919.  
  920.            }
  921.  
  922.         }
  923.  
  924.    // Indicate size/move handled
  925.  
  926.       return (MRESULT) NULL;
  927.  
  928.      }
  929.  
  930.  
  931. // Function: MDIDesktopWndProc - MDI Desktop window procedure
  932. // ----------------------------------------------------------
  933.    MRESULT EXPENTRY MDIDesktopWndProc (hwndDesktop, msg, mp1, mp2)
  934.  
  935.       HWND hwndDesktop;                // Desktop window
  936.       USHORT msg;                      // PM message
  937.       MPARAM mp1;                      // Mesage parameter 1
  938.       MPARAM mp2;                      // Mesage parameter 2
  939.  
  940.    // Define function data
  941.  
  942.      {PINSTDESKTOP pinst;              // -->instance data
  943.       PINSTDOCUMENT pinstDocument;     // -->document instance data
  944.       CHAR szName[MAX_STRING];         // Title text
  945.  
  946.    // Locate instance data
  947.  
  948.       pinst = (PINSTDESKTOP) WinQueryWindowULong (hwndDesktop, QWL_USER + sizeof (PVOID));
  949.  
  950.    // Analyze and process message
  951.  
  952.       switch (msg)
  953.  
  954.         {case WM_CLOSE:
  955.             return MDIDesktopClose (pinst);
  956.  
  957.          case WM_COMMAND:
  958.             return MDIDesktopCommand (pinst, LOUSHORT (mp1));
  959.  
  960.          case WM_CREATE:
  961.             return MDIDesktopCreate (hwndDesktop, (PDESKTOPCREATEPARMS) mp1);
  962.  
  963.          case WM_DESTROY:
  964.             return MDIDesktopDestroy (pinst);
  965.  
  966.          case WM_INITMENU:
  967.             if (pinst->hwndDocument != (HWND) NULL)
  968.                WinSendMsg (pinst->hwndDocument, msg, mp1, mp2);
  969.             return (MRESULT) NULL;
  970.  
  971.          case WM_MENUEND:
  972.             if (pinst->hwndDocument != (HWND) NULL)
  973.                WinSendMsg (pinst->hwndDocument, msg, mp1, mp2);
  974.             return (MRESULT) NULL;
  975.  
  976.          case WM_MINMAXFRAME:
  977.             return MDIDesktopMinMax (pinst, (PSWP) mp1);
  978.  
  979.          case WM_MOVE:
  980.             return MDIDesktopSizeAndMove (pinst);
  981.  
  982.          case WM_PAINT:
  983.             return MDIDesktopPaint (pinst);
  984.  
  985.          case WM_SIZE:
  986.             return MDIDesktopSizeAndMove (pinst);
  987.  
  988.          case MDI_MSG_LOCATE_DESKTOP_DATA:
  989.             return (MRESULT) pinst->pvDeskData;
  990.  
  991.          case MDI_MSG_LOCATE_DOCUMENT_DATA:
  992.             if (pinst->hwndDocument != (HWND) NULL)
  993.               {pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (pinst->hwndDocument, QWL_USER + sizeof (PVOID));
  994.                return (MRESULT) pinstDocument->pvDocData;
  995.               }
  996.             else return (MRESULT) NULL;
  997.  
  998.          case MDI_MSG_LOCATE_INSTANCE_DATA:
  999.             if (pinst->hwndDocument != (HWND) NULL)
  1000.               {pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (pinst->hwndDocument, QWL_USER + sizeof (PVOID));
  1001.                return (MRESULT) pinstDocument->pvInstData;
  1002.               }
  1003.             else return (MRESULT) NULL;
  1004.  
  1005.          case MDI_MSG_LOCATE_ACTIVE_DOCUMENT:
  1006.             return (MRESULT) pinst->hwndDocument;
  1007.  
  1008.          case MDI_MSG_LOCATE_DESKTOP_MENU:
  1009.             return (MRESULT) pinst->hwndMenu;
  1010.  
  1011.          case MDI_MSG_LOCATE_DOCUMENT_MENU:
  1012.             if (pinst->hwndDocument != (HWND) NULL)
  1013.               {pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (pinst->hwndDocument, QWL_USER + sizeof (PVOID));
  1014.                return (MRESULT) pinstDocument->hwndMenu;
  1015.               }
  1016.             else return (MRESULT) NULL;
  1017.  
  1018.          case MDI_MSG_SET_DESKTOP_TITLE:
  1019.             strcpy (pinst->szTitleText, (PCHAR) mp1);
  1020.             if (pinst->hwndDocument != (HWND) NULL)
  1021.               {pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (pinst->hwndDocument, QWL_USER + sizeof (PVOID));
  1022.                if (pinstDocument->usState == SWP_MAXIMIZE)
  1023.                  {if ((pinstDocument->iName == 0) || (pinstDocument->szTitleText[0]))
  1024.                      sprintf (szName, "%s - %s", (pinst->szTitleText[0])? pinst->szTitleText : pinst->szName,
  1025.                       (pinstDocument->szTitleText[0])? pinstDocument->szTitleText : pinstDocument->szName);
  1026.                   else sprintf (szName, "%s - %s:%d", (pinst->szTitleText[0])? pinst->szTitleText : pinst->szName,
  1027.                       (pinstDocument->szTitleText[0])? pinstDocument->szTitleText : pinstDocument->szName, pinstDocument->iName);
  1028.                   WinSetWindowText (pinst->hwndFrame, szName);
  1029.                  }
  1030.                else WinSetWindowText (pinst->hwndFrame, pinst->szTitleText);
  1031.               }
  1032.             else WinSetWindowText (pinst->hwndFrame, pinst->szTitleText);
  1033.             return (MRESULT) NULL;
  1034.  
  1035.          case MDI_MSG_SET_INSTANCE_TITLE:
  1036.             if (pinst->hwndDocument != (HWND) NULL)
  1037.               {pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (pinst->hwndDocument, QWL_USER + sizeof (PVOID));
  1038.                strcpy (pinstDocument->szTitleText, (PCHAR) mp1);
  1039.                MDIDocumentTitlesRebuild (pinstDocument, UPDATE_TITLE);
  1040.               }
  1041.             WinSendMsg (pinst->hwndDesktop, MDI_MSG_SET_DESKTOP_TITLE,
  1042.               (MPARAM) (pinst->szTitleText[0])? pinst->szTitleText : pinst->szName, (MPARAM) NULL);
  1043.             return (MRESULT) NULL;
  1044.  
  1045.         }
  1046.  
  1047.    // Return to PM
  1048.  
  1049.       return WinDefWindowProc (hwndDesktop, msg, mp1, mp2);
  1050.  
  1051.      }
  1052.  
  1053.  
  1054. // Function: MDIDocumentActivate - Activate MDI Document
  1055. // -----------------------------------------------------
  1056.    MRESULT FAR MDIDocumentActivate (pinst, fActivate)
  1057.  
  1058.       PINSTDOCUMENT pinst;             // -->document instance data
  1059.       BOOL fActivate;                  // TRUE == document is being activated
  1060.  
  1061.    // Define function data
  1062.  
  1063.      {PINSTDESKTOP pinstDesktop;       // -->desktop instance data
  1064.       CHAR szName[MAX_STRING];         // Desktop name
  1065.       MENUITEM mi;                     // Menu item
  1066.       USHORT iItem;                    // Menu item position
  1067.       USHORT usNotify;                 // Notification code
  1068.  
  1069.    // Locate the desktop instance data
  1070.  
  1071.       pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (pinst->hwndDesktop, QWL_USER + sizeof (PVOID));
  1072.  
  1073.    // Notify document instance of activation/deactivation
  1074.  
  1075.       usNotify = (fActivate)? MDI_NOTIFY_ACTIVATE_INSTANCE : MDI_NOTIFY_DEACTIVATE_INSTANCE;
  1076.       WinSendMsg (pinst->hwndDocument, WM_CONTROL,
  1077.         MPFROM2SHORT (pinst->idDesktop, usNotify), (MPARAM) pinst->pvInstData);
  1078.  
  1079.    // Show/hide all frame controls if document is not maximized or minimized
  1080.  
  1081.       if ((pinst->usState != SWP_MAXIMIZE) && (pinst->usState != SWP_MINIMIZE))
  1082.          MDIDocumentShowFrameCtls (pinst, fActivate, FALSE, TRUE);
  1083.  
  1084.    // Set the handle of the active document window in the desktop
  1085.  
  1086.       pinstDesktop->hwndDocument = (fActivate)? pinst->hwndDocument : (HWND) NULL;
  1087.  
  1088.    // Check/uncheck the document title in the window menu
  1089.  
  1090.       WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_SETITEMATTR,
  1091.         MPFROM2SHORT (pinst->idInternal, FALSE),
  1092.         MPFROM2SHORT (MIA_CHECKED, (fActivate)? MIA_CHECKED : FALSE));
  1093.  
  1094.    // For maximized documents, insert/remove the maximized child system
  1095.    // menu from the desktop and set/reset the desktop title
  1096.  
  1097.       if (pinst->usState == SWP_MAXIMIZE)
  1098.         {if (fActivate)
  1099.            {if (! (BOOL) SHORT1FROMMR (WinSendMsg (pinstDesktop->hwndMenu, MM_QUERYITEM,
  1100.               MPFROM2SHORT (MENU_MAXCHILD_SYSMENU, FALSE), (MPARAM) &mi)))
  1101.               {WinSendMsg (pinstDesktop->hwndMenu, MM_INSERTITEM, (MPARAM) &(pinstDesktop->miSysMenu), (MPARAM) NULL);
  1102.                pinstDesktop->miWindow.iPosition++;
  1103.               }
  1104.             if ((pinst->iName == 0) || (pinst->szTitleText[0]))
  1105.               {sprintf (szName, "%s - %s", (pinstDesktop->szTitleText[0])? pinstDesktop->szTitleText : pinstDesktop->szName,
  1106.                 (pinst->szTitleText[0])? pinst->szTitleText : pinst->szName);
  1107.               }
  1108.             else
  1109.               {sprintf (szName, "%s - %s:%d", (pinstDesktop->szTitleText[0])? pinstDesktop->szTitleText : pinstDesktop->szName,
  1110.                 (pinst->szTitleText[0])? pinst->szTitleText : pinst->szName, pinst->iName);
  1111.               }
  1112.             WinSetWindowText (pinstDesktop->hwndFrame, szName);
  1113.            }
  1114.          else
  1115.            {if ((BOOL) SHORT1FROMMR (WinSendMsg (pinstDesktop->hwndMenu, MM_QUERYITEM,
  1116.               MPFROM2SHORT (MENU_MAXCHILD_SYSMENU, FALSE), (MPARAM) &mi)))
  1117.               {WinSendMsg (pinstDesktop->hwndMenu, MM_REMOVEITEM,
  1118.                  MPFROM2SHORT (MENU_MAXCHILD_SYSMENU, FALSE), (MPARAM) NULL);
  1119.                pinstDesktop->miWindow.iPosition--;
  1120.               }
  1121.             WinSetWindowText (pinstDesktop->hwndFrame, (pinstDesktop->szTitleText[0])? pinstDesktop->szTitleText : pinstDesktop->szName);
  1122.            }
  1123.         }
  1124.  
  1125.    // Disable the menu to avoid flicker
  1126.  
  1127.       WinEnableWindow (pinstDesktop->hwndMenu, FALSE);
  1128.  
  1129.    // If we are activating the document, remove the old menu delta
  1130.  
  1131.       if (fActivate && pinstDesktop->hwndMenuDelta && (pinstDesktop->hwndMenuDelta != pinst->hwndMenu))
  1132.         {for (iItem = 0; iItem < pinstDesktop->cidDelta; iItem++)
  1133.             WinSendMsg (pinstDesktop->hwndMenu, MM_REMOVEITEM, MPFROM2SHORT (pinstDesktop->idDelta[iItem], TRUE), (MPARAM) NULL);
  1134.          pinstDesktop->cidDelta = 0;
  1135.         }
  1136.  
  1137.    // If we are activating the document, insert the new menu delta
  1138.  
  1139.       if (fActivate && pinst->hwndMenu && (pinstDesktop->hwndMenuDelta != pinst->hwndMenu))
  1140.         {iItem = 0;
  1141.          while ((mi.id = SHORT1FROMMR (WinSendMsg (pinst->hwndMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT (iItem), (MPARAM) NULL))) != MID_ERROR)
  1142.            {WinSendMsg (pinst->hwndMenu, MM_QUERYITEMTEXT, MPFROM2SHORT (mi.id, MAX_STRING), (MPARAM) szName);
  1143.             WinSendMsg (pinst->hwndMenu, MM_QUERYITEM, MPFROM2SHORT (mi.id, FALSE), (MPARAM) &mi);
  1144.             mi.iPosition = pinstDesktop->miDelta.iPosition + iItem;
  1145.             WinSendMsg (pinstDesktop->hwndMenu, MM_INSERTITEM, (MPARAM) &mi, (MPARAM) szName);
  1146.             if (iItem < MAX_MENUDELTA)
  1147.                pinstDesktop->idDelta[iItem] = mi.id;
  1148.             iItem++;
  1149.            }
  1150.          pinstDesktop->hwndMenuDelta = pinst->hwndMenu;
  1151.          pinstDesktop->cidDelta = min (MAX_MENUDELTA, iItem);
  1152.         }
  1153.  
  1154.    // Reenable the menu
  1155.  
  1156.       WinEnableWindow (pinstDesktop->hwndMenu, TRUE);
  1157.  
  1158.    // Indicate activate handled
  1159.  
  1160.       return (MRESULT) NULL;
  1161.  
  1162.      }
  1163.  
  1164.  
  1165. // Function: MDIDocumentArrange - Arrange all documents in the desktop
  1166. // -------------------------------------------------------------------
  1167.    VOID FAR MDIDocumentArrange (hwndDesktop, fStyle)
  1168.  
  1169.       HWND hwndDesktop;                // Desktop window
  1170.       USHORT fStyle;                   // AWP_TILED or AWP_CASCADED
  1171.  
  1172.    // Define function data
  1173.  
  1174.      {USHORT cswpWnd, cswpIcon;        // Window, Icon count
  1175.       PSWP pswpWnd, pswpIcon;          // Window, Icon positions
  1176.       ULONG ulStyle;                   // Style flags
  1177.       RECTL rcl;                       // Rectangle work area
  1178.       HWND hwnd;                       // Window work area
  1179.       SHORT cDocs;                     // Document count
  1180.       USHORT yIcon;                    // Icon height
  1181.       SHORT cxBorderInset;             // Border inset width
  1182.       USHORT i;                        // Counter
  1183.       PINSTDESKTOP pinstDesktop;       // -->desktop instance data
  1184.       PINSTDOCUMENT pinstDocument;     // -->document instance data
  1185.       HWND hwndDocument;               // Document window
  1186.       USHORT usNotify;                 // Notification code
  1187.  
  1188.       SHORT cxBorder =                 // Border width
  1189.         (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CXSIZEBORDER);
  1190.  
  1191.       SHORT cyBorder =                 // Border height
  1192.         (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CYSIZEBORDER);
  1193.  
  1194.    // Locate the desktop instance data
  1195.  
  1196.       pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (hwndDesktop, QWL_USER + sizeof (PVOID));
  1197.  
  1198.    // Count the number of document windows
  1199.  
  1200.       for (cDocs = 0, hwnd = WinQueryWindow (hwndDesktop, QW_TOP, FALSE);
  1201.         hwnd; hwnd = WinQueryWindow (hwnd, QW_NEXT, FALSE)) cDocs++;
  1202.  
  1203.    // Allocate space for document and icon positions
  1204.  
  1205.       pswpWnd = (PSWP) AllocMemAlloc ((LONG) (sizeof(SWP) * cDocs));
  1206.       pswpIcon = (PSWP) AllocMemAlloc ((LONG) (sizeof(SWP) * cDocs));
  1207.  
  1208.    // Enumerate windows and selectively add them to the arrange lists
  1209.  
  1210.       for (cswpWnd = cswpIcon = 0, hwnd = WinQueryWindow (hwndDesktop, QW_TOP, FALSE);
  1211.        hwnd; hwnd = WinQueryWindow (hwnd, QW_NEXT, FALSE))
  1212.  
  1213.       // Make sure the window is visible and owned by the desktop
  1214.  
  1215.         {ulStyle = WinQueryWindowULong (hwnd, QWL_STYLE);
  1216.          if (WinQueryWindow (hwnd, QW_OWNER, FALSE)
  1217.           || (WinQueryWindowUShort (hwnd, QWS_ID) == 0)
  1218.           || !(ulStyle & WS_VISIBLE)) continue;
  1219.  
  1220.       // Count icons
  1221.  
  1222.          if (ulStyle & WS_MINIMIZED)
  1223.             pswpIcon[cswpIcon++].hwnd = hwnd;
  1224.  
  1225.       // Count windows (restore any that are maximized)
  1226.  
  1227.          else
  1228.            {if (ulStyle & WS_MAXIMIZED)
  1229.               {hwndDocument = WinWindowFromID (hwnd, FID_CLIENT);
  1230.                pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong
  1231.                  (hwndDocument, QWL_USER + sizeof (PVOID));
  1232.                WinSetParent (pinstDocument->hwndMinMax, pinstDocument->hwndFrame, FALSE);
  1233.                WinSetWindowPos (hwnd, (HWND) NULL, 0, 0, 0, 0, SWP_RESTORE);
  1234.                if (pinstDesktop->hwndDocument != hwndDocument)
  1235.                   MDIDocumentShowFrameCtls (pinstDocument, FALSE, FALSE, TRUE);
  1236.               }
  1237.             pswpWnd[cswpWnd++].hwnd = hwnd;
  1238.            }
  1239.  
  1240.       // Loop until all windows accounted for
  1241.  
  1242.         }
  1243.  
  1244.    // Get dimensions of desktop window
  1245.  
  1246.       WinQueryWindowRect (hwndDesktop, &rcl);
  1247.       cxBorderInset = (SHORT) (WinQuerySysValue (HWND_DESKTOP, SV_CXBYTEALIGN)
  1248.         - WinQuerySysValue (HWND_DESKTOP, SV_CXSIZEBORDER));
  1249.       WinInflateRect ((HAB) NULL, &rcl, -cxBorderInset, -cxBorderInset * (cyBorder / cxBorder));
  1250.  
  1251.    // Make room for a single row of icons
  1252.  
  1253.       if (cswpIcon > 0)
  1254.         {yIcon = LOUSHORT (WinQuerySysValue(HWND_DESKTOP, SV_CYICON));
  1255.          rcl.yBottom += (yIcon * ICON_PARK_NUM) / ICON_PARK_DENOM;
  1256.         }
  1257.  
  1258.    // Set window positions
  1259.  
  1260.       if (fStyle == AWP_CASCADED)
  1261.          MDIDocumentArrangeCascaded (&rcl, cswpWnd, pswpWnd);
  1262.       else if (fStyle == AWP_TILED)
  1263.          MDIDocumentArrangeTiled (&rcl, cswpWnd, pswpWnd);
  1264.  
  1265.    // Set icon positions
  1266.  
  1267.       for (i = 0; i < cswpIcon; i++)
  1268.         {pswpIcon[i].x = 0;
  1269.          pswpIcon[i].y = 0;
  1270.          pswpIcon[i].fs = SWP_MOVE;
  1271.         }
  1272.  
  1273.    // Inform all windows that they are being tiled or cascaded
  1274.  
  1275.       for (i = 0; i < cswpWnd; i++)
  1276.        {if (fStyle == AWP_CASCADED)
  1277.           usNotify = MDI_NOTIFY_CASCADE_INSTANCE;
  1278.         else if (fStyle == AWP_TILED)
  1279.           usNotify = MDI_NOTIFY_TILE_INSTANCE;
  1280.         pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong
  1281.           (WinWindowFromID (pswpWnd[i].hwnd, FID_CLIENT), QWL_USER + sizeof (PVOID));
  1282.         WinSendMsg (pinstDocument->hwndDocument, WM_CONTROL,
  1283.           MPFROM2SHORT (pinstDocument->idDesktop, usNotify), (MPARAM) pinstDocument->pvInstData);
  1284.        }
  1285.  
  1286.    // Reposition all windows and icons
  1287.  
  1288.       WinSetMultWindowPos ((HAB) NULL, pswpWnd, cswpWnd);
  1289.    // WinSetMultWindowPos ((HAB) NULL, pswpIcon, cswpIcon);
  1290.  
  1291.    // Free space used for document and icon positions
  1292.  
  1293.       AllocMemFree (pswpWnd);
  1294.       AllocMemFree (pswpIcon);
  1295.  
  1296.      }
  1297.  
  1298.  
  1299. // Function: MDIDocumentArrangeCascaded - Arrange all documents cascaded
  1300. // ---------------------------------------------------------------------
  1301.    VOID FAR MDIDocumentArrangeCascaded (prc, cWnd, aswp)
  1302.  
  1303.       PRECTL prc;                      // -->area in which arrange will occur
  1304.       SHORT cWnd;                      // Count of windows
  1305.       PSWP aswp;                       // Array of window positions
  1306.  
  1307.    // Define function data
  1308.  
  1309.      {SHORT xEdge, yEdge;
  1310.       SHORT xDelta, yDelta;
  1311.       SHORT cMaxWnd;
  1312.       SHORT x, y, i, j;
  1313.       RECTL rc;
  1314.  
  1315.       SHORT cxBorder =
  1316.         (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CXSIZEBORDER);
  1317.  
  1318.       SHORT cyBorder =
  1319.         (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CYSIZEBORDER);
  1320.  
  1321.    // Set cascade parameters
  1322.  
  1323.       rc.xLeft = prc->xLeft - cxBorder;
  1324.       rc.xRight = prc->xRight + cyBorder;
  1325.       rc.yBottom = prc->yBottom - cyBorder;
  1326.       rc.yTop = prc->yTop + cyBorder;
  1327.  
  1328.    // Get x and y deltas from system values
  1329.  
  1330.       xDelta = LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER))
  1331.         + LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CXMINMAXBUTTON)) / 2 + 2;
  1332.       yDelta = LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR));
  1333.  
  1334.    // Get initial cut at yEdge using fraction
  1335.  
  1336.       yEdge = (((SHORT)(rc.yTop - rc.yBottom)) * CASC_EDGE_NUM) / CASC_EDGE_DENOM;
  1337.  
  1338.    // Determine maximum number of deltas used per run
  1339.  
  1340.       cMaxWnd = (((SHORT)(rc.yTop - rc.yBottom)) - yEdge) / yDelta;
  1341.  
  1342.    // Set x and y edges so full cascade will fill rectangle completely
  1343.  
  1344.       xEdge = ((SHORT)(rc.xRight - rc.xLeft)) - xDelta/2 - cMaxWnd * xDelta;
  1345.       yEdge = ((SHORT)(rc.yTop - rc.yBottom)) - cMaxWnd * yDelta;
  1346.       cMaxWnd++;
  1347.  
  1348.    // Arrange if only one run is needed
  1349.  
  1350.       if (cWnd <= cMaxWnd)
  1351.         {x = (SHORT)rc. xLeft;
  1352.          y = (SHORT)rc. yTop - yEdge;
  1353.          for (i = cWnd - 1; i >= 0; i--)
  1354.            {aswp[i].x = x;
  1355.             aswp[i].y = y;
  1356.             aswp[i].cx = xEdge;
  1357.             aswp[i].cy = yEdge;
  1358.             aswp[i].fs = SWP_SIZE | SWP_MOVE;
  1359.             x += xDelta;
  1360.             y -= yDelta;
  1361.            }
  1362.         }
  1363.  
  1364.    // Arrange if multiple runs are necessary; start at bottom
  1365.    // right, iterate up to top left
  1366.  
  1367.       else
  1368.         {i = 0;
  1369.          while (i < cWnd)
  1370.            {x = ((SHORT)rc. xLeft) + (cMaxWnd-1) * xDelta;
  1371.             y = ((SHORT)rc. yTop) - yEdge - (cMaxWnd-1) * yDelta;
  1372.             for (j = 0; j < cMaxWnd; j++)
  1373.               {aswp[i].x = x;
  1374.                aswp[i].y = y;
  1375.                aswp[i].cx = xEdge;
  1376.                aswp[i].cy = yEdge;
  1377.                aswp[i].fs = SWP_SIZE | SWP_MOVE;
  1378.                x -= xDelta;
  1379.                y += yDelta;
  1380.                if (++i >= cWnd) break;
  1381.               }
  1382.             if (i >= cWnd) break;
  1383.             x = ((SHORT)rc. xLeft) + (cMaxWnd-1) * xDelta + xDelta/2;
  1384.             y = ((SHORT)rc. yTop) - yEdge - (cMaxWnd-1) * yDelta + yDelta/2;
  1385.             for (j = 0; j < cMaxWnd - 1; j++)
  1386.               {aswp[i].x = x;
  1387.                aswp[i].y = y;
  1388.                aswp[i].cx = xEdge;
  1389.                aswp[i].cy = yEdge;
  1390.                aswp[i].fs = SWP_SIZE | SWP_MOVE;
  1391.                x -= xDelta;
  1392.                y += yDelta;
  1393.                if (++i >= cWnd) break;
  1394.               }
  1395.            }
  1396.         }
  1397.      }
  1398.  
  1399.  
  1400. // Function: MDIDocumentArrangeTiled - Arrange all documents tiled
  1401. // ---------------------------------------------------------------
  1402.    VOID FAR MDIDocumentArrangeTiled (prc, cWnd, aswp)
  1403.  
  1404.       PRECTL prc;                      // -->area in which arrange will occur
  1405.       SHORT cWnd;                      // Count of windows
  1406.       PSWP aswp;                       // Array of window positions
  1407.  
  1408.    // Define function data
  1409.  
  1410.      {USHORT usRoot;
  1411.       SHORT cExtras;
  1412.       SHORT iChange;
  1413.       SHORT cDiff;
  1414.       SHORT x, y, cx, cy;
  1415.       SHORT iRow, iCol;
  1416.  
  1417.       SHORT cxBorder =
  1418.         (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CXSIZEBORDER);
  1419.  
  1420.       SHORT cyBorder =
  1421.         (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CYSIZEBORDER);
  1422.  
  1423.    // Get grid dimensions
  1424.  
  1425.       if ((USHORT) cWnd > (0xFE * 0xFE))
  1426.          usRoot = 0x00FF;
  1427.       else for (usRoot = 0; (usRoot * usRoot) < (USHORT) cWnd; usRoot++);
  1428.       cExtras = usRoot * usRoot - cWnd;
  1429.  
  1430.    // Find column where number of rows increases and find initial
  1431.    // difference of rows versus columns
  1432.  
  1433.       if (cExtras >= (SHORT) usRoot)
  1434.         {iChange = cExtras - (SHORT) usRoot;
  1435.          cDiff = 2;
  1436.         }
  1437.       else
  1438.         {iChange = cExtras;
  1439.          cDiff = 1;
  1440.         }
  1441.  
  1442.    // Assign x coordinates
  1443.  
  1444.       x = (SHORT)prc->xLeft;
  1445.       cx = 0;
  1446.       for (iCol = 0; iCol < (SHORT) usRoot; iCol++)
  1447.         {x += cx - cxBorder;
  1448.          cx = ((SHORT)prc->xLeft) + (((SHORT)(prc->xRight - prc->xLeft))
  1449.            * (iCol + 1)) / usRoot - x + cxBorder;
  1450.          for (iRow = 0; iRow < (SHORT) usRoot - cDiff; iRow++)
  1451.            {aswp[iRow * usRoot + iCol].x = x;
  1452.             aswp[iRow * usRoot + iCol].cx = cx;
  1453.             aswp[iRow * usRoot + iCol].fs = SWP_SIZE | SWP_MOVE;
  1454.            }
  1455.          if (iCol >= iChange)
  1456.            {aswp[iRow * usRoot + iCol - iChange].x = x;
  1457.             aswp[iRow * usRoot + iCol - iChange].cx = cx;
  1458.             aswp[iRow * usRoot + iCol - iChange].fs = SWP_SIZE | SWP_MOVE;
  1459.            }
  1460.         }
  1461.  
  1462.    // Assign y coordinates, for columns without extra row
  1463.  
  1464.       y = (SHORT)prc->yBottom;
  1465.       cy = 0;
  1466.       for (iRow = usRoot - cDiff - 1; iRow >= 0; iRow--)
  1467.         {y += cy - cyBorder;
  1468.          cy = ((SHORT)prc->yBottom) + (((SHORT)(prc->yTop - prc->yBottom))
  1469.            * (usRoot - cDiff - iRow)) / (usRoot - cDiff) - y + cyBorder;
  1470.          for (iCol = 0; iCol < iChange; iCol++)
  1471.            {aswp[iRow * usRoot + iCol].y = y;
  1472.             aswp[iRow * usRoot + iCol].cy = cy;
  1473.            }
  1474.         }
  1475.  
  1476.    // Assign y coordinates, for columns with extra row
  1477.    // do last row first (different offsets)
  1478.  
  1479.       y = (SHORT)prc->yBottom - cyBorder;
  1480.       cy = ((SHORT)(prc->yTop - prc->yBottom)) / (usRoot - cDiff + 1) + (2 * cyBorder);
  1481.       for (iCol = iChange; iCol < (SHORT) usRoot; iCol++)
  1482.         {aswp[usRoot * (usRoot - cDiff) + iCol - iChange].y = y;
  1483.          aswp[usRoot * (usRoot - cDiff) + iCol - iChange].cy = cy;
  1484.         }
  1485.       for (iRow = usRoot - cDiff - 1; iRow >= 0; iRow--)
  1486.         {y += cy - cyBorder;
  1487.          cy = ((SHORT)(prc->yBottom)) + (((SHORT)(prc->yTop - prc->yBottom))
  1488.            * (usRoot - cDiff - iRow + 1)) / (usRoot - cDiff + 1) - y + cyBorder;
  1489.          for (iCol = iChange; iCol < (SHORT) usRoot; iCol++)
  1490.            {aswp[iRow * usRoot + iCol].y = y;
  1491.             aswp[iRow * usRoot + iCol].cy = cy;
  1492.            }
  1493.         }
  1494.      }
  1495.  
  1496.  
  1497. // Function: MDIDocumentClone - Clone MDI Document
  1498. // -----------------------------------------------
  1499.    VOID FAR MDIDocumentClone (pinst)
  1500.  
  1501.       PINSTDOCUMENT pinst;             // -->document instance data
  1502.  
  1503.    // Define function data
  1504.  
  1505.      {PINSTDESKTOP pinstDesktop;       // -->desktop instance data
  1506.       HWND hwndDocument;               // New document window
  1507.       HWND hwndFrame;                  // New document frame
  1508.       HPOINTER hptrIcon;               // New document icon
  1509.       ULONG flFrameFlags;              // Frame flags
  1510.       USHORT usID;                     // Document id
  1511.  
  1512.    // Locate the desktop instance data
  1513.  
  1514.       pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (pinst->hwndDesktop,
  1515.         QWL_USER + sizeof (PVOID));
  1516.  
  1517.    // Copy creation flags from base document; set defaults if missing
  1518.  
  1519.       if (pinst->flCreateFlags != (ULONG) NULL)
  1520.         flFrameFlags = pinst->flCreateFlags;
  1521.       else flFrameFlags = FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER | FCF_MINMAX
  1522.         | FCF_SHELLPOSITION | FCF_NOBYTEALIGN;
  1523.  
  1524.    // Copy QWS_ID from base document
  1525.  
  1526.       usID = WinQueryWindowUShort (pinst->hwndDocument, QWS_ID);
  1527.  
  1528.    // Create new document
  1529.  
  1530.       hwndFrame = MDICreateDocument (pinst->pfnUser, pinstDesktop->hwndDesktop,
  1531.         flFrameFlags, pinst->szName, pinst->hmodResources, pinst->idResources,
  1532.         &hwndDocument, pinst->cbDocData, pinst->cbInstData, usID);
  1533.  
  1534.    // Copy QWL_USER from base document
  1535.  
  1536.       WinSetWindowULong (hwndDocument, QWL_USER, WinQueryWindowULong
  1537.         (pinst->hwndDocument, QWL_USER));
  1538.  
  1539.    // If applicable, copy icon from base document
  1540.  
  1541.       if ((hptrIcon = (HPOINTER) WinSendMsg (pinst->hwndFrame,
  1542.         WM_QUERYICON, (MPARAM) NULL, (MPARAM) NULL)) != NULL)
  1543.          WinSendMsg (hwndFrame, WM_SETICON, (MPARAM) hptrIcon, (MPARAM) NULL);
  1544.  
  1545.      }
  1546.  
  1547.  
  1548. // Function: MDIDocumentClose - Close MDI Document
  1549. // -----------------------------------------------
  1550.    MRESULT FAR MDIDocumentClose (pinst)
  1551.  
  1552.       PINSTDOCUMENT pinst;             // -->document instance data
  1553.  
  1554.    // Destroy document window if the user lets us
  1555.  
  1556.      {if ((BOOL) SHORT1FROMMR (WinSendMsg (pinst->hwndDocument, WM_CONTROL,
  1557.        MPFROM2SHORT (pinst->idDesktop, MDI_INHIBIT_CLOSE_INSTANCE),
  1558.        (MPARAM) pinst->pvInstData)) == FALSE)
  1559.          WinDestroyWindow (pinst->hwndFrame);
  1560.  
  1561.    // Indicate close handled
  1562.  
  1563.       return (MRESULT) NULL;
  1564.  
  1565.      }
  1566.  
  1567.  
  1568. // Function: MDIDocumentCommand - Handle MDI Document Command
  1569. // ----------------------------------------------------------
  1570.    MRESULT FAR MDIDocumentCommand (pinst, usCommand)
  1571.  
  1572.       PINSTDOCUMENT pinst;             // -->document instance data
  1573.       USHORT usCommand;                // WM_COMMAND code
  1574.  
  1575.    // Act upon command code
  1576.  
  1577.      {switch (usCommand)
  1578.  
  1579.    // Handle Desktop system menu command by passing it to the desktop frame
  1580.  
  1581.         {case CMD_DESKTOP_SIZE:
  1582.          case CMD_DESKTOP_MOVE:
  1583.          case CMD_DESKTOP_MINIMIZE:
  1584.          case CMD_DESKTOP_MAXIMIZE:
  1585.          case CMD_DESKTOP_CLOSE:
  1586.          case CMD_DESKTOP_NEXT:
  1587.          case CMD_DESKTOP_APPMENU:
  1588.          case CMD_DESKTOP_SYSMENU:
  1589.          case CMD_DESKTOP_RESTORE:
  1590.             WinSendMsg (pinst->hwndDesktop, WM_COMMAND,
  1591.               MPFROMSHORT (usCommand), MPFROM2SHORT (CMDSRC_ACCELERATOR, FALSE));
  1592.             break;
  1593.  
  1594.    // Handle Document system menu command by passing the system equivalent
  1595.    // to the document's frame. However, if the document is maximized,
  1596.    // the command is passed to the desktop for processing
  1597.  
  1598.          case CMD_DOCUMENT_SIZE:
  1599.          case CMD_DOCUMENT_MOVE:
  1600.          case CMD_DOCUMENT_MINIMIZE:
  1601.          case CMD_DOCUMENT_MAXIMIZE:
  1602.          case CMD_DOCUMENT_CLOSE:
  1603.          case CMD_DOCUMENT_NEXT:
  1604.          case CMD_DOCUMENT_APPMENU:
  1605.          case CMD_DOCUMENT_SYSMENU:
  1606.          case CMD_DOCUMENT_RESTORE:
  1607.             if (pinst->usState == SWP_MAXIMIZE)
  1608.                WinSendMsg (pinst->hwndDesktop, WM_COMMAND,
  1609.                  MPFROMSHORT (usCommand), MPFROM2SHORT (CMDSRC_ACCELERATOR, FALSE));
  1610.             else
  1611.                WinSendMsg (pinst->hwndFrame, WM_SYSCOMMAND,
  1612.                  MPFROMSHORT ((usCommand - CMD_DOCUMENT_BASE) | SC_SIZE),
  1613.                  MPFROM2SHORT (CMDSRC_ACCELERATOR, FALSE));
  1614.             break;
  1615.  
  1616.    // Terminate command processing
  1617.  
  1618.         }
  1619.  
  1620.    // Indicate command handled
  1621.  
  1622.       return (MRESULT) NULL;
  1623.  
  1624.      }
  1625.  
  1626.  
  1627. // Function: MDIDocumentCreate - Create MDI Document
  1628. // -------------------------------------------------
  1629.    MRESULT FAR MDIDocumentCreate (hwndDocument, pdoccp)
  1630.  
  1631.       HWND hwndDocument;               // Document window
  1632.       PDOCUMENTCREATEPARMS pdoccp;     // -->document creation parameters
  1633.  
  1634.    // Define function data
  1635.  
  1636.      {PINSTDOCUMENT pinst;             // -->instance data
  1637.       PINSTDOCUMENT pinstFirst;        // -->first document instance data
  1638.       PINSTDESKTOP pinstDesktop;       // -->desktop instance data
  1639.       MENUITEM mi;                     // Menu structure
  1640.       CHAR szClassName[MAX_STRING];    // Class name
  1641.       BOOL fIniDatFound;               // TRUE == OS2.INI data found
  1642.       USHORT cbBuf;                    // Length of OS2.INI data
  1643.       HWND hwndSibling;                // Sibling window handle
  1644.       SWP swp;                         // Sibling position
  1645.  
  1646.    // Acquire instance data and save in MDI document window
  1647.  
  1648.       pinst = AllocMemAlloc ((LONG) (sizeof (*pinst)));
  1649.       WinSetWindowULong (hwndDocument, QWL_USER + sizeof (PVOID), (ULONG) pinst);
  1650.  
  1651.    // Copy document creation parameters if available
  1652.  
  1653.       if (pdoccp != (PDOCUMENTCREATEPARMS) NULL)
  1654.         {pinst->cbDocData = pdoccp->cbDocData;
  1655.          pinst->cbInstData = pdoccp->cbInstData;
  1656.          pinst->pfnUser = pdoccp->pfnUser;
  1657.          pinst->flCreateFlags = pdoccp->flCreateFlags;
  1658.          pinst->hmodResources = pdoccp->hmodResources;
  1659.          pinst->idResources = pdoccp->idResources;
  1660.         }
  1661.  
  1662.    // Initialize inter-window relationships
  1663.  
  1664.       pinst->hwndDocument = hwndDocument;
  1665.       pinst->hwndFrame = WinQueryWindow (pinst->hwndDocument, QW_PARENT, FALSE);
  1666.       pinst->hwndDesktop = WinQueryWindow (pinst->hwndFrame, QW_PARENT, FALSE);
  1667.       pinst->hwndMenu = WinWindowFromID (pinst->hwndFrame, FID_MENU);
  1668.       pinst->hwndSysMenu = WinWindowFromID (pinst->hwndFrame, FID_SYSMENU);
  1669.       pinst->hwndTitleBar = WinWindowFromID (pinst->hwndFrame, FID_TITLEBAR);
  1670.       pinst->hwndMinMax = WinWindowFromID (pinst->hwndFrame, FID_MINMAX);
  1671.       pinst->hwndVScroll = WinWindowFromID (pinst->hwndFrame, FID_VERTSCROLL);
  1672.       pinst->hwndHScroll = WinWindowFromID (pinst->hwndFrame, FID_HORZSCROLL);
  1673.       pinst->idDesktop = WinQueryWindowUShort (WinQueryWindow (pinst->hwndDesktop, QW_PARENT, FALSE), QWS_ID);
  1674.  
  1675.    // Verify inter-window relationships
  1676.  
  1677.       WinQueryClassName (pinst->hwndDesktop, sizeof (szClassName), szClassName);
  1678.       while (stricmp (szClassName, MDI_DESKTOPCLASS) != 0)
  1679.          TellUser (ERROR_DOCUMENT_PARENT_INVALID, MDI_MODNAME, MB_ABORTRETRYIGNORE | MB_ICONHAND);
  1680.  
  1681.       while (pinst->hwndSysMenu == (HWND) NULL)
  1682.          TellUser (ERROR_DOCUMENT_NO_SYSMENU, MDI_MODNAME, MB_ABORTRETRYIGNORE | MB_ICONHAND);
  1683.  
  1684.    // Find the desktop instance data
  1685.  
  1686.       pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (pinst->hwndDesktop, QWL_USER + sizeof (PVOID));
  1687.  
  1688.    // Load accelerator table
  1689.  
  1690.       pinst->haccel = MDILoadAccelTable (ACCEL_DOCUMENT);
  1691.       WinSetAccelTable ((HAB) NULL, pinst->haccel, pinst->hwndFrame);
  1692.  
  1693.    // Make sure that the menu bar (if any) is not displayed
  1694.  
  1695.       if (pinst->hwndMenu != (HWND) NULL)
  1696.         {WinSetParent (pinst->hwndMenu, HWND_OBJECT, FALSE);
  1697.          WinSetOwner (pinst->hwndMenu, pinst->hwndDesktop);
  1698.          WinSendMsg (pinst->hwndFrame, WM_UPDATEFRAME, MPFROMSHORT (FCF_MENU), (MPARAM) NULL);
  1699.         }
  1700.  
  1701.    // Alter the appearance of the child system menu to the MDI standard
  1702.  
  1703.       WinSendMsg (pinst->hwndSysMenu, MM_QUERYITEM, MPFROM2SHORT (SC_SYSMENU, FALSE), (MPARAM) &mi);
  1704.       WinSendMsg (pinst->hwndSysMenu, MM_REMOVEITEM, MPFROM2SHORT (SC_SYSMENU, FALSE), (MPARAM) NULL);
  1705.       mi.hItem = (ULONG) WinGetSysBitmap (HWND_DESKTOP, SBMP_CHILDSYSMENU);
  1706.       mi.hwndSubMenu = MDILoadMenu (pinst->hwndSysMenu, MENU_CHILD_SYSMENU);
  1707.       WinSendMsg (pinst->hwndSysMenu, MM_INSERTITEM, (MPARAM) &mi, (MPARAM) NULL);
  1708.  
  1709.    // Determine initial title
  1710.  
  1711.       WinQueryWindowText (pinst->hwndFrame, sizeof (pinst->szName), pinst->szName);
  1712.  
  1713.    // Rebuild the titles of all document windows inserting the current title
  1714.  
  1715.       pinstFirst = MDIDocumentTitlesRebuild (pinst, INSERT_TITLE);
  1716.  
  1717.    // If applicable, allocate user document and instance data
  1718.  
  1719.       if (pdoccp && (pdoccp->cbInstData > 0))
  1720.          pinst->pvInstData = AllocMemAlloc ((LONG) (pdoccp->cbInstData));
  1721.       if (pdoccp && (pdoccp->cbDocData > 0))
  1722.         {if (pinst == pinstFirst)
  1723.             pinst->pvDocData = AllocMemAlloc ((LONG) (pdoccp->cbDocData));
  1724.          else if (pinstFirst != NULL)
  1725.             pinst->pvDocData = pinstFirst->pvDocData;
  1726.         }
  1727.  
  1728.    // Recall window information from OS2.INI file, if available
  1729.  
  1730.       cbBuf = sizeof (pinst->swp);
  1731.       pinst->swp.fs = 0;
  1732.       if (! pinstDesktop->fDisableDocumentPosition)
  1733.         fIniDatFound = WinQueryProfileData ((HAB) NULL, MDI_DOCUMENTCLASS,
  1734.           pinst->szName, &(pinst->swp), &cbBuf);
  1735.       else fIniDatFound = FALSE;
  1736.  
  1737.    // If no prior position was stored, or if the window was maximized,
  1738.    // minimized or hidden, find a default position inside the desktop
  1739.    // window. If there is a sibling that is a frame, and is itself not
  1740.    // maximized, minimized or hidden, offset the new window from it
  1741.  
  1742.       if (! fIniDatFound || (pinst->swp.fs & (SWP_MINIMIZE | SWP_MAXIMIZE /* | SWP_HIDE */)))
  1743.         {WinQueryWindowPos (pinst->hwndDesktop, &swp);
  1744.          pinst->swp.cx = swp.cx / 2;
  1745.          pinst->swp.cy = swp.cy / 2;
  1746.          pinst->swp.x = swp.x + ((SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CXVSCROLL) / 2);
  1747.          pinst->swp.y = swp.y + pinst->swp.cy - ((SHORT) WinQuerySysValue
  1748.            (HWND_DESKTOP, SV_CYTITLEBAR) / 2);
  1749.          if ((hwndSibling = WinQueryWindow (pinst->hwndFrame, QW_NEXT, FALSE)) != (HWND) NULL)
  1750.            {WinQueryClassName (hwndSibling, sizeof (szClassName), szClassName);
  1751.             if (strcmpi (szClassName, "#1") == 0)
  1752.               {WinQueryWindowPos (hwndSibling, &swp);
  1753.                if (! (swp.fs & (SWP_MINIMIZE | SWP_MAXIMIZE /* | SWP_HIDE */)))
  1754.                  {pinst->swp.x = swp.x + ((SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CXVSCROLL) / 2);
  1755.                   pinst->swp.y = swp.y - (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CYTITLEBAR);
  1756.                   pinst->swp.cx = swp.cx;
  1757.                   pinst->swp.cy = swp.cy;
  1758.                  }
  1759.               }
  1760.            }
  1761.          pinst->swp.fs &= ~SWP_HIDE;
  1762.         }
  1763.  
  1764.    // Re-tile or re-cascade all windows if necessary or simply
  1765.    // display and position document window
  1766.  
  1767.       if (pinstDesktop->fTileAlways)
  1768.          MDIDocumentArrange (pinst->hwndDesktop, AWP_TILED);
  1769.       else if (pinstDesktop->fCascadeAlways)
  1770.          MDIDocumentArrange (pinst->hwndDesktop, AWP_CASCADED);
  1771.       else
  1772.         {pinst->swp.fs |= SWP_MOVE | SWP_SIZE | SWP_SHOW | SWP_ZORDER;
  1773.          pinst->swp.hwndInsertBehind = HWND_TOP;
  1774.          pinst->swp.hwnd = pinst->hwndFrame;
  1775.          WinSetMultWindowPos ((HAB) NULL, &(pinst->swp), 1);
  1776.         }
  1777.  
  1778.    // Force the current window to be activated
  1779.  
  1780.       MDIDocumentActivate (pinst, TRUE);
  1781.  
  1782.    // Indicate create handled
  1783.  
  1784.       return (MRESULT) NULL;
  1785.  
  1786.      }
  1787.  
  1788.  
  1789. // Function: MDIDocumentDestroy - Destroy MDI Document
  1790. // ---------------------------------------------------
  1791.    MRESULT FAR MDIDocumentDestroy (pinst)
  1792.  
  1793.       PINSTDOCUMENT pinst;             // -->document instance data
  1794.  
  1795.    // Define function data
  1796.  
  1797.      {PINSTDESKTOP pinstDesktop;       // -->desktop instance data
  1798.       PINSTDOCUMENT pinstFirst;        // -->first document instance data
  1799.       PINSTDOCUMENT pinstDocument;     // -->next active document instance data
  1800.       HWND hwndFrame;                  // Next active document frame
  1801.       MENUITEM mi;                     // Menu item
  1802.  
  1803.    // Find the desktop instance data
  1804.  
  1805.       pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (pinst->hwndDesktop, QWL_USER + sizeof (PVOID));
  1806.  
  1807.    // Save window position onto OS2.INI file
  1808.  
  1809.       pinst->swp.fs &= ~SWP_HIDE;
  1810.       if (! pinstDesktop->fDisableDocumentPosition)
  1811.         WinWriteProfileData ((HAB) NULL, MDI_DOCUMENTCLASS, pinst->szName,
  1812.           &(pinst->swp), sizeof (pinst->swp));
  1813.  
  1814.    // Rebuild the titles of all document windows removing the current title
  1815.  
  1816.       pinstFirst = MDIDocumentTitlesRebuild (pinst, REMOVE_TITLE);
  1817.  
  1818.    // Free accelerator table
  1819.  
  1820.       WinDestroyAccelTable (pinst->haccel);
  1821.  
  1822.    // Re-tile or re-cascade all remaining windows if necessary
  1823.  
  1824.       if (pinstDesktop->fTileAlways)
  1825.          MDIDocumentArrange (pinst->hwndDesktop, AWP_TILED);
  1826.       else if (pinstDesktop->fCascadeAlways)
  1827.          MDIDocumentArrange (pinst->hwndDesktop, AWP_CASCADED);
  1828.  
  1829.    // If there is a next entry in the window submenu, activate it
  1830.  
  1831.       if ((mi.id = SHORT1FROMMR (WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_ITEMIDFROMPOSITION,
  1832.        MPFROMSHORT (CMD_WINDOW_MAX - CMD_WINDOW - pinstDesktop->fDisableNewDocument), (MPARAM) NULL))) > 0)
  1833.         {hwndFrame = MDIDocumentFrameFromID (pinstDesktop->hwndDesktop, mi.id);
  1834.          WinSetWindowPos (hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_ACTIVATE | SWP_ZORDER);
  1835.          pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (WinWindowFromID (hwndFrame, FID_CLIENT), QWL_USER + sizeof (PVOID));
  1836.          if (pinstDocument)
  1837.             MDIDocumentActivate (pinstDocument, TRUE);
  1838.         }
  1839.  
  1840.    // Tell user instance and maybe document will be destroyed
  1841.  
  1842.       WinSendMsg (pinst->hwndDocument, WM_CONTROL,
  1843.         MPFROM2SHORT (pinst->idDesktop, MDI_NOTIFY_DESTROY_INSTANCE),
  1844.         (MPARAM) pinst->pvInstData);
  1845.       if (pinstFirst == (PINSTDOCUMENT) NULL)
  1846.          WinSendMsg (pinst->hwndDocument, WM_CONTROL,
  1847.            MPFROM2SHORT (pinst->idDesktop, MDI_NOTIFY_DESTROY_DOCUMENT), (MPARAM) pinst->pvDocData);
  1848.  
  1849.    // If applicable, free the user document and instance data
  1850.  
  1851.       if (pinst->pvInstData)
  1852.          AllocMemFree (pinst->pvInstData);
  1853.       if (pinst->pvDocData && (pinstFirst == (PINSTDOCUMENT) NULL))
  1854.          AllocMemFree (pinst->pvDocData);
  1855.  
  1856.    // Free instance data
  1857.  
  1858.       AllocMemFree (pinst);
  1859.  
  1860.    // Indicate destroy handled
  1861.  
  1862.       return (MRESULT) NULL;
  1863.  
  1864.      }
  1865.  
  1866.  
  1867. // Function: MDIDocumentFrameFromID - Return Document Frame From Its Internal ID
  1868. // -----------------------------------------------------------------------------
  1869.    HWND FAR MDIDocumentFrameFromID (hwndDesktop, idInternal)
  1870.  
  1871.       HWND hwndDesktop;                // Desktop window
  1872.       USHORT idInternal;               // Requested internal id
  1873.  
  1874.    // Define function data
  1875.  
  1876.      {PINSTDOCUMENT pinstDocument;     // -->document instance data
  1877.       HWND hwndFrame;                  // Document frame
  1878.  
  1879.    // Scan for a match on internal id
  1880.  
  1881.       for (hwndFrame = WinQueryWindow (hwndDesktop, QW_TOP, FALSE);
  1882.        hwndFrame; hwndFrame = WinQueryWindow (hwndFrame, QW_NEXT, FALSE))
  1883.         {if ((WinQueryWindow (hwndFrame, QW_OWNER, FALSE) == (HWND) NULL)
  1884.           && (WinQueryWindowUShort (hwndFrame, QWS_ID) != 0))
  1885.            {pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong
  1886.               (WinWindowFromID (hwndFrame, FID_CLIENT), QWL_USER + sizeof (PVOID));
  1887.             if (pinstDocument->idInternal == idInternal) break;
  1888.            }
  1889.         }
  1890.  
  1891.    // Return to caller
  1892.  
  1893.       return hwndFrame;
  1894.  
  1895.      }
  1896.  
  1897.  
  1898. // Function: MDIDocumentHide - Hide MDI Document
  1899. // ---------------------------------------------
  1900.    VOID FAR MDIDocumentHide (pinst)
  1901.  
  1902.       PINSTDOCUMENT pinst;             // -->document instance data
  1903.  
  1904.    // Define function data
  1905.  
  1906.      {PINSTDESKTOP pinstDesktop;       // -->desktop instance data
  1907.       PINSTDOCUMENT pinstDocument;     // -->next active document instance data
  1908.       HWND hwndFrame;                  // Next active document frame
  1909.       MENUITEM mi;                     // Menu item
  1910.       SHORT iItem;                     // Item index
  1911.  
  1912.    // Locate the desktop instance data
  1913.  
  1914.       pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (pinst->hwndDesktop, QWL_USER + sizeof (PVOID));
  1915.  
  1916.    // Hide document
  1917.  
  1918.       WinShowWindow (pinst->hwndFrame, FALSE);
  1919.       pinst->usState |= SWP_HIDE;
  1920.  
  1921.    // Hide document entry from window submenu
  1922.  
  1923.       MDIDocumentTitlesRebuild (pinst, HIDE_TITLE);
  1924.  
  1925.    // Delete any remaining menu delta entries
  1926.  
  1927.       for (iItem = 0; iItem < (SHORT) pinstDesktop->cidDelta; iItem++)
  1928.          WinSendMsg (pinstDesktop->hwndMenu, MM_REMOVEITEM, MPFROM2SHORT (pinstDesktop->idDelta[iItem], TRUE), (MPARAM) NULL);
  1929.       pinstDesktop->cidDelta = 0;
  1930.  
  1931.    // If there is a next entry in the window submenu, activate it
  1932.  
  1933.       if ((mi.id = SHORT1FROMMR (WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_ITEMIDFROMPOSITION,
  1934.        MPFROMSHORT (CMD_WINDOW_MAX - CMD_WINDOW - pinstDesktop->fDisableNewDocument), (MPARAM) NULL))) > 0)
  1935.         {hwndFrame = MDIDocumentFrameFromID (pinstDesktop->hwndDesktop, mi.id);
  1936.          WinSetWindowPos (hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_ACTIVATE | SWP_ZORDER);
  1937.          pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (WinWindowFromID (hwndFrame, FID_CLIENT), QWL_USER + sizeof (PVOID));
  1938.          if (pinstDocument)
  1939.             MDIDocumentActivate (pinstDocument, TRUE);
  1940.         }
  1941.  
  1942.    // Otherwise, remove any maximized child system menu and reset the desktop
  1943.    // In addition, we disable the HIDE and NEW window menu options
  1944.  
  1945.       else
  1946.         {WinSendMsg (pinstDesktop->hwndMenu, MM_REMOVEITEM,
  1947.            MPFROM2SHORT (MENU_MAXCHILD_SYSMENU, FALSE), (MPARAM) NULL);
  1948.          WinSetWindowText (pinstDesktop->hwndFrame, (pinstDesktop->szTitleText[0])? pinstDesktop->szTitleText : pinstDesktop->szName);
  1949.          pinstDesktop->hwndDocument = (HWND) NULL;
  1950.          WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_SETITEMATTR,
  1951.            MPFROM2SHORT (CMD_HIDE, FALSE), MPFROM2SHORT (MIA_DISABLED, MIA_DISABLED));
  1952.          WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_SETITEMATTR,
  1953.            MPFROM2SHORT (CMD_NEW_DOCUMENT, FALSE), MPFROM2SHORT (MIA_DISABLED, MIA_DISABLED));
  1954.         }
  1955.  
  1956.    // Enable the UNHIDE window submenu option
  1957.  
  1958.       WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_SETITEMATTR,
  1959.         MPFROM2SHORT (CMD_UNHIDE, FALSE), MPFROM2SHORT (MIA_DISABLED, FALSE));
  1960.  
  1961.    // Re-tile or re-cascade if necessary
  1962.  
  1963.       if (pinstDesktop->fTileAlways)
  1964.          MDIDocumentArrange (pinstDesktop->hwndDesktop, AWP_TILED);
  1965.       else if (pinstDesktop->fCascadeAlways)
  1966.          MDIDocumentArrange (pinstDesktop->hwndDesktop, AWP_CASCADED);
  1967.  
  1968.      }
  1969.  
  1970.  
  1971. // Function: MDIDocumentMinMax - Minimize/Maximize MDI Document
  1972. // ------------------------------------------------------------
  1973.    MRESULT FAR MDIDocumentMinMax (pinst, pswp)
  1974.  
  1975.       PINSTDOCUMENT pinst;             // -->document instance data
  1976.       PSWP pswp;                       // -->document position information
  1977.  
  1978.    // Define function data
  1979.  
  1980.      {PINSTDESKTOP pinstDesktop;       // -->desktop instance data
  1981.       CHAR szName[MAX_STRING];         // Desktop name
  1982.       MENUITEM mi;                     // Menu item
  1983.  
  1984.    // Update document state flags
  1985.  
  1986.       pinst->usState = pswp->fs & (SWP_MAXIMIZE | SWP_MINIMIZE);
  1987.  
  1988.    // Show/hide all frame controls
  1989.  
  1990.       MDIDocumentShowFrameCtls (pinst, (pinst->usState != SWP_MAXIMIZE), TRUE, FALSE);
  1991.  
  1992.    // Locate the desktop instance data
  1993.  
  1994.       pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (pinst->hwndDesktop, QWL_USER + sizeof (PVOID));
  1995.  
  1996.    // For maximized documents, insert the maximized child system
  1997.    // menu to the desktop if it does not already exist, and update
  1998.    // the desktop title
  1999.  
  2000.       if (pinst->usState == SWP_MAXIMIZE)
  2001.         {if (! (BOOL) SHORT1FROMMR (WinSendMsg (pinstDesktop->hwndMenu, MM_QUERYITEM,
  2002.            MPFROM2SHORT (MENU_MAXCHILD_SYSMENU, FALSE), (MPARAM) &mi)))
  2003.            {WinSendMsg (pinstDesktop->hwndMenu, MM_INSERTITEM,
  2004.               (MPARAM) &(pinstDesktop->miSysMenu), (MPARAM) NULL);
  2005.             pinstDesktop->miWindow.iPosition++;
  2006.            }
  2007.          if ((pinst->iName == 0) || (pinst->szTitleText[0]))
  2008.            {sprintf (szName, "%s - %s", (pinstDesktop->szTitleText[0])? pinstDesktop->szTitleText : pinstDesktop->szName,
  2009.              (pinst->szTitleText[0])? pinst->szTitleText : pinst->szName);
  2010.            }
  2011.          else
  2012.            {sprintf (szName, "%s - %s:%d", (pinstDesktop->szTitleText[0])? pinstDesktop->szTitleText : pinstDesktop->szName,
  2013.              (pinst->szTitleText[0])? pinst->szTitleText : pinst->szName, pinst->iName);
  2014.            }
  2015.          WinSetWindowText (pinstDesktop->hwndFrame, szName);
  2016.         }
  2017.  
  2018.    // Otherwise, remove the maximized child system menu from the desktop
  2019.    // and reset the desktop title
  2020.  
  2021.       else
  2022.         {if ((BOOL) SHORT1FROMMR (WinSendMsg (pinstDesktop->hwndMenu, MM_QUERYITEM,
  2023.            MPFROM2SHORT (MENU_MAXCHILD_SYSMENU, FALSE), (MPARAM) &mi)))
  2024.            {WinSendMsg (pinstDesktop->hwndMenu, MM_REMOVEITEM,
  2025.               MPFROM2SHORT (MENU_MAXCHILD_SYSMENU, FALSE), (MPARAM) NULL);
  2026.             pinstDesktop->miWindow.iPosition--;
  2027.            }
  2028.          WinSetWindowText (pinstDesktop->hwndFrame, (pinstDesktop->szTitleText[0])? pinstDesktop->szTitleText : pinstDesktop->szName);
  2029.         }
  2030.  
  2031.    // Indicate min/max handled
  2032.  
  2033.       return (MRESULT) NULL;
  2034.  
  2035.      }
  2036.  
  2037.  
  2038. // Function: MDIDocumentMoreDlgProc - MDI Document "More Documents" dialog procedure
  2039. // ---------------------------------------------------------------------------------
  2040.    MRESULT EXPENTRY MDIDocumentMoreDlgProc (hwndMore, msg, mp1, mp2)
  2041.  
  2042.       HWND hwndMore;                   // More dialog box
  2043.       USHORT msg;                      // PM message
  2044.       MPARAM mp1;                      // Message parameter 1
  2045.       MPARAM mp2;                      // Message parameter 2
  2046.  
  2047.    // Define function data
  2048.  
  2049.      {HWND hwndDocument;               // Document window
  2050.       HWND hwndFrame;                  // Its frame
  2051.       HWND hwndActive;                 // Document to be made active
  2052.       CHAR szClassName[MAX_STRING];    // Class/Title name
  2053.       CHAR szName[MAX_STRING];         // Window name
  2054.       PINSTDESKTOP pinstDesktop;       // -->desktop instance data
  2055.       PINSTDOCUMENT pinstDocument;     // -->document instance data
  2056.       SHORT cmd;                       // Which window to retrieve
  2057.       SHORT i;                         // Temporary counter
  2058.  
  2059.    // Analyze and process message
  2060.  
  2061.       switch (msg)
  2062.  
  2063.       // Initially, load list box with all window titles
  2064.  
  2065.         {case WM_INITDLG:
  2066.             pinstDesktop = (PINSTDESKTOP) mp2;
  2067.             WinSetWindowULong (hwndMore, QWL_USER, (ULONG) pinstDesktop);
  2068.  
  2069.          // Scan each document window in the desktop
  2070.  
  2071.             cmd = QW_TOP;
  2072.             hwndFrame = pinstDesktop->hwndDesktop;
  2073.             while ((hwndFrame = WinQueryWindow (hwndFrame, cmd, FALSE)) != (HWND) NULL)
  2074.               {cmd = QW_NEXT;
  2075.                WinQueryClassName (hwndFrame, sizeof (szClassName), szClassName);
  2076.                if (strcmpi (szClassName, "#1") != 0) continue;
  2077.                hwndDocument = WinWindowFromID (hwndFrame, FID_CLIENT);
  2078.                WinQueryClassName (hwndDocument, sizeof (szClassName), szClassName);
  2079.                if (strcmpi (szClassName, MDI_DOCUMENTCLASS) != 0) continue;
  2080.                pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (hwndDocument, QWL_USER + sizeof (PVOID));
  2081.  
  2082.             // Add the document title to the list box
  2083.  
  2084.                if (! (pinstDocument->usState & SWP_HIDE))
  2085.                  {if ((pinstDocument->iName == 0) || (pinstDocument->szTitleText[0]))
  2086.                      sprintf (szClassName, "%s", (pinstDocument->szTitleText[0])? pinstDocument->szTitleText : pinstDocument->szName);
  2087.                   else sprintf (szClassName, "%s:%d", pinstDocument->szName, pinstDocument->iName);
  2088.                   WinSendMsg (WinWindowFromID (hwndMore, DIALOG_MORE_LISTBOX),
  2089.                     LM_INSERTITEM, MPFROMSHORT (LIT_SORTASCENDING), (MPARAM) szClassName);
  2090.                  }
  2091.  
  2092.             // Loop until all documents processed
  2093.  
  2094.               }
  2095.  
  2096.          // Indicate initialize handled
  2097.  
  2098.             return (MRESULT) NULL;
  2099.  
  2100.       // When OK hit, make selected entry active
  2101.  
  2102.          case WM_COMMAND:
  2103.             hwndActive = (HWND) NULL;
  2104.             if (SHORT1FROMMR (mp1) == DID_OK)
  2105.               {i = SHORT1FROMMR (WinSendDlgItemMsg (hwndMore, DIALOG_MORE_LISTBOX,
  2106.                  LM_QUERYSELECTION, MPFROMSHORT (LIT_FIRST), (MPARAM) NULL));
  2107.                WinSendDlgItemMsg (hwndMore, DIALOG_MORE_LISTBOX,
  2108.                  LM_QUERYITEMTEXT, MPFROM2SHORT (i, sizeof (szName)), (MPARAM) szName);
  2109.                pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (hwndMore, QWL_USER);
  2110.  
  2111.             // Scan each document window in the desktop
  2112.  
  2113.                cmd = QW_TOP;
  2114.                hwndFrame = pinstDesktop->hwndDesktop;
  2115.                while ((hwndFrame = WinQueryWindow (hwndFrame, cmd, FALSE)) != (HWND) NULL)
  2116.                  {cmd = QW_NEXT;
  2117.                   WinQueryClassName (hwndFrame, sizeof (szClassName), szClassName);
  2118.                   if (strcmpi (szClassName, "#1") != 0) continue;
  2119.                   hwndDocument = WinWindowFromID (hwndFrame, FID_CLIENT);
  2120.                   WinQueryClassName (hwndDocument, sizeof (szClassName), szClassName);
  2121.                   if (strcmpi (szClassName, MDI_DOCUMENTCLASS) != 0) continue;
  2122.                   pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (hwndDocument, QWL_USER + sizeof (PVOID));
  2123.  
  2124.                // Determine the document title
  2125.  
  2126.                   if ((pinstDocument->iName == 0) || (pinstDocument->szTitleText[0]))
  2127.                      sprintf (szClassName, "%s", (pinstDocument->szTitleText[0])? pinstDocument->szTitleText : pinstDocument->szName);
  2128.                   else sprintf (szClassName, "%s:%d", pinstDocument->szName, pinstDocument->iName);
  2129.  
  2130.                // If the selected document title matches, make it active
  2131.  
  2132.                   if (strcmp (szName, szClassName) == 0)
  2133.                      hwndActive = pinstDocument->hwndFrame;
  2134.  
  2135.                // Loop until all documents processed
  2136.  
  2137.                  }
  2138.  
  2139.               }
  2140.  
  2141.          // Indicate dialog box terminated
  2142.  
  2143.             WinDismissDlg (hwndMore, SHORT1FROMMP (mp1));
  2144.             if (hwndActive != (HWND) NULL)
  2145.                WinSetWindowPos (hwndActive, HWND_TOP, 0, 0, 0, 0, SWP_ACTIVATE | SWP_ZORDER);
  2146.             return (MRESULT) NULL;
  2147.  
  2148.         }
  2149.  
  2150.    // Return to PM
  2151.  
  2152.       return WinDefDlgProc (hwndMore, msg, mp1, mp2);
  2153.  
  2154.      }
  2155.  
  2156.  
  2157. // Function: MDIDocumentPaint - Paint MDI Document
  2158. // -----------------------------------------------
  2159.    MRESULT FAR MDIDocumentPaint (pinst)
  2160.  
  2161.       PINSTDOCUMENT pinst;             // -->document instance data
  2162.  
  2163.    // Define function data
  2164.  
  2165.      {HPS hps;                         // Presentation space
  2166.       RECTL rcl;                       // Update rectangle
  2167.  
  2168.    // Paint a SYSCLR_WINDOW background
  2169.  
  2170.       hps = WinBeginPaint (pinst->hwndDocument, (HPS) NULL, &rcl);
  2171.       WinFillRect (hps, &rcl, SYSCLR_APPWORKSPACE);
  2172.       WinEndPaint (hps);
  2173.  
  2174.    // Indicate paint handled
  2175.  
  2176.       return (MRESULT) NULL;
  2177.  
  2178.      }
  2179.  
  2180.  
  2181. // Function: MDIDocumentShowFrameCtls - Show or Hide Documernt Frame Controls
  2182. // --------------------------------------------------------------------------
  2183.    VOID FAR MDIDocumentShowFrameCtls (pinst, fShow, fTitle, fScroll)
  2184.  
  2185.       PINSTDOCUMENT pinst;             // -->document instance data
  2186.       BOOL fShow;                      // TRUE == show frame controls
  2187.       BOOL fTitle;                     // TRUE == handle title bar
  2188.       BOOL fScroll;                    // TRUE == handle scroll bars
  2189.  
  2190.    // Define function data
  2191.  
  2192.      {ULONG flStyle = 0;               // Frame style
  2193.       PINSTDESKTOP pinstDesktop;       // -->desktop instance data
  2194.  
  2195.    // Locate the desktop instance data
  2196.  
  2197.       pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (pinst->hwndDesktop, QWL_USER + sizeof (PVOID));
  2198.  
  2199.    // Show/hide all frame controls
  2200.  
  2201.       WinShowWindow (pinst->hwndSysMenu, FALSE);
  2202.       WinSetParent (pinst->hwndSysMenu, (fShow)? pinst->hwndFrame : HWND_OBJECT, FALSE);
  2203.       if (pinst->hwndSysMenu != (HWND) NULL) flStyle |= FCF_SYSMENU;
  2204.  
  2205.       WinShowWindow (pinst->hwndMinMax, FALSE);
  2206.       WinSetParent (pinst->hwndMinMax, (fShow)? pinst->hwndFrame : HWND_OBJECT, FALSE);
  2207.       if (pinst->hwndMinMax != (HWND) NULL) flStyle |= FCF_MINMAX;
  2208.  
  2209.       WinShowWindow (pinst->hwndTitleBar, FALSE);
  2210.       if (fTitle)
  2211.          WinSetParent (pinst->hwndTitleBar, (fShow)? pinst->hwndFrame : HWND_OBJECT, FALSE);
  2212.       else WinSetParent (pinst->hwndTitleBar, pinst->hwndFrame, FALSE);
  2213.       if (pinst->hwndTitleBar != (HWND) NULL) flStyle |= FCF_TITLEBAR;
  2214.  
  2215.    // Handle scroll bars if necessary
  2216.  
  2217.       if (fScroll && (! pinstDesktop->fKeepScrollBars))
  2218.         {WinShowWindow (pinst->hwndVScroll, FALSE);
  2219.          WinSetParent (pinst->hwndVScroll, (fShow)? pinst->hwndFrame : HWND_OBJECT, FALSE);
  2220.          if (pinst->hwndVScroll != (HWND) NULL) flStyle |= FCF_VERTSCROLL;
  2221.          WinShowWindow (pinst->hwndHScroll, FALSE);
  2222.          WinSetParent (pinst->hwndHScroll, (fShow)? pinst->hwndFrame : HWND_OBJECT, FALSE);
  2223.          if (pinst->hwndHScroll != (HWND) NULL) flStyle |= FCF_HORZSCROLL;
  2224.         }
  2225.  
  2226.    // Update frame window
  2227.  
  2228.       WinSendMsg (pinst->hwndFrame, WM_UPDATEFRAME, (MPARAM) flStyle, (MPARAM) NULL);
  2229.  
  2230.    // Return
  2231.  
  2232.      }
  2233.  
  2234.  
  2235. // Function: MDIDocumentTitlesRebuild - Rebuild the titles of all Documents
  2236. // ------------------------------------------------------------------------
  2237.    PINSTDOCUMENT FAR MDIDocumentTitlesRebuild (pinst, usCommand)
  2238.  
  2239.       PINSTDOCUMENT pinst;             // -->document instance data
  2240.       USHORT usCommand;                // INSERT_TITLE or REMOVE_TITLE or UPDATE_TITLE or HIDE_TITLE
  2241.  
  2242.    // Define function data
  2243.  
  2244.      {HWND hwndDocument;               // Document window
  2245.       HWND hwndFrame;                  // Its frame
  2246.       CHAR szClassName[MAX_STRING];    // Class/Title name
  2247.       PINSTDOCUMENT pinstFirst;        // -->first document instance data
  2248.       PINSTDOCUMENT pinstDocument;     // -->document instance data
  2249.       PINSTDESKTOP pinstDesktop;       // -->desktop instance data
  2250.       MENUITEM mi;                     // Menu item
  2251.       SHORT cmd;                       // Which window to retrieve
  2252.       SHORT nSameName;                 // Number of documents with the same name
  2253.       SHORT nDocuments;                // Number of documents
  2254.       SHORT iDocument;                 // Document index
  2255.       SHORT cVisDocs;                  // Count of visible documents
  2256.       SHORT iItem;                     // Item index
  2257.       BOOL fMore;                      // TRUE == "more..." present
  2258.       BOOL fListed;                    // TRUE == at least one document listed
  2259.  
  2260.    // Find the desktop instance data
  2261.  
  2262.       pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (pinst->hwndDesktop, QWL_USER + sizeof (PVOID));
  2263.  
  2264.    // Count the number of documents that already exist with the same name
  2265.    // as the current document and the total number of documents
  2266.  
  2267.       cmd = QW_TOP;
  2268.       hwndFrame = pinst->hwndDesktop;
  2269.       nDocuments = nSameName = 0;
  2270.       while ((hwndFrame = WinQueryWindow (hwndFrame, cmd, FALSE)) != (HWND) NULL)
  2271.         {cmd = QW_NEXT;
  2272.          WinQueryClassName (hwndFrame, sizeof (szClassName), szClassName);
  2273.          if (strcmpi (szClassName, "#1") != 0) continue;
  2274.          hwndDocument = WinWindowFromID (hwndFrame, FID_CLIENT);
  2275.          WinQueryClassName (hwndDocument, sizeof (szClassName), szClassName);
  2276.          if (strcmpi (szClassName, MDI_DOCUMENTCLASS) != 0) continue;
  2277.          pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (hwndDocument, QWL_USER + sizeof (PVOID));
  2278.          nDocuments++;
  2279.          if (pinst == pinstDocument) continue;
  2280.          if (strcmp (pinst->szName, pinstDocument->szName) == 0)
  2281.             nSameName++;
  2282.         }
  2283.       if (usCommand == REMOVE_TITLE) nDocuments--;
  2284.  
  2285.    // If there is exactly one document, insert the window submenu
  2286.    // if it has not already been created
  2287.  
  2288.       if ((nDocuments == 1) && (usCommand == INSERT_TITLE))
  2289.         {if (! pinstDesktop->fKeepWindowsMenu)
  2290.            WinSendMsg (pinstDesktop->hwndMenu, MM_INSERTITEM, (MPARAM) &(pinstDesktop->miWindow), (MPARAM) pinstDesktop->pszWindow);
  2291.         }
  2292.  
  2293.    // If there are no documents left, remove the window submenu and any
  2294.    // remaining menu delta. If we cannot remove the windows menu item,
  2295.    // we disable relevant entries
  2296.  
  2297.       else if ((nDocuments == 0) && (usCommand == REMOVE_TITLE))
  2298.         {if (! pinstDesktop->fKeepWindowsMenu)
  2299.             WinSendMsg (pinstDesktop->hwndMenu, MM_REMOVEITEM, MPFROM2SHORT (MENU_WINDOW, FALSE), (MPARAM) NULL);
  2300.          for (iItem = 0; iItem < (SHORT) pinstDesktop->cidDelta; iItem++)
  2301.             WinSendMsg (pinstDesktop->hwndMenu, MM_REMOVEITEM, MPFROM2SHORT (pinstDesktop->idDelta[iItem], TRUE), (MPARAM) NULL);
  2302.          pinstDesktop->cidDelta = 0;
  2303.         }
  2304.  
  2305.    // Remove all the document entries in the window submenu
  2306.  
  2307.       for (iDocument = 0; iDocument <= nDocuments; iDocument++)
  2308.         {WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_DELETEITEM,
  2309.            MPFROM2SHORT (CMD_SELECT_DOCUMENT + iDocument, FALSE), (MPARAM) NULL);
  2310.         }
  2311.  
  2312.    // Remove any "more documents" entry
  2313.  
  2314.       WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_DELETEITEM,
  2315.         MPFROM2SHORT (CMD_MORE_DOCUMENTS, FALSE), (MPARAM) NULL);
  2316.       fMore = FALSE;
  2317.  
  2318.    // Scan each document window in the desktop
  2319.  
  2320.       cmd = QW_TOP;
  2321.       hwndFrame = pinst->hwndDesktop;
  2322.       iDocument = -1;
  2323.       cVisDocs = 0;
  2324.       pinstFirst = (PINSTDOCUMENT) NULL;
  2325.       fListed = FALSE;
  2326.       while ((hwndFrame = WinQueryWindow (hwndFrame, cmd, FALSE)) != (HWND) NULL)
  2327.         {cmd = QW_NEXT;
  2328.          WinQueryClassName (hwndFrame, sizeof (szClassName), szClassName);
  2329.          if (strcmpi (szClassName, "#1") != 0) continue;
  2330.          hwndDocument = WinWindowFromID (hwndFrame, FID_CLIENT);
  2331.          WinQueryClassName (hwndDocument, sizeof (szClassName), szClassName);
  2332.          if (strcmpi (szClassName, MDI_DOCUMENTCLASS) != 0) continue;
  2333.          pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (hwndDocument, QWL_USER + sizeof (PVOID));
  2334.  
  2335.       // Reset the id of this document
  2336.  
  2337.          if ((pinst == pinstDocument) && (usCommand == REMOVE_TITLE))
  2338.            {pinstDocument->idInternal =  CMD_SELECT_DOCUMENT - 1;
  2339.             continue;
  2340.            }
  2341.          else if ((usCommand == INSERT_TITLE) || (usCommand == REMOVE_TITLE))
  2342.            {iDocument++;
  2343.             pinstDocument->idInternal = CMD_SELECT_DOCUMENT + iDocument;
  2344.            }
  2345.  
  2346.       // If document titles match, re-number title
  2347.  
  2348.          if (strcmp (pinst->szName, pinstDocument->szName) == 0)
  2349.  
  2350.          // If we are inserting the current title, re-number apropriately
  2351.  
  2352.            {if ((usCommand == INSERT_TITLE) || (usCommand == UPDATE_TITLE))
  2353.               {if (nSameName == 0)
  2354.                  {pinstDocument->iName = 0;
  2355.                   if (usCommand == UPDATE_TITLE)
  2356.                      WinSetWindowText (pinstDocument->hwndFrame, pinstDocument->szTitleText);
  2357.                  }
  2358.                else if (nSameName == 1)
  2359.                  {pinstDocument->iName = (pinst == pinstDocument)? 2 : 1;
  2360.                   if (pinstDocument->szTitleText[0])
  2361.                      sprintf (szClassName, "%s", pinstDocument->szTitleText);
  2362.                   else sprintf (szClassName, "%s:%d", pinstDocument->szName, pinstDocument->iName);
  2363.                   WinSetWindowText (pinstDocument->hwndFrame, szClassName);
  2364.                  }
  2365.                else if (pinst == pinstDocument)
  2366.                  {pinstDocument->iName = nSameName + 1;
  2367.                   if (pinstDocument->szTitleText[0])
  2368.                      sprintf (szClassName, "%s", pinstDocument->szTitleText);
  2369.                   else sprintf (szClassName, "%s:%d", pinstDocument->szName, pinstDocument->iName);
  2370.                   WinSetWindowText (pinstDocument->hwndFrame, szClassName);
  2371.                  }
  2372.               }
  2373.  
  2374.          // If we are removing the current title, re-number apropriately
  2375.  
  2376.             else if (usCommand == REMOVE_TITLE)
  2377.               {if (nSameName == 1)
  2378.                  {pinstDocument->iName = 0;
  2379.                   sprintf (szClassName, "%s", (pinstDocument->szTitleText[0])? pinstDocument->szTitleText : pinstDocument->szName);
  2380.                   WinSetWindowText (pinstDocument->hwndFrame, szClassName);
  2381.                  }
  2382.                else if ((nSameName > 1) && (pinstDocument->iName > pinst->iName))
  2383.                  {pinstDocument->iName--;
  2384.                   if (pinstDocument->szTitleText[0])
  2385.                      sprintf (szClassName, "%s", pinstDocument->szTitleText);
  2386.                   else sprintf (szClassName, "%s:%d", pinstDocument->szName, pinstDocument->iName);
  2387.                   WinSetWindowText (pinstDocument->hwndFrame, szClassName);
  2388.                  }
  2389.               }
  2390.  
  2391.          // Save a pointer to the instance data of the first document
  2392.          // with the same name
  2393.  
  2394.             if (pinstDocument->iName <= 1)
  2395.                pinstFirst = pinstDocument;
  2396.            }
  2397.  
  2398.       // Put document title into the window submenu if it is not hidden
  2399.       // and if there are not already 9 entries
  2400.  
  2401.          if (! (pinstDocument->usState & SWP_HIDE) && (cVisDocs < 9))
  2402.            {mi.id = pinstDocument->idInternal;
  2403.             mi.iPosition = MIT_END;
  2404.             mi.afAttribute = 0;
  2405.             mi.hwndSubMenu = (HWND) NULL;
  2406.             mi.hItem = (ULONG) NULL;
  2407.             mi.afStyle = MIS_TEXT;
  2408.             if ((pinstDocument->iName == 0) || (pinstDocument->szTitleText[0]))
  2409.                sprintf (szClassName, "%s", (pinstDocument->szTitleText[0])? pinstDocument->szTitleText : pinstDocument->szName);
  2410.             else sprintf (szClassName, "%s:%d", pinstDocument->szName, pinstDocument->iName);
  2411.             WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_INSERTITEM, (MPARAM) &mi, (MPARAM) szClassName);
  2412.             if ((usCommand == UPDATE_TITLE) && (pinstDesktop->hwndDocument == pinstDocument->hwndDocument))
  2413.                WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_SETITEMATTR,
  2414.                  MPFROM2SHORT (mi.id, FALSE), MPFROM2SHORT (MIA_CHECKED, MIA_CHECKED));
  2415.             cVisDocs++;
  2416.             fListed = TRUE;
  2417.            }
  2418.  
  2419.       // Put the "More Documents..." entry in the window submenu
  2420.       // if there are more than 9 entries
  2421.  
  2422.          else if ((cVisDocs == 9) && !fMore)
  2423.            {mi.id = CMD_MORE_DOCUMENTS;
  2424.             mi.iPosition = MIT_END;
  2425.             mi.afAttribute = 0;
  2426.             mi.hwndSubMenu = (HWND) NULL;
  2427.             mi.hItem = (ULONG) NULL;
  2428.             mi.afStyle = MIS_TEXT;
  2429.             MDILoadString (STRING_MORE_DOCUMENTS, sizeof (szClassName), szClassName);
  2430.             WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_INSERTITEM, (MPARAM) &mi, (MPARAM) szClassName);
  2431.             fMore = TRUE;
  2432.            }
  2433.  
  2434.       // Loop until all windows processed
  2435.  
  2436.         }
  2437.  
  2438.    // If at least one document is listed in the window submenu, enable
  2439.    // the HIDE and NEW window submenu options
  2440.  
  2441.       if (nDocuments > 0)
  2442.         {WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_SETITEMATTR,
  2443.            MPFROM2SHORT (CMD_HIDE, FALSE), MPFROM2SHORT (MIA_DISABLED, FALSE));
  2444.          WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_SETITEMATTR,
  2445.            MPFROM2SHORT (CMD_NEW_DOCUMENT, FALSE), MPFROM2SHORT (MIA_DISABLED, FALSE));
  2446.         }
  2447.       else if (pinstDesktop->fKeepWindowsMenu)
  2448.         {WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_SETITEMATTR,
  2449.            MPFROM2SHORT (CMD_HIDE, FALSE), MPFROM2SHORT (MIA_DISABLED, MIA_DISABLED));
  2450.          WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_SETITEMATTR,
  2451.            MPFROM2SHORT (CMD_UNHIDE, FALSE), MPFROM2SHORT (MIA_DISABLED, MIA_DISABLED));
  2452.          WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_SETITEMATTR,
  2453.            MPFROM2SHORT (CMD_NEW_DOCUMENT, FALSE), MPFROM2SHORT (MIA_DISABLED, MIA_DISABLED));
  2454.         }
  2455.  
  2456.    // Return pointer to instance data of first document with the same name
  2457.  
  2458.       return pinstFirst;
  2459.  
  2460.      }
  2461.  
  2462.  
  2463. // Function: MDIDocumentUnhideDlgProc - MDI Document Unhide dialog procedure
  2464. // -------------------------------------------------------------------------
  2465.    MRESULT EXPENTRY MDIDocumentUnhideDlgProc (hwndUnhide, msg, mp1, mp2)
  2466.  
  2467.       HWND hwndUnhide;                 // Unhide dialog box
  2468.       USHORT msg;                      // PM message
  2469.       MPARAM mp1;                      // Message parameter 1
  2470.       MPARAM mp2;                      // Message parameter 2
  2471.  
  2472.    // Define function data
  2473.  
  2474.      {HWND hwndDocument;               // Document window
  2475.       HWND hwndFrame;                  // Its frame
  2476.       HWND hwndFirst;                  // First document unhidden
  2477.       CHAR szClassName[MAX_STRING];    // Class/Title name
  2478.       CHAR szName[MAX_STRING];         // Window name
  2479.       PINSTDESKTOP pinstDesktop;       // -->desktop instance data
  2480.       PINSTDOCUMENT pinstDocument;     // -->document instance data
  2481.       SHORT cmd;                       // Which window to retrieve
  2482.       SHORT nItems, nUnhidden;         // Number of items, number unhidden
  2483.       SHORT i;                         // Temporary counter
  2484.  
  2485.    // Analyze and process message
  2486.  
  2487.       switch (msg)
  2488.  
  2489.       // Initially, load list box with all hidden window titles
  2490.  
  2491.         {case WM_INITDLG:
  2492.             pinstDesktop = (PINSTDESKTOP) mp2;
  2493.             WinSetWindowULong (hwndUnhide, QWL_USER, (ULONG) pinstDesktop);
  2494.  
  2495.          // Scan each document window in the desktop
  2496.  
  2497.             cmd = QW_TOP;
  2498.             hwndFrame = pinstDesktop->hwndDesktop;
  2499.             while ((hwndFrame = WinQueryWindow (hwndFrame, cmd, FALSE)) != (HWND) NULL)
  2500.               {cmd = QW_NEXT;
  2501.                WinQueryClassName (hwndFrame, sizeof (szClassName), szClassName);
  2502.                if (strcmpi (szClassName, "#1") != 0) continue;
  2503.                hwndDocument = WinWindowFromID (hwndFrame, FID_CLIENT);
  2504.                WinQueryClassName (hwndDocument, sizeof (szClassName), szClassName);
  2505.                if (strcmpi (szClassName, MDI_DOCUMENTCLASS) != 0) continue;
  2506.                pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (hwndDocument, QWL_USER + sizeof (PVOID));
  2507.  
  2508.             // If the document is hidden, add its title to the list box
  2509.  
  2510.                if (pinstDocument->usState & SWP_HIDE)
  2511.                  {if ((pinstDocument->iName == 0) || (pinstDocument->szTitleText[0]))
  2512.                      sprintf (szClassName, "%s", (pinstDocument->szTitleText[0])? pinstDocument->szTitleText : pinstDocument->szName);
  2513.                   else sprintf (szClassName, "%s:%d", pinstDocument->szName, pinstDocument->iName);
  2514.                   WinSendMsg (WinWindowFromID (hwndUnhide, DIALOG_UNHIDE_LISTBOX),
  2515.                     LM_INSERTITEM, MPFROMSHORT (LIT_SORTASCENDING), (MPARAM) szClassName);
  2516.                  }
  2517.  
  2518.             // Loop until all documents processed
  2519.  
  2520.               }
  2521.  
  2522.          // Indicate initialize handled
  2523.  
  2524.             return (MRESULT) NULL;
  2525.  
  2526.       // When OK hit, unhide all selected entries
  2527.  
  2528.          case WM_COMMAND:
  2529.             if (SHORT1FROMMR (mp1) == DID_OK)
  2530.  
  2531.          // Scan each selected entry in the list box
  2532.  
  2533.               {i = SHORT1FROMMR (WinSendDlgItemMsg (hwndUnhide, DIALOG_UNHIDE_LISTBOX,
  2534.                  LM_QUERYSELECTION, MPFROMSHORT (LIT_FIRST), (MPARAM) NULL));
  2535.                nItems = SHORT1FROMMR (WinSendDlgItemMsg (hwndUnhide, DIALOG_UNHIDE_LISTBOX,
  2536.                  LM_QUERYITEMCOUNT, (MPARAM) NULL, (MPARAM) NULL));
  2537.                nUnhidden = 0;
  2538.                hwndFirst = (HWND) NULL;
  2539.                pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (hwndUnhide, QWL_USER);
  2540.                while (i != LIT_NONE)
  2541.                  {WinSendDlgItemMsg (hwndUnhide, DIALOG_UNHIDE_LISTBOX,
  2542.                     LM_QUERYITEMTEXT, MPFROM2SHORT (i, sizeof (szName)), (MPARAM) szName);
  2543.  
  2544.                // Scan each document window in the desktop
  2545.  
  2546.                   cmd = QW_TOP;
  2547.                   hwndFrame = pinstDesktop->hwndDesktop;
  2548.                   while ((hwndFrame = WinQueryWindow (hwndFrame, cmd, FALSE)) != (HWND) NULL)
  2549.                     {cmd = QW_NEXT;
  2550.                      WinQueryClassName (hwndFrame, sizeof (szClassName), szClassName);
  2551.                      if (strcmpi (szClassName, "#1") != 0) continue;
  2552.                      hwndDocument = WinWindowFromID (hwndFrame, FID_CLIENT);
  2553.                      WinQueryClassName (hwndDocument, sizeof (szClassName), szClassName);
  2554.                      if (strcmpi (szClassName, MDI_DOCUMENTCLASS) != 0) continue;
  2555.                      pinstDocument = (PINSTDOCUMENT) WinQueryWindowULong (hwndDocument, QWL_USER + sizeof (PVOID));
  2556.  
  2557.                   // If the document is hidden, extract its title
  2558.  
  2559.                      if (pinstDocument->usState & SWP_HIDE)
  2560.                        {if ((pinstDocument->iName == 0) || (pinstDocument->szTitleText[0]))
  2561.                            sprintf (szClassName, "%s", (pinstDocument->szTitleText[0])? pinstDocument->szTitleText : pinstDocument->szName);
  2562.                         else sprintf (szClassName, "%s:%d", pinstDocument->szName, pinstDocument->iName);
  2563.  
  2564.                      // If title matches select list box entry, unhide document
  2565.                      // and put its entry back in the window menu
  2566.  
  2567.                         if (strcmp (szClassName, szName) == 0)
  2568.                           {pinstDocument->usState &= ~SWP_HIDE;
  2569.                            WinShowWindow (pinstDocument->hwndFrame, TRUE);
  2570.                            MDIDocumentTitlesRebuild (pinstDocument, HIDE_TITLE);
  2571.                            if (hwndFirst == (HWND) NULL)
  2572.                               hwndFirst = pinstDocument->hwndFrame;
  2573.                            nUnhidden++;
  2574.                            break;
  2575.                           }
  2576.                        }
  2577.  
  2578.                   // Loop until all documents scanned
  2579.  
  2580.                     }
  2581.  
  2582.                // Loop until all list box entries processed
  2583.  
  2584.                   i = SHORT1FROMMR (WinSendDlgItemMsg (hwndUnhide, DIALOG_UNHIDE_LISTBOX,
  2585.                     LM_QUERYSELECTION, MPFROMSHORT (i), (MPARAM) NULL));
  2586.                  }
  2587.  
  2588.             // If all entries have been unhidden, disable the
  2589.             // UNHIDE window submenu option
  2590.  
  2591.                if (nItems == nUnhidden)
  2592.                   WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_SETITEMATTR,
  2593.                     MPFROM2SHORT (CMD_UNHIDE, FALSE), MPFROM2SHORT (MIA_DISABLED, MIA_DISABLED));
  2594.  
  2595.             // If any entries at all have been unhidden, enable the
  2596.             // HIDE and NEW window submenu options
  2597.  
  2598.                WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_SETITEMATTR,
  2599.                  MPFROM2SHORT (CMD_HIDE, FALSE), MPFROM2SHORT (MIA_DISABLED, FALSE));
  2600.                WinSendMsg (pinstDesktop->miWindow.hwndSubMenu, MM_SETITEMATTR,
  2601.                  MPFROM2SHORT (CMD_NEW_DOCUMENT, FALSE), MPFROM2SHORT (MIA_DISABLED, FALSE));
  2602.  
  2603.             // Re-tile or re-cascade if necessary
  2604.  
  2605.                if (pinstDesktop->fTileAlways)
  2606.                   MDIDocumentArrange (pinstDesktop->hwndDesktop, AWP_TILED);
  2607.                else if (pinstDesktop->fCascadeAlways)
  2608.                   MDIDocumentArrange (pinstDesktop->hwndDesktop, AWP_CASCADED);
  2609.  
  2610.             // Activate the first document unhidden
  2611.  
  2612.                if (hwndFirst != (HWND) NULL)
  2613.                   WinSetWindowPos (hwndFirst, HWND_TOP, 0, 0, 0, 0, SWP_ACTIVATE | SWP_ZORDER);
  2614.  
  2615.               }
  2616.  
  2617.          // Indicate dialog box terminated
  2618.  
  2619.             WinDismissDlg (hwndUnhide, SHORT1FROMMP (mp1));
  2620.             return (MRESULT) NULL;
  2621.  
  2622.         }
  2623.  
  2624.    // Return to PM
  2625.  
  2626.       return WinDefDlgProc (hwndUnhide, msg, mp1, mp2);
  2627.  
  2628.      }
  2629.  
  2630.  
  2631. // Function: MDIDocumentWndProc - MDI Document window procedure
  2632. // ------------------------------------------------------------
  2633.    MRESULT EXPENTRY MDIDocumentWndProc (hwndDocument, msg, mp1, mp2)
  2634.  
  2635.       HWND hwndDocument;               // Document window
  2636.       USHORT msg;                      // PM message
  2637.       MPARAM mp1;                      // Message parameter 1
  2638.       MPARAM mp2;                      // Message parameter 2
  2639.  
  2640.    // Define function data
  2641.  
  2642.      {PINSTDOCUMENT pinst;             // -->instance data
  2643.       PINSTDESKTOP pinstDesktop;       // -->desktop instance data
  2644.       CHAR szName[MAX_STRING];         // Title text
  2645.  
  2646.    // Locate instance data
  2647.  
  2648.       pinst = (PINSTDOCUMENT) WinQueryWindowULong (hwndDocument, QWL_USER + sizeof (PVOID));
  2649.  
  2650.    // Analyze and process message
  2651.  
  2652.       switch (msg)
  2653.  
  2654.         {case WM_ACTIVATE:
  2655.             return MDIDocumentActivate (pinst, (BOOL) SHORT1FROMMP (mp1));
  2656.  
  2657.          case WM_CLOSE:
  2658.             return MDIDocumentClose (pinst);
  2659.  
  2660.          case WM_COMMAND:
  2661.             return MDIDocumentCommand (pinst, LOUSHORT (mp1));
  2662.  
  2663.          case WM_CREATE:
  2664.             return MDIDocumentCreate (hwndDocument, (PDOCUMENTCREATEPARMS) mp1);
  2665.  
  2666.          case WM_DESTROY:
  2667.             return MDIDocumentDestroy (pinst);
  2668.  
  2669.          case WM_MINMAXFRAME:
  2670.             return MDIDocumentMinMax (pinst, (PSWP) mp1);
  2671.  
  2672.          case WM_MOVE:
  2673.             return (MRESULT) !WinQueryWindowPos (pinst->hwndFrame, &(pinst->swp));
  2674.  
  2675.          case WM_PAINT:
  2676.             return MDIDocumentPaint (pinst);
  2677.  
  2678.          case WM_SIZE:
  2679.             return (MRESULT) !WinQueryWindowPos (pinst->hwndFrame, &(pinst->swp));
  2680.  
  2681.          case MDI_MSG_LOCATE_DESKTOP_DATA:
  2682.             pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (pinst->hwndDesktop, QWL_USER + sizeof (PVOID));
  2683.             return (MRESULT) pinstDesktop->pvDeskData;
  2684.  
  2685.          case MDI_MSG_LOCATE_DOCUMENT_DATA:
  2686.             return (MRESULT) pinst->pvDocData;
  2687.  
  2688.          case MDI_MSG_LOCATE_INSTANCE_DATA:
  2689.             return (MRESULT) pinst->pvInstData;
  2690.  
  2691.          case MDI_MSG_LOCATE_ACTIVE_DOCUMENT:
  2692.             return (MRESULT) hwndDocument;
  2693.  
  2694.          case MDI_MSG_LOCATE_DESKTOP_MENU:
  2695.             pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (pinst->hwndDesktop, QWL_USER + sizeof (PVOID));
  2696.             return (MRESULT) pinstDesktop->hwndMenu;
  2697.  
  2698.          case MDI_MSG_LOCATE_DOCUMENT_MENU:
  2699.             return (MRESULT) pinst->hwndMenu;
  2700.  
  2701.          case MDI_MSG_SET_DESKTOP_TITLE:
  2702.             pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (pinst->hwndDesktop, QWL_USER + sizeof (PVOID));
  2703.             strcpy (pinstDesktop->szTitleText, (PCHAR) mp1);
  2704.             if (pinst->usState == SWP_MAXIMIZE)
  2705.               {if ((pinst->iName == 0) || (pinst->szTitleText[0]))
  2706.                   sprintf (szName, "%s - %s", (pinstDesktop->szTitleText[0])? pinstDesktop->szTitleText : pinstDesktop->szName,
  2707.                    (pinst->szTitleText[0])? pinst->szTitleText : pinst->szName);
  2708.                else sprintf (szName, "%s - %s:%d", (pinstDesktop->szTitleText[0])? pinstDesktop->szTitleText : pinstDesktop->szName,
  2709.                    (pinst->szTitleText[0])? pinst->szTitleText : pinst->szName, pinst->iName);
  2710.                WinSetWindowText (pinstDesktop->hwndFrame, szName);
  2711.               }
  2712.             else WinSetWindowText (pinstDesktop->hwndFrame, pinstDesktop->szTitleText);
  2713.             return (MRESULT) NULL;
  2714.  
  2715.          case MDI_MSG_SET_INSTANCE_TITLE:
  2716.             pinstDesktop = (PINSTDESKTOP) WinQueryWindowULong (pinst->hwndDesktop, QWL_USER + sizeof (PVOID));
  2717.             strcpy (pinst->szTitleText, (PCHAR) mp1);
  2718.             MDIDocumentTitlesRebuild (pinst, UPDATE_TITLE);
  2719.             WinSendMsg (pinstDesktop->hwndDesktop, MDI_MSG_SET_DESKTOP_TITLE,
  2720.               (MPARAM) (pinstDesktop->szTitleText[0])? pinstDesktop->szTitleText : pinstDesktop->szName, (MPARAM) NULL);
  2721.             return (MRESULT) NULL;
  2722.  
  2723.         }
  2724.  
  2725.    // Return to PM
  2726.  
  2727.       return WinDefWindowProc (hwndDocument, msg, mp1, mp2);
  2728.  
  2729.      }
  2730.  
  2731.  
  2732. // Function: MDIInitialize - Initialize MDI processing
  2733. // ---------------------------------------------------
  2734.    VOID EXPENTRY MDIInitialize (hab)
  2735.  
  2736.       HAB hab;                         // Application anchor block
  2737.  
  2738.    // Define function data
  2739.  
  2740.      {static DOSFSRSEM dosfsrs;        // Semaphore to block registration
  2741.       static BOOL fRegistered = FALSE; // TRUE if already registered
  2742.  
  2743.    // Block the actions that follow such that only one process at a
  2744.    // time executes them.
  2745.  
  2746.       DosFSRamSemRequest (&dosfsrs, SEM_INDEFINITE_WAIT);
  2747.  
  2748.    // Once only, perform initialization.
  2749.  
  2750.       if (! fRegistered)
  2751.  
  2752.       // Register MDI Desktop window class
  2753.  
  2754.         {WinRegisterClass (hab, MDI_DESKTOPCLASS, MDIDesktopWndProc,
  2755.            /*CS_PUBLIC |*/ CS_CLIPCHILDREN | CS_SIZEREDRAW | CS_MOVENOTIFY, cbExtraData);
  2756.  
  2757.       // Register MDI Document window class
  2758.  
  2759.          WinRegisterClass (hab, MDI_DOCUMENTCLASS, MDIDocumentWndProc,
  2760.            /*CS_PUBLIC |*/ CS_CLIPCHILDREN | CS_SIZEREDRAW | CS_MOVENOTIFY, cbExtraData);
  2761.  
  2762.       // Indicate initialization complete
  2763.  
  2764.        /*fRegistered = TRUE;*/
  2765.         }
  2766.  
  2767.    // Release the block and return
  2768.  
  2769.       DosFSRamSemClear (&dosfsrs);
  2770.      }
  2771.  
  2772.  
  2773. // Function: MDILoadAccelTable - Load an MDI Accelerator Table
  2774. // -----------------------------------------------------------
  2775.    HACCEL FAR MDILoadAccelTable (idAccelTable)
  2776.  
  2777.       USHORT idAccelTable;             // Accelerator table id
  2778.  
  2779.    // Define function data
  2780.  
  2781.      {HACCEL haccel;                   // Accelerator table
  2782.       HMODULE hmod;                    // DLL module handle
  2783.       CHAR szDLL[MAX_STRING];          // DLL name
  2784.       PCHAR pszDot;                    // Temporary pointer
  2785.  
  2786.    // Extract the DLL name from our name
  2787.  
  2788.       strcpy (szDLL, MDI_MODNAME);
  2789.       if ((pszDot = strrchr (szDLL, '.')) != (PCHAR) NULL)
  2790.         *pszDot = 0;
  2791.  
  2792.    // Load accelerator table
  2793.  
  2794.       DosLoadModule (szDLL, sizeof (szDLL), szDLL, &hmod);
  2795.       haccel = WinLoadAccelTable ((HAB) NULL, hmod, idAccelTable);
  2796.       DosFreeModule (hmod);
  2797.  
  2798.    // Return handle
  2799.  
  2800.       return haccel;
  2801.  
  2802.      }
  2803.  
  2804.  
  2805. // Function: MDILoadDialog - Load an MDI Dialog Box
  2806. // ------------------------------------------------
  2807.    HWND FAR MDILoadDialog (hwndParent, pfnDlgProc, idDialog, pCreateParms)
  2808.  
  2809.       HWND hwndParent;                 // Dialog box parent
  2810.       PFNWP pfnDlgProc;                // Dialog box procedure
  2811.       USHORT idDialog;                 // Dialog box id
  2812.       PVOID pCreateParms;              // Creation parameters
  2813.  
  2814.    // Define function data
  2815.  
  2816.      {HWND hdlg;                       // Dialog box
  2817.       HMODULE hmod;                    // DLL module handle
  2818.       CHAR szDLL[MAX_STRING];          // DLL name
  2819.       PCHAR pszDot;                    // Temporary pointer
  2820.  
  2821.    // Extract the DLL name from our name
  2822.  
  2823.       strcpy (szDLL, MDI_MODNAME);
  2824.       if ((pszDot = strrchr (szDLL, '.')) != (PCHAR) NULL)
  2825.         *pszDot = 0;
  2826.  
  2827.    // Load dialog box
  2828.  
  2829.       DosLoadModule (szDLL, sizeof (szDLL), szDLL, &hmod);
  2830.       hdlg = WinLoadDlg (HWND_DESKTOP, hwndParent, pfnDlgProc, hmod, idDialog, pCreateParms);
  2831.       DosFreeModule (hmod);
  2832.  
  2833.    // Return handle
  2834.  
  2835.       return hdlg;
  2836.  
  2837.      }
  2838.  
  2839.  
  2840. // Function: MDILoadMenu - Load an MDI Menu
  2841. // ----------------------------------------
  2842.    HWND FAR MDILoadMenu (hwndParent, idMenu)
  2843.  
  2844.       HWND hwndParent;                 // Menu parent
  2845.       USHORT idMenu;                   // Menu identifier
  2846.  
  2847.    // Define function data
  2848.  
  2849.      {HWND hMenu;                      // Menu
  2850.       HMODULE hmod;                    // DLL module handle
  2851.       CHAR szDLL[MAX_STRING];          // DLL name
  2852.       SEL sel;                         // Menu template selector
  2853.       PVOID pvmt;                      // Menu template address
  2854.       PCHAR pszDot;                    // Temporary pointer
  2855.  
  2856.    // Extract the DLL name from our name
  2857.  
  2858.       strcpy (szDLL, MDI_MODNAME);
  2859.       if ((pszDot = strrchr (szDLL, '.')) != (PCHAR) NULL)
  2860.         *pszDot = 0;
  2861.  
  2862.    // Load menu
  2863.  
  2864.       DosLoadModule (szDLL, sizeof (szDLL), szDLL, &hmod);
  2865.       DosGetResource (hmod, RT_MENU, idMenu, &sel);
  2866.       pvmt = MAKEP (sel, 0);
  2867.       hMenu = WinCreateWindow (hwndParent, WC_MENU, (PSZ) NULL, (ULONG) NULL,
  2868.           0, 0, 0, 0, hwndParent, HWND_BOTTOM, idMenu, pvmt, (PVOID) NULL);
  2869.       DosFreeSeg (sel);
  2870.       DosFreeModule (hmod);
  2871.  
  2872.    // Return handle
  2873.  
  2874.       return hMenu;
  2875.  
  2876.      }
  2877.  
  2878.  
  2879. // Function: MDILoadString - Load an MDI String
  2880. // --------------------------------------------
  2881.    VOID FAR MDILoadString (idString, cbString, pszString)
  2882.  
  2883.       USHORT idString;                 // String id
  2884.       USHORT cbString;                 // Max size of string text
  2885.       PCHAR pszString;                 // -->string text
  2886.  
  2887.    // Define function data
  2888.  
  2889.      {HMODULE hmod;                    // DLL module handle
  2890.       CHAR szDLL[MAX_STRING];          // DLL name
  2891.       PCHAR pszDot;                    // Temporary pointer
  2892.  
  2893.    // Extract the DLL name from our name
  2894.  
  2895.       strcpy (szDLL, MDI_MODNAME);
  2896.       if ((pszDot = strrchr (szDLL, '.')) != (PCHAR) NULL)
  2897.         *pszDot = 0;
  2898.  
  2899.    // Load string
  2900.  
  2901.       DosLoadModule (szDLL, sizeof (szDLL), szDLL, &hmod);
  2902.       WinLoadString ((HAB) NULL, hmod, idString, cbString, pszString);
  2903.       DosFreeModule (hmod);
  2904.  
  2905.    // Return to caller
  2906.  
  2907.  
  2908.      }
  2909.