/* gkrellsun.c * Copyright (C) 2004 Kurt V. Hindenburg * Copyright (C) 2001, 2002, 2003 Norman Walsh. Derived from gkrellmoon by * Dale P. Smith and wmSun by Mike Henderson * * $Id: gkrellsun.c,v 1.63 2004/09/08 16:44:42 kvh009 Exp $ * */ #if !defined(WIN32) #include #else #include #include time_t* CurrentTime; #endif #include /* splint */ extern gchar* g_string_free (/*@only@*/ GString *, gboolean); extern void pango_font_description_free (/*@owned@*/PangoFontDescription *); #define PLUGIN_HEIGHT 54 #define SUN_WIDTH 54 #define SUN_HEIGHT 54 #define SUN_INNER_WIDTH 52 #define SUN_INNER_HEIGHT 52 #define SUN_INNER_XOFS 1 #define SUN_INNER_YOFS 1 #include "../images/uvsun.xpm" #include "../images/osun.xpm" #define UVSUN_XPM uvsun_xpm #define UVSUN_COUNT 2 #define OSUN_XPM osun_xpm #define OSUN_COUNT 6 #define DIGIT_COUNT 15 #include "../images/star.xpm" #define STAR_XPM star_xpm #define STAR_XOFS 3 #define STAR_YOFS 3 #define STAR_COUNT 2 #include "../images/dot.xpm" #define DOT_XPM dot_xpm #define DOT_COUNT 2 #include "../images/moon_60.xpm" #define MOON_FULL_XPM moon_60_xpm #define MOON_FULL_WIDTH 48 #define MOON_FULL_HEIGHT 48 #define MOON_FULL_COUNT 60 #include "../images/moon.xpm" #define MOON_SM_XPM moon_xpm #define MOON_SM_WIDTH 8 #define MOON_SM_HEIGHT 8 #define MOON_SM_COUNT 61 #define MOON_SM_INVISIBLE 60 #define STYLE_NAME "sun" #define PLUGIN_CONFIG_KEYWORD "sun" #define SUNCLOCK_MAJOR_VERSION 0 #define SUNCLOCK_MINOR_VERSION 12 #define SUNCLOCK_PATCH_VERSION 2 #define NUMBER_OF_SUNS 2 #define NUMBER_OF_TIMES 3 #define UV_SUN 0 #define ORANGE_SUN 1 #define TIME_RISE 0 #define TIME_SET 1 #define TIME_ETA 2 #define DIGIT_SPACE 3 #define DIGIT_AM 4 #define DIGIT_PM 5 #define FONT_CURRENT 0 #define FONT_NEW 1 #define CLOCK12 0 #define CLOCK24 1 static gchar *sunNames[NUMBER_OF_SUNS] = { "UVSUN", "ORANGESUN" }; static gchar *moonPhases[9] = { "New", "Waxing Crescent", "First Quarter", "Waxing Gibbous", "Full", "Waning Gibbous", "Last Quarter", "Waning Crescent", "New" }; /* Allow each sun and each time (rise, set, eta) to have their own color; one font for them all */ typedef struct { GdkColor timeColors[NUMBER_OF_SUNS][NUMBER_OF_TIMES]; GkrellmTextstyle *timeStyles[NUMBER_OF_SUNS][NUMBER_OF_TIMES]; PangoFontDescription /*@owned@*//*@null@*/*fontDesc; gchar fontNames[2][128]; /* Current and new*/ gint timeXOffsets[2]; /* 12hour / 24hour formats */ gint timeYOffsets[3]; /* RISE/SET/ETA */ } TextOptions; typedef struct { int longitude; int displayed_longitude; int latitude; int displayed_latitude; int clock24; int showStar; int showPath; int show90Path; int showETA; int showMiniMoon; int whichSun; int sunmoon_toggle_minutes; int debug; } Options; static GkrellmMonitor *sun_monitor; static GkrellmPanel *panel; static Options options; static TextOptions textOptions; static gint style_id; static gint redraw = 1; gboolean colorsCreated = FALSE; static int baseX = 0; static int baseY = 0; static gint panel_view = 0; /* 0 = sun; 1 = moon */ static GtkWidget *longitude_spin_button = NULL; static GtkWidget *latitude_spin_button = NULL; static GtkWidget *clock24_button = NULL; static GtkWidget *showStar_button = NULL; static GtkWidget *showPath_button = NULL; static GtkWidget *show90Path_button = NULL; static GtkWidget *showMiniMoon_button = NULL; static GtkWidget *showETA_button = NULL; static GtkWidget *debug_button = NULL; static GtkWidget *long_E_radio_button = NULL; static GtkWidget *long_W_radio_button = NULL; static GtkWidget *lat_N_radio_button = NULL; static GtkWidget *lat_S_radio_button = NULL; static GtkWidget *sunmoon_spin_button = NULL; static GdkColormap *colormap = NULL; static GtkWidget *sun_radio_button[NUMBER_OF_SUNS]; static GdkColor timeColors_drawingarea[NUMBER_OF_SUNS][NUMBER_OF_TIMES]; static GtkWidget *times_drawingarea[NUMBER_OF_SUNS][NUMBER_OF_TIMES]; static gchar time_str[NUMBER_OF_TIMES][7]; /* 00:00p */ static GkrellmDecal *time_decal[NUMBER_OF_SUNS][NUMBER_OF_TIMES] = { { NULL, NULL, NULL } , { NULL, NULL, NULL } }; static GdkPixmap *uvsun_image = NULL; static GdkBitmap *uvsun_mask = NULL; static GkrellmDecal *uvsun = NULL; static GdkPixmap *osun_image = NULL; static GdkBitmap *osun_mask = NULL; static GkrellmDecal *osun = NULL; static GdkPixmap *star_image = NULL; static GdkBitmap *star_mask = NULL; static GkrellmDecal *star = NULL; static GdkPixmap *dot_image = NULL; static GdkBitmap *dot_mask = NULL; static GdkPixmap *moon_full_image = NULL; static GdkBitmap *moon_full_mask = NULL; static GkrellmDecal *moon_full = NULL; static GdkPixmap *moon_sm_image = NULL; static GdkBitmap *moon_sm_mask = NULL; static GkrellmDecal *moon_sm = NULL; #define PATH_COUNT 14 #define HALF_PATH_COUNT 7 #define PATH_SPACING 4 static GkrellmDecal *path[PATH_COUNT]; static GkrellmDecal *path90[PATH_COUNT]; static GtkTooltips *tooltip; static GkrellmTicks *pGK; #include "CalcEphem.h" typedef struct CTrans SunData; typedef struct _Sun Sun; struct _Sun { SunData data; }; extern long CurrentGMTTime; /*long CurrentGMTTime = 0;*/ static Sun sununit; static gchar *sun_data_dir; static void load_sun_data(void); static void save_sun_data(void); static void update_tooltip(Sun *sun); static void update_sun_data(Sun * sun) { struct tm *time_struc; /* The tm struct is defined in */ gdouble local_std_time, univ_time, eot; glong date; gint day_of_month, month, year; CurrentGMTTime = (long) time(NULL); time_struc = gmtime((time_t)&CurrentGMTTime); /* It may return NULL when the year does not fit into an integer.*/ if (time_struc == NULL) { g_message(_("Error: gmtime returned NULL\n")); exit(EXIT_FAILURE); } univ_time = time_struc->tm_hour + time_struc->tm_min / 60.0 + time_struc->tm_sec / 3600.0; /* The date needs to be the date in UTC, i.e. in greenwich, so * be sure not to call the localtime function until after date * has been set (there's only one tm structure). */ year = time_struc->tm_year + 1900; month = time_struc->tm_mon + 1; day_of_month = time_struc->tm_mday; date = year * 10000 + month * 100 + day_of_month; if (options.debug == TRUE) { g_message(_("gkrellsun debug: GMT date = %04d-%02d-%02d (%ld)\n"), year, month, day_of_month, date); } time_struc = localtime((time_t)&CurrentGMTTime); if (time_struc == NULL) { g_message(_("Error: localtime returned NULL\n")); exit(EXIT_FAILURE); } local_std_time = time_struc->tm_hour + time_struc->tm_min / 60.0 + time_struc->tm_sec / 3600.0; if (options.debug == TRUE) { g_message(_("gkrellsun: local date = %04d-%02d-%02d\n"), time_struc->tm_year + 1900, time_struc->tm_mon + 1, time_struc->tm_mday); } sun->data.Glat = (gdouble)options.latitude; sun->data.Glon = (gdouble)options.longitude; if (options.debug == TRUE) { g_message(_("gkrellsun: latitude = %d\n"), options.latitude); g_message(_("gkrellsun: longitude = %d\n"), options.longitude); } sunclock_CalcEphem(date, univ_time, &sun->data, options.debug); /* CalcEphem(date, univ_time, &sun->data);*/ sun->data.LST = local_std_time; sun->data.LMT = univ_time - sun->data.Glon / 15.0; /* splint - Two real (float, double, or long double) values are compared directly using a C primitive. This may produce unexpected results since floating point representations are inexact. Instead, compare the difference to FLT_EPSILON */ if (sun->data.LMT < DBL_EPSILON) /* < 0.0 */ sun->data.LMT += 24.0; if ((sun->data.LMT - 24.0) > DBL_EPSILON) /* > 24.0 */ sun->data.LMT -= 24.0; if (options.debug == TRUE) { g_message(_("gkrellsun: sun LST (Local Standard Time) = %6.2f\n"), sun->data.LST); g_message(_("gkrellsun: sun LMT (Local Mean Time) = %6.2f\n"), sun->data.LMT); g_message(_("gkrellsun: sun Rise = %d\n"), sun->data.Rise); g_message(_("gkrellsun: sun Set = %d\n"), sun->data.Set); g_message(_("gkrellsun: sun LTRise = %6.2f\n"), sun->data.LTRise); g_message(_("gkrellsun: sun LTSet = %6.2f\n"), sun->data.LTSet); g_message(_("gkrellsun: A_moon = %6.2f\n"), sun->data.A_moon); g_message(_("gkrellsun: h_moon = %6.2f\n"), sun->data.h_moon); g_message(_("gkrellsun: moon age = %6.2f\n"), sun->data.MoonAge); g_message(_("gkrellsun: SinGlat = %6.2f\n"), sun->data.SinGlat); g_message(_("gkrellsun: CosGlat = %6.2f\n"), sun->data.CosGlat); } /* eot is the equation of time. gmst is Greenwich Sidereal * Time. This equation below is correct, but confusing at * first. It's easy to see when you draw the following * picture: A sphere with 0 and 180 degree longitude, North on * top, a meridian for the real sun, a meridian for a fictive * average sun, a meridian denoting the vernal equinox. Note * that universal time is the hour angle between 180 degrees * and the fictive sun's meridian measured clockwise. gmst is * the hour angle between 0 degrees and the meridian of the * vernal equinox measured clockwise. RA_sun/15.0 is the hour * angle of the real sun measured counterclockwise from the * vernal equinox. eot is the difference between the real and * the fictive sun. Looking at the picture, it's easy to see * that 12=RA_sun/15-gmst+eot+utc (12 hours = 180 deg.) */ eot = 12.0 - univ_time + sun->data.gmst - sun->data.RA_sun / 15.0; if (eot < DBL_EPSILON) eot += 24.0; if ((eot - 24.0) > DBL_EPSILON) /* (eot > 24.0) */ eot -= 24.0; sun->data.LAT = sun->data.LMT + eot; if ((sun->data.LAT - 0.0) < DBL_EPSILON) /* < 0.0) */ sun->data.LAT += 24.0; if ((sun->data.LAT - 24.0) > DBL_EPSILON) /* > 24.0)*/ sun->data.LAT -= 24.0; update_tooltip(sun); } /* Adjust the hour to reflect 12 or 24 hour clock */ static int clock_adjust_hour( const int H ) { int hour; hour = H; /* For a 24-hour clock, range is 0..23 */ if( options.clock24 == TRUE ) { hour %= 24; } /* For a 12-hour clock, range is 1..12 */ else { hour = ( ( hour - 1 ) % 12 ) + 1; } return hour; } /* End of clock_adjust_hour() */ /* Adjust AM/PM indicator to reflect 12 or 24 hour clock */ static int clock_ampm( const int H ) { int ampm_digit; /* Default is 24-hour (no AM/PM indicator) */ ampm_digit = DIGIT_SPACE; /* For a 12-hour clock, set the AM/PM indicator */ if( options.clock24 == FALSE ) { if( H < 12 ) { ampm_digit = DIGIT_AM; } else { ampm_digit = DIGIT_PM; } } return ampm_digit; } /* End of clock_ampm() */ /* Determine the letter to be used for a given AM/PM digit value */ static char ampm_letter( const int ampm_digit ) { char letter; switch( ampm_digit ) { case DIGIT_AM: letter = 'a'; break; case DIGIT_PM: letter = 'p'; break; case DIGIT_SPACE: letter = ' '; break; default: letter = '?'; break; } return letter; } /* End of ampm_letter() */ /* Determine the length of the day taking into account the case where the sun sets "before" it rises very far north. */ static double dayLength(Sun *sun) { /* woe unto you if you call this on a day when the sun doesn't rise and set */ double len = (sun->data.LTSet - sun->data.LTRise); if (sun->data.LTSet < sun->data.LTRise) { /* wrap around, we must be *way* north */ len += 24.0; } return len; } /* End of dayLength() */ static void printTOD(char *l, double tod) { double val = tod; int H, M; H = (int)val; val = (val-H)*60.0; M = (int)val; if (H >= 12) { if (H > 12) { H -= 12; } g_message("%s %d:%02dp\n", l, H, M); } else { g_message("%s %d:%02da\n", l, H, M); } } static double percentOfDay(Sun *sun, double tod) { if (sun->data.Rise && sun->data.Set) { return (tod - sun->data.LTRise) / dayLength(sun); } else { return 0; } } static double percentOfAltitude(Sun *sun, double tod) { double dayperc = percentOfDay(sun, tod); if ((dayperc - 0.5) > DBL_EPSILON) /* > 0.5) */ { return 1.0 - dayperc; } else { return dayperc; } } static double altitudeAtNoon(Sun *sun) { double altnoon = 90.0 - sun->data.Glat + sun->data.DEC_sun; if ((altnoon - 90.0) > DBL_EPSILON) /* > 90) */ { altnoon = 90.0 - (altnoon - 90.0); } return altnoon; } static void drawSun(Sun *sun) { int image_number; double perc = percentOfAltitude(sun, sun->data.LST) * 2; int x = (gkrellm_chart_width() - SUN_WIDTH) / 2; int y = (PLUGIN_HEIGHT - SUN_INNER_HEIGHT) / 2 + 1; double s_set = sun->data.LTRise + dayLength(sun); if (options.whichSun == ORANGE_SUN) { gkrellm_make_decal_invisible(panel, uvsun); gkrellm_make_decal_visible(panel, osun); gkrellm_draw_decal_pixmap(panel, uvsun, 0); if (sun->data.Rise && sun->data.Set) { /* If the sun rises and sets today... */ if (((sun->data.LST - sun->data.LTRise) < DBL_EPSILON) || ((sun->data.LST - s_set) > DBL_EPSILON)) { image_number = 1; } else { image_number = 2; if ((perc - 0.25) > DBL_EPSILON) image_number = 3; if ((perc - 0.50) > DBL_EPSILON) image_number = 4; if ((perc - 0.75) > DBL_EPSILON) image_number = 5; } } else if (!sun->data.Rise && sun->data.Set) { /* If the sun doesn't rise but it does set... */ if ((sun->data.LST - sun->data.LTRise) > DBL_EPSILON) { image_number = 1; } else { image_number = 4; } } else if (sun->data.Rise && !sun->data.Set) { /* If the sun rises but it doesn't set... */ if ((sun->data.LST - sun->data.LTRise) < DBL_EPSILON) { image_number = 1; } else { image_number = 4; } } else { /* The sun neither rises nor sets */ image_number = 1; } gkrellm_draw_decal_pixmap(panel, osun, image_number); gkrellm_move_decal(panel, osun, x, y); } else { gkrellm_make_decal_visible(panel, uvsun); gkrellm_make_decal_invisible(panel, osun); gkrellm_draw_decal_pixmap(panel, osun, 0); gkrellm_draw_decal_pixmap(panel, uvsun, 1); gkrellm_move_decal(panel, uvsun, x, y); } gkrellm_draw_panel_layers(panel); } static int moon_image_number(double MoonPhase) { /* MoonPhase expresses phase of moon as fraction of 1; 0.5=full. */ gdouble image_float; gint image_int; gint image_number; image_float = MoonPhase * (gdouble) MOON_FULL_COUNT; image_int = (gint) image_float; if ((image_float - image_int) >= 0.5) image_number = (image_int + 1) % MOON_FULL_COUNT; else image_number = image_int % MOON_FULL_COUNT; return image_number; } static void drawFullMoon(Sun *sun) { /* double alt = sun->data.h_moon; */ int x = (gkrellm_chart_width() - MOON_FULL_WIDTH) / 2; int y = (PLUGIN_HEIGHT - MOON_FULL_HEIGHT) / 2; gint image_number = moon_image_number(sun->data.MoonPhase); gkrellm_draw_decal_pixmap(panel, moon_full, image_number); gkrellm_make_decal_visible(panel, moon_full); gkrellm_move_decal(panel, moon_full, x, y); gkrellm_draw_panel_layers(panel); } static void drawMoon(Sun *sun, int visible) { gint image_number = moon_image_number(sun->data.MoonPhase); double alt = sun->data.h_moon; int x = baseX + SUN_WIDTH - MOON_SM_WIDTH - SUN_INNER_XOFS; int y = 0; gkrellm_draw_decal_pixmap(panel, moon_sm, MOON_SM_INVISIBLE); if (alt < 0) { return; } y = (int) (alt / 90.0 * SUN_HEIGHT / 2.0); y = baseY + y; y = SUN_INNER_HEIGHT - y - SUN_INNER_YOFS; if (options.debug) { printf("Moon at %d, %d (%6.2f): %d\n", x, y, alt, image_number); } if (visible) { gkrellm_move_decal(panel, moon_sm, x, y); gkrellm_draw_decal_pixmap(panel, moon_sm, image_number); } } /* for a circle that crosses (0,0), (26, y2), (52, 0) compute the center (x0,y0) */ static double centerX(/*@unused@*/double y2) { return 26; } static double centerY(double y2) { double x1 = 0; double y1 = 0; double x2 = 26; return ( ((y2*y2) - (x1*x1) + (2*x1*x2) - (x2*x2)) / (2 * (y2 - y1)) ); } static int computeY(int x, double maxAlt) { double x0, y0, x2, y2, radius; double tx, ty; /* Compute y2, the point at apogee */ x2 = 26; y2 = 26 * maxAlt / 90.0; /* Compute x0,y0 the center of the circle */ x0 = centerX(y2); /*y2?*/ y0 = centerY(y2); radius = y2 - y0; /* calculate y from the circle... */ tx = (double)(x - 26); ty = sqrt((radius*radius) - (tx*tx)); return (int) (ty + y0); } static void computePath(Sun *sun, GkrellmDecal **path, double maxAlt) { double unitLength = dayLength(sun) / (PATH_COUNT-1); double tod; int count, x, y; /* Divide the length of the solar day into PATH_COUNT segments */ if (!sun->data.Rise || !sun->data.Set) { return; } if (options.debug) { printTOD("Rise: ", sun->data.LTRise); printTOD("Set: ", sun->data.LTSet); g_message(_("At Noon: %6.2f\n"), altitudeAtNoon(sun)); g_message(_("Max: %6.2f\n"), maxAlt); } for (count = 0; count < PATH_COUNT; count++) { tod = sun->data.LTRise + (count * unitLength); x = (int) (SUN_INNER_WIDTH * percentOfDay(sun, tod)); y = computeY(x, maxAlt); if (options.debug) { g_message ("[%d] ", count); g_message ("%6.2f, %6.2f (%d, %d) ", percentOfDay(sun, tod), percentOfAltitude(sun, tod), x, y); printTOD("", tod); } x = baseX + x + SUN_INNER_XOFS; y = baseY + y; y = SUN_INNER_HEIGHT - y - SUN_INNER_YOFS; gkrellm_move_decal(panel, path[count], x, y); } } static void drawPath(GkrellmDecal **path, int imgNo) { int count; for (count = 0; count < PATH_COUNT; count++) { gkrellm_draw_decal_pixmap(panel, path[count], imgNo); } } /* tod = Time of Day, showTime whether to display time, whichTime TIME_RISE/TIME_SET/TIME_ETA, eta don't display a/p */ static void drawTextTime(double tod, int showTime, int whichTime, int eta) { double val = tod; int H, M, ampm_digit; gchar *t; t = g_strndup(" ", 6); H = (int)val; val = (val-H)*60.0; M = (int)val; ampm_digit = clock_ampm( H ); H = clock_adjust_hour( H ); if (eta) { ampm_digit = DIGIT_SPACE; } if (showTime) { t[0]=(int)(H / 10) + '0'; t[1]=(int)(H % 10) + '0'; t[2]=':'; t[3]=(int)(M / 10) + '0'; t[4]=(int)(M % 10) + '0'; if (ampm_digit == DIGIT_AM) { t[5]='a'; } else if (ampm_digit == DIGIT_PM) { t[5]='p'; } else { t[5]=' '; } } g_strlcpy(time_str[whichTime], t, 7); /* 7 = buffer size (6 + NULL) */ g_free(t); }; static void sun_update_plugin() { int image_x_offset, image_y_offset; int pos_x, pos_y; int starImage = 0; double eta = 0; double s_set; int inDaylight = 0; int timeXOffsets, sun, time; struct tm *t; /* If the theme has changed, redraw will be 1 */ /* Currently, the plugin is updated on the 5 minute tick. */ if (!(redraw || pGK->minute_tick)) return; t = gkrellm_get_current_time(); if (options.sunmoon_toggle_minutes > 0) if (!redraw && (t->tm_min % options.sunmoon_toggle_minutes) == 0) { panel_view = 1 - panel_view; /* Toggle between SUN/MOON */ redraw = 1; /* Force redraw */ } if (!(redraw || ((t->tm_min % 5) ==0) )) return; /* printf("Update/Redrawing plugin: redraw=%d, minute_tick=%d, 5_minute_tick=%d\n", redraw, pGK->minute_tick, (t->tm_min % 5) == 0); */ redraw = 0; update_sun_data(&sununit); s_set = sununit.data.LTRise + dayLength(&sununit); inDaylight = (sununit.data.LST >= sununit.data.LTRise && sununit.data.LST <= s_set && sununit.data.Rise && sununit.data.Set); if (panel_view == 0) { /* Sun is visiable */ gkrellm_make_decal_invisible(panel, moon_full); sun = options.whichSun; for (time = 0; time < NUMBER_OF_TIMES; time++) gkrellm_make_decal_visible(panel, time_decal[sun][time]); gkrellm_make_decal_visible(panel, star); drawSun(&sununit); drawMoon(&sununit,options.showMiniMoon); } else { /* Moon is visiable */ gkrellm_make_decal_visible(panel, moon_full); gkrellm_make_decal_invisible(panel, uvsun); gkrellm_make_decal_invisible(panel, osun); gkrellm_make_decal_invisible(panel, star); drawPath(path, 0); drawPath(path90, 0); sun = options.whichSun; for (time = 0; time < NUMBER_OF_TIMES; time++) gkrellm_make_decal_invisible(panel, time_decal[sun][time]); drawFullMoon(&sununit); drawMoon(&sununit,0); gkrellm_draw_panel_layers(panel); return; } drawPath(path, options.showPath && inDaylight); drawPath(path90, options.show90Path && inDaylight); /* Clear out text - Only really needed for ETA, since RISE/SET will always be displayed. */ /* drawTextTime(sununit.data.LTRise, 0, TIME_RISE, 0); drawTextTime(sununit.data.LTRise, 0, TIME_SET, 0);*/ drawTextTime(0, 0, TIME_ETA, 0); if (options.showETA == TRUE) /* Allow all suns to show ETA */ { if ((sununit.data.LST - sununit.data.LTRise) < DBL_EPSILON) { eta = sununit.data.LTRise - sununit.data.LST; drawTextTime(eta, 1, TIME_ETA, 1); } if (((sununit.data.LST - sununit.data.LTRise) >= DBL_EPSILON) && ((sununit.data.LST - s_set) < DBL_EPSILON)) { eta = s_set - sununit.data.LST; drawTextTime(eta, 1, TIME_ETA, 1); } } if (sununit.data.Rise) { drawTextTime(sununit.data.LTRise, 1, TIME_RISE, 0); } else { drawTextTime(sununit.data.LTRise, 0, TIME_RISE, 0); } if (sununit.data.Set) { drawTextTime(sununit.data.LTSet, 1, TIME_SET, 0); } else { drawTextTime(sununit.data.LTSet, 0, TIME_SET, 0); } starImage = 0; /* by default off */ /* Draw the star if the sun rises and sets today. */ if (options.showStar && inDaylight) { if (options.debug) printTOD("Current Time: ", sununit.data.LST); /* Calculate plot pos */ pos_x = (int) (SUN_INNER_WIDTH * percentOfDay(&sununit, sununit.data.LST)); pos_y = computeY(pos_x, altitudeAtNoon(&sununit)); image_x_offset = pos_x + baseX + SUN_INNER_XOFS - STAR_XOFS; image_y_offset = SUN_INNER_HEIGHT - (pos_y + baseY) - SUN_INNER_YOFS - STAR_YOFS; if (options.debug) g_message (_("Star at: (%d,%d) %d\n"), image_x_offset, image_y_offset, pos_y); gkrellm_move_decal(panel, star, image_x_offset, image_y_offset); starImage = 1; } timeXOffsets = textOptions.timeXOffsets[CLOCK12]; if (options.clock24) timeXOffsets = textOptions.timeXOffsets[CLOCK24]; sun = options.whichSun; for (time = 0; time < NUMBER_OF_TIMES; time++) { gkrellm_decal_text_clear(time_decal[sun][time]); gkrellm_decal_text_insert(time_decal[sun][time], time_str[time], textOptions.timeStyles[sun][time], 0, 0); if (time == TIME_ETA) gkrellm_move_decal(panel, time_decal[sun][time], textOptions.timeXOffsets[CLOCK24], textOptions.timeYOffsets[time]); else gkrellm_move_decal(panel, time_decal[sun][time], timeXOffsets, textOptions.timeYOffsets[time]); } gkrellm_draw_decal_pixmap(panel, star, starImage); gkrellm_draw_panel_layers(panel); } static void update_tooltip(Sun *sun) { GString *mboxes; gchar time_format[128]; gchar format_string[128]; double val, altnoon; int H,M; int ampm_digit; char EW, NS; int dlat, dlon; gint moonphase; if (tooltip == NULL) return; mboxes = g_string_sized_new(512); dlat = options.latitude; NS = 'N'; if (dlat < 0) { NS = 'S'; dlat = -dlat; } dlon = options.longitude; EW = 'W'; if (dlon < 0) { EW = 'E'; dlon = -dlon; } (void)g_string_append_printf(mboxes, _("Location: %d%c %d%c\n"), dlat, NS, dlon, EW); if (panel_view == 0) { /* Sun */ /* Determine clock format */ if( options.clock24 ) { g_strlcpy( time_format, "%02d:%02d", sizeof( time_format ) ); } else { g_strlcpy( time_format, "%d:%02d%c", sizeof( time_format ) ); } /* Sun rise ... */ if (sun->data.Rise) { val = sun->data.LTRise; H = (int)val; M = (int)((val-H)*60.0); ampm_digit = clock_ampm( H ); H = clock_adjust_hour( H ); (void)g_snprintf( format_string, sizeof( format_string ), _("Sunrise: %s\n"), time_format ); (void)g_string_append_printf(mboxes, format_string, H, M, ampm_letter(ampm_digit) ); } else { (void)g_string_append_printf(mboxes, _("Sunrise: never\n")); } /* Sun set ... */ if (sun->data.Set) { val = sun->data.LTSet; H = (int)val; M = (int)((val-H)*60.0); ampm_digit = clock_ampm( H ); H = clock_adjust_hour( H ); (void)g_snprintf( format_string, sizeof( format_string ), _("Sunset: %s\n"), time_format ); (void)g_string_append_printf(mboxes, format_string, H, M, ampm_letter(ampm_digit) ); } else { (void)g_string_append_printf(mboxes, _("Sunset: never\n")); } /* Solar noon ... */ if (sun->data.Rise && sun->data.Set) { val = sun->data.LTRise + (dayLength(sun)/2.0); H = (int)val; M = (int)((val-H)*60.0); ampm_digit = clock_ampm( H ); H = clock_adjust_hour( H ); (void)g_snprintf( format_string, sizeof(format_string), _("Solar noon: %s\n"), time_format ); (void)g_string_append_printf(mboxes, format_string, H, M, ampm_letter(ampm_digit) ); /* Solar altitude at noon */ altnoon = 90.0 - sun->data.Glat + sun->data.DEC_sun; if ((altnoon - 90.0) > DBL_EPSILON) /* > */ { altnoon = 90.0 - (altnoon - 90.0); } (void)g_string_append_printf(mboxes, _("Altitude at noon: %4.1f\n"), altnoon); /* Altitude now */ val = (sun->data.LST - sun->data.LTRise) / dayLength(sun); if ((val - 0.5) > DBL_EPSILON) /* > */ { val = 1.0 - val; } (void)g_string_append_printf(mboxes, _("Altitude now: %4.1f\n"), altnoon * val * 2); (void)g_string_append_printf(mboxes, _("\nClick to see Moon")); } } else { /* Moon */ (void)g_string_append_printf(mboxes, _("\nMoon Altitude: %4.1f"), sun->data.h_moon); (void)g_string_append_printf(mboxes, _("\nMoon Phase: %4.1f\n"), sun->data.MoonPhase); /* MoonPhase: 0 -> 1; there are 8 phase names */ moonphase = (gint) ((sun->data.MoonPhase * 8.0) + 0.4); (void)g_string_append_printf(mboxes, _("Moon Phase: %s\n"), moonPhases[moonphase]); (void)g_string_append_printf(mboxes, _("\nClick to see Sun")); } /* Removing the last \n removes an empty line at the bottom of the tooltip */ gtk_tooltips_set_tip(tooltip, panel->drawing_area, mboxes->str, NULL); gtk_tooltips_set_delay(tooltip, 750); gtk_tooltips_enable(tooltip); (void)g_string_free(mboxes, TRUE); } static gint panel_expose_event(GtkWidget *widget, GdkEventExpose *ev) { gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], panel->pixmap, ev->area.x, ev->area.y, ev->area.x, ev->area.y, ev->area.width, ev->area.height); return FALSE; } static void panel_button_event(/*@unused@*/GtkWidget *widget, GdkEventButton *ev, /*@unused@*/gpointer data) { switch (ev->button) { case 1: panel_view = 1 - panel_view; /* Toggle between SUN/MOON */ redraw = 1; /* Force redraw */ break; case 2: break; case 3: gkrellm_open_config_window(sun_monitor); break; } } static void load_images() { GkrellmPiximage *image = NULL; /* Should we verify image was loaded? */ (void)gkrellm_load_piximage(NULL, OSUN_XPM, &image, NULL); (void)gkrellm_scale_piximage_to_pixmap(image, &osun_image, &osun_mask, 0, 0); (void)gkrellm_load_piximage(NULL, UVSUN_XPM, &image, NULL); (void)gkrellm_scale_piximage_to_pixmap(image, &uvsun_image, &uvsun_mask, 0, 0); (void)gkrellm_load_piximage(NULL, STAR_XPM, &image, NULL); (void)gkrellm_scale_piximage_to_pixmap(image, &star_image, &star_mask, 0, 0); (void)gkrellm_load_piximage(NULL, MOON_FULL_XPM, &image, NULL); (void)gkrellm_scale_piximage_to_pixmap(image, &moon_full_image, &moon_full_mask, 0, 0); (void)gkrellm_load_piximage(NULL, MOON_SM_XPM, &image, NULL); (void)gkrellm_scale_piximage_to_pixmap(image, &moon_sm_image, &moon_sm_mask, 0, 0); (void)gkrellm_load_piximage(NULL, DOT_XPM, &image, NULL); (void)gkrellm_scale_piximage_to_pixmap(image, &dot_image, &dot_mask, 0, 0); } /* Since init is only called upon gkrellm startup, set stuff to NULL here in case user enables plugin */ /* If plubin disabled or when gkrellm2 quits */ static void cb_plugin_disabled() { gint i, j; save_sun_data(); if (textOptions.fontDesc) pango_font_description_free (textOptions.fontDesc); /* This happens when user quits X Windows and gkrellm2 is still running */ if (colormap == NULL) { /* printf("ERROR : colormap is NULL at cb_plugin_disabled\n");*/ exit(EXIT_FAILURE); } /* Note : If the plugin was never created then there is nothing to free */ /* Free each suns' times colors */ for (i = 0; i < NUMBER_OF_SUNS; i++ ) { for (j = 0; j < NUMBER_OF_TIMES; j++) { if (colorsCreated == TRUE) gdk_colormap_free_colors(colormap, &timeColors_drawingarea[i][j],1); } } colorsCreated = FALSE; colormap = NULL; /* textOptions.fontDesc = NULL;*/ } /* Calculate height and width of text given a Pango Font */ static void getFontDimensions(gchar *text, gint *width, gint *height) { gint baseline, y_ink; *width = 0; *height = 0; /* All the times have the same font */ gkrellm_text_extents(textOptions.timeStyles[UV_SUN][TIME_RISE]->font, text, (gint)strlen(text), width, height, &baseline, &y_ink); /* For now, we'll use the baseline as height. */ *height = baseline; } /* Given a font name (as a string), calculate gdkFont, x_offsets for both 12 and 24 hour times */ static void setFontInfo(void) { gint chart_width, starting_y, y_spacing, time, sun; gint hour12_text_width, hour24_text_width, text_height; hour12_text_width = 0; hour24_text_width = 0; text_height = 0; y_spacing = 1; /* Spacing between times */ if (textOptions.fontDesc != NULL) pango_font_description_free (textOptions.fontDesc); textOptions.fontDesc = pango_font_description_from_string (textOptions.fontNames[FONT_NEW]); if (textOptions.fontDesc == NULL) { g_message(_("FATAL Error : Could not get Pango font description for %s\n"), textOptions.fontNames[FONT_NEW]); g_message(_(" Please email the author stating which font you picked.\n\n")); exit(EXIT_FAILURE); } /* If all is good, set NEW = CURRENT */ g_strlcpy(textOptions.fontNames[FONT_CURRENT], textOptions.fontNames[FONT_NEW], 128); for (time = 0; time < NUMBER_OF_TIMES; time++) { /* Use the same font for all suns and all times */ for (sun = 0; sun < NUMBER_OF_SUNS; sun++) { textOptions.timeStyles[sun][time]->font = textOptions.fontDesc; } } chart_width = gkrellm_chart_width(); getFontDimensions("00:00a", &hour12_text_width, &text_height); getFontDimensions("00:00", &hour24_text_width, &text_height); textOptions.timeXOffsets[CLOCK12] = (chart_width - hour12_text_width) / 2; textOptions.timeXOffsets[CLOCK24] = (chart_width - hour24_text_width) / 2; starting_y = textOptions.timeYOffsets[0]; /* Starting y position for times */ /*printf("text height %d, starting_y %d, y_spacing %d\n",text_height, starting_y, y_spacing);*/ for (time = 0; time < NUMBER_OF_TIMES; time++) { textOptions.timeYOffsets[time] = starting_y + ( (text_height + y_spacing) * time); } } static void createTimeDecals(gboolean destroy_decals) { gint sun, time; for(sun = 0; sun < NUMBER_OF_SUNS; sun++) { for (time = 0; time < NUMBER_OF_TIMES; time++) { if (destroy_decals) gkrellm_destroy_decal(time_decal[sun][time]); time_decal[sun][time] = gkrellm_create_decal_text(panel, "A8y", textOptions.timeStyles[sun][time], gkrellm_meter_style(style_id), -1, textOptions.timeYOffsets[sun], -1); // time_decal[sun][time]->flags |= DF_OVERLAY_PIXMAPS | DF_TOP_LAYER; gkrellm_decal_text_clear(time_decal[sun][time]); } } } static void sun_create_plugin(GtkWidget *vbox, gint first_create) { GkrellmStyle *style = NULL; int image_x_offset, image_y_offset; int count; gint sun, time; colorsCreated = TRUE; update_sun_data(&sununit); if (first_create) { panel = gkrellm_panel_new0(); load_sun_data(); load_images(); } else /* Theme changed */ { redraw = 1; } style = gkrellm_meter_style(style_id); colormap = gdk_colormap_get_system(); if (colormap == NULL) { g_message(_(" ERROR : colormap is NULL\n")); exit(EXIT_FAILURE); } for(sun = 0; sun < NUMBER_OF_SUNS; sun++) { for (time = 0; time < NUMBER_OF_TIMES; time++) { g_free(textOptions.timeStyles[sun][time]); textOptions.timeStyles[sun][time] = gkrellm_copy_textstyle(gkrellm_meter_textstyle(style_id)); textOptions.timeStyles[sun][time]->effect = 0; /* Turn off shadow */ if (! gdk_colormap_alloc_color(colormap, &(textOptions.timeColors[sun][time]),FALSE, TRUE) ) { g_message(_("ERROR allocating color for sun %d, time %d\n"),sun, time); } textOptions.timeStyles[sun][time]->color = textOptions.timeColors[sun][time]; timeColors_drawingarea[sun][time] = textOptions.timeColors[sun][time]; } } /* Load the solar images */ baseX = (gkrellm_chart_width() - SUN_WIDTH) / 2; baseY = (PLUGIN_HEIGHT - SUN_HEIGHT) / 2; image_x_offset = baseX; image_y_offset = baseY; uvsun = gkrellm_create_decal_pixmap(panel, uvsun_image, uvsun_mask, UVSUN_COUNT, style, image_x_offset, image_y_offset); osun = gkrellm_create_decal_pixmap(panel, osun_image, osun_mask, OSUN_COUNT, style, image_x_offset, image_y_offset); /* Load the star */ image_x_offset = baseX; image_y_offset = baseY; image_x_offset += 3; image_y_offset += 3; star = gkrellm_create_decal_pixmap(panel, star_image, star_mask, STAR_COUNT, style, image_x_offset, image_y_offset); /* Load the dots */ for (count = 0; count < PATH_COUNT; count++) { path[count] = gkrellm_create_decal_pixmap(panel, dot_image, dot_mask, DIGIT_COUNT, style, 0, count*PATH_SPACING); path90[count] = gkrellm_create_decal_pixmap(panel, dot_image, dot_mask, DIGIT_COUNT, style, 0, count*PATH_SPACING); } computePath(&sununit, path, altitudeAtNoon(&sununit)); computePath(&sununit, path90, 90); /* Load the moon */ image_x_offset = (gkrellm_chart_width() - MOON_FULL_WIDTH) / 2; image_y_offset = (PLUGIN_HEIGHT - MOON_FULL_HEIGHT) / 2; moon_full = gkrellm_create_decal_pixmap(panel, moon_full_image, moon_full_mask, MOON_FULL_COUNT, style, image_x_offset, image_y_offset); /* Load the small moon */ image_x_offset = baseX + SUN_WIDTH - MOON_SM_WIDTH - SUN_INNER_XOFS; image_y_offset = (PLUGIN_HEIGHT - MOON_SM_HEIGHT) / 2; moon_sm = gkrellm_create_decal_pixmap(panel, moon_sm_image, moon_sm_mask, MOON_SM_COUNT, style, image_x_offset, image_y_offset); panel->textstyle = gkrellm_meter_textstyle(style_id); gkrellm_panel_configure(panel, NULL, style); gkrellm_panel_create(vbox, sun_monitor, panel); if (first_create) { (void)gtk_signal_connect(GTK_OBJECT(panel->drawing_area), "expose_event", (GtkSignalFunc) panel_expose_event, NULL); (void)gtk_signal_connect(GTK_OBJECT(panel->drawing_area), "button_press_event", (GtkSignalFunc) panel_button_event, NULL); tooltip=gtk_tooltips_new(); } gkrellm_disable_plugin_connect(sun_monitor, cb_plugin_disabled); /* After creating panel */ setFontInfo(); createTimeDecals(FALSE); } static gint setTextColor_cb(/*@unused@*/GtkWidget *widget, /*@unused@*/GdkEventButton *ev, gpointer data) { GtkColorSelection *colorsel; GtkWidget *w; GdkColor color; gint response; gint whichTime = (gint)data % 10; gint whichSun = (gint)data / 10; w = gtk_color_selection_dialog_new(_("Pick a color")); colorsel = GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(w)->colorsel); gtk_color_selection_set_previous_color(colorsel, &timeColors_drawingarea[whichSun][whichTime]); gtk_color_selection_set_current_color(colorsel, &timeColors_drawingarea[whichSun][whichTime]); gtk_color_selection_set_has_palette(colorsel, TRUE); response = gtk_dialog_run(GTK_DIALOG(w)); if (response == GTK_RESPONSE_OK) { gtk_color_selection_get_current_color(colorsel, &color); gtk_widget_modify_bg(times_drawingarea[whichSun][whichTime], GTK_STATE_NORMAL, &color); timeColors_drawingarea[whichSun][whichTime] = color; } gtk_widget_hide(w); return TRUE; } static gint setTextFont_cb(/*@unused@*/GtkWidget *widget, /*@unused@*/GdkEventButton *ev, /*@unused@*/gpointer data) { GtkWidget *w; gint response; w = gtk_font_selection_dialog_new(_("Pick a font for all the times")); if (!gtk_font_selection_dialog_set_font_name((GtkFontSelectionDialog *)w, textOptions.fontNames[FONT_CURRENT])) { /* Should not happen */ g_message(_("Error could not find font %s\n"),textOptions.fontNames[FONT_CURRENT]); } gtk_font_selection_dialog_set_preview_text((GtkFontSelectionDialog *)w,"012345679:ap"); response = gtk_dialog_run(GTK_DIALOG(w)); if (response == GTK_RESPONSE_OK) { g_strlcpy(textOptions.fontNames[FONT_NEW], gtk_font_selection_dialog_get_font_name((GtkFontSelectionDialog *)w), 128); } gtk_widget_hide(w); return TRUE; } gboolean expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data) { gdk_draw_arc (widget->window, widget->style->bg_gc[GTK_WIDGET_STATE (widget)], TRUE, 0, 0, widget->allocation.width, widget->allocation.height, 0, 64 * 360); return TRUE; } static void sun_create_tab(GtkWidget *tab_vbox) { GtkWidget *tabs; GtkWidget *vbox, *thbox, *frame, *table; GtkWidget *ll_vbox, *ll_frame; GtkWidget *long_hbox, *lat_hbox; GtkWidget *table1; gint time; guint sun; GtkWidget *font_button; guint x; GtkSizeGroup *ll_size_group; tabs = gtk_notebook_new(); gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tabs), GTK_POS_TOP); gtk_box_pack_start(GTK_BOX(tab_vbox), tabs, TRUE, TRUE, 0); /* --Setup Tab */ vbox = gkrellm_gtk_notebook_page(tabs, _("Setup")); ll_frame = (GtkWidget *)gtk_frame_new(NULL); ll_vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), ll_frame, TRUE, FALSE, 0); gtk_container_add(GTK_CONTAINER(ll_frame),(GtkWidget *)ll_vbox); lat_hbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(ll_vbox), lat_hbox, FALSE, FALSE, 0); lat_N_radio_button = gtk_radio_button_new_with_label_from_widget ( NULL, _("North")); lat_S_radio_button = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON (lat_N_radio_button), _("South")); gtk_box_pack_start(GTK_BOX(lat_hbox), lat_N_radio_button, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(lat_hbox), lat_S_radio_button, FALSE, FALSE, 0); gkrellm_gtk_spin_button(lat_hbox, &latitude_spin_button, (gfloat) options.displayed_latitude, (gfloat)0.0, (gfloat)90.0, (gfloat)1.0, (gfloat)-1.0, 0, 60, NULL, NULL, FALSE, _("Latitude in decimal degrees")); long_hbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(ll_vbox), long_hbox, FALSE, FALSE, 0); long_E_radio_button = gtk_radio_button_new_with_label_from_widget ( NULL, _("East")); long_W_radio_button = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON (long_E_radio_button), _("West")); gtk_box_pack_start(GTK_BOX(long_hbox), long_E_radio_button, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(long_hbox), long_W_radio_button, FALSE, FALSE, 0); gkrellm_gtk_spin_button(long_hbox, &longitude_spin_button, (gfloat) options.displayed_longitude, (gfloat)0.0, (gfloat)180.0, (gfloat)1.0, (gfloat)-1.0, 0, 60, NULL, NULL, FALSE, _("Longitude in decimal degrees")); ll_size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); gtk_size_group_add_widget(ll_size_group, lat_N_radio_button); gtk_size_group_add_widget(ll_size_group, lat_S_radio_button); gtk_size_group_add_widget(ll_size_group, long_W_radio_button); gtk_size_group_add_widget(ll_size_group, long_E_radio_button); if (options.latitude >= 0) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lat_N_radio_button), TRUE); else gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lat_S_radio_button), TRUE); if (options.longitude >= 0) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (long_W_radio_button), TRUE); else gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (long_E_radio_button), TRUE); /* Layout for suns' text colors and font */ thbox = gtk_hbox_new(TRUE, 5); gtk_box_pack_start(GTK_BOX(vbox), thbox, FALSE, TRUE, 10); frame = (GtkWidget *)gtk_frame_new(NULL); table = (GtkWidget *)gtk_table_new(2,9, FALSE); gtk_container_add(GTK_CONTAINER(thbox),(GtkWidget *)frame); gtk_container_add(GTK_CONTAINER(frame),(GtkWidget *)table); for(sun=0; sun < NUMBER_OF_SUNS; sun++) { x = 0; for(time=0; time < NUMBER_OF_TIMES; time++) { times_drawingarea[sun][time] = gtk_drawing_area_new(); gtk_widget_set_size_request (times_drawingarea[sun][time], 40, 10); gtk_widget_modify_bg ((GtkWidget *)times_drawingarea[sun][time], GTK_STATE_NORMAL, &timeColors_drawingarea[sun][time]); g_signal_connect(G_OBJECT (times_drawingarea[sun][time]), "expose_event", G_CALLBACK (expose_event_callback), NULL); gtk_widget_add_events((GtkWidget *)times_drawingarea[sun][time], GDK_BUTTON_PRESS_MASK ); g_signal_connect(G_OBJECT(times_drawingarea[sun][time]), "button_press_event", G_CALLBACK(setTextColor_cb), (gpointer)((sun*10)+time) ); } switch(sun) { case 0: sun_radio_button[sun] = (GtkWidget *)gtk_radio_button_new_with_label (NULL, sunNames[sun]); break; default : sun_radio_button[sun] = (GtkWidget *)gtk_radio_button_new_with_label(gtk_radio_button_get_group (GTK_RADIO_BUTTON (sun_radio_button[sun-1])), sunNames[sun]); } /* left, right, top, bottom */ gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(sun_radio_button[sun]), x, x+1, sun, sun+1, GTK_FILL, GTK_SHRINK, 0,0 ); x++; gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(gtk_label_new(_(" ::: "))), x, x+1, sun, sun+1, GTK_SHRINK, GTK_SHRINK, 0,0); x++; gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(gtk_label_new(_("Rise="))), x, x+1, sun, sun+1, GTK_SHRINK, GTK_SHRINK, 0,0); x++; gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(times_drawingarea[sun][TIME_RISE]), x, x+1, sun, sun+1,GTK_SHRINK, GTK_FILL, 0,0); x++; gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(gtk_label_new(_("Set="))), x, x+1, sun, sun+1,GTK_SHRINK, GTK_SHRINK, 0,0); x++; gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(times_drawingarea[sun][TIME_SET]), x,x+1, sun, sun+1, GTK_SHRINK, GTK_FILL, 0,0); x++; gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(gtk_label_new(_("ETA="))), x, x+1, sun, sun+1,GTK_SHRINK, GTK_SHRINK, 0,0); x++; gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(times_drawingarea[sun][TIME_ETA]), x,x+1, sun, sun+1, GTK_SHRINK, GTK_FILL, 0,0); } /* TODO: Add key shortcut for Alt-F */ font_button = (GtkWidget *)gtk_button_new_from_stock("gtk-select-font"); gtk_table_attach((GtkTable *)table, font_button, 8,8+1, sun-2, sun+1, GTK_SHRINK, GTK_FILL, 0,0); (void)g_signal_connect (G_OBJECT(font_button), "button_press_event", G_CALLBACK (setTextFont_cb), (gpointer)sun); gtk_table_set_row_spacing((GtkTable *)table,0,10); gtk_table_set_col_spacing((GtkTable *)table,3,20); gtk_table_set_col_spacing((GtkTable *)table,5,20); gtk_table_set_col_spacing((GtkTable *)table,7,20); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sun_radio_button[options.whichSun]), TRUE); /* Other options */ table1 = (GtkWidget *)gtk_table_new(2, 3, TRUE); gtk_table_set_col_spacings((GtkTable *)table1, 15); gtk_box_pack_start(GTK_BOX(vbox), table1, TRUE, TRUE, 5); clock24_button = gtk_check_button_new_with_label (_("Use 24 hour clock")); /* showStar_button = gtk_check_button_new_with_label (_("Show star"));*/ showStar_button = gtk_check_button_new_with_label (_("Show relative position")); showPath_button = gtk_check_button_new_with_label (_("Show path")); show90Path_button = gtk_check_button_new_with_label (_("Show apogee path")); showMiniMoon_button = gtk_check_button_new_with_label (_("Show mini-moon")); showETA_button = gtk_check_button_new_with_label (_("Show rise/set ETA")); gtk_table_attach((GtkTable *)table1, clock24_button, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); gtk_table_attach((GtkTable *)table1, showStar_button, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0); gtk_table_attach((GtkTable *)table1, showPath_button, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); gtk_table_attach((GtkTable *)table1, show90Path_button, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); gtk_table_attach((GtkTable *)table1, showETA_button, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0); gtk_table_attach((GtkTable *)table1, showMiniMoon_button, 2, 3, 1, 2, GTK_FILL, GTK_FILL, 0, 0); gtk_toggle_button_set_active((GtkToggleButton *)clock24_button, options.clock24); gtk_toggle_button_set_active((GtkToggleButton *)showStar_button, options.showStar); gtk_toggle_button_set_active((GtkToggleButton *)showPath_button, options.showPath); gtk_toggle_button_set_active((GtkToggleButton *)show90Path_button, options.show90Path); gtk_toggle_button_set_active((GtkToggleButton *)showMiniMoon_button, options.showMiniMoon); gtk_toggle_button_set_active((GtkToggleButton *)showETA_button, options.showETA); gkrellm_gtk_spin_button(vbox, &sunmoon_spin_button, (int) options.sunmoon_toggle_minutes, (gfloat)0.0, (gfloat)60.0, (gfloat)1.0, (gfloat)1.0, 0, 0, NULL, NULL, FALSE, _("Minutes to toggle between Sun and Moon images (0 to disable).")); gkrellm_gtk_check_button(vbox, &debug_button, options.debug, TRUE, 0, _("Enable debugging output")); /* ----------------- info text --------------------*/ { GtkWidget *text; gint i; gchar *info_text[] = { N_("GKrellM2 SunClock Plugin\n\n"), N_("Click on the image to toggle the Sun/Moon view.\n\n"), N_("Latitude and Longitude:\n"), N_("
    \tLatitude: N is +, S is -\t\tLongitude: E is -, W is +.\n"), N_("\tWorld:\thttp://www.calle.com/world/\n" \ "\tUSA:\thttp://www.census.gov/cgi-bin/gazetteer\n" \ "\tInfo:\t\thttp://www.wunderground.com\n"), N_("Use 24 hour clock:\n"), N_("\tdisplay sunrise/sunset using 24 hour clock\n"), N_("Show star:\n"), N_("\tdisplay a small star showing the relative position of the sun\n" \ "\tas it appears on the horizon.\n"), N_("Show path:\n"), N_("\tuse dots to show the path of the sun across the sky\n"), N_("Show apogee path:\n"), N_("\tuse dots to show the path the sun would take if it went\n" \ "\t through the zenith at solar noon (it's highest path).\n"), N_("Show sun rise/set ETA:\n"), N_("\tshow ETA until sunrise/sunset below sunrise/sunset times\n"), }; vbox = gkrellm_gtk_notebook_page(tabs, _("Info")); text = gkrellm_gtk_scrolled_text_view(vbox, NULL, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); for (i=0; i < sizeof(info_text)/sizeof(gchar *); ++i) gkrellm_gtk_text_view_append(text, _(info_text[i])); } /* ----------------- about text --------------------*/ { gchar *plugin_about_text; GtkWidget *label, *text; plugin_about_text = g_strdup_printf( _("SunClock %d.%d.%d\n" \ "GKrellM2 SunClock Plugin\n" \ "$Id: gkrellsun.c,v 1.63 2004/09/08 16:44:42 kvh009 Exp $\n\n" \ "Copyright (C) 2001, 2002, 2003, 2004 Norman Walsh\n" \ "ndw@nwalsh.com\n\n" \ "v0.10.0+ Additional code by Kurt V. Hindenburg\n" \ "Copyright (C) 2004 Kurt V. Hindenburg\n" \ "public@kurt.hindenburg.name\n\n" \ "Derived from MoonClock 0.3 Copyright (C) 2001 Dale P. Smith\n" \ "and wmSun 1.03 Copyright (C) 1999 Mike Hnderson\n\n" \ "Released under the GNU Public Licence"), SUNCLOCK_MAJOR_VERSION, SUNCLOCK_MINOR_VERSION, SUNCLOCK_PATCH_VERSION); text = gtk_label_new(plugin_about_text); label = gtk_label_new(_("About")); gtk_notebook_append_page(GTK_NOTEBOOK(tabs),text,label); g_free(plugin_about_text); } } static void sun_apply_config() { gint sun, time, whichSun; options.clock24 = GTK_TOGGLE_BUTTON(clock24_button)->active; options.showStar = GTK_TOGGLE_BUTTON(showStar_button)->active; options.showPath = GTK_TOGGLE_BUTTON(showPath_button)->active; options.show90Path = GTK_TOGGLE_BUTTON(show90Path_button)->active; options.showMiniMoon = GTK_TOGGLE_BUTTON(showMiniMoon_button)->active; options.showETA = GTK_TOGGLE_BUTTON(showETA_button)->active; options.debug = GTK_TOGGLE_BUTTON(debug_button)->active; options.latitude = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON(latitude_spin_button)); options.displayed_latitude = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON(latitude_spin_button)); options.longitude = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON(longitude_spin_button)); options.displayed_longitude = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON(longitude_spin_button)); if (options.longitude < 0) options.displayed_longitude = -(options.longitude); else options.displayed_longitude = options.longitude; if (options.latitude < 0) options.displayed_latitude = -(options.latitude); else options.displayed_latitude = options.latitude; options.sunmoon_toggle_minutes = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON(sunmoon_spin_button)); if (GTK_TOGGLE_BUTTON(lat_S_radio_button)->active) options.latitude = -(options.latitude); if (GTK_TOGGLE_BUTTON(long_E_radio_button)->active) options.longitude = -(options.longitude); /* Will need changed when more than 2 suns */ whichSun = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (sun_radio_button[UV_SUN])); if (whichSun) whichSun = UV_SUN; else whichSun = ORANGE_SUN; options.whichSun = whichSun; /* Clear out time_decals */ for (sun = 0; sun < NUMBER_OF_SUNS; sun++) { for (time = 0; time < NUMBER_OF_TIMES; time++) { gkrellm_decal_text_clear(time_decal[sun][time]); } } /* Test to see if any colors have changed; checking all of the colors solves the problem if the user clicks on a sun's color when that sun is not active. */ for (sun = 0; sun < NUMBER_OF_SUNS; sun++) { for (time = 0; time < NUMBER_OF_TIMES; time++) { if (gdk_color_equal(&textOptions.timeColors[sun][time], &timeColors_drawingarea[sun][time]) == FALSE) { /* Only free the color that gets replaced */ gdk_colormap_free_colors(colormap, &textOptions.timeColors[sun][time],1); textOptions.timeColors[sun][time] = timeColors_drawingarea[sun][time]; if (gdk_colormap_alloc_color(colormap, &(textOptions.timeColors[sun][time]), FALSE, TRUE) == FALSE) { g_message(_("ERROR allocating color for sun %d, time %d\n"),sun, time); } } textOptions.timeStyles[sun][time]->color = textOptions.timeColors[sun][time]; timeColors_drawingarea[sun][time] = textOptions.timeColors[sun][time]; /* Update color block */ gtk_widget_modify_bg((GtkWidget *)times_drawingarea[sun][time], GTK_STATE_NORMAL, &textOptions.timeColors[sun][time]); } } /* Check for new font */ if (strncmp(textOptions.fontNames[FONT_CURRENT], textOptions.fontNames[FONT_NEW], 128)) { setFontInfo(); createTimeDecals(TRUE); } /* Update the display and tooltip to reflect changes */ update_sun_data( &sununit ); computePath(&sununit, path, altitudeAtNoon(&sununit)); /* computePath(&sununit, path90, 90);*/ redraw = 1; panel_view = 0; /* Force sun to panel */ update_tooltip ( &sununit ); } static GkrellmMonitor plugin_mon = { "Sun Clock", /* Name, for config tab. */ 0, /* Id, 0 if a plugin */ sun_create_plugin, /* The create_plugin() function */ sun_update_plugin, /* The update_plugin() function */ sun_create_tab, /* The create_plugin_tab() config function */ sun_apply_config, /* The apply_plugin_config() function */ /*sun_save_config,*/ /* The save_plugin_config() function */ NULL, /* The save_plugin_config() function */ /*sun_load_config,*/ /* The load_plugin_config() function */ NULL, /* The load_plugin_config() function */ PLUGIN_CONFIG_KEYWORD, /* config keyword */ NULL, /* Undefined 2 */ NULL, /* Undefined 1 */ NULL, /* private */ MON_INSERT_AFTER|MON_CLOCK,/* Insert plugin before this monitor. */ NULL, /* Handle if a plugin, filled in by GKrellM */ NULL /* path if a plugin, filled in by GKrellM */ }; #if defined(WIN32) __declspec(dllexport) GkrellmMonitor * gkrellm_init_plugin(win32_plugin_callbacks* calls) #else GkrellmMonitor * gkrellm_init_plugin() #endif { gint sun, time; #if defined(WIN32) callbacks = calls; pwin32GK = callbacks->GK; #endif sun_data_dir = gkrellm_make_data_file_name("sun", NULL); options.longitude = 73; /* Where I live! */ options.displayed_longitude = 73; /* Where I live! */ options.latitude = 42; options.displayed_latitude = 42; options.clock24 = 1; /* Use a 24 hour clock */ options.showStar = 1; /* Plot the star */ options.showPath = 0; /* But not the path */ options.show90Path = 0; /* Or the apogee path */ options.showMiniMoon = 0; /* Or the mini moon */ options.showETA = 0; /* Or the rise/set ETA */ options.debug = 0; /* No debugging */ options.whichSun = 0; options.sunmoon_toggle_minutes = 15; /* Toggle every x minutes */ #ifdef ENABLE_NLS bind_textdomain_codeset(PACKAGE, "UTF-8"); #endif /* ENABLE_NLS */ style_id = gkrellm_add_meter_style(&plugin_mon, STYLE_NAME); pGK = gkrellm_ticks(); for (time = 0; time < NUMBER_OF_TIMES; time++) { for (sun = 0; sun < NUMBER_OF_SUNS; sun++) { textOptions.timeColors[sun][time].red = 65535; textOptions.timeColors[sun][time].green = 65535; textOptions.timeColors[sun][time].blue = 65535; } g_strlcpy(time_str[time]," ",6); /* 1st one is all the matters, starting y for TIME_RISE */ textOptions.timeYOffsets[time] = 5; } g_strlcpy(textOptions.fontNames[FONT_CURRENT], "sans 8", 128); g_strlcpy(textOptions.fontNames[FONT_NEW], "sans 8", 128); colorsCreated = FALSE; textOptions.fontDesc = NULL; /* Upon gkrellm2 exiting, use same routine when plugin disabled */ g_atexit(cb_plugin_disabled); sun_monitor = &plugin_mon; return &plugin_mon; } static void load_sun_data(void) { gchar *contents = NULL; gchar *filename; gint i; gchar **lines; gchar *nfilename; gchar **entry; gchar **centry; int sun, type, red, green, blue; filename = g_build_filename(sun_data_dir, G_DIR_SEPARATOR_S, "sun", NULL); if (options.debug == TRUE) g_message(_("Loading %s data from <%s>\n"), PLUGIN_CONFIG_KEYWORD, filename); if (g_file_test (filename, G_FILE_TEST_EXISTS) == FALSE) { g_message(_("gkrellsun : Data file doesn't exist! %s\n"), filename); g_free(filename); return; } if (g_file_get_contents (filename, &contents, NULL, NULL) == FALSE) { g_message(_("gkrellsun : Unable to get contents of data file! %s\n"), filename); g_free(filename); return; } lines = g_strsplit (contents, "\n", -1); /* Check to see that data file is using '=' (ie. not old data file) */ if (g_strrstr(lines[0], "=") == NULL) { nfilename = g_build_filename(sun_data_dir, G_DIR_SEPARATOR_S, "sun-oldformat", NULL); g_message(_("gkrellsun : You are using an old-format data file. Not reading it... A copy of the old file is at %s\n"), nfilename); if (rename (filename, nfilename) < 0) { g_message(_("gkrellsun: Unable to rename %s to %s\n"), filename, nfilename); } g_free(filename); g_free(nfilename); g_strfreev (lines); return; } g_free(filename); for (i = 0; lines[i] != NULL; i++) { entry = g_strsplit (lines[i], "=", -1); if (entry[0] == NULL) continue; if (g_str_has_prefix(entry[0], "longitude")) { options.longitude=(int)g_ascii_strtoull(entry[1], NULL, 10); if (options.longitude < 0) options.displayed_longitude = -(options.longitude); else options.displayed_longitude = options.longitude; } else if (g_str_has_prefix(entry[0], "latitude")) { options.latitude=(int)g_ascii_strtoull(entry[1], NULL, 10); if (options.latitude < 0) options.displayed_latitude = -(options.latitude); else options.displayed_latitude = options.latitude; } else if (g_str_has_prefix(entry[0], "clock24")) { options.clock24=(int)g_ascii_strtoull(entry[1], NULL, 10); } else if (g_str_has_prefix(entry[0], "showstar")) { options.showStar=(int)g_ascii_strtoull(entry[1], NULL, 10); } else if (g_str_has_prefix(entry[0], "showpath")) { options.showPath=(int)g_ascii_strtoull(entry[1], NULL, 10); } else if (g_str_has_prefix(entry[0], "show90path")) { options.show90Path=(int)g_ascii_strtoull(entry[1], NULL, 10); } else if (g_str_has_prefix(entry[0], "showMiniMoon")) { options.showMiniMoon=(int)g_ascii_strtoull(entry[1], NULL, 10); } else if (g_str_has_prefix(entry[0], "showeta")) { options.showETA=(int)g_ascii_strtoull(entry[1], NULL, 10); } else if (g_str_has_prefix(entry[0], "toggleminutes")) { options.sunmoon_toggle_minutes=(int)g_ascii_strtoull(entry[1], NULL, 10); } else if (g_str_has_prefix(entry[0], "sun")) { options.whichSun=(int)g_ascii_strtoull(entry[1], NULL, 10); } else if (g_str_has_prefix(entry[0], "font")) { g_stpcpy(textOptions.fontNames[FONT_NEW], entry[1]); } else if (g_str_has_prefix(entry[0], "debug")) { options.debug=(int)g_ascii_strtoull(entry[1], NULL, 10); } else if (g_str_has_prefix(entry[0], "colors")) { centry = g_strsplit (entry[1], " ", -1); sun = (int)g_ascii_strtoull(centry[0], NULL, 10); type = (int)g_ascii_strtoull(centry[1], NULL, 10); red = (int)g_ascii_strtoull(centry[2], NULL, 10); green = (int)g_ascii_strtoull(centry[3], NULL, 10); blue = (int)g_ascii_strtoull(centry[4], NULL, 10); textOptions.timeColors[sun][type].red = (guint16)red; textOptions.timeColors[sun][type].green = (guint16)green; textOptions.timeColors[sun][type].blue = (guint16)blue; g_strfreev (centry); } else g_message(_("gkrellsun: Unknown entry in data file %s\n"), entry[0]); g_strfreev (entry); } g_strfreev (lines); } static void save_sun_data(void) { FILE *f; GdkColor c; gint sun, time; gchar *filename; filename = g_build_filename(sun_data_dir, G_DIR_SEPARATOR_S, "sun", NULL); if (options.debug == TRUE) g_message(_("Saving %s to <%s>\n"), PLUGIN_CONFIG_KEYWORD, filename); if ((f = fopen(filename, "w")) == NULL) { g_message(_("gkrellsun : Unable to save data to %s!\n"), filename); g_free(filename); return; } fprintf(f, "longitude=%d\n", options.longitude); fprintf(f, "latitude=%d\n", options.latitude); fprintf(f, "clock24=%d\n", options.clock24); fprintf(f, "showstar=%d\n", options.showStar); fprintf(f, "showpath=%d\n", options.showPath); fprintf(f, "show90path=%d\n", options.show90Path); fprintf(f, "showMiniMoon=%d\n", options.showMiniMoon); fprintf(f, "showeta=%d\n", options.showETA); fprintf(f, "debug=%d\n", options.debug); fprintf(f, "font=%s\n", textOptions.fontNames[FONT_CURRENT]); /* Before colors */ fprintf(f, "sun=%d\n", options.whichSun); for (sun = 0; sun < NUMBER_OF_SUNS; sun++) { for (time = 0; time < NUMBER_OF_TIMES; time++) { c = textOptions.timeColors[sun][time]; fprintf(f, "colors=%d %d %d %d %d\n", sun, time, (int)c.red, (int)c.green, (int)c.blue); } } fprintf(f, "toggleminutes=%d\n", options.sunmoon_toggle_minutes); g_free(filename); fclose(f); }