Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gnome-applets/gweather/ChangeLog,v
retrieving revision 1.287
diff -u -r1.287 ChangeLog
--- ChangeLog	8 Nov 2004 16:55:44 -0000	1.287
+++ ChangeLog	22 Nov 2004 05:16:24 -0000
@@ -1,3 +1,31 @@
+2004-11-20  Frank Solensky  <frank@solensky.org>
+
+	reviewed by: <delete if not using a buddy>
+
+	* gweather-dialog.c: (gweather_dialog_create),
+	(gweather_dialog_update): Display local sunrise, sunset times
+	* gweather-pref.c: (gweather_pref_set_accessibility),
+	(update_dialog), (change_cb), (row_selected_cb):
+	save coordinates of preferred location
+	* gweather-xml.c: (gweather_xml_parse_location):
+	parse coordinate strings
+	* gweather.h: add local sunrise, sunset times to GWeatherApplet
+	* weather.c: (dmsh2rad), (weather_location_new),
+	(weather_location_config_read), (weather_location_clone),
+	(request_done), (make_time), (metar_tok_time), (ecl2equ),
+	(gstObsv), (t0), (sun), (calc_sun), (_weather_info_fill),
+	(weather_info_config_read), (weather_info_get_update),
+	(weather_info_get_sunrise), (weather_info_get_sunset),
+	(init_pixbufs), (_weather_info_get_pixbuf): calculations for
+	and pixmax selection based on times of local sunrise and sunset;
+	make_time simplified
+	* weather.h: store latitute, longitude in WeatherLocation;
+	additional entry points
+	* Locations.xml.in: Add examples of coordinates for "city"
+	locations plus Perth
+
+	Closes #68616.
+	
 2004-11-09  Davyd Madeley  <davyd@madeley.id.au>
 
 	* gweather-applet.c: Make gweather work with transparent panels.
Index: Locations.xml.in
===================================================================
RCS file: /cvs/gnome/gnome-applets/gweather/Locations.xml.in,v
retrieving revision 1.22
diff -u -r1.22 Locations.xml.in
--- Locations.xml.in	19 Nov 2004 14:05:32 -0000	1.22
+++ Locations.xml.in	22 Nov 2004 05:16:27 -0000
@@ -586,19 +586,23 @@
     <location>
      <_name>Ted Stevens Anchorage Airport</_name>
      <code>PANC</code>
+     <coordinates>61-10-28N 149-59-46W</coordinates>
     </location>
     <location>
      <!-- TRANSLATOR: AFB is short for "Air Force Base" -->
      <_name>Elmendorf AFB</_name>
      <code>PAED</code>
+     <coordinates>61-15-11N 149-47-38W</coordinates>
     </location>
     <location>
      <_name>Lake Hood Sea Plane Base</_name>
      <code>PALH</code>
+     <coordinates>61-11N 149-58W</coordinates>
     </location>
     <location>
      <_name>Merrill Field</_name>
      <code>PAMR</code>
+     <coordinates>61-13N 149-51W</coordinates>
     </location>
    </city>
    <location>
@@ -2691,14 +2695,22 @@
     <location>
      <_name>Albuquerque Airport</_name>
      <code>KABQ</code>
+     <coordinates>35-02-30N 106-36-53W</coordinates>
     </location>
     <location>
      <_name>Double Eagle II Airport</_name>
      <code>KAEG</code>
+     <coordinates>35-08-42N 106-47-42W</coordinates>
     </location>
     <location>
      <_name>Nexrad</_name>
      <code>KABX</code>     
+     <coordinates>35-09N 106-49W</coordinates>
+    </location>
+    <location>
+     <_name>Albuquerque Radar Site</_name>
+     <code>KZAB</code>
+     <coordinates>35-10N 106-34W</coordinates>
     </location>
    </city>
    <location>
@@ -5021,18 +5033,22 @@
     <location>
      <_name>Hartsfield Airport</_name>
      <code>KATL</code>
+     <coordinates>33-37-47N 084-26-32W</coordinates>
     </location>
     <location>
      <_name>De Kalb-Peachtree Airport</_name>
      <code>KPDK</code>
+     <coordinates>33-52-42N 084-17-53W</coordinates>
     </location>
     <location>
      <_name>Falcon Field</_name>
      <code>KFFC</code>
+     <coordinates>33-21-19N 084-34-01W</coordinates>
     </location>
     <location>
      <_name>Fulton County Airport</_name>
      <code>KFTY</code>
+     <coordinates>33-46-39N 084-31-28W</coordinates>
     </location>
    </city>
    <location>
@@ -5272,32 +5288,44 @@
     <location>
      <_name>Lakefront</_name>
      <code>KCGX</code>
+     <coordinates>41-52N 087-36W</coordinates>
     </location>
     <location>
      <_name>Lansing</_name>
      <code>KIGQ</code>
+     <coordinates>41-32-24N 087-31-56W</coordinates>
     </location>
     <location>
      <_name>Midway Airport</_name>
      <code>KMDW</code>
+     <coordinates>41-47-03N 087-45-19W</coordinates>
     </location>
     <location>
      <_name>O'Hare Airport</_name>
      <code>KORD</code>
      <zone>ILZ013</zone>
+     <coordinates>41-58-47N 087-54-16W</coordinates>
+    </location>
+    <location>
+     <_name>Romeoville, Lewis University Airport</_name>
+     <code>KLOT</code>
+     <coordinates>41-36-30N 088-05-39W</coordinates>
     </location>
     <location>
      <_name>Waukegan</_name>
      <code>KUGN</code>
+     <coordinates>42-25N 087-52W</coordinates>
     </location>
     <location>
      <_name>West Chicago</_name>
      <code>KDPA</code>
+     <coordinates>41-53-47N 088-15-04W</coordinates>
     </location>
     <location>
      <_name>Wheeling</_name>
      <code>KPWK</code>
      <zone>ILZ006</zone>
+     <coordinates>42-07-15N 087-54-17W</coordinates>
     </location>
    </city>
    <location>
@@ -5479,15 +5507,18 @@
     <location>
      <_name>Inner Harbor</_name>
      <code>KDMH</code>
+     <coordinates>39-17N 076-37W</coordinates>
     </location>
     <location>
      <_name>Martin</_name>
      <code>KMTN</code>
+     <coordinates>39-20N 076-25W</coordinates>
     </location>
     <location>
      <_name>Glen Burnie</_name>
      <code>KBWI</code>
      <zone>MDZ014</zone>
+     <coordinates>39-10-00N 076-41-00W</coordinates>
     </location>
    </city>
    <location>
@@ -6723,18 +6754,22 @@
     <location>
      <_name>Airport</_name>
      <code>KCRP</code>
+     <coordinates>27-46-23N 097-30-46W</coordinates>
     </location>
     <location>
      <_name>Cabiness Field</_name>
      <code>KNGW</code>
+     <coordinates>27-43-21N 097-26-33W</coordinates>
     </location>
     <location>
      <_name>Naval Air Station</_name>
      <code>KNGP</code>
+     <coordinates>27-41-19N 097-17-30W</coordinates>
     </location>
     <location>
      <_name>Waldron</_name>
      <code>KNVT</code>
