1 /* ======================================================= *
2  * Copyright 1998-2005 Stephen C. Grubb                    *
3  * http://ploticus.sourceforge.net                         *
4  * Covered by GPL; see the file ./Copyright for details.   *
5  * ======================================================= */
6 
7 /* ===========================
8    X11 xlib driver for ploticus.
9 
10    No checking for redundant calls is made here.
11 
12    Revisions:
13 	951109 - made font selection more robust and accessable via GRAPHCORE_XFONT env var.
14 	951109 - reduced # of redraws when window is moved
15 	960424 - improved efficiency re loading fonts
16 		 added color capability
17 		 added backing store capability
18 
19    ===========================
20 */
21 
22 
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25 #include <X11/Xos.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include "x11shades.h"
30 #include "pixpt.h"  /* circle ptlists */
31 
32 extern int TDH_err(), PLG_he(), PLGX_loadfont(), PLGX_pointsize(), PLGX_dot(), PLG_xsca(), PLG_ysca();
33 extern int PLGX_stroke(), PLGX_fill(), GL_member(), PLG_xrgb_to_rgb(), GL_goodnum(), PLG_colorname_to_rgb();
34 extern int atoi();
35 
36 
37 /* #define MAX_D_ROWS 1000 */		/* LIMIT: max# points in one polygon */
38 #define DEFAULT_FONT "-adobe-courier-bold-r-normal"
39 #define MISC_FONT "-misc-fixed-medium-r-normal"    /* available on NDG xterminals */
40 #define LAST_RESORT_FONT "9x15"
41 #define MAXCOLORS 40
42 #define MAXFONTS 8
43 
44 #define E_EXPOSE 1010  /* window has been exposed and contents restored from last save */
45 #define E_RESIZE 1011  /* window has been resized */
46 #define E_COLORMAP_FULL 1100 /* alert app that there are no more colors */
47 #define E_MONODISPLAY 1101 /* alert app that display is monochrome */
48 
49 
50 /* no initstatic for X11 .. doesn't seem necessary now */
51 static double x_oldx = 0, x_oldy = 0;
52 static int x_waitflag;
53 static Display	*x_disp;
54 static Window	x_win;
55 static int x_screen;
56 static GC x_gc;
57 static char x_dash[10][6]= {
58 		  {1}, {1,1}, {3,1}, {5,1}, {2,1,1,1}, {4,1,1,1}, {6,1,1,1},
59 		  {2,1,1,1,1,1}, {4,1,1,1,1,1}, {6,1,1,1,1,1} };
60 static int x_ndash[10] = { 1, 2, 2, 2, 4, 4, 4, 6, 6, 6 };
61 static int x_pixelsinch;
62 
63 /* create pixmap tiles for shading.. */
64 static Pixmap x_s_00, x_s_10, x_s_20, x_s_30, x_s_40, x_s_50, x_s_60, x_s_70, x_s_80, x_s_90, x_s1_0;
65 static Pixmap x_shadetile;
66 
67 /* polygon vertexes */
68 /* static XPoint x_vlist[MAX_D_ROWS]; */
69 static XPoint *x_ptlist;
70 static int x_npt = 0, x_maxpt;
71 
72 static int x_winheight, x_winwidth;   /* current size of window */
73 static int x_upperleftx, x_upperlefty; /* screen pixel position of upper left of window */
74 static double x_textscale = 1.0;
75 static int x_mapped; /* 1 if window mapped (visible) 0 if not */
76 
77 /**** text ****/
78 static XFontStruct *x_font; /* the full name of the current font */
79 static Font x_fontlist[MAXFONTS]; /* fonts for various text sizes loaded at setup time */
80 static XFontStruct *x_fontstructlist[MAXFONTS]; /* info for fonts */
81 static char x_fontset[120]; /* the font short name - known to be available */
82 
83 
84 /**** color ****/
85 struct x_rgbp {
86 	unsigned short r, g, b;
87 	unsigned long pix;
88 	};
89 static struct x_rgbp x_rgblist[ MAXCOLORS ]; /* list of r,g,b colors already allocated */
90 static int rgb_avail = 0;  /* next available slot in above array. */
91 static int x_colordisplay;  /* 1 if color, 0 if not */
92 static Colormap x_default_cmap;
93 static int x_display_depth;
94 static int x_colormessagedone = 0; /* 1 if the "Failure to allocate color" message has
95 					already been displayed. */
96 
97 /**** backing store ****/
98 static Pixmap x_backstore;
99 static int x_backstoreused = 0;
100 
101 static int x_mapflag = 1;	/* 1 if window should be mapped initally, 0 if it should be hidden initially - added 9/17/04 scg */
102 
103 /***** functions *****/
104 extern double PLG_xsca_inv(), PLG_ysca_inv();
105 #define Exsca( h )	PLG_xsca( h )
106 #define Eysca( h )	PLG_ysca( h )
107 #define Exsca_inv( h )	PLG_xsca_inv( h )
108 #define Eysca_inv( h )	PLG_ysca_inv( h )
109 #define Eerr(a,b,c)	TDH_err(a,b,c)
110 
111 
112 
113 /* =========================== */
114 /* get the graphcore environment handles.. */
115 int
PLGX_gethandle(display,window,gc)116 PLGX_gethandle( display, window, gc )
117 Display *display;
118 Window *window;
119 GC *gc;
120 {
121 display = x_disp;
122 window = &x_win;
123 gc = &x_gc;
124 return( 0 );
125 }
126 
127 /* ========================== */
128 /* ========================== */
129 /* ========================== */
130 int
PLGX_setup(name,pixels_inch,x_max,y_max,upperleftx,upperlefty,maxdrivervect)131 PLGX_setup( name, pixels_inch, x_max, y_max, upperleftx, upperlefty, maxdrivervect )
132 char name[];
133 int pixels_inch;
134 double x_max, y_max;
135 int upperleftx, upperlefty;  /* may be passed as -1, -1 for automatic centering on screen */
136 int maxdrivervect;
137 {
138 XSizeHints win_size;
139 XEvent event;
140 int nplanes; /* # of planes of display */
141 unsigned long fg, bg; /* forground and background for setting pixmaps */
142 char *userfont;
143 char *getenv();
144 int stat;
145 Font fnt;
146 int ptsizes[8];
147 int i;
148 double foo;
149 
150 ptsizes[0] = 8;
151 ptsizes[1] = 10;
152 ptsizes[2] = 12;
153 ptsizes[3] = 14;
154 ptsizes[4] = 18;
155 ptsizes[5] = 24;
156 
157 /* get window size in pixels */
158 x_winwidth =  (int)(x_max * pixels_inch );
159 x_winheight = (int)(y_max * pixels_inch );
160 x_pixelsinch = pixels_inch;
161 
162 
163 
164 /* initialize parameters */
165 x_font = NULL;
166 x_textscale = 1.0;
167 
168 /* open the display indicated in DISPLAY env var.. */
169 if(( x_disp = XOpenDisplay( NULL )) == NULL ) return( Eerr( 12040, "X Display not properly identified.  Set DISPLAY=", "" ) );
170 
171 /* see if user font env variable is defined.. */
172 userfont = getenv( "GRAPHCORE_XFONT" );
173 
174 /* malloc the drawing vector.. scg 5/4/04 */
175 x_maxpt = maxdrivervect;
176 x_ptlist = (XPoint *) malloc( x_maxpt * sizeof( XPoint ) );
177 
178 /* window size */
179 x_screen = DefaultScreen( x_disp );
180 
181 
182 if( upperleftx < 0 ) x_upperleftx = ( DisplayWidth( x_disp, x_screen ) / 2 ) - (x_winwidth / 2); /* center in screen */
183 else x_upperleftx = upperleftx;
184 
185 if( upperlefty < 0 ) x_upperlefty = ( DisplayHeight( x_disp, x_screen ) / 2 ) - (x_winheight / 2); /* center in screen */
186 else x_upperlefty = upperlefty;
187 
188 win_size.flags = PPosition | PSize;
189 win_size.x = x_upperleftx;
190 win_size.y = x_upperlefty;
191 win_size.width = x_winwidth;
192 win_size.height = x_winheight;
193 
194 /* create the window */
195 x_win = XCreateSimpleWindow (
196 	x_disp,
197 	RootWindow(x_disp, x_screen),	/*  parent window */
198 	win_size.x,
199 	win_size.y,		/*  location	  */
200 	win_size.width,
201 	win_size.height,	/*  size          */
202 	5,			/*  border	  */
203 	BlackPixel(x_disp,x_screen),	/*  forground	  */
204 	WhitePixel(x_disp,x_screen)	/*  background	  */
205 	);
206 
207 XSetWMNormalHints( x_disp, x_win, &win_size );
208 
209 XStoreName( x_disp, x_win, name );
210 
211 
212 /* determine whether screen is monochrome or color.. */
213 x_display_depth = DefaultDepth( x_disp, x_screen );
214 x_default_cmap = DefaultColormap( x_disp, x_screen );
215 /* x_default_cmap = XCreateColormap( x_disp, x_win, x_screen, AllocAll ); */ /* use this to create a private colormap */
216 if( x_display_depth > 1 ) x_colordisplay = 1;
217 else 	{
218 	x_colordisplay = 0;
219 	PLG_he( 0.0, 0.0, E_MONODISPLAY );
220 	}
221 
222 
223 /* create pattern grays for monochrome displays */
224 fg = BlackPixel(x_disp, x_screen);
225 bg = WhitePixel(x_disp, x_screen);
226 nplanes = XDisplayPlanes( x_disp, x_screen );
227 x_s_00 = XCreatePixmapFromBitmapData( x_disp, x_win, (char *)x_im_00, 16, 16, fg, bg, nplanes);
228 x_s_10 = XCreatePixmapFromBitmapData( x_disp, x_win, (char *)x_im_10, 16, 16, fg, bg, nplanes);
229 x_s_20 = XCreatePixmapFromBitmapData( x_disp, x_win, (char *)x_im_20, 16, 16, fg, bg, nplanes);
230 x_s_30 = XCreatePixmapFromBitmapData( x_disp, x_win, (char *)x_im_30, 16, 16, fg, bg, nplanes);
231 x_s_40 = XCreatePixmapFromBitmapData( x_disp, x_win, (char *)x_im_40, 16, 16, fg, bg, nplanes);
232 x_s_50 = XCreatePixmapFromBitmapData( x_disp, x_win, (char *)x_im_50, 16, 16, fg, bg, nplanes);
233 x_s_60 = XCreatePixmapFromBitmapData( x_disp, x_win, (char *)x_im_60, 16, 16, fg, bg, nplanes);
234 x_s_70 = XCreatePixmapFromBitmapData( x_disp, x_win, (char *)x_im_70, 16, 16, fg, bg, nplanes);
235 x_s_80 = XCreatePixmapFromBitmapData( x_disp, x_win, (char *)x_im_80, 16, 16, fg, bg, nplanes);
236 x_s_90 = XCreatePixmapFromBitmapData( x_disp, x_win, (char *)x_im_90, 16, 16, fg, bg, nplanes);
237 x_s1_0 = XCreatePixmapFromBitmapData( x_disp, x_win, (char *)x_im1_0, 16, 16, fg, bg, nplanes);
238 
239 
240 /*  create graphics context */
241 x_gc = XCreateGC( x_disp, x_win, 0, NULL );
242 
243 
244 /* set foreground and background colors.. */
245 XSetForeground( x_disp, x_gc, BlackPixel( x_disp, x_screen ));
246 XSetBackground( x_disp, x_gc, WhitePixel( x_disp, x_screen )); /* added SCG 950907 */
247 
248 /* set other attributes.. */
249 XSetLineAttributes( x_disp, x_gc, 1, LineSolid, CapButt, JoinMiter );
250 XSetFillStyle( x_disp, x_gc, FillSolid ); /* FillSolid is used for lines & text;
251 						we switch over to FillTiled for
252 						polygons below.. */
253 x_shadetile = x_s_00;
254 XSetTile( x_disp, x_gc, x_shadetile );
255 
256 
257 /* find a font to use.. */
258 stat = PLGX_loadfont( userfont, 10, &fnt ); 		/* user's choice font */
259 if( stat == 0 ) strcpy( x_fontset, userfont );
260 else	{
261 	stat = PLGX_loadfont( DEFAULT_FONT, 10, &fnt ); /* default font */
262 	if( stat == 0 ) strcpy( x_fontset, DEFAULT_FONT );
263 	else	{
264 		stat = PLGX_loadfont( MISC_FONT, 10, &fnt );    /* available on ndg xterms */
265 		if( stat == 0 ) strcpy( x_fontset, MISC_FONT );
266 		else	{
267 			stat = PLGX_loadfont( LAST_RESORT_FONT, 0, &fnt );	/* last resort.. */
268 			if( stat == 0 ) strcpy( x_fontset, LAST_RESORT_FONT );
269 			else return( Eerr( 12041, "Cannot load an X font.", "" ) );
270 			}
271 		}
272 	}
273 
274 /* load a range of point sizes in the requested font.. */
275 for( i = 0; i < 6; i++ ) {
276 	stat = PLGX_loadfont( x_fontset, ptsizes[i], &x_fontlist[i] );
277 	if( stat != 0 ) Eerr( 12042, "X Font load error", x_fontset );
278 	x_fontstructlist[i] = x_font;
279 	}
280 /* set the initial default font.. */
281 PLGX_pointsize( 10, &foo );
282 
283 
284 /* create pixmap for backing store.. */
285 x_backstore = XCreatePixmap( x_disp, x_win, x_winwidth, x_winheight, x_display_depth );
286 
287 
288 /* Set up for events  */
289 /*  we want: (1) mouse clicks (2) Key presses (3) expose events (4) resize events */
290 XSelectInput (
291 	x_disp,
292 	x_win,
293 	ButtonPressMask | ExposureMask | KeyPressMask | StructureNotifyMask
294 	);
295 
296 
297 /* map the window */
298 if( x_mapflag ) {
299 	XMapWindow( x_disp, x_win );
300 	x_mapped = 1;
301 
302 	/* wait for initial expose event to draw.. */
303 	while( 1 ) {
304 		XNextEvent( x_disp, &event );
305 		if( event.type == Expose ) break;
306 		}
307 	}
308 
309 return( 0 );
310 }
311 /* ============================== */
312 /* save window to backing store.. */
313 int
PLGX_savewin()314 PLGX_savewin( )
315 {
316 
317 XCopyArea( x_disp, x_win, x_backstore, x_gc, 0, 0, x_winwidth, x_winheight, 0, 0 );
318 x_backstoreused = 1;
319 return( 0 );
320 
321 }
322 /* ============================== */
323 /* restore window from backing store.. */
324 int
PLGX_restorewin()325 PLGX_restorewin( )
326 {
327 if( ! x_backstoreused ) return( 0 );
328 XCopyArea( x_disp, x_backstore, x_win, x_gc, 0, 0, x_winwidth, x_winheight, 0, 0 );
329 return( 0 );
330 }
331 
332 /* =============================== */
333 int
PLGX_event(event)334 PLGX_event( event )
335 XEvent event;
336 {
337 int x, y;
338 unsigned eid;
339 int charcount;
340 KeySym ks;
341 XComposeStatus compose; /* not used */
342 char buf[80];
343 
344 
345 if( event.type == KeyPress ) {
346 	x = event.xkey.x;
347 	y = event.xkey.y;
348 
349 	charcount = XLookupString( (XKeyEvent *) &event, buf, 80, &ks, &compose );
350 
351 	/* screen out shift, control, alt, etc. */
352 	if( ks >= 0xFFE1 && ks <= 0xFFEE ) x_waitflag = 0;
353 
354 	else	{
355 
356 		eid = buf[0];
357 
358 
359 		/* arrow keys, pg up, pg dn  - added scg 9/9/98 */
360 		/* home=550  left = 551   up = 552   right = 553    down = 554   pg up=555   pg down=556  end=557 */
361 		if( ks >= 0xFF50 && ks <= 0xFF58 ) {
362 			ks &= 0x00FF;
363 			eid = ks + 470;
364 			x_waitflag = PLG_he( Exsca_inv( x ), Eysca_inv( y ), eid );
365 			}
366 
367 		/* all other keys */
368 		else	{
369 			/* eid &= 0x007F; */
370 			ks &= 0x00FF;
371 			if( charcount < 1 ) eid = ks - 96; /* map control chars to ascii 1-26 */
372 			x_waitflag = PLG_he( Exsca_inv( x ), Eysca_inv( y ), eid );
373 			}
374 		}
375 	}
376 else if( event.type == ButtonPress ) {
377 	x = event.xbutton.x;
378 	y = event.xbutton.y;
379 	if( event.xbutton.button == Button1 ) eid = 1001;
380 	else if( event.xbutton.button == Button2 ) eid = 1002;
381 	else if( event.xbutton.button == Button3 ) eid = 1003;
382 	x_waitflag = PLG_he( Exsca_inv( x ), Eysca_inv( y ), eid );
383 	}
384 else if( event.type == Expose ) {
385 	if( event.xexpose.count == 0 ) {
386 		PLG_he( 0.0, 0.0, E_EXPOSE );
387 		}
388 	}
389 
390 else if( event.type == ConfigureNotify ) {
391 
392 #ifdef SUSPENDED
393 	/* seems to work better without.. scg 9/24/04 */
394 
395 	/* on openwin, this event is generated when window is moved, and when it is
396 	 * resized.  We need do nothing when it is simply moved; when it is resized
397 	 * we need to recalculate and redisplay everything.. */
398 
399 	if( (double)event.xconfigure.width != x_winwidth ||
400 	   (double)(event.xconfigure.height) != x_winheight ) { /* if size changed.. */
401 
402 		Pixmap tmppixmap;
403 		int minh, minw;
404 
405 		/* see which width and which height are smallest, new size or old size */
406 		if( event.xconfigure.width < x_winwidth ) minw = event.xconfigure.width;
407 		else minw = x_winwidth;
408 		if( event.xconfigure.height < x_winheight ) minh = event.xconfigure.height;
409 		else minh = x_winheight;
410 
411 		/* now set the window size */
412 		x_winwidth = event.xconfigure.width;
413 		x_winheight = event.xconfigure.height;
414 
415 		/* need to handle backing store.. */
416 
417 		/* allocate a new pixmap sized to the new window size.. */
418 		tmppixmap = XCreatePixmap( x_disp, x_win, x_winwidth,
419 			x_winheight, x_display_depth );
420 
421 		/* copy from window to new backing store to get a blank area..*/
422 		XCopyArea( x_disp, x_win, tmppixmap, x_gc, 0, 0, minw, minh, 0, 0 );
423 
424 		/* copy from old backing store to new based on min size.. */
425 		XCopyArea( x_disp, x_backstore, tmppixmap, x_gc, 0, 0, minw, minh, 0, 0 );
426 
427 		/* free the old backing store.. */
428 		XFreePixmap( x_disp, x_backstore );
429 
430 		/* and make x_backstore point to new backing store.. */
431 		x_backstore = tmppixmap;
432 
433 		PLG_he( (double)(event.xconfigure.width),
434 			(double)(event.xconfigure.height), E_RESIZE );
435 
436 		PLGX_savewin( );
437 		}
438 #endif
439 	}
440 else if( event.type == MappingNotify ) {
441 	XRefreshKeyboardMapping( (XMappingEvent *) &event );
442 	}
443 return( 0 );
444 }
445 
446 
447 /* ============================== */
448 /* Code driven resize of window.
449    To use this, caller must be prepared to redraw display when this routine returns.
450    All parameters (except pixels_inch) may be sent as -1 = don't change */
451 
452 int
PLGX_resizewin(pixels_inch,upperleftx,upperlefty,x_max,y_max)453 PLGX_resizewin( pixels_inch, upperleftx, upperlefty, x_max, y_max )
454 int pixels_inch, upperleftx, upperlefty;
455 double x_max, y_max;
456 {
457 #ifdef SUSPENDED /* on linux x11R6 .. this routine leads to instability apparently related to x_backstore.. */
458 
459 XSizeHints win_size;
460 
461 /* get window size in pixels */
462 if( x_max > 0 ) x_winwidth =  (int)(x_max * pixels_inch );
463 if( y_max > 0 ) x_winheight = (int)(y_max * pixels_inch );
464 
465 if( upperleftx < 0 ) x_upperleftx = ( DisplayWidth( x_disp, x_screen ) / 2 ) - (x_winwidth / 2); /* center on screen */
466 if( upperlefty < 0 ) x_upperlefty = ( DisplayHeight( x_disp, x_screen ) / 2 ) - (x_winheight / 2); /* center on screen */
467 if( upperleftx > 0 ) x_upperleftx = upperleftx;
468 if( upperlefty > 0 ) x_upperlefty = upperlefty;
469 
470 win_size.x = x_upperleftx; win_size.y = x_upperlefty;
471 win_size.width = x_winwidth; win_size.height = x_winheight;
472 
473 /* resize the window */
474 XMoveResizeWindow ( x_disp, x_win, win_size.x, win_size.y, win_size.width, win_size.height );
475 
476 /* free and reallocate backing store at new size.. */
477 XFreePixmap( x_disp, x_backstore );
478 x_backstore = XCreatePixmap( x_disp, x_win, x_winwidth, x_winheight, x_display_depth );
479 
480 /* XSetWMNormalHints( x_disp, x_win, &win_size ); */
481 XFlush( x_disp ); /* scg 2-13-96 */
482 
483 #endif
484 return( 0 );
485 }
486 
487 /* =============================== */
488 int
PLGX_wait()489 PLGX_wait()
490 {
491 XEvent event;
492 x_waitflag = 0;
493 while( ! x_waitflag ) {
494 	XNextEvent( x_disp, &event );
495 	PLGX_event( event );
496         }
497 return( 0 );
498 }
499 
500 /* ==================== dot */
501 int
PLGX_dot(x,y)502 PLGX_dot( x, y )
503 double x, y;
504 {
505 XDrawPoint( x_disp, x_win, x_gc, Exsca( x ), Eysca( y ) );
506 return( 0 );
507 }
508 
509 /* ====================  line to */
510 int
PLGX_lineto(x,y)511 PLGX_lineto(x,y)
512 double x, y;
513 {
514 
515 
516 if( x_npt >= x_maxpt ) PLGX_stroke();  /* stroke what we have so far then begin a new line.. */
517 
518 if( x_npt == 0 ) { x_ptlist[0].x = Exsca( x_oldx ); x_ptlist[0].y = Eysca( x_oldy ); x_npt++; }
519 x_ptlist[ x_npt ].x = Exsca(x);
520 x_ptlist[ x_npt ].y = Eysca(y);
521 x_npt++;
522 
523 /* rewritten 5/4/04 scg.. was:
524  * a = Exsca( x_oldx ); b = Eysca( x_oldy ); c = Exsca( x ); d = Eysca( y );
525  * XDrawLine( x_disp, x_win, x_gc, a, b, c, d );
526  */
527 
528 x_oldx=x;
529 x_oldy=y;
530 return( 0 );
531 }
532 
533 /* =====================  moveto */
534 int
PLGX_moveto(x,y)535 PLGX_moveto(x,y)
536 double x, y;
537 {
538 x_oldx = x;
539 x_oldy = y;
540 return( 0 );
541 }
542 
543 /* ======================== stroke */
544 int
PLGX_stroke()545 PLGX_stroke()
546 {
547 XDrawLines( x_disp, x_win, x_gc, x_ptlist, x_npt, CoordModeOrigin );
548 x_npt = 0;
549 return( 0 );
550 }
551 
552 /* ===================== raw line - no conversion on coords */
553 int
PLGX_rawline(a,b,c,d)554 PLGX_rawline( a, b, c, d )
555 int a, b, c, d;
556 {
557 XDrawLine( x_disp, x_win, x_gc, a, b, c, d );
558 return( 0 );
559 }
560 
561 /* ===================== set point size of type */
562 /* pointsize */
563 int
PLGX_pointsize(p,aw)564 PLGX_pointsize( p, aw )
565 int p;
566 double *aw; /* width of one character -- returned */
567 {
568 
569 Font fnt;
570 int i;
571 
572 /* scale based upon pixels/inch */
573 p = (int)(p * x_textscale);
574 
575 /* use p to get index into font list.. */
576 if( p <= 6 )  i = 0;
577 else if( p == 7 || p == 8 )  i = 1;
578 else if( p == 9 || p == 10 )  i = 2;
579 else if( p >= 11 && p <= 14 ) i = 3;
580 else if( p >= 15 && p <= 18 ) i = 4;
581 else i = 5;
582 
583 fnt = x_fontlist[i]; /* access font from pre-allocated list */
584 x_font = x_fontstructlist[i]; /* and get font info */
585 
586 /* get the approximate text width.. */
587 *aw = Exsca_inv( XTextWidth( x_font, "A", 1 ) );
588 
589 /* set the font.. */
590 XSetFont( x_disp, x_gc, fnt );
591 return( 0 );
592 }
593 
594 /* ======================== */
595 /* x_ LOADFONT - given short font name f, see if an X font is available for
596    the requested size, or something close.. */
597 /* When this routine returns successfully, Font is returned in fnt, and
598    XFontStruct is placed in x_font. */
599 
600 int
PLGX_loadfont(f,size,fnt)601 PLGX_loadfont( f, size, fnt )
602 char *f;
603 int size;
604 Font *fnt;
605 {
606 char fontname[100];
607 char ofslist[12];
608 int i, p;
609 /* Font fnt; */
610 
611 strcpy( ofslist, "EFDGCHBIAJ" ); /* used to vary the size.. */
612 
613 if( f == NULL ) return( 1 );
614 if( f[0] == '\0' ) return( 1 );
615 if( strcmp( f, LAST_RESORT_FONT ) == 0 ) {
616 	strcpy( fontname, f );
617 	x_font = XLoadQueryFont( x_disp, fontname );
618 	if( x_font == NULL ) return( 1 );
619 	goto LOAD_IT;
620 	}
621 
622 for( i = 0; i < 10; i++ ) { /* try 10 times with varying sizes until we get a hit.. */
623 	p = size + ( ofslist[i] - 'E' );
624 	sprintf( fontname, "%s--%d-*-*-*-*-*-*-*", f, p );
625 	x_font = XLoadQueryFont( x_disp, fontname );
626 	if( x_font != NULL ) break;
627 	}
628 if( i == 10 ) return( 1 ); /* not found */
629 
630 LOAD_IT:
631 *fnt = XLoadFont( x_disp, fontname );
632 return( 0 );
633 }
634 
635 /* ==================== x_scaletext - when window is resized, to adjust text size */
636 int
PLGX_scaletext(f)637 PLGX_scaletext( f )
638 double f;
639 {
640 x_textscale = f;
641 return( 0 );
642 }
643 
644 /* ==================== x_display left adjusted text starting at current position */
645 int
PLGX_text(s,aw)646 PLGX_text( s, aw )
647 char s[];
648 double *aw; /* actual string width in inches (sent back) */
649 {
650 /* XSetFillStyle( x_disp, x_gc, FillSolid ); */  /* added SCG 950907 */
651 XDrawString( x_disp, x_win, x_gc, Exsca( x_oldx ), Eysca( x_oldy ), s, strlen( s ) );
652 /* XSetFillStyle( x_disp, x_gc, FillTiled ); */  /* added SCG 950907 */
653 *aw = Exsca_inv( XTextWidth( x_font, s, strlen( s ) ) );
654 x_oldx += ( *aw );
655 return( 0 );
656 }
657 
658 /* ==================== x_display centered text */
659 int
PLGX_centext(s,w,x,aw)660 PLGX_centext( s, w, x, aw )
661 char s[];
662 double w;
663 double *x; /* actual X starting point in inches (sent back) */
664 double *aw; /* actual string width in inches (sent back) */
665 {
666 double width;
667 
668 /* GL_strip_ws( s ); */ /* removed scg 8/23/04 (suscript) */
669 width = Exsca_inv( XTextWidth( x_font, s, strlen( s ) ) );
670 PLGX_moveto( x_oldx+((w-width)/2.0), x_oldy );
671 PLGX_text( s, aw );
672 *x = Exsca_inv((int)( x_oldx+((w-width)/2.0) ) );
673 return( 0 );
674 }
675 
676 /* ==================== x_display right-justified text */
677 int
PLGX_rightjust(s,w,x,aw)678 PLGX_rightjust( s, w, x, aw )
679 char s[];
680 double w;
681 double *x; /* actual X starting point in inches (sent back) */
682 double *aw; /* actual string width in inches (sent back) */
683 {
684 double width;
685 
686 /* GL_strip_ws( s ); */ /* removed scg 8/23/04 (suscript) */
687 width = Exsca_inv( XTextWidth( x_font, s, strlen( s ) ) );
688 PLGX_moveto( x_oldx+(w-width), x_oldy );
689 PLGX_text( s, aw );
690 *x = Exsca_inv((int)(x_oldx+(w-width) ));
691 return( 0 );
692 }
693 
694 /* ========= set line thickness and dash pattern attribs ============= */
695 
696 int
PLGX_linetype(t,w,mag)697 PLGX_linetype( t, w, mag )
698 char t[];
699 double w, mag;
700 {
701 int i, j;
702 int linewidth;
703 char dashlist[12];
704 int style;
705 
706 if( t[0] == '\0' ) return( 0 );
707 linewidth = (w*1.6) + 0.5;
708 style = atoi( t );
709 if( style < 1 || style > 9 ) {
710 	XSetLineAttributes( x_disp, x_gc, linewidth, LineSolid, CapButt, JoinMiter );
711 	}
712 else	{
713 	for( i = 0; i < x_ndash[ style % 10 ]; i++ ) {
714 		j = (int) ( x_dash[ style %10 ][i] * mag );
715 		if( j < 1 ) j = 1;
716 		if( j > 127 ) j = 127; /* keep in char range */
717 		dashlist[i] = (char) j;
718 		}
719 
720 	XSetDashes( x_disp, x_gc, 0, dashlist, x_ndash[ atoi(t)%10 ] );
721 	XSetLineAttributes( x_disp, x_gc, linewidth, LineOnOffDash, CapButt, JoinMiter );
722 	}
723 return( 0 );
724 }
725 
726 /* ==================== add to "fill path" */
727 int
PLGX_path(x,y)728 PLGX_path( x, y )
729 double x, y;
730 {
731 
732 if( x_npt >= x_maxpt ) PLGX_fill(); /* fill what we have so far then start over.. */
733 
734 if( x_npt == 0 ) { x_ptlist[0].x = Exsca( x_oldx ); x_ptlist[0].y = Eysca( x_oldy ); x_npt++; }
735 x_ptlist[ x_npt ].x = Exsca(x);
736 x_ptlist[ x_npt ].y = Eysca(y);
737 x_npt++;
738 return( 0 );
739 }
740 
741 
742 /* ==================== fill prev. defined polygon path with current color */
743 int
PLGX_fill()744 PLGX_fill( )
745 {
746 
747 if( !x_colordisplay ) {
748 	XSetTile( x_disp, x_gc, x_shadetile );
749 	XSetFillStyle( x_disp, x_gc, FillTiled );   /* added SCG 11-10-95 */
750 	}
751 
752 
753 XFillPolygon( x_disp, x_win, x_gc, x_ptlist, x_npt, Complex, CoordModeOrigin );
754 
755 /* set fillstyle back to solid and set tile back to black.. */
756 if( !x_colordisplay ) {
757 	XSetFillStyle( x_disp, x_gc, FillSolid );   /* added SCG 11-10-95 */
758 	XSetTile( x_disp, x_gc, x_s_00 );
759 	}
760 /* reset vertex counter */
761 x_npt = 0;
762 return( 0 );
763 }
764 
765 /* ==================== set drawing color */
766 int
PLGX_color(color)767 PLGX_color( color )
768 char *color;
769 {
770 int i, n;
771 double r, g, b, avg, atof(), PLG_rgb_to_gray();
772 int slen;
773 
774 /* color parameter can be in any of these forms:
775    "rgb(R,G,B)"  where R(ed), G(reen), and B(lue) are 0.0 (none) to 1.0 (full)
776    "xrgb(xxxxxx)" or "xrgb(xxxxxxxxxxxx)"
777    "hsb(H,S,B)"  where H(ue), S(aturation), and B(rightness) range from 0.0 to 1.0.
778    "gray(S)"	 where S is 0.0 (black) to 1.0 (white)
779    "S"		 same as above
780 */
781 for( i = 0, slen = strlen( color ); i < slen; i++ ) {
782 	if( GL_member( color[i], "(),/:|-" ) ) color[i] = ' ';
783 	}
784 
785 /* for now, convert to gray using the first parameter.. */
786 if( strncmp( color, "rgb", 3 )==0 ) {
787 	n = sscanf( color, "%*s %lf %lf %lf", &r, &g, &b );
788 	if( n != 3 ) { Eerr( 24780, "Invalid color", color ); return(1); }
789 	}
790 else if( strncmp( color, "gray", 4 )==0 || strncmp( color, "grey", 4 )==0 ) {
791 	n = sscanf( color, "%*s %lf", &r );
792 	if( n != 1 ) { Eerr( 24780, "Invalid color", color ); return(1); }
793 	g = b = r;
794 	}
795 else if( strncmp( color, "xrgb", 4 )==0 ) {
796         if (PLG_xrgb_to_rgb( &color[5], &r, &g, &b)) return(1);
797         }
798 else if( color[0] == 'x' ) {  /* added scg 11/5/07 */
799         if (PLG_xrgb_to_rgb( &color[1], &r, &g, &b)) return(1);
800         }
801 else if( GL_goodnum( color, &i ) ) {
802 	r = atof( color );
803 	g = b = r;
804 	}
805 else PLG_colorname_to_rgb( color, &r, &g, &b );
806 
807 
808 if( ! x_colordisplay ) {
809 	avg = PLG_rgb_to_gray( r, g, b );
810 
811 	/* select a tile for current shading.. */
812 	if( avg == 1.0 ) x_shadetile = x_s1_0;  /* white */
813 	else if( avg <= .15 ) x_shadetile = x_s_00; /* black */
814 	else if( avg > .95 ) x_shadetile = x_s_90; /* greys.. */
815 	else if( avg > .90 ) x_shadetile = x_s_80;
816 	else if( avg > .85 ) x_shadetile = x_s_70;
817 	else if( avg > .75 ) x_shadetile = x_s_60;
818 	else if( avg > .65 ) x_shadetile = x_s_50;
819 	else if( avg > .55 ) x_shadetile = x_s_40;
820 	else if( avg > .45 ) x_shadetile = x_s_30;
821 	else if( avg > .35 ) x_shadetile = x_s_20;
822 	else if( avg > .15 ) x_shadetile = x_s_10;
823 	else x_shadetile = (Pixmap ) 0;
824 
825 	/* set color for lines and text.. */
826 	if( r >= 1.0 && g >= 1.0 && b >= 1.0 ) {  /* white */
827 		XSetForeground( x_disp, x_gc, WhitePixel( x_disp, x_screen ));
828 		XSetBackground( x_disp, x_gc, BlackPixel( x_disp, x_screen )); /* 950907 */
829 		}
830 	else {  /* black */
831 		XSetForeground( x_disp, x_gc, BlackPixel( x_disp, x_screen ));
832 		XSetBackground( x_disp, x_gc, WhitePixel( x_disp, x_screen )); /* 950907 */
833 		}
834 	}
835 else	{
836 	unsigned short sr, sg, sb;
837 	XColor colordef;
838 	int status;
839 
840 	/* convert double r, g, b to unsigned short.. 1.0 to 65535 */
841 	sr = (unsigned short)(r * 65535.0);
842 	sg = (unsigned short)(g * 65535.0);
843 	sb = (unsigned short)(b * 65535.0);
844 
845 	/* see if this color is in list of colors allocated so far.. */
846 	for( i = 0; i < rgb_avail; i++ ) {
847 		if( sr == x_rgblist[i].r && sg == x_rgblist[i].g &&
848 			sb == x_rgblist[i].b  ) break;
849 		}
850 	if( i == rgb_avail ) { 	/* it wasn't found, add it to the list.. */
851 		if( rgb_avail >= MAXCOLORS ) {
852 			i = rgb_avail = 0;
853 
854 			}
855 		colordef.red = sr;
856 		colordef.green = sg;
857 		colordef.blue = sb;
858 		status = XAllocColor( x_disp, x_default_cmap, &colordef );
859 		if( status == 0 ) {
860 			if( !x_colormessagedone ) Eerr( 12050, "warning, X colormap full; colors may be inaccurate", "" );
861 			x_colormessagedone = 1;
862 			XSetForeground( x_disp, x_gc, colordef.pixel );
863 			return( 1 );
864 			}
865 		XSetForeground( x_disp, x_gc, colordef.pixel );
866 		x_rgblist[i].r = sr; /* colordef.red; */
867 		x_rgblist[i].g = sg; /* colordef.green; */
868 		x_rgblist[i].b = sb; /* colordef.blue; */
869 		x_rgblist[i].pix = colordef.pixel;
870 		rgb_avail++;
871 		return( 1 );
872 		}
873 	else 	{
874 		XSetForeground( x_disp, x_gc, x_rgblist[i].pix );
875 		return( 1 );
876 		}
877 	}
878 return( 0 );
879 }
880 
881 /* ================================ */
882 /* PIXPT - pixel data point - clean data points rendered by setting pixels directly */
883 /* added scg 5/29/06 */
884 /* note: color already set by symboldet() */
885 int
PLGX_pixpt(x,y,symcode)886 PLGX_pixpt( x, y, symcode )
887 double x, y;
888 char *symcode;
889 {
890 int a, b;
891 int i, j, irow, icol, radius, iw, omode, scanend;
892 double atof();
893 
894 /* Note - this code is essentially replicated in grgd.c */
895 
896 if( symcode[0] == 'o' ) { omode = 1; symcode[0] = 'p'; }
897 else omode = 0;
898 
899 a = Exsca( x ); b = Eysca( y ); /* convert to pixel coordinates */
900 
901 if( strncmp( symcode, "pixsquare", 9 )==0 ) {
902 	radius = (int) (atof( &symcode[9] ) * x_pixelsinch);
903 	if( radius < 1 ) radius = 3;
904 	if( omode ) { /* do top and bottom lines */
905 		irow = b-radius; for( icol = a-radius; icol < a+radius; icol++ ) XDrawPoint( x_disp, x_win, x_gc,  icol, irow );
906 		irow = b+radius; for( icol = a-radius; icol <= a+radius; icol++ ) XDrawPoint( x_disp, x_win, x_gc,  icol, irow );
907 		}
908 	for( irow = b-radius; irow < b+radius; irow++ ) {
909 		if( omode ) { XDrawPoint( x_disp, x_win, x_gc,  a-radius, irow ); XDrawPoint( x_disp, x_win, x_gc, a+radius, irow ); }
910 		else { for( icol = a-radius; icol < a+radius; icol++ ) XDrawPoint( x_disp, x_win, x_gc,  icol, irow ); }
911 		}
912 	}
913 else if( strncmp( symcode, "pixcircle", 9 )==0 ) {
914 	radius = (int) (atof( &symcode[9] ) * x_pixelsinch);
915 	if( radius <= 2 ) goto DO_DIAMOND;
916 	else if( radius > 9 ) radius = 9;
917 	for( i = circliststart[radius]; ; i+= 2 ) {
918 		scanend = circpt[i+1];
919 		if( circpt[i] == 0 && scanend == 0 ) break;
920 		for( j = 0; j <= scanend; j++ ) {
921 			if( omode && !( j == scanend )) continue;
922 			XDrawPoint( x_disp, x_win, x_gc,  a-j, b+circpt[i] );
923 			if( j > 0 ) XDrawPoint( x_disp, x_win, x_gc,  a+j, b+circpt[i] );
924 			XDrawPoint( x_disp, x_win, x_gc,  a-j, b-circpt[i] );
925 			if( j > 0 ) XDrawPoint( x_disp, x_win, x_gc,  a+j, b-circpt[i] );
926 			if( omode ) {
927 				XDrawPoint( x_disp, x_win, x_gc,  a+circpt[i], b-j );
928 				if( j > 0 ) XDrawPoint( x_disp, x_win, x_gc,  a+circpt[i], b+j );
929 				XDrawPoint( x_disp, x_win, x_gc,  a-circpt[i], b-j );
930 				if( j > 0 ) XDrawPoint( x_disp, x_win, x_gc,  a-circpt[i], b+j );
931 				}
932 			}
933 		}
934 	}
935 else if( strncmp( symcode, "pixdiamond", 10 )==0 ) {
936 	radius = (int) (atof( &symcode[10] ) * x_pixelsinch);
937 	DO_DIAMOND:
938 	if( radius < 1 ) radius = 3;
939 	radius++;  /* improves consistency w/ other shapes */
940 	for( irow = b-radius, iw = 0; irow <= (b+radius); irow++, iw++ ) {
941 	    scanend = a+abs(iw);
942 	    for( icol = a-abs(iw), j = 0; icol <= scanend; icol++, j++ ) {
943 		if( omode && !( j == 0 || icol == scanend )) ;
944 		else XDrawPoint( x_disp, x_win, x_gc,  icol, irow );
945 		}
946 	    if( irow == b ) iw = (-radius);
947 	    }
948 	}
949 else if( strncmp( symcode, "pixtriangle", 11 )==0 ) {
950 	radius = (int) (atof( &symcode[11] ) * x_pixelsinch);
951 	if( radius < 1 ) radius = 3;
952 	for( irow = b-radius, iw = 0; irow <= b+radius; irow++, iw++ ) {
953 	    scanend = a+abs(iw/2);
954 	    for( icol = a-abs(iw/2), j = 0; icol <= scanend; icol++, j++ ) {
955 		if( omode && irow == b+radius ) XDrawPoint( x_disp, x_win, x_gc,  icol, irow-1 );
956 		else if( omode && !( j == 0 || icol == scanend ));
957 		else XDrawPoint( x_disp, x_win, x_gc,  icol, irow-1 );
958 		}
959 	    }
960 	}
961 else if( strncmp( symcode, "pixdowntriangle", 15 )==0 ) {
962 	radius = (int) (atof( &symcode[15] ) * x_pixelsinch);
963 	if( radius < 1 ) radius = 3;
964 	for( irow = b+radius, iw = 0; irow >= (b-radius); irow--, iw++ ) {
965 	    scanend = a+abs(iw/2);
966 	    for( icol = a-abs(iw/2), j = 0; icol <= scanend; icol++, j++ ) {
967 		if( omode && irow == b-radius ) XDrawPoint( x_disp, x_win, x_gc,  icol, irow-1 );
968 		else if( omode && !(j == 0 || icol == scanend ));
969 		else XDrawPoint( x_disp, x_win, x_gc,  icol, irow );
970 		}
971 	    }
972 	}
973 return( 0 );
974 }
975 
976 /* ==================== asynchronous */
977 int
PLGX_async()978 PLGX_async()
979 {
980 XEvent event;
981 while( 1 ) {
982 	if( XCheckMaskEvent( x_disp, ButtonPressMask | ExposureMask |
983 		KeyPressMask | StructureNotifyMask , &event ) != True ) return(1);
984 	PLGX_event( event );
985         }
986 }
987 /* ==================== */
988 int
PLGX_flush()989 PLGX_flush()
990 {
991 XFlush( x_disp );
992 return( 0 );
993 }
994 
995 /* ===================== */
996 int
PLGX_appear()997 PLGX_appear()
998 {
999 XEvent event;
1000 
1001 if( x_mapped ) return( 0 );
1002 
1003 /* map the window */
1004 XMapWindow( x_disp, x_win );
1005 x_mapped = 1;
1006 
1007 /* wait for initial expose event to draw.. */
1008 /* added scg 9/17/04 */
1009 while( 1 ) {
1010         XNextEvent( x_disp, &event );
1011         if( event.type == Expose ) break;
1012         }
1013 
1014 /* redraw everything.. */
1015 XFlush( x_disp );
1016 return( 0 );
1017 }
1018 /* ====================== */
1019 int
PLGX_disappear()1020 PLGX_disappear()
1021 {
1022 if( ! x_mapped ) return( 0 );
1023 
1024 /* unmap the window.. */
1025 XUnmapWindow( x_disp, x_win );
1026 x_mapped = 0;
1027 XFlush( x_disp );
1028 return( 0 );
1029 }
1030 
1031 /* ======================= */
1032 /* allow various obscure settings to be done.. */
1033 int
PLGX_flag(what,val)1034 PLGX_flag( what, val )
1035 char *what;
1036 int val;
1037 {
1038 if( strcmp( what, "initial_map" )==0 ) x_mapflag = val;
1039 return( 0 );
1040 }
1041 
1042 /* ======================= */
1043 int
PLGX_screen_dimensions(height,width)1044 PLGX_screen_dimensions( height, width )
1045 int *height, *width;
1046 {
1047 *height = DisplayHeight( x_disp, x_screen );
1048 *width = DisplayWidth( x_disp, x_screen );
1049 return( 0 );
1050 }
1051 
1052 /* ======================================================= *
1053  * Copyright 1998-2005 Stephen C. Grubb                    *
1054  * http://ploticus.sourceforge.net                         *
1055  * Covered by GPL; see the file ./Copyright for details.   *
1056  * ======================================================= */
1057