[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/gnuplot/gnuplot/master/src/os2/gclient.c [Back]  [Original]

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

    PROGRAM: Gnupmdrv

    MODULE:  gclient.c

    This file contains the client window procedures for Gnupmdrv

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

/* PM driver for GNUPLOT */

/*[
 * Copyright 1992, 1993, 1998, 2004, 2019-2021   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
 *
 *
 * CONTRIBUTIONS:
 *
 *   Petr Mikulik  (see PM labels)
 *       - menu item to keep aspect ratio on/off (October 1997)
 *       - mouse support (1998, 1999); changes made after gnuplot 3.7.0.5:
 *	    - use gnuplot's pid in the name of shared memory (11. 5. 1999)
 *	    - mouse in maps; distance in polar coords (14. 5. 1999)
 *	    - event semaphore for sending data via shared memory;
 *	      zooming completely revised;
 *	      remap keys in 'case WM_CHAR';
 *	      Ctrl-C for breaking long drawings;
 *	      new menu items under 'Mouse' and 'Utilities' (August 1999)
 *	- rewrite of mouse support for the new scheme common with X11
 *	      (October 1999 - January 2000)
 *      - pm3d stuff (since January 1999)
 *
 *   Franz Bakan
 *       - communication gnupmdrv -> gnuplot via shared memory (April 1999)
 *       - date and time on x axis (August 1999)
 *
 *   Bastian Maerkisch
 *       RGB colors, pattern fill, images, fixes (2004, 2005)
 *       dashed lines, bold/italic text, fill style for boxes and polygons, fixes (2019)
 *       line-to-ruler, zoom-coordinates, cleanup, fixes (2021)
 *
 */

#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
#ifdef HAVE_EXCEPTQ
# define INCL_DOSEXCEPTIONS
# define INCL_DOSMODULEMGR
#endif
#define INCL_DOSQUEUES
#define INCL_WINSWITCHLIST
#define INCL_GPIPRIMITIVES
#define INCL_GPILCIDS
#include 
/* Warning: the OS/2 headers already define LT_DEFAULT
            which conflicts with our definition. */
#undef LT_DEFAULT

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "config.h"
#include "version.c" /* directly include version information */
#include "term_api.h"
#include "gnupmdrv.h"
#include "pm_msgs.h"
#include "mousecmn.h"
/* Finally, include the common mousing declarations and routines: */
#include "gpexecute.h"


/*==== m i s c e l l a n e o u s =============================================*/

/* Bug report #570  (Feb. 2008)
   The standard font selection dialog is somehow broken after saving options.
   (Feb. 2021) For newer OS/2 versions, this seems no longer be the case, but
   you can still use the font palette dialog instead.
*/
#define STANDARD_FONT_DIALOG 1

/*==== d e b u g g i n g =====================================================*/

#ifdef HAVE_EXCEPTQ
# include 
/* missing definition */
BOOL    LoadExceptq(EXCEPTIONREGISTRATIONRECORD* pExRegRec,
                    const char* pOpts, const char* pInfo);
#endif
#ifdef HAVE_PMPRINTF
# include 
#endif
#define DEBUG_IMAGE(a) // PmPrintf a
#define DEBUG_COLOR(a) // PmPrintf a
#define DEBUG_FONT(a) // PmPrintf a
#define DEBUG_LINES(a) // PmPrintf a
#define DEBUG_LAYER(a) // PmPrintf a
#define TEXT_DEBUG(x) // PmPrintf x

/*==== 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_RED,
    CLR_GREEN,
    CLR_BLUE,
    CLR_PINK,
    CLR_CYAN,
    CLR_BROWN,
    CLR_YELLOW,
    CLR_DARKBLUE,
    CLR_DARKRED,
    CLR_DARKGREEN,
    CLR_DARKCYAN,
    CLR_DARKPINK,
    CLR_PALEGRAY,
    CLR_WHITE
};

static BOOL bCols_init = FALSE;

/* Note that there are 16 colours used for drawing. The two more
   entries in this array were added by Ilya to avoid drawing white
   line on white background. */
#define nColors 16
static LONG alColourTable[nColors + 2];

static BOOL bPMPaletteMode = TRUE; /* do we use PM palette manager? */

/* RGB equivalents of all normal CLR_xxx colour constants
   Note: First entry corresponds to CLR_WHITE, which is negative (-2)!
*/
static LONG rgb_colors[18];
/* macro to facilitate translation */
#define RGB_TRANS(v) rgb_colors[(v)-CLR_WHITE]

/* A value of 0 indicates direct rgb colors without palette */
#define   RGB_PALETTE_SIZE 0    /* size of the 'virtual' palette used for
				   translation of index to RGB value */

/* GNUBUF is the size of the buffer for the data stream from gnuplot.
   Requests larger than this are split. By default, we use 128kB. */
#define   GNUBUF    131072      /* buffer for gnuplot commands */
#define   PIPEBUF   4096        /* size of pipe buffers */

#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     20

static HDC      hdcScreen;
static HPS      hpsScreen;     /* screen pres. space */
static int      iSeg = 1;

static HSWITCH hSwitch = 0;    /* switching between windows */
static SWCNTRL swGnu;

static BOOL     bColours = TRUE;
static BOOL     bShellPos = FALSE;
static BOOL     bPopFront = TRUE;
static BOOL     bKeepRatio = TRUE;

static double   multLineHor  = 1.; /* Horizontal and vertical spacing shifts */
static double   multLineVert = 0.; /* for multiline prints.		    */

static int	codepage = 0;

static int 	ulMouseSprintfFormatItem = IDM_MOUSE_FORMAT_XcY;
static const  char  *SetDataStyles[] = {
    "boxes", "dots", "fsteps", "histeps", "impulses",
    "lines", "linespoints", "points", "steps"
};

static ULONG    ulShellPos[4];
static PAUSEDATA pausedata = {sizeof(PAUSEDATA), NULL, NULL};
static char     szInitialFontNameSize[FONTBUF] = INITIAL_FONT;
static int      iInitialFontSize;
static char     *szInitialFontName;
static char     szFontNameSize[FONTBUF];	/* default name and size, format: "10.Helvetica" */
static char	szCurrentFontNameSize[FONTBUF];	/* currently selected font */
static unsigned fontscale = 100;	/* scaling factor for font size in percent */
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 ULONG    ulPauseItem  = IDM_PAUSEDLG;

static HWND     hSysMenu;

            /* stuff for screen-draw thread control */

static TID     tidDraw, tidSpawn;

static BOOL    breakDrawing = FALSE;
            /* //PM flag for stopping (long) drawings */

            /* 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;

/* useMouse is set when user switches mousing on, e.g. the mouse is allowed */
static BOOL useMouse = TRUE;

/* gnuplot's PM terminal sends GR_MOUSECAPABLE message from its init routine, which
   sets the variable below. Then we are sure that we talk to a mouse-capable
   terminal and can read the mouse data from the pipe.
   Non-mouseable versions of PM terminal or non-gnuplot programs using
   gnupmdrv will let this variable unset, thus no mousing occurs.
*/
static BOOL mouseTerminal = FALSE;

/* Lock (hide) mouse when building the plot (redrawing screen).
   Otherwise gnupmdrv would crash when trying to display mouse position
   in a window not yet plotted.
*/
static BOOL lock_mouse = TRUE;

/* Status of zoom box */
static struct Zoombox {
    BOOL on;		/* set during zooming */
    POINTL from, to;		/* corners of the zoom box */
    char * text1, * text2;	/* texts in the corners (i.e. positions) */
} zoombox = { FALSE, {0,0}, {0,0}, NULL, NULL };

/* Structure for the ruler: on/off, position,... */
static struct {
   BOOL on;
   int x, y;  /* ruler position */
} ruler = { 0, 0, 0 };

/* Status of the line from ruler to cursor */
static struct {
    BOOL on;	/* ruler line active ? */
    int x, y;	/* ruler line end position (previous cursor position) */
} ruler_lineto = { FALSE, 0, 0 };

// Pointer definition
HWND hptrDefault, hptrCrossHair, hptrScaling,
    hptrRotating, hptrZooming, hptrCurrent;

// After passing gpPMmenu in PM_pipe and SET_GRAPHICS, it seems not to be possible
// to update the menu. Thus this flag is set on and menu is updated
// afterwards.
struct t_gpPMmenu gpPMmenu;
BOOL gpPMmenu_update_req = FALSE;

// colours of mouse-relating drawings (CLR_DEFAULT is not allowed!)
#define COLOR_MOUSE    CLR_BLACK    // mouse position
#define COLOR_ANNOTATE CLR_BLACK    // annotating strings (MB3)
#define COLOR_RULER    CLR_DARKPINK // colour of the ruler
#define COLOR_ERROR    CLR_RED      // colour of error messages

static enum JUSTIFY jmode;

static SIZEF sizBaseSubSup;
static SIZEF sizCurSubSup;
static SIZEF sizCurFont;
static long lVOffset = 0;
static SIZEF sizBaseFont;

static struct _ft {
    char *name;
    int   codepage;
    BOOL  bold;
    BOOL  italic;
    LONG  lcid;
} tabFont[256] = {
    {NULL, 0, FALSE, FALSE, 0L},
    {NULL}
};

typedef struct _plotlist {
    int no;	   // plot number
    unsigned plot; // segment number of plot
    unsigned plot1; // segment number of plot
    unsigned key;  // segment number of key
    unsigned key1;  // segment number of key
    struct _plotlist *next;
} plotlist;
static plotlist * plots = NULL;

typedef struct image_list_entry {
    PBITMAPINFO2 pbmi;
    PBYTE image;
    struct image_list_entry *next;
} image_list_entry;
static image_list_entry *image_list = NULL;


/*==== 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     SelectFont(HPS, char *);
static void     SwapFont(HPS, char *);
static void     CopyToClipBrd(HWND);
static void     ReadGnu(void*);
static void     SetFillStyle(HPS hps, int style);
static HPS      InitScreenPS(void);
static APIRET   BufRead(HFILE, void*, int, PULONG);
static BOOL     GetNewFont(HWND, HPS);
void            SigHandler(int);
static void     FontExpand(char *);
#ifdef PM_KEEP_OLD_ENHANCED_TEXT
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 *);
#endif
static void     LMove(HPS hps, POINTL *p);
static void     LLine(HPS hps, POINTL *p);
static int      LType(int iType);

/* Functions related to mouse processing */
static void     TextToClipboard(PCSZ);
static void     GetMousePosViewport(HWND hWnd, int *mx, int *my);
static void     MousePosToViewport(int *x, int *y, SHORT mx, SHORT my);
static void     gpPMmenu_update(void);
static void     ResetStatusLineText(void);
static void     DisplayStatusLine();
static void     UpdateStatusLine(char *text);
static void     DrawMouseText(HPS hps, PPOINTL pt, char * text, LONG len);
static void     DrawZoomBox(void);
static void     DrawRuler(void);
static void     DrawRulerLineTo(void);
static BOOL     modify_segment(HPS hps, unsigned seg, unsigned op);

#define IGNORE_MOUSE (!mouseTerminal || !useMouse || lock_mouse)
/*  don't react to mouse in the event handler, and avoid some crashes */

/* Drag'n'Drop support from PMEmacs */
struct drop {
    unsigned long cookie;
    unsigned len;
    char str[CCHMAXPATH];
};


/*==== c o d e ===============================================================*/

/* Our own versions of strlcpy and strlcat, required only for EMX. */
#ifndef __KLIBC__
#undef strlcpy
static size_t
strlcpy(char *dst, const char *src, size_t size)
{
    size_t len = strlen(src);
    if (size > 0) {
	strncpy(dst, src, size);
	if (len >= size)
	    dst[size - 1] = NUL;
    }
    return len;
}

#undef strlcat
size_t
strlcat(char *dst, const char *src, size_t size)
{
    size_t len = strlen(dst);
    return strlcpy(dst + len, src, size - len) + len;
}
#endif


/* An object is being dragged over the client window.  Check whether
   it can be dropped or not. */

void
report_error(HWND hWnd, char* s)
{
      HPS hps;
      POINTL pt;
      RECTL rc;

      hps = WinGetPS(hWnd);
      GpiSetMix(hps, FM_OVERPAINT);
      /* clear the rectangle below the text */
      /* GpiSetColor(hps, RGB_TRANS(CLR_CYAN)); */
      GpiSetColor(hps, RGB_TRANS(CLR_BACKGROUND));
      pt.x = 0;
      pt.y = 0;
      GpiMove(hps,&pt);
      /* clear the whole line */
      GpiQueryPageViewport(hpsScreen,&rc);
      pt.x = rc.xRight;
      pt.y = 16;
      GpiBox(hps, DRO_FILL, &pt, 0,0);
      /* now write the mouse position on the screen */
      GpiSetColor(hps, RGB_TRANS(COLOR_ERROR)); /* set text color */
      GpiSetCharMode(hps,CM_MODE1);

      pt.x = 2;
      pt.y = 2;
      GpiCharStringAt(hps,&pt,(long)strlen(s),s);
      WinReleasePS(hps);
}


MRESULT
drag_over(HWND hWnd, PDRAGINFO pDraginfo)
{
    PDRAGITEM pditem;
    USHORT indicator, operation;

/* Redefine this macro for debugging. */
#define DRAG_FAIL(x) report_error(hWnd,x)

    indicator = DOR_NODROPOP; operation = DO_COPY;
    if (!DrgAccessDraginfo(pDraginfo))
	DRAG_FAIL("DrgAccessDraginfo failed");
    else if (!(pDraginfo->usOperation == DO_DEFAULT
	       || pDraginfo->usOperation == DO_COPY))
	DRAG_FAIL("Invalid operation");
    else if (DrgQueryDragitemCount(pDraginfo) < 1)
	DRAG_FAIL("Invalid count");
    else {
	pditem = DrgQueryDragitemPtr(pDraginfo, 0);
	if (!(pditem->fsSupportedOps & DO_COPYABLE))
	    DRAG_FAIL("Not copyable");
	else if (!DrgVerifyRMF(pditem, "DRM_OS2FILE", NULL))
	    DRAG_FAIL("DrgVerifyRMF failed");
	else {
	    /* The object can be dropped (copied). */
	    indicator = DOR_DROP; operation = DO_COPY;
	}
    }
    DrgFreeDraginfo(pDraginfo);
    return (MRFROM2SHORT(indicator, operation));
}


/* An object is dropped on the client window. */

MRESULT
drag_drop(HWND hwnd, PDRAGINFO pDraginfo)
{
  PDRAGITEM pditem;
  POINTL ptl;
  char name[CCHMAXPATH];
  char path[CCHMAXPATH];
  char *p;
  int count, idx, len;

  DrgAccessDraginfo(pDraginfo);
  ptl.x = pDraginfo->xDrop; ptl.y = pDraginfo->yDrop;
  WinMapWindowPoints(HWND_DESKTOP, hwnd, &ptl, 1);
  count = DrgQueryDragitemCount(pDraginfo);
  for (idx = 0; idx < count; ++idx) {
      pditem = DrgQueryDragitemPtr(pDraginfo, idx);
      DrgQueryStrName(pditem->hstrContainerName, sizeof(path), path);
      DrgQueryStrName(pditem->hstrSourceName, sizeof(name), name);
      DrgSendTransferMsg(pditem->hwndItem, DM_ENDCONVERSATION,
			 MPFROMLONG(pditem->ulItemID),
			 MPFROMSHORT(DMFL_TARGETSUCCESSFUL));
      len = strlen(path);
      if (len >= 1 && strchr("\\/:", path[len-1]) == NULL)
	  path[len++] = '/';
      if (len + strlen(name) + 1  0x%x", (int)c, pm3d_color));
		break;
	    }

	    case GR_SET_RGBCOLOR :
	    {
		int rgb_color;

		FLUSHPATH(hps, "GR_SET_RGBCOLOR");

		BufRead(hRead, &rgb_color, sizeof(rgb_color), &cbR);
		/* ignore alpha value */
		rgb_color &= 0x00ffffff;

		// monochrome mode:  map to gray
		if (!bColours) {
		    int r = (rgb_color >> 16) & 0xff;
		    int g = (rgb_color >>  8) & 0xff;
		    int b = (rgb_color      ) & 0xff;
		    int luma = (r * 30 + g * 59 + b * 11) / 100;
		    rgb_color = (luma bRed;
			    int g = pRGB->bGreen;
			    int b = pRGB->bBlue;
			    int luma = (r * 30 + g * 59 + b * 11) / 100;
			    pRGB->bRed = pRGB->bGreen = pRGB->bBlue = luma;
			    pImage += 3;
			}
			pImage += pad_bytes;
		    }
		}

		points[0].x = corner[0].x;
		points[0].y = corner[1].y;
		points[1].x = corner[1].x;
		points[1].y = corner[0].y;
		points[2].x = points[2].y = 0;
		points[3].x = M;
		points[3].y = N;

		// construct a clip path
		clip.x = corner[2].x;
		clip.y = corner[2].y;
		GpiMove(hps, &clip);
		GpiBeginPath(hps, 1);
		clip.x = corner[3].x;
		clip.y = corner[3].y;
		GpiBox(hps, DRO_OUTLINE, &clip, 0, 0);
		GpiEndPath(hps);
		GpiSetClipPath(hps, 1, SCP_AND);

		pbmi = (PBITMAPINFO2) calloc(sizeof(BITMAPINFOHEADER2), 1);
		pbmi->cbFix = sizeof(BITMAPINFOHEADER2);
		pbmi->cx = M;
		pbmi->cy = N;
		pbmi->cPlanes = 1;
		pbmi->cBitCount = 24;
		pbmi->ulCompression = BCA_UNCOMP;

		if (*buff == GR_RGBA_IMAGE) {
		    pbmi2 = (PBITMAPINFO2) calloc(sizeof(BITMAPINFOHEADER2) + 255 * sizeof(RGB2), 1);
		    memcpy(pbmi2, pbmi, sizeof(BITMAPINFOHEADER2));
		    pbmi2->cBitCount = 8;
		    /* The color table maps alpha values to binary transparency. */
		    pbmi2->argbColor[0xff].bBlue  = 0xff;
		    pbmi2->argbColor[0xff].bGreen = 0xff;
		    pbmi2->argbColor[0xff].bRed   = 0xff;
#if 1
		    /* Stamp out the mask first, then draw the image.
		       This actually relies on the color of transparent pixels being set to black,
		       which we don't do. But source images are likely that way already. */
		    hits = GpiDrawBits(hps, mask, pbmi2, 4, points, ROP_SRCAND, BBO_IGNORE);
		    hits = GpiDrawBits(hps, image, pbmi, 4, points, ROP_SRCPAINT, BBO_IGNORE);
#else
		    /* Better version, which does not require image manipulation. But it is slower
		       and causes more flicker:
		       XOR with image, stamp out mask, XOR with image again. */
		    hits = GpiDrawBits(hps, image, pbmi, 4, points, ROP_SRCINVERT, BBO_IGNORE);
		    hits = GpiDrawBits(hps, mask, pbmi2, 4, points, ROP_SRCAND, BBO_IGNORE);
		    hits = GpiDrawBits(hps, image, pbmi, 4, points, ROP_SRCINVERT, BBO_IGNORE);
#endif
		} else {
		    hits = GpiDrawBits(hps, image, pbmi, 4, points, ROP_SRCCOPY, BBO_IGNORE);
		}

		if (hits == GPI_ERROR) {
		    PERRINFO perriBlk = WinGetErrorInfo(hab);
		    if (perriBlk) {
			PSZ pszOffset, pszErrMsg;
			pszOffset = ((PSZ)perriBlk) + perriBlk->offaoffszMsg;
			pszErrMsg = ((PSZ)perriBlk) + *((PULONG)pszOffset);
			if (perriBlk->cDetailLevel >= 2)
				pszErrMsg = ((PSZ)perriBlk) + ((PULONG)pszOffset)[1];
			DEBUG_IMAGE(("GpiDrawBits code=%x msg=%s", perriBlk->idError, pszErrMsg));
			// DEBUG_IMAGE(("GpiDrawBits code=%x", perriErrorInfo->idError));
			WinFreeErrorInfo(perriBlk);
		    }
		}

		// reset clip region
		GpiSetClipPath(hps, 0, SCP_RESET);

		/* We have to keep the image data and header in memory since
		   we use retained graphics. */
		ile = (image_list_entry *) malloc(sizeof(image_list_entry));
		ile->next = image_list;
		ile->pbmi = pbmi;
		ile->image = image;
		image_list = ile;

		if (*buff == GR_RGBA_IMAGE) {
		    ile = (image_list_entry *) malloc(sizeof(image_list_entry));
		    ile->next = image_list;
		    ile->pbmi = pbmi2;
		    ile->image = mask;
		    image_list = ile;
		}
		break;
	    }

	    case SET_RULER : /* set_ruler(int x, int y) term API: x pixels coordinates */
		    pt.x = (long int) ((x * (double) rc.xRight) / (double) GNUXPAGE);
		    pt.y = (long int) ((x * (double) rc.yTop) / (double) GNUYPAGE);
		    WinMapWindowPoints(hApp, HWND_DESKTOP, &pt, 1);
		    WinSetPointerPos(HWND_DESKTOP, pt.x, pt.y);
		    break;
		}
		case -1: /* start zooming; zooming cursor */
		    zoombox.on = TRUE;
		    zoombox.from.x = zoombox.to.x = x;
		    zoombox.from.y = zoombox.to.y = y;
		    break;
		case 0:  /* standard cross-hair cursor */
		    WinSetPointer(HWND_DESKTOP,
				  hptrCurrent =
				  (useMouse ? hptrCrossHair:hptrDefault));
		    break;
		case 1:  /* cursor during rotation */
		    WinSetPointer(HWND_DESKTOP, hptrCurrent = hptrRotating);
		    break;
		case 2:  /* cursor during scaling */
		    WinSetPointer(HWND_DESKTOP, hptrCurrent = hptrScaling);
		    break;
		case 3:  /* cursor during zooming */
		    WinSetPointer(HWND_DESKTOP, hptrCurrent = hptrZooming);
		    break;
		}
		if (c >= 0 && zoombox.on) { /* erase zoom box */
		    DrawZoomBox();
		    zoombox.on = FALSE;
		}
		if (c >= 0 && ruler_lineto.on) { /* erase ruler line */
		    DrawRulerLineTo();
		    ruler_lineto.on = FALSE;
		}
		break;
	    }

	    case SET_CLIPBOARD :  /* set_clipboard(const char s[]) term API */
	    {
		int len;
		char *s;

		BufRead(hRead, &len, sizeof(int), &cbR);
		s = malloc(len + 1);
		BufRead(hRead,s, len+1, &cbR);
		TextToClipboard(s);
		free(s);
		break;
	    }

	    case SET_MENU :   /* update menu according to the gnuplot core
			  * settings, e.g.(un)checking menu items */
		if (mouseTerminal) {
		    /* we are connected to mouseable terminal */
		    BufRead(hRead, &gpPMmenu, sizeof(gpPMmenu), &cbR);
		    if (useMouse != gpPMmenu.use_mouse)
			WinSetPointer(HWND_DESKTOP,
				      hptrCurrent = (gpPMmenu.use_mouse
						     ?hptrCrossHair
						     :hptrDefault));
		    useMouse = gpPMmenu.use_mouse;
		    gpPMmenu_update_req = TRUE;
		}
		break;

	    case GR_MOUSECAPABLE :
		/* notification of being connected to a mouse-enabled terminal */
		mouseTerminal = TRUE;
		break;

	    default :
		/* This should not happen if the versions of gnuplot and gnupmdrv match. */
