XEphem/GUI/xephem/splash.c

381 lines
9.5 KiB
C

/* build a shell in a separate process to display info before main XEphem
* window appears. reads messages on stdin, dies when sees eof.
*/
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <Xm/Xm.h>
#include <Xm/RowColumn.h>
#include <Xm/Label.h>
#include <Xm/ToggleB.h>
#include <Xm/DrawingA.h>
#include <Xm/Text.h>
#include "xephem.h"
static int wantSplash (void);
static void forkSplash (int argc, char *argv[], XrmOptionDescRec options[],
int nops);
static void createSplash (int argc, char *argv[], XrmOptionDescRec options[],
int nops);
static void noteSplash (int on);
static void inputCB (XtPointer client, int *fdp, XtInputId *idp);
static void life_to (XtPointer client, XtIntervalId *id);
static void life_mark (Display *dsp, Window win, GC gc, int x);
static void life_exp_cb (Widget w, XtPointer client, XtPointer call);
static void onoff_cb (Widget w, XtPointer client, XtPointer call);
#define MWW 400 /* main window width */
#define LTO 100 /* life meter pause, ms */
#define LMH 7 /* life meter height */
#define LMT 3 /* life meter line thickness */
#define NMM 5 /* number of moving markers */
static Widget stf_w; /* message text field */
static FILE *splashpipe; /* write here to send message */
static Widget life_w; /* scrolling life meter */
static GC lgc; /* life meter gc */
static Pixel lfg, lbg; /* life meter fg and bg colors */
static Dimension llw, llh; /* life meter size */
static char nsfn[] = "nosplash";/* nosplash flag file name */
/* perhaps start splash, depending on args and nosplash file.
* scan argv for following, remove if found
* -nosplash: do not run splash and remove nsfn[]
* -splash: run splash and create nsfn[]
* [neither]: run splash depending on whether nsfs[] exists
*/
void
splashOpen (int *argc, char *argv[], XrmOptionDescRec options[], int nops)
{
int go = -1;
int i;
/* scan for -splash and -nosplash and remove if found */
for (i = 0; i < *argc; i++) {
if (strcmp (argv[i], "-nosplash") == 0) {
go = 0;
*argc -= 1;
memmove (&argv[i], &argv[i+1], (*argc+1) * sizeof(char *));
noteSplash (0);
break;
}
if (strcmp (argv[i], "-splash") == 0) {
go = 1;
*argc -= 1;
memmove (&argv[i], &argv[i+1], (*argc+1) * sizeof(char *));
noteSplash (1);
break;
}
}
/* CHAPG Alex Chupahin patched
it seems, OpenVMS 7.3-1 Motif version has a bug(?) or specific fiches (?), so splash screen is not work for a while.
I hope, this is not very importent, because the program is working nicely :), but I will work to fix it :)
*/
#ifdef VMS
go=0;
noteSplash (0);
#endif
/* if neither honor flag file */
if (go < 0)
go = wantSplash();
if (go) {
/* copy argv so our XtAppInit can eat it sep from xephem's */
int myargc = *argc;
char **myargv = (char **) malloc ((myargc+1)*sizeof(char *));
memcpy (myargv, argv, (myargc+1)*sizeof(char *));
forkSplash(myargc, myargv, options, nops);
free ((char *)myargv);
}
}
/* called by the real xephem to display a line of text on the splash window,
* of stderr if not enabled
*/
void
splashMsg (char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
vfprintf (splashpipe ? splashpipe : stderr, fmt, ap);
va_end (ap);
}
/* called by the real xephem to close the splash window */
void
splashClose (void)
{
if (!splashpipe)
return;
fclose (splashpipe);
splashpipe = NULL;
}
/* create the splash GUI.
* we already a separate process
*/
static void
createSplash (int argc, char *argv[], XrmOptionDescRec options[], int nops)
{
XrmDatabase dspdb;
Widget l_w, rc_w, nsrc_w, ns_w;
char t[1024];
Arg args[20];
int sw;
int n;
/* create splash shell */
newEnv(&argc, argv);
n = 0;
XtSetArg (args[n], XmNtitle, "xephem Splash"); n++;
XtSetArg (args[n], XmNy, 200); n++;
XtSetArg (args[n], XmNwidth, MWW); n++;
XtSetArg (args[n], XmNoverrideRedirect, True); n++;
XtSetArg (args[n], XmNborderWidth, 2); n++;
toplevel_w = XtAppInitialize (&xe_app, myclass, options, nops,
&argc, argv, fallbacks, args, n);
/* get XEphem resources */
dspdb = XtDatabase (XtDisplay(toplevel_w));
XrmCombineFileDatabase("/etc/XEphem", &dspdb, True);
XrmCombineFileDatabase(userResFile(), &dspdb, True);
/* set private colormap if desired */
xe_cm = checkCM (DefaultColormap(XtD,DefaultScreen(XtD)), 20);
set_something (toplevel_w, XmNcolormap, (XtArgVal)xe_cm);
/* center on screen */
sw = WidthOfScreen (XtScreen(toplevel_w));
set_something (toplevel_w, XmNx, (XtArgVal)((sw-MWW)/2));
/* main manager is a rowcolumn */
n = 0;
XtSetArg (args[n], XmNisAligned, False); n++;
XtSetArg (args[n], XmNmarginHeight, 10); n++;
XtSetArg (args[n], XmNmarginWidth, 10); n++;
XtSetArg (args[n], XmNspacing, 10); n++;
rc_w = XmCreateRowColumn (toplevel_w, "Splash", args, n);
XtManageChild (rc_w);
/* title */
n = 0;
XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
l_w = XmCreateLabel (rc_w, "title", args, n);
set_xmstring (l_w, XmNlabelString,
"XEphem ... from Clear Sky Institute Inc");
XtManageChild (l_w);
make_logo (rc_w);
/* subtitle */
n = 0;
XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
l_w = XmCreateLabel (rc_w, "subtitle", args, n);
sprintf (t,"Version %s -- released %s\n%s", PATCHLEVEL, PATCHDATE,
COPYRIGHT);
set_xmstring (l_w, XmNlabelString, t);
XtManageChild (l_w);
/* add drawing area for life meter, with timer */
n = 0;
XtSetArg (args[n], XmNheight, LMH); n++;
life_w = XmCreateDrawingArea (rc_w, "DA", args, n);
XtAddCallback (life_w, XmNexposeCallback, life_exp_cb, NULL);
XtManageChild (life_w);
/* add text widget for progress messages */
n = 0;
XtSetArg (args[n], XmNrows, 15); n++;
XtSetArg (args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
XtSetArg (args[n], XmNcursorPositionVisible, False); n++;
XtSetArg (args[n], XmNblinkRate, 0); n++;
stf_w = XmCreateText (rc_w, "messages", args, n);
XtManageChild (stf_w);
/* add a disable PB -- RC is to prevent it being full width */
n = 0;
XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;
nsrc_w = XmCreateRowColumn (rc_w, "NSRC", args, n);
XtManageChild (nsrc_w);
n = 0;
ns_w = XmCreateToggleButton (nsrc_w, "NS", args, n);
XtAddCallback (ns_w, XmNvalueChangedCallback, onoff_cb, NULL);
set_xmstring (ns_w, XmNlabelString,"Disable this splash next time");
XtManageChild (ns_w);
/* connect what real xephem writes to splashpipe to our stdin */
XtAppAddInput (xe_app, 0, (XtPointer)XtInputReadMask, inputCB, NULL);
/* go */
XtRealizeWidget(toplevel_w);
XtAppMainLoop(xe_app);
}
/* called whenever input arrives from the real xephem. exit on eof */
static void
inputCB (XtPointer client, int *fdp, XtInputId *idp)
{
char buf[1024];
int nr;
nr = read (*fdp, buf, sizeof(buf)-1);
if (nr <= 0)
exit(0);
buf[nr] = '\0';
XmTextInsert (stf_w, XmTextGetLastPosition(stf_w), buf);
}
/* called when life meter gets exp -- use to init and start heartbeat */
static void
life_exp_cb (Widget w, XtPointer client, XtPointer call)
{
Display *dsp = XtDisplay(w);
Window win = XtWindow(w);
Arg args[20];
int n;
n = 0;
XtSetArg (args[n], XmNforeground, &lfg); n++;
XtSetArg (args[n], XmNbackground, &lbg); n++;
XtGetValues (stf_w, args, n);
XtSetArg (args[n], XmNwidth, &llw); n++;
XtSetArg (args[n], XmNheight, &llh); n++;
XtGetValues (life_w, args, n);
if (!lgc) {
/* just once: build GC, init, start timer */
lgc = XCreateGC (dsp, win, 0L, NULL);
XSetLineAttributes (dsp, lgc, LMT, LineSolid, CapRound, JoinRound);
XSetForeground (dsp, lgc, lfg);
for (n = -LMT*2; n < llw; n += LMT*2)
life_mark (dsp, win, lgc, n);
XtAppAddTimeOut (xe_app, LTO, life_to, (XtPointer)1);
}
}
/* called regularly to show activity */
static void
life_to (XtPointer client, XtIntervalId *id)
{
static int lmx;
Display *dsp = XtDisplay(life_w);
Window win = XtWindow(life_w);
int gap = (LMT*2)*((llw/NMM)/(LMT*2));
int i;
/* move forward, wrap */
if ((lmx += LMT*2) > llw + LMT*2)
lmx = 0;
/* point markers every gap, each way of lmx, let X clip */
for (i = 0; i < NMM*2; i++) {
int dx = (i - NMM)*gap;
/* draw new */
XSetForeground (dsp, lgc, lbg);
life_mark (dsp, win, lgc, lmx + dx);
/* erase prev */
XSetForeground (dsp, lgc, lfg);
life_mark (dsp, win, lgc, lmx + dx - LMT*2);
}
XSync (dsp, True);
/* repeat */
XtAppAddTimeOut (xe_app, LTO, life_to, NULL);
}
/* draw one life marker pip */
static void
life_mark (Display *dsp, Window win, GC gc, int x)
{
XDrawLine (dsp, win, gc, x+llh-LMT/2, LMT/2, x+LMT/2, llh-LMT/2-1);
}
/* create the splash process, connect splashpipe to its stdin */
static void
forkSplash (int argc, char *argv[], XrmOptionDescRec options[], int nops)
{
int p[2];
if (pipe(p) < 0)
exit(0);
if (fork() == 0) {
dup2 (p[0], 0);
close (p[0]);
close (p[1]);
createSplash(argc, argv, options, nops);
abort();
}
close (p[0]);
splashpipe = fdopen (p[1], "w");
setbuf (splashpipe, NULL);
}
/* called to toggle splash screen now and forever */
static void
onoff_cb (Widget w, XtPointer client, XtPointer call)
{
noteSplash (!XmToggleButtonGetState(w));
}
/* record in flag file whether we want splash */
static void
noteSplash (int on)
{
char nos[1024];
FILE *fp;
sprintf (nos, "%s/%s", getPrivateDir(), nsfn);
if (on) {
remove (nos);
} else {
fp = fopen (nos, "w");
if (fp)
fclose (fp);
}
}
/* return 1 if flag file indicates we want splash else 0 */
static int
wantSplash (void)
{
char nos[1024];
FILE *fp;
sprintf (nos, "%s/%s", getPrivateDir(), nsfn);
fp = fopen (nos, "r");
if (fp)
fclose (fp);
return (!fp);
}