//===============================================================
// vWindow.cpp - vWindow class functions - MSWindows
//
// Copyright (C) 1995,1996,1997,1998  Bruce E. Wampler
//
// This file is part of the V C++ GUI Framework, and is covered
// under the terms of the GNU Library General Public License,
// Version 2. This library has NO WARRANTY. See the source file
// vapp.cxx for more complete information about license terms.
//===============================================================
#include <v/vos2.h>            // for OS/2 stuff
#include <v/vapp.h>            // we are a friend of App
#include <v/vwindow.h>         // our header
#include <v/vpane.h>           // we have panes
#include <v/vcmdpane.h>
#include <v/vmenu.h>
#include <v/vkeys.h>
#include <v/vnotice.h>

  // Frames are subclassed to this procedure
  MRESULT EXPENTRY wpFrameProc(HWND hDlg, ULONG uMsg, MPARAM mp1, MPARAM mp2);
  // this is a temp pointer to the original frame procedure that is subclassed
  PFNWP orgFrameProc;

// Define static data of the class
    int vWindow::_numWindows = 0;
    vWindow* vWindow::_WinList = 0;
    HWND vWindow::_curWin = 0;
    HWND vWindow::_prevWin = 0;

//======================>>> vWindow::vWindow <<<=======================
  vWindow::vWindow(VCONST char *name, int width, int height,
    WindowType wintype ) : vBaseWindow(name)          // constructor
  {
    SysDebug2(Constructor,"vWindow::vWindow(width %d, height %d) constructor\n",
       width, height)
//    _WindowMenuIndex = 0;    // haven't added windows menu yet
    // make handles null
    _menuBar = 0;
    _paneList = 0;          // no panes yet
    _numPanes = 0;
    _CmdPaneList = NULL;    // no command panes registered
    // Set height and width using default if 0 supplied
    _WinHeight = height ? height : theApp->DefaultHeight();
    _WinWidth = width ? width : theApp->DefaultWidth();
    _wType = wintype;
    _NextWin = _WinList;       // link in at top
    _WinList = this;
    _canvasPane = 0;           // no canvas pane yet
    _justActivated = 0;
    _mouseDown = 0;
    _shiftKeyDown = 0;
    _ctrlKeyDown = 0;
    _mouseDrag = -1;
    _createdOK = 0;
    initialize();              // set this guy up
  }
//======================>>> vWindow::vWindow <<<=======================
  vWindow::vWindow(const vWindow& w) :                 // Copy Constructor
    vBaseWindow(w)
  {
    // Copy is shallow, but we track that it is a copy
    vSysError("vWindow - V semantics do not support copy constructors!");
  }

//======================>>> vWindow::~vWindow <<<=======================
  vWindow::~vWindow()                  // destructor
  {
    SysDebug(Destructor,"vWindow::~vWindow destructor\n")

    PaneList* temp;
    for (PaneList* pl = _paneList ; pl != 0 ; )
    {
      temp = pl;
      pl = pl->nextPL;
      delete temp;             // delete the PaneLists we allocated
    }
  }

//======================>>> vWindow::AddPane <<<=======================
  void vWindow::AddPane(vPane* add_pane)
  {
    SysDebug1(Build,"vWindow::AddPane() to %s\n",_name)
    // Add a pane to the window
    PaneList* newPane = new PaneList;  // add a new pane to the list
    newPane->pane = add_pane;          // this is the pane we are adding
    newPane->nextPL = _paneList;       // add new pane in at top
    _paneList = newPane;
    if (add_pane->_paneType == P_Menu) // P_Menu is special
    {
      _menuPane = add_pane;
      add_pane->initialize(this, (HWND)_menuBar);
    }
    else if ((add_pane->_paneType == P_Canvas) ||      // client window PS
        (add_pane->_paneType == P_TextCanvas))
    {
      add_pane->initialize(this, _myClient);  // _myClient is owner
    }
    else
      add_pane->initialize(this, _myClient); // _myClient is owner
  }

//========================>>> vWindow::registerCmdPane <<<======================
  void vWindow::registerCmdPane(vCommandPane* cmdPane)
  {
       SysDebug(Misc,"vWindow::registerCmdPane\n")
       CmdPaneList* newList = new CmdPaneList; // new cell to add to list
       newList->commandPane = cmdPane;         // remember the cmd pane
       newList->nextCPList = _CmdPaneList;             // link in at front
       _CmdPaneList = newList;
       if (cmdPane->_isDisplayed)
         _numPanes++;
  }

//========================>>> vWindow::unregisterCmdPane <<<=======================
  void vWindow::unregisterCmdPane(vCommandPane* cmdPane)
  {
    // Scan pane list to unregister this window and free some space
    CmdPaneList *curCP, *tmp, *last, *next;
    last = 0;
    for (curCP = _CmdPaneList ; curCP !=0 ; curCP = next)
    {
      next = curCP->nextCPList;
      if (curCP->commandPane == cmdPane)
      {
        SysDebug(Misc,"vWindow::unregisterCmdPane\n")
        tmp = curCP;
        if (curCP == _CmdPaneList)
          _CmdPaneList = curCP->nextCPList;
        else
          last->nextCPList = curCP->nextCPList;
        delete tmp;                     // free the list space
        if (cmdPane->_isDisplayed)
          _numPanes--;
      }
      last = curCP;
    }
  }

//========================>>> vWindow::showCmdPane <<<=======================
  void vWindow::showCmdPanes(void)
  {
    CmdPaneList *curCP;
    for (curCP = _CmdPaneList ; curCP !=0 ; curCP = curCP->nextCPList)
    {
      if ( (curCP->commandPane)->_isDisplayed == 0 )
      {
        (curCP->commandPane)->_isDisplayed = 1;
        _numPanes++;
        WinShowWindow((curCP->commandPane)->_wDialog, TRUE);
        AdjustSize(curCP->commandPane);
      }
    }
  }

