PLplot 5.15.0
Loading...
Searching...
No Matches
tkwin.c
Go to the documentation of this file.
1// PLplot Tk device driver.
2//
3// Copyright (C) 2004 Maurice LeBrun
4// Copyright (C) 2004 Joao Cardoso
5//
6// This file is part of PLplot.
7//
8// PLplot is free software; you can redistribute it and/or modify
9// it under the terms of the GNU Library General Public License as published
10// by the Free Software Foundation; either version 2 of the License, or
11// (at your option) any later version.
12//
13// PLplot is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU Library General Public License for more details.
17//
18// You should have received a copy of the GNU Library General Public License
19// along with PLplot; if not, write to the Free Software
20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21//
22// This device driver is designed to be used by a PlPlotter, and in fact requires
23// the existence of an enclosing PlPlotter.
24//
25// The idea is that this should develop into a completely cross-platform driver
26// for use by the cross platform Tk system.
27//
28//
29
30#include "plDevs.h"
31
32#define DEBUG
33
34#ifdef PLD_tkwin
35
36
37#define NEED_PLDEBUG
38#include "plplotP.h"
39#include "pltkwd.h"
40#include "drivers.h"
41#include "plevent.h"
42
43#define _TCLINT
44#ifdef USE_TCL_STUBS
45// Unfortunately, tkInt.h ends up loading Malloc.h under Windows
46// So we have to deal with this mess
47 #undef malloc
48 #undef free
49 #undef realloc
50 #undef calloc
51#if defined ( _WIN32 ) || defined ( MAC_TCL )
52#include <tkInt.h>
53#else
54#include <tk.h>
55#endif
56 #define malloc ckalloc
57 #define free( m ) ckfree( (char *) m )
58 #define realloc ckrealloc
59 #define calloc ckcalloc
60#else
61#if defined ( _WIN32 ) || defined ( MAC_TCL )
62#include <tkInt.h>
63#else
64#include <tk.h>
65#endif
66#endif
67
68#ifdef ckalloc
69#undef ckalloc
70#define ckalloc malloc
71#endif
72#ifdef ckfree
73#undef ckfree
74#define ckfree free
75#endif
76#ifdef free
77#undef free
78#endif
79
80// Device info
81PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_tkwin = "tkwin:New tk driver:1:tkwin:45:tkwin\n";
82
83
84void * ckcalloc( size_t nmemb, size_t size );
85
86//
87// We want to use the 'pure Tk' interface. On Unix we can use
88// some direct calls to X instead of Tk, if we want, although
89// that code hasn't been tested for some time. So this define
90// is required on Windows/MacOS and perhaps optional on Unix.
91//
92#define USE_TK
93
94#ifdef _WIN32
95#define XSynchronize( display, bool ) { display->request++; }
96#define XSync( display, bool ) { display->request++; }
97#define XFlush( display )
98#endif
99
100// Dummy definition of PlPlotter containing first few fields
101typedef struct PlPlotter
102{
103 Tk_Window tkwin; // Window that embodies the frame. NULL
104 // means that the window has been destroyed
105 // but the data structures haven't yet been
106 // cleaned up.
107 //
108 Display *display; // Display containing widget. Used, among
109 // other things, so that resources can be
110 // freed even after tkwin has gone away.
111 //
112 Tcl_Interp *interp; // Interpreter associated with
113 // widget. Used to delete widget
114 // command.
115 //
116} PlPlotter;
117
118void CopyColour( XColor* from, XColor* to );
119void Tkw_StoreColor( PLStream* pls, TkwDisplay* tkwd, XColor* col );
120static int pltk_AreWeGrayscale( PlPlotter *plf );
121void PlplotterAtEop( Tcl_Interp *interp, register PlPlotter *plPlotterPtr );
122void PlplotterAtBop( Tcl_Interp *interp, register PlPlotter *plPlotterPtr );
123
124static int synchronize = 0; // change to 1 for synchronized operation
125// for debugging only
126
127// Number of instructions to skip between querying the X server for events
128
129#define MAX_INSTR 20
130
131// Pixels/mm
132
133#define PHYSICAL 0 // Enables physical scaling..
134
135// Set constants for dealing with colormap. In brief:
136//
137// ccmap When set, turns on custom color map
138//
139// XWM_COLORS Number of low "pixel" values to copy.
140// CMAP0_COLORS Color map 0 entries.
141// CMAP1_COLORS Color map 1 entries.
142// MAX_COLORS Maximum colors period.
143//
144// See Init_CustomCmap() and Init_DefaultCmap() for more info.
145// Set ccmap at your own risk -- still under development.
146//
147
148// plplot_tkwin_ccmap is statically defined in pltkwd.h. Note that
149// plplotter.c also includes that header and uses that variable.
150
151#define XWM_COLORS 70
152#define CMAP0_COLORS 16
153#define CMAP1_COLORS 50
154#define MAX_COLORS 256
155
156#ifndef USE_TK
157// Variables to hold RGB components of given colormap.
158// Used in an ugly hack to get past some X11R5 and TK limitations.
159
160static int sxwm_colors_set;
161static XColor sxwm_colors[MAX_COLORS];
162#endif
163
164// Keep pointers to all the displays in use
165
166static TkwDisplay *tkwDisplay[PLTKDISPLAYS];
167
168#if !defined ( MAC_TCL ) && !defined ( _WIN32 )
169static unsigned char CreatePixmapStatus;
170static int CreatePixmapErrorHandler( Display *display, XErrorEvent *error );
171#endif
172
173// Function prototypes
174// Initialization
175
176static void Init( PLStream *pls );
177static void InitColors( PLStream *pls );
178static void AllocCustomMap( PLStream *pls );
179static void AllocCmap0( PLStream *pls );
180static void AllocCmap1( PLStream *pls );
181static void CreatePixmap( PLStream *pls );
182static void GetVisual( PLStream *pls );
183static void AllocBGFG( PLStream *pls );
184
185// Escape function commands
186
187static void ExposeCmd( PLStream *pls, PLDisplay *ptr );
188static void RedrawCmd( PLStream *pls );
189static void ResizeCmd( PLStream *pls, PLDisplay *ptr );
190#ifndef USE_TK
191static void GetCursorCmd( PLStream *pls, PLGraphicsIn *ptr );
192#endif
193static void FillPolygonCmd( PLStream *pls );
194#ifdef USING_PLESC_COPY
195static void CopyCommand( PLStream *pls );
196#endif
197
198// Miscellaneous
199
200static void StoreCmap0( PLStream *pls );
201static void StoreCmap1( PLStream *pls );
202static void WaitForPage( PLStream *pls );
203
205
206void plD_init_tkwin( PLStream * );
207void plD_line_tkwin( PLStream *, short, short, short, short );
208void plD_polyline_tkwin( PLStream *, short *, short *, PLINT );
209void plD_eop_tkwin( PLStream * );
210void plD_bop_tkwin( PLStream * );
211void plD_tidy_tkwin( PLStream * );
212void plD_state_tkwin( PLStream *, PLINT );
213void plD_esc_tkwin( PLStream *, PLINT, void * );
214void plD_wait_tkwin( PLStream * );
216
218{
219#ifndef ENABLE_DYNDRIVERS
220 pdt->pl_MenuStr = "PLplot Tk plotter";
221 pdt->pl_DevName = "tkwin";
222#endif
224 pdt->pl_seq = 45;
225 pdt->pl_init = (plD_init_fp) plD_init_tkwin;
226 pdt->pl_line = (plD_line_fp) plD_line_tkwin;
227 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_tkwin;
228 pdt->pl_eop = (plD_eop_fp) plD_eop_tkwin;
229 pdt->pl_bop = (plD_bop_fp) plD_bop_tkwin;
230 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_tkwin;
231 pdt->pl_state = (plD_state_fp) plD_state_tkwin;
232 pdt->pl_esc = (plD_esc_fp) plD_esc_tkwin;
233 pdt->pl_wait = (plD_wait_fp) plD_wait_tkwin;
234}
235
236//--------------------------------------------------------------------------
237// plD_init_tkwin()
238//
239// Initialize device.
240// Tk-dependent stuff done in plD_open_tkwin() and Init().
241//--------------------------------------------------------------------------
242
243void
244plD_init_tkwin( PLStream *pls )
245{
246 TkwDev *dev;
247 float pxlx, pxly;
248 int xmin = 0;
249 int xmax = PIXELS_X - 1;
250 int ymin = 0;
251 int ymax = PIXELS_Y - 1;
252
253 dbug_enter( "plD_init_tkw" );
254
255 pls->termin = 1; // Is an interactive terminal
256 pls->dev_flush = 1; // Handle our own flushes
257 pls->dev_fill0 = 1; // Handle solid fills
258 pls->plbuf_write = 1; // Activate plot buffer
259
260 // The real meat of the initialization done here
261
262 if ( pls->dev == NULL )
264
265 dev = (TkwDev *) pls->dev;
266
267 Init( pls );
268
269 // Get ready for plotting
270
271 dev->xlen = (short) ( xmax - xmin );
272 dev->ylen = (short) ( ymax - ymin );
273
274 dev->xscale_init = (double) dev->init_width / (double) dev->xlen;
275 dev->yscale_init = (double) dev->init_height / (double) dev->ylen;
276
277 dev->xscale = dev->xscale_init;
278 dev->yscale = dev->yscale_init;
279
280#if PHYSICAL
281 pxlx = (PLFLT) ( (double) PIXELS_X / dev->width * DPMM );
282 pxly = (PLFLT) ( (double) PIXELS_Y / dev->height * DPMM );
283#else
284 pxlx = (PLFLT) ( (double) PIXELS_X / LPAGE_X );
285 pxly = (PLFLT) ( (double) PIXELS_Y / LPAGE_Y );
286#endif
287
288 plP_setpxl( pxlx, pxly );
289 plP_setphy( xmin, xmax, ymin, ymax );
290}
291
292//--------------------------------------------------------------------------
293// plD_open_tkwin()
294//
295// Performs basic driver initialization, without actually opening or
296// modifying a window. May be called by the outside world before plinit
297// in case the caller needs early access to the driver internals (not
298// very common -- currently only used externally by plplotter).
299//--------------------------------------------------------------------------
300
301void
303{
304 TkwDev *dev;
305 TkwDisplay *tkwd;
306 int i;
307
308 dbug_enter( "plD_open_tkw" );
309
310 // Allocate and initialize device-specific data
311
312 if ( pls->dev != NULL )
313 plwarn( "plD_open_tkw: device pointer is already set" );
314
315 pls->dev = (TkwDev *) calloc( 1, (size_t) sizeof ( TkwDev ) );
316 if ( pls->dev == NULL )
317 plexit( "plD_init_tkw: Out of memory." );
318
319 dev = (TkwDev *) pls->dev;
320
321 // Variables used in querying the X server for events
322
323 dev->instr = 0;
324 dev->max_instr = MAX_INSTR;
325
326 // See if display matches any already in use, and if so use that
327
328 dev->tkwd = NULL;
329 for ( i = 0; i < PLTKDISPLAYS; i++ )
330 {
331 if ( tkwDisplay[i] == NULL )
332 {
333 continue;
334 }
335 else if ( pls->FileName == NULL && tkwDisplay[i]->displayName == NULL )
336 {
337 dev->tkwd = tkwDisplay[i];
338 break;
339 }
340 else if ( pls->FileName == NULL || tkwDisplay[i]->displayName == NULL )
341 {
342 continue;
343 }
344 else if ( strcmp( tkwDisplay[i]->displayName, pls->FileName ) == 0 )
345 {
346 dev->tkwd = tkwDisplay[i];
347 break;
348 }
349 }
350
351 // If no display matched, create a new one
352
353 if ( dev->tkwd == NULL )
354 {
355 dev->tkwd = (TkwDisplay *) calloc( 1, (size_t) sizeof ( TkwDisplay ) );
356 if ( dev->tkwd == NULL )
357 plexit( "Init: Out of memory." );
358
359 for ( i = 0; i < PLTKDISPLAYS; i++ )
360 {
361 if ( tkwDisplay[i] == NULL )
362 break;
363 }
364 if ( i == PLTKDISPLAYS )
365 plexit( "Init: Out of tkwDisplay's." );
366
367 tkwDisplay[i] = tkwd = (TkwDisplay *) dev->tkwd;
368 tkwd->nstreams = 1;
369
370 //
371 // If we don't have a tk widget we're being called on, then
372 // abort operations now
373 //
374 if ( pls->plPlotterPtr == NULL )
375 {
376 plexit( "No tk plframe widget to connect to" );
377 }
378 // Old version for MacOS Tk8.0
379 //
380 // char deflt[] = "Macintosh:0";
381 // pls->FileName = deflt;
382 // tkwd->display = (Display*) TkpOpenDisplay(pls->FileName);
383 //
384
385 // Open display
386#if defined ( MAC_TCL ) || defined ( _WIN32 )
387 if ( !pls->FileName )
388 {
389 //
390 // Need to strdup because Tk has allocated the screen name,
391 // but we will actually 'free' it later ourselves, and therefore
392 // need to own the memory.
393 //
394 pls->FileName = plstrdup( TkGetDefaultScreenName( NULL, NULL ) );
395 }
396 tkwd->display = pls->plPlotterPtr->display;
397#else
398 tkwd->display = XOpenDisplay( pls->FileName );
399#endif
400 if ( tkwd->display == NULL )
401 {
402 plexit( "Can't open display" );
403 }
404 tkwd->displayName = pls->FileName;
405 tkwd->screen = DefaultScreen( tkwd->display );
406 if ( synchronize )
407 {
408 XSynchronize( tkwd->display, 1 );
409 }
410 // Get colormap and visual
411
412 tkwd->map = Tk_Colormap( pls->plPlotterPtr->tkwin );
413 GetVisual( pls );
414
415 //
416 // Figure out if we have a color display or not.
417 // Default is color IF the user hasn't specified and IF the output device is
418 // not grayscale.
419 //
420
421 if ( pls->colorset )
422 tkwd->color = pls->color;
423 else
424 {
425 pls->color = 1;
426 tkwd->color = !pltk_AreWeGrayscale( pls->plPlotterPtr );
427 }
428
429 // Allocate & set background and foreground colors
430
431 AllocBGFG( pls );
433 }
434
435 // Display matched, so use existing display data
436
437 else
438 {
439 tkwd = (TkwDisplay *) dev->tkwd;
440 tkwd->nstreams++;
441 }
442 tkwd->ixwd = i;
443}
444
445//--------------------------------------------------------------------------
446// plD_line_tkwin()
447//
448// Draw a line in the current color from (x1,y1) to (x2,y2).
449//--------------------------------------------------------------------------
450
451void
452plD_line_tkwin( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
453{
454 TkwDev *dev = (TkwDev *) pls->dev;
455 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
456
457 int x1 = x1a, y1 = y1a, x2 = x2a, y2 = y2a;
458
459 if ( dev->flags & 1 )
460 return;
461
462 y1 = dev->ylen - y1;
463 y2 = dev->ylen - y2;
464
465 x1 = (int) ( x1 * dev->xscale );
466 x2 = (int) ( x2 * dev->xscale );
467 y1 = (int) ( y1 * dev->yscale );
468 y2 = (int) ( y2 * dev->yscale );
469
470 if ( dev->write_to_window )
471 XDrawLine( tkwd->display, dev->window, dev->gc, x1, y1, x2, y2 );
472
473 if ( dev->write_to_pixmap )
474 XDrawLine( tkwd->display, dev->pixmap, dev->gc, x1, y1, x2, y2 );
475}
476
477//--------------------------------------------------------------------------
478// plD_polyline_tkwin()
479//
480// Draw a polyline in the current color from (x1,y1) to (x2,y2).
481//--------------------------------------------------------------------------
482
483void
484plD_polyline_tkwin( PLStream *pls, short *xa, short *ya, PLINT npts )
485{
486 TkwDev *dev = (TkwDev *) pls->dev;
487 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
488
489 PLINT i;
490 XPoint _pts[PL_MAXPOLY];
491 XPoint *pts;
492
493 if ( dev->flags & 1 )
494 return;
495
496 if ( npts > PL_MAXPOLY )
497 {
498 pts = (XPoint *) malloc( sizeof ( XPoint ) * (size_t) npts );
499 }
500 else
501 {
502 pts = _pts;
503 }
504
505 for ( i = 0; i < npts; i++ )
506 {
507 pts[i].x = (short) ( dev->xscale * xa[i] );
508 pts[i].y = (short) ( dev->yscale * ( dev->ylen - ya[i] ) );
509 }
510
511 if ( dev->write_to_window )
512 XDrawLines( tkwd->display, dev->window, dev->gc, pts, npts,
513 CoordModeOrigin );
514
515 if ( dev->write_to_pixmap )
516 XDrawLines( tkwd->display, dev->pixmap, dev->gc, pts, npts,
517 CoordModeOrigin );
518
519 if ( npts > PL_MAXPOLY )
520 {
521 free( pts );
522 }
523}
524
525//--------------------------------------------------------------------------
526// plD_eop_tkwin()
527//
528// End of page.
529//--------------------------------------------------------------------------
530
531void
532plD_eop_tkwin( PLStream *pls )
533{
534 TkwDev *dev = (TkwDev *) pls->dev;
535 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
536
537 dbug_enter( "plD_eop_tkw" );
538 if ( dev->flags & 1 )
539 return;
540
541 XFlush( tkwd->display );
542 if ( pls->db )
543 ExposeCmd( pls, NULL );
544}
545
546//--------------------------------------------------------------------------
547// plD_wait_tkwin()
548//
549// User must hit return (or third mouse button) to continue.
550//--------------------------------------------------------------------------
551
552void
553plD_wait_tkwin( PLStream *pls )
554{
555 TkwDev *dev = (TkwDev *) pls->dev;
556 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
557
558 dbug_enter( "plD_wait_tkw" );
559 if ( dev->flags & 1 )
560 return;
561
562 WaitForPage( pls );
563}
564
565//--------------------------------------------------------------------------
566// WaitForPage()
567//
568// This routine waits for the user to advance the plot, while handling
569// all other events.
570//--------------------------------------------------------------------------
571
572static void
573WaitForPage( PLStream *pls )
574{
575 PlPlotter *plf = pls->plPlotterPtr;
576 TkwDev *dev = (TkwDev *) pls->dev;
577
578 dbug_enter( "WaitForPage" );
579
580 dev->flags &= 1;
581 if ( plf == NULL )
582 {
583 plwarn( "WaitForPage: Illegal call --- driver can't find enclosing PlPlotter" );
584 return;
585 }
586 PlplotterAtEop( plf->interp, plf );
587
588 while ( !( dev->flags ) && !Tcl_InterpDeleted( plf->interp ) && ( Tk_GetNumMainWindows() > 0 ) )
589 {
590 Tcl_DoOneEvent( 0 );
591 }
592
593 if ( Tcl_InterpDeleted( plf->interp ) || ( Tk_GetNumMainWindows() <= 0 ) )
594 {
595 dev->flags |= 1;
596 }
597
598 dev->flags &= 1;
599}
600
601//--------------------------------------------------------------------------
602// plD_bop_tkwin()
603//
604// Set up for the next page.
605//--------------------------------------------------------------------------
606
607void
608plD_bop_tkwin( PLStream *pls )
609{
610 PlPlotter *plf = pls->plPlotterPtr;
611 TkwDev *dev = (TkwDev *) pls->dev;
612 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
613
614 XRectangle xrect;
615 xrect.x = 0; xrect.y = 0;
616 xrect.width = (short unsigned) dev->width;
617 xrect.height = (short unsigned) dev->height;
618
619 dbug_enter( "plD_bop_tkw" );
620 if ( dev->flags & 1 )
621 return;
622
623 if ( dev->write_to_window )
624 {
625#ifdef MAC_TCL
626 // MacTk only has these X calls
627 XSetForeground( tkwd->display, dev->gc, tkwd->cmap0[0].pixel );
628 XFillRectangles( tkwd->display, dev->window, dev->gc, &xrect, 1 );
629 XSetForeground( tkwd->display, dev->gc, dev->curcolor.pixel );
630#else
631 XClearWindow( tkwd->display, dev->window );
632#endif
633 }
634 if ( dev->write_to_pixmap )
635 {
636 XSetForeground( tkwd->display, dev->gc, tkwd->cmap0[0].pixel );
637 XFillRectangles( tkwd->display, dev->pixmap, dev->gc, &xrect, 1 );
638 XSetForeground( tkwd->display, dev->gc, dev->curcolor.pixel );
639 }
640 XSync( tkwd->display, 0 );
641 pls->page++;
642 PlplotterAtBop( plf->interp, plf );
643}
644
645//--------------------------------------------------------------------------
646// plD_tidy_tkwin()
647//
648// Close graphics file
649//--------------------------------------------------------------------------
650
651void
652plD_tidy_tkwin( PLStream *pls )
653{
654 TkwDev *dev = (TkwDev *) pls->dev;
655 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
656
657 dbug_enter( "plD_tidy_tkw" );
658
659 tkwd->nstreams--;
660 if ( tkwd->nstreams == 0 )
661 {
662 int ixwd = tkwd->ixwd;
663 XFreeGC( tkwd->display, dev->gc );
664#if !defined ( MAC_TCL ) && !defined ( _WIN32 )
665 XCloseDisplay( tkwd->display );
666#endif
667 free_mem( tkwDisplay[ixwd] );
668 }
669 //
670 // Vince removed this November 1999. It seems as if a simple
671 // 'plframe .p ; destroy .p' leaves a temporary buf file open
672 // if we clear this flag here. It should be checked and then
673 // cleared by whoever called us. An alternative fix would
674 // be to carry out the check/tidy here. The plframe widget
675 // handles this stuff for us.
676 //
677 // pls->plbuf_write = 0;
678}
679
680//--------------------------------------------------------------------------
681// plD_state_tkwin()
682//
683// Handle change in PLStream state (color, pen width, fill attribute, etc).
684//--------------------------------------------------------------------------
685
686void
687plD_state_tkwin( PLStream *pls, PLINT op )
688{
689 TkwDev *dev = (TkwDev *) pls->dev;
690 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
691 dbug_enter( "plD_state_tkw" );
692 if ( dev->flags & 1 )
693 return;
694
695 switch ( op )
696 {
697 case PLSTATE_WIDTH:
698 break;
699
700 case PLSTATE_COLOR0: {
701 int icol0 = pls->icol0;
702 if ( tkwd->color )
703 {
704 if ( icol0 == PL_RGB_COLOR )
705 {
706 PLColor_to_TkColor( &pls->curcolor, &dev->curcolor );
707 Tkw_StoreColor( pls, tkwd, &dev->curcolor );
708 }
709 else
710 {
711 dev->curcolor = tkwd->cmap0[icol0];
712 }
713 XSetForeground( tkwd->display, dev->gc, dev->curcolor.pixel );
714 }
715 else
716 {
717 dev->curcolor = tkwd->fgcolor;
718 XSetForeground( tkwd->display, dev->gc, dev->curcolor.pixel );
719 }
720 break;
721 }
722
723 case PLSTATE_COLOR1: {
724 int icol1;
725
726 if ( tkwd->ncol1 == 0 )
727 AllocCmap1( pls );
728
729 if ( tkwd->ncol1 < 2 )
730 break;
731
732 icol1 = ( pls->icol1 * ( tkwd->ncol1 - 1 ) ) / ( pls->ncol1 - 1 );
733 if ( tkwd->color )
734 dev->curcolor = tkwd->cmap1[icol1];
735 else
736 dev->curcolor = tkwd->fgcolor;
737
738 XSetForeground( tkwd->display, dev->gc, dev->curcolor.pixel );
739 break;
740 }
741
742 case PLSTATE_CMAP0:
744 StoreCmap0( pls );
745 break;
746
747 case PLSTATE_CMAP1:
748 StoreCmap1( pls );
749 break;
750 }
751}
752
753//--------------------------------------------------------------------------
754// plD_esc_tkwin()
755//
756// Escape function.
757//
758// Functions:
759//
760// PLESC_EH Handle pending events
761// PLESC_EXPOSE Force an expose
762// PLESC_FILL Fill polygon
763// PLESC_FLUSH Flush X event buffer
764// PLESC_GETC Get coordinates upon mouse click
765// PLESC_REDRAW Force a redraw
766// PLESC_RESIZE Force a resize
767//--------------------------------------------------------------------------
768
769void
770plD_esc_tkwin( PLStream *pls, PLINT op, void *ptr )
771{
772 TkwDev *dev = (TkwDev *) pls->dev;
773#ifndef USE_TK
774 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
775#endif
776 dbug_enter( "plD_esc_tkw" );
777 if ( dev->flags & 1 )
778 return;
779
780 switch ( op )
781 {
782 case PLESC_EH:
783#ifndef USE_TK
784 HandleEvents( pls );
785#endif
786 break;
787
788 case PLESC_EXPOSE:
789 ExposeCmd( pls, (PLDisplay *) ptr );
790 break;
791
792 case PLESC_FILL:
793 FillPolygonCmd( pls );
794 break;
795
796 case PLESC_FLUSH:
797#ifndef USE_TK
798 HandleEvents( pls );
799 XFlush( tkwd->display );
800#endif
801 break;
802
803 case PLESC_GETC:
804#ifndef USE_TK
805 GetCursorCmd( pls, (PLGraphicsIn *) ptr );
806#endif
807 break;
808
809 case PLESC_REDRAW:
810 RedrawCmd( pls );
811 break;
812
813 case PLESC_RESIZE:
814 ResizeCmd( pls, (PLDisplay *) ptr );
815 break;
816
817// Added by Vince, disabled by default since we want a minimal patch
818#ifdef USING_PLESC_COPY
819 case PLESC_COPY:
820 CopyCommand( pls );
821 break;
822#endif
823 }
824}
825
826#ifdef USING_PLESC_COPY
827//--------------------------------------------------------------------------
828// CopyCommand()
829//
830// Copy a rectangle to a new part of the image.
831// Points described in first 3 elements of pls->dev_x[] and pls->dev_y[].
832//--------------------------------------------------------------------------
833
834static void
835CopyCommand( PLStream *pls )
836{
837 int x0, w, x1, y0, h, y1;
838 TkwDev *dev = (TkwDev *) pls->dev;
839 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
840
841 x0 = (int) ( dev->xscale * pls->dev_x[0] );
842 x1 = (int) ( dev->xscale * pls->dev_x[2] );
843 y0 = (int) ( dev->yscale * ( dev->ylen - pls->dev_y[0] ) );
844 y1 = (int) ( dev->yscale * ( dev->ylen - pls->dev_y[2] ) );
845 w = (int) ( dev->xscale * ( pls->dev_x[1] - pls->dev_x[0] ) );
846 h = (int) ( -dev->yscale * ( pls->dev_y[1] - pls->dev_y[0] ) );
847
848 if ( dev->write_to_window )
849 XCopyArea( tkwd->display, dev->window, dev->window, dev->gc,
850 x0, y0, w, h, x1, y1 );
851
852 if ( dev->write_to_pixmap )
853 XCopyArea( tkwd->display, dev->pixmap, dev->pixmap, dev->gc,
854 x0, y0, w, h, x1, y1 );
855}
856#endif
857
858//--------------------------------------------------------------------------
859// FillPolygonCmd()
860//
861// Fill polygon described in points pls->dev_x[] and pls->dev_y[].
862// Only solid color fill supported.
863//--------------------------------------------------------------------------
864
865static void
866FillPolygonCmd( PLStream *pls )
867{
868 TkwDev *dev = (TkwDev *) pls->dev;
869 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
870 XPoint _pts[PL_MAXPOLY];
871 XPoint *pts;
872 int i;
873
874 if ( pls->dev_npts > PL_MAXPOLY )
875 {
876 pts = (XPoint *) malloc( sizeof ( XPoint ) * (size_t) ( pls->dev_npts ) );
877 }
878 else
879 {
880 pts = _pts;
881 }
882
883 for ( i = 0; i < pls->dev_npts; i++ )
884 {
885 pts[i].x = (short) ( dev->xscale * pls->dev_x[i] );
886 pts[i].y = (short) ( dev->yscale * ( dev->ylen - pls->dev_y[i] ) );
887 }
888
889// Fill polygons
890
891 if ( dev->write_to_window )
892 XFillPolygon( tkwd->display, dev->window, dev->gc,
893 pts, pls->dev_npts, Nonconvex, CoordModeOrigin );
894
895 if ( dev->write_to_pixmap )
896 XFillPolygon( tkwd->display, dev->pixmap, dev->gc,
897 pts, pls->dev_npts, Nonconvex, CoordModeOrigin );
898
899// If in debug mode, draw outline of boxes being filled
900
901#ifdef DEBUG
902 if ( pls->debug )
903 {
904 XSetForeground( tkwd->display, dev->gc, tkwd->fgcolor.pixel );
905 if ( dev->write_to_window )
906 XDrawLines( tkwd->display, dev->window, dev->gc, pts, pls->dev_npts,
907 CoordModeOrigin );
908
909 if ( dev->write_to_pixmap )
910 XDrawLines( tkwd->display, dev->pixmap, dev->gc, pts, pls->dev_npts,
911 CoordModeOrigin );
912
913 XSetForeground( tkwd->display, dev->gc, dev->curcolor.pixel );
914 }
915#endif
916
917 if ( pls->dev_npts > PL_MAXPOLY )
918 {
919 free( pts );
920 }
921}
922
923//--------------------------------------------------------------------------
924// Init()
925//
926// Xlib initialization routine.
927//
928// Controlling routine for X window creation and/or initialization.
929// The user may customize the window in the following ways:
930//
931// display: pls->OutFile (use plsfnam() or -display option)
932// size: pls->xlength, pls->ylength (use plspage() or -geo option)
933// bg color: pls->cmap0[0] (use plscolbg() or -bg option)
934//--------------------------------------------------------------------------
935
936static void
937Init( PLStream *pls )
938{
939 PlPlotter *plf;
940 TkwDev *dev = (TkwDev *) pls->dev;
941 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
942
943 dbug_enter( "Init" );
944
945 dev->window = (Window) pls->window_id;
946
947 plf = pls->plPlotterPtr;
948 if ( plf == NULL )
949 {
950 plwarn( "Init: Illegal call --- driver can't find enclosing PlPlotter" );
951 return;
952 }
953
954// Initialize colors
955 InitColors( pls );
956#ifndef MAC_TCL
957 XSetWindowColormap( tkwd->display, dev->window, tkwd->map );
958#else
959#endif
960
961// Set up GC for ordinary draws
962 if ( !dev->gc )
963 dev->gc = XCreateGC( tkwd->display, dev->window, 0, 0 );
964
965// Set up GC for rubber-band draws
966 if ( !tkwd->gcXor )
967 {
968 XGCValues gcValues;
969 unsigned long mask;
970
971 gcValues.background = tkwd->cmap0[0].pixel;
972 gcValues.foreground = 0xFF;
973 gcValues.function = GXxor;
974 mask = GCForeground | GCBackground | GCFunction;
975
976 tkwd->gcXor = XCreateGC( tkwd->display, dev->window, mask, &gcValues );
977 }
978
979// Get initial drawing area dimensions
980 dev->width = (unsigned int) Tk_Width( plf->tkwin );
981 dev->height = (unsigned int) Tk_Height( plf->tkwin );
982#if defined( TK_MAJOR_VERSION ) && TK_MAJOR_VERSION >= 9
983 dev->border = (unsigned int) Tk_InternalBorderLeft( plf->tkwin );
984#else
985 dev->border = (unsigned int) Tk_InternalBorderWidth( plf->tkwin );
986#endif
987 tkwd->depth = (unsigned int) Tk_Depth( plf->tkwin );
988
989 dev->init_width = dev->width;
990 dev->init_height = dev->height;
991
992 // Set up flags that determine what we are writing to
993 // If nopixmap is set, ignore db
994
995 if ( pls->nopixmap )
996 {
997 dev->write_to_pixmap = 0;
998 pls->db = 0;
999 }
1000 else
1001 {
1002 dev->write_to_pixmap = 1;
1003 }
1004 dev->write_to_window = !pls->db;
1005
1006 // Create pixmap for holding plot image (for expose events).
1007
1008 if ( dev->write_to_pixmap )
1009 CreatePixmap( pls );
1010
1011 // Set drawing color
1012
1013 plD_state_tkwin( pls, PLSTATE_COLOR0 );
1014
1015 XSetWindowBackground( tkwd->display, dev->window, tkwd->cmap0[0].pixel );
1016 XSetBackground( tkwd->display, dev->gc, tkwd->cmap0[0].pixel );
1017}
1018
1019//--------------------------------------------------------------------------
1020// ExposeCmd()
1021//
1022// Event handler routine for expose events.
1023// These are "pure" exposures (no resize), so don't need to clear window.
1024//--------------------------------------------------------------------------
1025
1026static void
1027ExposeCmd( PLStream *pls, PLDisplay *pldis )
1028{
1029 TkwDev *dev = (TkwDev *) pls->dev;
1030 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
1031 int x, y, width, height;
1032
1033 dbug_enter( "ExposeCmd" );
1034
1035 // Return if plD_init_tkw hasn't been called yet
1036
1037 if ( dev == NULL )
1038 {
1039 plwarn( "ExposeCmd: Illegal call -- driver uninitialized" );
1040 return;
1041 }
1042
1043 // Exposed area. If unspecified, the entire window is used.
1044
1045 if ( pldis == NULL )
1046 {
1047 x = 0;
1048 y = 0;
1049 width = (int) dev->width;
1050 height = (int) dev->height;
1051 }
1052 else
1053 {
1054 x = (int) pldis->x;
1055 y = (int) pldis->y;
1056 width = (int) pldis->width;
1057 height = (int) pldis->height;
1058 }
1059
1060 // Usual case: refresh window from pixmap
1061 // DEBUG option: draws rectangle around refreshed region
1062
1063 XSync( tkwd->display, 0 );
1064 if ( dev->write_to_pixmap )
1065 {
1066 XCopyArea( tkwd->display, dev->pixmap, dev->window, dev->gc,
1067 x, y, (unsigned int) width, (unsigned int) height, x, y );
1068 XSync( tkwd->display, 0 );
1069#ifdef DEBUG
1070 if ( pls->debug )
1071 {
1072 XPoint pts[5];
1073 int x0 = x, x1 = x + width, y0 = y, y1 = y + height;
1074 pts[0].x = (short) x0; pts[0].y = (short) y0;
1075 pts[1].x = (short) x1; pts[1].y = (short) y0;
1076 pts[2].x = (short) x1; pts[2].y = (short) y1;
1077 pts[3].x = (short) x0; pts[3].y = (short) y1;
1078 pts[4].x = (short) x0; pts[4].y = (short) y0;
1079
1080 XDrawLines( tkwd->display, dev->window, dev->gc, pts, 5,
1081 CoordModeOrigin );
1082 }
1083#endif
1084 }
1085 else
1086 {
1087 plRemakePlot( pls );
1088 XFlush( tkwd->display );
1089 }
1090}
1091
1092//--------------------------------------------------------------------------
1093// ResizeCmd()
1094//
1095// Event handler routine for resize events.
1096//--------------------------------------------------------------------------
1097
1098static void
1099ResizeCmd( PLStream *pls, PLDisplay *pldis )
1100{
1101 TkwDev *dev = (TkwDev *) pls->dev;
1102 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
1103 int write_to_window = dev->write_to_window;
1104
1105 dbug_enter( "ResizeCmd" );
1106
1107 // Return if plD_init_tkw hasn't been called yet
1108
1109 if ( dev == NULL )
1110 {
1111 plwarn( "ResizeCmd: Illegal call -- driver uninitialized" );
1112 return;
1113 }
1114
1115 // Return if pointer to window not specified.
1116
1117 if ( pldis == NULL )
1118 {
1119 plwarn( "ResizeCmd: Illegal call -- window pointer uninitialized" );
1120 return;
1121 }
1122
1123 // Reset current window bounds
1124
1125 dev->width = pldis->width;
1126 dev->height = pldis->height;
1127
1128 dev->xscale = dev->width / (double) dev->init_width;
1129 dev->yscale = dev->height / (double) dev->init_height;
1130
1131 dev->xscale = dev->xscale * dev->xscale_init;
1132 dev->yscale = dev->yscale * dev->yscale_init;
1133
1134#if PHYSICAL
1135 {
1136 float pxlx = (double) PIXELS_X / dev->width * DPMM;
1137 float pxly = (double) PIXELS_Y / dev->height * DPMM;
1138 plP_setpxl( pxlx, pxly );
1139 }
1140#endif
1141
1142 // Note: the following order MUST be obeyed -- if you instead redraw into
1143 // the window and then copy it to the pixmap, off-screen parts of the window
1144 // may contain garbage which is then transferred to the pixmap (and thus
1145 // will not go away after an expose).
1146 //
1147
1148 // Resize pixmap using new dimensions
1149
1150 if ( dev->write_to_pixmap )
1151 {
1152 dev->write_to_window = 0;
1153#if defined ( _WIN32 ) || defined ( MAC_TCL )
1154 Tk_FreePixmap( tkwd->display, dev->pixmap );
1155#else
1156 // Vince's original driver code used
1157 // Tk_FreePixmap(tkwd->display, dev->pixmap);
1158 //which is defined in tk-8.3 (and 8.2?) source as
1159 //void
1160 // Tk_FreePixmap(display, pixmap)
1161 // Display *display;
1162 // Pixmap pixmap;
1163 // {
1164 // XFreePixmap(display, pixmap);
1165 // Tk_FreeXId(display, (XID) pixmap);
1166 // }
1167 // But that bombed under Linux and tcl/tk8.2 so now just call
1168 // XFreePixmap directly. (Not recommended as permanent solution
1169 // because you eventually run out of resources according to man
1170 // page if you don't call Tk_FreeXId.) Vince is still looking into
1171 // how to resolve this problem.
1172 //
1173 XFreePixmap( tkwd->display, dev->pixmap );
1174#endif
1175 CreatePixmap( pls );
1176 }
1177
1178 // Initialize & redraw (to pixmap, if available).
1179
1180 plD_bop_tkwin( pls );
1181 plRemakePlot( pls );
1182 XSync( tkwd->display, 0 );
1183
1184 // If pixmap available, fake an expose
1185
1186 if ( dev->write_to_pixmap )
1187 {
1188 dev->write_to_window = write_to_window;
1189 XCopyArea( tkwd->display, dev->pixmap, dev->window, dev->gc, 0, 0,
1190 dev->width, dev->height, 0, 0 );
1191 XSync( tkwd->display, 0 );
1192 }
1193}
1194
1195//--------------------------------------------------------------------------
1196// RedrawCmd()
1197//
1198// Handles page redraw without resize (pixmap does not get reallocated).
1199// Calling this makes sure all necessary housekeeping gets done.
1200//--------------------------------------------------------------------------
1201
1202static void
1203RedrawCmd( PLStream *pls )
1204{
1205 TkwDev *dev = (TkwDev *) pls->dev;
1206 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
1207 int write_to_window = dev->write_to_window;
1208
1209 dbug_enter( "RedrawCmd" );
1210
1211 // Return if plD_init_tkw hasn't been called yet
1212
1213 if ( dev == NULL )
1214 {
1215 plwarn( "RedrawCmd: Illegal call -- driver uninitialized" );
1216 return;
1217 }
1218
1219 // Initialize & redraw (to pixmap, if available).
1220
1221 if ( dev->write_to_pixmap )
1222 dev->write_to_window = 0;
1223
1224 plD_bop_tkwin( pls );
1225 plRemakePlot( pls );
1226 XSync( tkwd->display, 0 );
1227
1228 dev->write_to_window = write_to_window;
1229
1230 // If pixmap available, fake an expose
1231
1232 if ( dev->write_to_pixmap )
1233 {
1234 XCopyArea( tkwd->display, dev->pixmap, dev->window, dev->gc, 0, 0,
1235 dev->width, dev->height, 0, 0 );
1236 XSync( tkwd->display, 0 );
1237 }
1238}
1239
1240//--------------------------------------------------------------------------
1241// CreatePixmap()
1242//
1243// This routine creates a pixmap, doing error trapping in case there
1244// isn't enough memory on the server.
1245//--------------------------------------------------------------------------
1246
1247static void
1248CreatePixmap( PLStream *pls )
1249{
1250 TkwDev *dev = (TkwDev *) pls->dev;
1251 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
1252 Tk_Window tkwin = pls->plPlotterPtr->tkwin;
1253
1254#if !defined ( MAC_TCL ) && !defined ( _WIN32 )
1255 int ( *oldErrorHandler )( Display *, XErrorEvent * );
1256 oldErrorHandler = XSetErrorHandler( CreatePixmapErrorHandler );
1257 CreatePixmapStatus = Success;
1258#endif
1259
1260#ifdef MAC_TCL
1261 // MAC_TCL's version of XCreatePixmap doesn't like 0 by 0 maps
1262 if ( dev->width == 0 )
1263 {
1264 dev->width = 10;
1265 }
1266 if ( dev->height == 0 )
1267 {
1268 dev->height = 10;
1269 }
1270#endif
1271 pldebug( "CreatePixmap",
1272 "creating pixmap: width = %d, height = %d, depth = %d\n",
1273 dev->width, dev->height, tkwd->depth );
1274//
1275// dev->pixmap = Tk_GetPixmap(tkwd->display, dev->window,
1276// dev->width, dev->height, tkwd->depth);
1277//
1278//
1279// Vince's original driver code used Tk_Display(tkwin) for first argument,
1280// but that bombed on an Linux tcl/tk 8.2 machine. Something was wrong
1281// with that value. Thus, we now use tkwd->display, and that works well.
1282// Vince is looking into why Tk_Display(tkwin) is badly defined under 8.2.
1283// old code:
1284//
1285// dev->pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
1286// Tk_Width(tkwin), Tk_Height(tkwin),
1287// DefaultDepthOfScreen(Tk_Screen(tkwin)));
1288//
1289 dev->pixmap = Tk_GetPixmap( tkwd->display, Tk_WindowId( tkwin ),
1290 Tk_Width( tkwin ), Tk_Height( tkwin ),
1291 DefaultDepthOfScreen( Tk_Screen( tkwin ) ) );
1292 XSync( tkwd->display, 0 );
1293#if !defined ( MAC_TCL ) && !defined ( _WIN32 )
1294 if ( CreatePixmapStatus != Success )
1295 {
1296 dev->write_to_pixmap = 0;
1297 dev->write_to_window = 1;
1298 pls->db = 0;
1299 fprintf( stderr, "\n\
1300 Warning: pixmap could not be allocated (insufficient memory on server).\n\
1301 Driver will redraw the entire plot to handle expose events.\n" );
1302 }
1303
1304 XSetErrorHandler( oldErrorHandler );
1305#endif
1306}
1307
1308//--------------------------------------------------------------------------
1309// GetVisual()
1310//
1311// Get visual info. In order to safely use a visual other than that of
1312// the parent (which hopefully is that returned by DefaultVisual), you
1313// must first find (using XGetRGBColormaps) or create a colormap matching
1314// this visual and then set the colormap window attribute in the
1315// XCreateWindow attributes and valuemask arguments. I don't do this
1316// right now, so this is turned off by default.
1317//--------------------------------------------------------------------------
1318
1319static void
1320GetVisual( PLStream *pls )
1321{
1322 int depth;
1323 TkwDev *dev = (TkwDev *) pls->dev;
1324 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
1325
1326 dbug_enter( "GetVisual" );
1327
1328 tkwd->visual = Tk_GetVisual( pls->plPlotterPtr->interp,
1329 pls->plPlotterPtr->tkwin,
1330 "best",
1331 &depth, NULL );
1332 tkwd->depth = (unsigned int) depth;
1333}
1334
1335//--------------------------------------------------------------------------
1336// AllocBGFG()
1337//
1338// Allocate background & foreground colors. If possible, I choose pixel
1339// values such that the fg pixel is the xor of the bg pixel, to make
1340// rubber-banding easy to see.
1341//--------------------------------------------------------------------------
1342
1343static void
1344AllocBGFG( PLStream *pls )
1345{
1346 TkwDev *dev = (TkwDev *) pls->dev;
1347 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
1348
1349#ifndef USE_TK
1350 int i, j, npixels;
1351 unsigned long plane_masks[1], pixels[MAX_COLORS];
1352#endif
1353
1354 dbug_enter( "AllocBGFG" );
1355
1356 // If not on a color system, just return
1357
1358 if ( !tkwd->color )
1359 return;
1360#ifndef USE_TK
1361 // Allocate r/w color cell for background
1362
1363 if ( XAllocColorCells( tkwd->display, tkwd->map, False,
1364 plane_masks, 0, pixels, 1 ) )
1365 {
1366 tkwd->cmap0[0].pixel = pixels[0];
1367 }
1368 else
1369 {
1370 plexit( "couldn't allocate background color cell" );
1371 }
1372
1373 // Allocate as many colors as we can
1374
1375 npixels = MAX_COLORS;
1376 for (;; )
1377 {
1378 if ( XAllocColorCells( tkwd->display, tkwd->map, False,
1379 plane_masks, 0, pixels, npixels ) )
1380 break;
1381 npixels--;
1382 if ( npixels == 0 )
1383 break;
1384 }
1385
1386 // Find the color with pixel = xor of the bg color pixel.
1387 // If a match isn't found, the last pixel allocated is used.
1388
1389 for ( i = 0; i < npixels - 1; i++ )
1390 {
1391 if ( pixels[i] == ( ~tkwd->cmap0[0].pixel & 0xFF ) )
1392 break;
1393 }
1394
1395 // Use this color cell for our foreground color. Then free the rest.
1396
1397 tkwd->fgcolor.pixel = pixels[i];
1398 for ( j = 0; j < npixels; j++ )
1399 {
1400 if ( j != i )
1401 XFreeColors( tkwd->display, tkwd->map, &pixels[j], 1, 0 );
1402 }
1403#endif
1404}
1405
1406//--------------------------------------------------------------------------
1407// pltkwin_setBGFG()
1408//
1409// Set background & foreground colors. Foreground over background should
1410// have high contrast.
1411//--------------------------------------------------------------------------
1412
1413void
1415{
1416 TkwDev *dev = (TkwDev *) pls->dev;
1417 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
1418 PLColor fgcolor;
1419 int gslevbg, gslevfg;
1420
1421 dbug_enter( "pltkwin_setBGFG" );
1422
1423 //
1424 // Set background color.
1425 //
1426 // Background defaults to black on color screens, white on grayscale (many
1427 // grayscale monitors have poor contrast, and black-on-white looks better).
1428 //
1429
1430 if ( !tkwd->color )
1431 {
1432 pls->cmap0[0].r = pls->cmap0[0].g = pls->cmap0[0].b = 0xFF;
1433 }
1434 gslevbg = (int) ( ( (long) pls->cmap0[0].r +
1435 (long) pls->cmap0[0].g +
1436 (long) pls->cmap0[0].b ) / 3 );
1437
1438 PLColor_to_TkColor( &pls->cmap0[0], &tkwd->cmap0[0] );
1439
1440 //
1441 // Set foreground color.
1442 //
1443 // Used for grayscale output, since otherwise the plots can become nearly
1444 // unreadable (i.e. if colors get mapped onto grayscale values). In this
1445 // case it becomes the grayscale level for all draws, and is taken to be
1446 // black if the background is light, and white if the background is dark.
1447 // Note that white/black allocations never fail.
1448 //
1449
1450 if ( gslevbg > 0x7F )
1451 gslevfg = 0;
1452 else
1453 gslevfg = 0xFF;
1454
1455 fgcolor.r = fgcolor.g = fgcolor.b = (unsigned char) gslevfg;
1456
1457 PLColor_to_TkColor( &fgcolor, &tkwd->fgcolor );
1458
1459 // Now store
1460#ifndef USE_TK
1461 if ( tkwd->color )
1462 {
1463 XStoreColor( tkwd->display, tkwd->map, &tkwd->fgcolor );
1464 XStoreColor( tkwd->display, tkwd->map, &tkwd->cmap0[0] );
1465 }
1466 else
1467 {
1468 XAllocColor( tkwd->display, tkwd->map, &tkwd->cmap0[0] );
1469 XAllocColor( tkwd->display, tkwd->map, &tkwd->fgcolor );
1470 }
1471#else
1472 Tkw_StoreColor( pls, tkwd, &tkwd->cmap0[0] );
1473 Tkw_StoreColor( pls, tkwd, &tkwd->fgcolor );
1474#endif
1475}
1476
1477//--------------------------------------------------------------------------
1478// InitColors()
1479//
1480// Does all color initialization.
1481//--------------------------------------------------------------------------
1482
1483static void
1484InitColors( PLStream *pls )
1485{
1486 TkwDev *dev = (TkwDev *) pls->dev;
1487 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
1488
1489 dbug_enter( "InitColors" );
1490
1491 // Allocate and initialize color maps.
1492 // Defer cmap1 allocation until it's actually used
1493
1494 if ( tkwd->color )
1495 {
1496 if ( plplot_tkwin_ccmap )
1497 {
1498 AllocCustomMap( pls );
1499 }
1500 else
1501 {
1502 AllocCmap0( pls );
1503 }
1504 }
1505}
1506
1507//--------------------------------------------------------------------------
1508// AllocCustomMap()
1509//
1510// Initializes custom color map and all the cruft that goes with it.
1511//
1512// Assuming all color X displays do 256 colors, the breakdown is as follows:
1513//
1514// XWM_COLORS Number of low "pixel" values to copy. These are typically
1515// allocated first, thus are in use by the window manager. I
1516// copy them to reduce flicker.
1517//
1518// CMAP0_COLORS Color map 0 entries. I allocate these both in the default
1519// colormap and the custom colormap to reduce flicker.
1520//
1521// CMAP1_COLORS Color map 1 entries. There should be as many as practical
1522// available for smooth shading. On the order of 50-100 is
1523// pretty reasonable. You don't really need all 256,
1524// especially if all you're going to do is to print it to
1525// postscript (which doesn't have any intrinsic limitation on
1526// the number of colors).
1527//
1528// It's important to leave some extra colors unallocated for Tk. In
1529// particular the palette tools require a fair amount. I recommend leaving
1530// at least 40 or so free.
1531//--------------------------------------------------------------------------
1532
1533static void
1534AllocCustomMap( PLStream *pls )
1535{
1536 TkwDev *dev = (TkwDev *) pls->dev;
1537 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
1538
1539 XColor xwm_colors[MAX_COLORS];
1540 int i;
1541#ifndef USE_TK
1542 int npixels;
1543 unsigned long plane_masks[1], pixels[MAX_COLORS];
1544#endif
1545
1546 dbug_enter( "AllocCustomMap" );
1547
1548 // Determine current default colors
1549
1550 for ( i = 0; i < MAX_COLORS; i++ )
1551 {
1552 xwm_colors[i].pixel = (long unsigned) i;
1553 }
1554#ifndef MAC_TCL
1555 XQueryColors( tkwd->display, tkwd->map, xwm_colors, MAX_COLORS );
1556#endif
1557
1558 // Allocate cmap0 colors in the default colormap.
1559 // The custom cmap0 colors are later stored at the same pixel values.
1560 // This is a really cool trick to reduce the flicker when changing colormaps.
1561 //
1562
1563 AllocCmap0( pls );
1564 XAllocColor( tkwd->display, tkwd->map, &tkwd->fgcolor );
1565
1566 // Create new color map
1567
1568 tkwd->map = XCreateColormap( tkwd->display, DefaultRootWindow( tkwd->display ),
1569 tkwd->visual, AllocNone );
1570
1571 // Now allocate all colors so we can fill the ones we want to copy
1572
1573#ifndef USE_TK
1574 npixels = MAX_COLORS;
1575 for (;; )
1576 {
1577 if ( XAllocColorCells( tkwd->display, tkwd->map, False,
1578 plane_masks, 0, pixels, npixels ) )
1579 break;
1580 npixels--;
1581 if ( npixels == 0 )
1582 plexit( "couldn't allocate any colors" );
1583 }
1584
1585 // Fill the low colors since those are in use by the window manager
1586
1587 for ( i = 0; i < XWM_COLORS; i++ )
1588 {
1589 XStoreColor( tkwd->display, tkwd->map, &xwm_colors[i] );
1590 pixels[xwm_colors[i].pixel] = 0;
1591 }
1592
1593 // Fill the ones we will use in cmap0
1594
1595 for ( i = 0; i < tkwd->ncol0; i++ )
1596 {
1597 XStoreColor( tkwd->display, tkwd->map, &tkwd->cmap0[i] );
1598 pixels[tkwd->cmap0[i].pixel] = 0;
1599 }
1600
1601 // Finally, if the colormap was saved by an external agent, see if there are
1602 // any differences from the current default map and save those! A very cool
1603 // (or sick, depending on how you look at it) trick to get over some X and
1604 // Tk limitations.
1605 //
1606
1607 if ( sxwm_colors_set )
1608 {
1609 for ( i = 0; i < MAX_COLORS; i++ )
1610 {
1611 if ( ( xwm_colors[i].red != sxwm_colors[i].red ) ||
1612 ( xwm_colors[i].green != sxwm_colors[i].green ) ||
1613 ( xwm_colors[i].blue != sxwm_colors[i].blue ) )
1614 {
1615 if ( pixels[i] != 0 )
1616 {
1617 XStoreColor( tkwd->display, tkwd->map, &xwm_colors[i] );
1618 pixels[i] = 0;
1619 }
1620 }
1621 }
1622 }
1623
1624 // Now free the ones we're not interested in
1625
1626 for ( i = 0; i < npixels; i++ )
1627 {
1628 if ( pixels[i] != 0 )
1629 XFreeColors( tkwd->display, tkwd->map, &pixels[i], 1, 0 );
1630 }
1631#endif
1632 // Allocate colors in cmap 1
1633
1634 AllocCmap1( pls );
1635}
1636
1637//--------------------------------------------------------------------------
1638// AllocCmap0()
1639//
1640// Allocate & initialize cmap0 entries.
1641//--------------------------------------------------------------------------
1642
1643static void
1644AllocCmap0( PLStream *pls )
1645{
1646 TkwDev *dev = (TkwDev *) pls->dev;
1647 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
1648
1649#ifndef USE_TK
1650 int npixels;
1651 int i;
1652 unsigned long plane_masks[1], pixels[MAX_COLORS];
1653#endif
1654
1655 dbug_enter( "AllocCmap0" );
1656
1657 // Allocate and assign colors in cmap 0
1658
1659#ifndef USE_TK
1660 npixels = pls->ncol0 - 1;
1661 for (;; )
1662 {
1663 if ( XAllocColorCells( tkwd->display, tkwd->map, False,
1664 plane_masks, 0, &pixels[1], npixels ) )
1665 break;
1666 npixels--;
1667 if ( npixels == 0 )
1668 plexit( "couldn't allocate any colors" );
1669 }
1670
1671 tkwd->ncol0 = npixels + 1;
1672 for ( i = 1; i < tkwd->ncol0; i++ )
1673 {
1674 tkwd->cmap0[i].pixel = pixels[i];
1675 }
1676#else
1677 // We use the Tk color scheme
1678 tkwd->ncol0 = pls->ncol0;
1679#endif
1680 StoreCmap0( pls );
1681}
1682
1683//--------------------------------------------------------------------------
1684// AllocCmap1()
1685//
1686// Allocate & initialize cmap1 entries. If using the default color map,
1687// must severely limit number of colors otherwise TK won't have enough.
1688//--------------------------------------------------------------------------
1689
1690static void
1691AllocCmap1( PLStream *pls )
1692{
1693 TkwDev *dev = (TkwDev *) pls->dev;
1694 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
1695
1696 int npixels;
1697#ifndef USE_TK
1698 int i, j;
1699 unsigned long plane_masks[1], pixels[MAX_COLORS];
1700#endif
1701
1702 dbug_enter( "AllocCmap1" );
1703
1704 // Allocate colors in cmap 1
1705
1706 npixels = MAX( 2, MIN( CMAP1_COLORS, pls->ncol1 ) );
1707#ifndef USE_TK
1708 for (;; )
1709 {
1710 if ( XAllocColorCells( tkwd->display, tkwd->map, False,
1711 plane_masks, 0, pixels, npixels ) )
1712 break;
1713 npixels--;
1714 if ( npixels == 0 )
1715 break;
1716 }
1717
1718 if ( npixels < 2 )
1719 {
1720 tkwd->ncol1 = -1;
1721 fprintf( stderr,
1722 "Warning: unable to allocate sufficient colors in cmap1\n" );
1723 return;
1724 }
1725 else
1726 {
1727 tkwd->ncol1 = npixels;
1728 if ( pls->verbose )
1729 fprintf( stderr, "AllocCmap1 (xwin.c): Allocated %d colors in cmap1\n", npixels );
1730 }
1731
1732 // Don't assign pixels sequentially, to avoid strange problems with xor GC's
1733 // Skipping by 2 seems to do the job best
1734
1735 for ( j = i = 0; i < tkwd->ncol1; i++ )
1736 {
1737 while ( pixels[j] == 0 )
1738 j++;
1739
1740 tkwd->cmap1[i].pixel = pixels[j];
1741 pixels[j] = 0;
1742
1743 j += 2;
1744 if ( j >= tkwd->ncol1 )
1745 j = 0;
1746 }
1747#else
1748 tkwd->ncol1 = npixels;
1749#endif
1750 StoreCmap1( pls );
1751}
1752
1753//--------------------------------------------------------------------------
1754// StoreCmap0()
1755//
1756// Stores cmap 0 entries in X-server colormap.
1757//--------------------------------------------------------------------------
1758
1759static void
1760StoreCmap0( PLStream *pls )
1761{
1762 TkwDev *dev = (TkwDev *) pls->dev;
1763 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
1764 int i;
1765
1766 if ( !tkwd->color )
1767 return;
1768
1769 for ( i = 1; i < tkwd->ncol0; i++ )
1770 {
1771 PLColor_to_TkColor( &pls->cmap0[i], &tkwd->cmap0[i] );
1772#ifndef USE_TK
1773 XStoreColor( tkwd->display, tkwd->map, &tkwd->cmap0[i] );
1774#else
1775 Tkw_StoreColor( pls, tkwd, &tkwd->cmap0[i] );
1776#endif
1777 }
1778}
1779
1780void CopyColour( XColor* from, XColor* to )
1781{
1782 to->pixel = from->pixel;
1783 to->red = from->red;
1784 to->blue = from->blue;
1785 to->green = from->green;
1786 to->flags = from->flags;
1787}
1788
1789//--------------------------------------------------------------------------
1790// StoreCmap1()
1791//
1792// Stores cmap 1 entries in X-server colormap.
1793//--------------------------------------------------------------------------
1794
1795static void
1796StoreCmap1( PLStream *pls )
1797{
1798 TkwDev *dev = (TkwDev *) pls->dev;
1799 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd;
1800
1801 PLColor cmap1color;
1802 int i;
1803
1804 if ( !tkwd->color )
1805 return;
1806
1807 for ( i = 0; i < tkwd->ncol1; i++ )
1808 {
1809 plcol_interp( pls, &cmap1color, i, tkwd->ncol1 );
1810 PLColor_to_TkColor( &cmap1color, &tkwd->cmap1[i] );
1811#ifndef USE_TK
1812 XStoreColor( tkwd->display, tkwd->map, &tkwd->cmap1[i] );
1813#else
1814 Tkw_StoreColor( pls, tkwd, &tkwd->cmap1[i] );
1815#endif
1816 }
1817}
1818
1819void Tkw_StoreColor( PLStream* pls, TkwDisplay* tkwd, XColor* col )
1820{
1821 XColor *xc;
1822#ifndef USE_TK
1823 XStoreColor( tkwd->display, tkwd->map, col );
1824#else
1825 (void) tkwd; // tkwd unused in this case
1826 // We're probably losing memory here
1827 xc = Tk_GetColorByValue( pls->plPlotterPtr->tkwin, col );
1828 CopyColour( xc, col );
1829#endif
1830}
1831
1832//--------------------------------------------------------------------------
1833// void PLColor_to_TkColor()
1834//
1835// Copies the supplied PLColor to an XColor, padding with bits as necessary
1836// (a PLColor uses 8 bits for color storage, while an XColor uses 16 bits).
1837// The argument types follow the same order as in the function name.
1838//--------------------------------------------------------------------------
1839
1840#define ToXColor( a ) ( ( ( 0xFF & ( a ) ) << 8 ) | ( a ) )
1841#define ToPLColor( a ) ( ( (U_LONG) a ) >> 8 )
1842
1843void
1844PLColor_to_TkColor( PLColor *plcolor, XColor *xcolor )
1845{
1846 xcolor->red = (short unsigned) ToXColor( plcolor->r );
1847 xcolor->green = (short unsigned) ToXColor( plcolor->g );
1848 xcolor->blue = (short unsigned) ToXColor( plcolor->b );
1849 xcolor->flags = DoRed | DoGreen | DoBlue;
1850}
1851
1852//--------------------------------------------------------------------------
1853// void PLColor_from_TkColor()
1854//
1855// Copies the supplied XColor to a PLColor, stripping off bits as
1856// necessary. See the previous routine for more info.
1857//--------------------------------------------------------------------------
1858
1859void
1860PLColor_from_TkColor( PLColor *plcolor, XColor *xcolor )
1861{
1862 plcolor->r = (unsigned char) ToPLColor( xcolor->red );
1863 plcolor->g = (unsigned char) ToPLColor( xcolor->green );
1864 plcolor->b = (unsigned char) ToPLColor( xcolor->blue );
1865}
1866
1867//--------------------------------------------------------------------------
1868// void PLColor_from_TkColor_Changed()
1869//
1870// Copies the supplied XColor to a PLColor, stripping off bits as
1871// necessary. See the previous routine for more info.
1872//
1873// Returns 1 if the color was different from the old one.
1874//--------------------------------------------------------------------------
1875
1876int
1877PLColor_from_TkColor_Changed( PLColor *plcolor, XColor *xcolor )
1878{
1879 int changed = 0;
1880 int color;
1881 color = ToPLColor( xcolor->red );
1882
1883 if ( plcolor->r != color )
1884 {
1885 changed = 1;
1886 plcolor->r = (unsigned char) color;
1887 }
1888 color = ToPLColor( xcolor->green );
1889 if ( plcolor->g != color )
1890 {
1891 changed = 1;
1892 plcolor->g = (unsigned char) color;
1893 }
1894 color = ToPLColor( xcolor->blue );
1895 if ( plcolor->b != color )
1896 {
1897 changed = 1;
1898 plcolor->b = (unsigned char) color;
1899 }
1900 return changed;
1901}
1902
1903//--------------------------------------------------------------------------
1904// int pltk_AreWeGrayscale(PlPlotter *plf)
1905//
1906// Determines if we're using a monochrome or grayscale device.
1907// gmf 11-8-91; Courtesy of Paul Martz of Evans and Sutherland.
1908// Changed July 1996 by Vince: now uses Tk to check the enclosing PlPlotter
1909//--------------------------------------------------------------------------
1910
1911static int
1912pltk_AreWeGrayscale( PlPlotter *plf )
1913{
1914#if defined ( __cplusplus ) || defined ( c_plusplus )
1915#define THING c_class
1916#else
1917#define THING class
1918#endif
1919
1920 Visual* visual;
1921 // get the window's Visual
1922 visual = Tk_Visual( plf->tkwin );
1923 if ( ( visual->THING != GrayScale ) && ( visual->THING != StaticGray ) )
1924 return ( 0 );
1925 // if we got this far, only StaticGray and GrayScale classes available
1926 return ( 1 );
1927}
1928
1929#if !defined ( MAC_TCL ) && !defined ( _WIN32 )
1930//--------------------------------------------------------------------------
1931// CreatePixmapErrorHandler()
1932//
1933// Error handler used in CreatePixmap() to catch errors in allocating
1934// storage for pixmap. This way we can nicely substitute redraws for
1935// pixmap copies if the server has insufficient memory.
1936//--------------------------------------------------------------------------
1937
1938static int
1939CreatePixmapErrorHandler( Display *display, XErrorEvent *error )
1940{
1941 if ( error->error_code == BadAlloc )
1942 {
1943 CreatePixmapStatus = error->error_code;
1944 }
1945 else
1946 {
1947 char buffer[256];
1948 XGetErrorText( display, error->error_code, buffer, 256 );
1949 fprintf( stderr, "Error in XCreatePixmap: %s.\n", buffer );
1950 }
1951 return 1;
1952}
1953#endif
1954
1955#else
1956int
1958{
1959 return 0;
1960}
1961
1962#endif // PLD_tkwin
1963
1964void * ckcalloc( size_t nmemb, size_t size )
1965{
1966 long *ptr;
1967 long *p;
1968 size *= nmemb;
1969 ptr = (long *) malloc( size );
1970 if ( !ptr )
1971 return ( 0 );
1972
1973#if !__POWERPC__
1974
1975 for ( size = ( size / sizeof ( long ) ) + 1, p = ptr; --size; )
1976 *p++ = 0;
1977
1978#else
1979
1980 for ( size = ( size / sizeof ( long ) ) + 1, p = ptr - 1; --size; )
1981 *++p = 0;
1982
1983#endif
1984
1985 return ( ptr );
1986}
@ plDevType_Interactive
Definition disptab.h:14
void(* plD_line_fp)(struct PLStream_struct *, short, short, short, short)
Definition disptab.h:68
void(* plD_tidy_fp)(struct PLStream_struct *)
Definition disptab.h:72
void(* plD_bop_fp)(struct PLStream_struct *)
Definition disptab.h:71
void(* plD_wait_fp)(struct PLStream_struct *)
Definition disptab.h:75
void(* plD_state_fp)(struct PLStream_struct *, PLINT)
Definition disptab.h:73
void(* plD_eop_fp)(struct PLStream_struct *)
Definition disptab.h:70
void(* plD_init_fp)(struct PLStream_struct *)
Definition disptab.h:67
void(* plD_esc_fp)(struct PLStream_struct *, PLINT, void *)
Definition disptab.h:74
void(* plD_polyline_fp)(struct PLStream_struct *, short *, short *, PLINT)
Definition disptab.h:69
PLDLLIMPEXP_DRIVER void plD_dispatch_init_tkwin(PLDispatchTable *pdt)
#define MIN(a, b)
Definition dsplint.c:29
#define MAX(a, b)
Definition dsplint.c:28
void plRemakePlot(PLStream *pls)
Definition plbuf.c:1397
static int error
Definition plcont.c:61
void plP_setpxl(PLFLT xpmm, PLFLT ypmm)
Definition plcore.c:4238
void plP_setphy(PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax)
Definition plcore.c:4249
static PLStream * pls[PL_NSTREAMS]
Definition plcore.h:88
void plwarn(PLCHAR_VECTOR errormsg)
Definition plctrl.c:1863
void plcol_interp(PLStream *pls, PLColor *newcolor, int i, int ncol)
Definition plctrl.c:2530
void plexit(PLCHAR_VECTOR errormsg)
Definition plctrl.c:1958
char PLDLLIMPEXP * plstrdup(PLCHAR_VECTOR src)
Definition plctrl.c:2985
#define PLDLLIMPEXP_DRIVER
Definition pldll.h:81
static PLINT * buffer
Definition plfill.c:74
#define PL_MAXPOLY
Definition plplotP.h:283
#define LPAGE_X
Definition plplotP.h:308
#define PIXELS_X
Definition plplotP.h:304
#define PLSTATE_WIDTH
Definition plplotP.h:362
#define PLSTATE_CMAP0
Definition plplotP.h:366
#define PLSTATE_COLOR1
Definition plplotP.h:364
#define DPMM
Definition plplotP.h:306
#define LPAGE_Y
Definition plplotP.h:309
#define PLSTATE_CMAP1
Definition plplotP.h:367
#define PL_RGB_COLOR
Definition plplotP.h:285
#define PLSTATE_COLOR0
Definition plplotP.h:363
#define free_mem(a)
Definition plplotP.h:182
#define PIXELS_Y
Definition plplotP.h:305
#define PLESC_EXPOSE
Definition plplot.h:274
#define PLESC_GETC
Definition plplot.h:283
float PLFLT
Definition plplot.h:163
#define PLESC_EH
Definition plplot.h:282
#define PLESC_FLUSH
Definition plplot.h:281
#define PLESC_RESIZE
Definition plplot.h:275
#define PLESC_FILL
Definition plplot.h:279
int PLINT
Definition plplot.h:181
#define PLESC_REDRAW
Definition plplot.h:276
void PlplotterAtEop(Tcl_Interp *interp, register PlPlotter *plPlotterPtr)
Definition plplotter.c:2546
void PlplotterAtBop(Tcl_Interp *interp, register PlPlotter *plPlotterPtr)
Definition plplotter.c:2556
void pltkwin_setBGFG(PLStream *pls)
static int plplot_tkwin_ccmap
Definition pltkwd.h:41
int PLColor_from_TkColor_Changed(PLColor *plcolor, XColor *xcolor)
#define PLTKDISPLAYS
Definition pltkwd.h:31
void Tkw_StoreColor(PLStream *pls, TkwDisplay *tkwd, XColor *col)
void PLColor_from_TkColor(PLColor *plcolor, XColor *xcolor)
void PLColor_to_TkColor(PLColor *plcolor, XColor *xcolor)
void plD_open_tkwin(PLStream *pls)
static int color
Definition ps.c:78
unsigned char r
Definition plplot.h:548
unsigned char g
Definition plplot.h:549
unsigned char b
Definition plplot.h:550
plD_eop_fp pl_eop
Definition disptab.h:86
const char * pl_DevName
Definition disptab.h:80
plD_esc_fp pl_esc
Definition disptab.h:90
plD_wait_fp pl_wait
Definition disptab.h:91
plD_polyline_fp pl_polyline
Definition disptab.h:85
plD_state_fp pl_state
Definition disptab.h:89
plD_tidy_fp pl_tidy
Definition disptab.h:88
plD_line_fp pl_line
Definition disptab.h:84
plD_init_fp pl_init
Definition disptab.h:83
plD_bop_fp pl_bop
Definition disptab.h:87
const char * pl_MenuStr
Definition disptab.h:79
Tk_Window tkwin
Definition plplotter.c:104
double xscale_init
Definition pltkwd.h:84
short xlen
Definition pltkwd.h:89
unsigned width
Definition pltkwd.h:82
Window window
Definition pltkwd.h:72
double xscale
Definition pltkwd.h:86
unsigned border
Definition pltkwd.h:82
long init_height
Definition pltkwd.h:80
XColor curcolor
Definition pltkwd.h:75
int flags
Definition pltkwd.h:78
Pixmap pixmap
Definition pltkwd.h:73
int write_to_window
Definition pltkwd.h:91
int write_to_pixmap
Definition pltkwd.h:92
int max_instr
Definition pltkwd.h:95
GC gc
Definition pltkwd.h:74
long init_width
Definition pltkwd.h:79
unsigned height
Definition pltkwd.h:82
TkwDisplay * tkwd
Definition pltkwd.h:70
short ylen
Definition pltkwd.h:89
double yscale
Definition pltkwd.h:87
int instr
Definition pltkwd.h:94
double yscale_init
Definition pltkwd.h:85
int nstreams
Definition pltkwd.h:48
int screen
Definition pltkwd.h:51
Display * display
Definition pltkwd.h:52
char * displayName
Definition pltkwd.h:50
int ncol1
Definition pltkwd.h:59
GC gcXor
Definition pltkwd.h:54
Colormap map
Definition pltkwd.h:55
int ncol0
Definition pltkwd.h:58
Visual * visual
Definition pltkwd.h:53
int color
Definition pltkwd.h:57
XColor cmap0[16]
Definition pltkwd.h:60
unsigned depth
Definition pltkwd.h:56
int ixwd
Definition pltkwd.h:49
XColor cmap1[256]
Definition pltkwd.h:61
XColor fgcolor
Definition pltkwd.h:62
#define dbug_enter(a)
Definition tclMatrix.c:65
static Tcl_Interp * interp
Definition tkMain.c:117
static int synchronize
Definition tkMain.c:129
static const char * display
Definition tkMain.c:133
int pldummy_tkwin()
Definition tkwin.c:1957
void * ckcalloc(size_t nmemb, size_t size)
Definition tkwin.c:1964