PLplot 5.15.0
Loading...
Searching...
No Matches
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>
39int pthread_mutexattr_settype( pthread_mutexattr_t *attr, int kind );
40static void events_thread( void *pls );
41static pthread_mutex_t events_mutex;
42static int already = 0;
43#endif
44
45// Device info
46PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_xwin = "xwin:X-Window (Xlib):1:xwin:5:xw\n";
47
48static int synchronize = 0; // change to 1 for X synchronized operation
49 // Use "-drvopt sync" cmd line option to set.
50
51static int nobuffered = 0; // make it a buffered device by default
52 // use "-drvopt unbuffered" to make it unbuffered
53
54static int noinitcolors = 0; // Call InitColors by default
55 // use "-drvopt noinitcolors" to leave colors uninitialized
56
57static int defaultvisual = 1; // use "-drvopt defvis=0" to not use the default visual
58
59static 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
116static int sxwm_colors_set;
117static XColor sxwm_colors[RWMAP_MAX_COLORS];
118
119// Keep pointers to all the displays in use
120
121static XwDisplay *xwDisplay[PLXDISPLAYS];
122
123// Function prototypes
124
125// Driver entry and dispatch setup
126
128
129void plD_init_xw( PLStream * );
130void plD_line_xw( PLStream *, short, short, short, short );
131void plD_polyline_xw( PLStream *, short *, short *, PLINT );
132void plD_eop_xw( PLStream * );
133void plD_bop_xw( PLStream * );
134void plD_tidy_xw( PLStream * );
135void plD_wait_xw( PLStream * );
136void plD_state_xw( PLStream *, PLINT );
137void plD_esc_xw( PLStream *, PLINT, void * );
138
139// Initialization
140
141static void OpenXwin( PLStream *pls );
142static void Init( PLStream *pls );
143static void InitMain( PLStream *pls );
144static void InitColors( PLStream *pls );
145static void AllocCustomMap( PLStream *pls );
146static void AllocCmap0( PLStream *pls );
147static void AllocCmap1( PLStream *pls );
148static void MapMain( PLStream *pls );
149static void CreatePixmap( PLStream *pls );
150static void GetVisual( PLStream *pls );
151static void AllocBGFG( PLStream *pls );
152static int AreWeGrayscale( Display *display );
153
154// Routines to poll the X-server
155
156static void WaitForPage( PLStream *pls );
157static void CheckForEvents( PLStream *pls );
158static void HandleEvents( PLStream *pls );
159
160// Event handlers
161
162static void MasterEH( PLStream *pls, XEvent *event );
163static void ClientEH( PLStream *pls, XEvent *event );
164static void ExposeEH( PLStream *pls, XEvent *event );
165static void ResizeEH( PLStream *pls, XEvent *event );
166static void MotionEH( PLStream *pls, XEvent *event );
167static void EnterEH( PLStream *pls, XEvent *event );
168static void LeaveEH( PLStream *pls, XEvent *event );
169static void KeyEH( PLStream *pls, XEvent *event );
170static void ButtonEH( PLStream *pls, XEvent *event );
171static void LookupXKeyEvent( PLStream *pls, XEvent *event );
172static void LookupXButtonEvent( PLStream *pls, XEvent *event );
173
174static void ProcessKey( PLStream *pls );
175static void LocateKey( PLStream *pls );
176static void ProcessButton( PLStream *pls );
177static void LocateButton( PLStream *pls );
178static void Locate( PLStream *pls );
179
180// Routines for manipulating graphic crosshairs
181
182static void CreateXhairs( PLStream *pls );
183static void DestroyXhairs( PLStream *pls );
184static void DrawXhairs( PLStream *pls, int x0, int y0 );
185static void UpdateXhairs( PLStream *pls );
186
187// Escape function commands
188
189static void ExposeCmd( PLStream *pls, PLDisplay *ptr );
190static void RedrawCmd( PLStream *pls );
191static void ResizeCmd( PLStream *pls, PLDisplay *ptr );
192static void ConfigBufferingCmd( PLStream *pls, PLBufferingCB *ptr );
193static void GetCursorCmd( PLStream *pls, PLGraphicsIn *ptr );
194static void FillPolygonCmd( PLStream *pls );
195static void XorMod( PLStream *pls, PLINT *mod );
196static void DrawImage( PLStream *pls );
197
198// Miscellaneous
199
200static void StoreCmap0( PLStream *pls );
201static void StoreCmap1( PLStream *pls );
202static void imageops( PLStream *pls, PLINT *ptr );
203static void SetBGFG( PLStream *pls );
204#ifdef DUMMY
205static void SaveColormap( Display *display, Colormap colormap );
206#endif
207static void PLColor_to_XColor( PLColor *plcolor, XColor *xcolor );
208static void PLColor_from_XColor( PLColor *plcolor, XColor *xcolor );
209
210static 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
218{
219#ifndef ENABLE_DYNDRIVERS
220 pdt->pl_MenuStr = "X-Window (Xlib)";
221 pdt->pl_DevName = "xwin";
222#endif
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
243void
244plD_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
356void
357plD_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
399static void
400XorMod( 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
417void
418plD_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
476void
477plD_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
505void
506plD_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
548void
549plD_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
599void
600plD_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
625void
626plD_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
742void
743plD_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
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
830static void
831GetCursorCmd( 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;
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
867static void
868FillPolygonCmd( 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
936static void
937OpenXwin( 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
1073static void
1074Init( 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
1175static void
1176InitMain( 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
1251static void
1252MapMain( 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
1301static void
1302WaitForPage( 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
1341static void
1342events_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
1439static void
1440CheckForEvents( 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
1460static void
1461HandleEvents( 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
1490static void
1491MasterEH( 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
1542static void
1543ClientEH( 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;
1552 dev->exit_eventloop = TRUE;
1553 // plexit( "" );
1554 }
1555}
1556
1557
1558//--------------------------------------------------------------------------
1559// KeyEH()
1560//
1561// Event handler routine for keyboard events.
1562//--------------------------------------------------------------------------
1563
1564static void
1565KeyEH( 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
1584static void
1585ButtonEH( 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
1619static void
1620LookupXKeyEvent( 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
1664static void
1665LookupXButtonEvent( 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
1691static void
1692ProcessKey( 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
1741static void
1742ProcessButton( 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
1776static void
1777LocateKey( 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
1891static void
1892LocateButton( 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
1934static void
1935Locate( 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
1984static void
1985MotionEH( 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
2003static void
2004EnterEH( 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
2021static void
2022LeaveEH( 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
2036static void
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
2086static void
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
2114static void
2115DrawXhairs( 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
2140static void
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
2160static void
2161ExposeEH( 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
2216static void
2217ResizeEH( 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
2262static void
2263ExposeCmd( 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
2335static void
2336ResizeCmd( 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
2432static void ConfigBufferingCmd( PLStream *pls, PLBufferingCB *ptr )
2433{
2434 XwDev *dev = (XwDev *) pls->dev;
2435
2436 switch ( ptr->cmd )
2437 {
2439 dev->write_to_window = 0;
2440 pls->db = 1;
2441 break;
2442
2444 dev->write_to_window = 1;
2445 pls->db = 0;
2446 break;
2447
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
2465static void
2466RedrawCmd( 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
2519static unsigned char CreatePixmapStatus;
2520
2521static int
2522CreatePixmapErrorHandler( 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
2541static void
2542CreatePixmap( 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\
2565Warning: pixmap could not be allocated (insufficient memory on server).\n\
2566Driver 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
2583static void
2584GetVisual( 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
2722static void
2723AllocBGFG( 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
2795static void
2796SetBGFG( 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
2862static void
2863InitColors( 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
2911static void
2912AllocCustomMap( 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
3015static void
3016AllocCmap0( 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
3137static void
3138AllocCmap1( 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
3267static void
3268StoreCmap0( 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
3293static void
3294StoreCmap1( 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
3327static void
3328PLColor_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
3343static void
3344PLColor_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
3359static int
3360AreWeGrayscale( 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
3404static void
3405SaveColormap( 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
3436static int
3437GetImageErrorHandler( 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
3455static void
3456DrawImage( 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
3639static void
3640imageops( 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
3669int
3671{
3672 return 0;
3673}
3674
3675#endif // PLD_xwin
void(* plD_line_fp)(struct PLStream_struct *, short, short, short, short)
Definition disptab.h:68
void(* plD_tidy_fp)(struct PLStream_struct *)
Definition disptab.h:72
void(* plD_bop_fp)(struct PLStream_struct *)
Definition disptab.h:71
void(* plD_wait_fp)(struct PLStream_struct *)
Definition disptab.h:75
void(* plD_state_fp)(struct PLStream_struct *, PLINT)
Definition disptab.h:73
void(* plD_eop_fp)(struct PLStream_struct *)
Definition disptab.h:70
@ plDevType_Interactive
Definition disptab.h:14
void(* plD_init_fp)(struct PLStream_struct *)
Definition disptab.h:67
void(* plD_esc_fp)(struct PLStream_struct *, PLINT, void *)
Definition disptab.h:74
void(* plD_polyline_fp)(struct PLStream_struct *, short *, short *, PLINT)
Definition disptab.h:69
PLDLLIMPEXP_DRIVER void plD_dispatch_init_xw(PLDispatchTable *pdt)
#define MIN(a, b)
Definition dsplint.c:29
#define MAX(a, b)
Definition dsplint.c:28
#define U_INT
Definition pdf.h:34
int plParseDrvOpts(DrvOpt *acc_opt)
Definition plargs.c:1461
void plRemakePlot(PLStream *pls)
Definition plbuf.c:1397
static int error
Definition plcont.c:61
void plP_setpxl(PLFLT xpmm, PLFLT ypmm)
Definition plcore.c:4238
void plP_setphy(PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax)
Definition plcore.c:4249
static PLStream * pls[PL_NSTREAMS]
Definition plcore.h:88
void plwarn(PLCHAR_VECTOR errormsg)
Definition plctrl.c:1863
void plcol_interp(PLStream *pls, PLColor *newcolor, int i, int ncol)
Definition plctrl.c:2530
void plGinInit(PLGraphicsIn *gin)
Definition plctrl.c:2887
void plexit(PLCHAR_VECTOR errormsg)
Definition plctrl.c:1958
void plabort(PLCHAR_VECTOR errormsg)
Definition plctrl.c:1894
#define PLDLLIMPEXP_DRIVER
Definition pldll.h:81
#define PLK_Next
Definition plevent.h:68
#define PLK_Up
Definition plevent.h:64
#define PLK_Return
Definition plevent.h:50
#define PLK_Down
Definition plevent.h:66
#define PLK_Left
Definition plevent.h:63
#define PLK_Right
Definition plevent.h:65
#define PLK_Escape
Definition plevent.h:51
#define PLK_Linefeed
Definition plevent.h:49
static PLINT * buffer
Definition plfill.c:74
PLINT plTranslateCursor(PLGraphicsIn *plg)
Definition plpage.c:259
#define PL_MAXPOLY
Definition plplotP.h:283
#define LPAGE_X
Definition plplotP.h:308
#define PIXELS_X
Definition plplotP.h:304
#define PLSTATE_WIDTH
Definition plplotP.h:362
#define PLSTATE_CMAP0
Definition plplotP.h:366
#define PLSTATE_COLOR1
Definition plplotP.h:364
#define TRUE
Definition plplotP.h:176
#define FALSE
Definition plplotP.h:177
#define DPMM
Definition plplotP.h:306
#define LPAGE_Y
Definition plplotP.h:309
#define PLSTATE_CMAP1
Definition plplotP.h:367
#define PL_RGB_COLOR
Definition plplotP.h:285
@ DRV_INT
Definition plplotP.h:758
#define PLSTATE_COLOR0
Definition plplotP.h:363
#define free_mem(a)
Definition plplotP.h:182
#define PIXELS_Y
Definition plplotP.h:305
#define ZEROW2D
Definition plplot.h:323
#define PLESC_EXPOSE
Definition plplot.h:274
#define PLESC_GETC
Definition plplot.h:283
#define PLESC_PL2DEVCOL
Definition plplot.h:293
#define PLESC_DOUBLEBUFFERING_QUERY
Definition plplot.h:578
#define PLESC_DEV2PLCOL
Definition plplot.h:294
float PLFLT
Definition plplot.h:163
#define PLESC_SETBGFG
Definition plplot.h:295
#define PL_MAXKEY
Definition plplot.h:408
#define plgra
Definition plplot.h:740
#define PLESC_EH
Definition plplot.h:282
#define PLESC_DEVINIT
Definition plplot.h:296
#define ONEW2B
Definition plplot.h:324
#define ZEROW2B
Definition plplot.h:322
#define PLESC_FLUSH
Definition plplot.h:281
#define PL_UNUSED(x)
Definition plplot.h:138
#define PLESC_IMAGE
Definition plplot.h:291
#define pltext
Definition plplot.h:855
#define PLESC_DOUBLEBUFFERING_DISABLE
Definition plplot.h:577
#define PLESC_RESIZE
Definition plplot.h:275
#define PLESC_FILL
Definition plplot.h:279
#define ONEW2D
Definition plplot.h:325
#define PLESC_XORMOD
Definition plplot.h:286
int PLINT
Definition plplot.h:181
#define PLESC_DOUBLEBUFFERING
Definition plplot.h:285
#define PLESC_IMAGEOPS
Definition plplot.h:292
#define PLESC_DOUBLEBUFFERING_ENABLE
Definition plplot.h:576
#define PLESC_REDRAW
Definition plplot.h:276
#define PLPLOT_MUTEX_RECURSIVE
static void UpdateXhairs(PlPlotter *)
Definition plplotter.c:1231
static void DestroyXhairs(PlPlotter *)
Definition plplotter.c:1191
static void DrawXhairs(PlPlotter *, int, int)
Definition plplotter.c:1206
static void CreateXhairs(PlPlotter *)
Definition plplotter.c:1153
static int child
Definition plserver.c:45
static int plplot_ccmap
Definition plxwd.h:37
#define PLXDISPLAYS
Definition plxwd.h:27
PLCHAR_VECTOR name
Definition plplot.h:552
unsigned char r
Definition plplot.h:548
unsigned char g
Definition plplot.h:549
unsigned char b
Definition plplot.h:550
plD_eop_fp pl_eop
Definition disptab.h:86
const char * pl_DevName
Definition disptab.h:80
plD_esc_fp pl_esc
Definition disptab.h:90
plD_wait_fp pl_wait
Definition disptab.h:91
plD_polyline_fp pl_polyline
Definition disptab.h:85
plD_state_fp pl_state
Definition disptab.h:89
plD_tidy_fp pl_tidy
Definition disptab.h:88
plD_line_fp pl_line
Definition disptab.h:84
plD_init_fp pl_init
Definition disptab.h:83
plD_bop_fp pl_bop
Definition disptab.h:87
const char * pl_MenuStr
Definition disptab.h:79
unsigned int y
Definition plplot.h:461
unsigned int x
Definition plplot.h:461
unsigned int height
Definition plplot.h:462
unsigned int width
Definition plplot.h:462
char string[PL_MAXKEY]
Definition plplot.h:440
PLFLT wX
Definition plplot.h:443
PLFLT wY
Definition plplot.h:443
PLFLT dY
Definition plplot.h:442
unsigned int state
Definition plplot.h:436
unsigned int keysym
Definition plplot.h:437
PLFLT dX
Definition plplot.h:442
unsigned int button
Definition plplot.h:438
void(* KeyEH)(PLGraphicsIn *gin, void *KeyEH_data, int *exit_eventloop)
Definition plstrm.h:598
void * ButtonEH_data
Definition plstrm.h:604
PLINT ncol1
Definition plstrm.h:539
long window_id
Definition plstrm.h:634
PLINT verbose
Definition plstrm.h:527
PLINT ylength
Definition plstrm.h:617
PLINT ncol0
Definition plstrm.h:539
PLColor * cmap0
Definition plstrm.h:544
PLINT dev_fill0
Definition plstrm.h:571
PLINT page
Definition plstrm.h:578
void * LocateEH_data
Definition plstrm.h:608
PLINT dev_npts
Definition plstrm.h:581
int ext_resize_draw
Definition plstrm.h:635
PLINT imclxmin
Definition plstrm.h:590
PLINT debug
Definition plstrm.h:527
PLINT color
Definition plstrm.h:569
short * dev_y
Definition plstrm.h:582
PLBOOL stream_closed
Definition plstrm.h:782
int nopixmap
Definition plstrm.h:635
PLINT xoffset
Definition plstrm.h:618
void(* LocateEH)(PLGraphicsIn *gin, void *LocateEH_data, int *locate_mode)
Definition plstrm.h:606
int db
Definition plstrm.h:635
PLINT plbuf_write
Definition plstrm.h:567
PLFLT width
Definition plstrm.h:552
PLINT yoffset
Definition plstrm.h:618
short * dev_x
Definition plstrm.h:582
char * plwindow
Definition plstrm.h:640
PLINT dev_fastimg
Definition plstrm.h:572
PLINT dev_nptsX
Definition plstrm.h:586
PLINT imclymax
Definition plstrm.h:590
PLColor tmpcolor
Definition plstrm.h:543
PLColor curcolor
Definition plstrm.h:543
PLINT icol1
Definition plstrm.h:539
char * FileName
Definition plstrm.h:576
PLINT dev_xor
Definition plstrm.h:572
short * dev_iy
Definition plstrm.h:587
short * dev_ix
Definition plstrm.h:587
unsigned short * dev_z
Definition plstrm.h:588
unsigned short dev_zmax
Definition plstrm.h:589
PLINT termin
Definition plstrm.h:568
PLINT plbuf_read
Definition plstrm.h:567
void * dev
Definition plstrm.h:594
PLINT xlength
Definition plstrm.h:617
PLINT imclymin
Definition plstrm.h:590
PLINT nopause
Definition plstrm.h:568
PLINT dev_flush
Definition plstrm.h:571
PLINT colorset
Definition plstrm.h:569
void(* ButtonEH)(PLGraphicsIn *gin, void *ButtonEH_data, int *exit_eventloop)
Definition plstrm.h:602
PLINT dev_nptsY
Definition plstrm.h:586
PLINT dev_eofill
Definition plstrm.h:788
PLINT imclxmax
Definition plstrm.h:590
PLINT icol0
Definition plstrm.h:539
void * KeyEH_data
Definition plstrm.h:600
PLFLT diorot
Definition plstrm.h:661
Definition plxwd.h:68
int instr
Definition plxwd.h:94
Window window
Definition plxwd.h:72
int write_to_window
Definition plxwd.h:91
XPoint xhair_y[2]
Definition plxwd.h:101
Pixmap pixmap
Definition plxwd.h:73
short xlen
Definition plxwd.h:89
unsigned width
Definition plxwd.h:82
XwDisplay * xwd
Definition plxwd.h:69
long init_width
Definition plxwd.h:79
GC gc
Definition plxwd.h:74
unsigned border
Definition plxwd.h:82
long event_mask
Definition plxwd.h:77
int locate_mode
Definition plxwd.h:99
long init_height
Definition plxwd.h:80
int exit_eventloop
Definition plxwd.h:78
XPoint xhair_x[2]
Definition plxwd.h:101
unsigned height
Definition plxwd.h:82
int drawing_xhairs
Definition plxwd.h:100
XColor bgcolor
Definition plxwd.h:107
double xscale
Definition plxwd.h:86
double xscale_init
Definition plxwd.h:84
XColor curcolor
Definition plxwd.h:75
double yscale_init
Definition plxwd.h:85
double yscale
Definition plxwd.h:87
int max_instr
Definition plxwd.h:95
void(* MasterEH)(PLStream *, XEvent *)
Definition plxwd.h:103
PLGraphicsIn gin
Definition plxwd.h:97
int is_main
Definition plxwd.h:71
int write_to_pixmap
Definition plxwd.h:92
short ylen
Definition plxwd.h:89
Visual * visual
Definition plxwd.h:49
Colormap map
Definition plxwd.h:51
int ncol1_alloc
Definition plxwd.h:57
unsigned depth
Definition plxwd.h:52
int ncol1
Definition plxwd.h:56
Cursor xhair_cursor
Definition plxwd.h:61
XColor * cmap0
Definition plxwd.h:58
int color
Definition plxwd.h:53
int rw_cmap
Definition plxwd.h:62
int screen
Definition plxwd.h:47
int ncol0
Definition plxwd.h:54
XColor fgcolor
Definition plxwd.h:60
int ixwd
Definition plxwd.h:45
int ncol0_alloc
Definition plxwd.h:55
GC gcXor
Definition plxwd.h:50
XColor * cmap1
Definition plxwd.h:59
char * displayName
Definition plxwd.h:46
Display * display
Definition plxwd.h:48
int nstreams
Definition plxwd.h:44
#define dbug_enter(a)
Definition tclMatrix.c:59
static int synchronize
Definition tkMain.c:132
static const char * display
Definition tkMain.c:136
int pldummy_xwin()
Definition xwin.c:3670