#ifdef HAVE_PMPRINTF
		PmPrintf("Unknown command: 0x%02x '%c'", *buff, *buff);
#endif
		break;
	    }
	}
    }
    DosDisConnectNPipe(hRead);
    WinPostMsg(hApp, WM_CLOSE, 0L, 0L);

#ifdef HAVE_EXCEPTQ
    UninstallExceptq(&exRegRec);
#endif
}


static void
SetFillStyle(HPS hps, int style)
{
    switch (style & 0x0f) {
    case FS_SOLID:
    case FS_TRANSPARENT_SOLID:
    {
	/* style == 1 --> fill with intensity according to filldensity */
	static const ULONG patternlist[] = {
	    PATSYM_NOSHADE, PATSYM_DENSE8, PATSYM_DENSE7,
	    PATSYM_DENSE6, PATSYM_DENSE5, PATSYM_DENSE4,
	    PATSYM_DENSE3, PATSYM_DENSE2, PATSYM_DENSE1,
	    PATSYM_SOLID
	};
	unsigned pattern;

	pattern = (unsigned) trunc(9 * ((style >> 4) / 100.0) + 0.5);
	if (pattern >= 10)
	    pattern = 9; /* only 10 patterns in list */
	GpiSetMix(hps, FM_OVERPAINT);
	if ((style & 0x0f) == FS_SOLID)
	    GpiSetBackMix(hps, BM_OVERPAINT);
	else
	    GpiSetBackMix(hps, BM_LEAVEALONE);
	GpiSetPattern(hps, patternlist[pattern]);
	break;
    }

    case FS_PATTERN:
    case FS_TRANSPARENT_PATTERN:
    {
	/* style == 2 --> fill with pattern according to fillpattern */
	/* the upper 3 nibbles of 'style' contain pattern number */
	static const ULONG patternlist[] = {
	    PATSYM_NOSHADE, PATSYM_DIAGHATCH,
	    PATSYM_HATCH, PATSYM_SOLID,
	    PATSYM_DIAG4, PATSYM_DIAG2,
	    PATSYM_DIAG3, PATSYM_DIAG1
	};
	unsigned pattern;

	pattern = (style >> 4) % 8;
	GpiSetMix(hps, FM_OVERPAINT);
	if ((style & 0x0f) == FS_PATTERN)
	    GpiSetBackMix(hps, BM_OVERPAINT);
	else
	    GpiSetBackMix(hps, BM_LEAVEALONE);
	GpiSetPattern(hps, patternlist[pattern]);
	break;
    }

    case FS_EMPTY:
    default:
	/* style == 0 or unknown --> fill with background color */
	GpiSetMix(hps, FM_OVERPAINT);
	GpiSetBackMix(hps, BM_OVERPAINT);
	GpiSetPattern(hps, PATSYM_SOLID);
	break;

    }
}


