PLplot: xwin.c Source File

PLplot 5.15.0

xwin.c
Go to the documentation of this file.
1 // PLplot X-windows device driver.
2 //
3 // Copyright (C) 2004 Maurice LeBrun
4 // Copyright (C) 2004 Joao Cardoso
5 // Copyright (C) 2004 Rafael Laboissiere
6 // Copyright (C) 2004 Andrew Ross
7 //
8 // This file is part of PLplot.
9 //
10 // PLplot is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU Library General Public License as published
12 // by the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // PLplot is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Library General Public License for more details.
19 //
20 // You should have received a copy of the GNU Library General Public License
21 // along with PLplot; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 //
24 //
25 #include "plDevs.h"
26
27 #define DEBUG
28
29 #ifdef PLD_xwin
30 #define NEED_PLDEBUG
31 #include "plplotP.h"
32 #include "plxwd.h"
33 #include "drivers.h"
34 #include "plevent.h"
35
36 #ifdef PL_HAVE_PTHREAD
37 #include <pthread.h>
38 #include <signal.h>
39 int pthread_mutexattr_settype( pthread_mutexattr_t *attr, int kind );
40 static void events_thread( void *pls );
41 static pthread_mutex_t events_mutex;
42 static int already = 0;
43 #endif
44
45 // Device info
46 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_xwin = "xwin:X-Window (Xlib):1:xwin:5:xw\n";
47
48 static int synchronize = 0; // change to 1 for X synchronized operation
49 // Use "-drvopt sync" cmd line option to set.
50
51 static int nobuffered = 0; // make it a buffered device by default
52 // use "-drvopt unbuffered" to make it unbuffered
53
54 static int noinitcolors = 0; // Call InitColors by default
55 // use "-drvopt noinitcolors" to leave colors uninitialized
56
57 static int defaultvisual = 1; // use "-drvopt defvis=0" to not use the default visual
58
59 static int usepthreads = 1; // use "-drvopt usepth=0" to not use pthreads to redisplay
60
61 //
62 // When -drvopt defvis is defined, DefaultVisual() is used to get the visual.
63 // Otherwise, the visual is obtained using XGetVisualInfo() to make a match.
64 //
65
66 //#define HACK_STATICCOLOR
67
68 // Number of instructions to skip between querying the X server for events
69
70 #define MAX_INSTR 20
71
72 // The xwin driver uses the xscale and yscale values to convert from virtual
73 // to real pixels using the current size in pixels of the display window.
74 // We define PHYSICAL here so that PLplot core knows about this rescaling
75 // and mm values are converted to virtual pixels at a ratio consistent with
76 // a constant ratio of DPMM real pixels per mm.
77 #define PHYSICAL 1
78
79 // These need to be distinguished since the handling is slightly different.
80
81 #define LOCATE_INVOKED_VIA_API 1
82 #define LOCATE_INVOKED_VIA_DRIVER 2
83
84 // Set constants for dealing with colormap. In brief:
85 //
86 // --- custom colormaps ---
87 // ccmap When set, turns on custom color map
88 // CCMAP_XWM_COLORS Number of low "pixel" values to copy.
89 //
90 // --- r/w colormaps --
91 // RWMAP_CMAP1_COLORS Color map 1 entries.
92 // RWMAP_MAX_COLORS Maximum colors in RW colormaps
93 //
94 // --- r/o colormaps --
95 // ROMAP_CMAP1_COLORS Color map 1 entries.
96 // TC_CMAP1_COLORS TrueColor visual Color map 1 entries.
97 //
98 // See Init_CustomCmap() and Init_DefaultCmap() for more info.
99 // Set ccmap at your own risk -- still under development.
100 //
101
102 // plplot_ccmap is statically defined in plxwd.h. Note that
103 // plframe.c also includes that header and uses the variable.
104
105 #define CCMAP_XWM_COLORS 70
106
107 #define RWMAP_CMAP1_COLORS 50
108 #define RWMAP_MAX_COLORS 256
109
110 #define ROMAP_CMAP1_COLORS 50
111 #define TC_CMAP1_COLORS 200
112
113 // Variables to hold RGB components of given colormap.
114 // Used in an ugly hack to get past some X11R5 and TK limitations.
115
116 static int sxwm_colors_set;
117 static XColor sxwm_colors[RWMAP_MAX_COLORS];
118
119 // Keep pointers to all the displays in use
120
121 static XwDisplay *xwDisplay[PLXDISPLAYS];
122
123 // Function prototypes
124
125 // Driver entry and dispatch setup
126
127 void plD_dispatch_init_xw( PLDispatchTable *pdt );
128
129 void plD_init_xw( PLStream * );
130 void plD_line_xw( PLStream *, short, short, short, short );
131 void plD_polyline_xw( PLStream *, short *, short *, PLINT );
132 void plD_eop_xw( PLStream * );
133 void plD_bop_xw( PLStream * );
134 void plD_tidy_xw( PLStream * );
135 void plD_wait_xw( PLStream * );
136 void plD_state_xw( PLStream *, PLINT );
137 void plD_esc_xw( PLStream *, PLINT, void * );
138
139 // Initialization
140
141 static void OpenXwin( PLStream *pls );
142 static void Init( PLStream *pls );
143 static void InitMain( PLStream *pls );
144 static void InitColors( PLStream *pls );
145 static void AllocCustomMap( PLStream *pls );
146 static void AllocCmap0( PLStream *pls );
147 static void AllocCmap1( PLStream *pls );
148 static void MapMain( PLStream *pls );
149 static void CreatePixmap( PLStream *pls );
150 static void GetVisual( PLStream *pls );
151 static void AllocBGFG( PLStream *pls );
152 static int AreWeGrayscale( Display *display );
153
154 // Routines to poll the X-server
155
156 static void WaitForPage( PLStream *pls );
157 static void CheckForEvents( PLStream *pls );
158 static void HandleEvents( PLStream *pls );
159
160 // Event handlers
161
162 static void MasterEH( PLStream *pls, XEvent *event );
163 static void ClientEH( PLStream *pls, XEvent *event );
164 static void ExposeEH( PLStream *pls, XEvent *event );
165 static void ResizeEH( PLStream *pls, XEvent *event );
166 static void MotionEH( PLStream *pls, XEvent *event );
167 static void EnterEH( PLStream *pls, XEvent *event );
168 static void LeaveEH( PLStream *pls, XEvent *event );
169 static void KeyEH( PLStream *pls, XEvent *event );
170 static void ButtonEH( PLStream *pls, XEvent *event );
171 static void LookupXKeyEvent( PLStream *pls, XEvent *event );
172 static void LookupXButtonEvent( PLStream *pls, XEvent *event );
173
174 static void ProcessKey( PLStream *pls );
175 static void LocateKey( PLStream *pls );
176 static void ProcessButton( PLStream *pls );
177 static void LocateButton( PLStream *pls );
178 static void Locate( PLStream *pls );
179
180 // Routines for manipulating graphic crosshairs
181
182 static void CreateXhairs( PLStream *pls );
183 static void DestroyXhairs( PLStream *pls );
184 static void DrawXhairs( PLStream *pls, int x0, int y0 );
185 static void UpdateXhairs( PLStream *pls );
186
187 // Escape function commands
188
189 static void ExposeCmd( PLStream *pls, PLDisplay *ptr );
190 static void RedrawCmd( PLStream *pls );
191 static void ResizeCmd( PLStream *pls, PLDisplay *ptr );
192 static void ConfigBufferingCmd( PLStream *pls, PLBufferingCB *ptr );
193 static void GetCursorCmd( PLStream *pls, PLGraphicsIn *ptr );
194 static void FillPolygonCmd( PLStream *pls );
195 static void XorMod( PLStream *pls, PLINT *mod );
196 static void DrawImage( PLStream *pls );
197
198 // Miscellaneous
199
200 static void StoreCmap0( PLStream *pls );
201 static void StoreCmap1( PLStream *pls );
202 static void imageops( PLStream *pls, PLINT *ptr );
203 static void SetBGFG( PLStream *pls );
204 #ifdef DUMMY
205 static void SaveColormap( Display *display, Colormap colormap );
206 #endif
207 static void PLColor_to_XColor( PLColor *plcolor, XColor *xcolor );
208 static void PLColor_from_XColor( PLColor *plcolor, XColor *xcolor );
209
210 static DrvOpt xwin_options[] = { { "sync", DRV_INT, &synchronize, "Synchronized X server operation (0|1)" },
211 { "nobuffered", DRV_INT, &nobuffered, "Sets unbuffered operation (0|1)" },
212 { "noinitcolors", DRV_INT, &noinitcolors, "Sets cmap0 allocation (0|1)" },
213 { "defvis", DRV_INT, &defaultvisual, "Use the Default Visual (0|1)" },
214 { "usepth", DRV_INT, &usepthreads, "Use pthreads (0|1)" },
215 { NULL, DRV_INT, NULL, NULL } };
216
217 void plD_dispatch_init_xw( PLDispatchTable *pdt )
218 {
219 #ifndef ENABLE_DYNDRIVERS
220 pdt->pl_MenuStr = "X-Window (Xlib)";
221 pdt->pl_DevName = "xwin";
222 #endif
223 pdt->pl_type = plDevType_Interactive;
224 pdt->pl_seq = 5;
225 pdt->pl_init = (plD_init_fp) plD_init_xw;
226 pdt->pl_line = (plD_line_fp) plD_line_xw;
227 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_xw;
228 pdt->pl_eop = (plD_eop_fp) plD_eop_xw;
229 pdt->pl_bop = (plD_bop_fp) plD_bop_xw;
230 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_xw;
231 pdt->pl_state = (plD_state_fp) plD_state_xw;
232 pdt->pl_esc = (plD_esc_fp) plD_esc_xw;
233 pdt->pl_wait = (plD_wait_fp) plD_wait_xw;
234 }
235
236 //--------------------------------------------------------------------------
237 // plD_init_xw()
238 //
239 // Initialize device.
240 // X-dependent stuff done in OpenXwin() and Init().
241 //--------------------------------------------------------------------------
242
243 void
244 plD_init_xw( PLStream *pls )
245 {
246 XwDev *dev;
247 PLFLT pxlx, pxly;
248 int xmin = 0;
249 int xmax = PIXELS_X - 1;
250 int ymin = 0;
251 int ymax = PIXELS_Y - 1;
252
253 dbug_enter( "plD_init_xw" );
254
255 pls->termin = 1; // Is an interactive terminal
256 pls->dev_flush = 1; // Handle our own flushes
257 pls->dev_fill0 = 1; // Handle solid fills
258 pls->plbuf_write = 1; // Activate plot buffer
259 pls->dev_fastimg = 1; // is a fast image device
260 pls->dev_xor = 1; // device support xor mode
261
262 #ifndef PL_HAVE_PTHREAD
263 usepthreads = 0;
264 #endif
265
266 plParseDrvOpts( xwin_options );
267
268 #ifndef PL_HAVE_PTHREAD
269 if ( usepthreads )
270 plwarn( "You said you want pthreads, but they are not available." );
271 #endif
272
273 if ( nobuffered )
274 pls->plbuf_write = 0; // deactivate plot buffer
275
276 // The real meat of the initialization done here
277
278 if ( pls->dev == NULL )
279 OpenXwin( pls );
280
281 dev = (XwDev *) pls->dev;
282
283 Init( pls );
284
285 // Get ready for plotting
286
287 dev->xlen = (short) ( xmax - xmin );
288 dev->ylen = (short) ( ymax - ymin );
289
290 dev->xscale_init = (double) dev->init_width / (double) dev->xlen;
291 dev->yscale_init = (double) dev->init_height / (double) dev->ylen;
292
293 dev->xscale = dev->xscale_init;
294 dev->yscale = dev->yscale_init;
295
296 #if PHYSICAL
297 pxlx = DPMM / dev->xscale;
298 pxly = DPMM / dev->yscale;
299 #else
300 pxlx = (double) PIXELS_X / LPAGE_X;
301 pxly = (double) PIXELS_Y / LPAGE_Y;
302 #endif
303
304 plP_setpxl( pxlx, pxly );
305 plP_setphy( xmin, xmax, ymin, ymax );
306
307 #ifdef PL_HAVE_PTHREAD
308 if ( usepthreads )
309 {
310 pthread_mutexattr_t mutexatt;
311 pthread_attr_t pthattr;
312
313 if ( !already )
314 {
315 pthread_mutexattr_init( &mutexatt );
316 if ( pthread_mutexattr_settype( &mutexatt, PLPLOT_MUTEX_RECURSIVE ) )
317 plexit( "xwin: pthread_mutexattr_settype() failed!\n" );
318
319 pthread_mutex_init( &events_mutex, &mutexatt );
320 already = 1;
321 }
322 else
323 {
324 pthread_mutex_lock( &events_mutex );
325 already++;
326 pthread_mutex_unlock( &events_mutex );
327 }
328
329 pthread_attr_init( &pthattr );
330 pthread_attr_setdetachstate( &pthattr, PTHREAD_CREATE_JOINABLE );
331
332 if ( pthread_create( &( dev->updater ), &pthattr, ( void *( * )( void * ) ) & events_thread, (void *) pls ) )
333 {
334 pthread_mutex_lock( &events_mutex );
335 already--;
336 pthread_mutex_unlock( &events_mutex );
337
338 if ( already == 0 )
339 {
340 pthread_mutex_destroy( &events_mutex );
341 plexit( "xwin: pthread_create() failed!\n" );
342 }
343 else
344 plwarn( "xwin: couldn't create thread for this plot window!\n" );
345 }
346 }
347 #endif
348 }
349
350 //--------------------------------------------------------------------------
351 // plD_line_xw()
352 //
353 // Draw a line in the current color from (x1,y1) to (x2,y2).
354 //--------------------------------------------------------------------------
355
356 void
357 plD_line_xw( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
358 {
359 XwDev *dev = (XwDev *) pls->dev;
360 XwDisplay *xwd = (XwDisplay *) dev->xwd;
361
362 int x1 = x1a, y1 = y1a, x2 = x2a, y2 = y2a;
363
364 dbug_enter( "plD_line_xw" );
365
366 #ifdef PL_HAVE_PTHREAD
367 if ( usepthreads )
368 pthread_mutex_lock( &events_mutex );
369 #endif
370
371 CheckForEvents( pls );
372
373 y1 = dev->ylen - y1;
374 y2 = dev->ylen - y2;
375
376 x1 = (int) ( x1 * dev->xscale );
377 x2 = (int) ( x2 * dev->xscale );
378 y1 = (int) ( y1 * dev->yscale );
379 y2 = (int) ( y2 * dev->yscale );
380
381 if ( dev->write_to_window )
382 XDrawLine( xwd->display, dev->window, dev->gc, x1, y1, x2, y2 );
383
384 if ( dev->write_to_pixmap )
385 XDrawLine( xwd->display, dev->pixmap, dev->gc, x1, y1, x2, y2 );
386
387 #ifdef PL_HAVE_PTHREAD
388 if ( usepthreads )
389 pthread_mutex_unlock( &events_mutex );
390 #endif
391 }
392
393 //--------------------------------------------------------------------------
394 // XorMod()
395 //
396 // Enter xor mode ( mod != 0) or leave it ( mode = 0)
397 //--------------------------------------------------------------------------
398
399 static void
400 XorMod( PLStream *pls, PLINT *mod )
401 {
402 XwDev *dev = (XwDev *) pls->dev;
403 XwDisplay *xwd = (XwDisplay *) dev->xwd;
404
405 if ( *mod == 0 )
406 XSetFunction( xwd->display, dev->gc, GXcopy );
407 else
408 XSetFunction( xwd->display, dev->gc, GXxor );
409 }
410
411 //--------------------------------------------------------------------------
412 // plD_polyline_xw()
413 //
414 // Draw a polyline in the current color from (x1,y1) to (x2,y2).
415 //--------------------------------------------------------------------------
416
417 void
418 plD_polyline_xw( PLStream *pls, short *xa, short *ya, PLINT npts )
419 {
420 XwDev *dev = (XwDev *) pls->dev;
421 XwDisplay *xwd = (XwDisplay *) dev->xwd;
422
423 PLINT i;
424 XPoint _pts[PL_MAXPOLY];
425 XPoint *pts;
426
427 if ( npts > PL_MAXPOLY )
428 {
429 pts = (XPoint *) malloc( sizeof ( XPoint ) * (size_t) npts );
430 }
431 else
432 {
433 pts = _pts;
434 }
435
436 dbug_enter( "plD_polyline_xw" );
437
438 #ifdef PL_HAVE_PTHREAD
439 if ( usepthreads )
440 pthread_mutex_lock( &events_mutex );
441 #endif
442
443 CheckForEvents( pls );
444
445 for ( i = 0; i < npts; i++ )
446 {
447 pts[i].x = (short) ( dev->xscale * xa[i] );
448 pts[i].y = (short) ( dev->yscale * ( dev->ylen - ya[i] ) );
449 }
450
451 if ( dev->write_to_window )
452 XDrawLines( xwd->display, dev->window, dev->gc, pts, npts,
453 CoordModeOrigin );
454
455 if ( dev->write_to_pixmap )
456 XDrawLines( xwd->display, dev->pixmap, dev->gc, pts, npts,
457 CoordModeOrigin );
458
459 #ifdef PL_HAVE_PTHREAD
460 if ( usepthreads )
461 pthread_mutex_unlock( &events_mutex );
462 #endif
463
464 if ( npts > PL_MAXPOLY )
465 {
466 free( pts );
467 }
468 }
469
470 //--------------------------------------------------------------------------
471 // plD_eop_xw()
472 //
473 // End of page. User must hit return (or third mouse button) to continue.
474 //--------------------------------------------------------------------------
475
476 void
477 plD_eop_xw( PLStream *pls )
478 {
479 XwDev *dev = (XwDev *) pls->dev;
480 XwDisplay *xwd = (XwDisplay *) dev->xwd;
481
482 dbug_enter( "plD_eop_xw" );
483
484 #ifdef PL_HAVE_PTHREAD
485 if ( usepthreads )
486 pthread_mutex_lock( &events_mutex );
487 #endif
488
489 XFlush( xwd->display );
490 if ( pls->db )
491 ExposeCmd( pls, NULL );
492
493 #ifdef PL_HAVE_PTHREAD
494 if ( usepthreads )
495 pthread_mutex_unlock( &events_mutex );
496 #endif
497 }
498
499 //--------------------------------------------------------------------------
500 // plD_bop_xw()
501 //
502 // Set up for the next page.
503 //--------------------------------------------------------------------------
504
505 void
506 plD_bop_xw( PLStream *pls )
507 {
508 XwDev *dev = (XwDev *) pls->dev;
509 XwDisplay *xwd = (XwDisplay *) dev->xwd;
510
511 dbug_enter( "plD_bop_xw" );
512
513 #ifdef PL_HAVE_PTHREAD
514 if ( usepthreads )
515 pthread_mutex_lock( &events_mutex );
516 #endif
517
518 dev->bgcolor = xwd->cmap0[0];
519
520 if ( dev->write_to_window )
521 {
522 XSetWindowBackground( xwd->display, dev->window, dev->bgcolor.pixel );
523 XSetBackground( xwd->display, dev->gc, dev->bgcolor.pixel );
524 XClearWindow( xwd->display, dev->window );
525 }
526 if ( dev->write_to_pixmap )
527 {
528 XSetForeground( xwd->display, dev->gc, dev->bgcolor.pixel );
529 XFillRectangle( xwd->display, dev->pixmap, dev->gc, 0, 0,
530 dev->width, dev->height );
531 XSetForeground( xwd->display, dev->gc, dev->curcolor.pixel );
532 }
533 XSync( xwd->display, 0 );
534 pls->page++;
535
536 #ifdef PL_HAVE_PTHREAD
537 if ( usepthreads )
538 pthread_mutex_unlock( &events_mutex );
539 #endif
540 }
541
542 //--------------------------------------------------------------------------
543 // plD_tidy_xw()
544 //
545 // Close graphics file
546 //--------------------------------------------------------------------------
547
548 void
549 plD_tidy_xw( PLStream *pls )
550 {
551 XwDev *dev = (XwDev *) pls->dev;
552 XwDisplay *xwd = (XwDisplay *) dev->xwd;
553
554 dbug_enter( "plD_tidy_xw" );
555
556 #ifdef PL_HAVE_PTHREAD
557 if ( usepthreads )
558 {
559 pthread_mutex_lock( &events_mutex );
560 if ( pthread_cancel( dev->updater ) == 0 )
561 pthread_join( dev->updater, NULL );
562
563 pthread_mutex_unlock( &events_mutex );
564 if ( --already == 0 )
565 pthread_mutex_destroy( &events_mutex );
566 }
567 #endif
568
569 if ( dev->is_main )
570 {
571 XDestroyWindow( xwd->display, dev->window );
572 if ( dev->write_to_pixmap )
573 XFreePixmap( xwd->display, dev->pixmap );
574 XFlush( xwd->display );
575 }
576
577 xwd->nstreams--;
578 if ( xwd->nstreams == 0 )
579 {
580 int ixwd = xwd->ixwd;
581 XFreeGC( xwd->display, dev->gc );
582 XFreeGC( xwd->display, xwd->gcXor );
583 XCloseDisplay( xwd->display );
584 free_mem( xwd->cmap0 );
585 free_mem( xwd->cmap1 );
586 free_mem( xwDisplay[ixwd] );
587 }
588 // ANR: if we set this here the tmp file will not be closed
589 // See also comment in tkwin.c
590 //pls->plbuf_write = 0;
591 }
592
593 //--------------------------------------------------------------------------
594 // plD_wait_xw()
595 //
596 // Wait for user input
597 //--------------------------------------------------------------------------
598
599 void
600 plD_wait_xw( PLStream *pls )
601 {
602 XwDev *dev = (XwDev *) pls->dev;
603 dbug_enter( "plD_eop_xw" );
604
605 #ifdef PL_HAVE_PTHREAD
606 if ( usepthreads )
607 pthread_mutex_lock( &events_mutex );
608 #endif
609
610 if ( dev->is_main )
611 WaitForPage( pls );
612
613 #ifdef PL_HAVE_PTHREAD
614 if ( usepthreads )
615 pthread_mutex_unlock( &events_mutex );
616 #endif
617 }
618
619 //--------------------------------------------------------------------------
620 // plD_state_xw()
621 //
622 // Handle change in PLStream state (color, pen width, fill attribute, etc).
623 //--------------------------------------------------------------------------
624
625 void
626 plD_state_xw( PLStream *pls, PLINT op )
627 {
628 XwDev *dev = (XwDev *) pls->dev;
629 XwDisplay *xwd = (XwDisplay *) dev->xwd;
630
631 dbug_enter( "plD_state_xw" );
632
633 #ifdef PL_HAVE_PTHREAD
634 if ( usepthreads )
635 pthread_mutex_lock( &events_mutex );
636 #endif
637
638 CheckForEvents( pls );
639
640 switch ( op )
641 {
642 case PLSTATE_WIDTH:
643 XSetLineAttributes( xwd->display, dev->gc, (unsigned int) pls->width,
644 LineSolid, CapRound, JoinMiter );
645 break;
646
647 case PLSTATE_COLOR0: {
648 int icol0 = pls->icol0;
649 if ( xwd->color )
650 {
651 if ( icol0 == PL_RGB_COLOR )
652 {
653 PLColor_to_XColor( &pls->curcolor, &dev->curcolor );
654 if ( !XAllocColor( xwd->display, xwd->map, &dev->curcolor ) )
655 {
656 fprintf( stderr, "Warning: could not allocate color\n" );
657 dev->curcolor.pixel = xwd->fgcolor.pixel;
658 }
659 }
660 else
661 {
662 dev->curcolor = xwd->cmap0[icol0];
663 }
664 XSetForeground( xwd->display, dev->gc, dev->curcolor.pixel );
665 }
666 else
667 {
668 dev->curcolor = xwd->fgcolor;
669 XSetForeground( xwd->display, dev->gc, dev->curcolor.pixel );
670 }
671 break;
672 }
673
674 case PLSTATE_COLOR1: {
675 int icol1;
676
677 if ( xwd->ncol1 == 0 )
678 AllocCmap1( pls );
679
680 if ( xwd->ncol1 < 2 )
681 break;
682
683 icol1 = ( pls->icol1 * ( xwd->ncol1 - 1 ) ) / ( pls->ncol1 - 1 );
684 if ( xwd->color )
685 dev->curcolor = xwd->cmap1[icol1];
686 else
687 dev->curcolor = xwd->fgcolor;
688
689 XSetForeground( xwd->display, dev->gc, dev->curcolor.pixel );
690 break;
691 }
692
693 case PLSTATE_CMAP0:
694 SetBGFG( pls );
695 // If ncol0 has changed, need to reallocate
696 if ( pls->ncol0 != xwd->ncol0 )
697 AllocCmap0( pls );
698 StoreCmap0( pls );
699 break;
700
701 case PLSTATE_CMAP1:
702 StoreCmap1( pls );
703 break;
704 }
705
706 #ifdef PL_HAVE_PTHREAD
707 if ( usepthreads )
708 pthread_mutex_unlock( &events_mutex );
709 #endif
710 }
711
712 //--------------------------------------------------------------------------
713 // plD_esc_xw()
714 //
715 // Escape function.
716 //
717 // Functions:
718 //
719 // PLESC_EH Handle pending events
720 // PLESC_EXPOSE Force an expose
721 // PLESC_FILL Fill polygon
722 // PLESC_FLUSH Flush X event buffer
723 // PLESC_GETC Get coordinates upon mouse click
724 // PLESC_REDRAW Force a redraw
725 // PLESC_RESIZE Force a resize
726 // PLESC_XORMOD set/reset xor mode
727 // PLESC_IMAGE draw the image in a fast way
728 // PLESC_IMAGEOPS: image related operations:
729 // ZEROW2D disable writing to display
730 // ZEROW2B disable writing to buffer
731 // ONEW2D enable writing to display
732 // ONEW2B enable writing to buffer
733 // PLESC_PL2DEVCOL convert PLColor to device color (XColor)
734 // PLESC_DEV2PLCOL convert device color (XColor) to PLColor
735 // PLESC_SETBGFG set BG, FG colors
736 // PLESC_DEVINIT alternate device initialization
737 //
738 // Note the [GET|SET]DEVCOL functions go through the intermediary stream
739 // variable tmpcolor to keep the syntax simple.
740 //--------------------------------------------------------------------------
741
742 void
743 plD_esc_xw( PLStream *pls, PLINT op, void *ptr )
744 {
745 dbug_enter( "plD_esc_xw" );
746
747 #ifdef PL_HAVE_PTHREAD
748 if ( usepthreads )
749 pthread_mutex_lock( &events_mutex );
750 #endif
751
752 switch ( op )
753 {
754 case PLESC_EH:
755 HandleEvents( pls );
756 break;
757
758 case PLESC_EXPOSE:
759 ExposeCmd( pls, (PLDisplay *) ptr );
760 break;
761
762 case PLESC_FILL:
763 FillPolygonCmd( pls );
764 break;
765
766 case PLESC_FLUSH: {
767 XwDev *dev = (XwDev *) pls->dev;
768 XwDisplay *xwd = (XwDisplay *) dev->xwd;
769 HandleEvents( pls );
770 XFlush( xwd->display );
771 break;
772 }
773 case PLESC_GETC:
774 GetCursorCmd( pls, (PLGraphicsIn *) ptr );
775 break;
776
777 case PLESC_REDRAW:
778 RedrawCmd( pls );
779 break;
780
781 case PLESC_RESIZE:
782 ResizeCmd( pls, (PLDisplay *) ptr );
783 break;
784
785 case PLESC_XORMOD:
786 XorMod( pls, (PLINT *) ptr );
787 break;
788
789 case PLESC_DOUBLEBUFFERING:
790 ConfigBufferingCmd( pls, (PLBufferingCB *) ptr );
791 break;
792
793 case PLESC_IMAGE:
794 DrawImage( pls );
795 break;
796
797 case PLESC_IMAGEOPS:
798 imageops( pls, (PLINT *) ptr );
799 break;
800
801 case PLESC_PL2DEVCOL:
802 PLColor_to_XColor( &pls->tmpcolor, (XColor *) ptr );
803 break;
804
805 case PLESC_DEV2PLCOL:
806 PLColor_from_XColor( &pls->tmpcolor, (XColor *) ptr );
807 break;
808
809 case PLESC_SETBGFG:
810 SetBGFG( pls );
811 break;
812
813 case PLESC_DEVINIT:
814 OpenXwin( pls );
815 break;
816 }
817
818 #ifdef PL_HAVE_PTHREAD
819 if ( usepthreads )
820 pthread_mutex_unlock( &events_mutex );
821 #endif
822 }
823
824 //--------------------------------------------------------------------------
825 // GetCursorCmd()
826 //
827 // Waits for a graphics input event and returns coordinates.
828 //--------------------------------------------------------------------------
829
830 static void
831 GetCursorCmd( PLStream *pls, PLGraphicsIn *ptr )
832 {
833 XwDev *dev = (XwDev *) pls->dev;
834 XwDisplay *xwd = (XwDisplay *) dev->xwd;
835 XEvent event;
836 PLGraphicsIn *gin = &( dev->gin );
837
838 // Initialize
839
840 plGinInit( gin );
841 dev->locate_mode = LOCATE_INVOKED_VIA_API;
842 CreateXhairs( pls );
843
844 // Run event loop until a point is selected
845
846 while ( gin->pX < 0 && dev->locate_mode )
847 {
848 // XWindowEvent( xwd->display, dev->window, dev->event_mask, &event );
849 XNextEvent( xwd->display, &event );
850 MasterEH( pls, &event );
851 }
852 *ptr = *gin;
853 if ( dev->locate_mode )
854 {
855 dev->locate_mode = 0;
856 DestroyXhairs( pls );
857 }
858 }
859
860 //--------------------------------------------------------------------------
861 // FillPolygonCmd()
862 //
863 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
864 // Only solid color fill supported.
865 //--------------------------------------------------------------------------
866
867 static void
868 FillPolygonCmd( PLStream *pls )
869 {
870 XwDev *dev = (XwDev *) pls->dev;
871 XwDisplay *xwd = (XwDisplay *) dev->xwd;
872 XPoint _pts[PL_MAXPOLY];
873 XPoint *pts;
874 int i;
875
876 if ( pls->dev_npts > PL_MAXPOLY )
877 {
878 pts = (XPoint *) malloc( sizeof ( XPoint ) * (size_t) ( pls->dev_npts ) );
879 }
880 else
881 {
882 pts = _pts;
883 }
884
885 CheckForEvents( pls );
886
887 for ( i = 0; i < pls->dev_npts; i++ )
888 {
889 pts[i].x = (short) ( dev->xscale * pls->dev_x[i] );
890 pts[i].y = (short) ( dev->yscale * ( dev->ylen - pls->dev_y[i] ) );
891 }
892
893 // Fill polygons
894
895 if ( dev->write_to_window )
896 XFillPolygon( xwd->display, dev->window, dev->gc,
897 pts, pls->dev_npts, Complex, CoordModeOrigin );
898
899 if ( dev->write_to_pixmap )
900 XFillPolygon( xwd->display, dev->pixmap, dev->gc,
901 pts, pls->dev_npts, Complex, CoordModeOrigin );
902
903 // If in debug mode, draw outline of boxes being filled
904
905 #ifdef DEBUG
906 if ( pls->debug )
907 {
908 XSetForeground( xwd->display, dev->gc, xwd->fgcolor.pixel );
909 if ( dev->write_to_window )
910 XDrawLines( xwd->display, dev->window, dev->gc, pts, pls->dev_npts,
911 CoordModeOrigin );
912
913 if ( dev->write_to_pixmap )
914 XDrawLines( xwd->display, dev->pixmap, dev->gc, pts, pls->dev_npts,
915 CoordModeOrigin );
916
917 XSetForeground( xwd->display, dev->gc, dev->curcolor.pixel );
918 }
919 #endif
920
921 if ( pls->dev_npts > PL_MAXPOLY )
922 {
923 free( pts );
924 }
925 }
926
927 //--------------------------------------------------------------------------
928 // OpenXwin()
929 //
930 // Performs basic driver initialization, without actually opening or
931 // modifying a window. May be called by the outside world before plinit
932 // in case the caller needs early access to the driver internals (not
933 // very common -- currently only used by the plframe widget).
934 //--------------------------------------------------------------------------
935
936 static void
937 OpenXwin( PLStream *pls )
938 {
939 XwDev *dev;
940 XwDisplay *xwd;
941 int i;
942
943 dbug_enter( "OpenXwin" );
944
945 // Allocate and initialize device-specific data
946
947 if ( pls->dev != NULL )
948 plwarn( "OpenXwin: device pointer is already set" );
949
950 pls->dev = calloc( 1, (size_t) sizeof ( XwDev ) );
951 if ( pls->dev == NULL )
952 plexit( "plD_init_xw: Out of memory." );
953
954 dev = (XwDev *) pls->dev;
955
956 // Variables used in querying the X server for events
957
958 dev->instr = 0;
959 dev->max_instr = MAX_INSTR;
960
961 // See if display matches any already in use, and if so use that
962
963 dev->xwd = NULL;
964 for ( i = 0; i < PLXDISPLAYS; i++ )
965 {
966 if ( xwDisplay[i] == NULL )
967 {
968 continue;
969 }
970 else if ( pls->FileName == NULL && xwDisplay[i]->displayName == NULL )
971 {
972 dev->xwd = xwDisplay[i];
973 break;
974 }
975 else if ( pls->FileName == NULL || xwDisplay[i]->displayName == NULL )
976 {
977 continue;
978 }
979 else if ( strcmp( xwDisplay[i]->displayName, pls->FileName ) == 0 )
980 {
981 dev->xwd = xwDisplay[i];
982 break;
983 }
984 }
985
986 // If no display matched, create a new one
987
988 if ( dev->xwd == NULL )
989 {
990 dev->xwd = (XwDisplay *) calloc( 1, (size_t) sizeof ( XwDisplay ) );
991 if ( dev->xwd == NULL )
992 plexit( "Init: Out of memory." );
993
994 for ( i = 0; i < PLXDISPLAYS; i++ )
995 {
996 if ( xwDisplay[i] == NULL )
997 break;
998 }
999 if ( i == PLXDISPLAYS )
1000 plexit( "Init: Out of xwDisplay's." );
1001
1002 xwDisplay[i] = xwd = (XwDisplay *) dev->xwd;
1003 xwd->nstreams = 1;
1004
1005 // Open display
1006 #ifdef PL_HAVE_PTHREAD
1007 if ( usepthreads )
1008 if ( !XInitThreads() )
1009 plexit( "xwin: XInitThreads() not successful." );
1010 #endif
1011 xwd->display = XOpenDisplay( pls->FileName );
1012 if ( xwd->display == NULL )
1013 {
1014 plexit( "Can't open display" );
1015 }
1016 xwd->displayName = pls->FileName;
1017 xwd->screen = DefaultScreen( xwd->display );
1018 if ( synchronize )
1019 XSynchronize( xwd->display, 1 );
1020
1021 // Get colormap and visual
1022 xwd->map = DefaultColormap( xwd->display, xwd->screen );
1023 GetVisual( pls );
1024
1025 //
1026 // Figure out if we have a color display or not.
1027 // Default is color IF the user hasn't specified and IF the output device
1028 // is not grayscale.
1029 //
1030 if ( pls->colorset )
1031 xwd->color = pls->color;
1032 else
1033 {
1034 pls->color = 1;
1035 xwd->color = !AreWeGrayscale( xwd->display );
1036 }
1037
1038 // Allocate space for colors
1039 // Note cmap1 allocation is deferred
1040 xwd->ncol0_alloc = pls->ncol0;
1041 xwd->cmap0 = (XColor *) calloc( (size_t) ( pls->ncol0 ), sizeof ( XColor ) );
1042 if ( xwd->cmap0 == 0 )
1043 plexit( "couldn't allocate space for cmap0 colors" );
1044
1045 // Allocate & set background and foreground colors
1046 AllocBGFG( pls );
1047 SetBGFG( pls );
1048 }
1049
1050 // Display matched, so use existing display data
1051
1052 else
1053 {
1054 xwd = (XwDisplay *) dev->xwd;
1055 xwd->nstreams++;
1056 }
1057 xwd->ixwd = i;
1058 }
1059
1060 //--------------------------------------------------------------------------
1061 // Init()
1062 //
1063 // Xlib initialization routine.
1064 //
1065 // Controlling routine for X window creation and/or initialization.
1066 // The user may customize the window in the following ways:
1067 //
1068 // display: pls->OutFile (use plsfnam() or -display option)
1069 // size: pls->xlength, pls->ylength (use plspage() or -geo option)
1070 // bg color: pls->cmap0[0] (use plscolbg() or -bg option)
1071 //--------------------------------------------------------------------------
1072
1073 static void
1074 Init( PLStream *pls )
1075 {
1076 XwDev *dev = (XwDev *) pls->dev;
1077 XwDisplay *xwd = (XwDisplay *) dev->xwd;
1078
1079 Window root;
1080 int x, y;
1081
1082 dbug_enter( "Init" );
1083
1084 // If not plotting into a child window, need to create main window now
1085
1086 if ( pls->window_id == 0 )
1087 {
1088 dev->is_main = TRUE;
1089 InitMain( pls );
1090 }
1091 else
1092 {
1093 dev->is_main = FALSE;
1094 dev->window = (Window) pls->window_id;
1095 }
1096
1097 // Initialize colors
1098
1099 if ( noinitcolors == 0 )
1100 InitColors( pls );
1101 XSetWindowColormap( xwd->display, dev->window, xwd->map );
1102
1103 // Set up GC for ordinary draws
1104
1105 if ( !dev->gc )
1106 dev->gc = XCreateGC( xwd->display, dev->window, 0, 0 );
1107
1108 // Set up GC for rubber-band draws
1109
1110 if ( !xwd->gcXor )
1111 {
1112 XGCValues gcValues;
1113 unsigned long mask;
1114
1115 gcValues.background = xwd->cmap0[0].pixel;
1116 gcValues.foreground = 0xFF;
1117 gcValues.function = GXxor;
1118 mask = GCForeground | GCBackground | GCFunction;
1119
1120 xwd->gcXor = XCreateGC( xwd->display, dev->window, mask, &gcValues );
1121 }
1122
1123 // Get initial drawing area dimensions
1124
1125 (void) XGetGeometry( xwd->display, dev->window, &root, &x, &y,
1126 &dev->width, &dev->height, &dev->border, &xwd->depth );
1127
1128 dev->init_width = (long) dev->width;
1129 dev->init_height = (long) dev->height;
1130
1131 // Set up flags that determine what we are writing to
1132 // If nopixmap is set, ignore db
1133
1134 if ( pls->nopixmap )
1135 {
1136 dev->write_to_pixmap = 0;
1137 pls->db = 0;
1138 }
1139 else
1140 {
1141 dev->write_to_pixmap = 1;
1142 }
1143 dev->write_to_window = !pls->db;
1144
1145 // Create pixmap for holding plot image (for expose events).
1146
1147 if ( dev->write_to_pixmap )
1148 CreatePixmap( pls );
1149
1150 // Set drawing color
1151
1152 plD_state_xw( pls, PLSTATE_COLOR0 );
1153
1154 XSetWindowBackground( xwd->display, dev->window, xwd->cmap0[0].pixel );
1155 XSetBackground( xwd->display, dev->gc, xwd->cmap0[0].pixel );
1156
1157 // Set fill rule.
1158 if ( pls->dev_eofill )
1159 XSetFillRule( xwd->display, dev->gc, EvenOddRule );
1160 else
1161 XSetFillRule( xwd->display, dev->gc, WindingRule );
1162
1163 // If main window, need to map it and wait for exposure
1164
1165 if ( dev->is_main )
1166 MapMain( pls );
1167 }
1168
1169 //--------------------------------------------------------------------------
1170 // InitMain()
1171 //
1172 // Create main window using standard Xlib calls.
1173 //--------------------------------------------------------------------------
1174
1175 static void
1176 InitMain( PLStream *pls )
1177 {
1178 XwDev *dev = (XwDev *) pls->dev;
1179 XwDisplay *xwd = (XwDisplay *) dev->xwd;
1180
1181 Window root;
1182 XSizeHints hint;
1183 int x, y;
1184 U_INT width, height, border, depth;
1185
1186 dbug_enter( "InitMain" );
1187
1188 // Get root window geometry
1189
1190 (void) XGetGeometry( xwd->display, DefaultRootWindow( xwd->display ),
1191 &root, &x, &y, &width, &height, &border, &depth );
1192
1193 // Set window size
1194 // Need to be careful to set XSizeHints flags correctly
1195
1196 hint.flags = 0;
1197 if ( pls->xlength == 0 && pls->ylength == 0 )
1198 hint.flags |= PSize;
1199 else
1200 hint.flags |= USSize;
1201
1202 if ( pls->xlength == 0 )
1203 pls->xlength = (PLINT) ( width * 0.75 );
1204 if ( pls->ylength == 0 )
1205 pls->ylength = (PLINT) ( height * 0.75 );
1206
1207 if ( pls->xlength > (short) width )
1208 pls->xlength = (PLINT) ( width - dev->border * 2 );
1209 if ( pls->ylength > (short) height )
1210 pls->ylength = (PLINT) ( height - dev->border * 2 );
1211
1212 hint.width = (int) pls->xlength;
1213 hint.height = (int) pls->ylength;
1214 dev->border = 5;
1215
1216 // Set window position if specified by the user.
1217 // Otherwise leave up to the window manager
1218
1219 if ( pls->xoffset != 0 || pls->yoffset != 0 )
1220 {
1221 hint.flags |= USPosition;
1222 hint.x = (int) pls->xoffset;
1223 hint.y = (int) pls->yoffset;
1224 }
1225 else
1226 {
1227 hint.x = 0;
1228 hint.y = 0;
1229 }
1230
1231 // Window creation
1232
1233 dev->window =
1234 XCreateWindow( xwd->display,
1235 DefaultRootWindow( xwd->display ),
1236 hint.x, hint.y, (unsigned int) hint.width, (unsigned int) hint.height,
1237 dev->border, (int) xwd->depth,
1238 InputOutput, xwd->visual,
1239 0, NULL );
1240
1241 XSetStandardProperties( xwd->display, dev->window, pls->plwindow, pls->plwindow,
1242 None, 0, 0, &hint );
1243 }
1244
1245 //--------------------------------------------------------------------------
1246 // MapMain()
1247 //
1248 // Sets up event handlers, maps main window and waits for exposure.
1249 //--------------------------------------------------------------------------
1250
1251 static void
1252 MapMain( PLStream *pls )
1253 {
1254 XwDev *dev = (XwDev *) pls->dev;
1255 XwDisplay *xwd = (XwDisplay *) dev->xwd;
1256 XEvent event;
1257
1258 dbug_enter( "MapMain" );
1259
1260 // Input event selection
1261
1262 dev->event_mask =
1263 ButtonPressMask |
1264 KeyPressMask |
1265 ExposureMask |
1266 ButtonMotionMask | // drag
1267 StructureNotifyMask;
1268
1269 XSelectInput( xwd->display, dev->window, dev->event_mask );
1270
1271 // Window mapping
1272
1273 XMapRaised( xwd->display, dev->window );
1274
1275 Atom wmDelete = XInternAtom( xwd->display, "WM_DELETE_WINDOW", False );
1276 XSetWMProtocols( xwd->display, dev->window, &wmDelete, 1 );
1277
1278 // Wait for exposure
1279 // Remove extraneous expose events from the event queue
1280
1281 for (;; )
1282 {
1283 XWindowEvent( xwd->display, dev->window, dev->event_mask, &event );
1284 if ( event.type == Expose )
1285 {
1286 while ( XCheckWindowEvent( xwd->display, dev->window,
1287 ExposureMask, &event ) )
1288 ;
1289 break;
1290 }
1291 }
1292 }
1293
1294 //--------------------------------------------------------------------------
1295 // WaitForPage()
1296 //
1297 // This routine waits for the user to advance the plot, while handling
1298 // all other events.
1299 //--------------------------------------------------------------------------
1300
1301 static void
1302 WaitForPage( PLStream *pls )
1303 {
1304 XwDev *dev = (XwDev *) pls->dev;
1305 XwDisplay *xwd = (XwDisplay *) dev->xwd;
1306 XEvent event;
1307
1308 dbug_enter( "WaitForPage" );
1309
1310 while ( !dev->exit_eventloop )
1311 {
1312 // XWindowEvent( xwd->display, dev->window, dev->event_mask, &event );
1313 XNextEvent( xwd->display, &event );
1314 MasterEH( pls, &event );
1315 }
1316 dev->exit_eventloop = FALSE;
1317 }
1318
1319 //--------------------------------------------------------------------------
1320 // events_thread()
1321 //
1322 // This function is being running continuously by a thread and is
1323 // responsible for dealing with expose and resize X events, in
1324 // the case that the main program is too busy to honor them.
1325 //
1326 // Dealing with other X events is possible, but not desirable,
1327 // e.g. treating the "Q" or right-mouse-button would terminate
1328 // the thread (if this is desirable, the thread should kill the
1329 // main program -- not thread aware -- and kill itself afterward).
1330 //
1331 // This works pretty well, but the main program *must* be linked
1332 // with the pthread library, although not being thread aware.
1333 // This happens automatically when linking against libplplot.so,
1334 // but when building modules for extending some language such as
1335 // Python or Octave, the language providing binary itself must be
1336 // relinked with -lpthread.
1337 //
1338 //--------------------------------------------------------------------------
1339
1340 #ifdef PL_HAVE_PTHREAD
1341 static void
1342 events_thread( void *pls )
1343 {
1344 if ( usepthreads )
1345 {
1346 PLStream *lpls = (PLStream *) pls;
1347 XwDev *dev = (XwDev *) lpls->dev;
1348 XwDisplay *xwd = (XwDisplay *) dev->xwd;
1349 PLStream *oplsc;
1350 struct timespec delay;
1351 XEvent event;
1352 long event_mask;
1353 sigset_t set;
1354
1355 //
1356 // only treats exposures and resizes, but remove usual events from queue,
1357 // as it can be disturbing to not have them acknowledged in real time,
1358 // because the program is busy, and suddenly all being acknowledged.
1359 // Also, the locator ("L" key) is sluggish if driven by the thread.
1360 //
1361 // But this approach is a problem when the thread removes events
1362 // from the queue while the program is responsible! The user hits 'L'
1363 // and nothing happens, as the thread removes it.
1364 //
1365 // Perhaps the "Q" key should have a different treatment, quiting the
1366 // program anyway?
1367 //
1368 // Changed: does not remove non treated events from the queue
1369 //
1370
1371 event_mask = ExposureMask | StructureNotifyMask;
1372
1373 // block all signal for this thread
1374 sigemptyset( &set );
1375 // sigfillset(&set); can't be all signals, decide latter
1376 sigaddset( &set, SIGINT );
1377
1378 sigprocmask( SIG_BLOCK, &set, NULL );
1379
1380 pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
1381 pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL );
1382
1383 delay.tv_sec = 0;
1384 delay.tv_nsec = 10000000; // this thread runs 10 times a second. (1/10 ms)
1385
1386 while ( 1 )
1387 {
1388 pthread_mutex_lock( &events_mutex );
1389
1390 if ( dev->is_main && !lpls->plbuf_read &&
1391 ++dev->instr % dev->max_instr == 0 )
1392 {
1393 dev->instr = 0;
1394 while ( XCheckWindowEvent( xwd->display, dev->window, event_mask, &event ) )
1395 {
1396 // As ResizeEH() ends up calling plRemakePlot(), that
1397 // indirectly uses the current stream, one needs to
1398 // temporarily set plplot current stream to this thread's
1399 // stream
1400
1401 oplsc = plsc;
1402 plsc = lpls;
1403 switch ( event.type )
1404 {
1405 case Expose:
1406 ExposeEH( lpls, &event );
1407 break;
1408 case ConfigureNotify:
1409 ResizeEH( lpls, &event );
1410 break;
1411 }
1412 plsc = oplsc;
1413 }
1414 }
1415
1416 pthread_mutex_unlock( &events_mutex );
1417 nanosleep( &delay, NULL ); // 10ms in linux
1418 /* pthread_yield(NULL); */ /* this puts too much load on the CPU */
1419 }
1420 }
1421 }
1422 #endif
1423
1424 //--------------------------------------------------------------------------
1425 // CheckForEvents()
1426 //
1427 // A front-end to HandleEvents(), which is only called if certain conditions
1428 // are satisfied:
1429 //
1430 // - must be the creator of the main window (i.e. PLplot is handling the
1431 // X event loop by polling).
1432 // - must not be in the middle of a plot redisplay (else the order of event
1433 // handling can become circuitous).
1434 // - only query X for events and process them every dev->max_instr times
1435 // this function is called (good for performance since querying X is a
1436 // nontrivial performance hit).
1437 //--------------------------------------------------------------------------
1438
1439 static void
1440 CheckForEvents( PLStream *pls )
1441 {
1442 XwDev *dev = (XwDev *) pls->dev;
1443
1444 if ( dev->is_main &&
1445 !pls->plbuf_read &&
1446 ++dev->instr % dev->max_instr == 0 )
1447 {
1448 dev->instr = 0;
1449 HandleEvents( pls );
1450 }
1451 }
1452
1453 //--------------------------------------------------------------------------
1454 // HandleEvents()
1455 //
1456 // Just a front-end to MasterEH(), for use when not actually waiting for an
1457 // event but only checking the event queue.
1458 //--------------------------------------------------------------------------
1459
1460 static void
1461 HandleEvents( PLStream *pls )
1462 {
1463 XwDev *dev = (XwDev *) pls->dev;
1464 XwDisplay *xwd = (XwDisplay *) dev->xwd;
1465 XEvent event;
1466
1467 while ( XCheckTypedWindowEvent( xwd->display, dev->window,
1468 ClientMessage, &event ) ||
1469 XCheckWindowEvent( xwd->display, dev->window,
1470 dev->event_mask, &event ) )
1471 MasterEH( pls, &event );
1472 }
1473
1474 //--------------------------------------------------------------------------
1475 // MasterEH()
1476 //
1477 // Master X event handler routine.
1478 // Redirects control to routines to handle:
1479 // - keyboard events
1480 // - mouse events
1481 // - expose events
1482 // - resize events
1483 //
1484 // By supplying a master event handler, the user can take over all event
1485 // processing. If events other than those trapped by PLplot need handling,
1486 // just call XSelectInput with the appropriate flags. The default PLplot
1487 // event handling can be modified arbitrarily by changing the event struct.
1488 //--------------------------------------------------------------------------
1489
1490 static void
1491 MasterEH( PLStream *pls, XEvent *event )
1492 {
1493 XwDev *dev = (XwDev *) pls->dev;
1494
1495 if ( dev->MasterEH != NULL )
1496 ( *dev->MasterEH )( pls, event );
1497
1498 switch ( event->type )
1499 {
1500 case KeyPress:
1501 KeyEH( pls, event );
1502 break;
1503
1504 case ButtonPress:
1505 ButtonEH( pls, event );
1506 break;
1507
1508 case Expose:
1509 ExposeEH( pls, event );
1510 break;
1511
1512 case ConfigureNotify:
1513 ResizeEH( pls, event );
1514 break;
1515
1516 case MotionNotify:
1517 if ( event->xmotion.state )
1518 ButtonEH( pls, event ); // drag
1519 MotionEH( pls, event );
1520 break;
1521
1522 case EnterNotify:
1523 EnterEH( pls, event );
1524 break;
1525
1526 case LeaveNotify:
1527 LeaveEH( pls, event );
1528 break;
1529
1530 case ClientMessage:
1531 ClientEH( pls, event );
1532 break;
1533 }
1534 }
1535
1536 //--------------------------------------------------------------------------
1537 // ClientEH()
1538 //
1539 // Event handler routine for client message events (WM_DELETE_WINDOW)
1540 //--------------------------------------------------------------------------
1541
1542 static void
1543 ClientEH( PLStream *pls, XEvent *event )
1544 {
1545 XwDev *dev = (XwDev *) pls->dev;
1546 XwDisplay *xwd = (XwDisplay *) dev->xwd;
1547
1548 if ( (Atom) event->xclient.data.l[0] == XInternAtom( xwd->display, "WM_DELETE_WINDOW", False ) )
1549 {
1550 pls->nopause = TRUE;
1551 pls->stream_closed = TRUE;
1552 dev->exit_eventloop = TRUE;
1553 // plexit( "" );
1554 }
1555 }
1556
1557
1558 //--------------------------------------------------------------------------
1559 // KeyEH()
1560 //
1561 // Event handler routine for keyboard events.
1562 //--------------------------------------------------------------------------
1563
1564 static void
1565 KeyEH( PLStream *pls, XEvent *event )
1566 {
1567 XwDev *dev = (XwDev *) pls->dev;
1568
1569 dbug_enter( "KeyEH" );
1570
1571 LookupXKeyEvent( pls, event );
1572 if ( dev->locate_mode )
1573 LocateKey( pls );
1574 else
1575 ProcessKey( pls );
1576 }
1577
1578 //--------------------------------------------------------------------------
1579 // ButtonEH()
1580 //
1581 // Event handler routine for ButtonPress events.
1582 //--------------------------------------------------------------------------
1583
1584 static void
1585 ButtonEH( PLStream *pls, XEvent *event )
1586 {
1587 XwDev *dev = (XwDev *) pls->dev;
1588
1589 dbug_enter( "ButtonEH" );
1590
1591 LookupXButtonEvent( pls, event );
1592 if ( dev->locate_mode )
1593 LocateButton( pls );
1594 else
1595 ProcessButton( pls );
1596 }
1597
1598 //--------------------------------------------------------------------------
1599 // LookupXKeyEvent()
1600 //
1601 // Fills in the PLGraphicsIn from an XKeyEvent. The PLGraphicsIn keysym is
1602 // the same as the X keysym for all cases except for control keys that have
1603 // ASCII equivalents, i.e.:
1604 //
1605 // Name X-keysym ASCII Ctrl-key
1606 // ---- -------- ----- --------
1607 // XK_BackSpace 0xFF08 0x08 ^H
1608 // XK_Tab 0xFF09 0x09 ^I
1609 // XK_Linefeed 0xFF0A 0x0A ^J
1610 // XK_Return 0xFF0D 0x0D ^M
1611 // XK_Escape 0xFF1B 0x1B ^[
1612 // XK_Delete 0xFFFF 0xFF (none)
1613 //
1614 // The ASCII representation of these characters is used for the PLGraphicsIn
1615 // keysym to simplify code logic. It turns out that the X keysyms are
1616 // identical to the ASCII values with the upper 8 bits set.
1617 //--------------------------------------------------------------------------
1618
1619 static void
1620 LookupXKeyEvent( PLStream *pls, XEvent *event )
1621 {
1622 XwDev *dev = (XwDev *) pls->dev;
1623 PLGraphicsIn *gin = &( dev->gin );
1624 XKeyEvent *keyEvent = (XKeyEvent *) event;
1625 KeySym keysym;
1626 int nchars, ncmax = PL_MAXKEY - 1;
1627 XComposeStatus cs;
1628
1629 gin->pX = keyEvent->x;
1630 gin->pY = keyEvent->y;
1631 gin->dX = (PLFLT) keyEvent->x / ( dev->width - 1 );
1632 gin->dY = 1.0 - (PLFLT) keyEvent->y / ( dev->height - 1 );
1633
1634 gin->state = keyEvent->state;
1635
1636 nchars = XLookupString( keyEvent, gin->string, ncmax, &keysym, &cs );
1637 gin->string[nchars] = '\0';
1638
1639 pldebug( "LookupXKeyEvent",
1640 "Keysym %x, translation: %s\n", keysym, gin->string );
1641
1642 switch ( keysym )
1643 {
1644 case XK_BackSpace:
1645 case XK_Tab:
1646 case XK_Linefeed:
1647 case XK_Return:
1648 case XK_Escape:
1649 case XK_Delete:
1650 gin->keysym = 0xFF & keysym;
1651 break;
1652
1653 default:
1654 gin->keysym = (unsigned int) keysym;
1655 }
1656 }
1657
1658 //--------------------------------------------------------------------------
1659 // LookupXButtonEvent()
1660 //
1661 // Fills in the PLGraphicsIn from an XButtonEvent.
1662 //--------------------------------------------------------------------------
1663
1664 static void
1665 LookupXButtonEvent( PLStream *pls, XEvent *event )
1666 {
1667 XwDev *dev = (XwDev *) pls->dev;
1668 PLGraphicsIn *gin = &( dev->gin );
1669 XButtonEvent *buttonEvent = (XButtonEvent *) event;
1670
1671 pldebug( "LookupXButtonEvent",
1672 "Button: %d, x: %d, y: %d\n",
1673 buttonEvent->button, buttonEvent->x, buttonEvent->y );
1674
1675 gin->pX = buttonEvent->x;
1676 gin->pY = buttonEvent->y;
1677 gin->dX = (PLFLT) buttonEvent->x / ( dev->width - 1 );
1678 gin->dY = 1.0 - (PLFLT) buttonEvent->y / ( dev->height - 1 );
1679
1680 gin->button = buttonEvent->button;
1681 gin->state = buttonEvent->state;
1682 gin->keysym = 0x20;
1683 }
1684
1685 //--------------------------------------------------------------------------
1686 // ProcessKey()
1687 //
1688 // Process keyboard events other than locate input.
1689 //--------------------------------------------------------------------------
1690
1691 static void
1692 ProcessKey( PLStream *pls )
1693 {
1694 XwDev *dev = (XwDev *) pls->dev;
1695 PLGraphicsIn *gin = &( dev->gin );
1696
1697 dbug_enter( "ProcessKey" );
1698
1699 // Call user keypress event handler. Since this is called first, the user
1700 // can disable all internal event handling by setting key.keysym to 0.
1701 //
1702 if ( pls->KeyEH != NULL )
1703 ( *pls->KeyEH )( gin, pls->KeyEH_data, &dev->exit_eventloop );
1704
1705 // Handle internal events
1706
1707 switch ( gin->keysym )
1708 {
1709 case PLK_Return:
1710 case PLK_Linefeed:
1711 case PLK_Next:
1712 // Advance to next page (i.e. terminate event loop) on a <eol>
1713 // Check for both <CR> and <LF> for portability, also a <Page Down>
1714 dev->exit_eventloop = TRUE;
1715 break;
1716
1717 case 'Q':
1718 // Terminate on a 'Q' (not 'q', since it's too easy to hit by mistake)
1719 pls->nopause = TRUE;
1720 plexit( "" );
1721 break;
1722
1723 case 'L':
1724 // Begin locate mode
1725 dev->locate_mode = LOCATE_INVOKED_VIA_DRIVER;
1726 CreateXhairs( pls );
1727 break;
1728 }
1729 }
1730
1731 //--------------------------------------------------------------------------
1732 // ProcessButton()
1733 //
1734 // Process ButtonPress events other than locate input.
1735 // On:
1736 // Button1: nothing (except when in locate mode, see ButtonLocate)
1737 // Button2: nothing
1738 // Button3: set page advance flag
1739 //--------------------------------------------------------------------------
1740
1741 static void
1742 ProcessButton( PLStream *pls )
1743 {
1744 XwDev *dev = (XwDev *) pls->dev;
1745 PLGraphicsIn *gin = &( dev->gin );
1746
1747 dbug_enter( "ProcessButton" );
1748
1749 // Call user event handler. Since this is called first, the user can
1750 // disable all PLplot internal event handling by setting gin->button to 0.
1751 //
1752 if ( pls->ButtonEH != NULL )
1753 ( *pls->ButtonEH )( gin, pls->ButtonEH_data, &dev->exit_eventloop );
1754
1755 // Handle internal events
1756
1757 switch ( gin->button )
1758 {
1759 case Button3:
1760 dev->exit_eventloop = TRUE;
1761 break;
1762 }
1763 }
1764
1765 //--------------------------------------------------------------------------
1766 // LocateKey()
1767 //
1768 // Front-end to locate handler for KeyPress events.
1769 // Provides for a number of special effects:
1770 //
1771 // <Escape> Ends locate mode
1772 // <Cursor> Moves cursor one pixel in the specified direction
1773 // <Mod-Cursor> Accelerated cursor movement (5x for each modifier)
1774 //--------------------------------------------------------------------------
1775
1776 static void
1777 LocateKey( PLStream *pls )
1778 {
1779 XwDev *dev = (XwDev *) pls->dev;
1780 XwDisplay *xwd = (XwDisplay *) dev->xwd;
1781 PLGraphicsIn *gin = &( dev->gin );
1782
1783 // End locate mode on <Escape>
1784
1785 if ( gin->keysym == PLK_Escape )
1786 {
1787 dev->locate_mode = 0;
1788 DestroyXhairs( pls );
1789 plGinInit( gin );
1790 }
1791
1792 // Ignore modifier keys
1793
1794 else if ( IsModifierKey( gin->keysym ) )
1795 {
1796 plGinInit( gin );
1797 }
1798
1799 // Now handle cursor keys
1800
1801 else if ( IsCursorKey( gin->keysym ) )
1802 {
1803 int x1, y1, dx = 0, dy = 0;
1804 int xmin = 0, xmax = (int) dev->width - 1, ymin = 0, ymax = (int) dev->height - 1;
1805
1806 switch ( gin->keysym )
1807 {
1808 case PLK_Left:
1809 dx = -1;
1810 break;
1811 case PLK_Right:
1812 dx = 1;
1813 break;
1814 case PLK_Up:
1815 dy = -1;
1816 break;
1817 case PLK_Down:
1818 dy = 1;
1819 break;
1820 }
1821
1822 // Each modifier key added increases the multiplication factor by 5
1823
1824 // Shift
1825
1826 if ( gin->state & 0x01 )
1827 {
1828 dx *= 5;
1829 dy *= 5;
1830 }
1831
1832 // Caps Lock
1833
1834 if ( gin->state & 0x02 )
1835 {
1836 dx *= 5;
1837 dy *= 5;
1838 }
1839
1840 // Control
1841
1842 if ( gin->state & 0x04 )
1843 {
1844 dx *= 5;
1845 dy *= 5;
1846 }
1847
1848 // Alt
1849
1850 if ( gin->state & 0x08 )
1851 {
1852 dx *= 5;
1853 dy *= 5;
1854 }
1855
1856 // Bounds checking so that we don't send cursor out of window
1857
1858 x1 = gin->pX + dx;
1859 y1 = gin->pY + dy;
1860
1861 if ( x1 < xmin )
1862 dx = xmin - gin->pX;
1863 if ( y1 < ymin )
1864 dy = ymin - gin->pY;
1865 if ( x1 > xmax )
1866 dx = xmax - gin->pX;
1867 if ( y1 > ymax )
1868 dy = ymax - gin->pY;
1869
1870 // Engage...
1871
1872 XWarpPointer( xwd->display, dev->window, None, 0, 0, 0, 0, dx, dy );
1873 plGinInit( gin );
1874 }
1875
1876 // Call ordinary locate handler
1877
1878 else
1879 {
1880 Locate( pls );
1881 }
1882 }
1883
1884 //--------------------------------------------------------------------------
1885 // LocateButton()
1886 //
1887 // Front-end to locate handler for ButtonPress events.
1888 // Only passes control to Locate() for Button1 presses.
1889 //--------------------------------------------------------------------------
1890
1891 static void
1892 LocateButton( PLStream *pls )
1893 {
1894 XwDev *dev = (XwDev *) pls->dev;
1895 PLGraphicsIn *gin = &( dev->gin );
1896
1897 switch ( gin->button )
1898 {
1899 case Button1:
1900 Locate( pls );
1901 break;
1902 }
1903 }
1904
1905 //--------------------------------------------------------------------------
1906 // Locate()
1907 //
1908 // Handles locate mode events.
1909 //
1910 // In locate mode: move cursor to desired location and select by pressing a
1911 // key or by clicking on the mouse (if available). Typically the world
1912 // coordinates of the selected point are reported.
1913 //
1914 // There are two ways to enter Locate mode -- via the API, or via a driver
1915 // command. The API entry point is the call plGetCursor(), which initiates
1916 // locate mode and does not return until input has been obtained. The
1917 // driver entry point is by entering a 'L' while the driver is waiting for
1918 // events.
1919 //
1920 // Locate mode input is reported in one of three ways:
1921 // 1. Through a returned PLGraphicsIn structure, when user has specified a
1922 // locate handler via (*pls->LocateEH).
1923 // 2. Through a returned PLGraphicsIn structure, when locate mode is invoked
1924 // by a plGetCursor() call.
1925 // 3. Through writes to stdout, when locate mode is invoked by a driver
1926 // command and the user has not supplied a locate handler.
1927 //
1928 // Hitting <Escape> will at all times end locate mode. Other keys will
1929 // typically be interpreted as locator input. Selecting a point out of
1930 // bounds will end locate mode unless the user overrides with a supplied
1931 // Locate handler.
1932 //--------------------------------------------------------------------------
1933
1934 static void
1935 Locate( PLStream *pls )
1936 {
1937 XwDev *dev = (XwDev *) pls->dev;
1938 PLGraphicsIn *gin = &( dev->gin );
1939
1940 // Call user locate mode handler if provided
1941
1942 if ( pls->LocateEH != NULL )
1943 ( *pls->LocateEH )( gin, pls->LocateEH_data, &dev->locate_mode );
1944
1945 // Use default procedure
1946
1947 else
1948 {
1949 // Try to locate cursor
1950
1951 if ( plTranslateCursor( gin ) )
1952 {
1953 // If invoked by the API, we're done
1954 // Otherwise send report to stdout
1955
1956 if ( dev->locate_mode == LOCATE_INVOKED_VIA_DRIVER )
1957 {
1958 pltext();
1959 if ( gin->keysym < 0xFF && isprint( gin->keysym ) )
1960 printf( "%f %f %c\n", gin->wX, gin->wY, gin->keysym );
1961 else
1962 printf( "%f %f 0x%02x\n", gin->wX, gin->wY, gin->keysym );
1963
1964 plgra();
1965 }
1966 }
1967 else
1968 {
1969 // Selected point is out of bounds, so end locate mode
1970
1971 dev->locate_mode = 0;
1972 DestroyXhairs( pls );
1973 }
1974 }
1975 }
1976
1977 //--------------------------------------------------------------------------
1978 // MotionEH()
1979 //
1980 // Event handler routine for MotionNotify events.
1981 // If drawing crosshairs, the first and last draws must be done "by hand".
1982 //--------------------------------------------------------------------------
1983
1984 static void
1985 MotionEH( PLStream *pls, XEvent *event )
1986 {
1987 XwDev *dev = (XwDev *) pls->dev;
1988 XMotionEvent *motionEvent = (XMotionEvent *) event;
1989
1990 if ( dev->drawing_xhairs )
1991 {
1992 DrawXhairs( pls, motionEvent->x, motionEvent->y );
1993 }
1994 }
1995
1996 //--------------------------------------------------------------------------
1997 // EnterEH()
1998 //
1999 // Event handler routine for EnterNotify events. Only called if drawing
2000 // crosshairs -- a draw must be done here to start off the new set.
2001 //--------------------------------------------------------------------------
2002
2003 static void
2004 EnterEH( PLStream *pls, XEvent *event )
2005 {
2006 XwDev *dev = (XwDev *) pls->dev;
2007 XCrossingEvent *crossingEvent = (XCrossingEvent *) event;
2008
2009 DrawXhairs( pls, crossingEvent->x, crossingEvent->y );
2010 dev->drawing_xhairs = 1;
2011 }
2012
2013 //--------------------------------------------------------------------------
2014 // LeaveEH()
2015 //
2016 // Event handler routine for EnterNotify or LeaveNotify events.
2017 // If drawing crosshairs, a draw must be done here to start off the new
2018 // set or erase the last set.
2019 //--------------------------------------------------------------------------
2020
2021 static void
2022 LeaveEH( PLStream *pls, XEvent * PL_UNUSED( event ) )
2023 {
2024 XwDev *dev = (XwDev *) pls->dev;
2025
2026 UpdateXhairs( pls );
2027 dev->drawing_xhairs = 0;
2028 }
2029
2030 //--------------------------------------------------------------------------
2031 // CreateXhairs()
2032 //
2033 // Creates graphic crosshairs at current pointer location.
2034 //--------------------------------------------------------------------------
2035
2036 static void
2037 CreateXhairs( PLStream *pls )
2038 {
2039 XwDev *dev = (XwDev *) pls->dev;
2040 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2041 Window root, child;
2042 int root_x, root_y, win_x, win_y;
2043 unsigned int mask;
2044 XEvent event;
2045
2046 // Get a crosshair cursor and switch to it.
2047
2048 if ( !xwd->xhair_cursor )
2049 xwd->xhair_cursor = XCreateFontCursor( xwd->display, XC_crosshair );
2050
2051 XDefineCursor( xwd->display, dev->window, xwd->xhair_cursor );
2052
2053 // Find current pointer location and draw graphic crosshairs if pointer is
2054 // inside our window
2055
2056 if ( XQueryPointer( xwd->display, dev->window, &root, &child,
2057 &root_x, &root_y, &win_x, &win_y, &mask ) )
2058 {
2059 if ( win_x >= 0 && win_x < (int) dev->width &&
2060 win_y >= 0 && win_y < (int) dev->height )
2061 {
2062 DrawXhairs( pls, win_x, win_y );
2063 dev->drawing_xhairs = 1;
2064 }
2065 }
2066
2067 // Sync the display and then throw away all pending motion events
2068
2069 XSync( xwd->display, 0 );
2070 while ( XCheckWindowEvent( xwd->display, dev->window,
2071 PointerMotionMask, &event ) )
2072 ;
2073
2074 // Catch PointerMotion and crossing events so we can update them properly
2075
2076 dev->event_mask |= PointerMotionMask | EnterWindowMask | LeaveWindowMask;
2077 XSelectInput( xwd->display, dev->window, dev->event_mask );
2078 }
2079
2080 //--------------------------------------------------------------------------
2081 // DestroyXhairs()
2082 //
2083 // Destroys graphic crosshairs.
2084 //--------------------------------------------------------------------------
2085
2086 static void
2087 DestroyXhairs( PLStream *pls )
2088 {
2089 XwDev *dev = (XwDev *) pls->dev;
2090 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2091
2092 // Switch back to boring old pointer
2093
2094 XUndefineCursor( xwd->display, dev->window );
2095
2096 // Don't catch PointerMotion or crossing events any more
2097
2098 dev->event_mask &=
2099 ~PointerMotionMask & ~EnterWindowMask & ~LeaveWindowMask;
2100 XSelectInput( xwd->display, dev->window, dev->event_mask );
2101
2102 // This draw removes the last set of graphic crosshairs
2103
2104 UpdateXhairs( pls );
2105 dev->drawing_xhairs = 0;
2106 }
2107
2108 //--------------------------------------------------------------------------
2109 // DrawXhairs()
2110 //
2111 // Draws graphic crosshairs at (x0, y0). The first draw erases the old set.
2112 //--------------------------------------------------------------------------
2113
2114 static void
2115 DrawXhairs( PLStream *pls, int x0, int y0 )
2116 {
2117 XwDev *dev = (XwDev *) pls->dev;
2118
2119 int xmin = 0, xmax = (int) dev->width - 1;
2120 int ymin = 0, ymax = (int) dev->height - 1;
2121
2122 if ( dev->drawing_xhairs )
2123 UpdateXhairs( pls );
2124
2125 dev->xhair_x[0].x = (short) xmin; dev->xhair_x[0].y = (short) y0;
2126 dev->xhair_x[1].x = (short) xmax; dev->xhair_x[1].y = (short) y0;
2127
2128 dev->xhair_y[0].x = (short) x0; dev->xhair_y[0].y = (short) ymin;
2129 dev->xhair_y[1].x = (short) x0; dev->xhair_y[1].y = (short) ymax;
2130
2131 UpdateXhairs( pls );
2132 }
2133
2134 //--------------------------------------------------------------------------
2135 // UpdateXhairs()
2136 //
2137 // Updates graphic crosshairs. If already there, they are erased.
2138 //--------------------------------------------------------------------------
2139
2140 static void
2141 UpdateXhairs( PLStream *pls )
2142 {
2143 XwDev *dev = (XwDev *) pls->dev;
2144 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2145
2146 XDrawLines( xwd->display, dev->window, xwd->gcXor, dev->xhair_x, 2,
2147 CoordModeOrigin );
2148
2149 XDrawLines( xwd->display, dev->window, xwd->gcXor, dev->xhair_y, 2,
2150 CoordModeOrigin );
2151 }
2152
2153 //--------------------------------------------------------------------------
2154 // ExposeEH()
2155 //
2156 // Event handler routine for expose events.
2157 // Front end to ExposeCmd() to deal with wierdnesses of Xlib.
2158 //--------------------------------------------------------------------------
2159
2160 static void
2161 ExposeEH( PLStream *pls, XEvent *event )
2162 {
2163 XwDev *dev = (XwDev *) pls->dev;
2164 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2165 XExposeEvent *exposeEvent = (XExposeEvent *) event;
2166 PLDisplay pldis;
2167 int redrawn;
2168
2169 dbug_enter( "ExposeEH" );
2170
2171 pldebug( "ExposeEH",
2172 "x = %d, y = %d, width = %d, height = %d, count = %d, pending = %d\n",
2173 exposeEvent->x, exposeEvent->y,
2174 exposeEvent->width, exposeEvent->height,
2175 exposeEvent->count, XPending( xwd->display ) );
2176
2177 // Handle expose
2178 // If we have anything overlaid (like crosshairs), we need to refresh the
2179 // entire plot in order to have a predictable outcome. In this case we
2180 // need to first clear window. Otherwise it's better to not clear it, for a
2181 // smoother redraw (unobscured regions appear to stay the same).
2182
2183 if ( dev->drawing_xhairs )
2184 {
2185 XClearWindow( xwd->display, dev->window );
2186 ExposeCmd( pls, NULL );
2187 UpdateXhairs( pls );
2188 redrawn = 1;
2189 }
2190 else
2191 {
2192 pldis.x = (unsigned int) exposeEvent->x;
2193 pldis.y = (unsigned int) exposeEvent->y;
2194 pldis.width = (unsigned int) exposeEvent->width;
2195 pldis.height = (unsigned int) exposeEvent->height;
2196
2197 ExposeCmd( pls, &pldis );
2198 redrawn = !dev->write_to_pixmap;
2199 }
2200
2201 // If entire plot was redrawn, remove extraneous events from the queue
2202
2203 if ( redrawn )
2204 while ( XCheckWindowEvent( xwd->display, dev->window,
2205 ExposureMask | StructureNotifyMask, event ) )
2206 ;
2207 }
2208
2209 //--------------------------------------------------------------------------
2210 // ResizeEH()
2211 //
2212 // Event handler routine for resize events.
2213 // Front end to ResizeCmd() to deal with wierdnesses of Xlib.
2214 //--------------------------------------------------------------------------
2215
2216 static void
2217 ResizeEH( PLStream *pls, XEvent *event )
2218 {
2219 XwDev *dev = (XwDev *) pls->dev;
2220 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2221 XConfigureEvent *configEvent = (XConfigureEvent *) event;
2222 PLDisplay pldis;
2223
2224 dbug_enter( "ResizeEH" );
2225
2226 pldis.width = (unsigned int) configEvent->width;
2227 pldis.height = (unsigned int) configEvent->height;
2228
2229 // Only need to resize if size is actually changed
2230
2231 if ( pldis.width == dev->width && pldis.height == dev->height )
2232 return;
2233
2234 pldebug( "ResizeEH",
2235 "x = %d, y = %d, pending = %d\n",
2236 configEvent->width, configEvent->height, XPending( xwd->display ) );
2237
2238 // Handle resize
2239
2240 ResizeCmd( pls, &pldis );
2241 if ( dev->drawing_xhairs )
2242 {
2243 UpdateXhairs( pls );
2244 }
2245
2246 // Remove extraneous Expose and ConfigureNotify events from the event queue
2247 // Exposes do not need to be handled since we've redrawn the whole plot
2248
2249 XFlush( xwd->display );
2250 while ( XCheckWindowEvent( xwd->display, dev->window,
2251 ExposureMask | StructureNotifyMask, event ) )
2252 ;
2253 }
2254
2255 //--------------------------------------------------------------------------
2256 // ExposeCmd()
2257 //
2258 // Event handler routine for expose events.
2259 // These are "pure" exposures (no resize), so don't need to clear window.
2260 //--------------------------------------------------------------------------
2261
2262 static void
2263 ExposeCmd( PLStream *pls, PLDisplay *pldis )
2264 {
2265 XwDev *dev = (XwDev *) pls->dev;
2266 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2267 int x, y;
2268 unsigned int width, height;
2269
2270 dbug_enter( "ExposeCmd" );
2271
2272 // Return if plD_init_xw hasn't been called yet
2273
2274 if ( dev == NULL )
2275 {
2276 plwarn( "ExposeCmd: Illegal call -- driver uninitialized" );
2277 return;
2278 }
2279
2280 // Exposed area. If unspecified, the entire window is used.
2281
2282 if ( pldis == NULL )
2283 {
2284 x = 0;
2285 y = 0;
2286 width = dev->width;
2287 height = dev->height;
2288 }
2289 else
2290 {
2291 x = (int) pldis->x;
2292 y = (int) pldis->y;
2293 width = pldis->width;
2294 height = pldis->height;
2295 }
2296
2297 // Usual case: refresh window from pixmap
2298 // DEBUG option: draws rectangle around refreshed region
2299
2300 XSync( xwd->display, 0 );
2301 if ( dev->write_to_pixmap )
2302 {
2303 XCopyArea( xwd->display, dev->pixmap, dev->window, dev->gc,
2304 x, y, width, height, x, y );
2305 XSync( xwd->display, 0 );
2306 #ifdef DEBUG
2307 if ( pls->debug )
2308 {
2309 XPoint pts[5];
2310 int x0 = x, x1 = x + (int) width, y0 = y, y1 = y + (int) height;
2311 pts[0].x = (short) x0; pts[0].y = (short) y0;
2312 pts[1].x = (short) x1; pts[1].y = (short) y0;
2313 pts[2].x = (short) x1; pts[2].y = (short) y1;
2314 pts[3].x = (short) x0; pts[3].y = (short) y1;
2315 pts[4].x = (short) x0; pts[4].y = (short) y0;
2316
2317 XDrawLines( xwd->display, dev->window, dev->gc, pts, 5,
2318 CoordModeOrigin );
2319 }
2320 #endif
2321 }
2322 else
2323 {
2324 plRemakePlot( pls );
2325 XFlush( xwd->display );
2326 }
2327 }
2328
2329 //--------------------------------------------------------------------------
2330 // ResizeCmd()
2331 //
2332 // Event handler routine for resize events.
2333 //--------------------------------------------------------------------------
2334
2335 static void
2336 ResizeCmd( PLStream *pls, PLDisplay *pldis )
2337 {
2338 XwDev *dev = (XwDev *) pls->dev;
2339 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2340 int write_to_window = dev->write_to_window;
2341
2342 dbug_enter( "ResizeCmd" );
2343
2344 // Return if plD_init_xw hasn't been called yet
2345
2346 if ( dev == NULL )
2347 {
2348 plwarn( "ResizeCmd: Illegal call -- driver uninitialized" );
2349 return;
2350 }
2351
2352 // Return if pointer to window not specified.
2353
2354 if ( pldis == NULL )
2355 {
2356 plwarn( "ResizeCmd: Illegal call -- window pointer uninitialized" );
2357 return;
2358 }
2359
2360 // Reset current window bounds
2361
2362 dev->width = pldis->width;
2363 dev->height = pldis->height;
2364
2365 dev->xscale = dev->width / (double) dev->init_width;
2366 dev->yscale = dev->height / (double) dev->init_height;
2367
2368 dev->xscale = dev->xscale * dev->xscale_init;
2369 dev->yscale = dev->yscale * dev->yscale_init;
2370
2371 #if PHYSICAL
2372 {
2373 PLFLT pxlx = DPMM / dev->xscale;
2374 PLFLT pxly = DPMM / dev->yscale;
2375 plP_setpxl( pxlx, pxly );
2376 }
2377 #endif
2378
2379 // Note: the following order MUST be obeyed -- if you instead redraw into
2380 // the window and then copy it to the pixmap, off-screen parts of the window
2381 // may contain garbage which is then transferred to the pixmap (and thus
2382 // will not go away after an expose).
2383 //
2384
2385 // Resize pixmap using new dimensions
2386
2387 if ( dev->write_to_pixmap )
2388 {
2389 dev->write_to_window = 0;
2390 XFreePixmap( xwd->display, dev->pixmap );
2391 CreatePixmap( pls );
2392 }
2393
2394 // This allows an external agent to take over the redraw
2395 if ( pls->ext_resize_draw )
2396 return;
2397
2398 // Initialize & redraw (to pixmap, if available).
2399
2400 if ( dev->write_to_pixmap )
2401 {
2402 XSetForeground( xwd->display, dev->gc, dev->bgcolor.pixel );
2403 XFillRectangle( xwd->display, dev->pixmap, dev->gc, 0, 0,
2404 dev->width, dev->height );
2405 XSetForeground( xwd->display, dev->gc, dev->curcolor.pixel );
2406 }
2407 if ( dev->write_to_window )
2408 {
2409 XClearWindow( xwd->display, dev->window );
2410 }
2411 plRemakePlot( pls );
2412 XSync( xwd->display, 0 );
2413
2414 // If pixmap available, fake an expose
2415
2416 if ( dev->write_to_pixmap )
2417 {
2418 dev->write_to_window = write_to_window;
2419 XCopyArea( xwd->display, dev->pixmap, dev->window, dev->gc, 0, 0,
2420 dev->width, dev->height, 0, 0 );
2421 XSync( xwd->display, 0 );
2422 }
2423 }
2424
2425 //--------------------------------------------------------------------------
2426 // ConfigBufferingCmd()
2427 //
2428 // Allows a widget to manipulate the double buffering support in the
2429 // xwin dirver.
2430 //--------------------------------------------------------------------------
2431
2432 static void ConfigBufferingCmd( PLStream *pls, PLBufferingCB *ptr )
2433 {
2434 XwDev *dev = (XwDev *) pls->dev;
2435
2436 switch ( ptr->cmd )
2437 {
2438 case PLESC_DOUBLEBUFFERING_ENABLE:
2439 dev->write_to_window = 0;
2440 pls->db = 1;
2441 break;
2442
2443 case PLESC_DOUBLEBUFFERING_DISABLE:
2444 dev->write_to_window = 1;
2445 pls->db = 0;
2446 break;
2447
2448 case PLESC_DOUBLEBUFFERING_QUERY:
2449 ptr->result = pls->db;
2450 break;
2451
2452 default:
2453 printf( "Unrecognized buffering request ignored.\n" );
2454 break;
2455 }
2456 }
2457
2458 //--------------------------------------------------------------------------
2459 // RedrawCmd()
2460 //
2461 // Handles page redraw without resize (pixmap does not get reallocated).
2462 // Calling this makes sure all necessary housekeeping gets done.
2463 //--------------------------------------------------------------------------
2464
2465 static void
2466 RedrawCmd( PLStream *pls )
2467 {
2468 XwDev *dev = (XwDev *) pls->dev;
2469 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2470 int write_to_window = dev->write_to_window;
2471
2472 dbug_enter( "RedrawCmd" );
2473
2474 // Return if plD_init_xw hasn't been called yet
2475
2476 if ( dev == NULL )
2477 {
2478 plwarn( "RedrawCmd: Illegal call -- driver uninitialized" );
2479 return;
2480 }
2481
2482 // Initialize & redraw (to pixmap, if available).
2483
2484 if ( dev->write_to_pixmap )
2485 {
2486 dev->write_to_window = 0;
2487 XSetForeground( xwd->display, dev->gc, dev->bgcolor.pixel );
2488 XFillRectangle( xwd->display, dev->pixmap, dev->gc, 0, 0,
2489 dev->width, dev->height );
2490 XSetForeground( xwd->display, dev->gc, dev->curcolor.pixel );
2491 }
2492 if ( dev->write_to_window )
2493 {
2494 XClearWindow( xwd->display, dev->window );
2495 }
2496 plRemakePlot( pls );
2497 XSync( xwd->display, 0 );
2498
2499 dev->write_to_window = write_to_window;
2500
2501 // If pixmap available, fake an expose
2502
2503 if ( dev->write_to_pixmap )
2504 {
2505 XCopyArea( xwd->display, dev->pixmap, dev->window, dev->gc, 0, 0,
2506 dev->width, dev->height, 0, 0 );
2507 XSync( xwd->display, 0 );
2508 }
2509 }
2510
2511 //--------------------------------------------------------------------------
2512 // CreatePixmapErrorHandler()
2513 //
2514 // Error handler used in CreatePixmap() to catch errors in allocating
2515 // storage for pixmap. This way we can nicely substitute redraws for
2516 // pixmap copies if the server has insufficient memory.
2517 //--------------------------------------------------------------------------
2518
2519 static unsigned char CreatePixmapStatus;
2520
2521 static int
2522 CreatePixmapErrorHandler( Display *display, XErrorEvent *error )
2523 {
2524 CreatePixmapStatus = error->error_code;
2525 if ( error->error_code != BadAlloc )
2526 {
2527 char buffer[256];
2528 XGetErrorText( display, error->error_code, buffer, 256 );
2529 fprintf( stderr, "Error in XCreatePixmap: %s.\n", buffer );
2530 }
2531 return 1;
2532 }
2533
2534 //--------------------------------------------------------------------------
2535 // CreatePixmap()
2536 //
2537 // This routine creates a pixmap, doing error trapping in case there
2538 // isn't enough memory on the server.
2539 //--------------------------------------------------------------------------
2540
2541 static void
2542 CreatePixmap( PLStream *pls )
2543 {
2544 XwDev *dev = (XwDev *) pls->dev;
2545 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2546
2547 int ( *oldErrorHandler )( Display *, XErrorEvent * );
2548
2549 oldErrorHandler = XSetErrorHandler( CreatePixmapErrorHandler );
2550
2551 CreatePixmapStatus = Success;
2552 pldebug( "CreatePixmap",
2553 "creating pixmap: width = %d, height = %d, depth = %d\n",
2554 dev->width, dev->height, xwd->depth );
2555
2556 dev->pixmap = XCreatePixmap( xwd->display, dev->window,
2557 dev->width, dev->height, xwd->depth );
2558 XSync( xwd->display, 0 );
2559 if ( CreatePixmapStatus != Success )
2560 {
2561 dev->write_to_pixmap = 0;
2562 dev->write_to_window = 1;
2563 pls->db = 0;
2564 fprintf( stderr, "\n\
2565 Warning: pixmap could not be allocated (insufficient memory on server).\n\
2566 Driver will redraw the entire plot to handle expose events.\n" );
2567 }
2568
2569 XSetErrorHandler( oldErrorHandler );
2570 }
2571
2572 //--------------------------------------------------------------------------
2573 // GetVisual()
2574 //
2575 // Get visual info. In order to safely use a visual other than that of
2576 // the parent (which hopefully is that returned by DefaultVisual), you
2577 // must first find (using XGetRGBColormaps) or create a colormap matching
2578 // this visual and then set the colormap window attribute in the
2579 // XCreateWindow attributes and valuemask arguments. I don't do this
2580 // right now, so this is turned off by default.
2581 //--------------------------------------------------------------------------
2582
2583 static void
2584 GetVisual( PLStream *pls )
2585 {
2586 XwDev *dev = (XwDev *) pls->dev;
2587 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2588 int visuals_matched = 0;
2589
2590 dbug_enter( "GetVisual" );
2591
2592 if ( !defaultvisual )
2593 {
2594 XVisualInfo vTemplate, *visualList;
2595
2596 // Try for an 8 plane display, if unavailable go for the default
2597
2598 vTemplate.screen = xwd->screen;
2599 vTemplate.depth = 8;
2600
2601 visualList = XGetVisualInfo( xwd->display,
2602 VisualScreenMask | VisualDepthMask,
2603 &vTemplate, &visuals_matched );
2604
2605 #ifdef HACK_STATICCOLOR
2606 if ( visuals_matched )
2607 {
2608 int i, found = 0;
2609 printf( "visuals_matched = %d\n", visuals_matched );
2610 for ( i = 0; i < visuals_matched && !found; i++ )
2611 {
2612 Visual *v = visualList[i].visual;
2613 printf( "Checking visual %d: ", i );
2614 switch ( v->class )
2615 {
2616 case PseudoColor:
2617 printf( "PseudoColor\n" );
2618 break;
2619 case GrayScale:
2620 printf( "GrayScale\n" );
2621 break;
2622 case DirectColor:
2623 printf( "DirectColor\n" );
2624 break;
2625 case TrueColor:
2626 printf( "TrueColor\n" );
2627 break;
2628 case StaticColor:
2629 printf( "StaticColor\n" );
2630 break;
2631 case StaticGray:
2632 printf( "StaticGray\n" );
2633 break;
2634 default:
2635 printf( "Unknown.\n" );
2636 break;
2637 }
2638 if ( v->class == StaticColor )
2639 {
2640 xwd->visual = v;
2641 xwd->depth = visualList[i].depth;
2642 found = 1;
2643 }
2644 }
2645 if ( !found )
2646 {
2647 plexit( "Unable to get a StaticColor visual." );
2648 }
2649 printf( "Found StaticColor visual, depth=%d\n", xwd->depth );
2650 }
2651 #else
2652 if ( visuals_matched )
2653 {
2654 xwd->visual = visualList->visual; // Choose first match.
2655 xwd->depth = (unsigned int) vTemplate.depth;
2656 }
2657 #endif // HACK_STATICCOLOR
2658 }
2659
2660 if ( !visuals_matched )
2661 {
2662 xwd->visual = DefaultVisual( xwd->display, xwd->screen );
2663 xwd->depth = (unsigned int) DefaultDepth( xwd->display, xwd->screen );
2664 }
2665
2666 // Check to see if we expect to be able to allocate r/w color cells.
2667
2668 switch ( xwd->visual->class )
2669 {
2670 case TrueColor:
2671 case StaticColor:
2672 case StaticGray:
2673 xwd->rw_cmap = 0;
2674 break;
2675 default:
2676 xwd->rw_cmap = 1;
2677 }
2678
2679 /*xwd->rw_cmap = 0;*/ /* debugging hack. */
2680
2681 // Just for kicks, see what kind of visual we got.
2682
2683 if ( pls->verbose )
2684 {
2685 fprintf( stderr, "XVisual class == " );
2686 switch ( xwd->visual->class )
2687 {
2688 case PseudoColor:
2689 fprintf( stderr, "PseudoColor\n" );
2690 break;
2691 case GrayScale:
2692 fprintf( stderr, "GrayScale\n" );
2693 break;
2694 case DirectColor:
2695 fprintf( stderr, "DirectColor\n" );
2696 break;
2697 case TrueColor:
2698 fprintf( stderr, "TrueColor\n" );
2699 break;
2700 case StaticColor:
2701 fprintf( stderr, "StaticColor\n" );
2702 break;
2703 case StaticGray:
2704 fprintf( stderr, "StaticGray\n" );
2705 break;
2706 default:
2707 fprintf( stderr, "Unknown.\n" );
2708 break;
2709 }
2710 fprintf( stderr, "xwd->rw_cmap = %d\n", xwd->rw_cmap );
2711 }
2712 }
2713
2714 //--------------------------------------------------------------------------
2715 // AllocBGFG()
2716 //
2717 // Allocate background & foreground colors. If possible, I choose pixel
2718 // values such that the fg pixel is the xor of the bg pixel, to make
2719 // rubber-banding easy to see.
2720 //--------------------------------------------------------------------------
2721
2722 static void
2723 AllocBGFG( PLStream *pls )
2724 {
2725 XwDev *dev = (XwDev *) pls->dev;
2726 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2727
2728 int i, j, npixels;
2729 unsigned long plane_masks[1], pixels[RWMAP_MAX_COLORS];
2730
2731 dbug_enter( "AllocBGFG" );
2732
2733 // If not on a color system, just return
2734 if ( !xwd->color )
2735 return;
2736
2737 if ( xwd->rw_cmap &&
2738 // r/w color maps
2739 XAllocColorCells( xwd->display, xwd->map, False,
2740 plane_masks, 0, pixels, 1 ) )
2741 {
2742 // background
2743 xwd->cmap0[0].pixel = pixels[0];
2744 }
2745 else
2746 {
2747 // r/o color maps
2748 xwd->cmap0[0].pixel = BlackPixel( xwd->display, xwd->screen );
2749 xwd->fgcolor.pixel = WhitePixel( xwd->display, xwd->screen );
2750 if ( xwd->rw_cmap && pls->verbose )
2751 fprintf( stderr, "Downgrading to r/o cmap.\n" );
2752 xwd->rw_cmap = 0;
2753 return;
2754 }
2755
2756 // Allocate as many colors as we can
2757
2758 npixels = RWMAP_MAX_COLORS;
2759 for (;; )
2760 {
2761 if ( XAllocColorCells( xwd->display, xwd->map, False,
2762 plane_masks, 0, pixels, (unsigned int) npixels ) )
2763 break;
2764 npixels--;
2765 if ( npixels == 0 )
2766 break;
2767 }
2768
2769 // Find the color with pixel = xor of the bg color pixel.
2770 // If a match isn't found, the last pixel allocated is used.
2771
2772 for ( i = 0; i < npixels - 1; i++ )
2773 {
2774 if ( pixels[i] == ( ~xwd->cmap0[0].pixel & 0xFF ) )
2775 break;
2776 }
2777
2778 // Use this color cell for our foreground color. Then free the rest.
2779
2780 xwd->fgcolor.pixel = pixels[i];
2781 for ( j = 0; j < npixels; j++ )
2782 {
2783 if ( j != i )
2784 XFreeColors( xwd->display, xwd->map, &pixels[j], 1, 0 );
2785 }
2786 }
2787
2788 //--------------------------------------------------------------------------
2789 // SetBGFG()
2790 //
2791 // Set background & foreground colors. Foreground over background should
2792 // have high contrast.
2793 //--------------------------------------------------------------------------
2794
2795 static void
2796 SetBGFG( PLStream *pls )
2797 {
2798 XwDev *dev = (XwDev *) pls->dev;
2799 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2800
2801 PLColor fgcolor;
2802 unsigned int gslevbg, gslevfg;
2803
2804 dbug_enter( "SetBGFG" );
2805
2806 //
2807 // Set background color.
2808 //
2809 // Background defaults to black on color screens, white on grayscale (many
2810 // grayscale monitors have poor contrast, and black-on-white looks better).
2811 //
2812
2813 if ( !xwd->color )
2814 {
2815 pls->cmap0[0].r = pls->cmap0[0].g = pls->cmap0[0].b = 0xFF;
2816 }
2817 gslevbg = (unsigned int) ( ( (long) pls->cmap0[0].r +
2818 (long) pls->cmap0[0].g +
2819 (long) pls->cmap0[0].b ) / 3 );
2820
2821 PLColor_to_XColor( &pls->cmap0[0], &xwd->cmap0[0] );
2822
2823 //
2824 // Set foreground color.
2825 //
2826 // Used for grayscale output, since otherwise the plots can become nearly
2827 // unreadable (i.e. if colors get mapped onto grayscale values). In this
2828 // case it becomes the grayscale level for all draws, and is taken to be
2829 // black if the background is light, and white if the background is dark.
2830 // Note that white/black allocations never fail.
2831 //
2832
2833 if ( gslevbg > 0x7F )
2834 gslevfg = 0;
2835 else
2836 gslevfg = 0xFF;
2837
2838 fgcolor.r = fgcolor.g = fgcolor.b = (unsigned char) gslevfg;
2839
2840 PLColor_to_XColor( &fgcolor, &xwd->fgcolor );
2841
2842 // Now store
2843
2844 if ( xwd->rw_cmap && xwd->color )
2845 {
2846 XStoreColor( xwd->display, xwd->map, &xwd->fgcolor );
2847 XStoreColor( xwd->display, xwd->map, &xwd->cmap0[0] );
2848 }
2849 else
2850 {
2851 XAllocColor( xwd->display, xwd->map, &xwd->cmap0[0] );
2852 XAllocColor( xwd->display, xwd->map, &xwd->fgcolor );
2853 }
2854 }
2855
2856 //--------------------------------------------------------------------------
2857 // InitColors()
2858 //
2859 // Does all color initialization.
2860 //--------------------------------------------------------------------------
2861
2862 static void
2863 InitColors( PLStream *pls )
2864 {
2865 XwDev *dev = (XwDev *) pls->dev;
2866 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2867
2868 dbug_enter( "InitColors" );
2869
2870 // Allocate and initialize color maps.
2871 // Defer cmap1 allocation until it's actually used
2872
2873 if ( xwd->color )
2874 {
2875 if ( plplot_ccmap )
2876 {
2877 AllocCustomMap( pls );
2878 }
2879 else
2880 {
2881 AllocCmap0( pls );
2882 }
2883 }
2884 }
2885
2886 //--------------------------------------------------------------------------
2887 // AllocCustomMap()
2888 //
2889 // Initializes custom color map and all the cruft that goes with it.
2890 //
2891 // Assuming all color X displays do 256 colors, the breakdown is as follows:
2892 //
2893 // CCMAP_XWM_COLORS
2894 // Number of low "pixel" values to copy. These are typically allocated
2895 // first, thus are in use by the window manager. I copy them to reduce
2896 // flicker.
2897 //
2898 //
2899 // RWMAP_CMAP1_COLORS
2900 // Color map 1 entries. There should be as many as practical available
2901 // for smooth shading. On the order of 50-100 is pretty reasonable. You
2902 // don't really need all 256, especially if all you're going to do is to
2903 // print it to postscript (which doesn't have any intrinsic limitation on
2904 // the number of colors).
2905 //
2906 // It's important to leave some extra colors unallocated for Tk. In
2907 // particular the palette tools require a fair amount. I recommend leaving
2908 // at least 40 or so free.
2909 //--------------------------------------------------------------------------
2910
2911 static void
2912 AllocCustomMap( PLStream *pls )
2913 {
2914 XwDev *dev = (XwDev *) pls->dev;
2915 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2916
2917 XColor xwm_colors[RWMAP_MAX_COLORS];
2918 int i, npixels;
2919 unsigned long plane_masks[1], pixels[RWMAP_MAX_COLORS];
2920
2921 dbug_enter( "AllocCustomMap" );
2922
2923 // Determine current default colors
2924
2925 for ( i = 0; i < RWMAP_MAX_COLORS; i++ )
2926 {
2927 xwm_colors[i].pixel = (unsigned long int) i;
2928 }
2929 XQueryColors( xwd->display, xwd->map, xwm_colors, RWMAP_MAX_COLORS );
2930
2931 // Allocate cmap0 colors in the default colormap.
2932 // The custom cmap0 colors are later stored at the same pixel values.
2933 // This is a really cool trick to reduce the flicker when changing colormaps.
2934 //
2935
2936 AllocCmap0( pls );
2937 XAllocColor( xwd->display, xwd->map, &xwd->fgcolor );
2938
2939 // Create new color map
2940
2941 xwd->map = XCreateColormap( xwd->display, DefaultRootWindow( xwd->display ),
2942 xwd->visual, AllocNone );
2943
2944 // Now allocate all colors so we can fill the ones we want to copy
2945
2946 npixels = RWMAP_MAX_COLORS;
2947 for (;; )
2948 {
2949 if ( XAllocColorCells( xwd->display, xwd->map, False,
2950 plane_masks, 0, pixels, (unsigned int) npixels ) )
2951 break;
2952 npixels--;
2953 if ( npixels == 0 )
2954 plexit( "couldn't allocate any colors" );
2955 }
2956
2957 // Fill the low colors since those are in use by the window manager
2958
2959 for ( i = 0; i < CCMAP_XWM_COLORS; i++ )
2960 {
2961 XStoreColor( xwd->display, xwd->map, &xwm_colors[i] );
2962 pixels[xwm_colors[i].pixel] = 0;
2963 }
2964
2965 // Fill the ones we will use in cmap0
2966
2967 for ( i = 0; i < xwd->ncol0; i++ )
2968 {
2969 XStoreColor( xwd->display, xwd->map, &xwd->cmap0[i] );
2970 pixels[xwd->cmap0[i].pixel] = 0;
2971 }
2972
2973 // Finally, if the colormap was saved by an external agent, see if there are
2974 // any differences from the current default map and save those! A very cool
2975 // (or sick, depending on how you look at it) trick to get over some X and
2976 // Tk limitations.
2977 //
2978
2979 if ( sxwm_colors_set )
2980 {
2981 for ( i = 0; i < RWMAP_MAX_COLORS; i++ )
2982 {
2983 if ( ( xwm_colors[i].red != sxwm_colors[i].red ) ||
2984 ( xwm_colors[i].green != sxwm_colors[i].green ) ||
2985 ( xwm_colors[i].blue != sxwm_colors[i].blue ) )
2986 {
2987 if ( pixels[i] != 0 )
2988 {
2989 XStoreColor( xwd->display, xwd->map, &xwm_colors[i] );
2990 pixels[i] = 0;
2991 }
2992 }
2993 }
2994 }
2995
2996 // Now free the ones we're not interested in
2997
2998 for ( i = 0; i < npixels; i++ )
2999 {
3000 if ( pixels[i] != 0 )
3001 XFreeColors( xwd->display, xwd->map, &pixels[i], 1, 0 );
3002 }
3003
3004 // Allocate colors in cmap 1
3005
3006 AllocCmap1( pls );
3007 }
3008
3009 //--------------------------------------------------------------------------
3010 // AllocCmap0()
3011 //
3012 // Allocate & initialize cmap0 entries.
3013 //--------------------------------------------------------------------------
3014
3015 static void
3016 AllocCmap0( PLStream *pls )
3017 {
3018 XwDev *dev = (XwDev *) pls->dev;
3019 XwDisplay *xwd = (XwDisplay *) dev->xwd;
3020 int i;
3021
3022 dbug_enter( "AllocCmap0" );
3023
3024 // Free all previous colors. This should work for both rw & ro colormaps
3025 for ( i = 1; i < xwd->ncol0; i++ )
3026 {
3027 unsigned long pixel = xwd->cmap0[i].pixel;
3028 XFreeColors( xwd->display, xwd->map, &pixel, 1, 0 );
3029 }
3030
3031 // If the number of colors increased, need to allocate enough space for them
3032 if ( pls->ncol0 > xwd->ncol0_alloc )
3033 {
3034 xwd->ncol0_alloc = pls->ncol0;
3035 xwd->cmap0 = (XColor *)
3036 realloc( xwd->cmap0, (size_t) pls->ncol0 * sizeof ( XColor ) );
3037 if ( xwd->cmap0 == 0 )
3038 plexit( "couldn't allocate space for cmap0 colors" );
3039 }
3040
3041 if ( xwd->rw_cmap )
3042 {
3043 int npixels;
3044 unsigned long plane_masks[1], pixels[RWMAP_MAX_COLORS];
3045
3046 // Allocate and assign colors in cmap 0
3047
3048 npixels = pls->ncol0 - 1;
3049 for (;; )
3050 {
3051 if ( XAllocColorCells( xwd->display, xwd->map, False,
3052 plane_masks, 0, &pixels[1], (unsigned int) npixels ) )
3053 break;
3054 npixels--;
3055 if ( npixels == 0 )
3056 plexit( "couldn't allocate any colors" );
3057 }
3058
3059 xwd->ncol0 = npixels + 1;
3060 for ( i = 1; i < xwd->ncol0; i++ )
3061 {
3062 xwd->cmap0[i].pixel = pixels[i];
3063 }
3064
3065 StoreCmap0( pls );
3066 }
3067 else
3068 {
3069 if ( pls->verbose )
3070 fprintf( stderr, "Attempting to allocate r/o colors in cmap0.\n" );
3071
3072 for ( i = 1; i < pls->ncol0; i++ )
3073 {
3074 int r;
3075 XColor c;
3076 PLColor_to_XColor( &pls->cmap0[i], &c );
3077 r = XAllocColor( xwd->display, xwd->map, &c );
3078 if ( pls->verbose )
3079 fprintf( stderr, "i=%d, r=%d, pixel=%d\n", i, r, (int) c.pixel );
3080 if ( r )
3081 {
3082 xwd->cmap0[i] = c;
3083 xwd->cmap0[i].pixel = c.pixel; // needed for deallocation
3084 }
3085 else
3086 {
3087 XColor screen_def, exact_def;
3088
3089 if ( pls->verbose )
3090 fprintf( stderr,
3091 "color alloc failed, trying by name: %s.\n",
3092 pls->cmap0[i].name );
3093
3094 // Hmm, didn't work, try another approach.
3095 r = XAllocNamedColor( xwd->display, xwd->map,
3096 pls->cmap0[i].name,
3097 &screen_def, &exact_def );
3098
3099 // xwd->cmap0[i] = screen_def;
3100
3101 if ( r )
3102 {
3103 if ( pls->verbose )
3104 fprintf( stderr, "yes, got a color by name.\n" );
3105
3106 xwd->cmap0[i] = screen_def;
3107 xwd->cmap0[i].pixel = screen_def.pixel;
3108 }
3109 else
3110 {
3111 r = XAllocNamedColor( xwd->display, xwd->map,
3112 "white",
3113 &screen_def, &exact_def );
3114 if ( r )
3115 {
3116 xwd->cmap0[i] = screen_def;
3117 xwd->cmap0[i].pixel = screen_def.pixel;
3118 }
3119 else
3120 printf( "Can't find white?! Giving up...\n" );
3121 }
3122 }
3123 }
3124 xwd->ncol0 = i;
3125
3126 if ( pls->verbose )
3127 fprintf( stderr, "Allocated %d colors in cmap0.\n", xwd->ncol0 );
3128 }
3129 }
3130
3131 //--------------------------------------------------------------------------
3132 // AllocCmap1()
3133 //
3134 // Allocate & initialize cmap1 entries.
3135 //--------------------------------------------------------------------------
3136
3137 static void
3138 AllocCmap1( PLStream *pls )
3139 {
3140 XwDev *dev = (XwDev *) pls->dev;
3141 XwDisplay *xwd = (XwDisplay *) dev->xwd;
3142
3143 int i, j, npixels;
3144 unsigned long plane_masks[1], pixels[RWMAP_MAX_COLORS];
3145
3146 dbug_enter( "AllocCmap1" );
3147
3148 if ( xwd->rw_cmap )
3149 {
3150 if ( pls->verbose )
3151 fprintf( stderr, "Attempting to allocate r/w colors in cmap1.\n" );
3152
3153 // If using the default color map, must severely limit number of colors
3154 // otherwise TK won't have enough.
3155
3156 npixels = MAX( 2, MIN( RWMAP_CMAP1_COLORS, pls->ncol1 ) );
3157 for (;; )
3158 {
3159 if ( XAllocColorCells( xwd->display, xwd->map, False,
3160 plane_masks, 0, pixels, (unsigned int) npixels ) )
3161 break;
3162 npixels--;
3163 if ( npixels == 0 )
3164 break;
3165 }
3166
3167 if ( npixels < 2 )
3168 {
3169 xwd->ncol1 = -1;
3170 fprintf( stderr, "Warning: unable to allocate sufficient colors in cmap1.\n" );
3171 return;
3172 }
3173
3174 xwd->ncol1 = npixels;
3175 if ( pls->verbose )
3176 fprintf( stderr, "AllocCmap1 (xwin.c): Allocated %d colors in cmap1.\n", npixels );
3177
3178 // Allocate space if it hasn't been done yet
3179 if ( !xwd->cmap1 )
3180 {
3181 xwd->ncol1_alloc = xwd->ncol1;
3182 xwd->cmap1 = (XColor *) calloc( (size_t) ( xwd->ncol1 ), sizeof ( XColor ) );
3183 if ( !xwd->cmap1 )
3184 plexit( "couldn't allocate space for cmap1 colors" );
3185 }
3186
3187 // Don't assign pixels sequentially, to avoid strange problems with xor
3188 // GC's. Skipping by 2 seems to do the job best.
3189
3190 for ( j = i = 0; i < xwd->ncol1; i++ )
3191 {
3192 while ( pixels[j] == 0 )
3193 j++;
3194
3195 xwd->cmap1[i].pixel = pixels[j];
3196 pixels[j] = 0;
3197
3198 j += 2;
3199 if ( j >= xwd->ncol1 )
3200 j = 0;
3201 }
3202
3203 StoreCmap1( pls );
3204 }
3205 else
3206 {
3207 int r, ncolors;
3208 PLColor cmap1color;
3209 XColor xcol;
3210
3211 if ( pls->verbose )
3212 fprintf( stderr, "Attempting to allocate r/o colors in cmap1.\n" );
3213
3214 switch ( xwd->visual->class )
3215 {
3216 case TrueColor:
3217 ncolors = TC_CMAP1_COLORS;
3218 break;
3219 default:
3220 ncolors = ROMAP_CMAP1_COLORS;
3221 }
3222
3223 // Allocate space if it hasn't been done yet
3224 if ( !xwd->cmap1 )
3225 {
3226 xwd->ncol1_alloc = ncolors;
3227 xwd->cmap1 = (XColor *) calloc( (size_t) ncolors, sizeof ( XColor ) );
3228 if ( !xwd->cmap1 )
3229 plexit( "couldn't allocate space for cmap1 colors" );
3230 }
3231
3232 for ( i = 0; i < ncolors; i++ )
3233 {
3234 plcol_interp( pls, &cmap1color, i, ncolors );
3235 PLColor_to_XColor( &cmap1color, &xcol );
3236
3237 r = XAllocColor( xwd->display, xwd->map, &xcol );
3238 if ( pls->verbose )
3239 fprintf( stderr, "i=%d, r=%d, pixel=%d\n", i, r, (int) xcol.pixel );
3240 if ( r )
3241 xwd->cmap1[i] = xcol;
3242 else
3243 break;
3244 }
3245 if ( i < ncolors )
3246 {
3247 xwd->ncol1 = -1;
3248 fprintf( stderr,
3249 "Warning: unable to allocate sufficient colors in cmap1\n" );
3250 return;
3251 }
3252 else
3253 {
3254 xwd->ncol1 = ncolors;
3255 if ( pls->verbose )
3256 fprintf( stderr, "AllocCmap1 (xwin.c): Allocated %d colors in cmap1\n", ncolors );
3257 }
3258 }
3259 }
3260
3261 //--------------------------------------------------------------------------
3262 // StoreCmap0()
3263 //
3264 // Stores cmap 0 entries in X-server colormap.
3265 //--------------------------------------------------------------------------
3266
3267 static void
3268 StoreCmap0( PLStream *pls )
3269 {
3270 XwDev *dev = (XwDev *) pls->dev;
3271 XwDisplay *xwd = (XwDisplay *) dev->xwd;
3272 int i;
3273
3274 if ( !xwd->color )
3275 return;
3276
3277 for ( i = 1; i < xwd->ncol0; i++ )
3278 {
3279 PLColor_to_XColor( &pls->cmap0[i], &xwd->cmap0[i] );
3280 if ( xwd->rw_cmap )
3281 XStoreColor( xwd->display, xwd->map, &xwd->cmap0[i] );
3282 else
3283 XAllocColor( xwd->display, xwd->map, &xwd->cmap0[i] );
3284 }
3285 }
3286
3287 //--------------------------------------------------------------------------
3288 // StoreCmap1()
3289 //
3290 // Stores cmap 1 entries in X-server colormap.
3291 //--------------------------------------------------------------------------
3292
3293 static void
3294 StoreCmap1( PLStream *pls )
3295 {
3296 XwDev *dev = (XwDev *) pls->dev;
3297 XwDisplay *xwd = (XwDisplay *) dev->xwd;
3298
3299 PLColor cmap1color;
3300 int i;
3301
3302 if ( !xwd->color )
3303 return;
3304
3305 for ( i = 0; i < xwd->ncol1; i++ )
3306 {
3307 plcol_interp( pls, &cmap1color, i, xwd->ncol1 );
3308 PLColor_to_XColor( &cmap1color, &xwd->cmap1[i] );
3309 if ( xwd->rw_cmap )
3310 XStoreColor( xwd->display, xwd->map, &xwd->cmap1[i] );
3311 else
3312 XAllocColor( xwd->display, xwd->map, &xwd->cmap1[i] );
3313 }
3314 }
3315
3316 //--------------------------------------------------------------------------
3317 // PLColor_to_XColor()
3318 //
3319 // Copies the supplied PLColor to an XColor, padding with bits as necessary
3320 // (a PLColor uses 8 bits for color storage, while an XColor uses 16 bits).
3321 // The argument types follow the same order as in the function name.
3322 //--------------------------------------------------------------------------
3323
3324 #define ToXColor( a ) ( ( ( 0xFF & ( a ) ) << 8 ) | ( a ) )
3325 #define ToPLColor( a ) ( ( (U_LONG) a ) >> 8 )
3326
3327 static void
3328 PLColor_to_XColor( PLColor *plcolor, XColor *xcolor )
3329 {
3330 xcolor->red = (short unsigned) ToXColor( plcolor->r );
3331 xcolor->green = (short unsigned) ToXColor( plcolor->g );
3332 xcolor->blue = (short unsigned) ToXColor( plcolor->b );
3333 xcolor->flags = DoRed | DoGreen | DoBlue;
3334 }
3335
3336 //--------------------------------------------------------------------------
3337 // PLColor_from_XColor()
3338 //
3339 // Copies the supplied XColor to a PLColor, stripping off bits as
3340 // necessary. See the previous routine for more info.
3341 //--------------------------------------------------------------------------
3342
3343 static void
3344 PLColor_from_XColor( PLColor *plcolor, XColor *xcolor )
3345 {
3346 plcolor->r = (unsigned char) ToPLColor( xcolor->red );
3347 plcolor->g = (unsigned char) ToPLColor( xcolor->green );
3348 plcolor->b = (unsigned char) ToPLColor( xcolor->blue );
3349 }
3350
3351 //--------------------------------------------------------------------------
3352 // AreWeGrayscale(Display *display)
3353 //
3354 // Determines if we're using a monochrome or grayscale device.
3355 // gmf 11-8-91; Courtesy of Paul Martz of Evans and Sutherland.
3356 // Altered Andrew Ross 26-01-2004 to fix memory leak.
3357 //--------------------------------------------------------------------------
3358
3359 static int
3360 AreWeGrayscale( Display *display )
3361 {
3362 #if defined ( __cplusplus ) || defined ( c_plusplus )
3363 #define THING c_class
3364 #else
3365 #define THING class
3366 #endif
3367
3368 XVisualInfo *visuals;
3369 int nitems, i, igray;
3370
3371 // get a list of info on the visuals available
3372 visuals = XGetVisualInfo( display, 0, NULL, &nitems );
3373
3374 igray = 1;
3375 // check the list looking for non-monochrome visual classes
3376 for ( i = 0; i < nitems; i++ )
3377 if ( ( visuals[i].THING != GrayScale ) &&
3378 ( visuals[i].THING != StaticGray ) )
3379 {
3380 igray = 0;
3381 break;
3382 }
3383
3384 XFree( visuals );
3385 // if igray = 1 only StaticGray and GrayScale classes available
3386 return igray;
3387 }
3388
3389 #ifdef DUMMY
3390 //--------------------------------------------------------------------------
3391 // SaveColormap() **** DUMMY, NOT USED ANYMORE ***
3392 //
3393 // Saves RGB components of given colormap.
3394 // Used in an ugly hack to get past some X11R5 and TK limitations.
3395 // This isn't guaranteed to work under all circumstances, but hopefully
3396 // in the future there will be a nicer way to accomplish the same thing.
3397 //
3398 // Note: I tried using XCopyColormapAndFree to do the same thing, but under
3399 // HPUX 9.01/VUE/X11R5 at least it doesn't preserve the previous read-only
3400 // color cell allocations made by Tk. Is this a bug? Have to look at the
3401 // source to find out.
3402 //--------------------------------------------------------------------------
3403
3404 static void
3405 SaveColormap( Display *display, Colormap colormap )
3406 {
3407 int i;
3408
3409 if ( !plplot_ccmap )
3410 return;
3411
3412 sxwm_colors_set = 1;
3413 for ( i = 0; i < RWMAP_MAX_COLORS; i++ )
3414 {
3415 sxwm_colors[i].pixel = i;
3416 }
3417 XQueryColors( display, colormap, sxwm_colors, RWMAP_MAX_COLORS );
3418 //
3419 // printf("\nAt startup, default colors are: \n\n");
3420 // for (i = 0; i < RWMAP_MAX_COLORS; i++) {
3421 // printf(" i: %d, pixel: %d, r: %d, g: %d, b: %d\n",
3422 // i, sxwm_colors[i].pixel,
3423 // sxwm_colors[i].red, sxwm_colors[i].green, sxwm_colors[i].blue);
3424 // }
3425 //
3426 }
3427 #endif
3428
3429 //--------------------------------------------------------------------------
3430 // GetImageErrorHandler()
3431 //
3432 // Error handler used in XGetImage() to catch errors when pixmap or window
3433 // are not completely viewable.
3434 //--------------------------------------------------------------------------
3435
3436 static int
3437 GetImageErrorHandler( Display *display, XErrorEvent *error )
3438 {
3439 if ( error->error_code != BadMatch )
3440 {
3441 char buffer[256];
3442 XGetErrorText( display, error->error_code, buffer, 256 );
3443 fprintf( stderr, "xwin: Error in XGetImage: %s.\n", buffer );
3444 }
3445 return 1;
3446 }
3447
3448 //--------------------------------------------------------------------------
3449 // DrawImage()
3450 //
3451 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
3452 // Only solid color fill supported.
3453 //--------------------------------------------------------------------------
3454
3455 static void
3456 DrawImage( PLStream *pls )
3457 {
3458 XwDev *dev = (XwDev *) pls->dev;
3459 XwDisplay *xwd = (XwDisplay *) dev->xwd;
3460 XImage *ximg = NULL;
3461 XColor curcolor;
3462 PLINT xmin, xmax, ymin, ymax, icol1;
3463
3464 int ( *oldErrorHandler )( Display *, XErrorEvent * );
3465
3466 float mlr, mtb;
3467 float blt, brt, brb, blb;
3468 float left, right;
3469 int kx, ky;
3470 int nx, ny, ix, iy;
3471 int i, corners[4], r[4] = { 0, 0, 0, 0 };
3472
3473 struct
3474 {
3475 float x, y;
3476 } Ppts[4];
3477
3478 CheckForEvents( pls );
3479
3480 xmin = (PLINT) ( dev->xscale * pls->imclxmin );
3481 xmax = (PLINT) ( dev->xscale * pls->imclxmax );
3482 ymin = (PLINT) ( dev->yscale * pls->imclymin );
3483 ymax = (PLINT) ( dev->yscale * pls->imclymax );
3484
3485 nx = pls->dev_nptsX;
3486 ny = pls->dev_nptsY;
3487
3488 // XGetImage() call fails if either the pixmap or window is not fully viewable!
3489 oldErrorHandler = XSetErrorHandler( GetImageErrorHandler );
3490
3491 XFlush( xwd->display );
3492 if ( dev->write_to_pixmap )
3493 ximg = XGetImage( xwd->display, dev->pixmap, 0, 0, dev->width, dev->height,
3494 AllPlanes, ZPixmap );
3495
3496 if ( dev->write_to_window )
3497 ximg = XGetImage( xwd->display, dev->window, 0, 0, dev->width, dev->height,
3498 AllPlanes, ZPixmap );
3499
3500 XSetErrorHandler( oldErrorHandler );
3501
3502 if ( ximg == NULL )
3503 {
3504 plabort( "Can't get image, the window must be partly off-screen, move it to fit screen" );
3505 return;
3506 }
3507
3508 if ( xwd->ncol1 == 0 )
3509 AllocCmap1( pls );
3510 if ( xwd->ncol1 < 2 )
3511 return;
3512
3513 // translate array for rotation
3514 switch ( (int) ( pls->diorot - 4. * floor( pls->diorot / 4. ) ) )
3515 {
3516 case 0:
3517 r[0] = 0; r[1] = 1; r[2] = 2; r[3] = 3; break;
3518 case 1:
3519 r[0] = 1; r[1] = 2; r[2] = 3; r[3] = 0; break;
3520 case 2:
3521 r[0] = 2; r[1] = 3; r[2] = 0; r[3] = 1; break;
3522 case 3:
3523 r[0] = 3; r[1] = 0; r[2] = 1; r[3] = 2;
3524 }
3525
3526 // after rotation and coordinate translation, each fill
3527 // lozangue will have coordinates (Ppts), slopes (m...)
3528 // and y intercepts (b...):
3529 //
3530 // Ppts[3]
3531 // **
3532 // mlr,blt * * mtb,brt
3533 // * *
3534 //Ppts[0]< > Ppts[2]
3535 // * *
3536 // mtb,blt * * mlr,brb
3537 // **
3538 // Ppts[1]
3539 //
3540
3541 // slope of left/right and top/bottom edges
3542 mlr = (float) ( ( dev->yscale * ( pls->dev_iy[1] - pls->dev_iy[0] ) ) /
3543 ( dev->xscale * ( pls->dev_ix[1] - pls->dev_ix[0] ) ) );
3544
3545 mtb = (float) ( ( dev->yscale * ( pls->dev_iy[ny] - pls->dev_iy[0] ) ) /
3546 ( dev->xscale * ( pls->dev_ix[ny] - pls->dev_ix[0] ) ) );
3547
3548 for ( ix = 0; ix < nx - 1; ix++ )
3549 {
3550 for ( iy = 0; iy < ny - 1; iy++ )
3551 {
3552 corners[0] = ix * ny + iy; // [ix][iy]
3553 corners[1] = ( ix + 1 ) * ny + iy; // [ix+1][iy]
3554 corners[2] = ( ix + 1 ) * ny + iy + 1; // [ix+1][iy+1]
3555 corners[3] = ix * ny + iy + 1; // [ix][iy+1]
3556
3557 for ( i = 0; i < 4; i++ )
3558 {
3559 Ppts[i].x = (float) ( dev->xscale * ( pls->dev_ix[corners[r[i]]] ) );
3560 Ppts[i].y = (float) ( dev->yscale * ( pls->dev_iy[corners[r[i]]] ) );
3561 }
3562
3563 // if any corner is inside the draw area
3564 if ( Ppts[0].x >= xmin || Ppts[2].x <= xmax ||
3565 Ppts[1].y >= ymin || Ppts[3].y <= ymax )
3566 {
3567 Ppts[0].x = MAX( Ppts[0].x, (float) xmin );
3568 Ppts[2].x = MIN( Ppts[2].x, (float) xmax );
3569 Ppts[1].y = MAX( Ppts[1].y, (float) ymin );
3570 Ppts[3].y = MIN( Ppts[3].y, (float) ymax );
3571
3572 // the Z array has size (nx-1)*(ny-1)
3573 icol1 = pls->dev_z[ix * ( ny - 1 ) + iy];
3574
3575 // only plot points within zmin/zmax range
3576 if ( icol1 < pls->dev_zmin || icol1 > pls->dev_zmax )
3577 continue;
3578
3579 icol1 = (PLINT) ( (float) icol1 / (float) USHRT_MAX * (float) ( xwd->ncol1 - 1 ) );
3580 if ( xwd->color )
3581 curcolor = xwd->cmap1[icol1];
3582 else
3583 curcolor = xwd->fgcolor;
3584
3585 // Fill square between current and next points.
3586
3587 // If the fill area is a single dot, accelerate the fill.
3588 if ( ( fabs( Ppts[2].x - Ppts[0].x ) == 1 ) &&
3589 ( fabs( Ppts[3].y - Ppts[1].y ) == 1 ) )
3590 {
3591 XPutPixel( ximg, (int) Ppts[0].x, (int) dev->height - 1 - (int) Ppts[0].y, (unsigned long) curcolor.pixel );
3592
3593 // integer rotate, accelerate
3594 }
3595 else if ( pls->diorot == floor( pls->diorot ) )
3596 {
3597 for ( ky = (int) Ppts[1].y; ky < (int) Ppts[3].y; ky++ )
3598 for ( kx = (int) Ppts[0].x; kx < (int) Ppts[2].x; kx++ )
3599 XPutPixel( ximg, kx, (int) dev->height - 1 - ky, (unsigned int) curcolor.pixel );
3600
3601 // lozangue, scanline fill it
3602 }
3603 else
3604 {
3605 // y interception point of left/right top/bottom edges
3606 blt = Ppts[0].y - mlr * Ppts[0].x;
3607 brb = Ppts[2].y - mlr * Ppts[2].x;
3608
3609 brt = Ppts[2].y - mtb * Ppts[2].x;
3610 blb = Ppts[0].y - mtb * Ppts[0].x;
3611
3612 for ( ky = (int) Ppts[1].y; ky < (int) Ppts[3].y; ky++ )
3613 {
3614 left = MAX( ( ( (float) ky - blt ) / mlr ), ( ( (float) ky - blb ) / mtb ) );
3615 right = MIN( ( ( (float) ky - brt ) / mtb ), ( ( (float) ky - brb ) / mlr ) );
3616 for ( kx = (int) Ppts[0].x; kx < (int) Ppts[2].x; kx++ )
3617 {
3618 if ( kx >= rint( left ) && kx <= rint( right ) )
3619 {
3620 XPutPixel( ximg, kx, (int) dev->height - 1 - ky, (unsigned int) curcolor.pixel );
3621 }
3622 }
3623 }
3624 }
3625 }
3626 }
3627 }
3628
3629 if ( dev->write_to_pixmap )
3630 XPutImage( xwd->display, dev->pixmap, dev->gc, ximg, 0, 0, 0, 0, dev->width, dev->height );
3631
3632 if ( dev->write_to_window )
3633 XPutImage( xwd->display, dev->window, dev->gc, ximg, 0, 0,
3634 0, 0, dev->width, dev->height );
3635
3636 XDestroyImage( ximg );
3637 }
3638
3639 static void
3640 imageops( PLStream *pls, PLINT *ptr )
3641 {
3642 XwDev *dev = (XwDev *) pls->dev;
3643 XwDisplay *xwd = (XwDisplay *) dev->xwd;
3644
3645 // TODO: store/revert to/from previous state
3646
3647 switch ( *ptr )
3648 {
3649 case ZEROW2D:
3650 dev->write_to_window = 0;
3651 break;
3652
3653 case ONEW2D:
3654 dev->write_to_window = 1;
3655 break;
3656
3657 case ZEROW2B:
3658 dev->write_to_pixmap = 0;
3659 break;
3660
3661 case ONEW2B:
3662 XFlush( xwd->display );
3663 dev->write_to_pixmap = 1;
3664 break;
3665 }
3666 }
3667
3668 #else
3669 int
3670 pldummy_xwin()
3671 {
3672 return 0;
3673 }
3674
3675 #endif // PLD_xwin
XwDisplay::cmap1
XColor * cmap1
Definition: plxwd.h:59
plParseDrvOpts
int plParseDrvOpts(DrvOpt *acc_opt)
Definition: plargs.c:1461
PLESC_REDRAW
#define PLESC_REDRAW
Definition: plplot.h:276
plplotP.h
XwDisplay::display
Display * display
Definition: plxwd.h:48
PLStream::plwindow
char * plwindow
Definition: plstrm.h:640
PLStream::dev_z
unsigned short * dev_z
Definition: plstrm.h:588
PLSTATE_CMAP0
#define PLSTATE_CMAP0
Definition: plplotP.h:366
PLStream::imclxmin
PLINT imclxmin
Definition: plstrm.h:590
PLColor
Definition: plplot.h:546
XwDev::locate_mode
int locate_mode
Definition: plxwd.h:99
PLESC_XORMOD
#define PLESC_XORMOD
Definition: plplot.h:286
plxwd.h
PLESC_DEVINIT
#define PLESC_DEVINIT
Definition: plplot.h:296
PLK_Escape
#define PLK_Escape
Definition: plevent.h:51
PLStream::LocateEH
void(* LocateEH)(PLGraphicsIn *gin, void *LocateEH_data, int *locate_mode)
Definition: plstrm.h:606
plexit
void plexit(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1958
PLESC_DOUBLEBUFFERING_ENABLE
#define PLESC_DOUBLEBUFFERING_ENABLE
Definition: plplot.h:576
PLStream::imclymax
PLINT imclymax
Definition: plstrm.h:590
PLESC_DOUBLEBUFFERING_QUERY
#define PLESC_DOUBLEBUFFERING_QUERY
Definition: plplot.h:578
PLStream::icol1
PLINT icol1
Definition: plstrm.h:539
XwDisplay::rw_cmap
int rw_cmap
Definition: plxwd.h:62
plDevType_Interactive
Definition: disptab.h:14
PLStream::window_id
long window_id
Definition: plstrm.h:634
PLK_Down
#define PLK_Down
Definition: plevent.h:66
plevent.h
PLColor::b
unsigned char b
Definition: plplot.h:550
PLGraphicsIn::dX
PLFLT dX
Definition: plplot.h:442
PLESC_FILL
#define PLESC_FILL
Definition: plplot.h:279
PL_RGB_COLOR
#define PL_RGB_COLOR
Definition: plplotP.h:285
XwDisplay::visual
Visual * visual
Definition: plxwd.h:49
PLESC_DOUBLEBUFFERING
#define PLESC_DOUBLEBUFFERING
Definition: plplot.h:285
PLDispatchTable::pl_esc
plD_esc_fp pl_esc
Definition: disptab.h:90
XwDev::xwd
XwDisplay * xwd
Definition: plxwd.h:69
PLDisplay::height
unsigned int height
Definition: plplot.h:462
PLStream::dev_iy
short * dev_iy
Definition: plstrm.h:587
XwDev::drawing_xhairs
int drawing_xhairs
Definition: plxwd.h:100
XwDev::height
unsigned height
Definition: plxwd.h:82
plD_tidy_fp
void(* plD_tidy_fp)(struct PLStream_struct *)
Definition: disptab.h:72
XwDev::pixmap
Pixmap pixmap
Definition: plxwd.h:73
PLDispatchTable::pl_seq
int pl_seq
Definition: disptab.h:82
plGinInit
void plGinInit(PLGraphicsIn *gin)
Definition: plctrl.c:2887
PLStream::dev_npts
PLINT dev_npts
Definition: plstrm.h:581
PLDispatchTable::pl_MenuStr
const char * pl_MenuStr
Definition: disptab.h:79
XwDisplay::displayName
char * displayName
Definition: plxwd.h:46
XwDev::exit_eventloop
int exit_eventloop
Definition: plxwd.h:78
XwDev::max_instr
int max_instr
Definition: plxwd.h:95
PLStream::ButtonEH
void(* ButtonEH)(PLGraphicsIn *gin, void *ButtonEH_data, int *exit_eventloop)
Definition: plstrm.h:602
XwDev::xlen
short xlen
Definition: plxwd.h:89
PLStream::color
PLINT color
Definition: plstrm.h:569
PL_MAXKEY
#define PL_MAXKEY
Definition: plplot.h:408
plcol_interp
void plcol_interp(PLStream *pls, PLColor *newcolor, int i, int ncol)
Definition: plctrl.c:2530
PLDisplay
Definition: plplot.h:459
PLDispatchTable::pl_tidy
plD_tidy_fp pl_tidy
Definition: disptab.h:88
PLStream::plbuf_write
PLINT plbuf_write
Definition: plstrm.h:567
MAX
#define MAX(a, b)
Definition: dsplint.c:28
plD_init_fp
void(* plD_init_fp)(struct PLStream_struct *)
Definition: disptab.h:67
plTranslateCursor
PLINT plTranslateCursor(PLGraphicsIn *plg)
Definition: plpage.c:259
PLStream::diorot
PLFLT diorot
Definition: plstrm.h:661
plD_eop_fp
void(* plD_eop_fp)(struct PLStream_struct *)
Definition: disptab.h:70
plD_wait_fp
void(* plD_wait_fp)(struct PLStream_struct *)
Definition: disptab.h:75
PLStream::dev_nptsY
PLINT dev_nptsY
Definition: plstrm.h:586
PLDispatchTable::pl_DevName
const char * pl_DevName
Definition: disptab.h:80
XwDev::xscale
double xscale
Definition: plxwd.h:86
PLSTATE_COLOR0
#define PLSTATE_COLOR0
Definition: plplotP.h:363
PLDispatchTable::pl_init
plD_init_fp pl_init
Definition: disptab.h:83
plabort
void plabort(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1894
error
static int error
Definition: plcont.c:61
XwDev::instr
int instr
Definition: plxwd.h:94
XwDisplay::ncol0_alloc
int ncol0_alloc
Definition: plxwd.h:55
PLStream::colorset
PLINT colorset
Definition: plstrm.h:569
pldummy_xwin
int pldummy_xwin()
Definition: xwin.c:3670
XwDisplay::nstreams
int nstreams
Definition: plxwd.h:44
PLSTATE_COLOR1
#define PLSTATE_COLOR1
Definition: plplotP.h:364
XwDisplay::ncol0
int ncol0
Definition: plxwd.h:54
XwDev::gin
PLGraphicsIn gin
Definition: plxwd.h:97
PLStream::stream_closed
PLBOOL stream_closed
Definition: plstrm.h:782
PLK_Linefeed
#define PLK_Linefeed
Definition: plevent.h:49
PLStream::dev_fastimg
PLINT dev_fastimg
Definition: plstrm.h:572
XwDev::write_to_pixmap
int write_to_pixmap
Definition: plxwd.h:92
PLStream::dev_x
short * dev_x
Definition: plstrm.h:582
PLSTATE_WIDTH
#define PLSTATE_WIDTH
Definition: plplotP.h:362
PLINT
int PLINT
Definition: plplot.h:181
PLStream::LocateEH_data
void * LocateEH_data
Definition: plstrm.h:608
MIN
#define MIN(a, b)
Definition: dsplint.c:29
XwDev::xhair_x
XPoint xhair_x[2]
Definition: plxwd.h:101
CreateXhairs
static void CreateXhairs(PlFrame *)
Definition: plframe.c:1294
PLStream::dev_zmax
unsigned short dev_zmax
Definition: plstrm.h:589
XwDisplay::ncol1
int ncol1
Definition: plxwd.h:56
XwDev::bgcolor
XColor bgcolor
Definition: plxwd.h:107
PLStream::tmpcolor
PLColor tmpcolor
Definition: plstrm.h:543
PLBufferingCB::result
PLINT result
Definition: plplot.h:573
PLStream::dev_nptsX
PLINT dev_nptsX
Definition: plstrm.h:586
synchronize
static int synchronize
Definition: tkMain.c:132
DestroyXhairs
static void DestroyXhairs(PlFrame *)
Definition: plframe.c:1347
plD_line_fp
void(* plD_line_fp)(struct PLStream_struct *, short, short, short, short)
Definition: disptab.h:68
XwDisplay::depth
unsigned depth
Definition: plxwd.h:52
PLPLOT_MUTEX_RECURSIVE
#define PLPLOT_MUTEX_RECURSIVE
Definition: plplot_config.h:174
PLStream::ncol0
PLINT ncol0
Definition: plstrm.h:539
PLColor::g
unsigned char g
Definition: plplot.h:549
plD_esc_fp
void(* plD_esc_fp)(struct PLStream_struct *, PLINT, void *)
Definition: disptab.h:74
PLStream::db
int db
Definition: plstrm.h:635
PLStream::ButtonEH_data
void * ButtonEH_data
Definition: plstrm.h:604
plD_polyline_fp
void(* plD_polyline_fp)(struct PLStream_struct *, short *, short *, PLINT)
Definition: disptab.h:69
PLStream::termin
PLINT termin
Definition: plstrm.h:568
PLSTATE_CMAP1
#define PLSTATE_CMAP1
Definition: plplotP.h:367
PLStream::icol0
PLINT icol0
Definition: plstrm.h:539
XwDev::gc
GC gc
Definition: plxwd.h:74
PIXELS_X
#define PIXELS_X
Definition: plplotP.h:304
dbug_enter
#define dbug_enter(a)
Definition: tclMatrix.c:59
DPMM
#define DPMM
Definition: plplotP.h:306
TRUE
#define TRUE
Definition: plplotP.h:176
PLStream::ylength
PLINT ylength
Definition: plstrm.h:617
PLDisplay::x
unsigned int x
Definition: plplot.h:461
U_INT
#define U_INT
Definition: pdf.h:34
PLESC_RESIZE
#define PLESC_RESIZE
Definition: plplot.h:275
PLDispatchTable
Definition: disptab.h:77
PLStream::FileName
char * FileName
Definition: plstrm.h:576
FALSE
#define FALSE
Definition: plplotP.h:177
XwDisplay::color
int color
Definition: plxwd.h:53
XwDisplay::screen
int screen
Definition: plxwd.h:47
PLDispatchTable::pl_bop
plD_bop_fp pl_bop
Definition: disptab.h:87
PLStream::KeyEH
void(* KeyEH)(PLGraphicsIn *gin, void *KeyEH_data, int *exit_eventloop)
Definition: plstrm.h:598
XwDisplay::fgcolor
XColor fgcolor
Definition: plxwd.h:60
PLESC_EH
#define PLESC_EH
Definition: plplot.h:282
LPAGE_Y
#define LPAGE_Y
Definition: plplotP.h:309
XwDev::border
unsigned border
Definition: plxwd.h:82
DrvOpt
Definition: plplotP.h:748
XwDev::write_to_window
int write_to_window
Definition: plxwd.h:91
PLStream::verbose
PLINT verbose
Definition: plstrm.h:527
PLDispatchTable::pl_line
plD_line_fp pl_line
Definition: disptab.h:84
buffer
static PLINT * buffer
Definition: plfill.c:74
XwDev::xscale_init
double xscale_init
Definition: plxwd.h:84
child
static int child
Definition: plserver.c:45
DrawXhairs
static void DrawXhairs(PlFrame *, int, int)
Definition: plframe.c:1385
plP_setpxl
void plP_setpxl(PLFLT xpmm, PLFLT ypmm)
Definition: plcore.c:4238
pltext
#define pltext
Definition: plplot.h:855
PLStream::cmap0
PLColor * cmap0
Definition: plstrm.h:544
drivers.h
PLColor::name
PLCHAR_VECTOR name
Definition: plplot.h:552
plDevs.h
PLDLLIMPEXP_DRIVER
#define PLDLLIMPEXP_DRIVER
Definition: pldll.h:81
PLStream::dev_xor
PLINT dev_xor
Definition: plstrm.h:572
PLGraphicsIn::keysym
unsigned int keysym
Definition: plplot.h:437
PLK_Left
#define PLK_Left
Definition: plevent.h:63
pls
static PLStream * pls[PL_NSTREAMS]
Definition: plcore.h:88
plP_setphy
void plP_setphy(PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax)
Definition: plcore.c:4249
XwDev::MasterEH
void(* MasterEH)(PLStream *, XEvent *)
Definition: plxwd.h:103
ZEROW2D
#define ZEROW2D
Definition: plplot.h:323
PLXDISPLAYS
#define PLXDISPLAYS
Definition: plxwd.h:27
XwDisplay::map
Colormap map
Definition: plxwd.h:51
PLStream::ext_resize_draw
int ext_resize_draw
Definition: plstrm.h:635
XwDev::event_mask
long event_mask
Definition: plxwd.h:77
PLStream::imclymin
PLINT imclymin
Definition: plstrm.h:590
PLStream::xlength
PLINT xlength
Definition: plstrm.h:617
LPAGE_X
#define LPAGE_X
Definition: plplotP.h:308
PLStream::yoffset
PLINT yoffset
Definition: plstrm.h:618
XwDev::yscale_init
double yscale_init
Definition: plxwd.h:85
PLStream::nopixmap
int nopixmap
Definition: plstrm.h:635
PLStream::dev_y
short * dev_y
Definition: plstrm.h:582
plD_dispatch_init_xw
PLDLLIMPEXP_DRIVER void plD_dispatch_init_xw(PLDispatchTable *pdt)
PLStream
Definition: plstrm.h:523
UpdateXhairs
static void UpdateXhairs(PlFrame *)
Definition: plframe.c:1410
PLGraphicsIn::wX
PLFLT wX
Definition: plplot.h:443
XwDev::curcolor
XColor curcolor
Definition: plxwd.h:75
PIXELS_Y
#define PIXELS_Y
Definition: plplotP.h:305
XwDev::init_width
long init_width
Definition: plxwd.h:79
PLStream::KeyEH_data
void * KeyEH_data
Definition: plstrm.h:600
PLDispatchTable::pl_wait
plD_wait_fp pl_wait
Definition: disptab.h:91
PL_HAVE_PTHREAD
#define PL_HAVE_PTHREAD
Definition: plplot_config.h:124
ONEW2D
#define ONEW2D
Definition: plplot.h:325
PLStream::dev_ix
short * dev_ix
Definition: plstrm.h:587
PL_UNUSED
#define PL_UNUSED(x)
Definition: plplot.h:138
PLGraphicsIn::pX
int pX
Definition: plplot.h:441
plRemakePlot
void plRemakePlot(PLStream *pls)
Definition: plbuf.c:1397
PLFLT
float PLFLT
Definition: plplot.h:163
XwDev::init_height
long init_height
Definition: plxwd.h:80
PLStream::page
PLINT page
Definition: plstrm.h:578
plD_bop_fp
void(* plD_bop_fp)(struct PLStream_struct *)
Definition: disptab.h:71
PLESC_DOUBLEBUFFERING_DISABLE
#define PLESC_DOUBLEBUFFERING_DISABLE
Definition: plplot.h:577
free_mem
#define free_mem(a)
Definition: plplotP.h:182
PLBufferingCB
Definition: plplot.h:570
PLK_Return
#define PLK_Return
Definition: plevent.h:50
plplot_ccmap
static int plplot_ccmap
Definition: plxwd.h:37
PLStream::plbuf_read
PLINT plbuf_read
Definition: plstrm.h:567
PLK_Up
#define PLK_Up
Definition: plevent.h:64
PLK_Next
#define PLK_Next
Definition: plevent.h:68
XwDev::ylen
short ylen
Definition: plxwd.h:89
PLK_Right
#define PLK_Right
Definition: plevent.h:65
XwDev::width
unsigned width
Definition: plxwd.h:82
PLGraphicsIn::state
unsigned int state
Definition: plplot.h:436
XwDisplay::cmap0
XColor * cmap0
Definition: plxwd.h:58
PLColor::r
unsigned char r
Definition: plplot.h:548
PLStream::nopause
PLINT nopause
Definition: plstrm.h:568
XwDev
Definition: plxwd.h:67
PLStream::width
PLFLT width
Definition: plstrm.h:552
plwarn
void plwarn(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1863
DRV_INT
Definition: plplotP.h:758
PLBufferingCB::cmd
PLINT cmd
Definition: plplot.h:572
PLStream::imclxmax
PLINT imclxmax
Definition: plstrm.h:590
display
static const char * display
Definition: tkMain.c:136
PLESC_IMAGE
#define PLESC_IMAGE
Definition: plplot.h:291
PLGraphicsIn::button
unsigned int button
Definition: plplot.h:438
XwDev::is_main
int is_main
Definition: plxwd.h:71
XwDisplay::xhair_cursor
Cursor xhair_cursor
Definition: plxwd.h:61
XwDev::yscale
double yscale
Definition: plxwd.h:87
PLStream::curcolor
PLColor curcolor
Definition: plstrm.h:543
PLESC_DEV2PLCOL
#define PLESC_DEV2PLCOL
Definition: plplot.h:294
PLDispatchTable::pl_state
plD_state_fp pl_state
Definition: disptab.h:89
PLESC_SETBGFG
#define PLESC_SETBGFG
Definition: plplot.h:295
PLESC_IMAGEOPS
#define PLESC_IMAGEOPS
Definition: plplot.h:292
PLGraphicsIn::dY
PLFLT dY
Definition: plplot.h:442
PLDispatchTable::pl_eop
plD_eop_fp pl_eop
Definition: disptab.h:86
PLStream::xoffset
PLINT xoffset
Definition: plstrm.h:618
PLStream::debug
PLINT debug
Definition: plstrm.h:527
XwDisplay::ncol1_alloc
int ncol1_alloc
Definition: plxwd.h:57
PLStream::ncol1
PLINT ncol1
Definition: plstrm.h:539
PLESC_GETC
#define PLESC_GETC
Definition: plplot.h:283
PLESC_PL2DEVCOL
#define PLESC_PL2DEVCOL
Definition: plplot.h:293
PLDisplay::width
unsigned int width
Definition: plplot.h:462
XwDisplay::ixwd
int ixwd
Definition: plxwd.h:45
XwDev::xhair_y
XPoint xhair_y[2]
Definition: plxwd.h:101
PLStream::dev_flush
PLINT dev_flush
Definition: plstrm.h:571
PLGraphicsIn::pY
int pY
Definition: plplot.h:441
PLDisplay::y
unsigned int y
Definition: plplot.h:461
PLDispatchTable::pl_polyline
plD_polyline_fp pl_polyline
Definition: disptab.h:85
plD_state_fp
void(* plD_state_fp)(struct PLStream_struct *, PLINT)
Definition: disptab.h:73
PLGraphicsIn::wY
PLFLT wY
Definition: plplot.h:443
XwDev::window
Window window
Definition: plxwd.h:72
PLStream::dev
void * dev
Definition: plstrm.h:594
PLGraphicsIn::string
char string[PL_MAXKEY]
Definition: plplot.h:440
PLESC_EXPOSE
#define PLESC_EXPOSE
Definition: plplot.h:274
XwDisplay
Definition: plxwd.h:42
ZEROW2B
#define ZEROW2B
Definition: plplot.h:322
XwDisplay::gcXor
GC gcXor
Definition: plxwd.h:50
plgra
#define plgra
Definition: plplot.h:740
ONEW2B
#define ONEW2B
Definition: plplot.h:324
PLStream::dev_fill0
PLINT dev_fill0
Definition: plstrm.h:571
PLDispatchTable::pl_type
int pl_type
Definition: disptab.h:81
PLStream::dev_eofill
PLINT dev_eofill
Definition: plstrm.h:788
PL_MAXPOLY
#define PL_MAXPOLY
Definition: plplotP.h:283
PLESC_FLUSH
#define PLESC_FLUSH
Definition: plplot.h:281
PLGraphicsIn
Definition: plplot.h:433