/* code to manage the sun display */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xephem.h" static void sun_create_shell (void); static void sun_help_cb (Widget w, XtPointer client, XtPointer data); static void sun_close_cb (Widget w, XtPointer client, XtPointer data); static void sun_popdown_cb (Widget w, XtPointer client, XtPointer call); static void sun_fpd_cb (Widget w, XtPointer client, XtPointer data); static void sun_load_cb (Widget w, XtPointer client, XtPointer data); static void sun_exp_cb (Widget w, XtPointer client, XtPointer data); static void sun_download_cb (Widget w, XtPointer client, XtPointer data); static void sun_save_cb (Widget w, XtPointer client, XtPointer data); static void sun_load1(void); static void sun_print_cb (Widget w, XtPointer client, XtPointer data); static void sun_mloop_cb (Widget w, XtPointer client, XtPointer data); static void sun_motion_eh (Widget w, XtPointer client, XEvent *ev, Boolean *continue_to_dispatch); static int readSOHOImage(void); static int displayPic (char fn[], unsigned char *pic, int picl); static void storePicFN (char fn[], int w); static int getTS (int *tp, int *sp); static int scanDir (char *dir, char ***files, int nfiles); static void sun_refresh(void); static int sun_ano (double *fracX, double *fracY, int *xp, int *yp, int w2x, int arg); static void sun_print(void); static void sun_ps_annotate(void); static void location (int x, int dx, int y, int dy, double scale, double *rap, double *decp); static int sun_gather (char ***files); static void sun_display (FILE *fp, char *name); static double carrington(Now *np); #define SUNPOLERA degrad(286.13000) /* RA of n pole */ #define SUNPOLEDEC degrad(63.87000) /* dec of n pole */ #define NSREAD 2048 /* size of socket read */ static Widget sunshell_w; /* main shell */ static Widget sunda_w; /* main drawing area */ static Widget ssw_w; /* scrolled window for sun */ static Widget lpd_w; /* Load pulldown */ static Widget bytype_w; /* whether to filter by Type */ static Widget bysize_w; /* whether to filter by Size */ static Widget ts_w; /* timestamp label */ static Widget save_w; /* save PB */ static Widget coords_w; /* coordinates label */ static Widget crn_w; /* Carrington rotation number label */ static Pixmap sun_pm; /* staging area */ static unsigned char *rawpic; /* current raw picture file, if any */ static long rawpicl; /* length of rawpic */ static char *picfn; /* malloced name of current picture */ /* info about each image format choice */ typedef struct { char *name; /* widget name of this choice */ char *label; /* widget label of this choice */ char *file; /* string in file name for this type */ int dx, dy; /* shift from image center to sun @ 1024 */ float scale; /* image scale, rads/pixel @ 1024 */ Widget w; /* controlling TB */ } SOHOType; /* N.B. order must agree with switch in sun_print() */ static SOHOType stype[] = { {"EIT171", "EIT 171", "eit_171", 0, 0, degrad(0.00075)}, {"EIT195", "EIT 195", "eit_195", 0, 0, degrad(0.00075)}, {"EIT284", "EIT 284", "eit_284", 0, 0, degrad(0.00075)}, {"EIT304", "EIT 304", "eit_304", 0, 0, degrad(0.00075)}, {"HMICon", "HMI Continuum", "hmi_igr", 0, 0, degrad(0.00055)}, {"HMIMag", "HMI Magnetogram", "hmi_mag", 0, 0, degrad(0.00055)}, {"LASC2", "LASCO C2", "c2", -16, 20, degrad(0.00365)}, {"LASC3", "LASCO C3", "c3", -16, 20, degrad(0.00775)}, }; /* info about size of image to get/display */ typedef struct { char *name; /* widget name of this choice */ char *label; /* widget label of this choice */ char *file; /* string in file name for this size */ int scale; /* wrt 256 */ Widget w; /* controlling TB */ } SOHOSize; static SOHOSize ssize[] = { {"512x512", "512x512", "512", 2}, {"1024x1024", "1024x1024", "1024", 1}, }; static char *sohohost; /* SOHO web site */ static char suncategory[] = "Sun"; /* bring up the sun menu, creating if first time */ void sun_manage() { if (!sunshell_w) { sun_create_shell(); sohohost = getXRes ("SOHOhost", NULL); } XtPopup (sunshell_w, XtGrabNone); set_something (sunshell_w, XmNiconic, (XtArgVal)False); /* rely on expose to do fresh update */ /* register we are now up */ setXRes (sun_viewupres(), "1"); } /* called to update our scene */ void sun_update (Now *np, int how_much) { if (!isUp(sunshell_w)) return; timestamp (np, ts_w); f_double (crn_w, "CRN: %.6f", carrington(np)); if (sun_pm) sun_refresh(); } /* called to put up or remove the watch cursor. */ void sun_cursor (Cursor c) { Window win; if (sunshell_w && (win = XtWindow(sunshell_w)) != 0) { Display *dsp = XtDisplay(sunshell_w); if (c) XDefineCursor (dsp, win, c); else XUndefineCursor (dsp, win); } } /* called when basic resources change */ void sun_newres() { if (!sunshell_w) return; sun_update (mm_get_now(), 1); } /* return the name of the resource containing whether this view is up */ char * sun_viewupres() { return ("SunViewUp"); } /* create main shell */ static void sun_create_shell () { Widget pd_w, cb_w, mb_w; Widget w, f_w; Arg args[20]; char buf[64]; int i; int n; /* create outter shell and form */ n = 0; XtSetArg (args[n], XmNcolormap, xe_cm); n++; XtSetArg (args[n], XmNtitle, "xephem Sun"); n++; XtSetArg (args[n], XmNiconName, "Sun"); n++; XtSetArg (args[n], XmNdeleteResponse, XmUNMAP); n++; sunshell_w = XtCreatePopupShell ("Sun", topLevelShellWidgetClass, toplevel_w, args, n); set_something (sunshell_w, XmNcolormap, (XtArgVal)xe_cm); XtAddCallback (sunshell_w, XmNpopdownCallback, sun_popdown_cb, 0); setup_icon (sunshell_w); sr_reg (sunshell_w, "XEphem*Sun.x", suncategory, 0); sr_reg (sunshell_w, "XEphem*Sun.y", suncategory, 0); sr_reg (sunshell_w, "XEphem*Sun.height", suncategory, 0); sr_reg (sunshell_w, "XEphem*Sun.width", suncategory, 0); sr_reg (NULL, sun_viewupres(), suncategory, 0); n = 0; XtSetArg (args[n], XmNverticalSpacing, 5); n++; XtSetArg (args[n], XmNhorizontalSpacing, 5); n++; f_w = XmCreateForm (sunshell_w, "SunF", args, n); XtAddCallback (f_w, XmNhelpCallback, sun_help_cb, 0); XtManageChild(f_w); /* menu bar */ n = 0; XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++; mb_w = XmCreateMenuBar (f_w, "SMB", args, n); XtManageChild (mb_w); /* Control */ n = 0; pd_w = XmCreatePulldownMenu (mb_w, "CPD", args, n); n = 0; XtSetArg (args[n], XmNmnemonic, 'D'); n++; w = XmCreatePushButton (pd_w, "Download", args, n); set_xmstring (w, XmNlabelString, "Download latest"); wtip (w, "Download latest SOHO image of given Type and Size"); XtAddCallback (w, XmNactivateCallback, sun_download_cb, 0); XtManageChild (w); /* save not sensitive until image has been downloaded */ n = 0; XtSetArg (args[n], XmNmnemonic, 'S'); n++; XtSetArg (args[n], XmNsensitive, False); n++; save_w = XmCreatePushButton (pd_w, "Save", args, n); set_xmstring (save_w, XmNlabelString, "Save downloaded image"); wtip (save_w, "Save newly downloaded image to local disk"); XtAddCallback (save_w, XmNactivateCallback, sun_save_cb, 0); XtManageChild (save_w); n = 0; w = XmCreateSeparator (pd_w, "S1", args, n); XtManageChild (w); n = 0; XtSetArg (args[n], XmNmnemonic, 'T'); n++; XtSetArg (args[n], XmNindicatorOn, True); n++; XtSetArg (args[n], XmNvisibleWhenOff, True); n++; bytype_w = XmCreateToggleButton (pd_w, "ByType", args, n); set_xmstring (bytype_w, XmNlabelString, "Filter Files by Type"); wtip (bytype_w, "Whether Files restricts choices to Type"); sr_reg (bytype_w, NULL, suncategory, 0); XtManageChild (bytype_w); n = 0; XtSetArg (args[n], XmNmnemonic, 'F'); n++; XtSetArg (args[n], XmNindicatorOn, True); n++; XtSetArg (args[n], XmNvisibleWhenOff, True); n++; bysize_w = XmCreateToggleButton (pd_w, "BySize", args, n); set_xmstring (bysize_w, XmNlabelString, "Filter Files by Size"); wtip (bysize_w, "Whether Files restricts choices to Size"); sr_reg (bysize_w, NULL, suncategory, 0); XtManageChild (bysize_w); n = 0; w = XmCreateSeparator (pd_w, "S1", args, n); XtManageChild (w); n = 0; XtSetArg (args[n], XmNmnemonic, 'P'); n++; w = XmCreatePushButton (pd_w, "Print", args, n); XtAddCallback (w, XmNactivateCallback, sun_print_cb, NULL); wtip (w, "Print the current SOHO image"); set_xmstring (w, XmNlabelString, "Print..."); XtManageChild (w); n = 0; XtSetArg (args[n], XmNmnemonic, 'U'); n++; w = XmCreatePushButton (pd_w, "Ann", args, n); XtAddCallback (w, XmNactivateCallback, ano_cb, NULL); set_xmstring (w, XmNlabelString, "User annotation..."); wtip (w, "Draw text and lines on curret SOHO image"); XtManageChild (w); n = 0; n += ml_addacc (args, n); XtSetArg (args[n], XmNmnemonic, 'm'); n++; w = XmCreatePushButton (pd_w, "Movie", args, n); XtAddCallback (w, XmNactivateCallback, sun_mloop_cb, NULL); set_xmstring (w, XmNlabelString, "Add to movie..."); wtip (w, "Add current image to movie loop"); XtManageChild (w); n = 0; w = XmCreateSeparator (pd_w, "S1", args, n); XtManageChild (w); n = 0; XtSetArg (args[n], XmNmnemonic, 'C'); n++; w = XmCreatePushButton (pd_w, "Close", args, n); wtip (w, "Close this SOHO window"); XtAddCallback (w, XmNactivateCallback, sun_close_cb, NULL); XtManageChild (w); n = 0; XtSetArg (args[n], XmNmnemonic, 'C'); n++; XtSetArg (args[n], XmNsubMenuId, pd_w); n++; cb_w = XmCreateCascadeButton (mb_w, "Control", args, n); XtManageChild (cb_w); /* Load */ n = 0; lpd_w = XmCreatePulldownMenu (mb_w, "FPD", args, n); XtAddCallback (lpd_w, XmNmapCallback, sun_fpd_cb, NULL); n = 0; XtSetArg (args[n], XmNmnemonic, 'L'); n++; XtSetArg (args[n], XmNsubMenuId, lpd_w); n++; cb_w = XmCreateCascadeButton (mb_w, "Files", args, n); wtip (cb_w, "Select a local SOHO file to display"); XtManageChild (cb_w); /* Type */ n = 0; XtSetArg (args[n], XmNradioBehavior, True); n++; XtSetArg (args[n], XmNradioAlwaysOne, True); n++; pd_w = XmCreatePulldownMenu (mb_w, "TPD", args, n); for (i = 0; i < XtNumber(stype); i++) { SOHOType *tp = &stype[i]; n = 0; XtSetArg (args[n], XmNindicatorOn, True); n++; XtSetArg (args[n], XmNvisibleWhenOff, True); n++; tp->w = XmCreateToggleButton (pd_w, tp->name, args, n); set_xmstring (tp->w, XmNlabelString, tp->label); sprintf (buf, "XEphem*Sun*%s.set", tp->name); sr_reg (tp->w, buf, suncategory, 0); XtManageChild (tp->w); } n = 0; XtSetArg (args[n], XmNmnemonic, 'T'); n++; XtSetArg (args[n], XmNsubMenuId, pd_w); n++; cb_w = XmCreateCascadeButton (mb_w, "Type", args, n); wtip (cb_w, "Specify SOHO image type to download"); XtManageChild (cb_w); /* Size */ n = 0; XtSetArg (args[n], XmNradioBehavior, True); n++; XtSetArg (args[n], XmNradioAlwaysOne, True); n++; pd_w = XmCreatePulldownMenu (mb_w, "TPD", args, n); for (i = 0; i < XtNumber(ssize); i++) { SOHOSize *sp = &ssize[i]; n = 0; XtSetArg (args[n], XmNindicatorOn, True); n++; XtSetArg (args[n], XmNvisibleWhenOff, True); n++; sp->w = XmCreateToggleButton (pd_w, sp->name, args, n); set_xmstring (sp->w, XmNlabelString, sp->label); sprintf (buf, "XEphem*Sun*%s.set", sp->name); sr_reg (sp->w, buf, suncategory, 0); XtManageChild (sp->w); } n = 0; XtSetArg (args[n], XmNmnemonic, 'S'); n++; XtSetArg (args[n], XmNsubMenuId, pd_w); n++; cb_w = XmCreateCascadeButton (mb_w, "Size", args, n); wtip (cb_w, "Specify SOHO image size to download"); XtManageChild (cb_w); /* help */ n = 0; pd_w = XmCreatePulldownMenu (mb_w, "TPD", args, n); n = 0; XtSetArg (args[n], XmNmnemonic, 'H'); n++; w = XmCreatePushButton (pd_w, "Help", args, n); XtAddCallback (w, XmNactivateCallback, sun_help_cb, 0); XtManageChild (w); n = 0; XtSetArg (args[n], XmNmnemonic, 'H'); n++; XtSetArg (args[n], XmNsubMenuId, pd_w); n++; cb_w = XmCreateCascadeButton (mb_w, "Help", args, n); set_something (mb_w, XmNmenuHelpWidget, (XtArgVal)cb_w); XtManageChild (cb_w); /* time stamp and CRN at bottom */ n = 0; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNrightPosition, 50); n++; XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++; ts_w = XmCreateLabel (f_w, "TS", args, n); XtManageChild (ts_w); n = 0; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNleftPosition, 50); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++; crn_w = XmCreateLabel (f_w, "CRN", args, n); XtManageChild (crn_w); /* cursor coords above */ n = 0; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNbottomWidget, ts_w); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++; coords_w = XmCreateLabel (f_w, "Coordinates", args, n); XtManageChild (coords_w); /* remainder is scrolled window for image */ n = 0; XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNtopWidget, mb_w); n++; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNbottomWidget, coords_w); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNscrollingPolicy, XmAUTOMATIC); n++; XtSetArg (args[n], XmNshadowThickness, 1); n++; ssw_w = XmCreateScrolledWindow (f_w, "SunSW", args, n); XtManageChild (ssw_w); /* workarea is a drawing area */ n = 0; XtSetArg (args[n], XmNwidth, 1024); n++; /* not critical */ XtSetArg (args[n], XmNheight, 1024); n++; /* not critical */ XtSetArg (args[n], XmNmarginHeight, 0); n++; sunda_w = XmCreateDrawingArea (ssw_w, "SunMap", args, n); XtAddEventHandler (sunda_w,PointerMotionMask,False,sun_motion_eh,0); XtAddCallback (sunda_w, XmNexposeCallback, sun_exp_cb, NULL); XtManageChild (sunda_w); /* SW assumes work is its child but just to be tidy about it .. */ set_something (ssw_w, XmNworkWindow, (XtArgVal)sunda_w); } /* called when the main scrolled area needs refreshing */ /* ARGSUSED */ static void sun_exp_cb (Widget w, XtPointer client, XtPointer call) { XmDrawingAreaCallbackStruct *c = (XmDrawingAreaCallbackStruct *)call; XExposeEvent *e = &c->event->xexpose; Now *np = mm_get_now(); watch_cursor (1); switch (c->reason) { case XmCR_EXPOSE: { /* turn off gravity so we get expose events for either shrink or * expand. * also center the scroll bars initially. */ static int before; if (!before) { XSetWindowAttributes swa; unsigned long mask = CWBitGravity | CWBackingStore; swa.bit_gravity = ForgetGravity; swa.backing_store = NotUseful; XChangeWindowAttributes (e->display, e->window, mask, &swa); before = 1; } break; } default: printf ("Unexpected mda_w event. type=%d\n", c->reason); abort(); } if (!sun_pm) sun_load1(); /* load initial if possible */ if (sun_pm) sun_refresh(); timestamp (np, ts_w); f_double (crn_w, "CRN: %.6f", carrington(np)); watch_cursor (0); } /* ARGSUSED */ static void sun_help_cb (Widget w, XtPointer client, XtPointer data) { static char *msg[] = { "This tool opens and displays solar images" }; hlp_dialog ("Sun", msg, XtNumber(msg)); } static void sun_popdown_cb (Widget w, XtPointer client, XtPointer data) { /* register we are now down */ setXRes (sun_viewupres(), "0"); } /* ARGSUSED */ static void sun_close_cb (Widget w, XtPointer client, XtPointer data) { /* let popdown do the real work */ XtPopdown (sunshell_w); } static int fn_cmp (const void *s1, const void *s2) { return (strcmp (*(char **)s1, *(char **)s2)); } /* ARGSUSED */ static void sun_print_cb (Widget w, XtPointer client, XtPointer data) { XPSAsk ("Sun View", sun_print); } /* ARGSUSED */ static void sun_mloop_cb (Widget w, XtPointer client, XtPointer data) { ml_add (sun_pm, ts_w); } /* proceed to generate a postscript file. * call XPSClose() when finished. */ static void sun_print () { Display *dsp = XtDisplay(sunda_w); Window win = XtWindow(sunda_w); Window root; Pixmap drawpm; int rx, ry; unsigned int bw, dep; unsigned int wid, hei; int s, t; /* must be up and showing */ if (!isUp(sunshell_w) || !sun_pm) { xe_msg (1, "Sun image be open to print."); XPSClose(); return; } watch_cursor(1); /* get size */ getTS (&t, &s); s = 1024/ssize[s].scale; /* fit view in square across the top and prepare to capture X calls */ XPSXBegin (sun_pm, 0, 0, s, s, 1*72, 10*72, (int)(6.5*72)); /* since our normal expose refresh draws annotation directly into the * sunda_w window (which in turn is because we don't want to burn it * into the sun_pm which we create only once when the image is read) * we have to build another temp pixmap here just to add annotation * Also, it would look nice to block out the black background of * the MDI images but they use the same color in the dark sunspots. */ XGetGeometry (dsp, win, &root, &rx, &ry, &wid, &hei, &bw, &dep); drawpm = XCreatePixmap (dsp, win, wid, hei, dep); XCopyArea (XtD, sun_pm, drawpm, DefaultGC(XtD, DefaultScreen(XtD)), 0, 0, wid, hei, 0, 0); ano_draw (sunda_w, drawpm, sun_ano, 0); XPSPixmap (drawpm, s, s, xe_cm, 0, 0); XFreePixmap (dsp, drawpm); /* no more X captures */ XPSXEnd(); /* add some extra info */ sun_ps_annotate (); /* finished */ XPSClose(); watch_cursor(0); } static void sun_ps_annotate() { Now *np = mm_get_now(); char dir[128]; char buf[128]; int ctr = 306; /* = 8.5*72/2 */ int lx = ctr-5; int y; /* caption */ y = AROWY(13); (void) strcpy (buf, "XEphem Solar View"); (void) sprintf (dir, "(%s) %d %d cstr", buf, ctr, y); XPSDirect (dir); y = AROWY(9); fs_date (buf, pref_get(PREF_DATE_FORMAT), mjd_day(mjd)); (void) sprintf (dir, "(UTC Date:) %d %d rstr (%s) %d %d lstr\n", lx, y, buf, lx+10, y); XPSDirect (dir); y = AROWY(8); fs_time (buf, mjd_hr(mjd)); (void) sprintf (dir, "(UTC Time:) %d %d rstr (%s) %d %d lstr\n", lx, y, buf, lx+10, y); XPSDirect (dir); y = AROWY(7); sprintf (buf, "%.6f", carrington(np)); (void) sprintf (dir,"(Carrington number:) %d %d rstr (%s) %d %d lstr\n", lx, y, buf, lx+10, y); XPSDirect (dir); } /* load one file initially for fun */ static void sun_load1() { char **files; int nfiles; nfiles = sun_gather (&files); if (nfiles > 0) { FILE *fp = fopend (files[0], "auxil", "r"); sun_display (fp, files[0]); fclose (fp); XtFree ((char *) files); } } /* gather and sort all qualified file names. * N.B. caller must free *files */ static int sun_gather (char ***files) { char sdir[1024]; int nfiles = 0; *files = NULL; sprintf (sdir, "%s/auxil", getShareDir()); nfiles += scanDir (sdir, files, nfiles); nfiles += scanDir (getPrivateDir(), files, nfiles); qsort (*files, nfiles, sizeof(char *), fn_cmp); return (nfiles); } /* display the given picture file stream */ static void sun_display (FILE *fp, char *name) { unsigned char *pic; int picl; fseek (fp, 0L, SEEK_END); picl = (int) ftell(fp); pic = (unsigned char *) XtMalloc (picl); fseek (fp, 0L, SEEK_SET); fread (pic, picl, 1, fp); if (displayPic (name, pic, picl) < 0) XtFree ((char *)pic); /* already told user why */ } /* called when the Files pulldown is about to come up */ /* ARGSUSED */ static void sun_fpd_cb (Widget w, XtPointer client, XtPointer data) { WidgetList children; Cardinal numChildren; char **files; int i, nfiles; /* gather and sort all file names */ nfiles = sun_gather (&files); /* load into pulldown menu */ get_something (lpd_w, XmNchildren, (XtArgVal)&children); get_something (lpd_w, XmNnumChildren, (XtArgVal)&numChildren); for (i = 0; i < nfiles; i++) { Widget w; if (i < numChildren) { w = children[i]; } else { w = XmCreatePushButton (lpd_w, "LPDPB", NULL, 0); XtAddCallback (w, XmNactivateCallback, sun_load_cb, NULL); } set_xmstring (w, XmNlabelString, files[i]); XtManageChild (w); } /* turn off unused buttons */ for (; i < numChildren; i++) XtUnmanageChild (children[i]); /* set to multi-column if lots of files */ if (nfiles >= 5) set_something (w,XmNnumColumns,(XtArgVal)((int)(sqrt(nfiles/5.0)))); else set_something (w, XmNnumColumns, (XtArgVal)1); /* finished with list */ XtFree ((char *) files); } /* called to load a local file when a Load PB is clicked. * local file name is our labelString */ /* ARGSUSED */ static void sun_load_cb (Widget w, XtPointer client, XtPointer data) { char *name; FILE *fp; int i; get_xmstring (w, XmNlabelString, &name); fp = fopend (name, "auxil", "r"); if (fp) { /* display */ sun_display (fp, name); fclose (fp); /* set type and size in menus to match based on fn */ for (i = 0; i < XtNumber(stype); i++) { if (strstr (name, stype[i].file)) { XmToggleButtonSetState (stype[i].w, True, True); break; } } for (i = 0; i < XtNumber(ssize); i++) { if (strstr (name, ssize[i].file)) { XmToggleButtonSetState (ssize[i].w, True, True); break; } } /* can not save a file loaded from disk */ XtSetSensitive (save_w, False); } XtFree (name); } /* called to download the latest image of the current type and size */ /* ARGSUSED */ static void sun_download_cb (Widget w, XtPointer client, XtPointer data) { watch_cursor (1); /* read image */ if (readSOHOImage() < 0) { stopd_down(); watch_cursor (0); return; } /* ok to save */ XtSetSensitive (save_w, True); stopd_down(); watch_cursor (0); } /* called to save giffn[], if any, in private dir */ /* ARGSUSED */ static void sun_save_cb (Widget w, XtPointer client, XtPointer data) { char fn[1024]; FILE *fp; /* never allowed again until new download */ XtSetSensitive (save_w, False); /* sanity check */ if (!picfn || !rawpic) { xe_msg (1, "No image to save"); return; } /* create file */ sprintf (fn, "%s/%s", getPrivateDir(), picfn); fp = fopenh (fn, "w"); if (!fp) { xe_msg (1, "%s:\n%s", fn, syserrstr()); return; } /* write */ if (fwrite (rawpic, rawpicl, 1, fp) != 1) { xe_msg (1, "%s:\n%s", picfn, syserrstr()); fclose (fp); return; } /* ok */ if (confirm()) xe_msg (1, "%s:\nWritten successfully", picfn); fclose (fp); } /* called to display coords from cursor roaming */ static void sun_motion_eh (Widget w, XtPointer client, XEvent *ev, Boolean *dispatch) { Display *dsp = XtDisplay(w); Window win = XtWindow(w); SOHOType *tp; SOHOSize *sp; int t, s; Window root, child; int rx, ry, wx, wy; unsigned mask; unsigned int bw, dep; unsigned int wid, hei; double r, d; char cbuf[64], rbuf[32], dbuf[32]; if (!picfn || !rawpic) return; XGetGeometry (dsp, win, &root, &rx, &ry, &wid, &hei, &bw, &dep); XQueryPointer (dsp, win, &root, &child, &rx, &ry, &wx, &wy, &mask); getTS (&t, &s); tp = &stype[t]; sp = &ssize[s]; location (wx-wid/2, tp->dx/sp->scale, wy-hei/2, tp->dy/sp->scale, tp->scale*sp->scale, &r, &d); fs_sexa (rbuf, radhr(r), 3, 600); fs_sexa (dbuf, raddeg(d), 3, 60); sprintf (cbuf, "RA, Dec: %s %s", rbuf, dbuf); set_xmstring (coords_w, XmNlabelString, cbuf); } /* read picture from sohohost and display. * store picture in rawpic[] and its filename in *picfn. * return 0 if ok else xe_msg and -1 */ static int readSOHOImage() { char fn[1024]; int t, s; char get[1024]; char buf[1024]; char filetime[100]; char filetype[100]; int isjpeg, jpegl; int njpeg; unsigned char *jpeg; XE_SSL_FD ssl_fd; int fd, nr; struct tm tm; memset(&ssl_fd, 0, sizeof(ssl_fd)); memset(&tm, 0, sizeof(struct tm)); /* get desired type and size */ if (getTS (&t, &s) < 0) return (-1); /* build latest fn */ sprintf (filetype, "%s", stype[t].file); sprintf (fn, "/data/realtime/%s/%s/latest.jpg", filetype, ssize[s].file); /* build GET command */ sprintf (get, "GET http://%s%s HTTP/1.0\r\nUser-Agent: xephem/%s\r\n\r\n", sohohost, fn, PATCHLEVEL); /* query server */ fd = httpsGET (sohohost, get, buf, &ssl_fd); if (fd < 0) { xe_msg (1, "https get: %s", buf); return (-1); } /* read header (everything to first blank line), looking for jpeg */ isjpeg = 0; jpegl = 0; while (ssl_recvline (&ssl_fd, buf, sizeof(buf)) > 1) { xe_msg (0, "Rcv: %s", buf); if (strstr (buf, "Content-Type:") && strstr (buf, "image/jpeg")) isjpeg = 1; if (strstr (buf, "Content-Length:")) jpegl = atoi (buf+15); if (strstr (buf, "Last-Modified:")) { strptime(buf+20, "%d %b %Y %H:%M:%S %Z", &tm); strftime(filetime, sizeof(filetime), "%Y%m%d_%H%M%S", &tm); xe_msg (0, "Rcv: Filetime: %s", filetime); } } if (!isjpeg) { while (ssl_recvline (&ssl_fd, buf, sizeof(buf)) > 0) xe_msg (0, "Rcv: %s", buf); xe_msg (1, "Error talking to SOHO .. see File->System log\n"); SSL_free (ssl_fd.ssl); close (ssl_fd.fd); return (-1); } if (jpegl == 0) { xe_msg (1, "No Content-Length in header"); SSL_free (ssl_fd.ssl); close (ssl_fd.fd); return (-1); } /* remainder should be a jpeg file, read into jpeg[] */ pm_up(); jpeg = NULL; for (njpeg = 0; njpeg < jpegl; njpeg += nr) { pm_set (100*njpeg/jpegl); jpeg = (unsigned char *) XtRealloc ((char*)jpeg, njpeg+NSREAD); nr = SSL_read (ssl_fd.ssl, jpeg+njpeg, NSREAD); if (nr <= 0) { xe_msg (1, "%s: ssl read error code: %d", sohohost, SSL_get_error(ssl_fd.ssl, nr)); pm_down(); SSL_free (ssl_fd.ssl); close (ssl_fd.fd); return (-1); } if (nr == 0) break; } pm_down(); SSL_free (ssl_fd.ssl); close (ssl_fd.fd); sprintf (fn, "/%s_%s.jpg", filetime, filetype); /* display jpeg */ if (displayPic (fn, jpeg, njpeg) < 0) return (-1); /* clean up */ return (0); } /* display the picture file named fn and install as the "current" file. * return 0 if ok, else -1 and why xe_msg() * N.B. picture must be malloced memory and user should /not/ free, let us manage it */ static int displayPic (char fn[], unsigned char *pic, int picl) { static XColor xcol[256]; static int xcolset; Pixmap pm; char buf[1024]; int w, h; int ok = 0; /* explode into pm */ if (strstr (fn, ".gif")) { ok = 1; if (gif2pm (XtD, xe_cm, pic, picl, &w, &h, &pm, buf) < 0) { xe_msg (1, "Display GIF: %s:\n%s", fn, buf); return (-1); } } if (strstr (fn, ".jpg")) { char tmpfn[2048]; FILE *tmpfp; ok = 1; /* free last batch of colors */ if (xcolset) { freeXColors (XtD, xe_cm, xcol, XtNumber(xcol)); xcolset = 0; } /* convert JPEG to pixmap */ (void) tempfilename (tmpfn, "suntmp", ".jpg"); tmpfp = fopen (tmpfn, "wb+"); if (!tmpfp) { xe_msg (1, "Can not create tmp file: %s", tmpfn); return (-1); } fwrite(pic, picl, 1, tmpfp); rewind(tmpfp); if (jpeg2pm (XtD, xe_cm, tmpfp, &w, &h, &pm, xcol, buf) < 0) { xe_msg (1, "Display JPEG: %s:\n%s", fn, buf); fclose (tmpfp); unlink (tmpfn); return (-1); } xcolset = 1; fclose (tmpfp); unlink (tmpfn); } if (ok == 0) { xe_msg (1, "Unknown file type: %s", fn); return (-1); } /* replace pixmap and center */ if (sun_pm) XFreePixmap (XtD, sun_pm); sun_pm = pm; set_something (sunda_w, XmNwidth, (XtArgVal)(Dimension)w); set_something (sunda_w, XmNheight, (XtArgVal)(Dimension)h); centerScrollBars(ssw_w); sun_refresh(); if (rawpic) XtFree ((char *)rawpic); rawpic = pic; rawpicl = picl; storePicFN (fn, w); return (0); } /* store base of fn[] in picfn[], include width w in name somewhere */ static void storePicFN (char fn[], int w) { char buf[1024]; char *sp, *lsp; /* find last slash in fn */ lsp = NULL; for (sp = fn; sp; sp = strchr (sp+1, '/')) lsp = sp; if (!lsp) { printf ("Bug! no / in filename '%s'\n", fn); abort(); } sprintf (buf, "SOHO_%d_%s", w, lsp+1); if (picfn) XtFree (picfn); picfn = XtNewString (buf); } /* get indices into user's current type and size settings. * either can be NULL if not interested. */ static int getTS (int *tp, int *sp) { int i; if (tp) { for (i = 0; i < XtNumber(stype); i++) { if (XmToggleButtonGetState (stype[i].w)) { *tp = i; break; } } if (i == XtNumber(stype)) { xe_msg (1, "No SOHO type"); return (-1); } } if (sp) { for (i = 0; i < XtNumber(ssize); i++) { if (XmToggleButtonGetState (ssize[i].w)) { *sp = i; break; } } if (i == XtNumber(ssize)) { xe_msg (1, "No SOHO size"); return (-1); } } return (0); } static int scanDir (char *dir, char ***files, int nfiles) { int bytype = XmToggleButtonGetState (bytype_w); int bysize = XmToggleButtonGetState (bysize_w); int t, s; DIR *dirp; struct dirent *dp; int n; /* get type and size settings if currently interested */ if ((bytype || bysize) && getTS (&t, &s) < 0) return (0); /* open and scan the directory for matching names */ dirp = opendir (dir); if (!dirp) return (0); for (n = 0; (dp = readdir (dirp)) != NULL; ) { if (strncmp (dp->d_name, "SOHO", 4) == 0 && (!bytype || strstr (dp->d_name, stype[t].file)) && (!bysize || strstr (dp->d_name, ssize[s].file))) { *files = (char **) XtRealloc ((char *)(*files), (nfiles + n + 1) * sizeof(char *)); (*files)[nfiles + n++] = XtNewString (dp->d_name); } } /* finished */ closedir (dirp); return (n); } static void sun_refresh() { Dimension w, h; get_something (sunda_w, XmNwidth, (XtArgVal)&w); get_something (sunda_w, XmNheight, (XtArgVal)&h); XCopyArea (XtD, sun_pm, XtWindow(sunda_w), DefaultGC(XtD, DefaultScreen(XtD)), 0, 0, w, h, 0, 0); /* draw annotation directly onto window so we don't dirty up the * pixmap (which we only load with the image once) */ ano_draw (sunda_w, XtWindow(sunda_w), sun_ano, 0); } /* convert image proportions to/from X windows coords depending on w2x. * return whether visible. */ static int sun_ano (double *fracX, double *fracY, int *xp, int *yp, int w2x, int arg) { Display *dsp = XtDisplay (sunda_w); unsigned int nx, ny, bw, d; Window root; int x, y; XGetGeometry(dsp, sun_pm, &root, &x, &y, &nx, &ny, &bw, &d); if (w2x) { *xp = (int)floor(*fracX*nx + 0.5); *yp = (int)floor(*fracY*ny + 0.5); } else { *fracX = (double)*xp/nx; *fracY = (double)*yp/ny; } return (*xp>=0 && *xp=0 && *yps_dec); double cd = cos (sop->s_dec); double xp, yp, p, cp, sp; /* SOHO image is always rotated with N solar axis vertical. * find rotation, p, to bring equatoral N up. */ solve_sphere (sop->s_ra-SUNPOLERA, PI/2-SUNPOLEDEC, sd, cd, NULL, &p); /* rotate screen coords so eq N is up */ cp = cos(p); sp = sin(p); y -= dy; x -= dx; xp = x*cp - y*sp; yp = x*sp + y*cp; *decp = sop->s_dec - yp*scale; *rap = sop->s_ra - xp*scale/cos(*decp); range (rap, 2*PI); } /* display carrington coord for current time */ static double carrington(Now *np) { return ((1./27.2753)*((mjd+MJD0)-2398167.0) + 1.0); }