//======================>>> vWindow::initialize <<<=======================
  void vWindow::initialize(void)
  {
    SysDebug(Build,"vWindow::initialize\n")
    SWP swp;
//    ERRORID _errorCode;
//    HAB _hab = theApp->_hab;
//    _errorCode = WinGetLastError(_hab);

    // define frame window attributes
    ULONG flCreate= FCF_SYSMENU        |        // system menu
                   FCF_TITLEBAR       |        // titlebar
                   FCF_SIZEBORDER     |        // resizeable border
                   FCF_ICON           |        // associate icon
                   FCF_TASKLIST       |        // app name in tasklist
                   FCF_MINMAX;                 // min/max buttons

    // create the frame window
    FRAMECDATA fcData;
    fcData.cb = sizeof(FRAMECDATA);
    fcData.flCreateFlags = flCreate;
    fcData.hmodResources = (HMODULE) NULL;
    fcData.idResources = vID_FRAME;

    _myHwnd = WinCreateWindow(HWND_DESKTOP,       // parent is desktop
                               WC_FRAME,            // window class
                               (PSZ) _name,         // window text
                               0,                   // initially invisible
                               0,0,                 // position
                               0,0,                 // size
                               theApp->_Frame,      // owner
                               HWND_TOP,            // top Z-order
                               vID_FRAME,           // frame ID
                               &fcData,             // frame class data
                               NULL);               // no presentation params


    // Create a menu bar by adding a dummy item then deleting it
    LPMT pmt;
    MTI *pmti;
    pmt = (LPMT) calloc(1, sizeof(MT));
    pmt->len = sizeof(MT);
    pmt->codepage = theApp->_codePage;
    pmt->reserved = 0;
    pmt->cMti = 1;                             // one template item

    pmti=&pmt->rgMti[0];
    pmti->afStyle = MIS_TEXT;
    pmti->pad = 0;
    pmti->idItem = M_Test;              // this is the menu item id
    pmti->c[0] = 0;

    _menuBar = WinCreateMenu(_myHwnd, pmt); // Menu Bar
    free(pmt);

    WinSendMsg(_myHwnd, WM_UPDATEFRAME, MPFROMLONG(FCF_MENU), MPVOID);

    // center and size the window
    // first we need to compute the frame size needed to allow enough space for
    // a client window of the desired size
    RECTL rcl;
    rcl.xLeft = 0;
    rcl.yBottom = 0;
    rcl.xRight = _WinWidth;   // client width
    rcl.yTop = _WinHeight;    // client height

    // compute the frame size to hold desired client
    WinCalcFrameRect(_myHwnd, &rcl, FALSE);

    // find the screen size for the system
    LONG lDisplayWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
    LONG lDisplayHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);

    // set the frame to the computed size and center it on screen
    WinSetWindowPos(_myHwnd,
         HWND_TOP,
         (lDisplayWidth - (rcl.xRight - rcl.xLeft) )/2,
         (lDisplayHeight - (rcl.yTop - rcl.yBottom) )/2,   // x, y
         rcl.xRight - rcl.xLeft,          // width
         rcl.yTop - rcl.yBottom,          // height
         SWP_MOVE | SWP_SIZE | SWP_SHOW | SWP_ACTIVATE);

    // create the client window
    _myClient  = WinCreateWindow(_myHwnd,            // parent
                              (PSZ)szvWindowClass,  // window class
                              NULL,                 // window text
                              WS_CLIPSIBLINGS |
                              FS_NOBYTEALIGN,      // and don't make it initially visible
                              0,0,                  // position
                              0,0,                  // size
                              _myHwnd,              // owner
                              HWND_BOTTOM,          // bottom Z-order
                              FID_CLIENT,           // frame ID
                              (PVOID) this,         // control data
                              NULL);                // no presentation params

    // subclass frame so we can position cmdpanes and client during
    // resize events
    _orgFrameProc = (PVOID) WinSubclassWindow(_myHwnd, wpFrameProc);
    SysDebug2(OS2Dev,"vWindow:initialize framehwnd:%u _orgFrameProc:%u \n",
       _myHwnd, _orgFrameProc);
    WinSetWindowULong(_myHwnd, QWL_USER, (ULONG)this);

    // set size and position of client
    LONG sbx = WinQuerySysValue (HWND_DESKTOP, SV_CXSIZEBORDER);      // x border width
    LONG sby = WinQuerySysValue (HWND_DESKTOP, SV_CYSIZEBORDER);      // y border width

    // Now set the client to the desired size leaving room for the toolbar
    WinSetWindowPos(_myClient,
      HWND_TOP,
      sbx, sby,             // don't forget about the frame edge
      _WinWidth,            // width
      _WinHeight,           // height
      SWP_MOVE | SWP_SIZE );

   // now we delete the dummy menu item
   WinSendMsg(_menuBar, MM_DELETEITEM, MPFROM2SHORT(M_Test, TRUE), MPVOID);

   // update title bar name
   WinSetWindowText(_myClient, _name);

   // save a copy of this in the window structure
   WinSetWindowPtr(_myClient, 0 , this);
   ++_numWindows;              // bump how many windows up
   _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW, TRUE);
   WinSetFocus (HWND_DESKTOP, _myHwnd);
   _createdOK = 1;
   SysDebug2(OS2Dev,"  Frame Handle = %u  Client Handle = %u\n", _myHwnd, _myClient)
  }

//============================>>> vWindow::SetWinCursor <<<==================
  void vWindow::SetWinCursor(VCursor vcursor)
  {
    switch (vcursor)
    {
      case VC_None:
        // _cursor = ::LoadCursor(NULL, IDC_ARROW);
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW, FALSE);
        break;
      case VC_Arrow:
        // _cursor = ::LoadCursor(NULL, IDC_ARROW);
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW, FALSE);
        break;
      case VC_CenterArrow:
        // _cursor = ::LoadCursor(NULL, IDC_UPARROW);
        // OS/2 does not have a single-ended up arrow!!
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_SIZENS, FALSE);
        break;
      case VC_CrossHair:
        // _cursor = ::LoadCursor(NULL, IDC_CROSS);
        // OS/2 does not have a cross!!
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_MOVE, FALSE);
        break;
      case VC_EWArrows:
        // _cursor = ::LoadCursor(NULL, IDC_SIZEWE);
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_SIZEWE, FALSE);
        break;
      case VC_Hand:
        // _cursor = ::LoadCursor(NULL, IDC_ARROW);
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW, FALSE);
        break;
      case VC_IBar:
        // _cursor = ::LoadCursor(NULL, IDC_IBEAM);
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_TEXT, FALSE);
        break;
      case VC_Icon:
        // _cursor = ::LoadCursor(NULL, IDC_ICON);
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_APPICON, FALSE);
        break;
      case VC_NSArrows:
        // _cursor = ::LoadCursor(NULL, IDC_SIZENS);
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_SIZENS, FALSE);
        break;
      case VC_Pencil:
        // _cursor = ::LoadCursor(NULL, IDC_ARROW);
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW, FALSE);
        break;
      case VC_Question:
        // _cursor = ::LoadCursor(NULL, IDC_CROSS);
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_MOVE, FALSE);
        break;
      case VC_Sizer:
        // _cursor = ::LoadCursor(NULL, IDC_SIZE);
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_SIZE, FALSE);
        break;
      case VC_Wait:
        // _cursor = ::LoadCursor(NULL, IDC_WAIT);
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_WAIT, FALSE);
        break;
      case VC_X:
        // _cursor = ::LoadCursor(NULL, IDC_ARROW);
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW, FALSE);
        break;
      default:
        // _cursor = ::LoadCursor(NULL, IDC_ARROW);
        _cursor = WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW, FALSE);
        break;
    }

    WinSetPointer (HWND_DESKTOP, _cursor);
  }

