• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

tkwin.c

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

Generated on Wed Oct 12 2011 20:42:23 for PLplot by  doxygen 1.7.1