/*
 * Video subsystem for Windows using GUI windows instead of Console
 * with multiple windows support
 *   Copyright 2004 Budyanto Dj. <budyanto@centrin.net.id>
 *
 * GTWVW is initially created based on:
 *
 * =Id: gtwvt.c,v 1.60 2004-01-26 08:14:07 vouchcac Exp =
 * Video subsystem for Windows using GUI windows instead of Console
 *     Copyright 2003 Peter Rees <peter@rees.co.nz>
 *                    Rees Software & Systems Ltd
 * based on
 *   Bcc ConIO Video subsystem by
 *     Copyright 2002 Marek Paliwoda <paliwoda@inteia.pl>
 *     Copyright 2002 Przemyslaw Czerpak <druzus@polbox.com>
 *   Video subsystem for Windows compilers
 *     Copyright 1999-2000 Paul Tucker <ptucker@sympatico.ca>
 *     Copyright 2002 Przemyslaw Czerpak <druzus@polbox.com>
 *
 * The following parts are Copyright of the individual authors.
 *
 *
 * Copyright 1999 David G. Holm <dholm@jsd-llc.com>
 *    hb_gt_wvw_Tone()
 *
 * See COPYING.txt for licensing terms.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option )
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.txt.   If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA (or visit the web site https://www.gnu.org/ ).
 *
 * As a special exception, the Harbour Project gives permission for
 * additional uses of the text contained in its release of Harbour.
 *
 * The exception is that, if you link the Harbour libraries with other
 * files to produce an executable, this does not by itself cause the
 * resulting executable to be covered by the GNU General Public License.
 * Your use of that executable is in no way restricted on account of
 * linking the Harbour library code into it.
 *
 * This exception does not however invalidate any other reasons why
 * the executable file might be covered by the GNU General Public License.
 *
 * This exception applies only to the code released by the Harbour
 * Project under the name Harbour.  If you copy code from other
 * Harbour Project or Free Software Foundation releases into a copy of
 * Harbour, as the General Public License permits, the exception does
 * not apply to the code that you add in this way.   To avoid misleading
 * anyone as to the status of such modified files, you must delete
 * this exception notice from them.
 *
 * If you write modifications of your own for Harbour, it is your choice
 * whether to permit this exception to apply to your modifications.
 * If you do not wish that, delete this exception notice.
 *
 */

/*
 * Individual authors:
 * (C) 2003-2004 Giancarlo Niccolai <gc at niccolai dot ws>
 *         Standard xplatform GT Info system,
 *         Graphical object system and event system.
 *         hb_gtInfo() And GTO_* implementation.
 *
 * (C) 2004 Mauricio Abre <maurifull@datafull.com>
 *         Cross-GT, multiplatform Graphics API
 *
 * (C) 2009 Cristiam Azambuja <cristiam@datacempro.com.br>
 *          Marson de Paula <marson@datacempro.com.br>
 *          Data Cempro Informatica (www.datacempro.com.br)
 *          Refactoring for xHarbour 1.2.1
 */

#include "hbgtwvw.h"

#if defined( __WATCOMC__ )
   #include <conio.h>
#endif

#include "hbgfxdef.ch"
#define     SubclassWindow( hwnd, lpfn )       \
   ( ( WNDPROC ) SetWindowLongPtr( ( hwnd ), GWLP_WNDPROC, ( LPARAM ) ( WNDPROC ) ( lpfn ) ) )


/* settable by user: ****************************************************/

#if 0
static UINT s_uiPaintRefresh = 100;        /* milliseconds between timer check */

static BOOL s_bMainCoordMode = FALSE;      /* in this mode, all HB_GT_FUNC() uses Main Window's coordinate */

static BOOL s_bVertCaret = FALSE;          /* if TRUE, caret is in Vertical style */

static BOOL s_bNOSTARTUPSUBWINDOW = FALSE; /* if TRUE, subwindow will not be displayed during opening */
/* use wvw_NoStartupSubWindow() to check/set it */

static BOOL s_bDefCentreWindow = FALSE;  /* default CentreWindow setting for subwindows */

static BOOL s_bDefHCentreWindow = FALSE; /* default HCentreWindow setting for subwindows */
static BOOL s_bDefVCentreWindow = FALSE; /* default VCentreWindow setting for subwindows */

static int s_byDefLineSpacing = 0;       /* default line spacing */

static int s_iDefLSpaceColor = -1;       /* if >= 0 this will be the color index
                                            for spacing between lines */

static BOOL s_bAllowNonTop = FALSE;      /* allow non-topmost window's control to
                                            accept input */

static BOOL s_bRecurseCBlock = FALSE;    /* allow control's codeblock
                                            to recurse */

static LOGFONT s_lfPB = { 0 };           /* default font for pushbuttons */

static LOGFONT s_lfSB = { 0 };           /* default font for statusbar  */
static LOGFONT s_lfCB = { 0 };           /* default font for comboboxes */

static LOGFONT s_lfEB = { 0 };           /* default font for editboxes */

static LOGFONT s_lfCX = { 0 };           /* font for 'focused'checkbox */
static LOGFONT s_lfST = { 0 };           /* font for static control    */

static HWND hWndTT = 0;                  /* Window handle Tool Tip     */
#endif

/* read only by user ***/

/* for GTWVW private use: ***********************************************/
#if 0
static BOOL s_bQuickSetMode = FALSE;   /* quick SetMode(), to reset MaxRow() and MaxCol() only */

static BOOL s_bFlashingWindow = FALSE; /* topmost window is flashing
                                          due to invalid input on other
                                          window */

static int s_iScrolling        = 0;    /* scrollbar is scrolling */
static int s_iWrongButtonUp    = 0;    /* number of consecutive scrollbar's WM_LBUTTONUP encountered by gtProcessMessages */
static int s_iMaxWrongButtonUp = 500;  /* max number of s_iWrongButtonUp. If it goes higher than this number,
                                          the scrollbar is forced to stop */

static TCHAR szAppName[]     = TEXT( "Harbour WVW" );
static TCHAR szSubWinName[]  = TEXT( "Harbour WVW subwindows" );
static BOOL  s_bSWRegistered = FALSE;

static UINT s_usNumWindows;                     /*number of windows                         */
static UINT s_usCurWindow = 0;                  /*current window handled by HB_GT_FUNC(...) */

static WIN_DATA * s_pWindows[ WVW_MAXWINDOWS ]; /*array of WIN_DATA                         */
static APP_DATA   s_sApp;                       /*application wide vars                     */
#endif
WVW_DATA *      s_pWvwData;
static BOOL     bStartMode = TRUE;
static COLORREF _COLORS[]  = {
   BLACK,
   BLUE,
   GREEN,
   CYAN,
   RED,
   MAGENTA,
   BROWN,
   WHITE,
   LIGHT_GRAY,
   BRIGHT_BLUE,
   BRIGHT_GREEN,
   BRIGHT_CYAN,
   BRIGHT_RED,
   BRIGHT_MAGENTA,
   YELLOW,
   BRIGHT_WHITE
};

#ifdef WVW_DEBUG
static int nCountPuts = 0, nCountScroll = 0, nCountPaint = 0, nSetFocus = 0, nKillFocus = 0;
#endif

static int K_Ctrl[] = {
   K_CTRL_A, K_CTRL_B, K_CTRL_C, K_CTRL_D, K_CTRL_E, K_CTRL_F, K_CTRL_G, K_CTRL_H,
   K_CTRL_I, K_CTRL_J, K_CTRL_K, K_CTRL_L, K_CTRL_M, K_CTRL_N, K_CTRL_O, K_CTRL_P,
   K_CTRL_Q, K_CTRL_R, K_CTRL_S, K_CTRL_T, K_CTRL_U, K_CTRL_V, K_CTRL_W, K_CTRL_X,
   K_CTRL_Y, K_CTRL_Z
};


/*                                                                   */
/*                  private functions declaration                    */
/*                                                                   */
HB_EXTERN_BEGIN
static void    hb_gtInitStatics( UINT usWinNum, LPCTSTR lpszWinName, USHORT usRow1, USHORT usCol1, USHORT usRow2, USHORT usCol2 );
static void    hb_gt_wvwAddCharToInputQueue( int data );
static HWND    hb_gt_wvwCreateWindow( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow );
static BOOL    hb_gt_wvwInitWindow( WIN_DATA * pWindowData, HWND hWnd, USHORT col, USHORT row );

static void    hb_gt_wvwResetWindowSize( WIN_DATA * pWindowData, HWND hWnd );
static BOOL    hb_gt_wvwSetCodePage( UINT usWinNum, int iCodePage );
static LRESULT CALLBACK hb_gt_wvwWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
static BOOL    hb_gt_wvwAllocSpBuffer( WIN_DATA * pWindowData, USHORT col, USHORT row );

static void    hb_gt_wvwSetWindowTitle( UINT usWinNum, LPCTSTR title );
static PHB_ITEM hb_gt_wvw_GetWindowTitle( UINT usWinNum, PHB_ITEM pItem );
static HICON   hb_gt_wvwSetWindowIcon( UINT usWinNum, int icon, const char * lpIconName );
static HICON   hb_gt_wvwSetWindowIconFromFile( UINT usWinNum, LPCTSTR icon );


static BOOL    hb_gt_wvwSetCentreWindow( UINT usWinNum, BOOL bCentre, BOOL bPaint );

static BOOL    hb_gt_wvwValidWindowSize( WIN_DATA * pWindowData, int rows, int cols, HFONT hFont, int iWidth,
                                         int * pmaxrows, int * pmaxcols );

static void    hb_gt_wvwSetCaretOn( WIN_DATA * pWindowData, BOOL bOn );
static BOOL    hb_gt_wvwSetCaretPos( WIN_DATA * pWindowData );
static void    hb_gt_wvwValidateCaret( WIN_DATA * pWindowData );

static void    hb_gt_wvwSetMouseX( WIN_DATA * pWindowData, USHORT ix );
static void    hb_gt_wvwSetMouseY( WIN_DATA * pWindowData, USHORT iy );

static int     hb_gt_wvwJustTranslateKey( int key, int shiftkey, int altkey, int controlkey );
static void    hb_gt_wvwTranslateKey( int key, int shiftkey, int altkey, int controlkey );

static void    hb_gt_wvwSetInvalidRect( WIN_DATA * pWindowData, USHORT left, USHORT top, USHORT right, USHORT bottom );
static void    hb_gt_wvwDoInvalidateRect( WIN_DATA * pWindowData );

static void    hb_gt_wvwHandleMenuSelection( int );

static void    hb_gt_wvwUnreachedXY( WIN_DATA * pWindowData, int * cols, int * rows );
static POINT   hb_gt_wvwGetColRowFromXY( WIN_DATA * pWindowData, USHORT x, USHORT y );
static POINT   hb_gt_wvwTBGetColRowFromXY( WIN_DATA * pWindowData, USHORT x, USHORT y );

static POINT   hb_gt_wvwGetColRowForTextBuffer( WIN_DATA * pWindowData, USHORT index );

static void    hb_gt_wvwValidateCol( WIN_DATA * pWindowData );
static void    hb_gt_wvwValidateRow( WIN_DATA * pWindowData );

static USHORT  hb_gt_wvwCalcPixelHeight( WIN_DATA * pWindowData );
static USHORT  hb_gt_wvwCalcPixelWidth( WIN_DATA * pWindowData );
static BOOL    hb_gt_wvwSetColors( WIN_DATA * pWindowData, HDC hdc, BYTE attr );


static BOOL    hb_gt_wvwTextOut( WIN_DATA * pWindowData, HDC hdc, USHORT col, USHORT row, LPCTSTR lpString, USHORT cbString  );
static void    hb_gt_wvwSetStringInTextBuffer( WIN_DATA * pWindowData, int col, int row, BYTE color, BYTE attr, BYTE * sBuffer, ULONG length );
static USHORT  hb_gt_wvwGetIndexForTextBuffer( WIN_DATA * pWindowData, USHORT col, USHORT row );


static void    hb_gt_wvwCreateObjects( UINT usWinNum );
static void    hb_gt_wvwKillCaret( WIN_DATA * pWindowData );
static void    hb_gt_wvwCreateCaret( WIN_DATA * pWindowData );
static void    hb_gt_wvwMouseEvent( WIN_DATA * pWindowData, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
static void    hb_gt_wvwTBMouseEvent( WIN_DATA * pWindowData, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );

static void    hb_gt_wvwCreateToolTipWindow( WIN_DATA * pWindowData );

/* multi-window related static functions: */
static void hb_gt_wvwWindowPrologue( void );
static void hb_gt_wvwWindowEpilogue( void );

static UINT hb_gt_wvwOpenWindow( LPCTSTR lpszWinName, int usRow1, int usCol1, int usRow2, int usCol2, DWORD dwStyle, int iParentWin );
static void hb_gt_wvwCloseWindow( void );
static BOOL hb_gt_wvwAcceptingInput( void );
static BOOL hb_gt_wvwBufferedKey( LONG lKey );

static void hb_gt_wvwInputNotAllowed( UINT usWinNum, UINT message, WPARAM wParam, LPARAM lParam );

static BOOL hb_gt_wvwInWindow( UINT usWinNum, USHORT usrow, USHORT uscol );
static UINT hb_gt_wvwFindWindow( USHORT usRow, USHORT usCol );
static UINT hb_gt_wvwSetCurWindow( UINT usWinNum );

/* functions created in order to allow us operating MainCoord Mode: */
static void   hb_wvw_vmouse_Init( void );
static void   hb_wvw_vmouse_Exit( void );
static void   hb_wvw_vmouse_SetPos( WIN_DATA * pWindowData, USHORT usRow, USHORT usCol );
static int    hb_gt_wvw_usDispCount( WIN_DATA * pWindowData );
static void   hb_gt_wvw_vDispBegin( WIN_DATA * pWindowData );
static void   hb_gt_wvw_vDispEnd( WIN_DATA * pWindowData );
static void  hb_gt_wvw_vGetText( WIN_DATA * pWindowData, USHORT top, USHORT left, USHORT bottom, USHORT right, BYTE * sBuffer );
static void  hb_gt_wvw_vPuts( WIN_DATA * pWindowData, int iRow, int iCol, BYTE byColor, BYTE byAttr, BYTE * pbyStr, ULONG ulLen );
static void  hb_gt_wvw_vReplicate( WIN_DATA * pWindowData, int iRow, int iCol, int bColor, BYTE bAttr, USHORT usChar, ULONG ulLen );
static void  hb_gt_wvw_vPutText( WIN_DATA * pWindowData, USHORT top, USHORT left, USHORT bottom, USHORT right, const char * sBuffer, int bColor );
static void  hb_gt_wvw_vSetAttribute( WIN_DATA * pWindowData, int iTop, int iLeft, int iBottom, int iRight, int bColor );
static BOOL  hb_gt_wvw_bSetMode( WIN_DATA * pWindowData, USHORT row, USHORT col );
static void  hb_gt_wvw_vxPutch( WIN_DATA * pWindowData, USHORT iRow, USHORT iCol, int bColor, BYTE bChar );
static void  hb_gt_wvw_usBox( WIN_DATA * pWindowData, int iTop, int iLeft, int iBottom, int iRight, const char * pbyFrame, int bColor );
static void  hb_gt_wvw_vSetPos( WIN_DATA * pWindowData, int iRow, int iCol );

static void   hb_wvw_InitPendingRect( WIN_DATA * pWindowData );
static void   hb_wvw_UpdatePendingRect( WIN_DATA * pWindowData, USHORT usRow1, USHORT usCol1, USHORT usRow2, USHORT usCol2 );


static void   hb_gt_wvwFillLineSpace( WIN_DATA * pWindowData, HDC hdc, USHORT startCol, USHORT irow, USHORT len, BYTE byAttrib );

static BITMAPINFO * PackedDibLoad( PTSTR szFileName );
static int PackedDibGetWidth( BITMAPINFO * pPackedDib );
static int PackedDibGetHeight( BITMAPINFO * pPackedDib );
static int PackedDibGetBitCount( BITMAPINFO * pPackedDib );

static int PackedDibGetInfoHeaderSize( BITMAPINFO * pPackedDib );
static int PackedDibGetColorsUsed( BITMAPINFO * pPackedDib );
static int PackedDibGetNumColors( BITMAPINFO * pPackedDib );
static int PackedDibGetColorTableSize( BITMAPINFO * pPackedDib );

static BYTE * PackedDibGetBitsPtr( BITMAPINFO * pPackedDib );


/* picture caching function: */
static IPicture * FindPictureHandle( const char * szFileName, int * piWidth, int * piHeight );
static void AddPictureHandle( const char * szFileName, IPicture * iPicture, int iWidth, int iHeight );

/* bitmap caching functions for user drawn bitmaps (wvw_drawimage) */
static HBITMAP FindUserBitmapHandle( const char * szFileName, int * piWidth, int * piHeight );
static void AddUserBitmapHandle( const char * szFileName, HBITMAP hBitmap, int iWidth, int iHeight );


static int GetControlClass( UINT usWinNum, HWND hWndCtrl );

static void RunControlBlock( UINT usWinNum, BYTE byCtrlClass, HWND hWndCtrl, UINT message, WPARAM wParam, LPARAM lParam, int iEventType );
static void ReposControls( UINT usWinNum, BYTE byCtrlClass );

static BOOL hb_wvw_Move_Ready( BOOL b_p_IsReady );
static BOOL hb_wvw_Size_Ready( BOOL b_p_SizeIsReady );


/*                                                                   */
/* mouse initialization was made in cmdarg.c                         */
/*                                                                   */

#include "hbgtcore.h"
#include "hbinit.h"
#include "hbapiitm.h"

/* set in mainwin.c                                                  */
/*                                                                   */
extern int hb_iCmdShow;

static int s_iCursorStyle;
static int s_iOldCurStyle;

static HB_FHANDLE s_iStdIn, s_iStdOut, s_iStdErr;

static int s_GtId;
static HB_GT_FUNCS SuperTable;
#define HB_GTSUPER   ( &SuperTable )
#define HB_GTID_PTR  ( &s_GtId )

HB_EXTERN_END

LONG  GetFontDialogUnits( HWND h, HFONT f )
{

   HFONT  hFont;
   HFONT  hFontOld;
   LONG   avgWidth;
   HDC    hDc;
   char * tmp = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
   SIZE   sz;

   /* get the hdc to the main window */
   hDc = GetDC( h );

   /* with the current font attributes, select the font */
   hFont    = f; /* GetStockObject(ANSI_VAR_FONT); */
   hFontOld = ( HFONT ) SelectObject( hDc, &hFont );

   /* get its length, then calculate the average character width */

   GetTextExtentPoint32( hDc, tmp, 52, &sz );
   avgWidth = ( sz.cx / 52 );

   /* re-select the previous font & delete the hDc */
   SelectObject( hDc, hFontOld );
   DeleteObject( hFont );
   ReleaseDC( h, hDc );


   return avgWidth;

}


/*                                                                   */
/*                     GT Specific Functions                         */
/*                                                                   */


static void hb_gt_wvw_Init( PHB_GT pGT, HB_FHANDLE hFilenoStdin, HB_FHANDLE hFilenoStdout, HB_FHANDLE hFilenoStderr )
{
   HANDLE hInstance;
   HANDLE hPrevInstance;
   int    iCmdShow;

   USHORT i;

   if( bStartMode )
   {
      s_pWvwData = ( WVW_DATA * ) hb_xgrab( sizeof( WVW_DATA ) );
      memset( s_pWvwData, 0, sizeof( WVW_DATA ) );
      s_pWvwData->s_sApp = ( APP_DATA * ) hb_xgrab( sizeof( APP_DATA ) );
      memset( s_pWvwData->s_sApp, 0, sizeof( APP_DATA ) );

      s_pWvwData->s_uiPaintRefresh      = 100;
      s_pWvwData->s_bMainCoordMode      = FALSE;
      s_pWvwData->s_bVertCaret          = FALSE;
      s_pWvwData->s_bNOSTARTUPSUBWINDOW = FALSE;
      s_pWvwData->s_bDefCentreWindow    = FALSE;
      s_pWvwData->s_bDefHCentreWindow   = FALSE;
      s_pWvwData->s_bDefVCentreWindow   = FALSE;
      s_pWvwData->s_byDefLineSpacing    = 0;
      s_pWvwData->s_iDefLSpaceColor     = -1;
      s_pWvwData->s_bAllowNonTop        = FALSE;
      s_pWvwData->s_bRecurseCBlock      = FALSE;
      s_pWvwData->hWndTT = 0;
      s_pWvwData->s_bQuickSetMode     = FALSE;
      s_pWvwData->s_bFlashingWindow   = FALSE;
      s_pWvwData->s_iScrolling        = 0;
      s_pWvwData->s_iWrongButtonUp    = 0;
      s_pWvwData->s_iMaxWrongButtonUp = 500;
      strcpy( s_pWvwData->szAppName, "Harbour WVW" );
      strcpy( s_pWvwData->szSubWinName, "Harbour WVW subwindows" );
      s_pWvwData->s_bSWRegistered = FALSE;
      s_pWvwData->s_usCurWindow   = 0;
      bStartMode = FALSE;
   }


   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_Init()" ) );

   /* stdin && stdout && stderr */
   s_iStdIn  = hFilenoStdin;
   s_iStdOut = hFilenoStdout;
   s_iStdErr = hFilenoStderr;

   if( ! hb_winmainArgGet( &hInstance, &hPrevInstance, &iCmdShow ) )
   {
      hInstance = GetModuleHandle( NULL );
      iCmdShow  = 1;
   }

   s_iOldCurStyle = s_iCursorStyle = SC_NORMAL;

   s_pWvwData->s_usNumWindows = 0;
   for( i = 0; i < WVW_MAXWINDOWS; i++ )
      s_pWvwData->s_pWindows[ i ] = NULL;

   hb_gt_wvwWindowPrologue();

   hb_gtInitStatics( 0, ( LPCTSTR ) s_pWvwData->szAppName, 0, 0, WVW_DEFAULT_ROWS - 1, WVW_DEFAULT_COLS - 1 );

   s_pWvwData->hInstance = ( HINSTANCE ) hInstance;

   s_pWvwData->s_pWindows[ 0 ]->hWnd = hb_gt_wvwCreateWindow( ( HINSTANCE ) hInstance, ( HINSTANCE ) hPrevInstance, "", iCmdShow );

   if( ! s_pWvwData->s_pWindows[ 0 ]->hWnd )
      /*  Runtime error
       */
      hb_errRT_TERM( EG_CREATE, 10001, "WINAPI CreateWindow() failed", "hb_gt_Init()", 0, 0 );

   {
      PHB_ITEM pItem = hb_itemPutCPtr( NULL, hb_cmdargBaseProgName() );
      void *   hWindowTitle;

      hb_gt_wvwSetWindowTitle( 0, HB_ITEMGETSTR( pItem, &hWindowTitle, NULL ) );
      hb_strfree( hWindowTitle );
      hb_itemRelease( pItem );
   }

   hb_gt_wvwCreateObjects( 0 );
   s_pWvwData->s_pWindows[ 0 ]->hdc     = GetDC( s_pWvwData->s_pWindows[ 0 ]->hWnd );
   s_pWvwData->s_pWindows[ 0 ]->hCompDC = CreateCompatibleDC( s_pWvwData->s_pWindows[ 0 ]->hdc );

   /*
      Apos o Device Context e as PENs e BRUSHes criados, atribuo uma PEN e um BRUSH qualquer apenas para pegar
      o handle original da PEN e BRUSH do Device Context
    */
   s_pWvwData->s_sApp->OriginalPen   = ( HPEN ) SelectObject( s_pWvwData->s_pWindows[ 0 ]->hdc, ( HPEN ) s_pWvwData->s_sApp->penWhite );
   s_pWvwData->s_sApp->OriginalBrush = ( HBRUSH ) SelectObject( s_pWvwData->s_pWindows[ 0 ]->hdc, ( HBRUSH ) s_pWvwData->s_sApp->currentBrush );
   /*
      E, logo apos, restaura aos valores originais mantendo em s_pWvwData->s_sApp os valores salvos para restauracao
      quando for utilizar DeleteObject()
    */
   SelectObject( s_pWvwData->s_pWindows[ 0 ]->hdc, ( HPEN ) s_pWvwData->s_sApp->OriginalPen );
   SelectObject( s_pWvwData->s_pWindows[ 0 ]->hdc, ( HBRUSH ) s_pWvwData->s_sApp->OriginalBrush );

   /* SUPER GT initialization */
   HB_GTSUPER_INIT( pGT, hFilenoStdin, hFilenoStdout, hFilenoStderr );
   HB_GTSELF_RESIZE( pGT, s_pWvwData->s_pWindows[ 0 ]->ROWS, s_pWvwData->s_pWindows[ 0 ]->COLS );

}


BOOL hb_gt_wvwDestroyPicture( IPicture * iPicture )
{
   BOOL bResult = FALSE;

   if( iPicture )
   {
      iPicture->lpVtbl->Release( iPicture );
      bResult = TRUE;
   }
   return bResult;
}


static void hb_gt_wvw_Exit( PHB_GT pGT )
{
/* void gt_Exit( void ) */
   int i;
   int j;
   WIN_DATA *       pWindowData;
   BITMAP_HANDLE *  pbh;
   PICTURE_HANDLE * pph;
   CONTROL_DATA *   pcd;

   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_Exit()" ) );

   HB_GTSUPER_EXIT( pGT );

   for( i = 0; i < WVW_DLGML_MAX; i++ )
      if( s_pWvwData->s_sApp->hDlgModeless[ i ] )
         SendMessage( s_pWvwData->s_sApp->hDlgModeless[ i ], WM_CLOSE, 0, 0 );

   /* destroy all objects from all windows */

   for( j = ( int ) ( s_pWvwData->s_usNumWindows - 1 ); j >= 0; j-- )
   {
      pWindowData = ( WIN_DATA * ) s_pWvwData->s_pWindows[ j ];

      if( pWindowData->hWnd )
      {

         KillTimer( pWindowData->hWnd, WVW_ID_SYSTEM_TIMER );
         if( s_pWvwData->s_sApp->pSymWVW_TIMER )
            KillTimer( pWindowData->hWnd, WVW_ID_BASE_TIMER + j );

         DeleteObject( ( HFONT ) pWindowData->hFont );

         /*
            Faz apenas para a janela 0 (a primeira) ja que existe, na criacao das mesmas, uma condicao para que
            apenas a primeira seja criada
            Obs: A exclusao desses objetos precisa ocorrer antes da Release do Device Context
          */
         if( j == 0 )
         {
            /*
               Seleciona PEN e BRUSH Originais
             */
            SelectObject( s_pWvwData->s_pWindows[ 0 ]->hdc, ( HPEN ) s_pWvwData->s_sApp->OriginalPen );
            SelectObject( s_pWvwData->s_pWindows[ 0 ]->hdc, ( HBRUSH ) s_pWvwData->s_sApp->OriginalBrush );

            /*
               Com PENs e BRUSHes liberadas, efetua exclusao
             */
            if( s_pWvwData->s_sApp->penWhite )
               DeleteObject( ( HPEN ) s_pWvwData->s_sApp->penWhite );
            if( s_pWvwData->s_sApp->penWhiteDim )
               DeleteObject( ( HPEN ) s_pWvwData->s_sApp->penWhiteDim );
            if( s_pWvwData->s_sApp->penBlack )
               DeleteObject( ( HPEN ) s_pWvwData->s_sApp->penBlack );
            if( s_pWvwData->s_sApp->penDarkGray )
               DeleteObject( ( HPEN ) s_pWvwData->s_sApp->penDarkGray );
            if( s_pWvwData->s_sApp->penGray )
               DeleteObject( ( HPEN ) s_pWvwData->s_sApp->penGray );
            if( s_pWvwData->s_sApp->penNull )
               DeleteObject( ( HPEN ) s_pWvwData->s_sApp->penNull );
            if( s_pWvwData->s_sApp->currentPen )
               DeleteObject( ( HPEN ) s_pWvwData->s_sApp->currentPen );
            if( s_pWvwData->s_sApp->currentBrush )
               DeleteObject( ( HBRUSH ) s_pWvwData->s_sApp->currentBrush );
            if( s_pWvwData->s_sApp->diagonalBrush )
               DeleteObject( ( HBRUSH ) s_pWvwData->s_sApp->diagonalBrush );
            if( s_pWvwData->s_sApp->solidBrush )
               DeleteObject( ( HBRUSH ) s_pWvwData->s_sApp->solidBrush );
            if( s_pWvwData->s_sApp->wvwWhiteBrush )
               DeleteObject( ( HBRUSH ) s_pWvwData->s_sApp->wvwWhiteBrush );
            if( s_pWvwData->s_sApp->gridPen )
               DeleteObject( ( HPEN ) s_pWvwData->s_sApp->gridPen );
         }

         if( pWindowData->hIcon )
            DestroyIcon( ( HICON ) pWindowData->hIcon );

         if( pWindowData->hdc )
            ReleaseDC( pWindowData->hWnd, pWindowData->hdc );

         if( pWindowData->hCompDC )
            DeleteDC( pWindowData->hCompDC );

         while( pWindowData->pcdCtrlList )
         {
            pcd = pWindowData->pcdCtrlList->pNext;
            DestroyWindow( pWindowData->pcdCtrlList->hWndCtrl );

            if( pWindowData->pcdCtrlList->phiCodeBlock )
               hb_itemRelease( pWindowData->pcdCtrlList->phiCodeBlock );


            hb_xfree( pWindowData->pcdCtrlList );
            pWindowData->pcdCtrlList = pcd;
         }

         DestroyWindow( pWindowData->hWnd );

         if( pWindowData->hPBfont )
            DeleteObject( ( HFONT ) pWindowData->hPBfont );

         if( pWindowData->hCBfont )
            DeleteObject( ( HFONT ) pWindowData->hCBfont );

         if( pWindowData->hCXfont )
            DeleteObject( ( HFONT ) pWindowData->hCXfont );

         if( pWindowData->hSBfont )
            DeleteObject( ( HFONT ) pWindowData->hSBfont );

         if( pWindowData->hSTfont )
            DeleteObject( ( HFONT ) pWindowData->hSTfont );
      }

      hb_gt_wvwWindowEpilogue();
   }

   if( s_pWvwData->s_bSWRegistered )
      UnregisterClass( s_pWvwData->szSubWinName, s_pWvwData->hInstance );

   UnregisterClass( s_pWvwData->szAppName, s_pWvwData->hInstance );

   for( i = 0; i < WVW_PICTURES_MAX; i++ )
      if( s_pWvwData->s_sApp->iPicture[ i ] )
         hb_gt_wvwDestroyPicture( s_pWvwData->s_sApp->iPicture[ i ] );

   for( i = 0; i < WVW_FONTS_MAX; i++ )
      if( s_pWvwData->s_sApp->hUserFonts[ i ] )
         DeleteObject( ( HFONT ) s_pWvwData->s_sApp->hUserFonts[ i ] );

   for( i = 0; i < WVW_PENS_MAX; i++ )
      if( s_pWvwData->s_sApp->hUserPens[ i ] )
         DeleteObject( ( HPEN ) s_pWvwData->s_sApp->hUserPens[ i ] );

   if( s_pWvwData->s_sApp->hMSImg32 )
      FreeLibrary( s_pWvwData->s_sApp->hMSImg32 );

   while( s_pWvwData->s_sApp->pbhBitmapList )
   {
      pbh = s_pWvwData->s_sApp->pbhBitmapList->pNext;
      DeleteObject( s_pWvwData->s_sApp->pbhBitmapList->hBitmap );

      hb_xfree( s_pWvwData->s_sApp->pbhBitmapList );
      s_pWvwData->s_sApp->pbhBitmapList = pbh;
   }

   while( s_pWvwData->s_sApp->pphPictureList )
   {
      pph = s_pWvwData->s_sApp->pphPictureList->pNext;
      hb_gt_wvwDestroyPicture( s_pWvwData->s_sApp->pphPictureList->iPicture );

      hb_xfree( s_pWvwData->s_sApp->pphPictureList );
      s_pWvwData->s_sApp->pphPictureList = pph;
   }

   while( s_pWvwData->s_sApp->pbhUserBitmap )
   {
      pbh = s_pWvwData->s_sApp->pbhUserBitmap->pNext;
      DeleteObject( s_pWvwData->s_sApp->pbhUserBitmap->hBitmap );

      hb_xfree( s_pWvwData->s_sApp->pbhUserBitmap );
      s_pWvwData->s_sApp->pbhUserBitmap = pbh;
   }
   if( s_pWvwData->s_sApp )
      hb_xfree( s_pWvwData->s_sApp );
   if( s_pWvwData )
      hb_xfree( s_pWvwData );

}


void hb_gt_wvw_SetPos( PHB_GT pGT, int iRow, int iCol )
{
   int i_Row = iRow;
   int i_Col = iCol;

   pGT->iRow = iRow;
   pGT->iCol = iCol;

   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_SetPos( %hd, %hd )", iRow, iCol ) );

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCPrologue( 2, &i_Row, &i_Col, NULL, NULL );

   hb_gt_wvw_vSetPos( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], i_Row, i_Col );

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCEpilogue();
}


static int hb_gt_wvw_MaxCol( PHB_GT pGT )
{
   HB_SYMBOL_UNUSED( pGT );
   return s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->COLS - 1;
}


static int hb_gt_wvw_MaxRow( PHB_GT pGT )
{
   HB_SYMBOL_UNUSED( pGT );
   return s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->ROWS - 1;
}


BOOL hb_gt_wvw_IsColor( PHB_GT pGT )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_IsColor()" ) );

   HB_SYMBOL_UNUSED( pGT );

   return TRUE;
}


static int hb_gt_wvw_GetCursorStyle( PHB_GT pGT  )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_GetCursorStyle()" ) );

   HB_SYMBOL_UNUSED( pGT );

   return s_iCursorStyle;
}


/*NOTE: works on TOPMOST window, NOT Current Window!
 *      (caret exists only in TOPMOST window)
 */

static void hb_gt_wvw_SetCursorStyle( PHB_GT pGT, int iStyle )
{
   BOOL       bCursorOn = TRUE;
   WIN_DATA * pWindowData;
   USHORT     usFullSize;

   HB_SYMBOL_UNUSED( pGT );

   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_SetCursorStyle( %hu )", iStyle ) );

   pWindowData = ( WIN_DATA * ) s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ];
   usFullSize  = ( USHORT ) ( s_pWvwData->s_bVertCaret ? pWindowData->PTEXTSIZE.x : pWindowData->PTEXTSIZE.y );

   s_iCursorStyle = iStyle;

   switch( iStyle )
   {
      case SC_NONE:
         pWindowData->CaretSize = 0;
         bCursorOn = FALSE;
         break;
      case SC_INSERT:
         pWindowData->CaretSize = ( usFullSize / 2 );
         break;
      case SC_SPECIAL1:
         pWindowData->CaretSize = usFullSize;
         break;
      case SC_SPECIAL2:
         pWindowData->CaretSize = -( usFullSize / 2 );
         break;
      case SC_NORMAL:
      default:
         pWindowData->CaretSize = 2;
         break;
   }

   if( bCursorOn )
   {
      if( ! s_pWvwData->s_bVertCaret )
         s_pWvwData->s_sApp->CaretExist = CreateCaret( pWindowData->hWnd, ( HBITMAP ) NULL, pWindowData->PTEXTSIZE.x, pWindowData->CaretSize );
      else
         s_pWvwData->s_sApp->CaretExist = CreateCaret( pWindowData->hWnd, ( HBITMAP ) NULL, pWindowData->CaretSize, pWindowData->PTEXTSIZE.y );
   }
   hb_gt_wvwSetCaretOn( pWindowData, bCursorOn );
}


static void hb_gt_wvw_DispBegin( PHB_GT pGT )
{

   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_DispBegin()" ) );

   HB_SYMBOL_UNUSED( pGT );

   hb_gt_wvw_vDispBegin( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ] );
}


static void hb_gt_wvw_DispEnd( PHB_GT pGT )
{

   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_DispEnd()" ) );

   HB_SYMBOL_UNUSED( pGT );

   hb_gt_wvw_vDispEnd( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ] );
}


static int hb_gt_wvw_DispCount( PHB_GT pGT )
{

   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_DispCount()" ) );

   HB_SYMBOL_UNUSED( pGT );

   return hb_gt_wvw_usDispCount( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ] );
}


static void hb_gt_wvw_Replicate( PHB_GT pGT, int iRow, int iCol, int bColor, BYTE bAttr, USHORT usChar, ULONG ulLen )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_Replicate( %hu, %hu, %hu, %i, %lu )", iRow, iCol, bColor, bAttr, usChar, ulLen ) );

   HB_SYMBOL_UNUSED( pGT );

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCPrologue( 2, &iRow, &iCol, NULL, NULL );

   hb_gt_wvw_vReplicate( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], iRow, iCol, bColor, bAttr, usChar, ulLen );

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCEpilogue();
}


static void hb_gt_wvw_PutText( PHB_GT pGT, int iRow, int iCol, int bColor, const char * pText, ULONG ulLen )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_PutText(%hu, %hu, %p, %lu, %hu)", iRow, iCol, pText, ulLen, bColor ) );

   HB_SYMBOL_UNUSED( pGT );

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCPrologue( 2, &iRow, &iCol, NULL, NULL );

   hb_gt_wvw_vPutText(  s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], ( USHORT ) iRow, ( USHORT ) iCol, ( USHORT ) iRow, ( USHORT ) ulLen == 0 ? ( USHORT ) 0 : ( USHORT ) iCol + ( ( USHORT ) ( ULONG ) ( ulLen ) ) - 1, pText, bColor );


   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCEpilogue();
}


static void hb_gt_wvw_SetAttribute( PHB_GT pGT, int iTop, int iLeft, int iBottom, int iRight, int bColor )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_hb_gt_wvw_SetbColoribute( %hu, %hu, %hu, %hu, %hu", iTop, iLeft, iBottom, iRight, bColor ) );

   HB_SYMBOL_UNUSED( pGT );

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCPrologue( 4, &iTop, &iLeft, &iBottom, &iRight );

   hb_gt_wvw_vSetAttribute( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], iTop, iLeft, iBottom, iRight, bColor );

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCEpilogue();
}


/*                                                                   */
/*    copied from gtwin...                                           */
/*                                                                   */

static void hb_gt_wvw_Scroll( PHB_GT pGT, int iTop, int iLeft, int iBottom, int iRight, int bColor, USHORT bChar, int iRows, int iCols )
{
   LONG usSaveRow, usSaveCol;

   BYTE   ucBlank[ WVW_CHAR_BUFFER ], ucBuff[ WVW_CHAR_BUFFER * 2 ];
   BYTE * fpBlank;
   BYTE * fpBuff;
   int    iLength = ( iRight - iLeft ) + 1;
   int    iCount, iColOld, iColNew, iColSize;
   BOOL   bMalloc = FALSE;

   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_Scroll( %hu, %hu, %hu, %hu, %hu, %hd, %hd )", iTop, iLeft, iBottom, iRight, bColor, iRows, iCols ) );

   HB_SYMBOL_UNUSED( pGT );
   HB_SYMBOL_UNUSED( bChar );

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCPrologue( 4, &iTop, &iLeft, &iBottom, &iRight );

   if( iLength > WVW_CHAR_BUFFER ) /* Avoid allocating memory if possible */
   {
      fpBlank = ( BYTE * ) hb_xgrab( iLength );
      fpBuff  = ( BYTE * ) hb_xgrab( iLength * 2 );  /* *2 room for attribs */
      bMalloc = TRUE;
   }
   else
   {
      fpBlank = ucBlank;
      fpBuff  = ucBuff;
   }

   memset( fpBlank, hb_gtGetClearChar(), iLength );

   iColOld  = iColNew = iLeft;
   iColSize = iLength - 1;
   if( iCols >= 0 )
   {
      iColOld  += iCols;
      iColSize -= iCols;
   }
   else
   {
      iColNew  -= iCols;
      iColSize += iCols;
   }
   /* use the ScrollWindowEx() where possible ( Optimised for Terminal Server )
    * if both iCols & iRows are ZERO then the entire area is to be cleared and
    * there is no advantage in using ScrollWindowEx()
    */

   s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->InvalidateWindow = hb_gt_wvw_usDispCount( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ] ) > 0 || ( ! iRows && ! iCols );

   if( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->InvalidateWindow )
      hb_gt_wvw_vDispBegin( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ] );

   usSaveCol = s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->caretPos.x;
   usSaveRow = s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->caretPos.y;
   for( iCount = ( iRows >= 0 ? iTop : iBottom );
        ( iRows >= 0 ? iCount <= iBottom : iCount >= iTop );
        ( iRows >= 0 ? iCount++ : iCount-- ) )
   {
      int iRowPos = iCount + iRows;

      /* Read the text to be scrolled into the current row */
      if( ( iRows || iCols ) && iRowPos <= iBottom && iRowPos >= iTop )
         hb_gt_wvw_vGetText( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], ( USHORT ) iRowPos, ( USHORT ) iColOld, ( USHORT ) iRowPos, ( USHORT ) iColOld + ( USHORT ) iColSize, fpBuff );

      /* Blank the scroll region in the current row */
      hb_gt_wvw_vPuts( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], iCount, iLeft, bColor, 0, fpBlank, iLength );

      /* Write the scrolled text to the current row */
      if( ( iRows || iCols ) && iRowPos <= iBottom && iRowPos >= iTop )
         hb_gt_wvw_vPutText( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], ( USHORT ) iCount, ( USHORT ) iColNew, ( USHORT ) iCount, ( USHORT ) iColNew + ( USHORT ) iColSize, fpBuff, 0 );
   }

   hb_gt_wvw_vSetPos( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], usSaveRow, usSaveCol );

   if( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->InvalidateWindow )
      hb_gt_wvw_vDispEnd( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ] );

   else
   {
      RECT cr = { 0 }, crInvalid = { 0 };

      cr.left   = iLeft + ( iCols > 0 ? 1 : 0 );
      cr.top    = iTop + ( iRows > 0 ? 1 : 0 );
      cr.right  = iRight - ( iCols < 0 ? 1 : 0 );
      cr.bottom = iBottom - ( iRows < 0 ? 1 : 0 );

      cr = hb_gt_wvwGetXYFromColRowRect( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], cr );

      cr.top -= ( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->byLineSpacing / 2 );

      cr.bottom += ( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->byLineSpacing / 2 );

      ScrollWindowEx( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->hWnd, -iCols * s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->PTEXTSIZE.x, -iRows * hb_wvw_LineHeight( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ] ), &cr, NULL, NULL, &crInvalid, 0 );
      InvalidateRect( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->hWnd, &crInvalid, FALSE );
      s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->InvalidateWindow = TRUE;

   }
   if( bMalloc )
   {
      hb_xfree( fpBlank );
      hb_xfree( fpBuff );
   }

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCEpilogue();

#ifdef WVW_DEBUG
   nCountScroll++;
#endif
}


/*                                                                   */
/*    resize the ( existing ) window                                 */
/*                                                                   */

static BOOL hb_gt_wvw_SetMode( PHB_GT pGT, int iRow, int iCol )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_SetMode( %hu, %hu )", iRow, iCol ) );

   HB_SYMBOL_UNUSED( pGT );

   if( s_pWvwData->s_bQuickSetMode ) /*this is eg. done when we are closing window
                                      * we do nothing here, what we need is performed by GTAPI level
                                      * ie. setting its s_height and s_width (= MaxRow() and MaxCol() )
                                      */
      return TRUE;

   return hb_gt_wvw_bSetMode( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], ( USHORT ) iRow, ( USHORT ) iCol );
}


static void hb_gt_wvw_WriteAt( PHB_GT pGT, int iRow, int iCol, const char * pText, ULONG ulLength )
{
   HB_GTSELF_PUTTEXT( pGT, iRow, iCol, ( BYTE ) HB_GTSELF_GETCOLOR( pGT ), pText, ulLength );

   /* Finally, save the new cursor position, even if off-screen */
   HB_GTSELF_SETPOS( pGT, iRow, iCol + ( int ) ulLength );
}


static BOOL hb_gt_wvw_GetBlink( PHB_GT pGT )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_GetBlink()" ) );
   HB_SYMBOL_UNUSED( pGT );
   return TRUE;
}


static void hb_gt_wvw_SetBlink( PHB_GT pGT, BOOL bBlink )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_SetBlink( %d )", ( int ) bBlink ) );
   HB_SYMBOL_UNUSED( pGT );
   HB_SYMBOL_UNUSED( bBlink );
}


static const char * hb_gt_wvw_Version( PHB_GT pGT, int iType )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_Version()" ) );
   HB_SYMBOL_UNUSED( pGT );

   if( iType == 0 )
      return HB_GT_DRVNAME( HB_GT_NAME );

   return "Harbour Terminal: Windows buffered WVW";
}


static void hb_gt_wvw_Box( PHB_GT pGT, int iTop, int iLeft, int iBottom, int iRight, const char * pbyFrame, int bColor )
{
   int i_Top    = ( iTop < 0 ? 0 : iTop );
   int i_Left   = ( iLeft < 0 ? 0 : iLeft );
   int i_Bottom = ( iBottom < 0 ? 0 : iBottom );
   int i_Right  = ( iRight < 0 ? 0 : iRight );

   HB_SYMBOL_UNUSED( pGT );

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCPrologue( 4, &i_Top, &i_Left, &i_Bottom, &i_Right );

   hb_gt_wvw_usBox( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], i_Top, i_Left, i_Bottom, i_Right, pbyFrame, bColor );

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCEpilogue();
}

static void hb_gt_wvw_HorizLine( PHB_GT pGT, int iRow, int iLeft, int iRight, USHORT bChar, int bColor )
{

   int iWidth;
   int i_Row   = ( iRow < 0 ? 0 : iRow );
   int i_Left  = ( iLeft < 0 ? 0 : iLeft );
   int i_Right = ( iRight < 0 ? 0 : iRight );

   HB_SYMBOL_UNUSED( pGT );

   if( s_pWvwData->s_bMainCoordMode )
   {

      if( i_Left > i_Right )
      {
         int temp;
         temp    = i_Left;
         i_Left  = i_Right;
         i_Right = temp;
      }
      hb_gt_wvwFUNCPrologue( 4, &i_Row, &i_Left, NULL, &i_Right );
   }

   iWidth = s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->COLS;

   if( i_Row < iWidth )
   {

      if( i_Left >= iWidth )
         i_Left = iWidth - 1;

      if( i_Right >= iWidth )
         i_Right = iWidth - 1;
      if( i_Left < i_Right )
         hb_gt_wvw_vReplicate( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], i_Row, i_Left, bColor, HB_GT_ATTR_BOX, bChar, i_Right - i_Left + 1 );
      else
         hb_gt_wvw_vReplicate( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], i_Row, i_Right, bColor, HB_GT_ATTR_BOX, bChar, i_Left - i_Right + 1 );
   }

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCEpilogue();
}

static void hb_gt_wvw_VertLine( PHB_GT pGT, int iCol, int iTop, int iBottom, USHORT bChar, int bColor )
{
   int i_Width;
   int i_Height;
   int i_Row;
   int i_Col    = ( iCol < 0 ? 0 : iCol );
   int i_Top    = ( iTop < 0 ? 0 : iTop );
   int i_Bottom = ( iBottom < 0 ? 0 : iBottom );

   HB_SYMBOL_UNUSED( pGT );

   if( s_pWvwData->s_bMainCoordMode )
   {

      if( i_Top > i_Bottom )
      {
         int temp;
         temp     = i_Top;
         i_Top    = i_Bottom;
         i_Bottom = temp;
      }

      hb_gt_wvwFUNCPrologue( 3, &i_Top, &i_Col, &i_Bottom, NULL );
   }

   i_Width  = s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->COLS;
   i_Height = s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->ROWS;

   if( i_Col < i_Width )
   {

      if( i_Top >= i_Height )
         i_Top = i_Height - 1;

      if( i_Bottom >= i_Height )
         i_Bottom = i_Height - 1;
      if( i_Top <= i_Bottom )
         i_Row = i_Top;
      else
      {
         i_Row    = i_Bottom;
         i_Bottom = i_Top;
      }

      hb_gt_wvw_vDispBegin( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ] );

      while( i_Row <= i_Bottom )
         hb_gt_wvw_vxPutch( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], ( USHORT ) i_Row++, ( USHORT ) i_Col, bColor, bChar );

      hb_gt_wvw_vDispEnd( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ] );
   }

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCEpilogue();
}


static void hb_gt_wvw_OutStd( PHB_GT pGT, const char * pbyStr, HB_SIZE ulLen )
{
   HB_SYMBOL_UNUSED( pGT );
   hb_fsWriteLarge( s_iStdOut, ( BYTE * ) pbyStr, ulLen );
}


static void hb_gt_wvw_OutErr( PHB_GT pGT, const char * pbyStr, HB_SIZE ulLen )
{
   HB_SYMBOL_UNUSED( pGT );
   hb_fsWriteLarge( s_iStdErr, ( BYTE * ) pbyStr, ulLen );
}


static BOOL hb_gt_wvwGetCharFromInputQueue( int * c )
{
   UINT       uiWindow = s_pWvwData->s_usNumWindows - 1;
   WIN_DATA * pWindow  = s_pWvwData->s_pWindows[ uiWindow ];

/*
   int iNextPos;
   BOOL bRet = FALSE;

 * c = 0;

   iNextPos = ( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows-1 ]->keyPointerOut >= WVW_CHAR_QUEUE_SIZE - 1 ) ? 0 : s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows-1 ]->keyPointerOut+1 ;
   if ( iNextPos != s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows-1 ]->keyPointerIn )
   {
 * c = s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows-1 ]->Keys[ iNextPos ] ;
    s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows-1 ]->keyPointerOut = iNextPos ;
    bRet =  TRUE;
   }
   return( bRet );
 */
   if( pWindow->keyPointerOut != pWindow->keyPointerIn )
   {
      *c = pWindow->Keys[ pWindow->keyPointerOut ];
      if( ++pWindow->keyPointerOut >= WVW_CHAR_QUEUE_SIZE )
         pWindow->keyPointerOut = 0;
      return TRUE;
   }

   *c = 0;
   return FALSE;

}


static int hb_gt_wvw_ReadKey( PHB_GT pGT, int eventmask )
{
   int  c = 0;
   BOOL bKey;

   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_ReadKey( %d )", ( int ) eventmask ) );

   HB_SYMBOL_UNUSED( pGT );
   HB_SYMBOL_UNUSED( eventmask );

   hb_gt_wvwProcessMessages( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ] );

   bKey = hb_gt_wvwGetCharFromInputQueue( &c );

   return bKey ? c : 0;
}


/*                                                                   */
/* dDuration is in 'Ticks' (18.2 per second) */
/*                                                                   */
static void hb_gt_wvw_Tone( PHB_GT pGT, double dFrequency, double dDuration )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_Tone(%lf, %lf)", dFrequency, dDuration ) );

   HB_SYMBOL_UNUSED( pGT );

   hb_gt_winapi_tone( dFrequency, dDuration );
}


static void hb_gt_wvw_mouse_Init( PHB_GT pGT )
{
   HB_SYMBOL_UNUSED( pGT );
   hb_wvw_vmouse_Init();
   hb_gt_wvwCreateToolTipWindow( s_pWvwData->s_pWindows[ 0 ] );

}


static void hb_gt_wvw_mouse_Exit( PHB_GT pGT )
{
   HB_SYMBOL_UNUSED( pGT );
   hb_wvw_vmouse_Exit();
}


static BOOL hb_gt_wvw_mouse_IsPresent( PHB_GT pGT )
{
   HB_SYMBOL_UNUSED( pGT );
   return TRUE;
}


static int hb_gt_wvw_mouse_Col( PHB_GT pGT )
{
   HB_SYMBOL_UNUSED( pGT );
   if( s_pWvwData->s_bMainCoordMode )
      return hb_gt_wvwGetMouseX( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ] ) + hb_gt_wvwColOfs( s_pWvwData->s_usNumWindows - 1 );
   else
      return hb_gt_wvwGetMouseX( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ] );
}


static int hb_gt_wvw_mouse_Row( PHB_GT pGT )
{
   HB_SYMBOL_UNUSED( pGT );
   if( s_pWvwData->s_bMainCoordMode )
      return hb_gt_wvwGetMouseY( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ] ) + hb_gt_wvwRowOfs( s_pWvwData->s_usNumWindows - 1 );
   else
      return hb_gt_wvwGetMouseY( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ] );
}


static void hb_gt_wvw_mouse_SetPos( PHB_GT pGT, int iRow, int iCol )
{
   int i_Row = ( iRow < 0 ? 0 : iRow );
   int i_Col = ( iCol < 0 ? 0 : iCol );

   HB_SYMBOL_UNUSED( pGT );
   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCPrologue( 2, &i_Row, &i_Col, NULL, NULL );

   hb_wvw_vmouse_SetPos( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ], ( USHORT ) i_Row, ( USHORT ) i_Col );

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCEpilogue();

}


static void hb_gt_wvw_mouse_GetPos( PHB_GT pGT, int * piRow, int * piCol )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_mouse_GetPos(%p,%p,%p)", pGT, piRow, piCol ) );

   HB_SYMBOL_UNUSED( pGT );

   *piRow = hb_gt_wvw_mouse_Row( pGT );
   *piCol = hb_gt_wvw_mouse_Col( pGT );
}


static BOOL hb_gt_wvw_mouse_ButtonState( PHB_GT pGT, int iButton )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_mouse_ButtonState(%p,%i)", pGT, iButton ) );

   HB_SYMBOL_UNUSED( pGT );

   switch( iButton )
   {
      case 0:
         return ( GetKeyState( VK_LBUTTON ) & 0x8000 ) != 0;
      case 1:
         return ( GetKeyState( VK_RBUTTON ) & 0x8000 ) != 0;
      case 2:
         return ( GetKeyState( VK_MBUTTON ) & 0x8000 ) != 0;
   }
   return FALSE;
}


static int hb_gt_wvw_mouse_CountButton( PHB_GT pGT )
{
   HB_SYMBOL_UNUSED( pGT );
   return GetSystemMetrics( SM_CMOUSEBUTTONS );
}

/* *********************************************************************** */

/*WARNING: assume working on current window
 * NOTES: in MainCoord Mode current window is always the Main Window
 */
/* int gt_info(int iMsgType, BOOL bUpdate, int iParam, void *vpParam ) */
static BOOL hb_gt_wvw_Info( PHB_GT pGT, int iType, PHB_GT_INFO pInfo )
{
   WIN_DATA * pWindowData = s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ];
   int        iVal;

   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvw_Info(%p,%d,%p)", pGT, iType, pInfo ) );
   HB_SYMBOL_UNUSED( pGT );


   switch( iType )
   {
      case HB_GTI_ISSCREENPOS:
      case HB_GTI_KBDSUPPORT:
      case HB_GTI_ISGRAPHIC:
         pInfo->pResult = hb_itemPutL( pInfo->pResult, TRUE );
         break;

      case HB_GTI_ISUNICODE:
#if defined( UNICODE )
         pInfo->pResult = hb_itemPutL( pInfo->pResult, TRUE );
#else
         pInfo->pResult = hb_itemPutL( pInfo->pResult, FALSE );
#endif
         break;

      case HB_GTI_INPUTFD:
         pInfo->pResult = hb_itemPutNInt( pInfo->pResult,
                                          ( UINT_PTR ) GetStdHandle( STD_INPUT_HANDLE ) );
         break;

      case HB_GTI_OUTPUTFD:
         pInfo->pResult = hb_itemPutNInt( pInfo->pResult,
                                          ( UINT_PTR ) GetStdHandle( STD_OUTPUT_HANDLE ) );
         break;

      case HB_GTI_ERRORFD:
         pInfo->pResult = hb_itemPutNInt( pInfo->pResult,
                                          ( UINT_PTR ) GetStdHandle( STD_ERROR_HANDLE ) );
         break;

      case HB_GTI_FONTSIZE:
         pInfo->pResult = hb_itemPutNI( pInfo->pResult, pWindowData->PTEXTSIZE.y );
         iVal = hb_itemGetNI( pInfo->pNewVal );
         if( iVal > 0 )
         {
            HFONT hFont = hb_gt_wvwGetFont( pWindowData->fontFace, iVal, pWindowData->fontWidth, pWindowData->fontWeight, pWindowData->fontQuality, pWindowData->CodePage );
            /* make sure the font could actually be created */
            if( hFont )
            {
               pWindowData->fontHeight = iVal;
               /* is the window already opened? */
               if( pWindowData->hWnd )
               {
                  /* resize the window based on new fonts
                   */
                  hb_gt_wvwResetWindowSize( pWindowData, pWindowData->hWnd );

                  /* force resize of caret
                   */
                  hb_gt_wvwKillCaret( pWindowData );
                  hb_gt_wvwCreateCaret( pWindowData );
                  HB_GTSELF_REFRESH( hb_gt_Base() );
               }

               DeleteObject( hFont );
            }
         }
         break;

      case HB_GTI_FONTWIDTH:
         pInfo->pResult = hb_itemPutNI( pInfo->pResult, pWindowData->fontWidth );
         iVal = hb_itemGetNI( pInfo->pNewVal );
         if( iVal > 0 )
            /* store font status for next operation on fontsize */
            pWindowData->fontWidth = iVal;
         break;

      case HB_GTI_FONTNAME:
         pInfo->pResult = hb_itemPutC( pInfo->pResult, pWindowData->fontFace );
         if( hb_itemType( pInfo->pNewVal ) & HB_IT_STRING ) /* TODO */
            hb_strncpy( pWindowData->fontFace, hb_itemGetCPtr( pInfo->pNewVal ), LF_FACESIZE - 1 );
         break;

      case HB_GTI_FONTWEIGHT:
         switch( pWindowData->fontWeight )
         {
            case FW_THIN:
            case FW_EXTRALIGHT:
            case FW_LIGHT:
               iVal = HB_GTI_FONTW_THIN;
               break;

            case FW_DONTCARE:
            case FW_NORMAL:
            case FW_MEDIUM:
               iVal = HB_GTI_FONTW_NORMAL;
               break;

            case FW_SEMIBOLD:
            case FW_BOLD:
            case FW_EXTRABOLD:
            case FW_HEAVY:
               iVal = HB_GTI_FONTW_BOLD;
               break;

            default:
               iVal = 0;
               break;
         }
         pInfo->pResult = hb_itemPutNI( pInfo->pResult, iVal );
         if( hb_itemType( pInfo->pNewVal ) & HB_IT_NUMERIC )
         {
            /* store font status for next operation on fontsize */
            switch( hb_itemGetNI( pInfo->pNewVal ) )
            {
               case HB_GTI_FONTW_THIN:
                  pWindowData->fontWeight = FW_LIGHT;
                  break;
               case HB_GTI_FONTW_NORMAL:
                  pWindowData->fontWeight = FW_NORMAL;
                  break;
               case HB_GTI_FONTW_BOLD:
                  pWindowData->fontWeight = FW_BOLD;
                  break;
            }
         }
         break;

      case HB_GTI_FONTQUALITY:
         switch( pWindowData->fontQuality )
         {
            case ANTIALIASED_QUALITY:
               iVal = HB_GTI_FONTQ_HIGH;
               break;
            case DEFAULT_QUALITY:
            case DRAFT_QUALITY:
               iVal = HB_GTI_FONTQ_NORMAL;
               break;
            case NONANTIALIASED_QUALITY:
            case PROOF_QUALITY:
               iVal = HB_GTI_FONTQ_DRAFT;
               break;
            default:
               iVal = 0;
               break;
         }
         pInfo->pResult = hb_itemPutNI( pInfo->pResult, iVal );
         if( hb_itemType( pInfo->pNewVal ) & HB_IT_NUMERIC )
         {
            switch( hb_itemGetNI( pInfo->pNewVal ) )
            {
               case HB_GTI_FONTQ_HIGH:
                  pWindowData->fontQuality = ANTIALIASED_QUALITY;
                  break;
               case HB_GTI_FONTQ_NORMAL:
                  pWindowData->fontQuality = DEFAULT_QUALITY;
                  break;
               case HB_GTI_FONTQ_DRAFT:
                  pWindowData->fontQuality = DRAFT_QUALITY;
                  break;
            }
         }
         break;

      case HB_GTI_SCREENHEIGHT:
         /* NOTE 2004-06-18 currently not includes StatusBar and ToolBar, if any.
          * TODO            I Think it should return ALL window height, incl
          *                 StatusBar and ToolBar
          *                 ie. hb_gt_wvwCalcPixelHeight()
          * SEEALSO         hb_gt_wvwCalcPixelHeight()
          */

         /*NOTE 2004-07-19 screenheight includes linespacing, if any */


         pInfo->pResult = hb_itemPutNI( pInfo->pResult, hb_wvw_LineHeight( pWindowData ) * pWindowData->ROWS );
         iVal = hb_itemGetNI( pInfo->pNewVal );
         if( iVal > 0 )
            hb_gt_wvw_bSetMode( pWindowData, ( USHORT ) ( iVal / hb_wvw_LineHeight( pWindowData ) ), pWindowData->COLS );
         break;

      case HB_GTI_SCREENWIDTH:
         pInfo->pResult = hb_itemPutNI( pInfo->pResult, pWindowData->PTEXTSIZE.x * pWindowData->COLS );
         iVal = hb_itemGetNI( pInfo->pNewVal );
         if( iVal > 0 )
            hb_gt_wvw_bSetMode( pWindowData, pWindowData->ROWS, ( USHORT ) ( iVal / pWindowData->PTEXTSIZE.x ) );
         break;

      case HB_GTI_DESKTOPWIDTH:
      {
         RECT rDesk = { 0 };
         HWND hDesk;

         hDesk = GetDesktopWindow();
         GetWindowRect( hDesk, &rDesk );
         pInfo->pResult = hb_itemPutNI( pInfo->pResult, rDesk.right - rDesk.left );
         break;
      }

      case HB_GTI_DESKTOPHEIGHT:
      {
         /* NOTE 2004-06-18 currently includes StatusBar and ToolBar, if any.
          * TODO            Think: should it return chars area only?
          * SEEALSO         hb_gt_wvwCalcPixelHeight() - usSBHeight - usTBHeight
          */

         RECT rDesk = { 0 };
         HWND hDesk = GetDesktopWindow();
         GetWindowRect( hDesk, &rDesk );
         pInfo->pResult = hb_itemPutNI( pInfo->pResult, rDesk.bottom - rDesk.top );
         break;
      }

      case HB_GTI_DESKTOPCOLS:
      {
         RECT rDesk = { 0 };
         HWND hDesk;

         hDesk = GetDesktopWindow();
         GetClientRect( hDesk, &rDesk );

         pInfo->pResult = hb_itemPutNI( pInfo->pResult,
                                        ( rDesk.right - rDesk.left ) / pWindowData->PTEXTSIZE.x );
         break;
      }

      case HB_GTI_DESKTOPROWS:
      {
         /* NOTE 2004-06-18 currently includes StatusBar and ToolBar, if any.
          * TODO            I Think it should it return chars area only?
          * SEEALSO         hb_gt_wvwCalcPixelHeight() - usSBHeight - usTBHeight
          */

         /* NOTE 2004-07-19 screenheight includes linespacing, if any */

         RECT rDesk = { 0 };
         HWND hDesk;

         hDesk = GetDesktopWindow();
         GetClientRect( hDesk, &rDesk );

         pInfo->pResult = hb_itemPutNI( pInfo->pResult,
                                        ( rDesk.bottom - rDesk.top ) / hb_wvw_LineHeight( pWindowData ) );
         break;
      }
      case HB_GTI_WINTITLE:
         pInfo->pResult = hb_gt_wvw_GetWindowTitle( s_pWvwData->s_usCurWindow, pInfo->pResult );
         if( hb_itemType( pInfo->pNewVal ) & HB_IT_STRING )
         {
            void * hWindowTitle;
            hb_gt_wvwSetWindowTitle( s_pWvwData->s_usCurWindow, HB_ITEMGETSTR( pInfo->pNewVal, &hWindowTitle, NULL ) );
            hb_strfree( hWindowTitle );
         }
         break;
      case HB_GTI_CODEPAGE:
         pInfo->pResult = hb_itemPutNI( pInfo->pResult, pWindowData->CodePage );
         iVal = hb_itemGetNI( pInfo->pNewVal );
         if( iVal > 0 && iVal != pWindowData->CodePage )
            hb_gt_wvwSetCodePage( s_pWvwData->s_usCurWindow, iVal );
         break;

      case HB_GTI_ICONFILE:
      {
         HICON hIcon = NULL;
         if( hb_itemType( pInfo->pNewVal ) & HB_IT_STRING )
         {
            void * hImageName;
            hIcon = ( HICON ) hb_gt_wvwSetWindowIconFromFile( s_pWvwData->s_usCurWindow, HB_ITEMGETSTR( pInfo->pNewVal, &hImageName, NULL ) );
            hb_strfree( hImageName );
         }
         pInfo->pResult = hb_itemPutNInt( pInfo->pResult, ( UINT_PTR ) hIcon );
         break;
      }

      case HB_GTI_ICONRES:
      {
         HICON hIcon = NULL;
         if( hb_itemType( pInfo->pNewVal ) & HB_IT_STRING )
         {
            LPSTR lpIcon = ( LPSTR ) hb_itemGetCPtr( pInfo->pNewVal );
            hIcon = ( HICON ) hb_gt_wvwSetWindowIcon( s_pWvwData->s_usCurWindow, 0, ( char * ) lpIcon );
         }
         else if( hb_itemType( pInfo->pNewVal ) & HB_IT_NUMERIC )
            hIcon = ( HICON ) hb_gt_wvwSetWindowIcon( s_pWvwData->s_usCurWindow, hb_itemGetNI( pInfo->pNewVal ), NULL );
         pInfo->pResult = hb_itemPutNInt( pInfo->pResult, ( UINT_PTR ) hIcon );
         break;
      }

      /* TODO: these two doesn't seem right. see gtwin about what they're supposed to do */
      case HB_GTI_VIEWMAXWIDTH:
         pInfo->pResult = hb_itemPutNI( pInfo->pResult, pWindowData->COLS );
         break;

      case HB_GTI_VIEWMAXHEIGHT:
         pInfo->pResult = hb_itemPutNI( pInfo->pResult, pWindowData->ROWS );
         break;

      case HB_GTI_KBDSHIFTS:
         pInfo->pResult = hb_itemPutNI( pInfo->pResult, hb_gt_winapi_getKbdState() );
         if( hb_itemType( pInfo->pNewVal ) & HB_IT_NUMERIC )
            hb_gt_winapi_setKbdState( hb_itemGetNI( pInfo->pNewVal ) );
         break;

      case HB_GTI_CLIPBOARDDATA:
         if( hb_itemType( pInfo->pNewVal ) & HB_IT_STRING )
#if defined( UNICODE )
            hb_gt_winapi_setClipboard( CF_UNICODETEXT, pInfo->pNewVal );
#else
            hb_gt_winapi_setClipboard( pWindowData->CodePage == OEM_CHARSET ?
                                       CF_OEMTEXT : CF_TEXT, pInfo->pNewVal );
#endif
         else
         {
            if( pInfo->pResult == NULL )
               pInfo->pResult = hb_itemNew( NULL );
#if defined( UNICODE )
            hb_gt_winapi_getClipboard( CF_UNICODETEXT, pInfo->pResult );
#else
            hb_gt_winapi_getClipboard( pWindowData->CodePage == OEM_CHARSET ?
                                       CF_OEMTEXT : CF_TEXT, pInfo->pResult );
#endif
         }
         break;

      case HB_GTI_CURSORBLINKRATE:
         pInfo->pResult = hb_itemPutNI( pInfo->pResult, GetCaretBlinkTime() );
         if( hb_itemType( pInfo->pNewVal ) & HB_IT_NUMERIC )
            SetCaretBlinkTime( hb_itemGetNI( pInfo->pNewVal ) );
         break;

      case HB_GTI_SCREENSIZE:
      {
         int iX, iY;

         if( ! pInfo->pResult )
            pInfo->pResult = hb_itemNew( NULL );
         hb_arrayNew( pInfo->pResult, 2 );
         hb_itemPutNI( hb_arrayGetItemPtr( pInfo->pResult, 2 ), pWindowData->PTEXTSIZE.y * pWindowData->ROWS );
         hb_itemPutNI( hb_arrayGetItemPtr( pInfo->pResult, 1 ), pWindowData->PTEXTSIZE.x * pWindowData->COLS );
         iY = hb_itemGetNI( hb_arrayGetItemPtr( pInfo->pNewVal, 2 ) );
         iX = hb_itemGetNI( hb_arrayGetItemPtr( pInfo->pNewVal, 1 ) );

         if( iY > 0 )
#if 0
            BOOL bOldCentre = pWindowData->CentreWindow;
         pWVT->CentreWindow = pWVT->bMaximized ? TRUE : FALSE;
#endif
            hb_gt_wvw_bSetMode( pWindowData, ( USHORT ) ( iY / pWindowData->PTEXTSIZE.y ), ( USHORT ) ( iX / pWindowData->PTEXTSIZE.x ) );
         /* pWindowData->CentreWindow = bOldCentre; */
         break;
      }

      case HB_GTI_PALETTE:
         if( hb_itemType( pInfo->pNewVal ) & HB_IT_NUMERIC )
         {
            int iIndex = hb_itemGetNI( pInfo->pNewVal );

            if( iIndex > 0 && iIndex <= 16 )
            {
               pInfo->pResult = hb_itemPutNL( pInfo->pResult, _COLORS[ iIndex - 1 ] );

               if( hb_itemType( pInfo->pNewVal2 ) & HB_IT_NUMERIC )
                  _COLORS[ iIndex - 1 ] = hb_itemGetNL( pInfo->pNewVal2 );
            }
         }
         else
         {
            int i;
            if( ! pInfo->pResult )
               pInfo->pResult = hb_itemNew( NULL );
            hb_arrayNew( pInfo->pResult, 16 );
            for( i = 1; i <= 16; i++ )
               hb_itemPutNL( hb_arrayGetItemPtr( pInfo->pResult, i ), _COLORS[ i - 1 ] );

            if( hb_itemType( pInfo->pNewVal ) & HB_IT_ARRAY )
               if( hb_arrayLen( pInfo->pNewVal ) == 16 )
                  for( i = 0; i < 16; i++ )
                     _COLORS[ i ] = hb_arrayGetNL( pInfo->pNewVal, i + 1 );

         }
         break;
      default:
         return HB_GTSUPER_INFO( hb_gt_Base(), iType, pInfo );
   }

   return TRUE;
}

/* ********** Graphics API ********** */

/*
 * NOTE:
 *      GfxPrimitive() parameters may have different meanings
 *      ie: - Desired color is 'iBottom' for PUTPIXEL and 'iRight' for CIRCLE
 *          - Red is iTop, Green iLeft and Blue is iBottom for MAKECOLOR
 *
 */

#define SetGFXContext()  hPen = CreatePen( PS_SOLID, 1, color ); hOldPen = ( HPEN ) SelectObject( hdc, hPen ); hBrush = ( HBRUSH ) CreateSolidBrush( color ); hOldBrush = ( HBRUSH ) SelectObject( hdc, hBrush ); bOut = TRUE

/*WARNING: assume working on current window
 * NOTES: in MainCoord Mode current window is always the Main Window
 */

static int hb_gt_wvw_gfxPrimitive( PHB_GT pGT, int iType, int iTop, int iLeft, int iBottom, int iRight, int iColor )
{
   COLORREF   color;
   HPEN       hPen   = NULL, hOldPen = NULL;
   HBRUSH     hBrush = NULL, hOldBrush = NULL;
   HDC        hdc;
   BOOL       bOut        = FALSE;
   int        iRet        = 0;
   WIN_DATA * pWindowData = s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ];

   HB_SYMBOL_UNUSED( pGT );

   hdc = GetDC( pWindowData->hWnd );

   switch( iType )
   {
      case HB_GFX_ACQUIRESCREEN:
      case HB_GFX_RELEASESCREEN:
         ReleaseDC( pWindowData->hWnd, hdc );
         return 1;
      case HB_GFX_MAKECOLOR:
         ReleaseDC( pWindowData->hWnd, hdc );
         return ( int ) ( iTop << 16 | iLeft << 8 | iBottom );
      case HB_GFX_PUTPIXEL:
         color = RGB( iBottom >> 16, ( iBottom & 0xFF00 ) >> 8, iBottom & 0xFF );
         SetGFXContext();

         MoveToEx( hdc, iLeft, iTop, NULL );
         LineTo( hdc, iLeft, iTop );

         iRet = 1;
         break;
      case HB_GFX_LINE:
         color = RGB( iColor >> 16, ( iColor & 0xFF00 ) >> 8, iColor & 0xFF );
         SetGFXContext();

         MoveToEx( hdc, iLeft, iTop, NULL );
         LineTo( hdc, iRight, iBottom );

         iRet = 1;
         break;
      case HB_GFX_RECT:
      {
         RECT r = { 0 };
         r.left   = iLeft;
         r.top    = iTop;
         r.right  = iRight;
         r.bottom = iBottom;

         color = RGB( iColor >> 16, ( iColor & 0xFF00 ) >> 8, iColor & 0xFF );
         SetGFXContext();

         FrameRect( hdc, &r, hBrush );

         iRet = 1;
      }
      break;
      case HB_GFX_FILLEDRECT:
         color = RGB( iColor >> 16, ( iColor & 0xFF00 ) >> 8, iColor & 0xFF );
         SetGFXContext();

         Rectangle( hdc, iLeft, iTop, iRight, iBottom );

         iRet = 1;
         break;
      case HB_GFX_CIRCLE:
         color = RGB( iRight >> 16, ( iRight & 0xFF00 ) >> 8, iRight & 0xFF );
         SetGFXContext();

         Arc( hdc, iLeft - iBottom / 2, iTop - iBottom / 2, iLeft + iBottom / 2, iTop + iBottom / 2, 0, 0, 0, 0 );

         iRet = 1;
         break;
      case HB_GFX_FILLEDCIRCLE:
         color = RGB( iRight >> 16, ( iRight & 0xFF00 ) >> 8, iRight & 0xFF );
         SetGFXContext();

         Ellipse( hdc, iLeft - iBottom / 2, iTop - iBottom / 2, iLeft + iBottom / 2, iTop + iBottom / 2 );

         iRet = 1;
         break;
      case HB_GFX_ELLIPSE:
         color = RGB( iColor >> 16, ( iColor & 0xFF00 ) >> 8, iColor & 0xFF );
         SetGFXContext();

         Arc( hdc, iLeft - iRight / 2, iTop - iBottom / 2, iLeft + iRight / 2, iTop + iBottom / 2, 0, 0, 0, 0 );

         iRet = 1;
         break;
      case HB_GFX_FILLEDELLIPSE:
         color = RGB( iColor >> 16, ( iColor & 0xFF00 ) >> 8, iColor & 0xFF );
         SetGFXContext();

         Ellipse( hdc, iLeft - iRight / 2, iTop - iBottom / 2, iLeft + iRight / 2, iTop + iBottom / 2 );

         iRet = 1;
         break;
      case HB_GFX_FLOODFILL:
         color = RGB( iBottom >> 16, ( iBottom & 0xFF00 ) >> 8, iBottom & 0xFF );
         SetGFXContext();

         FloodFill( hdc, iLeft, iTop, iColor );

         iRet = 1;
         break;
   }

   if( bOut )
   {
      SelectObject( hdc, hOldPen );
      SelectObject( hdc, hOldBrush );
      DeleteObject( hBrush );
      DeleteObject( hPen );
   }

   ReleaseDC( pWindowData->hWnd, hdc );
   return iRet;
}

void gt_gfxText( int iTop, int iLeft, char * cBuf, int iColor, int iSize, int iWidth )
{
   HB_SYMBOL_UNUSED( iTop );
   HB_SYMBOL_UNUSED( iLeft );
   HB_SYMBOL_UNUSED( cBuf );
   HB_SYMBOL_UNUSED( iColor );
   HB_SYMBOL_UNUSED( iSize );
   HB_SYMBOL_UNUSED( iWidth );
}

/* ******** Graphics API end ******** */

/*
 *
 *                 Modeless Dialogs Implementation
 *                 copied and modified from Pritpal Bedi's work in GTWVT
 *
 */

BOOL CALLBACK hb_gt_wvwDlgProcMLess( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
   int      iIndex, iType;
   long int bReturn = FALSE;
   PHB_ITEM pFunc   = NULL;


   iType = ( int ) NULL;

   for( iIndex = 0; iIndex < WVW_DLGML_MAX; iIndex++ )
      if( ( s_pWvwData->s_sApp->hDlgModeless[ iIndex ] != NULL ) && ( s_pWvwData->s_sApp->hDlgModeless[ iIndex ] == hDlg ) )
      {
         if( s_pWvwData->s_sApp->pFunc[ iIndex ] != NULL )
         {
            pFunc = s_pWvwData->s_sApp->pFunc[ iIndex ];
            iType = s_pWvwData->s_sApp->iType[ iIndex ];
         }
         break;
      }

   if( pFunc )
   {
      switch( iType )
      {
         case 1:
            if( hb_vmRequestReenter() )
            {
               hb_vmPushDynSym( ( PHB_DYNS ) pFunc );
               hb_vmPushNil();
               hb_vmPushNumInt( ( HB_MAXINT ) ( HB_PTRDIFF ) hDlg );
               hb_vmPushNumInt( message );
               hb_vmPushNumInt( wParam  );
               hb_vmPushNumInt( lParam  );
               hb_vmDo( 4 );

               bReturn = hb_parnl( -1 );
               hb_vmRequestRestore();
            }
            break;

         case 2:

            /* eval the codeblock */

            /*

               if (s_pWvwData->s_sApp->pFunc[ iIndex ]->type == HB_IT_BLOCK)
               {
               HB_ITEM hihDlg, himessage, hiwParam, hilParam;
               PHB_ITEM pReturn;

               hihDlg.type = HB_IT_NIL;
               hb_itemPutNL( &hihDlg, (ULONG) hDlg );

               himessage.type = HB_IT_NIL;
               hb_itemPutNL( &himessage, (ULONG) message );

               hiwParam.type = HB_IT_NIL;
               hb_itemPutNL( &hiwParam, (ULONG) wParam );

               hilParam.type = HB_IT_NIL;
               hb_itemPutNL( &hilParam, (ULONG) lParam );

               pReturn = hb_itemDo( (PHB_ITEM) s_pWvwData->s_sApp->pFunc[ iIndex ], 4, &hihDlg, &himessage, &hiwParam, &hilParam );

               bReturn = hb_itemGetNL( pReturn );
               hb_itemRelease( pReturn );

               }
             */
            if( HB_IS_BLOCK( pFunc ) )
            {
               if( hb_vmRequestReenter() )
               {
                  hb_vmPushEvalSym();
                  hb_vmPush( s_pWvwData->s_sApp->pFunc[ iIndex ] );
                  hb_vmPushNumInt( ( HB_MAXINT ) ( HB_PTRDIFF ) hDlg );
                  hb_vmPushNumInt( message );
                  hb_vmPushNumInt( wParam );
                  hb_vmPushNumInt( lParam );
                  hb_vmSend( 4 );
                  bReturn = hb_parnl( -1 );
                  hb_vmRequestRestore();
               }
            }
            else
            {

            }

            break;
      }
   }

   switch( message )
   {
      case WM_COMMAND:
         switch( LOWORD( wParam ) )
         {
            case IDOK:
               DestroyWindow( hDlg );
               bReturn = TRUE;
               break;

            case IDCANCEL:
               DestroyWindow( hDlg );
               bReturn = FALSE;
               break;
         }
         break;

      case WM_CLOSE:
         DestroyWindow( hDlg );
         bReturn = FALSE;
         break;

      case WM_NCDESTROY:
         if( s_pWvwData->s_sApp->pFunc[ iIndex ] != NULL && s_pWvwData->s_sApp->iType[ iIndex ] == 2 )
            hb_itemRelease( s_pWvwData->s_sApp->pFunc[ iIndex ] );

         s_pWvwData->s_sApp->hDlgModeless[ iIndex ] = NULL;

         s_pWvwData->s_sApp->pFunc[ iIndex ] = NULL;
         s_pWvwData->s_sApp->iType[ iIndex ] = ( int ) NULL;
         bReturn = FALSE;
         break;
   }

   return bReturn;
}


BOOL CALLBACK hb_gt_wvwDlgProcModal( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
   int      iIndex, iType;
   long int bReturn = FALSE;
   PHB_ITEM pFunc   = NULL;

   int iFirst = ( int ) lParam;

   if( iFirst > 0 && iFirst <= WVW_DLGMD_MAX )
   {
      s_pWvwData->s_sApp->hDlgModal[ iFirst - 1 ] = hDlg;
      SendMessage( hDlg, WM_INITDIALOG, 0, 0 );
      return bReturn;
   }

   iType = ( int ) NULL;

   for( iIndex = 0; iIndex < WVW_DLGMD_MAX; iIndex++ )
      if( ( s_pWvwData->s_sApp->hDlgModal[ iIndex ] != NULL ) && ( s_pWvwData->s_sApp->hDlgModal[ iIndex ] == hDlg ) )
      {
         if( s_pWvwData->s_sApp->pFuncModal[ iIndex ] != NULL )
         {
            pFunc = s_pWvwData->s_sApp->pFuncModal[ iIndex ];
            iType = s_pWvwData->s_sApp->iTypeModal[ iIndex ];
         }
         break;
      }

   if( pFunc )
   {
      switch( iType )
      {
         case 1:
            if( hb_vmRequestReenter() )
            {
               hb_vmPushDynSym( ( PHB_DYNS ) pFunc );

               hb_vmPushNil();
               hb_vmPushNumInt( ( HB_MAXINT ) ( HB_PTRDIFF ) hDlg    );
               hb_vmPushNumInt( message );
               hb_vmPushNumInt( wParam  );
               hb_vmPushNumInt( lParam  );
               hb_vmDo( 4 );

               bReturn = hb_parnl( -1 );
               hb_vmRequestRestore();
            }
            break;

         case 2:
            /* eval the codeblock */
            /*
               if (s_pWvwData->s_sApp->pFuncModal[ iIndex ]->type == HB_IT_BLOCK )
               {
               HB_ITEM hihDlg, himessage, hiwParam, hilParam;
               PHB_ITEM pReturn;

               hihDlg.type = HB_IT_NIL;
               hb_itemPutNL( &hihDlg, (ULONG) hDlg );

               himessage.type = HB_IT_NIL;
               hb_itemPutNL( &himessage, (ULONG) message );

               hiwParam.type = HB_IT_NIL;
               hb_itemPutNL( &hiwParam, (ULONG) wParam );

               hilParam.type = HB_IT_NIL;
               hb_itemPutNL( &hilParam, (ULONG) lParam );

               pReturn = hb_itemDo( (PHB_ITEM) s_pWvwData->s_sApp->pFuncModal[ iIndex ], 4, &hihDlg, &himessage, &hiwParam, &hilParam );
               bReturn = hb_itemGetNL( pReturn );
               hb_itemRelease( pReturn );
               }
             */
            if( HB_IS_BLOCK( pFunc ) )
            {
               if( hb_vmRequestReenter() )
               {
                  hb_vmPushEvalSym();
                  hb_vmPush( pFunc );
                  hb_vmPushNumInt( ( HB_MAXINT ) ( HB_PTRDIFF ) hDlg );
                  hb_vmPushNumInt( message );
                  hb_vmPushNumInt( wParam );
                  hb_vmPushNumInt( lParam );
                  hb_vmSend( 4 );
                  bReturn = hb_parnl( -1 );
                  hb_vmRequestRestore();
               }
            }
            else
            {

            }

            break;
      }
   }

   switch( message )
   {
      case WM_COMMAND:
         switch( LOWORD( wParam ) )
         {
            case IDOK:
               EndDialog( hDlg, IDOK );
               bReturn = TRUE;
               break;

            case IDCANCEL:
               EndDialog( hDlg, IDCANCEL );
               bReturn = FALSE;
               break;
         }
         break;

      case WM_CLOSE:
         EndDialog( hDlg, IDCANCEL );
         bReturn = FALSE;
         break;

      case WM_NCDESTROY:
         if( s_pWvwData->s_sApp->pFuncModal[ iIndex ] != NULL && s_pWvwData->s_sApp->iTypeModal[ iIndex ] == 2 )
            hb_itemRelease( s_pWvwData->s_sApp->pFuncModal[ iIndex ] );

         s_pWvwData->s_sApp->hDlgModal[ iIndex ]  = NULL;
         s_pWvwData->s_sApp->pFuncModal[ iIndex ] = NULL;
         s_pWvwData->s_sApp->iTypeModal[ iIndex ] = ( int ) NULL;
         bReturn = FALSE;
         break;
   }

   return bReturn;
}


/*                                                                   */
/*                    WVW specific functions                         */
/*                                                                   */


static void hb_gt_wvwCreateObjects( UINT usWinNum )
{
   LOGBRUSH lb = { 0 };

   /* 2004-09-21 IMPORTANT:
      All these PENs and BRUSHes creations are temporarily disabled
      because WINDOW #1's CAN'T BE DELETED LATER!
      See also hb_gt_wvwCloseWindow() and gt_Exit()
      TODO: pls choose:
      (1) store PENs and BRUSHes as application-wide
      or
      (2) do the creation and deletion only when required
    */
   /* 2004-09-23 choose #1 of above option */
   if( usWinNum > 0 )
      return;

   s_pWvwData->s_sApp->penWhite    = CreatePen( PS_SOLID, 0, ( COLORREF ) RGB( 255, 255, 255 ) );
   s_pWvwData->s_sApp->penBlack    = CreatePen( PS_SOLID, 0, ( COLORREF ) RGB(   0, 0, 0 ) );
   s_pWvwData->s_sApp->penWhiteDim = CreatePen( PS_SOLID, 0, ( COLORREF ) RGB( 205, 205, 205 ) );
   s_pWvwData->s_sApp->penDarkGray = CreatePen( PS_SOLID, 0, ( COLORREF ) RGB( 150, 150, 150 ) );
   s_pWvwData->s_sApp->penGray     = CreatePen( PS_SOLID, 0, ( COLORREF ) _COLORS[ 7 ] );
   s_pWvwData->s_sApp->penNull     = CreatePen( PS_NULL, 0, ( COLORREF ) _COLORS[ 7 ] );
   s_pWvwData->s_sApp->currentPen  = CreatePen( PS_SOLID, 0, ( COLORREF ) RGB(   0, 0, 0 ) );

   lb.lbStyle = BS_NULL;
   lb.lbColor = RGB( 198, 198, 198 );
   lb.lbHatch = 0;
   s_pWvwData->s_sApp->currentBrush = CreateBrushIndirect( &lb );

   lb.lbStyle = BS_HATCHED;
   lb.lbColor = RGB( 210, 210, 210 );
   lb.lbHatch = HS_DIAGCROSS;                          /* HS_BDIAGONAL; */
   s_pWvwData->s_sApp->diagonalBrush = CreateBrushIndirect( &lb );

   lb.lbStyle = BS_SOLID;
   lb.lbColor = 0;                          /* RGB( 0,0,0 ); */
   lb.lbHatch = 0;
   s_pWvwData->s_sApp->solidBrush = CreateBrushIndirect( &lb );

   lb.lbStyle = BS_SOLID;
   lb.lbColor = _COLORS[ 7 ];
   lb.lbHatch = 0;
   s_pWvwData->s_sApp->wvwWhiteBrush = CreateBrushIndirect( &lb );

}


/*NOTE/TODO: this doesn't take MenuBar into account */
static USHORT hb_gt_wvwCalcPixelHeight( WIN_DATA * pWindowData )
{

   return hb_wvw_LineHeight( pWindowData ) * pWindowData->ROWS +
          pWindowData->usSBHeight +
          pWindowData->usTBHeight;
}


static USHORT hb_gt_wvwCalcPixelWidth( WIN_DATA * pWindowData )
{
   return ( USHORT ) pWindowData->PTEXTSIZE.x * pWindowData->COLS;
}


static BOOL hb_gt_wvwAllocSpBuffer( WIN_DATA * pWindowData, USHORT col, USHORT row )
{
   BOOL bRet = TRUE;

   pWindowData->COLS       = col;
   pWindowData->ROWS       = row;
   pWindowData->BUFFERSIZE = col * row * sizeof( char );
   pWindowData->pBuffer    = pWindowData->byBuffer;
   pWindowData->pColors    = pWindowData->byColors;


   memset( pWindowData->pBuffer, ' ', pWindowData->BUFFERSIZE );

   if( pWindowData->byWinId == 0 )
      memset( pWindowData->pColors, 0x07, pWindowData->BUFFERSIZE );

   else
      memset( pWindowData->pColors, hb_gtGetCurrColor(), pWindowData->BUFFERSIZE );

   return bRet;
}


static BOOL hb_gt_wvwInitWindow( WIN_DATA * pWindowData, HWND hWnd, USHORT col, USHORT row )
{

   BOOL bRet = hb_gt_wvwAllocSpBuffer( pWindowData, col, row );

   hb_gt_wvwResetWindowSize( pWindowData, hWnd );

   return bRet;
}


/* WVT commented out this function. WVW is still using it. */

static BOOL hb_gt_wvwValidWindowSize( WIN_DATA * pWindowData, int rows, int cols, HFONT hFont, int iWidth,
                                      int * pmaxrows, int * pmaxcols )
{
   HDC        hdc;
   HFONT      hOldFont;
   USHORT     width, height, maxWidth, maxHeight;
   USHORT     diffHeight, diffWidth;
   TEXTMETRIC tm         = { 0 };
   RECT       rcWorkArea = { 0 };

   RECT wi = { 0 }, ci = { 0 };

   SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWorkArea, 0 );

   maxWidth  = ( SHORT ) ( rcWorkArea.right - rcWorkArea.left + 1 );
   maxHeight = ( SHORT ) ( rcWorkArea.bottom - rcWorkArea.top + 1 );

   hdc      = GetDC( pWindowData->hWnd );
   hOldFont = ( HFONT ) SelectObject( hdc, hFont );
   GetTextMetrics( hdc, &tm );
   SelectObject( hdc, hOldFont );

   ReleaseDC( pWindowData->hWnd, hdc );

   width  = ( iWidth < 0 ? ( USHORT ) -iWidth : ( USHORT ) ( ( USHORT ) ( LONG ) ( tm.tmAveCharWidth ) ) ) * ( USHORT ) cols;    /* Total pixel width this setting would take */
   height = ( USHORT ) ( ( USHORT ) ( LONG ) ( tm.tmHeight ) ) * ( USHORT ) rows;                                                /* Total pixel height this setting would take */

   GetWindowRect( pWindowData->hWnd, &wi );
   GetClientRect( pWindowData->hWnd, &ci );

   diffWidth  = ( SHORT ) ( ( wi.right - wi.left ) - ( ci.right ) );
   diffHeight = ( SHORT ) ( ( wi.bottom - wi.top ) - ( ci.bottom ) );
   width     += diffWidth;
   height    += diffHeight;

   height += ( USHORT ) ( pWindowData->byLineSpacing * rows );

   height += pWindowData->usTBHeight;

   height += pWindowData->usSBHeight;

   /* TODO: should also calc menu */

   /* before returning, put the max possible rows/cols to pmaxrows/pmaxcols */
   if( pmaxrows )
      ( *pmaxrows ) = ( maxHeight - diffHeight - pWindowData->usTBHeight - pWindowData->usSBHeight ) /
                      hb_wvw_LineHeight( pWindowData );
   if( pmaxcols )
      ( *pmaxcols ) = ( maxWidth - diffWidth ) /
                      ( iWidth < 0 ? -iWidth : tm.tmAveCharWidth );

   return ( width <= maxWidth ) && ( height <= maxHeight );
}


static void hb_gt_wvwResetWindowSize( WIN_DATA * pWindowData, HWND hWnd )
{
   HDC        hdc;
   HFONT      hFont, hOldFont;
   USHORT     diffWidth, diffHeight;
   USHORT     height, width;
   RECT       wi = { 0 }, ci = { 0 };
   TEXTMETRIC tm = { 0 };

   RECT       rcWorkArea       = { 0 };
   RECT       rcMainClientArea = { 0 };
   int        n;
   WIN_DATA * pMainWindow;

   pMainWindow = s_pWvwData->s_pWindows[ 0 ];

   /* set the font and get it's size to determine the size of the client area
    * for the required number of rows and columns
    */
   hdc   = GetDC( hWnd );
   hFont = hb_gt_wvwGetFont( pWindowData->fontFace, pWindowData->fontHeight, pWindowData->fontWidth, pWindowData->fontWeight, pWindowData->fontQuality, pWindowData->CodePage );

   if( pWindowData->hFont )
      DeleteObject( ( HFONT ) pWindowData->hFont );

   pWindowData->hFont = hFont;
   hOldFont = ( HFONT ) SelectObject( hdc, hFont );

   GetTextMetrics( hdc, &tm );
   SetTextCharacterExtra( hdc, 0 ); /* do not add extra char spacing even if bold */

   SelectObject( hdc, hOldFont );
   ReleaseDC( hWnd, hdc );

   /* we will need to use the font size to handle the transformations from
    * row column space in the future, so we keep it around in a static!
    */

   pWindowData->PTEXTSIZE.x = pWindowData->fontWidth < 0 ? -pWindowData->fontWidth : tm.tmAveCharWidth;     /* For fixed FONT should == tm.tmMaxCharWidth */
   pWindowData->PTEXTSIZE.y = tm.tmHeight;                                                                  /*     but seems to be a problem on Win9X so */
   /*     assume proportional fonts always for Win9X */

   if( pWindowData->fontWidth < 0 || s_pWvwData->s_sApp->Win9X || ( tm.tmPitchAndFamily & TMPF_FIXED_PITCH ) || ( pWindowData->PTEXTSIZE.x != tm.tmMaxCharWidth ) )
      pWindowData->FixedFont = FALSE;
   else
      pWindowData->FixedFont = TRUE;

   for( n = 0; n < pWindowData->COLS; n++ ) /* pWindowData->FixedSize[] is used by ExtTextOut() to emulate */                            /*          fixed font when a proportional font is used */
      pWindowData->FixedSize[ n ] = pWindowData->PTEXTSIZE.x;

   if( IsZoomed( pWindowData->hWnd ) )
   {

      if( SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWorkArea, 0 ) )
      {
         wi.top    = rcWorkArea.top;
         wi.left   = rcWorkArea.left;
         wi.bottom = rcWorkArea.bottom;
         wi.right  = rcWorkArea.right;
      }
      else
         GetWindowRect( hWnd, &wi );

      height = ( ( USHORT ) ( LONG ) ( wi.bottom ) ) - ( ( USHORT ) ( LONG ) ( wi.top ) ) + 1;
      width  = ( ( USHORT ) ( LONG ) ( wi.right ) ) - ( ( USHORT ) ( LONG ) ( wi.left ) ) + 1;

   }
   else if( pWindowData->byWinId == 0 )
   {
      /* resize the window to get the specified number of rows and columns
       */
      height = hb_gt_wvwCalcPixelHeight( pWindowData );
      width  = hb_gt_wvwCalcPixelWidth( pWindowData );

      GetWindowRect( hWnd, &wi );
      GetClientRect( hWnd, &ci );

      diffWidth  = ( SHORT ) ( ( wi.right - wi.left ) - ( ci.right ) );
      diffHeight = ( SHORT ) ( ( wi.bottom - wi.top ) - ( ci.bottom ) );
      width     += diffWidth;
      height    += diffHeight;

      /* Centre the window within the CLIENT area on the screen
       *                   but only if pWindowData->CentreWindow == TRUE
       */

#if 0
      if( pWindowData->CentreWindow && SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWorkArea, 0 ) )
      {
         wi.left = rcWorkArea.left + ( ( ( rcWorkArea.right - rcWorkArea.left ) - ( width ) ) / 2 );
         wi.top  = rcWorkArea.top + ( ( ( rcWorkArea.bottom - rcWorkArea.top ) - ( height ) ) / 2 );
      }
#endif

      if( SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWorkArea, 0 ) )
      {
         if( pWindowData->CentreWindow )
         {
            wi.left = rcWorkArea.left + ( ( ( rcWorkArea.right - rcWorkArea.left ) - ( width ) ) / 2 );
            wi.top  = rcWorkArea.top + ( ( ( rcWorkArea.bottom - rcWorkArea.top ) - ( height ) ) / 2 );
         }
         else
         {
            if( pWindowData->HCentreWindow )
               wi.left = rcWorkArea.left + ( ( ( rcWorkArea.right - rcWorkArea.left ) - ( width ) ) / 2 );
            if( pWindowData->VCentreWindow )
               wi.top = rcWorkArea.top + ( ( ( rcWorkArea.bottom - rcWorkArea.top ) - ( height ) ) / 2 );
         }
      }
   }
   else
   {
      /* resize the window to get the specified number of rows and columns
       */
      height = hb_gt_wvwCalcPixelHeight( pWindowData );
      width  = hb_gt_wvwCalcPixelWidth( pWindowData );

      GetWindowRect( hWnd, &wi );
      GetClientRect( hWnd, &ci );

      diffWidth  = ( SHORT ) ( ( wi.right - wi.left ) - ( ci.right ) );
      diffHeight = ( SHORT ) ( ( wi.bottom - wi.top ) - ( ci.bottom ) );
      width     += diffWidth;
      height    += diffHeight;

      /* Centre the window within the area of the MAIN WINDOW
       *                   but only if pWindowData->CentreWindow == TRUE
       */
      GetWindowRect( ( *pMainWindow ).hWnd, &rcWorkArea );
      GetClientRect( ( *pMainWindow ).hWnd, &rcMainClientArea );

      if( pWindowData->CentreWindow )
      {
         wi.left = rcWorkArea.left + ( ( ( rcWorkArea.right - rcWorkArea.left ) - ( width ) ) / 2 );
         wi.top  = rcWorkArea.top + ( ( ( rcWorkArea.bottom - rcWorkArea.top ) - ( height ) ) / 2 );
      }
      else
      {
         if( pWindowData->HCentreWindow )
            wi.left = rcWorkArea.left + ( ( ( rcWorkArea.right - rcWorkArea.left ) - ( width ) ) / 2 );
         else
            wi.left = rcWorkArea.left + ( pWindowData->usColOfs * ( *pMainWindow ).PTEXTSIZE.x );

         if( pWindowData->VCentreWindow )
            wi.top = rcWorkArea.top + ( ( ( rcWorkArea.bottom - rcWorkArea.top ) - ( height ) ) / 2 );
         else
         {
            wi.top = rcWorkArea.top + ( pWindowData->usRowOfs * hb_wvw_LineHeight( pMainWindow ) );

            wi.top -= diffHeight;

            wi.top += ( ( rcWorkArea.bottom - rcWorkArea.top ) - ( rcMainClientArea.bottom ) );

            wi.top += ( *pMainWindow ).usTBHeight;

            wi.top -= ( *pWindowData ).usTBHeight;
         }
      }
   }

   if( ! IsZoomed( hWnd ) )
      SetWindowPos( hWnd, NULL, wi.left, wi.top, width, height, SWP_NOZORDER );
   else
   {
      SetWindowPos( hWnd, NULL, wi.left, wi.top, width, height, SWP_NOZORDER );
      InvalidateRect( hWnd, NULL, FALSE );
   }

   if( pWindowData->hStatusBar != NULL )
      SetWindowPos( pWindowData->hStatusBar, NULL, wi.left, wi.bottom - pWindowData->usSBHeight, width, pWindowData->usSBHeight, SWP_NOZORDER );

   if( pWindowData->hToolBar != NULL )
      SetWindowPos( pWindowData->hToolBar, NULL, wi.left, wi.top - pWindowData->usTBHeight, width, pWindowData->usTBHeight, SWP_NOZORDER );

   if( pWindowData->pcdCtrlList != NULL )
      ReposControls( pWindowData->byWinId, 0 );

   if( pWindowData->byWinId == s_pWvwData->s_usNumWindows - 1 )
      hb_gt_wvwSetCaretPos( pWindowData );

   if( pWindowData->byWinId == 0 )
      HB_GTSELF_RESIZE( hb_gt_Base(), pWindowData->ROWS, pWindowData->COLS );
}


static int hb_wvw_key_ansi_to_oem( int c )
{
   char pszAnsi[ 4 ];
   char pszOem[ 4 ];

   sprintf( pszAnsi, "%c", c );
   CharToOemBuff( ( LPCSTR ) pszAnsi, ( LPTSTR ) pszOem, 1 );
   c = ( BYTE ) *pszOem;

   return c;
}


static void xUserPaintNow( UINT usWinNum )
{
   static BOOL bRunning = FALSE;

   /*make sure we don't execute it > 1 time
    * eg. if s_pWvwData->s_uiPaintRefresh is too small
    */
   if( bRunning )
      return;

   bRunning = TRUE;

   s_pWvwData->s_pWindows[ usWinNum ]->bPaintPending = FALSE;

   if( s_pWvwData->s_sApp->pSymWVW_PAINT )
      if( hb_vmRequestReenter() )
      {
         hb_vmPushDynSym( s_pWvwData->s_sApp->pSymWVW_PAINT );
         hb_vmPushNil();
         hb_vmPushInteger( ( int ) ( usWinNum ) );

         /* follow WVT convention to not passing coordinates anymore
            hb_vmPushInteger( ( int ) (rpaint.top)  );
            hb_vmPushInteger( ( int ) (rpaint.left)  );
            hb_vmPushInteger( ( int ) (rpaint.bottom)  );
            hb_vmPushInteger( ( int ) (rpaint.right)  );
            hb_vmDo( 5 );
          */

         hb_vmDo( 1 );

         hb_vmRequestRestore();
      }

   if( ! s_pWvwData->s_pWindows[ usWinNum ]->bPaintPending )
      hb_wvw_InitPendingRect( s_pWvwData->s_pWindows[ usWinNum ] );

   bRunning = FALSE;
}


static void xUserTimerNow( UINT usWinNum, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
   static BOOL bRunning = FALSE;

   /*make sure we don't execute it > 1 time
    * eg. if timer interval is too small
    * the call will be lost in this case
    */
   if( bRunning )
      return;

   bRunning = TRUE;

   if( s_pWvwData->s_sApp->pSymWVW_TIMER )
      if( hb_vmRequestReenter() )
      {
         hb_vmPushDynSym( s_pWvwData->s_sApp->pSymWVW_TIMER );
         hb_vmPushNil();
         hb_vmPushInteger( ( int ) ( usWinNum ) );
         hb_vmPushNumInt( ( HB_MAXINT ) ( HB_PTRDIFF ) hWnd    );
         hb_vmPushNumInt( message );
         hb_vmPushNumInt( wParam  );
         hb_vmPushNumInt( lParam  );
         hb_vmDo( 5 );

         hb_vmRequestRestore();
      }

   bRunning = FALSE;
}


static LRESULT CALLBACK hb_gt_wvwWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{

   BOOL     bRet;
   long int res;

   UINT       usWinNum;
   WIN_DATA * pWindowData;

   for( usWinNum = 0; usWinNum < s_pWvwData->s_usNumWindows; usWinNum++ )
      if( s_pWvwData->s_pWindows[ usWinNum ]->hWnd == hWnd )
         break;

   if( usWinNum >= s_pWvwData->s_usNumWindows )
      usWinNum = s_pWvwData->s_usNumWindows - 1;

   pWindowData = s_pWvwData->s_pWindows[ usWinNum ];

   switch( message )
   {
      case WM_CREATE:

         bRet = hb_gt_wvwInitWindow( pWindowData, hWnd, pWindowData->COLS, pWindowData->ROWS );

         return bRet;

      case WM_COMMAND: /* handle menu items */
      {

         BOOL bTopMost = ( s_pWvwData->s_usNumWindows == usWinNum + 1 );
         int  iEvent   = ( int ) HIWORD( wParam );
         int  iId      = ( int ) LOWORD( wParam );

         if( iId < WVW_ID_BASE_PUSHBUTTON )
         {

            if( bTopMost || s_pWvwData->s_bAllowNonTop )
               hb_gt_wvwHandleMenuSelection( ( int ) LOWORD( wParam ) );
            else
               hb_gt_wvwInputNotAllowed( usWinNum, message, wParam, lParam );
         }
         else
         if( iId <= WVW_ID_MAX_PUSHBUTTON )
         {
            if( bTopMost || s_pWvwData->s_bAllowNonTop )
            {

               HWND hWndCtrl = ( HWND ) lParam;
               UINT uiPBid;
               byte bStyle;

               uiPBid = ( UINT ) FindControlId( usWinNum, WVW_CONTROL_PUSHBUTTON, hWndCtrl, &bStyle );
               if( uiPBid == 0 )
               {

                  hb_gt_wvwHandleMenuSelection( ( int ) LOWORD( wParam ) );

                  return 0;
               }

               RunControlBlock( usWinNum, WVW_CONTROL_PUSHBUTTON, hWndCtrl, message, wParam, lParam, 0 );

               return 0;
            } /* button click */
            else
               hb_gt_wvwInputNotAllowed( usWinNum, message, wParam, lParam );
         }
         else
         if( iId <= WVW_ID_MAX_COMBOBOX )
         {

            /*
               int lowordwParam = (int) LOWORD(wParam);
               int hiwordwParam = (int) HIWORD(wParam);
               int lowordlParam = (int) LOWORD(lParam);
               int hiwordlParam = (int) HIWORD(lParam);
               HWND hWndCtrl = (HWND) lParam;

               TraceLog( NULL, "debugging: WM_COMMAND is processed?\n" );
               TraceLog( NULL, "  lowordwParam (control id)=%i\n", lowordwParam );
               TraceLog( NULL, "  hiwordwParam (notification)=%i\n", hiwordwParam );
               TraceLog( NULL, "  lowordlParam=%i\n", lowordlParam );
               TraceLog( NULL, "  hiwordlParam=%i\n", hiwordlParam );
             */

            switch( iEvent )
            {

               case CBN_SELCHANGE:
               case CBN_SETFOCUS:
               case CBN_KILLFOCUS:

                  if( ( iEvent == CBN_KILLFOCUS ) || bTopMost || s_pWvwData->s_bAllowNonTop )
                  {

                     HWND hWndCtrl = ( HWND ) lParam;
                     UINT uiCBid;
                     byte bStyle;

                     uiCBid = ( UINT ) FindControlId( usWinNum, WVW_CONTROL_COMBOBOX, hWndCtrl, &bStyle );
                     if( uiCBid == 0 )
                     {

                        hb_gt_wvwHandleMenuSelection( ( int ) LOWORD( wParam ) );

                        return 0;
                     }

                     RunControlBlock( usWinNum, WVW_CONTROL_COMBOBOX, hWndCtrl, message, wParam, lParam, ( int ) iEvent );

                     return 0;
                  }
                  else
                  {
                     hb_gt_wvwInputNotAllowed( usWinNum, message, wParam, lParam );
                     if( iEvent == CBN_SETFOCUS )
                        SetFocus( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->hWnd );
                  }
            }

            return 1;
         } /* combobox */
         else
         if( iId <= WVW_ID_MAX_EDITBOX )
         {

            /*
               int lowordwParam = (int) LOWORD(wParam);
               int hiwordwParam = (int) HIWORD(wParam);
               int lowordlParam = (int) LOWORD(lParam);
               int hiwordlParam = (int) HIWORD(lParam);
               HWND hWndCtrl = (HWND) lParam;

               TraceLog( NULL, "debugging: WM_COMMAND is processed?\n" );
               TraceLog( NULL, "  lowordwParam (control id)=%i\n", lowordwParam );
               TraceLog( NULL, "  hiwordwParam (notification)=%i\n", hiwordwParam );
               TraceLog( NULL, "  lowordlParam=%i\n", lowordlParam );
               TraceLog( NULL, "  hiwordlParam=%i\n", hiwordlParam );
             */

            switch( iEvent )
            {
               case EN_SETFOCUS:
               case EN_KILLFOCUS:
               case EN_CHANGE:

                  if( ( iEvent == EN_KILLFOCUS ) || bTopMost || s_pWvwData->s_bAllowNonTop )
                  {

                     HWND hWndCtrl = ( HWND ) lParam;
                     UINT uiEBid;
                     byte bStyle;

                     uiEBid = ( UINT ) FindControlId( usWinNum, WVW_CONTROL_EDITBOX, hWndCtrl, &bStyle );
                     if( uiEBid == 0 )
                     {

                        hb_gt_wvwHandleMenuSelection( ( int ) LOWORD( wParam ) );

                        return 0;
                     }

                     RunControlBlock( usWinNum, WVW_CONTROL_EDITBOX, hWndCtrl, message, wParam, lParam, ( int ) iEvent );

                     return 0;
                  }
                  else
                  {
                     hb_gt_wvwInputNotAllowed( usWinNum, message, wParam, lParam );
                     if( iEvent == EN_SETFOCUS )
                        SetFocus( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->hWnd );
                  }
            }

            return 1;
         } /* editbox */

         return 0;
      }

      case WM_MENUSELECT:
         if( s_pWvwData->s_sApp->pSymWVW_MENUSELECT )
            if( hb_vmRequestReenter() )
            {

               hb_vmPushDynSym( s_pWvwData->s_sApp->pSymWVW_MENUSELECT );
               hb_vmPushNil();
               hb_vmPushInteger( ( int ) ( usWinNum ) );
               hb_vmPushNumInt( ( HB_MAXINT ) ( HB_PTRDIFF ) hWnd    );
               hb_vmPushNumInt( message );
               hb_vmPushNumInt( wParam  );
               hb_vmPushNumInt( lParam  );
               hb_vmDo( 5 );

               hb_vmRequestRestore();
            }


         return 0;

      case WM_PAINT:
      {
         PAINTSTRUCT ps = { 0 };
         HDC         hdc;
         USHORT      irow;
         RECT        updateRect = { 0 }, rcRect = { 0 };

         RECT  ci = { 0 };
         int   ixbeyond;
         int   iybeyond;
         BOOL  bR       = FALSE, bB = FALSE;
         int   colStart = 0, colStop = 0, rowStart = 0, rowStop = 0;
         HFONT hOldFont;

         GetUpdateRect( hWnd, &updateRect, FALSE );
         /* WARNING!!!
          * the GetUpdateRect call MUST be made BEFORE the BeginPaint call, since
          * BeginPaint resets the update rectangle - don't move it or nothing is drawn!
          */

         /* 2005-06-25 TODO: MSDN says app should NOT call BeginPaint if GetUpdateRect returns zero */

         hdc = BeginPaint( hWnd, &ps );

         hOldFont = ( HFONT ) SelectObject( hdc, pWindowData->hFont );

         ixbeyond = pWindowData->COLS * pWindowData->PTEXTSIZE.x;

         iybeyond = hb_wvw_LineHeight( pWindowData ) * pWindowData->ROWS +
                    pWindowData->usTBHeight;

         if( updateRect.left > ixbeyond || updateRect.top > iybeyond )
         {
            /* do nothing now, will be handled later */

         }
         else
         /*
          * using the update rect, determine which rows and columns of text
          * to paint, and do so
          */
         if( pWindowData->pBuffer != NULL && pWindowData->pColors != NULL )
         {

            /* need to account for truncation in conversion
             * i.e. redraw any 'cell' partially covered...
             */
            rcRect = hb_gt_wvwGetColRowFromXYRect( pWindowData, updateRect );

            /*
               WVT uses global vars as follows:

               _s.rowStart = max( 0, rcRect.top-1 );
               _s.rowStop  = min( _s.ROWS, rcRect.bottom+1 );
               _s.colStart = max( 0, rcRect.left -1 );
               _s.colStop  = min( _s.COLS, rcRect.right+1 );

               WVW can't do that way, because we use TIMER method to repaint
               WVW's pending repaint rect is stored in rPaintPending
             */

            rowStart = max( 0, rcRect.top );

            rowStop = min( pWindowData->ROWS - 1, rcRect.bottom );

            colStart = rcRect.left;
            colStop  = rcRect.right;

            for( irow = ( USHORT ) rowStart; irow <= ( USHORT ) rowStop; irow++ )
            {
               USHORT icol, index, startIndex, startCol, len;
               BYTE   oldColor, color;

               icol       = ( USHORT ) colStart;
               index      = hb_gt_wvwGetIndexForTextBuffer( pWindowData, icol, irow );
               startIndex = index;
               startCol   = icol;
               len        = 0;
               oldColor   = *( pWindowData->pColors + index );

               /* colorute may change mid line...
                * so buffer up text with same color, and output it
                * then do next section with same color, etc
                */

               while( icol <= colStop )
               {
                  if( index >= pWindowData->BUFFERSIZE )
                     break;
                  color = *( pWindowData->pColors + index );
                  if( color != oldColor )
                  {
                     hb_gt_wvwSetColors( pWindowData, hdc, oldColor );
                     hb_gt_wvwTextOut( pWindowData, hdc, startCol, irow, ( char const * ) pWindowData->pBuffer + startIndex, len );

                     if( pWindowData->byLineSpacing > 0 )
                        hb_gt_wvwFillLineSpace( pWindowData, hdc, startCol, irow, len, oldColor );

                     oldColor   = color;
                     startIndex = index;
                     startCol   = icol;
                     len        = 0;

                  }
                  icol++;
                  len++;
                  index++;
               }

               hb_gt_wvwSetColors( pWindowData, hdc, oldColor );
               hb_gt_wvwTextOut( pWindowData, hdc, startCol, irow, ( char const * ) pWindowData->pBuffer + startIndex, len );

               if( pWindowData->byLineSpacing > 0 )
                  hb_gt_wvwFillLineSpace( pWindowData, hdc, startCol, irow, len, oldColor );
            }
         }

         /* Here we must also paint the unreachable region on the right, if any.
            This beyond reach area is due to Min/Max/Close button on
            a small window
            OR
            unreached area due to MAXIMIZED mode
          */

         if( updateRect.right == ixbeyond )
         {

            GetClientRect( hWnd, &ci );

            if( ci.right > ixbeyond )
            {
               rcRect.left   = ixbeyond;
               rcRect.top    = updateRect.top;
               rcRect.right  = ci.right;
               rcRect.bottom = updateRect.bottom;

               InvalidateRect( hWnd, &rcRect, FALSE );

               bR = TRUE;

            }

         }
         else if( updateRect.right > ixbeyond )
         {

            LOGBRUSH lb = { 0 };
            HBRUSH   hBrush;

            COLORREF bkColor = _COLORS[ pWindowData->byColors[ 0 ] >> 4 ];

            rcRect.left   = max( ixbeyond, updateRect.left );
            rcRect.top    = updateRect.top;
            rcRect.right  = updateRect.right;
            rcRect.bottom = updateRect.bottom;

            lb.lbStyle = BS_SOLID;
            lb.lbColor = bkColor;
            lb.lbHatch = 0;

            hBrush = CreateBrushIndirect( &lb );

            FillRect( hdc, &rcRect, hBrush );

            SelectObject( s_pWvwData->s_pWindows[ 0 ]->hdc, ( HBRUSH ) s_pWvwData->s_sApp->OriginalBrush );
            DeleteObject( hBrush );
         }

         if( IsZoomed( hWnd ) )
         {

            if( updateRect.bottom == iybeyond )
            {

               GetClientRect( hWnd, &ci );

               if( ci.bottom > iybeyond )
               {
                  rcRect.left   = updateRect.left;
                  rcRect.top    = iybeyond;
                  rcRect.right  = updateRect.right;
                  rcRect.bottom = ci.bottom;

                  InvalidateRect( hWnd, &rcRect, FALSE );
                  bB = TRUE;
               }

            }
            /* Here we must also paint the unreachable region on the bottom, if any.
               This beyond reach area is due to MAXIMIZED state of
               a small window */
            else if( updateRect.bottom > iybeyond )
            {

               LOGBRUSH lb = { 0 };
               HBRUSH   hBrush;

               COLORREF bkColor = _COLORS[ pWindowData->byColors[ 0 ] >> 4 ];

               rcRect.left   = updateRect.left;
               rcRect.top    = max( iybeyond, updateRect.top );
               rcRect.right  = updateRect.right;
               rcRect.bottom = updateRect.bottom;

               lb.lbStyle = BS_SOLID;
               lb.lbColor = bkColor;
               lb.lbHatch = 0;

               hBrush = CreateBrushIndirect( &lb );

               FillRect( hdc, &rcRect, hBrush );

               SelectObject( s_pWvwData->s_pWindows[ 0 ]->hdc, ( HBRUSH ) s_pWvwData->s_sApp->OriginalBrush );
               DeleteObject( hBrush );
            }

            if( bR && bB )
            {

               rcRect.left   = ixbeyond;
               rcRect.top    = iybeyond;
               rcRect.right  = ci.right;
               rcRect.bottom = ci.bottom;

               InvalidateRect( hWnd, &rcRect, FALSE );

            }
         }

#if 0
         if( hb_gt_gobjects != NULL )
         {
            s_wvw_paintGraphicObjects( hdc, &updateRect );
         }
#endif

         SelectObject( hdc, hOldFont );

         EndPaint( hWnd, &ps );

         if( pWindowData->bPaint )
         {
            if( s_pWvwData->s_sApp->pSymWVW_PAINT )
            {

               pWindowData->bPaintPending = TRUE;

               hb_wvw_UpdatePendingRect( pWindowData, ( USHORT ) rowStart, ( USHORT ) colStart,
                                         ( USHORT ) rowStop, ( USHORT ) colStop );

               if( s_pWvwData->s_uiPaintRefresh == 0 )
                  xUserPaintNow( usWinNum );
            }
         }
         else
            pWindowData->bPaint = TRUE;

#ifdef WVW_DEBUG
         printf( "\nPuts( %d ), Scroll( %d ), Paint( %d ), SetFocus( %d ), KillFocus( %d ) ", nCountPuts, nCountScroll, ++nCountPaint, nSetFocus, nKillFocus );
#endif
         return 0;
      }

      case WM_MY_UPDATE_CARET:
         hb_gt_wvwSetCaretPos( pWindowData );
         return 0;

      case WM_SETFOCUS:
#ifdef WVW_DEBUG
         nSetFocus++;
#endif

         if( usWinNum == s_pWvwData->s_usNumWindows - 1 )
         {

            if( ! s_pWvwData->s_bMainCoordMode )
               hb_gtSetPos( ( SHORT ) pWindowData->caretPos.y, ( SHORT ) pWindowData->caretPos.x );
            else
               hb_gtSetPos( ( ( USHORT ) ( LONG ) ( pWindowData->caretPos.y ) ) + hb_gt_wvwRowOfs( usWinNum ),
                            ( ( USHORT ) ( LONG ) ( pWindowData->caretPos.x ) ) + hb_gt_wvwColOfs( usWinNum ) );

            hb_gt_wvwCreateCaret( pWindowData );

         }

         if( pWindowData->bGetFocus )
         {

            if( s_pWvwData->s_sApp->pSymWVW_SETFOCUS )
               if( hb_vmRequestReenter() )
               {

                  hb_vmPushDynSym( s_pWvwData->s_sApp->pSymWVW_SETFOCUS );
                  hb_vmPushNil();
                  hb_vmPushInteger( ( int ) ( usWinNum ) );
                  hb_vmPushNumInt( ( HB_MAXINT ) ( HB_PTRDIFF ) hWnd    );
                  hb_vmDo( 2 );
                  hb_vmRequestRestore();
               }

         }
         else
            pWindowData->bGetFocus = TRUE;

         return 0;

      case WM_KILLFOCUS:
#ifdef WVW_DEBUG
         nKillFocus++;
#endif

         hb_gt_wvwKillCaret( pWindowData );

         if( s_pWvwData->s_sApp->pSymWVW_KILLFOCUS )
#if 0
            hb_vmPushState();
         hb_vmPushSymbol( s_pWvwData->s_sApp->pSymWVW_KILLFOCUS->pSymbol );
#endif
            if( hb_vmRequestReenter() )
            {
               hb_vmPushDynSym( s_pWvwData->s_sApp->pSymWVW_KILLFOCUS );
               hb_vmPushNil();
               hb_vmPushInteger( ( int ) ( usWinNum ) );
               hb_vmPushNumInt( ( HB_MAXINT ) ( HB_PTRDIFF ) hWnd );
               hb_vmDo( 2 );
               hb_vmRequestRestore();
            }
         return 0;

      case WM_KEYDOWN:
      case WM_SYSKEYDOWN:
/*    case WM_CHAR: */
         /* case WM_SYSCHAR: */

      {
         BOOL bAlt = GetKeyState( VK_MENU ) & 0x8000;

         if( ! hb_gt_wvwAcceptingInput() )
         {
            if( hb_gt_wvwBufferedKey( ( LONG ) wParam ) )
               hb_gt_wvwInputNotAllowed( usWinNum, message, wParam, lParam );
            return 0;
         }

         pWindowData->bIgnoreWM_SYSCHAR = FALSE;
         switch( wParam )
         {

            case VK_LEFT:
               hb_gt_wvwTranslateKey( K_LEFT, K_SH_LEFT, K_ALT_LEFT, K_CTRL_LEFT );
               break;
            case VK_RIGHT:
               hb_gt_wvwTranslateKey( K_RIGHT, K_SH_RIGHT, K_ALT_RIGHT, K_CTRL_RIGHT );
               break;
            case VK_UP:
               hb_gt_wvwTranslateKey( K_UP, K_SH_UP, K_ALT_UP, K_CTRL_UP );
               break;
            case VK_DOWN:
               hb_gt_wvwTranslateKey( K_DOWN, K_SH_DOWN, K_ALT_DOWN, K_CTRL_DOWN );
               break;
            case VK_HOME:
               hb_gt_wvwTranslateKey( K_HOME, K_SH_HOME, K_ALT_HOME, K_CTRL_HOME );
               break;
            case VK_END:
               hb_gt_wvwTranslateKey( K_END, K_SH_END, K_ALT_END, K_CTRL_END );
               break;
            case VK_DELETE:
               hb_gt_wvwTranslateKey( K_DEL, K_SH_DEL, K_ALT_DEL, K_CTRL_DEL );
               break;
            case VK_INSERT:
               hb_gt_wvwTranslateKey( K_INS, K_SH_INS, K_ALT_INS, K_CTRL_INS );
               break;
            case VK_PRIOR:
               hb_gt_wvwTranslateKey( K_PGUP, K_SH_PGUP, K_ALT_PGUP, K_CTRL_PGUP );
               break;
            case VK_NEXT:
               hb_gt_wvwTranslateKey( K_PGDN, K_SH_PGDN, K_ALT_PGDN, K_CTRL_PGDN );
               break;
            case VK_F1:
               hb_gt_wvwTranslateKey( K_F1, K_SH_F1, K_ALT_F1, K_CTRL_F1 );
               break;
            case VK_F2:
               hb_gt_wvwTranslateKey( K_F2, K_SH_F2, K_ALT_F2, K_CTRL_F2 );
               break;
            case VK_F3:
               hb_gt_wvwTranslateKey( K_F3, K_SH_F3, K_ALT_F3, K_CTRL_F3 );
               break;
            case VK_F4:
               if( s_pWvwData->s_sApp->AltF4Close && bAlt )
                  return DefWindowProc( hWnd, message, wParam, lParam );
               else
                  hb_gt_wvwTranslateKey( K_F4, K_SH_F4, K_ALT_F4, K_CTRL_F4 );
               break;
            case VK_F5:
               hb_gt_wvwTranslateKey( K_F5, K_SH_F5, K_ALT_F5, K_CTRL_F5 );
               break;
            case VK_F6:
               hb_gt_wvwTranslateKey( K_F6, K_SH_F6, K_ALT_F6, K_CTRL_F6 );
               break;
            case VK_F7:
               hb_gt_wvwTranslateKey( K_F7, K_SH_F7, K_ALT_F7, K_CTRL_F7 );
               break;
            case VK_F8:
               hb_gt_wvwTranslateKey( K_F8, K_SH_F8, K_ALT_F8, K_CTRL_F8 );
               break;
            case VK_F9:
               hb_gt_wvwTranslateKey( K_F9, K_SH_F9, K_ALT_F9, K_CTRL_F9 );
               break;
            case VK_F10:
               hb_gt_wvwTranslateKey( K_F10, K_SH_F10, K_ALT_F10, K_CTRL_F10 );
               break;
            case VK_F11:
               hb_gt_wvwTranslateKey( K_F11, K_SH_F11, K_ALT_F11, K_CTRL_F11 );
               break;
            case VK_F12:
               hb_gt_wvwTranslateKey( K_F12, K_SH_F12, K_ALT_F12, K_CTRL_F12 );
               break;
            default:
            {
               BOOL bCtrl     = GetKeyState( VK_CONTROL ) & 0x8000;
               BOOL bShift    = GetKeyState( VK_SHIFT ) & 0x8000;
               int  iScanCode = HIWORD( lParam ) & 0xFF;

               if( bCtrl && iScanCode == 76 )       /* CTRL_VK_NUMPAD5 ) */
                  hb_gt_wvwAddCharToInputQueue( KP_CTRL_5 );
               else if( bCtrl && wParam == VK_TAB ) /* K_CTRL_TAB */
               {

                  if( bShift )
                     hb_gt_wvwAddCharToInputQueue( K_CTRL_SH_TAB );
                  else
                     hb_gt_wvwAddCharToInputQueue( K_CTRL_TAB );
               }
               else if( iScanCode == 70 )                            /* Ctrl_Break key OR Scroll LOCK key */
               {
                  if( bCtrl )                                        /* Not scroll lock */
                  {
                     hb_gt_wvwAddCharToInputQueue( HB_BREAK_FLAG );  /* Pretend Alt+C pressed */

                     pWindowData->bIgnoreWM_SYSCHAR = TRUE;
                  }
                  else
                     DefWindowProc( hWnd, message, wParam, lParam );  /* Let windows handle ScrollLock */
               }
               else if( bCtrl && iScanCode == 53 && bShift )
                  hb_gt_wvwAddCharToInputQueue( K_CTRL_QUESTION );
               else if( ( bAlt || bCtrl ) && (
                           wParam == VK_MULTIPLY || wParam == VK_ADD || wParam == VK_SUBTRACT
                           || wParam == VK_DIVIDE ) )
               {
                  if( bAlt )
                     pWindowData->bIgnoreWM_SYSCHAR = TRUE;
                  switch( wParam )
                  {
                     case VK_MULTIPLY:
                        hb_gt_wvwTranslateKey( '*', '*', KP_ALT_ASTERISK, KP_CTRL_ASTERISK );
                        break;
                     case VK_ADD:
                        hb_gt_wvwTranslateKey( '+', '+', KP_ALT_PLUS, KP_CTRL_PLUS );
                        break;
                     case VK_SUBTRACT:
                        hb_gt_wvwTranslateKey( '-', '-', KP_ALT_MINUS, KP_CTRL_MINUS );
                        break;
                     case VK_DIVIDE:
                        hb_gt_wvwTranslateKey( '/', '/', KP_ALT_SLASH, KP_CTRL_SLASH );
                        break;
                  }
               }
               else if( pWindowData->EnableShortCuts )
                  return DefWindowProc( hWnd, message, wParam, lParam );
            }
         }
         return 0;
      }

      case WM_CHAR:
      {
         BOOL bCtrl     = GetKeyState( VK_CONTROL ) & 0x8000;
         int  iScanCode = HIWORD( lParam ) & 0xFF;
         int  c         = ( int ) wParam;
         HWND hMouseCapturer;

         hMouseCapturer = GetCapture();
         if( hMouseCapturer )
            SendMessage( hMouseCapturer, WM_LBUTTONUP, 0, 0 );

         if( ! hb_gt_wvwAcceptingInput() )
         {

            hb_gt_wvwInputNotAllowed( usWinNum, message, wParam, lParam );
            return 0;
         }

         if( ! pWindowData->bIgnoreWM_SYSCHAR )
         {

            if( bCtrl && iScanCode == 28 )            /* K_CTRL_RETURN */
               hb_gt_wvwAddCharToInputQueue( K_CTRL_RETURN );
            else if( bCtrl && ( c >= 1 && c <= 26 ) ) /* K_CTRL_A - Z */
               hb_gt_wvwAddCharToInputQueue( K_Ctrl[ c - 1 ]  );
            else
            {
               switch( c )
               {
                  /* handle special characters */
                  case VK_BACK:
                     hb_gt_wvwTranslateKey( K_BS, K_SH_BS, K_ALT_BS, K_CTRL_BS );
                     break;
                  case VK_TAB:
                     hb_gt_wvwTranslateKey( K_TAB, K_SH_TAB, K_ALT_TAB, K_CTRL_TAB );
                     break;
                  case VK_RETURN:
                     hb_gt_wvwTranslateKey( K_RETURN, K_SH_RETURN, K_ALT_RETURN, K_CTRL_RETURN );
                     break;
                  case VK_ESCAPE:
                     hb_gt_wvwAddCharToInputQueue( K_ESC );
                     break;
                  default:

                     if( pWindowData->CodePage == OEM_CHARSET )
                        c = hb_wvw_key_ansi_to_oem( c );
                     hb_gt_wvwAddCharToInputQueue( c );
                     break;
               }
            }
         }

         pWindowData->bIgnoreWM_SYSCHAR = FALSE;
         return 0;
      }

      case WM_SYSCHAR:

         if( ! hb_gt_wvwAcceptingInput() )
         {

            hb_gt_wvwInputNotAllowed( usWinNum, message, wParam, lParam );

            pWindowData->bIgnoreWM_SYSCHAR = FALSE;
            return 0;
         }

         if( ! pWindowData->bIgnoreWM_SYSCHAR )
         {
            int c, iScanCode = HIWORD( lParam ) & 0xFF;
            switch( iScanCode )
            {
               case  2:
                  c = K_ALT_1;
                  break;
               case  3:
                  c = K_ALT_2;
                  break;
               case  4:
                  c = K_ALT_3;
                  break;
               case  5:
                  c = K_ALT_4;
                  break;
               case  6:
                  c = K_ALT_5;
                  break;
               case  7:
                  c = K_ALT_6;
                  break;
               case  8:
                  c = K_ALT_7;
                  break;
               case  9:
                  c = K_ALT_8;
                  break;
               case 10:
                  c = K_ALT_9;
                  break;
               case 11:
                  c = K_ALT_0;
                  break;
               case 13:
                  c = K_ALT_EQUALS;
                  break;
               case 14:
                  c = K_ALT_BS;
                  break;
               case 16:
                  c = K_ALT_Q;
                  break;
               case 17:
                  c = K_ALT_W;
                  break;
               case 18:
                  c = K_ALT_E;
                  break;
               case 19:
                  c = K_ALT_R;
                  break;
               case 20:
                  c = K_ALT_T;
                  break;
               case 21:
                  c = K_ALT_Y;
                  break;
               case 22:
                  c = K_ALT_U;
                  break;
               case 23:
                  c = K_ALT_I;
                  break;
               case 24:
                  c = K_ALT_O;
                  break;
               case 25:
                  c = K_ALT_P;
                  break;
               case 30:
                  c = K_ALT_A;
                  break;
               case 31:
                  c = K_ALT_S;
                  break;
               case 32:
                  c = K_ALT_D;
                  break;
               case 33:
                  c = K_ALT_F;
                  break;
               case 34:
                  c = K_ALT_G;
                  break;
               case 35:
                  c = K_ALT_H;
                  break;
               case 36:
                  c = K_ALT_J;
                  break;
               case 37:
                  c = K_ALT_K;
                  break;
               case 38:
                  c = K_ALT_L;
                  break;
               case 44:
                  c = K_ALT_Z;
                  break;
               case 45:
                  c = K_ALT_X;
                  break;
               case 46:
                  c = K_ALT_C;
                  break;
               case 47:
                  c = K_ALT_V;
                  break;
               case 48:
                  c = K_ALT_B;
                  break;
               case 49:
                  c = K_ALT_N;
                  break;
               case 50:
                  c = K_ALT_M;
                  break;
               default:
                  c = ( int ) wParam;
                  break;
            }
            hb_gt_wvwAddCharToInputQueue( c );

         }

         pWindowData->bIgnoreWM_SYSCHAR = FALSE;
         return 0;

      case WM_QUERYENDSESSION: /* Closing down computer */
         /* if we have set a shutdown command return false,
          * so windows ( and our app )doesn't shutdown
          * otherwise let the default handler take it
          */
         hb_vmRequestQuit();
         return 0;

      case WM_CLOSE: /* Clicked 'X' on system menu */
         /* if an event has been set then return it otherwise
            fake an Alt+C
          */

         /* 2004-06-10
            reject if not accepting input (topmost window not on focus) */
         if( ! hb_gt_wvwAcceptingInput() )
         {

            hb_gt_wvwInputNotAllowed( usWinNum, message, wParam, lParam );

            return 0;
         }

         if( usWinNum == 0 )
            /* bdj note 2006-07-24:
               We should put this line here, as per FSG change on 2006-06-26:
                 hb_gtHandleClose()
               However, if there is no gtSetCloseHandler, ALT+C effect is not produced as it should.
               So for now I put it back to the old behaviour with the following two lines, until hb_gtHandleClose() is fixed.
             */
/*         hb_gt_wvwAddCharToInputQueue( HB_BREAK_FLAG ); */
            hb_gt_wvwAddCharToInputQueue( K_ESC );

         else
            hb_gt_wvwAddCharToInputQueue( K_ESC );

         return 0;

      case WM_QUIT:
      case WM_DESTROY:
         return 0;

      case WM_ENTERIDLE:
         /* FSG - 2004-05-12 - Signal than i'm on idle */
         hb_idleState();
         return 0;

      case WM_RBUTTONDOWN:
      case WM_LBUTTONDOWN:
      case WM_RBUTTONUP:
      case WM_LBUTTONUP:
      case WM_RBUTTONDBLCLK:
      case WM_LBUTTONDBLCLK:
      case WM_MBUTTONDOWN:
      case WM_MBUTTONUP:
      case WM_MBUTTONDBLCLK:
      case WM_MOUSEMOVE:
      case WM_MOUSEWHEEL:
      case WM_NCMOUSEMOVE:

         if( ! hb_gt_wvwAcceptingInput() || ( usWinNum != s_pWvwData->s_usNumWindows - 1 ) )
            return 0;

         hb_gt_wvwMouseEvent( pWindowData, hWnd, message, wParam, lParam );
         return 0;

      case WM_TIMER:

         if( wParam < WVW_ID_BASE_TIMER && pWindowData->bPaintPending )
            xUserPaintNow( usWinNum );

         if( wParam >= WVW_ID_BASE_TIMER && s_pWvwData->s_sApp->pSymWVW_TIMER )
            xUserTimerNow( usWinNum, hWnd, message, wParam, lParam );

         return 0;

      case WM_HSCROLL:
      case WM_VSCROLL:
      {
         HWND hWndCtrl = ( HWND ) lParam;
         UINT uiXBid;
         byte bStyle;
         BOOL bTopMost = ( s_pWvwData->s_usNumWindows == usWinNum + 1 );

         /* reject if not accepting input (topmost window not on focus) */

         if( ! bTopMost && ! s_pWvwData->s_bAllowNonTop )
         {

            hb_gt_wvwInputNotAllowed( usWinNum, message, wParam, lParam );
            return 0;
         }

         /*************/

         uiXBid = ( UINT ) FindControlId( usWinNum, WVW_CONTROL_SCROLLBAR, hWndCtrl, &bStyle );
         if( uiXBid == 0 )
            return 0;

         RunControlBlock( usWinNum, WVW_CONTROL_SCROLLBAR, hWndCtrl, message, wParam, lParam, 0 );

         return 0;
      } /* WM_VSCROLL  WM_HSCROLL */

      case WM_SIZE:

         if( hb_wvw_Size_Ready( 0 ) )
         {

            hb_gt_wvwResetWindowSize( pWindowData, hWnd );

            if( s_pWvwData->s_sApp->pSymWVW_SIZE )
               if( hb_vmRequestReenter() )
               {
                  hb_vmPushDynSym( s_pWvwData->s_sApp->pSymWVW_SIZE );
                  hb_vmPushNil();
                  hb_vmPushInteger( ( int ) ( usWinNum ) );
                  hb_vmPushNumInt( ( HB_MAXINT ) ( HB_PTRDIFF ) hWnd    );
                  hb_vmPushNumInt( message );
                  hb_vmPushNumInt( wParam  );
                  hb_vmPushNumInt( lParam  );
                  hb_vmDo( 5 );
                  hb_vmRequestRestore();
               }

            return 0;
         }

      case WM_MOVE:
         if( hb_wvw_Move_Ready( 0 ) )
         {

            if( s_pWvwData->s_sApp->pSymWVW_MOVE )
               if( hb_vmRequestReenter() )
               {
                  hb_vmPushDynSym( s_pWvwData->s_sApp->pSymWVW_MOVE );
                  hb_vmPushNil();
                  hb_vmPushInteger( ( int ) ( usWinNum ) );
                  hb_vmPushNumInt( wParam  );
                  hb_vmPushNumInt( lParam  );
                  hb_vmDo( 3 );
                  hb_vmRequestRestore();
               }
            return 0;
         }
      case WM_CTLCOLORSTATIC:
      case WM_CTLCOLOREDIT:

         if( s_pWvwData->s_sApp->pSymWVW_ONCTLCOLOR )
         {

            SetBkMode( ( HDC ) wParam, TRANSPARENT );
            hb_vmPushDynSym( s_pWvwData->s_sApp->pSymWVW_ONCTLCOLOR );
            hb_vmPushNil();
            hb_vmPushNumInt( wParam  );
            hb_vmPushNumInt( lParam  );
            hb_vmDo( 2 );
            res = hb_parnl( -1 );


            if( res != -1 )
               return ( LRESULT ) res;

         }

      case WM_SYSCOMMAND: /* handle system menu items */  /*SP-ADDED*/
         if( s_pWvwData->s_usNumWindows != usWinNum + 1 )
            hb_gt_wvwInputNotAllowed( usWinNum, message, wParam, lParam );
         else
         {
            switch( LOWORD( wParam ) )
            {
               case SC_SIZE:
               case SC_MOVE:
               case SC_MINIMIZE:
               case SC_MAXIMIZE:
               case SC_CLOSE:
               case SC_NEXTWINDOW:
               case SC_RESTORE:
                  hb_gt_wvwHandleMenuSelection( ( int ) LOWORD( wParam ) );
            }
         }

      case WM_DRAWITEM:

         if( pWindowData->bSBPaint )
         {
            LPDRAWITEMSTRUCT lpDIS;
            PTSTR ptStr;
            RECT  rectCorner;
            /* long             lSBColorForeground, lSBColorBackground; */

            size_t        stLen;
            const TCHAR * pEnd;

            pWindowData->bSBPaint = FALSE;

            lpDIS = ( LPDRAWITEMSTRUCT ) lParam;

            ptStr      = ( PTSTR ) lpDIS->itemData;
            rectCorner = lpDIS->rcItem;


            if( pWindowData->cSBColorForeground )
               /* lSBColorForeground = strtol( s_cSBColorForeground, NULL, 10 ); */
               SetTextColor( lpDIS->hDC, pWindowData->cSBColorForeground );  /* lSBColorForeground ); */

            if( pWindowData->cSBColorBackground )
               /* lSBColorBackground = strtol( s_cSBColorBackground, NULL, 10 ); */
               SetBkColor( lpDIS->hDC, pWindowData->cSBColorBackground );  /* lSBColorBackground ); */

            for( pEnd = ptStr; *pEnd != TEXT( '\0' ); pEnd++ )
               continue;

            stLen = pEnd - ptStr;

            ExtTextOut( lpDIS->hDC, rectCorner.top, rectCorner.left + 3, 0, &lpDIS->rcItem, ptStr, stLen, NULL );

            return 0;
         }

   }
   return DefWindowProc( hWnd, message, wParam, lParam );
}


static BOOL hb_wvw_Move_Ready( BOOL b_p_IsReady )
{
   static BOOL s_bIsReady = FALSE;

   if( b_p_IsReady )
      s_bIsReady = b_p_IsReady;
   return s_bIsReady;
}


static BOOL hb_wvw_Size_Ready( BOOL b_p_SizeIsReady )
{
   static BOOL s_bSizeIsReady = FALSE;

   if( b_p_SizeIsReady )
      s_bSizeIsReady = b_p_SizeIsReady;
   return s_bSizeIsReady;
}


static HWND hb_gt_wvwCreateWindow( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow )
{
   HWND     hWnd;
   WNDCLASS wndclass = { 0 };

   HB_SYMBOL_UNUSED( hPrevInstance );
   HB_SYMBOL_UNUSED( szCmdLine );

   InitCommonControls();

   wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
   wndclass.lpfnWndProc   = hb_gt_wvwWndProc;
   wndclass.cbClsExtra    = 0;
   wndclass.cbWndExtra    = 0;
   wndclass.hInstance     = hInstance;
   wndclass.hIcon         = NULL;
   wndclass.hCursor       = LoadCursor( NULL, IDC_ARROW );
   wndclass.hbrBackground = NULL;
   wndclass.lpszMenuName  = NULL;
   wndclass.lpszClassName = s_pWvwData->szAppName;

   if( ! RegisterClass( &wndclass ) )
   {
      MessageBox( NULL, TEXT( "Failed to register class." ),
                  s_pWvwData->szAppName, MB_ICONERROR );
      return 0;
   }

   hWnd = CreateWindow( s_pWvwData->szAppName,                                      /*classname      */
                        TEXT( "HARBOUR_WVW" ),                                      /*window name    */

                        WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |  /*style          */
                        WS_CLIPCHILDREN,

                        0,                                  /*x              */
                        0,                                  /*y              */
                        CW_USEDEFAULT,                      /*width          */
                        CW_USEDEFAULT,                      /*height         */
                        NULL,                               /*window parent  */
                        NULL,                               /*menu           */
                        hInstance,                          /*instance       */
                        NULL );                             /*lpParam        */

   if( hWnd == NULL )
   {
      MessageBox( NULL, TEXT( "Failed to create window." ),
                  TEXT( "HARBOUR_WVW" ), MB_ICONERROR );
      return NULL;
   }

   s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->hWnd = hWnd;

   if( s_pWvwData->s_sApp->pSymWVW_PAINT && s_pWvwData->s_uiPaintRefresh > 0 )
      SetTimer( hWnd, WVW_ID_SYSTEM_TIMER, ( UINT ) s_pWvwData->s_uiPaintRefresh, NULL );

   /* If you wish to show window the way you want, put somewhere in your application
    * ANNOUNCE HB_NOSTARTUPWINDOW
    * If so compiled, then you need to issue wvw_ShowWindow( nWinNum, SW_RESTORE )
    * at the point you desire in your code.
    */
   if( hb_dynsymFind( "HB_NOSTARTUPWINDOW" ) != NULL )
      iCmdShow = SW_HIDE;

   ShowWindow( hWnd, iCmdShow );

   UpdateWindow( hWnd );

   return hWnd;
}


static void hb_gt_wvwCreateToolTipWindow( WIN_DATA * pWindowData )
{
   INITCOMMONCONTROLSEX icex = { 0 };
   HWND     hWndTT;
   TOOLINFO ti = { 0 };

   /* Load the tooltip class from the DLL.
    */
   icex.dwSize = sizeof( icex );
   icex.dwICC  = ICC_BAR_CLASSES;

   if( ! InitCommonControlsEx( &icex ) )
      return;

   /* Create the tooltip control.
    *
    * TODO: shouldn't we set hWndOwner to pWindowData->hWnd instead of NULL?
    */
   hWndTT = CreateWindow( TOOLTIPS_CLASS, TEXT( "" ),
                          WS_POPUP | TTS_ALWAYSTIP,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL,
                          ( HMENU ) NULL,
                          s_pWvwData->hInstance,
                          NULL );

   SetWindowPos( hWndTT,
                 HWND_TOPMOST,
                 0,
                 0,
                 0,
                 0,
                 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );

   /* Prepare TOOLINFO structure for use as tracking tooltip.
    */
   ti.cbSize    = sizeof( TOOLINFO );
   ti.uFlags    = TTF_SUBCLASS;
   ti.hwnd      = pWindowData->hWnd;
   ti.uId       = WVW_ID_BASE_TOOLTIP + pWindowData->byWinId;
   ti.hinst     = s_pWvwData->hInstance;
   ti.lpszText  = "";
   ti.rect.left = ti.rect.top = ti.rect.bottom = ti.rect.right = 0;

   /* Add the tool to the control, displaying an error if needed.
    */
   if( ! SendMessage( s_pWvwData->hWndTT, TTM_ADDTOOL, 0, ( LPARAM ) &ti ) )
      return;

   pWindowData->hWndTT = hWndTT;
}


DWORD hb_gt_wvwProcessMessages( WIN_DATA * pWindowData )
{
   MSG  msg;
   int  iIndex;
   BOOL bProcessed;

   HB_SYMBOL_UNUSED( pWindowData );

   while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
   {

      if( s_pWvwData->s_iScrolling && msg.message == WM_LBUTTONUP )
      {

         s_pWvwData->s_iWrongButtonUp++;
         if( s_pWvwData->s_iWrongButtonUp >= s_pWvwData->s_iMaxWrongButtonUp )
         {
            HWND hMouseCapturer;

            hMouseCapturer = GetCapture();
            if( hMouseCapturer )
            {

               SendMessage( hMouseCapturer, WM_LBUTTONUP, 0, 0 );
               ReleaseCapture();
            }

            s_pWvwData->s_iScrolling = 0;

         }

         return 0;
      }
      else
      {
         s_pWvwData->s_iWrongButtonUp = 0;
         PeekMessage( &msg, NULL, 0, 0, PM_REMOVE );
      }

      bProcessed = FALSE;
      for( iIndex = 0; iIndex < WVW_DLGML_MAX; iIndex++ )
      {
         if( s_pWvwData->s_sApp->hDlgModeless[ iIndex ] != 0 )
            if( IsDialogMessage( s_pWvwData->s_sApp->hDlgModeless[ iIndex ], &msg ) )
            {
               bProcessed = TRUE;
               break;
            }
      }

      if( bProcessed == FALSE )
      {
         TranslateMessage( &msg );
         DispatchMessage( &msg );
      }
   }

   return msg.wParam;

}


POINT hb_gt_wvwGetXYFromColRow( WIN_DATA * pWindowData, USHORT col, USHORT row )
{
   POINT xy = { 0 };

   xy.x = ( col ) * pWindowData->PTEXTSIZE.x;

   xy.y = ( row ) * hb_wvw_LineHeight( pWindowData ) + ( pWindowData->byLineSpacing / 2 );

   xy.y += pWindowData->usTBHeight;

   return xy;
}


static void hb_gt_wvwUnreachedXY( WIN_DATA * pWindowData, int * cols, int * rows )
{
   RECT  ci = { 0 };
   POINT xy = { 0 };

   if( ! IsZoomed( pWindowData->hWnd ) )
   {
      if( rows )
         ( *rows ) = 0;
      if( cols )
         ( *cols ) = 0;
      return;
   }

   xy = hb_gt_wvwGetXYFromColRow( pWindowData, pWindowData->COLS, pWindowData->ROWS );

   GetClientRect( pWindowData->hWnd, &ci );

   if( rows )
      ( *rows ) = ci.bottom - xy.y - pWindowData->usSBHeight;
   if( cols )
      ( *cols ) = ci.right - xy.x;
}


/*
 * get the row and column from xy pixel client coordinates
 * This works because we are using the FIXED system font
 *
 */
static POINT hb_gt_wvwGetColRowFromXY( WIN_DATA * pWindowData, USHORT x, USHORT y )
{
   POINT colrow = { 0 };

   colrow.x = ( x / pWindowData->PTEXTSIZE.x );

   y -= pWindowData->usTBHeight;

   colrow.y = ( y / ( pWindowData->PTEXTSIZE.y + pWindowData->byLineSpacing ) );

   return colrow;
}

static POINT hb_gt_wvwTBGetColRowFromXY( WIN_DATA * pWindowData, USHORT x, USHORT y )
{
   POINT colrow = { 0 };

   colrow.x = ( x / pWindowData->PTEXTSIZE.x );

   colrow.y = ( y / ( pWindowData->PTEXTSIZE.y + pWindowData->byLineSpacing ) );

   return colrow;
}


/*
 * return a rectangle with row and column data, corresponding to the XY pixel
 * coordinates
 * This works because we are using the FIXED system font
 *
 */

RECT hb_gt_wvwGetColRowFromXYRect( WIN_DATA * pWindowData, RECT xy )
{
   RECT colrow = { 0 };
   int  usLineSpaces;

   xy.top    -= pWindowData->usTBHeight;
   xy.bottom -= pWindowData->usTBHeight;

   /* TODO: pls improve efficiency */
   usLineSpaces = pWindowData->byLineSpacing;

   colrow.left = ( xy.left / pWindowData->PTEXTSIZE.x );
   colrow.top  = ( xy.top / ( pWindowData->PTEXTSIZE.y + usLineSpaces ) );

   /* Adjust for when rectangle EXACTLY overlaps characters */
   colrow.right  = ( xy.right / pWindowData->PTEXTSIZE.x - ( xy.right % pWindowData->PTEXTSIZE.x ? 0 : 1 ) );
   colrow.bottom = ( xy.bottom / ( pWindowData->PTEXTSIZE.y + usLineSpaces ) - ( xy.bottom % ( pWindowData->PTEXTSIZE.y + usLineSpaces ) ? 0 : 1 ) );

   return colrow;
}


/*
 * return a rectangle with the XY pixel coordinates corresponding to
 * the row and column data
 * This works because we are using the FIXED system font
 *
 */
RECT hb_gt_wvwGetXYFromColRowRect( WIN_DATA * pWindowData, RECT colrow )
{
   RECT xy = { 0 };

   xy.left = ( colrow.left ) * pWindowData->PTEXTSIZE.x;

   xy.top = ( colrow.top ) * hb_wvw_LineHeight( pWindowData ) + ( pWindowData->byLineSpacing / 2 );

   xy.right = ( colrow.right + 1 ) * pWindowData->PTEXTSIZE.x;

   xy.bottom = ( colrow.bottom + 1 ) * hb_wvw_LineHeight( pWindowData )
               - ( pWindowData->byLineSpacing / 2 );

   xy.top    += pWindowData->usTBHeight;
   xy.bottom += pWindowData->usTBHeight;

   return xy;
}


static void hb_gt_wvwCreateCaret( WIN_DATA * pWindowData )
{
   /* create and show the caret
    * create an underline caret of height - _s.CaretSize
    */

   if( pWindowData->byWinId == s_pWvwData->s_usNumWindows - 1 )
   {
      if( ! s_pWvwData->s_bVertCaret )
         s_pWvwData->s_sApp->CaretExist = CreateCaret( pWindowData->hWnd, ( HBITMAP ) NULL, pWindowData->PTEXTSIZE.x, pWindowData->CaretSize );
      else
         s_pWvwData->s_sApp->CaretExist = CreateCaret( pWindowData->hWnd, ( HBITMAP ) NULL, pWindowData->CaretSize, pWindowData->PTEXTSIZE.y );
   }
   else
      s_pWvwData->s_sApp->CaretExist = FALSE;

   if( s_pWvwData->s_sApp->CaretExist && s_pWvwData->s_sApp->displayCaret )
   {
      hb_gt_wvwSetCaretPos( pWindowData );
      ShowCaret( pWindowData->hWnd );
   }
}


static void hb_gt_wvwKillCaret( WIN_DATA * pWindowData )
{
   HB_SYMBOL_UNUSED( pWindowData );

   if( s_pWvwData->s_sApp->CaretExist )
   {
      DestroyCaret();
      s_pWvwData->s_sApp->CaretExist = FALSE;
   }
}


/*
 * hb_gt_wvwSetCaretPos converts col and row to x and y ( pixels ) and calls
 * the Windows function SetCaretPos ( with the expected coordinates )
 */

static BOOL hb_gt_wvwSetCaretPos( WIN_DATA * pWindowData )
{
   POINT xy = { 0 };

   xy = hb_gt_wvwGetXYFromColRow( pWindowData, ( SHORT ) pWindowData->caretPos.x, ( SHORT ) pWindowData->caretPos.y );
   if( pWindowData->CaretSize > 0 )
   {
      if( ! s_pWvwData->s_bVertCaret )
         xy.y += ( pWindowData->PTEXTSIZE.y - pWindowData->CaretSize );

   }
   else
   {
      if( ! s_pWvwData->s_bVertCaret )
         xy.y -= pWindowData->CaretSize;
      else
         xy.x += pWindowData->PTEXTSIZE.x;
   }
   if( s_pWvwData->s_sApp->CaretExist )
      SetCaretPos( xy.x, xy.y );
   return TRUE;
}


/*
 * hb_gt_wvwValidateRow checks the row bounds for the caret, wrapping if indicated
 */

static void hb_gt_wvwValidateRow( WIN_DATA * pWindowData )
{
   if( pWindowData->caretPos.y < 0 )
   {
      pWindowData->caretPos.y = pWindowData->ROWS - 1;
      if( pWindowData->caretPos.x > 0 )
         pWindowData->caretPos.x--;
      else
         pWindowData->caretPos.x = pWindowData->COLS - 1;
   }
   else if( pWindowData->caretPos.y >= pWindowData->ROWS )
   {
      pWindowData->caretPos.y = 0;
      if( pWindowData->caretPos.x < pWindowData->COLS - 1 )
         pWindowData->caretPos.x++;
      else
         pWindowData->caretPos.x = 0;
   }
}


/*
 * hb_gt_wvwValidateCol checks the column bounds for the caret, wrapping if indicated
 */

static void hb_gt_wvwValidateCol( WIN_DATA * pWindowData )
{
   if( pWindowData->caretPos.x < 0 )
   {
      pWindowData->caretPos.x = pWindowData->COLS - 1;
      if( pWindowData->caretPos.y > 0 )
         pWindowData->caretPos.y--;
      else
         pWindowData->caretPos.y = pWindowData->ROWS - 1;
   }
   else if( pWindowData->caretPos.x >= pWindowData->COLS )
   {
      pWindowData->caretPos.x = 0;
      if( pWindowData->caretPos.y < pWindowData->ROWS - 1 )
         pWindowData->caretPos.y++;
      else
         pWindowData->caretPos.y = 0;
   }
}


/*
 * hb_gt_wvwValidateCaret checks the bounds for the caret, wrapping if indicated
 * before setting the caret position on the screen
 */

static void hb_gt_wvwValidateCaret( WIN_DATA * pWindowData )
{
   hb_gt_wvwValidateCol( pWindowData );
   hb_gt_wvwValidateRow( pWindowData );

   /* send message to window to display updated caret
    */
   SendMessage( pWindowData->hWnd, WM_MY_UPDATE_CARET, 0, 0 );
}


/*
 * hb_gt_wvwGetIndexForTextBuffer takes a row and column, and returns the appropriate
 * index into the screen Text buffer
 */

static USHORT hb_gt_wvwGetIndexForTextBuffer( WIN_DATA * pWindowData, USHORT col, USHORT row )
{
   return row * pWindowData->COLS + col;
}


/*
 * hb_gt_wvwGetColRowForTextBuffer takes an index into the screen Text buffer
 * and returns the corresponding row and column
 */
static POINT hb_gt_wvwGetColRowForTextBuffer( WIN_DATA * pWindowData, USHORT index )
{
   POINT colrow = { 0 };

   colrow.x = index % pWindowData->COLS;
   colrow.y = index / pWindowData->COLS;

   return colrow;
}


/*
 * hb_gt_wvwTextOut converts col and row to x and y ( pixels ) and calls
 * the Windows function TextOut with the expected coordinates
 */

static BOOL hb_gt_wvwTextOut( WIN_DATA * pWindowData, HDC hdc, USHORT col, USHORT row, LPCTSTR lpString, USHORT cbString  )
{
   BOOL  Result;
   POINT xy    = { 0 };
   RECT  mClip = { 0 };

   if( cbString > pWindowData->COLS )
      cbString = pWindowData->COLS;
   xy = hb_gt_wvwGetXYFromColRow( pWindowData, col, row );

   /* safer solution by Oscar Hernandez Suarez: */

   SetRect( &mClip, xy.x, xy.y, xy.x + cbString * pWindowData->PTEXTSIZE.x, xy.y + pWindowData->PTEXTSIZE.y );
   if( pWindowData->FixedFont )
      Result = ExtTextOut( hdc, xy.x, xy.y, ETO_CLIPPED | ETO_OPAQUE, &mClip, lpString,
                           cbString, NULL );
   else
      Result = ExtTextOut( hdc, xy.x, xy.y, ETO_CLIPPED | ETO_OPAQUE, &mClip, lpString,
                           cbString, pWindowData->FixedSize );

   return Result;
}


/*                                                                   */
/* get for and background colours from attribute and set them for window
 */

static BOOL hb_gt_wvwSetColors( WIN_DATA * pWindowData, HDC hdc, BYTE attr )
{
   int fore = attr & 0x000F;
   int back = ( attr & 0x00F0 ) >> 4;

   pWindowData->foreground = _COLORS[ fore ];
   pWindowData->background = _COLORS[ back ];

   SetTextColor( hdc, pWindowData->foreground );
   SetBkColor( hdc, pWindowData->background );

   return TRUE;
}


/*                                                                   */
/* compute invalid rect in pixels, from row and col
 */
static void hb_gt_wvwSetInvalidRect( WIN_DATA * pWindowData, USHORT left, USHORT top, USHORT right, USHORT bottom )
{
   RECT rect = { 0 };

   if( pWindowData->InvalidateWindow )
   {
      rect.left   = left;
      rect.top    = top;
      rect.right  = right;
      rect.bottom = bottom;

      rect = hb_gt_wvwGetXYFromColRowRect( pWindowData, rect );

      /* check for wrapping */
      /*                    */
      rect.left = min( rect.left, rect.right );
      rect.top  = min( rect.top, rect.bottom );

      rect.right  = max( rect.left, rect.right );
      rect.bottom = max( rect.top, rect.bottom );

      rect.top    -= ( pWindowData->byLineSpacing / 2 );
      rect.bottom += ( pWindowData->byLineSpacing / 2 );

      if( pWindowData->RectInvalid.left < 0 )
         memcpy( &( pWindowData->RectInvalid ), &rect, sizeof( RECT ) );
      else
      {
         pWindowData->RectInvalid.left   = min( pWindowData->RectInvalid.left, rect.left   );
         pWindowData->RectInvalid.top    = min( pWindowData->RectInvalid.top, rect.top    );
         pWindowData->RectInvalid.right  = max( pWindowData->RectInvalid.right, rect.right  );
         pWindowData->RectInvalid.bottom = max( pWindowData->RectInvalid.bottom, rect.bottom );
      }
      hb_gt_wvwDoInvalidateRect( pWindowData );
   }
}


static void hb_gt_wvwDoInvalidateRect( WIN_DATA * pWindowData )
{

   if( hb_gt_wvw_usDispCount( pWindowData ) <= 0 && ( pWindowData->RectInvalid.left != -1 ) )
   {

      InvalidateRect( pWindowData->hWnd, &pWindowData->RectInvalid, FALSE );

      pWindowData->RectInvalid.left = -1;
      hb_gt_wvwProcessMessages( pWindowData );
   }
}


/*NOTE: this function is called when after a key event occurs.
 *      since we are accepting input only from focused topmost window, no need to handle input on other window
 *      (in current design, only topmost window accepting input)
 */

static void hb_gt_wvwTranslateKey( int key, int shiftkey, int altkey, int controlkey )
{

   int iKey = hb_gt_wvwJustTranslateKey( key, shiftkey, altkey, controlkey );

   hb_gt_wvwAddCharToInputQueue( iKey );
}

static int hb_gt_wvwJustTranslateKey( int key, int shiftkey, int altkey, int controlkey )
{
   int nVirtKey = GetKeyState( VK_MENU );

   if( nVirtKey & 0x8000 )
      return altkey;
   else
   {
      nVirtKey = GetKeyState( VK_CONTROL );
      if( nVirtKey & 0x8000 )
         return controlkey;
      else
      {
         nVirtKey = GetKeyState( VK_SHIFT );
         if( nVirtKey & 0x8000 )
            return shiftkey;
         else
            return key;
      }
   }
}


/*                                                                   */
/* font stuff                                                        */
/* use the standard fixed oem font, unless the caller has requested set size fonts
 */

HFONT hb_gt_wvwGetFont( const char * pszFace, int iHeight, int iWidth, int iWeight, int iQuality, int iCodePage )
{
   HFONT hFont;

   if( iHeight > 0 )
   {
      LOGFONT logfont = { 0 };

      logfont.lfEscapement     = 0;
      logfont.lfOrientation    = 0;
      logfont.lfWeight         = iWeight;
      logfont.lfItalic         = 0;
      logfont.lfUnderline      = 0;
      logfont.lfStrikeOut      = 0;
      logfont.lfCharSet        = ( BYTE ) iCodePage;        /* OEM_CHARSET;                                    */
      logfont.lfOutPrecision   = 0;
      logfont.lfClipPrecision  = 0;
      logfont.lfQuality        = ( BYTE ) iQuality;         /* DEFAULT_QUALITY, DRAFT_QUALITY or PROOF_QUALITY */
      logfont.lfPitchAndFamily = FIXED_PITCH + FF_MODERN;   /* all mapping depends on fixed width fonts!       */
      logfont.lfHeight         = iHeight;
      logfont.lfWidth = iWidth < 0 ? -iWidth : iWidth;

      strcpy( logfont.lfFaceName, pszFace );

      hFont = CreateFontIndirect( &logfont );
   }
   else
      hFont = ( HFONT ) GetStockObject( OEM_FIXED_FONT );
   return hFont;

}


static void hb_gtInitStatics( UINT usWinNum, LPCTSTR lpszWinName, USHORT usRow1, USHORT usCol1, USHORT usRow2, USHORT usCol2 )
{
   OSVERSIONINFO osvi;
   HINSTANCE     h;
   WIN_DATA *    pWindowData;
   WIN_DATA *    pPrevWindow;
   int iIndex;

   pWindowData = s_pWvwData->s_pWindows[ usWinNum ];

   if( usWinNum == 0 )
   {
      pWindowData->byWinId = ( int ) usWinNum;
      strcpy( pWindowData->szWinName, lpszWinName );

      pWindowData->usRowOfs    = usRow1;
      pWindowData->usColOfs    = usCol1;
      pWindowData->uiDispCount = 0;

      pWindowData->ROWS       = usRow2 - usRow1 + 1;
      pWindowData->COLS       = usCol2 - usCol1 + 1;
      pWindowData->foreground = WHITE;
      pWindowData->background = BLACK;
      pWindowData->BUFFERSIZE = 0;
      pWindowData->pColors    = NULL;
      pWindowData->pBuffer    = NULL;
      pWindowData->caretPos.x = 0;
      pWindowData->caretPos.y = 0;

      s_pWvwData->s_sApp->CaretExist = FALSE;

      pWindowData->CaretSize     = 2;
      pWindowData->mousePos.x    = 0;
      pWindowData->mousePos.y    = 0;
      pWindowData->MouseMove     = FALSE;
      pWindowData->hWnd          = NULL;
      pWindowData->keyPointerIn  = 0;
      pWindowData->keyPointerOut = 0;
      pWindowData->keyLast       = 0;
      memset( &pWindowData->Keys, 0, sizeof( pWindowData->Keys ) );

      s_pWvwData->s_sApp->displayCaret = TRUE;

      pWindowData->RectInvalid.left = -1;

      pWindowData->PTEXTSIZE.x = 8;
      pWindowData->PTEXTSIZE.y = 12;

      pWindowData->fontHeight  = 20;
      pWindowData->fontWidth   = 10;
      pWindowData->fontWeight  = FW_NORMAL;
      pWindowData->fontQuality = DEFAULT_QUALITY;
      strcpy( pWindowData->fontFace, "Courier New" );

      pWindowData->LastMenuEvent = 0;
      pWindowData->MenuKeyEvent  = WVW_DEFAULT_MENUKEYEVENT;
      pWindowData->CentreWindow  = TRUE;             /* Default is to always display window in centre of screen */

      /* two following parameters are meaningful only if CentreWindow is FALSE */
      pWindowData->HCentreWindow = FALSE;                /* horizontally */
      pWindowData->VCentreWindow = FALSE;                /* vertically */

      pWindowData->CodePage = GetACP();                  /* Set code page to default system                         */

      osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
      GetVersionEx( &osvi );
      s_pWvwData->s_sApp->Win9X      = ( osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS );
      s_pWvwData->s_sApp->AltF4Close = FALSE;

      pWindowData->InvalidateWindow = TRUE;
      pWindowData->EnableShortCuts  = FALSE;

      pWindowData->bToolTipActive = FALSE;
      pWindowData->hWndTT         = NULL;
      pWindowData->hPopup         = NULL;

      s_pWvwData->s_lfPB.lfHeight      = pWindowData->fontHeight - 2;
      s_pWvwData->s_lfPB.lfWidth       = 0;
      s_pWvwData->s_lfPB.lfEscapement  = 0;
      s_pWvwData->s_lfPB.lfOrientation = 0;
      s_pWvwData->s_lfPB.lfWeight      = 0;
      s_pWvwData->s_lfPB.lfItalic      = 0;
      s_pWvwData->s_lfPB.lfUnderline   = 0;
      s_pWvwData->s_lfPB.lfStrikeOut   = 0;
      s_pWvwData->s_lfPB.lfCharSet     = DEFAULT_CHARSET;

      s_pWvwData->s_lfPB.lfQuality        = DEFAULT_QUALITY;
      s_pWvwData->s_lfPB.lfPitchAndFamily = FF_DONTCARE;
      strcpy( s_pWvwData->s_lfPB.lfFaceName, "Arial" );

      s_pWvwData->s_lfSB.lfHeight      = 12;
      s_pWvwData->s_lfSB.lfWidth       = 0;
      s_pWvwData->s_lfSB.lfEscapement  = 0;
      s_pWvwData->s_lfSB.lfOrientation = 0;
      s_pWvwData->s_lfSB.lfWeight      = 400;       /* */
      s_pWvwData->s_lfSB.lfItalic      = 0;
      s_pWvwData->s_lfSB.lfUnderline   = 0;
      s_pWvwData->s_lfSB.lfStrikeOut   = 0;
      s_pWvwData->s_lfSB.lfCharSet     = DEFAULT_CHARSET;

      s_pWvwData->s_lfSB.lfQuality        = DEFAULT_QUALITY;
      s_pWvwData->s_lfSB.lfPitchAndFamily = FF_DONTCARE;
      strcpy( s_pWvwData->s_lfSB.lfFaceName, "Arial" );

      s_pWvwData->s_lfCB.lfHeight      = pWindowData->fontHeight - 2;
      s_pWvwData->s_lfCB.lfWidth       = 0;
      s_pWvwData->s_lfCB.lfEscapement  = 0;
      s_pWvwData->s_lfCB.lfOrientation = 0;
      s_pWvwData->s_lfCB.lfWeight      = 0;
      s_pWvwData->s_lfCB.lfItalic      = 0;
      s_pWvwData->s_lfCB.lfUnderline   = 0;
      s_pWvwData->s_lfCB.lfStrikeOut   = 0;
      s_pWvwData->s_lfCB.lfCharSet     = DEFAULT_CHARSET;

      s_pWvwData->s_lfCB.lfQuality        = DEFAULT_QUALITY;
      s_pWvwData->s_lfCB.lfPitchAndFamily = FF_DONTCARE;
      strcpy( s_pWvwData->s_lfCB.lfFaceName, "Arial" );

      s_pWvwData->s_lfEB.lfHeight      = pWindowData->fontHeight - 2;
      s_pWvwData->s_lfEB.lfWidth       = 0;
      s_pWvwData->s_lfEB.lfEscapement  = 0;
      s_pWvwData->s_lfEB.lfOrientation = 0;
      s_pWvwData->s_lfEB.lfWeight      = 0;
      s_pWvwData->s_lfEB.lfItalic      = 0;
      s_pWvwData->s_lfEB.lfUnderline   = 0;
      s_pWvwData->s_lfEB.lfStrikeOut   = 0;
      s_pWvwData->s_lfEB.lfCharSet     = DEFAULT_CHARSET;

      s_pWvwData->s_lfEB.lfQuality        = DEFAULT_QUALITY;
      s_pWvwData->s_lfEB.lfPitchAndFamily = FF_DONTCARE;
      strcpy( s_pWvwData->s_lfEB.lfFaceName, "Arial" );

      s_pWvwData->s_lfCX.lfHeight      = pWindowData->fontHeight - 2;
      s_pWvwData->s_lfCX.lfWidth       = 0;
      s_pWvwData->s_lfCX.lfEscapement  = 0;
      s_pWvwData->s_lfCX.lfOrientation = 0;
      s_pWvwData->s_lfCX.lfWeight      = 0;
      s_pWvwData->s_lfCX.lfItalic      = 0;
      s_pWvwData->s_lfCX.lfUnderline   = 0;
      s_pWvwData->s_lfCX.lfStrikeOut   = 0;
      s_pWvwData->s_lfCX.lfCharSet     = DEFAULT_CHARSET;

      s_pWvwData->s_lfCX.lfQuality        = DEFAULT_QUALITY;
      s_pWvwData->s_lfCX.lfPitchAndFamily = FF_DONTCARE;
      strcpy( s_pWvwData->s_lfCX.lfFaceName, "Arial" );

      s_pWvwData->s_lfST.lfHeight      = pWindowData->fontHeight;
      s_pWvwData->s_lfST.lfWidth       = 0;
      s_pWvwData->s_lfST.lfEscapement  = 0;
      s_pWvwData->s_lfST.lfOrientation = 0;
      s_pWvwData->s_lfST.lfWeight      = 0;
      s_pWvwData->s_lfST.lfItalic      = 0;
      s_pWvwData->s_lfST.lfUnderline   = 0;
      s_pWvwData->s_lfST.lfStrikeOut   = 0;
      s_pWvwData->s_lfST.lfCharSet     = DEFAULT_CHARSET;

      s_pWvwData->s_lfST.lfQuality        = DEFAULT_QUALITY;
      s_pWvwData->s_lfST.lfPitchAndFamily = FF_DONTCARE;
      strcpy( s_pWvwData->s_lfST.lfFaceName, pWindowData->fontFace );

      s_pWvwData->s_sApp->pSymWVW_PAINT      = hb_dynsymFind( "WVW_PAINT" );
      s_pWvwData->s_sApp->pSymWVW_SETFOCUS   = hb_dynsymFind( "WVW_SETFOCUS" );
      s_pWvwData->s_sApp->pSymWVW_KILLFOCUS  = hb_dynsymFind( "WVW_KILLFOCUS" );
      s_pWvwData->s_sApp->pSymWVW_MOUSE      = hb_dynsymFind( "WVW_MOUSE" );
      s_pWvwData->s_sApp->pSymWVW_MENUSELECT = hb_dynsymFind( "WVW_MENUSELECT" );
      s_pWvwData->s_sApp->pSymWVW_TBMOUSE    = hb_dynsymFind( "WVW_TBMOUSE" );

      s_pWvwData->s_sApp->pSymWVW_SIZE = hb_dynsymFind( "WVW_SIZE" );
      s_pWvwData->s_sApp->pSymWVW_MOVE = hb_dynsymFind( "WVW_MOVE" );

      s_pWvwData->s_sApp->pSymWVW_INPUTFOCUS = hb_dynsymFind( "WVW_INPUTFOCUS" );
      s_pWvwData->s_sApp->pSymWVW_TIMER      = hb_dynsymFind( "WVW_TIMER" );
      s_pWvwData->s_sApp->pSymWVW_ONCTLCOLOR = hb_dynsymFind( "WVW_ONCTLCOLOR" );

      h = LoadLibrary( "msimg32.dll" );
      if( h )
      {
         s_pWvwData->s_sApp->pfnGF = ( wvwGradientFill ) HB_WINAPI_GETPROCADDRESS( h, "GradientFill" );
         if( s_pWvwData->s_sApp->pfnGF )
            s_pWvwData->s_sApp->hMSImg32 = h;
      }

      for( iIndex = 0; iIndex < WVW_DLGML_MAX; iIndex++ )
      {
         s_pWvwData->s_sApp->hDlgModeless[ iIndex ] = NULL;

         s_pWvwData->s_sApp->pFunc[ iIndex ] = NULL;
         s_pWvwData->s_sApp->iType[ iIndex ] = ( int ) NULL;
      }

      for( iIndex = 0; iIndex < WVW_DLGMD_MAX; iIndex++ )
      {
         s_pWvwData->s_sApp->hDlgModal[ iIndex ]  = NULL;
         s_pWvwData->s_sApp->pFuncModal[ iIndex ] = NULL;
         s_pWvwData->s_sApp->iTypeModal[ iIndex ] = ( int ) NULL;
      }

      s_pWvwData->s_sApp->pbhBitmapList  = NULL;
      s_pWvwData->s_sApp->pphPictureList = NULL;

      s_pWvwData->s_sApp->pbhUserBitmap = NULL;
      s_pWvwData->s_sApp->uiBMcache     = 0;
      s_pWvwData->s_sApp->uiMaxBMcache  = WVW_DEFAULT_MAX_BMCACHE;

   }
   else
   {

      if( ! s_pWvwData->s_bMainCoordMode )
         pPrevWindow = s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ];
      else
         pPrevWindow = s_pWvwData->s_pWindows[ usWinNum - 1 ];

      pWindowData->byWinId = usWinNum;
      strcpy( pWindowData->szWinName, lpszWinName );
      pWindowData->usRowOfs    = usRow1;
      pWindowData->usColOfs    = usCol1;
      pWindowData->uiDispCount = 0;

      pWindowData->ROWS = usRow2 - usRow1 + 1;
      pWindowData->COLS = usCol2 - usCol1 + 1;

      pWindowData->foreground = pPrevWindow->foreground;
      pWindowData->background = pPrevWindow->background;
      pWindowData->BUFFERSIZE = 0;
      pWindowData->pColors    = NULL;
      pWindowData->pBuffer    = NULL;
      pWindowData->caretPos.x = 0;
      pWindowData->caretPos.y = 0;

      pWindowData->CaretSize     = pPrevWindow->CaretSize;
      pWindowData->mousePos.x    = 0;
      pWindowData->mousePos.y    = 0;
      pWindowData->MouseMove     = pPrevWindow->MouseMove;
      pWindowData->hWnd          = NULL;
      pWindowData->keyPointerIn  = 0;
      pWindowData->keyPointerOut = 0;
      pWindowData->keyLast       = 0;
      memset( &pWindowData->Keys, 0, sizeof( pWindowData->Keys ) );

      pWindowData->RectInvalid.left = -1;
      pWindowData->PTEXTSIZE.x      = pPrevWindow->PTEXTSIZE.x;
      pWindowData->PTEXTSIZE.y      = pPrevWindow->PTEXTSIZE.y;
      pWindowData->fontHeight       = pPrevWindow->fontHeight;
      pWindowData->fontWidth        = pPrevWindow->fontWidth;
      pWindowData->fontWeight       = pPrevWindow->fontWeight;
      pWindowData->fontQuality      = pPrevWindow->fontQuality;
      strcpy( pWindowData->fontFace, pPrevWindow->fontFace );
      pWindowData->LastMenuEvent = 0;
      pWindowData->MenuKeyEvent  = WVW_DEFAULT_MENUKEYEVENT;

      pWindowData->CentreWindow = s_pWvwData->s_bDefCentreWindow;

      /* two following parameters are meaningful only if CentreWindow is FALSE */
      pWindowData->HCentreWindow = s_pWvwData->s_bDefHCentreWindow;        /* horizontally */
      pWindowData->VCentreWindow = s_pWvwData->s_bDefVCentreWindow;        /* vertically */

      pWindowData->CodePage = pPrevWindow->CodePage;

      pWindowData->InvalidateWindow = TRUE;
      pWindowData->EnableShortCuts  = pPrevWindow->EnableShortCuts;

      pWindowData->bToolTipActive = FALSE;
      pWindowData->hWndTT         = NULL;
      pWindowData->hPopup         = NULL;

   }

   pWindowData->bIgnoreWM_SYSCHAR = FALSE;
   pWindowData->bPaint    = FALSE;
   pWindowData->bGetFocus = FALSE;

   pWindowData->byLineSpacing = s_pWvwData->s_byDefLineSpacing;

   pWindowData->iLSpaceColor = s_pWvwData->s_iDefLSpaceColor;

   pWindowData->bPaintPending = FALSE;
   hb_wvw_InitPendingRect( pWindowData );

   pWindowData->hStatusBar = NULL;
   pWindowData->usSBHeight = 0;

   pWindowData->bSBPaint = FALSE;
   pWindowData->cSBColorForeground = 0;
   pWindowData->cSBColorBackground = 0;

   pWindowData->hToolBar   = NULL;
   pWindowData->usTBHeight = 0;

   pWindowData->pcdCtrlList = NULL;

   pWindowData->hPBfont = NULL;              /* will be created on first creation of pushbutton, if ever */

   pWindowData->hCBfont = NULL;              /* will be created on first creation of combobox, if ever */

   pWindowData->hEBfont = NULL;              /* will be created on first creation of editbox, if ever */

   pWindowData->hCXfont = NULL;              /* will be created on first creation of checkbox, if ever */

   pWindowData->hSBfont = NULL;              /* will be created on first creation of statusbar, if ever */

   pWindowData->hSTfont = NULL;              /* will be created on first creation of static control, if ever */

   s_pWvwData->s_usCurWindow = usWinNum;
}


/*
 *  functions for handling the input queues for the mouse and keyboard
 */

/*NOTE: current design allows topmost window only who accepts input */

static void hb_gt_wvwAddCharToInputQueue( int iKey )
{
   UINT uiWinNum = s_pWvwData->s_usNumWindows - 1;
   int  iNextPos = s_pWvwData->s_pWindows[ uiWinNum ]->keyPointerIn;

   if( iKey == K_MOUSEMOVE || iKey == K_NCMOUSEMOVE )
      if( s_pWvwData->s_pWindows[ uiWinNum ]->keyLast == iKey && s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->keyPointerIn != s_pWvwData->s_pWindows[ uiWinNum ]->keyPointerOut )
         return;

   s_pWvwData->s_pWindows[ uiWinNum ]->Keys[ iNextPos ] = s_pWvwData->s_pWindows[ uiWinNum ]->keyLast = iKey;
   if( ++iNextPos >= WVW_CHAR_QUEUE_SIZE )
      iNextPos = 0;
   if( iNextPos != s_pWvwData->s_pWindows[ uiWinNum ]->keyPointerOut )
      s_pWvwData->s_pWindows[ uiWinNum ]->keyPointerIn = iNextPos;

}


USHORT hb_gt_wvwGetMouseX( WIN_DATA * pWindowData )
{
   return ( SHORT ) pWindowData->mousePos.x;
}


USHORT hb_gt_wvwGetMouseY( WIN_DATA * pWindowData )
{
   return ( SHORT ) pWindowData->mousePos.y;
}


static void hb_gt_wvwSetMouseX( WIN_DATA * pWindowData, USHORT ix )
{
   pWindowData->mousePos.x = ix;
}


static void hb_gt_wvwSetMouseY( WIN_DATA * pWindowData, USHORT iy )
{
   pWindowData->mousePos.y = iy;
}


/*
 * hb_gt_wvwSetStringInTextBuffer puts the string of the specified length into the TextBuffer at
 * the specified caret position
 * It then determines the invalid rectangle, so the string will be displayed
 */
static void hb_gt_wvwSetStringInTextBuffer( WIN_DATA * pWindowData, int col, int row, BYTE color, BYTE attr, BYTE * sBuffer, ULONG length )
{
   POINT  end = { 0 };
   USHORT index;

   HB_SYMBOL_UNUSED( attr );

   /* determine the index and put the string into the TextBuffer
    */
   index = hb_gt_wvwGetIndexForTextBuffer( pWindowData, ( USHORT ) col, ( USHORT ) row );
   if( ( length + index ) <= ( ULONG ) pWindowData->BUFFERSIZE )
   {
      memcpy( ( pWindowData->pBuffer + index ), sBuffer, length );

      memset( ( pWindowData->pColors + index ), color, length );

      /*  determine bounds of rect around character to refresh
       */
      end = hb_gt_wvwGetColRowForTextBuffer( pWindowData, index + ( ( ( USHORT ) ( ULONG ) ( length ) ) - 1 ) );
      hb_gt_wvwSetInvalidRect( pWindowData, ( USHORT ) col, ( USHORT ) row, ( USHORT ) end.x, ( USHORT ) end.y );
   }
}


static void hb_gt_wvwSetCaretOn( WIN_DATA * pWindowData, BOOL bOn )
{

   if( s_pWvwData->s_sApp->CaretExist )
   {
      if( bOn )
      {
         hb_gt_wvwSetCaretPos( pWindowData );
         ShowCaret( pWindowData->hWnd );
      }
      else
         HideCaret( pWindowData->hWnd );
   }

   s_pWvwData->s_sApp->displayCaret = bOn;
}


static void hb_gt_wvwHandleMenuSelection( int menuIndex )
{
   s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->LastMenuEvent = menuIndex;
   hb_gt_wvwAddCharToInputQueue( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->MenuKeyEvent );
}


static void hb_gt_wvwMouseEvent( WIN_DATA * pWindowData, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
   POINT xy       = { 0 }, colrow = { 0 };
   SHORT keyCode  = 0;
   SHORT keyState = 0;
   ULONG lPopupRet;

   HB_SYMBOL_UNUSED( hWnd );
   HB_SYMBOL_UNUSED( wParam );

   if( message == WM_MOUSEMOVE || message == WM_NCMOUSEMOVE )
      if( ! pWindowData->MouseMove )
         return;

   xy.x = LOWORD( lParam );
   xy.y = HIWORD( lParam );

   colrow = hb_gt_wvwGetColRowFromXY( pWindowData, ( SHORT ) xy.x, ( SHORT ) xy.y );

   hb_gt_wvwSetMouseX( pWindowData, ( SHORT ) colrow.x );
   hb_gt_wvwSetMouseY( pWindowData, ( SHORT ) colrow.y );

   switch( message )
   {
      case WM_LBUTTONDBLCLK:
         keyCode = K_LDBLCLK;
         break;

      case WM_RBUTTONDBLCLK:
         keyCode = K_RDBLCLK;
         break;

      case WM_LBUTTONDOWN:
      {

         HWND hWndFocus = ( HWND ) GetFocus();

         if( GetControlClass( pWindowData->byWinId, hWndFocus ) > 0 )
            SetFocus( hWnd );

      }
         keyCode = K_LBUTTONDOWN;
         break;

      case WM_RBUTTONDOWN:
         keyCode = K_RBUTTONDOWN;
         break;

      case WM_LBUTTONUP:
         keyCode = K_LBUTTONUP;
         break;

      case WM_RBUTTONUP:

         if( pWindowData->hPopup )
         {
            GetCursorPos( &xy );
            lPopupRet = TrackPopupMenu( pWindowData->hPopup, TPM_CENTERALIGN + TPM_RETURNCMD, xy.x, xy.y, 0, hWnd, NULL );
            if( lPopupRet )
               hb_gt_wvwAddCharToInputQueue( lPopupRet );
            return;
         }
         else
         {
            keyCode = K_RBUTTONUP;
            break;
         }

      case WM_MBUTTONDOWN:
         keyCode = K_MBUTTONDOWN;
         break;

      case WM_MBUTTONUP:
         keyCode = K_MBUTTONUP;
         break;

      case WM_MBUTTONDBLCLK:
         keyCode = K_MDBLCLK;
         break;

      case WM_MOUSEMOVE:
         keyState = ( SHORT ) wParam;

         if( keyState == MK_LBUTTON )
            keyCode = K_MMLEFTDOWN;
         else if( keyState == MK_RBUTTON )
            keyCode = K_MMRIGHTDOWN;
         else if( keyState == MK_MBUTTON )
            keyCode = K_MMMIDDLEDOWN;
         else
            keyCode = K_MOUSEMOVE;
         break;

      case WM_MOUSEWHEEL:
         keyState = HIWORD( wParam );

         if( keyState > 0 )
            keyCode = K_MWFORWARD;
         else
            keyCode = K_MWBACKWARD;

         break;

      case WM_NCMOUSEMOVE:
         keyCode = K_NCMOUSEMOVE;
         break;
   }

   if( s_pWvwData->s_sApp->pSymWVW_MOUSE && keyCode != 0 )
      if( hb_vmRequestReenter() )
      {

         hb_vmPushDynSym( s_pWvwData->s_sApp->pSymWVW_MOUSE );
         hb_vmPushNil();
         hb_vmPushInteger( ( int ) ( pWindowData->byWinId ) );
         hb_vmPushLong( ( SHORT ) keyCode );
         hb_vmPushLong( ( SHORT ) colrow.y );
         hb_vmPushLong( ( SHORT ) colrow.x );
         hb_vmPushLong( ( SHORT ) keyState );
         hb_vmDo( 5 );

         hb_vmRequestRestore();
      }

   hb_gt_wvwAddCharToInputQueue( keyCode );
}

static void hb_gt_wvwTBMouseEvent( WIN_DATA * pWindowData, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
   POINT xy       = { 0 }, colrow = { 0 };
   SHORT keyCode  = 0;
   SHORT keyState = 0;
   ULONG lPopupRet;

   HB_SYMBOL_UNUSED( hWnd );
   HB_SYMBOL_UNUSED( wParam );

   if( message == WM_MOUSEMOVE || message == WM_NCMOUSEMOVE )
      if( ! pWindowData->MouseMove )
         return;

   xy.x = LOWORD( lParam );
   xy.y = HIWORD( lParam );

   colrow = hb_gt_wvwTBGetColRowFromXY( pWindowData, ( SHORT ) xy.x, ( SHORT ) xy.y );

   hb_gt_wvwSetMouseX( pWindowData, ( SHORT ) colrow.x );
   hb_gt_wvwSetMouseY( pWindowData, ( SHORT ) colrow.y );

   switch( message )
   {
      case WM_LBUTTONDBLCLK:
         keyCode = K_LDBLCLK;
         break;

      case WM_RBUTTONDBLCLK:
         keyCode = K_RDBLCLK;
         break;

      case WM_LBUTTONDOWN:
      {

         HWND hWndFocus = ( HWND ) GetFocus();

         if( GetControlClass( pWindowData->byWinId, hWndFocus ) > 0 )
            SetFocus( hWnd );

      }
         keyCode = K_LBUTTONDOWN;
         break;

      case WM_RBUTTONDOWN:
         keyCode = K_RBUTTONDOWN;
         break;

      case WM_LBUTTONUP:
         keyCode = K_LBUTTONUP;
         break;

      case WM_RBUTTONUP:

         if( pWindowData->hPopup )
         {
            GetCursorPos( &xy );
            lPopupRet = TrackPopupMenu( pWindowData->hPopup, TPM_CENTERALIGN + TPM_RETURNCMD, xy.x, xy.y, 0, hWnd, NULL );
            if( lPopupRet )
               hb_gt_wvwAddCharToInputQueue( lPopupRet );
            return;
         }
         else
         {
            keyCode = K_RBUTTONUP;
            break;
         }

      case WM_MBUTTONDOWN:
         keyCode = K_MBUTTONDOWN;
         break;

      case WM_MBUTTONUP:
         keyCode = K_MBUTTONUP;
         break;

      case WM_MBUTTONDBLCLK:
         keyCode = K_MDBLCLK;
         break;

      case WM_MOUSEMOVE:
         keyState = ( SHORT ) wParam;

         if( keyState == MK_LBUTTON )
            keyCode = K_MMLEFTDOWN;
         else if( keyState == MK_RBUTTON )
            keyCode = K_MMRIGHTDOWN;
         else if( keyState == MK_MBUTTON )
            keyCode = K_MMMIDDLEDOWN;
         else
            keyCode = K_MOUSEMOVE;
         break;

      case WM_MOUSEWHEEL:
         keyState = HIWORD( wParam );

         if( keyState > 0 )
            keyCode = K_MWFORWARD;
         else
            keyCode = K_MWBACKWARD;

         break;

      case WM_NCMOUSEMOVE:
         keyCode = K_NCMOUSEMOVE;
         break;
   }

   if( s_pWvwData->s_sApp->pSymWVW_TBMOUSE && keyCode != 0 )
      if( hb_vmRequestReenter() )
      {
         hb_vmPushDynSym( s_pWvwData->s_sApp->pSymWVW_TBMOUSE );
         hb_vmPushNil();
         hb_vmPushInteger( ( int ) ( pWindowData->byWinId ) );
         hb_vmPushLong( ( SHORT ) keyCode );
         hb_vmPushLong( ( SHORT ) colrow.y );
         hb_vmPushLong( ( SHORT ) colrow.x );
         hb_vmPushLong( ( SHORT ) keyState );
         hb_vmDo( 5 );

         hb_vmRequestRestore();
      }


   hb_gt_wvwAddCharToInputQueue( keyCode );
}


static void hb_gt_wvwWindowPrologue( void )
{
   UINT uiWindow;

   if( s_pWvwData->s_usNumWindows >= WVW_MAXWINDOWS )
      /*  Runtime error
       */
      hb_errRT_TERM( EG_BOUND, 10001, "Maximum Number of Windows Exceeded", "hb_gt_wvwWindowPrologue()", 0, 0 );

   s_pWvwData->s_usNumWindows++;
   uiWindow = s_pWvwData->s_usNumWindows;
   s_pWvwData->s_pWindows[ uiWindow - 1 ] = ( WIN_DATA * ) hb_xgrab( sizeof( WIN_DATA ) );
   memset( s_pWvwData->s_pWindows[ uiWindow - 1 ], 0, sizeof( WIN_DATA ) );

}

static void hb_gt_wvwWindowEpilogue( void )
{

   if( s_pWvwData->s_usNumWindows == 0 )
      hb_errRT_TERM( EG_BOUND, 10001, "No more window to destroy", "hb_gt_wvwWindowEpilogue()", 0, 0 );
   hb_xfree( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ] );
   s_pWvwData->s_usNumWindows--;

   if( s_pWvwData->s_usNumWindows > 0 )
      s_pWvwData->s_usCurWindow = s_pWvwData->s_usNumWindows - 1;
}

static UINT hb_gt_wvwOpenWindow( LPCTSTR lpszWinName, int iRow1, int iCol1, int iRow2, int iCol2,
                                 DWORD dwStyle, int iParentWin ) /*assume s_pWvwData->s_usNumWindows >= 1 (ie. this will be the second or third window)
                                                                  * this is similar to gt_init(), only gt_init() is for Main Window
                                                                  * usRowx and usColx determine the initial position and initial size of window
                                                                  *(relative to MAIN window, NOT to parent window)
                                                                  */
{
   HWND hWnd;

   WNDCLASS   wndclass;
   WIN_DATA * pParentWindow;
   int        iCmdShow;

   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvwOpenWindow()" ) );

   /* in MainCoord Mode make sure that usRowx and usColx are within Main Window's bound! */
#if 0
   if( s_pWvwData->s_bMainCoordMode && ( ! hb_gt_wvwInWindow( 0, iRow1, iCol1 ) || ! hb_gt_wvwInWindow( 0, iRow2, iCol2 ) ) )
   {
      MessageBox( NULL, TEXT( "Invalid (Row,Col)" ),
                  lpszWinName, MB_ICONERROR );
      return 0;
   }
#endif

   if( iParentWin < 0 )
      pParentWindow = NULL;

   else
      pParentWindow = s_pWvwData->s_pWindows[ ( USHORT ) iParentWin ];

   InitCommonControls();

   if( ! s_pWvwData->s_bSWRegistered && ( s_pWvwData->s_usNumWindows == 1 ) )
   {
      wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
      wndclass.lpfnWndProc   = hb_gt_wvwWndProc;
      wndclass.cbClsExtra    = 0;
      wndclass.cbWndExtra    = 0;
      wndclass.hInstance     = s_pWvwData->hInstance;
      wndclass.hIcon         = NULL;
      wndclass.hCursor       = LoadCursor( NULL, IDC_ARROW );
      wndclass.hbrBackground = NULL;
      wndclass.lpszMenuName  = NULL;
      wndclass.lpszClassName = s_pWvwData->szSubWinName;

      if( ! RegisterClass( &wndclass ) )
      {

         MessageBox( NULL, TEXT( "Failed to register class." ),
                     s_pWvwData->szSubWinName, MB_ICONERROR );
         return 0;
      }

      s_pWvwData->s_bSWRegistered = TRUE;
   }

   hb_gt_wvwWindowPrologue();
   hb_gtInitStatics( s_pWvwData->s_usNumWindows - 1, lpszWinName, ( USHORT ) iRow1, ( USHORT ) iCol1, ( USHORT ) iRow2, ( USHORT ) iCol2 );

   hWnd = CreateWindow( s_pWvwData->szSubWinName,
                        lpszWinName,             /* window name */

                        dwStyle,

                        /* notes: do NOT use WS_CHILD style for subwindows
                                  child windows can NOT get input focus
                           TODO: handle WM_MOVE to simulate behaviour similar to WS_CHILD's
                                 at least to keep subwindow "nearby" the MAIN window */

                        0,                                                       /*x               */
                        0,                                                       /*y               */
                        CW_USEDEFAULT,                                           /*width           */
                        CW_USEDEFAULT,                                           /*height          */

                        ( pParentWindow == NULL ? NULL : pParentWindow->hWnd ),  /*x parent window */

                        NULL,                                                    /*menu            */
                        s_pWvwData->hInstance,                                   /*x instance      */
                        NULL );                                                  /*lpParam         */

   s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->hWnd = hWnd;

   if( hWnd == NULL )
   {

      LPVOID lpMsgBuf;

      FormatMessage(
         FORMAT_MESSAGE_ALLOCATE_BUFFER |
         FORMAT_MESSAGE_FROM_SYSTEM |
         FORMAT_MESSAGE_IGNORE_INSERTS,
         NULL,
         GetLastError(),
         MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
         ( LPTSTR ) &lpMsgBuf,
         0,
         NULL
         );

      MessageBox( NULL, ( LPCTSTR ) lpMsgBuf, "WINAPI failed to CreateWindow", MB_ICONERROR );
      LocalFree( lpMsgBuf );

      hb_gt_wvwWindowEpilogue();

      return 0;
   }

   if( s_pWvwData->s_sApp->pSymWVW_PAINT && s_pWvwData->s_uiPaintRefresh > 0 )
      SetTimer( hWnd, WVW_ID_SYSTEM_TIMER, ( UINT ) s_pWvwData->s_uiPaintRefresh, NULL );

   /* If you wish to show window the way you want, put somewhere in your application
    * ANNOUNCE HB_NOSTARTUPWINDOW
    * If so compiled, then you need to issue wvw_ShowWindow( nWinNum, SW_RESTORE )
    * at the point you desire in your code.
    */

   if( s_pWvwData->s_bNOSTARTUPSUBWINDOW )
      iCmdShow = SW_HIDE;
   else
      iCmdShow = SW_SHOWNORMAL;

   ShowWindow( hWnd, iCmdShow );
   UpdateWindow( hWnd );

   hb_gt_wvwSetWindowTitle( s_pWvwData->s_usNumWindows - 1, lpszWinName );

   hb_gt_wvwCreateObjects( s_pWvwData->s_usNumWindows - 1 );

   s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->hdc     = GetDC( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->hWnd );
   s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->hCompDC = CreateCompatibleDC( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->hdc );
   s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->hIcon   = NULL;

   /* Apos o Device Context e as PENs e BRUSHes criados, atribuo uma PEN e um BRUSH qualquer apenas para pegar
      o handle original da PEN e BRUSH do Device Context */
   /* E, logo apos, restaura aos valores originais mantendo em s_pWvwData->s_sApp os valores salvos para restauracao
      quando for utilizar DeleteObject()
    */
   SelectObject( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->hdc, ( HPEN ) s_pWvwData->s_sApp->OriginalPen );
   SelectObject( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->hdc, ( HBRUSH ) s_pWvwData->s_sApp->OriginalBrush );


   return s_pWvwData->s_usNumWindows - 1;
}

static void hb_gt_wvwCloseWindow( void ) /*assume s_pWvwData->s_usNumWindows >= 2 (ie. we are not closing main window)
                                          * similar to gt_exit(), only gt_exit() closes main window
                                          */
{
   WIN_DATA *     pWindowData;
   CONTROL_DATA * pcd;

   HB_TRACE( HB_TR_DEBUG, ( "hb_gt_wvwCloseWindow()" ) );

   /* destroy objects from current (last/topmost) window */

   pWindowData = ( WIN_DATA * ) s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ];

   if( pWindowData->hWnd )
   {

      KillTimer( pWindowData->hWnd, WVW_ID_SYSTEM_TIMER );

      if( s_pWvwData->s_sApp->pSymWVW_TIMER )
         KillTimer( pWindowData->hWnd, WVW_ID_BASE_TIMER + s_pWvwData->s_usNumWindows - 1 );

      /* 2004-09-21 IMPORTANT:
         All these PENs and BRUSHes deletions return OK,
         but GDI objects are reported as still in use by Task Manager.
         We now temporarily disable PENs and BRUSHes creation during
         window ppening.
         See also gt_exit.
         TODO: pls choose:
         (1) store PENs and BRUSHes as application-wide
         or
         (2) do the creation and deletion only when required
       */
      /* 2004-09-23 choose #1 of above option
         DeleteObject( ( HPEN   ) pWindowData->penWhite );
         DeleteObject( ( HPEN   ) pWindowData->penWhiteDim );
         DeleteObject( ( HPEN   ) pWindowData->penBlack );
         DeleteObject( ( HPEN   ) pWindowData->penDarkGray );
         DeleteObject( ( HPEN   ) pWindowData->penGray );
         DeleteObject( ( HPEN   ) pWindowData->penNull );
         DeleteObject( ( HPEN   ) pWindowData->currentPen );
         DeleteObject( ( HBRUSH ) pWindowData->currentBrush );
         DeleteObject( ( HBRUSH ) pWindowData->diagonalBrush );
         DeleteObject( ( HBRUSH ) pWindowData->solidBrush );
         DeleteObject( ( HBRUSH ) pWindowData->wvwWhiteBrush );
       */

      DeleteObject( ( HFONT ) pWindowData->hFont );

      if( pWindowData->hdc )
         ReleaseDC( pWindowData->hWnd, pWindowData->hdc );

      if( pWindowData->hCompDC )
         DeleteDC( pWindowData->hCompDC );

      while( pWindowData->pcdCtrlList )
      {
         pcd = pWindowData->pcdCtrlList->pNext;
         DestroyWindow( pWindowData->pcdCtrlList->hWndCtrl );

         if( pWindowData->pcdCtrlList->phiCodeBlock )
            hb_itemRelease( pWindowData->pcdCtrlList->phiCodeBlock );


         hb_xfree( pWindowData->pcdCtrlList );
         pWindowData->pcdCtrlList = pcd;
      }

      DestroyWindow( pWindowData->hWnd );

      if( pWindowData->hPBfont )
         DeleteObject( ( HFONT ) pWindowData->hPBfont );

      if( pWindowData->hCBfont )
         DeleteObject( ( HFONT ) pWindowData->hCBfont );

      if( pWindowData->hCXfont )
         DeleteObject( ( HFONT ) pWindowData->hCXfont );

      if( pWindowData->hSBfont )
         DeleteObject( ( HFONT ) pWindowData->hSBfont );

      if( pWindowData->hSTfont )
         DeleteObject( ( HFONT ) pWindowData->hSTfont );

      if( pWindowData->hIcon )
         DestroyIcon( ( HICON ) pWindowData->hIcon );
   }

   hb_gt_wvwWindowEpilogue();

   /*

      if (s_pWvwData->s_usNumWindows == 1)
      {
      if (!UnregisterClass( s_pWvwData->szSubWinName,s_pWvwData->hInstance ))
      {
       MessageBox( NULL, TEXT( "Failed UnregisterClass" ),
                   s_pWvwData->szAppName, MB_ICONERROR );
      }
      }
    */

   SetFocus( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->hWnd );

}

static BOOL hb_gt_wvwBufferedKey( LONG lKey )
{

   return lKey != VK_SHIFT &&
          lKey != VK_MENU &&
          lKey != VK_CONTROL &&
          lKey != VK_PAUSE &&
          lKey != VK_CAPITAL &&
          lKey != VK_NUMLOCK &&
          lKey != VK_SCROLL;
}

static BOOL hb_gt_wvwAcceptingInput( void ) /* returns TRUE if we are accepting input,
                                             * ie. Current focused window is the topmost window
                                             */
{
   HWND hWndFocus = ( HWND ) GetFocus();

   return hWndFocus == s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->hWnd ||
          GetControlClass( s_pWvwData->s_usNumWindows - 1, hWndFocus ) > 0;
}

/* this TIMERPROC is to flash the topmost window using FlashWindow.
   need to do it this way since FlashWindowEx is not available in Win95 */
static VOID CALLBACK hb_gt_wvwFlashWindow( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime )
{
   static BYTE byCount = 0;

   HB_SYMBOL_UNUSED( uMsg );
   HB_SYMBOL_UNUSED( dwTime );

   FlashWindow( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->hWnd, TRUE );

   if( ++byCount >= 15 )
   {

      KillTimer( hwnd, idEvent );
      byCount = 0;
      s_pWvwData->s_bFlashingWindow = FALSE;
   }
}

static void hb_gt_wvwInputNotAllowed( UINT usWinNum, UINT message, WPARAM wParam, LPARAM lParam )
{

   /* user may handle this event and returns .T. from .prg level
      using function WVW_INPUTFOCUS()
    */
   if( s_pWvwData->s_sApp->pSymWVW_INPUTFOCUS )
   {
      BOOL bHandled = FALSE;

      if( hb_vmRequestReenter() )
      {

         hb_vmPushDynSym( s_pWvwData->s_sApp->pSymWVW_INPUTFOCUS );
         hb_vmPushNil();
         hb_vmPushInteger( ( int ) ( usWinNum ) );
         hb_vmPushNumInt( ( HB_MAXINT ) ( HB_PTRDIFF ) s_pWvwData->s_pWindows[ usWinNum ]->hWnd    );
         hb_vmPushNumInt( message );
         hb_vmPushNumInt( wParam  );
         hb_vmPushNumInt( lParam  );
         hb_vmDo( 5 );

         bHandled = hb_parnl( -1 );
         hb_vmRequestRestore();
      }

      if( bHandled )
         return;
   }

   MessageBeep( MB_OK );

   /* this simpler method is not available in Win95
      fwi.cbSize = sizeof(fwi);
      fwi.hwnd = s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows-1 ]->hWnd;
      fwi.dwFlags = FLASHW_CAPTION | FLASHW_TRAY;
      fwi.uCount = 5;
      fwi.dwTimeout = 100;
      FlashWindowEx(&fwi);
    */

   if( ! s_pWvwData->s_bFlashingWindow )
   {
      s_pWvwData->s_bFlashingWindow = TRUE;
      SetTimer( NULL, 0, 50, ( TIMERPROC ) hb_gt_wvwFlashWindow );
   }

}

/********************************************************************
   MainCoord Mode
 ********************************************************************
   In this mode an xHarbour program uses (row,col) coordinate relative to
   Main Window's coordinate. It is similar to old Clipper program which
   uses coordinate relative to the physical screen area.

   This mode can be set and reset during runtime,eg.
   oldCoordMode := wvw_SetMainCoord( .t. )

   Illustration:
 *+------
 *|Main Window (Window 0)
 *|MaxRow()=24 MaxCol()=79
 |   +---------------
 |   |Window1 RowOfs=3 ColOfs=4
 |   |MaxRow()=9 MaxCol()=29
 |   |          +--------------------------------------+
 |   |          |Window2 RowOfs=6 ColOfs=15            |
 |   |          |MaxRow()=3 MaxCol()=49                |
 |   |          |                                      |

   @ 6,15 say "text1" will be written to Window2 starting at 0,0
   @ 3,15 say "text2" will be written to Window1 starting at 0,11
   @ 3, 2 say "text3" will be written to Main Window starting at 3,2

   Notice that the entire "text3" will be written in Main Window, disregarding
   the fact that "xt3" might be expected to be written to Window1. This
   potential unfortunate situation is considered a "punishment" for the
   "bad" practice of the programmer.

   If more than one pair of coordinate is dealt with, the second one is ignored.
   Example:
   Scroll(2,2,10,10) will operate on Main Window on the above illustration.

   WARNING:
   Remember current restriction that topmost window is the only one allowed
   to accept user input, still.

   GTWVW parts that needs to be modified:
   HB_GT_FUNC( ... ) should NOT call another HB_GT_FUNC() to avoid
   double translation of coordinates.

   Then all output oriented HB_GT_FUNC() needs to translate coord:
   - HB_GT_FUNC( hb_gt_wvw_PutText() )         c
   - HB_GT_FUNC( hb_gt_wvw_SetPos() )          c
   - HB_GT_FUNC( hb_gt_wvw_SetAttribute() )    c
   - HB_GT_FUNC( gt_xPutch() )          c
   - etc.

   Higher level functions uses coord as passed by user, eg.:
   - HB_FUNC( WVW_NOPENWINDOW )
   - etc.

   Lower level functions (both static and exported ones) use coord relative
   to the referred window, eg.:
   - hb_gt_wvwSetStringInTextBuffer()
   - hb_gt_wvwTextOut()
   - etc

 */

/* returns row offset of window usWinNum */
USHORT hb_gt_wvwRowOfs( UINT usWinNum )
{
   return s_pWvwData->s_pWindows[ usWinNum ]->usRowOfs;
}

/* returns col offset of window usWinNum */
USHORT hb_gt_wvwColOfs( UINT usWinNum )
{
   return s_pWvwData->s_pWindows[ usWinNum ]->usColOfs;
}

/*(usrow,uscol) is coordinate relative to Main Window (MainCoord Mode)
 * returns true if usrow and uscol is within MaxRow() and MaxCol() of Window usWinNum
 */
static BOOL hb_gt_wvwInWindow( UINT usWinNum, USHORT usrow, USHORT uscol )
{
   return usrow >= hb_gt_wvwRowOfs( usWinNum ) &&
          usrow <= ( s_pWvwData->s_pWindows[ usWinNum ]->ROWS - 1 + hb_gt_wvwRowOfs( usWinNum ) ) &&
          uscol >= hb_gt_wvwColOfs( usWinNum ) &&
          uscol <= ( s_pWvwData->s_pWindows[ usWinNum ]->COLS - 1 + hb_gt_wvwColOfs( usWinNum ) );
}

/*returns winnum containing (usRow,usCol) coordinate
 * only meaningful in s_pWvwData->s_bMainCoordMode
 */
static UINT hb_gt_wvwFindWindow( USHORT usRow, USHORT usCol )
{
   UINT i;

   if( ! s_pWvwData->s_bMainCoordMode )
      return s_pWvwData->s_usNumWindows - 1;

   for( i = s_pWvwData->s_usNumWindows - 1; i > 0; i-- )
      if( hb_gt_wvwInWindow( i, usRow, usCol ) )
         break;

   return i;
}

/* this is the prologue for any HB_GT_FUNC() that is output/coordinate oriented
 * called only if s_pWvwData->s_bMainCoordMode
 * row2 and col2 is not taken into account during window finding, but they are translated too
 */
void hb_gt_wvwFUNCPrologue( BYTE byNumCoord, int * iRow1, int * iCol1, int * iRow2, int * iCol2 )
{
   UINT usWinNum;

   if( byNumCoord < 2 )
      ( *iCol1 ) = ( USHORT ) s_pWvwData->s_pWindows[ 0 ]->caretPos.x;
   if( byNumCoord < 1 )
      ( *iRow1 ) = ( USHORT ) s_pWvwData->s_pWindows[ 0 ]->caretPos.y;

   usWinNum = hb_gt_wvwFindWindow( ( USHORT ) *iRow1, ( USHORT ) *iCol1 );

   if( iRow1 )
      ( *iRow1 ) -= hb_gt_wvwRowOfs( usWinNum );
   if( iCol1 )
      ( *iCol1 ) -= hb_gt_wvwColOfs( usWinNum );
   if( iRow2 )
      ( *iRow2 ) -= hb_gt_wvwRowOfs( usWinNum );
   if( iCol2 )
      ( *iCol2 ) -= hb_gt_wvwColOfs( usWinNum );

   hb_gt_wvwSetCurWindow( usWinNum );

}

/* this is the epilogue for any HB_GT_FUNC() that is output/coordinate oriented
 * called only if s_pWvwData->s_bMainCoordMode
 */
void hb_gt_wvwFUNCEpilogue( void )
{

   s_pWvwData->s_pWindows[ 0 ]->caretPos.y = s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->caretPos.y + hb_gt_wvwRowOfs( s_pWvwData->s_usCurWindow );
   s_pWvwData->s_pWindows[ 0 ]->caretPos.x = s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->caretPos.x + hb_gt_wvwColOfs( s_pWvwData->s_usCurWindow );

   hb_gt_wvwSetCurWindow( 0 );

   if( s_pWvwData->s_sApp->CaretExist && s_pWvwData->s_sApp->displayCaret )
      hb_gt_wvwSetCaretPos( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ] );


}

void hb_wvw_HBFUNCPrologue( UINT usWinNum,
                            USHORT * pusRow1, USHORT * pusCol1,
                            USHORT * pusRow2, USHORT * pusCol2 )
{

   if( pusRow1 )
      ( *pusRow1 ) -= hb_gt_wvwRowOfs( usWinNum );
   if( pusCol1 )
      ( *pusCol1 ) -= hb_gt_wvwColOfs( usWinNum );
   if( pusRow2 )
      ( *pusRow2 ) -= hb_gt_wvwRowOfs( usWinNum );
   if( pusCol2 )
      ( *pusCol2 ) -= hb_gt_wvwColOfs( usWinNum );

}

/*assigns a new value to s_pWvwData->s_usCurWindow
 * returns old value of s_pWvwData->s_usCurWindow
 * WARNING!! we must make sure that it is done in !s_pWvwData->s_bMainCoordMode, otherwise
 *          some GT_FUNC will be trapped into circular reference!
 */
static UINT hb_gt_wvwSetCurWindow( UINT usWinNum )
{
   UINT usOldWin = s_pWvwData->s_usCurWindow;
   BOOL bMainCoordMode;

   if( usWinNum == usOldWin )
      return usOldWin;

   s_pWvwData->s_usCurWindow = usWinNum;

   bMainCoordMode = s_pWvwData->s_bMainCoordMode;
   s_pWvwData->s_bMainCoordMode = FALSE;

   /*updating GTAPI's statics:
    * tell GTAPI about the new MaxRow(), MaxCol()
    */
   s_pWvwData->s_bQuickSetMode = TRUE;

   hb_gtSetMode( s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->ROWS, s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->COLS );

   s_pWvwData->s_bQuickSetMode = FALSE;

   /* tell GTAPI about the new Row(), Col() */

   hb_gtSetPos( ( SHORT ) s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->caretPos.y,
                ( SHORT ) s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ]->caretPos.x );
   /* done updating GTAPI's statics......... */

   s_pWvwData->s_bMainCoordMode = bMainCoordMode;

   return usOldWin;
}


/*                                                                   */
/*               Supporters of HB_GT_FUNC(...)                       */
/*               DONE: These all are to be made window selective!    */
/*                     all row and col are relative to its own window! */
/*               Budyanto Dj. <budyanto@centrin.net.id>              */
/*                                                                   */


/* NOTE:works for topmost window only */
static void hb_wvw_vmouse_Init( void )
{
   hb_wvw_vmouse_SetPos( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ], 0, 0 );
}

static void   hb_wvw_vmouse_Exit( void )
{
}

static void   hb_wvw_vmouse_SetPos( WIN_DATA * pWindowData, USHORT usRow, USHORT usCol )
{
   POINT xy = { 0 };

   hb_gt_wvwSetMouseY( pWindowData, usRow );
   hb_gt_wvwSetMouseX( pWindowData, usCol );

   xy = hb_gt_wvwGetXYFromColRow( pWindowData, usCol, usRow );

   if( ClientToScreen( pWindowData->hWnd, &xy ) )
      SetCursorPos( xy.x, xy.y + ( pWindowData->PTEXTSIZE.y / 2 ) );
}

static int hb_gt_wvw_usDispCount( WIN_DATA * pWindowData )
{
   return pWindowData->uiDispCount;
}

static void hb_gt_wvw_vDispBegin( WIN_DATA * pWindowData )
{
   ++( pWindowData->uiDispCount );
}

static void   hb_gt_wvw_vDispEnd( WIN_DATA * pWindowData )
{

   if( pWindowData->uiDispCount > 0 )
      --( pWindowData->uiDispCount );
   if( pWindowData->uiDispCount <= 0 )
      hb_gt_wvwDoInvalidateRect( pWindowData );
}

static void hb_gt_wvw_vGetText( WIN_DATA * pWindowData, USHORT top, USHORT left, USHORT bottom, USHORT right, BYTE * sBuffer )
{
   USHORT irow, icol, index, j;

   j = 0;
   for( irow = top; irow <= bottom; irow++ )
   {
      index = hb_gt_wvwGetIndexForTextBuffer( pWindowData, left, irow );
      for( icol = left; icol <= right; icol++ )
      {
         if( index >= pWindowData->BUFFERSIZE )
            break;
         else
         {
            sBuffer[ j++ ] = pWindowData->pBuffer[ index ];
            sBuffer[ j++ ] = pWindowData->pColors[ index ];
            index++;
         }
      }
   }
}

static void  hb_gt_wvw_vPuts( WIN_DATA * pWindowData, int iRow, int iCol, BYTE byColor, BYTE byAttr, BYTE * pbyStr, ULONG ulLen )
{
   hb_gt_wvwSetStringInTextBuffer( pWindowData, iCol, iRow, byColor, byAttr, pbyStr, ulLen );
#ifdef WVW_DEBUG
   nCountPuts++;
#endif
}

static void  hb_gt_wvw_vReplicate( WIN_DATA * pWindowData, int iRow, int iCol, int bColor, BYTE bAttr, USHORT usChar, ULONG ulLen )
{
   BYTE  ucBuff[ WVW_CHAR_BUFFER ], * byChars;
   ULONG i;
   BOOL  bMalloc = FALSE;

   if( ulLen > WVW_CHAR_BUFFER )
   {
      byChars = ( BYTE * ) hb_xgrab( ulLen );
      bMalloc = TRUE;
   }
   else
      byChars = ucBuff;

   for( i = 0; i < ulLen; i++ )
      *( byChars + i ) = ( BYTE ) usChar;

   hb_gt_wvwSetStringInTextBuffer( pWindowData, iCol, iRow, bColor, bAttr, byChars, ulLen );
   if( bMalloc )
      hb_xfree( byChars );
}


static BOOL hb_gt_wvw_GetChar( PHB_GT pGT, int iRow, int iCol,
                               int * pbColor, BYTE * pbAttr, USHORT * pusChar )
{
   WIN_DATA * pWindowData;
   long       lIndex;

   HB_SYMBOL_UNUSED( pbAttr );

   pWindowData = ( WIN_DATA * ) s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ];

   HB_GTSELF_CHECKPOS( pGT, iRow, iCol, &lIndex );

   if( lIndex < pWindowData->BUFFERSIZE )
   {
      *pusChar = pWindowData->pBuffer[ lIndex ];
      *pbColor = pWindowData->pColors[ lIndex ];

      return TRUE;
   }
   return FALSE;
}

static BOOL hb_gt_wvw_PutChar( PHB_GT pGT, int iRow, int iCol,
                               int bColor, BYTE bAttr, USHORT usChar )
{
   WIN_DATA * pWindowData;
   long       lIndex;

   HB_SYMBOL_UNUSED( bAttr );

   pWindowData = ( WIN_DATA * ) s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ];

   HB_GTSELF_CHECKPOS( pGT, iRow, iCol, &lIndex );

   if( lIndex < pWindowData->BUFFERSIZE )
   {
      pWindowData->pBuffer[ lIndex ] = ( BYTE ) usChar;
      pWindowData->pColors[ lIndex ] = bColor;

      return TRUE;
   }
   return FALSE;
}

static BOOL hb_gt_wvw_CheckPos( PHB_GT pGT, int iRow, int iCol, long * plIndex )
{
   WIN_DATA * pWindowData;

   HB_SYMBOL_UNUSED( pGT );

   pWindowData = ( WIN_DATA * ) s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ];
   *plIndex    = ( long ) hb_gt_wvwGetIndexForTextBuffer( pWindowData, ( USHORT ) iCol, ( USHORT ) iRow );

   return TRUE;
}

static void hb_gt_wvw_GetSize( PHB_GT pGT, int * piRows, int  * piCols )
{
   WIN_DATA * pWindowData;

   HB_SYMBOL_UNUSED( pGT );

   pWindowData = ( WIN_DATA * ) s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ];

   *piRows = pWindowData->ROWS;
   *piCols = pWindowData->COLS;
}

static void hb_gt_wvw_Save( PHB_GT pGT, int iTop, int iLeft, int iBottom, int iRight,
                            void * pBuffer )
{
   BYTE * pbyBuffer = ( BYTE * ) pBuffer;

   int i_Top    = ( iTop < 0 ? 0 : iTop );
   int i_Left   = ( iLeft < 0 ? 0 : iLeft );
   int i_Bottom = ( iBottom < 0 ? 0 : iBottom );
   int i_Right  = ( iRight < 0 ? 0 : iRight );

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCPrologue( 4, &i_Top, &i_Left, &i_Bottom, &i_Right );

   while( i_Top <= i_Bottom )
   {
      int    iColor;
      USHORT usChar;
      int    iCol;

      for( iCol = i_Left; iCol <= i_Right; ++iCol )
      {
         if( ! HB_GTSELF_GETCHAR( pGT, i_Top, iCol, &iColor, NULL, &usChar ) )
         {
            usChar = ( USHORT ) HB_GTSELF_GETCLEARCHAR( pGT );
            iColor = HB_GTSELF_GETCLEARCOLOR( pGT );
         }
         *pbyBuffer++ = ( BYTE ) usChar;
         *pbyBuffer++ = ( BYTE ) iColor;   /* TOFIX */
      }
      ++i_Top;
   }

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCEpilogue();
}

static void hb_gt_wvw_Rest( PHB_GT pGT, int iTop, int iLeft, int iBottom, int iRight,
                            const void * pBuffer )
{
   BYTE * pbyBuffer = ( BYTE * ) pBuffer;

   WIN_DATA * pWindowData;
   int        iSaveTop;
   int        i_Top    = ( iTop < 0 ? 0 : iTop );
   int        i_Left   = ( iLeft < 0 ? 0 : iLeft );
   int        i_Bottom = ( iBottom < 0 ? 0 : iBottom );
   int        i_Right  = ( iRight < 0 ? 0 : iRight );

   pWindowData = ( WIN_DATA * ) s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ];

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCPrologue( 4, &i_Top, &i_Left, &i_Bottom, &i_Right );

   iSaveTop = i_Top;

   while( iSaveTop <= i_Bottom )
   {
      int    bColor;
      USHORT usChar;
      int    iCol;

      for( iCol = i_Left; iCol <= i_Right; ++iCol )
      {
         usChar = *pbyBuffer++;
         bColor = *pbyBuffer++;

         HB_GTSELF_PUTCHAR( pGT, iSaveTop, iCol, bColor, 0, usChar );

      }
      ++iSaveTop;
   }

   pWindowData->InvalidateWindow = TRUE;
   hb_gt_wvwSetInvalidRect( pWindowData, ( USHORT ) i_Left, ( USHORT ) i_Top, ( USHORT ) i_Right, ( USHORT ) i_Bottom );

   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwFUNCEpilogue();
}

static void hb_gt_wvw_ExposeArea( PHB_GT pGT, int iTop, int iLeft, int iBottom, int iRight )
{
   HB_SYMBOL_UNUSED( pGT );
   HB_SYMBOL_UNUSED( iTop );
   HB_SYMBOL_UNUSED( iLeft );
   HB_SYMBOL_UNUSED( iBottom );
   HB_SYMBOL_UNUSED( iRight );
}


static void  hb_gt_wvw_vPutText( WIN_DATA * pWindowData, USHORT top, USHORT left, USHORT bottom, USHORT right, const char * sBuffer, int bColor )
{
   USHORT irow, icol, index, j;

   j = 0;
   for( irow = top; irow <= bottom; irow++ )
   {
      index = hb_gt_wvwGetIndexForTextBuffer( pWindowData, left, irow );
      for( icol = left; icol <= right; icol++ )
      {
         if( index >= pWindowData->BUFFERSIZE )
            break;
         else
         {
            pWindowData->pBuffer[ index ] = sBuffer[ j++ ];

            if( bColor )
               pWindowData->pColors[ index ] = bColor;
            else
               pWindowData->pColors[ index ] = sBuffer[ j++ ];
            index++;
         }
      }
   }
   hb_gt_wvwSetInvalidRect( pWindowData, ( USHORT ) left, ( USHORT ) top, ( USHORT ) right, ( USHORT ) bottom );
}

static void  hb_gt_wvw_vSetAttribute( WIN_DATA * pWindowData, int iTop, int iLeft, int iBottom, int iRight, int bColor )
{
   int irow, icol, index;


   for( irow = iTop; irow <= iBottom; irow++ )
   {
      index = hb_gt_wvwGetIndexForTextBuffer( pWindowData, ( USHORT ) iLeft, ( USHORT ) irow );
      for( icol = iLeft; icol <= iRight; icol++ )
      {
         if( index >= pWindowData->BUFFERSIZE )
            break;
         else
            pWindowData->pColors[ index++ ] = bColor;
      }
   }
   hb_gt_wvwSetInvalidRect( pWindowData, ( USHORT ) iLeft, ( USHORT ) iTop, ( USHORT ) iRight, ( USHORT ) iBottom );
}

static BOOL  hb_gt_wvw_bSetMode( WIN_DATA * pWindowData, USHORT row, USHORT col )
{
   BOOL  bResult = FALSE;
   HFONT hFont;

   if( row <= WVW_MAX_ROWS && col <= WVW_MAX_COLS )
   {

      if( pWindowData->hWnd )
      {
         hFont = hb_gt_wvwGetFont( pWindowData->fontFace, pWindowData->fontHeight, pWindowData->fontWidth, pWindowData->fontWeight, pWindowData->fontQuality, pWindowData->CodePage );
         if( hFont )
         {
            /* make sure that the mode selected along with the current
             * font settings will fit in the window
             *
             * JC1: See my note
             * x gtwvt comments out the following condition! (see also SetFont)
             * x TODO: I THINK I am right to keep it, am I?
             */
            if( hb_gt_wvwValidWindowSize( pWindowData, row, col, hFont, pWindowData->fontWidth, NULL, NULL ) )
               bResult = hb_gt_wvwInitWindow( pWindowData, pWindowData->hWnd, col, row );

            DeleteObject( hFont );
            /* HB_GTSELF_REFRESH( hb_gt_Base() ); */
         }
      }
      else
         bResult = hb_gt_wvwAllocSpBuffer( pWindowData, row, col );
   }
   return bResult;
}

static void  hb_gt_wvw_vxPutch( WIN_DATA * pWindowData, USHORT iRow, USHORT iCol, int bColor, BYTE bChar )
{
   USHORT index;

   index = hb_gt_wvwGetIndexForTextBuffer( pWindowData, iCol, iRow );
   if( index < pWindowData->BUFFERSIZE )
   {
      pWindowData->pBuffer[ index ] = bChar;
      pWindowData->pColors[ index ] = bColor;

      /*  determine bounds of rect around character to refresh
       */
      hb_gt_wvwSetInvalidRect( pWindowData, iCol, iRow, iCol, iRow );
   }
}

static void hb_gt_wvw_usBox( WIN_DATA * pWindowData, int iTop, int iLeft, int iBottom, int iRight,
                             const char * pbyFrame, int bColor )
{
   int    i;
   int    iRow;
   int    iCol;
   int    iHeight;
   int    iWidth;
   USHORT sWidth  = pWindowData->COLS;
   USHORT sHeight = pWindowData->ROWS;
   BYTE   szBox[ 10 ];
   BYTE   bPadCh = ( BYTE ) HB_GTSELF_GETCLEARCHAR( hb_gt_Base() );

   if( ( iLeft >= 0 && iLeft < sWidth ) ||
       ( iRight >= 0 && iRight < sWidth ) ||
       ( iTop >= 0 && iTop < sHeight ) ||
       ( iBottom >= 0 && iBottom < sHeight ) )
   {
      if( pbyFrame )
         for( i = 0; *pbyFrame && i < 9; ++i )
            bPadCh = szBox[ i ] = *pbyFrame++;
      else
         i = 0;

      while( i < 8 )
         szBox[ i++ ] = bPadCh;
      szBox[ i ] = '\0';

      /* Ensure that box is drawn from Top Left to Bottom Right. */
      if( iTop > iBottom )
      {
         iRow    = iTop;
         iTop    = iBottom;
         iBottom = iRow;
      }
      if( iLeft > iRight )
      {
         iRow   = iLeft;
         iLeft  = iRight;
         iRight = iRow;
      }

      /* Draw the box or line as specified */
      iHeight = iBottom - iTop + 1;
      iWidth  = iRight - iLeft + 1;

      hb_gt_wvw_vDispBegin( pWindowData );

      if( iHeight > 1 && iWidth > 1 &&
          iTop >= 0 && iTop < sHeight &&
          iLeft >= 0 && iLeft < sWidth )
         hb_gt_wvw_vxPutch( pWindowData, ( USHORT ) iTop, ( USHORT ) iLeft, bColor, szBox[ 0 ] );  /* Upper Left corner */

      iCol = ( iWidth > 1 ? iLeft + 1 : iLeft );
      if( iCol < 0 )
      {
         iWidth += iCol;
         iCol    = 0;
      }
      if( iRight >= sWidth )
         iWidth -= iRight - sWidth;

      if( iCol < iRight && iCol < sWidth &&
          iTop >= 0 && iTop < sHeight )
         hb_gt_wvw_vReplicate( pWindowData, iTop, iCol, bColor, HB_GT_ATTR_BOX, szBox[ 1 ], iWidth + ( ( iRight - iLeft ) > 1 ? -2 : 0 ) );    /* iTop line */
      if( iHeight > 1 &&
          ( iRight - iLeft ) > 0 && iRight < sWidth &&
          iTop >= 0 && iTop < sHeight )
         hb_gt_wvw_vxPutch( pWindowData, ( USHORT ) iTop, ( USHORT ) iRight, bColor, szBox[ 2 ] );  /* Upper Right corner */
      if( szBox[ 8 ] && iHeight > 2 && iWidth > 2 )
      {
         for( iRow = iTop + 1; iRow < iBottom; iRow++ )
            if( iRow >= 0 && iRow < sHeight )
            {
               iCol = iLeft;
               if( iCol < 0 )
                  iCol = 0;                                                                                                           /* The width was corrected earlier. */
               else
                  hb_gt_wvw_vxPutch( pWindowData, ( USHORT ) iRow, ( USHORT ) iCol++, bColor, szBox[ 7 ] );                           /* Left side */

               hb_gt_wvw_vReplicate( pWindowData, ( USHORT ) iRow, ( USHORT ) iCol, bColor, HB_GT_ATTR_BOX, szBox[ 8 ], iWidth - 2 ); /* Fill */
               if( iRight < sWidth )
                  hb_gt_wvw_vxPutch( pWindowData, ( USHORT ) iRow, ( USHORT ) iRight, bColor, szBox[ 3 ] );                           /* Right side */
            }
      }
      else
      {
         for( iRow = ( iWidth > 1 ? iTop + 1 : iTop ); iRow < ( ( iRight - iLeft ) > 1 ? iBottom : iBottom + 1 ); iRow++ )
            if( iRow >= 0 && iRow < sHeight )
            {
               if( iLeft >= 0 && iLeft < sWidth )
                  hb_gt_wvw_vxPutch( pWindowData, ( USHORT ) iRow, ( USHORT ) iLeft, bColor, szBox[ 7 ] );            /* Left side */
               if( ( iWidth > 1 || iLeft < 0 ) && iRight < sWidth )
                  hb_gt_wvw_vxPutch( pWindowData, ( USHORT ) iRow, ( USHORT ) iRight, bColor, szBox[ 3 ] );           /* Right side */
            }
      }

      if( iHeight > 1 && iWidth > 1 )
      {
         if( iLeft >= 0 && iBottom < sHeight )
            hb_gt_wvw_vxPutch( pWindowData, ( USHORT ) iBottom, ( USHORT ) iLeft, bColor, szBox[ 6 ] );              /* Bottom iLeft corner */
         iCol = iLeft + 1;
         if( iCol < 0 )
            iCol = 0;                                                                                            /* The width was corrected earlier. */
         if( iCol <= iRight && iBottom < sHeight )
            hb_gt_wvw_vReplicate( pWindowData, iBottom, iCol, bColor, HB_GT_ATTR_BOX, szBox[ 5 ], iWidth - 2 );  /* Bottom line */
         if( iRight < sWidth && iBottom < sHeight )
            hb_gt_wvw_vxPutch( pWindowData, ( USHORT ) iBottom, ( USHORT ) iRight, bColor, szBox[ 4 ] );         /* Bottom Right corner */
      }

      hb_gt_wvw_vDispEnd( pWindowData );
   }
}

static void  hb_gt_wvw_vSetPos( WIN_DATA * pWindowData, int iRow, int iCol )
{

   if( iRow >= 0 && iRow < pWindowData->ROWS && iCol >= 0 && iCol <= pWindowData->COLS )
   {
      pWindowData->caretPos.x = iCol;
      pWindowData->caretPos.y = iRow;
      hb_gt_wvwValidateCaret( pWindowData );
   }
}


/*                                                                   */
/*               Other static functions                              */
/*               Budyanto Dj. <budyanto@centrin.net.id>              */
/*                                                                   */


/*hb_wvw_InitPendingRect( ) is called during init static, or after userpaint */
/*This function must be called only when bPaintPending == FALSE              */

static void   hb_wvw_InitPendingRect( WIN_DATA * pWindowData )
{

   pWindowData->rPaintPending.left   = WVW_MAX_COLS - 1;
   pWindowData->rPaintPending.top    = WVW_MAX_ROWS - 1;
   pWindowData->rPaintPending.right  = 0;
   pWindowData->rPaintPending.bottom = 0;
}


/*hb_wvw_UpdatePendingRect( ) is called by hb_gt_wvwWndProc()        */
/*This function's job is to update paint pending rect                */

static void   hb_wvw_UpdatePendingRect( WIN_DATA * pWindowData, USHORT usRow1, USHORT usCol1, USHORT usRow2, USHORT usCol2 )
{
   pWindowData->rPaintPending.left   = HB_MIN( pWindowData->rPaintPending.left, usCol1 );
   pWindowData->rPaintPending.top    = HB_MIN( pWindowData->rPaintPending.top, usRow1 );
   pWindowData->rPaintPending.right  = HB_MAX( pWindowData->rPaintPending.right, usCol2 );
   pWindowData->rPaintPending.bottom = HB_MAX( pWindowData->rPaintPending.bottom, usRow2 );
}

/* returns lineheight, ie. including linespacing if any */
BYTE   hb_wvw_LineHeight( WIN_DATA * pWindowData )
{
   return ( ( BYTE ) ( LONG ) ( pWindowData->PTEXTSIZE.y ) ) + ( BYTE ) pWindowData->byLineSpacing;
}

/* fills linespace above and below the text area.
   caller should check that linespacing is > 0.
   has no effect if linespacing == 0 */
static void hb_gt_wvwFillLineSpace( WIN_DATA * pWindowData, HDC hdc, USHORT startCol, USHORT irow, USHORT len, BYTE byAttrib )
{
   RECT     rc = { 0 };
   LOGBRUSH lb = { 0 };
   HBRUSH   hBrush;

   int      byColorIndex = pWindowData->iLSpaceColor < 0 ? ( ( byAttrib & 0x00F0 ) >> 4 ) : pWindowData->iLSpaceColor;
   COLORREF bkColor      = _COLORS[ byColorIndex ];

   rc.top    = irow;
   rc.left   = startCol;
   rc.bottom = irow;
   rc.right  = startCol + len - 1;
   rc        = hb_gt_wvwGetXYFromColRowRect( pWindowData, rc );

   lb.lbStyle = BS_SOLID;
   lb.lbColor = bkColor;
   lb.lbHatch = 0;

   hBrush = CreateBrushIndirect( &lb );

   rc.bottom = rc.top;
   rc.top   -= ( pWindowData->byLineSpacing / 2 );
   FillRect( hdc, &rc, hBrush );

   rc.top    = rc.bottom + pWindowData->PTEXTSIZE.y;
   rc.bottom = rc.top + ( pWindowData->byLineSpacing / 2 );
   FillRect( hdc, &rc, hBrush );

   SelectObject( s_pWvwData->s_pWindows[ 0 ]->hdc, ( HBRUSH ) s_pWvwData->s_sApp->OriginalBrush );
   DeleteObject( hBrush );

}


/*                                                                   */
/*               Exported functions for API calls                    */

/*                                                                   */


BOOL hb_gt_wvwSetMenuKeyEvent( UINT usWinNum, int iMenuKeyEvent )
{
   int iOldEvent;

   iOldEvent = s_pWvwData->s_pWindows[ usWinNum ]->MenuKeyEvent;
   if( iMenuKeyEvent )
      s_pWvwData->s_pWindows[ usWinNum ]->MenuKeyEvent = iMenuKeyEvent;
   return iOldEvent;
}


static BOOL hb_gt_wvwSetCentreWindow( UINT usWinNum, BOOL bCentre, BOOL bPaint )
{
   BOOL bWasCentre;

   bWasCentre = s_pWvwData->s_pWindows[ usWinNum ]->CentreWindow;
   s_pWvwData->s_pWindows[ usWinNum ]->CentreWindow = bCentre;
   if( bPaint )
   {

      if( ! IsZoomed( s_pWvwData->s_pWindows[ usWinNum ]->hWnd ) )
         ShowWindow( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, SW_RESTORE );

      else
         ShowWindow( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, SW_MAXIMIZE );

      hb_gt_wvwResetWindowSize( s_pWvwData->s_pWindows[ usWinNum ], s_pWvwData->s_pWindows[ usWinNum ]->hWnd );
   }
   return bWasCentre;
}


void hb_gt_wvwResetWindow( UINT usWinNum )
{
   hb_gt_wvwResetWindowSize( s_pWvwData->s_pWindows[ usWinNum ], s_pWvwData->s_pWindows[ usWinNum ]->hWnd );
}


static BOOL hb_gt_wvwSetCodePage( UINT usWinNum, int iCodePage )
{
   int iOldCodePage;

   iOldCodePage = s_pWvwData->s_pWindows[ usWinNum ]->CodePage;
   if( iCodePage )
      s_pWvwData->s_pWindows[ usWinNum ]->CodePage = iCodePage;
   if( iOldCodePage != iCodePage )
      hb_gt_wvwResetWindow( usWinNum );
   return iOldCodePage;
}


int hb_gt_wvwGetLastMenuEvent( UINT usWinNum )
{
   return s_pWvwData->s_pWindows[ usWinNum ]->LastMenuEvent;
}


int hb_gt_wvwSetLastMenuEvent( UINT usWinNum, int iLastMenuEvent )
{
   int iRetval = s_pWvwData->s_pWindows[ usWinNum ]->LastMenuEvent;

   s_pWvwData->s_pWindows[ usWinNum ]->LastMenuEvent = iLastMenuEvent;
   return iRetval;
}


static void hb_gt_wvwSetWindowTitle( UINT usWinNum, LPCSTR title )
{
   SetWindowText( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, title );
}

static PHB_ITEM hb_gt_wvw_GetWindowTitle( UINT usWinNum, PHB_ITEM pItem )
{
   TCHAR buffer[ WVW_MAX_TITLE_SIZE ];
   int   iResult;

   iResult = GetWindowText( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, buffer, WVW_MAX_TITLE_SIZE );
   buffer[ HB_SIZEOFARRAY( buffer ) - 1 ] = TEXT( '\0' );
   if( iResult > 0 )
      return HB_ITEMPUTSTR( pItem, buffer );
   else
      return hb_itemPutC( pItem, NULL );
}


static HICON hb_gt_wvwSetWindowIcon( UINT usWinNum, int icon, const char * lpIconName )
{
   HICON hIcon;

   if( lpIconName == NULL )
      hIcon = LoadIcon( s_pWvwData->hInstance, MAKEINTRESOURCE( icon ) );
   else
      hIcon = LoadIcon( s_pWvwData->hInstance, lpIconName );

   if( hIcon )
   {
      SendMessage( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, WM_SETICON, ICON_SMALL, ( LPARAM ) hIcon ); /* Set Title Bar ICON */
      SendMessage( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, WM_SETICON, ICON_BIG, ( LPARAM ) hIcon );   /* Set Task List Icon */
      s_pWvwData->s_pWindows[ usWinNum ]->hIcon = hIcon;
   }

   return hIcon;
}


static HICON hb_gt_wvwSetWindowIconFromFile( UINT usWinNum, LPCTSTR icon )
{
   HICON hIcon = ( HICON ) LoadImage( ( HINSTANCE ) NULL, icon, IMAGE_ICON, 0, 0, LR_LOADFROMFILE );

   if( hIcon )
   {
      SendMessage( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, WM_SETICON, ICON_SMALL, ( LPARAM ) hIcon ); /* Set Title Bar ICON */
      SendMessage( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, WM_SETICON, ICON_BIG, ( LPARAM ) hIcon );   /* Set Task List Icon */
      s_pWvwData->s_pWindows[ usWinNum ]->hIcon = hIcon;
   }

   return hIcon;
}


int hb_gt_wvwGetWindowTitle( UINT usWinNum, char * title, int length )
{
   return GetWindowText( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, title, length );
}


BOOL hb_gt_wvwSetFont( UINT usWinNum, const char * fontFace, int height, int width, int Bold, int Quality )
{
   int        size;
   BOOL       bResult     = FALSE;
   HFONT      hFont       = hb_gt_wvwGetFont( fontFace, height, width, Bold, Quality, s_pWvwData->s_pWindows[ usWinNum ]->CodePage );
   WIN_DATA * pWindowData = s_pWvwData->s_pWindows[ usWinNum ];

   /* make sure the font could actually be created
    */
   if( hFont )
   {
      /* make sure that the font  will fit inside the
       * window with the current pWindowData->ROWS and pWindowData->COLS setting
       *
       * JC1: There's definitely something WRONG with this way of thinking.
       * This makes effectively impossible to enlarge the window from it's
       * initial size.
       *
       * x with the above remark, gtwvt comments out the following condition:
       * x TODO: I THINK I am I to keep it, am I?
       */

      if( hb_gt_wvwValidWindowSize( pWindowData, pWindowData->ROWS, pWindowData->COLS, hFont, width, NULL, NULL ) )
      {
         pWindowData->fontHeight  = height;
         pWindowData->fontWidth   = width;
         pWindowData->fontWeight  = Bold;
         pWindowData->fontQuality = Quality;

         size = strlen( fontFace );
         if( ( size > 0 ) && ( size < LF_FACESIZE - 1 ) )
            strcpy( pWindowData->fontFace, fontFace );
         if( pWindowData->hWnd )
         {
            /* resize the window based on new fonts
             */
            hb_gt_wvwResetWindowSize( pWindowData, pWindowData->hWnd );

            /* force resize of caret
             */
            hb_gt_wvwKillCaret( pWindowData );
            hb_gt_wvwCreateCaret( pWindowData );
         }
         bResult = TRUE;
      }
      DeleteObject( hFont );
   }
   return bResult;
}


HWND hb_gt_wvwGetWindowHandle( UINT usWinNum )
{
   return s_pWvwData->s_pWindows[ usWinNum ]->hWnd;
}


void hb_gt_wvwPostMessage( UINT usWinNum, int message )
{
   SendMessage( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, WM_CHAR, message, 0 );
}


BOOL hb_gt_wvwSetWindowPos( UINT usWinNum, int left, int top )
{
   RECT wi = { 0 };

   GetWindowRect( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, &wi );
   return SetWindowPos( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, NULL, left, top, ( wi.right - wi.left ) + 1, ( wi.bottom - wi.top ) + 1, SWP_NOZORDER );
}


BOOL hb_gt_wvwSetAltF4Close( BOOL bCanClose )
{
   BOOL bWas;

   bWas = s_pWvwData->s_sApp->AltF4Close;
   s_pWvwData->s_sApp->AltF4Close = bCanClose;
   return bWas;
}


void hb_gt_wvwDoProcessMessages( UINT usWinNum )
{
   /*NOTE: despite the parameter, the following will actually process messages for all windows*/
   hb_gt_wvwProcessMessages( s_pWvwData->s_pWindows[ usWinNum ] );
}


BOOL hb_gt_wvwSetMouseMove( UINT usWinNum, BOOL bHandleEvent )
{
   BOOL bWas = s_pWvwData->s_pWindows[ usWinNum ]->MouseMove;

   s_pWvwData->s_pWindows[ usWinNum ]->MouseMove = bHandleEvent;
   return bWas;
}


BOOL hb_gt_wvwEnableShortCuts( UINT usWinNum, BOOL bEnable )
{
   BOOL bWas = s_pWvwData->s_pWindows[ usWinNum ]->EnableShortCuts;

   s_pWvwData->s_pWindows[ usWinNum ]->EnableShortCuts = bEnable;
   return bWas;
}

BOOL GetIPictDimension( IPicture * pPic, int * pWidth, int * pHeight )
{
   OLE_HANDLE oHtemp;
   BITMAP     bmTemp;

   pPic->lpVtbl->get_Handle( pPic, &oHtemp );

   GetObject( ( HBITMAP ) oHtemp, sizeof( BITMAP ), ( LPSTR ) &bmTemp );
   *pWidth  = bmTemp.bmWidth;
   *pHeight = bmTemp.bmHeight;

   return TRUE;
}

BOOL GetImageDimension( const char * image, int * pWidth, int * pHeight )
{

   HBITMAP hBitmap;
   BOOL    bResult = TRUE;

   *pWidth = 0; *pHeight = 0;
   hBitmap = FindUserBitmapHandle( image, pWidth, pHeight );

   if( ! hBitmap )
   {
      IPicture * pPic;

      *pWidth = 0; *pHeight = 0;

      pPic = hb_gt_wvwLoadPicture( image );
      if( ! pPic )
         return FALSE;

      bResult = GetIPictDimension( pPic, pWidth, pHeight );

      hb_gt_wvwDestroyPicture( pPic );
   }

   return bResult;
}

static void DrawTransparentBitmap( HDC hdc, HBITMAP hBitmap, short xStart,
                                   short yStart,
                                   int iDestWidth, int iDestHeight )
{
   BITMAP   bm;
   COLORREF cColor;
   HBITMAP  bmAndBack, bmAndObject, bmAndMem;
   HBITMAP  bmBackOld, bmObjectOld, bmMemOld;
   HDC      hdcMem, hdcBack, hdcObject, hdcTemp;
   HDC      hdcCopy;
   HBITMAP  bmStretch, bmStretchOld;
   POINT    ptSize;
   COLORREF cTransparentColor;

   hdcCopy = CreateCompatibleDC( hdc );
   SelectObject( hdcCopy, hBitmap );

   cTransparentColor = GetPixel( hdcCopy,
                                 0,
                                 0 );

   GetObject( hBitmap, sizeof( BITMAP ), ( LPSTR ) &bm );
   ptSize.x = bm.bmWidth;
   ptSize.y = bm.bmHeight;
   DPtoLP( hdcCopy, &ptSize, 1 );

   bmStretch    = CreateCompatibleBitmap( hdc, iDestWidth, iDestHeight );
   hdcTemp      = CreateCompatibleDC( hdc );
   bmStretchOld = ( HBITMAP ) SelectObject( hdcTemp, bmStretch );

   StretchBlt( hdcTemp, 0, 0,
               iDestWidth, iDestHeight,
               hdcCopy, 0, 0,
               ptSize.x, ptSize.y,
               SRCCOPY );

   hdcBack   = CreateCompatibleDC( hdc );
   hdcObject = CreateCompatibleDC( hdc );
   hdcMem    = CreateCompatibleDC( hdc );

   bmAndBack = CreateBitmap( iDestWidth, iDestHeight, 1, 1, NULL );

   bmAndObject = CreateBitmap( iDestWidth, iDestHeight, 1, 1, NULL );

   bmAndMem = CreateCompatibleBitmap( hdc, iDestWidth, iDestHeight );

   bmBackOld   = ( HBITMAP ) SelectObject( hdcBack, bmAndBack );
   bmObjectOld = ( HBITMAP ) SelectObject( hdcObject, bmAndObject );
   bmMemOld    = ( HBITMAP ) SelectObject( hdcMem, bmAndMem );

   SetMapMode( hdcTemp, GetMapMode( hdc ) );

   cColor = SetBkColor( hdcTemp, cTransparentColor );

   BitBlt( hdcObject, 0, 0, iDestWidth, iDestHeight, hdcTemp, 0, 0,
           SRCCOPY );

   SetBkColor( hdcTemp, cColor );

   BitBlt( hdcBack, 0, 0, iDestWidth, iDestHeight, hdcObject, 0, 0,
           NOTSRCCOPY );

   BitBlt( hdcMem, 0, 0, iDestWidth, iDestHeight, hdc, xStart, yStart,
           SRCCOPY );

   BitBlt( hdcMem, 0, 0, iDestWidth, iDestHeight, hdcObject, 0, 0, SRCAND );

   BitBlt( hdcTemp, 0, 0, iDestWidth, iDestHeight, hdcBack, 0, 0, SRCAND );

   BitBlt( hdcMem, 0, 0, iDestWidth, iDestHeight, hdcTemp, 0, 0, SRCPAINT );

   BitBlt( hdc, xStart, yStart, iDestWidth, iDestHeight, hdcMem, 0, 0,
           SRCCOPY );

   DeleteObject( SelectObject( hdcBack, bmBackOld ) );
   DeleteObject( SelectObject( hdcObject, bmObjectOld ) );
   DeleteObject( SelectObject( hdcMem, bmMemOld ) );
   DeleteObject( SelectObject( hdcTemp, bmStretchOld ) );

   DeleteDC( hdcMem );
   DeleteDC( hdcBack );
   DeleteDC( hdcObject );
   DeleteDC( hdcTemp );
   DeleteDC( hdcCopy );
}

/* 2006-07-24 Notes:
   (1) Transparency
   if bTransparent is .t., top-left pixel is used as the transparent color,

   (2) Caching
   WARNING this function will always CACHE the image.
   Do not use it to draw large number of images, because image handle
   is never closed.
   TODO: make it an option.
 */
BOOL hb_gt_wvwDrawImage( UINT usWinNum, int x1, int y1, int wd, int ht, const char * image, BOOL bTransparent )
{
   HBITMAP hBitmap;
   BOOL    bResult;
   int     iWidth, iHeight;
   HDC     hdc, hdcMem;

   WIN_DATA * pWindowData = s_pWvwData->s_pWindows[ usWinNum ];

   iWidth = 0;  iHeight = 0;

   hBitmap = FindUserBitmapHandle( image, &iWidth, &iHeight );
   if( ! hBitmap )
   {
      IPicture * pPic;
      OLE_HANDLE oHtemp;
      BITMAP     bmTemp;

      pPic = hb_gt_wvwLoadPicture( image );
      if( ! pPic )
         return FALSE;

      /* 2006-07-24 canNOT do it this way:
         pPic->lpVtbl->get_Width( pPic,&lWidth );
         pPic->lpVtbl->get_Height( pPic,&lHeight );
         iWidth = (int) lWidth;
         iHeight = (int) lHeight;
       */

      pPic->lpVtbl->get_Handle( pPic, &oHtemp );

      hBitmap = ( HBITMAP ) CopyImage( ( HBITMAP ) oHtemp, IMAGE_BITMAP, 0, 0,
                                       LR_COPYRETURNORG );

      hb_gt_wvwDestroyPicture( pPic );

      if( ! hBitmap )
         return FALSE;

      GetObject( hBitmap, sizeof( BITMAP ), ( LPSTR ) &bmTemp );
      iWidth  = bmTemp.bmWidth;
      iHeight = bmTemp.bmHeight;

      AddUserBitmapHandle( image, hBitmap, iWidth, iHeight );
   }

   hdc = GetDC( pWindowData->hWnd );

   if( bTransparent )
   {
      DrawTransparentBitmap( hdc,
                             hBitmap,
                             ( short ) x1,
                             ( short ) y1,
                             wd,
                             ht );
      bResult = TRUE;
   }
   else
   {
      int iOldMode;

      hdcMem = CreateCompatibleDC( hdc );

      SelectObject( hdcMem, hBitmap );

      iOldMode = SetStretchBltMode( hdc, COLORONCOLOR );

      bResult = StretchBlt(
         hdc,                          /* handle to destination DC */
         x1,                           /* x-coord of destination upper-left corner */
         y1,                           /* y-coord of destination upper-left corner */
         wd,                           /* width of destination rectangle */
         ht,                           /* height of destination rectangle */
         hdcMem,                       /* handle to source DC */
         0,                            /* x-coord of source upper-left corner */
         0,                            /* y-coord of source upper-left corner */
         iWidth,                       /* width of source rectangle */
         iHeight,                      /* height of source rectangle */
         SRCCOPY                       /* raster operation code */
         );

      SetStretchBltMode( hdc, iOldMode );

      DeleteDC( hdcMem );

   }

   ReleaseDC( pWindowData->hWnd, hdc );

   return bResult;
}


IPicture * hb_gt_wvwLoadPicture( const char * image )
{
   IStream * iStream;

   LPVOID  iPicture = NULL;
   HGLOBAL hGlobal;
   HANDLE  hFile;
   DWORD   nFileSize;
   DWORD   nReadByte;

   hFile = CreateFile( image, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
   if( hFile != INVALID_HANDLE_VALUE )
   {
      nFileSize = GetFileSize( hFile, NULL );

      if( nFileSize != INVALID_FILE_SIZE )
      {
         hGlobal = GlobalAlloc( GPTR, nFileSize );

         if( hGlobal )
         {
            if( ReadFile( hFile, hGlobal, nFileSize, &nReadByte, NULL ) )
            {
               CreateStreamOnHGlobal( hGlobal, TRUE, &iStream );

               OleLoadPicture( iStream, nFileSize, TRUE, ( REFIID ) &IID_IPicture, &iPicture );

            }
            GlobalFree( hGlobal );
         }
      }
      CloseHandle( hFile );
   }

   return ( IPicture * ) iPicture;
}


BOOL hb_gt_wvwRenderPicture( UINT usWinNum, int x1, int y1, int wd, int ht, IPicture * iPicture, BOOL bTransp )
{
   LONG       lWidth, lHeight;
   int        x, y, xe, ye;
   int        c   = x1;
   int        r   = y1;
   int        dc  = wd;
   int        dr  = ht;
   int        tor = 0;
   int        toc = 0;
   HRGN       hrgn1;
   POINT      lpp         = { 0 };
   BOOL       bResult     = FALSE;
   WIN_DATA * pWindowData = s_pWvwData->s_pWindows[ usWinNum ];

   if( iPicture )
   {
      /* if bTransp, we use different method */
      if( bTransp )
      {
         OLE_HANDLE oHtemp;
         HDC        hdc;

         iPicture->lpVtbl->get_Handle( iPicture, &oHtemp );

         if( oHtemp )
         {
            hdc = GetDC( pWindowData->hWnd );
            DrawTransparentBitmap( hdc,
                                   ( HBITMAP ) oHtemp,
                                   ( short ) x1,
                                   ( short ) y1,
                                   wd,
                                   ht );
            ReleaseDC( pWindowData->hWnd, hdc );

            bResult = TRUE;
         }
         else
            bResult = FALSE;
         return bResult;
      }
      /* endif bTransp, we use different method */

      iPicture->lpVtbl->get_Width( iPicture, &lWidth );
      iPicture->lpVtbl->get_Height( iPicture, &lHeight );

      if( dc == 0 )
         dc = ( int ) ( ( float ) dr * lWidth / lHeight );
      if( dr == 0 )
         dr = ( int ) ( ( float ) dc * lHeight / lWidth );
      if( tor == 0 )
         tor = dr;
      if( toc == 0 )
         toc = dc;
      x  = c;
      y  = r;
      xe = c + toc - 1;
      ye = r + tor - 1;

      GetViewportOrgEx( pWindowData->hdc, &lpp );

      hrgn1 = CreateRectRgn( c + lpp.x, r + lpp.y, xe + lpp.x, ye + lpp.y );
      SelectClipRgn( pWindowData->hdc, hrgn1 );

      while( x < xe )
      {
         while( y < ye )
         {
            iPicture->lpVtbl->Render( iPicture, pWindowData->hdc, x, y, dc, dr, 0,
                                      lHeight, lWidth, -lHeight, NULL );
            y += dr;
         }
         y  = r;
         x += dc;
      }

      SelectClipRgn( pWindowData->hdc, NULL );
      DeleteObject( hrgn1 );

      bResult = TRUE;
   }

   return bResult;
}


WIN_DATA * hb_gt_wvwGetGlobalData( UINT usWinNum )
{
   return s_pWvwData->s_pWindows[ usWinNum ];
}


COLORREF hb_gt_wvwGetColorData( int iIndex )
{
   return _COLORS[ iIndex ];
}


BOOL hb_gt_wvwSetColorData( int iIndex, COLORREF ulCr )
{
   BOOL bResult = FALSE;

   if( iIndex >= 0 && iIndex < 16 )
   {
      _COLORS[ iIndex ] = ulCr;
      bResult = TRUE;
   }
   return bResult;
}


/*
   difference with gtwvt's:
   here we have an option bTight.
   if it is true, only one pixel lines used (outer lines are not drawn)

   TODO: combine it with aOffset like DrawImage ?
 */

void hb_gt_wvwDrawBoxRaised( UINT usWinNum, int iTop, int iLeft, int iBottom, int iRight, BOOL bTight ) /* <-- none in gtwvt */
{
   WIN_DATA * pWindowData = s_pWvwData->s_pWindows[ usWinNum ];

   if( ! bTight )
      SelectObject( pWindowData->hdc, s_pWvwData->s_sApp->penWhiteDim );
   else
      SelectObject( pWindowData->hdc, s_pWvwData->s_sApp->penWhite );

   MoveToEx( pWindowData->hdc, iLeft, iTop, NULL );        /*  Top Inner  */
   LineTo( pWindowData->hdc, iRight, iTop );

   MoveToEx( pWindowData->hdc, iLeft, iTop, NULL );        /*  Left Inner */
   LineTo( pWindowData->hdc, iLeft, iBottom );

   if( ! bTight )
   {
      SelectObject( pWindowData->hdc, s_pWvwData->s_sApp->penWhite );

      MoveToEx( pWindowData->hdc, iLeft - 1, iTop - 1, NULL ); /*  Top Outer  */
      LineTo( pWindowData->hdc, iRight + 1, iTop - 1 );

      MoveToEx( pWindowData->hdc, iLeft - 1, iTop - 1, NULL ); /*  Left Outer */
      LineTo( pWindowData->hdc, iLeft - 1, iBottom + 1 );
   }

   if( ! bTight )
      SelectObject( pWindowData->hdc, s_pWvwData->s_sApp->penDarkGray );
   else
      SelectObject( pWindowData->hdc, s_pWvwData->s_sApp->penBlack );

   MoveToEx( pWindowData->hdc, iLeft, iBottom, NULL );     /*  Bottom Inner  */
   LineTo( pWindowData->hdc, iRight, iBottom );

   MoveToEx( pWindowData->hdc, iRight, iBottom, NULL );    /*  Right Inner   */
   LineTo( pWindowData->hdc, iRight, iTop );

   if( ! bTight )
   {
      SelectObject( pWindowData->hdc, s_pWvwData->s_sApp->penBlack );

      MoveToEx( pWindowData->hdc, iLeft - 1, iBottom + 1, NULL ); /*  Bottom Outer */
      LineTo( pWindowData->hdc, iRight + 1 + 1, iBottom + 1 );

      MoveToEx( pWindowData->hdc, iRight + 1, iTop - 1, NULL ); /*  Right Outer  */
      LineTo( pWindowData->hdc, iRight + 1, iBottom + 1 );
   }

}


/*
   difference with gtwvt's:
   here we have an option bTight.
   if it is true, only one pixel lines used (outer lines are not drawn)

   TODO: combine it with aOffset like DrawImage ?
 */

void hb_gt_wvwDrawBoxRecessed( UINT usWinNum, int iTop, int iLeft, int iBottom, int iRight, BOOL bTight )
{
   WIN_DATA * pWindowData = s_pWvwData->s_pWindows[ usWinNum ];

   if( ! bTight )
      SelectObject( pWindowData->hdc, s_pWvwData->s_sApp->penWhiteDim );
   else
      SelectObject( pWindowData->hdc, s_pWvwData->s_sApp->penWhite );

   MoveToEx( pWindowData->hdc, iRight, iTop, NULL );            /* Right Inner  */
   LineTo( pWindowData->hdc, iRight, iBottom );

   MoveToEx( pWindowData->hdc, iLeft, iBottom, NULL );          /* Bottom Inner */
   LineTo( pWindowData->hdc, iRight, iBottom );

   if( ! bTight )
   {
      SelectObject( pWindowData->hdc, s_pWvwData->s_sApp->penWhite );

      MoveToEx( pWindowData->hdc, iRight + 1, iTop - 1, NULL );   /* Right Outer  */
      LineTo( pWindowData->hdc, iRight + 1, iBottom + 1 );

      MoveToEx( pWindowData->hdc, iLeft - 1, iBottom + 1, NULL ); /* Bottom Outer */
      LineTo( pWindowData->hdc, iRight + 2, iBottom + 1 );

   }

   SelectObject( pWindowData->hdc, s_pWvwData->s_sApp->penGray );

   MoveToEx( pWindowData->hdc, iLeft, iTop, NULL );             /* Left Inner */
   LineTo( pWindowData->hdc, iLeft, iBottom );

   MoveToEx( pWindowData->hdc, iLeft, iTop, NULL );             /* Top Inner  */
   LineTo( pWindowData->hdc, iRight, iTop );

   if( ! bTight )
   {
      SelectObject( pWindowData->hdc, s_pWvwData->s_sApp->penDarkGray );

      MoveToEx( pWindowData->hdc, iLeft - 1, iTop - 1, NULL );    /* Left Outer */
      LineTo( pWindowData->hdc, iLeft - 1, iBottom + 1 );

      MoveToEx( pWindowData->hdc, iLeft - 1, iTop - 1, NULL );    /* Top Outer  */
      LineTo( pWindowData->hdc, iRight + 1, iTop - 1 );
   }

}


void hb_gt_wvwDrawOutline( UINT usWinNum, int iTop, int iLeft, int iBottom, int iRight )
{
   WIN_DATA * pWindowData = s_pWvwData->s_pWindows[ usWinNum ];

   MoveToEx( pWindowData->hdc, iLeft, iTop, NULL );        /*  Top     */
   LineTo( pWindowData->hdc, iRight, iTop );

   MoveToEx( pWindowData->hdc, iLeft, iTop, NULL );        /*  Left    */
   LineTo( pWindowData->hdc, iLeft, iBottom );

   MoveToEx( pWindowData->hdc, iLeft, iBottom, NULL );     /*  Bottom   */
   LineTo( pWindowData->hdc, iRight, iBottom );

   MoveToEx( pWindowData->hdc, iRight, iTop, NULL );       /*  Right    */
   LineTo( pWindowData->hdc, iRight, iBottom + 1 );

}
/* BOOL hb_gt_wvw_KeyEvent( message, wParam, lParam  ); */

/*NOTE: are these workable in MULTI_GT ? */
/* static void gtFnInit( PHB_GT_FUNCS gt_funcs ) */
static BOOL hb_gt_FuncInit( PHB_GT_FUNCS pFuncTable )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_gtFnInit( %p )", pFuncTable ) );

   pFuncTable->Init   = hb_gt_wvw_Init;
   pFuncTable->Exit   = hb_gt_wvw_Exit;
   pFuncTable->MaxCol = hb_gt_wvw_MaxCol;
   pFuncTable->MaxRow = hb_gt_wvw_MaxRow;

   pFuncTable->SetPos         = hb_gt_wvw_SetPos;
   pFuncTable->IsColor        = hb_gt_wvw_IsColor;
   pFuncTable->GetCursorStyle = hb_gt_wvw_GetCursorStyle;
   pFuncTable->SetCursorStyle = hb_gt_wvw_SetCursorStyle;
   pFuncTable->DispBegin      = hb_gt_wvw_DispBegin;
   pFuncTable->DispEnd        = hb_gt_wvw_DispEnd;
   pFuncTable->DispCount      = hb_gt_wvw_DispCount;
   pFuncTable->Replicate      = hb_gt_wvw_Replicate;
   pFuncTable->WriteAt        = hb_gt_wvw_WriteAt;
   pFuncTable->PutText        = hb_gt_wvw_PutText;
   pFuncTable->SetAttribute   = hb_gt_wvw_SetAttribute;
/*  pFuncTable->Scroll                = hb_gt_wvw_Scroll; */
   pFuncTable->SetMode   = hb_gt_wvw_SetMode;
   pFuncTable->GetBlink  = hb_gt_wvw_GetBlink;
   pFuncTable->SetBlink  = hb_gt_wvw_SetBlink;
   pFuncTable->Version   = hb_gt_wvw_Version;
   pFuncTable->Box       = hb_gt_wvw_Box;
   pFuncTable->HorizLine = hb_gt_wvw_HorizLine;
   pFuncTable->VertLine  = hb_gt_wvw_VertLine;
   pFuncTable->OutStd    = hb_gt_wvw_OutStd;
   pFuncTable->OutErr    = hb_gt_wvw_OutErr;
   pFuncTable->Tone      = hb_gt_wvw_Tone;
   pFuncTable->ReadKey   = hb_gt_wvw_ReadKey;
   pFuncTable->Info      = hb_gt_wvw_Info;

   pFuncTable->GetChar    = hb_gt_wvw_GetChar;
   pFuncTable->PutChar    = hb_gt_wvw_PutChar;
   pFuncTable->CheckPos   = hb_gt_wvw_CheckPos;
   pFuncTable->GetSize    = hb_gt_wvw_GetSize;
   pFuncTable->Save       = hb_gt_wvw_Save;
   pFuncTable->Rest       = hb_gt_wvw_Rest;
   pFuncTable->ExposeArea = hb_gt_wvw_ExposeArea;


   /* Graphics API */
   pFuncTable->GfxPrimitive = hb_gt_wvw_gfxPrimitive;

   pFuncTable->MouseInit        = hb_gt_wvw_mouse_Init;
   pFuncTable->MouseExit        = hb_gt_wvw_mouse_Exit;
   pFuncTable->MouseIsPresent   = hb_gt_wvw_mouse_IsPresent;
   pFuncTable->MouseCol         = hb_gt_wvw_mouse_Col;
   pFuncTable->MouseRow         = hb_gt_wvw_mouse_Row;
   pFuncTable->MouseSetPos      = hb_gt_wvw_mouse_SetPos;
   pFuncTable->MouseGetPos      = hb_gt_wvw_mouse_GetPos;
   pFuncTable->MouseCountButton = hb_gt_wvw_mouse_CountButton;
   pFuncTable->MouseButtonState = hb_gt_wvw_mouse_ButtonState;

   return TRUE;
}

#include "hbgtreg.h"

/* GetSet Functions for static Variable */

BOOL hb_gt_wvw_GetMainCoordMode( void )
{
   return s_pWvwData->s_bMainCoordMode;
}

UINT hb_gt_wvw_GetNumWindows( void )
{
   return s_pWvwData->s_usNumWindows;
}

UINT hb_gt_wvw_GetCurWindow( void )
{
   return s_pWvwData->s_usCurWindow;
}

WIN_DATA * hb_gt_wvw_GetWindowsData( UINT iWin )
{
   return ( WIN_DATA * ) s_pWvwData->s_pWindows[ iWin ];
}

char * hb_gt_wvw_GetAppName( void )
{
   return s_pWvwData->szAppName;
}

APP_DATA * hb_gt_wvwGetAppData( void )
{
   return s_pWvwData->s_sApp;
}

WVW_DATA * hb_getWvwData( void )
{
   return s_pWvwData;
}


/*                                                                   */
/*               Window Related xHarbour callable functions          */
/*               Budyanto Dj. <budyanto@centrin.net.id>              */
/*                                                                   */


/* 2004-07-13 this function was named WVW_lOpenWindow()
 *  now it is wvw_nOpenWindow()
 *  it now returns numeric

 *  wvw_nOpenWindow(cWinName, row1, col1, row2, col2, ;
 *                nStyle, nParentWin)
 * rowx and colx are relative to MAIN WINDOW (not current window!)
 * rowx and colx are used for:
 * (1) positioning window to its initial position,
 * (2) determining the size of the window (new MaxRow() and MaxCol())
 * (3) saved into RowOfs and ColOfs for MainCoord mode
 *
 * nStyle is window style (eg. WS_OVERLAPPEDWINDOW, etc.)
 *       default is: WS_CAPTION|WS_SYSMENU |WS_CLIPCHILDREN
 *       WARNING: you must know what you're doing if you supplied this param
 *       NOTES: if you will use controls such as PUSHBUTTON,
 *              you MUST include WS_CLIPCHILDREN.
 *
 * nParentWin is parent window of the new on we're about to open.
 *       default is: current window (in Standard Mode)
 *                   last window (in MainCoord Mode)
 *       If you want the new window to not have parent,
 *       pass -1 as nParentWin.
 *
 *
 * returns window number if successful
 * returns 0 if failed
 */

HB_FUNC( WVW_NOPENWINDOW )
{
   LPCTSTR lpszWinName;
   void *  hWinName;

   int        iLen;
   WIN_DATA * pParentWindow;

   WIN_DATA * pWindowData;
   int        irow1, icol1, irow2, icol2;
   RECT       wi = { 0 }, rcWorkArea = { 0 };
   UINT       usWinNum;

   DWORD     dwStyle    = ( HB_ISNIL( 6 ) ? ( ( DWORD ) ( WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN ) ) : ( ( DWORD ) hb_parnl( 6 ) ) );
   INT       iParentWin = ( HB_ISNIL( 7 ) ? ( s_pWvwData->s_bMainCoordMode ? s_pWvwData->s_usNumWindows - 1 : s_pWvwData->s_usCurWindow ) : ( ( INT ) hb_parni( 7 ) ) );
   PHB_FNAME pFileName;

   if( s_pWvwData->s_usNumWindows == 0 )
   {
      hb_retni( 0 );
      return;
   }

   if( s_pWvwData->s_usNumWindows == WVW_MAXWINDOWS )
   {
      MessageBox( NULL, TEXT( "Too many Windows to open" ),
                  TEXT( "Error" ), MB_ICONERROR );
      hb_retni( 0 );
      return;
   }

   if( iParentWin > ( INT ) s_pWvwData->s_usNumWindows - 1 )
   {
      MessageBox( NULL, TEXT( "Invalid Parent Window" ),
                  TEXT( "Error" ), MB_ICONERROR );
      hb_retni( 0 );
      return;
   }

   if( iParentWin < 0 )
   {
      if( ! s_pWvwData->s_bMainCoordMode )
         pParentWindow = s_pWvwData->s_pWindows[ s_pWvwData->s_usCurWindow ];
      else
         pParentWindow = s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ];
   }
   else
      pParentWindow = s_pWvwData->s_pWindows[ ( USHORT ) iParentWin ];

   if( HB_ISCHAR( 1 ) )
   {
      iLen = hb_parclen( 1 );
      if( iLen > WVW_MAXWINNAMELENGTH - 1 )
      {
         MessageBox( NULL, TEXT( "Windows name too long" ),
                     TEXT( "Error" ), MB_ICONERROR );
         hb_retni( 0 );
         return;
      }
      pFileName   = NULL;
      lpszWinName = HB_PARSTR( 1, &hWinName, NULL );
   }
   else
   {
      PHB_ITEM pItem = hb_itemPutCPtr( NULL, hb_cmdargBaseProgName() );

      lpszWinName = HB_ITEMGETSTR( pItem, &hWinName, NULL );
      hb_itemRelease( pItem );
   }

   irow1 = HB_ISNIL( 2 ) ? 0 : hb_parni( 2 );
   icol1 = HB_ISNIL( 3 ) ? 0 : hb_parni( 3 );
   irow2 = HB_ISNIL( 4 ) ? pParentWindow->ROWS - 1 :  hb_parni( 4 );
   icol2 = HB_ISNIL( 5 ) ? pParentWindow->COLS - 1 :  hb_parni( 5 );

   usWinNum = hb_gt_wvwOpenWindow( lpszWinName, irow1, icol1, irow2, icol2,
                                   dwStyle, iParentWin );

   hb_strfree( hWinName );

   if( usWinNum == 0 )
   {
      hb_retni( 0 );

      if( pFileName )
         hb_xfree( pFileName );

      return;
   }

   pWindowData = s_pWvwData->s_pWindows[ usWinNum ];

   GetWindowRect( pWindowData->hWnd, &wi );
   SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWorkArea, 0 );
   if( wi.right < rcWorkArea.left || wi.left > rcWorkArea.right ||
       wi.top > rcWorkArea.bottom || wi.bottom < rcWorkArea.top )
   {
      hb_gt_wvwSetCentreWindow( 0, TRUE, TRUE );
      hb_gt_wvwSetCentreWindow( usWinNum, s_pWvwData->s_bDefCentreWindow, TRUE );
   }

   if( s_pWvwData->s_bMainCoordMode )
      s_pWvwData->s_usCurWindow = usWinNum;

   hb_gtSetMode( pWindowData->ROWS, pWindowData->COLS );


   if( s_pWvwData->s_bMainCoordMode )
      hb_gt_wvwSetCurWindow( 0 );

   SendMessage( pWindowData->hWnd, WM_SETFOCUS, 0, 0 );

   if( pFileName )
      hb_xfree( pFileName );

   hb_retni( usWinNum );

}

HB_FUNC( WVW_GET_HND_WINDOW )
{
   UINT       usWinNum    = WVW_WHICH_WINDOW;
   WIN_DATA * pWindowData = s_pWvwData->s_pWindows[ usWinNum ];

   HB_RETHANDLE( pWindowData->hWnd );
}

HB_FUNC( WVW_MOVE_READY )
{
   BOOL bIsReady;

   bIsReady = hb_wvw_Move_Ready( 0 );

   if( HB_ISLOG( 1 ) )
      bIsReady = hb_wvw_Move_Ready( hb_parl( 1 ) );
   hb_retl( bIsReady );
}

HB_FUNC( WVW_SIZE_READY )
{
   BOOL bIsReady;

   bIsReady = hb_wvw_Size_Ready( 0 );

   if( HB_ISLOG( 1 ) )
      bIsReady = hb_wvw_Size_Ready( hb_parl( 1 ) );
   hb_retl( bIsReady );
}


/*wvw_lCloseWindow()
 * closes the last/topmost window
 * returns .t. if successful
 */
HB_FUNC( WVW_LCLOSEWINDOW )
{
   WIN_DATA * pWindowData;

   if( s_pWvwData->s_usNumWindows <= 1 )
   {

      MessageBox( NULL, TEXT( "No more window to close" ),
                  "Error", MB_ICONERROR );
      hb_retl( FALSE );
      return;
   }

   hb_gt_wvwCloseWindow();

   if( ! s_pWvwData->s_bMainCoordMode )
   {

      s_pWvwData->s_bQuickSetMode = TRUE;

      hb_gtSetMode( s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->ROWS, s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ]->COLS );

      s_pWvwData->s_bQuickSetMode = FALSE;
   }
   else
      hb_gt_wvwSetCurWindow( 0 );

   pWindowData = s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ];

   SendMessage( pWindowData->hWnd, WM_SETFOCUS, 0, 0 );

   hb_retl( TRUE );
}

/*wvw_nNumWindows()
 * returns number of windows opened (including main window)
 */
HB_FUNC( WVW_NNUMWINDOWS )
{
   hb_retni( ( int ) s_pWvwData->s_usNumWindows );
}

/*wvw_XReposWindow(lAnchored)
 * reposition all windows to their initial position
 *
 * if lAnchored == .t. (default)
 *    all subwindows are positioned according to their respective (row1,col1) coordinate
 * else
 *    all subwindows are positioned according to whatever their "CenterWindow" setting
 *    (see also wvw_CenterWindow())
 */
HB_FUNC( WVW_XREPOSWINDOW )
{
   UINT i;
   BOOL bAnchored = ( HB_ISLOG( 1 ) ? hb_parl( 1 ) : TRUE );

   /* centerize Main Window, only if not maximized */

   {
      hb_gt_wvwSetCentreWindow( 0, TRUE, TRUE );
   }

   /* reposition all subwindows */
   for( i = 1; i < s_pWvwData->s_usNumWindows; i++ )
   {

      if( bAnchored )
         hb_gt_wvwSetCentreWindow( i, FALSE, TRUE );
      else
         hb_gt_wvwSetCentreWindow( i, s_pWvwData->s_pWindows[ i ]->CentreWindow, TRUE );
   }
}

/* wvw_nSetCurWindow( nWinNum )   (0==MAIN)
 *  assigns nWinNum as the new current window (s_pWvwData->s_usCurWindow)
 *  returns old current window
 *  example: saved := wvw_nSetCurWindow(0)
 *         ? "This will be displayed in Main Window"
 *         wvw_nSetCurWindow(saved)
 * notes: makes sense only if !s_pWvwData->s_bMainCoordMode
 */
HB_FUNC( WVW_NSETCURWINDOW )
{
   INT sWinNum;

   if( HB_ISNIL( 1 ) )
      hb_retni( ( int ) ( s_pWvwData->s_usCurWindow ) );
   else
   {
      sWinNum = hb_parni( 1 );
      if( sWinNum >= 0 && sWinNum < ( INT ) s_pWvwData->s_usNumWindows )
         hb_retni( ( int ) ( hb_gt_wvwSetCurWindow( sWinNum ) ) );
      else
         hb_errRT_TERM( EG_BOUND, 10001, "Window Number out of range", "WVW_nSetCurWindow()", 0, 0 );

   }
}

/*wvw_nRowOfs( [nWinNum] )
 * returns row offset of window #nWinNum (0==MAIN), relative to Main Window
 * nWinNum defaults to current window
 */
HB_FUNC( WVW_NROWOFS )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   hb_retni( ( int ) hb_gt_wvwRowOfs( usWinNum ) );
}

/*wvw_nColOfs( [nWinNum] )
 * returns col offset of window #nWinNum (0==MAIN), relative to Main Window
 * nWinNum defaults to topmost window
 */
HB_FUNC( WVW_NCOLOFS )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   hb_retni( ( int ) hb_gt_wvwColOfs( usWinNum ) );
}

/*
 * wvw_MaxMaxRow( [nWinNum] )
 * returns maximum possible MaxRow() in current screen setting for font used by window nWinNum
 *
 */
HB_FUNC( WVW_MAXMAXROW )
{
   UINT usWinNum = WVW_WHICH_WINDOW;
   int  maxrows;

   /* rows and cols passed are dummy ones */
   hb_gt_wvwValidWindowSize( s_pWvwData->s_pWindows[ usWinNum ], 10, 10, s_pWvwData->s_pWindows[ usWinNum ]->hFont, s_pWvwData->s_pWindows[ usWinNum ]->fontWidth,
                             &maxrows, NULL );
   hb_retni( maxrows - 1 );
}

/*
 * wvw_MaxMaxCol( [nWinNum] )
 * returns maximum possible MaxCol() in current screen setting for font used by window nWinNum
 *
 */
HB_FUNC( WVW_MAXMAXCOL )
{
   UINT usWinNum = WVW_WHICH_WINDOW;
   int  maxcols;

   /* rows and cols passed are dummy ones */
   hb_gt_wvwValidWindowSize( s_pWvwData->s_pWindows[ usWinNum ], 10, 10, s_pWvwData->s_pWindows[ usWinNum ]->hFont, s_pWvwData->s_pWindows[ usWinNum ]->fontWidth,
                             NULL, &maxcols );
   hb_retni( maxcols - 1 );
}

/*
 * wvw_UnreachedBr( [nWinNum], [nBottomPixels], [nRightPixels] )
 * get unreached pixels
 * below MaxRow() to nBottomPixels
 * and on the right of maxcols() to nRightPixels
 *
 */
HB_FUNC( WVW_UNREACHEDBR )
{
   UINT usWinNum = WVW_WHICH_WINDOW;
   int  cols, rows;

   hb_gt_wvwUnreachedXY( s_pWvwData->s_pWindows[ usWinNum ], &cols, &rows );
   if( HB_ISBYREF( 2 ) )
      hb_storni( rows, 2 );
   if( HB_ISBYREF( 3 ) )
      hb_storni( cols, 3 );
}

/*wvw_SetMainCoord( [lMainCoord] )
 * returns old setting of s_pWvwData->s_bMainCoordMode,
 * then assigns s_pWvwData->s_bMainCoordMode := lMainCoord (if supplied)
 */
HB_FUNC( WVW_SETMAINCOORD )
{
   BOOL bOldMainCoordMode = s_pWvwData->s_bMainCoordMode;

   if( ! HB_ISNIL( 1 ) )
   {
      s_pWvwData->s_bMainCoordMode = hb_parl( 1 );

      if( ! s_pWvwData->s_bMainCoordMode )
         hb_gt_wvwSetCurWindow( s_pWvwData->s_usNumWindows - 1 );
      else
         hb_gt_wvwSetCurWindow( 0 );
   }

   hb_retl( bOldMainCoordMode );
}

/* wvw_AddRows( [nWinNum], nRows)
 * add nRows rows to window nWinNum (nRows may be < 0)
 * returns .t. if successful
 *
 * NOTES: newly added rows (for nRows>0) will be colored with
 *        column 0 of original last row
 * WARNING: no checking if window size will become larger than desktop area
 *          (except if in MainCoord Mode, because it is implied from
 *           restriction of resulted MaxRow())
 */

/* WARNING! this function relies on the fact that char/attr buffers are static!
 */
HB_FUNC( WVW_ADDROWS )
{
   UINT       usWinNum    = WVW_WHICH_WINDOW;
   WIN_DATA * pWindowData = s_pWvwData->s_pWindows[ usWinNum ];
   int        iRows       = HB_ISNIL( 2 ) ? 0 : hb_parni( 2 );
   USHORT     height, width;
   USHORT     diffheight, diffwidth;
   USHORT     usNumChars;

   RECT wi = { 0 }, ci = { 0 };

   if( iRows == 0 )
   {
      hb_retl( TRUE );
      return;
   }

   if( /* (iRows < 0) || */
      ( s_pWvwData->s_bMainCoordMode && ( pWindowData->usRowOfs + pWindowData->ROWS + iRows > s_pWvwData->s_pWindows[ 0 ]->ROWS ) ) ||
      ( pWindowData->ROWS + iRows > WVW_MAX_ROWS ) ||
      ( pWindowData->ROWS + iRows < 1 )
      )
   {
      hb_retl( FALSE );
      return;
   }

   usNumChars = ( USHORT ) iRows * pWindowData->COLS;

   if( iRows > 0 )
   {
      /* initialize chars and attributes */
      USHORT usBufLastRow = hb_gt_wvwGetIndexForTextBuffer( pWindowData, 0, pWindowData->ROWS - 1 );
      USHORT usBufStart   = hb_gt_wvwGetIndexForTextBuffer( pWindowData, 0, pWindowData->ROWS );

      memset( &( pWindowData->byBuffer[ usBufStart ] ), ' ', usNumChars );

      memset( &( pWindowData->byColors[ usBufStart ] ), ( char ) pWindowData->byColors[ usBufLastRow ], usNumChars );
   }

   /* update vars */
   pWindowData->ROWS       += ( USHORT ) iRows;
   pWindowData->BUFFERSIZE += usNumChars * sizeof( char );

   if( ! s_pWvwData->s_bMainCoordMode )
   {
      UINT usCurWindow = s_pWvwData->s_usCurWindow;
      s_pWvwData->s_usCurWindow = usWinNum;

      s_pWvwData->s_bQuickSetMode = TRUE;

      hb_gtSetMode( pWindowData->ROWS, pWindowData->COLS );

      s_pWvwData->s_bQuickSetMode = FALSE;

      s_pWvwData->s_usCurWindow = usCurWindow;
   }

   /* resize the window to get the specified number of rows and columns
    */
   height = hb_gt_wvwCalcPixelHeight( pWindowData );
   width  = hb_gt_wvwCalcPixelWidth( pWindowData );

   GetWindowRect( pWindowData->hWnd, &wi );
   GetClientRect( pWindowData->hWnd, &ci );
   diffheight = ( USHORT ) ( ( wi.bottom - wi.top ) - ( ci.bottom - ci.top ) );
   diffwidth  = ( USHORT ) ( ( wi.right - wi.left ) - ( ci.right - ci.left ) );

   height += diffheight;
   width  += diffwidth;

   SetWindowPos( pWindowData->hWnd, NULL, wi.left, wi.top, width, height, SWP_NOZORDER );

   if( pWindowData->hStatusBar != NULL )
      SetWindowPos( pWindowData->hStatusBar, NULL, wi.left, wi.bottom - pWindowData->usSBHeight, width, pWindowData->usSBHeight, SWP_NOZORDER );


#if 0
   /**** THESE are not required, because we simply enlarged/shrinked the window downward
         NOTICE however that some control may not be fully visible */

   if( pWindowData->hToolBar != NULL )
      SetWindowPos( pWindowData->hToolBar, NULL, wi.left, wi.top - pWindowData->usTBHeight, width, pWindowData->usTBHeight, SWP_NOZORDER );


   if( pWindowData->pcdCtrlList != NULL )
      ReposControls( pWindowData->byWinId, 0 );

   if( pWindowData->byWinId == s_pWvwData->s_usNumWindows - 1 )
      hb_gt_wvwSetCaretPos( pWindowData );

#endif

   if( iRows > 0 )
   {
      /* invalidate rect of the newly added rows */
      pWindowData->InvalidateWindow = TRUE;
      hb_gt_wvwSetInvalidRect( pWindowData,
                               ( USHORT ) 0, ( USHORT ) pWindowData->ROWS - ( USHORT ) iRows,
                               ( USHORT ) pWindowData->COLS - 1, ( USHORT ) pWindowData->ROWS - 1 );
   }

   hb_retl( TRUE );

}

/*
 * wvw_NoClose( [nWinNum] )
 * disable CLOSE 'X' button of a window
 *
 * no return value
 */
HB_FUNC( WVW_NOCLOSE )
{
   UINT  usWinNum = WVW_WHICH_WINDOW;
   HMENU hMenu    = GetSystemMenu( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, FALSE );

   if( hMenu )
   {
      DeleteMenu( hMenu, SC_CLOSE, MF_BYCOMMAND );
      DrawMenuBar( s_pWvwData->s_pWindows[ usWinNum ]->hWnd );
   }
}

/*
 *  wvw_SetWinStyle( [nWinNum], [nStyle] )
 *  Get/Set window style
 *  NOTES: if window has controls (eg. pushbutton, scrollbar)
 *       you should include WS_CLIPCHILDREN in nStyle
 *
 * SIDE EFFECT:
 *       if window is hidden, applying nStyle here will cause it to show
 *
 * return Window Style prior to applying the new style
 */

HB_FUNC( WVW_SETWINSTYLE )
{
   UINT     usWinNum = WVW_WHICH_WINDOW;
   LONG_PTR lpStyle;

   if( HB_ISNUM( 2 ) )
   {
      lpStyle = SetWindowLongPtr( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, GWL_STYLE, ( LONG_PTR ) hb_parnl( 2 ) );
      SetWindowPos( s_pWvwData->s_pWindows[ usWinNum ]->hWnd,
                    NULL,
                    0, 0, 0, 0,
                    SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED );
      ShowWindow( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, SW_SHOWNORMAL );
   }
   else
      lpStyle = GetWindowLongPtr( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, GWL_STYLE );
   hb_retnl( lpStyle );
}

/*
 * wvw_EnableMaximize( [nWinNum], [lEnable] )
 * Get/Set maximize button
 *
 * returns maximize box state prior to applying the new style
 *
 * NOTE: in order to enable MAXIMIZE button, app should have WVW_SIZE() callback function
 */

HB_FUNC( WVW_ENABLEMAXIMIZE )
{
   UINT     usWinNum = WVW_WHICH_WINDOW;
   LONG_PTR lpStyle;
   BOOL     bState;

   lpStyle = GetWindowLongPtr( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, GWL_STYLE );
   bState  = ( BOOL ) ( lpStyle & ( LONG_PTR ) WS_MAXIMIZEBOX );
   hb_retl( bState );

   if( HB_ISLOG( 2 ) )
   {
      if( hb_parl( 2 ) )
      {
         if( bState )
            return;          /* no need */
         lpStyle |= ( LONG_PTR ) WS_MAXIMIZEBOX;
      }
      else
      {
         if( ! bState )
            return;           /* no need */
         lpStyle &= ~( LONG_PTR ) WS_MAXIMIZEBOX;
      }

      SetWindowLongPtr( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, GWL_STYLE, lpStyle );
      SetWindowPos( s_pWvwData->s_pWindows[ usWinNum ]->hWnd,
                    NULL,
                    0, 0, 0, 0,
                    SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED );
      ShowWindow( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, SW_SHOW );
   }
}


/*                                                                   */
/*               GTWVW parameter setting from .prg                   */
/*               Budyanto Dj. <budyanto@centrin.net.id>              */
/*                                                                   */


/*wvw_SetPaintRefresh( [nPaintRefresh] )
 * returns old setting of s_pWvwData->s_uiPaintRefresh (millisec between calls to WVW_PAINT)
 * then assigns s_pWvwData->s_uiPaintRefresh:= nPaintRefresh (if supplied)
 * NOTES: nPaintRefresh must be >= 50
 *       or nPaintRefresh == 0, causing Repaint to execute immediately, as GTWVT
 */
HB_FUNC( WVW_SETPAINTREFRESH )
{
   UINT uiOldPaintRefresh = s_pWvwData->s_uiPaintRefresh;

   if( HB_ISNUM( 1 ) && ( hb_parni( 1 ) >= 50 || hb_parni( 1 ) == 0 ) )
   {
      s_pWvwData->s_uiPaintRefresh = hb_parni( 1 );

      if( s_pWvwData->s_sApp->pSymWVW_PAINT )
      {
         UINT i;
         for( i = 0; i < s_pWvwData->s_usNumWindows; i++ )
         {

            if( s_pWvwData->s_uiPaintRefresh > 0 )
               SetTimer( s_pWvwData->s_pWindows[ i ]->hWnd, WVW_ID_SYSTEM_TIMER, ( UINT ) s_pWvwData->s_uiPaintRefresh, NULL );
            else
               KillTimer( s_pWvwData->s_pWindows[ i ]->hWnd, WVW_ID_SYSTEM_TIMER );
         }
      }
   }

   hb_retni( uiOldPaintRefresh );
}

/*wvw_SetVertCaret( [lOn] )
 * if lOn is supplied:
 * lOn == .t.: turn caret into vertical caret
 * lOn == .f.: turn caret into horizontal caret
 * return old setting of s_pWvwData->s_bVertCaret
 */
/*TODO: do you want to make it window selective?*/
HB_FUNC( WVW_SETVERTCARET )
{
   BOOL       bOldVertCaret = s_pWvwData->s_bVertCaret;
   WIN_DATA * pWindowData   = s_pWvwData->s_pWindows[ s_pWvwData->s_usNumWindows - 1 ];

   if( ! HB_ISNIL( 1 ) )
   {
      s_pWvwData->s_bVertCaret = hb_parl( 1 );

      /*TODO: we should recalculate width and height of caret! */
      hb_gt_wvwKillCaret( pWindowData );
      hb_gt_wvwCreateCaret( pWindowData );

   }

   hb_retl( bOldVertCaret );
}

/*wvw_SetDefCentreWindow( [lCentre] )
 * returns old setting of s_pWvwData->s_bDefCentreWindow (default CentreWindow setting for newly opened subwindow)
 * then assigns s_pWvwData->s_bDefCentreWindow := lCentre (if supplied)
 * NOTES:
 * - lCentre will be the default CentreWindow for all subwindow opens
 */
HB_FUNC( WVW_SETDEFCENTREWINDOW )
{
   BOOL bOldDef = s_pWvwData->s_bDefCentreWindow;

   if( ! HB_ISNIL( 1 ) && HB_ISLOG( 1 ) )
      s_pWvwData->s_bDefCentreWindow = hb_parl( 1 );

   hb_retl( bOldDef );
}

/*wvw_SetDefHCentreWindow( [lCentre] )
 * returns old setting of s_pWvwData->s_bDefHCentreWindow (default horizontal CentreWindow setting for newly opened subwindow)
 * then assigns s_pWvwData->s_bDefHCentreWindow := lCentre (if supplied)
 * NOTES:
 * - lCentre will be the default CentreWindow for all subwindow opens
 */
HB_FUNC( WVW_SETDEFHCENTREWINDOW )
{
   BOOL bOldDef = s_pWvwData->s_bDefHCentreWindow;

   if( ! HB_ISNIL( 1 ) && HB_ISLOG( 1 ) )
      s_pWvwData->s_bDefHCentreWindow = hb_parl( 1 );

   hb_retl( bOldDef );
}

/*wvw_SetDefVCentreWindow( [lCentre] )
 * returns old setting of s_pWvwData->s_bDefVCentreWindow (default horizontal CentreWindow setting for newly opened subwindow)
 * then assigns s_pWvwData->s_bDefVCentreWindow := lCentre (if supplied)
 * NOTES:
 * - lCentre will be the default CentreWindow for all subwindow opens
 */
HB_FUNC( WVW_SETDEFVCENTREWINDOW )
{
   BOOL bOldDef = s_pWvwData->s_bDefVCentreWindow;

   if( ! HB_ISNIL( 1 ) && HB_ISLOG( 1 ) )
      s_pWvwData->s_bDefVCentreWindow = hb_parl( 1 );

   hb_retl( bOldDef );
}

/*wvw_SetDefLineSpacing( [nLineSpacing] )
 * returns old setting of s_pWvwData->s_byDefLineSpacing (default linespacing between lines)
 * then assigns s_pWvwData->s_byDefLineSpacing:= nLineSpacing (if supplied)
 * NOTES:
 * - nLineSpacing will be the default line spacing for all window opens
 * - nLineSpacing must be even, positive number <= 40
 *   otherwise it will be ignored
 * - to check line spacing being used by a window, use wvw_SetLineSpacing()
 */
HB_FUNC( WVW_SETDEFLINESPACING )
{
   int byOldLineSpacing = s_pWvwData->s_byDefLineSpacing;

   if( ! HB_ISNIL( 1 ) && HB_ISNUM( 1 ) && hb_parni( 1 ) >= 0 && hb_parni( 1 ) <= 40 && /*nobody is crazy enough to use > 40 */
       fmod( hb_parnd( 1 ), 2 ) == 0 )
      s_pWvwData->s_byDefLineSpacing = hb_parni( 1 );

   hb_retni( byOldLineSpacing );
}

/*wvw_SetLineSpacing( [nWinNum], [nLineSpacing] )
 * returns old setting of linespacing between lines in window nWinNum
 * then set the line spacing to nLineSpacing (if supplied)
 * NOTES:
 * - nLineSpacing must be even, positive number <= 40
 *   otherwise it will be ignored
 * - if window size will become too high, line spacing is restored
 * - to change default line spacing for next window open, use wvw_SetDefLineSpacing()
 */
HB_FUNC( WVW_SETLINESPACING )
{
   UINT       usWinNum         = WVW_WHICH_WINDOW;
   WIN_DATA * pWindowData      = s_pWvwData->s_pWindows[ usWinNum ];
   int        byOldLineSpacing = pWindowData->byLineSpacing;

   if( ! HB_ISNIL( 2 ) && HB_ISNUM( 2 ) && hb_parni( 2 ) >= 0 && hb_parni( 2 ) <= 40 && /*nobody is crazy enough to use > 40 */
       fmod( hb_parnd( 2 ), 2 ) == 0 )
   {
      USHORT height, maxHeight;
      RECT   rcWorkArea = { 0 };

      SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWorkArea, 0 );
      maxHeight = ( SHORT ) ( rcWorkArea.bottom - rcWorkArea.top );

      pWindowData->byLineSpacing = hb_parni( 2 );
      height = hb_gt_wvwCalcPixelHeight( pWindowData );

      /* TODO/WARNING: this height doesn't take Menu Bar into account */
      if( height >= maxHeight )
         pWindowData->byLineSpacing = byOldLineSpacing;
      else
         hb_gt_wvwResetWindow( usWinNum );
   }

   hb_retni( byOldLineSpacing );
}

/*wvw_SetDefLSpaceColor( [nColorIndex] )
 * returns old setting of s_pWvwData->s_iDefLSpaceColor (color index of spacing between lines)
 * then assigns s_pWvwData->s_iDefLSpaceColor:= nColorIndex (if supplied)
 * NOTES:
 * - nColorIndex will be the default line spacing color for all window opens
 * - nColorIndex must >= 0 and <= 15, or == -1
 *   nCOlorIndex == 0:black, 1:blue, ..., 7:white, ..., 15:bright white
 *   nColorIndex == -1 means line spacing has no color
 * - to check line spacing color being used by a window, use wvw_SetLSpaceColor()
 */
HB_FUNC( WVW_SETDEFLSPACECOLOR )
{
   int iOldDefLSpaceColor = s_pWvwData->s_iDefLSpaceColor;

   if( ! HB_ISNIL( 1 ) && HB_ISNUM( 1 ) && hb_parni( 1 ) >= -1 && hb_parni( 1 ) <= 15 )
      s_pWvwData->s_iDefLSpaceColor = hb_parni( 1 );

   hb_retni( iOldDefLSpaceColor );
}

/*wvw_SetLSpaceColor( [nWinNum], [nColorIndex] )
 * returns old setting of line space color in window nWinNum
 * then set the line spacing color to nColorIndex (if supplied)
 * NOTES:
 * - nColorIndex must be >= 0 and <= 15, or -1
 *   otherwise it will be ignored
 *   nCOlorIndex == 0:black, 1:blue, ..., 7:white, ..., 15:bright white
 * - nColorIndex == -1 means line spacing is not colored
 * - to change default line space color for next window open, use wvw_SetDefLineSpacing()
 */
HB_FUNC( WVW_SETLSPACECOLOR )
{
   UINT       usWinNum        = WVW_WHICH_WINDOW;
   WIN_DATA * pWindowData     = s_pWvwData->s_pWindows[ usWinNum ];
   int        iOldLSpaceColor = pWindowData->iLSpaceColor;

   if( ! HB_ISNIL( 2 ) && HB_ISNUM( 2 ) && hb_parni( 2 ) >= -1 && hb_parni( 2 ) <= 15 )
   {
      pWindowData->iLSpaceColor = hb_parni( 2 );

      if( iOldLSpaceColor != pWindowData->iLSpaceColor )
         hb_gt_wvwSetInvalidRect( pWindowData, 0, 0, pWindowData->COLS - 1, pWindowData->ROWS - 1 );
   }

   hb_retni( iOldLSpaceColor );
}

/*wvw_AllowNonTopEvent( [lAllow] )
 * returns old setting of s_pWvwData->s_bAllowNonTop
 * and set s_pWvwData->s_bAllowNonTop := lAllow (if this optional param is passed)
 *
 * REMARKS:
 * s_pWvwData->s_bAllowNonTop determines how controls behave on non-topmost window
 * if s_pWvwData->s_bAllowNonTop==.t., control's codeblock will always be executed
 *                         when an event occurs on the control
 * if s_pWvwData->s_bAllowNonTop==.f. (the default)
 *                         control's codeblock will be executed only
 *                         if the control is on the topmost window.
 * IMPORTANT NOTE: KILLFOCUS event will always be executed in all condition
 *
 */
HB_FUNC( WVW_ALLOWNONTOPEVENT )
{
   BOOL bOldSetting = s_pWvwData->s_bAllowNonTop;

   if( HB_ISLOG( 1 ) )
      s_pWvwData->s_bAllowNonTop = hb_parl( 1 );

   hb_retl( bOldSetting );
}

/*wvw_RecurseCBlock( [lAllow] )
 * returns old setting of s_pWvwData->s_bRecurseCBlock
 * and set s_pWvwData->s_bRecurseCBlock := lAllow (if this optional param is passed)
 *
 * REMARKS:
 * s_pWvwData->s_bRecurseCBlock determines whether gtwvw allow recursion into control's codeblock
 * if s_pWvwData->s_bRecurseCBlock==.t., control's codeblock is allowed to recurse
 * if s_pWvwData->s_bRecurseCBlock==.f. (the default)
 *                         control's codeblock is not allowed to recurse
 * NOTE: if you are using s_pWvwData->s_bRecurseCBlock == .t. make sure your
 *       codeblock is reentrant, otherwise you may have weird result.
 */
HB_FUNC( WVW_RECURSECBLOCK )
{
   BOOL bOldSetting = s_pWvwData->s_bRecurseCBlock;

   if( HB_ISLOG( 1 ) )
      s_pWvwData->s_bRecurseCBlock = hb_parl( 1 );

   hb_retl( bOldSetting );
}

/*wvw_NoStartupSubWindow( [lOn] )
 * if lOn is supplied:
 * lOn == .t.: when opening window, window will not be displayed
 * lOn == .f.: when opening window, window will be displayed (default)
 * return old setting of s_bNOSTARTUPWINDOW
 */
HB_FUNC( WVW_NOSTARTUPSUBWINDOW )
{
   BOOL bOldNOSTARTUPSUBWINDOW = s_pWvwData->s_bNOSTARTUPSUBWINDOW;

   if( ! HB_ISNIL( 1 ) )
      s_pWvwData->s_bNOSTARTUPSUBWINDOW = hb_parl( 1 );

   hb_retl( bOldNOSTARTUPSUBWINDOW );
}


HB_FUNC( WVW_GETSCREENWIDTH )
{
   hb_retni( GetSystemMetrics( SM_CXSCREEN ) );
}


HB_FUNC( WVW_GETSCREENHEIGHT )
{
   hb_retni( GetSystemMetrics( SM_CYSCREEN ) );
}


/*wvw_SetWindowCentre( nWinNum,   (0==MAIN)
 *                     lCentre,
 *                     lPaintIt)  (if .f. it will just assign lCentre to WIN_DATA)
 */
HB_FUNC( WVW_SETWINDOWCENTRE )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   hb_gt_wvwSetCentreWindow( usWinNum, hb_parl( 2 ), hb_parl( 3 ) );
}


/*wvw_EnableShortcuts( nWinNum, lEnable )
 * lEnable defaults to .t.
 *
 * returns old setting of EnableShortCuts
 */
HB_FUNC( WVW_ENABLESHORTCUTS )
{
   UINT usWinNum = WVW_WHICH_WINDOW;
   BOOL bEnable  = HB_ISNIL( 2 ) ? TRUE : hb_parl( 2 );

   hb_retl( hb_gt_wvwEnableShortCuts( usWinNum, bEnable ) );
}


HB_FUNC( WVW_SETALTF4CLOSE )
{
   hb_retl( hb_gt_wvwSetAltF4Close( hb_parl( 1 ) ) );
}


HB_FUNC( WVW_PROCESSMESSAGES )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   hb_gt_wvwDoProcessMessages( usWinNum );

   hb_retl( 1 );
}


HB_FUNC( WVW_GETTITLE )
{
   UINT usWinNum = WVW_WHICH_WINDOW;
   BYTE ucText[ 1024 ];

   hb_gt_wvwGetWindowTitle( usWinNum, ( char * ) ucText, 1023 );

   hb_retc( ( char * ) ucText );
}


/*                                                                   */
/*   Author.....: Francesco Saverio Giudice <info@fsgiudice.com>     */
/*   Syntax.....: wvw_GetRGBColor( nColor ) --> nRGBColor            */
/*   Description: Return the RGB values passing the color positional value */
/*                0=Black, 1=Blue, etc                               */
/*                as returned from hb_ColorToN()                     */
/*   Creat. Date: 2004-01-15                                         */
/*   Last Modif.: 2004-01-15                                         */
/*                                                                   */


HB_FUNC( WVW_GETRGBCOLOR )
{
   int iColor;

   if( ! HB_ISNIL( 1 ) )
   {
      iColor = hb_parni( 1 );
      if( iColor >= 0 && iColor < 16 ) /* Test bound error */
         hb_retnl( _COLORS[ iColor ] );

   }
}


/*                                                                   */
/*                       Giancarlo Niccolai                          */
/*                                                                   */


/*                    Clipboard functions                            */


HB_FUNC( WVW_GETCLIPBOARD )
{
   HGLOBAL hglb;
   LPTSTR  lptstr;

   if( ! IsClipboardFormatAvailable( CF_TEXT ) )
      hb_ret();

   if( ! OpenClipboard( NULL ) )
      hb_ret();

   hglb = GetClipboardData( CF_TEXT );
   if( hglb != NULL )
   {
      lptstr = ( LPSTR ) GlobalLock( hglb );
      if( lptstr != NULL )
      {
         hb_retc( lptstr );
         GlobalUnlock( hglb );
      }
   }
   CloseClipboard();
}


HB_FUNC( WVW_SETCLIPBOARD )
{
   LPTSTR       lptstrCopy;
   HGLOBAL      hglbCopy;
   const char * cText;
   int          nLen;

   if( ! IsClipboardFormatAvailable( CF_TEXT ) )
   {
      hb_retl( FALSE );
      return;
   }

   /* Check params
    */
   if( ! HB_ISCHAR( 1 ) )
   {
      hb_retl( FALSE );
      return;
   }

   if( ! OpenClipboard( NULL ) )
   {
      hb_retl( FALSE );
      return;
   }
   EmptyClipboard();

   /* Get text from PRG
    */
   cText = hb_parcx( 1 );
   nLen  = hb_parclen( 1 );

   /* Allocate a global memory object for the text.
    */
   hglbCopy = GlobalAlloc( GMEM_MOVEABLE, ( nLen + 1 ) * sizeof( TCHAR ) );
   if( hglbCopy == NULL )
   {
      CloseClipboard();
      hb_retl( FALSE );
      return;
   }

   /* Lock the handle and copy the text to the buffer.
    */
   lptstrCopy = ( LPSTR ) GlobalLock( hglbCopy );
   memcpy( lptstrCopy, cText, ( nLen + 1 ) * sizeof( TCHAR ) );
   lptstrCopy[ nLen + 1 ] = ( TCHAR ) 0;
   GlobalUnlock( hglbCopy );

   /* Place the handle on the clipboard.
    */
   SetClipboardData( CF_TEXT, hglbCopy );

   CloseClipboard();
   hb_retl( TRUE );
}


HB_FUNC( WVW_PASTEFROMCLIPBOARD )
{
   HGLOBAL hglb;
   LPTSTR  lptstr;
   ULONG   ul;

   if( ! IsClipboardFormatAvailable( CF_TEXT ) )
      hb_ret();

   if( ! OpenClipboard( NULL ) )
      hb_ret();

   hglb = GetClipboardData( CF_TEXT );
   if( hglb != NULL )
   {
      lptstr = ( LPSTR ) GlobalLock( hglb );
      if( lptstr != NULL )
      {
         /*TraceLog( NULL, "Clipboard %s\n", (LPSTR) lptstr );        */
         /*TraceLog( NULL, "Clipboard size %u\n", GlobalSize(hglb) ); */

         for( ul = 0; ul < GlobalSize( hglb ); ul++ )
            hb_gt_wvwAddCharToInputQueue( ( int ) lptstr[ ul ] );
         /*TraceLog( NULL, "Value %i\n", ( int ) lptstr[ ul ] );   */
         GlobalUnlock( hglb );
      }
   }
   CloseClipboard();
}

HB_FUNC( WVW_KEYBOARD )
{
   hb_gt_wvwAddCharToInputQueue( hb_parnl( 1 ) );
}


/*                    End of Clipboard Functions                     */


HB_FUNC( WVW_INVALIDATERECT )
{
   UINT       usWinNum    = WVW_WHICH_WINDOW;
   WIN_DATA * pWindowData = s_pWvwData->s_pWindows[ usWinNum ];
   RECT       rc = { 0 };
   POINT      xy = { 0 };

   USHORT usTop    = ( USHORT ) hb_parni( 2 ),
          usLeft   = ( USHORT ) hb_parni( 3 ),
          usBottom = ( USHORT ) hb_parni( 4 ),
          usRight  = ( USHORT ) hb_parni( 5 );

   if( s_pWvwData->s_bMainCoordMode )
      hb_wvw_HBFUNCPrologue( usWinNum, &usTop, &usLeft, &usBottom, &usRight );

   xy        = hb_gt_wvwGetXYFromColRow( pWindowData, usLeft, usTop );
   rc.top    = xy.y;
   rc.left   = xy.x;
   xy        = hb_gt_wvwGetXYFromColRow( pWindowData, usRight + 1, usBottom + 1 );
   rc.bottom = xy.y - 1;
   rc.right  = xy.x - 1;

   InvalidateRect( pWindowData->hWnd, &rc, TRUE );
}


HB_FUNC( WVW_ISLBUTTONPRESSED )
{
   hb_retl( GetKeyState( VK_LBUTTON ) & 0x8000 );
}


HB_FUNC( WVW_CLIENTTOSCREEN )
{
   UINT       usWinNum    = WVW_WHICH_WINDOW;
   WIN_DATA * pWindowData = s_pWvwData->s_pWindows[ usWinNum ];
   PHB_ITEM   paXY        = hb_itemArrayNew( 2 );
   POINT      xy     = { 0 };
   USHORT     usTop  = ( USHORT ) hb_parni( 2 ),
              usLeft = ( USHORT ) hb_parni( 3 );

   if( s_pWvwData->s_bMainCoordMode )
      hb_wvw_HBFUNCPrologue( usWinNum, &usTop, &usLeft, NULL, NULL );

   xy = hb_gt_wvwGetXYFromColRow( pWindowData, usLeft, usTop );

   ClientToScreen( pWindowData->hWnd, &xy );

   hb_arraySetNL( paXY, 1, xy.x );
   hb_arraySetNL( paXY, 2, xy.y );

   hb_itemReturnRelease( paXY );
}


/*                                                                   */
/*               Pritpal Bedi <pritpal@vouchcac.com>                 */
/*                                                                   */


HB_FUNC( WVW_SETFONT )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   hb_retl( hb_gt_wvwSetFont( usWinNum,
                              HB_ISNIL( 2 ) ? s_pWvwData->s_pWindows[ usWinNum ]->fontFace   : hb_parcx( 2 ),
                              HB_ISNIL( 3 ) ? s_pWvwData->s_pWindows[ usWinNum ]->fontHeight : hb_parni( 3 ),
                              HB_ISNIL( 4 ) ? s_pWvwData->s_pWindows[ usWinNum ]->fontWidth  : hb_parni( 4 ),
                              HB_ISNIL( 5 ) ? s_pWvwData->s_pWindows[ usWinNum ]->fontWeight : hb_parni( 5 ),
                              HB_ISNIL( 6 ) ? s_pWvwData->s_pWindows[ usWinNum ]->fontQuality : hb_parni( 6 )
                              ) );
}


HB_FUNC( WVW_SETICON )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   if( HB_ISNUM( 2 ) || HB_ISCHAR( 3 ) )
      hb_retptr( ( void * ) hb_gt_wvwSetWindowIcon( usWinNum, hb_parni( 2 ), hb_parc( 3 ) ) );
   else
   {
      void * hImageName;
      hb_retptr( ( void * ) hb_gt_wvwSetWindowIconFromFile( usWinNum, HB_PARSTRDEF( 2, &hImageName, NULL ) ) );
      hb_strfree( hImageName );
   }
}


HB_FUNC( WVW_SETTITLE )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   hb_gt_wvwSetWindowTitle( usWinNum, hb_parcx( 2 ) );
}


/* wvw_SetWindowPos( nWinNum, nXposition, nYposition)  (position in pixel) */
HB_FUNC( WVW_SETWINDOWPOS )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   hb_gt_wvwSetWindowPos( usWinNum, hb_parni( 2 ), hb_parni( 3 ) );
}


HB_FUNC( WVW_GETWINDOWHANDLE )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   hb_retnl( ( LONG ) hb_gt_wvwGetWindowHandle( usWinNum ) );
}


HB_FUNC( WVW_SETCODEPAGE )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   hb_retni( hb_gt_wvwSetCodePage( usWinNum, hb_parni( 2 ) ) );
}


/* wvw_CenterWindow( nWinNum, lCenter, lPaint )   (nWinNum==0==MAIN) */
HB_FUNC( WVW_CENTERWINDOW )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   hb_retl( hb_gt_wvwSetCentreWindow( usWinNum,
                                      HB_ISNIL( 2 ) ? TRUE  : hb_parl( 2 ),
                                      HB_ISNIL( 3 ) ? FALSE : hb_parl( 3 ) ) );
}


HB_FUNC( WVW_SETMOUSEMOVE )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   if( HB_ISNIL( 2 ) )
      hb_retl( s_pWvwData->s_pWindows[ usWinNum ]->MouseMove );
   else
      hb_retl( hb_gt_wvwSetMouseMove( usWinNum, hb_parl( 2 ) ) );
}


HB_FUNC( WVW_GETXYFROMROWCOL )
{
   UINT     usWinNum = WVW_WHICH_WINDOW;
   PHB_ITEM paXY     = hb_itemArrayNew( 2 );
   POINT    xy       = { 0 };

   xy = hb_gt_wvwGetXYFromColRow( s_pWvwData->s_pWindows[ usWinNum ], ( USHORT ) hb_parni( 3 ), ( USHORT ) hb_parni( 2 ) );

   hb_arraySetNL( paXY, 1, xy.x );
   hb_arraySetNL( paXY, 2, xy.y );

   hb_itemReturnRelease( paXY );
}


/* wvw_GetRowColFromXY( [nWinNum], nX, nY )
 * return an array {nRow, nCol}
 */
HB_FUNC( WVW_GETROWCOLFROMXY )
{
   UINT     usWinNum = WVW_WHICH_WINDOW;
   PHB_ITEM paRowCol = hb_itemArrayNew( 2 );
   POINT    RowCol;

   RowCol = hb_gt_wvwGetColRowFromXY( s_pWvwData->s_pWindows[ usWinNum ], ( USHORT ) hb_parni( 2 ), ( USHORT ) hb_parni( 3 ) );

   hb_arraySetNL( paRowCol, 1, RowCol.y );
   hb_arraySetNL( paRowCol, 2, RowCol.x );

   hb_itemReturnRelease( paRowCol );
}


HB_FUNC( WVW_GETFONTINFO )
{
   UINT     usWinNum = WVW_WHICH_WINDOW;
   PHB_ITEM info     = hb_itemArrayNew( 7 );

   hb_arraySetC(  info, 1, s_pWvwData->s_pWindows[ usWinNum ]->fontFace    );
   hb_arraySetNL( info, 2, s_pWvwData->s_pWindows[ usWinNum ]->fontHeight  );
   hb_arraySetNL( info, 3, s_pWvwData->s_pWindows[ usWinNum ]->fontWidth   );
   hb_arraySetNL( info, 4, s_pWvwData->s_pWindows[ usWinNum ]->fontWeight  );
   hb_arraySetNL( info, 5, s_pWvwData->s_pWindows[ usWinNum ]->fontQuality );
   hb_arraySetNL( info, 6, s_pWvwData->s_pWindows[ usWinNum ]->PTEXTSIZE.y );
   hb_arraySetNL( info, 7, s_pWvwData->s_pWindows[ usWinNum ]->PTEXTSIZE.x );

   hb_itemReturnRelease( info );

}


HB_FUNC( WVW_GETPALETTE )
{
   PHB_ITEM info = hb_itemArrayNew( 16 );
   int      i;

   for( i = 0; i < 16; i++ )
      hb_arraySetNL( info, i + 1, _COLORS[ i ] );

   hb_itemReturnRelease( info );

}


/*                                                                   */
/*    wvw_SetPalette( aRGBValues ) -> An array of 16 elements with RGB values */
/*                                                                   */
HB_FUNC( WVW_SETPALETTE )
{
   int i;

   for( i = 0; i < 16; i++ )
      _COLORS[ i ] = hb_parvnl( 1, i + 1 );
}


HB_FUNC( WVW_MINIMIZE )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   ShowWindow( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, SW_MINIMIZE );
}


/* wvw_Maximize( [nWinNum] )
   maximizes the window, if callback function WVW_SIZE exists

   note: in gtwvt Wvt_Maximize() restores the window, not maximizes it
   see also: wvw_Restore(), wvw_MaxMaxRow(), wvw_MaxMaxCol()
 */
HB_FUNC( WVW_MAXIMIZE )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   if( ! ( s_pWvwData->s_sApp->pSymWVW_SIZE ) )
      /* the old, default behaviour as in gtwvt */
      ShowWindow( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, SW_RESTORE );
   else
      /* app seems to be ready to handle the maximized window */
      ShowWindow( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, SW_MAXIMIZE );

}

/* wvw_Restore( [nWinNum] )
   restores the window (similar with gtwvt's Wvt_Maximize())

   WARNING: restoring window from its maximized state might need handling
            in callback function WVW_SIZE,
            because this function assumes no change in MaxRow()/MaxCol()
   see also: wvw_Maximize(), wvw_MaxMaxRow(), wvw_MaxMaxCol()
 */
HB_FUNC( WVW_RESTORE )
{
   UINT usWinNum = WVW_WHICH_WINDOW;

   ShowWindow( s_pWvwData->s_pWindows[ usWinNum ]->hWnd, SW_RESTORE );
}

/* about WVW_SIZE callback function:

   parameters:
   function WVW_SIZE(nWinNum, hWnd, message, wParam, lParam)

   notes:
 * this function is called by gtwvw AFTER the size is changed
 * WARNING: screen repainting is not performed completely by gtwvw at this point of call
 * WARNING: this function may be called BEFORE gtwvw initialization (use wvw_gtinit() to check)
 * WARNING: this function may be called AFTER xharbour vm cleans up static variables,
              so do NOT use static variables in this function (unless you guard the usage properly)!
              you may however uses MEMVAR such as PUBLIC variables

 */


/* NOTE: this is not supported in GTWVW */
#if 0

HB_FUNC( WVW_SETGUI )
{
   BOOL bGui = s_pWvwData->s_sApp->bGui;

   if( ! HB_ISNIL( 1 ) )
      s_pWvwData->s_sApp->bGui = hb_parl( 1 );

   hb_retl( bGui );
}

#endif

/*
 *
 *  Helper routine.  Take an input pointer, return closest
 *  pointer that is aligned on a DWORD (4 byte) boundary.
 */

LPWORD lpwAlign( LPWORD lpIn )
{
   ULONG ul;

   ul   = ( ULONG ) lpIn;
   ul  += 3;
   ul >>= 2;
   ul <<= 2;
   return ( LPWORD ) ul;
}

int nCopyAnsiToWideChar( LPWORD lpWCStr, LPSTR lpAnsiIn )
{
   int nChar = 0;

   do
   {
      *lpWCStr++ = ( WORD ) *lpAnsiIn;
      nChar++;
   }
   while( *lpAnsiIn++ );

   return nChar;
}

IPicture * rr_LoadPictureFromResource( const char * resname, UINT iresimage, LONG * lwidth, LONG * lheight )
{
   HBITMAP    hbmpx;
   IPicture * iPicture = NULL;
   PICTDESC   picd;
/* int nSize; */
   char szResname[ _MAX_PATH + 1 ];
   int  iWidth, iHeight;

   iWidth  = *lwidth;
   iHeight = *lheight;

   if( resname == NULL )
   {
      sprintf( szResname, "?%u", iresimage );

      hbmpx = FindBitmapHandle( szResname, &iWidth, &iHeight );

      if( ! hbmpx )
      {
         hbmpx = ( HBITMAP ) LoadImage( s_pWvwData->hInstance, ( LPCTSTR ) MAKEINTRESOURCE( ( WORD ) iresimage ), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR );
         AddBitmapHandle( szResname, hbmpx, iWidth, iHeight );
      }
   }
   else
   {
      hbmpx = FindBitmapHandle( resname, &iWidth, &iHeight );

      if( ! hbmpx )
      {
         hbmpx = ( HBITMAP ) LoadImage( s_pWvwData->hInstance, resname, IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR );
         AddBitmapHandle( resname, hbmpx, iWidth, iHeight );
      }
   }
   *lwidth  = iWidth;
   *lheight = iHeight;

   if( hbmpx != NULL )
   {
      iPicture = FindPictureHandle( resname, &iWidth, &iHeight );

      if( iPicture == NULL )
      {
         picd.cbSizeofstruct = sizeof( PICTDESC );
         picd.picType        = PICTYPE_BITMAP;
         picd.bmp.hbitmap    = hbmpx;
         OleCreatePictureIndirect( &picd, &IID_IPicture, TRUE, ( LPVOID * ) &iPicture );
         AddPictureHandle( resname, iPicture, iWidth, iHeight );
      }
   }
   if( iPicture != NULL )
   {
      iPicture->lpVtbl->get_Width( iPicture, lwidth );
      iPicture->lpVtbl->get_Height( iPicture, lheight );
   }
   return iPicture;
}

IPicture * rr_LoadPicture( const char * filename, LONG * lwidth, LONG * lheight )
{
   IStream *  iStream  = NULL;
   IPicture * iPicture = NULL;
   HGLOBAL    hGlobal;
   void *     pGlobal;
   HANDLE     hFile;
   DWORD      nFileSize, nReadByte;

   hFile = CreateFile( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
   if( hFile == INVALID_HANDLE_VALUE )
      return NULL;
   nFileSize = GetFileSize( hFile, NULL );
   hGlobal   = GlobalAlloc( GMEM_MOVEABLE, nFileSize + 4096 );
   pGlobal   = GlobalLock( hGlobal );
   ReadFile( hFile, pGlobal, nFileSize, &nReadByte, NULL );
   CloseHandle( hFile );
   CreateStreamOnHGlobal( hGlobal, TRUE, &iStream );
   if( iStream == NULL )
   {
      GlobalUnlock( hGlobal );
      GlobalFree( hGlobal );
      return NULL;
   }
   OleLoadPicture( iStream, nFileSize, TRUE, &IID_IPicture, ( LPVOID * ) &iPicture );
   GlobalUnlock( hGlobal );
   GlobalFree( hGlobal );
   iStream->lpVtbl->Release( iStream );
   iStream = NULL;
   if( iPicture != NULL )
   {
      iPicture->lpVtbl->get_Width( iPicture, lwidth );
      iPicture->lpVtbl->get_Height( iPicture, lheight );
   }
   return iPicture;
}


/* PENDING decision:
   2004-09-08 TODO: GTWVT deliberately adds new parm aOffset before nRoundHeight
                    I hate it when doing such thing
 */


/* Supporting functions */


static BITMAPINFO * PackedDibLoad( PTSTR szFileName )
{
   BITMAPFILEHEADER bmfh;
   BITMAPINFO *     pbmi;
   BOOL   bSuccess;
   DWORD  dwPackedDibSize, dwBytesRead;
   HANDLE hFile;

   hFile = CreateFile( szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
                       OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL );

   if( hFile == INVALID_HANDLE_VALUE )
      return NULL;

   bSuccess = ReadFile( hFile, &bmfh, sizeof( BITMAPFILEHEADER ),
                        &dwBytesRead, NULL );

   if( ! bSuccess || ( dwBytesRead != sizeof( BITMAPFILEHEADER ) )
       || ( bmfh.bfType != *( WORD * ) "BM" ) )
   {
      CloseHandle( hFile );
      return NULL;
   }

   dwPackedDibSize = bmfh.bfSize - sizeof( BITMAPFILEHEADER );

   pbmi = ( BITMAPINFO * ) hb_xgrab( dwPackedDibSize );

   bSuccess = ReadFile( hFile, pbmi, dwPackedDibSize, &dwBytesRead, NULL );
   CloseHandle( hFile );

   if( ! bSuccess || ( dwBytesRead != dwPackedDibSize ) )
   {

      hb_xfree( pbmi );
      return NULL;
   }

   return pbmi;
}

static int PackedDibGetWidth( BITMAPINFO * pPackedDib )
{
   if( pPackedDib->bmiHeader.biSize == sizeof( BITMAPCOREHEADER ) )
      return ( ( PBITMAPCOREINFO ) pPackedDib )->bmciHeader.bcWidth;
   else
      return pPackedDib->bmiHeader.biWidth;
}

static int PackedDibGetHeight( BITMAPINFO * pPackedDib )
{
   if( pPackedDib->bmiHeader.biSize == sizeof( BITMAPCOREHEADER ) )
      return ( ( PBITMAPCOREINFO ) pPackedDib )->bmciHeader.bcHeight;
   else
      return abs( pPackedDib->bmiHeader.biHeight );
}

static int PackedDibGetBitCount( BITMAPINFO * pPackedDib )
{
   if( pPackedDib->bmiHeader.biSize == sizeof( BITMAPCOREHEADER ) )
      return ( ( PBITMAPCOREINFO ) pPackedDib )->bmciHeader.bcBitCount;
   else
      return pPackedDib->bmiHeader.biBitCount;
}

static int PackedDibGetInfoHeaderSize( BITMAPINFO * pPackedDib )
{
   if( pPackedDib->bmiHeader.biSize == sizeof( BITMAPCOREHEADER ) )
      return ( ( PBITMAPCOREINFO ) pPackedDib )->bmciHeader.bcSize;

   else if( pPackedDib->bmiHeader.biSize == sizeof( BITMAPINFOHEADER ) )
      return pPackedDib->bmiHeader.biSize +
             ( pPackedDib->bmiHeader.biCompression ==
               BI_BITFIELDS ? 12 : 0 );

   else
      return pPackedDib->bmiHeader.biSize;
}

static int PackedDibGetColorsUsed( BITMAPINFO * pPackedDib )
{
   if( pPackedDib->bmiHeader.biSize == sizeof( BITMAPCOREHEADER ) )
      return 0;
   else
      return pPackedDib->bmiHeader.biClrUsed;
}

static int PackedDibGetNumColors( BITMAPINFO * pPackedDib )
{
   int iNumColors;

   iNumColors = PackedDibGetColorsUsed( pPackedDib );

   if( iNumColors == 0 && PackedDibGetBitCount( pPackedDib ) < 16 )
      iNumColors = 1 << PackedDibGetBitCount( pPackedDib );

   return iNumColors;
}

static int PackedDibGetColorTableSize( BITMAPINFO * pPackedDib )
{
   if( pPackedDib->bmiHeader.biSize == sizeof( BITMAPCOREHEADER ) )
      return PackedDibGetNumColors( pPackedDib ) * sizeof( RGBTRIPLE );
   else
      return PackedDibGetNumColors( pPackedDib ) * sizeof( RGBQUAD );
}

static BYTE * PackedDibGetBitsPtr( BITMAPINFO * pPackedDib )
{
   return ( ( BYTE * ) pPackedDib ) + PackedDibGetInfoHeaderSize( pPackedDib ) +
          PackedDibGetColorTableSize( pPackedDib );
}

/* FindBitmapHandle and AddBitmapHandle are for bitmaps associated with
   Windows controls such as toolbar, pushbutton, checkbox, etc */
HBITMAP FindBitmapHandle( const char * szFileName, int * piWidth, int * piHeight )
{
   BITMAP_HANDLE * pbh = s_pWvwData->s_sApp->pbhBitmapList;

   BOOL bStrictDimension = ! ( *piWidth == 0 && *piHeight == 0 );

   while( pbh )
   {

      if( strcmp( szFileName, pbh->szFilename ) == 0 &&
          ( ! bStrictDimension ||
            ( *piWidth == pbh->iWidth &&
              *piHeight == pbh->iHeight
            )
          )
          )
      {
         if( ! bStrictDimension )
         {
            *piWidth  = pbh->iWidth;
            *piHeight = pbh->iHeight;
         }
         return pbh->hBitmap;
      }

      pbh = pbh->pNext;
   }
   return NULL;
}

void AddBitmapHandle( const char * szFileName, HBITMAP hBitmap, int iWidth, int iHeight )
{
   BITMAP_HANDLE * pbhNew = ( BITMAP_HANDLE * ) hb_xgrab( sizeof( BITMAP_HANDLE ) );

   memset( pbhNew, 0, sizeof( BITMAP_HANDLE ) );

   strcpy( pbhNew->szFilename, szFileName );
   pbhNew->hBitmap = hBitmap;
   pbhNew->iWidth  = iWidth;
   pbhNew->iHeight = iHeight;
   pbhNew->pNext   = s_pWvwData->s_sApp->pbhBitmapList;

   s_pWvwData->s_sApp->pbhBitmapList = pbhNew;

}

/* FindPictureHandle and AddPictureHandle are for bitmaps associated with
   Windows controls such as toolbar, pushbutton, checkbox, etc */
static IPicture * FindPictureHandle( const char * szFileName, int * piWidth, int * piHeight )
{
   PICTURE_HANDLE * pph = s_pWvwData->s_sApp->pphPictureList;

   BOOL bStrictDimension = ! ( *piWidth == 0 && *piHeight == 0 );

   while( pph )
   {

      if( strcmp( szFileName, pph->szFilename ) == 0 &&
          ( ! bStrictDimension ||
            ( *piWidth == pph->iWidth &&
              *piHeight == pph->iHeight
            )
          )
          )
      {
         if( ! bStrictDimension )
         {
            *piWidth  = pph->iWidth;
            *piHeight = pph->iHeight;
         }
         return pph->iPicture;
      }

      pph = pph->pNext;
   }
   return NULL;
}

static void AddPictureHandle( const char * szFileName, IPicture * iPicture, int iWidth, int iHeight )
{
   PICTURE_HANDLE * pphNew = ( PICTURE_HANDLE * ) hb_xgrab( sizeof( PICTURE_HANDLE ) );

   memset( pphNew, 0, sizeof( PICTURE_HANDLE ) );
   strcpy( pphNew->szFilename, szFileName );
   pphNew->iPicture = iPicture;
   pphNew->iWidth   = iWidth;
   pphNew->iHeight  = iHeight;
   pphNew->pNext    = s_pWvwData->s_sApp->pphPictureList;

   s_pWvwData->s_sApp->pphPictureList = pphNew;

}

/* FindUserBitmapHandle and AddUserBitmapHandle are for bitmaps NOT associated with
   Windows controls such as toolbar, pushbutton, checkbox, etc
   IOW, it is for user drawn images (wvw_drawimage)
 */
static HBITMAP FindUserBitmapHandle( const char * szFileName, int * piWidth, int * piHeight )
{
   BITMAP_HANDLE * pbh   = s_pWvwData->s_sApp->pbhUserBitmap;
   BOOL bStrictDimension = ! ( *piWidth == 0 && *piHeight == 0 );

   while( pbh )
   {

      if( strcmp( szFileName, pbh->szFilename ) == 0 &&
          ( ! bStrictDimension ||
            ( *piWidth == pbh->iWidth &&
              *piHeight == pbh->iHeight
            )
          )
          )
      {
         if( ! bStrictDimension )
         {
            *piWidth  = pbh->iWidth;
            *piHeight = pbh->iHeight;
         }

         return pbh->hBitmap;
      }
      pbh = pbh->pNext;
   }

   return NULL;
}

static void AddUserBitmapHandle( const char * szFileName, HBITMAP hBitmap, int iWidth, int iHeight )
{
   BITMAP_HANDLE * pbhNew = ( BITMAP_HANDLE * ) hb_xgrab( sizeof( BITMAP_HANDLE ) );

   memset( pbhNew, 0, sizeof( BITMAP_HANDLE ) );

   strcpy( pbhNew->szFilename, szFileName );
   pbhNew->hBitmap = hBitmap;
   pbhNew->iWidth  = iWidth;
   pbhNew->iHeight = iHeight;

   if( s_pWvwData->s_sApp->uiBMcache >= s_pWvwData->s_sApp->uiMaxBMcache )
   {
      BITMAP_HANDLE * pbhTail, * pbhPrev;

      pbhTail = s_pWvwData->s_sApp->pbhUserBitmap;
      pbhPrev = NULL;
      while( pbhTail && pbhTail->pNext )
      {
         pbhPrev = pbhTail;
         pbhTail = pbhTail->pNext;
      }

      if( pbhTail )
      {
         DeleteObject( pbhTail->hBitmap );
         hb_xfree( pbhTail );
         if( pbhPrev )
            pbhPrev->pNext = NULL;
         else
            s_pWvwData->s_sApp->pbhUserBitmap = NULL;
         s_pWvwData->s_sApp->uiBMcache--;
      }
   }

   s_pWvwData->s_sApp->uiBMcache++;
   pbhNew->pNext = s_pWvwData->s_sApp->pbhUserBitmap;
   s_pWvwData->s_sApp->pbhUserBitmap = pbhNew;

}


static HBITMAP hPrepareBitmap( char * szBitmap, UINT uiBitmap,
                               int iExpWidth, int iExpHeight,
                               BOOL bMap3Dcolors,
                               HWND hCtrl )
{
   HBITMAP hBitmap;

   UINT uiOptions = bMap3Dcolors ? LR_LOADMAP3DCOLORS : LR_DEFAULTCOLOR;
   char szResname[ _MAX_PATH + 1 ];

   if( szBitmap )
   {
      hBitmap = FindBitmapHandle( szBitmap, &iExpWidth, &iExpHeight );

      if( ! hBitmap )
      {
         hBitmap = ( HBITMAP ) LoadImage( s_pWvwData->hInstance,
                                          szBitmap,
                                          IMAGE_BITMAP,
                                          iExpWidth,
                                          iExpHeight,
                                          uiOptions );
         if( hBitmap )
         {
            AddBitmapHandle( szBitmap, hBitmap, iExpWidth, iExpHeight );
            return hBitmap;
         }
      }
   }
   else
   {
      sprintf( szResname, "?%u", uiBitmap );
      hBitmap = FindBitmapHandle( szResname, &iExpWidth, &iExpHeight );

      if( ! hBitmap )
      {
         hBitmap = ( HBITMAP ) LoadImage( s_pWvwData->hInstance,
                                          ( LPCTSTR ) MAKEINTRESOURCE( ( WORD ) uiBitmap ),
                                          IMAGE_BITMAP,
                                          iExpWidth,
                                          iExpHeight,
                                          uiOptions );

         if( hBitmap )
         {
            AddBitmapHandle( szResname, hBitmap, iExpWidth, iExpHeight );
            return hBitmap;
         }
         else
            return NULL;
      }
   }

   if( ! hBitmap && szBitmap )
   {
      /* loading from file */
      int iWidth, iHeight;

      hBitmap = FindBitmapHandle( szBitmap, &iExpWidth, &iExpHeight );

      if( ! hBitmap )
      {
         BITMAPINFO * pPackedDib = NULL;
         HDC          hdc;

         if( ! bMap3Dcolors )
            pPackedDib = PackedDibLoad( szBitmap );

         if( pPackedDib || bMap3Dcolors )
         {

            hdc = GetDC( hCtrl );

            if( ! bMap3Dcolors )
            {

               hBitmap = CreateDIBitmap( hdc,
                                         ( PBITMAPINFOHEADER ) pPackedDib,
                                         CBM_INIT,
                                         PackedDibGetBitsPtr( pPackedDib ),
                                         pPackedDib,
                                         DIB_RGB_COLORS );

               if( hBitmap == NULL )
                  return NULL;

               iWidth  = PackedDibGetWidth( pPackedDib );
               iHeight = PackedDibGetHeight( pPackedDib );
            }
            else
            {

               hBitmap = ( HBITMAP ) LoadImage( ( HINSTANCE ) NULL,
                                                szBitmap,
                                                IMAGE_BITMAP,
                                                iExpWidth,
                                                iExpHeight,

                                                LR_LOADFROMFILE | LR_LOADMAP3DCOLORS );

               if( hBitmap == NULL )
                  return NULL;

               iWidth  = iExpWidth;
               iHeight = iExpHeight;
            }

            if( iExpWidth == 0 && iExpHeight == 0 )
            {
               iWidth  = iExpWidth;
               iHeight = iExpHeight;
            }

            if( iExpWidth != iWidth || iExpHeight != iHeight )
            {

               HDC     hdcSource, hdcTarget;
               HBITMAP hBitmap2;
               BOOL    bResult;

               hdcSource = CreateCompatibleDC( hdc );
               SelectObject( hdcSource, hBitmap );

               hdcTarget = CreateCompatibleDC( hdc );
               hBitmap2  = CreateCompatibleBitmap( hdcSource, iExpWidth, iExpHeight );
               SelectObject( hdcTarget, hBitmap2 );

               bResult = StretchBlt(
                  hdcTarget,                          /* handle to destination DC                 */
                  0,                                  /* x-coord of destination upper-left corner */
                  0,                                  /* y-coord of destination upper-left corner */
                  iExpWidth,                          /* width of destination rectangle           */
                  iExpHeight,                         /* height of destination rectangle          */
                  hdcSource,                          /* handle to source DC                      */
                  0,                                  /* x-coord of source upper-left corner      */
                  0,                                  /* y-coord of source upper-left corner      */
                  iWidth,                             /* width of source rectangle                */
                  iHeight,                            /* height of source rectangle               */
                  SRCCOPY                             /* raster operation code                    */
                  );

               if( ! bResult )
               {

                  MessageBox( NULL, TEXT( "Cannot shrink/stretch bitmap for WVW Control" ),
                              s_pWvwData->szAppName, MB_ICONERROR );

                  DeleteObject( hBitmap2 );
               }
               else
               {

                  DeleteObject( hBitmap );
                  hBitmap = hBitmap2;
                  iWidth  = iExpWidth;
                  iHeight = iExpHeight;
               }

               DeleteDC( hdcSource );
               DeleteDC( hdcTarget );

            }

            ReleaseDC( hCtrl, hdc );

            AddBitmapHandle( szBitmap, hBitmap, iWidth, iHeight );

            if( pPackedDib )
               hb_xfree( pPackedDib );
         }
         else
            return NULL;
      }
   }

   return hBitmap;
}

/* add one button to existing Toolbar */
/*
   uiBitmap is resource id
 */

BOOL AddTBButton( HWND hWndToolbar, char * szBitmap, UINT uiBitmap, char * pszLabel, int iCommand, int iBitmapType, BOOL bMap3Dcolors, WIN_DATA * pWindowData, BOOL bDropdown )
{
   TBBUTTON    tbb;
   TBADDBITMAP tbab;
   char        szBuffer[ WVW_TB_LABELMAXLENGTH + 2 ];
   int         iNewBitmap, iNewString;
   int         iOffset;
   BOOL        bSuccess;
   HBITMAP     hBitmap;

   if( iCommand == 0 )
   {
      tbb.iBitmap   = 0;
      tbb.idCommand = 0;
      tbb.fsState   = TBSTATE_ENABLED;
      tbb.fsStyle   = TBSTYLE_SEP;
      tbb.dwData    = 0;
      tbb.iString   = 0;

      bSuccess = ( BOOL ) SendMessage( hWndToolbar, TB_ADDBUTTONS, ( WPARAM ) 1, ( LPARAM ) ( LPTBBUTTON ) &tbb );
      return bSuccess;
   }

   switch( iBitmapType )
   {
      case 0:
         iOffset = 0;
         break;
      case 1:
         iOffset = pWindowData->iStartStdBitmap;
         break;
      case 2:
         iOffset = pWindowData->iStartViewBitmap;
         break;
      case 3:
         iOffset = pWindowData->iStartHistBitmap;
         break;
      default:
         iOffset = 0;
         break;
   }

   if( iBitmapType == 0 )
   {
      int iExpWidth, iExpHeight;

      iExpWidth  = pWindowData->iTBImgWidth;
      iExpHeight = pWindowData->iTBImgHeight;

      hBitmap = hPrepareBitmap( szBitmap, uiBitmap,
                                iExpWidth, iExpHeight,
                                bMap3Dcolors,
                                hWndToolbar );

      if( ! hBitmap )
         return FALSE;

      tbab.hInst = NULL;
      tbab.nID   = ( UINT_PTR ) hBitmap;
      iNewBitmap = SendMessage( hWndToolbar, TB_ADDBITMAP, ( WPARAM ) 1, ( WPARAM ) &tbab );

   }
   else /* system bitmap */
      iNewBitmap = ( int ) uiBitmap + iOffset;

   szBuffer[ 0 ] = ( char ) 0;
   strcat( szBuffer, pszLabel );
   szBuffer[ strlen( szBuffer ) + 1 ] = ( char ) 0;
   iNewString = SendMessage( hWndToolbar, TB_ADDSTRING, ( WPARAM ) 0, ( LPARAM ) szBuffer );

   tbb.iBitmap   = iNewBitmap;
   tbb.idCommand = iCommand;
   tbb.fsState   = TBSTATE_ENABLED;
   tbb.fsStyle   = TBSTYLE_BUTTON;
   if( bDropdown )
      tbb.fsStyle = tbb.fsStyle | 0x0080 /*BTNS_WHOLEDROPDOWN*/;
   tbb.dwData  = 0;
   tbb.iString = iNewString;

   bSuccess = SendMessage( hWndToolbar, TB_ADDBUTTONS, ( WPARAM ) 1, ( LPARAM ) ( LPTBBUTTON ) &tbb );

   return bSuccess;
}

int IndexToCommand( HWND hWndTB, int iIndex )
{
   TBBUTTON tbb;

   if( SendMessage( hWndTB, TB_GETBUTTON, ( WPARAM ) iIndex, ( LPARAM ) ( LPTBBUTTON ) &tbb ) )
      return tbb.idCommand;
   else
      return 0;
}

int CommandToIndex( HWND hWndTB, int iCommand )
{
   return SendMessage( hWndTB, TB_COMMANDTOINDEX, ( WPARAM ) iCommand, ( LPARAM ) 0 );
}

void hb_gt_wvwTBinitSize( WIN_DATA * pWindowData, HWND hWndTB )
{
   RECT rTB = { 0 };

   SendMessage( hWndTB, TB_AUTOSIZE, ( WPARAM ) 0, ( LPARAM ) 0 );

   if( GetClientRect( hWndTB, &rTB ) )
   {

      USHORT usTBHeight = ( USHORT ) rTB.bottom;

      pWindowData->usTBHeight = usTBHeight + 2;

   }
}

LRESULT CALLBACK hb_gt_wvwTBProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
   HWND       hWndParent = GetParent( hWnd );
   UINT       usWinNum;
   WIN_DATA * pWindowData;

   if( hWndParent == NULL )
   {
      /* TODO: runtime/internal error is better */
      MessageBox( NULL, TEXT( "hb_gt_wvwTBProc(): parent of toolbar is missing" ),
                  s_pWvwData->szAppName, MB_ICONERROR );

      return DefWindowProc( hWnd, message, wParam, lParam );
   }

   for( usWinNum = 0; usWinNum < s_pWvwData->s_usNumWindows; usWinNum++ )
      if( s_pWvwData->s_pWindows[ usWinNum ]->hWnd == hWndParent )
         break;

   if( usWinNum >= s_pWvwData->s_usNumWindows )
   {
      /* TODO: runtime/internal error is better */
      MessageBox( NULL, TEXT( "hb_gt_wvwTBProc(): invalid handle of tollbar's parent" ),
                  s_pWvwData->szAppName, MB_ICONERROR );

      return DefWindowProc( hWnd, message, wParam, lParam );
   }

   pWindowData = s_pWvwData->s_pWindows[ usWinNum ];

   switch( message )
   {
      case WM_RBUTTONDOWN:
      case WM_LBUTTONDOWN:
      case WM_RBUTTONUP:
      case WM_LBUTTONUP:
      case WM_RBUTTONDBLCLK:
      case WM_LBUTTONDBLCLK:
      case WM_MBUTTONDOWN:
      case WM_MBUTTONUP:
      case WM_MBUTTONDBLCLK:
      case WM_MOUSEMOVE:
      case WM_MOUSEWHEEL:
      case WM_NCMOUSEMOVE:

         if( ! hb_gt_wvwAcceptingInput() || ( usWinNum != s_pWvwData->s_usNumWindows - 1 ) )
            return 0;

         hb_gt_wvwTBMouseEvent( pWindowData, hWnd, message, wParam, lParam );
#if 0
         return 0;
         TB_ISBUTTONHIGHLIGHTED
#endif
      case WM_PAINT:
      {

         HGDIOBJ hOldObj;
         HDC     hdc;
         RECT    rTB = { 0 };
         int     iTop, iRight;

         CallWindowProc( ( WNDPROC ) pWindowData->tbOldProc, hWnd, message, wParam, lParam );

         GetClientRect( hWnd, &rTB );
         iTop   = rTB.bottom - 3;
         iRight = rTB.right;

         hdc = GetDC( hWnd );

         hOldObj = SelectObject( hdc, s_pWvwData->s_sApp->penWhite );

         MoveToEx( hdc, 0, iTop, NULL );          /* Top */
         LineTo( hdc, iRight, iTop );

         SelectObject( hdc, s_pWvwData->s_sApp->penBlack );

         MoveToEx( hdc, 0, iTop + 2, NULL );        /* Bottom */
         LineTo( hdc, iRight, iTop + 2 );

         SelectObject( hdc, s_pWvwData->s_sApp->penDarkGray );
         MoveToEx( hdc, 0, iTop + 1, NULL );        /* Middle */
         LineTo( hdc, iRight, iTop + 1 );

         SelectObject( pWindowData->hdc, hOldObj );
         ReleaseDC( hWnd, hdc );

         return 0;
      }

   }

   return CallWindowProc( ( WNDPROC ) pWindowData->tbOldProc, hWnd, message, wParam, lParam );
}


/* .prg callable functions                                           */


/* SCROLLBAR begins                                                  */


/*********************** start control (eg. scrollbar) list handler ***************************/

HWND FindControlHandle( UINT usWinNum, BYTE byCtrlClass, UINT uiCtrlid, byte * pbStyle )
{
   WIN_DATA *     pWindowData = s_pWvwData->s_pWindows[ usWinNum ];
   CONTROL_DATA * pcd         = pWindowData->pcdCtrlList;

   while( pcd )
   {
      if( byCtrlClass == pcd->byCtrlClass && uiCtrlid == pcd->uiCtrlid )
      {
         *pbStyle = pcd->bStyle;
         return pcd->hWndCtrl;
      }
      pcd = pcd->pNext;
   }
   return NULL;
}

UINT FindControlId( UINT usWinNum, BYTE byCtrlClass, HWND hWndCtrl, byte * pbStyle )
{
   WIN_DATA *     pWindowData = s_pWvwData->s_pWindows[ usWinNum ];
   CONTROL_DATA * pcd         = pWindowData->pcdCtrlList;

   while( pcd )
   {
      if( byCtrlClass == pcd->byCtrlClass && hWndCtrl == pcd->hWndCtrl )
      {
         *pbStyle = pcd->bStyle;
         return pcd->uiCtrlid;
      }
      pcd = pcd->pNext;
   }
   return ( UINT ) NULL;
}

UINT LastControlId( UINT usWinNum, BYTE byCtrlClass )
{
   WIN_DATA *     pWindowData = s_pWvwData->s_pWindows[ usWinNum ];
   CONTROL_DATA * pcd         = pWindowData->pcdCtrlList;

   while( pcd && byCtrlClass != pcd->byCtrlClass )
      pcd = pcd->pNext;

   if( pcd )
      return pcd->uiCtrlid;
   else
      return 0;
}

void AddControlHandle( UINT usWinNum, BYTE byCtrlClass, HWND hWndCtrl, UINT uiCtrlid, PHB_ITEM phiCodeBlock, RECT rCtrl, RECT rOffCtrl, byte bStyle )
{
   WIN_DATA *     pWindowData = s_pWvwData->s_pWindows[ usWinNum ];
   CONTROL_DATA * pcdNew      = ( CONTROL_DATA * ) hb_xgrab( sizeof( CONTROL_DATA ) );

   memset( pcdNew, 0, sizeof( CONTROL_DATA ) );

   pcdNew->byCtrlClass = byCtrlClass;
   pcdNew->hWndCtrl    = hWndCtrl;
   pcdNew->uiCtrlid    = uiCtrlid;

   pcdNew->phiCodeBlock = NULL;

   if( phiCodeBlock != NULL )
      pcdNew->phiCodeBlock = hb_itemNew( phiCodeBlock );


   pcdNew->bBusy  = FALSE;
   pcdNew->uiBusy = 0;

   pcdNew->rCtrl.top       = rCtrl.top;
   pcdNew->rCtrl.left      = rCtrl.left;
   pcdNew->rCtrl.bottom    = rCtrl.bottom;
   pcdNew->rCtrl.right     = rCtrl.right;
   pcdNew->rOffCtrl.top    = rOffCtrl.top;
   pcdNew->rOffCtrl.left   = rOffCtrl.left;
   pcdNew->rOffCtrl.bottom = rOffCtrl.bottom;
   pcdNew->rOffCtrl.right  = rOffCtrl.right;

   pcdNew->bStyle = bStyle;

   pcdNew->OldProc = ( WNDPROC ) NULL;

   pcdNew->pNext = pWindowData->pcdCtrlList;

   pWindowData->pcdCtrlList = pcdNew;
}

CONTROL_DATA * GetControlData( UINT usWinNum, BYTE byCtrlClass, HWND hWndCtrl, UINT uiCtrlid )
{
   WIN_DATA *     pWindowData = s_pWvwData->s_pWindows[ usWinNum ];
   CONTROL_DATA * pcd         = pWindowData->pcdCtrlList;

   while( pcd )
   {
      if( byCtrlClass == pcd->byCtrlClass &&
          ( ( hWndCtrl && hWndCtrl == pcd->hWndCtrl ) ||
            ( uiCtrlid && uiCtrlid == pcd->uiCtrlid ) ) )
         return pcd;
      pcd = pcd->pNext;
   }
   return NULL;
}

BOOL StoreControlProc( UINT usWinNum, BYTE byCtrlClass, HWND hWndCtrl, WNDPROC OldProc )
{
   WIN_DATA *     pWindowData = s_pWvwData->s_pWindows[ usWinNum ];
   CONTROL_DATA * pcd         = pWindowData->pcdCtrlList;

   while( pcd )
   {
      if( byCtrlClass == pcd->byCtrlClass && hWndCtrl == pcd->hWndCtrl )
      {
         pcd->OldProc = OldProc;
         return TRUE;
      }
      pcd = pcd->pNext;
   }
   return FALSE;
}

WNDPROC GetControlProc( UINT usWinNum, BYTE byCtrlClass, HWND hWndCtrl )
{
   WIN_DATA *     pWindowData = s_pWvwData->s_pWindows[ usWinNum ];
   CONTROL_DATA * pcd         = pWindowData->pcdCtrlList;

   while( pcd )
   {
      if( byCtrlClass == pcd->byCtrlClass && hWndCtrl == pcd->hWndCtrl )
         return pcd->OldProc;
      pcd = pcd->pNext;
   }
   return ( WNDPROC ) NULL;
}

static int GetControlClass( UINT usWinNum, HWND hWndCtrl )
{

   WIN_DATA *     pWindowData = s_pWvwData->s_pWindows[ usWinNum ];
   CONTROL_DATA * pcd         = pWindowData->pcdCtrlList;

   while( pcd )
   {
      if( hWndCtrl == pcd->hWndCtrl )
         return pcd->byCtrlClass;
      pcd = pcd->pNext;
   }
   return 0;
}

static void RunControlBlock( UINT usWinNum, BYTE byCtrlClass, HWND hWndCtrl, UINT message, WPARAM wParam, LPARAM lParam, int iEventType )
{
   WIN_DATA *     pWindowData = s_pWvwData->s_pWindows[ usWinNum ];
   CONTROL_DATA * pcd         = pWindowData->pcdCtrlList;

   while( pcd && ( byCtrlClass != pcd->byCtrlClass || hWndCtrl != pcd->hWndCtrl ) )
      pcd = pcd->pNext;

   if( pcd == NULL )
      return;

   if( ( pcd->byCtrlClass == WVW_CONTROL_SCROLLBAR ||
         pcd->byCtrlClass == WVW_CONTROL_PUSHBUTTON ||
         pcd->byCtrlClass == WVW_CONTROL_COMBOBOX ||
         pcd->byCtrlClass == WVW_CONTROL_EDITBOX
         )
       && pcd->phiCodeBlock )
   {
      PHB_ITEM phiWinNum, phiXBid, phiXBmsg, phiXBpos;
      PHB_ITEM pReturn;

      if( pcd->bBusy )
         if( ! s_pWvwData->s_bRecurseCBlock )
            return;

      pcd->bBusy = TRUE;
      pcd->uiBusy++;

      phiWinNum = hb_itemNew( NULL );
      hb_itemPutNI( phiWinNum, ( int ) usWinNum );

      phiXBid = hb_itemNew( NULL );
      hb_itemPutNI( phiXBid, ( int ) pcd->uiCtrlid );

      if( pcd->byCtrlClass == WVW_CONTROL_SCROLLBAR )
      {
         phiXBmsg = hb_itemNew( NULL );
         hb_itemPutNI( phiXBmsg, ( int ) LOWORD( wParam ) );

         phiXBpos = hb_itemNew( NULL );
         hb_itemPutNI( phiXBpos, ( int ) HIWORD( wParam ) );

         pReturn = hb_itemDo( pcd->phiCodeBlock, 4, phiWinNum, phiXBid, phiXBmsg, phiXBpos );
         hb_itemRelease( pReturn );
         hb_itemRelease( phiXBmsg );
         hb_itemRelease( phiXBpos );
      }
      else if( pcd->byCtrlClass == WVW_CONTROL_PUSHBUTTON )
      {

         pReturn = hb_itemDo( pcd->phiCodeBlock, 2, phiWinNum, phiXBid );
         hb_itemRelease( pReturn );
      }
      else if( pcd->byCtrlClass == WVW_CONTROL_COMBOBOX )
      {
         int iCurSel;

         PHB_ITEM phiEvent, phiIndex;

         switch( iEventType )
         {
            case CBN_SELCHANGE:
            case CBN_SETFOCUS:
            case CBN_KILLFOCUS:
               iCurSel = SendMessage( ( HWND ) pcd->hWndCtrl,
                                      CB_GETCURSEL,
                                      ( WPARAM ) 0,
                                      ( LPARAM ) 0
                                      );
               if( iCurSel == CB_ERR )
                  break;

#if 0
               /***********************
                  let user find by his own, what is the string of iCurSel
                  we don;t have to do this: */

               iTextLen = SendMessage( ( HWND ) pcd->hWndCtrl,
                                       CB_GETLBTEXTLEN,
                                       ( WPARAM ) iCurSel;
                                       ( LPARAM ) 0
                                       );
               lptstrSelected = ( char * ) hb_xgrab( iTextLen + 1 );

               SendMessage( ( HWND ) pcd->hWndCtrl,
                            CB_GETLBTEXT,
                            ( WPARAM ) iCurSel,
                            ( LPARAM ) lptstrSelected
                            );

               ...

               hb_xfree( lptstrSelected );

#endif

               /* now execute the codeblock */
               phiEvent = hb_itemNew( NULL );
               hb_itemPutNI( phiEvent, iEventType );

               phiIndex = hb_itemNew( NULL );
               hb_itemPutNI( phiIndex, ( int ) iCurSel );

               pReturn = hb_itemDo( pcd->phiCodeBlock, 4, phiWinNum, phiXBid, phiEvent, phiIndex );
               hb_itemRelease( pReturn );
               hb_itemRelease( phiEvent );
               hb_itemRelease( phiIndex );

         }
      }
      else if( pcd->byCtrlClass == WVW_CONTROL_EDITBOX )
      {
         PHB_ITEM phiEvent;

         switch( iEventType )
         {
            case EN_SETFOCUS:
            case EN_KILLFOCUS:
            case EN_CHANGE:

               /* now execute the codeblock */
               phiEvent = hb_itemNew( NULL );

               hb_itemPutNI( phiEvent, ( int ) iEventType );

               pReturn = hb_itemDo( pcd->phiCodeBlock, 3, phiWinNum, phiXBid, phiEvent );
               hb_itemRelease( pReturn );
               hb_itemRelease( phiEvent );

               break;

         }
      }

      hb_itemRelease( phiWinNum );
      hb_itemRelease( phiXBid );

      pcd->uiBusy--;

      if( pcd->uiBusy == 0 )
         pcd->bBusy = FALSE;
   }

   HB_SYMBOL_UNUSED( message );
   HB_SYMBOL_UNUSED( lParam );

}

static void ReposControls( UINT usWinNum, BYTE byCtrlClass )
{
   WIN_DATA *     pWindowData = s_pWvwData->s_pWindows[ usWinNum ];
   CONTROL_DATA * pcd         = pWindowData->pcdCtrlList;

   while( pcd )
   {
      if( byCtrlClass == 0 || byCtrlClass == pcd->byCtrlClass )
      {
         POINT xy = { 0 };
         int   iTop, iLeft, iBottom, iRight;

         xy    = hb_gt_wvwGetXYFromColRow( pWindowData, ( USHORT ) pcd->rCtrl.left, ( USHORT ) pcd->rCtrl.top );
         iTop  = xy.y + pcd->rOffCtrl.top;
         iLeft = xy.x + pcd->rOffCtrl.left;

         xy = hb_gt_wvwGetXYFromColRow( pWindowData, ( ( USHORT ) ( LONG ) ( pcd->rCtrl.right ) ) + 1, ( ( USHORT ) ( LONG ) ( pcd->rCtrl.bottom ) ) + 1 );

         xy.y -= pWindowData->byLineSpacing;

         if( pcd->byCtrlClass == WVW_CONTROL_SCROLLBAR )
         {

            if( pcd->bStyle == SBS_VERT )
            {
               iBottom = xy.y - 1 + pcd->rOffCtrl.bottom;
               iRight  = iLeft + pWindowData->PTEXTSIZE.y - 1 + pcd->rOffCtrl.right;
            }
            else
            {
               iRight  = xy.x - 1 + pcd->rOffCtrl.right;
               iBottom = iTop + pWindowData->PTEXTSIZE.y - 1 + pcd->rOffCtrl.bottom;
            }
         }
         else if( pcd->byCtrlClass == WVW_CONTROL_PUSHBUTTON )
         {
            iBottom = xy.y - 1 + pcd->rOffCtrl.bottom;
            iRight  = xy.x - 1 + pcd->rOffCtrl.right;
         }
         else if( pcd->byCtrlClass == WVW_CONTROL_PROGRESSBAR )
         {
            iBottom = xy.y - 1 + pcd->rOffCtrl.bottom;
            iRight  = xy.x - 1 + pcd->rOffCtrl.right;
         }
         else if( pcd->byCtrlClass == WVW_CONTROL_COMBOBOX )
         {

            iBottom = xy.y - 1 + ( pcd->rOffCtrl.bottom * hb_wvw_LineHeight( pWindowData ) );
            iRight  = xy.x - 1 + pcd->rOffCtrl.right;
         }
         else if( pcd->byCtrlClass == WVW_CONTROL_EDITBOX )
         {
            iBottom = xy.y - 1 + pcd->rOffCtrl.bottom;
            iRight  = xy.x - 1 + pcd->rOffCtrl.right;
         }
         else
         {

            hb_errRT_TERM( EG_NOFUNC, 10001, "Undefined Control Class", "ReposControls()", 0, 0 );

            /* dummy assignment, to avoid warning in mingw32: */
            iBottom = 0;
            iRight  = 0;
         }

         SetWindowPos( pcd->hWndCtrl, NULL, iLeft, iTop, iRight - iLeft + 1, iBottom - iTop + 1, SWP_NOZORDER );
      }

      pcd = pcd->pNext;
   }
}

/*********************** end control (eg. scrollbar) list handler ***************************/


/* SCROLLBAR begins                                                  */


LRESULT CALLBACK hb_gt_wvwXBProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
   HWND hWndParent = GetParent( hWnd );
   UINT usWinNum;

   UINT uiXBid;
   /* byte bStyle; */
   WNDPROC OldProc;

   if( message == WM_MOUSEACTIVATE )
      s_pWvwData->s_iScrolling = 1;


   if( hWndParent == NULL )
      return DefWindowProc( hWnd, message, wParam, lParam );

   for( usWinNum = 0; usWinNum < s_pWvwData->s_usNumWindows; usWinNum++ )
      if( s_pWvwData->s_pWindows[ usWinNum ]->hWnd == hWndParent )
         break;

   if( usWinNum >= s_pWvwData->s_usNumWindows )
      return DefWindowProc( hWnd, message, wParam, lParam );

   uiXBid = ( UINT ) GetWindowLong( hWnd, GWL_ID );
   if( uiXBid == 0 )
   {
      MessageBox( NULL, TEXT( "Failed FindControlId of Scrollbar" ),
                  s_pWvwData->szAppName, MB_ICONERROR );

      return DefWindowProc( hWnd, message, wParam, lParam );
   }

   OldProc = GetControlProc( usWinNum, WVW_CONTROL_SCROLLBAR, hWnd );
   if( OldProc == NULL )
   {
      MessageBox( NULL, TEXT( "Failed GetControlProc of Scrollbar" ),
                  s_pWvwData->szAppName, MB_ICONERROR );

      return DefWindowProc( hWnd, message, wParam, lParam );
   }

   switch( message )
   {

      case WM_LBUTTONUP:

         CallWindowProc( OldProc, hWnd, message, wParam, lParam );
         if( GetCapture() == hWnd )
         {
            ReleaseCapture();

            InvalidateRect( hWnd, NULL, FALSE );

         }
         return 0;

      case WM_RBUTTONDOWN:

         s_pWvwData->s_iScrolling = 0;

         return 0;
      case WM_RBUTTONUP:

         return 0;

   }

   if( message == WM_CAPTURECHANGED )
      s_pWvwData->s_iScrolling = 0;


   return CallWindowProc( OldProc, hWnd, message, wParam, lParam );
}


/* PUSHBUTTON begins                                                 */


LRESULT CALLBACK hb_gt_wvwBtnProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
   HWND hWndParent = GetParent( hWnd );
   UINT usWinNum;

   UINT uiPBid;

   WNDPROC OldProc;

   if( hWndParent == NULL )
      return DefWindowProc( hWnd, message, wParam, lParam );

   for( usWinNum = 0; usWinNum < s_pWvwData->s_usNumWindows; usWinNum++ )
      if( s_pWvwData->s_pWindows[ usWinNum ]->hWnd == hWndParent )
         break;

   if( usWinNum >= s_pWvwData->s_usNumWindows )
      return DefWindowProc( hWnd, message, wParam, lParam );

   uiPBid = ( UINT ) GetWindowLong( hWnd, GWL_ID );
   if( uiPBid == 0 )
   {

      MessageBox( NULL, TEXT( "Failed FindControlId" ),
                  s_pWvwData->szAppName, MB_ICONERROR );

      return DefWindowProc( hWnd, message, wParam, lParam );
   }

   OldProc = GetControlProc( usWinNum, WVW_CONTROL_PUSHBUTTON, hWnd );
   if( OldProc == NULL )
   {

      MessageBox( NULL, TEXT( "Failed GetControlProc" ),
                  s_pWvwData->szAppName, MB_ICONERROR );

      return DefWindowProc( hWnd, message, wParam, lParam );
   }

   switch( message )
   {

      case WM_KEYDOWN:
      case WM_SYSKEYDOWN:
      {
         BOOL bAlt   = GetKeyState( VK_MENU ) & 0x8000;
         BOOL bCtrl  = GetKeyState( VK_CONTROL ) & 0x8000;
         BOOL bShift = GetKeyState( VK_SHIFT ) & 0x8000;

         int c = ( int ) wParam;

         if( ! bAlt && ! bCtrl && ! bShift && wParam == VK_SPACE )
            break;

         if( ! hb_gt_wvwBufferedKey( ( LONG ) wParam ) )
            break;

         switch( c )
         {

            /*
               case VK_RETURN:
               {

               SendMessage(hWnd, BM_CLICK, 0, 0);

               break;

               }
             */

            default:
               SetFocus( hWndParent );
               PostMessage( hWndParent, message, wParam, lParam );

               break;

         }
         return 0;

      }

         /*
            case WM_RBUTTONDBLCLK:
            case WM_LBUTTONDBLCLK:
            case WM_MBUTTONDOWN:
            case WM_MBUTTONUP:
            case WM_MBUTTONDBLCLK:
            case WM_MOUSEMOVE:
            case WM_MOUSEWHEEL:
          */
         {

         }

   }

   return CallWindowProc( ( WNDPROC ) OldProc, hWnd, message, wParam, lParam );
}

/************************
 * BEGIN button supporters
 * for pushbutton and checkbox
 *************************/

/*ASSUME: WVW_ID_BASE_PUSHBUTTON == WVW_ID_BASE_CHECKBOX
 *        WVW_CONTROL_PUSHBUTTON == WVW_CONTROL_CHECKBOX
 */
UINT ButtonCreate( UINT usWinNum, USHORT usTop, USHORT usLeft, USHORT usBottom, USHORT usRight, LPCTSTR lpszCaption,
                   char * szBitmap, UINT uiBitmap, PHB_ITEM phbiCodeBlock,
                   int iOffTop, int iOffLeft, int iOffBottom, int iOffRight,
                   double dStretch, BOOL bMap3Dcolors,
                   int iStyle )
{
   WIN_DATA * pWindowData = s_pWvwData->s_pWindows[ usWinNum ];
   HWND       hWndParent  = pWindowData->hWnd;
   HWND       hWndButton;
   POINT      xy = { 0 };
   int        iTop, iLeft, iBottom, iRight;
   UINT       uiPBid;

   if( pWindowData->hPBfont == NULL )
   {
      pWindowData->hPBfont = CreateFontIndirect( &s_pWvwData->s_lfPB );
      if( pWindowData->hPBfont == NULL )
         return 0;
   }

   if( s_pWvwData->s_bMainCoordMode )
      hb_wvw_HBFUNCPrologue( usWinNum, &usTop, &usLeft, &usBottom, &usRight );

   xy    = hb_gt_wvwGetXYFromColRow( pWindowData, usLeft, usTop );
   iTop  = xy.y + iOffTop;
   iLeft = xy.x + iOffLeft;

   xy = hb_gt_wvwGetXYFromColRow( pWindowData, usRight + 1, usBottom + 1 );

   xy.y -= pWindowData->byLineSpacing;

   iBottom = xy.y - 1 + iOffBottom;
   iRight  = xy.x - 1 + iOffRight;

   uiPBid = LastControlId( usWinNum, WVW_CONTROL_PUSHBUTTON );
   if( uiPBid == 0 )
      uiPBid = WVW_ID_BASE_PUSHBUTTON;
   else
      uiPBid++;

   if( szBitmap || uiBitmap )
      iStyle |= BS_BITMAP;

   hWndButton = CreateWindowEx(
      0L,                                       /* no extended styles */
      "BUTTON",                                 /* pushbutton/checkbox control class */
      ( LPSTR ) lpszCaption,                    /* text for caption */
      WS_CHILD | WS_VISIBLE | ( DWORD ) iStyle, /* button styles */
      iLeft,                                    /* horizontal position */
      iTop,                                     /* vertical position */
      iRight - iLeft + 1,                       /* width of the button */
      iBottom - iTop + 1,                       /* height */
      hWndParent,                               /* handle to parent window */
      ( HMENU ) uiPBid,                         /* id for this button control */
      s_pWvwData->hInstance,                    /* instance owning this window */
      ( LPVOID ) NULL                           /* pointer not needed */
      );

   if( hWndButton )
   {
      RECT    rXB = { 0 }, rOffXB = { 0 };
      WNDPROC OldProc;

      if( szBitmap || uiBitmap )
      {
         HBITMAP hBitmap;
         int     iExpWidth, iExpHeight;

         iExpWidth  = iRight - iLeft + 1;
         iExpHeight = iBottom - iTop + 1;
         hBitmap    = hPrepareBitmap( szBitmap, uiBitmap,
                                      ( int ) dStretch * iExpWidth, ( int ) dStretch * iExpHeight,
                                      bMap3Dcolors,
                                      hWndButton );

         if( hBitmap )
            SendMessage( hWndButton,               /* handle to destination window */
                         BM_SETIMAGE,              /* message to send */
                         ( WPARAM ) IMAGE_BITMAP,  /* image type */
                         ( LPARAM ) hBitmap );     /* handle to the image (HANDLE) */
      }

      rXB.top       = usTop;     rXB.left = usLeft;
      rXB.bottom    = usBottom; rXB.right = usRight;
      rOffXB.top    = iOffTop;     rOffXB.left = iOffLeft;
      rOffXB.bottom = iOffBottom; rOffXB.right = iOffRight;

      AddControlHandle( usWinNum, WVW_CONTROL_PUSHBUTTON, hWndButton, uiPBid, ( PHB_ITEM ) phbiCodeBlock, rXB, rOffXB, ( byte ) iStyle );

#if 0
      OldProc = SetWindowLongPtr( hWndButton,
                                  GWLP_WNDPROC, ( LONG_PTR ) hb_gt_wvwBtnProc );
#endif
      OldProc = SubclassWindow( hWndButton, hb_gt_wvwBtnProc );

      StoreControlProc( usWinNum, WVW_CONTROL_PUSHBUTTON, hWndButton, OldProc );


      SendMessage( hWndButton, WM_SETFONT, ( WPARAM ) pWindowData->hPBfont, ( LPARAM ) TRUE );
      hb_stornl( ( LONG ) hWndButton, 12 );

      return uiPBid;
   }
   else
      return 0;

}

/*************************
* END button supporters
* for pushbutton and checkbox
*************************/


LRESULT CALLBACK hb_gt_wvwCBProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
   HWND hWndParent = GetParent( hWnd );
   UINT usWinNum;

   UINT    uiCBid;
   WNDPROC OldProc;
   BYTE    bKbdType;

   if( hWndParent == NULL )
      return DefWindowProc( hWnd, message, wParam, lParam );

   for( usWinNum = 0; usWinNum < s_pWvwData->s_usNumWindows; usWinNum++ )
      if( s_pWvwData->s_pWindows[ usWinNum ]->hWnd == hWndParent )
         break;

   if( usWinNum >= s_pWvwData->s_usNumWindows )
      return DefWindowProc( hWnd, message, wParam, lParam );

   uiCBid = ( UINT ) FindControlId( usWinNum, WVW_CONTROL_COMBOBOX, hWnd, &bKbdType );

   if( uiCBid == 0 )
   {
      MessageBox( NULL, TEXT( "Failed FindControlId" ),
                  s_pWvwData->szAppName, MB_ICONERROR );

      return DefWindowProc( hWnd, message, wParam, lParam );
   }

   OldProc = GetControlProc( usWinNum, WVW_CONTROL_COMBOBOX, hWnd );
   if( OldProc == NULL )
   {
      MessageBox( NULL, TEXT( "Failed GetControlProc" ),
                  s_pWvwData->szAppName, MB_ICONERROR );

      return DefWindowProc( hWnd, message, wParam, lParam );
   }

   switch( message )
   {

      case WM_KEYDOWN:
      case WM_SYSKEYDOWN:
      {
         BOOL bAlt   = GetKeyState( VK_MENU ) & 0x8000;
         BOOL bCtrl  = GetKeyState( VK_CONTROL ) & 0x8000;
         BOOL bShift = GetKeyState( VK_SHIFT ) & 0x8000;
         int  c      = ( int ) wParam;
         BOOL bDropped;

         if( ! hb_gt_wvwBufferedKey( ( LONG ) wParam ) )
            break;

         bDropped = SendMessage( ( HWND ) hWnd,
                                 CB_GETDROPPEDSTATE,
                                 ( WPARAM ) 0,
                                 ( LPARAM ) 0
                                 );

         if( bKbdType == WVW_CB_KBD_STANDARD )
         {

            switch( c )
            {

               case VK_F4:
                  if( bAlt )
                  {
                     SetFocus( hWndParent );
                     PostMessage( hWndParent, message, wParam, lParam );
                     return 0;
                  }
                  break;

               case VK_ESCAPE:
                  if( ! bCtrl && ! bAlt && ! bShift && ! bDropped )
                  {
                     SetFocus( hWndParent );
                     PostMessage( hWndParent, message, wParam, lParam );
                     return 0;
                  }
                  break;

               case VK_TAB:
                  if( ! bCtrl && ! bAlt )
                  {
                     SetFocus( hWndParent );
                     PostMessage( hWndParent, message, wParam, lParam );
                     return 0;
                  }
                  break;

               case VK_NEXT:

                  if( bDropped || bAlt || bShift || bCtrl )
                     break;
                  else
                  {

                     if( ! bDropped )
                     {
                        SendMessage( ( HWND ) hWnd,
                                     CB_SHOWDROPDOWN,
                                     ( WPARAM ) TRUE,
                                     ( LPARAM ) 0
                                     );
                        return 0;
                     }
                     else
                     {

                        SetFocus( hWndParent );
                        PostMessage( hWndParent, message, wParam, lParam );
                        return 0;
                     }
                  }

               case VK_RETURN:
                  if( ! bCtrl && ! bAlt && ! bShift && ! bDropped )
                  {
                     SetFocus( hWndParent );
                     PostMessage( hWndParent, message, wParam, lParam );
                     return 0;
                  }
                  break;

               default:
                  break;
            }

            break;

         }     /* WVW_CB_KBD_STANDARD */
         else  /* assume WVW_CB_KBD_CLIPPER */
         {
            switch( c )
            {

               case VK_F4:
                  if( bAlt )
                  {
                     SetFocus( hWndParent );
                     PostMessage( hWndParent, message, wParam, lParam );
                     return 0;
                  }
                  break;

               case VK_RETURN:

                  if( bDropped || bAlt || bShift || bCtrl )
                     break;
                  else
                  {

                     if( ! bDropped )
                     {
                        SendMessage(
                           ( HWND ) hWnd,
                           CB_SHOWDROPDOWN,
                           ( WPARAM ) TRUE,
                           ( LPARAM ) 0
                           );
                        return 0;
                     }
                     else
                     {

                        SetFocus( hWndParent );
                        PostMessage( hWndParent, message, wParam, lParam );
                        return 0;
                     }
                  }

               case VK_ESCAPE:
                  if( bDropped || bAlt || bShift || bCtrl )
                     break;
                  else
                  {
                     SetFocus( hWndParent );
                     PostMessage( hWndParent, message, wParam, lParam );
                     return 0;
                  }

               case VK_UP:
               case VK_DOWN:
               case VK_RIGHT:
               case VK_LEFT:
               case VK_HOME:
               case VK_END:
               case VK_PRIOR:
               case VK_NEXT:
                  if( bDropped )
                     break;
                  else
                  {
                     SetFocus( hWndParent );
                     PostMessage( hWndParent, message, wParam, lParam );
                     return 0;
                  }

               case VK_TAB:
                  if( ! bCtrl && ! bAlt )
                  {

                     SetFocus( hWndParent );
                     PostMessage( hWndParent, message, wParam, lParam );
                     return 0;
                  }
                  break;
            }
            break;

         }
      }

   }

   return CallWindowProc( ( WNDPROC ) OldProc, hWnd, message, wParam, lParam );
}


/* EDITBOX begins (experimental)                                    */


LRESULT CALLBACK hb_gt_wvwEBProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
   HWND hWndParent = GetParent( hWnd );
   UINT usWinNum;

   UINT    uiEBid;
   WNDPROC OldProc;
   BYTE    bEBType;
   int     iKey;

   if( hWndParent == NULL )
      return DefWindowProc( hWnd, message, wParam, lParam );

   for( usWinNum = 0; usWinNum < s_pWvwData->s_usNumWindows; usWinNum++ )
      if( s_pWvwData->s_pWindows[ usWinNum ]->hWnd == hWndParent )
         break;

   if( usWinNum >= s_pWvwData->s_usNumWindows )
      return DefWindowProc( hWnd, message, wParam, lParam );

   uiEBid = ( UINT ) FindControlId( usWinNum, WVW_CONTROL_EDITBOX, hWnd, &bEBType );

   if( uiEBid == 0 )
   {
      MessageBox( NULL, TEXT( "Failed FindControlId" ),
                  s_pWvwData->szAppName, MB_ICONERROR );

      return DefWindowProc( hWnd, message, wParam, lParam );
   }

   OldProc = GetControlProc( usWinNum, WVW_CONTROL_EDITBOX, hWnd );
   if( OldProc == NULL )
   {
      MessageBox( NULL, TEXT( "Failed GetControlProc" ),
                  s_pWvwData->szAppName, MB_ICONERROR );

      return DefWindowProc( hWnd, message, wParam, lParam );
   }

   iKey = 0;
   switch( message )
   {
      case WM_KEYDOWN:
      case WM_SYSKEYDOWN:
      {
         BOOL bAlt = GetKeyState( VK_MENU ) & 0x8000;
         int  c    = ( int ) wParam;
         switch( c )
         {
            case VK_F1:
               iKey = hb_gt_wvwJustTranslateKey( K_F1, K_SH_F1, K_ALT_F1, K_CTRL_F1 );
               break;
            case VK_F2:
               iKey = hb_gt_wvwJustTranslateKey( K_F2, K_SH_F2, K_ALT_F2, K_CTRL_F2 );
               break;
            case VK_F3:
               iKey = hb_gt_wvwJustTranslateKey( K_F3, K_SH_F3, K_ALT_F3, K_CTRL_F3 );
               break;
            case VK_F4:
               if( bAlt )
               {
                  SetFocus( hWndParent );
                  PostMessage( hWndParent, message, wParam, lParam );
                  return 0;
               }
               else
                  iKey = hb_gt_wvwJustTranslateKey( K_F4, K_SH_F4, K_ALT_F4, K_CTRL_F4 );
               break;
            case VK_F5:
               iKey = hb_gt_wvwJustTranslateKey( K_F5, K_SH_F5, K_ALT_F5, K_CTRL_F5 );
               break;
            case VK_F6:
               iKey = hb_gt_wvwJustTranslateKey( K_F6, K_SH_F6, K_ALT_F6, K_CTRL_F6 );
               break;
            case VK_F7:
               iKey = hb_gt_wvwJustTranslateKey( K_F7, K_SH_F7, K_ALT_F7, K_CTRL_F7 );
               break;
            case VK_F8:
               iKey = hb_gt_wvwJustTranslateKey( K_F8, K_SH_F8, K_ALT_F8, K_CTRL_F8 );
               break;
            case VK_F9:
               iKey = hb_gt_wvwJustTranslateKey( K_F9, K_SH_F9, K_ALT_F9, K_CTRL_F9 );
               break;
            case VK_F10:
               iKey = hb_gt_wvwJustTranslateKey( K_F10, K_SH_F10, K_ALT_F10, K_CTRL_F10 );
               break;
            case VK_F11:
               iKey = hb_gt_wvwJustTranslateKey( K_F11, K_SH_F11, K_ALT_F11, K_CTRL_F11 );
               break;
            case VK_F12:
               iKey = hb_gt_wvwJustTranslateKey( K_F12, K_SH_F12, K_ALT_F12, K_CTRL_F12 );
               break;
         }
         break;
      }

      case WM_CHAR:
      {
         BOOL bCtrl     = GetKeyState( VK_CONTROL ) & 0x8000;
         int  iScanCode = HIWORD( lParam ) & 0xFF;
         int  c         = ( int ) wParam;
         if( bCtrl && iScanCode == 28 )
            iKey = K_CTRL_RETURN;
         else if( bCtrl && ( c >= 1 && c <= 26 ) )
            iKey = K_Ctrl[ c - 1 ];
         else
         {
            switch( c )
            {

               case VK_BACK:
                  iKey = hb_gt_wvwJustTranslateKey( K_BS, K_SH_BS, K_ALT_BS, K_CTRL_BS );
                  break;
               case VK_TAB:
                  iKey = hb_gt_wvwJustTranslateKey( K_TAB, K_SH_TAB, K_ALT_TAB, K_CTRL_TAB );
                  break;
               case VK_RETURN:
                  iKey = hb_gt_wvwJustTranslateKey( K_RETURN, K_SH_RETURN, K_ALT_RETURN, K_CTRL_RETURN );
                  break;
               case VK_ESCAPE:
                  iKey = K_ESC;
                  break;
               default:
                  if( s_pWvwData->s_pWindows[ usWinNum ]->CodePage == OEM_CHARSET )
                     c = hb_wvw_key_ansi_to_oem( c );
                  iKey = c;
                  break;
            }
         }
         break;
      }

      case WM_SYSCHAR:
      {
         int c, iScanCode = HIWORD( lParam ) & 0xFF;
         switch( iScanCode )
         {
            case  2:
               c = K_ALT_1;
               break;
            case  3:
               c = K_ALT_2;
               break;
            case  4:
               c = K_ALT_3;
               break;
            case  5:
               c = K_ALT_4;
               break;
            case  6:
               c = K_ALT_5;
               break;
            case  7:
               c = K_ALT_6;
               break;
            case  8:
               c = K_ALT_7;
               break;
            case  9:
               c = K_ALT_8;
               break;
            case 10:
               c = K_ALT_9;
               break;
            case 11:
               c = K_ALT_0;
               break;
            case 13:
               c = K_ALT_EQUALS;
               break;
            case 14:
               c = K_ALT_BS;
               break;
            case 16:
               c = K_ALT_Q;
               break;
            case 17:
               c = K_ALT_W;
               break;
            case 18:
               c = K_ALT_E;
               break;
            case 19:
               c = K_ALT_R;
               break;
            case 20:
               c = K_ALT_T;
               break;
            case 21:
               c = K_ALT_Y;
               break;
            case 22:
               c = K_ALT_U;
               break;
            case 23:
               c = K_ALT_I;
               break;
            case 24:
               c = K_ALT_O;
               break;
            case 25:
               c = K_ALT_P;
               break;
            case 30:
               c = K_ALT_A;
               break;
            case 31:
               c = K_ALT_S;
               break;
            case 32:
               c = K_ALT_D;
               break;
            case 33:
               c = K_ALT_F;
               break;
            case 34:
               c = K_ALT_G;
               break;
            case 35:
               c = K_ALT_H;
               break;
            case 36:
               c = K_ALT_J;
               break;
            case 37:
               c = K_ALT_K;
               break;
            case 38:
               c = K_ALT_L;
               break;
            case 44:
               c = K_ALT_Z;
               break;
            case 45:
               c = K_ALT_X;
               break;
            case 46:
               c = K_ALT_C;
               break;
            case 47:
               c = K_ALT_V;
               break;
            case 48:
               c = K_ALT_B;
               break;
            case 49:
               c = K_ALT_N;
               break;
            case 50:
               c = K_ALT_M;
               break;
            default:
               c = ( int ) wParam;
               break;
         }
         iKey = c;
         break;
      }

   }

   if( iKey != 0 )
   {
      PHB_ITEM pCodeblock;
      PHB_ITEM hiKey = hb_itemNew( NULL );
      PHB_ITEM pReturn;
      BOOL     bCodeExec = FALSE;

      hb_itemPutNI( hiKey, iKey );

      pCodeblock = hb_itemDoC( "SETKEY", 1, hiKey );
      if( HB_IS_BLOCK( pCodeblock ) )
      {
         SetFocus( hWndParent );
         pReturn = hb_itemDo( pCodeblock, 0 );
         hb_itemRelease( pReturn );
         SetFocus( hWnd );
         bCodeExec = TRUE;
      }
      hb_itemRelease( pCodeblock );
      hb_itemRelease( hiKey );
      if( bCodeExec )
         return 0;
   }

   switch( message )
   {
      case WM_KEYDOWN:
      case WM_SYSKEYDOWN:
      {
         BOOL bAlt   = GetKeyState( VK_MENU ) & 0x8000;
         BOOL bCtrl  = GetKeyState( VK_CONTROL ) & 0x8000;
         BOOL bShift = GetKeyState( VK_SHIFT ) & 0x8000;
         int  c      = ( int ) wParam;
         BOOL bMultiline;

         if( ! hb_gt_wvwBufferedKey( ( LONG ) wParam ) )
            break;

         bMultiline = ( ( bEBType & WVW_EB_MULTILINE ) == WVW_EB_MULTILINE );

         switch( c )
         {

            case VK_F4:
               if( bAlt )
               {
                  SetFocus( hWndParent );
                  PostMessage( hWndParent, message, wParam, lParam );
                  return 0;
               }
               break;

            case VK_RETURN:
               if( bMultiline || bAlt || bShift || bCtrl )
                  break;
               else if( ! bMultiline )
               {
                  SetFocus( hWndParent );
                  PostMessage( hWndParent, message, wParam, lParam );
                  return 0;
               }

            case VK_ESCAPE:

               if( bAlt || bShift || bCtrl )
                  break;
               else
               {
                  SetFocus( hWndParent );
                  PostMessage( hWndParent, message, wParam, lParam );
                  return 0;
               }

            case VK_UP:
            case VK_DOWN:

            case VK_PRIOR:
            case VK_NEXT:
               if( bMultiline )
                  break;
               else
               {
                  SetFocus( hWndParent );
                  PostMessage( hWndParent, message, wParam, lParam );
                  return 0;
               }

            case VK_TAB:
               if( ! bCtrl && ! bAlt )
               {

                  SetFocus( hWndParent );
                  PostMessage( hWndParent, message, wParam, lParam );

                  return 0;
               }
               break;

            case VK_BACK:
               if( ! bAlt )
                  break;
               if( SendMessage(
                      ( HWND ) hWnd,
                      EM_CANUNDO,
                      ( WPARAM ) 0,
                      ( LPARAM ) 0
                      ) )
               {
                  SendMessage(
                     ( HWND ) hWnd,
                     EM_UNDO,
                     ( WPARAM ) 0,
                     ( LPARAM ) 0
                     );
                  return 0;
               }
               break;

         }
         break;

      }

      case WM_CHAR:
      {
         BOOL bCtrl = GetKeyState( VK_CONTROL ) & 0x8000;
         int  c     = ( int ) wParam;
         switch( c )
         {
            case VK_TAB:
               return 0;

            case 1:
               if( bCtrl )
               {
                  SendMessage( ( HWND ) hWnd,
                               EM_SETSEL,
                               ( WPARAM ) 0,
                               ( LPARAM ) -1
                               );
                  return 0;
               }
               break;

            default:
               break;
         }
         break;

      }
   }

   return CallWindowProc( ( WNDPROC ) OldProc, hWnd, message, wParam, lParam );
}


/* EDITBOX ends (experimental)                                       */


/*
 *
 *             Direct WinApi Functions - Prefixed WIN_*()
 *            Original work of Pritpal Bedi on wvtutils.c
 *
 * TODO: should be moved to separate modul. totally independent of GT.
 *
 */