//============================>>> vWindow::CloseWin <<<==========================
  void vWindow::CloseWin(void)
  {
    //   close button class callback
    //
    vWindow* w_list;

    // close base window, which cleans up some stuff
    SysDebug1(Build,"vWindow::CloseWin() - %s.\n",_name)
    closeBaseWindow();         // close this window
    --_numWindows;
    // Remove from active list
    if (_WinList == this)      // first one on list
    {
      _WinList = _WinList->_NextWin; // point to next
    }
    else
    {
      for (w_list = _WinList ; w_list != 0 ; w_list = w_list->_NextWin)
      {
        if (w_list->_NextWin == this)
        {
          // remove from list
          w_list->_NextWin = (w_list->_NextWin)->_NextWin;
          break;
        }
      }
    }
    WinDestroyWindow(WinQueryWindow(_myClient, QW_PARENT));
  }

//======================>>> vWindow::ShowPane <<<=======================
  void vWindow::ShowPane(vPane* wpane, int OnOrOff) VCONST
  {
    // Show or hide this pane
    // Search all panes until we find this one
    for (PaneList* pl = _paneList ; pl != 0 ; pl = pl->nextPL)
    {
      if (pl->pane == wpane)
      {
        (pl->pane)->ShowPane(OnOrOff); // let each pane show hide
        return;
      }
    }
    return;
  }

//====================>>> vWindow::GetValue <<<======================
  int vWindow::GetValue(ItemVal id) VCONST
  {
    // scan all buttons in this window to retrieve the what value
    int retval = 0;            // default to 0
    // Search all panes until we find this id
    for (PaneList* pl = _paneList ; pl != 0 ; pl = pl->nextPL)
    {
      if ((pl->pane)->GetPaneValue(id, retval))
      {
        return retval;
      }
    }
    return 0;
  }

//=========================>>> vWindow::KeyIn <<<==========================
  void vWindow::KeyIn(vKey keysym, unsigned int shift)
  {
    // General interface to a keyboard event
    theApp->KeyIn(this, keysym, shift); // pass on unprocessed keys to app
  }

//=======================>>> vWindow::KeyInEV <<<==========================
  MRESULT vWindow::KeyInEV(USHORT KeyFlags, USHORT AscChar, USHORT VirtKey)
  {
    // Local interface to a keyboard event

    unsigned int WinCodes[] =
    {
      VK_BACKSPACE, VK_TAB, VK_NEWLINE, VK_ENTER, VK_PAUSE,
      VK_ESC, VK_BACKTAB,
      VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN,
      VK_PAGEUP,VK_PAGEDOWN, VK_END, VK_INSERT, VK_DELETE,
      VK_F1, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7,
      VK_F8, VK_F9, VK_F10, VK_F11, VK_F12, VK_F13,
      VK_F14, VK_F15, VK_F16, 0
    };
    unsigned int vCodes[] =
    {
      vk_BackSpace, vk_Tab, vk_Linefeed, vk_Return, vk_Pause,
      vk_Escape, vk_BackTab,
      vk_Home, vk_Left, vk_Up, vk_Right, vk_Down,
      vk_Page_Up, vk_Page_Down, vk_End, vk_Insert, vk_Delete,
      vk_F1, vk_F2,vk_F3, vk_F4, vk_F5, vk_F6, vk_F7,
      vk_F8, vk_F9,vk_F10, vk_F11, vk_F12, vk_F13,
      vk_F14, vk_F15, vk_F16, 0
    };
    ItemVal id;
    vKey vkey;
    int shift = 0;

    if (KeyFlags & KC_SHIFT)
      shift |= VKM_Shift;

    if (KeyFlags & KC_CTRL)
      shift |= VKM_Ctrl;

    if (KeyFlags & KC_ALT)
      shift |= VKM_Alt;

    // we check if its an ascii character key
    // that does not require mapping
    if (KeyFlags & KC_CHAR)
    {
      vkey = AscChar;
    }
    // control keys must be handled differently
    // translate control characters to the actual ASCII values
    else if (KeyFlags &  KC_SCANCODE && KeyFlags & KC_CTRL )
    {
      if(!AscChar)
        return(0);
      else if (AscChar >= 'a' &&  AscChar <= 'z' )
        vkey = AscChar - '`';
      else if (AscChar >= 'A' &&  AscChar <= 'Z' )
        vkey = AscChar - '@';
      else
        vkey = AscChar;

      if (vkey < ' ')
        shift &= VKM_Shift;     // Kill VKM_Ctrl for real control chars
    }
    else if (KeyFlags &  KC_SCANCODE && KeyFlags & KC_ALT )
    {
      if(!AscChar)
        return(0);
      vkey = AscChar;
    }
    else  // must be a virtual key
    {
      int ix;
      for (ix = 0 ; WinCodes[ix] != 0 ; ++ix)
      {
        if (WinCodes[ix] == VirtKey)
        {
          vkey = vCodes[ix];
          break;
        }
      }
      if (WinCodes[ix] == 0)  // Ignore keys with no mapping
        return (FALSE);
    }

    // finish off with some special cases...
    // V defines a shift-tab virtual key
    if (vkey == vk_Tab && (shift | VKM_Shift) != 0)
      vkey = vk_BackTab;

    // check if key is a menu accelerator, or just regular input
    if (((vMenuPane*)_menuPane)->CheckAccel(vkey, shift, id))
      MenuCommand(id);
    else
      KeyIn(vkey,shift);      // pass on to general code

    return (MRESULT) TRUE;
  }

//======================>>> vWindow::MenuCommand <<<==========================
  void vWindow::MenuCommand(ItemVal id)
  {
    // Menu Commands go through here first, then the regular WindowCommand

    WindowCommand(id, id, C_Menu);
  }