+     <coordinates>27-37-52N 097-18-42W</coordinates>
     </location>
    </city>
    <location>
@@ -6762,22 +6797,27 @@
     <location>
      <_name>Addison</_name>
      <code>KADS</code>
+     <coordinates>32-58N 096-50W</coordinates>
     </location>
     <location>
      <_name>Dallas-Fort Worth</_name>
      <code>KDFW</code>
+     <coordinates>32-53-49N 097-01-19W</coordinates>
     </location>
     <location>
      <_name>Love Field</_name>
      <code>KDAL</code>
+     <coordinates>32-51-09N 096-51-20W</coordinates>
     </location>
     <location>
-     <_name>NAS</_name>
+     <_name>Naval Air Station</_name>
      <code>KNBE</code>
+     <coordinates>32-44N 096-58W</coordinates>
     </location>
     <location>
      <_name>Redbird</_name>
      <code>KRBD</code>
+     <coordinates>32-40-33N 096-51-50W</coordinates>
     </location>
    </city>
    <location>
@@ -6867,30 +6907,37 @@
     <location>
      <_name>Ellington Field</_name>
      <code>KEFD</code>
+     <coordinates>29-36N 095-10W</coordinates>
     </location>
     <location>
      <_name>Galviston Nexrad</_name>
+     <coordinates>29-28N 095-05W</coordinates>
      <code>KHGX</code>
     </location>
     <location>
      <_name>Hooks Airport</_name>
      <code>KDWH</code>
+     <coordinates>30-04-03N 095-33-22W</coordinates>
     </location>
     <location>
      <_name>Hobby Airport</_name>
      <code>KHOU</code>
+     <coordinates>29-38-15N 095-16-57W</coordinates>
     </location>
     <location>
      <_name>Houston Intercontinental Airport</_name>
      <code>KIAH</code>
+     <coordinates>29-59-33N 095-21-50W</coordinates>
     </location>
     <location>
      <_name>Perland</_name>
      <code>KLVJ</code>
+     <coordinates>29-31-16N 095-14-31W</coordinates>
     </location>
     <location>
      <_name>Sugar Land</_name>
      <code>KSGR</code>
+     <coordinates>29-37-20N 095-39-24W</coordinates>
     </location>
    </city>
    <location>
@@ -7596,14 +7643,17 @@
     <location>
      <_name>Hull Coast Guard Light Station</_name>
      <code>K29B</code>
+     <coordinates>42-19N 070-53W</coordinates>
     </location>
     <location>
      <_name>Logan Airport</_name>
      <code>KBOS</code>
+     <coordinates>42-21-38N 071-00-38W</coordinates>
     </location>
     <location>
      <_name>Nexrad</_name>
      <code>KBOX</code>
+     <coordinates>41-57N 071-08W</coordinates>
     </location>
    </city>
    <location>
@@ -7796,14 +7846,17 @@
     <location>
      <_name>Central Park</_name>
      <code>KNYC</code>
+     <coordinates>40-47-00N 073-58-00W</coordinates>
     </location>
     <location>
      <_name>Kennedy Airport</_name>
      <code>KJFK</code>
+     <coordinates>40-38-19N 073-45-44W</coordinates>
     </location>
     <location>
      <_name>La Guardia Airport</_name>
      <code>KLGA</code>
+     <coordinates>40-46-45N 073-52-48W</coordinates>
     </location>
    </city>
    <location>
@@ -11903,6 +11956,7 @@
     <_name>Melbourne</_name>
     <code>YMML</code>
     <zone>@IDV10450</zone>
+    <coordinates>37-40S 144-50E</coordinates>
    </location>
    <location>
     <_name>Norfolk Island</_name>
@@ -11913,6 +11967,7 @@
     <_name>Perth</_name>
     <code>YPPH</code>
     <zone>@IDW12300</zone>
+    <coordinates>31-56S 115-57E</coordinates>
    </location>
    <location>
     <_name>Port Hedland</_name>
Index: gweather-dialog.c
===================================================================
RCS file: /cvs/gnome/gnome-applets/gweather/gweather-dialog.c,v
retrieving revision 1.47
diff -u -r1.47 gweather-dialog.c
--- gweather-dialog.c	22 Oct 2004 14:10:36 -0000	1.47
+++ gweather-dialog.c	22 Nov 2004 05:16:27 -0000
@@ -139,6 +139,8 @@
   GtkWidget *cond_vis_lbl;
   GtkWidget *cond_dew_lbl;
   GtkWidget *cond_apparent_lbl;
+  GtkWidget *cond_sunrise_lbl;
+  GtkWidget *cond_sunset_lbl;
   GtkWidget *cond_frame_alignment;
   GtkWidget *current_note_lbl;
   GtkWidget *forecast_note_lbl;
@@ -185,7 +187,7 @@
   gtk_container_add (GTK_CONTAINER (weather_notebook), cond_hbox);
   gtk_container_set_border_width (GTK_CONTAINER (cond_hbox), 4);
 
-  cond_table = gtk_table_new (11, 2, FALSE);
+  cond_table = gtk_table_new (13, 2, FALSE);
   gtk_widget_show (cond_table);
   gtk_box_pack_start (GTK_BOX (cond_hbox), cond_table, TRUE, TRUE, 0);
   gtk_container_set_border_width (GTK_CONTAINER (cond_table), 12);
@@ -280,6 +282,22 @@
   gtk_label_set_justify (GTK_LABEL (cond_vis_lbl), GTK_JUSTIFY_LEFT);
   gtk_misc_set_alignment (GTK_MISC (cond_vis_lbl), 0, 0.5);
 
