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

xwin.c

Go to the documentation of this file.
00001 // $Id: xwin.c 11749 2011-05-12 20:39:42Z airwin $
00002 //
00003 //      PLplot X-windows device driver.
00004 //
00005 // Copyright (C) 2004  Maurice LeBrun
00006 // Copyright (C) 2004  Joao Cardoso
00007 // Copyright (C) 2004  Rafael Laboissiere
00008 // Copyright (C) 2004  Andrew Ross
00009 //
00010 // This file is part of PLplot.
00011 //
00012 // PLplot is free software; you can redistribute it and/or modify
00013 // it under the terms of the GNU Library General Public License as published
00014 // by the Free Software Foundation; either version 2 of the License, or
00015 // (at your option) any later version.
00016 //
00017 // PLplot is distributed in the hope that it will be useful,
00018 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 // GNU Library General Public License for more details.
00021 //
00022 // You should have received a copy of the GNU Library General Public License
00023 // along with PLplot; if not, write to the Free Software
00024 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00025 //
00026 //
00027 #include "plDevs.h"
00028 
00029 #define DEBUG
00030 
00031 #ifdef PLD_xwin
00032 #define NEED_PLDEBUG
00033 #include "plplotP.h"
00034 #include "plxwd.h"
00035 #include "drivers.h"
00036 #include "plevent.h"
00037 
00038 #ifdef PL_HAVE_PTHREAD
00039 #include <pthread.h>
00040 #include <signal.h>
00041 int    pthread_mutexattr_settype( pthread_mutexattr_t *attr, int kind );
00042 static void events_thread( void *pls );
00043 static pthread_mutex_t events_mutex;
00044 static int             already = 0;
00045 #endif
00046 
00047 // Device info
00048 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_xwin = "xwin:X-Window (Xlib):1:xwin:5:xw\n";
00049 
00050 static int synchronize = 0;                   // change to 1 for X synchronized operation
00051                                               // Use "-drvopt sync" cmd line option to set.
00052 
00053 static int nobuffered = 0;                    // make it a buffered device by default
00054                                               // use "-drvopt unbuffered" to make it unbuffered
00055 
00056 static int noinitcolors = 0;                  // Call InitColors by default
00057                                               // use "-drvopt noinitcolors" to leave colors uninitialized
00058 
00059 static int defaultvisual = 1;                 // use "-drvopt defvis=0" to not use the default visual
00060 
00061 static int usepthreads = 1;                   // use "-drvopt usepth=0" to not use pthreads to redisplay
00062 
00063 //
00064 // When -drvopt defvis is defined, DefaultVisual() is used to get the visual.
00065 // Otherwise, the visual is obtained using XGetVisualInfo() to make a match.
00066 //
00067 
00068 //#define HACK_STATICCOLOR
00069 
00070 // Number of instructions to skip between querying the X server for events
00071 
00072 #define MAX_INSTR    20
00073 
00074 // The xwin driver uses the xscale and yscale values to convert from virtual
00075 // to real pixels using the current size in pixels of the display window.
00076 // We define PHYSICAL here so that PLplot core knows about this rescaling
00077 // and mm values are converted to virtual pixels at a ratio consistent with
00078 // a constant ratio of DPMM real pixels per mm.
00079 #define PHYSICAL    1
00080 
00081 // These need to be distinguished since the handling is slightly different.
00082 
00083 #define LOCATE_INVOKED_VIA_API       1
00084 #define LOCATE_INVOKED_VIA_DRIVER    2
00085 
00086 // Set constants for dealing with colormap.  In brief:
00087 //
00088 //      --- custom colormaps ---
00089 // ccmap                When set, turns on custom color map
00090 // CCMAP_XWM_COLORS     Number of low "pixel" values to copy.
00091 //
00092 //      --- r/w colormaps --
00093 // RWMAP_CMAP1_COLORS   Color map 1 entries.
00094 // RWMAP_MAX_COLORS     Maximum colors in RW colormaps
00095 //
00096 //      --- r/o colormaps --
00097 // ROMAP_CMAP1_COLORS   Color map 1 entries.
00098 // TC_CMAP1_COLORS      TrueColor visual Color map 1 entries.
00099 //
00100 // See Init_CustomCmap() and  Init_DefaultCmap() for more info.
00101 // Set ccmap at your own risk -- still under development.
00102 //
00103 
00104 // plplot_ccmap is statically defined in plxwd.h.  Note that
00105 // plframe.c also includes that header and uses the variable.
00106 
00107 #define CCMAP_XWM_COLORS      70
00108 
00109 #define RWMAP_CMAP1_COLORS    50
00110 #define RWMAP_MAX_COLORS      256
00111 
00112 #define ROMAP_CMAP1_COLORS    50
00113 #define TC_CMAP1_COLORS       200
00114 
00115 // Variables to hold RGB components of given colormap.
00116 // Used in an ugly hack to get past some X11R5 and TK limitations.
00117 
00118 static int    sxwm_colors_set;
00119 static XColor sxwm_colors[RWMAP_MAX_COLORS];
00120 
00121 // Keep pointers to all the displays in use
00122 
00123 static XwDisplay *xwDisplay[PLXDISPLAYS];
00124 
00125 // Function prototypes
00126 
00127 // Driver entry and dispatch setup
00128 
00129 void plD_dispatch_init_xw( PLDispatchTable *pdt );
00130 
00131 void plD_init_xw( PLStream * );
00132 void plD_line_xw( PLStream *, short, short, short, short );
00133 void plD_polyline_xw( PLStream *, short *, short *, PLINT );
00134 void plD_eop_xw( PLStream * );
00135 void plD_bop_xw( PLStream * );
00136 void plD_tidy_xw( PLStream * );
00137 void plD_state_xw( PLStream *, PLINT );
00138 void plD_esc_xw( PLStream *, PLINT, void * );
00139 
00140 // Initialization
00141 
00142 static void  OpenXwin( PLStream *pls );
00143 static void  Init( PLStream *pls );
00144 static void  InitMain( PLStream *pls );
00145 static void  InitColors( PLStream *pls );
00146 static void  AllocCustomMap( PLStream *pls );
00147 static void  AllocCmap0( PLStream *pls );
00148 static void  AllocCmap1( PLStream *pls );
00149 static void  MapMain( PLStream *pls );
00150 static void  CreatePixmap( PLStream *pls );
00151 static void  GetVisual( PLStream *pls );
00152 static void  AllocBGFG( PLStream *pls );
00153 static int   AreWeGrayscale( Display *display );
00154 
00155 // Routines to poll the X-server
00156 
00157 static void  WaitForPage( PLStream *pls );
00158 static void  CheckForEvents( PLStream *pls );
00159 static void  HandleEvents( PLStream *pls );
00160 
00161 // Event handlers
00162 
00163 static void  MasterEH( PLStream *pls, XEvent *event );
00164 static void  ClientEH( PLStream *pls, XEvent *event );
00165 static void  ExposeEH( PLStream *pls, XEvent *event );
00166 static void  ResizeEH( PLStream *pls, XEvent *event );
00167 static void  MotionEH( PLStream *pls, XEvent *event );
00168 static void  EnterEH( PLStream *pls, XEvent *event );
00169 static void  LeaveEH( PLStream *pls, XEvent *event );
00170 static void  KeyEH( PLStream *pls, XEvent *event );
00171 static void  ButtonEH( PLStream *pls, XEvent *event );
00172 static void  LookupXKeyEvent( PLStream *pls, XEvent *event );
00173 static void  LookupXButtonEvent( PLStream *pls, XEvent *event );
00174 
00175 static void  ProcessKey( PLStream *pls );
00176 static void  LocateKey( PLStream *pls );
00177 static void  ProcessButton( PLStream *pls );
00178 static void  LocateButton( PLStream *pls );
00179 static void  Locate( PLStream *pls );
00180 
00181 // Routines for manipulating graphic crosshairs
00182 
00183 static void  CreateXhairs( PLStream *pls );
00184 static void  DestroyXhairs( PLStream *pls );
00185 static void  DrawXhairs( PLStream *pls, int x0, int y0 );
00186 static void  UpdateXhairs( PLStream *pls );
00187 
00188 // Escape function commands
00189 
00190 static void  ExposeCmd( PLStream *pls, PLDisplay *ptr );
00191 static void  RedrawCmd( PLStream *pls );
00192 static void  ResizeCmd( PLStream *pls, PLDisplay *ptr );
00193 static void  ConfigBufferingCmd( PLStream *pls, PLBufferingCB *ptr );
00194 static void  GetCursorCmd( PLStream *pls, PLGraphicsIn *ptr );
00195 static void  FillPolygonCmd( PLStream *pls );
00196 static void  XorMod( PLStream *pls, PLINT *mod );
00197 static void  DrawImage( PLStream *pls );
00198 
00199 // Miscellaneous
00200 
00201 static void  StoreCmap0( PLStream *pls );
00202 static void  StoreCmap1( PLStream *pls );
00203 static void  imageops( PLStream *pls, PLINT *ptr );
00204 static void  SetBGFG( PLStream *pls );
00205 #ifdef DUMMY
00206 static void  SaveColormap( Display *display, Colormap colormap );
00207 #endif
00208 static void  PLColor_to_XColor( PLColor *plcolor, XColor *xcolor );
00209 static void  PLColor_from_XColor( PLColor *plcolor, XColor *xcolor );
00210 
00211 static DrvOpt xwin_options[] = { { "sync",         DRV_INT, &synchronize,   "Synchronized X server operation (0|1)" },
00212                                  { "nobuffered",   DRV_INT, &nobuffered,    "Sets unbuffered operation (0|1)"       },
00213                                  { "noinitcolors", DRV_INT, &noinitcolors,  "Sets cmap0 allocation (0|1)"           },
00214                                  { "defvis",       DRV_INT, &defaultvisual, "Use the Default Visual (0|1)"          },
00215                                  { "usepth",       DRV_INT, &usepthreads,   "Use pthreads (0|1)"                    },
00216                                  { NULL,           DRV_INT, NULL,           NULL                                    } };
00217 
00218 void plD_dispatch_init_xw( PLDispatchTable *pdt )
00219 {
00220 #ifndef ENABLE_DYNDRIVERS
00221     pdt->pl_MenuStr = "X-Window (Xlib)";
00222     pdt->pl_DevName = "xwin";
00223 #endif
00224     pdt->pl_type     = plDevType_Interactive;
00225     pdt->pl_seq      = 5;
00226     pdt->pl_init     = (plD_init_fp) plD_init_xw;
00227     pdt->pl_line     = (plD_line_fp) plD_line_xw;
00228     pdt->pl_polyline = (plD_polyline_fp) plD_polyline_xw;
00229     pdt->pl_eop      = (plD_eop_fp) plD_eop_xw;
00230     pdt->pl_bop      = (plD_bop_fp) plD_bop_xw;
00231     pdt->pl_tidy     = (plD_tidy_fp) plD_tidy_xw;
00232     pdt->pl_state    = (plD_state_fp) plD_state_xw;
00233     pdt->pl_esc      = (plD_esc_fp) plD_esc_xw;
00234 }
00235 
00236 //--------------------------------------------------------------------------
00237 // plD_init_xw()
00238 //
00239 // Initialize device.
00240 // X-dependent stuff done in OpenXwin() and Init().
00241 //--------------------------------------------------------------------------
00242 
00243 void
00244 plD_init_xw( PLStream *pls )
00245 {
00246     XwDev *dev;
00247     PLFLT 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_xw" );
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     pls->dev_fastimg = 1;       // is a fast image device
00260     pls->dev_xor     = 1;       // device support xor mode
00261 
00262 #ifndef PL_HAVE_PTHREAD
00263     usepthreads = 0;
00264 #endif
00265 
00266     plParseDrvOpts( xwin_options );
00267 
00268 #ifndef PL_HAVE_PTHREAD
00269     if ( usepthreads )
00270         plwarn( "You said you want pthreads, but they are not available." );
00271 #endif
00272 
00273     if ( nobuffered )
00274         pls->plbuf_write = 0;   // deactivate plot buffer
00275 
00276 // The real meat of the initialization done here
00277 
00278     if ( pls->dev == NULL )
00279         OpenXwin( pls );
00280 
00281     dev = (XwDev *) pls->dev;
00282 
00283     Init( pls );
00284 
00285 // Get ready for plotting
00286 
00287     dev->xlen = xmax - xmin;
00288     dev->ylen = ymax - ymin;
00289 
00290     dev->xscale_init = dev->init_width / (double) dev->xlen;
00291     dev->yscale_init = dev->init_height / (double) dev->ylen;
00292 
00293     dev->xscale = dev->xscale_init;
00294     dev->yscale = dev->yscale_init;
00295 
00296 #if PHYSICAL
00297     pxlx = DPMM / dev->xscale;
00298     pxly = DPMM / dev->yscale;
00299 #else
00300     pxlx = (double) PIXELS_X / LPAGE_X;
00301     pxly = (double) PIXELS_Y / LPAGE_Y;
00302 #endif
00303 
00304     plP_setpxl( pxlx, pxly );
00305     plP_setphy( xmin, xmax, ymin, ymax );
00306 
00307 #ifdef PL_HAVE_PTHREAD
00308     if ( usepthreads )
00309     {
00310         pthread_mutexattr_t mutexatt;
00311         pthread_attr_t      pthattr;
00312 
00313         if ( !already )
00314         {
00315             pthread_mutexattr_init( &mutexatt );
00316             if ( pthread_mutexattr_settype( &mutexatt, PLPLOT_MUTEX_RECURSIVE ) )
00317                 plexit( "xwin: pthread_mutexattr_settype() failed!\n" );
00318 
00319             pthread_mutex_init( &events_mutex, &mutexatt );
00320             already = 1;
00321         }
00322         else
00323         {
00324             pthread_mutex_lock( &events_mutex );
00325             already++;
00326             pthread_mutex_unlock( &events_mutex );
00327         }
00328 
00329         pthread_attr_init( &pthattr );
00330         pthread_attr_setdetachstate( &pthattr, PTHREAD_CREATE_JOINABLE );
00331 
00332         if ( pthread_create( &( dev->updater ), &pthattr, (void *) &events_thread, (void *) pls ) )
00333         {
00334             pthread_mutex_lock( &events_mutex );
00335             already--;
00336             pthread_mutex_unlock( &events_mutex );
00337 
00338             if ( already == 0 )
00339             {
00340                 pthread_mutex_destroy( &events_mutex );
00341                 plexit( "xwin: pthread_create() failed!\n" );
00342             }
00343             else
00344                 plwarn( "xwin: couldn't create thread for this plot window!\n" );
00345         }
00346     }
00347 #endif
00348 }
00349 
00350 //--------------------------------------------------------------------------
00351 // plD_line_xw()
00352 //
00353 // Draw a line in the current color from (x1,y1) to (x2,y2).
00354 //--------------------------------------------------------------------------
00355 
00356 void
00357 plD_line_xw( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
00358 {
00359     XwDev     *dev = (XwDev *) pls->dev;
00360     XwDisplay *xwd = (XwDisplay *) dev->xwd;
00361 
00362     int       x1 = x1a, y1 = y1a, x2 = x2a, y2 = y2a;
00363 
00364     dbug_enter( "plD_line_xw" );
00365 
00366 #ifdef PL_HAVE_PTHREAD
00367     if ( usepthreads )
00368         pthread_mutex_lock( &events_mutex );
00369 #endif
00370 
00371     CheckForEvents( pls );
00372 
00373     y1 = dev->ylen - y1;
00374     y2 = dev->ylen - y2;
00375 
00376     x1 = x1 * dev->xscale;
00377     x2 = x2 * dev->xscale;
00378     y1 = y1 * dev->yscale;
00379     y2 = y2 * dev->yscale;
00380 
00381     if ( dev->write_to_window )
00382         XDrawLine( xwd->display, dev->window, dev->gc, x1, y1, x2, y2 );
00383 
00384     if ( dev->write_to_pixmap )
00385         XDrawLine( xwd->display, dev->pixmap, dev->gc, x1, y1, x2, y2 );
00386 
00387 #ifdef PL_HAVE_PTHREAD
00388     if ( usepthreads )
00389         pthread_mutex_unlock( &events_mutex );
00390 #endif
00391 }
00392 
00393 //--------------------------------------------------------------------------
00394 // XorMod()
00395 //
00396 // Enter xor mode ( mod != 0) or leave it ( mode = 0)
00397 //--------------------------------------------------------------------------
00398 
00399 static void
00400 XorMod( PLStream *pls, PLINT *mod )
00401 {
00402     XwDev     *dev = (XwDev *) pls->dev;
00403     XwDisplay *xwd = (XwDisplay *) dev->xwd;
00404 
00405     if ( *mod == 0 )
00406         XSetFunction( xwd->display, dev->gc, GXcopy );
00407     else
00408         XSetFunction( xwd->display, dev->gc, GXxor );
00409 }
00410 
00411 //--------------------------------------------------------------------------
00412 // plD_polyline_xw()
00413 //
00414 // Draw a polyline in the current color from (x1,y1) to (x2,y2).
00415 //--------------------------------------------------------------------------
00416 
00417 void
00418 plD_polyline_xw( PLStream *pls, short *xa, short *ya, PLINT npts )
00419 {
00420     XwDev     *dev = (XwDev *) pls->dev;
00421     XwDisplay *xwd = (XwDisplay *) dev->xwd;
00422 
00423     PLINT     i;
00424     XPoint    _pts[PL_MAXPOLY];
00425     XPoint    *pts;
00426 
00427     if ( npts > PL_MAXPOLY )
00428     {
00429         pts = (XPoint *) malloc( sizeof ( XPoint ) * npts );
00430     }
00431     else
00432     {
00433         pts = _pts;
00434     }
00435 
00436     dbug_enter( "plD_polyline_xw" );
00437 
00438 #ifdef PL_HAVE_PTHREAD
00439     if ( usepthreads )
00440         pthread_mutex_lock( &events_mutex );
00441 #endif
00442 
00443     CheckForEvents( pls );
00444 
00445     for ( i = 0; i < npts; i++ )
00446     {
00447         pts[i].x = dev->xscale * xa[i];
00448         pts[i].y = dev->yscale * ( dev->ylen - ya[i] );
00449     }
00450 
00451     if ( dev->write_to_window )
00452         XDrawLines( xwd->display, dev->window, dev->gc, pts, npts,
00453             CoordModeOrigin );
00454 
00455     if ( dev->write_to_pixmap )
00456         XDrawLines( xwd->display, dev->pixmap, dev->gc, pts, npts,
00457             CoordModeOrigin );
00458 
00459 #ifdef PL_HAVE_PTHREAD
00460     if ( usepthreads )
00461         pthread_mutex_unlock( &events_mutex );
00462 #endif
00463 
00464     if ( npts > PL_MAXPOLY )
00465     {
00466         free( pts );
00467     }
00468 }
00469 
00470 //--------------------------------------------------------------------------
00471 // plD_eop_xw()
00472 //
00473 // End of page.  User must hit return (or third mouse button) to continue.
00474 //--------------------------------------------------------------------------
00475 
00476 void
00477 plD_eop_xw( PLStream *pls )
00478 {
00479     XwDev     *dev = (XwDev *) pls->dev;
00480     XwDisplay *xwd = (XwDisplay *) dev->xwd;
00481 
00482     dbug_enter( "plD_eop_xw" );
00483 
00484 #ifdef PL_HAVE_PTHREAD
00485     if ( usepthreads )
00486         pthread_mutex_lock( &events_mutex );
00487 #endif
00488 
00489     XFlush( xwd->display );
00490     if ( pls->db )
00491         ExposeCmd( pls, NULL );
00492 
00493     if ( dev->is_main && !pls->nopause )
00494         WaitForPage( pls );
00495 
00496 #ifdef PL_HAVE_PTHREAD
00497     if ( usepthreads )
00498         pthread_mutex_unlock( &events_mutex );
00499 #endif
00500 }
00501 
00502 //--------------------------------------------------------------------------
00503 // plD_bop_xw()
00504 //
00505 // Set up for the next page.
00506 //--------------------------------------------------------------------------
00507 
00508 void
00509 plD_bop_xw( PLStream *pls )
00510 {
00511     XwDev     *dev = (XwDev *) pls->dev;
00512     XwDisplay *xwd = (XwDisplay *) dev->xwd;
00513 
00514     dbug_enter( "plD_bop_xw" );
00515 
00516 #ifdef PL_HAVE_PTHREAD
00517     if ( usepthreads )
00518         pthread_mutex_lock( &events_mutex );
00519 #endif
00520 
00521     dev->bgcolor = xwd->cmap0[0];
00522 
00523     if ( dev->write_to_window )
00524     {
00525         XSetWindowBackground( xwd->display, dev->window, dev->bgcolor.pixel );
00526         XSetBackground( xwd->display, dev->gc, dev->bgcolor.pixel );
00527         XClearWindow( xwd->display, dev->window );
00528     }
00529     if ( dev->write_to_pixmap )
00530     {
00531         XSetForeground( xwd->display, dev->gc, dev->bgcolor.pixel );
00532         XFillRectangle( xwd->display, dev->pixmap, dev->gc, 0, 0,
00533             dev->width, dev->height );
00534         XSetForeground( xwd->display, dev->gc, dev->curcolor.pixel );
00535     }
00536     XSync( xwd->display, 0 );
00537     pls->page++;
00538 
00539 #ifdef PL_HAVE_PTHREAD
00540     if ( usepthreads )
00541         pthread_mutex_unlock( &events_mutex );
00542 #endif
00543 }
00544 
00545 //--------------------------------------------------------------------------
00546 // plD_tidy_xw()
00547 //
00548 // Close graphics file
00549 //--------------------------------------------------------------------------
00550 
00551 void
00552 plD_tidy_xw( PLStream *pls )
00553 {
00554     XwDev     *dev = (XwDev *) pls->dev;
00555     XwDisplay *xwd = (XwDisplay *) dev->xwd;
00556 
00557     dbug_enter( "plD_tidy_xw" );
00558 
00559 #ifdef PL_HAVE_PTHREAD
00560     if ( usepthreads )
00561     {
00562         pthread_mutex_lock( &events_mutex );
00563         if ( pthread_cancel( dev->updater ) == 0 )
00564             pthread_join( dev->updater, NULL );
00565 
00566         pthread_mutex_unlock( &events_mutex );
00567         if ( --already == 0 )
00568             pthread_mutex_destroy( &events_mutex );
00569     }
00570 #endif
00571 
00572     if ( dev->is_main )
00573     {
00574         XDestroyWindow( xwd->display, dev->window );
00575         if ( dev->write_to_pixmap )
00576             XFreePixmap( xwd->display, dev->pixmap );
00577         XFlush( xwd->display );
00578     }
00579 
00580     xwd->nstreams--;
00581     if ( xwd->nstreams == 0 )
00582     {
00583         int ixwd = xwd->ixwd;
00584         XFreeGC( xwd->display, dev->gc );
00585         XFreeGC( xwd->display, xwd->gcXor );
00586         XCloseDisplay( xwd->display );
00587         free_mem( xwd->cmap0 );
00588         free_mem( xwd->cmap1 );
00589         free_mem( xwDisplay[ixwd] );
00590     }
00591     // ANR: if we set this here the tmp file will not be closed
00592     // See also comment in tkwin.c
00593     //pls->plbuf_write = 0;
00594 }
00595 
00596 //--------------------------------------------------------------------------
00597 // plD_state_xw()
00598 //
00599 // Handle change in PLStream state (color, pen width, fill attribute, etc).
00600 //--------------------------------------------------------------------------
00601 
00602 void
00603 plD_state_xw( PLStream *pls, PLINT op )
00604 {
00605     XwDev     *dev = (XwDev *) pls->dev;
00606     XwDisplay *xwd = (XwDisplay *) dev->xwd;
00607 
00608     dbug_enter( "plD_state_xw" );
00609 
00610 #ifdef PL_HAVE_PTHREAD
00611     if ( usepthreads )
00612         pthread_mutex_lock( &events_mutex );
00613 #endif
00614 
00615     CheckForEvents( pls );
00616 
00617     switch ( op )
00618     {
00619     case PLSTATE_WIDTH:
00620         XSetLineAttributes( xwd->display, dev->gc, pls->width,
00621             LineSolid, CapRound, JoinMiter );
00622         break;
00623 
00624     case PLSTATE_COLOR0: {
00625         int icol0 = pls->icol0;
00626         if ( xwd->color )
00627         {
00628             if ( icol0 == PL_RGB_COLOR )
00629             {
00630                 PLColor_to_XColor( &pls->curcolor, &dev->curcolor );
00631                 if ( !XAllocColor( xwd->display, xwd->map, &dev->curcolor ) )
00632                 {
00633                     fprintf( stderr, "Warning: could not allocate color\n" );
00634                     dev->curcolor.pixel = xwd->fgcolor.pixel;
00635                 }
00636             }
00637             else
00638             {
00639                 dev->curcolor = xwd->cmap0[icol0];
00640             }
00641             XSetForeground( xwd->display, dev->gc, dev->curcolor.pixel );
00642         }
00643         else
00644         {
00645             dev->curcolor = xwd->fgcolor;
00646             XSetForeground( xwd->display, dev->gc, dev->curcolor.pixel );
00647         }
00648         break;
00649     }
00650 
00651     case PLSTATE_COLOR1: {
00652         int icol1;
00653 
00654         if ( xwd->ncol1 == 0 )
00655             AllocCmap1( pls );
00656 
00657         if ( xwd->ncol1 < 2 )
00658             break;
00659 
00660         icol1 = ( pls->icol1 * ( xwd->ncol1 - 1 ) ) / ( pls->ncol1 - 1 );
00661         if ( xwd->color )
00662             dev->curcolor = xwd->cmap1[icol1];
00663         else
00664             dev->curcolor = xwd->fgcolor;
00665 
00666         XSetForeground( xwd->display, dev->gc, dev->curcolor.pixel );
00667         break;
00668     }
00669 
00670     case PLSTATE_CMAP0:
00671         SetBGFG( pls );
00672         // If ncol0 has changed, need to reallocate
00673         if ( pls->ncol0 != xwd->ncol0 )
00674             AllocCmap0( pls );
00675         StoreCmap0( pls );
00676         break;
00677 
00678     case PLSTATE_CMAP1:
00679         StoreCmap1( pls );
00680         break;
00681     }
00682 
00683 #ifdef PL_HAVE_PTHREAD
00684     if ( usepthreads )
00685         pthread_mutex_unlock( &events_mutex );
00686 #endif
00687 }
00688 
00689 //--------------------------------------------------------------------------
00690 // plD_esc_xw()
00691 //
00692 // Escape function.
00693 //
00694 // Functions:
00695 //
00696 //    PLESC_EH  Handle pending events
00697 //    PLESC_EXPOSE      Force an expose
00698 //    PLESC_FILL        Fill polygon
00699 //    PLESC_FLUSH       Flush X event buffer
00700 //    PLESC_GETC        Get coordinates upon mouse click
00701 //    PLESC_REDRAW      Force a redraw
00702 //    PLESC_RESIZE      Force a resize
00703 //    PLESC_XORMOD      set/reset xor mode
00704 //    PLESC_IMAGE     draw the image in a fast way
00705 //    PLESC_IMAGEOPS: image related operations:
00706 //         ZEROW2D      disable writing to display
00707 //         ZEROW2B      disable writing to buffer
00708 //         ONEW2D       enable  writing to display
00709 //         ONEW2B       enable  writing to buffer
00710 //    PLESC_PL2DEVCOL   convert PLColor to device color (XColor)
00711 //    PLESC_DEV2PLCOL   convert device color (XColor) to PLColor
00712 //    PLESC_SETBGFG     set BG, FG colors
00713 //    PLESC_DEVINIT     alternate device initialization
00714 //
00715 // Note the [GET|SET]DEVCOL functions go through the intermediary stream
00716 // variable tmpcolor to keep the syntax simple.
00717 //--------------------------------------------------------------------------
00718 
00719 void
00720 plD_esc_xw( PLStream *pls, PLINT op, void *ptr )
00721 {
00722     dbug_enter( "plD_esc_xw" );
00723 
00724 #ifdef PL_HAVE_PTHREAD
00725     if ( usepthreads )
00726         pthread_mutex_lock( &events_mutex );
00727 #endif
00728 
00729     switch ( op )
00730     {
00731     case PLESC_EH:
00732         HandleEvents( pls );
00733         break;
00734 
00735     case PLESC_EXPOSE:
00736         ExposeCmd( pls, (PLDisplay *) ptr );
00737         break;
00738 
00739     case PLESC_FILL:
00740         FillPolygonCmd( pls );
00741         break;
00742 
00743     case PLESC_FLUSH: {
00744         XwDev     *dev = (XwDev *) pls->dev;
00745         XwDisplay *xwd = (XwDisplay *) dev->xwd;
00746         HandleEvents( pls );
00747         XFlush( xwd->display );
00748         break;
00749     }
00750     case PLESC_GETC:
00751         GetCursorCmd( pls, (PLGraphicsIn *) ptr );
00752         break;
00753 
00754     case PLESC_REDRAW:
00755         RedrawCmd( pls );
00756         break;
00757 
00758     case PLESC_RESIZE:
00759         ResizeCmd( pls, (PLDisplay *) ptr );
00760         break;
00761 
00762     case PLESC_XORMOD:
00763         XorMod( pls, (PLINT *) ptr );
00764         break;
00765 
00766     case PLESC_DOUBLEBUFFERING:
00767         ConfigBufferingCmd( pls, (PLBufferingCB *) ptr );
00768         break;
00769 
00770     case PLESC_IMAGE:
00771         DrawImage( pls );
00772         break;
00773 
00774     case PLESC_IMAGEOPS:
00775         imageops( pls, (PLINT *) ptr );
00776         break;
00777 
00778     case PLESC_PL2DEVCOL:
00779         PLColor_to_XColor( &pls->tmpcolor, (XColor *) ptr );
00780         break;
00781 
00782     case PLESC_DEV2PLCOL:
00783         PLColor_from_XColor( &pls->tmpcolor, (XColor *) ptr );
00784         break;
00785 
00786     case PLESC_SETBGFG:
00787         SetBGFG( pls );
00788         break;
00789 
00790     case PLESC_DEVINIT:
00791         OpenXwin( pls );
00792         break;
00793     }
00794 
00795 #ifdef PL_HAVE_PTHREAD
00796     if ( usepthreads )
00797         pthread_mutex_unlock( &events_mutex );
00798 #endif
00799 }
00800 
00801 //--------------------------------------------------------------------------
00802 // GetCursorCmd()
00803 //
00804 // Waits for a graphics input event and returns coordinates.
00805 //--------------------------------------------------------------------------
00806 
00807 static void
00808 GetCursorCmd( PLStream *pls, PLGraphicsIn *ptr )
00809 {
00810     XwDev        *dev = (XwDev *) pls->dev;
00811     XwDisplay    *xwd = (XwDisplay *) dev->xwd;
00812     XEvent       event;
00813     PLGraphicsIn *gin = &( dev->gin );
00814 
00815 // Initialize
00816 
00817     plGinInit( gin );
00818     dev->locate_mode = LOCATE_INVOKED_VIA_API;
00819     CreateXhairs( pls );
00820 
00821 // Run event loop until a point is selected
00822 
00823     while ( gin->pX < 0 && dev->locate_mode )
00824     {
00825         // XWindowEvent( xwd->display, dev->window, dev->event_mask, &event );
00826         XNextEvent( xwd->display, &event );
00827         MasterEH( pls, &event );
00828     }
00829     *ptr = *gin;
00830     if ( dev->locate_mode )
00831     {
00832         dev->locate_mode = 0;
00833         DestroyXhairs( pls );
00834     }
00835 }
00836 
00837 //--------------------------------------------------------------------------
00838 // FillPolygonCmd()
00839 //
00840 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
00841 // Only solid color fill supported.
00842 //--------------------------------------------------------------------------
00843 
00844 static void
00845 FillPolygonCmd( PLStream *pls )
00846 {
00847     XwDev     *dev = (XwDev *) pls->dev;
00848     XwDisplay *xwd = (XwDisplay *) dev->xwd;
00849     XPoint    _pts[PL_MAXPOLY];
00850     XPoint    *pts;
00851     int       i;
00852 
00853     if ( pls->dev_npts > PL_MAXPOLY )
00854     {
00855         pts = (XPoint *) malloc( sizeof ( XPoint ) * pls->dev_npts );
00856     }
00857     else
00858     {
00859         pts = _pts;
00860     }
00861 
00862     CheckForEvents( pls );
00863 
00864     for ( i = 0; i < pls->dev_npts; i++ )
00865     {
00866         pts[i].x = dev->xscale * pls->dev_x[i];
00867         pts[i].y = dev->yscale * ( dev->ylen - pls->dev_y[i] );
00868     }
00869 
00870 // Fill polygons
00871 
00872     if ( dev->write_to_window )
00873         XFillPolygon( xwd->display, dev->window, dev->gc,
00874             pts, pls->dev_npts, Complex, CoordModeOrigin );
00875 
00876     if ( dev->write_to_pixmap )
00877         XFillPolygon( xwd->display, dev->pixmap, dev->gc,
00878             pts, pls->dev_npts, Complex, CoordModeOrigin );
00879 
00880 // If in debug mode, draw outline of boxes being filled
00881 
00882 #ifdef DEBUG
00883     if ( pls->debug )
00884     {
00885         XSetForeground( xwd->display, dev->gc, xwd->fgcolor.pixel );
00886         if ( dev->write_to_window )
00887             XDrawLines( xwd->display, dev->window, dev->gc, pts, pls->dev_npts,
00888                 CoordModeOrigin );
00889 
00890         if ( dev->write_to_pixmap )
00891             XDrawLines( xwd->display, dev->pixmap, dev->gc, pts, pls->dev_npts,
00892                 CoordModeOrigin );
00893 
00894         XSetForeground( xwd->display, dev->gc, dev->curcolor.pixel );
00895     }
00896 #endif
00897 
00898     if ( pls->dev_npts > PL_MAXPOLY )
00899     {
00900         free( pts );
00901     }
00902 }
00903 
00904 //--------------------------------------------------------------------------
00905 // OpenXwin()
00906 //
00907 // Performs basic driver initialization, without actually opening or
00908 // modifying a window.  May be called by the outside world before plinit
00909 // in case the caller needs early access to the driver internals (not
00910 // very common -- currently only used by the plframe widget).
00911 //--------------------------------------------------------------------------
00912 
00913 static void
00914 OpenXwin( PLStream *pls )
00915 {
00916     XwDev     *dev;
00917     XwDisplay *xwd;
00918     int       i;
00919 
00920     dbug_enter( "OpenXwin" );
00921 
00922 // Allocate and initialize device-specific data
00923 
00924     if ( pls->dev != NULL )
00925         plwarn( "OpenXwin: device pointer is already set" );
00926 
00927     pls->dev = calloc( 1, (size_t) sizeof ( XwDev ) );
00928     if ( pls->dev == NULL )
00929         plexit( "plD_init_xw: Out of memory." );
00930 
00931     dev = (XwDev *) pls->dev;
00932 
00933 // Variables used in querying the X server for events
00934 
00935     dev->instr     = 0;
00936     dev->max_instr = MAX_INSTR;
00937 
00938 // See if display matches any already in use, and if so use that
00939 
00940     dev->xwd = NULL;
00941     for ( i = 0; i < PLXDISPLAYS; i++ )
00942     {
00943         if ( xwDisplay[i] == NULL )
00944         {
00945             continue;
00946         }
00947         else if ( pls->FileName == NULL && xwDisplay[i]->displayName == NULL )
00948         {
00949             dev->xwd = xwDisplay[i];
00950             break;
00951         }
00952         else if ( pls->FileName == NULL || xwDisplay[i]->displayName == NULL )
00953         {
00954             continue;
00955         }
00956         else if ( strcmp( xwDisplay[i]->displayName, pls->FileName ) == 0 )
00957         {
00958             dev->xwd = xwDisplay[i];
00959             break;
00960         }
00961     }
00962 
00963 // If no display matched, create a new one
00964 
00965     if ( dev->xwd == NULL )
00966     {
00967         dev->xwd = (XwDisplay *) calloc( 1, (size_t) sizeof ( XwDisplay ) );
00968         if ( dev->xwd == NULL )
00969             plexit( "Init: Out of memory." );
00970 
00971         for ( i = 0; i < PLXDISPLAYS; i++ )
00972         {
00973             if ( xwDisplay[i] == NULL )
00974                 break;
00975         }
00976         if ( i == PLXDISPLAYS )
00977             plexit( "Init: Out of xwDisplay's." );
00978 
00979         xwDisplay[i]  = xwd = (XwDisplay *) dev->xwd;
00980         xwd->nstreams = 1;
00981 
00982 // Open display
00983 #ifdef PL_HAVE_PTHREAD
00984         if ( usepthreads )
00985             if ( !XInitThreads() )
00986                 plexit( "xwin: XInitThreads() not successful." );
00987 #endif
00988         xwd->display = XOpenDisplay( pls->FileName );
00989         if ( xwd->display == NULL )
00990         {
00991             plexit( "Can't open display" );
00992         }
00993         xwd->displayName = pls->FileName;
00994         xwd->screen      = DefaultScreen( xwd->display );
00995         if ( synchronize )
00996             XSynchronize( xwd->display, 1 );
00997 
00998         // Get colormap and visual
00999         xwd->map = DefaultColormap( xwd->display, xwd->screen );
01000         GetVisual( pls );
01001 
01002         //
01003         // Figure out if we have a color display or not.
01004         // Default is color IF the user hasn't specified and IF the output device
01005         // is not grayscale.
01006         //
01007         if ( pls->colorset )
01008             xwd->color = pls->color;
01009         else
01010         {
01011             pls->color = 1;
01012             xwd->color = !AreWeGrayscale( xwd->display );
01013         }
01014 
01015         // Allocate space for colors
01016         // Note cmap1 allocation is deferred
01017         xwd->ncol0_alloc = pls->ncol0;
01018         xwd->cmap0       = (XColor *) calloc( pls->ncol0, (size_t) sizeof ( XColor ) );
01019         if ( xwd->cmap0 == 0 )
01020             plexit( "couldn't allocate space for cmap0 colors" );
01021 
01022         // Allocate & set background and foreground colors
01023         AllocBGFG( pls );
01024         SetBGFG( pls );
01025     }
01026 
01027 // Display matched, so use existing display data
01028 
01029     else
01030     {
01031         xwd = (XwDisplay *) dev->xwd;
01032         xwd->nstreams++;
01033     }
01034     xwd->ixwd = i;
01035 }
01036 
01037 //--------------------------------------------------------------------------
01038 // Init()
01039 //
01040 // Xlib initialization routine.
01041 //
01042 // Controlling routine for X window creation and/or initialization.
01043 // The user may customize the window in the following ways:
01044 //
01045 // display:     pls->OutFile (use plsfnam() or -display option)
01046 // size:        pls->xlength, pls->ylength (use plspage() or -geo option)
01047 // bg color:    pls->cmap0[0] (use plscolbg() or -bg option)
01048 //--------------------------------------------------------------------------
01049 
01050 static void
01051 Init( PLStream *pls )
01052 {
01053     XwDev     *dev = (XwDev *) pls->dev;
01054     XwDisplay *xwd = (XwDisplay *) dev->xwd;
01055 
01056     Window    root;
01057     int       x, y;
01058 
01059     dbug_enter( "Init" );
01060 
01061 // If not plotting into a child window, need to create main window now
01062 
01063     if ( pls->window_id == 0 )
01064     {
01065         dev->is_main = TRUE;
01066         InitMain( pls );
01067     }
01068     else
01069     {
01070         dev->is_main = FALSE;
01071         dev->window  = pls->window_id;
01072     }
01073 
01074 // Initialize colors
01075 
01076     if ( noinitcolors == 0 )
01077         InitColors( pls );
01078     XSetWindowColormap( xwd->display, dev->window, xwd->map );
01079 
01080 // Set up GC for ordinary draws
01081 
01082     if ( !dev->gc )
01083         dev->gc = XCreateGC( xwd->display, dev->window, 0, 0 );
01084 
01085 // Set up GC for rubber-band draws
01086 
01087     if ( !xwd->gcXor )
01088     {
01089         XGCValues     gcValues;
01090         unsigned long mask;
01091 
01092         gcValues.background = xwd->cmap0[0].pixel;
01093         gcValues.foreground = 0xFF;
01094         gcValues.function   = GXxor;
01095         mask = GCForeground | GCBackground | GCFunction;
01096 
01097         xwd->gcXor = XCreateGC( xwd->display, dev->window, mask, &gcValues );
01098     }
01099 
01100 // Get initial drawing area dimensions
01101 
01102     (void) XGetGeometry( xwd->display, dev->window, &root, &x, &y,
01103         &dev->width, &dev->height, &dev->border, &xwd->depth );
01104 
01105     dev->init_width  = dev->width;
01106     dev->init_height = dev->height;
01107 
01108 // Set up flags that determine what we are writing to
01109 // If nopixmap is set, ignore db
01110 
01111     if ( pls->nopixmap )
01112     {
01113         dev->write_to_pixmap = 0;
01114         pls->db = 0;
01115     }
01116     else
01117     {
01118         dev->write_to_pixmap = 1;
01119     }
01120     dev->write_to_window = !pls->db;
01121 
01122 // Create pixmap for holding plot image (for expose events).
01123 
01124     if ( dev->write_to_pixmap )
01125         CreatePixmap( pls );
01126 
01127 // Set drawing color
01128 
01129     plD_state_xw( pls, PLSTATE_COLOR0 );
01130 
01131     XSetWindowBackground( xwd->display, dev->window, xwd->cmap0[0].pixel );
01132     XSetBackground( xwd->display, dev->gc, xwd->cmap0[0].pixel );
01133 
01134 // Set fill rule.
01135     if ( pls->dev_eofill )
01136         XSetFillRule( xwd->display, dev->gc, EvenOddRule );
01137     else
01138         XSetFillRule( xwd->display, dev->gc, WindingRule );
01139 
01140 // If main window, need to map it and wait for exposure
01141 
01142     if ( dev->is_main )
01143         MapMain( pls );
01144 }
01145 
01146 //--------------------------------------------------------------------------
01147 // InitMain()
01148 //
01149 // Create main window using standard Xlib calls.
01150 //--------------------------------------------------------------------------
01151 
01152 static void
01153 InitMain( PLStream *pls )
01154 {
01155     XwDev      *dev = (XwDev *) pls->dev;
01156     XwDisplay  *xwd = (XwDisplay *) dev->xwd;
01157 
01158     Window     root;
01159     XSizeHints hint;
01160     int        x, y;
01161     U_INT      width, height, border, depth;
01162 
01163     dbug_enter( "InitMain" );
01164 
01165 // Get root window geometry
01166 
01167     (void) XGetGeometry( xwd->display, DefaultRootWindow( xwd->display ),
01168         &root, &x, &y, &width, &height, &border, &depth );
01169 
01170 // Set window size
01171 // Need to be careful to set XSizeHints flags correctly
01172 
01173     hint.flags = 0;
01174     if ( pls->xlength == 0 && pls->ylength == 0 )
01175         hint.flags |= PSize;
01176     else
01177         hint.flags |= USSize;
01178 
01179     if ( pls->xlength == 0 )
01180         pls->xlength = width * 0.75;
01181     if ( pls->ylength == 0 )
01182         pls->ylength = height * 0.75;
01183 
01184     if ( pls->xlength > (short) width )
01185         pls->xlength = width - dev->border * 2;
01186     if ( pls->ylength > (short) height )
01187         pls->ylength = height - dev->border * 2;
01188 
01189     hint.width  = (int) pls->xlength;
01190     hint.height = (int) pls->ylength;
01191     dev->border = 5;
01192 
01193 // Set window position if specified by the user.
01194 // Otherwise leave up to the window manager
01195 
01196     if ( pls->xoffset != 0 || pls->yoffset != 0 )
01197     {
01198         hint.flags |= USPosition;
01199         hint.x      = (int) pls->xoffset;
01200         hint.y      = (int) pls->yoffset;
01201     }
01202     else
01203     {
01204         hint.x = 0;
01205         hint.y = 0;
01206     }
01207 
01208 // Window creation
01209 
01210     dev->window =
01211         XCreateWindow( xwd->display,
01212             DefaultRootWindow( xwd->display ),
01213             hint.x, hint.y, hint.width, hint.height,
01214             dev->border, xwd->depth,
01215             InputOutput, xwd->visual,
01216             0, NULL );
01217 
01218     XSetStandardProperties( xwd->display, dev->window, pls->plwindow, pls->plwindow,
01219         None, 0, 0, &hint );
01220 }
01221 
01222 //--------------------------------------------------------------------------
01223 // MapMain()
01224 //
01225 // Sets up event handlers, maps main window and waits for exposure.
01226 //--------------------------------------------------------------------------
01227 
01228 static void
01229 MapMain( PLStream *pls )
01230 {
01231     XwDev     *dev = (XwDev *) pls->dev;
01232     XwDisplay *xwd = (XwDisplay *) dev->xwd;
01233     XEvent    event;
01234 
01235     dbug_enter( "MapMain" );
01236 
01237 // Input event selection
01238 
01239     dev->event_mask =
01240         ButtonPressMask |
01241         KeyPressMask |
01242         ExposureMask |
01243         ButtonMotionMask |     // drag
01244         StructureNotifyMask;
01245 
01246     XSelectInput( xwd->display, dev->window, dev->event_mask );
01247 
01248 // Window mapping
01249 
01250     XMapRaised( xwd->display, dev->window );
01251 
01252     Atom wmDelete = XInternAtom( xwd->display, "WM_DELETE_WINDOW", False );
01253     XSetWMProtocols( xwd->display, dev->window, &wmDelete, 1 );
01254 
01255 // Wait for exposure
01256 // Remove extraneous expose events from the event queue
01257 
01258     for (;; )
01259     {
01260         XWindowEvent( xwd->display, dev->window, dev->event_mask, &event );
01261         if ( event.type == Expose )
01262         {
01263             while ( XCheckWindowEvent( xwd->display, dev->window,
01264                         ExposureMask, &event ) )
01265                 ;
01266             break;
01267         }
01268     }
01269 }
01270 
01271 //--------------------------------------------------------------------------
01272 // WaitForPage()
01273 //
01274 // This routine waits for the user to advance the plot, while handling
01275 // all other events.
01276 //--------------------------------------------------------------------------
01277 
01278 static void
01279 WaitForPage( PLStream *pls )
01280 {
01281     XwDev     *dev = (XwDev *) pls->dev;
01282     XwDisplay *xwd = (XwDisplay *) dev->xwd;
01283     XEvent    event;
01284 
01285     dbug_enter( "WaitForPage" );
01286 
01287     while ( !dev->exit_eventloop )
01288     {
01289         // XWindowEvent( xwd->display, dev->window, dev->event_mask, &event );
01290         XNextEvent( xwd->display, &event );
01291         MasterEH( pls, &event );
01292     }
01293     dev->exit_eventloop = FALSE;
01294 }
01295 
01296 //--------------------------------------------------------------------------
01297 // events_thread()
01298 //
01299 // This function is being running continously by a thread and is
01300 // responsible for dealing with expose and resize X events, in
01301 // the case that the main program is too busy to honor them.
01302 //
01303 // Dealing with other X events is possible, but not desirable,
01304 // e.g. treating the "Q" or right-mouse-button would terminate
01305 // the thread (if this is desirable, the thread should kill the
01306 // main program -- not thread aware -- and kill itself afterward).
01307 //
01308 // This works pretty well, but the main program *must* be linked
01309 // with the pthread library, although not being thread aware.
01310 // This happens automatically when linking against libplplot.so,
01311 // but when building modules for extending some language such as
01312 // Python or Octave, the language providing binary itself must be
01313 // relinked with -lpthread.
01314 //
01315 //--------------------------------------------------------------------------
01316 
01317 #ifdef PL_HAVE_PTHREAD
01318 static void
01319 events_thread( void *pls )
01320 {
01321     if ( usepthreads )
01322     {
01323         PLStream        *lpls = (PLStream *) pls;
01324         XwDev           *dev  = (XwDev *) lpls->dev;
01325         XwDisplay       *xwd  = (XwDisplay *) dev->xwd;
01326         PLStream        *oplsc;
01327         struct timespec delay;
01328         XEvent          event;
01329         long            event_mask;
01330         sigset_t        set;
01331 
01332         //
01333         // only treats exposures and resizes, but remove usual events from queue,
01334         // as it can be disturbing to not have them acknowledged in real time,
01335         // because the program is busy, and suddenly all being acknowledged.
01336         // Also, the locator ("L" key) is sluggish if driven by the thread.
01337         //
01338         // But this approach is a problem when the thread removes events
01339         // from the queue while the program is responsible! The user hits 'L'
01340         // and nothing happens, as the thread removes it.
01341         //
01342         // Perhaps the "Q" key should have a different treatment, quiting the
01343         // program anyway?
01344         //
01345         // Changed: does not remove non treated events from the queue
01346         //
01347 
01348         event_mask = ExposureMask | StructureNotifyMask;
01349 
01350         // block all signal for this thread
01351         sigemptyset( &set );
01352         // sigfillset(&set);  can't be all signals, decide latter
01353         sigaddset( &set, SIGINT );
01354 
01355         sigprocmask( SIG_BLOCK, &set, NULL );
01356 
01357         pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
01358         pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL );
01359 
01360         delay.tv_sec  = 0;
01361         delay.tv_nsec = 10000000; // this thread runs 10 times a second. (1/10 ms)
01362 
01363         while ( 1 )
01364         {
01365             pthread_mutex_lock( &events_mutex );
01366 
01367             if ( dev->is_main && !lpls->plbuf_read &&
01368                  ++dev->instr % dev->max_instr == 0 )
01369             {
01370                 dev->instr = 0;
01371                 while ( XCheckWindowEvent( xwd->display, dev->window, event_mask, &event ) )
01372                 {
01373                     // As ResizeEH() ends up calling plRemakePlot(), that
01374                     // indirectly uses the current stream, one needs to
01375                     // temporarily set plplot current stream to this thread's
01376                     // stream
01377 
01378                     oplsc = plsc;
01379                     plsc  = lpls;
01380                     switch ( event.type )
01381                     {
01382                     case Expose:
01383                         ExposeEH( lpls, &event );
01384                         break;
01385                     case ConfigureNotify:
01386                         ResizeEH( lpls, &event );
01387                         break;
01388                     }
01389                     plsc = oplsc;
01390                 }
01391             }
01392 
01393             pthread_mutex_unlock( &events_mutex );
01394             nanosleep( &delay, NULL ); // 10ms in linux
01395             /* pthread_yield(NULL); */ /* this puts too much load on the CPU */
01396         }
01397     }
01398 }
01399 #endif
01400 
01401 //--------------------------------------------------------------------------
01402 // CheckForEvents()
01403 //
01404 // A front-end to HandleEvents(), which is only called if certain conditions
01405 // are satisfied:
01406 //
01407 // - must be the creator of the main window (i.e. PLplot is handling the
01408 //   X event loop by polling).
01409 // - must not be in the middle of a plot redisplay (else the order of event
01410 //   handling can become circuitous).
01411 // - only query X for events and process them every dev->max_instr times
01412 //   this function is called (good for performance since querying X is a
01413 //   nontrivial performance hit).
01414 //--------------------------------------------------------------------------
01415 
01416 static void
01417 CheckForEvents( PLStream *pls )
01418 {
01419     XwDev *dev = (XwDev *) pls->dev;
01420 
01421     if ( dev->is_main &&
01422          !pls->plbuf_read &&
01423          ++dev->instr % dev->max_instr == 0 )
01424     {
01425         dev->instr = 0;
01426         HandleEvents( pls );
01427     }
01428 }
01429 
01430 //--------------------------------------------------------------------------
01431 // HandleEvents()
01432 //
01433 // Just a front-end to MasterEH(), for use when not actually waiting for an
01434 // event but only checking the event queue.
01435 //--------------------------------------------------------------------------
01436 
01437 static void
01438 HandleEvents( PLStream *pls )
01439 {
01440     XwDev     *dev = (XwDev *) pls->dev;
01441     XwDisplay *xwd = (XwDisplay *) dev->xwd;
01442     XEvent    event;
01443 
01444     while ( XCheckTypedWindowEvent( xwd->display, dev->window,
01445                 ClientMessage, &event ) ||
01446             XCheckWindowEvent( xwd->display, dev->window,
01447                 dev->event_mask, &event ) )
01448         MasterEH( pls, &event );
01449 }
01450 
01451 //--------------------------------------------------------------------------
01452 // MasterEH()
01453 //
01454 // Master X event handler routine.
01455 // Redirects control to routines to handle:
01456 //    - keyboard events
01457 //    - mouse events
01458 //    - expose events
01459 //    - resize events
01460 //
01461 // By supplying a master event handler, the user can take over all event
01462 // processing.  If events other than those trapped by PLplot need handling,
01463 // just call XSelectInput with the appropriate flags.  The default PLplot
01464 // event handling can be modified arbitrarily by changing the event struct.
01465 //--------------------------------------------------------------------------
01466 
01467 static void
01468 MasterEH( PLStream *pls, XEvent *event )
01469 {
01470     XwDev *dev = (XwDev *) pls->dev;
01471 
01472     if ( dev->MasterEH != NULL )
01473         ( *dev->MasterEH )( pls, event );
01474 
01475     switch ( event->type )
01476     {
01477     case KeyPress:
01478         KeyEH( pls, event );
01479         break;
01480 
01481     case ButtonPress:
01482         ButtonEH( pls, event );
01483         break;
01484 
01485     case Expose:
01486         ExposeEH( pls, event );
01487         break;
01488 
01489     case ConfigureNotify:
01490         ResizeEH( pls, event );
01491         break;
01492 
01493     case MotionNotify:
01494         if ( event->xmotion.state )
01495             ButtonEH( pls, event ); // drag
01496         MotionEH( pls, event );
01497         break;
01498 
01499     case EnterNotify:
01500         EnterEH( pls, event );
01501         break;
01502 
01503     case LeaveNotify:
01504         LeaveEH( pls, event );
01505         break;
01506 
01507     case ClientMessage:
01508         ClientEH( pls, event );
01509         break;
01510     }
01511 }
01512 
01513 //--------------------------------------------------------------------------
01514 // ClientEH()
01515 //
01516 // Event handler routine for client message events (WM_DELETE_WINDOW)
01517 //--------------------------------------------------------------------------
01518 
01519 static void
01520 ClientEH( PLStream *pls, XEvent *event )
01521 {
01522     XwDev     *dev = (XwDev *) pls->dev;
01523     XwDisplay *xwd = (XwDisplay *) dev->xwd;
01524 
01525     if ( event->xclient.data.l[0] == XInternAtom( xwd->display, "WM_DELETE_WINDOW", False ) )
01526     {
01527         pls->nopause        = TRUE;
01528         pls->stream_closed  = TRUE;
01529         dev->exit_eventloop = TRUE;
01530         // plexit( "" );
01531     }
01532 }
01533 
01534 
01535 //--------------------------------------------------------------------------
01536 // KeyEH()
01537 //
01538 // Event handler routine for keyboard events.
01539 //--------------------------------------------------------------------------
01540 
01541 static void
01542 KeyEH( PLStream *pls, XEvent *event )
01543 {
01544     XwDev *dev = (XwDev *) pls->dev;
01545 
01546     dbug_enter( "KeyEH" );
01547 
01548     LookupXKeyEvent( pls, event );
01549     if ( dev->locate_mode )
01550         LocateKey( pls );
01551     else
01552         ProcessKey( pls );
01553 }
01554 
01555 //--------------------------------------------------------------------------
01556 // ButtonEH()
01557 //
01558 // Event handler routine for ButtonPress events.
01559 //--------------------------------------------------------------------------
01560 
01561 static void
01562 ButtonEH( PLStream *pls, XEvent *event )
01563 {
01564     XwDev *dev = (XwDev *) pls->dev;
01565 
01566     dbug_enter( "ButtonEH" );
01567 
01568     LookupXButtonEvent( pls, event );
01569     if ( dev->locate_mode )
01570         LocateButton( pls );
01571     else
01572         ProcessButton( pls );
01573 }
01574 
01575 //--------------------------------------------------------------------------
01576 // LookupXKeyEvent()
01577 //
01578 // Fills in the PLGraphicsIn from an XKeyEvent.  The PLGraphicsIn keysym is
01579 // the same as the X keysym for all cases except for control keys that have
01580 // ASCII equivalents, i.e.:
01581 //
01582 // Name               X-keysym  ASCII   Ctrl-key
01583 // ----               --------  -----   --------
01584 // XK_BackSpace        0xFF08   0x08      ^H
01585 // XK_Tab              0xFF09   0x09      ^I
01586 // XK_Linefeed         0xFF0A   0x0A      ^J
01587 // XK_Return           0xFF0D   0x0D      ^M
01588 // XK_Escape           0xFF1B   0x1B      ^[
01589 // XK_Delete           0xFFFF   0xFF     (none)
01590 //
01591 // The ASCII representation of these characters is used for the PLGraphicsIn
01592 // keysym to simplify code logic.  It turns out that the X keysyms are
01593 // identical to the ASCII values with the upper 8 bits set.
01594 //--------------------------------------------------------------------------
01595 
01596 static void
01597 LookupXKeyEvent( PLStream *pls, XEvent *event )
01598 {
01599     XwDev          *dev      = (XwDev *) pls->dev;
01600     PLGraphicsIn   *gin      = &( dev->gin );
01601     XKeyEvent      *keyEvent = (XKeyEvent *) event;
01602     KeySym         keysym;
01603     int            nchars, ncmax = PL_MAXKEY - 1;
01604     XComposeStatus cs;
01605 
01606     gin->pX = keyEvent->x;
01607     gin->pY = keyEvent->y;
01608     gin->dX = (PLFLT) keyEvent->x / ( dev->width - 1 );
01609     gin->dY = 1.0 - (PLFLT) keyEvent->y / ( dev->height - 1 );
01610 
01611     gin->state = keyEvent->state;
01612 
01613     nchars = XLookupString( keyEvent, gin->string, ncmax, &keysym, &cs );
01614     gin->string[nchars] = '\0';
01615 
01616     pldebug( "LookupXKeyEvent",
01617         "Keysym %x, translation: %s\n", keysym, gin->string );
01618 
01619     switch ( keysym )
01620     {
01621     case XK_BackSpace:
01622     case XK_Tab:
01623     case XK_Linefeed:
01624     case XK_Return:
01625     case XK_Escape:
01626     case XK_Delete:
01627         gin->keysym = 0xFF & keysym;
01628         break;
01629 
01630     default:
01631         gin->keysym = keysym;
01632     }
01633 }
01634 
01635 //--------------------------------------------------------------------------
01636 // LookupXButtonEvent()
01637 //
01638 // Fills in the PLGraphicsIn from an XButtonEvent.
01639 //--------------------------------------------------------------------------
01640 
01641 static void
01642 LookupXButtonEvent( PLStream *pls, XEvent *event )
01643 {
01644     XwDev        *dev         = (XwDev *) pls->dev;
01645     PLGraphicsIn *gin         = &( dev->gin );
01646     XButtonEvent *buttonEvent = (XButtonEvent *) event;
01647 
01648     pldebug( "LookupXButtonEvent",
01649         "Button: %d, x: %d, y: %d\n",
01650         buttonEvent->button, buttonEvent->x, buttonEvent->y );
01651 
01652     gin->pX = buttonEvent->x;
01653     gin->pY = buttonEvent->y;
01654     gin->dX = (PLFLT) buttonEvent->x / ( dev->width - 1 );
01655     gin->dY = 1.0 - (PLFLT) buttonEvent->y / ( dev->height - 1 );
01656 
01657     gin->button = buttonEvent->button;
01658     gin->state  = buttonEvent->state;
01659     gin->keysym = 0x20;
01660 }
01661 
01662 //--------------------------------------------------------------------------
01663 // ProcessKey()
01664 //
01665 // Process keyboard events other than locate input.
01666 //--------------------------------------------------------------------------
01667 
01668 static void
01669 ProcessKey( PLStream *pls )
01670 {
01671     XwDev        *dev = (XwDev *) pls->dev;
01672     PLGraphicsIn *gin = &( dev->gin );
01673 
01674     dbug_enter( "ProcessKey" );
01675 
01676 // Call user keypress event handler.  Since this is called first, the user
01677 // can disable all internal event handling by setting key.keysym to 0.
01678 //
01679     if ( pls->KeyEH != NULL )
01680         ( *pls->KeyEH )( gin, pls->KeyEH_data, &dev->exit_eventloop );
01681 
01682 // Handle internal events
01683 
01684     switch ( gin->keysym )
01685     {
01686     case PLK_Return:
01687     case PLK_Linefeed:
01688     case PLK_Next:
01689         // Advance to next page (i.e. terminate event loop) on a <eol>
01690         // Check for both <CR> and <LF> for portability, also a <Page Down>
01691         dev->exit_eventloop = TRUE;
01692         break;
01693 
01694     case 'Q':
01695         // Terminate on a 'Q' (not 'q', since it's too easy to hit by mistake)
01696         pls->nopause = TRUE;
01697         plexit( "" );
01698         break;
01699 
01700     case 'L':
01701         // Begin locate mode
01702         dev->locate_mode = LOCATE_INVOKED_VIA_DRIVER;
01703         CreateXhairs( pls );
01704         break;
01705     }
01706 }
01707 
01708 //--------------------------------------------------------------------------
01709 // ProcessButton()
01710 //
01711 // Process ButtonPress events other than locate input.
01712 // On:
01713 //   Button1: nothing (except when in locate mode, see ButtonLocate)
01714 //   Button2: nothing
01715 //   Button3: set page advance flag
01716 //--------------------------------------------------------------------------
01717 
01718 static void
01719 ProcessButton( PLStream *pls )
01720 {
01721     XwDev        *dev = (XwDev *) pls->dev;
01722     PLGraphicsIn *gin = &( dev->gin );
01723 
01724     dbug_enter( "ProcessButton" );
01725 
01726 // Call user event handler.  Since this is called first, the user can
01727 // disable all PLplot internal event handling by setting gin->button to 0.
01728 //
01729     if ( pls->ButtonEH != NULL )
01730         ( *pls->ButtonEH )( gin, pls->ButtonEH_data, &dev->exit_eventloop );
01731 
01732 // Handle internal events
01733 
01734     switch ( gin->button )
01735     {
01736     case Button3:
01737         dev->exit_eventloop = TRUE;
01738         break;
01739     }
01740 }
01741 
01742 //--------------------------------------------------------------------------
01743 // LocateKey()
01744 //
01745 // Front-end to locate handler for KeyPress events.
01746 // Provides for a number of special effects:
01747 //
01748 //  <Escape>            Ends locate mode
01749 //  <Cursor>            Moves cursor one pixel in the specified direction
01750 //  <Mod-Cursor>        Accelerated cursor movement (5x for each modifier)
01751 //--------------------------------------------------------------------------
01752 
01753 static void
01754 LocateKey( PLStream *pls )
01755 {
01756     XwDev        *dev = (XwDev *) pls->dev;
01757     XwDisplay    *xwd = (XwDisplay *) dev->xwd;
01758     PLGraphicsIn *gin = &( dev->gin );
01759 
01760 // End locate mode on <Escape>
01761 
01762     if ( gin->keysym == PLK_Escape )
01763     {
01764         dev->locate_mode = 0;
01765         DestroyXhairs( pls );
01766         plGinInit( gin );
01767     }
01768 
01769 // Ignore modifier keys
01770 
01771     else if ( IsModifierKey( gin->keysym ) )
01772     {
01773         plGinInit( gin );
01774     }
01775 
01776 // Now handle cursor keys
01777 
01778     else if ( IsCursorKey( gin->keysym ) )
01779     {
01780         int x1, y1, dx = 0, dy = 0;
01781         int xmin = 0, xmax = dev->width - 1, ymin = 0, ymax = dev->height - 1;
01782 
01783         switch ( gin->keysym )
01784         {
01785         case PLK_Left:
01786             dx = -1;
01787             break;
01788         case PLK_Right:
01789             dx = 1;
01790             break;
01791         case PLK_Up:
01792             dy = -1;
01793             break;
01794         case PLK_Down:
01795             dy = 1;
01796             break;
01797         }
01798 
01799         // Each modifier key added increases the multiplication factor by 5
01800 
01801         // Shift
01802 
01803         if ( gin->state & 0x01 )
01804         {
01805             dx *= 5;
01806             dy *= 5;
01807         }
01808 
01809         // Caps Lock
01810 
01811         if ( gin->state & 0x02 )
01812         {
01813             dx *= 5;
01814             dy *= 5;
01815         }
01816 
01817         // Control
01818 
01819         if ( gin->state & 0x04 )
01820         {
01821             dx *= 5;
01822             dy *= 5;
01823         }
01824 
01825         // Alt
01826 
01827         if ( gin->state & 0x08 )
01828         {
01829             dx *= 5;
01830             dy *= 5;
01831         }
01832 
01833         // Bounds checking so that we don't send cursor out of window
01834 
01835         x1 = gin->pX + dx;
01836         y1 = gin->pY + dy;
01837 
01838         if ( x1 < xmin )
01839             dx = xmin - gin->pX;
01840         if ( y1 < ymin )
01841             dy = ymin - gin->pY;
01842         if ( x1 > xmax )
01843             dx = xmax - gin->pX;
01844         if ( y1 > ymax )
01845             dy = ymax - gin->pY;
01846 
01847         // Engage...
01848 
01849         XWarpPointer( xwd->display, dev->window, None, 0, 0, 0, 0, dx, dy );
01850         plGinInit( gin );
01851     }
01852 
01853 // Call ordinary locate handler
01854 
01855     else
01856     {
01857         Locate( pls );
01858     }
01859 }
01860 
01861 //--------------------------------------------------------------------------
01862 // LocateButton()
01863 //
01864 // Front-end to locate handler for ButtonPress events.
01865 // Only passes control to Locate() for Button1 presses.
01866 //--------------------------------------------------------------------------
01867 
01868 static void
01869 LocateButton( PLStream *pls )
01870 {
01871     XwDev        *dev = (XwDev *) pls->dev;
01872     PLGraphicsIn *gin = &( dev->gin );
01873 
01874     switch ( gin->button )
01875     {
01876     case Button1:
01877         Locate( pls );
01878         break;
01879     }
01880 }
01881 
01882 //--------------------------------------------------------------------------
01883 // Locate()
01884 //
01885 // Handles locate mode events.
01886 //
01887 // In locate mode: move cursor to desired location and select by pressing a
01888 // key or by clicking on the mouse (if available).  Typically the world
01889 // coordinates of the selected point are reported.
01890 //
01891 // There are two ways to enter Locate mode -- via the API, or via a driver
01892 // command.  The API entry point is the call plGetCursor(), which initiates
01893 // locate mode and does not return until input has been obtained.  The
01894 // driver entry point is by entering a 'L' while the driver is waiting for
01895 // events.
01896 //
01897 // Locate mode input is reported in one of three ways:
01898 // 1. Through a returned PLGraphicsIn structure, when user has specified a
01899 //    locate handler via (*pls->LocateEH).
01900 // 2. Through a returned PLGraphicsIn structure, when locate mode is invoked
01901 //    by a plGetCursor() call.
01902 // 3. Through writes to stdout, when locate mode is invoked by a driver
01903 //    command and the user has not supplied a locate handler.
01904 //
01905 // Hitting <Escape> will at all times end locate mode.  Other keys will
01906 // typically be interpreted as locator input.  Selecting a point out of
01907 // bounds will end locate mode unless the user overrides with a supplied
01908 // Locate handler.
01909 //--------------------------------------------------------------------------
01910 
01911 static void
01912 Locate( PLStream *pls )
01913 {
01914     XwDev        *dev = (XwDev *) pls->dev;
01915     PLGraphicsIn *gin = &( dev->gin );
01916 
01917 // Call user locate mode handler if provided
01918 
01919     if ( pls->LocateEH != NULL )
01920         ( *pls->LocateEH )( gin, pls->LocateEH_data, &dev->locate_mode );
01921 
01922 // Use default procedure
01923 
01924     else
01925     {
01926         // Try to locate cursor
01927 
01928         if ( plTranslateCursor( gin ) )
01929         {
01930             // If invoked by the API, we're done
01931             // Otherwise send report to stdout
01932 
01933             if ( dev->locate_mode == LOCATE_INVOKED_VIA_DRIVER )
01934             {
01935                 pltext();
01936                 if ( gin->keysym < 0xFF && isprint( gin->keysym ) )
01937                     printf( "%f %f %c\n", gin->wX, gin->wY, gin->keysym );
01938                 else
01939                     printf( "%f %f 0x%02x\n", gin->wX, gin->wY, gin->keysym );
01940 
01941                 plgra();
01942             }
01943         }
01944         else
01945         {
01946             // Selected point is out of bounds, so end locate mode
01947 
01948             dev->locate_mode = 0;
01949             DestroyXhairs( pls );
01950         }
01951     }
01952 }
01953 
01954 //--------------------------------------------------------------------------
01955 // MotionEH()
01956 //
01957 // Event handler routine for MotionNotify events.
01958 // If drawing crosshairs, the first and last draws must be done "by hand".
01959 //--------------------------------------------------------------------------
01960 
01961 static void
01962 MotionEH( PLStream *pls, XEvent *event )
01963 {
01964     XwDev        *dev         = (XwDev *) pls->dev;
01965     XMotionEvent *motionEvent = (XMotionEvent *) event;
01966 
01967     if ( dev->drawing_xhairs )
01968     {
01969         DrawXhairs( pls, motionEvent->x, motionEvent->y );
01970     }
01971 }
01972 
01973 //--------------------------------------------------------------------------
01974 // EnterEH()
01975 //
01976 // Event handler routine for EnterNotify events.  Only called if drawing
01977 // crosshairs -- a draw must be done here to start off the new set.
01978 //--------------------------------------------------------------------------
01979 
01980 static void
01981 EnterEH( PLStream *pls, XEvent *event )
01982 {
01983     XwDev          *dev           = (XwDev *) pls->dev;
01984     XCrossingEvent *crossingEvent = (XCrossingEvent *) event;
01985 
01986     DrawXhairs( pls, crossingEvent->x, crossingEvent->y );
01987     dev->drawing_xhairs = 1;
01988 }
01989 
01990 //--------------------------------------------------------------------------
01991 // LeaveEH()
01992 //
01993 // Event handler routine for EnterNotify or LeaveNotify events.
01994 // If drawing crosshairs, a draw must be done here to start off the new
01995 // set or erase the last set.
01996 //--------------------------------------------------------------------------
01997 
01998 static void
01999 LeaveEH( PLStream *pls, XEvent *event )
02000 {
02001     XwDev *dev = (XwDev *) pls->dev;
02002 
02003     UpdateXhairs( pls );
02004     dev->drawing_xhairs = 0;
02005 }
02006 
02007 //--------------------------------------------------------------------------
02008 // CreateXhairs()
02009 //
02010 // Creates graphic crosshairs at current pointer location.
02011 //--------------------------------------------------------------------------
02012 
02013 static void
02014 CreateXhairs( PLStream *pls )
02015 {
02016     XwDev        *dev = (XwDev *) pls->dev;
02017     XwDisplay    *xwd = (XwDisplay *) dev->xwd;
02018     Window       root, child;
02019     int          root_x, root_y, win_x, win_y;
02020     unsigned int mask;
02021     XEvent       event;
02022 
02023 // Get a crosshair cursor and switch to it.
02024 
02025     if ( !xwd->xhair_cursor )
02026         xwd->xhair_cursor = XCreateFontCursor( xwd->display, XC_crosshair );
02027 
02028     XDefineCursor( xwd->display, dev->window, xwd->xhair_cursor );
02029 
02030 // Find current pointer location and draw graphic crosshairs if pointer is
02031 // inside our window
02032 
02033     if ( XQueryPointer( xwd->display, dev->window, &root, &child,
02034              &root_x, &root_y, &win_x, &win_y, &mask ) )
02035     {
02036         if ( win_x >= 0 && win_x < (int) dev->width &&
02037              win_y >= 0 && win_y < (int) dev->height )
02038         {
02039             DrawXhairs( pls, win_x, win_y );
02040             dev->drawing_xhairs = 1;
02041         }
02042     }
02043 
02044 // Sync the display and then throw away all pending motion events
02045 
02046     XSync( xwd->display, 0 );
02047     while ( XCheckWindowEvent( xwd->display, dev->window,
02048                 PointerMotionMask, &event ) )
02049         ;
02050 
02051 // Catch PointerMotion and crossing events so we can update them properly
02052 
02053     dev->event_mask |= PointerMotionMask | EnterWindowMask | LeaveWindowMask;
02054     XSelectInput( xwd->display, dev->window, dev->event_mask );
02055 }
02056 
02057 //--------------------------------------------------------------------------
02058 // DestroyXhairs()
02059 //
02060 // Destroys graphic crosshairs.
02061 //--------------------------------------------------------------------------
02062 
02063 static void
02064 DestroyXhairs( PLStream *pls )
02065 {
02066     XwDev     *dev = (XwDev *) pls->dev;
02067     XwDisplay *xwd = (XwDisplay *) dev->xwd;
02068 
02069 // Switch back to boring old pointer
02070 
02071     XUndefineCursor( xwd->display, dev->window );
02072 
02073 // Don't catch PointerMotion or crossing events any more
02074 
02075     dev->event_mask &=
02076         ~PointerMotionMask & ~EnterWindowMask & ~LeaveWindowMask;
02077     XSelectInput( xwd->display, dev->window, dev->event_mask );
02078 
02079 // This draw removes the last set of graphic crosshairs
02080 
02081     UpdateXhairs( pls );
02082     dev->drawing_xhairs = 0;
02083 }
02084 
02085 //--------------------------------------------------------------------------
02086 // DrawXhairs()
02087 //
02088 // Draws graphic crosshairs at (x0, y0).  The first draw erases the old set.
02089 //--------------------------------------------------------------------------
02090 
02091 static void
02092 DrawXhairs( PLStream *pls, int x0, int y0 )
02093 {
02094     XwDev *dev = (XwDev *) pls->dev;
02095 
02096     int   xmin = 0, xmax = dev->width - 1;
02097     int   ymin = 0, ymax = dev->height - 1;
02098 
02099     if ( dev->drawing_xhairs )
02100         UpdateXhairs( pls );
02101 
02102     dev->xhair_x[0].x = xmin; dev->xhair_x[0].y = y0;
02103     dev->xhair_x[1].x = xmax; dev->xhair_x[1].y = y0;
02104 
02105     dev->xhair_y[0].x = x0; dev->xhair_y[0].y = ymin;
02106     dev->xhair_y[1].x = x0; dev->xhair_y[1].y = ymax;
02107 
02108     UpdateXhairs( pls );
02109 }
02110 
02111 //--------------------------------------------------------------------------
02112 // UpdateXhairs()
02113 //
02114 // Updates graphic crosshairs.  If already there, they are erased.
02115 //--------------------------------------------------------------------------
02116 
02117 static void
02118 UpdateXhairs( PLStream *pls )
02119 {
02120     XwDev     *dev = (XwDev *) pls->dev;
02121     XwDisplay *xwd = (XwDisplay *) dev->xwd;
02122 
02123     XDrawLines( xwd->display, dev->window, xwd->gcXor, dev->xhair_x, 2,
02124         CoordModeOrigin );
02125 
02126     XDrawLines( xwd->display, dev->window, xwd->gcXor, dev->xhair_y, 2,
02127         CoordModeOrigin );
02128 }
02129 
02130 //--------------------------------------------------------------------------
02131 // ExposeEH()
02132 //
02133 // Event handler routine for expose events.
02134 // Front end to ExposeCmd() to deal with wierdnesses of Xlib.
02135 //--------------------------------------------------------------------------
02136 
02137 static void
02138 ExposeEH( PLStream *pls, XEvent *event )
02139 {
02140     XwDev        *dev         = (XwDev *) pls->dev;
02141     XwDisplay    *xwd         = (XwDisplay *) dev->xwd;
02142     XExposeEvent *exposeEvent = (XExposeEvent *) event;
02143     PLDisplay    pldis;
02144     int          redrawn;
02145 
02146     dbug_enter( "ExposeEH" );
02147 
02148     pldebug( "ExposeEH",
02149         "x = %d, y = %d, width = %d, height = %d, count = %d, pending = %d\n",
02150         exposeEvent->x, exposeEvent->y,
02151         exposeEvent->width, exposeEvent->height,
02152         exposeEvent->count, XPending( xwd->display ) );
02153 
02154 // Handle expose
02155 // If we have anything overlaid (like crosshairs), we need to refresh the
02156 // entire plot in order to have a predictable outcome.  In this case we
02157 // need to first clear window.  Otherwise it's better to not clear it, for a
02158 // smoother redraw (unobscured regions appear to stay the same).
02159 
02160     if ( dev->drawing_xhairs )
02161     {
02162         XClearWindow( xwd->display, dev->window );
02163         ExposeCmd( pls, NULL );
02164         UpdateXhairs( pls );
02165         redrawn = 1;
02166     }
02167     else
02168     {
02169         pldis.x      = exposeEvent->x;
02170         pldis.y      = exposeEvent->y;
02171         pldis.width  = exposeEvent->width;
02172         pldis.height = exposeEvent->height;
02173 
02174         ExposeCmd( pls, &pldis );
02175         redrawn = !dev->write_to_pixmap;
02176     }
02177 
02178 // If entire plot was redrawn, remove extraneous events from the queue
02179 
02180     if ( redrawn )
02181         while ( XCheckWindowEvent( xwd->display, dev->window,
02182                     ExposureMask | StructureNotifyMask, event ) )
02183             ;
02184 }
02185 
02186 //--------------------------------------------------------------------------
02187 // ResizeEH()
02188 //
02189 // Event handler routine for resize events.
02190 // Front end to ResizeCmd() to deal with wierdnesses of Xlib.
02191 //--------------------------------------------------------------------------
02192 
02193 static void
02194 ResizeEH( PLStream *pls, XEvent *event )
02195 {
02196     XwDev           *dev         = (XwDev *) pls->dev;
02197     XwDisplay       *xwd         = (XwDisplay *) dev->xwd;
02198     XConfigureEvent *configEvent = (XConfigureEvent *) event;
02199     PLDisplay       pldis;
02200 
02201     dbug_enter( "ResizeEH" );
02202 
02203     pldis.width  = configEvent->width;
02204     pldis.height = configEvent->height;
02205 
02206 // Only need to resize if size is actually changed
02207 
02208     if ( pldis.width == dev->width && pldis.height == dev->height )
02209         return;
02210 
02211     pldebug( "ResizeEH",
02212         "x = %d, y = %d, pending = %d\n",
02213         configEvent->width, configEvent->height, XPending( xwd->display ) );
02214 
02215 // Handle resize
02216 
02217     ResizeCmd( pls, &pldis );
02218     if ( dev->drawing_xhairs )
02219     {
02220         UpdateXhairs( pls );
02221     }
02222 
02223 // Remove extraneous Expose and ConfigureNotify events from the event queue
02224 // Exposes do not need to be handled since we've redrawn the whole plot
02225 
02226     XFlush( xwd->display );
02227     while ( XCheckWindowEvent( xwd->display, dev->window,
02228                 ExposureMask | StructureNotifyMask, event ) )
02229         ;
02230 }
02231 
02232 //--------------------------------------------------------------------------
02233 // ExposeCmd()
02234 //
02235 // Event handler routine for expose events.
02236 // These are "pure" exposures (no resize), so don't need to clear window.
02237 //--------------------------------------------------------------------------
02238 
02239 static void
02240 ExposeCmd( PLStream *pls, PLDisplay *pldis )
02241 {
02242     XwDev     *dev = (XwDev *) pls->dev;
02243     XwDisplay *xwd = (XwDisplay *) dev->xwd;
02244     int       x, y, width, height;
02245 
02246     dbug_enter( "ExposeCmd" );
02247 
02248 // Return if plD_init_xw hasn't been called yet
02249 
02250     if ( dev == NULL )
02251     {
02252         plwarn( "ExposeCmd: Illegal call -- driver uninitialized" );
02253         return;
02254     }
02255 
02256 // Exposed area.  If unspecified, the entire window is used.
02257 
02258     if ( pldis == NULL )
02259     {
02260         x      = 0;
02261         y      = 0;
02262         width  = dev->width;
02263         height = dev->height;
02264     }
02265     else
02266     {
02267         x      = pldis->x;
02268         y      = pldis->y;
02269         width  = pldis->width;
02270         height = pldis->height;
02271     }
02272 
02273 // Usual case: refresh window from pixmap
02274 // DEBUG option: draws rectangle around refreshed region
02275 
02276     XSync( xwd->display, 0 );
02277     if ( dev->write_to_pixmap )
02278     {
02279         XCopyArea( xwd->display, dev->pixmap, dev->window, dev->gc,
02280             x, y, width, height, x, y );
02281         XSync( xwd->display, 0 );
02282 #ifdef DEBUG
02283         if ( pls->debug )
02284         {
02285             XPoint pts[5];
02286             int    x0 = x, x1 = x + width, y0 = y, y1 = y + height;
02287             pts[0].x = x0; pts[0].y = y0;
02288             pts[1].x = x1; pts[1].y = y0;
02289             pts[2].x = x1; pts[2].y = y1;
02290             pts[3].x = x0; pts[3].y = y1;
02291             pts[4].x = x0; pts[4].y = y0;
02292 
02293             XDrawLines( xwd->display, dev->window, dev->gc, pts, 5,
02294                 CoordModeOrigin );
02295         }
02296 #endif
02297     }
02298     else
02299     {
02300         plRemakePlot( pls );
02301         XFlush( xwd->display );
02302     }
02303 }
02304 
02305 //--------------------------------------------------------------------------
02306 // ResizeCmd()
02307 //
02308 // Event handler routine for resize events.
02309 //--------------------------------------------------------------------------
02310 
02311 static void
02312 ResizeCmd( PLStream *pls, PLDisplay *pldis )
02313 {
02314     XwDev     *dev            = (XwDev *) pls->dev;
02315     XwDisplay *xwd            = (XwDisplay *) dev->xwd;
02316     int       write_to_window = dev->write_to_window;
02317 
02318     dbug_enter( "ResizeCmd" );
02319 
02320 // Return if plD_init_xw hasn't been called yet
02321 
02322     if ( dev == NULL )
02323     {
02324         plwarn( "ResizeCmd: Illegal call -- driver uninitialized" );
02325         return;
02326     }
02327 
02328 // Return if pointer to window not specified.
02329 
02330     if ( pldis == NULL )
02331     {
02332         plwarn( "ResizeCmd: Illegal call -- window pointer uninitialized" );
02333         return;
02334     }
02335 
02336 // Reset current window bounds
02337 
02338     dev->width  = pldis->width;
02339     dev->height = pldis->height;
02340 
02341     dev->xscale = dev->width / (double) dev->init_width;
02342     dev->yscale = dev->height / (double) dev->init_height;
02343 
02344     dev->xscale = dev->xscale * dev->xscale_init;
02345     dev->yscale = dev->yscale * dev->yscale_init;
02346 
02347 #if PHYSICAL
02348     {
02349         PLFLT pxlx = DPMM / dev->xscale;
02350         PLFLT pxly = DPMM / dev->yscale;
02351         plP_setpxl( pxlx, pxly );
02352     }
02353 #endif
02354 
02355 // Note: the following order MUST be obeyed -- if you instead redraw into
02356 // the window and then copy it to the pixmap, off-screen parts of the window
02357 // may contain garbage which is then transferred to the pixmap (and thus
02358 // will not go away after an expose).
02359 //
02360 
02361 // Resize pixmap using new dimensions
02362 
02363     if ( dev->write_to_pixmap )
02364     {
02365         dev->write_to_window = 0;
02366         XFreePixmap( xwd->display, dev->pixmap );
02367         CreatePixmap( pls );
02368     }
02369 
02370 // This allows an external agent to take over the redraw
02371     if ( pls->ext_resize_draw )
02372         return;
02373 
02374 // Initialize & redraw (to pixmap, if available).
02375 
02376     if ( dev->write_to_pixmap )
02377     {
02378         XSetForeground( xwd->display, dev->gc, dev->bgcolor.pixel );
02379         XFillRectangle( xwd->display, dev->pixmap, dev->gc, 0, 0,
02380             dev->width, dev->height );
02381         XSetForeground( xwd->display, dev->gc, dev->curcolor.pixel );
02382     }
02383     if ( dev->write_to_window )
02384     {
02385         XClearWindow( xwd->display, dev->window );
02386     }
02387     plRemakePlot( pls );
02388     XSync( xwd->display, 0 );
02389 
02390 // If pixmap available, fake an expose
02391 
02392     if ( dev->write_to_pixmap )
02393     {
02394         dev->write_to_window = write_to_window;
02395         XCopyArea( xwd->display, dev->pixmap, dev->window, dev->gc, 0, 0,
02396             dev->width, dev->height, 0, 0 );
02397         XSync( xwd->display, 0 );
02398     }
02399 }
02400 
02401 //--------------------------------------------------------------------------
02402 // ConfigBufferingCmd()
02403 //
02404 // Allows a widget to manipulate the double buffering support in the
02405 // xwin dirver.
02406 //--------------------------------------------------------------------------
02407 
02408 static void ConfigBufferingCmd( PLStream *pls, PLBufferingCB *ptr )
02409 {
02410     XwDev *dev = (XwDev *) pls->dev;
02411 
02412     switch ( ptr->cmd )
02413     {
02414     case PLESC_DOUBLEBUFFERING_ENABLE:
02415         dev->write_to_window = 0;
02416         pls->db = 1;
02417         break;
02418 
02419     case PLESC_DOUBLEBUFFERING_DISABLE:
02420         dev->write_to_window = 1;
02421         pls->db = 0;
02422         break;
02423 
02424     case PLESC_DOUBLEBUFFERING_QUERY:
02425         ptr->result = pls->db;
02426         break;
02427 
02428     default:
02429         printf( "Unrecognized buffering request ignored.\n" );
02430         break;
02431     }
02432 }
02433 
02434 //--------------------------------------------------------------------------
02435 // RedrawCmd()
02436 //
02437 // Handles page redraw without resize (pixmap does not get reallocated).
02438 // Calling this makes sure all necessary housekeeping gets done.
02439 //--------------------------------------------------------------------------
02440 
02441 static void
02442 RedrawCmd( PLStream *pls )
02443 {
02444     XwDev     *dev            = (XwDev *) pls->dev;
02445     XwDisplay *xwd            = (XwDisplay *) dev->xwd;
02446     int       write_to_window = dev->write_to_window;
02447 
02448     dbug_enter( "RedrawCmd" );
02449 
02450 // Return if plD_init_xw hasn't been called yet
02451 
02452     if ( dev == NULL )
02453     {
02454         plwarn( "RedrawCmd: Illegal call -- driver uninitialized" );
02455         return;
02456     }
02457 
02458 // Initialize & redraw (to pixmap, if available).
02459 
02460     if ( dev->write_to_pixmap )
02461     {
02462         dev->write_to_window = 0;
02463         XSetForeground( xwd->display, dev->gc, dev->bgcolor.pixel );
02464         XFillRectangle( xwd->display, dev->pixmap, dev->gc, 0, 0,
02465             dev->width, dev->height );
02466         XSetForeground( xwd->display, dev->gc, dev->curcolor.pixel );
02467     }
02468     if ( dev->write_to_window )
02469     {
02470         XClearWindow( xwd->display, dev->window );
02471     }
02472     plRemakePlot( pls );
02473     XSync( xwd->display, 0 );
02474 
02475     dev->write_to_window = write_to_window;
02476 
02477 // If pixmap available, fake an expose
02478 
02479     if ( dev->write_to_pixmap )
02480     {
02481         XCopyArea( xwd->display, dev->pixmap, dev->window, dev->gc, 0, 0,
02482             dev->width, dev->height, 0, 0 );
02483         XSync( xwd->display, 0 );
02484     }
02485 }
02486 
02487 //--------------------------------------------------------------------------
02488 // CreatePixmapErrorHandler()
02489 //
02490 // Error handler used in CreatePixmap() to catch errors in allocating
02491 // storage for pixmap.  This way we can nicely substitute redraws for
02492 // pixmap copies if the server has insufficient memory.
02493 //--------------------------------------------------------------------------
02494 
02495 static unsigned char CreatePixmapStatus;
02496 
02497 static int
02498 CreatePixmapErrorHandler( Display *display, XErrorEvent *error )
02499 {
02500     CreatePixmapStatus = error->error_code;
02501     if ( error->error_code != BadAlloc )
02502     {
02503         char buffer[256];
02504         XGetErrorText( display, error->error_code, buffer, 256 );
02505         fprintf( stderr, "Error in XCreatePixmap: %s.\n", buffer );
02506     }
02507     return 1;
02508 }
02509 
02510 //--------------------------------------------------------------------------
02511 // CreatePixmap()
02512 //
02513 // This routine creates a pixmap, doing error trapping in case there
02514 // isn't enough memory on the server.
02515 //--------------------------------------------------------------------------
02516 
02517 static void
02518 CreatePixmap( PLStream *pls )
02519 {
02520     XwDev     *dev = (XwDev *) pls->dev;
02521     XwDisplay *xwd = (XwDisplay *) dev->xwd;
02522 
02523     int       ( *oldErrorHandler )();
02524 
02525     oldErrorHandler = XSetErrorHandler( CreatePixmapErrorHandler );
02526 
02527     CreatePixmapStatus = Success;
02528     pldebug( "CreatePixmap",
02529         "creating pixmap: width = %d, height = %d, depth = %d\n",
02530         dev->width, dev->height, xwd->depth );
02531 
02532     dev->pixmap = XCreatePixmap( xwd->display, dev->window,
02533         dev->width, dev->height, xwd->depth );
02534     XSync( xwd->display, 0 );
02535     if ( CreatePixmapStatus != Success )
02536     {
02537         dev->write_to_pixmap = 0;
02538         dev->write_to_window = 1;
02539         pls->db = 0;
02540         fprintf( stderr, "\n\
02541 Warning: pixmap could not be allocated (insufficient memory on server).\n\
02542 Driver will redraw the entire plot to handle expose events.\n" );
02543     }
02544 
02545     XSetErrorHandler( oldErrorHandler );
02546 }
02547 
02548 //--------------------------------------------------------------------------
02549 // GetVisual()
02550 //
02551 // Get visual info.  In order to safely use a visual other than that of
02552 // the parent (which hopefully is that returned by DefaultVisual), you
02553 // must first find (using XGetRGBColormaps) or create a colormap matching
02554 // this visual and then set the colormap window attribute in the
02555 // XCreateWindow attributes and valuemask arguments.  I don't do this
02556 // right now, so this is turned off by default.
02557 //--------------------------------------------------------------------------
02558 
02559 static void
02560 GetVisual( PLStream *pls )
02561 {
02562     XwDev     *dev            = (XwDev *) pls->dev;
02563     XwDisplay *xwd            = (XwDisplay *) dev->xwd;
02564     int       visuals_matched = 0;
02565 
02566     dbug_enter( "GetVisual" );
02567 
02568     if ( !defaultvisual )
02569     {
02570         XVisualInfo vTemplate, *visualList;
02571 
02572 // Try for an 8 plane display, if unavailable go for the default
02573 
02574         vTemplate.screen = xwd->screen;
02575         vTemplate.depth  = 8;
02576 
02577         visualList = XGetVisualInfo( xwd->display,
02578             VisualScreenMask | VisualDepthMask,
02579             &vTemplate, &visuals_matched );
02580 
02581 #ifdef HACK_STATICCOLOR
02582         if ( visuals_matched )
02583         {
02584             int i, found = 0;
02585             printf( "visuals_matched = %d\n", visuals_matched );
02586             for ( i = 0; i < visuals_matched && !found; i++ )
02587             {
02588                 Visual *v = visualList[i].visual;
02589                 printf( "Checking visual %d: ", i );
02590                 switch ( v->class )
02591                 {
02592                 case PseudoColor:
02593                     printf( "PseudoColor\n" );
02594                     break;
02595                 case GrayScale:
02596                     printf( "GrayScale\n" );
02597                     break;
02598                 case DirectColor:
02599                     printf( "DirectColor\n" );
02600                     break;
02601                 case TrueColor:
02602                     printf( "TrueColor\n" );
02603                     break;
02604                 case StaticColor:
02605                     printf( "StaticColor\n" );
02606                     break;
02607                 case StaticGray:
02608                     printf( "StaticGray\n" );
02609                     break;
02610                 default:
02611                     printf( "Unknown.\n" );
02612                     break;
02613                 }
02614                 if ( v->class == StaticColor )
02615                 {
02616                     xwd->visual = v;
02617                     xwd->depth  = visualList[i].depth;
02618                     found       = 1;
02619                 }
02620             }
02621             if ( !found )
02622             {
02623                 plexit( "Unable to get a StaticColor visual." );
02624             }
02625             printf( "Found StaticColor visual, depth=%d\n", xwd->depth );
02626         }
02627 #else
02628         if ( visuals_matched )
02629         {
02630             xwd->visual = visualList->visual;   // Choose first match.
02631             xwd->depth  = vTemplate.depth;
02632         }
02633 #endif  // HACK_STATICCOLOR
02634     }
02635 
02636     if ( !visuals_matched )
02637     {
02638         xwd->visual = DefaultVisual( xwd->display, xwd->screen );
02639         xwd->depth  = DefaultDepth( xwd->display, xwd->screen );
02640     }
02641 
02642 // Check to see if we expect to be able to allocate r/w color cells.
02643 
02644     switch ( xwd->visual->class )
02645     {
02646     case TrueColor:
02647     case StaticColor:
02648     case StaticGray:
02649         xwd->rw_cmap = 0;
02650         break;
02651     default:
02652         xwd->rw_cmap = 1;
02653     }
02654 
02655 /*xwd->rw_cmap = 0;*/ /* debugging hack. */
02656 
02657 // Just for kicks, see what kind of visual we got.
02658 
02659     if ( pls->verbose )
02660     {
02661         fprintf( stderr, "XVisual class == " );
02662         switch ( xwd->visual->class )
02663         {
02664         case PseudoColor:
02665             fprintf( stderr, "PseudoColor\n" );
02666             break;
02667         case GrayScale:
02668             fprintf( stderr, "GrayScale\n" );
02669             break;
02670         case DirectColor:
02671             fprintf( stderr, "DirectColor\n" );
02672             break;
02673         case TrueColor:
02674             fprintf( stderr, "TrueColor\n" );
02675             break;
02676         case StaticColor:
02677             fprintf( stderr, "StaticColor\n" );
02678             break;
02679         case StaticGray:
02680             fprintf( stderr, "StaticGray\n" );
02681             break;
02682         default:
02683             fprintf( stderr, "Unknown.\n" );
02684             break;
02685         }
02686         fprintf( stderr, "xwd->rw_cmap = %d\n", xwd->rw_cmap );
02687     }
02688 }
02689 
02690 //--------------------------------------------------------------------------
02691 // AllocBGFG()
02692 //
02693 // Allocate background & foreground colors.  If possible, I choose pixel
02694 // values such that the fg pixel is the xor of the bg pixel, to make
02695 // rubber-banding easy to see.
02696 //--------------------------------------------------------------------------
02697 
02698 static void
02699 AllocBGFG( PLStream *pls )
02700 {
02701     XwDev         *dev = (XwDev *) pls->dev;
02702     XwDisplay     *xwd = (XwDisplay *) dev->xwd;
02703 
02704     int           i, j, npixels;
02705     unsigned long plane_masks[1], pixels[RWMAP_MAX_COLORS];
02706 
02707     dbug_enter( "AllocBGFG" );
02708 
02709 // If not on a color system, just return
02710     if ( !xwd->color )
02711         return;
02712 
02713     if ( xwd->rw_cmap &&
02714          // r/w color maps
02715          XAllocColorCells( xwd->display, xwd->map, False,
02716              plane_masks, 0, pixels, 1 ) )
02717     {
02718         // background
02719         xwd->cmap0[0].pixel = pixels[0];
02720     }
02721     else
02722     {
02723         // r/o color maps
02724         xwd->cmap0[0].pixel = BlackPixel( xwd->display, xwd->screen );
02725         xwd->fgcolor.pixel  = WhitePixel( xwd->display, xwd->screen );
02726         if ( xwd->rw_cmap && pls->verbose )
02727             fprintf( stderr, "Downgrading to r/o cmap.\n" );
02728         xwd->rw_cmap = 0;
02729         return;
02730     }
02731 
02732 // Allocate as many colors as we can
02733 
02734     npixels = RWMAP_MAX_COLORS;
02735     for (;; )
02736     {
02737         if ( XAllocColorCells( xwd->display, xwd->map, False,
02738                  plane_masks, 0, pixels, npixels ) )
02739             break;
02740         npixels--;
02741         if ( npixels == 0 )
02742             break;
02743     }
02744 
02745 // Find the color with pixel = xor of the bg color pixel.
02746 // If a match isn't found, the last pixel allocated is used.
02747 
02748     for ( i = 0; i < npixels - 1; i++ )
02749     {
02750         if ( pixels[i] == ( ~xwd->cmap0[0].pixel & 0xFF ) )
02751             break;
02752     }
02753 
02754 // Use this color cell for our foreground color.  Then free the rest.
02755 
02756     xwd->fgcolor.pixel = pixels[i];
02757     for ( j = 0; j < npixels; j++ )
02758     {
02759         if ( j != i )
02760             XFreeColors( xwd->display, xwd->map, &pixels[j], 1, 0 );
02761     }
02762 }
02763 
02764 //--------------------------------------------------------------------------
02765 // SetBGFG()
02766 //
02767 // Set background & foreground colors.  Foreground over background should
02768 // have high contrast.
02769 //--------------------------------------------------------------------------
02770 
02771 static void
02772 SetBGFG( PLStream *pls )
02773 {
02774     XwDev     *dev = (XwDev *) pls->dev;
02775     XwDisplay *xwd = (XwDisplay *) dev->xwd;
02776 
02777     PLColor   fgcolor;
02778     int       gslevbg, gslevfg;
02779 
02780     dbug_enter( "SetBGFG" );
02781 
02782 //
02783 // Set background color.
02784 //
02785 // Background defaults to black on color screens, white on grayscale (many
02786 // grayscale monitors have poor contrast, and black-on-white looks better).
02787 //
02788 
02789     if ( !xwd->color )
02790     {
02791         pls->cmap0[0].r = pls->cmap0[0].g = pls->cmap0[0].b = 0xFF;
02792     }
02793     gslevbg = ( (long) pls->cmap0[0].r +
02794                 (long) pls->cmap0[0].g +
02795                 (long) pls->cmap0[0].b ) / 3;
02796 
02797     PLColor_to_XColor( &pls->cmap0[0], &xwd->cmap0[0] );
02798 
02799 //
02800 // Set foreground color.
02801 //
02802 // Used for grayscale output, since otherwise the plots can become nearly
02803 // unreadable (i.e. if colors get mapped onto grayscale values).  In this
02804 // case it becomes the grayscale level for all draws, and is taken to be
02805 // black if the background is light, and white if the background is dark.
02806 // Note that white/black allocations never fail.
02807 //
02808 
02809     if ( gslevbg > 0x7F )
02810         gslevfg = 0;
02811     else
02812         gslevfg = 0xFF;
02813 
02814     fgcolor.r = fgcolor.g = fgcolor.b = gslevfg;
02815 
02816     PLColor_to_XColor( &fgcolor, &xwd->fgcolor );
02817 
02818 // Now store
02819 
02820     if ( xwd->rw_cmap && xwd->color )
02821     {
02822         XStoreColor( xwd->display, xwd->map, &xwd->fgcolor );
02823         XStoreColor( xwd->display, xwd->map, &xwd->cmap0[0] );
02824     }
02825     else
02826     {
02827         XAllocColor( xwd->display, xwd->map, &xwd->cmap0[0] );
02828         XAllocColor( xwd->display, xwd->map, &xwd->fgcolor );
02829     }
02830 }
02831 
02832 //--------------------------------------------------------------------------
02833 // InitColors()
02834 //
02835 // Does all color initialization.
02836 //--------------------------------------------------------------------------
02837 
02838 static void
02839 InitColors( PLStream *pls )
02840 {
02841     XwDev     *dev = (XwDev *) pls->dev;
02842     XwDisplay *xwd = (XwDisplay *) dev->xwd;
02843 
02844     dbug_enter( "InitColors" );
02845 
02846 // Allocate and initialize color maps.
02847 // Defer cmap1 allocation until it's actually used
02848 
02849     if ( xwd->color )
02850     {
02851         if ( plplot_ccmap )
02852         {
02853             AllocCustomMap( pls );
02854         }
02855         else
02856         {
02857             AllocCmap0( pls );
02858         }
02859     }
02860 }
02861 
02862 //--------------------------------------------------------------------------
02863 // AllocCustomMap()
02864 //
02865 // Initializes custom color map and all the cruft that goes with it.
02866 //
02867 // Assuming all color X displays do 256 colors, the breakdown is as follows:
02868 //
02869 // CCMAP_XWM_COLORS
02870 //      Number of low "pixel" values to copy.  These are typically allocated
02871 //      first, thus are in use by the window manager. I copy them to reduce
02872 //      flicker.
02873 //
02874 //
02875 // RWMAP_CMAP1_COLORS
02876 //      Color map 1 entries.  There should be as many as practical available
02877 //      for smooth shading.  On the order of 50-100 is pretty reasonable.  You
02878 //      don't really need all 256, especially if all you're going to do is to
02879 //      print it to postscript (which doesn't have any intrinsic limitation on
02880 //      the number of colors).
02881 //
02882 // It's important to leave some extra colors unallocated for Tk.  In
02883 // particular the palette tools require a fair amount.  I recommend leaving
02884 // at least 40 or so free.
02885 //--------------------------------------------------------------------------
02886 
02887 static void
02888 AllocCustomMap( PLStream *pls )
02889 {
02890     XwDev         *dev = (XwDev *) pls->dev;
02891     XwDisplay     *xwd = (XwDisplay *) dev->xwd;
02892 
02893     XColor        xwm_colors[RWMAP_MAX_COLORS];
02894     int           i, npixels;
02895     unsigned long plane_masks[1], pixels[RWMAP_MAX_COLORS];
02896 
02897     dbug_enter( "AllocCustomMap" );
02898 
02899 // Determine current default colors
02900 
02901     for ( i = 0; i < RWMAP_MAX_COLORS; i++ )
02902     {
02903         xwm_colors[i].pixel = i;
02904     }
02905     XQueryColors( xwd->display, xwd->map, xwm_colors, RWMAP_MAX_COLORS );
02906 
02907 // Allocate cmap0 colors in the default colormap.
02908 // The custom cmap0 colors are later stored at the same pixel values.
02909 // This is a really cool trick to reduce the flicker when changing colormaps.
02910 //
02911 
02912     AllocCmap0( pls );
02913     XAllocColor( xwd->display, xwd->map, &xwd->fgcolor );
02914 
02915 // Create new color map
02916 
02917     xwd->map = XCreateColormap( xwd->display, DefaultRootWindow( xwd->display ),
02918         xwd->visual, AllocNone );
02919 
02920 // Now allocate all colors so we can fill the ones we want to copy
02921 
02922     npixels = RWMAP_MAX_COLORS;
02923     for (;; )
02924     {
02925         if ( XAllocColorCells( xwd->display, xwd->map, False,
02926                  plane_masks, 0, pixels, npixels ) )
02927             break;
02928         npixels--;
02929         if ( npixels == 0 )
02930             plexit( "couldn't allocate any colors" );
02931     }
02932 
02933 // Fill the low colors since those are in use by the window manager
02934 
02935     for ( i = 0; i < CCMAP_XWM_COLORS; i++ )
02936     {
02937         XStoreColor( xwd->display, xwd->map, &xwm_colors[i] );
02938         pixels[xwm_colors[i].pixel] = 0;
02939     }
02940 
02941 // Fill the ones we will use in cmap0
02942 
02943     for ( i = 0; i < xwd->ncol0; i++ )
02944     {
02945         XStoreColor( xwd->display, xwd->map, &xwd->cmap0[i] );
02946         pixels[xwd->cmap0[i].pixel] = 0;
02947     }
02948 
02949 // Finally, if the colormap was saved by an external agent, see if there are
02950 // any differences from the current default map and save those!  A very cool
02951 // (or sick, depending on how you look at it) trick to get over some X and
02952 // Tk limitations.
02953 //
02954 
02955     if ( sxwm_colors_set )
02956     {
02957         for ( i = 0; i < RWMAP_MAX_COLORS; i++ )
02958         {
02959             if ( ( xwm_colors[i].red != sxwm_colors[i].red ) ||
02960                  ( xwm_colors[i].green != sxwm_colors[i].green ) ||
02961                  ( xwm_colors[i].blue != sxwm_colors[i].blue ) )
02962             {
02963                 if ( pixels[i] != 0 )
02964                 {
02965                     XStoreColor( xwd->display, xwd->map, &xwm_colors[i] );
02966                     pixels[i] = 0;
02967                 }
02968             }
02969         }
02970     }
02971 
02972 // Now free the ones we're not interested in
02973 
02974     for ( i = 0; i < npixels; i++ )
02975     {
02976         if ( pixels[i] != 0 )
02977             XFreeColors( xwd->display, xwd->map, &pixels[i], 1, 0 );
02978     }
02979 
02980 // Allocate colors in cmap 1
02981 
02982     AllocCmap1( pls );
02983 }
02984 
02985 //--------------------------------------------------------------------------
02986 // AllocCmap0()
02987 //
02988 // Allocate & initialize cmap0 entries.
02989 //--------------------------------------------------------------------------
02990 
02991 static void
02992 AllocCmap0( PLStream *pls )
02993 {
02994     XwDev     *dev = (XwDev *) pls->dev;
02995     XwDisplay *xwd = (XwDisplay *) dev->xwd;
02996     int       i;
02997 
02998     dbug_enter( "AllocCmap0" );
02999 
03000 // Free all previous colors.  This should work for both rw & ro colormaps
03001     for ( i = 1; i < xwd->ncol0; i++ )
03002     {
03003         unsigned long pixel = xwd->cmap0[i].pixel;
03004         XFreeColors( xwd->display, xwd->map, &pixel, 1, 0 );
03005     }
03006 
03007 // If the number of colors increased, need to allocate enough space for them
03008     if ( pls->ncol0 > xwd->ncol0_alloc )
03009     {
03010         xwd->ncol0_alloc = pls->ncol0;
03011         xwd->cmap0       = (XColor *)
03012                            realloc( xwd->cmap0, (size_t) pls->ncol0 * sizeof ( XColor ) );
03013         if ( xwd->cmap0 == 0 )
03014             plexit( "couldn't allocate space for cmap0 colors" );
03015     }
03016 
03017     if ( xwd->rw_cmap )
03018     {
03019         int           npixels;
03020         unsigned long plane_masks[1], pixels[RWMAP_MAX_COLORS];
03021 
03022         // Allocate and assign colors in cmap 0
03023 
03024         npixels = pls->ncol0 - 1;
03025         for (;; )
03026         {
03027             if ( XAllocColorCells( xwd->display, xwd->map, False,
03028                      plane_masks, 0, &pixels[1], npixels ) )
03029                 break;
03030             npixels--;
03031             if ( npixels == 0 )
03032                 plexit( "couldn't allocate any colors" );
03033         }
03034 
03035         xwd->ncol0 = npixels + 1;
03036         for ( i = 1; i < xwd->ncol0; i++ )
03037         {
03038             xwd->cmap0[i].pixel = pixels[i];
03039         }
03040 
03041         StoreCmap0( pls );
03042     }
03043     else
03044     {
03045         if ( pls->verbose )
03046             fprintf( stderr, "Attempting to allocate r/o colors in cmap0.\n" );
03047 
03048         for ( i = 1; i < pls->ncol0; i++ )
03049         {
03050             int    r;
03051             XColor c;
03052             PLColor_to_XColor( &pls->cmap0[i], &c );
03053             r = XAllocColor( xwd->display, xwd->map, &c );
03054             if ( pls->verbose )
03055                 fprintf( stderr, "i=%d, r=%d, pixel=%d\n", i, r, (int) c.pixel );
03056             if ( r )
03057             {
03058                 xwd->cmap0[i]       = c;
03059                 xwd->cmap0[i].pixel = c.pixel; // needed for deallocation
03060             }
03061             else
03062             {
03063                 XColor screen_def, exact_def;
03064 
03065                 if ( pls->verbose )
03066                     fprintf( stderr,
03067                         "color alloc failed, trying by name: %s.\n",
03068                         pls->cmap0[i].name );
03069 
03070                 // Hmm, didn't work, try another approach.
03071                 r = XAllocNamedColor( xwd->display, xwd->map,
03072                     pls->cmap0[i].name,
03073                     &screen_def, &exact_def );
03074 
03075 //                 xwd->cmap0[i] = screen_def;
03076 
03077                 if ( r )
03078                 {
03079                     if ( pls->verbose )
03080                         fprintf( stderr, "yes, got a color by name.\n" );
03081 
03082                     xwd->cmap0[i]       = screen_def;
03083                     xwd->cmap0[i].pixel = screen_def.pixel;
03084                 }
03085                 else
03086                 {
03087                     r = XAllocNamedColor( xwd->display, xwd->map,
03088                         "white",
03089                         &screen_def, &exact_def );
03090                     if ( r )
03091                     {
03092                         xwd->cmap0[i]       = screen_def;
03093                         xwd->cmap0[i].pixel = screen_def.pixel;
03094                     }
03095                     else
03096                         printf( "Can't find white?! Giving up...\n" );
03097                 }
03098             }
03099         }
03100         xwd->ncol0 = i;
03101 
03102         if ( pls->verbose )
03103             fprintf( stderr, "Allocated %d colors in cmap0.\n", xwd->ncol0 );
03104     }
03105 }
03106 
03107 //--------------------------------------------------------------------------
03108 // AllocCmap1()
03109 //
03110 // Allocate & initialize cmap1 entries.
03111 //--------------------------------------------------------------------------
03112 
03113 static void
03114 AllocCmap1( PLStream *pls )
03115 {
03116     XwDev         *dev = (XwDev *) pls->dev;
03117     XwDisplay     *xwd = (XwDisplay *) dev->xwd;
03118 
03119     int           i, j, npixels;
03120     unsigned long plane_masks[1], pixels[RWMAP_MAX_COLORS];
03121 
03122     dbug_enter( "AllocCmap1" );
03123 
03124     if ( xwd->rw_cmap )
03125     {
03126         if ( pls->verbose )
03127             fprintf( stderr, "Attempting to allocate r/w colors in cmap1.\n" );
03128 
03129         // If using the default color map, must severely limit number of colors
03130         // otherwise TK won't have enough.
03131 
03132         npixels = MAX( 2, MIN( RWMAP_CMAP1_COLORS, pls->ncol1 ) );
03133         for (;; )
03134         {
03135             if ( XAllocColorCells( xwd->display, xwd->map, False,
03136                      plane_masks, 0, pixels, npixels ) )
03137                 break;
03138             npixels--;
03139             if ( npixels == 0 )
03140                 break;
03141         }
03142 
03143         if ( npixels < 2 )
03144         {
03145             xwd->ncol1 = -1;
03146             fprintf( stderr, "Warning: unable to allocate sufficient colors in cmap1.\n" );
03147             return;
03148         }
03149 
03150         xwd->ncol1 = npixels;
03151         if ( pls->verbose )
03152             fprintf( stderr, "AllocCmap1 (xwin.c): Allocated %d colors in cmap1.\n", npixels );
03153 
03154         // Allocate space if it hasn't been done yet
03155         if ( !xwd->cmap1 )
03156         {
03157             xwd->ncol1_alloc = xwd->ncol1;
03158             xwd->cmap1       = (XColor *) calloc( xwd->ncol1, (size_t) sizeof ( XColor ) );
03159             if ( !xwd->cmap1 )
03160                 plexit( "couldn't allocate space for cmap1 colors" );
03161         }
03162 
03163         // Don't assign pixels sequentially, to avoid strange problems with xor
03164         // GC's.  Skipping by 2 seems to do the job best.
03165 
03166         for ( j = i = 0; i < xwd->ncol1; i++ )
03167         {
03168             while ( pixels[j] == 0 )
03169                 j++;
03170 
03171             xwd->cmap1[i].pixel = pixels[j];
03172             pixels[j]           = 0;
03173 
03174             j += 2;
03175             if ( j >= xwd->ncol1 )
03176                 j = 0;
03177         }
03178 
03179         StoreCmap1( pls );
03180     }
03181     else
03182     {
03183         int     i, r, ncolors;
03184         PLColor cmap1color;
03185         XColor  xcol;
03186 
03187         if ( pls->verbose )
03188             fprintf( stderr, "Attempting to allocate r/o colors in cmap1.\n" );
03189 
03190         switch ( xwd->visual->class )
03191         {
03192         case TrueColor:
03193             ncolors = TC_CMAP1_COLORS;
03194             break;
03195         default:
03196             ncolors = ROMAP_CMAP1_COLORS;
03197         }
03198 
03199         // Allocate space if it hasn't been done yet
03200         if ( !xwd->cmap1 )
03201         {
03202             xwd->ncol1_alloc = ncolors;
03203             xwd->cmap1       = (XColor *) calloc( ncolors, (size_t) sizeof ( XColor ) );
03204             if ( !xwd->cmap1 )
03205                 plexit( "couldn't allocate space for cmap1 colors" );
03206         }
03207 
03208         for ( i = 0; i < ncolors; i++ )
03209         {
03210             plcol_interp( pls, &cmap1color, i, ncolors );
03211             PLColor_to_XColor( &cmap1color, &xcol );
03212 
03213             r = XAllocColor( xwd->display, xwd->map, &xcol );
03214             if ( pls->verbose )
03215                 fprintf( stderr, "i=%d, r=%d, pixel=%d\n", i, r, (int) xcol.pixel );
03216             if ( r )
03217                 xwd->cmap1[i] = xcol;
03218             else
03219                 break;
03220         }
03221         if ( i < ncolors )
03222         {
03223             xwd->ncol1 = -1;
03224             fprintf( stderr,
03225                 "Warning: unable to allocate sufficient colors in cmap1\n" );
03226             return;
03227         }
03228         else
03229         {
03230             xwd->ncol1 = ncolors;
03231             if ( pls->verbose )
03232                 fprintf( stderr, "AllocCmap1 (xwin.c): Allocated %d colors in cmap1\n", ncolors );
03233         }
03234     }
03235 }
03236 
03237 //--------------------------------------------------------------------------
03238 // StoreCmap0()
03239 //
03240 // Stores cmap 0 entries in X-server colormap.
03241 //--------------------------------------------------------------------------
03242 
03243 static void
03244 StoreCmap0( PLStream *pls )
03245 {
03246     XwDev     *dev = (XwDev *) pls->dev;
03247     XwDisplay *xwd = (XwDisplay *) dev->xwd;
03248     int       i;
03249 
03250     if ( !xwd->color )
03251         return;
03252 
03253     for ( i = 1; i < xwd->ncol0; i++ )
03254     {
03255         PLColor_to_XColor( &pls->cmap0[i], &xwd->cmap0[i] );
03256         if ( xwd->rw_cmap )
03257             XStoreColor( xwd->display, xwd->map, &xwd->cmap0[i] );
03258         else
03259             XAllocColor( xwd->display, xwd->map, &xwd->cmap0[i] );
03260     }
03261 }
03262 
03263 //--------------------------------------------------------------------------
03264 // StoreCmap1()
03265 //
03266 // Stores cmap 1 entries in X-server colormap.
03267 //--------------------------------------------------------------------------
03268 
03269 static void
03270 StoreCmap1( PLStream *pls )
03271 {
03272     XwDev     *dev = (XwDev *) pls->dev;
03273     XwDisplay *xwd = (XwDisplay *) dev->xwd;
03274 
03275     PLColor   cmap1color;
03276     int       i;
03277 
03278     if ( !xwd->color )
03279         return;
03280 
03281     for ( i = 0; i < xwd->ncol1; i++ )
03282     {
03283         plcol_interp( pls, &cmap1color, i, xwd->ncol1 );
03284         PLColor_to_XColor( &cmap1color, &xwd->cmap1[i] );
03285         if ( xwd->rw_cmap )
03286             XStoreColor( xwd->display, xwd->map, &xwd->cmap1[i] );
03287         else
03288             XAllocColor( xwd->display, xwd->map, &xwd->cmap1[i] );
03289     }
03290 }
03291 
03292 //--------------------------------------------------------------------------
03293 // PLColor_to_XColor()
03294 //
03295 // Copies the supplied PLColor to an XColor, padding with bits as necessary
03296 // (a PLColor uses 8 bits for color storage, while an XColor uses 16 bits).
03297 // The argument types follow the same order as in the function name.
03298 //--------------------------------------------------------------------------
03299 
03300 #define ToXColor( a )     ( ( ( 0xFF & ( a ) ) << 8 ) | ( a ) )
03301 #define ToPLColor( a )    ( ( (U_LONG) a ) >> 8 )
03302 
03303 static void
03304 PLColor_to_XColor( PLColor *plcolor, XColor *xcolor )
03305 {
03306     xcolor->red   = ToXColor( plcolor->r );
03307     xcolor->green = ToXColor( plcolor->g );
03308     xcolor->blue  = ToXColor( plcolor->b );
03309     xcolor->flags = DoRed | DoGreen | DoBlue;
03310 }
03311 
03312 //--------------------------------------------------------------------------
03313 // PLColor_from_XColor()
03314 //
03315 // Copies the supplied XColor to a PLColor, stripping off bits as
03316 // necessary.  See the previous routine for more info.
03317 //--------------------------------------------------------------------------
03318 
03319 static void
03320 PLColor_from_XColor( PLColor *plcolor, XColor *xcolor )
03321 {
03322     plcolor->r = ToPLColor( xcolor->red );
03323     plcolor->g = ToPLColor( xcolor->green );
03324     plcolor->b = ToPLColor( xcolor->blue );
03325 }
03326 
03327 //--------------------------------------------------------------------------
03328 // AreWeGrayscale(Display *display)
03329 //
03330 // Determines if we're using a monochrome or grayscale device.
03331 // gmf 11-8-91; Courtesy of Paul Martz of Evans and Sutherland.
03332 // Altered Andrew Ross 26-01-2004 to fix memory leak.
03333 //--------------------------------------------------------------------------
03334 
03335 static int
03336 AreWeGrayscale( Display *display )
03337 {
03338 #if defined ( __cplusplus ) || defined ( c_plusplus )
03339 #define THING    c_class
03340 #else
03341 #define THING    class
03342 #endif
03343 
03344     XVisualInfo *visuals;
03345     int         nitems, i, igray;
03346 
03347     // get a list of info on the visuals available
03348     visuals = XGetVisualInfo( display, 0, NULL, &nitems );
03349 
03350     igray = 1;
03351     // check the list looking for non-monochrome visual classes
03352     for ( i = 0; i < nitems; i++ )
03353         if ( ( visuals[i].THING != GrayScale ) &&
03354              ( visuals[i].THING != StaticGray ) )
03355         {
03356             igray = 0;
03357             break;
03358         }
03359 
03360     XFree( visuals );
03361     // if igray = 1 only StaticGray and GrayScale classes available
03362     return igray;
03363 }
03364 
03365 #ifdef DUMMY
03366 //--------------------------------------------------------------------------
03367 // SaveColormap()  **** DUMMY, NOT USED ANYMORE ***
03368 //
03369 // Saves RGB components of given colormap.
03370 // Used in an ugly hack to get past some X11R5 and TK limitations.
03371 // This isn't guaranteed to work under all circumstances, but hopefully
03372 // in the future there will be a nicer way to accomplish the same thing.
03373 //
03374 // Note: I tried using XCopyColormapAndFree to do the same thing, but under
03375 // HPUX 9.01/VUE/X11R5 at least it doesn't preserve the previous read-only
03376 // color cell allocations made by Tk.  Is this a bug?  Have to look at the
03377 // source to find out.
03378 //--------------------------------------------------------------------------
03379 
03380 static void
03381 SaveColormap( Display *display, Colormap colormap )
03382 {
03383     int i;
03384 
03385     if ( !plplot_ccmap )
03386         return;
03387 
03388     sxwm_colors_set = 1;
03389     for ( i = 0; i < RWMAP_MAX_COLORS; i++ )
03390     {
03391         sxwm_colors[i].pixel = i;
03392     }
03393     XQueryColors( display, colormap, sxwm_colors, RWMAP_MAX_COLORS );
03394 //
03395 //  printf("\nAt startup, default colors are: \n\n");
03396 //  for (i = 0; i < RWMAP_MAX_COLORS; i++) {
03397 //      printf(" i: %d,  pixel: %d,  r: %d,  g: %d,  b: %d\n",
03398 //             i, sxwm_colors[i].pixel,
03399 //             sxwm_colors[i].red, sxwm_colors[i].green, sxwm_colors[i].blue);
03400 //  }
03401 //
03402 }
03403 #endif
03404 
03405 //--------------------------------------------------------------------------
03406 // GetImageErrorHandler()
03407 //
03408 // Error handler used in XGetImage() to catch errors when pixmap or window
03409 // are not completely viewable.
03410 //--------------------------------------------------------------------------
03411 
03412 static int
03413 GetImageErrorHandler( Display *display, XErrorEvent *error )
03414 {
03415     if ( error->error_code != BadMatch )
03416     {
03417         char buffer[256];
03418         XGetErrorText( display, error->error_code, buffer, 256 );
03419         fprintf( stderr, "xwin: Error in XGetImage: %s.\n", buffer );
03420     }
03421     return 1;
03422 }
03423 
03424 //--------------------------------------------------------------------------
03425 // DrawImage()
03426 //
03427 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
03428 // Only solid color fill supported.
03429 //--------------------------------------------------------------------------
03430 
03431 static void
03432 DrawImage( PLStream *pls )
03433 {
03434     XwDev     *dev  = (XwDev *) pls->dev;
03435     XwDisplay *xwd  = (XwDisplay *) dev->xwd;
03436     XImage    *ximg = NULL;
03437     XColor    curcolor;
03438     PLINT     xmin, xmax, ymin, ymax, icol1;
03439 
03440     int       ( *oldErrorHandler )();
03441 
03442     float     mlr, mtb;
03443     float     blt, brt, brb, blb;
03444     float     left, right;
03445     int       kx, ky;
03446     int       nx, ny, ix, iy;
03447     int       i, corners[4], r[4];
03448 
03449     struct
03450     {
03451         float x, y;
03452     } Ppts[4];
03453 
03454     CheckForEvents( pls );
03455 
03456     xmin = dev->xscale * pls->imclxmin;
03457     xmax = dev->xscale * pls->imclxmax;
03458     ymin = dev->yscale * pls->imclymin;
03459     ymax = dev->yscale * pls->imclymax;
03460 
03461     nx = pls->dev_nptsX;
03462     ny = pls->dev_nptsY;
03463 
03464 // XGetImage() call fails if either the pixmap or window is not fully viewable!
03465     oldErrorHandler = XSetErrorHandler( GetImageErrorHandler );
03466 
03467     XFlush( xwd->display );
03468     if ( dev->write_to_pixmap )
03469         ximg = XGetImage( xwd->display, dev->pixmap, 0, 0, dev->width, dev->height,
03470             AllPlanes, ZPixmap );
03471 
03472     if ( dev->write_to_window )
03473         ximg = XGetImage( xwd->display, dev->window, 0, 0, dev->width, dev->height,
03474             AllPlanes, ZPixmap );
03475 
03476     XSetErrorHandler( oldErrorHandler );
03477 
03478     if ( ximg == NULL )
03479     {
03480         plabort( "Can't get image, the window must be partly off-screen, move it to fit screen" );
03481         return;
03482     }
03483 
03484     if ( xwd->ncol1 == 0 )
03485         AllocCmap1( pls );
03486     if ( xwd->ncol1 < 2 )
03487         return;
03488 
03489 // translate array for rotation
03490     switch ( (int) ( pls->diorot - 4. * floor( pls->diorot / 4. ) ) )
03491     {
03492     case 0:
03493         r[0] = 0; r[1] = 1; r[2] = 2; r[3] = 3; break;
03494     case 1:
03495         r[0] = 1; r[1] = 2; r[2] = 3; r[3] = 0; break;
03496     case 2:
03497         r[0] = 2; r[1] = 3; r[2] = 0; r[3] = 1; break;
03498     case 3:
03499         r[0] = 3; r[1] = 0; r[2] = 1; r[3] = 2;
03500     }
03501 
03502     // after rotation and coordinate translation, each fill
03503     // lozangue will have coordinates (Ppts), slopes (m...)
03504     // and y intercepts (b...):
03505     //
03506     //        Ppts[3]
03507     //          **
03508     // mlr,blt *  * mtb,brt
03509     //        *    *
03510     //Ppts[0]<      > Ppts[2]
03511     //        *    *
03512     // mtb,blt *  * mlr,brb
03513     //          **
03514     //        Ppts[1]
03515     //
03516 
03517 // slope of left/right and top/bottom edges
03518     mlr = ( dev->yscale * ( pls->dev_iy[1] - pls->dev_iy[0] ) ) /
03519           ( dev->xscale * ( pls->dev_ix[1] - pls->dev_ix[0] ) );
03520 
03521     mtb = ( dev->yscale * ( pls->dev_iy[ny] - pls->dev_iy[0] ) ) /
03522           ( dev->xscale * ( pls->dev_ix[ny] - pls->dev_ix[0] ) );
03523 
03524     for ( ix = 0; ix < nx - 1; ix++ )
03525     {
03526         for ( iy = 0; iy < ny - 1; iy++ )
03527         {
03528             corners[0] = ix * ny + iy;             // [ix][iy]
03529             corners[1] = ( ix + 1 ) * ny + iy;     // [ix+1][iy]
03530             corners[2] = ( ix + 1 ) * ny + iy + 1; // [ix+1][iy+1]
03531             corners[3] = ix * ny + iy + 1;         // [ix][iy+1]
03532 
03533             for ( i = 0; i < 4; i++ )
03534             {
03535                 Ppts[i].x = dev->xscale * ( pls->dev_ix[corners[r[i]]] );
03536                 Ppts[i].y = dev->yscale * ( pls->dev_iy[corners[r[i]]] );
03537             }
03538 
03539             // if any corner is inside the draw area
03540             if ( Ppts[0].x >= xmin || Ppts[2].x <= xmax ||
03541                  Ppts[1].y >= ymin || Ppts[3].y <= ymax )
03542             {
03543                 Ppts[0].x = MAX( Ppts[0].x, xmin );
03544                 Ppts[2].x = MIN( Ppts[2].x, xmax );
03545                 Ppts[1].y = MAX( Ppts[1].y, ymin );
03546                 Ppts[3].y = MIN( Ppts[3].y, ymax );
03547 
03548                 // the Z array has size (nx-1)*(ny-1)
03549                 icol1 = pls->dev_z[ix * ( ny - 1 ) + iy];
03550 
03551                 // only plot points within zmin/zmax range
03552                 if ( icol1 < pls->dev_zmin || icol1 > pls->dev_zmax )
03553                     continue;
03554 
03555                 icol1 = icol1 / (float) USHRT_MAX * ( xwd->ncol1 - 1 );
03556                 if ( xwd->color )
03557                     curcolor = xwd->cmap1[icol1];
03558                 else
03559                     curcolor = xwd->fgcolor;
03560 
03561                 // Fill square between current and next points.
03562 
03563                 // If the fill area is a single dot, accelerate the fill.
03564                 if ( ( fabs( Ppts[2].x - Ppts[0].x ) == 1 ) &&
03565                      ( fabs( Ppts[3].y - Ppts[1].y ) == 1 ) )
03566                 {
03567                     XPutPixel( ximg, Ppts[0].x, dev->height - 1 - Ppts[0].y, curcolor.pixel );
03568 
03569                     // integer rotate, accelerate
03570                 }
03571                 else if ( pls->diorot == floor( pls->diorot ) )
03572                 {
03573                     for ( ky = Ppts[1].y; ky < Ppts[3].y; ky++ )
03574                         for ( kx = Ppts[0].x; kx < Ppts[2].x; kx++ )
03575                             XPutPixel( ximg, kx, dev->height - 1 - ky, curcolor.pixel );
03576 
03577                     // lozangue, scanline fill it
03578                 }
03579                 else
03580                 {
03581                     // y interception point of left/right top/bottom edges
03582                     blt = Ppts[0].y - mlr * Ppts[0].x;
03583                     brb = Ppts[2].y - mlr * Ppts[2].x;
03584 
03585                     brt = Ppts[2].y - mtb * Ppts[2].x;
03586                     blb = Ppts[0].y - mtb * Ppts[0].x;
03587 
03588                     for ( ky = Ppts[1].y; ky < Ppts[3].y; ky++ )
03589                     {
03590                         left  = MAX( ( ( ky - blt ) / mlr ), ( ( ky - blb ) / mtb ) );
03591                         right = MIN( ( ( ky - brt ) / mtb ), ( ( ky - brb ) / mlr ) );
03592                         for ( kx = Ppts[0].x; kx < Ppts[2].x; kx++ )
03593                         {
03594                             if ( kx >= rint( left ) && kx <= rint( right ) )
03595                             {
03596                                 XPutPixel( ximg, kx, dev->height - 1 - ky, curcolor.pixel );
03597                             }
03598                         }
03599                     }
03600                 }
03601             }
03602         }
03603     }
03604 
03605     if ( dev->write_to_pixmap )
03606         XPutImage( xwd->display, dev->pixmap, dev->gc, ximg, 0, 0, 0, 0, dev->width, dev->height );
03607 
03608     if ( dev->write_to_window )
03609         XPutImage( xwd->display, dev->window, dev->gc, ximg, 0, 0,
03610             0, 0, dev->width, dev->height );
03611 
03612     XDestroyImage( ximg );
03613 }
03614 
03615 static void
03616 imageops( PLStream *pls, PLINT *ptr )
03617 {
03618     XwDev     *dev = (XwDev *) pls->dev;
03619     XwDisplay *xwd = (XwDisplay *) dev->xwd;
03620 
03621 // TODO: store/revert to/from previous state
03622 
03623     switch ( *ptr )
03624     {
03625     case ZEROW2D:
03626         dev->write_to_window = 0;
03627         break;
03628 
03629     case ONEW2D:
03630         dev->write_to_window = 1;
03631         break;
03632 
03633     case ZEROW2B:
03634         dev->write_to_pixmap = 0;
03635         break;
03636 
03637     case ONEW2B:
03638         XFlush( xwd->display );
03639         dev->write_to_pixmap = 1;
03640         break;
03641     }
03642 }
03643 
03644 #else
03645 int
03646 pldummy_xwin()
03647 {
03648     return 0;
03649 }
03650 
03651 #endif                          // PLD_xwin

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