/*
** pull next plot command out of buffer read from GNUPLOT
*/
static APIRET
BufRead(HFILE hfile, void *buf, int nBytes, ULONG *pcbR)
{
    ULONG ulR, ulRR;
    int rc;
    static char buffer[GNUBUF];
    static char *pbuffer = buffer + GNUBUF;
    static char *ebuffer = buffer + GNUBUF;

    for (; nBytes > 0; nBytes--) {
	if (pbuffer >= ebuffer) {
	    ulR = GNUBUF;
	    rc = DosRead(hfile, buffer, ulR, &ulRR);
#ifdef HAVE_PMPRINTF
	    if ((rc != NO_ERROR && rc != ERROR_MORE_DATA) || (ulRR == 0))
		PmPrintf("BufRead error: %i bytes read: %li", rc, ulRR);
#endif
	    // ERROR_MORE_DATA signals that there's more data in the pipe
	    if (rc != NO_ERROR && rc != ERROR_MORE_DATA)
		return rc;
	    if (ulRR == 0)
		return ERROR_NO_DATA;
	    pbuffer = buffer;
	    ebuffer = pbuffer + ulRR;
	}
	*(char*)buf++ = *pbuffer++;
    }
    /* FIXME: pcbR is neither set nor used anywhere */
    return NO_ERROR;
}