+  cond_sunrise_lbl = gtk_label_new (_("Sunrise:"));
+  gtk_widget_show (cond_sunrise_lbl);
+  gtk_table_attach (GTK_TABLE (cond_table), cond_sunrise_lbl, 0, 1, 11, 12,
+                    (GtkAttachOptions) (GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+  gtk_label_set_justify (GTK_LABEL (cond_sunrise_lbl), GTK_JUSTIFY_LEFT);
+  gtk_misc_set_alignment (GTK_MISC (cond_sunrise_lbl), 0, 0.5);
+
+  cond_sunset_lbl = gtk_label_new (_("Sunset:"));
+  gtk_widget_show (cond_sunset_lbl);
+  gtk_table_attach (GTK_TABLE (cond_table), cond_sunset_lbl, 0, 1, 12, 13,
+                    (GtkAttachOptions) (GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+  gtk_label_set_justify (GTK_LABEL (cond_sunset_lbl), GTK_JUSTIFY_LEFT);
+  gtk_misc_set_alignment (GTK_MISC (cond_sunset_lbl), 0, 0.5);
+
   gw_applet->cond_location = gtk_label_new ("");
   gtk_widget_show (gw_applet->cond_location);
   gtk_table_attach (GTK_TABLE (cond_table), gw_applet->cond_location, 1, 2, 0, 1,
@@ -379,6 +397,24 @@
   gtk_label_set_justify (GTK_LABEL (gw_applet->cond_vis), GTK_JUSTIFY_LEFT);
   gtk_misc_set_alignment (GTK_MISC (gw_applet->cond_vis), 0, 0.5);
 
+  gw_applet->cond_sunrise = gtk_label_new ("");
+  gtk_widget_show (gw_applet->cond_sunrise);
+  gtk_table_attach (GTK_TABLE (cond_table), gw_applet->cond_sunrise, 1, 2, 11, 12,
+                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+  gtk_label_set_selectable (GTK_LABEL (gw_applet->cond_sunrise), TRUE);
+  gtk_label_set_justify (GTK_LABEL (gw_applet->cond_sunrise), GTK_JUSTIFY_LEFT);
+  gtk_misc_set_alignment (GTK_MISC (gw_applet->cond_sunrise), 0, 0.5);
+
+  gw_applet->cond_sunset = gtk_label_new ("");
+  gtk_widget_show (gw_applet->cond_sunset);
+  gtk_table_attach (GTK_TABLE (cond_table), gw_applet->cond_sunset, 1, 2, 12, 13,
+                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+  gtk_label_set_selectable (GTK_LABEL (gw_applet->cond_sunset), TRUE);
+  gtk_label_set_justify (GTK_LABEL (gw_applet->cond_sunset), GTK_JUSTIFY_LEFT);
+  gtk_misc_set_alignment (GTK_MISC (gw_applet->cond_sunset), 0, 0.5);
+
   cond_frame_alignment = gtk_alignment_new (0.5, 0, 1, 0);
   gtk_widget_show (cond_frame_alignment);
   gtk_box_pack_end (GTK_BOX (cond_hbox), cond_frame_alignment, FALSE, FALSE, 0);
@@ -539,6 +575,8 @@
     gtk_label_set_text(GTK_LABEL(gw_applet->cond_wind), weather_info_get_wind(gw_applet->gweather_info));
     gtk_label_set_text(GTK_LABEL(gw_applet->cond_pressure), weather_info_get_pressure(gw_applet->gweather_info));
     gtk_label_set_text(GTK_LABEL(gw_applet->cond_vis), weather_info_get_visibility(gw_applet->gweather_info));
+    gtk_label_set_text(GTK_LABEL(gw_applet->cond_sunrise), weather_info_get_sunrise(gw_applet->gweather_info));
+    gtk_label_set_text(GTK_LABEL(gw_applet->cond_sunset), weather_info_get_sunset(gw_applet->gweather_info));
 
     /* Update forecast */
     if (gw_applet->gweather_pref.location->zone_valid) {
Index: gweather-pref.c
===================================================================
RCS file: /cvs/gnome/gnome-applets/gweather/gweather-pref.c,v
retrieving revision 1.84
diff -u -r1.84 gweather-pref.c
--- gweather-pref.c	12 Oct 2004 13:57:01 -0000	1.84
+++ gweather-pref.c	22 Nov 2004 05:16:27 -0000
@@ -68,16 +68,16 @@
     { SPEED_UNIT_KPH,     "km/h"    },
     { SPEED_UNIT_MPH,     "mph"     },
     { SPEED_UNIT_KNOTS,   "knots"   },
-	{ 0, NULL }
+    { 0, NULL }
 };
 
 static GConfEnumStringPair pressure_unit_enum_map [] = {
     { PRESSURE_UNIT_DEFAULT, "Default" },
-	{ PRESSURE_UNIT_KPA,     "kPa"     },
-	{ PRESSURE_UNIT_HPA,     "hPa"     },
-	{ PRESSURE_UNIT_MB,      "mb"      },
+    { PRESSURE_UNIT_KPA,     "kPa"     },
+    { PRESSURE_UNIT_HPA,     "hPa"     },
+    { PRESSURE_UNIT_MB,      "mb"      },
     { PRESSURE_UNIT_MM_HG,   "mmHg"    },
-	{ PRESSURE_UNIT_INCH_HG, "inHg"    },
+    { PRESSURE_UNIT_INCH_HG, "inHg"    },
     { 0, NULL }
 };
 
@@ -178,20 +178,19 @@
 
     /* Relation between components in General page */
 
-    add_atk_relation (gw_applet->pref_basic_update_btn, gw_applet->pref_basic_update_spin,                                             ATK_RELATION_CONTROLLER_FOR);
-    add_atk_relation (gw_applet->pref_basic_radar_btn, gw_applet->pref_basic_radar_url_btn,                                            ATK_RELATION_CONTROLLER_FOR);
-    add_atk_relation (gw_applet->pref_basic_radar_btn, gw_applet->pref_basic_radar_url_entry                                            , ATK_RELATION_CONTROLLER_FOR);
-
-    add_atk_relation (gw_applet->pref_basic_update_spin, gw_applet->pref_basic_update_btn,                                             ATK_RELATION_CONTROLLED_BY);
-    add_atk_relation (gw_applet->pref_basic_radar_url_btn, gw_applet->pref_basic_radar_btn,                                            ATK_RELATION_CONTROLLED_BY);
-    add_atk_relation (gw_applet->pref_basic_radar_url_entry, gw_applet->pref_basic_radar_btn                                            , ATK_RELATION_CONTROLLED_BY);
+    add_atk_relation (gw_applet->pref_basic_update_btn, gw_applet->pref_basic_update_spin, ATK_RELATION_CONTROLLER_FOR);
+    add_atk_relation (gw_applet->pref_basic_radar_btn, gw_applet->pref_basic_radar_url_btn, ATK_RELATION_CONTROLLER_FOR);
+    add_atk_relation (gw_applet->pref_basic_radar_btn, gw_applet->pref_basic_radar_url_entry, ATK_RELATION_CONTROLLER_FOR);
+
+    add_atk_relation (gw_applet->pref_basic_update_spin, gw_applet->pref_basic_update_btn, ATK_RELATION_CONTROLLED_BY);
+    add_atk_relation (gw_applet->pref_basic_radar_url_btn, gw_applet->pref_basic_radar_btn, ATK_RELATION_CONTROLLED_BY);
+    add_atk_relation (gw_applet->pref_basic_radar_url_entry, gw_applet->pref_basic_radar_btn, ATK_RELATION_CONTROLLED_BY);
 
     /* Accessible Name and Description for the components in Preference Dialog */
    
-    set_access_namedesc (gw_applet->pref_tree, _("Location view"),                                                       _("Select Location from the list"));
-    
-    set_access_namedesc (gw_applet->pref_basic_update_spin, _("Update spin button"),                                      _("Spinbutton for updating"));
-    set_access_namedesc (gw_applet->pref_basic_radar_url_entry, _("Address Entry"),                                        _("Enter the URL"));
+    set_access_namedesc (gw_applet->pref_tree, _("Location view"), _("Select Location from the list"));
+    set_access_namedesc (gw_applet->pref_basic_update_spin, _("Update spin button"), _("Spinbutton for updating"));
+    set_access_namedesc (gw_applet->pref_basic_radar_url_entry, _("Address Entry"), _("Enter the URL"));
 
 }
 
@@ -217,28 +216,28 @@
     if ( gw_applet->gweather_pref.use_temperature_default) {
         gtk_combo_box_set_active (GTK_COMBO_BOX(gw_applet->pref_basic_temp_combo), 0);
     } else {
-		gtk_combo_box_set_active (GTK_COMBO_BOX(gw_applet->pref_basic_temp_combo), 
-	                 gw_applet->gweather_pref.temperature_unit -1);
+        gtk_combo_box_set_active (GTK_COMBO_BOX(gw_applet->pref_basic_temp_combo), 
+				  gw_applet->gweather_pref.temperature_unit -1);
     }
 	
     if ( gw_applet->gweather_pref.use_speed_default) {
         gtk_combo_box_set_active (GTK_COMBO_BOX(gw_applet->pref_basic_speed_combo), 0);
     } else {
         gtk_combo_box_set_active (GTK_COMBO_BOX(gw_applet->pref_basic_speed_combo), 
-	                 gw_applet->gweather_pref.speed_unit -1);
+				  gw_applet->gweather_pref.speed_unit -1);
     }
 	
     if ( gw_applet->gweather_pref.use_pressure_default) {
         gtk_combo_box_set_active (GTK_COMBO_BOX(gw_applet->pref_basic_pres_combo), 0);
     } else {
         gtk_combo_box_set_active (GTK_COMBO_BOX(gw_applet->pref_basic_pres_combo), 
-	                 gw_applet->gweather_pref.pressure_unit -1);
+				  gw_applet->gweather_pref.pressure_unit -1);
     }
     if ( gw_applet->gweather_pref.use_distance_default) {
         gtk_combo_box_set_active (GTK_COMBO_BOX(gw_applet->pref_basic_dist_combo), 0);
     } else {
         gtk_combo_box_set_active (GTK_COMBO_BOX(gw_applet->pref_basic_dist_combo), 
-	                 gw_applet->gweather_pref.distance_unit -1);
+				  gw_applet->gweather_pref.distance_unit -1);
     }
 
 #if 0
@@ -306,8 +305,8 @@
 {
     GWeatherApplet *gw_applet = user_data;
     
-    soft_set_sensitive(gw_applet->pref_basic_update_spin, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gw_applet->pref_basic_update_btn)));
-    
+    soft_set_sensitive(gw_applet->pref_basic_update_spin,
+		       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gw_applet->pref_basic_update_btn)));
     return;
 }
 
