/* xorbit.c Program using X11 to make simulation of planetary orbits. To compile: linux: gcc -O2 -o xorbit xorbit.c -lm -lX11 -L/usr/X11/lib Sun: cc -O -o xorbit xorbit.c -lm -lX11 -I/usr/openwin/include other?: cc -O -o xorbit xorbit.c -lm -lX11 -I/usr/local/include Usage should be self-explanatory, use buttons or keys as shown in the help screen to give commands. Everything should work OK under window exposure and resizing. Gary Wysin (wysin@phys.ksu.edu, http://www.phys.ksu.edu/~wysin/) */ #include #include #include #include #include /* for usual io */ #include /* for tolower() */ #include /* for exit, malloc() */ #include /* for sin, etc */ #include /* for usleep() */ /* These are used as arguments to nearly every Xlib routine, so it saves routine arguments to declare them global. If there were additional source files, they would be declared extern there. */ Display *display; int screen_num; Window win, quitbutton, pausebutton, helpbutton; Window eccbutton, speedbutton, reversebutton, areabutton; unsigned int win_width, win_height; /* main window size */ XSizeHints *size_hints; int depth,darkcolor,lightcolor,deepcolor,brightcolor,yellowcolor,black,white; long event_mask; XIconSize *size_list; XWMHints *wm_hints; XClassHint *class_hints; XTextProperty windowName, iconName; GC gcbw,gcpen,gcdeep,gcbrt,gcyel,gcclear; XFontStruct *small_font, *large_font; static char *PAUSE[2] = {"pause","run"}; /* dimensions for control buttons */ #define BORDER 6 #define BUTTONWIDTH 60 #define BUTTONHEIGHT 24 #define BIGBUTTWIDTH 6*BUTTONWIDTH+5*BORDER #define NORESIZE 0 #define RESIZE 1 #define icon_width 32 #define icon_height 32 static unsigned char icon_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x44, 0x02, 0x50, 0x5c, 0x04, 0x07, 0x20, 0xd4, 0x5d, 0x02, 0x50, 0x54, 0x54, 0x02, 0x88, 0x54, 0x54, 0x02, 0x04, 0x5d, 0x5c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x1e, 0x1e, 0x00, 0x80, 0x03, 0x70, 0x00, 0x80, 0x00, 0xc0, 0x03, 0xe0, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x0c, 0x10, 0x00, 0x00, 0x08, 0x10, 0x1c, 0x00, 0x08, 0x10, 0x1c, 0x10, 0x08, 0x10, 0x1c, 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, 0x30, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x00, 0x06, 0xc0, 0x00, 0x80, 0x03, 0x80, 0x03, 0xf0, 0x00, 0x00, 0x1e, 0x1e, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static char *progname; /* name this program was invoked by */ /* Global physical variables */ int min_x, min_y; /* Minimum graphics x- and y-coordinates */ int max_x, max_y; /* Maximum graphics x- and y-coordinates */ int x_sun, y_sun; /* Sun's Coordinates */ int x_earth, y_earth; /* Planet (Earth's) Coordinates */ int x_old, y_old; /* Planet old (Earth's) Coordinates */ int AU; /* One astronomical unit in pixels */ int sun_rad; /* One solar radius in pixels */ int earth_rad; /* One earth radius in pixels */ double ECCENTRIC=0.0; /* Orbit eccentricity < 1. */ double FCC; /* sqrt(1-ECCENTRIC*ECCENTRIC). */ /* Functions defined within this file. */ void openwindow(); void getGC(); void load_font(); void draw_frame(); char help(); void calc_coords(); void makebuttons(); Window makebutton(); void drawbuttons(); void drawbutton(); double theta_delay(); void draw_planet(); void main(argc, argv) int argc; char **argv; { char window_name[128], icon_name[80], ecc_name[80]; XEvent report; int buttonnum; double time=0.0; /* current time. */ long time_delay=2L; /* microsecs of delay between frames. */ long flash_time=200000L; /* microsecs of button flashes. */ double dtime=-0.20; /* time delay for Kepler's 2nd Law. */ double theta=0.0; /* the "parameter" for the orbit. */ double theta2; /* the "parameter" at delayed position. */ double del_time=0.002; /* increment of the time. */ char ModelName[80], onechar; int pause,redraw,nextstep,newsys,newscale,planets,buttime; progname = argv[0]; /* set the initial values of control flags. */ newsys=newscale=pause=1; redraw=nextstep=planets=buttime=0; sprintf(ModelName,"%s: ",progname); sprintf(window_name,"%s - Elliptical Planetary Orbits",progname); sprintf(icon_name,"%s",progname); openwindow(argc,argv,window_name,icon_name); calc_coords(NORESIZE); makebuttons(); XSynchronize(display,1); /* get events, use flags newscale, newsys, redraw,... to tell when system needs updating. */ while(1) { if(pause|XPending(display)) { XNextEvent(display, &report); onechar='0'; /* flag for no control event. */ switch (report.type) { case ConfigureNotify: /* window has been resized, change width and height */ /* printf("ConfigureNotify event\n"); */ win_width = report.xconfigure.width; win_height = report.xconfigure.height; XClearWindow(display,win); drawbuttons(pause); newscale=1; break; case Expose: /* unless this is the last contiguous expose, don't draw the window */ /* printf("Expose event: win= %ld, count = %d\n", report.xexpose.window,report.xexpose.count); */ if (report.xexpose.count!=0 || report.xexpose.window!=win) break; drawbuttons(pause); redraw=1; break; case ButtonPress: buttonnum=report.xbutton.button; if (report.xbutton.window==quitbutton) onechar='q'; else if (report.xbutton.window==pausebutton) onechar='p'; else if (report.xbutton.window==speedbutton) { if(buttonnum==Button3) onechar='.'; else if(buttonnum==Button1) onechar=','; } else if (report.xbutton.window==reversebutton) onechar='r'; else if (report.xbutton.window==areabutton) { if(buttonnum==Button3) onechar='a'; else if(buttonnum==Button1) onechar='s'; } else if (report.xbutton.window==helpbutton) { onechar=help(win,gcyel,large_font,pause,&newsys,&newscale); redraw=1; } else if (report.xbutton.window==eccbutton) { ECCENTRIC=(double)(report.xbutton.x)/(double)(BIGBUTTWIDTH); if(ECCENTRIC>0.999) ECCENTRIC=0.999; newsys=1; } break; case KeyPress: onechar=(char)XKeycodeToKeysym(display,report.xkey.keycode,0); /* printf("KeyPress Event: "); * * printf(" keycode = %d, ", report.xkey.keycode); * * printf(" KeySym = %c\n", onechar ); */ if(onechar=='h' ) /* get help. */ { onechar=help(win,gcyel,large_font,pause,&newsys,&newscale); redraw=1; } /* trickle down into default (no break) */ default: /* all events selected by StructureNotifyMask * except ConfigureNotify are thrown away here, * since nothing is done with them */ break; } /* end switch */ /* This block determines what flags to set based on the key or button commands that were given, and flashes the buttons. */ if(onechar!='0') { if(onechar=='q') { drawbutton(quitbutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"QUIT!",-1); usleep(flash_time); XUnloadFont(display, small_font->fid); XUnloadFont(display, large_font->fid); XFreeGC(display, gcpen); XFreeGC(display, gcyel); XFreeGC(display, gcclear); XFreeGC(display, gcbrt); XFreeGC(display, gcbw); XFreeGC(display, gcdeep); XCloseDisplay(display); exit(0); } else if(onechar==' ') /* single step mode. */ { pause=1; nextstep=1; drawbutton(pausebutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"STEP",1); usleep(flash_time); drawbutton(pausebutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,PAUSE[pause],1-2*pause); } else if(onechar=='p' || onechar=='\r') /* pause/resume action. */ { pause=1-pause; drawbutton(pausebutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,PAUSE[pause],1-2*pause); } else if(onechar=='e') /* increase eccentricity. */ { ECCENTRIC += ECCENTRIC<0.9985 ? 0.001 : 0.0 ; newsys=1; } else if(onechar=='c') /* decrease eccentricity. */ { ECCENTRIC -= ECCENTRIC>=0.001 ? 0.001 : 0.0 ; newsys=1; } else if(onechar=='s') /* smaller dtime. */ { dtime *= 0.95; drawbutton(areabutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"SMALLER",-1); if(pause) { usleep(flash_time); drawbutton(areabutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"area",1); } else buttime=10; } else if(onechar=='a') /* larger dtime. */ { dtime *= 1.05; drawbutton(areabutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"LARGER",-1); if(pause) { usleep(flash_time); drawbutton(areabutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"area",1); } else buttime=10; } else if(onechar=='r') /* reverse time. */ { del_time *= -1.0; dtime *= -1.0; drawbutton(reversebutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"REVERSE",-1); if(pause) { usleep(flash_time); drawbutton(reversebutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"reverse",1); } else buttime=10; } else if(onechar=='.') /* speedup frames. */ { del_time *= 1.08; drawbutton(speedbutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"FASTER",-1); if(pause) { usleep(flash_time); drawbutton(speedbutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"speed",1); } else buttime=10; } else if(onechar==',') /* slowdown frames. */ { del_time *= 0.92; drawbutton(speedbutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"SLOWER",-1); if(pause) { usleep(flash_time); drawbutton(speedbutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"speed",1); } else buttime=10; } } } /* End Event. */ /* Following if statements determine what to do based on the current flags. */ if(newsys) /* ECCENTRICITY got modified. */ { /* modify window size for new ECCENTRICITY. */ calc_coords(RESIZE); XResizeWindow(display,win,win_width,win_height); sprintf(ecc_name,"eccentricity = %5.3f",ECCENTRIC); drawbutton(eccbutton,0,0,BIGBUTTWIDTH,BUTTONHEIGHT,ecc_name,1); redraw=1; newsys=0; } if(newscale) /* window size got modified. */ { /* Fix scaling of all coordinates when window re-sized. */ calc_coords(NORESIZE); redraw=1; newscale=0; } if(redraw) { /* clear old picture and prepare to redraw planets, below. */ /* buttons are not redrawn when returning from help(). */ /* printf("redrawing window %ld\n",report.xexpose.window); */ XFillRectangle(display,win,gcclear,0,min_y-BORDER,win_width,(win_height+BORDER-min_y)); /* place box around system. */ draw_frame(win, gcpen); planets=1; redraw=0; } /* Update the planet's theta, time, and clear the old image. */ if(pause-1 || nextstep) { /* fixed del_time ==> varying del_theta. */ usleep(time_delay); theta=theta_delay(theta,del_time); time += del_time; draw_planet(gcclear, gcbrt, "P", earth_rad, x_earth, y_earth); planets=1; nextstep=0; } if(planets) { /* draw the Sun and planet. Note that xy system is left handed. Need appropriate minus sign to get a positive (counterclockwise) orbit. */ x_earth=(int)(x_sun-(double)AU*(cos(theta)-ECCENTRIC)); y_earth=(int)(y_sun+(double)AU*FCC*sin(theta)); draw_planet(gcyel, gcyel, "Sun", sun_rad, x_sun, y_sun); draw_planet(gcpen, gcbrt, "P", earth_rad, x_earth, y_earth); theta2=theta_delay(theta,dtime); x_old=x_sun-AU*(cos(theta2)-ECCENTRIC); y_old=y_sun+AU*FCC*sin(theta2); draw_planet(gcbw, gcdeep, "", 1, x_old, y_old); planets=0; } if(--buttime==0) drawbuttons(pause); } /* end while */ } /* end main */ /*************************************************************/ void calc_coords(resize) int resize; { /* Set global variables for drawing */ int xrange, yrange; ECCENTRIC=fabs(ECCENTRIC); FCC=sqrt(1.0-ECCENTRIC*ECCENTRIC); min_x = 3*BORDER; /* minimum x-coordinate */ max_x = win_width-3*BORDER; /* maximum x-coordinate */ xrange= max_x - min_x; min_y = 2*(BORDER+BUTTONHEIGHT)+3*BORDER; /* minimum y-coordinate */ if(resize) win_height = min_y+FCC*win_width+4*BORDER; max_y = win_height-3*BORDER; /* maximum y-coordinate */ yrange= max_y - min_y; /* choose size of orbit to fill screen. */ AU = 0.48 * ( yrange < FCC*xrange ? yrange/FCC : xrange ); x_sun = (min_x + max_x)/2 - ECCENTRIC * AU ; /* Set X coord for Sun */ y_sun = (min_y + max_y)/2; /* Set Y coord for Sun */ earth_rad = AU/40; /* earth's radius in pixels */ sun_rad = AU/23; /* Sun's radius in pixels */ /* printf("\nsun = %d, %d\n", x_sun,y_sun); */ return; } /*************************************************************/ double theta_delay(double theta1, double dt) { /* Given a small time delay dt, determines the corresponding delay in the "angle" parameter theta for the parametric representation of the orbit; time=theta-ECCENTRIC*sin(theta). */ double s1, dtheta, new, change, EPS=0.000001; dtheta=dt; s1=sin(theta1); do { new=dt+ECCENTRIC*(sin(theta1+dtheta)-s1); change=new-dtheta; dtheta=new; } while(fabs(change)>EPS); return (theta1+dtheta); } /*************************************************************/ void draw_planet(gcball, gcline, name, R, X, Y) GC gcball, gcline; char *name; int R; int X; int Y; { int size; size = (R<<1); XDrawLine(display,win,gcline,x_sun,y_sun,X,Y); if(size>=4) XFillArc(display,win,gcball,X-R,Y-R,size,size,0,23200); else XDrawPoint(display,win,gcball,X,Y); return; } /*************************************************************/ void makebuttons() /* creates the buttons; call after any resizing */ { int x=BORDER; XDestroySubwindows(display,win); eccbutton = makebutton(x,2*BORDER+BUTTONHEIGHT,BIGBUTTWIDTH,BUTTONHEIGHT); quitbutton = makebutton(x,BORDER,BUTTONWIDTH,BUTTONHEIGHT); x += BORDER+BUTTONWIDTH; pausebutton = makebutton(x,BORDER,BUTTONWIDTH,BUTTONHEIGHT); x += BORDER+BUTTONWIDTH; reversebutton = makebutton(x,BORDER,BUTTONWIDTH,BUTTONHEIGHT); x += BORDER+BUTTONWIDTH; speedbutton = makebutton(x,BORDER,BUTTONWIDTH,BUTTONHEIGHT); x += BORDER+BUTTONWIDTH; areabutton = makebutton(x,BORDER,BUTTONWIDTH,BUTTONHEIGHT); x += BORDER+BUTTONWIDTH; helpbutton = makebutton(x,BORDER,BUTTONWIDTH,BUTTONHEIGHT); return; } /*************************************************************/ Window makebutton(xoffset,yoffset,xsize,ysize) int xoffset,yoffset,xsize,ysize; /* Puts button of specified dimensions on window. Nothing is drawn. */ {Window buttonwindow; long event_mask; buttonwindow=XCreateSimpleWindow(display,win,xoffset,yoffset, xsize,ysize,0,lightcolor,deepcolor); event_mask=ButtonPressMask|ExposureMask; /* look for mouse-button presses */ XSelectInput(display,buttonwindow,event_mask); XMapWindow(display,buttonwindow); return buttonwindow; } /*************************************************************/ void drawbuttons(paused) int paused; /* draws or redraws the buttons; call after Exposures. */ { char name[80]; sprintf(name,"eccentricity = %5.3f",ECCENTRIC); /* XSetForeground(display,gcpen,lightcolor); */ /* XFillRectangle(display,win,gcpen,0,0,win_width,win_height>>3); */ drawbutton(eccbutton,0,0,BIGBUTTWIDTH,BUTTONHEIGHT,name,1); drawbutton(quitbutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"quit",1); drawbutton(pausebutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,PAUSE[paused],1-2*paused); drawbutton(reversebutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"reverse",1); drawbutton(speedbutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"speed",1); drawbutton(areabutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"area",1); drawbutton(helpbutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"help",1); return; } /*************************************************************/ void drawbutton(buttonwindow,xoffset,yoffset,xsize,ysize,text,state) Window buttonwindow; int xoffset,yoffset,xsize,ysize,state; char * text; /* Draw a button in buttonwindow of specified dimensions with text centered. Color of button determined by sign of "state." size of border determined by magnitude. */ {int textlength,ht,strwidth,i,j; int cdark,clight,cup,cdown; int cleft,cright,cbutton,ctext; cup=deepcolor; cdown=yellowcolor; cdark=darkcolor; clight=lightcolor; if (state<0) {cbutton=cdown; ctext=cdark; cleft=cdark; cright=clight; } else {cbutton=cup; ctext=clight; cleft=clight; cright=cdark; } if (1==depth) clight=cleft=cright=black; j=abs(state); XSetForeground(display,gcpen,cbutton); XFillRectangle(display,buttonwindow,gcpen,xoffset+j,yoffset+j, xsize-2*j,ysize-2*j); XSetForeground(display,gcpen,cleft); XFillRectangle(display,buttonwindow,gcpen,xoffset,yoffset,xsize,j); XFillRectangle(display,buttonwindow,gcpen,xoffset,yoffset,j,ysize); XSetForeground(display,gcpen,cright); for (i=0;iascent+large_font->descent; XSetForeground(display,gcpen,ctext); XDrawString(display,buttonwindow,gcpen, xoffset+(xsize-strwidth)/2, yoffset+(ysize+ht+1)/2, text,textlength); } XSetForeground(display,gcpen,lightcolor); return; } /*************************************************************/ void openwindow(argc,argv,window_name,icon_name) /* a lot of this is taken from the basicwin program in the Xlib Programming Manual */ int argc; char **argv; char *window_name; char *icon_name; { int x, y; unsigned int border_width = 4; unsigned int display_width, display_height; Pixmap icon_pixmap; char *display_name = NULL; XColor xcolor,colorcell; Colormap cmap; if (!(size_hints = XAllocSizeHints())) { fprintf(stderr, "%s: failure allocating memory\n", progname); exit(0); } if (!(wm_hints = XAllocWMHints())) { fprintf(stderr, "%s: failure allocating memory\n", progname); exit(0); } if (!(class_hints = XAllocClassHint())) { fprintf(stderr, "%s: failure allocating memory\n", progname); exit(0); } /* connect to X server */ if ( (display=XOpenDisplay(display_name)) == NULL ) { (void) fprintf( stderr, "%s: cannot connect to X server %s\n", progname, XDisplayName(display_name)); exit( -1 ); } /* get screen size from display structure macro */ screen_num = DefaultScreen(display); display_width = DisplayWidth(display, screen_num); display_height = DisplayHeight(display, screen_num); depth=DefaultDepth(display,screen_num); cmap=DefaultColormap(display,screen_num); /* depth=1; */ /* uncomment to test monochrome display */ darkcolor=black=BlackPixel(display,screen_num); lightcolor=white=WhitePixel(display,screen_num); if (depth>1) /* color? This is not the right way to do it, but .... */ { if (XAllocNamedColor(display,cmap,"DeepSkyBlue",&colorcell,&xcolor)) { lightcolor=colorcell.pixel; } if (XAllocNamedColor(display,cmap,"gray8",&colorcell,&xcolor)) { darkcolor=colorcell.pixel; } if (XAllocNamedColor(display,cmap,"red",&colorcell,&xcolor)) { brightcolor=colorcell.pixel; } if (XAllocNamedColor(display,cmap,"yellow",&colorcell,&xcolor)) { yellowcolor=colorcell.pixel; } if (XAllocNamedColor(display,cmap,"MidnightBlue",&colorcell,&xcolor)) { deepcolor=colorcell.pixel; } } /* Note that in a real application, x and y would default to 0 * but would be settable from the command line or resource database. */ x = y = 0; /* size window with enough room for text */ /* win_height = 7*display_height/8; */ /* win_width = 3*win_height/4; */ win_width = display_width/2; win_height = 2*(BORDER+BUTTONHEIGHT)+win_width+5*BORDER; /* create opaque window */ win = XCreateSimpleWindow(display, RootWindow(display,screen_num), x, y, win_width, win_height, border_width, lightcolor, darkcolor); /* Create pixmap of depth 1 (bitmap) for icon */ icon_pixmap = XCreateBitmapFromData(display, win, icon_bits, icon_width, icon_height); /* Set size hints for window manager. The window manager may * override these settings. Note that in a real * application if size or position were set by the user * the flags would be UPosition and USize, and these would * override the window manager's preferences for this window. */ /* x, y, width, and height hints are now taken from * the actual settings of the window when mapped. Note * that PPosition and PSize must be specified anyway. */ size_hints->flags = PPosition | PSize | PMinSize; size_hints->min_width = 6*(BORDER+BUTTONWIDTH)+BORDER; size_hints->min_height = 2*(BORDER+BUTTONHEIGHT)+7*BORDER +(int)(sqrt(0.002)*size_hints->min_width); /* These calls store window_name and icon_name into * XTextProperty structures and set their other * fields properly. */ if (XStringListToTextProperty(&window_name, 1, &windowName) == 0) { (void) fprintf( stderr, "%s: structure allocation for windowName failed.\n", progname); exit(-1); } if (XStringListToTextProperty(&icon_name, 1, &iconName) == 0) { (void) fprintf( stderr, "%s: structure allocation for iconName failed.\n", progname); exit(-1); } wm_hints->initial_state = NormalState; wm_hints->input = True; wm_hints->icon_pixmap = icon_pixmap; wm_hints->flags = StateHint | IconPixmapHint | InputHint; class_hints->res_name = progname; class_hints->res_class = "Basicwin"; XSetWMProperties(display,win,&windowName,&iconName, argv,argc,size_hints,wm_hints,class_hints); /* Select event types wanted */ event_mask=ExposureMask|KeyPressMask|ButtonPressMask|StructureNotifyMask; XSelectInput(display,win,event_mask); load_font("6x10",&small_font); load_font("8x16",&large_font); /* make graphics contexts: gcbw for white on black gcpen for various, defaults to darkcolor on lightcolor gcclear does the reverse. */ getGC(win, &gcbw, large_font, white, black); getGC(win, &gcpen, large_font, lightcolor, darkcolor); getGC(win, &gcdeep, large_font, deepcolor, darkcolor); getGC(win, &gcclear, small_font, darkcolor, lightcolor); getGC(win, &gcbrt, large_font, brightcolor, darkcolor); getGC(win, &gcyel, large_font, yellowcolor, darkcolor); /* Display window */ XMapWindow(display, win); return; } /*************************************************************/ void getGC(win, gc, font_info, fg_color, bg_color) Window win; GC *gc; XFontStruct *font_info; int fg_color, bg_color; { unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */ XGCValues values; unsigned int line_width = 1; int line_style = LineSolid; int cap_style = CapRound; int join_style = JoinRound; int dash_offset = 0; static char dash_list[] = {12, 24}; int list_length = 2; /* Create default Graphics Context */ *gc = XCreateGC(display, win, valuemask, &values); /* specify font */ XSetFont(display, *gc, font_info->fid); /* specify foreground fg_color */ XSetForeground(display, *gc, fg_color); /* specify background bg_color */ XSetBackground(display, *gc, bg_color); /* set line attributes */ XSetLineAttributes(display, *gc, line_width, line_style, cap_style, join_style); /* set dashes */ XSetDashes(display, *gc, dash_offset, dash_list, list_length); return; } /*************************************************************/ void load_font(fontname,font_info) char *fontname; XFontStruct **font_info; { /* Load font and get font information structure. */ if ((*font_info = XLoadQueryFont(display,fontname)) == NULL) { (void) fprintf( stderr, "%s: Cannot open %s font\n", progname, fontname); exit(-1); } } /*************************************************************/ char help(win, gc, font_info, pause, newsys, newscale) /* Writes help information, allows for resizing and taking any command and returning it to the calling program. */ Window win; GC gc; XFontStruct *font_info; int pause,*newsys,*newscale; #define NLINES 24 { char *string[NLINES] = { "Simulation of elliptical planetary orbits", " ", "Use mouse buttons (left=less, right=more)", "(location on eccentricity bar sets value)", " ", " or", " ", "Touch keys for the following actions:", " ", " q quit", " r reverse orbital direction", " e larger eccentricity", " c smaller eccentricity", " a larger Kepler 2nd Law area", " s smaller Kepler 2nd Law area", " , slow down motion", " . speed up motion", " p pause/resume action", " CR pause/resume action", " space single small steps", " ", "Hit any key or command to continue.", " ", "wysin@phys.ksu.edu [Gary Wysin]." }; int go,redraw,i,len; int x0,y0,y1,resized,width,ht; unsigned int old_width,old_height; XEvent report; int buttonnum; char onechar='h'; go=redraw=1; resized=0; old_width=win_width; old_height=win_height; /* need length for both XTextWidth and XDrawString */ len=strlen(string[0]); /* get string width for centering first line */ width=XTextWidth(font_info,string[0],len); ht=(font_info->ascent + font_info->descent); y1=2*(BORDER+BUTTONHEIGHT)+BORDER+ht; /* wait for any key or button event to continue. */ do { if(redraw) { x0=(win_width-width)>>1; y0=win_height-NLINES*ht; if(y0>y1) /* set positioning of the first line of text. */ { y0=(y0+y1)>>1; XFillRectangle(display,win,gcclear,0,min_y-BORDER,win_width,(win_height+BORDER-min_y)); } else /* auto-resize window if too small for text. */ { resized=1; win_height=y1+NLINES*ht+2*BORDER; y0=y1+BORDER; XResizeWindow(display,win,win_width,win_height); } drawbuttons(pause); draw_frame(win,gcpen); /* output texts */ for(i=0; i