home *** CD-ROM | disk | FTP | other *** search
/ synchro.net / synchro.net.tar / synchro.net / main / BBS / ODOORS62.ZIP / ODFrame.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-08-07  |  62.2 KB  |  1,759 lines

  1. /* OpenDoors Online Software Programming Toolkit
  2.  * (C) Copyright 1991 - 1999 by Brian Pirie.
  3.  *
  4.  * This library is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU Lesser General Public
  6.  * License as published by the Free Software Foundation; either
  7.  * version 2 of the License, or (at your option) any later version.
  8.  *
  9.  * This library is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12.  * Lesser General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU Lesser General Public
  15.  * License along with this library; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17.  *
  18.  *
  19.  *        File: ODFrame.c
  20.  *
  21.  * Description: Implements the OpenDoors frame window which provides the
  22.  *              menu, toolbar, and status bar. The frame window's client
  23.  *              area contains the display window which shows the door's
  24.  *              output as the remote user would see it. This file should
  25.  *              not be built into non-Windows versions of OpenDoors.
  26.  *
  27.  *   Revisions: Date          Ver   Who  Change
  28.  *              ---------------------------------------------------------------
  29.  *              Aug 20, 1995  6.00  BP   Created.
  30.  *              Dec 20, 1995  6.00  BP   Remember toolbar & statusbar settings.
  31.  *              Dec 22, 1995  6.00  BP   Added od_connect_speed.
  32.  *              Jan 20, 1996  6.00  BP   Made ODFrameCenter...() shared.
  33.  *              Jan 21, 1996  6.00  BP   Added ODScrnShowMessage() and related.
  34.  *              Feb 17, 1996  6.00  BP   Add ...Accelerator() return value.
  35.  *              Feb 17, 1996  6.00  BP   Pass WM_MENUSELECT to DefWindowProc().
  36.  *              Feb 19, 1996  6.00  BP   Changed version number to 6.00.
  37.  *              Feb 21, 1996  6.00  BP   Fixed user keyboard off command.
  38.  *              Feb 22, 1996  6.00  BP   Allow escape to close Help About box.
  39.  *              Feb 23, 1996  6.00  BP   Properly update when toolbar turned on
  40.  *              Mar 03, 1996  6.10  BP   Begin version 6.10.
  41.  *              Mar 14, 1996  6.10  BP   Added configuration menu option.
  42.  */
  43.  
  44. #define BUILDING_OPENDOORS
  45.  
  46. #include <stdio.h>
  47.  
  48. #include "windows.h"
  49. #include "commctrl.h"
  50.  
  51. #include "OpenDoor.h"
  52. #include "ODRes.h"
  53. #include "ODFrame.h"
  54. #include "ODGen.h"
  55. #include "ODScrn.h"
  56. #include "ODKrnl.h"
  57.  
  58. #ifdef ODPLAT_WIN32
  59.  
  60. /* Frame window information structure. */
  61. typedef struct
  62. {
  63.    HINSTANCE hInstance;
  64.    BOOL bToolbarOn;
  65.    HWND hwndToolbar;
  66.    BOOL bStatusBarOn;
  67.    HWND hwndStatusBar;
  68.    HWND hwndTimeEdit;
  69.    HWND hwndTimeUpDown;
  70.    BOOL bWantsChatIndicator;
  71.    HACCEL hacclFrameCommands;
  72.    HWND hwndMessageWindow;
  73.    char *pszCurrentMessage;
  74.    int nCurrentMessageFlags;
  75. } tODFrameWindowInfo;
  76.  
  77. /* Toolbar button information. */
  78. TBBUTTON atbButtons[] =
  79. {
  80.    {0,   0,                         TBSTATE_ENABLED,  TBSTYLE_SEP,    0, 0},
  81.    {0,   0,                         TBSTATE_ENABLED,  TBSTYLE_SEP,    0, 0},
  82.    {0,   0,                         TBSTATE_ENABLED,  TBSTYLE_SEP,    0, 0},
  83.    {0,   0,                         TBSTATE_ENABLED,  TBSTYLE_SEP,    0, 0},
  84.    {0,   0,                         TBSTATE_ENABLED,  TBSTYLE_SEP,    0, 0},
  85.    {0,   0,                         TBSTATE_ENABLED,  TBSTYLE_SEP,    0, 0},
  86.    {0,   0,                         TBSTATE_ENABLED,  TBSTYLE_SEP,    0, 0},
  87.    {0,   0,                         TBSTATE_ENABLED,  TBSTYLE_SEP,    0, 0},
  88.    {0,   0,                         TBSTATE_ENABLED,  TBSTYLE_SEP,    0, 0},
  89.    {0,   0,                         TBSTATE_ENABLED,  TBSTYLE_SEP,    0, 0},
  90.    {0,   ID_DOOR_CHATMODE,          TBSTATE_ENABLED,  TBSTYLE_BUTTON, 0, 0},
  91.    {0,   0,                         TBSTATE_ENABLED,  TBSTYLE_SEP,    0, 0},
  92.    {1,   ID_DOOR_USERKEYBOARDOFF,   TBSTATE_ENABLED,  TBSTYLE_BUTTON, 0, 0},
  93.    {2,   ID_DOOR_SYSOPNEXT,         TBSTATE_ENABLED,  TBSTYLE_BUTTON, 0, 0},
  94.    {0,   0,                         TBSTATE_ENABLED,  TBSTYLE_SEP,    0, 0},
  95.    {3,   ID_DOOR_HANGUP,            TBSTATE_ENABLED,  TBSTYLE_BUTTON, 0, 0},
  96.    {4,   ID_DOOR_LOCKOUT,           TBSTATE_ENABLED,  TBSTYLE_BUTTON, 0, 0},
  97.    {5,   ID_DOOR_EXIT,              TBSTATE_ENABLED,  TBSTYLE_BUTTON, 0, 0},
  98. };
  99.  
  100. /* Other toolbar settings. */
  101. #define NUM_TOOLBAR_BITMAPS   6
  102. #define MIN_TIME              0
  103. #define MAX_TIME              1440
  104.  
  105. /* Pointer to default edit box window procedure. */
  106. WNDPROC pfnDefEditProc = NULL;
  107. WNDPROC pfnDefToolbarProc = NULL;
  108.  
  109. /* Global frame window handle. */
  110. static HWND hwndCurrentFrame;
  111.  
  112. /* Status bar settings. */
  113. #define NUM_STATUS_PARTS      2
  114. #define NODE_PART_WIDTH       65
  115.  
  116. /* Child window IDs. */
  117. #define ID_TOOLBAR            1000
  118. #define ID_TIME_EDIT          1001
  119. #define ID_TIME_UPDOWN        1002
  120. #define ID_STATUSBAR          1003
  121.  
  122.  
  123. /* Private function prototypes. */
  124. static HWND ODFrameCreateToolbar(HWND hwndParent, HANDLE hInstance,
  125.    tODFrameWindowInfo *pWindowInfo);
  126. static void ODFrameDestroyToolbar(HWND hwndToolbar,
  127.    tODFrameWindowInfo *pWindowInfo);
  128. static HWND ODFrameCreateStatusBar(HWND hwndParent, HANDLE hInstance);
  129. static void ODFrameSetMainStatusText(HWND hwndStatusBar);
  130. static void ODFrameDestroyStatusBar(HWND hwndStatusBar);
  131. static void ODFrameSizeStatusBar(HWND hwndStatusBar);
  132. LRESULT CALLBACK ODFrameWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  133.    LPARAM lParam);
  134. LRESULT CALLBACK ODFrameToolbarProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  135.    LPARAM lParam);
  136. static void ODFrameUpdateTimeLeft(tODFrameWindowInfo *pWindowInfo);
  137. LRESULT CALLBACK ODFrameTimeEditProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  138.    LPARAM lParam);
  139. BOOL CALLBACK ODFrameAboutDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
  140.    LPARAM lParam);
  141. static HWND ODFrameCreateWindow(HANDLE hInstance);
  142. static void ODFrameDestroyWindow(HWND hwndFrame);
  143. static void ODFrameMessageLoop(HANDLE hInstance, HWND hwndFrame);
  144. DWORD OD_THREAD_FUNC ODFrameThreadProc(void *pParam);
  145. BOOL CALLBACK ODFrameMessageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
  146.    LPARAM lParam);
  147.  
  148.  
  149. /* ----------------------------------------------------------------------------
  150.  * ODFrameCreateWindow()                               *** PRIVATE FUNCTION ***
  151.  *
  152.  * Creates the OpenDoors frame window and its children.
  153.  *
  154.  * Parameters: hInstance   - Handle to application instance.
  155.  *
  156.  *     Return: A handle to the newly created window, or NULL on failure.
  157.  */
  158. static HWND ODFrameCreateWindow(HANDLE hInstance)
  159. {
  160.    HWND hwndFrameWindow = NULL;
  161.    WNDCLASS wcFrameWindow;
  162.    tODFrameWindowInfo *pWindowInfo = NULL;
  163.    tODThreadHandle hScreenThread;
  164.    HKEY hOpenDoorsKey;
  165.    DWORD cbData;
  166.  
  167.    /* Register the main frame window's window class. */
  168.    memset(&wcFrameWindow, 0, sizeof(wcFrameWindow));
  169.    wcFrameWindow.style = CS_HREDRAW | CS_VREDRAW;
  170.    wcFrameWindow.lpfnWndProc = ODFrameWindowProc;
  171.    wcFrameWindow.cbClsExtra = 0;
  172.    wcFrameWindow.cbWndExtra = 0;
  173.    wcFrameWindow.hInstance = hInstance;
  174.    if(od_control.od_app_icon != NULL)
  175.    {
  176.       wcFrameWindow.hIcon = od_control.od_app_icon;
  177.    }
  178.    else
  179.    {
  180.       wcFrameWindow.hIcon
  181.          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_OPENDOORS));
  182.    }
  183.    wcFrameWindow.hCursor = LoadCursor(NULL, IDC_ARROW);
  184.    wcFrameWindow.hbrBackground = NULL;
  185.    wcFrameWindow.lpszMenuName = MAKEINTRESOURCE(IDR_FRAME_MENU);
  186.    wcFrameWindow.lpszClassName = "ODFrame";
  187.  
  188.    RegisterClass(&wcFrameWindow);
  189.  
  190.    /* Setup window information structure. */
  191.    pWindowInfo = malloc(sizeof(tODFrameWindowInfo));
  192.    if(!pWindowInfo)
  193.    {
  194.       return(NULL);
  195.    }
  196.    pWindowInfo->hInstance = hInstance;
  197.    pWindowInfo->hwndTimeEdit = NULL;
  198.    pWindowInfo->hwndTimeUpDown = NULL;
  199.    pWindowInfo->bWantsChatIndicator = FALSE;
  200.    pWindowInfo->hwndMessageWindow = NULL;
  201.  
  202.    /* Determine whether or not the toolbar and status bar are on. */
  203.    RegCreateKey(HKEY_CURRENT_USER, "Software\\Pirie\\OpenDoors",
  204.       &hOpenDoorsKey);
  205.  
  206.    cbData = sizeof(pWindowInfo->bToolbarOn);
  207.    if(RegQueryValueEx(hOpenDoorsKey, "ToolBarOn", NULL, NULL, 
  208.       (LPBYTE)&pWindowInfo->bToolbarOn,
  209.       &cbData) != ERROR_SUCCESS)
  210.    {
  211.       pWindowInfo->bToolbarOn = TRUE;
  212.       RegSetValueEx(hOpenDoorsKey, "ToolBarOn", 0, REG_DWORD,
  213.          (LPBYTE)&pWindowInfo->bToolbarOn,
  214.          sizeof(pWindowInfo->bToolbarOn));
  215.    }
  216.  
  217.    cbData = sizeof(pWindowInfo->bStatusBarOn);
  218.    if(RegQueryValueEx(hOpenDoorsKey, "StatusBarOn", NULL, NULL, 
  219.       (LPBYTE)&pWindowInfo->bStatusBarOn,
  220.       &cbData) != ERROR_SUCCESS)
  221.    {
  222.       pWindowInfo->bStatusBarOn = TRUE;
  223.       RegSetValueEx(hOpenDoorsKey, "StatusBarOn", 0, REG_DWORD,
  224.          (LPBYTE)&pWindowInfo->bStatusBarOn,
  225.          sizeof(pWindowInfo->bStatusBarOn));
  226.    }
  227.  
  228.    RegCloseKey(hOpenDoorsKey);
  229.  
  230.    /* Create the main frame window. */
  231.    if((hwndFrameWindow = CreateWindowEx(
  232.       0L,
  233.       wcFrameWindow.lpszClassName,
  234.       od_control.od_prog_name,
  235.       WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX,
  236.       CW_USEDEFAULT,
  237.       0,
  238.       0,
  239.       0,
  240.       NULL,
  241.       NULL,
  242.       hInstance,
  243.       pWindowInfo)) == NULL)
  244.    {
  245.       /* On window creation failure, return NULL. */
  246.       return(NULL);
  247.    }
  248.  
  249.    /* Load accelerator table for the  frame window. */
  250.    pWindowInfo->hacclFrameCommands
  251.       = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_FRAME));
  252.  
  253.    /* Create the OpenDoors toolbar. On failure, we will continue anyhow. */
  254.    if(pWindowInfo->bToolbarOn)
  255.    {
  256.       pWindowInfo->hwndToolbar =
  257.          ODFrameCreateToolbar(hwndFrameWindow, hInstance, pWindowInfo);
  258.    }
  259.  
  260.    /* Create the status bar. On failure, we will continue anyhow. */
  261.    if(pWindowInfo->bStatusBarOn)
  262.    {
  263.       pWindowInfo->hwndStatusBar =
  264.          ODFrameCreateStatusBar(hwndFrameWindow, hInstance);
  265.    }
  266.  
  267.    /* Updates state of the window from whether or not the user has */
  268.    /* requested a chat with the sysop.                             */
  269.    ODFrameUpdateWantChat();
  270.  
  271.    /* Create the local screen window, which occupies the remaining */
  272.    /* client area of the frame window.                             */
  273.    ODScrnStartWindow(hInstance, &hScreenThread, hwndFrameWindow);
  274.  
  275.    return(hwndFrameWindow);
  276. }
  277.  
  278.  
  279. /* ----------------------------------------------------------------------------
  280.  * ODFrameCreateToolbar()                              *** PRIVATE FUNCTION ***
  281.  *
  282.  * Creates the OpenDoors toolbar.
  283.  *
  284.  * Parameters: hwndParent  - Handle to the parent window.
  285.  *
  286.  *             hInstance   - Handle to the executable file's module instance.
  287.  *
  288.  *             pWindowInfo - Pointer to frame window information structure.
  289.  *
  290.  *     Return: A handle to the toolbar on success, or NULL on failure.
  291.  */
  292. static HWND ODFrameCreateToolbar(HWND hwndParent, HANDLE hInstance,
  293.    tODFrameWindowInfo *pWindowInfo)
  294. {
  295.    HWND hwndToolbar = NULL;
  296.    HWND hwndTimeEdit = NULL;
  297.    HWND hwndTimeUpDown = NULL;
  298.    HWND hwndToolTip;
  299.    BOOL bSuccess = FALSE;
  300.  
  301.    ASSERT(hwndParent != NULL);
  302.    ASSERT(hInstance != NULL);
  303.    ASSERT(pWindowInfo != NULL);
  304.  
  305.    /* First, attempt to create the toolbar window. */
  306.    hwndToolbar = CreateToolbarEx(hwndParent,
  307.       WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS,
  308.       ID_TOOLBAR, NUM_TOOLBAR_BITMAPS, hInstance, IDB_TOOLBAR,
  309.       atbButtons, DIM(atbButtons), 0, 0, 0, 0, sizeof(TBBUTTON));
  310.  
  311.    if(hwndToolbar == NULL)
  312.    {
  313.       goto CleanUp;
  314.    }
  315.  
  316.    /* Change the window proc for the toolbar window to our own, keeping a */
  317.    /* pointer to the original window proc.                                */
  318.    pfnDefToolbarProc = (WNDPROC)GetWindowLong(hwndToolbar, GWL_WNDPROC);
  319.    SetWindowLong(hwndToolbar, GWL_WNDPROC, (LONG)ODFrameToolbarProc);
  320.  
  321.    /* Next, create an edit control on the toolbar, to allow the user's */
  322.    /* time remaining online to be adjusted.                            */
  323.    hwndTimeEdit = CreateWindowEx(WS_EX_STATICEDGE, "EDIT", "",
  324.       WS_CHILD | WS_BORDER | WS_VISIBLE | ES_LEFT,
  325.       0, 0, 70, 22, hwndToolbar, (HMENU)ID_TIME_EDIT, hInstance, NULL);
  326.  
  327.    if(hwndTimeEdit == NULL)
  328.    {
  329.       goto CleanUp;
  330.    }
  331.  
  332.    /* Now that the edit window has the appropriate parent, we set its */
  333.    /* position accordingly. */
  334.    SetWindowPos(hwndTimeEdit, NULL, 2, 2, 0, 0,
  335.       SWP_NOZORDER | SWP_NOSIZE);
  336.  
  337.    /* Set font of the edit control to be the standard non-bold font. */
  338.    SendMessage(hwndTimeEdit, WM_SETFONT,
  339.       (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(FALSE, 0));
  340.  
  341.    /* Change the window proc for the edit window to our own, keeping a */
  342.    /* pointer to the original window proc. */
  343.    pfnDefEditProc = (WNDPROC)GetWindowLong(hwndTimeEdit, GWL_WNDPROC);
  344.    SetWindowLong(hwndTimeEdit, GWL_WNDPROC, (LONG)ODFrameTimeEditProc);
  345.  
  346.    /* Add the time edit control to the tooltip control. */
  347.  
  348.    /* Obtain a handle to the toolbar's tooltip control. */
  349.    hwndToolTip = (HWND)SendMessage(hwndToolbar, TB_GETTOOLTIPS, 0, 0);
  350.    if(hwndToolTip)
  351.    {
  352.       TOOLINFO ToolInfo;
  353.  
  354.       /* Fill TOOLINFO structure. */
  355.       ToolInfo.cbSize = sizeof(ToolInfo);
  356.       ToolInfo.uFlags = TTF_IDISHWND | TTF_CENTERTIP;
  357.       ToolInfo.lpszText = "User's Time Remaining";
  358.       ToolInfo.hwnd = hwndParent;
  359.       ToolInfo.uId = (UINT)hwndTimeEdit;
  360.       ToolInfo.hinst = hInstance;
  361.  
  362.       /* Setup tooltips for the time edit box. */
  363.       SendMessage(hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ToolInfo);
  364.    }
  365.  
  366.    /* Now, we create an up-down control to buddy with the edit control. */
  367.    hwndTimeUpDown = CreateWindowEx(0L, UPDOWN_CLASS, "",
  368.       WS_CHILD | WS_BORDER | WS_VISIBLE | UDS_ARROWKEYS |
  369.       UDS_ALIGNRIGHT, 0, 0, 8, 8,
  370.          hwndToolbar, (HMENU)ID_TIME_UPDOWN, hInstance, NULL);
  371.  
  372.    if(hwndTimeUpDown == NULL)
  373.    {
  374.       goto CleanUp;
  375.    }
  376.  
  377.    /* Set the up-down control's buddy control to be the edit control that */
  378.    /* we just created.                                                    */
  379.    SendMessage(hwndTimeUpDown, UDM_SETBUDDY, (LONG)hwndTimeEdit, 0L);
  380.  
  381.    /* Set the valid range of values for the edit control. */
  382.    SendMessage(hwndTimeUpDown, UDM_SETRANGE, 0L, MAKELONG(MAX_TIME, MIN_TIME));
  383.  
  384.    /* Store handles to time limit edit and up-down controls. */
  385.    pWindowInfo->hwndTimeEdit = hwndTimeEdit;
  386.    pWindowInfo->hwndTimeUpDown = hwndTimeUpDown;
  387.  
  388.    /* Next, we set the default text for the edit control. */
  389.    ODFrameUpdateTimeLeft(pWindowInfo);
  390.  
  391.    /* Return with success. */
  392.    bSuccess = TRUE;
  393.  
  394. CleanUp:
  395.    if(!bSuccess)
  396.    {
  397.       /* On failure, free any allocated resources. */
  398.       if(hwndTimeUpDown != NULL)
  399.       {
  400.          DestroyWindow(hwndTimeUpDown);
  401.       }
  402.       if(hwndTimeEdit != NULL)
  403.       {
  404.          DestroyWindow(hwndTimeUpDown);
  405.       }
  406.       if(hwndToolbar != NULL)
  407.       {
  408.          DestroyWindow(hwndToolbar);
  409.          hwndToolbar = NULL;
  410.       }
  411.    }
  412.  
  413.    /* Return handle to newly created toolbar, or NULL on failure. */
  414.    return(hwndToolbar);
  415. }
  416.  
  417.  
  418. /* ----------------------------------------------------------------------------
  419.  * ODFrameDestroyToolbar()                             *** PRIVATE FUNCTION ***
  420.  *
  421.  * Destroys the OpenDoors toolbar.
  422.  *
  423.  * Parameters: hwndToolbar - Handle to previously created toolbar.
  424.  *
  425.  *             pWindowInfo - Pointer to frame window information structure.
  426.  *
  427.  *     Return: void.
  428.  */
  429. static void ODFrameDestroyToolbar(HWND hwndToolbar,
  430.    tODFrameWindowInfo *pWindowInfo)
  431. {
  432.    ASSERT(hwndToolbar != NULL);
  433.    ASSERT(pWindowInfo != NULL);
  434.  
  435.    /* Destroy the time up-down control, and NULL its handle in the frame */
  436.    /* window information structure.                                      */
  437.    DestroyWindow(pWindowInfo->hwndTimeUpDown);
  438.    pWindowInfo->hwndTimeUpDown = NULL;
  439.  
  440.    /* Destroy the time edit control, and NULL its handle in the frame window */
  441.    /* information structure.                                                 */
  442.    DestroyWindow(pWindowInfo->hwndTimeEdit);
  443.    pWindowInfo->hwndTimeEdit = NULL;
  444.  
  445.    /* Now, destroy the toolbar itself. */
  446.    DestroyWindow(hwndToolbar);
  447. }
  448.  
  449.  
  450. /* ----------------------------------------------------------------------------
  451.  * ODFrameCreateStatusBar()                            *** PRIVATE FUNCTION ***
  452.  *
  453.  * Creates the OpenDoors status bar.
  454.  *
  455.  * Parameters: hwndParent  - Handle to the parent window.
  456.  *
  457.  *             hInstance   - Handle to the executable file's module instance.
  458.  *
  459.  *     Return: A handle to the status bar on success, or NULL on failure.
  460.  */
  461. static HWND ODFrameCreateStatusBar(HWND hwndParent, HANDLE hInstance)
  462. {
  463.    HWND hwndStatusBar = NULL;
  464.    char szStatusText[20];
  465.  
  466.    ASSERT(hwndParent != NULL);
  467.  
  468.    /* Create the status bar window. */
  469.    hwndStatusBar = CreateWindowEx(0L, STATUSCLASSNAME, "",
  470.       WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
  471.       hwndParent, (HMENU)ID_STATUSBAR, hInstance, NULL);
  472.  
  473.    if(hwndStatusBar == NULL)
  474.    {
  475.       return(NULL);
  476.    }
  477.  
  478.    /* Set the size of the status bar parts from the size of the frame */
  479.    /* window.                                                         */
  480.    ODFrameSizeStatusBar(hwndStatusBar);
  481.  
  482.    /* Add the user's name, location and connection info string. */
  483.    ODFrameSetMainStatusText(hwndStatusBar);
  484.  
  485.    /* Add the node number string. */
  486.    sprintf(szStatusText, "Node %d", od_control.od_node);
  487.    SendMessage(hwndStatusBar, SB_SETTEXT, (WPARAM)1, (LPARAM)szStatusText);
  488.  
  489.    return(hwndStatusBar);
  490. }
  491.  
  492.  
  493. /* ----------------------------------------------------------------------------
  494.  * ODFrameSetMainStatusText()                          *** PRIVATE FUNCTION ***
  495.  *
  496.  * Updates the text that is displayed in the main pane of the status bar.
  497.  *
  498.  * Parameters: hwndStatusBar - Handle to the status bar.
  499.  *
  500.  *     Return: void.
  501.  */
  502. static void ODFrameSetMainStatusText(HWND hwndStatusBar)
  503. {
  504.    char szStatusText[160];
  505.  
  506.    ASSERT(hwndStatusBar != NULL);
  507.  
  508.    /* Generate base status bar text, with the user's name, location and */
  509.    /* connection information.                                           */
  510.    if(od_control.baud == 0)
  511.    {
  512.       sprintf(szStatusText, "%s of %s in local mode",
  513.          od_control.user_name,
  514.          od_control.user_location);
  515.    }
  516.    else
  517.    {
  518.       sprintf(szStatusText, "%s of %s at %ldbps",
  519.          od_control.user_name,
  520.          od_control.user_location,
  521.          od_control.od_connect_speed);
  522.    }
  523.  
  524.    /* If the user has paged the sysop, then include reason for chat if */
  525.    /* it is available.                                                 */
  526.    if(od_control.user_wantchat && strlen(od_control.user_reasonforchat) > 0)
  527.    {
  528.       strcat(szStatusText, " (Reason for chat: \"");
  529.       strcat(szStatusText, od_control.user_reasonforchat);
  530.       strcat(szStatusText, "\")");
  531.    }
  532.  
  533.    /* Update status bar text in the main status bar pane with the newly */
  534.    /* generated string.                                                 */
  535.    SendMessage(hwndStatusBar, SB_SETTEXT, (WPARAM)0, (LPARAM)szStatusText);
  536. }
  537.  
  538.  
  539. /* ----------------------------------------------------------------------------
  540.  * ODFrameDestroyStatusBar()                           *** PRIVATE FUNCTION ***
  541.  *
  542.  * Destroys the OpenDoors status bar.
  543.  *
  544.  * Parameters: hwndStatusBar    - Handle to previously created status bar.
  545.  *
  546.  *     Return: void.
  547.  */
  548. static void ODFrameDestroyStatusBar(HWND hwndStatusBar)
  549. {
  550.    DestroyWindow(hwndStatusBar);
  551. }
  552.  
  553.  
  554. /* ----------------------------------------------------------------------------
  555.  * ODFrameSizeStatusBar()                              *** PRIVATE FUNCTION ***
  556.  *
  557.  * Creates the OpenDoors status bar.
  558.  *
  559.  * Parameters: hwndStatusBar  - Handle to existing status bar window.
  560.  *
  561.  *     Return: void.
  562.  */
  563. static void ODFrameSizeStatusBar(HWND hwndStatusBar)
  564. {
  565.    int anWidths[NUM_STATUS_PARTS];
  566.    int nStatusWidth;
  567.    RECT rcStatusBar;
  568.  
  569.    /* Determine the total width of the status bar. */
  570.    GetWindowRect(hwndStatusBar, &rcStatusBar);
  571.    nStatusWidth = rcStatusBar.right - rcStatusBar.left;
  572.  
  573.    /* Calculate the width of the parts from the total width. */
  574.    anWidths[0] = nStatusWidth - NODE_PART_WIDTH;
  575.    anWidths[1] = -1;
  576.  
  577.    /* Update the status bar part settings. */
  578.    SendMessage(hwndStatusBar, SB_SETPARTS, NUM_STATUS_PARTS,
  579.       (LPARAM)anWidths);
  580. }
  581.  
  582.  
  583. /* ----------------------------------------------------------------------------
  584.  * ODFrameGetUsedClientAtTop()
  585.  *
  586.  * Determines height in pixels of the space used at the top of the
  587.  * frame window's client area, by the toolbar, etc.
  588.  *
  589.  * Parameters: hwndFrame - Handle to the OpenDoors frame window.
  590.  *
  591.  *     Return: The height of the used space, in pixels.
  592.  */
  593. INT ODFrameGetUsedClientAtTop(HWND hwndFrame)
  594. {
  595.    tODFrameWindowInfo *pWindowInfo;
  596.    RECT rcWindow;
  597.  
  598.    pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwndFrame, GWL_USERDATA);
  599.  
  600.    if(!pWindowInfo->bToolbarOn) return(0);
  601.  
  602.    GetWindowRect(pWindowInfo->hwndToolbar, &rcWindow);
  603.  
  604.    return(rcWindow.bottom - rcWindow.top - 2);
  605. }
  606.  
  607.  
  608. /* ----------------------------------------------------------------------------
  609.  * ODFrameGetUsedClientAtBottom()
  610.  *
  611.  * Determines height in pixels of the space used at the bottom of the
  612.  * frame window's client area, by the status bar, etc.
  613.  *
  614.  * Parameters: hwndFrame - Handle to the OpenDoors frame window.
  615.  *
  616.  *     Return: The height of the used space, in pixels.
  617.  */
  618. INT ODFrameGetUsedClientAtBottom(HWND hwndFrame)
  619. {
  620.    tODFrameWindowInfo *pWindowInfo;
  621.    RECT rcWindow;
  622.  
  623.    pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwndFrame, GWL_USERDATA);
  624.  
  625.    if(!pWindowInfo->bStatusBarOn) return(0);
  626.  
  627.    GetWindowRect(pWindowInfo->hwndStatusBar, &rcWindow);
  628.  
  629.    return(rcWindow.bottom - rcWindow.top - 1);
  630. }
  631.  
  632.  
  633. /* ----------------------------------------------------------------------------
  634.  * ODFrameWindowProc()                                 *** PRIVATE FUNCTION ***
  635.  *
  636.  * The OpenDoors frame window proceedure.
  637.  *
  638.  * Parameters: hwnd   - Handle to the OpenDoors frame window.
  639.  *
  640.  *             uMsg   - Specifies the message.
  641.  *
  642.  *             wParam - Specifies additional message information. The content
  643.  *                      of this parameter depends on the value of the uMsg
  644.  *                      parameter.
  645.  *
  646.  *             lParam - Specifies additional message information. The content
  647.  *                      of this parameter depends on the value of the uMsg
  648.  *                      parameter.
  649.  *
  650.  *     Return: The return value is the result of the message processing and
  651.  *             depends on the message.
  652.  */
  653. LRESULT CALLBACK ODFrameWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  654.    LPARAM lParam)
  655. {
  656.    tODFrameWindowInfo *pWindowInfo;
  657.  
  658.    pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwnd, GWL_USERDATA);
  659.  
  660.    switch(uMsg)
  661.    {
  662.       case WM_CREATE:
  663.       {
  664.          /* At window creation time, store a pointer to the window */
  665.          /* information structure in window's user data.           */
  666.          CREATESTRUCT *pCreateStruct = (CREATESTRUCT *)lParam;
  667.          pWindowInfo = (tODFrameWindowInfo *)pCreateStruct->lpCreateParams;
  668.          SetWindowLong(hwnd, GWL_USERDATA, (LONG)pWindowInfo);
  669.  
  670.          /* Update the enabled and checked states of frame window commands. */
  671.          ODFrameUpdateCmdUI();
  672.  
  673.          /* If the client has not provided a help callback function, then */
  674.          /* remove the Contents item from the help menu.                  */
  675.          if(od_control.od_help_callback == NULL)
  676.          {
  677.             RemoveMenu(GetMenu(hwnd), ID_HELP_CONTENTS, MF_BYCOMMAND);
  678.          }
  679.  
  680.          if(od_control.od_config_callback == NULL)
  681.          {
  682.             RemoveMenu(GetMenu(hwnd), ID_DOOR_CONFIG, MF_BYCOMMAND);
  683.          }
  684.          break;
  685.       }
  686.  
  687.       case WM_CLOSE:
  688.          /* If door exit has been chosen, confirm with local user. */
  689.          if(MessageBox(hwnd,
  690.             "You are about to terminate this session and return the user to the BBS.\nDo you wish to proceed?",
  691.             od_control.od_prog_name,
  692.             MB_ICONQUESTION | MB_YESNO) == IDYES)
  693.          {
  694.             /* Normal door exit (drop to BBS) is implemented by the */
  695.             /* WM_DESTROY handler.                                  */
  696.             ODFrameDestroyWindow(hwnd);
  697.          }
  698.          break;
  699.  
  700.       case WM_DESTROY:
  701.          /* If toolbar is on, then it must be destroyed when the frame */
  702.          /* window is destroyed.                                       */
  703.          if(pWindowInfo->bToolbarOn)
  704.          {
  705.             ODFrameDestroyToolbar(GetDlgItem(hwnd, ID_TOOLBAR), pWindowInfo);
  706.          }
  707.  
  708.          /* If status bar is on, then it must be destroyed when the frame */
  709.          /* window is destroyed.                                          */
  710.          if(pWindowInfo->bStatusBarOn)
  711.          {
  712.             ODFrameDestroyStatusBar(GetDlgItem(hwnd, ID_STATUSBAR));
  713.          }
  714.  
  715.          /* Now, force OpenDoors to shutdown. */
  716.          ODKrnlForceOpenDoorsShutdown(ERRORLEVEL_DROPTOBBS);
  717.  
  718.          /* When the frame window is destroyed, it is the window proc's   */
  719.          /* responsiblity to deallocate the window information structure. */
  720.          free(pWindowInfo);
  721.          SetWindowLong(hwnd, GWL_USERDATA, (LONG)NULL);
  722.  
  723.          /* Reset current frame window handle. */
  724.          hwndCurrentFrame = NULL;
  725.          break;
  726.  
  727.       case WM_SETFOCUS:
  728.          /* Whenver input focus is set to the frame window, pass the input */
  729.          /* focus on to the screen window, which fills most of our client  */
  730.          /* area.                                                          */
  731.          ODScrnSetFocusToWindow();
  732.          break;
  733.  
  734.       case WM_TIMER:
  735.          /* If the window flash timer has elapsed, then flash the window. */
  736.          FlashWindow(hwnd, TRUE);
  737.          break;
  738.  
  739.       case WM_COMMAND:
  740.          /* An OpenDoors-defined command has been selected, so switch on */
  741.          /* the command ID.                                              */
  742.          switch(LOWORD(wParam))
  743.          {
  744.             case ID_HELP_ABOUT:
  745.                /* Display the OpenDoors default about box. */
  746.                DialogBox(pWindowInfo->hInstance, MAKEINTRESOURCE(IDD_ABOUT),
  747.                   hwnd, ODFrameAboutDlgProc);
  748.                break;
  749.  
  750.             case ID_HELP_CONTENTS:
  751.                /* Call the client's help callback function, if one was */
  752.                /* provided.                                            */
  753.                if(od_control.od_help_callback != NULL)
  754.                {
  755.                   (*od_control.od_help_callback)();
  756.                }
  757.                break;
  758.  
  759.             case ID_DOOR_CONFIG:
  760.                if(od_control.od_config_callback != NULL)
  761.                {
  762.                   (*od_control.od_config_callback)();
  763.                }
  764.                break;
  765.  
  766.             case ID_DOOR_EXIT:
  767.                /* On request for normal door exit (drop to BBS), just send  */
  768.                /* a close message to this window. This will prompt to       */
  769.                /* confirm exit, and then shutdown OpenDoors if appropriate. */
  770.                PostMessage(hwnd, WM_CLOSE, 0, 0L);
  771.                break;
  772.  
  773.             case ID_DOOR_CHATMODE:
  774.                /* If chat mode is currently active, then end it. */
  775.                if(od_control.od_chat_active)
  776.                {
  777.                   ODKrnlEndChatMode();
  778.                }
  779.                /* If chat mode is not currently active, then start it. */
  780.                else
  781.                {
  782.                   ODKrnlStartChatThread(TRUE);
  783.                }
  784.                break;
  785.  
  786.             case ID_DOOR_USERKEYBOARDOFF:
  787.                /* If user keyboard off command has been chosen, then toggle */
  788.                /* keyboard off mode on or off.                              */
  789.                od_control.od_user_keyboard_on
  790.                   = !od_control.od_user_keyboard_on;
  791.  
  792.                /* Update the keyboard off menu item and toolbar button. */
  793.                CheckMenuItem(GetMenu(hwnd), ID_DOOR_USERKEYBOARDOFF,
  794.                   MF_BYCOMMAND | (od_control.od_user_keyboard_on
  795.                   ? MF_UNCHECKED : MF_CHECKED));
  796.                SendMessage(GetDlgItem(hwnd, ID_TOOLBAR), TB_CHECKBUTTON,
  797.                   ID_DOOR_USERKEYBOARDOFF,
  798.                   MAKELONG(!od_control.od_user_keyboard_on, 0));
  799.                break;
  800.  
  801.             case ID_DOOR_SYSOPNEXT:
  802.                /* If sysop next command has been chosen, then toggle the */
  803.                /* sysop next flag on or off.                             */
  804.                od_control.sysop_next = !od_control.sysop_next;
  805.  
  806.                /* Update the sysop next menu item and toolbar button. */
  807.                CheckMenuItem(GetMenu(hwnd), ID_DOOR_SYSOPNEXT, MF_BYCOMMAND |
  808.                   (od_control.sysop_next ? MF_CHECKED : MF_UNCHECKED));
  809.                SendMessage(GetDlgItem(hwnd, ID_TOOLBAR), TB_CHECKBUTTON,
  810.                   ID_DOOR_SYSOPNEXT, MAKELONG(od_control.sysop_next, 0));
  811.                break;
  812.  
  813.             case ID_DOOR_HANGUP:
  814.                /* If hangup command has been chosen, then confirm with the */
  815.                /* local user.                                              */
  816.                if(MessageBox(hwnd,
  817.                   "You are about to disconnect this user. Do you wish to proceed?",
  818.                   od_control.od_prog_name,
  819.                   MB_ICONQUESTION | MB_YESNO) == IDYES)
  820.                {
  821.                   ODKrnlForceOpenDoorsShutdown(ERRORLEVEL_HANGUP);
  822.                }
  823.                break;
  824.  
  825.             case ID_DOOR_LOCKOUT:
  826.                /* If lockout command has been chosen, the confirm with the */
  827.                /* local user.                                              */
  828.                if(MessageBox(hwnd,
  829.                   "You are about to lock out this user. Do you wish to proceed?",
  830.                   od_control.od_prog_name,
  831.                   MB_ICONQUESTION | MB_YESNO) == IDYES)
  832.                {
  833.                   /* Set the user's access security level to 0. */
  834.                   od_control.user_security = 0;
  835.  
  836.                   ODKrnlForceOpenDoorsShutdown(ERRORLEVEL_HANGUP);
  837.                }
  838.                break;
  839.  
  840.             case ID_VIEW_TOOL_BAR:
  841.             {
  842.                HKEY hOpenDoorsKey;
  843.  
  844.                /* If toolbar on/off command has been chosen ... */
  845.                if(pWindowInfo->bToolbarOn)
  846.                {
  847.                   /* If the toolbar is on, then turn it off. */
  848.                   ODFrameDestroyToolbar(GetDlgItem(hwnd, ID_TOOLBAR),
  849.                      pWindowInfo);
  850.                   pWindowInfo->bToolbarOn = FALSE;
  851.                   CheckMenuItem(GetMenu(hwnd), ID_VIEW_TOOL_BAR,
  852.                      MF_BYCOMMAND | MF_UNCHECKED);
  853.                }
  854.                else
  855.                {
  856.                   /* If the toolbar is off, then turn it on. */
  857.                   pWindowInfo->hwndToolbar = ODFrameCreateToolbar(hwnd,
  858.                      pWindowInfo->hInstance, pWindowInfo);
  859.                   pWindowInfo->bToolbarOn = TRUE;
  860.                   CheckMenuItem(GetMenu(hwnd), ID_VIEW_TOOL_BAR,
  861.                      MF_BYCOMMAND | MF_CHECKED);
  862.                   ODFrameUpdateCmdUI();
  863.                }
  864.  
  865.                /* Adjust window sizes accordingly. */
  866.                ODScrnAdjustWindows();
  867.  
  868.                /* Update the toolbar setting in the registry. */
  869.                RegCreateKey(HKEY_CURRENT_USER, "Software\\Pirie\\OpenDoors",
  870.                   &hOpenDoorsKey);
  871.                RegSetValueEx(hOpenDoorsKey, "ToolBarOn", 0, REG_DWORD,
  872.                   (LPBYTE)&pWindowInfo->bToolbarOn,
  873.                   sizeof(pWindowInfo->bToolbarOn));
  874.                RegCloseKey(hOpenDoorsKey);
  875.                break;
  876.             }
  877.  
  878.             case ID_VIEW_STAT_BAR:
  879.             {
  880.                HKEY hOpenDoorsKey;
  881.  
  882.                /* If the status bar on/off command has been chosen ... */
  883.                if(pWindowInfo->bStatusBarOn)
  884.                {
  885.                   /* If the status bar is on, then turn it off. */
  886.                   pWindowInfo->bStatusBarOn = FALSE;
  887.                   CheckMenuItem(GetMenu(hwnd), ID_VIEW_STAT_BAR,
  888.                      MF_BYCOMMAND | MF_UNCHECKED);
  889.                   ODFrameDestroyStatusBar(GetDlgItem(hwnd, ID_STATUSBAR));
  890.                }
  891.                else
  892.                {
  893.                   /* If the status bar is off, then turn it on. */
  894.                   pWindowInfo->bStatusBarOn = TRUE;
  895.                   CheckMenuItem(GetMenu(hwnd), ID_VIEW_STAT_BAR,
  896.                      MF_BYCOMMAND | MF_CHECKED);
  897.                   pWindowInfo->hwndStatusBar =
  898.                      ODFrameCreateStatusBar(hwnd, pWindowInfo->hInstance);
  899.                }
  900.  
  901.                /* Adjust window sizes accordingly. */
  902.                ODScrnAdjustWindows();
  903.  
  904.                /* Update the status bar setting in the registry. */
  905.                RegCreateKey(HKEY_CURRENT_USER, "Software\\Pirie\\OpenDoors",
  906.                   &hOpenDoorsKey);
  907.                RegSetValueEx(hOpenDoorsKey, "StatusBarOn", 0, REG_DWORD,
  908.                   (LPBYTE)&pWindowInfo->bStatusBarOn,
  909.                   sizeof(pWindowInfo->bStatusBarOn));
  910.                RegCloseKey(hOpenDoorsKey);
  911.                break;
  912.             }
  913.  
  914.             case ID_USER_ADDONEMINUTE:
  915.                /* If add one minute command has been chosen, then        */
  916.                /* increment the user's time, up to the maximum allowable */
  917.                /* time.                                                  */
  918.                if(od_control.user_timelimit < MAX_TIME)
  919.                {
  920.                   od_control.user_timelimit++;
  921.                   ODFrameUpdateTimeLeft(pWindowInfo);
  922.                }
  923.                break;
  924.  
  925.             case ID_USER_ADDFIVEMINUTES:
  926.                /* If add five minutes command has been chosen, then */
  927.                /* adjust the user's time accordingly.               */
  928.                od_control.user_timelimit =
  929.                   MIN(od_control.user_timelimit + 5, MAX_TIME);
  930.                ODFrameUpdateTimeLeft(pWindowInfo);
  931.                break;
  932.  
  933.             case ID_USER_SUBTRACTONEMINUTE:
  934.                /* If subtract one minute command has been chosen, then */
  935.                /* adjust the user's time accordingly.                  */
  936.                if(od_control.user_timelimit > MIN_TIME)
  937.                {
  938.                   od_control.user_timelimit--;
  939.                   ODFrameUpdateTimeLeft(pWindowInfo);
  940.                }
  941.                break;
  942.  
  943.             case ID_USER_SUBTRACTFIVEMINUTES:
  944.                /* If the subtract five mintues command has been chosen, */
  945.                /* then adjust the user's time accordingly.              */
  946.                od_control.user_timelimit =
  947.                   MAX(od_control.user_timelimit - 5, MIN_TIME);
  948.                ODFrameUpdateTimeLeft(pWindowInfo);
  949.                break;
  950.  
  951.             case ID_USER_INACTIVITYTIMER:
  952.                /* If the user inactivity timer command has been chosen, */
  953.                /* then toggle the timer on or off.                      */
  954.                od_control.od_disable_inactivity =
  955.                   !od_control.od_disable_inactivity;
  956.                CheckMenuItem(GetMenu(hwnd), ID_USER_INACTIVITYTIMER,
  957.                   MF_BYCOMMAND | (od_control.od_disable_inactivity ?
  958.                   MF_UNCHECKED : MF_CHECKED));
  959.                break;
  960.  
  961.             case ID_TIME_EDIT:
  962.             {
  963.                /* If the user's time remaining has been directly edited, */
  964.                /* then adjust the time limit accordingly.                */
  965.                if(HIWORD(wParam) == EN_CHANGE)
  966.                {
  967.                   char szTimeText[40];
  968.                   GetWindowText((HWND)lParam, szTimeText, sizeof(szTimeText));
  969.                   od_control.user_timelimit = atoi(szTimeText);
  970.  
  971.                   /* Do not allow the time limit to fall outside of the */
  972.                   /* valid range.                                       */
  973.                   od_control.user_timelimit =
  974.                      MAX(MIN_TIME, od_control.user_timelimit);
  975.                   od_control.user_timelimit =
  976.                      MIN(MAX_TIME, od_control.user_timelimit);
  977.  
  978.                   /* Update the position of the up-down control. */
  979.                   SendMessage(pWindowInfo->hwndTimeUpDown, UDM_SETPOS, 0,
  980.                      (LPARAM)MAKELONG(od_control.user_timelimit, 0));
  981.                }
  982.             }
  983.  
  984.             default:
  985.                return(TRUE);
  986.          }
  987.          return(FALSE);
  988.  
  989.       case WM_NOTIFY:
  990.          /* A control parent notification message has been sent. */
  991.          switch(((LPNMHDR)lParam)->code)
  992.          {
  993.             case TTN_NEEDTEXT:
  994.             {
  995.                /* This is the message from the tool tip control, requesting */
  996.                /* the appropriate string to display for the current toolbar */
  997.                /* item.                                                     */
  998.                LPTOOLTIPTEXT lpToolTipText = (LPTOOLTIPTEXT)lParam;
  999.                switch(lpToolTipText->hdr.idFrom)
  1000.                {
  1001.                   case ID_DOOR_EXIT:
  1002.                      lpToolTipText->lpszText = "Exit To BBS";
  1003.                      break;
  1004.                   case ID_DOOR_CHATMODE:
  1005.                      lpToolTipText->lpszText = "Chat Mode";
  1006.                      break;
  1007.                   case ID_DOOR_USERKEYBOARDOFF:
  1008.                      lpToolTipText->lpszText = "User Keyboard Off";
  1009.                      break;
  1010.                   case ID_DOOR_SYSOPNEXT:
  1011.                      lpToolTipText->lpszText = "Sysop Next";
  1012.                      break;
  1013.                   case ID_DOOR_HANGUP:
  1014.                      lpToolTipText->lpszText = "Hangup";
  1015.                      break;
  1016.                   case ID_DOOR_LOCKOUT:
  1017.                      lpToolTipText->lpszText = "Lockout";
  1018.                      break;
  1019.                }
  1020.                break;
  1021.             }
  1022.          }
  1023.          break;
  1024.  
  1025.       case WM_VSCROLL:
  1026.          /* A scrolling action has taken place. */
  1027.  
  1028.          /* If it is the time limit up-down control that has scrolled. */
  1029.          if((HWND)lParam == pWindowInfo->hwndTimeUpDown)
  1030.          {
  1031.             int nPos = HIWORD(wParam);
  1032.  
  1033.             /* Adjust the user's time limit. */
  1034.             od_control.user_timelimit = MAX(MIN(nPos, MAX_TIME), MIN_TIME);
  1035.  
  1036.             /* Update the time left displayed in the edit box. */
  1037.             ODFrameUpdateTimeLeft(pWindowInfo);
  1038.          }
  1039.          break;
  1040.  
  1041.       case WM_SIZE:
  1042.          /* The OpenDoors frame window has been resized, so its contents */
  1043.          /* must now be resized accordingly.                             */
  1044.  
  1045.          /* Pass the message on to the status bar window, so that it will */
  1046.          /* automatically adjust its own position and overall size.       */
  1047.          SendMessage(GetDlgItem(hwnd, ID_STATUSBAR), WM_SIZE, wParam, lParam);
  1048.  
  1049.          /* Now, adjust the size of each part of the status bar. */
  1050.          ODFrameSizeStatusBar(GetDlgItem(hwnd, ID_STATUSBAR));
  1051.  
  1052.          /* Pass the message on to the toolbar, so that it will resize */
  1053.          /* iteself.                                                   */
  1054.          SendMessage(GetDlgItem(hwnd, ID_TOOLBAR), WM_SIZE, wParam, lParam);
  1055.          break;
  1056.  
  1057.       case WM_MENUSELECT:
  1058.          /* If the user has selected an item on the menu, then we should */
  1059.          /* update the status bar accordingly.                           */
  1060.          if(HIWORD(wParam) == 0xFFFF)
  1061.          {
  1062.             /* If menu is being exited, then turn off the status bar simple */
  1063.             /* mode.                                                        */
  1064.             HWND hwndStatusBar = GetDlgItem(hwnd, ID_STATUSBAR);
  1065.  
  1066.             SendMessage(hwndStatusBar, SB_SIMPLE, (WPARAM)FALSE, 0L);
  1067.          }
  1068.          else
  1069.          {
  1070.             char szCommandString[160] = "";
  1071.             HWND hwndStatusBar = GetDlgItem(hwnd, ID_STATUSBAR);
  1072.  
  1073.             /* A new menu item is being selected. */
  1074.  
  1075.             /* If this item is on the system menu, then provide the strings */
  1076.             /* for any of those menu items.                                 */
  1077.             if(HIWORD(wParam) & MF_SYSMENU)
  1078.             {
  1079.                switch(LOWORD(wParam))
  1080.                {
  1081.                   case SC_SIZE:
  1082.                      strcpy(szCommandString,
  1083.                         "Resizes this window.");
  1084.                      break;
  1085.                   case SC_MOVE:
  1086.                      strcpy(szCommandString,
  1087.                         "Moves this window.");
  1088.                      break;
  1089.                   case SC_MINIMIZE:
  1090.                      strcpy(szCommandString,
  1091.                         "Collapses this window to an icon.");
  1092.                      break;
  1093.                   case SC_MAXIMIZE:
  1094.                      strcpy(szCommandString,
  1095.                         "Expands this window to fill the screen.");
  1096.                      break;
  1097.                   case SC_CLOSE:
  1098.                      strcpy(szCommandString,
  1099.                         "Closes this window, and returns the user to the BBS.");
  1100.                      break;
  1101.                   case SC_RESTORE:
  1102.                      strcpy(szCommandString,
  1103.                         "Restores this window to normal size.");
  1104.                      break;
  1105.                   case SC_TASKLIST:
  1106.                      strcpy(szCommandString,
  1107.                         "");
  1108.                      break;
  1109.                }
  1110.             }
  1111.             else
  1112.             {
  1113.                /* If this item is on the window menu provided by OpenDoors, */
  1114.                /* then load the status bar string for this command ID.      */
  1115.                LoadString(pWindowInfo->hInstance, LOWORD(wParam),
  1116.                   szCommandString, sizeof(szCommandString));
  1117.             }
  1118.  
  1119.             /* Switch the status bar into simple (single-paned) mode. */
  1120.             SendMessage(hwndStatusBar, SB_SIMPLE, (WPARAM)TRUE, 0L);
  1121.  
  1122.             /* Set the text for the status bar. */
  1123.             SendMessage(hwndStatusBar, SB_SETTEXT, (WPARAM)255 | SBT_NOBORDERS,
  1124.                (LPARAM)szCommandString);
  1125.          }
  1126.          return(DefWindowProc(hwnd, uMsg, wParam, lParam));
  1127.  
  1128.       case WM_SHOW_MESSAGE:
  1129.          if(pWindowInfo->hwndMessageWindow == NULL)
  1130.          {
  1131.             pWindowInfo->pszCurrentMessage = (char *)lParam;
  1132.             pWindowInfo->nCurrentMessageFlags = (int)wParam;
  1133.  
  1134.             /* Create the message window. */
  1135.             DialogBoxParam(pWindowInfo->hInstance,
  1136.                MAKEINTRESOURCE(IDD_MESSAGE), hwnd, ODFrameMessageDlgProc,
  1137.                (LPARAM)pWindowInfo);
  1138.          }
  1139.          break;
  1140.  
  1141.       case WM_REMOVE_MESSAGE:
  1142.          if(pWindowInfo->hwndMessageWindow != NULL)
  1143.          {
  1144.             PostMessage(pWindowInfo->hwndMessageWindow, WM_COMMAND,
  1145.                MAKELONG(IDOK, 0), 0L);
  1146.             pWindowInfo->hwndMessageWindow = NULL;
  1147.          }
  1148.          break;
  1149.  
  1150.       default:
  1151.          /* Pass messages that we don't explicitly handle on to the */
  1152.          /* default window proc.                                    */
  1153.          return(DefWindowProc(hwnd, uMsg, wParam, lParam));
  1154.    }
  1155.  
  1156.    return(0);
  1157. }
  1158.  
  1159.  
  1160. /* ----------------------------------------------------------------------------
  1161.  * ODFrameUpdateCmdUI()
  1162.  *
  1163.  * Updates the enabled and checked state of OpenDoors commands that may change.
  1164.  *
  1165.  * Parameters: None.
  1166.  *
  1167.  *     Return: void.
  1168.  */
  1169. void ODFrameUpdateCmdUI(void)
  1170. {
  1171.    HWND hwndFrame = hwndCurrentFrame;
  1172.    HMENU hMenu = GetMenu(hwndFrame);
  1173.    HWND hwndToolbar = GetDlgItem(hwndFrame, ID_TOOLBAR);
  1174.    tODFrameWindowInfo *pWindowInfo;
  1175.  
  1176.    if(hwndFrame == NULL) return;
  1177.  
  1178.    /* Obtain window information structure. */
  1179.    pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwndFrame, GWL_USERDATA);
  1180.    if(pWindowInfo == NULL) return;
  1181.  
  1182.    /* Check or uncheck the toolbar and status bar menu items. */
  1183.    CheckMenuItem(hMenu, ID_VIEW_TOOL_BAR, MF_BYCOMMAND |
  1184.       (pWindowInfo->bToolbarOn ? MF_CHECKED : MF_UNCHECKED));
  1185.    CheckMenuItem(hMenu, ID_VIEW_STAT_BAR, MF_BYCOMMAND |
  1186.       (pWindowInfo->bStatusBarOn ? MF_CHECKED : MF_UNCHECKED));
  1187.  
  1188.    /* Check or uncheck the inactivity timer menu item. */
  1189.    CheckMenuItem(hMenu, ID_USER_INACTIVITYTIMER, MF_BYCOMMAND |
  1190.       (od_control.od_disable_inactivity ? MF_UNCHECKED : MF_CHECKED));
  1191.  
  1192.    /* Check or uncheck the sysop next menu item and toolbar button. */
  1193.    CheckMenuItem(hMenu, ID_DOOR_SYSOPNEXT, MF_BYCOMMAND |
  1194.       (od_control.sysop_next ? MF_CHECKED : MF_UNCHECKED));
  1195.    SendMessage(hwndToolbar, TB_CHECKBUTTON,
  1196.       ID_DOOR_SYSOPNEXT, MAKELONG(od_control.sysop_next, 0));
  1197.  
  1198.    /* Check or uncheck the keyboard off menu item and toolbar button. */
  1199.    CheckMenuItem(hMenu, ID_DOOR_USERKEYBOARDOFF, MF_BYCOMMAND |
  1200.       (od_control.od_user_keyboard_on ? MF_UNCHECKED : MF_CHECKED));
  1201.    SendMessage(hwndToolbar, TB_CHECKBUTTON,
  1202.       ID_DOOR_USERKEYBOARDOFF,
  1203.       MAKELONG(!od_control.od_user_keyboard_on, 0));
  1204.  
  1205.    /* Update the chat mode menu item and toolbar button. */
  1206.    CheckMenuItem(hMenu, ID_DOOR_CHATMODE, MF_BYCOMMAND |
  1207.       (od_control.od_chat_active ? MF_CHECKED : MF_UNCHECKED));
  1208.    SendMessage(hwndToolbar, TB_CHECKBUTTON, ID_DOOR_CHATMODE,
  1209.       MAKELONG(od_control.od_chat_active, 0));
  1210. }
  1211.  
  1212.  
  1213. /* ----------------------------------------------------------------------------
  1214.  * ODFrameUpdateTimeDisplay()
  1215.  *
  1216.  * Updates the remaining time online that is displayed anywhere by the frame
  1217.  * window. Uses ODFrameUpdateTimeLeft().
  1218.  *
  1219.  * Parameters: None.
  1220.  *
  1221.  *     Return: void.
  1222.  */
  1223. void ODFrameUpdateTimeDisplay(void)
  1224. {
  1225.    tODFrameWindowInfo *pWindowInfo;
  1226.  
  1227.    /* If there is no current frame window, then return without doing */
  1228.    /* anything.                                                      */
  1229.    if(hwndCurrentFrame == NULL) return;
  1230.  
  1231.    pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwndCurrentFrame,
  1232.       GWL_USERDATA);
  1233.    ASSERT(pWindowInfo != NULL);
  1234.  
  1235.    ODFrameUpdateTimeLeft(pWindowInfo);
  1236. }
  1237.  
  1238.  
  1239. /* ----------------------------------------------------------------------------
  1240.  * ODFrameUpdateWantChat()
  1241.  *
  1242.  * Updates the state of the flashing wants-chat indicator on the frame window.
  1243.  *
  1244.  * Parameters: None.
  1245.  *
  1246.  *     Return: void.
  1247.  */
  1248. void ODFrameUpdateWantChat(void)
  1249. {
  1250.    tODFrameWindowInfo *pWindowInfo;
  1251.  
  1252.    /* If there is no current frame window, then return without doing */
  1253.    /* anything.                                                      */
  1254.    if(hwndCurrentFrame == NULL) return;
  1255.  
  1256.    pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwndCurrentFrame,
  1257.       GWL_USERDATA);
  1258.    ASSERT(pWindowInfo != NULL);
  1259.  
  1260.    /* If the status bar is on, then update the text displayed in the */
  1261.    /* status bar's main pane.                                        */
  1262.    if(pWindowInfo->bStatusBarOn)
  1263.    {
  1264.       ODFrameSetMainStatusText(pWindowInfo->hwndStatusBar);
  1265.    }
  1266.  
  1267.    /* Toggle the state of the wants-chat indicator, of needed. */
  1268.    if(pWindowInfo->bWantsChatIndicator && !od_control.user_wantchat)
  1269.    {
  1270.       /* Restore original window text. */
  1271.       SetWindowText(hwndCurrentFrame, od_control.od_prog_name);
  1272.  
  1273.       /* Restore the window flash to its original state. */
  1274.       FlashWindow(hwndCurrentFrame, FALSE);
  1275.  
  1276.       /* Destroy the Windows timer. */
  1277.       KillTimer(hwndCurrentFrame, 1);
  1278.  
  1279.       /* Record that wants chat indicator is now off. */
  1280.       pWindowInfo->bWantsChatIndicator = FALSE;
  1281.    }
  1282.    else if (!pWindowInfo->bWantsChatIndicator && od_control.user_wantchat)
  1283.    {
  1284.       /* Set window title to include the wants chat indicator. */
  1285.       char szNewWindowTitle[sizeof(od_control.od_prog_name) + 20];
  1286.       sprintf(szNewWindowTitle, "%s - User Wants Chat",
  1287.          od_control.od_prog_name);
  1288.       SetWindowText(hwndCurrentFrame, szNewWindowTitle);
  1289.  
  1290.       /* Start the flashing the window. */
  1291.       SetTimer(hwndCurrentFrame, 1,
  1292.          GetCaretBlinkTime(), NULL);
  1293.  
  1294.       /* Record that wants chat indicator is now on. */
  1295.       pWindowInfo->bWantsChatIndicator = TRUE;
  1296.    }
  1297. }
  1298.  
  1299.  
  1300. /* ----------------------------------------------------------------------------
  1301.  * ODFrameDestroyWindow()                              *** PRIVATE FUNCTION ***
  1302.  *
  1303.  * Destroys the OpenDoors frame window and its children.
  1304.  *
  1305.  * Parameters: hwndFrame   - Handle to the window previously created by
  1306.  *                           ODFrameCreateWindow().
  1307.  *
  1308.  *     Return: void.
  1309.  */
  1310. static void ODFrameDestroyWindow(HWND hwndFrame)
  1311. {
  1312.    tODFrameWindowInfo *pWindowInfo;
  1313.  
  1314.    ASSERT(hwndFrame != NULL);
  1315.  
  1316.    /* Obtain a pointer to the frame window information structure. */
  1317.    pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwndFrame, GWL_USERDATA);
  1318.  
  1319.    /* At this point, deallocate the accelerator table. */
  1320.    if(pWindowInfo->hacclFrameCommands != NULL)
  1321.    {
  1322.       DestroyAcceleratorTable(pWindowInfo->hacclFrameCommands);
  1323.    }
  1324.  
  1325.    /* Destroying the main frame window will automatically cause its */
  1326.    /* children to be destroyed.                                     */
  1327.    DestroyWindow(hwndFrame);
  1328. }
  1329.  
  1330.  
  1331. /* ----------------------------------------------------------------------------
  1332.  * ODFrameToolbarProc()                                *** PRIVATE FUNCTION ***
  1333.  *
  1334.  * The toolbar window proceedure.
  1335.  *
  1336.  * Parameters: hwnd   - Handle to the toolbar window.
  1337.  *
  1338.  *             uMsg   - Specifies the message.
  1339.  *
  1340.  *             wParam - Specifies additional message information. The content
  1341.  *                      of this parameter depends on the value of the uMsg
  1342.  *                      parameter.
  1343.  *
  1344.  *             lParam - Specifies additional message information. The content
  1345.  *                      of this parameter depends on the value of the uMsg
  1346.  *                      parameter.
  1347.  *
  1348.  *     Return: The return value is the result of the message processing and
  1349.  *             depends on the message.
  1350.  */
  1351. LRESULT CALLBACK ODFrameToolbarProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  1352.    LPARAM lParam)
  1353. {
  1354.    switch(uMsg)
  1355.    {
  1356.       /* Forward needed message to the main frame window proceedure. */
  1357.       case WM_VSCROLL:
  1358.       case WM_COMMAND:
  1359.          SendMessage(GetParent(hwnd), uMsg, wParam, lParam);
  1360.          break;
  1361.    }
  1362.  
  1363.    /* Pass all messages on to the default toolbar window proceedure. */
  1364.    return(CallWindowProc(pfnDefToolbarProc, hwnd, uMsg, wParam, lParam));
  1365. }
  1366.  
  1367.  
  1368. /* ----------------------------------------------------------------------------
  1369.  * ODFrameUpdateTimeLeft()                             *** PRIVATE FUNCTION ***
  1370.  *
  1371.  * Updates the displayed time remaining from od_control.user_timelimit.
  1372.  *
  1373.  * Parameters: pWindowInfo - Pointer to frame window information structure.
  1374.  *
  1375.  *     Return: void.
  1376.  */
  1377. static void ODFrameUpdateTimeLeft(tODFrameWindowInfo *pWindowInfo)
  1378. {
  1379.    char szTimeLeft[12];
  1380.    RECT rcWindow;
  1381.  
  1382.    if(pWindowInfo->hwndTimeEdit == NULL)
  1383.    {
  1384.       /* If the time limit edit control does not exist (i.e., if the       */
  1385.       /* toolbar is not currently on), then there is nothing for us to do. */
  1386.       return;
  1387.    }
  1388.  
  1389.    /* Generate the string to be displayed in the edit control. */
  1390.    sprintf(szTimeLeft, "%d min.", od_control.user_timelimit);
  1391.  
  1392.    /* Set the edit control's text to the new string. */
  1393.    SetWindowText(pWindowInfo->hwndTimeEdit, szTimeLeft);
  1394.  
  1395.    /* Force edit control to be redrawn. (Except for rightmost pixel */
  1396.    /* column.)                                                      */
  1397.    GetWindowRect(pWindowInfo->hwndTimeEdit, &rcWindow);
  1398.    rcWindow.right--;
  1399.    InvalidateRect(pWindowInfo->hwndTimeEdit, &rcWindow, TRUE);
  1400.  
  1401.    /* Set the position of the up-down control to match. */
  1402.    SendMessage(pWindowInfo->hwndTimeUpDown, UDM_SETPOS, 0,
  1403.       (LPARAM)MAKELONG(od_control.user_timelimit, 0));
  1404. }
  1405.  
  1406.  
  1407. /* ----------------------------------------------------------------------------
  1408.  * ODFrameTimeEditProc()                               *** PRIVATE FUNCTION ***
  1409.  *
  1410.  * The time edit window proceedure. Relays mouse messages from the edit box
  1411.  * to the tooltip control, and then passes all messages on to the standard
  1412.  * edit box window proceedure.
  1413.  *
  1414.  * Parameters: hwnd   - Handle to the time edit window.
  1415.  *
  1416.  *             uMsg   - Specifies the message.
  1417.  *
  1418.  *             wParam - Specifies additional message information. The content
  1419.  *                      of this parameter depends on the value of the uMsg
  1420.  *                      parameter.
  1421.  *
  1422.  *             lParam - Specifies additional message information. The content
  1423.  *                      of this parameter depends on the value of the uMsg
  1424.  *                      parameter.
  1425.  *
  1426.  *     Return: The return value is the result of the message processing and
  1427.  *             depends on the message.
  1428.  */
  1429. LRESULT CALLBACK ODFrameTimeEditProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  1430.    LPARAM lParam)
  1431. {
  1432.    switch(uMsg)
  1433.    {
  1434.       case WM_MOUSEMOVE:
  1435.       case WM_LBUTTONDOWN:
  1436.       case WM_LBUTTONUP:
  1437.       {
  1438.          MSG msg;
  1439.          HWND hwndToolTip;
  1440.  
  1441.          /* Setup message structure. */
  1442.          msg.lParam = lParam;
  1443.          msg.wParam = wParam;
  1444.          msg.message = uMsg;
  1445.          msg.hwnd = hwnd;
  1446.  
  1447.          /* Obtain handle to the tooltip window. */
  1448.          hwndToolTip = (HWND)SendMessage(GetParent(hwnd), TB_GETTOOLTIPS,
  1449.             0, 0);
  1450.  
  1451.          /* Relay the message to the tooltip window. */
  1452.          SendMessage(hwndToolTip, TTM_RELAYEVENT, 0, (LPARAM)(LPMSG)&msg);
  1453.  
  1454.          break;
  1455.       }
  1456.    }
  1457.  
  1458.    /* Pass all messages on to the default edit box window proceedure. */
  1459.    return(CallWindowProc(pfnDefEditProc, hwnd, uMsg, wParam, lParam));
  1460. }
  1461.  
  1462.  
  1463. /* ----------------------------------------------------------------------------
  1464.  * ODFrameAboutDlgProc()
  1465.  *
  1466.  * DialogProc for the OpenDoors default Help About dialog box.
  1467.  *
  1468.  * Parameters: hwndDlg  - Window handle to the dialog box.
  1469.  *
  1470.  *             uMsg     - Message ID.
  1471.  *
  1472.  *             wParam   - First message parameter.
  1473.  *
  1474.  *             lParam   - Second message parameter.
  1475.  *
  1476.  *     Return: TRUE if message is processed, FALSE otherwise.
  1477.  */
  1478. BOOL CALLBACK ODFrameAboutDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
  1479.    LPARAM lParam)
  1480. {
  1481.    switch(uMsg)
  1482.    {
  1483.       case WM_INITDIALOG:
  1484.          /* At dialog box creation time, update the text in the about      */
  1485.          /* box with any information provided by the OpenDoors programmer. */
  1486.  
  1487.          /* If a program name has been provided, then display it. */
  1488.          if(strcmp(od_control.od_prog_name, OD_VER_SHORTNAME) != 0)
  1489.          {
  1490.             SetWindowText(GetDlgItem(hwndDlg, IDC_DOORNAME),
  1491.                od_control.od_prog_name);
  1492.          }
  1493.  
  1494.          /* If copyright information has been provided, then display it. */
  1495.          if(strlen(od_control.od_prog_copyright) > 0)
  1496.          {
  1497.             SetWindowText(GetDlgItem(hwndDlg, IDC_COPYRIGHT),
  1498.                od_control.od_prog_copyright);
  1499.          }
  1500.  
  1501.          /* If program version information has been provided, then display */
  1502.          /* it.                                                            */
  1503.          if(strlen(od_control.od_prog_version) > 0)
  1504.          {
  1505.             SetWindowText(GetDlgItem(hwndDlg, IDC_VERSION),
  1506.                od_control.od_prog_version);
  1507.          }
  1508.  
  1509.          /* Center the about dialog box in the area occupied by the */
  1510.          /* main frame window.                                      */
  1511.          ODFrameCenterWindowInParent(hwndDlg);
  1512.  
  1513.          return(TRUE);
  1514.  
  1515.       case WM_COMMAND:
  1516.          /* If a command has been chosen. */
  1517.          switch(LOWORD(wParam))
  1518.          {
  1519.             case IDCANCEL:
  1520.             case IDOK:
  1521.                /* If the OK button has been pressed, then close the dialog. */
  1522.                EndDialog(hwndDlg, IDOK);
  1523.                break;
  1524.          }
  1525.          return(TRUE);
  1526.  
  1527.       default:
  1528.          /* Otherwise, indicate that this message has not been processed. */
  1529.          return(FALSE);
  1530.    }
  1531. }
  1532.  
  1533.  
  1534. /* ----------------------------------------------------------------------------
  1535.  * ODFrameCenterWindowInParent()                       *** PRIVATE FUNCTION ***
  1536.  *
  1537.  * Repositions the specified window so that it is centered in its parent.
  1538.  *
  1539.  * Parameters: hwndChild - The window to reposition.
  1540.  *
  1541.  *     Return: void.
  1542.  */
  1543. void ODFrameCenterWindowInParent(HWND hwndChild)
  1544. {
  1545.    HWND hwndParent;
  1546.    RECT rcParent;
  1547.    RECT rcChild;
  1548.    INT nChildWidth;
  1549.    INT nChildHeight;
  1550.    INT nParentWidth;
  1551.    INT nParentHeight;
  1552.  
  1553.    ASSERT(hwndChild != NULL);
  1554.  
  1555.    /* Obtain a handle to the parent window. */
  1556.    hwndParent = GetParent(hwndChild);
  1557.    ASSERT(hwndParent != NULL);
  1558.  
  1559.    /* Obtain the bounding boxes of both windows. */
  1560.    GetWindowRect(hwndChild, &rcChild);
  1561.    GetWindowRect(hwndParent, &rcParent);
  1562.    
  1563.    /* Determine the height and width of both windows. */
  1564.    nChildWidth = rcChild.right - rcChild.left;
  1565.    nChildHeight = rcChild.bottom - rcChild.top;
  1566.    nParentWidth = rcParent.right - rcParent.left;
  1567.    nParentHeight = rcParent.bottom - rcParent.top;
  1568.  
  1569.    /* Move the child to the center of the parent. */
  1570.    SetWindowPos(hwndChild, NULL,
  1571.       rcParent.left + (nParentWidth - nChildWidth) / 2,
  1572.       rcParent.top + (nParentHeight - nChildHeight) / 2,
  1573.       0, 0, SWP_NOSIZE | SWP_NOZORDER);
  1574. }
  1575.  
  1576.  
  1577. /* ----------------------------------------------------------------------------
  1578.  * ODFrameMessageLoop()                                *** PRIVATE FUNCTION ***
  1579.  *
  1580.  * Message loop for OpenDoors local UI thread (frame window handling).
  1581.  *
  1582.  * Parameters: hInstance   - Handle to current instance.
  1583.  *
  1584.  *             hwndFrame   - Handle to the frame window.
  1585.  *
  1586.  *     Return: void.
  1587.  */
  1588. static void ODFrameMessageLoop(HANDLE hInstance, HWND hwndFrame)
  1589. {
  1590.    MSG msg;
  1591.  
  1592.    ASSERT(hInstance != NULL);
  1593.    ASSERT(hwndFrame != NULL);
  1594.  
  1595.    /* Loop, fetching, translating and dispatching messages for any windows */
  1596.    /* created by this thread. (GetMessage() blocks when no messages are    */
  1597.    /* available.)                                                          */
  1598.    while(GetMessage(&msg, NULL, 0, 0))
  1599.    {
  1600.       if(!ODFrameTranslateAccelerator(hwndFrame, &msg))
  1601.       {
  1602.          TranslateMessage(&msg);
  1603.          DispatchMessage(&msg);
  1604.       }
  1605.    }
  1606. }
  1607.  
  1608.  
  1609. /* ----------------------------------------------------------------------------
  1610.  * ODFrameTranslateAccelerator()
  1611.  *
  1612.  * Translates WM_KEYDOWN or WM_SYSKEYDOWN messages to frame window commands,
  1613.  * if needed, based on the frame window's accelerator table.
  1614.  *
  1615.  * Parameters: hwndFrame  - Handle to the OpenDoors main frame window.
  1616.  *
  1617.  *             pMsg       - Pointer to the message that may require
  1618.  *                          translation.
  1619.  *
  1620.  *     Return: TRUE if message was translated, FALSE if not.
  1621.  */
  1622. BOOL ODFrameTranslateAccelerator(HWND hwndFrame, LPMSG pMsg)
  1623. {
  1624.    tODFrameWindowInfo *pWindowInfo;
  1625.  
  1626.    ASSERT(hwndFrame != NULL);
  1627.    ASSERT(pMsg != NULL);
  1628.  
  1629.    /* Obtain a pointer to the frame window information structure. */
  1630.    pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwndFrame, GWL_USERDATA);
  1631.    ASSERT(pWindowInfo != NULL);
  1632.  
  1633.    /* Perform accelerator translation, based on the frame window's */
  1634.    /* accelerator table, sending any resulting WM_COMMAND messages */
  1635.    /* to the frame window.                                         */
  1636.    return(TranslateAccelerator(hwndFrame, pWindowInfo->hacclFrameCommands,
  1637.       pMsg) != 0);
  1638. }
  1639.  
  1640.  
  1641. /* ----------------------------------------------------------------------------
  1642.  * ODFrameThreadProc()                                 *** PRIVATE FUNCTION ***
  1643.  *
  1644.  * Function that execute the OpenDoors frame window thread.
  1645.  *
  1646.  * Parameters: pParam   - The thread parameter, which must be the handle to the
  1647.  *                        current application instance.
  1648.  *
  1649.  *     Return: TRUE on success, or FALSE on failure.
  1650.  */
  1651. DWORD OD_THREAD_FUNC ODFrameThreadProc(void *pParam)
  1652. {
  1653.    HWND hwndFrame;
  1654.    HANDLE hInstance = (HANDLE)pParam;
  1655.  
  1656.    /* Create the frame window. */
  1657.    hwndFrame = ODFrameCreateWindow(hInstance);
  1658.  
  1659.    if(hwndFrame == NULL)
  1660.    {
  1661.       return(FALSE);
  1662.    }
  1663.  
  1664.    /* Store a pointer to the frame window. */
  1665.    hwndCurrentFrame = hwndFrame;
  1666.  
  1667.    /* Loop, processing messages for the frame window. */
  1668.    ODFrameMessageLoop(hInstance, hwndFrame);
  1669.  
  1670.    /* Destroy the frame window. */
  1671.    ODFrameDestroyWindow(hwndFrame);
  1672.  
  1673.    return(TRUE);
  1674. }
  1675.  
  1676.  
  1677. /* ----------------------------------------------------------------------------
  1678.  * ODFrameStart()
  1679.  *
  1680.  * Function that starts up the frame window.
  1681.  *
  1682.  * Parameters: hInstance     - Handle to the current application instance.
  1683.  *
  1684.  *             phFrameThread - Pointer to the frame thread handle.
  1685.  *
  1686.  *     Return: kODRCSuccess on success, or an error code on failure.
  1687.  */
  1688. tODResult ODFrameStart(HANDLE hInstance, tODThreadHandle *phFrameThread)
  1689. {
  1690.    return(ODThreadCreate(phFrameThread, ODFrameThreadProc,
  1691.       (void *)hInstance));
  1692. }
  1693.  
  1694.  
  1695. /* ----------------------------------------------------------------------------
  1696.  * ODFrameMessageDlgProc()
  1697.  *
  1698.  * Dialog proceedure for the OpenDoors message window.
  1699.  *
  1700.  * Parameters: hwndDlg  - Window handle to the dialog box.
  1701.  *
  1702.  *             uMsg     - Message ID.
  1703.  *
  1704.  *             wParam   - First message parameter.
  1705.  *
  1706.  *             lParam   - Second message parameter.
  1707.  *
  1708.  *     Return: TRUE if message is processed, FALSE otherwise.
  1709.  */
  1710. BOOL CALLBACK ODFrameMessageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
  1711.    LPARAM lParam)
  1712. {
  1713.    switch(uMsg)
  1714.    {
  1715.       case WM_INITDIALOG:
  1716.       {
  1717.          tODFrameWindowInfo *pWindowInfo;
  1718.  
  1719.          pWindowInfo = (tODFrameWindowInfo *)lParam;
  1720.  
  1721.          ASSERT(pWindowInfo != NULL);
  1722.  
  1723.          pWindowInfo->hwndMessageWindow = hwndDlg;
  1724.          
  1725.          /* Set the message window title. */
  1726.          SetWindowText(hwndDlg, od_control.od_prog_name);
  1727.  
  1728.          /* Change the text displayed in the message window. */
  1729.          SetWindowText(GetDlgItem(hwndDlg, IDC_MESSAGE_TEXT1),
  1730.             (char *)pWindowInfo->pszCurrentMessage);
  1731.  
  1732.          /* Center window in parent window. */
  1733.          ODFrameCenterWindowInParent(hwndDlg);
  1734.  
  1735.          return(FALSE);
  1736.       }
  1737.  
  1738.       case WM_COMMAND:
  1739.          /* If a command has been chosen. */
  1740.          switch(LOWORD(wParam))
  1741.          {
  1742.             case IDOK:
  1743.                /* If the OK button has been pressed, then close the dialog. */
  1744.                EndDialog(hwndDlg, IDOK);
  1745.                break;
  1746.          }
  1747.          return(TRUE);
  1748.  
  1749.       default:
  1750.          /* Indicate that this message has not been processed. */
  1751.          return(FALSE);
  1752.    }
  1753.  
  1754.    return(TRUE);
  1755. }
  1756.  
  1757.  
  1758. #endif /* ODPLAT_WIN32 */
  1759.