@@ -331,11 +330,13 @@
     panel_applet_gconf_set_string(gw_applet->applet, "location2", loc->zone, NULL);
     panel_applet_gconf_set_string(gw_applet->applet, "location3", loc->radar, NULL);
     panel_applet_gconf_set_string(gw_applet->applet, "location4", loc->trans_name, NULL);
+    panel_applet_gconf_set_string(gw_applet->applet, "coordinates", loc->coordinates, NULL);
+    
     if (gw_applet->gweather_pref.location) {
        weather_location_free (gw_applet->gweather_pref.location);
     }
-    
     gw_applet->gweather_pref.location = weather_location_config_read (gw_applet->applet);
+    
     gweather_update (gw_applet);
 } 
 
Index: gweather-xml.c
===================================================================
RCS file: /cvs/gnome/gnome-applets/gweather/gweather-xml.c,v
retrieving revision 1.2
diff -u -r1.2 gweather-xml.c
--- gweather-xml.c	28 Sep 2004 16:58:06 -0000	1.2
+++ gweather-xml.c	22 Nov 2004 05:16:28 -0000
@@ -34,6 +34,7 @@
  *    <code>IWIN code</code>
  *    <zone>Forecast code (North America, Australia, UK only)</zone>
  *    <radar>Weather.com radar map code (North America only)</radar>
+ *    <coordinates>Latitude and longitude as DD-MM[-SS][H] pair</coordinates>
  *   </location>
  *   <state>
  *     <location>
@@ -87,6 +88,7 @@
 #define GWEATHER_XML_NODE_CODE       "code"
 #define GWEATHER_XML_NODE_ZONE       "zone"
 #define GWEATHER_XML_NODE_RADAR      "radar"
+#define GWEATHER_XML_NODE_COORD      "coordinates"
 
 /* XML Attributes */
 #define GWEATHER_XML_ATTR_FORMAT    "format"
@@ -241,8 +243,8 @@
 					 GtkTreeIter* iter, GtkTreeIter* r_iter, GtkTreeIter* c_iter,
 					 xmlChar *dfltZone, xmlChar *dfltRadar, xmlChar *untransCity, xmlChar *transCity)
 {
-    int ret, type;
-    xmlChar *name, *untrans_name, *trans_name, *code, *zone, *radar;
+    int type;
+    xmlChar *name, *untrans_name, *trans_name, *code, *zone, *radar, *coordinates;
     GtkTreeStore *store;
     WeatherLocation* new_loc;
     gint pref;
@@ -259,6 +261,7 @@
     code = NULL;
     zone = dfltZone;
     radar = dfltRadar;
+    coordinates = NULL;
     pref = -1;
 
     /* create a node in the tree for this region */
@@ -279,9 +282,11 @@
             } else if ( code == NULL && strcmp (name, GWEATHER_XML_NODE_CODE) == 0 ) {
                 code = gweather_xml_get_value (reader);
             } else if ( strcmp (name, GWEATHER_XML_NODE_ZONE) == 0 ) {
-                zone = gweather_xml_get_value (reader);
+	        zone = gweather_xml_get_value (reader);
             } else if ( strcmp (name, GWEATHER_XML_NODE_RADAR) == 0 ) {
                 radar = gweather_xml_get_value (reader);
+	    } else if ( strcmp (name, GWEATHER_XML_NODE_COORD) == 0 ) {
+		coordinates = gweather_xml_get_value (reader);
 	    } else {
 	        xmlFree (gweather_xml_get_value (reader) );
 	    }
@@ -292,7 +297,7 @@
     
     /* Add an entry in the tree for the location */
     new_loc = weather_location_new((untransCity ? untransCity : untrans_name), (transCity ? transCity : trans_name),
-				   code, zone, radar);
+				   code, zone, radar, coordinates);
     gtk_tree_store_set (store, iter, GWEATHER_PREF_COL_POINTER, new_loc, -1);
 
     /* Free xml attributes */
@@ -303,6 +308,7 @@
         xmlFree(zone);
     if (radar != dfltRadar)
         xmlFree(radar);
