From fe8aea1c3b5348347633da18a02b0bffd3b266a1 Mon Sep 17 00:00:00 2001 From: Perberos Date: Thu, 1 Dec 2011 21:42:39 -0300 Subject: moving from https://github.com/perberos/mate-desktop-environment --- libmateweather/AUTHORS | 5 + libmateweather/Makefile.am | 152 +++ libmateweather/Makefile.in | 1121 +++++++++++++++++ libmateweather/README | 7 + libmateweather/location-entry.c | 591 +++++++++ libmateweather/location-entry.h | 61 + libmateweather/mateweather-enum-types.c | 29 + libmateweather/mateweather-enum-types.h | 23 + libmateweather/mateweather-location.c | 814 +++++++++++++ libmateweather/mateweather-location.h | 89 ++ libmateweather/mateweather-mateconf.c | 310 +++++ libmateweather/mateweather-mateconf.h | 84 ++ libmateweather/mateweather-prefs.c | 395 ++++++ libmateweather/mateweather-prefs.h | 76 ++ libmateweather/mateweather-timezone.c | 405 +++++++ libmateweather/mateweather-timezone.h | 54 + libmateweather/mateweather-uninstalled.pc.in | 13 + libmateweather/mateweather-win32.c | 100 ++ libmateweather/mateweather-win32.h | 43 + libmateweather/mateweather-xml.c | 165 +++ libmateweather/mateweather-xml.h | 37 + libmateweather/mateweather.pc.in | 14 + libmateweather/mateweather.schemas.in | 173 +++ libmateweather/parser.c | 263 ++++ libmateweather/parser.h | 43 + libmateweather/test_locations.c | 65 + libmateweather/test_metar.c | 74 ++ libmateweather/test_sun_moon.c | 90 ++ libmateweather/timezone-menu.c | 415 +++++++ libmateweather/timezone-menu.h | 54 + libmateweather/weather-bom.c | 82 ++ libmateweather/weather-iwin.c | 475 ++++++++ libmateweather/weather-met.c | 179 +++ libmateweather/weather-metar.c | 559 +++++++++ libmateweather/weather-moon.c | 198 +++ libmateweather/weather-priv.h | 195 +++ libmateweather/weather-sun.c | 353 ++++++ libmateweather/weather-wx.c | 107 ++ libmateweather/weather.c | 1651 ++++++++++++++++++++++++++ libmateweather/weather.h | 288 +++++ 40 files changed, 9852 insertions(+) create mode 100644 libmateweather/AUTHORS create mode 100644 libmateweather/Makefile.am create mode 100644 libmateweather/Makefile.in create mode 100644 libmateweather/README create mode 100644 libmateweather/location-entry.c create mode 100644 libmateweather/location-entry.h create mode 100644 libmateweather/mateweather-enum-types.c create mode 100644 libmateweather/mateweather-enum-types.h create mode 100644 libmateweather/mateweather-location.c create mode 100644 libmateweather/mateweather-location.h create mode 100644 libmateweather/mateweather-mateconf.c create mode 100644 libmateweather/mateweather-mateconf.h create mode 100644 libmateweather/mateweather-prefs.c create mode 100644 libmateweather/mateweather-prefs.h create mode 100644 libmateweather/mateweather-timezone.c create mode 100644 libmateweather/mateweather-timezone.h create mode 100644 libmateweather/mateweather-uninstalled.pc.in create mode 100644 libmateweather/mateweather-win32.c create mode 100644 libmateweather/mateweather-win32.h create mode 100644 libmateweather/mateweather-xml.c create mode 100644 libmateweather/mateweather-xml.h create mode 100644 libmateweather/mateweather.pc.in create mode 100644 libmateweather/mateweather.schemas.in create mode 100644 libmateweather/parser.c create mode 100644 libmateweather/parser.h create mode 100644 libmateweather/test_locations.c create mode 100644 libmateweather/test_metar.c create mode 100644 libmateweather/test_sun_moon.c create mode 100644 libmateweather/timezone-menu.c create mode 100644 libmateweather/timezone-menu.h create mode 100644 libmateweather/weather-bom.c create mode 100644 libmateweather/weather-iwin.c create mode 100644 libmateweather/weather-met.c create mode 100644 libmateweather/weather-metar.c create mode 100644 libmateweather/weather-moon.c create mode 100644 libmateweather/weather-priv.h create mode 100644 libmateweather/weather-sun.c create mode 100644 libmateweather/weather-wx.c create mode 100644 libmateweather/weather.c create mode 100644 libmateweather/weather.h (limited to 'libmateweather') 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 + +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 = @MATECONF_SCHEMA_FILE_DIR@ +schema_in_files = mateweather.schemas.in +schema_DATA = $(schema_in_files:.schemas.in=.schemas) + +@INTLTOOL_SCHEMAS_RULE@ + +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. +# @configure_input@ + +# 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. + +@SET_MAKE@ + + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +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 = @build@ +host_triplet = @host@ +@OS_WIN32_TRUE@am__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 +@OS_WIN32_TRUE@am__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 $@ +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 $@ +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 $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -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 " $@; +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 $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +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 = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALL_LINGUAS = @ALL_LINGUAS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +COMPRESS_EXT = @COMPRESS_EXT@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIR = @DATADIR@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISABLE_DEPRECATED = @DISABLE_DEPRECATED@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GLADEDIR = @GLADEDIR@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_LIBS = @GLIB_LIBS@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GOBJECT_QUERY = @GOBJECT_QUERY@ +GREP = @GREP@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_LIBS = @GTK_LIBS@ +HTML_DIR = @HTML_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +INTLLIBS = @INTLLIBS@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +INTLTOOL_MERGE = @INTLTOOL_MERGE@ +INTLTOOL_PERL = @INTLTOOL_PERL@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBDIR = @LIBDIR@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@ +LIBSOUP_LIBS = @LIBSOUP_LIBS@ +LIBSOUP_MATE_CFLAGS = @LIBSOUP_MATE_CFLAGS@ +LIBSOUP_MATE_LIBS = @LIBSOUP_MATE_LIBS@ +LIBTOOL = @LIBTOOL@ +LIBXML_CFLAGS = @LIBXML_CFLAGS@ +LIBXML_LIBS = @LIBXML_LIBS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_VERSION = @LT_VERSION@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MATECONFTOOL = @MATECONFTOOL@ +MATECONF_CFLAGS = @MATECONF_CFLAGS@ +MATECONF_LIBS = @MATECONF_LIBS@ +MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@ +MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@ +MKDIR_P = @MKDIR_P@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGFMT_OPTS = @MSGFMT_OPTS@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POFILES = @POFILES@ +POSUB = @POSUB@ +PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ +PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ +PYGOBJECT_CFLAGS = @PYGOBJECT_CFLAGS@ +PYGOBJECT_LIBS = @PYGOBJECT_LIBS@ +PYGTK_DEFS = @PYGTK_DEFS@ +PYTHON = @PYTHON@ +PYTHONDIR = @PYTHONDIR@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +REGEX_LIBS = @REGEX_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +XGETTEXT = @XGETTEXT@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +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) +@OS_WIN32_FALSE@EXTRA_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 = @MATECONF_SCHEMA_FILE_DIR@ +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: @MAINTAINER_MODE_TRUE@ $(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 $@; 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)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(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: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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)/$@ +mateweather-uninstalled.pc: $(top_builddir)/config.status $(srcdir)/mateweather-uninstalled.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +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 + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-location-entry.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-mateweather-enum-types.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-mateweather-location.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-mateweather-mateconf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-mateweather-prefs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-mateweather-timezone.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-mateweather-win32.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-mateweather-xml.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-parser.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-timezone-menu.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-weather-bom.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-weather-iwin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-weather-met.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-weather-metar.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-weather-moon.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-weather-sun.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-weather-wx.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmateweather_la-weather.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_locations-test_locations.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_metar-test_metar.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_sun_moon-test_sun_moon.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libmateweather_la-weather.lo: weather.c +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather.Tpo $(DEPDIR)/libmateweather_la-weather.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='weather.c' object='libmateweather_la-weather.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather-metar.Tpo $(DEPDIR)/libmateweather_la-weather-metar.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='weather-metar.c' object='libmateweather_la-weather-metar.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather-iwin.Tpo $(DEPDIR)/libmateweather_la-weather-iwin.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='weather-iwin.c' object='libmateweather_la-weather-iwin.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather-met.Tpo $(DEPDIR)/libmateweather_la-weather-met.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='weather-met.c' object='libmateweather_la-weather-met.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather-bom.Tpo $(DEPDIR)/libmateweather_la-weather-bom.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='weather-bom.c' object='libmateweather_la-weather-bom.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather-wx.Tpo $(DEPDIR)/libmateweather_la-weather-wx.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='weather-wx.c' object='libmateweather_la-weather-wx.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather-sun.Tpo $(DEPDIR)/libmateweather_la-weather-sun.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='weather-sun.c' object='libmateweather_la-weather-sun.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-weather-moon.Tpo $(DEPDIR)/libmateweather_la-weather-moon.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='weather-moon.c' object='libmateweather_la-weather-moon.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-mateweather-enum-types.Tpo $(DEPDIR)/libmateweather_la-mateweather-enum-types.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mateweather-enum-types.c' object='libmateweather_la-mateweather-enum-types.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-mateweather-prefs.Tpo $(DEPDIR)/libmateweather_la-mateweather-prefs.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mateweather-prefs.c' object='libmateweather_la-mateweather-prefs.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-mateweather-mateconf.Tpo $(DEPDIR)/libmateweather_la-mateweather-mateconf.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mateweather-mateconf.c' object='libmateweather_la-mateweather-mateconf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-mateweather-xml.Tpo $(DEPDIR)/libmateweather_la-mateweather-xml.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mateweather-xml.c' object='libmateweather_la-mateweather-xml.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-mateweather-location.Tpo $(DEPDIR)/libmateweather_la-mateweather-location.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mateweather-location.c' object='libmateweather_la-mateweather-location.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-mateweather-timezone.Tpo $(DEPDIR)/libmateweather_la-mateweather-timezone.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mateweather-timezone.c' object='libmateweather_la-mateweather-timezone.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-location-entry.Tpo $(DEPDIR)/libmateweather_la-location-entry.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='location-entry.c' object='libmateweather_la-location-entry.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-timezone-menu.Tpo $(DEPDIR)/libmateweather_la-timezone-menu.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='timezone-menu.c' object='libmateweather_la-timezone-menu.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-parser.Tpo $(DEPDIR)/libmateweather_la-parser.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='parser.c' object='libmateweather_la-parser.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmateweather_la-mateweather-win32.Tpo $(DEPDIR)/libmateweather_la-mateweather-win32.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mateweather-win32.c' object='libmateweather_la-mateweather-win32.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_locations-test_locations.Tpo $(DEPDIR)/test_locations-test_locations.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test_locations.c' object='test_locations-test_locations.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_locations-test_locations.Tpo $(DEPDIR)/test_locations-test_locations.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test_locations.c' object='test_locations-test_locations.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_metar-test_metar.Tpo $(DEPDIR)/test_metar-test_metar.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test_metar.c' object='test_metar-test_metar.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_metar-test_metar.Tpo $(DEPDIR)/test_metar-test_metar.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test_metar.c' object='test_metar-test_metar.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_sun_moon-test_sun_moon.Tpo $(DEPDIR)/test_sun_moon-test_sun_moon.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test_sun_moon.c' object='test_sun_moon-test_sun_moon.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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 +@am__fastdepCC_TRUE@ $(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` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_sun_moon-test_sun_moon.Tpo $(DEPDIR)/test_sun_moon-test_sun_moon.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test_sun_moon.c' object='test_sun_moon-test_sun_moon.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(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) \ + "$$@" $$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) +@MATECONF_SCHEMAS_INSTALL_FALSE@uninstall-local: +@MATECONF_SCHEMAS_INSTALL_FALSE@install-data-local: +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) + +@INTLTOOL_SCHEMAS_RULE@ + +@MATECONF_SCHEMAS_INSTALL_TRUE@install-data-local: +@MATECONF_SCHEMAS_INSTALL_TRUE@ if test -z "$(DESTDIR)" ; then \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ for p in $(schema_DATA) ; do \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-install-rule $$p ; \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ done \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ fi +@MATECONF_SCHEMAS_INSTALL_TRUE@uninstall-local: +@MATECONF_SCHEMAS_INSTALL_TRUE@ for p in $(schema_DATA) ; do \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-uninstall-rule $$p ; \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ done +#$(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 + * . + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE +#include "location-entry.h" + +#include + +/** + * MateWeatherLocationEntry: + * + * A subclass of #GtkEntry that provides autocompletion on + * #MateWeatherLocations + **/ + +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 () 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: + /* with no parent , or with a single + * child . + */ + 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 + * . + */ + +#ifndef MATEWEATHER_LOCATION_ENTRY_H +#define MATEWEATHER_LOCATION_ENTRY_H 1 + +#include +#include + +#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 + +#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 + * . + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#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 + * . + */ + +#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 +#include +#include + +#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 + * . + * + * Authors: + * Philip Langdale + * Papadimitriou Spiros + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#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 + * . + * + * Authors: + * Philip Langdale + * Papadimitriou Spiros + */ + +#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 +#include +#include + +#include + +#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 + * . + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT +#include +#endif + +#include + +#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 + * . + */ + +#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 +#include + +/* 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 + * . + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#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 + * . + */ + +#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 + +#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 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datarootdir=@datarootdir@ +libdir=@libdir@ +includedir=@includedir@ + +Name: MateWeather +Description: MateWeather shared library +Version: @VERSION@ +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 + * . + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#ifdef G_OS_WIN32 + +#include + +#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 + * . + */ + +#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 + * . + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#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 + * . + */ + +#ifndef __MATEWEATHER_XML_H__ +#define __MATEWEATHER_XML_H__ + +#include +#include + +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 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datarootdir=@datarootdir@ +libdir=@libdir@ +includedir=@includedir@ + +Name: MateWeather +Description: MateWeather shared library +Version: @VERSION@ +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 @@ + + + + + /schemas/apps/mateweather/prefs/auto_update + mateweather-applet-2 + bool + true + + Update the data automatically + Determines whether the applet automatically updates its weather statistics or not. + + + + /schemas/apps/mateweather/prefs/auto_update_interval + mateweather-applet-2 + int + 1800 + + Update interval + The interval, in seconds, between automatic updates. + + + + /schemas/apps/mateweather/prefs/enable_metric + mateweather-applet-2 + bool + false + + Use metric units + Use metric units instead of english units. + + + + /schemas/apps/mateweather/prefs/distance_unit + mateweather-applet-2 + string + Default + + Distance unit + The unit to use for visibility. + + + + /schemas/apps/mateweather/prefs/pressure_unit + mateweather-applet-2 + string + Default + + Pressure unit + The unit to use for pressure. + + + + /schemas/apps/mateweather/prefs/speed_unit + mateweather-applet-2 + string + Default + + Speed unit + The unit to use for wind speed. + + + + /schemas/apps/mateweather/prefs/temperature_unit + mateweather-applet-2 + string + Default + + Temperature unit + The unit to use for temperature. + + + + /schemas/apps/mateweather/prefs/enable_detailed_forecast + mateweather-applet-2 + bool + false + + Not used anymore + + + + /schemas/apps/mateweather/prefs/enable_radar_map + mateweather-applet-2 + bool + false + + Display radar map + Fetch a radar map on each update. + + + + /schemas/apps/mateweather/prefs/location0 + mateweather-applet-2 + string + + DEFAULT_LOCATION + Weather location information + Weather location information. + + + + /schemas/apps/mateweather/prefs/location1 + mateweather-applet-2 + string + + DEFAULT_CODE + Nearby city + Nearby major zone, such as a capital city, as found from http://git.gnome.org/cgit/libmateweather/plain/data/Locations.xml.in + + + + /schemas/apps/mateweather/prefs/location2 + mateweather-applet-2 + string + + DEFAULT_ZONE + Zone location + A unique zone for the city, as found from http://git.gnome.org/cgit/libmateweather/plain/data/Locations.xml.in + + + + /schemas/apps/mateweather/prefs/location3 + mateweather-applet-2 + string + + DEFAULT_RADAR + Radar location + 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 + + + + /schemas/apps/mateweather/prefs/location4 + mateweather-applet-2 + string + + DEFAULT_LOCATION + Weather for a city + The city that mateweather displays information for. + + + + /schemas/apps/mateweather/prefs/coordinates + mateweather-applet-2 + string + + DEFAULT_COORDINATES + Location coordinates + Latitude and longitude of your location expressed in DD-MM-SS[NS] DD-MM-SS[EW]. + + + + /schemas/apps/mateweather/prefs/use_custom_radar_url + mateweather-applet-2 + bool + false + + Use custom url for the radar map + If true, then retrieve a radar map from a location specified by the "radar" key. + + + + /schemas/apps/mateweather/prefs/radar + mateweather-applet-2 + string + + Url for the radar map + The custom url from where to retrieve a radar map. + + + + 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 + * . + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE +#include "weather-priv.h" + +#include "parser.h" + +#include +#include +#include + +/** + * 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 + * . + */ + +#ifndef MATEWEATHER_PARSER_H +#define MATEWEATHER_PARSER_H 1 + +#include +#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 +#include +#include +#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 +#include +#include + +#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, >ime, + "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 + * . + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE +#include "timezone-menu.h" +#include "weather-priv.h" + +#include + +/** + * 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 (%s)", + 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 ("%s", 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 + * . + */ + +#ifndef MATEWEATHER_TIMEZONE_MENU_H +#define MATEWEATHER_TIMEZONE_MENU_H 1 + +#include +#include + +#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 + * . + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#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, "
");
+    g_return_val_if_fail (p != NULL, NULL);
+
+    rp = strstr (p, "
"); + g_return_val_if_fail (rp !=NULL, NULL); + + p += 5; /* skip the
 */
+
+    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
+ * .
+ */
+
+#ifdef HAVE_CONFIG_H
+#include 
+#endif
+
+#include 
+#include 
+#include 
+
+#include 
+
+#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  */
+                                    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
+ * .
+ */
+
+#ifdef HAVE_CONFIG_H
+#include 
+#endif
+
+#include 
+#include 
+#include 
+
+#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, "&", 5) == 0) {
+		*o++ = '&';
+		count++;
+		p += 5;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "<", 4) == 0) {
+		*o++ = '<';
+		count++;
+		p += 4;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, ">", 4) == 0) {
+		*o++ = '>';
+		count++;
+		p += 4;
+		continue;
+	    }
+	}
+	if (*p == '<') {
+	    if (g_ascii_strncasecmp (p, "
", 4) == 0) { + *o++ = '\n'; + count = 0; + } + if (g_ascii_strncasecmp (p, "", 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: "); + 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 + * . + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#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 + * . + */ + +/* + * Formulas from: + * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith + * Cambridge University Press 1988 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef __FreeBSD__ +#include +#endif + +#include +#include +#include +#include + +#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 + * . + */ + +#ifndef __WEATHER_PRIV_H_ +#define __WEATHER_PRIV_H_ + +#include "config.h" + +#include +#include +#include +#ifdef HAVE_LIBSOUP_MATE +#include +#else +#include +#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 + * . + */ + +/* + * 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 +#endif + +#include +#include +#include + +#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, <m); + ltm.tm_sec = 0; + ltm.tm_min = 0; + ltm.tm_hour = 0; + ltm.tm_mday++; + nxtEvent = mktime (<m); + + 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 + * . + */ + +#ifdef HAVE_CONFIG_H +#include +#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 + * . + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_VALUES_H +#include +#endif + +#include +#include + +#include +#include + +#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", °, &min); + sec = 0; + } else if (p2 == 1 + p1) { + return DBL_MAX; + } else { + sscanf (latlon, "%d-%d-%d", °, &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 */ + +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 + * . + */ + +#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 + +#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_ */ -- cgit v1.2.1