#ifdef STANDARD_FONT_DIALOG

/*
** Get a new font using standard font dialog
*/
BOOL
GetNewFont(HWND hwnd, HPS hps)
{
    static FONTDLG pfdFontdlg; /* Font dialog info structure */
    int iSize;
    char szPtList[64];
    HWND hwndFontDlg;          /* Font dialog window handle */
    char szFamilyName[FONTBUF];
    char * p, * q;
    BOOL bold = FALSE;
    BOOL italic = FALSE;

    // determine font size
    iSize = atoi(szFontNameSize);

    // determine family name
    p = strchr(szFontNameSize, '.');
    if (p == NULL)
	strlcpy(szFamilyName, szFontNameSize, FONTBUF);
    else
	strlcpy(szFamilyName, p + 1, FONTBUF);
    if (szFamilyName[0] == NUL) {
	// apply default font
	strlcpy(szFamilyName, szInitialFontName, FONTBUF);
    }

    // determine attributes, strip
    p = strstr(szFamilyName, ":Bold");
    if (p == NULL)
	p = strstr(szFamilyName, " Bold");
    q = strstr(szFamilyName, ":Italic");
    if (q == NULL)
	q = strstr(szFamilyName, " Italic");
    bold = (p != NULL);
    italic = (q != NULL);
    if (p != NULL) *p = NUL;
    if (q != NULL) *q = NUL;

    DEBUG_FONT(("Font dialog init: %ipt \"%s\"%s%s", iSize, 	szFamilyName,
		bold ? ", bold" : "", italic ? ", italic" : ""));

    memset(&pfdFontdlg, 0, sizeof(FONTDLG));
    pfdFontdlg.cbSize = sizeof(FONTDLG);
    pfdFontdlg.hpsScreen = hps;
    pfdFontdlg.pszFamilyname = szFamilyName;
    pfdFontdlg.usFamilyBufLen = FONTBUF;
    pfdFontdlg.fl = FNTS_HELPBUTTON |
	FNTS_CENTER | FNTS_VECTORONLY;
    pfdFontdlg.flType = FTYPE_ROUNDED_DONT_CARE | FTYPE_OBLIQUE_DONT_CARE |
	(italic ? FTYPE_ITALIC : 0);
    pfdFontdlg.clrFore = CLR_BLACK;
    pfdFontdlg.clrBack = CLR_WHITE;
    pfdFontdlg.usWeight = bold ? FWEIGHT_BOLD : FWEIGHT_NORMAL;
    pfdFontdlg.fAttrs.usRecordLength = sizeof(FATTRS);
    pfdFontdlg.fAttrs.usCodePage = codepage;

    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 (hwndFontDlg && (pfdFontdlg.lReturn == DID_OK)) {
	bold = (pfdFontdlg.usWeight == FWEIGHT_BOLD);
	italic = (pfdFontdlg.flType & FTYPE_ITALIC);
	iSize = FIXEDINT(pfdFontdlg.fxPointSize);
	snprintf(szFontNameSize, FONTBUF, "%d.%s%s%s",
		iSize, pfdFontdlg.pszFamilyname,
		bold ? ":Bold" :  "", italic ? ":Italic" : "");
	DEBUG_FONT(("Font selection: %s", szFontNameSize));
	return TRUE;
    } else {
	return FALSE;
    }
}