//==================>>> vWindow::SetValue <<<========================
  void vWindow::SetValue(ItemVal id, int val, ItemSetType setType)
  {
    // Set the given item on or off
    for (PaneList* pl = /* w_list->*/ _paneList ; pl != 0 ; pl = pl->nextPL)
    {
      (pl->pane)->SetPaneValue(id, val, setType);
    }
  }

//==================>>> vWindow::SetValueAll <<<========================
  void vWindow::SetValueAll(ItemVal id, int val, ItemSetType setType)
  {
    // Set the given item on or off in all windows

    // search all windows to set all buttons
    for (vWindow* w_list = _WinList ; w_list != 0 ; w_list = w_list->_NextWin)
    {
      // in each window, search each pane list
      for (PaneList* pl = /* w_list->*/ _paneList ; pl != 0 ; pl = pl->nextPL)
      {
        (pl->pane)->SetPaneValue(id, val, setType);
      }
    }
  }

//================>>> vWindow::GetPosition <<<========================
  void vWindow::GetPosition(int& left, int& top, int& width, int& height) VCONST
  {
    // We give the total width of frame including controls
    // here.  If you need just the canvas dimensions then use
    // canvas->GetHeight and canvas->GetWidth

    RECTL rct;
    WinQueryWindowRect (_myHwnd, &rct);
    WinMapWindowPoints (_myHwnd ,HWND_DESKTOP, (PPOINTL) &rct, 2);
    LONG DisplayHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);

    // in OS/2 the origin is at the bottom left corner whereas V has the
    // origin in the top left corner.  We need to transform coords from
    // os/2 to V space to get the right results
    // CAUTION: WinQuery return rc coords are inclusive/exclusive
    top = (DisplayHeight-1) - rct.yTop;
    left = rct.xLeft;
    width = rct.xRight - rct.xLeft;
    height = rct.yTop - rct.yBottom;
  }

//================>>> vWindow::SetPosition <<<========================
  void vWindow::SetPosition(int left, int top)
  {
    // the args must specify the location of the frame window
    // not the client window

    RECTL ar;
    WinQueryWindowRect (_myHwnd, &ar);
    int height =  ar.yTop - ar.yBottom;
    LONG DisplayHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);

    // in OS/2 the origin is at the bottom left corner whereas V has the
    // origin in the top left corner.  We need to transform coords from
    // V to os/2 space to get the right results
    top = (DisplayHeight-1) - top;

    // CAUTION: WinSetWindowPos rc coords are inclusive/exclusive
    //          and use the bottom left corner
    int bottom = top - height;

    WinSetWindowPos (_myHwnd,HWND_TOP,
      left,bottom,
      0,0,
      SWP_MOVE);
  }

//================>>> vWindow::RaiseWindow <<<========================
  void vWindow::RaiseWindow(void)
  {
    // raise this window to the top of all other windows
    WinSetWindowPos(_myHwnd,HWND_TOP, 0, 0, 0, 0, SWP_ZORDER | SWP_ACTIVATE);
  }

//================>>> vWindow::SetString <<<========================
  void vWindow::SetString(ItemVal id, VCONST char* str)
  {
    // search all buttons in this windows to set to correct value
    for (PaneList* pl = /* w_list->*/ _paneList ; pl != 0 ; pl = pl->nextPL)
    {
      (pl->pane)->SetPaneString(id, str);
    }
  }

//================>>> vWindow::SetStringAll <<<========================
  void vWindow::SetStringAll(ItemVal id, VCONST char* str)
  {
    // search all buttons in all windows to set to correct value
    for (vWindow* w_list = _WinList ; w_list != 0 ; w_list = w_list->_NextWin)
    {
      // in each window, search each pane list
      for (PaneList* pl = /* w_list->*/ _paneList ; pl != 0 ; pl = pl->nextPL)
      {
        (pl->pane)->SetPaneString(id, str);
      }
    }
  }

//======================>>> vWindow::SetTitle <<<==========================
  void vWindow::SetTitle(VCONST char* title)
  {
    // set the title in the title bar
    WinSetWindowText(_myHwnd, title);
  }

//======================>>> vWindow::UpdateView <<<========================
  void vWindow::UpdateView(vWindow* sender, int hint, void* pHint)
  {
    // This is the overridable function called by the framwork to take
    // action on changes which happened in the model (document).
    //
    //     sender: Hint on which window caused the change in model
    //     hint:   Enum defined in your derived app class.
    //             Hints about which kind of change is made, so that only
    //             appropriate action is taken on appropriate windows.
    //     pHint:  This is normally a pointer to a object representing the
    //             document, or part of it.  If the App has multiple open
    //             documents, and multiple views for each document, a
    //             typical use is to update only the views for the
    //             document, except the sender's.
  }

//======================>>> vWindow::WindowCommand <<<==========================
  void vWindow::WindowCommand(ItemVal id, ItemVal retval, CmdType ctype)
  {
    SysDebug1(CmdEvents,"vWindow::WindowCommand(id: %d)\n",id)
    theApp->AppCommand(this, id, retval, ctype); // Pass unprocessed cmds to app
  }

