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