Files
harbour-core/harbour/source/rtl/gtsln/gtsln.c

1291 lines
39 KiB
C

/*
* $Id$
*/
/*
* Harbour Project source code:
* Video subsystem based on Slang screen library.
*
* Copyright 2000 Marek Paliwoda <paliwoda@inetia.pl>
* www - http://www.harbour-project.org
*
* 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. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://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.
*
*/
/* NOTE: User programs should never call this layer directly! */
/* *********************************************************************** */
#include <slang.h>
/* missing defines in previous versions of Slang - this can not work ! */
#if SLANG_VERSION < 10400
typedef unsigned short SLsmg_Char_Type;
#define SLSMG_EXTRACT_CHAR( x ) ( ( x ) & 0xFF )
#define SLSMG_EXTRACT_COLOR( x ) ( ( ( x ) >> 8 ) & 0xFF )
#define SLSMG_BUILD_CHAR( ch, color ) ( ( ( SLsmg_Char_Type ) ( unsigned char )( ch ) ) | ( ( color ) << 8 ) )
#if SLANG_VERSION < 10308
#define SLSMG_DIAMOND_CHAR 0x04
#define SLSMG_DEGREE_CHAR 0xF8
#define SLSMG_PLMINUS_CHAR 0xF1
#define SLSMG_BULLET_CHAR 0xF9
#define SLSMG_LARROW_CHAR 0x1B
#define SLSMG_RARROW_CHAR 0x1A
#define SLSMG_DARROW_CHAR 0x19
#define SLSMG_UARROW_CHAR 0x18
#define SLSMG_BOARD_CHAR 0xB2
#define SLSMG_BLOCK_CHAR 0xDB
/*
#define SLSMG_BOARD_CHAR 'h'
#define SLSMG_BLOCK_CHAR '0'
*/
#endif
#endif
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include "hbapi.h"
#include "hbapigt.h"
#include "inkey.ch"
/* *********************************************************************** */
/* if we can not manipulate cursor state */
#define SC_UNAVAIL -1
/* to convert DeadKey+letter to national character */
extern unsigned char s_convKDeadKeys[];
extern int hb_gt_Init_Terminal( int phase );
/* to convert characters displayed */
static void hb_gt_build_conv_tabs();
/* extern int _SLsnprintf (char *, unsigned int, char *, ...); */
/* the name of an environmet variable containig a definition of nation chars.*/
/* A definition is a list of pairs of chars. The first char in each pair is */
/* an ASCII key, which should be pressed *after* a "DeadKey" was pressed to */
/* get the nation char, a second in that pair is a corresponding nation char */
unsigned char *hb_NationCharsEnvName = "HRBNATIONCHARS";
/* *********************************************************************** */
static USHORT s_uiDispCount = 0;
static SHORT s_sCursorStyle = SC_NORMAL;
static BOOL s_linuxConsole = FALSE;
static BOOL s_underXTerm = FALSE;
/* indicate if we are currently running a command from system */
static BOOL s_bSuspended = FALSE;
/* standard output */
static int s_iFilenoStdout;
/* to convert high characters (mostly graphics, nation and control chars) */
static SLsmg_Char_Type s_convHighChars[ 256 ];
/* bit indication if char is a nation char - assumes char is 8-bit */
static unsigned char s_IsNationChar[ 128 / 8 ];
/* to convert colors to Clipper mode */
static char * s_colorNames[] =
{
"black" ,
"blue" ,
"green" ,
"cyan" ,
"red" ,
"magenta" ,
"brown" ,
"lightgray" ,
"gray" ,
"brightblue" ,
"brightgreen" ,
"brightcyan" ,
"brightred" ,
"brightmagenta",
"yellow" ,
"white"
};
/* a box drawing hack when nation chars are used */
static BOOL s_bUse_Alt_Char_Hack = FALSE;
/* *********************************************************************** */
volatile BOOL hb_gt_sln_bScreen_Size_Changed = FALSE;
/* window's resize handler */
static void sigwinch_handler( int sig )
{
hb_gt_sln_bScreen_Size_Changed = TRUE;
SLsignal( SIGWINCH, sigwinch_handler );
}
/* *********************************************************************** */
/* I think this function should not be void. It should be BOOL */
void hb_gt_Init( int iFilenoStdin, int iFilenoStdout, int iFilenoStderr )
{
BOOL gt_Inited = FALSE;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Init()"));
s_iFilenoStdout = iFilenoStdout;
s_uiDispCount = 0;
/* read a terminal descripion from a terminfo database */
SLtt_get_terminfo();
/* initialize higher-level Slang routines */
if( SLkp_init() != -1 )
{
/* initialize a terminal stuff and a Slang
keyboard subsystem for the first time */
if( hb_gt_Init_Terminal( 0 ) )
{
/* initialize a screen handling subsytem */
if( SLsmg_init_smg() != -1 )
{
/* install window resize handler */
SLsignal( SIGWINCH, sigwinch_handler );
/* do not indicate USER_BREAK in SLang_Error - ??? */
SLang_Ignore_User_Abort = 1;
/* no default abort procesing */
SLang_set_abort_signal( NULL );
/* NOTE: this is incompatible with CLIPPER
but under Unix we should assume cursor is
visible on startup because we cannot figure
out a current cursor state
*/
/* turn on a cursor visibility */
if( SLtt_set_cursor_visibility( 1 ) == -1 )
s_sCursorStyle = SC_UNAVAIL;
/* an uncertain way to check if we run under linux console */
{
char * tmp = hb_getenv( "TERM" );
s_linuxConsole = tmp && tmp[ 0 ] != '\0' && ( strncmp( tmp, "linux", 5 ) == 0 );
if( tmp )
hb_xfree( ( void * ) tmp );
}
/* an uncertain way to check if we run under xterm */
{
char * tmp = hb_getenv( "TERM" );
s_underXTerm = tmp && tmp[ 0 ] != '\0' && ( strncmp( tmp, "xterm", 5 ) == 0 );
if( tmp )
hb_xfree( ( void * ) tmp );
}
/* NOTE: this driver is implemented in a way that it is
imposible to get intensity/blinking background mode.
The reason is the way Slang is written.
This is incompatible with Clipper. */
SLtt_Blink_Mode = 0;
SLtt_Use_Blink_For_ACS = 0;
SLsmg_Display_Eight_Bit = 160;
/* initialize conversion tables */
hb_gt_build_conv_tabs();
/* ensure we are in a normal chars set */
SLtt_set_alt_char_set( 0 );
/* NOTE: due to a work of a Slang library which does not
prepare its internal screen buffer properly, a screen
must be cleared before normal work. This is not
compatible with Clipper */
SLsmg_cls();
SLsmg_gotorc( 0, 0 );
SLsmg_refresh();
gt_Inited = TRUE;
}
}
}
hb_mouse_Init();
if( ! gt_Inited )
{
char *errmsg = '\r'+'\n'+"Internal error : screen driver initialization failure"+'\r'+'\n'+( char )0;
/* something went wrong - restore default settings */
SLang_reset_tty();
/* TODO: a standard Harbour error should be generated here ! */
write( iFilenoStderr, errmsg , strlen( errmsg ) );
exit( 20 );
}
}
/* *********************************************************************** */
void hb_gt_Exit( void )
{
char *escstr;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Exit()"));
hb_mouse_Exit();
/* NOTE: This is incompatible with Clipper - on exit leave a cursor visible */
if( s_sCursorStyle != SC_UNAVAIL )
hb_gt_SetCursorStyle( SC_NORMAL );
SLsmg_refresh();
SLsmg_reset_smg();
SLang_reset_tty();
/* restore a standard bell frequency and duration */
if( s_linuxConsole )
{
escstr = "\033[10]";
write( s_iFilenoStdout, escstr, strlen( escstr ) );
escstr = "\033[11]";
write( s_iFilenoStdout, escstr, strlen( escstr ) );
}
}
/* *********************************************************************** */
USHORT hb_gt_GetScreenWidth( void )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_GetScreenWidth()"));
return SLtt_Screen_Cols;
}
/* *********************************************************************** */
USHORT hb_gt_GetScreenHeight( void )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_GetScreenHeight()"));
return SLtt_Screen_Rows;
}
/* *********************************************************************** */
SHORT hb_gt_Col( void )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Col()"));
return SLsmg_get_column();
}
/* *********************************************************************** */
SHORT hb_gt_Row( void )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Row()"));
return SLsmg_get_row();
}
/* *********************************************************************** */
void hb_gt_SetPos( SHORT iRow, SHORT iCol, SHORT iMethod )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_SetPos(%hd, %hd, %hd)", iRow, iCol, iMethod));
HB_SYMBOL_UNUSED( iMethod );
SLsmg_gotorc( iRow, iCol );
/* SLtt_goto_rc( iRow, iCol ); */
if( s_uiDispCount == 0 )
SLsmg_refresh();
}
/* *********************************************************************** */
BOOL hb_gt_AdjustPos( BYTE * pStr, ULONG ulLen )
{
ULONG ulCount;
USHORT row = SLsmg_get_row();
USHORT col = SLsmg_get_column();
HB_TRACE(HB_TR_DEBUG, ("hb_gt_AdjustPos(%s, %lu)", pStr, ulLen ));
for( ulCount = 0; ulCount < ulLen; ulCount++ )
{
switch( *pStr++ )
{
case HB_CHAR_BEL:
break;
case HB_CHAR_BS:
if( col )
col--;
else
{
col = SLtt_Screen_Cols - 1;
if( row )
row--;
}
break;
case HB_CHAR_LF:
col = 0;
/* This is a hack. Out<xxx>() is done outside Slang and
it can't be tracked currently by Slang. This should
be changed in console.c */
SLtt_write_string( "\r" );
if( row < SLtt_Screen_Rows - 1 )
row++;
break;
case HB_CHAR_CR:
col = 0;
break;
default:
if( col < SLtt_Screen_Cols - 1 )
col++;
else
{
col = 0;
if( row < SLtt_Screen_Rows - 1 )
row++;
}
}
}
hb_gt_SetPos( row, col, HB_GT_SET_POS_AFTER );
return TRUE;
}
/* *********************************************************************** */
USHORT hb_gt_GetCursorStyle( void )
{
/* TODO: What shape is the cursor? */
HB_TRACE(HB_TR_DEBUG, ("hb_gt_GetCursorStyle()"));
/* if we don't know a cursor state - assume visible */
if( s_sCursorStyle == SC_UNAVAIL )
return( SC_NORMAL );
return( s_sCursorStyle );
}
/* *********************************************************************** */
void hb_gt_SetCursorStyle( USHORT uiStyle )
{
/* keyseq to define cursor shape under linux console */
static char cursDefseq[] = { 27, '[', '?', '1', 'c', 0 };
HB_TRACE(HB_TR_DEBUG, ("hb_gt_SetCursorStyle(%hu)", uiStyle));
/* TODO: How to set the shape of the cursor on terminals ? */
if( s_sCursorStyle == SC_UNAVAIL )
return;
if( ( s_sCursorStyle >= SC_NONE ) && ( s_sCursorStyle <= SC_SPECIAL2 ) )
{
s_sCursorStyle = uiStyle;
SLtt_set_cursor_visibility( s_sCursorStyle != SC_NONE );
#ifdef __linux__
/* NOTE: cursor apearence works only under linux console */
if( s_linuxConsole )
{
switch( uiStyle )
{
case SC_NONE:
cursDefseq[ 3 ] = '1';
break;
case SC_NORMAL:
cursDefseq[ 3 ] = '2';
break;
case SC_INSERT:
cursDefseq[ 3 ] = '4';
break;
case SC_SPECIAL1:
cursDefseq[ 3 ] = '8';
break;
case SC_SPECIAL2:
/* TODO: find a proper sequqnce to set a cursor
to SC_SPECIAL2 under Linux console */
cursDefseq[ 3 ] = '4';
break;
}
SLtt_write_string( cursDefseq );
}
#endif
if( s_uiDispCount == 0 )
/* SLsmg_refresh(); */
SLtt_flush_output();
}
}
/* *********************************************************************** */
BOOL hb_gt_IsColor( void )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_IsColor()"));
return SLtt_Use_Ansi_Colors;
}
/* *********************************************************************** */
static void hb_gt_xPutch( USHORT uiRow, USHORT uiCol, BYTE byAttr, BYTE byChar )
{
unsigned char Pos, Msk;
SLsmg_Char_Type SLchar, SLattr;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_xPutch(%hu, %hu, %d, %i)", uiRow, uiCol, (int) byAttr, byChar));
Pos = ( unsigned char ) ( ( byChar & 0x7F ) >> 3 );
Msk = ( unsigned char ) ( 1 << ( byChar & 0x07 ) );
/* build a Slang converted attribute - note we are clearing a high bit of color */
SLattr = ( SLsmg_Char_Type )( ( ( byAttr - 7 ) & 0x7F ) << 8 );
/* this hack turns on Normal Char Set when we should draw a nation char. */
if( s_bUse_Alt_Char_Hack || !( s_IsNationChar[ Pos ] & Msk ) )
SLchar = s_convHighChars[ byChar ] | SLattr; /* build a Slang char */
else
SLchar = ( SLsmg_Char_Type )byChar | SLattr; /* build a Slang char */
SLsmg_gotorc( uiRow, uiCol );
SLsmg_write_raw( &SLchar, 1 );
}
/* *********************************************************************** */
void hb_gt_Puts( USHORT uiRow, USHORT uiCol, BYTE byAttr, BYTE * pbyStr, ULONG ulLen )
{
ULONG i;
BYTE byChar;
unsigned char Pos, Msk;
SLsmg_Char_Type SLchar, SLattr, *pScr;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Puts(%hu, %hu, %d, %p, %lu)", uiRow, uiCol, (int) byAttr, pbyStr, ulLen));
pScr = ( SLsmg_Char_Type * ) hb_xgrab( ( ulLen + 1 ) * sizeof( SLsmg_Char_Type ) );
/* build a Slang converted attribute - note we are clearing a high bit of color */
SLattr = ( SLsmg_Char_Type )( ( ( byAttr - 7 ) & 0x7F ) << 8 );
for( i = 0; i < ulLen; i++ )
{
/* a next char to process */
byChar = *pbyStr++;
Pos = ( unsigned char ) ( ( byChar & 0x7F ) >> 3 );
Msk = ( unsigned char ) ( 1 << ( byChar & 0x07 ) );
/* this hack turns on Normal Char Set when we should draw a nation char. */
if( s_bUse_Alt_Char_Hack || !( s_IsNationChar[ Pos ] & Msk ) )
SLchar = s_convHighChars[ byChar ] | SLattr; /* build a Slang char */
else
SLchar = ( SLsmg_Char_Type )byChar | SLattr; /* build a Slang char */
*( pScr + i ) = SLchar;
}
SLsmg_gotorc( uiRow, uiCol );
if( ulLen > 0 )
SLsmg_write_raw( pScr, ulLen );
/* NOTE : enable this if problems with cursor positioning occur */
/* hb_gt_SetPos( uiRow, uiCol + ulLen, HB_GT_SET_POS_AFTER ); */
hb_xfree( ( BYTE * )pScr );
}
/* *********************************************************************** */
int hb_gt_RectSize( USHORT rows, USHORT cols )
{
return rows * cols * sizeof( SLsmg_Char_Type );
}
/* *********************************************************************** */
void hb_gt_GetText( USHORT uiTop, USHORT uiLeft, USHORT uiBottom, USHORT uiRight, BYTE * pbyDst )
{
int Cols;
USHORT usSavRow = SLsmg_get_row();
USHORT usSavCol = SLsmg_get_column();
SLsmg_Char_Type * pBuf = ( SLsmg_Char_Type * ) pbyDst;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_GetText(%hu, %hu, %hu, %hu, %p)", uiTop, uiLeft, uiBottom, uiRight, pbyDst));
Cols = uiRight - uiLeft + 1;
while( uiTop <= uiBottom )
{
SLsmg_gotorc( uiTop, uiLeft );
SLsmg_read_raw( pBuf, Cols );
pBuf += Cols;
++uiTop;
}
SLsmg_gotorc( usSavRow, usSavCol );
}
/* *********************************************************************** */
void hb_gt_PutText( USHORT uiTop, USHORT uiLeft, USHORT uiBottom, USHORT uiRight, BYTE * pbySrc )
{
int Cols;
USHORT usSavRow = SLsmg_get_row();
USHORT usSavCol = SLsmg_get_column();
SLsmg_Char_Type * pBuf = ( SLsmg_Char_Type * ) pbySrc;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_PutText(%hu, %hu, %hu, %hu, %p)", uiTop, uiLeft, uiBottom, uiRight, pbySrc));
Cols = uiRight - uiLeft + 1;
while( uiTop <= uiBottom )
{
SLsmg_gotorc( uiTop, uiLeft );
SLsmg_write_raw( pBuf, Cols );
pBuf += Cols;
++uiTop;
}
hb_gt_SetPos( usSavRow, usSavCol, HB_GT_SET_POS_AFTER );
}
/* *********************************************************************** */
void hb_gt_SetAttribute( USHORT uiTop, USHORT uiLeft, USHORT uiBottom, USHORT uiRight, BYTE byAttr )
{
int Rows, Cols;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_SetAttribute(%hu, %hu, %hu, %hu, %d)", uiTop, uiLeft, uiBottom, uiRight, (int) byAttr));
Rows = uiBottom - uiTop + 1;
Cols = uiRight - uiLeft + 1;
/* note: we are clearing a high bit of color */
SLsmg_set_color_in_region( ( byAttr - 7 ) & 0x7F, uiTop, uiLeft, Rows, Cols );
if( s_uiDispCount == 0 )
SLsmg_refresh();
}
/* *********************************************************************** */
/* NOTE : hb_gt_Scroll is based on gtdos.c, but changed to get scroll
worked well when scrolling horizontally. Clipper behaves
strange here. */
void hb_gt_Scroll( USHORT usTop, USHORT usLeft, USHORT usBottom, USHORT usRight, BYTE byAttr, SHORT iRows, SHORT iCols )
{
SHORT usSaveRow, usSaveCol;
USHORT uiSize;
int iLength = ( usRight - usLeft ) + 1;
int iCount, iColOld, iColNew, iColSize;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Scroll(%hu, %hu, %hu, %hu, %d, %hd, %hd)", usTop, usLeft, usBottom, usRight, (int) byAttr, iRows, iCols));
if( hb_gtRectSize( usTop, usLeft, usBottom, usRight, &uiSize ) == 0 )
{
unsigned char * fpBlank = ( unsigned char * ) hb_xgrab( iLength );
unsigned char * fpBuff = ( unsigned char * ) hb_xgrab( iLength * sizeof( SLsmg_Char_Type ) );
memset( fpBlank, ' ', iLength );
iColOld = iColNew = usLeft;
if( iCols >= 0 )
{
iColOld += iCols;
iColSize = ( int ) ( usRight - usLeft );
iColSize -= iCols;
}
else
{
iColNew -= iCols;
iColSize = ( int ) ( usRight - usLeft );
iColSize += iCols;
}
/* this is probably not compatible with Clipper */
hb_gt_DispBegin();
hb_gtGetPos( &usSaveRow, &usSaveCol );
for( iCount = ( iRows >= 0 ? usTop : usBottom );
( iRows >= 0 ? iCount <= usBottom : iCount >= usTop );
( iRows >= 0 ? iCount++ : iCount-- ) )
{
int iRowPos = iCount + iRows;
/* Read the text to be scrolled into the current row */
if( ( iRows || iCols ) && iRowPos <= usBottom && iRowPos >= usTop )
hb_gt_GetText( iRowPos, iColOld, iRowPos, iColOld + iColSize, fpBuff );
/* Blank the scroll region in the current row */
hb_gt_Puts( iCount, usLeft, byAttr, fpBlank, iLength );
/* Write the scrolled text to the current row */
if( ( iRows || iCols ) && iRowPos <= usBottom && iRowPos >= usTop )
hb_gt_PutText( iCount, iColNew, iCount, iColNew + iColSize, fpBuff );
}
hb_xfree( fpBlank );
hb_xfree( fpBuff );
/* hb_gtSetPos( usSaveRow, usSaveCol ); */
SLsmg_gotorc( usSaveRow, usSaveCol );
/* this is probably not compatible with Clipper */
hb_gt_DispEnd();
}
}
/* *********************************************************************** */
void hb_gt_DispBegin( void )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_DispBegin()"));
++s_uiDispCount;
}
/* *********************************************************************** */
void hb_gt_DispEnd()
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_DispEnd()"));
/* is this compatible with Clipper ? */
if( s_uiDispCount > 0 )
--s_uiDispCount;
if( s_uiDispCount == 0 )
SLsmg_refresh();
}
/* *********************************************************************** */
BOOL hb_gt_SetMode( USHORT uiRows, USHORT uiCols )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_SetMode(%hu, %hu)", uiRows, uiCols));
HB_SYMBOL_UNUSED( uiRows );
HB_SYMBOL_UNUSED( uiCols );
/* TODO: How to change the size of the screen? */
return FALSE;
}
/* *********************************************************************** */
BOOL hb_gt_GetBlink()
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_GetBlink()"));
/* TODO: current implementation disables blinking/intensity */
return FALSE;
}
/* *********************************************************************** */
void hb_gt_SetBlink( BOOL bBlink )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_SetBlink(%d)", (int) bBlink));
/* TODO: current implementation disables blinking/intensity */
HB_SYMBOL_UNUSED( bBlink );
}
/* *********************************************************************** */
void hb_gt_Tone( double dFrequency, double dDuration )
{
char escstr[ 64 ];
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Tone(%lf, %lf)", dFrequency, dDuration));
/* TODO: Implement this for other consoles than linux ? */
dFrequency = HB_MIN( HB_MAX( 0.0, dFrequency ), 32767.0 );
/* dDuration = dDuration * 1000.0 / 18.2; */ /* clocks */
if( s_linuxConsole )
{
snprintf( escstr, 63, "\033[10;%hd]", ( int )dFrequency );
SLtt_write_string( escstr );
snprintf( escstr, 63, "\033[11;%hd]", ( int )( dDuration * 1000.0 / 18.2 ) );
SLtt_write_string( escstr );
SLtt_flush_output();
}
SLtt_beep();
if( s_linuxConsole )
{
/* NOTE : the code below is adapted from gtdos.c/hb_gt_Tone() */
dDuration *= 1800;
while( dDuration > 0.0 )
{
USHORT temp = ( USHORT ) HB_MIN( HB_MAX( 0, dDuration ), 1000 );
static struct timespec nanosecs;
dDuration -= temp;
if( temp <= 0 )
/* Ensure that the loop gets terminated when
only a fraction of the delay time remains. */
dDuration = -1.0;
else
{
hb_idleState();
nanosecs.tv_sec = 0;
nanosecs.tv_nsec = temp * 10;
nanosleep( &nanosecs, NULL );
}
}
}
}
/* *********************************************************************** */
char * hb_gt_Version( void )
{
return "Harbour Terminal: Slang";
}
/* *********************************************************************** */
USHORT hb_gt_DispCount()
{
return s_uiDispCount;
}
/* *********************************************************************** */
void hb_gt_Replicate( USHORT uiRow, USHORT uiCol, BYTE byAttr, BYTE byChar, ULONG ulLen )
{
ULONG i;
unsigned char Pos, Msk;
SLsmg_Char_Type SLchar, SLattr, * pScr;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Replicate(%hu, %hu, %i, %i, %lu)", uiRow, uiCol, byAttr, byChar, ulLen));
pScr = ( SLsmg_Char_Type * ) hb_xgrab( ( ulLen + 1 ) * sizeof( SLsmg_Char_Type ) );
Pos = ( unsigned char ) ( ( byChar & 0x7F ) >> 3 );
Msk = ( unsigned char ) ( 1 << ( byChar & 0x07 ) );
/* build a Slang converted attribute - note we are clearing a high bit of color */
SLattr = ( SLsmg_Char_Type )( ( ( byAttr - 7 ) & 0x7F ) << 8 );
/* this hack turns on Normal Char Set when we should draw a nation char. */
if( s_bUse_Alt_Char_Hack || !( s_IsNationChar[ Pos ] & Msk ) )
SLchar = s_convHighChars[ byChar ] | SLattr; /* build a Slang char */
else
SLchar = ( SLsmg_Char_Type )byChar | SLattr; /* build a Slang char */
for( i = 0; i < ulLen; i++ )
*( pScr + i ) = SLchar;
SLsmg_gotorc( uiRow, uiCol );
if( ulLen > 0 )
{
SLsmg_write_raw( pScr, ulLen );
/* this should not be needed here. hb_gtRepChar() should set this for us */
hb_gt_SetPos( uiRow, uiCol + ulLen, HB_GT_SET_POS_AFTER );
}
hb_xfree( ( BYTE * ) pScr );
}
/* *********************************************************************** */
USHORT hb_gt_Box( SHORT Top, SHORT Left, SHORT Bottom, SHORT Right,
BYTE * szBox, BYTE byAttr )
{
USHORT ret = 1;
SHORT Row;
SHORT Col;
SHORT Height;
SHORT Width;
/* a box drawing hack */
BOOL SaveUseAltChar = s_bUse_Alt_Char_Hack;
/* a box drawing hack */
s_bUse_Alt_Char_Hack = TRUE;
if( Left >= 0 || Left < hb_gt_GetScreenWidth()
|| Right >= 0 || Right < hb_gt_GetScreenWidth()
|| Top >= 0 || Top < hb_gt_GetScreenHeight()
|| Bottom >= 0 || Bottom < hb_gt_GetScreenHeight() )
{
/* Ensure that box is drawn from top left to bottom right. */
if( Top > Bottom )
{
SHORT tmp = Top;
Top = Bottom;
Bottom = tmp;
}
if( Left > Right )
{
SHORT tmp = Left;
Left = Right;
Right = tmp;
}
/* Draw the box or line as specified */
Height = Bottom - Top + 1;
Width = Right - Left + 1;
hb_gt_DispBegin();
if( Height > 1 && Width > 1 && Top >= 0 && Top < hb_gt_GetScreenHeight() && Left >= 0 && Left < hb_gt_GetScreenWidth() )
hb_gt_xPutch( Top, Left, byAttr, szBox[ 0 ] ); /* Upper left corner */
Col = ( Height > 1 ? Left + 1 : Left );
if(Col < 0 )
{
Width += Col;
Col = 0;
}
if( Right >= hb_gt_GetScreenWidth() )
{
Width -= Right - hb_gt_GetScreenWidth();
}
if( Col <= Right && Col < hb_gt_GetScreenWidth() && Top >= 0 && Top < hb_gt_GetScreenHeight() )
hb_gt_Replicate( Top, Col, byAttr, szBox[ 1 ], Width + ( (Right - Left) > 1 ? -2 : 0 ) ); /* Top line */
if( Height > 1 && (Right - Left) > 1 && Right < hb_gt_GetScreenWidth() && Top >= 0 && Top < hb_gt_GetScreenHeight() )
hb_gt_xPutch( Top, Right, byAttr, szBox[ 2 ] ); /* Upper right corner */
if( szBox[ 8 ] && Height > 2 && Width > 2 )
{
for( Row = Top + 1; Row < Bottom; Row++ )
{
if( Row >= 0 && Row < hb_gt_GetScreenHeight() )
{
Col = Left;
if( Col < 0 )
Col = 0; /* The width was corrected earlier. */
else
hb_gt_xPutch( Row, Col++, byAttr, szBox[ 7 ] ); /* Left side */
hb_gt_Replicate( Row, Col, byAttr, szBox[ 8 ], Width - 2 ); /* Fill */
if( Right < hb_gt_GetScreenWidth() )
hb_gt_xPutch( Row, Right, byAttr, szBox[ 3 ] ); /* Right side */
}
}
}
else
{
for( Row = ( Width > 1 ? Top + 1 : Top ); Row < ( (Right - Left ) > 1 ? Bottom : Bottom + 1 ); Row++ )
{
if( Row >= 0 && Row < hb_gt_GetScreenHeight() )
{
if( Left >= 0 && Left < hb_gt_GetScreenWidth() )
hb_gt_xPutch( Row, Left, byAttr, szBox[ 7 ] ); /* Left side */
if( ( Width > 1 || Left < 0 ) && Right < hb_gt_GetScreenWidth() )
hb_gt_xPutch( Row, Right, byAttr, szBox[ 3 ] ); /* Right side */
}
}
}
if( Height > 1 && Width > 1 )
{
if( Left >= 0 && Bottom < hb_gt_GetScreenHeight() )
hb_gt_xPutch( Bottom, Left, byAttr, szBox[ 6 ] ); /* Bottom left corner */
Col = Left + 1;
if( Col < 0 )
Col = 0; /* The width was corrected earlier. */
if( Col <= Right && Bottom < hb_gt_GetScreenHeight() )
hb_gt_Replicate( Bottom, Col, byAttr, szBox[ 5 ], Width - 2 ); /* Bottom line */
if( Right < hb_gt_GetScreenWidth() && Bottom < hb_gt_GetScreenHeight() )
hb_gt_xPutch( Bottom, Right, byAttr, szBox[ 4 ] ); /* Bottom right corner */
}
hb_gt_DispEnd();
/* NOTE : enable this if problems with cursor positioning occur */
/* SLsmg_gotorc( uiTop + 1, uiLeft + 1 ); */
hb_gt_DispEnd();
/* a box drawing hack */
s_bUse_Alt_Char_Hack = SaveUseAltChar;
ret = 0;
}
return ret;
}
/* *********************************************************************** */
USHORT hb_gt_BoxD( SHORT Top, SHORT Left, SHORT Bottom, SHORT Right, BYTE * pbyFrame, BYTE byAttr )
{
return hb_gt_Box( Top, Left, Bottom, Right, pbyFrame, byAttr );
}
/* *********************************************************************** */
USHORT hb_gt_BoxS( SHORT Top, SHORT Left, SHORT Bottom, SHORT Right, BYTE * pbyFrame, BYTE byAttr )
{
return hb_gt_Box( Top, Left, Bottom, Right, pbyFrame, byAttr );
}
/* *********************************************************************** */
USHORT hb_gt_HorizLine( SHORT Row, SHORT Left, SHORT Right, BYTE byChar, BYTE byAttr )
{
USHORT ret = 1;
BOOL SaveUseAltChar = s_bUse_Alt_Char_Hack;
if( Row >= 0 && Row < hb_gt_GetScreenHeight() )
{
/* a box drawing hack */
s_bUse_Alt_Char_Hack = TRUE;
if( Left < 0 )
Left = 0;
else if( Left >= hb_gt_GetScreenWidth() )
Left = hb_gt_GetScreenWidth() - 1;
if( Right < 0 )
Right = 0;
else if( Right >= hb_gt_GetScreenWidth() )
Right = hb_gt_GetScreenWidth() - 1;
if( Left < Right )
hb_gt_Replicate( Row, Left, byAttr, byChar, Right - Left + 1 );
else
hb_gt_Replicate( Row, Right, byAttr, byChar, Left - Right + 1 );
/* a box drawing hack */
s_bUse_Alt_Char_Hack = SaveUseAltChar;
ret = 0;
}
return ret;
}
/* *********************************************************************** */
USHORT hb_gt_VertLine( SHORT Col, SHORT Top, SHORT Bottom, BYTE byChar, BYTE byAttr )
{
USHORT ret = 1;
USHORT uRow;
BOOL SaveUseAltChar = s_bUse_Alt_Char_Hack;
if( Col >= 0 && Col < hb_gt_GetScreenWidth() )
{
/* a box drawing hack */
s_bUse_Alt_Char_Hack = TRUE;
if( Top < 0 )
Top = 0;
else if( Top >= hb_gt_GetScreenHeight() )
Top = hb_gt_GetScreenHeight() - 1;
if( Bottom < 0 )
Bottom = 0;
else if( Bottom >= hb_gt_GetScreenHeight() )
Bottom = hb_gt_GetScreenHeight() - 1;
if( Top <= Bottom )
uRow = Top;
else
{
uRow = Bottom;
Bottom = Top;
}
while( uRow <= Bottom )
hb_gt_xPutch( uRow++, Col, byAttr, byChar );
/* a box drawing hack */
s_bUse_Alt_Char_Hack = SaveUseAltChar;
hb_gt_SetPos( Bottom + 1, Col, HB_GT_SET_POS_AFTER );
ret = 0;
}
return ret;
}
/* *********************************************************************** */
/* NOTE: these two are for prepare Slang to temporary
finish its work. They should be called from run.c. */
/* *********************************************************************** */
BOOL hb_gt_Suspend()
{
if( ! s_bSuspended )
{
if( SLsmg_suspend_smg() != -1 )
{
SLang_reset_tty();
s_bSuspended = TRUE;
}
}
return s_bSuspended;
}
/* *********************************************************************** */
BOOL hb_gt_Resume()
{
if( s_bSuspended &&
SLsmg_resume_smg() != -1 &&
hb_gt_Init_Terminal( 1 ) != -1
)
{
SLsmg_refresh(); /* reinitialize a terminal */
s_bSuspended = FALSE;
}
return( !s_bSuspended );
}
/* *********************************************************************** */
BOOL hb_gt_PreExt()
{
SLsmg_refresh();
return TRUE;
}
/* *********************************************************************** */
BOOL hb_gt_PostExt()
{
return TRUE;
}
/* *********************************************************************** */
static void hb_gt_build_conv_tabs()
{
int i, fg, bg, len;
unsigned char * p, ch;
SLsmg_Char_Type SLch;
/* COMPATIBILITY: Slang uses bit 0x8000 as an alternate
char mask so it leaves us only 128 possible fgbg colors.
(see Notes in Slang sources). This is incompatible with
Clipper. Slang uses color 0 as a default color so we
rotate color table by 7 to set color 0 to be color 7 */
for( i = 7; i < 256 + 7; i++ )
{
fg = ( i & 0x0F );
bg = ( i >> 4 ) & 0x07; /* bit 7 is a blinking attribute - not used here */
/* rotate by 7 : 0->249, 1->250,...6->255, 7->0, ... 255->248 */
ch = ( unsigned char ) ( i - 7 );
SLtt_set_color( ( int )ch, ( char * ) NULL, s_colorNames[ fg ], s_colorNames[ bg ] );
/*
fprintf( stderr, "%3d %3d %3d %8lx %s %s\n", ch, i+7, i,
SLtt_get_color_object( ( int )ch ), s_colorNames[ fg ],
s_colorNames[ bg ] );
*/
}
/* build a conversion chars table */
for( i = 0; i < 32; i++ )
/* under Unix control-chars are not visible in a general meaning */
s_convHighChars[ i ] = ( SLsmg_Char_Type ) '.';
/* s_convHighChars[ i ] = ( ( SLsmg_Char_Type ) i ) | 0x8000; */
for( i = 32; i < 128; i++ )
/* lower 128-32 chars are from normal char set */
s_convHighChars[ i ] = ( SLsmg_Char_Type ) i;
for( i = 128; i < 256; i++ )
/* upper 128 chars are from alternate char set */
s_convHighChars[ i ] = ( ( SLsmg_Char_Type ) i ) | 0x8000;
/* init an alternate chars table */
if( ( p = SLtt_Graphics_Char_Pairs ) )
{
len = strlen( p );
/* alternate char set should be even */
if( ( len != ( ( len / 2 ) * 2 ) ) && ( len > 0 ) )
--len;
for( i = 0; i < len / 2; i++ )
{
ch = *p++;
ch &= 0x7F; /* is this really nessecary ? */
SLch = ( ( SLsmg_Char_Type )( *p ) ) | 0x8000;
switch( ch )
{
case SLSMG_HLINE_CHAR : s_convHighChars[ 196 ] = SLch; break;
case SLSMG_VLINE_CHAR : s_convHighChars[ 179 ] = SLch; break;
case SLSMG_ULCORN_CHAR : s_convHighChars[ 218 ] = SLch; break;
case SLSMG_URCORN_CHAR : s_convHighChars[ 191 ] = SLch; break;
case SLSMG_LLCORN_CHAR : s_convHighChars[ 192 ] = SLch; break;
case SLSMG_LRCORN_CHAR : s_convHighChars[ 217 ] = SLch; break;
case SLSMG_CKBRD_CHAR : s_convHighChars[ 176 ] = SLch; break;
case SLSMG_RTEE_CHAR : s_convHighChars[ 180 ] = SLch; break;
case SLSMG_LTEE_CHAR : s_convHighChars[ 195 ] = SLch; break;
case SLSMG_UTEE_CHAR : s_convHighChars[ 194 ] = SLch; break;
case SLSMG_DTEE_CHAR : s_convHighChars[ 193 ] = SLch; break;
case SLSMG_PLUS_CHAR : s_convHighChars[ 197 ] = SLch; break;
/*
case SLSMG_DEGREE_CHAR; : s_convHighChars[ ] = SLch; break;
case SLSMG_PLMINUS_CHAR : s_convHighChars[ ] = SLch; break;
case SLSMG_BULLET_CHAR : s_convHighChars[ ] = SLch; break;
*/
case SLSMG_DIAMOND_CHAR : s_convHighChars[ 04 ] = SLch;
break;
case SLSMG_LARROW_CHAR : s_convHighChars[ 17 ] = SLch;
s_convHighChars[ 27 ] = SLch;
break;
case SLSMG_RARROW_CHAR : s_convHighChars[ 16 ] = SLch;
s_convHighChars[ 26 ] = SLch;
break;
case SLSMG_DARROW_CHAR : s_convHighChars[ 25 ] = SLch;
s_convHighChars[ 31 ] = SLch;
break;
case SLSMG_UARROW_CHAR : s_convHighChars[ 24 ] = SLch;
s_convHighChars[ 30 ] = SLch;
break;
case SLSMG_BOARD_CHAR : s_convHighChars[ 178 ] = SLch;
break;
case SLSMG_BLOCK_CHAR : s_convHighChars[ 219 ] = SLch;
break;
}
++p;
}
}
/* QUESTION: do we have double, single-double, ... frames under xterm ? */
if( s_underXTerm )
{
/* frames of all Clipper type are _B_SINBLE under xterm */
s_convHighChars[ 205 ] = s_convHighChars[ 196 ];
s_convHighChars[ 186 ] = s_convHighChars[ 179 ];
s_convHighChars[ 201 ] = s_convHighChars[ 218 ];
s_convHighChars[ 214 ] = s_convHighChars[ 218 ];
s_convHighChars[ 213 ] = s_convHighChars[ 218 ];
s_convHighChars[ 187 ] = s_convHighChars[ 191 ];
s_convHighChars[ 183 ] = s_convHighChars[ 191 ];
s_convHighChars[ 184 ] = s_convHighChars[ 191 ];
s_convHighChars[ 200 ] = s_convHighChars[ 192 ];
s_convHighChars[ 211 ] = s_convHighChars[ 192 ];
s_convHighChars[ 212 ] = s_convHighChars[ 192 ];
s_convHighChars[ 188 ] = s_convHighChars[ 217 ];
s_convHighChars[ 189 ] = s_convHighChars[ 217 ];
s_convHighChars[ 190 ] = s_convHighChars[ 217 ];
s_convHighChars[ 185 ] = s_convHighChars[ 118 ];
s_convHighChars[ 204 ] = s_convHighChars[ 195 ];
s_convHighChars[ 203 ] = s_convHighChars[ 194 ];
s_convHighChars[ 202 ] = s_convHighChars[ 193 ];
s_convHighChars[ 206 ] = s_convHighChars[ 197 ];
}
/* init national chars */
p = hb_getenv( hb_NationCharsEnvName );
if( p && p[ 0 ] != '\0' )
{
unsigned char Pos, Msk;
len = strlen( p );
/* a len of definition of National chars should be even */
if( ( len != ( ( len / 2 ) * 2 ) ) && ( len > 0 ) )
--len;
/* no more than 128 National chars are allowed */
if( len > 256 ) len = 256;
/* the first element contains a number of Dead keys defined in an ENVAR */
s_convKDeadKeys[ 0 ] = ( unsigned char ) ( len / 2 );
for( i = 0; i < len / 2; i++ )
{
ch = *p++;
s_convKDeadKeys[ 2 * i + 1 ] = ch;
s_convKDeadKeys[ 2 * i + 2 ] = *p;
Pos = ( unsigned char ) ( ( *p & 0x7F ) >> 3 );
Msk = ( unsigned char ) ( 1 << ( *p & 0x07 ) );
s_IsNationChar[ Pos ] |= Msk;
++p;
}
/*
for( i=0; i <= ( ( int ) s_convKDeadKeys[ 0 ] ) * 2; i++ )
fprintf( stderr, "%3d %c\r\n", i, s_convKDeadKeys[ i ] );
ch=getc( stdin );
*/
}
if( p )
hb_xfree( ( void * ) p );
}
/* *********************************************************************** */