• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

plframe.c

Go to the documentation of this file.
00001 // $Id: plframe.c 11760 2011-06-01 19:29:11Z airwin $
00002 //
00003 //  Copyright 1993, 1994, 1995
00004 //  Maurice LeBrun                      mjl@dino.ph.utexas.edu
00005 //  Institute for Fusion Studies        University of Texas at Austin
00006 //
00007 //  Copyright (C) 2004  Joao Cardoso
00008 //  Copyright (C) 2004  Andrew Ross
00009 //
00010 //  This file is part of PLplot.
00011 //
00012 //  PLplot is free software; you can redistribute it and/or modify
00013 //  it under the terms of the GNU Library General Public License as published
00014 //  by the Free Software Foundation; either version 2 of the License, or
00015 //  (at your option) any later version.
00016 //
00017 //  PLplot is distributed in the hope that it will be useful,
00018 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 //  GNU Library General Public License for more details.
00021 //
00022 //  You should have received a copy of the GNU Library General Public License
00023 //  along with PLplot; if not, write to the Free Software
00024 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00025 //
00026 //
00027 //  Based upon tkFrame.c from the TK 3.2 distribution:
00028 //
00029 //  Copyright 1990 Regents of the University of California.
00030 //  Permission to use, copy, modify, and distribute this
00031 //  software and its documentation for any purpose and without
00032 //  fee is hereby granted, provided that the above copyright
00033 //  notice appear in all copies.  The University of California
00034 //  makes no representations about the suitability of this
00035 //  software for any purpose.  It is provided "as is" without
00036 //  express or implied warranty.
00037 //
00038 //--------------------------------------------------------------------------
00039 //
00040 //  This module implements "plframe" widgets for the Tk toolkit.  These are
00041 //  frames that have extra logic to allow them to be interfaced with the
00042 //  PLplot X driver.  These are then drawn into and respond to keyboard and
00043 //  mouse events.
00044 //
00045 //
00046 // #define DEBUG_ENTER
00047 // #define DEBUG
00048 //
00049 
00050 #define DEBUGx
00051 
00052 #define NEED_PLDEBUG
00053 #include "plserver.h"
00054 #include "plxwd.h"
00055 #include "tcpip.h"
00056 
00057 #ifdef PL_HAVE_UNISTD_H
00058 #include <unistd.h>
00059 #endif
00060 #include <fcntl.h>
00061 
00062 #undef HAVE_ITCL
00063 
00064 #define NDEV    100             // Max number of output device types in menu
00065 
00066 // If set, BUFFER_FIFO causes FIFO i/o to be buffered
00067 
00068 #define BUFFER_FIFO    1
00069 
00070 // If set, causes a file handler to be used with FIFO
00071 
00072 #define FH_FIFO    0
00073 
00074 // A handy command wrapper
00075 
00076 #define plframe_cmd( code ) \
00077     if ( ( code ) == TCL_ERROR ) return ( TCL_ERROR );
00078 
00079 // Backward compatibility junk
00080 
00081 #if TCL_MAJOR_VERSION <= 7 && TCL_MINOR_VERSION <= 4
00082 #define Tk_Cursor    Cursor
00083 #endif
00084 
00085 //
00086 // A data structure of the following type is kept for each
00087 // plframe that currently exists for this process:
00088 //
00089 
00090 typedef struct
00091 {
00092 // This is stuff taken from tkFrame.c
00093 
00094     Tk_Window tkwin;            // Window that embodies the frame.  NULL
00095                                 // means that the window has been destroyed
00096                                 // but the data structures haven't yet been
00097                                 // cleaned up.
00098     Display    *display;        // Display containing widget.  Used, among
00099                                 // other things, so that resources can be
00100                                 // freed even after tkwin has gone away.
00101     Tcl_Interp *interp;         // Interpreter associated with
00102                                 // widget.  Used to delete widget
00103                                 // command.
00104 #ifdef HAVE_ITCL
00105     Tcl_Command widgetCmd;      // Token for frame's widget command.
00106 #endif
00107     Tk_3DBorder border;         // Structure used to draw 3-D border and
00108                                 // background.
00109     int         borderWidth;    // Width of 3-D border (if any).
00110     int         relief;         // 3-d effect: TK_RELIEF_RAISED etc.
00111     int         width;          // Width to request for window.  <= 0 means
00112                                 // don't request any size.
00113     int         height;         // Height to request for window.  <= 0 means
00114                                 // don't request any size.
00115     Tk_Cursor   cursor;         // Current cursor for window, or None.
00116     int         flags;          // Various flags;  see below for
00117                                 // definitions.
00118 
00119 // These are new to plframe widgets
00120 
00121 // control stuff
00122 
00123     int      tkwin_initted;     // Set first time widget is mapped
00124     PLStream *pls;              // PLplot stream pointer
00125     PLINT    ipls;              // PLplot stream number
00126     PLINT    ipls_save;         // PLplot stream number, save files
00127 
00128     PLRDev   *plr;              // Renderer state information.  Malloc'ed
00129     XColor   *bgColor;          // Background color
00130     char     *plpr_cmd;         // Holds print command name.  Malloc'ed
00131 
00132 // Used to handle resize and expose events
00133 
00134     PLDisplay pldis;            // Info about the display window
00135     int       prevWidth;        // Previous window width
00136     int       prevHeight;       // Previous window height
00137 
00138 // Support for save operations
00139 
00140     char *SaveFnam;             // File name we are currently saving to.
00141                                 // Malloc'ed.
00142     char **devDesc;             // Descriptive names for file-oriented
00143                                 // devices.  Malloc'ed.
00144     char **devName;             // Keyword names of file-oriented devices.
00145                                 // Malloc'ed.
00146 
00147 // Used in selecting & modifying plot or device area
00148 
00149     GC        xorGC;            // GC used for rubber-band drawing
00150     XPoint    pts[5];           // Points for rubber-band drawing
00151     int       continue_draw;    // Set when doing rubber-band draws
00152     Tk_Cursor xhair_cursor;     // cursor used for drawing
00153     PLFLT     xl, xr, yl, yr;   // Bounds on plot viewing area
00154     char      *xScrollCmd;      // Command prefix for communicating with
00155                                 // horizontal scrollbar.  NULL means no
00156                                 // command to issue.  Malloc'ed.
00157     char      *yScrollCmd;      // Command prefix for communicating with
00158                                 // vertical scrollbar.  NULL means no
00159                                 // command to issue.  Malloc'ed.
00160 
00161 // Used for flashing bop or eop condition
00162 
00163     char *bopCmd;               // Proc to call at bop
00164     char *eopCmd;               // Proc to call at eop
00165 
00166 // Used for drawing graphic crosshairs
00167 
00168     int    xhairs;              // Configuration option to turn on xhairs
00169     int    drawing_xhairs;      // Set if we are currently drawing xhairs
00170     XPoint xhair_x[2];          // Points for horizontal xhair line
00171     XPoint xhair_y[2];          // Points for vertical xhair line
00172 
00173 // Used for drawing a rubber band lilne segment
00174 
00175     int    rband;               // Configuration option to turn on rband
00176     int    drawing_rband;       // See if we are currently drawing rband
00177     XPoint rband_pt[2];         // Ends of rubber band line
00178 } PlFrame;
00179 
00180 //
00181 // Flag bits for plframes:
00182 //
00183 // REFRESH_PENDING:             Non-zero means a DoWhenIdle handler
00184 //                              has already been queued to refresh
00185 //                              this window.
00186 // RESIZE_PENDING;              Used to reschedule resize events
00187 // REDRAW_PENDING;              Used to redraw contents of plot buffer
00188 // UPDATE_V_SCROLLBAR:          Non-zero means vertical scrollbar needs
00189 //                              to be updated.
00190 // UPDATE_H_SCROLLBAR:          Non-zero means horizontal scrollbar needs
00191 //                              to be updated.
00192 //
00193 
00194 #define REFRESH_PENDING       1
00195 #define RESIZE_PENDING        2
00196 #define REDRAW_PENDING        4
00197 #define UPDATE_V_SCROLLBAR    8
00198 #define UPDATE_H_SCROLLBAR    16
00199 
00200 // Defaults for plframes:
00201 
00202 #define DEF_PLFRAME_BG_COLOR        "Black"
00203 #define DEF_PLFRAME_BG_MONO         "White"
00204 #define DEF_PLFRAME_BORDER_WIDTH    "0"
00205 #define DEF_PLFRAME_CURSOR          ( (char *) NULL )
00206 #define DEF_PLFRAME_HEIGHT          "0"
00207 #define DEF_PLFRAME_RELIEF          "flat"
00208 #define DEF_PLFRAME_WIDTH           "0"
00209 
00210 // Configuration info
00211 
00212 static Tk_ConfigSpec configSpecs[] = {
00213     { TK_CONFIG_BORDER,        "-background",     "background",     "Background",
00214       DEF_PLFRAME_BG_COLOR, Tk_Offset( PlFrame, border ),
00215       TK_CONFIG_COLOR_ONLY },
00216 //
00217 //  {TK_CONFIG_COLOR, (char *) NULL, (char *) NULL, (char *) NULL,
00218 //      (char *) NULL, Tk_Offset(PlFrame, bgColor),
00219 //      TK_CONFIG_COLOR_ONLY},
00220 //
00221 #ifndef MAC_TCL
00222     { TK_CONFIG_COLOR,         "-plbg",           "plbackground",   "Plbackground",
00223       DEF_PLFRAME_BG_COLOR, Tk_Offset( PlFrame, bgColor ),
00224       TK_CONFIG_COLOR_ONLY },
00225 #endif
00226     { TK_CONFIG_BORDER,        "-background",     "background",     "Background",
00227       DEF_PLFRAME_BG_MONO, Tk_Offset( PlFrame, border ),
00228       TK_CONFIG_MONO_ONLY },
00229 //
00230 //  {TK_CONFIG_COLOR, (char *) NULL, (char *) NULL, (char *) NULL,
00231 //      (char *) NULL, Tk_Offset(PlFrame, bgColor),
00232 //      TK_CONFIG_MONO_ONLY},
00233 //
00234 #ifndef MAC_TCL
00235     { TK_CONFIG_COLOR,         "-plbg",           (char *) NULL,    (char *) NULL,
00236       DEF_PLFRAME_BG_MONO, Tk_Offset( PlFrame, bgColor ),
00237       TK_CONFIG_MONO_ONLY },
00238 #endif
00239     { TK_CONFIG_SYNONYM,       "-bd",             "borderWidth",    (char *) NULL,
00240       (char *) NULL, 0, 0 },
00241     { TK_CONFIG_SYNONYM,       "-bg",             "background",     (char *) NULL,
00242       (char *) NULL, 0, 0 },
00243     { TK_CONFIG_PIXELS,        "-borderwidth",    "borderWidth",    "BorderWidth",
00244       DEF_PLFRAME_BORDER_WIDTH, Tk_Offset( PlFrame, borderWidth ), 0 },
00245     { TK_CONFIG_ACTIVE_CURSOR, "-cursor",         "cursor",         "Cursor",
00246       DEF_PLFRAME_CURSOR, Tk_Offset( PlFrame, cursor ), TK_CONFIG_NULL_OK },
00247     { TK_CONFIG_STRING,        "-bopcmd",         "bopcmd",         "PgCommand",
00248       (char *) NULL, Tk_Offset( PlFrame, bopCmd ), TK_CONFIG_NULL_OK },
00249     { TK_CONFIG_STRING,        "-eopcmd",         "eopcmd",         "PgCommand",
00250       (char *) NULL, Tk_Offset( PlFrame, eopCmd ), TK_CONFIG_NULL_OK },
00251     { TK_CONFIG_PIXELS,        "-height",         "height",         "Height",
00252       DEF_PLFRAME_HEIGHT, Tk_Offset( PlFrame, height ), 0 },
00253     { TK_CONFIG_RELIEF,        "-relief",         "relief",         "Relief",
00254       DEF_PLFRAME_RELIEF, Tk_Offset( PlFrame, relief ), 0 },
00255     { TK_CONFIG_PIXELS,        "-width",          "width",          "Width",
00256       DEF_PLFRAME_WIDTH, Tk_Offset( PlFrame, width ), 0 },
00257     { TK_CONFIG_BOOLEAN,       "-xhairs",         (char *) NULL,    (char *) NULL,
00258       "0", Tk_Offset( PlFrame, xhairs ), TK_CONFIG_DONT_SET_DEFAULT },
00259     { TK_CONFIG_BOOLEAN,       "-rubberband",     (char *) NULL,    (char *) NULL,
00260       "0", Tk_Offset( PlFrame, rband ), TK_CONFIG_DONT_SET_DEFAULT },
00261     { TK_CONFIG_STRING,        "-xscrollcommand", "xScrollCommand", "ScrollCommand",
00262       (char *) NULL, Tk_Offset( PlFrame, xScrollCmd ), TK_CONFIG_NULL_OK },
00263     { TK_CONFIG_STRING,        "-yscrollcommand", "yScrollCommand", "ScrollCommand",
00264       (char *) NULL, Tk_Offset( PlFrame, yScrollCmd ), TK_CONFIG_NULL_OK },
00265     { TK_CONFIG_END,           (char *) NULL,     (char *) NULL,    (char *) NULL,
00266       (char *) NULL, 0, 0 }
00267 };
00268 
00269 // Forward declarations for procedures defined later in this file:
00270 
00271 // Externals
00272 
00273 int   plFrameCmd( ClientData, Tcl_Interp *, int, const char ** );
00274 
00275 // These are invoked by the TK dispatcher
00276 
00277 #if TK_MAJOR_VERSION < 4 || ( TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION == 0 )
00278 #define FreeProcArg    ClientData
00279 #else
00280 #define FreeProcArg    char *
00281 #endif
00282 
00283 static void  DestroyPlFrame( FreeProcArg );
00284 static void  DisplayPlFrame( ClientData );
00285 static void  PlFrameInit( ClientData );
00286 static void  PlFrameConfigureEH( ClientData, XEvent * );
00287 static void  PlFrameExposeEH( ClientData, XEvent * );
00288 static void  PlFrameMotionEH( ClientData, register XEvent * );
00289 static void  PlFrameEnterEH( ClientData, register XEvent * );
00290 static void  PlFrameLeaveEH( ClientData, register XEvent * );
00291 static void  PlFrameKeyEH( ClientData, register XEvent * );
00292 static int   PlFrameWidgetCmd( ClientData, Tcl_Interp *, int, const char ** );
00293 static int   ReadData( ClientData, int );
00294 static void  Install_cmap( PlFrame *plFramePtr );
00295 
00296 // These are invoked by PlFrameWidgetCmd to process widget commands
00297 
00298 static int   Closelink( Tcl_Interp *, PlFrame *, int, const char ** );
00299 static int   Cmd( Tcl_Interp *, PlFrame *, int, const char ** );
00300 static int   ColorManip( Tcl_Interp *, PlFrame *, int, const char ** );
00301 static int   ConfigurePlFrame( Tcl_Interp *, PlFrame *, int, const char **, int );
00302 static int   Draw( Tcl_Interp *, PlFrame *, int, const char ** );
00303 static int   Info( Tcl_Interp *, PlFrame *, int, const char ** );
00304 static int   Openlink( Tcl_Interp *, PlFrame *, int, const char ** );
00305 static int   Orient( Tcl_Interp *, PlFrame *, int, const char ** );
00306 static int   Page( Tcl_Interp *, PlFrame *, int, const char ** );
00307 static int   Print( Tcl_Interp *, PlFrame *, int, const char ** );
00308 static int   Redraw( Tcl_Interp *, PlFrame *, int, const char ** );
00309 static int   Save( Tcl_Interp *, PlFrame *, int, const char ** );
00310 static int   View( Tcl_Interp *, PlFrame *, int, const char ** );
00311 static int   xScroll( Tcl_Interp *, PlFrame *, int, const char ** );
00312 static int   yScroll( Tcl_Interp *, PlFrame *, int, const char ** );
00313 static int   report( Tcl_Interp *, PlFrame *, int, const char ** );
00314 
00315 // Routines for manipulating graphic crosshairs
00316 
00317 static void  CreateXhairs( PlFrame * );
00318 static void  DestroyXhairs( PlFrame * );
00319 static void  DrawXhairs( PlFrame *, int, int );
00320 static void  UpdateXhairs( PlFrame * );
00321 
00322 // Routines for manipulating the rubberband line
00323 
00324 static void  CreateRband( PlFrame * );
00325 static void  DestroyRband( PlFrame * );
00326 static void  DrawRband( PlFrame *, int, int );
00327 static void  UpdateRband( PlFrame * );
00328 
00329 // Callbacks from plplot library
00330 
00331 static void  process_bop( void *, int * );
00332 static void  process_eop( void *, int * );
00333 
00334 // Utility routines
00335 
00336 static void  gbox( PLFLT *, PLFLT *, PLFLT *, PLFLT *, const char ** );
00337 static void  UpdateVScrollbar( register PlFrame * );
00338 static void  UpdateHScrollbar( register PlFrame * );
00339 
00340 //
00341 //--------------------------------------------------------------------------
00342 //
00343 // plFrameCmd --
00344 //
00345 //      This procedure is invoked to process the "plframe" Tcl
00346 //      command.  See the user documentation for details on what it
00347 //      does.
00348 //
00349 // Results:
00350 //      A standard Tcl result.
00351 //
00352 // Side effects:
00353 //      See the user documentation.
00354 //
00355 //--------------------------------------------------------------------------
00356 //
00357 
00358 int
00359 plFrameCmd( ClientData clientData, Tcl_Interp *interp,
00360             int argc, const char **argv )
00361 {
00362     Tk_Window        new;
00363     register PlFrame *plFramePtr;
00364     register PLRDev  *plr;
00365     int i, ndev;
00366 
00367     dbug_enter( "plFrameCmd" );
00368 
00369     if ( argc < 2 )
00370     {
00371         Tcl_AppendResult( interp, "wrong # args: should be \"",
00372             argv[0], " pathName ?options?\"", (char *) NULL );
00373         return TCL_ERROR;
00374     }
00375 
00376 // Create the window.
00377 
00378     new = Tk_CreateWindowFromPath( interp, Tk_MainWindow( interp ),
00379         argv[1], (char *) NULL );
00380     if ( new == NULL )
00381     {
00382         return TCL_ERROR;
00383     }
00384 
00385     plFramePtr                 = (PlFrame *) ckalloc( sizeof ( PlFrame ) );
00386     plFramePtr->tkwin          = new;
00387     plFramePtr->display        = Tk_Display( new );
00388     plFramePtr->interp         = interp;
00389     plFramePtr->xorGC          = NULL;
00390     plFramePtr->border         = NULL;
00391     plFramePtr->cursor         = None;
00392     plFramePtr->xhair_cursor   = None;
00393     plFramePtr->flags          = 0;
00394     plFramePtr->width          = Tk_Width( plFramePtr->tkwin );
00395     plFramePtr->height         = Tk_Height( plFramePtr->tkwin );
00396     plFramePtr->prevWidth      = 0;
00397     plFramePtr->prevHeight     = 0;
00398     plFramePtr->continue_draw  = 0;
00399     plFramePtr->ipls           = 0;
00400     plFramePtr->ipls_save      = 0;
00401     plFramePtr->tkwin_initted  = 0;
00402     plFramePtr->bgColor        = NULL;
00403     plFramePtr->plpr_cmd       = NULL;
00404     plFramePtr->bopCmd         = NULL;
00405     plFramePtr->eopCmd         = NULL;
00406     plFramePtr->xhairs         = 0;
00407     plFramePtr->drawing_xhairs = 0;
00408     plFramePtr->rband          = 0;
00409     plFramePtr->drawing_rband  = 0;
00410     plFramePtr->xScrollCmd     = NULL;
00411     plFramePtr->yScrollCmd     = NULL;
00412     plFramePtr->xl             = 0.;
00413     plFramePtr->yl             = 0.;
00414     plFramePtr->xr             = 1.;
00415     plFramePtr->yr             = 1.;
00416     plFramePtr->SaveFnam       = NULL;
00417     plFramePtr->pldis.x        = 0;
00418     plFramePtr->pldis.y        = 0;
00419     plFramePtr->pldis.width    = 0;
00420     plFramePtr->pldis.height   = 0;
00421 
00422     plFramePtr->plr = (PLRDev *) ckalloc( sizeof ( PLRDev ) );
00423     plr             = plFramePtr->plr;
00424     plr->pdfs       = NULL;
00425     plr->at_bop     = 0;
00426     plr->at_eop     = 0;
00427     plr->iodev      = (PLiodev *) ckalloc( sizeof ( PLiodev ) );
00428     plr_start( plr );
00429 
00430 // Associate new PLplot stream with this widget
00431 
00432     plmkstrm( &plFramePtr->ipls );
00433     plgpls( &plFramePtr->pls );
00434 
00435 // Set up stuff for rubber-band drawing
00436 
00437     plFramePtr->xhair_cursor =
00438         Tk_GetCursor( plFramePtr->interp, plFramePtr->tkwin, "crosshair" );
00439 
00440 // Partially initialize X driver.
00441 
00442     pllib_init();
00443 
00444     plsdev( "xwin" );
00445     pllib_devinit();
00446     plP_esc( PLESC_DEVINIT, NULL );
00447 
00448 // Create list of valid device names and keywords for page dumps
00449 
00450     plFramePtr->devDesc = (char **) ckalloc( NDEV * sizeof ( char ** ) );
00451     plFramePtr->devName = (char **) ckalloc( NDEV * sizeof ( char ** ) );
00452     for ( i = 0; i < NDEV; i++ )
00453     {
00454         plFramePtr->devDesc[i] = NULL;
00455         plFramePtr->devName[i] = NULL;
00456     }
00457     ndev = NDEV;
00458     plgFileDevs( (const char ***) &plFramePtr->devDesc, (const char ***) &plFramePtr->devName, &ndev );
00459 
00460 // Start up event handlers and other good stuff
00461 
00462     Tk_SetClass( new, "Plframe" );
00463 
00464     Tk_CreateEventHandler( plFramePtr->tkwin, StructureNotifyMask,
00465         PlFrameConfigureEH, (ClientData) plFramePtr );
00466 
00467     Tk_CreateEventHandler( plFramePtr->tkwin, ExposureMask,
00468         PlFrameExposeEH, (ClientData) plFramePtr );
00469 
00470 #ifdef HAVE_ITCL
00471     plFramePtr->widgetCmd =
00472 #endif
00473     Tcl_CreateCommand( interp, Tk_PathName( plFramePtr->tkwin ),
00474         (Tcl_CmdProc *) PlFrameWidgetCmd, (ClientData) plFramePtr, (Tcl_CmdDeleteProc *) NULL );
00475 #ifdef HAVE_ITCL
00476     Itk_SetWidgetCommand( plFramePtr->tkwin, plFramePtr->widgetCmd );
00477 #endif
00478 
00479     if ( ConfigurePlFrame( interp, plFramePtr, argc - 2, argv + 2, 0 ) != TCL_OK )
00480     {
00481 #ifdef HAVE_ITCL
00482         Itk_SetWidgetCommand( plFramePtr->tkwin, (Tcl_Command) NULL );
00483 #endif
00484         Tk_DestroyWindow( plFramePtr->tkwin );
00485         return TCL_ERROR;
00486     }
00487     interp->result = Tk_PathName( plFramePtr->tkwin );
00488 
00489     return TCL_OK;
00490 }
00491 
00492 //
00493 //--------------------------------------------------------------------------
00494 //
00495 // PlFrameWidgetCmd --
00496 //
00497 //      This procedure is invoked to process the Tcl command that
00498 //      corresponds to a plframe widget.  See the user
00499 //      documentation for details on what it does.
00500 //
00501 // Results:
00502 //      A standard Tcl result.
00503 //
00504 // Side effects:
00505 //      See the user documentation.
00506 //
00507 //--------------------------------------------------------------------------
00508 //
00509 
00510 static int
00511 PlFrameWidgetCmd( ClientData clientData, Tcl_Interp *interp,
00512                   int argc, const char **argv )
00513 {
00514     register PlFrame *plFramePtr = (PlFrame *) clientData;
00515     int  result = TCL_OK;
00516     int  length;
00517     char c;
00518 
00519     dbug_enter( "PlFrameWidgetCmd" );
00520 
00521 #ifdef DEBUG
00522     {
00523         int      i;
00524         PLStream *pls;
00525         plgpls( pls );
00526         printf( "Current stream %d, frame stream %d\n",
00527             pls->ipls, plFramePtr->ipls );
00528         printf( "PlFrameWidgetCmd: " );
00529         for ( i = 0; i < argc; i++ )
00530             printf( " %s", argv[i] );
00531         printf( "\n" );
00532     }
00533 #endif
00534 
00535     if ( argc < 2 )
00536     {
00537         Tcl_AppendResult( interp, "wrong # args: should be \"",
00538             argv[0], " option ?arg arg ...?\"", (char *) NULL );
00539         return TCL_ERROR;
00540     }
00541     Tk_Preserve( (ClientData) plFramePtr );
00542     c      = argv[1][0];
00543     length = strlen( argv[1] );
00544 
00545 // First, before anything else, we have to set the stream to be the one that
00546 // corresponds to this widget.
00547     plsstrm( plFramePtr->ipls );
00548 
00549 // cmd -- issue a command to the PLplot library
00550 
00551     if ( ( c == 'c' ) && ( strncmp( argv[1], "cmd", length ) == 0 ) )
00552     {
00553         result = Cmd( interp, plFramePtr, argc - 2, argv + 2 );
00554     }
00555 
00556 // cget
00557 
00558     else if ( ( c == 'c' ) && ( strncmp( argv[1], "cget", length ) == 0 ) )
00559     {
00560         if ( argc > 2 )
00561         {
00562             Tcl_AppendResult( interp, "wrong # args: should be \"",
00563                 argv[0], " cget <option>\"", (char *) NULL );
00564             result = TCL_ERROR;
00565             goto done;
00566         }
00567         else
00568         {
00569             result = Tk_ConfigureInfo( interp, plFramePtr->tkwin, configSpecs,
00570                 (char *) plFramePtr, (char *) NULL, 0 );
00571         }
00572     }
00573 
00574 // configure
00575 
00576     else if ( ( c == 'c' ) && ( strncmp( argv[1], "configure", length ) == 0 ) )
00577     {
00578         if ( argc == 2 )
00579         {
00580             result = Tk_ConfigureInfo( interp, plFramePtr->tkwin, configSpecs,
00581                 (char *) plFramePtr, (char *) NULL, 0 );
00582         }
00583         else if ( argc == 3 )
00584         {
00585             result = Tk_ConfigureInfo( interp, plFramePtr->tkwin, configSpecs,
00586                 (char *) plFramePtr, argv[2], 0 );
00587         }
00588         else
00589         {
00590             result = ConfigurePlFrame( interp, plFramePtr, argc - 2, argv + 2,
00591                 TK_CONFIG_ARGV_ONLY );
00592         }
00593     }
00594 
00595 // double buffering
00596 
00597     else if ( ( c == 'd' ) &&
00598               ( ( strncmp( argv[1], "db", length ) == 0 ) ||
00599                 ( strncmp( argv[1], "doublebuffering", length == 0 ) ) ) )
00600     {
00601         PLBufferingCB bcb;
00602 
00603         if ( argc == 3 )
00604         {
00605             if ( strcmp( argv[2], "on" ) == 0 )
00606             {
00607                 bcb.cmd = PLESC_DOUBLEBUFFERING_ENABLE;
00608                 pl_cmd( PLESC_DOUBLEBUFFERING, &bcb );
00609             }
00610             if ( strcmp( argv[2], "off" ) == 0 )
00611             {
00612                 bcb.cmd = PLESC_DOUBLEBUFFERING_DISABLE;
00613                 pl_cmd( PLESC_DOUBLEBUFFERING, &bcb );
00614             }
00615             if ( strcmp( argv[2], "query" ) == 0 )
00616             {
00617                 bcb.cmd = PLESC_DOUBLEBUFFERING_QUERY;
00618                 pl_cmd( PLESC_DOUBLEBUFFERING, &bcb );
00619                 sprintf( interp->result, "%d", bcb.result );
00620             }
00621         }
00622 
00623         result = TCL_OK;
00624     }
00625 
00626 // closelink -- Close a binary data link previously opened with openlink
00627 
00628     else if ( ( c == 'c' ) && ( strncmp( argv[1], "closelink", length ) == 0 ) )
00629     {
00630         if ( argc > 2 )
00631         {
00632             Tcl_AppendResult( interp, "wrong # args: should be \"",
00633                 argv[0], (char *) NULL );
00634             result = TCL_ERROR;
00635             goto done;
00636         }
00637         else
00638         {
00639             result = Closelink( interp, plFramePtr, argc - 2, argv + 2 );
00640         }
00641     }
00642 
00643 // draw -- rubber-band draw used in region selection
00644 
00645     else if ( ( c == 'd' ) && ( strncmp( argv[1], "draw", length ) == 0 ) )
00646     {
00647         if ( argc == 2 )
00648         {
00649             Tcl_AppendResult( interp, "wrong # args: should be \"",
00650                 argv[0], " draw op ?options?\"", (char *) NULL );
00651             result = TCL_ERROR;
00652             goto done;
00653         }
00654         else
00655         {
00656             result = Draw( interp, plFramePtr, argc - 2, argv + 2 );
00657         }
00658     }
00659 
00660 // color-manipulating commands, grouped together for convenience
00661 
00662     else if ( ( ( c == 'g' ) && ( ( strncmp( argv[1], "gcmap0", length ) == 0 ) ||
00663                                   ( strncmp( argv[1], "gcmap1", length ) == 0 ) ) ) ||
00664               ( ( c == 's' ) && ( ( strncmp( argv[1], "scmap0", length ) == 0 ) ||
00665                                   ( strncmp( argv[1], "scmap1", length ) == 0 ) ||
00666                                   ( strncmp( argv[1], "scol0", length ) == 0 ) ||
00667                                   ( strncmp( argv[1], "scol1", length ) == 0 ) ) ) )
00668         result = ColorManip( interp, plFramePtr, argc - 1, argv + 1 );
00669 
00670 // info -- returns requested info
00671 
00672     else if ( ( c == 'i' ) && ( strncmp( argv[1], "info", length ) == 0 ) )
00673     {
00674         result = Info( interp, plFramePtr, argc - 2, argv + 2 );
00675     }
00676 
00677 // orient -- Set plot orientation
00678 
00679     else if ( ( c == 'o' ) && ( strncmp( argv[1], "orient", length ) == 0 ) )
00680     {
00681         result = Orient( interp, plFramePtr, argc - 2, argv + 2 );
00682     }
00683 
00684 // openlink -- Open a binary data link (FIFO or socket)
00685 
00686     else if ( ( c == 'o' ) && ( strncmp( argv[1], "openlink", length ) == 0 ) )
00687     {
00688         if ( argc < 3 )
00689         {
00690             Tcl_AppendResult( interp, "wrong # args: should be \"",
00691                 argv[0], " option ?arg arg ...?\"", (char *) NULL );
00692             result = TCL_ERROR;
00693             goto done;
00694         }
00695         else
00696         {
00697             result = Openlink( interp, plFramePtr, argc - 2, argv + 2 );
00698         }
00699     }
00700 
00701 // page -- change or return output page setup
00702 
00703     else if ( ( c == 'p' ) && ( strncmp( argv[1], "page", length ) == 0 ) )
00704     {
00705         result = Page( interp, plFramePtr, argc - 2, argv + 2 );
00706     }
00707 
00708 // print -- prints plot
00709 
00710     else if ( ( c == 'p' ) && ( strncmp( argv[1], "print", length ) == 0 ) )
00711     {
00712         result = Print( interp, plFramePtr, argc - 2, argv + 2 );
00713     }
00714 
00715 // redraw -- redraw plot
00716 
00717     else if ( ( c == 'r' ) && ( strncmp( argv[1], "redraw", length ) == 0 ) )
00718     {
00719         if ( argc > 2 )
00720         {
00721             Tcl_AppendResult( interp, "wrong # args: should be \"",
00722                 argv[0], " redraw\"", (char *) NULL );
00723             result = TCL_ERROR;
00724             goto done;
00725         }
00726         else
00727         {
00728             result = Redraw( interp, plFramePtr, argc - 2, argv + 2 );
00729         }
00730     }
00731 
00732 // report -- find out useful info about the plframe (GMF)
00733 
00734     else if ( ( c == 'r' ) && ( strncmp( argv[1], "report", length ) == 0 ) )
00735     {
00736         result = report( interp, plFramePtr, argc - 2, argv + 2 );
00737     }
00738 
00739 // save -- saves plot to the specified plot file type
00740 
00741     else if ( ( c == 's' ) && ( strncmp( argv[1], "save", length ) == 0 ) )
00742     {
00743         result = Save( interp, plFramePtr, argc - 2, argv + 2 );
00744     }
00745 
00746 // view -- change or return window into plot
00747 
00748     else if ( ( c == 'v' ) && ( strncmp( argv[1], "view", length ) == 0 ) )
00749     {
00750         result = View( interp, plFramePtr, argc - 2, argv + 2 );
00751     }
00752 
00753 // xscroll -- horizontally scroll window into plot
00754 
00755     else if ( ( c == 'x' ) && ( strncmp( argv[1], "xscroll", length ) == 0 ) )
00756     {
00757         if ( argc == 2 || argc > 3 )
00758         {
00759             Tcl_AppendResult( interp, "wrong # args: should be \"",
00760                 argv[0], " xscroll pixel\"", (char *) NULL );
00761             result = TCL_ERROR;
00762             goto done;
00763         }
00764         else
00765         {
00766             result = xScroll( interp, plFramePtr, argc - 2, argv + 2 );
00767         }
00768     }
00769 
00770 // yscroll -- vertically scroll window into plot
00771 
00772     else if ( ( c == 'y' ) && ( strncmp( argv[1], "yscroll", length ) == 0 ) )
00773     {
00774         if ( argc == 2 || argc > 3 )
00775         {
00776             Tcl_AppendResult( interp, "wrong # args: should be \"",
00777                 argv[0], " yscroll pixel\"", (char *) NULL );
00778             result = TCL_ERROR;
00779             goto done;
00780         }
00781         else
00782         {
00783             result = yScroll( interp, plFramePtr, argc - 2, argv + 2 );
00784         }
00785     }
00786 
00787 // unrecognized widget command
00788 
00789     else
00790     {
00791         Tcl_AppendResult( interp, "bad option \"", argv[1],
00792             "\":  must be closelink, cmd, configure, draw, ",
00793             "gcmap0, gcmap1, ",
00794             "info, openlink, orient, page, print, redraw, save, ",
00795             "scmap0, scmap1, scol0, scol1, ",
00796             "view, xscroll, or yscroll", (char *) NULL );
00797 
00798         result = TCL_ERROR;
00799 #ifdef DEBUG
00800         printf( "bad option!\n" );
00801 #endif
00802     }
00803 
00804 #ifdef DEBUG
00805     printf( "result=%d current stream=%d\n", result, plsc->ipls );
00806 #endif
00807 
00808 done:
00809     Tk_Release( (ClientData) plFramePtr );
00810     return result;
00811 }
00812 
00813 //
00814 //--------------------------------------------------------------------------
00815 //
00816 // DestroyPlFrame --
00817 //
00818 //      This procedure is invoked by Tk_EventuallyFree or Tk_Release to
00819 //      clean up the internal structure of a plframe at a safe time
00820 //      (when no-one is using it anymore).
00821 //
00822 // Results:
00823 //      None.
00824 //
00825 // Side effects:
00826 //      Everything associated with the plframe is freed up.
00827 //
00828 //--------------------------------------------------------------------------
00829 //
00830 
00831 static void
00832 DestroyPlFrame( FreeProcArg clientData )
00833 {
00834     register PlFrame *plFramePtr = (PlFrame *) clientData;
00835     register PLRDev  *plr        = plFramePtr->plr;
00836 
00837     dbug_enter( "DestroyPlFrame" );
00838 
00839     if ( plFramePtr->border != NULL )
00840     {
00841         Tk_Free3DBorder( plFramePtr->border );
00842     }
00843     if ( plFramePtr->bgColor != NULL )
00844     {
00845         Tk_FreeColor( plFramePtr->bgColor );
00846     }
00847     if ( plFramePtr->plpr_cmd != NULL )
00848     {
00849         ckfree( (char *) plFramePtr->plpr_cmd );
00850     }
00851     if ( plFramePtr->cursor != None )
00852     {
00853         Tk_FreeCursor( plFramePtr->display, plFramePtr->cursor );
00854     }
00855     if ( plFramePtr->xhair_cursor != None )
00856     {
00857         Tk_FreeCursor( plFramePtr->display, plFramePtr->xhair_cursor );
00858     }
00859     if ( plFramePtr->xorGC != NULL )
00860     {
00861         Tk_FreeGC( plFramePtr->display, plFramePtr->xorGC );
00862     }
00863     if ( plFramePtr->yScrollCmd != NULL )
00864     {
00865         ckfree( (char *) plFramePtr->yScrollCmd );
00866     }
00867     if ( plFramePtr->xScrollCmd != NULL )
00868     {
00869         ckfree( (char *) plFramePtr->xScrollCmd );
00870     }
00871     if ( plFramePtr->SaveFnam != NULL )
00872     {
00873         ckfree( (char *) plFramePtr->SaveFnam );
00874     }
00875     if ( plFramePtr->devDesc != NULL )
00876     {
00877         ckfree( (char *) plFramePtr->devDesc );
00878     }
00879     if ( plFramePtr->devName != NULL )
00880     {
00881         ckfree( (char *) plFramePtr->devName );
00882     }
00883 
00884 // Clean up data connection
00885 
00886     pdf_close( plr->pdfs );
00887     ckfree( (char *) plFramePtr->plr->iodev );
00888 
00889 // Tell PLplot to clean up
00890 
00891     plsstrm( plFramePtr->ipls );
00892     plend1();
00893 
00894 // Delete main data structures
00895 
00896     ckfree( (char *) plFramePtr->plr );
00897     ckfree( (char *) plFramePtr );
00898 }
00899 
00900 //
00901 //--------------------------------------------------------------------------
00902 //
00903 // PlFrameConfigureEH --
00904 //
00905 //      Invoked by the Tk dispatcher on structure changes to a plframe.
00906 //
00907 // Results:
00908 //      None.
00909 //
00910 // Side effects:
00911 //      When the window gets deleted, internal structures get cleaned up.
00912 //      When it gets resized, it is redrawn.
00913 //
00914 //--------------------------------------------------------------------------
00915 //
00916 
00917 static void
00918 PlFrameConfigureEH( ClientData clientData, register XEvent *eventPtr )
00919 {
00920     register PlFrame   *plFramePtr = (PlFrame *) clientData;
00921     register Tk_Window tkwin       = plFramePtr->tkwin;
00922 
00923     dbug_enter( "PlFrameConfigureEH" );
00924 
00925     switch ( eventPtr->type )
00926     {
00927     case ConfigureNotify:
00928         pldebug( "PLFrameConfigureEH", "ConfigureNotify\n" );
00929         plFramePtr->flags |= RESIZE_PENDING;
00930         plFramePtr->width  = Tk_Width( tkwin );
00931         plFramePtr->height = Tk_Height( tkwin );
00932         if ( ( tkwin != NULL ) && !( plFramePtr->flags & REFRESH_PENDING ) )
00933         {
00934             Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
00935             plFramePtr->flags |= REFRESH_PENDING;
00936             plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
00937         }
00938         break;
00939 
00940     case DestroyNotify:
00941         pldebug( "PLFrameConfigureEH", "DestroyNotify\n" );
00942 #ifdef HAVE_ITCL
00943         Itk_SetWidgetCommand( plFramePtr->tkwin, (Tcl_Command) NULL );
00944         Tcl_DeleteCommand2( plFramePtr->interp, plFramePtr->widgetCmd );
00945 #else
00946         Tcl_DeleteCommand( plFramePtr->interp, Tk_PathName( tkwin ) );
00947 #endif
00948         plFramePtr->tkwin = NULL;
00949         if ( plFramePtr->flags & REFRESH_PENDING )
00950         {
00951             Tk_CancelIdleCall( DisplayPlFrame, (ClientData) plFramePtr );
00952         }
00953         Tk_EventuallyFree( (ClientData) plFramePtr, DestroyPlFrame );
00954         break;
00955 
00956     case MapNotify:
00957         pldebug( "PLFrameConfigureEH", "MapNotify\n" );
00958         if ( plFramePtr->flags & REFRESH_PENDING )
00959         {
00960             Tk_CancelIdleCall( DisplayPlFrame, (ClientData) plFramePtr );
00961         }
00962 
00963         // For some reason, "." must be mapped or PlFrameInit will die (Note:
00964         // mapped & withdrawn or mapped in the withdrawn state is OK). Issuing
00965         // an update fixes this.  I'd love to know why this occurs.
00966         //
00967 
00968         if ( !plFramePtr->tkwin_initted )
00969         {
00970             Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
00971         }
00972         Tk_DoWhenIdle( PlFrameInit, (ClientData) plFramePtr );
00973         break;
00974     }
00975 }
00976 
00977 //
00978 //--------------------------------------------------------------------------
00979 //
00980 // PlFrameExposeEH --
00981 //
00982 //      Invoked by the Tk dispatcher on exposes of a plframe.
00983 //
00984 // Results:
00985 //      None.
00986 //
00987 // Side effects:
00988 //      Widget is redisplayed.
00989 //
00990 // Note: it's customary in Tk to collapse multiple exposes, so for best
00991 // performance without losing the window contents, I keep track of the
00992 // smallest single rectangle that can satisfy all expose events.  If there
00993 // are any overlaid graphics (like crosshairs), however, we need to refresh
00994 // the entire plot in order to have a predictable outcome.
00995 //
00996 //--------------------------------------------------------------------------
00997 
00998 static void
00999 PlFrameExposeEH( ClientData clientData, register XEvent *eventPtr )
01000 {
01001     register PlFrame   *plFramePtr = (PlFrame *) clientData;
01002     XExposeEvent       *event      = (XExposeEvent *) eventPtr;
01003     register Tk_Window tkwin       = plFramePtr->tkwin;
01004 
01005     dbug_enter( "PlFrameExposeEH" );
01006 
01007     pldebug( "PLFrameExposeEH", "Expose\n" );
01008 
01009 // Set up the area to refresh
01010 
01011     if ( !( plFramePtr->drawing_xhairs || plFramePtr->drawing_rband ) )
01012     {
01013         int x0_old, x1_old, y0_old, y1_old, x0_new, x1_new, y0_new, y1_new;
01014 
01015         x0_old = plFramePtr->pldis.x;
01016         y0_old = plFramePtr->pldis.y;
01017         x1_old = x0_old + plFramePtr->pldis.width;
01018         y1_old = y0_old + plFramePtr->pldis.height;
01019 
01020         x0_new = event->x;
01021         y0_new = event->y;
01022         x1_new = x0_new + event->width;
01023         y1_new = y0_new + event->height;
01024 
01025         plFramePtr->pldis.x      = MIN( x0_old, x0_new );
01026         plFramePtr->pldis.y      = MIN( y0_old, y0_new );
01027         plFramePtr->pldis.width  = MAX( x1_old, x1_new ) - plFramePtr->pldis.x;
01028         plFramePtr->pldis.height = MAX( y1_old, y1_new ) - plFramePtr->pldis.y;
01029     }
01030 
01031 // Invoke DoWhenIdle handler to redisplay widget.
01032 
01033     if ( event->count == 0 )
01034     {
01035         if ( ( tkwin != NULL ) && !( plFramePtr->flags & REFRESH_PENDING ) )
01036         {
01037             Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
01038             plFramePtr->width  = Tk_Width( tkwin );
01039             plFramePtr->height = Tk_Height( tkwin );
01040             plFramePtr->flags |= REFRESH_PENDING;
01041         }
01042     }
01043 }
01044 
01045 //
01046 //--------------------------------------------------------------------------
01047 //
01048 // PlFrameMotionEH --
01049 //
01050 //      Invoked by the Tk dispatcher on MotionNotify events in a plframe.
01051 //      Not invoked unless we are drawing graphic crosshairs.
01052 //
01053 // Results:
01054 //      None.
01055 //
01056 // Side effects:
01057 //      Graphic crosshairs are drawn.
01058 //
01059 //--------------------------------------------------------------------------
01060 //
01061 
01062 static void
01063 PlFrameMotionEH( ClientData clientData, register XEvent *eventPtr )
01064 {
01065     register PlFrame *plFramePtr = (PlFrame *) clientData;
01066     XMotionEvent     *event      = (XMotionEvent *) eventPtr;
01067 
01068     dbug_enter( "PlFrameMotionEH" );
01069 
01070     if ( plFramePtr->drawing_xhairs )
01071     {
01072         DrawXhairs( plFramePtr, event->x, event->y );
01073     }
01074     if ( plFramePtr->drawing_rband )
01075     {
01076         DrawRband( plFramePtr, event->x, event->y );
01077     }
01078 }
01079 
01080 //
01081 //--------------------------------------------------------------------------
01082 //
01083 // PlFrameEnterEH --
01084 //
01085 //      Invoked by the Tk dispatcher on EnterNotify events in a plframe.
01086 //      Not invoked unless we are drawing graphic crosshairs.
01087 //
01088 // Results:
01089 //      None.
01090 //
01091 // Side effects:
01092 //      Graphic crosshairs are updated.
01093 //
01094 //--------------------------------------------------------------------------
01095 
01096 static void
01097 PlFrameEnterEH( ClientData clientData, register XEvent *eventPtr )
01098 {
01099     register PlFrame *plFramePtr    = (PlFrame *) clientData;
01100     XCrossingEvent   *crossingEvent = (XCrossingEvent *) eventPtr;
01101 
01102     dbug_enter( "PlFrameEnterEH" );
01103 
01104     if ( plFramePtr->xhairs )
01105     {
01106         DrawXhairs( plFramePtr, crossingEvent->x, crossingEvent->y );
01107         plFramePtr->drawing_xhairs = 1;
01108     }
01109     if ( plFramePtr->rband )
01110     {
01111         plFramePtr->drawing_rband = 1;
01112         UpdateRband( plFramePtr );
01113         DrawRband( plFramePtr, crossingEvent->x, crossingEvent->y );
01114     }
01115 }
01116 
01117 //
01118 //--------------------------------------------------------------------------
01119 //
01120 // PlFrameLeaveEH --
01121 //
01122 //      Invoked by the Tk dispatcher on LeaveNotify events in a plframe.
01123 //      Not invoked unless we are drawing graphic crosshairs.
01124 //
01125 // Results:
01126 //      None.
01127 //
01128 // Side effects:
01129 //      Graphic crosshairs are updated.
01130 //
01131 //--------------------------------------------------------------------------
01132 
01133 static void
01134 PlFrameLeaveEH( ClientData clientData, register XEvent *eventPtr )
01135 {
01136     register PlFrame *plFramePtr = (PlFrame *) clientData;
01137 
01138     dbug_enter( "PlFrameLeaveEH" );
01139 
01140     if ( plFramePtr->drawing_xhairs )
01141     {
01142         UpdateXhairs( plFramePtr );
01143         plFramePtr->drawing_xhairs = 0;
01144     }
01145     if ( plFramePtr->drawing_rband )
01146     {
01147         UpdateRband( plFramePtr );
01148         plFramePtr->drawing_rband = 0;
01149     }
01150 }
01151 
01152 //
01153 //--------------------------------------------------------------------------
01154 //
01155 // PlFrameKeyEH --
01156 //
01157 //      Invoked by the Tk dispatcher on Keypress events in a plframe.
01158 //      Not invoked unless we are drawing graphic crosshairs.
01159 //
01160 // Results:
01161 //      None.
01162 //
01163 // Side effects:
01164 //      Keypress events get filtered.  If a cursor key is pushed, the
01165 //      graphic crosshairs are moved in the appropriate direction.  Using a
01166 //      modifier key multiplies the movement a factor of 5 for each key
01167 //      added.
01168 //
01169 //--------------------------------------------------------------------------
01170 //
01171 
01172 static void
01173 PlFrameKeyEH( ClientData clientData, register XEvent *eventPtr )
01174 {
01175     register PlFrame   *plFramePtr = (PlFrame *) clientData;
01176     XKeyEvent          *event      = (XKeyEvent *) eventPtr;
01177     register Tk_Window tkwin       = plFramePtr->tkwin;
01178 
01179     KeySym             keysym;
01180     int            nchars;
01181     char           string[11];
01182     XComposeStatus cs;
01183 
01184     dbug_enter( "PlFrameKeyEH" );
01185 
01186     nchars         = XLookupString( event, string, 10, &keysym, &cs );
01187     string[nchars] = '\0';
01188     pldebug( "PlFrameKeyEH", "Keysym %x, translation: %s\n", keysym, string );
01189 
01190     if ( IsModifierKey( keysym ) )
01191     {
01192         eventPtr->type = 0;
01193     }
01194     else if ( IsCursorKey( keysym ) )
01195     {
01196         int x1, y1, dx = 0, dy = 0;
01197         int x0   = event->x, y0 = event->y;
01198         int xmin = 0, xmax = Tk_Width( tkwin ) - 1;
01199         int ymin = 0, ymax = Tk_Height( tkwin ) - 1;
01200 
01201         switch ( keysym )
01202         {
01203         case XK_Left:
01204             dx = -1;
01205             break;
01206         case XK_Right:
01207             dx = 1;
01208             break;
01209         case XK_Up:
01210             dy = -1;
01211             break;
01212         case XK_Down:
01213             dy = 1;
01214             break;
01215         }
01216 
01217         // Each modifier key added increases the multiplication factor by 5
01218 
01219         // Shift
01220 
01221         if ( event->state & 0x01 )
01222         {
01223             dx *= 5;
01224             dy *= 5;
01225         }
01226 
01227         // Caps Lock
01228 
01229         if ( event->state & 0x02 )
01230         {
01231             dx *= 5;
01232             dy *= 5;
01233         }
01234 
01235         // Control
01236 
01237         if ( event->state & 0x04 )
01238         {
01239             dx *= 5;
01240             dy *= 5;
01241         }
01242 
01243         // Alt
01244 
01245         if ( event->state & 0x08 )
01246         {
01247             dx *= 5;
01248             dy *= 5;
01249         }
01250 
01251         // Bounds checking so that we don't send cursor out of window
01252 
01253         x1 = x0 + dx;
01254         y1 = y0 + dy;
01255 
01256         if ( x1 < xmin )
01257             dx = xmin - x0;
01258         if ( y1 < ymin )
01259             dy = ymin - y0;
01260         if ( x1 > xmax )
01261             dx = xmax - x0;
01262         if ( y1 > ymax )
01263             dy = ymax - y0;
01264 
01265         // Engage...
01266 
01267         XWarpPointer( plFramePtr->display, Tk_WindowId( tkwin ),
01268             None, 0, 0, 0, 0, dx, dy );
01269         eventPtr->type = 0;
01270     }
01271 }
01272 
01273 //--------------------------------------------------------------------------
01274 // CreateXhairs()
01275 //
01276 // Creates graphic crosshairs at current pointer location.
01277 //--------------------------------------------------------------------------
01278 
01279 static void
01280 CreateXhairs( PlFrame *plFramePtr )
01281 {
01282     register Tk_Window tkwin = plFramePtr->tkwin;
01283     Window             root, child;
01284     int root_x, root_y, win_x, win_y;
01285     unsigned int       mask;
01286 
01287 // Switch to crosshair cursor.
01288 
01289     Tk_DefineCursor( tkwin, plFramePtr->xhair_cursor );
01290 
01291 // Find current pointer location and draw graphic crosshairs if pointer is
01292 // inside our window.
01293 
01294     if ( XQueryPointer( plFramePtr->display, Tk_WindowId( tkwin ),
01295              &root, &child, &root_x, &root_y, &win_x, &win_y,
01296              &mask ) )
01297     {
01298         if ( win_x >= 0 && win_x < Tk_Width( tkwin ) &&
01299              win_y >= 0 && win_y < Tk_Height( tkwin ) )
01300         {
01301             DrawXhairs( plFramePtr, win_x, win_y );
01302             plFramePtr->drawing_xhairs = 1;
01303         }
01304     }
01305 
01306 // Catch PointerMotion and crossing events so we can update them properly
01307 
01308     if ( !plFramePtr->drawing_rband )
01309     {
01310         Tk_CreateEventHandler( tkwin, PointerMotionMask,
01311             PlFrameMotionEH, (ClientData) plFramePtr );
01312 
01313         Tk_CreateEventHandler( tkwin, EnterWindowMask,
01314             PlFrameEnterEH, (ClientData) plFramePtr );
01315 
01316         Tk_CreateEventHandler( tkwin, LeaveWindowMask,
01317             PlFrameLeaveEH, (ClientData) plFramePtr );
01318     }
01319 
01320 // Catch KeyPress events so we can filter them
01321 
01322     Tk_CreateEventHandler( tkwin, KeyPressMask,
01323         PlFrameKeyEH, (ClientData) plFramePtr );
01324 }
01325 
01326 //--------------------------------------------------------------------------
01327 // DestroyXhairs()
01328 //
01329 // Destroys graphic crosshairs.
01330 //--------------------------------------------------------------------------
01331 
01332 static void
01333 DestroyXhairs( PlFrame *plFramePtr )
01334 {
01335     register Tk_Window tkwin = plFramePtr->tkwin;
01336 
01337 // Switch back to boring old pointer
01338 
01339     Tk_DefineCursor( tkwin, plFramePtr->cursor );
01340 
01341 // Don't catch PointerMotion or crossing events any more
01342 
01343     if ( !plFramePtr->drawing_rband )
01344     {
01345         Tk_DeleteEventHandler( tkwin, PointerMotionMask,
01346             PlFrameMotionEH, (ClientData) plFramePtr );
01347 
01348         Tk_DeleteEventHandler( tkwin, EnterWindowMask,
01349             PlFrameEnterEH, (ClientData) plFramePtr );
01350 
01351         Tk_DeleteEventHandler( tkwin, LeaveWindowMask,
01352             PlFrameLeaveEH, (ClientData) plFramePtr );
01353     }
01354 
01355     Tk_DeleteEventHandler( tkwin, KeyPressMask,
01356         PlFrameKeyEH, (ClientData) plFramePtr );
01357 
01358 // This draw removes the last set of graphic crosshairs
01359 
01360     UpdateXhairs( plFramePtr );
01361     plFramePtr->drawing_xhairs = 0;
01362 }
01363 
01364 //--------------------------------------------------------------------------
01365 // DrawXhairs()
01366 //
01367 // Draws graphic crosshairs at (x0, y0).  The first draw erases the old set.
01368 //--------------------------------------------------------------------------
01369 
01370 static void
01371 DrawXhairs( PlFrame *plFramePtr, int x0, int y0 )
01372 {
01373     register Tk_Window tkwin = plFramePtr->tkwin;
01374     int xmin = 0, xmax = Tk_Width( tkwin ) - 1;
01375     int ymin = 0, ymax = Tk_Height( tkwin ) - 1;
01376 
01377     if ( plFramePtr->drawing_xhairs )
01378         UpdateXhairs( plFramePtr );
01379 
01380     plFramePtr->xhair_x[0].x = xmin; plFramePtr->xhair_x[0].y = y0;
01381     plFramePtr->xhair_x[1].x = xmax; plFramePtr->xhair_x[1].y = y0;
01382 
01383     plFramePtr->xhair_y[0].x = x0; plFramePtr->xhair_y[0].y = ymin;
01384     plFramePtr->xhair_y[1].x = x0; plFramePtr->xhair_y[1].y = ymax;
01385 
01386     UpdateXhairs( plFramePtr );
01387 }
01388 
01389 //--------------------------------------------------------------------------
01390 // UpdateXhairs()
01391 //
01392 // Updates graphic crosshairs.  If already there, they are erased.
01393 //--------------------------------------------------------------------------
01394 
01395 static void
01396 UpdateXhairs( PlFrame *plFramePtr )
01397 {
01398     register Tk_Window tkwin = plFramePtr->tkwin;
01399 
01400     XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
01401         plFramePtr->xorGC, plFramePtr->xhair_x, 2,
01402         CoordModeOrigin );
01403 
01404     XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
01405         plFramePtr->xorGC, plFramePtr->xhair_y, 2,
01406         CoordModeOrigin );
01407 }
01408 
01409 //--------------------------------------------------------------------------
01410 // CreateRband()
01411 //
01412 // Initiate rubber banding.
01413 //--------------------------------------------------------------------------
01414 
01415 static void
01416 CreateRband( PlFrame *plFramePtr )
01417 {
01418     register Tk_Window tkwin = plFramePtr->tkwin;
01419     Window             root, child;
01420     int root_x, root_y, win_x, win_y;
01421     unsigned int       mask;
01422 
01423 // Find current pointer location, and initiate rubber banding.
01424 
01425     if ( XQueryPointer( plFramePtr->display, Tk_WindowId( tkwin ),
01426              &root, &child, &root_x, &root_y, &win_x, &win_y,
01427              &mask ) )
01428     {
01429         if ( win_x >= 0 && win_x < Tk_Width( tkwin ) &&
01430              win_y >= 0 && win_y < Tk_Height( tkwin ) )
01431         {
01432             // Okay, pointer is in our window.
01433             plFramePtr->rband_pt[0].x = win_x;
01434             plFramePtr->rband_pt[0].y = win_y;
01435 
01436             DrawRband( plFramePtr, win_x, win_y );
01437             plFramePtr->drawing_rband = 1;
01438         }
01439         else
01440         {
01441             // Hmm, somehow they turned it on without even being in the window.
01442             // Just put the anchor in top left, they'll soon realize this is a
01443             // mistake...
01444 
01445             plFramePtr->rband_pt[0].x = 0;
01446             plFramePtr->rband_pt[0].y = 0;
01447 
01448             DrawRband( plFramePtr, win_x, win_y );
01449             plFramePtr->drawing_rband = 1;
01450         }
01451     }
01452 
01453 // Catch PointerMotion and crossing events so we can update them properly
01454 
01455     if ( !plFramePtr->drawing_xhairs )
01456     {
01457         Tk_CreateEventHandler( tkwin, PointerMotionMask,
01458             PlFrameMotionEH, (ClientData) plFramePtr );
01459 
01460         Tk_CreateEventHandler( tkwin, EnterWindowMask,
01461             PlFrameEnterEH, (ClientData) plFramePtr );
01462 
01463         Tk_CreateEventHandler( tkwin, LeaveWindowMask,
01464             PlFrameLeaveEH, (ClientData) plFramePtr );
01465     }
01466 }
01467 
01468 //--------------------------------------------------------------------------
01469 // DestroyRband()
01470 //
01471 // Turn off rubber banding.
01472 //--------------------------------------------------------------------------
01473 
01474 static void
01475 DestroyRband( PlFrame *plFramePtr )
01476 {
01477     register Tk_Window tkwin = plFramePtr->tkwin;
01478 
01479 // Don't catch PointerMotion or crossing events any more
01480 
01481     if ( !plFramePtr->drawing_xhairs )
01482     {
01483         Tk_DeleteEventHandler( tkwin, PointerMotionMask,
01484             PlFrameMotionEH, (ClientData) plFramePtr );
01485 
01486         Tk_DeleteEventHandler( tkwin, EnterWindowMask,
01487             PlFrameEnterEH, (ClientData) plFramePtr );
01488 
01489         Tk_DeleteEventHandler( tkwin, LeaveWindowMask,
01490             PlFrameLeaveEH, (ClientData) plFramePtr );
01491     }
01492 
01493 // This draw removes the residual rubber band.
01494 
01495     UpdateRband( plFramePtr );
01496     plFramePtr->drawing_rband = 0;
01497 }
01498 
01499 //--------------------------------------------------------------------------
01500 // DrawRband()
01501 //
01502 // Draws a rubber band from the anchor to the current cursor location.
01503 //--------------------------------------------------------------------------
01504 
01505 static void
01506 DrawRband( PlFrame *plFramePtr, int x0, int y0 )
01507 {
01508 // If the line is already up, clear it.
01509 
01510     if ( plFramePtr->drawing_rband )
01511         UpdateRband( plFramePtr );
01512 
01513     plFramePtr->rband_pt[1].x = x0; plFramePtr->rband_pt[1].y = y0;
01514 
01515     UpdateRband( plFramePtr );
01516 }
01517 
01518 //--------------------------------------------------------------------------
01519 // UpdateRband()
01520 //
01521 // Updates rubber band.  If already there, it is erased.
01522 //--------------------------------------------------------------------------
01523 
01524 static void
01525 UpdateRband( PlFrame *plFramePtr )
01526 {
01527     register Tk_Window tkwin = plFramePtr->tkwin;
01528 
01529     XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
01530         plFramePtr->xorGC, plFramePtr->rband_pt, 2,
01531         CoordModeOrigin );
01532 }
01533 
01534 //
01535 //--------------------------------------------------------------------------
01536 //
01537 // PlFrameInit --
01538 //
01539 //      Invoked to handle miscellaneous initialization after window gets
01540 //      mapped.
01541 //
01542 // Results:
01543 //      None.
01544 //
01545 // Side effects:
01546 //      PLplot internal parameters and device driver are initialized.
01547 //
01548 //--------------------------------------------------------------------------
01549 
01550 static void
01551 PlFrameInit( ClientData clientData )
01552 {
01553     register PlFrame   *plFramePtr = (PlFrame *) clientData;
01554     register Tk_Window tkwin       = plFramePtr->tkwin;
01555 
01556 // Set up window parameters and arrange for window to be refreshed
01557 
01558     plFramePtr->flags |= REFRESH_PENDING;
01559     plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
01560 
01561 // First-time initialization
01562 
01563     if ( !plFramePtr->tkwin_initted )
01564     {
01565         plsstrm( plFramePtr->ipls );
01566         plsxwin( Tk_WindowId( tkwin ) );
01567         plspause( 0 );
01568         plinit();
01569 // plplot_ccmap is statically defined in plxwd.h.  Note that
01570 // xwin.c also includes that header and uses that variable.
01571         if ( plplot_ccmap )
01572         {
01573             Install_cmap( plFramePtr );
01574         }
01575         if ( plFramePtr->bopCmd != NULL )
01576             plsbopH( process_bop, (void *) plFramePtr );
01577         if ( plFramePtr->eopCmd != NULL )
01578             plseopH( process_eop, (void *) plFramePtr );
01579 
01580         plbop();
01581 
01582         plFramePtr->tkwin_initted = 1;
01583         plFramePtr->width         = Tk_Width( tkwin );
01584         plFramePtr->height        = Tk_Height( tkwin );
01585         plFramePtr->prevWidth     = plFramePtr->width;
01586         plFramePtr->prevHeight    = plFramePtr->height;
01587     }
01588 
01589 // Draw plframe
01590 
01591     DisplayPlFrame( clientData );
01592 
01593     if ( plFramePtr->xhairs )
01594         CreateXhairs( plFramePtr );
01595 
01596     if ( plFramePtr->rband )
01597         CreateRband( plFramePtr );
01598 }
01599 
01600 //
01601 //--------------------------------------------------------------------------
01602 //
01603 // Install_cmap --
01604 //
01605 //      Installs X driver color map as necessary when custom color maps
01606 //      are used.
01607 //
01608 // Results:
01609 //      None.
01610 //
01611 // Side effects:
01612 //      Parent color maps may get changed.
01613 //
01614 //--------------------------------------------------------------------------
01615 //
01616 
01617 static void
01618 Install_cmap( PlFrame *plFramePtr )
01619 {
01620     XwDev *dev;
01621 
01622 #define INSTALL_COLORMAP_IN_TK
01623 #ifdef  INSTALL_COLORMAP_IN_TK
01624     dev = (XwDev *) plFramePtr->pls->dev;
01625     Tk_SetWindowColormap( Tk_MainWindow( plFramePtr->interp ), dev->xwd->map );
01626 
01627 //
01628 // If the colormap is local to this widget, the WM must be informed that
01629 // it should be installed when the widget gets the focus.  The top level
01630 // window must be added to the end of its own list, because otherwise the
01631 // window manager adds it to the front (as required by the ICCCM).  Thanks
01632 // to Paul Mackerras for providing this info in his TK photo widget.
01633 //
01634 
01635 #else
01636     int    count = 0;
01637     Window top, colormap_windows[5];
01638 
01639     top = Tk_WindowId( Tk_MainWindow( plFramePtr->interp ) );
01640 
01641     colormap_windows[count++] = Tk_WindowId( plFramePtr->tkwin );
01642     colormap_windows[count++] = top;
01643 
01644     if ( !XSetWMColormapWindows( plFramePtr->display,
01645              top, colormap_windows, count ) )
01646         fprintf( stderr, "Unable to set color map property!\n" );
01647 #endif
01648 }
01649 
01650 //
01651 //--------------------------------------------------------------------------
01652 //
01653 // DisplayPlFrame --
01654 //
01655 //      This procedure is invoked to display a plframe widget.
01656 //
01657 // Results:
01658 //      None.
01659 //
01660 // Side effects:
01661 //      Commands are output to X to display the plframe in its
01662 //      current mode.
01663 //
01664 //--------------------------------------------------------------------------
01665 //
01666 
01667 static void
01668 DisplayPlFrame( ClientData clientData )
01669 {
01670     register PlFrame   *plFramePtr = (PlFrame *) clientData;
01671     register Tk_Window tkwin       = plFramePtr->tkwin;
01672 
01673     dbug_enter( "DisplayPlFrame" );
01674 
01675 // Update scrollbars if needed
01676 
01677     if ( plFramePtr->flags & UPDATE_V_SCROLLBAR )
01678     {
01679         UpdateVScrollbar( plFramePtr );
01680     }
01681     if ( plFramePtr->flags & UPDATE_H_SCROLLBAR )
01682     {
01683         UpdateHScrollbar( plFramePtr );
01684     }
01685     plFramePtr->flags &= ~( UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR );
01686 
01687 // If not mapped yet, just return and cancel pending refresh
01688 
01689     if ( ( plFramePtr->tkwin == NULL ) || !Tk_IsMapped( tkwin ) )
01690     {
01691         plFramePtr->flags &= ~REFRESH_PENDING;
01692         return;
01693     }
01694 
01695 // Redraw border if necessary
01696 
01697     if ( ( plFramePtr->border != NULL ) &&
01698          ( plFramePtr->relief != TK_RELIEF_FLAT ) )
01699     {
01700 #if TK_MAJOR_VERSION >= 4 && TK_MINOR_VERSION >= 0
01701         Tk_Draw3DRectangle( plFramePtr->tkwin, Tk_WindowId( tkwin ),
01702             plFramePtr->border, 0, 0, Tk_Width( tkwin ), Tk_Height( tkwin ),
01703             plFramePtr->borderWidth, plFramePtr->relief );
01704 #else
01705         Tk_Draw3DRectangle( plFramePtr->display, Tk_WindowId( tkwin ),
01706             plFramePtr->border, 0, 0, Tk_Width( tkwin ), Tk_Height( tkwin ),
01707             plFramePtr->borderWidth, plFramePtr->relief );
01708 #endif
01709     }
01710 
01711 // All refresh events
01712 
01713     if ( plFramePtr->flags & REFRESH_PENDING )
01714     {
01715         plFramePtr->flags &= ~REFRESH_PENDING;
01716 
01717         // Reschedule resizes to avoid occasional ordering conflicts with
01718         // the packer's resize of the window (this call must come last).
01719 
01720         if ( plFramePtr->flags & RESIZE_PENDING )
01721         {
01722             plFramePtr->flags |= REFRESH_PENDING;
01723             plFramePtr->flags &= ~RESIZE_PENDING;
01724             Tk_DoWhenIdle( DisplayPlFrame, clientData );
01725             return;
01726         }
01727 
01728         // Redraw -- replay contents of plot buffer
01729 
01730         if ( plFramePtr->flags & REDRAW_PENDING )
01731         {
01732             plFramePtr->flags &= ~REDRAW_PENDING;
01733             plsstrm( plFramePtr->ipls );
01734             pl_cmd( PLESC_REDRAW, (void *) NULL );
01735         }
01736 
01737         // Resize -- if window bounds have changed
01738 
01739         else if ( ( plFramePtr->width != plFramePtr->prevWidth ) ||
01740                   ( plFramePtr->height != plFramePtr->prevHeight ) )
01741         {
01742             plFramePtr->pldis.width  = plFramePtr->width;
01743             plFramePtr->pldis.height = plFramePtr->height;
01744 
01745             plsstrm( plFramePtr->ipls );
01746             pl_cmd( PLESC_RESIZE, (void *) &( plFramePtr->pldis ) );
01747             plFramePtr->prevWidth  = plFramePtr->width;
01748             plFramePtr->prevHeight = plFramePtr->height;
01749         }
01750 
01751         // Expose -- if window bounds are unchanged
01752 
01753         else
01754         {
01755             plsstrm( plFramePtr->ipls );
01756             if ( plFramePtr->drawing_xhairs )
01757             {
01758                 XClearWindow( plFramePtr->display, Tk_WindowId( tkwin ) );
01759                 XFlush( plFramePtr->display );
01760                 pl_cmd( PLESC_EXPOSE, NULL );
01761             }
01762             else
01763             {
01764                 pl_cmd( PLESC_EXPOSE, (void *) &( plFramePtr->pldis ) );
01765             }
01766 
01767             // Reset window bounds so that next time they are set fresh
01768 
01769             plFramePtr->pldis.x      = Tk_X( tkwin ) + Tk_Width( tkwin );
01770             plFramePtr->pldis.y      = Tk_Y( tkwin ) + Tk_Height( tkwin );
01771             plFramePtr->pldis.width  = -Tk_Width( tkwin );
01772             plFramePtr->pldis.height = -Tk_Height( tkwin );
01773         }
01774 
01775         // Update graphic crosshairs if necessary
01776 
01777         if ( plFramePtr->drawing_xhairs )
01778         {
01779             UpdateXhairs( plFramePtr );
01780         }
01781 
01782         // Update rubber band if necessary.
01783 
01784         if ( plFramePtr->drawing_rband )
01785         {
01786             UpdateRband( plFramePtr );
01787         }
01788     }
01789 }
01790 
01791 //--------------------------------------------------------------------------
01792 // Routines to process widget commands.
01793 //--------------------------------------------------------------------------
01794 
01795 //--------------------------------------------------------------------------
01796 // scol0
01797 //
01798 // Sets a color in cmap0.
01799 //--------------------------------------------------------------------------
01800 
01801 static int
01802 scol0( Tcl_Interp *interp, register PlFrame *plFramePtr,
01803        int i, const char *col, int *p_changed )
01804 {
01805     PLStream *pls = plFramePtr->pls;
01806     XColor   xcol;
01807     PLINT    r, g, b;
01808 
01809     if ( col == NULL )
01810     {
01811         Tcl_AppendResult( interp, "color value not specified",
01812             (char *) NULL );
01813         return TCL_ERROR;
01814     }
01815 
01816     if ( !XParseColor( plFramePtr->display,
01817              Tk_Colormap( plFramePtr->tkwin ), col, &xcol ) )
01818     {
01819         Tcl_AppendResult( interp, "Couldn't parse color ", col,
01820             (char *) NULL );
01821         return TCL_ERROR;
01822     }
01823 
01824     r = (unsigned) ( xcol.red & 0xFF00 ) >> 8;
01825     g = (unsigned) ( xcol.green & 0xFF00 ) >> 8;
01826     b = (unsigned) ( xcol.blue & 0xFF00 ) >> 8;
01827 
01828     if ( ( pls->cmap0[i].r != r ) ||
01829          ( pls->cmap0[i].g != g ) ||
01830          ( pls->cmap0[i].b != b ) )
01831     {
01832         pls->cmap0[i].r = r;
01833         pls->cmap0[i].g = g;
01834         pls->cmap0[i].b = b;
01835         *p_changed      = 1;
01836     }
01837 
01838     return TCL_OK;
01839 }
01840 
01841 //--------------------------------------------------------------------------
01842 // scol1
01843 //
01844 // Sets a color in cmap1.
01845 //--------------------------------------------------------------------------
01846 
01847 static int
01848 scol1( Tcl_Interp *interp, register PlFrame *plFramePtr,
01849        int i, const char *col, const char *pos, const char *rev, int *p_changed )
01850 {
01851     PLStream *pls = plFramePtr->pls;
01852     XColor   xcol;
01853     PLFLT    h, l, s, r, g, b, p;
01854     int      reverse;
01855 
01856     if ( col == NULL )
01857     {
01858         Tcl_AppendResult( interp, "color value not specified",
01859             (char *) NULL );
01860         return TCL_ERROR;
01861     }
01862 
01863     if ( pos == NULL )
01864     {
01865         Tcl_AppendResult( interp, "control point position not specified",
01866             (char *) NULL );
01867         return TCL_ERROR;
01868     }
01869 
01870     if ( rev == NULL )
01871     {
01872         Tcl_AppendResult( interp, "interpolation sense not specified",
01873             (char *) NULL );
01874         return TCL_ERROR;
01875     }
01876 
01877     if ( !XParseColor( plFramePtr->display,
01878              Tk_Colormap( plFramePtr->tkwin ), col, &xcol ) )
01879     {
01880         Tcl_AppendResult( interp, "Couldn't parse color ", col,
01881             (char *) NULL );
01882         return TCL_ERROR;
01883     }
01884 
01885     r = ( (unsigned) ( xcol.red & 0xFF00 ) >> 8 ) / 255.0;
01886     g = ( (unsigned) ( xcol.green & 0xFF00 ) >> 8 ) / 255.0;
01887     b = ( (unsigned) ( xcol.blue & 0xFF00 ) >> 8 ) / 255.0;
01888 
01889     plrgbhls( r, g, b, &h, &l, &s );
01890 
01891     p       = atof( pos ) / 100.0;
01892     reverse = atoi( rev );
01893 
01894     if ( ( pls->cmap1cp[i].h != h ) ||
01895          ( pls->cmap1cp[i].l != l ) ||
01896          ( pls->cmap1cp[i].s != s ) ||
01897          ( pls->cmap1cp[i].p != p ) ||
01898          ( pls->cmap1cp[i].rev != reverse ) )
01899     {
01900         pls->cmap1cp[i].h   = h;
01901         pls->cmap1cp[i].l   = l;
01902         pls->cmap1cp[i].s   = s;
01903         pls->cmap1cp[i].p   = p;
01904         pls->cmap1cp[i].rev = reverse;
01905         *p_changed          = 1;
01906     }
01907     return TCL_OK;
01908 }
01909 
01910 //--------------------------------------------------------------------------
01911 // ColorManip
01912 //
01913 // Processes color manipulation widget commands.
01914 //
01915 // This provides an alternate API for the plplot color handling functions
01916 // (prepend a "pl" to get the corresponding plplot function).  They differ
01917 // from the versions in the Tcl API in the following ways:
01918 //
01919 //  - X11 conventions are used rather than plplot ones.  XParseColor is used
01920 //    to convert a string into its 3 rgb components.  This lets you use
01921 //    symbolic names or hex notation for color values.
01922 //
01923 //  - these expect/emit Tcl array values in lists rather than in tclmatrix
01924 //    form, like most "normal" Tcl tools.  For usage, see the examples in the
01925 //    palette tools (plcolor.tcl).
01926 //--------------------------------------------------------------------------
01927 
01928 static int
01929 ColorManip( Tcl_Interp *interp, register PlFrame *plFramePtr,
01930             int argc, const char **argv )
01931 {
01932     PLStream *pls = plFramePtr->pls;
01933     int      length;
01934     char     c;
01935     int      result = TCL_OK;
01936     char     *tmpstring;
01937 
01938 #ifdef DEBUG
01939     if ( pls->debug )
01940     {
01941         int i;
01942         fprintf( stderr, "There are %d arguments to ColorManip:", argc );
01943         for ( i = 0; i < argc; i++ )
01944         {
01945             fprintf( stderr, " %s", argv[i] );
01946         }
01947         fprintf( stderr, "\n" );
01948     }
01949 #endif
01950 
01951 // Make sure widget has been initialized before going any further
01952 
01953     if ( !plFramePtr->tkwin_initted )
01954     {
01955         Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
01956     }
01957 
01958 // Set stream number and get ready to process the command
01959 
01960     plsstrm( plFramePtr->ipls );
01961 
01962     c      = argv[0][0];
01963     length = strlen( argv[0] );
01964 
01965 // gcmap0 -- get color map 0
01966 // first arg is number of colors, the rest are hex number specifications
01967 
01968     if ( ( c == 'g' ) && ( strncmp( argv[0], "gcmap0", length ) == 0 ) )
01969     {
01970         int           i;
01971         unsigned long plcolor;
01972         char          str[10];
01973 
01974         sprintf( str, "%d", (int) pls->ncol0 );
01975         Tcl_AppendElement( interp, str );
01976         for ( i = 0; i < pls->ncol0; i++ )
01977         {
01978             plcolor = ( ( pls->cmap0[i].r << 16 ) |
01979                         ( pls->cmap0[i].g << 8 ) |
01980                         ( pls->cmap0[i].b ) );
01981 
01982             sprintf( str, "#%06lx", ( plcolor & 0xFFFFFF ) );
01983             Tcl_AppendElement( interp, str );
01984         }
01985         result = TCL_OK;
01986     }
01987 
01988 // gcmap1 -- get color map 1
01989 // first arg is number of control points
01990 // the rest are hex number specifications followed by positions (0-100)
01991 
01992     else if ( ( c == 'g' ) && ( strncmp( argv[0], "gcmap1", length ) == 0 ) )
01993     {
01994         int           i;
01995         unsigned long plcolor;
01996         char          str[10];
01997         PLFLT         h, l, s, r, g, b;
01998         int           r1, g1, b1;
01999 
02000         sprintf( str, "%d", (int) pls->ncp1 );
02001         Tcl_AppendElement( interp, str );
02002         for ( i = 0; i < pls->ncp1; i++ )
02003         {
02004             h = pls->cmap1cp[i].h;
02005             l = pls->cmap1cp[i].l;
02006             s = pls->cmap1cp[i].s;
02007 
02008             plhlsrgb( h, l, s, &r, &g, &b );
02009 
02010             r1 = MAX( 0, MIN( 255, (int) ( 256. * r ) ) );
02011             g1 = MAX( 0, MIN( 255, (int) ( 256. * g ) ) );
02012             b1 = MAX( 0, MIN( 255, (int) ( 256. * b ) ) );
02013 
02014             plcolor = ( ( r1 << 16 ) | ( g1 << 8 ) | ( b1 ) );
02015 
02016             sprintf( str, "#%06lx", ( plcolor & 0xFFFFFF ) );
02017             Tcl_AppendElement( interp, str );
02018 
02019             sprintf( str, "%02d", (int) ( 100 * pls->cmap1cp[i].p ) );
02020             Tcl_AppendElement( interp, str );
02021 
02022             sprintf( str, "%01d", (int) ( pls->cmap1cp[i].rev ) );
02023             Tcl_AppendElement( interp, str );
02024         }
02025         result = TCL_OK;
02026     }
02027 
02028 // scmap0 -- set color map 0
02029 // first arg is number of colors, the rest are hex number specifications
02030 
02031     else if ( ( c == 's' ) && ( strncmp( argv[0], "scmap0", length ) == 0 ) )
02032     {
02033         int  i, changed = 1, ncol0 = atoi( argv[1] );
02034         char *col;
02035 
02036         if ( ncol0 > 16 || ncol0 < 1 )
02037         {
02038             Tcl_AppendResult( interp, "illegal number of colors in cmap0: ",
02039                 argv[1], (char *) NULL );
02040             return TCL_ERROR;
02041         }
02042 
02043         pls->ncol0 = ncol0;
02044         tmpstring  = (char *) malloc( strlen( argv[2] ) + 1 );
02045         strcpy( tmpstring, argv[2] );
02046         col = strtok( tmpstring, " " );
02047         for ( i = 0; i < pls->ncol0; i++ )
02048         {
02049             if ( col == NULL )
02050                 break;
02051 
02052             if ( scol0( interp, plFramePtr, i, col, &changed ) != TCL_OK )
02053                 return TCL_ERROR;
02054 
02055             col = strtok( NULL, " " );
02056         }
02057         free( tmpstring );
02058 
02059         if ( changed )
02060             plP_state( PLSTATE_CMAP0 );
02061     }
02062 
02063 // scmap1 -- set color map 1
02064 // first arg is number of colors, the rest are hex number specifications
02065 
02066     else if ( ( c == 's' ) && ( strncmp( argv[0], "scmap1", length ) == 0 ) )
02067     {
02068         int  i, changed = 1, ncp1 = atoi( argv[1] );
02069         char *col, *pos, *rev;
02070 
02071         if ( ncp1 > 32 || ncp1 < 1 )
02072         {
02073             Tcl_AppendResult( interp,
02074                 "illegal number of control points in cmap1: ",
02075                 argv[1], (char *) NULL );
02076             return TCL_ERROR;
02077         }
02078 
02079         tmpstring = (char *) malloc( strlen( argv[2] ) + 1 );
02080         strcpy( tmpstring, argv[2] );
02081         col = strtok( tmpstring, " " );
02082         pos = strtok( NULL, " " );
02083         rev = strtok( NULL, " " );
02084         for ( i = 0; i < ncp1; i++ )
02085         {
02086             if ( col == NULL )
02087                 break;
02088 
02089             if ( scol1( interp, plFramePtr,
02090                      i, col, pos, rev, &changed ) != TCL_OK )
02091                 return TCL_ERROR;
02092 
02093             col = strtok( NULL, " " );
02094             pos = strtok( NULL, " " );
02095             rev = strtok( NULL, " " );
02096         }
02097         free( tmpstring );
02098 
02099         if ( changed )
02100         {
02101             PLStream *pls = plFramePtr->pls;
02102             pls->ncp1 = ncp1;
02103             plcmap1_calc();
02104         }
02105     }
02106 
02107 // scol0 -- set single color in cmap0
02108 // first arg is the color number, the next is the color in hex
02109 
02110     else if ( ( c == 's' ) && ( strncmp( argv[0], "scol0", length ) == 0 ) )
02111     {
02112         int i = atoi( argv[1] ), changed = 1;
02113 
02114         if ( i > pls->ncol0 || i < 0 )
02115         {
02116             Tcl_AppendResult( interp, "illegal color number in cmap0: ",
02117                 argv[1], (char *) NULL );
02118             return TCL_ERROR;
02119         }
02120 
02121         if ( scol0( interp, plFramePtr, i, argv[2], &changed ) != TCL_OK )
02122             return TCL_ERROR;
02123 
02124         if ( changed )
02125             plP_state( PLSTATE_CMAP0 );
02126     }
02127 
02128 // scol1 -- set color of control point in cmap1
02129 // first arg is the control point, the next two are the color in hex and pos
02130 
02131     else if ( ( c == 's' ) && ( strncmp( argv[0], "scol1", length ) == 0 ) )
02132     {
02133         int i = atoi( argv[1] ), changed = 1;
02134 
02135         if ( i > pls->ncp1 || i < 0 )
02136         {
02137             Tcl_AppendResult( interp, "illegal control point number in cmap1: ",
02138                 argv[1], (char *) NULL );
02139             return TCL_ERROR;
02140         }
02141 
02142         if ( scol1( interp, plFramePtr,
02143                  i, argv[2], argv[3], argv[4], &changed ) != TCL_OK )
02144             return TCL_ERROR;
02145 
02146         if ( changed )
02147             plcmap1_calc();
02148     }
02149 
02150     plflush();
02151     return result;
02152 }
02153 
02154 //--------------------------------------------------------------------------
02155 // Cmd
02156 //
02157 // Processes "cmd" widget command.
02158 // Handles commands that go more or less directly to the PLplot library.
02159 // Most of these come out of the PLplot Tcl API support file.
02160 //--------------------------------------------------------------------------
02161 
02162 static int
02163 Cmd( Tcl_Interp *interp, register PlFrame *plFramePtr,
02164      int argc, const char **argv )
02165 {
02166     int  result    = TCL_OK;
02167     char cmdlist[] = "";
02168 
02169 #ifdef DEBUG
02170     PLStream *pls = plFramePtr->pls;
02171     if ( pls->debug )
02172     {
02173         int i;
02174         fprintf( stderr, "There are %d arguments to Cmd:", argc );
02175         for ( i = 0; i < argc; i++ )
02176         {
02177             fprintf( stderr, " %s", argv[i] );
02178         }
02179         fprintf( stderr, "\n" );
02180     }
02181 #endif
02182 
02183 // no option -- return list of available PLplot commands
02184 
02185     if ( argc == 0 )
02186         return plTclCmd( cmdlist, interp, argc, argv );
02187 
02188 // Make sure widget has been initialized before going any further
02189 
02190     if ( !plFramePtr->tkwin_initted )
02191     {
02192         Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
02193     }
02194 
02195 // Set stream number and get ready to process the command
02196 
02197     plsstrm( plFramePtr->ipls );
02198 
02199 // Process command
02200 
02201     result = plTclCmd( cmdlist, interp, argc, argv );
02202 
02203     plflush();
02204     return result;
02205 }
02206 
02207 //
02208 //--------------------------------------------------------------------------
02209 //
02210 // ConfigurePlFrame --
02211 //
02212 //      This procedure is called to process an argv/argc list, plus the Tk
02213 //      option database, in order to configure (or reconfigure) a
02214 //      plframe widget.
02215 //
02216 // Results:
02217 //      The return value is a standard Tcl result.  If TCL_ERROR is
02218 //      returned, then interp->result contains an error message.
02219 //
02220 // Side effects:
02221 //      Configuration information, such as text string, colors, font, etc.
02222 //      get set for plFramePtr; old resources get freed, if there were
02223 //      any.
02224 //
02225 //--------------------------------------------------------------------------
02226 //
02227 
02228 static int
02229 ConfigurePlFrame( Tcl_Interp *interp, register PlFrame *plFramePtr,
02230                   int argc, const char **argv, int flags )
02231 {
02232     register Tk_Window tkwin = plFramePtr->tkwin;
02233     PLStream           *pls  = plFramePtr->pls;
02234     XwDev              *dev  = (XwDev *) pls->dev;
02235     XwDisplay          *xwd  = (XwDisplay *) dev->xwd;
02236     XGCValues          gcValues;
02237     unsigned long      mask;
02238     int need_redisplay = 0;
02239 
02240 #ifdef DEBUG
02241     if ( pls->debug )
02242     {
02243         int i;
02244         fprintf( stderr, "Arguments to configure are:" );
02245         for ( i = 0; i < argc; i++ )
02246         {
02247             fprintf( stderr, " %s", argv[i] );
02248         }
02249         fprintf( stderr, "\n" );
02250     }
02251 #endif
02252 
02253     dbug_enter( "ConfigurePlFrame" );
02254 
02255     if ( Tk_ConfigureWidget( interp, tkwin, configSpecs,
02256              argc, (CONST char **) argv, (char *) plFramePtr, flags ) != TCL_OK )
02257     {
02258         return TCL_ERROR;
02259     }
02260 
02261 //
02262 // Set background color using xwin driver's pixel value.  Done this way so
02263 // that (a) we can use r/w color cells, and (b) the BG pixel values as set
02264 // here and in the xwin driver are consistent.
02265 //
02266 
02267     plsstrm( plFramePtr->ipls );
02268     plP_esc( PLESC_DEV2PLCOL, (void *) plFramePtr->bgColor );
02269     pl_cpcolor( &pls->cmap0[0], &pls->tmpcolor );
02270     plP_esc( PLESC_SETBGFG, NULL );
02271 
02272     Tk_SetWindowBackground( tkwin, xwd->cmap0[0].pixel );
02273     Tk_SetWindowBorder( tkwin, xwd->cmap0[0].pixel );
02274 
02275 // Set up GC for rubber-band draws
02276 
02277     gcValues.background = xwd->cmap0[0].pixel;
02278     gcValues.foreground = 0xFF;
02279     gcValues.function   = GXxor;
02280     mask = GCForeground | GCBackground | GCFunction;
02281 
02282     if ( plFramePtr->xorGC != NULL )
02283         Tk_FreeGC( plFramePtr->display, plFramePtr->xorGC );
02284 
02285     plFramePtr->xorGC = Tk_GetGC( plFramePtr->tkwin, mask, &gcValues );
02286 
02287 // Geometry settings
02288 
02289     Tk_SetInternalBorder( tkwin, plFramePtr->borderWidth );
02290     if ( ( plFramePtr->width > 0 ) || ( plFramePtr->height > 0 ) )
02291     {
02292         Tk_GeometryRequest( tkwin, plFramePtr->width, plFramePtr->height );
02293         if ( ( plFramePtr->width != plFramePtr->prevWidth ) ||
02294              ( plFramePtr->height != plFramePtr->prevHeight ) )
02295             need_redisplay = 1;
02296     }
02297 
02298 // Create or destroy graphic crosshairs as specified
02299 
02300     if ( Tk_IsMapped( tkwin ) )
02301     {
02302         if ( plFramePtr->xhairs )
02303         {
02304             if ( !plFramePtr->drawing_xhairs )
02305                 CreateXhairs( plFramePtr );
02306         }
02307         else
02308         {
02309             if ( plFramePtr->drawing_xhairs )
02310                 DestroyXhairs( plFramePtr );
02311         }
02312     }
02313 
02314 // Create or destroy rubber band as specified
02315 
02316     if ( Tk_IsMapped( tkwin ) )
02317     {
02318         if ( plFramePtr->rband )
02319         {
02320             if ( !plFramePtr->drawing_rband )
02321                 CreateRband( plFramePtr );
02322         }
02323         else
02324         {
02325             if ( plFramePtr->drawing_rband )
02326                 DestroyRband( plFramePtr );
02327         }
02328     }
02329 
02330 // Arrange for window to be refreshed if necessary
02331 
02332     if ( need_redisplay && Tk_IsMapped( tkwin )
02333          && !( plFramePtr->flags & REFRESH_PENDING ) )
02334     {
02335         Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
02336         plFramePtr->flags |= REFRESH_PENDING;
02337         plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
02338     }
02339 
02340     return TCL_OK;
02341 }
02342 
02343 //--------------------------------------------------------------------------
02344 // Draw
02345 //
02346 // Processes "draw" widget command.
02347 // Handles rubber-band drawing.
02348 //--------------------------------------------------------------------------
02349 
02350 static int
02351 Draw( Tcl_Interp *interp, register PlFrame *plFramePtr,
02352       int argc, const char **argv )
02353 {
02354     register Tk_Window tkwin = plFramePtr->tkwin;
02355     int  result = TCL_OK;
02356     char c      = argv[0][0];
02357     int  length = strlen( argv[0] );
02358 
02359 // Make sure widget has been initialized before going any further
02360 
02361     if ( !plFramePtr->tkwin_initted )
02362     {
02363         Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
02364     }
02365 
02366 // init -- sets up for rubber-band drawing
02367 
02368     if ( ( c == 'i' ) && ( strncmp( argv[0], "init", length ) == 0 ) )
02369     {
02370         Tk_DefineCursor( tkwin, plFramePtr->xhair_cursor );
02371     }
02372 
02373 // end -- ends rubber-band drawing
02374 
02375     else if ( ( c == 'e' ) && ( strncmp( argv[0], "end", length ) == 0 ) )
02376     {
02377         Tk_DefineCursor( tkwin, plFramePtr->cursor );
02378         if ( plFramePtr->continue_draw )
02379         {
02380             XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
02381                 plFramePtr->xorGC, plFramePtr->pts, 5,
02382                 CoordModeOrigin );
02383             XSync( Tk_Display( tkwin ), 0 );
02384         }
02385 
02386         plFramePtr->continue_draw = 0;
02387     }
02388 
02389 // rect -- draw a rectangle, used to select rectangular areas
02390 // first draw erases old outline
02391 
02392     else if ( ( c == 'r' ) && ( strncmp( argv[0], "rect", length ) == 0 ) )
02393     {
02394         if ( argc < 5 )
02395         {
02396             Tcl_AppendResult( interp, "wrong # args: should be \"",
02397                 " draw rect x0 y0 x1 y1\"", (char *) NULL );
02398             result = TCL_ERROR;
02399         }
02400         else
02401         {
02402             int x0, y0, x1, y1;
02403             int xmin = 0, xmax = Tk_Width( tkwin ) - 1;
02404             int ymin = 0, ymax = Tk_Height( tkwin ) - 1;
02405 
02406             x0 = atoi( argv[1] );
02407             y0 = atoi( argv[2] );
02408             x1 = atoi( argv[3] );
02409             y1 = atoi( argv[4] );
02410 
02411             x0 = MAX( xmin, MIN( xmax, x0 ) );
02412             y0 = MAX( ymin, MIN( ymax, y0 ) );
02413             x1 = MAX( xmin, MIN( xmax, x1 ) );
02414             y1 = MAX( ymin, MIN( ymax, y1 ) );
02415 
02416             if ( plFramePtr->continue_draw )
02417             {
02418                 XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
02419                     plFramePtr->xorGC, plFramePtr->pts, 5,
02420                     CoordModeOrigin );
02421                 XSync( Tk_Display( tkwin ), 0 );
02422             }
02423 
02424             plFramePtr->pts[0].x = x0; plFramePtr->pts[0].y = y0;
02425             plFramePtr->pts[1].x = x1; plFramePtr->pts[1].y = y0;
02426             plFramePtr->pts[2].x = x1; plFramePtr->pts[2].y = y1;
02427             plFramePtr->pts[3].x = x0; plFramePtr->pts[3].y = y1;
02428             plFramePtr->pts[4].x = x0; plFramePtr->pts[4].y = y0;
02429 
02430             XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
02431                 plFramePtr->xorGC, plFramePtr->pts, 5,
02432                 CoordModeOrigin );
02433             XSync( Tk_Display( tkwin ), 0 );
02434 
02435             plFramePtr->continue_draw = 1;
02436         }
02437     }
02438 
02439     return result;
02440 }
02441 
02442 //--------------------------------------------------------------------------
02443 // Info
02444 //
02445 // Processes "info" widget command.
02446 // Returns requested info.
02447 //--------------------------------------------------------------------------
02448 
02449 static int
02450 Info( Tcl_Interp *interp, register PlFrame *plFramePtr,
02451       int argc, const char **argv )
02452 {
02453     int  length;
02454     char c;
02455     int  result = TCL_OK;
02456 
02457 // no option -- return list of available info commands
02458 
02459     if ( argc == 0 )
02460     {
02461         Tcl_SetResult( interp, "devkeys devnames", TCL_STATIC );
02462         return TCL_OK;
02463     }
02464 
02465     c      = argv[0][0];
02466     length = strlen( argv[0] );
02467 
02468 // devkeys -- return list of supported device keywords
02469 
02470     if ( ( c == 'd' ) && ( strncmp( argv[0], "devkeys", length ) == 0 ) )
02471     {
02472         int i = 0;
02473         while ( plFramePtr->devName[i] != NULL )
02474             Tcl_AppendElement( interp, plFramePtr->devName[i++] );
02475 
02476         result = TCL_OK;
02477     }
02478 
02479 // devkeys -- return list of supported device types
02480 
02481     else if ( ( c == 'd' ) && ( strncmp( argv[0], "devnames", length ) == 0 ) )
02482     {
02483         int i = 0;
02484         while ( plFramePtr->devDesc[i] != NULL )
02485             Tcl_AppendElement( interp, plFramePtr->devDesc[i++] );
02486 
02487         result = TCL_OK;
02488     }
02489 
02490 // unrecognized
02491 
02492     else
02493     {
02494         Tcl_AppendResult( interp, "bad option to \"info\": must be ",
02495             "devkeys, devnames", (char *) NULL );
02496 
02497         result = TCL_ERROR;
02498     }
02499 
02500     return result;
02501 }
02502 
02503 //--------------------------------------------------------------------------
02504 // Openlink
02505 //
02506 // Processes "openlink" widget command.
02507 // Opens channel (FIFO or socket) for binary data transfer between client
02508 // and server.
02509 //--------------------------------------------------------------------------
02510 
02511 static int
02512 Openlink( Tcl_Interp *interp, register PlFrame *plFramePtr,
02513           int argc, const char **argv )
02514 {
02515     register PLRDev  *plr   = plFramePtr->plr;
02516     register PLiodev *iodev = plr->iodev;
02517 
02518     char             c = argv[0][0];
02519     int length         = strlen( argv[0] );
02520 
02521     dbug_enter( "Openlink" );
02522 
02523 // Open fifo
02524 
02525     if ( ( c == 'f' ) && ( strncmp( argv[0], "fifo", length ) == 0 ) )
02526     {
02527         if ( argc < 1 )
02528         {
02529             Tcl_AppendResult( interp, "bad command -- must be: ",
02530                 "openlink fifo <pathname>",
02531                 (char *) NULL );
02532             return TCL_ERROR;
02533         }
02534         if ( ( iodev->fd = open( argv[1], O_RDONLY ) ) == -1 )
02535         {
02536             Tcl_AppendResult( interp, "cannot open fifo ", argv[1],
02537                 " for read", (char *) NULL );
02538             return TCL_ERROR;
02539         }
02540         iodev->type     = 0;
02541         iodev->typeName = "fifo";
02542         iodev->file     = fdopen( iodev->fd, "rb" );
02543     }
02544 
02545 // Open socket
02546 
02547     else if ( ( c == 's' ) && ( strncmp( argv[0], "socket", length ) == 0 ) )
02548     {
02549         if ( argc < 1 )
02550         {
02551             Tcl_AppendResult( interp, "bad command -- must be: ",
02552                 "openlink socket <sock-id>",
02553                 (char *) NULL );
02554             return TCL_ERROR;
02555         }
02556         iodev->type       = 1;
02557         iodev->typeName   = "socket";
02558         iodev->fileHandle = argv[1];
02559 
02560 #if TCL_MAJOR_VERSION < 7 || ( TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION == 4 )
02561 #define FILECAST
02562 #else
02563 #define FILECAST    ( ClientData )
02564 #endif
02565 
02566 // Exclude UNIX-only feature
02567 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
02568         if ( Tcl_GetOpenFile( interp, iodev->fileHandle,
02569                  0, 1, FILECAST & iodev->file ) != TCL_OK )
02570         {
02571             return TCL_ERROR;
02572         }
02573 #endif
02574         iodev->fd = fileno( iodev->file );
02575     }
02576 
02577 // unrecognized
02578 
02579     else
02580     {
02581         Tcl_AppendResult( interp, "bad option to \"openlink\": must be ",
02582             "fifo or socket", (char *) NULL );
02583 
02584         return TCL_ERROR;
02585     }
02586 
02587     plr->pdfs = pdf_bopen( NULL, 4200 );
02588 // Sheesh, what a mess.  I don't see how Tk4.1's converter macro could
02589 // possibly work.
02590 #if TK_MAJOR_VERSION < 4 ||                               \
02591     ( TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION == 0 ) || \
02592     TK_MAJOR_VERSION > 7
02593 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
02594     Tk_CreateFileHandler( iodev->fd, TK_READABLE, (Tk_FileProc *) ReadData,
02595         (ClientData) plFramePtr );
02596 #endif
02597 #else
02598 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
02599     Tcl_CreateFileHandler( Tcl_GetFile( (ClientData) iodev->fd, TCL_UNIX_FD ),
02600         TK_READABLE, (Tk_FileProc *) ReadData,
02601         (ClientData) plFramePtr );
02602 #endif
02603 #endif
02604 
02605     return TCL_OK;
02606 }
02607 
02608 //--------------------------------------------------------------------------
02609 // Closelink
02610 //
02611 // Processes "closelink" widget command.
02612 // CLoses channel previously opened with the "openlink" widget command.
02613 //--------------------------------------------------------------------------
02614 
02615 static int
02616 Closelink( Tcl_Interp *interp, register PlFrame *plFramePtr,
02617            int argc, const char **argv )
02618 {
02619     register PLRDev  *plr   = plFramePtr->plr;
02620     register PLiodev *iodev = plr->iodev;
02621 
02622     dbug_enter( "Closelink" );
02623 
02624     if ( iodev->fd == 0 )
02625     {
02626         Tcl_AppendResult( interp, "no link currently open", (char *) NULL );
02627         return TCL_ERROR;
02628     }
02629 
02630 #if TK_MAJOR_VERSION < 4 ||                               \
02631     ( TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION == 0 ) || \
02632     TK_MAJOR_VERSION > 7
02633 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
02634     Tk_DeleteFileHandler( iodev->fd );
02635 #endif
02636 #else
02637 //    Tk_DeleteFileHandler( iodev->file );
02638 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
02639     Tcl_DeleteFileHandler( Tcl_GetFile( (ClientData) iodev->fd,
02640             TCL_UNIX_FD ) );
02641 #endif
02642 #endif
02643     pdf_close( plr->pdfs );
02644     iodev->fd = 0;
02645 
02646     return TCL_OK;
02647 }
02648 
02649 //--------------------------------------------------------------------------
02650 // process_data
02651 //
02652 // Utility function for processing data and other housekeeping.
02653 //--------------------------------------------------------------------------
02654 
02655 static int
02656 process_data( Tcl_Interp *interp, register PlFrame *plFramePtr )
02657 {
02658     register PLRDev  *plr   = plFramePtr->plr;
02659     register PLiodev *iodev = plr->iodev;
02660     int result = TCL_OK;
02661 
02662 // Process data
02663 
02664     if ( plr_process( plr ) == -1 )
02665     {
02666         Tcl_AppendResult( interp, "unable to read from ", iodev->typeName,
02667             (char *) NULL );
02668         result = TCL_ERROR;
02669     }
02670 
02671 // Signal bop if necessary
02672 
02673     if ( plr->at_bop && plFramePtr->bopCmd != NULL )
02674     {
02675         plr->at_bop = 0;
02676         if ( Tcl_Eval( interp, plFramePtr->bopCmd ) != TCL_OK )
02677             fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
02678                 plFramePtr->bopCmd, interp->result );
02679     }
02680 
02681 // Signal eop if necessary
02682 
02683     if ( plr->at_eop && plFramePtr->eopCmd != NULL )
02684     {
02685         plr->at_eop = 0;
02686         if ( Tcl_Eval( interp, plFramePtr->eopCmd ) != TCL_OK )
02687             fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
02688                 plFramePtr->eopCmd, interp->result );
02689     }
02690 
02691     return result;
02692 }
02693 
02694 //--------------------------------------------------------------------------
02695 // ReadData
02696 //
02697 // Reads & processes data.
02698 // Intended to be installed as a filehandler command.
02699 //--------------------------------------------------------------------------
02700 
02701 static int
02702 ReadData( ClientData clientData, int mask )
02703 {
02704     register PlFrame    *plFramePtr = (PlFrame *) clientData;
02705     register Tcl_Interp *interp     = plFramePtr->interp;
02706 
02707     register PLRDev     *plr   = plFramePtr->plr;
02708     register PLiodev    *iodev = plr->iodev;
02709     register PDFstrm    *pdfs  = plr->pdfs;
02710     int result = TCL_OK;
02711 
02712     if ( mask & TK_READABLE )
02713     {
02714         // Read from FIFO or socket
02715 
02716         plsstrm( plFramePtr->ipls );
02717         if ( pl_PacketReceive( interp, iodev, pdfs ) )
02718         {
02719             Tcl_AppendResult( interp, "Packet receive failed:\n\t %s\n",
02720                 (char *) NULL );
02721             return TCL_ERROR;
02722         }
02723 
02724         // If the packet isn't complete it will be put back and we just return.
02725         // Otherwise, the buffer pointer is saved and then cleared so that reads
02726         // from the buffer start at the beginning.
02727         //
02728         if ( pdfs->bp == 0 )
02729             return TCL_OK;
02730 
02731         plr->nbytes = pdfs->bp;
02732         pdfs->bp    = 0;
02733         result      = process_data( interp, plFramePtr );
02734     }
02735 
02736     return result;
02737 }
02738 
02739 //--------------------------------------------------------------------------
02740 // Orient
02741 //
02742 // Processes "orient" widget command.
02743 // Handles orientation of plot.
02744 //--------------------------------------------------------------------------
02745 
02746 static int
02747 Orient( Tcl_Interp *interp, register PlFrame *plFramePtr,
02748         int argc, const char **argv )
02749 {
02750     int result = TCL_OK;
02751 
02752 // orient -- return orientation of current plot window
02753 
02754     plsstrm( plFramePtr->ipls );
02755 
02756     if ( argc == 0 )
02757     {
02758         PLFLT rot;
02759         char  result_str[128];
02760         plgdiori( &rot );
02761         sprintf( result_str, "%f", rot );
02762         Tcl_SetResult( interp, result_str, TCL_VOLATILE );
02763     }
02764 
02765 // orient <rot> -- Set orientation to <rot>
02766 
02767     else
02768     {
02769         plsdiori( atof( argv[0] ) );
02770         result = Redraw( interp, plFramePtr, argc - 1, argv + 1 );
02771     }
02772 
02773     return result;
02774 }
02775 
02776 //--------------------------------------------------------------------------
02777 // Print
02778 //
02779 // Processes "print" widget command.
02780 // Handles printing of plot, duh.
02781 //
02782 // Creates a temporary file, dumps the current plot to it in metafile
02783 // form, and then execs the "plpr" script to actually print it.  Since we
02784 // output it in metafile form here, plpr must invoke plrender to drive the
02785 // output to the appropriate file type.  The script is responsible for the
02786 // deletion of the plot metafile.
02787 //--------------------------------------------------------------------------
02788 
02789 static int
02790 Print( Tcl_Interp *interp, register PlFrame *plFramePtr,
02791        int argc, const char **argv )
02792 {
02793     PLINT ipls;
02794     int   result = TCL_OK;
02795     char  *sfnam;
02796     FILE  *sfile;
02797     pid_t pid;
02798 
02799 // Make sure widget has been initialized before going any further
02800 
02801     if ( !plFramePtr->tkwin_initted )
02802     {
02803         Tcl_AppendResult( interp, "Error -- widget not plotted to yet",
02804             (char *) NULL );
02805         return TCL_ERROR;
02806     }
02807 
02808 // Create stream for save
02809 
02810     plmkstrm( &ipls );
02811     if ( ipls < 0 )
02812     {
02813         Tcl_AppendResult( interp, "Error -- cannot create stream",
02814             (char *) NULL );
02815         return TCL_ERROR;
02816     }
02817 
02818 // Open file for writes
02819     sfnam = NULL;
02820 
02821     // Create and open temporary file
02822     if ( ( sfile = pl_create_tempfile( &sfnam ) ) == NULL )
02823     {
02824         Tcl_AppendResult( interp,
02825             "Error -- cannot open plot file for writing",
02826             (char *) NULL );
02827         plend1();
02828         if ( sfnam != NULL )
02829             free( sfnam );
02830         return TCL_ERROR;
02831     }
02832 
02833 // Initialize stream
02834 
02835     plsdev( "plmeta" );
02836     plsfile( sfile );
02837 // FIXME: plmeta/plrender need to honor these, needed to preserve the aspect ratio
02838     plspage( 0., 0., plFramePtr->width, plFramePtr->height, 0, 0 );
02839     plcpstrm( plFramePtr->ipls, 0 );
02840     pladv( 0 );
02841 
02842 // Remake current plot, close file, and switch back to original stream
02843 
02844     plreplot();
02845     plend1();
02846     plsstrm( plFramePtr->ipls );
02847 
02848 // So far so good.  Time to exec the print script.
02849 
02850     if ( plFramePtr->plpr_cmd == NULL )
02851         plFramePtr->plpr_cmd = plFindCommand( "plpr" );
02852 
02853     if ( ( plFramePtr->plpr_cmd == NULL ) || ( pid = fork() ) < 0 )
02854     {
02855         Tcl_AppendResult( interp,
02856             "Error -- cannot fork print process",
02857             (char *) NULL );
02858         result = TCL_ERROR;
02859     }
02860     else if ( pid == 0 )
02861     {
02862         if ( execl( plFramePtr->plpr_cmd, plFramePtr->plpr_cmd, sfnam,
02863                  (char *) 0 ) )
02864         {
02865             fprintf( stderr, "Unable to exec print command.\n" );
02866             free( sfnam );
02867             _exit( 1 );
02868         }
02869     }
02870 
02871     free( sfnam );
02872 
02873     return result;
02874 }
02875 
02876 //--------------------------------------------------------------------------
02877 // Page
02878 //
02879 // Processes "page" widget command.
02880 // Handles parameters such as margin, aspect ratio, and justification
02881 // of final plot.
02882 //--------------------------------------------------------------------------
02883 
02884 static int
02885 Page( Tcl_Interp *interp, register PlFrame *plFramePtr,
02886       int argc, const char **argv )
02887 {
02888 // page -- return current device window parameters
02889 
02890     plsstrm( plFramePtr->ipls );
02891 
02892     if ( argc == 0 )
02893     {
02894         PLFLT mar, aspect, jx, jy;
02895         char  result_str[128];
02896 
02897         plgdidev( &mar, &aspect, &jx, &jy );
02898         sprintf( result_str, "%g %g %g %g", mar, aspect, jx, jy );
02899         Tcl_SetResult( interp, result_str, TCL_VOLATILE );
02900         return TCL_OK;
02901     }
02902 
02903 // page <mar> <aspect> <jx> <jy> -- set up page
02904 
02905     if ( argc < 4 )
02906     {
02907         Tcl_AppendResult( interp, "wrong # args: should be \"",
02908             " page mar aspect jx jy\"", (char *) NULL );
02909         return TCL_ERROR;
02910     }
02911 
02912     plsdidev( atof( argv[0] ), atof( argv[1] ), atof( argv[2] ), atof( argv[3] ) );
02913     return ( Redraw( interp, plFramePtr, argc - 1, argv + 1 ) );
02914 }
02915 
02916 //--------------------------------------------------------------------------
02917 // Redraw
02918 //
02919 // Processes "redraw" widget command.
02920 // Turns loose a DoWhenIdle command to redraw plot by replaying contents
02921 // of plot buffer.
02922 //--------------------------------------------------------------------------
02923 
02924 static int
02925 Redraw( Tcl_Interp *interp, register PlFrame *plFramePtr,
02926         int argc, const char **argv )
02927 {
02928     dbug_enter( "Redraw" );
02929 
02930     plFramePtr->flags |= REDRAW_PENDING;
02931     if ( ( plFramePtr->tkwin != NULL ) &&
02932          !( plFramePtr->flags & REFRESH_PENDING ) )
02933     {
02934         Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
02935         plFramePtr->flags |= REFRESH_PENDING;
02936     }
02937 
02938     return TCL_OK;
02939 }
02940 
02941 //--------------------------------------------------------------------------
02942 // Save
02943 //
02944 // Processes "save" widget command.
02945 // Saves plot to a file.
02946 //--------------------------------------------------------------------------
02947 
02948 static int
02949 Save( Tcl_Interp *interp, register PlFrame *plFramePtr,
02950       int argc, const char **argv )
02951 {
02952     int  length;
02953     char c;
02954     FILE *sfile;
02955 
02956 // Make sure widget has been initialized before going any further
02957 
02958     if ( !plFramePtr->tkwin_initted )
02959     {
02960         Tcl_AppendResult( interp, "Error -- widget not plotted to yet",
02961             (char *) NULL );
02962         return TCL_ERROR;
02963     }
02964 
02965 // save -- save to already open file
02966 
02967     if ( argc == 0 )
02968     {
02969         if ( !plFramePtr->ipls_save )
02970         {
02971             Tcl_AppendResult( interp, "Error -- no current save file",
02972                 (char *) NULL );
02973             return TCL_ERROR;
02974         }
02975         plsstrm( plFramePtr->ipls_save );
02976         // Note: many drivers ignore these, needed to preserve the aspect ratio
02977         plspage( 0., 0., plFramePtr->width, plFramePtr->height, 0, 0 );
02978         plcpstrm( plFramePtr->ipls, 0 );
02979         pladv( 0 );
02980         plreplot();
02981         plflush();
02982         plsstrm( plFramePtr->ipls );
02983         return TCL_OK;
02984     }
02985 
02986     c      = argv[0][0];
02987     length = strlen( argv[0] );
02988 
02989 // save to specified device & file
02990 
02991     if ( ( c == 'a' ) && ( strncmp( argv[0], "as", length ) == 0 ) )
02992     {
02993         if ( argc < 3 )
02994         {
02995             Tcl_AppendResult( interp, "wrong # args: should be \"",
02996                 " save as device file\"", (char *) NULL );
02997             return TCL_ERROR;
02998         }
02999 
03000         // If save previously in effect, delete old stream
03001 
03002         if ( plFramePtr->ipls_save )
03003         {
03004             plsstrm( plFramePtr->ipls_save );
03005             plend1();
03006         }
03007 
03008         // Create stream for saves to selected device & file
03009 
03010         plmkstrm( &plFramePtr->ipls_save );
03011         if ( plFramePtr->ipls_save < 0 )
03012         {
03013             Tcl_AppendResult( interp, "Error -- cannot create stream",
03014                 (char *) NULL );
03015             plFramePtr->ipls_save = 0;
03016             return TCL_ERROR;
03017         }
03018 
03019         // Open file for writes
03020 
03021         if ( ( sfile = fopen( argv[2], "wb+" ) ) == NULL )
03022         {
03023             Tcl_AppendResult( interp, "Error -- cannot open file ", argv[2],
03024                 " for writing", (char *) NULL );
03025             plFramePtr->ipls_save = 0;
03026             plend1();
03027             return TCL_ERROR;
03028         }
03029 
03030         // Initialize stream
03031 
03032         plsdev( argv[1] );
03033         plsfile( sfile );
03034         // Note: many drivers ignore these, needed to preserve the aspect ratio
03035         plspage( 0., 0., plFramePtr->width, plFramePtr->height, 0, 0 );
03036         plcpstrm( plFramePtr->ipls, 0 );
03037         pladv( 0 );
03038 
03039         // Remake current plot and then switch back to original stream
03040 
03041         plreplot();
03042         plflush();
03043         plsstrm( plFramePtr->ipls );
03044     }
03045 
03046 // close save file
03047 
03048     else if ( ( c == 'c' ) && ( strncmp( argv[0], "close", length ) == 0 ) )
03049     {
03050         if ( !plFramePtr->ipls_save )
03051         {
03052             Tcl_AppendResult( interp, "Error -- no current save file",
03053                 (char *) NULL );
03054             return TCL_ERROR;
03055         }
03056         else
03057         {
03058             plsstrm( plFramePtr->ipls_save );
03059             plend1();
03060             plFramePtr->ipls_save = 0;
03061             plsstrm( plFramePtr->ipls );
03062         }
03063     }
03064 
03065 // unrecognized
03066 
03067     else
03068     {
03069         Tcl_AppendResult( interp, "bad option to \"save\": must be ",
03070             "as or close", (char *) NULL );
03071 
03072         return TCL_ERROR;
03073     }
03074 
03075     return TCL_OK;
03076 }
03077 
03078 //--------------------------------------------------------------------------
03079 // View
03080 //
03081 // Processes "view" widget command.
03082 // Handles translation & scaling of view into plot.
03083 //--------------------------------------------------------------------------
03084 
03085 static int
03086 View( Tcl_Interp *interp, register PlFrame *plFramePtr,
03087       int argc, const char **argv )
03088 {
03089     int   length;
03090     char  c;
03091     PLFLT xl, xr, yl, yr;
03092 
03093 // view -- return current relative plot window coordinates
03094 
03095     plsstrm( plFramePtr->ipls );
03096 
03097     if ( argc == 0 )
03098     {
03099         char result_str[128];
03100         plgdiplt( &xl, &yl, &xr, &yr );
03101         sprintf( result_str, "%g %g %g %g", xl, yl, xr, yr );
03102         Tcl_SetResult( interp, result_str, TCL_VOLATILE );
03103         return TCL_OK;
03104     }
03105 
03106     c      = argv[0][0];
03107     length = strlen( argv[0] );
03108 
03109 // view bounds -- return relative device coordinates of bounds on current
03110 // plot window
03111 
03112     if ( ( c == 'b' ) && ( strncmp( argv[0], "bounds", length ) == 0 ) )
03113     {
03114         char result_str[128];
03115         xl = 0.; yl = 0.;
03116         xr = 1.; yr = 1.;
03117         pldip2dc( &xl, &yl, &xr, &yr );
03118         sprintf( result_str, "%g %g %g %g", xl, yl, xr, yr );
03119         Tcl_SetResult( interp, result_str, TCL_VOLATILE );
03120         return TCL_OK;
03121     }
03122 
03123 // view reset -- Resets plot
03124 
03125     if ( ( c == 'r' ) && ( strncmp( argv[0], "reset", length ) == 0 ) )
03126     {
03127         xl = 0.; yl = 0.;
03128         xr = 1.; yr = 1.;
03129         plsdiplt( xl, yl, xr, yr );
03130     }
03131 
03132 // view select -- set window into plot space
03133 // Specifies in terms of plot window coordinates, not device coordinates
03134 
03135     else if ( ( c == 's' ) && ( strncmp( argv[0], "select", length ) == 0 ) )
03136     {
03137         if ( argc < 5 )
03138         {
03139             Tcl_AppendResult( interp, "wrong # args: should be \"",
03140                 " view select xmin ymin xmax ymax\"",
03141                 (char *) NULL );
03142             return TCL_ERROR;
03143         }
03144         else
03145         {
03146             gbox( &xl, &yl, &xr, &yr, argv + 1 );
03147             plsdiplt( xl, yl, xr, yr );
03148         }
03149     }
03150 
03151 // view zoom -- set window into plot space incrementally (zoom)
03152 // Here we need to take the page (device) offsets into account
03153 
03154     else if ( ( c == 'z' ) && ( strncmp( argv[0], "zoom", length ) == 0 ) )
03155     {
03156         if ( argc < 5 )
03157         {
03158             Tcl_AppendResult( interp, "wrong # args: should be \"",
03159                 " view zoom xmin ymin xmax ymax\"",
03160                 (char *) NULL );
03161             return TCL_ERROR;
03162         }
03163         else
03164         {
03165             gbox( &xl, &yl, &xr, &yr, argv + 1 );
03166             pldid2pc( &xl, &yl, &xr, &yr );
03167             plsdiplz( xl, yl, xr, yr );
03168         }
03169     }
03170 
03171 // unrecognized
03172 
03173     else
03174     {
03175         Tcl_AppendResult( interp, "bad option \"", argv[1],
03176             "\":  options to \"view\" are: bounds, reset, select, or zoom",
03177             (char *) NULL );
03178 
03179         return TCL_ERROR;
03180     }
03181 
03182 // Update plot window bounds and arrange for plot to be updated
03183 
03184     plgdiplt( &xl, &yl, &xr, &yr );
03185     plFramePtr->xl     = xl;
03186     plFramePtr->yl     = yl;
03187     plFramePtr->xr     = xr;
03188     plFramePtr->yr     = yr;
03189     plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
03190 
03191     return ( Redraw( interp, plFramePtr, argc, argv ) );
03192 }
03193 
03194 //--------------------------------------------------------------------------
03195 // xScroll
03196 //
03197 // Processes "xscroll" widget command.
03198 // Handles horizontal scroll-bar invoked translation of view into plot.
03199 //--------------------------------------------------------------------------
03200 
03201 static int
03202 xScroll( Tcl_Interp *interp, register PlFrame *plFramePtr,
03203          int argc, const char **argv )
03204 {
03205     int   x0, width = Tk_Width( plFramePtr->tkwin );
03206     PLFLT xl, xr, yl, yr, xlen;
03207 
03208     plsstrm( plFramePtr->ipls );
03209 
03210     xlen = plFramePtr->xr - plFramePtr->xl;
03211     x0   = atoi( argv[0] );
03212     xl   = x0 / (double) width;
03213     xl   = MAX( 0., MIN( ( 1. - xlen ), xl ) );
03214     xr   = xl + xlen;
03215 
03216     yl = plFramePtr->yl;
03217     yr = plFramePtr->yr;
03218 
03219     plFramePtr->xl = xl;
03220     plFramePtr->xr = xr;
03221 
03222     plsdiplt( xl, yl, xr, yr );
03223 
03224     plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
03225     return ( Redraw( interp, plFramePtr, argc, argv ) );
03226 }
03227 
03228 //--------------------------------------------------------------------------
03229 // yScroll
03230 //
03231 // Processes "yscroll" widget command.
03232 // Handles vertical scroll-bar invoked translation of view into plot.
03233 //--------------------------------------------------------------------------
03234 
03235 static int
03236 yScroll( Tcl_Interp *interp, register PlFrame *plFramePtr,
03237          int argc, const char **argv )
03238 {
03239     int   y0, height = Tk_Height( plFramePtr->tkwin );
03240     PLFLT xl, xr, yl, yr, ylen;
03241 
03242     plsstrm( plFramePtr->ipls );
03243 
03244     ylen = plFramePtr->yr - plFramePtr->yl;
03245     y0   = atoi( argv[0] );
03246     yr   = 1. - y0 / (double) height;
03247     yr   = MAX( 0. + ylen, MIN( 1., yr ) );
03248     yl   = yr - ylen;
03249 
03250     xl = plFramePtr->xl;
03251     xr = plFramePtr->xr;
03252 
03253     plFramePtr->yl = yl;
03254     plFramePtr->yr = yr;
03255 
03256     plsdiplt( xl, yl, xr, yr );
03257 
03258     plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
03259     return ( Redraw( interp, plFramePtr, argc, argv ) );
03260 }
03261 
03262 //--------------------------------------------------------------------------
03263 // report
03264 //
03265 // 4/17/95 GMF
03266 // Processes "report" widget command.
03267 //--------------------------------------------------------------------------
03268 
03269 static int
03270 report( Tcl_Interp *interp, register PlFrame *plFramePtr,
03271         int argc, const char **argv )
03272 {
03273     PLFLT x, y;
03274 //    fprintf( stdout, "Made it into report, argc=%d\n", argc );
03275 
03276     if ( argc == 0 )
03277     {
03278         interp->result = "report what?";
03279         return TCL_ERROR;
03280     }
03281 
03282     if ( !strcmp( argv[0], "wc" ) )
03283     {
03284         XwDev        *dev = (XwDev *) plFramePtr->pls->dev;
03285         PLGraphicsIn *gin = &( dev->gin );
03286 
03287         if ( argc != 3 )
03288         {
03289             interp->result = "Wrong # of args: report wc x y";
03290             return TCL_ERROR;
03291         }
03292 
03293         x = atof( argv[1] );
03294         y = atof( argv[2] );
03295 
03296         gin->dX = (PLFLT) x / ( dev->width - 1 );
03297         gin->dY = 1.0 - (PLFLT) y / ( dev->height - 1 );
03298 
03299         // Try to locate cursor
03300 
03301         if ( plTranslateCursor( gin ) )
03302         {
03303             sprintf( interp->result, "%f %f", gin->wX, gin->wY );
03304             return TCL_OK;
03305         }
03306 
03307         interp->result = "Cannot locate";
03308         return TCL_OK;
03309     }
03310 
03311     interp->result = "nonsensical request.";
03312     return TCL_ERROR;
03313 }
03314 
03315 //--------------------------------------------------------------------------
03316 // Custom bop handler.
03317 // Mostly for support of multi-page Tcl scripts from plserver.
03318 //--------------------------------------------------------------------------
03319 
03320 static void
03321 process_bop( void *clientData, int *skip_driver_bop )
03322 {
03323     register PlFrame *plFramePtr = (PlFrame *) clientData;
03324 
03325     if ( Tcl_Eval( plFramePtr->interp, plFramePtr->bopCmd ) != TCL_OK )
03326         fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
03327             plFramePtr->bopCmd, plFramePtr->interp->result );
03328 }
03329 
03330 //--------------------------------------------------------------------------
03331 // Custom eop handler.
03332 // Mostly for support of multi-page Tcl scripts from plserver.
03333 //--------------------------------------------------------------------------
03334 
03335 static void
03336 process_eop( void *clientData, int *skip_driver_eop )
03337 {
03338     register PlFrame *plFramePtr = (PlFrame *) clientData;
03339 
03340     if ( Tcl_Eval( plFramePtr->interp, plFramePtr->eopCmd ) != TCL_OK )
03341         fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
03342             plFramePtr->eopCmd, plFramePtr->interp->result );
03343 }
03344 
03345 //--------------------------------------------------------------------------
03346 // Utility routines
03347 //--------------------------------------------------------------------------
03348 
03349 //--------------------------------------------------------------------------
03350 // UpdateVScrollbar
03351 //
03352 // Updates vertical scrollbar if needed.
03353 //--------------------------------------------------------------------------
03354 
03355 static void
03356 UpdateVScrollbar( register PlFrame *plFramePtr )
03357 {
03358     int  height = Tk_Height( plFramePtr->tkwin );
03359     char string[60];
03360     int  totalUnits, windowUnits, firstUnit, lastUnit, result;
03361 
03362     if ( plFramePtr->yScrollCmd == NULL )
03363         return;
03364 
03365     totalUnits  = height;
03366     firstUnit   = 0.5 + (PLFLT) height * ( 1. - plFramePtr->yr );
03367     lastUnit    = 0.5 + (PLFLT) height * ( 1. - plFramePtr->yl );
03368     windowUnits = lastUnit - firstUnit;
03369     sprintf( string, " %d %d %d %d",
03370         totalUnits, windowUnits, firstUnit, lastUnit );
03371 
03372     result = Tcl_VarEval( plFramePtr->interp, plFramePtr->yScrollCmd, string,
03373         (char *) NULL );
03374 
03375     if ( result != TCL_OK )
03376     {
03377         Tk_BackgroundError( plFramePtr->interp );
03378     }
03379 }
03380 
03381 //--------------------------------------------------------------------------
03382 // UpdateHScrollbar
03383 //
03384 // Updates horizontal scrollbar if needed.
03385 //--------------------------------------------------------------------------
03386 
03387 static void
03388 UpdateHScrollbar( register PlFrame *plFramePtr )
03389 {
03390     int  width = Tk_Width( plFramePtr->tkwin );
03391     char string[60];
03392     int  totalUnits, windowUnits, firstUnit, lastUnit, result;
03393 
03394     if ( plFramePtr->xScrollCmd == NULL )
03395         return;
03396 
03397     totalUnits  = width;
03398     firstUnit   = 0.5 + (PLFLT) width * plFramePtr->xl;
03399     lastUnit    = 0.5 + (PLFLT) width * plFramePtr->xr;
03400     windowUnits = lastUnit - firstUnit;
03401     sprintf( string, " %d %d %d %d",
03402         totalUnits, windowUnits, firstUnit, lastUnit );
03403 
03404     result = Tcl_VarEval( plFramePtr->interp, plFramePtr->xScrollCmd, string,
03405         (char *) NULL );
03406 
03407     if ( result != TCL_OK )
03408     {
03409         Tk_BackgroundError( plFramePtr->interp );
03410     }
03411 }
03412 
03413 //--------------------------------------------------------------------------
03414 // gbox
03415 //
03416 // Returns selection box coordinates.  It's best if the TCL script does
03417 // bounds checking on the input but I do it here as well just to be safe.
03418 //--------------------------------------------------------------------------
03419 
03420 static void
03421 gbox( PLFLT *xl, PLFLT *yl, PLFLT *xr, PLFLT *yr, const char **argv )
03422 {
03423     PLFLT x0, y0, x1, y1;
03424 
03425     x0 = atof( argv[0] );
03426     y0 = atof( argv[1] );
03427     x1 = atof( argv[2] );
03428     y1 = atof( argv[3] );
03429 
03430     x0 = MAX( 0., MIN( 1., x0 ) );
03431     y0 = MAX( 0., MIN( 1., y0 ) );
03432     x1 = MAX( 0., MIN( 1., x1 ) );
03433     y1 = MAX( 0., MIN( 1., y1 ) );
03434 
03435 // Only need two vertices, pick the lower left and upper right
03436 
03437     *xl = MIN( x0, x1 );
03438     *yl = MIN( y0, y1 );
03439     *xr = MAX( x0, x1 );
03440     *yr = MAX( y0, y1 );
03441 }

Generated on Wed Oct 12 2011 20:42:22 for PLplot by  doxygen 1.7.1