+    xmlFree(coordinates);
 
     /* If this location is actually the currently selected one, select it */
     if ( loc && weather_location_equal (new_loc, loc) ) {
Index: gweather.h
===================================================================
RCS file: /cvs/gnome/gnome-applets/gweather/gweather.h,v
retrieving revision 1.15
diff -u -r1.15 gweather.h
--- gweather.h	9 Aug 2004 09:06:58 -0000	1.15
+++ gweather.h	22 Nov 2004 05:16:28 -0000
@@ -133,6 +133,8 @@
 	GtkWidget *cond_pressure;
 	GtkWidget *cond_vis;
 	GtkWidget *cond_apparent;
+	GtkWidget *cond_sunrise;
+	GtkWidget *cond_sunset;
 	GtkWidget *cond_image;
 	GtkWidget *forecast_text;
 	GtkWidget *radar_image;
Index: weather.c
===================================================================
RCS file: /cvs/gnome/gnome-applets/gweather/weather.c,v
retrieving revision 1.93
diff -u -r1.93 weather.c
--- weather.c	24 Aug 2004 03:32:21 -0000	1.93
+++ weather.c	22 Nov 2004 05:16:29 -0000
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <ctype.h>
 #include <math.h>
+#include <values.h>
 
 #ifdef __FreeBSD__
 #include <sys/types.h>
@@ -38,6 +39,7 @@
 void
 close_cb (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data);
 static gchar* formatWeatherMsg (gchar* msg);
+static gboolean calc_sun (WeatherInfo *info);
 
 /* FIXME: these global variables will cause conflicts when multiple
 ** instances of the applets update at the same time
@@ -66,8 +68,49 @@
 #define VISIBILITY_SM_TO_KM(sm)  ((sm) * 1.609344)
 #define VISIBILITY_SM_TO_M(sm)   (VISIBILITY_SM_TO_KM(sm) * 1000)
 
+#define DEGREES_TO_RADIANS(deg)   ((fmod(deg,360.) / 180.) * M_PI)
+#define RADIANS_TO_DEGREES(rad)   ((rad) * 180. / M_PI)
+#define RADIANS_TO_HOURS(rad)     ((rad) * 12. / M_PI)
 
-WeatherLocation *weather_location_new (const gchar *untrans_name, const gchar *trans_name, const gchar *code, const gchar *zone, const gchar *radar)
+/*
+ * Convert string of the form "DD-MM-SSH" to radians
+ * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
+ * Return value is positive for N,E; negative for S,W.
+ */
+gdouble dmsh2rad (const gchar *latlon)
+{
+    char *p1, *p2;
+    int deg, min, sec, dir;
+    gdouble value;
+    
+    if (latlon == NULL)
+	return DBL_MAX;
+    p1 = strchr(latlon, '-');
+    p2 = strrchr(latlon, '-');
+    if (p1 == NULL || p1 == latlon) {
+        return DBL_MAX;
+    } else if (p1 == p2) {
+	sscanf (latlon, "%u-%u", &deg, &min);
+	sec = 0;
+    } else if (p2 == 1 + p1) {
+	return DBL_MAX;
+    } else {
+	sscanf (latlon, "%u-%u-%u", &deg, &min, &sec);
+    }
+    if (deg > 180 || min >= 60 || sec >= 60)
+	return DBL_MAX;
+    value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI / 648000.;
+
+    dir = toupper(latlon[strlen(latlon) - 1]);
+    if (dir == 'W' || dir == 'S')
+	value = -value;
+    else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
+	value = DBL_MAX;
+    return value;
+}
+
+WeatherLocation *weather_location_new (const gchar *untrans_name, const gchar *trans_name, const gchar *code,
+				       const gchar *zone, const gchar *radar, const gchar *coordinates)
 {
     WeatherLocation *location;
 
@@ -102,13 +145,25 @@
         location->zone_valid = TRUE;
     }
 
+    char lat[12], lon[12];
+    if (coordinates && sscanf(coordinates, "%s %s", lat, lon) == 2) {
+        location->coordinates = g_strdup(coordinates);
+        location->latitude = dmsh2rad (lat);
+	location->longitude = dmsh2rad (lon);
+    } else {
+        location->coordinates = g_strdup("---");
+        location->latitude = DBL_MAX;
+        location->longitude = DBL_MAX;
+    }
+    location->latlon_valid = (location->latitude < DBL_MAX && location->longitude < DBL_MAX);
+    
     return location;
 }
 
 WeatherLocation *weather_location_config_read (PanelApplet *applet)
 {
     WeatherLocation *location;
-    gchar *untrans_name, *trans_name, *code, *zone, *radar;
+    gchar *untrans_name, *trans_name, *code, *zone, *radar, *coordinates;
     
     untrans_name = panel_applet_gconf_get_string(applet, "location0", NULL);
     if (!untrans_name) {
@@ -162,6 +217,7 @@
         g_free (zone);
 		zone = g_strdup ("PAZ021");
     }
+
     radar = panel_applet_gconf_get_string(applet, "location3", NULL);
     if (!radar) {
         if (g_strstr_len("DEFAULT_RADAR", 13, N_("DEFAULT_RADAR")) == NULL) {
@@ -178,13 +234,22 @@
         radar = g_strdup ("pit");
     }
 
-    location = weather_location_new(untrans_name, trans_name, code, zone, radar);
+    coordinates = panel_applet_gconf_get_string(applet, "coordinates", NULL);
+    if (coordinates && g_strstr_len ("DEFAULT_COORDINATES", 19, coordinates) ) {
+        g_free (coordinates);
+	coordinates = NULL;
+    }
+    
+    
+    location = weather_location_new(untrans_name, trans_name, code, zone, radar, coordinates);
+    
     g_free (untrans_name);
     g_free (trans_name);
     g_free (code);
     g_free (zone);
     g_free (radar);
-
+    g_free (coordinates);
+    
     return location;
 }
 
@@ -193,7 +258,11 @@
     WeatherLocation *clone;
 
     clone = weather_location_new (location->untrans_name, location->trans_name, 
-                                                   location->code, location->zone, location->radar);
+				  location->code, location->zone,
+				  location->radar, location->coordinates);
+    clone->latitude = location->latitude;
+    clone->longitude = location->longitude;
+    clone->latlon_valid = location->latlon_valid;
     return clone;
 }
 
@@ -345,7 +414,8 @@
     	return;
 
     gnome_vfs_async_close(handle, close_cb, info->applet);
-    
+
+    info->sunValid = info->valid && calc_sun(info);
     return;
 }
 
@@ -427,100 +497,38 @@
     regcomp(&metar_re[COND_RE], COND_RE_STR, REG_EXTENDED);
 }
 
-static inline gint days_in_month (gint month, gint year)
+/* Return time of weather report as secs since epoch UTC */
+static time_t make_time (gint utcDate, gint utcHour, gint utcMin)
 {
-    if (month == 1)
-        return ((year % 4) == 0) ? 29 : 28;
-    else if (((month <= 6) && (month % 2 == 0)) || ((month >=7) && (month % 2 != 0)))
-        return 31;
-    else
-        return 30;
-}
+    const time_t now = time(NULL);
+    struct tm tm;
 
