PLplot: plframe.c Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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