#ifdef INCRCSDATA
static char RCSid[]="$Id: gclient.c,v 1.15 1998/03/22 22:34:21 drd Exp $" ;
#endif
/****************************************************************************
PROGRAM: Gnupmdrv
MODULE: gclient.c
This file contains the client window procedures for Gnupmdrv
****************************************************************************/
/* PM driver for GNUPLOT */
/*[
* Copyright 1992, 1993, 1998 Roger Fearick
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* Permission to modify the software is granted, but not the right to
* distribute the complete modified source code. Modifications are to
* be distributed as patches to the released version. Permission to
* distribute binaries produced by compiling modified sources is granted,
* provided you
* 1. distribute the corresponding source modifications from the
* released version in the form of a patch file along with the binaries,
* 2. add special version identification to distinguish your version
* in addition to the base release version number,
* 3. provide your name and address as the primary contact for the
* support of your modified version, and
* 4. retain our contact information in regard to use of the base
* software.
* Permission to distribute the released version of the source code along
* with corresponding source modifications in the form of a patch file is
* granted with same provisions 2 through 4 for binary distributions.
*
* This software is provided "as is" without express or implied warranty
* to the extent permitted by applicable law.
]*/
/*
* AUTHOR
*
* Gnuplot driver for OS/2: Roger Fearick
*
* Send your comments or suggestions to
* info-gnuplot@dartmouth.edu.
* This is a mailing list; to join it send a note to
* majordomo@dartmouth.edu.
* Send bug reports to
* bug-gnuplot@dartmouth.edu.
**/
#define INCL_PM
#define INCL_WIN
#define INCL_SPL
#define INCL_SPLDOSPRINT
#define INCL_WINSTDFONT
#define INCL_DOSMEMMGR
#define INCL_DOSPROCESS
#define INCL_DOSERRORS
#define INCL_DOSFILEMGR
#define INCL_DOSNMPIPES
#define INCL_DOSSESMGR
#define INCL_DOSSEMAPHORES
#define INCL_DOSMISC
#define INCL_DOSQUEUES
#define INCL_WINSWITCHLIST
#include <os2.h>
#include <string.h>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <math.h>
#include <stdlib.h>
#include <unistd.h>
#include <process.h>
#include <signal.h>
#include "gnupmdrv.h"
/*==== g l o b a l d a t a ================================================*/
extern char szIPCName[] ; /* name used in IPC with gnuplot */
extern char szIniFile[256] ; /* full path of ini file */
extern int bServer ;
extern int bPersist ;
extern int bEnhanced ;
/*==== l o c a l d a t a ==================================================*/
static long lLineTypes[7] = { LINETYPE_SOLID,
LINETYPE_SHORTDASH,
LINETYPE_DOT,
LINETYPE_DASHDOT,
LINETYPE_LONGDASH,
LINETYPE_DOUBLEDOT,
LINETYPE_DASHDOUBLEDOT } ;
static long lCols[16] = { CLR_BLACK,
CLR_DARKGRAY,
CLR_BLUE,
CLR_RED,
CLR_GREEN,
CLR_CYAN,
CLR_PINK,
CLR_YELLOW,
CLR_DARKBLUE,
CLR_DARKRED,
CLR_DARKGREEN,
CLR_DARKCYAN,
CLR_DARKPINK,
CLR_BROWN,
CLR_PALEGRAY,
CLR_WHITE } ;
static LONG alColourTable[ 16 ] ;
#define GNUBUF 1024 /* buffer for gnuplot commands */
#define PIPEBUF 4096 /* size of pipe buffers */
#define CMDALLOC 4096 /* command buffer allocation increment (ints) */
#define ENVSIZE 2048 /* size of environment */
#define PAUSE_DLG 1 /* pause handled in dialog box */
#define PAUSE_BTN 2 /* pause handled by menu item */
#define PAUSE_GNU 3 /* pause handled by Gnuplot */
#define DEFLW 50
static ULONG ppidGnu=0L ; /* gnuplot pid */
static HPS hpsScreen ; /* screen pres. space */
static int iSeg = 1 ;
static HSWITCH hSwitch = 0 ; /* switching between windows */
static SWCNTRL swGnu ;
static BOOL bLineTypes = FALSE ; // true if use dashed linetypes
BOOL bWideLines ;
static BOOL bColours = TRUE ;
static BOOL bShellPos = FALSE ;
static BOOL bPlotPos = FALSE ;
static BOOL bPopFront = TRUE ;
static BOOL bNewFont = FALSE ;
static BOOL bHorz = TRUE ;
static ULONG ulPlotPos[4] ;
static ULONG ulShellPos[4] ;
static PAUSEDATA pausedata = {sizeof(PAUSEDATA), NULL, NULL} ;
static char szFontNameSize[FONTBUF] ;
static PRQINFO3 infPrinter = { "" } ;
static QPRINT qPrintData = { sizeof(QPRINT), 0.0, 0.0, 1.0, 1.0, 0,
"", "", &infPrinter, 0, NULL } ;
//static HEV semStartSeq ; /* semaphore to start things in right sequence */
static HEV semPause ;
static HMTX semHpsAccess ;
static ULONG ulPauseReply = 1 ;
static ULONG ulPauseMode = PAUSE_DLG ;
static HWND hSysMenu ;
/* stuff for screen-draw thread control */
static BOOL bExist ;
//static HEV semDrawDone ;
/* thread control */
static TID tidDraw, tidSpawn ;
/* font data */
static int lSupOffset = 0 ;
static int lSubOffset = 0 ;
static int lBaseSupOffset = 0 ;
static int lBaseSubOffset = 0 ;
static int lCharWidth = 217 ;
static int lCharHeight = 465 ;
/*==== f u n c t i o n s =====================================================*/
int DoPrint( HWND ) ;
HBITMAP CopyToBitmap( HPS ) ;
HMF CopyToMetaFile( HPS ) ;
MRESULT WmClientCmdProc( HWND , ULONG, MPARAM, MPARAM ) ;
void ChangeCheck( HWND, USHORT, USHORT ) ;
BOOL QueryIni( HAB ) ;
static void SaveIni( HWND ) ;
static void ThreadDraw( void* ) ;
static void DoPaint( HWND, HPS ) ;
static void Display( HPS ) ;
void SelectFont( HPS, char * );
void SwapFont( HPS, char * );
static void CopyToClipBrd( HWND ) ;
static void ReadGnu( void* ) ;
static void EditLineTypes( HWND, HPS, BOOL ) ;
static void EditCharCell( HPS, SIZEF* ) ;
static HPS InitScreenPS( void ) ;
static int BufRead( HFILE, void*, int, PULONG ) ;
int GetNewFont( HWND, HPS ) ;
void SigHandler( int ) ;
void FontExpand( char * ) ;
static char *ParseText(HPS, char *, BOOL, char *,
int, int, BOOL, BOOL ) ;
static void CharStringAt(HPS, int, int, int, char *) ;
static int QueryTextBox( HPS, int, char * ) ;
static void LMove( HPS hps, POINTL *p ) ;
static void LLine( HPS hps, POINTL *p ) ;
static void LType( int iType ) ;
/*==== c o d e ===============================================================*/
MRESULT EXPENTRY DisplayClientWndProc(HWND hWnd, ULONG message, MPARAM mp1, MPARAM mp2)
/*
** Window proc for main window
** -- passes most stuff to active child window via WmClientCmdProc
** -- passes DDE messages to DDEProc
*/
{
static BOOL bSw = FALSE ;
static BOOL bFirst = TRUE ;
static RECTL rectlPaint = { 0, 0, 0, 0 } ;
static int iPaintCount = 0 ;
static int firstcall = 1 ;
switch (message) {
case WM_CREATE:
{
HDC hdcScreen ;
SIZEL sizlPage ;
// set initial values
ChangeCheck( hWnd, IDM_LINES_THICK, bWideLines?IDM_LINES_THICK:0 ) ;
ChangeCheck( hWnd, IDM_LINES_SOLID, bLineTypes?0:IDM_LINES_SOLID ) ;
ChangeCheck( hWnd, IDM_COLOURS, bColours?IDM_COLOURS:0 ) ;
ChangeCheck( hWnd, IDM_FRONT, bPopFront?IDM_FRONT:0 ) ;
// disable close from system menu (close only from gnuplot)
hApp = WinQueryWindow( hWnd, QW_PARENT ) ; /* temporary assignment.. */
hSysMenu = WinWindowFromID( hApp, FID_SYSMENU ) ;
// setup semaphores
// DosCreateEventSem( NULL, &semDrawDone, 0L, 0L ) ;
// DosCreateEventSem( NULL, &semStartSeq, 0L, 0L ) ;
DosCreateEventSem( NULL, &semPause, 0L, 0L ) ;
DosCreateMutexSem( NULL, &semHpsAccess, 0L, 1L ) ;
bExist = TRUE ;
// create a dc and hps to draw on the screen
hdcScreen = WinOpenWindowDC( hWnd ) ;
sizlPage.cx = 0 ; sizlPage.cy = 0 ;
sizlPage.cx = 19500 ; sizlPage.cy = 12500 ;
hpsScreen = GpiCreatePS( hab, hdcScreen, &sizlPage,
PU_HIMETRIC|GPIT_NORMAL|GPIA_ASSOC) ;
// spawn server for GNUPLOT ...
tidSpawn = _beginthread( ReadGnu, NULL, 32768, NULL ) ;
}
break ;
case WM_GPSTART:
// get details of command-line window
hSwitch = WinQuerySwitchHandle( 0, ppidGnu ) ;
WinQuerySwitchEntry( hSwitch, &swGnu ) ;
if( firstcall ) {
// set size of this window
WinSetWindowPos( WinQueryWindow( hWnd, QW_PARENT ),
bPopFront?HWND_TOP:swGnu.hwnd,
ulShellPos[0],
ulShellPos[1],
ulShellPos[2],
ulShellPos[3],
bShellPos?(bPopFront?SWP_SIZE|SWP_MOVE|SWP_SHOW|SWP_ACTIVATE
:SWP_SIZE|SWP_MOVE|SWP_SHOW|SWP_ZORDER)
:(bPopFront?SWP_SHOW|SWP_ACTIVATE:SWP_SHOW|SWP_ZORDER) ) ;
signal( SIGTERM, SigHandler ) ;
firstcall = 0 ;
}
if( !bPopFront ) WinSwitchToProgram( hSwitch ) ;
// DosPostEventSem( semDrawDone ) ;
DosReleaseMutexSem( semHpsAccess ) ;
return 0 ;
case WM_COMMAND:
return WmClientCmdProc( hWnd , message , mp1 , mp2 ) ;
case WM_CHAR:
/* If the user types a command in the driver window,
we route it to the gnuplot window and switch that
to the front. Doesn't work for full-screen
sessions, though (but does switch). */
{
USHORT usFlag ;
usFlag = SHORT1FROMMP( mp1 ) ;
if( !(usFlag & (KC_KEYUP|KC_ALT|KC_CTRL)) ) {
USHORT uc = SHORT1FROMMP( mp2 ) ;
HWND hw = WinQueryWindow( swGnu.hwnd, QW_BOTTOM ) ;
WinSetFocus( HWND_DESKTOP, hw ) ;
WinSendMsg( hw, message,
MPFROM2SHORT((USHORT)(KC_SCANCODE), 1),
MPFROMSHORT(uc) ) ;
WinSwitchToProgram( hSwitch ) ;
}
}
break ;
case WM_DESTROY:
if( WinSendMsg( hWnd, WM_USER_PRINT_QBUSY, 0L, 0L ) != 0L ) {
WinMessageBox( HWND_DESKTOP,
hWnd,
"Still printing - not closed",
APP_NAME,
0,
MB_OK | MB_ICONEXCLAMATION ) ;
return 0L ;
}
return (WinDefWindowProc(hWnd, message, mp1, mp2));
case WM_PAINT:
{
ULONG ulCount ;
PID pid; TID tid;
HPS hps_tmp;
RECTL rectl_tmp;
DosQueryMutexSem( semHpsAccess, &pid, &tid, &ulCount ) ;
if (( ulCount > 0 ) && (tid != tidDraw)) {
/* simple repaint while building plot or metafile */
/* use temporary PS */
hps_tmp = WinBeginPaint(hWnd,0,&rectl_tmp );
WinFillRect(hps_tmp,&rectl_tmp,CLR_BACKGROUND);
WinEndPaint(hps_tmp);
/* add dirty rectangle to saved rectangle */
/* to be repainted when PS is available again */
WinUnionRect(hab,&rectlPaint,&rectl_tmp,&rectlPaint);
iPaintCount ++ ;
break ;
}
WinInvalidateRect( hWnd, &rectlPaint, TRUE ) ;
DoPaint( hWnd, hpsScreen ) ;
WinSetRectEmpty( hab, &rectlPaint ) ;
}
break ;
case WM_SIZE :
{
WinInvalidateRect( hWnd, NULL, TRUE ) ;
}
break ;
case WM_PRESPARAMCHANGED:
{
char *pp ;
ULONG ulID ;
pp = malloc(FONTBUF) ;
if( WinQueryPresParam( hWnd,
PP_FONTNAMESIZE,
0,
&ulID,
FONTBUF,
pp,
QPF_NOINHERIT ) != 0L ) {
strcpy( szFontNameSize, pp ) ;
bNewFont = TRUE ;
WinInvalidateRect( hWnd, NULL, TRUE ) ;
}
free(pp) ;
}
break ;
case WM_USER_PRINT_BEGIN:
case WM_USER_PRINT_OK :
case WM_USER_DEV_ERROR :
case WM_USER_PRINT_ERROR :
case WM_USER_PRINT_QBUSY :
return( PrintCmdProc( hWnd, message, mp1, mp2 ) ) ;
case WM_GNUPLOT:
// display the plot
if( bPopFront )
WinSetWindowPos( hwndFrame, HWND_TOP, 0,0,0,0, SWP_ACTIVATE|SWP_ZORDER ) ;
if( iPaintCount > 0 ) { /* if outstanding paint messages, repaint */
WinInvalidateRect( hWnd, &rectlPaint, TRUE ) ;
iPaintCount = 0 ;
}
return 0L ;
case WM_PAUSEPLOT:
/* put pause message on screen, or enable 'continue' button */
if( ulPauseMode == PAUSE_DLG ) {
pausedata.pszMessage = (char*)mp1 ;
WinLoadDlg( HWND_DESKTOP,
hWnd,
(PFNWP)PauseMsgDlgProc,
0L,
IDD_PAUSEBOX,
&pausedata ) ;
}
else {
WinEnableMenuItem( WinWindowFromID(
WinQueryWindow( hWnd, QW_PARENT ), FID_MENU ),
IDM_CONTINUE,
TRUE ) ;
}
return 0L ;
case WM_PAUSEEND:
/* resume plotting */
ulPauseReply = (ULONG) mp1 ;
DosPostEventSem( semPause ) ;
return 0L ;
default: /* Passes it on if unproccessed */
return (WinDefWindowProc(hWnd, message, mp1, mp2));
}
return (NULL);
}
MRESULT WmClientCmdProc(HWND hWnd, ULONG message, MPARAM mp1, MPARAM mp2)
/*
** Handle client window command (menu) messages
*/
{
extern HWND hApp ;
static ulPauseItem = IDM_PAUSEDLG ;
switch( (USHORT) SHORT1FROMMP( mp1 ) ) {
case IDM_ABOUT : /* show the 'About' box */
WinDlgBox( HWND_DESKTOP,
hWnd ,
(PFNWP)About ,
0L,
ID_ABOUT,
NULL ) ;
break ;
case IDM_GPLOTINF: /* view gnuplot.inf */
{
char path[256] ;
char *p ;
strcpy( path, "start view " ) ;
if( (p=getenv("GNUPLOT")) != NULL ) {
strcat( path, p ) ;
strcat( path, "/" ) ;
}
strcat( path, "gnuplot" ) ;
system( path ) ;
}
break ;
case IDM_PRINT : /* print plot */
if( SetupPrinter( hWnd, &qPrintData ) ) {
WinPostMsg( hWnd,
WM_USER_PRINT_BEGIN,
(MPARAM) &qPrintData,
(MPARAM) hpsScreen ) ;
}
break ;
case IDM_PRINTSETUP : /* select printer */
WinDlgBox( HWND_DESKTOP,
hWnd ,
(PFNWP)QPrintersDlgProc,
0L,
IDD_QUERYPRINT,
qPrintData.szPrinterName ) ;
break ;
case IDM_LINES_THICK:
// change line setting
bWideLines = !bWideLines ;
ChangeCheck( hWnd, IDM_LINES_THICK, bWideLines?IDM_LINES_THICK:0 ) ;
WinInvalidateRect( hWnd, NULL, TRUE ) ;
break ;
case IDM_LINES_SOLID:
// change line setting
bLineTypes = !bLineTypes ;
ChangeCheck( hWnd, IDM_LINES_SOLID, bLineTypes?0:IDM_LINES_SOLID ) ;
EditLineTypes( hWnd, hpsScreen, bLineTypes ) ;
WinInvalidateRect( hWnd, NULL, TRUE ) ;
break ;
case IDM_COLOURS:
// change colour setting
bColours = !bColours ;
ChangeCheck( hWnd, IDM_COLOURS, bColours?IDM_COLOURS:0 ) ;
WinInvalidateRect( hWnd, NULL, TRUE ) ;
break ;
case IDM_FRONT:
/* toggle z-order forcing */
bPopFront = !bPopFront ;
ChangeCheck( hWnd, IDM_FRONT, bPopFront?IDM_FRONT:0 ) ;
break ;
case IDM_FONTS:
if( GetNewFont( hWnd, hpsScreen ) ) {
bNewFont = TRUE ;
WinInvalidateRect( hWnd, NULL, TRUE ) ;
}
break ;
case IDM_SAVE :
SaveIni( hWnd ) ;
break ;
case IDM_COPY : /* copy to clipboard */
if( WinOpenClipbrd( hab ) ) {
CopyToClipBrd( hWnd ) ;
}
else {
WinMessageBox( HWND_DESKTOP,
hWnd,
"Can't open clipboard",
APP_NAME,
0,
MB_OK | MB_ICONEXCLAMATION ) ;
}
break ;
case IDM_CLEARCLIP : /* clear clipboard */
if( WinOpenClipbrd( hab ) ) {
WinEmptyClipbrd( hab ) ;
WinCloseClipbrd( hab ) ;
}
else {
WinMessageBox( HWND_DESKTOP,
hWnd,
"Can't open clipboard",
APP_NAME,
0,
MB_OK | MB_ICONEXCLAMATION ) ;
}
break ;
case IDM_COMMAND: /* go back to GNUPLOT command window */
WinSwitchToProgram( hSwitch ) ;
break ;
case IDM_CONTINUE:
WinPostMsg( hWnd, WM_PAUSEEND, (MPARAM)1L, (MPARAM)0L ) ;
WinEnableMenuItem( WinWindowFromID(
WinQueryWindow( hWnd, QW_PARENT ), FID_MENU ),
IDM_CONTINUE,
FALSE ) ;
break ;
case IDM_PAUSEGNU: /* gnuplot handles pause */
ChangeCheck( hWnd, ulPauseItem, IDM_PAUSEGNU ) ;
ulPauseItem = IDM_PAUSEGNU ;
ulPauseMode = PAUSE_GNU ;
break ;
case IDM_PAUSEDLG: /* pause message in dlg box */
ChangeCheck( hWnd, ulPauseItem, IDM_PAUSEDLG ) ;
ulPauseItem = IDM_PAUSEDLG ;
ulPauseMode = PAUSE_DLG ;
break ;
case IDM_PAUSEBTN: /* pause uses menu button, no message */
ChangeCheck( hWnd, ulPauseItem, IDM_PAUSEBTN ) ;
ulPauseItem = IDM_PAUSEBTN ;
ulPauseMode = PAUSE_BTN ;
break ;
case IDM_HELPFORHELP:
WinSendMsg(WinQueryHelpInstance(hWnd),
HM_DISPLAY_HELP, 0L, 0L ) ;
return 0L ;
case IDM_EXTENDEDHELP:
WinSendMsg(WinQueryHelpInstance(hWnd),
HM_EXT_HELP, 0L, 0L);
return 0L ;
case IDM_KEYSHELP:
WinSendMsg(WinQueryHelpInstance(hWnd),
HM_KEYS_HELP, 0L, 0L);
return 0L ;
case IDM_HELPINDEX:
WinSendMsg(WinQueryHelpInstance(hWnd),
HM_HELP_INDEX, 0L, 0L);
return 0L ;
default :
return WinDefWindowProc( hWnd, message, mp1, mp2 ) ;
}
return( NULL ) ;
}
void ChangeCheck( HWND hWnd , USHORT wItem1 , USHORT wItem2 )
/*
** Utility function:
**
** move check mark from menu item 1 to item 2
*/
{
HWND hMenu ;
hMenu = WinWindowFromID( WinQueryWindow( hWnd, QW_PARENT ),
FID_MENU ) ;
if( wItem1 != 0 )
WinSendMsg( hMenu,
MM_SETITEMATTR,
MPFROM2SHORT( wItem1, TRUE ),
MPFROM2SHORT( MIA_CHECKED, 0 ) ) ;
if( wItem2 != 0 )
WinSendMsg( hMenu,
MM_SETITEMATTR,
MPFROM2SHORT( wItem2, TRUE ),
MPFROM2SHORT( MIA_CHECKED, MIA_CHECKED ) ) ;
}
static void CopyToClipBrd( HWND hWnd )
/*
** Copy window to clipboard as bitmap.
*/
{
HAB hab ;
HBITMAP hbm ;
HMF hmf ;
hab = WinQueryAnchorBlock( hWnd ) ;
WinEmptyClipbrd( hab ) ;
hbm = CopyToBitmap( hpsScreen ) ;
WinSetClipbrdData( hab, (ULONG) hbm, CF_BITMAP, CFI_HANDLE) ;
hmf = CopyToMetaFile( hpsScreen ) ;
WinSetClipbrdData( hab, (ULONG) hmf, CF_METAFILE, CFI_HANDLE) ;
WinCloseClipbrd( hab ) ;
}
HBITMAP CopyToBitmap( HPS hps )
/*
** Copy ps to a bitmap.
*/
{
HPS hpsMem ;
HWND hwnd ;
HAB hab ;
PSZ psz[4] = {NULL,"Display",NULL,NULL} ;
HDC hdcMem, hdcScr ;
SIZEL sizel ;
BITMAPINFOHEADER2 bmp ;
PBITMAPINFO2 pbmi ;
HBITMAP hbm ;
BYTE abBmp[80] ;
LONG alData[2] ;
RECTL rectl ;
POINTL aptl[6] ;
HMF hmf ;
hdcScr = GpiQueryDevice( hps ) ;
hwnd = WinWindowFromDC( hdcScr ) ;
hab = WinQueryAnchorBlock( hwnd ) ;
hdcMem = DevOpenDC( hab,
OD_MEMORY,
"*",
4L,
(PDEVOPENDATA) psz,
hdcScr ) ;
sizel.cx = 0/*GNUPAGE*/ ; sizel.cy = 0/*GNUPAGE*/ ;
hpsMem = GpiCreatePS( hab, hdcMem, &sizel, PU_PELS|GPIA_ASSOC|GPIT_MICRO ) ;
GpiQueryDeviceBitmapFormats( hpsMem, 2L, alData ) ;
WinQueryWindowRect( hwnd, &rectl ) ;
memset( &bmp, 0, sizeof(bmp) ) ;
bmp.cbFix = (ULONG) sizeof( bmp ) ;
bmp.cx = (SHORT) (rectl.xRight-rectl.xLeft) ;
bmp.cy = (SHORT) (rectl.yTop-rectl.yBottom) ;
bmp.cPlanes = alData[0] ;
bmp.cBitCount = alData[1] ;
hbm = GpiCreateBitmap( hpsMem, &bmp, 0, NULL, NULL ) ;
GpiSetBitmap( hpsMem, hbm ) ;
aptl[0].x = 0 ; aptl[0].y = 0 ;
aptl[1].x = (LONG)bmp.cx ; aptl[1].y = (LONG)bmp.cy ;
aptl[2].x = 0 ; aptl[2].y = 0 ;
GpiBitBlt( hpsMem, hps, 3L, aptl, ROP_SRCCOPY, BBO_IGNORE ) ;
GpiDestroyPS( hpsMem ) ;
DevCloseDC( hdcMem ) ;
return hbm ;
}
HMF CopyToMetaFile( HPS hps )
/*
** Copy ps to a mteafile.
*/
{
HDC hdcMF, hdcOld ;
HAB hab ;
HWND hwnd ;
PSZ psz[4] = {NULL,"Display",NULL,NULL} ;
HMF hmf ;
hdcOld = GpiQueryDevice( hps ) ;
hwnd = WinWindowFromDC( hdcOld ) ;
hab = WinQueryAnchorBlock( hwnd ) ;
hdcMF = DevOpenDC( hab, OD_METAFILE, "*", 4L, psz, hdcOld ) ;
DosRequestMutexSem( semHpsAccess, (ULONG) SEM_INDEFINITE_WAIT ) ;
GpiSetDrawingMode( hps, DM_DRAW ) ;
GpiAssociate( hps, 0 ) ;
GpiAssociate( hps, hdcMF ) ;
ScalePS( hps ) ;
GpiDrawChain( hps ) ;
GpiAssociate( hps, 0 ) ;
GpiAssociate( hps, hdcOld ) ;
DosReleaseMutexSem( semHpsAccess ) ;
hmf = DevCloseDC( hdcMF ) ;
return hmf ;
}
BOOL QueryIni( HAB hab )
/*
** Query INI file
*/
{
BOOL bPos, bData, bSwp ;
ULONG ulOpts[5] ;
HINI hini ;
ULONG ulCB ;
char *p ;
static SWP pauseswp ;
// read gnuplot ini file
hini = PrfOpenProfile( hab, szIniFile ) ;
ulCB = sizeof( ulShellPos ) ;
bPos = PrfQueryProfileData( hini, APP_NAME, INISHELLPOS, &ulShellPos, &ulCB ) ;
ulCB = sizeof( SWP ) ;
bSwp = PrfQueryProfileData( hini, APP_NAME, INIPAUSEPOS, &pauseswp, &ulCB ) ;
if( bSwp ) pausedata.pswp = &pauseswp ;
ulCB = sizeof( ulOpts ) ;
bData = PrfQueryProfileData( hini, APP_NAME, INIOPTS, &ulOpts, &ulCB ) ;
if( bData ) {
bLineTypes = (BOOL)ulOpts[0] ;
bWideLines = (BOOL)ulOpts[1] ;
bColours = (BOOL)ulOpts[2] ;
ulPauseMode = ulOpts[3] ;
bPopFront = (BOOL)ulOpts[4] ;
}
else {
bLineTypes = FALSE ; /* default values */
/* bWideLines = FALSE ; */
bColours = TRUE ;
bPopFront = TRUE ;
ulPauseMode = 1 ;
}
ulCB = 4*sizeof(float) ;
PrfQueryProfileData( hini, APP_NAME, INIFRAC, &qPrintData.xsize, &ulCB ) ;
if( PrfQueryProfileSize( hini, APP_NAME, INIPRDRIV, &ulCB ) ) {
PDRIVDATA pdriv = (PDRIVDATA) malloc( ulCB ) ;
if( pdriv != NULL ) {
PrfQueryProfileData( hini, APP_NAME, INIPRDRIV, pdriv, &ulCB ) ;
qPrintData.pdriv = pdriv ;
qPrintData.cbpdriv = ulCB ;
}
}
PrfQueryProfileString( hini, APP_NAME, INIPRPR, "",
qPrintData.szPrinterName,
(long) sizeof qPrintData.szPrinterName ) ;
PrfQueryProfileString( hini, APP_NAME, INIFONT, INITIAL_FONT,
szFontNameSize, FONTBUF ) ;
ulCB = sizeof( ulOpts ) ;
bData = PrfQueryProfileData( hini, APP_NAME, INICHAR, &ulOpts, &ulCB ) ;
if( bData ) {
lCharWidth = ulOpts[0] ;
lCharHeight = ulOpts[1] ;
}
else {
lCharWidth = 217 ;
lCharHeight = 465 ;
}
PrfCloseProfile( hini ) ;
if( qPrintData.szPrinterName[0] == '\0' ) {
// get default printer name
PrfQueryProfileString( HINI_PROFILE,
"PM_SPOOLER",
"PRINTER",
";",
qPrintData.szPrinterName,
(long) sizeof qPrintData.szPrinterName ) ;
if( (p=strchr( qPrintData.szPrinterName, ';' )) != NULL ) *p = '\0' ;
}
bShellPos = bPos ;
return bPos ;
}
static void SaveIni( HWND hWnd )
/*
** save data in ini file
*/
{
SWP swp ;
HINI hini ;
ULONG ulOpts[5] ;
HFILE hfile ;
ULONG ulAct ;
ERRORID errid ;
char achErr[64] ;
HAB hab ;
hab = WinQueryAnchorBlock( hWnd ) ;
hini = PrfOpenProfile( hab, szIniFile ) ;
if( hini != NULLHANDLE ) {
WinQueryWindowPos( hwndFrame, &swp ) ;
ulPlotPos[0] = swp.x ;
ulPlotPos[1] = swp.y ;
ulPlotPos[2] = swp.cx ;
ulPlotPos[3] = swp.cy ;
PrfWriteProfileData( hini, APP_NAME, INISHELLPOS, &ulPlotPos, sizeof(ulPlotPos) ) ;
if( pausedata.pswp != NULL )
PrfWriteProfileData( hini, APP_NAME, INIPAUSEPOS,
pausedata.pswp, sizeof(SWP) ) ;
ulOpts[0] = (ULONG)bLineTypes ;
ulOpts[1] = (ULONG)bWideLines ;
ulOpts[2] = (ULONG)bColours ;
ulOpts[3] = ulPauseMode ;
ulOpts[4] = (ULONG)bPopFront ;
PrfWriteProfileData( hini, APP_NAME, INIOPTS, &ulOpts, sizeof(ulOpts) ) ;
PrfWriteProfileData( hini, APP_NAME, INIFRAC, &qPrintData.xsize, 4*sizeof(float) ) ;
if( qPrintData.pdriv != NULL )
PrfWriteProfileData( hini, APP_NAME, INIPRDRIV, qPrintData.pdriv,
qPrintData.cbpdriv ) ;
PrfWriteProfileString( hini, APP_NAME, INIPRPR,
qPrintData.szPrinterName[0] == '\0'? NULL:
qPrintData.szPrinterName ) ;
PrfWriteProfileString( hini, APP_NAME, INIFONT, szFontNameSize ) ;
ulOpts[0] = (ULONG)lCharWidth ;
ulOpts[1] = (ULONG)lCharHeight ;
PrfWriteProfileData( hini, APP_NAME, INICHAR, &ulOpts, sizeof(ulOpts) ) ;
PrfCloseProfile( hini ) ;
}
else {
WinMessageBox( HWND_DESKTOP,
HWND_DESKTOP,
"Can't write ini file",
APP_NAME,
0,
MB_OK | MB_ICONEXCLAMATION ) ;
}
}
static void DoPaint( HWND hWnd, HPS hps )
/*
** Paint the screen with current data
*/
{
ULONG ulCount ;
static RECTL rectl ;
if( tidDraw != 0 ) {
/* already drawing - stop it; include the rectl now
being drawn in, in the update region; and return
without calling beginpaint so that the paint
message is resent */
GpiSetStopDraw( hpsScreen, SDW_ON ) ;
DosSleep(1) ;
WinInvalidateRect( hWnd, &rectl, TRUE ) ;
return ;
}
/* winbeginpaint here, so paint message is
not resent when we return, then spawn a
thread to do the drawing */
WinBeginPaint( hWnd, hps, &rectl ) ; //rl
tidDraw = _beginthread( ThreadDraw, NULL, 32768, NULL ) ;
}
static void ThreadDraw( void* arg )
/*
** Thread to draw plot on screen
*/
{
HAB hab ;
hab = WinInitialize( 0 ) ;
InitScreenPS() ;
DosRequestMutexSem( semHpsAccess, (ULONG) SEM_INDEFINITE_WAIT ) ;
ScalePS( hpsScreen ) ;
GpiSetStopDraw( hpsScreen, SDW_OFF ) ;
GpiSetDrawingMode( hpsScreen, DM_DRAW ) ;
GpiDrawChain( hpsScreen ) ;
WinEndPaint( hpsScreen ) ;
DosReleaseMutexSem( semHpsAccess ) ;
WinTerminate( hab ) ;
tidDraw = 0 ;
}
HPS InitScreenPS()
/*
** Initialise the screen ps for drawing
*/
{
RECTL rectClient ;
int nColour = 0 ;
GpiResetPS( hpsScreen, GRES_ATTRS ) ;
GpiErase(hpsScreen);
WinQueryWindowRect( hApp, (PRECTL)&rectClient ) ;
{
double ratio = 1.560 ;
double xs = rectClient.xRight - rectClient.xLeft ;
double ys = rectClient.yTop - rectClient.yBottom ;
if( ys > xs/ratio ) { /* reduce ys to fit */
rectClient.yTop = rectClient.yBottom + (int)(xs/ratio) ;
}
else if( ys < xs/ratio ) { /* reduce xs to fit */
rectClient.xRight = rectClient.xLeft + (int)(ys*ratio) ;
}
}
GpiSetPageViewport( hpsScreen, &rectClient ) ;
if( !bColours ) {
int i ;
for( i=0; i<8; i++ ) alColourTable[i] = 0 ;
for( i=8; i<16; i++ ) alColourTable[i] = 0 ;
alColourTable[0] = 0xFFFFFF ;
nColour = 16 ;
}
GpiCreateLogColorTable( hpsScreen,
LCOL_RESET,
LCOLF_CONSECRGB,
0, nColour, alColourTable ) ;
return hpsScreen ;
}
enum JUSTIFY { LEFT, CENTRE, RIGHT } jmode;
short ScalePS( HPS hps )
/*
** Get a font to use
** Scale the plot area to world coords for subsequent plotting
*/
{
RECTL rectView ;
SelectFont( hps, szFontNameSize ) ;
return 0 ;
}
static SIZEF sizBaseSubSup ;
static SIZEF sizCurSubSup ;
static SIZEF sizCurFont ;
static long lVOffset = 0 ;
static SIZEF sizBaseFont ;
static struct _ft {
char *name ;
LONG lcid ;
} tabFont[256] = {{NULL,0L}, {NULL}};
void SelectFont( HPS hps, char *szFontNameSize )
/*
** Select a named and sized outline (adobe) font
*/
{
HDC hdc ;
FATTRS fat ;
LONG xDeviceRes, yDeviceRes ;
POINTL ptlFont ;
SIZEF sizfx ;
static LONG lcid = 0L ;
static char *szFontName ;
static short shPointSize ;
sscanf( szFontNameSize, "%hd", &shPointSize ) ;
szFontName = strchr( szFontNameSize, '.' ) + 1 ;
fat.usRecordLength = sizeof fat ;
fat.fsSelection = 0 ;
fat.lMatch = 0 ;
fat.idRegistry = 0 ;
fat.usCodePage = 0 ; //GpiQueryCp (hps) ;
fat.lMaxBaselineExt = 0 ;
fat.lAveCharWidth = 0 ;
fat.fsType = 0 ;
fat.fsFontUse = FATTR_FONTUSE_OUTLINE |
FATTR_FONTUSE_TRANSFORMABLE ;
strcpy (fat.szFacename, szFontName) ;
if(tabFont[0].name !=NULL) free( tabFont[0].name ) ;
tabFont[0].name = strdup( szFontName ) ;
tabFont[0].lcid = 10L ;
lcid = GpiQueryCharSet( hps ) ;
if( lcid != 10L ) lcid = 10L ;
else {
GpiSetCharSet( hps, 0L) ;
GpiDeleteSetId( hps, lcid ) ;
}
GpiCreateLogFont (hps, NULL, lcid, &fat) ;
GpiSetCharSet( hps, lcid ) ;
hdc = GpiQueryDevice (hps) ;
DevQueryCaps (hdc, CAPS_HORIZONTAL_RESOLUTION, 1L, &xDeviceRes) ;
DevQueryCaps (hdc, CAPS_VERTICAL_RESOLUTION, 1L, &yDeviceRes) ;
// Find desired font size in pixels
ptlFont.x = 2540L * (long)shPointSize / 72L ;
ptlFont.y = 2540L * (long)shPointSize / 72L ;
// Set the character box
sizfx.cx = MAKEFIXED (ptlFont.x, 0) ;
sizfx.cy = MAKEFIXED (ptlFont.y, 0) ;
lVOffset = ptlFont.y ;
sizBaseFont = sizfx ;
GpiSetCharBox (hps, &sizfx) ;
// set up some useful globals
{
FONTMETRICS fm ;
GpiQueryFontMetrics( hps, sizeof(FONTMETRICS), &fm ) ;
lBaseSubOffset = -fm.lSubscriptYOffset ;
lBaseSupOffset = fm.lSuperscriptYOffset ;
lSubOffset = lBaseSubOffset ;
lSupOffset = lBaseSupOffset ;
lCharHeight = fm.lMaxAscender*1.2 ;
lCharWidth = fm.lAveCharWidth ;
sizBaseSubSup.cx = MAKEFIXED( ptlFont.x*0.7, 0 ) ;
sizBaseSubSup.cy = MAKEFIXED( ptlFont.y*0.7, 0 ) ;
}
sizCurFont = sizBaseFont ;
sizCurSubSup = sizBaseSubSup ;
if( bNewFont ) {
// EditCharCell( hps, &sizfx ) ;
bNewFont = FALSE ;
}
}
void SwapFont( HPS hps, char *szFNS )
/*
** Select a named and sized outline (adobe) font
*/
{
HDC hdc ;
FATTRS fat ;
LONG xDeviceRes, yDeviceRes ;
POINTL ptlFont ;
SIZEF sizfx ;
static LONG lcid = 0L ;
static int itab = 1 ;
static char *szFontName ;
static short shPointSize ;
if( szFNS == NULL ) { /* restore base font */
sizCurFont = sizBaseFont ;
sizCurSubSup = sizBaseSubSup ;
lSubOffset = lBaseSubOffset ;
lSupOffset = lBaseSupOffset ;
GpiSetCharSet( hps, 10 ) ;
GpiSetCharBox (hps, &sizBaseFont) ;
}
else {
sscanf( szFNS, "%hd", &shPointSize ) ;
szFontName = strchr( szFNS, '.' ) + 1 ;
{
int i ;
lcid = 0 ;
for(i=0;i<itab;i++) {
if( strcmp( szFontName, tabFont[i].name ) == 0 ) {
lcid = tabFont[i].lcid ;
break ;
}
}
}
if( lcid == 0 ) {
fat.usRecordLength = sizeof fat ;
fat.fsSelection = 0 ;
fat.lMatch = 0 ;
fat.idRegistry = 0 ;
fat.usCodePage = 0 ; //GpiQueryCp (hps) ;
fat.lMaxBaselineExt = 0 ;
fat.lAveCharWidth = 0 ;
fat.fsType = 0 ;
fat.fsFontUse = FATTR_FONTUSE_OUTLINE |
FATTR_FONTUSE_TRANSFORMABLE ;
strcpy (fat.szFacename, szFontName) ;
tabFont[itab].name = strdup( szFontName ) ;
lcid = itab+10 ;
tabFont[itab].lcid = lcid ;
++itab ;
// lcid = 11L ;
GpiSetCharSet( hps, 0L) ;
GpiDeleteSetId( hps, lcid ) ;
GpiCreateLogFont (hps, NULL, lcid, &fat) ;
}
GpiSetCharSet( hps, lcid ) ;
hdc = GpiQueryDevice (hps) ;
DevQueryCaps (hdc, CAPS_HORIZONTAL_RESOLUTION, 1L, &xDeviceRes) ;
DevQueryCaps (hdc, CAPS_VERTICAL_RESOLUTION, 1L, &yDeviceRes) ;
// Find desired font size in pixels
ptlFont.x = 2540L * (long)shPointSize / 72L ;
ptlFont.y = 2540L * (long)shPointSize / 72L ;
// Set the character box
sizCurFont.cx = MAKEFIXED (ptlFont.x, 0) ;
sizCurFont.cy = MAKEFIXED (ptlFont.y, 0) ;
// lVOffset = ptlFont.y ;
GpiSetCharBox (hps, &sizCurFont) ;
sizCurSubSup.cx = MAKEFIXED( ptlFont.x*0.7, 0 ) ;
sizCurSubSup.cy = MAKEFIXED( ptlFont.y*0.7, 0 ) ;
// set up some useful globals
{
FONTMETRICS fm ;
GpiQueryFontMetrics( hps, sizeof(FONTMETRICS), &fm ) ;
lSubOffset = -fm.lSubscriptYOffset ;
lSupOffset = fm.lSuperscriptYOffset ;
}
}
}
static void ReadGnu( void* arg )
/*
** Thread to read plot commands from GNUPLOT pm driver.
** Opens named pipe, then clears semaphore to allow GNUPLOT driver to proceed.
** Reads commands and builds a command list.
*/
{
HPIPE hRead = 0L ;
POINTL ptl ;
POINTL aptl[4] ;
long lCurCol ;
long lOldLine = 0 ;
BOOL bBW = FALSE ; /* passed frpm print.c ?? */
BOOL bPath = FALSE ;
BOOL bDots = FALSE ;
char *szEnv ;
char *szFileBuf ;
ULONG rc;
USHORT usErr ;
ULONG cbR ;
USHORT i ;
PID ppid ;
unsigned char buff[2] ;
HEV hev ;
static char *szPauseText = NULL ;
ULONG ulPause ;
char *pszPipeName, *pszSemName ;
LONG commands[4] ;
HPS hps ;
HAB hab ;
int linewidth = DEFLW ;
hab = WinInitialize( 0 ) ;
DosEnterCritSec() ;
pszPipeName = malloc( 256 ) ;
pszSemName = malloc( 256 ) ;
DosExitCritSec() ;
strcpy( pszPipeName, "\\pipe\\" ) ;
strcpy( pszSemName, "\\sem32\\" ) ;
strcat( pszPipeName, szIPCName ) ;
strcat( pszSemName, szIPCName ) ;
/* open a named pipe for communication with gnuplot */
rc = DosCreateNPipe( pszPipeName,
&hRead,
NP_ACCESS_DUPLEX|NP_NOINHERIT|NP_NOWRITEBEHIND ,
1|NP_WAIT|NP_READMODE_MESSAGE|NP_TYPE_MESSAGE,
PIPEBUF,
PIPEBUF,
0xFFFFFFFF) ;
hev = 0 ; /* OK, gnuplot can try to open npipe ... */
DosOpenEventSem( pszSemName, &hev ) ;
DosPostEventSem( hev ) ;
/* attach to gnuplot */
server:
if( DosConnectNPipe( hRead ) == 0L ) {
WinPostMsg( hSysMenu,
MM_SETITEMATTR,
MPFROM2SHORT(SC_CLOSE, TRUE ),
MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED) ) ;
/* store graphics commands */
/* use semaphore to prevent problems with drawing while reallocating
the command buffers */
DosRead( hRead, &ppidGnu, 4, &cbR ) ;
// DosPostEventSem( semStartSeq ) ; /* once we've got pidGnu */
WinPostMsg( hApp, WM_GPSTART, 0, 0 ) ;
hps = hpsScreen ;
InitScreenPS() ;
while (1) {
usErr=BufRead(hRead,buff, 1, &cbR) ;
if( usErr != 0 ) break ;
switch( *buff ) {
case 'G' : /* enter graphics mode */
{
ULONG ulCount ;
if( tidDraw != 0 ) {
/* already drawing - stop it */
GpiSetStopDraw( hpsScreen, SDW_ON ) ;
while(tidDraw != 0) DosSleep(1) ;
}
/* wait for access to command list and lock it */
// DosWaitEventSem( semDrawDone, SEM_INDEFINITE_WAIT ) ;
// DosEnterCritSec() ;
DosRequestMutexSem( semHpsAccess, (ULONG) SEM_INDEFINITE_WAIT ) ;
InitScreenPS() ;
ScalePS( hps ) ;
// DosResetEventSem( semDrawDone, &ulCount ) ;
GpiSetDrawingMode( hps, DM_DRAWANDRETAIN ) ;
for(i=1;i<=iSeg;i++)
GpiDeleteSegment( hps, i ) ;
iSeg = 1 ;
GpiOpenSegment( hps, iSeg ) ;
// DosExitCritSec() ;
GpiSetLineEnd( hps, LINEEND_ROUND ) ;
GpiSetLineWidthGeom( hps, linewidth ) ;
GpiSetCharBox (hps, &sizBaseFont) ;
}
break ;
case 'Q' : /* query terminal info */
DosWrite( hRead, &lCharWidth, sizeof(int), &cbR ) ;
DosWrite( hRead, &lCharHeight, sizeof(int), &cbR ) ;
break ;
case 'E' : /* leave graphics mode (graph completed) */
if( bPath ) {
GpiEndPath( hps ) ;
GpiStrokePath( hps, 1, 0 ) ;
bPath = FALSE ;
}
GpiCloseSegment( hps ) ;
// DosPostEventSem( semDrawDone ) ;
DosReleaseMutexSem( semHpsAccess ) ;
WinPostMsg( hApp, WM_GNUPLOT, 0L, 0L ) ;
break ;
case 'R' :
/* gnuplot has reset drivers, allow user to kill this */
WinPostMsg( hSysMenu,
MM_SETITEMATTR,
MPFROM2SHORT(SC_CLOSE, TRUE ),
MPFROM2SHORT(MIA_DISABLED, (USHORT)0 ) ) ;
/* if we are keeping us on the screen, wait for new connection */
if( bServer||bPersist ) {
DosDisConnectNPipe( hRead ) ;
goto server ;
}
break ;
case 'r' :
/* resume after multiplot */
{
ULONG ulCount ;
DosRequestMutexSem( semHpsAccess, (ULONG) SEM_INDEFINITE_WAIT ) ;
// DosWaitEventSem( semDrawDone, SEM_INDEFINITE_WAIT ) ;
iSeg++ ;
// DosResetEventSem( semDrawDone, &ulCount ) ;
GpiSetDrawingMode( hps, DM_DRAWANDRETAIN ) ;
GpiOpenSegment( hps, iSeg ) ;
}
break ;
case 's' :
/* suspend after multiplot */
break ;
case 'M' : /* move */
case 'V' : /* draw vector */
if( *buff=='M' ) {
if( bPath ) {
GpiEndPath( hps ) ;
GpiStrokePath( hps, 1, 0 ) ;
bPath = FALSE ;
}
}
else {
if( bWideLines/*bWideLines*/ && !bPath ) {
GpiBeginPath( hps, 1 ) ;
bPath = TRUE ;
}
}
BufRead(hRead,&ptl.x, 2*sizeof(int), &cbR) ;
if( (*buff=='V') && bDots ) ptl.x += 5 ;
else if( (*buff=='M') && bDots ) ptl.x -= 5 ;
if( *buff == 'M' ) LMove( hps, &ptl ) ;
else LLine( hps, &ptl ) ;
break ;
case 'P' : /* pause */
{
int len ;
BufRead(hRead,&len, sizeof(int), &cbR) ;
len = (len+sizeof(int)-1)/sizeof(int) ;
if( len > 0 ){ /* get pause text */
DosEnterCritSec() ;
szPauseText = malloc( len*sizeof(int) ) ;
DosExitCritSec() ;
BufRead(hRead,szPauseText, len*sizeof(int), &cbR) ;
}
if( ulPauseMode != PAUSE_GNU ) {
/* pause and wait for semaphore to be cleared */
DosResetEventSem( semPause, &ulPause ) ;
WinPostMsg( hApp, WM_PAUSEPLOT, (MPARAM) szPauseText, 0L ) ;
DosWaitEventSem( semPause, SEM_INDEFINITE_WAIT ) ;
}
else { /* gnuplot handles pause */
ulPauseReply = 2 ;
}
DosEnterCritSec() ;
if( szPauseText != NULL ) free( szPauseText ) ;
szPauseText = NULL ;
DosExitCritSec() ;
/* reply to gnuplot so it can continue */
DosWrite( hRead, &ulPauseReply, sizeof(int), &cbR ) ;
}
break ;
case 'T' : /* write text */
/* read x, y, len */
if( bPath ) {
GpiEndPath( hps ) ;
GpiStrokePath( hps, 1, 0 ) ;
bPath = FALSE ;
}
{
int x, y, len, sw ;
char *str ;
BufRead(hRead,&x, sizeof(int), &cbR) ;
BufRead(hRead,&y, sizeof(int), &cbR) ;
BufRead(hRead,&len, sizeof(int), &cbR) ;
DosEnterCritSec() ;
len = (len+sizeof(int)-1)/sizeof(int) ;
if( len == 0 ) len = 1 ; //?? how about read
str = malloc( len*sizeof(int) ) ;
*str = '\0' ;
DosExitCritSec() ;
BufRead(hRead, str, len*sizeof(int), &cbR) ;
lCurCol = GpiQueryColor( hps ) ;
GpiSetColor( hps, CLR_BLACK ) ;
sw = QueryTextBox( hps, strlen(str), str ) ;
switch(jmode) {
case LEFT: sw = 0; break;
case CENTRE: sw = -sw/2; break;
case RIGHT: sw = -sw; break;
}
if( bHorz ) {
ptl.x = (LONG)(x+sw) ; ptl.y = (LONG)(y-lVOffset/4) ;
}
else {
ptl.x = (LONG)x ; ptl.y = (LONG)(y+sw) ;
}
if(bEnhanced)
CharStringAt( hps, ptl.x, ptl.y, strlen( str ) , str ) ;
else
GpiCharStringAt( hps, &ptl, strlen( str ), str ) ;
GpiSetColor( hps, lCurCol ) ;
DosEnterCritSec() ;
free(str) ;
DosExitCritSec() ;
}
break ;
case 'J' : /* justify */
BufRead(hRead,&jmode, sizeof(int), &cbR) ;
break ;
case 'A' : /* text angle */
{
int ta ;
GRADIENTL grdl ;
SIZEF sizHor, sizVer ;
if( bPath ) {
GpiEndPath( hps ) ;
GpiStrokePath( hps, 1, 0 ) ;
bPath = FALSE ;
}
BufRead(hRead,&ta, sizeof(int), &cbR) ;
if( ta == 0 ) {
grdl.x = 0L ; grdl.y = 0L ;
GpiSetCharAngle( hps, &grdl ) ;
if( !bHorz ) {
bHorz = TRUE ;
}
}
else if( ta == 1 ) {
grdl.x = 0L ; grdl.y = 1L ;
GpiSetCharAngle( hps, &grdl ) ;
if( bHorz ) {
bHorz = FALSE ;
}
}
}
break ;
case 'L' : /* line type */
{
int lt, col ;
if( bPath ) {
GpiEndPath( hps ) ;
GpiStrokePath( hps, 1, 0 ) ;
bPath = FALSE ;
}
BufRead(hRead,<, sizeof(int), &cbR) ;
/* linetype = -2 axes, -1 border, 0 arrows, all to 0 */
col = lt ;
if( lt == -2 ) GpiSetLineWidthGeom( hps, DEFLW*0.85 ) ;
else if( lt == -1 ) GpiSetLineWidthGeom( hps, DEFLW*0.6 ) ;
else GpiSetLineWidthGeom( hps, linewidth ) ;
if( lt < 0 ) lt = 0 ;
lt = (lt%8);
col = (col+2)%16 ;
GpiLabel( hps, lLineTypes[lt] ) ;
lOldLine=lt ;
LType( (bLineTypes||bBW)?lt:0 ) ;
// GpiSetLineType( hps, (bLineTypes||bBW)?lLineTypes[lt]:lLineTypes[0] ) ;
if( !bBW ) { /* maintain some flexibility here in case we don't want
the model T option */
if( bColours ) GpiSetColor( hps, lCols[col] ) ;
else GpiSetColor( hps, CLR_BLACK ) ;
}
}
break ;
case 'W' : /* line width */
{
int lw ;
if( bPath ) {
GpiEndPath( hps ) ;
GpiStrokePath( hps, 1, 0 ) ;
bPath = FALSE ;
}
BufRead(hRead,&lw, sizeof(int), &cbR) ;
GpiSetLineWidthGeom( hps, DEFLW*lw/100 ) ;
linewidth = DEFLW*lw/100 ;
}
break ;
case 'D' : /* points mode */
{
int lt ;
BufRead(hRead,<, sizeof(int), &cbR) ;
/* 1: enter point mode, 0: exit */
if( bLineTypes || bBW ) {
if( lt==1) LType(0) ;
else LType( lOldLine ) ;
// if( lt == 1 ) lOldLine = GpiSetLineType( hps, lLineTypes[0] ) ;
// else GpiSetLineType( hps, lOldLine ) ;
}
// if( lt == 1 ) GpiSetLineWidthGeom( hps, 20 ) ;
// else GpiSetLineWidthGeom( hps, 50 ) ;
bDots = lt ;
}
break ;
case 'F' : /* set font */
{
int len ;
char *str ;
char font[FONTBUF] ;
BufRead(hRead,&len, sizeof(int), &cbR) ;
len = (len+sizeof(int)-1)/sizeof(int) ;
if( len == 0 ) {
SwapFont( hps, NULL ) ;
}
else {
char *p ;
str = malloc( len*sizeof(int) ) ;
BufRead(hRead, str, len*sizeof(int), &cbR) ;
p = strchr(str, ',') ;
if( p==NULL ) strcpy( font, "14" ) ;
else {
*p = '\0' ;
strcpy( font, p+1 ) ;
}
strcat( font,"." ) ;
strcat( font, str ) ;
free( str ) ;
SwapFont( hps, font ) ;
}
}
break ;
case 'O' : /* set options */
{
int len ;
char *str ;
BufRead(hRead,&len, sizeof(int), &cbR) ;
len = (len+sizeof(int)-1)/sizeof(int) ;
bWideLines = FALSE ; /* reset options */
bEnhanced = FALSE ;
if( len > 0 ) {
char *p ;
p = str = malloc( len*sizeof(int) ) ;
BufRead(hRead, str, len*sizeof(int), &cbR) ;
while( (p=strchr(p,'-')) != NULL ) {
++p ;
if( *p == 'w' ) bWideLines = TRUE ;
if( *p == 'e' ) bEnhanced = TRUE ;
++p ;
}
free( str ) ;
}
}
break ;
default : /* should handle error */
break ;
}
}
}
exitserver:
DosDisConnectNPipe( hRead ) ;
WinPostMsg( hApp, WM_CLOSE, 0L, 0L ) ;
}
static void EditLineTypes( HWND hwnd, HPS hps, BOOL bDashed )
/*
*/
{
int i, rc ;
char buf[64] ;
GpiSetDrawingMode( hps, DM_RETAIN ) ;
GpiOpenSegment( hps, iSeg ) ;
GpiSetEditMode( hps, SEGEM_REPLACE ) ;
for( i=0; i<7; i++ ) {
while( GpiSetElementPointerAtLabel( hps, lLineTypes[i] ) ) {
GpiOffsetElementPointer( hps, 1 ) ;
GpiSetLineType( hps, bDashed?lLineTypes[i]:lLineTypes[0] ) ;
}
GpiSetElementPointer( hps, 0 ) ;
}
GpiSetEditMode( hps, SEGEM_INSERT ) ;
GpiCloseSegment( hps ) ;
}
static void EditCharCell( HPS hps, SIZEF *psize )
/*
** Edit segment to change char cell (font size)
*/
{
int i ;
LONG rl, rc ;
SIZEF sizH, sizV ;
char buf[64] ;
int iVert = 0 ;
sizH = *psize ;
sizV.cx = sizH.cy ;
sizV.cy = sizH.cx ;
GpiSetDrawingMode( hps, DM_RETAIN ) ;
GpiOpenSegment( hps, iSeg ) ;
GpiSetEditMode( hps, SEGEM_REPLACE ) ;
i=0 ;
while( GpiSetElementPointer( hps, i ) ) {
rc = GpiQueryElementPointer( hps) ;
if( rc != i ) break ;
rl = GpiQueryElementType( hps, &rc, 0, NULL ) ;
if( rc == 0x34 || rc == 0x74 ) {
LONG gdata ;
GpiQueryElement( hps, 5, 4, (PBYTE)&gdata ) ;
if( gdata == 0 ) iVert = 0 ;
else iVert = 1 ;
}
else if( rc==0x33 || rc==0x03 ) GpiSetCharBox(hps, iVert?&sizV:&sizH ) ;
++i ;
}
GpiSetEditMode( hps, SEGEM_INSERT ) ;
GpiCloseSegment( hps ) ;
}
static int BufRead( HFILE hfile, void *buf, int nBytes, ULONG *pcbR )
/*
** pull next plot command out of buffer read from GNUPLOT
*/
{
ULONG ulR, ulRR ;
int rc ;
static char buffer[GNUBUF] ;
static char *pbuffer = buffer+GNUBUF, *ebuffer = buffer+GNUBUF ;
for( ; nBytes > 0 ; nBytes-- ) {
if( pbuffer >= ebuffer ) {
ulR = GNUBUF ;
rc = DosRead( hfile, buffer, ulR, &ulRR ) ;
if( rc != 0 ) return rc ;
if( ulRR == 0 ) return 1 ;
pbuffer = buffer ;
ebuffer = pbuffer+ulRR ;
}
*(char*)buf++ = *pbuffer++ ;
}
return 0L ;
}
int GetNewFont( HWND hwnd, HPS hps )
/*
** Get a new font using standard font dialog
*/
{
static FONTDLG pfdFontdlg; /* Font dialog info structure */
static int i1 =1 ;
static int iSize ;
char szPtList[64] ;
HWND hwndFontDlg; /* Font dialog window handle */
char *p ;
char szFamilyname[FACESIZE];
if( i1 ) {
strcpy( pfdFontdlg.fAttrs.szFacename, strchr( szFontNameSize, '.' ) + 1 ) ;
strcpy( szFamilyname, strchr( szFontNameSize, '.' ) + 1 ) ;
sscanf( szFontNameSize, "%d", &iSize ) ;
memset(&pfdFontdlg, 0, sizeof(FONTDLG));
pfdFontdlg.cbSize = sizeof(FONTDLG);
pfdFontdlg.hpsScreen = hps;
/* szFamilyname[0] = 0;*/
pfdFontdlg.pszFamilyname = szFamilyname;
pfdFontdlg.usFamilyBufLen = FACESIZE;
pfdFontdlg.fl = FNTS_HELPBUTTON |
FNTS_CENTER | FNTS_VECTORONLY |
FNTS_OWNERDRAWPREVIEW ;
pfdFontdlg.clrFore = CLR_BLACK;
pfdFontdlg.clrBack = CLR_WHITE;
pfdFontdlg.usWeight = FWEIGHT_NORMAL ; //5 ;
pfdFontdlg.fAttrs.usCodePage = 0;
pfdFontdlg.fAttrs.usRecordLength = sizeof(FATTRS) ;
}
sprintf( szPtList, "%d 8 10 12 14 18 24", iSize ) ;
pfdFontdlg.pszPtSizeList = szPtList ;
pfdFontdlg.fxPointSize = MAKEFIXED(iSize,0);
hwndFontDlg = WinFontDlg(HWND_DESKTOP, hwnd, &pfdFontdlg);
if( i1 ) {
pfdFontdlg.fl = FNTS_HELPBUTTON |
FNTS_CENTER | FNTS_VECTORONLY |
FNTS_INITFROMFATTRS ;
i1=0;
}
if (hwndFontDlg && (pfdFontdlg.lReturn == DID_OK)) {
iSize = FIXEDINT( pfdFontdlg.fxPointSize ) ;
sprintf( szFontNameSize, "%d.%s", iSize, pfdFontdlg.fAttrs.szFacename ) ;
return 1 ;
}
else return 0 ;
}
void SigHandler( int sig )
/*
** Handle termination signal to free up resources before
** termination.
*/
{
if( sig == SIGTERM ) {
if( bPersist ) {
DosKillThread( tidSpawn ) ;
signal( SIGTERM, SIG_ACK ) ;
return ;
}
DosEnterCritSec() ;
DosKillThread( tidSpawn ) ;
DosKillThread( tidDraw ) ;
DosExitCritSec() ;
exit(0) ;
}
}
/* disable debugging info */
#define TEXT_DEBUG(x) /* fprintf x; */
/* used in determining height of processed text */
//static float max_height, min_height;
/* process a bit of string, and return the last character used.
* p is start of string
* brace is TRUE to keep processing to }, FALSE for do one character
* fontname & fontsize are obvious
* base is the current baseline
* widthflag is TRUE if the width of this should count,
* FALSE for zero width boxes
* showflag is TRUE if this should be shown,
* FALSE if it should not be shown (like TeX \phantom)
*/
static char *starttext = NULL ;
static int textlen = 0 ;
static BOOL bText = FALSE ;
static int textwidth = 0 ;
static POINTL ptlText ;
static FILE *ff ;
static char *ParseText(HPS hps, char *p, BOOL brace, char *fontname,
int fontsize, int base, BOOL widthflag, BOOL showflag)
{
POINTL aptl[TXTBOX_COUNT] ;
BOOL bChangeFont = FALSE ;
TEXT_DEBUG((ff,"RECURSE WITH [%p] %s, %d %s %.1f %.1f %d %d\n", p, p, brace, fontname, fontsize, base, widthflag, showflag))
/* Start each recursion with a clean string */
//{FILE *ff;int i=textlen;ff=fopen("deb","a");
//for(i=0;i<textlen;i++)fputc(starttext[i], ff);fputc('\n',ff) ; fclose(ff);}
if( textlen > 0 ) {
GpiQueryTextBox( hps, textlen, starttext, TXTBOX_COUNT, aptl ) ;
if( bHorz ) textwidth += aptl[TXTBOX_BOTTOMRIGHT].x ;
else textwidth += aptl[TXTBOX_BOTTOMRIGHT].y ;
}
if( bText ) {
if(textlen > 0 ) {
GpiCharStringAt( hps, &ptlText, textlen, starttext ) ;
ptlText.x += aptl[TXTBOX_CONCAT].x + (bHorz?0:(-base)) ;
ptlText.y += aptl[TXTBOX_CONCAT].y + (bHorz?base:0) ;
}
else {
ptlText.x += (bHorz?0:(-base)) ;
ptlText.y += (bHorz?base:0) ;
}
}
textlen = 0 ;
starttext = p ;
if( fontname != NULL ) {
char szFont[FONTBUF] ;
sprintf(szFont, "%d.%s", fontsize, fontname ) ;
SwapFont( hps, szFont ) ;
bChangeFont = TRUE ;
}
if( base != 0 ) GpiSetCharBox( hps, &sizCurSubSup ) ;
for ( ; *p; ++p)
{ int shift;
switch (*p)
{
case '}' :
/*{{{ deal with it*/
if (brace) {
brace = 0 ;
break ;
}
break;
/*}}}*/
case '_' :
case '^' :
/*{{{ deal with super/sub script*/
shift = (*p == '^') ? lSupOffset : lSubOffset;
p = ParseText(hps, p+1, FALSE, NULL/*fontname*/, fontsize*0.7, base+shift, widthflag, showflag);
break;
/*}}}*/
case '{' :
{
char *savepos=NULL, save=0;
char *localfontname=fontname, ch;
char localfontbuf[FONTBUF] ;
int recode=1;
int f=fontsize;
BOOL bChangeFont = FALSE ;
char *q=localfontbuf ;
/*{{{ recurse (possibly with a new font) */
TEXT_DEBUG((ff,"Dealing with {\n"))
if (*++p == '/')
{ /* then parse a fontname, optional fontsize */
while (*++p == ' ');
if (*p=='-')
{
recode=0;
while (*++p == ' ');
}
localfontname = p;
while ((ch = *p) > ' ' && ch != '=') {
localfontname=localfontbuf ;
if(*p=='_') *q=' ' ;
else *q=*p ;
++p;++q;
}
*q = '\0' ;
FontExpand( localfontbuf ) ;
save = *(savepos=p);
if (ch == '=')
{
*p++ = '\0';
/*{{{ get optional font size*/
TEXT_DEBUG((ff,"Calling strtod(%s) ...", p))
f = strtod(p, &p);
TEXT_DEBUG((ff,"Retured %.1f and %s\n", f, p))
if (!f) f = fontsize;
TEXT_DEBUG((ff,"Font size %.1f\n", f))
/*}}}*/
}
else
{
*p++ = '\0';
f = fontsize;
}
while (*p == ' ')
++p;
if (! (*localfontname)) {
localfontname = fontname;
if( f != fontsize )
localfontname = strchr( szFontNameSize, '.' ) + 1 ;
}
}
/*}}}*/
TEXT_DEBUG((ff,"Before recursing, we are at [%p] %s\n", p, p))
p = ParseText(hps,p, TRUE, localfontname, f, base, widthflag, showflag);
TEXT_DEBUG((ff,"BACK WITH %s\n", p));
if (savepos)
/* restore overwritten character */
*savepos = save;
break;
}
case '@' :
/*{{{ phantom box - prints next 'char', then restores currentpoint */
p = ParseText(hps,++p, FALSE, NULL/*fontname*/, fontsize, base, FALSE, showflag);
break;
/*}}}*/
case '&' :
/*{{{ character skip - skips space equal to length of character(s) */
p = ParseText(hps,++p, FALSE, NULL/*fontname*/, fontsize, base, widthflag, FALSE);
break;
/*}}}*/
case '\\' :
{
char buffer[4] ; /* should need only one char.. */
char *q = buffer ;
*q = '\0' ;
ParseText(hps,q, FALSE, NULL, fontsize, base, widthflag, showflag);
/*{{{ is it an escape */
/* special cases */
if (p[1]=='\\' || p[1]=='{' || p[1]=='}')
{
*q++=p[1] ;
++p ;
}
#if 0
else if (p[1] >= '0' && p[1] <= '7')
{
/* up to 3 octal digits */
int c = 0 ;
c+=p[1];
++p;
if (p[1] >= '0' && p[1] <= '7')
{
c*=8; c+=p[1];
++p;
if (p[1] >= '0' && p[1] <= '7')
{
c*=8; c+=p[1];
++p;
}
}
*q++ = c ;
break;
}
#endif
*q = '\0' ;
textlen = 1 ;
starttext=buffer ;
ParseText(hps,q, FALSE, NULL/*fontname*/, fontsize, base, widthflag, showflag);
starttext=p+1 ;
textlen = 0 ;
/*}}}*/
}
break ;
default:
++textlen ;
/*}}}*/
}
/* like TeX, we only do one character in a recursion, unless it's
* in braces
*/
if (!brace) break ;
}
if( textlen > 0 ) {
GpiQueryTextBox( hps, textlen, starttext, TXTBOX_COUNT, aptl ) ;
if( widthflag ) {
if( bHorz ) textwidth += aptl[TXTBOX_BOTTOMRIGHT].x ;
else textwidth += aptl[TXTBOX_BOTTOMRIGHT].y ;
}
}
if( bText ) {
if( textlen > 0 ) {
if( showflag)
GpiCharStringAt( hps, &ptlText, textlen, starttext ) ;
if( widthflag ) {
ptlText.x += aptl[TXTBOX_CONCAT].x ;
ptlText.y += aptl[TXTBOX_CONCAT].y ;
}
}
if( base != 0 ) {
ptlText.x -= (bHorz?0:(-base)) ;
ptlText.y -= (bHorz?base:0) ;
}
}
if( bChangeFont ) {
SwapFont( hps, NULL ) ;
bChangeFont = FALSE ;
}
if( base != 0 ) GpiSetCharBox( hps, &sizBaseFont ) ;
textlen = 0 ;
starttext = p+1 ;
return p;
}
static void CharStringAt(HPS hps, int x, int y, int len, char *str)
{
/* flush any pending graphics (all the XShow routines do this...) */
char *fontname ;
int fontsize ;
if (!strlen(str))
return;
/* set up the globals */
ptlText.x = x ;
ptlText.y = y ;
bText = TRUE ;
starttext = NULL ;
textlen = 0 ;
textwidth = 0 ;
sscanf( szFontNameSize, "%d", &fontsize ) ;
fontname = strchr( szFontNameSize, '.' ) + 1 ;
while (*(str = ParseText(hps, str, TRUE, NULL,
fontsize,
0.0, TRUE, TRUE)));
}
static int QueryTextBox( HPS hps, int len, char *str )
{
char *fontname ;
int fontsize ;
if (!strlen(str))
return 0 ;
/* set up the globals */
bText = FALSE ;
starttext = NULL ;
textlen = 0 ;
textwidth = 0 ;
sscanf( szFontNameSize, "%d", &fontsize ) ;
fontname = strchr( szFontNameSize, '.' ) + 1 ;
while (*(str = ParseText(hps, str, TRUE, NULL,
fontsize,
0.0, TRUE, TRUE)));
return textwidth ;
}
void FontExpand( char *name )
{
if ( strcmp(name,"S")==0 ) strcpy( name, "Symbol Set" ) ;
else if( strcmp(name,"H")==0 ) strcpy( name, "Helvetica" ) ;
else if( strcmp(name,"T")==0 ) strcpy( name, "Times New Roman" ) ;
else if( strcmp(name,"C")==0 ) strcpy( name, "Courier" ) ;
}
/*=======================================*/
static POINTL pCur ;
static int iLinebegin = 1 ;
static int iLtype = 0 ;
static int iState = 0 ;
static double togo = 0.0 ;
static int iPatt[8][9]
= {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 300, 200, -1, 0, 0, 0, 0, 0, 0 },
{ 150, 150, -1, 0, 0, 0, 0, 0, 0 },
{ 300, 200, 150, 200, -1, 0, 0, 0, 0 },
{ 500, 200, -1, 0, 0, 0, 0, 0, 0 },
{ 300, 200, 150, 200, 150, 200, -1, 0, 0 },
{ 300, 200, 150, 200, 150, 200, 150, 200, -1 },
{ 500, 200, 150, 200, -1, 0, 0, 0, 0 }
} ;
void LMove( HPS hps, POINTL *p )
{
double ds, dx, dy ;
if( iLinebegin ) {
pCur = *p ;
GpiMove( hps, p ) ;
}
else if( iLtype == 0 ) GpiMove( hps, p ) ;
else {
dx = p->x - pCur.x ;
dy = p->y - pCur.y ;
ds = sqrt( dx*dx + dy*dy ) ;
dx /= ds ; dy /= ds ;
while( ds > 0.0 ) {
if( ds < togo ) {
togo -= ds ;
ds = 0.0 ;
GpiMove( hps, p ) ;
pCur = *p ;
}
else {
POINTL pn ;
pn.x = pCur.x + togo * dx ;
pn.y = pCur.y + togo * dy ;
GpiMove( hps, &pn ) ;
pCur = pn ;
ds -= togo ;
iState++ ;
if( iPatt[iLtype][iState] < 0 ) {
togo = iPatt[iLtype][0] ;
iState = 0 ;
}
else togo = iPatt[iLtype][iState] ;
}
}
}
}
void LLine( HPS hps, POINTL *p )
{
double ds, dx, dy ;
if( iLinebegin ) iLinebegin = 0 ;
if( iLtype == 0 ) GpiLine( hps, p ) ;
else {
dx = p->x - pCur.x ;
dy = p->y - pCur.y ;
ds = sqrt( dx*dx + dy*dy ) ;
dx /= ds ; dy /= ds ;
while( ds > 0.0 ) {
if( ds < togo ) {
togo -= ds ;
ds = 0.0 ;
if( iState&1 ) GpiMove( hps, p ) ;
else GpiLine( hps, p ) ;
pCur = *p ;
}
else {
POINTL pn ;
pn.x = pCur.x + togo * dx ;
pn.y = pCur.y + togo * dy ;
if( iState&1 ) GpiMove( hps, &pn ) ;
else GpiLine( hps, &pn ) ;
pCur = pn ;
ds -= togo ;
iState++ ;
if( iPatt[iLtype][iState] < 0 ) {
togo = iPatt[iLtype][0] ;
iState = 0 ;
}
else togo = iPatt[iLtype][iState] ;
}
}
}
}
void LType( int iType )
{
iLinebegin = 1 ;
if( iType > 7 ) iType = 0 ;
iLtype = iType ;
iState = 0 ;
togo = iPatt[iLtype][0] ;
}