PLplot
5.10.0
|
00001 // PLplot Tk device driver. 00002 // 00003 // Copyright (C) 2004 Maurice LeBrun 00004 // Copyright (C) 2004 Joao Cardoso 00005 // 00006 // This file is part of PLplot. 00007 // 00008 // PLplot is free software; you can redistribute it and/or modify 00009 // it under the terms of the GNU Library General Public License as published 00010 // by the Free Software Foundation; either version 2 of the License, or 00011 // (at your option) any later version. 00012 // 00013 // PLplot is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 // GNU Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public License 00019 // along with PLplot; if not, write to the Free Software 00020 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 // 00022 // This device driver is designed to be used by a PlPlotter, and in fact requires 00023 // the existence of an enclosing PlPlotter. 00024 // 00025 // The idea is that this should develop into a completely cross-platform driver 00026 // for use by the cross platform Tk system. 00027 // 00028 // 00029 00030 #include "plDevs.h" 00031 00032 #define DEBUG 00033 00034 #ifdef PLD_tkwin 00035 00036 00037 #define NEED_PLDEBUG 00038 #include "plplotP.h" 00039 #include "pltkwd.h" 00040 #include "drivers.h" 00041 #include "plevent.h" 00042 00043 #define _TCLINT 00044 #ifdef USE_TCL_STUBS 00045 // Unfortunately, tkInt.h ends up loading Malloc.h under Windows 00046 // So we have to deal with this mess 00047 #undef malloc 00048 #undef free 00049 #undef realloc 00050 #undef calloc 00051 #if defined ( __WIN32__ ) || defined ( MAC_TCL ) 00052 #include <tkInt.h> 00053 #else 00054 #include <tk.h> 00055 #endif 00056 #define malloc ckalloc 00057 #define free( m ) ckfree( (char *) m ) 00058 #define realloc ckrealloc 00059 #define calloc ckcalloc 00060 #else 00061 #if defined ( __WIN32__ ) || defined ( MAC_TCL ) 00062 #include <tkInt.h> 00063 #else 00064 #include <tk.h> 00065 #endif 00066 #endif 00067 00068 #ifdef ckalloc 00069 #undef ckalloc 00070 #define ckalloc malloc 00071 #endif 00072 #ifdef ckfree 00073 #undef ckfree 00074 #define ckfree free 00075 #endif 00076 #ifdef free 00077 #undef free 00078 #endif 00079 00080 // Device info 00081 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_tkwin = "tkwin:New tk driver:1:tkwin:45:tkwin\n"; 00082 00083 00084 void * ckcalloc( size_t nmemb, size_t size ); 00085 00086 // 00087 // We want to use the 'pure Tk' interface. On Unix we can use 00088 // some direct calls to X instead of Tk, if we want, although 00089 // that code hasn't been tested for some time. So this define 00090 // is required on Windows/MacOS and perhaps optional on Unix. 00091 // 00092 #define USE_TK 00093 00094 #ifdef __WIN32__ 00095 #define XSynchronize( display, bool ) { display->request++; } 00096 #define XSync( display, bool ) { display->request++; } 00097 #define XFlush( display ) 00098 #endif 00099 00100 // Dummy definition of PlPlotter containing first few fields 00101 typedef struct PlPlotter 00102 { 00103 Tk_Window tkwin; // Window that embodies the frame. NULL 00104 // means that the window has been destroyed 00105 // but the data structures haven't yet been 00106 // cleaned up. 00107 // 00108 Display *display; // Display containing widget. Used, among 00109 // other things, so that resources can be 00110 // freed even after tkwin has gone away. 00111 // 00112 Tcl_Interp *interp; // Interpreter associated with 00113 // widget. Used to delete widget 00114 // command. 00115 // 00116 } PlPlotter; 00117 00118 void CopyColour( XColor* from, XColor* to ); 00119 void Tkw_StoreColor( PLStream* pls, TkwDisplay* tkwd, XColor* col ); 00120 static int pltk_AreWeGrayscale( PlPlotter *plf ); 00121 void PlplotterAtEop( Tcl_Interp *interp, register PlPlotter *plPlotterPtr ); 00122 void PlplotterAtBop( Tcl_Interp *interp, register PlPlotter *plPlotterPtr ); 00123 00124 static int synchronize = 0; // change to 1 for synchronized operation 00125 // for debugging only 00126 00127 // Number of instructions to skip between querying the X server for events 00128 00129 #define MAX_INSTR 20 00130 00131 // Pixels/mm 00132 00133 #define PHYSICAL 0 // Enables physical scaling.. 00134 00135 // Set constants for dealing with colormap. In brief: 00136 // 00137 // ccmap When set, turns on custom color map 00138 // 00139 // XWM_COLORS Number of low "pixel" values to copy. 00140 // CMAP0_COLORS Color map 0 entries. 00141 // CMAP1_COLORS Color map 1 entries. 00142 // MAX_COLORS Maximum colors period. 00143 // 00144 // See Init_CustomCmap() and Init_DefaultCmap() for more info. 00145 // Set ccmap at your own risk -- still under development. 00146 // 00147 00148 // plplot_tkwin_ccmap is statically defined in pltkwd.h. Note that 00149 // plplotter.c also includes that header and uses that variable. 00150 00151 #define XWM_COLORS 70 00152 #define CMAP0_COLORS 16 00153 #define CMAP1_COLORS 50 00154 #define MAX_COLORS 256 00155 00156 #ifndef USE_TK 00157 // Variables to hold RGB components of given colormap. 00158 // Used in an ugly hack to get past some X11R5 and TK limitations. 00159 00160 static int sxwm_colors_set; 00161 static XColor sxwm_colors[MAX_COLORS]; 00162 #endif 00163 00164 // Keep pointers to all the displays in use 00165 00166 static TkwDisplay *tkwDisplay[PLTKDISPLAYS]; 00167 00168 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) 00169 static unsigned char CreatePixmapStatus; 00170 static int CreatePixmapErrorHandler( Display *display, XErrorEvent *error ); 00171 #endif 00172 00173 // Function prototypes 00174 // Initialization 00175 00176 static void Init( PLStream *pls ); 00177 static void InitColors( PLStream *pls ); 00178 static void AllocCustomMap( PLStream *pls ); 00179 static void AllocCmap0( PLStream *pls ); 00180 static void AllocCmap1( PLStream *pls ); 00181 static void CreatePixmap( PLStream *pls ); 00182 static void GetVisual( PLStream *pls ); 00183 static void AllocBGFG( PLStream *pls ); 00184 00185 // Escape function commands 00186 00187 static void ExposeCmd( PLStream *pls, PLDisplay *ptr ); 00188 static void RedrawCmd( PLStream *pls ); 00189 static void ResizeCmd( PLStream *pls, PLDisplay *ptr ); 00190 #ifndef USE_TK 00191 static void GetCursorCmd( PLStream *pls, PLGraphicsIn *ptr ); 00192 #endif 00193 static void FillPolygonCmd( PLStream *pls ); 00194 #ifdef USING_PLESC_COPY 00195 static void CopyCommand( PLStream *pls ); 00196 #endif 00197 00198 // Miscellaneous 00199 00200 static void StoreCmap0( PLStream *pls ); 00201 static void StoreCmap1( PLStream *pls ); 00202 static void WaitForPage( PLStream *pls ); 00203 00204 void plD_dispatch_init_tkwin( PLDispatchTable *pdt ); 00205 00206 void plD_init_tkwin( PLStream * ); 00207 void plD_line_tkwin( PLStream *, short, short, short, short ); 00208 void plD_polyline_tkwin( PLStream *, short *, short *, PLINT ); 00209 void plD_eop_tkwin( PLStream * ); 00210 void plD_bop_tkwin( PLStream * ); 00211 void plD_tidy_tkwin( PLStream * ); 00212 void plD_state_tkwin( PLStream *, PLINT ); 00213 void plD_esc_tkwin( PLStream *, PLINT, void * ); 00214 void plD_open_tkwin( PLStream *pls ); 00215 00216 void plD_dispatch_init_tkwin( PLDispatchTable *pdt ) 00217 { 00218 #ifndef ENABLE_DYNDRIVERS 00219 pdt->pl_MenuStr = "PLplot Tk plotter"; 00220 pdt->pl_DevName = "tkwin"; 00221 #endif 00222 pdt->pl_type = plDevType_Interactive; 00223 pdt->pl_seq = 45; 00224 pdt->pl_init = (plD_init_fp) plD_init_tkwin; 00225 pdt->pl_line = (plD_line_fp) plD_line_tkwin; 00226 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_tkwin; 00227 pdt->pl_eop = (plD_eop_fp) plD_eop_tkwin; 00228 pdt->pl_bop = (plD_bop_fp) plD_bop_tkwin; 00229 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_tkwin; 00230 pdt->pl_state = (plD_state_fp) plD_state_tkwin; 00231 pdt->pl_esc = (plD_esc_fp) plD_esc_tkwin; 00232 } 00233 00234 //-------------------------------------------------------------------------- 00235 // plD_init_tkwin() 00236 // 00237 // Initialize device. 00238 // Tk-dependent stuff done in plD_open_tkwin() and Init(). 00239 //-------------------------------------------------------------------------- 00240 00241 void 00242 plD_init_tkwin( PLStream *pls ) 00243 { 00244 TkwDev *dev; 00245 float pxlx, pxly; 00246 int xmin = 0; 00247 int xmax = PIXELS_X - 1; 00248 int ymin = 0; 00249 int ymax = PIXELS_Y - 1; 00250 00251 dbug_enter( "plD_init_tkw" ); 00252 00253 pls->termin = 1; // Is an interactive terminal 00254 pls->dev_flush = 1; // Handle our own flushes 00255 pls->dev_fill0 = 1; // Handle solid fills 00256 pls->plbuf_write = 1; // Activate plot buffer 00257 00258 // The real meat of the initialization done here 00259 00260 if ( pls->dev == NULL ) 00261 plD_open_tkwin( pls ); 00262 00263 dev = (TkwDev *) pls->dev; 00264 00265 Init( pls ); 00266 00267 // Get ready for plotting 00268 00269 dev->xlen = (short) ( xmax - xmin ); 00270 dev->ylen = (short) ( ymax - ymin ); 00271 00272 dev->xscale_init = (double) dev->init_width / (double) dev->xlen; 00273 dev->yscale_init = (double) dev->init_height / (double) dev->ylen; 00274 00275 dev->xscale = dev->xscale_init; 00276 dev->yscale = dev->yscale_init; 00277 00278 #if PHYSICAL 00279 pxlx = (PLFLT) ( (double) PIXELS_X / dev->width * DPMM ); 00280 pxly = (PLFLT) ( (double) PIXELS_Y / dev->height * DPMM ); 00281 #else 00282 pxlx = (PLFLT) ( (double) PIXELS_X / LPAGE_X ); 00283 pxly = (PLFLT) ( (double) PIXELS_Y / LPAGE_Y ); 00284 #endif 00285 00286 plP_setpxl( pxlx, pxly ); 00287 plP_setphy( xmin, xmax, ymin, ymax ); 00288 } 00289 00290 //-------------------------------------------------------------------------- 00291 // plD_open_tkwin() 00292 // 00293 // Performs basic driver initialization, without actually opening or 00294 // modifying a window. May be called by the outside world before plinit 00295 // in case the caller needs early access to the driver internals (not 00296 // very common -- currently only used externally by plplotter). 00297 //-------------------------------------------------------------------------- 00298 00299 void 00300 plD_open_tkwin( PLStream *pls ) 00301 { 00302 TkwDev *dev; 00303 TkwDisplay *tkwd; 00304 int i; 00305 00306 dbug_enter( "plD_open_tkw" ); 00307 00308 // Allocate and initialize device-specific data 00309 00310 if ( pls->dev != NULL ) 00311 plwarn( "plD_open_tkw: device pointer is already set" ); 00312 00313 pls->dev = (TkwDev *) calloc( 1, (size_t) sizeof ( TkwDev ) ); 00314 if ( pls->dev == NULL ) 00315 plexit( "plD_init_tkw: Out of memory." ); 00316 00317 dev = (TkwDev *) pls->dev; 00318 00319 // Variables used in querying the X server for events 00320 00321 dev->instr = 0; 00322 dev->max_instr = MAX_INSTR; 00323 00324 // See if display matches any already in use, and if so use that 00325 00326 dev->tkwd = NULL; 00327 for ( i = 0; i < PLTKDISPLAYS; i++ ) 00328 { 00329 if ( tkwDisplay[i] == NULL ) 00330 { 00331 continue; 00332 } 00333 else if ( pls->FileName == NULL && tkwDisplay[i]->displayName == NULL ) 00334 { 00335 dev->tkwd = tkwDisplay[i]; 00336 break; 00337 } 00338 else if ( pls->FileName == NULL || tkwDisplay[i]->displayName == NULL ) 00339 { 00340 continue; 00341 } 00342 else if ( strcmp( tkwDisplay[i]->displayName, pls->FileName ) == 0 ) 00343 { 00344 dev->tkwd = tkwDisplay[i]; 00345 break; 00346 } 00347 } 00348 00349 // If no display matched, create a new one 00350 00351 if ( dev->tkwd == NULL ) 00352 { 00353 dev->tkwd = (TkwDisplay *) calloc( 1, (size_t) sizeof ( TkwDisplay ) ); 00354 if ( dev->tkwd == NULL ) 00355 plexit( "Init: Out of memory." ); 00356 00357 for ( i = 0; i < PLTKDISPLAYS; i++ ) 00358 { 00359 if ( tkwDisplay[i] == NULL ) 00360 break; 00361 } 00362 if ( i == PLTKDISPLAYS ) 00363 plexit( "Init: Out of tkwDisplay's." ); 00364 00365 tkwDisplay[i] = tkwd = (TkwDisplay *) dev->tkwd; 00366 tkwd->nstreams = 1; 00367 00368 // 00369 // If we don't have a tk widget we're being called on, then 00370 // abort operations now 00371 // 00372 if ( pls->plPlotterPtr == NULL ) 00373 { 00374 plexit( "No tk plframe widget to connect to" ); 00375 } 00376 // Old version for MacOS Tk8.0 00377 // 00378 // char deflt[] = "Macintosh:0"; 00379 // pls->FileName = deflt; 00380 // tkwd->display = (Display*) TkpOpenDisplay(pls->FileName); 00381 // 00382 00383 // Open display 00384 #if defined ( MAC_TCL ) || defined ( __WIN32__ ) 00385 if ( !pls->FileName ) 00386 { 00387 // 00388 // Need to strdup because Tk has allocated the screen name, 00389 // but we will actually 'free' it later ourselves, and therefore 00390 // need to own the memory. 00391 // 00392 pls->FileName = plstrdup( TkGetDefaultScreenName( NULL, NULL ) ); 00393 } 00394 tkwd->display = pls->plPlotterPtr->display; 00395 #else 00396 tkwd->display = XOpenDisplay( pls->FileName ); 00397 #endif 00398 if ( tkwd->display == NULL ) 00399 { 00400 plexit( "Can't open display" ); 00401 } 00402 tkwd->displayName = pls->FileName; 00403 tkwd->screen = DefaultScreen( tkwd->display ); 00404 if ( synchronize ) 00405 { 00406 XSynchronize( tkwd->display, 1 ); 00407 } 00408 // Get colormap and visual 00409 00410 tkwd->map = Tk_Colormap( pls->plPlotterPtr->tkwin ); 00411 GetVisual( pls ); 00412 00413 // 00414 // Figure out if we have a color display or not. 00415 // Default is color IF the user hasn't specified and IF the output device is 00416 // not grayscale. 00417 // 00418 00419 if ( pls->colorset ) 00420 tkwd->color = pls->color; 00421 else 00422 { 00423 pls->color = 1; 00424 tkwd->color = !pltk_AreWeGrayscale( pls->plPlotterPtr ); 00425 } 00426 00427 // Allocate & set background and foreground colors 00428 00429 AllocBGFG( pls ); 00430 pltkwin_setBGFG( pls ); 00431 } 00432 00433 // Display matched, so use existing display data 00434 00435 else 00436 { 00437 tkwd = (TkwDisplay *) dev->tkwd; 00438 tkwd->nstreams++; 00439 } 00440 tkwd->ixwd = i; 00441 } 00442 00443 //-------------------------------------------------------------------------- 00444 // plD_line_tkwin() 00445 // 00446 // Draw a line in the current color from (x1,y1) to (x2,y2). 00447 //-------------------------------------------------------------------------- 00448 00449 void 00450 plD_line_tkwin( PLStream *pls, short x1a, short y1a, short x2a, short y2a ) 00451 { 00452 TkwDev *dev = (TkwDev *) pls->dev; 00453 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 00454 00455 int x1 = x1a, y1 = y1a, x2 = x2a, y2 = y2a; 00456 00457 if ( dev->flags & 1 ) 00458 return; 00459 00460 y1 = dev->ylen - y1; 00461 y2 = dev->ylen - y2; 00462 00463 x1 = (int) ( x1 * dev->xscale ); 00464 x2 = (int) ( x2 * dev->xscale ); 00465 y1 = (int) ( y1 * dev->yscale ); 00466 y2 = (int) ( y2 * dev->yscale ); 00467 00468 if ( dev->write_to_window ) 00469 XDrawLine( tkwd->display, dev->window, dev->gc, x1, y1, x2, y2 ); 00470 00471 if ( dev->write_to_pixmap ) 00472 XDrawLine( tkwd->display, dev->pixmap, dev->gc, x1, y1, x2, y2 ); 00473 } 00474 00475 //-------------------------------------------------------------------------- 00476 // plD_polyline_tkwin() 00477 // 00478 // Draw a polyline in the current color from (x1,y1) to (x2,y2). 00479 //-------------------------------------------------------------------------- 00480 00481 void 00482 plD_polyline_tkwin( PLStream *pls, short *xa, short *ya, PLINT npts ) 00483 { 00484 TkwDev *dev = (TkwDev *) pls->dev; 00485 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 00486 00487 PLINT i; 00488 XPoint _pts[PL_MAXPOLY]; 00489 XPoint *pts; 00490 00491 if ( dev->flags & 1 ) 00492 return; 00493 00494 if ( npts > PL_MAXPOLY ) 00495 { 00496 pts = (XPoint *) malloc( sizeof ( XPoint ) * (size_t) npts ); 00497 } 00498 else 00499 { 00500 pts = _pts; 00501 } 00502 00503 for ( i = 0; i < npts; i++ ) 00504 { 00505 pts[i].x = (short) ( dev->xscale * xa[i] ); 00506 pts[i].y = (short) ( dev->yscale * ( dev->ylen - ya[i] ) ); 00507 } 00508 00509 if ( dev->write_to_window ) 00510 XDrawLines( tkwd->display, dev->window, dev->gc, pts, npts, 00511 CoordModeOrigin ); 00512 00513 if ( dev->write_to_pixmap ) 00514 XDrawLines( tkwd->display, dev->pixmap, dev->gc, pts, npts, 00515 CoordModeOrigin ); 00516 00517 if ( npts > PL_MAXPOLY ) 00518 { 00519 free( pts ); 00520 } 00521 } 00522 00523 //-------------------------------------------------------------------------- 00524 // plD_eop_tkwin() 00525 // 00526 // End of page. User must hit return (or third mouse button) to continue. 00527 //-------------------------------------------------------------------------- 00528 00529 void 00530 plD_eop_tkwin( PLStream *pls ) 00531 { 00532 TkwDev *dev = (TkwDev *) pls->dev; 00533 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 00534 00535 dbug_enter( "plD_eop_tkw" ); 00536 if ( dev->flags & 1 ) 00537 return; 00538 00539 XFlush( tkwd->display ); 00540 if ( pls->db ) 00541 ExposeCmd( pls, NULL ); 00542 00543 if ( !pls->nopause ) 00544 WaitForPage( pls ); 00545 } 00546 00547 //-------------------------------------------------------------------------- 00548 // WaitForPage() 00549 // 00550 // This routine waits for the user to advance the plot, while handling 00551 // all other events. 00552 //-------------------------------------------------------------------------- 00553 00554 static void 00555 WaitForPage( PLStream *pls ) 00556 { 00557 PlPlotter *plf = pls->plPlotterPtr; 00558 TkwDev *dev = (TkwDev *) pls->dev; 00559 00560 dbug_enter( "WaitForPage" ); 00561 00562 dev->flags &= 1; 00563 if ( plf == NULL ) 00564 { 00565 plwarn( "WaitForPage: Illegal call --- driver can't find enclosing PlPlotter" ); 00566 return; 00567 } 00568 PlplotterAtEop( plf->interp, plf ); 00569 00570 while ( !( dev->flags ) && !Tcl_InterpDeleted( plf->interp ) && ( Tk_GetNumMainWindows() > 0 ) ) 00571 { 00572 Tcl_DoOneEvent( 0 ); 00573 } 00574 00575 if ( Tcl_InterpDeleted( plf->interp ) || ( Tk_GetNumMainWindows() <= 0 ) ) 00576 { 00577 dev->flags |= 1; 00578 } 00579 00580 dev->flags &= 1; 00581 } 00582 00583 //-------------------------------------------------------------------------- 00584 // plD_bop_tkwin() 00585 // 00586 // Set up for the next page. 00587 //-------------------------------------------------------------------------- 00588 00589 void 00590 plD_bop_tkwin( PLStream *pls ) 00591 { 00592 PlPlotter *plf = pls->plPlotterPtr; 00593 TkwDev *dev = (TkwDev *) pls->dev; 00594 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 00595 00596 XRectangle xrect; 00597 xrect.x = 0; xrect.y = 0; 00598 xrect.width = (short unsigned) dev->width; 00599 xrect.height = (short unsigned) dev->height; 00600 00601 dbug_enter( "plD_bop_tkw" ); 00602 if ( dev->flags & 1 ) 00603 return; 00604 00605 if ( dev->write_to_window ) 00606 { 00607 #ifdef MAC_TCL 00608 // MacTk only has these X calls 00609 XSetForeground( tkwd->display, dev->gc, tkwd->cmap0[0].pixel ); 00610 XFillRectangles( tkwd->display, dev->window, dev->gc, &xrect, 1 ); 00611 XSetForeground( tkwd->display, dev->gc, dev->curcolor.pixel ); 00612 #else 00613 XClearWindow( tkwd->display, dev->window ); 00614 #endif 00615 } 00616 if ( dev->write_to_pixmap ) 00617 { 00618 XSetForeground( tkwd->display, dev->gc, tkwd->cmap0[0].pixel ); 00619 XFillRectangles( tkwd->display, dev->pixmap, dev->gc, &xrect, 1 ); 00620 XSetForeground( tkwd->display, dev->gc, dev->curcolor.pixel ); 00621 } 00622 XSync( tkwd->display, 0 ); 00623 pls->page++; 00624 PlplotterAtBop( plf->interp, plf ); 00625 } 00626 00627 //-------------------------------------------------------------------------- 00628 // plD_tidy_tkwin() 00629 // 00630 // Close graphics file 00631 //-------------------------------------------------------------------------- 00632 00633 void 00634 plD_tidy_tkwin( PLStream *pls ) 00635 { 00636 TkwDev *dev = (TkwDev *) pls->dev; 00637 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 00638 00639 dbug_enter( "plD_tidy_tkw" ); 00640 00641 tkwd->nstreams--; 00642 if ( tkwd->nstreams == 0 ) 00643 { 00644 int ixwd = tkwd->ixwd; 00645 XFreeGC( tkwd->display, dev->gc ); 00646 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) 00647 XCloseDisplay( tkwd->display ); 00648 #endif 00649 free_mem( tkwDisplay[ixwd] ); 00650 } 00651 // 00652 // Vince removed this November 1999. It seems as if a simple 00653 // 'plframe .p ; destroy .p' leaves a temporary buf file open 00654 // if we clear this flag here. It should be checked and then 00655 // cleared by whoever called us. An alternative fix would 00656 // be to carry out the check/tidy here. The plframe widget 00657 // handles this stuff for us. 00658 // 00659 // pls->plbuf_write = 0; 00660 } 00661 00662 //-------------------------------------------------------------------------- 00663 // plD_state_tkwin() 00664 // 00665 // Handle change in PLStream state (color, pen width, fill attribute, etc). 00666 //-------------------------------------------------------------------------- 00667 00668 void 00669 plD_state_tkwin( PLStream *pls, PLINT op ) 00670 { 00671 TkwDev *dev = (TkwDev *) pls->dev; 00672 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 00673 dbug_enter( "plD_state_tkw" ); 00674 if ( dev->flags & 1 ) 00675 return; 00676 00677 switch ( op ) 00678 { 00679 case PLSTATE_WIDTH: 00680 break; 00681 00682 case PLSTATE_COLOR0: { 00683 int icol0 = pls->icol0; 00684 if ( tkwd->color ) 00685 { 00686 if ( icol0 == PL_RGB_COLOR ) 00687 { 00688 PLColor_to_TkColor( &pls->curcolor, &dev->curcolor ); 00689 Tkw_StoreColor( pls, tkwd, &dev->curcolor ); 00690 } 00691 else 00692 { 00693 dev->curcolor = tkwd->cmap0[icol0]; 00694 } 00695 XSetForeground( tkwd->display, dev->gc, dev->curcolor.pixel ); 00696 } 00697 else 00698 { 00699 dev->curcolor = tkwd->fgcolor; 00700 XSetForeground( tkwd->display, dev->gc, dev->curcolor.pixel ); 00701 } 00702 break; 00703 } 00704 00705 case PLSTATE_COLOR1: { 00706 int icol1; 00707 00708 if ( tkwd->ncol1 == 0 ) 00709 AllocCmap1( pls ); 00710 00711 if ( tkwd->ncol1 < 2 ) 00712 break; 00713 00714 icol1 = ( pls->icol1 * ( tkwd->ncol1 - 1 ) ) / ( pls->ncol1 - 1 ); 00715 if ( tkwd->color ) 00716 dev->curcolor = tkwd->cmap1[icol1]; 00717 else 00718 dev->curcolor = tkwd->fgcolor; 00719 00720 XSetForeground( tkwd->display, dev->gc, dev->curcolor.pixel ); 00721 break; 00722 } 00723 00724 case PLSTATE_CMAP0: 00725 pltkwin_setBGFG( pls ); 00726 StoreCmap0( pls ); 00727 break; 00728 00729 case PLSTATE_CMAP1: 00730 StoreCmap1( pls ); 00731 break; 00732 } 00733 } 00734 00735 //-------------------------------------------------------------------------- 00736 // plD_esc_tkwin() 00737 // 00738 // Escape function. 00739 // 00740 // Functions: 00741 // 00742 // PLESC_EH Handle pending events 00743 // PLESC_EXPOSE Force an expose 00744 // PLESC_FILL Fill polygon 00745 // PLESC_FLUSH Flush X event buffer 00746 // PLESC_GETC Get coordinates upon mouse click 00747 // PLESC_REDRAW Force a redraw 00748 // PLESC_RESIZE Force a resize 00749 //-------------------------------------------------------------------------- 00750 00751 void 00752 plD_esc_tkwin( PLStream *pls, PLINT op, void *ptr ) 00753 { 00754 TkwDev *dev = (TkwDev *) pls->dev; 00755 #ifndef USE_TK 00756 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 00757 #endif 00758 dbug_enter( "plD_esc_tkw" ); 00759 if ( dev->flags & 1 ) 00760 return; 00761 00762 switch ( op ) 00763 { 00764 case PLESC_EH: 00765 #ifndef USE_TK 00766 HandleEvents( pls ); 00767 #endif 00768 break; 00769 00770 case PLESC_EXPOSE: 00771 ExposeCmd( pls, (PLDisplay *) ptr ); 00772 break; 00773 00774 case PLESC_FILL: 00775 FillPolygonCmd( pls ); 00776 break; 00777 00778 case PLESC_FLUSH: 00779 #ifndef USE_TK 00780 HandleEvents( pls ); 00781 XFlush( tkwd->display ); 00782 #endif 00783 break; 00784 00785 case PLESC_GETC: 00786 #ifndef USE_TK 00787 GetCursorCmd( pls, (PLGraphicsIn *) ptr ); 00788 #endif 00789 break; 00790 00791 case PLESC_REDRAW: 00792 RedrawCmd( pls ); 00793 break; 00794 00795 case PLESC_RESIZE: 00796 ResizeCmd( pls, (PLDisplay *) ptr ); 00797 break; 00798 00799 // Added by Vince, disabled by default since we want a minimal patch 00800 #ifdef USING_PLESC_COPY 00801 case PLESC_COPY: 00802 CopyCommand( pls ); 00803 break; 00804 #endif 00805 } 00806 } 00807 00808 #ifdef USING_PLESC_COPY 00809 //-------------------------------------------------------------------------- 00810 // CopyCommand() 00811 // 00812 // Copy a rectangle to a new part of the image. 00813 // Points described in first 3 elements of pls->dev_x[] and pls->dev_y[]. 00814 //-------------------------------------------------------------------------- 00815 00816 static void 00817 CopyCommand( PLStream *pls ) 00818 { 00819 int x0, w, x1, y0, h, y1; 00820 TkwDev *dev = (TkwDev *) pls->dev; 00821 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 00822 00823 x0 = (int) ( dev->xscale * pls->dev_x[0] ); 00824 x1 = (int) ( dev->xscale * pls->dev_x[2] ); 00825 y0 = (int) ( dev->yscale * ( dev->ylen - pls->dev_y[0] ) ); 00826 y1 = (int) ( dev->yscale * ( dev->ylen - pls->dev_y[2] ) ); 00827 w = (int) ( dev->xscale * ( pls->dev_x[1] - pls->dev_x[0] ) ); 00828 h = (int) ( -dev->yscale * ( pls->dev_y[1] - pls->dev_y[0] ) ); 00829 00830 if ( dev->write_to_window ) 00831 XCopyArea( tkwd->display, dev->window, dev->window, dev->gc, 00832 x0, y0, w, h, x1, y1 ); 00833 00834 if ( dev->write_to_pixmap ) 00835 XCopyArea( tkwd->display, dev->pixmap, dev->pixmap, dev->gc, 00836 x0, y0, w, h, x1, y1 ); 00837 } 00838 #endif 00839 00840 //-------------------------------------------------------------------------- 00841 // FillPolygonCmd() 00842 // 00843 // Fill polygon described in points pls->dev_x[] and pls->dev_y[]. 00844 // Only solid color fill supported. 00845 //-------------------------------------------------------------------------- 00846 00847 static void 00848 FillPolygonCmd( PLStream *pls ) 00849 { 00850 TkwDev *dev = (TkwDev *) pls->dev; 00851 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 00852 XPoint _pts[PL_MAXPOLY]; 00853 XPoint *pts; 00854 int i; 00855 00856 if ( pls->dev_npts > PL_MAXPOLY ) 00857 { 00858 pts = (XPoint *) malloc( sizeof ( XPoint ) * (size_t) ( pls->dev_npts ) ); 00859 } 00860 else 00861 { 00862 pts = _pts; 00863 } 00864 00865 for ( i = 0; i < pls->dev_npts; i++ ) 00866 { 00867 pts[i].x = (short) ( dev->xscale * pls->dev_x[i] ); 00868 pts[i].y = (short) ( dev->yscale * ( dev->ylen - pls->dev_y[i] ) ); 00869 } 00870 00871 // Fill polygons 00872 00873 if ( dev->write_to_window ) 00874 XFillPolygon( tkwd->display, dev->window, dev->gc, 00875 pts, pls->dev_npts, Nonconvex, CoordModeOrigin ); 00876 00877 if ( dev->write_to_pixmap ) 00878 XFillPolygon( tkwd->display, dev->pixmap, dev->gc, 00879 pts, pls->dev_npts, Nonconvex, CoordModeOrigin ); 00880 00881 // If in debug mode, draw outline of boxes being filled 00882 00883 #ifdef DEBUG 00884 if ( pls->debug ) 00885 { 00886 XSetForeground( tkwd->display, dev->gc, tkwd->fgcolor.pixel ); 00887 if ( dev->write_to_window ) 00888 XDrawLines( tkwd->display, dev->window, dev->gc, pts, pls->dev_npts, 00889 CoordModeOrigin ); 00890 00891 if ( dev->write_to_pixmap ) 00892 XDrawLines( tkwd->display, dev->pixmap, dev->gc, pts, pls->dev_npts, 00893 CoordModeOrigin ); 00894 00895 XSetForeground( tkwd->display, dev->gc, dev->curcolor.pixel ); 00896 } 00897 #endif 00898 00899 if ( pls->dev_npts > PL_MAXPOLY ) 00900 { 00901 free( pts ); 00902 } 00903 } 00904 00905 //-------------------------------------------------------------------------- 00906 // Init() 00907 // 00908 // Xlib initialization routine. 00909 // 00910 // Controlling routine for X window creation and/or initialization. 00911 // The user may customize the window in the following ways: 00912 // 00913 // display: pls->OutFile (use plsfnam() or -display option) 00914 // size: pls->xlength, pls->ylength (use plspage() or -geo option) 00915 // bg color: pls->cmap0[0] (use plscolbg() or -bg option) 00916 //-------------------------------------------------------------------------- 00917 00918 static void 00919 Init( PLStream *pls ) 00920 { 00921 PlPlotter *plf; 00922 TkwDev *dev = (TkwDev *) pls->dev; 00923 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 00924 00925 dbug_enter( "Init" ); 00926 00927 dev->window = (Window) pls->window_id; 00928 00929 plf = pls->plPlotterPtr; 00930 if ( plf == NULL ) 00931 { 00932 plwarn( "Init: Illegal call --- driver can't find enclosing PlPlotter" ); 00933 return; 00934 } 00935 00936 // Initialize colors 00937 InitColors( pls ); 00938 #ifndef MAC_TCL 00939 XSetWindowColormap( tkwd->display, dev->window, tkwd->map ); 00940 #else 00941 #endif 00942 00943 // Set up GC for ordinary draws 00944 if ( !dev->gc ) 00945 dev->gc = XCreateGC( tkwd->display, dev->window, 0, 0 ); 00946 00947 // Set up GC for rubber-band draws 00948 if ( !tkwd->gcXor ) 00949 { 00950 XGCValues gcValues; 00951 unsigned long mask; 00952 00953 gcValues.background = tkwd->cmap0[0].pixel; 00954 gcValues.foreground = 0xFF; 00955 gcValues.function = GXxor; 00956 mask = GCForeground | GCBackground | GCFunction; 00957 00958 tkwd->gcXor = XCreateGC( tkwd->display, dev->window, mask, &gcValues ); 00959 } 00960 00961 // Get initial drawing area dimensions 00962 dev->width = (unsigned int) Tk_Width( plf->tkwin ); 00963 dev->height = (unsigned int) Tk_Height( plf->tkwin ); 00964 dev->border = (unsigned int) Tk_InternalBorderWidth( plf->tkwin ); 00965 tkwd->depth = (unsigned int) Tk_Depth( plf->tkwin ); 00966 00967 dev->init_width = dev->width; 00968 dev->init_height = dev->height; 00969 00970 // Set up flags that determine what we are writing to 00971 // If nopixmap is set, ignore db 00972 00973 if ( pls->nopixmap ) 00974 { 00975 dev->write_to_pixmap = 0; 00976 pls->db = 0; 00977 } 00978 else 00979 { 00980 dev->write_to_pixmap = 1; 00981 } 00982 dev->write_to_window = !pls->db; 00983 00984 // Create pixmap for holding plot image (for expose events). 00985 00986 if ( dev->write_to_pixmap ) 00987 CreatePixmap( pls ); 00988 00989 // Set drawing color 00990 00991 plD_state_tkwin( pls, PLSTATE_COLOR0 ); 00992 00993 XSetWindowBackground( tkwd->display, dev->window, tkwd->cmap0[0].pixel ); 00994 XSetBackground( tkwd->display, dev->gc, tkwd->cmap0[0].pixel ); 00995 } 00996 00997 //-------------------------------------------------------------------------- 00998 // ExposeCmd() 00999 // 01000 // Event handler routine for expose events. 01001 // These are "pure" exposures (no resize), so don't need to clear window. 01002 //-------------------------------------------------------------------------- 01003 01004 static void 01005 ExposeCmd( PLStream *pls, PLDisplay *pldis ) 01006 { 01007 TkwDev *dev = (TkwDev *) pls->dev; 01008 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 01009 int x, y, width, height; 01010 01011 dbug_enter( "ExposeCmd" ); 01012 01013 // Return if plD_init_tkw hasn't been called yet 01014 01015 if ( dev == NULL ) 01016 { 01017 plwarn( "ExposeCmd: Illegal call -- driver uninitialized" ); 01018 return; 01019 } 01020 01021 // Exposed area. If unspecified, the entire window is used. 01022 01023 if ( pldis == NULL ) 01024 { 01025 x = 0; 01026 y = 0; 01027 width = (int) dev->width; 01028 height = (int) dev->height; 01029 } 01030 else 01031 { 01032 x = (int) pldis->x; 01033 y = (int) pldis->y; 01034 width = (int) pldis->width; 01035 height = (int) pldis->height; 01036 } 01037 01038 // Usual case: refresh window from pixmap 01039 // DEBUG option: draws rectangle around refreshed region 01040 01041 XSync( tkwd->display, 0 ); 01042 if ( dev->write_to_pixmap ) 01043 { 01044 XCopyArea( tkwd->display, dev->pixmap, dev->window, dev->gc, 01045 x, y, (unsigned int) width, (unsigned int) height, x, y ); 01046 XSync( tkwd->display, 0 ); 01047 #ifdef DEBUG 01048 if ( pls->debug ) 01049 { 01050 XPoint pts[5]; 01051 int x0 = x, x1 = x + width, y0 = y, y1 = y + height; 01052 pts[0].x = (short) x0; pts[0].y = (short) y0; 01053 pts[1].x = (short) x1; pts[1].y = (short) y0; 01054 pts[2].x = (short) x1; pts[2].y = (short) y1; 01055 pts[3].x = (short) x0; pts[3].y = (short) y1; 01056 pts[4].x = (short) x0; pts[4].y = (short) y0; 01057 01058 XDrawLines( tkwd->display, dev->window, dev->gc, pts, 5, 01059 CoordModeOrigin ); 01060 } 01061 #endif 01062 } 01063 else 01064 { 01065 plRemakePlot( pls ); 01066 XFlush( tkwd->display ); 01067 } 01068 } 01069 01070 //-------------------------------------------------------------------------- 01071 // ResizeCmd() 01072 // 01073 // Event handler routine for resize events. 01074 //-------------------------------------------------------------------------- 01075 01076 static void 01077 ResizeCmd( PLStream *pls, PLDisplay *pldis ) 01078 { 01079 TkwDev *dev = (TkwDev *) pls->dev; 01080 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 01081 int write_to_window = dev->write_to_window; 01082 01083 dbug_enter( "ResizeCmd" ); 01084 01085 // Return if plD_init_tkw hasn't been called yet 01086 01087 if ( dev == NULL ) 01088 { 01089 plwarn( "ResizeCmd: Illegal call -- driver uninitialized" ); 01090 return; 01091 } 01092 01093 // Return if pointer to window not specified. 01094 01095 if ( pldis == NULL ) 01096 { 01097 plwarn( "ResizeCmd: Illegal call -- window pointer uninitialized" ); 01098 return; 01099 } 01100 01101 // Reset current window bounds 01102 01103 dev->width = pldis->width; 01104 dev->height = pldis->height; 01105 01106 dev->xscale = dev->width / (double) dev->init_width; 01107 dev->yscale = dev->height / (double) dev->init_height; 01108 01109 dev->xscale = dev->xscale * dev->xscale_init; 01110 dev->yscale = dev->yscale * dev->yscale_init; 01111 01112 #if PHYSICAL 01113 { 01114 float pxlx = (double) PIXELS_X / dev->width * DPMM; 01115 float pxly = (double) PIXELS_Y / dev->height * DPMM; 01116 plP_setpxl( pxlx, pxly ); 01117 } 01118 #endif 01119 01120 // Note: the following order MUST be obeyed -- if you instead redraw into 01121 // the window and then copy it to the pixmap, off-screen parts of the window 01122 // may contain garbage which is then transferred to the pixmap (and thus 01123 // will not go away after an expose). 01124 // 01125 01126 // Resize pixmap using new dimensions 01127 01128 if ( dev->write_to_pixmap ) 01129 { 01130 dev->write_to_window = 0; 01131 #if defined ( __WIN32__ ) || defined ( MAC_TCL ) 01132 Tk_FreePixmap( tkwd->display, dev->pixmap ); 01133 #else 01134 // Vince's original driver code used 01135 // Tk_FreePixmap(tkwd->display, dev->pixmap); 01136 //which is defined in tk-8.3 (and 8.2?) source as 01137 //void 01138 // Tk_FreePixmap(display, pixmap) 01139 // Display *display; 01140 // Pixmap pixmap; 01141 // { 01142 // XFreePixmap(display, pixmap); 01143 // Tk_FreeXId(display, (XID) pixmap); 01144 // } 01145 // But that bombed under Linux and tcl/tk8.2 so now just call 01146 // XFreePixmap directly. (Not recommended as permanent solution 01147 // because you eventually run out of resources according to man 01148 // page if you don't call Tk_FreeXId.) Vince is still looking into 01149 // how to resolve this problem. 01150 // 01151 XFreePixmap( tkwd->display, dev->pixmap ); 01152 #endif 01153 CreatePixmap( pls ); 01154 } 01155 01156 // Initialize & redraw (to pixmap, if available). 01157 01158 plD_bop_tkwin( pls ); 01159 plRemakePlot( pls ); 01160 XSync( tkwd->display, 0 ); 01161 01162 // If pixmap available, fake an expose 01163 01164 if ( dev->write_to_pixmap ) 01165 { 01166 dev->write_to_window = write_to_window; 01167 XCopyArea( tkwd->display, dev->pixmap, dev->window, dev->gc, 0, 0, 01168 dev->width, dev->height, 0, 0 ); 01169 XSync( tkwd->display, 0 ); 01170 } 01171 } 01172 01173 //-------------------------------------------------------------------------- 01174 // RedrawCmd() 01175 // 01176 // Handles page redraw without resize (pixmap does not get reallocated). 01177 // Calling this makes sure all necessary housekeeping gets done. 01178 //-------------------------------------------------------------------------- 01179 01180 static void 01181 RedrawCmd( PLStream *pls ) 01182 { 01183 TkwDev *dev = (TkwDev *) pls->dev; 01184 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 01185 int write_to_window = dev->write_to_window; 01186 01187 dbug_enter( "RedrawCmd" ); 01188 01189 // Return if plD_init_tkw hasn't been called yet 01190 01191 if ( dev == NULL ) 01192 { 01193 plwarn( "RedrawCmd: Illegal call -- driver uninitialized" ); 01194 return; 01195 } 01196 01197 // Initialize & redraw (to pixmap, if available). 01198 01199 if ( dev->write_to_pixmap ) 01200 dev->write_to_window = 0; 01201 01202 plD_bop_tkwin( pls ); 01203 plRemakePlot( pls ); 01204 XSync( tkwd->display, 0 ); 01205 01206 dev->write_to_window = write_to_window; 01207 01208 // If pixmap available, fake an expose 01209 01210 if ( dev->write_to_pixmap ) 01211 { 01212 XCopyArea( tkwd->display, dev->pixmap, dev->window, dev->gc, 0, 0, 01213 dev->width, dev->height, 0, 0 ); 01214 XSync( tkwd->display, 0 ); 01215 } 01216 } 01217 01218 //-------------------------------------------------------------------------- 01219 // CreatePixmap() 01220 // 01221 // This routine creates a pixmap, doing error trapping in case there 01222 // isn't enough memory on the server. 01223 //-------------------------------------------------------------------------- 01224 01225 static void 01226 CreatePixmap( PLStream *pls ) 01227 { 01228 TkwDev *dev = (TkwDev *) pls->dev; 01229 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 01230 Tk_Window tkwin = pls->plPlotterPtr->tkwin; 01231 01232 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) 01233 int ( *oldErrorHandler )( Display *, XErrorEvent * ); 01234 oldErrorHandler = XSetErrorHandler( CreatePixmapErrorHandler ); 01235 CreatePixmapStatus = Success; 01236 #endif 01237 01238 #ifdef MAC_TCL 01239 // MAC_TCL's version of XCreatePixmap doesn't like 0 by 0 maps 01240 if ( dev->width == 0 ) 01241 { 01242 dev->width = 10; 01243 } 01244 if ( dev->height == 0 ) 01245 { 01246 dev->height = 10; 01247 } 01248 #endif 01249 pldebug( "CreatePixmap", 01250 "creating pixmap: width = %d, height = %d, depth = %d\n", 01251 dev->width, dev->height, tkwd->depth ); 01252 // 01253 // dev->pixmap = Tk_GetPixmap(tkwd->display, dev->window, 01254 // dev->width, dev->height, tkwd->depth); 01255 // 01256 // 01257 // Vince's original driver code used Tk_Display(tkwin) for first argument, 01258 // but that bombed on an Linux tcl/tk 8.2 machine. Something was wrong 01259 // with that value. Thus, we now use tkwd->display, and that works well. 01260 // Vince is looking into why Tk_Display(tkwin) is badly defined under 8.2. 01261 // old code: 01262 // 01263 // dev->pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), 01264 // Tk_Width(tkwin), Tk_Height(tkwin), 01265 // DefaultDepthOfScreen(Tk_Screen(tkwin))); 01266 // 01267 dev->pixmap = Tk_GetPixmap( tkwd->display, Tk_WindowId( tkwin ), 01268 Tk_Width( tkwin ), Tk_Height( tkwin ), 01269 DefaultDepthOfScreen( Tk_Screen( tkwin ) ) ); 01270 XSync( tkwd->display, 0 ); 01271 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) 01272 if ( CreatePixmapStatus != Success ) 01273 { 01274 dev->write_to_pixmap = 0; 01275 dev->write_to_window = 1; 01276 pls->db = 0; 01277 fprintf( stderr, "\n\ 01278 Warning: pixmap could not be allocated (insufficient memory on server).\n\ 01279 Driver will redraw the entire plot to handle expose events.\n" ); 01280 } 01281 01282 XSetErrorHandler( oldErrorHandler ); 01283 #endif 01284 } 01285 01286 //-------------------------------------------------------------------------- 01287 // GetVisual() 01288 // 01289 // Get visual info. In order to safely use a visual other than that of 01290 // the parent (which hopefully is that returned by DefaultVisual), you 01291 // must first find (using XGetRGBColormaps) or create a colormap matching 01292 // this visual and then set the colormap window attribute in the 01293 // XCreateWindow attributes and valuemask arguments. I don't do this 01294 // right now, so this is turned off by default. 01295 //-------------------------------------------------------------------------- 01296 01297 static void 01298 GetVisual( PLStream *pls ) 01299 { 01300 int depth; 01301 TkwDev *dev = (TkwDev *) pls->dev; 01302 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 01303 01304 dbug_enter( "GetVisual" ); 01305 01306 tkwd->visual = Tk_GetVisual( pls->plPlotterPtr->interp, 01307 pls->plPlotterPtr->tkwin, 01308 "best", 01309 &depth, NULL ); 01310 tkwd->depth = (unsigned int) depth; 01311 } 01312 01313 //-------------------------------------------------------------------------- 01314 // AllocBGFG() 01315 // 01316 // Allocate background & foreground colors. If possible, I choose pixel 01317 // values such that the fg pixel is the xor of the bg pixel, to make 01318 // rubber-banding easy to see. 01319 //-------------------------------------------------------------------------- 01320 01321 static void 01322 AllocBGFG( PLStream *pls ) 01323 { 01324 TkwDev *dev = (TkwDev *) pls->dev; 01325 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 01326 01327 #ifndef USE_TK 01328 int i, j, npixels; 01329 unsigned long plane_masks[1], pixels[MAX_COLORS]; 01330 #endif 01331 01332 dbug_enter( "AllocBGFG" ); 01333 01334 // If not on a color system, just return 01335 01336 if ( !tkwd->color ) 01337 return; 01338 #ifndef USE_TK 01339 // Allocate r/w color cell for background 01340 01341 if ( XAllocColorCells( tkwd->display, tkwd->map, False, 01342 plane_masks, 0, pixels, 1 ) ) 01343 { 01344 tkwd->cmap0[0].pixel = pixels[0]; 01345 } 01346 else 01347 { 01348 plexit( "couldn't allocate background color cell" ); 01349 } 01350 01351 // Allocate as many colors as we can 01352 01353 npixels = MAX_COLORS; 01354 for (;; ) 01355 { 01356 if ( XAllocColorCells( tkwd->display, tkwd->map, False, 01357 plane_masks, 0, pixels, npixels ) ) 01358 break; 01359 npixels--; 01360 if ( npixels == 0 ) 01361 break; 01362 } 01363 01364 // Find the color with pixel = xor of the bg color pixel. 01365 // If a match isn't found, the last pixel allocated is used. 01366 01367 for ( i = 0; i < npixels - 1; i++ ) 01368 { 01369 if ( pixels[i] == ( ~tkwd->cmap0[0].pixel & 0xFF ) ) 01370 break; 01371 } 01372 01373 // Use this color cell for our foreground color. Then free the rest. 01374 01375 tkwd->fgcolor.pixel = pixels[i]; 01376 for ( j = 0; j < npixels; j++ ) 01377 { 01378 if ( j != i ) 01379 XFreeColors( tkwd->display, tkwd->map, &pixels[j], 1, 0 ); 01380 } 01381 #endif 01382 } 01383 01384 //-------------------------------------------------------------------------- 01385 // pltkwin_setBGFG() 01386 // 01387 // Set background & foreground colors. Foreground over background should 01388 // have high contrast. 01389 //-------------------------------------------------------------------------- 01390 01391 void 01392 pltkwin_setBGFG( PLStream *pls ) 01393 { 01394 TkwDev *dev = (TkwDev *) pls->dev; 01395 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 01396 PLColor fgcolor; 01397 int gslevbg, gslevfg; 01398 01399 dbug_enter( "pltkwin_setBGFG" ); 01400 01401 // 01402 // Set background color. 01403 // 01404 // Background defaults to black on color screens, white on grayscale (many 01405 // grayscale monitors have poor contrast, and black-on-white looks better). 01406 // 01407 01408 if ( !tkwd->color ) 01409 { 01410 pls->cmap0[0].r = pls->cmap0[0].g = pls->cmap0[0].b = 0xFF; 01411 } 01412 gslevbg = (int) ( ( (long) pls->cmap0[0].r + 01413 (long) pls->cmap0[0].g + 01414 (long) pls->cmap0[0].b ) / 3 ); 01415 01416 PLColor_to_TkColor( &pls->cmap0[0], &tkwd->cmap0[0] ); 01417 01418 // 01419 // Set foreground color. 01420 // 01421 // Used for grayscale output, since otherwise the plots can become nearly 01422 // unreadable (i.e. if colors get mapped onto grayscale values). In this 01423 // case it becomes the grayscale level for all draws, and is taken to be 01424 // black if the background is light, and white if the background is dark. 01425 // Note that white/black allocations never fail. 01426 // 01427 01428 if ( gslevbg > 0x7F ) 01429 gslevfg = 0; 01430 else 01431 gslevfg = 0xFF; 01432 01433 fgcolor.r = fgcolor.g = fgcolor.b = (unsigned char) gslevfg; 01434 01435 PLColor_to_TkColor( &fgcolor, &tkwd->fgcolor ); 01436 01437 // Now store 01438 #ifndef USE_TK 01439 if ( tkwd->color ) 01440 { 01441 XStoreColor( tkwd->display, tkwd->map, &tkwd->fgcolor ); 01442 XStoreColor( tkwd->display, tkwd->map, &tkwd->cmap0[0] ); 01443 } 01444 else 01445 { 01446 XAllocColor( tkwd->display, tkwd->map, &tkwd->cmap0[0] ); 01447 XAllocColor( tkwd->display, tkwd->map, &tkwd->fgcolor ); 01448 } 01449 #else 01450 Tkw_StoreColor( pls, tkwd, &tkwd->cmap0[0] ); 01451 Tkw_StoreColor( pls, tkwd, &tkwd->fgcolor ); 01452 #endif 01453 } 01454 01455 //-------------------------------------------------------------------------- 01456 // InitColors() 01457 // 01458 // Does all color initialization. 01459 //-------------------------------------------------------------------------- 01460 01461 static void 01462 InitColors( PLStream *pls ) 01463 { 01464 TkwDev *dev = (TkwDev *) pls->dev; 01465 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 01466 01467 dbug_enter( "InitColors" ); 01468 01469 // Allocate and initialize color maps. 01470 // Defer cmap1 allocation until it's actually used 01471 01472 if ( tkwd->color ) 01473 { 01474 if ( plplot_tkwin_ccmap ) 01475 { 01476 AllocCustomMap( pls ); 01477 } 01478 else 01479 { 01480 AllocCmap0( pls ); 01481 } 01482 } 01483 } 01484 01485 //-------------------------------------------------------------------------- 01486 // AllocCustomMap() 01487 // 01488 // Initializes custom color map and all the cruft that goes with it. 01489 // 01490 // Assuming all color X displays do 256 colors, the breakdown is as follows: 01491 // 01492 // XWM_COLORS Number of low "pixel" values to copy. These are typically 01493 // allocated first, thus are in use by the window manager. I 01494 // copy them to reduce flicker. 01495 // 01496 // CMAP0_COLORS Color map 0 entries. I allocate these both in the default 01497 // colormap and the custom colormap to reduce flicker. 01498 // 01499 // CMAP1_COLORS Color map 1 entries. There should be as many as practical 01500 // available for smooth shading. On the order of 50-100 is 01501 // pretty reasonable. You don't really need all 256, 01502 // especially if all you're going to do is to print it to 01503 // postscript (which doesn't have any intrinsic limitation on 01504 // the number of colors). 01505 // 01506 // It's important to leave some extra colors unallocated for Tk. In 01507 // particular the palette tools require a fair amount. I recommend leaving 01508 // at least 40 or so free. 01509 //-------------------------------------------------------------------------- 01510 01511 static void 01512 AllocCustomMap( PLStream *pls ) 01513 { 01514 TkwDev *dev = (TkwDev *) pls->dev; 01515 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 01516 01517 XColor xwm_colors[MAX_COLORS]; 01518 int i; 01519 #ifndef USE_TK 01520 int npixels; 01521 unsigned long plane_masks[1], pixels[MAX_COLORS]; 01522 #endif 01523 01524 dbug_enter( "AllocCustomMap" ); 01525 01526 // Determine current default colors 01527 01528 for ( i = 0; i < MAX_COLORS; i++ ) 01529 { 01530 xwm_colors[i].pixel = (long unsigned) i; 01531 } 01532 #ifndef MAC_TCL 01533 XQueryColors( tkwd->display, tkwd->map, xwm_colors, MAX_COLORS ); 01534 #endif 01535 01536 // Allocate cmap0 colors in the default colormap. 01537 // The custom cmap0 colors are later stored at the same pixel values. 01538 // This is a really cool trick to reduce the flicker when changing colormaps. 01539 // 01540 01541 AllocCmap0( pls ); 01542 XAllocColor( tkwd->display, tkwd->map, &tkwd->fgcolor ); 01543 01544 // Create new color map 01545 01546 tkwd->map = XCreateColormap( tkwd->display, DefaultRootWindow( tkwd->display ), 01547 tkwd->visual, AllocNone ); 01548 01549 // Now allocate all colors so we can fill the ones we want to copy 01550 01551 #ifndef USE_TK 01552 npixels = MAX_COLORS; 01553 for (;; ) 01554 { 01555 if ( XAllocColorCells( tkwd->display, tkwd->map, False, 01556 plane_masks, 0, pixels, npixels ) ) 01557 break; 01558 npixels--; 01559 if ( npixels == 0 ) 01560 plexit( "couldn't allocate any colors" ); 01561 } 01562 01563 // Fill the low colors since those are in use by the window manager 01564 01565 for ( i = 0; i < XWM_COLORS; i++ ) 01566 { 01567 XStoreColor( tkwd->display, tkwd->map, &xwm_colors[i] ); 01568 pixels[xwm_colors[i].pixel] = 0; 01569 } 01570 01571 // Fill the ones we will use in cmap0 01572 01573 for ( i = 0; i < tkwd->ncol0; i++ ) 01574 { 01575 XStoreColor( tkwd->display, tkwd->map, &tkwd->cmap0[i] ); 01576 pixels[tkwd->cmap0[i].pixel] = 0; 01577 } 01578 01579 // Finally, if the colormap was saved by an external agent, see if there are 01580 // any differences from the current default map and save those! A very cool 01581 // (or sick, depending on how you look at it) trick to get over some X and 01582 // Tk limitations. 01583 // 01584 01585 if ( sxwm_colors_set ) 01586 { 01587 for ( i = 0; i < MAX_COLORS; i++ ) 01588 { 01589 if ( ( xwm_colors[i].red != sxwm_colors[i].red ) || 01590 ( xwm_colors[i].green != sxwm_colors[i].green ) || 01591 ( xwm_colors[i].blue != sxwm_colors[i].blue ) ) 01592 { 01593 if ( pixels[i] != 0 ) 01594 { 01595 XStoreColor( tkwd->display, tkwd->map, &xwm_colors[i] ); 01596 pixels[i] = 0; 01597 } 01598 } 01599 } 01600 } 01601 01602 // Now free the ones we're not interested in 01603 01604 for ( i = 0; i < npixels; i++ ) 01605 { 01606 if ( pixels[i] != 0 ) 01607 XFreeColors( tkwd->display, tkwd->map, &pixels[i], 1, 0 ); 01608 } 01609 #endif 01610 // Allocate colors in cmap 1 01611 01612 AllocCmap1( pls ); 01613 } 01614 01615 //-------------------------------------------------------------------------- 01616 // AllocCmap0() 01617 // 01618 // Allocate & initialize cmap0 entries. 01619 //-------------------------------------------------------------------------- 01620 01621 static void 01622 AllocCmap0( PLStream *pls ) 01623 { 01624 TkwDev *dev = (TkwDev *) pls->dev; 01625 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 01626 01627 #ifndef USE_TK 01628 int npixels; 01629 int i; 01630 unsigned long plane_masks[1], pixels[MAX_COLORS]; 01631 #endif 01632 01633 dbug_enter( "AllocCmap0" ); 01634 01635 // Allocate and assign colors in cmap 0 01636 01637 #ifndef USE_TK 01638 npixels = pls->ncol0 - 1; 01639 for (;; ) 01640 { 01641 if ( XAllocColorCells( tkwd->display, tkwd->map, False, 01642 plane_masks, 0, &pixels[1], npixels ) ) 01643 break; 01644 npixels--; 01645 if ( npixels == 0 ) 01646 plexit( "couldn't allocate any colors" ); 01647 } 01648 01649 tkwd->ncol0 = npixels + 1; 01650 for ( i = 1; i < tkwd->ncol0; i++ ) 01651 { 01652 tkwd->cmap0[i].pixel = pixels[i]; 01653 } 01654 #else 01655 // We use the Tk color scheme 01656 tkwd->ncol0 = pls->ncol0; 01657 #endif 01658 StoreCmap0( pls ); 01659 } 01660 01661 //-------------------------------------------------------------------------- 01662 // AllocCmap1() 01663 // 01664 // Allocate & initialize cmap1 entries. If using the default color map, 01665 // must severely limit number of colors otherwise TK won't have enough. 01666 //-------------------------------------------------------------------------- 01667 01668 static void 01669 AllocCmap1( PLStream *pls ) 01670 { 01671 TkwDev *dev = (TkwDev *) pls->dev; 01672 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 01673 01674 int npixels; 01675 #ifndef USE_TK 01676 int i, j; 01677 unsigned long plane_masks[1], pixels[MAX_COLORS]; 01678 #endif 01679 01680 dbug_enter( "AllocCmap1" ); 01681 01682 // Allocate colors in cmap 1 01683 01684 npixels = MAX( 2, MIN( CMAP1_COLORS, pls->ncol1 ) ); 01685 #ifndef USE_TK 01686 for (;; ) 01687 { 01688 if ( XAllocColorCells( tkwd->display, tkwd->map, False, 01689 plane_masks, 0, pixels, npixels ) ) 01690 break; 01691 npixels--; 01692 if ( npixels == 0 ) 01693 break; 01694 } 01695 01696 if ( npixels < 2 ) 01697 { 01698 tkwd->ncol1 = -1; 01699 fprintf( stderr, 01700 "Warning: unable to allocate sufficient colors in cmap1\n" ); 01701 return; 01702 } 01703 else 01704 { 01705 tkwd->ncol1 = npixels; 01706 if ( pls->verbose ) 01707 fprintf( stderr, "AllocCmap1 (xwin.c): Allocated %d colors in cmap1\n", npixels ); 01708 } 01709 01710 // Don't assign pixels sequentially, to avoid strange problems with xor GC's 01711 // Skipping by 2 seems to do the job best 01712 01713 for ( j = i = 0; i < tkwd->ncol1; i++ ) 01714 { 01715 while ( pixels[j] == 0 ) 01716 j++; 01717 01718 tkwd->cmap1[i].pixel = pixels[j]; 01719 pixels[j] = 0; 01720 01721 j += 2; 01722 if ( j >= tkwd->ncol1 ) 01723 j = 0; 01724 } 01725 #else 01726 tkwd->ncol1 = npixels; 01727 #endif 01728 StoreCmap1( pls ); 01729 } 01730 01731 //-------------------------------------------------------------------------- 01732 // StoreCmap0() 01733 // 01734 // Stores cmap 0 entries in X-server colormap. 01735 //-------------------------------------------------------------------------- 01736 01737 static void 01738 StoreCmap0( PLStream *pls ) 01739 { 01740 TkwDev *dev = (TkwDev *) pls->dev; 01741 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 01742 int i; 01743 01744 if ( !tkwd->color ) 01745 return; 01746 01747 for ( i = 1; i < tkwd->ncol0; i++ ) 01748 { 01749 PLColor_to_TkColor( &pls->cmap0[i], &tkwd->cmap0[i] ); 01750 #ifndef USE_TK 01751 XStoreColor( tkwd->display, tkwd->map, &tkwd->cmap0[i] ); 01752 #else 01753 Tkw_StoreColor( pls, tkwd, &tkwd->cmap0[i] ); 01754 #endif 01755 } 01756 } 01757 01758 void CopyColour( XColor* from, XColor* to ) 01759 { 01760 to->pixel = from->pixel; 01761 to->red = from->red; 01762 to->blue = from->blue; 01763 to->green = from->green; 01764 to->flags = from->flags; 01765 } 01766 01767 //-------------------------------------------------------------------------- 01768 // StoreCmap1() 01769 // 01770 // Stores cmap 1 entries in X-server colormap. 01771 //-------------------------------------------------------------------------- 01772 01773 static void 01774 StoreCmap1( PLStream *pls ) 01775 { 01776 TkwDev *dev = (TkwDev *) pls->dev; 01777 TkwDisplay *tkwd = (TkwDisplay *) dev->tkwd; 01778 01779 PLColor cmap1color; 01780 int i; 01781 01782 if ( !tkwd->color ) 01783 return; 01784 01785 for ( i = 0; i < tkwd->ncol1; i++ ) 01786 { 01787 plcol_interp( pls, &cmap1color, i, tkwd->ncol1 ); 01788 PLColor_to_TkColor( &cmap1color, &tkwd->cmap1[i] ); 01789 #ifndef USE_TK 01790 XStoreColor( tkwd->display, tkwd->map, &tkwd->cmap1[i] ); 01791 #else 01792 Tkw_StoreColor( pls, tkwd, &tkwd->cmap1[i] ); 01793 #endif 01794 } 01795 } 01796 01797 void Tkw_StoreColor( PLStream* pls, TkwDisplay* tkwd, XColor* col ) 01798 { 01799 XColor *xc; 01800 #ifndef USE_TK 01801 XStoreColor( tkwd->display, tkwd->map, col ); 01802 #else 01803 (void) tkwd; // tkwd unused in this case 01804 // We're probably losing memory here 01805 xc = Tk_GetColorByValue( pls->plPlotterPtr->tkwin, col ); 01806 CopyColour( xc, col ); 01807 #endif 01808 } 01809 01810 //-------------------------------------------------------------------------- 01811 // void PLColor_to_TkColor() 01812 // 01813 // Copies the supplied PLColor to an XColor, padding with bits as necessary 01814 // (a PLColor uses 8 bits for color storage, while an XColor uses 16 bits). 01815 // The argument types follow the same order as in the function name. 01816 //-------------------------------------------------------------------------- 01817 01818 #define ToXColor( a ) ( ( ( 0xFF & ( a ) ) << 8 ) | ( a ) ) 01819 #define ToPLColor( a ) ( ( (U_LONG) a ) >> 8 ) 01820 01821 void 01822 PLColor_to_TkColor( PLColor *plcolor, XColor *xcolor ) 01823 { 01824 xcolor->red = (short unsigned) ToXColor( plcolor->r ); 01825 xcolor->green = (short unsigned) ToXColor( plcolor->g ); 01826 xcolor->blue = (short unsigned) ToXColor( plcolor->b ); 01827 xcolor->flags = DoRed | DoGreen | DoBlue; 01828 } 01829 01830 //-------------------------------------------------------------------------- 01831 // void PLColor_from_TkColor() 01832 // 01833 // Copies the supplied XColor to a PLColor, stripping off bits as 01834 // necessary. See the previous routine for more info. 01835 //-------------------------------------------------------------------------- 01836 01837 void 01838 PLColor_from_TkColor( PLColor *plcolor, XColor *xcolor ) 01839 { 01840 plcolor->r = (unsigned char) ToPLColor( xcolor->red ); 01841 plcolor->g = (unsigned char) ToPLColor( xcolor->green ); 01842 plcolor->b = (unsigned char) ToPLColor( xcolor->blue ); 01843 } 01844 01845 //-------------------------------------------------------------------------- 01846 // void PLColor_from_TkColor_Changed() 01847 // 01848 // Copies the supplied XColor to a PLColor, stripping off bits as 01849 // necessary. See the previous routine for more info. 01850 // 01851 // Returns 1 if the color was different from the old one. 01852 //-------------------------------------------------------------------------- 01853 01854 int 01855 PLColor_from_TkColor_Changed( PLColor *plcolor, XColor *xcolor ) 01856 { 01857 int changed = 0; 01858 int color; 01859 color = ToPLColor( xcolor->red ); 01860 01861 if ( plcolor->r != color ) 01862 { 01863 changed = 1; 01864 plcolor->r = (unsigned char) color; 01865 } 01866 color = ToPLColor( xcolor->green ); 01867 if ( plcolor->g != color ) 01868 { 01869 changed = 1; 01870 plcolor->g = (unsigned char) color; 01871 } 01872 color = ToPLColor( xcolor->blue ); 01873 if ( plcolor->b != color ) 01874 { 01875 changed = 1; 01876 plcolor->b = (unsigned char) color; 01877 } 01878 return changed; 01879 } 01880 01881 //-------------------------------------------------------------------------- 01882 // int pltk_AreWeGrayscale(PlPlotter *plf) 01883 // 01884 // Determines if we're using a monochrome or grayscale device. 01885 // gmf 11-8-91; Courtesy of Paul Martz of Evans and Sutherland. 01886 // Changed July 1996 by Vince: now uses Tk to check the enclosing PlPlotter 01887 //-------------------------------------------------------------------------- 01888 01889 static int 01890 pltk_AreWeGrayscale( PlPlotter *plf ) 01891 { 01892 #if defined ( __cplusplus ) || defined ( c_plusplus ) 01893 #define THING c_class 01894 #else 01895 #define THING class 01896 #endif 01897 01898 Visual* visual; 01899 // get the window's Visual 01900 visual = Tk_Visual( plf->tkwin ); 01901 if ( ( visual->THING != GrayScale ) && ( visual->THING != StaticGray ) ) 01902 return ( 0 ); 01903 // if we got this far, only StaticGray and GrayScale classes available 01904 return ( 1 ); 01905 } 01906 01907 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) 01908 //-------------------------------------------------------------------------- 01909 // CreatePixmapErrorHandler() 01910 // 01911 // Error handler used in CreatePixmap() to catch errors in allocating 01912 // storage for pixmap. This way we can nicely substitute redraws for 01913 // pixmap copies if the server has insufficient memory. 01914 //-------------------------------------------------------------------------- 01915 01916 static int 01917 CreatePixmapErrorHandler( Display *display, XErrorEvent *error ) 01918 { 01919 if ( error->error_code == BadAlloc ) 01920 { 01921 CreatePixmapStatus = error->error_code; 01922 } 01923 else 01924 { 01925 char buffer[256]; 01926 XGetErrorText( display, error->error_code, buffer, 256 ); 01927 fprintf( stderr, "Error in XCreatePixmap: %s.\n", buffer ); 01928 } 01929 return 1; 01930 } 01931 #endif 01932 01933 #else 01934 int 01935 pldummy_tkwin() 01936 { 01937 return 0; 01938 } 01939 01940 #endif // PLD_tkwin 01941 01942 void * ckcalloc( size_t nmemb, size_t size ) 01943 { 01944 long *ptr; 01945 long *p; 01946 size *= nmemb; 01947 ptr = (long *) malloc( size ); 01948 if ( !ptr ) 01949 return ( 0 ); 01950 01951 #if !__POWERPC__ 01952 01953 for ( size = ( size / sizeof ( long ) ) + 1, p = ptr; --size; ) 01954 *p++ = 0; 01955 01956 #else 01957 01958 for ( size = ( size / sizeof ( long ) ) + 1, p = ptr - 1; --size; ) 01959 *++p = 0; 01960 01961 #endif 01962 01963 return ( ptr ); 01964 }