summaryrefslogtreecommitdiff
path: root/libmateweather
diff options
context:
space:
mode:
authorPerberos <[email protected]>2011-12-01 21:42:39 -0300
committerPerberos <[email protected]>2011-12-01 21:42:39 -0300
commitfe8aea1c3b5348347633da18a02b0bffd3b266a1 (patch)
tree9881bf77df7572844707cc7c50bd8ca6b5a97076 /libmateweather
downloadlibmateweather-fe8aea1c3b5348347633da18a02b0bffd3b266a1.tar.bz2
libmateweather-fe8aea1c3b5348347633da18a02b0bffd3b266a1.tar.xz
moving from https://github.com/perberos/mate-desktop-environment
Diffstat (limited to 'libmateweather')
-rw-r--r--libmateweather/AUTHORS5
-rw-r--r--libmateweather/Makefile.am152
-rw-r--r--libmateweather/Makefile.in1121
-rw-r--r--libmateweather/README7
-rw-r--r--libmateweather/location-entry.c591
-rw-r--r--libmateweather/location-entry.h61
-rw-r--r--libmateweather/mateweather-enum-types.c29
-rw-r--r--libmateweather/mateweather-enum-types.h23
-rw-r--r--libmateweather/mateweather-location.c814
-rw-r--r--libmateweather/mateweather-location.h89
-rw-r--r--libmateweather/mateweather-mateconf.c310
-rw-r--r--libmateweather/mateweather-mateconf.h84
-rw-r--r--libmateweather/mateweather-prefs.c395
-rw-r--r--libmateweather/mateweather-prefs.h76
-rw-r--r--libmateweather/mateweather-timezone.c405
-rw-r--r--libmateweather/mateweather-timezone.h54
-rw-r--r--libmateweather/mateweather-uninstalled.pc.in13
-rw-r--r--libmateweather/mateweather-win32.c100
-rw-r--r--libmateweather/mateweather-win32.h43
-rw-r--r--libmateweather/mateweather-xml.c165
-rw-r--r--libmateweather/mateweather-xml.h37
-rw-r--r--libmateweather/mateweather.pc.in14
-rw-r--r--libmateweather/mateweather.schemas.in173
-rw-r--r--libmateweather/parser.c263
-rw-r--r--libmateweather/parser.h43
-rw-r--r--libmateweather/test_locations.c65
-rw-r--r--libmateweather/test_metar.c74
-rw-r--r--libmateweather/test_sun_moon.c90
-rw-r--r--libmateweather/timezone-menu.c415
-rw-r--r--libmateweather/timezone-menu.h54
-rw-r--r--libmateweather/weather-bom.c82
-rw-r--r--libmateweather/weather-iwin.c475
-rw-r--r--libmateweather/weather-met.c179
-rw-r--r--libmateweather/weather-metar.c559
-rw-r--r--libmateweather/weather-moon.c198
-rw-r--r--libmateweather/weather-priv.h195
-rw-r--r--libmateweather/weather-sun.c353
-rw-r--r--libmateweather/weather-wx.c107
-rw-r--r--libmateweather/weather.c1651
-rw-r--r--libmateweather/weather.h288
40 files changed, 9852 insertions, 0 deletions
diff --git a/libmateweather/AUTHORS b/libmateweather/AUTHORS
new file mode 100644
index 0000000..30a8eee
--- /dev/null
+++ b/libmateweather/AUTHORS
@@ -0,0 +1,5 @@
+The library:
+Philip Langdale <[email protected]>
+
+Almost all of the code is refactored from the mateweather applet,
+so checkout that AUTHORS file too.
diff --git a/libmateweather/Makefile.am b/libmateweather/Makefile.am
new file mode 100644
index 0000000..8502708
--- /dev/null
+++ b/libmateweather/Makefile.am
@@ -0,0 +1,152 @@
+lib_LTLIBRARIES = libmateweather.la
+
+libmateweatherincdir = $(includedir)/libmateweather
+mateweather_old_headers = \
+ weather.h mateweather-mateconf.h mateweather-prefs.h mateweather-xml.h
+mateweather_new_headers = \
+ mateweather-location.h location-entry.h \
+ mateweather-timezone.h timezone-menu.h
+libmateweatherinc_HEADERS = \
+ $(mateweather_old_headers) \
+ $(mateweather_new_headers) \
+ mateweather-enum-types.h
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = mateweather.pc
+
+libmateweather_la_SOURCES = \
+ weather.c weather.h weather-priv.h \
+ weather-metar.c weather-iwin.c weather-met.c \
+ weather-bom.c weather-wx.c \
+ weather-sun.c weather-moon.c \
+ mateweather-enum-types.c \
+ mateweather-prefs.c mateweather-prefs.h \
+ mateweather-mateconf.c mateweather-mateconf.h \
+ mateweather-xml.c mateweather-xml.h \
+ mateweather-location.c mateweather-location.h \
+ mateweather-timezone.c mateweather-timezone.h \
+ mateweather-win32.h \
+ location-entry.c location-entry.h \
+ timezone-menu.c timezone-menu.h \
+ parser.c parser.h
+
+if OS_WIN32
+libmateweather_la_SOURCES += mateweather-win32.c
+else
+EXTRA_libmateweather_la_SOURCES = mateweather-win32.c
+endif
+
+libmateweather_la_CFLAGS = \
+ -I$(top_srcdir) \
+ -I$(srcdir) \
+ $(WARN_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(LIBXML_CFLAGS) \
+ $(LIBSOUP_CFLAGS) \
+ $(MATECONF_CFLAGS) \
+ -DG_LOG_DOMAIN=\"MateWeather\" \
+ -DMATELOCALEDIR=\""$(datadir)/locale"\" \
+ -DMATEWEATHER_XML_LOCATION_DIR=\""$(pkgdatadir)"\"
+
+libmateweather_la_LIBADD = \
+ -lm \
+ $(GTK_LIBS) \
+ $(LIBXML_LIBS) \
+ $(LIBSOUP_LIBS) \
+ $(MATECONF_LIBS) \
+ $(REGEX_LIBS)
+
+libmateweather_la_LDFLAGS = \
+ -version-info $(LT_VERSION) -no-undefined
+
+# something is wrong with glib-mkenums, please research the issue
+MKENUMS_GENERATED = mateweather-enum-types.c mateweather-enum-types.h
+
+mateweather-enum-types.h: $(mateweather_new_headers)
+# $(AM_V_GEN)( cd $(srcdir) && $(GLIB_MKENUMS) --template mateweather-enum-types.h.tmpl \
+# $(mateweather_new_headers) ) > mateweather-enum-types.h.tmp \
+# && mv mateweather-enum-types.h.tmp mateweather-enum-types.h \
+# || rm -f mateweather-enum-type.h.tmp
+
+mateweather-enum-types.c: $(libmateweatherinclude_HEADERS)
+# $(AM_V_GEN)( cd $(srcdir) && $(GLIB_MKENUMS) --template mateweather-enum-types.c.tmpl \
+# $(mateweather_new_headers) ) > mateweather-enum-types.c.tmp \
+# && mv mateweather-enum-types.c.tmp mateweather-enum-types.c \
+# || rm -f mateweather-enum-type.c.tmp
+
+BUILT_SOURCES = $(MKENUMS_GENERATED)
+
+test_metar_SOURCES = test_metar.c
+
+test_metar_CFLAGS = \
+ -I$(top_srcdir) \
+ -I$(srcdir) \
+ $(WARN_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(LIBSOUP_CFLAGS) \
+ -DG_LOG_DOMAIN=\"MateWeather\"
+
+test_metar_LDADD = \
+ $(GTK_LIBS) \
+ $(LIBSOUP_LIBS) \
+ $(REGEX_LIBS) \
+ libmateweather.la
+
+test_locations_SOURCES = test_locations.c
+
+test_locations_CFLAGS = \
+ -I$(top_srcdir) \
+ -I$(srcdir) \
+ $(WARN_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(MATE_VFS_APPLETS_CFLAGS) \
+ -DG_LOG_DOMAIN=\"MateWeather\"
+
+test_locations_LDADD = libmateweather.la $(GTK_LIBS)
+
+test_sun_moon_SOURCES = \
+ test_sun_moon.c
+
+test_sun_moon_CFLAGS = \
+ -I$(top_srcdir) \
+ -I$(srcdir) \
+ $(WARN_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(LIBSOUP_CFLAGS) \
+ -DG_LOG_DOMAIN=\"MateWeather\"
+
+test_sun_moon_LDADD = \
+ $(GTK_LIBS) \
+ $(LIBSOUP_LIBS) \
+ libmateweather.la
+
+noinst_HEADERS = weather-priv.h mateweather-win32.h
+noinst_PROGRAMS = test_metar test_locations test_sun_moon
+
+schemadir = @[email protected]
+schema_in_files = mateweather.schemas.in
+schema_DATA = $(schema_in_files:.schemas.in=.schemas)
+
+
+if MATECONF_SCHEMAS_INSTALL
+install-data-local:
+ if test -z "$(DESTDIR)" ; then \
+ for p in $(schema_DATA) ; do \
+ MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-install-rule $$p ; \
+ done \
+ fi
+uninstall-local:
+ for p in $(schema_DATA) ; do \
+ MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-uninstall-rule $$p ; \
+ done
+endif
+
+EXTRA_DIST = mateweather.pc.in mateweather-uninstalled.pc.in $(schema_in_files)
+
+EXTRA_PROGRAMS = test_metar test_sun_moon
+
+CLEANFILES = $(schema_DATA) $(EXTRA_PROGRAMS)
+#$(MKENUMS_GENERATED)
+
+-include $(top_srcdir)/git.mk
diff --git a/libmateweather/Makefile.in b/libmateweather/Makefile.in
new file mode 100644
index 0000000..ccf5677
--- /dev/null
+++ b/libmateweather/Makefile.in
@@ -0,0 +1,1121 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+
+
+pkgdatadir = $(datadir)/@[email protected]
+pkgincludedir = $(includedir)/@[email protected]
+pkglibdir = $(libdir)/@[email protected]
+pkglibexecdir = $(libexecdir)/@[email protected]
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @[email protected]
+host_triplet = @[email protected]
[email protected][email protected]__append_1 = mateweather-win32.c
+noinst_PROGRAMS = test_metar$(EXEEXT) test_locations$(EXEEXT) \
+ test_sun_moon$(EXEEXT)
+EXTRA_PROGRAMS = test_metar$(EXEEXT) test_sun_moon$(EXEEXT)
+subdir = libmateweather
+DIST_COMMON = README $(libmateweatherinc_HEADERS) $(noinst_HEADERS) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/mateweather-uninstalled.pc.in \
+ $(srcdir)/mateweather.pc.in AUTHORS
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gtk-doc.m4 \
+ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = mateweather.pc mateweather-uninstalled.pc
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" \
+ "$(DESTDIR)$(schemadir)" "$(DESTDIR)$(libmateweatherincdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libmateweather_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am__libmateweather_la_SOURCES_DIST = weather.c weather.h \
+ weather-priv.h weather-metar.c weather-iwin.c weather-met.c \
+ weather-bom.c weather-wx.c weather-sun.c weather-moon.c \
+ mateweather-enum-types.c mateweather-prefs.c \
+ mateweather-prefs.h mateweather-mateconf.c \
+ mateweather-mateconf.h mateweather-xml.c mateweather-xml.h \
+ mateweather-location.c mateweather-location.h \
+ mateweather-timezone.c mateweather-timezone.h \
+ mateweather-win32.h location-entry.c location-entry.h \
+ timezone-menu.c timezone-menu.h parser.c parser.h \
+ mateweather-win32.c
[email protected][email protected]__objects_1 = libmateweather_la-mateweather-win32.lo
+am_libmateweather_la_OBJECTS = libmateweather_la-weather.lo \
+ libmateweather_la-weather-metar.lo \
+ libmateweather_la-weather-iwin.lo \
+ libmateweather_la-weather-met.lo \
+ libmateweather_la-weather-bom.lo \
+ libmateweather_la-weather-wx.lo \
+ libmateweather_la-weather-sun.lo \
+ libmateweather_la-weather-moon.lo \
+ libmateweather_la-mateweather-enum-types.lo \
+ libmateweather_la-mateweather-prefs.lo \
+ libmateweather_la-mateweather-mateconf.lo \
+ libmateweather_la-mateweather-xml.lo \
+ libmateweather_la-mateweather-location.lo \
+ libmateweather_la-mateweather-timezone.lo \
+ libmateweather_la-location-entry.lo \
+ libmateweather_la-timezone-menu.lo libmateweather_la-parser.lo \
+ $(am__objects_1)
+am__EXTRA_libmateweather_la_SOURCES_DIST = mateweather-win32.c
+libmateweather_la_OBJECTS = $(am_libmateweather_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+libmateweather_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(libmateweather_la_CFLAGS) $(CFLAGS) \
+ $(libmateweather_la_LDFLAGS) $(LDFLAGS) -o [email protected]
+PROGRAMS = $(noinst_PROGRAMS)
+am_test_locations_OBJECTS = test_locations-test_locations.$(OBJEXT)
+test_locations_OBJECTS = $(am_test_locations_OBJECTS)
+test_locations_DEPENDENCIES = libmateweather.la $(am__DEPENDENCIES_1)
+test_locations_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(test_locations_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o \
+am_test_metar_OBJECTS = test_metar-test_metar.$(OBJEXT)
+test_metar_OBJECTS = $(am_test_metar_OBJECTS)
+test_metar_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) libmateweather.la
+test_metar_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(test_metar_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o [email protected]
+am_test_sun_moon_OBJECTS = test_sun_moon-test_sun_moon.$(OBJEXT)
+test_sun_moon_OBJECTS = $(am_test_sun_moon_OBJECTS)
+test_sun_moon_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) libmateweather.la
+test_sun_moon_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(test_sun_moon_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o [email protected]
+DEFAULT_INCLUDES = [email protected][email protected] -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " [email protected];
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o [email protected]
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " [email protected];
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " [email protected];
+SOURCES = $(libmateweather_la_SOURCES) \
+ $(EXTRA_libmateweather_la_SOURCES) $(test_locations_SOURCES) \
+ $(test_metar_SOURCES) $(test_sun_moon_SOURCES)
+DIST_SOURCES = $(am__libmateweather_la_SOURCES_DIST) \
+ $(am__EXTRA_libmateweather_la_SOURCES_DIST) \
+ $(test_locations_SOURCES) $(test_metar_SOURCES) \
+ $(test_sun_moon_SOURCES)
+DATA = $(pkgconfig_DATA) $(schema_DATA)
+HEADERS = $(libmateweatherinc_HEADERS) $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @[email protected]
+ACLOCAL_AMFLAGS = @[email protected]
+ALL_LINGUAS = @[email protected]
+AM_DEFAULT_VERBOSITY = @[email protected]
+AUTOCONF = @[email protected]
+AUTOHEADER = @[email protected]
+AUTOMAKE = @[email protected]
+CATALOGS = @[email protected]
+CATOBJEXT = @[email protected]
+CCDEPMODE = @[email protected]
+COMPRESS_EXT = @[email protected]
+CPPFLAGS = @[email protected]
+CYGPATH_W = @[email protected]
+DATADIR = @[email protected]
+DATADIRNAME = @[email protected]
+DISABLE_DEPRECATED = @[email protected]
+DLLTOOL = @[email protected]
+DSYMUTIL = @[email protected]
+DUMPBIN = @[email protected]
+GETTEXT_PACKAGE = @[email protected]
+GLADEDIR = @[email protected]
+GLIB_CFLAGS = @[email protected]
+GLIB_GENMARSHAL = @[email protected]
+GLIB_LIBS = @[email protected]
+GLIB_MKENUMS = @[email protected]
+GMOFILES = @[email protected]
+GMSGFMT = @[email protected]
+GOBJECT_QUERY = @[email protected]
+GTKDOC_CHECK = @[email protected]
+GTKDOC_MKPDF = @[email protected]
+GTKDOC_REBASE = @[email protected]
+GTK_CFLAGS = @[email protected]
+GTK_LIBS = @[email protected]
+HTML_DIR = @[email protected]
+INSTALL = @[email protected]
+INSTALL_DATA = @[email protected]
+INSTALL_PROGRAM = @[email protected]
+INSTALL_SCRIPT = @[email protected]
+INSTALL_STRIP_PROGRAM = @[email protected]
+INSTOBJEXT = @[email protected]
+INTLLIBS = @[email protected]
+INTLTOOL_EXTRACT = @[email protected]
+INTLTOOL_MERGE = @[email protected]
+INTLTOOL_PERL = @[email protected]
+INTLTOOL_UPDATE = @[email protected]
+LDFLAGS = @[email protected]
+LIBOBJS = @[email protected]
+LIBSOUP_CFLAGS = @[email protected]
+LIBSOUP_LIBS = @[email protected]
+LIBSOUP_MATE_CFLAGS = @[email protected]
+LIBSOUP_MATE_LIBS = @[email protected]
+LIBTOOL = @[email protected]
+LIBXML_CFLAGS = @[email protected]
+LIBXML_LIBS = @[email protected]
+LTLIBOBJS = @[email protected]
+LT_VERSION = @[email protected]
+MAKEINFO = @[email protected]
+MANIFEST_TOOL = @[email protected]
+MATECONFTOOL = @[email protected]
+MATECONF_CFLAGS = @[email protected]
+MATECONF_LIBS = @[email protected]
+MATECONF_SCHEMA_CONFIG_SOURCE = @[email protected]
+MATECONF_SCHEMA_FILE_DIR = @[email protected]
+MKDIR_P = @[email protected]
+MKINSTALLDIRS = @[email protected]
+MSGFMT_OPTS = @[email protected]
+MSGMERGE = @[email protected]
+OBJDUMP = @[email protected]
+OTOOL64 = @[email protected]
+PACKAGE = @[email protected]
+PACKAGE_BUGREPORT = @[email protected]
+PACKAGE_NAME = @[email protected]
+PACKAGE_STRING = @[email protected]
+PACKAGE_TARNAME = @[email protected]
+PACKAGE_URL = @[email protected]
+PACKAGE_VERSION = @[email protected]
+PATH_SEPARATOR = @[email protected]
+PKG_CONFIG = @[email protected]
+PKG_CONFIG_LIBDIR = @[email protected]
+PKG_CONFIG_PATH = @[email protected]
+POFILES = @[email protected]
+PO_IN_DATADIR_FALSE = @[email protected]
+PO_IN_DATADIR_TRUE = @[email protected]
+PYGOBJECT_CFLAGS = @[email protected]
+PYGOBJECT_LIBS = @[email protected]
+PYGTK_DEFS = @[email protected]
+PYTHONDIR = @[email protected]
+PYTHON_EXEC_PREFIX = @[email protected]
+PYTHON_INCLUDES = @[email protected]
+PYTHON_PLATFORM = @[email protected]
+PYTHON_PREFIX = @[email protected]
+PYTHON_VERSION = @[email protected]
+REGEX_LIBS = @[email protected]
+SET_MAKE = @[email protected]
+USE_NLS = @[email protected]
+VERSION = @[email protected]
+WARN_CFLAGS = @[email protected]
+XGETTEXT = @[email protected]
+abs_builddir = @[email protected]
+abs_srcdir = @[email protected]
+abs_top_builddir = @[email protected]
+abs_top_srcdir = @[email protected]
+ac_ct_AR = @[email protected]
+ac_ct_CC = @[email protected]
+ac_ct_DUMPBIN = @[email protected]
+am__include = @[email protected]
+am__leading_dot = @[email protected]
+am__quote = @[email protected]
+am__tar = @[email protected]
+am__untar = @[email protected]
+build_alias = @[email protected]
+build_cpu = @[email protected]
+build_os = @[email protected]
+build_vendor = @[email protected]
+builddir = @[email protected]
+datadir = @[email protected]
+datarootdir = @[email protected]
+exec_prefix = @[email protected]
+host_alias = @[email protected]
+host_cpu = @[email protected]
+host_os = @[email protected]
+host_vendor = @[email protected]
+htmldir = @[email protected]
+includedir = @[email protected]
+infodir = @[email protected]
+install_sh = @[email protected]
+libexecdir = @[email protected]
+localedir = @[email protected]
+localstatedir = @[email protected]
+mkdir_p = @[email protected]
+oldincludedir = @[email protected]
+pkgpyexecdir = @[email protected]
+pkgpythondir = @[email protected]
+program_transform_name = @[email protected]
+pyexecdir = @[email protected]
+pythondir = @[email protected]
+sbindir = @[email protected]
+sharedstatedir = @[email protected]
+sysconfdir = @[email protected]
+target_alias = @[email protected]
+top_build_prefix = @[email protected]
+top_builddir = @[email protected]
+top_srcdir = @[email protected]
+lib_LTLIBRARIES = libmateweather.la
+libmateweatherincdir = $(includedir)/libmateweather
+mateweather_old_headers = \
+ weather.h mateweather-mateconf.h mateweather-prefs.h mateweather-xml.h
+
+mateweather_new_headers = \
+ mateweather-location.h location-entry.h \
+ mateweather-timezone.h timezone-menu.h
+
+libmateweatherinc_HEADERS = \
+ $(mateweather_old_headers) \
+ $(mateweather_new_headers) \
+ mateweather-enum-types.h
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = mateweather.pc
+libmateweather_la_SOURCES = weather.c weather.h weather-priv.h \
+ weather-metar.c weather-iwin.c weather-met.c weather-bom.c \
+ weather-wx.c weather-sun.c weather-moon.c \
+ mateweather-enum-types.c mateweather-prefs.c \
+ mateweather-prefs.h mateweather-mateconf.c \
+ mateweather-mateconf.h mateweather-xml.c mateweather-xml.h \
+ mateweather-location.c mateweather-location.h \
+ mateweather-timezone.c mateweather-timezone.h \
+ mateweather-win32.h location-entry.c location-entry.h \
+ timezone-menu.c timezone-menu.h parser.c parser.h \
+ $(am__append_1)
[email protected][email protected]_libmateweather_la_SOURCES = mateweather-win32.c
+libmateweather_la_CFLAGS = \
+ -I$(top_srcdir) \
+ -I$(srcdir) \
+ $(WARN_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(LIBXML_CFLAGS) \
+ $(LIBSOUP_CFLAGS) \
+ $(MATECONF_CFLAGS) \
+ -DG_LOG_DOMAIN=\"MateWeather\" \
+ -DMATELOCALEDIR=\""$(datadir)/locale"\" \
+ -DMATEWEATHER_XML_LOCATION_DIR=\""$(pkgdatadir)"\"
+
+libmateweather_la_LIBADD = \
+ -lm \
+ $(GTK_LIBS) \
+ $(LIBXML_LIBS) \
+ $(LIBSOUP_LIBS) \
+ $(MATECONF_LIBS) \
+ $(REGEX_LIBS)
+
+libmateweather_la_LDFLAGS = \
+ -version-info $(LT_VERSION) -no-undefined
+
+
+# something is wrong with glib-mkenums, please research the issue
+MKENUMS_GENERATED = mateweather-enum-types.c mateweather-enum-types.h
+# $(AM_V_GEN)( cd $(srcdir) && $(GLIB_MKENUMS) --template mateweather-enum-types.c.tmpl \
+# $(mateweather_new_headers) ) > mateweather-enum-types.c.tmp \
+# && mv mateweather-enum-types.c.tmp mateweather-enum-types.c \
+# || rm -f mateweather-enum-type.c.tmp
+BUILT_SOURCES = $(MKENUMS_GENERATED)
+test_metar_SOURCES = test_metar.c
+test_metar_CFLAGS = \
+ -I$(top_srcdir) \
+ -I$(srcdir) \
+ $(WARN_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(LIBSOUP_CFLAGS) \
+ -DG_LOG_DOMAIN=\"MateWeather\"
+
+test_metar_LDADD = \
+ $(GTK_LIBS) \
+ $(LIBSOUP_LIBS) \
+ $(REGEX_LIBS) \
+ libmateweather.la
+
+test_locations_SOURCES = test_locations.c
+test_locations_CFLAGS = \
+ -I$(top_srcdir) \
+ -I$(srcdir) \
+ $(WARN_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(MATE_VFS_APPLETS_CFLAGS) \
+ -DG_LOG_DOMAIN=\"MateWeather\"
+
+test_locations_LDADD = libmateweather.la $(GTK_LIBS)
+test_sun_moon_SOURCES = \
+ test_sun_moon.c
+
+test_sun_moon_CFLAGS = \
+ -I$(top_srcdir) \
+ -I$(srcdir) \
+ $(WARN_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(LIBSOUP_CFLAGS) \
+ -DG_LOG_DOMAIN=\"MateWeather\"
+
+test_sun_moon_LDADD = \
+ $(GTK_LIBS) \
+ $(LIBSOUP_LIBS) \
+ libmateweather.la
+
+noinst_HEADERS = weather-priv.h mateweather-win32.h
+schemadir = @[email protected]
+schema_in_files = mateweather.schemas.in
+schema_DATA = $(schema_in_files:.schemas.in=.schemas)
+EXTRA_DIST = mateweather.pc.in mateweather-uninstalled.pc.in $(schema_in_files)
+CLEANFILES = $(schema_DATA) $(EXTRA_PROGRAMS)
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @[email protected] $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f [email protected]; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libmateweather/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libmateweather/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/[email protected] $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/[email protected] $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @[email protected] $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @[email protected] $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+mateweather.pc: $(top_builddir)/config.status $(srcdir)/mateweather.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/[email protected]
+mateweather-uninstalled.pc: $(top_builddir)/config.status $(srcdir)/mateweather-uninstalled.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/[email protected]
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libmateweather.la: $(libmateweather_la_OBJECTS) $(libmateweather_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libmateweather_la_LINK) -rpath $(libdir) $(libmateweather_la_OBJECTS) $(libmateweather_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+test_locations$(EXEEXT): $(test_locations_OBJECTS) $(test_locations_DEPENDENCIES)
+ @rm -f test_locations$(EXEEXT)
+ $(AM_V_CCLD)$(test_locations_LINK) $(test_locations_OBJECTS) $(test_locations_LDADD) $(LIBS)
+test_metar$(EXEEXT): $(test_metar_OBJECTS) $(test_metar_DEPENDENCIES)
+ @rm -f test_metar$(EXEEXT)
+ $(AM_V_CCLD)$(test_metar_LINK) $(test_metar_OBJECTS) $(test_metar_LDADD) $(LIBS)
+test_sun_moon$(EXEEXT): $(test_sun_moon_OBJECTS) $(test_sun_moon_DEPENDENCIES)
+ @rm -f test_sun_moon$(EXEEXT)
+ $(AM_V_CCLD)$(test_sun_moon_LINK) $(test_sun_moon_OBJECTS) $(test_sun_moon_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+
+.c.o:
[email protected][email protected] $(AM_V_CC)$(COMPILE) -MT [email protected] -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o [email protected] $<
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+
+.c.obj:
[email protected][email protected] $(AM_V_CC)$(COMPILE) -MT [email protected] -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o [email protected] `$(CYGPATH_W) '$<'`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
[email protected][email protected] $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
[email protected][email protected] $(AM_V_CC)$(LTCOMPILE) -MT [email protected] -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o [email protected] $<
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+
+libmateweather_la-weather.lo: weather.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-weather.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-weather.Tpo -c -o libmateweather_la-weather.lo `test -f 'weather.c' || echo '$(srcdir)/'`weather.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather.Tpo $(DEPDIR)/libmateweather_la-weather.Plo
[email protected][email protected]@[email protected] source='weather.c' object='libmateweather_la-weather.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-weather.lo `test -f 'weather.c' || echo '$(srcdir)/'`weather.c
+
+libmateweather_la-weather-metar.lo: weather-metar.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-weather-metar.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-weather-metar.Tpo -c -o libmateweather_la-weather-metar.lo `test -f 'weather-metar.c' || echo '$(srcdir)/'`weather-metar.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather-metar.Tpo $(DEPDIR)/libmateweather_la-weather-metar.Plo
[email protected][email protected]@[email protected] source='weather-metar.c' object='libmateweather_la-weather-metar.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-weather-metar.lo `test -f 'weather-metar.c' || echo '$(srcdir)/'`weather-metar.c
+
+libmateweather_la-weather-iwin.lo: weather-iwin.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-weather-iwin.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-weather-iwin.Tpo -c -o libmateweather_la-weather-iwin.lo `test -f 'weather-iwin.c' || echo '$(srcdir)/'`weather-iwin.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather-iwin.Tpo $(DEPDIR)/libmateweather_la-weather-iwin.Plo
[email protected][email protected]@[email protected] source='weather-iwin.c' object='libmateweather_la-weather-iwin.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-weather-iwin.lo `test -f 'weather-iwin.c' || echo '$(srcdir)/'`weather-iwin.c
+
+libmateweather_la-weather-met.lo: weather-met.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-weather-met.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-weather-met.Tpo -c -o libmateweather_la-weather-met.lo `test -f 'weather-met.c' || echo '$(srcdir)/'`weather-met.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather-met.Tpo $(DEPDIR)/libmateweather_la-weather-met.Plo
[email protected][email protected]@[email protected] source='weather-met.c' object='libmateweather_la-weather-met.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-weather-met.lo `test -f 'weather-met.c' || echo '$(srcdir)/'`weather-met.c
+
+libmateweather_la-weather-bom.lo: weather-bom.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-weather-bom.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-weather-bom.Tpo -c -o libmateweather_la-weather-bom.lo `test -f 'weather-bom.c' || echo '$(srcdir)/'`weather-bom.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather-bom.Tpo $(DEPDIR)/libmateweather_la-weather-bom.Plo
[email protected][email protected]@[email protected] source='weather-bom.c' object='libmateweather_la-weather-bom.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-weather-bom.lo `test -f 'weather-bom.c' || echo '$(srcdir)/'`weather-bom.c
+
+libmateweather_la-weather-wx.lo: weather-wx.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-weather-wx.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-weather-wx.Tpo -c -o libmateweather_la-weather-wx.lo `test -f 'weather-wx.c' || echo '$(srcdir)/'`weather-wx.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather-wx.Tpo $(DEPDIR)/libmateweather_la-weather-wx.Plo
[email protected][email protected]@[email protected] source='weather-wx.c' object='libmateweather_la-weather-wx.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-weather-wx.lo `test -f 'weather-wx.c' || echo '$(srcdir)/'`weather-wx.c
+
+libmateweather_la-weather-sun.lo: weather-sun.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-weather-sun.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-weather-sun.Tpo -c -o libmateweather_la-weather-sun.lo `test -f 'weather-sun.c' || echo '$(srcdir)/'`weather-sun.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather-sun.Tpo $(DEPDIR)/libmateweather_la-weather-sun.Plo
[email protected][email protected]@[email protected] source='weather-sun.c' object='libmateweather_la-weather-sun.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-weather-sun.lo `test -f 'weather-sun.c' || echo '$(srcdir)/'`weather-sun.c
+
+libmateweather_la-weather-moon.lo: weather-moon.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-weather-moon.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-weather-moon.Tpo -c -o libmateweather_la-weather-moon.lo `test -f 'weather-moon.c' || echo '$(srcdir)/'`weather-moon.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather-moon.Tpo $(DEPDIR)/libmateweather_la-weather-moon.Plo
[email protected][email protected]@[email protected] source='weather-moon.c' object='libmateweather_la-weather-moon.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-weather-moon.lo `test -f 'weather-moon.c' || echo '$(srcdir)/'`weather-moon.c
+
+libmateweather_la-mateweather-enum-types.lo: mateweather-enum-types.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-mateweather-enum-types.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-mateweather-enum-types.Tpo -c -o libmateweather_la-mateweather-enum-types.lo `test -f 'mateweather-enum-types.c' || echo '$(srcdir)/'`mateweather-enum-types.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-mateweather-enum-types.Tpo $(DEPDIR)/libmateweather_la-mateweather-enum-types.Plo
[email protected][email protected]@[email protected] source='mateweather-enum-types.c' object='libmateweather_la-mateweather-enum-types.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-mateweather-enum-types.lo `test -f 'mateweather-enum-types.c' || echo '$(srcdir)/'`mateweather-enum-types.c
+
+libmateweather_la-mateweather-prefs.lo: mateweather-prefs.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-mateweather-prefs.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-mateweather-prefs.Tpo -c -o libmateweather_la-mateweather-prefs.lo `test -f 'mateweather-prefs.c' || echo '$(srcdir)/'`mateweather-prefs.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-mateweather-prefs.Tpo $(DEPDIR)/libmateweather_la-mateweather-prefs.Plo
[email protected][email protected]@[email protected] source='mateweather-prefs.c' object='libmateweather_la-mateweather-prefs.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-mateweather-prefs.lo `test -f 'mateweather-prefs.c' || echo '$(srcdir)/'`mateweather-prefs.c
+
+libmateweather_la-mateweather-mateconf.lo: mateweather-mateconf.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-mateweather-mateconf.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-mateweather-mateconf.Tpo -c -o libmateweather_la-mateweather-mateconf.lo `test -f 'mateweather-mateconf.c' || echo '$(srcdir)/'`mateweather-mateconf.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-mateweather-mateconf.Tpo $(DEPDIR)/libmateweather_la-mateweather-mateconf.Plo
[email protected][email protected]@[email protected] source='mateweather-mateconf.c' object='libmateweather_la-mateweather-mateconf.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-mateweather-mateconf.lo `test -f 'mateweather-mateconf.c' || echo '$(srcdir)/'`mateweather-mateconf.c
+
+libmateweather_la-mateweather-xml.lo: mateweather-xml.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-mateweather-xml.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-mateweather-xml.Tpo -c -o libmateweather_la-mateweather-xml.lo `test -f 'mateweather-xml.c' || echo '$(srcdir)/'`mateweather-xml.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-mateweather-xml.Tpo $(DEPDIR)/libmateweather_la-mateweather-xml.Plo
[email protected][email protected]@[email protected] source='mateweather-xml.c' object='libmateweather_la-mateweather-xml.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-mateweather-xml.lo `test -f 'mateweather-xml.c' || echo '$(srcdir)/'`mateweather-xml.c
+
+libmateweather_la-mateweather-location.lo: mateweather-location.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-mateweather-location.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-mateweather-location.Tpo -c -o libmateweather_la-mateweather-location.lo `test -f 'mateweather-location.c' || echo '$(srcdir)/'`mateweather-location.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-mateweather-location.Tpo $(DEPDIR)/libmateweather_la-mateweather-location.Plo
[email protected][email protected]@[email protected] source='mateweather-location.c' object='libmateweather_la-mateweather-location.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-mateweather-location.lo `test -f 'mateweather-location.c' || echo '$(srcdir)/'`mateweather-location.c
+
+libmateweather_la-mateweather-timezone.lo: mateweather-timezone.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-mateweather-timezone.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-mateweather-timezone.Tpo -c -o libmateweather_la-mateweather-timezone.lo `test -f 'mateweather-timezone.c' || echo '$(srcdir)/'`mateweather-timezone.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-mateweather-timezone.Tpo $(DEPDIR)/libmateweather_la-mateweather-timezone.Plo
[email protected][email protected]@[email protected] source='mateweather-timezone.c' object='libmateweather_la-mateweather-timezone.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-mateweather-timezone.lo `test -f 'mateweather-timezone.c' || echo '$(srcdir)/'`mateweather-timezone.c
+
+libmateweather_la-location-entry.lo: location-entry.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-location-entry.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-location-entry.Tpo -c -o libmateweather_la-location-entry.lo `test -f 'location-entry.c' || echo '$(srcdir)/'`location-entry.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-location-entry.Tpo $(DEPDIR)/libmateweather_la-location-entry.Plo
[email protected][email protected]@[email protected] source='location-entry.c' object='libmateweather_la-location-entry.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-location-entry.lo `test -f 'location-entry.c' || echo '$(srcdir)/'`location-entry.c
+
+libmateweather_la-timezone-menu.lo: timezone-menu.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-timezone-menu.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-timezone-menu.Tpo -c -o libmateweather_la-timezone-menu.lo `test -f 'timezone-menu.c' || echo '$(srcdir)/'`timezone-menu.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-timezone-menu.Tpo $(DEPDIR)/libmateweather_la-timezone-menu.Plo
[email protected][email protected]@[email protected] source='timezone-menu.c' object='libmateweather_la-timezone-menu.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-timezone-menu.lo `test -f 'timezone-menu.c' || echo '$(srcdir)/'`timezone-menu.c
+
+libmateweather_la-parser.lo: parser.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-parser.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-parser.Tpo -c -o libmateweather_la-parser.lo `test -f 'parser.c' || echo '$(srcdir)/'`parser.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-parser.Tpo $(DEPDIR)/libmateweather_la-parser.Plo
[email protected][email protected]@[email protected] source='parser.c' object='libmateweather_la-parser.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-parser.lo `test -f 'parser.c' || echo '$(srcdir)/'`parser.c
+
+libmateweather_la-mateweather-win32.lo: mateweather-win32.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -MT libmateweather_la-mateweather-win32.lo -MD -MP -MF $(DEPDIR)/libmateweather_la-mateweather-win32.Tpo -c -o libmateweather_la-mateweather-win32.lo `test -f 'mateweather-win32.c' || echo '$(srcdir)/'`mateweather-win32.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-mateweather-win32.Tpo $(DEPDIR)/libmateweather_la-mateweather-win32.Plo
[email protected][email protected]@[email protected] source='mateweather-win32.c' object='libmateweather_la-mateweather-win32.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmateweather_la_CFLAGS) $(CFLAGS) -c -o libmateweather_la-mateweather-win32.lo `test -f 'mateweather-win32.c' || echo '$(srcdir)/'`mateweather-win32.c
+
+test_locations-test_locations.o: test_locations.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_locations_CFLAGS) $(CFLAGS) -MT test_locations-test_locations.o -MD -MP -MF $(DEPDIR)/test_locations-test_locations.Tpo -c -o test_locations-test_locations.o `test -f 'test_locations.c' || echo '$(srcdir)/'`test_locations.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/test_locations-test_locations.Tpo $(DEPDIR)/test_locations-test_locations.Po
[email protected][email protected]@[email protected] source='test_locations.c' object='test_locations-test_locations.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_locations_CFLAGS) $(CFLAGS) -c -o test_locations-test_locations.o `test -f 'test_locations.c' || echo '$(srcdir)/'`test_locations.c
+
+test_locations-test_locations.obj: test_locations.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_locations_CFLAGS) $(CFLAGS) -MT test_locations-test_locations.obj -MD -MP -MF $(DEPDIR)/test_locations-test_locations.Tpo -c -o test_locations-test_locations.obj `if test -f 'test_locations.c'; then $(CYGPATH_W) 'test_locations.c'; else $(CYGPATH_W) '$(srcdir)/test_locations.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/test_locations-test_locations.Tpo $(DEPDIR)/test_locations-test_locations.Po
[email protected][email protected]@[email protected] source='test_locations.c' object='test_locations-test_locations.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_locations_CFLAGS) $(CFLAGS) -c -o test_locations-test_locations.obj `if test -f 'test_locations.c'; then $(CYGPATH_W) 'test_locations.c'; else $(CYGPATH_W) '$(srcdir)/test_locations.c'; fi`
+
+test_metar-test_metar.o: test_metar.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_metar_CFLAGS) $(CFLAGS) -MT test_metar-test_metar.o -MD -MP -MF $(DEPDIR)/test_metar-test_metar.Tpo -c -o test_metar-test_metar.o `test -f 'test_metar.c' || echo '$(srcdir)/'`test_metar.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/test_metar-test_metar.Tpo $(DEPDIR)/test_metar-test_metar.Po
[email protected][email protected]@[email protected] source='test_metar.c' object='test_metar-test_metar.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_metar_CFLAGS) $(CFLAGS) -c -o test_metar-test_metar.o `test -f 'test_metar.c' || echo '$(srcdir)/'`test_metar.c
+
+test_metar-test_metar.obj: test_metar.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_metar_CFLAGS) $(CFLAGS) -MT test_metar-test_metar.obj -MD -MP -MF $(DEPDIR)/test_metar-test_metar.Tpo -c -o test_metar-test_metar.obj `if test -f 'test_metar.c'; then $(CYGPATH_W) 'test_metar.c'; else $(CYGPATH_W) '$(srcdir)/test_metar.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/test_metar-test_metar.Tpo $(DEPDIR)/test_metar-test_metar.Po
[email protected][email protected]@[email protected] source='test_metar.c' object='test_metar-test_metar.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_metar_CFLAGS) $(CFLAGS) -c -o test_metar-test_metar.obj `if test -f 'test_metar.c'; then $(CYGPATH_W) 'test_metar.c'; else $(CYGPATH_W) '$(srcdir)/test_metar.c'; fi`
+
+test_sun_moon-test_sun_moon.o: test_sun_moon.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_sun_moon_CFLAGS) $(CFLAGS) -MT test_sun_moon-test_sun_moon.o -MD -MP -MF $(DEPDIR)/test_sun_moon-test_sun_moon.Tpo -c -o test_sun_moon-test_sun_moon.o `test -f 'test_sun_moon.c' || echo '$(srcdir)/'`test_sun_moon.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/test_sun_moon-test_sun_moon.Tpo $(DEPDIR)/test_sun_moon-test_sun_moon.Po
[email protected][email protected]@[email protected] source='test_sun_moon.c' object='test_sun_moon-test_sun_moon.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_sun_moon_CFLAGS) $(CFLAGS) -c -o test_sun_moon-test_sun_moon.o `test -f 'test_sun_moon.c' || echo '$(srcdir)/'`test_sun_moon.c
+
+test_sun_moon-test_sun_moon.obj: test_sun_moon.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_sun_moon_CFLAGS) $(CFLAGS) -MT test_sun_moon-test_sun_moon.obj -MD -MP -MF $(DEPDIR)/test_sun_moon-test_sun_moon.Tpo -c -o test_sun_moon-test_sun_moon.obj `if test -f 'test_sun_moon.c'; then $(CYGPATH_W) 'test_sun_moon.c'; else $(CYGPATH_W) '$(srcdir)/test_sun_moon.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/test_sun_moon-test_sun_moon.Tpo $(DEPDIR)/test_sun_moon-test_sun_moon.Po
[email protected][email protected]@[email protected] source='test_sun_moon.c' object='test_sun_moon-test_sun_moon.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_sun_moon_CFLAGS) $(CFLAGS) -c -o test_sun_moon-test_sun_moon.obj `if test -f 'test_sun_moon.c'; then $(CYGPATH_W) 'test_sun_moon.c'; else $(CYGPATH_W) '$(srcdir)/test_sun_moon.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkgconfigDATA: $(pkgconfig_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)"
+ @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
+ done
+
+uninstall-pkgconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(pkgconfigdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(pkgconfigdir)" && rm -f $$files
+install-schemaDATA: $(schema_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(schemadir)" || $(MKDIR_P) "$(DESTDIR)$(schemadir)"
+ @list='$(schema_DATA)'; test -n "$(schemadir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(schemadir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(schemadir)" || exit $$?; \
+ done
+
+uninstall-schemaDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(schema_DATA)'; test -n "$(schemadir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(schemadir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(schemadir)" && rm -f $$files
+install-libmateweatherincHEADERS: $(libmateweatherinc_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(libmateweatherincdir)" || $(MKDIR_P) "$(DESTDIR)$(libmateweatherincdir)"
+ @list='$(libmateweatherinc_HEADERS)'; test -n "$(libmateweatherincdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libmateweatherincdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(libmateweatherincdir)" || exit $$?; \
+ done
+
+uninstall-libmateweatherincHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libmateweatherinc_HEADERS)'; test -n "$(libmateweatherincdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(libmateweatherincdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(libmateweatherincdir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "[email protected]" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(schemadir)" "$(DESTDIR)$(libmateweatherincdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-data-local install-libmateweatherincHEADERS \
+ install-pkgconfigDATA install-schemaDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES \
+ uninstall-libmateweatherincHEADERS uninstall-local \
+ uninstall-pkgconfigDATA uninstall-schemaDATA
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS ctags \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-data-local install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-libLTLIBRARIES \
+ install-libmateweatherincHEADERS install-man install-pdf \
+ install-pdf-am install-pkgconfigDATA install-ps install-ps-am \
+ install-schemaDATA install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-libLTLIBRARIES \
+ uninstall-libmateweatherincHEADERS uninstall-local \
+ uninstall-pkgconfigDATA uninstall-schemaDATA
+
+
+mateweather-enum-types.h: $(mateweather_new_headers)
+# $(AM_V_GEN)( cd $(srcdir) && $(GLIB_MKENUMS) --template mateweather-enum-types.h.tmpl \
+# $(mateweather_new_headers) ) > mateweather-enum-types.h.tmp \
+# && mv mateweather-enum-types.h.tmp mateweather-enum-types.h \
+# || rm -f mateweather-enum-type.h.tmp
+
+mateweather-enum-types.c: $(libmateweatherinclude_HEADERS)
+
+
[email protected][email protected] if test -z "$(DESTDIR)" ; then \
[email protected][email protected] for p in $(schema_DATA) ; do \
[email protected][email protected] MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-install-rule $$p ; \
[email protected][email protected] for p in $(schema_DATA) ; do \
[email protected][email protected] MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-uninstall-rule $$p ; \
+#$(MKENUMS_GENERATED)
+
+-include $(top_srcdir)/git.mk
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libmateweather/README b/libmateweather/README
new file mode 100644
index 0000000..610c5be
--- /dev/null
+++ b/libmateweather/README
@@ -0,0 +1,7 @@
+libmateweather
+-----------
+
+libmateweather is the retrieval backend from the mateweather mate-applet.
+It's generally useful for applications that need to get weather
+information. It also includes helper functions to access the mateweather
+mateconf schema.
diff --git a/libmateweather/location-entry.c b/libmateweather/location-entry.c
new file mode 100644
index 0000000..f6ce624
--- /dev/null
+++ b/libmateweather/location-entry.c
@@ -0,0 +1,591 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* location-entry.c - Location-selecting text entry
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "location-entry.h"
+
+#include <string.h>
+
+/**
+ * MateWeatherLocationEntry:
+ *
+ * A subclass of #GtkEntry that provides autocompletion on
+ * #MateWeatherLocation<!-- -->s
+ **/
+
+G_DEFINE_TYPE (MateWeatherLocationEntry, mateweather_location_entry, GTK_TYPE_ENTRY)
+
+enum {
+ PROP_0,
+
+ PROP_TOP,
+ PROP_LOCATION,
+
+ LAST_PROP
+};
+
+static void mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+ MateWeatherLocation *top);
+static void set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec);
+
+enum
+{
+ MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
+ MATEWEATHER_LOCATION_ENTRY_COL_LOCATION,
+ MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME,
+ MATEWEATHER_LOCATION_ENTRY_COL_SORT_NAME,
+ MATEWEATHER_LOCATION_ENTRY_NUM_COLUMNS
+};
+
+static gboolean matcher (GtkEntryCompletion *completion, const char *key,
+ GtkTreeIter *iter, gpointer user_data);
+static gboolean match_selected (GtkEntryCompletion *completion,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer entry);
+static void entry_changed (MateWeatherLocationEntry *entry);
+
+static void
+mateweather_location_entry_init (MateWeatherLocationEntry *entry)
+{
+ GtkEntryCompletion *completion;
+
+ completion = gtk_entry_completion_new ();
+
+ gtk_entry_completion_set_popup_set_width (completion, FALSE);
+ gtk_entry_completion_set_text_column (completion, MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME);
+ gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+
+ g_signal_connect (completion, "match_selected",
+ G_CALLBACK (match_selected), entry);
+
+ gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+ g_object_unref (completion);
+
+ entry->custom_text = FALSE;
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed), NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+ MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+ if (entry->location)
+ mateweather_location_unref (entry->location);
+ if (entry->top)
+ mateweather_location_unref (entry->top);
+
+ G_OBJECT_CLASS (mateweather_location_entry_parent_class)->finalize (object);
+}
+
+static void
+mateweather_location_entry_class_init (MateWeatherLocationEntryClass *location_entry_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (location_entry_class);
+
+ object_class->finalize = finalize;
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+
+ /* properties */
+ g_object_class_install_property (
+ object_class, PROP_TOP,
+ g_param_spec_pointer ("top",
+ "Top Location",
+ "The MateWeatherLocation whose children will be used to fill in the entry",
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (
+ object_class, PROP_LOCATION,
+ g_param_spec_pointer ("location",
+ "Location",
+ "The selected MateWeatherLocation",
+ G_PARAM_READWRITE));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case PROP_TOP:
+ mateweather_location_entry_build_model (MATEWEATHER_LOCATION_ENTRY (object),
+ g_value_get_pointer (value));
+ break;
+ case PROP_LOCATION:
+ mateweather_location_entry_set_location (MATEWEATHER_LOCATION_ENTRY (object),
+ g_value_get_pointer (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+ switch (prop_id) {
+ case PROP_LOCATION:
+ g_value_set_pointer (value, entry->location);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+entry_changed (MateWeatherLocationEntry *entry)
+{
+ entry->custom_text = TRUE;
+}
+
+static void
+set_location_internal (MateWeatherLocationEntry *entry,
+ GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ MateWeatherLocation *loc;
+ char *name;
+
+ if (entry->location)
+ mateweather_location_unref (entry->location);
+
+ if (iter) {
+ gtk_tree_model_get (model, iter,
+ MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
+ MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+ -1);
+ entry->location = mateweather_location_ref (loc);
+ gtk_entry_set_text (GTK_ENTRY (entry), name);
+ entry->custom_text = FALSE;
+ g_free (name);
+ } else {
+ entry->location = NULL;
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+ entry->custom_text = TRUE;
+ }
+
+ gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
+ g_object_notify (G_OBJECT (entry), "location");
+}
+
+/**
+ * mateweather_location_entry_set_location:
+ * @entry: a #MateWeatherLocationEntry
+ * @loc: (allow-none): a #MateWeatherLocation in @entry, or %NULL to
+ * clear @entry
+ *
+ * Sets @entry's location to @loc, and updates the text of the
+ * entry accordingly.
+ **/
+void
+mateweather_location_entry_set_location (MateWeatherLocationEntry *entry,
+ MateWeatherLocation *loc)
+{
+ GtkEntryCompletion *completion;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ MateWeatherLocation *cmploc;
+
+ g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+
+ completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+ model = gtk_entry_completion_get_model (completion);
+
+ gtk_tree_model_get_iter_first (model, &iter);
+ do {
+ gtk_tree_model_get (model, &iter,
+ MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+ -1);
+ if (loc == cmploc) {
+ set_location_internal (entry, model, &iter);
+ return;
+ }
+ } while (gtk_tree_model_iter_next (model, &iter));
+
+ set_location_internal (entry, model, NULL);
+}
+
+/**
+ * mateweather_location_entry_get_location:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Gets the location that was set by a previous call to
+ * mateweather_location_entry_set_location() or was selected by the user.
+ *
+ * Return value: (transfer full) (allow-none): the selected location
+ * (which you must unref when you are done with it), or %NULL if no
+ * location is selected.
+ **/
+MateWeatherLocation *
+mateweather_location_entry_get_location (MateWeatherLocationEntry *entry)
+{
+ g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), NULL);
+
+ if (entry->location)
+ return mateweather_location_ref (entry->location);
+ else
+ return NULL;
+}
+
+/**
+ * mateweather_location_entry_has_custom_text:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Checks whether or not @entry's text has been modified by the user.
+ * Note that this does not mean that no location is associated with @entry.
+ * mateweather_location_entry_get_location() should be used for this.
+ *
+ * Return value: %TRUE if @entry's text was modified by the user, or %FALSE if
+ * it's set to the default text of a location.
+ **/
+gboolean
+mateweather_location_entry_has_custom_text (MateWeatherLocationEntry *entry)
+{
+ g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+
+ return entry->custom_text;
+}
+
+/**
+ * mateweather_location_entry_set_city:
+ * @entry: a #MateWeatherLocationEntry
+ * @city_name: (allow-none): the city name, or %NULL
+ * @code: the METAR station code
+ *
+ * Sets @entry's location to a city with the given @code, and given
+ * @city_name, if non-%NULL. If there is no matching city, sets
+ * @entry's location to %NULL.
+ *
+ * Return value: %TRUE if @entry's location could be set to a matching city,
+ * %FALSE otherwise.
+ **/
+gboolean
+mateweather_location_entry_set_city (MateWeatherLocationEntry *entry,
+ const char *city_name,
+ const char *code)
+{
+ GtkEntryCompletion *completion;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ MateWeatherLocation *cmploc;
+ const char *cmpcode;
+ char *cmpname;
+
+ g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+ g_return_val_if_fail (code != NULL, FALSE);
+
+ completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+ model = gtk_entry_completion_get_model (completion);
+
+ gtk_tree_model_get_iter_first (model, &iter);
+ do {
+ gtk_tree_model_get (model, &iter,
+ MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+ -1);
+
+ cmpcode = mateweather_location_get_code (cmploc);
+ if (!cmpcode || strcmp (cmpcode, code) != 0)
+ continue;
+
+ if (city_name) {
+ cmpname = mateweather_location_get_city_name (cmploc);
+ if (!cmpname || strcmp (cmpname, city_name) != 0) {
+ g_free (cmpname);
+ continue;
+ }
+ g_free (cmpname);
+ }
+
+ set_location_internal (entry, model, &iter);
+ return TRUE;
+ } while (gtk_tree_model_iter_next (model, &iter));
+
+ set_location_internal (entry, model, NULL);
+
+ return FALSE;
+}
+
+static void
+fill_location_entry_model (GtkTreeStore *store, MateWeatherLocation *loc,
+ const char *parent_display_name,
+ const char *parent_compare_name)
+{
+ MateWeatherLocation **children;
+ char *display_name, *compare_name;
+ GtkTreeIter iter;
+ int i;
+
+ children = mateweather_location_get_children (loc);
+
+ switch (mateweather_location_get_level (loc)) {
+ case MATEWEATHER_LOCATION_WORLD:
+ case MATEWEATHER_LOCATION_REGION:
+ case MATEWEATHER_LOCATION_ADM2:
+ /* Ignore these levels of hierarchy; just recurse, passing on
+ * the names from the parent node.
+ */
+ for (i = 0; children[i]; i++) {
+ fill_location_entry_model (store, children[i],
+ parent_display_name,
+ parent_compare_name);
+ }
+ break;
+
+ case MATEWEATHER_LOCATION_COUNTRY:
+ /* Recurse, initializing the names to the country name */
+ for (i = 0; children[i]; i++) {
+ fill_location_entry_model (store, children[i],
+ mateweather_location_get_name (loc),
+ mateweather_location_get_sort_name (loc));
+ }
+ break;
+
+ case MATEWEATHER_LOCATION_ADM1:
+ /* Recurse, adding the ADM1 name to the country name */
+ display_name = g_strdup_printf ("%s, %s", mateweather_location_get_name (loc), parent_display_name);
+ compare_name = g_strdup_printf ("%s, %s", mateweather_location_get_sort_name (loc), parent_compare_name);
+
+ for (i = 0; children[i]; i++) {
+ fill_location_entry_model (store, children[i],
+ display_name, compare_name);
+ }
+
+ g_free (display_name);
+ g_free (compare_name);
+ break;
+
+ case MATEWEATHER_LOCATION_CITY:
+ if (children[0] && children[1]) {
+ /* If there are multiple (<location>) children, add a line
+ * for each of them.
+ */
+ for (i = 0; children[i]; i++) {
+ display_name = g_strdup_printf ("%s (%s), %s",
+ mateweather_location_get_name (loc),
+ mateweather_location_get_name (children[i]),
+ parent_display_name);
+ compare_name = g_strdup_printf ("%s (%s), %s",
+ mateweather_location_get_sort_name (loc),
+ mateweather_location_get_sort_name (children[i]),
+ parent_compare_name);
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter,
+ MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[i],
+ MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+ MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+ -1);
+
+ g_free (display_name);
+ g_free (compare_name);
+ }
+ } else if (children[0]) {
+ /* Else there's only one location. This is a mix of the
+ * city-with-multiple-location case above and the
+ * location-with-no-city case below.
+ */
+ display_name = g_strdup_printf ("%s, %s",
+ mateweather_location_get_name (loc),
+ parent_display_name);
+ compare_name = g_strdup_printf ("%s, %s",
+ mateweather_location_get_sort_name (loc),
+ parent_compare_name);
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter,
+ MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[0],
+ MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+ MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+ -1);
+
+ g_free (display_name);
+ g_free (compare_name);
+ }
+ break;
+
+ case MATEWEATHER_LOCATION_WEATHER_STATION:
+ /* <location> with no parent <city>, or <city> with a single
+ * child <location>.
+ */
+ display_name = g_strdup_printf ("%s, %s",
+ mateweather_location_get_name (loc),
+ parent_display_name);
+ compare_name = g_strdup_printf ("%s, %s",
+ mateweather_location_get_sort_name (loc),
+ parent_compare_name);
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter,
+ MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, loc,
+ MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+ MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+ -1);
+
+ g_free (display_name);
+ g_free (compare_name);
+ break;
+ }
+
+ mateweather_location_free_children (loc, children);
+}
+
+static void
+mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+ MateWeatherLocation *top)
+{
+ GtkTreeStore *store = NULL;
+
+ entry->top = mateweather_location_ref (top);
+
+ store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
+ fill_location_entry_model (store, top, NULL, NULL);
+ gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)),
+ GTK_TREE_MODEL (store));
+ g_object_unref (store);
+}
+
+static char *
+find_word (const char *full_name, const char *word, int word_len,
+ gboolean whole_word, gboolean is_first_word)
+{
+ char *p = (char *)full_name - 1;
+
+ while ((p = strchr (p + 1, *word))) {
+ if (strncmp (p, word, word_len) != 0)
+ continue;
+
+ if (p > (char *)full_name) {
+ char *prev = g_utf8_prev_char (p);
+
+ /* Make sure p points to the start of a word */
+ if (g_unichar_isalpha (g_utf8_get_char (prev)))
+ continue;
+
+ /* If we're matching the first word of the key, it has to
+ * match the first word of the location, city, state, or
+ * country. Eg, it either matches the start of the string
+ * (which we already know it doesn't at this point) or
+ * it is preceded by the string ", " (which isn't actually
+ * a perfect test. FIXME)
+ */
+ if (is_first_word) {
+ if (prev == (char *)full_name || strncmp (prev - 1, ", ", 2) != 0)
+ continue;
+ }
+ }
+
+ if (whole_word && g_unichar_isalpha (g_utf8_get_char (p + word_len)))
+ continue;
+
+ return p;
+ }
+ return NULL;
+}
+
+static gboolean
+matcher (GtkEntryCompletion *completion, const char *key,
+ GtkTreeIter *iter, gpointer user_data)
+{
+ char *name, *name_mem;
+ MateWeatherLocation *loc;
+ gboolean is_first_word = TRUE, match;
+ int len;
+
+ gtk_tree_model_get (gtk_entry_completion_get_model (completion), iter,
+ MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, &name_mem,
+ MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+ -1);
+ name = name_mem;
+
+ if (!loc) {
+ g_free (name_mem);
+ return FALSE;
+ }
+
+ /* All but the last word in KEY must match a full word from NAME,
+ * in order (but possibly skipping some words from NAME).
+ */
+ len = strcspn (key, " ");
+ while (key[len]) {
+ name = find_word (name, key, len, TRUE, is_first_word);
+ if (!name) {
+ g_free (name_mem);
+ return FALSE;
+ }
+
+ key += len;
+ while (*key && !g_unichar_isalpha (g_utf8_get_char (key)))
+ key = g_utf8_next_char (key);
+ while (*name && !g_unichar_isalpha (g_utf8_get_char (name)))
+ name = g_utf8_next_char (name);
+
+ len = strcspn (key, " ");
+ is_first_word = FALSE;
+ }
+
+ /* The last word in KEY must match a prefix of a following word in NAME */
+ match = find_word (name, key, strlen (key), FALSE, is_first_word) != NULL;
+ g_free (name_mem);
+ return match;
+}
+
+static gboolean
+match_selected (GtkEntryCompletion *completion,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer entry)
+{
+ set_location_internal (entry, model, iter);
+ return TRUE;
+}
+
+/**
+ * mateweather_location_entry_new:
+ * @top: the top-level location for the entry.
+ *
+ * Creates a new #MateWeatherLocationEntry.
+ *
+ * @top will normally be a location returned from
+ * mateweather_location_new_world(), but you can create an entry that
+ * only accepts a smaller set of locations if you want.
+ *
+ * Return value: the new #MateWeatherLocationEntry
+ **/
+GtkWidget *
+mateweather_location_entry_new (MateWeatherLocation *top)
+{
+ return g_object_new (MATEWEATHER_TYPE_LOCATION_ENTRY,
+ "top", top,
+ NULL);
+}
diff --git a/libmateweather/location-entry.h b/libmateweather/location-entry.h
new file mode 100644
index 0000000..9f1e3a0
--- /dev/null
+++ b/libmateweather/location-entry.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* location-entry.h - Location-selecting text entry
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEWEATHER_LOCATION_ENTRY_H
+#define MATEWEATHER_LOCATION_ENTRY_H 1
+
+#include <gtk/gtk.h>
+#include <libmateweather/mateweather-location.h>
+
+#define MATEWEATHER_TYPE_LOCATION_ENTRY (mateweather_location_entry_get_type ())
+#define MATEWEATHER_LOCATION_ENTRY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MATEWEATHER_TYPE_LOCATION_ENTRY, MateWeatherLocationEntry))
+#define MATEWEATHER_LOCATION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MATEWEATHER_TYPE_LOCATION_ENTRY, MateWeatherLocationEntryClass))
+#define MATEWEATHER_IS_LOCATION_ENTRY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MATEWEATHER_TYPE_LOCATION_ENTRY))
+#define MATEWEATHER_IS_LOCATION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MATEWEATHER_TYPE_LOCATION_ENTRY))
+#define MATEWEATHER_LOCATION_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MATEWEATHER_TYPE_LOCATION_ENTRY, MateWeatherLocationEntryClass))
+
+typedef struct {
+ GtkEntry parent;
+
+ /*< private >*/
+ MateWeatherLocation *location, *top;
+ guint custom_text : 1;
+} MateWeatherLocationEntry;
+
+typedef struct {
+ GtkEntryClass parent_class;
+
+} MateWeatherLocationEntryClass;
+
+GType mateweather_location_entry_get_type (void);
+
+GtkWidget *mateweather_location_entry_new (MateWeatherLocation *top);
+
+void mateweather_location_entry_set_location (MateWeatherLocationEntry *entry,
+ MateWeatherLocation *loc);
+MateWeatherLocation *mateweather_location_entry_get_location (MateWeatherLocationEntry *entry);
+
+gboolean mateweather_location_entry_has_custom_text (MateWeatherLocationEntry *entry);
+
+gboolean mateweather_location_entry_set_city (MateWeatherLocationEntry *entry,
+ const char *city_name,
+ const char *code);
+
+#endif
diff --git a/libmateweather/mateweather-enum-types.c b/libmateweather/mateweather-enum-types.c
new file mode 100644
index 0000000..731123e
--- /dev/null
+++ b/libmateweather/mateweather-enum-types.c
@@ -0,0 +1,29 @@
+/* Generated data (by glib-mkenums) */
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-enum-types.h"
+#include "mateweather-location.h"
+/* enumerations from "mateweather-location.h" */
+GType mateweather_location_level_get_type(void)
+{
+ static GType etype = 0;
+
+ if (G_UNLIKELY(etype == 0))
+ {
+ static const GEnumValue values[] = {
+ {MATEWEATHER_LOCATION_WORLD, "MATEWEATHER_LOCATION_WORLD", "world"},
+ {MATEWEATHER_LOCATION_REGION, "MATEWEATHER_LOCATION_REGION", "region"},
+ {MATEWEATHER_LOCATION_COUNTRY, "MATEWEATHER_LOCATION_COUNTRY", "country"},
+ {MATEWEATHER_LOCATION_ADM1, "MATEWEATHER_LOCATION_ADM1", "adm1"},
+ {MATEWEATHER_LOCATION_ADM2, "MATEWEATHER_LOCATION_ADM2", "adm2"},
+ {MATEWEATHER_LOCATION_CITY, "MATEWEATHER_LOCATION_CITY", "city"},
+ {MATEWEATHER_LOCATION_WEATHER_STATION, "MATEWEATHER_LOCATION_WEATHER_STATION", "weather-station"},
+ {0, NULL, NULL}
+ };
+ etype = g_enum_register_static(g_intern_static_string("MateWeatherLocationLevel"), values);
+ }
+
+ return etype;
+}
+
+/* Generated data ends here */
diff --git a/libmateweather/mateweather-enum-types.h b/libmateweather/mateweather-enum-types.h
new file mode 100644
index 0000000..a04670c
--- /dev/null
+++ b/libmateweather/mateweather-enum-types.h
@@ -0,0 +1,23 @@
+
+/* Generated data (by glib-mkenums) */
+
+#ifndef __MATEWEATHER_ENUM_TYPES_H__
+#define __MATEWEATHER_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* enumerations from "mateweather-location.h" */
+GType mateweather_location_level_get_type (void) G_GNUC_CONST;
+#define MATEWEATHER_TYPE_LOCATION_LEVEL (mateweather_location_level_get_type ())
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MATEWEATHER_ENUM_TYPES_H__ */
+
+/* Generated data ends here */
+
diff --git a/libmateweather/mateweather-location.c b/libmateweather/mateweather-location.c
new file mode 100644
index 0000000..df205d4
--- /dev/null
+++ b/libmateweather/mateweather-location.c
@@ -0,0 +1,814 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-location.c - Location-handling code
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <locale.h>
+#include <gtk/gtk.h>
+#include <libxml/xmlreader.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-location.h"
+#include "mateweather-timezone.h"
+#include "parser.h"
+#include "weather-priv.h"
+
+/**
+ * MateWeatherLocation:
+ *
+ * A #MateWeatherLocation represents a "location" of some type known to
+ * libmateweather; anything from a single weather station to the entire
+ * world. See #MateWeatherLocationLevel for information about how the
+ * hierarchy of locations works.
+ **/
+
+struct _MateWeatherLocation {
+ char *name, *sort_name;
+ MateWeatherLocation *parent, **children;
+ MateWeatherLocationLevel level;
+ char *country_code, *tz_hint;
+ char *station_code, *forecast_zone, *radar;
+ double latitude, longitude;
+ gboolean latlon_valid;
+ MateWeatherTimezone **zones;
+
+ int ref_count;
+};
+
+/**
+ * MateWeatherLocationLevel:
+ * @MATEWEATHER_LOCATION_WORLD: A location representing the entire world.
+ * @MATEWEATHER_LOCATION_REGION: A location representing a continent or
+ * other top-level region.
+ * @MATEWEATHER_LOCATION_COUNTRY: A location representing a "country" (or
+ * other geographic unit that has an ISO-3166 country code)
+ * @MATEWEATHER_LOCATION_ADM1: A location representing a "first-level
+ * administrative division"; ie, a state, province, or similar
+ * division.
+ * @MATEWEATHER_LOCATION_ADM2: A location representing a subdivision of a
+ * %MATEWEATHER_LOCATION_ADM1 location. (Not currently used.)
+ * @MATEWEATHER_LOCATION_CITY: A location representing a city
+ * @MATEWEATHER_LOCATION_WEATHER_STATION: A location representing a
+ * weather station.
+ *
+ * The size/scope of a particular #MateWeatherLocation.
+ *
+ * Locations form a hierarchy, with a %MATEWEATHER_LOCATION_WORLD
+ * location at the top, divided into regions or countries, and so on.
+ * Countries may or may not be divided into "adm1"s, and "adm1"s may
+ * or may not be divided into "adm2"s. A city will have at least one,
+ * and possibly several, weather stations inside it. Weather stations
+ * will never appear outside of cities.
+ **/
+
+static int
+sort_locations_by_name (gconstpointer a, gconstpointer b)
+{
+ MateWeatherLocation *loc_a = *(MateWeatherLocation **)a;
+ MateWeatherLocation *loc_b = *(MateWeatherLocation **)b;
+
+ return g_utf8_collate (loc_a->sort_name, loc_b->sort_name);
+}
+
+static int
+sort_locations_by_distance (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ MateWeatherLocation *loc_a = *(MateWeatherLocation **)a;
+ MateWeatherLocation *loc_b = *(MateWeatherLocation **)b;
+ MateWeatherLocation *city = (MateWeatherLocation *)user_data;
+ double dist_a, dist_b;
+
+ dist_a = mateweather_location_get_distance (loc_a, city);
+ dist_b = mateweather_location_get_distance (loc_b, city);
+ if (dist_a < dist_b)
+ return -1;
+ else if (dist_a > dist_b)
+ return 1;
+ else
+ return 0;
+}
+
+static gboolean
+parse_coordinates (const char *coordinates,
+ double *latitude, double *longitude)
+{
+ char *p;
+
+ *latitude = g_ascii_strtod (coordinates, &p) * M_PI / 180.0;
+ if (p == (char *)coordinates)
+ return FALSE;
+ if (*p++ != ' ')
+ return FALSE;
+ *longitude = g_ascii_strtod (p, &p) * M_PI / 180.0;
+ return !*p;
+}
+
+static char *
+unparse_coordinates (double latitude, double longitude)
+{
+ int lat_d, lat_m, lat_s, lon_d, lon_m, lon_s;
+ char lat_dir, lon_dir;
+
+ latitude = latitude * 180.0 / M_PI;
+ longitude = longitude * 180.0 / M_PI;
+
+ if (latitude < 0.0) {
+ lat_dir = 'S';
+ latitude = -latitude;
+ } else
+ lat_dir = 'N';
+ if (longitude < 0.0) {
+ lon_dir = 'W';
+ longitude = -longitude;
+ } else
+ lon_dir = 'E';
+
+ lat_d = (int)latitude;
+ lat_m = (int)(latitude * 60.0) - lat_d * 60;
+ lat_s = (int)(latitude * 3600.0) - lat_d * 3600 - lat_m * 60;
+ lon_d = (int)longitude;
+ lon_m = (int)(longitude * 60.0) - lon_d * 60;
+ lon_s = (int)(longitude * 3600.0) - lon_d * 3600 - lon_m * 60;
+
+ return g_strdup_printf ("%02d-%02d-%02d%c %03d-%02d-%02d%c",
+ lat_d, lat_m, lat_s, lat_dir,
+ lon_d, lon_m, lon_s, lon_dir);
+}
+
+static MateWeatherLocation *
+location_new_from_xml (MateWeatherParser *parser, MateWeatherLocationLevel level,
+ MateWeatherLocation *parent)
+{
+ MateWeatherLocation *loc, *child;
+ GPtrArray *children = NULL;
+ const char *tagname;
+ char *value, *normalized;
+ int tagtype, i;
+
+ loc = g_slice_new0 (MateWeatherLocation);
+ loc->parent = parent;
+ loc->level = level;
+ loc->ref_count = 1;
+ children = g_ptr_array_new ();
+
+ if (xmlTextReaderRead (parser->xml) != 1)
+ goto error_out;
+ while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
+ XML_READER_TYPE_END_ELEMENT) {
+ if (tagtype != XML_READER_TYPE_ELEMENT) {
+ if (xmlTextReaderRead (parser->xml) != 1)
+ goto error_out;
+ continue;
+ }
+
+ tagname = (const char *) xmlTextReaderConstName (parser->xml);
+ if (!strcmp (tagname, "name") && !loc->name) {
+ value = mateweather_parser_get_localized_value (parser);
+ if (!value)
+ goto error_out;
+ loc->name = g_strdup (value);
+ xmlFree (value);
+ normalized = g_utf8_normalize (loc->name, -1, G_NORMALIZE_ALL);
+ loc->sort_name = g_utf8_casefold (normalized, -1);
+ g_free (normalized);
+
+ } else if (!strcmp (tagname, "iso-code") && !loc->country_code) {
+ value = mateweather_parser_get_value (parser);
+ if (!value)
+ goto error_out;
+ loc->country_code = g_strdup (value);
+ xmlFree (value);
+ } else if (!strcmp (tagname, "tz-hint") && !loc->tz_hint) {
+ value = mateweather_parser_get_value (parser);
+ if (!value)
+ goto error_out;
+ loc->tz_hint = g_strdup (value);
+ xmlFree (value);
+ } else if (!strcmp (tagname, "code") && !loc->station_code) {
+ value = mateweather_parser_get_value (parser);
+ if (!value)
+ goto error_out;
+ loc->station_code = g_strdup (value);
+ xmlFree (value);
+ } else if (!strcmp (tagname, "coordinates") && !loc->latlon_valid) {
+ value = mateweather_parser_get_value (parser);
+ if (!value)
+ goto error_out;
+ if (parse_coordinates (value, &loc->latitude, &loc->longitude))
+ loc->latlon_valid = TRUE;
+ xmlFree (value);
+ } else if (!strcmp (tagname, "zone") && !loc->forecast_zone) {
+ value = mateweather_parser_get_value (parser);
+ if (!value)
+ goto error_out;
+ loc->forecast_zone = g_strdup (value);
+ xmlFree (value);
+ } else if (!strcmp (tagname, "radar") && !loc->radar) {
+ value = mateweather_parser_get_value (parser);
+ if (!value)
+ goto error_out;
+ loc->radar = g_strdup (value);
+ xmlFree (value);
+
+ } else if (!strcmp (tagname, "region")) {
+ child = location_new_from_xml (parser, MATEWEATHER_LOCATION_REGION, loc);
+ if (!child)
+ goto error_out;
+ if (parser->use_regions)
+ g_ptr_array_add (children, child);
+ else {
+ if (child->children) {
+ for (i = 0; child->children[i]; i++)
+ g_ptr_array_add (children, mateweather_location_ref (child->children[i]));
+ }
+ mateweather_location_unref (child);
+ }
+ } else if (!strcmp (tagname, "country")) {
+ child = location_new_from_xml (parser, MATEWEATHER_LOCATION_COUNTRY, loc);
+ if (!child)
+ goto error_out;
+ g_ptr_array_add (children, child);
+ } else if (!strcmp (tagname, "state")) {
+ child = location_new_from_xml (parser, MATEWEATHER_LOCATION_ADM1, loc);
+ if (!child)
+ goto error_out;
+ g_ptr_array_add (children, child);
+ } else if (!strcmp (tagname, "city")) {
+ child = location_new_from_xml (parser, MATEWEATHER_LOCATION_CITY, loc);
+ if (!child)
+ goto error_out;
+ g_ptr_array_add (children, child);
+ } else if (!strcmp (tagname, "location")) {
+ child = location_new_from_xml (parser, MATEWEATHER_LOCATION_WEATHER_STATION, loc);
+ if (!child)
+ goto error_out;
+ g_ptr_array_add (children, child);
+
+ } else if (!strcmp (tagname, "timezones")) {
+ loc->zones = mateweather_timezones_parse_xml (parser);
+ if (!loc->zones)
+ goto error_out;
+
+ } else {
+ if (xmlTextReaderNext (parser->xml) != 1)
+ goto error_out;
+ }
+ }
+ if (xmlTextReaderRead (parser->xml) != 1 && parent)
+ goto error_out;
+
+ if (children->len) {
+ if (level == MATEWEATHER_LOCATION_CITY)
+ g_ptr_array_sort_with_data (children, sort_locations_by_distance, loc);
+ else
+ g_ptr_array_sort (children, sort_locations_by_name);
+
+ g_ptr_array_add (children, NULL);
+ loc->children = (MateWeatherLocation **)g_ptr_array_free (children, FALSE);
+ } else
+ g_ptr_array_free (children, TRUE);
+
+ return loc;
+
+error_out:
+ mateweather_location_unref (loc);
+ for (i = 0; i < children->len; i++)
+ mateweather_location_unref (children->pdata[i]);
+ g_ptr_array_free (children, TRUE);
+
+ return NULL;
+}
+
+/**
+ * mateweather_location_new_world:
+ * @use_regions: whether or not to divide the world into regions
+ *
+ * Creates a new #MateWeatherLocation of type %MATEWEATHER_LOCATION_WORLD,
+ * representing a hierarchy containing all of the locations from
+ * Locations.xml.
+ *
+ * If @use_regions is %TRUE, the immediate children of the returned
+ * location will be %MATEWEATHER_LOCATION_REGION nodes, representing the
+ * top-level "regions" of Locations.xml (the continents and a few
+ * other divisions), and the country-level nodes will be the children
+ * of the regions. If @use_regions is %FALSE, the regions will be
+ * skipped, and the children of the returned location will be the
+ * %MATEWEATHER_LOCATION_COUNTRY nodes.
+ *
+ * Return value: (allow-none): a %MATEWEATHER_LOCATION_WORLD location, or
+ * %NULL if Locations.xml could not be found or could not be parsed.
+ **/
+MateWeatherLocation *
+mateweather_location_new_world (gboolean use_regions)
+{
+ MateWeatherParser *parser;
+ MateWeatherLocation *world;
+
+ parser = mateweather_parser_new (use_regions);
+ if (!parser)
+ return NULL;
+
+ world = location_new_from_xml (parser, MATEWEATHER_LOCATION_WORLD, NULL);
+
+ mateweather_parser_free (parser);
+ return world;
+}
+
+/**
+ * mateweather_location_ref:
+ * @loc: a #MateWeatherLocation
+ *
+ * Adds 1 to @loc's reference count.
+ *
+ * Return value: @loc
+ **/
+MateWeatherLocation *
+mateweather_location_ref (MateWeatherLocation *loc)
+{
+ g_return_val_if_fail (loc != NULL, NULL);
+
+ loc->ref_count++;
+ return loc;
+}
+
+/**
+ * mateweather_location_unref:
+ * @loc: a #MateWeatherLocation
+ *
+ * Subtracts 1 from @loc's reference count, and frees it if the
+ * reference count reaches 0.
+ **/
+void
+mateweather_location_unref (MateWeatherLocation *loc)
+{
+ int i;
+
+ g_return_if_fail (loc != NULL);
+
+ if (--loc->ref_count)
+ return;
+
+ g_free (loc->name);
+ g_free (loc->sort_name);
+ g_free (loc->country_code);
+ g_free (loc->tz_hint);
+ g_free (loc->station_code);
+ g_free (loc->forecast_zone);
+ g_free (loc->radar);
+
+ if (loc->children) {
+ for (i = 0; loc->children[i]; i++) {
+ loc->children[i]->parent = NULL;
+ mateweather_location_unref (loc->children[i]);
+ }
+ g_free (loc->children);
+ }
+
+ if (loc->zones) {
+ for (i = 0; loc->zones[i]; i++)
+ mateweather_timezone_unref (loc->zones[i]);
+ g_free (loc->zones);
+ }
+
+ g_slice_free (MateWeatherLocation, loc);
+}
+
+GType
+mateweather_location_get_type (void)
+{
+ static volatile gsize type_volatile = 0;
+
+ if (g_once_init_enter (&type_volatile)) {
+ GType type = g_boxed_type_register_static (
+ g_intern_static_string ("MateWeatherLocation"),
+ (GBoxedCopyFunc) mateweather_location_ref,
+ (GBoxedFreeFunc) mateweather_location_unref);
+ g_once_init_leave (&type_volatile, type);
+ }
+ return type_volatile;
+}
+
+/**
+ * mateweather_location_get_name:
+ * @loc: a #MateWeatherLocation
+ *
+ * Gets @loc's name, localized into the current language.
+ *
+ * Note that %MATEWEATHER_LOCATION_WEATHER_STATION nodes are not
+ * localized, and so the name returned for those nodes will always be
+ * in English, and should therefore not be displayed to the user.
+ * (FIXME: should we just not return a name?)
+ *
+ * Return value: @loc's name
+ **/
+const char *
+mateweather_location_get_name (MateWeatherLocation *loc)
+{
+ g_return_val_if_fail (loc != NULL, NULL);
+ return loc->name;
+}
+
+/**
+ * mateweather_location_get_sort_name:
+ * @loc: a #MateWeatherLocation
+ *
+ * Gets @loc's "sort name", which is the name after having
+ * g_utf8_normalize() (with %G_NORMALIZE_ALL) and g_utf8_casefold()
+ * called on it. You can use this to sort locations, or to comparing
+ * user input against a location name.
+ *
+ * Return value: @loc's sort name
+ **/
+const char *
+mateweather_location_get_sort_name (MateWeatherLocation *loc)
+{
+ g_return_val_if_fail (loc != NULL, NULL);
+ return loc->sort_name;
+}
+
+/**
+ * mateweather_location_get_level:
+ * @loc: a #MateWeatherLocation
+ *
+ * Gets @loc's level, from %MATEWEATHER_LOCATION_WORLD, to
+ * %MATEWEATHER_LOCATION_WEATHER_STATION.
+ *
+ * Return value: @loc's level
+ **/
+MateWeatherLocationLevel
+mateweather_location_get_level (MateWeatherLocation *loc)
+{
+ g_return_val_if_fail (loc != NULL, MATEWEATHER_LOCATION_WORLD);
+ return loc->level;
+}
+
+/**
+ * mateweather_location_get_parent:
+ * @loc: a #MateWeatherLocation
+ *
+ * Gets @loc's parent location.
+ *
+ * Return value: (transfer none) (allow-none): @loc's parent, or %NULL
+ * if @loc is a %MATEWEATHER_LOCATION_WORLD node.
+ **/
+MateWeatherLocation *
+mateweather_location_get_parent (MateWeatherLocation *loc)
+{
+ g_return_val_if_fail (loc != NULL, NULL);
+ return loc->parent;
+}
+
+/**
+ * mateweather_location_get_children:
+ * @loc: a #MateWeatherLocation
+ *
+ * Gets an array of @loc's children; this is owned by @loc and will
+ * not remain valid if @loc is freed.
+ *
+ * Return value: (transfer none) (array zero-terminated=1): @loc's
+ * children. (May be empty, but will not be %NULL.)
+ **/
+MateWeatherLocation **
+mateweather_location_get_children (MateWeatherLocation *loc)
+{
+ static MateWeatherLocation *no_children = NULL;
+
+ g_return_val_if_fail (loc != NULL, NULL);
+
+ if (loc->children)
+ return loc->children;
+ else
+ return &no_children;
+}
+
+
+/**
+ * mateweather_location_free_children:
+ * @loc: a #MateWeatherLocation
+ * @children: an array of @loc's children
+ *
+ * This is a no-op. Do not use it.
+ *
+ * Deprecated: This is a no-op.
+ **/
+void
+mateweather_location_free_children (MateWeatherLocation *loc,
+ MateWeatherLocation **children)
+{
+ ;
+}
+
+/**
+ * mateweather_location_has_coords:
+ * @loc: a #MateWeatherLocation
+ *
+ * Checks if @loc has valid latitude and longitude.
+ *
+ * Return value: %TRUE if @loc has valid latitude and longitude.
+ **/
+gboolean
+mateweather_location_has_coords (MateWeatherLocation *loc)
+{
+ g_return_val_if_fail (loc != NULL, FALSE);
+ return loc->latlon_valid;
+}
+
+/**
+ * mateweather_location_get_coords:
+ * @loc: a #MateWeatherLocation
+ * @latitude: (out): on return will contain @loc's latitude
+ * @longitude: (out): on return will contain @loc's longitude
+ *
+ * Gets @loc's coordinates; you must check
+ * mateweather_location_has_coords() before calling this.
+ **/
+void
+mateweather_location_get_coords (MateWeatherLocation *loc,
+ double *latitude, double *longitude)
+{
+ //g_return_if_fail (loc->latlon_valid);
+ g_return_if_fail (loc != NULL);
+ g_return_if_fail (latitude != NULL);
+ g_return_if_fail (longitude != NULL);
+
+ *latitude = loc->latitude / M_PI * 180.0;
+ *longitude = loc->longitude / M_PI * 180.0;
+}
+
+/**
+ * mateweather_location_get_distance:
+ * @loc: a #MateWeatherLocation
+ * @loc2: a second #MateWeatherLocation
+ *
+ * Determines the distance in kilometers between @loc and @loc2.
+ *
+ * Return value: the distance between @loc and @loc2.
+ **/
+double
+mateweather_location_get_distance (MateWeatherLocation *loc, MateWeatherLocation *loc2)
+{
+ /* average radius of the earth in km */
+ static const double radius = 6372.795;
+
+ g_return_val_if_fail (loc != NULL, 0);
+ g_return_val_if_fail (loc2 != NULL, 0);
+
+ //g_return_val_if_fail (loc->latlon_valid, 0.0);
+ //g_return_val_if_fail (loc2->latlon_valid, 0.0);
+
+ return acos (cos (loc->latitude) * cos (loc2->latitude) * cos (loc->longitude - loc2->longitude) +
+ sin (loc->latitude) * sin (loc2->latitude)) * radius;
+}
+
+/**
+ * mateweather_location_get_country:
+ * @loc: a #MateWeatherLocation
+ *
+ * Gets the ISO 3166 country code of @loc (or %NULL if @loc is a
+ * region- or world-level location)
+ *
+ * Return value: (allow-none): @loc's country code (or %NULL if @loc
+ * is a region- or world-level location)
+ **/
+const char *
+mateweather_location_get_country (MateWeatherLocation *loc)
+{
+ g_return_val_if_fail (loc != NULL, NULL);
+
+ while (loc->parent && !loc->country_code)
+ loc = loc->parent;
+ return loc->country_code;
+}
+
+/**
+ * mateweather_location_get_timezone:
+ * @loc: a #MateWeatherLocation
+ *
+ * Gets the timezone associated with @loc, if known.
+ *
+ * The timezone is owned either by @loc or by one of its parents.
+ * FIXME.
+ *
+ * Return value: (transfer none) (allow-none): @loc's timezone, or
+ * %NULL
+ **/
+MateWeatherTimezone *
+mateweather_location_get_timezone (MateWeatherLocation *loc)
+{
+ const char *tz_hint;
+ int i;
+
+ g_return_val_if_fail (loc != NULL, NULL);
+
+ while (loc && !loc->tz_hint)
+ loc = loc->parent;
+ if (!loc)
+ return NULL;
+ tz_hint = loc->tz_hint;
+
+ while (loc) {
+ while (loc && !loc->zones)
+ loc = loc->parent;
+ if (!loc)
+ return NULL;
+ for (i = 0; loc->zones[i]; i++) {
+ if (!strcmp (tz_hint, mateweather_timezone_get_tzid (loc->zones[i])))
+ return loc->zones[i];
+ }
+ loc = loc->parent;
+ }
+
+ return NULL;
+}
+
+static void
+add_timezones (MateWeatherLocation *loc, GPtrArray *zones)
+{
+ int i;
+
+ if (loc->zones) {
+ for (i = 0; loc->zones[i]; i++)
+ g_ptr_array_add (zones, mateweather_timezone_ref (loc->zones[i]));
+ }
+ if (loc->level < MATEWEATHER_LOCATION_COUNTRY && loc->children) {
+ for (i = 0; loc->children[i]; i++)
+ add_timezones (loc->children[i], zones);
+ }
+}
+
+/**
+ * mateweather_location_get_timezones:
+ * @loc: a #MateWeatherLocation
+ *
+ * Gets an array of all timezones associated with any location under
+ * @loc. You can use mateweather_location_free_timezones() to free this
+ * array.
+ *
+ * Return value: (transfer full) (array zero-terminated=1): an array
+ * of timezones. May be empty but will not be %NULL.
+ **/
+MateWeatherTimezone **
+mateweather_location_get_timezones (MateWeatherLocation *loc)
+{
+ GPtrArray *zones;
+
+ g_return_val_if_fail (loc != NULL, NULL);
+
+ zones = g_ptr_array_new ();
+ add_timezones (loc, zones);
+ g_ptr_array_add (zones, NULL);
+ return (MateWeatherTimezone **)g_ptr_array_free (zones, FALSE);
+}
+
+/**
+ * mateweather_location_free_timezones:
+ * @loc: a #MateWeatherLocation
+ * @zones: an array returned from mateweather_location_get_timezones()
+ *
+ * Frees the array of timezones returned by
+ * mateweather_location_get_timezones().
+ **/
+void
+mateweather_location_free_timezones (MateWeatherLocation *loc,
+ MateWeatherTimezone **zones)
+{
+ int i;
+
+ g_return_if_fail (loc != NULL);
+ g_return_if_fail (zones != NULL);
+
+ for (i = 0; zones[i]; i++)
+ mateweather_timezone_unref (zones[i]);
+ g_free (zones);
+}
+
+/**
+ * mateweather_location_get_code:
+ * @loc: a #MateWeatherLocation
+ *
+ * Gets the METAR station code associated with a
+ * %MATEWEATHER_LOCATION_WEATHER_STATION location.
+ *
+ * Return value: (allow-none): @loc's METAR station code, or %NULL
+ **/
+const char *
+mateweather_location_get_code (MateWeatherLocation *loc)
+{
+ g_return_val_if_fail (loc != NULL, NULL);
+ return loc->station_code;
+}
+
+/**
+ * mateweather_location_get_city_name:
+ * @loc: a #MateWeatherLocation
+ *
+ * For a %MATEWEATHER_LOCATION_CITY location, this is equivalent to
+ * mateweather_location_get_name(). For a
+ * %MATEWEATHER_LOCATION_WEATHER_STATION location, it is equivalent to
+ * calling mateweather_location_get_name() on the location's parent. For
+ * other locations it will return %NULL.
+ *
+ * Return value: (allow-none) @loc's city name, or %NULL
+ **/
+char *
+mateweather_location_get_city_name (MateWeatherLocation *loc)
+{
+ g_return_val_if_fail (loc != NULL, NULL);
+
+ if (loc->level == MATEWEATHER_LOCATION_CITY)
+ return g_strdup (loc->name);
+ else if (loc->level == MATEWEATHER_LOCATION_WEATHER_STATION &&
+ loc->parent &&
+ loc->parent->level == MATEWEATHER_LOCATION_CITY)
+ return g_strdup (loc->parent->name);
+ else
+ return NULL;
+}
+
+WeatherLocation *
+mateweather_location_to_weather_location (MateWeatherLocation *gloc,
+ const char *name)
+{
+ const char *code = NULL, *zone = NULL, *radar = NULL, *tz_hint = NULL;
+ MateWeatherLocation *l;
+ WeatherLocation *wloc;
+ char *coords;
+
+ g_return_val_if_fail (gloc != NULL, NULL);
+
+ if (!name)
+ name = mateweather_location_get_name (gloc);
+
+ if (gloc->level == MATEWEATHER_LOCATION_CITY && gloc->children)
+ l = gloc->children[0];
+ else
+ l = gloc;
+
+ if (l->latlon_valid)
+ coords = unparse_coordinates (l->latitude, l->longitude);
+ else
+ coords = NULL;
+
+ while (l && (!code || !zone || !radar || !tz_hint)) {
+ if (!code && l->station_code)
+ code = l->station_code;
+ if (!zone && l->forecast_zone)
+ zone = l->forecast_zone;
+ if (!radar && l->radar)
+ radar = l->radar;
+ if (!tz_hint && l->tz_hint)
+ tz_hint = l->tz_hint;
+ l = l->parent;
+ }
+
+ wloc = weather_location_new (name, code, zone, radar, coords,
+ mateweather_location_get_country (gloc),
+ tz_hint);
+ g_free (coords);
+ return wloc;
+}
+
+/**
+ * mateweather_location_get_weather:
+ * @loc: a %MateWeatherLocation
+ *
+ * Creates a #WeatherInfo corresponding to @loc; you can use
+ * weather_info_update() to fill it in.
+ *
+ * Return value: (transfer full): a #WeatherInfo corresponding to
+ * @loc.
+ **/
+WeatherInfo *
+mateweather_location_get_weather (MateWeatherLocation *loc)
+{
+ WeatherLocation *wloc;
+ WeatherInfo *info;
+
+ g_return_val_if_fail (loc != NULL, NULL);
+
+ wloc = mateweather_location_to_weather_location (loc, NULL);
+ info = weather_info_new (wloc, NULL, NULL, NULL);
+ weather_location_free (wloc);
+ return info;
+}
diff --git a/libmateweather/mateweather-location.h b/libmateweather/mateweather-location.h
new file mode 100644
index 0000000..7bb9fa9
--- /dev/null
+++ b/libmateweather/mateweather-location.h
@@ -0,0 +1,89 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-location.h - Location-handling code
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MATEWEATHER_LOCATIONS_H__
+#define __MATEWEATHER_LOCATIONS_H__
+
+#ifndef MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#error "libmateweather should only be used if you understand that it's subject to change, and is not supported as a fixed API/ABI or as part of the platform"
+#endif
+
+#include <glib.h>
+#include <libmateweather/mateweather-timezone.h>
+#include <libmateweather/weather.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _MateWeatherLocation MateWeatherLocation;
+
+typedef enum { /*< underscore_name=mateweather_location_level >*/
+ MATEWEATHER_LOCATION_WORLD,
+ MATEWEATHER_LOCATION_REGION,
+ MATEWEATHER_LOCATION_COUNTRY,
+ /* ADM1 = first-order administrative division = state/province, etc */
+ MATEWEATHER_LOCATION_ADM1,
+ /* ADM2 = second-order division = county, etc */
+ MATEWEATHER_LOCATION_ADM2,
+ MATEWEATHER_LOCATION_CITY,
+ MATEWEATHER_LOCATION_WEATHER_STATION
+} MateWeatherLocationLevel;
+
+GType mateweather_location_get_type (void);
+#define MATEWEATHER_TYPE_LOCATION (mateweather_location_get_type ())
+
+MateWeatherLocation *mateweather_location_new_world (gboolean use_regions);
+MateWeatherLocation *mateweather_location_ref (MateWeatherLocation *loc);
+void mateweather_location_unref (MateWeatherLocation *loc);
+
+const char *mateweather_location_get_name (MateWeatherLocation *loc);
+const char *mateweather_location_get_sort_name (MateWeatherLocation *loc);
+MateWeatherLocationLevel mateweather_location_get_level (MateWeatherLocation *loc);
+MateWeatherLocation *mateweather_location_get_parent (MateWeatherLocation *loc);
+
+MateWeatherLocation **mateweather_location_get_children (MateWeatherLocation *loc);
+void mateweather_location_free_children (MateWeatherLocation *loc,
+ MateWeatherLocation **children);
+
+gboolean mateweather_location_has_coords (MateWeatherLocation *loc);
+void mateweather_location_get_coords (MateWeatherLocation *loc,
+ double *latitude,
+ double *longitude);
+double mateweather_location_get_distance (MateWeatherLocation *loc,
+ MateWeatherLocation *loc2);
+
+const char *mateweather_location_get_country (MateWeatherLocation *loc);
+
+MateWeatherTimezone *mateweather_location_get_timezone (MateWeatherLocation *loc);
+MateWeatherTimezone **mateweather_location_get_timezones (MateWeatherLocation *loc);
+void mateweather_location_free_timezones (MateWeatherLocation *loc,
+ MateWeatherTimezone **zones);
+
+const char *mateweather_location_get_code (MateWeatherLocation *loc);
+char *mateweather_location_get_city_name (MateWeatherLocation *loc);
+
+WeatherInfo *mateweather_location_get_weather (MateWeatherLocation *loc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MATEWEATHER_LOCATIONS_H__ */
diff --git a/libmateweather/mateweather-mateconf.c b/libmateweather/mateweather-mateconf.c
new file mode 100644
index 0000000..f8f6f1b
--- /dev/null
+++ b/libmateweather/mateweather-mateconf.c
@@ -0,0 +1,310 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * mateweather-mateconf.c: MateConf interaction methods for mateweather.
+ *
+ * Copyright (C) 2005 Philip Langdale, Papadimitriou Spiros
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Philip Langdale <[email protected]>
+ * Papadimitriou Spiros <[email protected]>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-mateconf.h"
+#include "weather-priv.h"
+
+struct _MateWeatherMateConf
+{
+ MateConfClient *mateconf;
+ char *prefix;
+};
+
+
+MateWeatherMateConf *
+mateweather_mateconf_new (const char *prefix)
+{
+ MateWeatherMateConf *ctx = g_new0 (MateWeatherMateConf, 1);
+ ctx->mateconf = mateconf_client_get_default ();
+ ctx->prefix = g_strdup (prefix);
+
+ return ctx;
+}
+
+
+void
+mateweather_mateconf_free (MateWeatherMateConf *ctx)
+{
+ if (!ctx)
+ return;
+
+ g_object_unref (ctx->mateconf);
+ g_free (ctx->prefix);
+ g_free (ctx);
+}
+
+
+MateConfClient *
+mateweather_mateconf_get_client (MateWeatherMateConf *ctx)
+{
+ g_return_val_if_fail (ctx != NULL, NULL);
+ return ctx->mateconf;
+}
+
+
+gchar *
+mateweather_mateconf_get_full_key (MateWeatherMateConf *ctx,
+ const gchar *key)
+{
+ g_return_val_if_fail (ctx != NULL, NULL);
+ g_return_val_if_fail (key != NULL, NULL);
+
+ return g_strdup_printf ("%s/%s", ctx->prefix, key);
+}
+
+void
+mateweather_mateconf_set_bool (MateWeatherMateConf *ctx,
+ const gchar *key,
+ gboolean the_bool,
+ GError **opt_error)
+{
+ gchar *full_key;
+
+ g_return_if_fail (ctx != NULL);
+ g_return_if_fail (key != NULL);
+ g_return_if_fail (opt_error == NULL || *opt_error == NULL);
+
+ full_key = mateweather_mateconf_get_full_key (ctx, key);
+ mateconf_client_set_bool (ctx->mateconf, full_key, the_bool, opt_error);
+ g_free (full_key);
+}
+
+void
+mateweather_mateconf_set_int (MateWeatherMateConf *ctx,
+ const gchar *key,
+ gint the_int,
+ GError **opt_error)
+{
+ gchar *full_key;
+
+ g_return_if_fail (ctx != NULL);
+ g_return_if_fail (key != NULL);
+ g_return_if_fail (opt_error == NULL || *opt_error == NULL);
+
+ full_key = mateweather_mateconf_get_full_key (ctx, key);
+ mateconf_client_set_int (ctx->mateconf, full_key, the_int, opt_error);
+ g_free (full_key);
+}
+
+void
+mateweather_mateconf_set_string (MateWeatherMateConf *ctx,
+ const gchar *key,
+ const gchar *the_string,
+ GError **opt_error)
+{
+ gchar *full_key;
+
+ g_return_if_fail (ctx != NULL);
+ g_return_if_fail (key != NULL);
+ g_return_if_fail (opt_error == NULL || *opt_error == NULL);
+
+ full_key = mateweather_mateconf_get_full_key (ctx, key);
+ mateconf_client_set_string (ctx->mateconf, full_key, the_string, opt_error);
+ g_free (full_key);
+}
+
+gboolean
+mateweather_mateconf_get_bool (MateWeatherMateConf *ctx,
+ const gchar *key,
+ GError **opt_error)
+{
+ gchar *full_key;
+ gboolean ret;
+
+ g_return_val_if_fail (ctx != NULL, FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+ g_return_val_if_fail (opt_error == NULL || *opt_error == NULL, FALSE);
+
+ full_key = mateweather_mateconf_get_full_key (ctx, key);
+ ret = mateconf_client_get_bool (ctx->mateconf, full_key, opt_error);
+ g_free (full_key);
+ return ret;
+}
+
+gint
+mateweather_mateconf_get_int (MateWeatherMateConf *ctx,
+ const gchar *key,
+ GError **opt_error)
+{
+ gchar *full_key;
+ gint ret;
+
+ g_return_val_if_fail (ctx != NULL, 0);
+ g_return_val_if_fail (key != NULL, 0);
+ g_return_val_if_fail (opt_error == NULL || *opt_error == NULL, 0);
+
+ full_key = mateweather_mateconf_get_full_key (ctx, key);
+ ret = mateconf_client_get_int (ctx->mateconf, full_key, opt_error);
+ g_free (full_key);
+ return ret;
+}
+
+gchar *
+mateweather_mateconf_get_string (MateWeatherMateConf *ctx,
+ const gchar *key,
+ GError **opt_error)
+{
+ gchar *full_key;
+ gchar *ret;
+
+ g_return_val_if_fail (ctx != NULL, NULL);
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (opt_error == NULL || *opt_error == NULL, NULL);
+
+ full_key = mateweather_mateconf_get_full_key (ctx, key);
+ ret = mateconf_client_get_string (ctx->mateconf, full_key, opt_error);
+ g_free (full_key);
+ return ret;
+}
+
+
+WeatherLocation *
+mateweather_mateconf_get_location (MateWeatherMateConf *ctx)
+{
+ WeatherLocation *location;
+ gchar *name, *code, *zone, *radar, *coordinates;
+
+ g_return_val_if_fail (ctx != NULL, NULL);
+
+ name = mateweather_mateconf_get_string (ctx, "location4", NULL);
+ if (!name)
+ {
+ /* TRANSLATOR: Change this to the default location name,
+ * used when you first start the Weather Applet. This is
+ * the common localised name that corresponds to
+ * the location code (DEFAULT_CODE) you will put on the next message
+ * For example, for the Greek locale, we set this to "Athens", the
+ * capital city and we write it in Greek. It's important to translate
+ * this name.
+ *
+ * If you do not require a DEFAULT_LOCATION, set this to
+ * "DEFAULT_LOCATION".
+ */
+ if (strcmp ("DEFAULT_LOCATION", _("DEFAULT_LOCATION")))
+ name = g_strdup (_("DEFAULT_LOCATION"));
+ else
+ name = g_strdup ("Pittsburgh");
+ }
+
+ code = mateweather_mateconf_get_string (ctx, "location1", NULL);
+ if (!code)
+ {
+ /* TRANSLATOR: Change this to the code of your default location that
+ * corresponds to the DEFAULT_LOCATION name you put above. This is
+ * normally a four-letter (ICAO) code and can be found in
+ * http://git.gnome.org/cgit/libmateweather/plain/data/Locations.xml.in
+ * NB. The web page is over 1.7MB in size.
+ * Pick a default location like a capital city so that it would be ok
+ * for more of your users. For example, for Greek, we use "LGAV" for
+ * the capital city, Athens.
+ *
+ * If you do not require a DEFAULT_CODE, set this to "DEFAULT_CODE".
+ */
+ if (strcmp ("DEFAULT_CODE", _("DEFAULT_CODE")))
+ code = g_strdup (_("DEFAULT_CODE"));
+ else
+ code = g_strdup ("KPIT");
+ }
+
+ zone = mateweather_mateconf_get_string (ctx, "location2", NULL);
+ if (!zone)
+ {
+ /* TRANSLATOR: Change this to the zone of your default location that
+ * corresponds to the DEFAULT_LOCATION and DEFAULT_CODE you put above.
+ * Normally, US and Canada locations have zones while the rest do not.
+ * Check
+ * http://git.gnome.org/cgit/libmateweather/plain/data/Locations.xml.in
+ * as any zone you put here must also be present in the Locations.xml
+ * file.
+ *
+ * If your default location does not have a zone, set this to
+ * "DEFAULT_ZONE".
+ */
+ if (strcmp ("DEFAULT_ZONE", _("DEFAULT_ZONE")))
+ zone = g_strdup (_("DEFAULT_ZONE" ));
+ else
+ zone = g_strdup ("PAZ021");
+ }
+
+ radar = mateweather_mateconf_get_string (ctx, "location3", NULL);
+ if (!radar)
+ {
+ /* TRANSLATOR: Change this to the radar of your default location that
+ * corresponds to the DEFAULT_LOCATION and DEFAULT_CODE you put above.
+ * Normally, US and Canada locations have radar names while the rest do
+ * not. Check
+ * http://git.gnome.org/cgit/libmateweather/plain/data/Locations.xml.in
+ * as any radar you put here must also be present in the Locations.xml
+ * file.
+ *
+ * If your default location does not have a radar, set this to " "
+ * (or space).
+ * If you do not have a default location, set this to DEFAULT_RADAR.
+ */
+ if (strcmp ("DEFAULT_RADAR", _("DEFAULT_RADAR")))
+ radar = g_strdup (_("DEFAULT_RADAR"));
+ else
+ radar = g_strdup ("pit");
+ }
+
+ coordinates = mateweather_mateconf_get_string (ctx, "coordinates", NULL);
+ if (!coordinates)
+ {
+ /* TRANSLATOR: Change this to the coordinates of your default location
+ * that corresponds to the DEFAULT_LOCATION and DEFAULT_CODE you put
+ * above. Check
+ * http://git.gnome.org/cgit/libmateweather/plain/data/Locations.xml.in
+ * as any coordinates you put here must also be present in the
+ * Locations.xml file.
+ *
+ * If your default location does not have known coordinates, set this
+ * to " " (or space).
+ * If you do not have a default location, set this to
+ * DEFAULT_COORDINATES.
+ */
+ if (strcmp ("DEFAULT_COORDINATES", _("DEFAULT_COORDINATES")))
+ coordinates = g_strdup (_("DEFAULT_COORDINATES"));
+ else
+ coordinates = g_strdup ("40-32N 080-13W");
+ }
+
+ location = weather_location_new (name, code, zone, radar, coordinates,
+ NULL, NULL);
+
+ g_free (name);
+ g_free (code);
+ g_free (zone);
+ g_free (radar);
+ g_free (coordinates);
+
+ return location;
+}
diff --git a/libmateweather/mateweather-mateconf.h b/libmateweather/mateweather-mateconf.h
new file mode 100644
index 0000000..5132d81
--- /dev/null
+++ b/libmateweather/mateweather-mateconf.h
@@ -0,0 +1,84 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * mateweather-mateconf.h: MateConf interaction methods for mateweather.
+ *
+ * Copyright (C) 2005 Philip Langdale, Papadimitriou Spiros
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Philip Langdale <[email protected]>
+ * Papadimitriou Spiros <[email protected]>
+ */
+
+#ifndef __MATEWEATHER_MATECONF_WRAPPER_H__
+#define __MATEWEATHER_MATECONF_WRAPPER_H__
+
+
+#ifndef MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#error "libmateweather should only be used if you understand that it's subject to change, and is not supported as a fixed API/ABI or as part of the platform"
+#endif
+
+
+#include <glib.h>
+#include <mateconf/mateconf-client.h>
+#include <mateconf/mateconf-value.h>
+
+#include <libmateweather/weather.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _MateWeatherMateConf MateWeatherMateConf;
+
+MateWeatherMateConf * mateweather_mateconf_new (const char *prefix);
+void mateweather_mateconf_free (MateWeatherMateConf *ctx);
+
+MateConfClient * mateweather_mateconf_get_client (MateWeatherMateConf *ctx);
+
+WeatherLocation * mateweather_mateconf_get_location (MateWeatherMateConf *ctx);
+
+gchar * mateweather_mateconf_get_full_key (MateWeatherMateConf *ctx,
+ const gchar *key);
+
+void mateweather_mateconf_set_bool (MateWeatherMateConf *ctx,
+ const gchar *key,
+ gboolean the_bool,
+ GError **opt_error);
+void mateweather_mateconf_set_int (MateWeatherMateConf *ctx,
+ const gchar *key,
+ gint the_int,
+ GError **opt_error);
+void mateweather_mateconf_set_string (MateWeatherMateConf *ctx,
+ const gchar *key,
+ const gchar *the_string,
+ GError **opt_error);
+
+gboolean mateweather_mateconf_get_bool (MateWeatherMateConf *ctx,
+ const gchar *key,
+ GError **opt_error);
+gint mateweather_mateconf_get_int (MateWeatherMateConf *ctx,
+ const gchar *key,
+ GError **opt_error);
+gchar * mateweather_mateconf_get_string (MateWeatherMateConf *ctx,
+ const gchar *key,
+ GError **opt_error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MATEWEATHER_MATECONF_WRAPPER_H__ */
diff --git a/libmateweather/mateweather-prefs.c b/libmateweather/mateweather-prefs.c
new file mode 100644
index 0000000..b533ca2
--- /dev/null
+++ b/libmateweather/mateweather-prefs.c
@@ -0,0 +1,395 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-prefs.c - Preference handling functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
+#include <langinfo.h>
+#endif
+
+#include <mateconf/mateconf-client.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-prefs.h"
+#include "weather-priv.h"
+
+static MateConfEnumStringPair temp_unit_enum_map [] = {
+ { TEMP_UNIT_DEFAULT, N_("Default") },
+ /* translators: Kelvin */
+ { TEMP_UNIT_KELVIN, N_("K") },
+ /* translators: Celsius */
+ { TEMP_UNIT_CENTIGRADE, N_("C") },
+ /* translators: Fahrenheit */
+ { TEMP_UNIT_FAHRENHEIT, N_("F") },
+ { 0, NULL }
+};
+
+static MateConfEnumStringPair speed_unit_enum_map [] = {
+ { SPEED_UNIT_DEFAULT, N_("Default") },
+ /* translators: meters per second */
+ { SPEED_UNIT_MS, N_("m/s") },
+ /* translators: kilometers per hour */
+ { SPEED_UNIT_KPH, N_("km/h") },
+ /* translators: miles per hour */
+ { SPEED_UNIT_MPH, N_("mph") },
+ /* translators: knots (speed unit) */
+ { SPEED_UNIT_KNOTS, N_("knots") },
+ /* translators: wind speed */
+ { SPEED_UNIT_BFT, N_("Beaufort scale") },
+ { 0, NULL }
+};
+
+static MateConfEnumStringPair pressure_unit_enum_map [] = {
+ { PRESSURE_UNIT_DEFAULT, N_("Default") },
+ /* translators: kilopascals */
+ { PRESSURE_UNIT_KPA, N_("kPa") },
+ /* translators: hectopascals */
+ { PRESSURE_UNIT_HPA, N_("hPa") },
+ /* translators: millibars */
+ { PRESSURE_UNIT_MB, N_("mb") },
+ /* translators: millimeters of mercury */
+ { PRESSURE_UNIT_MM_HG, N_("mmHg") },
+ /* translators: inches of mercury */
+ { PRESSURE_UNIT_INCH_HG, N_("inHg") },
+ /* translators: atmosphere */
+ { PRESSURE_UNIT_ATM, N_("atm") },
+ { 0, NULL }
+};
+
+static MateConfEnumStringPair distance_unit_enum_map [] = {
+ { DISTANCE_UNIT_DEFAULT, N_("Default") },
+ /* translators: meters */
+ { DISTANCE_UNIT_METERS, N_("m") },
+ /* translators: kilometers */
+ { DISTANCE_UNIT_KM, N_("km") },
+ /* translators: miles */
+ { DISTANCE_UNIT_MILES, N_("mi") },
+ { 0, NULL }
+};
+
+
+static void
+parse_temp_string (const gchar *mateconf_str, MateWeatherPrefs *prefs)
+{
+ gint value = 0;
+#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
+ char *imperial = NULL;
+#endif
+
+ prefs->temperature_unit = TEMP_UNIT_INVALID;
+ prefs->use_temperature_default = TRUE;
+
+ if ( mateconf_str && mateconf_string_to_enum (temp_unit_enum_map, mateconf_str, &value) ) {
+ prefs->temperature_unit = value;
+
+ if ((prefs->temperature_unit == TEMP_UNIT_DEFAULT) &&
+ (mateconf_string_to_enum (temp_unit_enum_map, _("DEFAULT_TEMP_UNIT"), &value)) ) {
+ prefs->temperature_unit = value;
+ } else {
+ prefs->use_temperature_default = FALSE;
+ }
+ } else {
+ /* TRANSLATOR: This is the default unit to use for temperature measurements. */
+ /* Valid values are: "K" (Kelvin), "C" (Celsius) and "F" (Fahrenheit) */
+ if (mateconf_string_to_enum (temp_unit_enum_map, _("DEFAULT_TEMP_UNIT"), &value) ) {
+ prefs->temperature_unit = value;
+ }
+ }
+ if (!prefs->temperature_unit || prefs->temperature_unit == TEMP_UNIT_DEFAULT ) {
+#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
+ imperial = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT);
+ if ( imperial && imperial[0] == 2 ) {
+ /* imperial */
+ prefs->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+ } else
+#endif
+ prefs->temperature_unit = TEMP_UNIT_CENTIGRADE;
+ }
+}
+
+static void
+parse_speed_string (const gchar *mateconf_str, MateWeatherPrefs *prefs)
+{
+ gint value = 0;
+#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
+ char *imperial = NULL;
+#endif
+
+ prefs->speed_unit = SPEED_UNIT_INVALID;
+ prefs->use_speed_default = TRUE;
+
+ if (mateconf_str && mateconf_string_to_enum (speed_unit_enum_map, mateconf_str, &value) ) {
+ prefs->speed_unit = value;
+ if ((prefs->speed_unit == SPEED_UNIT_DEFAULT) &&
+ (mateconf_string_to_enum (speed_unit_enum_map, _("DEFAULT_SPEED_UNIT"), &value)) ) {
+ prefs->speed_unit = value;
+ } else {
+ prefs->use_speed_default = FALSE;
+ }
+ }
+ else {
+ /* TRANSLATOR: This is the default unit to use for wind speed. */
+ /* Valid values are: "m/s" (meters per second), "km/h" (kilometers per hour), */
+ /* "mph" (miles per hour) and "knots" */
+ if (mateconf_string_to_enum (speed_unit_enum_map, _("DEFAULT_SPEED_UNIT"), &value) ) {
+ prefs->speed_unit = value;
+ }
+ }
+ if ((!prefs->speed_unit) || prefs->speed_unit == SPEED_UNIT_DEFAULT) {
+#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
+ imperial = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT);
+ if (imperial && imperial[0] == 2) {
+ /* imperial */
+ prefs->speed_unit = SPEED_UNIT_KNOTS;
+ } else
+#endif
+ prefs->speed_unit = SPEED_UNIT_MS;
+ }
+}
+
+
+static void
+parse_pressure_string (const gchar *mateconf_str, MateWeatherPrefs *prefs)
+{
+ gint value = 0;
+#ifdef _NL_MEASUREMENT_MEASUREMENT
+ char *imperial = NULL;
+#endif
+
+ prefs->pressure_unit = PRESSURE_UNIT_INVALID;
+ prefs->use_pressure_default = TRUE;
+
+ if ( mateconf_str && mateconf_string_to_enum (pressure_unit_enum_map, mateconf_str, &value) ) {
+ prefs->pressure_unit = value;
+
+ if ((prefs->pressure_unit == PRESSURE_UNIT_DEFAULT) &&
+ (mateconf_string_to_enum (pressure_unit_enum_map, _("DEFAULT_PRESSURE_UNIT"), &value)) ) {
+ prefs->pressure_unit = value;
+ } else {
+ prefs->use_pressure_default = FALSE;
+ }
+ }
+ else {
+ /* TRANSLATOR: This is the default unit to use for atmospheric pressure. */
+ /* Valid values are: "kPa" (kiloPascals), "hPa" (hectoPascals),
+ "mb" (millibars), "mmHg" (millimeters of mercury),
+ "inHg" (inches of mercury) and "atm" (atmosphere) */
+ if (mateconf_string_to_enum (pressure_unit_enum_map, _("DEFAULT_PRESSURE_UNIT"), &value) ) {
+ prefs->pressure_unit = value;
+ }
+ }
+ if ( (!prefs->pressure_unit) || prefs->pressure_unit == PRESSURE_UNIT_DEFAULT ) {
+#ifdef _NL_MEASUREMENT_MEASUREMENT
+ imperial = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT);
+ if (imperial && imperial[0] == 2) {
+ /* imperial */
+ prefs->pressure_unit = PRESSURE_UNIT_INCH_HG;
+ } else
+#endif
+ prefs->pressure_unit = PRESSURE_UNIT_HPA;
+ }
+}
+
+static void
+parse_distance_string (const gchar *mateconf_str, MateWeatherPrefs *prefs)
+{
+ gint value = 0;
+#ifdef _NL_MEASUREMENT_MEASUREMENT
+ char *imperial = NULL;
+#endif
+
+ prefs->distance_unit = DISTANCE_UNIT_INVALID;
+ prefs->use_distance_default = TRUE;
+ if (mateconf_str && mateconf_string_to_enum (distance_unit_enum_map, mateconf_str, &value)) {
+ prefs->distance_unit = value;
+
+ if ((prefs->distance_unit == DISTANCE_UNIT_DEFAULT) &&
+ (mateconf_string_to_enum (distance_unit_enum_map, _("DEFAULT_DISTANCE_UNIT"), &value)) ) {
+ prefs->distance_unit = value;
+ } else {
+ prefs->use_distance_default = FALSE;
+ }
+ }
+ else {
+ /* TRANSLATOR: This is the default unit to use for visibility distance. */
+ /* Valid values are: "m" (meters), "km" (kilometers) and "mi" (miles) */
+ if (mateconf_string_to_enum (distance_unit_enum_map, _("DEFAULT_DISTANCE_UNIT"), &value) ) {
+ prefs->distance_unit = value;
+ }
+ }
+
+ if ((!prefs->distance_unit) || prefs->distance_unit == DISTANCE_UNIT_DEFAULT) {
+#ifdef _NL_MEASUREMENT_MEASUREMENT
+ imperial = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT);
+ if (imperial && imperial[0] == 2) {
+ /* imperial */
+ prefs->distance_unit = DISTANCE_UNIT_MILES;
+ } else
+#endif
+ prefs->distance_unit = DISTANCE_UNIT_METERS;
+ }
+
+ return;
+}
+
+const char *
+mateweather_prefs_temp_enum_to_string (TempUnit temp)
+{
+ return mateconf_enum_to_string (temp_unit_enum_map, temp);
+}
+
+const char *
+mateweather_prefs_speed_enum_to_string (SpeedUnit speed)
+{
+ return mateconf_enum_to_string (speed_unit_enum_map, speed);
+}
+
+const char *
+mateweather_prefs_pressure_enum_to_string (PressureUnit pressure)
+{
+ return mateconf_enum_to_string (pressure_unit_enum_map, pressure);
+}
+
+const char *
+mateweather_prefs_distance_enum_to_string (DistanceUnit distance)
+{
+ return mateconf_enum_to_string (distance_unit_enum_map, distance);
+}
+
+
+void
+mateweather_prefs_load (MateWeatherPrefs *prefs, MateWeatherMateConf *ctx)
+{
+ GError *error = NULL;
+ gchar *mateconf_str = NULL;
+
+ g_return_if_fail (prefs != NULL);
+ g_return_if_fail (ctx != NULL);
+
+ if (prefs->location) {
+ weather_location_free (prefs->location);
+ }
+ prefs->location = mateweather_mateconf_get_location (ctx);
+
+ /* Assume we use unit defaults */
+ prefs->use_temperature_default = TRUE;
+ prefs->use_speed_default = TRUE;
+ prefs->use_pressure_default = TRUE;
+ prefs->use_distance_default = TRUE;
+
+ prefs->update_interval =
+ mateweather_mateconf_get_int (ctx, "auto_update_interval", &error);
+ if (error) {
+ g_print ("%s \n", error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+ prefs->update_interval = MAX (prefs->update_interval, 60);
+ prefs->update_enabled =
+ mateweather_mateconf_get_bool (ctx, "auto_update", NULL);
+ prefs->detailed =
+ mateweather_mateconf_get_bool (ctx, "enable_detailed_forecast", NULL);
+ prefs->radar_enabled =
+ mateweather_mateconf_get_bool (ctx, "enable_radar_map", NULL);
+ prefs->use_custom_radar_url =
+ mateweather_mateconf_get_bool (ctx, "use_custom_radar_url", NULL);
+
+ if (prefs->radar) {
+ g_free (prefs->radar);
+ prefs->radar = NULL;
+ }
+ prefs->radar = mateweather_mateconf_get_string (ctx, "radar", NULL);
+
+ mateconf_str = mateweather_mateconf_get_string (ctx, MATECONF_TEMP_UNIT, NULL);
+ parse_temp_string (mateconf_str, prefs);
+ g_free (mateconf_str);
+
+ mateconf_str = mateweather_mateconf_get_string (ctx, MATECONF_SPEED_UNIT, NULL);
+ parse_speed_string (mateconf_str, prefs);
+ g_free (mateconf_str);
+
+ mateconf_str = mateweather_mateconf_get_string (ctx, MATECONF_PRESSURE_UNIT, NULL);
+ parse_pressure_string (mateconf_str, prefs);
+ g_free (mateconf_str);
+
+ mateconf_str = mateweather_mateconf_get_string (ctx, MATECONF_DISTANCE_UNIT, NULL);
+ parse_distance_string (mateconf_str, prefs);
+ g_free (mateconf_str);
+
+ return;
+}
+
+TempUnit
+mateweather_prefs_parse_temperature (const char *str, gboolean *is_default)
+{
+ MateWeatherPrefs prefs;
+
+ g_return_val_if_fail (str != NULL, TEMP_UNIT_INVALID);
+ g_return_val_if_fail (is_default != NULL, TEMP_UNIT_INVALID);
+
+ parse_temp_string (str, &prefs);
+ *is_default = prefs.use_temperature_default;
+ return prefs.temperature_unit;
+}
+
+SpeedUnit
+mateweather_prefs_parse_speed (const char *str, gboolean *is_default)
+{
+ MateWeatherPrefs prefs;
+
+ g_return_val_if_fail (str != NULL, SPEED_UNIT_INVALID);
+ g_return_val_if_fail (is_default != NULL, SPEED_UNIT_INVALID);
+
+ parse_speed_string (str, &prefs);
+ *is_default = prefs.use_speed_default;
+ return prefs.speed_unit;
+}
+
+static const char *
+get_translated_unit (int unit, MateConfEnumStringPair *pairs, int min_value, int max_value)
+{
+ g_return_val_if_fail (unit >= min_value && unit <= max_value, NULL);
+
+ return _(pairs[unit - 1].str); /* minus 1 because enum value 0 is for "invalid" (look at weather.h) */
+}
+
+const char *
+mateweather_prefs_get_temp_display_name (TempUnit temp)
+{
+ return get_translated_unit (temp, temp_unit_enum_map, TEMP_UNIT_DEFAULT, TEMP_UNIT_FAHRENHEIT);
+}
+
+const char *
+mateweather_prefs_get_speed_display_name (SpeedUnit speed)
+{
+ return get_translated_unit (speed, speed_unit_enum_map, SPEED_UNIT_DEFAULT, SPEED_UNIT_BFT);
+}
+
+const char *
+mateweather_prefs_get_pressure_display_name (PressureUnit pressure)
+{
+ return get_translated_unit (pressure, pressure_unit_enum_map, PRESSURE_UNIT_DEFAULT, PRESSURE_UNIT_ATM);
+}
+
+const char *
+mateweather_prefs_get_distance_display_name (DistanceUnit distance)
+{
+ return get_translated_unit (distance, distance_unit_enum_map, DISTANCE_UNIT_DEFAULT, DISTANCE_UNIT_MILES);
+}
diff --git a/libmateweather/mateweather-prefs.h b/libmateweather/mateweather-prefs.h
new file mode 100644
index 0000000..17cc65f
--- /dev/null
+++ b/libmateweather/mateweather-prefs.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-prefs.h - Preference handling functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MATEWEATHER_PREFS_H_
+#define __MATEWEATHER_PREFS_H_
+
+
+#ifndef MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#error "libmateweather should only be used if you understand that it's subject to change, and is not supported as a fixed API/ABI or as part of the platform"
+#endif
+
+
+#include <libmateweather/weather.h>
+#include <libmateweather/mateweather-mateconf.h>
+
+/* mateconf keys */
+#define MATECONF_TEMP_UNIT "temperature_unit"
+#define MATECONF_SPEED_UNIT "speed_unit"
+#define MATECONF_PRESSURE_UNIT "pressure_unit"
+#define MATECONF_DISTANCE_UNIT "distance_unit"
+
+typedef struct _MateWeatherPrefs MateWeatherPrefs;
+
+struct _MateWeatherPrefs {
+ WeatherLocation *location;
+ gint update_interval; /* in seconds */
+ gboolean update_enabled;
+ gboolean detailed;
+ gboolean radar_enabled;
+ gboolean use_custom_radar_url;
+ gchar *radar;
+
+ TempUnit temperature_unit;
+ gboolean use_temperature_default;
+ SpeedUnit speed_unit;
+ gboolean use_speed_default;
+ PressureUnit pressure_unit;
+ gboolean use_pressure_default;
+ DistanceUnit distance_unit;
+ gboolean use_distance_default;
+};
+
+void mateweather_prefs_load (MateWeatherPrefs *prefs,
+ MateWeatherMateConf *ctx);
+
+const char * mateweather_prefs_temp_enum_to_string (TempUnit temp);
+const char * mateweather_prefs_speed_enum_to_string (SpeedUnit speed);
+const char * mateweather_prefs_pressure_enum_to_string (PressureUnit pressure);
+const char * mateweather_prefs_distance_enum_to_string (DistanceUnit distance);
+
+TempUnit mateweather_prefs_parse_temperature (const char *str,
+ gboolean *is_default);
+SpeedUnit mateweather_prefs_parse_speed (const char *str,
+ gboolean *is_default);
+
+const char * mateweather_prefs_get_temp_display_name (TempUnit temp);
+const char * mateweather_prefs_get_speed_display_name (SpeedUnit speed);
+const char * mateweather_prefs_get_pressure_display_name (PressureUnit pressure);
+const char * mateweather_prefs_get_distance_display_name (DistanceUnit distance);
+
+#endif /* __MATEWEATHER_PREFS_H_ */
diff --git a/libmateweather/mateweather-timezone.c b/libmateweather/mateweather-timezone.c
new file mode 100644
index 0000000..8c75d70
--- /dev/null
+++ b/libmateweather/mateweather-timezone.c
@@ -0,0 +1,405 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-timezone.c - Timezone handling
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-timezone.h"
+#include "parser.h"
+#include "weather-priv.h"
+
+/**
+ * MateWeatherTimezone:
+ *
+ * A timezone.
+ *
+ * There are no public methods for creating timezones; they can only
+ * be created by calling mateweather_location_new_world() to parse
+ * Locations.xml, and then calling various #MateWeatherLocation methods
+ * to extract relevant timezones from the location hierarchy.
+ **/
+struct _MateWeatherTimezone {
+ char *id, *name;
+ int offset, dst_offset;
+ gboolean has_dst;
+
+ int ref_count;
+};
+
+#define TZ_MAGIC "TZif"
+#define TZ_HEADER_SIZE 44
+#define TZ_TIMECNT_OFFSET 32
+#define TZ_TRANSITIONS_OFFSET 44
+
+#define TZ_TTINFO_SIZE 6
+#define TZ_TTINFO_GMTOFF_OFFSET 0
+#define TZ_TTINFO_ISDST_OFFSET 4
+
+static gboolean
+parse_tzdata (const char *tzname, time_t start, time_t end,
+ int *offset, gboolean *has_dst, int *dst_offset)
+{
+ char *filename, *contents;
+ gsize length;
+ int timecnt, transitions_size, ttinfo_map_size;
+ int initial_transition = -1, second_transition = -1;
+ gint32 *transitions;
+ char *ttinfo_map, *ttinfos;
+ gint32 initial_offset, second_offset;
+ char initial_isdst, second_isdst;
+ int i;
+
+ filename = g_build_filename (ZONEINFO_DIR, tzname, NULL);
+ if (!g_file_get_contents (filename, &contents, &length, NULL)) {
+ g_free (filename);
+ return FALSE;
+ }
+ g_free (filename);
+
+ if (length < TZ_HEADER_SIZE ||
+ strncmp (contents, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) {
+ g_free (contents);
+ return FALSE;
+ }
+
+ timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
+ transitions = (void *)(contents + TZ_TRANSITIONS_OFFSET);
+ transitions_size = timecnt * sizeof (*transitions);
+ ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
+ ttinfo_map_size = timecnt;
+ ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
+
+ /* @transitions is an array of @timecnt time_t values. We need to
+ * find the transition into the current offset, which is the last
+ * transition before @start. If the following transition is before
+ * @end, then note that one too, since it presumably means we're
+ * doing DST.
+ */
+ for (i = 1; i < timecnt && initial_transition == -1; i++) {
+ if (GINT32_FROM_BE (transitions[i]) > start) {
+ initial_transition = ttinfo_map[i - 1];
+ if (GINT32_FROM_BE (transitions[i]) < end)
+ second_transition = ttinfo_map[i];
+ }
+ }
+ if (initial_transition == -1) {
+ if (timecnt)
+ initial_transition = ttinfo_map[timecnt - 1];
+ else
+ initial_transition = 0;
+ }
+
+ /* Copy the data out of the corresponding ttinfo structs */
+ initial_offset = *(gint32 *)(ttinfos +
+ initial_transition * TZ_TTINFO_SIZE +
+ TZ_TTINFO_GMTOFF_OFFSET);
+ initial_offset = GINT32_FROM_BE (initial_offset);
+ initial_isdst = *(ttinfos +
+ initial_transition * TZ_TTINFO_SIZE +
+ TZ_TTINFO_ISDST_OFFSET);
+
+ if (second_transition != -1) {
+ second_offset = *(gint32 *)(ttinfos +
+ second_transition * TZ_TTINFO_SIZE +
+ TZ_TTINFO_GMTOFF_OFFSET);
+ second_offset = GINT32_FROM_BE (second_offset);
+ second_isdst = *(ttinfos +
+ second_transition * TZ_TTINFO_SIZE +
+ TZ_TTINFO_ISDST_OFFSET);
+
+ *has_dst = (initial_isdst != second_isdst);
+ } else
+ *has_dst = FALSE;
+
+ if (!*has_dst)
+ *offset = initial_offset / 60;
+ else {
+ if (initial_isdst) {
+ *offset = second_offset / 60;
+ *dst_offset = initial_offset / 60;
+ } else {
+ *offset = initial_offset / 60;
+ *dst_offset = second_offset / 60;
+ }
+ }
+
+ g_free (contents);
+ return TRUE;
+}
+
+static MateWeatherTimezone *
+parse_timezone (MateWeatherParser *parser)
+{
+ MateWeatherTimezone *zone = NULL;
+ char *id = NULL, *name = NULL;
+ int offset = 0, dst_offset = 0;
+ gboolean has_dst = FALSE;
+
+ id = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "id");
+ if (!id) {
+ xmlTextReaderNext (parser->xml);
+ return NULL;
+ }
+
+ if (!xmlTextReaderIsEmptyElement (parser->xml)) {
+ if (xmlTextReaderRead (parser->xml) != 1) {
+ xmlFree (id);
+ return NULL;
+ }
+
+ while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+ if (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT) {
+ if (xmlTextReaderRead (parser->xml) != 1)
+ break;
+ continue;
+ }
+
+ if (!strcmp ((const char *) xmlTextReaderConstName (parser->xml), "name"))
+ name = mateweather_parser_get_localized_value (parser);
+ else {
+ if (xmlTextReaderNext (parser->xml) != 1)
+ break;
+ }
+ }
+ }
+
+ if (parse_tzdata (id, parser->year_start, parser->year_end,
+ &offset, &has_dst, &dst_offset)) {
+ zone = g_slice_new0 (MateWeatherTimezone);
+ zone->ref_count = 1;
+ zone->id = g_strdup (id);
+ zone->name = g_strdup (name);
+ zone->offset = offset;
+ zone->has_dst = has_dst;
+ zone->dst_offset = dst_offset;
+ }
+
+ xmlFree (id);
+ if (name)
+ xmlFree (name);
+
+ return zone;
+}
+
+MateWeatherTimezone **
+mateweather_timezones_parse_xml (MateWeatherParser *parser)
+{
+ GPtrArray *zones;
+ MateWeatherTimezone *zone;
+ const char *tagname;
+ int tagtype, i;
+
+ zones = g_ptr_array_new ();
+
+ if (xmlTextReaderRead (parser->xml) != 1)
+ goto error_out;
+ while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
+ XML_READER_TYPE_END_ELEMENT) {
+ if (tagtype != XML_READER_TYPE_ELEMENT) {
+ if (xmlTextReaderRead (parser->xml) != 1)
+ goto error_out;
+ continue;
+ }
+
+ tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+ if (!strcmp (tagname, "timezone")) {
+ zone = parse_timezone (parser);
+ if (zone)
+ g_ptr_array_add (zones, zone);
+ }
+
+ if (xmlTextReaderNext (parser->xml) != 1)
+ goto error_out;
+ }
+ if (xmlTextReaderRead (parser->xml) != 1)
+ goto error_out;
+
+ g_ptr_array_add (zones, NULL);
+ return (MateWeatherTimezone **)g_ptr_array_free (zones, FALSE);
+
+error_out:
+ for (i = 0; i < zones->len; i++)
+ mateweather_timezone_unref (zones->pdata[i]);
+ g_ptr_array_free (zones, TRUE);
+ return NULL;
+}
+
+/**
+ * mateweather_timezone_ref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Adds 1 to @zone's reference count.
+ *
+ * Return value: @zone
+ **/
+MateWeatherTimezone *
+mateweather_timezone_ref (MateWeatherTimezone *zone)
+{
+ g_return_val_if_fail (zone != NULL, NULL);
+
+ zone->ref_count++;
+ return zone;
+}
+
+/**
+ * mateweather_timezone_unref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Subtracts 1 from @zone's reference count and frees it if it reaches 0.
+ **/
+void
+mateweather_timezone_unref (MateWeatherTimezone *zone)
+{
+ g_return_if_fail (zone != NULL);
+
+ if (!--zone->ref_count) {
+ g_free (zone->id);
+ g_free (zone->name);
+ g_slice_free (MateWeatherTimezone, zone);
+ }
+}
+
+GType
+mateweather_timezone_get_type (void)
+{
+ static volatile gsize type_volatile = 0;
+
+ if (g_once_init_enter (&type_volatile)) {
+ GType type = g_boxed_type_register_static (
+ g_intern_static_string ("MateWeatherTimezone"),
+ (GBoxedCopyFunc) mateweather_timezone_ref,
+ (GBoxedFreeFunc) mateweather_timezone_unref);
+ g_once_init_leave (&type_volatile, type);
+ }
+ return type_volatile;
+}
+
+/**
+ * mateweather_timezone_get_utc:
+ *
+ * Gets the UTC timezone.
+ *
+ * Return value: a #MateWeatherTimezone for UTC, or %NULL on error.
+ **/
+MateWeatherTimezone *
+mateweather_timezone_get_utc (void)
+{
+ MateWeatherTimezone *zone = NULL;
+
+ zone = g_slice_new0 (MateWeatherTimezone);
+ zone->ref_count = 1;
+ zone->id = g_strdup ("GMT");
+ zone->name = g_strdup (_("Greenwich Mean Time"));
+ zone->offset = 0;
+ zone->has_dst = FALSE;
+ zone->dst_offset = 0;
+
+ return zone;
+}
+
+/**
+ * mateweather_timezone_get_name:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's name; a translated, user-presentable string.
+ *
+ * Note that the returned name might not be unique among timezones,
+ * and may not make sense to the user unless it is presented along
+ * with the timezone's country's name (or in some context where the
+ * country is obvious).
+ *
+ * Return value: @zone's name
+ **/
+const char *
+mateweather_timezone_get_name (MateWeatherTimezone *zone)
+{
+ g_return_val_if_fail (zone != NULL, NULL);
+ return zone->name;
+}
+
+/**
+ * mateweather_timezone_get_tzid:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's tzdata identifier, eg "America/New_York".
+ *
+ * Return value: @zone's tzid
+ **/
+const char *
+mateweather_timezone_get_tzid (MateWeatherTimezone *zone)
+{
+ g_return_val_if_fail (zone != NULL, NULL);
+ return zone->id;
+}
+
+/**
+ * mateweather_timezone_get_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's standard offset from UTC, in minutes. Eg, a value of
+ * %120 would indicate "GMT+2".
+ *
+ * Return value: @zone's standard offset, in minutes
+ **/
+int
+mateweather_timezone_get_offset (MateWeatherTimezone *zone)
+{
+ g_return_val_if_fail (zone != NULL, 0);
+ return zone->offset;
+}
+
+/**
+ * mateweather_timezone_has_dst:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Checks if @zone observes daylight/summer time for part of the year.
+ *
+ * Return value: %TRUE if @zone observes daylight/summer time.
+ **/
+gboolean
+mateweather_timezone_has_dst (MateWeatherTimezone *zone)
+{
+ g_return_val_if_fail (zone != NULL, FALSE);
+ return zone->has_dst;
+}
+
+/**
+ * mateweather_timezone_get_dst_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's daylight/summer time offset from UTC, in minutes. Eg,
+ * a value of %120 would indicate "GMT+2". This is only meaningful if
+ * mateweather_timezone_has_dst() returns %TRUE.
+ *
+ * Return value: @zone's daylight/summer time offset, in minutes
+ **/
+int
+mateweather_timezone_get_dst_offset (MateWeatherTimezone *zone)
+{
+ g_return_val_if_fail (zone != NULL, 0);
+ g_return_val_if_fail (zone->has_dst, 0);
+ return zone->dst_offset;
+}
+
diff --git a/libmateweather/mateweather-timezone.h b/libmateweather/mateweather-timezone.h
new file mode 100644
index 0000000..58c5d2b
--- /dev/null
+++ b/libmateweather/mateweather-timezone.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-timezone.c - Timezone handling
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MATEWEATHER_TIMEZONE_H__
+#define __MATEWEATHER_TIMEZONE_H__
+
+#ifndef MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#error "libmateweather should only be used if you understand that it's subject to change, and is not supported as a fixed API/ABI or as part of the platform"
+#endif
+
+#include <glib-object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _MateWeatherTimezone MateWeatherTimezone;
+
+GType mateweather_timezone_get_type (void);
+#define MATEWEATHER_TYPE_TIMEZONE (mateweather_timezone_get_type ())
+
+const char *mateweather_timezone_get_name (MateWeatherTimezone *zone);
+const char *mateweather_timezone_get_tzid (MateWeatherTimezone *zone);
+int mateweather_timezone_get_offset (MateWeatherTimezone *zone);
+gboolean mateweather_timezone_has_dst (MateWeatherTimezone *zone);
+int mateweather_timezone_get_dst_offset (MateWeatherTimezone *zone);
+
+MateWeatherTimezone *mateweather_timezone_ref (MateWeatherTimezone *zone);
+void mateweather_timezone_unref (MateWeatherTimezone *zone);
+
+MateWeatherTimezone *mateweather_timezone_get_utc (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MATEWEATHER_TIMEZONE_H__ */
diff --git a/libmateweather/mateweather-uninstalled.pc.in b/libmateweather/mateweather-uninstalled.pc.in
new file mode 100644
index 0000000..ac37302
--- /dev/null
+++ b/libmateweather/mateweather-uninstalled.pc.in
@@ -0,0 +1,13 @@
+
+Name: MateWeather
+Description: MateWeather shared library
+Requires: glib-2.0 gobject-2.0 gdk-pixbuf-2.0 gtk+-2.0 mateconf-2.0
+Requires.private: libxml-2.0 libsoup-2.4
+Libs: ${pc_top_builddir}/${pcfiledir}/libmateweather.la
+Cflags: -I${pc_top_builddir}/${pcfiledir}/..
diff --git a/libmateweather/mateweather-win32.c b/libmateweather/mateweather-win32.c
new file mode 100644
index 0000000..1d3e197
--- /dev/null
+++ b/libmateweather/mateweather-win32.c
@@ -0,0 +1,100 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-win32.c - Win32 portability
+ *
+ * Copyright 2008, Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+
+#ifdef G_OS_WIN32
+
+#include <windows.h>
+
+#include "mateweather-win32.h"
+
+static HMODULE dll = NULL;
+
+/* Prototype first to silence gcc warning */
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL,
+ DWORD fdwReason,
+ LPVOID lpvReserved);
+
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL,
+ DWORD fdwReason,
+ LPVOID lpvReserved)
+{
+ if (fdwReason == DLL_PROCESS_ATTACH)
+ dll = hinstDLL;
+
+ return TRUE;
+}
+
+char *
+_mateweather_win32_get_zoneinfo_dir (void)
+{
+ static char *retval = NULL;
+ char *root;
+
+ if (retval)
+ return retval;
+
+ root = g_win32_get_package_installation_directory_of_module (dll);
+ retval = g_build_filename (root, "share/zoneinfo", NULL);
+ g_free (root);
+
+ return retval;
+}
+
+char *
+_mateweather_win32_get_locale_dir (void)
+{
+ static char *retval = NULL;
+ char *root;
+
+ if (retval)
+ return retval;
+
+ root = g_win32_get_package_installation_directory_of_module (dll);
+ retval = g_build_filename (root, "share/locale", NULL);
+ g_free (root);
+
+ return retval;
+}
+
+char *
+_mateweather_win32_get_xml_location_dir (void)
+{
+ static char *retval = NULL;
+ char *root;
+
+ if (retval)
+ return retval;
+
+ root = g_win32_get_package_installation_directory_of_module (dll);
+ retval = g_build_filename (root, "share/libmateweather", NULL);
+ g_free (root);
+
+ return retval;
+}
+
+#endif
diff --git a/libmateweather/mateweather-win32.h b/libmateweather/mateweather-win32.h
new file mode 100644
index 0000000..184ac4f
--- /dev/null
+++ b/libmateweather/mateweather-win32.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-win32.h - Win32 portability
+ *
+ * Copyright 2008, Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MATEWEATHER_WIN32_H__
+#define __MATEWEATHER_WIN32_H__
+
+#ifdef _WIN32
+
+#define localtime_r(t,tmp) (localtime (t) ? ((*tmp) = *localtime (t), tmp) : NULL)
+
+#undef MATELOCALEDIR
+#define MATELOCALEDIR _mateweather_win32_get_locale_dir ()
+
+#undef ZONEINFO_DIR
+#define ZONEINFO_DIR _mateweather_win32_get_zoneinfo_dir ()
+
+#undef MATEWEATHER_XML_LOCATION_DIR
+#define MATEWEATHER_XML_LOCATION_DIR _mateweather_win32_get_xml_location_dir ()
+
+char *_mateweather_win32_get_locale_dir (void);
+char *_mateweather_win32_get_zoneinfo_dir (void);
+char *_mateweather_win32_get_xml_location_dir (void);
+
+#endif
+
+#endif /* __MATEWEATHER_WIN32_H__ */
diff --git a/libmateweather/mateweather-xml.c b/libmateweather/mateweather-xml.c
new file mode 100644
index 0000000..5fee6fe
--- /dev/null
+++ b/libmateweather/mateweather-xml.c
@@ -0,0 +1,165 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-xml.c - Locations.xml parsing code
+ *
+ * Copyright (C) 2005 Ryan Lortie, 2004 Gareth Owen
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <locale.h>
+#include <gtk/gtk.h>
+#include <libxml/xmlreader.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-xml.h"
+#include "weather-priv.h"
+
+static gboolean
+mateweather_xml_parse_node (MateWeatherLocation *gloc,
+ GtkTreeStore *store, GtkTreeIter *parent)
+{
+ GtkTreeIter iter, *self = &iter;
+ MateWeatherLocation **children, *parent_loc;
+ MateWeatherLocationLevel level;
+ WeatherLocation *wloc;
+ const char *name;
+ int i;
+
+ name = mateweather_location_get_name (gloc);
+ children = mateweather_location_get_children (gloc);
+ level = mateweather_location_get_level (gloc);
+
+ if (!children[0] && level < MATEWEATHER_LOCATION_WEATHER_STATION) {
+ mateweather_location_free_children (gloc, children);
+ return TRUE;
+ }
+
+ switch (mateweather_location_get_level (gloc)) {
+ case MATEWEATHER_LOCATION_WORLD:
+ case MATEWEATHER_LOCATION_ADM2:
+ self = parent;
+ break;
+
+ case MATEWEATHER_LOCATION_REGION:
+ case MATEWEATHER_LOCATION_COUNTRY:
+ case MATEWEATHER_LOCATION_ADM1:
+ /* Create a row with a name but no WeatherLocation */
+ gtk_tree_store_append (store, &iter, parent);
+ gtk_tree_store_set (store, &iter,
+ MATEWEATHER_XML_COL_LOC, name,
+ -1);
+ break;
+
+ case MATEWEATHER_LOCATION_CITY:
+ /* If multiple children, treat this like a
+ * region/country/adm1. If a single child, merge with that
+ * location.
+ */
+ gtk_tree_store_append (store, &iter, parent);
+ gtk_tree_store_set (store, &iter,
+ MATEWEATHER_XML_COL_LOC, name,
+ -1);
+ if (children[0] && !children[1]) {
+ wloc = mateweather_location_to_weather_location (children[0], name);
+ gtk_tree_store_set (store, &iter,
+ MATEWEATHER_XML_COL_POINTER, wloc,
+ -1);
+ }
+ break;
+
+ case MATEWEATHER_LOCATION_WEATHER_STATION:
+ gtk_tree_store_append (store, &iter, parent);
+ gtk_tree_store_set (store, &iter,
+ MATEWEATHER_XML_COL_LOC, name,
+ -1);
+
+ parent_loc = mateweather_location_get_parent (gloc);
+ if (parent_loc && mateweather_location_get_level (parent_loc) == MATEWEATHER_LOCATION_CITY)
+ name = mateweather_location_get_name (parent_loc);
+ wloc = mateweather_location_to_weather_location (gloc, name);
+ gtk_tree_store_set (store, &iter,
+ MATEWEATHER_XML_COL_POINTER, wloc,
+ -1);
+ break;
+ }
+
+ for (i = 0; children[i]; i++) {
+ if (!mateweather_xml_parse_node (children[i], store, self)) {
+ mateweather_location_free_children (gloc, children);
+ return FALSE;
+ }
+ }
+
+ mateweather_location_free_children (gloc, children);
+ return TRUE;
+}
+
+GtkTreeModel *
+mateweather_xml_load_locations (void)
+{
+ MateWeatherLocation *world;
+ GtkTreeStore *store;
+
+ world = mateweather_location_new_world (TRUE);
+ if (!world)
+ return NULL;
+
+ store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
+
+ if (!mateweather_xml_parse_node (world, store, NULL)) {
+ mateweather_xml_free_locations ((GtkTreeModel *)store);
+ store = NULL;
+ }
+
+ mateweather_location_unref (world);
+
+ return (GtkTreeModel *)store;
+}
+
+static gboolean
+free_locations (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
+{
+ WeatherLocation *loc = NULL;
+
+ gtk_tree_model_get (model, iter,
+ MATEWEATHER_XML_COL_POINTER, &loc,
+ -1);
+
+ if (loc) {
+ weather_location_free (loc);
+ gtk_tree_store_set ((GtkTreeStore *)model, iter,
+ MATEWEATHER_XML_COL_POINTER, NULL,
+ -1);
+ }
+
+ return FALSE;
+}
+
+/* Frees model returned from @mateweather_xml_load_locations. It contains allocated
+ WeatherLocation-s, thus this takes care of the freeing of that memory. */
+void
+mateweather_xml_free_locations (GtkTreeModel *locations)
+{
+ if (locations && GTK_IS_TREE_STORE (locations)) {
+ gtk_tree_model_foreach (locations, free_locations, NULL);
+ g_object_unref (locations);
+ }
+}
diff --git a/libmateweather/mateweather-xml.h b/libmateweather/mateweather-xml.h
new file mode 100644
index 0000000..da53aab
--- /dev/null
+++ b/libmateweather/mateweather-xml.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-xml.h
+ *
+ * Copyright (C) 2004 Gareth Owen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MATEWEATHER_XML_H__
+#define __MATEWEATHER_XML_H__
+
+#include <gtk/gtk.h>
+#include <libmateweather/weather.h>
+
+enum
+{
+ MATEWEATHER_XML_COL_LOC = 0,
+ MATEWEATHER_XML_COL_POINTER,
+ MATEWEATHER_XML_NUM_COLUMNS
+};
+
+GtkTreeModel *mateweather_xml_load_locations (void);
+void mateweather_xml_free_locations (GtkTreeModel *locations);
+
+#endif /* __MATEWEATHER_XML_H__ */
diff --git a/libmateweather/mateweather.pc.in b/libmateweather/mateweather.pc.in
new file mode 100644
index 0000000..d332631
--- /dev/null
+++ b/libmateweather/mateweather.pc.in
@@ -0,0 +1,14 @@
+
+Name: MateWeather
+Description: MateWeather shared library
+Requires: glib-2.0 gobject-2.0 gdk-pixbuf-2.0 gtk+-2.0 mateconf-2.0
+Requires.private: libxml-2.0 libsoup-2.4
+Libs: -L${libdir} -lmateweather
+Libs.private: -lm
+Cflags: -I${includedir}
diff --git a/libmateweather/mateweather.schemas.in b/libmateweather/mateweather.schemas.in
new file mode 100644
index 0000000..3b81d35
--- /dev/null
+++ b/libmateweather/mateweather.schemas.in
@@ -0,0 +1,173 @@
+<mateconfschemafile>
+<schemalist>
+
+<schema>
+ <key>/schemas/apps/mateweather/prefs/auto_update</key>
+ <owner>mateweather-applet-2</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Update the data automatically</short>
+ <long>Determines whether the applet automatically updates its weather statistics or not.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/auto_update_interval</key>
+ <owner>mateweather-applet-2</owner>
+ <type>int</type>
+ <default>1800</default>
+ <locale name="C">
+ <short>Update interval</short>
+ <long>The interval, in seconds, between automatic updates.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/enable_metric</key>
+ <owner>mateweather-applet-2</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Use metric units</short>
+ <long>Use metric units instead of english units.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/distance_unit</key>
+ <owner>mateweather-applet-2</owner>
+ <type>string</type>
+ <default>Default</default>
+ <locale name="C">
+ <short>Distance unit</short>
+ <long>The unit to use for visibility.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/pressure_unit</key>
+ <owner>mateweather-applet-2</owner>
+ <type>string</type>
+ <default>Default</default>
+ <locale name="C">
+ <short>Pressure unit</short>
+ <long>The unit to use for pressure.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/speed_unit</key>
+ <owner>mateweather-applet-2</owner>
+ <type>string</type>
+ <default>Default</default>
+ <locale name="C">
+ <short>Speed unit</short>
+ <long>The unit to use for wind speed.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/temperature_unit</key>
+ <owner>mateweather-applet-2</owner>
+ <type>string</type>
+ <default>Default</default>
+ <locale name="C">
+ <short>Temperature unit</short>
+ <long>The unit to use for temperature.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/enable_detailed_forecast</key>
+ <owner>mateweather-applet-2</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Not used anymore</short>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/enable_radar_map</key>
+ <owner>mateweather-applet-2</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Display radar map</short>
+ <long>Fetch a radar map on each update.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/location0</key>
+ <owner>mateweather-applet-2</owner>
+ <type>string</type>
+ <locale name="C">
+ <default>DEFAULT_LOCATION</default>
+ <short>Weather location information</short>
+ <long>Weather location information.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/location1</key>
+ <owner>mateweather-applet-2</owner>
+ <type>string</type>
+ <locale name="C">
+ <default>DEFAULT_CODE</default>
+ <short>Nearby city</short>
+ <long>Nearby major zone, such as a capital city, as found from http://git.gnome.org/cgit/libmateweather/plain/data/Locations.xml.in</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/location2</key>
+ <owner>mateweather-applet-2</owner>
+ <type>string</type>
+ <locale name="C">
+ <default>DEFAULT_ZONE</default>
+ <short>Zone location</short>
+ <long>A unique zone for the city, as found from http://git.gnome.org/cgit/libmateweather/plain/data/Locations.xml.in</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/location3</key>
+ <owner>mateweather-applet-2</owner>
+ <type>string</type>
+ <locale name="C">
+ <default>DEFAULT_RADAR</default>
+ <short>Radar location</short>
+ <long>A three-digit-long code for retrieving radar maps from weather.com, found from http://git.gnome.org/cgit/libmateweather/plain/data/Locations.xml.in</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/location4</key>
+ <owner>mateweather-applet-2</owner>
+ <type>string</type>
+ <locale name="C">
+ <default>DEFAULT_LOCATION</default>
+ <short>Weather for a city</short>
+ <long>The city that mateweather displays information for.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/coordinates</key>
+ <owner>mateweather-applet-2</owner>
+ <type>string</type>
+ <locale name="C">
+ <default>DEFAULT_COORDINATES</default>
+ <short>Location coordinates</short>
+ <long>Latitude and longitude of your location expressed in DD-MM-SS[NS] DD-MM-SS[EW].</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/use_custom_radar_url</key>
+ <owner>mateweather-applet-2</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Use custom url for the radar map</short>
+ <long>If true, then retrieve a radar map from a location specified by the "radar" key.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/mateweather/prefs/radar</key>
+ <owner>mateweather-applet-2</owner>
+ <type>string</type>
+ <locale name="C">
+ <short>Url for the radar map</short>
+ <long>The custom url from where to retrieve a radar map.</long>
+ </locale>
+</schema>
+</schemalist>
+</mateconfschemafile>
diff --git a/libmateweather/parser.c b/libmateweather/parser.c
new file mode 100644
index 0000000..9e4bb63
--- /dev/null
+++ b/libmateweather/parser.c
@@ -0,0 +1,263 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* parser.c - Locations.xml parser
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#include "parser.h"
+
+#include <string.h>
+#include <glib.h>
+#include <libxml/xmlreader.h>
+
+/**
+ * mateweather_parser_get_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Gets the text of the element whose start tag @parser is pointing to.
+ * Leaves @parser pointing at the next node after the element's end tag.
+ *
+ * Return value: the text of the current node, as a libxml-allocated
+ * string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_value (MateWeatherParser *parser)
+{
+ char *value;
+
+ /* check for null node */
+ if (xmlTextReaderIsEmptyElement (parser->xml))
+ return NULL;
+
+ /* the next "node" is the text node containing the value we want to get */
+ if (xmlTextReaderRead (parser->xml) != 1)
+ return NULL;
+
+ value = (char *) xmlTextReaderValue (parser->xml);
+
+ /* move on to the end of this node */
+ while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+ if (xmlTextReaderRead (parser->xml) != 1) {
+ xmlFree (value);
+ return NULL;
+ }
+ }
+
+ /* consume the end element too */
+ if (xmlTextReaderRead (parser->xml) != 1) {
+ xmlFree (value);
+ return NULL;
+ }
+
+ return value;
+}
+
+/**
+ * mateweather_parser_get_localized_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Looks at the name of the element @parser is currently pointing to, and
+ * returns the content of either that node, or a following node with
+ * the same name but an "xml:lang" attribute naming one of the locale
+ * languages. Leaves @parser pointing to the next node after the last
+ * consecutive element with the same name as the original element.
+ *
+ * Return value: the localized (or unlocalized) text, as a
+ * libxml-allocated string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_localized_value (MateWeatherParser *parser)
+{
+ const char *this_language;
+ int best_match = INT_MAX;
+ const char *lang, *tagname, *next_tagname;
+ gboolean keep_going;
+ char *name = NULL;
+ int i;
+
+ tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+ do {
+ /* First let's get the language */
+ lang = (const char *) xmlTextReaderConstXmlLang (parser->xml);
+
+ if (lang == NULL)
+ this_language = "C";
+ else
+ this_language = lang;
+
+ /* the next "node" is text node containing the actual name */
+ if (xmlTextReaderRead (parser->xml) != 1) {
+ if (name)
+ xmlFree (name);
+ return NULL;
+ }
+
+ for (i = 0; parser->locales[i] && i < best_match; i++) {
+ if (!strcmp (parser->locales[i], this_language)) {
+ /* if we've already encounted a less accurate
+ translation, then free it */
+ g_free (name);
+
+ name = (char *) xmlTextReaderValue (parser->xml);
+ best_match = i;
+
+ break;
+ }
+ }
+
+ /* Skip to close tag */
+ while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+ if (xmlTextReaderRead (parser->xml) != 1) {
+ xmlFree (name);
+ return NULL;
+ }
+ }
+
+ /* Skip junk */
+ do {
+ if (xmlTextReaderRead (parser->xml) != 1) {
+ xmlFree (name);
+ return NULL;
+ }
+ } while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT &&
+ xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT);
+
+ /* if the next tag has the same name then keep going */
+ next_tagname = (const char *) xmlTextReaderConstName (parser->xml);
+ keep_going = !strcmp (next_tagname, tagname);
+
+ } while (keep_going);
+
+ return name;
+}
+
+MateWeatherParser *
+mateweather_parser_new (gboolean use_regions)
+{
+ MateWeatherParser *parser;
+ int zlib_support;
+ int i, keep_going;
+ char *filename;
+ char *tagname, *format;
+ time_t now;
+ struct tm tm;
+
+ parser = g_slice_new0 (MateWeatherParser);
+ parser->use_regions = use_regions;
+ parser->locales = g_get_language_names ();
+
+ zlib_support = xmlHasFeature (XML_WITH_ZLIB);
+
+ /* First try to load a locale-specific XML. It's much faster. */
+ filename = NULL;
+ for (i = 0; parser->locales[i] != NULL; i++) {
+ filename = g_strdup_printf ("%s/Locations.%s.xml",
+ MATEWEATHER_XML_LOCATION_DIR,
+ parser->locales[i]);
+
+ if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+ break;
+
+ g_free (filename);
+ filename = NULL;
+
+ if (!zlib_support)
+ continue;
+
+ filename = g_strdup_printf ("%s/Locations.%s.xml.gz",
+ MATEWEATHER_XML_LOCATION_DIR,
+ parser->locales[i]);
+
+ if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+ break;
+
+ g_free (filename);
+ filename = NULL;
+ }
+
+ /* Fall back on the file containing either all translations, or only
+ * the english names (depending on the configure flags).
+ */
+ if (!filename)
+ filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml", NULL);
+
+ if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR) && zlib_support) {
+ g_free (filename);
+ filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml.gz", NULL);
+ }
+
+ /* Open the xml file containing the different locations */
+ parser->xml = xmlNewTextReaderFilename (filename);
+ g_free (filename);
+
+ if (parser->xml == NULL)
+ goto error_out;
+
+ /* fast forward to the first element */
+ do {
+ /* if we encounter a problem here, exit right away */
+ if (xmlTextReaderRead (parser->xml) != 1)
+ goto error_out;
+ } while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT);
+
+ /* check the name and format */
+ tagname = (char *) xmlTextReaderName (parser->xml);
+ keep_going = tagname && !strcmp (tagname, "mateweather");
+ xmlFree (tagname);
+
+ if (!keep_going)
+ goto error_out;
+
+ format = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "format");
+ keep_going = format && !strcmp (format, "1.0");
+ xmlFree (format);
+
+ if (!keep_going)
+ goto error_out;
+
+ /* Get timestamps for the start and end of this year */
+ now = time (NULL);
+ tm = *gmtime (&now);
+ tm.tm_mon = 0;
+ tm.tm_mday = 1;
+ tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+ parser->year_start = mktime (&tm);
+ tm.tm_year++;
+ parser->year_end = mktime (&tm);
+
+ return parser;
+
+error_out:
+ mateweather_parser_free (parser);
+ return NULL;
+}
+
+void
+mateweather_parser_free (MateWeatherParser *parser)
+{
+ if (parser->xml)
+ xmlFreeTextReader (parser->xml);
+ g_slice_free (MateWeatherParser, parser);
+}
diff --git a/libmateweather/parser.h b/libmateweather/parser.h
new file mode 100644
index 0000000..6547490
--- /dev/null
+++ b/libmateweather/parser.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* parser.h - Locations.xml parser
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEWEATHER_PARSER_H
+#define MATEWEATHER_PARSER_H 1
+
+#include <libxml/xmlreader.h>
+#include "mateweather-timezone.h"
+
+typedef struct {
+ xmlTextReaderPtr xml;
+ const char * const *locales;
+ gboolean use_regions;
+ time_t year_start, year_end;
+} MateWeatherParser;
+
+MateWeatherParser *mateweather_parser_new (gboolean use_regions);
+void mateweather_parser_free (MateWeatherParser *parser);
+
+char *mateweather_parser_get_value (MateWeatherParser *parser);
+char *mateweather_parser_get_localized_value (MateWeatherParser *parser);
+
+/* from mateweather-timezone.c */
+MateWeatherTimezone **mateweather_timezones_parse_xml (MateWeatherParser *parser);
+
+#endif
diff --git a/libmateweather/test_locations.c b/libmateweather/test_locations.c
new file mode 100644
index 0000000..b0400c2
--- /dev/null
+++ b/libmateweather/test_locations.c
@@ -0,0 +1,65 @@
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "location-entry.h"
+#include "timezone-menu.h"
+
+static void
+deleted (GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ gtk_main_quit ();
+}
+
+static void
+location_changed (GObject *object, GParamSpec *param, gpointer tzmenu)
+{
+ MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+ MateWeatherLocation *loc;
+ MateWeatherTimezone *zone;
+
+ loc = mateweather_location_entry_get_location (entry);
+ g_return_if_fail (loc != NULL);
+ zone = mateweather_location_get_timezone (loc);
+ if (zone)
+ mateweather_timezone_menu_set_tzid (tzmenu, mateweather_timezone_get_tzid (zone));
+ else
+ mateweather_timezone_menu_set_tzid (tzmenu, NULL);
+ if (zone)
+ mateweather_timezone_unref (zone);
+ mateweather_location_unref (loc);
+}
+
+int
+main (int argc, char **argv)
+{
+ MateWeatherLocation *loc;
+ GtkWidget *window, *vbox, *entry;
+ GtkWidget *combo;
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "location");
+ gtk_container_set_border_width (GTK_CONTAINER (window), 8);
+ g_signal_connect (window, "delete-event",
+ G_CALLBACK (deleted), NULL);
+
+ vbox = gtk_vbox_new (FALSE, 8);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+
+ loc = mateweather_location_new_world (FALSE);
+ entry = mateweather_location_entry_new (loc);
+ gtk_widget_set_size_request (entry, 400, -1);
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, TRUE, 0);
+
+ combo = mateweather_timezone_menu_new (loc);
+ mateweather_location_unref (loc);
+ gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, TRUE, 0);
+
+ g_signal_connect (entry, "notify::location",
+ G_CALLBACK (location_changed), combo);
+
+ gtk_widget_show_all (window);
+
+ gtk_main ();
+
+ return 0;
+}
diff --git a/libmateweather/test_metar.c b/libmateweather/test_metar.c
new file mode 100644
index 0000000..b36e4d9
--- /dev/null
+++ b/libmateweather/test_metar.c
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Simple program to reproduce METAR parsing results from command line
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#ifndef BUFLEN
+#define BUFLEN 4096
+#endif /* BUFLEN */
+
+int
+main (int argc, char **argv)
+{
+ FILE* stream = stdin;
+ gchar* filename = NULL;
+ GOptionEntry entries[] = {
+ { "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
+ "file constaining metar observations", NULL },
+ { NULL }
+ };
+ GOptionContext* context;
+ GError* error = NULL;
+ char buf[BUFLEN];
+ int len;
+ WeatherInfo info;
+
+ context = g_option_context_new ("- test libmateweather metar parser");
+ g_option_context_add_main_entries (context, entries, NULL);
+ g_option_context_parse (context, &argc, &argv, &error);
+
+ if (error) {
+ perror (error->message);
+ return error->code;
+ }
+ if (filename) {
+ stream = fopen (filename, "r");
+ if (!stream) {
+ perror ("fopen");
+ return -1;
+ }
+ } else {
+ fprintf (stderr, "Enter a METAR string...\n");
+ }
+
+ while (fgets (buf, sizeof (buf), stream)) {
+ len = strlen (buf);
+ if (buf[len - 1] == '\n') {
+ buf[--len] = '\0';
+ }
+ printf ("\n%s\n", buf);
+
+ memset (&info, 0, sizeof (info));
+ info.valid = 1;
+ metar_parse (buf, &info);
+ weather_info_to_metric (&info);
+ printf ("Returned info:\n");
+ printf (" update: %s", ctime (&info.update));
+ printf (" sky: %s\n", weather_info_get_sky (&info));
+ printf (" cond: %s\n", weather_info_get_conditions (&info));
+ printf (" temp: %s\n", weather_info_get_temp (&info));
+ printf (" dewp: %s\n", weather_info_get_dew (&info));
+ printf (" wind: %s\n", weather_info_get_wind (&info));
+ printf (" pressure: %s\n", weather_info_get_pressure (&info));
+ printf (" vis: %s\n", weather_info_get_visibility (&info));
+
+ // TODO: retrieve location's lat/lon to display sunrise/set times
+ }
+ return 0;
+}
diff --git a/libmateweather/test_sun_moon.c b/libmateweather/test_sun_moon.c
new file mode 100644
index 0000000..9ee1fd7
--- /dev/null
+++ b/libmateweather/test_sun_moon.c
@@ -0,0 +1,90 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#include <glib.h>
+#include <string.h>
+#include <time.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+int
+main (int argc, char **argv)
+{
+ WeatherInfo info;
+ GOptionContext* context;
+ GError* error = NULL;
+ gdouble latitude, longitude;
+ WeatherLocation location;
+ gchar* gtime = NULL;
+ GDate gdate;
+ struct tm tm;
+ gboolean bsun, bmoon;
+ time_t phases[4];
+ const GOptionEntry entries[] = {
+ { "latitude", 0, 0, G_OPTION_ARG_DOUBLE, &latitude,
+ "observer's latitude in degrees north", NULL },
+ { "longitude", 0, 0, G_OPTION_ARG_DOUBLE, &longitude,
+ "observer's longitude in degrees east", NULL },
+ { "time", 0, 0, G_OPTION_ARG_STRING, &gtime,
+ "time in seconds from Unix epoch", NULL },
+ { NULL }
+ };
+
+ memset(&location, 0, sizeof(WeatherLocation));
+ memset(&info, 0, sizeof(WeatherInfo));
+
+ context = g_option_context_new ("- test libmateweather sun/moon calculations");
+ g_option_context_add_main_entries (context, entries, NULL);
+ g_option_context_parse (context, &argc, &argv, &error);
+
+ if (error) {
+ perror (error->message);
+ return error->code;
+ }
+ else if (latitude < -90. || latitude > 90.) {
+ perror ("invalid latitude: should be [-90 .. 90]");
+ return -1;
+ } else if (longitude < -180. || longitude > 180.) {
+ perror ("invalid longitude: should be [-180 .. 180]");
+ return -1;
+ }
+
+ location.latitude = DEGREES_TO_RADIANS(latitude);
+ location.longitude = DEGREES_TO_RADIANS(longitude);
+ location.latlon_valid = TRUE;
+ info.location = &location;
+ info.valid = TRUE;
+
+ if (gtime != NULL) {
+ // printf(" gtime=%s\n", gtime);
+ g_date_set_parse(&gdate, gtime);
+ g_date_to_struct_tm(&gdate, &tm);
+ info.update = mktime(&tm);
+ } else {
+ info.update = time(NULL);
+ }
+
+ bsun = calc_sun_time(&info, info.update);
+ bmoon = calc_moon(&info);
+
+ printf (" Latitude %7.3f %c Longitude %7.3f %c for %s All times UTC\n",
+ fabs(latitude), (latitude >= 0. ? 'N' : 'S'),
+ fabs(longitude), (longitude >= 0. ? 'E' : 'W'),
+ asctime(gmtime(&info.update)));
+ printf("sunrise: %s",
+ (info.sunriseValid ? ctime(&info.sunrise) : "(invalid)\n"));
+ printf("sunset: %s",
+ (info.sunsetValid ? ctime(&info.sunset) : "(invalid)\n"));
+ if (bmoon) {
+ printf("moonphase: %g\n", info.moonphase);
+ printf("moonlat: %g\n", info.moonlatitude);
+
+ if (calc_moon_phases(&info, phases)) {
+ printf(" New: %s", asctime(gmtime(&phases[0])));
+ printf(" 1stQ: %s", asctime(gmtime(&phases[1])));
+ printf(" Full: %s", asctime(gmtime(&phases[2])));
+ printf(" 3rdQ: %s", asctime(gmtime(&phases[3])));
+ }
+ }
+ return 0;
+}
diff --git a/libmateweather/timezone-menu.c b/libmateweather/timezone-menu.c
new file mode 100644
index 0000000..eb34931
--- /dev/null
+++ b/libmateweather/timezone-menu.c
@@ -0,0 +1,415 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* timezone-menu.c - Timezone-selecting menu
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "timezone-menu.h"
+#include "weather-priv.h"
+
+#include <string.h>
+
+/**
+ * MateWeatherTimezoneMenu:
+ *
+ * A #GtkComboBox subclass for choosing a #MateWeatherTimezone
+ **/
+
+G_DEFINE_TYPE (MateWeatherTimezoneMenu, mateweather_timezone_menu, GTK_TYPE_COMBO_BOX)
+
+enum {
+ PROP_0,
+
+ PROP_TOP,
+ PROP_TZID,
+
+ LAST_PROP
+};
+
+static void set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec);
+
+static void changed (GtkComboBox *combo);
+
+static GtkTreeModel *mateweather_timezone_model_new (MateWeatherLocation *top);
+static gboolean row_separator_func (GtkTreeModel *model, GtkTreeIter *iter,
+ gpointer data);
+static void is_sensitive (GtkCellLayout *cell_layout, GtkCellRenderer *cell,
+ GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data);
+
+static void
+mateweather_timezone_menu_init (MateWeatherTimezoneMenu *menu)
+{
+ GtkCellRenderer *renderer;
+
+ gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (menu),
+ row_separator_func, NULL, NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (menu), renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (menu), renderer,
+ "markup", 0,
+ NULL);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (menu),
+ renderer, is_sensitive, NULL, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+ MateWeatherTimezoneMenu *menu = MATEWEATHER_TIMEZONE_MENU (object);
+
+ if (menu->zone)
+ mateweather_timezone_unref (menu->zone);
+
+ G_OBJECT_CLASS (mateweather_timezone_menu_parent_class)->finalize (object);
+}
+
+static void
+mateweather_timezone_menu_class_init (MateWeatherTimezoneMenuClass *timezone_menu_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (timezone_menu_class);
+ GtkComboBoxClass *combo_class = GTK_COMBO_BOX_CLASS (timezone_menu_class);
+
+ object_class->finalize = finalize;
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+
+ combo_class->changed = changed;
+
+ /* properties */
+ g_object_class_install_property (
+ object_class, PROP_TOP,
+ g_param_spec_pointer ("top",
+ "Top Location",
+ "The MateWeatherLocation whose children will be used to fill in the menu",
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (
+ object_class, PROP_TZID,
+ g_param_spec_string ("tzid",
+ "TZID",
+ "The selected TZID",
+ NULL,
+ G_PARAM_READWRITE));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ GtkTreeModel *model;
+
+ switch (prop_id) {
+ case PROP_TOP:
+ model = mateweather_timezone_model_new (g_value_get_pointer (value));
+ gtk_combo_box_set_model (GTK_COMBO_BOX (object), model);
+ g_object_unref (model);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (object), 0);
+ break;
+
+ case PROP_TZID:
+ mateweather_timezone_menu_set_tzid (MATEWEATHER_TIMEZONE_MENU (object),
+ g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ MateWeatherTimezoneMenu *menu = MATEWEATHER_TIMEZONE_MENU (object);
+
+ switch (prop_id) {
+ case PROP_TZID:
+ g_value_set_string (value, mateweather_timezone_menu_get_tzid (menu));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+enum {
+ MATEWEATHER_TIMEZONE_MENU_NAME,
+ MATEWEATHER_TIMEZONE_MENU_ZONE
+};
+
+static void
+changed (GtkComboBox *combo)
+{
+ MateWeatherTimezoneMenu *menu = MATEWEATHER_TIMEZONE_MENU (combo);
+ GtkTreeIter iter;
+
+ if (menu->zone)
+ mateweather_timezone_unref (menu->zone);
+
+ gtk_combo_box_get_active_iter (combo, &iter);
+ gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
+ MATEWEATHER_TIMEZONE_MENU_ZONE, &menu->zone,
+ -1);
+
+ if (menu->zone)
+ mateweather_timezone_ref (menu->zone);
+
+ g_object_notify (G_OBJECT (combo), "tzid");
+}
+
+static void
+append_offset (GString *desc, int offset)
+{
+ int hours, minutes;
+
+ hours = offset / 60;
+ minutes = (offset > 0) ? offset % 60 : -offset % 60;
+
+ if (minutes)
+ g_string_append_printf (desc, "GMT%+d:%02d", hours, minutes);
+ else if (hours)
+ g_string_append_printf (desc, "GMT%+d", hours);
+ else
+ g_string_append (desc, "GMT");
+}
+
+static char *
+get_offset (MateWeatherTimezone *zone)
+{
+ GString *desc;
+
+ desc = g_string_new (NULL);
+ append_offset (desc, mateweather_timezone_get_offset (zone));
+ if (mateweather_timezone_has_dst (zone)) {
+ g_string_append (desc, " / ");
+ append_offset (desc, mateweather_timezone_get_dst_offset (zone));
+ }
+ return g_string_free (desc, FALSE);
+}
+
+static void
+insert_location (GtkTreeStore *store, MateWeatherTimezone *zone, const char *loc_name, GtkTreeIter *parent)
+{
+ GtkTreeIter iter;
+ char *name, *offset;
+
+ offset = get_offset (zone);
+ name = g_strdup_printf ("%s <small>(%s)</small>",
+ loc_name ? loc_name : mateweather_timezone_get_name (zone),
+ offset);
+ gtk_tree_store_append (store, &iter, parent);
+ gtk_tree_store_set (store, &iter,
+ MATEWEATHER_TIMEZONE_MENU_NAME, name,
+ MATEWEATHER_TIMEZONE_MENU_ZONE, mateweather_timezone_ref (zone),
+ -1);
+ g_free (name);
+ g_free (offset);
+}
+
+static void
+insert_locations (GtkTreeStore *store, MateWeatherLocation *loc)
+{
+ int i;
+
+ if (mateweather_location_get_level (loc) < MATEWEATHER_LOCATION_COUNTRY) {
+ MateWeatherLocation **children;
+
+ children = mateweather_location_get_children (loc);
+ for (i = 0; children[i]; i++)
+ insert_locations (store, children[i]);
+ mateweather_location_free_children (loc, children);
+ } else {
+ MateWeatherTimezone **zones;
+ GtkTreeIter iter;
+
+ zones = mateweather_location_get_timezones (loc);
+ if (zones[1]) {
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter,
+ MATEWEATHER_TIMEZONE_MENU_NAME, mateweather_location_get_name (loc),
+ -1);
+
+ for (i = 0; zones[i]; i++) {
+ insert_location (store, zones[i], NULL, &iter);
+ }
+ } else if (zones[0]) {
+ insert_location (store, zones[0], mateweather_location_get_name (loc), NULL);
+ }
+
+ mateweather_location_free_timezones (loc, zones);
+ }
+}
+
+static GtkTreeModel *
+mateweather_timezone_model_new (MateWeatherLocation *top)
+{
+ GtkTreeStore *store;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ char *unknown;
+ MateWeatherTimezone *utc;
+
+ store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
+ model = GTK_TREE_MODEL (store);
+
+ unknown = g_markup_printf_escaped ("<i>%s</i>", C_("timezone", "Unknown"));
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter,
+ MATEWEATHER_TIMEZONE_MENU_NAME, unknown,
+ MATEWEATHER_TIMEZONE_MENU_ZONE, NULL,
+ -1);
+
+ utc = mateweather_timezone_get_utc ();
+ if (utc) {
+ insert_location (store, utc, NULL, NULL);
+ mateweather_timezone_unref (utc);
+ }
+
+ gtk_tree_store_append (store, &iter, NULL);
+
+ g_free (unknown);
+
+ insert_locations (store, top);
+
+ return model;
+}
+
+static gboolean
+row_separator_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
+{
+ char *name;
+
+ gtk_tree_model_get (model, iter,
+ MATEWEATHER_TIMEZONE_MENU_NAME, &name,
+ -1);
+ if (name) {
+ g_free (name);
+ return FALSE;
+ } else
+ return TRUE;
+}
+
+static void
+is_sensitive (GtkCellLayout *cell_layout, GtkCellRenderer *cell,
+ GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+ gboolean sensitive;
+
+ sensitive = !gtk_tree_model_iter_has_child (tree_model, iter);
+ g_object_set (cell, "sensitive", sensitive, NULL);
+}
+
+/**
+ * mateweather_timezone_menu_new:
+ * @top: the top-level location for the menu.
+ *
+ * Creates a new #MateWeatherTimezoneMenu.
+ *
+ * @top will normally be a location returned from
+ * mateweather_location_new_world(), but you can create a menu that
+ * contains the timezones from a smaller set of locations if you want.
+ *
+ * Return value: the new #MateWeatherTimezoneMenu
+ **/
+GtkWidget *
+mateweather_timezone_menu_new (MateWeatherLocation *top)
+{
+ return g_object_new (MATEWEATHER_TYPE_TIMEZONE_MENU,
+ "top", top,
+ NULL);
+}
+
+typedef struct {
+ GtkComboBox *combo;
+ const char *tzid;
+} SetTimezoneData;
+
+static gboolean
+check_tzid (GtkTreeModel *model, GtkTreePath *path,
+ GtkTreeIter *iter, gpointer data)
+{
+ SetTimezoneData *tzd = data;
+ MateWeatherTimezone *zone;
+
+ gtk_tree_model_get (model, iter,
+ MATEWEATHER_TIMEZONE_MENU_ZONE, &zone,
+ -1);
+ if (!zone)
+ return FALSE;
+
+ if (!strcmp (mateweather_timezone_get_tzid (zone), tzd->tzid)) {
+ gtk_combo_box_set_active_iter (tzd->combo, iter);
+ return TRUE;
+ } else
+ return FALSE;
+}
+
+/**
+ * mateweather_timezone_menu_set_tzid:
+ * @menu: a #MateWeatherTimezoneMenu
+ * @tzid: (allow-none): a tzdata id (eg, "America/New_York")
+ *
+ * Sets @menu to the given @tzid. If @tzid is %NULL, sets @menu to
+ * "Unknown".
+ **/
+void
+mateweather_timezone_menu_set_tzid (MateWeatherTimezoneMenu *menu,
+ const char *tzid)
+{
+ SetTimezoneData tzd;
+
+ g_return_if_fail (MATEWEATHER_IS_TIMEZONE_MENU (menu));
+
+ if (!tzid) {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (menu), 0);
+ return;
+ }
+
+ tzd.combo = GTK_COMBO_BOX (menu);
+ tzd.tzid = tzid;
+ gtk_tree_model_foreach (gtk_combo_box_get_model (tzd.combo),
+ check_tzid, &tzd);
+}
+
+/**
+ * mateweather_timezone_menu_get_tzid:
+ * @menu: a #MateWeatherTimezoneMenu
+ *
+ * Gets @menu's timezone id.
+ *
+ * Return value: (allow-none): @menu's tzid, or %NULL if no timezone
+ * is selected.
+ **/
+const char *
+mateweather_timezone_menu_get_tzid (MateWeatherTimezoneMenu *menu)
+{
+ g_return_val_if_fail (MATEWEATHER_IS_TIMEZONE_MENU (menu), NULL);
+
+ if (!menu->zone)
+ return NULL;
+ return mateweather_timezone_get_tzid (menu->zone);
+}
+
diff --git a/libmateweather/timezone-menu.h b/libmateweather/timezone-menu.h
new file mode 100644
index 0000000..00d4b4b
--- /dev/null
+++ b/libmateweather/timezone-menu.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* timezone-menu.h - Timezone-selecting menu
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEWEATHER_TIMEZONE_MENU_H
+#define MATEWEATHER_TIMEZONE_MENU_H 1
+
+#include <gtk/gtk.h>
+#include <libmateweather/mateweather-location.h>
+
+#define MATEWEATHER_TYPE_TIMEZONE_MENU (mateweather_timezone_menu_get_type ())
+#define MATEWEATHER_TIMEZONE_MENU(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MATEWEATHER_TYPE_TIMEZONE_MENU, MateWeatherTimezoneMenu))
+#define MATEWEATHER_TIMEZONE_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MATEWEATHER_TYPE_TIMEZONE_MENU, MateWeatherTimezoneMenuClass))
+#define MATEWEATHER_IS_TIMEZONE_MENU(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MATEWEATHER_TYPE_TIMEZONE_MENU))
+#define MATEWEATHER_IS_TIMEZONE_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MATEWEATHER_TYPE_TIMEZONE_MENU))
+#define MATEWEATHER_TIMEZONE_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MATEWEATHER_TYPE_TIMEZONE_MENU, MateWeatherTimezoneMenuClass))
+
+typedef struct {
+ GtkComboBox parent;
+
+ /*< private >*/
+ MateWeatherTimezone *zone;
+} MateWeatherTimezoneMenu;
+
+typedef struct {
+ GtkComboBoxClass parent_class;
+
+} MateWeatherTimezoneMenuClass;
+
+GType mateweather_timezone_menu_get_type (void);
+
+GtkWidget *mateweather_timezone_menu_new (MateWeatherLocation *top);
+
+void mateweather_timezone_menu_set_tzid (MateWeatherTimezoneMenu *menu,
+ const char *tzid);
+const char *mateweather_timezone_menu_get_tzid (MateWeatherTimezoneMenu *menu);
+
+#endif
diff --git a/libmateweather/weather-bom.c b/libmateweather/weather-bom.c
new file mode 100644
index 0000000..ab0e558
--- /dev/null
+++ b/libmateweather/weather-bom.c
@@ -0,0 +1,82 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-bom.c - Australian Bureau of Meteorology forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static gchar *
+bom_parse (const gchar *meto)
+{
+ gchar *p, *rp;
+
+ g_return_val_if_fail (meto != NULL, NULL);
+
+ p = strstr (meto, "<pre>");
+ g_return_val_if_fail (p != NULL, NULL);
+
+ rp = strstr (p, "</pre>");
+ g_return_val_if_fail (rp !=NULL, NULL);
+
+ p += 5; /* skip the <pre> */
+
+ return g_strndup (p, rp-p);
+}
+
+static void
+bom_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+
+ g_return_if_fail (info != NULL);
+
+ if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+ g_warning ("Failed to get BOM forecast data: %d %s.\n",
+ msg->status_code, msg->reason_phrase);
+ request_done (info, FALSE);
+ return;
+ }
+
+ info->forecast = bom_parse (msg->response_body->data);
+ request_done (info, TRUE);
+}
+
+void
+bom_start_open (WeatherInfo *info)
+{
+ gchar *url;
+ SoupMessage *msg;
+ WeatherLocation *loc;
+
+ loc = info->location;
+
+ url = g_strdup_printf ("http://www.bom.gov.au/cgi-bin/wrap_fwo.pl?%s.txt",
+ loc->zone + 1);
+
+ msg = soup_message_new ("GET", url);
+ soup_session_queue_message (info->session, msg, bom_finish, info);
+ g_free (url);
+
+ info->requests_pending++;
+}
diff --git a/libmateweather/weather-iwin.c b/libmateweather/weather-iwin.c
new file mode 100644
index 0000000..e098354
--- /dev/null
+++ b/libmateweather/weather-iwin.c
@@ -0,0 +1,475 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-iwin.c - US National Weather Service IWIN forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+/**
+ * Humans don't deal well with .MONDAY...SUNNY AND BLAH BLAH.TUESDAY...THEN THIS AND THAT.WEDNESDAY...RAINY BLAH BLAH.
+ * This function makes it easier to read.
+ */
+static gchar *
+formatWeatherMsg (gchar *forecast)
+{
+ gchar *ptr = forecast;
+ gchar *startLine = NULL;
+
+ while (0 != *ptr) {
+ if (ptr[0] == '\n' && ptr[1] == '.') {
+ /* This removes the preamble by shifting the relevant data
+ * down to the start of the buffer. */
+ if (NULL == startLine) {
+ memmove (forecast, ptr, strlen (ptr) + 1);
+ ptr = forecast;
+ ptr[0] = ' ';
+ }
+ ptr[1] = '\n';
+ ptr += 2;
+ startLine = ptr;
+ } else if (ptr[0] == '.' && ptr[1] == '.' && ptr[2] == '.' && NULL != startLine) {
+ memmove (startLine + 2, startLine, (ptr - startLine) * sizeof (gchar));
+ startLine[0] = ' ';
+ startLine[1] = '\n';
+ ptr[2] = '\n';
+
+ ptr += 3;
+
+ } else if (ptr[0] == '$' && ptr[1] == '$') {
+ ptr[0] = ptr[1] = ' ';
+
+ } else {
+ ptr++;
+ }
+ }
+
+ return forecast;
+}
+
+static gboolean
+hasAttr (xmlNode *node, const char *attr_name, const char *attr_value)
+{
+ xmlChar *attr;
+ gboolean res = FALSE;
+
+ if (!node)
+ return res;
+
+ attr = xmlGetProp (node, (const xmlChar *) attr_name);
+
+ if (!attr)
+ return res;
+
+ res = g_str_equal ((const char *)attr, attr_value);
+
+ xmlFree (attr);
+
+ return res;
+}
+
+static GSList *
+parseForecastXml (const char *buff, WeatherInfo *master_info)
+{
+ GSList *res = NULL;
+ xmlDocPtr doc;
+ xmlNode *root, *node;
+
+ g_return_val_if_fail (master_info != NULL, NULL);
+
+ if (!buff || !*buff)
+ return NULL;
+
+ #define XC (const xmlChar *)
+ #define isElem(_node,_name) g_str_equal ((const char *)_node->name, _name)
+
+ doc = xmlParseMemory (buff, strlen (buff));
+ if (!doc)
+ return NULL;
+
+ /* Description at http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.pdf */
+ root = xmlDocGetRootElement (doc);
+ for (node = root->xmlChildrenNode; node; node = node->next) {
+ if (node->name == NULL || node->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (isElem (node, "data")) {
+ xmlNode *n;
+ char *time_layout = NULL;
+ time_t update_times[7] = {0};
+
+ for (n = node->children; n; n = n->next) {
+ if (!n->name)
+ continue;
+
+ if (isElem (n, "time-layout")) {
+ if (!time_layout && hasAttr (n, "summarization", "24hourly")) {
+ xmlNode *c;
+ int count = 0;
+
+ for (c = n->children; c && (count < 7 || !time_layout); c = c->next) {
+ if (c->name && !time_layout && isElem (c, "layout-key")) {
+ xmlChar *val = xmlNodeGetContent (c);
+
+ if (val) {
+ time_layout = g_strdup ((const char *)val);
+ xmlFree (val);
+ }
+ } else if (c->name && isElem (c, "start-valid-time")) {
+ xmlChar *val = xmlNodeGetContent (c);
+
+ if (val) {
+ GTimeVal tv;
+
+ if (g_time_val_from_iso8601 ((const char *)val, &tv)) {
+ update_times[count] = tv.tv_sec;
+ } else {
+ update_times[count] = 0;
+ }
+
+ count++;
+
+ xmlFree (val);
+ }
+ }
+ }
+
+ if (count != 7) {
+ /* There can be more than one time-layout element, the other
+ with only few children, which is not the one to use. */
+ g_free (time_layout);
+ time_layout = NULL;
+ }
+ }
+ } else if (isElem (n, "parameters")) {
+ xmlNode *p;
+
+ /* time-layout should be always before parameters */
+ if (!time_layout)
+ break;
+
+ if (!res) {
+ int i;
+
+ for (i = 0; i < 7; i++) {
+ WeatherInfo *nfo = weather_info_clone (master_info);
+
+ if (nfo) {
+ nfo->valid = FALSE;
+ nfo->forecast_type = FORECAST_ZONE;
+ nfo->update = update_times [i];
+ nfo->sky = -1;
+ nfo->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+ nfo->temp = -1000.0;
+ nfo->temp_min = -1000.0;
+ nfo->temp_max = -1000.0;
+ nfo->tempMinMaxValid = FALSE;
+ nfo->cond.significant = FALSE;
+ nfo->cond.phenomenon = PHENOMENON_NONE;
+ nfo->cond.qualifier = QUALIFIER_NONE;
+ nfo->dew = -1000.0;
+ nfo->wind = -1;
+ nfo->windspeed = -1;
+ nfo->pressure = -1.0;
+ nfo->visibility = -1.0;
+ nfo->sunriseValid = FALSE;
+ nfo->sunsetValid = FALSE;
+ nfo->sunrise = 0;
+ nfo->sunset = 0;
+ g_free (nfo->forecast);
+ nfo->forecast = NULL;
+ nfo->session = NULL;
+ nfo->requests_pending = 0;
+ nfo->finish_cb = NULL;
+ nfo->cb_data = NULL;
+ res = g_slist_append (res, nfo);
+ }
+ }
+ }
+
+ for (p = n->children; p; p = p->next) {
+ if (p->name && isElem (p, "temperature") && hasAttr (p, "time-layout", time_layout)) {
+ xmlNode *c;
+ GSList *at = res;
+ gboolean is_max = hasAttr (p, "type", "maximum");
+
+ if (!is_max && !hasAttr (p, "type", "minimum"))
+ break;
+
+ for (c = p->children; c && at; c = c->next) {
+ if (isElem (c, "value")) {
+ WeatherInfo *nfo = (WeatherInfo *)at->data;
+ xmlChar *val = xmlNodeGetContent (c);
+
+ /* can pass some values as <value xsi:nil="true"/> */
+ if (!val || !*val) {
+ if (is_max)
+ nfo->temp_max = nfo->temp_min;
+ else
+ nfo->temp_min = nfo->temp_max;
+ } else {
+ if (is_max)
+ nfo->temp_max = atof ((const char *)val);
+ else
+ nfo->temp_min = atof ((const char *)val);
+ }
+
+ if (val)
+ xmlFree (val);
+
+ nfo->tempMinMaxValid = nfo->tempMinMaxValid || (nfo->temp_max > -999.0 && nfo->temp_min > -999.0);
+ nfo->valid = nfo->tempMinMaxValid;
+
+ at = at->next;
+ }
+ }
+ } else if (p->name && isElem (p, "weather") && hasAttr (p, "time-layout", time_layout)) {
+ xmlNode *c;
+ GSList *at = res;
+
+ for (c = p->children; c && at; c = c->next) {
+ if (c->name && isElem (c, "weather-conditions")) {
+ WeatherInfo *nfo = at->data;
+ xmlChar *val = xmlGetProp (c, XC "weather-summary");
+
+ if (val && nfo) {
+ /* Checking from top to bottom, if 'value' contains 'name', then that win,
+ thus put longer (more precise) values to the top. */
+ int i;
+ struct _ph_list {
+ const char *name;
+ WeatherConditionPhenomenon ph;
+ } ph_list[] = {
+ { "Ice Crystals", PHENOMENON_ICE_CRYSTALS } ,
+ { "Volcanic Ash", PHENOMENON_VOLCANIC_ASH } ,
+ { "Blowing Sand", PHENOMENON_SANDSTORM } ,
+ { "Blowing Dust", PHENOMENON_DUSTSTORM } ,
+ { "Blowing Snow", PHENOMENON_FUNNEL_CLOUD } ,
+ { "Drizzle", PHENOMENON_DRIZZLE } ,
+ { "Rain", PHENOMENON_RAIN } ,
+ { "Snow", PHENOMENON_SNOW } ,
+ { "Fog", PHENOMENON_FOG } ,
+ { "Smoke", PHENOMENON_SMOKE } ,
+ { "Sand", PHENOMENON_SAND } ,
+ { "Haze", PHENOMENON_HAZE } ,
+ { "Dust", PHENOMENON_DUST } /*,
+ { "", PHENOMENON_SNOW_GRAINS } ,
+ { "", PHENOMENON_ICE_PELLETS } ,
+ { "", PHENOMENON_HAIL } ,
+ { "", PHENOMENON_SMALL_HAIL } ,
+ { "", PHENOMENON_UNKNOWN_PRECIPITATION } ,
+ { "", PHENOMENON_MIST } ,
+ { "", PHENOMENON_SPRAY } ,
+ { "", PHENOMENON_SQUALL } ,
+ { "", PHENOMENON_TORNADO } ,
+ { "", PHENOMENON_DUST_WHIRLS } */
+ };
+ struct _sky_list {
+ const char *name;
+ WeatherSky sky;
+ } sky_list[] = {
+ { "Mostly Sunny", SKY_BROKEN } ,
+ { "Mostly Clear", SKY_BROKEN } ,
+ { "Partly Cloudy", SKY_SCATTERED } ,
+ { "Mostly Cloudy", SKY_FEW } ,
+ { "Sunny", SKY_CLEAR } ,
+ { "Clear", SKY_CLEAR } ,
+ { "Cloudy", SKY_OVERCAST } ,
+ { "Clouds", SKY_SCATTERED } ,
+ { "Rain", SKY_SCATTERED } ,
+ { "Snow", SKY_SCATTERED }
+ };
+
+ nfo->valid = TRUE;
+ g_free (nfo->forecast);
+ nfo->forecast = g_strdup ((const char *)val);
+
+ for (i = 0; i < G_N_ELEMENTS (ph_list); i++) {
+ if (strstr ((const char *)val, ph_list [i].name)) {
+ nfo->cond.phenomenon = ph_list [i].ph;
+ break;
+ }
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (sky_list); i++) {
+ if (strstr ((const char *)val, sky_list [i].name)) {
+ nfo->sky = sky_list [i].sky;
+ break;
+ }
+ }
+ }
+
+ if (val)
+ xmlFree (val);
+
+ at = at->next;
+ }
+ }
+ }
+ }
+
+ if (res) {
+ gboolean have_any = FALSE;
+ GSList *r;
+
+ /* Remove invalid forecast data from the list.
+ They should be all valid or all invalid. */
+ for (r = res; r; r = r->next) {
+ WeatherInfo *nfo = r->data;
+
+ if (!nfo || !nfo->valid) {
+ if (r->data)
+ weather_info_free (r->data);
+
+ r->data = NULL;
+ } else {
+ have_any = TRUE;
+
+ if (nfo->tempMinMaxValid)
+ nfo->temp = (nfo->temp_min + nfo->temp_max) / 2.0;
+ }
+ }
+
+ if (!have_any) {
+ /* data members are freed already */
+ g_slist_free (res);
+ res = NULL;
+ }
+ }
+
+ break;
+ }
+ }
+
+ g_free (time_layout);
+
+ /* stop seeking XML */
+ break;
+ }
+ }
+ xmlFreeDoc (doc);
+
+ #undef XC
+ #undef isElem
+
+ return res;
+}
+
+static void
+iwin_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+
+ g_return_if_fail (info != NULL);
+
+ if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+ /* forecast data is not really interesting anyway ;) */
+ g_warning ("Failed to get IWIN forecast data: %d %s\n",
+ msg->status_code, msg->reason_phrase);
+ request_done (info, FALSE);
+ return;
+ }
+
+ if (info->forecast_type == FORECAST_LIST)
+ info->forecast_list = parseForecastXml (msg->response_body->data, info);
+ else
+ info->forecast = formatWeatherMsg (g_strdup (msg->response_body->data));
+
+ request_done (info, TRUE);
+}
+
+/* Get forecast into newly alloc'ed string */
+void
+iwin_start_open (WeatherInfo *info)
+{
+ gchar *url, *state, *zone;
+ WeatherLocation *loc;
+ SoupMessage *msg;
+
+ g_return_if_fail (info != NULL);
+ loc = info->location;
+ g_return_if_fail (loc != NULL);
+
+ if (loc->zone[0] == '-' && (info->forecast_type != FORECAST_LIST || !loc->latlon_valid))
+ return;
+
+ if (info->forecast) {
+ g_free (info->forecast);
+ info->forecast = NULL;
+ }
+
+ free_forecast_list (info);
+
+ if (info->forecast_type == FORECAST_LIST) {
+ /* see the description here: http://www.weather.gov/forecasts/xml/ */
+ if (loc->latlon_valid) {
+ struct tm tm;
+ time_t now = time (NULL);
+
+ localtime_r (&now, &tm);
+
+ url = g_strdup_printf ("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?&lat=%.02f&lon=%.02f&format=24+hourly&startDate=%04d-%02d-%02d&numDays=7",
+ RADIANS_TO_DEGREES (loc->latitude), RADIANS_TO_DEGREES (loc->longitude), 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday);
+
+ msg = soup_message_new ("GET", url);
+ g_free (url);
+ soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+ info->requests_pending++;
+ }
+
+ return;
+ }
+
+ if (loc->zone[0] == ':') {
+ /* Met Office Region Names */
+ metoffice_start_open (info);
+ return;
+ } else if (loc->zone[0] == '@') {
+ /* Australian BOM forecasts */
+ bom_start_open (info);
+ return;
+ }
+
+ /* The zone for Pittsburgh (for example) is given as PAZ021 in the locations
+ ** file (the PA stands for the state pennsylvania). The url used wants the state
+ ** as pa, and the zone as lower case paz021.
+ */
+ zone = g_ascii_strdown (loc->zone, -1);
+ state = g_strndup (zone, 2);
+
+ url = g_strdup_printf ("http://weather.noaa.gov/pub/data/forecasts/zone/%s/%s.txt", state, zone);
+
+ g_free (zone);
+ g_free (state);
+
+ msg = soup_message_new ("GET", url);
+ g_free (url);
+ soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+ info->requests_pending++;
+}
diff --git a/libmateweather/weather-met.c b/libmateweather/weather-met.c
new file mode 100644
index 0000000..8b47266
--- /dev/null
+++ b/libmateweather/weather-met.c
@@ -0,0 +1,179 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-met.c - UK Met Office forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static char *
+met_reprocess (char *x, int len)
+{
+ char *p = x;
+ char *o;
+ int spacing = 0;
+ static gchar *buf;
+ static gint buflen = 0;
+ gchar *lastspace = NULL;
+ int count = 0;
+
+ if (buflen < len)
+ {
+ if (buf)
+ g_free (buf);
+ buf = g_malloc (len + 1);
+ buflen = len;
+ }
+
+ o = buf;
+ x += len; /* End mark */
+
+ while (*p && p < x) {
+ if (g_ascii_isspace (*p)) {
+ if (!spacing) {
+ spacing = 1;
+ lastspace = o;
+ count++;
+ *o++ = ' ';
+ }
+ p++;
+ continue;
+ }
+ spacing = 0;
+ if (count > 75 && lastspace) {
+ count = o - lastspace - 1;
+ *lastspace = '\n';
+ lastspace = NULL;
+ }
+
+ if (*p == '&') {
+ if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
+ *o++ = '&';
+ count++;
+ p += 5;
+ continue;
+ }
+ if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
+ *o++ = '<';
+ count++;
+ p += 4;
+ continue;
+ }
+ if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
+ *o++ = '>';
+ count++;
+ p += 4;
+ continue;
+ }
+ }
+ if (*p == '<') {
+ if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
+ *o++ = '\n';
+ count = 0;
+ }
+ if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
+ *o++ = '\n';
+ *o++ = '\n';
+ count = 0;
+ }
+ p++;
+ while (*p && *p != '>')
+ p++;
+ if (*p)
+ p++;
+ continue;
+ }
+ *o++ = *p++;
+ count++;
+ }
+ *o = 0;
+ return buf;
+}
+
+
+/*
+ * Parse the metoffice forecast info.
+ * For mate 3.0 we want to just embed an HTML matecomponent component and
+ * be done with this ;)
+ */
+
+static gchar *
+met_parse (const gchar *meto)
+{
+ gchar *p;
+ gchar *rp;
+ gchar *r = g_strdup ("Met Office Forecast\n");
+ gchar *t;
+
+ g_return_val_if_fail (meto != NULL, r);
+
+ p = strstr (meto, "Summary: </b>");
+ g_return_val_if_fail (p != NULL, r);
+
+ rp = strstr (p, "Text issued at:");
+ g_return_val_if_fail (rp != NULL, r);
+
+ p += 13;
+ /* p to rp is the text block we want but in HTML malformat */
+ t = g_strconcat (r, met_reprocess (p, rp - p), NULL);
+ g_free (r);
+
+ return t;
+}
+
+static void
+met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+
+ g_return_if_fail (info != NULL);
+
+ if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+ g_warning ("Failed to get Met Office forecast data: %d %s.\n",
+ msg->status_code, msg->reason_phrase);
+ request_done (info, FALSE);
+ return;
+ }
+
+ info->forecast = met_parse (msg->response_body->data);
+ request_done (info, TRUE);
+}
+
+void
+metoffice_start_open (WeatherInfo *info)
+{
+ gchar *url;
+ SoupMessage *msg;
+ WeatherLocation *loc;
+
+ loc = info->location;
+ url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
+
+ msg = soup_message_new ("GET", url);
+ soup_session_queue_message (info->session, msg, met_finish, info);
+ g_free (url);
+
+ info->requests_pending++;
+}
diff --git a/libmateweather/weather-metar.c b/libmateweather/weather-metar.c
new file mode 100644
index 0000000..6dfcf9c
--- /dev/null
+++ b/libmateweather/weather-metar.c
@@ -0,0 +1,559 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-metar.c - Weather server functions (METAR)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+enum {
+ TIME_RE,
+ WIND_RE,
+ VIS_RE,
+ COND_RE,
+ CLOUD_RE,
+ TEMP_RE,
+ PRES_RE,
+
+ RE_NUM
+};
+
+/* Return time of weather report as secs since epoch UTC */
+static time_t
+make_time (gint utcDate, gint utcHour, gint utcMin)
+{
+ const time_t now = time (NULL);
+ struct tm tm;
+
+ localtime_r (&now, &tm);
+
+ /* If last reading took place just before midnight UTC on the
+ * first, adjust the date downward to allow for the month
+ * change-over. This ASSUMES that the reading won't be more than
+ * 24 hrs old! */
+ if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
+ tm.tm_mday = 0; /* mktime knows this is the last day of the previous
+ * month. */
+ } else {
+ tm.tm_mday = utcDate;
+ }
+ tm.tm_hour = utcHour;
+ tm.tm_min = utcMin;
+ tm.tm_sec = 0;
+
+ /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
+#ifdef HAVE_TM_TM_GMOFF
+ return tm.tm_gmtoff + mktime (&tm);
+#elif defined HAVE_TIMEZONE
+ return timezone + mktime (&tm);
+#endif
+}
+
+static void
+metar_tok_time (gchar *tokp, WeatherInfo *info)
+{
+ gint day, hr, min;
+
+ sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
+ info->update = make_time (day, hr, min);
+}
+
+static void
+metar_tok_wind (gchar *tokp, WeatherInfo *info)
+{
+ gchar sdir[4], sspd[4], sgust[4];
+ gint dir, spd = -1;
+ gchar *gustp;
+ size_t glen;
+
+ strncpy (sdir, tokp, 3);
+ sdir[3] = 0;
+ dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
+
+ memset (sspd, 0, sizeof (sspd));
+ glen = strspn (tokp + 3, CONST_DIGITS);
+ strncpy (sspd, tokp + 3, glen);
+ spd = atoi (sspd);
+ tokp += glen + 3;
+
+ gustp = strchr (tokp, 'G');
+ if (gustp) {
+ memset (sgust, 0, sizeof (sgust));
+ glen = strspn (gustp + 1, CONST_DIGITS);
+ strncpy (sgust, gustp + 1, glen);
+ tokp = gustp + 1 + glen;
+ }
+
+ if (!strcmp (tokp, "MPS"))
+ info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd);
+ else
+ info->windspeed = (WeatherWindSpeed)spd;
+
+ if ((349 <= dir) || (dir <= 11))
+ info->wind = WIND_N;
+ else if ((12 <= dir) && (dir <= 33))
+ info->wind = WIND_NNE;
+ else if ((34 <= dir) && (dir <= 56))
+ info->wind = WIND_NE;
+ else if ((57 <= dir) && (dir <= 78))
+ info->wind = WIND_ENE;
+ else if ((79 <= dir) && (dir <= 101))
+ info->wind = WIND_E;
+ else if ((102 <= dir) && (dir <= 123))
+ info->wind = WIND_ESE;
+ else if ((124 <= dir) && (dir <= 146))
+ info->wind = WIND_SE;
+ else if ((147 <= dir) && (dir <= 168))
+ info->wind = WIND_SSE;
+ else if ((169 <= dir) && (dir <= 191))
+ info->wind = WIND_S;
+ else if ((192 <= dir) && (dir <= 213))
+ info->wind = WIND_SSW;
+ else if ((214 <= dir) && (dir <= 236))
+ info->wind = WIND_SW;
+ else if ((237 <= dir) && (dir <= 258))
+ info->wind = WIND_WSW;
+ else if ((259 <= dir) && (dir <= 281))
+ info->wind = WIND_W;
+ else if ((282 <= dir) && (dir <= 303))
+ info->wind = WIND_WNW;
+ else if ((304 <= dir) && (dir <= 326))
+ info->wind = WIND_NW;
+ else if ((327 <= dir) && (dir <= 348))
+ info->wind = WIND_NNW;
+}
+
+static void
+metar_tok_vis (gchar *tokp, WeatherInfo *info)
+{
+ gchar *pfrac, *pend, *psp;
+ gchar sval[6];
+ gint num, den, val;
+
+ memset (sval, 0, sizeof (sval));
+
+ if (!strcmp (tokp,"CAVOK")) {
+ // "Ceiling And Visibility OK": visibility >= 10 KM
+ info->visibility=10000. / VISIBILITY_SM_TO_M (1.);
+ info->sky = SKY_CLEAR;
+ } else if (0 != (pend = strstr (tokp, "SM"))) {
+ // US observation: field ends with "SM"
+ pfrac = strchr (tokp, '/');
+ if (pfrac) {
+ if (*tokp == 'M') {
+ info->visibility = 0.001;
+ } else {
+ num = (*(pfrac - 1) - '0');
+ strncpy (sval, pfrac + 1, pend - pfrac - 1);
+ den = atoi (sval);
+ info->visibility =
+ ((WeatherVisibility)num / ((WeatherVisibility)den));
+
+ psp = strchr (tokp, ' ');
+ if (psp) {
+ *psp = '\0';
+ val = atoi (tokp);
+ info->visibility += (WeatherVisibility)val;
+ }
+ }
+ } else {
+ strncpy (sval, tokp, pend - tokp);
+ val = atoi (sval);
+ info->visibility = (WeatherVisibility)val;
+ }
+ } else {
+ // International observation: NNNN(DD NNNNDD)?
+ // For now: use only the minimum visibility and ignore its direction
+ strncpy (sval, tokp, strspn (tokp, CONST_DIGITS));
+ val = atoi (sval);
+ info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.);
+ }
+}
+
+static void
+metar_tok_cloud (gchar *tokp, WeatherInfo *info)
+{
+ gchar stype[4], salt[4];
+
+ strncpy (stype, tokp, 3);
+ stype[3] = 0;
+ if (strlen (tokp) == 6) {
+ strncpy (salt, tokp + 3, 3);
+ salt[3] = 0;
+ }
+
+ if (!strcmp (stype, "CLR")) {
+ info->sky = SKY_CLEAR;
+ } else if (!strcmp (stype, "SKC")) {
+ info->sky = SKY_CLEAR;
+ } else if (!strcmp (stype, "NSC")) {
+ info->sky = SKY_CLEAR;
+ } else if (!strcmp (stype, "BKN")) {
+ info->sky = SKY_BROKEN;
+ } else if (!strcmp (stype, "SCT")) {
+ info->sky = SKY_SCATTERED;
+ } else if (!strcmp (stype, "FEW")) {
+ info->sky = SKY_FEW;
+ } else if (!strcmp (stype, "OVC")) {
+ info->sky = SKY_OVERCAST;
+ }
+}
+
+static void
+metar_tok_pres (gchar *tokp, WeatherInfo *info)
+{
+ if (*tokp == 'A') {
+ gchar sintg[3], sfract[3];
+ gint intg, fract;
+
+ strncpy (sintg, tokp + 1, 2);
+ sintg[2] = 0;
+ intg = atoi (sintg);
+
+ strncpy (sfract, tokp + 3, 2);
+ sfract[2] = 0;
+ fract = atoi (sfract);
+
+ info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
+ } else { /* *tokp == 'Q' */
+ gchar spres[5];
+ gint pres;
+
+ strncpy (spres, tokp + 1, 4);
+ spres[4] = 0;
+ pres = atoi (spres);
+
+ info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres);
+ }
+}
+
+static void
+metar_tok_temp (gchar *tokp, WeatherInfo *info)
+{
+ gchar *ptemp, *pdew, *psep;
+
+ psep = strchr (tokp, '/');
+ *psep = 0;
+ ptemp = tokp;
+ pdew = psep + 1;
+
+ info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))
+ : TEMP_C_TO_F (atoi (ptemp));
+ if (*pdew) {
+ info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))
+ : TEMP_C_TO_F (atoi (pdew));
+ } else {
+ info->dew = -1000.0;
+ }
+}
+
+static void
+metar_tok_cond (gchar *tokp, WeatherInfo *info)
+{
+ gchar squal[3], sphen[4];
+ gchar *pphen;
+
+ if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
+ ++tokp; /* FIX */
+
+ if ((*tokp == '+') || (*tokp == '-'))
+ pphen = tokp + 1;
+ else if (strlen (tokp) < 4)
+ pphen = tokp;
+ else
+ pphen = tokp + 2;
+
+ memset (squal, 0, sizeof (squal));
+ strncpy (squal, tokp, pphen - tokp);
+ squal[pphen - tokp] = 0;
+
+ memset (sphen, 0, sizeof (sphen));
+ strncpy (sphen, pphen, sizeof (sphen));
+ sphen[sizeof (sphen)-1] = '\0';
+
+ /* Defaults */
+ info->cond.qualifier = QUALIFIER_NONE;
+ info->cond.phenomenon = PHENOMENON_NONE;
+ info->cond.significant = FALSE;
+
+ if (!strcmp (squal, "")) {
+ info->cond.qualifier = QUALIFIER_MODERATE;
+ } else if (!strcmp (squal, "-")) {
+ info->cond.qualifier = QUALIFIER_LIGHT;
+ } else if (!strcmp (squal, "+")) {
+ info->cond.qualifier = QUALIFIER_HEAVY;
+ } else if (!strcmp (squal, "VC")) {
+ info->cond.qualifier = QUALIFIER_VICINITY;
+ } else if (!strcmp (squal, "MI")) {
+ info->cond.qualifier = QUALIFIER_SHALLOW;
+ } else if (!strcmp (squal, "BC")) {
+ info->cond.qualifier = QUALIFIER_PATCHES;
+ } else if (!strcmp (squal, "PR")) {
+ info->cond.qualifier = QUALIFIER_PARTIAL;
+ } else if (!strcmp (squal, "TS")) {
+ info->cond.qualifier = QUALIFIER_THUNDERSTORM;
+ } else if (!strcmp (squal, "BL")) {
+ info->cond.qualifier = QUALIFIER_BLOWING;
+ } else if (!strcmp (squal, "SH")) {
+ info->cond.qualifier = QUALIFIER_SHOWERS;
+ } else if (!strcmp (squal, "DR")) {
+ info->cond.qualifier = QUALIFIER_DRIFTING;
+ } else if (!strcmp (squal, "FZ")) {
+ info->cond.qualifier = QUALIFIER_FREEZING;
+ } else {
+ return;
+ }
+
+ if (!strcmp (sphen, "DZ")) {
+ info->cond.phenomenon = PHENOMENON_DRIZZLE;
+ } else if (!strcmp (sphen, "RA")) {
+ info->cond.phenomenon = PHENOMENON_RAIN;
+ } else if (!strcmp (sphen, "SN")) {
+ info->cond.phenomenon = PHENOMENON_SNOW;
+ } else if (!strcmp (sphen, "SG")) {
+ info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
+ } else if (!strcmp (sphen, "IC")) {
+ info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
+ } else if (!strcmp (sphen, "PE")) {
+ info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
+ } else if (!strcmp (sphen, "GR")) {
+ info->cond.phenomenon = PHENOMENON_HAIL;
+ } else if (!strcmp (sphen, "GS")) {
+ info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
+ } else if (!strcmp (sphen, "UP")) {
+ info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
+ } else if (!strcmp (sphen, "BR")) {
+ info->cond.phenomenon = PHENOMENON_MIST;
+ } else if (!strcmp (sphen, "FG")) {
+ info->cond.phenomenon = PHENOMENON_FOG;
+ } else if (!strcmp (sphen, "FU")) {
+ info->cond.phenomenon = PHENOMENON_SMOKE;
+ } else if (!strcmp (sphen, "VA")) {
+ info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
+ } else if (!strcmp (sphen, "SA")) {
+ info->cond.phenomenon = PHENOMENON_SAND;
+ } else if (!strcmp (sphen, "HZ")) {
+ info->cond.phenomenon = PHENOMENON_HAZE;
+ } else if (!strcmp (sphen, "PY")) {
+ info->cond.phenomenon = PHENOMENON_SPRAY;
+ } else if (!strcmp (sphen, "DU")) {
+ info->cond.phenomenon = PHENOMENON_DUST;
+ } else if (!strcmp (sphen, "SQ")) {
+ info->cond.phenomenon = PHENOMENON_SQUALL;
+ } else if (!strcmp (sphen, "SS")) {
+ info->cond.phenomenon = PHENOMENON_SANDSTORM;
+ } else if (!strcmp (sphen, "DS")) {
+ info->cond.phenomenon = PHENOMENON_DUSTSTORM;
+ } else if (!strcmp (sphen, "PO")) {
+ info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
+ } else if (!strcmp (sphen, "+FC")) {
+ info->cond.phenomenon = PHENOMENON_TORNADO;
+ } else if (!strcmp (sphen, "FC")) {
+ info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
+ } else {
+ return;
+ }
+
+ if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
+ info->cond.significant = TRUE;
+}
+
+#define TIME_RE_STR "([0-9]{6})Z"
+#define WIND_RE_STR "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
+#define VIS_RE_STR "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
+ "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
+ "CAVOK"
+#define COND_RE_STR "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
+#define CLOUD_RE_STR "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
+#define TEMP_RE_STR "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
+#define PRES_RE_STR "(A|Q)([0-9]{4})"
+
+/* POSIX regular expressions do not allow us to express "match whole words
+ * only" in a simple way, so we have to wrap them all into
+ * (^| )(...regex...)( |$)
+ */
+#define RE_PREFIX "(^| )("
+#define RE_SUFFIX ")( |$)"
+
+static regex_t metar_re[RE_NUM];
+static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
+
+static void
+metar_init_re (void)
+{
+ static gboolean initialized = FALSE;
+ if (initialized)
+ return;
+ initialized = TRUE;
+
+ regcomp (&metar_re[TIME_RE], RE_PREFIX TIME_RE_STR RE_SUFFIX, REG_EXTENDED);
+ regcomp (&metar_re[WIND_RE], RE_PREFIX WIND_RE_STR RE_SUFFIX, REG_EXTENDED);
+ regcomp (&metar_re[VIS_RE], RE_PREFIX VIS_RE_STR RE_SUFFIX, REG_EXTENDED);
+ regcomp (&metar_re[COND_RE], RE_PREFIX COND_RE_STR RE_SUFFIX, REG_EXTENDED);
+ regcomp (&metar_re[CLOUD_RE], RE_PREFIX CLOUD_RE_STR RE_SUFFIX, REG_EXTENDED);
+ regcomp (&metar_re[TEMP_RE], RE_PREFIX TEMP_RE_STR RE_SUFFIX, REG_EXTENDED);
+ regcomp (&metar_re[PRES_RE], RE_PREFIX PRES_RE_STR RE_SUFFIX, REG_EXTENDED);
+
+ metar_f[TIME_RE] = metar_tok_time;
+ metar_f[WIND_RE] = metar_tok_wind;
+ metar_f[VIS_RE] = metar_tok_vis;
+ metar_f[COND_RE] = metar_tok_cond;
+ metar_f[CLOUD_RE] = metar_tok_cloud;
+ metar_f[TEMP_RE] = metar_tok_temp;
+ metar_f[PRES_RE] = metar_tok_pres;
+}
+
+gboolean
+metar_parse (gchar *metar, WeatherInfo *info)
+{
+ gchar *p;
+ //gchar *rmk;
+ gint i, i2;
+ regmatch_t rm, rm2;
+ gchar *tokp;
+
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (metar != NULL, FALSE);
+
+ metar_init_re ();
+
+ /*
+ * Force parsing to end at "RMK" field. This prevents a subtle
+ * problem when info within the remark happens to match an earlier state
+ * and, as a result, throws off all the remaining expression
+ */
+ if (0 != (p = strstr (metar, " RMK "))) {
+ *p = '\0';
+ //rmk = p + 5; // uncomment this if RMK data becomes useful
+ }
+
+ p = metar;
+ i = TIME_RE;
+ while (*p) {
+
+ i2 = RE_NUM;
+ rm2.rm_so = strlen (p);
+ rm2.rm_eo = rm2.rm_so;
+
+ for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
+ if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
+ && rm.rm_so < rm2.rm_so)
+ {
+ i2 = i;
+ /* Skip leading and trailing space characters, if present.
+ (the regular expressions include those characters to
+ only get matches limited to whole words). */
+ if (p[rm.rm_so] == ' ') rm.rm_so++;
+ if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
+ rm2.rm_so = rm.rm_so;
+ rm2.rm_eo = rm.rm_eo;
+ }
+ }
+
+ if (i2 != RE_NUM) {
+ tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
+ metar_f[i2] (tokp, info);
+ g_free (tokp);
+ }
+
+ p += rm2.rm_eo;
+ p += strspn (p, " ");
+ }
+ return TRUE;
+}
+
+static void
+metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+ WeatherLocation *loc;
+ const gchar *p, *eoln;
+ gchar *searchkey, *metar;
+ gboolean success = FALSE;
+
+ g_return_if_fail (info != NULL);
+
+ if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+ if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
+ info->network_error = TRUE;
+ else {
+ /* Translators: %d is an error code, and %s the error string */
+ g_warning (_("Failed to get METAR data: %d %s.\n"),
+ msg->status_code, msg->reason_phrase);
+ }
+ request_done (info, FALSE);
+ return;
+ }
+
+ loc = info->location;
+
+ searchkey = g_strdup_printf ("\n%s", loc->code);
+ p = strstr (msg->response_body->data, searchkey);
+ g_free (searchkey);
+ if (p) {
+ p += WEATHER_LOCATION_CODE_LEN + 2;
+ eoln = strchr(p, '\n');
+ if (eoln)
+ metar = g_strndup (p, eoln - p);
+ else
+ metar = g_strdup (p);
+ success = metar_parse (metar, info);
+ g_free (metar);
+ } else if (!strstr (msg->response_body->data, "National Weather Service")) {
+ /* The response doesn't even seem to have come from NWS...
+ * most likely it is a wifi hotspot login page. Call that a
+ * network error.
+ */
+ info->network_error = TRUE;
+ }
+
+ info->valid = success;
+ request_done (info, TRUE);
+}
+
+/* Read current conditions and fill in info structure */
+void
+metar_start_open (WeatherInfo *info)
+{
+ WeatherLocation *loc;
+ SoupMessage *msg;
+
+ g_return_if_fail (info != NULL);
+ info->valid = info->network_error = FALSE;
+ loc = info->location;
+ if (loc == NULL) {
+ g_warning (_("WeatherInfo missing location"));
+ return;
+ }
+
+ msg = soup_form_request_new (
+ "GET", "http://weather.noaa.gov/cgi-bin/mgetmetar.pl",
+ "cccc", loc->code,
+ NULL);
+ soup_session_queue_message (info->session, msg, metar_finish, info);
+
+ info->requests_pending++;
+}
diff --git a/libmateweather/weather-moon.c b/libmateweather/weather-moon.c
new file mode 100644
index 0000000..99f0a25
--- /dev/null
+++ b/libmateweather/weather-moon.c
@@ -0,0 +1,198 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-moon.c - Lunar calculations for mateweather
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Formulas from:
+ * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
+ * Cambridge University Press 1988
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#endif
+
+#include <math.h>
+#include <time.h>
+#include <string.h>
+#include <glib.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+/*
+ * Elements of the Moon's matecorba, epoch 2000 Jan 1.5
+ * http://ssd.jpl.nasa.gov/?sat_elem#earth
+ * The page only lists most values to 2 decimal places
+ */
+
+#define LUNAR_MEAN_LONGITUDE 218.316
+#define LUNAR_PERIGEE_MEAN_LONG 318.15
+#define LUNAR_NODE_MEAN_LONG 125.08
+#define LUNAR_PROGRESSION 13.176358
+#define LUNAR_INCLINATION DEGREES_TO_RADIANS(5.145396)
+
+/**
+ * calc_moon:
+ * @info: WeatherInfo containing time_t of interest. The
+ * values moonphase, moonlatitude and moonValid are updated
+ * on success.
+ *
+ * Returns: gboolean indicating success or failure.
+ * moonphase is expressed as degrees where '0' is a new moon,
+ * '90' is first quarter, etc.
+ */
+
+gboolean
+calc_moon (WeatherInfo *info)
+{
+ time_t t;
+ gdouble ra_h;
+ gdouble decl_r;
+ gdouble ndays, sunMeanAnom_d;
+ gdouble moonLong_d;
+ gdouble moonMeanAnom_d, moonMeanAnom_r;
+ gdouble sunEclipLong_r;
+ gdouble ascNodeMeanLong_d;
+ gdouble corrLong_d, eviction_d;
+ gdouble sinSunMeanAnom;
+ gdouble Ae, A3, Ec, A4, lN_r;
+ gdouble lambda_r, beta_r;
+
+ /*
+ * The comments refer to the enumerated steps to calculate the
+ * position of the moon (section 65 of above reference)
+ */
+ t = info->update;
+ ndays = EPOCH_TO_J2000(t) / 86400.;
+ sunMeanAnom_d = fmod (MEAN_ECLIPTIC_LONGITUDE (ndays) - PERIGEE_LONGITUDE (ndays),
+ 360.);
+ sunEclipLong_r = sunEclipLongitude (t);
+ moonLong_d = fmod (LUNAR_MEAN_LONGITUDE + (ndays * LUNAR_PROGRESSION),
+ 360.);
+ /* 5: moon's mean anomaly */
+ moonMeanAnom_d = fmod ((moonLong_d - (0.1114041 * ndays)
+ - (LUNAR_PERIGEE_MEAN_LONG + LUNAR_NODE_MEAN_LONG)),
+ 360.);
+ /* 6: ascending node mean longitude */
+ ascNodeMeanLong_d = fmod (LUNAR_NODE_MEAN_LONG - (0.0529539 * ndays),
+ 360.);
+ eviction_d = 1.2739 /* 7: eviction */
+ * sin (DEGREES_TO_RADIANS (2.0 * (moonLong_d - RADIANS_TO_DEGREES (sunEclipLong_r))
+ - moonMeanAnom_d));
+ sinSunMeanAnom = sin (DEGREES_TO_RADIANS (sunMeanAnom_d));
+ Ae = 0.1858 * sinSunMeanAnom;
+ A3 = 0.37 * sinSunMeanAnom; /* 8: annual equation */
+ moonMeanAnom_d += eviction_d - Ae - A3; /* 9: "third correction" */
+ moonMeanAnom_r = DEGREES_TO_RADIANS (moonMeanAnom_d);
+ Ec = 6.2886 * sin (moonMeanAnom_r); /* 10: equation of center */
+ A4 = 0.214 * sin (2.0 * moonMeanAnom_r); /* 11: "yet another correction" */
+
+ /* Steps 12-14 give the true longitude after correcting for variation */
+ moonLong_d += eviction_d + Ec - Ae + A4
+ + (0.6583 * sin (2.0 * (moonMeanAnom_r - sunEclipLong_r)));
+
+ /* 15: corrected longitude of node */
+ corrLong_d = ascNodeMeanLong_d - 0.16 * sinSunMeanAnom;
+
+ /*
+ * Calculate ecliptic latitude (16-19) and longitude (20) of the moon,
+ * then convert to right ascension and declination.
+ */
+ lN_r = DEGREES_TO_RADIANS (moonLong_d - corrLong_d); /* l''-N' */
+ lambda_r = DEGREES_TO_RADIANS(corrLong_d)
+ + atan2 (sin (lN_r) * cos (LUNAR_INCLINATION), cos (lN_r));
+ beta_r = asin (sin (lN_r) * sin (LUNAR_INCLINATION));
+ ecl2equ (t, lambda_r, beta_r, &ra_h, &decl_r);
+
+ /*
+ * The phase is the angle from the sun's longitude to the moon's
+ */
+ info->moonphase =
+ fmod (15.*ra_h - RADIANS_TO_DEGREES (sunEclipLongitude (info->update)),
+ 360.);
+ if (info->moonphase < 0)
+ info->moonphase += 360;
+ info->moonlatitude = RADIANS_TO_DEGREES (decl_r);
+ info->moonValid = TRUE;
+
+ return TRUE;
+}
+
+
+/**
+ * calc_moon_phases:
+ * @info: WeatherInfo containing the time_t of interest
+ * @phases: An array of four time_t values that will hold the returned values.
+ * The values are estimates of the time of the next new, quarter, full and
+ * three-quarter moons.
+ *
+ * Returns: gboolean indicating success or failure
+ */
+
+gboolean
+calc_moon_phases (WeatherInfo *info, time_t *phases)
+{
+ WeatherInfo temp;
+ time_t *ptime;
+ int idx;
+ gdouble advance;
+ int iter;
+ time_t dtime;
+
+ g_return_val_if_fail (info != NULL &&
+ (info->moonValid || calc_moon (info)),
+ FALSE);
+
+ ptime = phases;
+ memset(&temp, 0, sizeof(WeatherInfo));
+
+ for (idx = 0; idx < 4; idx++) {
+ temp.update = info->update;
+ temp.moonphase = info->moonphase;
+
+ /*
+ * First estimate on how far the moon needs to advance
+ * to get to the required phase
+ */
+ advance = (idx * 90.) - info->moonphase;
+ if (advance < 0.)
+ advance += 360.;
+
+ for (iter = 0; iter < 10; iter++) {
+ /* Convert angle change (degrees) to dtime (seconds) */
+ dtime = advance / LUNAR_PROGRESSION * 86400.;
+ if ((dtime > -10) && (dtime < 10))
+ break;
+ temp.update += dtime;
+ (void)calc_moon (&temp);
+
+ if (idx == 0 && temp.moonphase > 180.) {
+ advance = 360. - temp.moonphase;
+ } else {
+ advance = (idx * 90.) - temp.moonphase;
+ }
+ }
+ *ptime++ = temp.update;
+ }
+
+ return TRUE;
+}
diff --git a/libmateweather/weather-priv.h b/libmateweather/weather-priv.h
new file mode 100644
index 0000000..ccc7c2a
--- /dev/null
+++ b/libmateweather/weather-priv.h
@@ -0,0 +1,195 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-priv.h - Private header for weather server functions.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __WEATHER_PRIV_H_
+#define __WEATHER_PRIV_H_
+
+#include "config.h"
+
+#include <time.h>
+#include <libintl.h>
+#include <math.h>
+#ifdef HAVE_LIBSOUP_MATE
+#include <libsoup/soup-mate.h>
+#else
+#include <libsoup/soup.h>
+#endif
+
+#include "weather.h"
+#include "mateweather-location.h"
+
+#ifdef _WIN32
+#include "mateweather-win32.h"
+#endif
+
+const char *mateweather_gettext (const char *str) G_GNUC_FORMAT (1);
+const char *mateweather_dpgettext (const char *context, const char *str) G_GNUC_FORMAT (2);
+#define _(str) (mateweather_gettext (str))
+#define C_(context, str) (mateweather_dpgettext (context, str))
+#define N_(str) (str)
+
+
+#define WEATHER_LOCATION_CODE_LEN 4
+
+WeatherLocation *mateweather_location_to_weather_location (MateWeatherLocation *gloc,
+ const char *name);
+
+/*
+ * Weather information.
+ */
+
+struct _WeatherConditions {
+ gboolean significant;
+ WeatherConditionPhenomenon phenomenon;
+ WeatherConditionQualifier qualifier;
+};
+
+typedef struct _WeatherConditions WeatherConditions;
+
+typedef gdouble WeatherTemperature;
+typedef gdouble WeatherHumidity;
+typedef gdouble WeatherWindSpeed;
+typedef gdouble WeatherPressure;
+typedef gdouble WeatherVisibility;
+typedef time_t WeatherUpdate;
+
+struct _WeatherInfo {
+ WeatherForecastType forecast_type;
+
+ TempUnit temperature_unit;
+ SpeedUnit speed_unit;
+ PressureUnit pressure_unit;
+ DistanceUnit distance_unit;
+
+ gboolean valid;
+ gboolean network_error;
+ gboolean sunriseValid;
+ gboolean sunsetValid;
+ gboolean midnightSun;
+ gboolean polarNight;
+ gboolean moonValid;
+ gboolean tempMinMaxValid;
+ WeatherLocation *location;
+ WeatherUpdate update;
+ WeatherSky sky;
+ WeatherConditions cond;
+ WeatherTemperature temp;
+ WeatherTemperature temp_min;
+ WeatherTemperature temp_max;
+ WeatherTemperature dew;
+ WeatherWindDirection wind;
+ WeatherWindSpeed windspeed;
+ WeatherPressure pressure;
+ WeatherVisibility visibility;
+ WeatherUpdate sunrise;
+ WeatherUpdate sunset;
+ WeatherMoonPhase moonphase;
+ WeatherMoonLatitude moonlatitude;
+ gchar *forecast;
+ GSList *forecast_list; /* list of WeatherInfo* for the forecast, NULL if not available */
+ gchar *radar_buffer;
+ gchar *radar_url;
+ GdkPixbufLoader *radar_loader;
+ GdkPixbufAnimation *radar;
+ SoupSession *session;
+ gint requests_pending;
+
+ WeatherInfoFunc finish_cb;
+ gpointer cb_data;
+};
+
+/*
+ * Enum -> string conversions.
+ */
+
+const gchar * weather_wind_direction_string (WeatherWindDirection wind);
+const gchar * weather_sky_string (WeatherSky sky);
+const gchar * weather_conditions_string (WeatherConditions cond);
+
+/* Values common to the parsing source files */
+
+#define DATA_SIZE 5000
+
+#define CONST_DIGITS "0123456789"
+#define CONST_ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+/* Units conversions and names */
+
+#define TEMP_F_TO_C(f) (((f) - 32.0) * 0.555556)
+#define TEMP_F_TO_K(f) (TEMP_F_TO_C (f) + 273.15)
+#define TEMP_C_TO_F(c) (((c) * 1.8) + 32.0)
+
+#define WINDSPEED_KNOTS_TO_KPH(knots) ((knots) * 1.851965)
+#define WINDSPEED_KNOTS_TO_MPH(knots) ((knots) * 1.150779)
+#define WINDSPEED_KNOTS_TO_MS(knots) ((knots) * 0.514444)
+#define WINDSPEED_MS_TO_KNOTS(ms) ((ms) / 0.514444)
+/* 1 bft ~= (1 m/s / 0.836) ^ (2/3) */
+#define WINDSPEED_KNOTS_TO_BFT(knots) (pow ((knots) * 0.615363, 0.666666))
+
+#define PRESSURE_INCH_TO_KPA(inch) ((inch) * 3.386)
+#define PRESSURE_INCH_TO_HPA(inch) ((inch) * 33.86)
+#define PRESSURE_INCH_TO_MM(inch) ((inch) * 25.40005)
+#define PRESSURE_INCH_TO_MB(inch) (PRESSURE_INCH_TO_HPA (inch))
+#define PRESSURE_INCH_TO_ATM(inch) ((inch) * 0.033421052)
+#define PRESSURE_MBAR_TO_INCH(mbar) ((mbar) * 0.029533373)
+
+#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)
+
+/*
+ * Planetary Mean Orbit and their progressions from J2000 are based on the
+ * values in http://ssd.jpl.nasa.gov/txt/aprx_pos_planets.pdf
+ * converting longitudes from heliocentric to geocentric coordinates (+180)
+ */
+#define EPOCH_TO_J2000(t) ((gdouble)(t)-946727935.816)
+#define MEAN_ECLIPTIC_LONGITUDE(d) (280.46457166 + (d)/36525.*35999.37244981)
+#define SOL_PROGRESSION (360./365.242191)
+#define PERIGEE_LONGITUDE(d) (282.93768193 + (d)/36525.*0.32327364)
+
+void metar_start_open (WeatherInfo *info);
+void iwin_start_open (WeatherInfo *info);
+void metoffice_start_open (WeatherInfo *info);
+void bom_start_open (WeatherInfo *info);
+void wx_start_open (WeatherInfo *info);
+
+gboolean metar_parse (gchar *metar,
+ WeatherInfo *info);
+
+gboolean requests_init (WeatherInfo *info);
+void request_done (WeatherInfo *info,
+ gboolean ok);
+
+void ecl2equ (gdouble t,
+ gdouble eclipLon,
+ gdouble eclipLat,
+ gdouble *ra,
+ gdouble *decl);
+gdouble sunEclipLongitude (time_t t);
+gboolean calc_sun (WeatherInfo *info);
+gboolean calc_sun_time (WeatherInfo *info, time_t t);
+gboolean calc_moon (WeatherInfo *info);
+gboolean calc_moon_phases (WeatherInfo *info, time_t *phases);
+
+void free_forecast_list (WeatherInfo *info);
+
+#endif /* __WEATHER_PRIV_H_ */
+
diff --git a/libmateweather/weather-sun.c b/libmateweather/weather-sun.c
new file mode 100644
index 0000000..523bf0c
--- /dev/null
+++ b/libmateweather/weather-sun.c
@@ -0,0 +1,353 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-sun.c - Astronomy calculations for mateweather
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Formulas from:
+ * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
+ * Cambridge University Press 1988
+ * Unless otherwise noted, comments referencing "steps" are related to
+ * the algorithm presented in section 49 of above
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <time.h>
+#include <glib.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#define ECCENTRICITY(d) (0.01671123 - (d)/36525.*0.00004392)
+
+/*
+ * Ecliptic longitude of the sun at specified time (UT)
+ * The algoithm is described in section 47 of Duffett-Smith
+ * Return value is in radians
+ */
+gdouble
+sunEclipLongitude(time_t t)
+{
+ gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
+
+ /*
+ * Start with an estimate based on a fixed daily rate
+ */
+ ndays = EPOCH_TO_J2000(t) / 86400.;
+ meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)
+ - PERIGEE_LONGITUDE(ndays));
+
+ /*
+ * Approximate solution of Kepler's equation:
+ * Find E which satisfies E - e sin(E) = M (mean anomaly)
+ */
+ eccenAnom = meanAnom;
+ e = ECCENTRICITY(ndays);
+
+ while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
+ {
+ eccenAnom -= delta / (1.- e * cos(eccenAnom));
+ }
+
+ /*
+ * Earth's longitude on the ecliptic
+ */
+ longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))
+ + 2. * atan (sqrt ((1.+e)/(1.-e))
+ * tan (eccenAnom / 2.)),
+ 2. * M_PI);
+ if (longitude < 0.) {
+ longitude += 2 * M_PI;
+ }
+ return longitude;
+}
+
+static gdouble
+ecliptic_obliquity (gdouble time)
+{
+ gdouble jc = EPOCH_TO_J2000 (time) / (36525. * 86400.);
+ gdouble eclip_secs = (84381.448
+ - (46.84024 * jc)
+ - (59.e-5 * jc * jc)
+ + (1.813e-3 * jc * jc * jc));
+ return DEGREES_TO_RADIANS(eclip_secs / 3600.);
+}
+
+/*
+ * Convert ecliptic longitude and latitude (radians) to equitorial
+ * coordinates, expressed as right ascension (hours) and
+ * declination (radians)
+ */
+void
+ecl2equ (gdouble time,
+ gdouble eclipLon, gdouble eclipLat,
+ gdouble *ra, gdouble *decl)
+{
+ gdouble mEclipObliq = ecliptic_obliquity(time);
+
+ if (ra) {
+ *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)
+ - tan (eclipLat) * sin(mEclipObliq)),
+ cos (eclipLon)));
+ if (*ra < 0.)
+ *ra += 24.;
+ }
+ if (decl) {
+ *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
+ + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
+ }
+}
+
+/*
+ * Calculate rising and setting times for an object
+ * based on it equitorial coordinates (section 33 & 15)
+ * Returned "rise" and "set" values are sideral times in hours
+ */
+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) != 0) {
+ *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)
+{
+ 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;
+}
+
+
+static gboolean
+calc_sun2 (WeatherInfo *info, time_t t)
+{
+ gdouble obsLat = info->location->latitude;
+ gdouble obsLon = info->location->longitude;
+ time_t gm_midn;
+ time_t lcl_midn;
+ gdouble gm_hoff, lambda;
+ gdouble ra1, ra2;
+ gdouble decl1, decl2;
+ gdouble decl_midn, decl_noon;
+ gdouble rise1, rise2;
+ gdouble set1, set2;
+ gdouble tt, t00;
+ gdouble x, u, dt;
+
+ /* Approximate preceding local midnight at observer's longitude */
+ obsLat = info->location->latitude;
+ obsLon = info->location->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;
+
+ lambda = sunEclipLongitude (lcl_midn);
+
+ /*
+ * Calculate equitorial coordinates of sun at previous
+ * and next local midnights
+ */
+ ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
+ ecl2equ (lcl_midn + 86400.,
+ lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION), 0.,
+ &ra2, &decl2);
+
+ /*
+ * If the observer is within the Arctic or Antarctic Circles then
+ * the sun may be above or below the horizon for the full day.
+ */
+ decl_midn = MIN(decl1,decl2);
+ decl_noon = (decl1+decl2)/2.;
+ info->midnightSun =
+ (obsLat > (M_PI/2.-decl_midn)) || (obsLat < (-M_PI/2.-decl_midn));
+ info->polarNight =
+ (obsLat > (M_PI/2.+decl_noon)) || (obsLat < (-M_PI/2.+decl_noon));
+ if (info->midnightSun || info->polarNight) {
+ info->sunriseValid = info->sunsetValid = FALSE;
+ return FALSE;
+ }
+
+ /*
+ * Convert to rise and set times based positions for the preceding
+ * and following local midnights.
+ */
+ 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)) {
+ info->sunriseValid = info->sunsetValid = FALSE;
+ return FALSE;
+ }
+
+ if (rise2 < rise1) {
+ rise2 += 24.;
+ }
+ if (set2 < set1) {
+ set2 += 24.;
+ }
+
+ tt = t0(lcl_midn);
+ 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 to get a rise and set time
+ * based on the sun's position at local noon (step 8)
+ */
+ rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
+ set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
+
+ /*
+ * Calculate an adjustment value to account for parallax,
+ * refraction and the Sun's finite diameter (steps 9,10)
+ */
+ decl2 = (decl1 + decl2) / 2.;
+ x = DEGREES_TO_RADIANS(0.830725);
+ u = acos ( sin(obsLat) / cos(decl2) );
+ dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) );
+
+ /*
+ * Subtract the correction value from sunrise and add to sunset,
+ * then (step 11) convert sideral times to UT
+ */
+ rise1 = (rise1 - dt - tt) * 0.9972695661;
+ if (rise1 < 0.)
+ rise1 += 24;
+ else if (rise1 >= 24.)
+ rise1 -= 24.;
+ info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
+ info->sunrise = (rise1 * 3600.) + lcl_midn;
+
+ set1 = (set1 + dt - tt) * 0.9972695661;
+ if (set1 < 0.)
+ set1 += 24;
+ else if (set1 >= 24.)
+ set1 -= 24.;
+ info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
+ info->sunset = (set1 * 3600.) + lcl_midn;
+
+ return (info->sunriseValid || info->sunsetValid);
+}
+
+
+/**
+ * calc_sun_time:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ * @t: time_t
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun_time (WeatherInfo *info, time_t t)
+{
+ return info->location->latlon_valid && calc_sun2 (info, t);
+}
+
+/**
+ * calc_sun:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun (WeatherInfo *info)
+{
+ return calc_sun_time(info, time(NULL));
+}
+
+
+/**
+ * weather_info_next_sun_event:
+ * @info: #WeatherInfo structure
+ *
+ * Returns: the interval, in seconds, until the next "sun event":
+ * - local midnight, when rise and set times are recomputed
+ * - next sunrise, when icon changes to daytime version
+ * - next sunset, when icon changes to nighttime version
+ */
+gint
+weather_info_next_sun_event (WeatherInfo *info)
+{
+ time_t now = time (NULL);
+ struct tm ltm;
+ time_t nxtEvent;
+
+ g_return_val_if_fail (info != NULL, -1);
+
+ if (!calc_sun (info))
+ return -1;
+
+ /* Determine when the next local midnight occurs */
+ (void) localtime_r (&now, &ltm);
+ ltm.tm_sec = 0;
+ ltm.tm_min = 0;
+ ltm.tm_hour = 0;
+ ltm.tm_mday++;
+ nxtEvent = mktime (&ltm);
+
+ if (info->sunsetValid &&
+ (info->sunset > now) && (info->sunset < nxtEvent))
+ nxtEvent = info->sunset;
+ if (info->sunriseValid &&
+ (info->sunrise > now) && (info->sunrise < nxtEvent))
+ nxtEvent = info->sunrise;
+ return (gint)(nxtEvent - now);
+}
diff --git a/libmateweather/weather-wx.c b/libmateweather/weather-wx.c
new file mode 100644
index 0000000..e57fb0d
--- /dev/null
+++ b/libmateweather/weather-wx.c
@@ -0,0 +1,107 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-wx.c - Weather server functions (WX Radar)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+wx_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+ GdkPixbufAnimation *animation;
+
+ g_return_if_fail (info != NULL);
+
+ if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+ g_warning ("Failed to get radar map image: %d %s.\n",
+ msg->status_code, msg->reason_phrase);
+ g_object_unref (info->radar_loader);
+ request_done (info, FALSE);
+ return;
+ }
+
+ gdk_pixbuf_loader_close (info->radar_loader, NULL);
+ animation = gdk_pixbuf_loader_get_animation (info->radar_loader);
+ if (animation != NULL) {
+ if (info->radar)
+ g_object_unref (info->radar);
+ info->radar = animation;
+ g_object_ref (info->radar);
+ }
+ g_object_unref (info->radar_loader);
+
+ request_done (info, TRUE);
+}
+
+static void
+wx_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+ GError *error = NULL;
+
+ g_return_if_fail (info != NULL);
+
+ gdk_pixbuf_loader_write (info->radar_loader, (guchar *)chunk->data,
+ chunk->length, &error);
+ if (error) {
+ g_print ("%s \n", error->message);
+ g_error_free (error);
+ }
+}
+
+/* Get radar map and into newly allocated pixmap */
+void
+wx_start_open (WeatherInfo *info)
+{
+ gchar *url;
+ SoupMessage *msg;
+ WeatherLocation *loc;
+
+ g_return_if_fail (info != NULL);
+ info->radar = NULL;
+ info->radar_loader = gdk_pixbuf_loader_new ();
+ loc = info->location;
+ g_return_if_fail (loc != NULL);
+
+ if (info->radar_url)
+ url = g_strdup (info->radar_url);
+ else {
+ if (loc->radar[0] == '-')
+ return;
+ url = g_strdup_printf ("http://image.weather.com/web/radar/us_%s_closeradar_medium_usen.jpg", loc->radar);
+ }
+
+ msg = soup_message_new ("GET", url);
+ if (!msg) {
+ g_warning ("Invalid radar URL: %s\n", url);
+ g_free (url);
+ return;
+ }
+
+ g_signal_connect (msg, "got-chunk", G_CALLBACK (wx_got_chunk), info);
+ soup_message_body_set_accumulate (msg->response_body, FALSE);
+ soup_session_queue_message (info->session, msg, wx_finish, info);
+ g_free (url);
+
+ info->requests_pending++;
+}
diff --git a/libmateweather/weather.c b/libmateweather/weather.c
new file mode 100644
index 0000000..19a8c09
--- /dev/null
+++ b/libmateweather/weather.c
@@ -0,0 +1,1651 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather.c - Overall weather server functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#include <time.h>
+#include <unistd.h>
+
+#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+#define MOON_PHASES 36
+
+static void _weather_internal_check (void);
+
+
+static inline void
+mateweather_gettext_init (void)
+{
+ static gsize mateweather_gettext_initialized = FALSE;
+
+ if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))) {
+ bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+ g_once_init_leave (&mateweather_gettext_initialized, TRUE);
+ }
+}
+
+const char *
+mateweather_gettext (const char *str)
+{
+ mateweather_gettext_init ();
+ return dgettext (GETTEXT_PACKAGE, str);
+}
+
+const char *
+mateweather_dpgettext (const char *context,
+ const char *str)
+{
+ mateweather_gettext_init ();
+ return g_dpgettext2 (GETTEXT_PACKAGE, context, str);
+}
+
+/*
+ * 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.
+ */
+static 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, "%d-%d", &deg, &min);
+ sec = 0;
+ } else if (p2 == 1 + p1) {
+ return DBL_MAX;
+ } else {
+ sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
+ }
+ if (deg > 180 || min >= 60 || sec >= 60)
+ return DBL_MAX;
+ value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI / 648000.;
+
+ dir = g_ascii_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 *name, const gchar *code,
+ const gchar *zone, const gchar *radar,
+ const gchar *coordinates,
+ const gchar *country_code,
+ const gchar *tz_hint)
+{
+ WeatherLocation *location;
+
+ _weather_internal_check ();
+
+ location = g_new (WeatherLocation, 1);
+
+ /* name and metar code must be set */
+ location->name = g_strdup (name);
+ location->code = g_strdup (code);
+
+ if (zone) {
+ location->zone = g_strdup (zone);
+ } else {
+ location->zone = g_strdup ("------");
+ }
+
+ if (radar) {
+ location->radar = g_strdup (radar);
+ } else {
+ location->radar = g_strdup ("---");
+ }
+
+ if (location->zone[0] == '-') {
+ location->zone_valid = FALSE;
+ } else {
+ location->zone_valid = TRUE;
+ }
+
+ location->coordinates = NULL;
+ if (coordinates)
+ {
+ char **pieces;
+
+ pieces = g_strsplit (coordinates, " ", -1);
+
+ if (g_strv_length (pieces) == 2)
+ {
+ location->coordinates = g_strdup (coordinates);
+ location->latitude = dmsh2rad (pieces[0]);
+ location->longitude = dmsh2rad (pieces[1]);
+ }
+
+ g_strfreev (pieces);
+ }
+
+ if (!location->coordinates)
+ {
+ location->coordinates = g_strdup ("---");
+ location->latitude = DBL_MAX;
+ location->longitude = DBL_MAX;
+ }
+
+ location->latlon_valid = (location->latitude < DBL_MAX && location->longitude < DBL_MAX);
+
+ location->country_code = g_strdup (country_code);
+ location->tz_hint = g_strdup (tz_hint);
+
+ return location;
+}
+
+WeatherLocation *
+weather_location_clone (const WeatherLocation *location)
+{
+ WeatherLocation *clone;
+
+ g_return_val_if_fail (location != NULL, NULL);
+
+ clone = weather_location_new (location->name,
+ location->code, location->zone,
+ location->radar, location->coordinates,
+ location->country_code, location->tz_hint);
+ clone->latitude = location->latitude;
+ clone->longitude = location->longitude;
+ clone->latlon_valid = location->latlon_valid;
+ return clone;
+}
+
+void
+weather_location_free (WeatherLocation *location)
+{
+ if (location) {
+ g_free (location->name);
+ g_free (location->code);
+ g_free (location->zone);
+ g_free (location->radar);
+ g_free (location->coordinates);
+ g_free (location->country_code);
+ g_free (location->tz_hint);
+
+ g_free (location);
+ }
+}
+
+gboolean
+weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
+{
+ /* if something is NULL, then it's TRUE if and only if both are NULL) */
+ if (location1 == NULL || location2 == NULL)
+ return (location1 == location2);
+ if (!location1->code || !location2->code)
+ return (location1->code == location2->code);
+ if (!location1->name || !location2->name)
+ return (location1->name == location2->name);
+
+ return ((strcmp (location1->code, location2->code) == 0) &&
+ (strcmp (location1->name, location2->name) == 0));
+}
+
+static const gchar *wind_direction_str[] = {
+ N_("Variable"),
+ N_("North"), N_("North - NorthEast"), N_("Northeast"), N_("East - NorthEast"),
+ N_("East"), N_("East - Southeast"), N_("Southeast"), N_("South - Southeast"),
+ N_("South"), N_("South - Southwest"), N_("Southwest"), N_("West - Southwest"),
+ N_("West"), N_("West - Northwest"), N_("Northwest"), N_("North - Northwest")
+};
+
+const gchar *
+weather_wind_direction_string (WeatherWindDirection wind)
+{
+ if (wind <= WIND_INVALID || wind >= WIND_LAST)
+ return _("Invalid");
+
+ return _(wind_direction_str[(int)wind]);
+}
+
+static const gchar *sky_str[] = {
+ N_("Clear Sky"),
+ N_("Broken clouds"),
+ N_("Scattered clouds"),
+ N_("Few clouds"),
+ N_("Overcast")
+};
+
+const gchar *
+weather_sky_string (WeatherSky sky)
+{
+ if (sky <= SKY_INVALID || sky >= SKY_LAST)
+ return _("Invalid");
+
+ return _(sky_str[(int)sky]);
+}
+
+
+/*
+ * Even though tedious, I switched to a 2D array for weather condition
+ * strings, in order to facilitate internationalization, esp. for languages
+ * with genders.
+ */
+
+/*
+ * Almost all reportable combinations listed in
+ * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
+ * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
+ * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
+ * Combinations that are not possible are filled in with "??".
+ * Some other exceptions not handled yet, such as "SN BLSN" which has
+ * special meaning.
+ */
+
+/*
+ * Note, magic numbers, when you change the size here, make sure to change
+ * the below function so that new values are recognized
+ */
+/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
+/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+static const gchar *conditions_str[24][13] = {
+/* TRANSLATOR: If you want to know what "blowing" "shallow" "partial"
+ * etc means, you can go to http://www.weather.com/glossary/ and
+ * http://www.crh.noaa.gov/arx/wx.tbl.php */
+ /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm"), "??", "??", "??", "??" },
+ /* DRIZZLE */ {N_("Drizzle"), "??", N_("Light drizzle"), N_("Moderate drizzle"), N_("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle") },
+ /* RAIN */ {N_("Rain"), "??", N_("Light rain"), N_("Moderate rain"), N_("Heavy rain"), "??", "??", "??", N_("Thunderstorm"), "??", N_("Rain showers"), "??", N_("Freezing rain") },
+ /* SNOW */ {N_("Snow"), "??", N_("Light snow"), N_("Moderate snow"), N_("Heavy snow"), "??", "??", "??", N_("Snowstorm"), N_("Blowing snowfall"), N_("Snow showers"), N_("Drifting snow"), "??" },
+ /* SNOW_GRAINS */ {N_("Snow grains"), "??", N_("Light snow grains"), N_("Moderate snow grains"), N_("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
+ /* ICE_CRYSTALS */ {N_("Ice crystals"), "??", "??", N_("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+ /* ICE_PELLETS */ {N_("Ice pellets"), "??", N_("Few ice pellets"), N_("Moderate ice pellets"), N_("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm"), "??", N_("Showers of ice pellets"), "??", "??" },
+ /* HAIL */ {N_("Hail"), "??", "??", N_("Hail"), "??", "??", "??", "??", N_("Hailstorm"), "??", N_("Hail showers"), "??", "??", },
+ /* SMALL_HAIL */ {N_("Small hail"), "??", "??", N_("Small hail"), "??", "??", "??", "??", N_("Small hailstorm"), "??", N_("Showers of small hail"), "??", "??" },
+ /* PRECIPITATION */ {N_("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+ /* MIST */ {N_("Mist"), "??", "??", N_("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+ /* FOG */ {N_("Fog"), N_("Fog in the vicinity") , "??", N_("Fog"), "??", N_("Shallow fog"), N_("Patches of fog"), N_("Partial fog"), "??", "??", "??", "??", N_("Freezing fog") },
+ /* SMOKE */ {N_("Smoke"), "??", "??", N_("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+ /* VOLCANIC_ASH */ {N_("Volcanic ash"), "??", "??", N_("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+ /* SAND */ {N_("Sand"), "??", "??", N_("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand"), "", N_("Drifting sand"), "??" },
+ /* HAZE */ {N_("Haze"), "??", "??", N_("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+ /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays"), "??", "??", "??" },
+ /* DUST */ {N_("Dust"), "??", "??", N_("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust"), "??", N_("Drifting dust"), "??" },
+ /* SQUALL */ {N_("Squall"), "??", "??", N_("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+ /* SANDSTORM */ {N_("Sandstorm"), N_("Sandstorm in the vicinity") , "??", N_("Sandstorm"), N_("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
+ /* DUSTSTORM */ {N_("Duststorm"), N_("Duststorm in the vicinity") , "??", N_("Duststorm"), N_("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
+ /* FUNNEL_CLOUD */ {N_("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+ /* TORNADO */ {N_("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+ /* DUST_WHIRLS */ {N_("Dust whirls"), N_("Dust whirls in the vicinity") , "??", N_("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
+};
+
+const gchar *
+weather_conditions_string (WeatherConditions cond)
+{
+ const gchar *str;
+
+ if (!cond.significant) {
+ return "-";
+ } else {
+ if (cond.phenomenon > PHENOMENON_INVALID &&
+ cond.phenomenon < PHENOMENON_LAST &&
+ cond.qualifier > QUALIFIER_INVALID &&
+ cond.qualifier < QUALIFIER_LAST)
+ str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier]);
+ else
+ str = _("Invalid");
+ return (strlen (str) > 0) ? str : "-";
+ }
+}
+
+/* Locals turned global to facilitate asynchronous HTTP requests */
+
+
+gboolean
+requests_init (WeatherInfo *info)
+{
+ if (info->requests_pending)
+ return FALSE;
+
+ return TRUE;
+}
+
+void request_done (WeatherInfo *info, gboolean ok)
+{
+ if (ok) {
+ (void) calc_sun (info);
+ info->moonValid = info->valid && calc_moon (info);
+ }
+ if (!--info->requests_pending)
+ info->finish_cb (info, info->cb_data);
+}
+
+/* it's OK to pass in NULL */
+void
+free_forecast_list (WeatherInfo *info)
+{
+ GSList *p;
+
+ if (!info)
+ return;
+
+ for (p = info->forecast_list; p; p = p->next)
+ weather_info_free (p->data);
+
+ if (info->forecast_list) {
+ g_slist_free (info->forecast_list);
+ info->forecast_list = NULL;
+ }
+}
+
+/* Relative humidity computation - thanks to <[email protected]> */
+
+static inline gdouble
+calc_humidity (gdouble temp, gdouble dewp)
+{
+ gdouble esat, esurf;
+
+ if (temp > -500.0 && dewp > -500.0) {
+ temp = TEMP_F_TO_C (temp);
+ dewp = TEMP_F_TO_C (dewp);
+
+ esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
+ esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
+ } else {
+ esurf = -1.0;
+ esat = 1.0;
+ }
+ return ((esurf/esat) * 100.0);
+}
+
+static inline gdouble
+calc_apparent (WeatherInfo *info)
+{
+ gdouble temp = info->temp;
+ gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed);
+ gdouble apparent = -1000.;
+
+ /*
+ * Wind chill calculations as of 01-Nov-2001
+ * http://www.nws.noaa.gov/om/windchill/index.shtml
+ * Some pages suggest that the formula will soon be adjusted
+ * to account for solar radiation (bright sun vs cloudy sky)
+ */
+ if (temp <= 50.0) {
+ if (wind > 3.0) {
+ gdouble v = pow (wind, 0.16);
+ apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
+ } else if (wind >= 0.) {
+ apparent = temp;
+ }
+ }
+ /*
+ * Heat index calculations:
+ * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
+ */
+ else if (temp >= 80.0) {
+ if (info->temp >= -500. && info->dew >= -500.) {
+ gdouble humidity = calc_humidity (info->temp, info->dew);
+ gdouble t2 = temp * temp;
+ gdouble h2 = humidity * humidity;
+
+#if 1
+ /*
+ * A really precise formula. Note that overall precision is
+ * constrained by the accuracy of the instruments and that the
+ * we receive the temperature and dewpoints as integers.
+ */
+ gdouble t3 = t2 * temp;
+ gdouble h3 = h2 * temp;
+
+ apparent = 16.923
+ + 0.185212 * temp
+ + 5.37941 * humidity
+ - 0.100254 * temp * humidity
+ + 9.41695e-3 * t2
+ + 7.28898e-3 * h2
+ + 3.45372e-4 * t2 * humidity
+ - 8.14971e-4 * temp * h2
+ + 1.02102e-5 * t2 * h2
+ - 3.8646e-5 * t3
+ + 2.91583e-5 * h3
+ + 1.42721e-6 * t3 * humidity
+ + 1.97483e-7 * temp * h3
+ - 2.18429e-8 * t3 * h2
+ + 8.43296e-10 * t2 * h3
+ - 4.81975e-11 * t3 * h3;
+#else
+ /*
+ * An often cited alternative: values are within 5 degrees for
+ * most ranges between 10% and 70% humidity and to 110 degrees.
+ */
+ apparent = - 42.379
+ + 2.04901523 * temp
+ + 10.14333127 * humidity
+ - 0.22475541 * temp * humidity
+ - 6.83783e-3 * t2
+ - 5.481717e-2 * h2
+ + 1.22874e-3 * t2 * humidity
+ + 8.5282e-4 * temp * h2
+ - 1.99e-6 * t2 * h2;
+#endif
+ }
+ } else {
+ apparent = temp;
+ }
+
+ return apparent;
+}
+
+WeatherInfo *
+_weather_info_fill (WeatherInfo *info,
+ WeatherLocation *location,
+ const WeatherPrefs *prefs,
+ WeatherInfoFunc cb,
+ gpointer data)
+{
+ g_return_val_if_fail (((info == NULL) && (location != NULL)) || \
+ ((info != NULL) && (location == NULL)), NULL);
+ g_return_val_if_fail (prefs != NULL, NULL);
+
+ /* FIXME: i'm not sure this works as intended anymore */
+ if (!info) {
+ info = g_new0 (WeatherInfo, 1);
+ info->requests_pending = 0;
+ info->location = weather_location_clone (location);
+ } else {
+ location = info->location;
+ if (info->forecast)
+ g_free (info->forecast);
+ info->forecast = NULL;
+
+ free_forecast_list (info);
+
+ if (info->radar != NULL) {
+ g_object_unref (info->radar);
+ info->radar = NULL;
+ }
+ }
+
+ /* Update in progress */
+ if (!requests_init (info)) {
+ return NULL;
+ }
+
+ /* Defaults (just in case...) */
+ /* Well, no just in case anymore. We may actually fail to fetch some
+ * fields. */
+ info->forecast_type = prefs->type;
+
+ info->temperature_unit = prefs->temperature_unit;
+ info->speed_unit = prefs->speed_unit;
+ info->pressure_unit = prefs->pressure_unit;
+ info->distance_unit = prefs->distance_unit;
+
+ info->update = 0;
+ info->sky = -1;
+ info->cond.significant = FALSE;
+ info->cond.phenomenon = PHENOMENON_NONE;
+ info->cond.qualifier = QUALIFIER_NONE;
+ info->temp = -1000.0;
+ info->tempMinMaxValid = FALSE;
+ info->temp_min = -1000.0;
+ info->temp_max = -1000.0;
+ info->dew = -1000.0;
+ info->wind = -1;
+ info->windspeed = -1;
+ info->pressure = -1.0;
+ info->visibility = -1.0;
+ info->sunriseValid = FALSE;
+ info->sunsetValid = FALSE;
+ info->moonValid = FALSE;
+ info->sunrise = 0;
+ info->sunset = 0;
+ info->moonphase = 0;
+ info->moonlatitude = 0;
+ info->forecast = NULL;
+ info->forecast_list = NULL;
+ info->radar = NULL;
+ info->radar_url = prefs->radar && prefs->radar_custom_url ?
+ g_strdup (prefs->radar_custom_url) : NULL;
+ info->finish_cb = cb;
+ info->cb_data = data;
+
+ if (!info->session) {
+ info->session = soup_session_async_new ();
+#ifdef HAVE_LIBSOUP_MATE
+ soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_MATE);
+#endif
+ }
+
+ metar_start_open (info);
+ iwin_start_open (info);
+
+ if (prefs->radar) {
+ wx_start_open (info);
+ }
+
+ return info;
+}
+
+void
+weather_info_abort (WeatherInfo *info)
+{
+ g_return_if_fail (info != NULL);
+
+ if (info->session) {
+ soup_session_abort (info->session);
+ info->requests_pending = 0;
+ }
+}
+
+WeatherInfo *
+weather_info_clone (const WeatherInfo *info)
+{
+ WeatherInfo *clone;
+
+ g_return_val_if_fail (info != NULL, NULL);
+
+ clone = g_new (WeatherInfo, 1);
+
+
+ /* move everything */
+ g_memmove (clone, info, sizeof (WeatherInfo));
+
+
+ /* special moves */
+ clone->location = weather_location_clone (info->location);
+ /* This handles null correctly */
+ clone->forecast = g_strdup (info->forecast);
+ clone->radar_url = g_strdup (info->radar_url);
+
+ if (info->forecast_list) {
+ GSList *p;
+
+ clone->forecast_list = NULL;
+ for (p = info->forecast_list; p; p = p->next) {
+ clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
+ }
+
+ clone->forecast_list = g_slist_reverse (clone->forecast_list);
+ }
+
+ clone->radar = info->radar;
+ if (clone->radar != NULL)
+ g_object_ref (clone->radar);
+
+ return clone;
+}
+
+void
+weather_info_free (WeatherInfo *info)
+{
+ if (!info)
+ return;
+
+ weather_info_abort (info);
+ if (info->session)
+ g_object_unref (info->session);
+
+ weather_location_free (info->location);
+ info->location = NULL;
+
+ g_free (info->forecast);
+ info->forecast = NULL;
+
+ free_forecast_list (info);
+
+ if (info->radar != NULL) {
+ g_object_unref (info->radar);
+ info->radar = NULL;
+ }
+
+ g_free (info);
+}
+
+gboolean
+weather_info_is_valid (WeatherInfo *info)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ return info->valid;
+}
+
+gboolean
+weather_info_network_error (WeatherInfo *info)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ return info->network_error;
+}
+
+void
+weather_info_to_metric (WeatherInfo *info)
+{
+ g_return_if_fail (info != NULL);
+
+ info->temperature_unit = TEMP_UNIT_CENTIGRADE;
+ info->speed_unit = SPEED_UNIT_MS;
+ info->pressure_unit = PRESSURE_UNIT_HPA;
+ info->distance_unit = DISTANCE_UNIT_METERS;
+}
+
+void
+weather_info_to_imperial (WeatherInfo *info)
+{
+ g_return_if_fail (info != NULL);
+
+ info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+ info->speed_unit = SPEED_UNIT_MPH;
+ info->pressure_unit = PRESSURE_UNIT_INCH_HG;
+ info->distance_unit = DISTANCE_UNIT_MILES;
+}
+
+const WeatherLocation *
+weather_info_get_location (WeatherInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+ return info->location;
+}
+
+const gchar *
+weather_info_get_location_name (WeatherInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+ g_return_val_if_fail (info->location != NULL, NULL);
+ return info->location->name;
+}
+
+const gchar *
+weather_info_get_update (WeatherInfo *info)
+{
+ static gchar buf[200];
+ char *utf8, *timeformat;
+
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (!info->valid)
+ return "-";
+
+ if (info->update != 0) {
+ struct tm tm;
+ localtime_r (&info->update, &tm);
+ /* TRANSLATOR: this is a format string for strftime
+ * see `man 3 strftime` for more details
+ */
+ timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M"), -1,
+ NULL, NULL, NULL);
+ if (!timeformat) {
+ strcpy (buf, "???");
+ }
+ else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
+ strcpy (buf, "???");
+ }
+ g_free (timeformat);
+
+ /* Convert to UTF-8 */
+ utf8 = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+ strcpy (buf, utf8);
+ g_free (utf8);
+ } else {
+ strncpy (buf, _("Unknown observation time"), sizeof (buf));
+ buf[sizeof (buf)-1] = '\0';
+ }
+
+ return buf;
+}
+
+const gchar *
+weather_info_get_sky (WeatherInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+ if (!info->valid)
+ return "-";
+ if (info->sky < 0)
+ return _("Unknown");
+ return weather_sky_string (info->sky);
+}
+
+const gchar *
+weather_info_get_conditions (WeatherInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+ if (!info->valid)
+ return "-";
+ return weather_conditions_string (info->cond);
+}
+
+static const gchar *
+temperature_string (gfloat temp_f, TempUnit to_unit, gboolean want_round)
+{
+ static gchar buf[100];
+
+ switch (to_unit) {
+ case TEMP_UNIT_FAHRENHEIT:
+ if (!want_round) {
+ /* TRANSLATOR: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+ g_snprintf (buf, sizeof (buf), _("%.1f \302\260F"), temp_f);
+ } else {
+ /* TRANSLATOR: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+ g_snprintf (buf, sizeof (buf), _("%d \302\260F"), (int)floor (temp_f + 0.5));
+ }
+ break;
+ case TEMP_UNIT_CENTIGRADE:
+ if (!want_round) {
+ /* TRANSLATOR: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+ g_snprintf (buf, sizeof (buf), _("%.1f \302\260C"), TEMP_F_TO_C (temp_f));
+ } else {
+ /* TRANSLATOR: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+ g_snprintf (buf, sizeof (buf), _("%d \302\260C"), (int)floor (TEMP_F_TO_C (temp_f) + 0.5));
+ }
+ break;
+ case TEMP_UNIT_KELVIN:
+ if (!want_round) {
+ /* TRANSLATOR: This is the temperature in kelvin */
+ g_snprintf (buf, sizeof (buf), _("%.1f K"), TEMP_F_TO_K (temp_f));
+ } else {
+ /* TRANSLATOR: This is the temperature in kelvin */
+ g_snprintf (buf, sizeof (buf), _("%d K"), (int)floor (TEMP_F_TO_K (temp_f)));
+ }
+ break;
+
+ case TEMP_UNIT_INVALID:
+ case TEMP_UNIT_DEFAULT:
+ default:
+ g_warning ("Conversion to illegal temperature unit: %d", to_unit);
+ return _("Unknown");
+ }
+
+ return buf;
+}
+
+const gchar *
+weather_info_get_temp (WeatherInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (!info->valid)
+ return "-";
+ if (info->temp < -500.0)
+ return _("Unknown");
+
+ return temperature_string (info->temp, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_min (WeatherInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (!info->valid || !info->tempMinMaxValid)
+ return "-";
+ if (info->temp_min < -500.0)
+ return _("Unknown");
+
+ return temperature_string (info->temp_min, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_max (WeatherInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (!info->valid || !info->tempMinMaxValid)
+ return "-";
+ if (info->temp_max < -500.0)
+ return _("Unknown");
+
+ return temperature_string (info->temp_max, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_dew (WeatherInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (!info->valid)
+ return "-";
+ if (info->dew < -500.0)
+ return _("Unknown");
+
+ return temperature_string (info->dew, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_humidity (WeatherInfo *info)
+{
+ static gchar buf[20];
+ gdouble humidity;
+
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (!info->valid)
+ return "-";
+
+ humidity = calc_humidity (info->temp, info->dew);
+ if (humidity < 0.0)
+ return _("Unknown");
+
+ /* TRANSLATOR: This is the humidity in percent */
+ g_snprintf (buf, sizeof (buf), _("%.f%%"), humidity);
+ return buf;
+}
+
+const gchar *
+weather_info_get_apparent (WeatherInfo *info)
+{
+ gdouble apparent;
+
+ g_return_val_if_fail (info != NULL, NULL);
+ if (!info->valid)
+ return "-";
+
+ apparent = calc_apparent (info);
+ if (apparent < -500.0)
+ return _("Unknown");
+
+ return temperature_string (apparent, info->temperature_unit, FALSE);
+}
+
+static const gchar *
+windspeed_string (gfloat knots, SpeedUnit to_unit)
+{
+ static gchar buf[100];
+
+ switch (to_unit) {
+ case SPEED_UNIT_KNOTS:
+ /* TRANSLATOR: This is the wind speed in knots */
+ g_snprintf (buf, sizeof (buf), _("%0.1f knots"), knots);
+ break;
+ case SPEED_UNIT_MPH:
+ /* TRANSLATOR: This is the wind speed in miles per hour */
+ g_snprintf (buf, sizeof (buf), _("%.1f mph"), WINDSPEED_KNOTS_TO_MPH (knots));
+ break;
+ case SPEED_UNIT_KPH:
+ /* TRANSLATOR: This is the wind speed in kilometers per hour */
+ g_snprintf (buf, sizeof (buf), _("%.1f km/h"), WINDSPEED_KNOTS_TO_KPH (knots));
+ break;
+ case SPEED_UNIT_MS:
+ /* TRANSLATOR: This is the wind speed in meters per second */
+ g_snprintf (buf, sizeof (buf), _("%.1f m/s"), WINDSPEED_KNOTS_TO_MS (knots));
+ break;
+ case SPEED_UNIT_BFT:
+ /* TRANSLATOR: This is the wind speed as a Beaufort force factor
+ * (commonly used in nautical wind estimation).
+ */
+ g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f"),
+ WINDSPEED_KNOTS_TO_BFT (knots));
+ break;
+ case SPEED_UNIT_INVALID:
+ case SPEED_UNIT_DEFAULT:
+ default:
+ g_warning ("Conversion to illegal speed unit: %d", to_unit);
+ return _("Unknown");
+ }
+
+ return buf;
+}
+
+const gchar *
+weather_info_get_wind (WeatherInfo *info)
+{
+ static gchar buf[200];
+
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (!info->valid)
+ return "-";
+ if (info->windspeed < 0.0 || info->wind < 0)
+ return _("Unknown");
+ if (info->windspeed == 0.00) {
+ strncpy (buf, _("Calm"), sizeof (buf));
+ buf[sizeof (buf)-1] = '\0';
+ } else {
+ /* TRANSLATOR: This is 'wind direction' / 'wind speed' */
+ g_snprintf (buf, sizeof (buf), _("%s / %s"),
+ weather_wind_direction_string (info->wind),
+ windspeed_string (info->windspeed, info->speed_unit));
+ }
+ return buf;
+}
+
+const gchar *
+weather_info_get_pressure (WeatherInfo *info)
+{
+ static gchar buf[100];
+
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (!info->valid)
+ return "-";
+ if (info->pressure < 0.0)
+ return _("Unknown");
+
+ switch (info->pressure_unit) {
+ case PRESSURE_UNIT_INCH_HG:
+ /* TRANSLATOR: This is pressure in inches of mercury */
+ g_snprintf (buf, sizeof (buf), _("%.2f inHg"), info->pressure);
+ break;
+ case PRESSURE_UNIT_MM_HG:
+ /* TRANSLATOR: This is pressure in millimeters of mercury */
+ g_snprintf (buf, sizeof (buf), _("%.1f mmHg"), PRESSURE_INCH_TO_MM (info->pressure));
+ break;
+ case PRESSURE_UNIT_KPA:
+ /* TRANSLATOR: This is pressure in kiloPascals */
+ g_snprintf (buf, sizeof (buf), _("%.2f kPa"), PRESSURE_INCH_TO_KPA (info->pressure));
+ break;
+ case PRESSURE_UNIT_HPA:
+ /* TRANSLATOR: This is pressure in hectoPascals */
+ g_snprintf (buf, sizeof (buf), _("%.2f hPa"), PRESSURE_INCH_TO_HPA (info->pressure));
+ break;
+ case PRESSURE_UNIT_MB:
+ /* TRANSLATOR: This is pressure in millibars */
+ g_snprintf (buf, sizeof (buf), _("%.2f mb"), PRESSURE_INCH_TO_MB (info->pressure));
+ break;
+ case PRESSURE_UNIT_ATM:
+ /* TRANSLATOR: This is pressure in atmospheres */
+ g_snprintf (buf, sizeof (buf), _("%.3f atm"), PRESSURE_INCH_TO_ATM (info->pressure));
+ break;
+
+ case PRESSURE_UNIT_INVALID:
+ case PRESSURE_UNIT_DEFAULT:
+ default:
+ g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
+ return _("Unknown");
+ }
+
+ return buf;
+}
+
+const gchar *
+weather_info_get_visibility (WeatherInfo *info)
+{
+ static gchar buf[100];
+
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (!info->valid)
+ return "-";
+ if (info->visibility < 0.0)
+ return _("Unknown");
+
+ switch (info->distance_unit) {
+ case DISTANCE_UNIT_MILES:
+ /* TRANSLATOR: This is the visibility in miles */
+ g_snprintf (buf, sizeof (buf), _("%.1f miles"), info->visibility);
+ break;
+ case DISTANCE_UNIT_KM:
+ /* TRANSLATOR: This is the visibility in kilometers */
+ g_snprintf (buf, sizeof (buf), _("%.1f km"), VISIBILITY_SM_TO_KM (info->visibility));
+ break;
+ case DISTANCE_UNIT_METERS:
+ /* TRANSLATOR: This is the visibility in meters */
+ g_snprintf (buf, sizeof (buf), _("%.0fm"), VISIBILITY_SM_TO_M (info->visibility));
+ break;
+
+ case DISTANCE_UNIT_INVALID:
+ case DISTANCE_UNIT_DEFAULT:
+ default:
+ g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
+ return _("Unknown");
+ }
+
+ 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);
+ return info->forecast;
+}
+
+/**
+ * weather_info_get_forecast_list:
+ * Returns list of WeatherInfo* objects for the forecast.
+ * The list is owned by the 'info' object thus is alive as long
+ * as the 'info'. This list is filled only when requested with
+ * type FORECAST_LIST and if available for given location.
+ * The 'update' property is the date/time when the forecast info
+ * is used for.
+ **/
+GSList *
+weather_info_get_forecast_list (WeatherInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (!info->valid)
+ return NULL;
+
+ return info->forecast_list;
+}
+
+GdkPixbufAnimation *
+weather_info_get_radar (WeatherInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+ return info->radar;
+}
+
+const gchar *
+weather_info_get_temp_summary (WeatherInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (!info->valid || info->temp < -500.0)
+ return "--";
+
+ return temperature_string (info->temp, info->temperature_unit, TRUE);
+
+}
+
+gchar *
+weather_info_get_weather_summary (WeatherInfo *info)
+{
+ const gchar *buf;
+
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (!info->valid)
+ return g_strdup (_("Retrieval failed"));
+ buf = weather_info_get_conditions (info);
+ if (!strcmp (buf, "-"))
+ buf = weather_info_get_sky (info);
+ return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
+}
+
+const gchar *
+weather_info_get_icon_name (WeatherInfo *info)
+{
+ WeatherConditions cond;
+ WeatherSky sky;
+ time_t current_time;
+ gboolean daytime;
+ gchar* icon;
+ static gchar icon_buffer[32];
+ WeatherMoonPhase moonPhase;
+ WeatherMoonLatitude moonLat;
+ gint phase;
+
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (!info->valid)
+ return NULL;
+
+ cond = info->cond;
+ sky = info->sky;
+
+ if (cond.significant) {
+ if (cond.phenomenon != PHENOMENON_NONE &&
+ cond.qualifier == QUALIFIER_THUNDERSTORM)
+ return "weather-storm";
+
+ switch (cond.phenomenon) {
+ case PHENOMENON_INVALID:
+ case PHENOMENON_LAST:
+ case PHENOMENON_NONE:
+ break;
+
+ case PHENOMENON_DRIZZLE:
+ case PHENOMENON_RAIN:
+ case PHENOMENON_UNKNOWN_PRECIPITATION:
+ case PHENOMENON_HAIL:
+ case PHENOMENON_SMALL_HAIL:
+ return "weather-showers";
+
+ case PHENOMENON_SNOW:
+ case PHENOMENON_SNOW_GRAINS:
+ case PHENOMENON_ICE_PELLETS:
+ case PHENOMENON_ICE_CRYSTALS:
+ return "weather-snow";
+
+ case PHENOMENON_TORNADO:
+ case PHENOMENON_SQUALL:
+ return "weather-storm";
+
+ case PHENOMENON_MIST:
+ case PHENOMENON_FOG:
+ case PHENOMENON_SMOKE:
+ case PHENOMENON_VOLCANIC_ASH:
+ case PHENOMENON_SAND:
+ case PHENOMENON_HAZE:
+ case PHENOMENON_SPRAY:
+ case PHENOMENON_DUST:
+ case PHENOMENON_SANDSTORM:
+ case PHENOMENON_DUSTSTORM:
+ case PHENOMENON_FUNNEL_CLOUD:
+ case PHENOMENON_DUST_WHIRLS:
+ return "weather-fog";
+ }
+ }
+
+ if (info->midnightSun ||
+ (!info->sunriseValid && !info->sunsetValid))
+ daytime = TRUE;
+ else if (info->polarNight)
+ daytime = FALSE;
+ else {
+ current_time = time (NULL);
+ daytime =
+ ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
+ ( !info->sunsetValid || (current_time < info->sunset) );
+ }
+
+ switch (sky) {
+ case SKY_INVALID:
+ case SKY_LAST:
+ case SKY_CLEAR:
+ if (daytime)
+ return "weather-clear";
+ else {
+ icon = g_stpcpy(icon_buffer, "weather-clear-night");
+ break;
+ }
+
+ case SKY_BROKEN:
+ case SKY_SCATTERED:
+ case SKY_FEW:
+ if (daytime)
+ return "weather-few-clouds";
+ else {
+ icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
+ break;
+ }
+
+ case SKY_OVERCAST:
+ return "weather-overcast";
+
+ default: /* unrecognized */
+ return NULL;
+ }
+
+ /*
+ * A phase-of-moon icon is to be returned.
+ * Determine which one based on the moon's location
+ */
+ if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
+ phase = (gint)((moonPhase * MOON_PHASES / 360.) + 0.5);
+ if (phase == MOON_PHASES) {
+ phase = 0;
+ } else if (phase > 0 &&
+ (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)
+ < moonLat)) {
+ /*
+ * Locations south of the moon's latitude will see the moon in the
+ * northern sky. The moon waxes and wanes from left to right
+ * so we reference an icon running in the opposite direction.
+ */
+ phase = MOON_PHASES - phase;
+ }
+
+ /*
+ * If the moon is not full then append the angle to the icon string.
+ * Note that an icon by this name is not required to exist:
+ * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
+ * the full moon image.
+ */
+ if ((0 == (MOON_PHASES & 0x1)) && (MOON_PHASES/2 != phase)) {
+ g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
+ "-%03d", phase * 360 / MOON_PHASES);
+ }
+ }
+ return icon_buffer;
+}
+
+static gboolean
+temperature_value (gdouble temp_f,
+ TempUnit to_unit,
+ gdouble *value,
+ TempUnit def_unit)
+{
+ gboolean ok = TRUE;
+
+ *value = 0.0;
+ if (temp_f < -500.0)
+ return FALSE;
+
+ if (to_unit == TEMP_UNIT_DEFAULT)
+ to_unit = def_unit;
+
+ switch (to_unit) {
+ case TEMP_UNIT_FAHRENHEIT:
+ *value = temp_f;
+ break;
+ case TEMP_UNIT_CENTIGRADE:
+ *value = TEMP_F_TO_C (temp_f);
+ break;
+ case TEMP_UNIT_KELVIN:
+ *value = TEMP_F_TO_K (temp_f);
+ break;
+ case TEMP_UNIT_INVALID:
+ case TEMP_UNIT_DEFAULT:
+ default:
+ ok = FALSE;
+ break;
+ }
+
+ return ok;
+}
+
+static gboolean
+speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
+{
+ gboolean ok = TRUE;
+
+ *value = -1.0;
+
+ if (knots < 0.0)
+ return FALSE;
+
+ if (to_unit == SPEED_UNIT_DEFAULT)
+ to_unit = def_unit;
+
+ switch (to_unit) {
+ case SPEED_UNIT_KNOTS:
+ *value = knots;
+ break;
+ case SPEED_UNIT_MPH:
+ *value = WINDSPEED_KNOTS_TO_MPH (knots);
+ break;
+ case SPEED_UNIT_KPH:
+ *value = WINDSPEED_KNOTS_TO_KPH (knots);
+ break;
+ case SPEED_UNIT_MS:
+ *value = WINDSPEED_KNOTS_TO_MS (knots);
+ break;
+ case SPEED_UNIT_BFT:
+ *value = WINDSPEED_KNOTS_TO_BFT (knots);
+ break;
+ case SPEED_UNIT_INVALID:
+ case SPEED_UNIT_DEFAULT:
+ default:
+ ok = FALSE;
+ break;
+ }
+
+ return ok;
+}
+
+static gboolean
+pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
+{
+ gboolean ok = TRUE;
+
+ *value = -1.0;
+
+ if (inHg < 0.0)
+ return FALSE;
+
+ if (to_unit == PRESSURE_UNIT_DEFAULT)
+ to_unit = def_unit;
+
+ switch (to_unit) {
+ case PRESSURE_UNIT_INCH_HG:
+ *value = inHg;
+ break;
+ case PRESSURE_UNIT_MM_HG:
+ *value = PRESSURE_INCH_TO_MM (inHg);
+ break;
+ case PRESSURE_UNIT_KPA:
+ *value = PRESSURE_INCH_TO_KPA (inHg);
+ break;
+ case PRESSURE_UNIT_HPA:
+ *value = PRESSURE_INCH_TO_HPA (inHg);
+ break;
+ case PRESSURE_UNIT_MB:
+ *value = PRESSURE_INCH_TO_MB (inHg);
+ break;
+ case PRESSURE_UNIT_ATM:
+ *value = PRESSURE_INCH_TO_ATM (inHg);
+ break;
+ case PRESSURE_UNIT_INVALID:
+ case PRESSURE_UNIT_DEFAULT:
+ default:
+ ok = FALSE;
+ break;
+ }
+
+ return ok;
+}
+
+static gboolean
+distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
+{
+ gboolean ok = TRUE;
+
+ *value = -1.0;
+
+ if (miles < 0.0)
+ return FALSE;
+
+ if (to_unit == DISTANCE_UNIT_DEFAULT)
+ to_unit = def_unit;
+
+ switch (to_unit) {
+ case DISTANCE_UNIT_MILES:
+ *value = miles;
+ break;
+ case DISTANCE_UNIT_KM:
+ *value = VISIBILITY_SM_TO_KM (miles);
+ break;
+ case DISTANCE_UNIT_METERS:
+ *value = VISIBILITY_SM_TO_M (miles);
+ break;
+ case DISTANCE_UNIT_INVALID:
+ case DISTANCE_UNIT_DEFAULT:
+ default:
+ ok = FALSE;
+ break;
+ }
+
+ return ok;
+}
+
+gboolean
+weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (sky != NULL, FALSE);
+
+ if (!info->valid)
+ return FALSE;
+
+ if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
+ return FALSE;
+
+ *sky = info->sky;
+
+ return TRUE;
+}
+
+gboolean
+weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (phenomenon != NULL, FALSE);
+ g_return_val_if_fail (qualifier != NULL, FALSE);
+
+ if (!info->valid)
+ return FALSE;
+
+ if (!info->cond.significant)
+ return FALSE;
+
+ if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
+ info->cond.phenomenon < PHENOMENON_LAST &&
+ info->cond.qualifier > QUALIFIER_INVALID &&
+ info->cond.qualifier < QUALIFIER_LAST))
+ return FALSE;
+
+ *phenomenon = info->cond.phenomenon;
+ *qualifier = info->cond.qualifier;
+
+ return TRUE;
+}
+
+gboolean
+weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ if (!info->valid)
+ return FALSE;
+
+ return temperature_value (info->temp, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ if (!info->valid || !info->tempMinMaxValid)
+ return FALSE;
+
+ return temperature_value (info->temp_min, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ if (!info->valid || !info->tempMinMaxValid)
+ return FALSE;
+
+ return temperature_value (info->temp_max, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ if (!info->valid)
+ return FALSE;
+
+ return temperature_value (info->dew, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ if (!info->valid)
+ return FALSE;
+
+ return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_update (WeatherInfo *info, time_t *value)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ if (!info->valid)
+ return FALSE;
+
+ *value = info->update;
+
+ return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ if (!info->valid || !info->sunriseValid)
+ return FALSE;
+
+ *value = info->sunrise;
+
+ return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ if (!info->valid || !info->sunsetValid)
+ return FALSE;
+
+ *value = info->sunset;
+
+ return TRUE;
+}
+
+gboolean
+weather_info_get_value_moonphase (WeatherInfo *info,
+ WeatherMoonPhase *value,
+ WeatherMoonLatitude *lat)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ if (!info->valid || !info->moonValid)
+ return FALSE;
+
+ *value = info->moonphase;
+ *lat = info->moonlatitude;
+
+ return TRUE;
+}
+
+gboolean
+weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
+{
+ gboolean res = FALSE;
+
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (speed != NULL, FALSE);
+ g_return_val_if_fail (direction != NULL, FALSE);
+
+ if (!info->valid)
+ return FALSE;
+
+ if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
+ return FALSE;
+
+ res = speed_value (info->windspeed, unit, speed, info->speed_unit);
+ *direction = info->wind;
+
+ return res;
+}
+
+gboolean
+weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ if (!info->valid)
+ return FALSE;
+
+ return pressure_value (info->pressure, unit, value, info->pressure_unit);
+}
+
+gboolean
+weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ if (!info->valid)
+ return FALSE;
+
+ return distance_value (info->visibility, unit, value, info->distance_unit);
+}
+
+/**
+ * weather_info_get_upcoming_moonphases:
+ * @info: WeatherInfo containing the time_t of interest
+ * @phases: An array of four time_t values that will hold the returned values.
+ * The values are estimates of the time of the next new, quarter, full and
+ * three-quarter moons.
+ *
+ * Returns: gboolean indicating success or failure
+ */
+gboolean
+weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (phases != NULL, FALSE);
+
+ return calc_moon_phases(info, phases);
+}
+
+static void
+_weather_internal_check (void)
+{
+ g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST);
+ g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST);
+ g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST);
+ g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST);
+}
diff --git a/libmateweather/weather.h b/libmateweather/weather.h
new file mode 100644
index 0000000..204e095
--- /dev/null
+++ b/libmateweather/weather.h
@@ -0,0 +1,288 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather.h - Public header for weather server functions.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __WEATHER_H_
+#define __WEATHER_H_
+
+
+#ifndef MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#error "libmateweather should only be used if you understand that it's subject to change, and is not supported as a fixed API/ABI or as part of the platform"
+#endif
+
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Location
+ */
+
+struct _WeatherLocation {
+ gchar *name;
+ gchar *code;
+ gchar *zone;
+ gchar *radar;
+ gboolean zone_valid;
+ gchar *coordinates;
+ gdouble latitude;
+ gdouble longitude;
+ gboolean latlon_valid;
+ gchar *country_code;
+ gchar *tz_hint;
+};
+
+typedef struct _WeatherLocation WeatherLocation;
+
+WeatherLocation * weather_location_new (const gchar *trans_name,
+ const gchar *code,
+ const gchar *zone,
+ const gchar *radar,
+ const gchar *coordinates,
+ const gchar *country_code,
+ const gchar *tz_hint);
+WeatherLocation * weather_location_clone (const WeatherLocation *location);
+void weather_location_free (WeatherLocation *location);
+gboolean weather_location_equal (const WeatherLocation *location1,
+ const WeatherLocation *location2);
+
+/*
+ * Weather prefs
+ */
+
+typedef enum _WeatherForecastType {
+ FORECAST_STATE,
+ FORECAST_ZONE,
+ FORECAST_LIST
+} WeatherForecastType;
+
+typedef enum {
+ TEMP_UNIT_INVALID = 0,
+ TEMP_UNIT_DEFAULT,
+ TEMP_UNIT_KELVIN,
+ TEMP_UNIT_CENTIGRADE,
+ TEMP_UNIT_FAHRENHEIT
+} TempUnit;
+
+typedef enum {
+ SPEED_UNIT_INVALID = 0,
+ SPEED_UNIT_DEFAULT,
+ SPEED_UNIT_MS, /* metres per second */
+ SPEED_UNIT_KPH, /* kilometres per hour */
+ SPEED_UNIT_MPH, /* miles per hour */
+ SPEED_UNIT_KNOTS, /* Knots */
+ SPEED_UNIT_BFT /* Beaufort scale */
+} SpeedUnit;
+
+typedef enum {
+ PRESSURE_UNIT_INVALID = 0,
+ PRESSURE_UNIT_DEFAULT,
+ PRESSURE_UNIT_KPA, /* kiloPascal */
+ PRESSURE_UNIT_HPA, /* hectoPascal */
+ PRESSURE_UNIT_MB, /* 1 millibars = 1 hectoPascal */
+ PRESSURE_UNIT_MM_HG, /* millimeters of mecury */
+ PRESSURE_UNIT_INCH_HG, /* inches of mercury */
+ PRESSURE_UNIT_ATM /* atmosphere */
+} PressureUnit;
+
+typedef enum {
+ DISTANCE_UNIT_INVALID = 0,
+ DISTANCE_UNIT_DEFAULT,
+ DISTANCE_UNIT_METERS,
+ DISTANCE_UNIT_KM,
+ DISTANCE_UNIT_MILES
+} DistanceUnit;
+
+struct _WeatherPrefs {
+ WeatherForecastType type;
+
+ gboolean radar;
+ const char *radar_custom_url;
+
+ TempUnit temperature_unit;
+ SpeedUnit speed_unit;
+ PressureUnit pressure_unit;
+ DistanceUnit distance_unit;
+};
+
+typedef struct _WeatherPrefs WeatherPrefs;
+
+/*
+ * Weather Info
+ */
+
+typedef struct _WeatherInfo WeatherInfo;
+
+typedef void (*WeatherInfoFunc) (WeatherInfo *info, gpointer data);
+
+WeatherInfo * _weather_info_fill (WeatherInfo *info,
+ WeatherLocation *location,
+ const WeatherPrefs *prefs,
+ WeatherInfoFunc cb,
+ gpointer data);
+#define weather_info_new(location, prefs, cb, data) _weather_info_fill (NULL, (location), (prefs), (cb), (data))
+#define weather_info_update(info, prefs, cb, data) _weather_info_fill ((info), NULL, (prefs), (cb), (data))
+
+void weather_info_abort (WeatherInfo *info);
+WeatherInfo * weather_info_clone (const WeatherInfo *info);
+void weather_info_free (WeatherInfo *info);
+
+gboolean weather_info_is_valid (WeatherInfo *info);
+gboolean weather_info_network_error (WeatherInfo *info);
+
+void weather_info_to_metric (WeatherInfo *info);
+void weather_info_to_imperial (WeatherInfo *info);
+
+const WeatherLocation * weather_info_get_location (WeatherInfo *info);
+const gchar * weather_info_get_location_name (WeatherInfo *info);
+const gchar * weather_info_get_update (WeatherInfo *info);
+const gchar * weather_info_get_sky (WeatherInfo *info);
+const gchar * weather_info_get_conditions (WeatherInfo *info);
+const gchar * weather_info_get_temp (WeatherInfo *info);
+const gchar * weather_info_get_temp_min (WeatherInfo *info);
+const gchar * weather_info_get_temp_max (WeatherInfo *info);
+const gchar * weather_info_get_dew (WeatherInfo *info);
+const gchar * weather_info_get_humidity (WeatherInfo *info);
+const gchar * weather_info_get_wind (WeatherInfo *info);
+const gchar * weather_info_get_pressure (WeatherInfo *info);
+const gchar * weather_info_get_visibility (WeatherInfo *info);
+const gchar * weather_info_get_apparent (WeatherInfo *info);
+const gchar * weather_info_get_sunrise (WeatherInfo *info);
+const gchar * weather_info_get_sunset (WeatherInfo *info);
+const gchar * weather_info_get_forecast (WeatherInfo *info);
+GSList * weather_info_get_forecast_list (WeatherInfo *info);
+GdkPixbufAnimation * weather_info_get_radar (WeatherInfo *info);
+
+const gchar * weather_info_get_temp_summary (WeatherInfo *info);
+gchar * weather_info_get_weather_summary(WeatherInfo *info);
+
+const gchar * weather_info_get_icon_name (WeatherInfo *info);
+gint weather_info_next_sun_event (WeatherInfo *info);
+
+/* values retrieving functions */
+
+enum _WeatherWindDirection {
+ WIND_INVALID = -1,
+ WIND_VARIABLE,
+ WIND_N, WIND_NNE, WIND_NE, WIND_ENE,
+ WIND_E, WIND_ESE, WIND_SE, WIND_SSE,
+ WIND_S, WIND_SSW, WIND_SW, WIND_WSW,
+ WIND_W, WIND_WNW, WIND_NW, WIND_NNW,
+ WIND_LAST
+};
+
+typedef enum _WeatherWindDirection WeatherWindDirection;
+
+enum _WeatherSky {
+ SKY_INVALID = -1,
+ SKY_CLEAR,
+ SKY_BROKEN,
+ SKY_SCATTERED,
+ SKY_FEW,
+ SKY_OVERCAST,
+ SKY_LAST
+};
+
+typedef enum _WeatherSky WeatherSky;
+
+enum _WeatherConditionPhenomenon {
+ PHENOMENON_INVALID = -1,
+
+ PHENOMENON_NONE,
+
+ PHENOMENON_DRIZZLE,
+ PHENOMENON_RAIN,
+ PHENOMENON_SNOW,
+ PHENOMENON_SNOW_GRAINS,
+ PHENOMENON_ICE_CRYSTALS,
+ PHENOMENON_ICE_PELLETS,
+ PHENOMENON_HAIL,
+ PHENOMENON_SMALL_HAIL,
+ PHENOMENON_UNKNOWN_PRECIPITATION,
+
+ PHENOMENON_MIST,
+ PHENOMENON_FOG,
+ PHENOMENON_SMOKE,
+ PHENOMENON_VOLCANIC_ASH,
+ PHENOMENON_SAND,
+ PHENOMENON_HAZE,
+ PHENOMENON_SPRAY,
+ PHENOMENON_DUST,
+
+ PHENOMENON_SQUALL,
+ PHENOMENON_SANDSTORM,
+ PHENOMENON_DUSTSTORM,
+ PHENOMENON_FUNNEL_CLOUD,
+ PHENOMENON_TORNADO,
+ PHENOMENON_DUST_WHIRLS,
+
+ PHENOMENON_LAST
+};
+
+typedef enum _WeatherConditionPhenomenon WeatherConditionPhenomenon;
+
+enum _WeatherConditionQualifier {
+ QUALIFIER_INVALID = -1,
+
+ QUALIFIER_NONE,
+
+ QUALIFIER_VICINITY,
+
+ QUALIFIER_LIGHT,
+ QUALIFIER_MODERATE,
+ QUALIFIER_HEAVY,
+ QUALIFIER_SHALLOW,
+ QUALIFIER_PATCHES,
+ QUALIFIER_PARTIAL,
+ QUALIFIER_THUNDERSTORM,
+ QUALIFIER_BLOWING,
+ QUALIFIER_SHOWERS,
+ QUALIFIER_DRIFTING,
+ QUALIFIER_FREEZING,
+
+ QUALIFIER_LAST
+};
+
+typedef enum _WeatherConditionQualifier WeatherConditionQualifier;
+typedef gdouble WeatherMoonPhase;
+typedef gdouble WeatherMoonLatitude;
+
+gboolean weather_info_get_value_update (WeatherInfo *info, time_t *value);
+gboolean weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky);
+gboolean weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier);
+gboolean weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value);
+gboolean weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value);
+gboolean weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value);
+gboolean weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value);
+gboolean weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value);
+gboolean weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction);
+gboolean weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value);
+gboolean weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value);
+gboolean weather_info_get_value_sunrise (WeatherInfo *info, time_t *value);
+gboolean weather_info_get_value_sunset (WeatherInfo *info, time_t *value);
+gboolean weather_info_get_value_moonphase (WeatherInfo *info, WeatherMoonPhase *value, WeatherMoonLatitude *lat);
+gboolean weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WEATHER_H_ */