PLplot  5.9.9
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plframe.c
Go to the documentation of this file.
1 // $Id: plframe.c 12210 2012-08-13 22:14:23Z andrewross $
2 //
3 // Copyright 1993, 1994, 1995
4 // Maurice LeBrun mjl@dino.ph.utexas.edu
5 // Institute for Fusion Studies University of Texas at Austin
6 //
7 // Copyright (C) 2004 Joao Cardoso
8 // Copyright (C) 2004 Andrew Ross
9 //
10 // This file is part of PLplot.
11 //
12 // PLplot is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU Library General Public License as published
14 // by the Free Software Foundation; either version 2 of the License, or
15 // (at your option) any later version.
16 //
17 // PLplot is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU Library General Public License for more details.
21 //
22 // You should have received a copy of the GNU Library General Public License
23 // along with PLplot; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 //
26 //
27 // Based upon tkFrame.c from the TK 3.2 distribution:
28 //
29 // Copyright 1990 Regents of the University of California.
30 // Permission to use, copy, modify, and distribute this
31 // software and its documentation for any purpose and without
32 // fee is hereby granted, provided that the above copyright
33 // notice appear in all copies. The University of California
34 // makes no representations about the suitability of this
35 // software for any purpose. It is provided "as is" without
36 // express or implied warranty.
37 //
38 //--------------------------------------------------------------------------
39 //
40 // This module implements "plframe" widgets for the Tk toolkit. These are
41 // frames that have extra logic to allow them to be interfaced with the
42 // PLplot X driver. These are then drawn into and respond to keyboard and
43 // mouse events.
44 //
45 //
46 // #define DEBUG_ENTER
47 // #define DEBUG
48 //
49 
50 #define DEBUGx
51 
52 #define NEED_PLDEBUG
53 #include "plserver.h"
54 #include "plxwd.h"
55 #include "tcpip.h"
56 
57 #ifdef PL_HAVE_UNISTD_H
58 #include <unistd.h>
59 #endif
60 #include <fcntl.h>
61 
62 #undef HAVE_ITCL
63 
64 #define NDEV 100 // Max number of output device types in menu
65 
66 // If set, BUFFER_FIFO causes FIFO i/o to be buffered
67 
68 #define BUFFER_FIFO 1
69 
70 // If set, causes a file handler to be used with FIFO
71 
72 #define FH_FIFO 0
73 
74 // A handy command wrapper
75 
76 #define plframe_cmd( code ) \
77  if ( ( code ) == TCL_ERROR ) return ( TCL_ERROR );
78 
79 // Backward compatibility junk
80 
81 #if TCL_MAJOR_VERSION <= 7 && TCL_MINOR_VERSION <= 4
82 #define Tk_Cursor Cursor
83 #endif
84 
85 //
86 // A data structure of the following type is kept for each
87 // plframe that currently exists for this process:
88 //
89 
90 typedef struct
91 {
92 // This is stuff taken from tkFrame.c
93 
94  Tk_Window tkwin; // Window that embodies the frame. NULL
95  // means that the window has been destroyed
96  // but the data structures haven't yet been
97  // cleaned up.
98  Display *display; // Display containing widget. Used, among
99  // other things, so that resources can be
100  // freed even after tkwin has gone away.
101  Tcl_Interp *interp; // Interpreter associated with
102  // widget. Used to delete widget
103  // command.
104 #ifdef HAVE_ITCL
105  Tcl_Command widgetCmd; // Token for frame's widget command.
106 #endif
107  Tk_3DBorder border; // Structure used to draw 3-D border and
108  // background.
109  int borderWidth; // Width of 3-D border (if any).
110  int relief; // 3-d effect: TK_RELIEF_RAISED etc.
111  int width; // Width to request for window. <= 0 means
112  // don't request any size.
113  int height; // Height to request for window. <= 0 means
114  // don't request any size.
115  Tk_Cursor cursor; // Current cursor for window, or None.
116  int flags; // Various flags; see below for
117  // definitions.
118 
119 // These are new to plframe widgets
120 
121 // control stuff
122 
123  int tkwin_initted; // Set first time widget is mapped
124  PLStream *pls; // PLplot stream pointer
125  PLINT ipls; // PLplot stream number
126  PLINT ipls_save; // PLplot stream number, save files
127 
128  PLRDev *plr; // Renderer state information. Malloc'ed
129  XColor *bgColor; // Background color
130  char *plpr_cmd; // Holds print command name. Malloc'ed
131 
132 // Used to handle resize and expose events
133 
134  PLDisplay pldis; // Info about the display window
135  int prevWidth; // Previous window width
136  int prevHeight; // Previous window height
137 
138 // Support for save operations
139 
140  char *SaveFnam; // File name we are currently saving to.
141  // Malloc'ed.
142  char **devDesc; // Descriptive names for file-oriented
143  // devices. Malloc'ed.
144  char **devName; // Keyword names of file-oriented devices.
145  // Malloc'ed.
146 
147 // Used in selecting & modifying plot or device area
148 
149  GC xorGC; // GC used for rubber-band drawing
150  XPoint pts[5]; // Points for rubber-band drawing
151  int continue_draw; // Set when doing rubber-band draws
152  Tk_Cursor xhair_cursor; // cursor used for drawing
153  PLFLT xl, xr, yl, yr; // Bounds on plot viewing area
154  char *xScrollCmd; // Command prefix for communicating with
155  // horizontal scrollbar. NULL means no
156  // command to issue. Malloc'ed.
157  char *yScrollCmd; // Command prefix for communicating with
158  // vertical scrollbar. NULL means no
159  // command to issue. Malloc'ed.
160 
161 // Used for flashing bop or eop condition
162 
163  char *bopCmd; // Proc to call at bop
164  char *eopCmd; // Proc to call at eop
165 
166 // Used for drawing graphic crosshairs
167 
168  int xhairs; // Configuration option to turn on xhairs
169  int drawing_xhairs; // Set if we are currently drawing xhairs
170  XPoint xhair_x[2]; // Points for horizontal xhair line
171  XPoint xhair_y[2]; // Points for vertical xhair line
172 
173 // Used for drawing a rubber band lilne segment
174 
175  int rband; // Configuration option to turn on rband
176  int drawing_rband; // See if we are currently drawing rband
177  XPoint rband_pt[2]; // Ends of rubber band line
178 } PlFrame;
179 
180 //
181 // Flag bits for plframes:
182 //
183 // REFRESH_PENDING: Non-zero means a DoWhenIdle handler
184 // has already been queued to refresh
185 // this window.
186 // RESIZE_PENDING; Used to reschedule resize events
187 // REDRAW_PENDING; Used to redraw contents of plot buffer
188 // UPDATE_V_SCROLLBAR: Non-zero means vertical scrollbar needs
189 // to be updated.
190 // UPDATE_H_SCROLLBAR: Non-zero means horizontal scrollbar needs
191 // to be updated.
192 //
193 
194 #define REFRESH_PENDING 1
195 #define RESIZE_PENDING 2
196 #define REDRAW_PENDING 4
197 #define UPDATE_V_SCROLLBAR 8
198 #define UPDATE_H_SCROLLBAR 16
199 
200 // Defaults for plframes:
201 
202 #define DEF_PLFRAME_BG_COLOR "Black"
203 #define DEF_PLFRAME_BG_MONO "White"
204 #define DEF_PLFRAME_BORDER_WIDTH "0"
205 #define DEF_PLFRAME_CURSOR ( (char *) NULL )
206 #define DEF_PLFRAME_HEIGHT "0"
207 #define DEF_PLFRAME_RELIEF "flat"
208 #define DEF_PLFRAME_WIDTH "0"
209 
210 // Configuration info
211 
212 static Tk_ConfigSpec configSpecs[] = {
213  { TK_CONFIG_BORDER, "-background", "background", "Background",
214  DEF_PLFRAME_BG_COLOR, Tk_Offset( PlFrame, border ),
215  TK_CONFIG_COLOR_ONLY, NULL },
216 //
217 // {TK_CONFIG_COLOR, (char *) NULL, (char *) NULL, (char *) NULL,
218 // (char *) NULL, Tk_Offset(PlFrame, bgColor),
219 // TK_CONFIG_COLOR_ONLY},
220 //
221 #ifndef MAC_TCL
222  { TK_CONFIG_COLOR, "-plbg", "plbackground", "Plbackground",
223  DEF_PLFRAME_BG_COLOR, Tk_Offset( PlFrame, bgColor ),
224  TK_CONFIG_COLOR_ONLY, NULL },
225 #endif
226  { TK_CONFIG_BORDER, "-background", "background", "Background",
227  DEF_PLFRAME_BG_MONO, Tk_Offset( PlFrame, border ),
228  TK_CONFIG_MONO_ONLY, NULL },
229 //
230 // {TK_CONFIG_COLOR, (char *) NULL, (char *) NULL, (char *) NULL,
231 // (char *) NULL, Tk_Offset(PlFrame, bgColor),
232 // TK_CONFIG_MONO_ONLY},
233 //
234 #ifndef MAC_TCL
235  { TK_CONFIG_COLOR, "-plbg", (char *) NULL, (char *) NULL,
236  DEF_PLFRAME_BG_MONO, Tk_Offset( PlFrame, bgColor ),
237  TK_CONFIG_MONO_ONLY, NULL },
238 #endif
239  { TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
240  (char *) NULL, 0, 0, NULL },
241  { TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
242  (char *) NULL, 0, 0, NULL },
243  { TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
244  DEF_PLFRAME_BORDER_WIDTH, Tk_Offset( PlFrame, borderWidth ), 0, NULL },
245  { TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
246  DEF_PLFRAME_CURSOR, Tk_Offset( PlFrame, cursor ), TK_CONFIG_NULL_OK, NULL },
247  { TK_CONFIG_STRING, "-bopcmd", "bopcmd", "PgCommand",
248  (char *) NULL, Tk_Offset( PlFrame, bopCmd ), TK_CONFIG_NULL_OK, NULL },
249  { TK_CONFIG_STRING, "-eopcmd", "eopcmd", "PgCommand",
250  (char *) NULL, Tk_Offset( PlFrame, eopCmd ), TK_CONFIG_NULL_OK, NULL },
251  { TK_CONFIG_PIXELS, "-height", "height", "Height",
252  DEF_PLFRAME_HEIGHT, Tk_Offset( PlFrame, height ), 0, NULL },
253  { TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
254  DEF_PLFRAME_RELIEF, Tk_Offset( PlFrame, relief ), 0, NULL },
255  { TK_CONFIG_PIXELS, "-width", "width", "Width",
256  DEF_PLFRAME_WIDTH, Tk_Offset( PlFrame, width ), 0, NULL },
257  { TK_CONFIG_BOOLEAN, "-xhairs", (char *) NULL, (char *) NULL,
258  "0", Tk_Offset( PlFrame, xhairs ), TK_CONFIG_DONT_SET_DEFAULT, NULL },
259  { TK_CONFIG_BOOLEAN, "-rubberband", (char *) NULL, (char *) NULL,
260  "0", Tk_Offset( PlFrame, rband ), TK_CONFIG_DONT_SET_DEFAULT, NULL },
261  { TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
262  (char *) NULL, Tk_Offset( PlFrame, xScrollCmd ), TK_CONFIG_NULL_OK, NULL },
263  { TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
264  (char *) NULL, Tk_Offset( PlFrame, yScrollCmd ), TK_CONFIG_NULL_OK, NULL },
265  { TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
266  (char *) NULL, 0, 0, NULL }
267 };
268 
269 // Forward declarations for procedures defined later in this file:
270 
271 // Externals
272 
273 int plFrameCmd( ClientData, Tcl_Interp *, int, const char ** );
274 
275 // These are invoked by the TK dispatcher
276 
277 #if TK_MAJOR_VERSION < 4 || ( TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION == 0 )
278 #define FreeProcArg ClientData
279 #else
280 #define FreeProcArg char *
281 #endif
282 
283 static void DestroyPlFrame( FreeProcArg );
284 static void DisplayPlFrame( ClientData );
285 static void PlFrameInit( ClientData );
286 static void PlFrameConfigureEH( ClientData, XEvent * );
287 static void PlFrameExposeEH( ClientData, XEvent * );
288 static void PlFrameMotionEH( ClientData, register XEvent * );
289 static void PlFrameEnterEH( ClientData, register XEvent * );
290 static void PlFrameLeaveEH( ClientData, register XEvent * );
291 static void PlFrameKeyEH( ClientData, register XEvent * );
292 static int PlFrameWidgetCmd( ClientData, Tcl_Interp *, int, const char ** );
293 static int ReadData( ClientData, int );
294 static void Install_cmap( PlFrame *plFramePtr );
295 
296 // These are invoked by PlFrameWidgetCmd to process widget commands
297 
298 static int Closelink( Tcl_Interp *, PlFrame *, int, const char ** );
299 static int Cmd( Tcl_Interp *, PlFrame *, int, const char ** );
300 static int ColorManip( Tcl_Interp *, PlFrame *, int, const char ** );
301 static int ConfigurePlFrame( Tcl_Interp *, PlFrame *, int, const char **, int );
302 static int Draw( Tcl_Interp *, PlFrame *, int, const char ** );
303 static int Info( Tcl_Interp *, PlFrame *, int, const char ** );
304 static int Openlink( Tcl_Interp *, PlFrame *, int, const char ** );
305 static int Orient( Tcl_Interp *, PlFrame *, int, const char ** );
306 static int Page( Tcl_Interp *, PlFrame *, int, const char ** );
307 static int Print( Tcl_Interp *, PlFrame *, int, const char ** );
308 static int Redraw( Tcl_Interp *, PlFrame *, int, const char ** );
309 static int Save( Tcl_Interp *, PlFrame *, int, const char ** );
310 static int View( Tcl_Interp *, PlFrame *, int, const char ** );
311 static int xScroll( Tcl_Interp *, PlFrame *, int, const char ** );
312 static int yScroll( Tcl_Interp *, PlFrame *, int, const char ** );
313 static int report( Tcl_Interp *, PlFrame *, int, const char ** );
314 
315 // Routines for manipulating graphic crosshairs
316 
317 static void CreateXhairs( PlFrame * );
318 static void DestroyXhairs( PlFrame * );
319 static void DrawXhairs( PlFrame *, int, int );
320 static void UpdateXhairs( PlFrame * );
321 
322 // Routines for manipulating the rubberband line
323 
324 static void CreateRband( PlFrame * );
325 static void DestroyRband( PlFrame * );
326 static void DrawRband( PlFrame *, int, int );
327 static void UpdateRband( PlFrame * );
328 
329 // Callbacks from plplot library
330 
331 static void process_bop( void *, int * );
332 static void process_eop( void *, int * );
333 
334 // Utility routines
335 
336 static void gbox( PLFLT *, PLFLT *, PLFLT *, PLFLT *, const char ** );
337 static void UpdateVScrollbar( register PlFrame * );
338 static void UpdateHScrollbar( register PlFrame * );
339 
340 //
341 //--------------------------------------------------------------------------
342 //
343 // plFrameCmd --
344 //
345 // This procedure is invoked to process the "plframe" Tcl
346 // command. See the user documentation for details on what it
347 // does.
348 //
349 // Results:
350 // A standard Tcl result.
351 //
352 // Side effects:
353 // See the user documentation.
354 //
355 //--------------------------------------------------------------------------
356 //
357 
358 int
359 plFrameCmd( ClientData PL_UNUSED( clientData ), Tcl_Interp *interp,
360  int argc, const char **argv )
361 {
362  Tk_Window new;
363  register PlFrame *plFramePtr;
364  register PLRDev *plr;
365  int i, ndev;
366 
367  dbug_enter( "plFrameCmd" );
368 
369  if ( argc < 2 )
370  {
371  Tcl_AppendResult( interp, "wrong # args: should be \"",
372  argv[0], " pathName ?options?\"", (char *) NULL );
373  return TCL_ERROR;
374  }
375 
376 // Create the window.
377 
378  new = Tk_CreateWindowFromPath( interp, Tk_MainWindow( interp ),
379  argv[1], (char *) NULL );
380  if ( new == NULL )
381  {
382  return TCL_ERROR;
383  }
384 
385  plFramePtr = (PlFrame *) ckalloc( sizeof ( PlFrame ) );
386  plFramePtr->tkwin = new;
387  plFramePtr->display = Tk_Display( new );
388  plFramePtr->interp = interp;
389  plFramePtr->xorGC = NULL;
390  plFramePtr->border = NULL;
391  plFramePtr->cursor = None;
392  plFramePtr->xhair_cursor = None;
393  plFramePtr->flags = 0;
394  plFramePtr->width = Tk_Width( plFramePtr->tkwin );
395  plFramePtr->height = Tk_Height( plFramePtr->tkwin );
396  plFramePtr->prevWidth = 0;
397  plFramePtr->prevHeight = 0;
398  plFramePtr->continue_draw = 0;
399  plFramePtr->ipls = 0;
400  plFramePtr->ipls_save = 0;
401  plFramePtr->tkwin_initted = 0;
402  plFramePtr->bgColor = NULL;
403  plFramePtr->plpr_cmd = NULL;
404  plFramePtr->bopCmd = NULL;
405  plFramePtr->eopCmd = NULL;
406  plFramePtr->xhairs = 0;
407  plFramePtr->drawing_xhairs = 0;
408  plFramePtr->rband = 0;
409  plFramePtr->drawing_rband = 0;
410  plFramePtr->xScrollCmd = NULL;
411  plFramePtr->yScrollCmd = NULL;
412  plFramePtr->xl = 0.;
413  plFramePtr->yl = 0.;
414  plFramePtr->xr = 1.;
415  plFramePtr->yr = 1.;
416  plFramePtr->SaveFnam = NULL;
417  plFramePtr->pldis.x = 0;
418  plFramePtr->pldis.y = 0;
419  plFramePtr->pldis.width = 0;
420  plFramePtr->pldis.height = 0;
421 
422  plFramePtr->plr = (PLRDev *) ckalloc( sizeof ( PLRDev ) );
423  plr = plFramePtr->plr;
424  plr->pdfs = NULL;
425  plr->at_bop = 0;
426  plr->at_eop = 0;
427  plr->iodev = (PLiodev *) ckalloc( sizeof ( PLiodev ) );
428  plr_start( plr );
429 
430 // Associate new PLplot stream with this widget
431 
432  plmkstrm( &plFramePtr->ipls );
433  plgpls( &plFramePtr->pls );
434 
435 // Set up stuff for rubber-band drawing
436 
437  plFramePtr->xhair_cursor =
438  Tk_GetCursor( plFramePtr->interp, plFramePtr->tkwin, "crosshair" );
439 
440 // Partially initialize X driver.
441 
442  pllib_init();
443 
444  plsdev( "xwin" );
445  pllib_devinit();
446  plP_esc( PLESC_DEVINIT, NULL );
447 
448 // Create list of valid device names and keywords for page dumps
449 
450  plFramePtr->devDesc = (char **) ckalloc( NDEV * sizeof ( char ** ) );
451  plFramePtr->devName = (char **) ckalloc( NDEV * sizeof ( char ** ) );
452  for ( i = 0; i < NDEV; i++ )
453  {
454  plFramePtr->devDesc[i] = NULL;
455  plFramePtr->devName[i] = NULL;
456  }
457  ndev = NDEV;
458  plgFileDevs( (const char ***) &plFramePtr->devDesc, (const char ***) &plFramePtr->devName, &ndev );
459 
460 // Start up event handlers and other good stuff
461 
462  Tk_SetClass( new, "Plframe" );
463 
464  Tk_CreateEventHandler( plFramePtr->tkwin, StructureNotifyMask,
465  PlFrameConfigureEH, (ClientData) plFramePtr );
466 
467  Tk_CreateEventHandler( plFramePtr->tkwin, ExposureMask,
468  PlFrameExposeEH, (ClientData) plFramePtr );
469 
470 #ifdef HAVE_ITCL
471  plFramePtr->widgetCmd =
472 #endif
473  Tcl_CreateCommand( interp, Tk_PathName( plFramePtr->tkwin ),
474  (Tcl_CmdProc *) PlFrameWidgetCmd, (ClientData) plFramePtr, (Tcl_CmdDeleteProc *) NULL );
475 #ifdef HAVE_ITCL
476  Itk_SetWidgetCommand( plFramePtr->tkwin, plFramePtr->widgetCmd );
477 #endif
478 
479  if ( ConfigurePlFrame( interp, plFramePtr, argc - 2, argv + 2, 0 ) != TCL_OK )
480  {
481 #ifdef HAVE_ITCL
482  Itk_SetWidgetCommand( plFramePtr->tkwin, (Tcl_Command) NULL );
483 #endif
484  Tk_DestroyWindow( plFramePtr->tkwin );
485  return TCL_ERROR;
486  }
487  Tcl_SetResult( interp, Tk_PathName( plFramePtr->tkwin ), TCL_VOLATILE );
488 
489  return TCL_OK;
490 }
491 
492 //
493 //--------------------------------------------------------------------------
494 //
495 // PlFrameWidgetCmd --
496 //
497 // This procedure is invoked to process the Tcl command that
498 // corresponds to a plframe widget. See the user
499 // documentation for details on what it does.
500 //
501 // Results:
502 // A standard Tcl result.
503 //
504 // Side effects:
505 // See the user documentation.
506 //
507 //--------------------------------------------------------------------------
508 //
509 
510 static int
511 PlFrameWidgetCmd( ClientData clientData, Tcl_Interp *interp,
512  int argc, const char **argv )
513 {
514  register PlFrame *plFramePtr = (PlFrame *) clientData;
515  int result = TCL_OK;
516  int length;
517  char c;
518  char res[20];
519 
520  dbug_enter( "PlFrameWidgetCmd" );
521 
522 #ifdef DEBUG
523  {
524  int i;
525  PLStream *pls;
526  plgpls( pls );
527  printf( "Current stream %d, frame stream %d\n",
528  pls->ipls, plFramePtr->ipls );
529  printf( "PlFrameWidgetCmd: " );
530  for ( i = 0; i < argc; i++ )
531  printf( " %s", argv[i] );
532  printf( "\n" );
533  }
534 #endif
535 
536  if ( argc < 2 )
537  {
538  Tcl_AppendResult( interp, "wrong # args: should be \"",
539  argv[0], " option ?arg arg ...?\"", (char *) NULL );
540  return TCL_ERROR;
541  }
542  Tk_Preserve( (ClientData) plFramePtr );
543  c = argv[1][0];
544  length = (int) strlen( argv[1] );
545 
546 // First, before anything else, we have to set the stream to be the one that
547 // corresponds to this widget.
548  plsstrm( plFramePtr->ipls );
549 
550 // cmd -- issue a command to the PLplot library
551 
552  if ( ( c == 'c' ) && ( strncmp( argv[1], "cmd", (size_t) length ) == 0 ) )
553  {
554  result = Cmd( interp, plFramePtr, argc - 2, argv + 2 );
555  }
556 
557 // cget
558 
559  else if ( ( c == 'c' ) && ( strncmp( argv[1], "cget", (size_t) length ) == 0 ) )
560  {
561  if ( argc > 2 )
562  {
563  Tcl_AppendResult( interp, "wrong # args: should be \"",
564  argv[0], " cget <option>\"", (char *) NULL );
565  result = TCL_ERROR;
566  goto done;
567  }
568  else
569  {
570  result = Tk_ConfigureInfo( interp, plFramePtr->tkwin, configSpecs,
571  (char *) plFramePtr, (char *) NULL, 0 );
572  }
573  }
574 
575 // configure
576 
577  else if ( ( c == 'c' ) && ( strncmp( argv[1], "configure", (size_t) length ) == 0 ) )
578  {
579  if ( argc == 2 )
580  {
581  result = Tk_ConfigureInfo( interp, plFramePtr->tkwin, configSpecs,
582  (char *) plFramePtr, (char *) NULL, 0 );
583  }
584  else if ( argc == 3 )
585  {
586  result = Tk_ConfigureInfo( interp, plFramePtr->tkwin, configSpecs,
587  (char *) plFramePtr, argv[2], 0 );
588  }
589  else
590  {
591  result = ConfigurePlFrame( interp, plFramePtr, argc - 2, argv + 2,
592  TK_CONFIG_ARGV_ONLY );
593  }
594  }
595 
596 // double buffering
597 
598  else if ( ( c == 'd' ) &&
599  ( ( strncmp( argv[1], "db", (size_t) length ) == 0 ) ||
600  ( strncmp( argv[1], "doublebuffering", (size_t) length == 0 ) ) ) )
601  {
602  PLBufferingCB bcb;
603 
604  if ( argc == 3 )
605  {
606  if ( strcmp( argv[2], "on" ) == 0 )
607  {
609  pl_cmd( PLESC_DOUBLEBUFFERING, &bcb );
610  }
611  if ( strcmp( argv[2], "off" ) == 0 )
612  {
614  pl_cmd( PLESC_DOUBLEBUFFERING, &bcb );
615  }
616  if ( strcmp( argv[2], "query" ) == 0 )
617  {
619  pl_cmd( PLESC_DOUBLEBUFFERING, &bcb );
620  snprintf( res, 20, "%d", bcb.result );
621  Tcl_SetResult( interp, res, TCL_VOLATILE );
622  }
623  }
624 
625  result = TCL_OK;
626  }
627 
628 // closelink -- Close a binary data link previously opened with openlink
629 
630  else if ( ( c == 'c' ) && ( strncmp( argv[1], "closelink", (size_t) length ) == 0 ) )
631  {
632  if ( argc > 2 )
633  {
634  Tcl_AppendResult( interp, "wrong # args: should be \"",
635  argv[0], (char *) NULL );
636  result = TCL_ERROR;
637  goto done;
638  }
639  else
640  {
641  result = Closelink( interp, plFramePtr, argc - 2, argv + 2 );
642  }
643  }
644 
645 // draw -- rubber-band draw used in region selection
646 
647  else if ( ( c == 'd' ) && ( strncmp( argv[1], "draw", (size_t) length ) == 0 ) )
648  {
649  if ( argc == 2 )
650  {
651  Tcl_AppendResult( interp, "wrong # args: should be \"",
652  argv[0], " draw op ?options?\"", (char *) NULL );
653  result = TCL_ERROR;
654  goto done;
655  }
656  else
657  {
658  result = Draw( interp, plFramePtr, argc - 2, argv + 2 );
659  }
660  }
661 
662 // color-manipulating commands, grouped together for convenience
663 
664  else if ( ( ( c == 'g' ) && ( ( strncmp( argv[1], "gcmap0", (size_t) length ) == 0 ) ||
665  ( strncmp( argv[1], "gcmap1", (size_t) length ) == 0 ) ) ) ||
666  ( ( c == 's' ) && ( ( strncmp( argv[1], "scmap0", (size_t) length ) == 0 ) ||
667  ( strncmp( argv[1], "scmap1", (size_t) length ) == 0 ) ||
668  ( strncmp( argv[1], "scol0", (size_t) length ) == 0 ) ||
669  ( strncmp( argv[1], "scol1", (size_t) length ) == 0 ) ) ) )
670  result = ColorManip( interp, plFramePtr, argc - 1, argv + 1 );
671 
672 // info -- returns requested info
673 
674  else if ( ( c == 'i' ) && ( strncmp( argv[1], "info", (size_t) length ) == 0 ) )
675  {
676  result = Info( interp, plFramePtr, argc - 2, argv + 2 );
677  }
678 
679 // orient -- Set plot orientation
680 
681  else if ( ( c == 'o' ) && ( strncmp( argv[1], "orient", (size_t) length ) == 0 ) )
682  {
683  result = Orient( interp, plFramePtr, argc - 2, argv + 2 );
684  }
685 
686 // openlink -- Open a binary data link (FIFO or socket)
687 
688  else if ( ( c == 'o' ) && ( strncmp( argv[1], "openlink", (size_t) length ) == 0 ) )
689  {
690  if ( argc < 3 )
691  {
692  Tcl_AppendResult( interp, "wrong # args: should be \"",
693  argv[0], " option ?arg arg ...?\"", (char *) NULL );
694  result = TCL_ERROR;
695  goto done;
696  }
697  else
698  {
699  result = Openlink( interp, plFramePtr, argc - 2, argv + 2 );
700  }
701  }
702 
703 // page -- change or return output page setup
704 
705  else if ( ( c == 'p' ) && ( strncmp( argv[1], "page", (size_t) length ) == 0 ) )
706  {
707  result = Page( interp, plFramePtr, argc - 2, argv + 2 );
708  }
709 
710 // print -- prints plot
711 
712  else if ( ( c == 'p' ) && ( strncmp( argv[1], "print", (size_t) length ) == 0 ) )
713  {
714  result = Print( interp, plFramePtr, argc - 2, argv + 2 );
715  }
716 
717 // redraw -- redraw plot
718 
719  else if ( ( c == 'r' ) && ( strncmp( argv[1], "redraw", (size_t) length ) == 0 ) )
720  {
721  if ( argc > 2 )
722  {
723  Tcl_AppendResult( interp, "wrong # args: should be \"",
724  argv[0], " redraw\"", (char *) NULL );
725  result = TCL_ERROR;
726  goto done;
727  }
728  else
729  {
730  result = Redraw( interp, plFramePtr, argc - 2, argv + 2 );
731  }
732  }
733 
734 // report -- find out useful info about the plframe (GMF)
735 
736  else if ( ( c == 'r' ) && ( strncmp( argv[1], "report", (size_t) length ) == 0 ) )
737  {
738  result = report( interp, plFramePtr, argc - 2, argv + 2 );
739  }
740 
741 // save -- saves plot to the specified plot file type
742 
743  else if ( ( c == 's' ) && ( strncmp( argv[1], "save", (size_t) length ) == 0 ) )
744  {
745  result = Save( interp, plFramePtr, argc - 2, argv + 2 );
746  }
747 
748 // view -- change or return window into plot
749 
750  else if ( ( c == 'v' ) && ( strncmp( argv[1], "view", (size_t) length ) == 0 ) )
751  {
752  result = View( interp, plFramePtr, argc - 2, argv + 2 );
753  }
754 
755 // xscroll -- horizontally scroll window into plot
756 
757  else if ( ( c == 'x' ) && ( strncmp( argv[1], "xscroll", (size_t) length ) == 0 ) )
758  {
759  if ( argc == 2 || argc > 3 )
760  {
761  Tcl_AppendResult( interp, "wrong # args: should be \"",
762  argv[0], " xscroll pixel\"", (char *) NULL );
763  result = TCL_ERROR;
764  goto done;
765  }
766  else
767  {
768  result = xScroll( interp, plFramePtr, argc - 2, argv + 2 );
769  }
770  }
771 
772 // yscroll -- vertically scroll window into plot
773 
774  else if ( ( c == 'y' ) && ( strncmp( argv[1], "yscroll", (size_t) length ) == 0 ) )
775  {
776  if ( argc == 2 || argc > 3 )
777  {
778  Tcl_AppendResult( interp, "wrong # args: should be \"",
779  argv[0], " yscroll pixel\"", (char *) NULL );
780  result = TCL_ERROR;
781  goto done;
782  }
783  else
784  {
785  result = yScroll( interp, plFramePtr, argc - 2, argv + 2 );
786  }
787  }
788 
789 // unrecognized widget command
790 
791  else
792  {
793  Tcl_AppendResult( interp, "bad option \"", argv[1],
794  "\": must be closelink, cmd, configure, draw, ",
795  "gcmap0, gcmap1, ",
796  "info, openlink, orient, page, print, redraw, save, ",
797  "scmap0, scmap1, scol0, scol1, ",
798  "view, xscroll, or yscroll", (char *) NULL );
799 
800  result = TCL_ERROR;
801 #ifdef DEBUG
802  printf( "bad option!\n" );
803 #endif
804  }
805 
806 #ifdef DEBUG
807  printf( "result=%d current stream=%d\n", result, plsc->ipls );
808 #endif
809 
810 done:
811  Tk_Release( (ClientData) plFramePtr );
812  return result;
813 }
814 
815 //
816 //--------------------------------------------------------------------------
817 //
818 // DestroyPlFrame --
819 //
820 // This procedure is invoked by Tk_EventuallyFree or Tk_Release to
821 // clean up the internal structure of a plframe at a safe time
822 // (when no-one is using it anymore).
823 //
824 // Results:
825 // None.
826 //
827 // Side effects:
828 // Everything associated with the plframe is freed up.
829 //
830 //--------------------------------------------------------------------------
831 //
832 
833 static void
835 {
836  register PlFrame *plFramePtr = (PlFrame *) clientData;
837  register PLRDev *plr = plFramePtr->plr;
838 
839  dbug_enter( "DestroyPlFrame" );
840 
841  if ( plFramePtr->border != NULL )
842  {
843  Tk_Free3DBorder( plFramePtr->border );
844  }
845  if ( plFramePtr->bgColor != NULL )
846  {
847  Tk_FreeColor( plFramePtr->bgColor );
848  }
849  if ( plFramePtr->plpr_cmd != NULL )
850  {
851  ckfree( (char *) plFramePtr->plpr_cmd );
852  }
853  if ( plFramePtr->cursor != None )
854  {
855  Tk_FreeCursor( plFramePtr->display, plFramePtr->cursor );
856  }
857  if ( plFramePtr->xhair_cursor != None )
858  {
859  Tk_FreeCursor( plFramePtr->display, plFramePtr->xhair_cursor );
860  }
861  if ( plFramePtr->xorGC != NULL )
862  {
863  Tk_FreeGC( plFramePtr->display, plFramePtr->xorGC );
864  }
865  if ( plFramePtr->yScrollCmd != NULL )
866  {
867  ckfree( (char *) plFramePtr->yScrollCmd );
868  }
869  if ( plFramePtr->xScrollCmd != NULL )
870  {
871  ckfree( (char *) plFramePtr->xScrollCmd );
872  }
873  if ( plFramePtr->SaveFnam != NULL )
874  {
875  ckfree( (char *) plFramePtr->SaveFnam );
876  }
877  if ( plFramePtr->devDesc != NULL )
878  {
879  ckfree( (char *) plFramePtr->devDesc );
880  }
881  if ( plFramePtr->devName != NULL )
882  {
883  ckfree( (char *) plFramePtr->devName );
884  }
885 
886 // Clean up data connection
887 
888  pdf_close( plr->pdfs );
889  ckfree( (char *) plFramePtr->plr->iodev );
890 
891 // Tell PLplot to clean up
892 
893  plsstrm( plFramePtr->ipls );
894  plend1();
895 
896 // Delete main data structures
897 
898  ckfree( (char *) plFramePtr->plr );
899  ckfree( (char *) plFramePtr );
900 }
901 
902 //
903 //--------------------------------------------------------------------------
904 //
905 // PlFrameConfigureEH --
906 //
907 // Invoked by the Tk dispatcher on structure changes to a plframe.
908 //
909 // Results:
910 // None.
911 //
912 // Side effects:
913 // When the window gets deleted, internal structures get cleaned up.
914 // When it gets resized, it is redrawn.
915 //
916 //--------------------------------------------------------------------------
917 //
918 
919 static void
920 PlFrameConfigureEH( ClientData clientData, register XEvent *eventPtr )
921 {
922  register PlFrame *plFramePtr = (PlFrame *) clientData;
923  register Tk_Window tkwin = plFramePtr->tkwin;
924 
925  dbug_enter( "PlFrameConfigureEH" );
926 
927  switch ( eventPtr->type )
928  {
929  case ConfigureNotify:
930  pldebug( "PLFrameConfigureEH", "ConfigureNotify\n" );
931  plFramePtr->flags |= RESIZE_PENDING;
932  plFramePtr->width = Tk_Width( tkwin );
933  plFramePtr->height = Tk_Height( tkwin );
934  if ( ( tkwin != NULL ) && !( plFramePtr->flags & REFRESH_PENDING ) )
935  {
936  Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
937  plFramePtr->flags |= REFRESH_PENDING;
938  plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
939  }
940  break;
941 
942  case DestroyNotify:
943  pldebug( "PLFrameConfigureEH", "DestroyNotify\n" );
944 #ifdef HAVE_ITCL
945  Itk_SetWidgetCommand( plFramePtr->tkwin, (Tcl_Command) NULL );
946  Tcl_DeleteCommand2( plFramePtr->interp, plFramePtr->widgetCmd );
947 #else
948  Tcl_DeleteCommand( plFramePtr->interp, Tk_PathName( tkwin ) );
949 #endif
950  plFramePtr->tkwin = NULL;
951  if ( plFramePtr->flags & REFRESH_PENDING )
952  {
953  Tk_CancelIdleCall( DisplayPlFrame, (ClientData) plFramePtr );
954  }
955  Tk_EventuallyFree( (ClientData) plFramePtr, DestroyPlFrame );
956  break;
957 
958  case MapNotify:
959  pldebug( "PLFrameConfigureEH", "MapNotify\n" );
960  if ( plFramePtr->flags & REFRESH_PENDING )
961  {
962  Tk_CancelIdleCall( DisplayPlFrame, (ClientData) plFramePtr );
963  }
964 
965  // For some reason, "." must be mapped or PlFrameInit will die (Note:
966  // mapped & withdrawn or mapped in the withdrawn state is OK). Issuing
967  // an update fixes this. I'd love to know why this occurs.
968  //
969 
970  if ( !plFramePtr->tkwin_initted )
971  {
972  Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
973  }
974  Tk_DoWhenIdle( PlFrameInit, (ClientData) plFramePtr );
975  break;
976  }
977 }
978 
979 //
980 //--------------------------------------------------------------------------
981 //
982 // PlFrameExposeEH --
983 //
984 // Invoked by the Tk dispatcher on exposes of a plframe.
985 //
986 // Results:
987 // None.
988 //
989 // Side effects:
990 // Widget is redisplayed.
991 //
992 // Note: it's customary in Tk to collapse multiple exposes, so for best
993 // performance without losing the window contents, I keep track of the
994 // smallest single rectangle that can satisfy all expose events. If there
995 // are any overlaid graphics (like crosshairs), however, we need to refresh
996 // the entire plot in order to have a predictable outcome.
997 //
998 //--------------------------------------------------------------------------
999 
1000 static void
1001 PlFrameExposeEH( ClientData clientData, register XEvent *eventPtr )
1002 {
1003  register PlFrame *plFramePtr = (PlFrame *) clientData;
1004  XExposeEvent *event = (XExposeEvent *) eventPtr;
1005  register Tk_Window tkwin = plFramePtr->tkwin;
1006 
1007  dbug_enter( "PlFrameExposeEH" );
1008 
1009  pldebug( "PLFrameExposeEH", "Expose\n" );
1010 
1011 // Set up the area to refresh
1012 
1013  if ( !( plFramePtr->drawing_xhairs || plFramePtr->drawing_rband ) )
1014  {
1015  int x0_old, x1_old, y0_old, y1_old, x0_new, x1_new, y0_new, y1_new;
1016 
1017  x0_old = (int) plFramePtr->pldis.x;
1018  y0_old = (int) plFramePtr->pldis.y;
1019  x1_old = x0_old + (int) plFramePtr->pldis.width;
1020  y1_old = y0_old + (int) plFramePtr->pldis.height;
1021 
1022  x0_new = event->x;
1023  y0_new = event->y;
1024  x1_new = x0_new + event->width;
1025  y1_new = y0_new + event->height;
1026 
1027  plFramePtr->pldis.x = (unsigned int) MIN( x0_old, x0_new );
1028  plFramePtr->pldis.y = (unsigned int) MIN( y0_old, y0_new );
1029  plFramePtr->pldis.width = (unsigned int) MAX( x1_old, x1_new ) - plFramePtr->pldis.x;
1030  plFramePtr->pldis.height = (unsigned int) MAX( y1_old, y1_new ) - plFramePtr->pldis.y;
1031  }
1032 
1033 // Invoke DoWhenIdle handler to redisplay widget.
1034 
1035  if ( event->count == 0 )
1036  {
1037  if ( ( tkwin != NULL ) && !( plFramePtr->flags & REFRESH_PENDING ) )
1038  {
1039  Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
1040  plFramePtr->width = Tk_Width( tkwin );
1041  plFramePtr->height = Tk_Height( tkwin );
1042  plFramePtr->flags |= REFRESH_PENDING;
1043  }
1044  }
1045 }
1046 
1047 //
1048 //--------------------------------------------------------------------------
1049 //
1050 // PlFrameMotionEH --
1051 //
1052 // Invoked by the Tk dispatcher on MotionNotify events in a plframe.
1053 // Not invoked unless we are drawing graphic crosshairs.
1054 //
1055 // Results:
1056 // None.
1057 //
1058 // Side effects:
1059 // Graphic crosshairs are drawn.
1060 //
1061 //--------------------------------------------------------------------------
1062 //
1063 
1064 static void
1065 PlFrameMotionEH( ClientData clientData, register XEvent *eventPtr )
1066 {
1067  register PlFrame *plFramePtr = (PlFrame *) clientData;
1068  XMotionEvent *event = (XMotionEvent *) eventPtr;
1069 
1070  dbug_enter( "PlFrameMotionEH" );
1071 
1072  if ( plFramePtr->drawing_xhairs )
1073  {
1074  DrawXhairs( plFramePtr, event->x, event->y );
1075  }
1076  if ( plFramePtr->drawing_rband )
1077  {
1078  DrawRband( plFramePtr, event->x, event->y );
1079  }
1080 }
1081 
1082 //
1083 //--------------------------------------------------------------------------
1084 //
1085 // PlFrameEnterEH --
1086 //
1087 // Invoked by the Tk dispatcher on EnterNotify events in a plframe.
1088 // Not invoked unless we are drawing graphic crosshairs.
1089 //
1090 // Results:
1091 // None.
1092 //
1093 // Side effects:
1094 // Graphic crosshairs are updated.
1095 //
1096 //--------------------------------------------------------------------------
1097 
1098 static void
1099 PlFrameEnterEH( ClientData clientData, register XEvent *eventPtr )
1100 {
1101  register PlFrame *plFramePtr = (PlFrame *) clientData;
1102  XCrossingEvent *crossingEvent = (XCrossingEvent *) eventPtr;
1103 
1104  dbug_enter( "PlFrameEnterEH" );
1105 
1106  if ( plFramePtr->xhairs )
1107  {
1108  DrawXhairs( plFramePtr, crossingEvent->x, crossingEvent->y );
1109  plFramePtr->drawing_xhairs = 1;
1110  }
1111  if ( plFramePtr->rband )
1112  {
1113  plFramePtr->drawing_rband = 1;
1114  UpdateRband( plFramePtr );
1115  DrawRband( plFramePtr, crossingEvent->x, crossingEvent->y );
1116  }
1117 }
1118 
1119 //
1120 //--------------------------------------------------------------------------
1121 //
1122 // PlFrameLeaveEH --
1123 //
1124 // Invoked by the Tk dispatcher on LeaveNotify events in a plframe.
1125 // Not invoked unless we are drawing graphic crosshairs.
1126 //
1127 // Results:
1128 // None.
1129 //
1130 // Side effects:
1131 // Graphic crosshairs are updated.
1132 //
1133 //--------------------------------------------------------------------------
1134 
1135 static void
1136 PlFrameLeaveEH( ClientData clientData, register XEvent * PL_UNUSED( eventPtr ) )
1137 {
1138  register PlFrame *plFramePtr = (PlFrame *) clientData;
1139 
1140  dbug_enter( "PlFrameLeaveEH" );
1141 
1142  if ( plFramePtr->drawing_xhairs )
1143  {
1144  UpdateXhairs( plFramePtr );
1145  plFramePtr->drawing_xhairs = 0;
1146  }
1147  if ( plFramePtr->drawing_rband )
1148  {
1149  UpdateRband( plFramePtr );
1150  plFramePtr->drawing_rband = 0;
1151  }
1152 }
1153 
1154 //
1155 //--------------------------------------------------------------------------
1156 //
1157 // PlFrameKeyEH --
1158 //
1159 // Invoked by the Tk dispatcher on Keypress events in a plframe.
1160 // Not invoked unless we are drawing graphic crosshairs.
1161 //
1162 // Results:
1163 // None.
1164 //
1165 // Side effects:
1166 // Keypress events get filtered. If a cursor key is pushed, the
1167 // graphic crosshairs are moved in the appropriate direction. Using a
1168 // modifier key multiplies the movement a factor of 5 for each key
1169 // added.
1170 //
1171 //--------------------------------------------------------------------------
1172 //
1173 
1174 static void
1175 PlFrameKeyEH( ClientData clientData, register XEvent *eventPtr )
1176 {
1177  register PlFrame *plFramePtr = (PlFrame *) clientData;
1178  XKeyEvent *event = (XKeyEvent *) eventPtr;
1179  register Tk_Window tkwin = plFramePtr->tkwin;
1180 
1181  KeySym keysym;
1182  int nchars;
1183  char string[11];
1184  XComposeStatus cs;
1185 
1186  dbug_enter( "PlFrameKeyEH" );
1187 
1188  nchars = XLookupString( event, string, 10, &keysym, &cs );
1189  string[nchars] = '\0';
1190  pldebug( "PlFrameKeyEH", "Keysym %x, translation: %s\n", keysym, string );
1191 
1192  if ( IsModifierKey( keysym ) )
1193  {
1194  eventPtr->type = 0;
1195  }
1196  else if ( IsCursorKey( keysym ) )
1197  {
1198  int x1, y1, dx = 0, dy = 0;
1199  int x0 = event->x, y0 = event->y;
1200  int xmin = 0, xmax = Tk_Width( tkwin ) - 1;
1201  int ymin = 0, ymax = Tk_Height( tkwin ) - 1;
1202 
1203  switch ( keysym )
1204  {
1205  case XK_Left:
1206  dx = -1;
1207  break;
1208  case XK_Right:
1209  dx = 1;
1210  break;
1211  case XK_Up:
1212  dy = -1;
1213  break;
1214  case XK_Down:
1215  dy = 1;
1216  break;
1217  }
1218 
1219  // Each modifier key added increases the multiplication factor by 5
1220 
1221  // Shift
1222 
1223  if ( event->state & 0x01 )
1224  {
1225  dx *= 5;
1226  dy *= 5;
1227  }
1228 
1229  // Caps Lock
1230 
1231  if ( event->state & 0x02 )
1232  {
1233  dx *= 5;
1234  dy *= 5;
1235  }
1236 
1237  // Control
1238 
1239  if ( event->state & 0x04 )
1240  {
1241  dx *= 5;
1242  dy *= 5;
1243  }
1244 
1245  // Alt
1246 
1247  if ( event->state & 0x08 )
1248  {
1249  dx *= 5;
1250  dy *= 5;
1251  }
1252 
1253  // Bounds checking so that we don't send cursor out of window
1254 
1255  x1 = x0 + dx;
1256  y1 = y0 + dy;
1257 
1258  if ( x1 < xmin )
1259  dx = xmin - x0;
1260  if ( y1 < ymin )
1261  dy = ymin - y0;
1262  if ( x1 > xmax )
1263  dx = xmax - x0;
1264  if ( y1 > ymax )
1265  dy = ymax - y0;
1266 
1267  // Engage...
1268 
1269  XWarpPointer( plFramePtr->display, Tk_WindowId( tkwin ),
1270  None, 0, 0, 0, 0, dx, dy );
1271  eventPtr->type = 0;
1272  }
1273 }
1274 
1275 //--------------------------------------------------------------------------
1276 // CreateXhairs()
1277 //
1278 // Creates graphic crosshairs at current pointer location.
1279 //--------------------------------------------------------------------------
1280 
1281 static void
1282 CreateXhairs( PlFrame *plFramePtr )
1283 {
1284  register Tk_Window tkwin = plFramePtr->tkwin;
1285  Window root, child;
1286  int root_x, root_y, win_x, win_y;
1287  unsigned int mask;
1288 
1289 // Switch to crosshair cursor.
1290 
1291  Tk_DefineCursor( tkwin, plFramePtr->xhair_cursor );
1292 
1293 // Find current pointer location and draw graphic crosshairs if pointer is
1294 // inside our window.
1295 
1296  if ( XQueryPointer( plFramePtr->display, Tk_WindowId( tkwin ),
1297  &root, &child, &root_x, &root_y, &win_x, &win_y,
1298  &mask ) )
1299  {
1300  if ( win_x >= 0 && win_x < Tk_Width( tkwin ) &&
1301  win_y >= 0 && win_y < Tk_Height( tkwin ) )
1302  {
1303  DrawXhairs( plFramePtr, win_x, win_y );
1304  plFramePtr->drawing_xhairs = 1;
1305  }
1306  }
1307 
1308 // Catch PointerMotion and crossing events so we can update them properly
1309 
1310  if ( !plFramePtr->drawing_rband )
1311  {
1312  Tk_CreateEventHandler( tkwin, PointerMotionMask,
1313  PlFrameMotionEH, (ClientData) plFramePtr );
1314 
1315  Tk_CreateEventHandler( tkwin, EnterWindowMask,
1316  PlFrameEnterEH, (ClientData) plFramePtr );
1317 
1318  Tk_CreateEventHandler( tkwin, LeaveWindowMask,
1319  PlFrameLeaveEH, (ClientData) plFramePtr );
1320  }
1321 
1322 // Catch KeyPress events so we can filter them
1323 
1324  Tk_CreateEventHandler( tkwin, KeyPressMask,
1325  PlFrameKeyEH, (ClientData) plFramePtr );
1326 }
1327 
1328 //--------------------------------------------------------------------------
1329 // DestroyXhairs()
1330 //
1331 // Destroys graphic crosshairs.
1332 //--------------------------------------------------------------------------
1333 
1334 static void
1335 DestroyXhairs( PlFrame *plFramePtr )
1336 {
1337  register Tk_Window tkwin = plFramePtr->tkwin;
1338 
1339 // Switch back to boring old pointer
1340 
1341  Tk_DefineCursor( tkwin, plFramePtr->cursor );
1342 
1343 // Don't catch PointerMotion or crossing events any more
1344 
1345  if ( !plFramePtr->drawing_rband )
1346  {
1347  Tk_DeleteEventHandler( tkwin, PointerMotionMask,
1348  PlFrameMotionEH, (ClientData) plFramePtr );
1349 
1350  Tk_DeleteEventHandler( tkwin, EnterWindowMask,
1351  PlFrameEnterEH, (ClientData) plFramePtr );
1352 
1353  Tk_DeleteEventHandler( tkwin, LeaveWindowMask,
1354  PlFrameLeaveEH, (ClientData) plFramePtr );
1355  }
1356 
1357  Tk_DeleteEventHandler( tkwin, KeyPressMask,
1358  PlFrameKeyEH, (ClientData) plFramePtr );
1359 
1360 // This draw removes the last set of graphic crosshairs
1361 
1362  UpdateXhairs( plFramePtr );
1363  plFramePtr->drawing_xhairs = 0;
1364 }
1365 
1366 //--------------------------------------------------------------------------
1367 // DrawXhairs()
1368 //
1369 // Draws graphic crosshairs at (x0, y0). The first draw erases the old set.
1370 //--------------------------------------------------------------------------
1371 
1372 static void
1373 DrawXhairs( PlFrame *plFramePtr, int x0, int y0 )
1374 {
1375  register Tk_Window tkwin = plFramePtr->tkwin;
1376  int xmin = 0, xmax = Tk_Width( tkwin ) - 1;
1377  int ymin = 0, ymax = Tk_Height( tkwin ) - 1;
1378 
1379  if ( plFramePtr->drawing_xhairs )
1380  UpdateXhairs( plFramePtr );
1381 
1382  plFramePtr->xhair_x[0].x = (short) xmin; plFramePtr->xhair_x[0].y = (short) y0;
1383  plFramePtr->xhair_x[1].x = (short) xmax; plFramePtr->xhair_x[1].y = (short) y0;
1384 
1385  plFramePtr->xhair_y[0].x = (short) x0; plFramePtr->xhair_y[0].y = (short) ymin;
1386  plFramePtr->xhair_y[1].x = (short) x0; plFramePtr->xhair_y[1].y = (short) ymax;
1387 
1388  UpdateXhairs( plFramePtr );
1389 }
1390 
1391 //--------------------------------------------------------------------------
1392 // UpdateXhairs()
1393 //
1394 // Updates graphic crosshairs. If already there, they are erased.
1395 //--------------------------------------------------------------------------
1396 
1397 static void
1398 UpdateXhairs( PlFrame *plFramePtr )
1399 {
1400  register Tk_Window tkwin = plFramePtr->tkwin;
1401 
1402  XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
1403  plFramePtr->xorGC, plFramePtr->xhair_x, 2,
1404  CoordModeOrigin );
1405 
1406  XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
1407  plFramePtr->xorGC, plFramePtr->xhair_y, 2,
1408  CoordModeOrigin );
1409 }
1410 
1411 //--------------------------------------------------------------------------
1412 // CreateRband()
1413 //
1414 // Initiate rubber banding.
1415 //--------------------------------------------------------------------------
1416 
1417 static void
1418 CreateRband( PlFrame *plFramePtr )
1419 {
1420  register Tk_Window tkwin = plFramePtr->tkwin;
1421  Window root, child;
1422  int root_x, root_y, win_x, win_y;
1423  unsigned int mask;
1424 
1425 // Find current pointer location, and initiate rubber banding.
1426 
1427  if ( XQueryPointer( plFramePtr->display, Tk_WindowId( tkwin ),
1428  &root, &child, &root_x, &root_y, &win_x, &win_y,
1429  &mask ) )
1430  {
1431  if ( win_x >= 0 && win_x < Tk_Width( tkwin ) &&
1432  win_y >= 0 && win_y < Tk_Height( tkwin ) )
1433  {
1434  // Okay, pointer is in our window.
1435  plFramePtr->rband_pt[0].x = (short) win_x;
1436  plFramePtr->rband_pt[0].y = (short) win_y;
1437 
1438  DrawRband( plFramePtr, win_x, win_y );
1439  plFramePtr->drawing_rband = 1;
1440  }
1441  else
1442  {
1443  // Hmm, somehow they turned it on without even being in the window.
1444  // Just put the anchor in top left, they'll soon realize this is a
1445  // mistake...
1446 
1447  plFramePtr->rband_pt[0].x = 0;
1448  plFramePtr->rband_pt[0].y = 0;
1449 
1450  DrawRband( plFramePtr, win_x, win_y );
1451  plFramePtr->drawing_rband = 1;
1452  }
1453  }
1454 
1455 // Catch PointerMotion and crossing events so we can update them properly
1456 
1457  if ( !plFramePtr->drawing_xhairs )
1458  {
1459  Tk_CreateEventHandler( tkwin, PointerMotionMask,
1460  PlFrameMotionEH, (ClientData) plFramePtr );
1461 
1462  Tk_CreateEventHandler( tkwin, EnterWindowMask,
1463  PlFrameEnterEH, (ClientData) plFramePtr );
1464 
1465  Tk_CreateEventHandler( tkwin, LeaveWindowMask,
1466  PlFrameLeaveEH, (ClientData) plFramePtr );
1467  }
1468 }
1469 
1470 //--------------------------------------------------------------------------
1471 // DestroyRband()
1472 //
1473 // Turn off rubber banding.
1474 //--------------------------------------------------------------------------
1475 
1476 static void
1477 DestroyRband( PlFrame *plFramePtr )
1478 {
1479  register Tk_Window tkwin = plFramePtr->tkwin;
1480 
1481 // Don't catch PointerMotion or crossing events any more
1482 
1483  if ( !plFramePtr->drawing_xhairs )
1484  {
1485  Tk_DeleteEventHandler( tkwin, PointerMotionMask,
1486  PlFrameMotionEH, (ClientData) plFramePtr );
1487 
1488  Tk_DeleteEventHandler( tkwin, EnterWindowMask,
1489  PlFrameEnterEH, (ClientData) plFramePtr );
1490 
1491  Tk_DeleteEventHandler( tkwin, LeaveWindowMask,
1492  PlFrameLeaveEH, (ClientData) plFramePtr );
1493  }
1494 
1495 // This draw removes the residual rubber band.
1496 
1497  UpdateRband( plFramePtr );
1498  plFramePtr->drawing_rband = 0;
1499 }
1500 
1501 //--------------------------------------------------------------------------
1502 // DrawRband()
1503 //
1504 // Draws a rubber band from the anchor to the current cursor location.
1505 //--------------------------------------------------------------------------
1506 
1507 static void
1508 DrawRband( PlFrame *plFramePtr, int x0, int y0 )
1509 {
1510 // If the line is already up, clear it.
1511 
1512  if ( plFramePtr->drawing_rband )
1513  UpdateRband( plFramePtr );
1514 
1515  plFramePtr->rband_pt[1].x = (short) x0; plFramePtr->rband_pt[1].y = (short) y0;
1516 
1517  UpdateRband( plFramePtr );
1518 }
1519 
1520 //--------------------------------------------------------------------------
1521 // UpdateRband()
1522 //
1523 // Updates rubber band. If already there, it is erased.
1524 //--------------------------------------------------------------------------
1525 
1526 static void
1527 UpdateRband( PlFrame *plFramePtr )
1528 {
1529  register Tk_Window tkwin = plFramePtr->tkwin;
1530 
1531  XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
1532  plFramePtr->xorGC, plFramePtr->rband_pt, 2,
1533  CoordModeOrigin );
1534 }
1535 
1536 //
1537 //--------------------------------------------------------------------------
1538 //
1539 // PlFrameInit --
1540 //
1541 // Invoked to handle miscellaneous initialization after window gets
1542 // mapped.
1543 //
1544 // Results:
1545 // None.
1546 //
1547 // Side effects:
1548 // PLplot internal parameters and device driver are initialized.
1549 //
1550 //--------------------------------------------------------------------------
1551 
1552 static void
1553 PlFrameInit( ClientData clientData )
1554 {
1555  register PlFrame *plFramePtr = (PlFrame *) clientData;
1556  register Tk_Window tkwin = plFramePtr->tkwin;
1557 
1558 // Set up window parameters and arrange for window to be refreshed
1559 
1560  plFramePtr->flags |= REFRESH_PENDING;
1561  plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
1562 
1563 // First-time initialization
1564 
1565  if ( !plFramePtr->tkwin_initted )
1566  {
1567  plsstrm( plFramePtr->ipls );
1568  plsxwin( (PLINT) Tk_WindowId( tkwin ) );
1569  plspause( 0 );
1570  plinit();
1571 // plplot_ccmap is statically defined in plxwd.h. Note that
1572 // xwin.c also includes that header and uses that variable.
1573  if ( plplot_ccmap )
1574  {
1575  Install_cmap( plFramePtr );
1576  }
1577  if ( plFramePtr->bopCmd != NULL )
1578  plsbopH( process_bop, (void *) plFramePtr );
1579  if ( plFramePtr->eopCmd != NULL )
1580  plseopH( process_eop, (void *) plFramePtr );
1581 
1582  plbop();
1583 
1584  plFramePtr->tkwin_initted = 1;
1585  plFramePtr->width = Tk_Width( tkwin );
1586  plFramePtr->height = Tk_Height( tkwin );
1587  plFramePtr->prevWidth = plFramePtr->width;
1588  plFramePtr->prevHeight = plFramePtr->height;
1589  }
1590 
1591 // Draw plframe
1592 
1593  DisplayPlFrame( clientData );
1594 
1595  if ( plFramePtr->xhairs )
1596  CreateXhairs( plFramePtr );
1597 
1598  if ( plFramePtr->rband )
1599  CreateRband( plFramePtr );
1600 }
1601 
1602 //
1603 //--------------------------------------------------------------------------
1604 //
1605 // Install_cmap --
1606 //
1607 // Installs X driver color map as necessary when custom color maps
1608 // are used.
1609 //
1610 // Results:
1611 // None.
1612 //
1613 // Side effects:
1614 // Parent color maps may get changed.
1615 //
1616 //--------------------------------------------------------------------------
1617 //
1618 
1619 static void
1620 Install_cmap( PlFrame *plFramePtr )
1621 {
1622  XwDev *dev;
1623 
1624 #define INSTALL_COLORMAP_IN_TK
1625 #ifdef INSTALL_COLORMAP_IN_TK
1626  dev = (XwDev *) plFramePtr->pls->dev;
1627  Tk_SetWindowColormap( Tk_MainWindow( plFramePtr->interp ), dev->xwd->map );
1628 
1629 //
1630 // If the colormap is local to this widget, the WM must be informed that
1631 // it should be installed when the widget gets the focus. The top level
1632 // window must be added to the end of its own list, because otherwise the
1633 // window manager adds it to the front (as required by the ICCCM). Thanks
1634 // to Paul Mackerras for providing this info in his TK photo widget.
1635 //
1636 
1637 #else
1638  int count = 0;
1639  Window top, colormap_windows[5];
1640 
1641  top = Tk_WindowId( Tk_MainWindow( plFramePtr->interp ) );
1642 
1643  colormap_windows[count++] = Tk_WindowId( plFramePtr->tkwin );
1644  colormap_windows[count++] = top;
1645 
1646  if ( !XSetWMColormapWindows( plFramePtr->display,
1647  top, colormap_windows, count ) )
1648  fprintf( stderr, "Unable to set color map property!\n" );
1649 #endif
1650 }
1651 
1652 //
1653 //--------------------------------------------------------------------------
1654 //
1655 // DisplayPlFrame --
1656 //
1657 // This procedure is invoked to display a plframe widget.
1658 //
1659 // Results:
1660 // None.
1661 //
1662 // Side effects:
1663 // Commands are output to X to display the plframe in its
1664 // current mode.
1665 //
1666 //--------------------------------------------------------------------------
1667 //
1668 
1669 static void
1670 DisplayPlFrame( ClientData clientData )
1671 {
1672  register PlFrame *plFramePtr = (PlFrame *) clientData;
1673  register Tk_Window tkwin = plFramePtr->tkwin;
1674 
1675  dbug_enter( "DisplayPlFrame" );
1676 
1677 // Update scrollbars if needed
1678 
1679  if ( plFramePtr->flags & UPDATE_V_SCROLLBAR )
1680  {
1681  UpdateVScrollbar( plFramePtr );
1682  }
1683  if ( plFramePtr->flags & UPDATE_H_SCROLLBAR )
1684  {
1685  UpdateHScrollbar( plFramePtr );
1686  }
1687  plFramePtr->flags &= ~( UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR );
1688 
1689 // If not mapped yet, just return and cancel pending refresh
1690 
1691  if ( ( plFramePtr->tkwin == NULL ) || !Tk_IsMapped( tkwin ) )
1692  {
1693  plFramePtr->flags &= ~REFRESH_PENDING;
1694  return;
1695  }
1696 
1697 // Redraw border if necessary
1698 
1699  if ( ( plFramePtr->border != NULL ) &&
1700  ( plFramePtr->relief != TK_RELIEF_FLAT ) )
1701  {
1702 #if TK_MAJOR_VERSION >= 4 && TK_MINOR_VERSION >= 0
1703  Tk_Draw3DRectangle( plFramePtr->tkwin, Tk_WindowId( tkwin ),
1704  plFramePtr->border, 0, 0, Tk_Width( tkwin ), Tk_Height( tkwin ),
1705  plFramePtr->borderWidth, plFramePtr->relief );
1706 #else
1707  Tk_Draw3DRectangle( plFramePtr->display, Tk_WindowId( tkwin ),
1708  plFramePtr->border, 0, 0, Tk_Width( tkwin ), Tk_Height( tkwin ),
1709  plFramePtr->borderWidth, plFramePtr->relief );
1710 #endif
1711  }
1712 
1713 // All refresh events
1714 
1715  if ( plFramePtr->flags & REFRESH_PENDING )
1716  {
1717  plFramePtr->flags &= ~REFRESH_PENDING;
1718 
1719  // Reschedule resizes to avoid occasional ordering conflicts with
1720  // the packer's resize of the window (this call must come last).
1721 
1722  if ( plFramePtr->flags & RESIZE_PENDING )
1723  {
1724  plFramePtr->flags |= REFRESH_PENDING;
1725  plFramePtr->flags &= ~RESIZE_PENDING;
1726  Tk_DoWhenIdle( DisplayPlFrame, clientData );
1727  return;
1728  }
1729 
1730  // Redraw -- replay contents of plot buffer
1731 
1732  if ( plFramePtr->flags & REDRAW_PENDING )
1733  {
1734  plFramePtr->flags &= ~REDRAW_PENDING;
1735  plsstrm( plFramePtr->ipls );
1736  pl_cmd( PLESC_REDRAW, (void *) NULL );
1737  }
1738 
1739  // Resize -- if window bounds have changed
1740 
1741  else if ( ( plFramePtr->width != plFramePtr->prevWidth ) ||
1742  ( plFramePtr->height != plFramePtr->prevHeight ) )
1743  {
1744  plFramePtr->pldis.width = (unsigned int) plFramePtr->width;
1745  plFramePtr->pldis.height = (unsigned int) plFramePtr->height;
1746 
1747  plsstrm( plFramePtr->ipls );
1748  pl_cmd( PLESC_RESIZE, (void *) &( plFramePtr->pldis ) );
1749  plFramePtr->prevWidth = plFramePtr->width;
1750  plFramePtr->prevHeight = plFramePtr->height;
1751  }
1752 
1753  // Expose -- if window bounds are unchanged
1754 
1755  else
1756  {
1757  plsstrm( plFramePtr->ipls );
1758  if ( plFramePtr->drawing_xhairs )
1759  {
1760  XClearWindow( plFramePtr->display, Tk_WindowId( tkwin ) );
1761  XFlush( plFramePtr->display );
1762  pl_cmd( PLESC_EXPOSE, NULL );
1763  }
1764  else
1765  {
1766  pl_cmd( PLESC_EXPOSE, (void *) &( plFramePtr->pldis ) );
1767  }
1768 
1769  // Reset window bounds so that next time they are set fresh
1770 
1771  plFramePtr->pldis.x = (unsigned int) ( Tk_X( tkwin ) + Tk_Width( tkwin ) );
1772  plFramePtr->pldis.y = (unsigned int) ( Tk_Y( tkwin ) + Tk_Height( tkwin ) );
1773  plFramePtr->pldis.width = (unsigned int) ( -Tk_Width( tkwin ) );
1774  plFramePtr->pldis.height = (unsigned int) ( -Tk_Height( tkwin ) );
1775  }
1776 
1777  // Update graphic crosshairs if necessary
1778 
1779  if ( plFramePtr->drawing_xhairs )
1780  {
1781  UpdateXhairs( plFramePtr );
1782  }
1783 
1784  // Update rubber band if necessary.
1785 
1786  if ( plFramePtr->drawing_rband )
1787  {
1788  UpdateRband( plFramePtr );
1789  }
1790  }
1791 }
1792 
1793 //--------------------------------------------------------------------------
1794 // Routines to process widget commands.
1795 //--------------------------------------------------------------------------
1796 
1797 //--------------------------------------------------------------------------
1798 // scol0
1799 //
1800 // Sets a color in cmap0.
1801 //--------------------------------------------------------------------------
1802 
1803 static int
1804 scol0( Tcl_Interp *interp, register PlFrame *plFramePtr,
1805  int i, const char *col, int *p_changed )
1806 {
1807  PLStream *pls = plFramePtr->pls;
1808  XColor xcol;
1809  PLINT r, g, b;
1810 
1811  if ( col == NULL )
1812  {
1813  Tcl_AppendResult( interp, "color value not specified",
1814  (char *) NULL );
1815  return TCL_ERROR;
1816  }
1817 
1818  if ( !XParseColor( plFramePtr->display,
1819  Tk_Colormap( plFramePtr->tkwin ), col, &xcol ) )
1820  {
1821  Tcl_AppendResult( interp, "Couldn't parse color ", col,
1822  (char *) NULL );
1823  return TCL_ERROR;
1824  }
1825 
1826  r = (unsigned) ( xcol.red & 0xFF00 ) >> 8;
1827  g = (unsigned) ( xcol.green & 0xFF00 ) >> 8;
1828  b = (unsigned) ( xcol.blue & 0xFF00 ) >> 8;
1829 
1830  if ( ( pls->cmap0[i].r != r ) ||
1831  ( pls->cmap0[i].g != g ) ||
1832  ( pls->cmap0[i].b != b ) )
1833  {
1834  pls->cmap0[i].r = (unsigned char) r;
1835  pls->cmap0[i].g = (unsigned char) g;
1836  pls->cmap0[i].b = (unsigned char) b;
1837  *p_changed = 1;
1838  }
1839 
1840  return TCL_OK;
1841 }
1842 
1843 //--------------------------------------------------------------------------
1844 // scol1
1845 //
1846 // Sets a color in cmap1.
1847 //--------------------------------------------------------------------------
1848 
1849 static int
1850 scol1( Tcl_Interp *interp, register PlFrame *plFramePtr,
1851  int i, const char *col, const char *pos, const char *rev, int *p_changed )
1852 {
1853  PLStream *pls = plFramePtr->pls;
1854  XColor xcol;
1855  PLFLT h, l, s, r, g, b, p;
1856  int reverse;
1857 
1858  if ( col == NULL )
1859  {
1860  Tcl_AppendResult( interp, "color value not specified",
1861  (char *) NULL );
1862  return TCL_ERROR;
1863  }
1864 
1865  if ( pos == NULL )
1866  {
1867  Tcl_AppendResult( interp, "control point position not specified",
1868  (char *) NULL );
1869  return TCL_ERROR;
1870  }
1871 
1872  if ( rev == NULL )
1873  {
1874  Tcl_AppendResult( interp, "interpolation sense not specified",
1875  (char *) NULL );
1876  return TCL_ERROR;
1877  }
1878 
1879  if ( !XParseColor( plFramePtr->display,
1880  Tk_Colormap( plFramePtr->tkwin ), col, &xcol ) )
1881  {
1882  Tcl_AppendResult( interp, "Couldn't parse color ", col,
1883  (char *) NULL );
1884  return TCL_ERROR;
1885  }
1886 
1887  r = ( (unsigned) ( xcol.red & 0xFF00 ) >> 8 ) / 255.0;
1888  g = ( (unsigned) ( xcol.green & 0xFF00 ) >> 8 ) / 255.0;
1889  b = ( (unsigned) ( xcol.blue & 0xFF00 ) >> 8 ) / 255.0;
1890 
1891  plrgbhls( r, g, b, &h, &l, &s );
1892 
1893  p = atof( pos ) / 100.0;
1894  reverse = atoi( rev );
1895 
1896  if ( ( pls->cmap1cp[i].h != h ) ||
1897  ( pls->cmap1cp[i].l != l ) ||
1898  ( pls->cmap1cp[i].s != s ) ||
1899  ( pls->cmap1cp[i].p != p ) ||
1900  ( pls->cmap1cp[i].alt_hue_path != reverse ) )
1901  {
1902  pls->cmap1cp[i].h = h;
1903  pls->cmap1cp[i].l = l;
1904  pls->cmap1cp[i].s = s;
1905  pls->cmap1cp[i].p = p;
1906  pls->cmap1cp[i].alt_hue_path = reverse;
1907  *p_changed = 1;
1908  }
1909  return TCL_OK;
1910 }
1911 
1912 //--------------------------------------------------------------------------
1913 // ColorManip
1914 //
1915 // Processes color manipulation widget commands.
1916 //
1917 // This provides an alternate API for the plplot color handling functions
1918 // (prepend a "pl" to get the corresponding plplot function). They differ
1919 // from the versions in the Tcl API in the following ways:
1920 //
1921 // - X11 conventions are used rather than plplot ones. XParseColor is used
1922 // to convert a string into its 3 rgb components. This lets you use
1923 // symbolic names or hex notation for color values.
1924 //
1925 // - these expect/emit Tcl array values in lists rather than in tclmatrix
1926 // form, like most "normal" Tcl tools. For usage, see the examples in the
1927 // palette tools (plcolor.tcl).
1928 //--------------------------------------------------------------------------
1929 
1930 static int
1931 ColorManip( Tcl_Interp *interp, register PlFrame *plFramePtr,
1932  int argc, const char **argv )
1933 {
1934  PLStream *pls = plFramePtr->pls;
1935  int length;
1936  char c;
1937  int result = TCL_OK;
1938  char *tmpstring;
1939 
1940 #ifdef DEBUG
1941  if ( pls->debug )
1942  {
1943  int i;
1944  fprintf( stderr, "There are %d arguments to ColorManip:", argc );
1945  for ( i = 0; i < argc; i++ )
1946  {
1947  fprintf( stderr, " %s", argv[i] );
1948  }
1949  fprintf( stderr, "\n" );
1950  }
1951 #else
1952  (void) argc; // Cast to void to suppress compiler warning about unused parameter
1953 #endif
1954 
1955 // Make sure widget has been initialized before going any further
1956 
1957  if ( !plFramePtr->tkwin_initted )
1958  {
1959  Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
1960  }
1961 
1962 // Set stream number and get ready to process the command
1963 
1964  plsstrm( plFramePtr->ipls );
1965 
1966  c = argv[0][0];
1967  length = (int) strlen( argv[0] );
1968 
1969 // gcmap0 -- get color map 0
1970 // first arg is number of colors, the rest are hex number specifications
1971 
1972  if ( ( c == 'g' ) && ( strncmp( argv[0], "gcmap0", (size_t) length ) == 0 ) )
1973  {
1974  int i;
1975  unsigned long plcolor;
1976  char str[10];
1977 
1978  sprintf( str, "%d", (int) pls->ncol0 );
1979  Tcl_AppendElement( interp, str );
1980  for ( i = 0; i < pls->ncol0; i++ )
1981  {
1982  plcolor = (unsigned long) ( ( pls->cmap0[i].r << 16 ) |
1983  ( pls->cmap0[i].g << 8 ) |
1984  ( pls->cmap0[i].b ) );
1985 
1986  sprintf( str, "#%06lx", ( plcolor & 0xFFFFFF ) );
1987  Tcl_AppendElement( interp, str );
1988  }
1989  result = TCL_OK;
1990  }
1991 
1992 // gcmap1 -- get color map 1
1993 // first arg is number of control points
1994 // the rest are hex number specifications followed by positions (0-100)
1995 
1996  else if ( ( c == 'g' ) && ( strncmp( argv[0], "gcmap1", (size_t) length ) == 0 ) )
1997  {
1998  int i;
1999  unsigned long plcolor;
2000  char str[10];
2001  PLFLT h, l, s, r, g, b;
2002  int r1, g1, b1;
2003 
2004  sprintf( str, "%d", (int) pls->ncp1 );
2005  Tcl_AppendElement( interp, str );
2006  for ( i = 0; i < pls->ncp1; i++ )
2007  {
2008  h = pls->cmap1cp[i].h;
2009  l = pls->cmap1cp[i].l;
2010  s = pls->cmap1cp[i].s;
2011 
2012  plhlsrgb( h, l, s, &r, &g, &b );
2013 
2014  r1 = MAX( 0, MIN( 255, (int) ( 256. * r ) ) );
2015  g1 = MAX( 0, MIN( 255, (int) ( 256. * g ) ) );
2016  b1 = MAX( 0, MIN( 255, (int) ( 256. * b ) ) );
2017 
2018  plcolor = (unsigned long) ( ( r1 << 16 ) | ( g1 << 8 ) | ( b1 ) );
2019 
2020  sprintf( str, "#%06lx", ( plcolor & 0xFFFFFF ) );
2021  Tcl_AppendElement( interp, str );
2022 
2023  sprintf( str, "%02d", (int) ( 100 * pls->cmap1cp[i].p ) );
2024  Tcl_AppendElement( interp, str );
2025 
2026  sprintf( str, "%01d", (int) ( pls->cmap1cp[i].alt_hue_path ) );
2027  Tcl_AppendElement( interp, str );
2028  }
2029  result = TCL_OK;
2030  }
2031 
2032 // scmap0 -- set color map 0
2033 // first arg is number of colors, the rest are hex number specifications
2034 
2035  else if ( ( c == 's' ) && ( strncmp( argv[0], "scmap0", (size_t) length ) == 0 ) )
2036  {
2037  int i, changed = 1, ncol0 = atoi( argv[1] );
2038  char *col;
2039 
2040  if ( ncol0 > 16 || ncol0 < 1 )
2041  {
2042  Tcl_AppendResult( interp, "illegal number of colors in cmap0: ",
2043  argv[1], (char *) NULL );
2044  return TCL_ERROR;
2045  }
2046 
2047  pls->ncol0 = ncol0;
2048  tmpstring = (char *) malloc( strlen( argv[2] ) + 1 );
2049  strcpy( tmpstring, argv[2] );
2050  col = strtok( tmpstring, " " );
2051  for ( i = 0; i < pls->ncol0; i++ )
2052  {
2053  if ( col == NULL )
2054  break;
2055 
2056  if ( scol0( interp, plFramePtr, i, col, &changed ) != TCL_OK )
2057  return TCL_ERROR;
2058 
2059  col = strtok( NULL, " " );
2060  }
2061  free( tmpstring );
2062 
2063  if ( changed )
2065  }
2066 
2067 // scmap1 -- set color map 1
2068 // first arg is number of colors, the rest are hex number specifications
2069 
2070  else if ( ( c == 's' ) && ( strncmp( argv[0], "scmap1", (size_t) length ) == 0 ) )
2071  {
2072  int i, changed = 1, ncp1 = atoi( argv[1] );
2073  char *col, *pos, *rev;
2074 
2075  if ( ncp1 > 32 || ncp1 < 1 )
2076  {
2077  Tcl_AppendResult( interp,
2078  "illegal number of control points in cmap1: ",
2079  argv[1], (char *) NULL );
2080  return TCL_ERROR;
2081  }
2082 
2083  tmpstring = (char *) malloc( strlen( argv[2] ) + 1 );
2084  strcpy( tmpstring, argv[2] );
2085  col = strtok( tmpstring, " " );
2086  pos = strtok( NULL, " " );
2087  rev = strtok( NULL, " " );
2088  for ( i = 0; i < ncp1; i++ )
2089  {
2090  if ( col == NULL )
2091  break;
2092 
2093  if ( scol1( interp, plFramePtr,
2094  i, col, pos, rev, &changed ) != TCL_OK )
2095  return TCL_ERROR;
2096 
2097  col = strtok( NULL, " " );
2098  pos = strtok( NULL, " " );
2099  rev = strtok( NULL, " " );
2100  }
2101  free( tmpstring );
2102 
2103  if ( changed )
2104  {
2105  plFramePtr->pls->ncp1 = ncp1;
2106  plcmap1_calc();
2107  }
2108  }
2109 
2110 // scol0 -- set single color in cmap0
2111 // first arg is the color number, the next is the color in hex
2112 
2113  else if ( ( c == 's' ) && ( strncmp( argv[0], "scol0", (size_t) length ) == 0 ) )
2114  {
2115  int i = atoi( argv[1] ), changed = 1;
2116 
2117  if ( i > pls->ncol0 || i < 0 )
2118  {
2119  Tcl_AppendResult( interp, "illegal color number in cmap0: ",
2120  argv[1], (char *) NULL );
2121  return TCL_ERROR;
2122  }
2123 
2124  if ( scol0( interp, plFramePtr, i, argv[2], &changed ) != TCL_OK )
2125  return TCL_ERROR;
2126 
2127  if ( changed )
2129  }
2130 
2131 // scol1 -- set color of control point in cmap1
2132 // first arg is the control point, the next two are the color in hex and pos
2133 
2134  else if ( ( c == 's' ) && ( strncmp( argv[0], "scol1", (size_t) length ) == 0 ) )
2135  {
2136  int i = atoi( argv[1] ), changed = 1;
2137 
2138  if ( i > pls->ncp1 || i < 0 )
2139  {
2140  Tcl_AppendResult( interp, "illegal control point number in cmap1: ",
2141  argv[1], (char *) NULL );
2142  return TCL_ERROR;
2143  }
2144 
2145  if ( scol1( interp, plFramePtr,
2146  i, argv[2], argv[3], argv[4], &changed ) != TCL_OK )
2147  return TCL_ERROR;
2148 
2149  if ( changed )
2150  plcmap1_calc();
2151  }
2152 
2153  plflush();
2154  return result;
2155 }
2156 
2157 //--------------------------------------------------------------------------
2158 // Cmd
2159 //
2160 // Processes "cmd" widget command.
2161 // Handles commands that go more or less directly to the PLplot library.
2162 // Most of these come out of the PLplot Tcl API support file.
2163 //--------------------------------------------------------------------------
2164 
2165 static int
2166 Cmd( Tcl_Interp *interp, register PlFrame *plFramePtr,
2167  int argc, const char **argv )
2168 {
2169  int result = TCL_OK;
2170  char cmdlist[] = "";
2171 
2172 #ifdef DEBUG
2173  PLStream *pls = plFramePtr->pls;
2174  if ( pls->debug )
2175  {
2176  int i;
2177  fprintf( stderr, "There are %d arguments to Cmd:", argc );
2178  for ( i = 0; i < argc; i++ )
2179  {
2180  fprintf( stderr, " %s", argv[i] );
2181  }
2182  fprintf( stderr, "\n" );
2183  }
2184 #endif
2185 
2186 // no option -- return list of available PLplot commands
2187 
2188  if ( argc == 0 )
2189  return plTclCmd( cmdlist, interp, argc, argv );
2190 
2191 // Make sure widget has been initialized before going any further
2192 
2193  if ( !plFramePtr->tkwin_initted )
2194  {
2195  Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
2196  }
2197 
2198 // Set stream number and get ready to process the command
2199 
2200  plsstrm( plFramePtr->ipls );
2201 
2202 // Process command
2203 
2204  result = plTclCmd( cmdlist, interp, argc, argv );
2205 
2206  plflush();
2207  return result;
2208 }
2209 
2210 //
2211 //--------------------------------------------------------------------------
2212 //
2213 // ConfigurePlFrame --
2214 //
2215 // This procedure is called to process an argv/argc list, plus the Tk
2216 // option database, in order to configure (or reconfigure) a
2217 // plframe widget.
2218 //
2219 // Results:
2220 // The return value is a standard Tcl result. If TCL_ERROR is
2221 // returned, then interp->result contains an error message.
2222 //
2223 // Side effects:
2224 // Configuration information, such as text string, colors, font, etc.
2225 // get set for plFramePtr; old resources get freed, if there were
2226 // any.
2227 //
2228 //--------------------------------------------------------------------------
2229 //
2230 
2231 static int
2232 ConfigurePlFrame( Tcl_Interp *interp, register PlFrame *plFramePtr,
2233  int argc, const char **argv, int flags )
2234 {
2235  register Tk_Window tkwin = plFramePtr->tkwin;
2236  PLStream *pls = plFramePtr->pls;
2237  XwDev *dev = (XwDev *) pls->dev;
2238  XwDisplay *xwd = (XwDisplay *) dev->xwd;
2239  XGCValues gcValues;
2240  unsigned long mask;
2241  int need_redisplay = 0;
2242 
2243 #ifdef DEBUG
2244  if ( pls->debug )
2245  {
2246  int i;
2247  fprintf( stderr, "Arguments to configure are:" );
2248  for ( i = 0; i < argc; i++ )
2249  {
2250  fprintf( stderr, " %s", argv[i] );
2251  }
2252  fprintf( stderr, "\n" );
2253  }
2254 #endif
2255 
2256  dbug_enter( "ConfigurePlFrame" );
2257 
2258  if ( Tk_ConfigureWidget( interp, tkwin, configSpecs,
2259  argc, (CONST char **) argv, (char *) plFramePtr, flags ) != TCL_OK )
2260  {
2261  return TCL_ERROR;
2262  }
2263 
2264 //
2265 // Set background color using xwin driver's pixel value. Done this way so
2266 // that (a) we can use r/w color cells, and (b) the BG pixel values as set
2267 // here and in the xwin driver are consistent.
2268 //
2269 
2270  plsstrm( plFramePtr->ipls );
2271  plP_esc( PLESC_DEV2PLCOL, (void *) plFramePtr->bgColor );
2272  pl_cpcolor( &pls->cmap0[0], &pls->tmpcolor );
2273  plP_esc( PLESC_SETBGFG, NULL );
2274 
2275  Tk_SetWindowBackground( tkwin, xwd->cmap0[0].pixel );
2276  Tk_SetWindowBorder( tkwin, xwd->cmap0[0].pixel );
2277 
2278 // Set up GC for rubber-band draws
2279 
2280  gcValues.background = xwd->cmap0[0].pixel;
2281  gcValues.foreground = 0xFF;
2282  gcValues.function = GXxor;
2283  mask = GCForeground | GCBackground | GCFunction;
2284 
2285  if ( plFramePtr->xorGC != NULL )
2286  Tk_FreeGC( plFramePtr->display, plFramePtr->xorGC );
2287 
2288  plFramePtr->xorGC = Tk_GetGC( plFramePtr->tkwin, mask, &gcValues );
2289 
2290 // Geometry settings
2291 
2292  Tk_SetInternalBorder( tkwin, plFramePtr->borderWidth );
2293  if ( ( plFramePtr->width > 0 ) || ( plFramePtr->height > 0 ) )
2294  {
2295  Tk_GeometryRequest( tkwin, plFramePtr->width, plFramePtr->height );
2296  if ( ( plFramePtr->width != plFramePtr->prevWidth ) ||
2297  ( plFramePtr->height != plFramePtr->prevHeight ) )
2298  need_redisplay = 1;
2299  }
2300 
2301 // Create or destroy graphic crosshairs as specified
2302 
2303  if ( Tk_IsMapped( tkwin ) )
2304  {
2305  if ( plFramePtr->xhairs )
2306  {
2307  if ( !plFramePtr->drawing_xhairs )
2308  CreateXhairs( plFramePtr );
2309  }
2310  else
2311  {
2312  if ( plFramePtr->drawing_xhairs )
2313  DestroyXhairs( plFramePtr );
2314  }
2315  }
2316 
2317 // Create or destroy rubber band as specified
2318 
2319  if ( Tk_IsMapped( tkwin ) )
2320  {
2321  if ( plFramePtr->rband )
2322  {
2323  if ( !plFramePtr->drawing_rband )
2324  CreateRband( plFramePtr );
2325  }
2326  else
2327  {
2328  if ( plFramePtr->drawing_rband )
2329  DestroyRband( plFramePtr );
2330  }
2331  }
2332 
2333 // Arrange for window to be refreshed if necessary
2334 
2335  if ( need_redisplay && Tk_IsMapped( tkwin )
2336  && !( plFramePtr->flags & REFRESH_PENDING ) )
2337  {
2338  Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
2339  plFramePtr->flags |= REFRESH_PENDING;
2340  plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
2341  }
2342 
2343  return TCL_OK;
2344 }
2345 
2346 //--------------------------------------------------------------------------
2347 // Draw
2348 //
2349 // Processes "draw" widget command.
2350 // Handles rubber-band drawing.
2351 //--------------------------------------------------------------------------
2352 
2353 static int
2354 Draw( Tcl_Interp *interp, register PlFrame *plFramePtr,
2355  int argc, const char **argv )
2356 {
2357  register Tk_Window tkwin = plFramePtr->tkwin;
2358  int result = TCL_OK;
2359  char c = argv[0][0];
2360  int length = (int) strlen( argv[0] );
2361 
2362 // Make sure widget has been initialized before going any further
2363 
2364  if ( !plFramePtr->tkwin_initted )
2365  {
2366  Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
2367  }
2368 
2369 // init -- sets up for rubber-band drawing
2370 
2371  if ( ( c == 'i' ) && ( strncmp( argv[0], "init", (size_t) length ) == 0 ) )
2372  {
2373  Tk_DefineCursor( tkwin, plFramePtr->xhair_cursor );
2374  }
2375 
2376 // end -- ends rubber-band drawing
2377 
2378  else if ( ( c == 'e' ) && ( strncmp( argv[0], "end", (size_t) length ) == 0 ) )
2379  {
2380  Tk_DefineCursor( tkwin, plFramePtr->cursor );
2381  if ( plFramePtr->continue_draw )
2382  {
2383  XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
2384  plFramePtr->xorGC, plFramePtr->pts, 5,
2385  CoordModeOrigin );
2386  XSync( Tk_Display( tkwin ), 0 );
2387  }
2388 
2389  plFramePtr->continue_draw = 0;
2390  }
2391 
2392 // rect -- draw a rectangle, used to select rectangular areas
2393 // first draw erases old outline
2394 
2395  else if ( ( c == 'r' ) && ( strncmp( argv[0], "rect", (size_t) length ) == 0 ) )
2396  {
2397  if ( argc < 5 )
2398  {
2399  Tcl_AppendResult( interp, "wrong # args: should be \"",
2400  " draw rect x0 y0 x1 y1\"", (char *) NULL );
2401  result = TCL_ERROR;
2402  }
2403  else
2404  {
2405  int x0, y0, x1, y1;
2406  int xmin = 0, xmax = Tk_Width( tkwin ) - 1;
2407  int ymin = 0, ymax = Tk_Height( tkwin ) - 1;
2408 
2409  x0 = atoi( argv[1] );
2410  y0 = atoi( argv[2] );
2411  x1 = atoi( argv[3] );
2412  y1 = atoi( argv[4] );
2413 
2414  x0 = MAX( xmin, MIN( xmax, x0 ) );
2415  y0 = MAX( ymin, MIN( ymax, y0 ) );
2416  x1 = MAX( xmin, MIN( xmax, x1 ) );
2417  y1 = MAX( ymin, MIN( ymax, y1 ) );
2418 
2419  if ( plFramePtr->continue_draw )
2420  {
2421  XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
2422  plFramePtr->xorGC, plFramePtr->pts, 5,
2423  CoordModeOrigin );
2424  XSync( Tk_Display( tkwin ), 0 );
2425  }
2426 
2427  plFramePtr->pts[0].x = (short) x0; plFramePtr->pts[0].y = (short) y0;
2428  plFramePtr->pts[1].x = (short) x1; plFramePtr->pts[1].y = (short) y0;
2429  plFramePtr->pts[2].x = (short) x1; plFramePtr->pts[2].y = (short) y1;
2430  plFramePtr->pts[3].x = (short) x0; plFramePtr->pts[3].y = (short) y1;
2431  plFramePtr->pts[4].x = (short) x0; plFramePtr->pts[4].y = (short) y0;
2432 
2433  XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
2434  plFramePtr->xorGC, plFramePtr->pts, 5,
2435  CoordModeOrigin );
2436  XSync( Tk_Display( tkwin ), 0 );
2437 
2438  plFramePtr->continue_draw = 1;
2439  }
2440  }
2441 
2442  return result;
2443 }
2444 
2445 //--------------------------------------------------------------------------
2446 // Info
2447 //
2448 // Processes "info" widget command.
2449 // Returns requested info.
2450 //--------------------------------------------------------------------------
2451 
2452 static int
2453 Info( Tcl_Interp *interp, register PlFrame *plFramePtr,
2454  int argc, const char **argv )
2455 {
2456  int length;
2457  char c;
2458  int result = TCL_OK;
2459 
2460 // no option -- return list of available info commands
2461 
2462  if ( argc == 0 )
2463  {
2464  Tcl_SetResult( interp, "devkeys devnames", TCL_STATIC );
2465  return TCL_OK;
2466  }
2467 
2468  c = argv[0][0];
2469  length = (int) strlen( argv[0] );
2470 
2471 // devkeys -- return list of supported device keywords
2472 
2473  if ( ( c == 'd' ) && ( strncmp( argv[0], "devkeys", (size_t) length ) == 0 ) )
2474  {
2475  int i = 0;
2476  while ( plFramePtr->devName[i] != NULL )
2477  Tcl_AppendElement( interp, plFramePtr->devName[i++] );
2478 
2479  result = TCL_OK;
2480  }
2481 
2482 // devkeys -- return list of supported device types
2483 
2484  else if ( ( c == 'd' ) && ( strncmp( argv[0], "devnames", (size_t) length ) == 0 ) )
2485  {
2486  int i = 0;
2487  while ( plFramePtr->devDesc[i] != NULL )
2488  Tcl_AppendElement( interp, plFramePtr->devDesc[i++] );
2489 
2490  result = TCL_OK;
2491  }
2492 
2493 // unrecognized
2494 
2495  else
2496  {
2497  Tcl_AppendResult( interp, "bad option to \"info\": must be ",
2498  "devkeys, devnames", (char *) NULL );
2499 
2500  result = TCL_ERROR;
2501  }
2502 
2503  return result;
2504 }
2505 
2506 //--------------------------------------------------------------------------
2507 // Openlink
2508 //
2509 // Processes "openlink" widget command.
2510 // Opens channel (FIFO or socket) for binary data transfer between client
2511 // and server.
2512 //--------------------------------------------------------------------------
2513 
2514 static int
2515 Openlink( Tcl_Interp *interp, register PlFrame *plFramePtr,
2516  int argc, const char **argv )
2517 {
2518  register PLRDev *plr = plFramePtr->plr;
2519  register PLiodev *iodev = plr->iodev;
2520 
2521  char c = argv[0][0];
2522  int length = (int) strlen( argv[0] );
2523 
2524  dbug_enter( "Openlink" );
2525 
2526 // Open fifo
2527 
2528  if ( ( c == 'f' ) && ( strncmp( argv[0], "fifo", (size_t) length ) == 0 ) )
2529  {
2530  if ( argc < 1 )
2531  {
2532  Tcl_AppendResult( interp, "bad command -- must be: ",
2533  "openlink fifo <pathname>",
2534  (char *) NULL );
2535  return TCL_ERROR;
2536  }
2537  if ( ( iodev->fd = open( argv[1], O_RDONLY ) ) == -1 )
2538  {
2539  Tcl_AppendResult( interp, "cannot open fifo ", argv[1],
2540  " for read", (char *) NULL );
2541  return TCL_ERROR;
2542  }
2543  iodev->type = 0;
2544  iodev->typeName = "fifo";
2545  iodev->file = fdopen( iodev->fd, "rb" );
2546  }
2547 
2548 // Open socket
2549 
2550  else if ( ( c == 's' ) && ( strncmp( argv[0], "socket", (size_t) length ) == 0 ) )
2551  {
2552  if ( argc < 1 )
2553  {
2554  Tcl_AppendResult( interp, "bad command -- must be: ",
2555  "openlink socket <sock-id>",
2556  (char *) NULL );
2557  return TCL_ERROR;
2558  }
2559  iodev->type = 1;
2560  iodev->typeName = "socket";
2561  iodev->fileHandle = argv[1];
2562 
2563 #if TCL_MAJOR_VERSION < 7 || ( TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION == 4 )
2564 #define FILECAST
2565 #else
2566 #define FILECAST ( ClientData )
2567 #endif
2568 
2569 // Exclude UNIX-only feature
2570 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
2571  if ( Tcl_GetOpenFile( interp, iodev->fileHandle,
2572  0, 1, FILECAST & iodev->file ) != TCL_OK )
2573  {
2574  return TCL_ERROR;
2575  }
2576 #endif
2577  iodev->fd = fileno( iodev->file );
2578  }
2579 
2580 // unrecognized
2581 
2582  else
2583  {
2584  Tcl_AppendResult( interp, "bad option to \"openlink\": must be ",
2585  "fifo or socket", (char *) NULL );
2586 
2587  return TCL_ERROR;
2588  }
2589 
2590  plr->pdfs = pdf_bopen( NULL, 4200 );
2591 // Sheesh, what a mess. I don't see how Tk4.1's converter macro could
2592 // possibly work.
2593 #if TK_MAJOR_VERSION < 4 || \
2594  ( TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION == 0 ) || \
2595  TK_MAJOR_VERSION > 7
2596 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
2597  Tk_CreateFileHandler( iodev->fd, TK_READABLE, (Tk_FileProc *) ReadData,
2598  (ClientData) plFramePtr );
2599 #endif
2600 #else
2601 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
2602  Tcl_CreateFileHandler( Tcl_GetFile( (ClientData) iodev->fd, TCL_UNIX_FD ),
2603  TK_READABLE, (Tk_FileProc *) ReadData,
2604  (ClientData) plFramePtr );
2605 #endif
2606 #endif
2607 
2608  return TCL_OK;
2609 }
2610 
2611 //--------------------------------------------------------------------------
2612 // Closelink
2613 //
2614 // Processes "closelink" widget command.
2615 // CLoses channel previously opened with the "openlink" widget command.
2616 //--------------------------------------------------------------------------
2617 
2618 static int
2619 Closelink( Tcl_Interp *interp, register PlFrame *plFramePtr,
2620  int PL_UNUSED( argc ), const char ** PL_UNUSED( argv ) )
2621 {
2622  register PLRDev *plr = plFramePtr->plr;
2623  register PLiodev *iodev = plr->iodev;
2624 
2625  dbug_enter( "Closelink" );
2626 
2627  if ( iodev->fd == 0 )
2628  {
2629  Tcl_AppendResult( interp, "no link currently open", (char *) NULL );
2630  return TCL_ERROR;
2631  }
2632 
2633 #if TK_MAJOR_VERSION < 4 || \
2634  ( TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION == 0 ) || \
2635  TK_MAJOR_VERSION > 7
2636 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
2637  Tk_DeleteFileHandler( iodev->fd );
2638 #endif
2639 #else
2640 // Tk_DeleteFileHandler( iodev->file );
2641 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
2642  Tcl_DeleteFileHandler( Tcl_GetFile( (ClientData) iodev->fd,
2643  TCL_UNIX_FD ) );
2644 #endif
2645 #endif
2646  pdf_close( plr->pdfs );
2647  iodev->fd = 0;
2648 
2649  return TCL_OK;
2650 }
2651 
2652 //--------------------------------------------------------------------------
2653 // process_data
2654 //
2655 // Utility function for processing data and other housekeeping.
2656 //--------------------------------------------------------------------------
2657 
2658 static int
2659 process_data( Tcl_Interp *interp, register PlFrame *plFramePtr )
2660 {
2661  register PLRDev *plr = plFramePtr->plr;
2662  register PLiodev *iodev = plr->iodev;
2663  int result = TCL_OK;
2664 
2665 // Process data
2666 
2667  if ( plr_process( plr ) == -1 )
2668  {
2669  Tcl_AppendResult( interp, "unable to read from ", iodev->typeName,
2670  (char *) NULL );
2671  result = TCL_ERROR;
2672  }
2673 
2674 // Signal bop if necessary
2675 
2676  if ( plr->at_bop && plFramePtr->bopCmd != NULL )
2677  {
2678  plr->at_bop = 0;
2679  if ( Tcl_Eval( interp, plFramePtr->bopCmd ) != TCL_OK )
2680  fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
2681  plFramePtr->bopCmd, Tcl_GetStringResult( interp ) );
2682  }
2683 
2684 // Signal eop if necessary
2685 
2686  if ( plr->at_eop && plFramePtr->eopCmd != NULL )
2687  {
2688  plr->at_eop = 0;
2689  if ( Tcl_Eval( interp, plFramePtr->eopCmd ) != TCL_OK )
2690  fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
2691  plFramePtr->eopCmd, Tcl_GetStringResult( interp ) );
2692  }
2693 
2694  return result;
2695 }
2696 
2697 //--------------------------------------------------------------------------
2698 // ReadData
2699 //
2700 // Reads & processes data.
2701 // Intended to be installed as a filehandler command.
2702 //--------------------------------------------------------------------------
2703 
2704 static int
2705 ReadData( ClientData clientData, int mask )
2706 {
2707  register PlFrame *plFramePtr = (PlFrame *) clientData;
2708  register Tcl_Interp *interp = plFramePtr->interp;
2709 
2710  register PLRDev *plr = plFramePtr->plr;
2711  register PLiodev *iodev = plr->iodev;
2712  register PDFstrm *pdfs = plr->pdfs;
2713  int result = TCL_OK;
2714 
2715  if ( mask & TK_READABLE )
2716  {
2717  // Read from FIFO or socket
2718 
2719  plsstrm( plFramePtr->ipls );
2720  if ( pl_PacketReceive( interp, iodev, pdfs ) )
2721  {
2722  Tcl_AppendResult( interp, "Packet receive failed:\n\t %s\n",
2723  (char *) NULL );
2724  return TCL_ERROR;
2725  }
2726 
2727  // If the packet isn't complete it will be put back and we just return.
2728  // Otherwise, the buffer pointer is saved and then cleared so that reads
2729  // from the buffer start at the beginning.
2730  //
2731  if ( pdfs->bp == 0 )
2732  return TCL_OK;
2733 
2734  plr->nbytes = (int) pdfs->bp;
2735  pdfs->bp = 0;
2736  result = process_data( interp, plFramePtr );
2737  }
2738 
2739  return result;
2740 }
2741 
2742 //--------------------------------------------------------------------------
2743 // Orient
2744 //
2745 // Processes "orient" widget command.
2746 // Handles orientation of plot.
2747 //--------------------------------------------------------------------------
2748 
2749 static int
2750 Orient( Tcl_Interp *interp, register PlFrame *plFramePtr,
2751  int argc, const char **argv )
2752 {
2753  int result = TCL_OK;
2754 
2755 // orient -- return orientation of current plot window
2756 
2757  plsstrm( plFramePtr->ipls );
2758 
2759  if ( argc == 0 )
2760  {
2761  PLFLT rot;
2762  char result_str[128];
2763  plgdiori( &rot );
2764  sprintf( result_str, "%f", rot );
2765  Tcl_SetResult( interp, result_str, TCL_VOLATILE );
2766  }
2767 
2768 // orient <rot> -- Set orientation to <rot>
2769 
2770  else
2771  {
2772  plsdiori( atof( argv[0] ) );
2773  result = Redraw( interp, plFramePtr, argc - 1, argv + 1 );
2774  }
2775 
2776  return result;
2777 }
2778 
2779 //--------------------------------------------------------------------------
2780 // Print
2781 //
2782 // Processes "print" widget command.
2783 // Handles printing of plot, duh.
2784 //
2785 // Creates a temporary file, dumps the current plot to it in metafile
2786 // form, and then execs the "plpr" script to actually print it. Since we
2787 // output it in metafile form here, plpr must invoke plrender to drive the
2788 // output to the appropriate file type. The script is responsible for the
2789 // deletion of the plot metafile.
2790 //--------------------------------------------------------------------------
2791 
2792 static int
2793 Print( Tcl_Interp *interp, register PlFrame *plFramePtr,
2794  int PL_UNUSED( argc ), const char ** PL_UNUSED( argv ) )
2795 {
2796  PLINT ipls;
2797  int result = TCL_OK;
2798  char *sfnam;
2799  FILE *sfile;
2800  pid_t pid;
2801 
2802 // Make sure widget has been initialized before going any further
2803 
2804  if ( !plFramePtr->tkwin_initted )
2805  {
2806  Tcl_AppendResult( interp, "Error -- widget not plotted to yet",
2807  (char *) NULL );
2808  return TCL_ERROR;
2809  }
2810 
2811 // Create stream for save
2812 
2813  plmkstrm( &ipls );
2814  if ( ipls < 0 )
2815  {
2816  Tcl_AppendResult( interp, "Error -- cannot create stream",
2817  (char *) NULL );
2818  return TCL_ERROR;
2819  }
2820 
2821 // Open file for writes
2822  sfnam = NULL;
2823 
2824  // Create and open temporary file
2825  if ( ( sfile = pl_create_tempfile( &sfnam ) ) == NULL )
2826  {
2827  Tcl_AppendResult( interp,
2828  "Error -- cannot open plot file for writing",
2829  (char *) NULL );
2830  plend1();
2831  if ( sfnam != NULL )
2832  free( sfnam );
2833  return TCL_ERROR;
2834  }
2835 
2836 // Initialize stream
2837 
2838  plsdev( "plmeta" );
2839  plsfile( sfile );
2840 // FIXME: plmeta/plrender need to honor these, needed to preserve the aspect ratio
2841  plspage( 0., 0., plFramePtr->width, plFramePtr->height, 0, 0 );
2842  plcpstrm( plFramePtr->ipls, 0 );
2843  pladv( 0 );
2844 
2845 // Remake current plot, close file, and switch back to original stream
2846 
2847  plreplot();
2848  plend1();
2849  plsstrm( plFramePtr->ipls );
2850 
2851 // So far so good. Time to exec the print script.
2852 
2853  if ( plFramePtr->plpr_cmd == NULL )
2854  plFramePtr->plpr_cmd = plFindCommand( "plpr" );
2855 
2856  if ( ( plFramePtr->plpr_cmd == NULL ) || ( pid = fork() ) < 0 )
2857  {
2858  Tcl_AppendResult( interp,
2859  "Error -- cannot fork print process",
2860  (char *) NULL );
2861  result = TCL_ERROR;
2862  }
2863  else if ( pid == 0 )
2864  {
2865  if ( execl( plFramePtr->plpr_cmd, plFramePtr->plpr_cmd, sfnam,
2866  (char *) 0 ) )
2867  {
2868  fprintf( stderr, "Unable to exec print command.\n" );
2869  free( sfnam );
2870  _exit( 1 );
2871  }
2872  }
2873 
2874  free( sfnam );
2875 
2876  return result;
2877 }
2878 
2879 //--------------------------------------------------------------------------
2880 // Page
2881 //
2882 // Processes "page" widget command.
2883 // Handles parameters such as margin, aspect ratio, and justification
2884 // of final plot.
2885 //--------------------------------------------------------------------------
2886 
2887 static int
2888 Page( Tcl_Interp *interp, register PlFrame *plFramePtr,
2889  int argc, const char **argv )
2890 {
2891 // page -- return current device window parameters
2892 
2893  plsstrm( plFramePtr->ipls );
2894 
2895  if ( argc == 0 )
2896  {
2897  PLFLT mar, aspect, jx, jy;
2898  char result_str[128];
2899 
2900  plgdidev( &mar, &aspect, &jx, &jy );
2901  sprintf( result_str, "%g %g %g %g", mar, aspect, jx, jy );
2902  Tcl_SetResult( interp, result_str, TCL_VOLATILE );
2903  return TCL_OK;
2904  }
2905 
2906 // page <mar> <aspect> <jx> <jy> -- set up page
2907 
2908  if ( argc < 4 )
2909  {
2910  Tcl_AppendResult( interp, "wrong # args: should be \"",
2911  " page mar aspect jx jy\"", (char *) NULL );
2912  return TCL_ERROR;
2913  }
2914 
2915  plsdidev( atof( argv[0] ), atof( argv[1] ), atof( argv[2] ), atof( argv[3] ) );
2916  return ( Redraw( interp, plFramePtr, argc - 1, argv + 1 ) );
2917 }
2918 
2919 //--------------------------------------------------------------------------
2920 // Redraw
2921 //
2922 // Processes "redraw" widget command.
2923 // Turns loose a DoWhenIdle command to redraw plot by replaying contents
2924 // of plot buffer.
2925 //--------------------------------------------------------------------------
2926 
2927 static int
2928 Redraw( Tcl_Interp *PL_UNUSED( interp ), register PlFrame *plFramePtr,
2929  int PL_UNUSED( argc ), const char ** PL_UNUSED( argv ) )
2930 {
2931  dbug_enter( "Redraw" );
2932 
2933  plFramePtr->flags |= REDRAW_PENDING;
2934  if ( ( plFramePtr->tkwin != NULL ) &&
2935  !( plFramePtr->flags & REFRESH_PENDING ) )
2936  {
2937  Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
2938  plFramePtr->flags |= REFRESH_PENDING;
2939  }
2940 
2941  return TCL_OK;
2942 }
2943 
2944 //--------------------------------------------------------------------------
2945 // Save
2946 //
2947 // Processes "save" widget command.
2948 // Saves plot to a file.
2949 //--------------------------------------------------------------------------
2950 
2951 static int
2952 Save( Tcl_Interp *interp, register PlFrame *plFramePtr,
2953  int argc, const char **argv )
2954 {
2955  int length;
2956  char c;
2957  FILE *sfile;
2958 
2959 // Make sure widget has been initialized before going any further
2960 
2961  if ( !plFramePtr->tkwin_initted )
2962  {
2963  Tcl_AppendResult( interp, "Error -- widget not plotted to yet",
2964  (char *) NULL );
2965  return TCL_ERROR;
2966  }
2967 
2968 // save -- save to already open file
2969 
2970  if ( argc == 0 )
2971  {
2972  if ( !plFramePtr->ipls_save )
2973  {
2974  Tcl_AppendResult( interp, "Error -- no current save file",
2975  (char *) NULL );
2976  return TCL_ERROR;
2977  }
2978  plsstrm( plFramePtr->ipls_save );
2979  // Note: many drivers ignore these, needed to preserve the aspect ratio
2980  plspage( 0., 0., plFramePtr->width, plFramePtr->height, 0, 0 );
2981  plcpstrm( plFramePtr->ipls, 0 );
2982  pladv( 0 );
2983  plreplot();
2984  plflush();
2985  plsstrm( plFramePtr->ipls );
2986  return TCL_OK;
2987  }
2988 
2989  c = argv[0][0];
2990  length = (int) strlen( argv[0] );
2991 
2992 // save to specified device & file
2993 
2994  if ( ( c == 'a' ) && ( strncmp( argv[0], "as", (size_t) length ) == 0 ) )
2995  {
2996  if ( argc < 3 )
2997  {
2998  Tcl_AppendResult( interp, "wrong # args: should be \"",
2999  " save as device file\"", (char *) NULL );
3000  return TCL_ERROR;
3001  }
3002 
3003  // If save previously in effect, delete old stream
3004 
3005  if ( plFramePtr->ipls_save )
3006  {
3007  plsstrm( plFramePtr->ipls_save );
3008  plend1();
3009  }
3010 
3011  // Create stream for saves to selected device & file
3012 
3013  plmkstrm( &plFramePtr->ipls_save );
3014  if ( plFramePtr->ipls_save < 0 )
3015  {
3016  Tcl_AppendResult( interp, "Error -- cannot create stream",
3017  (char *) NULL );
3018  plFramePtr->ipls_save = 0;
3019  return TCL_ERROR;
3020  }
3021 
3022  // Open file for writes
3023 
3024  if ( ( sfile = fopen( argv[2], "wb+" ) ) == NULL )
3025  {
3026  Tcl_AppendResult( interp, "Error -- cannot open file ", argv[2],
3027  " for writing", (char *) NULL );
3028  plFramePtr->ipls_save = 0;
3029  plend1();
3030  return TCL_ERROR;
3031  }
3032 
3033  // Initialize stream
3034 
3035  plsdev( argv[1] );
3036  plsfile( sfile );
3037  // Note: many drivers ignore these, needed to preserve the aspect ratio
3038  plspage( 0., 0., plFramePtr->width, plFramePtr->height, 0, 0 );
3039  plcpstrm( plFramePtr->ipls, 0 );
3040  pladv( 0 );
3041 
3042  // Remake current plot and then switch back to original stream
3043 
3044  plreplot();
3045  plflush();
3046  plsstrm( plFramePtr->ipls );
3047  }
3048 
3049 // close save file
3050 
3051  else if ( ( c == 'c' ) && ( strncmp( argv[0], "close", (size_t) length ) == 0 ) )
3052  {
3053  if ( !plFramePtr->ipls_save )
3054  {
3055  Tcl_AppendResult( interp, "Error -- no current save file",
3056  (char *) NULL );
3057  return TCL_ERROR;
3058  }
3059  else
3060  {
3061  plsstrm( plFramePtr->ipls_save );
3062  plend1();
3063  plFramePtr->ipls_save = 0;
3064  plsstrm( plFramePtr->ipls );
3065  }
3066  }
3067 
3068 // unrecognized
3069 
3070  else
3071  {
3072  Tcl_AppendResult( interp, "bad option to \"save\": must be ",
3073  "as or close", (char *) NULL );
3074 
3075  return TCL_ERROR;
3076  }
3077 
3078  return TCL_OK;
3079 }
3080 
3081 //--------------------------------------------------------------------------
3082 // View
3083 //
3084 // Processes "view" widget command.
3085 // Handles translation & scaling of view into plot.
3086 //--------------------------------------------------------------------------
3087 
3088 static int
3089 View( Tcl_Interp *interp, register PlFrame *plFramePtr,
3090  int argc, const char **argv )
3091 {
3092  int length;
3093  char c;
3094  PLFLT xl, xr, yl, yr;
3095 
3096 // view -- return current relative plot window coordinates
3097 
3098  plsstrm( plFramePtr->ipls );
3099 
3100  if ( argc == 0 )
3101  {
3102  char result_str[128];
3103  plgdiplt( &xl, &yl, &xr, &yr );
3104  sprintf( result_str, "%g %g %g %g", xl, yl, xr, yr );
3105  Tcl_SetResult( interp, result_str, TCL_VOLATILE );
3106  return TCL_OK;
3107  }
3108 
3109  c = argv[0][0];
3110  length = (int) strlen( argv[0] );
3111 
3112 // view bounds -- return relative device coordinates of bounds on current
3113 // plot window
3114 
3115  if ( ( c == 'b' ) && ( strncmp( argv[0], "bounds", (size_t) length ) == 0 ) )
3116  {
3117  char result_str[128];
3118  xl = 0.; yl = 0.;
3119  xr = 1.; yr = 1.;
3120  pldip2dc( &xl, &yl, &xr, &yr );
3121  sprintf( result_str, "%g %g %g %g", xl, yl, xr, yr );
3122  Tcl_SetResult( interp, result_str, TCL_VOLATILE );
3123  return TCL_OK;
3124  }
3125 
3126 // view reset -- Resets plot
3127 
3128  if ( ( c == 'r' ) && ( strncmp( argv[0], "reset", (size_t) length ) == 0 ) )
3129  {
3130  xl = 0.; yl = 0.;
3131  xr = 1.; yr = 1.;
3132  plsdiplt( xl, yl, xr, yr );
3133  }
3134 
3135 // view select -- set window into plot space
3136 // Specifies in terms of plot window coordinates, not device coordinates
3137 
3138  else if ( ( c == 's' ) && ( strncmp( argv[0], "select", (size_t) length ) == 0 ) )
3139  {
3140  if ( argc < 5 )
3141  {
3142  Tcl_AppendResult( interp, "wrong # args: should be \"",
3143  " view select xmin ymin xmax ymax\"",
3144  (char *) NULL );
3145  return TCL_ERROR;
3146  }
3147  else
3148  {
3149  gbox( &xl, &yl, &xr, &yr, argv + 1 );
3150  plsdiplt( xl, yl, xr, yr );
3151  }
3152  }
3153 
3154 // view zoom -- set window into plot space incrementally (zoom)
3155 // Here we need to take the page (device) offsets into account
3156 
3157  else if ( ( c == 'z' ) && ( strncmp( argv[0], "zoom", (size_t) length ) == 0 ) )
3158  {
3159  if ( argc < 5 )
3160  {
3161  Tcl_AppendResult( interp, "wrong # args: should be \"",
3162  " view zoom xmin ymin xmax ymax\"",
3163  (char *) NULL );
3164  return TCL_ERROR;
3165  }
3166  else
3167  {
3168  gbox( &xl, &yl, &xr, &yr, argv + 1 );
3169  pldid2pc( &xl, &yl, &xr, &yr );
3170  plsdiplz( xl, yl, xr, yr );
3171  }
3172  }
3173 
3174 // unrecognized
3175 
3176  else
3177  {
3178  Tcl_AppendResult( interp, "bad option \"", argv[1],
3179  "\": options to \"view\" are: bounds, reset, select, or zoom",
3180  (char *) NULL );
3181 
3182  return TCL_ERROR;
3183  }
3184 
3185 // Update plot window bounds and arrange for plot to be updated
3186 
3187  plgdiplt( &xl, &yl, &xr, &yr );
3188  plFramePtr->xl = xl;
3189  plFramePtr->yl = yl;
3190  plFramePtr->xr = xr;
3191  plFramePtr->yr = yr;
3192  plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
3193 
3194  return ( Redraw( interp, plFramePtr, argc, argv ) );
3195 }
3196 
3197 //--------------------------------------------------------------------------
3198 // xScroll
3199 //
3200 // Processes "xscroll" widget command.
3201 // Handles horizontal scroll-bar invoked translation of view into plot.
3202 //--------------------------------------------------------------------------
3203 
3204 static int
3205 xScroll( Tcl_Interp *interp, register PlFrame *plFramePtr,
3206  int argc, const char **argv )
3207 {
3208  int x0, width = Tk_Width( plFramePtr->tkwin );
3209  PLFLT xl, xr, yl, yr, xlen;
3210 
3211  plsstrm( plFramePtr->ipls );
3212 
3213  xlen = plFramePtr->xr - plFramePtr->xl;
3214  x0 = atoi( argv[0] );
3215  xl = x0 / (double) width;
3216  xl = MAX( 0., MIN( ( 1. - xlen ), xl ) );
3217  xr = xl + xlen;
3218 
3219  yl = plFramePtr->yl;
3220  yr = plFramePtr->yr;
3221 
3222  plFramePtr->xl = xl;
3223  plFramePtr->xr = xr;
3224 
3225  plsdiplt( xl, yl, xr, yr );
3226 
3227  plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
3228  return ( Redraw( interp, plFramePtr, argc, argv ) );
3229 }
3230 
3231 //--------------------------------------------------------------------------
3232 // yScroll
3233 //
3234 // Processes "yscroll" widget command.
3235 // Handles vertical scroll-bar invoked translation of view into plot.
3236 //--------------------------------------------------------------------------
3237 
3238 static int
3239 yScroll( Tcl_Interp *interp, register PlFrame *plFramePtr,
3240  int argc, const char **argv )
3241 {
3242  int y0, height = Tk_Height( plFramePtr->tkwin );
3243  PLFLT xl, xr, yl, yr, ylen;
3244 
3245  plsstrm( plFramePtr->ipls );
3246 
3247  ylen = plFramePtr->yr - plFramePtr->yl;
3248  y0 = atoi( argv[0] );
3249  yr = 1. - y0 / (double) height;
3250  yr = MAX( 0. + ylen, MIN( 1., yr ) );
3251  yl = yr - ylen;
3252 
3253  xl = plFramePtr->xl;
3254  xr = plFramePtr->xr;
3255 
3256  plFramePtr->yl = yl;
3257  plFramePtr->yr = yr;
3258 
3259  plsdiplt( xl, yl, xr, yr );
3260 
3261  plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
3262  return ( Redraw( interp, plFramePtr, argc, argv ) );
3263 }
3264 
3265 //--------------------------------------------------------------------------
3266 // report
3267 //
3268 // 4/17/95 GMF
3269 // Processes "report" widget command.
3270 //--------------------------------------------------------------------------
3271 
3272 static int
3273 report( Tcl_Interp *interp, register PlFrame *plFramePtr,
3274  int argc, const char **argv )
3275 {
3276  PLFLT x, y;
3277  char tmpstring[50];
3278 // fprintf( stdout, "Made it into report, argc=%d\n", argc );
3279 
3280  if ( argc == 0 )
3281  {
3282  Tcl_SetResult( interp, "report what?", TCL_STATIC );
3283  return TCL_ERROR;
3284  }
3285 
3286  if ( !strcmp( argv[0], "wc" ) )
3287  {
3288  XwDev *dev = (XwDev *) plFramePtr->pls->dev;
3289  PLGraphicsIn *gin = &( dev->gin );
3290 
3291  if ( argc != 3 )
3292  {
3293  Tcl_SetResult( interp, "Wrong # of args: report wc x y", TCL_STATIC );
3294  return TCL_ERROR;
3295  }
3296 
3297  x = atof( argv[1] );
3298  y = atof( argv[2] );
3299 
3300  gin->dX = (PLFLT) x / ( dev->width - 1 );
3301  gin->dY = 1.0 - (PLFLT) y / ( dev->height - 1 );
3302 
3303  // Try to locate cursor
3304 
3305  if ( plTranslateCursor( gin ) )
3306  {
3307  snprintf( tmpstring, 50, "%f %f", gin->wX, gin->wY );
3308  Tcl_SetResult( interp, tmpstring, TCL_VOLATILE );
3309  return TCL_OK;
3310  }
3311 
3312  Tcl_SetResult( interp, "Cannot locate", TCL_STATIC );
3313  return TCL_OK;
3314  }
3315 
3316  Tcl_SetResult( interp, "nonsensical request.", TCL_STATIC );
3317  return TCL_ERROR;
3318 }
3319 
3320 //--------------------------------------------------------------------------
3321 // Custom bop handler.
3322 // Mostly for support of multi-page Tcl scripts from plserver.
3323 //--------------------------------------------------------------------------
3324 
3325 static void
3326 process_bop( void *clientData, int * PL_UNUSED( skip_driver_bop ) )
3327 {
3328  register PlFrame *plFramePtr = (PlFrame *) clientData;
3329 
3330  if ( Tcl_Eval( plFramePtr->interp, plFramePtr->bopCmd ) != TCL_OK )
3331  fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
3332  plFramePtr->bopCmd, Tcl_GetStringResult( plFramePtr->interp ) );
3333 }
3334 
3335 //--------------------------------------------------------------------------
3336 // Custom eop handler.
3337 // Mostly for support of multi-page Tcl scripts from plserver.
3338 //--------------------------------------------------------------------------
3339 
3340 static void
3341 process_eop( void *clientData, int * PL_UNUSED( skip_driver_eop ) )
3342 {
3343  register PlFrame *plFramePtr = (PlFrame *) clientData;
3344 
3345  if ( Tcl_Eval( plFramePtr->interp, plFramePtr->eopCmd ) != TCL_OK )
3346  fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
3347  plFramePtr->eopCmd, Tcl_GetStringResult( plFramePtr->interp ) );
3348 }
3349 
3350 //--------------------------------------------------------------------------
3351 // Utility routines
3352 //--------------------------------------------------------------------------
3353 
3354 //--------------------------------------------------------------------------
3355 // UpdateVScrollbar
3356 //
3357 // Updates vertical scrollbar if needed.
3358 //--------------------------------------------------------------------------
3359 
3360 static void
3361 UpdateVScrollbar( register PlFrame *plFramePtr )
3362 {
3363  int height = Tk_Height( plFramePtr->tkwin );
3364  char string[60];
3365  int totalUnits, windowUnits, firstUnit, lastUnit, result;
3366 
3367  if ( plFramePtr->yScrollCmd == NULL )
3368  return;
3369 
3370  totalUnits = height;
3371  firstUnit = (int) ( 0.5 + (PLFLT) height * ( 1. - plFramePtr->yr ) );
3372  lastUnit = (int) ( 0.5 + (PLFLT) height * ( 1. - plFramePtr->yl ) );
3373  windowUnits = lastUnit - firstUnit;
3374  sprintf( string, " %d %d %d %d",
3375  totalUnits, windowUnits, firstUnit, lastUnit );
3376 
3377  result = Tcl_VarEval( plFramePtr->interp, plFramePtr->yScrollCmd, string,
3378  (char *) NULL );
3379 
3380  if ( result != TCL_OK )
3381  {
3382  Tk_BackgroundError( plFramePtr->interp );
3383  }
3384 }
3385 
3386 //--------------------------------------------------------------------------
3387 // UpdateHScrollbar
3388 //
3389 // Updates horizontal scrollbar if needed.
3390 //--------------------------------------------------------------------------
3391 
3392 static void
3393 UpdateHScrollbar( register PlFrame *plFramePtr )
3394 {
3395  int width = Tk_Width( plFramePtr->tkwin );
3396  char string[60];
3397  int totalUnits, windowUnits, firstUnit, lastUnit, result;
3398 
3399  if ( plFramePtr->xScrollCmd == NULL )
3400  return;
3401 
3402  totalUnits = width;
3403  firstUnit = (int) ( 0.5 + (PLFLT) width * plFramePtr->xl );
3404  lastUnit = (int) ( 0.5 + (PLFLT) width * plFramePtr->xr );
3405  windowUnits = lastUnit - firstUnit;
3406  sprintf( string, " %d %d %d %d",
3407  totalUnits, windowUnits, firstUnit, lastUnit );
3408 
3409  result = Tcl_VarEval( plFramePtr->interp, plFramePtr->xScrollCmd, string,
3410  (char *) NULL );
3411 
3412  if ( result != TCL_OK )
3413  {
3414  Tk_BackgroundError( plFramePtr->interp );
3415  }
3416 }
3417 
3418 //--------------------------------------------------------------------------
3419 // gbox
3420 //
3421 // Returns selection box coordinates. It's best if the TCL script does
3422 // bounds checking on the input but I do it here as well just to be safe.
3423 //--------------------------------------------------------------------------
3424 
3425 static void
3426 gbox( PLFLT *xl, PLFLT *yl, PLFLT *xr, PLFLT *yr, const char **argv )
3427 {
3428  PLFLT x0, y0, x1, y1;
3429 
3430  x0 = atof( argv[0] );
3431  y0 = atof( argv[1] );
3432  x1 = atof( argv[2] );
3433  y1 = atof( argv[3] );
3434 
3435  x0 = MAX( 0., MIN( 1., x0 ) );
3436  y0 = MAX( 0., MIN( 1., y0 ) );
3437  x1 = MAX( 0., MIN( 1., x1 ) );
3438  y1 = MAX( 0., MIN( 1., y1 ) );
3439 
3440 // Only need two vertices, pick the lower left and upper right
3441 
3442  *xl = MIN( x0, x1 );
3443  *yl = MIN( y0, y1 );
3444  *xr = MAX( x0, x1 );
3445  *yr = MAX( y0, y1 );
3446 }
int alt_hue_path
Definition: plplot.h:469
PLDLLIMPEXP_TCLTK int plTclCmd(char *cmdlist, Tcl_Interp *interp, int argc, const char **argv)
Definition: tclAPI.c:267
PLStream * pls
Definition: plframe.c:124
#define PLESC_REDRAW
Definition: plplot.h:216
Definition: pdf.h:63
#define PLSTATE_CMAP0
Definition: plplotP.h:333
PLControlPt cmap1cp[PL_MAX_CMAP1CP]
Definition: plstrm.h:553
static char ** argv
Definition: qt.cpp:40
#define DEF_PLFRAME_HEIGHT
Definition: plframe.c:206
int plr_process(PLRDev *plr)
Definition: plr.c:117
#define plsstrm
Definition: plplot.h:727
#define PLESC_DEVINIT
Definition: plplot.h:236
const char * typeName
Definition: pdf.h:70
#define plspage
Definition: plplot.h:723
#define PLESC_DOUBLEBUFFERING_ENABLE
Definition: plplot.h:481
int prevWidth
Definition: plframe.c:135
#define UPDATE_H_SCROLLBAR
Definition: plframe.c:198
#define PLESC_DOUBLEBUFFERING_QUERY
Definition: plplot.h:483
void plP_esc(PLINT op, void *ptr)
Definition: plcore.c:270
PLFLT h
Definition: plplot.h:464
PDFstrm * pdf_bopen(U_CHAR *buffer, size_t bufmax)
Definition: pdfutils.c:152
void pl_cpcolor(PLColor *to, PLColor *from)
Definition: plcore.c:2619
unsigned char b
Definition: plplot.h:455
const char * fileHandle
Definition: pdf.h:68
xr
set xl $x0 set yl $y0
Definition: Plframe.py:678
PLINT ncp1
Definition: plstrm.h:545
static int Closelink(Tcl_Interp *, PlFrame *, int, const char **)
#define DEF_PLFRAME_BORDER_WIDTH
Definition: plframe.c:204
PLFLT xr
Definition: plframe.c:153
#define PLESC_DOUBLEBUFFERING
Definition: plplot.h:225
static int Orient(Tcl_Interp *, PlFrame *, int, const char **)
void pldid2pc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
Definition: plcore.c:1573
XwDisplay * xwd
Definition: plxwd.h:71
Definition: pdf.h:51
int plFrameCmd(ClientData, Tcl_Interp *, int, const char **)
unsigned int height
Definition: plplot.h:382
static int Draw(Tcl_Interp *, PlFrame *, int, const char **)
static int PlFrameWidgetCmd(ClientData, Tcl_Interp *, int, const char **)
Definition: plframe.c:511
#define Tk_Cursor
Definition: plframe.c:82
static void PlFrameMotionEH(ClientData, register XEvent *)
Definition: plframe.c:1065
void plseopH(void(*handler)(void *, int *), void *handler_data)
Definition: plcore.c:3594
unsigned height
Definition: plxwd.h:84
XPoint rband_pt[2]
Definition: plframe.c:177
int fd
Definition: pdf.h:65
int width
Definition: plframe.c:111
#define REDRAW_PENDING
Definition: plframe.c:196
static int argc
Definition: qt.cpp:39
static int Redraw(Tcl_Interp *, PlFrame *, int, const char **)
static void PlFrameEnterEH(ClientData, register XEvent *)
Definition: plframe.c:1099
static void DestroyPlFrame(FreeProcArg)
Definition: plframe.c:834
FILE * pl_create_tempfile(char **fname)
Definition: plstdio.c:171
PLINT ipls_save
Definition: plframe.c:126
static void CreateRband(PlFrame *)
Definition: plframe.c:1418
static void UpdateRband(PlFrame *)
Definition: plframe.c:1527
void plcmap1_calc(void)
Definition: plctrl.c:798
PLDisplay pldis
Definition: plframe.c:134
void plr_start(PLRDev *plr)
Definition: plr.c:97
static int Cmd(Tcl_Interp *, PlFrame *, int, const char **)
#define b1
Definition: defines.h:18
#define MAX(a, b)
Definition: dsplint.c:28
#define plsdiori
Definition: plplot.h:703
static void process_bop(void *, int *)
XPoint xhair_y[2]
Definition: plframe.c:171
#define NDEV
Definition: plframe.c:64
int at_eop
Definition: plserver.h:24
#define plinit
Definition: plplot.h:650
void PLFLT PLINT PLINT PLFLT x
PLFLT xl
Definition: plframe.c:153
void plsfile(FILE *file)
Definition: plcore.c:3652
PLFLT l
Definition: plplot.h:465
tuple xmin
Definition: Plframe.py:907
void pldip2dc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
Definition: plcore.c:1619
#define plbop
Definition: plplot.h:591
static int ConfigurePlFrame(Tcl_Interp *, PlFrame *, int, const char **, int)
#define plsdiplt
Definition: plplot.h:704
FILE * file
Definition: pdf.h:66
static void Install_cmap(PlFrame *plFramePtr)
Definition: plframe.c:1620
static void PlFrameLeaveEH(ClientData, register XEvent *)
static PLINT ipls
Definition: plcore.h:88
PLGraphicsIn gin
Definition: plxwd.h:99
tuple ymin
Definition: Plframe.py:908
#define plgdiplt
Definition: plplot.h:626
char * bopCmd
Definition: plframe.c:163
static int xScroll(Tcl_Interp *, PlFrame *, int, const char **)
static void DestroyRband(PlFrame *)
Definition: plframe.c:1477
#define UPDATE_V_SCROLLBAR
Definition: plframe.c:197
#define plend1
Definition: plplot.h:605
int PLINT
Definition: plplot.h:175
char * plFindCommand(const char *fn)
Definition: plctrl.c:2128
#define plgdiori
Definition: plplot.h:625
#define MIN(a, b)
Definition: dsplint.c:29
PLINT ipls
Definition: plframe.c:125
#define FILECAST
static void CreateXhairs(PlFrame *)
Definition: plframe.c:1282
XPoint pts[5]
Definition: plframe.c:150
PLColor tmpcolor
Definition: plstrm.h:549
static void process_eop(void *, int *)
PLINT result
Definition: plplot.h:478
#define DEF_PLFRAME_WIDTH
Definition: plframe.c:208
PLiodev * iodev
Definition: plserver.h:22
int plTranslateCursor(PLGraphicsIn *plg)
Definition: plpage.c:255
static void DestroyXhairs(PlFrame *)
Definition: plframe.c:1335
#define plgdidev
Definition: plplot.h:624
static void PlFrameExposeEH(ClientData, XEvent *)
PLFLT p
Definition: plplot.h:467
PLINT ncol0
Definition: plstrm.h:545
#define plcpstrm
Definition: plplot.h:602
unsigned char g
Definition: plplot.h:454
static void UpdateHScrollbar(register PlFrame *)
Definition: plframe.c:3393
static int scol1(Tcl_Interp *interp, register PlFrame *plFramePtr, int i, const char *col, const char *pos, const char *rev, int *p_changed)
Definition: plframe.c:1850
static void PlFrameConfigureEH(ClientData, XEvent *)
#define snprintf
Definition: plplotP.h:240
PLStream * pls[]
static int report(Tcl_Interp *, PlFrame *, int, const char **)
#define plsdidev
Definition: plplot.h:701
#define dbug_enter(a)
Definition: tclMatrix.c:60
int height
Definition: plframe.c:113
xl
set sign_dx [expr ($dx > 0) ? 1 : -1] set sign_dy [expr ($dy > 0) ? 1 : -1]
Definition: Plframe.py:623
#define REFRESH_PENDING
Definition: plframe.c:194
Tk_3DBorder border
Definition: plframe.c:107
#define DEF_PLFRAME_RELIEF
Definition: plframe.c:207
unsigned int x
Definition: plplot.h:381
Tk_Cursor xhair_cursor
Definition: plframe.c:152
void PLFLT PLINT PLINT PLFLT PLFLT y
#define PLESC_RESIZE
Definition: plplot.h:215
PLINT ipls
Definition: plstrm.h:533
static void PlFrameInit(ClientData)
Definition: plframe.c:1553
static void gbox(PLFLT *, PLFLT *, PLFLT *, PLFLT *, const char **)
Definition: plframe.c:3426
Display * display
Definition: plframe.c:98
char * eopCmd
Definition: plframe.c:164
int tkwin_initted
Definition: plframe.c:123
static int Page(Tcl_Interp *, PlFrame *, int, const char **)
char ** devDesc
Definition: plframe.c:142
static Tk_ConfigSpec configSpecs[]
Definition: plframe.c:212
#define plhlsrgb
Definition: plplot.h:647
static void DrawRband(PlFrame *, int, int)
Definition: plframe.c:1508
gint count
Definition: gcw-lib.c:726
int drawing_xhairs
Definition: plframe.c:169
static int child
Definition: plserver.c:48
static void DrawXhairs(PlFrame *, int, int)
Definition: plframe.c:1373
void pl_cmd(PLINT op, void *ptr)
Definition: plctrl.c:2101
int flags
Definition: plframe.c:116
#define DEF_PLFRAME_BG_MONO
Definition: plframe.c:203
void plgFileDevs(const char ***p_menustr, const char ***p_devname, int *p_ndev)
Definition: plcore.c:3381
PLColor * cmap0
Definition: plstrm.h:550
PLFLT yr
Definition: plframe.c:153
int relief
Definition: plframe.c:110
int rband
Definition: plframe.c:175
#define plsdiplz
Definition: plplot.h:705
static int ReadData(ClientData, int)
Definition: plframe.c:2705
#define plspause
Definition: plplot.h:726
tuple xmax
Definition: Plframe.py:909
static int View(Tcl_Interp *, PlFrame *, int, const char **)
Colormap map
Definition: plxwd.h:53
char * plpr_cmd
Definition: plframe.c:130
void
Definition: f95/scstubs.c:588
static void PlFrameKeyEH(ClientData, register XEvent *)
Definition: plframe.c:1175
XColor * bgColor
Definition: plframe.c:129
PLDLLIMPEXP_TCLTK int pl_PacketReceive(Tcl_Interp *interp, PLiodev *iodev, PDFstrm *pdfs)
void pllib_devinit()
Definition: plcore.c:2760
Tcl_Interp * interp
Definition: plframe.c:101
static void UpdateXhairs(PlFrame *)
Definition: plframe.c:1398
subroutine plsdev(dnam)
Definition: sfstubs.f90:67
int nbytes
Definition: plserver.h:23
void plP_state(PLINT op)
Definition: plcore.c:253
int xhairs
Definition: plframe.c:168
char * yScrollCmd
Definition: plframe.c:157
int borderWidth
Definition: plframe.c:109
#define plmkstrm
Definition: plplot.h:663
#define PL_UNUSED(x)
Definition: plplot.h:130
float PLFLT
Definition: plplot.h:159
XPoint xhair_x[2]
Definition: plframe.c:170
int pdf_close(PDFstrm *pdfs)
Definition: pdfutils.c:238
#define plflush
Definition: plplot.h:614
static void DisplayPlFrame(ClientData)
Definition: plframe.c:1670
#define PLESC_DOUBLEBUFFERING_DISABLE
Definition: plplot.h:482
static int scol0(Tcl_Interp *interp, register PlFrame *plFramePtr, int i, const char *col, int *p_changed)
Definition: plframe.c:1804
static int plplot_ccmap
Definition: plxwd.h:39
PLRDev * plr
Definition: plframe.c:128
static int Openlink(Tcl_Interp *, PlFrame *, int, const char **)
GC xorGC
Definition: plframe.c:149
void plsbopH(void(*handler)(void *, int *), void *handler_data)
Definition: plcore.c:3585
PLFLT yl
Definition: plframe.c:153
unsigned width
Definition: plxwd.h:84
char ** devName
Definition: plframe.c:144
tuple ymax
Definition: Plframe.py:910
#define FreeProcArg
Definition: plframe.c:278
#define DEF_PLFRAME_CURSOR
Definition: plframe.c:205
unsigned char r
Definition: plplot.h:453
static int yScroll(Tcl_Interp *, PlFrame *, int, const char **)
Definition: plxwd.h:69
char * SaveFnam
Definition: plframe.c:140
int type
Definition: pdf.h:69
static void UpdateVScrollbar(register PlFrame *)
Definition: plframe.c:3361
static int process_data(Tcl_Interp *interp, register PlFrame *plFramePtr)
Definition: plframe.c:2659
int continue_draw
Definition: plframe.c:151
void pllib_init()
Definition: plcore.c:2144
#define DEF_PLFRAME_BG_COLOR
Definition: plframe.c:202
PLINT cmd
Definition: plplot.h:477
#define plreplot
Definition: plplot.h:679
int prevHeight
Definition: plframe.c:136
static int Info(Tcl_Interp *, PlFrame *, int, const char **)
static int Save(Tcl_Interp *, PlFrame *, int, const char **)
static Tcl_Interp * interp
Definition: tkMain.c:116
#define PLESC_DEV2PLCOL
Definition: plplot.h:234
#define PLESC_SETBGFG
Definition: plplot.h:235
int at_bop
Definition: plserver.h:24
PLFLT s
Definition: plplot.h:466
PDFstrm * pdfs
Definition: plserver.h:21
size_t bp
Definition: pdf.h:58
dx
if { $zoomopts($this,1) == 0 } then {
Definition: Plframe.py:613
Tk_Window tkwin
Definition: plframe.c:94
PLINT debug
Definition: plstrm.h:533
#define pladv
Definition: plplot.h:587
unsigned int width
Definition: plplot.h:382
Tk_Cursor cursor
Definition: plframe.c:115
unsigned int y
Definition: plplot.h:381
void * dev
Definition: plstrm.h:599
static int ColorManip(Tcl_Interp *, PlFrame *, int, const char **)
void plgpls(PLStream **p_pls)
Definition: plcore.c:3543
#define PLESC_EXPOSE
Definition: plplot.h:214
#define plrgbhls
Definition: plplot.h:682
#define RESIZE_PENDING
Definition: plframe.c:195
char * xScrollCmd
Definition: plframe.c:154
int drawing_rband
Definition: plframe.c:176
static int Print(Tcl_Interp *, PlFrame *, int, const char **)