-/* FIX - there *must* be a simpler, less stupid way to do this!... */
-time_t make_time (gint date, gint hour, gint min)
-{
-    struct tm *tm;
-    struct tm tms;
-    time_t now;
-    gint loc_mday, loc_hour, gm_mday, gm_hour;
-    gint hour_diff;  /* local time = UTC - hour_diff */
-    gint is_dst;
-
-    now = time(NULL);
-
-    tm = gmtime(&now);
-    gm_mday = tm->tm_mday;
-    gm_hour = tm->tm_hour;
-    memcpy(&tms, tm, sizeof(struct tm));
-
-    tm = localtime(&now);
-    loc_mday = tm->tm_mday;
-    loc_hour = tm->tm_hour;
-    is_dst = tm->tm_isdst;
-
-    /* Estimate timezone */
-    if (gm_mday == loc_mday)
-        hour_diff = gm_hour - loc_hour;
-    else
-        if ((gm_mday == loc_mday + 1) || ((gm_mday == 1) && (loc_mday >= 27)))
-            hour_diff = gm_hour + (24 - loc_hour);
-        else
-            hour_diff = -((24 - gm_hour) + loc_hour);
-
-    /* Make time */
-    tms.tm_min  = min;
-    tms.tm_sec  = 0;
-    tms.tm_hour = hour - hour_diff;
-    tms.tm_mday = date;
-    tms.tm_isdst = is_dst;
-    if (tms.tm_hour < 0) {
-        tms.tm_hour += 24;
-        --tms.tm_mday;
-        if (tms.tm_mday < 1) {
-            --tms.tm_mon;
-            if (tms.tm_mon < 0) {
-                tms.tm_mon = 11;
-                --tms.tm_year;
-            }
-            tms.tm_mday = days_in_month(tms.tm_mon, tms.tm_year + 1900);
-        }
-    } else if (tms.tm_hour > 23) {
-        tms.tm_hour -= 24;
-        ++tms.tm_mday;
-        if (tms.tm_mday > days_in_month(tms.tm_mon, tms.tm_year + 1900)) {
-            ++tms.tm_mon;
-            if (tms.tm_mon > 11) {
-                tms.tm_mon = 0;
-                ++tms.tm_year;
-            }
-            tms.tm_mday = 1;
-        }
+    gmtime_r (&now, &tm);
+
+    /* If last reading took place just before midnight UTC on the first, adjust the
+     * date downward.  This ASSUMES that the reading won't be more than 24 hrs old! */
+    if (utcDate > tm.tm_mday) {
+        tm.tm_mday--;
+    } else {
+        tm.tm_mday = utcDate;
     }
+    tm.tm_hour = utcHour;
+    tm.tm_min  = utcMin;
+    tm.tm_sec  = 0;
 
-    return mktime(&tms);
+    /* mktime() assumes value is local, not UTC.  Use tm_gmtoff to compensate */
+   return tm.tm_gmtoff + mktime(&tm);
 }
 
 static gboolean metar_tok_time (gchar *tokp, WeatherInfo *info)
 {
-    gchar sday[3], shr[3], smin[3];
     gint day, hr, min;
 
     if (regexec(&metar_re[TIME_RE], tokp, 0, NULL, 0) == REG_NOMATCH)
         return FALSE;
 
-    strncpy(sday, tokp, 2);
-    sday[2] = 0;
-    day = atoi(sday);
-
-    strncpy(shr, tokp+2, 2);
-    shr[2] = 0;
-    hr = atoi(shr);
-
-    strncpy(smin, tokp+4, 2);
-    smin[2] = 0;
-    min = atoi(smin);
-
+    sscanf(tokp, "%2u%2u%2u", &day, &hr, &min);
+    
     info->update = make_time(day, hr, min);
 
     return TRUE;
@@ -780,6 +788,198 @@
 }
 
 
+/*
+ * Formulas from:
+ * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
+ * Cambridge University Press 1988
+ *
+ * Planetary Mean Orbit parameters from http://ssd.jpl.nasa.gov/elem_planets.html,
+ * converting longitudes from heliocentric to geocentric coordinates
+ * epoch J2000 (2000 Jan 1 12:00:00 UTC)
+ */
+
+#define EPOCH_TO_J2000(t)       (t-946728000)
+#define MEAN_ECLIPTIC_LONGITUDE 280.46435
+#define PERIGEE_LONGITUDE       282.94719
+#define ECCENTRICITY            0.01671002
+#define MEAN_ECLIPTIC_OBLIQUITY 
+#define SOL_PROGRESSION         (360./365.242191)
+
+/*
+ * Convert ecliptic longitude (radians) to equitorial coordinates,
+ * expressed as right ascension (hours) and declination (radians)
+ * Assume ecliptic latitude is 0.0
+ */
+static void ecl2equ (gdouble time, gdouble eclipLon,
+		     gdouble *ra, gdouble *decl)
+{
+    gdouble jc = EPOCH_TO_J2000(time) / (36525. * 86400.);
+    gdouble mEclipObliq = DEGREES_TO_RADIANS(23.439291667
+					     - .013004166 * jc
+					     - 1.666667e-7 * jc * jc
+					     + 5.027777e-7 * jc * jc * jc);
+    *ra = RADIANS_TO_HOURS(atan2 ( sin(eclipLon) * cos(mEclipObliq), cos(eclipLon)));
+    if (*ra < 0.)
+        *ra += 24.;
+    *decl = asin ( sin(mEclipObliq) * sin(eclipLon) );
+}
+
+/*
+ * Calculate rising and setting times of an object
+ * based on it equitorial coordinates
+ */
+static void gstObsv (gdouble ra, gdouble decl,
+		     gdouble obsLat, gdouble obsLon,
+		     gdouble *rise, gdouble *set)
+{
+    double a = acos(-tan(obsLat) * tan(decl));
+    double b;
+
+    if (isnan(a)) {
+	*set = *rise = a;
+	return;
+    }
+    a = RADIANS_TO_HOURS(a);
+    b = 24. - a + ra;
+    a += ra;
+    a -= RADIANS_TO_HOURS(obsLon);
+    b -= RADIANS_TO_HOURS(obsLon);
+    if ((a = fmod(a, 24.)) < 0)
+      a += 24.;
+    if ((b = fmod(b, 24.)) < 0)
+      b += 24.;
+
+    *set = a;
+    *rise = b;
+}
+
+
+static gdouble t0(time_t date)
+{
+    register gdouble t = ((gdouble)(EPOCH_TO_J2000(date) / 86400)) / 36525.0;
+    gdouble t0 = fmod( 6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
+    if (t0 < 0.)
+        t0 += 24.;
+    return t0;
+}
+
+
+
+gboolean sun (time_t t, gdouble obsLat, gdouble obsLon,
+	  time_t *rise, time_t *set)
+{
+    time_t gm_midn;
+    time_t lcl_midn;
+    gdouble gm_hoff;
+    
+    /* Approximate preceding local midnight at observer's longitude */
+    gm_midn = t - (t % 86400);
+    gm_hoff = floor((RADIANS_TO_DEGREES(obsLon) + 7.5) / 15.);
+    lcl_midn = gm_midn - 3600. * gm_hoff;
+    if (t - lcl_midn >= 86400)
+        lcl_midn += 86400;
+    else if (lcl_midn > t)
+        lcl_midn -= 86400;
+    
+    /* 
+     * Ecliptic longitude of the sun at midnight local time
+     * Start with an estimate based on a fixed daily rate
+     */
+    gdouble ndays = EPOCH_TO_J2000(lcl_midn) / 86400.;
+    gdouble meanAnom = DEGREES_TO_RADIANS(ndays * SOL_PROGRESSION
+					  + MEAN_ECLIPTIC_LONGITUDE - PERIGEE_LONGITUDE);
+    
+    /*
+     * Approximate solution of Kepler's equation:
+     * Find E which satisfies  E - e sin(E) = M (mean anomaly)
+     */
+    gdouble eccenAnom = meanAnom;
+    gdouble delta;
+    gdouble lambda;
+    
+    while (1e-12 < fabs( delta = eccenAnom - ECCENTRICITY * sin(eccenAnom) - meanAnom))
+    {
+	eccenAnom -= delta / (1.- ECCENTRICITY * cos(eccenAnom));
+    }
+
+    /* Sun's longitude on the ecliptic */
+    lambda = fmod( DEGREES_TO_RADIANS ( PERIGEE_LONGITUDE )
+		   + 2. * atan( sqrt((1.+ECCENTRICITY)/(1.-ECCENTRICITY))
+				* tan ( eccenAnom / 2. ) ),
+		   2. * M_PI);
+    
+    /* Calculate equitorial coordinates of sun at previous and next local midnights */
+
+    gdouble ra1, ra2, decl1, decl2;
+    
+    ecl2equ (lcl_midn, lambda, &ra1, &decl1);
+    ecl2equ (lcl_midn + 86400., lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION), &ra2, &decl2);
+    
+    /* Convert to rise and set times assuming the earth were to stay in its position
+     * in its orbit around the sun.  This will soon be followed by interpolating
+     * between the two
+     */
+
+    gdouble rise1, rise2, set1, set2;
+    gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise1, &set1);
+    gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise2, &set2);
+    
+    /* TODO: include calculations for regions near the poles. */
+    if (isnan(rise1) || isnan(rise2))
+        return FALSE;
+
+    gdouble tt = t0(lcl_midn);
+    gdouble t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)) * 1.002737909;
+
+    if (t00 < 0.)
+	t00 += 24.;
+
+    if (rise1 < t00) {
+        rise1 += 24.;
+        rise2 += 24.;
+    }
+    if (set1 < t00) {
+        set1  += 24.;
+        set2  += 24.;
+    }
+    
+    /*
+     * Interpolate between the two
+     */
+    rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
+    set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
+
+    decl2 = (decl1 + decl2) / 2.;
+    gdouble x = DEGREES_TO_RADIANS(0.830725);
+    gdouble u = acos ( sin(obsLat) / cos(decl2) );
+    gdouble dt =  RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) )
+				     / cos(decl2) );
+    
+    rise1 = (rise1 - dt - tt) * 0.9972695661;
+    set1  = (set1 + dt - tt) * 0.9972695661;
+    if (rise1 < 0.)
+      rise1 += 24;
+    else if (rise1 >= 24.)
+      rise1 -= 24.;
+    if (set1 < 0.)
+      set1 += 24;
+    else if (set1 >= 24.)
+      set1 -= 24.;
+    
+    *rise = (rise1 * 3600.) + lcl_midn;
+    *set = (set1 * 3600.) + lcl_midn;
+    return TRUE;
+}
+
+
+static gboolean calc_sun (WeatherInfo *info)
+{
+  return info->location->latlon_valid
+    && sun(info->update,
+	   info->location->latitude, info->location->longitude,
+	   &info->sunrise, &info->sunset);
+}
+
 static gboolean metar_tok_temp (gchar *tokp, WeatherInfo *info)
 {
     gchar *ptemp, *pdew, *psep;
@@ -1250,7 +1450,7 @@
         info->forecast = formatWeatherMsg(g_strdup (info->iwin_buffer));
     }
     else if (result != GNOME_VFS_OK) {
-	 g_print("%s", gnome_vfs_result_to_string(result));
+	g_print("%s", gnome_vfs_result_to_string(result));
         g_warning("Failed to get IWIN data.\n");
     } else {
         gnome_vfs_async_read(handle, body, DATA_SIZE - 1, iwin_finish_read, gw_applet);
@@ -1874,13 +2074,14 @@
     	info->location = weather_location_clone(location);
     } else {
         location = info->location;
-	    if (info->forecast)
-	    	g_free (info->forecast);
-	    info->forecast = NULL;
-		if (info->radar != NULL) {
-			gdk_pixmap_unref (info->radar);
-			info->radar = NULL;
-		}
+	if (info->forecast)
+	    g_free (info->forecast);
+
+	info->forecast = NULL;
+	if (info->radar != NULL) {
+	    gdk_pixmap_unref (info->radar);
+	    info->radar = NULL;
+	}
     }
 
     /* Update in progress */