#else

/*
** Get a new font using standard font palette
*/
BOOL
GetNewFont(HWND hwnd, HPS hps)
{
    HOBJECT hObject;
    ULONG ulView = 0; /* OPEN_DEFAULT */
    BOOL fSuccess = FALSE;

    hObject = WinQueryObject("");
    if (hObject != NULLHANDLE)
	fSuccess = WinOpenObject(hObject, ulView, TRUE);
    return fSuccess;
}

#endif /* STANDARD_FONT_DIALOG */


/*
**  Handle termination signal to free up resources before
**  termination.
*/
void SigHandler(int sig)
{
    if (sig == SIGTERM) {
        if (bPersist) {
            DosKillThread(tidSpawn);
            return;
	}
        DosEnterCritSec();
        DosKillThread(tidSpawn);
        DosKillThread(tidDraw);
        DosExitCritSec();
        exit(0);
    }
}


#ifdef PM_KEEP_OLD_ENHANCED_TEXT

/* 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 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(("RECURSE WITH [%p] %s, %d %s %d %d %d %d\n",
		p, p, brace, fontname, fontsize, base,
		widthflag, showflag));

    /* Start each recursion with a clean string */
    if (textlen > 0) {
	GpiQueryTextBox(hps, textlen, starttext, TXTBOX_COUNT, aptl);
	textwidth += aptl[TXTBOX_BOTTOMRIGHT].x * multLineHor;
	textwidth += aptl[TXTBOX_BOTTOMRIGHT].y * multLineVert;
    }

    if (bText) {
	if (textlen > 0) {
	    GpiCharStringAt(hps, &ptlText, textlen, starttext);
	    ptlText.x += aptl[TXTBOX_CONCAT].x - multLineVert * base;
	    ptlText.y += aptl[TXTBOX_CONCAT].y + multLineHor * base;
	} else {
	    ptlText.x -= multLineVert * base;
	    ptlText.y += multLineHor * base;
	}
    }
    textlen = 0;
    starttext = p;

    if (fontname != NULL) {
	char szFont[FONTBUF];

	snprintf(szFont, FONTBUF, "%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;
	    /*}}}*/

	case '_':
	case '^':
	    /*{{{  deal with super/sub script*/
	    shift = ((*p == '^') ? lSupOffset : lSubOffset);
	    p = ParseText(hps, p+1, FALSE,
			  NULL/*fontname*/, fontsize*0.8,
			  base+shift, widthflag, showflag);
	    break;
	    /*}}}*/

	case '{':
	{
	    char *savepos=NULL, save=0;
	    char *localfontname=fontname, ch;
	    char localfontbuf[FONTBUF];
	    int recode=1;
	    int f=fontsize;
	    char *q=localfontbuf;

	    /*{{{  recurse(possibly with a new font) */

	    TEXT_DEBUG(("Dealing with {\n"));
	    if (*++p == '/') {
		/* then parse a fontname, optional fontsize */
		while (*++p == ' ')
		    ;		/* do nothing */
		if (*p=='-') {
		    recode=0;
		    while (*++p == ' ')
			;	/* do nothing */
		}
		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(("Calling strtod(%s) ...", p));
		    f = strtod(p, &p);
		    TEXT_DEBUG(("Returned %.1f and %s\n", f, p));

		    if (!f)
			f = fontsize;

		    TEXT_DEBUG(("Font size %d\n", f));
		    /*}}}*/
		} else {
		    *p++ = '\0';
		    f = fontsize;
		}

		while (*p == ' ')
		    ++p;

		if (!(*localfontname)) {
		    localfontname = fontname;
		    if (f != fontsize)
			localfontname = strchr(szFontNameSize, '.') + 1;
		}
	    } /* if ('/') */
	    /*}}}*/

	    TEXT_DEBUG(("Before recursing, we are at [%p] %s\n", p, p));

	    p = ParseText(hps,p, TRUE, localfontname, f, base, widthflag, showflag);

	    TEXT_DEBUG(("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] = '0' && p[1] = '0' && p[1] 

Web Proxy Viewer  |  New URL  |  Original Page