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