@@ -1902,6 +2103,9 @@
     info->windspeed = -1;
     info->pressure = -1.0;
     info->visibility = -1.0;
+    info->sunValid = FALSE;
+    info->sunrise = 0;
+    info->sunset = 0;
     info->forecast = NULL;
     info->radar = NULL;
     info->radar_url = NULL;
@@ -1982,6 +2186,9 @@
     info->windspeed = -1;
     info->pressure = -1.0;
     info->visibility = -1.0;
+    info->sunValid = FALSE;
+    info->sunrise = 0;
+    info->sunset = 0;
     info->forecast = g_strdup ("None");
     info->radar = NULL;  /* FIX */
     info->requests_pending = FALSE;
@@ -2109,9 +2316,9 @@
         return "-";
 
     if (info->update != 0) {
-        struct tm *tm;
-        tm = localtime(&info->update);
-        if (strftime(buf, sizeof(buf), _("%a, %b %d / %H:%M"), tm) <= 0)
+        struct tm tm;
+        localtime_r(&info->update, &tm);
+        if (strftime(buf, sizeof(buf), _("%a, %b %d / %H:%M"), &tm) <= 0)
 		strcpy (buf, "???");
 	buf[sizeof(buf)-1] = '\0';
     } else {
@@ -2383,6 +2590,46 @@
     return buf;
 }
 
