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