//======================>>> vWindow::AdjustSize <<<==========================
  void vWindow::AdjustSize(vCommandPane* cmdPane)
  {
    // This is called whenever a status bar or command pane
    // is added to or removed from the frame or its visibility changes.
    SWP FrameSWP;

    // find the SWP for the frame window SWP
    WinQueryWindowPos(_myHwnd, &FrameSWP);

    SysDebug1(OS2Dev,"vWindow::AdjustSize height:%u \n", FrameSWP.cy + cmdPane->_windowH)

    // now change frame size for new pane so that client stays same size
    if ( cmdPane->_isDisplayed)
      WinSetWindowPos(_myHwnd, HWND_TOP, 0,0, FrameSWP.cx,
        FrameSWP.cy + cmdPane->_windowH, SWP_SIZE);
    // else pane is now hidden so shrink pane
    else
      WinSetWindowPos(_myHwnd, HWND_TOP, 0,0, FrameSWP.cx,
        FrameSWP.cy - cmdPane->_windowH, SWP_SIZE);

/*
    SWP ClientSWP, MenuSWP;

    // find the SWP for the client window SWP
    WinQueryWindowPos(_myClient, &ClientSWP);

    // find the SWP for the client window SWP
    WinQueryWindowPos(WinWindowFromID(_myHwnd, FID_MENU), &MenuSWP);

    // CAUTION: all coords in SWP are relative to frame origin
    WinQueryWindowRect(_myClient, &rc);          // the Client space we have

    int topY = pSWP[usClient].y + rc.yTop-rc.yBottom; // Need to track space used by
    int botY = pSWP[usClient].y;                      // cmd bars and status bars

    SysDebug3(OS2Dev,"WM_FORMATFRAME: itemCount:%u botY:%u topY:%u \n",
      itemCount, botY, topY);

    // now we need to fix up the sizes so that the cmd panes go at the

    // top and the status panes at the bottom with the client in the middle

    for (curCPL = _CmdPaneList ; curCPL != 0 ; curCPL = curCPL->nextCPList)

    {
      cp = curCPL->commandPane;      // pointer to CommandPane
      if (cp->_isShown && cp->_isDisplayed && WinIsWindow(theApp->AppCP(), cp->HwndDialog())
        && WinIsWindowVisible(cp->HwndDialog()))
      {
        if (cp->paneType() != P_Status)        // Cmd bar
        {
          pSWP[itemCount].hwnd = cp->HwndDialog();      // Window handle
          pSWP[itemCount].hwndInsertBehind = HWND_TOP ; // On which window (ONTOP)
          pSWP[itemCount].fl = SWP_SIZE | SWP_MOVE;     // SWP_SIZE style flag
          pSWP[itemCount].cy = cp->_windowH;            // height is fixed
          pSWP[itemCount].cx = pSWP[usMenu].cx ;        // width is menu width
          pSWP[itemCount].x  = pSWP[usClient].x ;       // XPOS in FRAME

          // YPOS in FRAME
          topY -= cp->_windowH;
          cp->_windowY = topY;
          pSWP[itemCount].y  = topY;
          // adjust client window size
          // If not, the client window will ovelap pane
          pSWP[usClient].cy= pSWP[usClient].cy - pSWP[itemCount].cy;
          SysDebug3(OS2Dev,"   added cmdP hwnd:%u at topY:%u _windowH:%u \n",
            cp->HwndDialog(), topY, cp->_windowH);

        }                                      // Status bar
        else
        {
          pSWP[itemCount].hwnd = cp->HwndDialog();      // Window handle
          pSWP[itemCount].fl = SWP_SIZE | SWP_MOVE;     // SWP_SIZE style flag
          pSWP[itemCount].cy = cp->_windowH;            // height is fixed
          pSWP[itemCount].cx = pSWP[usMenu].cx ;        // width is menu width
          pSWP[itemCount].x  = pSWP[usClient].x ;       // XPOS in FRAME

          // YPOS in FRAME
          botY += cp->_windowH;
          cp->_windowY = botY;
          pSWP[itemCount].y  = botY;
          pSWP[itemCount].hwndInsertBehind = HWND_TOP ; // On which window (ONTOP)

          // adjust client window size
          // If not, the client window will ovelap pane

          pSWP[usClient].cy= pSWP[usClient].cy - pSWP[itemCount].cy;
          pSWP[usClient].y= pSWP[usClient].y + pSWP[itemCount].cy;
        }
          itemCount--;   // decrement to next free pane SWP
      } // if
    } // for
*/
  }