+const gchar *weather_info_get_sunrise (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+    
+    g_return_val_if_fail(info && info->location, NULL);
+    
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r(&info->sunrise, &tm);
+    if (strftime(buf, sizeof(buf), _("%H:%M"), &tm) <= 0)
+        return "-";
+    return buf;
+}
+
+const gchar *weather_info_get_sunset (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+    
+    g_return_val_if_fail(info && info->location, NULL);
+    
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r(&info->sunset, &tm);
+    if (strftime(buf, sizeof(buf), _("%H:%M"), &tm) <= 0)
+        return "-";
+    return buf;
+}
+
 const gchar *weather_info_get_forecast (WeatherInfo *info)
 {
     g_return_val_if_fail(info != NULL, NULL);
@@ -2430,8 +2677,10 @@
 #define PIX_TSTORM    5
 #define PIX_SNOW      6
 #define PIX_FOG       7
+#define PIX_MOON      8
+#define PIX_MOONCLOUD 9
 
-#define NUM_PIX       8
+#define NUM_PIX      10
 
 #if 0
 static void
@@ -2454,7 +2703,20 @@
 {
     static gboolean initialized = FALSE;
     GtkIconTheme *icon_theme;
-
+    static char *icons[NUM_PIX] = {
+      "stock_unknown",
+      "stock_weather-sunny",
+      "stock_weather-few-clouds",
+      "stock_weather-cloudy",
+      "stock_weather-showers",
+      "stock_weather-storm",
+      "stock_weahter-snow",
+      "stock_weather-fog",
+      "stock_weather-moon",
+      "stock_weather-few-clouds-night"
+    };
+    int idx;
+    
     if (initialized)
        return;
     initialized = TRUE;
@@ -2462,24 +2724,12 @@
     icon_theme = gtk_icon_theme_get_default ();
 
     weather_pixbufs_mini = g_new(GdkPixbuf *, NUM_PIX);
-    weather_pixbufs_mini[PIX_UNKNOWN] = gtk_icon_theme_load_icon (icon_theme, "stock_unknown", 16, 0, NULL);
-    weather_pixbufs_mini[PIX_SUN] = gtk_icon_theme_load_icon (icon_theme, "stock_weather-sunny", 16, 0, NULL);
-    weather_pixbufs_mini[PIX_SUNCLOUD] = gtk_icon_theme_load_icon (icon_theme, "stock_weather-few-clouds", 16, 0, NULL);
-    weather_pixbufs_mini[PIX_CLOUD] = gtk_icon_theme_load_icon (icon_theme, "stock_weather-cloudy", 16, 0, NULL);
-    weather_pixbufs_mini[PIX_RAIN] = gtk_icon_theme_load_icon (icon_theme, "stock_weather-showers", 16, 0, NULL);
-    weather_pixbufs_mini[PIX_TSTORM] = gtk_icon_theme_load_icon (icon_theme, "stock_weather-storm", 16, 0, NULL);
-    weather_pixbufs_mini[PIX_SNOW] = gtk_icon_theme_load_icon (icon_theme, "stock_weather-snow", 16, 0, NULL);
-    weather_pixbufs_mini[PIX_FOG] = gtk_icon_theme_load_icon (icon_theme, "stock_weather-fog", 16, 0, NULL);
-
     weather_pixbufs = g_new(GdkPixbuf *, NUM_PIX);
-    weather_pixbufs[PIX_UNKNOWN] = gtk_icon_theme_load_icon (icon_theme, "stock_unknown", 48, 0, NULL);
-    weather_pixbufs[PIX_SUN] = gtk_icon_theme_load_icon (icon_theme, "stock_weather-sunny", 48, 0, NULL);
-    weather_pixbufs[PIX_SUNCLOUD] = gtk_icon_theme_load_icon (icon_theme, "stock_weather-few-clouds", 48, 0, NULL);
-    weather_pixbufs[PIX_CLOUD] = gtk_icon_theme_load_icon (icon_theme, "stock_weather-cloudy", 48, 0, NULL);
-    weather_pixbufs[PIX_RAIN] = gtk_icon_theme_load_icon (icon_theme, "stock_weather-showers", 48, 0, NULL);
-    weather_pixbufs[PIX_TSTORM] = gtk_icon_theme_load_icon (icon_theme, "stock_weather-storm", 48, 0, NULL);
-    weather_pixbufs[PIX_SNOW] = gtk_icon_theme_load_icon (icon_theme, "stock_weather-snow", 48, 0, NULL);
-    weather_pixbufs[PIX_FOG] = gtk_icon_theme_load_icon (icon_theme, "stock_weather-fog", 48, 0, NULL);
+
+    for (idx = 0; idx < NUM_PIX; idx++) {
+        weather_pixbufs_mini[idx] = gtk_icon_theme_load_icon (icon_theme, icons[idx], 16, 0, NULL);
+        weather_pixbufs[idx] = gtk_icon_theme_load_icon (icon_theme, icons[idx], 48, 0, NULL);
+    }
 }
 
 void _weather_info_get_pixbuf (WeatherInfo *info, gboolean mini, GdkPixbuf **pixbuf)
@@ -2567,14 +2817,16 @@
 	            idx = PIX_UNKNOWN;
                 }
         } else {
+	    gboolean useSun = (! info->sunValid )
+	                      || (info->update >= info->sunrise && info->update < info->sunset);
             switch (sky) {
             case SKY_CLEAR:
-                idx = PIX_SUN;
+	        idx = useSun ? PIX_SUN : PIX_MOON;
                 break;
             case SKY_BROKEN:
             case SKY_SCATTERED:
             case SKY_FEW:
-                idx = PIX_SUNCLOUD;
+	        idx = useSun ? PIX_SUNCLOUD : PIX_MOONCLOUD;
                 break;
             case SKY_OVERCAST:
                 idx = PIX_CLOUD;
Index: weather.h
===================================================================
RCS file: /cvs/gnome/gnome-applets/gweather/weather.h,v
retrieving revision 1.25
diff -u -r1.25 weather.h
--- weather.h	26 Jun 2004 12:18:43 -0000	1.25
+++ weather.h	22 Nov 2004 05:16:29 -0000
@@ -34,11 +34,16 @@
     gchar *zone;
     gchar *radar;
     gboolean zone_valid;
+    gchar *coordinates;
+    gdouble  latitude;
+    gdouble  longitude;
+    gboolean latlon_valid;
 };
 
 
 
-extern WeatherLocation *weather_location_new (const gchar *untrans_name, const gchar *trans_name, const gchar *code, const gchar *zone, const gchar *radar);
+extern WeatherLocation *weather_location_new (const gchar *untrans_name, const gchar *trans_name, const gchar *code,
+					      const gchar *zone, const gchar *radar, const gchar *coordinates);
 extern WeatherLocation *weather_location_clone (const WeatherLocation *location);
 extern void weather_location_free (WeatherLocation *location);
 extern gboolean weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2);
@@ -163,6 +168,7 @@
 
 struct _WeatherInfo {
     gboolean valid;
+    gboolean sunValid;
     WeatherLocation *location;
     WeatherUpdate update;
     WeatherSky sky;
@@ -173,6 +179,8 @@
     WeatherWindSpeed windspeed;
     WeatherPressure pressure;
     WeatherVisibility visibility;
+    WeatherUpdate sunrise;
+    WeatherUpdate sunset;
     gchar *forecast;
     gchar *metar_buffer;
     gchar *iwin_buffer;
@@ -219,6 +227,8 @@
 extern const gchar *weather_info_get_pressure (WeatherInfo *info);
 extern const gchar *weather_info_get_visibility (WeatherInfo *info);
 extern const gchar *weather_info_get_apparent (WeatherInfo *info);
+extern const gchar *weather_info_get_sunrise(WeatherInfo *info);
+extern const gchar *weather_info_get_sunset(WeatherInfo *info);
 extern const gchar *weather_info_get_forecast (WeatherInfo *info);
 extern GdkPixmap *weather_info_get_radar (WeatherInfo *info);
 
@@ -227,7 +237,6 @@
 
 extern void update_finish (WeatherInfo *info);
 
-extern time_t make_time (gint date, gint hour, gint min);
 
 extern void _weather_info_get_pixbuf (WeatherInfo *info, gboolean mini, GdkPixbuf **pixbuf);
 #define weather_info_get_pixbuf_mini(info,pixbuf) _weather_info_get_pixbuf((info), TRUE, (pixbuf))
