From c51ef797a707f4e2c6f9688d4378f2b0e9898a66 Mon Sep 17 00:00:00 2001 From: Perberos Date: Thu, 1 Dec 2011 22:56:10 -0300 Subject: moving from https://github.com/perberos/mate-desktop-environment --- applets/clock/Makefile.am | 205 ++ applets/clock/Makefile.in | 1595 +++++++++ applets/clock/calendar-client.c | 2169 ++++++++++++ applets/clock/calendar-client.h | 153 + applets/clock/calendar-debug.h | 56 + applets/clock/calendar-sources.c | 658 ++++ applets/clock/calendar-sources.h | 70 + applets/clock/calendar-window.c | 2125 +++++++++++ applets/clock/calendar-window.h | 84 + applets/clock/clock-face.c | 462 +++ applets/clock/clock-face.h | 64 + applets/clock/clock-location-tile.c | 728 ++++ applets/clock/clock-location-tile.h | 51 + applets/clock/clock-location.c | 894 +++++ applets/clock/clock-location.h | 87 + applets/clock/clock-map.c | 700 ++++ applets/clock/clock-map.h | 43 + applets/clock/clock-marshallers.list | 3 + applets/clock/clock-menu.xml | 8 + applets/clock/clock-sunpos.c | 197 + applets/clock/clock-sunpos.h | 8 + applets/clock/clock-utils.c | 127 + applets/clock/clock-utils.h | 57 + applets/clock/clock.c | 3745 ++++++++++++++++++++ applets/clock/clock.h | 41 + applets/clock/clock.schemas.in | 313 ++ applets/clock/clock.ui | 1136 ++++++ ....mate.panel.ClockApplet.mate-panel-applet.in.in | 18 + ...mate.panel.applet.ClockAppletFactory.service.in | 3 + applets/clock/pixmaps/Makefile.am | 21 + applets/clock/pixmaps/Makefile.in | 537 +++ applets/clock/pixmaps/clock-calendar-icon.png | Bin 0 -> 653 bytes applets/clock/pixmaps/clock-face-large.svg | 291 ++ applets/clock/pixmaps/clock-face-small-day.svg | 290 ++ applets/clock/pixmaps/clock-face-small-evening.svg | 290 ++ applets/clock/pixmaps/clock-face-small-morning.svg | 290 ++ applets/clock/pixmaps/clock-face-small-night.svg | 291 ++ applets/clock/pixmaps/clock-face-small.svg | 290 ++ .../clock/pixmaps/clock-map-location-current.png | Bin 0 -> 379 bytes .../clock/pixmaps/clock-map-location-hilight.png | Bin 0 -> 346 bytes .../clock/pixmaps/clock-map-location-marker.png | Bin 0 -> 283 bytes applets/clock/pixmaps/clock-map.png | Bin 0 -> 25244 bytes applets/clock/pixmaps/clock-map.svg | 755 ++++ applets/clock/set-timezone.c | 291 ++ applets/clock/set-timezone.h | 40 + applets/clock/system-timezone.c | 1048 ++++++ applets/clock/system-timezone.h | 87 + applets/clock/test-system-timezone.c | 122 + 48 files changed, 20443 insertions(+) create mode 100644 applets/clock/Makefile.am create mode 100644 applets/clock/Makefile.in create mode 100644 applets/clock/calendar-client.c create mode 100644 applets/clock/calendar-client.h create mode 100644 applets/clock/calendar-debug.h create mode 100644 applets/clock/calendar-sources.c create mode 100644 applets/clock/calendar-sources.h create mode 100644 applets/clock/calendar-window.c create mode 100644 applets/clock/calendar-window.h create mode 100644 applets/clock/clock-face.c create mode 100644 applets/clock/clock-face.h create mode 100644 applets/clock/clock-location-tile.c create mode 100644 applets/clock/clock-location-tile.h create mode 100644 applets/clock/clock-location.c create mode 100644 applets/clock/clock-location.h create mode 100644 applets/clock/clock-map.c create mode 100644 applets/clock/clock-map.h create mode 100644 applets/clock/clock-marshallers.list create mode 100644 applets/clock/clock-menu.xml create mode 100644 applets/clock/clock-sunpos.c create mode 100644 applets/clock/clock-sunpos.h create mode 100644 applets/clock/clock-utils.c create mode 100644 applets/clock/clock-utils.h create mode 100644 applets/clock/clock.c create mode 100644 applets/clock/clock.h create mode 100644 applets/clock/clock.schemas.in create mode 100644 applets/clock/clock.ui create mode 100644 applets/clock/org.mate.panel.ClockApplet.mate-panel-applet.in.in create mode 100644 applets/clock/org.mate.panel.applet.ClockAppletFactory.service.in create mode 100644 applets/clock/pixmaps/Makefile.am create mode 100644 applets/clock/pixmaps/Makefile.in create mode 100644 applets/clock/pixmaps/clock-calendar-icon.png create mode 100644 applets/clock/pixmaps/clock-face-large.svg create mode 100644 applets/clock/pixmaps/clock-face-small-day.svg create mode 100644 applets/clock/pixmaps/clock-face-small-evening.svg create mode 100644 applets/clock/pixmaps/clock-face-small-morning.svg create mode 100644 applets/clock/pixmaps/clock-face-small-night.svg create mode 100644 applets/clock/pixmaps/clock-face-small.svg create mode 100644 applets/clock/pixmaps/clock-map-location-current.png create mode 100644 applets/clock/pixmaps/clock-map-location-hilight.png create mode 100644 applets/clock/pixmaps/clock-map-location-marker.png create mode 100644 applets/clock/pixmaps/clock-map.png create mode 100644 applets/clock/pixmaps/clock-map.svg create mode 100644 applets/clock/set-timezone.c create mode 100644 applets/clock/set-timezone.h create mode 100644 applets/clock/system-timezone.c create mode 100644 applets/clock/system-timezone.h create mode 100644 applets/clock/test-system-timezone.c (limited to 'applets/clock') diff --git a/applets/clock/Makefile.am b/applets/clock/Makefile.am new file mode 100644 index 00000000..afda6eb2 --- /dev/null +++ b/applets/clock/Makefile.am @@ -0,0 +1,205 @@ +SUBDIRS = pixmaps + +noinst_LTLIBRARIES = libsystem-timezone.la +noinst_PROGRAMS = test-system-timezone + +AM_CPPFLAGS = \ + $(TZ_CFLAGS) \ + $(DISABLE_DEPRECATED_CFLAGS) + +AM_CFLAGS = $(WARN_CFLAGS) + +libsystem_timezone_la_SOURCES = \ + system-timezone.c \ + system-timezone.h +libsystem_timezone_la_LIBADD = $(TZ_LIBS) + +if HAVE_LIBECAL +CALENDAR_SOURCES = \ + calendar-client.c \ + calendar-client.h \ + calendar-sources.c \ + calendar-sources.h \ + calendar-debug.h +endif + +CLOCK_SOURCES = \ + calendar-window.c \ + calendar-window.h \ + clock.c \ + clock.h \ + clock-face.c \ + clock-face.h \ + clock-location.c \ + clock-location.h \ + clock-location-tile.c \ + clock-location-tile.h \ + clock-map.c \ + clock-map.h \ + clock-sunpos.c \ + clock-sunpos.h \ + clock-utils.c \ + clock-utils.h \ + set-timezone.c \ + set-timezone.h \ + $(BUILT_SOURCES) \ + $(CALENDAR_SOURCES) + +CLOCK_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + $(LIBMATE_PANEL_APPLET_CFLAGS) \ + $(CLOCK_CFLAGS) \ + -I$(srcdir)/../../libmate-panel-applet \ + -I$(top_builddir)/libmate-panel-applet \ + -DMATELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ + -DBUILDERDIR=\""$(uidir)"\" \ + -DCLOCK_MENU_UI_DIR=\""$(xmluidir)"\" \ + -DICONDIR=\""$(datadir)/mate-panel/pixmaps"\" \ + -DCLOCK_EDS_ICONDIR="\"$(CLOCK_EDS_ICONDIR)\"" \ + -DMATEWEATHER_I_KNOW_THIS_IS_UNSTABLE + +CLOCK_LDADD = \ + ../../libmate-panel-applet/libmate-panel-applet-3.la \ + $(CLOCK_LIBS) \ + $(LIBMATE_PANEL_APPLET_LIBS) \ + libsystem-timezone.la \ + -lm + +test_system_timezone_SOURCES = \ + test-system-timezone.c +test_system_timezone_LDADD = libsystem-timezone.la + +if CLOCK_INPROCESS +APPLET_IN_PROCESS = true +APPLET_LOCATION = $(pkglibdir)/libclock-applet.so + +clock_appletlibdir = $(pkglibdir) +clock_appletlib_LTLIBRARIES = libclock-applet.la +libclock_applet_la_SOURCES = $(CLOCK_SOURCES) +libclock_applet_la_CPPFLAGS = $(CLOCK_CPPFLAGS) +libclock_applet_la_LIBADD = $(CLOCK_LDADD) +libclock_applet_la_LDFLAGS = -module -avoid-version +libclock_applet_la_CFLAGS = $(AM_CFLAGS) +$(libclock_applet_la_OBJECTS): $(BUILT_SOURCES) +else +APPLET_IN_PROCESS = false +APPLET_LOCATION = $(libexecdir)/clock-applet + +libexec_PROGRAMS = clock-applet +clock_applet_SOURCES = $(CLOCK_SOURCES) +clock_applet_CPPFLAGS = $(CLOCK_CPPFLAGS) +clock_applet_LDADD = $(CLOCK_LDADD) +clock_applet_CFLAGS = $(AM_CFLAGS) +$(clock_applet_OBJECTS): $(BUILT_SOURCES) +endif + +clock-marshallers.c: clock-marshallers.list + $(AM_V_GEN)glib-genmarshal --prefix _clock_marshal --header --body --internal $< > $@ + +clock-marshallers.h: clock-marshallers.list + $(AM_V_GEN)glib-genmarshal --prefix _clock_marshal --header --internal $< > $@ + +clock_enum_headers = \ + $(top_srcdir)/applets/clock/clock-utils.h + +clock-typebuiltins.c: @REBUILD@ $(clock_enum_headers) + $(AM_V_GEN)glib-mkenums \ + --fhead "#include \n" \ + --fhead "#include \"clock-typebuiltins.h\"\n\n" \ + --fprod "\n/* enumerations from \"@filename@\" */" \ + --fprod "\n#include \"@filename@\"\n" \ + --vhead "static const GEnumValue _@enum_name@_values[] = {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n};\n\n" \ + --vtail "GType\n@enum_name@_get_type (void)\n{\n" \ + --vtail " static GType type = 0;\n\n" \ + --vtail " if (!type)\n" \ + --vtail " type = g_enum_register_static (\"@EnumName@\", _@enum_name@_values);\n\n" \ + --vtail " return type;\n}\n\n" \ + $(clock_enum_headers) > $@ + +clock-typebuiltins.h: @REBUILD@ $(clock_enum_headers) + $(AM_V_GEN)glib-mkenums \ + --fhead "#ifndef __CLOCK_TYPEBUILTINS_H__\n" \ + --fhead "#define __CLOCK_TYPEBUILTINS_H__ 1\n\n" \ + --fhead "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n" \ + --ftail "#ifdef __cplusplus\n}\n#endif\n\n" \ + --ftail "#endif /* __CLOCK_TYPEBUILTINS_H__ */\n" \ + --fprod "\n/* --- @filename@ --- */" \ + --eprod "#define CLOCK_TYPE_@ENUMSHORT@ @enum_name@_get_type()\n" \ + --eprod "GType @enum_name@_get_type (void);\n" \ + $(clock_enum_headers) > $@ + +BUILT_SOURCES = \ + clock-marshallers.c \ + clock-marshallers.h \ + clock-typebuiltins.c \ + clock-typebuiltins.h + +appletdir = $(datadir)/mate-panel/applets +applet_in_files = org.mate.panel.ClockApplet.mate-panel-applet.in +applet_DATA = $(applet_in_files:.mate-panel-applet.in=.mate-panel-applet) + +$(applet_in_files): $(applet_in_files).in Makefile + $(AM_V_GEN)sed \ + -e "s|\@LOCATION\@|$(APPLET_LOCATION)|" \ + -e "s|\@IN_PROCESS\@|$(APPLET_IN_PROCESS)|" \ + -e "s|\@VERSION\@|$(PACKAGE_VERSION)|" \ + $< > $@ + +@PANEL_INTLTOOL_MATE_PANEL_APPLET_RULE@ + +if !CLOCK_INPROCESS +servicedir = $(datadir)/dbus-1/services +service_in_files = org.mate.panel.applet.ClockAppletFactory.service.in +service_DATA = $(service_in_files:.service.in=.service) + +org.mate.panel.applet.ClockAppletFactory.service: $(service_in_files) + $(AM_V_GEN)sed \ + -e "s|\@LOCATION\@|$(APPLET_LOCATION)|" \ + $< > $@ +endif + +uidir = $(datadir)/mate-panel/ui +ui_DATA = clock.ui + +xmluidir = $(datadir)/mate-panel/ui +xmlui_DATA = clock-menu.xml + +schemasdir = $(MATECONF_SCHEMA_FILE_DIR) +schemas_in_files = clock.schemas.in +schemas_DATA = $(schemas_in_files:.schemas.in=.schemas) + +@INTLTOOL_SCHEMAS_RULE@ + +if MATECONF_SCHEMAS_INSTALL +install-data-local: + if test -z "$(DESTDIR)" ; then \ + for p in $(schemas_DATA) ; do \ + MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-install-rule $(top_builddir)/applets/clock/$$p ; \ + done \ + fi +uninstall-local: + for p in $(schema_DATA) ; do \ + MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-uninstall-rule $(top_builddir)/applets/clock/$$p ; \ + done +endif + +EXTRA_DIST = \ + org.mate.panel.ClockApplet.mate-panel-applet.in.in \ + $(schemas_in_files) \ + $(xmlui_DATA) \ + $(ui_DATA) \ + clock-marshallers.list \ + $(service_in_files) + +CLEANFILES = \ + $(BUILT_SOURCES) \ + $(applet_DATA) \ + $(applet_DATA).in \ + $(service_DATA) \ + $(schemas_DATA) \ + $(polkit_DATA) \ + $(dbus_services_DATA) + +-include $(top_srcdir)/git.mk diff --git a/applets/clock/Makefile.in b/applets/clock/Makefile.in new file mode 100644 index 00000000..e51ce949 --- /dev/null +++ b/applets/clock/Makefile.in @@ -0,0 +1,1595 @@ +# 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@ +noinst_PROGRAMS = test-system-timezone$(EXEEXT) +@CLOCK_INPROCESS_FALSE@libexec_PROGRAMS = clock-applet$(EXEEXT) +subdir = applets/clock +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/d-type.m4 \ + $(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)/m4/mate-doc-utils.m4 $(top_srcdir)/configure.ac +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 = +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)$(clock_appletlibdir)" \ + "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(appletdir)" \ + "$(DESTDIR)$(schemasdir)" "$(DESTDIR)$(servicedir)" \ + "$(DESTDIR)$(uidir)" "$(DESTDIR)$(xmluidir)" +LTLIBRARIES = $(clock_appletlib_LTLIBRARIES) $(noinst_LTLIBRARIES) +am__DEPENDENCIES_1 = +am__DEPENDENCIES_2 = \ + ../../libmate-panel-applet/libmate-panel-applet-3.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + libsystem-timezone.la +@CLOCK_INPROCESS_TRUE@libclock_applet_la_DEPENDENCIES = \ +@CLOCK_INPROCESS_TRUE@ $(am__DEPENDENCIES_2) +am__libclock_applet_la_SOURCES_DIST = calendar-window.c \ + calendar-window.h clock.c clock.h clock-face.c clock-face.h \ + clock-location.c clock-location.h clock-location-tile.c \ + clock-location-tile.h clock-map.c clock-map.h clock-sunpos.c \ + clock-sunpos.h clock-utils.c clock-utils.h set-timezone.c \ + set-timezone.h clock-marshallers.c clock-marshallers.h \ + clock-typebuiltins.c clock-typebuiltins.h calendar-client.c \ + calendar-client.h calendar-sources.c calendar-sources.h \ + calendar-debug.h +am__objects_1 = libclock_applet_la-clock-marshallers.lo \ + libclock_applet_la-clock-typebuiltins.lo +@HAVE_LIBECAL_TRUE@am__objects_2 = \ +@HAVE_LIBECAL_TRUE@ libclock_applet_la-calendar-client.lo \ +@HAVE_LIBECAL_TRUE@ libclock_applet_la-calendar-sources.lo +am__objects_3 = libclock_applet_la-calendar-window.lo \ + libclock_applet_la-clock.lo libclock_applet_la-clock-face.lo \ + libclock_applet_la-clock-location.lo \ + libclock_applet_la-clock-location-tile.lo \ + libclock_applet_la-clock-map.lo \ + libclock_applet_la-clock-sunpos.lo \ + libclock_applet_la-clock-utils.lo \ + libclock_applet_la-set-timezone.lo $(am__objects_1) \ + $(am__objects_2) +@CLOCK_INPROCESS_TRUE@am_libclock_applet_la_OBJECTS = \ +@CLOCK_INPROCESS_TRUE@ $(am__objects_3) +libclock_applet_la_OBJECTS = $(am_libclock_applet_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libclock_applet_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libclock_applet_la_CFLAGS) $(CFLAGS) \ + $(libclock_applet_la_LDFLAGS) $(LDFLAGS) -o $@ +@CLOCK_INPROCESS_TRUE@am_libclock_applet_la_rpath = -rpath \ +@CLOCK_INPROCESS_TRUE@ $(clock_appletlibdir) +libsystem_timezone_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_libsystem_timezone_la_OBJECTS = system-timezone.lo +libsystem_timezone_la_OBJECTS = $(am_libsystem_timezone_la_OBJECTS) +PROGRAMS = $(libexec_PROGRAMS) $(noinst_PROGRAMS) +am__clock_applet_SOURCES_DIST = calendar-window.c calendar-window.h \ + clock.c clock.h clock-face.c clock-face.h clock-location.c \ + clock-location.h clock-location-tile.c clock-location-tile.h \ + clock-map.c clock-map.h clock-sunpos.c clock-sunpos.h \ + clock-utils.c clock-utils.h set-timezone.c set-timezone.h \ + clock-marshallers.c clock-marshallers.h clock-typebuiltins.c \ + clock-typebuiltins.h calendar-client.c calendar-client.h \ + calendar-sources.c calendar-sources.h calendar-debug.h +am__objects_4 = clock_applet-clock-marshallers.$(OBJEXT) \ + clock_applet-clock-typebuiltins.$(OBJEXT) +@HAVE_LIBECAL_TRUE@am__objects_5 = \ +@HAVE_LIBECAL_TRUE@ clock_applet-calendar-client.$(OBJEXT) \ +@HAVE_LIBECAL_TRUE@ clock_applet-calendar-sources.$(OBJEXT) +am__objects_6 = clock_applet-calendar-window.$(OBJEXT) \ + clock_applet-clock.$(OBJEXT) clock_applet-clock-face.$(OBJEXT) \ + clock_applet-clock-location.$(OBJEXT) \ + clock_applet-clock-location-tile.$(OBJEXT) \ + clock_applet-clock-map.$(OBJEXT) \ + clock_applet-clock-sunpos.$(OBJEXT) \ + clock_applet-clock-utils.$(OBJEXT) \ + clock_applet-set-timezone.$(OBJEXT) $(am__objects_4) \ + $(am__objects_5) +@CLOCK_INPROCESS_FALSE@am_clock_applet_OBJECTS = $(am__objects_6) +clock_applet_OBJECTS = $(am_clock_applet_OBJECTS) +@CLOCK_INPROCESS_FALSE@clock_applet_DEPENDENCIES = \ +@CLOCK_INPROCESS_FALSE@ $(am__DEPENDENCIES_2) +clock_applet_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(clock_applet_CFLAGS) \ + $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +am_test_system_timezone_OBJECTS = test-system-timezone.$(OBJEXT) +test_system_timezone_OBJECTS = $(am_test_system_timezone_OBJECTS) +test_system_timezone_DEPENDENCIES = libsystem-timezone.la +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 = $(libclock_applet_la_SOURCES) \ + $(libsystem_timezone_la_SOURCES) $(clock_applet_SOURCES) \ + $(test_system_timezone_SOURCES) +DIST_SOURCES = $(am__libclock_applet_la_SOURCES_DIST) \ + $(libsystem_timezone_la_SOURCES) \ + $(am__clock_applet_SOURCES_DIST) \ + $(test_system_timezone_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +DATA = $(applet_DATA) $(schemas_DATA) $(service_DATA) $(ui_DATA) \ + $(xmlui_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALL_LINGUAS = @ALL_LINGUAS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLOCK_CFLAGS = @CLOCK_CFLAGS@ +CLOCK_EDS_ICONDIR = @CLOCK_EDS_ICONDIR@ +CLOCK_LIBS = @CLOCK_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISABLE_DEPRECATED = @DISABLE_DEPRECATED@ +DISABLE_DEPRECATED_CFLAGS = @DISABLE_DEPRECATED_CFLAGS@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DOC_USER_FORMATS = @DOC_USER_FORMATS@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGG_SMCLIENT_CFLAGS = @EGG_SMCLIENT_CFLAGS@ +EGG_SMCLIENT_LIBS = @EGG_SMCLIENT_LIBS@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FISH_CFLAGS = @FISH_CFLAGS@ +FISH_LIBS = @FISH_LIBS@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GIO_QUERYMODULES = @GIO_QUERYMODULES@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GREP = @GREP@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +HELP_DIR = @HELP_DIR@ +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@ +INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@ +INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@ +INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@ +INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@ +INTROSPECTION_LIBS = @INTROSPECTION_LIBS@ +INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@ +INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@ +INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBMATE_PANEL_APPLET_CFLAGS = @LIBMATE_PANEL_APPLET_CFLAGS@ +LIBMATE_PANEL_APPLET_LIBS = @LIBMATE_PANEL_APPLET_LIBS@ +LIBMATE_PANEL_APPLET_MATECOMPONENT_CFLAGS = @LIBMATE_PANEL_APPLET_MATECOMPONENT_CFLAGS@ +LIBMATE_PANEL_APPLET_MATECOMPONENT_LIBS = @LIBMATE_PANEL_APPLET_MATECOMPONENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MATE_PANEL_APPLET_LT_VERSION = @LIB_MATE_PANEL_APPLET_LT_VERSION@ +LIB_MATE_PANEL_APPLET_MATECOMPONENT_LT_VERSION = @LIB_MATE_PANEL_APPLET_MATECOMPONENT_LT_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MATECOMPONENT_ACT_IDLDIR = @MATECOMPONENT_ACT_IDLDIR@ +MATECOMPONENT_CFLAGS = @MATECOMPONENT_CFLAGS@ +MATECOMPONENT_IDLDIR = @MATECOMPONENT_IDLDIR@ +MATECOMPONENT_LIBS = @MATECOMPONENT_LIBS@ +MATECONFTOOL = @MATECONFTOOL@ +MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@ +MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@ +MATECORBA_IDL = @MATECORBA_IDL@ +MKDIR_P = @MKDIR_P@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGFMT_OPTS = @MSGFMT_OPTS@ +MSGMERGE = @MSGMERGE@ +NETWORK_MANAGER_CFLAGS = @NETWORK_MANAGER_CFLAGS@ +NETWORK_MANAGER_LIBS = @NETWORK_MANAGER_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NOTIFICATION_AREA_CFLAGS = @NOTIFICATION_AREA_CFLAGS@ +NOTIFICATION_AREA_LIBS = @NOTIFICATION_AREA_LIBS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OMF_DIR = @OMF_DIR@ +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@ +PANEL_CFLAGS = @PANEL_CFLAGS@ +PANEL_INTLTOOL_MATE_PANEL_APPLET_RULE = @PANEL_INTLTOOL_MATE_PANEL_APPLET_RULE@ +PANEL_LIBS = @PANEL_LIBS@ +PANEL_MODULE_MATECOMPONENT_CFLAGS = @PANEL_MODULE_MATECOMPONENT_CFLAGS@ +PANEL_MODULE_MATECOMPONENT_LIBS = @PANEL_MODULE_MATECOMPONENT_LIBS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +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@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +REBUILD = @REBUILD@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TZ_CFLAGS = @TZ_CFLAGS@ +TZ_LIBS = @TZ_LIBS@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +WNCKLET_CFLAGS = @WNCKLET_CFLAGS@ +WNCKLET_LIBS = @WNCKLET_LIBS@ +XGETTEXT = @XGETTEXT@ +XMKMF = @XMKMF@ +XRANDR_CFLAGS = @XRANDR_CFLAGS@ +XRANDR_LIBS = @XRANDR_LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +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@ +appletsdir = @appletsdir@ +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@ +modulesdir = @modulesdir@ +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@ +SUBDIRS = pixmaps +noinst_LTLIBRARIES = libsystem-timezone.la +AM_CPPFLAGS = \ + $(TZ_CFLAGS) \ + $(DISABLE_DEPRECATED_CFLAGS) + +AM_CFLAGS = $(WARN_CFLAGS) +libsystem_timezone_la_SOURCES = \ + system-timezone.c \ + system-timezone.h + +libsystem_timezone_la_LIBADD = $(TZ_LIBS) +@HAVE_LIBECAL_TRUE@CALENDAR_SOURCES = \ +@HAVE_LIBECAL_TRUE@ calendar-client.c \ +@HAVE_LIBECAL_TRUE@ calendar-client.h \ +@HAVE_LIBECAL_TRUE@ calendar-sources.c \ +@HAVE_LIBECAL_TRUE@ calendar-sources.h \ +@HAVE_LIBECAL_TRUE@ calendar-debug.h + +CLOCK_SOURCES = \ + calendar-window.c \ + calendar-window.h \ + clock.c \ + clock.h \ + clock-face.c \ + clock-face.h \ + clock-location.c \ + clock-location.h \ + clock-location-tile.c \ + clock-location-tile.h \ + clock-map.c \ + clock-map.h \ + clock-sunpos.c \ + clock-sunpos.h \ + clock-utils.c \ + clock-utils.h \ + set-timezone.c \ + set-timezone.h \ + $(BUILT_SOURCES) \ + $(CALENDAR_SOURCES) + +CLOCK_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + $(LIBMATE_PANEL_APPLET_CFLAGS) \ + $(CLOCK_CFLAGS) \ + -I$(srcdir)/../../libmate-panel-applet \ + -I$(top_builddir)/libmate-panel-applet \ + -DMATELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ + -DBUILDERDIR=\""$(uidir)"\" \ + -DCLOCK_MENU_UI_DIR=\""$(xmluidir)"\" \ + -DICONDIR=\""$(datadir)/mate-panel/pixmaps"\" \ + -DCLOCK_EDS_ICONDIR="\"$(CLOCK_EDS_ICONDIR)\"" \ + -DMATEWEATHER_I_KNOW_THIS_IS_UNSTABLE + +CLOCK_LDADD = \ + ../../libmate-panel-applet/libmate-panel-applet-3.la \ + $(CLOCK_LIBS) \ + $(LIBMATE_PANEL_APPLET_LIBS) \ + libsystem-timezone.la \ + -lm + +test_system_timezone_SOURCES = \ + test-system-timezone.c + +test_system_timezone_LDADD = libsystem-timezone.la +@CLOCK_INPROCESS_FALSE@APPLET_IN_PROCESS = false +@CLOCK_INPROCESS_TRUE@APPLET_IN_PROCESS = true +@CLOCK_INPROCESS_FALSE@APPLET_LOCATION = $(libexecdir)/clock-applet +@CLOCK_INPROCESS_TRUE@APPLET_LOCATION = $(pkglibdir)/libclock-applet.so +@CLOCK_INPROCESS_TRUE@clock_appletlibdir = $(pkglibdir) +@CLOCK_INPROCESS_TRUE@clock_appletlib_LTLIBRARIES = libclock-applet.la +@CLOCK_INPROCESS_TRUE@libclock_applet_la_SOURCES = $(CLOCK_SOURCES) +@CLOCK_INPROCESS_TRUE@libclock_applet_la_CPPFLAGS = $(CLOCK_CPPFLAGS) +@CLOCK_INPROCESS_TRUE@libclock_applet_la_LIBADD = $(CLOCK_LDADD) +@CLOCK_INPROCESS_TRUE@libclock_applet_la_LDFLAGS = -module -avoid-version +@CLOCK_INPROCESS_TRUE@libclock_applet_la_CFLAGS = $(AM_CFLAGS) +@CLOCK_INPROCESS_FALSE@clock_applet_SOURCES = $(CLOCK_SOURCES) +@CLOCK_INPROCESS_FALSE@clock_applet_CPPFLAGS = $(CLOCK_CPPFLAGS) +@CLOCK_INPROCESS_FALSE@clock_applet_LDADD = $(CLOCK_LDADD) +@CLOCK_INPROCESS_FALSE@clock_applet_CFLAGS = $(AM_CFLAGS) +clock_enum_headers = \ + $(top_srcdir)/applets/clock/clock-utils.h + +BUILT_SOURCES = \ + clock-marshallers.c \ + clock-marshallers.h \ + clock-typebuiltins.c \ + clock-typebuiltins.h + +appletdir = $(datadir)/mate-panel/applets +applet_in_files = org.mate.panel.ClockApplet.mate-panel-applet.in +applet_DATA = $(applet_in_files:.mate-panel-applet.in=.mate-panel-applet) +@CLOCK_INPROCESS_FALSE@servicedir = $(datadir)/dbus-1/services +@CLOCK_INPROCESS_FALSE@service_in_files = org.mate.panel.applet.ClockAppletFactory.service.in +@CLOCK_INPROCESS_FALSE@service_DATA = $(service_in_files:.service.in=.service) +uidir = $(datadir)/mate-panel/ui +ui_DATA = clock.ui +xmluidir = $(datadir)/mate-panel/ui +xmlui_DATA = clock-menu.xml +schemasdir = $(MATECONF_SCHEMA_FILE_DIR) +schemas_in_files = clock.schemas.in +schemas_DATA = $(schemas_in_files:.schemas.in=.schemas) +EXTRA_DIST = \ + org.mate.panel.ClockApplet.mate-panel-applet.in.in \ + $(schemas_in_files) \ + $(xmlui_DATA) \ + $(ui_DATA) \ + clock-marshallers.list \ + $(service_in_files) + +CLEANFILES = \ + $(BUILT_SOURCES) \ + $(applet_DATA) \ + $(applet_DATA).in \ + $(service_DATA) \ + $(schemas_DATA) \ + $(polkit_DATA) \ + $(dbus_services_DATA) + +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.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 applets/clock/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu applets/clock/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): +install-clock_appletlibLTLIBRARIES: $(clock_appletlib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(clock_appletlibdir)" || $(MKDIR_P) "$(DESTDIR)$(clock_appletlibdir)" + @list='$(clock_appletlib_LTLIBRARIES)'; test -n "$(clock_appletlibdir)" || 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)$(clock_appletlibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(clock_appletlibdir)"; \ + } + +uninstall-clock_appletlibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(clock_appletlib_LTLIBRARIES)'; test -n "$(clock_appletlibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(clock_appletlibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(clock_appletlibdir)/$$f"; \ + done + +clean-clock_appletlibLTLIBRARIES: + -test -z "$(clock_appletlib_LTLIBRARIES)" || rm -f $(clock_appletlib_LTLIBRARIES) + @list='$(clock_appletlib_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 + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_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 +libclock-applet.la: $(libclock_applet_la_OBJECTS) $(libclock_applet_la_DEPENDENCIES) + $(AM_V_CCLD)$(libclock_applet_la_LINK) $(am_libclock_applet_la_rpath) $(libclock_applet_la_OBJECTS) $(libclock_applet_la_LIBADD) $(LIBS) +libsystem-timezone.la: $(libsystem_timezone_la_OBJECTS) $(libsystem_timezone_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libsystem_timezone_la_OBJECTS) $(libsystem_timezone_la_LIBADD) $(LIBS) +install-libexecPROGRAMS: $(libexec_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(libexecdir)" || $(MKDIR_P) "$(DESTDIR)$(libexecdir)" + @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-libexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(libexecdir)" && rm -f $$files + +clean-libexecPROGRAMS: + @list='$(libexec_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 + +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 +clock-applet$(EXEEXT): $(clock_applet_OBJECTS) $(clock_applet_DEPENDENCIES) + @rm -f clock-applet$(EXEEXT) + $(AM_V_CCLD)$(clock_applet_LINK) $(clock_applet_OBJECTS) $(clock_applet_LDADD) $(LIBS) +test-system-timezone$(EXEEXT): $(test_system_timezone_OBJECTS) $(test_system_timezone_DEPENDENCIES) + @rm -f test-system-timezone$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_system_timezone_OBJECTS) $(test_system_timezone_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_applet-calendar-client.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_applet-calendar-sources.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_applet-calendar-window.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_applet-clock-face.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_applet-clock-location-tile.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_applet-clock-location.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_applet-clock-map.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_applet-clock-marshallers.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_applet-clock-sunpos.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_applet-clock-typebuiltins.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_applet-clock-utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_applet-clock.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_applet-set-timezone.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclock_applet_la-calendar-client.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclock_applet_la-calendar-sources.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclock_applet_la-calendar-window.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclock_applet_la-clock-face.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclock_applet_la-clock-location-tile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclock_applet_la-clock-location.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclock_applet_la-clock-map.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclock_applet_la-clock-marshallers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclock_applet_la-clock-sunpos.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclock_applet_la-clock-typebuiltins.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclock_applet_la-clock-utils.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclock_applet_la-clock.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclock_applet_la-set-timezone.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/system-timezone.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-system-timezone.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 $@ $< + +libclock_applet_la-calendar-window.lo: calendar-window.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -MT libclock_applet_la-calendar-window.lo -MD -MP -MF $(DEPDIR)/libclock_applet_la-calendar-window.Tpo -c -o libclock_applet_la-calendar-window.lo `test -f 'calendar-window.c' || echo '$(srcdir)/'`calendar-window.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclock_applet_la-calendar-window.Tpo $(DEPDIR)/libclock_applet_la-calendar-window.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='calendar-window.c' object='libclock_applet_la-calendar-window.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) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -c -o libclock_applet_la-calendar-window.lo `test -f 'calendar-window.c' || echo '$(srcdir)/'`calendar-window.c + +libclock_applet_la-clock.lo: clock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -MT libclock_applet_la-clock.lo -MD -MP -MF $(DEPDIR)/libclock_applet_la-clock.Tpo -c -o libclock_applet_la-clock.lo `test -f 'clock.c' || echo '$(srcdir)/'`clock.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclock_applet_la-clock.Tpo $(DEPDIR)/libclock_applet_la-clock.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock.c' object='libclock_applet_la-clock.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) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -c -o libclock_applet_la-clock.lo `test -f 'clock.c' || echo '$(srcdir)/'`clock.c + +libclock_applet_la-clock-face.lo: clock-face.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -MT libclock_applet_la-clock-face.lo -MD -MP -MF $(DEPDIR)/libclock_applet_la-clock-face.Tpo -c -o libclock_applet_la-clock-face.lo `test -f 'clock-face.c' || echo '$(srcdir)/'`clock-face.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclock_applet_la-clock-face.Tpo $(DEPDIR)/libclock_applet_la-clock-face.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-face.c' object='libclock_applet_la-clock-face.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) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -c -o libclock_applet_la-clock-face.lo `test -f 'clock-face.c' || echo '$(srcdir)/'`clock-face.c + +libclock_applet_la-clock-location.lo: clock-location.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -MT libclock_applet_la-clock-location.lo -MD -MP -MF $(DEPDIR)/libclock_applet_la-clock-location.Tpo -c -o libclock_applet_la-clock-location.lo `test -f 'clock-location.c' || echo '$(srcdir)/'`clock-location.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclock_applet_la-clock-location.Tpo $(DEPDIR)/libclock_applet_la-clock-location.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-location.c' object='libclock_applet_la-clock-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) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -c -o libclock_applet_la-clock-location.lo `test -f 'clock-location.c' || echo '$(srcdir)/'`clock-location.c + +libclock_applet_la-clock-location-tile.lo: clock-location-tile.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -MT libclock_applet_la-clock-location-tile.lo -MD -MP -MF $(DEPDIR)/libclock_applet_la-clock-location-tile.Tpo -c -o libclock_applet_la-clock-location-tile.lo `test -f 'clock-location-tile.c' || echo '$(srcdir)/'`clock-location-tile.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclock_applet_la-clock-location-tile.Tpo $(DEPDIR)/libclock_applet_la-clock-location-tile.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-location-tile.c' object='libclock_applet_la-clock-location-tile.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) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -c -o libclock_applet_la-clock-location-tile.lo `test -f 'clock-location-tile.c' || echo '$(srcdir)/'`clock-location-tile.c + +libclock_applet_la-clock-map.lo: clock-map.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -MT libclock_applet_la-clock-map.lo -MD -MP -MF $(DEPDIR)/libclock_applet_la-clock-map.Tpo -c -o libclock_applet_la-clock-map.lo `test -f 'clock-map.c' || echo '$(srcdir)/'`clock-map.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclock_applet_la-clock-map.Tpo $(DEPDIR)/libclock_applet_la-clock-map.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-map.c' object='libclock_applet_la-clock-map.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) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -c -o libclock_applet_la-clock-map.lo `test -f 'clock-map.c' || echo '$(srcdir)/'`clock-map.c + +libclock_applet_la-clock-sunpos.lo: clock-sunpos.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -MT libclock_applet_la-clock-sunpos.lo -MD -MP -MF $(DEPDIR)/libclock_applet_la-clock-sunpos.Tpo -c -o libclock_applet_la-clock-sunpos.lo `test -f 'clock-sunpos.c' || echo '$(srcdir)/'`clock-sunpos.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclock_applet_la-clock-sunpos.Tpo $(DEPDIR)/libclock_applet_la-clock-sunpos.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-sunpos.c' object='libclock_applet_la-clock-sunpos.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) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -c -o libclock_applet_la-clock-sunpos.lo `test -f 'clock-sunpos.c' || echo '$(srcdir)/'`clock-sunpos.c + +libclock_applet_la-clock-utils.lo: clock-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -MT libclock_applet_la-clock-utils.lo -MD -MP -MF $(DEPDIR)/libclock_applet_la-clock-utils.Tpo -c -o libclock_applet_la-clock-utils.lo `test -f 'clock-utils.c' || echo '$(srcdir)/'`clock-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclock_applet_la-clock-utils.Tpo $(DEPDIR)/libclock_applet_la-clock-utils.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-utils.c' object='libclock_applet_la-clock-utils.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) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -c -o libclock_applet_la-clock-utils.lo `test -f 'clock-utils.c' || echo '$(srcdir)/'`clock-utils.c + +libclock_applet_la-set-timezone.lo: set-timezone.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -MT libclock_applet_la-set-timezone.lo -MD -MP -MF $(DEPDIR)/libclock_applet_la-set-timezone.Tpo -c -o libclock_applet_la-set-timezone.lo `test -f 'set-timezone.c' || echo '$(srcdir)/'`set-timezone.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclock_applet_la-set-timezone.Tpo $(DEPDIR)/libclock_applet_la-set-timezone.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='set-timezone.c' object='libclock_applet_la-set-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) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -c -o libclock_applet_la-set-timezone.lo `test -f 'set-timezone.c' || echo '$(srcdir)/'`set-timezone.c + +libclock_applet_la-clock-marshallers.lo: clock-marshallers.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -MT libclock_applet_la-clock-marshallers.lo -MD -MP -MF $(DEPDIR)/libclock_applet_la-clock-marshallers.Tpo -c -o libclock_applet_la-clock-marshallers.lo `test -f 'clock-marshallers.c' || echo '$(srcdir)/'`clock-marshallers.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclock_applet_la-clock-marshallers.Tpo $(DEPDIR)/libclock_applet_la-clock-marshallers.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-marshallers.c' object='libclock_applet_la-clock-marshallers.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) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -c -o libclock_applet_la-clock-marshallers.lo `test -f 'clock-marshallers.c' || echo '$(srcdir)/'`clock-marshallers.c + +libclock_applet_la-clock-typebuiltins.lo: clock-typebuiltins.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -MT libclock_applet_la-clock-typebuiltins.lo -MD -MP -MF $(DEPDIR)/libclock_applet_la-clock-typebuiltins.Tpo -c -o libclock_applet_la-clock-typebuiltins.lo `test -f 'clock-typebuiltins.c' || echo '$(srcdir)/'`clock-typebuiltins.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclock_applet_la-clock-typebuiltins.Tpo $(DEPDIR)/libclock_applet_la-clock-typebuiltins.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-typebuiltins.c' object='libclock_applet_la-clock-typebuiltins.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) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -c -o libclock_applet_la-clock-typebuiltins.lo `test -f 'clock-typebuiltins.c' || echo '$(srcdir)/'`clock-typebuiltins.c + +libclock_applet_la-calendar-client.lo: calendar-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -MT libclock_applet_la-calendar-client.lo -MD -MP -MF $(DEPDIR)/libclock_applet_la-calendar-client.Tpo -c -o libclock_applet_la-calendar-client.lo `test -f 'calendar-client.c' || echo '$(srcdir)/'`calendar-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclock_applet_la-calendar-client.Tpo $(DEPDIR)/libclock_applet_la-calendar-client.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='calendar-client.c' object='libclock_applet_la-calendar-client.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) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -c -o libclock_applet_la-calendar-client.lo `test -f 'calendar-client.c' || echo '$(srcdir)/'`calendar-client.c + +libclock_applet_la-calendar-sources.lo: calendar-sources.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -MT libclock_applet_la-calendar-sources.lo -MD -MP -MF $(DEPDIR)/libclock_applet_la-calendar-sources.Tpo -c -o libclock_applet_la-calendar-sources.lo `test -f 'calendar-sources.c' || echo '$(srcdir)/'`calendar-sources.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclock_applet_la-calendar-sources.Tpo $(DEPDIR)/libclock_applet_la-calendar-sources.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='calendar-sources.c' object='libclock_applet_la-calendar-sources.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) $(libclock_applet_la_CPPFLAGS) $(CPPFLAGS) $(libclock_applet_la_CFLAGS) $(CFLAGS) -c -o libclock_applet_la-calendar-sources.lo `test -f 'calendar-sources.c' || echo '$(srcdir)/'`calendar-sources.c + +clock_applet-calendar-window.o: calendar-window.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-calendar-window.o -MD -MP -MF $(DEPDIR)/clock_applet-calendar-window.Tpo -c -o clock_applet-calendar-window.o `test -f 'calendar-window.c' || echo '$(srcdir)/'`calendar-window.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-calendar-window.Tpo $(DEPDIR)/clock_applet-calendar-window.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='calendar-window.c' object='clock_applet-calendar-window.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-calendar-window.o `test -f 'calendar-window.c' || echo '$(srcdir)/'`calendar-window.c + +clock_applet-calendar-window.obj: calendar-window.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-calendar-window.obj -MD -MP -MF $(DEPDIR)/clock_applet-calendar-window.Tpo -c -o clock_applet-calendar-window.obj `if test -f 'calendar-window.c'; then $(CYGPATH_W) 'calendar-window.c'; else $(CYGPATH_W) '$(srcdir)/calendar-window.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-calendar-window.Tpo $(DEPDIR)/clock_applet-calendar-window.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='calendar-window.c' object='clock_applet-calendar-window.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-calendar-window.obj `if test -f 'calendar-window.c'; then $(CYGPATH_W) 'calendar-window.c'; else $(CYGPATH_W) '$(srcdir)/calendar-window.c'; fi` + +clock_applet-clock.o: clock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock.o -MD -MP -MF $(DEPDIR)/clock_applet-clock.Tpo -c -o clock_applet-clock.o `test -f 'clock.c' || echo '$(srcdir)/'`clock.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock.Tpo $(DEPDIR)/clock_applet-clock.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock.c' object='clock_applet-clock.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock.o `test -f 'clock.c' || echo '$(srcdir)/'`clock.c + +clock_applet-clock.obj: clock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock.obj -MD -MP -MF $(DEPDIR)/clock_applet-clock.Tpo -c -o clock_applet-clock.obj `if test -f 'clock.c'; then $(CYGPATH_W) 'clock.c'; else $(CYGPATH_W) '$(srcdir)/clock.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock.Tpo $(DEPDIR)/clock_applet-clock.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock.c' object='clock_applet-clock.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock.obj `if test -f 'clock.c'; then $(CYGPATH_W) 'clock.c'; else $(CYGPATH_W) '$(srcdir)/clock.c'; fi` + +clock_applet-clock-face.o: clock-face.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-face.o -MD -MP -MF $(DEPDIR)/clock_applet-clock-face.Tpo -c -o clock_applet-clock-face.o `test -f 'clock-face.c' || echo '$(srcdir)/'`clock-face.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-face.Tpo $(DEPDIR)/clock_applet-clock-face.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-face.c' object='clock_applet-clock-face.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-face.o `test -f 'clock-face.c' || echo '$(srcdir)/'`clock-face.c + +clock_applet-clock-face.obj: clock-face.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-face.obj -MD -MP -MF $(DEPDIR)/clock_applet-clock-face.Tpo -c -o clock_applet-clock-face.obj `if test -f 'clock-face.c'; then $(CYGPATH_W) 'clock-face.c'; else $(CYGPATH_W) '$(srcdir)/clock-face.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-face.Tpo $(DEPDIR)/clock_applet-clock-face.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-face.c' object='clock_applet-clock-face.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-face.obj `if test -f 'clock-face.c'; then $(CYGPATH_W) 'clock-face.c'; else $(CYGPATH_W) '$(srcdir)/clock-face.c'; fi` + +clock_applet-clock-location.o: clock-location.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-location.o -MD -MP -MF $(DEPDIR)/clock_applet-clock-location.Tpo -c -o clock_applet-clock-location.o `test -f 'clock-location.c' || echo '$(srcdir)/'`clock-location.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-location.Tpo $(DEPDIR)/clock_applet-clock-location.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-location.c' object='clock_applet-clock-location.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-location.o `test -f 'clock-location.c' || echo '$(srcdir)/'`clock-location.c + +clock_applet-clock-location.obj: clock-location.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-location.obj -MD -MP -MF $(DEPDIR)/clock_applet-clock-location.Tpo -c -o clock_applet-clock-location.obj `if test -f 'clock-location.c'; then $(CYGPATH_W) 'clock-location.c'; else $(CYGPATH_W) '$(srcdir)/clock-location.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-location.Tpo $(DEPDIR)/clock_applet-clock-location.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-location.c' object='clock_applet-clock-location.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-location.obj `if test -f 'clock-location.c'; then $(CYGPATH_W) 'clock-location.c'; else $(CYGPATH_W) '$(srcdir)/clock-location.c'; fi` + +clock_applet-clock-location-tile.o: clock-location-tile.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-location-tile.o -MD -MP -MF $(DEPDIR)/clock_applet-clock-location-tile.Tpo -c -o clock_applet-clock-location-tile.o `test -f 'clock-location-tile.c' || echo '$(srcdir)/'`clock-location-tile.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-location-tile.Tpo $(DEPDIR)/clock_applet-clock-location-tile.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-location-tile.c' object='clock_applet-clock-location-tile.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-location-tile.o `test -f 'clock-location-tile.c' || echo '$(srcdir)/'`clock-location-tile.c + +clock_applet-clock-location-tile.obj: clock-location-tile.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-location-tile.obj -MD -MP -MF $(DEPDIR)/clock_applet-clock-location-tile.Tpo -c -o clock_applet-clock-location-tile.obj `if test -f 'clock-location-tile.c'; then $(CYGPATH_W) 'clock-location-tile.c'; else $(CYGPATH_W) '$(srcdir)/clock-location-tile.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-location-tile.Tpo $(DEPDIR)/clock_applet-clock-location-tile.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-location-tile.c' object='clock_applet-clock-location-tile.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-location-tile.obj `if test -f 'clock-location-tile.c'; then $(CYGPATH_W) 'clock-location-tile.c'; else $(CYGPATH_W) '$(srcdir)/clock-location-tile.c'; fi` + +clock_applet-clock-map.o: clock-map.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-map.o -MD -MP -MF $(DEPDIR)/clock_applet-clock-map.Tpo -c -o clock_applet-clock-map.o `test -f 'clock-map.c' || echo '$(srcdir)/'`clock-map.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-map.Tpo $(DEPDIR)/clock_applet-clock-map.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-map.c' object='clock_applet-clock-map.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-map.o `test -f 'clock-map.c' || echo '$(srcdir)/'`clock-map.c + +clock_applet-clock-map.obj: clock-map.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-map.obj -MD -MP -MF $(DEPDIR)/clock_applet-clock-map.Tpo -c -o clock_applet-clock-map.obj `if test -f 'clock-map.c'; then $(CYGPATH_W) 'clock-map.c'; else $(CYGPATH_W) '$(srcdir)/clock-map.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-map.Tpo $(DEPDIR)/clock_applet-clock-map.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-map.c' object='clock_applet-clock-map.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-map.obj `if test -f 'clock-map.c'; then $(CYGPATH_W) 'clock-map.c'; else $(CYGPATH_W) '$(srcdir)/clock-map.c'; fi` + +clock_applet-clock-sunpos.o: clock-sunpos.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-sunpos.o -MD -MP -MF $(DEPDIR)/clock_applet-clock-sunpos.Tpo -c -o clock_applet-clock-sunpos.o `test -f 'clock-sunpos.c' || echo '$(srcdir)/'`clock-sunpos.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-sunpos.Tpo $(DEPDIR)/clock_applet-clock-sunpos.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-sunpos.c' object='clock_applet-clock-sunpos.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-sunpos.o `test -f 'clock-sunpos.c' || echo '$(srcdir)/'`clock-sunpos.c + +clock_applet-clock-sunpos.obj: clock-sunpos.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-sunpos.obj -MD -MP -MF $(DEPDIR)/clock_applet-clock-sunpos.Tpo -c -o clock_applet-clock-sunpos.obj `if test -f 'clock-sunpos.c'; then $(CYGPATH_W) 'clock-sunpos.c'; else $(CYGPATH_W) '$(srcdir)/clock-sunpos.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-sunpos.Tpo $(DEPDIR)/clock_applet-clock-sunpos.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-sunpos.c' object='clock_applet-clock-sunpos.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-sunpos.obj `if test -f 'clock-sunpos.c'; then $(CYGPATH_W) 'clock-sunpos.c'; else $(CYGPATH_W) '$(srcdir)/clock-sunpos.c'; fi` + +clock_applet-clock-utils.o: clock-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-utils.o -MD -MP -MF $(DEPDIR)/clock_applet-clock-utils.Tpo -c -o clock_applet-clock-utils.o `test -f 'clock-utils.c' || echo '$(srcdir)/'`clock-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-utils.Tpo $(DEPDIR)/clock_applet-clock-utils.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-utils.c' object='clock_applet-clock-utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-utils.o `test -f 'clock-utils.c' || echo '$(srcdir)/'`clock-utils.c + +clock_applet-clock-utils.obj: clock-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-utils.obj -MD -MP -MF $(DEPDIR)/clock_applet-clock-utils.Tpo -c -o clock_applet-clock-utils.obj `if test -f 'clock-utils.c'; then $(CYGPATH_W) 'clock-utils.c'; else $(CYGPATH_W) '$(srcdir)/clock-utils.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-utils.Tpo $(DEPDIR)/clock_applet-clock-utils.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-utils.c' object='clock_applet-clock-utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-utils.obj `if test -f 'clock-utils.c'; then $(CYGPATH_W) 'clock-utils.c'; else $(CYGPATH_W) '$(srcdir)/clock-utils.c'; fi` + +clock_applet-set-timezone.o: set-timezone.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-set-timezone.o -MD -MP -MF $(DEPDIR)/clock_applet-set-timezone.Tpo -c -o clock_applet-set-timezone.o `test -f 'set-timezone.c' || echo '$(srcdir)/'`set-timezone.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-set-timezone.Tpo $(DEPDIR)/clock_applet-set-timezone.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='set-timezone.c' object='clock_applet-set-timezone.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-set-timezone.o `test -f 'set-timezone.c' || echo '$(srcdir)/'`set-timezone.c + +clock_applet-set-timezone.obj: set-timezone.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-set-timezone.obj -MD -MP -MF $(DEPDIR)/clock_applet-set-timezone.Tpo -c -o clock_applet-set-timezone.obj `if test -f 'set-timezone.c'; then $(CYGPATH_W) 'set-timezone.c'; else $(CYGPATH_W) '$(srcdir)/set-timezone.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-set-timezone.Tpo $(DEPDIR)/clock_applet-set-timezone.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='set-timezone.c' object='clock_applet-set-timezone.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-set-timezone.obj `if test -f 'set-timezone.c'; then $(CYGPATH_W) 'set-timezone.c'; else $(CYGPATH_W) '$(srcdir)/set-timezone.c'; fi` + +clock_applet-clock-marshallers.o: clock-marshallers.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-marshallers.o -MD -MP -MF $(DEPDIR)/clock_applet-clock-marshallers.Tpo -c -o clock_applet-clock-marshallers.o `test -f 'clock-marshallers.c' || echo '$(srcdir)/'`clock-marshallers.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-marshallers.Tpo $(DEPDIR)/clock_applet-clock-marshallers.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-marshallers.c' object='clock_applet-clock-marshallers.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-marshallers.o `test -f 'clock-marshallers.c' || echo '$(srcdir)/'`clock-marshallers.c + +clock_applet-clock-marshallers.obj: clock-marshallers.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-marshallers.obj -MD -MP -MF $(DEPDIR)/clock_applet-clock-marshallers.Tpo -c -o clock_applet-clock-marshallers.obj `if test -f 'clock-marshallers.c'; then $(CYGPATH_W) 'clock-marshallers.c'; else $(CYGPATH_W) '$(srcdir)/clock-marshallers.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-marshallers.Tpo $(DEPDIR)/clock_applet-clock-marshallers.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-marshallers.c' object='clock_applet-clock-marshallers.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-marshallers.obj `if test -f 'clock-marshallers.c'; then $(CYGPATH_W) 'clock-marshallers.c'; else $(CYGPATH_W) '$(srcdir)/clock-marshallers.c'; fi` + +clock_applet-clock-typebuiltins.o: clock-typebuiltins.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-typebuiltins.o -MD -MP -MF $(DEPDIR)/clock_applet-clock-typebuiltins.Tpo -c -o clock_applet-clock-typebuiltins.o `test -f 'clock-typebuiltins.c' || echo '$(srcdir)/'`clock-typebuiltins.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-typebuiltins.Tpo $(DEPDIR)/clock_applet-clock-typebuiltins.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-typebuiltins.c' object='clock_applet-clock-typebuiltins.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-typebuiltins.o `test -f 'clock-typebuiltins.c' || echo '$(srcdir)/'`clock-typebuiltins.c + +clock_applet-clock-typebuiltins.obj: clock-typebuiltins.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-clock-typebuiltins.obj -MD -MP -MF $(DEPDIR)/clock_applet-clock-typebuiltins.Tpo -c -o clock_applet-clock-typebuiltins.obj `if test -f 'clock-typebuiltins.c'; then $(CYGPATH_W) 'clock-typebuiltins.c'; else $(CYGPATH_W) '$(srcdir)/clock-typebuiltins.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-clock-typebuiltins.Tpo $(DEPDIR)/clock_applet-clock-typebuiltins.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='clock-typebuiltins.c' object='clock_applet-clock-typebuiltins.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-clock-typebuiltins.obj `if test -f 'clock-typebuiltins.c'; then $(CYGPATH_W) 'clock-typebuiltins.c'; else $(CYGPATH_W) '$(srcdir)/clock-typebuiltins.c'; fi` + +clock_applet-calendar-client.o: calendar-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-calendar-client.o -MD -MP -MF $(DEPDIR)/clock_applet-calendar-client.Tpo -c -o clock_applet-calendar-client.o `test -f 'calendar-client.c' || echo '$(srcdir)/'`calendar-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-calendar-client.Tpo $(DEPDIR)/clock_applet-calendar-client.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='calendar-client.c' object='clock_applet-calendar-client.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-calendar-client.o `test -f 'calendar-client.c' || echo '$(srcdir)/'`calendar-client.c + +clock_applet-calendar-client.obj: calendar-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-calendar-client.obj -MD -MP -MF $(DEPDIR)/clock_applet-calendar-client.Tpo -c -o clock_applet-calendar-client.obj `if test -f 'calendar-client.c'; then $(CYGPATH_W) 'calendar-client.c'; else $(CYGPATH_W) '$(srcdir)/calendar-client.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-calendar-client.Tpo $(DEPDIR)/clock_applet-calendar-client.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='calendar-client.c' object='clock_applet-calendar-client.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-calendar-client.obj `if test -f 'calendar-client.c'; then $(CYGPATH_W) 'calendar-client.c'; else $(CYGPATH_W) '$(srcdir)/calendar-client.c'; fi` + +clock_applet-calendar-sources.o: calendar-sources.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-calendar-sources.o -MD -MP -MF $(DEPDIR)/clock_applet-calendar-sources.Tpo -c -o clock_applet-calendar-sources.o `test -f 'calendar-sources.c' || echo '$(srcdir)/'`calendar-sources.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-calendar-sources.Tpo $(DEPDIR)/clock_applet-calendar-sources.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='calendar-sources.c' object='clock_applet-calendar-sources.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-calendar-sources.o `test -f 'calendar-sources.c' || echo '$(srcdir)/'`calendar-sources.c + +clock_applet-calendar-sources.obj: calendar-sources.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -MT clock_applet-calendar-sources.obj -MD -MP -MF $(DEPDIR)/clock_applet-calendar-sources.Tpo -c -o clock_applet-calendar-sources.obj `if test -f 'calendar-sources.c'; then $(CYGPATH_W) 'calendar-sources.c'; else $(CYGPATH_W) '$(srcdir)/calendar-sources.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clock_applet-calendar-sources.Tpo $(DEPDIR)/clock_applet-calendar-sources.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='calendar-sources.c' object='clock_applet-calendar-sources.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(clock_applet_CPPFLAGS) $(CPPFLAGS) $(clock_applet_CFLAGS) $(CFLAGS) -c -o clock_applet-calendar-sources.obj `if test -f 'calendar-sources.c'; then $(CYGPATH_W) 'calendar-sources.c'; else $(CYGPATH_W) '$(srcdir)/calendar-sources.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-appletDATA: $(applet_DATA) + @$(NORMAL_INSTALL) + test -z "$(appletdir)" || $(MKDIR_P) "$(DESTDIR)$(appletdir)" + @list='$(applet_DATA)'; test -n "$(appletdir)" || 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)$(appletdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(appletdir)" || exit $$?; \ + done + +uninstall-appletDATA: + @$(NORMAL_UNINSTALL) + @list='$(applet_DATA)'; test -n "$(appletdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(appletdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(appletdir)" && rm -f $$files +install-schemasDATA: $(schemas_DATA) + @$(NORMAL_INSTALL) + test -z "$(schemasdir)" || $(MKDIR_P) "$(DESTDIR)$(schemasdir)" + @list='$(schemas_DATA)'; test -n "$(schemasdir)" || 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)$(schemasdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(schemasdir)" || exit $$?; \ + done + +uninstall-schemasDATA: + @$(NORMAL_UNINSTALL) + @list='$(schemas_DATA)'; test -n "$(schemasdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(schemasdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(schemasdir)" && rm -f $$files +install-serviceDATA: $(service_DATA) + @$(NORMAL_INSTALL) + test -z "$(servicedir)" || $(MKDIR_P) "$(DESTDIR)$(servicedir)" + @list='$(service_DATA)'; test -n "$(servicedir)" || 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)$(servicedir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(servicedir)" || exit $$?; \ + done + +uninstall-serviceDATA: + @$(NORMAL_UNINSTALL) + @list='$(service_DATA)'; test -n "$(servicedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(servicedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(servicedir)" && rm -f $$files +install-uiDATA: $(ui_DATA) + @$(NORMAL_INSTALL) + test -z "$(uidir)" || $(MKDIR_P) "$(DESTDIR)$(uidir)" + @list='$(ui_DATA)'; test -n "$(uidir)" || 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)$(uidir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(uidir)" || exit $$?; \ + done + +uninstall-uiDATA: + @$(NORMAL_UNINSTALL) + @list='$(ui_DATA)'; test -n "$(uidir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(uidir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(uidir)" && rm -f $$files +install-xmluiDATA: $(xmlui_DATA) + @$(NORMAL_INSTALL) + test -z "$(xmluidir)" || $(MKDIR_P) "$(DESTDIR)$(xmluidir)" + @list='$(xmlui_DATA)'; test -n "$(xmluidir)" || 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)$(xmluidir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(xmluidir)" || exit $$?; \ + done + +uninstall-xmluiDATA: + @$(NORMAL_UNINSTALL) + @list='$(xmlui_DATA)'; test -n "$(xmluidir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(xmluidir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(xmluidir)" && rm -f $$files + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +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: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + 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: ctags-recursive $(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 + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-recursive +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(clock_appletlibdir)" "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(appletdir)" "$(DESTDIR)$(schemasdir)" "$(DESTDIR)$(servicedir)" "$(DESTDIR)$(uidir)" "$(DESTDIR)$(xmluidir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +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-recursive + +clean-am: clean-clock_appletlibLTLIBRARIES clean-generic \ + clean-libexecPROGRAMS clean-libtool clean-noinstLTLIBRARIES \ + clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-appletDATA install-clock_appletlibLTLIBRARIES \ + install-data-local install-schemasDATA install-serviceDATA \ + install-uiDATA install-xmluiDATA + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-libexecPROGRAMS + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-appletDATA \ + uninstall-clock_appletlibLTLIBRARIES uninstall-libexecPROGRAMS \ + uninstall-local uninstall-schemasDATA uninstall-serviceDATA \ + uninstall-uiDATA uninstall-xmluiDATA + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all check \ + ctags-recursive install install-am install-strip \ + tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean \ + clean-clock_appletlibLTLIBRARIES clean-generic \ + clean-libexecPROGRAMS clean-libtool clean-noinstLTLIBRARIES \ + clean-noinstPROGRAMS ctags ctags-recursive distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-appletDATA \ + install-clock_appletlibLTLIBRARIES 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-libexecPROGRAMS \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-schemasDATA install-serviceDATA \ + install-strip install-uiDATA install-xmluiDATA installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am \ + uninstall-appletDATA uninstall-clock_appletlibLTLIBRARIES \ + uninstall-libexecPROGRAMS uninstall-local \ + uninstall-schemasDATA uninstall-serviceDATA uninstall-uiDATA \ + uninstall-xmluiDATA + +@CLOCK_INPROCESS_TRUE@$(libclock_applet_la_OBJECTS): $(BUILT_SOURCES) +@CLOCK_INPROCESS_FALSE@$(clock_applet_OBJECTS): $(BUILT_SOURCES) + +clock-marshallers.c: clock-marshallers.list + $(AM_V_GEN)glib-genmarshal --prefix _clock_marshal --header --body --internal $< > $@ + +clock-marshallers.h: clock-marshallers.list + $(AM_V_GEN)glib-genmarshal --prefix _clock_marshal --header --internal $< > $@ + +clock-typebuiltins.c: @REBUILD@ $(clock_enum_headers) + $(AM_V_GEN)glib-mkenums \ + --fhead "#include \n" \ + --fhead "#include \"clock-typebuiltins.h\"\n\n" \ + --fprod "\n/* enumerations from \"@filename@\" */" \ + --fprod "\n#include \"@filename@\"\n" \ + --vhead "static const GEnumValue _@enum_name@_values[] = {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n};\n\n" \ + --vtail "GType\n@enum_name@_get_type (void)\n{\n" \ + --vtail " static GType type = 0;\n\n" \ + --vtail " if (!type)\n" \ + --vtail " type = g_enum_register_static (\"@EnumName@\", _@enum_name@_values);\n\n" \ + --vtail " return type;\n}\n\n" \ + $(clock_enum_headers) > $@ + +clock-typebuiltins.h: @REBUILD@ $(clock_enum_headers) + $(AM_V_GEN)glib-mkenums \ + --fhead "#ifndef __CLOCK_TYPEBUILTINS_H__\n" \ + --fhead "#define __CLOCK_TYPEBUILTINS_H__ 1\n\n" \ + --fhead "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n" \ + --ftail "#ifdef __cplusplus\n}\n#endif\n\n" \ + --ftail "#endif /* __CLOCK_TYPEBUILTINS_H__ */\n" \ + --fprod "\n/* --- @filename@ --- */" \ + --eprod "#define CLOCK_TYPE_@ENUMSHORT@ @enum_name@_get_type()\n" \ + --eprod "GType @enum_name@_get_type (void);\n" \ + $(clock_enum_headers) > $@ + +$(applet_in_files): $(applet_in_files).in Makefile + $(AM_V_GEN)sed \ + -e "s|\@LOCATION\@|$(APPLET_LOCATION)|" \ + -e "s|\@IN_PROCESS\@|$(APPLET_IN_PROCESS)|" \ + -e "s|\@VERSION\@|$(PACKAGE_VERSION)|" \ + $< > $@ + +@PANEL_INTLTOOL_MATE_PANEL_APPLET_RULE@ + +@CLOCK_INPROCESS_FALSE@org.mate.panel.applet.ClockAppletFactory.service: $(service_in_files) +@CLOCK_INPROCESS_FALSE@ $(AM_V_GEN)sed \ +@CLOCK_INPROCESS_FALSE@ -e "s|\@LOCATION\@|$(APPLET_LOCATION)|" \ +@CLOCK_INPROCESS_FALSE@ $< > $@ + +@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 $(schemas_DATA) ; do \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-install-rule $(top_builddir)/applets/clock/$$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 $(top_builddir)/applets/clock/$$p ; \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ done + +-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/applets/clock/calendar-client.c b/applets/clock/calendar-client.c new file mode 100644 index 00000000..77efa137 --- /dev/null +++ b/applets/clock/calendar-client.c @@ -0,0 +1,2169 @@ +/* + * Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + * William Jon McCann + * Martin Grimme + * Christian Kellner + */ + +#include + +#include "calendar-client.h" + +#include +#include +#define HANDLE_LIBICAL_MEMORY +#include +#include +#include + +#include "calendar-sources.h" + +#undef CALENDAR_ENABLE_DEBUG +#include "calendar-debug.h" + +#define CALENDAR_CONFIG_PREFIX "/apps/evolution/calendar" +#define CALENDAR_CONFIG_TIMEZONE CALENDAR_CONFIG_PREFIX "/display/timezone" + +#ifndef _ +#define _(x) gettext(x) +#endif + +#ifndef N_ +#define N_(x) x +#endif + +#define CALENDAR_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CALENDAR_TYPE_CLIENT, CalendarClientPrivate)) + +typedef struct _CalendarClientQuery CalendarClientQuery; +typedef struct _CalendarClientSource CalendarClientSource; + +struct _CalendarClientQuery +{ + ECalView *view; + GHashTable *events; +}; + +struct _CalendarClientSource +{ + CalendarClient *client; + ECal *source; + + CalendarClientQuery completed_query; + CalendarClientQuery in_progress_query; + + guint changed_signal_id; + + guint query_completed : 1; + guint query_in_progress : 1; +}; + +struct _CalendarClientPrivate +{ + CalendarSources *calendar_sources; + + GSList *appointment_sources; + GSList *task_sources; + + icaltimezone *zone; + + guint zone_listener; + MateConfClient *mateconf_client; + + guint day; + guint month; + guint year; +}; + +static void calendar_client_class_init (CalendarClientClass *klass); +static void calendar_client_init (CalendarClient *client); +static void calendar_client_finalize (GObject *object); +static void calendar_client_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void calendar_client_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static GSList *calendar_client_update_sources_list (CalendarClient *client, + GSList *sources, + GSList *esources, + guint changed_signal_id); +static void calendar_client_appointment_sources_changed (CalendarClient *client); +static void calendar_client_task_sources_changed (CalendarClient *client); + +static void calendar_client_stop_query (CalendarClient *client, + CalendarClientSource *source, + CalendarClientQuery *query); +static void calendar_client_start_query (CalendarClient *client, + CalendarClientSource *source, + const char *query); + +static void calendar_client_source_finalize (CalendarClientSource *source); +static void calendar_client_query_finalize (CalendarClientQuery *query); + +static void +calendar_client_update_appointments (CalendarClient *client); +static void +calendar_client_update_tasks (CalendarClient *client); + +enum +{ + PROP_O, + PROP_DAY, + PROP_MONTH, + PROP_YEAR +}; + +enum +{ + APPOINTMENTS_CHANGED, + TASKS_CHANGED, + LAST_SIGNAL +}; + +static GObjectClass *parent_class = NULL; +static guint signals [LAST_SIGNAL] = { 0, }; + +GType +calendar_client_get_type (void) +{ + static GType client_type = 0; + + if (!client_type) + { + static const GTypeInfo client_info = + { + sizeof (CalendarClientClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) calendar_client_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (CalendarClient), + 0, /* n_preallocs */ + (GInstanceInitFunc) calendar_client_init, + }; + + client_type = g_type_register_static (G_TYPE_OBJECT, + "CalendarClient", + &client_info, 0); + } + + return client_type; +} + +static void +calendar_client_class_init (CalendarClientClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->finalize = calendar_client_finalize; + gobject_class->set_property = calendar_client_set_property; + gobject_class->get_property = calendar_client_get_property; + + g_type_class_add_private (klass, sizeof (CalendarClientPrivate)); + + g_object_class_install_property (gobject_class, + PROP_DAY, + g_param_spec_uint ("day", + "Day", + "The currently monitored day between 1 and 31 (0 denotes unset)", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_MONTH, + g_param_spec_uint ("month", + "Month", + "The currently monitored month between 0 and 11", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_YEAR, + g_param_spec_uint ("year", + "Year", + "The currently monitored year", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE)); + + signals [APPOINTMENTS_CHANGED] = + g_signal_new ("appointments-changed", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalendarClientClass, tasks_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + signals [TASKS_CHANGED] = + g_signal_new ("tasks-changed", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalendarClientClass, tasks_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +/* Timezone code adapted from evolution/calendar/gui/calendar-config.c */ +/* The current timezone, e.g. "Europe/London". It may be NULL, in which case + you should assume UTC. */ +static gchar * +calendar_client_config_get_timezone (MateConfClient *mateconf_client) +{ + char *location; + + location = mateconf_client_get_string (mateconf_client, + CALENDAR_CONFIG_TIMEZONE, + NULL); + + return location; +} + +static icaltimezone * +calendar_client_config_get_icaltimezone (MateConfClient *mateconf_client) +{ + char *location; + icaltimezone *zone = NULL; + + location = calendar_client_config_get_timezone (mateconf_client); + if (!location) + return icaltimezone_get_utc_timezone (); + + zone = icaltimezone_get_builtin_timezone (location); + g_free (location); + + return zone; +} + +static void +calendar_client_set_timezone (CalendarClient *client) +{ + GSList *l; + GSList *esources; + + client->priv->zone = calendar_client_config_get_icaltimezone (client->priv->mateconf_client); + + esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources); + for (l = esources; l; l = l->next) { + ECal *source = l->data; + + e_cal_set_default_timezone (source, client->priv->zone, NULL); + } +} + +static void +calendar_client_timezone_changed_cb (MateConfClient *mateconf_client, + guint id, + MateConfEntry *entry, + CalendarClient *client) +{ + calendar_client_set_timezone (client); +} + +static void +cal_opened_cb (ECal *ecal, + ECalendarStatus status, + CalendarClientSource *cl_source) +{ + ECalSourceType s_type; + CalendarClient *client = cl_source->client; + + s_type = e_cal_get_source_type (ecal); + + if (status == E_CALENDAR_STATUS_BUSY && + e_cal_get_load_state (ecal) == E_CAL_LOAD_NOT_LOADED) + { + e_cal_open_async (ecal, FALSE); + return; + } + + g_signal_handlers_disconnect_by_func (ecal, cal_opened_cb, cl_source); + + if (status != E_CALENDAR_STATUS_OK) + { + if (s_type == E_CAL_SOURCE_TYPE_EVENT) + client->priv->appointment_sources = g_slist_remove (client->priv->appointment_sources, + cl_source); + else + client->priv->task_sources = g_slist_remove (client->priv->task_sources, + cl_source); + + calendar_client_source_finalize (cl_source); + g_free (cl_source); + + return; + } + + if (s_type == E_CAL_SOURCE_TYPE_EVENT) + calendar_client_update_appointments (client); + else + calendar_client_update_tasks (client); +} + +static void +load_calendars (CalendarClient *client, + CalendarEventType type) +{ + GSList *l, *clients; + + switch (type) + { + case CALENDAR_EVENT_APPOINTMENT: + clients = client->priv->appointment_sources; + break; + case CALENDAR_EVENT_TASK: + clients = client->priv->task_sources; + break; + default: + g_assert_not_reached (); + } + + for (l = clients; l != NULL; l = l->next) + { + ECal *ecal; + CalendarClientSource *cl_source = l->data; + + ecal = cl_source->source; + + if (e_cal_get_load_state (ecal) == E_CAL_LOAD_LOADED) + continue; + + g_signal_connect (G_OBJECT (ecal), "cal_opened", + G_CALLBACK (cal_opened_cb), cl_source); + e_cal_open_async (ecal, TRUE); + } +} + +static void +calendar_client_init (CalendarClient *client) +{ + GSList *esources; + + client->priv = CALENDAR_CLIENT_GET_PRIVATE (client); + + client->priv->calendar_sources = calendar_sources_get (); + client->priv->mateconf_client = mateconf_client_get_default (); + + esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources); + client->priv->appointment_sources = + calendar_client_update_sources_list (client, NULL, esources, signals [APPOINTMENTS_CHANGED]); + + esources = calendar_sources_get_task_sources (client->priv->calendar_sources); + client->priv->task_sources = + calendar_client_update_sources_list (client, NULL, esources, signals [TASKS_CHANGED]); + + /* set the timezone before loading the clients */ + calendar_client_set_timezone (client); + load_calendars (client, CALENDAR_EVENT_APPOINTMENT); + load_calendars (client, CALENDAR_EVENT_TASK); + + g_signal_connect_swapped (client->priv->calendar_sources, + "appointment-sources-changed", + G_CALLBACK (calendar_client_appointment_sources_changed), + client); + g_signal_connect_swapped (client->priv->calendar_sources, + "task-sources-changed", + G_CALLBACK (calendar_client_task_sources_changed), + client); + + mateconf_client_add_dir (client->priv->mateconf_client, + CALENDAR_CONFIG_PREFIX, + MATECONF_CLIENT_PRELOAD_NONE, + NULL); + + client->priv->zone_listener = mateconf_client_notify_add (client->priv->mateconf_client, + CALENDAR_CONFIG_TIMEZONE, + (MateConfClientNotifyFunc) calendar_client_timezone_changed_cb, + client, NULL, NULL); + + client->priv->day = -1; + client->priv->month = -1; + client->priv->year = -1; +} + +static void +calendar_client_finalize (GObject *object) +{ + CalendarClient *client = CALENDAR_CLIENT (object); + GSList *l; + + if (client->priv->zone_listener) + { + mateconf_client_notify_remove (client->priv->mateconf_client, + client->priv->zone_listener); + client->priv->zone_listener = 0; + } + + mateconf_client_remove_dir (client->priv->mateconf_client, + CALENDAR_CONFIG_PREFIX, + NULL); + + if (client->priv->mateconf_client) + g_object_unref (client->priv->mateconf_client); + client->priv->mateconf_client = NULL; + + for (l = client->priv->appointment_sources; l; l = l->next) + { + calendar_client_source_finalize (l->data); + g_free (l->data); + } + g_slist_free (client->priv->appointment_sources); + client->priv->appointment_sources = NULL; + + for (l = client->priv->task_sources; l; l = l->next) + { + calendar_client_source_finalize (l->data); + g_free (l->data); + } + g_slist_free (client->priv->task_sources); + client->priv->task_sources = NULL; + + if (client->priv->calendar_sources) + g_object_unref (client->priv->calendar_sources); + client->priv->calendar_sources = NULL; + + if (G_OBJECT_CLASS (parent_class)->finalize) + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +calendar_client_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + CalendarClient *client = CALENDAR_CLIENT (object); + + switch (prop_id) + { + case PROP_DAY: + calendar_client_select_day (client, g_value_get_uint (value)); + break; + case PROP_MONTH: + calendar_client_select_month (client, + g_value_get_uint (value), + client->priv->year); + break; + case PROP_YEAR: + calendar_client_select_month (client, + client->priv->month, + g_value_get_uint (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +calendar_client_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + CalendarClient *client = CALENDAR_CLIENT (object); + + switch (prop_id) + { + case PROP_DAY: + g_value_set_uint (value, client->priv->day); + break; + case PROP_MONTH: + g_value_set_uint (value, client->priv->month); + break; + case PROP_YEAR: + g_value_set_uint (value, client->priv->year); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +CalendarClient * +calendar_client_new (void) +{ + return g_object_new (CALENDAR_TYPE_CLIENT, NULL); +} + +/* @day and @month can happily be out of range as + * mktime() will normalize them correctly. From mktime(3): + * + * "If structure members are outside their legal interval, + * they will be normalized (so that, e.g., 40 October is + * changed into 9 November)." + * + * "What?", you say, "Something useful in libc?" + */ +static inline time_t +make_time_for_day_begin (int day, + int month, + int year) +{ + struct tm localtime_tm = { 0, }; + + localtime_tm.tm_mday = day; + localtime_tm.tm_mon = month; + localtime_tm.tm_year = year - 1900; + localtime_tm.tm_isdst = -1; + + return mktime (&localtime_tm); +} + +static inline char * +make_isodate_for_day_begin (int day, + int month, + int year) +{ + time_t utctime; + + utctime = make_time_for_day_begin (day, month, year); + + return utctime != -1 ? isodate_from_time_t (utctime) : NULL; +} + +static time_t +get_time_from_property (icalcomponent *ical, + icalproperty_kind prop_kind, + struct icaltimetype (* get_prop_func) (const icalproperty *prop), + icaltimezone *default_zone) +{ + icalproperty *prop; + struct icaltimetype ical_time; + icalparameter *param; + icaltimezone *timezone = NULL; + + prop = icalcomponent_get_first_property (ical, prop_kind); + if (!prop) + return 0; + + ical_time = get_prop_func (prop); + + param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER); + if (param) + timezone = icaltimezone_get_builtin_timezone_from_tzid (icalparameter_get_tzid (param)); + else if (icaltime_is_utc (ical_time)) + timezone = icaltimezone_get_utc_timezone (); + else + timezone = default_zone; + + return icaltime_as_timet_with_zone (ical_time, timezone); +} + +static char * +get_ical_uid (icalcomponent *ical) +{ + return g_strdup (icalcomponent_get_uid (ical)); +} + +static char * +get_ical_rid (icalcomponent *ical) +{ + icalproperty *prop; + struct icaltimetype ical_time; + + prop = icalcomponent_get_first_property (ical, ICAL_RECURRENCEID_PROPERTY); + if (!prop) + return NULL; + + ical_time = icalproperty_get_recurrenceid (prop); + + return icaltime_is_valid_time (ical_time) && !icaltime_is_null_time (ical_time) ? + g_strdup (icaltime_as_ical_string (ical_time)) : NULL; +} + +static char * +get_ical_summary (icalcomponent *ical) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (ical, ICAL_SUMMARY_PROPERTY); + if (!prop) + return NULL; + + return g_strdup (icalproperty_get_summary (prop)); +} + +static char * +get_ical_description (icalcomponent *ical) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (ical, ICAL_DESCRIPTION_PROPERTY); + if (!prop) + return NULL; + + return g_strdup (icalproperty_get_description (prop)); +} + +static inline time_t +get_ical_start_time (icalcomponent *ical, + icaltimezone *default_zone) +{ + return get_time_from_property (ical, + ICAL_DTSTART_PROPERTY, + icalproperty_get_dtstart, + default_zone); +} + +static inline time_t +get_ical_end_time (icalcomponent *ical, + icaltimezone *default_zone) +{ + return get_time_from_property (ical, + ICAL_DTEND_PROPERTY, + icalproperty_get_dtend, + default_zone); +} + +static gboolean +get_ical_is_all_day (icalcomponent *ical, + time_t start_time, + icaltimezone *default_zone) +{ + icalproperty *prop; + struct tm *start_tm; + time_t end_time; + struct icaldurationtype duration; + struct icaltimetype start_icaltime; + + start_icaltime = icalcomponent_get_dtstart (ical); + if (start_icaltime.is_date) + return TRUE; + + start_tm = gmtime (&start_time); + if (start_tm->tm_sec != 0 || + start_tm->tm_min != 0 || + start_tm->tm_hour != 0) + return FALSE; + + if ((end_time = get_ical_end_time (ical, default_zone))) + return (end_time - start_time) % 86400 == 0; + + prop = icalcomponent_get_first_property (ical, ICAL_DURATION_PROPERTY); + if (!prop) + return FALSE; + + duration = icalproperty_get_duration (prop); + + return icaldurationtype_as_int (duration) % 86400 == 0; +} + +static inline time_t +get_ical_due_time (icalcomponent *ical, + icaltimezone *default_zone) +{ + return get_time_from_property (ical, + ICAL_DUE_PROPERTY, + icalproperty_get_due, + default_zone); +} + +static guint +get_ical_percent_complete (icalcomponent *ical) +{ + icalproperty *prop; + icalproperty_status status; + int percent_complete; + + status = icalcomponent_get_status (ical); + if (status == ICAL_STATUS_COMPLETED) + return 100; + + prop = icalcomponent_get_first_property (ical, ICAL_COMPLETED_PROPERTY); + if (prop) + return 100; + + prop = icalcomponent_get_first_property (ical, ICAL_PERCENTCOMPLETE_PROPERTY); + if (!prop) + return 0; + + percent_complete = icalproperty_get_percentcomplete (prop); + + return CLAMP (percent_complete, 0, 100); +} + +static inline time_t +get_ical_completed_time (icalcomponent *ical, + icaltimezone *default_zone) +{ + return get_time_from_property (ical, + ICAL_COMPLETED_PROPERTY, + icalproperty_get_completed, + default_zone); +} + +static int +get_ical_priority (icalcomponent *ical) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (ical, ICAL_PRIORITY_PROPERTY); + if (!prop) + return -1; + + return icalproperty_get_priority (prop); +} + +static char * +get_source_color (ECal *esource) +{ + ESource *source; + + g_return_val_if_fail (E_IS_CAL (esource), NULL); + + source = e_cal_get_source (esource); + + return g_strdup (e_source_peek_color_spec (source)); +} + +static gchar * +get_source_uri (ECal *esource) +{ + ESource *source; + gchar *string; + gchar **list; + + g_return_val_if_fail (E_IS_CAL (esource), NULL); + + source = e_cal_get_source (esource); + string = g_strdup (e_source_get_uri (source)); + if (string) { + list = g_strsplit (string, ":", 2); + g_free (string); + + if (list[0]) { + string = g_strdup (list[0]); + g_strfreev (list); + return string; + } + g_strfreev (list); + } + return NULL; +} + +static inline int +null_safe_strcmp (const char *a, + const char *b) +{ + return (!a && !b) ? 0 : (a && !b) || (!a && b) ? 1 : strcmp (a, b); +} + +static inline gboolean +calendar_appointment_equal (CalendarAppointment *a, + CalendarAppointment *b) +{ + GSList *la, *lb; + + if (g_slist_length (a->occurrences) != g_slist_length (b->occurrences)) + return FALSE; + + for (la = a->occurrences, lb = b->occurrences; la && lb; la = la->next, lb = lb->next) + { + CalendarOccurrence *oa = la->data; + CalendarOccurrence *ob = lb->data; + + if (oa->start_time != ob->start_time || + oa->end_time != ob->end_time) + return FALSE; + } + + return + null_safe_strcmp (a->uid, b->uid) == 0 && + null_safe_strcmp (a->uri, b->uri) == 0 && + null_safe_strcmp (a->summary, b->summary) == 0 && + null_safe_strcmp (a->description, b->description) == 0 && + null_safe_strcmp (a->color_string, b->color_string) == 0 && + a->start_time == b->start_time && + a->end_time == b->end_time && + a->is_all_day == b->is_all_day; +} + +static void +calendar_appointment_copy (CalendarAppointment *appointment, + CalendarAppointment *appointment_copy) +{ + GSList *l; + + g_assert (appointment != NULL); + g_assert (appointment_copy != NULL); + + appointment_copy->occurrences = g_slist_copy (appointment->occurrences); + for (l = appointment_copy->occurrences; l; l = l->next) + { + CalendarOccurrence *occurrence = l->data; + CalendarOccurrence *occurrence_copy; + + occurrence_copy = g_new0 (CalendarOccurrence, 1); + occurrence_copy->start_time = occurrence->start_time; + occurrence_copy->end_time = occurrence->end_time; + + l->data = occurrence_copy; + } + + appointment_copy->uid = g_strdup (appointment->uid); + appointment_copy->uri = g_strdup (appointment->uri); + appointment_copy->summary = g_strdup (appointment->summary); + appointment_copy->description = g_strdup (appointment->description); + appointment_copy->color_string = g_strdup (appointment->color_string); + appointment_copy->start_time = appointment->start_time; + appointment_copy->end_time = appointment->end_time; + appointment_copy->is_all_day = appointment->is_all_day; +} + +static void +calendar_appointment_finalize (CalendarAppointment *appointment) +{ + GSList *l; + + for (l = appointment->occurrences; l; l = l->next) + g_free (l->data); + g_slist_free (appointment->occurrences); + appointment->occurrences = NULL; + + g_free (appointment->uid); + appointment->uid = NULL; + + g_free (appointment->rid); + appointment->rid = NULL; + + g_free (appointment->uri); + appointment->uri = NULL; + + g_free (appointment->summary); + appointment->summary = NULL; + + g_free (appointment->description); + appointment->description = NULL; + + g_free (appointment->color_string); + appointment->color_string = NULL; + + appointment->start_time = 0; + appointment->is_all_day = FALSE; +} + +static void +calendar_appointment_init (CalendarAppointment *appointment, + icalcomponent *ical, + CalendarClientSource *source, + icaltimezone *default_zone) +{ + appointment->uid = get_ical_uid (ical); + appointment->rid = get_ical_rid (ical); + appointment->uri = get_source_uri (source->source); + appointment->summary = get_ical_summary (ical); + appointment->description = get_ical_description (ical); + appointment->color_string = get_source_color (source->source); + appointment->start_time = get_ical_start_time (ical, default_zone); + appointment->end_time = get_ical_end_time (ical, default_zone); + appointment->is_all_day = get_ical_is_all_day (ical, + appointment->start_time, + default_zone); +} + +static icaltimezone * +resolve_timezone_id (const char *tzid, + ECal *source) +{ + icaltimezone *retval; + + retval = icaltimezone_get_builtin_timezone_from_tzid (tzid); + if (!retval) + { + e_cal_get_timezone (source, tzid, &retval, NULL); + } + + return retval; +} + +static gboolean +calendar_appointment_collect_occurrence (ECalComponent *component, + time_t occurrence_start, + time_t occurrence_end, + gpointer data) +{ + CalendarOccurrence *occurrence; + GSList **collect_loc = data; + + occurrence = g_new0 (CalendarOccurrence, 1); + occurrence->start_time = occurrence_start; + occurrence->end_time = occurrence_end; + + *collect_loc = g_slist_prepend (*collect_loc, occurrence); + + return TRUE; +} + +static void +calendar_appointment_generate_ocurrences (CalendarAppointment *appointment, + icalcomponent *ical, + ECal *source, + time_t start, + time_t end, + icaltimezone *default_zone) +{ + ECalComponent *ecal; + + g_assert (appointment->occurrences == NULL); + + ecal = e_cal_component_new (); + e_cal_component_set_icalcomponent (ecal, + icalcomponent_new_clone (ical)); + + e_cal_recur_generate_instances (ecal, + start, + end, + calendar_appointment_collect_occurrence, + &appointment->occurrences, + (ECalRecurResolveTimezoneFn) resolve_timezone_id, + source, + default_zone); + + g_object_unref (ecal); + + appointment->occurrences = g_slist_reverse (appointment->occurrences); +} + +static inline gboolean +calendar_task_equal (CalendarTask *a, + CalendarTask *b) +{ + return + null_safe_strcmp (a->uid, b->uid) == 0 && + null_safe_strcmp (a->summary, b->summary) == 0 && + null_safe_strcmp (a->description, b->description) == 0 && + null_safe_strcmp (a->color_string, b->color_string) == 0 && + a->start_time == b->start_time && + a->due_time == b->due_time && + a->percent_complete == b->percent_complete && + a->completed_time == b->completed_time && + a->priority == b->priority; +} + +static void +calendar_task_copy (CalendarTask *task, + CalendarTask *task_copy) +{ + g_assert (task != NULL); + g_assert (task_copy != NULL); + + task_copy->uid = g_strdup (task->uid); + task_copy->summary = g_strdup (task->summary); + task_copy->description = g_strdup (task->description); + task_copy->color_string = g_strdup (task->color_string); + task_copy->start_time = task->start_time; + task_copy->due_time = task->due_time; + task_copy->percent_complete = task->percent_complete; + task_copy->completed_time = task->completed_time; + task_copy->priority = task->priority; +} + +static void +calendar_task_finalize (CalendarTask *task) +{ + g_free (task->uid); + task->uid = NULL; + + g_free (task->summary); + task->summary = NULL; + + g_free (task->description); + task->description = NULL; + + g_free (task->color_string); + task->color_string = NULL; + + task->percent_complete = 0; +} + +static void +calendar_task_init (CalendarTask *task, + icalcomponent *ical, + CalendarClientSource *source, + icaltimezone *default_zone) +{ + task->uid = get_ical_uid (ical); + task->summary = get_ical_summary (ical); + task->description = get_ical_description (ical); + task->color_string = get_source_color (source->source); + task->start_time = get_ical_start_time (ical, default_zone); + task->due_time = get_ical_due_time (ical, default_zone); + task->percent_complete = get_ical_percent_complete (ical); + task->completed_time = get_ical_completed_time (ical, default_zone); + task->priority = get_ical_priority (ical); +} + +void +calendar_event_free (CalendarEvent *event) +{ + switch (event->type) + { + case CALENDAR_EVENT_APPOINTMENT: + calendar_appointment_finalize (CALENDAR_APPOINTMENT (event)); + break; + case CALENDAR_EVENT_TASK: + calendar_task_finalize (CALENDAR_TASK (event)); + break; + default: + g_assert_not_reached (); + break; + } + + g_free (event); +} + +static CalendarEvent * +calendar_event_new (icalcomponent *ical, + CalendarClientSource *source, + icaltimezone *default_zone) +{ + CalendarEvent *event; + + event = g_new0 (CalendarEvent, 1); + + switch (icalcomponent_isa (ical)) + { + case ICAL_VEVENT_COMPONENT: + event->type = CALENDAR_EVENT_APPOINTMENT; + calendar_appointment_init (CALENDAR_APPOINTMENT (event), + ical, + source, + default_zone); + break; + case ICAL_VTODO_COMPONENT: + event->type = CALENDAR_EVENT_TASK; + calendar_task_init (CALENDAR_TASK (event), + ical, + source, + default_zone); + break; + default: + g_warning ("Unknown calendar component type: %d\n", + icalcomponent_isa (ical)); + g_free (event); + return NULL; + } + + return event; +} + +static CalendarEvent * +calendar_event_copy (CalendarEvent *event) +{ + CalendarEvent *retval; + + if (!event) + return NULL; + + retval = g_new0 (CalendarEvent, 1); + + retval->type = event->type; + + switch (event->type) + { + case CALENDAR_EVENT_APPOINTMENT: + calendar_appointment_copy (CALENDAR_APPOINTMENT (event), + CALENDAR_APPOINTMENT (retval)); + break; + case CALENDAR_EVENT_TASK: + calendar_task_copy (CALENDAR_TASK (event), + CALENDAR_TASK (retval)); + break; + default: + g_assert_not_reached (); + break; + } + + return retval; +} + +static char * +calendar_event_get_uid (CalendarEvent *event) +{ + switch (event->type) + { + case CALENDAR_EVENT_APPOINTMENT: + return g_strdup_printf ("%s%s", CALENDAR_APPOINTMENT (event)->uid, CALENDAR_APPOINTMENT (event)->rid ? CALENDAR_APPOINTMENT (event)->rid : ""); + break; + case CALENDAR_EVENT_TASK: + return g_strdup (CALENDAR_TASK (event)->uid); + break; + default: + g_assert_not_reached (); + break; + } + + return NULL; +} + +static gboolean +calendar_event_equal (CalendarEvent *a, + CalendarEvent *b) +{ + if (!a && !b) + return TRUE; + + if ((a && !b) || (!a && b)) + return FALSE; + + if (a->type != b->type) + return FALSE; + + switch (a->type) + { + case CALENDAR_EVENT_APPOINTMENT: + return calendar_appointment_equal (CALENDAR_APPOINTMENT (a), + CALENDAR_APPOINTMENT (b)); + case CALENDAR_EVENT_TASK: + return calendar_task_equal (CALENDAR_TASK (a), + CALENDAR_TASK (b)); + default: + break; + } + + g_assert_not_reached (); + + return FALSE; +} + +static void +calendar_event_generate_ocurrences (CalendarEvent *event, + icalcomponent *ical, + ECal *source, + time_t start, + time_t end, + icaltimezone *default_zone) +{ + if (event->type != CALENDAR_EVENT_APPOINTMENT) + return; + + calendar_appointment_generate_ocurrences (CALENDAR_APPOINTMENT (event), + ical, + source, + start, + end, + default_zone); +} + +static inline void +calendar_event_debug_dump (CalendarEvent *event) +{ +#ifdef CALENDAR_ENABLE_DEBUG + switch (event->type) + { + case CALENDAR_EVENT_APPOINTMENT: + { + char *start_str; + char *end_str; + GSList *l; + + start_str = CALENDAR_APPOINTMENT (event)->start_time ? + isodate_from_time_t (CALENDAR_APPOINTMENT (event)->start_time) : + g_strdup ("(undefined)"); + end_str = CALENDAR_APPOINTMENT (event)->end_time ? + isodate_from_time_t (CALENDAR_APPOINTMENT (event)->end_time) : + g_strdup ("(undefined)"); + + dprintf ("Appointment: uid '%s', summary '%s', description '%s', " + "start_time '%s', end_time '%s', is_all_day %s\n", + CALENDAR_APPOINTMENT (event)->uid, + CALENDAR_APPOINTMENT (event)->summary, + CALENDAR_APPOINTMENT (event)->description, + start_str, + end_str, + CALENDAR_APPOINTMENT (event)->is_all_day ? "(true)" : "(false)"); + + g_free (start_str); + g_free (end_str); + + dprintf (" Occurrences:\n"); + for (l = CALENDAR_APPOINTMENT (event)->occurrences; l; l = l->next) + { + CalendarOccurrence *occurrence = l->data; + + start_str = occurrence->start_time ? + isodate_from_time_t (occurrence->start_time) : + g_strdup ("(undefined)"); + + end_str = occurrence->end_time ? + isodate_from_time_t (occurrence->end_time) : + g_strdup ("(undefined)"); + + dprintf (" start_time '%s', end_time '%s'\n", + start_str, end_str); + + g_free (start_str); + g_free (end_str); + } + } + break; + case CALENDAR_EVENT_TASK: + { + char *start_str; + char *due_str; + char *completed_str; + + start_str = CALENDAR_TASK (event)->start_time ? + isodate_from_time_t (CALENDAR_TASK (event)->start_time) : + g_strdup ("(undefined)"); + due_str = CALENDAR_TASK (event)->due_time ? + isodate_from_time_t (CALENDAR_TASK (event)->due_time) : + g_strdup ("(undefined)"); + completed_str = CALENDAR_TASK (event)->completed_time ? + isodate_from_time_t (CALENDAR_TASK (event)->completed_time) : + g_strdup ("(undefined)"); + + dprintf ("Task: uid '%s', summary '%s', description '%s', " + "start_time '%s', due_time '%s', percent_complete %d, completed_time '%s'\n", + CALENDAR_TASK (event)->uid, + CALENDAR_TASK (event)->summary, + CALENDAR_TASK (event)->description, + start_str, + due_str, + CALENDAR_TASK (event)->percent_complete, + completed_str); + + g_free (completed_str); + } + break; + default: + g_assert_not_reached (); + break; + } +#endif +} + +static inline CalendarClientQuery * +goddamn_this_is_crack (CalendarClientSource *source, + ECalView *view, + gboolean *emit_signal) +{ + g_assert (view != NULL); + + if (source->completed_query.view == view) + { + if (emit_signal) + *emit_signal = TRUE; + return &source->completed_query; + } + else if (source->in_progress_query.view == view) + { + if (emit_signal) + *emit_signal = FALSE; + return &source->in_progress_query; + } + + g_assert_not_reached (); + + return NULL; +} + +static void +calendar_client_handle_query_completed (CalendarClientSource *source, + ECalendarStatus status, + ECalView *view) +{ + CalendarClientQuery *query; + + query = goddamn_this_is_crack (source, view, NULL); + + dprintf ("Query %p completed: %s\n", query, e_cal_get_error_message (status)); + + if (status != E_CALENDAR_STATUS_OK) + { + g_warning ("Calendar query failed: %s\n", + e_cal_get_error_message (status)); + calendar_client_stop_query (source->client, source, query); + return; + } + + g_assert (source->query_in_progress != FALSE); + g_assert (query == &source->in_progress_query); + + calendar_client_query_finalize (&source->completed_query); + + source->completed_query = source->in_progress_query; + source->query_completed = TRUE; + + source->query_in_progress = FALSE; + source->in_progress_query.view = NULL; + source->in_progress_query.events = NULL; + + g_signal_emit (source->client, source->changed_signal_id, 0); +} + +static void +calendar_client_handle_query_result (CalendarClientSource *source, + GList *objects, + ECalView *view) +{ + CalendarClientQuery *query; + CalendarClient *client; + gboolean emit_signal; + gboolean events_changed; + GList *l; + time_t month_begin; + time_t month_end; + + client = source->client; + + query = goddamn_this_is_crack (source, view, &emit_signal); + + dprintf ("Query %p result: %d objects:\n", + query, g_list_length (objects)); + + month_begin = make_time_for_day_begin (1, + client->priv->month, + client->priv->year); + + month_end = make_time_for_day_begin (1, + client->priv->month + 1, + client->priv->year); + + events_changed = FALSE; + for (l = objects; l; l = l->next) + { + CalendarEvent *event; + CalendarEvent *old_event; + icalcomponent *ical = l->data; + char *uid; + + event = calendar_event_new (ical, source, client->priv->zone); + if (!event) + continue; + + calendar_event_generate_ocurrences (event, + ical, + source->source, + month_begin, + month_end, + client->priv->zone); + + uid = calendar_event_get_uid (event); + + old_event = g_hash_table_lookup (query->events, uid); + + if (!calendar_event_equal (event, old_event)) + { + dprintf ("Event %s: ", old_event ? "modified" : "added"); + + calendar_event_debug_dump (event); + + g_hash_table_replace (query->events, uid, event); + + events_changed = TRUE; + } + else + { + g_free (uid); + } + } + + if (emit_signal && events_changed) + { + g_signal_emit (source->client, source->changed_signal_id, 0); + } +} + +static gboolean +check_object_remove (gpointer key, + gpointer value, + gpointer data) +{ + char *uid = data; + ssize_t len; + + len = strlen (uid); + + if (len <= strlen (key) && strncmp (uid, key, len) == 0) + { + dprintf ("Event removed: "); + + calendar_event_debug_dump (value); + + return TRUE; + } + + return FALSE; +} + +static void +calendar_client_handle_objects_removed (CalendarClientSource *source, + GList *ids, + ECalView *view) +{ + CalendarClientQuery *query; + gboolean emit_signal; + gboolean events_changed; + GList *l; + + query = goddamn_this_is_crack (source, view, &emit_signal); + + events_changed = FALSE; + for (l = ids; l; l = l->next) + { + CalendarEvent *event; + ECalComponentId *id = l->data; + char *uid = g_strdup_printf ("%s%s", id->uid, id->rid ? id->rid : ""); + + if (!id->rid || !(*id->rid)) + { + int size = g_hash_table_size (query->events); + + g_hash_table_foreach_remove (query->events, check_object_remove, id->uid); + + if (size != g_hash_table_size (query->events)) + events_changed = TRUE; + } + else if ((event = g_hash_table_lookup (query->events, uid))) + { + dprintf ("Event removed: "); + + calendar_event_debug_dump (event); + + g_assert (g_hash_table_remove (query->events, uid)); + + events_changed = TRUE; + } + g_free (uid); + } + + if (emit_signal && events_changed) + { + g_signal_emit (source->client, source->changed_signal_id, 0); + } +} + +static void +calendar_client_query_finalize (CalendarClientQuery *query) +{ + if (query->view) + g_object_unref (query->view); + query->view = NULL; + + if (query->events) + g_hash_table_destroy (query->events); + query->events = NULL; +} + +static void +calendar_client_stop_query (CalendarClient *client, + CalendarClientSource *source, + CalendarClientQuery *query) +{ + if (query == &source->in_progress_query) + { + dprintf ("Stopping in progress query %p\n", query); + + g_assert (source->query_in_progress != FALSE); + + source->query_in_progress = FALSE; + } + else if (query == &source->completed_query) + { + dprintf ("Stopping completed query %p\n", query); + + g_assert (source->query_completed != FALSE); + + source->query_completed = FALSE; + } + else + g_assert_not_reached (); + + calendar_client_query_finalize (query); +} + +static void +calendar_client_start_query (CalendarClient *client, + CalendarClientSource *source, + const char *query) +{ + ECalView *view = NULL; + GError *error = NULL; + + if (!e_cal_get_query (source->source, query, &view, &error)) + { + g_warning ("Error preparing the query: '%s': %s\n", + query, error->message); + g_error_free (error); + return; + } + + g_assert (view != NULL); + + if (source->query_in_progress) + calendar_client_stop_query (client, source, &source->in_progress_query); + + dprintf ("Starting query %p: '%s'\n", &source->in_progress_query, query); + + source->query_in_progress = TRUE; + source->in_progress_query.view = view; + source->in_progress_query.events = + g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) calendar_event_free); + + g_signal_connect_swapped (view, "objects-added", + G_CALLBACK (calendar_client_handle_query_result), + source); + g_signal_connect_swapped (view, "objects-modified", + G_CALLBACK (calendar_client_handle_query_result), + source); + g_signal_connect_swapped (view, "objects-removed", + G_CALLBACK (calendar_client_handle_objects_removed), + source); + g_signal_connect_swapped (view, "view-done", + G_CALLBACK (calendar_client_handle_query_completed), + source); + + e_cal_view_start (view); +} + +static void +calendar_client_update_appointments (CalendarClient *client) +{ + GSList *l; + char *query; + char *month_begin; + char *month_end; + + if (client->priv->month == -1 || + client->priv->year == -1) + return; + + month_begin = make_isodate_for_day_begin (1, + client->priv->month, + client->priv->year); + + month_end = make_isodate_for_day_begin (1, + client->priv->month + 1, + client->priv->year); + + query = g_strdup_printf ("occur-in-time-range? (make-time \"%s\") " + "(make-time \"%s\")", + month_begin, month_end); + + for (l = client->priv->appointment_sources; l; l = l->next) + { + CalendarClientSource *cs = l->data; + + if (e_cal_get_load_state (cs->source) != E_CAL_LOAD_LOADED) + continue; + + calendar_client_start_query (client, cs, query); + } + + g_free (month_begin); + g_free (month_end); + g_free (query); +} + +/* FIXME: + * perhaps we should use evo's "hide_completed_tasks" pref? + */ +static void +calendar_client_update_tasks (CalendarClient *client) +{ + GSList *l; + char *query; + +#ifdef FIX_BROKEN_TASKS_QUERY + /* FIXME: this doesn't work for tasks without a start or + * due date + * Look at filter_task() to see the behaviour we + * want. + */ + + char *day_begin; + char *day_end; + + if (client->priv->day == -1 || + client->priv->month == -1 || + client->priv->year == -1) + return; + + day_begin = make_isodate_for_day_begin (client->priv->day, + client->priv->month, + client->priv->year); + + day_end = make_isodate_for_day_begin (client->priv->day + 1, + client->priv->month, + client->priv->year); + if (!day_begin || !day_end) + { + g_warning ("Cannot run query with invalid date: %dd %dy %dm\n", + client->priv->day, + client->priv->month, + client->priv->year); + g_free (day_begin); + g_free (day_end); + return; + } + + query = g_strdup_printf ("(and (occur-in-time-range? (make-time \"%s\") " + "(make-time \"%s\")) " + "(or (not is-completed?) " + "(and (is-completed?) " + "(not (completed-before? (make-time \"%s\"))))))", + day_begin, day_end, day_begin); +#else + query = g_strdup ("#t"); +#endif /* FIX_BROKEN_TASKS_QUERY */ + + for (l = client->priv->task_sources; l; l = l->next) + { + CalendarClientSource *cs = l->data; + + if (e_cal_get_load_state (cs->source) != E_CAL_LOAD_LOADED) + continue; + + calendar_client_start_query (client, cs, query); + } + +#ifdef FIX_BROKEN_TASKS_QUERY + g_free (day_begin); + g_free (day_end); +#endif + g_free (query); +} + +static void +calendar_client_source_finalize (CalendarClientSource *source) +{ + source->client = NULL; + + if (source->source) { + g_signal_handlers_disconnect_by_func (source->source, + cal_opened_cb, source); + g_object_unref (source->source); + } + source->source = NULL; + + calendar_client_query_finalize (&source->completed_query); + calendar_client_query_finalize (&source->in_progress_query); + + source->query_completed = FALSE; + source->query_in_progress = FALSE; +} + +static int +compare_calendar_sources (CalendarClientSource *s1, + CalendarClientSource *s2) +{ + return (s1->source == s2->source) ? 0 : 1; +} + +static GSList * +calendar_client_update_sources_list (CalendarClient *client, + GSList *sources, + GSList *esources, + guint changed_signal_id) +{ + GSList *retval, *l; + + retval = NULL; + + for (l = esources; l; l = l->next) + { + CalendarClientSource dummy_source; + CalendarClientSource *new_source; + GSList *s; + ECal *esource = l->data; + + dummy_source.source = esource; + + dprintf ("update_sources_list: adding client %s: ", + e_source_peek_uid (e_cal_get_source (esource))); + + if ((s = g_slist_find_custom (sources, + &dummy_source, + (GCompareFunc) compare_calendar_sources))) + { + dprintf ("already on list\n"); + new_source = s->data; + sources = g_slist_delete_link (sources, s); + } + else + { + dprintf ("added\n"); + new_source = g_new0 (CalendarClientSource, 1); + new_source->client = client; + new_source->source = g_object_ref (esource); + new_source->changed_signal_id = changed_signal_id; + } + + retval = g_slist_prepend (retval, new_source); + } + + for (l = sources; l; l = l->next) + { + CalendarClientSource *source = l->data; + + dprintf ("Removing client %s from list\n", + e_source_peek_uid (e_cal_get_source (source->source))); + + calendar_client_source_finalize (source); + g_free (source); + } + g_slist_free (sources); + + return retval; +} + +static void +calendar_client_appointment_sources_changed (CalendarClient *client) +{ + GSList *esources; + + dprintf ("appointment_sources_changed: updating ...\n"); + + esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources); + + client->priv->appointment_sources = + calendar_client_update_sources_list (client, + client->priv->appointment_sources, + esources, + signals [APPOINTMENTS_CHANGED]); + + load_calendars (client, CALENDAR_EVENT_APPOINTMENT); + calendar_client_update_appointments (client); +} + +static void +calendar_client_task_sources_changed (CalendarClient *client) +{ + GSList *esources; + + dprintf ("task_sources_changed: updating ...\n"); + + esources = calendar_sources_get_task_sources (client->priv->calendar_sources); + + client->priv->task_sources = + calendar_client_update_sources_list (client, + client->priv->task_sources, + esources, + signals [TASKS_CHANGED]); + + load_calendars (client, CALENDAR_EVENT_TASK); + calendar_client_update_tasks (client); +} + +void +calendar_client_get_date (CalendarClient *client, + guint *year, + guint *month, + guint *day) +{ + g_return_if_fail (CALENDAR_IS_CLIENT (client)); + + if (year) + *year = client->priv->year; + + if (month) + *month = client->priv->month; + + if (day) + *day = client->priv->day; +} + +void +calendar_client_select_month (CalendarClient *client, + guint month, + guint year) +{ + g_return_if_fail (CALENDAR_IS_CLIENT (client)); + g_return_if_fail (month <= 11); + + if (client->priv->year != year || client->priv->month != month) + { + client->priv->month = month; + client->priv->year = year; + + calendar_client_update_appointments (client); + calendar_client_update_tasks (client); + + g_object_freeze_notify (G_OBJECT (client)); + g_object_notify (G_OBJECT (client), "month"); + g_object_notify (G_OBJECT (client), "year"); + g_object_thaw_notify (G_OBJECT (client)); + } +} + +void +calendar_client_select_day (CalendarClient *client, + guint day) +{ + g_return_if_fail (CALENDAR_IS_CLIENT (client)); + g_return_if_fail (day <= 31); + + if (client->priv->day != day) + { + client->priv->day = day; + + /* don't need to update appointments unless + * the selected month changes + */ +#ifdef FIX_BROKEN_TASKS_QUERY + calendar_client_update_tasks (client); +#endif + + g_object_notify (G_OBJECT (client), "day"); + } +} + +typedef struct +{ + CalendarClient *client; + GSList *events; + time_t start_time; + time_t end_time; +} FilterData; + +typedef void (* CalendarEventFilterFunc) (const char *uid, + CalendarEvent *event, + FilterData *filter_data); + +static void +filter_appointment (const char *uid, + CalendarEvent *event, + FilterData *filter_data) +{ + GSList *occurrences, *l; + + if (event->type != CALENDAR_EVENT_APPOINTMENT) + return; + + occurrences = CALENDAR_APPOINTMENT (event)->occurrences; + CALENDAR_APPOINTMENT (event)->occurrences = NULL; + + for (l = occurrences; l; l = l->next) + { + CalendarOccurrence *occurrence = l->data; + time_t start_time = occurrence->start_time; + time_t end_time = occurrence->end_time; + + if ((start_time >= filter_data->start_time && + start_time < filter_data->end_time) || + (start_time <= filter_data->start_time && + (end_time - 1) > filter_data->start_time)) + { + CalendarEvent *new_event; + + new_event = calendar_event_copy (event); + + CALENDAR_APPOINTMENT (new_event)->start_time = occurrence->start_time; + CALENDAR_APPOINTMENT (new_event)->end_time = occurrence->end_time; + + filter_data->events = g_slist_prepend (filter_data->events, new_event); + } + } + + CALENDAR_APPOINTMENT (event)->occurrences = occurrences; +} + +static void +filter_task (const char *uid, + CalendarEvent *event, + FilterData *filter_data) +{ +#ifdef FIX_BROKEN_TASKS_QUERY + CalendarTask *task; +#endif + + if (event->type != CALENDAR_EVENT_TASK) + return; + +#ifdef FIX_BROKEN_TASKS_QUERY + task = CALENDAR_TASK (event); + + if (task->start_time && task->start_time > filter_data->start_time) + return; + + if (task->completed_time && + (task->completed_time < filter_data->start_time || + task->completed_time > filter_data->end_time)) + return; +#endif /* FIX_BROKEN_TASKS_QUERY */ + + filter_data->events = g_slist_prepend (filter_data->events, + calendar_event_copy (event)); +} + +static GSList * +calendar_client_filter_events (CalendarClient *client, + GSList *sources, + CalendarEventFilterFunc filter_func, + time_t start_time, + time_t end_time) +{ + FilterData filter_data; + GSList *l; + GSList *retval; + + if (!sources) + return NULL; + + filter_data.client = client; + filter_data.events = NULL; + filter_data.start_time = start_time; + filter_data.end_time = end_time; + + retval = NULL; + for (l = sources; l; l = l->next) + { + CalendarClientSource *source = l->data; + + if (source->query_completed) + { + filter_data.events = NULL; + g_hash_table_foreach (source->completed_query.events, + (GHFunc) filter_func, + &filter_data); + + filter_data.events = g_slist_reverse (filter_data.events); + + retval = g_slist_concat (retval, filter_data.events); + } + } + + return retval; +} + +GSList * +calendar_client_get_events (CalendarClient *client, + CalendarEventType event_mask) +{ + GSList *appointments; + GSList *tasks; + time_t day_begin; + time_t day_end; + + g_return_val_if_fail (CALENDAR_IS_CLIENT (client), NULL); + g_return_val_if_fail (client->priv->day != -1 && + client->priv->month != -1 && + client->priv->year != -1, NULL); + + day_begin = make_time_for_day_begin (client->priv->day, + client->priv->month, + client->priv->year); + day_end = make_time_for_day_begin (client->priv->day + 1, + client->priv->month, + client->priv->year); + + appointments = NULL; + if (event_mask & CALENDAR_EVENT_APPOINTMENT) + { + appointments = calendar_client_filter_events (client, + client->priv->appointment_sources, + filter_appointment, + day_begin, + day_end); + } + + tasks = NULL; + if (event_mask & CALENDAR_EVENT_TASK) + { + tasks = calendar_client_filter_events (client, + client->priv->task_sources, + filter_task, + day_begin, + day_end); + } + + return g_slist_concat (appointments, tasks); +} + +static inline int +day_from_time_t (time_t t) +{ + struct tm *tm = localtime (&t); + + g_assert (tm == NULL || (tm->tm_mday >=1 && tm->tm_mday <= 31)); + + return tm ? tm->tm_mday : 0; +} + +void +calendar_client_foreach_appointment_day (CalendarClient *client, + CalendarDayIter iter_func, + gpointer user_data) +{ + GSList *appointments, *l; + gboolean marked_days [32] = { FALSE, }; + time_t month_begin; + time_t month_end; + int i; + + g_return_if_fail (CALENDAR_IS_CLIENT (client)); + g_return_if_fail (iter_func != NULL); + g_return_if_fail (client->priv->month != -1 && + client->priv->year != -1); + + month_begin = make_time_for_day_begin (1, + client->priv->month, + client->priv->year); + month_end = make_time_for_day_begin (1, + client->priv->month + 1, + client->priv->year); + + appointments = calendar_client_filter_events (client, + client->priv->appointment_sources, + filter_appointment, + month_begin, + month_end); + for (l = appointments; l; l = l->next) + { + CalendarAppointment *appointment = l->data; + + if (appointment->start_time) + { + time_t day_time = appointment->start_time; + + if (day_time >= month_begin) + marked_days [day_from_time_t (day_time)] = TRUE; + + if (appointment->end_time) + { + int day_offset; + int duration = appointment->end_time - appointment->start_time; + /* mark the days for the appointment, no need to add an extra one when duration is a multiple of 86400 */ + for (day_offset = 1; day_offset <= duration / 86400 && duration != day_offset * 86400; day_offset++) + { + time_t day_tm = appointment->start_time + day_offset * 86400; + + if (day_tm > month_end) + break; + if (day_tm >= month_begin) + marked_days [day_from_time_t (day_tm)] = TRUE; + } + } + } + calendar_event_free (CALENDAR_EVENT (appointment)); + } + + g_slist_free (appointments); + + for (i = 1; i < 32; i++) + { + if (marked_days [i]) + iter_func (client, i, user_data); + } +} + +void +calendar_client_set_task_completed (CalendarClient *client, + char *task_uid, + gboolean task_completed, + guint percent_complete) +{ + GSList *l; + ECal *esource; + icalcomponent *ical; + icalproperty *prop; + icalproperty_status status; + + g_return_if_fail (CALENDAR_IS_CLIENT (client)); + g_return_if_fail (task_uid != NULL); + g_return_if_fail (task_completed == FALSE || percent_complete == 100); + + ical = NULL; + esource = NULL; + for (l = client->priv->task_sources; l; l = l->next) + { + CalendarClientSource *source = l->data; + + esource = source->source; + e_cal_get_object (esource, task_uid, NULL, &ical, NULL); + if (ical) + break; + } + + if (!ical) + { + g_warning ("Cannot locate task with uid = '%s'\n", task_uid); + return; + } + + g_assert (esource != NULL); + + /* Completed time */ + prop = icalcomponent_get_first_property (ical, + ICAL_COMPLETED_PROPERTY); + if (task_completed) + { + struct icaltimetype completed_time; + + completed_time = icaltime_current_time_with_zone (client->priv->zone); + if (!prop) + { + icalcomponent_add_property (ical, + icalproperty_new_completed (completed_time)); + } + else + { + icalproperty_set_completed (prop, completed_time); + } + } + else if (prop) + { + icalcomponent_remove_property (ical, prop); + } + + /* Percent complete */ + prop = icalcomponent_get_first_property (ical, + ICAL_PERCENTCOMPLETE_PROPERTY); + if (!prop) + { + icalcomponent_add_property (ical, + icalproperty_new_percentcomplete (percent_complete)); + } + else + { + icalproperty_set_percentcomplete (prop, percent_complete); + } + + /* Status */ + status = task_completed ? ICAL_STATUS_COMPLETED : ICAL_STATUS_NEEDSACTION; + prop = icalcomponent_get_first_property (ical, ICAL_STATUS_PROPERTY); + if (prop) + { + icalproperty_set_status (prop, status); + } + else + { + icalcomponent_add_property (ical, + icalproperty_new_status (status)); + } + + e_cal_modify_object (esource, ical, CALOBJ_MOD_ALL, NULL); +} diff --git a/applets/clock/calendar-client.h b/applets/clock/calendar-client.h new file mode 100644 index 00000000..9d502ba0 --- /dev/null +++ b/applets/clock/calendar-client.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + * William Jon McCann + * Martin Grimme + * Christian Kellner + */ + +#ifndef __CALENDAR_CLIENT_H__ +#define __CALENDAR_CLIENT_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + CALENDAR_EVENT_APPOINTMENT = 1 << 0, + CALENDAR_EVENT_TASK = 1 << 1, + CALENDAR_EVENT_ALL = (1 << 2) - 1 +} CalendarEventType; + +#define CALENDAR_TYPE_CLIENT (calendar_client_get_type ()) +#define CALENDAR_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CALENDAR_TYPE_CLIENT, CalendarClient)) +#define CALENDAR_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CALENDAR_TYPE_CLIENT, CalendarClientClass)) +#define CALENDAR_IS_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CALENDAR_TYPE_CLIENT)) +#define CALENDAR_IS_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CALENDAR_TYPE_CLIENT)) +#define CALENDAR_CLIENT_GET_CLASS(o)(G_TYPE_INSTANCE_GET_CLASS ((o), CALENDAR_TYPE_CLIENT, CalendarClientClass)) + +typedef struct _CalendarClient CalendarClient; +typedef struct _CalendarClientClass CalendarClientClass; +typedef struct _CalendarClientPrivate CalendarClientPrivate; + +struct _CalendarClient +{ + GObject parent; + CalendarClientPrivate *priv; +}; + +struct _CalendarClientClass +{ + GObjectClass parent_class; + + void (* appointments_changed) (CalendarClient *client); + void (* tasks_changed) (CalendarClient *client); +}; + + +typedef struct +{ + time_t start_time; + time_t end_time; +} CalendarOccurrence; + +typedef struct +{ + char *uid; + char *rid; + char *uri; + char *summary; + char *description; + char *color_string; + time_t start_time; + time_t end_time; + guint is_all_day : 1; + + /* Only used internally */ + GSList *occurrences; +} CalendarAppointment; + +typedef struct +{ + char *uid; + char *summary; + char *description; + char *color_string; + char *url; + time_t start_time; + time_t due_time; + guint percent_complete; + time_t completed_time; + int priority; +} CalendarTask; + +typedef struct +{ + union + { + CalendarAppointment appointment; + CalendarTask task; + } event; + CalendarEventType type; +} CalendarEvent; + +#define CALENDAR_EVENT(e) ((CalendarEvent *)(e)) +#define CALENDAR_APPOINTMENT(e) ((CalendarAppointment *)(e)) +#define CALENDAR_TASK(e) ((CalendarTask *)(e)) + +typedef void (* CalendarDayIter) (CalendarClient *client, + guint day, + gpointer user_data); + + +GType calendar_client_get_type (void) G_GNUC_CONST; +CalendarClient *calendar_client_new (void); + +void calendar_client_get_date (CalendarClient *client, + guint *year, + guint *month, + guint *day); +void calendar_client_select_month (CalendarClient *client, + guint month, + guint year); +void calendar_client_select_day (CalendarClient *client, + guint day); + +GSList *calendar_client_get_events (CalendarClient *client, + CalendarEventType event_mask); +void calendar_client_foreach_appointment_day (CalendarClient *client, + CalendarDayIter iter_func, + gpointer user_data); + +void calendar_client_set_task_completed (CalendarClient *client, + char *task_uid, + gboolean task_completed, + guint percent_complete); + +void calendar_event_free (CalendarEvent *event); + +#ifdef __cplusplus +} +#endif + +#endif /* __CALENDAR_CLIENT_H__ */ diff --git a/applets/clock/calendar-debug.h b/applets/clock/calendar-debug.h new file mode 100644 index 00000000..a7ea2a79 --- /dev/null +++ b/applets/clock/calendar-debug.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __CALENDAR_DEBUG_H__ +#define __CALENDAR_DEBUG_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CALENDAR_ENABLE_DEBUG + +#include + +#ifdef G_HAVE_ISO_VARARGS +# define dprintf(...) fprintf (stderr, __VA_ARGS__); +#elif defined(G_HAVE_GNUC_VARARGS) +# define dprintf(args...) fprintf (stderr, args); +#endif + +#else /* if !defined (CALENDAR_DEBUG) */ + +#ifdef G_HAVE_ISO_VARARGS +# define dprintf(...) +#elif defined(G_HAVE_GNUC_VARARGS) +# define dprintf(args...) +#endif + +#endif /* CALENDAR_ENABLE_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __CALENDAR_DEBUG_H__ */ diff --git a/applets/clock/calendar-sources.c b/applets/clock/calendar-sources.c new file mode 100644 index 00000000..721ff062 --- /dev/null +++ b/applets/clock/calendar-sources.c @@ -0,0 +1,658 @@ +/* + * Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + * William Jon McCann + * Martin Grimme + * Christian Kellner + */ + +#include + +#include "calendar-sources.h" + +#include +#include +#include +#define HANDLE_LIBICAL_MEMORY +#include +#include +#include + +#undef CALENDAR_ENABLE_DEBUG +#include "calendar-debug.h" + +#ifndef _ +#define _(x) gettext(x) +#endif + +#ifndef N_ +#define N_(x) x +#endif + +#define CALENDAR_SOURCES_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CALENDAR_TYPE_SOURCES, CalendarSourcesPrivate)) + +#define CALENDAR_SOURCES_EVO_DIR "/apps/evolution" +#define CALENDAR_SOURCES_APPOINTMENT_SOURCES_KEY CALENDAR_SOURCES_EVO_DIR "/calendar/sources" +#define CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR CALENDAR_SOURCES_EVO_DIR "/calendar/display" +#define CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_KEY CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR "/selected_calendars" +#define CALENDAR_SOURCES_TASK_SOURCES_KEY CALENDAR_SOURCES_EVO_DIR "/tasks/sources" +#define CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR CALENDAR_SOURCES_EVO_DIR "/calendar/tasks" +#define CALENDAR_SOURCES_SELECTED_TASK_SOURCES_KEY CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR "/selected_tasks" + +typedef struct _CalendarSourceData CalendarSourceData; + +struct _CalendarSourceData +{ + ECalSourceType source_type; + CalendarSources *sources; + guint changed_signal; + + GSList *clients; + GSList *selected_sources; + ESourceList *esource_list; + + guint selected_sources_listener; + char *selected_sources_dir; + + guint timeout_id; + + guint loaded : 1; +}; + +struct _CalendarSourcesPrivate +{ + CalendarSourceData appointment_sources; + CalendarSourceData task_sources; + + MateConfClient *mateconf_client; +}; + +static void calendar_sources_class_init (CalendarSourcesClass *klass); +static void calendar_sources_init (CalendarSources *sources); +static void calendar_sources_finalize (GObject *object); + +static void backend_died_cb (ECal *client, CalendarSourceData *source_data); +static void calendar_sources_esource_list_changed (ESourceList *source_list, + CalendarSourceData *source_data); + +enum +{ + APPOINTMENT_SOURCES_CHANGED, + TASK_SOURCES_CHANGED, + LAST_SIGNAL +}; +static guint signals [LAST_SIGNAL] = { 0, }; + +static GObjectClass *parent_class = NULL; +static CalendarSources *calendar_sources_singleton = NULL; + +GType +calendar_sources_get_type (void) +{ + static GType sources_type = 0; + + if (!sources_type) + { + static const GTypeInfo sources_info = + { + sizeof (CalendarSourcesClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) calendar_sources_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (CalendarSources), + 0, /* n_preallocs */ + (GInstanceInitFunc) calendar_sources_init, + }; + + sources_type = g_type_register_static (G_TYPE_OBJECT, + "CalendarSources", + &sources_info, 0); + } + + return sources_type; +} + +static void +calendar_sources_class_init (CalendarSourcesClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->finalize = calendar_sources_finalize; + + g_type_class_add_private (klass, sizeof (CalendarSourcesPrivate)); + + signals [APPOINTMENT_SOURCES_CHANGED] = + g_signal_new ("appointment-sources-changed", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalendarSourcesClass, + appointment_sources_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + signals [TASK_SOURCES_CHANGED] = + g_signal_new ("task-sources-changed", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalendarSourcesClass, + task_sources_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static void +calendar_sources_init (CalendarSources *sources) +{ + sources->priv = CALENDAR_SOURCES_GET_PRIVATE (sources); + + sources->priv->appointment_sources.source_type = E_CAL_SOURCE_TYPE_EVENT; + sources->priv->appointment_sources.sources = sources; + sources->priv->appointment_sources.changed_signal = signals [APPOINTMENT_SOURCES_CHANGED]; + sources->priv->appointment_sources.timeout_id = 0; + + sources->priv->task_sources.source_type = E_CAL_SOURCE_TYPE_TODO; + sources->priv->task_sources.sources = sources; + sources->priv->task_sources.changed_signal = signals [TASK_SOURCES_CHANGED]; + sources->priv->task_sources.timeout_id = 0; + + sources->priv->mateconf_client = mateconf_client_get_default (); +} + +static void +calendar_sources_finalize_source_data (CalendarSources *sources, + CalendarSourceData *source_data) +{ + if (source_data->loaded) + { + GSList *l; + + if (source_data->selected_sources_dir) + { + mateconf_client_remove_dir (sources->priv->mateconf_client, + source_data->selected_sources_dir, + NULL); + + g_free (source_data->selected_sources_dir); + source_data->selected_sources_dir = NULL; + } + + if (source_data->selected_sources_listener) + { + mateconf_client_notify_remove (sources->priv->mateconf_client, + source_data->selected_sources_listener); + source_data->selected_sources_listener = 0; + } + + for (l = source_data->clients; l; l = l->next) + { + g_signal_handlers_disconnect_by_func (G_OBJECT (l->data), + G_CALLBACK (backend_died_cb), + source_data); + g_object_unref (l->data); + } + g_slist_free (source_data->clients); + source_data->clients = NULL; + + if (source_data->esource_list) + { + g_signal_handlers_disconnect_by_func (source_data->esource_list, + G_CALLBACK (calendar_sources_esource_list_changed), + source_data); + g_object_unref (source_data->esource_list); + } + source_data->esource_list = NULL; + + for (l = source_data->selected_sources; l; l = l->next) + g_free (l->data); + g_slist_free (source_data->selected_sources); + source_data->selected_sources = NULL; + + if (source_data->timeout_id != 0) + { + g_source_remove (source_data->timeout_id); + source_data->timeout_id = 0; + } + + source_data->loaded = FALSE; + } +} + +static void +calendar_sources_finalize (GObject *object) +{ + CalendarSources *sources = CALENDAR_SOURCES (object); + + calendar_sources_finalize_source_data (sources, &sources->priv->appointment_sources); + calendar_sources_finalize_source_data (sources, &sources->priv->task_sources); + + if (sources->priv->mateconf_client) + g_object_unref (sources->priv->mateconf_client); + sources->priv->mateconf_client = NULL; + + if (G_OBJECT_CLASS (parent_class)->finalize) + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +CalendarSources * +calendar_sources_get (void) +{ + gpointer singleton_location = &calendar_sources_singleton; + + if (calendar_sources_singleton) + return g_object_ref (calendar_sources_singleton); + + calendar_sources_singleton = g_object_new (CALENDAR_TYPE_SOURCES, NULL); + g_object_add_weak_pointer (G_OBJECT (calendar_sources_singleton), + singleton_location); + + return calendar_sources_singleton; +} + +static gboolean +is_source_selected (ESource *esource, + GSList *selected_sources) +{ + const char *uid; + GSList *l; + + uid = e_source_peek_uid (esource); + + for (l = selected_sources; l; l = l->next) + { + const char *source = l->data; + + if (!strcmp (source, uid)) + return TRUE; + } + + return FALSE; +} + +static char * +auth_func_cb (ECal *ecal, + const char *prompt, + const char *key, + gpointer user_data) +{ + ESource *source; + const gchar *auth_domain; + const gchar *component_name; + + source = e_cal_get_source (ecal); + auth_domain = e_source_get_property (source, "auth-domain"); + component_name = auth_domain ? auth_domain : "Calendar"; + + return e_passwords_get_password (component_name, key); +} + +/* The clients are just created here but not loaded */ +static ECal * +get_ecal_from_source (ESource *esource, + ECalSourceType source_type, + GSList *existing_clients) +{ + ECal *retval; + + if (existing_clients) + { + GSList *l; + + for (l = existing_clients; l; l = l->next) + { + ECal *client = E_CAL (l->data); + + if (e_source_equal (esource, e_cal_get_source (client))) + { + dprintf (" load_esource: found existing source ... returning that\n"); + + return g_object_ref (client); + } + } + } + + retval = e_cal_new (esource, source_type); + if (!retval) + { + g_warning ("Could not load source '%s' from '%s'\n", + e_source_peek_name (esource), + e_source_peek_relative_uri (esource)); + return NULL; + } + + e_cal_set_auth_func (retval, auth_func_cb, NULL); + + return retval; +} + +/* - Order doesn't matter + * - Can just compare object pointers since we + * re-use client connections + */ +static gboolean +compare_ecal_lists (GSList *a, + GSList *b) +{ + GSList *l; + + if (g_slist_length (a) != g_slist_length (b)) + return FALSE; + + for (l = a; l; l = l->next) + { + if (!g_slist_find (b, l->data)) + return FALSE; + } + + return TRUE; +} + +static inline void +debug_dump_selected_sources (GSList *selected_sources) +{ +#ifdef CALENDAR_ENABLE_DEBUG + GSList *l; + + dprintf ("Selected sources:\n"); + for (l = selected_sources; l; l = l->next) + { + char *source = l->data; + + dprintf (" %s\n", source); + } + dprintf ("\n"); +#endif +} + +static inline void +debug_dump_ecal_list (GSList *ecal_list) +{ +#ifdef CALENDAR_ENABLE_DEBUG + GSList *l; + + dprintf ("Loaded clients:\n"); + for (l = ecal_list; l; l = l->next) + { + ECal *client = l->data; + ESource *source = e_cal_get_source (client); + + dprintf (" %s %s %s\n", + e_source_peek_uid (source), + e_source_peek_name (source), + e_cal_get_uri (client)); + } +#endif +} + +static void +calendar_sources_load_esource_list (CalendarSourceData *source_data); + +static gboolean +backend_restart (gpointer data) +{ + CalendarSourceData *source_data = data; + + calendar_sources_load_esource_list (source_data); + + source_data->timeout_id = 0; + + return FALSE; +} + +static void +backend_died_cb (ECal *client, CalendarSourceData *source_data) +{ + const char *uristr; + + source_data->clients = g_slist_remove (source_data->clients, client); + if (g_slist_length (source_data->clients) < 1) + { + g_slist_free (source_data->clients); + source_data->clients = NULL; + } + uristr = e_cal_get_uri (client); + g_warning ("The calendar backend for %s has crashed.", uristr); + + if (source_data->timeout_id != 0) + { + g_source_remove (source_data->timeout_id); + source_data->timeout_id = 0; + } + + source_data->timeout_id = g_timeout_add_seconds (2, backend_restart, + source_data); +} + +static void +calendar_sources_load_esource_list (CalendarSourceData *source_data) +{ + GSList *clients = NULL; + GSList *groups, *l; + gboolean emit_signal = FALSE; + + g_return_if_fail (source_data->esource_list != NULL); + + debug_dump_selected_sources (source_data->selected_sources); + + dprintf ("Source groups:\n"); + groups = e_source_list_peek_groups (source_data->esource_list); + for (l = groups; l; l = l->next) + { + GSList *esources, *s; + + dprintf (" %s\n", e_source_group_peek_uid (l->data)); + dprintf (" sources:\n"); + + esources = e_source_group_peek_sources (l->data); + for (s = esources; s; s = s->next) + { + ESource *esource = E_SOURCE (s->data); + ECal *client; + + dprintf (" type = '%s' uid = '%s', name = '%s', relative uri = '%s': \n", + source_data->source_type == E_CAL_SOURCE_TYPE_EVENT ? "appointment" : "task", + e_source_peek_uid (esource), + e_source_peek_name (esource), + e_source_peek_relative_uri (esource)); + + if (is_source_selected (esource, source_data->selected_sources) && + (client = get_ecal_from_source (esource, source_data->source_type, source_data->clients))) + { + clients = g_slist_prepend (clients, client); + } + } + } + dprintf ("\n"); + + if (source_data->loaded && + !compare_ecal_lists (source_data->clients, clients)) + emit_signal = TRUE; + + for (l = source_data->clients; l; l = l->next) + { + g_signal_handlers_disconnect_by_func (G_OBJECT (l->data), + G_CALLBACK (backend_died_cb), + source_data); + + g_object_unref (l->data); + } + g_slist_free (source_data->clients); + source_data->clients = g_slist_reverse (clients); + + /* connect to backend_died after we disconnected the previous signal + * handlers. If we do it before, we'll lose some handlers (for clients that + * were already there before) */ + for (l = source_data->clients; l; l = l->next) + { + g_signal_connect (G_OBJECT (l->data), "backend_died", + G_CALLBACK (backend_died_cb), source_data); + } + + if (emit_signal) + { + dprintf ("Emitting %s-sources-changed signal\n", + source_data->source_type == E_CAL_SOURCE_TYPE_EVENT ? "appointment" : "task"); + g_signal_emit (source_data->sources, source_data->changed_signal, 0); + } + + debug_dump_ecal_list (source_data->clients); +} + +static void +calendar_sources_esource_list_changed (ESourceList *source_list, + CalendarSourceData *source_data) + +{ + dprintf ("ESourceList changed, reloading\n"); + + calendar_sources_load_esource_list (source_data); +} + +static void +calendar_sources_selected_sources_notify (MateConfClient *client, + guint cnx_id, + MateConfEntry *entry, + CalendarSourceData *source_data) +{ + GSList *l; + + if (!entry->value || + entry->value->type != MATECONF_VALUE_LIST || + mateconf_value_get_list_type (entry->value) != MATECONF_VALUE_STRING) + return; + + dprintf ("Selected sources key (%s) changed, reloading\n", entry->key); + + for (l = source_data->selected_sources; l; l = l->next) + g_free (l->data); + source_data->selected_sources = NULL; + + for (l = mateconf_value_get_list (entry->value); l; l = l->next) + { + const char *source = mateconf_value_get_string (l->data); + + source_data->selected_sources = + g_slist_prepend (source_data->selected_sources, + g_strdup (source)); + } + source_data->selected_sources = + g_slist_reverse (source_data->selected_sources); + + calendar_sources_load_esource_list (source_data); +} + +static void +calendar_sources_load_sources (CalendarSources *sources, + CalendarSourceData *source_data, + const char *sources_key, + const char *selected_sources_key, + const char *selected_sources_dir) +{ + MateConfClient *mateconf_client; + GError *error; + + dprintf ("---------------------------\n"); + dprintf ("Loading sources:\n"); + dprintf (" sources_key: %s\n", sources_key); + dprintf (" selected_sources_key: %s\n", selected_sources_key); + dprintf (" selected_sources_dir: %s\n", selected_sources_dir); + + mateconf_client = sources->priv->mateconf_client; + + error = NULL; + source_data->selected_sources = mateconf_client_get_list (mateconf_client, + selected_sources_key, + MATECONF_VALUE_STRING, + &error); + if (error) + { + g_warning ("Failed to get selected sources from '%s': %s\n", + selected_sources_key, + error->message); + g_error_free (error); + return; + } + + mateconf_client_add_dir (mateconf_client, + selected_sources_dir, + MATECONF_CLIENT_PRELOAD_NONE, + NULL); + source_data->selected_sources_dir = g_strdup (selected_sources_dir); + + source_data->selected_sources_listener = + mateconf_client_notify_add (mateconf_client, + selected_sources_dir, + (MateConfClientNotifyFunc) calendar_sources_selected_sources_notify, + source_data, NULL, NULL); + + source_data->esource_list = e_source_list_new_for_mateconf (mateconf_client, sources_key); + g_signal_connect (source_data->esource_list, "changed", + G_CALLBACK (calendar_sources_esource_list_changed), + source_data); + + calendar_sources_load_esource_list (source_data); + + source_data->loaded = TRUE; + + dprintf ("---------------------------\n"); +} + +GSList * +calendar_sources_get_appointment_sources (CalendarSources *sources) +{ + g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL); + + if (!sources->priv->appointment_sources.loaded) + { + calendar_sources_load_sources (sources, + &sources->priv->appointment_sources, + CALENDAR_SOURCES_APPOINTMENT_SOURCES_KEY, + CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_KEY, + CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR); + } + + return sources->priv->appointment_sources.clients; +} + +GSList * +calendar_sources_get_task_sources (CalendarSources *sources) +{ + g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL); + + if (!sources->priv->task_sources.loaded) + { + calendar_sources_load_sources (sources, + &sources->priv->task_sources, + CALENDAR_SOURCES_TASK_SOURCES_KEY, + CALENDAR_SOURCES_SELECTED_TASK_SOURCES_KEY, + CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR); + } + + return sources->priv->task_sources.clients; +} diff --git a/applets/clock/calendar-sources.h b/applets/clock/calendar-sources.h new file mode 100644 index 00000000..3f080c55 --- /dev/null +++ b/applets/clock/calendar-sources.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + * William Jon McCann + * Martin Grimme + * Christian Kellner + */ + +#ifndef __CALENDAR_SOURCES_H__ +#define __CALENDAR_SOURCES_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CALENDAR_TYPE_SOURCES (calendar_sources_get_type ()) +#define CALENDAR_SOURCES(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CALENDAR_TYPE_SOURCES, CalendarSources)) +#define CALENDAR_SOURCES_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CALENDAR_TYPE_SOURCES, CalendarSourcesClass)) +#define CALENDAR_IS_SOURCES(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CALENDAR_TYPE_SOURCES)) +#define CALENDAR_IS_SOURCES_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CALENDAR_TYPE_SOURCES)) +#define CALENDAR_SOURCES_GET_CLASS(o)(G_TYPE_INSTANCE_GET_CLASS ((o), CALENDAR_TYPE_SOURCES, CalendarSourcesClass)) + +typedef struct _CalendarSources CalendarSources; +typedef struct _CalendarSourcesClass CalendarSourcesClass; +typedef struct _CalendarSourcesPrivate CalendarSourcesPrivate; + +struct _CalendarSources +{ + GObject parent; + CalendarSourcesPrivate *priv; +}; + +struct _CalendarSourcesClass +{ + GObjectClass parent_class; + + void (* appointment_sources_changed) (CalendarSources *sources); + void (* task_sources_changed) (CalendarSources *sources); +}; + + +GType calendar_sources_get_type (void) G_GNUC_CONST; +CalendarSources *calendar_sources_get (void); +GSList *calendar_sources_get_appointment_sources (CalendarSources *sources); +GSList *calendar_sources_get_task_sources (CalendarSources *sources); + +#ifdef __cplusplus +} +#endif + +#endif /* __CALENDAR_SOURCES_H__ */ diff --git a/applets/clock/calendar-window.c b/applets/clock/calendar-window.c new file mode 100644 index 00000000..d675f492 --- /dev/null +++ b/applets/clock/calendar-window.c @@ -0,0 +1,2125 @@ +/* + * calendar-window.c: toplevel window containing a calendar and + * tasks/appointments + * + * Copyright (C) 2007 Vincent Untz + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + * + * Most of the original code comes from clock.c + */ + + /* + * Evolution calendar integration TODO: + * + Fix treeview scrolling and sizing + * + Tooltips for tasks/appointments + * + Do everything backwards if the clock is on the bottom + * + Double clicking appointments/tasks should open them in evo + * + Consider using different colours for different sources + * + Consider doing a GtkMenu tearoff type thing + */ + +#include + +#include + +#include +#include + +#define MATE_DESKTOP_USE_UNSTABLE_API +#include + +#include "calendar-window.h" + +#include "clock.h" +#include "clock-utils.h" +#include "clock-typebuiltins.h" +#ifdef HAVE_LIBECAL +#include "calendar-client.h" +#endif + +#define CALENDAR_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CALENDAR_TYPE_WINDOW, CalendarWindowPrivate)) + +#define KEY_LOCATIONS_EXPANDED "expand_locations" +#ifdef HAVE_LIBECAL +/* For the following value, take into account the KEY_* that are not inside this #ifdef! */ +# define N_CALENDAR_WINDOW_MATECONF_PREFS 5 +# define KEY_APPOINTMENTS_EXPANDED "expand_appointments" +# define KEY_BIRTHDAYS_EXPANDED "expand_birthdays" +# define KEY_TASKS_EXPANDED "expand_tasks" +# define KEY_WEATHER_EXPANDED "expand_weather" + +# define KEY_CALENDAR_APP "/desktop/mate/applications/calendar" +# define KEY_TASKS_APP "/desktop/mate/applications/tasks" +#else +# define N_CALENDAR_WINDOW_MATECONF_PREFS 1 +#endif + +enum { + EDIT_LOCATIONS, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +struct _CalendarWindowPrivate { + GtkWidget *calendar; + + char *prefs_dir; + + gboolean invert_order; + gboolean show_weeks; + time_t *current_time; + + GtkWidget *locations_list; + +#ifdef HAVE_LIBECAL + ClockFormat time_format; + + CalendarClient *client; + + GtkWidget *appointment_list; + GtkWidget *birthday_list; + GtkWidget *weather_list; + GtkWidget *task_list; + + GtkListStore *appointments_model; + GtkListStore *tasks_model; + + GtkTreeSelection *previous_selection; + + GtkTreeModelFilter *appointments_filter; + GtkTreeModelFilter *birthdays_filter; + GtkTreeModelFilter *tasks_filter; + GtkTreeModelFilter *weather_filter; + + MateConfClient *mateconfclient; +#endif /* HAVE_LIBECAL */ +}; + +G_DEFINE_TYPE (CalendarWindow, calendar_window, GTK_TYPE_WINDOW) + +enum { + PROP_0, + PROP_INVERTORDER, + PROP_SHOWWEEKS, +#ifdef HAVE_LIBECAL + PROP_TIMEFORMAT, +#endif + PROP_CURRENTTIMEP, + PROP_PREFSDIR +}; + +static time_t *calendar_window_get_current_time_p (CalendarWindow *calwin); +static void calendar_window_set_current_time_p (CalendarWindow *calwin, + time_t *current_time); +static const char *calendar_window_get_prefs_dir (CalendarWindow *calwin); +static void calendar_window_set_prefs_dir (CalendarWindow *calwin, + const char *prefs_dir); +static GtkWidget * create_hig_frame (CalendarWindow *calwin, + const char *title, + const char *button_label, + const char *key, + GCallback callback); + +#ifdef HAVE_LIBECAL + +static void +clock_launch_calendar_tasks_app (CalendarWindow *calwin, + const char *key_program, + const char *argument) +{ + char **argv; + int argc; + char *key; + char *program; + gboolean terminal; + char *command_line; + GdkScreen *screen; + GError *error; + gboolean result; + + key = g_strdup_printf ("%s%s", key_program, "/exec"); + program = mateconf_client_get_string (calwin->priv->mateconfclient, + key, NULL); + g_free (key); + + key = g_strdup_printf ("%s%s", key_program, "/needs_term"); + terminal = mateconf_client_get_bool (calwin->priv->mateconfclient, + key, NULL); + g_free (key); + + if (program == NULL) { + g_printerr ("Cannot launch calendar/tasks application: key not set\n"); + return; + } + + command_line = g_find_program_in_path (program); + if (command_line == NULL) { + g_printerr ("Cannot launch calendar/tasks application: %s in path\n", program); + g_free (program); + return; + } + g_free (command_line); + + if (argument) { + argc = 2; + argv = g_new0 (char *, 3); + argv[1] = g_strdup (argument); + } else { + argc = 1; + argv = g_new0 (char *, 2); + } + argv[0] = program; /* no strdup, and it will get freed for free */ + + screen = gtk_widget_get_screen (calwin->priv->calendar); + error = NULL; + + if (terminal) + mate_desktop_prepend_terminal_to_vector (&argc, &argv); + + result = gdk_spawn_on_screen (screen, + NULL, /* working directory */ + argv, + NULL, /* envp */ + G_SPAWN_SEARCH_PATH, + NULL, /* child setup func */ + NULL, /* user data */ + NULL, /* child pid */ + &error); + + if (!result) { + g_printerr ("Cannot launch calendar/tasks application: %s\n", + error->message); + g_error_free (error); + } + + g_strfreev (argv); +} + +static void +clock_launch_calendar_app (CalendarWindow *calwin, + const char *argument) +{ + clock_launch_calendar_tasks_app (calwin, KEY_CALENDAR_APP, argument); +} + +static void +clock_launch_tasks_app (CalendarWindow *calwin, + const char *argument) +{ + clock_launch_calendar_tasks_app (calwin, KEY_TASKS_APP, argument); +} + +static void +update_frame_visibility (GtkWidget *frame, + GtkTreeModel *model) +{ + GtkTreeIter iter; + gboolean model_empty; + + if (!frame) + return; + + model_empty = !gtk_tree_model_get_iter_first (model, &iter); + + if (model_empty) + gtk_widget_hide (frame); + else + gtk_widget_show (frame); +} + +enum { + APPOINTMENT_COLUMN_UID, + APPOINTMENT_COLUMN_URI, + APPOINTMENT_COLUMN_SUMMARY, + APPOINTMENT_COLUMN_DESCRIPTION, + APPOINTMENT_COLUMN_START_TIME, + APPOINTMENT_COLUMN_START_TEXT, + APPOINTMENT_COLUMN_END_TIME, + APPOINTMENT_COLUMN_ALL_DAY, + APPOINTMENT_COLUMN_PIXBUF, + N_APPOINTMENT_COLUMNS +}; + +enum { + TASK_COLUMN_UID, + TASK_COLUMN_SUMMARY, + TASK_COLUMN_DESCRIPTION, + TASK_COLUMN_START_TIME, + TASK_COLUMN_DUE_TIME, + TASK_COLUMN_PERCENT_COMPLETE, + TASK_COLUMN_PERCENT_COMPLETE_TEXT, + TASK_COLUMN_COMPLETED, + TASK_COLUMN_COMPLETED_TIME, + TASK_COLUMN_OVERDUE_ATTR, + TASK_COLUMN_COLOR, + TASK_COLUMN_PRIORITY, + N_TASK_COLUMNS +}; + +static char * +format_time (ClockFormat format, + time_t t, + guint year, + guint month, + guint day) +{ + struct tm *tm; + char *time_format; + char result [256] = { 0, }; + + if (!t) + return NULL; + + tm = localtime (&t); + if (!tm) + return NULL; + + if (year == (tm->tm_year + 1900) && + month == tm->tm_mon && + day == tm->tm_mday) { + if (format == CLOCK_FORMAT_12) + /* Translators: This is a strftime format string. + * It is used to display the time in 12-hours format + * (eg, like in the US: 8:10 am). The %p expands to + * am/pm. */ + time_format = g_locale_from_utf8 (_("%l:%M %p"), -1, NULL, NULL, NULL); + else + /* Translators: This is a strftime format string. + * It is used to display the time in 24-hours format + * (eg, like in France: 20:10). */ + time_format = g_locale_from_utf8 (_("%H:%M"), -1, NULL, NULL, NULL); + } + else { + /* Translators: This is a strftime format string. + * It is used to display the start date of an appointment, in + * the most abbreviated way possible. */ + time_format = g_locale_from_utf8 (_("%b %d"), -1, NULL, NULL, NULL); + } + + strftime (result, sizeof (result), time_format, tm); + g_free (time_format); + + return g_locale_to_utf8 (result, -1, NULL, NULL, NULL); +} + +static void +handle_tasks_changed (CalendarWindow *calwin) +{ + GSList *events, *l; + + gtk_list_store_clear (calwin->priv->tasks_model); + + events = calendar_client_get_events (calwin->priv->client, + CALENDAR_EVENT_TASK); + for (l = events; l; l = l->next) { + CalendarTask *task = l->data; + GtkTreeIter iter; + char *percent_complete_text; + + g_assert (CALENDAR_EVENT (task)->type == CALENDAR_EVENT_TASK); + + /* FIXME: should this format be locale specific ? */ + percent_complete_text = g_strdup_printf ("%d%%", task->percent_complete); + + gtk_list_store_append (calwin->priv->tasks_model, &iter); + gtk_list_store_set (calwin->priv->tasks_model, &iter, + TASK_COLUMN_UID, task->uid, + TASK_COLUMN_SUMMARY, task->summary, + TASK_COLUMN_DESCRIPTION, task->description, + TASK_COLUMN_START_TIME, (gint64)task->start_time, + TASK_COLUMN_DUE_TIME, (gint64)task->due_time, + TASK_COLUMN_PERCENT_COMPLETE, task->percent_complete, + TASK_COLUMN_PERCENT_COMPLETE_TEXT, percent_complete_text, + TASK_COLUMN_COMPLETED, task->percent_complete == 100, + TASK_COLUMN_COMPLETED_TIME, (gint64)task->completed_time, + TASK_COLUMN_COLOR, task->color_string, + TASK_COLUMN_PRIORITY, task->priority, + -1); + + g_free (percent_complete_text); + calendar_event_free (CALENDAR_EVENT (task)); + } + g_slist_free (events); + + update_frame_visibility (calwin->priv->task_list, + GTK_TREE_MODEL (calwin->priv->tasks_filter)); +} + +static void +handle_task_completed_toggled (CalendarWindow *calwin, + const char *path_str, + GtkCellRendererToggle *cell) +{ + GtkTreePath *child_path, *path; + GtkTreeIter iter; + char *uid; + gboolean task_completed; + guint percent_complete; + + path = gtk_tree_path_new_from_string (path_str); + child_path = gtk_tree_model_filter_convert_path_to_child_path (calwin->priv->tasks_filter, path); + gtk_tree_model_get_iter (GTK_TREE_MODEL (calwin->priv->tasks_model), + &iter, child_path); + gtk_tree_model_get (GTK_TREE_MODEL (calwin->priv->tasks_model), + &iter, + TASK_COLUMN_UID, &uid, + TASK_COLUMN_COMPLETED, &task_completed, + TASK_COLUMN_PERCENT_COMPLETE, &percent_complete, + -1); + + task_completed = !task_completed; + percent_complete = task_completed ? 100 : 0; + + calendar_client_set_task_completed (calwin->priv->client, + uid, + task_completed, + percent_complete); + + g_free (uid); + gtk_tree_path_free (path); + gtk_tree_path_free (child_path); +} + +static void +handle_task_percent_complete_edited (CalendarWindow *calwin, + const char *path_str, + const char *text, + GtkCellRendererText *cell) +{ + GtkTreePath *child_path, *path; + GtkTreeIter iter; + char *uid; + int percent_complete; + char *error = NULL, *text_copy; + + path = gtk_tree_path_new_from_string (path_str); + child_path = gtk_tree_model_filter_convert_path_to_child_path (calwin->priv->tasks_filter, path); + gtk_tree_model_get_iter (GTK_TREE_MODEL (calwin->priv->tasks_model), + &iter, child_path); + gtk_tree_model_get (GTK_TREE_MODEL (calwin->priv->tasks_model), + &iter, TASK_COLUMN_UID, &uid, + -1); + + text_copy = g_strdup (text); + text_copy = g_strdelimit (text_copy, "%", ' '); + text_copy = g_strstrip (text_copy); + percent_complete = (int) g_strtod (text_copy, &error); + if (!error || !error [0]) { + gboolean task_completed; + + percent_complete = CLAMP (percent_complete, 0, 100); + task_completed = (percent_complete == 100); + + calendar_client_set_task_completed (calwin->priv->client, + uid, + task_completed, + percent_complete); + } + + g_free (uid); + g_free (text_copy); + gtk_tree_path_free (path); + gtk_tree_path_free (child_path); +} + +static gboolean +is_appointment (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *uri; + + gtk_tree_model_get (model, iter, APPOINTMENT_COLUMN_URI, &uri, -1); + if (uri) + return (g_ascii_strcasecmp (uri, "file") == 0 || + g_ascii_strcasecmp (uri, "webcal") == 0 || + g_ascii_strcasecmp (uri, "caldav") == 0 || + g_ascii_strcasecmp (uri, "exchange") == 0 || + g_ascii_strcasecmp (uri, "groupwise") == 0 || + g_ascii_strcasecmp (uri, "google") == 0); + return FALSE; +} + +static gboolean +is_birthday (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *uri; + + gtk_tree_model_get (model, iter, APPOINTMENT_COLUMN_URI, &uri, -1); + if (uri) + return (g_ascii_strcasecmp (uri, "contacts") == 0); + return FALSE; +} + +static gboolean +is_weather (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *uri; + + gtk_tree_model_get (model, iter, APPOINTMENT_COLUMN_URI, &uri, -1); + if (uri) + return (g_ascii_strcasecmp (uri, "weather") == 0); + return FALSE; +} + +static gboolean +filter_out_tasks (GtkTreeModel *model, + GtkTreeIter *iter, + CalendarWindow *calwin) +{ + gint64 start_time64; + gint64 completed_time64; + time_t start_time; + time_t completed_time; + time_t one_day_ago; + gboolean visible; + + gtk_tree_model_get (model, iter, + TASK_COLUMN_START_TIME, &start_time64, + TASK_COLUMN_COMPLETED_TIME, &completed_time64, + -1); + start_time = start_time64; + completed_time = completed_time64; + + one_day_ago = *(calwin->priv->current_time) - (24 * 60 * 60); + + visible = !start_time || start_time <= *(calwin->priv->current_time); + if (visible) + visible = !completed_time || completed_time >= one_day_ago; + + return visible; +} + +static void +modify_task_text_attributes (GtkTreeModel *model, + GtkTreeIter *iter, + GValue *value, + gint column, + CalendarWindow *calwin) +{ + gint64 due_time64; + time_t due_time; + PangoAttrList *attr_list; + PangoAttribute *attr; + GtkTreeIter child_iter; + + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + iter); + + if (column != TASK_COLUMN_OVERDUE_ATTR) { + memset (value, 0, sizeof (GValue)); + gtk_tree_model_get_value (GTK_TREE_MODEL (calwin->priv->tasks_model), + &child_iter, column, value); + + return; + } + + gtk_tree_model_get (GTK_TREE_MODEL (calwin->priv->tasks_model), + &child_iter, TASK_COLUMN_DUE_TIME, &due_time64, + -1); + due_time = due_time64; + + if (due_time && due_time > *(calwin->priv->current_time)) + return; + + attr_list = pango_attr_list_new (); + + attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD); + attr->start_index = 0; + attr->end_index = G_MAXINT; + pango_attr_list_insert (attr_list, attr); + + g_value_take_boxed (value, attr_list); +} + +static gboolean +task_activated_cb (GtkTreeView *view, + GtkTreePath *path, + GtkTreeViewColumn *column, + CalendarWindow *calwin) +{ + GtkTreeIter iter; + GtkTreePath *child_path; + char *uid; + char *argument; + + child_path = gtk_tree_model_filter_convert_path_to_child_path (calwin->priv->tasks_filter, + path); + + gtk_tree_model_get_iter (GTK_TREE_MODEL (calwin->priv->tasks_model), + &iter, child_path); + gtk_tree_model_get (GTK_TREE_MODEL (calwin->priv->tasks_model), + &iter, TASK_COLUMN_UID, &uid, -1); + + argument = g_strdup_printf ("task:%s", uid); + + clock_launch_tasks_app (calwin, argument); + + g_free (argument); + g_free (uid); + gtk_tree_path_free (child_path); + + return TRUE; +} + +static void +set_renderer_pixbuf_color_by_column (GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + gint column_number) +{ + char *color_string; + GdkPixbuf *pixbuf = NULL; + GdkColor color; + + gtk_tree_model_get (model, iter, column_number, &color_string, -1); + + if (color_string && gdk_color_parse (color_string, &color)) { + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 16, 16); + /* GdkColor has 16 bits per color, gdk_pixbuf only uses 8 bits + * per color. So just drop the least significant parts */ + gdk_pixbuf_fill (pixbuf, + (color.red & 0xff00) << 16 | + (color.green & 0xff00) << 8 | + (color.blue & 0xff00)); + + g_object_set (renderer, "visible", pixbuf != NULL, "pixbuf", pixbuf, NULL); + + if (pixbuf) + g_object_unref (pixbuf); + + g_free (color_string); + } +} + +static void +set_renderer_pixbuf_pixmap (GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + const char *iconpath) +{ + GdkPixbuf *pixbuf = NULL; + GError *error = NULL; + + if (!g_file_test (iconpath, G_FILE_TEST_IS_REGULAR)) { + g_printerr ("File '%s' does not exist.\n", iconpath); + return; + } + + pixbuf = gdk_pixbuf_new_from_file (iconpath, &error); + if (error) { + g_printerr ("Cannot load '%s': %s\n", + iconpath, error->message); + g_error_free (error); + return; + } + + g_object_set (renderer, + "visible", pixbuf != NULL, + "pixbuf", pixbuf, + NULL); + + if (pixbuf) + g_object_unref (pixbuf); +} + +static void +set_renderer_pixbuf_pixmap_for_bday (GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + gint data_column) +{ + const gchar *path = NULL; + gchar *type = NULL; + + gtk_tree_model_get (model, iter, data_column, &type, -1); + if (!type) + return; + + /* type should be in format like this: + * pas-id-4121A93E00000001-anniversary + * pas-id-41112AF900000003-birthday + * ... + */ + if (g_strrstr (type, "birthday") != NULL) + path = CLOCK_EDS_ICONDIR G_DIR_SEPARATOR_S "category_birthday_16.png"; + else if (g_strrstr (type, "anniversary") != NULL) + path = CLOCK_EDS_ICONDIR G_DIR_SEPARATOR_S "category_gifts_16.png"; + else + path = CLOCK_EDS_ICONDIR G_DIR_SEPARATOR_S "category_miscellaneous_16.png"; + + g_free (type); + + set_renderer_pixbuf_pixmap (renderer, model, iter, path); +} + +static void +set_renderer_pixbuf_pixmap_for_weather (GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter) +{ + set_renderer_pixbuf_pixmap (renderer, model, iter, + CLOCK_EDS_ICONDIR G_DIR_SEPARATOR_S "category_holiday_16.png"); +} + +static void +task_pixbuf_cell_data_func (GtkTreeViewColumn *column, + GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + set_renderer_pixbuf_color_by_column (renderer, + model, + iter, + TASK_COLUMN_COLOR); +} + +static void +appointment_pixbuf_cell_data_func (GtkTreeViewColumn *column, + GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + set_renderer_pixbuf_color_by_column (renderer, + model, + iter, + APPOINTMENT_COLUMN_PIXBUF); +} +static void +birthday_pixbuf_cell_data_func (GtkTreeViewColumn *column, + GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + + /* APPOINTMENT_COLUMN_UID contains data to select between + * anniversary or birthday + */ + set_renderer_pixbuf_pixmap_for_bday (renderer, + model, + iter, + APPOINTMENT_COLUMN_UID); +} +static void +weather_pixbuf_cell_data_func (GtkTreeViewColumn *column, + GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + + set_renderer_pixbuf_pixmap_for_weather (renderer, + model, + iter); +} + +static int +compare_tasks (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer user_data) +{ + gboolean done_a, done_b; + int priority_a, priority_b; + + gtk_tree_model_get (model, a, + TASK_COLUMN_COMPLETED, &done_a, + TASK_COLUMN_PRIORITY, &priority_a, + -1); + gtk_tree_model_get (model, b, + TASK_COLUMN_COMPLETED, &done_b, + TASK_COLUMN_PRIORITY, &priority_b, + -1); + + /* Always sort completed tasks last */ + if (done_a != done_b) + return done_a ? -1 : 1; + + /* We change undefined priorities so they appear as "Normal" */ + if (priority_a <= 0) + priority_a = 5; + if (priority_b <= 0) + priority_b = 5; + + /* We'll just use the ordering of the priority values. */ + if (priority_a < priority_b) + return -1; + else if (priority_a > priority_b) + return 1; + else { + gint64 due_time_a64, due_time_b64; + time_t due_time_a, due_time_b; + + gtk_tree_model_get (model, a, + TASK_COLUMN_DUE_TIME, &due_time_a64, -1); + gtk_tree_model_get (model, b, + TASK_COLUMN_DUE_TIME, &due_time_b64, -1); + due_time_a = due_time_a64; + due_time_b = due_time_b64; + + if (due_time_a < due_time_b) + return -1; + else if (due_time_a > due_time_b) + return 1; + else { + char *summary_a, *summary_b; + int res; + + gtk_tree_model_get (model, a, TASK_COLUMN_SUMMARY, &summary_a, -1); + gtk_tree_model_get (model, b, TASK_COLUMN_SUMMARY, &summary_b, -1); + + res = g_utf8_collate (summary_a ? summary_a: "", + summary_b ? summary_b: ""); + + g_free (summary_a); + g_free (summary_b); + + return res; + } + } +} + +static void +calendar_window_tree_selection_changed (GtkTreeSelection *selection, + CalendarWindow *calwin) +{ + if (selection == calwin->priv->previous_selection) + return; + + if (calwin->priv->previous_selection) { + g_signal_handlers_block_by_func (calwin->priv->previous_selection, + calendar_window_tree_selection_changed, + calwin); + gtk_tree_selection_unselect_all (calwin->priv->previous_selection); + g_signal_handlers_unblock_by_func (calwin->priv->previous_selection, + calendar_window_tree_selection_changed, + calwin); + } + + calwin->priv->previous_selection = selection; +} + +static void +edit_tasks (CalendarWindow *calwin) +{ + clock_launch_tasks_app (calwin, NULL); +} + +static GtkWidget * +create_task_list (CalendarWindow *calwin, + GtkWidget **tree_view, + GtkWidget **scrolled_window) +{ + GtkWidget *list; + GtkWidget *view; + GtkWidget *scrolled; + GtkCellRenderer *cell; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + + list = create_hig_frame (calwin, + _("Tasks"), _("Edit"), + KEY_TASKS_EXPANDED, + G_CALLBACK (edit_tasks)); + + *scrolled_window = scrolled = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), + GTK_SHADOW_IN); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + /* we show the widget before adding to the container, since adding to + * the container changes the visibility depending on the state of the + * expander */ + gtk_widget_show (scrolled); + gtk_container_add (GTK_CONTAINER (list), scrolled); + + g_assert (calwin->priv->tasks_model != NULL); + + *tree_view = view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (calwin->priv->tasks_filter)); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE); + + g_signal_connect (view, "row-activated", + G_CALLBACK (task_activated_cb), calwin); + + /* Source color */ + column = gtk_tree_view_column_new (); + cell = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_set_cell_data_func (column, cell, + (GtkTreeCellDataFunc) task_pixbuf_cell_data_func, + NULL, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); + + /* Completed toggle */ + column = gtk_tree_view_column_new (); + cell = gtk_cell_renderer_toggle_new (); + g_object_set (cell, + "activatable", TRUE, + NULL); + g_signal_connect_swapped (cell, "toggled", + G_CALLBACK (handle_task_completed_toggled), + calwin); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_add_attribute (column, cell, + "active", TASK_COLUMN_COMPLETED); + gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); + + /* Percent complete */ + column = gtk_tree_view_column_new (); + cell = gtk_cell_renderer_text_new (); + g_object_set (cell, + "editable", TRUE, + NULL); + g_signal_connect_swapped (cell, "edited", + G_CALLBACK (handle_task_percent_complete_edited), + calwin); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_add_attribute (column, cell, + "text", TASK_COLUMN_PERCENT_COMPLETE_TEXT); + gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); + + /* Summary */ + column = gtk_tree_view_column_new (); + cell = gtk_cell_renderer_text_new (); + g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_set_attributes (column, cell, + "text", TASK_COLUMN_SUMMARY, + "strikethrough", TASK_COLUMN_COMPLETED, + "attributes", TASK_COLUMN_OVERDUE_ATTR, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); + g_signal_connect (selection, "changed", + G_CALLBACK (calendar_window_tree_selection_changed), + calwin); + + gtk_container_add (GTK_CONTAINER (scrolled), view); + + gtk_widget_show (view); + + return list; +} + +static void +mark_day_on_calendar (CalendarClient *client, + guint day, + CalendarWindow *calwin) +{ + gtk_calendar_mark_day (GTK_CALENDAR (calwin->priv->calendar), day); +} + +static void +handle_appointments_changed (CalendarWindow *calwin) +{ + GSList *events, *l; + guint year, month, day; + + if (calwin->priv->calendar) { + gtk_calendar_clear_marks (GTK_CALENDAR (calwin->priv->calendar)); + + calendar_client_foreach_appointment_day (calwin->priv->client, + (CalendarDayIter) mark_day_on_calendar, + calwin); + } + + gtk_list_store_clear (calwin->priv->appointments_model); + + calendar_client_get_date (calwin->priv->client, &year, &month, &day); + + events = calendar_client_get_events (calwin->priv->client, + CALENDAR_EVENT_APPOINTMENT); + for (l = events; l; l = l->next) { + CalendarAppointment *appointment = l->data; + GtkTreeIter iter; + char *start_text; + + g_assert (CALENDAR_EVENT (appointment)->type == CALENDAR_EVENT_APPOINTMENT); + + if (appointment->is_all_day) + start_text = g_strdup (_("All Day")); + else + start_text = format_time (calwin->priv->time_format, + appointment->start_time, + year, month, day); + + + gtk_list_store_append (calwin->priv->appointments_model, + &iter); + gtk_list_store_set (calwin->priv->appointments_model, &iter, + APPOINTMENT_COLUMN_UID, appointment->uid, + APPOINTMENT_COLUMN_URI, appointment->uri, + APPOINTMENT_COLUMN_SUMMARY, appointment->summary, + APPOINTMENT_COLUMN_DESCRIPTION, appointment->description, + APPOINTMENT_COLUMN_START_TIME, (gint64)appointment->start_time, + APPOINTMENT_COLUMN_START_TEXT, start_text, + APPOINTMENT_COLUMN_END_TIME, (gint64)appointment->end_time, + APPOINTMENT_COLUMN_ALL_DAY, appointment->is_all_day, + APPOINTMENT_COLUMN_PIXBUF, appointment->color_string, + -1); + + g_free (start_text); + calendar_event_free (CALENDAR_EVENT (appointment)); + } + g_slist_free (events); + + update_frame_visibility (calwin->priv->appointment_list, + GTK_TREE_MODEL (calwin->priv->appointments_filter)); + update_frame_visibility (calwin->priv->birthday_list, + GTK_TREE_MODEL (calwin->priv->birthdays_filter)); + update_frame_visibility (calwin->priv->weather_list, + GTK_TREE_MODEL (calwin->priv->weather_filter)); +} + +static GtkWidget * +create_list_for_appointment_model (CalendarWindow *calwin, + const char *label, + GtkTreeModelFilter **filter, + GtkTreeModelFilterVisibleFunc is_for_filter, + GtkTreeCellDataFunc set_pixbuf_cell, + gboolean show_start, + GtkWidget **tree_view, + GtkWidget **scrolled_window, + const char *key, + GCallback callback) +{ + GtkWidget *list; + GtkWidget *view; + GtkWidget *scrolled; + GtkCellRenderer *cell; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + + + list = create_hig_frame (calwin, label, _("Edit"), key, callback); + + *scrolled_window = scrolled = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), + GTK_SHADOW_IN); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + /* we show the widget before adding to the container, since adding to + * the container changes the visibility depending on the state of the + * expander */ + gtk_widget_show (scrolled); + gtk_container_add (GTK_CONTAINER (list), scrolled); + + g_assert (calwin->priv->appointments_model != NULL); + + if (!*filter) { + *filter = + GTK_TREE_MODEL_FILTER ( + gtk_tree_model_filter_new (GTK_TREE_MODEL (calwin->priv->appointments_model), + NULL)); + gtk_tree_model_filter_set_visible_func ( + *filter, + (GtkTreeModelFilterVisibleFunc) is_for_filter, + calwin, + NULL); + } + + *tree_view = view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (*filter)); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE); + + /* Icon */ + column = gtk_tree_view_column_new (); + cell = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_set_cell_data_func (column, cell, + (GtkTreeCellDataFunc) set_pixbuf_cell, + NULL, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); + + if (show_start) { + /* Start time */ + column = gtk_tree_view_column_new (); + cell = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_add_attribute (column, cell, + "text", APPOINTMENT_COLUMN_START_TEXT); + gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); + } + + /* Summary */ + column = gtk_tree_view_column_new (); + cell = gtk_cell_renderer_text_new (); + g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_add_attribute (column, cell, + "text", APPOINTMENT_COLUMN_SUMMARY); + gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); + g_signal_connect (selection, "changed", + G_CALLBACK (calendar_window_tree_selection_changed), + calwin); + + gtk_container_add (GTK_CONTAINER (scrolled), view); + + gtk_widget_show (view); + + return list; +} + +static void +edit_appointments (CalendarWindow *calwin) +{ + clock_launch_calendar_app (calwin, NULL); +} + +static GtkWidget * +create_appointment_list (CalendarWindow *calwin, + GtkWidget **tree_view, + GtkWidget **scrolled_window) +{ + return create_list_for_appointment_model ( + calwin, + _("Appointments"), + &calwin->priv->appointments_filter, + is_appointment, + appointment_pixbuf_cell_data_func, + TRUE, + tree_view, + scrolled_window, + KEY_APPOINTMENTS_EXPANDED, + G_CALLBACK (edit_appointments)); +} + +static void +edit_birthdays (CalendarWindow *calwin) +{ + clock_launch_calendar_app (calwin, NULL); +} + +static GtkWidget * +create_birthday_list (CalendarWindow *calwin, + GtkWidget **tree_view, + GtkWidget **scrolled_window) +{ + /* FIXME: Figure out how to get rid of useless localized message in front of the summary */ + return create_list_for_appointment_model ( + calwin, + _("Birthdays and Anniversaries"), + &calwin->priv->birthdays_filter, + is_birthday, + birthday_pixbuf_cell_data_func, + FALSE, + tree_view, + scrolled_window, + KEY_BIRTHDAYS_EXPANDED, + G_CALLBACK (edit_birthdays)); +} + +static void +edit_weather (CalendarWindow *calwin) +{ + clock_launch_calendar_app (calwin, NULL); +} + + +static GtkWidget * +create_weather_list (CalendarWindow *calwin, + GtkWidget **tree_view, + GtkWidget **scrolled_window) +{ + return create_list_for_appointment_model ( + calwin, + _("Weather Information"), + &calwin->priv->weather_filter, + is_weather, + weather_pixbuf_cell_data_func, + FALSE, + tree_view, + scrolled_window, + KEY_WEATHER_EXPANDED, + G_CALLBACK (edit_weather)); +} + +static void +calendar_window_create_tasks_model (CalendarWindow *calwin) +{ + GType column_types [N_TASK_COLUMNS] = { + G_TYPE_STRING, /* uid */ + G_TYPE_STRING, /* summary */ + G_TYPE_STRING, /* description */ + G_TYPE_INT64, /* start time */ + G_TYPE_INT64, /* due time */ + G_TYPE_UINT, /* percent complete */ + G_TYPE_STRING, /* percent complete text */ + G_TYPE_BOOLEAN, /* completed */ + G_TYPE_INT64, /* completed time */ + PANGO_TYPE_ATTR_LIST, /* summary text attributes */ + G_TYPE_STRING, /* color */ + G_TYPE_INT /* priority */ + }; + + calwin->priv->tasks_model = gtk_list_store_newv (N_TASK_COLUMNS, + column_types); + + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (calwin->priv->tasks_model), + TASK_COLUMN_PRIORITY, + compare_tasks, + NULL, NULL); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (calwin->priv->tasks_model), + TASK_COLUMN_PRIORITY, + GTK_SORT_ASCENDING); + + calwin->priv->tasks_filter = GTK_TREE_MODEL_FILTER ( + gtk_tree_model_filter_new (GTK_TREE_MODEL (calwin->priv->tasks_model), + NULL)); + gtk_tree_model_filter_set_visible_func ( + calwin->priv->tasks_filter, + (GtkTreeModelFilterVisibleFunc) filter_out_tasks, + calwin, + NULL); + gtk_tree_model_filter_set_modify_func ( + calwin->priv->tasks_filter, + N_TASK_COLUMNS, + column_types, + (GtkTreeModelFilterModifyFunc) modify_task_text_attributes, + calwin, + NULL); +} + +static void +calendar_window_create_appointments_model (CalendarWindow *calwin) +{ + calwin->priv->appointments_model = + gtk_list_store_new (N_APPOINTMENT_COLUMNS, + G_TYPE_STRING, /* uid */ + G_TYPE_STRING, /* uri */ + G_TYPE_STRING, /* summary */ + G_TYPE_STRING, /* description */ + G_TYPE_INT64, /* start time */ + G_TYPE_STRING, /* start time text */ + G_TYPE_INT64, /* end time */ + G_TYPE_BOOLEAN, /* all day */ + G_TYPE_STRING); /* color */ + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (calwin->priv->appointments_model), + APPOINTMENT_COLUMN_START_TIME, + GTK_SORT_ASCENDING); +} + +static void +calendar_day_activated (GtkCalendar *calendar, + CalendarWindow *calwin) +{ + unsigned int day; + unsigned int month; + unsigned int year; + time_t date; + struct tm utc_date_tm; + struct tm local_date_tm = { 0, }; + char *argument; + + gtk_calendar_get_date (calendar, &year, &month, &day); + + local_date_tm.tm_mday = (int) day; + local_date_tm.tm_mon = (int) month; + local_date_tm.tm_year = (int) year - 1900; + local_date_tm.tm_isdst = -1; + + /* convert the local date picked in the calendar to broken-down UTC */ + date = mktime (&local_date_tm); + gmtime_r (&date, &utc_date_tm); + + /* FIXME: once bug 409200 is fixed, we'll have to make this hh:mm:ss + * instead of hhmmss */ + argument = g_strdup_printf ("calendar:///?startdate=" + "%.4d%.2d%.2dT%.2d%.2d%.2dZ", + utc_date_tm.tm_year + 1900, + utc_date_tm.tm_mon + 1, + utc_date_tm.tm_mday, + utc_date_tm.tm_hour, + utc_date_tm.tm_min, + 0); + + clock_launch_calendar_app (calwin, argument); + + g_free (argument); +} + +static void +calendar_day_selected (GtkCalendar *calendar, + CalendarWindow *calwin) +{ + guint day; + + gtk_calendar_get_date (calendar, NULL, NULL, &day); + + calendar_client_select_day (calwin->priv->client, day); + + handle_appointments_changed (calwin); + handle_tasks_changed (calwin); +} + +static void +calendar_month_selected (GtkCalendar *calendar, + CalendarWindow *calwin) +{ + guint year, month; + + gtk_calendar_get_date (calendar, &year, &month, NULL); + + calendar_client_select_month (calwin->priv->client, month, year); + + handle_appointments_changed (calwin); + handle_tasks_changed (calwin); +} + +typedef struct +{ + GtkWidget *calendar; + GtkWidget *tree; +} ConstraintData; + +static void +constrain_list_size (GtkWidget *widget, + GtkRequisition *requisition, + ConstraintData *constraint) +{ + GtkRequisition req; + int screen_h; + int max_height; + + /* constrain width to the calendar width */ + gtk_widget_size_request (constraint->calendar, &req); + requisition->width = MIN (requisition->width, req.width); + + screen_h = gdk_screen_get_height (gtk_widget_get_screen (widget)); + /* constrain height to be the tree height up to a max */ + max_height = (screen_h - req.height) / 3; + gtk_widget_size_request (constraint->tree, &req); + + requisition->height = MIN (req.height, max_height); + requisition->height += 2 * gtk_widget_get_style (widget)->ythickness; +} + +static void +setup_list_size_constraint (GtkWidget *widget, + GtkWidget *calendar, + GtkWidget *tree) +{ + ConstraintData *constraint; + + constraint = g_new0 (ConstraintData, 1); + constraint->calendar = calendar; + constraint->tree = tree; + + g_signal_connect_data (widget, "size-request", + G_CALLBACK (constrain_list_size), constraint, + (GClosureNotify) g_free, 0); +} + +static void +expander_activated (GtkExpander *expander, + CalendarWindow *calwin) +{ + const char *key; + + key = (const gchar*)g_object_get_data (G_OBJECT (expander), "mateconf-key"); + + if (mateconf_client_key_is_writable (calwin->priv->mateconfclient, + key, NULL)) { + mateconf_client_set_bool (calwin->priv->mateconfclient, key, + gtk_expander_get_expanded (expander), + NULL); + } +} + +static void +expanded_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + GtkExpander *expander) +{ + gboolean value; + + if (!entry->value || entry->value->type != MATECONF_VALUE_BOOL) + return; + + value = mateconf_value_get_bool (entry->value); + + gtk_expander_set_expanded (expander, value); +} + +static void +remove_listener (gpointer data) +{ + MateConfClient *client; + + client = mateconf_client_get_default (); + mateconf_client_notify_remove (client, GPOINTER_TO_UINT (data)); + g_object_unref (client); +} + +static void +connect_expander_with_mateconf (CalendarWindow *calwin, + GtkWidget *expander, + const char *relative_key) +{ + char *key; + gboolean expanded; + guint listener; + + key = g_strdup_printf ("%s/%s", + calwin->priv->prefs_dir, relative_key); + + g_object_set_data_full (G_OBJECT (expander), "mateconf-key", (gpointer)key, g_free); + + expanded = mateconf_client_get_bool (calwin->priv->mateconfclient, key, + NULL); + gtk_expander_set_expanded (GTK_EXPANDER (expander), expanded); + + g_signal_connect_after (expander, "activate", + G_CALLBACK (expander_activated), + calwin); + + listener = mateconf_client_notify_add ( + calwin->priv->mateconfclient, key, + (MateConfClientNotifyFunc) expanded_changed, + expander, NULL, NULL); + + g_object_set_data_full (G_OBJECT (expander), "listener-id", + GUINT_TO_POINTER (listener), remove_listener); +} +#endif /* HAVE_LIBECAL */ + +static void +calendar_window_pack_pim (CalendarWindow *calwin, + GtkWidget *vbox) +{ +#ifdef HAVE_LIBECAL + GtkWidget *list; + GtkWidget *tree_view; + GtkWidget *scrolled_window; + guint year, month, day; + + calendar_window_create_tasks_model (calwin); + calendar_window_create_appointments_model (calwin); + + list = create_task_list (calwin, &tree_view, &scrolled_window); + setup_list_size_constraint (scrolled_window, + calwin->priv->calendar, tree_view); + update_frame_visibility (list, + GTK_TREE_MODEL (calwin->priv->tasks_model)); + calwin->priv->task_list = list; + + list = create_birthday_list (calwin, &tree_view, &scrolled_window); + setup_list_size_constraint (scrolled_window, + calwin->priv->calendar, tree_view); + update_frame_visibility (list, + GTK_TREE_MODEL (calwin->priv->birthdays_filter)); + calwin->priv->birthday_list = list; + + list = create_weather_list (calwin, &tree_view, &scrolled_window); + setup_list_size_constraint (scrolled_window, + calwin->priv->calendar, tree_view); + update_frame_visibility (list, + GTK_TREE_MODEL (calwin->priv->weather_filter)); + calwin->priv->weather_list = list; + + list = create_appointment_list (calwin, &tree_view, &scrolled_window); + setup_list_size_constraint (scrolled_window, + calwin->priv->calendar, tree_view); + update_frame_visibility (list, + GTK_TREE_MODEL (calwin->priv->appointments_filter)); + calwin->priv->appointment_list = list; + + if (!calwin->priv->invert_order) { + gtk_box_pack_start (GTK_BOX (vbox), + calwin->priv->task_list, + TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (vbox), + calwin->priv->appointment_list, + TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (vbox), + calwin->priv->birthday_list, + TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (vbox), + calwin->priv->weather_list, + TRUE, TRUE, 0); + } else { + gtk_box_pack_start (GTK_BOX (vbox), + calwin->priv->weather_list, + TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (vbox), + calwin->priv->birthday_list, + TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (vbox), + calwin->priv->appointment_list, + TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (vbox), + calwin->priv->task_list, + TRUE, TRUE, 0); + } + + if (!calwin->priv->client) { + calwin->priv->client = calendar_client_new (); + + g_signal_connect_swapped (calwin->priv->client, + "tasks-changed", + G_CALLBACK (handle_tasks_changed), + calwin); + g_signal_connect_swapped (calwin->priv->client, + "appointments-changed", + G_CALLBACK (handle_appointments_changed), + calwin); + } + + gtk_calendar_get_date (GTK_CALENDAR (calwin->priv->calendar), + &year, &month, &day); + + calendar_client_select_day (calwin->priv->client, day); + calendar_client_select_month (calwin->priv->client, month, year); + + handle_tasks_changed (calwin); + handle_appointments_changed (calwin); + + g_signal_connect (calwin->priv->calendar, + "day-selected-double-click", + G_CALLBACK (calendar_day_activated), + calwin); + g_signal_connect (calwin->priv->calendar, + "day-selected", + G_CALLBACK (calendar_day_selected), + calwin); + g_signal_connect (calwin->priv->calendar, + "month-changed", + G_CALLBACK (calendar_month_selected), + calwin); +#endif /* HAVE_LIBECAL */ +} + +static GtkWidget * +calendar_window_create_calendar (CalendarWindow *calwin) +{ + GtkWidget *calendar; + GtkCalendarDisplayOptions options; + struct tm *tm; + + calendar = gtk_calendar_new (); + options = gtk_calendar_get_display_options (GTK_CALENDAR (calendar)); + if (calwin->priv->show_weeks) + options |= GTK_CALENDAR_SHOW_WEEK_NUMBERS; + else + options &= ~(GTK_CALENDAR_SHOW_WEEK_NUMBERS); + gtk_calendar_set_display_options (GTK_CALENDAR (calendar), options); + + tm = localtime (calwin->priv->current_time); + + gtk_calendar_select_month (GTK_CALENDAR (calendar), + tm->tm_mon, + tm->tm_year + 1900); + gtk_calendar_select_day (GTK_CALENDAR (calendar), tm->tm_mday); + + return calendar; +} + +static void +expand_collapse_child (GtkWidget *child, + gpointer data) +{ + gboolean expanded; + + if (data == child || gtk_widget_is_ancestor (data, child)) + return; + + expanded = gtk_expander_get_expanded (GTK_EXPANDER (data)); + g_object_set (child, "visible", expanded, NULL); +} + +static void +expand_collapse (GtkWidget *expander, + GParamSpec *pspec, + gpointer data) +{ + GtkWidget *box = data; + + gtk_container_foreach (GTK_CONTAINER (box), + (GtkCallback)expand_collapse_child, + expander); +} + +static void add_child (GtkContainer *container, + GtkWidget *child, + GtkExpander *expander) +{ + expand_collapse_child (child, expander); +} + +static GtkWidget * +create_hig_frame (CalendarWindow *calwin, + const char *title, + const char *button_label, + const char *key, + GCallback callback) +{ + GtkWidget *vbox; + GtkWidget *alignment; + GtkWidget *label; + GtkWidget *hbox; + GtkWidget *button; + char *bold_title; + char *text; + GtkWidget *expander; + + vbox = gtk_vbox_new (FALSE, 6); + + bold_title = g_strdup_printf ("%s", title); + expander = gtk_expander_new (bold_title); + g_free (bold_title); + gtk_expander_set_use_markup (GTK_EXPANDER (expander), TRUE); + + hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), expander, FALSE, FALSE, 0); + gtk_widget_show_all (vbox); + + g_signal_connect (expander, "notify::expanded", + G_CALLBACK (expand_collapse), hbox); + g_signal_connect (expander, "notify::expanded", + G_CALLBACK (expand_collapse), vbox); + + /* FIXME: this doesn't really work, since "add" does not + * get emitted for e.g. gtk_box_pack_start + */ + g_signal_connect (vbox, "add", G_CALLBACK (add_child), expander); + g_signal_connect (hbox, "add", G_CALLBACK (add_child), expander); + + if (button_label) { + button = gtk_button_new (); + text = g_markup_printf_escaped ("%s", button_label); + label = gtk_label_new (text); + g_free (text); + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + gtk_container_add (GTK_CONTAINER (button), label); + + alignment = gtk_alignment_new (1, 0, 0, 0); + gtk_container_add (GTK_CONTAINER (alignment), button); + gtk_widget_show_all (alignment); + + gtk_container_add (GTK_CONTAINER (hbox), alignment); + + g_signal_connect_swapped (button, "clicked", callback, calwin); + } + +#ifdef HAVE_LIBECAL + connect_expander_with_mateconf (calwin, expander, key); +#endif + + return vbox; +} + +static void +edit_locations (CalendarWindow *calwin) +{ + g_signal_emit (calwin, signals[EDIT_LOCATIONS], 0); +} + +static void +calendar_window_pack_locations (CalendarWindow *calwin, GtkWidget *vbox) +{ + calwin->priv->locations_list = create_hig_frame (calwin, + _("Locations"), _("Edit"), + KEY_LOCATIONS_EXPANDED, + G_CALLBACK (edit_locations)); + + /* we show the widget before adding to the container, since adding to + * the container changes the visibility depending on the state of the + * expander */ + gtk_widget_show (calwin->priv->locations_list); + gtk_container_add (GTK_CONTAINER (vbox), calwin->priv->locations_list); + + //gtk_box_pack_start (GTK_BOX (vbox), calwin->priv->locations_list, TRUE, FALSE, 0); +} + +static void +calendar_window_fill (CalendarWindow *calwin) +{ + GtkWidget *frame; + GtkWidget *vbox; + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); + gtk_container_add (GTK_CONTAINER (calwin), frame); + gtk_widget_show (frame); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 6); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_widget_show (vbox); + + calwin->priv->calendar = calendar_window_create_calendar (calwin); + gtk_widget_show (calwin->priv->calendar); + + if (!calwin->priv->invert_order) { + gtk_box_pack_start (GTK_BOX (vbox), + calwin->priv->calendar, TRUE, FALSE, 0); + calendar_window_pack_pim (calwin, vbox); + calendar_window_pack_locations (calwin, vbox); + } else { + calendar_window_pack_locations (calwin, vbox); + calendar_window_pack_pim (calwin, vbox); + gtk_box_pack_start (GTK_BOX (vbox), + calwin->priv->calendar, TRUE, FALSE, 0); + } +} + +GtkWidget * +calendar_window_get_locations_box (CalendarWindow *calwin) +{ + return calwin->priv->locations_list; +} + +static GObject * +calendar_window_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *obj; + CalendarWindow *calwin; + + obj = G_OBJECT_CLASS (calendar_window_parent_class)->constructor (type, + n_construct_properties, + construct_properties); + + calwin = CALENDAR_WINDOW (obj); + + g_assert (calwin->priv->current_time != NULL); + g_assert (calwin->priv->prefs_dir != NULL); + + calendar_window_fill (calwin); + + return obj; +} + +static void +calendar_window_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + CalendarWindow *calwin; + + g_return_if_fail (CALENDAR_IS_WINDOW (object)); + + calwin = CALENDAR_WINDOW (object); + + switch (prop_id) { + case PROP_INVERTORDER: + g_value_set_boolean (value, + calendar_window_get_invert_order (calwin)); + break; + case PROP_SHOWWEEKS: + g_value_set_boolean (value, + calendar_window_get_show_weeks (calwin)); + break; +#ifdef HAVE_LIBECAL + case PROP_TIMEFORMAT: + g_value_set_enum (value, + calendar_window_get_time_format (calwin)); + break; +#endif + case PROP_CURRENTTIMEP: + g_value_set_pointer (value, + calendar_window_get_current_time_p (calwin)); + break; + case PROP_PREFSDIR: + g_value_set_string (value, + calendar_window_get_prefs_dir (calwin)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +calendar_window_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + CalendarWindow *calwin; + + g_return_if_fail (CALENDAR_IS_WINDOW (object)); + + calwin = CALENDAR_WINDOW (object); + + switch (prop_id) { + case PROP_INVERTORDER: + calendar_window_set_invert_order (calwin, + g_value_get_boolean (value)); + break; + case PROP_SHOWWEEKS: + calendar_window_set_show_weeks (calwin, + g_value_get_boolean (value)); + break; +#ifdef HAVE_LIBECAL + case PROP_TIMEFORMAT: + calendar_window_set_time_format (calwin, + g_value_get_enum (value)); + break; +#endif + case PROP_CURRENTTIMEP: + calendar_window_set_current_time_p (calwin, + g_value_get_pointer (value)); + break; + case PROP_PREFSDIR: + calendar_window_set_prefs_dir (calwin, + g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +calendar_window_destroy (GtkObject *object) +{ +#ifdef HAVE_LIBECAL + CalendarWindow *calwin; + + calwin = CALENDAR_WINDOW (object); + + if (calwin->priv->client) + g_object_unref (calwin->priv->client); + calwin->priv->client = NULL; + + if (calwin->priv->appointments_model) + g_object_unref (calwin->priv->appointments_model); + calwin->priv->appointments_model = NULL; + + if (calwin->priv->tasks_model) + g_object_unref (calwin->priv->tasks_model); + calwin->priv->tasks_model = NULL; + + if (calwin->priv->appointments_filter) + g_object_unref (calwin->priv->appointments_filter); + calwin->priv->appointments_filter = NULL; + + if (calwin->priv->birthdays_filter) + g_object_unref (calwin->priv->birthdays_filter); + calwin->priv->birthdays_filter = NULL; + + if (calwin->priv->tasks_filter) + g_object_unref (calwin->priv->tasks_filter); + calwin->priv->tasks_filter = NULL; + + if (calwin->priv->weather_filter) + g_object_unref (calwin->priv->weather_filter); + calwin->priv->weather_filter = NULL; + + if (calwin->priv->mateconfclient) + g_object_unref (calwin->priv->mateconfclient); + calwin->priv->mateconfclient = NULL; +#endif /* HAVE_LIBECAL */ + + GTK_OBJECT_CLASS (calendar_window_parent_class)->destroy (object); +} + +static void +calendar_window_class_init (CalendarWindowClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS (klass); + + gobject_class->constructor = calendar_window_constructor; + gobject_class->get_property = calendar_window_get_property; + gobject_class->set_property = calendar_window_set_property; + + gtkobject_class->destroy = calendar_window_destroy; + + g_type_class_add_private (klass, sizeof (CalendarWindowPrivate)); + + signals[EDIT_LOCATIONS] = g_signal_new ("edit-locations", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CalendarWindowClass, edit_locations), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_object_class_install_property ( + gobject_class, + PROP_INVERTORDER, + g_param_spec_boolean ("invert-order", + "Invert Order", + "Invert order of the calendar and tree views", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_SHOWWEEKS, + g_param_spec_boolean ("show-weeks", + "Show Weeks", + "Show weeks in the calendar", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + +#ifdef HAVE_LIBECAL + g_object_class_install_property ( + gobject_class, + PROP_TIMEFORMAT, + g_param_spec_enum ("time-format", + "Time Format", + "Time format used to display time", + CLOCK_TYPE_FORMAT, + clock_locale_format (), + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); +#endif + + g_object_class_install_property ( + gobject_class, + PROP_CURRENTTIMEP, + g_param_spec_pointer ("current-time", + "Current Time", + "Pointer to a variable containing the current time", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property ( + gobject_class, + PROP_PREFSDIR, + g_param_spec_string ("prefs-dir", + "Preferences Directory", + "Preferences directory in MateConf", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +calendar_window_init (CalendarWindow *calwin) +{ + GtkWindow *window; + + calwin->priv = CALENDAR_WINDOW_GET_PRIVATE (calwin); + + window = GTK_WINDOW (calwin); + gtk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_DOCK); + gtk_window_set_decorated (window, FALSE); + gtk_window_set_resizable (window, FALSE); + gtk_window_stick (window); + gtk_window_set_title (window, _("Calendar")); + gtk_window_set_icon_name (window, CLOCK_ICON); + +#ifdef HAVE_LIBECAL + calwin->priv->previous_selection = NULL; + calwin->priv->mateconfclient = mateconf_client_get_default (); +#endif +} + +GtkWidget * +calendar_window_new (time_t *static_current_time, + const char *prefs_dir, + gboolean invert_order) +{ + CalendarWindow *calwin; + + calwin = g_object_new (CALENDAR_TYPE_WINDOW, + "type", GTK_WINDOW_TOPLEVEL, + "current-time", static_current_time, + "invert-order", invert_order, + "prefs-dir", prefs_dir, + NULL); + + return GTK_WIDGET (calwin); +} + +void +calendar_window_refresh (CalendarWindow *calwin) +{ + g_return_if_fail (CALENDAR_IS_WINDOW (calwin)); + +#ifdef HAVE_LIBECAL + if (calwin->priv->appointments_filter && calwin->priv->appointment_list) + gtk_tree_model_filter_refilter (calwin->priv->appointments_filter); + if (calwin->priv->birthdays_filter && calwin->priv->birthday_list) + gtk_tree_model_filter_refilter (calwin->priv->birthdays_filter); + if (calwin->priv->tasks_filter && calwin->priv->task_list) + gtk_tree_model_filter_refilter (calwin->priv->tasks_filter); + if (calwin->priv->weather_filter && calwin->priv->weather_list) + gtk_tree_model_filter_refilter (calwin->priv->weather_filter); +#endif +} + +gboolean +calendar_window_get_invert_order (CalendarWindow *calwin) +{ + g_return_val_if_fail (CALENDAR_IS_WINDOW (calwin), FALSE); + + return calwin->priv->invert_order; +} + +void +calendar_window_set_invert_order (CalendarWindow *calwin, + gboolean invert_order) +{ + g_return_if_fail (CALENDAR_IS_WINDOW (calwin)); + + if (invert_order == calwin->priv->invert_order) + return; + + calwin->priv->invert_order = invert_order; + //FIXME: update the order of the content of the window + + g_object_notify (G_OBJECT (calwin), "invert-order"); +} + +gboolean +calendar_window_get_show_weeks (CalendarWindow *calwin) +{ + g_return_val_if_fail (CALENDAR_IS_WINDOW (calwin), FALSE); + + return calwin->priv->show_weeks; +} + +void +calendar_window_set_show_weeks (CalendarWindow *calwin, + gboolean show_weeks) +{ + GtkCalendarDisplayOptions options; + + g_return_if_fail (CALENDAR_IS_WINDOW (calwin)); + + if (show_weeks == calwin->priv->show_weeks) + return; + + calwin->priv->show_weeks = show_weeks; + + if (calwin->priv->calendar) { + options = gtk_calendar_get_display_options (GTK_CALENDAR (calwin->priv->calendar)); + + if (show_weeks) + options |= GTK_CALENDAR_SHOW_WEEK_NUMBERS; + else + options &= ~(GTK_CALENDAR_SHOW_WEEK_NUMBERS); + + gtk_calendar_set_display_options (GTK_CALENDAR (calwin->priv->calendar), + options); + } + + g_object_notify (G_OBJECT (calwin), "show-weeks"); +} + +ClockFormat +calendar_window_get_time_format (CalendarWindow *calwin) +{ + g_return_val_if_fail (CALENDAR_IS_WINDOW (calwin), + CLOCK_FORMAT_INVALID); + +#ifdef HAVE_LIBECAL + return calwin->priv->time_format; +#else + return CLOCK_FORMAT_INVALID; +#endif +} + +void +calendar_window_set_time_format (CalendarWindow *calwin, + ClockFormat time_format) +{ + g_return_if_fail (CALENDAR_IS_WINDOW (calwin)); + +#ifdef HAVE_LIBECAL + if (time_format != CLOCK_FORMAT_12 && time_format != CLOCK_FORMAT_24) + time_format = clock_locale_format (); + + if (time_format == calwin->priv->time_format) + return; + + calwin->priv->time_format = time_format; + /* Time to display for appointments has changed */ + if (calwin->priv->appointments_model) + handle_appointments_changed (calwin); + + g_object_notify (G_OBJECT (calwin), "time-format"); +#endif +} + +static time_t * +calendar_window_get_current_time_p (CalendarWindow *calwin) +{ + g_return_val_if_fail (CALENDAR_IS_WINDOW (calwin), NULL); + + return calwin->priv->current_time; +} + +static void +calendar_window_set_current_time_p (CalendarWindow *calwin, + time_t *current_time) +{ + g_return_if_fail (CALENDAR_IS_WINDOW (calwin)); + + if (current_time == calwin->priv->current_time) + return; + + calwin->priv->current_time = current_time; + + g_object_notify (G_OBJECT (calwin), "current-time"); +} + +static const char * +calendar_window_get_prefs_dir (CalendarWindow *calwin) +{ + g_return_val_if_fail (CALENDAR_IS_WINDOW (calwin), NULL); + + return calwin->priv->prefs_dir; +} + +static void +calendar_window_set_prefs_dir (CalendarWindow *calwin, + const char *prefs_dir) +{ + g_return_if_fail (CALENDAR_IS_WINDOW (calwin)); + + if (!calwin->priv->prefs_dir && (!prefs_dir || !prefs_dir [0])) + return; + + if (calwin->priv->prefs_dir && prefs_dir && prefs_dir [0] && + !strcmp (calwin->priv->prefs_dir, prefs_dir)) + return; + + if (calwin->priv->prefs_dir) + g_free (calwin->priv->prefs_dir); + calwin->priv->prefs_dir = NULL; + + if (prefs_dir && prefs_dir [0]) + calwin->priv->prefs_dir = g_strdup (prefs_dir); + + g_object_notify (G_OBJECT (calwin), "prefs-dir"); +} diff --git a/applets/clock/calendar-window.h b/applets/clock/calendar-window.h new file mode 100644 index 00000000..0b0546c8 --- /dev/null +++ b/applets/clock/calendar-window.h @@ -0,0 +1,84 @@ +/* + * calendar-window.h: toplevel window containing a calendar and + * tasks/appointments + * + * Copyright (C) 2007 Vincent Untz + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + * + * Most of the original code comes from clock.c + */ + +#ifndef CALENDAR_WINDOW_H +#define CALENDAR_WINDOW_H + +#include +#include "clock-utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CALENDAR_TYPE_WINDOW (calendar_window_get_type ()) +#define CALENDAR_WINDOW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CALENDAR_TYPE_WINDOW, CalendarWindow)) +#define CALENDAR_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CALENDAR_TYPE_WINDOW, CalendarWindowClass)) +#define CALENDAR_IS_WINDOW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CALENDAR_TYPE_WINDOW)) +#define CALENDAR_IS_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CALENDAR_TYPE_WINDOW)) +#define CALENDAR_WINDOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CALENDAR_TYPE_WINDOW, CalendarWindowClass)) + +typedef struct _CalendarWindow CalendarWindow; +typedef struct _CalendarWindowClass CalendarWindowClass; +typedef struct _CalendarWindowPrivate CalendarWindowPrivate; + +struct _CalendarWindow { + GtkWindow parent_instance; + + CalendarWindowPrivate *priv; +}; + +struct _CalendarWindowClass { + GtkWindowClass parent_class; + + void (* edit_locations) (CalendarWindow *calwin); +}; + +GType calendar_window_get_type (void) G_GNUC_CONST; +GtkWidget *calendar_window_new (time_t *static_current_time, + const char *prefs_dir, + gboolean invert_order); + +void calendar_window_refresh (CalendarWindow *calwin); + +GtkWidget *calendar_window_get_locations_box (CalendarWindow *calwin); + +gboolean calendar_window_get_invert_order (CalendarWindow *calwin); +void calendar_window_set_invert_order (CalendarWindow *calwin, + gboolean invert_order); +gboolean calendar_window_get_show_weeks (CalendarWindow *calwin); +void calendar_window_set_show_weeks (CalendarWindow *calwin, + gboolean show_weeks); +ClockFormat calendar_window_get_time_format (CalendarWindow *calwin); +void calendar_window_set_time_format (CalendarWindow *calwin, + ClockFormat time_format); + +#ifdef __cplusplus +} +#endif + +#endif /* CALENDAR_WINDOW_H */ diff --git a/applets/clock/clock-face.c b/applets/clock/clock-face.c new file mode 100644 index 00000000..53f0e4f4 --- /dev/null +++ b/applets/clock/clock-face.c @@ -0,0 +1,462 @@ +/** + * clock.c + * + * A GTK+ widget that implements a clock face + * + * (c) 2007, Peter Teichman + * (c) 2005-2006, Davyd Madeley + * + * Authors: + * Davyd Madeley + * Peter Teichman + */ + +#include +#include +#include + +#include + +#include "clock-face.h" +#include "clock-location.h" + +static GHashTable *pixbuf_cache = NULL; + +#define CLOCK_FACE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), INTL_TYPE_CLOCK_FACE, ClockFacePrivate)) + +G_DEFINE_TYPE (ClockFace, clock_face, GTK_TYPE_WIDGET) + +static void clock_face_finalize (GObject *); +static gboolean clock_face_expose (GtkWidget *clock, GdkEventExpose *event); +static void clock_face_size_request (GtkWidget *clock, + GtkRequisition *requisition); +static void clock_face_size_allocate (GtkWidget *clock, + GtkAllocation *allocation); + +static void update_time_and_face (ClockFace *this, + gboolean force_face_loading); +static void clock_face_load_face (ClockFace *this, + gint width, gint height); + +typedef struct _ClockFacePrivate ClockFacePrivate; + +typedef enum { + CLOCK_FACE_MORNING, + CLOCK_FACE_DAY, + CLOCK_FACE_EVENING, + CLOCK_FACE_NIGHT, + CLOCK_FACE_INVALID +} ClockFaceTimeOfDay; + +struct _ClockFacePrivate +{ + struct tm time; /* the time on the clock face */ + int minute_offset; /* the offset of the minutes hand */ + + ClockFaceSize size; + ClockFaceTimeOfDay timeofday; + ClockLocation *location; + GdkPixbuf *face_pixbuf; + GtkWidget *size_widget; +}; + +static void +clock_face_class_init (ClockFaceClass *class) +{ + GObjectClass *obj_class; + GtkWidgetClass *widget_class; + + obj_class = G_OBJECT_CLASS (class); + widget_class = GTK_WIDGET_CLASS (class); + + /* GtkWidget signals */ + widget_class->expose_event = clock_face_expose; + widget_class->size_request = clock_face_size_request; + widget_class->size_allocate = clock_face_size_allocate; + + /* GObject signals */ + obj_class->finalize = clock_face_finalize; + + g_type_class_add_private (obj_class, sizeof (ClockFacePrivate)); +} + +static void +clock_face_init (ClockFace *this) +{ + ClockFacePrivate *priv = CLOCK_FACE_GET_PRIVATE (this); + + priv->size = CLOCK_FACE_SMALL; + priv->timeofday = CLOCK_FACE_INVALID; + priv->location = NULL; + priv->size_widget = NULL; + + gtk_widget_set_has_window (GTK_WIDGET (this), FALSE); +} + +static void +draw (GtkWidget *this, cairo_t *cr) +{ + ClockFacePrivate *priv; + GtkAllocation allocation; + double x, y; + double radius; + int hours, minutes, seconds; + + /* Hand lengths as a multiple of the clock radius */ + double hour_length, min_length, sec_length; + + priv = CLOCK_FACE_GET_PRIVATE (this); + + if (priv->size == CLOCK_FACE_LARGE) { + hour_length = 0.45; + min_length = 0.6; + sec_length = 0.65; + } else { + hour_length = 0.5; + min_length = 0.7; + sec_length = 0.8; /* not drawn currently */ + } + + gtk_widget_get_allocation (this, &allocation); + + x = allocation.x + allocation.width / 2; + y = allocation.y + allocation.height / 2; + radius = MIN (allocation.width / 2, + allocation.height / 2) - 5; + + cairo_save (cr); + cairo_translate (cr, allocation.x, allocation.y); + + /* clock back */ + if (priv->face_pixbuf) { + GdkWindow *window = gtk_widget_get_window (this); + gdk_draw_pixbuf (GDK_DRAWABLE (window), + NULL, + priv->face_pixbuf, + 0, 0, + allocation.x, + allocation.y, + allocation.width, + allocation.height, + GDK_RGB_DITHER_NONE, 0, 0); + } + + cairo_restore (cr); + + /* clock hands */ + hours = priv->time.tm_hour; + minutes = priv->time.tm_min + priv->minute_offset; + seconds = priv->time.tm_sec; + + cairo_set_line_width (cr, 1); + + /* hour hand: + * the hour hand is rotated 30 degrees (pi/6 r) per hour + + * 1/2 a degree (pi/360 r) per minute + */ + cairo_save (cr); + cairo_move_to (cr, x, y); + cairo_line_to (cr, x + radius * hour_length * sin (M_PI / 6 * hours + + M_PI / 360 * minutes), + y + radius * hour_length * -cos (M_PI / 6 * hours + + M_PI / 360 * minutes)); + cairo_stroke (cr); + cairo_restore (cr); + /* minute hand: + * the minute hand is rotated 6 degrees (pi/30 r) per minute + */ + cairo_move_to (cr, x, y); + cairo_line_to (cr, x + radius * min_length * sin (M_PI / 30 * minutes), + y + radius * min_length * -cos (M_PI / 30 * minutes)); + cairo_stroke (cr); + + /* seconds hand: + * operates identically to the minute hand + */ + if (priv->size == CLOCK_FACE_LARGE) { + cairo_save (cr); + cairo_set_source_rgb (cr, 0.937, 0.161, 0.161); /* tango red */ + cairo_move_to (cr, x, y); + cairo_line_to (cr, x + radius * sec_length * sin (M_PI / 30 * seconds), + y + radius * sec_length * -cos (M_PI / 30 * seconds)); + cairo_stroke (cr); + cairo_restore (cr); + } +} + +static gboolean +clock_face_expose (GtkWidget *this, GdkEventExpose *event) +{ + cairo_t *cr; + + /* get a cairo_t */ + cr = gdk_cairo_create (gtk_widget_get_window (this)); + + cairo_rectangle (cr, + event->area.x, event->area.y, + event->area.width, event->area.height); + cairo_clip (cr); + + draw (this, cr); + + cairo_destroy (cr); + + return FALSE; +} + +static void +clock_face_redraw_canvas (ClockFace *this) +{ + gtk_widget_queue_draw (GTK_WIDGET (this)); +} + +static void +clock_face_size_request (GtkWidget *this, + GtkRequisition *requisition) +{ + ClockFacePrivate *priv = CLOCK_FACE_GET_PRIVATE (this); + + if (priv->size_widget != NULL) { + GtkRequisition req; + + /* Tie our size to the height of the size_widget */ + gtk_widget_size_request (GTK_WIDGET (priv->size_widget), &req); + + /* Pad out our height by a little bit - this improves + the balance */ + requisition->width = req.height + req.height / 8; + requisition->height = req.height + req.height / 8; + } else if (priv->face_pixbuf != NULL) { + int w, h; + + /* Use the size of the current pixbuf */ + w = gdk_pixbuf_get_width (GDK_PIXBUF (priv->face_pixbuf)); + h = gdk_pixbuf_get_height (GDK_PIXBUF (priv->face_pixbuf)); + + requisition->width = w; + requisition->height = h; + } else { + /* we don't know anything, so use known dimensions for the svg + * files */ + if (priv->size == CLOCK_FACE_LARGE) { + requisition->width = 50; + requisition->height = 50; + } else { + requisition->width = 36; + requisition->height = 36; + } + } +} + +static void +clock_face_size_allocate (GtkWidget *this, + GtkAllocation *allocation) +{ + GtkAllocation this_allocation; + GtkAllocation old_allocation; + + gtk_widget_get_allocation (this, &this_allocation); + + old_allocation.width = this_allocation.width; + old_allocation.height = this_allocation.height; + + if (GTK_WIDGET_CLASS (clock_face_parent_class)->size_allocate) + GTK_WIDGET_CLASS (clock_face_parent_class)->size_allocate (this, allocation); + + if (old_allocation.width == allocation->width && + old_allocation.height == allocation->height) + return; + + /* Reload the face for the new size */ + update_time_and_face (CLOCK_FACE (this), TRUE); +} + +static void +update_time_and_face (ClockFace *this, + gboolean force_face_loading) +{ + ClockFacePrivate *priv; + ClockFaceTimeOfDay timeofday; + + priv = CLOCK_FACE_GET_PRIVATE (this); + + /* update the time */ + if (priv->location) { + clock_location_localtime (priv->location, &priv->time); + } else { + time_t timet; + time (&timet); + localtime_r (&timet, &priv->time); + } + + /* FIXME this should be a mateconf setting + * Or we could use some code from clock-sun.c? + * currently we hardcode + * morning 7-9 + * day 9-17 + * evening 17-22 + * night 22-7 + */ + if (priv->time.tm_hour < 7) + timeofday = CLOCK_FACE_NIGHT; + else if (priv->time.tm_hour < 9) + timeofday = CLOCK_FACE_MORNING; + else if (priv->time.tm_hour < 17) + timeofday = CLOCK_FACE_DAY; + else if (priv->time.tm_hour < 22) + timeofday = CLOCK_FACE_EVENING; + else + timeofday = CLOCK_FACE_NIGHT; + + if (priv->timeofday != timeofday || force_face_loading) { + GtkAllocation allocation; + gint width, height; + + priv->timeofday = timeofday; + + gtk_widget_get_allocation (GTK_WIDGET (this), &allocation); + + width = allocation.width; + height = allocation.height; + + /* Only load the pixbuf if we have some space allocated. + * Note that 1x1 is not really some space... */ + if (width > 1 && height > 1) + clock_face_load_face (this, width, height); + } +} + +gboolean +clock_face_refresh (ClockFace *this) +{ + update_time_and_face (this, FALSE); + clock_face_redraw_canvas (this); + + return TRUE; /* keep running this event */ +} + +GtkWidget * +clock_face_new (ClockFaceSize size) +{ + GObject *obj = g_object_new (INTL_TYPE_CLOCK_FACE, NULL); + ClockFacePrivate *priv = CLOCK_FACE_GET_PRIVATE (obj); + + priv->size = size; + + return GTK_WIDGET (obj); +} + +GtkWidget * +clock_face_new_with_location (ClockFaceSize size, + ClockLocation *loc, + GtkWidget *size_widget) +{ + GObject *obj = g_object_new (INTL_TYPE_CLOCK_FACE, NULL); + ClockFacePrivate *priv = CLOCK_FACE_GET_PRIVATE (obj); + + priv->size = size; + priv->location = g_object_ref (loc); + priv->size_widget = g_object_ref (size_widget); + + return GTK_WIDGET (obj); +} + +static void +clock_face_finalize (GObject *obj) +{ + ClockFacePrivate *priv = CLOCK_FACE_GET_PRIVATE (obj); + + if (priv->location) { + g_object_unref (priv->location); + priv->location = NULL; + } + + if (priv->face_pixbuf) { + g_object_unref (priv->face_pixbuf); + priv->face_pixbuf = NULL; + } + + if (priv->size_widget) { + g_object_unref (priv->size_widget); + priv->size_widget = NULL; + } + + G_OBJECT_CLASS (clock_face_parent_class)->finalize (obj); + + if (pixbuf_cache && g_hash_table_size (pixbuf_cache) == 0) { + g_hash_table_destroy (pixbuf_cache); + pixbuf_cache = NULL; + } +} + +/* The pixbuf is being disposed, so remove it from the cache */ +static void +remove_pixbuf_from_cache (const char *key, + GObject *pixbuf) +{ + g_hash_table_remove (pixbuf_cache, key); +} + +static void +clock_face_load_face (ClockFace *this, gint width, gint height) +{ + ClockFacePrivate *priv = CLOCK_FACE_GET_PRIVATE (this); + const gchar *size_string[2] = { "small", "large" }; + const gchar *daytime_string[4] = { "morning", "day", "evening", "night" }; + gchar *cache_name; + gchar *name; + + if (!pixbuf_cache) + pixbuf_cache = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); + + if (priv->face_pixbuf != NULL) { + /* This might empty the cache, but it's useless to destroy + * it since this object is still alive and might add another + * pixbuf in the cache later (eg, a few lines below) */ + g_object_unref (priv->face_pixbuf); + priv->face_pixbuf = NULL; + } + + /* Look for the pixbuf in the process-wide cache first */ + cache_name = g_strdup_printf ("%d-%d-%d-%d", + priv->size, priv->timeofday, + width, height); + + priv->face_pixbuf = g_hash_table_lookup (pixbuf_cache, cache_name); + if (priv->face_pixbuf) { + g_object_ref (priv->face_pixbuf); + return; + } + + /* The pixbuf is not cached, let's load it */ + name = g_strconcat (ICONDIR, "/clock-face-", size_string[priv->size], + "-", daytime_string[priv->timeofday], ".svg", + NULL); + priv->face_pixbuf = rsvg_pixbuf_from_file_at_size (name, + width, height, + NULL); + g_free (name); + + if (!priv->face_pixbuf) { + name = g_strconcat (ICONDIR, "/clock-face-", + size_string[priv->size], ".svg", NULL); + priv->face_pixbuf = rsvg_pixbuf_from_file_at_size (name, + width, + height, + NULL); + g_free (name); + } + + /* Save the found pixbuf in the cache */ + if (priv->face_pixbuf) { + g_hash_table_replace (pixbuf_cache, + cache_name, priv->face_pixbuf); + /* This will handle automatic removal from the cache when + * the pixbuf isn't needed anymore */ + g_object_weak_ref (G_OBJECT (priv->face_pixbuf), + (GWeakNotify) remove_pixbuf_from_cache, + cache_name); + } else + g_free (cache_name); +} diff --git a/applets/clock/clock-face.h b/applets/clock/clock-face.h new file mode 100644 index 00000000..3c665c63 --- /dev/null +++ b/applets/clock/clock-face.h @@ -0,0 +1,64 @@ +/** + * clock.h + * + * A GTK+ widget that implements a clock face + * + * (c) 2007, Peter Teichman + * (c) 2005-2006, Davyd Madeley + * + * Authors: + * Davyd Madeley + * Peter Teichman + */ + +#ifndef __INTL_CLOCK_FACE_H__ +#define __INTL_CLOCK_FACE_H__ + +#include +#include "clock-location.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define INTL_TYPE_CLOCK_FACE (clock_face_get_type ()) +#define CLOCK_FACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INTL_TYPE_CLOCK_FACE, ClockFace)) +#define CLOCK_FACE_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), INTL_CLOCK_FACE, ClockFaceClass)) +#define INTL_IS_CLOCK_FACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INTL_TYPE_CLOCK_FACE)) +#define INTL_IS_CLOCK_FACE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), INTL_TYPE_CLOCK_FACE)) +#define CLOCK_FACE_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS ((obj), INTL_TYPE_CLOCK_FACE, ClockFaceClass)) + +typedef struct _ClockFace ClockFace; +typedef struct _ClockFaceClass ClockFaceClass; + +struct _ClockFace +{ + GtkWidget parent; + + /* < private > */ +}; + +struct _ClockFaceClass +{ + GtkWidgetClass parent_class; +}; + +typedef enum { + CLOCK_FACE_SMALL, + CLOCK_FACE_LARGE +} ClockFaceSize; + +GType clock_face_get_type (void); + +GtkWidget *clock_face_new (ClockFaceSize size); +GtkWidget *clock_face_new_with_location (ClockFaceSize size, + ClockLocation *loc, + GtkWidget *size_widget); +gboolean clock_face_refresh (ClockFace *this); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/applets/clock/clock-location-tile.c b/applets/clock/clock-location-tile.c new file mode 100644 index 00000000..a6f6a4ce --- /dev/null +++ b/applets/clock/clock-location-tile.c @@ -0,0 +1,728 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include + +#include "clock.h" +#include "clock-face.h" +#include "clock-location-tile.h" +#include "clock-location.h" +#include "clock-utils.h" +#include "clock-marshallers.h" +#include "set-timezone.h" + +G_DEFINE_TYPE (ClockLocationTile, clock_location_tile, GTK_TYPE_ALIGNMENT) + +enum { + TILE_PRESSED, + NEED_CLOCK_FORMAT, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +typedef struct { + ClockLocation *location; + + struct tm last_refresh; + long last_offset; + + ClockFaceSize size; + + GtkWidget *box; + GtkWidget *clock_face; + GtkWidget *city_label; + GtkWidget *time_label; + + GtkWidget *current_button; + GtkWidget *current_label; + GtkWidget *current_marker; + GtkWidget *current_spacer; + GtkSizeGroup *current_group; + GtkSizeGroup *button_group; + + GtkWidget *weather_icon; + + gulong location_weather_updated_id; +} ClockLocationTilePrivate; + +static void clock_location_tile_finalize (GObject *); + +#define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CLOCK_LOCATION_TILE_TYPE, ClockLocationTilePrivate)) + +static void clock_location_tile_fill (ClockLocationTile *this); +static void update_weather_icon (ClockLocation *loc, WeatherInfo *info, gpointer data); +static gboolean weather_tooltip (GtkWidget *widget, + gint x, gint y, + gboolean keyboard_mode, + GtkTooltip *tooltip, + gpointer data); + +ClockLocationTile * +clock_location_tile_new (ClockLocation *loc, + ClockFaceSize size) +{ + ClockLocationTile *this; + ClockLocationTilePrivate *priv; + + this = g_object_new (CLOCK_LOCATION_TILE_TYPE, NULL); + priv = PRIVATE (this); + + priv->location = g_object_ref (loc); + priv->size = size; + + clock_location_tile_fill (this); + + update_weather_icon (loc, clock_location_get_weather_info (loc), this); + gtk_widget_set_has_tooltip (priv->weather_icon, TRUE); + + g_signal_connect (priv->weather_icon, "query-tooltip", + G_CALLBACK (weather_tooltip), this); + priv->location_weather_updated_id = g_signal_connect (G_OBJECT (loc), "weather-updated", + G_CALLBACK (update_weather_icon), this); + + return this; +} + +static void +clock_location_tile_class_init (ClockLocationTileClass *this_class) +{ + GObjectClass *g_obj_class = G_OBJECT_CLASS (this_class); + + g_obj_class->finalize = clock_location_tile_finalize; + + g_type_class_add_private (this_class, sizeof (ClockLocationTilePrivate)); + + signals[TILE_PRESSED] = g_signal_new ("tile-pressed", + G_TYPE_FROM_CLASS (g_obj_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (ClockLocationTileClass, tile_pressed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[NEED_CLOCK_FORMAT] = g_signal_new ("need-clock-format", + G_TYPE_FROM_CLASS (g_obj_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ClockLocationTileClass, need_clock_format), + NULL, + NULL, + _clock_marshal_INT__VOID, + G_TYPE_INT, 0); +} + +static void +clock_location_tile_init (ClockLocationTile *this) +{ + ClockLocationTilePrivate *priv = PRIVATE (this); + + priv->location = NULL; + + memset (&(priv->last_refresh), 0, sizeof (struct tm)); + priv->last_offset = 0; + + priv->size = CLOCK_FACE_SMALL; + + priv->clock_face = NULL; + priv->city_label = NULL; + priv->time_label = NULL; +} + +static void +clock_location_tile_finalize (GObject *g_obj) +{ + ClockLocationTilePrivate *priv = PRIVATE (g_obj); + + if (priv->location) { + g_signal_handler_disconnect (priv->location, priv->location_weather_updated_id); + priv->location_weather_updated_id = 0; + + g_object_unref (priv->location); + priv->location = NULL; + } + + if (priv->button_group) { + g_object_unref (priv->button_group); + priv->button_group = NULL; + } + + if (priv->current_group) { + g_object_unref (priv->current_group); + priv->current_group = NULL; + } + + G_OBJECT_CLASS (clock_location_tile_parent_class)->finalize (g_obj); +} + +static gboolean +press_on_tile (GtkWidget *widget, + GdkEventButton *event, + ClockLocationTile *tile) +{ + g_signal_emit (tile, signals[TILE_PRESSED], 0); + + return TRUE; +} + +static void +make_current_cb (gpointer data, GError *error) +{ + GtkWidget *dialog; + + if (error) { + dialog = gtk_message_dialog_new (NULL, + 0, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Failed to set the system timezone")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + gtk_window_present (GTK_WINDOW (dialog)); + + g_error_free (error); + } +} + +static void +make_current (GtkWidget *widget, ClockLocationTile *tile) +{ + ClockLocationTilePrivate *priv = PRIVATE (tile); + GtkWidget *toplevel; + guint xid; + + xid = 0; + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tile)); + + if (toplevel) { + GdkWindow *window = gtk_widget_get_window (toplevel); + + if (window) + xid = GDK_WINDOW_XWINDOW (window); + } + + clock_location_make_current (priv->location, + xid, + (GFunc)make_current_cb, tile, NULL); +} + +static gboolean +enter_or_leave_tile (GtkWidget *widget, + GdkEventCrossing *event, + ClockLocationTile *tile) +{ + ClockLocationTilePrivate *priv = PRIVATE (tile); + + if (event->mode != GDK_CROSSING_NORMAL) { + return TRUE; + } + + if (clock_location_is_current (priv->location)) { + gtk_widget_hide (priv->current_button); + gtk_widget_hide (priv->current_spacer); + gtk_widget_show (priv->current_marker); + + return TRUE; + } + + if (event->type == GDK_ENTER_NOTIFY) { + gint can_set; + + if (clock_location_is_current_timezone (priv->location)) + can_set = 2; + else + can_set = can_set_system_timezone (); + if (can_set != 0) { + gtk_label_set_markup (GTK_LABEL (priv->current_label), + can_set == 1 ? + _("Set...") : + _("Set")); + gtk_widget_hide (priv->current_spacer); + gtk_widget_hide (priv->current_marker); + gtk_widget_show (priv->current_button); + } + else { + gtk_widget_hide (priv->current_marker); + gtk_widget_hide (priv->current_button); + gtk_widget_show (priv->current_spacer); + } + } + else { + if (event->detail != GDK_NOTIFY_INFERIOR) { + gtk_widget_hide (priv->current_button); + gtk_widget_hide (priv->current_marker); + gtk_widget_show (priv->current_spacer); + } + } + + return TRUE; +} + +static void +clock_location_tile_fill (ClockLocationTile *this) +{ + ClockLocationTilePrivate *priv = PRIVATE (this); + GtkWidget *align; + GtkWidget *strut; + GtkWidget *box; + GtkWidget *alignment; + GtkWidget *tile; + GtkWidget *head_section; + + priv->box = gtk_event_box_new (); + + gtk_widget_add_events (priv->box, GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); + g_signal_connect (priv->box, "button-press-event", + G_CALLBACK (press_on_tile), this); + g_signal_connect (priv->box, "enter-notify-event", + G_CALLBACK (enter_or_leave_tile), this); + g_signal_connect (priv->box, "leave-notify-event", + G_CALLBACK (enter_or_leave_tile), this); + + alignment = gtk_alignment_new (0, 0, 1, 0); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 3, 3, 3, 0); + + tile = gtk_hbox_new (FALSE, 6); + head_section = gtk_vbox_new (FALSE, 0); + + priv->city_label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (priv->city_label), 0, 0); + + align = gtk_alignment_new (0, 0, 0, 0); + gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, 3); + gtk_container_add (GTK_CONTAINER (align), priv->city_label); + gtk_box_pack_start (GTK_BOX (head_section), align, FALSE, FALSE, 0); + + priv->time_label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (priv->time_label), 0, 0); + + priv->weather_icon = gtk_image_new (); + align = gtk_alignment_new (0, 0, 0, 0); + gtk_container_add (GTK_CONTAINER (align), priv->weather_icon); + + box = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (head_section), box, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), priv->time_label, FALSE, FALSE, 0); + + priv->current_button = gtk_button_new (); + /* The correct label is set on EnterNotify events */ + priv->current_label = gtk_label_new (""); + gtk_widget_show (priv->current_label); + gtk_widget_set_no_show_all (priv->current_button, TRUE); + gtk_container_add (GTK_CONTAINER (priv->current_button), priv->current_label); + gtk_widget_set_tooltip_text (priv->current_button, + _("Set location as current location and use its timezone for this computer")); + + priv->current_marker = gtk_image_new_from_icon_name ("go-home", GTK_ICON_SIZE_BUTTON); + gtk_misc_set_alignment (GTK_MISC (priv->current_marker), 1.0, 0.5); + gtk_widget_set_no_show_all (priv->current_marker, TRUE); + + priv->current_spacer = gtk_event_box_new (); + gtk_widget_set_no_show_all (priv->current_spacer, TRUE); + + strut = gtk_event_box_new (); + gtk_box_pack_start (GTK_BOX (box), strut, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (box), priv->current_button, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), priv->current_marker, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), priv->current_spacer, FALSE, FALSE, 0); + priv->button_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL); + gtk_size_group_set_ignore_hidden (priv->button_group, FALSE); + gtk_size_group_add_widget (priv->button_group, strut); + gtk_size_group_add_widget (priv->button_group, priv->current_button); + + /* + * Avoid resizing the popup as the tiles display the current marker, + * set button or nothing. For that purpose, replace 'nothing' with + * an event box, and force the button, marker and spacer to have the + * same size via a size group. The visibility of the three is managed + * manually to ensure that only one of them is shown at any time. + * (The all have to be shown initially to get the sizes worked out, + * but they are never visible together). + */ + priv->current_group = gtk_size_group_new (GTK_SIZE_GROUP_BOTH); + gtk_size_group_set_ignore_hidden (priv->current_group, FALSE); + gtk_size_group_add_widget (priv->current_group, priv->current_button); + gtk_size_group_add_widget (priv->current_group, priv->current_marker); + gtk_size_group_add_widget (priv->current_group, priv->current_spacer); + + gtk_widget_show (priv->current_button); + gtk_widget_show (priv->current_marker); + gtk_widget_show (priv->current_spacer); + + g_signal_connect (priv->current_button, "clicked", + G_CALLBACK (make_current), this); + + priv->clock_face = clock_face_new_with_location ( + priv->size, priv->location, head_section); + + gtk_box_pack_start (GTK_BOX (tile), priv->clock_face, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (tile), head_section, TRUE, TRUE, 0); + + gtk_container_add (GTK_CONTAINER (alignment), tile); + gtk_container_add (GTK_CONTAINER (priv->box), alignment); + gtk_container_add (GTK_CONTAINER (this), priv->box); +} + +static gboolean +clock_needs_face_refresh (ClockLocationTile *this) +{ + ClockLocationTilePrivate *priv = PRIVATE (this); + struct tm now; + + clock_location_localtime (priv->location, &now); + + if (now.tm_year > priv->last_refresh.tm_year + || now.tm_mon > priv->last_refresh.tm_mon + || now.tm_mday > priv->last_refresh.tm_mday + || now.tm_hour > priv->last_refresh.tm_hour + || now.tm_min > priv->last_refresh.tm_min) { + return TRUE; + } + + if ((priv->size == CLOCK_FACE_LARGE) + && now.tm_sec > priv->last_refresh.tm_sec) { + return TRUE; + } + + return FALSE; +} + +static gboolean +clock_needs_label_refresh (ClockLocationTile *this) +{ + ClockLocationTilePrivate *priv = PRIVATE (this); + struct tm now; + long offset; + + clock_location_localtime (priv->location, &now); + offset = clock_location_get_offset (priv->location); + + if (now.tm_year > priv->last_refresh.tm_year + || now.tm_mon > priv->last_refresh.tm_mon + || now.tm_mday > priv->last_refresh.tm_mday + || now.tm_hour > priv->last_refresh.tm_hour + || now.tm_min > priv->last_refresh.tm_min + || offset != priv->last_offset) { + return TRUE; + } + + return FALSE; +} + +static void +copy_tm (struct tm *from, struct tm *to) +{ + to->tm_sec = from->tm_sec; + to->tm_min = from->tm_min; + to->tm_hour = from->tm_hour; + to->tm_mday = from->tm_mday; + to->tm_mon = from->tm_mon; + to->tm_year = from->tm_year; + to->tm_wday = from->tm_wday; + to->tm_yday = from->tm_yday; +} + +static char * +format_time (struct tm *now, + char *tzname, + ClockFormat clock_format, + long offset) +{ + char buf[256]; + char *format; + time_t local_t; + struct tm local_now; + char *utf8; + char *tmp; + long hours, minutes; + + time (&local_t); + localtime_r (&local_t, &local_now); + + if (local_now.tm_wday != now->tm_wday) { + if (clock_format == CLOCK_FORMAT_12) { + /* Translators: This is a strftime format string. + * It is used to display the time in 12-hours format + * (eg, like in the US: 8:10 am), when the local + * weekday differs from the weekday at the location + * (the %A expands to the weekday). The %p expands to + * am/pm. */ + format = _("%l:%M %p (%A)"); + } + else { + /* Translators: This is a strftime format string. + * It is used to display the time in 24-hours format + * (eg, like in France: 20:10), when the local + * weekday differs from the weekday at the location + * (the %A expands to the weekday). */ + format = _("%H:%M (%A)"); + } + } + else { + if (clock_format == CLOCK_FORMAT_12) { + /* Translators: This is a strftime format string. + * It is used to display the time in 12-hours format + * (eg, like in the US: 8:10 am). The %p expands to + * am/pm. */ + format = _("%l:%M %p"); + } + else { + /* Translators: This is a strftime format string. + * It is used to display the time in 24-hours format + * (eg, like in France: 20:10). */ + format = _("%H:%M"); + } + } + + if (strftime (buf, sizeof (buf), format, now) <= 0) { + strcpy (buf, "???"); + } + + hours = offset / 3600; + minutes = labs (offset % 3600) / 60; + + if (hours != 0 && minutes != 0) { + tmp = g_strdup_printf ("%s %s %+ld:%ld", buf, tzname, hours, minutes); + } + else if (hours != 0) { + tmp = g_strdup_printf ("%s %s %+ld", buf, tzname, hours); + } + else { + tmp = g_strdup_printf ("%s %s", buf, tzname); + } + + utf8 = g_locale_to_utf8 (tmp, -1, NULL, NULL, NULL); + + g_free (tmp); + + return utf8; +} + +static char * +convert_time_to_str (time_t now, ClockFormat clock_format) +{ + const gchar *format; + struct tm *tm; + gchar buf[128]; + + if (clock_format == CLOCK_FORMAT_12) { + /* Translators: This is a strftime format string. + * It is used to display the time in 12-hours format (eg, like + * in the US: 8:10 am). The %p expands to am/pm. + */ + format = _("%l:%M %p"); + } + else { + /* Translators: This is a strftime format string. + * It is used to display the time in 24-hours format (eg, like + * in France: 20:10). + */ + format = _("%H:%M"); + } + + tm = localtime (&now); + strftime (buf, sizeof (buf) - 1, format, tm); + + return g_locale_to_utf8 (buf, -1, NULL, NULL, NULL); +} + +void +clock_location_tile_refresh (ClockLocationTile *this, gboolean force_refresh) +{ + ClockLocationTilePrivate *priv = PRIVATE (this); + gchar *tmp, *tzname; + struct tm now; + long offset; + int format; + + g_return_if_fail (IS_CLOCK_LOCATION_TILE (this)); + + if (clock_location_is_current (priv->location)) { + gtk_widget_hide (priv->current_spacer); + gtk_widget_hide (priv->current_button); + gtk_widget_show (priv->current_marker); + } + else { + if (gtk_widget_get_visible (priv->current_marker)) { + gtk_widget_hide (priv->current_marker); + gtk_widget_hide (priv->current_button); + gtk_widget_show (priv->current_spacer); + } + } + + if (clock_needs_face_refresh (this)) { + clock_face_refresh (CLOCK_FACE (priv->clock_face)); + } + + if (!force_refresh && !clock_needs_label_refresh (this)) { + return; + } + + clock_location_localtime (priv->location, &now); + tzname = clock_location_get_tzname (priv->location); + + copy_tm (&now, &(priv->last_refresh)); + priv->last_offset = clock_location_get_offset (priv->location); + + tmp = g_strdup_printf ("%s", + clock_location_get_display_name (priv->location)); + gtk_label_set_markup (GTK_LABEL (priv->city_label), tmp); + g_free (tmp); + + g_signal_emit (this, signals[NEED_CLOCK_FORMAT], 0, &format); + + offset = - priv->last_offset; + + tmp = format_time (&now, tzname, format, offset); + + gtk_label_set_markup (GTK_LABEL (priv->time_label), tmp); + + g_free (tmp); +} + +void +weather_info_setup_tooltip (WeatherInfo *info, ClockLocation *location, GtkTooltip *tooltip, + ClockFormat clock_format) +{ + GdkPixbuf *pixbuf = NULL; + GtkIconTheme *theme = NULL; + const gchar *conditions, *wind; + gchar *temp, *apparent; + gchar *line1, *line2, *line3, *line4, *tip; + const gchar *icon_name; + const gchar *sys_timezone; + time_t sunrise_time, sunset_time; + gchar *sunrise_str, *sunset_str; + + icon_name = weather_info_get_icon_name (info); + theme = gtk_icon_theme_get_default (); + pixbuf = gtk_icon_theme_load_icon (theme, icon_name, 48, + GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL); + if (pixbuf) + gtk_tooltip_set_icon (tooltip, pixbuf); + + conditions = weather_info_get_conditions (info); + if (strcmp (conditions, "-") != 0) + line1 = g_strdup_printf (_("%s, %s"), + conditions, + weather_info_get_sky (info)); + else + line1 = g_strdup (weather_info_get_sky (info)); + + /* we need to g_strdup() since both functions return the same address + * of a static buffer */ + temp = g_strdup (weather_info_get_temp (info)); + apparent = g_strdup (weather_info_get_apparent (info)); + if (strcmp (apparent, temp) != 0 && + /* FMQ: it's broken to read from another module's translations; add some API to libmateweather. */ + strcmp (apparent, dgettext ("mate-applets-2.0", "Unknown")) != 0) + /* Translators: The two strings are temperatures. */ + line2 = g_strdup_printf (_("%s, feels like %s"), temp, apparent); + else + line2 = g_strdup (temp); + g_free (temp); + g_free (apparent); + + wind = weather_info_get_wind (info); + if (strcmp (apparent, dgettext ("mate-applets-2.0", "Unknown")) != 0) + line3 = g_strdup_printf ("%s\n", wind); + else + line3 = g_strdup (""); + + sys_timezone = getenv ("TZ"); + setenv ("TZ", clock_location_get_timezone (location), 1); + tzset (); + if (weather_info_get_value_sunrise (info, &sunrise_time)) + sunrise_str = convert_time_to_str (sunrise_time, clock_format); + else + sunrise_str = g_strdup ("???"); + if (weather_info_get_value_sunset (info, &sunset_time)) + sunset_str = convert_time_to_str (sunset_time, clock_format); + else + sunset_str = g_strdup ("???"); + line4 = g_strdup_printf (_("Sunrise: %s / Sunset: %s"), + sunrise_str, sunset_str); + g_free (sunrise_str); + g_free (sunset_str); + + if (sys_timezone) + setenv ("TZ", sys_timezone, 1); + else + unsetenv ("TZ"); + tzset (); + + tip = g_strdup_printf ("%s\n%s\n%s%s", line1, line2, line3, line4); + gtk_tooltip_set_markup (tooltip, tip); + g_free (line1); + g_free (line2); + g_free (line3); + g_free (line4); + g_free (tip); +} + +static gboolean +weather_tooltip (GtkWidget *widget, + gint x, + gint y, + gboolean keyboard_mode, + GtkTooltip *tooltip, + gpointer data) +{ + ClockLocationTile *tile = data; + ClockLocationTilePrivate *priv = PRIVATE (tile); + WeatherInfo *info; + int clock_format; + + info = clock_location_get_weather_info (priv->location); + + if (!info || !weather_info_is_valid (info)) + return FALSE; + + g_signal_emit (tile, signals[NEED_CLOCK_FORMAT], 0, &clock_format); + + weather_info_setup_tooltip (info, priv->location, tooltip, clock_format); + + return TRUE; +} + +static void +update_weather_icon (ClockLocation *loc, WeatherInfo *info, gpointer data) +{ + ClockLocationTile *tile = data; + ClockLocationTilePrivate *priv = PRIVATE (tile); + GdkPixbuf *pixbuf = NULL; + GtkIconTheme *theme = NULL; + const gchar *icon_name; + + if (!info || !weather_info_is_valid (info)) + return; + + icon_name = weather_info_get_icon_name (info); + theme = gtk_icon_theme_get_default (); + pixbuf = gtk_icon_theme_load_icon (theme, icon_name, 16, + GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL); + + if (pixbuf) { + gtk_image_set_from_pixbuf (GTK_IMAGE (priv->weather_icon), pixbuf); + gtk_alignment_set_padding (GTK_ALIGNMENT (gtk_widget_get_parent (priv->weather_icon)), 0, 0, 0, 6); + } +} + +ClockLocation * +clock_location_tile_get_location (ClockLocationTile *this) +{ + ClockLocationTilePrivate *priv; + + g_return_val_if_fail (IS_CLOCK_LOCATION_TILE (this), NULL); + + priv = PRIVATE (this); + + return g_object_ref (priv->location); +} diff --git a/applets/clock/clock-location-tile.h b/applets/clock/clock-location-tile.h new file mode 100644 index 00000000..00ccb5a8 --- /dev/null +++ b/applets/clock/clock-location-tile.h @@ -0,0 +1,51 @@ +#ifndef __CLOCK_LOCATION_TILE_H__ +#define __CLOCK_LOCATION_TILE_H__ + +#include + +#include "clock.h" +#include "clock-face.h" +#include "clock-location.h" +#include "clock-utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CLOCK_LOCATION_TILE_TYPE (clock_location_tile_get_type ()) +#define CLOCK_LOCATION_TILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CLOCK_LOCATION_TILE_TYPE, ClockLocationTile)) +#define CLOCK_LOCATION_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), CLOCK_LOCATION_TILE_TYPE, ClockLocationTileClass)) +#define IS_CLOCK_LOCATION_TILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CLOCK_LOCATION_TILE_TYPE)) +#define IS_CLOCK_LOCATION_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), CLOCK_LOCATION_TILE_TYPE)) +#define CLOCK_LOCATION_TILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CLOCK_LOCATION_TILE_TYPE, ClockLocationTileClass)) + +typedef struct +{ + GtkAlignment parent; +} ClockLocationTile; + +typedef struct +{ + GtkAlignmentClass parent_class; + + void (* tile_pressed) (ClockLocationTile *tile); + int (* need_clock_format) (ClockLocationTile *tile); +} ClockLocationTileClass; + +GType clock_location_tile_get_type (void); + +ClockLocationTile *clock_location_tile_new (ClockLocation *loc, + ClockFaceSize size); + +ClockLocation *clock_location_tile_get_location (ClockLocationTile *this); + +void weather_info_setup_tooltip (WeatherInfo *info, ClockLocation *location, GtkTooltip *tip, + ClockFormat clock_format); + +void clock_location_tile_refresh (ClockLocationTile *this, + gboolean force_refresh); + +#ifdef __cplusplus +} +#endif +#endif /* __CLOCK_H__ */ diff --git a/applets/clock/clock-location.c b/applets/clock/clock-location.c new file mode 100644 index 00000000..1b81c517 --- /dev/null +++ b/applets/clock/clock-location.c @@ -0,0 +1,894 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HAVE_NETWORK_MANAGER +#include +#include +#include +#endif + +#include "clock-location.h" +#include "clock-marshallers.h" +#include "set-timezone.h" +#include "system-timezone.h" + +G_DEFINE_TYPE (ClockLocation, clock_location, G_TYPE_OBJECT) + +typedef struct { + gchar *name; + gchar *city; + + SystemTimezone *systz; + + gchar *timezone; + + gchar *tzname; + + gfloat latitude; + gfloat longitude; + + gchar *weather_code; + WeatherInfo *weather_info; + guint weather_timeout; + guint weather_retry_time; + + TempUnit temperature_unit; + SpeedUnit speed_unit; +} ClockLocationPrivate; + +#define WEATHER_TIMEOUT_BASE 30 +#define WEATHER_TIMEOUT_MAX 1800 +#define WEATHER_EMPTY_CODE "-" + +enum { + WEATHER_UPDATED, + SET_CURRENT, + LAST_SIGNAL +}; + +static guint location_signals[LAST_SIGNAL] = { 0 }; + +static void clock_location_finalize (GObject *); +static void clock_location_set_tz (ClockLocation *this); +static void clock_location_unset_tz (ClockLocation *this); +static void setup_weather_updates (ClockLocation *loc); +static void add_to_network_monitor (ClockLocation *loc); +static void remove_from_network_monitor (ClockLocation *loc); + +static gchar *clock_location_get_valid_weather_code (const gchar *code); + +#define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CLOCK_LOCATION_TYPE, ClockLocationPrivate)) + +ClockLocation * +clock_location_find_and_ref (GList *locations, + const gchar *name, + const gchar *city, + const gchar *timezone, + gfloat latitude, + gfloat longitude, + const gchar *code) +{ + GList *l; + ClockLocationPrivate *priv; + + for (l = locations; l != NULL; l = l->next) { + priv = PRIVATE (l->data); + + if (priv->latitude == latitude && + priv->longitude == longitude && + g_strcmp0 (priv->weather_code, code) == 0 && + g_strcmp0 (priv->timezone, timezone) == 0 && + g_strcmp0 (priv->city, city) == 0 && + g_strcmp0 (priv->name, name) == 0) + break; + } + + if (l != NULL) + return g_object_ref (CLOCK_LOCATION (l->data)); + else + return NULL; +} + +ClockLocation * +clock_location_new (const gchar *name, const gchar *city, + const gchar *timezone, + gfloat latitude, gfloat longitude, + const gchar *code, WeatherPrefs *prefs) +{ + ClockLocation *this; + ClockLocationPrivate *priv; + + this = g_object_new (CLOCK_LOCATION_TYPE, NULL); + priv = PRIVATE (this); + + priv->name = g_strdup (name); + priv->city = g_strdup (city); + priv->timezone = g_strdup (timezone); + + /* initialize priv->tzname */ + clock_location_set_tz (this); + clock_location_unset_tz (this); + + priv->latitude = latitude; + priv->longitude = longitude; + + priv->weather_code = clock_location_get_valid_weather_code (code); + + if (prefs) { + priv->temperature_unit = prefs->temperature_unit; + priv->speed_unit = prefs->speed_unit; + } + + setup_weather_updates (this); + + return this; +} + +static ClockLocation *current_location = NULL; + +static void +clock_location_class_init (ClockLocationClass *this_class) +{ + GObjectClass *g_obj_class = G_OBJECT_CLASS (this_class); + + g_obj_class->finalize = clock_location_finalize; + + location_signals[WEATHER_UPDATED] = + g_signal_new ("weather-updated", + G_OBJECT_CLASS_TYPE (g_obj_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (ClockLocationClass, weather_updated), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + location_signals[SET_CURRENT] = + g_signal_new ("set-current", + G_OBJECT_CLASS_TYPE (g_obj_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (ClockLocationClass, set_current), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_type_class_add_private (this_class, sizeof (ClockLocationPrivate)); +} + +static void +clock_location_init (ClockLocation *this) +{ + ClockLocationPrivate *priv = PRIVATE (this); + + priv->name = NULL; + priv->city = NULL; + + priv->systz = system_timezone_new (); + + priv->timezone = NULL; + + priv->tzname = NULL; + + priv->latitude = 0; + priv->longitude = 0; + + priv->temperature_unit = TEMP_UNIT_CENTIGRADE; + priv->speed_unit = SPEED_UNIT_MS; +} + +static void +clock_location_finalize (GObject *g_obj) +{ + ClockLocationPrivate *priv = PRIVATE (g_obj); + + remove_from_network_monitor (CLOCK_LOCATION (g_obj)); + + if (priv->name) { + g_free (priv->name); + priv->name = NULL; + } + + if (priv->city) { + g_free (priv->city); + priv->city = NULL; + } + + if (priv->systz) { + g_object_unref (priv->systz); + priv->systz = NULL; + } + + if (priv->timezone) { + g_free (priv->timezone); + priv->timezone = NULL; + } + + if (priv->tzname) { + g_free (priv->tzname); + priv->tzname = NULL; + } + + if (priv->weather_code) { + g_free (priv->weather_code); + priv->weather_code = NULL; + } + + if (priv->weather_info) { + weather_info_free (priv->weather_info); + priv->weather_info = NULL; + } + + if (priv->weather_timeout) { + g_source_remove (priv->weather_timeout); + priv->weather_timeout = 0; + } + + G_OBJECT_CLASS (clock_location_parent_class)->finalize (g_obj); +} + +const gchar * +clock_location_get_display_name (ClockLocation *loc) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + + if (priv->name && priv->name[0]) + return priv->name; + else + return priv->city; +} + +const gchar * +clock_location_get_name (ClockLocation *loc) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + + return priv->name; +} + +void +clock_location_set_name (ClockLocation *loc, const gchar *name) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + + if (priv->name) { + g_free (priv->name); + priv->name = NULL; + } + + priv->name = g_strdup (name); +} + +const gchar * +clock_location_get_city (ClockLocation *loc) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + + return priv->city; +} + +void +clock_location_set_city (ClockLocation *loc, const gchar *city) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + + if (priv->city) { + g_free (priv->city); + priv->city = NULL; + } + + priv->city = g_strdup (city); +} + +gchar * +clock_location_get_timezone (ClockLocation *loc) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + + return priv->timezone; +} + +void +clock_location_set_timezone (ClockLocation *loc, const gchar *timezone) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + + if (priv->timezone) { + g_free (priv->timezone); + priv->timezone = NULL; + } + + priv->timezone = g_strdup (timezone); +} + +gchar * +clock_location_get_tzname (ClockLocation *loc) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + + return priv->tzname; +} + +void +clock_location_get_coords (ClockLocation *loc, gfloat *latitude, + gfloat *longitude) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + + *latitude = priv->latitude; + *longitude = priv->longitude; +} + +void +clock_location_set_coords (ClockLocation *loc, gfloat latitude, + gfloat longitude) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + + priv->latitude = latitude; + priv->longitude = longitude; +} + +static void +clock_location_set_tzname (ClockLocation *this, const char *tzname) +{ + ClockLocationPrivate *priv = PRIVATE (this); + + if (priv->tzname) { + if (strcmp (priv->tzname, tzname) == 0) { + return; + } + + g_free (priv->tzname); + priv->tzname = NULL; + } + + if (tzname) { + priv->tzname = g_strdup (tzname); + } else { + priv->tzname = NULL; + } +} + +static void +clock_location_set_tz (ClockLocation *this) +{ + ClockLocationPrivate *priv = PRIVATE (this); + + time_t now_t; + struct tm now; + + if (priv->timezone == NULL) { + return; + } + + setenv ("TZ", priv->timezone, 1); + tzset(); + + now_t = time (NULL); + localtime_r (&now_t, &now); + + if (now.tm_isdst > 0) { + clock_location_set_tzname (this, tzname[1]); + } else { + clock_location_set_tzname (this, tzname[0]); + } +} + +static void +clock_location_unset_tz (ClockLocation *this) +{ + ClockLocationPrivate *priv = PRIVATE (this); + const char *env_timezone; + + if (priv->timezone == NULL) { + return; + } + + env_timezone = system_timezone_get_env (priv->systz); + + if (env_timezone) { + setenv ("TZ", env_timezone, 1); + } else { + unsetenv ("TZ"); + } + tzset(); +} + +void +clock_location_localtime (ClockLocation *loc, struct tm *tm) +{ + time_t now; + + clock_location_set_tz (loc); + + time (&now); + localtime_r (&now, tm); + + clock_location_unset_tz (loc); +} + +gboolean +clock_location_is_current_timezone (ClockLocation *loc) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + const char *zone; + + zone = system_timezone_get (priv->systz); + + if (zone) + return strcmp (zone, priv->timezone) == 0; + else + return clock_location_get_offset (loc) == 0; +} + +gboolean +clock_location_is_current (ClockLocation *loc) +{ + if (current_location == loc) + return TRUE; + else if (current_location != NULL) + return FALSE; + + if (clock_location_is_current_timezone (loc)) { + /* Note that some code in clock.c depends on the fact that + * calling this function can set the current location if + * there's none */ + current_location = loc; + g_object_add_weak_pointer (G_OBJECT (current_location), + (gpointer *)¤t_location); + g_signal_emit (current_location, location_signals[SET_CURRENT], + 0, NULL); + + return TRUE; + } + + return FALSE; +} + + +glong +clock_location_get_offset (ClockLocation *loc) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + glong sys_timezone, local_timezone; + glong offset; + time_t t; + struct tm *tm; + + t = time (NULL); + + unsetenv ("TZ"); + tm = localtime (&t); + sys_timezone = timezone; + + if (tm->tm_isdst > 0) { + sys_timezone -= 3600; + } + + setenv ("TZ", priv->timezone, 1); + tm = localtime (&t); + local_timezone = timezone; + + if (tm->tm_isdst > 0) { + local_timezone -= 3600; + } + + offset = local_timezone - sys_timezone; + + clock_location_unset_tz (loc); + + return offset; +} + +typedef struct { + ClockLocation *location; + GFunc callback; + gpointer data; + GDestroyNotify destroy; +} MakeCurrentData; + +static void +make_current_cb (gpointer data, GError *error) +{ + MakeCurrentData *mcdata = data; + + if (error == NULL) { + if (current_location) + g_object_remove_weak_pointer (G_OBJECT (current_location), + (gpointer *)¤t_location); + current_location = mcdata->location; + g_object_add_weak_pointer (G_OBJECT (current_location), + (gpointer *)¤t_location); + g_signal_emit (current_location, location_signals[SET_CURRENT], + 0, NULL); + } + + if (mcdata->callback) + mcdata->callback (mcdata->data, error); + else + g_error_free (error); +} + +static void +free_make_current_data (gpointer data) +{ + MakeCurrentData *mcdata = data; + + if (mcdata->destroy) + mcdata->destroy (mcdata->data); + + g_object_unref (mcdata->location); + g_free (mcdata); +} + +void +clock_location_make_current (ClockLocation *loc, + guint transient_parent_xid, + GFunc callback, + gpointer data, + GDestroyNotify destroy) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + gchar *filename; + MakeCurrentData *mcdata; + + if (loc == current_location) { + if (destroy) + destroy (data); + return; + } + + if (clock_location_is_current_timezone (loc)) { + if (current_location) + g_object_remove_weak_pointer (G_OBJECT (current_location), + (gpointer *)¤t_location); + current_location = loc; + g_object_add_weak_pointer (G_OBJECT (current_location), + (gpointer *)¤t_location); + g_signal_emit (current_location, location_signals[SET_CURRENT], + 0, NULL); + if (callback) + callback (data, NULL); + if (destroy) + destroy (data); + return; + } + + mcdata = g_new (MakeCurrentData, 1); + + mcdata->location = g_object_ref (loc); + mcdata->callback = callback; + mcdata->data = data; + mcdata->destroy = destroy; + + filename = g_build_filename (SYSTEM_ZONEINFODIR, priv->timezone, NULL); + set_system_timezone_async (filename, + (GFunc)make_current_cb, + mcdata, + free_make_current_data); + g_free (filename); +} + +static gchar * +clock_location_get_valid_weather_code (const gchar *code) +{ + if (!code || code[0] == '\0') + return g_strdup (WEATHER_EMPTY_CODE); + else + return g_strdup (code); +} + +const gchar * +clock_location_get_weather_code (ClockLocation *loc) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + + return priv->weather_code; +} + +void +clock_location_set_weather_code (ClockLocation *loc, const gchar *code) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + + g_free (priv->weather_code); + priv->weather_code = clock_location_get_valid_weather_code (code); + + setup_weather_updates (loc); +} + +WeatherInfo * +clock_location_get_weather_info (ClockLocation *loc) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + + return priv->weather_info; +} + +static gboolean update_weather_info (gpointer data); + +static void +set_weather_update_timeout (ClockLocation *loc) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + guint timeout; + + if (!weather_info_network_error (priv->weather_info)) { + /* The last update succeeded; set the next update to + * happen in half an hour, and reset the retry timer. + */ + timeout = WEATHER_TIMEOUT_MAX; + priv->weather_retry_time = WEATHER_TIMEOUT_BASE; + } else { + /* The last update failed; set the next update + * according to the retry timer, and exponentially + * back off the retry timer. + */ + timeout = priv->weather_retry_time; + priv->weather_retry_time *= 2; + if (priv->weather_retry_time > WEATHER_TIMEOUT_MAX) + priv->weather_retry_time = WEATHER_TIMEOUT_MAX; + } + + if (priv->weather_timeout) + g_source_remove (priv->weather_timeout); + priv->weather_timeout = + g_timeout_add_seconds (timeout, update_weather_info, loc); +} + +static void +weather_info_updated (WeatherInfo *info, gpointer data) +{ + ClockLocation *loc = data; + ClockLocationPrivate *priv = PRIVATE (loc); + + set_weather_update_timeout (loc); + g_signal_emit (loc, location_signals[WEATHER_UPDATED], + 0, priv->weather_info); +} + +static gboolean +update_weather_info (gpointer data) +{ + ClockLocation *loc = data; + ClockLocationPrivate *priv = PRIVATE (loc); + WeatherPrefs prefs = { + FORECAST_STATE, + FALSE, + NULL, + TEMP_UNIT_CENTIGRADE, + SPEED_UNIT_MS, + PRESSURE_UNIT_MB, + DISTANCE_UNIT_KM + }; + + prefs.temperature_unit = priv->temperature_unit; + prefs.speed_unit = priv->speed_unit; + + weather_info_abort (priv->weather_info); + weather_info_update (priv->weather_info, + &prefs, weather_info_updated, loc); + + return TRUE; +} + +static gchar * +rad2dms (gfloat lat, gfloat lon) +{ + gchar h, h2; + gfloat d, deg, min, d2, deg2, min2; + + h = lat > 0 ? 'N' : 'S'; + d = fabs (lat); + deg = floor (d); + min = floor (60 * (d - deg)); + h2 = lon > 0 ? 'E' : 'W'; + d2 = fabs (lon); + deg2 = floor (d2); + min2 = floor (60 * (d2 - deg2)); + return g_strdup_printf ("%02d-%02d%c %02d-%02d%c", + (int)deg, (int)min, h, + (int)deg2, (int)min2, h2); +} + +static GList *locations = NULL; + +static void +update_weather_infos (void) +{ + GList *l; + + for (l = locations; l; l = l->next) { + ClockLocation *loc = l->data; + ClockLocationPrivate *priv = PRIVATE (loc); + + priv->weather_retry_time = WEATHER_TIMEOUT_BASE; + update_weather_info (loc); + } +} + +#ifdef HAVE_NETWORK_MANAGER +static void +state_notify (DBusPendingCall *pending, gpointer data) +{ + DBusMessage *msg = dbus_pending_call_steal_reply (pending); + + if (!msg) + return; + + if (dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_RETURN) { + dbus_uint32_t result; + + if (dbus_message_get_args (msg, NULL, + DBUS_TYPE_UINT32, &result, + DBUS_TYPE_INVALID)) { + if (result == NM_STATE_CONNECTED) { + update_weather_infos (); + } + } + } + + dbus_message_unref (msg); +} + +static void +check_network (DBusConnection *connection) +{ + DBusMessage *message; + DBusPendingCall *reply; + + message = dbus_message_new_method_call (NM_DBUS_SERVICE, + NM_DBUS_PATH, + NM_DBUS_INTERFACE, + "state"); + if (dbus_connection_send_with_reply (connection, message, &reply, -1)) { + dbus_pending_call_set_notify (reply, state_notify, NULL, NULL); + dbus_pending_call_unref (reply); + } + + dbus_message_unref (message); +} + +static DBusHandlerResult +filter_func (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + if (dbus_message_is_signal (message, + NM_DBUS_INTERFACE, + "StateChanged")) { + check_network (connection); + + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void +setup_network_monitor (void) +{ + GError *error; + DBusError derror; + static DBusGConnection *bus = NULL; + DBusConnection *dbus; + + if (bus == NULL) { + error = NULL; + bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (bus == NULL) { + g_warning ("Couldn't connect to system bus: %s", + error->message); + g_error_free (error); + + return; + } + + dbus_error_init (&derror); + dbus = dbus_g_connection_get_connection (bus); + dbus_connection_add_filter (dbus, filter_func, NULL, NULL); + dbus_bus_add_match (dbus, + "type='signal'," + "interface='" NM_DBUS_INTERFACE "'", + &derror); + if (dbus_error_is_set (&derror)) { + g_warning ("Couldn't register signal handler: %s: %s", + derror.name, derror.message); + dbus_error_free (&derror); + } + } +} +#endif + +static void +add_to_network_monitor (ClockLocation *loc) +{ +#ifdef HAVE_NETWORK_MANAGER + setup_network_monitor (); +#endif + + if (!g_list_find (locations, loc)) + locations = g_list_prepend (locations, loc); +} + +static void +remove_from_network_monitor (ClockLocation *loc) +{ + locations = g_list_remove (locations, loc); +} + +static void +setup_weather_updates (ClockLocation *loc) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + WeatherLocation *wl; + WeatherPrefs prefs = { + FORECAST_STATE, + FALSE, + NULL, + TEMP_UNIT_CENTIGRADE, + SPEED_UNIT_MS, + PRESSURE_UNIT_MB, + DISTANCE_UNIT_KM + }; + + gchar *dms; + + prefs.temperature_unit = priv->temperature_unit; + prefs.speed_unit = priv->speed_unit; + + if (priv->weather_info) { + weather_info_free (priv->weather_info); + priv->weather_info = NULL; + } + + if (priv->weather_timeout) { + g_source_remove (priv->weather_timeout); + priv->weather_timeout = 0; + } + + if (!priv->weather_code || + strcmp (priv->weather_code, WEATHER_EMPTY_CODE) == 0) + return; + + dms = rad2dms (priv->latitude, priv->longitude); + wl = weather_location_new (priv->city, priv->weather_code, + NULL, NULL, dms, NULL, NULL); + + priv->weather_info = + weather_info_new (wl, &prefs, weather_info_updated, loc); + + set_weather_update_timeout (loc); + + weather_location_free (wl); + g_free (dms); + + add_to_network_monitor (loc); +} + +void +clock_location_set_weather_prefs (ClockLocation *loc, + WeatherPrefs *prefs) +{ + ClockLocationPrivate *priv = PRIVATE (loc); + + priv->temperature_unit = prefs->temperature_unit; + priv->speed_unit = prefs->speed_unit; + + update_weather_info (loc); +} + diff --git a/applets/clock/clock-location.h b/applets/clock/clock-location.h new file mode 100644 index 00000000..ae2275aa --- /dev/null +++ b/applets/clock/clock-location.h @@ -0,0 +1,87 @@ +#ifndef __CLOCK_LOCATION_H__ +#define __CLOCK_LOCATION_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CLOCK_LOCATION_TYPE (clock_location_get_type ()) +#define CLOCK_LOCATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CLOCK_LOCATION_TYPE, ClockLocation)) +#define CLOCK_LOCATION_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), CLOCK_LOCATION_TYPE, ClockLocationClass)) +#define IS_CLOCK_LOCATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CLOCK_LOCATION_TYPE)) +#define IS_CLOCK_LOCATION_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), CLOCK_LOCATION_TYPE)) +#define CLOCK_LOCATION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CLOCK_LOCATION_TYPE, ClockLocationClass)) + +typedef struct +{ + GObject g_object; +} ClockLocation; + +typedef struct +{ + GObjectClass g_object_class; + + void (* weather_updated) (ClockLocation *location, WeatherInfo *info); + + void (* set_current) (ClockLocation *location); +} ClockLocationClass; + +GType clock_location_get_type (void); + +ClockLocation *clock_location_new (const gchar *name, const gchar *city, + const gchar *timezone, + gfloat latitude, gfloat longitude, + const gchar *code, + WeatherPrefs *prefs); + +ClockLocation *clock_location_find_and_ref (GList *locations, + const gchar *name, + const gchar *city, + const gchar *timezone, + gfloat latitude, + gfloat longitude, + const gchar *code); + +gchar *clock_location_get_tzname (ClockLocation *loc); + +const gchar *clock_location_get_display_name (ClockLocation *loc); + +const gchar *clock_location_get_name (ClockLocation *loc); +void clock_location_set_name (ClockLocation *loc, const gchar *name); + +const gchar *clock_location_get_city (ClockLocation *loc); +void clock_location_set_city (ClockLocation *loc, const gchar *city); + +gchar *clock_location_get_timezone (ClockLocation *loc); +void clock_location_set_timezone (ClockLocation *loc, const gchar *timezone); + +void clock_location_get_coords (ClockLocation *loc, gfloat *latitude, gfloat *longitude); +void clock_location_set_coords (ClockLocation *loc, gfloat latitude, gfloat longitude); + +void clock_location_localtime (ClockLocation *loc, struct tm *tm); + +gboolean clock_location_is_current (ClockLocation *loc); +void clock_location_make_current (ClockLocation *loc, + guint transient_parent_xid, + GFunc callback, + gpointer data, + GDestroyNotify destroy); +gboolean clock_location_is_current_timezone (ClockLocation *loc); + +const gchar *clock_location_get_weather_code (ClockLocation *loc); +void clock_location_set_weather_code (ClockLocation *loc, const gchar *code); +WeatherInfo *clock_location_get_weather_info (ClockLocation *loc); +void clock_location_set_weather_prefs (ClockLocation *loc, + WeatherPrefs *weather_prefs); + +glong clock_location_get_offset (ClockLocation *loc); + +#ifdef __cplusplus +} +#endif +#endif /* __CLOCK_LOCATION_H__ */ diff --git a/applets/clock/clock-map.c b/applets/clock/clock-map.c new file mode 100644 index 00000000..5a6e0379 --- /dev/null +++ b/applets/clock/clock-map.c @@ -0,0 +1,700 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "clock.h" +#include "clock-map.h" +#include "clock-sunpos.h" +#include "clock-marshallers.h" + +G_DEFINE_TYPE (ClockMap, clock_map, GTK_TYPE_WIDGET) + +enum { + NEED_LOCATIONS, + LAST_SIGNAL +}; + +enum { + MARKER_NORMAL = 0, + MARKER_HILIGHT, + MARKER_CURRENT, + MARKER_NB +}; + +static char *marker_files[MARKER_NB] = { + ICONDIR "/clock-map-location-marker.png", + ICONDIR "/clock-map-location-hilight.png", + ICONDIR "/clock-map-location-current.png" +}; + +static guint signals[LAST_SIGNAL]; + +typedef struct { + time_t last_refresh; + + gint width; + gint height; + + guint highlight_timeout_id; + + GdkPixbuf *stock_map_pixbuf; + GdkPixbuf *location_marker_pixbuf[MARKER_NB]; + + GdkPixbuf *location_map_pixbuf; + + /* The shadow itself */ + GdkPixbuf *shadow_pixbuf; + + /* The map with the shadow composited onto it */ + GdkPixbuf *shadow_map_pixbuf; +} ClockMapPrivate; + +static void clock_map_finalize (GObject *); +static void clock_map_size_request (GtkWidget *this, + GtkRequisition *requisition); +static void clock_map_size_allocate (GtkWidget *this, + GtkAllocation *allocation); +static gboolean clock_map_expose (GtkWidget *this, + GdkEventExpose *expose); + +static void clock_map_place_locations (ClockMap *this); +static void clock_map_render_shadow (ClockMap *this); +static void clock_map_display (ClockMap *this); + +#define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CLOCK_MAP_TYPE, ClockMapPrivate)) + +ClockMap * +clock_map_new (void) +{ + ClockMap *this; + + this = g_object_new (CLOCK_MAP_TYPE, NULL); + + return this; +} + +static void +clock_map_class_init (ClockMapClass *this_class) +{ + GObjectClass *g_obj_class = G_OBJECT_CLASS (this_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (g_obj_class); + + g_obj_class->finalize = clock_map_finalize; + + /* GtkWidget signals */ + widget_class->size_request = clock_map_size_request; + widget_class->size_allocate = clock_map_size_allocate; + widget_class->expose_event = clock_map_expose; + + g_type_class_add_private (this_class, sizeof (ClockMapPrivate)); + + /** + * ClockMap::need-locations + * + * The map widget emits this signal when it needs to know which + * locations to display. + * + * Returns: the handler should return a (GList *) of (ClockLocation *). + * The map widget will not modify this list, so the caller should keep + * it alive. + */ + signals[NEED_LOCATIONS] = g_signal_new ("need-locations", + G_TYPE_FROM_CLASS (g_obj_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ClockMapClass, need_locations), + NULL, + NULL, + _clock_marshal_POINTER__VOID, + G_TYPE_POINTER, 0); +} + +static void +clock_map_init (ClockMap *this) +{ + int i; + ClockMapPrivate *priv = PRIVATE (this); + + gtk_widget_set_has_window (GTK_WIDGET (this), FALSE); + + priv->last_refresh = 0; + priv->width = 0; + priv->height = 0; + priv->highlight_timeout_id = 0; + priv->stock_map_pixbuf = NULL; + + g_assert (sizeof (marker_files)/sizeof (char *) == MARKER_NB); + + for (i = 0; i < MARKER_NB; i++) { + priv->location_marker_pixbuf[i] = gdk_pixbuf_new_from_file + (marker_files[i], NULL); + } +} + +static void +clock_map_finalize (GObject *g_obj) +{ + ClockMapPrivate *priv = PRIVATE (g_obj); + int i; + + if (priv->highlight_timeout_id) { + g_source_remove (priv->highlight_timeout_id); + priv->highlight_timeout_id = 0; + } + + if (priv->stock_map_pixbuf) { + g_object_unref (priv->stock_map_pixbuf); + priv->stock_map_pixbuf = NULL; + } + + for (i = 0; i < MARKER_NB; i++) { + if (priv->location_marker_pixbuf[i]) { + g_object_unref (priv->location_marker_pixbuf[i]); + priv->location_marker_pixbuf[i] = NULL; + } + } + + if (priv->location_map_pixbuf) { + g_object_unref (priv->location_map_pixbuf); + priv->location_map_pixbuf = NULL; + } + + if (priv->shadow_pixbuf) { + g_object_unref (priv->shadow_pixbuf); + priv->shadow_pixbuf = NULL; + } + + if (priv->shadow_map_pixbuf) { + g_object_unref (priv->shadow_map_pixbuf); + priv->shadow_map_pixbuf = NULL; + } + + G_OBJECT_CLASS (clock_map_parent_class)->finalize (g_obj); +} + +void +clock_map_refresh (ClockMap *this) +{ + ClockMapPrivate *priv = PRIVATE (this); + GtkWidget *widget = GTK_WIDGET (this); + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); + + /* Only do something if we have some space allocated. + * Note that 1x1 is not really some space... */ + if (allocation.width <= 1 || allocation.height <= 1) + return; + + /* Allocation changed => we reload the map */ + if (priv->width != allocation.width || + priv->height != allocation.height) { + if (priv->stock_map_pixbuf) { + g_object_unref (priv->stock_map_pixbuf); + priv->stock_map_pixbuf = NULL; + } + + priv->width = allocation.width; + priv->height = allocation.height; + } + + if (!priv->stock_map_pixbuf) { + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_scale + (ICONDIR "/clock-map.png", + priv->width, priv->height, FALSE, NULL); + + priv->stock_map_pixbuf = pixbuf; + } + + clock_map_place_locations (this); + + clock_map_display (this); +} + +static gboolean +clock_map_expose (GtkWidget *this, GdkEventExpose *event) +{ + ClockMapPrivate *priv = PRIVATE (this); + GdkWindow *window; + GtkStyle *style; + GtkAllocation allocation; + GdkRectangle region; + cairo_t *cr; + + window = gtk_widget_get_window (this); + style = gtk_widget_get_style (this); + gtk_widget_get_allocation (this, &allocation); + + if (!priv->shadow_map_pixbuf) { + g_warning ("Needed to refresh the map in expose event."); + clock_map_refresh (CLOCK_MAP (this)); + } + + cr = gdk_cairo_create (window); + + region.x = allocation.x; + region.y = allocation.y; + region.width = gdk_pixbuf_get_width (priv->shadow_map_pixbuf); + region.height = gdk_pixbuf_get_height (priv->shadow_map_pixbuf); + + gdk_rectangle_intersect (®ion, &(event->area), ®ion); + gdk_draw_pixbuf (window, + style->black_gc, + priv->shadow_map_pixbuf, + region.x - allocation.x, + region.y - allocation.y, + region.x, + region.y, + region.width, + region.height, + GDK_RGB_DITHER_NORMAL, + 0, 0); + + /* draw a simple outline */ + cairo_rectangle ( + cr, + allocation.x + 0.5, allocation.y + 0.5, + gdk_pixbuf_get_width (priv->shadow_map_pixbuf) - 1, + gdk_pixbuf_get_height (priv->shadow_map_pixbuf) - 1); + + cairo_set_source_rgb ( + cr, + style->mid [GTK_STATE_ACTIVE].red / 65535.0, + style->mid [GTK_STATE_ACTIVE].green / 65535.0, + style->mid [GTK_STATE_ACTIVE].blue / 65535.0); + + cairo_set_line_width (cr, 1.0); + cairo_stroke (cr); + + cairo_destroy (cr); + + return FALSE; +} + +static void +clock_map_size_request (GtkWidget *this, GtkRequisition *requisition) +{ + requisition->width = 250; + requisition->height = 125; +} + +static void +clock_map_size_allocate (GtkWidget *this, GtkAllocation *allocation) +{ + ClockMapPrivate *priv = PRIVATE (this); + + if (GTK_WIDGET_CLASS (clock_map_parent_class)->size_allocate) + GTK_WIDGET_CLASS (clock_map_parent_class)->size_allocate (this, allocation); + + if (priv->width != allocation->width || + priv->height != allocation->height) + clock_map_refresh (CLOCK_MAP (this)); +} + +static void +clock_map_mark (ClockMap *this, gfloat latitude, gfloat longitude, gint mark) +{ + ClockMapPrivate *priv = PRIVATE (this); + GdkPixbuf *marker = priv->location_marker_pixbuf[mark]; + GdkPixbuf *partial = NULL; + + int x, y; + int width, height; + int marker_width, marker_height; + int dest_x, dest_y, dest_width, dest_height; + + width = gdk_pixbuf_get_width (priv->location_map_pixbuf); + height = gdk_pixbuf_get_height (priv->location_map_pixbuf); + + x = (width / 2.0 + (width / 2.0) * longitude / 180.0); + y = (height / 2.0 - (height / 2.0) * latitude / 90.0); + + marker_width = gdk_pixbuf_get_width (marker); + marker_height = gdk_pixbuf_get_height (marker); + + dest_x = x - marker_width / 2; + dest_y = y - marker_height / 2; + dest_width = marker_width; + dest_height = marker_height; + + /* create a small partial pixbuf if the mark is too close to + the north or south pole */ + if (dest_y < 0) { + partial = gdk_pixbuf_new_subpixbuf + (marker, 0, dest_y + marker_height, + marker_width, -dest_y); + + dest_y = 0.0; + marker_height = gdk_pixbuf_get_height (partial); + } else if (dest_y + dest_height > height) { + partial = gdk_pixbuf_new_subpixbuf + (marker, 0, 0, marker_width, height - dest_y); + marker_height = gdk_pixbuf_get_height (partial); + } + + if (partial) { + marker = partial; + } + + /* handle the cases where the marker needs to be placed across + the 180 degree longitude line */ + if (dest_x < 0) { + /* split into our two pixbufs for the left and right edges */ + GdkPixbuf *lhs = NULL; + GdkPixbuf *rhs = NULL; + + lhs = gdk_pixbuf_new_subpixbuf + (marker, -dest_x, 0, marker_width + dest_x, marker_height); + + gdk_pixbuf_composite (lhs, priv->location_map_pixbuf, + 0, dest_y, + gdk_pixbuf_get_width (lhs), + gdk_pixbuf_get_height (lhs), + 0, dest_y, + 1.0, 1.0, GDK_INTERP_NEAREST, 0xFF); + + rhs = gdk_pixbuf_new_subpixbuf + (marker, 0, 0, -dest_x, marker_height); + + gdk_pixbuf_composite (rhs, priv->location_map_pixbuf, + width - gdk_pixbuf_get_width (rhs) - 1, + dest_y, + gdk_pixbuf_get_width (rhs), + gdk_pixbuf_get_height (rhs), + width - gdk_pixbuf_get_width (rhs) - 1, + dest_y, + 1.0, 1.0, GDK_INTERP_NEAREST, 0xFF); + + g_object_unref (lhs); + g_object_unref (rhs); + } else if (dest_x + dest_width > width) { + /* split into our two pixbufs for the left and right edges */ + GdkPixbuf *lhs = NULL; + GdkPixbuf *rhs = NULL; + + lhs = gdk_pixbuf_new_subpixbuf + (marker, width - dest_x, 0, marker_width - width + dest_x, marker_height); + + gdk_pixbuf_composite (lhs, priv->location_map_pixbuf, + 0, dest_y, + gdk_pixbuf_get_width (lhs), + gdk_pixbuf_get_height (lhs), + 0, dest_y, + 1.0, 1.0, GDK_INTERP_NEAREST, 0xFF); + + rhs = gdk_pixbuf_new_subpixbuf + (marker, 0, 0, width - dest_x, marker_height); + + gdk_pixbuf_composite (rhs, priv->location_map_pixbuf, + width - gdk_pixbuf_get_width (rhs) - 1, + dest_y, + gdk_pixbuf_get_width (rhs), + gdk_pixbuf_get_height (rhs), + width - gdk_pixbuf_get_width (rhs) - 1, + dest_y, + 1.0, 1.0, GDK_INTERP_NEAREST, 0xFF); + + g_object_unref (lhs); + g_object_unref (rhs); + } else { + gdk_pixbuf_composite (marker, priv->location_map_pixbuf, + dest_x, dest_y, + gdk_pixbuf_get_width (marker), + gdk_pixbuf_get_height (marker), + dest_x, dest_y, + 1.0, 1.0, GDK_INTERP_NEAREST, 0xFF); + } + + if (partial != NULL) { + g_object_unref (partial); + } +} + +/** + * Return value: %TRUE if @loc can be placed on the map, %FALSE otherwise. + **/ +static gboolean +clock_map_place_location (ClockMap *this, ClockLocation *loc, gboolean hilight) +{ + gfloat latitude, longitude; + gint marker; + + clock_location_get_coords (loc, &latitude, &longitude); + /* 0/0 means unset, basically */ + if (latitude == 0 && longitude == 0) + return FALSE; + + if (hilight) + marker = MARKER_HILIGHT; + else if (clock_location_is_current (loc)) + marker = MARKER_CURRENT; + else + marker = MARKER_NORMAL; + + clock_map_mark (this, latitude, longitude, marker); + + return TRUE; +} + +static void +clock_map_place_locations (ClockMap *this) +{ + ClockMapPrivate *priv = PRIVATE (this); + GList *locs; + ClockLocation *loc; + + if (priv->location_map_pixbuf) { + g_object_unref (priv->location_map_pixbuf); + priv->location_map_pixbuf = NULL; + } + + priv->location_map_pixbuf = gdk_pixbuf_copy (priv->stock_map_pixbuf); + + locs = NULL; + g_signal_emit (this, signals[NEED_LOCATIONS], 0, &locs); + + while (locs) { + loc = CLOCK_LOCATION (locs->data); + + clock_map_place_location (this, loc, FALSE); + + locs = locs->next; + } + +#if 0 + /* map_mark test suite for the edge cases */ + + /* points around longitude 180 */ + clock_map_mark (this, 0.0, 180.0); + clock_map_mark (this, -15.0, -178.0); + clock_map_mark (this, -30.0, -176.0); + clock_map_mark (this, 15.0, 178.0); + clock_map_mark (this, 30.0, 176.0); + + clock_map_mark (this, 90.0, 180.0); + clock_map_mark (this, -90.0, 180.0); + + /* north pole & friends */ + clock_map_mark (this, 90.0, 0.0); + clock_map_mark (this, 88.0, -15.0); + clock_map_mark (this, 92.0, 15.0); + + /* south pole & friends */ + clock_map_mark (this, -90.0, 0.0); + clock_map_mark (this, -88.0, -15.0); + clock_map_mark (this, -92.0, 15.0); +#endif +} + +static void +clock_map_compute_vector (gdouble lat, gdouble lon, gdouble *vec) +{ + gdouble lat_rad, lon_rad; + lat_rad = lat * (M_PI/180.0); + lon_rad = lon * (M_PI/180.0); + + vec[0] = sin(lon_rad) * cos(lat_rad); + vec[1] = sin(lat_rad); + vec[2] = cos(lon_rad) * cos(lat_rad); +} + +static guchar +clock_map_is_sunlit (gdouble pos_lat, gdouble pos_long, + gdouble sun_lat, gdouble sun_long) +{ + gdouble pos_vec[3]; + gdouble sun_vec[3]; + gdouble dot; + + /* twilight */ + gdouble epsilon = 0.01; + + clock_map_compute_vector (pos_lat, pos_long, pos_vec); + clock_map_compute_vector (sun_lat, sun_long, sun_vec); + + /* compute the dot product of the two */ + dot = pos_vec[0]*sun_vec[0] + pos_vec[1]*sun_vec[1] + + pos_vec[2]*sun_vec[2]; + + if (dot > epsilon) { + return 0x00; + } + + if (dot < -epsilon) { + return 0xFF; + } + + return (guchar)(-128 * ((dot / epsilon) - 1)); +} + +static void +clock_map_render_shadow_pixbuf (GdkPixbuf *pixbuf) +{ + int x, y; + int height, width; + int n_channels, rowstride; + guchar *pixels, *p; + gdouble sun_lat, sun_lon; + time_t now = time (NULL); + + n_channels = gdk_pixbuf_get_n_channels (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + pixels = gdk_pixbuf_get_pixels (pixbuf); + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + + sun_position (now, &sun_lat, &sun_lon); + + for (y = 0; y < height; y++) { + gdouble lat = (height / 2.0 - y) / (height / 2.0) * 90.0; + + for (x = 0; x < width; x++) { + guchar shade; + gdouble lon = + (x - width / 2.0) / (width / 2.0) * 180.0; + + shade = clock_map_is_sunlit (lat, lon, + sun_lat, sun_lon); + + p = pixels + y * rowstride + x * n_channels; + p[3] = shade; + } + } +} + +static void +clock_map_render_shadow (ClockMap *this) +{ + ClockMapPrivate *priv = PRIVATE (this); + + if (priv->shadow_pixbuf) { + g_object_unref (priv->shadow_pixbuf); + } + + priv->shadow_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, + priv->width, priv->height); + + /* Initialize to all shadow */ + gdk_pixbuf_fill (priv->shadow_pixbuf, 0x6d9ccdff); + + clock_map_render_shadow_pixbuf (priv->shadow_pixbuf); + + if (priv->shadow_map_pixbuf) { + g_object_unref (priv->shadow_map_pixbuf); + } + + priv->shadow_map_pixbuf = gdk_pixbuf_copy (priv->location_map_pixbuf); + + gdk_pixbuf_composite (priv->shadow_pixbuf, priv->shadow_map_pixbuf, + 0, 0, priv->width, priv->height, + 0, 0, 1, 1, GDK_INTERP_NEAREST, 0x66); +} + +static void +clock_map_display (ClockMap *this) +{ + ClockMapPrivate *priv = PRIVATE (this); + + clock_map_render_shadow (this); + gtk_widget_queue_draw (GTK_WIDGET (this)); + + time (&priv->last_refresh); +} + +typedef struct { + ClockMap *map; + ClockLocation *location; + int count; +} BlinkData; + +static gboolean +highlight (gpointer user_data) +{ + BlinkData *data = user_data; + + if (data->count == 6) + return FALSE; + + if (data->count % 2 == 0) { + if (!clock_map_place_location (data->map, + data->location, TRUE)) + return FALSE; + } else + clock_map_place_locations (data->map); + clock_map_display (data->map); + + data->count++; + + return TRUE; +} + +static void +highlight_destroy (gpointer user_data) +{ + BlinkData *data = user_data; + ClockMapPrivate *priv; + + priv = PRIVATE (data->map); + priv->highlight_timeout_id = 0; + + g_object_unref (data->location); + g_free (data); +} + +void +clock_map_blink_location (ClockMap *this, ClockLocation *loc) +{ + BlinkData *data; + ClockMapPrivate *priv; + + priv = PRIVATE (this); + + g_return_if_fail (IS_CLOCK_MAP (this)); + g_return_if_fail (IS_CLOCK_LOCATION (loc)); + + data = g_new0 (BlinkData, 1); + data->map = this; + data->location = g_object_ref (loc); + + if (priv->highlight_timeout_id) { + g_source_remove (priv->highlight_timeout_id); + clock_map_place_locations (this); + } + + highlight (data); + + priv->highlight_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, + 300, highlight, data, + highlight_destroy); +} + +static gboolean +clock_map_needs_refresh (ClockMap *this) +{ + ClockMapPrivate *priv = PRIVATE (this); + time_t now_t; + + time (&now_t); + + /* refresh once per minute */ + return (ABS (now_t - priv->last_refresh) >= 60); +} + +void +clock_map_update_time (ClockMap *this) +{ + + g_return_if_fail (IS_CLOCK_MAP (this)); + + if (!clock_map_needs_refresh (this)) { + return; + } + + clock_map_display (this); +} diff --git a/applets/clock/clock-map.h b/applets/clock/clock-map.h new file mode 100644 index 00000000..2b662c87 --- /dev/null +++ b/applets/clock/clock-map.h @@ -0,0 +1,43 @@ +#ifndef __CLOCK_MAP_H__ +#define __CLOCK_MAP_H__ + +#include "clock.h" +#include "clock-location.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CLOCK_MAP_TYPE (clock_map_get_type ()) +#define CLOCK_MAP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CLOCK_MAP_TYPE, ClockMap)) +#define CLOCK_MAP_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), CLOCK_MAP_TYPE, ClockMapClass)) +#define IS_CLOCK_MAP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CLOCK_MAP_TYPE)) +#define IS_CLOCK_MAP_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), CLOCK_MAP_TYPE)) +#define CLOCK_MAP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CLOCK_MAP_TYPE, ClockMapClass)) + +typedef struct +{ + GtkWidget parent; +} ClockMap; + +typedef struct +{ + GtkWidgetClass parent_class; + + GList *(* need_locations) (ClockMap *map); +} ClockMapClass; + +GType clock_map_get_type (void); + +ClockMap *clock_map_new (void); +void clock_map_refresh (ClockMap *this); +void clock_map_update_time (ClockMap *this); +void clock_map_blink_location (ClockMap *this, ClockLocation *loc); + + +#ifdef __cplusplus +} +#endif +#endif /* __CLOCK_MAP_H__ */ diff --git a/applets/clock/clock-marshallers.list b/applets/clock/clock-marshallers.list new file mode 100644 index 00000000..8c4d3072 --- /dev/null +++ b/applets/clock/clock-marshallers.list @@ -0,0 +1,3 @@ +POINTER:VOID +VOID:OBJECT,STRING +INT:VOID diff --git a/applets/clock/clock-menu.xml b/applets/clock/clock-menu.xml new file mode 100644 index 00000000..abe0e071 --- /dev/null +++ b/applets/clock/clock-menu.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/applets/clock/clock-sunpos.c b/applets/clock/clock-sunpos.c new file mode 100644 index 00000000..2103fd90 --- /dev/null +++ b/applets/clock/clock-sunpos.c @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2007 Red Hat, Inc. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Jonathan Blandford + * Matthias Clasen + */ + +#include +#include +#include +#include "clock-sunpos.h" + +/* Calculated with the methods and figures from "Practical Astronomy With Your + * Calculator, version 3" by Peter Duffet-Smith. + */ +/* Table 6. Details of the Sun's apparent matecorba at epoch 1990.0 */ + +#define EPOCH 2447891.5 /* days */ /* epoch 1990 */ +#define UNIX_EPOCH 2440586.5 /* days */ /* epoch 1970 */ +#define EPSILON_G 279.403303 /* degrees */ /* ecliptic longitude at epoch 1990.0 */ +#define MU_G 282.768422 /* degrees */ /* ecliptic longitude at perigee */ +#define ECCENTRICITY 0.016713 /* eccentricity of matecorba */ +#define R_0 149598500 /* km */ /* semi-major axis */ +#define THETA_0 0.533128 /* degrees */ /* angular diameter at r = r_0 */ +#define MEAN_OBLIQUITY 23.440592 /* degrees */ /* mean obliquity of earth's axis at epoch 1990.0 */ + +#define NORMALIZE(x) \ + while (x>360) x-=360; while (x<0) x+= 360; + +#define DEG_TO_RADS(x) \ + (x * G_PI/180.0) + +#define RADS_TO_DEG(x) \ + (x * 180.0/G_PI) + +/* Calculate number of days since 4713BC. + */ +static gdouble +unix_time_to_julian_date (gint unix_time) +{ + return UNIX_EPOCH + (double) unix_time / (60 * 60 * 24); +} + +/* Finds an iterative solution for [ E - e sin (E) = M ] for values of e less + than 0.1. Page 90 */ + +#define ERROR_ACCURACY 1e-6 /* radians */ + +static gdouble +solve_keplers_equation (gdouble e, + gdouble M) +{ + gdouble d, E; + + /* start with an initial estimate */ + E = M; + + d = E - e * sin (E) - M; + + while (ABS (d) > ERROR_ACCURACY) + { + E = E - (d / (1 - e * cos (E))); + d = E - e * sin (E) - M; + } + + return E; +} + + /* convert the ecliptic longitude to right ascension and declination. Section 27. */ +static void +ecliptic_to_equatorial (gdouble lambda, + gdouble beta, + gdouble *ra, + gdouble *dec) +{ + gdouble cos_mo; + gdouble sin_mo; + + g_assert (ra != NULL); + g_assert (dec != NULL); + + sin_mo = sin (DEG_TO_RADS (MEAN_OBLIQUITY)); + cos_mo = cos (DEG_TO_RADS (MEAN_OBLIQUITY)); + + *ra = atan2 (sin (lambda) * cos_mo - tan (beta) * sin_mo, cos (lambda)); + *dec = asin (sin (beta) * cos_mo + cos (beta) * sin_mo * sin (lambda)); +} + +/* calculate GST. Section 12 */ +static gdouble +greenwich_sidereal_time (gdouble unix_time) +{ + gdouble u, JD, T, T0, UT; + + u = fmod (unix_time, 24 * 60 * 60); + JD = unix_time_to_julian_date (unix_time - u); + T = (JD - 2451545) / 36525; + T0 = 6.697374558 + (2400.051336 * T) + (0.000025862 * T * T); + T0 = fmod (T0, 24); + UT = u / (60 * 60); + T0 = T0 + UT * 1.002737909; + T0 = fmod (T0, 24); + + return T0; +} + +/* Calculate the position of the sun at a given time. pages 89-91 */ +void +sun_position (time_t unix_time, gdouble *lat, gdouble *lon) +{ + gdouble jd, D, N, M, E, x, v, lambda; + gdouble ra, dec; + jd = unix_time_to_julian_date (unix_time); + + /* Calculate number of days since the epoch */ + D = jd - EPOCH; + + N = D*360/365.242191; + + /* normalize to 0 - 360 degrees */ + NORMALIZE (N); + + /* Step 4: */ + M = N + EPSILON_G - MU_G; + NORMALIZE (M); + + /* Step 5: convert to radians */ + M = DEG_TO_RADS (M); + + /* Step 6: */ + E = solve_keplers_equation (ECCENTRICITY, M); + + /* Step 7: */ + x = sqrt ((1 + ECCENTRICITY)/(1 - ECCENTRICITY)) * tan (E/2); + + /* Step 8, 9 */ + v = 2 * RADS_TO_DEG (atan (x)); + NORMALIZE (v); + + /* Step 10 */ + lambda = v + MU_G; + NORMALIZE (lambda); + + /* convert the ecliptic longitude to right ascension and declination */ + ecliptic_to_equatorial (DEG_TO_RADS (lambda), 0.0, &ra, &dec); + + ra = ra - (G_PI/12) * greenwich_sidereal_time (unix_time); + ra = RADS_TO_DEG (ra); + dec = RADS_TO_DEG (dec); + NORMALIZE (ra); + NORMALIZE (dec); + + *lat = dec; + *lon = ra; +} + + +#if 0 +int +main (int argc, char *argv[]) +{ + gint i; + gint now; + GTimeVal timeval; + gdouble lat, lon; + + gtk_init (&argc, &argv); + + g_get_current_time (&timeval); + now = timeval.tv_sec; + + for (i = 0; i < now; i += 15 * 60) + { + sun_position (i, &lat, &lon); + g_print ("%d: %f %f\n", lat, lon); + } + + return 0; +} + +#endif diff --git a/applets/clock/clock-sunpos.h b/applets/clock/clock-sunpos.h new file mode 100644 index 00000000..97124505 --- /dev/null +++ b/applets/clock/clock-sunpos.h @@ -0,0 +1,8 @@ +#ifndef __CLOCK_SUNPOS_H__ +#define __CLOCK_SUNPOS_H__ + +#include + +void sun_position(time_t unix_time, gdouble *lat, gdouble *lon); + +#endif diff --git a/applets/clock/clock-utils.c b/applets/clock/clock-utils.c new file mode 100644 index 00000000..c9581e00 --- /dev/null +++ b/applets/clock/clock-utils.c @@ -0,0 +1,127 @@ +/* + * clock-utils.c + * + * Copyright (C) 2007 Vincent Untz + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + * + * Most of the original code comes from clock.c + */ + +#include "config.h" + +#ifdef HAVE_LANGINFO_H +#include +#endif + +#include + +#include + +#include "clock.h" + +#include "clock-utils.h" + +gboolean +clock_locale_supports_am_pm (void) +{ +#ifdef HAVE_NL_LANGINFO + const char *am; + + am = nl_langinfo (AM_STR); + return (am[0] != '\0'); +#else + return TRUE; +#endif +} + +ClockFormat +clock_locale_format (void) +{ + return clock_locale_supports_am_pm () ? + CLOCK_FORMAT_12 : CLOCK_FORMAT_24; +} + +void +clock_utils_display_help (GtkWidget *widget, + const char *doc_id, + const char *link_id) +{ + GError *error = NULL; + char *uri; + + if (link_id) + uri = g_strdup_printf ("ghelp:%s?%s", doc_id, link_id); + else + uri = g_strdup_printf ("ghelp:%s", doc_id); + + gtk_show_uri (gtk_widget_get_screen (widget), uri, + gtk_get_current_event_time (), &error); + + g_free (uri); + + if (error && + g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_error_free (error); + else if (error) { + GtkWidget *parent; + GtkWidget *dialog; + char *primary; + + if (GTK_IS_WINDOW (widget)) + parent = widget; + else + parent = NULL; + + primary = g_markup_printf_escaped ( + _("Could not display help document '%s'"), + doc_id); + dialog = gtk_message_dialog_new ( + parent ? GTK_WINDOW (parent) : NULL, + GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", primary); + + gtk_message_dialog_format_secondary_text ( + GTK_MESSAGE_DIALOG (dialog), + "%s", error->message); + + g_error_free (error); + g_free (primary); + + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), + NULL); + + gtk_window_set_icon_name (GTK_WINDOW (dialog), CLOCK_ICON); + gtk_window_set_screen (GTK_WINDOW (dialog), + gtk_widget_get_screen (widget)); + + if (parent == NULL) { + /* we have no parent window */ + gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), + FALSE); + gtk_window_set_title (GTK_WINDOW (dialog), + _("Error displaying help document")); + } + + gtk_widget_show (dialog); + } +} diff --git a/applets/clock/clock-utils.h b/applets/clock/clock-utils.h new file mode 100644 index 00000000..a185d9e2 --- /dev/null +++ b/applets/clock/clock-utils.h @@ -0,0 +1,57 @@ +/* + * clock-utils.h + * + * Copyright (C) 2007 Vincent Untz + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + * + * Most of the original code comes from clock.c + */ + +#ifndef __CLOCK_UTILS_H__ +#define __CLOCK_UTILS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Needs to match the indices in the combo of the prefs dialog */ +typedef enum { + CLOCK_FORMAT_INVALID = 0, + CLOCK_FORMAT_12, + CLOCK_FORMAT_24, + CLOCK_FORMAT_UNIX, + CLOCK_FORMAT_INTERNET, + CLOCK_FORMAT_CUSTOM +} ClockFormat; + +gboolean clock_locale_supports_am_pm (void); +ClockFormat clock_locale_format (void); + +void clock_utils_display_help (GtkWidget *widget, + const char *doc_id, + const char *link_id); + +#ifdef __cplusplus +} +#endif + +#endif /* __CLOCK_UTILS_H__ */ diff --git a/applets/clock/clock.c b/applets/clock/clock.c new file mode 100644 index 00000000..b4846009 --- /dev/null +++ b/applets/clock/clock.c @@ -0,0 +1,3745 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ +/* + * clock.c: the MATE clock applet + * + * Copyright (C) 1997-2003 Free Software Foundation, Inc. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Miguel de Icaza + * Frederico Mena + * Stuart Parmenter + * Alexander Larsson + * George Lebl + * Gediminas Paulauskas + * Mark McLoughlin + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef HAVE_LIBECAL +#include +#endif + +#include "clock.h" + +#include "calendar-window.h" +#include "clock-location.h" +#include "clock-location-tile.h" +#include "clock-map.h" +#include "clock-utils.h" +#include "set-timezone.h" +#include "system-timezone.h" + +#define INTERNETSECOND (864) +#define INTERNETBEAT (86400) + +#define NEVER_SENSITIVE "never_sensitive" + +#define N_MATECONF_PREFS 11 /* Keep this in sync with the number of keys below! */ +#define KEY_FORMAT "format" +#define KEY_SHOW_SECONDS "show_seconds" +#define KEY_SHOW_DATE "show_date" +#define KEY_SHOW_WEATHER "show_weather" +#define KEY_SHOW_TEMPERATURE "show_temperature" +#define KEY_CUSTOM_FORMAT "custom_format" +#define KEY_SHOW_WEEK "show_week_numbers" +#define KEY_CITIES "cities" +#define KEY_TEMPERATURE_UNIT "temperature_unit" +#define KEY_SPEED_UNIT "speed_unit" + +static MateConfEnumStringPair format_type_enum_map [] = { + { CLOCK_FORMAT_12, "12-hour" }, + { CLOCK_FORMAT_24, "24-hour" }, + { CLOCK_FORMAT_UNIX, "unix" }, + { CLOCK_FORMAT_INTERNET, "internet" }, + { CLOCK_FORMAT_CUSTOM, "custom" }, + { 0, NULL } +}; + +enum { + COL_CITY_NAME = 0, + COL_CITY_TZ, + COL_CITY_LOC, + COL_CITY_LAST +}; + +typedef struct _ClockData ClockData; + +struct _ClockData { + /* widgets */ + GtkWidget *applet; + + GtkWidget *panel_button; /* main toggle button for the whole clock */ + + GtkWidget *main_obox; /* orientable box inside panel_button */ + GtkWidget *weather_obox; /* orientable box for the weather widgets */ + + GtkWidget *clockw; /* main label for the date/time display */ + + GtkWidget *panel_weather_icon; + GtkWidget *panel_temperature_label; + + GtkWidget *props; + GtkWidget *calendar_popup; + + GtkWidget *clock_vbox; + GtkSizeGroup *clock_group; + + GtkBuilder *builder; + + /* Preferences dialog */ + GtkWidget *prefs_window; + GtkTreeView *prefs_locations; + + GtkWidget *prefs_location_add_button; + GtkWidget *prefs_location_edit_button; + GtkWidget *prefs_location_remove_button; + + MateWeatherLocationEntry *location_entry; + MateWeatherTimezoneMenu *zone_combo; + + GtkWidget *time_settings_button; + GtkWidget *calendar; + GtkWidget *hours_spin; + GtkWidget *minutes_spin; + GtkWidget *seconds_spin; + GtkWidget *set_time_button; + + GtkListStore *cities_store; + GtkWidget *cities_section; + GtkWidget *map_section; + GtkWidget *map_widget; + + /* Window to set the time */ + GtkWidget *set_time_window; + GtkWidget *current_time_label; + + /* preferences */ + ClockFormat format; + char *custom_format; + gboolean showseconds; + gboolean showdate; + gboolean showweek; + gboolean show_weather; + gboolean show_temperature; + + gboolean use_temperature_default; + gboolean use_speed_default; + TempUnit temperature_unit; + SpeedUnit speed_unit; + + /* Locations */ + GList *locations; + GList *location_tiles; + + /* runtime data */ + time_t current_time; + char *timeformat; + guint timeout; + MatePanelAppletOrient orient; + int size; + GtkAllocation old_allocation; + + SystemTimezone *systz; + + int fixed_width; + int fixed_height; + + GtkWidget *showseconds_check; + GtkWidget *showdate_check; + GtkWidget *custom_hbox; + GtkWidget *custom_label; + GtkWidget *custom_entry; + gboolean custom_format_shown; + + gboolean can_handle_format_12; + + guint listeners [N_MATECONF_PREFS]; +}; + +/* Used to count the number of clock instances. It's there to know when we + * should free resources that are shared. */ +static int clock_numbers = 0; + +static void update_clock (ClockData * cd); +static void update_tooltip (ClockData * cd); +static void update_panel_weather (ClockData *cd); +static int clock_timeout_callback (gpointer data); +static float get_itime (time_t current_time); + +static void set_atk_name_description (GtkWidget *widget, + const char *name, + const char *desc); +static void verb_display_properties_dialog (GtkAction *action, + ClockData *cd); + +static void display_properties_dialog (ClockData *cd, + gboolean start_in_locations_page); +static void display_help_dialog (GtkAction *action, + ClockData *cd); +static void display_about_dialog (GtkAction *action, + ClockData *cd); +static void position_calendar_popup (ClockData *cd); +static void update_orient (ClockData *cd); +static void applet_change_orient (MatePanelApplet *applet, + MatePanelAppletOrient orient, + ClockData *cd); + +static void edit_hide (GtkWidget *unused, ClockData *cd); +static gboolean edit_delete (GtkWidget *unused, GdkEvent *event, ClockData *cd); +static void save_cities_store (ClockData *cd); + +/* ClockBox, an instantiable GtkBox */ + +typedef GtkBox ClockBox; +typedef GtkBoxClass ClockBoxClass; + +static GType clock_box_get_type (void); + +G_DEFINE_TYPE (ClockBox, clock_box, GTK_TYPE_BOX) + +static void +clock_box_init (ClockBox *box) +{ +} + +static void +clock_box_class_init (ClockBoxClass *klass) +{ +} + +/* Clock */ + +static inline GtkWidget * +_clock_get_widget (ClockData *cd, + const char *name) +{ + return GTK_WIDGET (gtk_builder_get_object (cd->builder, name)); +} + +static void +unfix_size (ClockData *cd) +{ + cd->fixed_width = -1; + cd->fixed_height = -1; + gtk_widget_queue_resize (cd->panel_button); +} + +static int +calculate_minimum_width (GtkWidget *widget, + const gchar *text) +{ + PangoContext *context; + PangoLayout *layout; + int width, height; + int focus_width = 0; + int focus_pad = 0; + + context = gtk_widget_get_pango_context (widget); + + layout = pango_layout_new (context); + pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT); + pango_layout_set_text (layout, text, -1); + pango_layout_get_pixel_size (layout, &width, &height); + g_object_unref (G_OBJECT (layout)); + layout = NULL; + + gtk_widget_style_get (widget, + "focus-line-width", &focus_width, + "focus-padding", &focus_pad, + NULL); + + width += 2 * (focus_width + focus_pad + gtk_widget_get_style (widget)->xthickness); + + return width; +} + +static void +clock_set_timeout (ClockData *cd, + time_t now) +{ + int timeouttime; + + if (cd->format == CLOCK_FORMAT_INTERNET) { + int itime_ms; + + itime_ms = ((unsigned int) (get_itime (now) * 1000)); + + if (!cd->showseconds) + timeouttime = (999 - itime_ms % 1000) * 86.4 + 1; + else { + struct timeval tv; + gettimeofday (&tv, NULL); + itime_ms += (tv.tv_usec * 86.4) / 1000; + timeouttime = ((999 - itime_ms % 1000) * 86.4) / 100 + 1; + } + } else { + struct timeval tv; + + gettimeofday (&tv, NULL); + timeouttime = (G_USEC_PER_SEC - tv.tv_usec)/1000+1; + + /* timeout of one minute if we don't care about the seconds */ + if (cd->format != CLOCK_FORMAT_UNIX && + !cd->showseconds && + (!cd->set_time_window || !gtk_widget_get_visible (cd->set_time_window))) + timeouttime += 1000 * (59 - now % 60); + } + + cd->timeout = g_timeout_add (timeouttime, + clock_timeout_callback, + cd); +} + +static int +clock_timeout_callback (gpointer data) +{ + ClockData *cd = data; + time_t new_time; + + time (&new_time); + + if (!cd->showseconds && + (!cd->set_time_window || !gtk_widget_get_visible (cd->set_time_window)) && + cd->format != CLOCK_FORMAT_UNIX && + cd->format != CLOCK_FORMAT_CUSTOM) { + if (cd->format == CLOCK_FORMAT_INTERNET && + (unsigned int)get_itime (new_time) != + (unsigned int)get_itime (cd->current_time)) { + update_clock (cd); + } else if ((cd->format == CLOCK_FORMAT_12 || + cd->format == CLOCK_FORMAT_24) && + new_time / 60 != cd->current_time / 60) { + update_clock (cd); + } + } else { + update_clock (cd); + } + + clock_set_timeout (cd, new_time); + + return FALSE; +} + +static float +get_itime (time_t current_time) +{ + struct tm *tm; + float itime; + time_t bmt; + + /* BMT (Biel Mean Time) is GMT+1 */ + bmt = current_time + 3600; + tm = gmtime (&bmt); + itime = (tm->tm_hour*3600.0 + tm->tm_min*60.0 + tm->tm_sec)/86.4; + + return itime; +} + +/* adapted from panel-toplevel.c */ +static int +calculate_minimum_height (GtkWidget *widget, + MatePanelAppletOrient orientation) +{ + GtkStyle *style; + PangoContext *context; + PangoFontMetrics *metrics; + int focus_width = 0; + int focus_pad = 0; + int ascent; + int descent; + int thickness; + + style = gtk_widget_get_style (widget); + context = gtk_widget_get_pango_context (widget); + metrics = pango_context_get_metrics (context, + style->font_desc, + pango_context_get_language (context)); + + ascent = pango_font_metrics_get_ascent (metrics); + descent = pango_font_metrics_get_descent (metrics); + + pango_font_metrics_unref (metrics); + + gtk_widget_style_get (widget, + "focus-line-width", &focus_width, + "focus-padding", &focus_pad, + NULL); + + if (orientation == MATE_PANEL_APPLET_ORIENT_UP + || orientation == MATE_PANEL_APPLET_ORIENT_DOWN) { + thickness = style->ythickness; + } else { + thickness = style->xthickness; + } + + return PANGO_PIXELS (ascent + descent) + 2 * (focus_width + focus_pad + thickness); +} + +static gboolean +use_two_line_format (ClockData *cd) +{ + if (cd->size >= 2 * calculate_minimum_height (cd->panel_button, cd->orient)) + return TRUE; + + return FALSE; +} + +static char * +get_updated_timeformat (ClockData *cd) +{ + /* Show date in another line if panel is vertical, or + * horizontal but large enough to hold two lines of text + */ + char *result; + const char *time_format; + const char *date_format; + char *clock_format; + + if (cd->format == CLOCK_FORMAT_12) + /* Translators: This is a strftime format string. + * It is used to display the time in 12-hours format (eg, like + * in the US: 8:10 am). The %p expands to am/pm. */ + time_format = cd->showseconds ? _("%l:%M:%S %p") : _("%l:%M %p"); + else + /* Translators: This is a strftime format string. + * It is used to display the time in 24-hours format (eg, like + * in France: 20:10). */ + time_format = cd->showseconds ? _("%H:%M:%S") : _("%H:%M"); + + if (!cd->showdate) + clock_format = g_strdup (time_format); + + else { + /* Translators: This is a strftime format string. + * It is used to display the date. Replace %e with %d if, when + * the day of the month as a decimal number is a single digit, + * it should begin with a 0 in your locale (e.g. "May 01" + * instead of "May 1"). */ + date_format = _("%a %b %e"); + + if (use_two_line_format (cd)) + /* translators: reverse the order of these arguments + * if the time should come before the + * date on a clock in your locale. + */ + clock_format = g_strdup_printf (_("%1$s\n%2$s"), + date_format, + time_format); + else + /* translators: reverse the order of these arguments + * if the time should come before the + * date on a clock in your locale. + */ + clock_format = g_strdup_printf (_("%1$s, %2$s"), + date_format, + time_format); + } + + result = g_locale_from_utf8 (clock_format, -1, NULL, NULL, NULL); + g_free (clock_format); + + /* let's be paranoid */ + if (!result) + result = g_strdup ("???"); + + return result; +} + +static void +update_timeformat (ClockData *cd) +{ + g_free (cd->timeformat); + cd->timeformat = get_updated_timeformat (cd); +} + +/* sets accessible name and description for the widget */ +static void +set_atk_name_description (GtkWidget *widget, + const char *name, + const char *desc) +{ + AtkObject *obj; + obj = gtk_widget_get_accessible (widget); + + /* return if gail is not loaded */ + if (!GTK_IS_ACCESSIBLE (obj)) + return; + + if (desc != NULL) + atk_object_set_description (obj, desc); + if (name != NULL) + atk_object_set_name (obj, name); +} + +static void +update_location_tiles (ClockData *cd) +{ + GList *l; + + for (l = cd->location_tiles; l; l = l->next) { + ClockLocationTile *tile; + + tile = CLOCK_LOCATION_TILE (l->data); + clock_location_tile_refresh (tile, FALSE); + } +} + +static char * +format_time (ClockData *cd) +{ + struct tm *tm; + char hour[256]; + char *utf8; + + utf8 = NULL; + + tm = localtime (&cd->current_time); + + if (cd->format == CLOCK_FORMAT_UNIX) { + if (use_two_line_format (cd)) { + utf8 = g_strdup_printf ("%lu\n%05lu", + (unsigned long)(cd->current_time / 100000L), + (unsigned long)(cd->current_time % 100000L)); + } else { + utf8 = g_strdup_printf ("%lu", + (unsigned long)cd->current_time); + } + } else if (cd->format == CLOCK_FORMAT_INTERNET) { + float itime = get_itime (cd->current_time); + if (cd->showseconds) + utf8 = g_strdup_printf ("@%3.2f", itime); + else + utf8 = g_strdup_printf ("@%3d", (unsigned int) itime); + } else if (cd->format == CLOCK_FORMAT_CUSTOM) { + char *timeformat = g_locale_from_utf8 (cd->custom_format, -1, + NULL, NULL, NULL); + if (!timeformat) + strcpy (hour, "???"); + else if (strftime (hour, sizeof (hour), timeformat, tm) <= 0) + strcpy (hour, "???"); + g_free (timeformat); + + utf8 = g_locale_to_utf8 (hour, -1, NULL, NULL, NULL); + } else { + if (strftime (hour, sizeof (hour), cd->timeformat, tm) <= 0) + strcpy (hour, "???"); + + utf8 = g_locale_to_utf8 (hour, -1, NULL, NULL, NULL); + } + + if (!utf8) + utf8 = g_strdup (hour); + + return utf8; +} + +static gchar * +format_time_24 (ClockData *cd) +{ + struct tm *tm; + gchar buf[128]; + + tm = localtime (&cd->current_time); + strftime (buf, sizeof (buf) - 1, "%k:%M:%S", tm); + return g_locale_to_utf8 (buf, -1, NULL, NULL, NULL); +} + +static void +update_clock (ClockData * cd) +{ + gboolean use_markup; + char *utf8; + + use_markup = FALSE; + + time (&cd->current_time); + utf8 = format_time (cd); + + use_markup = FALSE; + if (pango_parse_markup (utf8, -1, 0, NULL, NULL, NULL, NULL)) + use_markup = TRUE; + + if (use_markup) + gtk_label_set_markup (GTK_LABEL (cd->clockw), utf8); + else + gtk_label_set_text (GTK_LABEL (cd->clockw), utf8); + + g_free (utf8); + + update_orient (cd); + gtk_widget_queue_resize (cd->panel_button); + + update_tooltip (cd); + update_location_tiles (cd); + + if (cd->map_widget && cd->calendar_popup && gtk_widget_get_visible (cd->calendar_popup)) + clock_map_update_time (CLOCK_MAP (cd->map_widget)); + + if (cd->current_time_label && + gtk_widget_get_visible (cd->current_time_label)) { + utf8 = format_time_24 (cd); + gtk_label_set_text (GTK_LABEL (cd->current_time_label), utf8); + g_free (utf8); + } +} + +static void +update_tooltip (ClockData * cd) +{ + if (!cd->showdate) { + struct tm *tm; + char date[256]; + char *utf8, *loc; + char *zone; + time_t now_t; + struct tm now; + char *tip; + + tm = localtime (&cd->current_time); + + utf8 = NULL; + + /* Show date in tooltip. */ + /* Translators: This is a strftime format string. + * It is used to display a date. Please leave "%%s" as it is: + * it will be used to insert the timezone name later. */ + loc = g_locale_from_utf8 (_("%A %B %d (%%s)"), -1, NULL, NULL, NULL); + if (!loc) + strcpy (date, "???"); + else if (strftime (date, sizeof (date), loc, tm) <= 0) + strcpy (date, "???"); + g_free (loc); + + utf8 = g_locale_to_utf8 (date, -1, NULL, NULL, NULL); + + /* Add the timezone name */ + + tzset (); + time (&now_t); + localtime_r (&now_t, &now); + + if (now.tm_isdst > 0) { + zone = tzname[1]; + } else { + zone = tzname[0]; + } + + tip = g_strdup_printf (utf8, zone); + + gtk_widget_set_tooltip_text (cd->panel_button, tip); + g_free (utf8); + g_free (tip); + } else { +#ifdef HAVE_LIBECAL + if (cd->calendar_popup) + gtk_widget_set_tooltip_text (cd->panel_button, + _("Click to hide your appointments and tasks")); + else + gtk_widget_set_tooltip_text (cd->panel_button, + _("Click to view your appointments and tasks")); +#else + if (cd->calendar_popup) + gtk_widget_set_tooltip_text (cd->panel_button, + _("Click to hide month calendar")); + else + gtk_widget_set_tooltip_text (cd->panel_button, + _("Click to view month calendar")); +#endif + } +} + +static void +refresh_clock (ClockData *cd) +{ + unfix_size (cd); + update_clock (cd); +} + +static void +refresh_clock_timeout(ClockData *cd) +{ + unfix_size (cd); + + update_timeformat (cd); + + if (cd->timeout) + g_source_remove (cd->timeout); + + update_clock (cd); + + clock_set_timeout (cd, cd->current_time); +} + +/** + * This is like refresh_clock_timeout(), except that we only care about whether + * the time actually changed. We don't care about the format. + */ +static void +refresh_click_timeout_time_only (ClockData *cd) +{ + if (cd->timeout) + g_source_remove (cd->timeout); + clock_timeout_callback (cd); +} + +static void +free_locations (ClockData *cd) +{ + GList *l; + + for (l = cd->locations; l; l = l->next) + g_object_unref (l->data); + + g_list_free (cd->locations); + cd->locations = NULL; +} + +static void +destroy_clock (GtkWidget * widget, ClockData *cd) +{ + MateConfClient *client; + int i; + + client = mateconf_client_get_default (); + + for (i = 0; i < N_MATECONF_PREFS; i++) + mateconf_client_notify_remove ( + client, cd->listeners [i]); + + g_object_unref (G_OBJECT (client)); + + if (cd->timeout) + g_source_remove (cd->timeout); + cd->timeout = 0; + + if (cd->props) + gtk_widget_destroy (cd->props); + cd->props = NULL; + + if (cd->calendar_popup) + gtk_widget_destroy (cd->calendar_popup); + cd->calendar_popup = NULL; + + g_free (cd->timeformat); + g_free (cd->custom_format); + + free_locations (cd); + + g_list_free (cd->location_tiles); + cd->location_tiles = NULL; + + if (cd->systz) { + g_object_unref (cd->systz); + cd->systz = NULL; + } + + if (cd->cities_store) { + g_object_unref (cd->cities_store); + cd->cities_store = NULL; + } + + if (cd->builder) { + g_object_unref (cd->builder); + cd->builder = NULL; + } + + g_free (cd); + +#ifdef HAVE_LIBECAL + if (clock_numbers > 0) { + e_passwords_shutdown (); + clock_numbers--; + } +#endif +} + +static gboolean +close_on_escape (GtkWidget *widget, + GdkEventKey *event, + GtkToggleButton *toggle_button) +{ + if (event->keyval == GDK_Escape) { + gtk_toggle_button_set_active (toggle_button, FALSE); + return TRUE; + } + + return FALSE; +} + +static gboolean +delete_event (GtkWidget *widget, + GdkEvent *event, + GtkToggleButton *toggle_button) +{ + gtk_toggle_button_set_active (toggle_button, FALSE); + return TRUE; +} + +static void +edit_locations_cb (CalendarWindow *calwin, gpointer data) +{ + ClockData *cd; + + cd = data; + + display_properties_dialog (cd, TRUE); +} + +static GtkWidget * +create_calendar (ClockData *cd) +{ + GtkWidget *window; + char *prefs_dir; + + prefs_dir = mate_panel_applet_get_preferences_key (MATE_PANEL_APPLET (cd->applet)); + window = calendar_window_new (&cd->current_time, + prefs_dir, + cd->orient == MATE_PANEL_APPLET_ORIENT_UP); + g_free (prefs_dir); + + calendar_window_set_show_weeks (CALENDAR_WINDOW (window), + cd->showweek); + calendar_window_set_time_format (CALENDAR_WINDOW (window), + cd->format); + + gtk_window_set_screen (GTK_WINDOW (window), + gtk_widget_get_screen (cd->applet)); + + g_signal_connect (window, "edit-locations", + G_CALLBACK (edit_locations_cb), cd); + + g_signal_connect (window, "delete_event", + G_CALLBACK (delete_event), cd->panel_button); + g_signal_connect (window, "key_press_event", + G_CALLBACK (close_on_escape), cd->panel_button); + + return window; +} + +static void +position_calendar_popup (ClockData *cd) +{ + GtkRequisition req; + GtkAllocation allocation; + GdkScreen *screen; + GdkRectangle monitor; + GdkGravity gravity = GDK_GRAVITY_NORTH_WEST; + int button_w, button_h; + int x, y; + int w, h; + int i, n; + gboolean found_monitor = FALSE; + + /* Get root origin of the toggle button, and position above that. */ + gdk_window_get_origin (gtk_widget_get_window (cd->panel_button), + &x, &y); + + gtk_window_get_size (GTK_WINDOW (cd->calendar_popup), &w, &h); + gtk_widget_size_request (cd->calendar_popup, &req); + w = req.width; + h = req.height; + + gtk_widget_get_allocation (cd->panel_button, &allocation); + button_w = allocation.width; + button_h = allocation.height; + + screen = gtk_window_get_screen (GTK_WINDOW (cd->calendar_popup)); + + n = gdk_screen_get_n_monitors (screen); + for (i = 0; i < n; i++) { + gdk_screen_get_monitor_geometry (screen, i, &monitor); + if (x >= monitor.x && x <= monitor.x + monitor.width && + y >= monitor.y && y <= monitor.y + monitor.height) { + found_monitor = TRUE; + break; + } + } + + if (!found_monitor) { + /* eek, we should be on one of those xinerama + monitors */ + monitor.x = 0; + monitor.y = 0; + monitor.width = gdk_screen_get_width (screen); + monitor.height = gdk_screen_get_height (screen); + } + + /* Based on panel orientation, position the popup. + * Ignore window gravity since the window is undecorated. + * The orientations are all named backward from what + * I expected. + */ + switch (cd->orient) { + case MATE_PANEL_APPLET_ORIENT_RIGHT: + x += button_w; + if ((y + h) > monitor.y + monitor.height) + y -= (y + h) - (monitor.y + monitor.height); + + if ((y + h) > (monitor.height / 2)) + gravity = GDK_GRAVITY_SOUTH_WEST; + else + gravity = GDK_GRAVITY_NORTH_WEST; + + break; + case MATE_PANEL_APPLET_ORIENT_LEFT: + x -= w; + if ((y + h) > monitor.y + monitor.height) + y -= (y + h) - (monitor.y + monitor.height); + + if ((y + h) > (monitor.height / 2)) + gravity = GDK_GRAVITY_SOUTH_EAST; + else + gravity = GDK_GRAVITY_NORTH_EAST; + + break; + case MATE_PANEL_APPLET_ORIENT_DOWN: + y += button_h; + if ((x + w) > monitor.x + monitor.width) + x -= (x + w) - (monitor.x + monitor.width); + + gravity = GDK_GRAVITY_NORTH_WEST; + + break; + case MATE_PANEL_APPLET_ORIENT_UP: + y -= h; + if ((x + w) > monitor.x + monitor.width) + x -= (x + w) - (monitor.x + monitor.width); + + gravity = GDK_GRAVITY_SOUTH_WEST; + + break; + } + + gtk_window_move (GTK_WINDOW (cd->calendar_popup), x, y); + gtk_window_set_gravity (GTK_WINDOW (cd->calendar_popup), gravity); +} + +static void +add_to_group (GtkWidget *child, gpointer data) +{ + GtkSizeGroup *group = data; + + gtk_size_group_add_widget (group, child); +} + +static void +create_clock_window (ClockData *cd) +{ + GtkWidget *locations_box; + + locations_box = calendar_window_get_locations_box (CALENDAR_WINDOW (cd->calendar_popup)); + gtk_widget_show (locations_box); + + cd->clock_vbox = gtk_vbox_new (FALSE, 6); + gtk_container_add (GTK_CONTAINER (locations_box), cd->clock_vbox); + + cd->clock_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + gtk_size_group_set_ignore_hidden (cd->clock_group, FALSE); + + gtk_container_foreach (GTK_CONTAINER (locations_box), + (GtkCallback) add_to_group, + cd->clock_group); +} + +static gint +sort_locations_by_name (gconstpointer a, gconstpointer b) +{ + ClockLocation *loc_a = (ClockLocation *) a; + ClockLocation *loc_b = (ClockLocation *) b; + + const char *name_a = clock_location_get_display_name (loc_a); + const char *name_b = clock_location_get_display_name (loc_b); + + return strcmp (name_a, name_b); +} + +static void +create_cities_store (ClockData *cd) +{ + GtkTreeIter iter; + GList *cities = cd->locations; + GList *list = NULL; + + if (cd->cities_store) { + g_object_unref (G_OBJECT (cd->cities_store)); + cd->cities_store = NULL; + } + + /* City name, Timezone name, Coordinates in lat/long */ + cd->cities_store = g_object_ref (gtk_list_store_new (COL_CITY_LAST, + G_TYPE_STRING, /* COL_CITY_NAME */ + G_TYPE_STRING, /* COL_CITY_TZ */ + CLOCK_LOCATION_TYPE)); /* COL_CITY_LOC */ + + list = g_list_copy (cities); + list = g_list_sort (list, sort_locations_by_name); + + while (list) { + ClockLocation *loc = CLOCK_LOCATION (list->data); + + gtk_list_store_append (cd->cities_store, &iter); + gtk_list_store_set (cd->cities_store, &iter, + COL_CITY_NAME, clock_location_get_display_name (loc), + /* FIXME: translate the timezone */ + COL_CITY_TZ, clock_location_get_timezone (loc), + COL_CITY_LOC, loc, + -1); + + list = list->next; + } + + + if (cd->prefs_window) { + GtkWidget *widget = _clock_get_widget (cd, "cities_list"); + gtk_tree_view_set_model (GTK_TREE_VIEW (widget), + GTK_TREE_MODEL (cd->cities_store)); + } +} + +static gint +sort_locations_by_time (gconstpointer a, gconstpointer b) +{ + ClockLocation *loc_a = (ClockLocation *) a; + ClockLocation *loc_b = (ClockLocation *) b; + + struct tm tm_a; + struct tm tm_b; + gint ret; + + clock_location_localtime (loc_a, &tm_a); + clock_location_localtime (loc_b, &tm_b); + + ret = (tm_a.tm_year == tm_b.tm_year) ? 0 : 1; + if (ret) { + return (tm_a.tm_year < tm_b.tm_year) ? -1 : 1; + } + + ret = (tm_a.tm_mon == tm_b.tm_mon) ? 0 : 1; + if (ret) { + return (tm_a.tm_mon < tm_b.tm_mon) ? -1 : 1; + } + + ret = (tm_a.tm_mday == tm_b.tm_mday) ? 0 : 1; + if (ret) { + return (tm_a.tm_mday < tm_b.tm_mday) ? -1 : 1; + } + + ret = (tm_a.tm_hour == tm_b.tm_hour) ? 0 : 1; + if (ret) { + return (tm_a.tm_hour < tm_b.tm_hour) ? -1 : 1; + } + + ret = (tm_a.tm_min == tm_b.tm_min) ? 0 : 1; + if (ret) { + return (tm_a.tm_min < tm_b.tm_min) ? -1 : 1; + } + + ret = (tm_a.tm_sec == tm_b.tm_sec) ? 0 : 1; + if (ret) { + return (tm_a.tm_sec < tm_b.tm_sec) ? -1 : 1; + } + + return ret; +} + +static void +location_tile_pressed_cb (ClockLocationTile *tile, gpointer data) +{ + ClockData *cd = data; + ClockLocation *loc; + + loc = clock_location_tile_get_location (tile); + + clock_map_blink_location (CLOCK_MAP (cd->map_widget), loc); + + g_object_unref (loc); +} + +static ClockFormat +location_tile_need_clock_format_cb(ClockLocationTile *tile, gpointer data) +{ + ClockData *cd = data; + + return cd->format; +} + +static void +create_cities_section (ClockData *cd) +{ + GList *node; + ClockLocationTile *city; + GList *cities; + + if (cd->cities_section) { + gtk_widget_destroy (cd->cities_section); + cd->cities_section = NULL; + } + + g_list_free (cd->location_tiles); + cd->location_tiles = NULL; + + cd->cities_section = gtk_vbox_new (FALSE, 6); + gtk_container_set_border_width (GTK_CONTAINER (cd->cities_section), 0); + + cities = cd->locations; + if (g_list_length (cities) == 0) { + /* if the list is empty, don't bother showing the + cities section */ + gtk_widget_hide (cd->cities_section); + return; + } + + /* Copy the existing list, so we can sort it nondestructively */ + node = g_list_copy (cities); + node = g_list_sort (node, sort_locations_by_time); + node = g_list_reverse (node); + + while (node) { + ClockLocation *loc = node->data; + + city = clock_location_tile_new (loc, CLOCK_FACE_SMALL); + g_signal_connect (city, "tile-pressed", + G_CALLBACK (location_tile_pressed_cb), cd); + g_signal_connect (city, "need-clock-format", + G_CALLBACK (location_tile_need_clock_format_cb), cd); + + gtk_box_pack_start (GTK_BOX (cd->cities_section), + GTK_WIDGET (city), + FALSE, FALSE, 0); + + cd->location_tiles = g_list_prepend (cd->location_tiles, city); + + clock_location_tile_refresh (city, TRUE); + + node = g_list_next (node); + } + + g_list_free (node); + + gtk_box_pack_end (GTK_BOX (cd->clock_vbox), + cd->cities_section, FALSE, FALSE, 0); + + gtk_widget_show_all (cd->cities_section); +} + +static GList * +map_need_locations_cb (ClockMap *map, gpointer data) +{ + ClockData *cd = data; + + return cd->locations; +} + +static void +create_map_section (ClockData *cd) +{ + ClockMap *map; + + if (cd->map_widget) { + gtk_widget_destroy (GTK_WIDGET (cd->map_section)); + cd->map_widget = NULL; + } + + map = clock_map_new (); + g_signal_connect (map, "need-locations", + G_CALLBACK (map_need_locations_cb), cd); + + cd->map_section = gtk_alignment_new (0, 0, 1, 1); + cd->map_widget = GTK_WIDGET (map); + + gtk_container_add (GTK_CONTAINER (cd->map_section), cd->map_widget); + + gtk_alignment_set_padding (GTK_ALIGNMENT (cd->map_section), 1, 1, 1, 1); + + gtk_box_pack_start (GTK_BOX (cd->clock_vbox), cd->map_section, FALSE, FALSE, 0); + gtk_widget_show (cd->map_widget); + gtk_widget_show (cd->map_section); +} + +static void +update_calendar_popup (ClockData *cd) +{ + if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cd->panel_button))) { + if (cd->calendar_popup) { + gtk_widget_destroy (cd->calendar_popup); + cd->calendar_popup = NULL; + cd->cities_section = NULL; + cd->map_section = NULL; + cd->map_widget = NULL; + cd->clock_vbox = NULL; + + g_list_free (cd->location_tiles); + cd->location_tiles = NULL; + } + update_tooltip (cd); + return; + } + + if (!cd->calendar_popup) { + cd->calendar_popup = create_calendar (cd); + g_object_add_weak_pointer (G_OBJECT (cd->calendar_popup), + (gpointer *) &cd->calendar_popup); + update_tooltip (cd); + + create_clock_window (cd); + create_cities_store (cd); + create_cities_section (cd); + create_map_section (cd); + } + + if (cd->calendar_popup && gtk_widget_get_realized (cd->panel_button)) { + calendar_window_refresh (CALENDAR_WINDOW (cd->calendar_popup)); + position_calendar_popup (cd); + gtk_window_present (GTK_WINDOW (cd->calendar_popup)); + } +} + +static void +toggle_calendar (GtkWidget *button, + ClockData *cd) +{ + /* if time is wrong, the user might try to fix it by clicking on the + * clock */ + refresh_click_timeout_time_only (cd); + update_calendar_popup (cd); +} + +static gboolean +do_not_eat_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + if (event->button != 1) + g_signal_stop_emission_by_name (widget, "button_press_event"); + + return FALSE; +} + +/* Don't request smaller size then the last one we did, this avoids + jumping when proportional fonts are used. We must take care to + call "unfix_size" whenever options are changed or such where + we'd want to forget the fixed size */ +static void +clock_size_request (GtkWidget *clock, GtkRequisition *req, gpointer data) +{ + ClockData *cd = data; + + if (req->width > cd->fixed_width) + cd->fixed_width = req->width; + if (req->height > cd->fixed_height) + cd->fixed_height = req->height; + req->width = cd->fixed_width; + req->height = cd->fixed_height; +} + +static void +clock_update_text_gravity (GtkWidget *label) +{ + PangoLayout *layout; + PangoContext *context; + + layout = gtk_label_get_layout (GTK_LABEL (label)); + context = pango_layout_get_context (layout); + pango_context_set_base_gravity (context, PANGO_GRAVITY_AUTO); +} + +static inline void +force_no_focus_padding (GtkWidget *widget) +{ + static gboolean first_time = TRUE; + + if (first_time) { + gtk_rc_parse_string ("\n" + " style \"clock-applet-button-style\"\n" + " {\n" + " GtkWidget::focus-line-width=0\n" + " GtkWidget::focus-padding=0\n" + " }\n" + "\n" + " widget \"*.clock-applet-button\" style \"clock-applet-button-style\"\n" + "\n"); + first_time = FALSE; + } + + gtk_widget_set_name (widget, "clock-applet-button"); +} + +static GtkWidget * +create_main_clock_button (void) +{ + GtkWidget *button; + + button = gtk_toggle_button_new (); + gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); + + force_no_focus_padding (button); + + return button; +} + +static GtkWidget * +create_main_clock_label (ClockData *cd) +{ + GtkWidget *label; + + label = gtk_label_new (NULL); + g_signal_connect (label, "size_request", + G_CALLBACK (clock_size_request), + cd); + g_signal_connect_swapped (label, "style_set", + G_CALLBACK (unfix_size), + cd); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER); + clock_update_text_gravity (label); + g_signal_connect (label, "screen-changed", + G_CALLBACK (clock_update_text_gravity), + NULL); + + return label; +} + +static gboolean +weather_tooltip (GtkWidget *widget, + gint x, + gint y, + gboolean keyboard_mode, + GtkTooltip *tooltip, + ClockData *cd) +{ + GList *locations, *l; + WeatherInfo *info; + + locations = cd->locations; + + for (l = locations; l; l = l->next) { + ClockLocation *location = l->data; + if (clock_location_is_current (location)) { + info = clock_location_get_weather_info (location); + if (!info || !weather_info_is_valid (info)) + continue; + + weather_info_setup_tooltip (info, location, tooltip, cd->format); + + return TRUE; + } + } + + return FALSE; +} + +static void +create_clock_widget (ClockData *cd) +{ +#ifdef HAVE_LIBECAL + clock_numbers++; + e_passwords_init (); +#endif + + /* Main toggle button */ + cd->panel_button = create_main_clock_button (); + g_signal_connect (cd->panel_button, "button_press_event", + G_CALLBACK (do_not_eat_button_press), NULL); + g_signal_connect (cd->panel_button, "toggled", + G_CALLBACK (toggle_calendar), cd); + g_signal_connect (G_OBJECT (cd->panel_button), "destroy", + G_CALLBACK (destroy_clock), + cd); + gtk_widget_show (cd->panel_button); + + /* Main orientable box */ + cd->main_obox = g_object_new (clock_box_get_type (), NULL); + gtk_box_set_spacing (GTK_BOX (cd->main_obox), 12); /* spacing between weather and time */ + gtk_container_add (GTK_CONTAINER (cd->panel_button), cd->main_obox); + gtk_widget_show (cd->main_obox); + + /* Weather orientable box */ + cd->weather_obox = g_object_new (clock_box_get_type (), NULL); + gtk_box_set_spacing (GTK_BOX (cd->weather_obox), 2); /* spacing between weather icon and temperature */ + gtk_box_pack_start (GTK_BOX (cd->main_obox), cd->weather_obox, FALSE, FALSE, 0); + gtk_widget_set_has_tooltip (cd->weather_obox, TRUE); + g_signal_connect (cd->weather_obox, "query-tooltip", + G_CALLBACK (weather_tooltip), cd); + + /* Weather widgets */ + cd->panel_weather_icon = gtk_image_new (); + gtk_box_pack_start (GTK_BOX (cd->weather_obox), cd->panel_weather_icon, FALSE, FALSE, 0); + + cd->panel_temperature_label = gtk_label_new (NULL); + gtk_box_pack_start (GTK_BOX (cd->weather_obox), cd->panel_temperature_label, FALSE, FALSE, 0); + + /* Main label for time display */ + cd->clockw = create_main_clock_label (cd); + gtk_box_pack_start (GTK_BOX (cd->main_obox), cd->clockw, FALSE, FALSE, 0); + gtk_widget_show (cd->clockw); + + /* Done! */ + + set_atk_name_description (GTK_WIDGET (cd->applet), NULL, + _("Computer Clock")); + + gtk_container_add (GTK_CONTAINER (cd->applet), cd->panel_button); + gtk_container_set_border_width (GTK_CONTAINER (cd->applet), 0); + + cd->props = NULL; + cd->orient = -1; + cd->size = mate_panel_applet_get_size (MATE_PANEL_APPLET (cd->applet)); + + update_panel_weather (cd); + + /* Refresh the clock so that it paints its first state */ + refresh_clock_timeout (cd); + applet_change_orient (MATE_PANEL_APPLET (cd->applet), + mate_panel_applet_get_orient (MATE_PANEL_APPLET (cd->applet)), + cd); +} + +static void +update_orient (ClockData *cd) +{ + const gchar *text; + int min_width; + GtkAllocation allocation; + gdouble new_angle; + gdouble angle; + + text = gtk_label_get_text (GTK_LABEL (cd->clockw)); + min_width = calculate_minimum_width (cd->panel_button, text); + gtk_widget_get_allocation (cd->panel_button, &allocation); + + if (cd->orient == MATE_PANEL_APPLET_ORIENT_LEFT && + min_width > allocation.width) + new_angle = 270; + else if (cd->orient == MATE_PANEL_APPLET_ORIENT_RIGHT && + min_width > allocation.width) + new_angle = 90; + else + new_angle = 0; + + angle = gtk_label_get_angle (GTK_LABEL (cd->clockw)); + if (angle != new_angle) { + unfix_size (cd); + gtk_label_set_angle (GTK_LABEL (cd->clockw), new_angle); + gtk_label_set_angle (GTK_LABEL (cd->panel_temperature_label), new_angle); + } +} + +/* this is when the panel orientation changes */ +static void +applet_change_orient (MatePanelApplet *applet, + MatePanelAppletOrient orient, + ClockData *cd) +{ + GtkOrientation o; + + if (orient == cd->orient) + return; + + cd->orient = orient; + + switch (cd->orient) { + case MATE_PANEL_APPLET_ORIENT_RIGHT: + o = GTK_ORIENTATION_VERTICAL; + break; + case MATE_PANEL_APPLET_ORIENT_LEFT: + o = GTK_ORIENTATION_VERTICAL; + break; + case MATE_PANEL_APPLET_ORIENT_DOWN: + o = GTK_ORIENTATION_HORIZONTAL; + break; + case MATE_PANEL_APPLET_ORIENT_UP: + o = GTK_ORIENTATION_HORIZONTAL; + break; + default: + g_assert_not_reached (); + return; + } + + gtk_orientable_set_orientation (GTK_ORIENTABLE (cd->main_obox), o); + gtk_orientable_set_orientation (GTK_ORIENTABLE (cd->weather_obox), o); + + unfix_size (cd); + update_clock (cd); + update_calendar_popup (cd); +} + +/* this is when the panel size changes */ +static void +panel_button_change_pixel_size (GtkWidget *widget, + GtkAllocation *allocation, + ClockData *cd) +{ + int new_size; + + if (cd->old_allocation.width == allocation->width && + cd->old_allocation.height == allocation->height) + return; + + cd->old_allocation.width = allocation->width; + cd->old_allocation.height = allocation->height; + + if (cd->orient == MATE_PANEL_APPLET_ORIENT_LEFT || + cd->orient == MATE_PANEL_APPLET_ORIENT_RIGHT) + new_size = allocation->width; + else + new_size = allocation->height; + + cd->size = new_size; + + unfix_size (cd); + update_timeformat (cd); + update_clock (cd); +} + +static void +copy_time (GtkAction *action, + ClockData *cd) +{ + char string[256]; + char *utf8; + + if (cd->format == CLOCK_FORMAT_UNIX) { + g_snprintf (string, sizeof(string), "%lu", + (unsigned long)cd->current_time); + } else if (cd->format == CLOCK_FORMAT_INTERNET) { + float itime = get_itime (cd->current_time); + if (cd->showseconds) + g_snprintf (string, sizeof (string), "@%3.2f", itime); + else + g_snprintf (string, sizeof (string), "@%3d", + (unsigned int) itime); + } else { + struct tm *tm; + char *format; + + if (cd->format == CLOCK_FORMAT_CUSTOM) { + format = g_locale_from_utf8 (cd->custom_format, -1, + NULL, NULL, NULL); + } else if (cd->format == CLOCK_FORMAT_12) { + if (cd->showseconds) + /* Translators: This is a strftime format + * string. + * It is used to display the time in 12-hours + * format with a leading 0 if needed (eg, like + * in the US: 08:10 am). The %p expands to + * am/pm. */ + format = g_locale_from_utf8 (_("%I:%M:%S %p"), -1, NULL, NULL, NULL); + else + /* Translators: This is a strftime format + * string. + * It is used to display the time in 12-hours + * format with a leading 0 if needed (eg, like + * in the US: 08:10 am). The %p expands to + * am/pm. */ + format = g_locale_from_utf8 (_("%I:%M %p"), -1, NULL, NULL, NULL); + } else { + if (cd->showseconds) + /* Translators: This is a strftime format + * string. + * It is used to display the time in 24-hours + * format (eg, like in France: 20:10). */ + format = g_locale_from_utf8 (_("%H:%M:%S"), -1, NULL, NULL, NULL); + else + /* Translators: This is a strftime format + * string. + * It is used to display the time in 24-hours + * format (eg, like in France: 20:10). */ + format = g_locale_from_utf8 (_("%H:%M"), -1, NULL, NULL, NULL); + } + + tm = localtime (&cd->current_time); + + if (!format) + strcpy (string, "???"); + else if (strftime (string, sizeof (string), format, tm) <= 0) + strcpy (string, "???"); + g_free (format); + } + + utf8 = g_locale_to_utf8 (string, -1, NULL, NULL, NULL); + gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY), + utf8, -1); + gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), + utf8, -1); + g_free (utf8); +} + +static void +copy_date (GtkAction *action, + ClockData *cd) +{ + struct tm *tm; + char string[256]; + char *utf8, *loc; + + tm = localtime (&cd->current_time); + + /* Translators: This is a strftime format string. + * It is used to display a date in the full format (so that people can + * copy and paste it elsewhere). */ + loc = g_locale_from_utf8 (_("%A, %B %d %Y"), -1, NULL, NULL, NULL); + if (!loc) + strcpy (string, "???"); + else if (strftime (string, sizeof (string), loc, tm) <= 0) + strcpy (string, "???"); + g_free (loc); + + utf8 = g_locale_to_utf8 (string, -1, NULL, NULL, NULL); + gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY), + utf8, -1); + gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), + utf8, -1); + g_free (utf8); +} + +static void +update_set_time_button (ClockData *cd) +{ + gint can_set; + + /* this returns more than just a boolean; check the documentation of + * the dbus method for more information */ + can_set = can_set_system_time (); + + if (cd->time_settings_button) + gtk_widget_set_sensitive (cd->time_settings_button, can_set); + + if (cd->set_time_button) { + gtk_widget_set_sensitive (cd->set_time_button, can_set != 0); + gtk_button_set_label (GTK_BUTTON (cd->set_time_button), + can_set == 1 ? + _("Set System Time...") : + _("Set System Time")); + } +} + +static void +set_time_callback (ClockData *cd, GError *error) +{ + GtkWidget *window; + GtkWidget *dialog; + + if (error) { + dialog = gtk_message_dialog_new (NULL, + 0, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Failed to set the system time")); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + gtk_window_present (GTK_WINDOW (dialog)); + + g_error_free (error); + } + else + update_set_time_button (cd); + + window = _clock_get_widget (cd, "set-time-window"); + gtk_widget_hide (window); +} + +static void +set_time (GtkWidget *widget, ClockData *cd) +{ + struct tm t; + time_t tim; + guint year, month, day; + + time (&tim); + /* sets t.isdst -- we could set it to -1 to have mktime() guess the + * right value , but we don't know if this works with all libc */ + localtime_r (&tim, &t); + + t.tm_sec = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (cd->seconds_spin)); + t.tm_min = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (cd->minutes_spin)); + t.tm_hour = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (cd->hours_spin)); + gtk_calendar_get_date (GTK_CALENDAR (cd->calendar), &year, &month, &day); + t.tm_year = year - 1900; + t.tm_mon = month; + t.tm_mday = day; + + tim = mktime (&t); + + set_system_time_async (tim, (GFunc)set_time_callback, cd, NULL); +} + +static void +cancel_time_settings (GtkWidget *button, ClockData *cd) +{ + gtk_widget_hide (cd->set_time_window); + + refresh_click_timeout_time_only (cd); +} + +static gboolean +delete_time_settings (GtkWidget *widget, GdkEvent *event, gpointer data) +{ + cancel_time_settings (widget, data); + + return TRUE; +} + +static void +fill_time_settings_window (ClockData *cd) +{ + time_t now_t; + struct tm now; + + /* Fill the time settings */ + tzset (); + time (&now_t); + localtime_r (&now_t, &now); + + gtk_spin_button_set_value (GTK_SPIN_BUTTON (cd->seconds_spin), now.tm_sec); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (cd->minutes_spin), now.tm_min); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (cd->hours_spin), now.tm_hour); + + gtk_calendar_select_month (GTK_CALENDAR (cd->calendar), now.tm_mon, + now.tm_year + 1900); + gtk_calendar_select_day (GTK_CALENDAR (cd->calendar), now.tm_mday); +} + +static void +wrap_cb (GtkSpinButton *spin, ClockData *cd) +{ + gdouble value; + gdouble min, max; + GtkSpinType direction; + + value = gtk_spin_button_get_value (spin); + gtk_spin_button_get_range (spin, &min, &max); + + if (value == min) + direction = GTK_SPIN_STEP_FORWARD; + else + direction = GTK_SPIN_STEP_BACKWARD; + + if (spin == (GtkSpinButton *) cd->seconds_spin) + gtk_spin_button_spin (GTK_SPIN_BUTTON (cd->minutes_spin), direction, 1.0); + else if (spin == (GtkSpinButton *) cd->minutes_spin) + gtk_spin_button_spin (GTK_SPIN_BUTTON (cd->hours_spin), direction, 1.0); + else { + guint year, month, day; + GDate *date; + + gtk_calendar_get_date (GTK_CALENDAR (cd->calendar), &year, &month, &day); + + date = g_date_new_dmy (day, month + 1, year); + + if (direction == GTK_SPIN_STEP_FORWARD) + g_date_add_days (date, 1); + else + g_date_subtract_days (date, 1); + + year = g_date_get_year (date); + month = g_date_get_month (date) - 1; + day = g_date_get_day (date); + + gtk_calendar_select_month (GTK_CALENDAR (cd->calendar), month, year); + gtk_calendar_select_day (GTK_CALENDAR (cd->calendar), day); + + g_date_free (date); + } +} + +static gboolean +output_cb (GtkSpinButton *spin, + gpointer data) +{ + GtkAdjustment *adj; + gchar *text; + int value; + + adj = gtk_spin_button_get_adjustment (spin); + value = (int) gtk_adjustment_get_value (adj); + text = g_strdup_printf ("%02d", value); + gtk_entry_set_text (GTK_ENTRY (spin), text); + g_free (text); + + return TRUE; +} + +static void +ensure_time_settings_window_is_created (ClockData *cd) +{ + GtkWidget *cancel_button; + + if (cd->set_time_window) + return; + + cd->set_time_window = _clock_get_widget (cd, "set-time-window"); + g_signal_connect (cd->set_time_window, "delete_event", + G_CALLBACK (delete_time_settings), cd); + + cd->calendar = _clock_get_widget (cd, "calendar"); + cd->hours_spin = _clock_get_widget (cd, "hours_spin"); + cd->minutes_spin = _clock_get_widget (cd, "minutes_spin"); + cd->seconds_spin = _clock_get_widget (cd, "seconds_spin"); + + gtk_entry_set_width_chars (GTK_ENTRY (cd->hours_spin), 2); + gtk_entry_set_width_chars (GTK_ENTRY (cd->minutes_spin), 2); + gtk_entry_set_width_chars (GTK_ENTRY (cd->seconds_spin), 2); + gtk_entry_set_alignment (GTK_ENTRY (cd->hours_spin), 1.0); + gtk_entry_set_alignment (GTK_ENTRY (cd->minutes_spin), 1.0); + gtk_entry_set_alignment (GTK_ENTRY (cd->seconds_spin), 1.0); + g_signal_connect (cd->seconds_spin, "wrapped", G_CALLBACK (wrap_cb), cd); + g_signal_connect (cd->minutes_spin, "wrapped", G_CALLBACK (wrap_cb), cd); + g_signal_connect (cd->hours_spin, "wrapped", G_CALLBACK (wrap_cb), cd); + + g_signal_connect (cd->minutes_spin, "output", G_CALLBACK (output_cb), cd); + g_signal_connect (cd->seconds_spin, "output", G_CALLBACK (output_cb), cd); + + cd->set_time_button = _clock_get_widget (cd, "set-time-button"); + g_signal_connect (cd->set_time_button, "clicked", G_CALLBACK (set_time), cd); + + cancel_button = _clock_get_widget (cd, "cancel-set-time-button"); + g_signal_connect (cancel_button, "clicked", G_CALLBACK (cancel_time_settings), cd); + + cd->current_time_label = _clock_get_widget (cd, "current_time_label"); +} + +static void +run_time_settings (GtkWidget *unused, ClockData *cd) +{ + ensure_time_settings_window_is_created (cd); + fill_time_settings_window (cd); + + update_set_time_button (cd); + + gtk_window_present (GTK_WINDOW (cd->set_time_window)); + + refresh_click_timeout_time_only (cd); +} + +static void +config_date (GtkAction *action, + ClockData *cd) +{ + run_time_settings (NULL, cd); +} + +/* current timestamp */ +static const GtkActionEntry clock_menu_actions [] = { + { "ClockPreferences", GTK_STOCK_PROPERTIES, N_("_Preferences"), + NULL, NULL, + G_CALLBACK (verb_display_properties_dialog) }, + { "ClockHelp", GTK_STOCK_HELP, N_("_Help"), + NULL, NULL, + G_CALLBACK (display_help_dialog) }, + { "ClockAbout", GTK_STOCK_ABOUT, N_("_About"), + NULL, NULL, + G_CALLBACK (display_about_dialog) }, + { "ClockCopyTime", GTK_STOCK_COPY, N_("Copy _Time"), + NULL, NULL, + G_CALLBACK (copy_time) }, + { "ClockCopyDate", GTK_STOCK_COPY, N_("Copy _Date"), + NULL, NULL, + G_CALLBACK (copy_date) }, + { "ClockConfig", GTK_STOCK_PREFERENCES, N_("Ad_just Date & Time"), + NULL, NULL, + G_CALLBACK (config_date) } +}; + +static void +format_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + ClockData *clock) +{ + const char *value; + int new_format; + + if (!entry->value || entry->value->type != MATECONF_VALUE_STRING) + return; + + value = mateconf_value_get_string (entry->value); + if (!mateconf_string_to_enum (format_type_enum_map, value, &new_format)) + return; + + if (!clock->can_handle_format_12 && new_format == CLOCK_FORMAT_12) + new_format = CLOCK_FORMAT_24; + + if (new_format == clock->format) + return; + + clock->format = new_format; + refresh_clock_timeout (clock); + + if (clock->calendar_popup != NULL) { + calendar_window_set_time_format (CALENDAR_WINDOW (clock->calendar_popup), clock->format); + position_calendar_popup (clock); + } + +} + +static void +show_seconds_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + ClockData *clock) +{ + gboolean value; + + if (!entry->value || entry->value->type != MATECONF_VALUE_BOOL) + return; + + value = mateconf_value_get_bool (entry->value); + + clock->showseconds = (value != 0); + refresh_clock_timeout (clock); +} + +static void +show_date_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + ClockData *clock) +{ + gboolean value; + + if (!entry->value || entry->value->type != MATECONF_VALUE_BOOL) + return; + + value = mateconf_value_get_bool (entry->value); + + clock->showdate = (value != 0); + update_timeformat (clock); + refresh_clock (clock); +} + +static void +update_panel_weather (ClockData *cd) +{ + if (cd->show_weather) + gtk_widget_show (cd->panel_weather_icon); + else + gtk_widget_hide (cd->panel_weather_icon); + + if (cd->show_temperature) + gtk_widget_show (cd->panel_temperature_label); + else + gtk_widget_hide (cd->panel_temperature_label); + + if ((cd->show_weather || cd->show_temperature) && + g_list_length (cd->locations) > 0) + gtk_widget_show (cd->weather_obox); + else + gtk_widget_hide (cd->weather_obox); + + gtk_widget_queue_resize (cd->applet); +} + +static void +update_weather_bool_value_and_toggle_from_mateconf (ClockData *cd, MateConfEntry *entry, + gboolean *value_loc, const char *widget_name) +{ + GtkWidget *widget; + gboolean value; + + if (!entry->value || entry->value->type != MATECONF_VALUE_BOOL) + return; + + value = mateconf_value_get_bool (entry->value); + + *value_loc = (value != 0); + + widget = _clock_get_widget (cd, widget_name); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), + *value_loc); + + update_panel_weather (cd); +} + +static void +show_weather_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + ClockData *cd) +{ + update_weather_bool_value_and_toggle_from_mateconf (cd, entry, &cd->show_weather, "weather_check"); +} + +static void +show_temperature_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + ClockData *cd) +{ + update_weather_bool_value_and_toggle_from_mateconf (cd, entry, &cd->show_temperature, "temperature_check"); +} + +static void +location_weather_updated_cb (ClockLocation *location, + WeatherInfo *info, + gpointer data) +{ + ClockData *cd = data; + const gchar *icon_name; + const gchar *temp; + GtkIconTheme *theme; + GdkPixbuf *pixbuf; + + if (!info || !weather_info_is_valid (info)) + return; + + if (!clock_location_is_current (location)) + return; + + icon_name = weather_info_get_icon_name (info); + /* FIXME: mmh, screen please? Also, don't hardcode to 16 */ + theme = gtk_icon_theme_get_default (); + pixbuf = gtk_icon_theme_load_icon (theme, icon_name, 16, + GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL); + + temp = weather_info_get_temp_summary (info); + + gtk_image_set_from_pixbuf (GTK_IMAGE (cd->panel_weather_icon), pixbuf); + gtk_label_set_text (GTK_LABEL (cd->panel_temperature_label), temp); +} + +static void +location_set_current_cb (ClockLocation *loc, + gpointer data) +{ + ClockData *cd = data; + WeatherInfo *info; + + info = clock_location_get_weather_info (loc); + location_weather_updated_cb (loc, info, cd); + + if (cd->map_widget) + clock_map_refresh (CLOCK_MAP (cd->map_widget)); + update_location_tiles (cd); + save_cities_store (cd); +} + +static void +locations_changed (ClockData *cd) +{ + GList *l; + ClockLocation *loc; + glong id; + + if (!cd->locations) { + if (cd->weather_obox) + gtk_widget_hide (cd->weather_obox); + if (cd->panel_weather_icon) + gtk_image_set_from_pixbuf (GTK_IMAGE (cd->panel_weather_icon), + NULL); + if (cd->panel_temperature_label) + gtk_label_set_text (GTK_LABEL (cd->panel_temperature_label), + ""); + } else { + if (cd->weather_obox) + gtk_widget_show (cd->weather_obox); + } + + for (l = cd->locations; l; l = l->next) { + loc = l->data; + + id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (loc), "weather-updated")); + if (id == 0) { + id = g_signal_connect (loc, "weather-updated", + G_CALLBACK (location_weather_updated_cb), cd); + g_object_set_data (G_OBJECT (loc), "weather-updated", GINT_TO_POINTER (id)); + g_signal_connect (loc, "set-current", + G_CALLBACK (location_set_current_cb), cd); + } + } + + if (cd->map_widget) + clock_map_refresh (CLOCK_MAP (cd->map_widget)); + + if (cd->clock_vbox) + create_cities_section (cd); +} + + +static void +set_locations (ClockData *cd, GList *locations) +{ + free_locations (cd); + cd->locations = locations; + locations_changed (cd); +} + +typedef struct { + GList *cities; + ClockData *cd; +} LocationParserData; + +/* Parser for our serialized locations in mateconf */ +static void +location_start_element (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + ClockLocation *loc; + LocationParserData *data = user_data; + ClockData *cd = data->cd; + WeatherPrefs prefs; + const gchar *att_name; + + gchar *name = NULL; + gchar *city = NULL; + gchar *timezone = NULL; + gfloat latitude = 0.0; + gfloat longitude = 0.0; + gchar *code = NULL; + gboolean current = FALSE; + + int index = 0; + + prefs.temperature_unit = cd->temperature_unit; + prefs.speed_unit = cd->speed_unit; + + if (strcmp (element_name, "location") != 0) { + return; + } + + setlocale (LC_NUMERIC, "POSIX"); + + for (att_name = attribute_names[index]; att_name != NULL; + att_name = attribute_names[++index]) { + if (strcmp (att_name, "name") == 0) { + name = (gchar *)attribute_values[index]; + } else if (strcmp (att_name, "city") == 0) { + city = (gchar *)attribute_values[index]; + } else if (strcmp (att_name, "timezone") == 0) { + timezone = (gchar *)attribute_values[index]; + } else if (strcmp (att_name, "latitude") == 0) { + sscanf (attribute_values[index], "%f", &latitude); + } else if (strcmp (att_name, "longitude") == 0) { + sscanf (attribute_values[index], "%f", &longitude); + } else if (strcmp (att_name, "code") == 0) { + code = (gchar *)attribute_values[index]; + } + else if (strcmp (att_name, "current") == 0) { + if (strcmp (attribute_values[index], "true") == 0) { + current = TRUE; + } + } + } + + setlocale (LC_NUMERIC, ""); + + if ((!name && !city) || !timezone) { + return; + } + + /* migration from the old configuration, when name == city */ + if (!city) + city = name; + + loc = clock_location_find_and_ref (cd->locations, name, city, + timezone, latitude, longitude, code); + if (!loc) + loc = clock_location_new (name, city, timezone, + latitude, longitude, code, &prefs); + + if (current && clock_location_is_current_timezone (loc)) + clock_location_make_current (loc, GDK_WINDOW_XWINDOW (gtk_widget_get_window (cd->applet)), + NULL, NULL, NULL); + + data->cities = g_list_append (data->cities, loc); +} + +static GMarkupParser location_parser = { + location_start_element, NULL, NULL, NULL, NULL +}; + +static void +cities_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + ClockData *cd) +{ + LocationParserData data; + + GSList *cur = NULL; + + GMarkupParseContext *context; + + data.cities = NULL; + data.cd = cd; + + if (!entry->value || entry->value->type != MATECONF_VALUE_LIST) + return; + + context = g_markup_parse_context_new (&location_parser, 0, &data, NULL); + + cur = mateconf_value_get_list (entry->value); + + while (cur) { + const char *str = mateconf_value_get_string (cur->data); + g_markup_parse_context_parse (context, str, strlen (str), NULL); + + cur = cur->next; + } + + g_markup_parse_context_free (context); + + set_locations (cd, data.cities); + create_cities_store (cd); +} + +static void +update_temperature_combo (ClockData *cd) +{ + GtkWidget *widget; + int active_index; + + widget = _clock_get_widget (cd, "temperature_combo"); + + if (cd->use_temperature_default) + active_index = 0; + else + active_index = cd->temperature_unit - 1; + + gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active_index); +} + +static void +update_weather_locations (ClockData *cd) +{ + GList *locations, *l; + WeatherPrefs prefs = { + FORECAST_STATE, + FALSE, + NULL, + TEMP_UNIT_CENTIGRADE, + SPEED_UNIT_MS, + PRESSURE_UNIT_MB, + DISTANCE_UNIT_KM + }; + + prefs.temperature_unit = cd->temperature_unit; + prefs.speed_unit = cd->speed_unit; + + locations = cd->locations; + + for (l = locations; l; l = l->next) { + clock_location_set_weather_prefs (l->data, &prefs); + } +} + +static void +clock_migrate_to_26 (ClockData *clock) +{ + gboolean unixtime; + gboolean internettime; + int hourformat; + + internettime = mate_panel_applet_mateconf_get_bool (MATE_PANEL_APPLET (clock->applet), + "internet_time", + NULL); + unixtime = mate_panel_applet_mateconf_get_bool (MATE_PANEL_APPLET (clock->applet), + "unix_time", + NULL); + hourformat = mate_panel_applet_mateconf_get_int (MATE_PANEL_APPLET (clock->applet), + "hour_format", + NULL); + + if (unixtime) + clock->format = CLOCK_FORMAT_UNIX; + else if (internettime) + clock->format = CLOCK_FORMAT_INTERNET; + else if (hourformat == 12) + clock->format = CLOCK_FORMAT_12; + else if (hourformat == 24) + clock->format = CLOCK_FORMAT_24; + + /* It's still possible that we have none of the old keys, in which case + * we're not migrating from 2.6, but the config is simply wrong. So + * don't set the format key in this case. */ + if (clock->format != CLOCK_FORMAT_INVALID) + mate_panel_applet_mateconf_set_string (MATE_PANEL_APPLET (clock->applet), + KEY_FORMAT, + mateconf_enum_to_string (format_type_enum_map, + clock->format), + NULL); +} + +static void +clock_timezone_changed (SystemTimezone *systz, + const char *new_tz, + ClockData *cd) +{ + /* This will refresh the current location */ + save_cities_store (cd); + + refresh_click_timeout_time_only (cd); +} + +static void +parse_and_set_temperature_string (const char *str, ClockData *cd) +{ + gint value = 0; + gboolean use_default = FALSE; + + value = mateweather_prefs_parse_temperature (str, &use_default); + + cd->use_temperature_default = use_default; + cd->temperature_unit = value; +} + +static void +parse_and_set_speed_string (const char *str, ClockData *cd) +{ + gint value = 0; + gboolean use_default = FALSE; + + value = mateweather_prefs_parse_speed (str, &use_default); + + cd->use_speed_default = use_default; + cd->speed_unit = value; +} + +static void +temperature_unit_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + ClockData *cd) +{ + const gchar *value; + + if (!entry->value || entry->value->type != MATECONF_VALUE_STRING) + return; + + value = mateconf_value_get_string (entry->value); + parse_and_set_temperature_string (value, cd); + update_temperature_combo (cd); + update_weather_locations (cd); +} + +static void +update_speed_combo (ClockData *cd) +{ + GtkWidget *widget; + int active_index; + + widget = _clock_get_widget (cd, "wind_speed_combo"); + + if (cd->use_speed_default) + active_index = 0; + else + active_index = cd->speed_unit - 1; + + gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active_index); +} + +static void +speed_unit_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + ClockData *cd) +{ + const gchar *value; + + if (!entry->value || entry->value->type != MATECONF_VALUE_STRING) + return; + + value = mateconf_value_get_string (entry->value); + parse_and_set_speed_string (value, cd); + update_speed_combo (cd); + update_weather_locations (cd); +} + +static void +custom_format_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + ClockData *clock) +{ + const char *value; + + if (!entry->value || entry->value->type != MATECONF_VALUE_STRING) + return; + + value = mateconf_value_get_string (entry->value); + + g_free (clock->custom_format); + clock->custom_format = g_strdup (value); + + if (clock->format == CLOCK_FORMAT_CUSTOM) + refresh_clock (clock); +} + +static void +show_week_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + ClockData *clock) +{ + gboolean value; + + if (!entry->value || entry->value->type != MATECONF_VALUE_BOOL) + return; + + value = mateconf_value_get_bool (entry->value); + + if (clock->showweek == (value != 0)) + return; + + clock->showweek = (value != 0); + + if (clock->calendar_popup != NULL) { + calendar_window_set_show_weeks (CALENDAR_WINDOW (clock->calendar_popup), clock->showweek); + position_calendar_popup (clock); + } +} + +static guint +setup_mateconf_preference (ClockData *cd, MateConfClient *client, const char *key_name, MateConfClientNotifyFunc callback) +{ + char *key; + guint id; + + key = mate_panel_applet_mateconf_get_full_key (MATE_PANEL_APPLET (cd->applet), + key_name); + id = mateconf_client_notify_add (client, key, + callback, + cd, NULL, NULL); + g_free (key); + + return id; +} + +static void +setup_mateconf (ClockData *cd) +{ + struct { + const char *key_name; + MateConfClientNotifyFunc callback; + } prefs[] = { + { KEY_FORMAT, (MateConfClientNotifyFunc) format_changed }, + { KEY_SHOW_SECONDS, (MateConfClientNotifyFunc) show_seconds_changed }, + { KEY_SHOW_DATE, (MateConfClientNotifyFunc) show_date_changed }, + { KEY_SHOW_WEATHER, (MateConfClientNotifyFunc) show_weather_changed }, + { KEY_SHOW_TEMPERATURE, (MateConfClientNotifyFunc) show_temperature_changed }, + { KEY_CUSTOM_FORMAT, (MateConfClientNotifyFunc) custom_format_changed }, + { KEY_SHOW_WEEK, (MateConfClientNotifyFunc) show_week_changed }, + { KEY_CITIES, (MateConfClientNotifyFunc) cities_changed }, + { KEY_TEMPERATURE_UNIT, (MateConfClientNotifyFunc) temperature_unit_changed }, + { KEY_SPEED_UNIT, (MateConfClientNotifyFunc) speed_unit_changed }, + }; + + MateConfClient *client; + int i; + + client = mateconf_client_get_default (); + + for (i = 0; i < G_N_ELEMENTS (prefs); i++) + cd->listeners[i] = setup_mateconf_preference (cd, client, prefs[i].key_name, prefs[i].callback); + + g_object_unref (G_OBJECT (client)); +} + +static GList * +parse_mateconf_cities (ClockData *cd, GSList *values) +{ + GSList *cur = values; + LocationParserData data; + GMarkupParseContext *context; + + data.cities = NULL; + data.cd = cd; + + context = + g_markup_parse_context_new (&location_parser, 0, &data, NULL); + + while (cur) { + const char *str = (char *)cur->data; + g_markup_parse_context_parse (context, str, strlen(str), NULL); + + cur = cur->next; + } + + g_markup_parse_context_free (context); + + return data.cities; +} + +static void +load_mateconf_settings (ClockData *cd) +{ + MatePanelApplet *applet; + int format; + char *format_str; + char *value; + GError *error; + GSList *values = NULL; + GList *cities = NULL; + + applet = MATE_PANEL_APPLET (cd->applet); + + cd->format = CLOCK_FORMAT_INVALID; + + format_str = mate_panel_applet_mateconf_get_string (applet, KEY_FORMAT, NULL); + if (format_str && + mateconf_string_to_enum (format_type_enum_map, format_str, &format)) + cd->format = format; + else + clock_migrate_to_26 (cd); + + g_free (format_str); + + if (cd->format == CLOCK_FORMAT_INVALID) + cd->format = clock_locale_format (); + + cd->custom_format = mate_panel_applet_mateconf_get_string (applet, KEY_CUSTOM_FORMAT, NULL); + cd->showseconds = mate_panel_applet_mateconf_get_bool (applet, KEY_SHOW_SECONDS, NULL); + + error = NULL; + cd->showdate = mate_panel_applet_mateconf_get_bool (applet, KEY_SHOW_DATE, &error); + if (error) { + g_error_free (error); + /* if on a small screen don't show date by default */ + if (gdk_screen_width () <= 800) + cd->showdate = FALSE; + else + cd->showdate = TRUE; + } + + cd->show_weather = mate_panel_applet_mateconf_get_bool (applet, KEY_SHOW_WEATHER, NULL); + cd->show_temperature = mate_panel_applet_mateconf_get_bool (applet, KEY_SHOW_TEMPERATURE, NULL); + cd->showweek = mate_panel_applet_mateconf_get_bool (applet, KEY_SHOW_WEEK, NULL); + cd->timeformat = NULL; + + cd->can_handle_format_12 = (clock_locale_format () == CLOCK_FORMAT_12); + if (!cd->can_handle_format_12 && cd->format == CLOCK_FORMAT_12) + cd->format = CLOCK_FORMAT_24; + + value = mate_panel_applet_mateconf_get_string (applet, KEY_TEMPERATURE_UNIT, NULL); + parse_and_set_temperature_string (value, cd); + g_free (value); + + value = mate_panel_applet_mateconf_get_string (applet, KEY_SPEED_UNIT, NULL); + parse_and_set_speed_string (value, cd); + g_free (value); + + values = mate_panel_applet_mateconf_get_list (MATE_PANEL_APPLET (cd->applet), KEY_CITIES, + MATECONF_VALUE_STRING, NULL); + + if (g_slist_length (values) == 0) { + cities = NULL; + } else { + cities = parse_mateconf_cities (cd, values); + } + + set_locations (cd, cities); +} + +static gboolean +fill_clock_applet (MatePanelApplet *applet) +{ + ClockData *cd; + GtkActionGroup *action_group; + GtkAction *action; + gchar *ui_path; + char *filename; + GError *error; + + mate_panel_applet_add_preferences (applet, CLOCK_SCHEMA_DIR, NULL); + mate_panel_applet_set_flags (applet, MATE_PANEL_APPLET_EXPAND_MINOR); + + cd = g_new0 (ClockData, 1); + cd->fixed_width = -1; + cd->fixed_height = -1; + + cd->applet = GTK_WIDGET (applet); + + setup_mateconf (cd); + load_mateconf_settings (cd); + + cd->builder = gtk_builder_new (); + gtk_builder_set_translation_domain (cd->builder, GETTEXT_PACKAGE); + filename = g_build_filename (BUILDERDIR, "clock.ui", NULL); + + error = NULL; + gtk_builder_add_from_file (cd->builder, filename, &error); + if (error) { + g_warning ("Error loading \"%s\": %s", + filename, error->message); + g_error_free (error); + } + + g_free (filename); + + create_clock_widget (cd); + +#ifndef CLOCK_INPROCESS + gtk_window_set_default_icon_name (CLOCK_ICON); +#endif + gtk_widget_show (cd->applet); + + /* FIXME: Update this comment. */ + /* we have to bind change_orient before we do applet_widget_add + since we need to get an initial change_orient signal to set our + initial oriantation, and we get that during the _add call */ + g_signal_connect (G_OBJECT (cd->applet), + "change_orient", + G_CALLBACK (applet_change_orient), + cd); + + g_signal_connect (G_OBJECT (cd->panel_button), + "size_allocate", + G_CALLBACK (panel_button_change_pixel_size), + cd); + + mate_panel_applet_set_background_widget (MATE_PANEL_APPLET (cd->applet), + GTK_WIDGET (cd->applet)); + + action_group = gtk_action_group_new ("ClockApplet Menu Actions"); + gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); + gtk_action_group_add_actions (action_group, + clock_menu_actions, + G_N_ELEMENTS (clock_menu_actions), + cd); + ui_path = g_build_filename (CLOCK_MENU_UI_DIR, "clock-menu.xml", NULL); + mate_panel_applet_setup_menu_from_file (MATE_PANEL_APPLET (cd->applet), + ui_path, action_group); + g_free (ui_path); + + if (mate_panel_applet_get_locked_down (MATE_PANEL_APPLET (cd->applet))) { + action = gtk_action_group_get_action (action_group, "ClockPreferences"); + gtk_action_set_visible (action, FALSE); + + action = gtk_action_group_get_action (action_group, "ClockConfig"); + gtk_action_set_visible (action, FALSE); + } + + cd->systz = system_timezone_new (); + g_signal_connect (cd->systz, "changed", + G_CALLBACK (clock_timezone_changed), cd); + + action = gtk_action_group_get_action (action_group, "ClockConfig"); + gtk_action_set_visible (action, can_set_system_time ()); + g_object_unref (action_group); + + return TRUE; +} + +/* FIXME old clock applet */ +#if 0 +static void +setup_writability_sensitivity (ClockData *clock, GtkWidget *w, GtkWidget *label, const char *key) +{ + /* FMQ: was used from old preferences dialog; fix this up */ + char *fullkey; + MateConfClient *client; + + client = mateconf_client_get_default (); + + fullkey = mate_panel_applet_mateconf_get_full_key + (MATE_PANEL_APPLET (clock->applet), key); + + if ( ! mateconf_client_key_is_writable (client, fullkey, NULL)) { + g_object_set_data (G_OBJECT (w), NEVER_SENSITIVE, + GINT_TO_POINTER (1)); + gtk_widget_set_sensitive (w, FALSE); + if (label != NULL) { + g_object_set_data (G_OBJECT (label), NEVER_SENSITIVE, + GINT_TO_POINTER (1)); + gtk_widget_set_sensitive (label, FALSE); + } + } + + g_free (fullkey); + + g_object_unref (G_OBJECT (client)); +} + +static void +update_properties_for_format (ClockData *cd, + GtkComboBox *combo, + ClockFormat format) +{ + + /* show the custom format things the first time we actually + * have a custom format set in MateConf, but after that don't + * unshow it if the format changes + */ + if (!cd->custom_format_shown && + (cd->format == CLOCK_FORMAT_CUSTOM || + (cd->custom_format && cd->custom_format [0]))) { + gtk_widget_show (cd->custom_hbox); + gtk_widget_show (cd->custom_label); + gtk_widget_show (cd->custom_entry); + + gtk_combo_box_append_text (combo, _("Custom format")); + + cd->custom_format_shown = TRUE; + } + + /* Some combinations of options do not make sense */ + switch (format) { + case CLOCK_FORMAT_12: + case CLOCK_FORMAT_24: + gtk_widget_set_sensitive (cd->showseconds_check, TRUE); + gtk_widget_set_sensitive (cd->showdate_check, TRUE); + gtk_widget_set_sensitive (cd->custom_entry, FALSE); + gtk_widget_set_sensitive (cd->custom_label, FALSE); + break; + case CLOCK_FORMAT_UNIX: + gtk_widget_set_sensitive (cd->showseconds_check, FALSE); + gtk_widget_set_sensitive (cd->showdate_check, FALSE); + gtk_widget_set_sensitive (cd->custom_entry, FALSE); + gtk_widget_set_sensitive (cd->custom_label, FALSE); + break; + case CLOCK_FORMAT_INTERNET: + gtk_widget_set_sensitive (cd->showseconds_check, TRUE); + gtk_widget_set_sensitive (cd->showdate_check, FALSE); + gtk_widget_set_sensitive (cd->custom_entry, FALSE); + gtk_widget_set_sensitive (cd->custom_label, FALSE); + break; + case CLOCK_FORMAT_CUSTOM: + gtk_widget_set_sensitive (cd->showseconds_check, FALSE); + gtk_widget_set_sensitive (cd->showdate_check, FALSE); + gtk_widget_set_sensitive (cd->custom_entry, TRUE); + gtk_widget_set_sensitive (cd->custom_label, TRUE); + break; + default: + g_assert_not_reached (); + break; + } +} + +static void +set_format_cb (GtkComboBox *combo, + ClockData *cd) +{ + /* FMQ: was used from old preferences dialog; fix this up */ + ClockFormat format; + + /* valid values begin from 1 */ + if (cd->can_handle_format_12) + format = gtk_combo_box_get_active (combo) + 1; + else + format = gtk_combo_box_get_active (combo) + 2; + + update_properties_for_format (cd, combo, format); + + if (cd->format != format) + mate_panel_applet_mateconf_set_string (MATE_PANEL_APPLET (cd->applet), + KEY_FORMAT, + mateconf_enum_to_string (format_type_enum_map, format), + NULL); +} +#endif + +static void +set_show_seconds_cb (GtkWidget *w, + ClockData *clock) +{ + mate_panel_applet_mateconf_set_bool (MATE_PANEL_APPLET (clock->applet), + KEY_SHOW_SECONDS, + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)), + NULL); +} + +static void +set_show_date_cb (GtkWidget *w, + ClockData *clock) +{ + mate_panel_applet_mateconf_set_bool (MATE_PANEL_APPLET (clock->applet), + KEY_SHOW_DATE, + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)), + NULL); +} + +static void +set_show_weather_cb (GtkWidget *w, + ClockData *clock) +{ + mate_panel_applet_mateconf_set_bool (MATE_PANEL_APPLET (clock->applet), + KEY_SHOW_WEATHER, + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)), + NULL); +} + +static void +set_show_temperature_cb (GtkWidget *w, + ClockData *clock) +{ + mate_panel_applet_mateconf_set_bool (MATE_PANEL_APPLET (clock->applet), + KEY_SHOW_TEMPERATURE, + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)), + NULL); +} + +#if 0 +static void +set_show_zones_cb (GtkWidget *w, + ClockData *clock) +{ + mate_panel_applet_mateconf_set_bool (MATE_PANEL_APPLET (clock->applet), + KEY_SHOW_ZONES, + GTK_TOGGLE_BUTTON (w)->active, + NULL); +} +#endif + +/* FIXME old clock applet */ +#if 0 +static void +set_custom_format_cb (GtkEntry *entry, + ClockData *cd) +{ + /* FMQ: was used from old preferences dialog; fix this up */ + const char *custom_format; + + custom_format = gtk_entry_get_text (entry); + mate_panel_applet_mateconf_set_string (MATE_PANEL_APPLET (cd->applet), + KEY_CUSTOM_FORMAT, custom_format, NULL); +} +#endif + +static void +prefs_locations_changed (GtkTreeSelection *selection, ClockData *cd) +{ + gint n; + + n = gtk_tree_selection_count_selected_rows (selection); + gtk_widget_set_sensitive (cd->prefs_location_edit_button, n > 0); + gtk_widget_set_sensitive (cd->prefs_location_remove_button, n > 0); +} + +static gchar * +loc_to_string (ClockLocation *loc) +{ + const gchar *name, *city; + gfloat latitude, longitude; + gchar *ret; + + name = clock_location_get_name (loc); + city = clock_location_get_city (loc); + clock_location_get_coords (loc, &latitude, &longitude); + + setlocale (LC_NUMERIC, "POSIX"); + + ret = g_markup_printf_escaped + ("", + name ? name : "", + city ? city : "", + clock_location_get_timezone (loc), + latitude, longitude, + clock_location_get_weather_code (loc), + clock_location_is_current (loc) ? "true" : "false"); + + setlocale (LC_NUMERIC, ""); + + return ret; +} + +static void +save_cities_store (ClockData *cd) +{ + ClockLocation *loc; + GList *node = cd->locations; + + GSList *root = NULL; + GSList *list = NULL; + + while (node) { + loc = CLOCK_LOCATION (node->data); + list = g_slist_prepend (list, loc_to_string (loc)); + node = node->next; + } + + list = g_slist_reverse (list); + mate_panel_applet_mateconf_set_list (MATE_PANEL_APPLET (cd->applet), + KEY_CITIES, MATECONF_VALUE_STRING, list, NULL); + + root = list; + + while (list) { + g_free (list->data); + list = g_slist_next (list); + } + + g_slist_free (root); +} + +static void +run_prefs_edit_save (GtkButton *button, ClockData *cd) +{ + GtkWidget *edit_window = _clock_get_widget (cd, "edit-location-window"); + + ClockLocation *loc = g_object_get_data (G_OBJECT (edit_window), "clock-location"); + + GtkWidget *lat_entry = _clock_get_widget (cd, "edit-location-latitude-entry"); + GtkWidget *lon_entry = _clock_get_widget (cd, "edit-location-longitude-entry"); + GtkWidget *lat_combo = _clock_get_widget (cd, "edit-location-latitude-combo"); + GtkWidget *lon_combo = _clock_get_widget (cd, "edit-location-longitude-combo"); + + const gchar *timezone, *weather_code; + gchar *city, *name; + + MateWeatherLocation *gloc; + gfloat lat = 0; + gfloat lon = 0; + + timezone = mateweather_timezone_menu_get_tzid (cd->zone_combo); + if (!timezone) { + edit_hide (NULL, cd); + return; + } + + city = NULL; + weather_code = NULL; + name = NULL; + + gloc = mateweather_location_entry_get_location (cd->location_entry); + if (gloc) { + city = mateweather_location_get_city_name (gloc); + weather_code = mateweather_location_get_code (gloc); + } + + if (mateweather_location_entry_has_custom_text (cd->location_entry)) { + name = gtk_editable_get_chars (GTK_EDITABLE (cd->location_entry), 0, -1); + } + + sscanf (gtk_entry_get_text (GTK_ENTRY (lat_entry)), "%f", &lat); + sscanf (gtk_entry_get_text (GTK_ENTRY (lon_entry)), "%f", &lon); + + if (gtk_combo_box_get_active (GTK_COMBO_BOX (lat_combo)) != 0) { + lat = -lat; + } + + if (gtk_combo_box_get_active (GTK_COMBO_BOX (lon_combo)) != 0) { + lon = -lon; + } + + if (loc) { + clock_location_set_timezone (loc, timezone); + clock_location_set_name (loc, name); + clock_location_set_city (loc, city); + clock_location_set_coords (loc, lat, lon); + clock_location_set_weather_code (loc, weather_code); + } else { + WeatherPrefs prefs; + + prefs.temperature_unit = cd->temperature_unit; + prefs.speed_unit = cd->speed_unit; + + loc = clock_location_new (name, city, timezone, lat, lon, weather_code, &prefs); + /* has the side-effect of setting the current location if + * there's none and this one can be considered as a current one + */ + clock_location_is_current (loc); + + cd->locations = g_list_append (cd->locations, loc); + } + g_free (name); + g_free (city); + + /* This will update everything related to locations to take into + * account the new location (via the mateconf notification) */ + save_cities_store (cd); + + edit_hide (edit_window, cd); +} + +static void +update_coords_helper (gfloat value, GtkWidget *entry, GtkWidget *combo) +{ + gchar *tmp; + + tmp = g_strdup_printf ("%f", fabsf (value)); + gtk_entry_set_text (GTK_ENTRY (entry), tmp); + g_free (tmp); + + if (value > 0) { + gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0); + } else { + gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 1); + } +} + +static void +update_coords (ClockData *cd, gboolean valid, gfloat lat, gfloat lon) +{ + GtkWidget *lat_entry = _clock_get_widget (cd, "edit-location-latitude-entry"); + GtkWidget *lon_entry = _clock_get_widget (cd, "edit-location-longitude-entry"); + GtkWidget *lat_combo = _clock_get_widget (cd, "edit-location-latitude-combo"); + GtkWidget *lon_combo = _clock_get_widget (cd, "edit-location-longitude-combo"); + + if (!valid) { + gtk_entry_set_text (GTK_ENTRY (lat_entry), ""); + gtk_entry_set_text (GTK_ENTRY (lon_entry), ""); + gtk_combo_box_set_active (GTK_COMBO_BOX (lat_combo), -1); + gtk_combo_box_set_active (GTK_COMBO_BOX (lon_combo), -1); + + return; + } + + update_coords_helper (lat, lat_entry, lat_combo); + update_coords_helper (lon, lon_entry, lon_combo); +} + +static void +fill_timezone_combo_from_location (ClockData *cd, ClockLocation *loc) +{ + if (loc != NULL) { + mateweather_timezone_menu_set_tzid (cd->zone_combo, + clock_location_get_timezone (loc)); + } else { + mateweather_timezone_menu_set_tzid (cd->zone_combo, NULL); + } +} + +static void +location_update_ok_sensitivity (ClockData *cd) +{ + GtkWidget *ok_button; + const gchar *timezone; + gchar *name; + + ok_button = _clock_get_widget (cd, "edit-location-ok-button"); + + timezone = mateweather_timezone_menu_get_tzid (cd->zone_combo); + name = gtk_editable_get_chars (GTK_EDITABLE (cd->location_entry), 0, -1); + + if (timezone && name && name[0] != '\0') { + gtk_widget_set_sensitive (ok_button, TRUE); + } else { + gtk_widget_set_sensitive (ok_button, FALSE); + } + + g_free (name); +} + +static void +location_changed (GObject *object, GParamSpec *param, ClockData *cd) +{ + MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object); + MateWeatherLocation *gloc; + MateWeatherTimezone *zone; + gboolean latlon_valid; + double latitude = 0.0, longitude = 0.0; + + gloc = mateweather_location_entry_get_location (entry); + + latlon_valid = gloc && mateweather_location_has_coords (gloc); + if (latlon_valid) + mateweather_location_get_coords (gloc, &latitude, &longitude); + update_coords (cd, latlon_valid, latitude, longitude); + + zone = gloc ? mateweather_location_get_timezone (gloc) : NULL; + if (zone) + mateweather_timezone_menu_set_tzid (cd->zone_combo, mateweather_timezone_get_tzid (zone)); + else + mateweather_timezone_menu_set_tzid (cd->zone_combo, NULL); + + if (gloc) + mateweather_location_unref (gloc); +} + +static void +location_name_changed (GObject *object, ClockData *cd) +{ + location_update_ok_sensitivity (cd); +} + +static void +location_timezone_changed (GObject *object, GParamSpec *param, ClockData *cd) +{ + location_update_ok_sensitivity (cd); +} + +static void +edit_clear (ClockData *cd) +{ + GtkWidget *lat_entry = _clock_get_widget (cd, "edit-location-latitude-entry"); + GtkWidget *lon_entry = _clock_get_widget (cd, "edit-location-longitude-entry"); + GtkWidget *lat_combo = _clock_get_widget (cd, "edit-location-latitude-combo"); + GtkWidget *lon_combo = _clock_get_widget (cd, "edit-location-longitude-combo"); + + /* clear out the old data */ + mateweather_location_entry_set_location (cd->location_entry, NULL); + mateweather_timezone_menu_set_tzid (cd->zone_combo, NULL); + + gtk_entry_set_text (GTK_ENTRY (lat_entry), ""); + gtk_entry_set_text (GTK_ENTRY (lon_entry), ""); + + gtk_combo_box_set_active (GTK_COMBO_BOX (lat_combo), -1); + gtk_combo_box_set_active (GTK_COMBO_BOX (lon_combo), -1); +} + +static void +edit_hide (GtkWidget *unused, ClockData *cd) +{ + GtkWidget *edit_window = _clock_get_widget (cd, "edit-location-window"); + + gtk_widget_hide (edit_window); + edit_clear (cd); +} + +static gboolean +edit_delete (GtkWidget *unused, GdkEvent *event, ClockData *cd) +{ + edit_hide (unused, cd); + + return TRUE; +} + +static gboolean +edit_hide_event (GtkWidget *widget, GdkEvent *event, ClockData *cd) +{ + edit_hide (widget, cd); + + return TRUE; +} + +static void +prefs_hide (GtkWidget *widget, ClockData *cd) +{ + GtkWidget *tree; + + edit_hide (widget, cd); + + gtk_widget_hide (cd->prefs_window); + + tree = _clock_get_widget (cd, "cities_list"); + + gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree))); + + refresh_click_timeout_time_only (cd); +} + +static gboolean +prefs_hide_event (GtkWidget *widget, GdkEvent *event, ClockData *cd) +{ + prefs_hide (widget, cd); + + return TRUE; +} + +static void +prefs_help (GtkWidget *widget, ClockData *cd) +{ + clock_utils_display_help (cd->prefs_window, + "clock", "clock-settings"); +} + +static void +remove_tree_row (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) +{ + ClockData *cd = data; + ClockLocation *loc = NULL; + + gtk_tree_model_get (model, iter, COL_CITY_LOC, &loc, -1); + cd->locations = g_list_remove (cd->locations, loc); + g_object_unref (loc); + + /* This will update everything related to locations to take into + * account the removed location (via the mateconf notification) */ + save_cities_store (cd); +} + +static void +run_prefs_locations_remove (GtkButton *button, ClockData *cd) +{ + GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (cd->prefs_locations)); + + gtk_tree_selection_selected_foreach (sel, remove_tree_row, cd); +} + +static void +run_prefs_locations_add (GtkButton *button, ClockData *cd) +{ + GtkWidget *edit_window = _clock_get_widget (cd, "edit-location-window"); + + fill_timezone_combo_from_location (cd, NULL); + + g_object_set_data (G_OBJECT (edit_window), "clock-location", NULL); + gtk_window_set_title (GTK_WINDOW (edit_window), _("Choose Location")); + gtk_window_set_transient_for (GTK_WINDOW (edit_window), GTK_WINDOW (cd->prefs_window)); + + if (g_object_get_data (G_OBJECT (edit_window), "delete-handler") == NULL) { + g_object_set_data (G_OBJECT (edit_window), "delete-handler", + GINT_TO_POINTER (g_signal_connect (edit_window, "delete_event", G_CALLBACK (edit_delete), cd))); + } + + location_update_ok_sensitivity (cd); + + gtk_widget_grab_focus (GTK_WIDGET (cd->location_entry)); + gtk_editable_set_position (GTK_EDITABLE (cd->location_entry), -1); + + gtk_window_present_with_time (GTK_WINDOW (edit_window), gtk_get_current_event_time ()); +} + +static void +edit_tree_row (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) +{ + ClockData *cd = data; + ClockLocation *loc; + const char *name; + gchar *tmp; + gfloat lat, lon; + + /* fill the dialog with this location's data, show it */ + GtkWidget *edit_window = _clock_get_widget (cd, "edit-location-window"); + + GtkWidget *lat_entry = _clock_get_widget (cd, "edit-location-latitude-entry"); + + GtkWidget *lon_entry = _clock_get_widget (cd, "edit-location-longitude-entry"); + + GtkWidget *lat_combo = _clock_get_widget (cd, "edit-location-latitude-combo"); + + GtkWidget *lon_combo = _clock_get_widget (cd, "edit-location-longitude-combo"); + + edit_clear (cd); + + gtk_tree_model_get (model, iter, COL_CITY_LOC, &loc, -1); + + mateweather_location_entry_set_city (cd->location_entry, + clock_location_get_city (loc), + clock_location_get_weather_code (loc)); + name = clock_location_get_name (loc); + if (name && name[0]) { + gtk_entry_set_text (GTK_ENTRY (cd->location_entry), name); + } + + clock_location_get_coords (loc, &lat, &lon); + + fill_timezone_combo_from_location (cd, loc); + + tmp = g_strdup_printf ("%f", fabsf(lat)); + gtk_entry_set_text (GTK_ENTRY (lat_entry), tmp); + g_free (tmp); + + if (lat > 0) { + gtk_combo_box_set_active (GTK_COMBO_BOX (lat_combo), 0); + } else { + gtk_combo_box_set_active (GTK_COMBO_BOX (lat_combo), 1); + } + + tmp = g_strdup_printf ("%f", fabsf(lon)); + gtk_entry_set_text (GTK_ENTRY (lon_entry), tmp); + g_free (tmp); + + if (lon > 0) { + gtk_combo_box_set_active (GTK_COMBO_BOX (lon_combo), 0); + } else { + gtk_combo_box_set_active (GTK_COMBO_BOX (lon_combo), 1); + } + + location_update_ok_sensitivity (cd); + + g_object_set_data (G_OBJECT (edit_window), "clock-location", loc); + + gtk_widget_grab_focus (GTK_WIDGET (cd->location_entry)); + gtk_editable_set_position (GTK_EDITABLE (cd->location_entry), -1); + + gtk_window_set_title (GTK_WINDOW (edit_window), _("Edit Location")); + gtk_window_present (GTK_WINDOW (edit_window)); +} + +static void +run_prefs_locations_edit (GtkButton *unused, ClockData *cd) +{ + GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (cd->prefs_locations)); + + gtk_tree_selection_selected_foreach (sel, edit_tree_row, cd); +} + +static void +set_12hr_format_radio_cb (GtkWidget *widget, ClockData *cd) +{ + const gchar *val; + ClockFormat format; + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) + format = CLOCK_FORMAT_12; + else + format = CLOCK_FORMAT_24; + + val = mateconf_enum_to_string (format_type_enum_map, format); + + mate_panel_applet_mateconf_set_string (MATE_PANEL_APPLET (cd->applet), + KEY_FORMAT, val, NULL); +} + +static void +temperature_combo_changed (GtkComboBox *combo, ClockData *cd) +{ + int value; + int old_value; + const gchar *str; + + value = gtk_combo_box_get_active (combo) + 1; + + if (cd->use_temperature_default) + old_value = TEMP_UNIT_DEFAULT; + else + old_value = cd->temperature_unit; + + if (value == old_value) + return; + + str = mateweather_prefs_temp_enum_to_string (value); + + mate_panel_applet_mateconf_set_string (MATE_PANEL_APPLET (cd->applet), + KEY_TEMPERATURE_UNIT, str, NULL); +} + +static void +speed_combo_changed (GtkComboBox *combo, ClockData *cd) +{ + int value; + int old_value; + const gchar *str; + + value = gtk_combo_box_get_active (combo) + 1; + + if (cd->use_speed_default) + old_value = SPEED_UNIT_DEFAULT; + else + old_value = cd->speed_unit; + + if (value == old_value) + return; + + str = mateweather_prefs_speed_enum_to_string (value); + + mate_panel_applet_mateconf_set_string (MATE_PANEL_APPLET (cd->applet), + KEY_SPEED_UNIT, str, NULL); +} + +static void +fill_prefs_window (ClockData *cd) +{ + static const int temperatures[] = { + TEMP_UNIT_DEFAULT, + TEMP_UNIT_KELVIN, + TEMP_UNIT_CENTIGRADE, + TEMP_UNIT_FAHRENHEIT, + -1 + }; + + static const int speeds[] = { + SPEED_UNIT_DEFAULT, + SPEED_UNIT_MS, + SPEED_UNIT_KPH, + SPEED_UNIT_MPH, + SPEED_UNIT_KNOTS, + SPEED_UNIT_BFT, + -1 + }; + + GtkWidget *radio_12hr; + GtkWidget *radio_24hr; + GtkWidget *widget; + GtkCellRenderer *renderer; + GtkTreeViewColumn *col; + GtkListStore *store; + int i; + + /* Set the 12 hour / 24 hour widget */ + radio_12hr = _clock_get_widget (cd, "12hr_radio"); + radio_24hr = _clock_get_widget (cd, "24hr_radio"); + + if (cd->format == CLOCK_FORMAT_12) + widget = radio_12hr; + else + widget = radio_24hr; + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE); + + g_signal_connect (radio_12hr, "toggled", + G_CALLBACK (set_12hr_format_radio_cb), cd); + + /* Set the "Show Date" checkbox */ + widget = _clock_get_widget (cd, "date_check"); + g_signal_connect (widget, "toggled", + G_CALLBACK (set_show_date_cb), cd); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), cd->showdate); + + /* Set the "Show Seconds" checkbox */ + widget = _clock_get_widget (cd, "seconds_check"); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), cd->showseconds); + g_signal_connect (widget, "toggled", + G_CALLBACK (set_show_seconds_cb), cd); + + /* Set the "Show weather" checkbox */ + widget = _clock_get_widget (cd, "weather_check"); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), cd->show_weather); + g_signal_connect (widget, "toggled", + G_CALLBACK (set_show_weather_cb), cd); + + /* Set the "Show temperature" checkbox */ + widget = _clock_get_widget (cd, "temperature_check"); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), cd->show_temperature); + g_signal_connect (widget, "toggled", + G_CALLBACK (set_show_temperature_cb), cd); + + /* Fill the Cities list */ + widget = _clock_get_widget (cd, "cities_list"); + + renderer = gtk_cell_renderer_text_new (); + col = gtk_tree_view_column_new_with_attributes (_("City Name"), renderer, "text", COL_CITY_NAME, NULL); + gtk_tree_view_insert_column (GTK_TREE_VIEW (widget), col, -1); + + renderer = gtk_cell_renderer_text_new (); + col = gtk_tree_view_column_new_with_attributes (_("City Time Zone"), renderer, "text", COL_CITY_TZ, NULL); + gtk_tree_view_insert_column (GTK_TREE_VIEW (widget), col, -1); + + if (cd->cities_store == NULL) + create_cities_store (cd); + + gtk_tree_view_set_model (GTK_TREE_VIEW (widget), + GTK_TREE_MODEL (cd->cities_store)); + + /* Temperature combo */ + widget = _clock_get_widget (cd, "temperature_combo"); + store = gtk_list_store_new (1, G_TYPE_STRING); + gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store)); + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget), renderer, "text", 0, NULL); + + for (i = 0; temperatures[i] != -1; i++) + gtk_combo_box_append_text (GTK_COMBO_BOX (widget), + mateweather_prefs_get_temp_display_name (temperatures[i])); + + update_temperature_combo (cd); + g_signal_connect (widget, "changed", + G_CALLBACK (temperature_combo_changed), cd); + + /* Wind speed combo */ + widget = _clock_get_widget (cd, "wind_speed_combo"); + store = gtk_list_store_new (1, G_TYPE_STRING); + gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store)); + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget), renderer, "text", 0, NULL); + + for (i = 0; speeds[i] != -1; i++) + gtk_combo_box_append_text (GTK_COMBO_BOX (widget), + mateweather_prefs_get_speed_display_name (speeds[i])); + + update_speed_combo (cd); + g_signal_connect (widget, "changed", + G_CALLBACK (speed_combo_changed), cd); +} + +static void +ensure_prefs_window_is_created (ClockData *cd) +{ + GtkWidget *edit_window; + GtkWidget *prefs_close_button; + GtkWidget *prefs_help_button; + GtkWidget *clock_options; + GtkWidget *edit_cancel_button; + GtkWidget *edit_ok_button; + GtkWidget *location_box; + GtkWidget *zone_box; + GtkWidget *location_name_label; + GtkWidget *timezone_label; + GtkTreeSelection *selection; + MateWeatherLocation *world; + + if (cd->prefs_window) + return; + + cd->prefs_window = _clock_get_widget (cd, "prefs-window"); + + gtk_window_set_icon_name (GTK_WINDOW (cd->prefs_window), CLOCK_ICON); + + prefs_close_button = _clock_get_widget (cd, "prefs-close-button"); + prefs_help_button = _clock_get_widget (cd, "prefs-help-button"); + clock_options = _clock_get_widget (cd, "clock-options"); + cd->prefs_locations = GTK_TREE_VIEW (_clock_get_widget (cd, "cities_list")); + location_name_label = _clock_get_widget (cd, "location-name-label"); + timezone_label = _clock_get_widget (cd, "timezone-label"); + + + if (!clock_locale_supports_am_pm ()) + gtk_widget_hide (clock_options); + + selection = gtk_tree_view_get_selection (cd->prefs_locations); + g_signal_connect (G_OBJECT (selection), "changed", + G_CALLBACK (prefs_locations_changed), cd); + + g_signal_connect (G_OBJECT (cd->prefs_window), "delete_event", + G_CALLBACK (prefs_hide_event), cd); + + g_signal_connect (G_OBJECT (prefs_close_button), "clicked", + G_CALLBACK (prefs_hide), cd); + + g_signal_connect (G_OBJECT (prefs_help_button), "clicked", + G_CALLBACK (prefs_help), cd); + + cd->prefs_location_remove_button = _clock_get_widget (cd, "prefs-locations-remove-button"); + + g_signal_connect (G_OBJECT (cd->prefs_location_remove_button), "clicked", + G_CALLBACK (run_prefs_locations_remove), cd); + + cd->prefs_location_add_button = _clock_get_widget (cd, "prefs-locations-add-button"); + + g_signal_connect (G_OBJECT (cd->prefs_location_add_button), "clicked", + G_CALLBACK (run_prefs_locations_add), cd); + + cd->prefs_location_edit_button = _clock_get_widget (cd, "prefs-locations-edit-button"); + + g_signal_connect (G_OBJECT (cd->prefs_location_edit_button), "clicked", + G_CALLBACK (run_prefs_locations_edit), cd); + + edit_window = _clock_get_widget (cd, "edit-location-window"); + + gtk_window_set_transient_for (GTK_WINDOW (edit_window), + GTK_WINDOW (cd->prefs_window)); + + g_signal_connect (G_OBJECT (edit_window), "delete_event", + G_CALLBACK (edit_hide_event), cd); + + edit_cancel_button = _clock_get_widget (cd, "edit-location-cancel-button"); + + edit_ok_button = _clock_get_widget (cd, "edit-location-ok-button"); + + world = mateweather_location_new_world (FALSE); + + location_box = _clock_get_widget (cd, "edit-location-name-box"); + cd->location_entry = MATEWEATHER_LOCATION_ENTRY (mateweather_location_entry_new (world)); + gtk_widget_show (GTK_WIDGET (cd->location_entry)); + gtk_container_add (GTK_CONTAINER (location_box), GTK_WIDGET (cd->location_entry)); + gtk_label_set_mnemonic_widget (GTK_LABEL (location_name_label), + GTK_WIDGET (cd->location_entry)); + + g_signal_connect (G_OBJECT (cd->location_entry), "notify::location", + G_CALLBACK (location_changed), cd); + g_signal_connect (G_OBJECT (cd->location_entry), "changed", + G_CALLBACK (location_name_changed), cd); + + zone_box = _clock_get_widget (cd, "edit-location-timezone-box"); + cd->zone_combo = MATEWEATHER_TIMEZONE_MENU (mateweather_timezone_menu_new (world)); + gtk_widget_show (GTK_WIDGET (cd->zone_combo)); + gtk_container_add (GTK_CONTAINER (zone_box), GTK_WIDGET (cd->zone_combo)); + gtk_label_set_mnemonic_widget (GTK_LABEL (timezone_label), + GTK_WIDGET (cd->zone_combo)); + + g_signal_connect (G_OBJECT (cd->zone_combo), "notify::tzid", + G_CALLBACK (location_timezone_changed), cd); + + mateweather_location_unref (world); + + g_signal_connect (G_OBJECT (edit_cancel_button), "clicked", + G_CALLBACK (edit_hide), cd); + + g_signal_connect (G_OBJECT (edit_ok_button), "clicked", + G_CALLBACK (run_prefs_edit_save), cd); + + /* Set up the time setting section */ + + cd->time_settings_button = _clock_get_widget (cd, "time-settings-button"); + g_signal_connect (cd->time_settings_button, "clicked", + G_CALLBACK (run_time_settings), cd); + + /* fill it with the current preferences */ + fill_prefs_window (cd); +} + +static void +display_properties_dialog (ClockData *cd, gboolean start_in_locations_page) +{ + ensure_prefs_window_is_created (cd); + + if (start_in_locations_page) { + GtkWidget *notebook = _clock_get_widget (cd, "notebook"); + gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 1); + } + + update_set_time_button (cd); + + gtk_window_set_screen (GTK_WINDOW (cd->prefs_window), + gtk_widget_get_screen (cd->applet)); + gtk_window_present (GTK_WINDOW (cd->prefs_window)); + + refresh_click_timeout_time_only (cd); + + /* FMQ: cd->props was the old preferences window; remove references to it */ + /* FMQ: connect to the Help button by hand; look at properties_response_cb() for the help code */ +#if 0 + /* FMQ: check the code below; replace the proper parts */ + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *combo; + GtkWidget *label; + + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("24 hour")); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("UNIX time")); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Internet time")); + + gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0); + gtk_widget_show (combo); + + cd->custom_hbox = gtk_hbox_new (FALSE, 12); + gtk_box_pack_start (GTK_BOX (vbox), cd->custom_hbox, TRUE, TRUE, 0); + + cd->custom_label = gtk_label_new_with_mnemonic (_("Custom _format:")); + gtk_label_set_use_markup (GTK_LABEL (cd->custom_label), TRUE); + gtk_label_set_justify (GTK_LABEL (cd->custom_label), + GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (cd->custom_label), 0, 0.5); + gtk_box_pack_start (GTK_BOX (cd->custom_hbox), + cd->custom_label, + FALSE, FALSE, 0); + + cd->custom_entry = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (cd->custom_hbox), + cd->custom_entry, + FALSE, FALSE, 0); + gtk_entry_set_text (GTK_ENTRY (cd->custom_entry), + cd->custom_format); + g_signal_connect (cd->custom_entry, "changed", + G_CALLBACK (set_custom_format_cb), + cd); + + g_signal_connect (cd->props, "destroy", + G_CALLBACK (gtk_widget_destroyed), + &cd->props); + g_signal_connect (cd->props, "response", + G_CALLBACK (properties_response_cb), + cd); + + cd->custom_format_shown = FALSE; + update_properties_for_format (cd, GTK_COMBO_BOX (combo), cd->format); + + /* valid values begin from 1 */ + if (cd->can_handle_format_12) + gtk_combo_box_set_active (GTK_COMBO_BOX (combo), + cd->format - 1); + else + gtk_combo_box_set_active (GTK_COMBO_BOX (combo), + cd->format - 2); + + g_signal_connect (combo, "changed", + G_CALLBACK (set_format_cb), cd); + + /* Now set up the sensitivity based on mateconf key writability */ + setup_writability_sensitivity (cd, combo, label, KEY_FORMAT); + setup_writability_sensitivity (cd, cd->custom_entry, cd->custom_label, + KEY_CUSTOM_FORMAT); + setup_writability_sensitivity (cd, cd->showseconds_check, NULL, KEY_SHOW_SECONDS); + setup_writability_sensitivity (cd, cd->showdate_check, NULL, KEY_SHOW_DATE); + + gtk_widget_show (cd->props); +#endif +} + +static void +verb_display_properties_dialog (GtkAction *action, + ClockData *cd) +{ + display_properties_dialog (cd, FALSE); +} + +static void +display_help_dialog (GtkAction *action, + ClockData *cd) +{ + clock_utils_display_help (cd->applet, "clock", NULL); +} + +static void display_about_dialog(GtkAction* action, ClockData* cd) +{ + static const gchar* authors[] = { + "George Lebl ", + "Gediminas Paulauskas ", + NULL + }; + + static const char* documenters[] = { + "Dan Mueth ", + NULL + }; + + char copyright[] = \ + "Copyright \xc2\xa9 1998-2004 Free Software Foundation, Inc."; + + gtk_show_about_dialog(NULL, + "program-name", _("Clock"), + "authors", authors, + "comments", _("The Clock displays the current time and date"), + "copyright", copyright, + "documenters", documenters, + "logo-icon-name", CLOCK_ICON, + "translator-credits", _("translator-credits"), + "version", VERSION, + "website", "http://matsusoft.com.ar/projects/mate/", + NULL); +} + +static gboolean +clock_factory (MatePanelApplet *applet, + const char *iid, + gpointer data) +{ + gboolean retval = FALSE; + + if (!strcmp (iid, "ClockApplet")) + retval = fill_clock_applet (applet); + + return retval; +} + +#ifdef CLOCK_INPROCESS +MATE_PANEL_APPLET_IN_PROCESS_FACTORY ("ClockAppletFactory", + PANEL_TYPE_APPLET, + "ClockApplet", + clock_factory, + NULL) +#else +MATE_PANEL_APPLET_OUT_PROCESS_FACTORY ("ClockAppletFactory", + PANEL_TYPE_APPLET, + "ClockApplet", + clock_factory, + NULL) +#endif diff --git a/applets/clock/clock.h b/applets/clock/clock.h new file mode 100644 index 00000000..f2347f68 --- /dev/null +++ b/applets/clock/clock.h @@ -0,0 +1,41 @@ +/* + * clock.h + * + * Copyright (C) 2007 Vincent Untz + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + * + * Most of the original code comes from clock.c + */ + +#ifndef CLOCK_H +#define CLOCK_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define CLOCK_ICON "mate-panel-clock" +#define CLOCK_SCHEMA_DIR "/schemas/apps/clock_applet/prefs" + +#ifdef __cplusplus +} +#endif + +#endif /* CLOCK_H */ diff --git a/applets/clock/clock.schemas.in b/applets/clock/clock.schemas.in new file mode 100644 index 00000000..badec94e --- /dev/null +++ b/applets/clock/clock.schemas.in @@ -0,0 +1,313 @@ + + + + + + /schemas/apps/clock_applet/prefs/format + clock-applet + string + + + + 24-hour + + Hour format + + This key specifies the hour format used by the clock applet. + Possible values are "12-hour", "24-hour", "internet", "unix" and + "custom". + If set to "internet", the clock will display Internet time. + The Internet time system divides the day into 1000 ".beats". There + are no time zones in this system, so time is the same all over the + world. + If set to "unix", the clock will display time in seconds since + Epoch, i.e. 1970-01-01. + If set to "custom", the clock will display time according to the + format specified in the custom_format key. + + + + 12-hour + + + + + /schemas/apps/clock_applet/prefs/custom_format + clock-applet + string + + + Custom format of the clock + + This key specifies the format used by the clock applet when the + format key is set to "custom". You can use conversion specifiers + understood by strftime() to obtain a specific format. See the + strftime() manual for more information. + + + + + + /schemas/apps/clock_applet/prefs/show_seconds + clock-applet + bool + false + + Show time with seconds + If true, display seconds in time. + + + + + /schemas/apps/clock_applet/prefs/show_date + clock-applet + bool + true + + Show date in clock + If true, display date in the clock, in addition to time. + + + + + /schemas/apps/clock_applet/prefs/show_tooltip + clock-applet + bool + true + + Show date in tooltip + + If true, show date in a tooltip when the pointer is over the clock. + + + + + + /schemas/apps/clock_applet/prefs/show_weather + clock-applet + bool + true + + Show weather in clock + If true, display a weather icon. + + + + + /schemas/apps/clock_applet/prefs/show_temperature + clock-applet + bool + true + + Show temperature in clock + If true, show the temperature next to the weather icon. + + + + + /schemas/apps/clock_applet/prefs/gmt_time + clock-applet + bool + false + + Use UTC + + The use of this key was deprecated in MATE 2.28 in favour of the + use of timezones. The schema is retained for compatibility with + older versions. + + + + + + /schemas/apps/clock_applet/prefs/config_tool + clock-applet + string + + + Time configuration tool + + The use of this key was deprecated in MATE 2.22 with the use + of an internal time configuration tool. The schema is retained for + compatibility with older versions. + + + + + + /schemas/apps/clock_applet/prefs/show_week_numbers + clock-applet + bool + true + + Show week numbers in calendar + + If true, show week numbers in the calendar. + + + + + + /schemas/apps/clock_applet/prefs/expand_appointments + clock-applet + bool + false + + Expand list of appointments + + If true, expand the list of appointments in the calendar window. + + + + + + /schemas/apps/clock_applet/prefs/expand_birthdays + clock-applet + bool + false + + Expand list of birthdays + + If true, expand the list of birthdays in the calendar window. + + + + + + /schemas/apps/clock_applet/prefs/expand_tasks + clock-applet + bool + false + + Expand list of tasks + + If true, expand the list of tasks in the calendar window. + + + + + + /schemas/apps/clock_applet/prefs/expand_weather + clock-applet + bool + false + + Expand list of weather information + + If true, expand the list of weather information in the calendar + window. + + + + + + /schemas/apps/clock_applet/prefs/expand_locations + clock-applet + bool + false + + Expand list of locations + + If true, expand the list of locations in the calendar + window. + + + + + + /schemas/apps/clock_applet/prefs/hour_format + clock-applet + int + 12 + + Hour format + + The use of this key was deprecated in MATE 2.6 in favour of the + 'format' key. The schema is retained for compatibility with older + versions. + + + + + + /schemas/apps/clock_applet/prefs/unix_time + clock-applet + bool + false + + Use UNIX time + + The use of this key was deprecated in MATE 2.6 in favour of the + 'format' key. The schema is retained for compatibility with older + versions. + + + + + + /schemas/apps/clock_applet/prefs/internet_time + clock-applet + bool + false + + Use Internet time + + The use of this key was deprecated in MATE 2.6 in favour of the + 'format' key. The schema is retained for compatibility with older + versions. + + + + + + /schemas/apps/clock_applet/prefs/cities + clock-applet + list + string + [] + + List of locations + + A list of locations to display in the calendar window. + + + + + + /schemas/apps/clock_applet/prefs/temperature_unit + clock-applet + string + Default + + Temperature unit + + The unit to use when showing temperatures. + + + + + + /schemas/apps/clock_applet/prefs/speed_unit + clock-applet + string + Default + + Speed unit + + The unit to use when showing wind speed. + + + + + + + diff --git a/applets/clock/clock.ui b/applets/clock/clock.ui new file mode 100644 index 00000000..11d9f8db --- /dev/null +++ b/applets/clock/clock.ui @@ -0,0 +1,1136 @@ + + + + + + 5 + False + dialog + False + + + True + vertical + + + True + 3 + 6 + 6 + + + True + vertical + 6 + + + True + True + never + never + + + True + none + + + gtk-missing-image + + + + + + + 0 + + + + + True + 5 + 5 + 4 + 6 + 6 + + + True + 0 + <small><i>Type a city, region, or country name and then select a match from the pop-up.</i></small> + True + True + + + 1 + 4 + 1 + 2 + GTK_FILL + + + + + + True + vertical + + + + + + 1 + 4 + GTK_FILL + GTK_FILL + + + + + True + vertical + + + + + + 1 + 4 + 2 + 3 + GTK_FILL + GTK_FILL + + + + + True + 0 + _Timezone: + True + + + 2 + 3 + GTK_FILL + + + + + + True + 0 + _Location Name: + True + + + GTK_FILL + + + + + + True + True + + + + 1 + 2 + 3 + 4 + + + + + + True + liststore2 + + + + 0 + + + + + 2 + 3 + 3 + 4 + GTK_FILL + GTK_FILL + + + + + True + 0 + <i>(optional)</i> + True + + + 3 + 4 + 3 + 4 + GTK_FILL + + + + + + True + 0 + <i>(optional)</i> + True + + + 3 + 4 + 4 + 5 + GTK_FILL + + + + + + True + liststore1 + + + + 0 + + + + + 2 + 3 + 4 + 5 + GTK_FILL + GTK_FILL + + + + + True + True + + + + 1 + 2 + 4 + 5 + + + + + + True + 0 + L_ongitude: + True + edit-location-longitude-entry + + + 4 + 5 + GTK_FILL + + + + + + True + vertical + 6 + True + + + True + 0 + L_atitude: + True + edit-location-latitude-entry + + + False + False + 0 + + + + + 3 + 4 + GTK_FILL + + + + + + + + 1 + + + + + 3 + + + + + + 1 + + + + + True + + + gtk-cancel + True + True + True + False + True + + + False + False + 0 + + + + + gtk-ok + True + True + True + False + True + + + False + False + 1 + + + + + False + end + 0 + + + + + + edit-location-cancel-button + edit-location-ok-button + + + + 5 + Time & Date + False + dialog + False + + + True + vertical + + + True + 0 + 7 + 6 + 7 + 7 + + + True + vertical + 12 + + + True + True + 2009 + 5 + 3 + + + 0 + + + + + True + 2 + 2 + 12 + 6 + + + True + + + True + True + + adjustment3 + 1 + True + True + + + False + False + 0 + + + + + True + True + + adjustment2 + 1 + True + True + + + False + False + 1 + + + + + True + True + + adjustment1 + 1 + True + True + + + False + False + 2 + + + + + 1 + 2 + 1 + 2 + + + + + + True + 0 + 23:59:59 + + + 1 + 2 + + + + + + True + 0 + _Time: + True + hours_spin + + + 1 + 2 + GTK_FILL + + + + + + True + 0 + Current Time: + + + GTK_FILL + + + + + + False + False + 1 + + + + + + + False + False + 1 + + + + + True + True + + + gtk-cancel + True + True + True + False + True + + + False + False + 0 + + + + + _Set System Time + True + True + False + True + + + False + False + 1 + + + + + False + end + 0 + + + + + + cancel-set-time-button + set-time-button + + + + + + + + + + East + + + West + + + + + + + + + + + North + + + South + + + + + 5 + Clock Preferences + False + center + dialog + False + + + True + vertical + 2 + + + True + True + 5 + + + True + 12 + vertical + 18 + + + True + vertical + 6 + + + True + 0 + Clock Format + + + + + + False + False + 0 + + + + + True + 12 + + + True + 13 + + + _12 hour format + True + True + False + True + True + + + False + False + 0 + + + + + _24 hour format + True + True + False + True + True + 12hr_radio + + + False + False + 1 + + + + + + + 1 + + + + + False + 0 + + + + + True + vertical + 6 + + + True + 0 + Panel Display + + + + + + False + False + 0 + + + + + True + 12 + + + True + vertical + 6 + + + Show the _date + True + True + False + True + True + + + False + False + 0 + + + + + Show seco_nds + True + True + False + True + True + + + False + False + 1 + + + + + Show _weather + True + True + False + True + True + + + False + False + 2 + + + + + Show _temperature + True + True + False + True + True + + + False + False + 3 + + + + + + + 1 + + + + + 1 + + + + + + + True + General + + + False + + + + + True + 12 + vertical + 18 + + + True + 6 + + + True + True + never + never + in + + + True + True + False + True + + + + + 0 + + + + + True + vertical + 6 + start + + + gtk-add + True + True + True + False + True + + + False + False + 0 + + + + + gtk-edit + True + True + True + False + True + + + False + False + 1 + + + + + gtk-remove + True + True + True + False + True + + + False + False + 2 + + + + + False + False + 1 + + + + + 0 + + + + + 1 + + + + + True + Locations + + + 1 + False + + + + + True + 12 + vertical + 18 + + + True + vertical + 6 + + + True + 0 + Display + + + + + + False + False + 0 + + + + + True + 12 + + + True + 4 + 2 + 12 + 6 + + + + 1 + 2 + 3 + 4 + GTK_FILL + GTK_FILL + + + + + 0 + _Visibility unit: + True + visibility_combo + + + 3 + 4 + GTK_FILL + + + + + + + 1 + 2 + 2 + 3 + GTK_FILL + GTK_FILL + + + + + 0 + _Pressure unit: + True + pressure_combo + + + 2 + 3 + GTK_FILL + + + + + + True + + + 1 + 2 + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + + + 1 + 2 + GTK_FILL + + + + + True + 0 + _Wind speed unit: + True + wind_speed_combo + + + 1 + 2 + GTK_FILL + + + + + + True + 0 + _Temperature unit: + True + temperature_combo + + + GTK_FILL + + + + + + + + 1 + + + + + 0 + + + + + 2 + + + + + True + Weather + + + 2 + False + + + + + 1 + + + + + True + + + gtk-help + True + True + True + False + True + + + False + False + 0 + + + + + Time _Settings + True + True + True + False + True + + + False + False + 1 + + + + + gtk-close + True + True + True + True + False + True + + + False + False + 2 + + + + + False + end + 0 + + + + + + prefs-help-button + time-settings-button + prefs-close-button + + + + 59 + 59 + 1 + 30 + + + 59 + 59 + 1 + 30 + + + 23 + 23 + 1 + 12 + + diff --git a/applets/clock/org.mate.panel.ClockApplet.mate-panel-applet.in.in b/applets/clock/org.mate.panel.ClockApplet.mate-panel-applet.in.in new file mode 100644 index 00000000..31ccda1f --- /dev/null +++ b/applets/clock/org.mate.panel.ClockApplet.mate-panel-applet.in.in @@ -0,0 +1,18 @@ +[Applet Factory] +Id=ClockAppletFactory +InProcess=@IN_PROCESS@ +Location=@LOCATION@ +_Name=Clock Applet Factory +_Description=Factory for clock applet + +[ClockApplet] +_Name=Clock +_Description=Get the current time and date +Icon=mate-panel-clock +MateComponentId=OAFIID:MATE_ClockApplet; +X-MATE-Bugzilla-Bugzilla=MATE +X-MATE-Bugzilla-Product=mate-panel +X-MATE-Bugzilla-Component=clock +X-MATE-Bugzilla-Version=@VERSION@ +X-MATE-Bugzilla-OtherBinaries=clock-applet + diff --git a/applets/clock/org.mate.panel.applet.ClockAppletFactory.service.in b/applets/clock/org.mate.panel.applet.ClockAppletFactory.service.in new file mode 100644 index 00000000..bb866606 --- /dev/null +++ b/applets/clock/org.mate.panel.applet.ClockAppletFactory.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.mate.panel.applet.ClockAppletFactory +Exec=@LOCATION@ diff --git a/applets/clock/pixmaps/Makefile.am b/applets/clock/pixmaps/Makefile.am new file mode 100644 index 00000000..3e9f5077 --- /dev/null +++ b/applets/clock/pixmaps/Makefile.am @@ -0,0 +1,21 @@ +icondir = $(datadir)/mate-panel/pixmaps +icon_DATA = \ + clock-calendar-icon.png \ + clock-face-large.svg \ + clock-face-small.svg \ + clock-face-small-morning.svg \ + clock-face-small-day.svg \ + clock-face-small-evening.svg \ + clock-face-small-night.svg \ + clock-map.png \ + clock-map-location-marker.png \ + clock-map-location-current.png \ + clock-map-location-hilight.png + +EXTRA_DIST = \ + clock-map.svg \ + $(icon_DATA) + +MAINTAINERCLEANFILES = Makefile.in + +-include $(top_srcdir)/git.mk diff --git a/applets/clock/pixmaps/Makefile.in b/applets/clock/pixmaps/Makefile.in new file mode 100644 index 00000000..11e6f2ff --- /dev/null +++ b/applets/clock/pixmaps/Makefile.in @@ -0,0 +1,537 @@ +# 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@ +subdir = applets/clock/pixmaps +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/d-type.m4 \ + $(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)/m4/mate-doc-utils.m4 $(top_srcdir)/configure.ac +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 = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +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)$(icondir)" +DATA = $(icon_DATA) +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@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLOCK_CFLAGS = @CLOCK_CFLAGS@ +CLOCK_EDS_ICONDIR = @CLOCK_EDS_ICONDIR@ +CLOCK_LIBS = @CLOCK_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISABLE_DEPRECATED = @DISABLE_DEPRECATED@ +DISABLE_DEPRECATED_CFLAGS = @DISABLE_DEPRECATED_CFLAGS@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DOC_USER_FORMATS = @DOC_USER_FORMATS@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGG_SMCLIENT_CFLAGS = @EGG_SMCLIENT_CFLAGS@ +EGG_SMCLIENT_LIBS = @EGG_SMCLIENT_LIBS@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FISH_CFLAGS = @FISH_CFLAGS@ +FISH_LIBS = @FISH_LIBS@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GIO_QUERYMODULES = @GIO_QUERYMODULES@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GREP = @GREP@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +HELP_DIR = @HELP_DIR@ +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@ +INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@ +INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@ +INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@ +INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@ +INTROSPECTION_LIBS = @INTROSPECTION_LIBS@ +INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@ +INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@ +INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBMATE_PANEL_APPLET_CFLAGS = @LIBMATE_PANEL_APPLET_CFLAGS@ +LIBMATE_PANEL_APPLET_LIBS = @LIBMATE_PANEL_APPLET_LIBS@ +LIBMATE_PANEL_APPLET_MATECOMPONENT_CFLAGS = @LIBMATE_PANEL_APPLET_MATECOMPONENT_CFLAGS@ +LIBMATE_PANEL_APPLET_MATECOMPONENT_LIBS = @LIBMATE_PANEL_APPLET_MATECOMPONENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MATE_PANEL_APPLET_LT_VERSION = @LIB_MATE_PANEL_APPLET_LT_VERSION@ +LIB_MATE_PANEL_APPLET_MATECOMPONENT_LT_VERSION = @LIB_MATE_PANEL_APPLET_MATECOMPONENT_LT_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MATECOMPONENT_ACT_IDLDIR = @MATECOMPONENT_ACT_IDLDIR@ +MATECOMPONENT_CFLAGS = @MATECOMPONENT_CFLAGS@ +MATECOMPONENT_IDLDIR = @MATECOMPONENT_IDLDIR@ +MATECOMPONENT_LIBS = @MATECOMPONENT_LIBS@ +MATECONFTOOL = @MATECONFTOOL@ +MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@ +MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@ +MATECORBA_IDL = @MATECORBA_IDL@ +MKDIR_P = @MKDIR_P@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGFMT_OPTS = @MSGFMT_OPTS@ +MSGMERGE = @MSGMERGE@ +NETWORK_MANAGER_CFLAGS = @NETWORK_MANAGER_CFLAGS@ +NETWORK_MANAGER_LIBS = @NETWORK_MANAGER_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NOTIFICATION_AREA_CFLAGS = @NOTIFICATION_AREA_CFLAGS@ +NOTIFICATION_AREA_LIBS = @NOTIFICATION_AREA_LIBS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OMF_DIR = @OMF_DIR@ +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@ +PANEL_CFLAGS = @PANEL_CFLAGS@ +PANEL_INTLTOOL_MATE_PANEL_APPLET_RULE = @PANEL_INTLTOOL_MATE_PANEL_APPLET_RULE@ +PANEL_LIBS = @PANEL_LIBS@ +PANEL_MODULE_MATECOMPONENT_CFLAGS = @PANEL_MODULE_MATECOMPONENT_CFLAGS@ +PANEL_MODULE_MATECOMPONENT_LIBS = @PANEL_MODULE_MATECOMPONENT_LIBS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +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@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +REBUILD = @REBUILD@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TZ_CFLAGS = @TZ_CFLAGS@ +TZ_LIBS = @TZ_LIBS@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +WNCKLET_CFLAGS = @WNCKLET_CFLAGS@ +WNCKLET_LIBS = @WNCKLET_LIBS@ +XGETTEXT = @XGETTEXT@ +XMKMF = @XMKMF@ +XRANDR_CFLAGS = @XRANDR_CFLAGS@ +XRANDR_LIBS = @XRANDR_LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +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@ +appletsdir = @appletsdir@ +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@ +modulesdir = @modulesdir@ +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@ +icondir = $(datadir)/mate-panel/pixmaps +icon_DATA = \ + clock-calendar-icon.png \ + clock-face-large.svg \ + clock-face-small.svg \ + clock-face-small-morning.svg \ + clock-face-small-day.svg \ + clock-face-small-evening.svg \ + clock-face-small-night.svg \ + clock-map.png \ + clock-map-location-marker.png \ + clock-map-location-current.png \ + clock-map-location-hilight.png + +EXTRA_DIST = \ + clock-map.svg \ + $(icon_DATA) + +MAINTAINERCLEANFILES = Makefile.in +all: all-am + +.SUFFIXES: +$(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 applets/clock/pixmaps/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu applets/clock/pixmaps/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): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-iconDATA: $(icon_DATA) + @$(NORMAL_INSTALL) + test -z "$(icondir)" || $(MKDIR_P) "$(DESTDIR)$(icondir)" + @list='$(icon_DATA)'; test -n "$(icondir)" || 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)$(icondir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(icondir)" || exit $$?; \ + done + +uninstall-iconDATA: + @$(NORMAL_UNINSTALL) + @list='$(icon_DATA)'; test -n "$(icondir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(icondir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(icondir)" && rm -f $$files +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +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: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(icondir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: 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: + +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 "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-iconDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +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 -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-iconDATA + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-iconDATA install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + uninstall uninstall-am uninstall-iconDATA + + +-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/applets/clock/pixmaps/clock-calendar-icon.png b/applets/clock/pixmaps/clock-calendar-icon.png new file mode 100644 index 00000000..cfab7200 Binary files /dev/null and b/applets/clock/pixmaps/clock-calendar-icon.png differ diff --git a/applets/clock/pixmaps/clock-face-large.svg b/applets/clock/pixmaps/clock-face-large.svg new file mode 100644 index 00000000..09b3224f --- /dev/null +++ b/applets/clock/pixmaps/clock-face-large.svg @@ -0,0 +1,291 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applets/clock/pixmaps/clock-face-small-day.svg b/applets/clock/pixmaps/clock-face-small-day.svg new file mode 100644 index 00000000..bd4b5b2e --- /dev/null +++ b/applets/clock/pixmaps/clock-face-small-day.svg @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applets/clock/pixmaps/clock-face-small-evening.svg b/applets/clock/pixmaps/clock-face-small-evening.svg new file mode 100644 index 00000000..17a9840b --- /dev/null +++ b/applets/clock/pixmaps/clock-face-small-evening.svg @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applets/clock/pixmaps/clock-face-small-morning.svg b/applets/clock/pixmaps/clock-face-small-morning.svg new file mode 100644 index 00000000..17a9840b --- /dev/null +++ b/applets/clock/pixmaps/clock-face-small-morning.svg @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applets/clock/pixmaps/clock-face-small-night.svg b/applets/clock/pixmaps/clock-face-small-night.svg new file mode 100644 index 00000000..d5a7d8e5 --- /dev/null +++ b/applets/clock/pixmaps/clock-face-small-night.svg @@ -0,0 +1,291 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applets/clock/pixmaps/clock-face-small.svg b/applets/clock/pixmaps/clock-face-small.svg new file mode 100644 index 00000000..bd4b5b2e --- /dev/null +++ b/applets/clock/pixmaps/clock-face-small.svg @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applets/clock/pixmaps/clock-map-location-current.png b/applets/clock/pixmaps/clock-map-location-current.png new file mode 100644 index 00000000..5c505d11 Binary files /dev/null and b/applets/clock/pixmaps/clock-map-location-current.png differ diff --git a/applets/clock/pixmaps/clock-map-location-hilight.png b/applets/clock/pixmaps/clock-map-location-hilight.png new file mode 100644 index 00000000..d7de5b78 Binary files /dev/null and b/applets/clock/pixmaps/clock-map-location-hilight.png differ diff --git a/applets/clock/pixmaps/clock-map-location-marker.png b/applets/clock/pixmaps/clock-map-location-marker.png new file mode 100644 index 00000000..48d2184f Binary files /dev/null and b/applets/clock/pixmaps/clock-map-location-marker.png differ diff --git a/applets/clock/pixmaps/clock-map.png b/applets/clock/pixmaps/clock-map.png new file mode 100644 index 00000000..31e1a777 Binary files /dev/null and b/applets/clock/pixmaps/clock-map.png differ diff --git a/applets/clock/pixmaps/clock-map.svg b/applets/clock/pixmaps/clock-map.svg new file mode 100644 index 00000000..d910af1c --- /dev/null +++ b/applets/clock/pixmaps/clock-map.svg @@ -0,0 +1,755 @@ + + + + + + + + + + + + + + +Created by potrace 1.7, written by Peter Selinger 2001-2005 + + + image/svg+xml + + The Earth + + + Garrett LeSage + + + A vectorized, cleaned up, tango-inspired map of the earth based off of the Evolution map. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applets/clock/set-timezone.c b/applets/clock/set-timezone.c new file mode 100644 index 00000000..3b4f1e56 --- /dev/null +++ b/applets/clock/set-timezone.c @@ -0,0 +1,291 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 David Zeuthen + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "set-timezone.h" + + +static DBusGConnection * +get_system_bus (void) +{ + GError *error; + static DBusGConnection *bus = NULL; + + if (bus == NULL) { + error = NULL; + bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (bus == NULL) { + g_warning ("Couldn't connect to system bus: %s", + error->message); + g_error_free (error); + } + } + + return bus; +} + +#define CACHE_VALIDITY_SEC 2 + +typedef void (*CanDoFunc) (gint value); + +static void +notify_can_do (DBusGProxy *proxy, + DBusGProxyCall *call, + void *user_data) +{ + CanDoFunc callback = user_data; + GError *error = NULL; + gint value; + + if (dbus_g_proxy_end_call (proxy, call, + &error, + G_TYPE_INT, &value, + G_TYPE_INVALID)) { + callback (value); + } +} + +static void +refresh_can_do (const gchar *action, CanDoFunc callback) +{ + DBusGConnection *bus; + DBusGProxy *proxy; + + bus = get_system_bus (); + if (bus == NULL) + return; + + proxy = dbus_g_proxy_new_for_name (bus, + "org.mate.SettingsDaemon.DateTimeMechanism", + "/", + "org.mate.SettingsDaemon.DateTimeMechanism"); + + dbus_g_proxy_begin_call_with_timeout (proxy, + action, + notify_can_do, + callback, NULL, + INT_MAX, + G_TYPE_INVALID); +} + +static gint settimezone_cache = 0; +static time_t settimezone_stamp = 0; + +static void +update_can_settimezone (gint res) +{ + settimezone_cache = res; + time (&settimezone_stamp); +} + +gint +can_set_system_timezone (void) +{ + time_t now; + + time (&now); + if (ABS (now - settimezone_stamp) > CACHE_VALIDITY_SEC) { + refresh_can_do ("CanSetTimezone", update_can_settimezone); + settimezone_stamp = now; + } + + return settimezone_cache; +} + +static gint settime_cache = 0; +static time_t settime_stamp = 0; + +static void +update_can_settime (gint res) +{ + settime_cache = res; + time (&settime_stamp); +} + +gint +can_set_system_time (void) +{ + time_t now; + + time (&now); + if (ABS (now - settime_stamp) > CACHE_VALIDITY_SEC) { + refresh_can_do ("CanSetTime", update_can_settime); + settime_stamp = now; + } + + return settime_cache; +} + +typedef struct { + gint ref_count; + gchar *call; + gint64 time; + gchar *filename; + GFunc callback; + gpointer data; + GDestroyNotify notify; +} SetTimeCallbackData; + +static void +free_data (gpointer d) +{ + SetTimeCallbackData *data = d; + + data->ref_count--; + if (data->ref_count == 0) { + if (data->notify) + data->notify (data->data); + g_free (data->filename); + g_free (data); + } +} + +static void +set_time_notify (DBusGProxy *proxy, + DBusGProxyCall *call, + void *user_data) +{ + SetTimeCallbackData *data = user_data; + GError *error = NULL; + + if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) { + if (data->callback) + data->callback (data->data, NULL); + } + else { + if (error->domain == DBUS_GERROR && + error->code == DBUS_GERROR_NO_REPLY) { + /* these errors happen because dbus doesn't + * use monotonic clocks + */ + g_warning ("ignoring no-reply error when setting time"); + g_error_free (error); + if (data->callback) + data->callback (data->data, NULL); + } + else { + if (data->callback) + data->callback (data->data, error); + else + g_error_free (error); + } + } +} + +static void +set_time_async (SetTimeCallbackData *data) +{ + DBusGConnection *bus; + DBusGProxy *proxy; + + bus = get_system_bus (); + if (bus == NULL) + return; + + proxy = dbus_g_proxy_new_for_name (bus, + "org.mate.SettingsDaemon.DateTimeMechanism", + "/", + "org.mate.SettingsDaemon.DateTimeMechanism"); + + data->ref_count++; + if (strcmp (data->call, "SetTime") == 0) + dbus_g_proxy_begin_call_with_timeout (proxy, + "SetTime", + set_time_notify, + data, free_data, + INT_MAX, + /* parameters: */ + G_TYPE_INT64, data->time, + G_TYPE_INVALID, + /* return values: */ + G_TYPE_INVALID); + else + dbus_g_proxy_begin_call_with_timeout (proxy, + "SetTimezone", + set_time_notify, + data, free_data, + INT_MAX, + /* parameters: */ + G_TYPE_STRING, data->filename, + G_TYPE_INVALID, + /* return values: */ + G_TYPE_INVALID); +} + +void +set_system_time_async (gint64 time, + GFunc callback, + gpointer d, + GDestroyNotify notify) +{ + SetTimeCallbackData *data; + + if (time == -1) + return; + + data = g_new0 (SetTimeCallbackData, 1); + data->ref_count = 1; + data->call = "SetTime"; + data->time = time; + data->filename = NULL; + data->callback = callback; + data->data = d; + data->notify = notify; + + set_time_async (data); + free_data (data); +} + +void +set_system_timezone_async (const gchar *filename, + GFunc callback, + gpointer d, + GDestroyNotify notify) +{ + SetTimeCallbackData *data; + + if (filename == NULL) + return; + + data = g_new0 (SetTimeCallbackData, 1); + data->ref_count = 1; + data->call = "SetTimezone"; + data->time = -1; + data->filename = g_strdup (filename); + data->callback = callback; + data->data = d; + data->notify = notify; + + set_time_async (data); + free_data (data); +} diff --git a/applets/clock/set-timezone.h b/applets/clock/set-timezone.h new file mode 100644 index 00000000..5280b079 --- /dev/null +++ b/applets/clock/set-timezone.h @@ -0,0 +1,40 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 David Zeuthen + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __SET_SYSTEM_TIMEZONE_H__ + +#include +#include + +gint can_set_system_timezone (void); + +gint can_set_system_time (void); + +void set_system_time_async (gint64 time, + GFunc callback, + gpointer data, + GDestroyNotify notify); + +void set_system_timezone_async (const gchar *filename, + GFunc callback, + gpointer data, + GDestroyNotify notify); + +#endif diff --git a/applets/clock/system-timezone.c b/applets/clock/system-timezone.c new file mode 100644 index 00000000..336f5a9f --- /dev/null +++ b/applets/clock/system-timezone.c @@ -0,0 +1,1048 @@ +/* System timezone handling + * + * Copyright (C) 2008 Novell, Inc. + * + * Authors: Vincent Untz + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Some code is based on previous code in clock-location.c and on code from + * tz.c (shipped with version <= 2.22.0). Those files were under the same + * license, with those authors and copyrights: + * + * clock-location.c: + * ================ + * No header, but most of the work was done (AFAIK) by + * Federico Mena Quintero + * Matthias Clasen + * + * tz.c: + * ==== + * Copyright (C) 2000-2001 Ximian, Inc. + * Copyright (C) 2004 Sun Microsystems, Inc. + * + * Authors: Hans Petter Jansson + * additional functions by Erwann Chenede + * reworked by Vincent Untz + * + * Largely based on Michael Fulbright's work on Anaconda. + */ + +/* FIXME: it'd be nice to filter out the timezones that we might get when + * parsing config files that are not in zone.tab. Note that it's also wrong + * in some cases: eg, in tzdata2008b, Asia/Calcutta got renamed to + * Asia/Kolkata and the old name is not in zone.tab. */ + +#include +#include + +#include +#include +#include + +#include "system-timezone.h" + +/* Files that we look at and that should be monitored */ +#define CHECK_NB 5 +#define ETC_TIMEZONE "/etc/timezone" +#define ETC_TIMEZONE_MAJ "/etc/TIMEZONE" +#define ETC_RC_CONF "/etc/rc.conf" +#define ETC_SYSCONFIG_CLOCK "/etc/sysconfig/clock" +#define ETC_CONF_D_CLOCK "/etc/conf.d/clock" +#define ETC_LOCALTIME "/etc/localtime" + +/* The first 4 characters in a timezone file, from tzfile.h */ +#define TZ_MAGIC "TZif" + +static char *files_to_check[CHECK_NB] = { + ETC_TIMEZONE, + ETC_TIMEZONE_MAJ, + ETC_SYSCONFIG_CLOCK, + ETC_CONF_D_CLOCK, + ETC_LOCALTIME +}; + +static GObject *systz_singleton = NULL; + +G_DEFINE_TYPE (SystemTimezone, system_timezone, G_TYPE_OBJECT) + +typedef struct { + char *tz; + char *env_tz; + GFileMonitor *monitors[CHECK_NB]; +} SystemTimezonePrivate; + +enum { + CHANGED, + LAST_SIGNAL +}; + +static guint system_timezone_signals[LAST_SIGNAL] = { 0 }; + +static GObject *system_timezone_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties); +static void system_timezone_finalize (GObject *obj); + +static void system_timezone_monitor_changed (GFileMonitor *handle, + GFile *file, + GFile *other_file, + GFileMonitorEvent event, + gpointer user_data); +static char *system_timezone_find (void); + +#define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SYSTEM_TIMEZONE_TYPE, SystemTimezonePrivate)) + +SystemTimezone * +system_timezone_new (void) +{ + return g_object_new (SYSTEM_TIMEZONE_TYPE, NULL); +} + +const char * +system_timezone_get (SystemTimezone *systz) +{ + SystemTimezonePrivate *priv; + + g_return_val_if_fail (IS_SYSTEM_TIMEZONE (systz), NULL); + + priv = PRIVATE (systz); + return priv->tz; +} + +const char * +system_timezone_get_env (SystemTimezone *systz) +{ + SystemTimezonePrivate *priv; + + g_return_val_if_fail (IS_SYSTEM_TIMEZONE (systz), NULL); + + priv = PRIVATE (systz); + return priv->env_tz; +} + +static void +system_timezone_class_init (SystemTimezoneClass *class) +{ + GObjectClass *g_obj_class = G_OBJECT_CLASS (class); + + g_obj_class->constructor = system_timezone_constructor; + g_obj_class->finalize = system_timezone_finalize; + + system_timezone_signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (g_obj_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (SystemTimezoneClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + g_type_class_add_private (class, sizeof (SystemTimezonePrivate)); +} + +static void +system_timezone_init (SystemTimezone *systz) +{ + int i; + SystemTimezonePrivate *priv = PRIVATE (systz); + + priv->tz = NULL; + priv->env_tz = NULL; + for (i = 0; i < CHECK_NB; i++) + priv->monitors[i] = NULL; +} + +static GObject * +system_timezone_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *obj; + SystemTimezonePrivate *priv; + int i; + + /* This is a singleton, we don't need to have it per-applet */ + if (systz_singleton) + return g_object_ref (systz_singleton); + + obj = G_OBJECT_CLASS (system_timezone_parent_class)->constructor ( + type, + n_construct_properties, + construct_properties); + + priv = PRIVATE (obj); + + priv->tz = system_timezone_find (); + + priv->env_tz = g_strdup (g_getenv ("TZ")); + + for (i = 0; i < CHECK_NB; i++) { + GFile *file; + GFile *parent; + GFileType parent_type; + + file = g_file_new_for_path (files_to_check[i]); + + parent = g_file_get_parent (file); + parent_type = g_file_query_file_type (parent, G_FILE_QUERY_INFO_NONE, NULL); + g_object_unref (parent); + + /* We don't try to monitor the file if the parent directory + * doesn't exist: this means we're on a system where this file + * is not useful to determine the system timezone. + * Since gio does not monitor file in non-existing directories + * in a clever way (as of gio 2.22, it just polls every other + * seconds to see if the directory now exists), this avoids + * unnecessary wakeups. */ + if (parent_type == G_FILE_TYPE_DIRECTORY) + priv->monitors[i] = g_file_monitor_file (file, + G_FILE_MONITOR_NONE, + NULL, NULL); + g_object_unref (file); + + if (priv->monitors[i]) + g_signal_connect (G_OBJECT (priv->monitors[i]), + "changed", + G_CALLBACK (system_timezone_monitor_changed), + obj); + } + + systz_singleton = obj; + + return systz_singleton; +} + +static void +system_timezone_finalize (GObject *obj) +{ + int i; + SystemTimezonePrivate *priv = PRIVATE (obj); + + if (priv->tz) { + g_free (priv->tz); + priv->tz = NULL; + } + + if (priv->env_tz) { + g_free (priv->env_tz); + priv->env_tz = NULL; + } + + for (i = 0; i < CHECK_NB; i++) { + if (priv->monitors[i]) + g_object_unref (priv->monitors[i]); + priv->monitors[i] = NULL; + } + + G_OBJECT_CLASS (system_timezone_parent_class)->finalize (obj); + + g_assert (obj == systz_singleton); + + systz_singleton = NULL; +} + +static void +system_timezone_monitor_changed (GFileMonitor *handle, + GFile *file, + GFile *other_file, + GFileMonitorEvent event, + gpointer user_data) +{ + SystemTimezonePrivate *priv = PRIVATE (user_data); + char *new_tz; + + if (event != G_FILE_MONITOR_EVENT_CHANGED && + event != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT && + event != G_FILE_MONITOR_EVENT_DELETED && + event != G_FILE_MONITOR_EVENT_CREATED) + return; + + new_tz = system_timezone_find (); + + g_assert (priv->tz != NULL && new_tz != NULL); + + if (strcmp (priv->tz, new_tz) != 0) { + g_free (priv->tz); + priv->tz = new_tz; + + g_signal_emit (G_OBJECT (user_data), + system_timezone_signals[CHANGED], + 0, priv->tz); + } else + g_free (new_tz); +} + + +/* + * Code to deal with the system timezone on all distros. + * There's no dependency on the SystemTimezone GObject here. + * + * Here's what we know: + * + * + /etc/localtime contains the binary data of the timezone. + * It can be a symlink to the actual data file, a hard link to the data + * file, or just a copy. So we can determine the timezone with this + * (reading the symlink, comparing inodes, or comparing content). + * + * + However, most distributions also have the timezone setting + * configured somewhere else. This might be better to read it from there. + * + * Debian/Ubuntu/Gentoo (new): content of /etc/timezone + * Fedora/Mandriva: the ZONE key in /etc/sysconfig/clock + * openSUSE: the TIMEZONE key in /etc/sysconfig/clock + * Solaris/OpenSolaris: the TZ key in /etc/TIMEZONE + * Arch Linux: the TIMEZONE key in /etc/rc.conf + * Gentoo (old): the ZONE key in /etc/conf.d/clock + * + * FIXME: reading the system-tools-backends, it seems there's this too: + * Solaris: the TZ key in /etc/default/init + * /etc/TIMEZONE seems to be a link to /etc/default/init + * + * First, some functions to handle those system config files. + * + */ + +/* This works for Debian and derivatives (including Ubuntu), and new Gentoo */ +static char * +system_timezone_read_etc_timezone (void) +{ + FILE *etc_timezone; + GString *reading; + int c; + + etc_timezone = g_fopen (ETC_TIMEZONE, "r"); + if (!etc_timezone) + return NULL; + + reading = g_string_new (""); + + c = fgetc (etc_timezone); + /* only get the first line, we'll validate the value later */ + while (c != EOF && !g_ascii_isspace (c)) { + reading = g_string_append_c (reading, c); + c = fgetc (etc_timezone); + } + + fclose (etc_timezone); + + if (reading->str && reading->str[0] != '\0') + return g_string_free (reading, FALSE); + else + g_string_free (reading, TRUE); + + return NULL; +} + +static gboolean +system_timezone_write_etc_timezone (const char *tz, + GError **error) +{ + char *content; + GError *our_error; + gboolean retval; + + if (!g_file_test (ETC_TIMEZONE, G_FILE_TEST_IS_REGULAR)) + return TRUE; + + content = g_strdup_printf ("%s\n", tz); + + our_error = NULL; + retval = g_file_set_contents (ETC_TIMEZONE, content, -1, &our_error); + g_free (content); + + if (!retval) { + g_set_error (error, SYSTEM_TIMEZONE_ERROR, + SYSTEM_TIMEZONE_ERROR_GENERAL, + ETC_TIMEZONE" cannot be overwritten: %s", + our_error->message); + g_error_free (our_error); + } + + return retval; +} + + +/* Read a file that looks like a key-file (but there's no need for groups) + * and get the last value for a specific key */ +static char * +system_timezone_read_key_file (const char *filename, + const char *key) +{ + GIOChannel *channel; + char *key_eq; + char *line; + char *retval; + + if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) + return NULL; + + channel = g_io_channel_new_file (filename, "r", NULL); + if (!channel) + return NULL; + + key_eq = g_strdup_printf ("%s=", key); + retval = NULL; + + while (g_io_channel_read_line (channel, &line, NULL, + NULL, NULL) == G_IO_STATUS_NORMAL) { + if (g_str_has_prefix (line, key_eq)) { + char *value; + int len; + + value = line + strlen (key_eq); + g_strstrip (value); + + len = strlen (value); + + if (value[0] == '\"') { + if (value[len - 1] == '\"') { + if (retval) + g_free (retval); + + retval = g_strndup (value + 1, + len - 2); + } + } else { + if (retval) + g_free (retval); + + retval = g_strdup (line + strlen (key_eq)); + } + + g_strstrip (retval); + } + + g_free (line); + } + + g_free (key_eq); + g_io_channel_unref (channel); + + return retval; +} + +static gboolean +system_timezone_write_key_file (const char *filename, + const char *key, + const char *value, + GError **error) +{ + GError *our_error; + char *content; + gsize len; + char *key_eq; + char **lines; + gboolean replaced; + gboolean retval; + int n; + + if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) + return TRUE; + + our_error = NULL; + + if (!g_file_get_contents (filename, &content, &len, &our_error)) { + g_set_error (error, SYSTEM_TIMEZONE_ERROR, + SYSTEM_TIMEZONE_ERROR_GENERAL, + "%s cannot be read: %s", + filename, our_error->message); + g_error_free (our_error); + return FALSE; + } + + lines = g_strsplit (content, "\n", 0); + g_free (content); + + key_eq = g_strdup_printf ("%s=", key); + replaced = FALSE; + + for (n = 0; lines[n] != NULL; n++) { + if (g_str_has_prefix (lines[n], key_eq)) { + char *old_value; + gboolean use_quotes; + + old_value = lines[n] + strlen (key_eq); + g_strstrip (old_value); + use_quotes = old_value[0] == '\"'; + + g_free (lines[n]); + + if (use_quotes) + lines[n] = g_strdup_printf ("%s\"%s\"", + key_eq, value); + else + lines[n] = g_strdup_printf ("%s%s", + key_eq, value); + + replaced = TRUE; + } + } + + g_free (key_eq); + + if (!replaced) { + g_strfreev (lines); + return TRUE; + } + + content = g_strjoinv ("\n", lines); + g_strfreev (lines); + + retval = g_file_set_contents (filename, content, -1, &our_error); + g_free (content); + + if (!retval) { + g_set_error (error, SYSTEM_TIMEZONE_ERROR, + SYSTEM_TIMEZONE_ERROR_GENERAL, + "%s cannot be overwritten: %s", + filename, our_error->message); + g_error_free (our_error); + } + + return retval; +} + +/* This works for Solaris/OpenSolaris */ +static char * +system_timezone_read_etc_TIMEZONE (void) +{ + return system_timezone_read_key_file (ETC_TIMEZONE_MAJ, + "TZ"); +} + +static gboolean +system_timezone_write_etc_TIMEZONE (const char *tz, + GError **error) +{ + return system_timezone_write_key_file (ETC_TIMEZONE_MAJ, + "TZ", tz, error); +} + +/* This works for Fedora and Mandriva */ +static char * +system_timezone_read_etc_sysconfig_clock (void) +{ + return system_timezone_read_key_file (ETC_SYSCONFIG_CLOCK, + "ZONE"); +} + +static gboolean +system_timezone_write_etc_sysconfig_clock (const char *tz, + GError **error) +{ + return system_timezone_write_key_file (ETC_SYSCONFIG_CLOCK, + "ZONE", tz, error); +} + +/* This works for openSUSE */ +static char * +system_timezone_read_etc_sysconfig_clock_alt (void) +{ + return system_timezone_read_key_file (ETC_SYSCONFIG_CLOCK, + "TIMEZONE"); +} + +static gboolean +system_timezone_write_etc_sysconfig_clock_alt (const char *tz, + GError **error) +{ + return system_timezone_write_key_file (ETC_SYSCONFIG_CLOCK, + "TIMEZONE", tz, error); +} + +/* This works for old Gentoo */ +static char * +system_timezone_read_etc_conf_d_clock (void) +{ + return system_timezone_read_key_file (ETC_CONF_D_CLOCK, + "TIMEZONE"); +} + +static gboolean +system_timezone_write_etc_conf_d_clock (const char *tz, + GError **error) +{ + return system_timezone_write_key_file (ETC_CONF_D_CLOCK, + "TIMEZONE", tz, error); +} + +/* This works for Arch Linux */ +static char * +system_timezone_read_etc_rc_conf (void) +{ + return system_timezone_read_key_file (ETC_RC_CONF, + "TIMEZONE"); +} + +static gboolean +system_timezone_write_etc_rc_conf (const char *tz, + GError **error) +{ + return system_timezone_write_key_file (ETC_RC_CONF, + "TIMEZONE", tz, error); +} + +/* + * + * First, getting the timezone. + * + */ + +static char * +system_timezone_strip_path_if_valid (const char *filename) +{ + int skip; + + if (!filename || !g_str_has_prefix (filename, SYSTEM_ZONEINFODIR"/")) + return NULL; + + /* Timezone data files also live under posix/ and right/ for some + * reason. + * FIXME: make sure accepting those files is valid. I think "posix" is + * okay, not sure about "right" */ + if (g_str_has_prefix (filename, SYSTEM_ZONEINFODIR"/posix/")) + skip = strlen (SYSTEM_ZONEINFODIR"/posix/"); + else if (g_str_has_prefix (filename, SYSTEM_ZONEINFODIR"/right/")) + skip = strlen (SYSTEM_ZONEINFODIR"/right/"); + else + skip = strlen (SYSTEM_ZONEINFODIR"/"); + + return g_strdup (filename + skip); +} + +/* Read the soft symlink from /etc/localtime */ +static char * +system_timezone_read_etc_localtime_softlink (void) +{ + char *file; + char *tz; + + if (!g_file_test (ETC_LOCALTIME, G_FILE_TEST_IS_SYMLINK)) + return NULL; + + file = g_file_read_link (ETC_LOCALTIME, NULL); + tz = system_timezone_strip_path_if_valid (file); + g_free (file); + + return tz; +} + +typedef gboolean (*CompareFiles) (struct stat *a_stat, + struct stat *b_stat, + const char *a_content, + gsize a_content_len, + const char *b_filename); + +static char * +recursive_compare (struct stat *localtime_stat, + const char *localtime_content, + gsize localtime_content_len, + char *file, + CompareFiles compare_func) +{ + struct stat file_stat; + + if (g_stat (file, &file_stat) != 0) + return NULL; + + if (S_ISREG (file_stat.st_mode)) { + if (compare_func (localtime_stat, + &file_stat, + localtime_content, + localtime_content_len, + file)) + return system_timezone_strip_path_if_valid (file); + else + return NULL; + } else if (S_ISDIR (file_stat.st_mode)) { + GDir *dir = NULL; + char *ret = NULL; + const char *subfile = NULL; + char *subpath = NULL; + + dir = g_dir_open (file, 0, NULL); + if (dir == NULL) + return NULL; + + while ((subfile = g_dir_read_name (dir)) != NULL) { + subpath = g_build_filename (file, subfile, NULL); + + ret = recursive_compare (localtime_stat, + localtime_content, + localtime_content_len, + subpath, + compare_func); + + g_free (subpath); + + if (ret != NULL) + break; + } + + g_dir_close (dir); + + return ret; + } + + return NULL; +} + + +static gboolean +files_are_identical_inode (struct stat *a_stat, + struct stat *b_stat, + const char *a_content, + gsize a_content_len, + const char *b_filename) +{ + return (a_stat->st_ino == b_stat->st_ino); +} + + +/* Determine if /etc/localtime is a hard link to some file, by looking at + * the inodes */ +static char * +system_timezone_read_etc_localtime_hardlink (void) +{ + struct stat stat_localtime; + + if (g_stat (ETC_LOCALTIME, &stat_localtime) != 0) + return NULL; + + if (!S_ISREG (stat_localtime.st_mode)) + return NULL; + + return recursive_compare (&stat_localtime, + NULL, + 0, + SYSTEM_ZONEINFODIR, + files_are_identical_inode); +} + +static gboolean +files_are_identical_content (struct stat *a_stat, + struct stat *b_stat, + const char *a_content, + gsize a_content_len, + const char *b_filename) +{ + char *b_content = NULL; + gsize b_content_len = -1; + int cmp; + + if (a_stat->st_size != b_stat->st_size) + return FALSE; + + if (!g_file_get_contents (b_filename, + &b_content, &b_content_len, NULL)) + return FALSE; + + if (a_content_len != b_content_len) { + g_free (b_content); + return FALSE; + } + + cmp = memcmp (a_content, b_content, a_content_len); + g_free (b_content); + + return (cmp == 0); +} + +/* Determine if /etc/localtime is a copy of a timezone file */ +static char * +system_timezone_read_etc_localtime_content (void) +{ + struct stat stat_localtime; + char *localtime_content = NULL; + gsize localtime_content_len = -1; + char *retval; + + if (g_stat (ETC_LOCALTIME, &stat_localtime) != 0) + return NULL; + + if (!S_ISREG (stat_localtime.st_mode)) + return NULL; + + if (!g_file_get_contents (ETC_LOCALTIME, + &localtime_content, + &localtime_content_len, + NULL)) + return NULL; + + retval = recursive_compare (&stat_localtime, + localtime_content, + localtime_content_len, + SYSTEM_ZONEINFODIR, + files_are_identical_content); + + g_free (localtime_content); + + return retval; +} + +typedef char * (*GetSystemTimezone) (void); +/* The order of the functions here define the priority of the methods used + * to find the timezone. First method has higher priority. */ +static GetSystemTimezone get_system_timezone_methods[] = { + /* cheap and "more correct" than data from a config file */ + system_timezone_read_etc_localtime_softlink, + /* reading various config files */ + system_timezone_read_etc_timezone, + system_timezone_read_etc_sysconfig_clock, + system_timezone_read_etc_sysconfig_clock_alt, + system_timezone_read_etc_TIMEZONE, + system_timezone_read_etc_rc_conf, + /* reading deprecated config files */ + system_timezone_read_etc_conf_d_clock, + /* reading /etc/timezone directly. Expensive since we have to stat + * many files */ + system_timezone_read_etc_localtime_hardlink, + system_timezone_read_etc_localtime_content, + NULL +}; + +static gboolean +system_timezone_is_valid (const char *tz) +{ + const char *c; + + if (!tz) + return FALSE; + + for (c = tz; *c != '\0'; c++) { + if (!(g_ascii_isalnum (*c) || + *c == '/' || *c == '-' || *c == '_')) + return FALSE; + } + + return TRUE; +} + +static char * +system_timezone_find (void) +{ + char *tz; + int i; + + for (i = 0; get_system_timezone_methods[i] != NULL; i++) { + tz = get_system_timezone_methods[i] (); + + if (system_timezone_is_valid (tz)) + return tz; + + g_free (tz); + } + + return g_strdup ("UTC"); +} + +/* + * + * Now, setting the timezone. + * + */ + +static gboolean +system_timezone_is_zone_file_valid (const char *zone_file, + GError **error) +{ + GError *our_error; + GIOChannel *channel; + GIOStatus status; + char buffer[strlen (TZ_MAGIC)]; + gsize read; + + /* First, check the zone_file is properly rooted */ + if (!g_str_has_prefix (zone_file, SYSTEM_ZONEINFODIR"/")) { + g_set_error (error, SYSTEM_TIMEZONE_ERROR, + SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, + "Timezone file needs to be under "SYSTEM_ZONEINFODIR); + return FALSE; + } + + /* Second, check it's a regular file that exists */ + if (!g_file_test (zone_file, G_FILE_TEST_IS_REGULAR)) { + g_set_error (error, SYSTEM_TIMEZONE_ERROR, + SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, + "No such timezone file %s", zone_file); + return FALSE; + } + + /* Third, check that it's a tzfile (see tzfile(5)). The file has a 4 + * bytes header which is TZ_MAGIC. + * + * TODO: is there glibc API for this? */ + our_error = NULL; + channel = g_io_channel_new_file (zone_file, "r", &our_error); + if (!our_error) + status = g_io_channel_read_chars (channel, + buffer, strlen (TZ_MAGIC), + &read, &our_error); + if (channel) + g_io_channel_unref (channel); + + if (our_error) { + g_set_error (error, SYSTEM_TIMEZONE_ERROR, + SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, + "Timezone file %s cannot be read: %s", + zone_file, our_error->message); + g_error_free (our_error); + return FALSE; + } + + if (read != strlen (TZ_MAGIC) || strncmp (buffer, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) { + g_set_error (error, SYSTEM_TIMEZONE_ERROR, + SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, + "%s is not a timezone file", + zone_file); + return FALSE; + } + + return TRUE; +} + +static gboolean +system_timezone_set_etc_timezone (const char *zone_file, + GError **error) +{ + GError *our_error; + char *content; + gsize len; + + if (!system_timezone_is_zone_file_valid (zone_file, error)) + return FALSE; + + /* If /etc/localtime is a symlink, write a symlink */ + if (g_file_test (ETC_LOCALTIME, G_FILE_TEST_IS_SYMLINK)) { + if (g_unlink (ETC_LOCALTIME) == 0 && + symlink (zone_file, ETC_LOCALTIME) == 0) + return TRUE; + + /* If we couldn't symlink the file, we'll just fallback on + * copying it */ + } + + /* Else copy the file to /etc/localtime. We explicitly avoid doing + * hard links since they break with different partitions */ + our_error = NULL; + if (!g_file_get_contents (zone_file, &content, &len, &our_error)) { + g_set_error (error, SYSTEM_TIMEZONE_ERROR, + SYSTEM_TIMEZONE_ERROR_GENERAL, + "Timezone file %s cannot be read: %s", + zone_file, our_error->message); + g_error_free (our_error); + return FALSE; + } + + if (!g_file_set_contents (ETC_LOCALTIME, content, len, &our_error)) { + g_set_error (error, SYSTEM_TIMEZONE_ERROR, + SYSTEM_TIMEZONE_ERROR_GENERAL, + ETC_LOCALTIME" cannot be overwritten: %s", + our_error->message); + g_error_free (our_error); + g_free (content); + return FALSE; + } + + g_free (content); + + return TRUE; +} + +typedef gboolean (*SetSystemTimezone) (const char *tz, + GError **error); +/* The order here does not matter too much: we'll try to change all files + * that already have a timezone configured. It matters in case of error, + * since the process will be stopped and the last methods won't be called. + * So we use the same order as in get_system_timezone_methods */ +static SetSystemTimezone set_system_timezone_methods[] = { + /* writing various config files if they exist and have the + * setting already present */ + system_timezone_write_etc_timezone, + system_timezone_write_etc_sysconfig_clock, + system_timezone_write_etc_sysconfig_clock_alt, + system_timezone_write_etc_TIMEZONE, + system_timezone_write_etc_rc_conf, + /* writing deprecated config files if they exist and have the + * setting already present */ + system_timezone_write_etc_conf_d_clock, + NULL +}; + +static gboolean +system_timezone_update_config (const char *tz, + GError **error) +{ + int i; + + for (i = 0; set_system_timezone_methods[i] != NULL; i++) { + if (!set_system_timezone_methods[i] (tz, error)) + return FALSE; + /* FIXME: maybe continue to change all config files if + * possible? */ + } + + return TRUE; +} + +gboolean +system_timezone_set_from_file (const char *zone_file, + GError **error) +{ + const char *tz; + + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + tz = zone_file + strlen (SYSTEM_ZONEINFODIR"/"); + + /* FIXME: is it right to return FALSE even when /etc/localtime was + * changed but not the config files? */ + return (system_timezone_set_etc_timezone (zone_file, error) && + system_timezone_update_config (tz, error)); +} + +gboolean +system_timezone_set (const char *tz, + GError **error) +{ + char *zone_file; + gboolean retval; + + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + zone_file = g_build_filename (SYSTEM_ZONEINFODIR, tz, NULL); + + /* FIXME: is it right to return FALSE even when /etc/localtime was + * changed but not the config files? */ + retval = system_timezone_set_etc_timezone (zone_file, error) && + system_timezone_update_config (tz, error); + + g_free (zone_file); + + return retval; +} + +GQuark +system_timezone_error_quark (void) +{ + static GQuark ret = 0; + + if (ret == 0) { + ret = g_quark_from_static_string ("system-timezone-error"); + } + + return ret; +} diff --git a/applets/clock/system-timezone.h b/applets/clock/system-timezone.h new file mode 100644 index 00000000..c67b5d37 --- /dev/null +++ b/applets/clock/system-timezone.h @@ -0,0 +1,87 @@ +/* System timezone handling + * + * Copyright (C) 2008 Novell, Inc. + * + * Authors: Vincent Untz + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SYSTEM_TIMEZONE_H__ +#define __SYSTEM_TIMEZONE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_SOLARIS +#define SYSTEM_ZONEINFODIR "/usr/share/lib/zoneinfo/tab" +#else +#define SYSTEM_ZONEINFODIR "/usr/share/zoneinfo" +#endif + + +#define SYSTEM_TIMEZONE_TYPE (system_timezone_get_type ()) +#define SYSTEM_TIMEZONE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SYSTEM_TIMEZONE_TYPE, SystemTimezone)) +#define SYSTEM_TIMEZONE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), SYSTEM_TIMEZONE_TYPE, SystemTimezoneClass)) +#define IS_SYSTEM_TIMEZONE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SYSTEM_TIMEZONE_TYPE)) +#define IS_SYSTEM_TIMEZONE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), SYSTEM_TIMEZONE_TYPE)) +#define SYSTEM_TIMEZONE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SYSTEM_TIMEZONE_TYPE, SystemTimezoneClass)) + +typedef struct +{ + GObject g_object; +} SystemTimezone; + +typedef struct +{ + GObjectClass g_object_class; + + void (* changed) (SystemTimezone *systz, + const char *tz); +} SystemTimezoneClass; + +GType system_timezone_get_type (void); + +SystemTimezone *system_timezone_new (void); + +const char *system_timezone_get (SystemTimezone *systz); +const char *system_timezone_get_env (SystemTimezone *systz); + +/* Functions to set the timezone. They won't be used by the applet, but + * by a program with more privileges */ + +#define SYSTEM_TIMEZONE_ERROR system_timezone_error_quark () +GQuark system_timezone_error_quark (void); + +typedef enum +{ + SYSTEM_TIMEZONE_ERROR_GENERAL, + SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, + SYSTEM_TIMEZONE_NUM_ERRORS +} SystemTimezoneError; + +gboolean system_timezone_set_from_file (const char *zone_file, + GError **error); +gboolean system_timezone_set (const char *tz, + GError **error); + +#ifdef __cplusplus +} +#endif +#endif /* __SYSTEM_TIMEZONE_H__ */ diff --git a/applets/clock/test-system-timezone.c b/applets/clock/test-system-timezone.c new file mode 100644 index 00000000..42a80611 --- /dev/null +++ b/applets/clock/test-system-timezone.c @@ -0,0 +1,122 @@ +/* Test for system timezone handling + * + * Copyright (C) 2008-2010 Novell, Inc. + * + * Authors: Vincent Untz + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include "system-timezone.h" + +static void +timezone_print (void) +{ + SystemTimezone *systz; + + systz = system_timezone_new (); + g_print ("Current timezone: %s\n", system_timezone_get (systz)); + g_object_unref (systz); +} + +static int +timezone_set (const char *new_tz) +{ + GError *error; + + error = NULL; + if (!system_timezone_set (new_tz, &error)) { + g_printerr ("%s\n", error->message); + g_error_free (error); + return 1; + } + + return 0; +} + +static void +timezone_changed (SystemTimezone *systz, + const char *new_tz, + gpointer data) +{ + g_print ("Timezone changed to: %s\n", new_tz); +} + +static void +timezone_monitor (void) +{ + SystemTimezone *systz; + GMainLoop *mainloop; + + systz = system_timezone_new (); + g_signal_connect (systz, "changed", + G_CALLBACK (timezone_changed), NULL); + + mainloop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (mainloop); + g_main_loop_unref (mainloop); + + g_object_unref (systz); +} + +int +main (int argc, + char **argv) +{ + int retval; + + gboolean get = FALSE; + gboolean monitor = FALSE; + char *tz_set = NULL; + + GError *error; + GOptionContext *context; + GOptionEntry options[] = { + { "get", 'g', 0, G_OPTION_ARG_NONE, &get, "Get the current timezone", NULL }, + { "set", 's', 0, G_OPTION_ARG_STRING, &tz_set, "Set the timezone to TIMEZONE", "TIMEZONE" }, + { "monitor", 'm', 0, G_OPTION_ARG_NONE, &monitor, "Monitor timezone changes", NULL }, + { NULL, 0, 0, 0, NULL, NULL, NULL } + }; + + retval = 0; + + g_type_init (); + + context = g_option_context_new (""); + g_option_context_add_main_entries (context, options, NULL); + + error = NULL; + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_printerr ("%s\n", error->message); + g_error_free (error); + g_option_context_free (context); + + return 1; + } + + g_option_context_free (context); + + if (get || (!tz_set && !monitor)) + timezone_print (); + else if (tz_set) + retval = timezone_set (tz_set); + else if (monitor) + timezone_monitor (); + else + g_assert_not_reached (); + + return retval; +} -- cgit v1.2.1