//===================>>> vWindow::WindowProc <<<=============================
  long vWindow::vWindowProc(HWND hWnd, ULONG message, MPARAM mp1, MPARAM mp2)
  {
/*
    if (message == WM_INITDLG)
      return TRUE;
*/
    switch (message)
    {
      case WM_CREATE:
      {
        return FALSE;
      }

      case WM_PAINT:
      {
        if (_canvasPane)
        {
          _canvasPane->ExposeEV();
          return 0;
        }
        // else pass to default procedure to validate the
        // region so the WM_PAINT message goes away
        break;
      }

      case WM_SIZE:
      {
        int width = SHORT1FROMMP( mp2 );
        int height = SHORT2FROMMP( mp2 );
        if (_canvasPane)
          _canvasPane->ResizeEV(width, height);
        break;                      // MUST also do default processing!
      }

      //  Mouse Numbering Scheme
      //  V   OS/2    Windows
      //  1   1       L
      //  2   3       M
      //  3   2       R
      case WM_BUTTON2DOWN:      // Right mouse down
      {
        // we need to convert the mouse coords which are in Device Space
        // to World Space since V interface is in World Space
        POINTL pt;
        pt.x = (int) SHORT1FROMMP(mp1);
        pt.y = (int) SHORT2FROMMP(mp1);
        if (_canvasPane)
        {
//          SysDebug3(MouseEvents,"vWindow::WM_BUTTON2DOWN:(x:%d,y:%d,btn:%d)\n",
//            pt.x, pt.y, 3)
//	  GpiConvert((_canvasPane->_cpDC)->handleDC(), CVTC_DEVICE, CVTC_WORLD, 1, &pt);
          (_canvasPane->_cpDC)->MapFromOS2(&pt);
//          SysDebug3(MouseEvents,"     after conversion (x:%d,y:%d,btn:%d)\n",
//            pt.x, pt.y, 3)
          _canvasPane->MouseDown(pt.x, pt.y, 3);
        }
        return 0;
      }

      case WM_BUTTON2UP:      // Right mouse up
      {
        // we need to convert the mouse coords which are in Device Space
        // to World Space since V interface is in World Space
        POINTL pt;
        pt.x = (int) SHORT1FROMMP(mp1);
        pt.y = (int) SHORT2FROMMP(mp1);
        if (_canvasPane)
        {
//          SysDebug3(MouseEvents,"vWindow::WM_BUTTON2UP:(x:%d,y:%d,btn:%d)\n",
//            pt.x, pt.y, 3)
//	  GpiConvert((_canvasPane->_cpDC)->handleDC(), CVTC_DEVICE, CVTC_WORLD, 1, &pt);
          (_canvasPane->_cpDC)->MapFromOS2(&pt);

//          SysDebug3(MouseEvents,"     after conversion (x:%d,y:%d,btn:%d)\n",
//            pt.x, pt.y, 3)
          _canvasPane->MouseUp(pt.x, pt.y, 3);
        }
        return 0;
      }

      case WM_BUTTON2DBLCLK:  // Right double click
      {
        // int x = (int) SHORT1FROMMP(mp1);
        // int y = (int) SHORT2FROMMP(mp1);
        break;
      }

      case WM_BUTTON3DOWN:    // middle button
      {
        // we need to convert the mouse coords which are in Device Space
        // to World Space since V interface is in World Space
        POINTL pt;
        pt.x = (int) SHORT1FROMMP(mp1);
        pt.y = (int) SHORT2FROMMP(mp1);
        if (_canvasPane)
        {
//          SysDebug3(MouseEvents,"vWindow::WM_BUTTON3DOWN:(x:%d,y:%d,btn:%d)\n",
//            pt.x, pt.y, 2)
//	  GpiConvert((_canvasPane->_cpDC)->handleDC(), CVTC_DEVICE, CVTC_WORLD, 1, &pt);
          (_canvasPane->_cpDC)->MapFromOS2(&pt);
//          SysDebug3(MouseEvents,"     after conversion (x:%d,y:%d,btn:%d)\n",
//            pt.x, pt.y, 2)
          _canvasPane->MouseDown(pt.x, pt.y, 2);
        }
        return 0;
      }

      case WM_BUTTON3UP:      // middle button
      {
        // we need to convert the mouse coords which are in Device Space
        // to World Space since V interface is in World Space
        POINTL pt;
        pt.x = (int) SHORT1FROMMP(mp1);
        pt.y = (int) SHORT2FROMMP(mp1);
        if (_canvasPane)
        {
//          SysDebug3(MouseEvents,"vWindow::WM_BUTTON3UP:(x:%d,y:%d,btn:%d)\n",
//            pt.x, pt.y, 2)
//	  GpiConvert((_canvasPane->_cpDC)->handleDC(), CVTC_DEVICE, CVTC_WORLD, 1, &pt);
          (_canvasPane->_cpDC)->MapFromOS2(&pt);
//          SysDebug3(MouseEvents,"     after conversion (x:%d,y:%d,btn:%d)\n",
//            pt.x, pt.y, 2)
          _canvasPane->MouseUp(pt.x, pt.y, 2);
        }
        return 0;
      }

      case WM_BUTTON3DBLCLK:   // middle button
      {
        // int x = (int) SHORT1FROMMP(mp1);
        // int y = (int) SHORT2FROMMP(mp1);
        break;
      }

      case WM_BUTTON1DOWN:    // Left mouse down
      {
/*
        // We want this to work like X. The first click in an MDI window
        // without focus changes focus, AND sends the LBUTTONDOWN message.
        // We don't want the focus message to go to the application, so
        // this kludgy code prevents the focus click from heading to the
        // canvas...
        if (_justActivated  && _prevWin != 0)
        {
          _justActivated = 0;
          break;
        }
*/
        // we want a click on the client to bring the app to the top
        if (WinQueryFocus(HWND_DESKTOP) != hWnd)
          WinFocusChange(HWND_DESKTOP, hWnd, 0);
        // we need to convert the mouse coords which are in Device Space
        // to World Space since V interface is in World Space
        POINTL pt;
        pt.x = (int) SHORT1FROMMP(mp1);
        pt.y = (int) SHORT2FROMMP(mp1);
        _mouseDown = 1;
        if (_canvasPane)
        {
//          SysDebug3(MouseEvents,"vWindow::WM_BUTTON1DOWN:(x:%d,y:%d,btn:%d)\n",
//            pt.x, pt.y, 1)
//	  GpiConvert((_canvasPane->_cpDC)->handleDC(), CVTC_DEVICE, CVTC_WORLD, 1, &pt);
          (_canvasPane->_cpDC)->MapFromOS2(&pt);

//          SysDebug3(MouseEvents,"     after conversion (x:%d,y:%d,btn:%d)\n",
//            pt.x, pt.y, 1)
          _canvasPane->MouseDown(pt.x, pt.y, 1);
        }
        return 0;
      }

      case WM_BUTTON1UP:         // Left mouse
      {
        // we need to convert the mouse coords which are in Device Space
        // to World Space since V interface is in World Space
        POINTL pt;
        pt.x = (int) SHORT1FROMMP(mp1);
        pt.y = (int) SHORT2FROMMP(mp1);
        if (_mouseDown && _canvasPane)
        {
//          SysDebug3(MouseEvents,"vWindow::WM_BUTTON1UP:(x:%d,y:%d,btn:%d)\n",
//            pt.x, pt.y, 1)
//	  GpiConvert((_canvasPane->_cpDC)->handleDC(), CVTC_DEVICE, CVTC_WORLD, 1, &pt);
          (_canvasPane->_cpDC)->MapFromOS2(&pt);

//          SysDebug3(MouseEvents,"     after conversion (x:%d,y:%d,btn:%d)\n",
//            pt.x, pt.y, 1)
          _canvasPane->MouseUp(pt.x, pt.y, 1);
        }
        _mouseDown = 0;
        return 0;
      }

      case WM_BUTTON1DBLCLK:        // Left mouse
      {
        // int x = (int) SHORT1FROMMP(mp1);
        // int y = (int) SHORT2FROMMP(mp1);
        break;
      }

      case WM_BUTTON1MOTIONSTART:     // start left button drag
      {
        _mouseDrag = 1;
        return 0;
      }

      case WM_BUTTON1MOTIONEND:       // end left button drag
      {
        _mouseDrag = -1;
        return 0;
      }

      case WM_BUTTON2MOTIONSTART:     // start right button drag
      {
        _mouseDrag = 3;
        return 0;
      }

      case WM_BUTTON2MOTIONEND:       // end right button drag
      {
        _mouseDrag = -1;
        return 0;
      }

      case WM_BUTTON3MOTIONSTART:     // start middle button drag
      {
        _mouseDrag = 2;
        return 0;
      }

      case WM_BUTTON3MOTIONEND:       // end middle button drag
      {
        _mouseDrag = -1;
        return 0;
      }

      case WM_MOUSEMOVE:      // Mouse move
      {
        // we need to convert the mouse coords which are in Device Space
        // to World Space since V interface is in World Space
        POINTL pt;
        pt.x = (int) SHORT1FROMMP(mp1);
        pt.y = (int) SHORT2FROMMP(mp1);
        WinSetPointer (HWND_DESKTOP, _cursor);
        // To make this work like the X version, we don't want any mouse
        // motion unless a button is down.
        if (_mouseDrag < 0)
        {
          if (_canvasPane)
          {
//	    GpiConvert((_canvasPane->_cpDC)->handleDC(), CVTC_DEVICE, CVTC_WORLD, 1, &pt);
            (_canvasPane->_cpDC)->MapFromOS2(&pt);

//            SysDebug2(MouseEvents,"vWindow::WM_MOUSEMOVE:(x:%d,y:%d)\n",
//              pt.x, pt.y)
            _canvasPane->MouseMotion(pt.x, pt.y);
          }
          else
            break;
        }
        else if (_canvasPane)
        {
//	  GpiConvert((_canvasPane->_cpDC)->handleDC(), CVTC_DEVICE, CVTC_WORLD, 1, &pt);
          (_canvasPane->_cpDC)->MapFromOS2(&pt);

//          SysDebug2(MouseEvents,"vWindow::WM_MOUSEMOVE:(x:%d,y:%d)\n",
//            pt.x, pt.y)
          _canvasPane->MouseMove(pt.x, pt.y, _mouseDrag);
        }
        return 0;
      }

      case WM_DESTROY:
      {
//      return 0;
        break;
      }

      case WM_COMMAND:
      {
        USHORT id = SHORT1FROMMP(mp1);
//      USHORT source = SHORT1FROMMP(mp2);
        MenuCommand((ItemVal)id);
        return 0;
      }

      // short1(mp1) key flag
      // char3(mp1)  repeat count
      // char4(mp1)  raw scan code
      // short1(mp2) character code
      // short2(mp2) virtual key code
      case WM_CHAR:
      {
        USHORT KeyFlags = SHORT1FROMMP(mp1);
        if (!(KeyFlags & KC_KEYUP))   // only want keydown event
        {
//SysDebug3(OS2Dev,"wpWindowProc:  WM_CHAR kflag=%x charcode=%x vkcode=%x\n",
//  SHORT1FROMMP(mp1), SHORT1FROMMP(mp2), SHORT2FROMMP(mp2))

          // we throw away key events involving just pressing the
          // shift, alt, or ctrl keys by themselves
          if (KeyFlags & KC_VIRTUALKEY)
          {
            if (SHORT2FROMMP(mp2) == VK_SHIFT || SHORT2FROMMP(mp2) == VK_ALT ||
              SHORT2FROMMP(mp2) == VK_CTRL )
            break;                            // throw away event
          }
          //                                 char code       virtual key code
          return (long) KeyInEV(KeyFlags, SHORT1FROMMP(mp2), SHORT2FROMMP(mp2));
        }
        break;
      }

      // window id  short1(mp1)
      // position   short1(mp2)
      // command    short2(mp2)
      case WM_HSCROLL:
      {
        if (_canvasPane)
          _canvasPane->HScrollEV(SHORT2FROMMP(mp2),
            SHORT1FROMMP(mp2), hWnd);
        return 0;
      }

      case WM_VSCROLL:
      {
        if (_canvasPane)
          _canvasPane->VScrollEV(SHORT2FROMMP(mp2),
            SHORT1FROMMP(mp2), hWnd);
        return 0;
      }

      case WM_FOCUSCHANGE:
      case WM_SETFOCUS:
      {
        int focus = SHORT1FROMMP(mp2);
        if (focus)               // we are gaining focus!
        {
          if (theApp->InExit())
            break;

	  // from v1.20 windoze code
	  if (theApp->ClipboardCheckText())
	    theApp->SetValueAll(M_Paste,1,Sensitive);
	  else
	    theApp->SetValueAll(M_Paste,0,Sensitive);

	  if (_canvasPane)
          {
            _canvasPane->EnterEV();
          }
        }
        else                        // we are losing focus
        {
          if (_canvasPane)
          {
            _canvasPane->LeaveEV();
          }
        }
//        return 0;
        break;
      }

      // Near as I can tell, WM_ACTIVATE is sent when the process
      // is activated and keyboard/mouse inputs are changed.  This is
      // different from gaining focus because that is sent only
      // when a msg queue focus change occurs, and can miss events
      // where the use selects a command bar or some other piece of
      // the application which is not the client window and which activates
      // the app but does not result in the client receiving focus.
      case WM_ACTIVATE:
      {
        int activate= SHORT1FROMMP(mp1);     // WM_ACTIVATE

        if (activate)               // we are activating!
        {
          if (theApp->InExit())
            break;
          _prevWin = _curWin;
          _curWin = hWnd;
          _justActivated = 1;
          if (_canvasPane)
          {
            _canvasPane->EnterEV();
          }
        }
        else                        // we are de-activating
        {
          if (_canvasPane)
          {
            _canvasPane->LeaveEV();
          }
        }
//        return 0;
        break;
      }

      case DM_DROP:
      {
	break;
      }

      case WM_ERASEBACKGROUND:  // when resized
      {
	return 1;
      }

// WM_SAVEAPPLICATION gets posted by WinDestroyWindow so
// need to avoid recursively calling CloseWin here
/*
      case WM_SAVEAPPLICATION:
      {
        CloseWin();
        return 0;
      }
*/
      case WM_CLOSE:
      {
        theApp->CloseAppWin(this);
        return 0;
      }

      default:
        break;
    }
    if (theApp->InExit())
      return 0;    // BEW: fix for 1.17
    return (long) WinDefWindowProc(hWnd, message, mp1, mp2 );
  }

