Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / os2 / gclient.c
diff --git a/src/os2/gclient.c b/src/os2/gclient.c
new file mode 100644 (file)
index 0000000..b8bedaf
--- /dev/null
@@ -0,0 +1,4145 @@
+#ifdef INCRCSDATA
+static char RCSid[]="$Id: gclient.c,v 1.47.2.1 2008/02/23 11:23:12 mikulik Exp $";
+#endif
+
+/****************************************************************************
+
+    PROGRAM: Gnupmdrv
+
+    MODULE:  gclient.c
+
+    This file contains the client window procedures for Gnupmdrv
+
+****************************************************************************/
+
+/* PM driver for GNUPLOT */
+
+/*[
+ * Copyright 1992, 1993, 1998, 2004   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)
+ */
+
+#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
+#define INCL_GPIPRIMITIVES
+#include <os2.h>
+#include <string.h>
+#include <stdio.h>
+#include <io.h>
+#include <fcntl.h>
+#include <math.h>
+#include <float.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <process.h>
+#include <signal.h>
+#include <time.h>
+#include "config.h"
+#include "term_api.h"
+#include "gnupmdrv.h"
+#include "pm_msgs.h"
+#define GNUPMDRV
+#include "mousecmn.h"
+
+
+/*==== m i s c e l l a n e o u s =============================================*/
+
+/* February 2008, according to the gnuplot bugs report #1773922
+   The standard font selection dialog is somehow broken after saving options.
+   Use the font palette dialog instead.
+*/
+/* #define STANDARD_FONT_DIALOG 1 */
+#undef STANDARD_FONT_DIALOG
+
+/*==== d e b u g g i n g =====================================================*/
+
+#if 0
+# include "pmprintf.h"
+# define DEBUG_IMAGE(a) PmPrintf a
+#else
+# define DEBUG_IMAGE(a)
+#endif
+
+#if 0
+# include "pmprintf.h"
+# define DEBUG_COLOR(a) PmPrintf a
+#else
+# define DEBUG_COLOR(a)
+#endif
+
+
+/*==== 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 long lCols_init = 0;
+static long lCols_num = 16;
+static long bkColor = -1;
+
+/* 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 */
+/* FIXME: gnupmdrv crashes if this is > GNUBUF/4 ! */
+/* FIXME: this must be <= 256 (see PM_SET_COLOR)   */
+#define   RGB_PALETTE_SIZE 0    /* size of the 'virtual' palette used for 
+                                  translation of index to RGB value */
+
+/* FIXME: increasing GNUBUF circumvents a bug/limitation in BufRead:
+   it cannot read datablocks larger than GNUBUF */
+#define   GNUBUF    131072
+//#define   GNUBUF    2048        /* buffer for gnuplot commands */
+#define   PIPEBUF   4096        /* size of pipe buffers */
+#define   CMDALLOC  4096        /* command buffer allocation increment (ints) */
+
+#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
+
+// ULONG    ppidGnu = 0L;  /* gnuplot pid  */ -- now in gpexecute.c
+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     bLineTypes = FALSE;    // true if use dashed linetypes
+static BOOL     bColours = TRUE;
+static BOOL     bShellPos = FALSE;
+static BOOL     bPopFront = TRUE;
+static BOOL     bKeepRatio = TRUE;     //PM
+#if 0
+static BOOL     bNewFont = FALSE;
+#endif
+
+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 BOOL     bSend2gp = FALSE;
+/* HBB FIXME 20040630: why isn't this 'static'? */
+const  char  *SetDataStyles[] = {
+    "boxes", "dots", "fsteps", "histeps", "impulses",
+    "lines", "linespoints", "points", "steps"
+};
+
+struct {
+    int on;  // set to 1 during zooming
+    POINTL from, to; // corners
+} zoombox = { 0 };
+
+
+static int zooming = 0;  // set to 1 during zooming
+static POINTL zoomrect_from, zoomrect_now;
+
+static ULONG    ulPlotPos[4];
+static ULONG    ulShellPos[4];
+static PAUSEDATA pausedata = {sizeof(PAUSEDATA), NULL, NULL};
+static char     szFontNameSize[FONTBUF];       /* default name and size, format: "10.Helvetica" */
+/* FIXME: this might not always get updated on font change */
+static char    szCurrentFontNameSize[FONTBUF]; /* currently selected font */
+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 HEV      semDrawDone;
+
+            /* thread control */
+
+static TID     tidDraw, tidSpawn;
+
+static int breakDrawing = 0;
+            /* //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;
+
+
+//PM: Now variables for mouse
+
+/* useMouse is set to 1 when user switches mousing on, e.g. the mouse is
+   allowed
+*/
+static int useMouse = 0;
+
+/* gnuplot's PM terminal sends GR_MOUSECAPABLE message from its init routine, which
+   sets the variable below to 1. Then we are sure that we talk to the
+   mouseable terminal and can read the mouseable data from the pipe.
+   Non-mouseable versions of PM terminal or non-new-gnuplot programs
+   using gnupmdrv will let this variable set to 0, thus no mousing occurs.
+*/
+static char mouseTerminal = 0;
+
+
+/* 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 char lock_mouse = 1;
+
+/* Structure for the ruler: on/off, position,...
+*/
+static struct {
+   int on;
+   int x, y;  /* ruler position */
+} ruler = {0,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;
+int gpPMmenu_update_req = 0;
+
+// 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;
+    LONG  lcid;
+} tabFont[256] = {
+    {NULL,0L},
+    {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     EditLineTypes(HWND, HPS, BOOL);
+#if 0
+static void     EditCharCell(HPS, SIZEF*);
+#endif
+static HPS      InitScreenPS(void);
+static int      BufRead(HFILE, void*, int, PULONG);
+static int      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 void     LType(int iType);
+
+/* Functions related to the 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     DisplayStatusLine(HPS hps);
+static void     UpdateStatusLine(HPS hps, char *text);
+static void     gpPMmenu_update(void);
+static void     DrawZoomBox(void);
+static void     DrawRuler(void);
+
+#define IGNORE_MOUSE (!mouseTerminal || useMouse==0 || lock_mouse)
+/* || !gp4mouse.graph */
+/*  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];
+};
+
+/* Circular buffer of objects recently dropped.  */
+
+#define DROP_MAX 8
+static int drop_count = 0;
+
+/* Each drop action is assigned a number, for relating drop events
+   with PMR_DROP requests. */
+
+/* Finally, include the common mousing declarations and routines: */
+#define GNUPMDRV
+  /* let mousing.c know whether called from gclient.c or gplt_x11.c */
+#include "../gpexecute.h"
+
+/* End of new functions related to the mouse processing */
+
+/*==== c o d e ===============================================================*/
+
+/* 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 if (DrgQueryDragitemCount(pDraginfo) > DROP_MAX - drop_count)
+       DRAG_FAIL("Circular buffer full");
+    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 && drop_count < DROP_MAX; ++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 <= sizeof(path)) {
+         strcpy(path + len, name);
+         for (p = path; *p != 0; ++p)
+             if (*p == '\\')
+                 *p = '/';
+         if (input_from_PM_Terminal) {
+             sprintf(input_from_PM_Terminal,
+                     "set loadpath \"%.*s\"; load \"%s\"",
+                     len, path, path);
+             gp_execute(0);
+         }
+      } else
+         report_error(hwnd, "Dropped path name too long");
+  } /* for(idx) */
+
+  DrgDeleteDraginfoStrHandles(pDraginfo);
+  DrgFreeDraginfo(pDraginfo);
+  return(0);
+}
+
+#if 0
+/* A color has been dropped on a frame(or the background color has
+   been changed with WinSetPresParam). */
+
+static void
+drop_color(HWND hwnd)
+{
+    RGB rgb;
+    char buf[3];
+
+    if (WinQueryPresParam(hwnd, PP_BACKGROUNDCOLOR, 0, NULL,
+                         sizeof(rgb), &rgb,
+                         QPF_NOINHERIT | QPF_PURERGBCOLOR) == sizeof(rgb)
+       ) {
+       buf[0] = rgb.bRed;
+       buf[1] = rgb.bGreen;
+       buf[2] = rgb.bBlue;
+#if CAN_DROP_COLOR
+       send_drop_color(buf, 3);
+#endif
+    }
+}
+#endif
+
+/*
+**  Window proc for main window
+**  -- passes most stuff to active child window via WmClientCmdProc
+**  -- passes DDE messages to DDEProc
+*/
+MRESULT
+EXPENTRY DisplayClientWndProc(HWND hWnd, ULONG message, MPARAM mp1, MPARAM mp2)
+{
+    static RECTL   rectlPaint = { 0, 0, 0, 0 };
+    static int     iPaintCount = 0;
+    static int     firstcall = 1;
+    static int     prev_mx = 0, prev_my = 0;           /* previous mouse position */
+    int            mx, my;                             /* current mouse position  */
+
+#if 1
+    GetMousePosViewport(hWnd, &mx, &my);
+#else
+    /* The following cannot be used because `message' is not OK for
+     * WM_CHAR */
+    /* macro which gets mouse coords in pixels */
+    mx = MOUSEMSG(&message)->x;
+    my = MOUSEMSG(&message)->y;
+    /* viewport units --- this trashes mx,my! */
+    MousePosToViewport(&mx, &my, mx, my);
+#endif
+
+    /* Graphics part, SET_GRAPHICS, required to update menu */
+    if (gpPMmenu_update_req)
+       gpPMmenu_update();
+
+    /* mouse events first */
+    switch (message) {
+    case WM_MOUSEMOVE:
+       if (IGNORE_MOUSE) {
+           WinSetPointer(HWND_DESKTOP, hptrDefault); /* set default pointer */
+           return 0L;
+       }
+       /* was the mouse moved? */
+       if ((prev_mx != mx) || (prev_my != my)) {
+#if 1
+           WinSetPointer(HWND_DESKTOP, hptrCurrent);
+#else
+           WinSetPointer(HWND_DESKTOP, hptrCrossHair);
+#endif
+           if (zoombox.on) {
+               DrawZoomBox(); /* erase zoom box */
+               zoombox.to.x = mx; zoombox.to.y = my;
+               DrawZoomBox(); /* draw new zoom box */
+           }
+           /* track(show) mouse position -- send the event to gnuplot */
+           gp_exec_event(GE_motion, mx, my, 0, 0, 0);
+       }
+       prev_mx = mx;
+       prev_my = my;
+       return 0L; /* end of WM_MOUSEMOVE */
+
+    case WM_BUTTON1DOWN:
+       WinSetFocus(HWND_DESKTOP, hWnd);
+       if (! IGNORE_MOUSE)
+           gp_exec_event(GE_buttonpress, mx, my, 1, 0, 0);
+       return 0L;
+
+    case WM_BUTTON2DOWN:
+       WinSetFocus(HWND_DESKTOP, hWnd);
+       if (!IGNORE_MOUSE)
+           gp_exec_event(GE_buttonpress, mx, my, 3, 0, 0);
+       return 0L;
+
+    case WM_BUTTON3DOWN:
+       WinSetFocus(HWND_DESKTOP, hWnd);
+       if (!IGNORE_MOUSE)
+           gp_exec_event(GE_buttonpress, mx, my, 2, 0, 0);
+       return 0L;
+
+    case WM_BUTTON1DBLCLK:
+       if (!IGNORE_MOUSE)
+           gp_exec_event(GE_buttonrelease, mx, my, 1, 0, 0);
+       return 0L;
+
+    case WM_BUTTON2DBLCLK:
+       if (!IGNORE_MOUSE)
+           /* Note: 9999 should be replaced by time! */
+           gp_exec_event(GE_buttonrelease, mx, my, 3, 9999, 0);
+       return 0L;
+
+    case WM_BUTTON3DBLCLK:
+       if (!IGNORE_MOUSE)
+           gp_exec_event(GE_buttonrelease, mx, my, 2, 9999, 0);
+       return 0L;
+
+#if 1
+    case WM_BUTTON1UP:
+#else
+    case WM_BUTTON1CLICK:
+#endif
+       if (!IGNORE_MOUSE)
+           gp_exec_event(GE_buttonrelease, mx, my, 1, 9999, 0);
+       return 0L;
+
+#if 0
+    case WM_BUTTON2UP:
+#else
+    case WM_BUTTON2CLICK:
+#endif
+       if (!IGNORE_MOUSE)
+           gp_exec_event(GE_buttonrelease, mx, my, 3, 9999, 0);
+       return 0L;
+
+#if 1
+    case WM_BUTTON3UP:
+#else
+    case WM_BUTTON3CLICK:
+#endif
+       if (!IGNORE_MOUSE)
+           gp_exec_event(GE_buttonrelease, mx, my, 2, 9999, 0);
+       return 0L;
+
+    } /* switch over mouse events */
+
+
+    switch (message) {
+    case WM_CREATE:
+    {
+       SIZEL   sizlPage;
+       LONG    NumColors;
+       LONG    PalSupport;
+
+       /* 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);
+       ChangeCheck(hWnd, IDM_KEEPRATIO, bKeepRatio?IDM_KEEPRATIO:0);
+       ChangeCheck(hWnd, IDM_USEMOUSE, useMouse?IDM_USEMOUSE:0);
+#if 0
+       ChangeCheck(hWnd, IDM_MOUSE_POLAR_DISTANCE, mousePolarDistance?IDM_MOUSE_POLAR_DISTANCE:0);
+#endif
+
+       /* 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);
+
+       /* create a dc and hps to draw on the screen */
+       hdcScreen = WinOpenWindowDC(hWnd);
+
+       /* How many colors can be displayed ? */
+       DevQueryCaps(hdcScreen, CAPS_COLORS, 1, &NumColors);
+       /* Is Palette Manager supported at all? */
+       DevQueryCaps(hdcScreen, CAPS_ADDITIONAL_GRAPHICS, 1, &PalSupport);
+
+       /* Determine if PM Palette Manager should be used */
+       bPMPaletteMode = (PalSupport & CAPS_PALETTE_MANAGER) &&
+                        (NumColors <= 256);
+       DEBUG_COLOR(( "WM_CREATE: colors = %i, pm = %i, rgb = %i",
+               NumColors, PalSupport & CAPS_PALETTE_MANAGER, !bPMPaletteMode ));
+
+       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);
+       /* initialize pointers */
+       hptrDefault = WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE);
+       hptrCrossHair = WinLoadPointer(HWND_DESKTOP,(ULONG)0, IDP_CROSSHAIR);
+       hptrScaling = WinLoadPointer(HWND_DESKTOP,(ULONG)0, IDP_SCALING);
+       hptrRotating = WinLoadPointer(HWND_DESKTOP,(ULONG)0, IDP_ROTATING);
+       hptrZooming = WinQuerySysPointer(HWND_DESKTOP, SPTR_MOVE, FALSE);
+       hptrCurrent = hptrCrossHair;
+
+       break;
+    }
+
+    case WM_GPSTART:
+       /* Show the Mouse menu if connected to mouseable PM terminal */
+       if (1 || mouseTerminal) /* PM: workaround for a bug---SEE "BUGS 2" IN README!!! */
+           /* if (mouseTerminal) */
+           WinEnableMenuItem(WinWindowFromID(
+                                 WinQueryWindow(hApp, QW_PARENT),
+                                 FID_MENU),
+                             IDM_MOUSE, TRUE);
+       if (!input_from_PM_Terminal) { /* no feedback */
+#define NOFEEDBACK(X)                                                  \
+           WinEnableMenuItem(WinWindowFromID(                          \
+                                 WinQueryWindow(hApp, QW_PARENT),      \
+                                 FID_MENU),                            \
+                             X, FALSE)
+           NOFEEDBACK(IDM_SET_GRID);
+           NOFEEDBACK(IDM_SET_LINLOGY);
+           NOFEEDBACK(IDM_SET_AUTOSCALE);
+           NOFEEDBACK(IDM_DO_REPLOT);
+           NOFEEDBACK(IDM_DO_RELOAD);
+           NOFEEDBACK(IDM_DO_SENDCOMMAND);
+           NOFEEDBACK(IDM_SET);
+#undef NOFEEDBACK
+       }
+
+       /* 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:
+    {
+       /* Note: doc for WM_CHAR is available in PMMSG.INF */
+       USHORT usFlag = SHORT1FROMMP(mp1); /* keyboard control codes */
+       SHORT  key = SHORT2FROMMP(mp2);    /* virtual key code */
+       static int last_modifier_mask = -99;
+       int modifier_mask =
+           ((usFlag & KC_SHIFT) ? Mod_Shift : 0)
+           | ((usFlag & KC_CTRL) ? Mod_Ctrl : 0)
+           | ((usFlag & KC_ALT) ? Mod_Alt : 0);
+
+       if (modifier_mask != last_modifier_mask) {
+           gp_exec_event(GE_modifier, mx, my, modifier_mask, 0, 0);
+           last_modifier_mask = modifier_mask;
+       }
+#if 0
+       if (!(usFlag & KC_SCANCODE))
+           return 0L; // only modifier mask has changed */
+#endif
+       if (usFlag & KC_KEYUP)
+           return 0L;   /* ignore key release events */
+#if 0
+       {
+           FILE *ff = fopen("deb", "a");
+           fprintf(ff, "key = %i c=%c\n", (int) key, (char) key);
+           fclose(ff);
+       }
+#endif
+
+       switch (key) {
+       case VK_SPACE: {
+           /* raise gnuplot's window */
+           HWND hw = WinQueryWindow(swGnu.hwnd, QW_BOTTOM);
+           WinSetFocus(HWND_DESKTOP, hw);
+           WinSendMsg(hw, message,
+                      MPFROM2SHORT((USHORT)(KC_SCANCODE), 1),
+                      0 /* MPFROMSHORT(key) */
+               );
+           WinSwitchToProgram(hSwitch);
+           break;
+       }
+           /* remap virtual keys to gnuplot's codes: */
+       case VK_BACKSPACE:
+           key = GP_BackSpace;
+           break;
+       case VK_TAB:
+           key = GP_Tab;
+           break;
+       case VK_NEWLINE:
+           key = GP_Return;
+           break;
+       case VK_PAUSE:
+           key = GP_Pause;
+           break;
+       case VK_SCRLLOCK:
+           key = GP_Scroll_Lock;
+           break;
+       case VK_SYSRQ:
+           key = GP_Sys_Req;
+           break;
+       case VK_ESC:
+           key = GP_Escape;
+           break;
+       case VK_DELETE:
+           key = GP_Delete;
+           break;
+       case VK_INSERT:
+           key = GP_KP_Insert;
+           break;
+       case VK_HOME:
+           key = GP_Home;
+           break;
+       case VK_LEFT:
+           key = GP_Left;
+           break;
+       case VK_UP:
+           key = GP_Up;
+           break;
+       case VK_RIGHT:
+           key = GP_Right;
+           break;
+       case VK_DOWN:
+           key = GP_Down;
+           break;
+       case VK_END:
+           key = GP_End;
+           break;
+       case VK_PAGEUP:
+           key = GP_PageUp;
+           break;
+       case VK_PAGEDOWN:
+           key = GP_PageDown;
+           break;
+       case VK_F1:
+           key = GP_F1;
+           break;
+       case VK_F2:
+           key = GP_F2;
+           break;
+       case VK_F3:
+           key = GP_F3;
+           break;
+       case VK_F4:
+           key = GP_F4;
+           break;
+       case VK_F5:
+           key = GP_F5;
+           break;
+       case VK_F6:
+           key = GP_F6;
+           break;
+       case VK_F7:
+           key = GP_F7;
+           break;
+       case VK_F8:
+           key = GP_F8;
+           break;
+       case VK_F9:
+           key = GP_F9;
+           break;
+       case VK_F10:
+           key = GP_F10;
+           break;
+       case VK_F11:
+           key = GP_F11;
+           break;
+       case VK_F12:
+           key = GP_F12;
+           break;
+       case VK_SHIFT:
+       case VK_CTRL:
+       case VK_ALT:
+           gp_exec_event(GE_modifier, mx, my, modifier_mask, 0, 0);
+           return 0L;
+       default:
+           key = SHORT1FROMMP(mp2); /* character key code */
+       } /* switch(key) */
+
+       if (key)
+           gp_exec_event(GE_keypress, mx, my, key, 0, 0);
+
+       return 0L;
+    } /*case(WM_CHAR) */
+
+    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                   */
+           lock_mouse = 1; /* PM: this may help against gnupmdrv crashes */
+           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);
+           lock_mouse = 0;
+           iPaintCount ++;
+           break;
+       }
+       lock_mouse = 1;
+       WinInvalidateRect(hWnd, &rectlPaint, TRUE);
+       DoPaint(hWnd, hpsScreen);
+       WinSetRectEmpty(hab, &rectlPaint);
+       lock_mouse = 0;
+       break;
+    }
+
+    case WM_SIZE :
+       WinInvalidateRect(hWnd, NULL, TRUE);
+       break;
+
+    case WM_PRESPARAMCHANGED: {
+       char *pp = malloc(FONTBUF);
+       ULONG ulID;
+
+       if (WinQueryPresParam(hWnd,
+                             PP_FONTNAMESIZE,
+                             0,
+                             &ulID,
+                             FONTBUF,
+                             pp,
+                             QPF_NOINHERIT) != 0L) {
+           strcpy(szFontNameSize, pp);
+#if 0
+           bNewFont = TRUE;
+#endif
+           WinInvalidateRect(hWnd, NULL, TRUE);
+       }
+       free(pp);
+#ifndef STANDARD_FONT_DIALOG
+       gp_execute("replot");
+#endif
+       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 */
+       lock_mouse = 1;
+       if (bPopFront) {
+           SWP swp; /* pop to front only if the window is not minimized */
+
+           if ((WinQueryWindowPos(hwndFrame,(PSWP) &swp) == TRUE)
+               &&((swp.fl & SWP_MINIMIZE) == 0))
+               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;
+       }
+       lock_mouse = 0;
+       return 0L;
+
+    case WM_PAUSEPLOT:
+    {
+       SWP swp; /* restore the window if it has been minimized */
+
+       if ((WinQueryWindowPos(hwndFrame, &swp) == TRUE)
+           &&((swp.fl & SWP_MINIMIZE) != 0))
+           WinSetWindowPos(hwndFrame, HWND_TOP, 0,0,0,0,
+                           SWP_RESTORE|SWP_SHOW|SWP_ACTIVATE);
+       /* 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;
+
+/* New event handles for mouse processing */
+
+#if 0 /* already defined */
+    case WM_MOUSEMOVE:
+       return  0L;
+#endif
+
+#if 0
+    case WM_BUTTON1DBLCLK:
+       /* put the mouse coordinates to the clipboard */
+       if (!IGNORE_MOUSE) {
+           SHORT mx = MOUSEMSG(&message)->x;
+           SHORT my = MOUSEMSG(&message)->y;
+           double x, y;
+           char s[256];
+           int frm = ulMouseSprintfFormatItem - IDM_MOUSE_FORMAT_X_Y;
+
+           /* Note: Another solution of getting mouse position
+            *(available at any method, not just in this handle
+            * event) is the following one:
+            *
+            * ok = WinQueryPointerPos(HWND_DESKTOP, &pt); // pt contains pos wrt desktop
+            * WinMapWindowPoints(HWND_DESKTOP, hWnd, &pt, 1); // pt contains pos wrt our hwnd window
+            * sprintf(s,"[%li,%li]",pt.x,pt.y);
+            */
+
+       }
+       return 0L; /* end of case WM_BUTTON1DBLCLK */
+#endif
+
+    case WM_BUTTON2CLICK: /* WM_BUTTON2UP: */
+       /* make zoom */
+       if (! IGNORE_MOUSE) {
+           POINTL tmp;
+           HPS hps = WinGetPS(hWnd);
+
+           if (pausing) { /* zoom is not allowed during pause */
+               DosBeep(440,111);
+               break;
+           }
+           DosBeep(555,155);
+           zoomrect_from.x = MOUSEMSG(&message)->x;
+           zoomrect_from.y = MOUSEMSG(&message)->y;
+           /* set opposite corner */
+           tmp.x = zoomrect_now.x = zoomrect_from.x + 50;
+           tmp.y = zoomrect_now.y = zoomrect_from.y + 50;
+           /* move mouse to opposite corner */
+           WinMapWindowPoints(hWnd, HWND_DESKTOP, &tmp, 1);
+           WinSetPointerPos(HWND_DESKTOP, tmp.x, tmp.y);
+           WinReleasePS(hps);
+           zooming = 1;
+       }
+       return 0; /* return from: case WM_BUTTON3DOWN(zoom) */
+
+    case WM_BUTTON3UP: /* WM_BUTTON3DBLCLK: */
+       /* write mouse position to screen */
+       if (! IGNORE_MOUSE) {
+           SHORT mx = MOUSEMSG(&message)->x; /* mouse position */
+           SHORT my = MOUSEMSG(&message)->y;
+           char s[256];
+           POINTL pt;
+           HPS hps = WinGetPS(hWnd);
+
+           GpiSetColor(hps, RGB_TRANS(COLOR_ANNOTATE));    /* set color of the text */
+           GpiSetCharMode(hps,CM_MODE1);
+           pt.x = mx; pt.y = my+4;
+           GpiCharStringAt(hps,&pt,(long)strlen(s),s);
+           /* draw a cross at the clicked position */
+           pt.x = mx-3; pt.y = my; GpiMove(hps,&pt);
+           pt.x += 7; GpiLine(hps,&pt);
+           pt.x = mx; pt.y = my - 3; GpiMove(hps,&pt);
+           pt.y += 7; GpiLine(hps,&pt);
+           WinReleasePS(hps);
+       }
+       return 0L; /* end of case WM_BUTTON3... */
+
+       /* End of new event handles for mouse processing */
+
+#if 0
+    case WM_PRESPARAMCHANGED:
+       if (LONGFROMMP(mp1) == PP_BACKGROUNDCOLOR)
+           drop_color(hWnd);
+       return 0;
+#endif
+
+    case DM_DRAGOVER:
+       /* Determine whether the object can be dropped. */
+       return(drag_over(hWnd, (PDRAGINFO) mp1));
+
+    case DM_DROP:
+       /* Drop an object. */
+       return(drag_drop(hWnd, (PDRAGINFO) mp1));
+
+    default:         /* Passes it on if unproccessed    */
+       return(WinDefWindowProc(hWnd, message, mp1, mp2));
+    } /* switch(message) */
+
+    return(NULL);
+}
+
+
+#if 0 /* unused */
+/*
+ * Gets the pointer position(in pixels) in the window hWnd
+ */
+void
+GetPointerPos(HWND hWnd, PPOINTL p)
+{
+    WinQueryPointerPos(HWND_DESKTOP, p);
+    /* this is position wrt desktop */
+    WinMapWindowPoints(HWND_DESKTOP, hWnd, p, 1);
+    /* pos. wrt our window in pixels */
+}
+#endif
+
+
+/* passing either n(n>=0) or f(when n==-1) */
+void
+SetMouseCoords(HWND hWnd, MPARAM mp1, int n, char *f)
+{
+    char s[100];
+
+    ChangeCheck(hWnd, ulMouseSprintfFormatItem, SHORT1FROMMP(mp1));
+    ulMouseSprintfFormatItem = SHORT1FROMMP(mp1);
+    if (n >= 0)
+       sprintf(s,"set mouse mouseformat %i clipboardformat %i", n, n);
+    else
+       sprintf(s,"set mouse mouseformat \"%s\" clipboardformat \"%s\"", f, f);
+    gp_execute(s);
+}
+
+
+/*
+**   Handle client window command(menu) messages
+*/
+MRESULT
+WmClientCmdProc(HWND hWnd, ULONG message, MPARAM mp1, MPARAM mp2)
+{
+    static int ulPauseItem = IDM_PAUSEDLG;
+    // static int ulMouseCoordItem = IDM_MOUSE_COORDINATES_REAL;
+    int mx, my;
+
+    GetMousePosViewport(hWnd,&mx,&my);
+
+    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 */
+    {
+       const char cmd_prefix[] = "start view ";
+       const char helpfile[] = "gnuplot.inf";
+       char *cmd;
+       char *gnuplot_path;
+       unsigned cmd_length;
+
+       cmd_length = strlen(cmd_prefix) + strlen(helpfile);
+        gnuplot_path = getenv("GNUPLOT");
+       if (gnuplot_path != NULL)
+           cmd_length += strlen(gnuplot_path) + 1;
+
+       cmd = (char *)malloc( cmd_length );
+       strcpy(cmd, cmd_prefix);
+       if (gnuplot_path != NULL) {
+           strcat(cmd, gnuplot_path);
+           strcat(cmd, "\\");
+       }
+       strcat(cmd, helpfile);
+       system(cmd);
+       free(cmd);
+       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_KEEPRATIO:
+       /* toggle keep aspect ratio */
+       bKeepRatio = !bKeepRatio;
+       ChangeCheck(hWnd, IDM_KEEPRATIO, bKeepRatio?IDM_KEEPRATIO:0);
+       WinInvalidateRect(hWnd, NULL, TRUE); /* redraw screen */
+       break;
+
+    case IDM_FONTS:
+       if (GetNewFont(hWnd, hpsScreen)) {
+#if 0
+           bNewFont = TRUE;
+#endif
+           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;
+
+
+       /* Now new mousing stuff: */
+
+    case IDM_USEMOUSE: /* toggle using/not using mouse cursor tracking */
+       useMouse = !useMouse;
+       ChangeCheck(hWnd, IDM_USEMOUSE, useMouse?IDM_USEMOUSE:0);
+       gp_execute(useMouse ? "set mouse" : "unset mouse");
+#if 0
+       if (!useMouse) /* redraw screen */
+           WinInvalidateRect(hWnd, NULL, TRUE);
+#endif
+       return 0L;
+
+    case IDM_MOUSE_HELP:
+       gp_exec_event(GE_keypress, mx, my, 'h', 1, 0);
+       return 0L;
+
+#if 0
+    case IDM_MOUSE_COORDINATES_REAL:
+       ChangeCheck(hWnd, ulMouseCoordItem, IDM_MOUSE_COORDINATES_REAL);
+       ulMouseCoordItem = IDM_MOUSE_COORDINATES_REAL;
+       return 0L;
+
+    case IDM_MOUSE_COORDINATES_PIXELS:
+       ChangeCheck(hWnd, ulMouseCoordItem, IDM_MOUSE_COORDINATES_PIXELS);
+       ulMouseCoordItem = IDM_MOUSE_COORDINATES_PIXELS;
+       return 0L;
+
+    case IDM_MOUSE_COORDINATES_SCREEN:
+       ChangeCheck(hWnd, ulMouseCoordItem, IDM_MOUSE_COORDINATES_SCREEN);
+       ulMouseCoordItem = IDM_MOUSE_COORDINATES_SCREEN;
+       return 0L;
+
+    case IDM_MOUSE_COORDINATES_XDATE:
+       ChangeCheck(hWnd, ulMouseCoordItem, IDM_MOUSE_COORDINATES_XDATE);
+       ulMouseCoordItem = IDM_MOUSE_COORDINATES_XDATE;
+       return 0L;
+
+    case IDM_MOUSE_COORDINATES_XTIME:
+       ChangeCheck(hWnd, ulMouseCoordItem, IDM_MOUSE_COORDINATES_XTIME);
+       ulMouseCoordItem = IDM_MOUSE_COORDINATES_XTIME;
+       return 0L;
+
+    case IDM_MOUSE_COORDINATES_XDATETIME:
+       ChangeCheck(hWnd, ulMouseCoordItem, IDM_MOUSE_COORDINATES_XDATETIME);
+       ulMouseCoordItem = IDM_MOUSE_COORDINATES_XDATETIME;
+       return 0L;
+#endif
+
+    case IDM_MOUSE_CMDS2CLIP:
+       /* toggle copying the command sent to gnuplot to clipboard */
+       bSend2gp = !bSend2gp;
+       ChangeCheck(hWnd, IDM_MOUSE_CMDS2CLIP, bSend2gp?IDM_MOUSE_CMDS2CLIP:0);
+       return 0L;
+
+    case IDM_MOUSE_FORMAT_pXcYp:
+       SetMouseCoords(hWnd, mp1, -1, "[%g, %g]");
+       return 0L;
+    case IDM_MOUSE_FORMAT_XcY:
+       SetMouseCoords(hWnd, mp1, 1, NULL);
+       return 0L;
+    case IDM_MOUSE_FORMAT_TIMEFMT:
+       SetMouseCoords(hWnd, mp1, 3, NULL);
+       return 0L;
+    case IDM_MOUSE_FORMAT_DATE:
+       SetMouseCoords(hWnd, mp1, 4, NULL);
+       return 0L;
+    case IDM_MOUSE_FORMAT_TIME:
+       SetMouseCoords(hWnd, mp1, 5, NULL);
+       return 0L;
+    case IDM_MOUSE_FORMAT_DATETIME:
+       SetMouseCoords(hWnd, mp1, 6, NULL);
+       return 0L;
+    case IDM_MOUSE_FORMAT_X_Y:
+       SetMouseCoords(hWnd, mp1, -1, "%g %g");
+       return 0L;
+    case IDM_MOUSE_FORMAT_XcYc:
+       SetMouseCoords(hWnd, mp1, -1, "%g %g ");
+       return 0L;
+    case IDM_MOUSE_FORMAT_XcYs:
+       SetMouseCoords(hWnd, mp1, -1, "%g %g, ");
+       return 0L;
+
+    case IDM_MOUSE_POLAR_DISTANCE:
+       /* toggle using/not using polar coords of distance */
+       gp_execute(gpPMmenu.polar_distance
+                  ? "set mouse nopolardistance"
+                  : "set mouse polardistance");
+       return 0L;
+
+    case IDM_MOUSE_ZOOMNEXT: /* zoom to next level */
+       gp_exec_event(GE_keypress, mx, my, 'n', 1, 0);
+       return 0L;
+
+    case IDM_MOUSE_UNZOOM: /* unzoom one level back */
+       gp_exec_event(GE_keypress, mx, my, 'p', 1, 0);
+       return 0L;
+
+    case IDM_MOUSE_UNZOOMALL: /* unzoom to the first level */
+       gp_exec_event(GE_keypress, mx, my, 'u', 1, 0);
+       return 0L;
+
+    case IDM_MOUSE_RULER:
+    {
+       int mx, my;
+
+       GetMousePosViewport(hWnd,&mx,&my);
+       gp_exec_event(GE_keypress, mx, my, 'r', 1, 0);
+       return 0L;
+    }
+
+    case IDM_BREAK_DRAWING:
+       breakDrawing = 1;
+       return 0L;
+
+    case IDM_SET_GRID:
+    {
+       gp_exec_event(GE_keypress, mx, my, 'g', 1, 0);
+       return 0L;
+    }
+
+    case IDM_SET_LINLOGY:
+    {
+       gp_exec_event(GE_keypress, mx, my, 'l', 1, 0);
+       return 0L;
+    }
+
+    case IDM_SET_AUTOSCALE:
+       gp_execute("set autoscale; replot");
+       return 0L;
+
+    case IDM_DO_REPLOT:
+       gp_execute("replot");
+       return 0L;
+
+    case IDM_DO_RELOAD:
+       gp_execute("history !load");
+       return 0L;
+
+    case IDM_DO_SENDCOMMAND:
+       if (input_from_PM_Terminal) {
+           if (pausing)
+               DosBeep(440,111);
+           else
+               WinDlgBox(HWND_DESKTOP, hWnd, SendCommandDlgProc,
+                         NULLHANDLE, IDM_DO_SENDCOMMAND,
+                         input_from_PM_Terminal);
+       }
+       return (MRESULT) 0;
+
+    case IDM_SET_D_S_BOXES:
+    case IDM_SET_D_S_DOTS:
+    case IDM_SET_D_S_FSTEPS:
+    case IDM_SET_D_S_HISTEPS:
+    case IDM_SET_D_S_IMPULSES:
+    case IDM_SET_D_S_LINES:
+    case IDM_SET_D_S_LINESPOINTS:
+    case IDM_SET_D_S_POINTS:
+    case IDM_SET_D_S_STEPS:
+       if (input_from_PM_Terminal)
+            sprintf(input_from_PM_Terminal, "set style data %s; replot",
+                   SetDataStyles[(USHORT) SHORT1FROMMP(mp1) - IDM_SET_D_S_BOXES ]);
+       gp_execute(0);
+       return 0L;
+
+    case IDM_SET_F_S_BOXES:
+    case IDM_SET_F_S_DOTS:
+    case IDM_SET_F_S_FSTEPS:
+    case IDM_SET_F_S_HISTEPS:
+    case IDM_SET_F_S_IMPULSES:
+    case IDM_SET_F_S_LINES:
+    case IDM_SET_F_S_LINESPOINTS:
+    case IDM_SET_F_S_POINTS:
+    case IDM_SET_F_S_STEPS:
+       if (input_from_PM_Terminal)
+            sprintf(input_from_PM_Terminal, "set style function %s; replot",
+                   SetDataStyles[(USHORT) SHORT1FROMMP(mp1) - IDM_SET_F_S_BOXES ]);
+       gp_execute(0);
+       return 0L;
+
+    default :
+       return WinDefWindowProc(hWnd, message, mp1, mp2);
+    } /* switch(message) */
+
+    return(NULL);
+}
+
+
+/*
+**  Utility function:
+**
+**  move check mark from menu item 1 to item 2
+*/
+void
+ChangeCheck(HWND hWnd , USHORT wItem1 , USHORT wItem2)
+{
+    HWND 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));
+}
+
+
+/*
+**  Copy window to clipboard as bitmap.
+*/
+static void
+CopyToClipBrd(HWND hWnd)
+{
+    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);
+}
+
+
+/*
+**  Copy ps to a bitmap.
+*/
+HBITMAP CopyToBitmap(HPS hps)
+{
+    HPS     hpsMem;
+    HWND    hwnd;
+    HAB     hab;
+    PSZ     psz[4] = {NULL, "Display", NULL, NULL};
+    HDC     hdcMem, hdcScr;
+    SIZEL   sizel;
+    BITMAPINFOHEADER2 bmp;
+    HBITMAP hbm;
+    LONG    alData[2];
+    RECTL   rectl;
+    POINTL  aptl[6];
+
+    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;
+}
+
+
+/*
+**  Copy ps to a metafile.
+*/
+HMF
+CopyToMetaFile(HPS hps)
+{
+    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;
+}
+
+
+/*
+** Query INI file
+*/
+BOOL
+QueryIni(HAB hab)
+{
+    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;
+    }
+    ulCB = sizeof(bKeepRatio);
+    bData = PrfQueryProfileData(hini, APP_NAME, INIKEEPRATIO, &ulOpts, &ulCB);
+    if (bData) bKeepRatio =(BOOL)ulOpts[0];
+
+    /* Mousing: */
+    /* Ignore reading "Use mouse" --- no good idea to have mouse on by default.
+       Maybe it was the reason of some crashes(mouse init before draw).
+       ulCB = sizeof(useMouse);
+       bData = PrfQueryProfileData(hini, APP_NAME, INIUSEMOUSE, &ulOpts, &ulCB);
+       if (bData) useMouse =(int)ulOpts[0];
+    */
+    /* ignore reading mouse cursor(real, relative or pixels).
+       Reason/bug: it does not switch the check mark in the menu, even
+       though it works as expected.
+       ulCB = sizeof(mouse_mode);
+       bData = PrfQueryProfileData(hini, APP_NAME, INIMOUSECOORD, &ulOpts, &ulCB);
+       if (bData) mouse_mode =(ULONG)ulOpts[0];
+    */
+
+    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;
+}
+
+
+/*
+** save data in ini file
+*/
+static void
+SaveIni(HWND hWnd)
+{
+    SWP     swp;
+    HINI    hini;
+    ULONG   ulOpts[5];
+    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));
+       PrfWriteProfileData(hini, APP_NAME, INIKEEPRATIO, &bKeepRatio,
+                           sizeof(bKeepRatio));
+
+       /* Mouse stuff */
+       /* Ignore reading "Use mouse" --- no good idea to have mouse on by default.
+          Maybe it was the reason of some crashes(mouse init before draw).
+          PrfWriteProfileData(hini, APP_NAME, INIUSEMOUSE, &useMouse, sizeof(useMouse));
+       */
+       /* Do not write the mouse coord. mode.
+          PrfWriteProfileData(hini, APP_NAME, INIMOUSECOORD, &mouse_mode, sizeof(mouse_mode));
+       */
+        PrfCloseProfile(hini);
+    } else {
+        WinMessageBox(HWND_DESKTOP,
+                     HWND_DESKTOP,
+                     "Can't write ini file",
+                     APP_NAME,
+                     0,
+                     MB_OK | MB_ICONEXCLAMATION);
+    }
+}
+
+
+/*
+**  Paint the screen with current data
+*/
+static void
+DoPaint(HWND hWnd, HPS hps)
+{
+    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);
+}
+
+
+/*
+**  Thread to draw plot on screen
+*/
+static void
+ThreadDraw(void* arg)
+{
+    HAB hab = WinInitialize(0);
+
+    InitScreenPS();
+
+    DosRequestMutexSem(semHpsAccess,(ULONG) SEM_INDEFINITE_WAIT);
+    ScalePS(hpsScreen);
+    GpiSetStopDraw(hpsScreen, SDW_OFF);
+    GpiSetDrawingMode(hpsScreen, DM_DRAW);
+    GpiDrawChain(hpsScreen);
+    DrawRuler();
+    DisplayStatusLine(hpsScreen);
+    WinEndPaint(hpsScreen);
+    DosReleaseMutexSem(semHpsAccess);
+    WinTerminate(hab);
+    tidDraw = 0;
+#if 0
+    /* This does not work here(why?!), thus moved to pm.trm: PM_text(); */
+    gp_exec_event(GE_plotdone, mx, my, 0, 0, 0); /* enable again zoom and scale by mouse motions */
+#endif
+}
+
+
+/*
+** Initialise the screen ps for drawing
+*/
+HPS
+InitScreenPS()
+{
+    RECTL   rectClient;
+    int     nColour = 0;
+
+    GpiResetPS(hpsScreen, GRES_ATTRS);
+#if 0 /* Use default background color(the original version) */
+    GpiErase(hpsScreen);
+    WinQueryWindowRect(hApp,(PRECTL)&rectClient);
+#else /* PM 14.3.2000: Use always white background */
+    WinQueryWindowRect(hApp,(PRECTL)&rectClient);
+    WinFillRect(hpsScreen,&rectClient,CLR_WHITE);
+#endif
+    if (bKeepRatio) {
+       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);
+       }
+    } else
+       /* PM: why this -10? Otherwise the right axis is too close to
+        * the right border. However, this -10 should be taken into
+        * account for mousing! Or can it be inside a transformation?
+        */
+       rectClient.xRight -= 10;
+
+    GpiSetPageViewport(hpsScreen, &rectClient);
+    if (!bColours) {
+        int i;
+
+       nColour = 16;
+       alColourTable[0] = 0xFFFFFF;
+       for (i=1; i<nColour; i++)
+           alColourTable[i] = 0;
+    }
+
+    if (bPMPaletteMode) {
+       int i;
+
+       GpiCreateLogColorTable(hpsScreen, LCOL_RESET, LCOLF_CONSECRGB,
+                              0, nColour, alColourTable);
+       if (!lCols_init) { /* Ilya: avoid white line on white background */
+           lCols_init = 1;
+           GpiQueryLogColorTable(hpsScreen, 0, 0, 16, alColourTable + 2);
+           alColourTable[2+CLR_WHITE] = 0xffffff;              /* -2 */
+           alColourTable[2+CLR_BLACK] = 0;                     /* -1 */
+           bkColor = alColourTable[2+CLR_BACKGROUND];
+           i = -1;
+           while (i++ < 16) {
+               if (alColourTable[2+lCols[i]] == bkColor) {
+                   while (i++ < 16)
+                       lCols[i - 1] = lCols[i];
+                   lCols_num--;
+                   break;
+               }
+           }
+       }
+
+       /* init rgb_colors: simple index translation only */
+       for (i=0; i<18; i++)
+           rgb_colors[i] = i + CLR_WHITE;
+    } else {
+       if (!lCols_init) {
+           int i;
+
+           lCols_init = 1;
+           /* get RGB values of all CLR_xxx constants */
+           for (i=0; i<18; i++)
+               rgb_colors[i] = GpiQueryRGBColor(hpsScreen, LCOLOPT_REALIZED, i + CLR_WHITE );
+       }
+
+       GpiCreateLogColorTable(hpsScreen, LCOL_RESET, LCOLF_RGB, 0, 0, 0);
+    }
+    return hpsScreen;
+}
+
+
+/*
+**  Get a font to use
+**  Scale the plot area to world coords for subsequent plotting
+*/
+short
+ScalePS(HPS hps)
+{
+    SelectFont(hps, szFontNameSize);
+    return 0;
+}
+
+
+/*
+**  Select a named and sized outline font
+*/
+void
+SelectFont(HPS hps, char *szFontNameSize)
+{
+    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      = codepage; /*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 0
+    if (bNewFont) {
+       /* EditCharCell(hps, &sizfx); */
+        bNewFont = FALSE;
+    }
+#endif
+}
+
+
+/*
+**  Select a named and sized outline(adobe) font
+*/
+void
+SwapFont(HPS hps, char *szFNS)
+{
+    HDC    hdc;
+    FATTRS  fat;
+    LONG   xDeviceRes, yDeviceRes;
+    POINTL ptlFont;
+    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      = codepage; /*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);
+        } /* if (lcid) */
+
+        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;
+       }
+    }
+}
+
+typedef struct image_list_entry {
+    PBITMAPINFO2 pbmi;
+    PBYTE image;
+    struct image_list_entry *next;
+} image_list_entry;
+static image_list_entry *image_list = NULL;
+
+
+/*
+** 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.
+*/
+static void
+ReadGnu(void* arg)
+{
+    HPIPE hRead = 0L;
+    POINTL ptl;
+    long lOldLine = 0;
+    BOOL bPath = FALSE;
+    BOOL bDots = FALSE;
+    ULONG rc;
+    USHORT usErr;
+    ULONG cbR;
+    USHORT i;
+    unsigned char buff[2];
+    HEV hev;
+    static char *szPauseText = NULL;
+    ULONG ulPause;
+    char *pszPipeName, *pszSemName;
+    HPS hps;
+    HAB hab;
+    int linewidth = DEFLW;
+    HPAL pm3d_hpal = 0;     /* palette used for make_palette() */
+    HPAL pm3d_hpal_old = 0; /* default palette used before make_palette() */
+    LONG pm3d_color = 0;    /* current colour (used if it is >0) */
+    ULONG *rgbTable = NULL; /* current colour table (this is a 'virtual' palette) */
+
+    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);
+
+       sprintf(mouseShareMemName, "\\SHAREMEM\\GP%i_Mouse_Input",(int)ppidGnu);
+       if (DosGetNamedSharedMem(&input_from_PM_Terminal,
+                                mouseShareMemName,
+                                PAG_WRITE)) {
+           /*now: gray menu items; old code: DosBeep(1440L,1000L); // indicates error */
+           input_from_PM_Terminal = 0;
+       }
+
+       semInputReady = 0;
+       /* semaphore 'semInputReady' must be open later in order to avoid problems */
+       /* with the server mode; also 'bhave_*' init here because of server */
+
+       /* 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;
+
+           if (breakDrawing) {
+               /* PM: drawing has been stopped(by Ctrl-C)... */
+               hps = 0;        /*     ...thus drawings go to nowhere... */
+               if (*buff == SET_TEXT) { /* ...unless 'plot finished' command */
+                   POINTL p;
+                   hps = hpsScreen;  /* drawings back to screen */
+                   breakDrawing = 0;
+                   GpiSetColor(hps, RGB_TRANS(CLR_RED)); /* cross the unfinished plot */
+                   GpiBeginPath(hps, 1);
+                   p.x = p.y = 0; GpiMove(hps, &p);
+                   p.x = 19500; p.y = 12500; GpiLine(hps, &p);
+                   p.x = 0; p.y = 12500; GpiMove(hps, &p);
+                   p.x = 19500; p.y = 0; GpiLine(hps, &p);
+                   GpiEndPath(hps);
+                   GpiStrokePath(hps, 1, 0);
+               }
+           }
+
+            switch (*buff) {
+           case SET_GRAPHICS :    /* enter graphics mode */
+           {
+               image_list_entry *ile;
+
+               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);
+
+               /* free image buffers from previous plot, if any */
+               while (image_list) {
+                   DEBUG_IMAGE(("freeing image from last plot"));
+                   ile = image_list;
+                   image_list = ile->next;
+                   free(ile->image);
+                   free(ile->pbmi);
+                   free(ile);
+               }
+
+               break;
+           }
+
+           case GR_QUERY :     /* query terminal info */
+               /* mouseable gnupmdrv sends greetings to mouseable PM terminal */
+               if (mouseTerminal) {
+                   int i=0xABCD;
+
+                   DosWrite(hRead, &i, sizeof(int), &cbR);
+               }
+               DosWrite(hRead, &lCharWidth, sizeof(int), &cbR);
+               DosWrite(hRead, &lCharHeight, sizeof(int), &cbR);
+               break;
+
+           case SET_TEXT :     /* leave graphics mode(graph completed) */
+               if (bPath) {
+                   GpiEndPath(hps);
+                   GpiStrokePath(hps, 1, 0);
+                   bPath = FALSE;
+               }
+               GpiCloseSegment(hps);
+               DrawRuler();
+               DisplayStatusLine(hps);
+               /* DosPostEventSem(semDrawDone); */
+               DosReleaseMutexSem(semHpsAccess);
+               WinPostMsg(hApp, WM_GNUPLOT, 0L, 0L);
+               break;
+
+           case GR_RESET :
+               /* 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 GR_RESUME :
+           {
+               /* resume after multiplot */
+               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 GR_MOVE :   /* move */
+           case GR_DRAW :   /* draw vector */
+           {
+               LONG curr_color;
+
+               if (pm3d_color >= 0) {
+                   curr_color = GpiQueryColor(hps);
+                   GpiSetColor(hps, pm3d_color);
+               }
+               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);
+
+               if (pm3d_color >= 0)
+                   GpiSetColor(hps, curr_color);
+           }
+           break;
+
+           case GR_PAUSE  :   /* pause */
+           {
+               int len;
+
+               pausing = 1;
+               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);
+               pausing = 0;
+               break;
+           }
+
+           case GR_ENH_TEXT :  /* write enhanced text */
+               if (bPath) {
+                   GpiEndPath(hps);
+                   GpiStrokePath(hps, 1, 0);
+                   bPath = FALSE;
+               }
+               {
+                    unsigned int x, y, len;
+                   unsigned int mode;
+                   int textwidth, textheight;
+                    char *str;
+                    POINTL aptl[TXTBOX_COUNT];
+
+                   /* read x, y, mode, len */
+                   BufRead(hRead, &x, sizeof(int), &cbR);
+                    BufRead(hRead, &y, sizeof(int), &cbR);
+                    BufRead(hRead, &mode, 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);
+
+                    GpiQueryTextBox(hps, strlen(str), str, TXTBOX_COUNT, aptl);
+                   textwidth = aptl[TXTBOX_CONCAT].x;
+                   textheight = aptl[TXTBOX_CONCAT].y;
+
+                   /* only display text if requested */
+                   if (mode & 0x01) {
+                       LONG curr_color;
+
+                       if (pm3d_color >= 0) {
+                           curr_color = GpiQueryColor(hps);
+                           GpiSetColor(hps, pm3d_color);
+                       }
+                       ptl.x = (LONG) (x + multLineVert * (lVOffset / 4));
+                       ptl.y = (LONG) (y - multLineHor * (lVOffset / 4));
+
+                       GpiSetBackMix(hps, BM_LEAVEALONE);
+                       GpiCharStringAt(hps, &ptl, strlen(str), str);
+
+                       if (pm3d_color >= 0)
+                           GpiSetColor(hps, curr_color);
+                   }
+
+                   /* report back textwidth */
+                   DosWrite(hRead, &textwidth, sizeof(textwidth), &cbR);
+                   DosWrite(hRead, &textheight, sizeof(textheight), &cbR);
+
+                    DosEnterCritSec();
+                    free(str);
+                   DosExitCritSec();
+
+                   break;
+               }
+
+           case GR_TEXT :   /* write text */
+               /* read x, y, len */
+               if (bPath) {
+                   GpiEndPath(hps);
+                   GpiStrokePath(hps, 1, 0);
+                   bPath = FALSE;
+               }
+               {
+                    unsigned int x, y, len;
+                   int sw;
+                    char *str;
+                   LONG curr_color;
+#ifndef PM_KEEP_OLD_ENHANCED_TEXT
+                    POINTL aptl[TXTBOX_COUNT];
+#endif
+                   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);
+                   if (pm3d_color >= 0) {
+                        curr_color = GpiQueryColor(hps);
+                       GpiSetColor(hps, pm3d_color);
+                   }
+
+#ifdef PM_KEEP_OLD_ENHANCED_TEXT
+                    sw = QueryTextBox(hps, strlen(str), str);
+#else
+                    GpiQueryTextBox(hps, strlen(str), str, TXTBOX_COUNT, aptl);
+                   sw = aptl[TXTBOX_BOTTOMRIGHT].x;
+#endif
+
+                    switch (jmode) {
+                   case LEFT:
+                       sw = 0;
+                       break;
+                   case CENTRE:
+                       sw /= -2;
+                       break;
+                   case RIGHT:
+                       sw *= -1;
+                       break;
+                   }
+
+                   ptl.x = (LONG) (x + multLineHor * sw + multLineVert * (lVOffset / 4));
+                   ptl.y = (LONG) (y + multLineVert * sw - multLineHor * (lVOffset / 4));      
+
+                   GpiSetBackMix(hps, BM_LEAVEALONE);
+
+#ifdef PM_KEEP_OLD_ENHANCED_TEXT
+                    if (bEnhanced)
+                        CharStringAt(hps, ptl.x, ptl.y, strlen(str) , str);
+                    else
+#endif
+                       GpiCharStringAt(hps, &ptl, strlen(str), str);
+
+                   if (pm3d_color >= 0)
+                        GpiSetColor(hps, curr_color);
+
+                    DosEnterCritSec();
+                    free(str);
+                   DosExitCritSec();
+
+                   break;
+               }
+
+           case SET_JUSTIFY :   /* justify */
+               BufRead(hRead, &jmode, sizeof(int), &cbR);
+               //printf( "SET_JUSTIFY: %i", jmode );
+               break;
+
+           case SET_ANGLE :   /* text angle */
+           {
+               int ta, t1;
+               GRADIENTL grdl;
+
+               if (bPath) {
+                   GpiEndPath(hps);
+                   GpiStrokePath(hps, 1, 0);
+                   bPath = FALSE;
+               }
+               BufRead(hRead, &ta, sizeof(int), &cbR);
+               t1 = ta % 360;
+               if (t1 < 0)
+                   t1 += 360;
+               switch (t1) {
+               case   0:
+                   grdl.x =  1L;
+                   grdl.y =  0L;
+                   multLineHor = 1;
+                   multLineVert = 0;
+                   break;
+               case  90:
+                   grdl.x =  0L;
+                   grdl.y =  1L;
+                   multLineHor = 0;
+                   multLineVert = 1;
+                   break;
+               case 180:
+                   grdl.x = -1L;
+                   grdl.y =  0L;
+                   multLineHor = -1;
+                   multLineVert = 0;
+                   break;
+               case 270:
+                   grdl.x =  0L;
+                   grdl.y = -1L;
+                   multLineHor = 0;
+                   multLineVert = -1;
+                   break;
+               default:  {
+                   double t = t1 * M_PI/180;
+
+                   grdl.x = (LONG) (100 * cos(t));
+                   grdl.y = (LONG) (100 * sin(t));
+                   multLineHor = cos(t);
+                   multLineVert = sin(t);
+               } /* default case */
+               } /* switch(t1) */
+
+               GpiSetCharAngle(hps, &grdl);
+               break;
+           }
+
+           case SET_LINE :   /* line type */
+           {
+               int lt, col;
+
+               if (bPath) {
+                   GpiEndPath(hps);
+                   GpiStrokePath(hps, 1, 0);
+                   bPath = FALSE;
+               }
+               BufRead(hRead,&lt, 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) ? lt : 0);
+               /* GpiSetLineType(hps, (bLineTypes) ? lLineTypes[lt] : lLineTypes[0]); */
+               /* maintain some flexibility here in case we don't want
+                * the model T option */
+               if (bColours)
+                   GpiSetColor(hps, RGB_TRANS(lCols[col]));
+               /* else GpiSetColor(hps, RGB_TRANS(CLR_BLACK)); */
+               else
+                   GpiSetColor(hps, RGB_TRANS(CLR_NEUTRAL));
+               pm3d_color = -1; /* switch off using pm3d colours */
+               break;
+           }
+
+           case SET_FILLBOX :   /* fill box */
+           {
+               int style;
+               unsigned int x, y, w, h;
+               POINTL pt;
+
+               BufRead(hRead,&style, sizeof(style), &cbR);
+               BufRead(hRead,&x, sizeof(x), &cbR);
+               BufRead(hRead,&y, sizeof(y), &cbR);
+               BufRead(hRead,&w, sizeof(w), &cbR);
+               BufRead(hRead,&h, sizeof(h), &cbR);
+               pt.x = x;
+               pt.y = y;
+               GpiMove(hpsScreen, &pt);
+               pt.x += w;
+               pt.y += h;
+
+               switch(style & 0xf) {
+
+                   case FS_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);
+                       GpiSetBackMix(hps, BM_OVERPAINT);
+                       GpiSetPattern(hps, patternlist[pattern]);
+                       break;
+                   }
+
+                   case FS_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);
+                       GpiSetBackMix(hps, BM_OVERPAINT);
+                       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);
+                       //GpiSetColor(hps, RGB_TRANS(CLR_BACKGROUND));  // fixes 'with boxes' white on white
+                       GpiSetPattern(hps, PATSYM_SOLID);
+                   }
+               }
+               GpiBox(hps, DRO_FILL, &pt, 0,0);
+               break;
+           }
+
+           case SET_LINEWIDTH :   /* 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 SET_POINTMODE :   /* points mode */
+           {
+               int lt;
+
+               BufRead(hRead,&lt, sizeof(int), &cbR);
+               /* 1: enter point mode, 0: exit */
+               if (bLineTypes) {
+                   if (lt==1)
+                       LType(0);
+                   else
+                       LType(lOldLine);
+#if 0
+                   if (lt == 1)
+                       lOldLine = GpiSetLineType(hps, lLineTypes[0]);
+                   else
+                       GpiSetLineType(hps, lOldLine);
+#endif /* 0 */
+               }
+#if 0
+               if (lt == 1)
+                   GpiSetLineWidthGeom(hps, 20);
+               else
+                   GpiSetLineWidthGeom(hps, 50);
+#endif /* 0 */
+               bDots = lt;
+           }
+           break;
+
+           case SET_FONT :   /* set font */
+           {
+               int len;
+
+               BufRead(hRead, &len, sizeof(int), &cbR);
+               len = (len + sizeof(int) - 1) / sizeof(int);
+
+               if (len == 0) {
+                   SwapFont(hps, NULL);
+                   strcpy(szCurrentFontNameSize, szFontNameSize);
+               } else {
+                   char font[FONTBUF];
+                   char *p, *tmp, *str;
+
+                   tmp = str = malloc(len * sizeof(int));
+                   BufRead(hRead, str, len * sizeof(int), &cbR);
+                   p = strchr(str, ',');
+                   if (p==NULL)
+                       strcpy(font, "10");
+                   else {
+                       *p = '\0';
+                       strcpy(font, p+1);
+                   }
+                   strcat(font, ".");
+                   /* allow abbreviation of some well known font names */
+                   FontExpand(str);
+                   strcat(font, str);
+                   free(tmp);
+                   SwapFont(hps, font);
+                   strcpy(szCurrentFontNameSize, font);
+               } /* else(len==0) */
+               break;
+           }
+
+           case GR_QUERY_FONT : /* query current font */
+           {
+               int namelen;
+
+               namelen = strlen(szCurrentFontNameSize);
+               DosWrite(hRead, &namelen, sizeof(int), &cbR);
+               DosWrite(hRead, szCurrentFontNameSize, namelen, &cbR);
+               /* FIXME: is padding necessary? */
+               break;
+           }
+
+           case SET_OPTIONS :   /* set options */
+           {
+               int len;
+               char *str;
+
+               BufRead(hRead,&len, sizeof(int), &cbR);
+               len =(len + sizeof(int) - 1) / sizeof(int);
+               bWideLines = FALSE; /* reset options */
+#ifdef PM_KEEP_OLD_ENHANCED_TEXT
+               bEnhanced = FALSE;
+#endif
+               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;
+#ifdef PM_KEEP_OLD_ENHANCED_TEXT
+                       if (*p == 'e')
+                           bEnhanced = TRUE;
+#endif
+                       ++p;
+                   }
+                   free(str);
+               }
+               break;
+           }
+
+           case SET_SPECIAL :   /* set special options */
+           {
+               char opt;
+#ifdef PM_KEEP_OLD_ENHANCED_TEXT
+               char param;
+               static int prev_bEnhanced = 0;
+#endif
+
+               BufRead(hRead,&opt, 1, &cbR);
+               switch (opt) {
+#ifdef PM_KEEP_OLD_ENHANCED_TEXT
+               case 'e': /* enhanced mode on, off and restore */
+                   BufRead(hRead,&param, 1, &cbR);         
+                   switch (param) {
+                   case '0': prev_bEnhanced = bEnhanced;
+                       bEnhanced = 0;
+                       break;
+                   case '1': prev_bEnhanced = bEnhanced;
+                       bEnhanced = 1;
+                       break;
+                   case '2': bEnhanced = prev_bEnhanced;
+                       break;
+                   }
+                   break;
+#endif
+               case 'c': /* set codepage */
+                   BufRead(hRead,&codepage, sizeof(codepage), &cbR);
+                   break;
+               case '^': /* raise window */
+                   WinSetWindowPos( hwndFrame, HWND_TOP, 0,0,0,0, SWP_RESTORE|SWP_SHOW|SWP_ACTIVATE|SWP_ZORDER ) ;
+                   WinSetFocus( HWND_DESKTOP, hApp ) ;
+                   break;
+               case '_': /* lower window */
+                   WinSetWindowPos( hwndFrame, HWND_BOTTOM, 0,0,0,0, SWP_ZORDER ) ;
+                   break;
+               }
+               break;
+           }
+
+           case PUT_TMPTEXT :
+           {  /* put_tmptext(int i, char c[]) term API */
+               /* i = 0 at statusline,
+                  1,2: at corners of zoom box, with \r separating text */
+               int where, l;
+               static char *text = NULL;
+               static int text_alloc = -1;
+
+               /* Position of the "table" of values resulting from
+                * mouse movement(and clicks).  Negative y value would
+                * position it at the top of the window---not
+                * implemented. */
+               BufRead(hRead,&where, sizeof(int), &cbR);
+               BufRead(hRead,&l, sizeof(int), &cbR);
+               if (text_alloc < l)
+                   text = realloc(text, text_alloc = l+10);
+               BufRead(hRead,&text[0], l, &cbR);
+               switch (where) {
+               case 0:
+                   UpdateStatusLine(hps,text);
+                   break;
+               case 1:
+               case 2:
+                   break; /* not implemented */
+               }
+               break;
+           }
+
+           /* Implementation problems(I haven't understood that from
+            * .INF doc): what is the difference between
+            * GpiCreateLogColorTable and GpiCreatePalette? */
+           case GR_MAKE_PALETTE :
+           {
+               unsigned char c;
+               int smooth_colors;
+               LONG lRetCount;
+
+               /* read switch */
+               BufRead(hRead, &c, sizeof(c), &cbR);
+               if (c == 0) {
+                   /* gnuplot asks for the number of colours in palette */
+                   smooth_colors = (bPMPaletteMode ? (256 - nColors) : RGB_PALETTE_SIZE);
+                   DosWrite(hRead, &smooth_colors, sizeof(int), &cbR);
+                   DEBUG_COLOR(("GR_MAKE_PALETTE: max %i colours", smooth_colors));
+                   break;
+               }
+
+               /* read the number of colours for the palette */
+               BufRead(hRead, &smooth_colors, sizeof(int), &cbR);
+               free(rgbTable);
+               rgbTable = malloc(smooth_colors * sizeof(ULONG));
+
+               /* append new RGB table after */
+               DEBUG_COLOR(("GR_MAKE_PALETTE: reading palette with %i colours", smooth_colors));
+               BufRead(hRead, &rgbTable[bPMPaletteMode ? nColors : 0],
+                       smooth_colors * sizeof(ULONG), &cbR);
+
+               if (bPMPaletteMode) {
+                   int i;
+                   ULONG cclr;
+
+                   /* preserve the first nColors entries of current palette */
+                   /* retrieve the current table */
+                   lRetCount = GpiQueryLogColorTable(hps, 0L, 0L, nColors, alColourTable);
+                   if ((lRetCount > 0) && (lRetCount != nColors)) /* ring for developers! */
+                       DosBeep(880, 777);
+                   for (i=0; i<nColors; i++)
+                       rgbTable[i] = alColourTable[i];
+
+                   if (pm3d_hpal != 0)
+                       GpiDeletePalette(pm3d_hpal);
+                   pm3d_hpal = GpiCreatePalette(hab, 0L, LCOLF_CONSECRGB,
+                                            (long) (nColors + smooth_colors), rgbTable);
+                   pm3d_hpal_old = GpiSelectPalette(hps, pm3d_hpal);
+
+                   /* tell presentation manager to use the new palette */
+                   WinRealizePalette(WinWindowFromDC(hdcScreen), hps, &cclr);
+               }
+               break;
+           }
+
+           case GR_RELEASE_PALETTE :
+#if 0 /* FIXME: REMOVE THIS ROUTINE COMPLETELY! */
+               if (pm3d_hpal) {
+                   GpiDeletePalette(pm3d_hpal);
+                   pm3d_hpal = 0;
+               }
+               /* GpiSelectPalette(hps, pm3d_hpal_old); */
+#endif
+               break;
+
+           case GR_SET_COLOR :
+           {
+               /* FIXME: usgage of uchar limits the size of the 'virtual'
+                         palette to 256 entries. (see also RGB_PALETTE_SIZE) */
+               unsigned char c;
+
+               BufRead(hRead, &c, sizeof(c), &cbR);
+               if (bPMPaletteMode)
+                   pm3d_color = c + nColors;
+               else
+                   pm3d_color = rgbTable[c];
+               DEBUG_COLOR(("GR_SET_COLOR: %i -> 0x%x", (int)c, pm3d_color)); 
+               break;
+           }
+
+           case GR_SET_RGBCOLOR :
+           {
+               int rgb_color;
+
+               BufRead(hRead, &rgb_color, sizeof(rgb_color), &cbR);
+
+               /* Find an approximate color in the current palette */
+               if (bPMPaletteMode)
+                   pm3d_color = GpiQueryColorIndex(hps, 0, rgb_color);
+               else
+                   pm3d_color = rgb_color;
+#if 0
+               {
+               int real_rgb = GpiQueryRGBColor(hps, LCOLOPT_REALIZED, pm3d_color);
+               DEBUG_COLOR(( "GR_SET_RGBCOLOR: req = %x  nearest = %x  index = %x", 
+                             rgb_color, real_rgb, pm3d_color ));
+               }
+#endif
+               break;
+           }
+
+           case GR_FILLED_POLYGON :
+           {
+               int points, x,y, i;
+               LONG curr_color;
+               POINTL p;
+
+               BufRead(hRead, &points, sizeof(points), &cbR);
+               GpiSetPattern(hps, PATSYM_SOLID);
+               GpiSetBackMix(hps, BM_OVERPAINT);
+               if (pm3d_color >= 0) {
+                   curr_color = GpiQueryColor(hps);
+                   GpiSetColor(hps, pm3d_color);
+               }
+
+               /* using colours defined in the palette */
+               GpiBeginArea(hps, BA_BOUNDARY | BA_ALTERNATE);
+               for (i = 0; i < points; i++) {
+                   BufRead(hRead, &x, sizeof(x), &cbR);
+                   BufRead(hRead, &y, sizeof(y), &cbR);
+                   p.x = x; p.y = y;
+                   if (i)
+                       GpiLine(hps, &p);
+                   else
+                       GpiMove(hps, &p);
+               }
+               GpiEndArea(hps);
+               if (pm3d_color >= 0)
+                   GpiSetColor(hps, curr_color);
+               break;
+           }
+
+           case GR_RGB_IMAGE : 
+           {
+               unsigned int i, M, N, image_size;
+               POINTL corner[4];
+               PBYTE image;
+               PBITMAPINFO2 pbmi;
+               POINTL points[4];
+               LONG hits;
+               PERRINFO perriBlk;
+               image_list_entry *ile;
+
+               BufRead(hRead, &M, sizeof(M), &cbR);
+               BufRead(hRead, &N, sizeof(N), &cbR);
+               for (i=0; i<4; i++) {
+                   BufRead(hRead, &(corner[i].x), sizeof(int), &cbR);
+                   BufRead(hRead, &(corner[i].y), sizeof(int), &cbR);
+               }
+               BufRead(hRead, &image_size, sizeof(image_size), &cbR);
+               DEBUG_IMAGE(("GR_IMAGE: M=%i, N=%i, size=%i", M, N, image_size));
+               DEBUG_IMAGE(("GR_IMAGE: corner [0]=(%i,%i) [1]=(%i,%i)", corner[0].x, corner[0].y, corner[1].x, corner[1].y));
+               image = (PBYTE) malloc(image_size);
+               /* FIXME: does not work if GNUBUF < image_size ! */
+               BufRead(hRead, image, image_size, &cbR);
+
+               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;
+
+               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;
+               hits = GpiDrawBits(hps, image, pbmi, 4, &points, ROP_SRCCOPY, BBO_IGNORE );
+
+#if 0
+               if (hits == GPI_ERROR) {
+                   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);
+                   }
+               }
+#endif
+
+               /* We have to keep the image and the image 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;
+
+               break;
+           }
+
+           case SET_RULER : { /* set_ruler(int x, int y) term API: x<0 switches ruler off */
+               int x, y;
+
+               BufRead(hRead, &x, sizeof(x), &cbR);
+               BufRead(hRead, &y, sizeof(y), &cbR);
+               DrawRuler(); /* remove previous drawing, if any */
+               if (x < 0) {
+                   ruler.on = 0;
+                   break;
+               }
+               ruler.on = 1;
+               ruler.x = x;
+               ruler.y = y;
+               DrawRuler();
+               break;
+           }
+
+           case SET_CURSOR : { /* set_cursor(int c, int x, int y) term API */
+               int c, x, y;
+
+               BufRead(hRead, &c, sizeof(x), &cbR);
+               BufRead(hRead, &x, sizeof(x), &cbR);
+               BufRead(hRead, &y, sizeof(y), &cbR);
+               switch (c) {
+               case -2: { /* move mouse to the given point */
+                   RECTL rc;
+                   POINTL pt;
+
+                   GpiQueryPageViewport(hpsScreen,&rc);
+                   /* only distance is important */
+                   rc.xRight -= rc.xLeft;
+                   rc.yTop -= rc.yBottom;
+                   /* window => pixels coordinates */
+                   pt.x =(long int) ((x * (double) rc.xRight) / 19500.0);
+                   pt.y =(long int) ((x * (double) rc.yTop) / 12500.0);
+                   WinMapWindowPoints(hApp, HWND_DESKTOP, &pt, 1);
+                   WinSetPointerPos(HWND_DESKTOP, pt.x, pt.y);
+                   break;
+               }
+               case -1: /* start zooming; zooming cursor */
+                   zoombox.on = 1;
+                   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 = 0;
+               }
+               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 = 1;
+               }
+               break;
+
+           case GR_MOUSECAPABLE :
+               /* notification of being connected to a mouse-enabled terminal */
+               mouseTerminal = 1;
+               break;
+
+           default :  /* should handle error */
+               break;
+           }
+       }
+    }
+    DosDisConnectNPipe(hRead);
+    WinPostMsg(hApp, WM_CLOSE, 0L, 0L);
+}
+
+
+static void
+EditLineTypes(HWND hwnd, HPS hps, BOOL bDashed)
+{
+    int i;
+
+    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);
+}
+
+
+#if 0
+/*
+** Edit segment to change char cell(font size)
+*/
+static void
+EditCharCell(HPS hps, SIZEF *psize)
+{
+    int i;
+    LONG rl, rc;
+    SIZEF sizH, sizV;
+    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);
+}
+#endif
+
+/*
+** pull next plot command out of buffer read from GNUPLOT
+*/
+static int
+BufRead(HFILE hfile, void *buf, int nBytes, ULONG *pcbR)
+{
+    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;
+}
+
+
+#ifdef STANDARD_FONT_DIALOG
+
+/*
+** Get a new font using standard font dialog
+*/
+int
+GetNewFont(HWND hwnd, HPS hps)
+{
+    static FONTDLG pfdFontdlg;      /* Font dialog info structure */
+    static int i1 =1;
+    static int iSize;
+    char szPtList[64];
+    HWND hwndFontDlg;     /* Font dialog window handle */
+    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;
+        pfdFontdlg.fAttrs.usCodePage = codepage;
+        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;
+}
+
+#else
+
+/*
+** Get a new font using standard font palette
+*/
+int
+GetNewFont(HWND hwnd, HPS hps)
+{
+ HOBJECT hObject;
+ ULONG ulView = 0; /* OPEN_DEFAULT */
+ BOOL fSuccess = FALSE;
+
+ hObject = WinQueryObject("<WP_FNTPAL>");
+ if (hObject != NULL)
+  { fSuccess = WinOpenObject(hObject, ulView, TRUE); }
+  if (fSuccess) return 1;
+  else return 0;
+}
+
+#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
+
+/* disable debugging info */
+#define TEXT_DEBUG(x) /* fprintf x */ ;
+
+/* 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 */
+#if 0
+    {
+       FILE *ff = fopen("deb","a");
+       int i=textlen;
+
+       for (i=0;i<textlen;i++)
+           fputc(starttext[i], ff);
+       fputc('\n',ff);
+       fclose(ff);
+    }
+#endif /* 0 */
+
+    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];
+
+       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;
+           /*}}}*/
+
+       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((ff,"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((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;
+               }
+           } /* if ('/') */
+           /*}}}*/
+
+           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 = c * 8 + p[1];
+                   ++p;
+                   if (p[1] >= '0' && p[1] <= '7') {
+                       c = c * 8 + p[1];
+                       ++p;
+                   }
+               }
+               *q++ = c;
+               break;
+           }
+#endif /* 0 */
+
+           *q = '\0';
+           textlen = 1;
+           starttext=buffer;
+           ParseText(hps,q, FALSE, NULL/*fontname*/, fontsize,
+                     base, widthflag, showflag);
+           starttext=p+1;
+           textlen = 0;
+           /*}}}*/
+           break;
+       }
+
+       default:
+           ++textlen;
+
+           /*}}}*/
+       } /* switch(character) */
+
+       /* 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) {
+           textwidth += aptl[TXTBOX_BOTTOMRIGHT].x * multLineHor;
+           textwidth += aptl[TXTBOX_BOTTOMRIGHT].y * multLineVert;
+       }
+    }
+    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 += multLineVert * base;
+           ptlText.y -= multLineHor * base;
+       }
+    }
+    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)))
+       ; /* do nothing */
+}
+
+
+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)))
+       ; /* do nothing */
+
+    return textwidth;
+}
+
+#endif
+
+
+void
+FontExpand(char *name)
+{
+    if (strcmp(name,"S") == 0)
+       strcpy(name, "Symbol Set");
+    if (strcmp(name,"Symbol") == 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];
+}
+
+
+/* Now routines for mouse etc. */
+
+static void
+TextToClipboard(PCSZ szTextIn)
+{
+    /* copy string given by szTextIn to the clipboard */
+    PSZ szTextOut = NULL;
+    ULONG ulRC = DosAllocSharedMem(
+       (PVOID*) &szTextOut, NULL,
+       strlen(szTextIn) + 1,
+       PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE);
+
+    if (!ulRC) {
+       HAB hab = 0;
+
+       strcpy(szTextOut, szTextIn);
+       WinOpenClipbrd(hab);
+       WinEmptyClipbrd(hab);
+       WinSetClipbrdData(hab,(ULONG) szTextOut, CF_TEXT, CFI_POINTER);
+       WinCloseClipbrd(hab);
+    }
+}
+
+
+/* Draw the ruler
+*/
+static void
+DrawRuler()
+{
+    POINTL p;
+
+    if (!ruler.on || ruler.x < 0)
+       return;
+    /* GpiSetColor(hpsScreen, RGB_TRANS(COLOR_RULER)); */
+    GpiSetColor(hpsScreen, RGB_TRANS(CLR_RED));
+    GpiSetLineWidth(hpsScreen, LINEWIDTH_THICK);
+    GpiSetMix(hpsScreen, FM_INVERT);
+    /*GpiBeginPath(hpsScreen, 1); // will this help? I don't know, but makes thic cross */
+
+    p.x = 0;
+    p.y = ruler.y;
+    GpiMove(hpsScreen, &p);
+
+    p.x = 19500;
+    GpiLine(hpsScreen, &p);
+
+    p.x = ruler.x;
+    p.y = 0;
+    GpiMove(hpsScreen, &p);
+
+    p.y = 12500;
+    GpiLine(hpsScreen, &p);
+
+    /*GpiEndPath(hpsScreen); */
+    /*GpiStrokePath(hpsScreen, 1, 0); */
+}
+
+
+#if 0
+/* This routine recalculates mouse/pointer position [mx,my] in [in pixels]
+current window to the real/true [x,y] coordinates of the plotted graph.
+*/
+void
+MousePosToGraphPos(
+    double *x, double *y,
+    HWND hWnd,
+    SHORT mx, SHORT my,
+    ULONG mouse_mode)
+{
+    RECTL rc;
+
+    if (mouse_mode == MOUSE_COORDINATES_PIXELS) {
+       *x = mx;
+       *y = my;
+       return;
+    }
+
+    /* Rectangle where we are moving: viewport, not the full window! */
+    GpiQueryPageViewport(hpsScreen, &rc);
+
+    /* only distance is important */
+    rc.xRight -= rc.xLeft;
+    rc.yTop -= rc.yBottom;
+
+    if (mouse_mode == MOUSE_COORDINATES_SCREEN) {
+       *x =(double) mx / rc.xRight;
+       *y =(double) my / rc.yTop;
+       return;
+    }
+
+    /* px=px(mx); mouse=>gnuplot driver coordinates */
+    *x = mx * 19500.0 / rc.xRight;
+    *y = my * 12500.0 / rc.yTop;
+
+    /* main job of transformation, which is not device dependent */
+    MousePosToGraphPosReal(x, y);
+}
+#endif
+
+
+/*
+ * This routine recalculates mouse/pointer position [mx,my] in [in pixels]
+ * current window to the viewport coordinates
+ */
+static void
+MousePosToViewport(int *x, int *y, SHORT mx, SHORT my)
+{
+    RECTL rc;
+
+    /* Rectangle where we are moving: viewport, not the full window! */
+    GpiQueryPageViewport(hpsScreen, &rc);
+
+    rc.xRight -= rc.xLeft;
+    rc.yTop -= rc.yBottom; /* only distance is important */
+
+    /* px=px(mx); mouse=>gnuplot driver coordinates */
+    *x =(int)(mx * 19500.0 / rc.xRight + 0.5);
+    *y =(int)(my * 12500.0 / rc.yTop + 0.5);
+}
+
+
+/*
+ * This routine gets the mouse/pointer position in the current window and
+ * recalculates it to the viewport coordinates
+ */
+static void
+GetMousePosViewport(HWND hWnd, int *mx, int *my)
+{
+    POINTL p;
+
+    WinQueryPointerPos(HWND_DESKTOP, &p); /* this is position wrt desktop */
+    WinMapWindowPoints(HWND_DESKTOP, hWnd, &p, 1); /* pos. wrt our window in pixels */
+    MousePosToViewport(mx,my,p.x,p.y);
+}
+
+
+/*
+ * Status line previous and current text:
+ */
+static char *sl_curr_text = NULL;
+
+/*
+ * Display the status line by the text
+ */
+static void
+DisplayStatusLine(HPS hps)
+{
+    POINTL pt;
+
+    if (!sl_curr_text)
+       return;
+    GpiSetColor(hps, RGB_TRANS(COLOR_MOUSE)); /* set text color */
+    GpiSetCharMode(hps, CM_MODE1);
+    pt.x = 2;
+    pt.y = 2;
+    GpiSetMix(hps, FM_INVERT);
+    /* GpiSetMix(hps, FM_XOR); */
+    GpiCharStringAt(hps, &pt,(long) strlen(sl_curr_text), sl_curr_text);
+}
+
+
+/*
+ * Update the status line by the text; firstly erase the previous text
+ */
+static void
+UpdateStatusLine(HPS hps, char *text)
+{
+    if (gpPMmenu_update_req)
+       gpPMmenu_update(); /* check for updated menu */
+    if (sl_curr_text) {
+       /* erase the previous text */
+       DisplayStatusLine(hps);
+       free(sl_curr_text);
+    }
+    if (!text || !*text)
+       sl_curr_text = 0;
+    else {
+       /* display new text */
+       sl_curr_text = strdup(text);
+       DisplayStatusLine(hps);
+    }
+}
+
+
+/*
+ * Graphics part SET_GRAPHICS or anything else required to update menu according to
+ * the items in gpPMmenu
+ */
+static void
+gpPMmenu_update()
+{
+#if 0
+    if (!gpPMmenu_update_req)
+       return;
+#endif
+
+    ChangeCheck(hApp, IDM_USEMOUSE, useMouse ? IDM_USEMOUSE:0);
+    WinEnableMenuItem(/* can this situation be unzoomed back? */
+       WinWindowFromID(WinQueryWindow(hApp, QW_PARENT), FID_MENU),
+       IDM_MOUSE_UNZOOM,(gpPMmenu.where_zoom_queue & 1) ? TRUE : FALSE);
+    WinEnableMenuItem(/* can this situation be unzoomed to the beginning? */
+       WinWindowFromID(WinQueryWindow(hApp, QW_PARENT), FID_MENU),
+       IDM_MOUSE_UNZOOMALL,(gpPMmenu.where_zoom_queue & 2) ? TRUE : FALSE);
+    if (
+       WinEnableMenuItem(/* can this situation be zoomed next? */
+           WinWindowFromID(WinQueryWindow(hApp, QW_PARENT), FID_MENU),
+           IDM_MOUSE_ZOOMNEXT,(gpPMmenu.where_zoom_queue & 4) ? TRUE : FALSE)
+       == TRUE) gpPMmenu_update_req = 0;
+    ChangeCheck(hApp, IDM_MOUSE_POLAR_DISTANCE, gpPMmenu.polar_distance?IDM_MOUSE_POLAR_DISTANCE:0);
+}
+
+
+static void
+DrawZoomBox()
+{
+    if (!zoombox.on)
+       return;
+    GpiSetLineWidth(hpsScreen, LINEWIDTH_NORMAL);
+    GpiSetLineType(hpsScreen,LINETYPE_SHORTDASH);
+    GpiSetMix(hpsScreen,FM_INVERT);
+    GpiMove(hpsScreen, &zoombox.from);
+    GpiBox(hpsScreen, DRO_OUTLINE, &zoombox.to, 0,0);
+    GpiSetLineType(hpsScreen,LINETYPE_DEFAULT);
+}
+
+/* eof gclient.c */
+