//===================>>> vWindow::wpFrameProc <<<=============================
  MRESULT EXPENTRY wpFrameProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  {
    vWindow* thisWin = (vWindow*) WinQueryWindowULong( hwnd, QWL_USER ); // Pointer from window word
    if (!thisWin)
    {
      return (MRESULT) WinDefWindowProc(hwnd, msg, mp1, mp2);
    }
    else
      return (MRESULT) thisWin->vFrameProc(hwnd, msg, mp1, mp2);
  }

//===================>>> vWindow::vFrameProc <<<=============================
  MRESULT vWindow::vFrameProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  {
    // set the original frame procedure
    // SysDebug(OS2Dev,"vWindow::vFrameProc\n")
    orgFrameProc = (PFNWP) _orgFrameProc;
    switch (msg)
    {
      case WM_QUERYFRAMECTLCOUNT:
      {
        USHORT   itemCount;

        //count frame controls
        itemCount = SHORT1FROMMR(orgFrameProc(hwnd,msg,mp1,mp2));

        SysDebug3(OS2Dev,"WM_QUERYFRAMECTLCOUNT: orgFrameProc:%u  itemCount:%u _numPanes:%u \n",
          orgFrameProc, itemCount, _numPanes );
        return (MRFROMSHORT(itemCount + _numPanes)); // add in our cmd panes
      }

      // This is called whenever the Frame is resized, or when the state of
      // a status bar or command pane changes
      case WM_FORMATFRAME :
      {
        RECTL rc;
        vCommandPane* cp;
        CmdPaneList *curCPL;
        USHORT usClient = 0, usMenu = 0;
        USHORT usHScroll = 0, usVScroll = 0;
        USHORT itemCount = SHORT1FROMMR(orgFrameProc( hwnd, msg, mp1, mp2 ));
        USHORT itemIndex = itemCount;
        PSWP pSWP = (PSWP) PVOIDFROMMP(mp1);      // start of SWP array

        // find the index for the client window SWP
        while (pSWP[usClient].hwnd != WinWindowFromID(_myHwnd, FID_CLIENT))
         ++usClient;

        // find the index for the menu bar SWP
        while (pSWP[usMenu].hwnd != WinWindowFromID(_myHwnd, FID_MENU))
          ++usMenu;

        // find the index, if any, for the horizontal scrollbar SWP
        // this may not exist, so we have to be careful here
        for (USHORT index = 0; index < itemCount; index++)
        {
          if (pSWP[index].hwnd == WinWindowFromID(_myHwnd, FID_HORZSCROLL))
          {
            usHScroll = index;
            break;
          }
        }

        // CAUTION: all coords in SWP are relative to frame origin
        int topY = pSWP[usClient].y + pSWP[usClient].cy;  // Need to track space used by
        int botY = pSWP[usClient].y;                      // cmd bars and status bars

//        SysDebug3(OS2Dev,"WM_FORMATFRAME: itemCount:%u botY:%u topY:%u \n",
//          itemCount, botY, topY);

        // now we need to fix up the sizes so that the cmd panes go at the
        // top and the status panes at the bottom with the client and
        // scroll bars, if any, in the middle
        for (curCPL = _CmdPaneList ; curCPL != 0 ; curCPL = curCPL->nextCPList)
        {
          cp = curCPL->commandPane;      // pointer to CommandPane
//        if (cp->_isDisplayed && WinIsWindow(theApp->AppCP(), cp->HwndDialog())
//          && WinIsWindowVisible(cp->HwndDialog()))
          if (cp->_isDisplayed && WinIsWindow(theApp->AppCP(), cp->HwndDialog()))
          {
            if (cp->paneType() != P_Status)     // Cmd bar
            {
              pSWP[itemIndex].hwnd = cp->HwndDialog();      // Window handle
              pSWP[itemIndex].hwndInsertBehind = HWND_TOP ; // On which window (ONTOP)
              pSWP[itemIndex].fl = SWP_SIZE | SWP_MOVE | SWP_SHOW;     // SWP_SIZE style flag
              pSWP[itemIndex].cy = cp->_windowH;            // height is fixed
              pSWP[itemIndex].cx = pSWP[usMenu].cx ;        // width is menu width
              pSWP[itemIndex].x  = pSWP[usMenu].x ;           // XPOS in FRAME
              // YPOS in FRAME
              topY -= cp->_windowH;
              cp->_windowY = topY;
              pSWP[itemIndex].y  = topY;
              // adjust client window size
              // If not, the client window will overlap pane
              pSWP[usClient].cy= pSWP[usClient].cy - pSWP[itemIndex].cy;
//              cp->_isShown = 1;
//              SysDebug3(OS2Dev,"   positioned cmdP hwnd:%u at topY:%u _windowH:%u \n",
//                cp->HwndDialog(), topY, cp->_windowH);
            }
            else                                // Status bar
            {
              pSWP[itemIndex].hwnd = cp->HwndDialog();      // Window handle
              pSWP[itemIndex].fl = SWP_SIZE | SWP_MOVE | SWP_SHOW;     // SWP_SIZE style flag
              pSWP[itemIndex].hwndInsertBehind = HWND_TOP ; // On which window (ONTOP)
              pSWP[itemIndex].cy = cp->_windowH;            // height is fixed
              pSWP[itemIndex].cx = pSWP[usMenu].cx ;        // width is menu width
              pSWP[itemIndex].x  = pSWP[usMenu].x ;       // XPOS in FRAME
              // YPOS in FRAME
              pSWP[itemIndex].y  = botY;
              cp->_windowY = botY;
              botY += cp->_windowH;
              // if there is a horizontal scroll bar, we need to shift the
              // status pane down by the scroll bar height since the frame
              // really badly wants to put the scroll bar at the bottom and
              // we must use all our powers to stop it! :-)
              if (usHScroll != 0)
                pSWP[itemIndex].y -= pSWP[usHScroll].cy;
              // adjust client window size
              // If not, the client window will overlap pane
              pSWP[usClient].cy= pSWP[usClient].cy - pSWP[itemIndex].cy;
              pSWP[usClient].y= pSWP[usClient].y + pSWP[itemIndex].cy;
//              cp->_isShown = 1;
//              SysDebug3(OS2Dev,"   positioned statP hwnd:%u at topY:%u _windowH:%u \n",
//                cp->HwndDialog(), topY, cp->_windowH);
            }
            itemIndex++;   // point to next free pane SWP
          } // if
        } // for

        // now we adjust the size of the scroll bars so they fit around
        // the smaller client size

        // find the index for the vertical scrollbar SWP
        for (usVScroll = 0; usVScroll < itemCount; usVScroll++)
        {
          if (pSWP[usVScroll].hwnd == WinWindowFromID(_myHwnd, FID_VERTSCROLL))
          {
            // found it!  Now make it the client height and position
            pSWP[usVScroll].cy = pSWP[usClient].cy;
            pSWP[usVScroll].y = pSWP[usClient].y;
            // if a horizontal bar also exists, then we need to make
            // the vertical bar a little longer to fill in the dead space
            // square that forms at the junction of the two scroll bars
            if (usHScroll != 0)
            {
              pSWP[usVScroll].cy += pSWP[usHScroll].cy;
              pSWP[usVScroll].y -= pSWP[usHScroll].cy;
            }
            SysDebug2(OS2Dev,"   positioned VScroll cy:%u at y:%u \n",
              pSWP[usVScroll].cy, pSWP[usVScroll].y);
            break;
          }
        }

        // if a horizontal scrollbar exists, move it above the status pane(s)
        // and below the client
        if (usHScroll != 0)
        {
          pSWP[usHScroll].y = pSWP[usClient].y - pSWP[usHScroll].cy;

          SysDebug2(OS2Dev,"   positioned HScroll cy:%u at y:%u \n",
            pSWP[usHScroll].cy, pSWP[usHScroll].y);
        }

        // return total count of frame controls
        itemCount += _numPanes;

        SysDebug2(OS2Dev,"WM_FORMATFRAME: itemCount:%u _numPanes:%u \n",
          itemCount, _numPanes);

        return( MRFROMSHORT(itemCount));
      }
      default: // Handling other messages
        return (MRESULT) orgFrameProc(hwnd,msg,mp1,mp2);
    }
  }

